Merge branch '0.9.x' into 1.0.x

Conflicts:
	actions/subscriptions.php
	lib/router.php
	lib/xmppmanager.php
	lib/xmppoutqueuehandler.php
This commit is contained in:
Brion Vibber 2010-10-25 13:08:57 -07:00
commit ca489631db
214 changed files with 46696 additions and 23573 deletions

View File

@ -1166,3 +1166,19 @@ StartShowNoticeForm: before showing the notice form (before <form>)
EndShowNoticeForm: after showing the notice form (after <form>) EndShowNoticeForm: after showing the notice form (after <form>)
- $action: action being executed - $action: action being executed
StartGrantRole: when a role is being assigned
- $profile: profile that will have the role
- $role: string name of the role
EndGrantRole: when a role has been successfully assigned
- $profile: profile that will have the role
- $role: string name of the role
StartRevokeRole: when a role is being revoked
- $profile: profile that will lose the role
- $role: string name of the role
EndRevokeRole: when a role has been revoked
- $profile: profile that lost the role
- $role: string name of the role

3
README
View File

@ -1484,7 +1484,8 @@ If an installation has only one user, this can simplify a lot of the
interface. It also makes the user's profile the root URL. interface. It also makes the user's profile the root URL.
enabled: Whether to run in "single user mode". Default false. enabled: Whether to run in "single user mode". Default false.
nickname: nickname of the single user. nickname: nickname of the single user. If no nickname is specified,
the site owner account will be used (if present).
robotstxt robotstxt
--------- ---------

View File

@ -89,7 +89,7 @@ class AllAction extends ProfileAction
// TRANS: Page title. %1$s is user nickname, %2$d is page number // TRANS: Page title. %1$s is user nickname, %2$d is page number
return sprintf(_('%1$s and friends, page %2$d'), $this->user->nickname, $this->page); return sprintf(_('%1$s and friends, page %2$d'), $this->user->nickname, $this->page);
} else { } else {
// TRANS: Page title. %1$s is user nickname // TRANS: Page title. %s is user nickname
return sprintf(_("%s and friends"), $this->user->nickname); return sprintf(_("%s and friends"), $this->user->nickname);
} }
} }
@ -103,7 +103,7 @@ class AllAction extends ProfileAction
'nickname' => 'nickname' =>
$this->user->nickname) $this->user->nickname)
), ),
// TRANS: %1$s is user nickname // TRANS: %s is user nickname
sprintf(_('Feed for friends of %s (RSS 1.0)'), $this->user->nickname)), sprintf(_('Feed for friends of %s (RSS 1.0)'), $this->user->nickname)),
new Feed(Feed::RSS2, new Feed(Feed::RSS2,
common_local_url( common_local_url(
@ -112,7 +112,7 @@ class AllAction extends ProfileAction
'id' => $this->user->nickname 'id' => $this->user->nickname
) )
), ),
// TRANS: %1$s is user nickname // TRANS: %s is user nickname
sprintf(_('Feed for friends of %s (RSS 2.0)'), $this->user->nickname)), sprintf(_('Feed for friends of %s (RSS 2.0)'), $this->user->nickname)),
new Feed(Feed::ATOM, new Feed(Feed::ATOM,
common_local_url( common_local_url(
@ -121,7 +121,7 @@ class AllAction extends ProfileAction
'id' => $this->user->nickname 'id' => $this->user->nickname
) )
), ),
// TRANS: %1$s is user nickname // TRANS: %s is user nickname
sprintf(_('Feed for friends of %s (Atom)'), $this->user->nickname)) sprintf(_('Feed for friends of %s (Atom)'), $this->user->nickname))
); );
} }
@ -134,18 +134,23 @@ class AllAction extends ProfileAction
function showEmptyListMessage() function showEmptyListMessage()
{ {
// TRANS: %1$s is user nickname // TRANS: %s is user nickname
$message = sprintf(_('This is the timeline for %s and friends but no one has posted anything yet.'), $this->user->nickname) . ' '; $message = sprintf(_('This is the timeline for %s and friends but no one has posted anything yet.'), $this->user->nickname) . ' ';
if (common_logged_in()) { if (common_logged_in()) {
$current_user = common_current_user(); $current_user = common_current_user();
if ($this->user->id === $current_user->id) { if ($this->user->id === $current_user->id) {
// TRANS: Encouragement displayed on logged in user's empty timeline.
// TRANS: This message contains Markdown links. Keep "](" together.
$message .= _('Try subscribing to more people, [join a group](%%action.groups%%) or post something yourself.'); $message .= _('Try subscribing to more people, [join a group](%%action.groups%%) or post something yourself.');
} else { } else {
// TRANS: %1$s is user nickname, %2$s is user nickname, %2$s is user nickname prefixed with "@" // TRANS: %1$s is user nickname, %2$s is user nickname, %2$s is user nickname prefixed with "@"
// TRANS: This message contains Markdown links. Keep "](" together.
$message .= sprintf(_('You can try to [nudge %1$s](../%2$s) from their profile or [post something to them](%%%%action.newnotice%%%%?status_textarea=%3$s).'), $this->user->nickname, $this->user->nickname, '@' . $this->user->nickname); $message .= sprintf(_('You can try to [nudge %1$s](../%2$s) from their profile or [post something to them](%%%%action.newnotice%%%%?status_textarea=%3$s).'), $this->user->nickname, $this->user->nickname, '@' . $this->user->nickname);
} }
} else { } else {
// TRANS: Encoutagement displayed on empty timeline user pages for anonymous users.
// TRANS: %s is a user nickname. This message contains Markdown links. Keep "](" together.
$message .= sprintf(_('Why not [register an account](%%%%action.register%%%%) and then nudge %s or post a notice to them.'), $this->user->nickname); $message .= sprintf(_('Why not [register an account](%%%%action.register%%%%) and then nudge %s or post a notice to them.'), $this->user->nickname);
} }
@ -181,7 +186,7 @@ class AllAction extends ProfileAction
// TRANS: H1 text // TRANS: H1 text
$this->element('h1', null, _("You and friends")); $this->element('h1', null, _("You and friends"));
} else { } else {
// TRANS: H1 text. %1$s is user nickname // TRANS: H1 text. %s is a user nickname
$this->element('h1', null, sprintf(_('%s and friends'), $this->user->nickname)); $this->element('h1', null, sprintf(_('%s and friends'), $this->user->nickname));
} }
} }

View File

