We are no longer offering accounts on this server. Consider https://gitlab.freedesktop.org/ as a place to host projects.

Commit b7d07466 authored by Zach Copley's avatar Zach Copley

Merge branch '0.9.x' into 1.0.x

Conflicts:
	actions/confirmaddress.php
	actions/emailsettings.php
	actions/hostmeta.php
	actions/imsettings.php
	actions/login.php
	actions/profilesettings.php
	actions/showgroup.php
	actions/smssettings.php
	actions/urlsettings.php
	actions/userauthorization.php
	actions/userdesignsettings.php
	classes/Memcached_DataObject.php
	index.php
	lib/accountsettingsaction.php
	lib/action.php
	lib/common.php
	lib/connectsettingsaction.php
	lib/designsettings.php
	lib/personalgroupnav.php
	lib/profileaction.php
	lib/userprofile.php
	plugins/ClientSideShorten/ClientSideShortenPlugin.php
	plugins/Facebook/FBConnectSettings.php
	plugins/Facebook/FacebookPlugin.php
	plugins/NewMenu/NewMenuPlugin.php
	plugins/NewMenu/newmenu.css
parents babdc430 061c8d95

Too many changes to show.

To preserve performance only 1000 of 1000+ files are displayed.
......@@ -1075,3 +1075,43 @@ StartCloseNoticeListItemElement: Before the closing </li> of a notice list eleme
EndCloseNoticeListItemElement: After the closing </li> of a notice list element
- $nli: The notice list item being shown
StartGroupEditFormData: Beginning the group edit form entries
- $form: The form widget being shown
EndGroupEditFormData: Ending the group edit form entries
- $form: The form widget being shown
StartGroupSave: After initializing but before saving a group
- &$group: group about to be saved
EndGroupSave: After saving a group, aliases, and first member
- $group: group that was saved
StartInterpretCommand: Before running a command
- $cmd: First word in the string, 'foo' in 'foo argument'
- $arg: Argument, if any, like 'argument' in 'foo argument'
- $user: User who issued the command
- &$result: Resulting command; you can set this!
EndInterpretCommand: Before running a command
- $cmd: First word in the string, 'foo' in 'foo argument'
- $arg: Argument, if any, like 'argument' in 'foo argument'
- $user: User who issued the command
- $result: Resulting command
StartGroupActionsList: Start the list of actions on a group profile page (after <ul>, before first <li>)
- $action: action being executed (for output and params)
- $group: group for the page
EndGroupActionsList: End the list of actions on a group profile page (before </ul>, after last </li>)
- $action: action being executed (for output and params)
- $group: group for the page
StartGroupProfileElements: Start showing stuff about the group on its profile page
- $action: action being executed (for output and params)
- $group: group for the page
EndGroupProfileElements: Start showing stuff about the group on its profile page
- $action: action being executed (for output and params)
- $group: group for the page
......@@ -1283,7 +1283,7 @@ biolimit: max character length of bio; 0 means no limit; null means to use
backup: whether users can backup their own profiles. Defaults to true.
restore: whether users can restore their profiles from backup files. Defaults
to true.
delete: whether users can delete their own accounts. Defaults to true.
delete: whether users can delete their own accounts. Defaults to false.
move: whether users can move their accounts to another server. Defaults
to true.
......@@ -1592,6 +1592,24 @@ proxy_user: Username to use for authenticating to the HTTP proxy. Default null.
proxy_password: Password to use for authenticating to the HTTP proxy. Default null.
proxy_auth_scheme: Scheme to use for authenticating to the HTTP proxy. Default null.
plugins
-------
default: associative array mapping plugin name to array of arguments. To disable
a default plugin, unset its value in this array.
locale_path: path for finding plugin locale files. In the plugin's directory
by default.
server: Server to find static files for a plugin when the page is plain old HTTP.
Defaults to site/server (same as pages). Use this to move plugin CSS and
JS files to a CDN.
sslserver: Server to find static files for a plugin when the page is HTTPS. Defaults
to site/server (same as pages). Use this to move plugin CSS and JS files
to a CDN.
path: Path to the plugin files. defaults to site/path + '/plugins/'. Expects that
each plugin will have a subdirectory at plugins/NameOfPlugin. Change this
if you're using a CDN.
sslpath: Path to use on the SSL server. Same as plugins/path.
Plugins
=======
......
......@@ -149,7 +149,7 @@ class ApiAccountUpdateDeliveryDeviceAction extends ApiAuthAction
if ($this->format == 'xml') {
$this->initDocument('xml');
$this->showTwitterXmlUser($twitter_user);
$this->showTwitterXmlUser($twitter_user, 'user', true);
$this->endDocument('xml');
} elseif ($this->format == 'json') {
$this->initDocument('json');
......
......@@ -154,7 +154,7 @@ class ApiAccountUpdateProfileAction extends ApiAuthAction
if ($this->format == 'xml') {
$this->initDocument('xml');
$this->showTwitterXmlUser($twitter_user);
$this->showTwitterXmlUser($twitter_user, 'user', true);
$this->endDocument('xml');
} elseif ($this->format == 'json') {
$this->initDocument('json');
......
......@@ -204,7 +204,7 @@ class ApiAccountUpdateProfileBackgroundImageAction extends ApiAuthAction
if ($this->format == 'xml') {
$this->initDocument('xml');
$this->showTwitterXmlUser($twitter_user);
$this->showTwitterXmlUser($twitter_user, 'user', true);
$this->endDocument('xml');
} elseif ($this->format == 'json') {
$this->initDocument('json');
......
......@@ -188,7 +188,7 @@ class ApiAccountUpdateProfileColorsAction extends ApiAuthAction
if ($this->format == 'xml') {
$this->initDocument('xml');
$this->showTwitterXmlUser($twitter_user);
$this->showTwitterXmlUser($twitter_user, 'user', true);
$this->endDocument('xml');
} elseif ($this->format == 'json') {
$this->initDocument('json');
......
......@@ -112,16 +112,17 @@ class ApiAccountUpdateProfileImageAction extends ApiAuthAction
return;
}
$type = $imagefile->preferredType();
$filename = Avatar::filename(
$user->id,
image_type_to_extension($imagefile->type),
image_type_to_extension($type),
null,
'tmp'.common_timestamp()
);
$filepath = Avatar::path($filename);
move_uploaded_file($imagefile->filepath, $filepath);
$imagefile->copyTo($filepath);
$profile = $this->user->getProfile();
......@@ -139,7 +140,7 @@ class ApiAccountUpdateProfileImageAction extends ApiAuthAction
if ($this->format == 'xml') {
$this->initDocument('xml');
$this->showTwitterXmlUser($twitter_user);
$this->showTwitterXmlUser($twitter_user, 'user', true);
$this->endDocument('xml');
} elseif ($this->format == 'json') {
$this->initDocument('json');
......
......@@ -39,7 +39,6 @@ require_once INSTALLDIR.'/lib/apibareauth.php';
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPLv3
* @link http://status.net/
*/
class ApiAtomServiceAction extends ApiBareAuthAction
{
/**
......@@ -50,13 +49,13 @@ class ApiAtomServiceAction extends ApiBareAuthAction
* @return boolean success flag
*
*/
function prepare($args)
{
parent::prepare($args);
$this->user = $this->getTargetUser($this->arg('id'));
if (empty($this->user)) {
// TRANS: Client error displayed when making an Atom API request for an unknown user.
$this->clientError(_('No such user.'), 404, $this->format);
return;
}
......@@ -71,7 +70,6 @@ class ApiAtomServiceAction extends ApiBareAuthAction
*
* @return void
*/
function handle($args)
{
parent::handle($args);
......@@ -83,13 +81,15 @@ class ApiAtomServiceAction extends ApiBareAuthAction
'xmlns:atom' => 'http://www.w3.org/2005/Atom',
'xmlns:activity' => 'http://activitystrea.ms/spec/1.0/'));
$this->elementStart('workspace');
$this->element('atom:title', null, _('Main'));
// TRANS: Title for Atom feed.
$this->element('atom:title', null, _m('ATOM','Main'));
$this->elementStart('collection',
array('href' => common_local_url('ApiTimelineUser',
array('id' => $this->user->id,
'format' => 'atom'))));
$this->element('atom:title',
null,
// TRANS: Title for Atom feed. %s is a user nickname.
sprintf(_("%s timeline"),
$this->user->nickname));
$this->element('accept', null, 'application/atom+xml;type=entry');
......@@ -100,6 +100,7 @@ class ApiAtomServiceAction extends ApiBareAuthAction
array('subscriber' => $this->user->id))));
$this->element('atom:title',
null,
// TRANS: Title for Atom feed with a user's subscriptions. %s is a user nickname.
sprintf(_("%s subscriptions"),
$this->user->nickname));
$this->element('accept', null, 'application/atom+xml;type=entry');
......@@ -110,6 +111,7 @@ class ApiAtomServiceAction extends ApiBareAuthAction
array('profile' => $this->user->id))));
$this->element('atom:title',
null,
// TRANS: Title for Atom feed with a user's favorite notices. %s is a user nickname.
sprintf(_("%s favorites"),
$this->user->nickname));
$this->element('accept', null, 'application/atom+xml;type=entry');
......@@ -120,6 +122,7 @@ class ApiAtomServiceAction extends ApiBareAuthAction
array('profile' => $this->user->id))));
$this->element('atom:title',
null,
// TRANS: Title for Atom feed with a user's memberships. %s is a user nickname.
sprintf(_("%s memberships"),
$this->user->nickname));
$this->element('accept', null, 'application/atom+xml;type=entry');
......
......@@ -92,6 +92,7 @@ class ApiBlockCreateAction extends ApiAuthAction
}
if (empty($this->user) || empty($this->other)) {
// TRANS: Client error displayed when trying to block a non-existing user or a user from another site.
$this->clientError(_('No such user.'), 404, $this->format);
return;
}
......
......@@ -141,7 +141,7 @@ class ApiDirectMessageNewAction extends ApiAuthAction
} else if (!$this->user->mutuallySubscribed($this->other)) {
$this->clientError(
// TRANS: Client error displayed trying to direct message another user who's not a friend (403).
_('Can\'t send direct messages to users who aren\'t your friend.'),
_('Cannot send direct messages to users who aren\'t your friend.'),
403,
$this->format
);
......
......@@ -66,6 +66,12 @@ class ApiGroupMembershipAction extends ApiPrivateAuthAction
parent::prepare($args);
$this->group = $this->getTargetGroup($this->arg('id'));
if (empty($this->group)) {
// TRANS: Client error displayed trying to show group membership on a non-existing group.
$this->clientError(_('Group not found.'), 404, $this->format);
return false;
}
$this->profiles = $this->getProfiles();
return true;
......@@ -84,12 +90,6 @@ class ApiGroupMembershipAction extends ApiPrivateAuthAction
{
parent::handle($args);
if (empty($this->group)) {
// TRANS: Client error displayed trying to show group membership on a non-existing group.
$this->clientError(_('Group not found.'), 404, $this->format);
return false;
}
// XXX: RSS and Atom
switch($this->format) {
......
......@@ -84,6 +84,7 @@ class ApiOauthAccessTokenAction extends ApiOauthAction
common_debug(var_export($req, true));
$code = $e->getCode();
$this->clientError($e->getMessage(), empty($code) ? 401 : $code, 'text');
return;
}
if (empty($atok)) {
......@@ -98,7 +99,7 @@ class ApiOauthAccessTokenAction extends ApiOauthAction
common_log(LOG_WARNING, $msg);
// TRANS: Client error given from the OAuth API when the request token or verifier is invalid.
$this->clientError(_("Invalid request token or verifier.", 400, 'text'));
$this->clientError(_('Invalid request token or verifier.'), 400, 'text');
} else {
common_log(
LOG_INFO,
......
......@@ -114,6 +114,7 @@ class ApiStatusesShowAction extends ApiPrivateAuthAction
$this->deleteNotice();
break;
default:
// TRANS: Client error displayed calling an unsupported HTTP error in API status show.
$this->clientError(_('HTTP method not supported.'), 405);
return;
}
......@@ -138,7 +139,9 @@ class ApiStatusesShowAction extends ApiPrivateAuthAction
$this->showSingleAtomStatus($this->notice);
break;
default:
throw new Exception(sprintf(_("Unsupported format: %s"), $this->format));
// TRANS: Exception thrown requesting an unsupported notice output format.
// TRANS: %s is the requested output format.
throw new Exception(sprintf(_("Unsupported format: %s."), $this->format));
}
} else {
// XXX: Twitter just sets a 404 header and doens't bother
......@@ -171,7 +174,7 @@ class ApiStatusesShowAction extends ApiPrivateAuthAction
*
* @return boolean true
*/
function isReadOnly($args)
{
return ($_SERVER['REQUEST_METHOD'] == 'GET' || $_SERVER['REQUEST_METHOD'] == 'HEAD');
......@@ -220,14 +223,16 @@ class ApiStatusesShowAction extends ApiPrivateAuthAction
function deleteNotice()
{
if ($this->format != 'atom') {
$this->clientError(_("Can only delete using the Atom format."));
// TRANS: Client error displayed when trying to delete a notice not using the Atom format.
$this->clientError(_('Can only delete using the Atom format.'));
return;
}
if (empty($this->auth_user) ||
($this->notice->profile_id != $this->auth_user->id &&
!$this->auth_user->hasRight(Right::DELETEOTHERSNOTICE))) {
$this->clientError(_('Can\'t delete this notice.'), 403);
// TRANS: Client error displayed when a user has no rights to delete notices of other users.
$this->clientError(_('Cannot delete this notice.'), 403);
return;
}
......@@ -240,6 +245,7 @@ class ApiStatusesShowAction extends ApiPrivateAuthAction
header('HTTP/1.1 200 OK');
header('Content-Type: text/plain');
// TRANS: Confirmation of notice deletion in API. %d is the ID (number) of the deleted notice.
print(sprintf(_('Deleted notice %d'), $this->notice->id));
print("\n");
}
......
......@@ -377,7 +377,7 @@ class ApiStatusesUpdateAction extends ApiAuthAction
function supported($cmd)
{
static $cmdlist = array('MessageCommand', 'SubCommand', 'UnsubCommand',
'FavCommand', 'OnCommand', 'OffCommand');
'FavCommand', 'OnCommand', 'OffCommand', 'JoinCommand', 'LeaveCommand');
if (in_array(get_class($cmd), $cmdlist)) {
return true;
......
......@@ -59,7 +59,8 @@ class ApiStatusnetConfigAction extends ApiAction
'notice' => array('contentlimit'),
'throttle' => array('enabled', 'count', 'timespan'),
'xmpp' => array('enabled', 'server', 'port', 'user'),
'integration' => array('source')
'integration' => array('source'),
'attachments' => array('uploads', 'file_quota')
);
/**
......@@ -96,7 +97,7 @@ class ApiStatusnetConfigAction extends ApiAction
foreach ($this->keys as $section => $settings) {
$this->elementStart($section);
foreach ($settings as $setting) {
$value = common_config($section, $setting);
$value = $this->setting($section, $setting);
if (is_array($value)) {
$value = implode(',', $value);
} else if ($value === false || $value == '0') {
......@@ -125,7 +126,7 @@ class ApiStatusnetConfigAction extends ApiAction
$result[$section] = array();
foreach ($settings as $setting) {
$result[$section][$setting]
= common_config($section, $setting);
= $this->setting($section, $setting);
}
}
$this->initDocument('json');
......@@ -143,6 +144,20 @@ class ApiStatusnetConfigAction extends ApiAction
}
}
function setting($section, $key) {
$result = common_config($section, $key);
if ($key == 'file_quota') {
// hack: adjust for the live upload limit
if (common_config($section, 'uploads')) {
$max = ImageFile::maxFileSizeInt();
} else {
$max = 0;
}
return min($result, $max);
}
return $result;
}
/**
* Return true if read only.
*
......
......@@ -169,6 +169,14 @@ class ApiTimelineFavoritesAction extends ApiBareAuthAction
case 'json':
$this->showJsonTimeline($this->notices);
break;
case 'as':
header('Content-Type: application/json; charset=utf-8');
$doc = new ActivityStreamJSONDocument($this->auth_user);
$doc->setTitle($title);
$doc->addLink($link,'alternate', 'text/html');
$doc->addItemsFromNotices($this->notices);
$this->raw($doc->asString());
break;
default:
// TRANS: Client error displayed when trying to handle an unknown API method.
$this->clientError(_('API method not found.'), $code = 404);
......
......@@ -263,6 +263,14 @@ class ApiTimelineFriendsAction extends ApiBareAuthAction
case 'json':
$this->showJsonTimeline($this->notices);
break;
case 'as':
header('Content-Type: application/json; charset=utf-8');
$doc = new ActivityStreamJSONDocument($this->auth_user);
$doc->setTitle($title);
$doc->addLink($link,'alternate', 'text/html');
$doc->addItemsFromNotices($this->notices);
$this->raw($doc->asString());
break;
default:
// TRANS: Client error displayed when trying to handle an unknown API method.
$this->clientError(_('API method not found.'), $code = 404);
......
......@@ -106,6 +106,11 @@ class ApiTimelineGroupAction extends ApiPrivateAuthAction
$self = $this->getSelfUri();
$link = common_local_url(
'ApiTimelineGroup',
array('nickname' => $this->group->nickname)
);
switch($this->format) {
case 'xml':
$this->showXmlTimeline($this->notices);
......@@ -123,24 +128,20 @@ class ApiTimelineGroupAction extends ApiPrivateAuthAction
break;
case 'atom':
header('Content-Type: application/atom+xml; charset=utf-8');
try {
$atom->addEntryFromNotices($this->notices);
$this->raw($atom->getString());
} catch (Atom10FeedException $e) {
$this->serverError(
// TRANS: Server error displayed when generating an Atom feed fails.
// TRANS: %s is the error.
sprintf(_('Could not generate feed for group - %s'),$e->getMessage()),
400,
$this->format
);
return;
}
break;
case 'json':
$this->showJsonTimeline($this->notices);
break;
case 'as':
header('Content-Type: application/json; charset=utf-8');
$doc = new ActivityStreamJSONDocument($this->auth_user);
$doc->setTitle($atom->title);
$doc->addLink($link, 'alternate', 'text/html');
$doc->addItemsFromNotices($this->notices);
$this->raw($doc->asString());
break;
default:
$this->clientError(
// TRANS: Client error displayed when trying to handle an unknown API method.
......
......@@ -168,6 +168,14 @@ class ApiTimelineHomeAction extends ApiBareAuthAction
case 'json':
$this->showJsonTimeline($this->notices);
break;
case 'as':
header('Content-Type: application/json; charset=utf-8');
$doc = new ActivityStreamJSONDocument($this->auth_user);
$doc->setTitle($title);
$doc->addLink($link, 'alternate', 'text/html');
$doc->addItemsFromNotices($this->notices);
$this->raw($doc->asString());
break;
default:
// TRANS: Client error displayed when trying to handle an unknown API method.
$this->clientError(_('API method not found.'), $code = 404);
......
......@@ -169,6 +169,14 @@ class ApiTimelineMentionsAction extends ApiBareAuthAction
case 'json':
$this->showJsonTimeline($this->notices);
break;
case 'as':
header('Content-Type: application/json; charset=utf-8');
$doc = new ActivityStreamJSONDocument($this->auth_user);
$doc->setTitle($title);
$doc->addLink($link, 'alternate', 'text/html');
$doc->addItemsFromNotices($this->notices);
$this->raw($doc->asString());
break;
default:
// TRANS: Client error displayed when trying to handle an unknown API method.
$this->clientError(_('API method not found.'), $code = 404);
......
......@@ -234,6 +234,14 @@ class ApiTimelinePublicAction extends ApiPrivateAuthAction
case 'json':
$this->showJsonTimeline($this->notices);
break;
case 'as':
header('Content-Type: application/json; charset=utf-8');
$doc = new ActivityStreamJSONDocument($this->auth_user);
$doc->setTitle($title);
$doc->addLink($link, 'alternate', 'text/html');
$doc->addItemsFromNotices($this->notices);
$this->raw($doc->asString());
break;
default:
// TRANS: Client error displayed when trying to handle an unknown API method.
$this->clientError(_('API method not found.'), $code = 404);
......
......@@ -92,6 +92,20 @@ class ApiTimelineRetweetedToMeAction extends ApiAuthAction
$offset = ($this->page-1) * $this->cnt;
$limit = $this->cnt;
// TRANS: Title for Atom feed "repeated to me". %s is the user nickname.
$title = sprintf(_("Repeated to %s"), $this->auth_user->nickname);
$subtitle = sprintf(
_('%1$s notices that were to repeated to %2$s / %3$s.'),
$sitename, $this->user->nickname, $profile->getBestName()
);
$taguribase = TagURI::base();
$id = "tag:$taguribase:RepeatedToMe:" . $this->auth_user->id;
$link = common_local_url(
'all',
array('nickname' => $this->auth_user->nickname)
);
$strm = $this->auth_user->repeatedToMe($offset, $limit, $this->since_id, $this->max_id);
switch ($this->format) {
......@@ -102,16 +116,31 @@ class ApiTimelineRetweetedToMeAction extends ApiAuthAction
$this->showJsonTimeline($strm);
break;
case 'atom':
$profile = $this->auth_user->getProfile();
header('Content-Type: application/atom+xml; charset=utf-8');
$atom = new AtomNoticeFeed($this->auth_user);
$atom->setId($id);
$atom->setTitle($title);
$atom->setSubtitle($subtitle);
$atom->setUpdated('now');
$atom->addLink($link);
// TRANS: Title for Atom feed "repeated to me". %s is the user nickname.
$title = sprintf(_("Repeated to %s"), $this->auth_user->nickname);
$taguribase = TagURI::base();
$id = "tag:$taguribase:RepeatedToMe:" . $this->auth_user->id;
$link = common_local_url('all',
array('nickname' => $this->auth_user->nickname));
$id = $this->arg('id');
$this->showAtomTimeline($strm, $title, $id, $link);
$atom->setSelfLink($self);
$atom->addEntryFromNotices($strm);
$this->raw($atom->getString());
break;
case 'as':
header('Content-Type: application/json; charset=utf-8');
$doc = new ActivityStreamJSONDocument($this->auth_user);
$doc->setTitle($title);
$doc->addLink($link, 'alternate', 'text/html');
$doc->addItemsFromNotices($strm);
$this->raw($doc->asString());
break;
default:
// TRANS: Client error displayed when trying to handle an unknown API method.
......
......@@ -93,9 +93,27 @@ class ApiTimelineRetweetsOfMeAction extends ApiAuthAction
$offset = ($this->page-1) * $this->cnt;
$limit = $this->cnt;
$strm = $this->auth_user->repeatsOfMe($offset, $limit, $this->since_id, $this->max_id);
// TRANS: Title of list of repeated notices of the logged in user.