diff --git a/CONFIGURE b/CONFIGURE index 217b32cc7c..120db976df 100644 --- a/CONFIGURE +++ b/CONFIGURE @@ -563,6 +563,11 @@ sslserver: if specified, this server will be used when creating HTTPS sslpath: if this and the sslserver are specified, this path will be used when creating HTTPS URLs. Otherwise, the attachments|path value will be used. +show_thumbs: show thumbnails in notice lists for uploaded images, and photos + and videos linked remotely that provide oEmbed info. Defaults to true. +show_html: show (filtered) text/html attachments (and oEmbed HTML etc.). + Doesn't affect AJAX calls. Defaults to false. +filename_base: for new files, choose one: 'upload', 'hash'. Defaults to hash. group ----- diff --git a/EVENTS.txt b/EVENTS.txt index cfba97403b..2f91a305f0 100644 --- a/EVENTS.txt +++ b/EVENTS.txt @@ -615,12 +615,12 @@ EndCheckPassword: After checking a username/password pair - $authenticatedUser: User object if credentials match a user, else null. StartChangePassword: Before changing a password -- $user: user +- Profile $target: The profile of the User that is changing password - $oldpassword: the user's old password - $newpassword: the desired new password EndChangePassword: After changing a password -- $user: user +- Profile $target: The profile of the User that just changed its password StartHashPassword: Generate a hashed version of the password (like a salted crypt) - &$hashed: Hashed version of the password, later put in the database diff --git a/INSTALL b/INSTALL index 90fa84923b..64f30139bf 100644 --- a/INSTALL +++ b/INSTALL @@ -196,7 +196,9 @@ your server (like lighttpd or nginx). file is well commented. * For lighttpd, inspect the lighttpd.conf.example file and apply the appropriate changes in your virtualhost configuration for lighttpd. - * For nginx and other webservers, we gladly accept contributions of + * For nginx, inspect the nginx.conf.sample file and apply the appropriate + changes. + * For other webservers, we gladly accept contributions of server configuration examples. 2. Assuming your webserver is properly configured and have its settings diff --git a/actions/all.php b/actions/all.php index 39041064f9..19413076b5 100644 --- a/actions/all.php +++ b/actions/all.php @@ -39,8 +39,6 @@ if (!defined('GNUSOCIAL')) { exit(1); } class AllAction extends ShowstreamAction { - var $notice; - public function getStream() { if ($this->scoped instanceof Profile && $this->scoped->isLocal() && $this->scoped->getUser()->streamModeOnly()) { @@ -54,7 +52,7 @@ class AllAction extends ShowstreamAction function title() { - if (!empty($this->scoped) && $this->scoped->id == $this->target->id) { + if (!empty($this->scoped) && $this->scoped->sameAs($this->target)) { // TRANS: Title of a user's own start page. return _('Home timeline'); } else { @@ -71,44 +69,44 @@ class AllAction extends ShowstreamAction common_local_url( 'ApiTimelineFriends', array( 'format' => 'as', - 'id' => $this->target->nickname + 'id' => $this->target->getNickname() ) ), // TRANS: %s is user nickname. - sprintf(_('Feed for friends of %s (Activity Streams JSON)'), $this->target->nickname)), + sprintf(_('Feed for friends of %s (Activity Streams JSON)'), $this->target->getNickname())), new Feed(Feed::RSS1, common_local_url( 'allrss', array( 'nickname' => - $this->target->nickname) + $this->target->getNickname()) ), // TRANS: %s is user nickname. - sprintf(_('Feed for friends of %s (RSS 1.0)'), $this->target->nickname)), + sprintf(_('Feed for friends of %s (RSS 1.0)'), $this->target->getNickname())), new Feed(Feed::RSS2, common_local_url( 'ApiTimelineFriends', array( 'format' => 'rss', - 'id' => $this->target->nickname + 'id' => $this->target->getNickname() ) ), // TRANS: %s is user nickname. - sprintf(_('Feed for friends of %s (RSS 2.0)'), $this->target->nickname)), + sprintf(_('Feed for friends of %s (RSS 2.0)'), $this->target->getNickname())), new Feed(Feed::ATOM, common_local_url( 'ApiTimelineFriends', array( 'format' => 'atom', - 'id' => $this->target->nickname + 'id' => $this->target->getNickname() ) ), // TRANS: %s is user nickname. - sprintf(_('Feed for friends of %s (Atom)'), $this->target->nickname)) + sprintf(_('Feed for friends of %s (Atom)'), $this->target->getNickname())) ); } function showEmptyListMessage() { // TRANS: Empty list message. %s is a user nickname. - $message = sprintf(_('This is the timeline for %s and friends but no one has posted anything yet.'), $this->target->nickname) . ' '; + $message = sprintf(_('This is the timeline for %s and friends but no one has posted anything yet.'), $this->target->getNickname()) . ' '; if (common_logged_in()) { if ($this->target->id === $this->scoped->id) { @@ -118,12 +116,12 @@ class AllAction extends ShowstreamAction } else { // 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->target->nickname, $this->target->nickname, '@' . $this->target->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->target->getNickname(), $this->target->getNickname(), '@' . $this->target->getNickname()); } } else { // TRANS: Encouragement 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->target->nickname); + $message .= sprintf(_('Why not [register an account](%%%%action.register%%%%) and then nudge %s or post a notice to them.'), $this->target->getNickname()); } $this->elementStart('div', 'guide'); @@ -134,19 +132,10 @@ class AllAction extends ShowstreamAction function showContent() { if (Event::handle('StartShowAllContent', array($this))) { - - $profile = null; - - $current_user = common_current_user(); - - if (!empty($current_user)) { - $profile = $current_user->getProfile(); - } - - if (!empty($current_user) && $current_user->streamModeOnly()) { + if ($this->scoped instanceof Profile && $this->scoped->isLocal() && $this->scoped->getUser()->streamModeOnly()) { $nl = new PrimaryNoticeList($this->notice, $this, array('show_n'=>NOTICES_PER_PAGE)); } else { - $nl = new ThreadedNoticeList($this->notice, $this, $profile); + $nl = new ThreadedNoticeList($this->notice, $this, $this->scoped); } $cnt = $nl->show(); @@ -157,7 +146,7 @@ class AllAction extends ShowstreamAction $this->pagination( $this->page > 1, $cnt > NOTICES_PER_PAGE, - $this->page, 'all', array('nickname' => $this->target->nickname) + $this->page, 'all', array('nickname' => $this->target->getNickname()) ); Event::handle('EndShowAllContent', array($this)); diff --git a/actions/allrss.php b/actions/allrss.php index fee52c79ab..4b6df25048 100644 --- a/actions/allrss.php +++ b/actions/allrss.php @@ -28,11 +28,7 @@ * along with this program. If not, see . */ -if (!defined('STATUSNET') && !defined('LACONICA')) { - exit(1); -} - -require_once INSTALLDIR.'/lib/rssaction.php'; +if (!defined('GNUSOCIAL')) { exit(1); } /** * RSS feed for user and friends timeline. @@ -46,52 +42,12 @@ require_once INSTALLDIR.'/lib/rssaction.php'; * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3 * @link http://status.net/ */ -class AllrssAction extends Rss10Action +class AllrssAction extends TargetedRss10Action { - var $user = null; - - /** - * Initialization. - * - * @param array $args Web and URL arguments - * - * @return boolean false if user doesn't exist - * - */ - function prepare($args) + protected function getNotices() { - parent::prepare($args); - $nickname = $this->trimmed('nickname'); - $this->user = User::getKV('nickname', $nickname); - - if (!$this->user) { - // TRANS: Client error when user not found for an rss related action. - $this->clientError(_('No such user.')); - } else { - $this->notices = $this->getNotices($this->limit); - return true; - } - } - - /** - * Get notices - * - * @param integer $limit max number of notices to return - * - * @return array notices - */ - function getNotices($limit=0) - { - $stream = new InboxNoticeStream($this->user->getProfile()); - $notice = $stream->getNotices(0, $limit, null, null); - - $notices = array(); - - while ($notice->fetch()) { - $notices[] = clone($notice); - } - - return $notices; + $stream = new InboxNoticeStream($this->target); + return $stream->getNotices(0, $this->limit)->fetchAll(); } /** @@ -101,33 +57,17 @@ class AllrssAction extends Rss10Action */ function getChannel() { - $user = $this->user; $c = array('url' => common_local_url('allrss', array('nickname' => - $user->nickname)), + $this->target->getNickname())), // TRANS: Message is used as link title. %s is a user nickname. - 'title' => sprintf(_('%s and friends'), $user->nickname), + 'title' => sprintf(_('%s and friends'), $this->target->getNickname()), 'link' => common_local_url('all', array('nickname' => - $user->nickname)), + $this->target->getNickname())), // TRANS: Message is used as link description. %1$s is a username, %2$s is a site name. 'description' => sprintf(_('Updates from %1$s and friends on %2$s!'), - $user->nickname, common_config('site', 'name'))); + $this->target->getNickname(), common_config('site', 'name'))); return $c; } - - /** - * Get image. - * - * @return string user avatar URL or null - */ - function getImage() - { - $user = $this->user; - $profile = $user->getProfile(); - if (!$profile) { - return null; - } - return $profile->avatarUrl(AVATAR_PROFILE_SIZE); - } } diff --git a/actions/apiaccountupdateprofile.php b/actions/apiaccountupdateprofile.php index a9842ec5d8..8767dabf85 100644 --- a/actions/apiaccountupdateprofile.php +++ b/actions/apiaccountupdateprofile.php @@ -96,21 +96,12 @@ class ApiAccountUpdateProfileAction extends ApiAuthAction $original = clone($profile); - if (!empty($this->name)) { - $profile->fullname = $this->name; - } - - if (!empty($this->url)) { - $profile->homepage = $this->url; - } - - if (!empty($this->description)) { - $profile->bio = $this->description; - } + $profile->fullname = $this->name; + $profile->homepage = $this->url; + $profile->bio = $this->description; + $profile->location = $this->location; if (!empty($this->location)) { - $profile->location = $this->location; - $loc = Location::fromName($this->location); if (!empty($loc)) { @@ -119,6 +110,12 @@ class ApiAccountUpdateProfileAction extends ApiAuthAction $profile->location_id = $loc->location_id; $profile->location_ns = $loc->location_ns; } + } else { + // location is empty so reset the extrapolated information too + $profile->lat = ''; + $profile->lon = ''; + $profile->location_id = ''; + $profile->location_ns = ''; } $result = $profile->update($original); diff --git a/actions/apitimelinetag.php b/actions/apitimelinetag.php index 04a4727a9d..1184440c7d 100644 --- a/actions/apitimelinetag.php +++ b/actions/apitimelinetag.php @@ -51,10 +51,14 @@ class ApiTimelineTagAction extends ApiPrivateAuthAction { var $notices = null; - protected function doPreparation() + protected function prepare(array $args=array()) { + parent::prepare($args); + $this->tag = $this->arg('tag'); $this->notices = $this->getNotices(); + + return true; } /** diff --git a/actions/avatarsettings.php b/actions/avatarsettings.php index 1f31cbdafe..4b618eb9be 100644 --- a/actions/avatarsettings.php +++ b/actions/avatarsettings.php @@ -76,11 +76,11 @@ class AvatarsettingsAction extends SettingsAction /** * Content area of the page * - * Shows a form for uploading an avatar. + * Shows a form for uploading an avatar. Currently overrides FormAction's showContent + * since we haven't made classes out of AvatarCropForm and AvatarUploadForm. * * @return void */ - function showContent() { if ($this->mode == 'crop') { @@ -243,52 +243,19 @@ class AvatarsettingsAction extends SettingsAction $this->elementEnd('form'); } - /** - * Handle a post - * - * We mux on the button name to figure out what the user actually wanted. - * - * @return void - */ - function handlePost() + protected function doPost() { - // Workaround for PHP returning empty $_POST and $_FILES when POST - // length > post_max_size in php.ini - - if (empty($_FILES) - && empty($_POST) - && ($_SERVER['CONTENT_LENGTH'] > 0) - ) { - // TRANS: Client error displayed when the number of bytes in a POST request exceeds a limit. - // 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'])); - return; - } - - // CSRF protection - - $token = $this->trimmed('token'); - if (!$token || $token != common_session_token()) { - // TRANS: Client error displayed when the session token does not match or is not given. - $this->showForm(_('There was a problem with your session token. '. - 'Try again, please.')); - return; - } - if (Event::handle('StartAvatarSaveForm', array($this))) { - if ($this->arg('upload')) { - $this->uploadAvatar(); - } else if ($this->arg('crop')) { - $this->cropAvatar(); - } else if ($this->arg('delete')) { - $this->deleteAvatar(); - } else { - // TRANS: Unexpected validation error on avatar upload form. - $this->showForm(_('Unexpected form submission.')); - } + if ($this->trimmed('upload')) { + return $this->uploadAvatar(); + } else if ($this->trimmed('crop')) { + return $this->cropAvatar(); + } else if ($this->trimmed('delete')) { + return $this->deleteAvatar(); + } else { + // TRANS: Unexpected validation error on avatar upload form. + throw new ClientException(_('Unexpected form submission.')); + } Event::handle('EndAvatarSaveForm', array($this)); } } @@ -303,21 +270,12 @@ class AvatarsettingsAction extends SettingsAction */ function uploadAvatar() { - try { - $imagefile = ImageFile::fromUpload('avatarfile'); - } catch (Exception $e) { - $this->showForm($e->getMessage()); - return; - } - if ($imagefile === null) { - // TRANS: Validation error on avatar upload form when no file was uploaded. - $this->showForm(_('No file uploaded.')); - return; - } + // ImageFile throws exception if something goes wrong, which we'll + // pick up and show as an error message above the form. + $imagefile = ImageFile::fromUpload('avatarfile'); - $cur = common_current_user(); $type = $imagefile->preferredType(); - $filename = Avatar::filename($cur->id, + $filename = Avatar::filename($this->scoped->getID(), image_type_to_extension($type), null, 'tmp'.common_timestamp()); @@ -338,8 +296,7 @@ class AvatarsettingsAction extends SettingsAction $this->mode = 'crop'; // TRANS: Avatar upload form instruction after uploading a file. - $this->showForm(_('Pick a square area of the image to be your avatar.'), - true); + return _('Pick a square area of the image to be your avatar.'); } /** @@ -351,13 +308,12 @@ class AvatarsettingsAction extends SettingsAction { $filedata = $_SESSION['FILEDATA']; - if (!$filedata) { + if (empty($filedata)) { // TRANS: Server error displayed if an avatar upload went wrong somehow server side. - $this->serverError(_('Lost our file data.')); + throw new ServerException(_('Lost our file data.')); } - $file_d = ($filedata['width'] > $filedata['height']) - ? $filedata['height'] : $filedata['width']; + $file_d = min($filedata['width'], $filedata['height']); $dest_x = $this->arg('avatar_crop_x') ? $this->arg('avatar_crop_x'):0; $dest_y = $this->arg('avatar_crop_y') ? $this->arg('avatar_crop_y'):0; @@ -369,11 +325,8 @@ class AvatarsettingsAction extends SettingsAction 'x' => $dest_x, 'y' => $dest_y, 'w' => $dest_w, 'h' => $dest_h); - $user = common_current_user(); - $profile = $user->getProfile(); - $imagefile = new ImageFile(null, $filedata['filepath']); - $filename = Avatar::filename($profile->getID(), image_type_to_extension($imagefile->preferredType()), + $filename = Avatar::filename($this->scoped->getID(), image_type_to_extension($imagefile->preferredType()), $size, common_timestamp()); try { $imagefile->resizeTo(Avatar::path($filename), $box); @@ -385,16 +338,16 @@ class AvatarsettingsAction extends SettingsAction } } - if ($profile->setOriginal($filename)) { + if ($this->scoped->setOriginal($filename)) { @unlink($filedata['filepath']); unset($_SESSION['FILEDATA']); $this->mode = 'upload'; // TRANS: Success message for having updated a user avatar. - $this->showForm(_('Avatar updated.'), true); - } else { - // TRANS: Error displayed on the avatar upload page if the avatar could not be updated for an unknown reason. - $this->showForm(_('Failed updating avatar.')); + return _('Avatar updated.'); } + + // TRANS: Error displayed on the avatar upload page if the avatar could not be updated for an unknown reason. + throw new ServerException(_('Failed updating avatar.')); } /** @@ -404,13 +357,10 @@ class AvatarsettingsAction extends SettingsAction */ function deleteAvatar() { - $user = common_current_user(); - $profile = $user->getProfile(); - - Avatar::deleteFromProfile($profile); + Avatar::deleteFromProfile($this->scoped); // TRANS: Success message for deleting a user avatar. - $this->showForm(_('Avatar deleted.'), true); + return _('Avatar deleted.'); } /** diff --git a/actions/deletenotice.php b/actions/deletenotice.php index eb84b4f3ae..40b276a348 100644 --- a/actions/deletenotice.php +++ b/actions/deletenotice.php @@ -28,80 +28,24 @@ * @link http://status.net/ */ -if (!defined('STATUSNET') && !defined('LACONICA')) { - exit(1); -} +if (!defined('GNUSOCIAL')) { exit(1); } // @todo FIXME: documentation needed. -class DeletenoticeAction extends Action +class DeletenoticeAction extends FormAction { - var $error = null; - var $user = null; - var $notice = null; - var $profile = null; - var $user_profile = null; + protected $notice = null; - function prepare($args) + protected function doPreparation() { - parent::prepare($args); + $this->notice = Notice::getByID($this->trimmed('notice')); - $this->user = common_current_user(); - - if (!$this->user) { - // TRANS: Error message displayed when trying to perform an action that requires a logged in user. - common_user_error(_('Not logged in.')); - exit; - } - - $notice_id = $this->trimmed('notice'); - $this->notice = Notice::getKV($notice_id); - - if (!$this->notice) { - // TRANS: Error message displayed trying to delete a non-existing notice. - common_user_error(_('No such notice.')); - exit; - } - - $this->profile = $this->notice->getProfile(); - $this->user_profile = $this->user->getProfile(); - - return true; - } - - function handle($args) - { - parent::handle($args); - - if ($this->notice->profile_id != $this->user_profile->id && - !$this->user->hasRight(Right::DELETEOTHERSNOTICE)) { + if (!$this->scoped->sameAs($this->notice->getProfile()) && + !$this->scoped->hasRight(Right::DELETEOTHERSNOTICE)) { // TRANS: Error message displayed trying to delete a notice that was not made by the current user. - common_user_error(_('Cannot delete this notice.')); - exit; + $this->clientError(_('Cannot delete this notice.')); } - // XXX: Ajax! - if ($_SERVER['REQUEST_METHOD'] == 'POST') { - $this->deleteNotice(); - } else if ($_SERVER['REQUEST_METHOD'] == 'GET') { - $this->showForm(); - } - } - - /** - * Show the page notice - * - * Shows instructions for the page - * - * @return void - */ - function showPageNotice() - { - $instr = $this->getInstructions(); - $output = common_markup_to_html($instr); - - $this->elementStart('div', 'instructions'); - $this->raw($output); - $this->elementEnd('div'); + $this->formOpts['notice'] = $this->notice; } function getInstructions() @@ -117,84 +61,17 @@ class DeletenoticeAction extends Action return _('Delete notice'); } - /** - * Wrapper for showing a page - * - * Stores an error and shows the page - * - * @param string $error Error, if any - * - * @return void - */ - function showForm($error = null) + protected function doPost() { - $this->error = $error; - $this->showPage(); - } - - /** - * Insert delete notice form into the content - * - * @return void - */ - function showContent() - { - $this->elementStart('form', array('id' => 'form_notice_delete', - 'class' => 'form_settings', - 'method' => 'post', - 'action' => common_local_url('deletenotice'))); - $this->elementStart('fieldset'); - // TRANS: Fieldset legend for the delete notice form. - $this->element('legend', null, _('Delete notice')); - $this->hidden('token', common_session_token()); - $this->hidden('notice', $this->trimmed('notice')); - // TRANS: Message for the delete notice form. - $this->element('p', null, _('Are you sure you want to delete this notice?')); - $this->submit('form_action-no', - // TRANS: Button label on the delete notice form. - _m('BUTTON','No'), - 'submit form_action-primary', - 'no', - // TRANS: Submit button title for 'No' when deleting a notice. - _('Do not delete this notice.')); - $this->submit('form_action-yes', - // TRANS: Button label on the delete notice form. - _m('BUTTON','Yes'), - 'submit form_action-secondary', - 'yes', - // TRANS: Submit button title for 'Yes' when deleting a notice. - _('Delete this notice.')); - $this->elementEnd('fieldset'); - $this->elementEnd('form'); - } - - function deleteNotice() - { - // CSRF protection - $token = $this->trimmed('token'); - - if (!$token || $token != common_session_token()) { - // TRANS: Client error displayed when the session token does not match or is not given. - $this->showForm(_('There was a problem with your session token. ' . - 'Try again, please.')); - return; - } - if ($this->arg('yes')) { - if (Event::handle('StartDeleteOwnNotice', array($this->user, $this->notice))) { + if (Event::handle('StartDeleteOwnNotice', array($this->scoped->getUser(), $this->notice))) { $this->notice->delete(); - Event::handle('EndDeleteOwnNotice', array($this->user, $this->notice)); + Event::handle('EndDeleteOwnNotice', array($this->scoped->getUser(), $this->notice)); } - } - - $url = common_get_returnto(); - - if ($url) { - common_set_returnto(null); } else { - $url = common_local_url('public'); + common_redirect(common_get_returnto(), 303); } - common_redirect($url, 303); + common_redirect(common_local_url('top'), 303); } } diff --git a/actions/emailsettings.php b/actions/emailsettings.php index a0f111c0d5..c02f1cdfad 100644 --- a/actions/emailsettings.php +++ b/actions/emailsettings.php @@ -28,11 +28,7 @@ * @link http://status.net/ */ -if (!defined('STATUSNET') && !defined('LACONICA')) { - exit(1); -} - - +if (!defined('GNUSOCIAL')) { exit(1); } /** * Settings for email @@ -112,8 +108,8 @@ class EmailsettingsAction extends SettingsAction // TRANS: Button label to remove a confirmed e-mail address. $this->submit('remove', _m('BUTTON','Remove')); } else { - $confirm = $this->getConfirmation(); - if ($confirm) { + try { + $confirm = $this->getConfirmation(); $this->element('p', array('id' => 'form_unconfirmed'), $confirm->address); $this->element('p', array('class' => 'form_note'), // TRANS: Form note in e-mail settings form. @@ -123,12 +119,12 @@ class EmailsettingsAction extends SettingsAction $this->hidden('email', $confirm->address); // TRANS: Button label to cancel an e-mail address confirmation procedure. $this->submit('cancel', _m('BUTTON','Cancel')); - } else { + } catch (NoResultException $e) { $this->elementStart('ul', 'form_data'); $this->elementStart('li'); // TRANS: Field label for e-mail address input in e-mail settings form. $this->input('email', _('Email address'), - ($this->arg('email')) ? $this->arg('email') : null, + $this->trimmed('email') ?: null, // TRANS: Instructions for e-mail address input form. Do not translate // TRANS: "example.org". It is one of the domain names reserved for // TRANS: use in examples by http://www.rfc-editor.org/rfc/rfc2606.txt. @@ -231,12 +227,6 @@ class EmailsettingsAction extends SettingsAction _('Allow friends to nudge me and send me an email.'), $user->emailnotifynudge); $this->elementEnd('li'); - $this->elementStart('li'); - $this->checkbox('emailmicroid', - // TRANS: Checkbox label in e-mail preferences form. - _('Publish a MicroID for my email address.'), - $user->emailmicroid); - $this->elementEnd('li'); Event::handle('EndEmailFormData', array($this, $this->scoped)); } $this->elementEnd('ul'); @@ -254,56 +244,36 @@ class EmailsettingsAction extends SettingsAction */ function getConfirmation() { - $user = common_current_user(); - $confirm = new Confirm_address(); - $confirm->user_id = $user->id; + $confirm->user_id = $this->scoped->getID(); $confirm->address_type = 'email'; if ($confirm->find(true)) { return $confirm; - } else { - return null; } + + throw new NoResultException($confirm); } - /** - * Handle posts - * - * Since there are a lot of different options on the page, we - * figure out what we're supposed to do based on which button was - * pushed - * - * @return void - */ - function handlePost() + protected function doPost() { - // CSRF protection - $token = $this->trimmed('token'); - if (!$token || $token != common_session_token()) { - // TRANS: Client error displayed when the session token does not match or is not given. - $this->show_form(_('There was a problem with your session token. '. - 'Try again, please.')); - return; + if ($this->arg('save')) { + return $this->savePreferences(); + } else if ($this->arg('add')) { + return $this->addAddress(); + } else if ($this->arg('cancel')) { + return $this->cancelConfirmation(); + } else if ($this->arg('remove')) { + return $this->removeAddress(); + } else if ($this->arg('removeincoming')) { + return $this->removeIncoming(); + } else if ($this->arg('newincoming')) { + return $this->newIncoming(); } - if ($this->arg('save')) { - $this->savePreferences(); - } else if ($this->arg('add')) { - $this->addAddress(); - } else if ($this->arg('cancel')) { - $this->cancelConfirmation(); - } else if ($this->arg('remove')) { - $this->removeAddress(); - } else if ($this->arg('removeincoming')) { - $this->removeIncoming(); - } else if ($this->arg('newincoming')) { - $this->newIncoming(); - } else { - // TRANS: Message given submitting a form with an unknown action in e-mail settings. - $this->showForm(_('Unexpected form submission.')); - } + // TRANS: Message given submitting a form with an unknown action in e-mail settings. + throw new ClientException(_('Unexpected form submission.')); } /** @@ -313,25 +283,21 @@ class EmailsettingsAction extends SettingsAction */ function savePreferences() { - $user = $this->scoped->getUser(); - if (Event::handle('StartEmailSaveForm', array($this, $this->scoped))) { $emailnotifysub = $this->booleanintstring('emailnotifysub'); $emailnotifymsg = $this->booleanintstring('emailnotifymsg'); $emailnotifynudge = $this->booleanintstring('emailnotifynudge'); $emailnotifyattn = $this->booleanintstring('emailnotifyattn'); - $emailmicroid = $this->booleanintstring('emailmicroid'); $emailpost = $this->booleanintstring('emailpost'); + $user = $this->scoped->getUser(); $user->query('BEGIN'); - $original = clone($user); $user->emailnotifysub = $emailnotifysub; $user->emailnotifymsg = $emailnotifymsg; $user->emailnotifynudge = $emailnotifynudge; $user->emailnotifyattn = $emailnotifyattn; - $user->emailmicroid = $emailmicroid; $user->emailpost = $emailpost; $result = $user->update($original); @@ -340,16 +306,15 @@ class EmailsettingsAction extends SettingsAction common_log_db_error($user, 'UPDATE', __FILE__); $user->query('ROLLBACK'); // TRANS: Server error thrown on database error updating e-mail preferences. - $this->serverError(_('Could not update user.')); + throw new ServerException(_('Could not update user.')); } $user->query('COMMIT'); Event::handle('EndEmailSaveForm', array($this, $this->scoped)); - - // TRANS: Confirmation message for successful e-mail preferences save. - $this->showForm(_('Email preferences saved.'), true); } + // TRANS: Confirmation message for successful e-mail preferences save. + return _('Email preferences saved.'); } /** @@ -359,38 +324,32 @@ class EmailsettingsAction extends SettingsAction */ function addAddress() { - $user = common_current_user(); + $user = $this->scoped->getUser(); $email = $this->trimmed('email'); // Some validation - if (!$email) { + if (empty($email)) { // TRANS: Message given saving e-mail address without having provided one. - $this->showForm(_('No email address.')); - return; + throw new ClientException(_('No email address.')); } $email = common_canonical_email($email); - if (!$email) { + if (empty($email)) { // TRANS: Message given saving e-mail address that cannot be normalised. - $this->showForm(_('Cannot normalize that email address.')); - return; + throw new ClientException(_('Cannot normalize that email address.')); } if (!Validate::email($email, common_config('email', 'check_domain'))) { // TRANS: Message given saving e-mail address that not valid. - $this->showForm(_('Not a valid email address.')); - return; + throw new ClientException(_('Not a valid email address.')); } else if ($user->email == $email) { // TRANS: Message given saving e-mail address that is already set. - $this->showForm(_('That is already your email address.')); - return; + throw new ClientException(_('That is already your email address.')); } else if ($this->emailExists($email)) { // TRANS: Message given saving e-mail address that is already set for another user. - $this->showForm(_('That email address already belongs '. - 'to another user.')); - return; + throw new ClientException(_('That email address already belongs to another user.')); } if (Event::handle('StartAddEmailAddress', array($user, $email))) { @@ -399,7 +358,7 @@ class EmailsettingsAction extends SettingsAction $confirm->address = $email; $confirm->address_type = 'email'; - $confirm->user_id = $user->id; + $confirm->user_id = $user->getID(); $confirm->code = common_confirmation_code(64); $result = $confirm->insert(); @@ -407,21 +366,19 @@ class EmailsettingsAction extends SettingsAction if ($result === false) { common_log_db_error($confirm, 'INSERT', __FILE__); // TRANS: Server error thrown on database error adding e-mail confirmation code. - $this->serverError(_('Could not insert confirmation code.')); + throw new ServerException(_('Could not insert confirmation code.')); } - common_debug('Sending confirmation address for user '.$user->id.' to email '.$email); - mail_confirm_address($user, $confirm->code, $user->nickname, $email); + common_debug('Sending confirmation address for user '.$user->getID().' to email '.$email); + mail_confirm_address($user, $confirm->code, $user->getNickname(), $email); Event::handle('EndAddEmailAddress', array($user, $email)); } // TRANS: Message given saving valid e-mail address that is to be confirmed. - $msg = _('A confirmation code was sent to the email address you added. '. + return _('A confirmation code was sent to the email address you added. '. 'Check your inbox (and spam box!) for the code and instructions '. 'on how to use it.'); - - $this->showForm($msg, true); } /** @@ -431,31 +388,29 @@ class EmailsettingsAction extends SettingsAction */ function cancelConfirmation() { - $email = $this->arg('email'); + $email = $this->trimmed('email'); - $confirm = $this->getConfirmation(); - - if (!$confirm) { + try { + $confirm = $this->getConfirmation(); + if ($confirm->address !== $email) { + // TRANS: Message given canceling e-mail address confirmation for the wrong e-mail address. + throw new ClientException(_('That is the wrong email address.')); + } + } catch (NoResultException $e) { // TRANS: Message given canceling e-mail address confirmation that is not pending. - $this->showForm(_('No pending confirmation to cancel.')); - return; - } - if ($confirm->address != $email) { - // TRANS: Message given canceling e-mail address confirmation for the wrong e-mail address. - $this->showForm(_('That is the wrong email address.')); - return; + throw new AlreadyFulfilledException(_('No pending confirmation to cancel.')); } $result = $confirm->delete(); - if (!$result) { + if ($result === false) { common_log_db_error($confirm, 'DELETE', __FILE__); // TRANS: Server error thrown on database error canceling e-mail address confirmation. - $this->serverError(_('Could not delete email confirmation.')); + throw new ServerException(_('Could not delete email confirmation.')); } // TRANS: Message given after successfully canceling e-mail address confirmation. - $this->showForm(_('Email confirmation cancelled.'), true); + return _('Email confirmation cancelled.'); } /** @@ -467,26 +422,22 @@ class EmailsettingsAction extends SettingsAction { $user = common_current_user(); - $email = $this->arg('email'); + $email = $this->trimmed('email'); // Maybe an old tab open...? - - if ($user->email != $email) { + if ($user->email !== $email) { // TRANS: Message given trying to remove an e-mail address that is not // TRANS: registered for the active user. - $this->showForm(_('That is not your email address.')); - return; + throw new ClientException(_('That is not your email address.')); } $original = clone($user); - $user->email = null; - // Throws exception on failure. Also performs it within a transaction. $user->updateWithKeys($original); // TRANS: Message given after successfully removing a registered e-mail address. - $this->showForm(_('The email address was removed.'), true); + return _('The email address was removed.'); } /** @@ -498,22 +449,19 @@ class EmailsettingsAction extends SettingsAction { $user = common_current_user(); - if (!$user->incomingemail) { + if (empty($user->incomingemail)) { // TRANS: Form validation error displayed when trying to remove an incoming e-mail address while no address has been set. - $this->showForm(_('No incoming email address.')); - return; + throw new AlreadyFulfilledException(_('No incoming email address.')); } $orig = clone($user); - $user->incomingemail = null; $user->emailpost = 0; - // Throws exception on failure. Also performs it within a transaction. $user->updateWithKeys($orig); // TRANS: Message given after successfully removing an incoming e-mail address. - $this->showForm(_('Incoming email address removed.'), true); + return _('Incoming email address removed.'); } /** @@ -524,17 +472,14 @@ class EmailsettingsAction extends SettingsAction function newIncoming() { $user = common_current_user(); - $orig = clone($user); - $user->incomingemail = mail_new_incoming_address(); $user->emailpost = 1; - // Throws exception on failure. Also performs it within a transaction. $user->updateWithKeys($orig); // TRANS: Message given after successfully adding an incoming e-mail address. - $this->showForm(_('New incoming email address added.'), true); + return _('New incoming email address added.'); } /** @@ -553,10 +498,10 @@ class EmailsettingsAction extends SettingsAction $other = User::getKV('email', $email); - if (!$other) { + if (!$other instanceof User) { return false; - } else { - return $other->id != $user->id; } + + return $other->id != $user->id; } } diff --git a/actions/foaf.php b/actions/foaf.php index bcdc86d886..260388ba44 100644 --- a/actions/foaf.php +++ b/actions/foaf.php @@ -17,24 +17,22 @@ * along with this program. If not, see . */ -if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); } +if (!defined('GNUSOCIAL')) { exit(1); } define('LISTENER', 1); define('LISTENEE', -1); define('BOTH', 0); // @todo XXX: Documentation missing. -class FoafAction extends Action +class FoafAction extends ManagedAction { function isReadOnly($args) { return true; } - function prepare($args) + protected function doPreparation() { - parent::prepare($args); - $nickname_arg = $this->arg('nickname'); if (empty($nickname_arg)) { @@ -69,10 +67,8 @@ class FoafAction extends Action return true; } - function handle($args) + public function showPage() { - parent::handle($args); - header('Content-Type: application/rdf+xml'); $this->startXML(); diff --git a/actions/groupbyid.php b/actions/groupbyid.php index b82a861e97..de87ec5c67 100644 --- a/actions/groupbyid.php +++ b/actions/groupbyid.php @@ -28,12 +28,7 @@ * @link http://status.net/ */ -if (!defined('STATUSNET') && !defined('LACONICA')) { - exit(1); -} - -require_once INSTALLDIR.'/lib/noticelist.php'; -require_once INSTALLDIR.'/lib/feedlist.php'; +if (!defined('GNUSOCIAL')) { exit(1); } /** * Permalink for a group @@ -47,53 +42,22 @@ 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 * @link http://status.net/ */ -class GroupbyidAction extends Action +class GroupbyidAction extends ManagedAction { /** group we're viewing. */ - var $group = null; + protected $group = null; - /** - * Is this page read-only? - * - * @return boolean true - */ function isReadOnly($args) { return true; } - function prepare($args) + protected function doPreparation() { - parent::prepare($args); - - $id = $this->arg('id'); - - if (!$id) { - // TRANS: Client error displayed referring to a group's permalink without providing a group ID. - $this->clientError(_('No ID.')); - } - - common_debug("Got ID $id"); - - $this->group = User_group::getKV('id', $id); - - if (!$this->group) { - // TRANS: Client error displayed referring to a group's permalink for a non-existing group ID. - $this->clientError(_('No such group.'), 404); - } - - return true; + $this->group = User_group::getByID($this->arg('id')); } - /** - * Handle the request - * - * Shows a profile for the group, some controls, and a list of - * group notices. - * - * @return void - */ - function handle($args) + public function showPage() { common_redirect($this->group->homeUrl(), 303); } diff --git a/actions/grouprss.php b/actions/grouprss.php index 87e34d73f8..14d85d89cd 100644 --- a/actions/grouprss.php +++ b/actions/grouprss.php @@ -28,11 +28,7 @@ * @link http://status.net/ */ -if (!defined('STATUSNET') && !defined('LACONICA')) { - exit(1); -} - -require_once INSTALLDIR.'/lib/rssaction.php'; +if (!defined('GNUSOCIAL')) { exit(1); } define('MEMBERS_PER_SECTION', 27); @@ -45,10 +41,10 @@ define('MEMBERS_PER_SECTION', 27); * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @link http://status.net/ */ -class groupRssAction extends Rss10Action +class GroupRssAction extends TargetedRss10Action { /** group we're viewing. */ - var $group = null; + protected $group = null; /** * Is this page read-only? @@ -60,18 +56,8 @@ class groupRssAction extends Rss10Action return true; } - /** - * Prepare the action - * - * Reads and validates arguments and instantiates the attributes. - * - * @param array $args $_REQUEST args - * - * @return boolean success flag - */ - function prepare($args) + protected function doStreamPreparation() { - parent::prepare($args); $nickname_arg = $this->arg('nickname'); $nickname = common_canonical_nickname($nickname_arg); @@ -90,52 +76,32 @@ class groupRssAction extends Rss10Action $local = Local_group::getKV('nickname', $nickname); - if (!$local) { + if (!$local instanceof Local_group) { // TRANS: Client error displayed when requesting a group RSS feed for group that does not exist. $this->clientError(_('No such group.'), 404); } - $this->group = User_group::getKV('id', $local->group_id); - - if (!$this->group) { - // TRANS: Client error displayed when requesting a group RSS feed for an object that is not a group. - $this->clientError(_('No such group.'), 404); - } - - $this->notices = $this->getNotices($this->limit); - return true; + $this->group = $local->getGroup(); + $this->target = $this->group->getProfile(); } - function getNotices($limit=0) + protected function getNotices() { - $group = $this->group; - - if (is_null($group)) { - return null; - } - - $notices = array(); - $notice = $group->getNotices(0, ($limit == 0) ? NOTICES_PER_PAGE : $limit); - - while ($notice->fetch()) { - $notices[] = clone($notice); - } - - return $notices; + $stream = $this->group->getNotices(0, $this->limit); + return $stream->fetchAll(); } function getChannel() { - $group = $this->group; $c = array('url' => common_local_url('grouprss', array('nickname' => - $group->nickname)), + $this->target->getNickname())), // TRANS: Message is used as link title. %s is a user nickname. - 'title' => sprintf(_('%s timeline'), $group->nickname), - 'link' => common_local_url('showgroup', array('nickname' => $group->nickname)), + 'title' => sprintf(_('%s timeline'), $this->target->getNickname()), + 'link' => common_local_url('showgroup', array('nickname' => $this->target->getNickname())), // TRANS: Message is used as link description. %1$s is a group name, %2$s is a site name. 'description' => sprintf(_('Updates from members of %1$s on %2$s!'), - $group->nickname, common_config('site', 'name'))); + $this->target->getNickname(), common_config('site', 'name'))); return $c; } diff --git a/actions/imsettings.php b/actions/imsettings.php index 92fff45a7d..40bea10e68 100644 --- a/actions/imsettings.php +++ b/actions/imsettings.php @@ -27,9 +27,7 @@ * @link http://status.net/ */ -if (!defined('STATUSNET') && !defined('LACONICA')) { - exit(1); -} +if (!defined('GNUSOCIAL')) { exit(1); } /** * Settings for Jabber/XMPP integration @@ -118,8 +116,8 @@ class ImsettingsAction extends SettingsAction // TRANS: Button label to remove a confirmed IM address. $this->submit('remove', _m('BUTTON','Remove')); } else { - $confirm = $this->getConfirmation($transport); - if ($confirm) { + try { + $confirm = $this->getConfirmation($transport); $this->element('p', 'form_unconfirmed', $confirm->address); // TRANS: Form note in IM settings form. $this->element('p', 'form_note', @@ -134,7 +132,7 @@ class ImsettingsAction extends SettingsAction $this->hidden('screenname', $confirm->address); // TRANS: Button label to cancel an IM address confirmation procedure. $this->submit('cancel', _m('BUTTON','Cancel')); - } else { + } catch (NoResultException $e) { $this->elementStart('ul', 'form_data'); $this->elementStart('li'); // TRANS: Field label for IM address. @@ -179,8 +177,6 @@ class ImsettingsAction extends SettingsAction // TRANS: Checkbox label in IM preferences form. array('name'=>'replies', 'description'=>_('Send me replies '. 'from people I\'m not subscribed to.')), - // TRANS: Checkbox label in IM preferences form. - array('name'=>'microid', 'description'=>_('Publish a MicroID')) ); foreach($preferences as $preference) { @@ -211,57 +207,35 @@ class ImsettingsAction extends SettingsAction */ function getConfirmation($transport) { - $user = common_current_user(); - $confirm = new Confirm_address(); - $confirm->user_id = $user->id; + $confirm->user_id = $this->scoped->getID(); $confirm->address_type = $transport; if ($confirm->find(true)) { return $confirm; - } else { - return null; } + + throw new NoResultException($confirm); } - /** - * Handle posts to this form - * - * Based on the button that was pressed, muxes out to other functions - * to do the actual task requested. - * - * All sub-functions reload the form with a message -- success or failure. - * - * @return void - */ - function handlePost() + protected function doPost() { - // CSRF protection - $token = $this->trimmed('token'); - if (!$token || $token != common_session_token()) { - // TRANS: Client error displayed when the session token does not match or is not given. - $this->showForm(_('There was a problem with your session token. '. - 'Try again, please.')); - return; - } - if ($this->arg('save')) { - $this->savePreferences(); + return $this->savePreferences(); } else if ($this->arg('add')) { - $this->addAddress(); + return $this->addAddress(); } else if ($this->arg('cancel')) { - $this->cancelConfirmation(); + return $this->cancelConfirmation(); } else if ($this->arg('remove')) { - $this->removeAddress(); - } else { - // TRANS: Message given submitting a form with an unknown action in Instant Messaging settings. - $this->showForm(_('Unexpected form submission.')); + return $this->removeAddress(); } + // TRANS: Message given submitting a form with an unknown action in Instant Messaging settings. + throw new ClientException(_('Unexpected form submission.')); } /** - * Save user's Jabber preferences + * Save user's XMPP preferences * * These are the checkboxes at the bottom of the page. They're used to * set different settings @@ -270,14 +244,12 @@ class ImsettingsAction extends SettingsAction */ function savePreferences() { - $user = common_current_user(); - $user_im_prefs = new User_im_prefs(); $user_im_prefs->query('BEGIN'); - $user_im_prefs->user_id = $user->id; + $user_im_prefs->user_id = $this->scoped->getID(); if($user_im_prefs->find() && $user_im_prefs->fetch()) { - $preferences = array('notify', 'updatefrompresence', 'replies', 'microid'); + $preferences = array('notify', 'updatefrompresence', 'replies'); do { $original = clone($user_im_prefs); @@ -289,15 +261,15 @@ class ImsettingsAction extends SettingsAction $result = $new->update($original); if ($result === false) { - common_log_db_error($user, 'UPDATE', __FILE__); + common_log_db_error($user_im_prefs, 'UPDATE', __FILE__); // TRANS: Server error thrown on database error updating IM preferences. - $this->serverError(_('Could not update IM preferences.')); + throw new ServerException(_('Could not update IM preferences.')); } }while($user_im_prefs->fetch()); } $user_im_prefs->query('COMMIT'); // TRANS: Confirmation message for successful IM preferences save. - $this->showForm(_('Preferences saved.'), true); + return _('Preferences saved.'); } /** @@ -310,49 +282,42 @@ class ImsettingsAction extends SettingsAction */ function addAddress() { - $user = common_current_user(); - $screenname = $this->trimmed('screenname'); $transport = $this->trimmed('transport'); // Some validation - if (!$screenname) { + if (empty($screenname)) { // TRANS: Message given saving IM address without having provided one. - $this->showForm(_('No screenname.')); - return; + throw new ClientException(_('No screenname.')); } - if (!$transport) { + if (empty($transport)) { // TRANS: Form validation error when no transport is available setting an IM address. - $this->showForm(_('No transport.')); - return; + throw new ClientException(_('No transport.')); } Event::handle('NormalizeImScreenname', array($transport, &$screenname)); - if (!$screenname) { + if (empty($screenname)) { // TRANS: Message given saving IM address that cannot be normalised. - $this->showForm(_('Cannot normalize that screenname.')); - return; + throw new ClientException(_('Cannot normalize that screenname.')); } $valid = false; Event::handle('ValidateImScreenname', array($transport, $screenname, &$valid)); if (!$valid) { // TRANS: Message given saving IM address that not valid. - $this->showForm(_('Not a valid screenname.')); - return; + throw new ClientException(_('Not a valid screenname.')); } else if ($this->screennameExists($transport, $screenname)) { // TRANS: Message given saving IM address that is already set for another user. - $this->showForm(_('Screenname already belongs to another user.')); - return; + throw new ClientException(_('Screenname already belongs to another user.')); } $confirm = new Confirm_address(); $confirm->address = $screenname; $confirm->address_type = $transport; - $confirm->user_id = $user->id; + $confirm->user_id = $this->scoped->getID(); $confirm->code = common_confirmation_code(64); $confirm->sent = common_sql_now(); $confirm->claimed = common_sql_now(); @@ -365,13 +330,10 @@ class ImsettingsAction extends SettingsAction $this->serverError(_('Could not insert confirmation code.')); } - Event::handle('SendImConfirmationCode', array($transport, $screenname, $confirm->code, $user)); + Event::handle('SendImConfirmationCode', array($transport, $screenname, $confirm->code, $this->scoped)); // TRANS: Message given saving valid IM address that is to be confirmed. - $msg = _('A confirmation code was sent '. - 'to the IM address you added.'); - - $this->showForm($msg, true); + return _('A confirmation code was sent to the IM address you added.'); } /** @@ -386,29 +348,27 @@ class ImsettingsAction extends SettingsAction $screenname = $this->trimmed('screenname'); $transport = $this->trimmed('transport'); - $confirm = $this->getConfirmation($transport); - - if (!$confirm) { + try { + $confirm = $this->getConfirmation($transport); + if ($confirm->address != $screenname) { + // TRANS: Message given canceling IM address confirmation for the wrong IM address. + throw new ClientException(_('That is the wrong IM address.')); + } + } catch (NoResultException $e) { // TRANS: Message given canceling Instant Messaging address confirmation that is not pending. - $this->showForm(_('No pending confirmation to cancel.')); - return; - } - if ($confirm->address != $screenname) { - // TRANS: Message given canceling IM address confirmation for the wrong IM address. - $this->showForm(_('That is the wrong IM address.')); - return; + throw new AlreadyFulfilledException(_('No pending confirmation to cancel.')); } $result = $confirm->delete(); - if (!$result) { + if ($result === false) { common_log_db_error($confirm, 'DELETE', __FILE__); // TRANS: Server error thrown on database error canceling IM address confirmation. - $this->serverError(_('Could not delete confirmation.')); + throw new ServerException(_('Could not delete confirmation.')); } // TRANS: Message given after successfully canceling IM address confirmation. - $this->showForm(_('IM confirmation cancelled.'), true); + return _('IM confirmation cancelled.'); } /** @@ -420,34 +380,32 @@ class ImsettingsAction extends SettingsAction */ function removeAddress() { - $user = common_current_user(); - $screenname = $this->trimmed('screenname'); $transport = $this->trimmed('transport'); // Maybe an old tab open...? $user_im_prefs = new User_im_prefs(); - $user_im_prefs->user_id = $user->id; - if(! ($user_im_prefs->find() && $user_im_prefs->fetch())) { + $user_im_prefs->user_id = $this->scoped->getID(); + $user_im_prefs->transport = $transport; + if (!$user_im_prefs->find(true)) { // TRANS: Message given trying to remove an IM address that is not // TRANS: registered for the active user. - $this->showForm(_('That is not your screenname.')); - return; + throw new AlreadyFulfilledException(_('There were no preferences stored for this transport.')); } $result = $user_im_prefs->delete(); - if (!$result) { - common_log_db_error($user, 'UPDATE', __FILE__); + if ($result === false) { + common_log_db_error($user_im_prefs, 'UPDATE', __FILE__); // TRANS: Server error thrown on database error removing a registered IM address. - $this->serverError(_('Could not update user IM preferences.')); + throw new ServerException(_('Could not update user IM preferences.')); } // XXX: unsubscribe to the old address // TRANS: Message given after successfully removing a registered Instant Messaging address. - $this->showForm(_('The IM address was removed.'), true); + return _('The IM address was removed.'); } /** @@ -463,15 +421,9 @@ class ImsettingsAction extends SettingsAction function screennameExists($transport, $screenname) { - $user = common_current_user(); - $user_im_prefs = new User_im_prefs(); $user_im_prefs->transport = $transport; $user_im_prefs->screenname = $screenname; - if($user_im_prefs->find() && $user_im_prefs->fetch()){ - return true; - }else{ - return false; - } + return $user_im_prefs->find(true) ? true : false; } } diff --git a/actions/logout.php b/actions/logout.php index 60aec3c83a..5394a38c9f 100644 --- a/actions/logout.php +++ b/actions/logout.php @@ -63,7 +63,7 @@ class LogoutAction extends ManagedAction } Event::handle('EndLogout', array($this)); - common_redirect(common_local_url('startpage')); + common_redirect(common_local_url('top')); } // Accessed through the action on events diff --git a/actions/newapplication.php b/actions/newapplication.php index 37bede0d72..5032bb7495 100644 --- a/actions/newapplication.php +++ b/actions/newapplication.php @@ -41,7 +41,7 @@ if (!defined('GNUSOCIAL')) { exit(1); } * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @link http://status.net/ */ -class NewApplicationAction extends FormAction +class NewApplicationAction extends SettingsAction { function title() { @@ -54,6 +54,7 @@ class NewApplicationAction extends FormAction if ($this->arg('cancel')) { common_redirect(common_local_url('oauthappssettings'), 303); } elseif ($this->arg('save')) { + //trySave will never return, just throw exception or redirect $this->trySave(); } @@ -72,7 +73,7 @@ class NewApplicationAction extends FormAction return _('Use this form to register a new application.'); } - private function trySave() + protected function trySave() { $name = $this->trimmed('name'); $description = $this->trimmed('description'); @@ -137,7 +138,7 @@ class NewApplicationAction extends FormAction $app->query('BEGIN'); $app->name = $name; - $app->owner = $this->scoped->id; + $app->owner = $this->scoped->getID(); $app->description = $description; $app->source_url = $source_url; $app->organization = $organization; diff --git a/actions/noticesearchrss.php b/actions/noticesearchrss.php index 14c280f62c..2a5187b885 100644 --- a/actions/noticesearchrss.php +++ b/actions/noticesearchrss.php @@ -28,11 +28,7 @@ * along with this program. If not, see . */ -if (!defined('STATUSNET') && !defined('LACONICA')) { - exit(1); -} - -require_once INSTALLDIR.'/lib/rssaction.php'; +if (!defined('GNUSOCIAL')) { exit(1); } /** * RSS feed for notice search action class. @@ -48,19 +44,7 @@ require_once INSTALLDIR.'/lib/rssaction.php'; */ class NoticesearchrssAction extends Rss10Action { - function init() - { - return true; - } - - function prepare($args) - { - parent::prepare($args); - $this->notices = $this->getNotices(); - return true; - } - - function getNotices($limit=0) + protected function getNotices() { $q = $this->trimmed('q'); $notices = array(); @@ -70,8 +54,7 @@ class NoticesearchrssAction extends Rss10Action $search_engine = $notice->getSearchEngine('notice'); $search_engine->set_sort_mode('chron'); - if (!$limit) $limit = 20; - $search_engine->limit(0, $limit, true); + $search_engine->limit(0, $this->limit, true); if (false === $search_engine->query($q)) { $cnt = 0; } else { diff --git a/actions/oauthappssettings.php b/actions/oauthappssettings.php index 29e6d56073..43e9b33663 100644 --- a/actions/oauthappssettings.php +++ b/actions/oauthappssettings.php @@ -27,11 +27,7 @@ * @link http://status.net/ */ -if (!defined('STATUSNET') && !defined('LACONICA')) { - exit(1); -} - -require_once INSTALLDIR . '/lib/applicationlist.php'; +if (!defined('GNUSOCIAL')) { exit(1); } /** * Show a user's registered OAuth applications @@ -47,19 +43,11 @@ require_once INSTALLDIR . '/lib/applicationlist.php'; class OauthappssettingsAction extends SettingsAction { - var $page = 0; + protected $page = null; - function prepare($args) + protected function doPreparation() { - parent::prepare($args); - $this->page = ($this->arg('page')) ? ($this->arg('page') + 0) : 1; - - 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.')); - } - - return true; + $this->page = $this->int('page') ?: 1; } /** @@ -86,21 +74,13 @@ class OauthappssettingsAction extends SettingsAction return _('Applications you have registered'); } - /** - * Content area of the page - * - * @return void - */ - function showContent() { - $user = common_current_user(); - $offset = ($this->page - 1) * APPS_PER_PAGE; $limit = APPS_PER_PAGE + 1; $application = new Oauth_application(); - $application->owner = $user->id; + $application->owner = $this->scoped->getID(); $application->whereAdd("name != 'anonymous'"); $application->limit($offset, $limit); $application->orderBy('created DESC'); @@ -109,7 +89,7 @@ class OauthappssettingsAction extends SettingsAction $cnt = 0; if ($application) { - $al = new ApplicationList($application, $user, $this); + $al = new ApplicationList($application, $this->scoped, $this); $cnt = $al->show(); if (0 == $cnt) { $this->showEmptyListMessage(); @@ -135,34 +115,11 @@ class OauthappssettingsAction extends SettingsAction function showEmptyListMessage() { - // TRANS: Empty list message on page with OAuth applications. + // TRANS: Empty list message on page with OAuth applications. Markup allowed $message = sprintf(_('You have not registered any applications yet.')); $this->elementStart('div', 'guide'); $this->raw(common_markup_to_html($message)); $this->elementEnd('div'); } - - /** - * Handle posts to this form - * - * Based on the button that was pressed, muxes out to other functions - * to do the actual task requested. - * - * All sub-functions reload the form with a message -- success or failure. - * - * @return void - */ - - function handlePost() - { - // CSRF protection - - $token = $this->trimmed('token'); - if (!$token || $token != common_session_token()) { - $this->showForm(_('There was a problem with your session token. '. - 'Try again, please.')); - return; - } - } } diff --git a/actions/oauthconnectionssettings.php b/actions/oauthconnectionssettings.php index 9aa3ad434f..0c5a143443 100644 --- a/actions/oauthconnectionssettings.php +++ b/actions/oauthconnectionssettings.php @@ -27,11 +27,7 @@ * @link http://status.net/ */ -if (!defined('STATUSNET') && !defined('LACONICA')) { - exit(1); -} - -require_once INSTALLDIR . '/lib/applicationlist.php'; +if (!defined('GNUSOCIAL')) { exit(1); } /** * Show connected OAuth applications @@ -46,15 +42,14 @@ require_once INSTALLDIR . '/lib/applicationlist.php'; */ class OauthconnectionssettingsAction extends SettingsAction { - var $page = null; - var $oauth_token = null; + var $page = null; - function prepare($args) + protected $oauth_token = null; + + protected function doPreparation() { - parent::prepare($args); $this->oauth_token = $this->arg('oauth_token'); - $this->page = ($this->arg('page')) ? ($this->arg('page') + 0) : 1; - return true; + $this->page = $this->int('page') ?: 1; } /** @@ -87,18 +82,15 @@ class OauthconnectionssettingsAction extends SettingsAction function showContent() { - $user = common_current_user(); - $profile = $user->getProfile(); - $offset = ($this->page - 1) * APPS_PER_PAGE; $limit = APPS_PER_PAGE + 1; - $connection = $user->getConnectedApps($offset, $limit); + $connection = $this->scoped->getConnectedApps($offset, $limit); $cnt = 0; if (!empty($connection)) { - $cal = new ConnectedAppsList($connection, $user, $this); + $cal = new ConnectedAppsList($connection, $this->scoped, $this); $cnt = $cal->show(); } @@ -111,7 +103,7 @@ class OauthconnectionssettingsAction extends SettingsAction $cnt > APPS_PER_PAGE, $this->page, 'connectionssettings', - array('nickname' => $user->nickname) + array('nickname' => $this->scoped->getNickname()) ); } @@ -125,24 +117,14 @@ class OauthconnectionssettingsAction extends SettingsAction * * @return void */ - function handlePost() + protected function doPost() { - // CSRF protection - - $token = $this->trimmed('token'); - if (!$token || $token != common_session_token()) { - // TRANS: Client error displayed when the session token does not match or is not given. - $this->showForm(_('There was a problem with your session token. '. - 'Try again, please.')); - return; - } - if ($this->arg('revoke')) { - $this->revokeAccess($this->oauth_token); - } else { - // TRANS: Client error when submitting a form with unexpected information. - $this->clientError(_('Unexpected form submission.'), 401); + return $this->revokeAccess($this->oauth_token); } + + // TRANS: Client error when submitting a form with unexpected information. + throw new ClientException(_('Unexpected form submission.'), 401); } /** diff --git a/actions/oldschoolsettings.php b/actions/oldschoolsettings.php index 25ec13e481..5c07195478 100644 --- a/actions/oldschoolsettings.php +++ b/actions/oldschoolsettings.php @@ -28,11 +28,7 @@ * @link http://status.net/ */ -if (!defined('STATUSNET')) { - // This check helps protect against security problems; - // your code file can't be executed directly from the web. - exit(1); -} +if (!defined('GNUSOCIAL')) { exit(1); } /** * Old-school settings @@ -77,35 +73,23 @@ class OldschoolsettingsAction extends SettingsAction * @return boolean true */ - function prepare($argarray) + protected function doPreparation() { if (!common_config('oldschool', 'enabled')) { throw new ClientException("Old-school settings not enabled."); } - parent::prepare($argarray); - return true; } - /** - * Handler method - * - * @param array $argarray is ignored since it's now passed in in prepare() - * - * @return void - */ - - function handlePost() + function doPost() { - $user = common_current_user(); - - $osp = Old_school_prefs::getKV('user_id', $user->id); + $osp = Old_school_prefs::getKV('user_id', $this->scoped->getID()); $orig = null; if (!empty($osp)) { $orig = clone($osp); } else { $osp = new Old_school_prefs(); - $osp->user_id = $user->id; + $osp->user_id = $this->scoped->getID(); $osp->created = common_sql_now(); } @@ -113,34 +97,25 @@ class OldschoolsettingsAction extends SettingsAction $osp->stream_nicknames = $this->boolean('stream_nicknames'); $osp->modified = common_sql_now(); - if (!empty($orig)) { + if ($orig instanceof Old_school_prefs) { $osp->update($orig); } else { $osp->insert(); } // TRANS: Confirmation shown when user profile settings are saved. - $this->showForm(_('Settings saved.'), true); - - return; - } - - function showContent() - { - $user = common_current_user(); - $form = new OldSchoolForm($this, $user); - $form->show(); + return _('Settings saved.'); } } -class OldSchoolForm extends Form +class OldSchoolSettingsForm extends Form { var $user; - function __construct($out, $user) + function __construct(Action $out) { parent::__construct($out); - $this->user = $user; + $this->user = $out->getScoped()->getUser(); } /** diff --git a/actions/passwordsettings.php b/actions/passwordsettings.php index db36b612a2..cfdb6c7817 100644 --- a/actions/passwordsettings.php +++ b/actions/passwordsettings.php @@ -28,11 +28,7 @@ * @link http://status.net/ */ -if (!defined('STATUSNET') && !defined('LACONICA')) { - exit(1); -} - - +if (!defined('STATUSNET')) { exit(1); } /** * Change password @@ -77,18 +73,8 @@ class PasswordsettingsAction extends SettingsAction $this->autofocus('oldpassword'); } - /** - * Content area of the page - * - * Shows a form for changing the password - * - * @return void - */ - function showContent() { - $user = common_current_user(); - $this->elementStart('form', array('method' => 'POST', 'id' => 'form_password', 'class' => 'form_settings', @@ -102,7 +88,7 @@ class PasswordsettingsAction extends SettingsAction $this->elementStart('ul', 'form_data'); // Users who logged in with OpenID won't have a pwd - if ($user->password) { + if ($this->scoped->hasPassword()) { $this->elementStart('li'); // TRANS: Field label on page where to change password. $this->password('oldpassword', _('Old password')); @@ -129,29 +115,8 @@ class PasswordsettingsAction extends SettingsAction $this->elementEnd('form'); } - /** - * Handle a post - * - * Validate input and save changes. Reload the form with a success - * or error message. - * - * @return void - */ - function handlePost() + protected function doPost() { - // CSRF protection - - $token = $this->trimmed('token'); - if (!$token || $token != common_session_token()) { - // TRANS: Client error displayed when the session token does not match or is not given. - $this->showForm(_('There was a problem with your session token. '. - 'Try again, please.')); - return; - } - - $user = common_current_user(); - assert(!is_null($user)); // should already be checked - // FIXME: scrub input $newpassword = $this->arg('newpassword'); @@ -161,49 +126,44 @@ class PasswordsettingsAction extends SettingsAction if (strlen($newpassword) < 6) { // TRANS: Form validation error on page where to change password. - $this->showForm(_('Password must be 6 or more characters.')); - return; + throw new ClientException(_('Password must be 6 or more characters.')); } else if (0 != strcmp($newpassword, $confirm)) { // TRANS: Form validation error on password change when password confirmation does not match. - $this->showForm(_('Passwords do not match.')); - return; + throw new ClientException(_('Passwords do not match.')); } - if ($user->password) { + $oldpassword = null; + if ($this->scoped->hasPassword()) { $oldpassword = $this->arg('oldpassword'); - if (!common_check_user($user->nickname, $oldpassword)) { + if (!common_check_user($this->scoped->getNickname(), $oldpassword)) { // TRANS: Form validation error on page where to change password. - $this->showForm(_('Incorrect old password.')); - return; + throw new ClientException(_('Incorrect old password.')); } - }else{ - $oldpassword = null; } - $success = false; - if(Event::handle('StartChangePassword', array($user, $oldpassword, $newpassword))){ + if (Event::handle('StartChangePassword', array($this->scoped, $oldpassword, $newpassword))) { //no handler changed the password, so change the password internally + $user = $this->scoped->getUser(); $original = clone($user); - $user->password = common_munge_password($newpassword, $user->id); + $user->password = common_munge_password($newpassword, $this->scoped); $val = $user->validate(); if ($val !== true) { // TRANS: Form validation error on page where to change password. - $this->showForm(_('Error saving user; invalid.')); - return; + throw new ServerException(_('Error saving user; invalid.')); } if (!$user->update($original)) { // TRANS: Server error displayed on page where to change password when password change // TRANS: could not be made because of a server error. - $this->serverError(_('Cannot save new password.')); + throw new ServerException(_('Cannot save new password.')); } - Event::handle('EndChangePassword', array($user)); + Event::handle('EndChangePassword', array($this->scoped)); } // TRANS: Form validation notice on page where to change password. - $this->showForm(_('Password saved.'), true); + return _('Password saved.'); } } diff --git a/actions/profilesettings.php b/actions/profilesettings.php index 7d3143d4b1..5804f21ca5 100644 --- a/actions/profilesettings.php +++ b/actions/profilesettings.php @@ -82,7 +82,6 @@ class ProfilesettingsAction extends SettingsAction */ function showContent() { - $profile = $this->scoped; $user = $this->scoped->getUser(); $this->elementStart('form', array('method' => 'post', @@ -100,7 +99,7 @@ class ProfilesettingsAction extends SettingsAction $this->elementStart('li'); // TRANS: Field label in form for profile settings. $this->input('nickname', _('Nickname'), - $this->arg('nickname') ?: $profile->nickname, + $this->trimmed('nickname') ?: $this->scoped->getNickname(), // TRANS: Tooltip for field label in form for profile settings. _('1-64 lowercase letters or numbers, no punctuation or spaces.'), null, false, // "name" (will be set to id), then "required" @@ -111,12 +110,12 @@ class ProfilesettingsAction extends SettingsAction $this->elementStart('li'); // TRANS: Field label in form for profile settings. $this->input('fullname', _('Full name'), - ($this->arg('fullname')) ? $this->arg('fullname') : $profile->fullname); + $this->trimmed('fullname') ?: $this->scoped->getFullname()); $this->elementEnd('li'); $this->elementStart('li'); // TRANS: Field label in form for profile settings. $this->input('homepage', _('Homepage'), - ($this->arg('homepage')) ? $this->arg('homepage') : $profile->homepage, + $this->trimmed('homepage') ?: $this->scoped->getHomepage(), // TRANS: Tooltip for field label in form for profile settings. _('URL of your homepage, blog, or profile on another site.')); $this->elementEnd('li'); @@ -137,13 +136,13 @@ class ProfilesettingsAction extends SettingsAction // TRANS: Text area label in form for profile settings where users can provide // TRANS: their biography. $this->textarea('bio', _('Bio'), - ($this->arg('bio')) ? $this->arg('bio') : $profile->bio, + $this->trimmed('bio') ?: $this->scoped->getDescription(), $bioInstr); $this->elementEnd('li'); $this->elementStart('li'); // TRANS: Field label in form for profile settings. $this->input('location', _('Location'), - ($this->arg('location')) ? $this->arg('location') : $profile->location, + $this->trimmed('location') ?: $this->scoped->location, // TRANS: Tooltip for field label in form for profile settings. _('Where you are, like "City, State (or Region), Country".')); $this->elementEnd('li'); @@ -152,14 +151,14 @@ class ProfilesettingsAction extends SettingsAction // TRANS: Checkbox label in form for profile settings. $this->checkbox('sharelocation', _('Share my current location when posting notices'), ($this->arg('sharelocation')) ? - $this->arg('sharelocation') : $this->scoped->shareLocation()); + $this->boolean('sharelocation') : $this->scoped->shareLocation()); $this->elementEnd('li'); } Event::handle('EndProfileFormData', array($this)); $this->elementStart('li'); // TRANS: Field label in form for profile settings. $this->input('tags', _('Tags'), - ($this->arg('tags')) ? $this->arg('tags') : implode(' ', $user->getSelfTags()), + $this->trimmed('tags') ?: implode(' ', Profile_tag::getSelfTagsArray($this->scoped)), // TRANS: Tooltip for field label in form for profile settings. _('Tags for yourself (letters, numbers, -, ., and _), comma- or space- separated.')); $this->elementEnd('li'); @@ -228,17 +227,8 @@ class ProfilesettingsAction extends SettingsAction * * @return void */ - function handlePost() + protected function doPost() { - // CSRF protection - $token = $this->trimmed('token'); - if (!$token || $token != common_session_token()) { - // TRANS: Form validation error. - $this->showForm(_('There was a problem with your session token. '. - 'Try again, please.')); - return; - } - if (Event::handle('StartProfileSaveForm', array($this))) { // $nickname will only be set if this changenick value is true. @@ -246,15 +236,13 @@ class ProfilesettingsAction extends SettingsAction try { $nickname = Nickname::normalize($this->trimmed('nickname'), true); } catch (NicknameTakenException $e) { - // Abort only if the nickname is occupied by another local profile - if ($e->profile->id != $this->scoped->id) { - $this->showForm($e->getMessage()); - return; + // Abort only if the nickname is occupied by _another_ local user profile + if (!$this->scoped->sameAs($e->profile)) { + throw $e; } - $nickname = Nickname::normalize($this->trimmed('nickname')); // without in-use check this time - } catch (NicknameException $e) { - $this->showForm($e->getMessage()); - return; + // Since the variable wasn't set before the exception was thrown, let's run + // the normalize sequence again, but without in-use check this time. + $nickname = Nickname::normalize($this->trimmed('nickname')); } } @@ -273,33 +261,27 @@ class ProfilesettingsAction extends SettingsAction if (!is_null($homepage) && (strlen($homepage) > 0) && !common_valid_http_url($homepage)) { // TRANS: Validation error in form for profile settings. - $this->showForm(_('Homepage is not a valid URL.')); - return; - } else if (!is_null($fullname) && mb_strlen($fullname) > 255) { + throw new ClientException(_('Homepage is not a valid URL.')); + } else if (!is_null($fullname) && mb_strlen($fullname) > 191) { // TRANS: Validation error in form for profile settings. - $this->showForm(_('Full name is too long (maximum 255 characters).')); - return; + throw new ClientException(_('Full name is too long (maximum 191 characters).')); } else if (Profile::bioTooLong($bio)) { // 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).', + throw new ClientException(sprintf(_m('Bio is too long (maximum %d character).', 'Bio is too long (maximum %d characters).', Profile::maxBio()), Profile::maxBio())); - return; - } else if (!is_null($location) && mb_strlen($location) > 255) { + } else if (!is_null($location) && mb_strlen($location) > 191) { // TRANS: Validation error in form for profile settings. - $this->showForm(_('Location is too long (maximum 255 characters).')); - return; + throw new ClientException(_('Location is too long (maximum 191 characters).')); } else if (is_null($timezone) || !in_array($timezone, DateTimeZone::listIdentifiers())) { // TRANS: Validation error in form for profile settings. - $this->showForm(_('Timezone not selected.')); - return; + throw new ClientException(_('Timezone not selected.')); } else if (!is_null($language) && strlen($language) > 50) { // TRANS: Validation error in form for profile settings. - $this->showForm(_('Language is too long (maximum 50 characters).')); - return; + throw new ClientException(_('Language is too long (maximum 50 characters).')); } $tags = array(); @@ -315,15 +297,14 @@ class ProfilesettingsAction extends SettingsAction 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)); - return; + throw new ClientException(sprintf(_('Invalid tag: "%s".'), $tag)); } $tag_priv[$tag] = $private; } } - $user = common_current_user(); + $user = $this->scoped->getUser(); $user->query('BEGIN'); // $user->nickname is updated through Profile->update(); @@ -346,54 +327,53 @@ class ProfilesettingsAction extends SettingsAction $result = $user->update($original); if ($result === false) { common_log_db_error($user, 'UPDATE', __FILE__); + $user->query('ROLLBACK'); // TRANS: Server error thrown when user profile settings could not be updated to // TRANS: automatically subscribe to any subscriber. - $this->serverError(_('Could not update user for autosubscribe or subscribe_policy.')); + throw new ServerException(_('Could not update user for autosubscribe or subscribe_policy.')); } // Re-initialize language environment if it changed common_init_language(); } - $profile = $user->getProfile(); + $original = clone($this->scoped); - $orig_profile = clone($profile); - - if (common_config('profile', 'changenick') == true && $profile->nickname !== $nickname) { + if (common_config('profile', 'changenick') == true && $this->scoped->getNickname() !== $nickname) { assert(Nickname::normalize($nickname)===$nickname); - common_debug("Changing user nickname from '{$profile->nickname}' to '{$nickname}'."); - $profile->nickname = $nickname; - $profile->profileurl = common_profile_url($profile->nickname); + common_debug("Changing user nickname from '{$this->scoped->getNickname()}' to '{$nickname}'."); + $this->scoped->nickname = $nickname; + $this->scoped->profileurl = common_profile_url($this->scoped->getNickname()); } - $profile->fullname = $fullname; - $profile->homepage = $homepage; - $profile->bio = $bio; - $profile->location = $location; + $this->scoped->fullname = $fullname; + $this->scoped->homepage = $homepage; + $this->scoped->bio = $bio; + $this->scoped->location = $location; $loc = Location::fromName($location); if (empty($loc)) { - $profile->lat = null; - $profile->lon = null; - $profile->location_id = null; - $profile->location_ns = null; + $this->scoped->lat = null; + $this->scoped->lon = null; + $this->scoped->location_id = null; + $this->scoped->location_ns = null; } else { - $profile->lat = $loc->lat; - $profile->lon = $loc->lon; - $profile->location_id = $loc->location_id; - $profile->location_ns = $loc->location_ns; + $this->scoped->lat = $loc->lat; + $this->scoped->lon = $loc->lon; + $this->scoped->location_id = $loc->location_id; + $this->scoped->location_ns = $loc->location_ns; } if (common_config('location', 'share') == 'user') { $exists = false; - $prefs = User_location_prefs::getKV('user_id', $user->id); + $prefs = User_location_prefs::getKV('user_id', $this->scoped->getID()); if (empty($prefs)) { $prefs = new User_location_prefs(); - $prefs->user_id = $user->id; + $prefs->user_id = $this->scoped->getID(); $prefs->created = common_sql_now(); } else { $exists = true; @@ -410,42 +390,37 @@ class ProfilesettingsAction extends SettingsAction if ($result === false) { common_log_db_error($prefs, ($exists) ? 'UPDATE' : 'INSERT', __FILE__); + $user->query('ROLLBACK'); // TRANS: Server error thrown when user profile location preference settings could not be updated. - $this->serverError(_('Could not save location prefs.')); + throw new ServerException(_('Could not save location prefs.')); } } - common_debug('Old profile: ' . common_log_objstring($orig_profile), __FILE__); - common_debug('New profile: ' . common_log_objstring($profile), __FILE__); + common_debug('Old profile: ' . common_log_objstring($original), __FILE__); + common_debug('New profile: ' . common_log_objstring($this->scoped), __FILE__); - $result = $profile->update($orig_profile); + $result = $this->scoped->update($original); if ($result === false) { - common_log_db_error($profile, 'UPDATE', __FILE__); + common_log_db_error($this->scoped, 'UPDATE', __FILE__); + $user->query('ROLLBACK'); // TRANS: Server error thrown when user profile settings could not be saved. - $this->serverError(_('Could not save profile.')); + throw new ServerException(_('Could not save profile.')); } // Set the user tags - $result = $user->setSelfTags($tags, $tag_priv); - - if (!$result) { - // TRANS: Server error thrown when user profile settings tags could not be saved. - $this->serverError(_('Could not save tags.')); - } + $result = Profile_tag::setSelfTags($this->scoped, $tags, $tag_priv); $user->query('COMMIT'); Event::handle('EndProfileSaveForm', array($this)); // TRANS: Confirmation shown when user profile settings are saved. - $this->showForm(_('Settings saved.'), true); + return _('Settings saved.'); } } function showAside() { - $user = common_current_user(); - $this->elementStart('div', array('id' => 'aside_primary', 'class' => 'aside')); @@ -453,7 +428,7 @@ class ProfilesettingsAction extends SettingsAction 'class' => 'section')); $this->elementStart('ul'); if (Event::handle('StartProfileSettingsActions', array($this))) { - if ($user->hasRight(Right::BACKUPACCOUNT)) { + if ($this->scoped->hasRight(Right::BACKUPACCOUNT)) { $this->elementStart('li'); $this->element('a', array('href' => common_local_url('backupaccount')), @@ -461,7 +436,7 @@ class ProfilesettingsAction extends SettingsAction _('Backup account')); $this->elementEnd('li'); } - if ($user->hasRight(Right::DELETEACCOUNT)) { + if ($this->scoped->hasRight(Right::DELETEACCOUNT)) { $this->elementStart('li'); $this->element('a', array('href' => common_local_url('deleteaccount')), @@ -469,7 +444,7 @@ class ProfilesettingsAction extends SettingsAction _('Delete account')); $this->elementEnd('li'); } - if ($user->hasRight(Right::RESTOREACCOUNT)) { + if ($this->scoped->hasRight(Right::RESTOREACCOUNT)) { $this->elementStart('li'); $this->element('a', array('href' => common_local_url('restoreaccount')), diff --git a/actions/publicrss.php b/actions/publicrss.php index 11db3b37a4..5dcff3ba3d 100644 --- a/actions/publicrss.php +++ b/actions/publicrss.php @@ -28,11 +28,7 @@ * along with this program. If not, see . */ -if (!defined('STATUSNET') && !defined('LACONICA')) { - exit(1); -} - -require_once INSTALLDIR.'/lib/rssaction.php'; +if (!defined('GNUSOCIAL')) { exit(1); } /** * RSS feed for public timeline. @@ -48,29 +44,6 @@ require_once INSTALLDIR.'/lib/rssaction.php'; */ class PublicrssAction extends Rss10Action { - /** - * Read arguments and initialize members - * - * @param array $args Arguments from $_REQUEST - * @return boolean success - */ - function prepare($args) - { - parent::prepare($args); - $this->notices = $this->getNotices($this->limit); - return true; - } - - /** - * Initialization. - * - * @return boolean true - */ - function init() - { - return true; - } - /** * Get notices * @@ -78,15 +51,10 @@ class PublicrssAction extends Rss10Action * * @return array notices */ - function getNotices($limit=0) + protected function getNotices() { - $notices = array(); - $notice = Notice::publicStream(0, ($limit == 0) ? 48 : $limit); - while ($notice->fetch()) { - $notices[] = clone($notice); - } - - return $notices; + $stream = Notice::publicStream(0, $this->limit); + return $stream->fetchAll(); } /** diff --git a/actions/recoverpassword.php b/actions/recoverpassword.php index 060ba83510..1cbb73fd4a 100644 --- a/actions/recoverpassword.php +++ b/actions/recoverpassword.php @@ -325,7 +325,7 @@ class RecoverpasswordAction extends Action $original = clone($user); - $user->password = common_munge_password($newpassword, $user->id); + $user->password = common_munge_password($newpassword, $user->getProfile()); if (!$user->update($original)) { common_log_db_error($user, 'UPDATE', __FILE__); diff --git a/actions/redirecturl.php b/actions/redirecturl.php index 4befa4ab84..db3784bf31 100644 --- a/actions/redirecturl.php +++ b/actions/redirecturl.php @@ -28,11 +28,7 @@ * @link http://status.net/ */ -if (!defined('STATUSNET')) { - // This check helps protect against security problems; - // your code file can't be executed directly from the web. - exit(1); -} +if (!defined('GNUSOCIAL')) { exit(1); } /** * Redirect to a given URL @@ -47,75 +43,27 @@ if (!defined('STATUSNET')) { * @link http://status.net/ */ -class RedirecturlAction extends Action +class RedirecturlAction extends ManagedAction { - protected $id = null; protected $file = null; - /** - * For initializing members of the class. - * - * @param array $argarray misc. arguments - * - * @return boolean true - */ - function prepare($argarray) + protected function doPreparation() { - parent::prepare($argarray); - - $this->id = $this->trimmed('id'); - - if (empty($this->id)) { - // TRANS: Client exception thrown when no ID parameter was provided. - throw new ClientException(_('No id parameter.')); - } - - $this->file = File::getKV('id', $this->id); - - if (empty($this->file)) { - // TRANS: Client exception thrown when an invalid ID parameter was provided for a file. - // TRANS: %d is the provided ID for which the file is not present (number). - throw new ClientException(sprintf(_('No such file "%d".'), - $this->id), - 404); - } + $this->file = File::getByID($this->int('id')); return true; } - /** - * Handler method - * - * @param array $argarray is ignored since it's now passed in in prepare() - * - * @return void - */ - function handle($argarray=null) + public function showPage() { common_redirect($this->file->url, 307); } - /** - * Return true if read only. - * - * MAY override - * - * @param array $args other arguments - * - * @return boolean is read only action? - */ function isReadOnly($args) { return true; } - /** - * Return last modified, if applicable. - * - * MAY override - * - * @return string last modified http header - */ function lastModified() { // For comparison with If-Last-Modified @@ -133,9 +81,9 @@ class RedirecturlAction extends Action */ function etag() { - return 'W/"' . implode(':', array($this->arg('action'), + return 'W/"' . implode(':', array($this->getActionName(), common_user_cache_hash(), common_language(), - $this->file->id)) . '"'; + $this->file->getID())) . '"'; } } diff --git a/actions/replies.php b/actions/replies.php index 8baf9d69e0..ae6ec90658 100644 --- a/actions/replies.php +++ b/actions/replies.php @@ -40,9 +40,6 @@ if (!defined('GNUSOCIAL')) { exit(1); } */ class RepliesAction extends ShowstreamAction { - var $page = null; - var $notice; - public function getStream() { return new ReplyNoticeStream($this->target->getID(), $this->scoped); @@ -85,7 +82,7 @@ class RepliesAction extends ShowstreamAction // TRANS: Link for feed with replies for a user. // TRANS: %s is a user nickname. sprintf(_('Replies feed for %s (Activity Streams JSON)'), - $this->user->nickname)), + $this->target->getNickname())), new Feed(Feed::RSS1, common_local_url('repliesrss', array('nickname' => $this->target->getNickname())), diff --git a/actions/repliesrss.php b/actions/repliesrss.php index 145b51aaea..54f83592c0 100644 --- a/actions/repliesrss.php +++ b/actions/repliesrss.php @@ -17,70 +17,34 @@ * along with this program. If not, see . */ -if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); } - -require_once(INSTALLDIR.'/lib/rssaction.php'); +if (!defined('GNUSOCIAL')) { exit(1); } // Formatting of RSS handled by Rss10Action -class RepliesrssAction extends Rss10Action +class RepliesrssAction extends TargetedRss10Action { - var $user = null; - - function prepare($args) + protected function getNotices() { - parent::prepare($args); - $nickname = $this->trimmed('nickname'); - $this->user = User::getKV('nickname', $nickname); - - if (!$this->user) { - // TRANS: Client error displayed when providing a non-existing nickname in a RSS 1.0 action. - $this->clientError(_('No such user.')); - } else { - $this->notices = $this->getNotices($this->limit); - return true; - } - } - - function getNotices($limit=0) - { - $user = $this->user; - - $notice = $user->getReplies(0, ($limit == 0) ? 48 : $limit); - - $notices = array(); - - while ($notice->fetch()) { - $notices[] = clone($notice); - } - - return $notices; + $stream = $this->target->getReplies(0, $this->limit); + return $stream->fetchAll(); } function getChannel() { - $user = $this->user; $c = array('url' => common_local_url('repliesrss', array('nickname' => - $user->nickname)), + $this->target->getNickname())), // TRANS: RSS reply feed title. %s is a user nickname. - 'title' => sprintf(_("Replies to %s"), $user->nickname), + 'title' => sprintf(_("Replies to %s"), $this->target->getNickname()), 'link' => common_local_url('replies', - array('nickname' => - $user->nickname)), + array('nickname' => $this->target->getNickname())), // TRANS: RSS reply feed description. // TRANS: %1$s is a user nickname, %2$s is the StatusNet site name. 'description' => sprintf(_('Replies to %1$s on %2$s.'), - $user->nickname, common_config('site', 'name'))); + $this->target->getNickname(), common_config('site', 'name'))); return $c; } - function getImage() - { - $profile = $this->user->getProfile(); - return $profile->avatarUrl(AVATAR_PROFILE_SIZE); - } - function isReadOnly($args) { return true; diff --git a/actions/robotstxt.php b/actions/robotstxt.php index d686042cb1..fdfc2bd1bd 100644 --- a/actions/robotstxt.php +++ b/actions/robotstxt.php @@ -27,9 +27,7 @@ * along with this program. If not, see . */ -if (!defined('STATUSNET')) { - exit(1); -} +if (!defined('GNUSOCIAL')) { exit(1); } /** * Prints out a static robots.txt @@ -40,19 +38,9 @@ if (!defined('STATUSNET')) { * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3 * @link http://status.net/ */ -class RobotstxtAction extends Action +class RobotstxtAction extends ManagedAction { - /** - * Handles requests - * - * Since this is a relatively static document, we - * don't do a prepare() - * - * @param array $args GET, POST, and URL params; unused. - * - * @return void - */ - function handle($args) + public function showPage() { if (Event::handle('StartRobotsTxt', array($this))) { diff --git a/actions/shownotice.php b/actions/shownotice.php index 4a1adfd7de..23386868dd 100644 --- a/actions/shownotice.php +++ b/actions/shownotice.php @@ -222,25 +222,12 @@ class ShownoticeAction extends ManagedAction /** * Extra content * - * We show the microid(s) for the author, if any. + * Facebook OpenGraph metadata. * * @return void */ function extraHead() { - $user = User::getKV($this->profile->id); - - if (!$user instanceof User) { - return; - } - - if ($user->emailmicroid && $user->email && $this->notice->uri) { - $id = new Microid('mailto:'. $user->email, - $this->notice->uri); - $this->element('meta', array('name' => 'microid', - 'content' => $id->toString())); - } - // Extras to aid in sharing notices to Facebook $avatarUrl = $this->profile->avatarUrl(AVATAR_PROFILE_SIZE); $this->element('meta', array('property' => 'og:image', diff --git a/actions/showstream.php b/actions/showstream.php index 6eccbd06bf..890c1e711b 100644 --- a/actions/showstream.php +++ b/actions/showstream.php @@ -47,37 +47,6 @@ if (!defined('GNUSOCIAL')) { exit(1); } */ class ShowstreamAction extends NoticestreamAction { - var $notice; - - protected function doPreparation() - { - // showstream requires a nickname - $nickname_arg = $this->arg('nickname'); - $nickname = common_canonical_nickname($nickname_arg); - - // Permanent redirect on non-canonical nickname - - if ($nickname_arg != $nickname) { - $args = array('nickname' => $nickname); - if ($this->arg('page') && $this->arg('page') != 1) { - $args['page'] = $this->arg['page']; - } - common_redirect(common_local_url($this->getActionName(), $args), 301); - } - $this->user = User::getKV('nickname', $nickname); - - if (!$this->user) { - $group = Local_group::getKV('nickname', $nickname); - if ($group instanceof Local_group) { - common_redirect($group->getProfile()->getUrl()); - } - // TRANS: Client error displayed when calling a profile action without specifying a user. - $this->clientError(_('No such user.'), 404); - } - - $this->target = $this->user->getProfile(); - } - public function getStream() { if (empty($this->tag)) { @@ -194,13 +163,6 @@ class ShowstreamAction extends NoticestreamAction 'content' => $this->target->getDescription())); } - if ($this->target->isLocal() && $this->target->getUser()->emailmicroid && $this->target->getUser()->email && $this->target->getUrl()) { - $id = new Microid('mailto:'.$this->target->getUser()->email, - $this->selfUrl()); - $this->element('meta', array('name' => 'microid', - 'content' => $id->toString())); - } - // See https://wiki.mozilla.org/Microsummaries $this->element('link', array('rel' => 'microsummary', @@ -289,7 +251,7 @@ class ShowstreamAction extends NoticestreamAction { parent::showSections(); if (!common_config('performance', 'high')) { - $cloud = new PersonalTagCloudSection($this, $this->user); + $cloud = new PersonalTagCloudSection($this->target, $this); $cloud->show(); } } @@ -298,7 +260,7 @@ class ShowstreamAction extends NoticestreamAction { $options = parent::noticeFormOptions(); - if (!$this->scoped instanceof Profile || $this->scoped->id != $this->target->id) { + if (!$this->scoped instanceof Profile || !$this->scoped->sameAs($this->target)) { $options['to_profile'] = $this->target; } diff --git a/actions/smssettings.php b/actions/smssettings.php index ec8841281d..ca6a7d04ef 100644 --- a/actions/smssettings.php +++ b/actions/smssettings.php @@ -27,9 +27,7 @@ * @link http://status.net/ */ -if (!defined('STATUSNET') && !defined('LACONICA')) { - exit(1); -} +if (!defined('GNUSOCIAL')) { exit(1); } /** * Settings for SMS @@ -45,6 +43,14 @@ if (!defined('STATUSNET') && !defined('LACONICA')) { class SmssettingsAction extends SettingsAction { + protected function doPreparation() + { + if (!common_config('sms', 'enabled')) { + // TRANS: Message given in the SMS settings if SMS is not enabled on the site. + throw new ServerException(_('SMS is not available.')); + } + } + /** * Title of the page * @@ -86,14 +92,7 @@ class SmssettingsAction extends SettingsAction */ function showContent() { - if (!common_config('sms', 'enabled')) { - $this->element('div', array('class' => 'error'), - // TRANS: Message given in the SMS settings if SMS is not enabled on the site. - _('SMS is not available.')); - return; - } - - $user = common_current_user(); + $user = $this->scoped->getUser(); $this->elementStart('form', array('method' => 'post', 'id' => 'form_settings_sms', @@ -118,8 +117,8 @@ class SmssettingsAction extends SettingsAction // TRANS: Button label to remove a confirmed SMS address. $this->submit('remove', _m('BUTTON','Remove')); } else { - $confirm = $this->getConfirmation(); - if ($confirm) { + try { + $confirm = $this->getConfirmation(); $carrier = Sms_carrier::getKV($confirm->address_extra); $this->element('p', 'form_unconfirmed', $confirm->address . ' (' . $carrier->name . ')'); @@ -141,7 +140,7 @@ class SmssettingsAction extends SettingsAction $this->elementEnd('ul'); // TRANS: Button label to confirm SMS confirmation code in SMS settings. $this->submit('confirm', _m('BUTTON','Confirm')); - } else { + } catch (NoResultException $e) { $this->elementStart('ul', 'form_data'); $this->elementStart('li'); // TRANS: Field label for SMS phone number input in SMS settings form. @@ -216,60 +215,38 @@ class SmssettingsAction extends SettingsAction */ function getConfirmation() { - $user = common_current_user(); - $confirm = new Confirm_address(); - $confirm->user_id = $user->id; + $confirm->user_id = $this->scoped->getID(); $confirm->address_type = 'sms'; if ($confirm->find(true)) { return $confirm; - } else { - return null; } + + throw new NoResultException($confirm); } - /** - * Handle posts to this form - * - * Based on the button that was pressed, muxes out to other functions - * to do the actual task requested. - * - * All sub-functions reload the form with a message -- success or failure. - * - * @return void - */ - function handlePost() + protected function doPost() { - // CSRF protection - - $token = $this->trimmed('token'); - if (!$token || $token != common_session_token()) { - // TRANS: Client error displayed when the session token does not match or is not given. - $this->showForm(_('There was a problem with your session token. '. - 'Try again, please.')); - return; - } if ($this->arg('save')) { - $this->savePreferences(); + return $this->savePreferences(); } else if ($this->arg('add')) { - $this->addAddress(); + return $this->addAddress(); } else if ($this->arg('cancel')) { - $this->cancelConfirmation(); + return $this->cancelConfirmation(); } else if ($this->arg('remove')) { - $this->removeAddress(); + return $this->removeAddress(); } else if ($this->arg('removeincoming')) { - $this->removeIncoming(); + return $this->removeIncoming(); } else if ($this->arg('newincoming')) { - $this->newIncoming(); + return $this->newIncoming(); } else if ($this->arg('confirm')) { - $this->confirmCode(); - } else { - // TRANS: Message given submitting a form with an unknown action in SMS settings. - $this->showForm(_('Unexpected form submission.')); + return $this->confirmCode(); } + // TRANS: Message given submitting a form with an unknown action in SMS settings. + throw new ClientException(_('Unexpected form submission.')); } /** @@ -281,30 +258,26 @@ class SmssettingsAction extends SettingsAction */ function savePreferences() { - $smsnotify = $this->boolean('smsnotify'); - - $user = common_current_user(); - - assert(!is_null($user)); // should already be checked + $user = $this->scoped->getUser(); $user->query('BEGIN'); $original = clone($user); - $user->smsnotify = $smsnotify; + $user->smsnotify = $this->boolean('smsnotify'); $result = $user->update($original); if ($result === false) { common_log_db_error($user, 'UPDATE', __FILE__); // TRANS: Server error thrown on database error updating SMS preferences. - $this->serverError(_('Could not update user.')); + throw new ServerException(_('Could not update user.')); } $user->query('COMMIT'); // TRANS: Confirmation message for successful SMS preferences save. - $this->showForm(_('SMS preferences saved.'), true); + return _('SMS preferences saved.'); } /** @@ -324,28 +297,24 @@ class SmssettingsAction extends SettingsAction // Some validation - if (!$sms) { + if (empty($sms)) { // TRANS: Message given saving SMS phone number without having provided one. - $this->showForm(_('No phone number.')); - return; + throw new ClientException(_('No phone number.')); } - if (!$carrier_id) { + if (empty($carrier_id)) { // TRANS: Message given saving SMS phone number without having selected a carrier. - $this->showForm(_('No carrier selected.')); - return; + throw new ClientException(_('No carrier selected.')); } $sms = common_canonical_sms($sms); - if ($user->sms == $sms) { + if ($user->sms === $sms) { // TRANS: Message given saving SMS phone number that is already set. - $this->showForm(_('That is already your phone number.')); - return; + throw new AlreadyFulfilledException(_('That is already your phone number.')); } else if ($this->smsExists($sms)) { // TRANS: Message given saving SMS phone number that is already set for another user. - $this->showForm(_('That phone number already belongs to another user.')); - return; + throw new ClientException(_('That phone number already belongs to another user.')); } $confirm = new Confirm_address(); @@ -353,7 +322,7 @@ class SmssettingsAction extends SettingsAction $confirm->address = $sms; $confirm->address_extra = $carrier_id; $confirm->address_type = 'sms'; - $confirm->user_id = $user->id; + $confirm->user_id = $this->scoped->getID(); $confirm->code = common_confirmation_code(40); $result = $confirm->insert(); @@ -371,11 +340,9 @@ class SmssettingsAction extends SettingsAction $carrier->toEmailAddress($sms)); // TRANS: Message given saving valid SMS phone number that is to be confirmed. - $msg = _('A confirmation code was sent to the phone number you added. '. + return _('A confirmation code was sent to the phone number you added. '. 'Check your phone for the code and instructions '. 'on how to use it.'); - - $this->showForm($msg, true); } /** @@ -390,29 +357,27 @@ class SmssettingsAction extends SettingsAction $sms = $this->trimmed('sms'); $carrier = $this->trimmed('carrier'); - $confirm = $this->getConfirmation(); - - if (!$confirm) { + try { + $confirm = $this->getConfirmation(); + if ($confirm->address != $sms) { + // TRANS: Message given canceling SMS phone number confirmation for the wrong phone number. + throw new ClientException(_('That is the wrong confirmation number.')); + } + } catch (NoResultException $e) { // TRANS: Message given canceling SMS phone number confirmation that is not pending. - $this->showForm(_('No pending confirmation to cancel.')); - return; - } - if ($confirm->address != $sms) { - // TRANS: Message given canceling SMS phone number confirmation for the wrong phone number. - $this->showForm(_('That is the wrong confirmation number.')); - return; + throw new AlreadyFulfilledException(_('No pending confirmation to cancel.')); } $result = $confirm->delete(); - if (!$result) { + if ($result === false) { common_log_db_error($confirm, 'DELETE', __FILE__); // TRANS: Server error thrown on database error canceling SMS phone number confirmation. - $this->serverError(_('Could not delete SMS confirmation.')); + throw new ServerException(_('Could not delete SMS confirmation.')); } // TRANS: Message given after successfully canceling SMS phone number confirmation. - $this->showForm(_('SMS confirmation cancelled.'), true); + return _('SMS confirmation cancelled.'); } /** @@ -422,7 +387,7 @@ class SmssettingsAction extends SettingsAction */ function removeAddress() { - $user = common_current_user(); + $user = $this->scoped->getUser(); $sms = $this->arg('sms'); $carrier = $this->arg('carrier'); @@ -432,8 +397,7 @@ class SmssettingsAction extends SettingsAction if ($user->sms != $sms) { // TRANS: Message given trying to remove an SMS phone number that is not // TRANS: registered for the active user. - $this->showForm(_('That is not your phone number.')); - return; + throw new ClientException(_('That is not your phone number.')); } $original = clone($user); @@ -446,7 +410,7 @@ class SmssettingsAction extends SettingsAction $user->updateWithKeys($original); // TRANS: Message given after successfully removing a registered SMS phone number. - $this->showForm(_('The SMS phone number was removed.'), true); + return _('The SMS phone number was removed.'); } /** @@ -460,15 +424,13 @@ class SmssettingsAction extends SettingsAction */ function smsExists($sms) { - $user = common_current_user(); - $other = User::getKV('sms', $sms); - if (!$other) { + if (!$other instanceof User) { return false; - } else { - return $other->id != $user->id; } + + return !$this->scoped->sameAs($other->getProfile()); } /** @@ -519,15 +481,12 @@ class SmssettingsAction extends SettingsAction { $code = $this->trimmed('code'); - if (!$code) { + if (empty($code)) { // TRANS: Message given saving SMS phone number confirmation code without having provided one. - $this->showForm(_('No code entered.')); - return; + throw new ClientException(_('No code entered.')); } - common_redirect(common_local_url('confirmaddress', - array('code' => $code)), - 303); + common_redirect(common_local_url('confirmaddress', array('code' => $code)), 303); } /** @@ -541,8 +500,7 @@ class SmssettingsAction extends SettingsAction if (!$user->incomingemail) { // TRANS: Form validation error displayed when trying to remove an incoming e-mail address while no address has been set. - $this->showForm(_('No incoming email address.')); - return; + throw new ClientException(_('No incoming email address.')); } $orig = clone($user); @@ -553,7 +511,7 @@ class SmssettingsAction extends SettingsAction $user->updateWithKeys($orig); // TRANS: Confirmation text after updating SMS settings. - $this->showForm(_('Incoming email address removed.'), true); + return _('Incoming email address removed.'); } /** @@ -565,7 +523,7 @@ class SmssettingsAction extends SettingsAction */ function newIncoming() { - $user = common_current_user(); + $user = $this->scoped->getUser(); $orig = clone($user); @@ -575,6 +533,6 @@ class SmssettingsAction extends SettingsAction $user->updateWithKeys($orig); // TRANS: Confirmation text after updating SMS settings. - $this->showForm(_('New incoming email address added.'), true); + return _('New incoming email address added.'); } } diff --git a/actions/startpage.php b/actions/startpage.php deleted file mode 100644 index 9ce00d9c53..0000000000 --- a/actions/startpage.php +++ /dev/null @@ -1,26 +0,0 @@ - $user->nickname)), 303); - } elseif (common_config('public', 'localonly')) { - common_redirect(common_local_url('public'), 303); - } else { - common_redirect(common_local_url('networkpublic'), 303); - } - } -} diff --git a/actions/subscriptions.php b/actions/subscriptions.php index 231a697230..b5734b3747 100644 --- a/actions/subscriptions.php +++ b/actions/subscriptions.php @@ -28,9 +28,7 @@ * @link http://status.net/ */ -if (!defined('STATUSNET') && !defined('LACONICA')) { - exit(1); -} +if (!defined('GNUSOCIAL')) { exit(1); } /** * A list of the user's subscriptions @@ -60,7 +58,7 @@ class SubscriptionsAction extends GalleryAction function showPageNotice() { - if ($this->scoped instanceof Profile && $this->scoped->id === $this->target->id) { + if ($this->scoped instanceof Profile && $this->scoped->sameAs($this->getTarget())) { $this->element('p', null, // TRANS: Page notice for page with an overview of all subscriptions // TRANS: of the logged in user's own profile. diff --git a/actions/tagrss.php b/actions/tagrss.php index 8a1494f131..0d4d68ffba 100644 --- a/actions/tagrss.php +++ b/actions/tagrss.php @@ -17,38 +17,28 @@ * along with this program. If not, see . */ -if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); } - -require_once(INSTALLDIR.'/lib/rssaction.php'); +if (!defined('GNUSOCIAL')) { exit(1); } // Formatting of RSS handled by Rss10Action + class TagrssAction extends Rss10Action { - var $tag; + protected $tag; - function prepare($args) { - parent::prepare($args); + protected function doStreamPreparation() + { $tag = common_canonical_tag($this->trimmed('tag')); $this->tag = Notice_tag::getKV('tag', $tag); - if (!$this->tag) { + if (!$this->tag instanceof Notice_tag) { // TRANS: Client error when requesting a tag feed for a non-existing tag. $this->clientError(_('No such tag.')); - } else { - $this->notices = $this->getNotices($this->limit); - return true; } } - function getNotices($limit=0) + protected function getNotices() { - $tag = $this->tag; - - if (is_null($tag)) { - return null; - } - - $notice = Notice_tag::getStream($tag->tag)->getNotices(0, ($limit == 0) ? NOTICES_PER_PAGE : $limit); - return $notice->fetchAll(); + $stream = Notice_tag::getStream($this->tag->tag)->getNotices(0, $this->limit); + return $stream->fetchAll(); } function getChannel() diff --git a/actions/top.php b/actions/top.php index 39abe3df26..d30a40bafe 100644 --- a/actions/top.php +++ b/actions/top.php @@ -20,67 +20,29 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * - * @category Top - * @package StatusNet - * @author Evan Prodromou - * @copyright 2010 StatusNet, Inc. - * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0 - * @link http://status.net/ - */ - -if (!defined('STATUSNET')) { - // This check helps protect against security problems; - // your code file can't be executed directly from the web. - exit(1); -} - -/** - * An action to redirect to the top of the site - * * @category Action - * @package StatusNet + * @package GNUsocial * @author Evan Prodromou + * @author Mikael Nordfeldth * @copyright 2010 StatusNet, Inc. - * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0 - * @link http://status.net/ + * @copyright 2015 Free Software Foundation, Inc. + * @license https://www.gnu.org/licenses/agpl-3.0.html AGPL 3.0 + * @link https://gnu.io/social */ -class TopAction extends Action +if (!defined('GNUSOCIAL')) { exit(1); } + +class TopAction extends ManagedAction { - /** - * For initializing members of the class. - * - * @param array $argarray misc. arguments - * - * @return boolean true - */ - - function prepare($argarray) - { - parent::prepare($argarray); - return true; - } - - /** - * Handler method - * - * @param array $argarray is ignored since it's now passed in in prepare() - * - * @return void - */ - - function handle($argarray=null) + public function showPage() { if (common_config('singleuser', 'enabled')) { - $url = common_local_url('showstream', array('nickname' => User::singleUserNickname())); + $user = User::singleUser(); + common_redirect(common_local_url('showstream', array('nickname' => $user->getNickname())), 303); + } elseif (common_config('public', 'localonly')) { + common_redirect(common_local_url('public'), 303); } else { - $url = common_local_url('public'); + common_redirect(common_local_url('networkpublic'), 303); } - - // XXX: Permanent? I think so. - - common_redirect($url, 301); - - return; } } diff --git a/actions/urlsettings.php b/actions/urlsettings.php index 69ad4c8690..c3e4ed50b2 100644 --- a/actions/urlsettings.php +++ b/actions/urlsettings.php @@ -28,9 +28,7 @@ * @link http://status.net/ */ -if (!defined('STATUSNET') && !defined('LACONICA')) { - exit(1); -} +if (!defined('GNUSOCIAL')) { exit(1); } /** * Miscellaneous settings actions @@ -83,7 +81,7 @@ class UrlsettingsAction extends SettingsAction */ function showContent() { - $user = common_current_user(); + $user = $this->scoped->getUser(); $this->elementStart('form', array('method' => 'post', 'id' => 'form_settings_other', @@ -154,31 +152,13 @@ class UrlsettingsAction extends SettingsAction $this->elementEnd('form'); } - /** - * Handle a post - * - * Saves the changes to url-shortening prefs and shows a success or failure - * message. - * - * @return void - */ - function handlePost() + protected function doPost() { - // CSRF protection - $token = $this->trimmed('token'); - if (!$token || $token != common_session_token()) { - // TRANS: Client error displayed when the session token does not match or is not given. - $this->showForm(_('There was a problem with your session token. '. - 'Try again, please.')); - return; - } - $urlshorteningservice = $this->trimmed('urlshorteningservice'); if (!is_null($urlshorteningservice) && strlen($urlshorteningservice) > 50) { // TRANS: Form validation error for form "Other settings" in user profile. - $this->showForm(_('URL shortening service is too long (maximum 50 characters).')); - return; + throw new ClientException(_('URL shortening service is too long (maximum 50 characters).')); } $maxurllength = $this->trimmed('maxurllength'); @@ -195,9 +175,7 @@ class UrlsettingsAction extends SettingsAction throw new ClientException(_('Invalid number for maximum notice length.')); } - $user = common_current_user(); - - assert(!is_null($user)); // should already be checked + $user = $this->scoped->getUser(); $user->query('BEGIN'); @@ -209,14 +187,15 @@ class UrlsettingsAction extends SettingsAction if ($result === false) { common_log_db_error($user, 'UPDATE', __FILE__); + $user->query('ROLLBACK'); // TRANS: Server error displayed when "Other" settings in user profile could not be updated on the server. - $this->serverError(_('Could not update user.')); + throw new ServerException(_('Could not update user.')); } $prefs = User_urlshortener_prefs::getPrefs($user); $orig = null; - if (empty($prefs)) { + if (!$prefs instanceof User_urlshortener_prefs) { $prefs = new User_urlshortener_prefs(); $prefs->user_id = $user->id; @@ -229,13 +208,14 @@ class UrlsettingsAction extends SettingsAction $prefs->maxurllength = $maxurllength; $prefs->maxnoticelength = $maxnoticelength; - if (!empty($orig)) { + if ($orig instanceof User_urlshortener_prefs) { $result = $prefs->update($orig); } else { $result = $prefs->insert(); } - if (!$result) { + if ($result === null) { + $user->query('ROLLBACK'); // TRANS: Server exception thrown in profile URL settings when preferences could not be saved. throw new ServerException(_('Error saving user URL shortening preferences.')); } @@ -243,6 +223,6 @@ class UrlsettingsAction extends SettingsAction $user->query('COMMIT'); // TRANS: Confirmation message after saving preferences. - $this->showForm(_('Preferences saved.'), true); + return _('Preferences saved.'); } } diff --git a/actions/usergroups.php b/actions/usergroups.php index fd112ba8ec..d4756dffb5 100644 --- a/actions/usergroups.php +++ b/actions/usergroups.php @@ -52,12 +52,12 @@ class UsergroupsAction extends GalleryAction if ($this->page == 1) { // TRANS: Page title for first page of groups for a user. // TRANS: %s is a nickname. - return sprintf(_('%s groups'), $this->user->nickname); + return sprintf(_('%s groups'), $this->getTarget()->getNickname()); } else { // TRANS: Page title for all but the first page of groups for a user. // TRANS: %1$s is a nickname, %2$d is a page number. return sprintf(_('%1$s groups, page %2$d'), - $this->user->nickname, + $this->getTarget()->getNickname(), $this->page); } } @@ -82,14 +82,14 @@ class UsergroupsAction extends GalleryAction $offset = ($this->page-1) * GROUPS_PER_PAGE; $limit = GROUPS_PER_PAGE + 1; - $groups = $this->user->getGroups($offset, $limit); + $groups = $this->getTarget()->getGroups($offset, $limit); if ($groups instanceof User_group) { - $gl = new GroupList($groups, $this->user, $this); + $gl = new GroupList($groups, $this->getTarget(), $this); $cnt = $gl->show(); $this->pagination($this->page > 1, $cnt > GROUPS_PER_PAGE, $this->page, 'usergroups', - array('nickname' => $this->user->nickname)); + array('nickname' => $this->getTarget()->getNickname())); } else { $this->showEmptyListMessage(); } @@ -102,11 +102,11 @@ class UsergroupsAction extends GalleryAction { // TRANS: Text on group page for a user that is not a member of any group. // TRANS: %s is a user nickname. - $message = sprintf(_('%s is not a member of any group.'), $this->user->nickname) . ' '; + $message = sprintf(_('%s is not a member of any group.'), $this->getTarget()->getNickname()) . ' '; if (common_logged_in()) { $current_user = common_current_user(); - if ($this->user->id === $current_user->id) { + if ($this->scoped->sameAs($this->getTarget())) { // TRANS: Text on group page for a user that is not a member of any group. This message contains // TRANS: a Markdown link in the form [link text](link) and a variable that should not be changed. $message .= _('Try [searching for groups](%%action.groupsearch%%) and joining them.'); @@ -119,7 +119,7 @@ class UsergroupsAction extends GalleryAction function showProfileBlock() { - $block = new AccountProfileBlock($this, $this->profile); + $block = new AccountProfileBlock($this, $this->getTarget()); $block->show(); } } diff --git a/actions/userrss.php b/actions/userrss.php index 308db94891..7bed1dd256 100644 --- a/actions/userrss.php +++ b/actions/userrss.php @@ -17,100 +17,54 @@ * along with this program. If not, see . */ -if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); } - -require_once(INSTALLDIR.'/lib/rssaction.php'); +if (!defined('GNUSOCIAL')) { exit(1); } // Formatting of RSS handled by Rss10Action -class UserrssAction extends Rss10Action +class UserrssAction extends TargetedRss10Action { - var $tag = null; + protected $tag = null; - function prepare($args) + protected function doStreamPreparation() { - parent::prepare($args); - $nickname = $this->trimmed('nickname'); - $this->user = User::getKV('nickname', $nickname); + parent::doStreamPreparation(); + $this->tag = $this->trimmed('tag'); + } - if (!$this->user) { - // TRANS: Client error displayed when user not found for an action. - $this->clientError(_('No such user.')); - } - + protected function getNotices() + { if (!empty($this->tag)) { - $this->notices = $this->getTaggedNotices(); - } else { - $this->notices = $this->getNotices(); + $stream = $this->getTarget()->getTaggedNotices($this->tag, 0, $this->limit); + return $stream->fetchAll(); } + // otherwise we fetch a normal user stream - return true; - } - - function getTaggedNotices() - { - $notice = $this->user->getTaggedNotices( - $this->tag, - 0, - ($this->limit == 0) ? NOTICES_PER_PAGE : $this->limit, - 0, - 0 - ); - - $notices = array(); - while ($notice->fetch()) { - $notices[] = clone($notice); - } - - return $notices; - } - - - function getNotices() - { - $notice = $this->user->getNotices( - 0, - ($this->limit == 0) ? NOTICES_PER_PAGE : $this->limit - ); - - $notices = array(); - while ($notice->fetch()) { - $notices[] = clone($notice); - } - - return $notices; + $stream = $this->getTarget()->getNotices(0, $this->limit); + return $stream->fetchAll(); } function getChannel() { - $user = $this->user; - $profile = $user->getProfile(); $c = array('url' => common_local_url('userrss', array('nickname' => - $user->nickname)), + $this->target->getNickname())), // TRANS: Message is used as link title. %s is a user nickname. - 'title' => sprintf(_('%s timeline'), $user->nickname), - 'link' => $profile->profileurl, + 'title' => sprintf(_('%s timeline'), $this->target->getNickname()), + 'link' => $this->target->getUrl(), // TRANS: Message is used as link description. %1$s is a username, %2$s is a site name. 'description' => sprintf(_('Updates from %1$s on %2$s!'), - $user->nickname, common_config('site', 'name'))); + $this->target->getNickname(), common_config('site', 'name'))); return $c; } - function getImage() - { - $profile = $this->user->getProfile(); - return $profile->avatarUrl(AVATAR_PROFILE_SIZE); - } - // override parent to add X-SUP-ID URL - function initRss($limit=0) + function initRss() { - $url = common_local_url('sup', null, null, $this->user->id); + $url = common_local_url('sup', null, null, $this->target->getID()); header('X-SUP-ID: '.$url); - parent::initRss($limit); + parent::initRss(); } function isReadOnly($args) diff --git a/avatar/.gitignore b/avatar/.gitignore deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/background/.gitignore b/background/.gitignore deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/classes/Conversation.php b/classes/Conversation.php index 537c214a4c..9ef1e06b76 100644 --- a/classes/Conversation.php +++ b/classes/Conversation.php @@ -110,8 +110,7 @@ class Conversation extends Managed_DataObject { $conv = new Conversation(); $conv->id = $notice->conversation; - $conv->find(true); - if (!$conv instanceof Conversation) { + if (!$conv->find(true)) { common_debug('Conversation does not exist for notice ID: '.$notice->id); throw new NoResultException($conv); } diff --git a/classes/File_redirection.php b/classes/File_redirection.php index ba516e4623..2b6f86ed27 100644 --- a/classes/File_redirection.php +++ b/classes/File_redirection.php @@ -166,7 +166,7 @@ class File_redirection extends Managed_DataObject * size (optional): byte size from Content-Length header * time (optional): timestamp from Last-Modified header */ - public function where($in_url, $discover=true) { + static function where($in_url, $discover=true) { // let's see if we know this... try { $a = File::getByUrl($in_url); @@ -176,7 +176,7 @@ class File_redirection extends Managed_DataObject try { $b = File_redirection::getByUrl($in_url); // this is a redirect to $b->file_id - $a = File::getKV('id', $b->file_id); + $a = File::getByID($b->file_id); return $a->url; } catch (NoResultException $e) { // Oh well, let's keep going @@ -186,10 +186,10 @@ class File_redirection extends Managed_DataObject if ($discover) { $ret = File_redirection::lookupWhere($in_url); return $ret; - } else { - // No manual dereferencing; leave the unknown URL as is. - return $in_url; } + + // No manual dereferencing; leave the unknown URL as is. + return $in_url; } /** @@ -206,7 +206,7 @@ class File_redirection extends Managed_DataObject * @param User $user whose shortening options to use; defaults to the current web session user * @return string */ - function makeShort($long_url, $user=null) + static function makeShort($long_url, $user=null) { $canon = File_redirection::_canonUrl($long_url); @@ -214,11 +214,7 @@ class File_redirection extends Managed_DataObject // Did we get one? Is it shorter? - if (!empty($short_url)) { - return $short_url; - } else { - return $long_url; - } + return !empty($short_url) ? $short_url : $long_url; } /** @@ -235,18 +231,14 @@ class File_redirection extends Managed_DataObject * @return string */ - function forceShort($long_url, $user) + static function forceShort($long_url, $user) { $canon = File_redirection::_canonUrl($long_url); $short_url = File_redirection::_userMakeShort($canon, $user, true); // Did we get one? Is it shorter? - if (!empty($short_url)) { - return $short_url; - } else { - return $long_url; - } + return !empty($short_url) ? $short_url : $long_url; } static function _userMakeShort($long_url, User $user=null, $force = false) { diff --git a/classes/Foreign_link.php b/classes/Foreign_link.php index 6176ec43bc..b3757448ad 100644 --- a/classes/Foreign_link.php +++ b/classes/Foreign_link.php @@ -56,34 +56,37 @@ class Foreign_link extends Managed_DataObject static function getByUserID($user_id, $service) { if (empty($user_id) || empty($service)) { - return null; + throw new ServerException('Empty user_id or service for Foreign_link::getByUserID'); } $flink = new Foreign_link(); - $flink->service = $service; $flink->user_id = $user_id; $flink->limit(1); - $result = $flink->find(true); + if (!$flink->find(true)) { + throw new NoResultException($flink); + } - return empty($result) ? null : $flink; + return $flink; } static function getByForeignID($foreign_id, $service) { if (empty($foreign_id) || empty($service)) { - return null; - } else { - $flink = new Foreign_link(); - $flink->service = $service; - $flink->foreign_id = $foreign_id; - $flink->limit(1); - - $result = $flink->find(true); - - return empty($result) ? null : $flink; + throw new ServerException('Empty foreign_id or service for Foreign_link::getByForeignID'); } + + $flink = new Foreign_link(); + $flink->service = $service; + $flink->foreign_id = $foreign_id; + $flink->limit(1); + + if (!$flink->find(true)) { + throw new NoResultException($flink); + } + + return $flink; } function set_flags($noticesend, $noticerecv, $replysync, $friendsync) @@ -124,21 +127,21 @@ class Foreign_link extends Managed_DataObject $fuser->limit(1); - if ($fuser->find(true)) { - return $fuser; + if (!$fuser->find(true)) { + throw new NoResultException($fuser); } - return null; + return $fuser; } function getUser() { - return User::getKV($this->user_id); + return Profile::getByID($this->user_id)->getUser(); } function getProfile() { - return Profile::getKV('id', $this->user_id); + return Profile::getByID($this->user_id); } // Make sure we only ever delete one record at a time diff --git a/classes/Foreign_user.php b/classes/Foreign_user.php index c1739d318a..1f6c77851d 100644 --- a/classes/Foreign_user.php +++ b/classes/Foreign_user.php @@ -41,33 +41,39 @@ class Foreign_user extends Managed_DataObject ); } - static function getForeignUser($id, $service) { + static function getForeignUser($id, $service) + { + if (empty($id) || empty($service)) { + throw new ServerException('Empty foreign user id or service for Foreign_user::getForeignUser'); + } $fuser = new Foreign_user(); - $fuser->id = $id; $fuser->service = $service; - $fuser->limit(1); - $result = $fuser->find(true); + if (!$fuser->find(true)) { + throw new NoResultException($fuser); + } - return empty($result) ? null : $fuser; + return $fuser; } static function getByNickname($nickname, $service) { if (empty($nickname) || empty($service)) { - return null; - } else { - $fuser = new Foreign_user(); - $fuser->service = $service; - $fuser->nickname = $nickname; - $fuser->limit(1); - - $result = $fuser->find(true); - - return empty($result) ? null : $fuser; + throw new ServerException('Empty nickname or service for Foreign_user::getByNickname'); } + + $fuser = new Foreign_user(); + $fuser->service = $service; + $fuser->nickname = $nickname; + $fuser->limit(1); + + if (!$fuser->find(true)) { + throw new NoResultException($fuser); + } + + return $fuser; } } diff --git a/classes/Local_group.php b/classes/Local_group.php index 9e95102d85..1cebd4c40c 100644 --- a/classes/Local_group.php +++ b/classes/Local_group.php @@ -50,7 +50,7 @@ class Local_group extends Managed_DataObject $group->find(true); if (!$group instanceof User_group) { common_log(LOG_ERR, 'User_group does not exist for Local_group: '.$this->group_id); - throw new NoResultException($group); + throw new NoSuchGroupException(array('id' => $this->group_id)); } return $group; } diff --git a/classes/Memcached_DataObject.php b/classes/Memcached_DataObject.php index c1f6f644db..41ce715210 100644 --- a/classes/Memcached_DataObject.php +++ b/classes/Memcached_DataObject.php @@ -74,7 +74,7 @@ class Memcached_DataObject extends Safe_DataObject { $obj = new $cls; - // php-compatible, for settype(), datatype + // PHP compatible datatype for settype() below $colType = $obj->columnType($keyCol); if (!in_array($colType, array('integer', 'int'))) { diff --git a/classes/Notice.php b/classes/Notice.php index 8c9957958b..0d0933115e 100644 --- a/classes/Notice.php +++ b/classes/Notice.php @@ -65,10 +65,6 @@ class Notice extends Managed_DataObject public $is_local; // int(4) public $source; // varchar(32) public $conversation; // int(4) - public $lat; // decimal(10,7) - public $lon; // decimal(10,7) - public $location_id; // int(4) - public $location_ns; // int(4) public $repeat_of; // int(4) public $verb; // varchar(191) not 255 because utf8mb4 takes more space public $object_type; // varchar(191) not 255 because utf8mb4 takes more space @@ -93,10 +89,6 @@ class Notice extends Managed_DataObject 'is_local' => array('type' => 'int', 'size' => 'tiny', 'default' => 0, 'description' => 'notice was generated by a user'), 'source' => array('type' => 'varchar', 'length' => 32, 'description' => 'source of comment, like "web", "im", or "clientname"'), 'conversation' => array('type' => 'int', 'description' => 'id of root notice in this conversation'), - 'lat' => array('type' => 'numeric', 'precision' => 10, 'scale' => 7, 'description' => 'latitude'), - 'lon' => array('type' => 'numeric', 'precision' => 10, 'scale' => 7, 'description' => 'longitude'), - 'location_id' => array('type' => 'int', 'description' => 'location id if possible'), - 'location_ns' => array('type' => 'int', 'description' => 'namespace for location'), 'repeat_of' => array('type' => 'int', 'description' => 'notice this is a repeat of'), 'object_type' => array('type' => 'varchar', 'length' => 191, 'description' => 'URI representing activity streams object type', 'default' => 'http://activitystrea.ms/schema/1.0/note'), 'verb' => array('type' => 'varchar', 'length' => 191, 'description' => 'URI representing activity streams verb', 'default' => 'http://activitystrea.ms/schema/1.0/post'), @@ -196,6 +188,7 @@ class Notice extends Managed_DataObject // Clear related records $this->clearReplies(); + $this->clearLocation(); $this->clearRepeats(); $this->clearTags(); $this->clearGroupInboxes(); @@ -523,18 +516,13 @@ class Notice extends Managed_DataObject // Handle repeat case - if (isset($repeat_of)) { + if (!empty($options['repeat_of'])) { // Check for a private one - $repeat = Notice::getKV('id', $repeat_of); + $repeat = Notice::getByID($options['repeat_of']); - if (!($repeat instanceof Notice)) { - // TRANS: Client exception thrown in notice when trying to repeat a missing or deleted notice. - throw new ClientException(_('Cannot repeat; original notice is missing or deleted.')); - } - - if ($profile->id == $repeat->profile_id) { + if ($profile->sameAs($repeat->getProfile())) { // TRANS: Client error displayed when trying to repeat an own notice. throw new ClientException(_('You cannot repeat your own notice.')); } @@ -610,12 +598,13 @@ class Notice extends Managed_DataObject if (empty($notice->conversation) and !empty($options['conversation'])) { $conv = Conversation::getKV('uri', $options['conversation']); if ($conv instanceof Conversation) { - common_debug('Conversation stitched together from (probably) reply to unknown remote user. Activity creation time ('.$notice->created.') should maybe be compared to conversation creation time ('.$conv->created.').'); + common_debug('Conversation stitched together from (probably) a reply to unknown remote user. Activity creation time ('.$notice->created.') should maybe be compared to conversation creation time ('.$conv->created.').'); $notice->conversation = $conv->id; } else { // Conversation URI was not found, so we must create it. But we can't create it // until we have a Notice ID because of the database layout... - $notice->tmp_conv_uri = $options['conversation']; + // $options['conversation'] will be used later after the $notice->insert(); + common_debug('Conversation URI not found, so we have to create it after inserting this Notice: '.$options['conversation']); } } else { // If we're not using the attached conversation URI let's remove it @@ -625,14 +614,15 @@ class Notice extends Managed_DataObject } } + $notloc = new Notice_location(); if (!empty($lat) && !empty($lon)) { - $notice->lat = $lat; - $notice->lon = $lon; + $notloc->lat = $lat; + $notloc->lon = $lon; } if (!empty($location_ns) && !empty($location_id)) { - $notice->location_id = $location_id; - $notice->location_ns = $location_ns; + $notloc->location_id = $location_id; + $notloc->location_ns = $location_ns; } if (!empty($rendered)) { @@ -671,12 +661,19 @@ class Notice extends Managed_DataObject // XXX: some of these functions write to the DB try { - $notice->insert(); // throws exception on failure + $notice->insert(); // throws exception on failure, if successful we have an ->id + + if (($notloc->lat && $notloc->lon) || ($notloc->location_id && $notloc->location_ns)) { + $notloc->notice_id = $notice->getID(); + $notloc->insert(); // store the notice location if it had any information + } + // If it's not part of a conversation, it's // the beginning of a new conversation. if (empty($notice->conversation)) { $orig = clone($notice); // $act->context->conversation will be null if it was not provided + $conv = Conversation::create($notice, $options['conversation']); $notice->conversation = $conv->id; $notice->update($orig); @@ -853,17 +850,28 @@ class Notice extends Managed_DataObject if (is_null($scope)) { $scope = $reply->scope; } + } else { + // If we don't know the reply, we might know the conversation! + // This will happen if a known remote user replies to an + // unknown remote user - within a known conversation. + if (empty($stored->conversation) and !empty($act->context->conversation)) { + $conv = Conversation::getKV('uri', $act->context->conversation); + if ($conv instanceof Conversation) { + common_debug('Conversation stitched together from (probably) a reply activity to unknown remote user. Activity creation time ('.$stored->created.') should maybe be compared to conversation creation time ('.$conv->created.').'); + $stored->conversation = $conv->id; + } else { + // Conversation URI was not found, so we must create it. But we can't create it + // until we have a Notice ID because of the database layout... + // $options['conversation'] will be used later after the $stored->insert(); + common_debug('Conversation URI from activity context not found, so we have to create it after inserting this Notice: '.$act->context->conversation); + } + } } + $notloc = null; if ($act->context instanceof ActivityContext) { - $location = $act->context->location; - if ($location) { - $stored->lat = $location->lat; - $stored->lon = $location->lon; - if ($location->location_id) { - $stored->location_ns = $location->location_ns; - $stored->location_id = $location->location_id; - } + if ($act->context->location instanceof Location) { + $notloc = Notice_location::fromLocation($act->context->location); } } else { $act->context = new ActivityContext(); @@ -890,6 +898,12 @@ class Notice extends Managed_DataObject try { $stored->insert(); // throws exception on error + + if ($notloc instanceof Notice_location) { + $notloc->notice_id = $stored->getID(); + $notloc->insert(); + } + $orig = clone($stored); // for updating later in this try clause $object = null; @@ -898,10 +912,11 @@ class Notice extends Managed_DataObject throw new ServerException('Unsuccessful call to StoreActivityObject '.$stored->uri . ': '.$act->asString()); } - // If it's not part of a conversation, it's - // the beginning of a new conversation. + // If it's not part of a conversation, it's the beginning + // of a new one (or belongs to a previously unknown URI). if (empty($stored->conversation)) { // $act->context->conversation will be null if it was not provided + common_debug('Creating a new conversation for stored notice ID='.$stored->getID().' with URI: '.$act->context->conversation); $conv = Conversation::create($stored, $act->context->conversation); $stored->conversation = $conv->id; } @@ -1203,17 +1218,15 @@ class Notice extends Managed_DataObject $this->_attachments[$this->id] = $attachments; } - function publicStream($offset=0, $limit=20, $since_id=0, $max_id=0) + static function publicStream($offset=0, $limit=20, $since_id=null, $max_id=null) { $stream = new PublicNoticeStream(); return $stream->getNotices($offset, $limit, $since_id, $max_id); } - - function conversationStream($id, $offset=0, $limit=20, $since_id=0, $max_id=0) + static function conversationStream($id, $offset=0, $limit=20, $since_id=null, $max_id=null) { $stream = new ConversationNoticeStream($id); - return $stream->getNotices($offset, $limit, $since_id, $max_id); } @@ -1225,18 +1238,17 @@ class Notice extends Managed_DataObject */ function hasConversation() { - if (!empty($this->conversation)) { - $conversation = Notice::conversationStream( - $this->conversation, - 1, - 1 - ); - - if ($conversation->N > 0) { - return true; - } + if (empty($this->conversation)) { + // this notice is not part of a conversation apparently + // FIXME: all notices should have a conversation value, right? + return false; } - return false; + + $stream = new ConversationNoticeStream($this->conversation); + $notice = $stream->getNotices(/*offset*/ 1, /*limit*/ 1); + + // if our "offset 1, limit 1" query got a result, return true else false + return $notice->N > 0; } /** @@ -1271,8 +1283,7 @@ class Notice extends Managed_DataObject $root = new Notice; $root->conversation = $this->conversation; $root->orderBy('notice.created ASC'); - $root->find(); - $root->fetch(); + $root->find(true); // true means "fetch first result" $root->free(); return $root; } @@ -1660,32 +1671,22 @@ class Notice extends Managed_DataObject protected $_replies = array(); /** - * Pull the complete list of @-reply targets for this notice. + * Pull the complete list of @-mentioned profile IDs for this notice. * * @return array of integer profile ids */ function getReplies() { - if (isset($this->_replies[$this->id])) { - return $this->_replies[$this->id]; + if (!isset($this->_replies[$this->getID()])) { + $mentions = Reply::multiGet('notice_id', array($this->getID())); + $this->_replies[$this->getID()] = $mentions->fetchAll('profile_id'); } - - $replyMap = Reply::listGet('notice_id', array($this->id)); - - $ids = array(); - - foreach ($replyMap[$this->id] as $reply) { - $ids[] = $reply->profile_id; - } - - $this->_replies[$this->id] = $ids; - - return $ids; + return $this->_replies[$this->getID()]; } function _setReplies($replies) { - $this->_replies[$this->id] = $replies; + $this->_replies[$this->getID()] = $replies; } /** @@ -1844,7 +1845,11 @@ class Notice extends Managed_DataObject // This is not a reply to something } - $ctx->location = $this->getLocation(); + try { + $ctx->location = Notice_location::locFromStored($this); + } catch (ServerException $e) { + $ctx->location = null; + } $conv = null; @@ -2090,23 +2095,6 @@ class Notice extends Managed_DataObject return ($contentlimit > 0 && !empty($content) && (mb_strlen($content) > $contentlimit)); } - function getLocation() - { - $location = null; - - if (!empty($this->location_id) && !empty($this->location_ns)) { - $location = Location::fromId($this->location_id, $this->location_ns); - } - - if (is_null($location)) { // no ID, or Location::fromId() failed - if (!empty($this->lat) && !empty($this->lon)) { - $location = Location::fromLatLon($this->lat, $this->lon); - } - } - - return $location; - } - /** * Convenience function for posting a repeat of an existing message. * @@ -2193,7 +2181,7 @@ class Notice extends Managed_DataObject return $notice->fetchAll('id'); } - function locationOptions($lat, $lon, $location_id, $location_ns, $profile = null) + static function locationOptions($lat, $lon, $location_id, $location_ns, $profile = null) { $options = array(); @@ -2277,6 +2265,16 @@ class Notice extends Managed_DataObject $reply->free(); } + function clearLocation() + { + $loc = new Notice_location(); + $loc->notice_id = $this->id; + + if ($loc->find()) { + $loc->delete(); + } + } + function clearFiles() { $f2p = new File_to_post(); @@ -2885,4 +2883,51 @@ class Notice extends Managed_DataObject $notice->_setReplies($ids); } } + + static public function beforeSchemaUpdate() + { + $table = strtolower(get_called_class()); + $schema = Schema::get(); + $schemadef = $schema->getTableDef($table); + + // 2015-09-04 We move Notice location data to Notice_location + // First we see if we have to do this at all + if (!isset($schemadef['fields']['lat']) + && !isset($schemadef['fields']['lon']) + && !isset($schemadef['fields']['location_id']) + && !isset($schemadef['fields']['location_ns'])) { + // We have already removed the location fields, so no need to migrate. + return; + } + // Then we make sure the Notice_location table is created! + $schema->ensureTable('notice_location', Notice_location::schemaDef()); + + // Then we continue on our road to migration! + echo "\nFound old $table table, moving location data to 'notice_location' table... (this will probably take a LONG time, but can be aborted and continued)"; + + $notice = new Notice(); + $notice->query(sprintf('SELECT id, lat, lon, location_id, location_ns FROM %1$s ' . + 'WHERE lat IS NOT NULL ' . + 'OR lon IS NOT NULL ' . + 'OR location_id IS NOT NULL ' . + 'OR location_ns IS NOT NULL', + $schema->quoteIdentifier($table))); + print "\nFound {$notice->N} notices with location data, inserting"; + while ($notice->fetch()) { + $notloc = Notice_location::getKV('notice_id', $notice->id); + if ($notloc instanceof Notice_location) { + print "-"; + continue; + } + $notloc = new Notice_location(); + $notloc->notice_id = $notice->id; + $notloc->lat= $notice->lat; + $notloc->lon= $notice->lon; + $notloc->location_id= $notice->location_id; + $notloc->location_ns= $notice->location_ns; + $notloc->insert(); + print "."; + } + print "\n"; + } } diff --git a/classes/Notice_location.php b/classes/Notice_location.php new file mode 100644 index 0000000000..1574414e11 --- /dev/null +++ b/classes/Notice_location.php @@ -0,0 +1,75 @@ + array( + 'notice_id' => array('type' => 'int', 'not null' => true, 'description' => 'notice that is the reply'), + 'lat' => array('type' => 'numeric', 'precision' => 10, 'scale' => 7, 'description' => 'latitude'), + 'lon' => array('type' => 'numeric', 'precision' => 10, 'scale' => 7, 'description' => 'longitude'), + 'location_id' => array('type' => 'int', 'description' => 'location id if possible'), + 'location_ns' => array('type' => 'int', 'description' => 'namespace for location'), + 'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'), + ), + 'primary key' => array('notice_id'), + 'foreign keys' => array( + 'notice_location_notice_id_fkey' => array('notice', array('notice_id' => 'id')), + ), + 'indexes' => array( + 'notice_location_location_id_idx' => array('location_id'), + ), + ); + } + + static function locFromStored(Notice $stored) + { + $loc = new Notice_location(); + $loc->notice_id = $stored->getID(); + if (!$loc->find(true)) { + throw new NoResultException($loc); + } + return $loc->asLocation(); + } + + static function fromLocation(Location $location) + { + $notloc = new Notice_location(); + $notloc->lat = $location->lat; + $notloc->lon = $location->lon; + $notloc->location_ns = $location->location_ns; + $notloc->location_id = $location->location_id; + return $notloc; + } + + public function asLocation() + { + $location = null; + + if (!empty($this->location_id) && !empty($this->location_ns)) { + $location = Location::fromId($this->location_id, $this->location_ns); + } + + if (is_null($location)) { // no ID, or Location::fromId() failed + $location = Location::fromLatLon($this->lat, $this->lon); + } + + if (is_null($location)) { + throw new ServerException('Location could not be looked up from existing data.'); + } + + return $location; + } +} diff --git a/classes/Profile.php b/classes/Profile.php index b5ba00caa9..09f9ca71d1 100644 --- a/classes/Profile.php +++ b/classes/Profile.php @@ -138,6 +138,18 @@ class Profile extends Managed_DataObject return true; } + // Returns false if the user has no password (which will always + // be the case for remote users). This can be the case for OpenID + // logins or other mechanisms which don't store a password hash. + public function hasPassword() + { + try { + return !empty($this->getUser()->hasPassword()); + } catch (NoSuchUserException $e) { + return false; + } + } + public function getObjectType() { // FIXME: More types... like peopletags and whatever @@ -242,6 +254,11 @@ class Profile extends Managed_DataObject return null; } + function getReplies($offset=0, $limit=NOTICES_PER_PAGE, $since_id=0, $before_id=0) + { + return Reply::stream($this->getID(), $offset, $limit, $since_id, $before_id); + } + function getTaggedNotices($tag, $offset=0, $limit=NOTICES_PER_PAGE, $since_id=0, $max_id=0) { $stream = new TaggedProfileNoticeStream($this, $tag); @@ -860,6 +877,11 @@ class Profile extends Managed_DataObject function delete($useWhere=false) { + // just in case it hadn't been done before... (usually set before adding deluser to queue handling!) + if (!$this->hasRole(Profile_role::DELETED)) { + $this->grantRole(Profile_role::DELETED); + } + $this->_deleteNotices(); $this->_deleteSubscriptions(); $this->_deleteTags(); @@ -1390,6 +1412,11 @@ class Profile extends Managed_DataObject return $this->fullname; } + public function getHomepage() + { + return $this->homepage; + } + public function getDescription() { return $this->bio; @@ -1566,6 +1593,11 @@ class Profile extends Managed_DataObject return $this; } + public function sameAs(Profile $other) + { + return $this->getID() === $other->getID(); + } + /** * This will perform shortenLinks with the connected User object. * @@ -1613,4 +1645,9 @@ class Profile extends Managed_DataObject public function setPref($namespace, $topic, $data) { return Profile_prefs::setData($this, $namespace, $topic, $data); } + + public function getConnectedApps($offset=0, $limit=null) + { + return $this->getUser()->getConnectedApps($offset, $limit); + } } diff --git a/classes/Profile_tag.php b/classes/Profile_tag.php index 6d6f49bedc..8034e68ccf 100644 --- a/classes/Profile_tag.php +++ b/classes/Profile_tag.php @@ -2,22 +2,15 @@ /** * Table Definition for profile_tag */ -require_once INSTALLDIR.'/classes/Memcached_DataObject.php'; class Profile_tag extends Managed_DataObject { - ###START_AUTOCODE - /* the code below is auto generated do not remove the above tag */ - public $__table = 'profile_tag'; // table name public $tagger; // int(4) primary_key not_null public $tagged; // int(4) primary_key not_null public $tag; // varchar(64) primary_key not_null public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP - /* the code above is auto generated do not remove the tag below */ - ###END_AUTOCODE - public static function schemaDef() { return array( @@ -52,6 +45,16 @@ class Profile_tag extends Managed_DataObject return Profile_list::pkeyGet(array('tagger' => $this->tagger, 'tag' => $this->tag)); } + static function getSelfTagsArray(Profile $target) + { + return self::getTagsArray($target->getID(), $target->getID(), $target); + } + + static function setSelfTags(Profile $target, array $newtags, array $privacy=array()) + { + return self::setTags($target->getID(), $target->getID(), $newtags, $privacy); + } + static function getTags($tagger, $tagged, $auth_user=null) { $profile_list = new Profile_list(); @@ -88,7 +91,7 @@ class Profile_tag extends Managed_DataObject return $profile_list; } - static function getTagsArray($tagger, $tagged, $auth_user_id=null) + static function getTagsArray($tagger, $tagged, Profile $scoped=null) { $ptag = new Profile_tag(); @@ -100,7 +103,7 @@ class Profile_tag extends Managed_DataObject 'and profile_tag.tagged = %d ', $tagger, $tagged); - if ($auth_user_id != $tagger) { + if (!$scoped instanceof Profile || $scoped->getID() !== $tagger) { $qry .= 'and profile_list.private = 0'; } @@ -115,10 +118,10 @@ class Profile_tag extends Managed_DataObject return $tags; } - static function setTags($tagger, $tagged, $newtags, $privacy=array()) { + static function setTags($tagger, $tagged, array $newtags, array $privacy=array()) { $newtags = array_unique($newtags); - $oldtags = self::getTagsArray($tagger, $tagged, $tagger); + $oldtags = self::getTagsArray($tagger, $tagged, Profile::getByID($tagger)); $ptag = new Profile_tag(); @@ -149,19 +152,18 @@ class Profile_tag extends Managed_DataObject 'tag' => $tag)); # if tag already exists, return it - if(!empty($ptag)) { + if ($ptag instanceof Profile_tag) { return $ptag; } - $tagger_profile = Profile::getKV('id', $tagger); - $tagged_profile = Profile::getKV('id', $tagged); + $tagger_profile = Profile::getByID($tagger); + $tagged_profile = Profile::getByID($tagged); if (Event::handle('StartTagProfile', array($tagger_profile, $tagged_profile, $tag))) { if (!$tagger_profile->canTag($tagged_profile)) { // TRANS: Client exception thrown trying to set a tag for a user that cannot be tagged. throw new ClientException(_('You cannot tag this user.')); - return false; } $tags = new Profile_list(); @@ -174,7 +176,6 @@ class Profile_tag extends Managed_DataObject 'which is the maximum allowed number of tags. ' . 'Try using or deleting some existing tags.'), common_config('peopletag', 'maxtags'))); - return false; } $plist = new Profile_list(); @@ -188,7 +189,6 @@ class Profile_tag extends Managed_DataObject 'which is the maximum allowed number. ' . 'Try unlisting others first.'), common_config('peopletag', 'maxpeople'), $tag)); - return false; } $newtag = new Profile_tag(); @@ -199,9 +199,9 @@ class Profile_tag extends Managed_DataObject $result = $newtag->insert(); - if (!$result) { common_log_db_error($newtag, 'INSERT', __FILE__); + $plist->query('ROLLBACK'); return false; } @@ -212,7 +212,6 @@ class Profile_tag extends Managed_DataObject $newtag->delete(); $profile_list->delete(); throw $e; - return false; } $profile_list->taggedCount(true); @@ -233,20 +232,17 @@ class Profile_tag extends Managed_DataObject if (Event::handle('StartUntagProfile', array($ptag))) { $orig = clone($ptag); $result = $ptag->delete(); - if (!$result) { + if ($result === false) { common_log_db_error($this, 'DELETE', __FILE__); return false; } Event::handle('EndUntagProfile', array($orig)); - if ($result) { - $profile_list = Profile_list::pkeyGet(array('tag' => $tag, 'tagger' => $tagger)); - if (!empty($profile_list)) { - $profile_list->taggedCount(true); - } - self::blowCaches($tagger, $tagged); - return true; + $profile_list = Profile_list::pkeyGet(array('tag' => $tag, 'tagger' => $tagger)); + if (!empty($profile_list)) { + $profile_list->taggedCount(true); } - return false; + self::blowCaches($tagger, $tagged); + return true; } } diff --git a/classes/Queue_item.php b/classes/Queue_item.php index 3a7d05adef..d41c53e0e0 100644 --- a/classes/Queue_item.php +++ b/classes/Queue_item.php @@ -40,7 +40,7 @@ class Queue_item extends Managed_DataObject * @param mixed $transports name of a single queue or array of queues to pull from * If not specified, checks all queues in the system. */ - static function top($transports=null) { + static function top($transports=null, array $ignored_transports=array()) { $qi = new Queue_item(); if ($transports) { @@ -52,6 +52,11 @@ class Queue_item extends Managed_DataObject $qi->transport = $transports; } } + if (!empty($ignored_transports)) { + // @fixme use safer escaping + $list = implode("','", array_map(array($qi, 'escape'), $ignored_transports)); + $qi->whereAdd("transport NOT IN ('$list')"); + } $qi->orderBy('created'); $qi->whereAdd('claimed is null'); diff --git a/classes/Reply.php b/classes/Reply.php index 36686d0c76..d3405e6581 100644 --- a/classes/Reply.php +++ b/classes/Reply.php @@ -55,10 +55,9 @@ class Reply extends Managed_DataObject return $result; } - function stream($user_id, $offset=0, $limit=NOTICES_PER_PAGE, $since_id=0, $max_id=0) + static function stream($user_id, $offset=0, $limit=NOTICES_PER_PAGE, $since_id=0, $max_id=0) { $stream = new ReplyNoticeStream($user_id); - return $stream->getNotices($offset, $limit, $since_id, $max_id); } } diff --git a/classes/Subscription_queue.php b/classes/Subscription_queue.php index 878fcf5796..a60293e215 100644 --- a/classes/Subscription_queue.php +++ b/classes/Subscription_queue.php @@ -47,10 +47,10 @@ class Subscription_queue extends Managed_DataObject return $rq; } - public function exists(Profile $subscriber, Profile $other) + static function exists(Profile $subscriber, Profile $other) { - $sub = Subscription_queue::pkeyGet(array('subscriber' => $subscriber->id, - 'subscribed' => $other->id)); + $sub = Subscription_queue::pkeyGet(array('subscriber' => $subscriber->getID(), + 'subscribed' => $other->getID())); return ($sub instanceof Subscription_queue); } diff --git a/classes/User.php b/classes/User.php index 3efaa5e721..e33c83e89c 100644 --- a/classes/User.php +++ b/classes/User.php @@ -42,7 +42,6 @@ class User extends Managed_DataObject public $emailnotifynudge; // tinyint(1) default_1 public $emailnotifymsg; // tinyint(1) default_1 public $emailnotifyattn; // tinyint(1) default_1 - public $emailmicroid; // tinyint(1) default_1 public $language; // varchar(50) public $timezone; // varchar(50) public $emailpost; // tinyint(1) default_1 @@ -77,7 +76,6 @@ class User extends Managed_DataObject 'emailnotifynudge' => array('type' => 'int', 'size' => 'tiny', 'default' => 1, 'description' => 'Notify by email of nudges'), 'emailnotifymsg' => array('type' => 'int', 'size' => 'tiny', 'default' => 1, 'description' => 'Notify by email of direct messages'), 'emailnotifyattn' => array('type' => 'int', 'size' => 'tiny', 'default' => 1, 'description' => 'Notify by email of @-replies'), - 'emailmicroid' => array('type' => 'int', 'size' => 'tiny', 'default' => 1, 'description' => 'whether to publish email microid'), 'language' => array('type' => 'varchar', 'length' => 50, 'description' => 'preferred language'), 'timezone' => array('type' => 'varchar', 'length' => 50, 'description' => 'timezone'), 'emailpost' => array('type' => 'int', 'size' => 'tiny', 'default' => 1, 'description' => 'Post by email'), @@ -132,6 +130,11 @@ class User extends Managed_DataObject return $this->_profile[$this->id]; } + public function sameAs(Profile $other) + { + return $this->getProfile()->sameAs($other); + } + public function getUri() { return $this->uri; @@ -142,6 +145,16 @@ class User extends Managed_DataObject return $this->getProfile()->getNickname(); } + static function getByNickname($nickname) + { + $user = User::getKV('nickname', $nickname); + if (!$user instanceof User) { + throw new NoSuchUserException(array('nickname' => $nickname)); + } + + return $user; + } + function isSubscribed(Profile $other) { return $this->getProfile()->isSubscribed($other); @@ -261,9 +274,7 @@ class User extends Managed_DataObject $user->emailnotifynudge = 1; $user->emailnotifymsg = 1; $user->emailnotifyattn = 1; - $user->emailmicroid = 1; $user->emailpost = 1; - $user->jabbermicroid = 1; $user->created = common_sql_now(); @@ -288,7 +299,7 @@ class User extends Managed_DataObject } if (!empty($password)) { // may not have a password for OpenID users - $user->password = common_munge_password($password, $id); + $user->password = common_munge_password($password); } $result = $user->insert(); @@ -439,7 +450,7 @@ class User extends Managed_DataObject function getReplies($offset=0, $limit=NOTICES_PER_PAGE, $since_id=0, $before_id=0) { - return Reply::stream($this->id, $offset, $limit, $since_id, $before_id); + return $this->getProfile()->getReplies($offset, $limit, $since_id, $before_id); } function getTaggedNotices($tag, $offset=0, $limit=NOTICES_PER_PAGE, $since_id=0, $before_id=0) { @@ -451,16 +462,6 @@ class User extends Managed_DataObject return $this->getProfile()->getNotices($offset, $limit, $since_id, $before_id); } - function getSelfTags() - { - return Profile_tag::getTagsArray($this->id, $this->id, $this->id); - } - - function setSelfTags($newtags, $privacy) - { - return Profile_tag::setTags($this->id, $this->id, $newtags, $privacy); - } - function block(Profile $other) { // Add a new block record @@ -597,8 +598,10 @@ class User extends Managed_DataObject } try { - $profile = $this->getProfile(); - $profile->delete(); + if (!$this->hasRole(Profile_role::DELETED)) { + $profile = $this->getProfile(); + $profile->delete(); + } } catch (UserNoProfileException $unp) { common_log(LOG_INFO, "User {$this->nickname} has no profile; continuing deletion."); } @@ -1004,6 +1007,11 @@ class User extends Managed_DataObject return $this->getProfile()->isPrivateStream(); } + public function hasPassword() + { + return !empty($this->password); + } + public function delPref($namespace, $topic) { return $this->getProfile()->delPref($namespace, $topic); diff --git a/classes/User_im_prefs.php b/classes/User_im_prefs.php index 16fd030bb4..6a5fc7f3ab 100644 --- a/classes/User_im_prefs.php +++ b/classes/User_im_prefs.php @@ -40,7 +40,6 @@ class User_im_prefs extends Managed_DataObject public $transport; // varchar(191) not_null not 255 because utf8mb4 takes more space public $notify; // tinyint(1) public $replies; // tinyint(1) - public $microid; // tinyint(1) public $updatefrompresence; // tinyint(1) public $created; // datetime not_null default_0000-00-00%2000%3A00%3A00 public $modified; // timestamp not_null default_CURRENT_TIMESTAMP @@ -57,7 +56,6 @@ class User_im_prefs extends Managed_DataObject 'transport' => array('type' => 'varchar', 'length' => 191, 'not null' => true, 'description' => 'transport (ex xmpp, aim)'), 'notify' => array('type' => 'int', 'size' => 'tiny', 'not null' => true, 'default' => 0, 'description' => 'Notify when a new notice is sent'), 'replies' => array('type' => 'int', 'size' => 'tiny', 'not null' => true, 'default' => 0, 'description' => 'Send replies from people not subscribed to'), - 'microid' => array('type' => 'int', 'size' => 'tiny', 'not null' => true, 'default' => 1, 'description' => 'Publish a MicroID'), 'updatefrompresence' => array('type' => 'int', 'size' => 'tiny', 'not null' => true, 'default' => 0, 'description' => 'Send replies from people not subscribed to.'), 'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'), 'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'), diff --git a/db/core.php b/db/core.php index ec3fe7f736..d779717fd4 100644 --- a/db/core.php +++ b/db/core.php @@ -39,6 +39,7 @@ $classes = array('Schema_version', 'Subscription_queue', 'Oauth_token_association', 'Notice', + 'Notice_location', 'Notice_source', 'Reply', 'Consumer', diff --git a/extlib/Mail/mimeDecode.php b/extlib/Mail/mimeDecode.php index aaa870c509..a0d06942f4 100644 --- a/extlib/Mail/mimeDecode.php +++ b/extlib/Mail/mimeDecode.php @@ -52,7 +52,7 @@ * @author Sean Coates * @copyright 2003-2006 PEAR * @license http://www.opensource.org/licenses/bsd-license.php BSD License - * @version CVS: $Id: mimeDecode.php,v 1.48 2006/12/03 13:43:33 cipri Exp $ + * @version CVS: $Id: mimeDecode.php 305875 2010-12-01 07:17:10Z alan_k $ * @link http://pear.php.net/package/Mail_mime */ @@ -147,6 +147,15 @@ class Mail_mimeDecode extends PEAR */ var $_decode_headers; + /** + * Flag to determine whether to include attached messages + * as body in the returned object. Depends on $_include_bodies + * + * @var boolean + * @access private + */ + var $_rfc822_bodies; + /** * Constructor. * @@ -165,6 +174,7 @@ class Mail_mimeDecode extends PEAR $this->_body = $body; $this->_decode_bodies = false; $this->_include_bodies = true; + $this->_rfc822_bodies = false; } /** @@ -187,7 +197,7 @@ class Mail_mimeDecode extends PEAR function decode($params = null) { // determine if this method has been called statically - $isStatic = !(isset($this) && get_class($this) == __CLASS__); + $isStatic = empty($this) || !is_a($this, __CLASS__); // Have we been called statically? // If so, create an object and pass details to that. @@ -208,6 +218,8 @@ class Mail_mimeDecode extends PEAR $params['decode_bodies'] : false; $this->_decode_headers = isset($params['decode_headers']) ? $params['decode_headers'] : false; + $this->_rfc822_bodies = isset($params['rfc_822bodies']) ? + $params['rfc_822bodies'] : false; $structure = $this->_decode($this->_header, $this->_body); if ($structure === false) { @@ -235,6 +247,7 @@ class Mail_mimeDecode extends PEAR $headers = $this->_parseHeaders($headers); foreach ($headers as $value) { + $value['value'] = $this->_decode_headers ? $this->_decodeHeader($value['value']) : $value['value']; if (isset($return->headers[strtolower($value['name'])]) AND !is_array($return->headers[strtolower($value['name'])])) { $return->headers[strtolower($value['name'])] = array($return->headers[strtolower($value['name'])]); $return->headers[strtolower($value['name'])][] = $value['value']; @@ -247,8 +260,8 @@ class Mail_mimeDecode extends PEAR } } - reset($headers); - while (list($key, $value) = each($headers)) { + + foreach ($headers as $key => $value) { $headers[$key]['name'] = strtolower($headers[$key]['name']); switch ($headers[$key]['name']) { @@ -261,7 +274,7 @@ class Mail_mimeDecode extends PEAR } if (isset($content_type['other'])) { - while (list($p_name, $p_value) = each($content_type['other'])) { + foreach($content_type['other'] as $p_name => $p_value) { $return->ctype_parameters[$p_name] = $p_value; } } @@ -271,7 +284,7 @@ class Mail_mimeDecode extends PEAR $content_disposition = $this->_parseHeaderValue($headers[$key]['value']); $return->disposition = $content_disposition['value']; if (isset($content_disposition['other'])) { - while (list($p_name, $p_value) = each($content_disposition['other'])) { + foreach($content_disposition['other'] as $p_name => $p_value) { $return->d_parameters[$p_name] = $p_value; } } @@ -303,6 +316,7 @@ class Mail_mimeDecode extends PEAR case 'multipart/alternative': case 'multipart/related': case 'multipart/mixed': + case 'application/vnd.wap.multipart.related': if(!isset($content_type['other']['boundary'])){ $this->_error = 'No boundary found for ' . $content_type['value'] . ' part'; return false; @@ -321,7 +335,11 @@ class Mail_mimeDecode extends PEAR break; case 'message/rfc822': - $obj = &new Mail_mimeDecode($body); + if ($this->_rfc822_bodies) { + $encoding = isset($content_transfer_encoding) ? $content_transfer_encoding['value'] : '7bit'; + $return->body = ($this->_decode_bodies ? $this->_decodeBody($body, $encoding) : $body); + } + $obj = new Mail_mimeDecode($body); $return->parts[] = $obj->decode(array('include_bodies' => $this->_include_bodies, 'decode_bodies' => $this->_decode_bodies, 'decode_headers' => $this->_decode_headers)); @@ -401,6 +419,11 @@ class Mail_mimeDecode extends PEAR if (preg_match("/^(.*?)\r?\n\r?\n(.*)/s", $input, $match)) { return array($match[1], $match[2]); } + // bug #17325 - empty bodies are allowed. - we just check that at least one line + // of headers exist.. + if (count(explode("\n",$input))) { + return array($input, ''); + } $this->_error = 'Could not split header and body'; return false; } @@ -419,7 +442,12 @@ class Mail_mimeDecode extends PEAR if ($input !== '') { // Unfold the input $input = preg_replace("/\r?\n/", "\r\n", $input); + //#7065 - wrapping.. with encoded stuff.. - probably not needed, + // wrapping space should only get removed if the trailing item on previous line is a + // encoded character + $input = preg_replace("/=\r\n(\t| )+/", '=', $input); $input = preg_replace("/\r\n(\t| )+/", ' ', $input); + $headers = explode("\r\n", trim($input)); foreach ($headers as $value) { @@ -430,7 +458,7 @@ class Mail_mimeDecode extends PEAR $return[] = array( 'name' => $hdr_name, - 'value' => $this->_decode_headers ? $this->_decodeHeader($hdr_value) : $hdr_value + 'value' => $hdr_value ); } } else { @@ -454,41 +482,161 @@ class Mail_mimeDecode extends PEAR function _parseHeaderValue($input) { - if (($pos = strpos($input, ';')) !== false) { - - $return['value'] = trim(substr($input, 0, $pos)); - $input = trim(substr($input, $pos+1)); - - if (strlen($input) > 0) { - - // This splits on a semi-colon, if there's no preceeding backslash - // Now works with quoted values; had to glue the \; breaks in PHP - // the regex is already bordering on incomprehensible - $splitRegex = '/([^;\'"]*[\'"]([^\'"]*([^\'"]*)*)[\'"][^;\'"]*|([^;]+))(;|$)/'; - preg_match_all($splitRegex, $input, $matches); - $parameters = array(); - for ($i=0; $i_decode_headers ? $this->_decodeHeader($input) : $input; $return['value'] = trim($input); + return $return; } + + + $value = substr($input, 0, $pos); + $value = $this->_decode_headers ? $this->_decodeHeader($value) : $value; + $return['value'] = trim($value); + $input = trim(substr($input, $pos+1)); + + if (!strlen($input) > 0) { + return $return; + } + // at this point input contains xxxx=".....";zzzz="...." + // since we are dealing with quoted strings, we need to handle this properly.. + $i = 0; + $l = strlen($input); + $key = ''; + $val = false; // our string - including quotes.. + $q = false; // in quote.. + $lq = ''; // last quote.. + + while ($i < $l) { + + $c = $input[$i]; + //var_dump(array('i'=>$i,'c'=>$c,'q'=>$q, 'lq'=>$lq, 'key'=>$key, 'val' =>$val)); + + $escaped = false; + if ($c == '\\') { + $i++; + if ($i == $l-1) { // end of string. + break; + } + $escaped = true; + $c = $input[$i]; + } + + + // state - in key.. + if ($val === false) { + if (!$escaped && $c == '=') { + $val = ''; + $key = trim($key); + $i++; + continue; + } + if (!$escaped && $c == ';') { + if ($key) { // a key without a value.. + $key= trim($key); + $return['other'][$key] = ''; + $return['other'][strtolower($key)] = ''; + } + $key = ''; + } + $key .= $c; + $i++; + continue; + } + + // state - in value.. (as $val is set..) + + if ($q === false) { + // not in quote yet. + if ((!strlen($val) || $lq !== false) && $c == ' ' || $c == "\t") { + $i++; + continue; // skip leading spaces after '=' or after '"' + } + if (!$escaped && ($c == '"' || $c == "'")) { + // start quoted area.. + $q = $c; + // in theory should not happen raw text in value part.. + // but we will handle it as a merged part of the string.. + $val = !strlen(trim($val)) ? '' : trim($val); + $i++; + continue; + } + // got end.... + if (!$escaped && $c == ';') { + + $val = trim($val); + $added = false; + if (preg_match('/\*[0-9]+$/', $key)) { + // this is the extended aaa*0=...;aaa*1=.... code + // it assumes the pieces arrive in order, and are valid... + $key = preg_replace('/\*[0-9]+$/', '', $key); + if (isset($return['other'][$key])) { + $return['other'][$key] .= $val; + if (strtolower($key) != $key) { + $return['other'][strtolower($key)] .= $val; + } + $added = true; + } + // continue and use standard setters.. + } + if (!$added) { + $return['other'][$key] = $val; + $return['other'][strtolower($key)] = $val; + } + $val = false; + $key = ''; + $lq = false; + $i++; + continue; + } + + $val .= $c; + $i++; + continue; + } + + // state - in quote.. + if (!$escaped && $c == $q) { // potential exit state.. + + // end of quoted string.. + $lq = $q; + $q = false; + $i++; + continue; + } + + // normal char inside of quoted string.. + $val.= $c; + $i++; + } + + // do we have anything left.. + if (strlen(trim($key)) || $val !== false) { + + $val = trim($val); + $added = false; + if ($val !== false && preg_match('/\*[0-9]+$/', $key)) { + // no dupes due to our crazy regexp. + $key = preg_replace('/\*[0-9]+$/', '', $key); + if (isset($return['other'][$key])) { + $return['other'][$key] .= $val; + if (strtolower($key) != $key) { + $return['other'][strtolower($key)] .= $val; + } + $added = true; + } + // continue and use standard setters.. + } + if (!$added) { + $return['other'][$key] = $val; + $return['other'][strtolower($key)] = $val; + } + } + // decode values. + foreach($return['other'] as $key =>$val) { + $return['other'][$key] = $this->_decode_headers ? $this->_decodeHeader($val) : $val; + } + //print_r($return); return $return; } @@ -510,13 +658,19 @@ class Mail_mimeDecode extends PEAR if ($boundary == $bs_check) { $boundary = $bs_possible; } + $tmp = preg_split("/--".preg_quote($boundary, '/')."((?=\s)|--)/", $input); - $tmp = explode('--' . $boundary, $input); - - for ($i = 1; $i < count($tmp) - 1; $i++) { - $parts[] = $tmp[$i]; + $len = count($tmp) -1; + for ($i = 1; $i < $len; $i++) { + if (strlen(trim($tmp[$i]))) { + $parts[] = $tmp[$i]; + } + } + + // add the last part on if it does not end with the 'closing indicator' + if (!empty($tmp[$len]) && strlen(trim($tmp[$len])) && $tmp[$len][0] != '-') { + $parts[] = $tmp[$len]; } - return $parts; } @@ -719,7 +873,7 @@ class Mail_mimeDecode extends PEAR case "to": case "cc": case "bcc": - $to = ",".$item['value']; + $to .= ",".$item['value']; default: break; } diff --git a/extlib/Mf2/Parser.php b/extlib/Mf2/Parser.php index 27805f2324..b8a954f2c8 100644 --- a/extlib/Mf2/Parser.php +++ b/extlib/Mf2/Parser.php @@ -13,17 +13,17 @@ use stdClass; /** * Parse Microformats2 - * + * * Functional shortcut for the commonest cases of parsing microformats2 from HTML. - * + * * Example usage: - * + * * use Mf2; * $output = Mf2\parse('Barnaby Walters'); * echo json_encode($output, JSON_PRETTY_PRINT); - * + * * Produces: - * + * * { * "items": [ * { @@ -35,7 +35,7 @@ use stdClass; * ], * "rels": {} * } - * + * * @param string|DOMDocument $input The HTML string or DOMDocument object to parse * @param string $url The URL the input document was found at, for relative URL resolution * @param bool $convertClassic whether or not to convert classic microformats @@ -84,7 +84,7 @@ function fetch($url, $convertClassic = true, &$curlInfo=null) { /** * Unicode to HTML Entities * @param string $input String containing characters to convert into HTML entities - * @return string + * @return string */ function unicodeToHtmlEntities($input) { return mb_convert_encoding($input, 'HTML-ENTITIES', mb_detect_encoding($input)); @@ -92,10 +92,10 @@ function unicodeToHtmlEntities($input) { /** * Collapse Whitespace - * + * * Collapses any sequences of whitespace within a string into a single space * character. - * + * * @deprecated since v0.2.3 * @param string $str * @return string @@ -113,10 +113,10 @@ function unicodeTrim($str) { /** * Microformat Name From Class string - * - * Given the value of @class, get the relevant mf classnames (e.g. h-card, + * + * Given the value of @class, get the relevant mf classnames (e.g. h-card, * p-name). - * + * * @param string $class A space delimited list of classnames * @param string $prefix The prefix to look for * @return string|array The prefixed name of the first microfomats class found or false @@ -127,9 +127,9 @@ function mfNamesFromClass($class, $prefix='h-') { $matches = array(); foreach ($classes as $classname) { - $compare_classname = strtolower(' ' . $classname); - $compare_prefix = strtolower(' ' . $prefix); - if (stristr($compare_classname, $compare_prefix) !== false && ($compare_classname != $compare_prefix)) { + $compare_classname = ' ' . $classname; + $compare_prefix = ' ' . $prefix; + if (strstr($compare_classname, $compare_prefix) !== false && ($compare_classname != $compare_prefix)) { $matches[] = ($prefix === 'h-') ? $classname : substr($classname, strlen($prefix)); } } @@ -139,10 +139,10 @@ function mfNamesFromClass($class, $prefix='h-') { /** * Get Nested µf Property Name From Class - * - * Returns all the p-, u-, dt- or e- prefixed classnames it finds in a + * + * Returns all the p-, u-, dt- or e- prefixed classnames it finds in a * space-separated string. - * + * * @param string $class * @return array */ @@ -153,19 +153,24 @@ function nestedMfPropertyNamesFromClass($class) { $class = str_replace(array(' ', ' ', "\n"), ' ', $class); foreach (explode(' ', $class) as $classname) { foreach ($prefixes as $prefix) { - $compare_classname = strtolower(' ' . $classname); - if (stristr($compare_classname, $prefix) && ($compare_classname != $prefix)) { - $propertyNames = array_merge($propertyNames, mfNamesFromClass($classname, ltrim($prefix))); + // Check if $classname is a valid property classname for $prefix. + if (mb_substr($classname, 0, mb_strlen($prefix)) == $prefix && $classname != $prefix) { + $propertyName = mb_substr($classname, mb_strlen($prefix)); + $propertyNames[$propertyName][] = $prefix; } } } + + foreach ($propertyNames as $property => $prefixes) { + $propertyNames[$property] = array_unique($prefixes); + } return $propertyNames; } /** * Wraps mfNamesFromClass to handle an element as input (common) - * + * * @param DOMElement $e The element to get the classname for * @param string $prefix The prefix to look for * @return mixed See return value of mf2\Parser::mfNameFromClass() @@ -192,28 +197,27 @@ function convertTimeFormat($time) { $hh = $mm = $ss = ''; preg_match('/(\d{1,2}):?(\d{2})?:?(\d{2})?(a\.?m\.?|p\.?m\.?)?/i', $time, $matches); - // if no am/pm specified + // If no am/pm is specified: if (empty($matches[4])) { return $time; - } - // else am/pm specified - else { + } else { + // Otherwise, am/pm is specified. $meridiem = strtolower(str_replace('.', '', $matches[4])); - // hours + // Hours. $hh = $matches[1]; - // add 12 to the pm hours + // Add 12 to hours if pm applies. if ($meridiem == 'pm' && ($hh < 12)) { $hh += 12; } $hh = str_pad($hh, 2, '0', STR_PAD_LEFT); - // minutes + // Minutes. $mm = (empty($matches[2]) ) ? '00' : $matches[2]; - // seconds, only if supplied + // Seconds, only if supplied. if (!empty($matches[3])) { $ss = $matches[3]; } @@ -229,11 +233,11 @@ function convertTimeFormat($time) { /** * Microformats2 Parser - * + * * A class which holds state for parsing microformats2 from HTML. - * + * * Example usage: - * + * * use Mf2; * $parser = new Mf2\Parser('

Barnaby Walters

'); * $output = $parser->parse(); @@ -244,18 +248,18 @@ class Parser { /** @var DOMXPath object which can be used to query over any fragment*/ public $xpath; - + /** @var DOMDocument */ public $doc; - + /** @var SplObjectStorage */ protected $parsed; - + public $jsonMode; /** * Constructor - * + * * @param DOMDocument|string $input The data to parse. A string of HTML or a DOMDocument * @param string $url The URL of the parsed document, for relative URL resolution * @param boolean $jsonMode Whether or not to use a stdClass instance for an empty `rels` dictionary. This breaks PHP looping over rels, but allows the output to be correctly serialized as JSON. @@ -271,20 +275,20 @@ class Parser { $doc = new DOMDocument(); @$doc->loadHTML(''); } - + $this->xpath = new DOMXPath($doc); - + $baseurl = $url; foreach ($this->xpath->query('//base[@href]') as $base) { $baseElementUrl = $base->getAttribute('href'); - + if (parse_url($baseElementUrl, PHP_URL_SCHEME) === null) { /* The base element URL is relative to the document URL. * * :/ * * Perhaps the author was high? */ - + $baseurl = resolveUrl($url, $baseElementUrl); } else { $baseurl = $baseElementUrl; @@ -296,31 +300,31 @@ class Parser { foreach ($this->xpath->query('//template') as $templateEl) { $templateEl->parentNode->removeChild($templateEl); } - + $this->baseurl = $baseurl; $this->doc = $doc; $this->parsed = new SplObjectStorage(); $this->jsonMode = $jsonMode; } - + private function elementPrefixParsed(\DOMElement $e, $prefix) { if (!$this->parsed->contains($e)) $this->parsed->attach($e, array()); - + $prefixes = $this->parsed[$e]; $prefixes[] = $prefix; $this->parsed[$e] = $prefixes; } - + private function isElementParsed(\DOMElement $e, $prefix) { if (!$this->parsed->contains($e)) return false; - + $prefixes = $this->parsed[$e]; - + if (!in_array($prefix, $prefixes)) return false; - + return true; } @@ -352,72 +356,72 @@ class Parser { // TODO: figure out if this has problems with sms: and geo: URLs public function resolveUrl($url) { - // If the URL is seriously malformed it’s probably beyond the scope of this + // If the URL is seriously malformed it’s probably beyond the scope of this // parser to try to do anything with it. if (parse_url($url) === false) return $url; - + $scheme = parse_url($url, PHP_URL_SCHEME); - + if (empty($scheme) and !empty($this->baseurl)) { return resolveUrl($this->baseurl, $url); } else { return $url; } } - + // Parsing Functions - + /** - * Parse value-class/value-title on an element, joining with $separator if + * Parse value-class/value-title on an element, joining with $separator if * there are multiple. - * + * * @param \DOMElement $e * @param string $separator = '' if multiple value-title elements, join with this string * @return string|null the parsed value or null if value-class or -title aren’t in use */ public function parseValueClassTitle(\DOMElement $e, $separator = '') { $valueClassElements = $this->xpath->query('./*[contains(concat(" ", @class, " "), " value ")]', $e); - + if ($valueClassElements->length !== 0) { // Process value-class stuff $val = ''; foreach ($valueClassElements as $el) { $val .= $this->textContent($el); } - + return unicodeTrim($val); } - + $valueTitleElements = $this->xpath->query('./*[contains(concat(" ", @class, " "), " value-title ")]', $e); - + if ($valueTitleElements->length !== 0) { // Process value-title stuff $val = ''; foreach ($valueTitleElements as $el) { $val .= $el->getAttribute('title'); } - + return unicodeTrim($val); } - + // No value-title or -class in this element return null; } - + /** * Given an element with class="p-*", get it’s value - * + * * @param DOMElement $p The element to parse * @return string The plaintext value of $p, dependant on type * @todo Make this adhere to value-class */ public function parseP(\DOMElement $p) { $classTitle = $this->parseValueClassTitle($p, ' '); - + if ($classTitle !== null) return $classTitle; - + if ($p->tagName == 'img' and $p->getAttribute('alt') !== '') { $pValue = $p->getAttribute('alt'); } elseif ($p->tagName == 'area' and $p->getAttribute('alt') !== '') { @@ -429,13 +433,13 @@ class Parser { } else { $pValue = unicodeTrim($this->textContent($p)); } - + return $pValue; } /** * Given an element with class="u-*", get the value of the URL - * + * * @param DOMElement $u The element to parse * @return string The plaintext value of $u, dependant on type * @todo make this adhere to value-class @@ -443,18 +447,18 @@ class Parser { public function parseU(\DOMElement $u) { if (($u->tagName == 'a' or $u->tagName == 'area') and $u->getAttribute('href') !== null) { $uValue = $u->getAttribute('href'); - } elseif ($u->tagName == 'img' and $u->getAttribute('src') !== null) { + } elseif (in_array($u->tagName, array('img', 'audio', 'video', 'source')) and $u->getAttribute('src') !== null) { $uValue = $u->getAttribute('src'); } elseif ($u->tagName == 'object' and $u->getAttribute('data') !== null) { $uValue = $u->getAttribute('data'); } - + if (isset($uValue)) { return $this->resolveUrl($uValue); } - + $classTitle = $this->parseValueClassTitle($u); - + if ($classTitle !== null) { return $classTitle; } elseif ($u->tagName == 'abbr' and $u->getAttribute('title') !== null) { @@ -468,7 +472,7 @@ class Parser { /** * Given an element with class="dt-*", get the value of the datetime as a php date object - * + * * @param DOMElement $dt The element to parse * @param array $dates Array of dates processed so far * @return string The datetime string found @@ -477,11 +481,11 @@ class Parser { // Check for value-class pattern $valueClassChildren = $this->xpath->query('./*[contains(concat(" ", @class, " "), " value ") or contains(concat(" ", @class, " "), " value-title ")]', $dt); $dtValue = false; - + if ($valueClassChildren->length > 0) { // They’re using value-class $dateParts = array(); - + foreach ($valueClassChildren as $e) { if (strstr(' ' . $e->getAttribute('class') . ' ', ' value-title ')) { $title = $e->getAttribute('title'); @@ -591,16 +595,16 @@ class Parser { $dtValue = $dt->nodeValue; } - if ( preg_match('/(\d{4}-\d{2}-\d{2})/', $dtValue, $matches) ) { + if (preg_match('/(\d{4}-\d{2}-\d{2})/', $dtValue, $matches)) { $dates[] = $matches[0]; } } /** - * if $dtValue is only a time and there are recently parsed dates, - * form the full date-time using the most recnetly parsed dt- value + * if $dtValue is only a time and there are recently parsed dates, + * form the full date-time using the most recently parsed dt- value */ - if ( (preg_match('/^\d{1,2}:\d{1,2}(Z?[+|-]\d{2}:?\d{2})?/', $dtValue) or preg_match('/^\d{1,2}[a|p]m/', $dtValue)) && !empty($dates) ) { + if ((preg_match('/^\d{1,2}:\d{1,2}(Z?[+|-]\d{2}:?\d{2})?/', $dtValue) or preg_match('/^\d{1,2}[a|p]m/', $dtValue)) && !empty($dates)) { $dtValue = convertTimeFormat($dtValue); $dtValue = end($dates) . 'T' . unicodeTrim($dtValue, 'T'); } @@ -613,15 +617,15 @@ class Parser { * * @param DOMElement $e The element to parse * @return string $e’s innerHTML - * + * * @todo need to mark this element as e- parsed so it doesn’t get parsed as it’s parent’s e-* too */ public function parseE(\DOMElement $e) { $classTitle = $this->parseValueClassTitle($e); - + if ($classTitle !== null) return $classTitle; - + // Expand relative URLs within children of this element // TODO: as it is this is not relative to only children, make this .// and rerun tests $this->resolveChildUrls($e); @@ -630,7 +634,7 @@ class Parser { foreach ($e->childNodes as $node) { $html .= $node->C14N(); } - + return array( 'html' => $html, 'value' => unicodeTrim($this->textContent($e)) @@ -639,7 +643,7 @@ class Parser { /** * Recursively parse microformats - * + * * @param DOMElement $e The element to parse * @return array A representation of the values contained within microformat $e */ @@ -660,26 +664,39 @@ class Parser { foreach ($this->xpath->query('.//*[contains(concat(" ", @class)," h-")]', $e) as $subMF) { // Parse $result = $this->parseH($subMF); - + // If result was already parsed, skip it if (null === $result) continue; + // In most cases, the value attribute of the nested microformat should be the p- parsed value of the elemnt. + // The only times this is different is when the microformat is nested under certain prefixes, which are handled below. $result['value'] = $this->parseP($subMF); // Does this µf have any property names other than h-*? $properties = nestedMfPropertyNamesFromElement($subMF); - + if (!empty($properties)) { // Yes! It’s a nested property µf - foreach ($properties as $property) { - $return[$property][] = $result; + foreach ($properties as $property => $prefixes) { + // Note: handling microformat nesting under multiple conflicting prefixes is not currently specified by the mf2 parsing spec. + $prefixSpecificResult = $result; + if (in_array('p-', $prefixes)) { + $prefixSpecificResult['value'] = $prefixSpecificResult['properties']['name'][0]; + } elseif (in_array('e-', $prefixes)) { + $eParsedResult = $this->parseE($subMF); + $prefixSpecificResult['html'] = $eParsedResult['html']; + $prefixSpecificResult['value'] = $eParsedResult['value']; + } elseif (in_array('u-', $prefixes)) { + $prefixSpecificResult['value'] = $this->parseU($subMF); + } + $return[$property][] = $prefixSpecificResult; } } else { // No, it’s a child µf $children[] = $result; } - + // Make sure this sub-mf won’t get parsed as a µf or property // TODO: Determine if clearing this is required? $this->elementPrefixParsed($subMF, 'h'); @@ -689,19 +706,24 @@ class Parser { $this->elementPrefixParsed($subMF, 'e'); } + if($e->tagName == 'area') { + $coords = $e->getAttribute('coords'); + $shape = $e->getAttribute('shape'); + } + // Handle p-* foreach ($this->xpath->query('.//*[contains(concat(" ", @class) ," p-")]', $e) as $p) { if ($this->isElementParsed($p, 'p')) continue; $pValue = $this->parseP($p); - + // Add the value to the array for it’s p- properties foreach (mfNamesFromElement($p, 'p-') as $propName) { if (!empty($propName)) $return[$propName][] = $pValue; } - + // Make sure this sub-mf won’t get parsed as a top level mf $this->elementPrefixParsed($p, 'p'); } @@ -710,32 +732,32 @@ class Parser { foreach ($this->xpath->query('.//*[contains(concat(" ", @class)," u-")]', $e) as $u) { if ($this->isElementParsed($u, 'u')) continue; - + $uValue = $this->parseU($u); - + // Add the value to the array for it’s property types foreach (mfNamesFromElement($u, 'u-') as $propName) { $return[$propName][] = $uValue; } - + // Make sure this sub-mf won’t get parsed as a top level mf $this->elementPrefixParsed($u, 'u'); } - + // Handle dt-* foreach ($this->xpath->query('.//*[contains(concat(" ", @class), " dt-")]', $e) as $dt) { if ($this->isElementParsed($dt, 'dt')) continue; - + $dtValue = $this->parseDT($dt, $dates); - + if ($dtValue) { // Add the value to the array for dt- properties foreach (mfNamesFromElement($dt, 'dt-') as $propName) { $return[$propName][] = $dtValue; } } - + // Make sure this sub-mf won’t get parsed as a top level mf $this->elementPrefixParsed($dt, 'dt'); } @@ -762,22 +784,43 @@ class Parser { if (!array_key_exists('name', $return)) { try { // Look for img @alt - if ($e->tagName == 'img' and $e->getAttribute('alt') != '') + if (($e->tagName == 'img' or $e->tagName == 'area') and $e->getAttribute('alt') != '') throw new Exception($e->getAttribute('alt')); - + if ($e->tagName == 'abbr' and $e->hasAttribute('title')) throw new Exception($e->getAttribute('title')); - + // Look for nested img @alt foreach ($this->xpath->query('./img[count(preceding-sibling::*)+count(following-sibling::*)=0]', $e) as $em) { - if ($em->getAttribute('alt') != '') + $emNames = mfNamesFromElement($em, 'h-'); + if (empty($emNames) && $em->getAttribute('alt') != '') { throw new Exception($em->getAttribute('alt')); + } } + // Look for nested area @alt + foreach ($this->xpath->query('./area[count(preceding-sibling::*)+count(following-sibling::*)=0]', $e) as $em) { + $emNames = mfNamesFromElement($em, 'h-'); + if (empty($emNames) && $em->getAttribute('alt') != '') { + throw new Exception($em->getAttribute('alt')); + } + } + + // Look for double nested img @alt foreach ($this->xpath->query('./*[count(preceding-sibling::*)+count(following-sibling::*)=0]/img[count(preceding-sibling::*)+count(following-sibling::*)=0]', $e) as $em) { - if ($em->getAttribute('alt') != '') + $emNames = mfNamesFromElement($em, 'h-'); + if (empty($emNames) && $em->getAttribute('alt') != '') { throw new Exception($em->getAttribute('alt')); + } + } + + // Look for double nested img @alt + foreach ($this->xpath->query('./*[count(preceding-sibling::*)+count(following-sibling::*)=0]/area[count(preceding-sibling::*)+count(following-sibling::*)=0]', $e) as $em) { + $emNames = mfNamesFromElement($em, 'h-'); + if (empty($emNames) && $em->getAttribute('alt') != '') { + throw new Exception($em->getAttribute('alt')); + } } throw new Exception($e->nodeValue); @@ -812,36 +855,58 @@ class Parser { // Check for u-url if (!array_key_exists('url', $return)) { // Look for img @src - if ($e->tagName == 'a') + if ($e->tagName == 'a' or $e->tagName == 'area') $url = $e->getAttribute('href'); - - // Look for nested img @src + + // Look for nested a @href foreach ($this->xpath->query('./a[count(preceding-sibling::a)+count(following-sibling::a)=0]', $e) as $em) { - $url = $em->getAttribute('href'); - break; + $emNames = mfNamesFromElement($em, 'h-'); + if (empty($emNames)) { + $url = $em->getAttribute('href'); + break; + } } - + + // Look for nested area @src + foreach ($this->xpath->query('./area[count(preceding-sibling::area)+count(following-sibling::area)=0]', $e) as $em) { + $emNames = mfNamesFromElement($em, 'h-'); + if (empty($emNames)) { + $url = $em->getAttribute('href'); + break; + } + } + if (!empty($url)) $return['url'][] = $this->resolveUrl($url); } // Make sure things are in alphabetical order sort($mfTypes); - + // Phew. Return the final result. $parsed = array( 'type' => $mfTypes, 'properties' => $return ); - if (!empty($children)) + + if (!empty($shape)) { + $parsed['shape'] = $shape; + } + + if (!empty($coords)) { + $parsed['coords'] = $coords; + } + + if (!empty($children)) { $parsed['children'] = array_values(array_filter($children)); + } return $parsed; } - + /** * Parse Rels and Alternatives - * - * Returns [$rels, $alternatives]. If the $rels value is to be empty, i.e. there are no links on the page + * + * Returns [$rels, $alternatives]. If the $rels value is to be empty, i.e. there are no links on the page * with a rel value *not* containing `alternate`, then the type of $rels depends on $this->jsonMode. If set * to true, it will be a stdClass instance, optimising for JSON serialisation. Otherwise (the default case), * it will be an empty array. @@ -849,18 +914,18 @@ class Parser { public function parseRelsAndAlternates() { $rels = array(); $alternates = array(); - + // Iterate through all a, area and link elements with rel attributes foreach ($this->xpath->query('//*[@rel and @href]') as $hyperlink) { if ($hyperlink->getAttribute('rel') == '') continue; - + // Resolve the href $href = $this->resolveUrl($hyperlink->getAttribute('href')); - + // Split up the rel into space-separated values $linkRels = array_filter(explode(' ', $hyperlink->getAttribute('rel'))); - + // If alternate in rels, create alternate structure, append if (in_array('alternate', $linkRels)) { $alt = array( @@ -869,10 +934,19 @@ class Parser { ); if ($hyperlink->hasAttribute('media')) $alt['media'] = $hyperlink->getAttribute('media'); - + if ($hyperlink->hasAttribute('hreflang')) $alt['hreflang'] = $hyperlink->getAttribute('hreflang'); - + + if ($hyperlink->hasAttribute('title')) + $alt['title'] = $hyperlink->getAttribute('title'); + + if ($hyperlink->hasAttribute('type')) + $alt['type'] = $hyperlink->getAttribute('type'); + + if ($hyperlink->nodeValue) + $alt['text'] = $hyperlink->nodeValue; + $alternates[] = $alt; } else { foreach ($linkRels as $rel) { @@ -880,38 +954,38 @@ class Parser { } } } - + if (empty($rels) and $this->jsonMode) { $rels = new stdClass(); } - + return array($rels, $alternates); } - + /** * Kicks off the parsing routine - * + * * If `$htmlSafe` is set, any angle brackets in the results from non e-* properties * will be HTML-encoded, bringing all output to the same level of encoding. - * + * * If a DOMElement is set as the $context, only descendants of that element will * be parsed for microformats. - * + * * @param bool $htmlSafe whether or not to html-encode non e-* properties. Defaults to false * @param DOMElement $context optionally an element from which to parse microformats * @return array An array containing all the µfs found in the current document */ public function parse($convertClassic = true, DOMElement $context = null) { $mfs = array(); - + if ($convertClassic) { $this->convertLegacy(); } - + $mfElements = null === $context ? $this->xpath->query('//*[contains(concat(" ", @class), " h-")]') : $this->xpath->query('.//*[contains(concat(" ", @class), " h-")]', $context); - + // Parser microformats foreach ($mfElements as $node) { // For each microformat @@ -920,64 +994,64 @@ class Parser { // Add the value to the array for this property type $mfs[] = $result; } - + // Parse rels list($rels, $alternates) = $this->parseRelsAndAlternates(); - + $top = array( 'items' => array_values(array_filter($mfs)), 'rels' => $rels ); - + if (count($alternates)) $top['alternates'] = $alternates; - + return $top; } - + /** * Parse From ID - * + * * Given an ID, parse all microformats which are children of the element with * that ID. - * + * * Note that rel values are still document-wide. - * - * If an element with the ID is not found, an empty skeleton mf2 array structure + * + * If an element with the ID is not found, an empty skeleton mf2 array structure * will be returned. - * + * * @param string $id * @param bool $htmlSafe = false whether or not to HTML-encode angle brackets in non e-* properties * @return array */ public function parseFromId($id, $convertClassic=true) { $matches = $this->xpath->query("//*[@id='{$id}']"); - + if (empty($matches)) return array('items' => array(), 'rels' => array(), 'alternates' => array()); - + return $this->parse($convertClassic, $matches->item(0)); } /** * Convert Legacy Classnames - * + * * Adds microformats2 classnames into a document containing only legacy * semantic classnames. - * + * * @return Parser $this */ public function convertLegacy() { $doc = $this->doc; $xp = new DOMXPath($doc); - + // replace all roots foreach ($this->classicRootMap as $old => $new) { foreach ($xp->query('//*[contains(concat(" ", @class, " "), " ' . $old . ' ") and not(contains(concat(" ", @class, " "), " ' . $new . ' "))]') as $el) { $el->setAttribute('class', $el->getAttribute('class') . ' ' . $new); } } - + foreach ($this->classicPropertyMap as $oldRoot => $properties) { $newRoot = $this->classicRootMap[$oldRoot]; foreach ($properties as $old => $new) { @@ -986,16 +1060,16 @@ class Parser { } } } - + return $this; } - + /** * XPath Query - * + * * Runs an XPath query over the current document. Works in exactly the same * way as DOMXPath::query. - * + * * @param string $expression * @param DOMNode $context * @return DOMNodeList @@ -1003,7 +1077,7 @@ class Parser { public function query($expression, $context = null) { return $this->xpath->query($expression, $context); } - + /** * Classic Root Classname map */ @@ -1013,11 +1087,11 @@ class Parser { 'hentry' => 'h-entry', 'hrecipe' => 'h-recipe', 'hresume' => 'h-resume', - 'hevent' => 'h-event', + 'vevent' => 'h-event', 'hreview' => 'h-review', 'hproduct' => 'h-product' ); - + public $classicPropertyMap = array( 'vcard' => array( 'fn' => 'p-name', @@ -1084,7 +1158,7 @@ class Parser { 'skill' => 'p-skill', 'affiliation' => 'p-affiliation h-card', ), - 'hevent' => array( + 'vevent' => array( 'dtstart' => 'dt-start', 'dtend' => 'dt-end', 'duration' => 'dt-duration', @@ -1246,7 +1320,7 @@ function resolveUrl($baseURI, $referenceURI) { # 5.2.3 Merge Paths function mergePaths($base, $reference) { # If the base URI has a defined authority component and an empty - # path, + # path, if($base['authority'] && $base['path'] == null) { # then return a string consisting of "/" concatenated with the # reference's path; otherwise, diff --git a/extlib/get_temp_dir.php b/extlib/get_temp_dir.php deleted file mode 100644 index 4ec96e5221..0000000000 --- a/extlib/get_temp_dir.php +++ /dev/null @@ -1,14 +0,0 @@ - diff --git a/file/.gitignore b/file/.gitignore deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/js/util.js b/js/util.js index b0274a91ba..cd982bbb17 100644 --- a/js/util.js +++ b/js/util.js @@ -1081,12 +1081,12 @@ var SN = { // StatusNet label.attr('title', label.text()); check.change(function () { - if (check.prop('checked') === true || $.cookie(SN.C.S.NoticeDataGeoCookie) === null) { + if (check.prop('checked') === true || $.cookie(SN.C.S.NoticeDataGeoCookie) === undefined) { label .attr('title', NoticeDataGeo_text.ShareDisable) .addClass('checked'); - if ($.cookie(SN.C.S.NoticeDataGeoCookie) === null || $.cookie(SN.C.S.NoticeDataGeoCookie) == 'disabled') { + if ($.cookie(SN.C.S.NoticeDataGeoCookie) === undefined || $.cookie(SN.C.S.NoticeDataGeoCookie) == 'disabled') { if (navigator.geolocation) { SN.U.NoticeGeoStatus(form, 'Requesting location from browser...'); navigator.geolocation.getCurrentPosition( @@ -1297,7 +1297,7 @@ var SN = { // StatusNet * @fixme what is this? */ Delete: function () { - $.cookie(SN.C.S.StatusNetInstance, null); + $.removeCookie(SN.C.S.StatusNetInstance); } }, diff --git a/lib/action.php b/lib/action.php index 29fadbf883..7f3aea9c1a 100644 --- a/lib/action.php +++ b/lib/action.php @@ -205,7 +205,7 @@ class Action extends HTMLOutputter // lawsuit * * @return nothing */ - function showPage() + public function showPage() { if (GNUsocial::isAjax()) { self::showAjax(); diff --git a/lib/activityutils.php b/lib/activityutils.php index d4c01232ec..f3383efda5 100644 --- a/lib/activityutils.php +++ b/lib/activityutils.php @@ -281,19 +281,20 @@ class ActivityUtils static function validateUri($uri) { // Check mailto: URIs first + $validate = new Validate(); if (preg_match('/^mailto:(.*)$/', $uri, $match)) { - return Validate::email($match[1], common_config('email', 'check_domain')); + return $validate->email($match[1], common_config('email', 'check_domain')); } - if (Validate::uri($uri)) { + if ($validate->uri($uri)) { return true; } // Possibly an upstream bug; tag: URIs aren't validated properly // unless you explicitly ask for them. All other schemes are accepted // for basic URI validation without asking. - if (Validate::uri($uri, array('allowed_scheme' => array('tag')))) { + if ($validate->uri($uri, array('allowed_scheme' => array('tag')))) { return true; } diff --git a/lib/apiaction.php b/lib/apiaction.php index 724447f120..fae8f33d0e 100644 --- a/lib/apiaction.php +++ b/lib/apiaction.php @@ -248,7 +248,7 @@ class ApiAction extends Action $twitter_user['friends_count'] = $profile->subscriptionCount(); - $twitter_user['created_at'] = $this->dateTwitter($profile->created); + $twitter_user['created_at'] = self::dateTwitter($profile->created); $timezone = 'UTC'; @@ -322,7 +322,7 @@ class ApiAction extends Action $twitter_status = array(); $twitter_status['text'] = $notice->content; $twitter_status['truncated'] = false; # Not possible on StatusNet - $twitter_status['created_at'] = $this->dateTwitter($notice->created); + $twitter_status['created_at'] = self::dateTwitter($notice->created); try { // We could just do $notice->reply_to but maybe the future holds a // different story for parenting. @@ -366,12 +366,13 @@ class ApiAction extends Action $twitter_status['in_reply_to_screen_name'] = ($replier_profile) ? $replier_profile->nickname : null; - if (isset($notice->lat) && isset($notice->lon)) { + try { + $notloc = Notice_location::locFromStored($notice); // This is the format that GeoJSON expects stuff to be in $twitter_status['geo'] = array('type' => 'Point', - 'coordinates' => array((float) $notice->lat, - (float) $notice->lon)); - } else { + 'coordinates' => array((float) $notloc->lat, + (float) $notloc->lon)); + } catch (ServerException $e) { $twitter_status['geo'] = null; } @@ -440,8 +441,8 @@ class ApiAction extends Action $twitter_group['homepage'] = $group->homepage; $twitter_group['description'] = $group->description; $twitter_group['location'] = $group->location; - $twitter_group['created'] = $this->dateTwitter($group->created); - $twitter_group['modified'] = $this->dateTwitter($group->modified); + $twitter_group['created'] = self::dateTwitter($group->created); + $twitter_group['modified'] = self::dateTwitter($group->modified); return $twitter_group; } @@ -547,13 +548,14 @@ class ApiAction extends Action $entry['pubDate'] = common_date_rfc2822($notice->created); $entry['guid'] = $entry['link']; - if (isset($notice->lat) && isset($notice->lon)) { + try { + $notloc = Notice_location::locFromStored($notice); // This is the format that GeoJSON expects stuff to be in. // showGeoRSS() below uses it for XML output, so we reuse it $entry['geo'] = array('type' => 'Point', - 'coordinates' => array((float) $notice->lat, - (float) $notice->lon)); - } else { + 'coordinates' => array((float) $notloc->lat, + (float) $notloc->lon)); + } catch (ServerException $e) { $entry['geo'] = null; } @@ -997,7 +999,13 @@ class ApiAction extends Action $statuses = array(); if (is_array($notice)) { - $notice = new ArrayWrapper($notice); + //FIXME: make everything calling showJsonTimeline use only Notice objects + common_debug('ArrayWrapper avoidance in progress! Beep boop, make showJsonTimeline only receive Notice objects!'); + $ids = array(); + foreach ($notice as $n) { + $ids[] = $n->getID(); + } + $notice = Notice::multiGet('id', $ids); } while ($notice->fetch()) { @@ -1196,7 +1204,7 @@ class ApiAction extends Action $this->endDocument('xml'); } - function dateTwitter($dt) + static function dateTwitter($dt) { $dateStr = date('d F Y H:i:s', strtotime($dt)); $d = new DateTime($dateStr, new DateTimeZone('UTC')); diff --git a/lib/apignusocialoauthdatastore.php b/lib/apignusocialoauthdatastore.php index da412df8d2..6f4403dec7 100644 --- a/lib/apignusocialoauthdatastore.php +++ b/lib/apignusocialoauthdatastore.php @@ -26,20 +26,20 @@ require_once 'OAuth.php'; */ class ApiGNUsocialOAuthDataStore extends OAuthDataStore { - function lookup_consumer($consumerKey) + function lookup_consumer($consumer_key) { - $con = Consumer::getKV('consumer_key', $consumerKey); + $con = Consumer::getKV('consumer_key', $consumer_key); if (!$con instanceof Consumer) { // Create an anon consumer and anon application if one // doesn't exist already - if ($consumerKey == 'anonymous') { + if ($consumer_key == 'anonymous') { common_debug("API OAuth - creating anonymous consumer"); $con = new Consumer(); - $con->consumer_key = $consumerKey; - $con->consumer_secret = $consumerKey; + $con->consumer_key = $consumer_key; + $con->consumer_secret = $consumer_key; $con->created = common_sql_now(); $result = $con->insert(); @@ -388,7 +388,7 @@ class ApiGNUsocialOAuthDataStore extends OAuthDataStore * * @return OAuthToken $token a new unauthorized OAuth request token */ - function new_request_token($consumer, $callback) + function new_request_token($consumer, $callback = null) { $t = new Token(); $t->consumer_key = $consumer->key; @@ -473,13 +473,13 @@ class ApiGNUsocialOAuthDataStore extends OAuthDataStore * @param type $token_key * @return OAuthToken */ - function lookup_token($consumer, $token_type, $token_key) + function lookup_token($consumer, $token_type, $token) { $t = new Token(); if (!is_null($consumer)) { $t->consumer_key = $consumer->key; } - $t->tok = $token_key; + $t->tok = $token; $t->type = ($token_type == 'access') ? 1 : 0; if ($t->find(true)) { return new OAuthToken($t->tok, $t->secret); diff --git a/lib/applicationlist.php b/lib/applicationlist.php index d0c9256df7..ab51a73096 100644 --- a/lib/applicationlist.php +++ b/lib/applicationlist.php @@ -27,13 +27,7 @@ * @link http://status.net/ */ -if (!defined('STATUSNET') && !defined('LACONICA')) { - exit(1); -} - -require_once INSTALLDIR . '/lib/widget.php'; - -define('APPS_PER_PAGE', 20); +if (!defined('GNUSOCIAL')) { exit(1); } /** * Widget to show a list of OAuth applications @@ -52,16 +46,12 @@ class ApplicationList extends Widget /** Owner of this list */ var $owner = null; - /** Action object using us. */ - var $action = null; - - function __construct($application, $owner=null, $action=null) + function __construct($application, Profile $owner, Action $out=null) { - parent::__construct($action); + parent::__construct($out); $this->application = $application; $this->owner = $owner; - $this->action = $action; } function show() @@ -75,7 +65,7 @@ class ApplicationList extends Widget if($cnt > APPS_PER_PAGE) { break; } - $this->showapplication(); + $this->showApplication(); } $this->out->elementEnd('ul'); @@ -85,8 +75,6 @@ class ApplicationList extends Widget function showApplication() { - $user = common_current_user(); - $this->out->elementStart('li', array('class' => 'application h-entry', 'id' => 'oauthclient-' . $this->application->id)); @@ -119,140 +107,3 @@ class ApplicationList extends Widget return; } } - -/** - * Widget to show a list of connected OAuth clients - * - * @category Application - * @package StatusNet - * @author Zach Copley - * @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::getKV('id', $this->connection->application_id); - - $this->out->elementStart('li', array('class' => 'application h-entry', - 'id' => 'oauthclient-' . $app->id)); - - $this->out->elementStart('a', array('href' => $app->source_url, - 'class' => 'h-card p-name')); - - if (!empty($app->icon)) { - $this->out->element('img', array('src' => $app->icon, - 'class' => 'avatar u-photo')); - } - if ($app->name != 'anonymous') { - $this->out->text($app->name); - } else { - // TRANS: Name for an anonymous application in application list. - $this->out->element('span', 'p-name', _('Unknown application')); - } - $this->out->elementEnd('a'); - - if ($app->name != 'anonymous') { - // @todo FIXME: i18n trouble. - // TRANS: Message has a leading space and a trailing space. Used in application list. - // TRANS: Before this message the application name is put, behind it the organisation that manages it. - $this->out->raw(_(' by ')); - - $this->out->element('a', array('href' => $app->homepage, - 'class' => 'h-card'), - $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); - - // @todo FIXME: i18n trouble. - $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 in application list to revoke access to user data. - $this->out->submit('revoke', _m('BUTTON','Revoke')); - $this->out->elementEnd('fieldset'); - $this->out->elementEnd('form'); - - $this->out->elementEnd('li'); - } -} diff --git a/lib/atomnoticefeed.php b/lib/atomnoticefeed.php index 292bc97e85..b7e1ed1b41 100644 --- a/lib/atomnoticefeed.php +++ b/lib/atomnoticefeed.php @@ -113,10 +113,12 @@ class AtomNoticeFeed extends Atom10Feed foreach ($notices as $notice) { $this->addEntryFromNotice($notice); } - } else { + } elseif ($notices instanceof Notice) { while ($notices->fetch()) { $this->addEntryFromNotice($notices); } + } else { + throw new ServerException('addEntryFromNotices got neither an array nor a Notice object'); } } @@ -125,7 +127,7 @@ class AtomNoticeFeed extends Atom10Feed * * @param Notice $notice a Notice to add */ - function addEntryFromNotice($notice) + function addEntryFromNotice(Notice $notice) { try { $source = $this->showSource(); diff --git a/lib/authenticationplugin.php b/lib/authenticationplugin.php index 66f11ca1a9..c33b0ef8a8 100644 --- a/lib/authenticationplugin.php +++ b/lib/authenticationplugin.php @@ -201,13 +201,13 @@ abstract class AuthenticationPlugin extends Plugin } } - function onStartChangePassword($user,$oldpassword,$newpassword) + function onStartChangePassword(Profile $target ,$oldpassword, $newpassword) { if($this->password_changeable){ $user_username = new User_username(); - $user_username->user_id=$user->id; + $user_username->user_id = $target->getID(); $user_username->provider_name=$this->provider_name; - if($user_username->find() && $user_username->fetch()){ + if ($user_username->find(true)) { $authenticated = $this->checkPassword($user_username->username, $oldpassword); if($authenticated){ $result = $this->changePassword($user_username->username,$oldpassword,$newpassword); diff --git a/lib/connectedappslist.php b/lib/connectedappslist.php new file mode 100644 index 0000000000..c2a27e75a8 --- /dev/null +++ b/lib/connectedappslist.php @@ -0,0 +1,163 @@ +. + * + * @category Application + * @package StatusNet + * @author Zach Copley + * @copyright 2008-2010 StatusNet, Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://status.net/ + */ + +if (!defined('GNUSOCIAL')) { exit(1); } + +/** + * Widget to show a list of connected OAuth clients + * + * @category Application + * @package StatusNet + * @author Zach Copley + * @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; + + function __construct($connection, Profile $owner, Action $out=null) + { + parent::__construct($out); + + common_debug("ConnectedAppsList constructor"); + + $this->connection = $connection; + $this->owner = $owner; + } + + /* 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::getKV('id', $this->connection->application_id); + + $this->out->elementStart('li', array('class' => 'application h-entry', + 'id' => 'oauthclient-' . $app->id)); + + $this->out->elementStart('a', array('href' => $app->source_url, + 'class' => 'h-card p-name')); + + if (!empty($app->icon)) { + $this->out->element('img', array('src' => $app->icon, + 'class' => 'avatar u-photo')); + } + if ($app->name != 'anonymous') { + $this->out->text($app->name); + } else { + // TRANS: Name for an anonymous application in application list. + $this->out->element('span', 'p-name', _('Unknown application')); + } + $this->out->elementEnd('a'); + + if ($app->name != 'anonymous') { + // @todo FIXME: i18n trouble. + // TRANS: Message has a leading space and a trailing space. Used in application list. + // TRANS: Before this message the application name is put, behind it the organisation that manages it. + $this->out->raw(_(' by ')); + + $this->out->element('a', array('href' => $app->homepage, + 'class' => 'h-card'), + $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); + + // @todo FIXME: i18n trouble. + $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 in application list to revoke access to user data. + $this->out->submit('revoke', _m('BUTTON','Revoke')); + $this->out->elementEnd('fieldset'); + $this->out->elementEnd('form'); + + $this->out->elementEnd('li'); + } +} diff --git a/lib/dbqueuemanager.php b/lib/dbqueuemanager.php index 45c4b694d2..9fb77eed96 100644 --- a/lib/dbqueuemanager.php +++ b/lib/dbqueuemanager.php @@ -72,7 +72,7 @@ class DBQueueManager extends QueueManager public function poll() { //$this->_log(LOG_DEBUG, 'Checking for notices...'); - $qi = Queue_item::top($this->activeQueues()); + $qi = Queue_item::top($this->activeQueues(), $this->getIgnoredTransports()); if (!$qi instanceof Queue_item) { //$this->_log(LOG_DEBUG, 'No notices waiting; idling.'); return false; diff --git a/lib/default.php b/lib/default.php index cf40f678ed..5bec29cc52 100644 --- a/lib/default.php +++ b/lib/default.php @@ -129,7 +129,7 @@ $default = 'biolimit' => null, 'changenick' => false, 'backup' => true, - 'restore' => true, + 'restore' => false, 'delete' => false, 'move' => true), 'image' => diff --git a/lib/deletenoticeform.php b/lib/deletenoticeform.php new file mode 100644 index 0000000000..d06004613a --- /dev/null +++ b/lib/deletenoticeform.php @@ -0,0 +1,67 @@ +notice = $formOpts['notice']; + } + + function id() + { + return 'form_notice_delete-' . $this->notice->getID(); + } + + function formClass() + { + return 'form_settings'; + } + + function action() + { + return common_local_url('deletenotice', array('notice' => $this->notice->getID())); + } + + function formLegend() + { + $this->out->element('legend', null, _('Delete notice')); + } + + function formData() + { + $this->out->element('p', null, _('Are you sure you want to delete this notice?')); + } + + /** + * Action elements + * + * @return void + */ + function formActions() + { + $this->out->submit('form_action-no', + // TRANS: Button label on the delete notice form. + _m('BUTTON','No'), + 'submit form_action-primary', + 'no', + // TRANS: Submit button title for 'No' when deleting a notice. + _('Do not delete this notice.')); + $this->out->submit('form_action-yes', + // TRANS: Button label on the delete notice form. + _m('BUTTON','Yes'), + 'submit form_action-secondary', + 'yes', + // TRANS: Submit button title for 'Yes' when deleting a notice. + _('Delete this notice.')); + } +} diff --git a/lib/deluserqueuehandler.php b/lib/deluserqueuehandler.php index 1baaf9331f..65866af418 100644 --- a/lib/deluserqueuehandler.php +++ b/lib/deluserqueuehandler.php @@ -74,8 +74,13 @@ class DelUserQueueHandler extends QueueHandler $qm = QueueManager::get(); $qm->enqueue($user, 'deluser'); } else { - // Out of notices? Let's finish deleting this guy! - $user->delete(); + // Out of notices? Let's finish deleting this profile! + try { + $user->getProfile()->delete(); + } catch (UserNoProfileException $e) { + // in case a profile didn't exist for some reason, just delete the User directly + $user->delete(); + } common_log(LOG_INFO, "User $user->id $user->nickname deleted."); return true; } diff --git a/lib/formaction.php b/lib/formaction.php index 5cf05d4a32..7d74fc4713 100644 --- a/lib/formaction.php +++ b/lib/formaction.php @@ -50,7 +50,7 @@ class FormAction extends ManagedAction protected function prepare(array $args=array()) { parent::prepare($args); - $this->form = $this->form ?: $this->action; + $this->form = $this->form ?: ucfirst($this->action); $this->args['form'] = $this->form; $this->type = !is_null($this->type) ? $this->type : $this->trimmed('type'); diff --git a/lib/framework.php b/lib/framework.php index da43297d10..d749d23bdf 100644 --- a/lib/framework.php +++ b/lib/framework.php @@ -23,7 +23,7 @@ define('GNUSOCIAL_ENGINE', 'GNU social'); define('GNUSOCIAL_ENGINE_URL', 'https://www.gnu.org/software/social/'); define('GNUSOCIAL_BASE_VERSION', '1.2.0'); -define('GNUSOCIAL_LIFECYCLE', 'alpha1'); // 'dev', 'alpha[0-9]+', 'beta[0-9]+', 'rc[0-9]+', 'release' +define('GNUSOCIAL_LIFECYCLE', 'alpha2'); // 'dev', 'alpha[0-9]+', 'beta[0-9]+', 'rc[0-9]+', 'release' define('GNUSOCIAL_VERSION', GNUSOCIAL_BASE_VERSION . '-' . GNUSOCIAL_LIFECYCLE); @@ -37,6 +37,7 @@ define('NOTICES_PER_PAGE', 20); define('PROFILES_PER_PAGE', 20); define('MESSAGES_PER_PAGE', 20); define('GROUPS_PER_PAGE', 20); +define('APPS_PER_PAGE', 20); define('GROUPS_PER_MINILIST', 8); define('PROFILES_PER_MINILIST', 8); @@ -136,9 +137,18 @@ spl_autoload_register('GNUsocial_class_autoload'); * and is available here: http://www.php-fig.org/psr/psr-0/ */ spl_autoload_register(function($class){ - $file = INSTALLDIR.'/extlib/'.preg_replace('{\\\\|_(?!.*\\\\)}', DIRECTORY_SEPARATOR, ltrim($class, '\\')).'.php'; + $class_path = preg_replace('{\\\\|_(?!.*\\\\)}', DIRECTORY_SEPARATOR, ltrim($class, '\\')).'.php'; + $file = INSTALLDIR.'/extlib/'.$class_path; if (file_exists($file)) { require_once $file; + return; + } + + # Try if the system has this external library + $file = '/usr/share/php/'.$class_path; + if (file_exists($file)) { + require_once $file; + return; } }); diff --git a/lib/galleryaction.php b/lib/galleryaction.php index f87043ac06..5dd0cfcfa7 100644 --- a/lib/galleryaction.php +++ b/lib/galleryaction.php @@ -36,35 +36,6 @@ class GalleryAction extends ProfileAction parent::handle(); } - protected function doPreparation() - { - // showstream requires a nickname - $nickname_arg = $this->arg('nickname'); - $nickname = common_canonical_nickname($nickname_arg); - - // Permanent redirect on non-canonical nickname - - if ($nickname_arg != $nickname) { - $args = array('nickname' => $nickname); - if ($this->arg('page') && $this->arg('page') != 1) { - $args['page'] = $this->arg['page']; - } - common_redirect(common_local_url($this->getActionName(), $args), 301); - } - $this->user = User::getKV('nickname', $nickname); - - if (!$this->user) { - $group = Local_group::getKV('nickname', $nickname); - if ($group instanceof Local_group) { - common_redirect($group->getProfile()->getUrl()); - } - // TRANS: Client error displayed when calling a profile action without specifying a user. - $this->clientError(_('No such user.'), 404); - } - - $this->target = $this->user->getProfile(); - } - function showContent() { $this->showTagsDropdown(); diff --git a/lib/imagefile.php b/lib/imagefile.php index 2d1a3af02e..68cfea48e7 100644 --- a/lib/imagefile.php +++ b/lib/imagefile.php @@ -189,6 +189,8 @@ class ImageFile case UPLOAD_ERR_NO_FILE: // No file; probably just a non-AJAX submission. + throw new ClientException(_('No file uploaded.')); + default: common_log(LOG_ERR, __METHOD__ . ": Unknown upload error " . $_FILES[$param]['error']); // TRANS: Exception thrown when uploading an image fails for an unknown reason. diff --git a/lib/implugin.php b/lib/implugin.php index 2da4fa961a..742147dbbd 100644 --- a/lib/implugin.php +++ b/lib/implugin.php @@ -126,17 +126,6 @@ abstract class ImPlugin extends Plugin */ abstract function daemonScreenname(); - /** - * get the microid uri of a given screenname - * - * @param string $screenname screenname - * - * @return string microid uri - */ - function microiduri($screenname) - { - return $this->transport . ':' . $screenname; - } //========================UTILITY FUNCTIONS USEFUL TO IMPLEMENTATIONS - MISC ========================\ /** @@ -254,11 +243,11 @@ abstract class ImPlugin extends Plugin * * @param string $screenname screenname sending to * @param string $code the confirmation code - * @param User $user user sending to + * @param Profile $target For whom the code is valid for * * @return boolean success value */ - function sendConfirmationCode($screenname, $code, $user) + function sendConfirmationCode($screenname, $code, Profile $target) { // TRANS: Body text for confirmation code e-mail. // TRANS: %1$s is a user nickname, %2$s is the StatusNet sitename, @@ -269,7 +258,7 @@ abstract class ImPlugin extends Plugin ' . (If you cannot click it, copy-and-paste it into the ' . 'address bar of your browser). If that user is not you, ' . 'or if you did not request this confirmation, just ignore this message.'), - $user->nickname, common_config('site', 'name'), $this->getDisplayName(), common_local_url('confirmaddress', null, array('code' => $code))); + $target->getNickname(), common_config('site', 'name'), $this->getDisplayName(), common_local_url('confirmaddress', null, array('code' => $code))); return $this->sendMessage($screenname, $body); } @@ -563,35 +552,20 @@ abstract class ImPlugin extends Plugin return true; } - function onEndShowHeadElements($action) + function onEndShowHeadElements(Action $action) { - $aname = $action->trimmed('action'); - - if ($aname == 'shownotice') { + if ($action instanceof ShownoticeAction) { $user_im_prefs = new User_im_prefs(); - $user_im_prefs->user_id = $action->profile->id; + $user_im_prefs->user_id = $action->notice->getProfile()->getID(); $user_im_prefs->transport = $this->transport; - if ($user_im_prefs->find() && $user_im_prefs->fetch() && $user_im_prefs->microid && $action->notice->uri) { - $id = new Microid($this->microiduri($user_im_prefs->screenname), - $action->notice->uri); - $action->element('meta', array('name' => 'microid', - 'content' => $id->toString())); - } - - } else if ($aname == 'showstream') { + } elseif ($action instanceof ShowstreamAction) { $user_im_prefs = new User_im_prefs(); - $user_im_prefs->user_id = $action->user->id; + $user_im_prefs->user_id = $action->getTarget()->getID(); $user_im_prefs->transport = $this->transport; - if ($user_im_prefs->find() && $user_im_prefs->fetch() && $user_im_prefs->microid && $action->profile->profileurl) { - $id = new Microid($this->microiduri($user_im_prefs->screenname), - $action->selfUrl()); - $action->element('meta', array('name' => 'microid', - 'content' => $id->toString())); - } } } @@ -620,11 +594,11 @@ abstract class ImPlugin extends Plugin 'daemonScreenname' => $this->daemonScreenname()); } - function onSendImConfirmationCode($transport, $screenname, $code, $user) + function onSendImConfirmationCode($transport, $screenname, $code, Profile $target) { if($transport == $this->transport) { - $this->sendConfirmationCode($screenname, $code, $user); + $this->sendConfirmationCode($screenname, $code, $target); return false; } } diff --git a/lib/installer.php b/lib/installer.php index 0a46b2a508..29a4383302 100644 --- a/lib/installer.php +++ b/lib/installer.php @@ -622,7 +622,7 @@ abstract class Installer $this->updateStatus("GNU social has been installed at $link"); $this->updateStatus( - 'DONE! You can visit your new GNU social site (log in as "'.htmlspecialchars($this->adminNick).'"). If this is your first GNU social install, make your experience the best possible by visiting our resource site to join the mailing list or IRC.. FAQ is found here.' + 'DONE! You can visit your new GNU social site (log in as "'.htmlspecialchars($this->adminNick).'"). If this is your first GNU social install, make your experience the best possible by visiting our resource site to join the mailing list or IRC. FAQ is found here.' ); return true; diff --git a/lib/mail.php b/lib/mail.php index 188792d02a..7ac743bfee 100644 --- a/lib/mail.php +++ b/lib/mail.php @@ -47,11 +47,13 @@ require_once 'Mail.php'; function mail_backend() { static $backend = null; + global $_PEAR; if (!$backend) { - $backend = Mail::factory(common_config('mail', 'backend'), + $mail = new Mail(); + $backend = $mail->factory(common_config('mail', 'backend'), common_config('mail', 'params') ?: array()); - if (PEAR::isError($backend)) { + if ($_PEAR->isError($backend)) { common_server_error($backend->getMessage(), 500); } } diff --git a/lib/microid.php b/lib/microid.php deleted file mode 100644 index e2e7d7607f..0000000000 --- a/lib/microid.php +++ /dev/null @@ -1,97 +0,0 @@ -. - * - * @category ID - * @package StatusNet - * @author Evan Prodromou - * @copyright 2008 StatusNet, Inc. - * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 - * @link http://status.net/ - */ - -if (!defined('STATUSNET') && !defined('LACONICA')) { - exit(1); -} - -/** - * A class for microids - * - * @category ID - * @package StatusNet - * @author Evan Prodromou - * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 - * @link http://status.net/ - * @see http://microid.org/ - */ - -class Microid -{ - /** Agent part of the ID. */ - - var $agent = null; - - /** Resource part of the ID. */ - - var $resource = null; - - /** - * Constructor - * - * @param string $agent Agent of the ID - * @param string $resource Resource part - */ - - function __construct($agent, $resource) - { - $this->agent = $agent; - $this->resource = $resource; - - } - - /** - * Generate a MicroID string - * - * @return string MicroID for agent and resource - */ - - function toString() - { - $agent_proto = $this->_getProto($this->agent); - $resource_proto = $this->_getProto($this->resource); - - return $agent_proto.'+'.$resource_proto.':sha1:'. - sha1(sha1($this->agent).sha1($this->resource)); - } - - /** - * Utility for getting the protocol part of a URI - * - * @param string $uri URI to parse - * - * @return string scheme part of the URI - */ - - function _getProto($uri) - { - $colon = strpos($uri, ':'); - return substr($uri, 0, $colon); - } -} diff --git a/lib/noticelistitem.php b/lib/noticelistitem.php index f25613b9a9..dc171409f4 100644 --- a/lib/noticelistitem.php +++ b/lib/noticelistitem.php @@ -368,18 +368,19 @@ class NoticeListItem extends Widget */ function showNoticeLocation() { - $id = $this->notice->id; - - $location = $this->notice->getLocation(); - - if (empty($location)) { + return; + try { + $location = Notice_location::locFromStored($this->notice); + } catch (NoResultException $e) { + return; + } catch (ServerException $e) { return; } $name = $location->getName(); - $lat = $this->notice->lat; - $lon = $this->notice->lon; + $lat = $location->lat; + $lon = $location->lon; $latlon = (!empty($lat) && !empty($lon)) ? $lat.';'.$lon : ''; if (empty($name)) { diff --git a/lib/noticestreamaction.php b/lib/noticestreamaction.php index 39c19d551f..ed8921860e 100644 --- a/lib/noticestreamaction.php +++ b/lib/noticestreamaction.php @@ -4,6 +4,7 @@ if (!defined('GNUSOCIAL')) { exit(1); } abstract class NoticestreamAction extends ProfileAction { + protected $notice = null; // holds the stream result protected function prepare(array $args=array()) { parent::prepare($args); diff --git a/lib/personaltagcloudsection.php b/lib/personaltagcloudsection.php index c861c4f57f..46b4661e89 100644 --- a/lib/personaltagcloudsection.php +++ b/lib/personaltagcloudsection.php @@ -27,9 +27,7 @@ * @link http://status.net/ */ -if (!defined('STATUSNET') && !defined('LACONICA')) { - exit(1); -} +if (!defined('GNUSOCIAL')) { exit(1); } /** * Personal tag cloud section @@ -42,12 +40,12 @@ if (!defined('STATUSNET') && !defined('LACONICA')) { */ class PersonalTagCloudSection extends TagCloudSection { - var $user = null; + protected $profile = null; - function __construct($out=null, $user=null) + function __construct(Profile $profile, HTMLOutputter $out=null) { parent::__construct($out); - $this->user = $user; + $this->profile = $profile; } function title() @@ -80,7 +78,7 @@ class PersonalTagCloudSection extends TagCloudSection $tag = Memcached_DataObject::cachedQuery('Notice_tag', sprintf($qry, - $this->user->id), + $this->profile->getID()), 3600); return $tag; } diff --git a/lib/profileaction.php b/lib/profileaction.php index d98bcd7f74..3dc28a7cc4 100644 --- a/lib/profileaction.php +++ b/lib/profileaction.php @@ -48,6 +48,36 @@ abstract class ProfileAction extends ManagedAction protected $target = null; // Profile that we're showing + protected function doPreparation() + { + // showstream requires a nickname + $nickname_arg = $this->trimmed('nickname'); + $nickname = common_canonical_nickname($nickname_arg); + + // Permanent redirect on non-canonical nickname + if ($nickname_arg != $nickname) { + $args = array('nickname' => $nickname); + if ($this->arg('page') && $this->arg('page') != 1) { + $args['page'] = $this->arg['page']; + } + common_redirect(common_local_url($this->getActionName(), $args), 301); + } + + try { + $user = User::getByNickname($nickname); + } catch (NoSuchUserException $e) { + $group = Local_group::getKV('nickname', $nickname); + if ($group instanceof Local_group) { + common_redirect($group->getProfile()->getUrl()); + } + + // No user nor group found, throw the NoSuchUserException again + throw $e; + } + + $this->target = $user->getProfile(); + } + protected function prepare(array $args=array()) { // this will call ->doPreparation() which child classes use to set $this->target @@ -58,9 +88,6 @@ abstract class ProfileAction extends ManagedAction throw new ClientException(_('This profile has been silenced by site moderators'), 403); } - // backwards compatibility until all actions are fixed to use $this->target - $this->profile = $this->target; - $this->tag = $this->trimmed('tag'); $this->page = ($this->arg('page')) ? ($this->arg('page')+0) : 1; common_set_returnto($this->selfUrl()); @@ -68,13 +95,11 @@ abstract class ProfileAction extends ManagedAction return true; } - protected function profileActionPreparation() - { - // Nothing to do by default. - } - public function getTarget() { + if (!$this->target instanceof Profile) { + throw new ServerException('No target profile in ProfileAction class'); + } return $this->target; } diff --git a/lib/profilelistitem.php b/lib/profilelistitem.php index e0b94ac76a..6fe7b99c7b 100644 --- a/lib/profilelistitem.php +++ b/lib/profilelistitem.php @@ -32,18 +32,26 @@ if (!defined('GNUSOCIAL')) { exit(1); } class ProfileListItem extends Widget { /** Current profile. */ + protected $target = null; var $profile = null; /** Action object using us. */ var $action = null; - function __construct($profile, $action) + // FIXME: Directory plugin sends a User_group here, but should send a Profile and handle User_group specifics itself + function __construct($target, HTMLOutputter $action) { parent::__construct($action); - $this->profile = $profile; + $this->target = $target; + $this->profile = $this->target; $this->action = $action; } + function getTarget() + { + return $this->target; + } + function show() { if (Event::handle('StartProfileListItem', array($this))) { diff --git a/lib/queuemanager.php b/lib/queuemanager.php index 45fe1e4ab4..487104099a 100644 --- a/lib/queuemanager.php +++ b/lib/queuemanager.php @@ -43,6 +43,7 @@ abstract class QueueManager extends IoManager protected $handlers = array(); protected $groups = array(); protected $activeGroups = array(); + protected $ignoredTransports = array(); /** * Factory function to pull the appropriate QueueManager object @@ -255,6 +256,17 @@ abstract class QueueManager extends IoManager return array_keys($queues); } + function getIgnoredTransports() + { + return array_keys($this->ignoredTransports); + } + + function ignoreTransport($transport) + { + // key is used for uniqueness, value doesn't mean anything + $this->ignoredTransports[$transport] = true; + } + /** * Initialize the list of queue handlers for the current site. * diff --git a/lib/router.php b/lib/router.php index ca8daf5a90..b13c51c328 100644 --- a/lib/router.php +++ b/lib/router.php @@ -108,6 +108,11 @@ class Router if (Event::handle('StartInitializeRouter', array(&$m))) { + // top of the menu hierarchy, sometimes "Home" + $m->connect('', array('action' => 'top')); + + // public endpoints + $m->connect('robots.txt', array('action' => 'robotstxt')); $m->connect('opensearch/people', array('action' => 'opensearch', @@ -156,13 +161,13 @@ class Router 'deleteaccount', 'restoreaccount', 'top', + 'public', ); foreach ($main as $a) { $m->connect('main/'.$a, array('action' => $a)); } - $m->connect('main/public', array('action' => 'public')); $m->connect('main/all', array('action' => 'networkpublic')); $m->connect('main/tagprofile/:id', array('action' => 'tagprofile'), @@ -239,12 +244,10 @@ class Router array('action' => 'shownotice'), array('notice' => '[0-9]+')); - $m->connect('notice/delete/:notice', + $m->connect('notice/:notice/delete', array('action' => 'deletenotice'), array('notice' => '[0-9]+')); - $m->connect('notice/delete', array('action' => 'deletenotice')); - // conversation $m->connect('conversation/:id', @@ -875,9 +878,6 @@ class Router array('action' => 'rsd', 'nickname' => $nickname)); - $m->connect('', - array('action' => 'startpage')); - // peopletags $m->connect('peopletags', @@ -930,9 +930,6 @@ class Router } } - $m->connect('', array('action' => 'startpage')); - $m->connect('main/public', array('action' => 'public')); - $m->connect('main/all', array('action' => 'networkpublic')); $m->connect('rss', array('action' => 'publicrss')); $m->connect('featuredrss', array('action' => 'featuredrss')); $m->connect('featured/', array('action' => 'featured')); @@ -950,6 +947,13 @@ class Router array('action' => 'subqueue'), array('nickname' => Nickname::DISPLAY_FMT)); + // some targeted RSS 1.0 actions (extends TargetedRss10Action) + foreach (array('all', 'replies') as $a) { + $m->connect(':nickname/'.$a.'/rss', + array('action' => $a.'rss'), + array('nickname' => Nickname::DISPLAY_FMT)); + } + // people tags $m->connect(':nickname/peopletags', @@ -1017,12 +1021,6 @@ class Router array('nickname' => Nickname::DISPLAY_FMT)); } - foreach (array('all', 'replies') as $a) { - $m->connect(':nickname/'.$a.'/rss', - array('action' => $a.'rss'), - array('nickname' => Nickname::DISPLAY_FMT)); - } - $m->connect(':nickname/avatar', array('action' => 'avatarbynickname'), array('nickname' => Nickname::DISPLAY_FMT)); diff --git a/lib/rssaction.php b/lib/rss10action.php similarity index 88% rename from lib/rssaction.php rename to lib/rss10action.php index c3e1283fed..137015530b 100644 --- a/lib/rssaction.php +++ b/lib/rss10action.php @@ -28,11 +28,11 @@ * @link http://status.net/ */ -if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); } +if (!defined('GNUSOCIAL')) { exit(1); } define('DEFAULT_RSS_LIMIT', 48); -class Rss10Action extends Action +class Rss10Action extends ManagedAction { // This will contain the details of each feed item's author and be used to generate SIOC data. @@ -41,47 +41,16 @@ class Rss10Action extends Action var $notices = null; var $tags_already_output = array(); - /** - * Constructor - * - * Just wraps the Action constructor. - * - * @param string $output URI to output to, default = stdout - * @param boolean $indent Whether to indent output, default true - * - * @see Action::__construct - */ - - function __construct($output='php://output', $indent=null) - { - parent::__construct($output, $indent); - } - - /** - * Do we need to write to the database? - * - * @return boolean true - */ - - function isReadonly() + public function isReadOnly($args) { return true; } - /** - * Read arguments and initialize members - * - * @param array $args Arguments from $_REQUEST - * @return boolean success - */ - - function prepare($args) + protected function doPreparation() { - parent::prepare($args); + $this->limit = $this->int('limit'); - $this->limit = (int) $this->trimmed('limit'); - - if ($this->limit == 0) { + if (empty($this->limit)) { $this->limit = DEFAULT_RSS_LIMIT; } @@ -93,7 +62,7 @@ class Rss10Action extends Action // If the user hits cancel -- bam! $this->show_basic_auth_error(); - return; + // the above calls 'exit' } else { $nickname = $_SERVER['PHP_AUTH_USER']; $password = $_SERVER['PHP_AUTH_PW']; @@ -104,27 +73,19 @@ class Rss10Action extends Action common_log(LOG_WARNING, "Failed RSS auth attempt, nickname = $nickname, proxy = $proxy, ip = $ip."); $this->show_basic_auth_error(); - return; + // the above calls 'exit' } } } - return true; + $this->doStreamPreparation(); + + $this->notices = $this->getNotices($this->limit); } - /** - * Handle a request - * - * @param array $args Arguments from $_REQUEST - * - * @return void - */ - - function handle($args) + protected function doStreamPreparation() { - // Parent handling, including cache check - parent::handle($args); - $this->showRss(); + // for example if we need to set $this->target or something } function show_basic_auth_error() @@ -137,6 +98,7 @@ class Rss10Action extends Action $this->element('request', null, $_SERVER['REQUEST_URI']); $this->elementEnd('hash'); $this->endXML(); + exit; } /** @@ -145,7 +107,7 @@ class Rss10Action extends Action * @return array an array of Notice objects sorted in reverse chron */ - function getNotices() + protected function getNotices() { return array(); } @@ -170,7 +132,7 @@ class Rss10Action extends Action return null; } - function showRss() + function showPage() { $this->initRss(); $this->showChannel(); @@ -254,15 +216,19 @@ class Rss10Action extends Action $this->element('dc:creator', null, ($profile->fullname) ? $profile->fullname : $profile->nickname); $this->element('foaf:maker', array('rdf:resource' => $creator_uri)); $this->element('sioc:has_creator', array('rdf:resource' => $creator_uri.'#acct')); - $location = $notice->getLocation(); - if ($location && isset($location->lat) && isset($location->lon)) { - $location_uri = $location->getRdfURL(); - $attrs = array('geo:lat' => $location->lat, - 'geo:long' => $location->lon); - if (strlen($location_uri)) { - $attrs['rdf:resource'] = $location_uri; + try { + $location = Notice_location::locFromStored($notice); + if (isset($location->lat) && isset($location->lon)) { + $location_uri = $location->getRdfURL(); + $attrs = array('geo:lat' => $location->lat, + 'geo:long' => $location->lon); + if (strlen($location_uri)) { + $attrs['rdf:resource'] = $location_uri; + } + $this->element('statusnet:origin', $attrs); } - $this->element('statusnet:origin', $attrs); + } catch (ServerException $e) { + // No result, so no location data } $this->element('statusnet:postIcon', array('rdf:resource' => $profile->avatarUrl())); $this->element('cc:licence', array('rdf:resource' => common_config('license', 'url'))); diff --git a/lib/settingsaction.php b/lib/settingsaction.php index fd4885c830..a98d002ca4 100644 --- a/lib/settingsaction.php +++ b/lib/settingsaction.php @@ -27,9 +27,7 @@ * @link http://status.net/ */ -if (!defined('STATUSNET') && !defined('LACONICA')) { - exit(1); -} +if (!defined('GNUSOCIAL')) { exit(1); } /** * Base class for settings group of actions @@ -43,113 +41,8 @@ if (!defined('STATUSNET') && !defined('LACONICA')) { * @see Widget */ -class SettingsAction extends Action +class SettingsAction extends FormAction { - /** - * A message for the user. - */ - - var $msg = null; - - /** - * Whether the message is a good one or a bad one. - */ - - var $success = false; - - /** - * Handle input and output a page - * - * @param array $args $_REQUEST arguments - * - * @return void - */ - - function handle($args) - { - parent::handle($args); - if (!common_logged_in()) { - // TRANS: Error message displayed when trying to perform an action that requires a logged in user. - $this->clientError(_('Not logged in.')); - } else if (!common_is_real_login()) { - // Cookie theft means that automatic logins can't - // change important settings or see private info, and - // _all_ our settings are important - common_set_returnto($this->selfUrl()); - $user = common_current_user(); - if (Event::handle('RedirectToLogin', array($this, $user))) { - common_redirect(common_local_url('login'), 303); - } - } else if ($_SERVER['REQUEST_METHOD'] == 'POST') { - $this->handlePost(); - } else { - $this->showForm(); - } - } - - /** - * Handle a POST request - * - * @return boolean success flag - */ - - function handlePost() - { - return false; - } - - /** - * show the settings form - * - * @param string $msg an extra message for the user - * @param string $success good message or bad message? - * - * @return void - */ - - function showForm($msg=null, $success=false) - { - $this->msg = $msg; - $this->success = $success; - - $this->showPage(); - } - - /** - * show human-readable instructions for the page - * - * @return void - */ - - function showPageNotice() - { - if ($this->msg) { - $this->element('div', ($this->success) ? 'success' : 'error', - $this->msg); - } else { - $inst = $this->getInstructions(); - $output = common_markup_to_html($inst); - - $this->elementStart('div', 'instructions'); - $this->raw($output); - $this->elementEnd('div'); - } - } - - /** - * instructions recipe for sub-classes - * - * Subclasses should override this to return readable instructions. They'll - * be processed by common_markup_to_html(). - * - * @return string instructions text - */ - - function getInstructions() - { - return ''; - } - /** * Show the local navigation menu * diff --git a/lib/siteprofile.php b/lib/siteprofile.php index 4bbffea754..a2c09efb2f 100644 --- a/lib/siteprofile.php +++ b/lib/siteprofile.php @@ -110,7 +110,6 @@ class PublicSite extends SiteProfileSettings 'plugins' => array( 'core' => self::corePlugins(), 'default' => array_merge(self::defaultPlugins(), array( - 'ExtendedProfile' => array(), 'RegisterThrottle' => array(), )) ), diff --git a/lib/tagcloudsection.php b/lib/tagcloudsection.php index 24a3bd98af..80a9042e0f 100644 --- a/lib/tagcloudsection.php +++ b/lib/tagcloudsection.php @@ -115,11 +115,10 @@ class TagCloudSection extends Section function tagUrl($tag) { - if ('showstream' === $this->out->trimmed('action')) { - return common_local_url('showstream', array('nickname' => $this->out->profile->nickname, 'tag' => $tag)); - } else { - return common_local_url('tag', array('tag' => $tag)); + if ($this->out instanceof ShowstreamAction) { + return common_local_url('showstream', array('nickname' => $this->out->getTarget()->getNickname(), 'tag' => $tag)); } + return common_local_url('tag', array('tag' => $tag)); } function divId() diff --git a/lib/targetedrss10action.php b/lib/targetedrss10action.php new file mode 100644 index 0000000000..ed7e262623 --- /dev/null +++ b/lib/targetedrss10action.php @@ -0,0 +1,51 @@ +. + * + * @category Mail + * @package StatusNet + * @author Evan Prodromou + * @author Earle Martin + * @copyright 2008-9 StatusNet, Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://status.net/ + */ + +if (!defined('GNUSOCIAL')) { exit(1); } + +class TargetedRss10Action extends Rss10Action +{ + protected $target = null; + + protected function doStreamPreparation() + { + $this->target = User::getByNickname($this->trimmed('nickname'))->getProfile(); + } + + public function getTarget() + { + return $this->target; + } + + function getImage() + { + return $this->target->avatarUrl(AVATAR_PROFILE_SIZE); + } +} diff --git a/lib/threadednoticelist.php b/lib/threadednoticelist.php index acb9efb972..ebf0a46089 100644 --- a/lib/threadednoticelist.php +++ b/lib/threadednoticelist.php @@ -195,7 +195,7 @@ class ThreadedNoticeListItem extends NoticeListItem function showEnd() { $max = $this->initialItems(); - if (!$this->repeat) { + if (!$this->repeat instanceof Notice) { $stream = new ConversationNoticeStream($this->notice->conversation, $this->userProfile); $notice = $stream->getNotices(0, $max + 2); $notices = array(); diff --git a/lib/util.php b/lib/util.php index f29d9559b9..66847a4350 100644 --- a/lib/util.php +++ b/lib/util.php @@ -210,7 +210,7 @@ function common_language() /** * Salted, hashed passwords are stored in the DB. */ -function common_munge_password($password, $id, Profile $profile=null) +function common_munge_password($password, Profile $profile=null) { $hashed = null; @@ -245,8 +245,7 @@ function common_check_user($nickname, $password) } if ($user instanceof User && !empty($password)) { - if (0 == strcmp(common_munge_password($password, $user->id), - $user->password)) { + if (0 == strcmp(common_munge_password($password, $user->getProfile()), $user->password)) { //internal checking passed $authenticatedUser = $user; } @@ -710,26 +709,22 @@ function common_find_mentions($text, Notice $notice) // Is it a reply? - if ($notice instanceof Notice) { - try { - $origNotice = $notice->getParent(); - $origAuthor = $origNotice->getProfile(); + try { + $origNotice = $notice->getParent(); + $origAuthor = $origNotice->getProfile(); - $ids = $origNotice->getReplies(); + $ids = $origNotice->getReplies(); - foreach ($ids as $id) { - $repliedTo = Profile::getKV('id', $id); - if ($repliedTo instanceof Profile) { - $origMentions[$repliedTo->nickname] = $repliedTo; - } + foreach ($ids as $id) { + try { + $repliedTo = Profile::getByID($id); + $origMentions[$repliedTo->getNickname()] = $repliedTo; + } catch (NoResultException $e) { + // continue foreach } - } catch (NoProfileException $e) { - common_log(LOG_WARNING, sprintf('Notice %d author profile id %d does not exist', $origNotice->id, $origNotice->profile_id)); - } catch (NoParentNoticeException $e) { - // This notice is not in reply to anything - } catch (Exception $e) { - common_log(LOG_WARNING, __METHOD__ . ' got exception ' . get_class($e) . ' : ' . $e->getMessage()); } + } catch (NoParentNoticeException $e) { + // It wasn't a reply to anything, so we can't harvest nickname-relations. } $matches = common_find_mentions_raw($text); @@ -2434,3 +2429,12 @@ function common_strip_html($html, $trim=true, $save_whitespace=false) $text = html_entity_decode(strip_tags($html), ENT_QUOTES, 'UTF-8'); return $trim ? trim($text) : $text; } + +function html_sprintf() +{ + $args = func_get_args(); + for ($i=1; $ixw = new XMLWriter(); $this->xw->openURI($output); if(is_null($indent)) { diff --git a/nginx.conf.sample b/nginx.conf.sample new file mode 100644 index 0000000000..d05c676bc1 --- /dev/null +++ b/nginx.conf.sample @@ -0,0 +1,53 @@ +server { + # Ports + listen 80; + # Uncomment the following line + # to enable HTTPS + #listen 443 ssl; + + # Server name + # Change "example.org" to your domain name + server_name example.org; + + # SSL + # Uncomment and change the paths to setup + # your SSL key/cert. See https://cipherli.st/ + # for more information + #ssl_certificate /path/to/ssl.cert; + #ssl_certificate_key /path/to/ssl.key; + + # Logs + # Uncomment and change the paths to setup + # logging + #access_log /path/to/access.log; + #error_log /path/to/error.log; + + # Root + # Change the path below to where you installed + # GNU social + root /path/to/gnusocial/root; + + # Index + index index.php; + + # PHP + location ~ \.php { + fastcgi_pass unix:/run/php-fpm/php-fpm.sock; + # Remove the "fastcgi_pass" line above and uncomment + # the one below to use TCP sockets instead of Unix sockets + #fastcgi_pass 127.0.0.1:9000; + fastcgi_index index.php; + include fastcgi.conf; + } + + # Location + location / { + try_files $uri $uri/ @gnusocial; + } + + # Fancy URLs + location @gnusocial { + rewrite ^(.*)$ /index.php?p=$1 last; + } +} + diff --git a/plugins/Activity/ActivityPlugin.php b/plugins/Activity/ActivityPlugin.php index 5144eb4666..d8f3c6c502 100644 --- a/plugins/Activity/ActivityPlugin.php +++ b/plugins/Activity/ActivityPlugin.php @@ -72,7 +72,7 @@ class ActivityPlugin extends Plugin // TRANS: Text for "started following" item in activity plugin. // TRANS: %1$s is a profile URL, %2$s is a profile name, // TRANS: %3$s is a profile URL, %4$s is a profile name. - $rendered = sprintf(_m('%2$s started following %4$s.'), + $rendered = html_sprintf(_m('%2$s started following %4$s.'), $profile->getUrl(), $profile->getBestName(), $other->getUrl(), @@ -110,7 +110,7 @@ class ActivityPlugin extends Plugin // TRANS: Text for "stopped following" item in activity plugin. // TRANS: %1$s is a profile URL, %2$s is a profile name, // TRANS: %3$s is a profile URL, %4$s is a profile name. - $rendered = sprintf(_m('%2$s stopped following %4$s.'), + $rendered = html_sprintf(_m('%2$s stopped following %4$s.'), $profile->getUrl(), $profile->getBestName(), $other->getUrl(), @@ -155,7 +155,7 @@ class ActivityPlugin extends Plugin // TRANS: Text for "stopped liking" item in activity plugin. // TRANS: %1$s is a profile URL, %2$s is a profile name, // TRANS: %3$s is a notice URL, %4$s is an author name. - $rendered = sprintf(_m('%2$s stopped liking %4$s\'s update.'), + $rendered = html_sprintf(_m('%2$s stopped liking %4$s\'s update.'), $profile->getUrl(), $profile->getBestName(), $notice->getUrl(), @@ -200,7 +200,7 @@ class ActivityPlugin extends Plugin // TRANS: Text for "joined group" item in activity plugin. // TRANS: %1$s is a profile URL, %2$s is a profile name, // TRANS: %3$s is a group URL, %4$s is a group name. - $rendered = sprintf(_m('%2$s joined the group %4$s.'), + $rendered = html_sprintf(_m('%2$s joined the group %4$s.'), $profile->getUrl(), $profile->getBestName(), $group->homeUrl(), @@ -241,7 +241,7 @@ class ActivityPlugin extends Plugin // TRANS: Text for "left group" item in activity plugin. // TRANS: %1$s is a profile URL, %2$s is a profile name, // TRANS: %3$s is a group URL, %4$s is a group name. - $rendered = sprintf(_m('%2$s left the group %4$s.'), + $rendered = html_sprintf(_m('%2$s left the group %4$s.'), $profile->getUrl(), $profile->getBestName(), $group->homeUrl(), diff --git a/plugins/AuthCrypt/AuthCryptPlugin.php b/plugins/AuthCrypt/AuthCryptPlugin.php index c669566772..540019f9c2 100644 --- a/plugins/AuthCrypt/AuthCryptPlugin.php +++ b/plugins/AuthCrypt/AuthCryptPlugin.php @@ -110,17 +110,17 @@ class AuthCryptPlugin extends AuthenticationPlugin * EVENTS */ - public function onStartChangePassword($user, $oldpassword, $newpassword) + public function onStartChangePassword(Profile $target, $oldpassword, $newpassword) { - if (!$this->checkPassword($user->nickname, $oldpassword)) { + if (!$this->checkPassword($target->getNickname(), $oldpassword)) { // if we ARE in overwrite mode, test password with common_check_user - if (!$this->overwrite || !common_check_user($user->nickname, $oldpassword)) { + if (!$this->overwrite || !common_check_user($target->getNickname(), $oldpassword)) { // either we're not in overwrite mode, or the password was incorrect return !$this->authoritative; } // oldpassword was apparently ok } - $changed = $this->changePassword($user->nickname, $oldpassword, $newpassword); + $changed = $this->changePassword($target->getNickname(), $oldpassword, $newpassword); return (!$changed && empty($this->authoritative)); } diff --git a/plugins/Bookmark/actions/bookmarksrss.php b/plugins/Bookmark/actions/bookmarksrss.php index fc3331482f..955b782666 100644 --- a/plugins/Bookmark/actions/bookmarksrss.php +++ b/plugins/Bookmark/actions/bookmarksrss.php @@ -28,11 +28,7 @@ * along with this program. If not, see . */ -if (!defined('STATUSNET') && !defined('LACONICA')) { - exit(1); -} - -require_once INSTALLDIR.'/lib/rssaction.php'; +if (!defined('GNUSOCIAL')) { exit(1); } /** * RSS feed for user bookmarks action class. @@ -48,54 +44,12 @@ require_once INSTALLDIR.'/lib/rssaction.php'; * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3 * @link http://status.net/ */ -class BookmarksrssAction extends Rss10Action +class BookmarksrssAction extends TargetedRss10Action { - /** The user whose bookmarks to display */ - - var $user = null; - - /** - * Find the user to display by supplied nickname - * - * @param array $args Arguments from $_REQUEST - * - * @return boolean success - */ - function prepare($args) - { - parent::prepare($args); - - $nickname = $this->trimmed('nickname'); - $this->user = User::getKV('nickname', $nickname); - - if (!$this->user) { - // TRANS: Client error displayed when trying to get the RSS feed with bookmarks of a user that does not exist. - $this->clientError(_('No such user.')); - } else { - $this->notices = $this->getNotices($this->limit); - return true; - } - } - - /** - * Get notices - * - * @param integer $limit max number of notices to return - * - * @return array notices - */ - function getNotices($limit=0) + protected function getNotices() { - $user = $this->user; - - $notice = new BookmarksNoticeStream($this->user->id, true); - $notice = $notice->getNotices(0, NOTICES_PER_PAGE); - - $notices = array(); - while ($notice->fetch()) { - $notices[] = clone($notice); - } - return $notices; + $stream = new BookmarksNoticeStream($this->target->getID(), true); + return $stream->getNotices(0, $this->limit)->fetchAll(); } /** @@ -105,31 +59,19 @@ class BookmarksrssAction extends Rss10Action */ function getChannel() { - $user = $this->user; $c = array('url' => common_local_url('bookmarksrss', array('nickname' => - $user->nickname)), + $this->target->getNickname())), // TRANS: Title of RSS feed with bookmarks of a user. // TRANS: %s is a user's nickname. - 'title' => sprintf(_("%s's bookmarks"), $user->nickname), + 'title' => sprintf(_("%s's bookmarks"), $this->target->getNickname()), 'link' => common_local_url('bookmarks', array('nickname' => - $user->nickname)), + $this->target->getNickname())), // TRANS: Desciption of RSS feed with bookmarks of a user. // TRANS: %1$s is a user's nickname, %2$s is the name of the StatusNet site. 'description' => sprintf(_('Bookmarks posted by %1$s on %2$s!'), - $user->nickname, common_config('site', 'name'))); + $this->target->getNickname(), common_config('site', 'name'))); return $c; } - - /** - * Get image. - * - * @return void - */ - function getImage() - { - return null; - } - } diff --git a/plugins/ChooseTheme/ChooseThemePlugin.php b/plugins/ChooseTheme/ChooseThemePlugin.php new file mode 100644 index 0000000000..b54e3d09a6 --- /dev/null +++ b/plugins/ChooseTheme/ChooseThemePlugin.php @@ -0,0 +1,74 @@ +. + * + * @author Knut Erik Hollund + * @copyright 2015 kollektivet0x242. http://www.kollektivet0x242.no + * + * @license GNU Affero General Public License http://www.gnu.org/licenses/ + */ + +class ChooseThemePlugin extends Plugin { + + public function onRouterInitialized(URLMapper $m) { + $m->connect('main/choosethemesettings', array('action' => 'choosethemesettings')); + } + + public function onPluginVersion(array &$versions) { + + $versions[] = array('name' => 'ChooseTheme', + 'version' => '0.1', + 'author' => 'Knut Erik "abjectio" Hollund', + 'homepage' => 'https://gitlab.com/kollektivet0x242/gsp-choosetheme', + 'rawdescription' => + // TRANS: Plugin description. + _m('Allowing user to select the preferred theme.')); + return true; + } + + /** + * Menu item for ChooseTheme + * + * @param Action $action action being executed + * + * @return boolean hook return + */ + function onEndAccountSettingsNav(Action $action) { + $action_name = $action->getActionName(); + + $action->menuItem(common_local_url('choosethemesettings'), + // TRANS: Poll plugin menu item on user settings page. + _m('MENU', 'Theme'), + // TRANS: Poll plugin tooltip for user settings menu item. + _m('Choose Theme'), + $action_name === 'themesettings'); + + return true; + } + + + function onStartShowStylesheets(Action $action) { + + //get the theme and set the current config for site and theme. + if($action->getScoped() instanceof Profile) { + $site_theme = common_config('site','theme'); + $user_theme = $action->getScoped()->getPref('chosen_theme', 'theme', $site_theme); + common_config_set('site', 'theme', $user_theme); + } + return true; + } +} diff --git a/plugins/ChooseTheme/README.md b/plugins/ChooseTheme/README.md new file mode 100644 index 0000000000..2e0a761fa1 --- /dev/null +++ b/plugins/ChooseTheme/README.md @@ -0,0 +1,13 @@ +### Choose theme +A simple plugin for [GNU social software](http://gnu.io/social/). +The plugin enables the user to select their own theme, independently on site setting and other users. + +#### Enable plugin +- Include this code in your GNU social instance. +- Edit your `config.php` to include `addPlugin("ChooseTheme");` + +#### How-to +- Choose settings from the GNU social menu. Choose 'Theme' on left menu. +- Select a theme and press 'Save'. + + diff --git a/plugins/ChooseTheme/actions/choosethemesettings.php b/plugins/ChooseTheme/actions/choosethemesettings.php new file mode 100644 index 0000000000..97ef7229c9 --- /dev/null +++ b/plugins/ChooseTheme/actions/choosethemesettings.php @@ -0,0 +1,187 @@ +. + * + * @author Knut Erik Hollund + * @copyright 2015 kollektivet0x242. http://www.kollektivet0x242.no + * + * @license GNU Affero General Public License http://www.gnu.org/licenses/ + */ + +if (!defined('STATUSNET') && !defined('GNUSOCIAL')) { + exit(1); +} + +class ChooseThemeSettingsAction extends SettingsAction { + + + /** + * Title of the page + * @return string Page title + */ + function title() { + // TRANS: Page title. + return _m('Choose theme settings'); + } + + /** + * Instructions for use + * @return string Instructions for use + */ + function getInstructions() { + // TRANS: Page instructions. + return _m('Choose theme'); + } + + /** + * Show the form for ChooseTheme + * @return void + */ + function showContent() { + + $site_theme = common_config('site','theme'); + $prefs = $this->scoped->getPref('chosen_theme', 'theme',$site_theme); + if ($prefs === null) { + common_debug('No chosen theme found in database for user.'); + } + + //Get a list of available themes on instance + $available_themes = Theme::listAvailable(); + $chosenone = array_search($prefs,$available_themes,true); + $form = new ChooseThemeForm($this, $chosenone); + $form->show(); + } + + + /** + * Handler method + * + * @param array $argarray is ignored since it's now passed in in prepare() + * @return void + */ + function handlePost() { + + //Get a list of available themes on instance + $available_themes = Theme::listAvailable(); + $chosen_theme = $available_themes[(int)$this->arg('dwct','0')]; + + $this->success = true; + $this->msg = _m('Settings saved.'); + + $this->success = $this->scoped->setPref('chosen_theme', 'theme', $chosen_theme); + // TRANS: Confirmation shown when user profile settings are saved. + if(!$this->success) $this->msg = _('No valid theme chosen.'); + + $this->showForm(_($this->msg), $this->success); + } +} + + +class ChooseThemeForm extends Form { + + protected $prefs = null; + + + function __construct($out, $prefs) { + parent::__construct($out); + + if ($prefs!=null) { + $this->prefs = $prefs; + } else { + $prefs = common_config('site','theme'); + } + +} + + /** + * Visible or invisible data elements + * + * Display the form fields that make up the data of the form. + * Sub-classes should overload this to show their data. + * @return void + */ + + function formData() { + + //Get a list of available themes on instance + $available_themes = Theme::listAvailable(); + + //Remove theme 'licenses' from selectable themes. + //The 'licenses' theme is not an actual theme and + //will just mess-up the gui. + $key = array_search('licenses',$available_themes); + if($key!=false){ + unset($available_themes[$key]); + } + + $this->elementStart('fieldset'); + $this->elementStart('ul', 'form_data'); + $this->elementStart('li'); + $this->dropdown('dwct',_m('Themes'),$available_themes,_m('Select a theme'),false, $this->prefs); + $this->elementEnd('li'); + $this->elementEnd('ul'); + $this->elementEnd('fieldset'); + + } + + /** + * Buttons for form actions + * + * Submit and cancel buttons (or whatever) + * Sub-classes should overload this to show their own buttons. + * @return void + */ + + function formActions() + { + $this->submit('submit', _('Save')); + } + + /** + * ID of the form + * + * Should be unique on the page. Sub-classes should overload this + * to show their own IDs. + * @return int ID of the form + */ + + function id() { + return 'form_choosetheme_prefs'; + } + + /** + * Action of the form. + * + * URL to post to. Should be overloaded by subclasses to give + * somewhere to post to. + * @return string URL to post to + */ + + function action() { + return common_local_url('choosethemesettings'); + } + + /** + * Class of the form. May include space-separated list of multiple classes. + * + * @return string the form's class + */ + + function formClass() { + return 'form_settings'; + } +} diff --git a/plugins/ChooseTheme/locale/ChooseTheme.pot b/plugins/ChooseTheme/locale/ChooseTheme.pot new file mode 100644 index 0000000000..df6c0ca7cc --- /dev/null +++ b/plugins/ChooseTheme/locale/ChooseTheme.pot @@ -0,0 +1,62 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the GNU social package. +# FIRST AUTHOR abjectio@kollektivet0x242.no, 2015. +# +msgid "" +msgstr "" +"Project-Id-Version: Choose Theme\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2015-06-10 22:00+0100\n" +"PO-Revision-Date: 2015-06-10 22:01+0100\n" +"Last-Translator: Knut Erik Hollund \n" +"Language-Team: kollektivet0x242.no \n" +"Language: en\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Poedit 1.5.4\n" +"X-Poedit-Basepath: ./actions\n" +"X-Poedit-KeywordsList: _m\n" +"X-Poedit-SearchPath-0: ./actions\n" +"X-Poedit-SearchPath-1: .\n" + +#: actions/choosethemesettings.php:38 +msgid "Choose theme settings" +msgstr "" + +#: actions/choosethemesettings.php:47 +msgid "Choose theme" +msgstr "" + +#: actions/choosethemesettings.php:83 +msgid "Settings saved." +msgstr "" + +#: actions/choosethemesettings.php:87 +msgid "No valid theme chosen." +msgstr "" + +#: actions/choosethemesettings.php:134 +msgid "Themes" +msgstr "" + +#: actions/choosethemesettings.php:134 +msgid "Select a theme" +msgstr "" + +#: actions/choosethemesettings.php:151 +msgid "Save" +msgstr "" + +#: ChooseThemePlugin.php:39 +msgid "Allowing user to select the preferred theme." +msgstr "" + +#: ChooseThemePlugin.php:55 +msgid "MENU" +msgstr "" + +#: ChooseThemePlugin.php:57 +msgid "Choose Theme" +msgstr "" diff --git a/plugins/ChooseTheme/locale/nb/LC_MESSAGES/ChooseTheme.po b/plugins/ChooseTheme/locale/nb/LC_MESSAGES/ChooseTheme.po new file mode 100644 index 0000000000..206a477185 --- /dev/null +++ b/plugins/ChooseTheme/locale/nb/LC_MESSAGES/ChooseTheme.po @@ -0,0 +1,62 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the GNU social package. +# FIRST AUTHOR abjectio@kollektivet0x242.no, 2015. +# +msgid "" +msgstr "" +"Project-Id-Version: Choose Theme\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2015-06-10 22:00+0100\n" +"PO-Revision-Date: 2015-06-10 22:04+0100\n" +"Last-Translator: Knut Erik Hollund \n" +"Language-Team: kollektivet0x242.no \n" +"Language: nb\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Poedit 1.5.4\n" +"X-Poedit-Basepath: ./actions\n" +"X-Poedit-KeywordsList: _m\n" +"X-Poedit-SearchPath-0: ./actions\n" +"X-Poedit-SearchPath-1: .\n" + +#: actions/choosethemesettings.php:38 +msgid "Choose theme settings" +msgstr "Innstillinger" + +#: actions/choosethemesettings.php:47 +msgid "Choose theme" +msgstr "Velg tema" + +#: actions/choosethemesettings.php:83 +msgid "Settings saved." +msgstr "Innstillinger lagret." + +#: actions/choosethemesettings.php:87 +msgid "No valid theme chosen." +msgstr "Ingen gyldige tema er valgt." + +#: actions/choosethemesettings.php:134 +msgid "Themes" +msgstr "Temaer" + +#: actions/choosethemesettings.php:134 +msgid "Select a theme" +msgstr "Velg tema" + +#: actions/choosethemesettings.php:151 +msgid "Save" +msgstr "Lagre" + +#: ChooseThemePlugin.php:39 +msgid "Allowing user to select the preferred theme." +msgstr "Lar brukeren velge sitt foretrukne tema." + +#: ChooseThemePlugin.php:55 +msgid "MENU" +msgstr "Tema" + +#: ChooseThemePlugin.php:57 +msgid "Choose Theme" +msgstr "Velg tema" diff --git a/plugins/DirectMessage/actions/apidirectmessage.php b/plugins/DirectMessage/actions/apidirectmessage.php index c18559f49d..8e7f6f8061 100644 --- a/plugins/DirectMessage/actions/apidirectmessage.php +++ b/plugins/DirectMessage/actions/apidirectmessage.php @@ -30,9 +30,7 @@ * @link http://status.net/ */ -if (!defined('STATUSNET')) { - exit(1); -} +if (!defined('GNUSOCIAL')) { exit(1); } /** * Show a list of direct messages from or to the authenticating user @@ -62,13 +60,11 @@ class ApiDirectMessageAction extends ApiAuthAction * * @return boolean success flag */ - function prepare($args) + protected function prepare(array $args=array()) { parent::prepare($args); - $this->user = $this->auth_user; - - if (empty($this->user)) { + if (!$this->scoped instanceof Profile) { // TRANS: Client error given when a user was not found (404). $this->clientError(_('No such user.'), 404); } @@ -83,30 +79,30 @@ class ApiDirectMessageAction extends ApiAuthAction $this->title = sprintf( // TRANS: Title. %s is a user nickname. _("Direct messages from %s"), - $this->user->nickname + $this->scoped->getNickname() ); $this->subtitle = sprintf( // TRANS: Subtitle. %s is a user nickname. _("All the direct messages sent from %s"), - $this->user->nickname + $this->scoped->getNickname() ); - $this->link = $server . $this->user->nickname . '/outbox'; + $this->link = $server . $this->scoped->getNickname() . '/outbox'; $this->selfuri_base = common_root_url() . 'api/direct_messages/sent'; - $this->id = "tag:$taguribase:SentDirectMessages:" . $this->user->id; + $this->id = "tag:$taguribase:SentDirectMessages:" . $this->scoped->getID(); } else { $this->title = sprintf( // TRANS: Title. %s is a user nickname. _("Direct messages to %s"), - $this->user->nickname + $this->scoped->getNickname() ); $this->subtitle = sprintf( // TRANS: Subtitle. %s is a user nickname. _("All the direct messages sent to %s"), - $this->user->nickname + $this->scoped->getNickname() ); - $this->link = $server . $this->user->nickname . '/inbox'; + $this->link = $server . $this->scoped->getNickname() . '/inbox'; $this->selfuri_base = common_root_url() . 'api/direct_messages'; - $this->id = "tag:$taguribase:DirectMessages:" . $this->user->id; + $this->id = "tag:$taguribase:DirectMessages:" . $this->scoped->getID(); } $this->messages = $this->getMessages(); @@ -114,18 +110,9 @@ class ApiDirectMessageAction extends ApiAuthAction return true; } - /** - * Handle the request - * - * Show the messages - * - * @param array $args $_REQUEST data (unused) - * - * @return void - */ - function handle($args) + protected function handle() { - parent::handle($args); + parent::handle(); $this->showMessages(); } @@ -166,9 +153,9 @@ class ApiDirectMessageAction extends ApiAuthAction $message = new Message(); if ($this->arg('sent')) { - $message->from_profile = $this->user->id; + $message->from_profile = $this->scoped->getID(); } else { - $message->to_profile = $this->user->id; + $message->to_profile = $this->scoped->getID(); } if (!empty($this->max_id)) { diff --git a/plugins/DirectMessage/actions/apidirectmessagenew.php b/plugins/DirectMessage/actions/apidirectmessagenew.php index 653fa3a9ed..e2c7ab5ca7 100644 --- a/plugins/DirectMessage/actions/apidirectmessagenew.php +++ b/plugins/DirectMessage/actions/apidirectmessagenew.php @@ -30,9 +30,7 @@ * @link http://status.net/ */ -if (!defined('STATUSNET')) { - exit(1); -} +if (!defined('GNUSOCIAL')) { exit(1); } /** * Creates a new direct message from the authenticating user to @@ -65,7 +63,7 @@ class ApiDirectMessageNewAction extends ApiAuthAction { parent::prepare($args); - if (empty($this->user)) { + if (!$this->scoped instanceof Profile) { // TRANS: Client error when user not found for an API direct message action. $this->clientError(_('No such user.'), 404); } @@ -111,10 +109,10 @@ class ApiDirectMessageNewAction extends ApiAuthAction if (!$this->other instanceof Profile) { // TRANS: Client error displayed if a recipient user could not be found (403). $this->clientError(_('Recipient user not found.'), 403); - } else if (!$this->user->mutuallySubscribed($this->other)) { + } else if (!$this->scoped->mutuallySubscribed($this->other)) { // TRANS: Client error displayed trying to direct message another user who's not a friend (403). $this->clientError(_('Cannot send direct messages to users who aren\'t your friend.'), 403); - } else if ($this->user->id == $this->other->id) { + } else if ($this->scoped->getID() === $this->other->getID()) { // Note: sending msgs to yourself is allowed by Twitter @@ -123,8 +121,8 @@ class ApiDirectMessageNewAction extends ApiAuthAction } $message = Message::saveNew( - $this->user->id, - $this->other->id, + $this->scoped->getID(), + $this->other->getID(), html_entity_decode($this->content, ENT_NOQUOTES, 'UTF-8'), $this->source ); diff --git a/plugins/Directory/css/directory.css b/plugins/Directory/css/directory.css index d49c28fe55..b4fe68d4cc 100644 --- a/plugins/Directory/css/directory.css +++ b/plugins/Directory/css/directory.css @@ -41,10 +41,6 @@ table.profile_list tr { float: none; } -table.profile_list tr.alt { - background-color: #def; /* zebra stripe */ -} - table.profie_list td { width: 100%; padding: 0; @@ -61,4 +57,4 @@ th.current.reverse { background-image: url(../images/control_arrow_up.gif); background-repeat: no-repeat; background-position: 60% 2px; -} \ No newline at end of file +} diff --git a/plugins/Directory/lib/sortablegrouplist.php b/plugins/Directory/lib/sortablegrouplist.php index 7474d0daa6..ab00068f6d 100644 --- a/plugins/Directory/lib/sortablegrouplist.php +++ b/plugins/Directory/lib/sortablegrouplist.php @@ -27,11 +27,7 @@ * @link http://status.net/ */ -if (!defined('STATUSNET')) { - exit(1); -} - -require_once INSTALLDIR . '/lib/subscriptionlist.php'; +if (!defined('GNUSOCIAL')) { exit(1); } /** * Widget to show a sortable list of subscriptions @@ -44,16 +40,6 @@ require_once INSTALLDIR . '/lib/subscriptionlist.php'; */ class SortableGroupList extends SortableSubscriptionList { - /** Owner of this list */ - var $owner = null; - - function __construct($profile, $owner=null, $action=null) - { - parent::__construct($profile, $owner, $action); - - $this->owner = $owner; - } - function startList() { $this->out->elementStart('table', array('class' => 'profile_list xoxo')); @@ -119,25 +105,14 @@ class SortableGroupList extends SortableSubscriptionList $this->out->elementStart('tbody'); } - function newListItem($profile, $odd) + function newListItem($profile) { - return new SortableGroupListItem($profile, $this->owner, $this->action, $odd); + return new SortableGroupListItem($profile, $this->owner, $this->action); } } class SortableGroupListItem extends SortableSubscriptionListItem { - /** Owner of this list */ - var $owner = null; - - function __construct($profile, $owner, $action, $alt) - { - parent::__construct($profile, $owner, $action, $alt); - - $this->alt = $alt; // is this row alternate? - $this->owner = $owner; - } - function showHomepage() { if (!empty($this->profile->homepage)) { diff --git a/plugins/Directory/lib/sortablesubscriptionlist.php b/plugins/Directory/lib/sortablesubscriptionlist.php index 75c42a5fdf..719834bc91 100644 --- a/plugins/Directory/lib/sortablesubscriptionlist.php +++ b/plugins/Directory/lib/sortablesubscriptionlist.php @@ -27,11 +27,7 @@ * @link http://status.net/ */ -if (!defined('STATUSNET')) { - exit(1); -} - -require_once INSTALLDIR . '/lib/subscriptionlist.php'; +if (!defined('GNUSOCIAL')) { exit(1); } /** * Widget to show a sortable list of subscriptions @@ -44,16 +40,6 @@ require_once INSTALLDIR . '/lib/subscriptionlist.php'; */ class SortableSubscriptionList extends SubscriptionList { - /** Owner of this list */ - var $owner = null; - - function __construct($profile, $owner=null, $action=null) - { - parent::__construct($profile, $owner, $action); - - $this->owner = $owner; - } - function startList() { $this->out->elementStart('table', array('class' => 'profile_list xoxo')); @@ -128,48 +114,14 @@ class SortableSubscriptionList extends SubscriptionList $this->out->elementEnd('table'); } - function showProfiles() + function newListItem($profile) { - // Note: we don't use fetchAll() because it's borked with query() - - $profiles = array(); - - while ($this->profile->fetch()) { - $profiles[] = clone($this->profile); - } - - $cnt = count($profiles); - - $max = min($cnt, $this->maxProfiles()); - - for ($i = 0; $i < $max; $i++) { - $odd = ($i % 2 == 0); // for zebra striping - $pli = $this->newListItem($profiles[$i], $odd); - $pli->show(); - } - - return $cnt; - } - - function newListItem($profile, $odd) - { - return new SortableSubscriptionListItem($profile, $this->owner, $this->action, $odd); + return new SortableSubscriptionListItem($profile, $this->owner, $this->action); } } class SortableSubscriptionListItem extends SubscriptionListItem { - /** Owner of this list */ - var $owner = null; - - function __construct($profile, $owner, $action, $alt) - { - parent::__construct($profile, $owner, $action); - - $this->alt = $alt; // is this row alternate? - $this->owner = $owner; - } - function startItem() { $attr = array( @@ -177,10 +129,6 @@ class SortableSubscriptionListItem extends SubscriptionListItem 'id' => 'profile-' . $this->profile->id ); - if ($this->alt) { - $attr['class'] .= ' alt'; - } - $this->out->elementStart('tr', $attr); } diff --git a/plugins/ExtendedProfile/actions/profiledetail.php b/plugins/ExtendedProfile/actions/profiledetail.php index a777a28e03..ea0b8ad630 100644 --- a/plugins/ExtendedProfile/actions/profiledetail.php +++ b/plugins/ExtendedProfile/actions/profiledetail.php @@ -17,13 +17,10 @@ * along with this program. If not, see . */ -if (!defined('STATUSNET')) { - exit(1); -} +if (!defined('GNUSOCIAL')) { exit(1); } class ProfileDetailAction extends ShowstreamAction { - function isReadOnly($args) { return true; @@ -31,7 +28,7 @@ class ProfileDetailAction extends ShowstreamAction function title() { - return $this->profile->getFancyName(); + return $this->target->getFancyName(); } function showStylesheets() { @@ -43,7 +40,7 @@ class ProfileDetailAction extends ShowstreamAction function showContent() { $cur = common_current_user(); - if ($cur && $cur->id == $this->profile->id) { // your own page + if ($this->scoped instanceof Profile && $this->scoped->sameAs($this->target)) { $this->elementStart('div', 'entity_actions'); $this->elementStart('ul'); $this->elementStart('li', 'entity_edit'); @@ -57,7 +54,7 @@ class ProfileDetailAction extends ShowstreamAction $this->elementEnd('div'); } - $widget = new ExtendedProfileWidget($this, $this->profile); + $widget = new ExtendedProfileWidget($this, $this->target); $widget->show(); } } diff --git a/plugins/ExtendedProfile/actions/profiledetailsettings.php b/plugins/ExtendedProfile/actions/profiledetailsettings.php index 8d8a33ec44..73bf364c7b 100644 --- a/plugins/ExtendedProfile/actions/profiledetailsettings.php +++ b/plugins/ExtendedProfile/actions/profiledetailsettings.php @@ -17,9 +17,7 @@ * along with this program. If not, see . */ -if (!defined('STATUSNET')) { - exit(1); -} +if (!defined('GNUSOCIAL')) { exit(1); } class ProfileDetailSettingsAction extends ProfileSettingsAction { @@ -29,18 +27,6 @@ class ProfileDetailSettingsAction extends ProfileSettingsAction return _m('Extended profile settings'); } - /** - * Instructions for use - * - * @return instructions for use - */ - function getInstructions() - { - // TRANS: Usage instructions for profile settings. - return _m('You can update your personal profile info here '. - 'so people know more about you.'); - } - function showStylesheets() { parent::showStylesheets(); $this->cssLink('plugins/ExtendedProfile/css/profiledetail.css'); @@ -53,36 +39,21 @@ class ProfileDetailSettingsAction extends ProfileSettingsAction return true; } - function handlePost() + protected function doPost() { - // CSRF protection - $token = $this->trimmed('token'); - if (!$token || $token != common_session_token()) { - $this->showForm( - // TRANS: Client error displayed when the session token does not match or is not given. - _m('There was a problem with your session token. ' - . 'Try again, please.' - ) - ); - return; + if ($this->arg('save')) { + return $this->saveDetails(); } - if ($this->arg('save')) { - $this->saveDetails(); - } else { - // TRANS: Message given submitting a form with an unknown action. - $this->showForm(_m('Unexpected form submission.')); - } + // TRANS: Message given submitting a form with an unknown action. + throw new ClientException(_m('Unexpected form submission.')); } function showContent() { - $cur = common_current_user(); - $profile = $cur->getProfile(); - $widget = new ExtendedProfileWidget( $this, - $profile, + $this->scoped, ExtendedProfileWidget::EDITABLE ); $widget->show(); @@ -92,49 +63,38 @@ class ProfileDetailSettingsAction extends ProfileSettingsAction { common_debug(var_export($_POST, true)); - $user = common_current_user(); + $this->saveStandardProfileDetails(); - try { - $this->saveStandardProfileDetails($user); + $simpleFieldNames = array('title', 'spouse', 'kids', 'manager'); + $dateFieldNames = array('birthday'); - $profile = $user->getProfile(); - - $simpleFieldNames = array('title', 'spouse', 'kids', 'manager'); - $dateFieldNames = array('birthday'); - - foreach ($simpleFieldNames as $name) { - $value = $this->trimmed('extprofile-' . $name); - if (!empty($value)) { - $this->saveField($user, $name, $value); - } + foreach ($simpleFieldNames as $name) { + $value = $this->trimmed('extprofile-' . $name); + if (!empty($value)) { + $this->saveField($name, $value); } - - foreach ($dateFieldNames as $name) { - $value = $this->trimmed('extprofile-' . $name); - $dateVal = $this->parseDate($name, $value); - $this->saveField( - $user, - $name, - null, - null, - null, - $dateVal - ); - } - - $this->savePhoneNumbers($user); - $this->saveIms($user); - $this->saveWebsites($user); - $this->saveExperiences($user); - $this->saveEducations($user); - - } catch (Exception $e) { - $this->showForm($e->getMessage(), false); - return; } + foreach ($dateFieldNames as $name) { + $value = $this->trimmed('extprofile-' . $name); + $dateVal = $this->parseDate($name, $value); + $this->saveField( + $name, + null, + null, + null, + $dateVal + ); + } + + $this->savePhoneNumbers(); + $this->saveIms(); + $this->saveWebsites(); + $this->saveExperiences(); + $this->saveEducations(); + // TRANS: Success message after saving extended profile details. - $this->showForm(_m('Details saved.'), true); + return _m('Details saved.'); } @@ -168,15 +128,14 @@ class ProfileDetailSettingsAction extends ProfileSettingsAction return null; } - function savePhoneNumbers($user) { + function savePhoneNumbers() { $phones = $this->findPhoneNumbers(); - $this->removeAll($user, 'phone'); + $this->removeAll('phone'); $i = 0; foreach($phones as $phone) { if (!empty($phone['value'])) { ++$i; $this->saveField( - $user, 'phone', $phone['value'], $phone['rel'], @@ -226,15 +185,14 @@ class ProfileDetailSettingsAction extends ProfileSettingsAction return $imArray; } - function saveIms($user) { + function saveIms() { $ims = $this->findIms(); - $this->removeAll($user, 'im'); + $this->removeAll('im'); $i = 0; foreach($ims as $im) { if (!empty($im['value'])) { ++$i; $this->saveField( - $user, 'im', $im['value'], $im['rel'], @@ -262,9 +220,9 @@ class ProfileDetailSettingsAction extends ProfileSettingsAction return $wsArray; } - function saveWebsites($user) { + function saveWebsites() { $sites = $this->findWebsites(); - $this->removeAll($user, 'website'); + $this->removeAll('website'); $i = 0; foreach($sites as $site) { if (!empty($site['value']) && !common_valid_http_url($site['value'])) { @@ -276,7 +234,6 @@ class ProfileDetailSettingsAction extends ProfileSettingsAction if (!empty($site['value'])) { ++$i; $this->saveField( - $user, 'website', $site['value'], $site['rel'], @@ -317,20 +274,19 @@ class ProfileDetailSettingsAction extends ProfileSettingsAction return $expArray; } - function saveExperiences($user) { + function saveExperiences() { common_debug('save experiences'); $experiences = $this->findExperiences(); - $this->removeAll($user, 'company'); - $this->removeAll($user, 'start'); - $this->removeAll($user, 'end'); // also stores 'current' + $this->removeAll('company'); + $this->removeAll('start'); + $this->removeAll('end'); // also stores 'current' $i = 0; foreach($experiences as $experience) { if (!empty($experience['company'])) { ++$i; $this->saveField( - $user, 'company', $experience['company'], null, @@ -338,7 +294,6 @@ class ProfileDetailSettingsAction extends ProfileSettingsAction ); $this->saveField( - $user, 'start', null, null, @@ -349,7 +304,6 @@ class ProfileDetailSettingsAction extends ProfileSettingsAction // Save "current" employer indicator in rel if ($experience['current']) { $this->saveField( - $user, 'end', null, 'current', // rel @@ -357,7 +311,6 @@ class ProfileDetailSettingsAction extends ProfileSettingsAction ); } else { $this->saveField( - $user, 'end', null, null, @@ -399,44 +352,40 @@ class ProfileDetailSettingsAction extends ProfileSettingsAction } - function saveEducations($user) { + function saveEducations() { common_debug('save education'); $edus = $this->findEducations(); common_debug(var_export($edus, true)); - $this->removeAll($user, 'school'); - $this->removeAll($user, 'degree'); - $this->removeAll($user, 'degree_descr'); - $this->removeAll($user, 'school_start'); - $this->removeAll($user, 'school_end'); + $this->removeAll('school'); + $this->removeAll('degree'); + $this->removeAll('degree_descr'); + $this->removeAll('school_start'); + $this->removeAll('school_end'); $i = 0; foreach($edus as $edu) { if (!empty($edu['school'])) { ++$i; $this->saveField( - $user, 'school', $edu['school'], null, $i ); $this->saveField( - $user, 'degree', $edu['degree'], null, $i ); $this->saveField( - $user, 'degree_descr', $edu['description'], null, $i ); $this->saveField( - $user, 'school_start', null, null, @@ -445,7 +394,6 @@ class ProfileDetailSettingsAction extends ProfileSettingsAction ); $this->saveField( - $user, 'school_end', null, null, @@ -491,35 +439,33 @@ class ProfileDetailSettingsAction extends ProfileSettingsAction /** * Save an extended profile field as a Profile_detail * - * @param User $user the current user * @param string $name field name * @param string $value field value * @param string $rel field rel (type) * @param int $index index (fields can have multiple values) * @param date $date related date */ - function saveField($user, $name, $value, $rel = null, $index = null, $date = null) + function saveField($name, $value, $rel = null, $index = null, $date = null) { - $profile = $user->getProfile(); $detail = new Profile_detail(); - $detail->profile_id = $profile->id; + $detail->profile_id = $this->scoped->getID(); $detail->field_name = $name; $detail->value_index = $index; $result = $detail->find(true); - if (empty($result)) { - $detial->value_index = $index; + if (!$result instanceof Profile_detail) { + $detail->value_index = $index; $detail->rel = $rel; $detail->field_value = $value; $detail->date = $date; $detail->created = common_sql_now(); $result = $detail->insert(); - if (empty($result)) { + if ($result === false) { common_log_db_error($detail, 'INSERT', __FILE__); // TRANS: Server error displayed when a field could not be saved in the database. - $this->serverError(_m('Could not save profile details.')); + throw new ServerException(_m('Could not save profile details.')); } } else { $orig = clone($detail); @@ -529,21 +475,20 @@ class ProfileDetailSettingsAction extends ProfileSettingsAction $detail->date = $date; $result = $detail->update($orig); - if (empty($result)) { + if ($result === false) { common_log_db_error($detail, 'UPDATE', __FILE__); // TRANS: Server error displayed when a field could not be saved in the database. - $this->serverError(_m('Could not save profile details.')); + throw new ServerException(_m('Could not save profile details.')); } } $detail->free(); } - function removeAll($user, $name) + function removeAll($name) { - $profile = $user->getProfile(); $detail = new Profile_detail(); - $detail->profile_id = $profile->id; + $detail->profile_id = $this->scoped->getID(); $detail->field_name = $name; $detail->delete(); $detail->free(); @@ -554,10 +499,8 @@ class ProfileDetailSettingsAction extends ProfileSettingsAction * * XXX: There's a lot of dupe code here from ProfileSettingsAction. * Do not want. - * - * @param User $user the current user */ - function saveStandardProfileDetails($user) + function saveStandardProfileDetails() { $fullname = $this->trimmed('extprofile-fullname'); $location = $this->trimmed('extprofile-location'); @@ -581,54 +524,47 @@ class ProfileDetailSettingsAction extends ProfileSettingsAction } } - $profile = $user->getProfile(); - - $oldTags = $user->getSelfTags(); + $oldTags = Profile_tag::getSelfTagsArray($this->scoped); $newTags = array_diff($tags, $oldTags); - if ($fullname != $profile->fullname - || $location != $profile->location + if ($fullname != $this->scoped->getFullname() + || $location != $this->scoped->location || !empty($newTags) - || $bio != $profile->bio) { + || $bio != $this->scoped->getDescription()) { - $orig = clone($profile); + $orig = clone($this->scoped); - $profile->nickname = $user->nickname; - $profile->fullname = $fullname; - $profile->bio = $bio; - $profile->location = $location; + // Skipping nickname change here until we add logic for when the site allows it or not + // old Profilesettings will still let us do that. + + $this->scoped->fullname = $fullname; + $this->scoped->bio = $bio; + $this->scoped->location = $location; $loc = Location::fromName($location); if (empty($loc)) { - $profile->lat = null; - $profile->lon = null; - $profile->location_id = null; - $profile->location_ns = null; + $this->scoped->lat = null; + $this->scoped->lon = null; + $this->scoped->location_id = null; + $this->scoped->location_ns = null; } else { - $profile->lat = $loc->lat; - $profile->lon = $loc->lon; - $profile->location_id = $loc->location_id; - $profile->location_ns = $loc->location_ns; + $this->scoped->lat = $loc->lat; + $this->scoped->lon = $loc->lon; + $this->scoped->location_id = $loc->location_id; + $this->scoped->location_ns = $loc->location_ns; } - $profile->profileurl = common_profile_url($user->nickname); - - $result = $profile->update($orig); + $result = $this->scoped->update($orig); if ($result === false) { - common_log_db_error($profile, 'UPDATE', __FILE__); + common_log_db_error($this->scoped, 'UPDATE', __FILE__); // TRANS: Server error thrown when user profile settings could not be saved. - $this->serverError(_m('Could not save profile.')); + throw new ServerException(_m('Could not save profile.')); } // Set the user tags - $result = $user->setSelfTags($tags); - - if (!$result) { - // TRANS: Server error thrown when user profile settings tags could not be saved. - $this->serverError(_m('Could not save tags.')); - } + $result = Profile_tag::setSelfTags($this->scoped, $tags); Event::handle('EndProfileSaveForm', array($this)); } diff --git a/plugins/ExtendedProfile/lib/extendedprofile.php b/plugins/ExtendedProfile/lib/extendedprofile.php index d73170b235..3682e6fc9d 100644 --- a/plugins/ExtendedProfile/lib/extendedprofile.php +++ b/plugins/ExtendedProfile/lib/extendedprofile.php @@ -52,7 +52,7 @@ class ExtendedProfile function loadFields() { $detail = new Profile_detail(); - $detail->profile_id = $this->profile->id; + $detail->profile_id = $this->profile->getID(); $detail->find(); $fields = array(); @@ -71,7 +71,7 @@ class ExtendedProfile */ function getTags() { - return implode(' ', $this->user->getSelfTags()); + return implode(' ', Profile_tag::getSelfTagsArray($this->profile)); } /** diff --git a/plugins/FacebookBridge/actions/facebookfinishlogin.php b/plugins/FacebookBridge/actions/facebookfinishlogin.php index 080c59612c..7cf493a994 100644 --- a/plugins/FacebookBridge/actions/facebookfinishlogin.php +++ b/plugins/FacebookBridge/actions/facebookfinishlogin.php @@ -519,34 +519,30 @@ class FacebookfinishloginAction extends Action function tryLogin() { - $flink = Foreign_link::getByForeignID($this->fbuid, FACEBOOK_SERVICE); - - if (!empty($flink)) { + try { + $flink = Foreign_link::getByForeignID($this->fbuid, FACEBOOK_SERVICE); $user = $flink->getUser(); - if (!empty($user)) { + common_log( + LOG_INFO, + sprintf( + 'Logged in Facebook user %s as user %d (%s)', + $this->fbuid, + $user->nickname, + $user->id + ), + __FILE__ + ); - common_log( - LOG_INFO, - sprintf( - 'Logged in Facebook user %s as user %d (%s)', - $this->fbuid, - $user->nickname, - $user->id - ), - __FILE__ - ); + common_set_user($user); + common_real_login(true); - common_set_user($user); - common_real_login(true); + // clear out the stupid cookie + setcookie('fb_access_token', '', time() - 3600); // one hour ago - // clear out the stupid cookie - setcookie('fb_access_token', '', time() - 3600); // one hour ago + $this->goHome($user->nickname); - $this->goHome($user->nickname); - } - - } else { + } catch (NoResultException $e) { $this->showForm(null, $this->bestNewNickname()); } } diff --git a/plugins/FacebookBridge/actions/facebooksettings.php b/plugins/FacebookBridge/actions/facebooksettings.php index 31e020a3ce..67dd20e036 100644 --- a/plugins/FacebookBridge/actions/facebooksettings.php +++ b/plugins/FacebookBridge/actions/facebooksettings.php @@ -26,9 +26,7 @@ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @link http://status.net/ */ -if (!defined('STATUSNET')) { - exit(1); -} +if (!defined('GNUSOCIAL')) { exit(1); } /** * Edit user settings for Facebook @@ -43,19 +41,11 @@ if (!defined('STATUSNET')) { */ class FacebooksettingsAction extends SettingsAction { private $facebook; // Facebook PHP-SDK client obj - private $flink; - private $user; - /** - * For initializing members of the class. - * - * @param array $argarray misc. arguments - * - * @return boolean true - */ - function prepare($args) { - parent::prepare($args); + protected $flink; + protected function doPreparation() + { $this->facebook = new Facebook( array( 'appId' => common_config('facebook', 'appid'), @@ -64,36 +54,21 @@ class FacebooksettingsAction extends SettingsAction { ) ); - $this->user = common_current_user(); - $this->flink = Foreign_link::getByUserID( - $this->user->id, + $this->scoped->getID(), FACEBOOK_SERVICE ); - - return true; } - /* - * Check the sessions token and dispatch - */ - function handlePost($args) { - // CSRF protection - - $token = $this->trimmed('token'); - if (!$token || $token != common_session_token()) { - $this->showForm( - // TRANS: Client error displayed when the session token does not match or is not given. - _m('There was a problem with your session token. Try again, please.') - ); - return; - } - + protected function doPost() + { if ($this->arg('save')) { - $this->saveSettings(); + return $this->saveSettings(); } else if ($this->arg('disconnect')) { - $this->disconnect(); + return $this->disconnect(); } + + throw new ClientException(_('No action to take on POST.')); } /** @@ -122,109 +97,110 @@ class FacebooksettingsAction extends SettingsAction { * @return void */ function showContent() { - if (!empty($this->flink)) { + if (!$this->flink instanceof Foreign_link) { + throw new ServerException(_m('You have not linked this account to Facebook.')); + } - $this->elementStart( - 'form', - array( - 'method' => 'post', - 'id' => 'form_settings_facebook', - 'class' => 'form_settings', - 'action' => common_local_url('facebooksettings') - ) - ); + $this->elementStart( + 'form', + array( + 'method' => 'post', + 'id' => 'form_settings_facebook', + 'class' => 'form_settings', + 'action' => common_local_url('facebooksettings') + ) + ); - $this->hidden('token', common_session_token()); + $this->hidden('token', common_session_token()); - // TRANS: Form note. User is connected to facebook. - $this->element('p', 'form_note', _m('Connected Facebook user')); + // TRANS: Form note. User is connected to facebook. + $this->element('p', 'form_note', _m('Connected Facebook user')); - $this->elementStart('p', array('class' => 'facebook-user-display')); + $this->elementStart('p', array('class' => 'facebook-user-display')); - $this->element( - 'fb:profile-pic', - array( - 'uid' => $this->flink->foreign_id, - 'size' => 'small', - 'linked' => 'true', - 'facebook-logo' => 'true' - ) - ); + $this->element( + 'fb:profile-pic', + array( + 'uid' => $this->flink->foreign_id, + 'size' => 'small', + 'linked' => 'true', + 'facebook-logo' => 'true' + ) + ); - $this->element( - 'fb:name', - array('uid' => $this->flink->foreign_id, 'useyou' => 'false') - ); + $this->element( + 'fb:name', + array('uid' => $this->flink->foreign_id, 'useyou' => 'false') + ); - $this->elementEnd('p'); + $this->elementEnd('p'); - $this->elementStart('ul', 'form_data'); + $this->elementStart('ul', 'form_data'); - $this->elementStart('li'); + $this->elementStart('li'); - $this->checkbox( - 'noticesync', + $this->checkbox( + 'noticesync', + // TRANS: Checkbox label in Facebook settings. + _m('Publish my notices to Facebook.'), + $this->flink->noticesync & FOREIGN_NOTICE_SEND + ); + + $this->elementEnd('li'); + + $this->elementStart('li'); + + $this->checkbox( + 'replysync', // TRANS: Checkbox label in Facebook settings. - _m('Publish my notices to Facebook.'), - ($this->flink) ? ($this->flink->noticesync & FOREIGN_NOTICE_SEND) : true + _m('Send "@" replies to Facebook.'), + $this->flink->noticesync & FOREIGN_NOTICE_SEND_REPLY + ); + + $this->elementEnd('li'); + + $this->elementStart('li'); + + // TRANS: Submit button to save synchronisation settings. + $this->submit('save', _m('BUTTON', 'Save')); + + $this->elementEnd('li'); + + $this->elementEnd('ul'); + + $this->elementStart('fieldset'); + + // TRANS: Fieldset legend for form to disconnect from Facebook. + $this->element('legend', null, _m('Disconnect my account from Facebook')); + + if (!$this->scoped->hasPassword()) { + $this->elementStart('p', array('class' => 'form_guide')); + + $msg = sprintf( + // TRANS: Notice in disconnect from Facebook form if user has no local StatusNet password. + _m('Disconnecting your Faceboook would make it impossible to '. + 'log in! Please [set a password](%s) first.'), + common_local_url('passwordsettings') ); - $this->elementEnd('li'); - - $this->elementStart('li'); - - $this->checkbox( - 'replysync', - // TRANS: Checkbox label in Facebook settings. - _m('Send "@" replies to Facebook.'), - ($this->flink) ? ($this->flink->noticesync & FOREIGN_NOTICE_SEND_REPLY) : true + $this->raw(common_markup_to_html($msg)); + $this->elementEnd('p'); + } else { + // @todo FIXME: i18n: This message is not being used. + // TRANS: Message displayed when initiating disconnect of a StatusNet user + // TRANS: from a Facebook account. %1$s is the StatusNet site name. + $msg = sprintf(_m('Keep your %1$s account but disconnect from Facebook. ' . + 'You\'ll use your %1$s password to log in.'), + common_config('site', 'name') ); - $this->elementEnd('li'); + // TRANS: Submit button. + $this->submit('disconnect', _m('BUTTON', 'Disconnect')); + } - $this->elementStart('li'); + $this->elementEnd('fieldset'); - // TRANS: Submit button to save synchronisation settings. - $this->submit('save', _m('BUTTON', 'Save')); - - $this->elementEnd('li'); - - $this->elementEnd('ul'); - - $this->elementStart('fieldset'); - - // TRANS: Fieldset legend for form to disconnect from Facebook. - $this->element('legend', null, _m('Disconnect my account from Facebook')); - - if (empty($this->user->password)) { - $this->elementStart('p', array('class' => 'form_guide')); - - $msg = sprintf( - // TRANS: Notice in disconnect from Facebook form if user has no local StatusNet password. - _m('Disconnecting your Faceboook would make it impossible to '. - 'log in! Please [set a password](%s) first.'), - common_local_url('passwordsettings') - ); - - $this->raw(common_markup_to_html($msg)); - $this->elementEnd('p'); - } else { - // @todo FIXME: i18n: This message is not being used. - // TRANS: Message displayed when initiating disconnect of a StatusNet user - // TRANS: from a Facebook account. %1$s is the StatusNet site name. - $msg = sprintf(_m('Keep your %1$s account but disconnect from Facebook. ' . - 'You\'ll use your %1$s password to log in.'), - common_config('site', 'name') - ); - - // TRANS: Submit button. - $this->submit('disconnect', _m('BUTTON', 'Disconnect')); - } - - $this->elementEnd('fieldset'); - - $this->elementEnd('form'); - } + $this->elementEnd('form'); } /* @@ -242,11 +218,10 @@ class FacebooksettingsAction extends SettingsAction { if ($result === false) { // TRANS: Notice in case saving of synchronisation preferences fail. - $this->showForm(_m('There was a problem saving your sync preferences.')); - } else { - // TRANS: Confirmation that synchronisation settings have been saved into the system. - $this->showForm(_m('Sync preferences saved.'), true); + throw new ServerException(_m('There was a problem saving your sync preferences.')); } + // TRANS: Confirmation that synchronisation settings have been saved into the system. + return _m('Sync preferences saved.'); } /* @@ -258,12 +233,12 @@ class FacebooksettingsAction extends SettingsAction { $this->flink = null; if ($result === false) { - common_log_db_error($user, 'DELETE', __FILE__); + common_log_db_error($this->flink, 'DELETE', __FILE__); // TRANS: Server error displayed when deleting the link to a Facebook account fails. - $this->serverError(_m('Could not delete link to Facebook.')); + throw new ServerException(_m('Could not delete link to Facebook.')); } - // TRANS: Confirmation message. StatusNet account was unlinked from Facebook. - $this->showForm(_m('You have disconnected from Facebook.'), true); + // TRANS: Confirmation message. GNU social account was unlinked from Facebook. + return _m('You have disconnected this account from Facebook.'); } } diff --git a/plugins/FacebookBridge/lib/facebookclient.php b/plugins/FacebookBridge/lib/facebookclient.php index 5b512dfdff..5faad5dfb7 100644 --- a/plugins/FacebookBridge/lib/facebookclient.php +++ b/plugins/FacebookBridge/lib/facebookclient.php @@ -66,13 +66,12 @@ class Facebookclient $this->notice = $notice; $profile_id = $profile ? $profile->id : $notice->profile_id; - $this->flink = Foreign_link::getByUserID( - $profile_id, - FACEBOOK_SERVICE - ); - - if (!empty($this->flink)) { + try { + $this->flink = Foreign_link::getByUserID($profile_id, FACEBOOK_SERVICE); $this->user = $this->flink->getUser(); + } catch (NoResultException $e) { + // at least $this->flink could've gotten set to something, + // but the logic that was here before didn't care, so let's not care either } } @@ -918,12 +917,9 @@ class Facebookclient static function addFacebookUser($fbuser) { // remove any existing, possibly outdated, record - $luser = Foreign_user::getForeignUser($fbuser->id, FACEBOOK_SERVICE); - - if (!empty($luser)) { - - $result = $luser->delete(); - + try { + $fuser = Foreign_user::getForeignUser($fbuser->id, FACEBOOK_SERVICE); + $result = $fuser->delete(); if ($result != false) { common_log( LOG_INFO, @@ -935,6 +931,8 @@ class Facebookclient __FILE__ ); } + } catch (NoResultException $e) { + // no old foreign users exist for this id } $fuser = new Foreign_user(); diff --git a/plugins/Favorite/actions/favoritesrss.php b/plugins/Favorite/actions/favoritesrss.php index 0cbebd723c..ca5602d5ec 100644 --- a/plugins/Favorite/actions/favoritesrss.php +++ b/plugins/Favorite/actions/favoritesrss.php @@ -28,11 +28,7 @@ * along with this program. If not, see . */ -if (!defined('STATUSNET') && !defined('LACONICA')) { - exit(1); -} - -require_once INSTALLDIR.'/lib/rssaction.php'; +if (!defined('GNUSOCIAL')) { exit(1); } /** * RSS feed for user favorites action class. @@ -47,50 +43,15 @@ require_once INSTALLDIR.'/lib/rssaction.php'; * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3 * @link http://status.net/ */ -class FavoritesrssAction extends Rss10Action +class FavoritesrssAction extends TargetedRss10Action { - /** The user whose favorites to display */ - - var $user = null; - - /** - * Find the user to display by supplied nickname - * - * @param array $args Arguments from $_REQUEST - * - * @return boolean success - */ - function prepare($args) + protected function getNotices() { - parent::prepare($args); + // is this our own stream? + $own = $this->scoped instanceof Profile ? $this->target->getID() === $this->scoped->getID() : false; - $nickname = $this->trimmed('nickname'); - $this->user = User::getKV('nickname', $nickname); - - if (!$this->user) { - // TRANS: Client error displayed when trying to get the RSS feed with favorites of a user that does not exist. - $this->clientError(_('No such user.')); - } else { - $this->notices = $this->getNotices($this->limit); - return true; - } - } - - /** - * Get notices - * - * @param integer $limit max number of notices to return - * - * @return array notices - */ - function getNotices($limit=0) - { - $notice = Fave::stream($this->user->id, 0, $limit, $false); - $notices = array(); - while ($notice->fetch()) { - $notices[] = clone($notice); - } - return $notices; + $stream = Fave::stream($this->target->getID(), 0, $this->limit, $own); + return $stream->fetchAll(); } /** @@ -116,15 +77,4 @@ class FavoritesrssAction extends Rss10Action $user->nickname, common_config('site', 'name'))); return $c; } - - /** - * Get image. - * - * @return void - */ - function getImage() - { - return null; - } - } diff --git a/plugins/Favorite/actions/showfavorites.php b/plugins/Favorite/actions/showfavorites.php index 98a6bfc5bf..cba29063c2 100644 --- a/plugins/Favorite/actions/showfavorites.php +++ b/plugins/Favorite/actions/showfavorites.php @@ -27,13 +27,7 @@ * @link http://status.net/ */ -if (!defined('STATUSNET') && !defined('LACONICA')) { - exit(1); -} - -require_once INSTALLDIR.'/lib/personalgroupnav.php'; -require_once INSTALLDIR.'/lib/noticelist.php'; -require_once INSTALLDIR.'/lib/feedlist.php'; +if (!defined('GNUSOCIAL')) { exit(1); } /** * List of replies @@ -44,119 +38,29 @@ 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 * @link http://status.net/ */ -class ShowfavoritesAction extends Action +class ShowfavoritesAction extends ShowstreamAction { - /** User we're getting the faves of */ - var $user = null; - /** Page of the faves we're on */ - var $page = null; - - /** - * Is this a read-only page? - * - * @return boolean true - */ - function isReadOnly($args) - { - return true; - } - - /** - * Title of the page - * - * Includes name of user and page number. - * - * @return string title of page - */ function title() { if ($this->page == 1) { // TRANS: Title for first page of favourite notices of a user. // TRANS: %s is the user for whom the favourite notices are displayed. - return sprintf(_('%s\'s favorite notices'), $this->user->nickname); + return sprintf(_('%s\'s favorite notices'), $this->getTarget()->getNickname()); } else { // TRANS: Title for all but the first page of favourite notices of a user. // TRANS: %1$s is the user for whom the favourite notices are displayed, %2$d is the page number. return sprintf(_('%1$s\'s favorite notices, page %2$d'), - $this->user->nickname, + $this->getTarget()->getNickname(), $this->page); } } - /** - * Prepare the object - * - * Check the input values and initialize the object. - * Shows an error page on bad input. - * - * @param array $args $_REQUEST data - * - * @return boolean success flag - */ - function prepare($args) + public function getStream() { - parent::prepare($args); - - $nickname = common_canonical_nickname($this->arg('nickname')); - - $this->user = User::getKV('nickname', $nickname); - - if (!$this->user) { - // TRANS: Client error displayed when trying to display favourite notices for a non-existing user. - $this->clientError(_('No such user.')); - } - - $this->page = $this->trimmed('page'); - - if (!$this->page) { - $this->page = 1; - } - - common_set_returnto($this->selfUrl()); - - $cur = common_current_user(); - - // Show imported/gateway notices as well as local if - // the user is looking at their own favorites, otherwise not. - $this->notice = Fave::stream($this->user->id, - ($this->page-1)*NOTICES_PER_PAGE, // offset - NOTICES_PER_PAGE + 1, // limit - (!empty($cur) && $cur->id == $this->user->id) // own feed? - ); - - if (empty($this->notice)) { - // TRANS: Server error displayed when favourite notices could not be retrieved from the database. - $this->serverError(_('Could not retrieve favorite notices.')); - } - - if($this->page > 1 && $this->notice->N == 0){ - // TRANS: Client error when page not found (404) - $this->clientError(_('No such page.'), 404); - } - - return true; + $own = $this->scoped instanceof Profile ? $this->scoped->sameAs($this->getTarget()) : false; + return new FaveNoticeStream($this->getTarget()->getID(), $own); } - /** - * Handle a request - * - * Just show the page. All args already handled. - * - * @param array $args $_REQUEST data - * - * @return void - */ - function handle($args) - { - parent::handle($args); - $this->showPage(); - } - - /** - * Feeds for the section - * - * @return array Feed objects to show - */ function getFeeds() { return array(new Feed(Feed::JSON, @@ -223,7 +127,7 @@ class ShowfavoritesAction extends Action * * @return void */ - function showContent() + function showNotices() { $nl = new FavoritesNoticeList($this->notice, $this); @@ -234,7 +138,7 @@ class ShowfavoritesAction extends Action $this->pagination($this->page > 1, $cnt > NOTICES_PER_PAGE, $this->page, 'showfavorites', - array('nickname' => $this->user->nickname)); + array('nickname' => $this->getTarget()->getNickname())); } function showPageNotice() { diff --git a/plugins/GeoURL/GeoURLPlugin.php b/plugins/GeoURL/GeoURLPlugin.php index caad8fde11..a8e2546c4f 100644 --- a/plugins/GeoURL/GeoURLPlugin.php +++ b/plugins/GeoURL/GeoURLPlugin.php @@ -57,25 +57,27 @@ class GeoURLPlugin extends Plugin * * @return boolean event handler flag */ - function onEndShowHeadElements($action) + function onEndShowHeadElements(Action $action) { $name = $action->trimmed('action'); $location = null; - if ($name == 'showstream') { - $profile = $action->profile; - if (!empty($profile) && !empty($profile->lat) && !empty($profile->lon)) { + if ($action instanceof ShowstreamAction) { + $profile = $action->getTarget(); + if (!empty($profile->lat) && !empty($profile->lon)) { $location = $profile->lat . ', ' . $profile->lon; } - } else if ($name == 'shownotice') { - $notice = $action->profile; - if (!empty($notice) && !empty($notice->lat) && !empty($notice->lon)) { + } elseif ($action instanceof ShownoticeAction) { + // FIXME: getNotice in ShownoticeAction will do a new lookup, we should fix those classes + // so they can reliably just get a pre-stored notice object which was fetched in Shownotice prepare()... + $notice = $action->notice; + if ($notice instanceof Notice && !empty($notice->lat) && !empty($notice->lon)) { $location = $notice->lat . ', ' . $notice->lon; } } - if (!empty($location)) { + if (!is_null($location)) { $action->element('meta', array('name' => 'ICBM', 'content' => $location)); $action->element('meta', array('name' => 'DC.title', diff --git a/plugins/Gravatar/GravatarPlugin.php b/plugins/Gravatar/GravatarPlugin.php deleted file mode 100644 index cf9e3a01fe..0000000000 --- a/plugins/Gravatar/GravatarPlugin.php +++ /dev/null @@ -1,74 +0,0 @@ -. - */ - -/** - * @package GravatarPlugin - * @maintainer Eric Helgeson - */ - -if (!defined('STATUSNET') && !defined('LACONICA')) { - // This check helps protect against security problems; - // your code file can't be executed directly from the web. - exit(1); -} - -class GravatarPlugin extends Plugin -{ - function onEndProfileGetAvatar($profile, $size, &$avatar) - { - if (empty($avatar)) { - try { - $user = $profile->getUser(); - if (!empty($user->email)) { - // Fake one! - $avatar = new Avatar(); - $avatar->width = $avatar->height = $size; - $avatar->url = $this->gravatar_url($user->email, $size); - return false; - } - } catch (NoSuchUserException $e) { - return true; - } - } - - return true; - } - - function gravatar_url($email, $size) - { - $url = "https://secure.gravatar.com/avatar.php?gravatar_id=". - md5(strtolower($email)). - "&default=".urlencode(Avatar::defaultImage($size)). - "&size=".$size; - return $url; - } - - function onPluginVersion(array &$versions) - { - $versions[] = array('name' => 'Gravatar', - 'version' => GNUSOCIAL_VERSION, - 'author' => 'Eric Helgeson, Evan Prodromou', - 'homepage' => 'http://status.net/wiki/Plugin:Gravatar', - 'rawdescription' => - // TRANS: Plugin decsription. - _m('The Gravatar plugin allows users to use their Gravatar with StatusNet.')); - - return true; - } -} diff --git a/plugins/Gravatar/README b/plugins/Gravatar/README deleted file mode 100644 index 0f6c7280d9..0000000000 --- a/plugins/Gravatar/README +++ /dev/null @@ -1,12 +0,0 @@ -GravatarPlugin 0.1 - -About: -This will allow users to use their Gravatar Avatar with your StatusNet install. - -Configuration: -add this to your config.php: -addPlugin('Gravatar', array()); - -To do: -Site default all on for gravatar by default -Migration Script diff --git a/plugins/Gravatar/locale/Gravatar.pot b/plugins/Gravatar/locale/Gravatar.pot deleted file mode 100644 index 01bcc5d69e..0000000000 --- a/plugins/Gravatar/locale/Gravatar.pot +++ /dev/null @@ -1,25 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# FIRST AUTHOR , YEAR. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: PACKAGE VERSION\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-02-27 16:31+0100\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language-Team: LANGUAGE \n" -"Language: \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=CHARSET\n" -"Content-Transfer-Encoding: 8bit\n" - -#. TRANS: Plugin decsription. -#: GravatarPlugin.php:70 -msgid "" -"The Gravatar plugin allows users to use their Gravatar with StatusNet." -msgstr "" diff --git a/plugins/Gravatar/locale/af/LC_MESSAGES/Gravatar.po b/plugins/Gravatar/locale/af/LC_MESSAGES/Gravatar.po deleted file mode 100644 index 0f97b86afc..0000000000 --- a/plugins/Gravatar/locale/af/LC_MESSAGES/Gravatar.po +++ /dev/null @@ -1,25 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# -# Translators: -msgid "" -msgstr "" -"Project-Id-Version: GNU social\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-02-02 17:47+0100\n" -"PO-Revision-Date: 2015-02-06 16:27+0000\n" -"Last-Translator: FULL NAME \n" -"Language-Team: Afrikaans (http://www.transifex.com/projects/p/gnu-social/language/af/)\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Language: af\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" - -#. TRANS: Plugin decsription. -#: GravatarPlugin.php:70 -msgid "" -"The Gravatar plugin allows users to use their Gravatar with StatusNet." -msgstr "" diff --git a/plugins/Gravatar/locale/ar/LC_MESSAGES/Gravatar.po b/plugins/Gravatar/locale/ar/LC_MESSAGES/Gravatar.po deleted file mode 100644 index 0ffd7f7b20..0000000000 --- a/plugins/Gravatar/locale/ar/LC_MESSAGES/Gravatar.po +++ /dev/null @@ -1,25 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# -# Translators: -msgid "" -msgstr "" -"Project-Id-Version: GNU social\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-02-02 17:47+0100\n" -"PO-Revision-Date: 2015-02-06 16:27+0000\n" -"Last-Translator: FULL NAME \n" -"Language-Team: Arabic (http://www.transifex.com/projects/p/gnu-social/language/ar/)\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Language: ar\n" -"Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5;\n" - -#. TRANS: Plugin decsription. -#: GravatarPlugin.php:70 -msgid "" -"The Gravatar plugin allows users to use their Gravatar with StatusNet." -msgstr "" diff --git a/plugins/Gravatar/locale/arz/LC_MESSAGES/Gravatar.po b/plugins/Gravatar/locale/arz/LC_MESSAGES/Gravatar.po deleted file mode 100644 index 86ede50f6a..0000000000 --- a/plugins/Gravatar/locale/arz/LC_MESSAGES/Gravatar.po +++ /dev/null @@ -1,25 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# -# Translators: -msgid "" -msgstr "" -"Project-Id-Version: GNU social\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-02-02 17:47+0100\n" -"PO-Revision-Date: 2015-02-06 16:27+0000\n" -"Last-Translator: FULL NAME \n" -"Language-Team: Arabic (Egypt) (http://www.transifex.com/projects/p/gnu-social/language/ar_EG/)\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Language: ar_EG\n" -"Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5;\n" - -#. TRANS: Plugin decsription. -#: GravatarPlugin.php:70 -msgid "" -"The Gravatar plugin allows users to use their Gravatar with StatusNet." -msgstr "" diff --git a/plugins/Gravatar/locale/ast/LC_MESSAGES/Gravatar.po b/plugins/Gravatar/locale/ast/LC_MESSAGES/Gravatar.po deleted file mode 100644 index fe73afad4e..0000000000 --- a/plugins/Gravatar/locale/ast/LC_MESSAGES/Gravatar.po +++ /dev/null @@ -1,25 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# -# Translators: -msgid "" -msgstr "" -"Project-Id-Version: GNU social\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-02-02 17:47+0100\n" -"PO-Revision-Date: 2015-02-06 16:27+0000\n" -"Last-Translator: FULL NAME \n" -"Language-Team: Asturian (http://www.transifex.com/projects/p/gnu-social/language/ast/)\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Language: ast\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" - -#. TRANS: Plugin decsription. -#: GravatarPlugin.php:70 -msgid "" -"The Gravatar plugin allows users to use their Gravatar with StatusNet." -msgstr "" diff --git a/plugins/Gravatar/locale/be-tarask/LC_MESSAGES/Gravatar.po b/plugins/Gravatar/locale/be-tarask/LC_MESSAGES/Gravatar.po deleted file mode 100644 index b495ade1d3..0000000000 --- a/plugins/Gravatar/locale/be-tarask/LC_MESSAGES/Gravatar.po +++ /dev/null @@ -1,25 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# -# Translators: -msgid "" -msgstr "" -"Project-Id-Version: GNU social\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-02-02 17:47+0100\n" -"PO-Revision-Date: 2015-02-06 16:27+0000\n" -"Last-Translator: FULL NAME \n" -"Language-Team: Belarusian (Tarask) (http://www.transifex.com/projects/p/gnu-social/language/be@tarask/)\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Language: be@tarask\n" -"Plural-Forms: nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" - -#. TRANS: Plugin decsription. -#: GravatarPlugin.php:70 -msgid "" -"The Gravatar plugin allows users to use their Gravatar with StatusNet." -msgstr "" diff --git a/plugins/Gravatar/locale/bg/LC_MESSAGES/Gravatar.po b/plugins/Gravatar/locale/bg/LC_MESSAGES/Gravatar.po deleted file mode 100644 index 7cd09ef12a..0000000000 --- a/plugins/Gravatar/locale/bg/LC_MESSAGES/Gravatar.po +++ /dev/null @@ -1,25 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# -# Translators: -msgid "" -msgstr "" -"Project-Id-Version: GNU social\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-02-02 17:47+0100\n" -"PO-Revision-Date: 2015-02-06 16:27+0000\n" -"Last-Translator: FULL NAME \n" -"Language-Team: Bulgarian (http://www.transifex.com/projects/p/gnu-social/language/bg/)\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Language: bg\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" - -#. TRANS: Plugin decsription. -#: GravatarPlugin.php:70 -msgid "" -"The Gravatar plugin allows users to use their Gravatar with StatusNet." -msgstr "" diff --git a/plugins/Gravatar/locale/br/LC_MESSAGES/Gravatar.po b/plugins/Gravatar/locale/br/LC_MESSAGES/Gravatar.po deleted file mode 100644 index 92ab60af5f..0000000000 --- a/plugins/Gravatar/locale/br/LC_MESSAGES/Gravatar.po +++ /dev/null @@ -1,25 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# -# Translators: -msgid "" -msgstr "" -"Project-Id-Version: GNU social\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-02-02 17:47+0100\n" -"PO-Revision-Date: 2015-02-06 16:27+0000\n" -"Last-Translator: FULL NAME \n" -"Language-Team: Breton (http://www.transifex.com/projects/p/gnu-social/language/br/)\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Language: br\n" -"Plural-Forms: nplurals=2; plural=(n > 1);\n" - -#. TRANS: Plugin decsription. -#: GravatarPlugin.php:70 -msgid "" -"The Gravatar plugin allows users to use their Gravatar with StatusNet." -msgstr "" diff --git a/plugins/Gravatar/locale/ca/LC_MESSAGES/Gravatar.po b/plugins/Gravatar/locale/ca/LC_MESSAGES/Gravatar.po deleted file mode 100644 index 1191b6865d..0000000000 --- a/plugins/Gravatar/locale/ca/LC_MESSAGES/Gravatar.po +++ /dev/null @@ -1,25 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# -# Translators: -msgid "" -msgstr "" -"Project-Id-Version: GNU social\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-02-02 17:47+0100\n" -"PO-Revision-Date: 2015-02-06 16:43+0000\n" -"Last-Translator: digitaldreamer \n" -"Language-Team: Catalan (http://www.transifex.com/projects/p/gnu-social/language/ca/)\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Language: ca\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" - -#. TRANS: Plugin decsription. -#: GravatarPlugin.php:70 -msgid "" -"The Gravatar plugin allows users to use their Gravatar with StatusNet." -msgstr "El connector del Gravatar permet als usuaris fer servir llur Gravatar amb l'StatusNet." diff --git a/plugins/Gravatar/locale/cs/LC_MESSAGES/Gravatar.po b/plugins/Gravatar/locale/cs/LC_MESSAGES/Gravatar.po deleted file mode 100644 index 2ce5576e7b..0000000000 --- a/plugins/Gravatar/locale/cs/LC_MESSAGES/Gravatar.po +++ /dev/null @@ -1,25 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# -# Translators: -msgid "" -msgstr "" -"Project-Id-Version: GNU social\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-02-02 17:47+0100\n" -"PO-Revision-Date: 2015-02-06 16:27+0000\n" -"Last-Translator: FULL NAME \n" -"Language-Team: Czech (http://www.transifex.com/projects/p/gnu-social/language/cs/)\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Language: cs\n" -"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n" - -#. TRANS: Plugin decsription. -#: GravatarPlugin.php:70 -msgid "" -"The Gravatar plugin allows users to use their Gravatar with StatusNet." -msgstr "" diff --git a/plugins/Gravatar/locale/da/LC_MESSAGES/Gravatar.po b/plugins/Gravatar/locale/da/LC_MESSAGES/Gravatar.po deleted file mode 100644 index d47b755da9..0000000000 --- a/plugins/Gravatar/locale/da/LC_MESSAGES/Gravatar.po +++ /dev/null @@ -1,25 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# -# Translators: -msgid "" -msgstr "" -"Project-Id-Version: GNU social\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-02-02 17:47+0100\n" -"PO-Revision-Date: 2015-02-06 16:27+0000\n" -"Last-Translator: FULL NAME \n" -"Language-Team: Danish (http://www.transifex.com/projects/p/gnu-social/language/da/)\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Language: da\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" - -#. TRANS: Plugin decsription. -#: GravatarPlugin.php:70 -msgid "" -"The Gravatar plugin allows users to use their Gravatar with StatusNet." -msgstr "" diff --git a/plugins/Gravatar/locale/de/LC_MESSAGES/Gravatar.po b/plugins/Gravatar/locale/de/LC_MESSAGES/Gravatar.po deleted file mode 100644 index 625c20c533..0000000000 --- a/plugins/Gravatar/locale/de/LC_MESSAGES/Gravatar.po +++ /dev/null @@ -1,25 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# -# Translators: -msgid "" -msgstr "" -"Project-Id-Version: GNU social\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-02-02 17:47+0100\n" -"PO-Revision-Date: 2015-02-06 16:43+0000\n" -"Last-Translator: digitaldreamer \n" -"Language-Team: German (http://www.transifex.com/projects/p/gnu-social/language/de/)\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Language: de\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" - -#. TRANS: Plugin decsription. -#: GravatarPlugin.php:70 -msgid "" -"The Gravatar plugin allows users to use their Gravatar with StatusNet." -msgstr "Das Gravatar-Plugin erlaubt es Benutzern, ihr Gravatar mit StatusNet zu verwenden." diff --git a/plugins/Gravatar/locale/el/LC_MESSAGES/Gravatar.po b/plugins/Gravatar/locale/el/LC_MESSAGES/Gravatar.po deleted file mode 100644 index 021657de04..0000000000 --- a/plugins/Gravatar/locale/el/LC_MESSAGES/Gravatar.po +++ /dev/null @@ -1,25 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# -# Translators: -msgid "" -msgstr "" -"Project-Id-Version: GNU social\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-02-02 17:47+0100\n" -"PO-Revision-Date: 2015-02-06 16:27+0000\n" -"Last-Translator: FULL NAME \n" -"Language-Team: Greek (http://www.transifex.com/projects/p/gnu-social/language/el/)\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Language: el\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" - -#. TRANS: Plugin decsription. -#: GravatarPlugin.php:70 -msgid "" -"The Gravatar plugin allows users to use their Gravatar with StatusNet." -msgstr "" diff --git a/plugins/Gravatar/locale/en_GB/LC_MESSAGES/Gravatar.po b/plugins/Gravatar/locale/en_GB/LC_MESSAGES/Gravatar.po deleted file mode 100644 index 7bc45a1f9f..0000000000 --- a/plugins/Gravatar/locale/en_GB/LC_MESSAGES/Gravatar.po +++ /dev/null @@ -1,25 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# -# Translators: -msgid "" -msgstr "" -"Project-Id-Version: GNU social\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-02-02 17:47+0100\n" -"PO-Revision-Date: 2015-02-06 16:27+0000\n" -"Last-Translator: FULL NAME \n" -"Language-Team: English (United Kingdom) (http://www.transifex.com/projects/p/gnu-social/language/en_GB/)\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Language: en_GB\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" - -#. TRANS: Plugin decsription. -#: GravatarPlugin.php:70 -msgid "" -"The Gravatar plugin allows users to use their Gravatar with StatusNet." -msgstr "" diff --git a/plugins/Gravatar/locale/eo/LC_MESSAGES/Gravatar.po b/plugins/Gravatar/locale/eo/LC_MESSAGES/Gravatar.po deleted file mode 100644 index a955db7931..0000000000 --- a/plugins/Gravatar/locale/eo/LC_MESSAGES/Gravatar.po +++ /dev/null @@ -1,25 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# -# Translators: -msgid "" -msgstr "" -"Project-Id-Version: GNU social\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-02-02 17:47+0100\n" -"PO-Revision-Date: 2015-02-06 16:27+0000\n" -"Last-Translator: FULL NAME \n" -"Language-Team: Esperanto (http://www.transifex.com/projects/p/gnu-social/language/eo/)\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Language: eo\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" - -#. TRANS: Plugin decsription. -#: GravatarPlugin.php:70 -msgid "" -"The Gravatar plugin allows users to use their Gravatar with StatusNet." -msgstr "" diff --git a/plugins/Gravatar/locale/es/LC_MESSAGES/Gravatar.po b/plugins/Gravatar/locale/es/LC_MESSAGES/Gravatar.po deleted file mode 100644 index b289d4f47f..0000000000 --- a/plugins/Gravatar/locale/es/LC_MESSAGES/Gravatar.po +++ /dev/null @@ -1,26 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# -# Translators: -# Juan Riquelme González , 2015 -msgid "" -msgstr "" -"Project-Id-Version: GNU social\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-02-02 17:47+0100\n" -"PO-Revision-Date: 2015-02-27 12:21+0000\n" -"Last-Translator: Juan Riquelme González \n" -"Language-Team: Spanish (http://www.transifex.com/projects/p/gnu-social/language/es/)\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Language: es\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" - -#. TRANS: Plugin decsription. -#: GravatarPlugin.php:70 -msgid "" -"The Gravatar plugin allows users to use their Gravatar with StatusNet." -msgstr "El complemento Gravatar permite a los usuarios utilizar su Gravatar en GNU social." diff --git a/plugins/Gravatar/locale/eu/LC_MESSAGES/Gravatar.po b/plugins/Gravatar/locale/eu/LC_MESSAGES/Gravatar.po deleted file mode 100644 index bb87408ddd..0000000000 --- a/plugins/Gravatar/locale/eu/LC_MESSAGES/Gravatar.po +++ /dev/null @@ -1,25 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# -# Translators: -msgid "" -msgstr "" -"Project-Id-Version: GNU social\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-02-02 17:47+0100\n" -"PO-Revision-Date: 2015-02-06 16:43+0000\n" -"Last-Translator: digitaldreamer \n" -"Language-Team: Basque (http://www.transifex.com/projects/p/gnu-social/language/eu/)\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Language: eu\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" - -#. TRANS: Plugin decsription. -#: GravatarPlugin.php:70 -msgid "" -"The Gravatar plugin allows users to use their Gravatar with StatusNet." -msgstr "Gravatar pluginak erabiltzaileei heuren Gravatarra StatusNet-en erabiltzen uzten die." diff --git a/plugins/Gravatar/locale/fa/LC_MESSAGES/Gravatar.po b/plugins/Gravatar/locale/fa/LC_MESSAGES/Gravatar.po deleted file mode 100644 index c7ee433734..0000000000 --- a/plugins/Gravatar/locale/fa/LC_MESSAGES/Gravatar.po +++ /dev/null @@ -1,25 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# -# Translators: -msgid "" -msgstr "" -"Project-Id-Version: GNU social\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-02-02 17:47+0100\n" -"PO-Revision-Date: 2015-02-06 16:27+0000\n" -"Last-Translator: FULL NAME \n" -"Language-Team: Persian (http://www.transifex.com/projects/p/gnu-social/language/fa/)\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Language: fa\n" -"Plural-Forms: nplurals=1; plural=0;\n" - -#. TRANS: Plugin decsription. -#: GravatarPlugin.php:70 -msgid "" -"The Gravatar plugin allows users to use their Gravatar with StatusNet." -msgstr "" diff --git a/plugins/Gravatar/locale/fi/LC_MESSAGES/Gravatar.po b/plugins/Gravatar/locale/fi/LC_MESSAGES/Gravatar.po deleted file mode 100644 index 7b0e4e1c44..0000000000 --- a/plugins/Gravatar/locale/fi/LC_MESSAGES/Gravatar.po +++ /dev/null @@ -1,25 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# -# Translators: -msgid "" -msgstr "" -"Project-Id-Version: GNU social\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-02-02 17:47+0100\n" -"PO-Revision-Date: 2015-02-06 16:27+0000\n" -"Last-Translator: FULL NAME \n" -"Language-Team: Finnish (http://www.transifex.com/projects/p/gnu-social/language/fi/)\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Language: fi\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" - -#. TRANS: Plugin decsription. -#: GravatarPlugin.php:70 -msgid "" -"The Gravatar plugin allows users to use their Gravatar with StatusNet." -msgstr "" diff --git a/plugins/Gravatar/locale/fr/LC_MESSAGES/Gravatar.po b/plugins/Gravatar/locale/fr/LC_MESSAGES/Gravatar.po deleted file mode 100644 index c24e581db1..0000000000 --- a/plugins/Gravatar/locale/fr/LC_MESSAGES/Gravatar.po +++ /dev/null @@ -1,25 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# -# Translators: -msgid "" -msgstr "" -"Project-Id-Version: GNU social\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-02-02 17:47+0100\n" -"PO-Revision-Date: 2015-02-06 16:43+0000\n" -"Last-Translator: digitaldreamer \n" -"Language-Team: French (http://www.transifex.com/projects/p/gnu-social/language/fr/)\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Language: fr\n" -"Plural-Forms: nplurals=2; plural=(n > 1);\n" - -#. TRANS: Plugin decsription. -#: GravatarPlugin.php:70 -msgid "" -"The Gravatar plugin allows users to use their Gravatar with StatusNet." -msgstr "Le greffon Gravatar permet aux utilisateurs d’utiliser leur image Gravatar avec StatusNet." diff --git a/plugins/Gravatar/locale/fur/LC_MESSAGES/Gravatar.po b/plugins/Gravatar/locale/fur/LC_MESSAGES/Gravatar.po deleted file mode 100644 index 3cd3fdfa88..0000000000 --- a/plugins/Gravatar/locale/fur/LC_MESSAGES/Gravatar.po +++ /dev/null @@ -1,25 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# -# Translators: -msgid "" -msgstr "" -"Project-Id-Version: GNU social\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-02-02 17:47+0100\n" -"PO-Revision-Date: 2015-02-06 16:27+0000\n" -"Last-Translator: FULL NAME \n" -"Language-Team: Friulian (http://www.transifex.com/projects/p/gnu-social/language/fur/)\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Language: fur\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" - -#. TRANS: Plugin decsription. -#: GravatarPlugin.php:70 -msgid "" -"The Gravatar plugin allows users to use their Gravatar with StatusNet." -msgstr "" diff --git a/plugins/Gravatar/locale/gl/LC_MESSAGES/Gravatar.po b/plugins/Gravatar/locale/gl/LC_MESSAGES/Gravatar.po deleted file mode 100644 index 629918e81f..0000000000 --- a/plugins/Gravatar/locale/gl/LC_MESSAGES/Gravatar.po +++ /dev/null @@ -1,25 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# -# Translators: -msgid "" -msgstr "" -"Project-Id-Version: GNU social\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-02-02 17:47+0100\n" -"PO-Revision-Date: 2015-02-06 16:43+0000\n" -"Last-Translator: digitaldreamer \n" -"Language-Team: Galician (http://www.transifex.com/projects/p/gnu-social/language/gl/)\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Language: gl\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" - -#. TRANS: Plugin decsription. -#: GravatarPlugin.php:70 -msgid "" -"The Gravatar plugin allows users to use their Gravatar with StatusNet." -msgstr "O complemento Gravatar permite aos usuarios usar o seu Gravatar co StatusNet." diff --git a/plugins/Gravatar/locale/he/LC_MESSAGES/Gravatar.po b/plugins/Gravatar/locale/he/LC_MESSAGES/Gravatar.po deleted file mode 100644 index 475f35cefb..0000000000 --- a/plugins/Gravatar/locale/he/LC_MESSAGES/Gravatar.po +++ /dev/null @@ -1,25 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# -# Translators: -msgid "" -msgstr "" -"Project-Id-Version: GNU social\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-02-02 17:47+0100\n" -"PO-Revision-Date: 2015-02-06 16:43+0000\n" -"Last-Translator: digitaldreamer \n" -"Language-Team: Hebrew (http://www.transifex.com/projects/p/gnu-social/language/he/)\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Language: he\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" - -#. TRANS: Plugin decsription. -#: GravatarPlugin.php:70 -msgid "" -"The Gravatar plugin allows users to use their Gravatar with StatusNet." -msgstr "תוסף Gravatar מאפשר למשתמשים להציג את ה־Gravatar שלהם בסטטוסנט." diff --git a/plugins/Gravatar/locale/hsb/LC_MESSAGES/Gravatar.po b/plugins/Gravatar/locale/hsb/LC_MESSAGES/Gravatar.po deleted file mode 100644 index 63410e7686..0000000000 --- a/plugins/Gravatar/locale/hsb/LC_MESSAGES/Gravatar.po +++ /dev/null @@ -1,25 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# -# Translators: -msgid "" -msgstr "" -"Project-Id-Version: GNU social\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-02-02 17:47+0100\n" -"PO-Revision-Date: 2015-02-06 16:27+0000\n" -"Last-Translator: FULL NAME \n" -"Language-Team: Upper Sorbian (http://www.transifex.com/projects/p/gnu-social/language/hsb/)\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Language: hsb\n" -"Plural-Forms: nplurals=4; plural=(n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n%100==4 ? 2 : 3);\n" - -#. TRANS: Plugin decsription. -#: GravatarPlugin.php:70 -msgid "" -"The Gravatar plugin allows users to use their Gravatar with StatusNet." -msgstr "" diff --git a/plugins/Gravatar/locale/hu/LC_MESSAGES/Gravatar.po b/plugins/Gravatar/locale/hu/LC_MESSAGES/Gravatar.po deleted file mode 100644 index 16c5f1b3e1..0000000000 --- a/plugins/Gravatar/locale/hu/LC_MESSAGES/Gravatar.po +++ /dev/null @@ -1,25 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# -# Translators: -msgid "" -msgstr "" -"Project-Id-Version: GNU social\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-02-02 17:47+0100\n" -"PO-Revision-Date: 2015-02-06 16:27+0000\n" -"Last-Translator: FULL NAME \n" -"Language-Team: Hungarian (http://www.transifex.com/projects/p/gnu-social/language/hu/)\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Language: hu\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" - -#. TRANS: Plugin decsription. -#: GravatarPlugin.php:70 -msgid "" -"The Gravatar plugin allows users to use their Gravatar with StatusNet." -msgstr "" diff --git a/plugins/Gravatar/locale/ia/LC_MESSAGES/Gravatar.po b/plugins/Gravatar/locale/ia/LC_MESSAGES/Gravatar.po deleted file mode 100644 index 63ffdb969c..0000000000 --- a/plugins/Gravatar/locale/ia/LC_MESSAGES/Gravatar.po +++ /dev/null @@ -1,25 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# -# Translators: -msgid "" -msgstr "" -"Project-Id-Version: GNU social\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-02-02 17:47+0100\n" -"PO-Revision-Date: 2015-02-06 16:43+0000\n" -"Last-Translator: digitaldreamer \n" -"Language-Team: Interlingua (http://www.transifex.com/projects/p/gnu-social/language/ia/)\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Language: ia\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" - -#. TRANS: Plugin decsription. -#: GravatarPlugin.php:70 -msgid "" -"The Gravatar plugin allows users to use their Gravatar with StatusNet." -msgstr "Le plug-in Gravatar permitte al usatores de usar lor Gravatar con StatusNet." diff --git a/plugins/Gravatar/locale/id/LC_MESSAGES/Gravatar.po b/plugins/Gravatar/locale/id/LC_MESSAGES/Gravatar.po deleted file mode 100644 index 3c2b453d5e..0000000000 --- a/plugins/Gravatar/locale/id/LC_MESSAGES/Gravatar.po +++ /dev/null @@ -1,25 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# -# Translators: -msgid "" -msgstr "" -"Project-Id-Version: GNU social\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-02-02 17:47+0100\n" -"PO-Revision-Date: 2015-02-06 16:27+0000\n" -"Last-Translator: FULL NAME \n" -"Language-Team: Indonesian (http://www.transifex.com/projects/p/gnu-social/language/id/)\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Language: id\n" -"Plural-Forms: nplurals=1; plural=0;\n" - -#. TRANS: Plugin decsription. -#: GravatarPlugin.php:70 -msgid "" -"The Gravatar plugin allows users to use their Gravatar with StatusNet." -msgstr "" diff --git a/plugins/Gravatar/locale/is/LC_MESSAGES/Gravatar.po b/plugins/Gravatar/locale/is/LC_MESSAGES/Gravatar.po deleted file mode 100644 index 3da39d3ca5..0000000000 --- a/plugins/Gravatar/locale/is/LC_MESSAGES/Gravatar.po +++ /dev/null @@ -1,25 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# -# Translators: -msgid "" -msgstr "" -"Project-Id-Version: GNU social\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-02-02 17:47+0100\n" -"PO-Revision-Date: 2015-02-06 16:27+0000\n" -"Last-Translator: FULL NAME \n" -"Language-Team: Icelandic (http://www.transifex.com/projects/p/gnu-social/language/is/)\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Language: is\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" - -#. TRANS: Plugin decsription. -#: GravatarPlugin.php:70 -msgid "" -"The Gravatar plugin allows users to use their Gravatar with StatusNet." -msgstr "" diff --git a/plugins/Gravatar/locale/it/LC_MESSAGES/Gravatar.po b/plugins/Gravatar/locale/it/LC_MESSAGES/Gravatar.po deleted file mode 100644 index 5793afcb7b..0000000000 --- a/plugins/Gravatar/locale/it/LC_MESSAGES/Gravatar.po +++ /dev/null @@ -1,25 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# -# Translators: -msgid "" -msgstr "" -"Project-Id-Version: GNU social\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-02-02 17:47+0100\n" -"PO-Revision-Date: 2015-02-06 16:43+0000\n" -"Last-Translator: digitaldreamer \n" -"Language-Team: Italian (http://www.transifex.com/projects/p/gnu-social/language/it/)\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Language: it\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" - -#. TRANS: Plugin decsription. -#: GravatarPlugin.php:70 -msgid "" -"The Gravatar plugin allows users to use their Gravatar with StatusNet." -msgstr "Il plugin Gravatar consente agli utenti di utilizzare i loro Gravatar con StatusNet." diff --git a/plugins/Gravatar/locale/ja/LC_MESSAGES/Gravatar.po b/plugins/Gravatar/locale/ja/LC_MESSAGES/Gravatar.po deleted file mode 100644 index 53263e5f95..0000000000 --- a/plugins/Gravatar/locale/ja/LC_MESSAGES/Gravatar.po +++ /dev/null @@ -1,25 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# -# Translators: -msgid "" -msgstr "" -"Project-Id-Version: GNU social\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-02-02 17:47+0100\n" -"PO-Revision-Date: 2015-02-06 16:27+0000\n" -"Last-Translator: FULL NAME \n" -"Language-Team: Japanese (http://www.transifex.com/projects/p/gnu-social/language/ja/)\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Language: ja\n" -"Plural-Forms: nplurals=1; plural=0;\n" - -#. TRANS: Plugin decsription. -#: GravatarPlugin.php:70 -msgid "" -"The Gravatar plugin allows users to use their Gravatar with StatusNet." -msgstr "" diff --git a/plugins/Gravatar/locale/ka/LC_MESSAGES/Gravatar.po b/plugins/Gravatar/locale/ka/LC_MESSAGES/Gravatar.po deleted file mode 100644 index 19511461c8..0000000000 --- a/plugins/Gravatar/locale/ka/LC_MESSAGES/Gravatar.po +++ /dev/null @@ -1,25 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# -# Translators: -msgid "" -msgstr "" -"Project-Id-Version: GNU social\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-02-02 17:47+0100\n" -"PO-Revision-Date: 2015-02-06 16:27+0000\n" -"Last-Translator: FULL NAME \n" -"Language-Team: Georgian (http://www.transifex.com/projects/p/gnu-social/language/ka/)\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Language: ka\n" -"Plural-Forms: nplurals=1; plural=0;\n" - -#. TRANS: Plugin decsription. -#: GravatarPlugin.php:70 -msgid "" -"The Gravatar plugin allows users to use their Gravatar with StatusNet." -msgstr "" diff --git a/plugins/Gravatar/locale/ko/LC_MESSAGES/Gravatar.po b/plugins/Gravatar/locale/ko/LC_MESSAGES/Gravatar.po deleted file mode 100644 index cde819b26d..0000000000 --- a/plugins/Gravatar/locale/ko/LC_MESSAGES/Gravatar.po +++ /dev/null @@ -1,25 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# -# Translators: -msgid "" -msgstr "" -"Project-Id-Version: GNU social\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-02-02 17:47+0100\n" -"PO-Revision-Date: 2015-02-06 16:27+0000\n" -"Last-Translator: FULL NAME \n" -"Language-Team: Korean (http://www.transifex.com/projects/p/gnu-social/language/ko/)\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Language: ko\n" -"Plural-Forms: nplurals=1; plural=0;\n" - -#. TRANS: Plugin decsription. -#: GravatarPlugin.php:70 -msgid "" -"The Gravatar plugin allows users to use their Gravatar with StatusNet." -msgstr "" diff --git a/plugins/Gravatar/locale/ksh/LC_MESSAGES/Gravatar.po b/plugins/Gravatar/locale/ksh/LC_MESSAGES/Gravatar.po deleted file mode 100644 index 2212303688..0000000000 --- a/plugins/Gravatar/locale/ksh/LC_MESSAGES/Gravatar.po +++ /dev/null @@ -1,25 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# -# Translators: -msgid "" -msgstr "" -"Project-Id-Version: GNU social\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-02-02 17:47+0100\n" -"PO-Revision-Date: 2015-02-06 16:27+0000\n" -"Last-Translator: FULL NAME \n" -"Language-Team: Colognian (http://www.transifex.com/projects/p/gnu-social/language/ksh/)\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Language: ksh\n" -"Plural-Forms: nplurals=3; plural=(n==0) ? 0 : (n==1) ? 1 : 2;\n" - -#. TRANS: Plugin decsription. -#: GravatarPlugin.php:70 -msgid "" -"The Gravatar plugin allows users to use their Gravatar with StatusNet." -msgstr "" diff --git a/plugins/Gravatar/locale/lb/LC_MESSAGES/Gravatar.po b/plugins/Gravatar/locale/lb/LC_MESSAGES/Gravatar.po deleted file mode 100644 index dd0a27f64b..0000000000 --- a/plugins/Gravatar/locale/lb/LC_MESSAGES/Gravatar.po +++ /dev/null @@ -1,25 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# -# Translators: -msgid "" -msgstr "" -"Project-Id-Version: GNU social\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-02-02 17:47+0100\n" -"PO-Revision-Date: 2015-02-06 16:27+0000\n" -"Last-Translator: FULL NAME \n" -"Language-Team: Luxembourgish (http://www.transifex.com/projects/p/gnu-social/language/lb/)\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Language: lb\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" - -#. TRANS: Plugin decsription. -#: GravatarPlugin.php:70 -msgid "" -"The Gravatar plugin allows users to use their Gravatar with StatusNet." -msgstr "" diff --git a/plugins/Gravatar/locale/lt/LC_MESSAGES/Gravatar.po b/plugins/Gravatar/locale/lt/LC_MESSAGES/Gravatar.po deleted file mode 100644 index be4f8879d9..0000000000 --- a/plugins/Gravatar/locale/lt/LC_MESSAGES/Gravatar.po +++ /dev/null @@ -1,25 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# -# Translators: -msgid "" -msgstr "" -"Project-Id-Version: GNU social\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-02-02 17:47+0100\n" -"PO-Revision-Date: 2015-02-06 16:27+0000\n" -"Last-Translator: FULL NAME \n" -"Language-Team: Lithuanian (http://www.transifex.com/projects/p/gnu-social/language/lt/)\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Language: lt\n" -"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && (n%100<10 || n%100>=20) ? 1 : 2);\n" - -#. TRANS: Plugin decsription. -#: GravatarPlugin.php:70 -msgid "" -"The Gravatar plugin allows users to use their Gravatar with StatusNet." -msgstr "" diff --git a/plugins/Gravatar/locale/lv/LC_MESSAGES/Gravatar.po b/plugins/Gravatar/locale/lv/LC_MESSAGES/Gravatar.po deleted file mode 100644 index 370e8f7f4d..0000000000 --- a/plugins/Gravatar/locale/lv/LC_MESSAGES/Gravatar.po +++ /dev/null @@ -1,25 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# -# Translators: -msgid "" -msgstr "" -"Project-Id-Version: GNU social\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-02-02 17:47+0100\n" -"PO-Revision-Date: 2015-02-07 09:39+0000\n" -"Last-Translator: digitaldreamer \n" -"Language-Team: Latvian (http://www.transifex.com/projects/p/gnu-social/language/lv/)\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Language: lv\n" -"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n != 0 ? 1 : 2);\n" - -#. TRANS: Plugin decsription. -#: GravatarPlugin.php:70 -msgid "" -"The Gravatar plugin allows users to use their Gravatar with StatusNet." -msgstr "" diff --git a/plugins/Gravatar/locale/mg/LC_MESSAGES/Gravatar.po b/plugins/Gravatar/locale/mg/LC_MESSAGES/Gravatar.po deleted file mode 100644 index 1f3889e434..0000000000 --- a/plugins/Gravatar/locale/mg/LC_MESSAGES/Gravatar.po +++ /dev/null @@ -1,25 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# -# Translators: -msgid "" -msgstr "" -"Project-Id-Version: GNU social\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-02-02 17:47+0100\n" -"PO-Revision-Date: 2015-02-06 16:27+0000\n" -"Last-Translator: FULL NAME \n" -"Language-Team: Malagasy (http://www.transifex.com/projects/p/gnu-social/language/mg/)\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Language: mg\n" -"Plural-Forms: nplurals=2; plural=(n > 1);\n" - -#. TRANS: Plugin decsription. -#: GravatarPlugin.php:70 -msgid "" -"The Gravatar plugin allows users to use their Gravatar with StatusNet." -msgstr "" diff --git a/plugins/Gravatar/locale/mk/LC_MESSAGES/Gravatar.po b/plugins/Gravatar/locale/mk/LC_MESSAGES/Gravatar.po deleted file mode 100644 index 14015f3948..0000000000 --- a/plugins/Gravatar/locale/mk/LC_MESSAGES/Gravatar.po +++ /dev/null @@ -1,25 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# -# Translators: -msgid "" -msgstr "" -"Project-Id-Version: GNU social\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-02-02 17:47+0100\n" -"PO-Revision-Date: 2015-02-06 16:43+0000\n" -"Last-Translator: digitaldreamer \n" -"Language-Team: Macedonian (http://www.transifex.com/projects/p/gnu-social/language/mk/)\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Language: mk\n" -"Plural-Forms: nplurals=2; plural=(n % 10 == 1 && n % 100 != 11) ? 0 : 1;\n" - -#. TRANS: Plugin decsription. -#: GravatarPlugin.php:70 -msgid "" -"The Gravatar plugin allows users to use their Gravatar with StatusNet." -msgstr "Приклучокот Gravatar им овозможува на корисниците да го користат својот Gravatar со StatusNet." diff --git a/plugins/Gravatar/locale/ml/LC_MESSAGES/Gravatar.po b/plugins/Gravatar/locale/ml/LC_MESSAGES/Gravatar.po deleted file mode 100644 index 71920fd8dc..0000000000 --- a/plugins/Gravatar/locale/ml/LC_MESSAGES/Gravatar.po +++ /dev/null @@ -1,25 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# -# Translators: -msgid "" -msgstr "" -"Project-Id-Version: GNU social\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-02-02 17:47+0100\n" -"PO-Revision-Date: 2015-02-06 16:27+0000\n" -"Last-Translator: FULL NAME \n" -"Language-Team: Malayalam (http://www.transifex.com/projects/p/gnu-social/language/ml/)\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Language: ml\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" - -#. TRANS: Plugin decsription. -#: GravatarPlugin.php:70 -msgid "" -"The Gravatar plugin allows users to use their Gravatar with StatusNet." -msgstr "" diff --git a/plugins/Gravatar/locale/ms/LC_MESSAGES/Gravatar.po b/plugins/Gravatar/locale/ms/LC_MESSAGES/Gravatar.po deleted file mode 100644 index 2bcaa63925..0000000000 --- a/plugins/Gravatar/locale/ms/LC_MESSAGES/Gravatar.po +++ /dev/null @@ -1,25 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# -# Translators: -msgid "" -msgstr "" -"Project-Id-Version: GNU social\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-02-02 17:47+0100\n" -"PO-Revision-Date: 2015-02-06 16:27+0000\n" -"Last-Translator: FULL NAME \n" -"Language-Team: Malay (http://www.transifex.com/projects/p/gnu-social/language/ms/)\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Language: ms\n" -"Plural-Forms: nplurals=1; plural=0;\n" - -#. TRANS: Plugin decsription. -#: GravatarPlugin.php:70 -msgid "" -"The Gravatar plugin allows users to use their Gravatar with StatusNet." -msgstr "" diff --git a/plugins/Gravatar/locale/my/LC_MESSAGES/Gravatar.po b/plugins/Gravatar/locale/my/LC_MESSAGES/Gravatar.po deleted file mode 100644 index 2bd1d77cd5..0000000000 --- a/plugins/Gravatar/locale/my/LC_MESSAGES/Gravatar.po +++ /dev/null @@ -1,25 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# -# Translators: -msgid "" -msgstr "" -"Project-Id-Version: GNU social\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-02-02 17:47+0100\n" -"PO-Revision-Date: 2015-02-06 16:27+0000\n" -"Last-Translator: FULL NAME \n" -"Language-Team: Burmese (http://www.transifex.com/projects/p/gnu-social/language/my/)\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Language: my\n" -"Plural-Forms: nplurals=1; plural=0;\n" - -#. TRANS: Plugin decsription. -#: GravatarPlugin.php:70 -msgid "" -"The Gravatar plugin allows users to use their Gravatar with StatusNet." -msgstr "" diff --git a/plugins/Gravatar/locale/nb/LC_MESSAGES/Gravatar.po b/plugins/Gravatar/locale/nb/LC_MESSAGES/Gravatar.po deleted file mode 100644 index 5bfca90a5f..0000000000 --- a/plugins/Gravatar/locale/nb/LC_MESSAGES/Gravatar.po +++ /dev/null @@ -1,25 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# -# Translators: -msgid "" -msgstr "" -"Project-Id-Version: GNU social\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-02-02 17:47+0100\n" -"PO-Revision-Date: 2015-02-06 16:27+0000\n" -"Last-Translator: FULL NAME \n" -"Language-Team: Norwegian Bokmål (http://www.transifex.com/projects/p/gnu-social/language/nb/)\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Language: nb\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" - -#. TRANS: Plugin decsription. -#: GravatarPlugin.php:70 -msgid "" -"The Gravatar plugin allows users to use their Gravatar with StatusNet." -msgstr "" diff --git a/plugins/Gravatar/locale/ne/LC_MESSAGES/Gravatar.po b/plugins/Gravatar/locale/ne/LC_MESSAGES/Gravatar.po deleted file mode 100644 index 0a8a3f54eb..0000000000 --- a/plugins/Gravatar/locale/ne/LC_MESSAGES/Gravatar.po +++ /dev/null @@ -1,25 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# -# Translators: -msgid "" -msgstr "" -"Project-Id-Version: GNU social\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-02-02 17:47+0100\n" -"PO-Revision-Date: 2015-02-07 09:30+0000\n" -"Last-Translator: digitaldreamer \n" -"Language-Team: Nepali (http://www.transifex.com/projects/p/gnu-social/language/ne/)\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Language: ne\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" - -#. TRANS: Plugin decsription. -#: GravatarPlugin.php:70 -msgid "" -"The Gravatar plugin allows users to use their Gravatar with StatusNet." -msgstr "" diff --git a/plugins/Gravatar/locale/nl/LC_MESSAGES/Gravatar.po b/plugins/Gravatar/locale/nl/LC_MESSAGES/Gravatar.po deleted file mode 100644 index 39339a349b..0000000000 --- a/plugins/Gravatar/locale/nl/LC_MESSAGES/Gravatar.po +++ /dev/null @@ -1,25 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# -# Translators: -msgid "" -msgstr "" -"Project-Id-Version: GNU social\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-02-02 17:47+0100\n" -"PO-Revision-Date: 2015-02-06 16:43+0000\n" -"Last-Translator: digitaldreamer \n" -"Language-Team: Dutch (http://www.transifex.com/projects/p/gnu-social/language/nl/)\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Language: nl\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" - -#. TRANS: Plugin decsription. -#: GravatarPlugin.php:70 -msgid "" -"The Gravatar plugin allows users to use their Gravatar with StatusNet." -msgstr "De plug-in Gravatar maak het mogelijk dat gebruikers hun Gravatar gebruiken in StatusNet." diff --git a/plugins/Gravatar/locale/nn/LC_MESSAGES/Gravatar.po b/plugins/Gravatar/locale/nn/LC_MESSAGES/Gravatar.po deleted file mode 100644 index 6c7a1ecd8e..0000000000 --- a/plugins/Gravatar/locale/nn/LC_MESSAGES/Gravatar.po +++ /dev/null @@ -1,25 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# -# Translators: -msgid "" -msgstr "" -"Project-Id-Version: GNU social\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-02-02 17:47+0100\n" -"PO-Revision-Date: 2015-02-06 16:27+0000\n" -"Last-Translator: FULL NAME \n" -"Language-Team: Norwegian Nynorsk (http://www.transifex.com/projects/p/gnu-social/language/nn/)\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Language: nn\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" - -#. TRANS: Plugin decsription. -#: GravatarPlugin.php:70 -msgid "" -"The Gravatar plugin allows users to use their Gravatar with StatusNet." -msgstr "" diff --git a/plugins/Gravatar/locale/pl/LC_MESSAGES/Gravatar.po b/plugins/Gravatar/locale/pl/LC_MESSAGES/Gravatar.po deleted file mode 100644 index 4bf9e1ab4a..0000000000 --- a/plugins/Gravatar/locale/pl/LC_MESSAGES/Gravatar.po +++ /dev/null @@ -1,25 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# -# Translators: -msgid "" -msgstr "" -"Project-Id-Version: GNU social\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-02-02 17:47+0100\n" -"PO-Revision-Date: 2015-02-06 16:43+0000\n" -"Last-Translator: digitaldreamer \n" -"Language-Team: Polish (http://www.transifex.com/projects/p/gnu-social/language/pl/)\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Language: pl\n" -"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" - -#. TRANS: Plugin decsription. -#: GravatarPlugin.php:70 -msgid "" -"The Gravatar plugin allows users to use their Gravatar with StatusNet." -msgstr "Wtyczka Gravatar umożliwia użytkownikom używanie obrazów Gravatar w StatusNet." diff --git a/plugins/Gravatar/locale/pt/LC_MESSAGES/Gravatar.po b/plugins/Gravatar/locale/pt/LC_MESSAGES/Gravatar.po deleted file mode 100644 index 50b36f6d3e..0000000000 --- a/plugins/Gravatar/locale/pt/LC_MESSAGES/Gravatar.po +++ /dev/null @@ -1,25 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# -# Translators: -msgid "" -msgstr "" -"Project-Id-Version: GNU social\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-02-02 17:47+0100\n" -"PO-Revision-Date: 2015-02-06 16:43+0000\n" -"Last-Translator: digitaldreamer \n" -"Language-Team: Portuguese (http://www.transifex.com/projects/p/gnu-social/language/pt/)\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Language: pt\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" - -#. TRANS: Plugin decsription. -#: GravatarPlugin.php:70 -msgid "" -"The Gravatar plugin allows users to use their Gravatar with StatusNet." -msgstr "O plugin Gravatar permite que os utilizadores usem o seu Gravatar com o StatusNet." diff --git a/plugins/Gravatar/locale/pt_BR/LC_MESSAGES/Gravatar.po b/plugins/Gravatar/locale/pt_BR/LC_MESSAGES/Gravatar.po deleted file mode 100644 index 3bd93e4ceb..0000000000 --- a/plugins/Gravatar/locale/pt_BR/LC_MESSAGES/Gravatar.po +++ /dev/null @@ -1,25 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# -# Translators: -msgid "" -msgstr "" -"Project-Id-Version: GNU social\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-02-02 17:47+0100\n" -"PO-Revision-Date: 2015-02-06 16:27+0000\n" -"Last-Translator: FULL NAME \n" -"Language-Team: Portuguese (Brazil) (http://www.transifex.com/projects/p/gnu-social/language/pt_BR/)\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Language: pt_BR\n" -"Plural-Forms: nplurals=2; plural=(n > 1);\n" - -#. TRANS: Plugin decsription. -#: GravatarPlugin.php:70 -msgid "" -"The Gravatar plugin allows users to use their Gravatar with StatusNet." -msgstr "" diff --git a/plugins/Gravatar/locale/ru/LC_MESSAGES/Gravatar.po b/plugins/Gravatar/locale/ru/LC_MESSAGES/Gravatar.po deleted file mode 100644 index 1f304ef9ca..0000000000 --- a/plugins/Gravatar/locale/ru/LC_MESSAGES/Gravatar.po +++ /dev/null @@ -1,25 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# -# Translators: -msgid "" -msgstr "" -"Project-Id-Version: GNU social\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-02-02 17:47+0100\n" -"PO-Revision-Date: 2015-02-06 16:27+0000\n" -"Last-Translator: FULL NAME \n" -"Language-Team: Russian (http://www.transifex.com/projects/p/gnu-social/language/ru/)\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Language: ru\n" -"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" - -#. TRANS: Plugin decsription. -#: GravatarPlugin.php:70 -msgid "" -"The Gravatar plugin allows users to use their Gravatar with StatusNet." -msgstr "" diff --git a/plugins/Gravatar/locale/sr-ec/LC_MESSAGES/Gravatar.po b/plugins/Gravatar/locale/sr-ec/LC_MESSAGES/Gravatar.po deleted file mode 100644 index 32a78b636a..0000000000 --- a/plugins/Gravatar/locale/sr-ec/LC_MESSAGES/Gravatar.po +++ /dev/null @@ -1,25 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# -# Translators: -msgid "" -msgstr "" -"Project-Id-Version: GNU social\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-02-02 17:47+0100\n" -"PO-Revision-Date: 2015-02-06 16:27+0000\n" -"Last-Translator: FULL NAME \n" -"Language-Team: Serbian (http://www.transifex.com/projects/p/gnu-social/language/sr/)\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Language: sr\n" -"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" - -#. TRANS: Plugin decsription. -#: GravatarPlugin.php:70 -msgid "" -"The Gravatar plugin allows users to use their Gravatar with StatusNet." -msgstr "" diff --git a/plugins/Gravatar/locale/sv/LC_MESSAGES/Gravatar.po b/plugins/Gravatar/locale/sv/LC_MESSAGES/Gravatar.po deleted file mode 100644 index a3f459f741..0000000000 --- a/plugins/Gravatar/locale/sv/LC_MESSAGES/Gravatar.po +++ /dev/null @@ -1,25 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# -# Translators: -msgid "" -msgstr "" -"Project-Id-Version: GNU social\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-02-02 17:47+0100\n" -"PO-Revision-Date: 2015-02-06 16:43+0000\n" -"Last-Translator: digitaldreamer \n" -"Language-Team: Swedish (http://www.transifex.com/projects/p/gnu-social/language/sv/)\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Language: sv\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" - -#. TRANS: Plugin decsription. -#: GravatarPlugin.php:70 -msgid "" -"The Gravatar plugin allows users to use their Gravatar with StatusNet." -msgstr "Gravatar-tillägget låter användare använda deras Gravatar med StatusNet." diff --git a/plugins/Gravatar/locale/ta/LC_MESSAGES/Gravatar.po b/plugins/Gravatar/locale/ta/LC_MESSAGES/Gravatar.po deleted file mode 100644 index c5b05969b4..0000000000 --- a/plugins/Gravatar/locale/ta/LC_MESSAGES/Gravatar.po +++ /dev/null @@ -1,25 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# -# Translators: -msgid "" -msgstr "" -"Project-Id-Version: GNU social\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-02-02 17:47+0100\n" -"PO-Revision-Date: 2015-02-07 08:48+0000\n" -"Last-Translator: digitaldreamer \n" -"Language-Team: Tamil (http://www.transifex.com/projects/p/gnu-social/language/ta/)\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Language: ta\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" - -#. TRANS: Plugin decsription. -#: GravatarPlugin.php:70 -msgid "" -"The Gravatar plugin allows users to use their Gravatar with StatusNet." -msgstr "" diff --git a/plugins/Gravatar/locale/te/LC_MESSAGES/Gravatar.po b/plugins/Gravatar/locale/te/LC_MESSAGES/Gravatar.po deleted file mode 100644 index f842abd66d..0000000000 --- a/plugins/Gravatar/locale/te/LC_MESSAGES/Gravatar.po +++ /dev/null @@ -1,25 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# -# Translators: -msgid "" -msgstr "" -"Project-Id-Version: GNU social\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-02-02 17:47+0100\n" -"PO-Revision-Date: 2015-02-06 16:27+0000\n" -"Last-Translator: FULL NAME \n" -"Language-Team: Telugu (http://www.transifex.com/projects/p/gnu-social/language/te/)\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Language: te\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" - -#. TRANS: Plugin decsription. -#: GravatarPlugin.php:70 -msgid "" -"The Gravatar plugin allows users to use their Gravatar with StatusNet." -msgstr "" diff --git a/plugins/Gravatar/locale/tl/LC_MESSAGES/Gravatar.po b/plugins/Gravatar/locale/tl/LC_MESSAGES/Gravatar.po deleted file mode 100644 index 76efd0d06f..0000000000 --- a/plugins/Gravatar/locale/tl/LC_MESSAGES/Gravatar.po +++ /dev/null @@ -1,25 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# -# Translators: -msgid "" -msgstr "" -"Project-Id-Version: GNU social\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-02-02 17:47+0100\n" -"PO-Revision-Date: 2015-02-06 16:43+0000\n" -"Last-Translator: digitaldreamer \n" -"Language-Team: Tagalog (http://www.transifex.com/projects/p/gnu-social/language/tl/)\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Language: tl\n" -"Plural-Forms: nplurals=2; plural=(n > 1);\n" - -#. TRANS: Plugin decsription. -#: GravatarPlugin.php:70 -msgid "" -"The Gravatar plugin allows users to use their Gravatar with StatusNet." -msgstr "Ang pamasak na Gravatar ay nagpapahintulot sa mga tagagamit na gamitin ang kanilang Gravatar na may StatusNet." diff --git a/plugins/Gravatar/locale/tr/LC_MESSAGES/Gravatar.po b/plugins/Gravatar/locale/tr/LC_MESSAGES/Gravatar.po deleted file mode 100644 index afd815239e..0000000000 --- a/plugins/Gravatar/locale/tr/LC_MESSAGES/Gravatar.po +++ /dev/null @@ -1,25 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# -# Translators: -msgid "" -msgstr "" -"Project-Id-Version: GNU social\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-02-02 17:47+0100\n" -"PO-Revision-Date: 2015-02-06 16:27+0000\n" -"Last-Translator: FULL NAME \n" -"Language-Team: Turkish (http://www.transifex.com/projects/p/gnu-social/language/tr/)\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Language: tr\n" -"Plural-Forms: nplurals=2; plural=(n > 1);\n" - -#. TRANS: Plugin decsription. -#: GravatarPlugin.php:70 -msgid "" -"The Gravatar plugin allows users to use their Gravatar with StatusNet." -msgstr "" diff --git a/plugins/Gravatar/locale/uk/LC_MESSAGES/Gravatar.po b/plugins/Gravatar/locale/uk/LC_MESSAGES/Gravatar.po deleted file mode 100644 index c84ec1db82..0000000000 --- a/plugins/Gravatar/locale/uk/LC_MESSAGES/Gravatar.po +++ /dev/null @@ -1,25 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# -# Translators: -msgid "" -msgstr "" -"Project-Id-Version: GNU social\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-02-02 17:47+0100\n" -"PO-Revision-Date: 2015-02-06 16:43+0000\n" -"Last-Translator: digitaldreamer \n" -"Language-Team: Ukrainian (http://www.transifex.com/projects/p/gnu-social/language/uk/)\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Language: uk\n" -"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" - -#. TRANS: Plugin decsription. -#: GravatarPlugin.php:70 -msgid "" -"The Gravatar plugin allows users to use their Gravatar with StatusNet." -msgstr "Додаток Gravatar дозволяє користувачам встановлювати аватарки з Gravatar для сайту StatusNet." diff --git a/plugins/Gravatar/locale/ur_PK/LC_MESSAGES/Gravatar.po b/plugins/Gravatar/locale/ur_PK/LC_MESSAGES/Gravatar.po deleted file mode 100644 index f7de61f290..0000000000 --- a/plugins/Gravatar/locale/ur_PK/LC_MESSAGES/Gravatar.po +++ /dev/null @@ -1,25 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# -# Translators: -msgid "" -msgstr "" -"Project-Id-Version: GNU social\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-02-02 17:47+0100\n" -"PO-Revision-Date: 2015-02-06 16:27+0000\n" -"Last-Translator: FULL NAME \n" -"Language-Team: Urdu (Pakistan) (http://www.transifex.com/projects/p/gnu-social/language/ur_PK/)\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Language: ur_PK\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" - -#. TRANS: Plugin decsription. -#: GravatarPlugin.php:70 -msgid "" -"The Gravatar plugin allows users to use their Gravatar with StatusNet." -msgstr "" diff --git a/plugins/Gravatar/locale/vi/LC_MESSAGES/Gravatar.po b/plugins/Gravatar/locale/vi/LC_MESSAGES/Gravatar.po deleted file mode 100644 index 0cdfdcc657..0000000000 --- a/plugins/Gravatar/locale/vi/LC_MESSAGES/Gravatar.po +++ /dev/null @@ -1,25 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# -# Translators: -msgid "" -msgstr "" -"Project-Id-Version: GNU social\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-02-02 17:47+0100\n" -"PO-Revision-Date: 2015-02-06 16:27+0000\n" -"Last-Translator: FULL NAME \n" -"Language-Team: Vietnamese (http://www.transifex.com/projects/p/gnu-social/language/vi/)\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Language: vi\n" -"Plural-Forms: nplurals=1; plural=0;\n" - -#. TRANS: Plugin decsription. -#: GravatarPlugin.php:70 -msgid "" -"The Gravatar plugin allows users to use their Gravatar with StatusNet." -msgstr "" diff --git a/plugins/Gravatar/locale/zh_CN/LC_MESSAGES/Gravatar.po b/plugins/Gravatar/locale/zh_CN/LC_MESSAGES/Gravatar.po deleted file mode 100644 index 8a2a5c68bd..0000000000 --- a/plugins/Gravatar/locale/zh_CN/LC_MESSAGES/Gravatar.po +++ /dev/null @@ -1,25 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# -# Translators: -msgid "" -msgstr "" -"Project-Id-Version: GNU social\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-02-02 17:47+0100\n" -"PO-Revision-Date: 2015-02-06 16:43+0000\n" -"Last-Translator: digitaldreamer \n" -"Language-Team: Chinese (China) (http://www.transifex.com/projects/p/gnu-social/language/zh_CN/)\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Language: zh_CN\n" -"Plural-Forms: nplurals=1; plural=0;\n" - -#. TRANS: Plugin decsription. -#: GravatarPlugin.php:70 -msgid "" -"The Gravatar plugin allows users to use their Gravatar with StatusNet." -msgstr "Gravatar 插件可以让用户在 StatusNet 站点使用自己的 Gravatar。" diff --git a/plugins/Gravatar/locale/zh_TW/LC_MESSAGES/Gravatar.po b/plugins/Gravatar/locale/zh_TW/LC_MESSAGES/Gravatar.po deleted file mode 100644 index 2a603fff53..0000000000 --- a/plugins/Gravatar/locale/zh_TW/LC_MESSAGES/Gravatar.po +++ /dev/null @@ -1,25 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# -# Translators: -msgid "" -msgstr "" -"Project-Id-Version: GNU social\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-02-02 17:47+0100\n" -"PO-Revision-Date: 2015-02-06 16:27+0000\n" -"Last-Translator: FULL NAME \n" -"Language-Team: Chinese (Taiwan) (http://www.transifex.com/projects/p/gnu-social/language/zh_TW/)\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Language: zh_TW\n" -"Plural-Forms: nplurals=1; plural=0;\n" - -#. TRANS: Plugin decsription. -#: GravatarPlugin.php:70 -msgid "" -"The Gravatar plugin allows users to use their Gravatar with StatusNet." -msgstr "" diff --git a/plugins/Mapstraction/actions/map.php b/plugins/Mapstraction/actions/map.php index be59f5ba0b..48861af994 100644 --- a/plugins/Mapstraction/actions/map.php +++ b/plugins/Mapstraction/actions/map.php @@ -120,9 +120,11 @@ class MapAction extends Action $jsonArray = array(); while ($this->notice->fetch()) { - if (!empty($this->notice->lat) && !empty($this->notice->lon)) { - $jsonNotice = $this->noticeAsJson($this->notice); - $jsonArray[] = $jsonNotice; + try { + $notloc = Notice_location::locFromStored($this->notice); + $jsonArray[] = $this->noticeAsJson($this->notice); + } catch (ServerException $e) { + // no location data } } diff --git a/plugins/ModLog/ModLogPlugin.php b/plugins/ModLog/ModLogPlugin.php index 32c96be0e8..d1e01ca849 100644 --- a/plugins/ModLog/ModLogPlugin.php +++ b/plugins/ModLog/ModLogPlugin.php @@ -101,10 +101,10 @@ class ModLogPlugin extends Plugin $modlog->profile_id = $profile->id; - $cur = common_current_user(); + $scoped = Profile::current(); - if (!empty($cur)) { - $modlog->moderator_id = $cur->id; + if ($scoped instanceof Profile) { + $modlog->moderator_id = $scoped->getID(); } $modlog->role = $role; @@ -118,21 +118,22 @@ class ModLogPlugin extends Plugin function onEndShowSections(Action $action) { - if ($action->arg('action') != 'showstream') { + if (!$action instanceof ShowstreamAction) { + // early return for actions we're not interested in return true; } - $cur = common_current_user(); - - if (empty($cur) || !$cur->hasRight(self::VIEWMODLOG)) { + $scoped = $action->getScoped(); + if (!$scoped instanceof Profile || !$scoped->hasRight(self::VIEWMODLOG)) { + // only continue if we are allowed to VIEWMODLOG return true; } - $profile = $action->profile; + $profile = $action->getTarget(); $ml = new ModLog(); - $ml->profile_id = $profile->id; + $ml->profile_id = $profile->getID(); $ml->orderBy("created"); $cnt = $ml->find(); @@ -152,13 +153,13 @@ class ModLogPlugin extends Plugin $action->element('td', null, sprintf(($ml->is_grant) ? _('+%s') : _('-%s'), $ml->role)); $action->elementStart('td'); if ($ml->moderator_id) { - $mod = Profile::getKV('id', $ml->moderator_id); + $mod = Profile::getByID($ml->moderator_id); if (empty($mod)) { $action->text(_('[unknown]')); } else { - $action->element('a', array('href' => $mod->profileurl, - 'title' => $mod->fullname), - $mod->nickname); + $action->element('a', array('href' => $mod->getUrl(), + 'title' => $mod->getFullname()), + $mod->getNickname()); } } else { $action->text(_('[unknown]')); diff --git a/plugins/OStatus/OStatusPlugin.php b/plugins/OStatus/OStatusPlugin.php index 630031fdde..0dace39db0 100644 --- a/plugins/OStatus/OStatusPlugin.php +++ b/plugins/OStatus/OStatusPlugin.php @@ -1063,8 +1063,12 @@ class OStatusPlugin extends Plugin function showEntityRemoteSubscribe($action, $target='ostatussub') { - $user = common_current_user(); - if ($user && ($user->id == $action->profile->id)) { + if (!$action->getScoped() instanceof Profile) { + // early return if we're not logged in + return true; + } + + if ($action->getScoped()->sameAs($action->getTarget())) { $action->elementStart('div', 'entity_actions'); $action->elementStart('p', array('id' => 'entity_remote_subscribe', 'class' => 'entity_subscribe')); @@ -1127,42 +1131,45 @@ class OStatusPlugin extends Plugin return true; } - function onStartProfileListItemActionElements($item, $profile=null) + // FIXME: This one can accept both an Action and a Widget. Confusing! Refactor to (HTMLOutputter $out, Profile $target)! + function onStartProfileListItemActionElements($item) { - if (!common_logged_in()) { - - $profileUser = User::getKV('id', $item->profile->id); - - if (!empty($profileUser)) { - - if ($item instanceof Action) { - $output = $item; - $profile = $item->profile; - } else { - $output = $item->out; - } - - // Add an OStatus subscribe - $output->elementStart('li', 'entity_subscribe'); - $url = common_local_url('ostatusinit', - array('nickname' => $profileUser->nickname)); - $output->element('a', array('href' => $url, - 'class' => 'entity_remote_subscribe'), - // TRANS: Link text for a user to subscribe to an OStatus user. - _m('Subscribe')); - $output->elementEnd('li'); - - $output->elementStart('li', 'entity_tag'); - $url = common_local_url('ostatustag', - array('nickname' => $profileUser->nickname)); - $output->element('a', array('href' => $url, - 'class' => 'entity_remote_tag'), - // TRANS: Link text for a user to list an OStatus user. - _m('List')); - $output->elementEnd('li'); - } + if (common_logged_in()) { + // only non-logged in users get to see the "remote subscribe" form + return true; + } elseif (!$item->getTarget()->isLocal()) { + // we can (for now) only provide remote subscribe forms for local users + return true; } + if ($item instanceof ProfileAction) { + $output = $item; + } elseif ($item instanceof Widget) { + $output = $item->out; + } else { + // Bad $item class, don't know how to use this for outputting! + throw new ServerException('Bad item type for onStartProfileListItemActionElements'); + } + + // Add an OStatus subscribe + $output->elementStart('li', 'entity_subscribe'); + $url = common_local_url('ostatusinit', + array('nickname' => $item->getTarget()->getNickname())); + $output->element('a', array('href' => $url, + 'class' => 'entity_remote_subscribe'), + // TRANS: Link text for a user to subscribe to an OStatus user. + _m('Subscribe')); + $output->elementEnd('li'); + + $output->elementStart('li', 'entity_tag'); + $url = common_local_url('ostatustag', + array('nickname' => $item->getTarget()->getNickname())); + $output->element('a', array('href' => $url, + 'class' => 'entity_remote_tag'), + // TRANS: Link text for a user to list an OStatus user. + _m('List')); + $output->elementEnd('li'); + return true; } diff --git a/plugins/OStatus/classes/Ostatus_profile.php b/plugins/OStatus/classes/Ostatus_profile.php index cb961dc96b..1c4428b16d 100644 --- a/plugins/OStatus/classes/Ostatus_profile.php +++ b/plugins/OStatus/classes/Ostatus_profile.php @@ -1977,6 +1977,38 @@ class Ostatus_profile extends Managed_DataObject return $oprofile->localProfile(); } + + public function updateUriKeys($profile_uri, array $hints=array()) + { + $orig = clone($this); + + common_debug('URIFIX These identities both say they are each other: "'.$orig->uri.'" and "'.$profile_uri.'"'); + $this->uri = $profile_uri; + + if (array_key_exists('feedurl', $hints)) { + if (!empty($this->feeduri)) { + common_debug('URIFIX Changing FeedSub ['.$feedsub->id.'] feeduri "'.$feedsub->uri.'" to "'.$hints['feedurl']); + $feedsub = FeedSub::getKV('uri', $this->feeduri); + $feedorig = clone($feedsub); + $feedsub->uri = $hints['feedurl']; + $feedsub->updateWithKeys($feedorig); + } else { + common_debug('URIFIX Old Ostatus_profile did not have feedurl set, ensuring feed: '.$hints['feedurl']); + FeedSub::ensureFeed($hints['feedurl']); + } + $this->feeduri = $hints['feedurl']; + } + if (array_key_exists('salmon', $hints)) { + common_debug('URIFIX Changing Ostatus_profile salmonuri from "'.$this->salmonuri.'" to "'.$hints['salmon'].'"'); + $this->salmonuri = $hints['salmon']; + } + + common_debug('URIFIX Updating Ostatus_profile URI for '.$orig->uri.' to '.$this->uri); + $this->updateWithKeys($orig, 'uri'); // 'uri' is the primary key column + + common_debug('URIFIX Subscribing/renewing feedsub for Ostatus_profile '.$this->uri); + $this->subscribe(); + } } /** diff --git a/plugins/OStatus/lib/magicenvelope.php b/plugins/OStatus/lib/magicenvelope.php index 9e02f5eab5..dfd3abaeab 100644 --- a/plugins/OStatus/lib/magicenvelope.php +++ b/plugins/OStatus/lib/magicenvelope.php @@ -50,8 +50,8 @@ class MagicEnvelope */ public function __construct($xml=null) { if (!empty($xml)) { - $dom = DOMDocument::loadXML($xml); - if (!$dom instanceof DOMDocument) { + $dom = new DOMDocument(); + if (!$dom->loadXML($xml)) { throw new ServerException('Tried to load malformed XML as DOM'); } elseif (!$this->fromDom($dom)) { throw new ServerException('Could not load MagicEnvelope from DOM'); diff --git a/plugins/OStatus/lib/salmonaction.php b/plugins/OStatus/lib/salmonaction.php index 5193d302f1..320ea6cdfa 100644 --- a/plugins/OStatus/lib/salmonaction.php +++ b/plugins/OStatus/lib/salmonaction.php @@ -259,12 +259,7 @@ class SalmonAction extends Action // Step 4: Is the newly introduced https://example.com/user/1 URI in the list of aliases // presented by http://example.com/user/1 (i.e. do they both say they are the same identity?) if (in_array($e->object_uri, $doublecheck_aliases)) { - common_debug('URIFIX These identities both say they are each other: "'.$aliased_uri.'" and "'.$e->object_uri.'"'); - $orig = clone($oprofile); - $oprofile->uri = $e->object_uri; - common_debug('URIFIX Updating Ostatus_profile URI for '.$aliased_uri.' to '.$oprofile->uri); - $oprofile->updateWithKeys($orig, 'uri'); // 'uri' is the primary key column - unset($orig); + $oprofile->updateUriKeys($e->object_uri, DiscoveryHints::fromXRD($xrd)); $this->oprofile = $oprofile; break; // don't iterate through aliases anymore } diff --git a/plugins/OpenID/OpenIDPlugin.php b/plugins/OpenID/OpenIDPlugin.php index 710a34410a..2e9ada9806 100644 --- a/plugins/OpenID/OpenIDPlugin.php +++ b/plugins/OpenID/OpenIDPlugin.php @@ -390,11 +390,11 @@ class OpenIDPlugin extends Plugin $action->element('link', array('rel' => 'openid2.provider', 'href' => common_local_url('openidserver'))); $action->element('link', array('rel' => 'openid2.local_id', - 'href' => $action->profile->profileurl)); + 'href' => $action->getTarget()->getUrl())); $action->element('link', array('rel' => 'openid.server', 'href' => common_local_url('openidserver'))); $action->element('link', array('rel' => 'openid.delegate', - 'href' => $action->profile->profileurl)); + 'href' => $action->getTarget()->getUrl())); } if ($action instanceof SitestreamAction) { diff --git a/plugins/OpenID/actions/openidsettings.php b/plugins/OpenID/actions/openidsettings.php index 0c20dac4cd..bf5d8886f1 100644 --- a/plugins/OpenID/actions/openidsettings.php +++ b/plugins/OpenID/actions/openidsettings.php @@ -27,9 +27,7 @@ * @link http://status.net/ */ -if (!defined('STATUSNET')) { - exit(1); -} +if (!defined('GNUSOCIAL')) { exit(1); } require_once INSTALLDIR.'/plugins/OpenID/openid.php'; @@ -86,8 +84,6 @@ class OpenidsettingsAction extends SettingsAction */ function showContent() { - $user = common_current_user(); - if (!common_config('openid', 'trusted_provider')) { $this->elementStart('form', array('method' => 'post', 'id' => 'form_settings_openid_add', @@ -115,7 +111,7 @@ class OpenidsettingsAction extends SettingsAction } $oid = new User_openid(); - $oid->user_id = $user->id; + $oid->user_id = $this->scoped->getID(); $cnt = $oid->find(); @@ -123,7 +119,7 @@ class OpenidsettingsAction extends SettingsAction // TRANS: Header on OpenID settings page. $this->element('h2', null, _m('HEADER','Remove OpenID')); - if ($cnt == 1 && !$user->password) { + if ($cnt == 1 && !$this->scoped->hasPassword()) { $this->element('p', 'form_guide', // TRANS: Form guide. @@ -184,7 +180,7 @@ class OpenidsettingsAction extends SettingsAction 'this list to deny it access to your OpenID.')); $this->elementStart('ul', 'form_data'); $user_openid_trustroot = new User_openid_trustroot(); - $user_openid_trustroot->user_id=$user->id; + $user_openid_trustroot->user_id = $this->scoped->getID(); if($user_openid_trustroot->find()) { while($user_openid_trustroot->fetch()) { $this->elementStart('li'); @@ -203,7 +199,7 @@ class OpenidsettingsAction extends SettingsAction $this->submit('settings_openid_trustroots_action-submit', _m('BUTTON','Remove'), 'submit', 'remove_trustroots'); $this->elementEnd('fieldset'); - $prefs = User_openid_prefs::getKV('user_id', $user->id); + $prefs = User_openid_prefs::getKV('user_id', $this->scoped->getID()); $this->elementStart('fieldset'); $this->element('legend', null, _m('LEGEND','Preferences')); @@ -224,38 +220,29 @@ class OpenidsettingsAction extends SettingsAction * * @return void */ - function handlePost() + protected function doPost() { - // CSRF protection - $token = $this->trimmed('token'); - if (!$token || $token != common_session_token()) { - // TRANS: Client error displayed when the session token does not match or is not given. - $this->showForm(_m('There was a problem with your session token. '. - 'Try again, please.')); - return; - } - if ($this->arg('add')) { if (common_config('openid', 'trusted_provider')) { // TRANS: Form validation error if no OpenID providers can be added. - $this->showForm(_m('Cannot add new providers.')); + throw new ServerException(_m('Cannot add new providers.')); } else { - $result = oid_authenticate($this->trimmed('openid_url'), - 'finishaddopenid'); + $result = oid_authenticate($this->trimmed('openid_url'), 'finishaddopenid'); if (is_string($result)) { // error message - $this->showForm($result); + throw new ServerException($result); } + return _('Added new provider.'); } } else if ($this->arg('remove')) { - $this->removeOpenid(); + return $this->removeOpenid(); } else if($this->arg('remove_trustroots')) { - $this->removeTrustroots(); + return $this->removeTrustroots(); } else if($this->arg('save_prefs')) { - $this->savePrefs(); - } else { - // TRANS: Unexpected form validation error. - $this->showForm(_m('Something weird happened.')); + return $this->savePrefs(); } + + // TRANS: Unexpected form validation error. + throw new ServerException(_m('No known action for POST.')); } /** @@ -268,26 +255,20 @@ class OpenidsettingsAction extends SettingsAction */ function removeTrustroots() { - $user = common_current_user(); - $trustroots = $this->arg('openid_trustroot'); - if($trustroots) { - foreach($trustroots as $trustroot) { - $user_openid_trustroot = User_openid_trustroot::pkeyGet( - array('user_id'=>$user->id, 'trustroot'=>$trustroot)); - if($user_openid_trustroot) { - $user_openid_trustroot->delete(); - } else { - // TRANS: Form validation error when trying to remove a non-existing trustroot. - $this->showForm(_m('No such OpenID trustroot.')); - return; - } + $trustroots = $this->arg('openid_trustroot', array()); + foreach($trustroots as $trustroot) { + $user_openid_trustroot = User_openid_trustroot::pkeyGet( + array('user_id'=>$this->scoped->getID(), 'trustroot'=>$trustroot)); + if($user_openid_trustroot) { + $user_openid_trustroot->delete(); + } else { + // TRANS: Form validation error when trying to remove a non-existing trustroot. + throw new ClientException(_m('No such OpenID trustroot.')); } - // TRANS: Success message after removing trustroots. - $this->showForm(_m('Trustroots removed.'), true); - } else { - $this->showForm(); } - return; + + // TRANS: Success message after removing trustroots. + return _m('Trustroots removed.'); } /** @@ -300,25 +281,19 @@ class OpenidsettingsAction extends SettingsAction */ function removeOpenid() { - $openid_url = $this->trimmed('openid_url'); + $oid = User_openid::getKV('canonical', $this->trimmed('openid_url')); - $oid = User_openid::getKV('canonical', $openid_url); - - if (!$oid) { + if (!$oid instanceof User_openid) { // TRANS: Form validation error for a non-existing OpenID. - $this->showForm(_m('No such OpenID.')); - return; + throw new ClientException(_m('No such OpenID.')); } - $cur = common_current_user(); - if (!$cur || $oid->user_id != $cur->id) { + if ($this->scoped->getID() !== $oid->user_id) { // TRANS: Form validation error if OpenID is connected to another user. - $this->showForm(_m('That OpenID does not belong to you.')); - return; + throw new ClientException(_m('That OpenID does not belong to you.')); } $oid->delete(); // TRANS: Success message after removing an OpenID. - $this->showForm(_m('OpenID removed.'), true); - return; + return _m('OpenID removed.'); } /** @@ -331,18 +306,12 @@ class OpenidsettingsAction extends SettingsAction */ function savePrefs() { - $cur = common_current_user(); - - if (empty($cur)) { - throw new ClientException(_("Not logged in.")); - } - $orig = null; - $prefs = User_openid_prefs::getKV('user_id', $cur->id); + $prefs = User_openid_prefs::getKV('user_id', $this->scoped->getID()); - if (empty($prefs)) { + if (!$prefs instanceof User_openid_prefs) { $prefs = new User_openid_prefs(); - $prefs->user_id = $cur->id; + $prefs->user_id = $this->scoped->getID(); $prefs->created = common_sql_now(); } else { $orig = clone($prefs); @@ -350,13 +319,12 @@ class OpenidsettingsAction extends SettingsAction $prefs->hide_profile_link = $this->booleanintstring('hide_profile_link'); - if (empty($orig)) { - $prefs->insert(); - } else { + if ($orig instanceof User_openid_prefs) { $prefs->update($orig); + } else { + $prefs->insert(); } - $this->showForm(_m('OpenID preferences saved.'), true); - return; + return _m('OpenID preferences saved.'); } } diff --git a/plugins/OpenID/openid.php b/plugins/OpenID/openid.php index 91a34bd6e3..ee854e8140 100644 --- a/plugins/OpenID/openid.php +++ b/plugins/OpenID/openid.php @@ -131,13 +131,15 @@ function oid_check_immediate($openid_url, $backto=null) function oid_authenticate($openid_url, $returnto, $immediate=false) { + if (!common_valid_http_url($openid_url)) { + throw new ClientException(_m('No valid URL provided for OpenID.')); + } $consumer = oid_consumer(); if (!$consumer) { // TRANS: OpenID plugin server error. - common_server_error(_m('Cannot instantiate OpenID consumer object.')); - return false; + throw new ServerException(_m('Cannot instantiate OpenID consumer object.')); } common_ensure_session(); @@ -148,12 +150,12 @@ function oid_authenticate($openid_url, $returnto, $immediate=false) if (!$auth_request) { common_log(LOG_ERR, __METHOD__ . ": mystery fail contacting $openid_url"); // TRANS: OpenID plugin message. Given when an OpenID is not valid. - return _m('Not a valid OpenID.'); + throw new ServerException(_m('Not a valid OpenID.')); } else if (Auth_OpenID::isFailure($auth_request)) { common_log(LOG_ERR, __METHOD__ . ": OpenID fail to $openid_url: $auth_request->message"); // TRANS: OpenID plugin server error. Given when the OpenID authentication request fails. // TRANS: %s is the failure message. - return sprintf(_m('OpenID failure: %s.'), $auth_request->message); + throw new ServerException(sprintf(_m('OpenID failure: %s.'), $auth_request->message)); } $sreg_request = Auth_OpenID_SRegRequest::build(// Required @@ -199,14 +201,12 @@ function oid_authenticate($openid_url, $returnto, $immediate=false) $redirect_url = $auth_request->redirectURL($trust_root, $process_url, $immediate); - if (!$redirect_url) { - } else if (Auth_OpenID::isFailure($redirect_url)) { + if (Auth_OpenID::isFailure($redirect_url)) { // TRANS: OpenID plugin server error. Given when the OpenID authentication request cannot be redirected. // TRANS: %s is the failure message. - return sprintf(_m('Could not redirect to server: %s.'), $redirect_url->message); - } else { - common_redirect($redirect_url, 303); + throw new ServerException(sprintf(_m('Could not redirect to server: %s.'), $redirect_url->message)); } + common_redirect($redirect_url, 303); /* } else { // Generate form markup and render it. diff --git a/plugins/OpportunisticQM/lib/opportunisticqueuemanager.php b/plugins/OpportunisticQM/lib/opportunisticqueuemanager.php index 4b2b679b58..b2dc61e15f 100644 --- a/plugins/OpportunisticQM/lib/opportunisticqueuemanager.php +++ b/plugins/OpportunisticQM/lib/opportunisticqueuemanager.php @@ -83,10 +83,17 @@ class OpportunisticQueueManager extends DBQueueManager // OpportunisticQM shouldn't discard items it can't handle, we're // only here to take care of what we _can_ handle! protected function noHandlerFound(Queue_item $qi, $rep=null) { - $this->_log(LOG_WARNING, "[{$qi->transport}:item {$qi->id}] Releasing claim for queue item without a handler"); + $this->_log(LOG_WARNING, "[{$qi->transport}:item {$qi->id}] Releasing claim for queue item without a handler"); $this->_fail($qi, true); // true here means "releaseOnly", so no error statistics since it's not an _error_ } + protected function _fail(Queue_item $qi, $releaseOnly=false) + { + parent::_fail($qi, $releaseOnly); + $this->_log(LOG_DEBUG, "[{$qi->transport}:item {$qi->id}] Ignoring this transport for the rest of this execution"); + $this->ignoreTransport($qi->transport); + } + /** * Takes care of running through the queue items, returning when * the limits setup in __construct are met. diff --git a/plugins/Poll/actions/pollsettings.php b/plugins/Poll/actions/pollsettings.php index b390812cf4..b95465d8d6 100644 --- a/plugins/Poll/actions/pollsettings.php +++ b/plugins/Poll/actions/pollsettings.php @@ -27,9 +27,7 @@ * @link http://status.net/ */ -if (!defined('STATUSNET') && !defined('LACONICA')) { - exit(1); -} +if (!defined('GNUSOCIAL')) { exit(1); } class PollSettingsAction extends SettingsAction { @@ -56,143 +54,36 @@ class PollSettingsAction extends SettingsAction return _m('Set your poll preferences'); } - /** - * Show the form for Poll - * - * @return void - */ - function showContent() + protected function getForm() { - $user = common_current_user(); - - $prefs = User_poll_prefs::getKV('user_id', $user->id); - + $prefs = User_poll_prefs::getKV('user_id', $this->scoped->getID()); $form = new PollPrefsForm($this, $prefs); - - $form->show(); + return $form; } - /** - * Handler method - * - * @param array $argarray is ignored since it's now passed in in prepare() - * - * @return void - */ - - function handlePost() + protected function doPost() { - $user = common_current_user(); - - $upp = User_poll_prefs::getKV('user_id', $user->id); + $upp = User_poll_prefs::getKV('user_id', $this->scoped->getID()); $orig = null; - if (!empty($upp)) { + if ($upp instanceof User_poll_prefs) { $orig = clone($upp); } else { $upp = new User_poll_prefs(); - $upp->user_id = $user->id; + $upp->user_id = $this->scoped->getID(); $upp->created = common_sql_now(); } $upp->hide_responses = $this->boolean('hide_responses'); $upp->modified = common_sql_now(); - if (!empty($orig)) { + if ($orig instanceof User_poll_prefs) { $upp->update($orig); } else { $upp->insert(); } // TRANS: Confirmation shown when user profile settings are saved. - $this->showForm(_('Settings saved.'), true); - - return; - } -} - -class PollPrefsForm extends Form -{ - var $prefs; - - function __construct($out, $prefs) - { - parent::__construct($out); - $this->prefs = $prefs; - } - - /** - * Visible or invisible data elements - * - * Display the form fields that make up the data of the form. - * Sub-classes should overload this to show their data. - * - * @return void - */ - - function formData() - { - $this->elementStart('fieldset'); - $this->elementStart('ul', 'form_data'); - $this->elementStart('li'); - $this->checkbox('hide_responses', - _('Do not deliver poll responses to my home timeline'), - (!empty($this->prefs) && $this->prefs->hide_responses)); - $this->elementEnd('li'); - $this->elementEnd('ul'); - $this->elementEnd('fieldset'); - } - - /** - * Buttons for form actions - * - * Submit and cancel buttons (or whatever) - * Sub-classes should overload this to show their own buttons. - * - * @return void - */ - - function formActions() - { - $this->submit('submit', _('Save')); - } - - /** - * ID of the form - * - * Should be unique on the page. Sub-classes should overload this - * to show their own IDs. - * - * @return int ID of the form - */ - - function id() - { - return 'form_poll_prefs'; - } - - /** - * Action of the form. - * - * URL to post to. Should be overloaded by subclasses to give - * somewhere to post to. - * - * @return string URL to post to - */ - - function action() - { - return common_local_url('pollsettings'); - } - - /** - * Class of the form. May include space-separated list of multiple classes. - * - * @return string the form's class - */ - - function formClass() - { - return 'form_settings'; + return _('Settings saved.'); } } diff --git a/plugins/Poll/forms/pollprefs.php b/plugins/Poll/forms/pollprefs.php new file mode 100644 index 0000000000..627b77d948 --- /dev/null +++ b/plugins/Poll/forms/pollprefs.php @@ -0,0 +1,87 @@ +prefs = $prefs; + } + + /** + * Visible or invisible data elements + * + * Display the form fields that make up the data of the form. + * Sub-classes should overload this to show their data. + * + * @return void + */ + + function formData() + { + $this->elementStart('fieldset'); + $this->elementStart('ul', 'form_data'); + $this->elementStart('li'); + $this->checkbox('hide_responses', + _('Do not deliver poll responses to my home timeline'), + ($this->prefs instanceof User_poll_prefs && $this->prefs->hide_responses)); + $this->elementEnd('li'); + $this->elementEnd('ul'); + $this->elementEnd('fieldset'); + } + + /** + * Buttons for form actions + * + * Submit and cancel buttons (or whatever) + * Sub-classes should overload this to show their own buttons. + * + * @return void + */ + + function formActions() + { + $this->submit('submit', _('Save')); + } + + /** + * ID of the form + * + * Should be unique on the page. Sub-classes should overload this + * to show their own IDs. + * + * @return int ID of the form + */ + + function id() + { + return 'form_poll_prefs'; + } + + /** + * Action of the form. + * + * URL to post to. Should be overloaded by subclasses to give + * somewhere to post to. + * + * @return string URL to post to + */ + + function action() + { + return common_local_url('pollsettings'); + } + + /** + * Class of the form. May include space-separated list of multiple classes. + * + * @return string the form's class + */ + + function formClass() + { + return 'form_settings'; + } +} diff --git a/plugins/RequireValidatedEmail/actions/confirmfirstemail.php b/plugins/RequireValidatedEmail/actions/confirmfirstemail.php index cc4b646f6b..d0d1893739 100644 --- a/plugins/RequireValidatedEmail/actions/confirmfirstemail.php +++ b/plugins/RequireValidatedEmail/actions/confirmfirstemail.php @@ -157,7 +157,7 @@ class ConfirmfirstemailAction extends Action $orig = clone($this->user); - $this->user->password = common_munge_password($this->password, $this->user->id); + $this->user->password = common_munge_password($this->password, $this->user->getProfile()); $this->user->update($orig); diff --git a/plugins/SearchSub/actions/searchsubs.php b/plugins/SearchSub/actions/searchsubs.php index 54563ed0e7..fd89075032 100644 --- a/plugins/SearchSub/actions/searchsubs.php +++ b/plugins/SearchSub/actions/searchsubs.php @@ -28,9 +28,7 @@ * @link http://status.net/ */ -if (!defined('STATUSNET') && !defined('LACONICA')) { - exit(1); -} +if (!defined('GNUSOCIAL')) { exit(1); } /** * A list of the user's subscriptions @@ -48,20 +46,19 @@ class SearchSubsAction extends GalleryAction if ($this->page == 1) { // TRANS: Header for subscriptions overview for a user (first page). // TRANS: %s is a user nickname. - return sprintf(_m('%s\'s search subscriptions'), $this->user->nickname); + return sprintf(_m('%s\'s search subscriptions'), $this->getTarget()->getNickname()); } 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(_m('%1$s\'s search subscriptions, page %2$d'), - $this->user->nickname, + $this->getTarget()->getNickname(), $this->page); } } function showPageNotice() { - $user = common_current_user(); - if ($user && ($user->id == $this->profile->id)) { + if ($this->scoped instanceof Profile && $this->scoped->sameAs($this->getTarget())) { $this->element('p', null, // TRANS: Page notice for page with an overview of all search subscriptions // TRANS: of the logged in user's own profile. @@ -71,7 +68,7 @@ class SearchSubsAction extends GalleryAction // 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(_m('%s has subscribed to receive all notices on this site matching the following searches:'), - $this->profile->nickname)); + $this->getTarget()->getNickname())); } } @@ -86,12 +83,12 @@ class SearchSubsAction extends GalleryAction $cnt = 0; $searchsub = new SearchSub(); - $searchsub->profile_id = $this->user->id; + $searchsub->profile_id = $this->getTarget()->getID(); $searchsub->limit($limit, $offset); $searchsub->find(); if ($searchsub->N) { - $list = new SearchSubscriptionsList($searchsub, $this->user, $this); + $list = new SearchSubscriptionsList($searchsub, $this->getTarget(), $this); $cnt = $list->show(); if (0 == $cnt) { $this->showEmptyListMessage(); @@ -102,7 +99,7 @@ class SearchSubsAction extends GalleryAction $this->pagination($this->page > 1, $cnt > PROFILES_PER_PAGE, $this->page, 'searchsubs', - array('nickname' => $this->user->nickname)); + array('nickname' => $this->getTarget()->getNickname())); Event::handle('EndShowTagSubscriptionsContent', array($this)); @@ -112,8 +109,7 @@ class SearchSubsAction extends GalleryAction function showEmptyListMessage() { if (common_logged_in()) { - $current_user = common_current_user(); - if ($this->user->id === $current_user->id) { + if ($this->scoped->sameAs($this->getTarget())) { // TRANS: Search subscription list text when the logged in user has no search subscriptions. $message = _m('You are not subscribed to any text searches right now. You can push the "Subscribe" button ' . 'on any notice text search to automatically receive any public messages on this site that match that ' . @@ -121,13 +117,13 @@ class SearchSubsAction extends GalleryAction } else { // TRANS: Search subscription list text when looking at the subscriptions for a of a user other // TRANS: than the logged in user that has no search subscriptions. %s is the user nickname. - $message = sprintf(_m('%s is not subscribed to any searches.'), $this->user->nickname); + $message = sprintf(_m('%s is not subscribed to any searches.'), $this->getTarget()->getNickname()); } } 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(_m('%s is not subscribed to any searches.'), $this->user->nickname); + $message = sprintf(_m('%s is not subscribed to any searches.'), $this->getTarget()->getNickname()); } $this->elementStart('div', 'guide'); diff --git a/plugins/SearchSub/lib/searchsubmenu.php b/plugins/SearchSub/lib/searchsubmenu.php index fa5b34942b..434ed8982c 100644 --- a/plugins/SearchSub/lib/searchsubmenu.php +++ b/plugins/SearchSub/lib/searchsubmenu.php @@ -86,7 +86,7 @@ class SearchSubMenu extends MoreMenu return $items; } - function item($actionName, $args, $label, $description, $id=null, $cls=null) + function item($actionName, array $args, $label, $description, $id=null, $cls=null) { if (empty($id)) { $id = $this->menuItemID($actionName, $args); diff --git a/plugins/SubMirror/actions/mirrorsettings.php b/plugins/SubMirror/actions/mirrorsettings.php index b5a49fe4fa..1bfc848ebb 100644 --- a/plugins/SubMirror/actions/mirrorsettings.php +++ b/plugins/SubMirror/actions/mirrorsettings.php @@ -25,7 +25,7 @@ * @link http://status.net/ */ -if (!defined('GNUSOCIAL') && !defined('STATUSNET')) { exit(1); } +if (!defined('GNUSOCIAL')) { exit(1); } class MirrorSettingsAction extends SettingsAction { @@ -62,9 +62,8 @@ class MirrorSettingsAction extends SettingsAction */ function showContent() { - $user = common_current_user(); $provider = $this->trimmed('provider'); - if ($provider) { + if (!empty($provider) || GNUsocial::isAjax()) { $this->showAddFeedForm($provider); } else { $this->elementStart('div', array('id' => 'add-mirror')); @@ -72,7 +71,7 @@ class MirrorSettingsAction extends SettingsAction $this->elementEnd('div'); $mirror = new SubMirror(); - $mirror->subscriber = $user->id; + $mirror->subscriber = $this->scoped->getID(); if ($mirror->find()) { while ($mirror->fetch()) { $this->showFeedForm($mirror); @@ -87,13 +86,11 @@ class MirrorSettingsAction extends SettingsAction $form->show(); } - function showFeedForm($mirror) + function showFeedForm(SubMirror $mirror) { - $profile = Profile::getKV('id', $mirror->subscribed); - if ($profile) { - $form = new EditMirrorForm($this, $profile); - $form->show(); - } + $profile = Profile::getByID($mirror->subscribed); + $form = new EditMirrorForm($this, $profile); + $form->show(); } function showAddFeedForm() @@ -112,41 +109,6 @@ class MirrorSettingsAction extends SettingsAction $form->show(); } - /** - * - * @param array $args - * - * @todo move the ajax display handling to common code - */ - function handle($args) - { - if ($this->boolean('ajax')) { - $this->startHTML('text/xml;charset=utf-8'); - $this->elementStart('head'); - // TRANS: Title for page with form to add a mirror feed provider on. - $this->element('title', null, _m('Provider add')); - $this->elementEnd('head'); - $this->elementStart('body'); - - $this->showAddFeedForm(); - - $this->elementEnd('body'); - $this->endHTML(); - } else { - return parent::handle($args); - } - } - /** - * Handle a POST request - * - * Muxes to different sub-functions based on which button was pushed - * - * @return void - */ - function handlePost() - { - } - /** * Show the local navigation menu * diff --git a/plugins/TagSub/actions/tagsubs.php b/plugins/TagSub/actions/tagsubs.php index be195250f6..1e927b4fd1 100644 --- a/plugins/TagSub/actions/tagsubs.php +++ b/plugins/TagSub/actions/tagsubs.php @@ -28,9 +28,7 @@ * @link http://status.net/ */ -if (!defined('STATUSNET') && !defined('LACONICA')) { - exit(1); -} +if (!defined('GNUSOCIAL')) { exit(1); } /** * A list of the user's subscriptions @@ -48,20 +46,19 @@ class TagSubsAction extends GalleryAction if ($this->page == 1) { // TRANS: Header for subscriptions overview for a user (first page). // TRANS: %s is a user nickname. - return sprintf(_m('%s\'s tag subscriptions'), $this->user->nickname); + return sprintf(_m('%s\'s tag subscriptions'), $this->getTarget()->getNickname()); } 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(_m('%1$s\'s tag subscriptions, page %2$d'), - $this->user->nickname, + $this->getTarget()->getNickname(), $this->page); } } function showPageNotice() { - $user = common_current_user(); - if ($user && ($user->id == $this->profile->id)) { + if ($this->scoped instanceof Profile && $this->scoped->sameAs($this->getTarget())) { $this->element('p', null, // TRANS: Page notice for page with an overview of all tag subscriptions // TRANS: of the logged in user's own profile. @@ -71,7 +68,7 @@ class TagSubsAction extends GalleryAction // 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(_m('%s has subscribed to receive all notices on this site containing the following tags:'), - $this->profile->nickname)); + $this->getTarget()->getNickname())); } } @@ -86,12 +83,12 @@ class TagSubsAction extends GalleryAction $cnt = 0; $tagsub = new TagSub(); - $tagsub->profile_id = $this->user->id; + $tagsub->profile_id = $this->getTarget()->getID(); $tagsub->limit($limit, $offset); $tagsub->find(); if ($tagsub->N) { - $list = new TagSubscriptionsList($tagsub, $this->user, $this); + $list = new TagSubscriptionsList($tagsub, $this->getTarget(), $this); $cnt = $list->show(); if (0 == $cnt) { $this->showEmptyListMessage(); @@ -102,7 +99,7 @@ class TagSubsAction extends GalleryAction $this->pagination($this->page > 1, $cnt > PROFILES_PER_PAGE, $this->page, 'tagsubs', - array('nickname' => $this->user->nickname)); + array('nickname' => $this->getTarget()->getNickname())); Event::handle('EndShowTagSubscriptionsContent', array($this)); @@ -112,8 +109,7 @@ class TagSubsAction extends GalleryAction function showEmptyListMessage() { if (common_logged_in()) { - $current_user = common_current_user(); - if ($this->user->id === $current_user->id) { + if ($this->scoped->sameAs($this->getTarget())) { // TRANS: Tag subscription list text when the logged in user has no tag subscriptions. $message = _m('You are not listening to any hash tags right now. You can push the "Subscribe" button ' . 'on any hashtag page to automatically receive any public messages on this site that use that ' . @@ -121,13 +117,13 @@ class TagSubsAction extends GalleryAction } else { // TRANS: Tag subscription list text when looking at the subscriptions for a of a user other // TRANS: than the logged in user that has no tag subscriptions. %s is the user nickname. - $message = sprintf(_m('%s is not following any tags.'), $this->user->nickname); + $message = sprintf(_m('%s is not following any tags.'), $this->getTarget()->getNickname()); } } 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(_m('%s is not following any tags.'), $this->user->nickname); + $message = sprintf(_m('%s is not following any tags.'), $this->getTarget()->getNickname()); } $this->elementStart('div', 'guide'); diff --git a/plugins/TwitterBridge/TwitterBridgePlugin.php b/plugins/TwitterBridge/TwitterBridgePlugin.php index 9b129ea21b..dd3007e309 100644 --- a/plugins/TwitterBridge/TwitterBridgePlugin.php +++ b/plugins/TwitterBridge/TwitterBridgePlugin.php @@ -26,9 +26,7 @@ * @link http://status.net/ */ -if (!defined('STATUSNET')) { - exit(1); -} +if (!defined('GNUSOCIAL')) { exit(1); } require_once __DIR__ . '/twitter.php'; @@ -387,12 +385,11 @@ class TwitterBridgePlugin extends Plugin { $n2s = Notice_to_status::getKV('notice_id', $notice->id); - if (!empty($n2s)) { + if ($n2s instanceof Notice_to_status) { - $flink = Foreign_link::getByUserID($notice->profile_id, - TWITTER_SERVICE); // twitter service - - if (empty($flink)) { + try { + $flink = Foreign_link::getByUserID($notice->profile_id, TWITTER_SERVICE); // twitter service + } catch (NoResultException $e) { return true; } @@ -424,15 +421,14 @@ class TwitterBridgePlugin extends Plugin */ function onEndFavorNotice(Profile $profile, Notice $notice) { - $flink = Foreign_link::getByUserID($profile->id, - TWITTER_SERVICE); // twitter service - - if (empty($flink)) { + try { + $flink = Foreign_link::getByUserID($profile->getID(), TWITTER_SERVICE); // twitter service + } catch (NoResultException $e) { return true; } if (!TwitterOAuthClient::isPackedToken($flink->credentials)) { - $this->log(LOG_INFO, "Skipping fave processing for {$profile->id} since link is not OAuth."); + $this->log(LOG_INFO, "Skipping fave processing for {$profile->getID()} since link is not OAuth."); return true; } @@ -464,10 +460,9 @@ class TwitterBridgePlugin extends Plugin */ function onEndDisfavorNotice(Profile $profile, Notice $notice) { - $flink = Foreign_link::getByUserID($profile->id, - TWITTER_SERVICE); // twitter service - - if (empty($flink)) { + try { + $flink = Foreign_link::getByUserID($profile->getID(), TWITTER_SERVICE); // twitter service + } catch (NoResultException $e) { return true; } @@ -516,16 +511,15 @@ class TwitterBridgePlugin extends Plugin { $fuser = null; - $flink = Foreign_link::getByUserID($profile->id, TWITTER_SERVICE); - - if (!empty($flink)) { + try { + $flink = Foreign_link::getByUserID($profile->id, TWITTER_SERVICE); $fuser = $flink->getForeignUser(); - if (!empty($fuser)) { - $links[] = array("href" => $fuser->uri, - "text" => sprintf(_("@%s on Twitter"), $fuser->nickname), - "image" => $this->path("icons/twitter-bird-white-on-blue.png")); - } + $links[] = array("href" => $fuser->uri, + "text" => sprintf(_("@%s on Twitter"), $fuser->nickname), + "image" => $this->path("icons/twitter-bird-white-on-blue.png")); + } catch (NoResultException $e) { + // no foreign link and/or user for Twitter on this profile ID } return true; @@ -569,16 +563,17 @@ class TwitterBridgePlugin extends Plugin if( count($noticeArray) != 1 ) { break; } $post = $noticeArray[0]; - $flink = Foreign_link::getByUserID($post->profile_id, TWITTER_SERVICE); - if( $flink ) { // Our local user has registered Twitter Gateway + try { + $flink = Foreign_link::getByUserID($post->profile_id, TWITTER_SERVICE); $fuser = Foreign_user::getForeignUser($flink->foreign_id, TWITTER_SERVICE); - if( $fuser ) { // Got nickname for local user's Twitter account - $action->element('meta', array('name' => 'twitter:creator', - 'content' => '@'.$fuser->nickname)); - } + $action->element('meta', array('name' => 'twitter:creator', + 'content' => '@'.$fuser->nickname)); + } catch (NoResultException $e) { + // no foreign link and/or user for Twitter on this profile ID } break; - default: break; + default: + break; } return true; diff --git a/plugins/TwitterBridge/actions/twitterauthorization.php b/plugins/TwitterBridge/actions/twitterauthorization.php index ae293edcf7..c9b892b640 100644 --- a/plugins/TwitterBridge/actions/twitterauthorization.php +++ b/plugins/TwitterBridge/actions/twitterauthorization.php @@ -28,9 +28,10 @@ * @link http://status.net/ */ -if (!defined('GNUSOCIAL') && !defined('STATUSNET')) { exit(1); } +if (!defined('GNUSOCIAL')) { exit(1); } require_once dirname(__DIR__) . '/twitter.php'; +require_once INSTALLDIR . '/lib/oauthclient.php'; /** * Class for doing OAuth authentication against Twitter @@ -48,127 +49,81 @@ require_once dirname(__DIR__) . '/twitter.php'; * @link http://status.net/ * */ -class TwitterauthorizationAction extends Action +class TwitterauthorizationAction extends FormAction { var $twuid = null; var $tw_fields = null; var $access_token = null; - var $signin = null; var $verifier = null; - /** - * Initialize class members. Looks for 'oauth_token' parameter. - * - * @param array $args misc. arguments - * - * @return boolean true - */ - function prepare($args) - { - parent::prepare($args); + protected $needLogin = false; // authorization page can also be used to create a new user - $this->signin = $this->boolean('signin'); + protected function doPreparation() + { $this->oauth_token = $this->arg('oauth_token'); $this->verifier = $this->arg('oauth_verifier'); - return true; + if ($this->scoped instanceof Profile) { + try { + $flink = Foreign_link::getByUserID($this->scoped->getID(), TWITTER_SERVICE); + $fuser = $flink->getForeignUser(); + + // If there's already a foreign link record and a foreign user + // (no exceptions were thrown when fetching either of them...) + // it means the accounts are already linked, and this is unecessary. + // So go back. + + common_redirect(common_local_url('twittersettings')); + } catch (NoResultException $e) { + // but if we don't have a foreign user linked, let's continue authorization procedure. + } + } } - /** - * Handler method - * - * @param array $args is ignored since it's now passed in in prepare() - * - * @return nothing - */ - function handle($args) + protected function doPost() { - parent::handle($args); + // User was not logged in to StatusNet before - if (common_logged_in()) { - $user = common_current_user(); - $flink = Foreign_link::getByUserID($user->id, TWITTER_SERVICE); + $this->twuid = $this->trimmed('twuid'); - // If there's already a foreign link record and a foreign user - // it means the accounts are already linked, and this is unecessary. - // So go back. + $this->tw_fields = array('screen_name' => $this->trimmed('tw_fields_screen_name'), + 'fullname' => $this->trimmed('tw_fields_fullname')); - if (isset($flink)) { - $fuser = $flink->getForeignUser(); - if (!empty($fuser)) { - common_redirect(common_local_url('twittersettings')); - } + $this->access_token = new OAuthToken($this->trimmed('access_token_key'), $this->trimmed('access_token_secret')); + + if ($this->arg('create')) { + common_debug('TwitterBridgeDebug - POST with create'); + if (!$this->boolean('license')) { + // TRANS: Form validation error displayed when the checkbox to agree to the license has not been checked. + throw new ClientException(_m('You cannot register if you do not agree to the license.')); } + return $this->createNewUser(); + } elseif ($this->arg('connect')) { + common_debug('TwitterBridgeDebug - POST with connect'); + return $this->connectNewUser(); } - if ($_SERVER['REQUEST_METHOD'] == 'POST') { - - // User was not logged in to StatusNet before - - $this->twuid = $this->trimmed('twuid'); - - $this->tw_fields = array('screen_name' => $this->trimmed('tw_fields_screen_name'), - 'fullname' => $this->trimmed('tw_fields_fullname')); - - $this->access_token = new OAuthToken($this->trimmed('access_token_key'), $this->trimmed('access_token_secret')); - - $token = $this->trimmed('token'); - - if (!$token || $token != common_session_token()) { - // TRANS: Client error displayed when the session token does not match or is not given. - $this->showForm(_m('There was a problem with your session token. Try again, please.')); - return; - } - - if ($this->arg('create')) { - if (!$this->boolean('license')) { - // TRANS: Form validation error displayed when the checkbox to agree to the license has not been checked. - $this->showForm(_m('You cannot register if you do not agree to the license.'), - $this->trimmed('newname')); - return; - } - $this->createNewUser(); - } else if ($this->arg('connect')) { - $this->connectNewUser(); - } else { - common_debug('Twitter bridge - ' . print_r($this->args, true)); - // TRANS: Form validation error displayed when an unhandled error occurs. - $this->showForm(_m('Something weird happened.'), - $this->trimmed('newname')); - } - } else { - // $this->oauth_token is only populated once Twitter authorizes our - // request token. If it's empty we're at the beginning of the auth - // process - - if (empty($this->oauth_token)) { - $this->authorizeRequestToken(); - } else { - $this->saveAccessToken(); - } - } + common_debug('TwitterBridgeDebug - ' . print_r($this->args, true)); + // TRANS: Form validation error displayed when an unhandled error occurs. + throw new ClientException(_m('No known action for POST.')); } /** * Asks Twitter for a request token, and then redirects to Twitter * to authorize it. - * - * @return nothing */ - function authorizeRequestToken() + protected function authorizeRequestToken() { try { // Get a new request token and authorize it - $client = new TwitterOAuthClient(); - $req_tok = $client->getRequestToken(); + $req_tok = $client->getTwitterRequestToken(); // Sock the request token away in the session temporarily - $_SESSION['twitter_request_token'] = $req_tok->key; $_SESSION['twitter_request_token_secret'] = $req_tok->secret; - $auth_link = $client->getAuthorizeLink($req_tok, $this->signin); + $auth_link = $client->getTwitterAuthorizeLink($req_tok, $this->boolean('signin')); } catch (OAuthClientException $e) { $msg = sprintf( 'OAuth client error - code: %1s, msg: %2s', @@ -176,10 +131,8 @@ class TwitterauthorizationAction extends Action $e->getMessage() ); common_log(LOG_INFO, 'Twitter bridge - ' . $msg); - $this->serverError( - // TRANS: Server error displayed when linking to a Twitter account fails. - _m('Could not link your Twitter account.') - ); + // TRANS: Server error displayed when linking to a Twitter account fails. + throw new ServerException(_m('Could not link your Twitter account.')); } common_redirect($auth_link); @@ -197,25 +150,19 @@ class TwitterauthorizationAction extends Action // token we sent them if ($_SESSION['twitter_request_token'] != $this->oauth_token) { - $this->serverError( - // TRANS: Server error displayed when linking to a Twitter account fails because of an incorrect oauth_token. - _m('Could not link your Twitter account: oauth_token mismatch.') - ); + // TRANS: Server error displayed when linking to a Twitter account fails because of an incorrect oauth_token. + throw new ServerException(_m('Could not link your Twitter account: oauth_token mismatch.')); } $twitter_user = null; try { - - $client = new TwitterOAuthClient($_SESSION['twitter_request_token'], - $_SESSION['twitter_request_token_secret']); + $client = new TwitterOAuthClient($_SESSION['twitter_request_token'], $_SESSION['twitter_request_token_secret']); // Exchange the request token for an access token - - $atok = $client->getAccessToken($this->verifier); + $atok = $client->getTwitterAccessToken($this->verifier); // Test the access token and get the user's Twitter info - $client = new TwitterOAuthClient($atok->key, $atok->secret); $twitter_user = $client->verifyCredentials(); @@ -226,17 +173,14 @@ class TwitterauthorizationAction extends Action $e->getMessage() ); common_log(LOG_INFO, 'Twitter bridge - ' . $msg); - $this->serverError( - // TRANS: Server error displayed when linking to a Twitter account fails. - _m('Could not link your Twitter account.') - ); + // TRANS: Server error displayed when linking to a Twitter account fails. + throw new ServerException(_m('Could not link your Twitter account.')); } - if (common_logged_in()) { + if ($this->scoped instanceof Profile) { // Save the access token and Twitter user info - $user = common_current_user(); - $this->saveForeignLink($user->id, $twitter_user->id, $atok); + $this->saveForeignLink($this->scoped->getID(), $twitter_user->id, $atok); save_twitter_user($twitter_user->id, $twitter_user->screen_name); } else { @@ -245,7 +189,7 @@ class TwitterauthorizationAction extends Action $this->tw_fields = array("screen_name" => $twitter_user->screen_name, "fullname" => $twitter_user->name); $this->access_token = $atok; - $this->tryLogin(); + return $this->tryLogin(); } // Clean up the the mess we made in the session @@ -297,24 +241,20 @@ class TwitterauthorizationAction extends Action $flink_id = $flink->insert(); + // We want to make sure we got a numerical >0 value, not just failed the insert (which would be === false) if (empty($flink_id)) { common_log_db_error($flink, 'INSERT', __FILE__); // TRANS: Server error displayed when linking to a Twitter account fails. - $this->serverError(_m('Could not link your Twitter account.')); + throw new ServerException(_m('Could not link your Twitter account.')); } return $flink_id; } - function showPageNotice() + function getInstructions() { - if ($this->error) { - $this->element('div', array('class' => 'error'), $this->error); - } else { - $this->element('div', 'instructions', - // TRANS: Page instruction. %s is the StatusNet sitename. - sprintf(_m('This is the first time you have logged into %s so we must connect your Twitter account to a local account. You can either create a new account, or connect with your existing account, if you have one.'), common_config('site', 'name'))); - } + // TRANS: Page instruction. %s is the StatusNet sitename. + return sprintf(_m('This is the first time you have logged into %s so we must connect your Twitter account to a local account. You can either create a new account, or connect with your existing account, if you have one.'), common_config('site', 'name')); } function title() @@ -323,16 +263,20 @@ class TwitterauthorizationAction extends Action return _m('Twitter Account Setup'); } - function showForm($error=null, $username=null) + public function showPage() { - $this->error = $error; - $this->username = $username; + // $this->oauth_token is only populated once Twitter authorizes our + // request token. If it's empty we're at the beginning of the auth + // process + if (empty($this->error)) { + if (empty($this->oauth_token)) { + // authorizeRequestToken either throws an exception or redirects + $this->authorizeRequestToken(); + } else { + $this->saveAccessToken(); + } + } - $this->showPage(); - } - - function showPage() - { parent::showPage(); } @@ -343,11 +287,6 @@ class TwitterauthorizationAction extends Action */ function showContent() { - if (!empty($this->message_text)) { - $this->element('p', null, $this->message); - return; - } - $this->elementStart('form', array('method' => 'post', 'id' => 'form_settings_twitter_connect', 'class' => 'form_settings', @@ -363,8 +302,8 @@ class TwitterauthorizationAction extends Action $this->hidden('tw_fields_name', $this->tw_fields['fullname']); $this->hidden('token', common_session_token()); - // Don't allow new account creation if site is flagged as invite only - if (common_config('site', 'inviteonly') == false) { + // Only allow new account creation if site is not flagged invite-only + if (!common_config('site', 'inviteonly')) { $this->elementStart('fieldset'); $this->element('legend', null, // TRANS: Fieldset legend. @@ -380,7 +319,7 @@ class TwitterauthorizationAction extends Action $this->elementStart('li'); // TRANS: Field label. $this->input('newname', _m('New nickname'), - ($this->username) ? $this->username : '', + $this->username ?: '', // TRANS: Field title for nickname field. _m('1-64 lowercase letters or numbers, no punctuation or spaces.')); $this->elementEnd('li'); @@ -479,46 +418,43 @@ class TwitterauthorizationAction extends Action return ''; } - function message($msg) - { - $this->message_text = $msg; - $this->showPage(); - } - - function createNewUser() + protected function createNewUser() { + common_debug('TwitterBridgeDebug - createNewUser'); if (!Event::handle('StartRegistrationTry', array($this))) { - return; + common_debug('TwitterBridgeDebug - StartRegistrationTry failed'); + // TRANS: Client error displayed when trying to create a new user but a plugin aborted the process. + throw new ClientException(_m('Registration of new user was aborted, maybe you failed a captcha?')); } if (common_config('site', 'closed')) { + common_debug('TwitterBridgeDebug - site is closed for registrations'); // TRANS: Client error displayed when trying to create a new user while creating new users is not allowed. - $this->clientError(_m('Registration not allowed.')); + throw new ClientException(_m('Registration not allowed.')); } $invite = null; if (common_config('site', 'inviteonly')) { + common_debug('TwitterBridgeDebug - site is inviteonly'); $code = $_SESSION['invitecode']; if (empty($code)) { // TRANS: Client error displayed when trying to create a new user while creating new users is not allowed. - $this->clientError(_m('Registration not allowed.')); + throw new ClientException(_m('Registration not allowed.')); } - $invite = Invitation::getKV($code); + $invite = Invitation::getKV('code', $code); - if (empty($invite)) { + if (!$invite instanceof Invite) { + common_debug('TwitterBridgeDebug - and we failed the invite code test'); // TRANS: Client error displayed when trying to create a new user with an invalid invitation code. - $this->clientError(_m('Not a valid invitation code.')); + throw new ClientException(_m('Not a valid invitation code.')); } } - try { - $nickname = Nickname::normalize($this->trimmed('newname'), true); - } catch (NicknameException $e) { - $this->showForm($e->getMessage()); - return; - } + common_debug('TwitterBridgeDebug - trying our nickname: '.$this->trimmed('newname')); + // Nickname::normalize throws exception if the nickname is taken + $nickname = Nickname::normalize($this->trimmed('newname'), true); $fullname = trim($this->tw_fields['fullname']); @@ -533,23 +469,18 @@ class TwitterauthorizationAction extends Action $args['email'] = $email; } - try { - $user = User::register($args); - } catch (Exception $e) { - $this->serverError($e->getMessage()); - } + common_debug('TwitterBridgeDebug - registering user with args:'.var_export($args,true)); + $user = User::register($args); - $result = $this->saveForeignLink($user->id, - $this->twuid, - $this->access_token); + common_debug('TwitterBridgeDebug - registered the user and saving foreign link for '.$user->id); + $this->saveForeignLink($user->id, + $this->twuid, + $this->access_token); + + common_debug('TwitterBridgeDebug - saving twitter user after creating new local user '.$user->id); save_twitter_user($this->twuid, $this->tw_fields['screen_name']); - if (!$result) { - // TRANS: Server error displayed when connecting a user to a Twitter user has failed. - $this->serverError(_m('Error connecting user to Twitter.')); - } - common_set_user($user); common_real_login(true); @@ -569,28 +500,23 @@ class TwitterauthorizationAction extends Action if (!common_check_user($nickname, $password)) { // TRANS: Form validation error displayed when connecting an existing user to a Twitter user fails because // TRANS: the provided username and/or password are incorrect. - $this->showForm(_m('Invalid username or password.')); - return; + throw new ClientException(_m('Invalid username or password.')); } $user = User::getKV('nickname', $nickname); - if (!empty($user)) { + if ($user instanceof User) { common_debug('TwitterBridge Plugin - ' . "Legit user to connect to Twitter: $nickname"); } - $result = $this->saveForeignLink($user->id, - $this->twuid, - $this->access_token); + // throws exception on failure + $this->saveForeignLink($user->id, + $this->twuid, + $this->access_token); save_twitter_user($this->twuid, $this->tw_fields['screen_name']); - if (!$result) { - // TRANS: Server error displayed connecting a user to a Twitter user has failed. - $this->serverError(_m('Error connecting user to Twitter.')); - } - common_debug('TwitterBridge Plugin - ' . "Connected Twitter user $this->twuid to local user $user->id"); @@ -618,34 +544,30 @@ class TwitterauthorizationAction extends Action common_redirect(common_local_url('twittersettings'), 303); } - function tryLogin() + protected function tryLogin() { common_debug('TwitterBridge Plugin - ' . "Trying login for Twitter user $this->twuid."); - $flink = Foreign_link::getByForeignID($this->twuid, - TWITTER_SERVICE); - - if (!empty($flink)) { + try { + $flink = Foreign_link::getByForeignID($this->twuid, TWITTER_SERVICE); $user = $flink->getUser(); - if (!empty($user)) { - - common_debug('TwitterBridge Plugin - ' . - "Logged in Twitter user $flink->foreign_id as user $user->id ($user->nickname)"); - - common_set_user($user); - common_real_login(true); - $this->goHome($user->nickname); - } - - } else { - common_debug('TwitterBridge Plugin - ' . - "No flink found for twuid: $this->twuid - new user"); + "Logged in Twitter user $flink->foreign_id as user $user->id ($user->nickname)"); - $this->showForm(null, $this->bestNewNickname()); + common_set_user($user); + common_real_login(true); + $this->goHome($user->nickname); + } catch (NoResultException $e) { + // Either no Foreign_link was found or not the user connected to it. + // Let's just continue to allow creating or logging in as a new user. } + common_debug("TwitterBridge Plugin - No flink found for twuid: {$this->twuid} - new user"); + + // FIXME: what do we want to do here? I forgot + return; + throw new ServerException(_m('No foreign link found for Twitter user')); } function goHome($nickname) diff --git a/plugins/TwitterBridge/actions/twitterlogin.php b/plugins/TwitterBridge/actions/twitterlogin.php index ee00714c9f..f4af7d577d 100644 --- a/plugins/TwitterBridge/actions/twitterlogin.php +++ b/plugins/TwitterBridge/actions/twitterlogin.php @@ -28,9 +28,7 @@ * @link http://status.net/ */ -if (!defined('STATUSNET') && !defined('LACONICA')) { - exit(1); -} +if (!defined('GNUSOCIAL')) { exit(1); } require_once dirname(__DIR__) . '/twitter.php'; @@ -46,20 +44,8 @@ require_once dirname(__DIR__) . '/twitter.php'; * * @see SettingsAction */ -class TwitterloginAction extends Action +class TwitterloginAction extends LoginAction { - function handle($args) - { - parent::handle($args); - - if (common_is_real_login()) { - // TRANS: Client error displayed when trying to log in using Twitter while already logged in to StatusNet. - $this->clientError(_m('Already logged in.')); - } - - $this->showPage(); - } - function title() { // TRANS: Title for login using Twitter page. @@ -72,15 +58,6 @@ class TwitterloginAction extends Action return _m('Login with your Twitter account'); } - function showPageNotice() - { - $instr = $this->getInstructions(); - $output = common_markup_to_html($instr); - $this->elementStart('div', 'instructions'); - $this->raw($output); - $this->elementEnd('div'); - } - function showContent() { $this->elementStart('a', array('href' => common_local_url('twitterauthorization', diff --git a/plugins/TwitterBridge/actions/twittersettings.php b/plugins/TwitterBridge/actions/twittersettings.php index 37abb4d272..ccdb44fcb9 100644 --- a/plugins/TwitterBridge/actions/twittersettings.php +++ b/plugins/TwitterBridge/actions/twittersettings.php @@ -27,9 +27,7 @@ * @link http://status.net/ */ -if (!defined('STATUSNET') && !defined('LACONICA')) { - exit(1); -} +if (!defined('GNUSOCIAL')) { exit(1); } require_once dirname(__DIR__) . '/twitter.php'; @@ -46,6 +44,18 @@ require_once dirname(__DIR__) . '/twitter.php'; */ class TwittersettingsAction extends ProfileSettingsAction { + protected $flink = null; + protected $fuser = null; + + protected function doPreparation() + { + try { + $this->flink = Foreign_link::getByUserID($this->scoped->getID(), TWITTER_SERVICE); + $this->fuser = $this->flink->getForeignUser(); + } catch (NoResultException $e) { + // No foreign link found for this user! + } + } /** * Title of the page * @@ -81,19 +91,6 @@ class TwittersettingsAction extends ProfileSettingsAction */ function showContent() { - - $user = common_current_user(); - - $profile = $user->getProfile(); - - $fuser = null; - - $flink = Foreign_link::getByUserID($user->id, TWITTER_SERVICE); - - if (!empty($flink)) { - $fuser = $flink->getForeignUser(); - } - $this->elementStart('form', array('method' => 'post', 'id' => 'form_settings_twitter', 'class' => 'form_settings', @@ -104,21 +101,11 @@ class TwittersettingsAction extends ProfileSettingsAction $this->elementStart('fieldset', array('id' => 'settings_twitter_account')); - if (empty($fuser)) { - $this->elementStart('ul', 'form_data'); - $this->elementStart('li', array('id' => 'settings_twitter_login_button')); - $this->element('a', array('href' => common_local_url('twitterauthorization')), - // TRANS: Link description to connect to a Twitter account. - 'Connect my Twitter account'); - $this->elementEnd('li'); - $this->elementEnd('ul'); - - $this->elementEnd('fieldset'); - } else { + if ($this->fuser instanceof Foreign_user) { // TRANS: Fieldset legend. $this->element('legend', null, _m('Twitter account')); $this->elementStart('p', array('id' => 'form_confirmed')); - $this->element('a', array('href' => $fuser->uri), $fuser->nickname); + $this->element('a', array('href' => $this->fuser->uri), $this->fuser->nickname); $this->elementEnd('p'); $this->element('p', 'form_note', // TRANS: Form note when a Twitter account has been connected. @@ -130,7 +117,7 @@ class TwittersettingsAction extends ProfileSettingsAction // TRANS: Fieldset legend. $this->element('legend', null, _m('Disconnect my account from Twitter')); - if (!$user->password) { + if (!$this->scoped->hasPassword()) { $this->elementStart('p', array('class' => 'form_guide')); // TRANS: Form guide. %s is a URL to the password settings. // TRANS: This message contains a Markdown link in the form [description](link). @@ -165,25 +152,19 @@ class TwittersettingsAction extends ProfileSettingsAction $this->checkbox('noticesend', // TRANS: Checkbox label. _m('Automatically send my notices to Twitter.'), - ($flink) ? - ($flink->noticesync & FOREIGN_NOTICE_SEND) : - true); + $this->flink->noticesync & FOREIGN_NOTICE_SEND); $this->elementEnd('li'); $this->elementStart('li'); $this->checkbox('replysync', // TRANS: Checkbox label. _m('Send local "@" replies to Twitter.'), - ($flink) ? - ($flink->noticesync & FOREIGN_NOTICE_SEND_REPLY) : - true); + $this->flink->noticesync & FOREIGN_NOTICE_SEND_REPLY); $this->elementEnd('li'); $this->elementStart('li'); $this->checkbox('friendsync', // TRANS: Checkbox label. _m('Subscribe to my Twitter friends here.'), - ($flink) ? - ($flink->friendsync & FOREIGN_FRIEND_RECV) : - false); + $this->flink->friendsync & FOREIGN_FRIEND_RECV); $this->elementEnd('li'); if (common_config('twitterimport','enabled')) { @@ -191,31 +172,37 @@ class TwittersettingsAction extends ProfileSettingsAction $this->checkbox('noticerecv', // TRANS: Checkbox label. _m('Import my friends timeline.'), - ($flink) ? - ($flink->noticesync & FOREIGN_NOTICE_RECV) : - false); + $this->flink->noticesync & FOREIGN_NOTICE_RECV); $this->elementEnd('li'); } else { // preserve setting even if bidrection bridge toggled off - if ($flink && ($flink->noticesync & FOREIGN_NOTICE_RECV)) { + if ($this->flink->noticesync & FOREIGN_NOTICE_RECV) { $this->hidden('noticerecv', true, 'noticerecv'); } } $this->elementEnd('ul'); - if ($flink) { + if ($this->flink instanceof Foreign_link) { // TRANS: Button text for saving Twitter integration settings. $this->submit('save', _m('BUTTON','Save')); } else { // TRANS: Button text for adding Twitter integration. $this->submit('add', _m('BUTTON','Add')); } - - $this->elementEnd('fieldset'); + } else { + $this->elementStart('ul', 'form_data'); + $this->elementStart('li', array('id' => 'settings_twitter_login_button')); + $this->element('a', array('href' => common_local_url('twitterauthorization')), + // TRANS: Link description to connect to a Twitter account. + 'Connect my Twitter account'); + $this->elementEnd('li'); + $this->elementEnd('ul'); } + $this->elementEnd('fieldset'); + $this->elementEnd('form'); } @@ -229,25 +216,15 @@ class TwittersettingsAction extends ProfileSettingsAction * * @return void */ - function handlePost() + protected function doPost() { - // CSRF protection - $token = $this->trimmed('token'); - if (!$token || $token != common_session_token()) { - // TRANS: Client error displayed when the session token does not match or is not given. - $this->showForm(_m('There was a problem with your session token. '. - 'Try again, please.')); - return; - } - if ($this->arg('save')) { - $this->savePreferences(); + return $this->savePreferences(); } else if ($this->arg('disconnect')) { - $this->removeTwitterAccount(); - } else { - // TRANS: Client error displayed when the submitted form contains unexpected data. - $this->showForm(_m('Unexpected form submission.')); + return $this->removeTwitterAccount(); } + // TRANS: Client error displayed when the submitted form contains unexpected data. + throw new ClientException(_m('Unexpected form submission.')); } /** @@ -255,26 +232,26 @@ class TwittersettingsAction extends ProfileSettingsAction * * @return void */ - function removeTwitterAccount() + protected function removeTwitterAccount() { - $user = common_current_user(); - $flink = Foreign_link::getByUserID($user->id, TWITTER_SERVICE); - - if (empty($flink)) { - // TRANS: Client error displayed when trying to remove a connected Twitter account when there isn't one connected. - $this->clientError(_m('No Twitter connection to remove.')); + if (!$this->flink instanceof Foreign_link) { + // TRANS: Error message possibly displayed when trying to remove a connected Twitter account when there isn't one connected. + throw new AlreadyFulfilledException(_m('No Twitter connection to remove.')); } - $result = $flink->safeDelete(); + $result = $this->flink->safeDelete(); - if (empty($result)) { - common_log_db_error($flink, 'DELETE', __FILE__); + if ($result === false) { + common_log_db_error($this->flink, 'DELETE', __FILE__); // TRANS: Server error displayed when trying to remove a connected Twitter account fails. - $this->serverError(_m('Could not remove Twitter user.')); + throw new ServerException(_m('Could not remove Twitter user.')); } + $this->flink = null; + $this->fuser = null; + // TRANS: Success message displayed after disconnecting a Twitter account. - $this->showForm(_m('Twitter account disconnected.'), true); + return _m('Twitter account disconnected.'); } /** @@ -282,43 +259,36 @@ class TwittersettingsAction extends ProfileSettingsAction * * @return void */ - function savePreferences() + protected function savePreferences() { $noticesend = $this->boolean('noticesend'); $noticerecv = $this->boolean('noticerecv'); $friendsync = $this->boolean('friendsync'); $replysync = $this->boolean('replysync'); - $user = common_current_user(); - $flink = Foreign_link::getByUserID($user->id, TWITTER_SERVICE); - - if (empty($flink)) { - common_log_db_error($flink, 'SELECT', __FILE__); - // @todo FIXME: Shouldn't this be a serverError()? + if (!$this->flink instanceof Foreign_link) { + common_log_db_error($this->flink, 'SELECT', __FILE__); // TRANS: Server error displayed when saving Twitter integration preferences fails. - $this->showForm(_m('Could not save Twitter preferences.')); - return; + throw new ServerException(_m('Your account is not linked to Twitter.')); } - $original = clone($flink); + $original = clone($this->flink); $wasReceiving = (bool)($original->noticesync & FOREIGN_NOTICE_RECV); - $flink->set_flags($noticesend, $noticerecv, $replysync, $friendsync); - $result = $flink->update($original); + $this->flink->set_flags($noticesend, $noticerecv, $replysync, $friendsync); + $result = $this->flink->update($original); if ($result === false) { - common_log_db_error($flink, 'UPDATE', __FILE__); - // @todo FIXME: Shouldn't this be a serverError()? + common_log_db_error($this->flink, 'UPDATE', __FILE__); // TRANS: Server error displayed when saving Twitter integration preferences fails. - $this->showForm(_m('Could not save Twitter preferences.')); - return; + throw new ServerException(_m('Could not save Twitter preferences.')); } if ($wasReceiving xor $noticerecv) { - $this->notifyDaemon($flink->foreign_id, $noticerecv); + $this->notifyDaemon($this->flink->foreign_id, $noticerecv); } // TRANS: Success message after saving Twitter integration preferences. - $this->showForm(_m('Twitter preferences saved.'), true); + return _m('Twitter preferences saved.'); } /** diff --git a/plugins/TwitterBridge/daemons/synctwitterfriends.php b/plugins/TwitterBridge/daemons/synctwitterfriends.php index a3862eedfd..9fa3b282b4 100755 --- a/plugins/TwitterBridge/daemons/synctwitterfriends.php +++ b/plugins/TwitterBridge/daemons/synctwitterfriends.php @@ -104,6 +104,7 @@ class SyncTwitterFriendsDaemon extends ParallelizingDaemon return $flinks; } + // FIXME: make it so we can force a Foreign_link here without colliding with parent function childTask($flink) { // Each child ps needs its own DB connection @@ -124,7 +125,7 @@ class SyncTwitterFriendsDaemon extends ParallelizingDaemon unset($_DB_DATAOBJECT['CONNECTIONS']); } - function fetchTwitterFriends($flink) + function fetchTwitterFriends(Foreign_link $flink) { $friends = array(); @@ -192,8 +193,14 @@ class SyncTwitterFriendsDaemon extends ParallelizingDaemon return $friends; } - function subscribeTwitterFriends($flink) + function subscribeTwitterFriends(Foreign_link $flink) { + try { + $profile = $flink->getProfile(); + } catch (NoResultException $e) { + common_log(LOG_WARNING, 'Foreign_link has no matching local profile for local ID: '.$flink->user_id); + } + $friends = $this->fetchTwitterFriends($flink); if (empty($friends)) { @@ -203,8 +210,6 @@ class SyncTwitterFriendsDaemon extends ParallelizingDaemon return false; } - $profile = $flink->getProfile(); - foreach ($friends as $friend) { $friend_name = $friend->screen_name; @@ -219,31 +224,24 @@ class SyncTwitterFriendsDaemon extends ParallelizingDaemon continue; } - // Check to see if there's a related local user - - $friend_flink = Foreign_link::getByForeignID($friend_id, - TWITTER_SERVICE); - - if (!empty($friend_flink)) { + // Check to see if there's a related local user and try to subscribe + try { + $friend_flink = Foreign_link::getByForeignID($friend_id, TWITTER_SERVICE); // Get associated user and subscribe her + $friend_profile = $friend_flink->getProfile(); - $friend_profile = Profile::getKV('id', $friend_flink->user_id); - - if ($friend_profile instanceof Profile) { - try { - $other = Profile::getKV('id', $invites->user_id); - Subscription::start($profile, $friend_profile); - common_log(LOG_INFO, - $this->name() . ' - Subscribed ' . - "{$friend_profile->nickname} to {$profile->nickname}."); - } catch (Exception $e) { - common_debug($this->name() . - ' - Tried and failed subscribing ' . - "{$friend_profile->nickname} to {$profile->nickname} - " . - $e->getMessage()); - } - } + Subscription::start($profile, $friend_profile); + common_log(LOG_INFO, + $this->name() . ' - Subscribed ' . + "{$friend_profile->nickname} to {$profile->nickname}."); + } catch (NoResultException $e) { + // either no foreign link for this friend's foreign ID or no profile found on local ID. + } catch (Exception $e) { + common_debug($this->name() . + ' - Tried and failed subscribing ' . + "{$friend_profile->nickname} to {$profile->nickname} - " . + $e->getMessage()); } } diff --git a/plugins/TwitterBridge/daemons/twitterstatusfetcher.php b/plugins/TwitterBridge/daemons/twitterstatusfetcher.php index d444b8aa5d..83e8a0df5e 100755 --- a/plugins/TwitterBridge/daemons/twitterstatusfetcher.php +++ b/plugins/TwitterBridge/daemons/twitterstatusfetcher.php @@ -128,6 +128,7 @@ class TwitterStatusFetcher extends ParallelizingDaemon return $flinks; } + // FIXME: make it so we can force a Foreign_link here without colliding with parent function childTask($flink) { // Each child ps needs its own DB connection @@ -149,14 +150,8 @@ class TwitterStatusFetcher extends ParallelizingDaemon unset($_DB_DATAOBJECT['CONNECTIONS']); } - function getTimeline($flink, $timelineUri = 'home_timeline') + function getTimeline(Foreign_link $flink, $timelineUri = 'home_timeline') { - if (empty($flink)) { - common_log(LOG_ERR, $this->name() . - " - Can't retrieve Foreign_link for foreign ID $fid"); - return; - } - common_log(LOG_DEBUG, $this->name() . ' - Trying to get ' . $timelineUri . ' timeline for Twitter user ' . $flink->foreign_id); diff --git a/plugins/TwitterBridge/lib/tweetinqueuehandler.php b/plugins/TwitterBridge/lib/tweetinqueuehandler.php index cc0c05f9a6..69ce5a61e9 100644 --- a/plugins/TwitterBridge/lib/tweetinqueuehandler.php +++ b/plugins/TwitterBridge/lib/tweetinqueuehandler.php @@ -51,8 +51,8 @@ class TweetInQueueHandler extends QueueHandler $importer = new TwitterImport(); $notice = $importer->importStatus($status); if ($notice instanceof Notice) { - $flink = Foreign_link::getByForeignID($receiver, TWITTER_SERVICE); - if ($flink instanceof Foreign_link) { + try { + $flink = Foreign_link::getByForeignID($receiver, TWITTER_SERVICE); common_log(LOG_DEBUG, "TweetInQueueHandler - Got flink so add notice ". $notice->id." to attentions for user ".$flink->user_id); try { @@ -63,7 +63,7 @@ class TweetInQueueHandler extends QueueHandler common_log(LOG_ERR, "Failed adding notice {$notice->id} to attentions for user {$flink->user_id}: " . $e->getMessage()); } - } else { + } catch (NoResultException $e) { common_log(LOG_DEBUG, "TweetInQueueHandler - No flink found for foreign user ".$receiver); } } diff --git a/plugins/TwitterBridge/lib/twitterimport.php b/plugins/TwitterBridge/lib/twitterimport.php index 45b7547ce2..d929fecf83 100644 --- a/plugins/TwitterBridge/lib/twitterimport.php +++ b/plugins/TwitterBridge/lib/twitterimport.php @@ -542,17 +542,17 @@ class TwitterImport } foreach ($status->entities->user_mentions as $mention) { - $flink = Foreign_link::getByForeignID($mention->id, TWITTER_SERVICE); - if (!empty($flink)) { - $user = User::getKV('id', $flink->user_id); - if (!empty($user)) { - $reply = new Reply(); - $reply->notice_id = $notice->id; - $reply->profile_id = $user->id; - $reply->modified = $notice->created; - common_log(LOG_INFO, __METHOD__ . ": saving reply: notice {$notice->id} to profile {$user->id}"); - $id = $reply->insert(); - } + try { + $flink = Foreign_link::getByForeignID($mention->id, TWITTER_SERVICE); + $user = $flink->getUser(); + $reply = new Reply(); + $reply->notice_id = $notice->id; + $reply->profile_id = $user->id; + $reply->modified = $notice->created; + common_log(LOG_INFO, __METHOD__ . ": saving reply: notice {$notice->id} to profile {$user->id}"); + $id = $reply->insert(); + } catch (NoResultException $e) { + common_log(LOG_WARNING, 'No local user found for Foreign_link with local User id: '.$flink->user_id); } } } diff --git a/plugins/TwitterBridge/lib/twitteroauthclient.php b/plugins/TwitterBridge/lib/twitteroauthclient.php index f992a09079..93d10b8d48 100644 --- a/plugins/TwitterBridge/lib/twitteroauthclient.php +++ b/plugins/TwitterBridge/lib/twitteroauthclient.php @@ -111,7 +111,7 @@ class TwitterOAuthClient extends OAuthClient * * @return OAuthToken $token the request token */ - function getRequestToken() + function getTwitterRequestToken() { return parent::getRequestToken( self::$requestTokenURL, @@ -126,7 +126,7 @@ class TwitterOAuthClient extends OAuthClient * * @return the link */ - function getAuthorizeLink($request_token, $signin = false) + function getTwitterAuthorizeLink($request_token, $signin = false) { $url = ($signin) ? self::$signinUrl : self::$authorizeURL; @@ -142,7 +142,7 @@ class TwitterOAuthClient extends OAuthClient * * @return OAuthToken $token the access token */ - function getAccessToken($verifier = null) + function getTwitterAccessToken($verifier = null) { return parent::getAccessToken( self::$accessTokenURL, diff --git a/plugins/TwitterBridge/scripts/fakestream.php b/plugins/TwitterBridge/scripts/fakestream.php index e827a07117..5d965e7394 100644 --- a/plugins/TwitterBridge/scripts/fakestream.php +++ b/plugins/TwitterBridge/scripts/fakestream.php @@ -62,12 +62,7 @@ if (have_option('n')) { */ function twitterAuthForUser(User $user) { - $flink = Foreign_link::getByUserID($user->id, - TWITTER_SERVICE); - if (!$flink) { - throw new ServerException("No Twitter config for this user."); - } - + $flink = Foreign_link::getByUserID($user->id, TWITTER_SERVICE); $token = TwitterOAuthClient::unpackToken($flink->credentials); if (!$token) { throw new ServerException("No Twitter OAuth credentials for this user."); diff --git a/plugins/TwitterBridge/scripts/streamtest.php b/plugins/TwitterBridge/scripts/streamtest.php index 4e8340bb3f..a642920cee 100644 --- a/plugins/TwitterBridge/scripts/streamtest.php +++ b/plugins/TwitterBridge/scripts/streamtest.php @@ -63,12 +63,7 @@ if (have_option('n')) { */ function twitterAuthForUser(User $user) { - $flink = Foreign_link::getByUserID($user->id, - TWITTER_SERVICE); - if (!$flink) { - throw new ServerException("No Twitter config for this user."); - } - + $flink = Foreign_link::getByUserID($user->id, TWITTER_SERVICE); $token = TwitterOAuthClient::unpackToken($flink->credentials); if (!$token) { throw new ServerException("No Twitter OAuth credentials for this user."); diff --git a/plugins/TwitterBridge/twitter.php b/plugins/TwitterBridge/twitter.php index b607fe6052..0f1e686ac8 100644 --- a/plugins/TwitterBridge/twitter.php +++ b/plugins/TwitterBridge/twitter.php @@ -28,16 +28,17 @@ function add_twitter_user($twitter_id, $screen_name) // Clear out any bad old foreign_users with the new user's legit URL // This can happen when users move around or fakester accounts get // repoed, and things like that. - $luser = Foreign_user::getForeignUser($twitter_id, TWITTER_SERVICE); - - if (!empty($luser)) { - $result = $luser->delete(); + try { + $fuser = Foreign_user::getForeignUser($twitter_id, TWITTER_SERVICE); + $result = $fuser->delete(); if ($result != false) { common_log( LOG_INFO, "Twitter bridge - removed old Twitter user: $screen_name ($twitter_id)." ); } + } catch (NoResultException $e) { + // no old foreign users exist for this id } $fuser = new Foreign_user(); @@ -49,9 +50,8 @@ function add_twitter_user($twitter_id, $screen_name) $fuser->created = common_sql_now(); $result = $fuser->insert(); - if (empty($result)) { - common_log(LOG_WARNING, - "Twitter bridge - failed to add new Twitter user: $twitter_id - $screen_name."); + if ($result === false) { + common_log(LOG_WARNING, "Twitter bridge - failed to add new Twitter user: $twitter_id - $screen_name."); common_log_db_error($fuser, 'INSERT', __FILE__); } else { common_log(LOG_INFO, @@ -66,11 +66,10 @@ function save_twitter_user($twitter_id, $screen_name) { // Check to see whether the Twitter user is already in the system, // and update its screen name and uri if so. - $fuser = Foreign_user::getForeignUser($twitter_id, TWITTER_SERVICE); + try { + $fuser = Foreign_user::getForeignUser($twitter_id, TWITTER_SERVICE); - if (!empty($fuser)) { // Delete old record if Twitter user changed screen name - if ($fuser->nickname != $screen_name) { $oldname = $fuser->nickname; $fuser->delete(); @@ -80,11 +79,13 @@ function save_twitter_user($twitter_id, $screen_name) $screen_name, $oldname)); } - } else { + } catch (NoResultException $e) { + // No old users exist for this id + // Kill any old, invalid records for this screen name - $fuser = Foreign_user::getByNickname($screen_name, TWITTER_SERVICE); - - if (!empty($fuser)) { + // XXX: Is this really only supposed to be run if the above getForeignUser fails? + try { + $fuser = Foreign_user::getByNickname($screen_name, TWITTER_SERVICE); $fuser->delete(); common_log( LOG_INFO, @@ -95,6 +96,8 @@ function save_twitter_user($twitter_id, $screen_name) $fuser->id ) ); + } catch (NoResultException $e) { + // No old users exist for this screen_name } } @@ -178,11 +181,15 @@ function twitter_id($status, $field='id') */ function broadcast_twitter($notice) { - $flink = Foreign_link::getByUserID($notice->profile_id, - TWITTER_SERVICE); + try { + $flink = Foreign_link::getByUserID($notice->profile_id, TWITTER_SERVICE); + } catch (NoResultException $e) { + // Alright so don't broadcast it then! (since there's no foreign link) + return true; + } // Don't bother with basic auth, since it's no longer allowed - if (!empty($flink) && TwitterOAuthClient::isPackedToken($flink->credentials)) { + if (TwitterOAuthClient::isPackedToken($flink->credentials)) { if (is_twitter_bound($notice, $flink)) { if (!empty($notice->repeat_of) && is_twitter_notice($notice->repeat_of)) { $retweet = retweet_notice($flink, Notice::getKV('id', $notice->repeat_of)); @@ -270,8 +277,13 @@ function twitter_update_params($notice) return $params; } -function broadcast_oauth($notice, $flink) { - $user = $flink->getUser(); +function broadcast_oauth($notice, Foreign_link $flink) { + try { + $user = $flink->getUser(); + } catch (ServerException $e) { + common_log(LOG_WARNING, 'Discarding broadcast_oauth for notice '.$notice->id.' because of exception: '.$e->getMessage()); + return true; + } $statustxt = format_status($notice); $params = twitter_update_params($notice); diff --git a/plugins/WebFinger/WebFingerPlugin.php b/plugins/WebFinger/WebFingerPlugin.php index 91dc9b53f7..c2a9c69d0c 100644 --- a/plugins/WebFinger/WebFingerPlugin.php +++ b/plugins/WebFinger/WebFingerPlugin.php @@ -144,7 +144,7 @@ class WebFingerPlugin extends Plugin public function onStartShowHTML($action) { if ($action instanceof ShowstreamAction) { - $acct = 'acct:'. $action->profile->nickname .'@'. common_config('site', 'server'); + $acct = 'acct:'. $action->getTarget()->getNickname() .'@'. common_config('site', 'server'); $url = common_local_url('webfinger') . '?resource='.$acct; foreach (array(Discovery::JRD_MIMETYPE, Discovery::XRD_MIMETYPE) as $type) { diff --git a/plugins/Xmpp/XmppPlugin.php b/plugins/Xmpp/XmppPlugin.php index 0a70268735..04101a8e2b 100644 --- a/plugins/Xmpp/XmppPlugin.php +++ b/plugins/Xmpp/XmppPlugin.php @@ -308,11 +308,6 @@ class XmppPlugin extends ImPlugin return true; } - function microiduri($screenname) - { - return 'xmpp:' . $screenname; - } - function sendMessage($screenname, $body) { $this->queuedConnection()->message($screenname, $body, 'chat'); diff --git a/scripts/delete_notice.php b/scripts/delete_notice.php new file mode 100755 index 0000000000..bf10cbb2b2 --- /dev/null +++ b/scripts/delete_notice.php @@ -0,0 +1,68 @@ +#!/usr/bin/env php +. + */ + +define('INSTALLDIR', realpath(dirname(__FILE__) . '/..')); + +$shortoptions = 'i::n::u::y'; +$longoptions = array('id=', 'nickname=', 'uri=', 'yes'); + +$helptext = <<getID()." by '".$notice->getProfile()->getNickname()."'. Are you sure? [y/N] "; + $response = fgets(STDIN); + if (strtolower(trim($response)) != 'y') { + print "Aborting.\n"; + exit(0); + } +} + +print "Deleting..."; +$notice->delete(); +print "DONE.\n"; diff --git a/theme/base/css/display.css b/theme/base/css/display.css index ddc225fb82..20f9aa775f 100644 --- a/theme/base/css/display.css +++ b/theme/base/css/display.css @@ -1622,6 +1622,11 @@ ul.profile_list li { display: block; } +table.profile_list tbody tr:nth-child(2n+1) { + background-color: #fafafa !important; + border: none !important; +} + .entity_profile .entity_nickname, .entity_profile .entity_fn { margin-left:0; diff --git a/theme/neo-gnu/css/display.css b/theme/neo-gnu/css/display.css index 39cce89e48..be9b80d41c 100644 --- a/theme/neo-gnu/css/display.css +++ b/theme/neo-gnu/css/display.css @@ -1141,11 +1141,6 @@ table.profile_list { background: url(../images/bluearrow_up.png) no-repeat top right; } -table.profile_list tr.alt { - background-color: #fafafa !important; - border: none !important; -} - td.entity_profile { width: auto; min-width: 250px; diff --git a/theme/neo/css/display.css b/theme/neo/css/display.css index 601845164b..575e6b7386 100644 --- a/theme/neo/css/display.css +++ b/theme/neo/css/display.css @@ -938,11 +938,6 @@ table.profile_list { background: url(../images/bluearrow_up.png) no-repeat top right; } -table.profile_list tr.alt { - background-color: #fafafa !important; - border: none !important; -} - td.entity_profile { width: auto; min-width: 250px;