@ -45,7 +45,6 @@ require_once INSTALLDIR . '/lib/apiauth.php';
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/ * @link http://status.net/
*/ */
class ApiAccountUpdateDeliveryDeviceAction extends ApiAuthAction class ApiAccountUpdateDeliveryDeviceAction extends ApiAuthAction
{ {
/** /**
@ -56,7 +55,6 @@ class ApiAccountUpdateDeliveryDeviceAction extends ApiAuthAction
* @return boolean success flag * @return boolean success flag
* *
*/ */
function prepare($args) function prepare($args)
{ {
parent::prepare($args); parent::prepare($args);
@ -76,7 +74,6 @@ class ApiAccountUpdateDeliveryDeviceAction extends ApiAuthAction
* *
* @return void * @return void
*/ */
function handle($args) function handle($args)
{ {
parent::handle($args); parent::handle($args);
@ -92,6 +89,7 @@ class ApiAccountUpdateDeliveryDeviceAction extends ApiAuthAction
if (!in_array($this->format, array('xml', 'json'))) { if (!in_array($this->format, array('xml', 'json'))) {
$this->clientError( $this->clientError(
// TRANS: Client error displayed handling a non-existing API method.
_('API method not found.'), _('API method not found.'),
404, 404,
$this->format $this->format
@ -102,16 +100,14 @@ class ApiAccountUpdateDeliveryDeviceAction extends ApiAuthAction
// Note: Twitter no longer supports IM // Note: Twitter no longer supports IM
if (!in_array(strtolower($this->device), array('sms', 'im', 'none'))) { if (!in_array(strtolower($this->device), array('sms', 'im', 'none'))) {
$this->clientError( // TRANS: Client error displayed when no valid device parameter is provided for a user's delivery device setting.
_( $this->clientError(_( 'You must specify a parameter named ' .
'You must specify a parameter named ' . '\'device\' with a value of one of: sms, im, none.' ));
'\'device\' with a value of one of: sms, im, none.'
)
);
return; return;
} }
if (empty($this->user)) { if (empty($this->user)) {
// TRANS: Client error displayed when no existing user is provided for a user's delivery device setting.
$this->clientError(_('No such user.'), 404, $this->format); $this->clientError(_('No such user.'), 404, $this->format);
return; return;
} }
@ -137,6 +133,7 @@ class ApiAccountUpdateDeliveryDeviceAction extends ApiAuthAction
if ($result === false) { if ($result === false) {
common_log_db_error($this->user, 'UPDATE', __FILE__); common_log_db_error($this->user, 'UPDATE', __FILE__);
// TRANS: Server error displayed when a user's delivery device cannot be updated.
$this->serverError(_('Could not update user.')); $this->serverError(_('Could not update user.'));
return; return;
} }
@ -161,5 +158,4 @@ class ApiAccountUpdateDeliveryDeviceAction extends ApiAuthAction
$this->endDocument('json'); $this->endDocument('json');
} }
} }
} }

View File

@ -43,10 +43,8 @@ require_once INSTALLDIR . '/lib/apiauth.php';
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/ * @link http://status.net/
*/ */
class ApiAccountUpdateProfileAction extends ApiAuthAction class ApiAccountUpdateProfileAction extends ApiAuthAction
{ {
/** /**
* Take arguments for running * Take arguments for running
* *
@ -55,7 +53,6 @@ class ApiAccountUpdateProfileAction extends ApiAuthAction
* @return boolean success flag * @return boolean success flag
* *
*/ */
function prepare($args) function prepare($args)
{ {
parent::prepare($args); parent::prepare($args);
@ -79,7 +76,6 @@ class ApiAccountUpdateProfileAction extends ApiAuthAction
* *
* @return void * @return void
*/ */
function handle($args) function handle($args)
{ {
parent::handle($args); parent::handle($args);
@ -103,6 +99,7 @@ class ApiAccountUpdateProfileAction extends ApiAuthAction
} }
if (empty($this->user)) { if (empty($this->user)) {
// TRANS: Client error displayed if a user could not be found.
$this->clientError(_('No such user.'), 404, $this->format); $this->clientError(_('No such user.'), 404, $this->format);
return; return;
} }
@ -110,6 +107,7 @@ class ApiAccountUpdateProfileAction extends ApiAuthAction
$profile = $this->user->getProfile(); $profile = $this->user->getProfile();
if (empty($profile)) { if (empty($profile)) {
// TRANS: Client error displayed if a user profile could not be found.
$this->clientError(_('User has no profile.')); $this->clientError(_('User has no profile.'));
return; return;
} }
@ -145,6 +143,7 @@ class ApiAccountUpdateProfileAction extends ApiAuthAction
if (!$result) { if (!$result) {
common_log_db_error($profile, 'UPDATE', __FILE__); common_log_db_error($profile, 'UPDATE', __FILE__);
// TRANS: Server error displayed if a user profile could not be saved.
$this->serverError(_('Could not save profile.')); $this->serverError(_('Could not save profile.'));
return; return;
} }
@ -163,5 +162,4 @@ class ApiAccountUpdateProfileAction extends ApiAuthAction
$this->endDocument('json'); $this->endDocument('json');
} }
} }
} }

View File

@ -42,10 +42,8 @@ require_once INSTALLDIR . '/lib/apiauth.php';
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/ * @link http://status.net/
*/ */
class ApiAccountUpdateProfileBackgroundImageAction extends ApiAuthAction class ApiAccountUpdateProfileBackgroundImageAction extends ApiAuthAction
{ {
var $tile = false; var $tile = false;
/** /**
@ -56,7 +54,6 @@ class ApiAccountUpdateProfileBackgroundImageAction extends ApiAuthAction
* @return boolean success flag * @return boolean success flag
* *
*/ */
function prepare($args) function prepare($args)
{ {
parent::prepare($args); parent::prepare($args);
@ -76,7 +73,6 @@ class ApiAccountUpdateProfileBackgroundImageAction extends ApiAuthAction
* *
* @return void * @return void
*/ */
function handle($args) function handle($args)
{ {
parent::handle($args); parent::handle($args);
@ -92,6 +88,7 @@ class ApiAccountUpdateProfileBackgroundImageAction extends ApiAuthAction
if (!in_array($this->format, array('xml', 'json'))) { if (!in_array($this->format, array('xml', 'json'))) {
$this->clientError( $this->clientError(
// TRANS: Client error displayed when trying to handle an unknown API method.
_('API method not found.'), _('API method not found.'),
404, 404,
$this->format $this->format
@ -106,8 +103,11 @@ class ApiAccountUpdateProfileBackgroundImageAction extends ApiAuthAction
&& empty($_POST) && empty($_POST)
&& ($_SERVER['CONTENT_LENGTH'] > 0) && ($_SERVER['CONTENT_LENGTH'] > 0)
) { ) {
$msg = _('The server was unable to handle that much POST ' . // TRANS: Client error displayed when the number of bytes in a POST request exceeds a limit.
'data (%s bytes) due to its current configuration.'); // TRANS: %s is the number of bytes of the CONTENT_LENGTH.
$msg = _m('The server was unable to handle that much POST data (%s byte) due to its current configuration.',
'The server was unable to handle that much POST data (%s bytes) due to its current configuration.',
intval($_SERVER['CONTENT_LENGTH']));
$this->clientError(sprintf($msg, $_SERVER['CONTENT_LENGTH'])); $this->clientError(sprintf($msg, $_SERVER['CONTENT_LENGTH']));
return; return;
@ -125,7 +125,6 @@ class ApiAccountUpdateProfileBackgroundImageAction extends ApiAuthAction
// is part of the img filename. // is part of the img filename.
if (empty($design)) { if (empty($design)) {
$this->user->query('BEGIN'); $this->user->query('BEGIN');
// save new design // save new design
@ -134,6 +133,7 @@ class ApiAccountUpdateProfileBackgroundImageAction extends ApiAuthAction
if (empty($id)) { if (empty($id)) {
common_log_db_error($id, 'INSERT', __FILE__); common_log_db_error($id, 'INSERT', __FILE__);
// TRANS: Client error displayed when saving design settings fails because of an empty id.
$this->clientError(_('Unable to save your design settings.')); $this->clientError(_('Unable to save your design settings.'));
return; return;
} }
@ -144,6 +144,7 @@ class ApiAccountUpdateProfileBackgroundImageAction extends ApiAuthAction
if (empty($result)) { if (empty($result)) {
common_log_db_error($original, 'UPDATE', __FILE__); common_log_db_error($original, 'UPDATE', __FILE__);
// TRANS: Client error displayed when saving design settings fails because of an empty result.
$this->clientError(_('Unable to save your design settings.')); $this->clientError(_('Unable to save your design settings.'));
$this->user->query('ROLLBACK'); $this->user->query('ROLLBACK');
return; return;
@ -185,6 +186,7 @@ class ApiAccountUpdateProfileBackgroundImageAction extends ApiAuthAction
if ($result === false) { if ($result === false) {
common_log_db_error($design, 'UPDATE', __FILE__); common_log_db_error($design, 'UPDATE', __FILE__);
// TRANS: Error displayed when updating design settings fails.
$this->showForm(_('Could not update your design.')); $this->showForm(_('Could not update your design.'));
return; return;
} }
@ -192,6 +194,7 @@ class ApiAccountUpdateProfileBackgroundImageAction extends ApiAuthAction
$profile = $this->user->getProfile(); $profile = $this->user->getProfile();
if (empty($profile)) { if (empty($profile)) {
// TRANS: Client error displayed when a user has no profile.
$this->clientError(_('User has no profile.')); $this->clientError(_('User has no profile.'));
return; return;
} }
@ -208,5 +211,4 @@ class ApiAccountUpdateProfileBackgroundImageAction extends ApiAuthAction
$this->endDocument('json'); $this->endDocument('json');
} }
} }
} }

View File

@ -95,9 +95,11 @@ class ApiAccountUpdateProfileImageAction extends ApiAuthAction
&& empty($_POST) && empty($_POST)
&& ($_SERVER['CONTENT_LENGTH'] > 0) && ($_SERVER['CONTENT_LENGTH'] > 0)
) { ) {
$msg = _('The server was unable to handle that much POST ' . // TRANS: Client error displayed when the number of bytes in a POST request exceeds a limit.
'data (%s bytes) due to its current configuration.'); // TRANS: %s is the number of bytes of the CONTENT_LENGTH.
$msg = _m('The server was unable to handle that much POST data (%s byte) due to its current configuration.',
'The server was unable to handle that much POST data (%s bytes) due to its current configuration.',
intval($_SERVER['CONTENT_LENGTH']));
$this->clientError(sprintf($msg, $_SERVER['CONTENT_LENGTH'])); $this->clientError(sprintf($msg, $_SERVER['CONTENT_LENGTH']));
return; return;
} }

View File

@ -46,7 +46,6 @@ require_once INSTALLDIR . '/lib/apiauth.php';
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/ * @link http://status.net/
*/ */
class ApiBlockCreateAction extends ApiAuthAction class ApiBlockCreateAction extends ApiAuthAction
{ {
var $other = null; var $other = null;
@ -59,7 +58,6 @@ class ApiBlockCreateAction extends ApiAuthAction
* @return boolean success flag * @return boolean success flag
* *
*/ */
function prepare($args) function prepare($args)
{ {
parent::prepare($args); parent::prepare($args);
@ -79,7 +77,6 @@ class ApiBlockCreateAction extends ApiAuthAction
* *
* @return void * @return void
*/ */
function handle($args) function handle($args)
{ {
parent::handle($args); parent::handle($args);
@ -103,6 +100,7 @@ class ApiBlockCreateAction extends ApiAuthAction
if ($this->user->id == $this->other->id) { if ($this->user->id == $this->other->id) {
$this->clientError( $this->clientError(
// TRANS: Client error displayed when users try to block themselves.
_("You cannot block yourself!"), _("You cannot block yourself!"),
403, 403,
$this->format $this->format
@ -124,10 +122,8 @@ class ApiBlockCreateAction extends ApiAuthAction
$this->showProfile($this->other, $this->format); $this->showProfile($this->other, $this->format);
$this->endDocument($this->format); $this->endDocument($this->format);
} else { } else {
// TRANS: Server error displayed when blocking a user has failed.
$this->serverError(_('Block user failed.'), 500, $this->format); $this->serverError(_('Block user failed.'), 500, $this->format);
} }
} }
} }

View File

@ -45,7 +45,6 @@ require_once INSTALLDIR . '/lib/apiauth.php';
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/ * @link http://status.net/
*/ */
class ApiBlockDestroyAction extends ApiAuthAction class ApiBlockDestroyAction extends ApiAuthAction
{ {
var $other = null; var $other = null;
@ -58,7 +57,6 @@ class ApiBlockDestroyAction extends ApiAuthAction
* @return boolean success flag * @return boolean success flag
* *
*/ */
function prepare($args) function prepare($args)
{ {
parent::prepare($args); parent::prepare($args);
@ -78,7 +76,6 @@ class ApiBlockDestroyAction extends ApiAuthAction
* *
* @return void * @return void
*/ */
function handle($args) function handle($args)
{ {
parent::handle($args); parent::handle($args);
@ -112,10 +109,8 @@ class ApiBlockDestroyAction extends ApiAuthAction
$this->showProfile($this->other, $this->format); $this->showProfile($this->other, $this->format);
$this->endDocument($this->format); $this->endDocument($this->format);
} else { } else {
// TRANS: Server error displayed when unblocking a user has failed.
$this->serverError(_('Unblock user failed.')); $this->serverError(_('Unblock user failed.'));
} }
} }
} }

View File

@ -121,9 +121,9 @@ class ApiDirectMessageNewAction extends ApiAuthAction
} else { } else {
$content_shortened = common_shorten_links($this->content); $content_shortened = common_shorten_links($this->content);
if (Message::contentTooLong($content_shortened)) { if (Message::contentTooLong($content_shortened)) {
// TRANS: Client error displayed when message content is too long.
// TRANS: %d is the maximum number of characters for a message.
$this->clientError( $this->clientError(
// TRANS: Client error displayed when message content is too long.
// TRANS: %d is the maximum number of characters for a message.
sprintf(_m('That\'s too long. Maximum message size is %d character.', 'That\'s too long. Maximum message size is %d characters.', Message::maxContent()), sprintf(_m('That\'s too long. Maximum message size is %d character.', 'That\'s too long. Maximum message size is %d characters.', Message::maxContent()),
Message::maxContent() Message::maxContent()
), ),

View File

@ -48,7 +48,6 @@ require_once INSTALLDIR . '/lib/apiauth.php';
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/ * @link http://status.net/
*/ */
class ApiFavoriteCreateAction extends ApiAuthAction class ApiFavoriteCreateAction extends ApiAuthAction
{ {
var $notice = null; var $notice = null;
@ -61,7 +60,6 @@ class ApiFavoriteCreateAction extends ApiAuthAction
* @return boolean success flag * @return boolean success flag
* *
*/ */
function prepare($args) function prepare($args)
{ {
parent::prepare($args); parent::prepare($args);
@ -81,7 +79,6 @@ class ApiFavoriteCreateAction extends ApiAuthAction
* *
* @return void * @return void
*/ */
function handle($args) function handle($args)
{ {
parent::handle($args); parent::handle($args);
@ -107,6 +104,7 @@ class ApiFavoriteCreateAction extends ApiAuthAction
if (empty($this->notice)) { if (empty($this->notice)) {
$this->clientError( $this->clientError(
// TRANS: Client error displayed when requesting a status with a non-existing ID.
_('No status found with that ID.'), _('No status found with that ID.'),
404, 404,
$this->format $this->format
@ -118,6 +116,7 @@ class ApiFavoriteCreateAction extends ApiAuthAction
if ($this->user->hasFave($this->notice)) { if ($this->user->hasFave($this->notice)) {
$this->clientError( $this->clientError(
// TRANS: Client error displayed when trying to mark a notice favourite that already is a favourite.
_('This status is already a favorite.'), _('This status is already a favorite.'),
403, 403,
$this->format $this->format
@ -129,6 +128,7 @@ class ApiFavoriteCreateAction extends ApiAuthAction
if (empty($fave)) { if (empty($fave)) {
$this->clientError( $this->clientError(
// TRANS: Client error displayed when marking a notice as favourite fails.
_('Could not create favorite.'), _('Could not create favorite.'),
403, 403,
$this->format $this->format
@ -166,5 +166,4 @@ class ApiFavoriteCreateAction extends ApiAuthAction
// XXX: notify by SMS // XXX: notify by SMS
} }
} }
} }

View File

@ -49,7 +49,6 @@ require_once INSTALLDIR . '/lib/apiauth.php';
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/ * @link http://status.net/
*/ */
class ApiGroupCreateAction extends ApiAuthAction class ApiGroupCreateAction extends ApiAuthAction
{ {
var $group = null; var $group = null;
@ -95,7 +94,6 @@ class ApiGroupCreateAction extends ApiAuthAction
* *
* @return void * @return void
*/ */
function handle($args) function handle($args)
{ {
parent::handle($args); parent::handle($args);
@ -111,6 +109,7 @@ class ApiGroupCreateAction extends ApiAuthAction
} }
if (empty($this->user)) { if (empty($this->user)) {
// TRANS: Client error given when a user was not found (404).
$this->clientError(_('No such user.'), 404, $this->format); $this->clientError(_('No such user.'), 404, $this->format);
return; return;
} }
@ -137,13 +136,13 @@ class ApiGroupCreateAction extends ApiAuthAction
break; break;
default: default:
$this->clientError( $this->clientError(
// TRANS: Client error given when an API method was not found (404).
_('API method not found.'), _('API method not found.'),
404, 404,
$this->format $this->format
); );
break; break;
} }
} }
/** /**
@ -164,6 +163,7 @@ class ApiGroupCreateAction extends ApiAuthAction
if (!$valid) { if (!$valid) {
$this->clientError( $this->clientError(
// TRANS: Validation error in form for group creation.
_( _(
'Nickname must have only lowercase letters ' . 'Nickname must have only lowercase letters ' .
'and numbers and no spaces.' 'and numbers and no spaces.'
@ -174,6 +174,7 @@ class ApiGroupCreateAction extends ApiAuthAction
return false; return false;
} elseif ($this->groupNicknameExists($this->nickname)) { } elseif ($this->groupNicknameExists($this->nickname)) {
$this->clientError( $this->clientError(
// TRANS: Client error trying to create a group with a nickname this is already in use.
_('Nickname already in use. Try another one.'), _('Nickname already in use. Try another one.'),
403, 403,
$this->format $this->format
@ -181,6 +182,7 @@ class ApiGroupCreateAction extends ApiAuthAction
return false; return false;
} else if (!User_group::allowedNickname($this->nickname)) { } else if (!User_group::allowedNickname($this->nickname)) {
$this->clientError( $this->clientError(
// TRANS: Client error in form for group creation.
_('Not a valid nickname.'), _('Not a valid nickname.'),
403, 403,
$this->format $this->format
@ -197,6 +199,7 @@ class ApiGroupCreateAction extends ApiAuthAction
) )
)) { )) {
$this->clientError( $this->clientError(
// TRANS: Client error in form for group creation.
_('Homepage is not a valid URL.'), _('Homepage is not a valid URL.'),
403, 403,
$this->format $this->format
@ -206,7 +209,8 @@ class ApiGroupCreateAction extends ApiAuthAction
!is_null($this->fullname) !is_null($this->fullname)
&& mb_strlen($this->fullname) > 255) { && mb_strlen($this->fullname) > 255) {
$this->clientError( $this->clientError(
_('Full name is too long (max 255 chars).'), // TRANS: Client error in form for group creation.
_('Full name is too long (maximum 255 characters).'),
403, 403,
$this->format $this->format
); );
@ -225,7 +229,7 @@ class ApiGroupCreateAction extends ApiAuthAction
!is_null($this->location) !is_null($this->location)
&& mb_strlen($this->location) > 255) { && mb_strlen($this->location) > 255) {
$this->clientError( $this->clientError(
_('Location is too long (max 255 chars).'), _('Location is too long (maximum 255 characters).'),
403, 403,
$this->format $this->format
); );

View File

@ -78,9 +78,11 @@ class ApiMediaUploadAction extends ApiAuthAction
&& empty($_POST) && empty($_POST)
&& ($_SERVER['CONTENT_LENGTH'] > 0) && ($_SERVER['CONTENT_LENGTH'] > 0)
) { ) {
$msg = _('The server was unable to handle that much POST ' . // TRANS: Client error displayed when the number of bytes in a POST request exceeds a limit.
'data (%s bytes) due to its current configuration.'); // TRANS: %s is the number of bytes of the CONTENT_LENGTH.
$msg = _m('The server was unable to handle that much POST data (%s byte) due to its current configuration.',
'The server was unable to handle that much POST data (%s bytes) due to its current configuration.',
intval($_SERVER['CONTENT_LENGTH']));
$this->clientError(sprintf($msg, $_SERVER['CONTENT_LENGTH'])); $this->clientError(sprintf($msg, $_SERVER['CONTENT_LENGTH']));
return; return;
} }

View File

@ -44,7 +44,6 @@ require_once INSTALLDIR . '/lib/apioauth.php';
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/ * @link http://status.net/
*/ */
class ApiOauthAccessTokenAction extends ApiOauthAction class ApiOauthAccessTokenAction extends ApiOauthAction
{ {
protected $reqToken = null; protected $reqToken = null;
@ -73,15 +72,15 @@ class ApiOauthAccessTokenAction extends ApiOauthAction
// Spec doesn't say they MUST be. // Spec doesn't say they MUST be.
try { try {
$req = OAuthRequest::from_request(); $req = OAuthRequest::from_request();
$this->reqToken = $req->get_parameter('oauth_token'); $this->reqToken = $req->get_parameter('oauth_token');
$this->verifier = $req->get_parameter('oauth_verifier'); $this->verifier = $req->get_parameter('oauth_verifier');
$app = $datastore->getAppByRequestToken($this->reqToken);
$app = $datastore->getAppByRequestToken($this->reqToken);
$atok = $server->fetch_access_token($req); $atok = $server->fetch_access_token($req);
} catch (OAuthException $e) { } catch (Exception $e) {
common_log(LOG_WARNING, 'API OAuthException - ' . $e->getMessage()); common_log(LOG_WARNING, 'API OAuthException - ' . $e->getMessage());
common_debug(var_export($req, true)); common_debug(var_export($req, true));
$code = $e->getCode(); $code = $e->getCode();
@ -99,14 +98,15 @@ class ApiOauthAccessTokenAction extends ApiOauthAction
$this->verifier $this->verifier
); );
common_log(LOG_WARNIGN, $msg); 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 { } else {
common_log( common_log(
LOG_INFO, LOG_INFO,
sprintf( sprintf(
"Issued now access token '%s' for application %d (%s).", "Issued access token '%s' for application %d (%s).",
$atok->key, $atok->key,
$app->id, $app->id,
$app->name $app->name

View File

@ -35,7 +35,7 @@ require_once INSTALLDIR . '/lib/apioauth.php';
require_once INSTALLDIR . '/lib/info.php'; require_once INSTALLDIR . '/lib/info.php';
/** /**
* Authorize an OAuth request token * Authorize an Oputh request token
* *
* @category API * @category API
* @package StatusNet * @package StatusNet
@ -43,7 +43,6 @@ require_once INSTALLDIR . '/lib/info.php';
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/ * @link http://status.net/
*/ */
class ApiOauthAuthorizeAction extends Action class ApiOauthAuthorizeAction extends Action
{ {
var $oauthTokenParam; var $oauthTokenParam;
@ -69,11 +68,11 @@ class ApiOauthAuthorizeAction extends Action
{ {
parent::prepare($args); parent::prepare($args);
$this->nickname = $this->trimmed('nickname'); $this->nickname = $this->trimmed('nickname');
$this->password = $this->arg('password'); $this->password = $this->arg('password');
$this->oauthTokenParam = $this->arg('oauth_token'); $this->oauthTokenParam = $this->arg('oauth_token');
$this->callback = $this->arg('oauth_callback'); $this->mode = $this->arg('mode');
$this->store = new ApiStatusNetOAuthDataStore(); $this->store = new ApiStatusNetOAuthDataStore();
try { try {
$this->app = $this->store->getAppByRequestToken($this->oauthTokenParam); $this->app = $this->store->getAppByRequestToken($this->oauthTokenParam);
@ -93,7 +92,6 @@ class ApiOauthAuthorizeAction extends Action
* *
* @return void * @return void
*/ */
function handle($args) function handle($args)
{ {
parent::handle($args); parent::handle($args);
@ -106,6 +104,7 @@ class ApiOauthAuthorizeAction extends Action
// Make sure a oauth_token parameter was provided // Make sure a oauth_token parameter was provided
if (empty($this->oauthTokenParam)) { if (empty($this->oauthTokenParam)) {
// TRANS: Client error given when no oauth_token was passed to the OAuth API.
$this->clientError(_('No oauth_token parameter provided.')); $this->clientError(_('No oauth_token parameter provided.'));
} else { } else {
@ -113,18 +112,21 @@ class ApiOauthAuthorizeAction extends Action
$this->reqToken = $this->store->getTokenByKey($this->oauthTokenParam); $this->reqToken = $this->store->getTokenByKey($this->oauthTokenParam);
if (empty($this->reqToken)) { if (empty($this->reqToken)) {
// TRANS: Client error given when an invalid request token was passed to the OAuth API.
$this->clientError(_('Invalid request token.')); $this->clientError(_('Invalid request token.'));
} else { } else {
// Check to make sure we haven't already authorized the token // Check to make sure we haven't already authorized the token
if ($this->reqToken->state != 0) { if ($this->reqToken->state != 0) {
$this->clientError(_("Invalid request token.")); // TRANS: Client error given when an invalid request token was passed to the OAuth API.
$this->clientError(_('Request token already authorized.'));
} }
} }
} }
// make sure there's an app associated with this token // make sure there's an app associated with this token
if (empty($this->app)) { if (empty($this->app)) {
// TRANS: Client error given when an invalid request token was passed to the OAuth API.
$this->clientError(_('Invalid request token.')); $this->clientError(_('Invalid request token.'));
} }
@ -154,10 +156,15 @@ class ApiOauthAuthorizeAction extends Action
// XXX Force credentials check? // XXX Force credentials check?
// XXX OpenID // @fixme this should probably use a unified login form handler
$user = null;
if (Event::handle('StartOAuthLoginCheck', array($this, &$user))) {
$user = common_check_user($this->nickname, $this->password);
}
Event::handle('EndOAuthLoginCheck', array($this, &$user));
$user = common_check_user($this->nickname, $this->password);
if (empty($user)) { if (empty($user)) {
// TRANS: Form validation error given when an invalid username and/or password was passed to the OAuth API.
$this->showForm(_("Invalid nickname / password!")); $this->showForm(_("Invalid nickname / password!"));
return; return;
} }
@ -165,10 +172,11 @@ class ApiOauthAuthorizeAction extends Action
$user = common_current_user(); $user = common_current_user();
} }
if ($this->arg('allow')) { // fetch the token
$this->reqToken = $this->store->getTokenByKey($this->oauthTokenParam);
assert(!empty($this->reqToken));
// fetch the token if ($this->arg('allow')) {
$this->reqToken = $this->store->getTokenByKey($this->oauthTokenParam);
// mark the req token as authorized // mark the req token as authorized
try { try {
@ -177,69 +185,56 @@ class ApiOauthAuthorizeAction extends Action
$this->serverError($e->getMessage()); $this->serverError($e->getMessage());
} }
// Check to see if there was a previous token associated common_log(
// with this user/app and kill it. If the user is doing this she LOG_INFO,
// probably doesn't want any old tokens anyway. sprintf(
"API OAuth - User %d (%s) has authorized request token %s for OAuth application %d (%s).",
$user->id,
$user->nickname,
$this->reqToken->tok,
$this->app->id,
$this->app->name
)
);
$appUser = Oauth_application_user::getByKeys($user, $this->app); // XXX: Make sure we have a oauth_token_association table. The table
// is now in the main schema, but because it is being added with
// a point release, it's unlikely to be there. This code can be
// removed as of 1.0.
$this->ensureOauthTokenAssociationTable();
if (!empty($appUser)) { $tokenAssoc = new Oauth_token_association();
$result = $appUser->delete();
if (!$result) { $tokenAssoc->profile_id = $user->id;
common_log_db_error($appUser, 'DELETE', __FILE__); $tokenAssoc->application_id = $this->app->id;
$this->serverError(_('Database error deleting OAuth application user.')); $tokenAssoc->token = $this->oauthTokenParam;
} $tokenAssoc->created = common_sql_now();
}
// associated the authorized req token with the user and the app $result = $tokenAssoc->insert();
$appUser = new Oauth_application_user();
$appUser->profile_id = $user->id;
$appUser->application_id = $this->app->id;
// Note: do not copy the access type from the application.
// The access type should always be 0 when the OAuth app
// user record has a request token associated with it.
// Access type gets assigned once an access token has been
// granted. The OAuth app user record then gets updated
// with the new access token and access type.
$appUser->token = $this->oauthTokenParam;
$appUser->created = common_sql_now();
$result = $appUser->insert();
if (!$result) { if (!$result) {
common_log_db_error($appUser, 'INSERT', __FILE__); common_log_db_error($tokenAssoc, 'INSERT', __FILE__);
$this->serverError(_('Database error inserting OAuth application user.')); // TRANS: Server error displayed when a database action fails.
$this->serverError(_('Database error inserting oauth_token_association.'));
} }
// If we have a callback redirect and provide the token $callback = $this->getCallback();
// Note: A callback specified in the app setup overrides whatever if (!empty($callback) && $this->reqToken->verified_callback != 'oob') {
// is passed in with the request. $targetUrl = $this->buildCallbackUrl(
$callback,
if (!empty($this->app->callback_url)) {
$this->callback = $this->app->callback_url;
}
if (!empty($this->callback)) {
$targetUrl = $this->getCallback(
$this->callback,
array( array(
'oauth_token' => $this->oauthTokenParam, 'oauth_token' => $this->oauthTokenParam,
'oauth_verifier' => $this->reqToken->verifier // 1.0a 'oauth_verifier' => $this->reqToken->verifier // 1.0a
) )
); );
common_log(LOG_INFO, "Redirecting to callback: $targetUrl");
// Redirect the user to the provided OAuth callback // Redirect the user to the provided OAuth callback
common_redirect($targetUrl, 303); common_redirect($targetUrl, 303);
} elseif ($this->app->type == 2) { } elseif ($this->app->type == 2) {
// Strangely, a web application seems to want to do the OOB // Strangely, a web application seems to want to do the OOB
// workflow. Because no callback was specified anywhere. // workflow. Because no callback was specified anywhere.
common_log( common_log(
@ -253,33 +248,123 @@ class ApiOauthAuthorizeAction extends Action
); );
} }
common_log(
LOG_INFO,
sprintf(
"The request token '%s' for OAuth application %s (%s) has been authorized.",
$this->oauthTokenParam,
$this->app->id,
$this->app->name
)
);
// Otherwise, inform the user that the rt was authorized // Otherwise, inform the user that the rt was authorized
$this->showAuthorized(); $this->showAuthorized();
} else if ($this->arg('cancel')) { } else if ($this->arg('cancel')) {
common_log(
LOG_INFO,
sprintf(
"API OAuth - User %d (%s) refused to authorize request token %s for OAuth application %d (%s).",
$user->id,
$user->nickname,
$this->reqToken->tok,
$this->app->id,
$this->app->name
)
);
try { try {
$this->store->revoke_token($this->oauthTokenParam, 0); $this->store->revoke_token($this->oauthTokenParam, 0);
$this->showCanceled();
} catch (Exception $e) { } catch (Exception $e) {
$this->ServerError($e->getMessage()); $this->ServerError($e->getMessage());
} }
$callback = $this->getCallback();
// If there's a callback available, inform the consumer the user
// has refused authorization
if (!empty($callback) && $this->reqToken->verified_callback != 'oob') {
$targetUrl = $this->buildCallbackUrl(
$callback,
array(
'oauth_problem' => 'user_refused',
)
);
common_log(LOG_INFO, "Redirecting to callback: $targetUrl");
// Redirect the user to the provided OAuth callback
common_redirect($targetUrl, 303);
}
// otherwise inform the user that authorization for the rt was declined
$this->showCanceled();
} else { } else {
// TRANS: Client error given on when invalid data was passed through a form in the OAuth API.
$this->clientError(_('Unexpected form submission.')); $this->clientError(_('Unexpected form submission.'));
} }
} }
// XXX Remove this function when we hit 1.0
function ensureOauthTokenAssociationTable()
{
$schema = Schema::get();
$reqTokenCols = array(
new ColumnDef('profile_id', 'integer', null, true, 'PRI'),
new ColumnDef('application_id', 'integer', null, true, 'PRI'),
new ColumnDef('token', 'varchar', 255, true, 'PRI'),
new ColumnDef('created', 'datetime', null, false),
new ColumnDef(
'modified',
'timestamp',
null,
false,
null,
'CURRENT_TIMESTAMP',
'on update CURRENT_TIMESTAMP'
)
);
$schema->ensureTable('oauth_token_association', $reqTokenCols);
}
/**
* Show body - override to add a special CSS class for the authorize
* page's "desktop mode" (minimal display)
*
* Calls template methods
*
* @return nothing
*/
function showBody()
{
$bodyClasses = array();
if ($this->desktopMode()) {
$bodyClasses[] = 'oauth-desktop-mode';
}
if (common_current_user()) {
$bodyClasses[] = 'user_in';
}
$attrs = array('id' => strtolower($this->trimmed('action')));
if (!empty($bodyClasses)) {
$attrs['class'] = implode(' ', $bodyClasses);
}
$this->elementStart('body', $attrs);
$this->elementStart('div', array('id' => 'wrap'));
if (Event::handle('StartShowHeader', array($this))) {
$this->showHeader();
Event::handle('EndShowHeader', array($this));
}
$this->showCore();
if (Event::handle('StartShowFooter', array($this))) {
$this->showFooter();
Event::handle('EndShowFooter', array($this));
}
$this->elementEnd('div');
$this->showScripts();
$this->elementEnd('body');
}
function showForm($error=null) function showForm($error=null)
{ {
$this->error = $error; $this->error = $error;
@ -299,9 +384,9 @@ class ApiOauthAuthorizeAction extends Action
* *
* @return string title of the page * @return string title of the page
*/ */
function title() function title()
{ {
// TRANS: Title for a page where a user can confirm/deny account access by an external application.
return _('An application would like to connect to your account'); return _('An application would like to connect to your account');
} }
@ -310,7 +395,6 @@ class ApiOauthAuthorizeAction extends Action
* *
* @return void * @return void
*/ */
function showContent() function showContent()
{ {
$this->elementStart('form', array('method' => 'post', $this->elementStart('form', array('method' => 'post',
@ -319,27 +403,40 @@ class ApiOauthAuthorizeAction extends Action
'action' => common_local_url('ApiOauthAuthorize'))); 'action' => common_local_url('ApiOauthAuthorize')));
$this->elementStart('fieldset'); $this->elementStart('fieldset');
$this->element('legend', array('id' => 'apioauthauthorize_allowdeny'), $this->element('legend', array('id' => 'apioauthauthorize_allowdeny'),
// TRANS: Fieldset legend.
_('Allow or deny access')); _('Allow or deny access'));
$this->hidden('token', common_session_token()); $this->hidden('token', common_session_token());
$this->hidden('mode', $this->mode);
$this->hidden('oauth_token', $this->oauthTokenParam); $this->hidden('oauth_token', $this->oauthTokenParam);
$this->hidden('oauth_callback', $this->callback); $this->hidden('oauth_callback', $this->callback);
$this->elementStart('ul', 'form_data'); $this->elementStart('ul', 'form_data');
$this->elementStart('li'); $this->elementStart('li');
$this->elementStart('p'); $this->elementStart('p');
if (!empty($this->app->icon)) { if (!empty($this->app->icon) && $this->app->name != 'anonymous') {
$this->element('img', array('src' => $this->app->icon)); $this->element('img', array('src' => $this->app->icon));
} }
$access = ($this->app->access_type & Oauth_application::$writeAccess) ? $access = ($this->app->access_type & Oauth_application::$writeAccess) ?
'access and update' : 'access'; 'access and update' : 'access';
$msg = _('The application <strong>%1$s</strong> by ' . // TRANS: User notification of external application requesting account access.
'<strong>%2$s</strong> would like the ability ' . // TRANS: %1$s is the application name requesting access, %2$s is the organisation behind the application,
// TRANS: %3$s is the access type requested, %4$s is the StatusNet sitename.
if ($this->app->name == 'anonymous') {
// Special message for the anonymous app and consumer
$msg = _('An application would like the ability ' .
'to <strong>%3$s</strong> your %4$s account data. ' . 'to <strong>%3$s</strong> your %4$s account data. ' .
'You should only give access to your %4$s account ' . 'You should only give access to your %4$s account ' .
'to third parties you trust.'); 'to third parties you trust.');
} else {
$msg = _('The application <strong>%1$s</strong> by ' .
'<strong>%2$s</strong> would like the ability ' .
'to <strong>%3$s</strong> your %4$s account data. ' .
'You should only give access to your %4$s account ' .
'to third parties you trust.');
}
$this->raw(sprintf($msg, $this->raw(sprintf($msg,
$this->app->name, $this->app->name,
@ -350,34 +447,43 @@ class ApiOauthAuthorizeAction extends Action
$this->elementEnd('li'); $this->elementEnd('li');
$this->elementEnd('ul'); $this->elementEnd('ul');
// quickie hack
$button = false;
if (!common_logged_in()) { if (!common_logged_in()) {
if (Event::handle('StartOAuthLoginForm', array($this, &$button))) {
$this->elementStart('fieldset');
// TRANS: Fieldset legend.
$this->element('legend', null, _m('LEGEND','Account'));
$this->elementStart('ul', 'form_data');
$this->elementStart('li');
// TRANS: Field label on OAuth API authorisation form.
$this->input('nickname', _('Nickname'));
$this->elementEnd('li');
$this->elementStart('li');
// TRANS: Field label on OAuth API authorisation form.
$this->password('password', _('Password'));
$this->elementEnd('li');
$this->elementEnd('ul');
$this->elementStart('fieldset'); $this->elementEnd('fieldset');
$this->element('legend', null, _('Account')); }
$this->elementStart('ul', 'form_data'); Event::handle('EndOAuthLoginForm', array($this, &$button));
$this->elementStart('li');
$this->input('nickname', _('Nickname'));
$this->elementEnd('li');
$this->elementStart('li');
$this->password('password', _('Password'));
$this->elementEnd('li');
$this->elementEnd('ul');
$this->elementEnd('fieldset');
} }
$this->element('input', array('id' => 'cancel_submit', $this->element('input', array('id' => 'cancel_submit',
'class' => 'submit submit form_action-primary', 'class' => 'submit submit form_action-primary',
'name' => 'cancel', 'name' => 'cancel',
'type' => 'submit', 'type' => 'submit',
'value' => _('Cancel'))); // TRANS: Button text that when clicked will cancel the process of allowing access to an account
// TRANS: by an external application.
'value' => _m('BUTTON','Cancel')));
$this->element('input', array('id' => 'allow_submit', $this->element('input', array('id' => 'allow_submit',
'class' => 'submit submit form_action-secondary', 'class' => 'submit submit form_action-secondary',
'name' => 'allow', 'name' => 'allow',
'type' => 'submit', 'type' => 'submit',
'value' => _('Allow'))); // TRANS: Button text that when clicked will allow access to an account by an external application.
'value' => $button ? $button : _m('BUTTON','Allow')));
$this->elementEnd('fieldset'); $this->elementEnd('fieldset');
$this->elementEnd('form'); $this->elementEnd('form');
@ -391,9 +497,9 @@ class ApiOauthAuthorizeAction extends Action
* *
* @return void * @return void
*/ */
function getInstructions() function getInstructions()
{ {
// TRANS: Form instructions.
return _('Authorize access to your account information.'); return _('Authorize access to your account information.');
} }
@ -404,18 +510,61 @@ class ApiOauthAuthorizeAction extends Action
* *
* @return void * @return void
*/ */
function showLocalNav() function showLocalNav()
{ {
// NOP // NOP
} }
/*
* Checks to see if a the "mode" parameter is present in the request
* and set to "desktop". If it is, the page is meant to be displayed in
* a small frame of another application, and we should suppress the
* header, aside, and footer.
*/
function desktopMode()
{
if (isset($this->mode) && $this->mode == 'desktop') {
return true;
} else {
return false;
}
}
/*
* Override - suppress output in "desktop" mode
*/
function showHeader()
{
if ($this->desktopMode() == false) {
parent::showHeader();
}
}
/*
* Override - suppress output in "desktop" mode
*/
function showAside()
{
if ($this->desktopMode() == false) {
parent::showAside();
}
}
/*
* Override - suppress output in "desktop" mode
*/
function showFooter()
{
if ($this->desktopMode() == false) {
parent::showFooter();
}
}
/** /**
* Show site notice. * Show site notice.
* *
* @return nothing * @return nothing
*/ */
function showSiteNotice() function showSiteNotice()
{ {
// NOP // NOP
@ -428,7 +577,6 @@ class ApiOauthAuthorizeAction extends Action
* *
* @return nothing * @return nothing
*/ */
function showNoticeForm() function showNoticeForm()
{ {
// NOP // NOP
@ -440,14 +588,16 @@ class ApiOauthAuthorizeAction extends Action
* *
* @return nothing * @return nothing
*/ */
function showCanceled() function showCanceled()
{ {
$info = new InfoAction( $info = new InfoAction(
// TRANS: Header for user notification after revoking OAuth access to an application.
_('Authorization canceled.'), _('Authorization canceled.'),
sprintf( sprintf(
// TRANS: User notification after revoking OAuth access to an application.
// TRANS: %s is an OAuth token.
_('The request token %s has been revoked.'), _('The request token %s has been revoked.'),
$this->oauthTokenParm $this->oauthTokenParam
) )
); );
@ -460,21 +610,29 @@ class ApiOauthAuthorizeAction extends Action
* *
* @return nothing * @return nothing
*/ */
function showAuthorized() function showAuthorized()
{ {
$title = sprintf( $title = sprintf(
_("You have successfully authorized %s."), // TRANS: Header of user notification after authorising an application access to a profile.
$this->app->name // TRANS: %s is the authorised application name.
_('You have successfully authorized %s.'),
($this->app->name == 'anonymous') ? 'the application' : $this->app->name
); );
$msg = sprintf( $msg = sprintf(
// TRANS: Uer notification after authorising an application access to a profile.
// TRANS: %s is the authorised application name.
_('Please return to %s and enter the following security code to complete the process.'), _('Please return to %s and enter the following security code to complete the process.'),
$this->app->name ($this->app->name == 'anonymous') ? 'the application' : $this->app->name
); );
if ($this->reqToken->verified_callback == 'oob') { if ($this->reqToken->verified_callback == 'oob') {
$pin = new ApiOauthPinAction($title, $msg, $this->reqToken->verifier); $pin = new ApiOauthPinAction(
$title,
$msg,
$this->reqToken->verifier,
$this->desktopMode()
);
$pin->showPage(); $pin->showPage();
} else { } else {
@ -494,6 +652,36 @@ class ApiOauthAuthorizeAction extends Action
} }
} }
/*
* Figure out what the callback should be
*/
function getCallback()
{
$callback = null;
// Return the verified callback if we have one
if ($this->reqToken->verified_callback != 'oob') {
$callback = $this->reqToken->verified_callback;
// Otherwise return the callback that was provided when
// registering the app
if (empty($callback)) {
common_debug(
"No verified callback found for request token, using application callback: "
. $this->app->callback_url,
__FILE__
);
$callback = $this->app->callback_url;
}
}
return $callback;
}
/* /*
* Properly format the callback URL and parameters so it's * Properly format the callback URL and parameters so it's
* suitable for a redirect in the OAuth dance * suitable for a redirect in the OAuth dance
@ -503,8 +691,7 @@ class ApiOauthAuthorizeAction extends Action
* *
* @return string $url a URL to use for redirecting to * @return string $url a URL to use for redirecting to
*/ */
function buildCallbackUrl($url, $params)
function getCallback($url, $params)
{ {
foreach ($params as $k => $v) { foreach ($params as $k => $v) {
$url = $this->appendQueryVar( $url = $this->appendQueryVar(
@ -527,7 +714,6 @@ class ApiOauthAuthorizeAction extends Action
* *
* @return string $url the new URL with added parameter * @return string $url the new URL with added parameter
*/ */
function appendQueryVar($url, $k, $v) { function appendQueryVar($url, $k, $v) {
$url = preg_replace('/(.*)(\?|&)' . $k . '=[^&]+?(&)(.*)/i', '$1$2$4', $url . '&'); $url = preg_replace('/(.*)(\?|&)' . $k . '=[^&]+?(&)(.*)/i', '$1$2$4', $url . '&');
$url = substr($url, 0, -1); $url = substr($url, 0, -1);

View File

@ -31,8 +31,6 @@ if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1); exit(1);
} }
require_once INSTALLDIR . '/lib/info.php';
/** /**
* Class for displaying an OAuth verifier pin * Class for displaying an OAuth verifier pin
* *
@ -47,13 +45,57 @@ require_once INSTALLDIR . '/lib/info.php';
class ApiOauthPinAction extends InfoAction class ApiOauthPinAction extends InfoAction
{ {
function __construct($title, $message, $verifier) function __construct($title, $message, $verifier, $desktopMode = false)
{ {
$this->verifier = $verifier; $this->verifier = $verifier;
$this->title = $title; $this->title = $title;
$this->desktopMode = $desktopMode;
parent::__construct($title, $message); parent::__construct($title, $message);
} }
/**
* Show body - override to add a special CSS class for the pin pages's
* "desktop mode" (minimal display)
*
* Calls template methods
*
* @return nothing
*/
function showBody()
{
$bodyClasses = array();
if ($this->desktopMode) {
$bodyClasses[] = 'oauth-desktop-mode';
}
if (common_current_user()) {
$bodyClasses[] = 'user_in';
}
$attrs = array('id' => strtolower($this->trimmed('action')));
if (!empty($bodyClasses)) {
$attrs['class'] = implode(' ', $bodyClasses);
}
$this->elementStart('body', $attrs);
$this->elementStart('div', array('id' => 'wrap'));
if (Event::handle('StartShowHeader', array($this))) {
$this->showHeader();
Event::handle('EndShowHeader', array($this));
}
$this->showCore();
if (Event::handle('StartShowFooter', array($this))) {
$this->showFooter();
Event::handle('EndShowFooter', array($this));
}
$this->elementEnd('div');
$this->showScripts();
$this->elementEnd('body');
}
/** /**
* Display content. * Display content.
* *

View File

@ -147,10 +147,8 @@ require_once INSTALLDIR . '/lib/mediafile.php';
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/ * @link http://status.net/
*/ */
class ApiStatusesUpdateAction extends ApiAuthAction class ApiStatusesUpdateAction extends ApiAuthAction
{ {
var $source = null;
var $status = null; var $status = null;
var $in_reply_to_status_id = null; var $in_reply_to_status_id = null;
var $lat = null; var $lat = null;
@ -164,7 +162,6 @@ class ApiStatusesUpdateAction extends ApiAuthAction
* @return boolean success flag * @return boolean success flag
* *
*/ */
function prepare($args) function prepare($args)
{ {
parent::prepare($args); parent::prepare($args);
@ -188,7 +185,6 @@ class ApiStatusesUpdateAction extends ApiAuthAction
* *
* @return void * @return void
*/ */
function handle($args) function handle($args)
{ {
parent::handle($args); parent::handle($args);
@ -210,8 +206,11 @@ class ApiStatusesUpdateAction extends ApiAuthAction
&& empty($_POST) && empty($_POST)
&& ($_SERVER['CONTENT_LENGTH'] > 0) && ($_SERVER['CONTENT_LENGTH'] > 0)
) { ) {
$msg = _('The server was unable to handle that much POST ' . // TRANS: Client error displayed when the number of bytes in a POST request exceeds a limit.
'data (%s bytes) due to its current configuration.'); // TRANS: %s is the number of bytes of the CONTENT_LENGTH.
$msg = _m('The server was unable to handle that much POST data (%s byte) due to its current configuration.',
'The server was unable to handle that much POST data (%s bytes) due to its current configuration.',
intval($_SERVER['CONTENT_LENGTH']));
$this->clientError(sprintf($msg, $_SERVER['CONTENT_LENGTH'])); $this->clientError(sprintf($msg, $_SERVER['CONTENT_LENGTH']));
return; return;
@ -219,6 +218,7 @@ class ApiStatusesUpdateAction extends ApiAuthAction
if (empty($this->status)) { if (empty($this->status)) {
$this->clientError( $this->clientError(
// TRANS: Client error displayed when the parameter "status" is missing.
_('Client must provide a \'status\' parameter with a value.'), _('Client must provide a \'status\' parameter with a value.'),
400, 400,
$this->format $this->format
@ -240,7 +240,11 @@ class ApiStatusesUpdateAction extends ApiAuthAction
$this->clientError( $this->clientError(
sprintf( sprintf(
_('That\'s too long. Max notice size is %d chars.'), // TRANS: Client error displayed when the parameter "status" is missing.
// TRANS: %d is the maximum number of character for a notice.
_m('That\'s too long. Maximum notice size is %d character.',
'That\'s too long. Maximum notice size is %d characters.',
Notice::maxContent()),
Notice::maxContent() Notice::maxContent()
), ),
406, 406,
@ -256,7 +260,6 @@ class ApiStatusesUpdateAction extends ApiAuthAction
$cmd = $inter->handle_command($this->auth_user, $status_shortened); $cmd = $inter->handle_command($this->auth_user, $status_shortened);
if ($cmd) { if ($cmd) {
if ($this->supported($cmd)) { if ($this->supported($cmd)) {
$cmd->execute(new Channel()); $cmd->execute(new Channel());
} }
@ -266,13 +269,10 @@ class ApiStatusesUpdateAction extends ApiAuthAction
// or not! // or not!
$this->notice = $this->auth_user->getCurrentNotice(); $this->notice = $this->auth_user->getCurrentNotice();
} else { } else {
$reply_to = null; $reply_to = null;
if (!empty($this->in_reply_to_status_id)) { if (!empty($this->in_reply_to_status_id)) {
// Check whether notice actually exists // Check whether notice actually exists
$reply = Notice::staticGet($this->in_reply_to_status_id); $reply = Notice::staticGet($this->in_reply_to_status_id);
@ -281,7 +281,8 @@ class ApiStatusesUpdateAction extends ApiAuthAction
$reply_to = $this->in_reply_to_status_id; $reply_to = $this->in_reply_to_status_id;
} else { } else {
$this->clientError( $this->clientError(
_('Not found.'), // TRANS: Client error displayed when replying to a non-existing notice.
_('Parent notice not found.'),
$code = 404, $code = 404,
$this->format $this->format
); );
@ -303,10 +304,9 @@ class ApiStatusesUpdateAction extends ApiAuthAction
if (Notice::contentTooLong($status_shortened)) { if (Notice::contentTooLong($status_shortened)) {
$upload->delete(); $upload->delete();
$msg = _( $msg = _m('Maximum notice size is %d character, including attachment URL.',
'Max notice size is %d chars, ' . 'Maximum notice size is %d characters, including attachment URL.',
'including attachment URL.' Notice::maxContent());
);
$this->clientError( $this->clientError(
sprintf($msg, Notice::maxContent()), sprintf($msg, Notice::maxContent()),
400, 400,
@ -345,7 +345,6 @@ class ApiStatusesUpdateAction extends ApiAuthAction
if (isset($upload)) { if (isset($upload)) {
$upload->attachToNotice($this->notice); $upload->attachToNotice($this->notice);
} }
} }
$this->showNotice(); $this->showNotice();
@ -356,7 +355,6 @@ class ApiStatusesUpdateAction extends ApiAuthAction
* *
* @return void * @return void
*/ */
function showNotice() function showNotice()
{ {
if (!empty($this->notice)) { if (!empty($this->notice)) {
@ -375,7 +373,6 @@ class ApiStatusesUpdateAction extends ApiAuthAction
* *
* @return boolean true or false * @return boolean true or false
*/ */
function supported($cmd) function supported($cmd)
{ {
static $cmdlist = array('MessageCommand', 'SubCommand', 'UnsubCommand', static $cmdlist = array('MessageCommand', 'SubCommand', 'UnsubCommand',
@ -387,5 +384,4 @@ class ApiStatusesUpdateAction extends ApiAuthAction
return false; return false;
} }
} }

View File

@ -254,9 +254,11 @@ class AvatarsettingsAction extends AccountSettingsAction
&& empty($_POST) && empty($_POST)
&& ($_SERVER['CONTENT_LENGTH'] > 0) && ($_SERVER['CONTENT_LENGTH'] > 0)
) { ) {
$msg = _('The server was unable to handle that much POST ' . // TRANS: Client error displayed when the number of bytes in a POST request exceeds a limit.
'data (%s bytes) due to its current configuration.'); // TRANS: %s is the number of bytes of the CONTENT_LENGTH.
$msg = _m('The server was unable to handle that much POST data (%s byte) due to its current configuration.',
'The server was unable to handle that much POST data (%s bytes) due to its current configuration.',
intval($_SERVER['CONTENT_LENGTH']));
$this->showForm(sprintf($msg, $_SERVER['CONTENT_LENGTH'])); $this->showForm(sprintf($msg, $_SERVER['CONTENT_LENGTH']));
return; return;
} }

View File

@ -120,8 +120,11 @@ class DesignadminpanelAction extends AdminPanelAction
&& empty($_POST) && empty($_POST)
&& ($_SERVER['CONTENT_LENGTH'] > 0) && ($_SERVER['CONTENT_LENGTH'] > 0)
) { ) {
$msg = _('The server was unable to handle that much POST ' . // TRANS: Client error displayed when the number of bytes in a POST request exceeds a limit.
'data (%s bytes) due to its current configuration.'); // TRANS: %s is the number of bytes of the CONTENT_LENGTH.
$msg = _m('The server was unable to handle that much POST data (%s byte) due to its current configuration.',
'The server was unable to handle that much POST data (%s bytes) due to its current configuration.',
intval($_SERVER['CONTENT_LENGTH']));
$this->clientException(sprintf($msg, $_SERVER['CONTENT_LENGTH'])); $this->clientException(sprintf($msg, $_SERVER['CONTENT_LENGTH']));
return; return;
} }

View File

@ -42,7 +42,6 @@ if (!defined('STATUSNET') && !defined('LACONICA')) {
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/ * @link http://status.net/
*/ */
class EditApplicationAction extends OwnerDesignAction class EditApplicationAction extends OwnerDesignAction
{ {
var $msg = null; var $msg = null;
@ -51,18 +50,19 @@ class EditApplicationAction extends OwnerDesignAction
function title() function title()
{ {
return _('Edit Application'); // TRANS: Title for "Edit application" form.
return _('Edit application');
} }
/** /**
* Prepare to run * Prepare to run
*/ */
function prepare($args) function prepare($args)
{ {
parent::prepare($args); parent::prepare($args);
if (!common_logged_in()) { if (!common_logged_in()) {
// TRANS: Client error displayed trying to edit an application while not logged in.
$this->clientError(_('You must be logged in to edit an application.')); $this->clientError(_('You must be logged in to edit an application.'));
return false; return false;
} }
@ -74,10 +74,12 @@ class EditApplicationAction extends OwnerDesignAction
$cur = common_current_user(); $cur = common_current_user();
if ($cur->id != $this->owner->id) { if ($cur->id != $this->owner->id) {
// TRANS: Client error displayed trying to edit an application while not being its owner.
$this->clientError(_('You are not the owner of this application.'), 401); $this->clientError(_('You are not the owner of this application.'), 401);
} }
if (!$this->app) { if (!$this->app) {
// TRANS: Client error displayed trying to edit an application that does not exist.
$this->clientError(_('No such application.')); $this->clientError(_('No such application.'));
return false; return false;
} }
@ -94,7 +96,6 @@ class EditApplicationAction extends OwnerDesignAction
* *
* @return void * @return void
*/ */
function handle($args) function handle($args)
{ {
parent::handle($args); parent::handle($args);
@ -115,8 +116,11 @@ class EditApplicationAction extends OwnerDesignAction
&& empty($_POST) && empty($_POST)
&& ($_SERVER['CONTENT_LENGTH'] > 0) && ($_SERVER['CONTENT_LENGTH'] > 0)
) { ) {
$msg = _('The server was unable to handle that much POST ' . // TRANS: Client error displayed when the number of bytes in a POST request exceeds a limit.
'data (%s bytes) due to its current configuration.'); // TRANS: %s is the number of bytes of the CONTENT_LENGTH.
$msg = _m('The server was unable to handle that much POST data (%s byte) due to its current configuration.',
'The server was unable to handle that much POST data (%s bytes) due to its current configuration.',
intval($_SERVER['CONTENT_LENGTH']));
$this->clientException(sprintf($msg, $_SERVER['CONTENT_LENGTH'])); $this->clientException(sprintf($msg, $_SERVER['CONTENT_LENGTH']));
return; return;
} }
@ -136,6 +140,7 @@ class EditApplicationAction extends OwnerDesignAction
} elseif ($this->arg('save')) { } elseif ($this->arg('save')) {
$this->trySave(); $this->trySave();
} else { } else {
// TRANS: Client error displayed submitting invalid form data for edit application.
$this->clientError(_('Unexpected form submission.')); $this->clientError(_('Unexpected form submission.'));
} }
} }
@ -158,6 +163,7 @@ class EditApplicationAction extends OwnerDesignAction
$this->element('p', 'error', $this->msg); $this->element('p', 'error', $this->msg);
} else { } else {
$this->element('p', 'instructions', $this->element('p', 'instructions',
// TRANS: Instructions for "Edit application" form.
_('Use this form to edit your application.')); _('Use this form to edit your application.'));
} }
} }
@ -174,36 +180,47 @@ class EditApplicationAction extends OwnerDesignAction
$access_type = $this->arg('default_access_type'); $access_type = $this->arg('default_access_type');
if (empty($name)) { if (empty($name)) {
// TRANS: Validation error shown when not providing a name in the "Edit application" form.
$this->showForm(_('Name is required.')); $this->showForm(_('Name is required.'));
return; return;
} elseif (mb_strlen($name) > 255) { } elseif (mb_strlen($name) > 255) {
$this->showForm(_('Name is too long (max 255 chars).')); // TRANS: Validation error shown when providing too long a name in the "Edit application" form.
$this->showForm(_('Name is too long (max 255 characters).'));
return; return;
} else if ($this->nameExists($name)) { } else if ($this->nameExists($name)) {
// TRANS: Validation error shown when providing a name for an application that already exists in the "Edit application" form.
$this->showForm(_('Name already in use. Try another one.')); $this->showForm(_('Name already in use. Try another one.'));
return; return;
} elseif (empty($description)) { } elseif (empty($description)) {
// TRANS: Validation error shown when not providing a description in the "Edit application" form.
$this->showForm(_('Description is required.')); $this->showForm(_('Description is required.'));
return; return;
} elseif (Oauth_application::descriptionTooLong($description)) { } elseif (Oauth_application::descriptionTooLong($description)) {
$this->showForm(sprintf( $this->showForm(sprintf(
_('Description is too long (max %d chars).'), // TRANS: Validation error shown when providing too long a description in the "Edit application" form.
_m('Description is too long (maximum %d character).',
'Description is too long (maximum %d characters).',
Oauth_application::maxDesc()),
Oauth_application::maxDesc())); Oauth_application::maxDesc()));
return; return;
} elseif (mb_strlen($source_url) > 255) { } elseif (mb_strlen($source_url) > 255) {
// TRANS: Validation error shown when providing too long a source URL in the "Edit application" form.
$this->showForm(_('Source URL is too long.')); $this->showForm(_('Source URL is too long.'));
return; return;
} elseif ((mb_strlen($source_url) > 0) } elseif ((mb_strlen($source_url) > 0)
&& !Validate::uri($source_url, && !Validate::uri($source_url,
array('allowed_schemes' => array('http', 'https')))) array('allowed_schemes' => array('http', 'https'))))
{ {
// TRANS: Validation error shown when providing an invalid source URL in the "Edit application" form.
$this->showForm(_('Source URL is not valid.')); $this->showForm(_('Source URL is not valid.'));
return; return;
} elseif (empty($organization)) { } elseif (empty($organization)) {
// TRANS: Validation error shown when not providing an organisation in the "Edit application" form.
$this->showForm(_('Organization is required.')); $this->showForm(_('Organization is required.'));
return; return;
} elseif (mb_strlen($organization) > 255) { } elseif (mb_strlen($organization) > 255) {
$this->showForm(_('Organization is too long (max 255 chars).')); // TRANS: Validation error shown when providing too long an arganisation name in the "Edit application" form.
$this->showForm(_('Organization is too long (maximum 255 characters).'));
return; return;
} elseif (empty($homepage)) { } elseif (empty($homepage)) {
$this->showForm(_('Organization homepage is required.')); $this->showForm(_('Organization homepage is required.'));
@ -212,9 +229,11 @@ class EditApplicationAction extends OwnerDesignAction
&& !Validate::uri($homepage, && !Validate::uri($homepage,
array('allowed_schemes' => array('http', 'https')))) array('allowed_schemes' => array('http', 'https'))))
{ {
// TRANS: Validation error shown when providing an invalid homepage URL in the "Edit application" form.
$this->showForm(_('Homepage is not a valid URL.')); $this->showForm(_('Homepage is not a valid URL.'));
return; return;
} elseif (mb_strlen($callback_url) > 255) { } elseif (mb_strlen($callback_url) > 255) {
// TRANS: Validation error shown when providing too long a callback URL in the "Edit application" form.
$this->showForm(_('Callback is too long.')); $this->showForm(_('Callback is too long.'));
return; return;
} elseif (mb_strlen($callback_url) > 0 } elseif (mb_strlen($callback_url) > 0
@ -222,6 +241,7 @@ class EditApplicationAction extends OwnerDesignAction
array('allowed_schemes' => array('http', 'https')) array('allowed_schemes' => array('http', 'https'))
)) ))
{ {
// TRANS: Validation error shown when providing an invalid callback URL in the "Edit application" form.
$this->showForm(_('Callback URL is not valid.')); $this->showForm(_('Callback URL is not valid.'));
return; return;
} }
@ -258,6 +278,7 @@ class EditApplicationAction extends OwnerDesignAction
// the next step. // the next step.
if ($result === false) { if ($result === false) {
common_log_db_error($this->app, 'UPDATE', __FILE__); common_log_db_error($this->app, 'UPDATE', __FILE__);
// TRANS: Server error occuring when an application could not be updated from the "Edit application" form.
$this->serverError(_('Could not update application.')); $this->serverError(_('Could not update application.'));
} }
@ -276,7 +297,6 @@ class EditApplicationAction extends OwnerDesignAction
* *
* @return boolean true if the name already exists * @return boolean true if the name already exists
*/ */
function nameExists($name) function nameExists($name)
{ {
$newapp = Oauth_application::staticGet('name', $name); $newapp = Oauth_application::staticGet('name', $name);
@ -286,6 +306,4 @@ class EditApplicationAction extends OwnerDesignAction
return $newapp->id != $this->app->id; return $newapp->id != $this->app->id;
} }
} }
} }

View File

@ -199,13 +199,13 @@ class EditgroupAction extends GroupDesignAction
$this->showForm(_('Homepage is not a valid URL.')); $this->showForm(_('Homepage is not a valid URL.'));
return; return;
} else if (!is_null($fullname) && mb_strlen($fullname) > 255) { } else if (!is_null($fullname) && mb_strlen($fullname) > 255) {
$this->showForm(_('Full name is too long (max 255 chars).')); $this->showForm(_('Full name is too long (maximum 255 characters).'));
return; return;
} else if (User_group::descriptionTooLong($description)) { } else if (User_group::descriptionTooLong($description)) {
$this->showForm(sprintf(_('description is too long (max %d chars).'), User_group::maxDescription())); $this->showForm(sprintf(_('Description is too long (max %d chars).'), User_group::maxDescription()));
return; return;
} else if (!is_null($location) && mb_strlen($location) > 255) { } else if (!is_null($location) && mb_strlen($location) > 255) {
$this->showForm(_('Location is too long (max 255 chars).')); $this->showForm(_('Location is too long (maximum 255 characters).'));
return; return;
} }

View File

@ -36,8 +36,11 @@ class InviteAction extends CurrentUserDesignAction
{ {
parent::handle($args); parent::handle($args);
if (!common_config('invite', 'enabled')) { if (!common_config('invite', 'enabled')) {
// TRANS: Client error displayed when trying to sent invites while they have been disabled.
$this->clientError(_('Invites have been disabled.')); $this->clientError(_('Invites have been disabled.'));
} else if (!common_logged_in()) { } else if (!common_logged_in()) {
// TRANS: Client error displayed when trying to sent invites while not logged in.
// TRANS: %s is the StatusNet site name.
$this->clientError(sprintf(_('You must be logged in to invite other users to use %s.'), $this->clientError(sprintf(_('You must be logged in to invite other users to use %s.'),
common_config('site', 'name'))); common_config('site', 'name')));
return; return;
@ -69,7 +72,9 @@ class InviteAction extends CurrentUserDesignAction
foreach ($addresses as $email) { foreach ($addresses as $email) {
$email = trim($email); $email = trim($email);
if (!Validate::email($email, common_config('email', 'check_domain'))) { if (!Validate::email($email, common_config('email', 'check_domain'))) {
$this->showForm(sprintf(_('Invalid email address: %s'), $email)); // TRANS: Form validation message when providing an e-mail address that does not validate.
// TRANS: %s is an invalid e-mail address.
$this->showForm(sprintf(_('Invalid email address: %s.'), $email));
return; return;
} }
} }
@ -107,8 +112,10 @@ class InviteAction extends CurrentUserDesignAction
function title() function title()
{ {
if ($this->mode == 'sent') { if ($this->mode == 'sent') {
return _('Invitation(s) sent'); // TRANS: Page title when invitations have been sent.
return _('Invitations sent');
} else { } else {
// TRANS: Page title when inviting potential users.
return _('Invite new users'); return _('Invite new users');
} }
} }
@ -125,28 +132,48 @@ class InviteAction extends CurrentUserDesignAction
function showInvitationSuccess() function showInvitationSuccess()
{ {
if ($this->already) { if ($this->already) {
$this->element('p', null, _('You are already subscribed to these users:')); // TRANS: Message displayed inviting users to use a StatusNet site while the inviting user
// TRANS: is already subscribed to one or more users with the given e-mail address(es).
// TRANS: Plural form is based on the number of reported already subscribed e-mail addresses.
// TRANS: Followed by a bullet list.
$this->element('p', null, _m('You are already subscribed to this user:',
'You are already subscribed to these users:',
count($this->already)));
$this->elementStart('ul'); $this->elementStart('ul');
foreach ($this->already as $other) { foreach ($this->already as $other) {
// TRANS: Used as list item for already subscribed users (%1$s is nickname, %2$s is e-mail address).
$this->element('li', null, sprintf(_('%1$s (%2$s)'), $other->nickname, $other->email)); $this->element('li', null, sprintf(_('%1$s (%2$s)'), $other->nickname, $other->email));
} }
$this->elementEnd('ul'); $this->elementEnd('ul');
} }
if ($this->subbed) { if ($this->subbed) {
$this->element('p', null, _('These people are already users and you were automatically subscribed to them:')); // TRANS: Message displayed inviting users to use a StatusNet site while the invited user
// TRANS: already uses a this StatusNet site. Plural form is based on the number of
// TRANS: reported already present people. Followed by a bullet list.
$this->element('p', null, _m('This person is already a user and you were automatically subscribed:',
'These people are already users and you were automatically subscribed to them:',
count($this->subbed)));
$this->elementStart('ul'); $this->elementStart('ul');
foreach ($this->subbed as $other) { foreach ($this->subbed as $other) {
// TRANS: Used as list item for already registered people (%1$s is nickname, %2$s is e-mail address).
$this->element('li', null, sprintf(_('%1$s (%2$s)'), $other->nickname, $other->email)); $this->element('li', null, sprintf(_('%1$s (%2$s)'), $other->nickname, $other->email));
} }
$this->elementEnd('ul'); $this->elementEnd('ul');
} }
if ($this->sent) { if ($this->sent) {
$this->element('p', null, _('Invitation(s) sent to the following people:')); // TRANS: Message displayed inviting users to use a StatusNet site. Plural form is
// TRANS: based on the number of invitations sent. Followed by a bullet list of
// TRANS: e-mail addresses to which invitations were sent.
$this->element('p', null, _m('Invitation sent to the following person:',
'Invitations sent to the following people:',
count($this->sent)));
$this->elementStart('ul'); $this->elementStart('ul');
foreach ($this->sent as $other) { foreach ($this->sent as $other) {
$this->element('li', null, $other); $this->element('li', null, $other);
} }
$this->elementEnd('ul'); $this->elementEnd('ul');
// TRANS: Generic message displayed after sending out one or more invitations to
// TRANS: people to join a StatusNet site.
$this->element('p', null, _('You will be notified when your invitees accept the invitation and register on the site. Thanks for growing the community!')); $this->element('p', null, _('You will be notified when your invitees accept the invitation and register on the site. Thanks for growing the community!'));
} }
} }
@ -159,6 +186,7 @@ class InviteAction extends CurrentUserDesignAction
} else { } else {
$this->elementStart('div', 'instructions'); $this->elementStart('div', 'instructions');
$this->element('p', null, $this->element('p', null,
// TRANS: Form instructions.
_('Use this form to invite your friends and colleagues to use this service.')); _('Use this form to invite your friends and colleagues to use this service.'));
$this->elementEnd('div'); $this->elementEnd('div');
} }
@ -179,18 +207,23 @@ class InviteAction extends CurrentUserDesignAction
'class' => 'form_settings', 'class' => 'form_settings',
'action' => common_local_url('invite'))); 'action' => common_local_url('invite')));
$this->elementStart('fieldset'); $this->elementStart('fieldset');
// TRANS: Form legend.
$this->element('legend', null, 'Send an invitation'); $this->element('legend', null, 'Send an invitation');
$this->hidden('token', common_session_token()); $this->hidden('token', common_session_token());
$this->elementStart('ul', 'form_data'); $this->elementStart('ul', 'form_data');
$this->elementStart('li'); $this->elementStart('li');
// TRANS: Field label for a list of e-mail addresses.
$this->textarea('addresses', _('Email addresses'), $this->textarea('addresses', _('Email addresses'),
$this->trimmed('addresses'), $this->trimmed('addresses'),
// TRANS: Tooltip for field label for a list of e-mail addresses.
_('Addresses of friends to invite (one per line)')); _('Addresses of friends to invite (one per line)'));
$this->elementEnd('li'); $this->elementEnd('li');
$this->elementStart('li'); $this->elementStart('li');
// TRANS: Field label for a personal message to send to invitees.
$this->textarea('personal', _('Personal message'), $this->textarea('personal', _('Personal message'),
$this->trimmed('personal'), $this->trimmed('personal'),
// TRANS: Tooltip for field label for a personal message to send to invitees.
_('Optionally add a personal message to the invitation.')); _('Optionally add a personal message to the invitation.'));
$this->elementEnd('li'); $this->elementEnd('li');
$this->elementEnd('ul'); $this->elementEnd('ul');
@ -224,10 +257,16 @@ class InviteAction extends CurrentUserDesignAction
$headers['From'] = mail_notify_from(); $headers['From'] = mail_notify_from();
$headers['To'] = trim($email); $headers['To'] = trim($email);
// TRANS: Subject for invitation email. Note that 'them' is correct as a gender-neutral singular 3rd-person pronoun in English. // TRANS: Subject for invitation email. Note that 'them' is correct as a gender-neutral
// TRANS: singular 3rd-person pronoun in English. %1$s is the inviting user, $2$s is
// TRANS: the StatusNet sitename.
$headers['Subject'] = sprintf(_('%1$s has invited you to join them on %2$s'), $bestname, $sitename); $headers['Subject'] = sprintf(_('%1$s has invited you to join them on %2$s'), $bestname, $sitename);
// TRANS: Body text for invitation email. Note that 'them' is correct as a gender-neutral singular 3rd-person pronoun in English. // TRANS: Body text for invitation email. Note that 'them' is correct as a gender-neutral
// TRANS: singular 3rd-person pronoun in English. %1$s is the inviting user, %2$s is the
// TRANS: StatusNet sitename, %3$s is the site URL, %4$s is the personal message from the
// TRANS: inviting user, %s%5 a link to the timeline for the inviting user, %s$6 is a link
// TRANS: to register with the StatusNet site.
$body = sprintf(_("%1\$s has invited you to join them on %2\$s (%3\$s).\n\n". $body = sprintf(_("%1\$s has invited you to join them on %2\$s (%3\$s).\n\n".
"%2\$s is a micro-blogging service that lets you keep up-to-date with people you know and people who interest you.\n\n". "%2\$s is a micro-blogging service that lets you keep up-to-date with people you know and people who interest you.\n\n".
"You can also share news about yourself, your thoughts, or your life online with people who know about you. ". "You can also share news about yourself, your thoughts, or your life online with people who know about you. ".

View File

@ -42,14 +42,14 @@ if (!defined('STATUSNET') && !defined('LACONICA')) {
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/ * @link http://status.net/
*/ */
class NewApplicationAction extends OwnerDesignAction class NewApplicationAction extends OwnerDesignAction
{ {
var $msg; var $msg;
function title() function title()
{ {
return _('New Application'); // TRANS: This is the title of the form for adding a new application.
return _('New application');
} }
/** /**
@ -61,6 +61,7 @@ class NewApplicationAction extends OwnerDesignAction
parent::prepare($args); parent::prepare($args);
if (!common_logged_in()) { if (!common_logged_in()) {
// TRANS: Client error displayed trying to add a new application while not logged in.
$this->clientError(_('You must be logged in to register an application.')); $this->clientError(_('You must be logged in to register an application.'));
return false; return false;
} }
@ -91,35 +92,38 @@ class NewApplicationAction extends OwnerDesignAction
function handlePost($args) function handlePost($args)
{ {
// Workaround for PHP returning empty $_POST and $_FILES when POST // Workaround for PHP returning empty $_POST and $_FILES when POST
// length > post_max_size in php.ini // length > post_max_size in php.ini
if (empty($_FILES) if (empty($_FILES)
&& empty($_POST) && empty($_POST)
&& ($_SERVER['CONTENT_LENGTH'] > 0) && ($_SERVER['CONTENT_LENGTH'] > 0)
) { ) {
$msg = _('The server was unable to handle that much POST ' . // TRANS: Client error displayed when the number of bytes in a POST request exceeds a limit.
'data (%s bytes) due to its current configuration.'); // TRANS: %s is the number of bytes of the CONTENT_LENGTH.
$msg = _m('The server was unable to handle that much POST data (%s byte) due to its current configuration.',
'The server was unable to handle that much POST data (%s bytes) due to its current configuration.',
intval($_SERVER['CONTENT_LENGTH']));
$this->clientException(sprintf($msg, $_SERVER['CONTENT_LENGTH'])); $this->clientException(sprintf($msg, $_SERVER['CONTENT_LENGTH']));
return; return;
} }
// CSRF protection // CSRF protection
$token = $this->trimmed('token'); $token = $this->trimmed('token');
if (!$token || $token != common_session_token()) { if (!$token || $token != common_session_token()) {
$this->clientError(_('There was a problem with your session token.')); $this->clientError(_('There was a problem with your session token.'));
return; return;
} }
$cur = common_current_user(); $cur = common_current_user();
if ($this->arg('cancel')) { if ($this->arg('cancel')) {
common_redirect(common_local_url('oauthappssettings'), 303); common_redirect(common_local_url('oauthappssettings'), 303);
} elseif ($this->arg('save')) { } elseif ($this->arg('save')) {
$this->trySave(); $this->trySave();
} else { } else {
$this->clientError(_('Unexpected form submission.')); $this->clientError(_('Unexpected form submission.'));
} }
} }
function showForm($msg=null) function showForm($msg=null)
@ -162,14 +166,18 @@ class NewApplicationAction extends OwnerDesignAction
$this->showForm(_('Name already in use. Try another one.')); $this->showForm(_('Name already in use. Try another one.'));
return; return;
} elseif (mb_strlen($name) > 255) { } elseif (mb_strlen($name) > 255) {
$this->showForm(_('Name is too long (max 255 chars).')); $this->showForm(_('Name is too long (maximum 255 chars).'));
return; return;
} elseif (empty($description)) { } elseif (empty($description)) {
$this->showForm(_('Description is required.')); $this->showForm(_('Description is required.'));
return; return;
} elseif (Oauth_application::descriptionTooLong($description)) { } elseif (Oauth_application::descriptionTooLong($description)) {
$this->showForm(sprintf( $this->showForm(sprintf(
_('Description is too long (max %d chars).'), // TRANS: Form validation error in New application form.
// TRANS: %d is the maximum number of characters for the description.
_m('Description is too long (maximum %d character).',
'Description is too long (maximum %d characters).',
Oauth_application::maxDesc()),
Oauth_application::maxDesc())); Oauth_application::maxDesc()));
return; return;
} elseif (empty($source_url)) { } elseif (empty($source_url)) {
@ -188,7 +196,7 @@ class NewApplicationAction extends OwnerDesignAction
$this->showForm(_('Organization is required.')); $this->showForm(_('Organization is required.'));
return; return;
} elseif (mb_strlen($organization) > 255) { } elseif (mb_strlen($organization) > 255) {
$this->showForm(_('Organization is too long (max 255 chars).')); $this->showForm(_('Organization is too long (maximum 255 chars).'));
return; return;
} elseif (empty($homepage)) { } elseif (empty($homepage)) {
$this->showForm(_('Organization homepage is required.')); $this->showForm(_('Organization homepage is required.'));

View File

@ -139,13 +139,13 @@ class NewgroupAction extends Action
$this->showForm(_('Homepage is not a valid URL.')); $this->showForm(_('Homepage is not a valid URL.'));
return; return;
} else if (!is_null($fullname) && mb_strlen($fullname) > 255) { } else if (!is_null($fullname) && mb_strlen($fullname) > 255) {
$this->showForm(_('Full name is too long (max 255 chars).')); $this->showForm(_('Full name is too long (maximum 255 characters).'));
return; return;
} else if (User_group::descriptionTooLong($description)) { } else if (User_group::descriptionTooLong($description)) {
$this->showForm(sprintf(_('description is too long (max %d chars).'), User_group::maxDescription())); $this->showForm(sprintf(_('description is too long (max %d chars).'), User_group::maxDescription()));
return; return;
} else if (!is_null($location) && mb_strlen($location) > 255) { } else if (!is_null($location) && mb_strlen($location) > 255) {
$this->showForm(_('Location is too long (max 255 chars).')); $this->showForm(_('Location is too long (maximum 255 characters).'));
return; return;
} }

View File

@ -147,8 +147,11 @@ class NewmessageAction extends Action
$content_shortened = common_shorten_links($this->content); $content_shortened = common_shorten_links($this->content);
if (Message::contentTooLong($content_shortened)) { if (Message::contentTooLong($content_shortened)) {
$this->showForm(sprintf(_('That\'s too long. ' . // TRANS: Form validation error displayed when message content is too long.
'Max message size is %d chars.'), // TRANS: %d is the maximum number of characters for a message.
$this->showForm(sprintf(_m('That\'s too long. Maximum message size is %d character.',
'That\'s too long. Maximum message size is %d characters.',
Message::maxContent()),
Message::maxContent())); Message::maxContent()));
return; return;
} }

View File

@ -82,7 +82,6 @@ class NewnoticeAction extends Action
* *
* @return void * @return void
*/ */
function handle($args) function handle($args)
{ {
if (!common_logged_in()) { if (!common_logged_in()) {
@ -91,9 +90,12 @@ class NewnoticeAction extends Action
// check for this before token since all POST and FILES data // check for this before token since all POST and FILES data
// is losts when size is exceeded // is losts when size is exceeded
if (empty($_POST) && $_SERVER['CONTENT_LENGTH']) { if (empty($_POST) && $_SERVER['CONTENT_LENGTH']) {
$this->clientError(sprintf(_('The server was unable to handle ' . // TRANS: Client error displayed when the number of bytes in a POST request exceeds a limit.
'that much POST data (%s bytes) due to its current configuration.'), // TRANS: %s is the number of bytes of the CONTENT_LENGTH.
$_SERVER['CONTENT_LENGTH'])); $msg = _m('The server was unable to handle that much POST data (%s byte) due to its current configuration.',
'The server was unable to handle that much POST data (%s bytes) due to its current configuration.',
intval($_SERVER['CONTENT_LENGTH']));
$this->clientError(sprintf($msg,$_SERVER['CONTENT_LENGTH']));
} }
parent::handle($args); parent::handle($args);
@ -352,4 +354,3 @@ class NewnoticeAction extends Action
$nli->show(); $nli->show();
} }
} }

View File

@ -82,7 +82,7 @@ class NudgeAction extends Action
} }
if (!$other->email || !$other->emailnotifynudge) { if (!$other->email || !$other->emailnotifynudge) {
$this->clientError(_('This user doesn\'t allow nudges or hasn\'t confirmed or set their email yet.')); $this->clientError(_('This user doesn\'t allow nudges or hasn\'t confirmed or set their email address yet.'));
return; return;
} }

View File

@ -56,6 +56,7 @@ class OauthappssettingsAction extends SettingsAction
$this->page = ($this->arg('page')) ? ($this->arg('page') + 0) : 1; $this->page = ($this->arg('page')) ? ($this->arg('page') + 0) : 1;
if (!common_logged_in()) { if (!common_logged_in()) {
// TRANS: Message displayed to an anonymous user trying to view OAuth application list.
$this->clientError(_('You must be logged in to list your applications.')); $this->clientError(_('You must be logged in to list your applications.'));
return false; return false;
} }
@ -71,6 +72,7 @@ class OauthappssettingsAction extends SettingsAction
function title() function title()
{ {
// TRANS: Page title for OAuth applications
return _('OAuth applications'); return _('OAuth applications');
} }
@ -82,6 +84,7 @@ class OauthappssettingsAction extends SettingsAction
function getInstructions() function getInstructions()
{ {
// TRANS: Page instructions for OAuth applications
return _('Applications you have registered'); return _('Applications you have registered');
} }
@ -100,6 +103,7 @@ class OauthappssettingsAction extends SettingsAction
$application = new Oauth_application(); $application = new Oauth_application();
$application->owner = $user->id; $application->owner = $user->id;
$application->whereAdd("name != 'anonymous'");
$application->limit($offset, $limit); $application->limit($offset, $limit);
$application->orderBy('created DESC'); $application->orderBy('created DESC');
$application->find(); $application->find();
@ -119,6 +123,7 @@ class OauthappssettingsAction extends SettingsAction
array('href' => common_local_url('newapplication'), array('href' => common_local_url('newapplication'),
'class' => 'more' 'class' => 'more'
), ),
// TRANS: Link description to add a new OAuth application.
'Register a new application'); 'Register a new application');
$this->elementEnd('p'); $this->elementEnd('p');
@ -132,6 +137,7 @@ class OauthappssettingsAction extends SettingsAction
function showEmptyListMessage() function showEmptyListMessage()
{ {
// TRANS: Empty list message on page with OAuth applications.
$message = sprintf(_('You have not registered any applications yet.')); $message = sprintf(_('You have not registered any applications yet.'));
$this->elementStart('div', 'guide'); $this->elementStart('div', 'guide');
@ -162,5 +168,4 @@ class OauthappssettingsAction extends SettingsAction
} }
} }
} }

View File

@ -22,7 +22,7 @@
* @category Settings * @category Settings
* @package StatusNet * @package StatusNet
* @author Zach Copley <zach@status.net> * @author Zach Copley <zach@status.net>
* @copyright 2008-2009 StatusNet, Inc. * @copyright 2008-2010 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/ * @link http://status.net/
*/ */
@ -46,17 +46,15 @@ require_once INSTALLDIR . '/lib/apioauthstore.php';
* *
* @see SettingsAction * @see SettingsAction
*/ */
class OauthconnectionssettingsAction extends ConnectSettingsAction class OauthconnectionssettingsAction extends ConnectSettingsAction
{ {
var $page = null;
var $page = null; var $oauth_token = null;
var $id = null;
function prepare($args) function prepare($args)
{ {
parent::prepare($args); parent::prepare($args);
$this->id = (int)$this->arg('id'); $this->oauth_token = $this->arg('oauth_token');
$this->page = ($this->arg('page')) ? ($this->arg('page') + 0) : 1; $this->page = ($this->arg('page')) ? ($this->arg('page') + 0) : 1;
return true; return true;
} }
@ -69,6 +67,7 @@ class OauthconnectionssettingsAction extends ConnectSettingsAction
function title() function title()
{ {
// TRANS: Title for OAuth connection settings.
return _('Connected applications'); return _('Connected applications');
} }
@ -80,7 +79,8 @@ class OauthconnectionssettingsAction extends ConnectSettingsAction
function getInstructions() function getInstructions()
{ {
return _('You have allowed the following applications to access your account.'); // TRANS: Instructions for OAuth connection settings.
return _('The following connections exist for your account.');
} }
/** /**
@ -97,22 +97,26 @@ class OauthconnectionssettingsAction extends ConnectSettingsAction
$offset = ($this->page - 1) * APPS_PER_PAGE; $offset = ($this->page - 1) * APPS_PER_PAGE;
$limit = APPS_PER_PAGE + 1; $limit = APPS_PER_PAGE + 1;
$application = $profile->getApplications($offset, $limit); $connection = $profile->getConnectedApps($offset, $limit);
$cnt = 0; $cnt = 0;
if (!empty($application)) { if (!empty($connection)) {
$al = new ApplicationList($application, $user, $this, true); $cal = new ConnectedAppsList($connection, $user, $this);
$cnt = $al->show(); $cnt = $cal->show();
} }
if ($cnt == 0) { if ($cnt == 0) {
$this->showEmptyListMessage(); $this->showEmptyListMessage();
} }
$this->pagination($this->page > 1, $cnt > APPS_PER_PAGE, $this->pagination(
$this->page, 'connectionssettings', $this->page > 1,
array('nickname' => $user->nickname)); $cnt > APPS_PER_PAGE,
$this->page,
'connectionssettings',
array('nickname' => $user->nickname)
);
} }
/** /**
@ -125,7 +129,6 @@ class OauthconnectionssettingsAction extends ConnectSettingsAction
* *
* @return void * @return void
*/ */
function handlePost() function handlePost()
{ {
// CSRF protection // CSRF protection
@ -138,44 +141,36 @@ class OauthconnectionssettingsAction extends ConnectSettingsAction
} }
if ($this->arg('revoke')) { if ($this->arg('revoke')) {
$this->revokeAccess($this->id); $this->revokeAccess($this->oauth_token);
// XXX: Show some indicator to the user of what's been done.
$this->showPage();
} else { } else {
// TRANS: Client error when submitting a form with unexpected information.
$this->clientError(_('Unexpected form submission.'), 401); $this->clientError(_('Unexpected form submission.'), 401);
return false; return false;
} }
} }
/** /**
* Revoke access to an authorized OAuth application * Revoke an access token
*
* XXX: Confirm revoke before doing it
* *
* @param int $appId the ID of the application * @param int $appId the ID of the application
* *
*/ */
function revokeAccess($token)
function revokeAccess($appId)
{ {
$cur = common_current_user(); $cur = common_current_user();
$app = Oauth_application::staticGet('id', $appId); $appUser = Oauth_application_user::getByUserAndToken($cur, $token);
if (empty($app)) {
$this->clientError(_('No such application.'), 404);
return false;
}
// XXX: Transaction here?
$appUser = Oauth_application_user::getByKeys($cur, $app);
if (empty($appUser)) { if (empty($appUser)) {
// TRANS: Client error when trying to revoke access for an application while not being a user of it.
$this->clientError(_('You are not a user of that application.'), 401); $this->clientError(_('You are not a user of that application.'), 401);
return false; return false;
} }
$app = Oauth_application::staticGet('id', $appUser->application_id);
$datastore = new ApiStatusNetOAuthDataStore(); $datastore = new ApiStatusNetOAuthDataStore();
$datastore->revoke_token($appUser->token, 1); $datastore->revoke_token($appUser->token, 1);
@ -183,18 +178,38 @@ class OauthconnectionssettingsAction extends ConnectSettingsAction
if (!$result) { if (!$result) {
common_log_db_error($orig, 'DELETE', __FILE__); common_log_db_error($orig, 'DELETE', __FILE__);
$this->clientError(sprintf(_('Unable to revoke access for app: %s.'), $app->id)); // TRANS: Client error when revoking access has failed for some reason.
// TRANS: %s is the application ID revoking access failed for.
$this->clientError(sprintf(_('Unable to revoke access for application: %s.'), $app->id));
return false; return false;
} }
$msg = 'User %s (id: %d) revoked access to app %s (id: %d)'; $msg = 'API OAuth - user %s (id: %d) revoked access token %s for app id %d';
common_log(LOG_INFO, sprintf($msg, $cur->nickname, common_log(
$cur->id, $app->name, $app->id)); LOG_INFO,
sprintf(
$msg,
$cur->nickname,
$cur->id,
$appUser->token,
$appUser->application_id
)
);
$msg = sprintf(
// TRANS: Success message after revoking access for an application.
// TRANS: %1$s is the application name, %2$s is the first part of the user token.
_('You have successfully revoked access for %1$s and the access token starting with %2$s.'),
$app->name,
substr($appUser->token, 0, 7)
);
$this->showForm($msg, true);
} }
function showEmptyListMessage() function showEmptyListMessage()
{ {
// TRANS: Empty list message when no applications have been authorised yet.
$message = _('You have not authorized any applications to use your account.'); $message = _('You have not authorized any applications to use your account.');
$this->elementStart('div', 'guide'); $this->elementStart('div', 'guide');
@ -204,15 +219,26 @@ class OauthconnectionssettingsAction extends ConnectSettingsAction
function showSections() function showSections()
{ {
$cur = common_current_user(); $cur = common_current_user();
$this->element('h2', null, 'Developers'); $this->elementStart('div', array('id' => 'developer-help', 'class' => 'section'));
$this->elementStart('p');
$this->raw(_('Developers can edit the registration settings for their applications ')); $this->element('h2', null, 'Developers');
$this->element('a', $this->elementStart('p');
array('href' => common_local_url('oauthappssettings')),
'here.'); $devMsg = sprintf(
$this->elementEnd('p'); // TRANS: Note for developers in the OAuth connection settings form.
// TRANS: This message contains a Markdown link. Do not separate "](".
// TRANS: %s is the URL to the OAuth settings.
_('Are you a developer? [Register an OAuth client application](%s) to use with this instance of StatusNet.'),
common_local_url('oauthappssettings')
);
$output = common_markup_to_html($devMsg);
$this->raw($output);
$this->elementEnd('p');
$this->elementEnd('section');
} }
} }

View File

@ -44,10 +44,8 @@ if (!defined('STATUSNET')) {
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/ * @link http://status.net/
*/ */
class PathsadminpanelAction extends AdminPanelAction class PathsadminpanelAction extends AdminPanelAction
{ {
/** /**
* Returns the page title * Returns the page title
* *
@ -56,6 +54,7 @@ class PathsadminpanelAction extends AdminPanelAction
function title() function title()
{ {
// TRANS: Title for Paths admin panel.
return _('Paths'); return _('Paths');
} }
@ -64,9 +63,9 @@ class PathsadminpanelAction extends AdminPanelAction
* *
* @return string instructions * @return string instructions
*/ */
function getInstructions() function getInstructions()
{ {
// TRANS: Form instructions for Path admin panel.
return _('Path and server settings for this StatusNet site'); return _('Path and server settings for this StatusNet site');
} }
@ -75,7 +74,6 @@ class PathsadminpanelAction extends AdminPanelAction
* *
* @return void * @return void
*/ */
function showForm() function showForm()
{ {
$form = new PathsAdminPanelForm($this); $form = new PathsAdminPanelForm($this);
@ -88,7 +86,6 @@ class PathsadminpanelAction extends AdminPanelAction
* *
* @return void * @return void
*/ */
function saveSettings() function saveSettings()
{ {
static $settings = array( static $settings = array(
@ -148,25 +145,29 @@ class PathsadminpanelAction extends AdminPanelAction
* *
* @return void * @return void
*/ */
function validate(&$values) function validate(&$values)
{ {
// Validate theme dir // Validate theme dir
if (!empty($values['theme']['dir']) && !is_readable($values['theme']['dir'])) { if (!empty($values['theme']['dir']) && !is_readable($values['theme']['dir'])) {
// TRANS: Client error in Paths admin panel.
// TRANS: %s is the directory that could not be read from.
$this->clientError(sprintf(_("Theme directory not readable: %s."), $values['theme']['dir'])); $this->clientError(sprintf(_("Theme directory not readable: %s."), $values['theme']['dir']));
} }
// Validate avatar dir // Validate avatar dir
if (empty($values['avatar']['dir']) || !is_writable($values['avatar']['dir'])) { if (empty($values['avatar']['dir']) || !is_writable($values['avatar']['dir'])) {
// TRANS: Client error in Paths admin panel.
// TRANS: %s is the avatar directory that could not be written to.
$this->clientError(sprintf(_("Avatar directory not writable: %s."), $values['avatar']['dir'])); $this->clientError(sprintf(_("Avatar directory not writable: %s."), $values['avatar']['dir']));
} }
// Validate background dir // Validate background dir
if (empty($values['background']['dir']) || !is_writable($values['background']['dir'])) { if (empty($values['background']['dir']) || !is_writable($values['background']['dir'])) {
// TRANS: Client error in Paths admin panel.
// TRANS: %s is the background directory that could not be written to.
$this->clientError(sprintf(_("Background directory not writable: %s."), $values['background']['dir'])); $this->clientError(sprintf(_("Background directory not writable: %s."), $values['background']['dir']));
} }
@ -175,27 +176,28 @@ class PathsadminpanelAction extends AdminPanelAction
// XXX: What else do we need to validate for lacales path here? --Z // XXX: What else do we need to validate for lacales path here? --Z
if (!empty($values['site']['locale_path']) && !is_readable($values['site']['locale_path'])) { if (!empty($values['site']['locale_path']) && !is_readable($values['site']['locale_path'])) {
// TRANS: Client error in Paths admin panel.
// TRANS: %s is the locales directory that could not be read from.
$this->clientError(sprintf(_("Locales directory not readable: %s."), $values['site']['locale_path'])); $this->clientError(sprintf(_("Locales directory not readable: %s."), $values['site']['locale_path']));
} }
// Validate SSL setup // Validate SSL setup
if (mb_strlen($values['site']['sslserver']) > 255) { if (mb_strlen($values['site']['sslserver']) > 255) {
// TRANS: Client error in Paths admin panel.
// TRANS: %s is the SSL server URL that is too long.
$this->clientError(_('Invalid SSL server. The maximum length is 255 characters.')); $this->clientError(_('Invalid SSL server. The maximum length is 255 characters.'));
} }
} }
} }
class PathsAdminPanelForm extends AdminForm class PathsAdminPanelForm extends AdminForm
{ {
/** /**
* ID of the form * ID of the form
* *
* @return int ID of the form * @return int ID of the form
*/ */
function id() function id()
{ {
return 'form_paths_admin_panel'; return 'form_paths_admin_panel';
@ -206,7 +208,6 @@ class PathsAdminPanelForm extends AdminForm
* *
* @return string class of the form * @return string class of the form
*/ */
function formClass() function formClass()
{ {
return 'form_settings'; return 'form_settings';
@ -217,7 +218,6 @@ class PathsAdminPanelForm extends AdminForm
* *
* @return string URL of the action * @return string URL of the action
*/ */
function action() function action()
{ {
return common_local_url('pathsadminpanel'); return common_local_url('pathsadminpanel');
@ -228,27 +228,39 @@ class PathsAdminPanelForm extends AdminForm
* *
* @return void * @return void
*/ */
function formData() function formData()
{ {
$this->out->elementStart('fieldset', array('id' => 'settings_paths_locale')); $this->out->elementStart('fieldset', array('id' => 'settings_paths_locale'));
// TRANS: Fieldset legend in Paths admin panel.
$this->out->element('legend', null, _('Site'), 'site'); $this->out->element('legend', null, _('Site'), 'site');
$this->out->elementStart('ul', 'form_data'); $this->out->elementStart('ul', 'form_data');
$this->li(); $this->li();
$this->input('server', _('Server'), _('Site\'s server hostname.')); $this->input('server',
// TRANS: Field label in Paths admin panel.
_('Server'),
_('Site\'s server hostname.'));
$this->unli(); $this->unli();
$this->li(); $this->li();
$this->input('path', _('Path'), _('Site path')); $this->input('path',
// TRANS: Field label in Paths admin panel.
_('Path'),
_('Site path.'));
$this->unli(); $this->unli();
$this->li(); $this->li();
$this->input('locale_path', _('Locale Directory'), _('Directory path to locales'), 'site'); $this->input('locale_path',
// TRANS: Field label in Paths admin panel.
_('Locale directory'),
_('Directory path to locales.'),
'site');
$this->unli(); $this->unli();
$this->li(); $this->li();
$this->out->checkbox('fancy', _('Fancy URLs'), $this->out->checkbox('fancy',
// TRANS: Checkbox label in Paths admin panel.
_('Fancy URLs'),
(bool) $this->value('fancy'), (bool) $this->value('fancy'),
_('Use fancy (more readable and memorable) URLs?')); _('Use fancy (more readable and memorable) URLs?'));
$this->unli(); $this->unli();
@ -262,43 +274,84 @@ class PathsAdminPanelForm extends AdminForm
$this->out->elementStart('ul', 'form_data'); $this->out->elementStart('ul', 'form_data');
$this->li(); $this->li();
$this->input('server', _('Server'), _('Server for themes'), 'theme'); $this->input('server',
// TRANS: Field label in Paths admin panel.
_('Server'),
// TRANS: Tooltip for field label in Paths admin panel.
_('Server for themes.'),
'theme');
$this->unli(); $this->unli();
$this->li(); $this->li();
$this->input('path', _('Path'), _('Web path to themes'), 'theme'); $this->input('path',
// TRANS: Field label in Paths admin panel.
_('Path'),
// TRANS: Tooltip for field label in Paths admin panel.
_('Web path to themes.'),
'theme');
$this->unli(); $this->unli();
$this->li(); $this->li();
$this->input('sslserver', _('SSL server'), _('SSL server for themes (default: SSL server)'), 'theme'); $this->input('sslserver',
// TRANS: Field label in Paths admin panel.
_('SSL server'),
// TRANS: Tooltip for field label in Paths admin panel.
_('SSL server for themes (default: SSL server).'),
'theme');
$this->unli(); $this->unli();
$this->li(); $this->li();
$this->input('sslpath', _('SSL path'), _('SSL path to themes (default: /theme/)'), 'theme'); $this->input('sslpath',
// TRANS: Field label in Paths admin panel.
_('SSL path'),
// TRANS: Tooltip for field label in Paths admin panel.
_('SSL path to themes (default: /theme/).'),
'theme');
$this->unli(); $this->unli();
$this->li(); $this->li();
$this->input('dir', _('Directory'), _('Directory where themes are located'), 'theme'); $this->input('dir',
// TRANS: Field label in Paths admin panel.
_('Directory'),
// TRANS: Tooltip for field label in Paths admin panel.
_('Directory where themes are located.'),
'theme');
$this->unli(); $this->unli();
$this->out->elementEnd('ul'); $this->out->elementEnd('ul');
$this->out->elementEnd('fieldset'); $this->out->elementEnd('fieldset');
$this->out->elementStart('fieldset', array('id' => 'settings_avatar-paths')); $this->out->elementStart('fieldset', array('id' => 'settings_avatar-paths'));
// TRANS: Fieldset legend in Paths admin panel.
$this->out->element('legend', null, _('Avatars')); $this->out->element('legend', null, _('Avatars'));
$this->out->elementStart('ul', 'form_data'); $this->out->elementStart('ul', 'form_data');
$this->li(); $this->li();
$this->input('server', _('Avatar server'), 'Server for avatars', 'avatar'); $this->input('server',
// TRANS: Field label in Paths admin panel.
_('Avatar server'),
// TRANS: Tooltip for field label in Paths admin panel.
_('Server for avatars.'),
'avatar');
$this->unli(); $this->unli();
$this->li(); $this->li();
$this->input('path', _('Avatar path'), 'Web path to avatars', 'avatar'); $this->input('path',
// TRANS: Field label in Paths admin panel.
_('Avatar path'),
// TRANS: Tooltip for field label in Paths admin panel.
_('Web path to avatars.'),
'avatar');
$this->unli(); $this->unli();
$this->li(); $this->li();
$this->input('dir', _('Avatar directory'), 'Directory where avatars are located', 'avatar'); $this->input('dir',
// TRANS: Field label in Paths admin panel.
_('Avatar directory'),
// TRANS: Tooltip for field label in Paths admin panel.
_('Directory where avatars are located.'),
'avatar');
$this->unli(); $this->unli();
$this->out->elementEnd('ul'); $this->out->elementEnd('ul');
@ -307,27 +360,53 @@ class PathsAdminPanelForm extends AdminForm
$this->out->elementStart('fieldset', array('id' => $this->out->elementStart('fieldset', array('id' =>
'settings_design_background-paths')); 'settings_design_background-paths'));
// TRANS: Fieldset legend in Paths admin panel.
$this->out->element('legend', null, _('Backgrounds')); $this->out->element('legend', null, _('Backgrounds'));
$this->out->elementStart('ul', 'form_data'); $this->out->elementStart('ul', 'form_data');
$this->li(); $this->li();
$this->input('server', _('Server'), 'Server for backgrounds', 'background'); $this->input('server',
// TRANS: Field label in Paths admin panel.
_('Server'),
// TRANS: Tooltip for field label in Paths admin panel.
_('Server for backgrounds.'),
'background');
$this->unli(); $this->unli();
$this->li(); $this->li();
$this->input('path', _('Path'), 'Web path to backgrounds', 'background'); $this->input('path',
// TRANS: Field label in Paths admin panel.
_('Path'),
// TRANS: Tooltip for field label in Paths admin panel.
_('Web path to backgrounds.'),
'background');
$this->unli(); $this->unli();
$this->li(); $this->li();
$this->input('sslserver', _('SSL server'), 'Server for backgrounds on SSL pages', 'background'); $this->input('sslserver',
// TRANS: Field label in Paths admin panel.
_('SSL server'),
// TRANS: Tooltip for field label in Paths admin panel.
_('Server for backgrounds on SSL pages.'),
'background');
$this->unli(); $this->unli();
$this->li(); $this->li();
$this->input('sslpath', _('SSL path'), 'Web path to backgrounds on SSL pages', 'background'); $this->input('sslpath',
// TRANS: Field label in Paths admin panel.
_('SSL path'),
// TRANS: Tooltip for field label in Paths admin panel.
_('Web path to backgrounds on SSL pages.'),
'background');
$this->unli(); $this->unli();
$this->li(); $this->li();
$this->input('dir', _('Directory'), 'Directory where backgrounds are located', 'background'); $this->input('dir',
// TRANS: Field label in Paths admin panel.
_('Directory'),
// TRANS: Tooltip for field label in Paths admin panel.
_('Directory where backgrounds are located.'),
'background');
$this->unli(); $this->unli();
$this->out->elementEnd('ul'); $this->out->elementEnd('ul');
@ -336,53 +415,90 @@ class PathsAdminPanelForm extends AdminForm
$this->out->elementStart('fieldset', array('id' => $this->out->elementStart('fieldset', array('id' =>
'settings_design_attachments-paths')); 'settings_design_attachments-paths'));
// TRANS: Fieldset legens in Paths admin panel.
$this->out->element('legend', null, _('Attachments')); $this->out->element('legend', null, _('Attachments'));
$this->out->elementStart('ul', 'form_data'); $this->out->elementStart('ul', 'form_data');
$this->li(); $this->li();
$this->input('server', _('Server'), 'Server for attachments', 'attachments'); $this->input('server',
// TRANS: Field label in Paths admin panel.
_('Server'),
// TRANS: Tooltip for field label in Paths admin panel.
_('Server for attachments.'),
'attachments');
$this->unli(); $this->unli();
$this->li(); $this->li();
$this->input('path', _('Path'), 'Web path to attachments', 'attachments'); $this->input('path',
// TRANS: Field label in Paths admin panel.
_('Path'),
// TRANS: Tooltip for field label in Paths admin panel.
_('Web path to attachments.'),
'attachments');
$this->unli(); $this->unli();
$this->li(); $this->li();
$this->input('sslserver', _('SSL server'), 'Server for attachments on SSL pages', 'attachments'); $this->input('sslserver',
// TRANS: Field label in Paths admin panel.
_('SSL server'),
// TRANS: Tooltip for field label in Paths admin panel.
_('Server for attachments on SSL pages.'),
'attachments');
$this->unli(); $this->unli();
$this->li(); $this->li();
$this->input('sslpath', _('SSL path'), 'Web path to attachments on SSL pages', 'attachments'); $this->input('sslpath',
// TRANS: Field label in Paths admin panel.
_('SSL path'),
// TRANS: Tooltip for field label in Paths admin panel.
_('Web path to attachments on SSL pages.'),
'attachments');
$this->unli(); $this->unli();
$this->li(); $this->li();
$this->input('dir', _('Directory'), 'Directory where attachments are located', 'attachments'); $this->input('dir',
// TRANS: Field label in Paths admin panel.
_('Directory'),
// TRANS: Tooltip for field label in Paths admin panel.
_('Directory where attachments are located.'),
'attachments');
$this->unli(); $this->unli();
$this->out->elementEnd('ul'); $this->out->elementEnd('ul');
$this->out->elementEnd('fieldset'); $this->out->elementEnd('fieldset');
$this->out->elementStart('fieldset', array('id' => 'settings_admin_ssl')); $this->out->elementStart('fieldset', array('id' => 'settings_admin_ssl'));
// TRANS: Fieldset legend in Paths admin panel.
$this->out->element('legend', null, _('SSL')); $this->out->element('legend', null, _('SSL'));
$this->out->elementStart('ul', 'form_data'); $this->out->elementStart('ul', 'form_data');
$this->li(); $this->li();
// TRANS: Drop down option in Paths admin panel (option for "When to use SSL").
$ssl = array('never' => _('Never'), $ssl = array('never' => _('Never'),
// TRANS: Drop down option in Paths admin panel (option for "When to use SSL").
'sometimes' => _('Sometimes'), 'sometimes' => _('Sometimes'),
// TRANS: Drop down option in Paths admin panel (option for "When to use SSL").
'always' => _('Always')); 'always' => _('Always'));
$this->out->dropdown('site-ssl', _('Use SSL'), // TRANS: Drop down label in Paths admin panel.
$ssl, _('When to use SSL'), $this->out->dropdown('site-ssl',
false, $this->value('ssl', 'site')); _('Use SSL'),
// TRANS: Tooltip for field label in Paths admin panel.
$ssl, _('When to use SSL.'),
false,
$this->value('ssl', 'site'));
$this->unli(); $this->unli();
$this->li(); $this->li();
$this->input('sslserver', _('SSL server'), $this->input('sslserver',
_('Server to direct SSL requests to'), 'site'); // TRANS: Field label in Paths admin panel.
_('SSL server'),
// TRANS: Tooltip for field label in Paths admin panel.
_('Server to direct SSL requests to.'),
'site');
$this->unli(); $this->unli();
$this->out->elementEnd('ul'); $this->out->elementEnd('ul');
$this->out->elementEnd('fieldset'); $this->out->elementEnd('fieldset');
} }
/** /**
@ -390,10 +506,11 @@ class PathsAdminPanelForm extends AdminForm
* *
* @return void * @return void
*/ */
function formActions() function formActions()
{ {
$this->out->submit('save', _('Save'), 'submit', // TRANS: Button text to store form data in the Paths admin panel.
$this->out->submit('save', _m('BUTTON','Save'), 'submit',
// TRANS: Button title text to store form data in the Paths admin panel.
'save', _('Save paths')); 'save', _('Save paths'));
} }
@ -410,7 +527,6 @@ class PathsAdminPanelForm extends AdminForm
* *
* @return void * @return void
*/ */
function input($setting, $title, $instructions, $section='site') function input($setting, $title, $instructions, $section='site')
{ {
$this->out->input("$section-$setting", $title, $this->value($setting, $section), $instructions); $this->out->input("$section-$setting", $title, $this->value($setting, $section), $instructions);

View File

@ -57,6 +57,7 @@ class ProfilesettingsAction extends AccountSettingsAction
function title() function title()
{ {
// TRANS: Page title for profile settings.
return _('Profile settings'); return _('Profile settings');
} }
@ -68,6 +69,7 @@ class ProfilesettingsAction extends AccountSettingsAction
function getInstructions() function getInstructions()
{ {
// TRANS: Usage instructions for profile settings.
return _('You can update your personal profile info here '. return _('You can update your personal profile info here '.
'so people know more about you.'); 'so people know more about you.');
} }
@ -96,6 +98,7 @@ class ProfilesettingsAction extends AccountSettingsAction
'class' => 'form_settings', 'class' => 'form_settings',
'action' => common_local_url('profilesettings'))); 'action' => common_local_url('profilesettings')));
$this->elementStart('fieldset'); $this->elementStart('fieldset');
// TRANS: Profile settings form legend.
$this->element('legend', null, _('Profile information')); $this->element('legend', null, _('Profile information'));
$this->hidden('token', common_session_token()); $this->hidden('token', common_session_token());
@ -103,38 +106,54 @@ class ProfilesettingsAction extends AccountSettingsAction
$this->elementStart('ul', 'form_data'); $this->elementStart('ul', 'form_data');
if (Event::handle('StartProfileFormData', array($this))) { if (Event::handle('StartProfileFormData', array($this))) {
$this->elementStart('li'); $this->elementStart('li');
// TRANS: Field label in form for profile settings.
$this->input('nickname', _('Nickname'), $this->input('nickname', _('Nickname'),
($this->arg('nickname')) ? $this->arg('nickname') : $profile->nickname, ($this->arg('nickname')) ? $this->arg('nickname') : $profile->nickname,
_('1-64 lowercase letters or numbers, no punctuation or spaces')); // TRANS: Tooltip for field label in form for profile settings.
_('1-64 lowercase letters or numbers, no punctuation or spaces.'));
$this->elementEnd('li'); $this->elementEnd('li');
$this->elementStart('li'); $this->elementStart('li');
// TRANS: Field label in form for profile settings.
$this->input('fullname', _('Full name'), $this->input('fullname', _('Full name'),
($this->arg('fullname')) ? $this->arg('fullname') : $profile->fullname); ($this->arg('fullname')) ? $this->arg('fullname') : $profile->fullname);
$this->elementEnd('li'); $this->elementEnd('li');
$this->elementStart('li'); $this->elementStart('li');
// TRANS: Field label in form for profile settings.
$this->input('homepage', _('Homepage'), $this->input('homepage', _('Homepage'),
($this->arg('homepage')) ? $this->arg('homepage') : $profile->homepage, ($this->arg('homepage')) ? $this->arg('homepage') : $profile->homepage,
_('URL of your homepage, blog, or profile on another site')); // TRANS: Tooltip for field label in form for profile settings.
_('URL of your homepage, blog, or profile on another site.'));
$this->elementEnd('li'); $this->elementEnd('li');
$this->elementStart('li'); $this->elementStart('li');
$maxBio = Profile::maxBio(); $maxBio = Profile::maxBio();
if ($maxBio > 0) { if ($maxBio > 0) {
$bioInstr = sprintf(_('Describe yourself and your interests in %d chars'), // TRANS: Tooltip for field label in form for profile settings. Plural
// TRANS: is decided by the number of characters available for the
// TRANS: biography (%d).
$bioInstr = sprintf(_m('Describe yourself and your interests in %d character',
'Describe yourself and your interests in %d characters',
$maxBio),
$maxBio); $maxBio);
} else { } else {
// TRANS: Tooltip for field label in form for profile settings.
$bioInstr = _('Describe yourself and your interests'); $bioInstr = _('Describe yourself and your interests');
} }
// TRANS: Text area label in form for profile settings where users can provide.
// TRANS: their biography.
$this->textarea('bio', _('Bio'), $this->textarea('bio', _('Bio'),
($this->arg('bio')) ? $this->arg('bio') : $profile->bio, ($this->arg('bio')) ? $this->arg('bio') : $profile->bio,
$bioInstr); $bioInstr);
$this->elementEnd('li'); $this->elementEnd('li');
$this->elementStart('li'); $this->elementStart('li');
// TRANS: Field label in form for profile settings.
$this->input('location', _('Location'), $this->input('location', _('Location'),
($this->arg('location')) ? $this->arg('location') : $profile->location, ($this->arg('location')) ? $this->arg('location') : $profile->location,
// TRANS: Tooltip for field label in form for profile settings.
_('Where you are, like "City, State (or Region), Country"')); _('Where you are, like "City, State (or Region), Country"'));
$this->elementEnd('li'); $this->elementEnd('li');
if (common_config('location', 'share') == 'user') { if (common_config('location', 'share') == 'user') {
$this->elementStart('li'); $this->elementStart('li');
// TRANS: Checkbox label in form for profile settings.
$this->checkbox('sharelocation', _('Share my current location when posting notices'), $this->checkbox('sharelocation', _('Share my current location when posting notices'),
($this->arg('sharelocation')) ? ($this->arg('sharelocation')) ?
$this->arg('sharelocation') : $user->shareLocation()); $this->arg('sharelocation') : $user->shareLocation());
@ -142,13 +161,17 @@ class ProfilesettingsAction extends AccountSettingsAction
} }
Event::handle('EndProfileFormData', array($this)); Event::handle('EndProfileFormData', array($this));
$this->elementStart('li'); $this->elementStart('li');
// TRANS: Field label in form for profile settings.
$this->input('tags', _('Tags'), $this->input('tags', _('Tags'),
($this->arg('tags')) ? $this->arg('tags') : implode(' ', $user->getSelfTags()), ($this->arg('tags')) ? $this->arg('tags') : implode(' ', $user->getSelfTags()),
// TRANS: Tooltip for field label in form for profile settings.
_('Tags for yourself (letters, numbers, -, ., and _), comma- or space- separated')); _('Tags for yourself (letters, numbers, -, ., and _), comma- or space- separated'));
$this->elementEnd('li'); $this->elementEnd('li');
$this->elementStart('li'); $this->elementStart('li');
$language = common_language(); $language = common_language();
// TRANS: Dropdownlist label in form for profile settings.
$this->dropdown('language', _('Language'), $this->dropdown('language', _('Language'),
// TRANS: Tooltip for dropdown list label in form for profile settings.
get_nice_language_list(), _('Preferred language'), get_nice_language_list(), _('Preferred language'),
false, $language); false, $language);
$this->elementEnd('li'); $this->elementEnd('li');
@ -158,12 +181,15 @@ class ProfilesettingsAction extends AccountSettingsAction
$timezones[$v] = $v; $timezones[$v] = $v;
} }
$this->elementStart('li'); $this->elementStart('li');
// TRANS: Dropdownlist label in form for profile settings.
$this->dropdown('timezone', _('Timezone'), $this->dropdown('timezone', _('Timezone'),
// TRANS: Tooltip for dropdown list label in form for profile settings.
$timezones, _('What timezone are you normally in?'), $timezones, _('What timezone are you normally in?'),
true, $timezone); true, $timezone);
$this->elementEnd('li'); $this->elementEnd('li');
$this->elementStart('li'); $this->elementStart('li');
$this->checkbox('autosubscribe', $this->checkbox('autosubscribe',
// TRANS: Checkbox label in form for profile settings.
_('Automatically subscribe to whoever '. _('Automatically subscribe to whoever '.
'subscribes to me (best for non-humans)'), 'subscribes to me (best for non-humans)'),
($this->arg('autosubscribe')) ? ($this->arg('autosubscribe')) ?
@ -171,7 +197,8 @@ class ProfilesettingsAction extends AccountSettingsAction
$this->elementEnd('li'); $this->elementEnd('li');
} }
$this->elementEnd('ul'); $this->elementEnd('ul');
$this->submit('save', _('Save')); // TRANS: Button to save input in profile settings.
$this->submit('save', _m('BUTTON','Save'));
$this->elementEnd('fieldset'); $this->elementEnd('fieldset');
$this->elementEnd('form'); $this->elementEnd('form');
@ -212,33 +239,46 @@ class ProfilesettingsAction extends AccountSettingsAction
if (!Validate::string($nickname, array('min_length' => 1, if (!Validate::string($nickname, array('min_length' => 1,
'max_length' => 64, 'max_length' => 64,
'format' => NICKNAME_FMT))) { 'format' => NICKNAME_FMT))) {
// TRANS: Validation error in form for profile settings.
$this->showForm(_('Nickname must have only lowercase letters and numbers and no spaces.')); $this->showForm(_('Nickname must have only lowercase letters and numbers and no spaces.'));
return; return;
} else if (!User::allowed_nickname($nickname)) { } else if (!User::allowed_nickname($nickname)) {
// TRANS: Validation error in form for profile settings.
$this->showForm(_('Not a valid nickname.')); $this->showForm(_('Not a valid nickname.'));
return; return;
} else if (!is_null($homepage) && (strlen($homepage) > 0) && } else if (!is_null($homepage) && (strlen($homepage) > 0) &&
!Validate::uri($homepage, array('allowed_schemes' => array('http', 'https')))) { !Validate::uri($homepage, array('allowed_schemes' => array('http', 'https')))) {
// TRANS: Validation error in form for profile settings.
$this->showForm(_('Homepage is not a valid URL.')); $this->showForm(_('Homepage is not a valid URL.'));
return; return;
} else if (!is_null($fullname) && mb_strlen($fullname) > 255) { } else if (!is_null($fullname) && mb_strlen($fullname) > 255) {
$this->showForm(_('Full name is too long (max 255 chars).')); // TRANS: Validation error in form for profile settings.
$this->showForm(_('Full name is too long (maximum 255 characters).'));
return; return;
} else if (Profile::bioTooLong($bio)) { } else if (Profile::bioTooLong($bio)) {
$this->showForm(sprintf(_('Bio is too long (max %d chars).'), // TRANS: Validation error in form for profile settings.
// TRANS: Plural form is used based on the maximum number of allowed
// TRANS: characters for the biography (%d).
$this->showForm(sprintf(_m('Bio is too long (maximum %d character).',
'Bio is too long (maximum %d characters).',
Profile::maxBio()),
Profile::maxBio())); Profile::maxBio()));
return; return;
} else if (!is_null($location) && mb_strlen($location) > 255) { } else if (!is_null($location) && mb_strlen($location) > 255) {
$this->showForm(_('Location is too long (max 255 chars).')); // TRANS: Validation error in form for profile settings.
$this->showForm(_('Location is too long (maximum 255 characters).'));
return; return;
} else if (is_null($timezone) || !in_array($timezone, DateTimeZone::listIdentifiers())) { } else if (is_null($timezone) || !in_array($timezone, DateTimeZone::listIdentifiers())) {
// TRANS: Validation error in form for profile settings.
$this->showForm(_('Timezone not selected.')); $this->showForm(_('Timezone not selected.'));
return; return;
} else if ($this->nicknameExists($nickname)) { } else if ($this->nicknameExists($nickname)) {
// TRANS: Validation error in form for profile settings.
$this->showForm(_('Nickname already in use. Try another one.')); $this->showForm(_('Nickname already in use. Try another one.'));
return; return;
} else if (!is_null($language) && strlen($language) > 50) { } else if (!is_null($language) && strlen($language) > 50) {
$this->showForm(_('Language is too long (max 50 chars).')); // TRANS: Validation error in form for profile settings.
$this->showForm(_('Language is too long (maximum 50 characters).'));
return; return;
} }
@ -250,6 +290,8 @@ class ProfilesettingsAction extends AccountSettingsAction
foreach ($tags as $tag) { foreach ($tags as $tag) {
if (!common_valid_profile_tag($tag)) { if (!common_valid_profile_tag($tag)) {
// TRANS: Validation error in form for profile settings.
// TRANS: %s is an invalid tag.
$this->showForm(sprintf(_('Invalid tag: "%s"'), $tag)); $this->showForm(sprintf(_('Invalid tag: "%s"'), $tag));
return; return;
} }
@ -280,6 +322,7 @@ class ProfilesettingsAction extends AccountSettingsAction
if ($result === false) { if ($result === false) {
common_log_db_error($user, 'UPDATE', __FILE__); common_log_db_error($user, 'UPDATE', __FILE__);
// TRANS: Server error thrown when user profile settings could not be updated.
$this->serverError(_('Couldn\'t update user.')); $this->serverError(_('Couldn\'t update user.'));
return; return;
} else { } else {
@ -303,6 +346,8 @@ class ProfilesettingsAction extends AccountSettingsAction
if ($result === false) { if ($result === false) {
common_log_db_error($user, 'UPDATE', __FILE__); common_log_db_error($user, 'UPDATE', __FILE__);
// TRANS: Server error thrown when user profile settings could not be updated to
// TRANS: automatically subscribe to any subscriber.
$this->serverError(_('Couldn\'t update user for autosubscribe.')); $this->serverError(_('Couldn\'t update user for autosubscribe.'));
return; return;
} }
@ -360,6 +405,7 @@ class ProfilesettingsAction extends AccountSettingsAction
if ($result === false) { if ($result === false) {
common_log_db_error($prefs, ($exists) ? 'UPDATE' : 'INSERT', __FILE__); common_log_db_error($prefs, ($exists) ? 'UPDATE' : 'INSERT', __FILE__);
// TRANS: Server error thrown when user profile location preference settings could not be updated.
$this->serverError(_('Couldn\'t save location prefs.')); $this->serverError(_('Couldn\'t save location prefs.'));
return; return;
} }
@ -372,6 +418,7 @@ class ProfilesettingsAction extends AccountSettingsAction
if ($result === false) { if ($result === false) {
common_log_db_error($profile, 'UPDATE', __FILE__); common_log_db_error($profile, 'UPDATE', __FILE__);
// TRANS: Server error thrown when user profile settings could not be saved.
$this->serverError(_('Couldn\'t save profile.')); $this->serverError(_('Couldn\'t save profile.'));
return; return;
} }
@ -380,6 +427,7 @@ class ProfilesettingsAction extends AccountSettingsAction
$result = $user->setSelfTags($tags); $result = $user->setSelfTags($tags);
if (!$result) { if (!$result) {
// TRANS: Server error thrown when user profile settings tags could not be saved.
$this->serverError(_('Couldn\'t save tags.')); $this->serverError(_('Couldn\'t save tags.'));
return; return;
} }
@ -388,6 +436,7 @@ class ProfilesettingsAction extends AccountSettingsAction
Event::handle('EndProfileSaveForm', array($this)); Event::handle('EndProfileSaveForm', array($this));
common_broadcast_profile($profile); common_broadcast_profile($profile);
// TRANS: Confirmation shown when user profile settings are saved.
$this->showForm(_('Settings saved.'), true); $this->showForm(_('Settings saved.'), true);
} }

View File

@ -44,7 +44,6 @@ define('TAGS_PER_PAGE', 100);
* @copyright 2008-2009 StatusNet, Inc. * @copyright 2008-2009 StatusNet, Inc.
* @link http://status.net/ * @link http://status.net/
*/ */
class PublictagcloudAction extends Action class PublictagcloudAction extends Action
{ {
function isReadOnly($args) function isReadOnly($args)
@ -54,24 +53,37 @@ class PublictagcloudAction extends Action
function title() function title()
{ {
// TRANS: Title for public tag cloud.
return _('Public tag cloud'); return _('Public tag cloud');
} }
function showPageNotice() function showPageNotice()
{ {
$this->element('p', 'instructions', $this->element('p', 'instructions',
sprintf(_('These are most popular recent tags on %s '), // TRANS: Instructions (more used like an explanation/header).
// TRANS: %s is the StatusNet sitename.
sprintf(_('These are most popular recent tags on %s'),
common_config('site', 'name'))); common_config('site', 'name')));
} }
function showEmptyList() function showEmptyList()
{ {
// TRANS: This message contains a Markdown URL. The link description is between
// TRANS: square brackets, and the link between parentheses. Do not separate "]("
// TRANS: and do not change the URL part.
$message = _('No one has posted a notice with a [hashtag](%%doc.tags%%) yet.') . ' '; $message = _('No one has posted a notice with a [hashtag](%%doc.tags%%) yet.') . ' ';
if (common_logged_in()) { if (common_logged_in()) {
// TRANS: Message shown to a logged in user for the public tag cloud
// TRANS: while no tags exist yet. "One" refers to the non-existing hashtag.
$message .= _('Be the first to post one!'); $message .= _('Be the first to post one!');
} }
else { else {
// TRANS: Message shown to a anonymous user for the public tag cloud
// TRANS: while no tags exist yet. "One" refers to the non-existing hashtag.
// TRANS: This message contains a Markdown URL. The link description is between
// TRANS: square brackets, and the link between parentheses. Do not separate "]("
// TRANS: and do not change the URL part.
$message .= _('Why not [register an account](%%action.register%%) and be the first to post one!'); $message .= _('Why not [register an account](%%action.register%%) and be the first to post one!');
} }

View File

@ -217,14 +217,16 @@ class RegisterAction extends Action
$this->showForm(_('Homepage is not a valid URL.')); $this->showForm(_('Homepage is not a valid URL.'));
return; return;
} else if (!is_null($fullname) && mb_strlen($fullname) > 255) { } else if (!is_null($fullname) && mb_strlen($fullname) > 255) {
$this->showForm(_('Full name is too long (max 255 chars).')); $this->showForm(_('Full name is too long (maximum 255 characters).'));
return; return;
} else if (Profile::bioTooLong($bio)) { } else if (Profile::bioTooLong($bio)) {
$this->showForm(sprintf(_('Bio is too long (max %d chars).'), $this->showForm(sprintf(_m('Bio is too long (maximum %d character).',
'Bio is too long (maximum %d characters).',
Profile::maxBio()),
Profile::maxBio())); Profile::maxBio()));
return; return;
} else if (!is_null($location) && mb_strlen($location) > 255) { } else if (!is_null($location) && mb_strlen($location) > 255) {
$this->showForm(_('Location is too long (max 255 chars).')); $this->showForm(_('Location is too long (maximum 255 characters).'));
return; return;
} else if (strlen($password) < 6) { } else if (strlen($password) < 6) {
$this->showForm(_('Password must be 6 or more characters.')); $this->showForm(_('Password must be 6 or more characters.'));
@ -458,7 +460,12 @@ class RegisterAction extends Action
$this->elementStart('li'); $this->elementStart('li');
$maxBio = Profile::maxBio(); $maxBio = Profile::maxBio();
if ($maxBio > 0) { if ($maxBio > 0) {
$bioInstr = sprintf(_('Describe yourself and your interests in %d chars'), // TRANS: Tooltip for field label in form for profile settings. Plural
// TRANS: is decided by the number of characters available for the
// TRANS: biography (%d).
$bioInstr = sprintf(_m('Describe yourself and your interests in %d character',
'Describe yourself and your interests in %d characters',
$maxBio),
$maxBio); $maxBio);
} else { } else {
$bioInstr = _('Describe yourself and your interests'); $bioInstr = _('Describe yourself and your interests');

View File

@ -54,7 +54,6 @@ require_once INSTALLDIR.'/lib/feedlist.php';
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/ * @link http://status.net/
*/ */
class ShowstreamAction extends ProfileAction class ShowstreamAction extends ProfileAction
{ {
function isReadOnly($args) function isReadOnly($args)
@ -84,7 +83,6 @@ class ShowstreamAction extends ProfileAction
function handle($args) function handle($args)
{ {
// Looks like we're good; start output // Looks like we're good; start output
// For YADIS discovery, we also have a <meta> tag // For YADIS discovery, we also have a <meta> tag
@ -180,7 +178,6 @@ class ShowstreamAction extends ProfileAction
$this->element('link', array('rel' => 'EditURI', $this->element('link', array('rel' => 'EditURI',
'type' => 'application/rsd+xml', 'type' => 'application/rsd+xml',
'href' => $rsd)); 'href' => $rsd));
} }
function showProfile() function showProfile()

View File

@ -41,14 +41,17 @@ if (!defined('STATUSNET') && !defined('LACONICA')) {
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/ * @link http://status.net/
*/ */
class SubscribersAction extends GalleryAction class SubscribersAction extends GalleryAction
{ {
function title() function title()
{ {
if ($this->page == 1) { if ($this->page == 1) {
// TRANS: Header for list of subscribers for a user (first page).
// TRANS: %s is the user's nickname.
return sprintf(_('%s subscribers'), $this->user->nickname); return sprintf(_('%s subscribers'), $this->user->nickname);
} else { } else {
// TRANS: Header for list of subscribers for a user (not first page).
// TRANS: %1$s is the user's nickname, $2$d is the page number.
return sprintf(_('%1$s subscribers, page %2$d'), return sprintf(_('%1$s subscribers, page %2$d'),
$this->user->nickname, $this->user->nickname,
$this->page); $this->page);
@ -60,10 +63,14 @@ class SubscribersAction extends GalleryAction
$user = common_current_user(); $user = common_current_user();
if ($user && ($user->id == $this->profile->id)) { if ($user && ($user->id == $this->profile->id)) {
$this->element('p', null, $this->element('p', null,
// TRANS: Page notice for page with an overview of all subscribers
// TRANS: of the logged in user's own profile.
_('These are the people who listen to '. _('These are the people who listen to '.
'your notices.')); 'your notices.'));
} else { } else {
$this->element('p', null, $this->element('p', null,
// TRANS: Page notice for page with an overview of all subscribers of a user other
// TRANS: than the logged in user. %s is the user nickname.
sprintf(_('These are the people who '. sprintf(_('These are the people who '.
'listen to %s\'s notices.'), 'listen to %s\'s notices.'),
$this->profile->nickname)); $this->profile->nickname));
@ -105,12 +112,20 @@ class SubscribersAction extends GalleryAction
if (common_logged_in()) { if (common_logged_in()) {
$current_user = common_current_user(); $current_user = common_current_user();
if ($this->user->id === $current_user->id) { if ($this->user->id === $current_user->id) {
$message = _('You have no subscribers. Try subscribing to people you know and they might return the favor'); // TRANS: Subscriber list text when the logged in user has no subscribers.
$message = _('You have no subscribers. Try subscribing to people you know and they might return the favor.');
} else { } else {
// TRANS: Subscriber list text when looking at the subscribers for a of a user other
// TRANS: than the logged in user that has no subscribers. %s is the user nickname.
$message = sprintf(_('%s has no subscribers. Want to be the first?'), $this->user->nickname); $message = sprintf(_('%s has no subscribers. Want to be the first?'), $this->user->nickname);
} }
} }
else { else {
// TRANS: Subscriber list text when looking at the subscribers for a of a user that has none
// TRANS: as an anonymous user. %s is the user nickname.
// TRANS: This message contains a Markdown URL. The link description is between
// TRANS: square brackets, and the link between parentheses. Do not separate "]("
// TRANS: and do not change the URL part.
$message = sprintf(_('%s has no subscribers. Why not [register an account](%%%%action.register%%%%) and be the first?'), $this->user->nickname); $message = sprintf(_('%s has no subscribers. Why not [register an account](%%%%action.register%%%%) and be the first?'), $this->user->nickname);
} }

View File

@ -41,16 +41,17 @@ if (!defined('STATUSNET') && !defined('LACONICA')) {
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/ * @link http://status.net/
*/ */
if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
class SubscriptionsAction extends GalleryAction class SubscriptionsAction extends GalleryAction
{ {
function title() function title()
{ {
if ($this->page == 1) { if ($this->page == 1) {
// TRANS: Header for subscriptions overview for a user (first page).
// TRANS: %s is a user nickname.
return sprintf(_('%s subscriptions'), $this->user->nickname); return sprintf(_('%s subscriptions'), $this->user->nickname);
} else { } else {
// TRANS: Header for subscriptions overview for a user (not first page).
// TRANS: %1$s is a user nickname, %2$d is the page number.
return sprintf(_('%1$s subscriptions, page %2$d'), return sprintf(_('%1$s subscriptions, page %2$d'),
$this->user->nickname, $this->user->nickname,
$this->page); $this->page);
@ -62,10 +63,14 @@ class SubscriptionsAction extends GalleryAction
$user = common_current_user(); $user = common_current_user();
if ($user && ($user->id == $this->profile->id)) { if ($user && ($user->id == $this->profile->id)) {
$this->element('p', null, $this->element('p', null,
// TRANS: Page notice for page with an overview of all subscriptions
// TRANS: of the logged in user's own profile.
_('These are the people whose notices '. _('These are the people whose notices '.
'you listen to.')); 'you listen to.'));
} else { } else {
$this->element('p', null, $this->element('p', null,
// TRANS: Page notice for page with an overview of all subscriptions of a user other
// TRANS: than the logged in user. %s is the user nickname.
sprintf(_('These are the people whose '. sprintf(_('These are the people whose '.
'notices %s listens to.'), 'notices %s listens to.'),
$this->profile->nickname)); $this->profile->nickname));
@ -123,12 +128,24 @@ class SubscriptionsAction extends GalleryAction
if (common_logged_in()) { if (common_logged_in()) {
$current_user = common_current_user(); $current_user = common_current_user();
if ($this->user->id === $current_user->id) { if ($this->user->id === $current_user->id) {
$message = _('You\'re not listening to anyone\'s notices right now, try subscribing to people you know. Try [people search](%%action.peoplesearch%%), look for members in groups you\'re interested in and in our [featured users](%%action.featured%%). If you\'re a [Twitter user](%%action.twittersettings%%), you can automatically subscribe to people you already follow there.'); // TRANS: Subscription list text when the logged in user has no subscriptions.
// TRANS: This message contains Markdown URLs. The link description is between
// TRANS: square brackets, and the link between parentheses. Do not separate "]("
// TRANS: and do not change the URL part.
$message = _('You\'re not listening to anyone\'s notices right now, try subscribing to people you know. '.
'Try [people search](%%action.peoplesearch%%), look for members in groups you\'re interested '.
'in and in our [featured users](%%action.featured%%). '.
'If you\'re a [Twitter user](%%action.twittersettings%%), you can automatically subscribe to '.
'people you already follow there.');
} else { } else {
// TRANS: Subscription list text when looking at the subscriptions for a of a user other
// TRANS: than the logged in user that has no subscriptions. %s is the user nickname.
$message = sprintf(_('%s is not listening to anyone.'), $this->user->nickname); $message = sprintf(_('%s is not listening to anyone.'), $this->user->nickname);
} }
} }
else { else {
// TRANS: Subscription list text when looking at the subscriptions for a of a user that has none
// TRANS: as an anonymous user. %s is the user nickname.
$message = sprintf(_('%s is not listening to anyone.'), $this->user->nickname); $message = sprintf(_('%s is not listening to anyone.'), $this->user->nickname);
} }
@ -207,6 +224,7 @@ class SubscriptionsListItem extends SubscriptionListItem
} }
$this->out->element('input', $attrs); $this->out->element('input', $attrs);
// TRANS: Checkbox label for enabling Jabber messages for a profile in a subscriptions list.
$this->out->element('label', array('for' => 'jabber-'.$this->profile->id), _('IM')); $this->out->element('label', array('for' => 'jabber-'.$this->profile->id), _('IM'));
} else { } else {
$this->out->hidden('jabber', $sub->jabber); $this->out->hidden('jabber', $sub->jabber);
@ -221,11 +239,13 @@ class SubscriptionsListItem extends SubscriptionListItem
} }
$this->out->element('input', $attrs); $this->out->element('input', $attrs);
// TRANS: Checkbox label for enabling SMS messages for a profile in a subscriptions list.
$this->out->element('label', array('for' => 'sms-'.$this->profile->id), _('SMS')); $this->out->element('label', array('for' => 'sms-'.$this->profile->id), _('SMS'));
} else { } else {
$this->out->hidden('sms', $sub->sms); $this->out->hidden('sms', $sub->sms);
} }
$this->out->submit('save', _('Save')); // TRANS: Save button for settings for a profile in a subscriptions list.
$this->out->submit('save', _m('BUTTON','Save'));
$this->out->elementEnd('form'); $this->out->elementEnd('form');
return; return;
} }

View File

@ -60,7 +60,7 @@ class Notice_tag extends Memcached_DataObject
} }
if ($max_id != 0) { if ($max_id != 0) {
$nt->whereAdd('notice_id < ' . $max_id); $nt->whereAdd('notice_id <= ' . $max_id);
} }
$nt->orderBy('notice_id DESC'); $nt->orderBy('notice_id DESC');

View File

@ -24,20 +24,51 @@ class Oauth_application_user extends Memcached_DataObject
/* the code above is auto generated do not remove the tag below */ /* the code above is auto generated do not remove the tag below */
###END_AUTOCODE ###END_AUTOCODE
static function getByKeys($user, $app) static function getByUserAndToken($user, $token)
{ {
if (empty($user) || empty($app)) { if (empty($user) || empty($token)) {
return null; return null;
} }
$oau = new Oauth_application_user(); $oau = new Oauth_application_user();
$oau->profile_id = $user->id; $oau->profile_id = $user->id;
$oau->application_id = $app->id; $oau->token = $token;
$oau->limit(1); $oau->limit(1);
$result = $oau->find(true); $result = $oau->find(true);
return empty($result) ? null : $oau; return empty($result) ? null : $oau;
} }
function updateKeys(&$orig)
{
$this->_connect();
$parts = array();
foreach (array('profile_id', 'application_id', 'token', 'access_type') as $k) {
if (strcmp($this->$k, $orig->$k) != 0) {
$parts[] = $k . ' = ' . $this->_quote($this->$k);
}
}
if (count($parts) == 0) {
# No changes
return true;
}
$toupdate = implode(', ', $parts);
$table = $this->tableName();
if(common_config('db','quote_identifiers')) {
$table = '"' . $table . '"';
}
$qry = 'UPDATE ' . $table . ' SET ' . $toupdate .
' WHERE profile_id = ' . $orig->profile_id
. ' AND application_id = ' . $orig->application_id
. " AND token = '$orig->token'";
$orig->decache();
$result = $this->query($qry);
if ($result) {
$this->encache();
}
return $result;
}
} }

View File

@ -0,0 +1,42 @@
<?php
/**
* Table Definition for oauth_association
*/
require_once INSTALLDIR . '/classes/Memcached_DataObject.php';
class Oauth_token_association extends Memcached_DataObject
{
###START_AUTOCODE
/* the code below is auto generated do not remove the above tag */
public $__table = 'oauth_token_association'; // table name
public $profile_id; // int(4) primary_key not_null
public $application_id; // int(4) primary_key not_null
public $token; // varchar(255) primary key not null
public $created; // datetime not_null
public $modified; // timestamp not_null default_CURRENT_TIMESTAMP
/* Static get */
function staticGet($k, $v = NULL) {
return Memcached_DataObject::staticGet('oauth_token_association', $k, $v);
}
/* the code above is auto generated do not remove the tag below */
###END_AUTOCODE
static function getByUserAndToken($user, $token)
{
if (empty($user) || empty($token)) {
return null;
}
$oau = new oauth_request_token();
$oau->profile_id = $user->id;
$oau->token = $token;
$oau->limit(1);
$result = $oau->find(true);
return empty($result) ? null : $oau;
}
}

View File

@ -199,7 +199,7 @@ class Profile extends Memcached_DataObject
} }
if ($max_id != 0) { if ($max_id != 0) {
$query .= " and id < $max_id"; $query .= " and id <= $max_id";
} }
$query .= ' order by id DESC'; $query .= ' order by id DESC';
@ -240,7 +240,7 @@ class Profile extends Memcached_DataObject
} }
if ($max_id != 0) { if ($max_id != 0) {
$query .= " and id < $max_id"; $query .= " and id <= $max_id";
} }
$query .= ' order by id DESC'; $query .= ' order by id DESC';
@ -401,10 +401,10 @@ class Profile extends Memcached_DataObject
return $profile; return $profile;
} }
function getApplications($offset = 0, $limit = null) function getConnectedApps($offset = 0, $limit = null)
{ {
$qry = $qry =
'SELECT a.* ' . 'SELECT u.* ' .
'FROM oauth_application_user u, oauth_application a ' . 'FROM oauth_application_user u, oauth_application a ' .
'WHERE u.profile_id = %d ' . 'WHERE u.profile_id = %d ' .
'AND a.id = u.application_id ' . 'AND a.id = u.application_id ' .
@ -419,11 +419,11 @@ class Profile extends Memcached_DataObject
} }
} }
$application = new Oauth_application(); $apps = new Oauth_application_user();
$cnt = $application->query(sprintf($qry, $this->id)); $cnt = $apps->query(sprintf($qry, $this->id));
return $application; return $apps;
} }
function subscriptionCount() function subscriptionCount()
@ -758,43 +758,52 @@ class Profile extends Memcached_DataObject
function grantRole($name) function grantRole($name)
{ {
$role = new Profile_role(); if (Event::handle('StartGrantRole', array($this, $name))) {
$role->profile_id = $this->id; $role = new Profile_role();
$role->role = $name;
$role->created = common_sql_now();
$result = $role->insert(); $role->profile_id = $this->id;
$role->role = $name;
$role->created = common_sql_now();
if (!$result) { $result = $role->insert();
common_log_db_error($role, 'INSERT', __FILE__);
return false; if (!$result) {
throw new Exception("Can't save role '$name' for profile '{$this->id}'");
}
Event::handle('EndGrantRole', array($this, $name));
} }
return true; return $result;
} }
function revokeRole($name) function revokeRole($name)
{ {
$role = Profile_role::pkeyGet(array('profile_id' => $this->id, if (Event::handle('StartRevokeRole', array($this, $name))) {
'role' => $name));
if (empty($role)) { $role = Profile_role::pkeyGet(array('profile_id' => $this->id,
// TRANS: Exception thrown when trying to revoke an existing role for a user that does not exist. 'role' => $name));
// TRANS: %1$s is the role name, %2$s is the user ID (number).
throw new Exception(sprintf(_('Cannot revoke role "%1$s" for user #%2$d; does not exist.'),$name, $this->id)); if (empty($role)) {
// TRANS: Exception thrown when trying to revoke an existing role for a user that does not exist.
// TRANS: %1$s is the role name, %2$s is the user ID (number).
throw new Exception(sprintf(_('Cannot revoke role "%1$s" for user #%2$d; does not exist.'),$name, $this->id));
}
$result = $role->delete();
if (!$result) {
common_log_db_error($role, 'DELETE', __FILE__);
// TRANS: Exception thrown when trying to revoke a role for a user with a failing database query.
// TRANS: %1$s is the role name, %2$s is the user ID (number).
throw new Exception(sprintf(_('Cannot revoke role "%1$s" for user #%2$d; database error.'),$name, $this->id));
}
Event::handle('EndRevokeRole', array($this, $name));
return true;
} }
$result = $role->delete();
if (!$result) {
common_log_db_error($role, 'DELETE', __FILE__);
// TRANS: Exception thrown when trying to revoke a role for a user with a failing database query.
// TRANS: %1$s is the role name, %2$s is the user ID (number).
throw new Exception(sprintf(_('Cannot revoke role "%1$s" for user #%2$d; database error.'),$name, $this->id));
}
return true;
} }
function isSandboxed() function isSandboxed()

View File

@ -55,7 +55,7 @@ class Reply extends Memcached_DataObject
} }
if ($max_id != 0) { if ($max_id != 0) {
$reply->whereAdd('notice_id < ' . $max_id); $reply->whereAdd('notice_id <= ' . $max_id);
} }
$reply->orderBy('notice_id DESC'); $reply->orderBy('notice_id DESC');

View File

@ -43,7 +43,6 @@ class Status_network_tag extends Safe_DataObject
$this->_connect(); $this->_connect();
} }
/* Static get */ /* Static get */
function staticGet($k,$v=null) function staticGet($k,$v=null)
{ {
@ -99,7 +98,7 @@ class Status_network_tag extends Safe_DataObject
if (Status_network::$cache) { if (Status_network::$cache) {
$packed = implode('|', $result); $packed = implode('|', $result);
Status_network::$cache->set($key, $packed, 3600); Status_network::$cache->set($key, $packed, 0, 3600);
} }
return $result; return $result;

View File

@ -870,4 +870,35 @@ class User extends Memcached_DataObject
return $owner; return $owner;
} }
/**
* Pull the primary site account to use in single-user mode.
* If a valid user nickname is listed in 'singleuser':'nickname'
* in the config, this will be used; otherwise the site owner
* account is taken by default.
*
* @return User
* @throws ServerException if no valid single user account is present
* @throws ServerException if called when not in single-user mode
*/
static function singleUser()
{
if (common_config('singleuser', 'enabled')) {
$nickname = common_config('singleuser', 'nickname');
if ($nickname) {
$user = User::staticGet('nickname', $nickname);
} else {
$user = User::siteOwner();
}
if ($user) {
return $user;
} else {
// TRANS: Server exception.
throw new ServerException(_('No single user defined for single-user mode.'));
}
} else {
// TRANS: Server exception.
throw new ServerException(_('Single-user mode code called when not enabled.'));
}
}
} }

View File

@ -401,6 +401,18 @@ modified = 384
profile_id = K profile_id = K
application_id = K application_id = K
[oauth_token_association]
profile_id = 129
application_id = 129
token = 130
created = 142
modified = 384
[oauth_token_association__keys]
profile_id = K
application_id = K
token = K
[profile] [profile]
id = 129 id = 129
nickname = 130 nickname = 130

View File

@ -232,6 +232,15 @@ create table oauth_application_user (
constraint primary key (profile_id, application_id) constraint primary key (profile_id, application_id)
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin; ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
create table oauth_token_association (
profile_id integer not null comment 'user of the application' references profile (id),
application_id integer not null comment 'id of the application' references oauth_application (id),
token varchar(255) comment 'request or access token',
created datetime not null comment 'date this record was created',
modified timestamp comment 'date this record was modified',
constraint primary key (profile_id, application_id, token)
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
/* These are used by JanRain OpenID library */ /* These are used by JanRain OpenID library */
create table oid_associations ( create table oid_associations (

View File

@ -362,9 +362,9 @@ class Action extends HTMLOutputter // lawsuit
*/ */
function showBody() function showBody()
{ {
$this->elementStart('body', (common_current_user()) ? array('id' => $this->trimmed('action'), $this->elementStart('body', (common_current_user()) ? array('id' => strtolower($this->trimmed('action')),
'class' => 'user_in') 'class' => 'user_in')
: array('id' => $this->trimmed('action'))); : array('id' => strtolower($this->trimmed('action'))));
$this->elementStart('div', array('id' => 'wrap')); $this->elementStart('div', array('id' => 'wrap'));
if (Event::handle('StartShowHeader', array($this))) { if (Event::handle('StartShowHeader', array($this))) {
$this->showHeader(); $this->showHeader();
@ -419,8 +419,9 @@ class Action extends HTMLOutputter // lawsuit
'class' => 'vcard')); 'class' => 'vcard'));
if (Event::handle('StartAddressData', array($this))) { if (Event::handle('StartAddressData', array($this))) {
if (common_config('singleuser', 'enabled')) { if (common_config('singleuser', 'enabled')) {
$user = User::singleUser();
$url = common_local_url('showstream', $url = common_local_url('showstream',
array('nickname' => common_config('singleuser', 'nickname'))); array('nickname' => $user->nickname));
} else { } else {
$url = common_local_url('public'); $url = common_local_url('public');
} }
@ -526,20 +527,20 @@ class Action extends HTMLOutputter // lawsuit
} }
// TRANS: Tooltip for main menu option "Login" // TRANS: Tooltip for main menu option "Login"
$tooltip = _m('TOOLTIP', 'Login to the site'); $tooltip = _m('TOOLTIP', 'Login to the site');
// TRANS: Main menu option when not logged in to log in
$this->menuItem(common_local_url('login'), $this->menuItem(common_local_url('login'),
// TRANS: Main menu option when not logged in to log in
_m('MENU', 'Login'), $tooltip, false, 'nav_login'); _m('MENU', 'Login'), $tooltip, false, 'nav_login');
} }
// TRANS: Tooltip for main menu option "Help" // TRANS: Tooltip for main menu option "Help"
$tooltip = _m('TOOLTIP', 'Help me!'); $tooltip = _m('TOOLTIP', 'Help me!');
// TRANS: Main menu option for help on the StatusNet site
$this->menuItem(common_local_url('doc', array('title' => 'help')), $this->menuItem(common_local_url('doc', array('title' => 'help')),
// TRANS: Main menu option for help on the StatusNet site
_m('MENU', 'Help'), $tooltip, false, 'nav_help'); _m('MENU', 'Help'), $tooltip, false, 'nav_help');
if ($user || !common_config('site', 'private')) { if ($user || !common_config('site', 'private')) {
// TRANS: Tooltip for main menu option "Search" // TRANS: Tooltip for main menu option "Search"
$tooltip = _m('TOOLTIP', 'Search for people or text'); $tooltip = _m('TOOLTIP', 'Search for people or text');
// TRANS: Main menu option when logged in or when the StatusNet instance is not private
$this->menuItem(common_local_url('peoplesearch'), $this->menuItem(common_local_url('peoplesearch'),
// TRANS: Main menu option when logged in or when the StatusNet instance is not private
_m('MENU', 'Search'), $tooltip, false, 'nav_search'); _m('MENU', 'Search'), $tooltip, false, 'nav_search');
} }
Event::handle('EndPrimaryNav', array($this)); Event::handle('EndPrimaryNav', array($this));

View File

@ -1400,8 +1400,10 @@ class ApiAction extends Action
if (is_numeric($this->arg('id'))) { if (is_numeric($this->arg('id'))) {
return Profile::staticGet($this->arg('id')); return Profile::staticGet($this->arg('id'));
} else if ($this->arg('id')) { } else if ($this->arg('id')) {
// Screen names currently can only uniquely identify a local user.
$nickname = common_canonical_nickname($this->arg('id')); $nickname = common_canonical_nickname($this->arg('id'));
return Profile::staticGet('nickname', $nickname); $user = User::staticGet('nickname', $nickname);
return $user ? $user->getProfile() : null;
} else if ($this->arg('user_id')) { } else if ($this->arg('user_id')) {
// This is to ensure that a non-numeric user_id still // This is to ensure that a non-numeric user_id still
// overrides screen_name even if it doesn't get used // overrides screen_name even if it doesn't get used
@ -1410,13 +1412,15 @@ class ApiAction extends Action
} }
} else if ($this->arg('screen_name')) { } else if ($this->arg('screen_name')) {
$nickname = common_canonical_nickname($this->arg('screen_name')); $nickname = common_canonical_nickname($this->arg('screen_name'));
return Profile::staticGet('nickname', $nickname); $user = User::staticGet('nickname', $nickname);
return $user ? $user->getProfile() : null;
} }
} else if (is_numeric($id)) { } else if (is_numeric($id)) {
return Profile::staticGet($id); return Profile::staticGet($id);
} else { } else {
$nickname = common_canonical_nickname($id); $nickname = common_canonical_nickname($id);
return Profile::staticGet('nickname', $nickname); $user = User::staticGet('nickname', $nickname);
return $user ? $user->getProfile() : null;
} }
} }

View File

@ -178,8 +178,10 @@ class ApiAuthAction extends ApiAction
} }
// set the source attr // set the source attr
if ($app->name != 'anonymous') {
$this->source = $app->name;
}
$this->source = $app->name;
$appUser = Oauth_application_user::staticGet('token', $access_token); $appUser = Oauth_application_user::staticGet('token', $access_token);
@ -261,7 +263,7 @@ class ApiAuthAction extends ApiAction
// show error if the user clicks 'cancel' // show error if the user clicks 'cancel'
// TRANS: Client error thrown when authentication fails becaus a user clicked "Cancel". // TRANS: Client error thrown when authentication fails becaus a user clicked "Cancel".
$this->clientError(_("Could not authenticate you."), 401, $this->format); $this->clientError(_('Could not authenticate you.'), 401, $this->format);
exit; exit;
} else { } else {
@ -288,7 +290,7 @@ class ApiAuthAction extends ApiAction
); );
$this->logAuthFailure($msg); $this->logAuthFailure($msg);
// TRANS: Client error thrown when authentication fails. // TRANS: Client error thrown when authentication fails.
$this->clientError(_("Could not authenticate you."), 401, $this->format); $this->clientError(_('Could not authenticate you.'), 401, $this->format);
exit; exit;
} }
} }
@ -340,7 +342,6 @@ class ApiAuthAction extends ApiAction
* *
* @param string $logMsg additional log message * @param string $logMsg additional log message
*/ */
function logAuthFailure($logMsg) function logAuthFailure($logMsg)
{ {
list($proxy, $ip) = common_client_ip(); list($proxy, $ip) = common_client_ip();

View File

@ -23,24 +23,71 @@ require_once INSTALLDIR . '/lib/oauthstore.php';
class ApiStatusNetOAuthDataStore extends StatusNetOAuthDataStore class ApiStatusNetOAuthDataStore extends StatusNetOAuthDataStore
{ {
function lookup_consumer($consumer_key) function lookup_consumer($consumerKey)
{ {
$con = Consumer::staticGet('consumer_key', $consumer_key); $con = Consumer::staticGet('consumer_key', $consumerKey);
if (!$con) { if (!$con) {
return null;
// Create an anon consumer and anon application if one
// doesn't exist already
if ($consumerKey == 'anonymous') {
common_debug("API OAuth - creating anonymous consumer");
$con = new Consumer();
$con->consumer_key = $consumerKey;
$con->consumer_secret = $consumerKey;
$con->created = common_sql_now();
$result = $con->insert();
if (!$result) {
// TRANS: Server error displayed when trying to create an anynymous OAuth consumer.
$this->serverError(_('Could not create anonymous consumer.'));
}
$app = Oauth_application::getByConsumerKey('anonymous');
if (!$app) {
common_debug("API OAuth - creating anonymous application");
$app = new OAuth_application();
$app->owner = 1; // XXX: What to do here?
$app->consumer_key = $con->consumer_key;
$app->name = 'anonymous';
$app->icon = 'default-avatar-stream.png'; // XXX: Fix this!
$app->description = "An anonymous application";
// XXX: allow the user to set the access type when
// authorizing? Currently we default to r+w for anonymous
// OAuth client applications
$app->access_type = 3; // read + write
$app->type = 2; // desktop
$app->created = common_sql_now();
$id = $app->insert();
if (!$id) {
// TRANS: Server error displayed when trying to create an anynymous OAuth application.
$this->serverError(_("Could not create anonymous OAuth application."));
}
}
} else {
return null;
}
} }
return new OAuthConsumer($con->consumer_key, return new OAuthConsumer(
$con->consumer_secret); $con->consumer_key,
$con->consumer_secret
);
} }
function getAppByRequestToken($token_key) function getAppByRequestToken($token_key)
{ {
// Look up the full req tokenx // Look up the full req token
$req_token = $this->lookup_token(null, $req_token = $this->lookup_token(
'request', null,
$token_key); 'request',
$token_key
);
if (empty($req_token)) { if (empty($req_token)) {
common_debug("couldn't get request token from oauth datastore"); common_debug("couldn't get request token from oauth datastore");
@ -58,7 +105,6 @@ class ApiStatusNetOAuthDataStore extends StatusNetOAuthDataStore
} }
// Look up the app // Look up the app
$app = new Oauth_application(); $app = new Oauth_application();
$app->consumer_key = $token->consumer_key; $app->consumer_key = $token->consumer_key;
$result = $app->find(true); $result = $app->find(true);
@ -75,12 +121,12 @@ class ApiStatusNetOAuthDataStore extends StatusNetOAuthDataStore
{ {
common_debug( common_debug(
sprintf( sprintf(
"%s - New access token from request token %s, consumer %s and verifier %s ", "New access token from request token %s, consumer %s and verifier %s ",
__FILE__,
$token, $token,
$consumer, $consumer,
$verifier $verifier
) ),
__FILE__
); );
$rt = new Token(); $rt = new Token();
@ -94,73 +140,123 @@ class ApiStatusNetOAuthDataStore extends StatusNetOAuthDataStore
if ($rt->find(true) && $rt->state == 1 && $rt->verifier == $verifier) { // authorized if ($rt->find(true) && $rt->state == 1 && $rt->verifier == $verifier) { // authorized
common_debug('request token found.', __FILE__); common_debug('Request token found.', __FILE__);
// find the associated user of the app // find the app and profile associated with this token
$tokenAssoc = Oauth_token_association::staticGet('token', $rt->tok);
if (!$tokenAssoc) {
throw new Exception(
// TRANS: Exception thrown when no token association could be found.
_('Could not find a profile and application associated with the request token.')
);
}
// check to see if we have previously issued an access token for this application
// and profile
$appUser = new Oauth_application_user(); $appUser = new Oauth_application_user();
$appUser->application_id = $app->id; $appUser->application_id = $app->id;
$appUser->token = $rt->tok; $appUser->profile_id = $tokenAssoc->profile_id;
$result = $appUser->find(true); $result = $appUser->find(true);
if (!empty($result)) { if (!empty($result)) {
common_debug("Ouath app user found.");
} else {
common_debug("Oauth app user not found. app id $app->id token $rt->tok");
return null;
}
// go ahead and make the access token common_log(LOG_INFO,
sprintf(
"Existing access token found for application %s, profile %s.",
$app->id,
$tokenAssoc->profile_id
)
);
$at = new Token(); $at = new Token();
$at->consumer_key = $consumer->key;
$at->tok = common_good_rand(16);
$at->secret = common_good_rand(16);
$at->type = 1; // access
$at->verifier = $verifier;
$at->verified_callback = $rt->verified_callback; // 1.0a
$at->created = DB_DataObject_Cast::dateTime();
if (!$at->insert()) { // fetch the full access token
$e = $at->_lastError; $at->consumer_key = $consumer->key;
common_debug('access token "'.$at->tok.'" not inserted: "'.$e->message.'"', __FILE__); $at->tok = $appUser->token;
return null;
} else { $result = $at->find(true);
common_debug('access token "'.$at->tok.'" inserted', __FILE__);
// burn the old one if (!$result) {
$orig_rt = clone($rt); throw new Exception(
$rt->state = 2; // used // TRANS: Exception thrown when no access token can be issued.
if (!$rt->update($orig_rt)) { _('Could not issue access token.')
return null; );
} }
common_debug('request token "'.$rt->tok.'" updated', __FILE__);
// update the token from req to access for the user // Yay, we can re-issue the access token
return new OAuthToken($at->tok, $at->secret);
$orig = clone($appUser); } else {
$appUser->token = $at->tok;
// It's at this point that we change the access type common_log(LOG_INFO,
// to whatever the application's access is. Request sprintf(
// tokens should always have an access type of 0, and "Creating new access token for application %s, profile %s.",
// therefore be unuseable for making requests for $app->id,
// protected resources. $tokenAssoc->profile_id
)
);
$appUser->access_type = $app->access_type; // make a brand new access token
$at = new Token();
$result = $appUser->update($orig); $at->consumer_key = $consumer->key;
$at->tok = common_good_rand(16);
$at->secret = common_good_rand(16);
$at->type = 1; // access
$at->verifier = $verifier;
$at->verified_callback = $rt->verified_callback; // 1.0a
$at->created = common_sql_now();
if (empty($result)) { if (!$at->insert()) {
common_debug('couldn\'t update OAuth app user.'); $e = $at->_lastError;
common_debug('access token "' . $at->tok . '" not inserted: "' . $e->message . '"', __FILE__);
return null; return null;
} else {
common_debug('access token "' . $at->tok . '" inserted', __FILE__);
// burn the old one
$orig_rt = clone($rt);
$rt->state = 2; // used
if (!$rt->update($orig_rt)) {
return null;
}
common_debug('request token "' . $rt->tok . '" updated', __FILE__);
}
// insert a new Oauth_application_user record w/access token
$appUser = new Oauth_application_user();
$appUser->profile_id = $tokenAssoc->profile_id;;
$appUser->application_id = $app->id;
$appUser->access_type = $app->access_type;
$appUser->token = $at->tok;
$appUser->created = common_sql_now();
$result = $appUser->insert();
if (!$result) {
common_log_db_error($appUser, 'INSERT', __FILE__);
// TRANS: Server error displayed when a database error occurs.
$this->serverError(_('Database error inserting OAuth application user.'));
} }
// Okay, good // Okay, good
return new OAuthToken($at->tok, $at->secret); return new OAuthToken($at->tok, $at->secret);
} }
} else { } else {
// the token was not authorized or not verfied
common_log(
LOG_INFO,
sprintf(
"API OAuth - Attempt to exchange unauthorized or unverified request token %s for an access token.",
$rt->tok
)
);
return null; return null;
} }
} }
@ -179,9 +275,9 @@ class ApiStatusNetOAuthDataStore extends StatusNetOAuthDataStore
* @return void * @return void
*/ */
public function revoke_token($token_key, $type = 0) { public function revoke_token($token_key, $type = 0) {
$rt = new Token(); $rt = new Token();
$rt->tok = $token_key; $rt->tok = $token_key;
$rt->type = $type; $rt->type = $type;
$rt->state = 0; $rt->state = 0;
if (!$rt->find(true)) { if (!$rt->find(true)) {
@ -203,7 +299,6 @@ class ApiStatusNetOAuthDataStore extends StatusNetOAuthDataStore
* *
* @return OAuthToken $token a new unauthorized OAuth request token * @return OAuthToken $token a new unauthorized OAuth request token
*/ */
function new_request_token($consumer, $callback) function new_request_token($consumer, $callback)
{ {
$t = new Token(); $t = new Token();
@ -228,6 +323,4 @@ class ApiStatusNetOAuthDataStore extends StatusNetOAuthDataStore
return new OAuthToken($t->tok, $t->secret); return new OAuthToken($t->tok, $t->secret);
} }
} }
} }

View File

@ -22,7 +22,7 @@
* @category Application * @category Application
* @package StatusNet * @package StatusNet
* @author Zach Copley <zach@status.net> * @author Zach Copley <zach@status.net>
* @copyright 2008-2009 StatusNet, Inc. * @copyright 2008-2010 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/ * @link http://status.net/
*/ */
@ -55,14 +55,13 @@ class ApplicationList extends Widget
/** Action object using us. */ /** Action object using us. */
var $action = null; var $action = null;
function __construct($application, $owner=null, $action=null, $connections = false) function __construct($application, $owner=null, $action=null)
{ {
parent::__construct($action); parent::__construct($action);
$this->application = $application; $this->application = $application;
$this->owner = $owner; $this->owner = $owner;
$this->action = $action; $this->action = $action;
$this->connections = $connections;
} }
function show() function show()
@ -88,24 +87,34 @@ class ApplicationList extends Widget
{ {
$user = common_current_user(); $user = common_current_user();
$this->out->elementStart('li', array('class' => 'application', $this->out->elementStart(
'id' => 'oauthclient-' . $this->application->id)); 'li',
array(
'class' => 'application',
'id' => 'oauthclient-' . $this->application->id
)
);
$this->out->elementStart('span', 'vcard author'); $this->out->elementStart('span', 'vcard author');
if (!$this->connections) {
$this->out->elementStart('a',
array('href' => common_local_url('showapplication',
array('id' => $this->application->id)),
'class' => 'url'));
} else { $this->out->elementStart(
$this->out->elementStart('a', array('href' => $this->application->source_url, 'a',
'class' => 'url')); array(
} 'href' => common_local_url(
'showapplication',
array('id' => $this->application->id)),
'class' => 'url'
)
);
if (!empty($this->application->icon)) { if (!empty($this->application->icon)) {
$this->out->element('img', array('src' => $this->application->icon, $this->out->element(
'class' => 'photo avatar')); 'img',
array(
'src' => $this->application->icon,
'class' => 'photo avatar'
)
);
} }
$this->out->element('span', 'fn', $this->application->name); $this->out->element('span', 'fn', $this->application->name);
@ -114,51 +123,18 @@ class ApplicationList extends Widget
$this->out->raw(' by '); $this->out->raw(' by ');
$this->out->element('a', array('href' => $this->application->homepage, $this->out->element(
'class' => 'url'), 'a',
$this->application->organization); array(
'href' => $this->application->homepage,
'class' => 'url'
),
$this->application->organization
);
$this->out->element('p', 'note', $this->application->description); $this->out->element('p', 'note', $this->application->description);
$this->out->elementEnd('li'); $this->out->elementEnd('li');
if ($this->connections) {
$appUser = Oauth_application_user::getByKeys($this->owner, $this->application);
if (empty($appUser)) {
common_debug("empty appUser!");
}
$this->out->elementStart('li');
// TRANS: Application access type
$readWriteText = _('read-write');
// TRANS: Application access type
$readOnlyText = _('read-only');
$access = ($this->application->access_type & Oauth_application::$writeAccess)
? $readWriteText : $readOnlyText;
$modifiedDate = common_date_string($appUser->modified);
// TRANS: Used in application list. %1$s is a modified date, %2$s is access type ("read-write" or "read-only")
$txt = sprintf(_('Approved %1$s - "%2$s" access.'),$modifiedDate,$access);
$this->out->raw($txt);
$this->out->elementEnd('li');
$this->out->elementStart('li', 'entity_revoke');
$this->out->elementStart('form', array('id' => 'form_revoke_app',
'class' => 'form_revoke_app',
'method' => 'POST',
'action' =>
common_local_url('oauthconnectionssettings')));
$this->out->elementStart('fieldset');
$this->out->hidden('id', $this->application->id);
$this->out->hidden('token', common_session_token());
// TRANS: Button label
$this->out->submit('revoke', _m('BUTTON','Revoke'));
$this->out->elementEnd('fieldset');
$this->out->elementEnd('form');
$this->out->elementEnd('li');
}
} }
/* Override this in subclasses. */ /* Override this in subclasses. */
@ -167,3 +143,162 @@ class ApplicationList extends Widget
return; return;
} }
} }
/**
* Widget to show a list of connected OAuth clients
*
* @category Application
* @package StatusNet
* @author Zach Copley <zach@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
class ConnectedAppsList extends Widget
{
/** Current connected application query */
var $connection = null;
/** Owner of this list */
var $owner = null;
/** Action object using us. */
var $action = null;
function __construct($connection, $owner=null, $action=null)
{
parent::__construct($action);
common_debug("ConnectedAppsList constructor");
$this->connection = $connection;
$this->owner = $owner;
$this->action = $action;
}
/* Override this in subclasses. */
function showOwnerControls()
{
return;
}
function show()
{
$this->out->elementStart('ul', 'applications');
$cnt = 0;
while ($this->connection->fetch()) {
$cnt++;
if($cnt > APPS_PER_PAGE) {
break;
}
$this->showConnection();
}
$this->out->elementEnd('ul');
return $cnt;
}
function showConnection()
{
$app = Oauth_application::staticGet('id', $this->connection->application_id);
$this->out->elementStart(
'li',
array(
'class' => 'application',
'id' => 'oauthclient-' . $app->id
)
);
$this->out->elementStart('span', 'vcard author');
$this->out->elementStart(
'a',
array(
'href' => $app->source_url,
'class' => 'url'
)
);
if (!empty($app->icon)) {
$this->out->element(
'img',
array(
'src' => $app->icon,
'class' => 'photo avatar'
)
);
}
if ($app->name != 'anonymous') {
$this->out->element('span', 'fn', $app->name);
}
$this->out->elementEnd('a');
if ($app->name == 'anonymous') {
$this->out->element('span', 'fn', "Unknown application");
}
$this->out->elementEnd('span');
if ($app->name != 'anonymous') {
// @todo FIXME: i18n trouble.
$this->out->raw(_(' by '));
$this->out->element(
'a',
array(
'href' => $app->homepage,
'class' => 'url'
),
$app->organization
);
}
// TRANS: Application access type
$readWriteText = _('read-write');
// TRANS: Application access type
$readOnlyText = _('read-only');
$access = ($this->connection->access_type & Oauth_application::$writeAccess)
? $readWriteText : $readOnlyText;
$modifiedDate = common_date_string($this->connection->modified);
// TRANS: Used in application list. %1$s is a modified date, %2$s is access type ("read-write" or "read-only")
$txt = sprintf(_('Approved %1$s - "%2$s" access.'), $modifiedDate, $access);
$this->out->raw(" - $txt");
if (!empty($app->description)) {
$this->out->element(
'p', array('class' => 'application_description'),
$app->description
);
}
$this->out->element(
'p', array(
'class' => 'access_token'),
// TRANS: Access token in the application list.
// TRANS: %s are the first 7 characters of the access token.
sprintf(_('Access token starting with: %s'), substr($this->connection->token, 0, 7))
);
$this->out->elementStart(
'form',
array(
'id' => 'form_revoke_app',
'class' => 'form_revoke_app',
'method' => 'POST',
'action' => common_local_url('oauthconnectionssettings')
)
);
$this->out->elementStart('fieldset');
$this->out->hidden('oauth_token', $this->connection->token);
$this->out->hidden('token', common_session_token());
// TRANS: Button label
$this->out->submit('revoke', _m('BUTTON','Revoke'));
$this->out->elementEnd('fieldset');
$this->out->elementEnd('form');
$this->out->elementEnd('li');
}
}

View File

@ -151,10 +151,10 @@ try {
// XXX: Throw a conniption if database not installed // XXX: Throw a conniption if database not installed
// XXX: Find a way to use htmlwriter for this instead of handcoded markup // XXX: Find a way to use htmlwriter for this instead of handcoded markup
// TRANS: Error message displayed when no configuration file was found for a StatusNet installation. // TRANS: Error message displayed when no configuration file was found for a StatusNet installation.
echo '<p>'. _('No configuration file found. ') .'</p>'; echo '<p>'. _('No configuration file found.') .'</p>';
// TRANS: Error message displayed when no configuration file was found for a StatusNet installation. // TRANS: Error message displayed when no configuration file was found for a StatusNet installation.
// TRANS: Is followed by a list of directories (separated by HTML breaks). // TRANS: Is followed by a list of directories (separated by HTML breaks).
echo '<p>'. _('I looked for configuration files in the following places: ') .'<br /> '; echo '<p>'. _('I looked for configuration files in the following places:') .'<br /> ';
echo implode($e->configFiles, '<br />'); echo implode($e->configFiles, '<br />');
// TRANS: Error message displayed when no configuration file was found for a StatusNet installation. // TRANS: Error message displayed when no configuration file was found for a StatusNet installation.
echo '<p>'. _('You may wish to run the installer to fix this.') .'</p>'; echo '<p>'. _('You may wish to run the installer to fix this.') .'</p>';

View File

@ -47,7 +47,6 @@ require_once INSTALLDIR.'/lib/servererroraction.php';
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3 * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
* @link http://status.net/ * @link http://status.net/
*/ */
class DBErrorAction extends ServerErrorAction class DBErrorAction extends ServerErrorAction
{ {
function __construct($message='Error', $code=500) function __construct($message='Error', $code=500)

View File

@ -43,7 +43,6 @@ if (!defined('STATUSNET') && !defined('LACONICA')) {
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/ * @link http://status.net/
*/ */
class Feed class Feed
{ {
const RSS1 = 1; const RSS1 = 1;

View File

@ -46,7 +46,6 @@ if (!defined('STATUSNET') && !defined('LACONICA')) {
* *
* @see Action::showExportList() * @see Action::showExportList()
*/ */
class FeedList extends Widget class FeedList extends Widget
{ {
var $action = null; var $action = null;

View File

@ -40,7 +40,6 @@ if (!defined('STATUSNET') && !defined('LACONICA')) {
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/ * @link http://status.net/
*/ */
class GroupsByMembersSection extends GroupSection class GroupsByMembersSection extends GroupSection
{ {
function getGroups() function getGroups()
@ -68,6 +67,7 @@ class GroupsByMembersSection extends GroupSection
function title() function title()
{ {
// TRANS: Title for groups with the most members section.
return _('Groups with most members'); return _('Groups with most members');
} }

View File

@ -40,7 +40,6 @@ if (!defined('STATUSNET') && !defined('LACONICA')) {
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/ * @link http://status.net/
*/ */
class GroupsByPostsSection extends GroupSection class GroupsByPostsSection extends GroupSection
{ {
function getGroups() function getGroups()
@ -68,6 +67,7 @@ class GroupsByPostsSection extends GroupSection
function title() function title()
{ {
// TRANS: Title for groups with the most posts section.
return _('Groups with most posts'); return _('Groups with most posts');
} }

View File

@ -45,7 +45,6 @@ define('GROUPS_PER_SECTION', 6);
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/ * @link http://status.net/
*/ */
class GroupSection extends Section class GroupSection extends Section
{ {
function showContent() function showContent()

View File

@ -40,7 +40,6 @@ if (!defined('STATUSNET') && !defined('LACONICA')) {
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/ * @link http://status.net/
*/ */
class GroupTagCloudSection extends TagCloudSection class GroupTagCloudSection extends TagCloudSection
{ {
var $group = null; var $group = null;
@ -53,6 +52,8 @@ class GroupTagCloudSection extends TagCloudSection
function title() function title()
{ {
// TRANS: Title for group tag cloud section.
// TRANS: %s is a group name.
return sprintf(_('Tags in %s group\'s notices'), $this->group->nickname); return sprintf(_('Tags in %s group\'s notices'), $this->group->nickname);
} }

View File

@ -170,19 +170,21 @@ function mail_to_user(&$user, $subject, $body, $headers=array(), $address=null)
function mail_confirm_address($user, $code, $nickname, $address) function mail_confirm_address($user, $code, $nickname, $address)
{ {
// TRANS: Subject for address confirmation email // TRANS: Subject for address confirmation email.
$subject = _('Email address confirmation'); $subject = _('Email address confirmation');
// TRANS: Body for address confirmation email. // TRANS: Body for address confirmation email.
$body = sprintf(_("Hey, %s.\n\n". // TRANS: %1$s is the addressed user's nickname, %2$s is the StatusNet sitename,
"Someone just entered this email address on %s.\n\n" . // TRANS: %3$s is the URL to confirm at.
$body = sprintf(_("Hey, %1\$s.\n\n".
"Someone just entered this email address on %2\$s.\n\n" .
"If it was you, and you want to confirm your entry, ". "If it was you, and you want to confirm your entry, ".
"use the URL below:\n\n\t%s\n\n" . "use the URL below:\n\n\t%3\$s\n\n" .
"If not, just ignore this message.\n\n". "If not, just ignore this message.\n\n".
"Thanks for your time, \n%s\n"), "Thanks for your time, \n%2\$s\n"),
$nickname, common_config('site', 'name'), $nickname,
common_local_url('confirmaddress', array('code' => $code)), common_config('site', 'name'),
common_config('site', 'name')); common_local_url('confirmaddress', array('code' => $code)));
$headers = array(); $headers = array();
return mail_to_user($user, $subject, $body, $headers, $address); return mail_to_user($user, $subject, $body, $headers, $address);
@ -239,41 +241,50 @@ function mail_subscribe_notify_profile($listenee, $other)
$headers = _mail_prepare_headers('subscribe', $listenee->nickname, $other->nickname); $headers = _mail_prepare_headers('subscribe', $listenee->nickname, $other->nickname);
$headers['From'] = mail_notify_from(); $headers['From'] = mail_notify_from();
$headers['To'] = $name . ' <' . $listenee->email . '>'; $headers['To'] = $name . ' <' . $listenee->email . '>';
// TRANS: Subject of new-subscriber notification e-mail // TRANS: Subject of new-subscriber notification e-mail.
// TRANS: %1$s is the subscribing user's nickname, %2$s is the StatusNet sitename.
$headers['Subject'] = sprintf(_('%1$s is now listening to '. $headers['Subject'] = sprintf(_('%1$s is now listening to '.
'your notices on %2$s.'), 'your notices on %2$s.'),
$other->getBestName(), $other->getBestName(),
common_config('site', 'name')); common_config('site', 'name'));
// TRANS: This is a paragraph in a new-subscriber e-mail.
// TRANS: %s is a URL where the subscriber can be reported as abusive.
$blocklink = sprintf(_("If you believe this account is being used abusively, " . $blocklink = sprintf(_("If you believe this account is being used abusively, " .
"you can block them from your subscribers list and " . "you can block them from your subscribers list and " .
"report as spam to site administrators at %s"), "report as spam to site administrators at %s"),
common_local_url('block', array('profileid' => $other->id))); common_local_url('block', array('profileid' => $other->id)));
// TRANS: Main body of new-subscriber notification e-mail // TRANS: Main body of new-subscriber notification e-mail.
// TRANS: %1$s is the subscriber's long name, %2$s is the StatusNet sitename,
// TRANS: %3$s is the subscriber's profile URL, %4$s is the subscriber's location (or empty)
// TRANS: %5$s is the subscriber's homepage URL (or empty), %6%s is the subscriber's bio (or empty)
// TRANS: %7$s is a link to the addressed user's e-mail settings.
$body = sprintf(_('%1$s is now listening to your notices on %2$s.'."\n\n". $body = sprintf(_('%1$s is now listening to your notices on %2$s.'."\n\n".
"\t".'%3$s'."\n\n". "\t".'%3$s'."\n\n".
'%4$s'. '%4$s'.
'%5$s'. '%5$s'.
'%6$s'. '%6$s'.
"\n".'Faithfully yours,'."\n".'%7$s.'."\n\n". "\n".'Faithfully yours,'."\n".'%2$s.'."\n\n".
"----\n". "----\n".
"Change your email address or ". "Change your email address or ".
"notification options at ".'%8$s' ."\n"), "notification options at ".'%7$s' ."\n"),
$long_name, $long_name,
common_config('site', 'name'), common_config('site', 'name'),
$other->profileurl, $other->profileurl,
($other->location) ? ($other->location) ?
// TRANS: Profile info line in new-subscriber notification e-mail // TRANS: Profile info line in new-subscriber notification e-mail.
// TRANS: %s is a location.
sprintf(_("Location: %s"), $other->location) . "\n" : '', sprintf(_("Location: %s"), $other->location) . "\n" : '',
($other->homepage) ? ($other->homepage) ?
// TRANS: Profile info line in new-subscriber notification e-mail // TRANS: Profile info line in new-subscriber notification e-mail.
// TRANS: %s is a homepage.
sprintf(_("Homepage: %s"), $other->homepage) . "\n" : '', sprintf(_("Homepage: %s"), $other->homepage) . "\n" : '',
(($other->bio) ? (($other->bio) ?
// TRANS: Profile info line in new-subscriber notification e-mail // TRANS: Profile info line in new-subscriber notification e-mail.
// TRANS: %s is biographical information.
sprintf(_("Bio: %s"), $other->bio) . "\n" : '') . sprintf(_("Bio: %s"), $other->bio) . "\n" : '') .
"\n\n" . $blocklink . "\n", "\n\n" . $blocklink . "\n",
common_config('site', 'name'),
common_local_url('emailsettings')); common_local_url('emailsettings'));
// reset localization // reset localization
@ -291,7 +302,6 @@ function mail_subscribe_notify_profile($listenee, $other)
* *
* @return void * @return void
*/ */
function mail_new_incoming_notify($user) function mail_new_incoming_notify($user)
{ {
$profile = $user->getProfile(); $profile = $user->getProfile();
@ -300,19 +310,21 @@ function mail_new_incoming_notify($user)
$headers['From'] = $user->incomingemail; $headers['From'] = $user->incomingemail;
$headers['To'] = $name . ' <' . $user->email . '>'; $headers['To'] = $name . ' <' . $user->email . '>';
// TRANS: Subject of notification mail for new posting email address // TRANS: Subject of notification mail for new posting email address.
// TRANS: %s is the StatusNet sitename.
$headers['Subject'] = sprintf(_('New email address for posting to %s'), $headers['Subject'] = sprintf(_('New email address for posting to %s'),
common_config('site', 'name')); common_config('site', 'name'));
// TRANS: Body of notification mail for new posting email address // TRANS: Body of notification mail for new posting email address.
// TRANS: %1$s is the StatusNet sitename, %2$s is the e-mail address to send
// TRANS: to to post by e-mail, %3$s is a URL to more instructions.
$body = sprintf(_("You have a new posting address on %1\$s.\n\n". $body = sprintf(_("You have a new posting address on %1\$s.\n\n".
"Send email to %2\$s to post new messages.\n\n". "Send email to %2\$s to post new messages.\n\n".
"More email instructions at %3\$s.\n\n". "More email instructions at %3\$s.\n\n".
"Faithfully yours,\n%4\$s"), "Faithfully yours,\n%1\$s"),
common_config('site', 'name'), common_config('site', 'name'),
$user->incomingemail, $user->incomingemail,
common_local_url('doc', array('title' => 'email')), common_local_url('doc', array('title' => 'email')));
common_config('site', 'name'));
mail_send($user->email, $headers, $body); mail_send($user->email, $headers, $body);
} }
@ -324,7 +336,6 @@ function mail_new_incoming_notify($user)
* *
* @return string new email address for incoming messages * @return string new email address for incoming messages
*/ */
function mail_new_incoming_address() function mail_new_incoming_address()
{ {
$prefix = common_confirmation_code(64); $prefix = common_confirmation_code(64);
@ -343,7 +354,6 @@ function mail_new_incoming_address()
* *
* @return success flag * @return success flag
*/ */
function mail_broadcast_notice_sms($notice) function mail_broadcast_notice_sms($notice)
{ {
// Now, get users subscribed to this profile // Now, get users subscribed to this profile
@ -395,7 +405,6 @@ function mail_broadcast_notice_sms($notice)
* *
* @return boolean success flag * @return boolean success flag
*/ */
function mail_send_sms_notice($notice, $user) function mail_send_sms_notice($notice, $user)
{ {
return mail_send_sms_notice_address($notice, return mail_send_sms_notice_address($notice,
@ -415,7 +424,6 @@ function mail_send_sms_notice($notice, $user)
* *
* @return boolean success flag * @return boolean success flag
*/ */
function mail_send_sms_notice_address($notice, $smsemail, $incomingemail) function mail_send_sms_notice_address($notice, $smsemail, $incomingemail)
{ {
$to = $nickname . ' <' . $smsemail . '>'; $to = $nickname . ' <' . $smsemail . '>';
@ -429,7 +437,8 @@ function mail_send_sms_notice_address($notice, $smsemail, $incomingemail)
$headers['From'] = ($incomingemail) ? $incomingemail : mail_notify_from(); $headers['From'] = ($incomingemail) ? $incomingemail : mail_notify_from();
$headers['To'] = $to; $headers['To'] = $to;
// TRANS: Subject line for SMS-by-email notification messages // TRANS: Subject line for SMS-by-email notification messages.
// TRANS: %s is the posting user's nickname.
$headers['Subject'] = sprintf(_('%s status'), $headers['Subject'] = sprintf(_('%s status'),
$other->getBestName()); $other->getBestName());
@ -449,17 +458,17 @@ function mail_send_sms_notice_address($notice, $smsemail, $incomingemail)
* *
* @return void * @return void
*/ */
function mail_confirm_sms($code, $nickname, $address) function mail_confirm_sms($code, $nickname, $address)
{ {
$recipients = $address; $recipients = $address;
$headers['From'] = mail_notify_from(); $headers['From'] = mail_notify_from();
$headers['To'] = $nickname . ' <' . $address . '>'; $headers['To'] = $nickname . ' <' . $address . '>';
// TRANS: Subject line for SMS-by-email address confirmation message // TRANS: Subject line for SMS-by-email address confirmation message.
$headers['Subject'] = _('SMS confirmation'); $headers['Subject'] = _('SMS confirmation');
// TRANS: Main body heading for SMS-by-email address confirmation message // TRANS: Main body heading for SMS-by-email address confirmation message.
// TRANS: %s is the addressed user's nickname.
$body = sprintf(_("%s: confirm you own this phone number with this code:"), $nickname); $body = sprintf(_("%s: confirm you own this phone number with this code:"), $nickname);
$body .= "\n\n"; $body .= "\n\n";
$body .= $code; $body .= $code;
@ -476,16 +485,18 @@ function mail_confirm_sms($code, $nickname, $address)
* *
* @return boolean success flag * @return boolean success flag
*/ */
function mail_notify_nudge($from, $to) function mail_notify_nudge($from, $to)
{ {
common_switch_locale($to->language); common_switch_locale($to->language);
// TRANS: Subject for 'nudge' notification email // TRANS: Subject for 'nudge' notification email.
// TRANS: %s is the nudging user.
$subject = sprintf(_('You\'ve been nudged by %s'), $from->nickname); $subject = sprintf(_('You\'ve been nudged by %s'), $from->nickname);
$from_profile = $from->getProfile(); $from_profile = $from->getProfile();
// TRANS: Body for 'nudge' notification email // TRANS: Body for 'nudge' notification email.
// TRANS: %1$s is the nuding user's long name, $2$s is the nudging user's nickname,
// TRANS: %3$s is a URL to post notices at, %4$s is the StatusNet sitename.
$body = sprintf(_("%1\$s (%2\$s) is wondering what you are up to ". $body = sprintf(_("%1\$s (%2\$s) is wondering what you are up to ".
"these days and is inviting you to post some news.\n\n". "these days and is inviting you to post some news.\n\n".
"So let's hear from you :)\n\n". "So let's hear from you :)\n\n".
@ -516,7 +527,6 @@ function mail_notify_nudge($from, $to)
* *
* @return boolean success code * @return boolean success code
*/ */
function mail_notify_message($message, $from=null, $to=null) function mail_notify_message($message, $from=null, $to=null)
{ {
if (is_null($from)) { if (is_null($from)) {
@ -532,12 +542,16 @@ function mail_notify_message($message, $from=null, $to=null)
} }
common_switch_locale($to->language); common_switch_locale($to->language);
// TRANS: Subject for direct-message notification email // TRANS: Subject for direct-message notification email.
// TRANS: %s is the sending user's nickname.
$subject = sprintf(_('New private message from %s'), $from->nickname); $subject = sprintf(_('New private message from %s'), $from->nickname);
$from_profile = $from->getProfile(); $from_profile = $from->getProfile();
// TRANS: Body for direct-message notification email // TRANS: Body for direct-message notification email.
// TRANS: %1$s is the sending user's long name, %2$s is the sending user's nickname,
// TRANS: %3$s is the message content, %4$s a URL to the message,
// TRANS: %5$s is the StatusNet sitename.
$body = sprintf(_("%1\$s (%2\$s) sent you a private message:\n\n". $body = sprintf(_("%1\$s (%2\$s) sent you a private message:\n\n".
"------------------------------------------------------\n". "------------------------------------------------------\n".
"%3\$s\n". "%3\$s\n".
@ -572,7 +586,6 @@ function mail_notify_message($message, $from=null, $to=null)
* *
* @return void * @return void
*/ */
function mail_notify_fave($other, $user, $notice) function mail_notify_fave($other, $user, $notice)
{ {
if (!$user->hasRight(Right::EMAILONFAVE)) { if (!$user->hasRight(Right::EMAILONFAVE)) {
@ -585,10 +598,15 @@ function mail_notify_fave($other, $user, $notice)
common_switch_locale($other->language); common_switch_locale($other->language);
// TRANS: Subject for favorite notification email // TRANS: Subject for favorite notification e-mail.
$subject = sprintf(_('%s (@%s) added your notice as a favorite'), $bestname, $user->nickname); // TRANS: %1$s is the adding user's long name, %2$s is the adding user's nickname.
$subject = sprintf(_('%1$s (@%2$s) added your notice as a favorite'), $bestname, $user->nickname);
// TRANS: Body for favorite notification email // TRANS: Body for favorite notification e-mail.
// TRANS: %1$s is the adding user's long name, $2$s is the date the notice was created,
// TRANS: %3$s is a URL to the faved notice, %4$s is the faved notice text,
// TRANS: %5$s is a URL to all faves of the adding user, %6$s is the StatusNet sitename,
// TRANS: %7$s is the adding user's nickname.
$body = sprintf(_("%1\$s (@%7\$s) just added your notice from %2\$s". $body = sprintf(_("%1\$s (@%7\$s) just added your notice from %2\$s".
" as one of their favorites.\n\n" . " as one of their favorites.\n\n" .
"The URL of your notice is:\n\n" . "The URL of your notice is:\n\n" .
@ -623,7 +641,6 @@ function mail_notify_fave($other, $user, $notice)
* *
* @return void * @return void
*/ */
function mail_notify_attn($user, $notice) function mail_notify_attn($user, $notice)
{ {
if (!$user->email || !$user->emailnotifyattn) { if (!$user->email || !$user->emailnotifyattn) {
@ -654,9 +671,16 @@ function mail_notify_attn($user, $notice)
$conversationEmailText = ''; $conversationEmailText = '';
} }
$subject = sprintf(_('%s (@%s) sent a notice to your attention'), $bestname, $sender->nickname); // TRANS: E-mail subject for notice notification.
// TRANS: %1$s is the sending user's long name, %2$s is the adding user's nickname.
$subject = sprintf(_('%1$s (@%2$s) sent a notice to your attention'), $bestname, $sender->nickname);
// TRANS: Body of @-reply notification e-mail. // TRANS: Body of @-reply notification e-mail.
// TRANS: %1$s is the sending user's long name, $2$s is the StatusNet sitename,
// TRANS: %3$s is a URL to the notice, %4$s is the notice text,
// TRANS: %5$s is a URL to the full conversion if it exists (otherwise empty),
// TRANS: %6$s is a URL to reply to the notice, %7$s is a URL to all @-replied for the addressed user,
// TRANS: %8$s is a URL to the addressed user's e-mail settings, %9$s is the sender's nickname.
$body = sprintf(_("%1\$s (@%9\$s) just sent a notice to your attention (an '@-reply') on %2\$s.\n\n". $body = sprintf(_("%1\$s (@%9\$s) just sent a notice to your attention (an '@-reply') on %2\$s.\n\n".
"The notice is here:\n\n". "The notice is here:\n\n".
"\t%3\$s\n\n" . "\t%3\$s\n\n" .
@ -709,4 +733,3 @@ function _mail_prepare_headers($msg_type, $to, $from)
return $headers; return $headers;
} }

View File

@ -34,7 +34,6 @@ if (!defined('STATUSNET') && !defined('LACONICA')) {
require_once 'Net/URL/Mapper.php'; require_once 'Net/URL/Mapper.php';
class StatusNet_URL_Mapper extends Net_URL_Mapper { class StatusNet_URL_Mapper extends Net_URL_Mapper {
private static $_singleton = null; private static $_singleton = null;
private function __construct() private function __construct()
@ -71,7 +70,6 @@ class StatusNet_URL_Mapper extends Net_URL_Mapper {
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/ * @link http://status.net/
*/ */
class Router class Router
{ {
var $m = null; var $m = null;
@ -560,11 +558,19 @@ class Router
'format' => '(xml|json)')); 'format' => '(xml|json)'));
// blocks // blocks
$m->connect('api/blocks/create.:format',
array('action' => 'ApiBlockCreate',
'format' => '(xml|json)'));
$m->connect('api/blocks/create/:id.:format', $m->connect('api/blocks/create/:id.:format',
array('action' => 'ApiBlockCreate', array('action' => 'ApiBlockCreate',
'id' => '[a-zA-Z0-9]+', 'id' => '[a-zA-Z0-9]+',
'format' => '(xml|json)')); 'format' => '(xml|json)'));
$m->connect('api/blocks/destroy.:format',
array('action' => 'ApiBlockDestroy',
'format' => '(xml|json)'));
$m->connect('api/blocks/destroy/:id.:format', $m->connect('api/blocks/destroy/:id.:format',
array('action' => 'ApiBlockDestroy', array('action' => 'ApiBlockDestroy',
'id' => '[a-zA-Z0-9]+', 'id' => '[a-zA-Z0-9]+',
@ -704,6 +710,7 @@ class Router
$m->connect('admin/sitenotice', array('action' => 'sitenoticeadminpanel')); $m->connect('admin/sitenotice', array('action' => 'sitenoticeadminpanel'));
$m->connect('admin/snapshot', array('action' => 'snapshotadminpanel')); $m->connect('admin/snapshot', array('action' => 'snapshotadminpanel'));
$m->connect('admin/license', array('action' => 'licenseadminpanel')); $m->connect('admin/license', array('action' => 'licenseadminpanel'));
$m->connect('admin/plugins', array('action' => 'pluginsadminpanel')); $m->connect('admin/plugins', array('action' => 'pluginsadminpanel'));
$m->connect('admin/plugins/enable/:plugin', $m->connect('admin/plugins/enable/:plugin',
array('action' => 'pluginenable'), array('action' => 'pluginenable'),
@ -720,16 +727,8 @@ class Router
if (common_config('singleuser', 'enabled')) { if (common_config('singleuser', 'enabled')) {
$user = User::siteOwner(); $user = User::singleUser();
$nickname = $user->nickname;
if (!empty($user)) {
$nickname = $user->nickname;
} else {
$nickname = common_config('singleuser', 'nickname');
if (empty($nickname)) {
throw new ServerException(_("No single user defined for single-user mode."));
}
}
foreach (array('subscriptions', 'subscribers', foreach (array('subscriptions', 'subscribers',
'all', 'foaf', 'xrds', 'all', 'foaf', 'xrds',
@ -784,9 +783,7 @@ class Router
$m->connect('', $m->connect('',
array('action' => 'showstream', array('action' => 'showstream',
'nickname' => $nickname)); 'nickname' => $nickname));
} else { } else {
$m->connect('', array('action' => 'public')); $m->connect('', array('action' => 'public'));
$m->connect('rss', array('action' => 'publicrss')); $m->connect('rss', array('action' => 'publicrss'));
$m->connect('featuredrss', array('action' => 'featuredrss')); $m->connect('featuredrss', array('action' => 'featuredrss'));
@ -867,7 +864,8 @@ class Router
} catch (Net_URL_Mapper_InvalidException $e) { } catch (Net_URL_Mapper_InvalidException $e) {
common_log(LOG_ERR, "Problem getting route for $path - " . common_log(LOG_ERR, "Problem getting route for $path - " .
$e->getMessage()); $e->getMessage());
$cac = new ClientErrorAction("Page not found.", 404); // TRANS: Client error on action trying to visit a non-existing page.
$cac = new ClientErrorAction(_('Page not found.'), 404);
$cac->showPage(); $cac->showPage();
} }
@ -894,7 +892,16 @@ class Router
if ($qpos !== false) { if ($qpos !== false) {
$url = substr($url, 0, $qpos+1) . $url = substr($url, 0, $qpos+1) .
str_replace('?', '&', substr($url, $qpos+1)); str_replace('?', '&', substr($url, $qpos+1));
// @fixme this is a hacky workaround for http_build_query in the
// lower-level code and bad configs that set the default separator
// to &amp; instead of &. Encoded &s in parameters will not be
// affected.
$url = substr($url, 0, $qpos+1) .
str_replace('&amp;', '&', substr($url, $qpos+1));
} }
return $url; return $url;
} }
} }

View File

@ -1002,8 +1002,9 @@ function common_tag_link($tag)
$canonical = common_canonical_tag($tag); $canonical = common_canonical_tag($tag);
if (common_config('singleuser', 'enabled')) { if (common_config('singleuser', 'enabled')) {
// regular TagAction isn't set up in 1user mode // regular TagAction isn't set up in 1user mode
$user = User::singleUser();
$url = common_local_url('showstream', $url = common_local_url('showstream',
array('nickname' => common_config('singleuser', 'nickname'), array('nickname' => $user->nickname,
'tag' => $canonical)); 'tag' => $canonical));
} else { } else {
$url = common_local_url('tag', array('tag' => $canonical)); $url = common_local_url('tag', array('tag' => $canonical));
@ -1107,7 +1108,17 @@ function common_local_url($action, $args=null, $params=null, $fragment=null, $ad
function common_is_sensitive($action) function common_is_sensitive($action)
{ {
static $sensitive = array('login', 'register', 'passwordsettings', 'api'); static $sensitive = array(
'login',
'register',
'passwordsettings',
'api',
'ApiOauthRequestToken',
'ApiOauthAccessToken',
'ApiOauthAuthorize',
'ApiOauthPin',
'showapplication'
);
$ssl = null; $ssl = null;
if (Event::handle('SensitiveAction', array($action, &$ssl))) { if (Event::handle('SensitiveAction', array($action, &$ssl))) {

View File

@ -32,7 +32,6 @@ if (!defined('STATUSNET') && !defined('LACONICA')) {
} }
class WebColor { class WebColor {
// XXX: Maybe make getters and setters for r,g,b values and tuples, // XXX: Maybe make getters and setters for r,g,b values and tuples,
// e.g.: to support this kinda CSS representation: rgb(255,0,0) // e.g.: to support this kinda CSS representation: rgb(255,0,0)
// http://www.w3.org/TR/CSS21/syndata.html#color-units // http://www.w3.org/TR/CSS21/syndata.html#color-units
@ -65,7 +64,6 @@ class WebColor {
* *
* @return nothing * @return nothing
*/ */
function parseColor($color) { function parseColor($color) {
if (is_numeric($color)) { if (is_numeric($color)) {
@ -90,13 +88,11 @@ class WebColor {
* *
* @return nothing * @return nothing
*/ */
function setNamedColor($name) function setNamedColor($name)
{ {
// XXX Implement this // XXX Implement this
} }
/** /**
* Sets the RGB color values from a a hex tuple * Sets the RGB color values from a a hex tuple
* *
@ -104,7 +100,6 @@ class WebColor {
* *
* @return nothing * @return nothing
*/ */
function setHexColor($hexcolor) { function setHexColor($hexcolor) {
if ($hexcolor[0] == '#') { if ($hexcolor[0] == '#') {
@ -120,7 +115,9 @@ class WebColor {
$hexcolor[1].$hexcolor[1], $hexcolor[1].$hexcolor[1],
$hexcolor[2].$hexcolor[2]); $hexcolor[2].$hexcolor[2]);
} else { } else {
$errmsg = _('%s is not a valid color! Use 3 or 6 hex chars.'); // TRANS: Validation error for a web colour.
// TRANS: %s is the provided (invalid) text for colour.
$errmsg = _('%s is not a valid color! Use 3 or 6 hex characters.');
throw new WebColorException(sprintf($errmsg, $hexcolor)); throw new WebColorException(sprintf($errmsg, $hexcolor));
} }
@ -137,7 +134,6 @@ class WebColor {
* *
* @return nothing * @return nothing
*/ */
function setIntColor($intcolor) function setIntColor($intcolor)
{ {
// We could do 32 bit and have an alpha channel because // We could do 32 bit and have an alpha channel because
@ -154,7 +150,6 @@ class WebColor {
* *
* @return string * @return string
*/ */
function hexValue() { function hexValue() {
$hexcolor = (strlen(dechex($this->red)) < 2 ? '0' : '' ) . $hexcolor = (strlen(dechex($this->red)) < 2 ? '0' : '' ) .
@ -165,7 +160,6 @@ class WebColor {
dechex($this->blue); dechex($this->blue);
return strtoupper($hexcolor); return strtoupper($hexcolor);
} }
/** /**
@ -176,7 +170,6 @@ class WebColor {
* *
* @return int * @return int
*/ */
function intValue() function intValue()
{ {
$intcolor = 256 * 256 * $this->red + 256 * $this->green + $this->blue; $intcolor = 256 * 256 * $this->red + 256 * $this->green + $this->blue;
@ -188,5 +181,3 @@ class WebColor {
class WebColorException extends Exception class WebColorException extends Exception
{ {
} }
?>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More