diff --git a/CONFIGURE b/CONFIGURE index d41f64b44f..8abc0513a9 100644 --- a/CONFIGURE +++ b/CONFIGURE @@ -182,6 +182,8 @@ sending out SMS email or XMPP messages, for off-line processing. See 'Queues and daemons' above for how to set this up. enabled: Whether to uses queues. Defaults to false. +daemon: Wather to use queuedaemon. Defaults to false, which means + you'll use OpportunisticQM plugin. subsystem: Which kind of queueserver to use. Values include "db" for our hacked-together database queuing (no other server required) and "stomp" for a stomp server. @@ -532,32 +534,6 @@ welcome: nickname of a user account that sends welcome messages to new If either of these special user accounts are specified, the users should be created before the configuration is updated. -snapshot --------- - -The software will, by default, send statistical snapshots about the -local installation to a stats server on the status.net Web site. This -data is used by the developers to prioritize development decisions. No -identifying data about users or organizations is collected. The data -is available to the public for review. Participating in this survey -helps StatusNet developers take your needs into account when updating -the software. - -run: string indicating when to run the statistics. Values can be 'web' - (run occasionally at Web time), 'cron' (run from a cron script), - or 'never' (don't ever run). If you set it to 'cron', remember to - schedule the script to run on a regular basis. -frequency: if run value is 'web', how often to report statistics. - Measured in Web hits; depends on how active your site is. - Default is 10000 -- that is, one report every 10000 Web hits, - on average. -reporturl: URL to post statistics to. Defaults to StatusNet developers' - report system, but if they go evil or disappear you may - need to update this to another value. Note: if you - don't want to report stats, it's much better to - set 'run' to 'never' than to set this value to something - nonsensical. - attachments ----------- diff --git a/EVENTS.txt b/EVENTS.txt index fd75036894..0a1951d640 100644 --- a/EVENTS.txt +++ b/EVENTS.txt @@ -966,6 +966,9 @@ StartShowNoticeForm: before showing the notice form (before
) EndShowNoticeForm: after showing the notice form (after ) - $action: action being executed +StartShowEntryForms: microapp entry form tab data +- &$tabs: tab assoc array with 'tag' => (title, href to create new entry) + StartGrantRole: when a role is being assigned - $profile: profile that will have the role - $role: string name of the role diff --git a/INSTALL b/INSTALL index bac8d34005..20817f3009 100644 --- a/INSTALL +++ b/INSTALL @@ -368,12 +368,41 @@ Queues and daemons ------------------ Some activities that StatusNet needs to do, like broadcast OStatus, SMS, -and XMPP messages, can be 'queued' and done by off-line bots instead. -For this to work, you must be able to run long-running offline -processes, either on your main Web server or on another server you -control. (Your other server will still need all the above -prerequisites, with the exception of Apache.) Installing on a separate -server is probably a good idea for high-volume sites. +XMPP messages and TwitterBridge operations, can be 'queued' and done by +off-line bots instead. + +Two mechanisms are available to achieve offline operations: + +* New embedded OpportunisticQM plugin, which is enabled by default +* Legacy queuedaemon script, which can be enabled via config file. + +### OpportunisticQM plugin + +This plugin is enabled by default. It tries its best to do background +job during regular HTTP requests, like API or HTML pages calls. + +Since queueing system is enabled by default, notices to be broadcasted +will be stored, by default, into DB (table queue_item). + +Each time it can, OpportunisticQM will try to handle some of them. + +This is a good solution whether you: + +* have no access to command line (shared hosting) +* do not want to deal with long-running PHP processes +* run a low traffic GNU social instance + +In other case, you really should consider enabling the queuedaemon for +performance reasons. Background daemons are necessary anyway if you wish +to use the Instant Messaging features such as communicating via XMPP. + +### queuedaemon + +If you want to use legacy queuedaemon, you must be able to run +long-running offline processes, either on your main Web server or on +another server you control. (Your other server will still need all the +above prerequisites, with the exception of Apache.) Installing on a +separate server is probably a good idea for high-volume sites. 1. You'll need the "CLI" (command-line interface) version of PHP installed on whatever server you use. @@ -399,6 +428,7 @@ server is probably a good idea for high-volume sites. server!), set the following variable: $config['queue']['enabled'] = true; + $config['queue']['daemon'] = true; You may also want to look at the 'daemon' section of this file for more daemon options. Note that if you set the 'user' and/or 'group' @@ -412,7 +442,7 @@ This will run the queue handlers: * queuedaemon.php - polls for queued items for inbox processing and pushing out to OStatus, SMS, XMPP, etc. * imdaemon.php - if an IM plugin is enabled (like XMPP) -* other daemons that you may have enabled +* other daemons, like TwitterBridge ones, that you may have enabled These daemons will automatically restart in most cases of failure including memory leaks (if a memory_limit is set), but may still die diff --git a/actions/all.php b/actions/all.php index 1d9509f6db..f794064f87 100644 --- a/actions/all.php +++ b/actions/all.php @@ -30,18 +30,12 @@ * @author Sarven Capadisli * @author Siebrand Mazeland * @author Zach Copley - * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org + * @copyright 2009-2014 Free Software Foundation, Inc http://www.fsf.org * @license GNU Affero General Public License http://www.gnu.org/licenses/ * @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') && !defined('STATUSNET')) { exit(1); } class AllAction extends ProfileAction { @@ -52,16 +46,16 @@ class AllAction extends ProfileAction return true; } - function prepare($args) + protected function prepare(array $args=array()) { parent::prepare($args); $user = common_current_user(); if (!empty($user) && $user->streamModeOnly()) { - $stream = new InboxNoticeStream($this->user, Profile::current()); + $stream = new InboxNoticeStream($this->target, $this->scoped); } else { - $stream = new ThreadingInboxNoticeStream($this->user, Profile::current()); + $stream = new ThreadingInboxNoticeStream($this->target, $this->scoped); } $this->notice = $stream->getNotices(($this->page-1)*NOTICES_PER_PAGE, @@ -75,14 +69,13 @@ class AllAction extends ProfileAction return true; } - function handle($args) + protected function handle() { - parent::handle($args); + parent::handle(); - if (!$this->user) { + if (!$this->target instanceof Profile) { // TRANS: Client error when user not found for an action. $this->clientError(_('No such user.')); - return; } $this->showPage(); @@ -90,15 +83,13 @@ class AllAction extends ProfileAction function title() { - $user = common_current_user(); - if (!empty($user) && $user->id == $this->user->id) { + if (!empty($this->scoped) && $this->scoped->id == $this->target->id) { // TRANS: Title of a user's own start page. return _('Home timeline'); } else { - $profile = $this->user->getProfile(); // TRANS: Title of another user's start page. // TRANS: %s is the other user's name. - return sprintf(_("%s's home timeline"), $profile->getBestName()); + return sprintf(_("%s's home timeline"), $this->target->getBestName()); } } @@ -109,60 +100,59 @@ class AllAction extends ProfileAction common_local_url( 'ApiTimelineFriends', array( 'format' => 'as', - 'id' => $this->user->nickname + 'id' => $this->target->nickname ) ), // TRANS: %s is user nickname. - sprintf(_('Feed for friends of %s (Activity Streams JSON)'), $this->user->nickname)), + sprintf(_('Feed for friends of %s (Activity Streams JSON)'), $this->target->nickname)), new Feed(Feed::RSS1, common_local_url( 'allrss', array( 'nickname' => - $this->user->nickname) + $this->target->nickname) ), // TRANS: %s is user nickname. - sprintf(_('Feed for friends of %s (RSS 1.0)'), $this->user->nickname)), + sprintf(_('Feed for friends of %s (RSS 1.0)'), $this->target->nickname)), new Feed(Feed::RSS2, common_local_url( 'ApiTimelineFriends', array( 'format' => 'rss', - 'id' => $this->user->nickname + 'id' => $this->target->nickname ) ), // TRANS: %s is user nickname. - sprintf(_('Feed for friends of %s (RSS 2.0)'), $this->user->nickname)), + sprintf(_('Feed for friends of %s (RSS 2.0)'), $this->target->nickname)), new Feed(Feed::ATOM, common_local_url( 'ApiTimelineFriends', array( 'format' => 'atom', - 'id' => $this->user->nickname + 'id' => $this->target->nickname ) ), // TRANS: %s is user nickname. - sprintf(_('Feed for friends of %s (Atom)'), $this->user->nickname)) + sprintf(_('Feed for friends of %s (Atom)'), $this->target->nickname)) ); } 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->user->nickname) . ' '; + $message = sprintf(_('This is the timeline for %s and friends but no one has posted anything yet.'), $this->target->nickname) . ' '; if (common_logged_in()) { - $current_user = common_current_user(); - if ($this->user->id === $current_user->id) { + if ($this->target->id === $this->scoped->id) { // TRANS: Encouragement displayed on logged in user's empty timeline. // TRANS: This message contains Markdown links. Keep "](" together. $message .= _('Try subscribing to more people, [join a group](%%action.groups%%) or post something yourself.'); } 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->user->nickname, $this->user->nickname, '@' . $this->user->nickname); + $message .= sprintf(_('You can try to [nudge %1$s](../%2$s) from their profile or [post something to them](%%%%action.newnotice%%%%?status_textarea=%3$s).'), $this->target->nickname, $this->target->nickname, '@' . $this->target->nickname); } } 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->user->nickname); + $message .= sprintf(_('Why not [register an account](%%%%action.register%%%%) and then nudge %s or post a notice to them.'), $this->target->nickname); } $this->elementStart('div', 'guide'); @@ -196,7 +186,7 @@ class AllAction extends ProfileAction $this->pagination( $this->page > 1, $cnt > NOTICES_PER_PAGE, - $this->page, 'all', array('nickname' => $this->user->nickname) + $this->page, 'all', array('nickname' => $this->target->nickname) ); Event::handle('EndShowAllContent', array($this)); @@ -225,7 +215,7 @@ class AllAction extends ProfileAction if (!common_config('performance', 'high')) { $pop = new PopularNoticeSection($this, Profile::current()); $pop->show(); - $pop = new InboxTagCloudSection($this, $this->user); + $pop = new InboxTagCloudSection($this, $this->target); $pop->show(); } } diff --git a/actions/apigroupjoin.php b/actions/apigroupjoin.php index 10081ae1b5..3e571801f2 100644 --- a/actions/apigroupjoin.php +++ b/actions/apigroupjoin.php @@ -72,7 +72,7 @@ class ApiGroupJoinAction extends ApiAuthAction /** * Handle the request * - * Save the new message + * Join the authenticated user to the group * * @return void */ @@ -80,7 +80,7 @@ class ApiGroupJoinAction extends ApiAuthAction { parent::handle(); - if (empty($this->user)) { + if (empty($this->scoped)) { // TRANS: Client error displayed when trying to have a non-existing user join a group. $this->clientError(_('No such user.'), 404); } @@ -90,23 +90,23 @@ class ApiGroupJoinAction extends ApiAuthAction $this->clientError(_('Group not found.'), 404); } - if ($this->user->isMember($this->group)) { + if ($this->scoped->isMember($this->group)) { // TRANS: Server error displayed when trying to join a group the user is already a member of. $this->clientError(_('You are already a member of that group.'), 403); } - if (Group_block::isBlocked($this->group, $this->user->getProfile())) { + if (Group_block::isBlocked($this->group, $this->scoped)) { // TRANS: Server error displayed when trying to join a group the user is blocked from joining. $this->clientError(_('You have been blocked from that group by the admin.'), 403); } try { - $this->user->joinGroup($this->group); + $this->scoped->joinGroup($this->group); } catch (Exception $e) { // TRANS: Server error displayed when joining a group failed in the database. // TRANS: %1$s is the joining user's nickname, $2$s is the group nickname for which the join failed. $this->serverError(sprintf(_('Could not join user %1$s to group %2$s.'), - $cur->nickname, $this->group->nickname)); + $this->scoped->nickname, $this->group->nickname)); } switch($this->format) { diff --git a/actions/apitimelinementions.php b/actions/apitimelinementions.php index ce6c73c0d1..c1811ac01b 100644 --- a/actions/apitimelinementions.php +++ b/actions/apitimelinementions.php @@ -119,8 +119,8 @@ class ApiTimelineMentionsAction extends ApiBareAuthAction // TRANS: Subtitle for timeline of most recent mentions of a user. // TRANS: %1$s is the StatusNet sitename, %2$s is a user nickname, // TRANS: %3$s is a user's full name. - _('%1$s updates that reply to updates from %2$s / %3$s.'), - $sitename, $this->target->getBestName(), $this->target->nickname + _('%1$s updates that reply to updates from %3$s / %2$s.'), + $sitename, $this->target->nickname, $this->target->getBestName() ); switch($this->format) { diff --git a/actions/blockedfromgroup.php b/actions/blockedfromgroup.php index 685d6dd068..a00c12ef58 100644 --- a/actions/blockedfromgroup.php +++ b/actions/blockedfromgroup.php @@ -49,7 +49,7 @@ class BlockedfromgroupAction extends GroupAction return true; } - function prepare($args) + protected function prepare(array $args=array()) { parent::prepare($args); $this->page = ($this->arg('page')) ? ($this->arg('page')+0) : 1; @@ -109,9 +109,9 @@ class BlockedfromgroupAction extends GroupAction } } - function handle($args) + protected function handle() { - parent::handle($args); + parent::handle(); $this->showPage(); } diff --git a/actions/editgroup.php b/actions/editgroup.php index 1f77880684..befbd55992 100644 --- a/actions/editgroup.php +++ b/actions/editgroup.php @@ -59,7 +59,7 @@ class EditgroupAction extends GroupAction * Prepare to run */ - function prepare($args) + protected function prepare(array $args=array()) { parent::prepare($args); @@ -119,13 +119,11 @@ class EditgroupAction extends GroupAction * * On GET, show the form. On POST, try to save the group. * - * @param array $args unused - * * @return void */ - function handle($args) + protected function handle() { - parent::handle($args); + parent::handle(); if ($_SERVER['REQUEST_METHOD'] == 'POST') { $this->trySave(); } else { @@ -177,7 +175,7 @@ class EditgroupAction extends GroupAction $nickname = Nickname::normalize($nickname, true); } catch (NicknameTakenException $e) { // Abort only if the nickname is occupied by _another_ group - if ($e->profile->id != $this->group->id) { + if ($e->profile->id != $this->group->profile_id) { $this->showForm($e->getMessage()); return; } diff --git a/actions/groupblock.php b/actions/groupblock.php index 2dbb897514..1c6ccb9e59 100644 --- a/actions/groupblock.php +++ b/actions/groupblock.php @@ -58,54 +58,45 @@ class GroupblockAction extends RedirectingAction 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.')); - return false; } $token = $this->trimmed('token'); if (empty($token) || $token != common_session_token()) { // TRANS: Client error displayed when the session token does not match or is not given. $this->clientError(_('There was a problem with your session token. Try again, please.')); - return; } $id = $this->trimmed('blockto'); if (empty($id)) { // TRANS: Client error displayed trying to block a user from a group while not specifying a to be blocked user profile. $this->clientError(_('No profile specified.')); - return false; } $this->profile = Profile::getKV('id', $id); if (empty($this->profile)) { // TRANS: Client error displayed trying to block a user from a group while specifying a non-existing profile. $this->clientError(_('No profile with that ID.')); - return false; } $group_id = $this->trimmed('blockgroup'); if (empty($group_id)) { // TRANS: Client error displayed trying to block a user from a group while not specifying a group to block a profile from. $this->clientError(_('No group specified.')); - return false; } $this->group = User_group::getKV('id', $group_id); if (empty($this->group)) { // TRANS: Client error displayed trying to block a user from a group while specifying a non-existing group. $this->clientError(_('No such group.')); - return false; } $user = common_current_user(); if (!$user->isAdmin($this->group)) { // TRANS: Client error displayed trying to block a user from a group while not being an admin user. $this->clientError(_('Only an admin can block group members.'), 401); - return false; } if (Group_block::isBlocked($this->group, $this->profile)) { // TRANS: Client error displayed trying to block a user from a group while user is already blocked from the given group. $this->clientError(_('User is already blocked from group.')); - return false; } // XXX: could have proactive blocks, but we don't have UI for it. if (!$this->profile->isMember($this->group)) { // TRANS: Client error displayed trying to block a user from a group while user is not a member of given group. $this->clientError(_('User is not a member of group.')); - return false; } return true; } diff --git a/actions/grouplogo.php b/actions/grouplogo.php index 1e62514312..adffe63c38 100644 --- a/actions/grouplogo.php +++ b/actions/grouplogo.php @@ -60,7 +60,7 @@ class GrouplogoAction extends GroupAction /** * Prepare to run */ - function prepare($args) + protected function prepare(array $args=array()) { parent::prepare($args); @@ -115,9 +115,9 @@ class GrouplogoAction extends GroupAction return true; } - function handle($args) + protected function handle() { - parent::handle($args); + parent::handle(); if ($_SERVER['REQUEST_METHOD'] == 'POST') { $this->handlePost(); } else { diff --git a/actions/groupmembers.php b/actions/groupmembers.php index 52979101fd..44c4dd6f99 100644 --- a/actions/groupmembers.php +++ b/actions/groupmembers.php @@ -52,7 +52,7 @@ class GroupmembersAction extends GroupAction return true; } - function prepare($args) + protected function prepare(array $args=array()) { parent::prepare($args); @@ -77,9 +77,9 @@ class GroupmembersAction extends GroupAction } } - function handle($args) + protected function handle() { - parent::handle($args); + parent::handle(); $this->showPage(); } diff --git a/actions/groupqueue.php b/actions/groupqueue.php index 1d5a3cd134..7227b11090 100644 --- a/actions/groupqueue.php +++ b/actions/groupqueue.php @@ -53,7 +53,7 @@ class GroupqueueAction extends GroupAction } // @todo FIXME: most of this belongs in a base class, sounds common to most group actions? - function prepare($args) + protected function prepare(array $args=array()) { parent::prepare($args); $this->page = ($this->arg('page')) ? ($this->arg('page')+0) : 1; @@ -119,9 +119,9 @@ class GroupqueueAction extends GroupAction } } - function handle($args) + protected function handle() { - parent::handle($args); + parent::handle(); $this->showPage(); } diff --git a/actions/showgroup.php b/actions/showgroup.php index 10601e58b4..e2b5e8d547 100644 --- a/actions/showgroup.php +++ b/actions/showgroup.php @@ -91,7 +91,7 @@ class ShowgroupAction extends GroupAction * * @return boolean success flag */ - function prepare($args) + protected function prepare(array $args=array()) { parent::prepare($args); @@ -123,8 +123,9 @@ class ShowgroupAction extends GroupAction * * @return void */ - function handle($args) + protected function handle() { + parent::handle(); $this->showPage(); } diff --git a/actions/shownotice.php b/actions/shownotice.php index 6a026d2d36..1f92978062 100644 --- a/actions/shownotice.php +++ b/actions/shownotice.php @@ -70,7 +70,7 @@ class ShownoticeAction extends Action * * @return success flag */ - function prepare($args) + protected function prepare(array $args=array()) { parent::prepare($args); if ($this->boolean('ajax')) { @@ -117,16 +117,16 @@ class ShownoticeAction extends Action * * @return Notice */ - function getNotice() + protected function getNotice() { $id = $this->arg('notice'); $notice = Notice::getKV('id', $id); - if (empty($notice)) { + if (!$notice instanceof Notice) { // Did we used to have it, and it got deleted? $deleted = Deleted_notice::getKV($id); - if (!empty($deleted)) { + if ($deleted instanceof Deleted_notice) { // TRANS: Client error displayed trying to show a deleted notice. $this->clientError(_('Notice deleted.'), 410); } else { @@ -211,9 +211,9 @@ class ShownoticeAction extends Action * * @return void */ - function handle($args) + protected function handle() { - parent::handle($args); + parent::handle(); if ($this->boolean('ajax')) { $this->showAjax(); diff --git a/actions/snapshotadminpanel.php b/actions/snapshotadminpanel.php deleted file mode 100644 index 214b3d648b..0000000000 --- a/actions/snapshotadminpanel.php +++ /dev/null @@ -1,255 +0,0 @@ -. - * - * @category Settings - * @package StatusNet - * @author Zach Copley - * @copyright 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('STATUSNET')) { - exit(1); -} - -/** - * Manage snapshots - * - * @category Admin - * @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 SnapshotadminpanelAction extends AdminPanelAction -{ - /** - * Returns the page title - * - * @return string page title - */ - function title() - { - // TRANS: Title for admin panel to configure snapshots. - return _m('TITLE','Snapshots'); - } - - /** - * Instructions for using this form. - * - * @return string instructions - */ - function getInstructions() - { - // TRANS: Instructions for admin panel to configure snapshots. - return _('Manage snapshot configuration'); - } - - /** - * Show the snapshots admin panel form - * - * @return void - */ - function showForm() - { - $form = new SnapshotAdminPanelForm($this); - $form->show(); - return; - } - - /** - * Save settings from the form - * - * @return void - */ - function saveSettings() - { - static $settings = array( - 'snapshot' => array('run', 'reporturl', 'frequency') - ); - - $values = array(); - - foreach ($settings as $section => $parts) { - foreach ($parts as $setting) { - $values[$section][$setting] = $this->trimmed($setting); - } - } - - // This throws an exception on validation errors - - $this->validate($values); - - // assert(all values are valid); - - $config = new Config(); - - $config->query('BEGIN'); - - foreach ($settings as $section => $parts) { - foreach ($parts as $setting) { - Config::save($section, $setting, $values[$section][$setting]); - } - } - - $config->query('COMMIT'); - - return; - } - - function validate(&$values) - { - // Validate snapshot run value - - if (!in_array($values['snapshot']['run'], array('web', 'cron', 'never'))) { - // TRANS: Client error displayed on admin panel for snapshots when providing an invalid run value. - $this->clientError(_('Invalid snapshot run value.')); - } - - // Validate snapshot frequency value - - if (!Validate::number($values['snapshot']['frequency'])) { - // TRANS: Client error displayed on admin panel for snapshots when providing an invalid value for frequency. - $this->clientError(_('Snapshot frequency must be a number.')); - } - - // Validate report URL - - if (!is_null($values['snapshot']['reporturl']) - && !common_valid_http_url($values['snapshot']['reporturl'])) { - // TRANS: Client error displayed on admin panel for snapshots when providing an invalid report URL. - $this->clientError(_('Invalid snapshot report URL.')); - } - } -} - -// @todo FIXME: add documentation -class SnapshotAdminPanelForm extends AdminForm -{ - /** - * ID of the form - * - * @return int ID of the form - */ - function id() - { - return 'form_snapshot_admin_panel'; - } - - /** - * class of the form - * - * @return string class of the form - */ - function formClass() - { - return 'form_settings'; - } - - /** - * Action of the form - * - * @return string URL of the action - */ - function action() - { - return common_local_url('snapshotadminpanel'); - } - - /** - * Data elements of the form - * - * @return void - */ - function formData() - { - $this->out->elementStart( - 'fieldset', - array('id' => 'settings_admin_snapshots') - ); - // TRANS: Fieldset legend on admin panel for snapshots. - $this->out->element('legend', null, _m('LEGEND','Snapshots')); - $this->out->elementStart('ul', 'form_data'); - $this->li(); - $snapshot = array( - // TRANS: Option in dropdown for snapshot method in admin panel for snapshots. - 'web' => _('Randomly during web hit'), - // TRANS: Option in dropdown for snapshot method in admin panel for snapshots. - 'cron' => _('In a scheduled job'), - // TRANS: Option in dropdown for snapshot method in admin panel for snapshots. - 'never' => _('Never') - ); - $this->out->dropdown( - 'run', - // TRANS: Dropdown label for snapshot method in admin panel for snapshots. - _('Data snapshots'), - $snapshot, - // TRANS: Dropdown title for snapshot method in admin panel for snapshots. - _('When to send statistical data to status.net servers.'), - false, - $this->value('run', 'snapshot') - ); - $this->unli(); - - $this->li(); - $this->input( - 'frequency', - // TRANS: Input field label for snapshot frequency in admin panel for snapshots. - _('Frequency'), - // TRANS: Input field title for snapshot frequency in admin panel for snapshots. - _('Snapshots will be sent once every N web hits.'), - 'snapshot' - ); - $this->unli(); - - $this->li(); - $this->input( - 'reporturl', - // TRANS: Input field label for snapshot report URL in admin panel for snapshots. - _('Report URL'), - // TRANS: Input field title for snapshot report URL in admin panel for snapshots. - _('Snapshots will be sent to this URL.'), - 'snapshot' - ); - $this->unli(); - $this->out->elementEnd('ul'); - $this->out->elementEnd('fieldset'); - } - - /** - * Action elements - * - * @return void - */ - function formActions() - { - $this->out->submit( - 'submit', - // TRANS: Button text to save snapshot settings. - _m('BUTTON','Save'), - 'submit', - null, - // TRANS: Button title to save snapshot settings. - _('Save snapshot settings.') - ); - } -} diff --git a/classes/Conversation.php b/classes/Conversation.php index 23f8dada0b..c76b0169ff 100755 --- a/classes/Conversation.php +++ b/classes/Conversation.php @@ -22,32 +22,28 @@ * @category Data * @package StatusNet * @author Zach Copley + * @author Mikael Nordfeldth * @copyright 2010 StatusNet Inc. + * @copyright 2009-2014 Free Software Foundation, Inc http://www.fsf.org * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @link http://status.net/ */ -require_once INSTALLDIR . '/classes/Memcached_DataObject.php'; +if (!defined('GNUSOCIAL')) { exit(1); } class Conversation extends Managed_DataObject { - ###START_AUTOCODE - /* the code below is auto generated do not remove the above tag */ - - public $__table = 'conversation'; // table name + public $__table = 'conversation'; // table name public $id; // int(4) primary_key not_null public $uri; // varchar(255) unique_key public $created; // datetime 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( 'fields' => array( - 'id' => array('type' => 'serial', 'not null' => true, 'description' => 'unique identifier'), + 'id' => array('type' => 'int', 'not null' => true, 'description' => 'should be set from root notice id (since 2014-03-01 commit)'), 'uri' => array('type' => 'varchar', 'length' => 255, 'description' => 'URI of the conversation'), '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'), @@ -64,25 +60,20 @@ class Conversation extends Managed_DataObject * * @return Conversation the new conversation DO */ - static function create() + static function create(Notice $notice) { + if (empty($notice->id)) { + throw new ServerException(_('Tried to create conversation for not yet inserted notice')); + } $conv = new Conversation(); $conv->created = common_sql_now(); - $id = $conv->insert(); + $conv->id = $notice->id; + $conv->uri = common_local_url('conversation', array('id' => $notice->id), null, null, false); + $result = $conv->insert(); - if (empty($id)) { + if ($result === false) { common_log_db_error($conv, 'INSERT', __FILE__); - return null; - } - - $orig = clone($conv); - $orig->uri = common_local_url('conversation', array('id' => $id), - null, null, false); - $result = $orig->update($conv); - - if (empty($result)) { - common_log_db_error($conv, 'UPDATE', __FILE__); - return null; + throw new ServerException(_('Failed to create conversation for notice')); } return $conv; diff --git a/classes/File.php b/classes/File.php index a5914b506e..db80159d3b 100644 --- a/classes/File.php +++ b/classes/File.php @@ -116,7 +116,9 @@ class File extends Managed_DataObject } catch (Exception $e) { return false; } - + if ($oembed_data === false) { + return false; + } $fo = File_oembed::getKV('file_id', $this->id); if ($fo instanceof File_oembed) { diff --git a/classes/Notice.php b/classes/Notice.php index f40a4c2111..c25f702989 100644 --- a/classes/Notice.php +++ b/classes/Notice.php @@ -142,20 +142,20 @@ class Notice extends Managed_DataObject const FOLLOWER_SCOPE = 8; protected $_profile = -1; - + public function getProfile() { if ($this->_profile === -1) { $this->_setProfile(Profile::getKV('id', $this->profile_id)); } - if (!$this->_profile instanceof Profile) { - throw new NoProfileException($this->profile_id); - } return $this->_profile; } - function _setProfile(Profile $profile) + public function _setProfile(Profile $profile=null) { + if (!$profile instanceof Profile) { + throw new NoProfileException($this->profile_id); + } $this->_profile = $profile; } @@ -216,6 +216,16 @@ class Notice extends Managed_DataObject return $this->url ?: $this->uri; } + public static function getByUri($uri) + { + $notice = new Notice(); + $notice->uri = $uri; + if (!$notice->find(true)) { + throw new NoResultException($notice); + } + return $notice; + } + /** * Extract #hashtags from this notice's content and save them to the database. */ @@ -577,13 +587,13 @@ class Notice extends Managed_DataObject // the beginning of a new conversation. if (empty($notice->conversation)) { - $conv = Conversation::create(); + $conv = Conversation::create($notice); $notice->conversation = $conv->id; $changed = true; } if ($changed) { - if (!$notice->update($orig)) { + if ($notice->update($orig) === false) { common_log_db_error($notice, 'UPDATE', __FILE__); // TRANS: Server exception thrown when a notice cannot be updated. throw new ServerException(_('Problem saving notice.')); @@ -2500,10 +2510,15 @@ class Notice extends Managed_DataObject { $map = self::getProfiles($notices); - foreach ($notices as $notice) { - if (array_key_exists($notice->profile_id, $map)) { - $notice->_setProfile($map[$notice->profile_id]); - } + foreach ($notices as $entry=>$notice) { + try { + if (array_key_exists($notice->profile_id, $map)) { + $notice->_setProfile($map[$notice->profile_id]); + } + } catch (NoProfileException $e) { + common_log(LOG_WARNING, "Failed to fill profile in Notice with non-existing entry for profile_id: {$e->id}"); + unset($notices[$entry]); + } } return array_values($map); diff --git a/classes/Profile.php b/classes/Profile.php index 76b2ac28d0..fe2ce343d7 100644 --- a/classes/Profile.php +++ b/classes/Profile.php @@ -256,7 +256,7 @@ class Profile extends Managed_DataObject return $stream->getNotices($offset, $limit, $since_id, $max_id); } - function isMember($group) + function isMember(User_group $group) { $groups = $this->getGroups(0, null); while ($groups instanceof User_group && $groups->fetch()) { @@ -267,7 +267,7 @@ class Profile extends Managed_DataObject return false; } - function isAdmin($group) + function isAdmin(User_group $group) { $gm = Group_member::pkeyGet(array('profile_id' => $this->id, 'group_id' => $group->id)); @@ -745,7 +745,7 @@ class Profile extends Managed_DataObject * @param Profile $other * @return boolean */ - function isSubscribed($other) + function isSubscribed(Profile $other) { return Subscription::exists($this, $other); } diff --git a/classes/User.php b/classes/User.php index 24a03b62fd..2b390bb90b 100644 --- a/classes/User.php +++ b/classes/User.php @@ -134,7 +134,7 @@ class User extends Managed_DataObject return $this->_profile; } - function isSubscribed($other) + function isSubscribed(Profile $other) { return $this->getProfile()->isSubscribed($other); } @@ -616,12 +616,12 @@ class User extends Managed_DataObject return true; } - function isMember($group) + function isMember(User_group $group) { return $this->getProfile()->isMember($group); } - function isAdmin($group) + function isAdmin(User_group $group) { return $this->getProfile()->isAdmin($group); } diff --git a/index.php b/index.php index 2b27845e59..82be959455 100644 --- a/index.php +++ b/index.php @@ -242,8 +242,6 @@ function main() } global $user, $action; - Snapshot::check(); - if (!_have_config()) { $msg = sprintf( // TRANS: Error message displayed when there is no StatusNet configuration file. diff --git a/install.php b/install.php index 088116d5c2..352d5a143c 100644 --- a/install.php +++ b/install.php @@ -118,7 +118,7 @@ class WebInstaller extends Installer function main() { if (!$this->checkPrereqs()) { - $this->showForm(); + $this->warning(_('Please fix the above stated problems and refresh this page to continue installing.')); return; } @@ -239,12 +239,12 @@ class WebInstaller extends Installer
  • -

    Nickname for the initial StatusNet user (administrator)

    +

    Nickname for the initial user (administrator)

  • -

    Password for the initial StatusNet user (administrator)

    +

    Password for the initial user (administrator)

  • @@ -253,7 +253,7 @@ class WebInstaller extends Installer
  • -

    Optional email address for the initial StatusNet user (administrator)

    +

    Optional email address for the initial user (administrator)

  • @@ -375,14 +375,15 @@ PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> - Install StatusNet - + Install GNU social + + - + @@ -390,8 +391,8 @@ PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"