forked from GNUsocial/gnu-social
		
	Merge branch 'nightly' of git.gnu.io:gnu/gnu-social into nightly
This commit is contained in:
		
							
								
								
									
										2
									
								
								INSTALL
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								INSTALL
									
									
									
									
									
								
							@@ -26,7 +26,7 @@ PHP modules
 | 
				
			|||||||
The following software packages are *required* for this software to
 | 
					The following software packages are *required* for this software to
 | 
				
			||||||
run correctly.
 | 
					run correctly.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- PHP 5.4+      For newer versions, some functions that are used may be
 | 
					- PHP 5.5+      For newer versions, some functions that are used may be
 | 
				
			||||||
                disabled by default, such as the pcntl_* family. See the
 | 
					                disabled by default, such as the pcntl_* family. See the
 | 
				
			||||||
                section on 'Queues and daemons' for more information.
 | 
					                section on 'Queues and daemons' for more information.
 | 
				
			||||||
- MariaDB 5+    GNU Social uses, by default, a MariaDB server for data
 | 
					- MariaDB 5+    GNU Social uses, by default, a MariaDB server for data
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -128,7 +128,7 @@ class ConversationAction extends ManagedAction
 | 
				
			|||||||
                                                    'format' => 'atom')),
 | 
					                                                    'format' => 'atom')),
 | 
				
			||||||
                              // TRANS: Title for link to notice feed.
 | 
					                              // TRANS: Title for link to notice feed.
 | 
				
			||||||
                              // TRANS: %s is a user nickname.
 | 
					                              // TRANS: %s is a user nickname.
 | 
				
			||||||
                              _('Conversation feed (Activity Streams JSON)')));
 | 
					                              _('Conversation feed (Atom)')));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -410,6 +410,7 @@ class EmailsettingsAction extends SettingsAction
 | 
				
			|||||||
                $this->serverError(_('Could not insert confirmation code.'));
 | 
					                $this->serverError(_('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);
 | 
					            mail_confirm_address($user, $confirm->code, $user->nickname, $email);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            Event::handle('EndAddEmailAddress', array($user, $email));
 | 
					            Event::handle('EndAddEmailAddress', array($user, $email));
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,7 +2,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
if (!defined('GNUSOCIAL')) { exit(1); }
 | 
					if (!defined('GNUSOCIAL')) { exit(1); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class NetworkpublicAction extends PublicAction
 | 
					class NetworkpublicAction extends SitestreamAction
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    protected function streamPrepare()
 | 
					    protected function streamPrepare()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
@@ -28,13 +28,6 @@ class NetworkpublicAction extends PublicAction
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    function extraHead()
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        // the PublicAction has some XRDS stuff that might be unique to the non-network public feed
 | 
					 | 
				
			||||||
        // FIXME: Solve this with a call that doesn't rely on parent:: and is unique for each class.
 | 
					 | 
				
			||||||
        ManagedAction::extraHead();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    function showSections()
 | 
					    function showSections()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        // Show invite button, as long as site isn't closed, and
 | 
					        // Show invite button, as long as site isn't closed, and
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -29,10 +29,6 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
if (!defined('GNUSOCIAL')) { exit(1); }
 | 
					if (!defined('GNUSOCIAL')) { exit(1); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Farther than any human will go
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
define('MAX_PUBLIC_PAGE', 100);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Action for displaying the public stream
 | 
					 * Action for displaying the public stream
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
@@ -43,54 +39,9 @@ define('MAX_PUBLIC_PAGE', 100);
 | 
				
			|||||||
 * @link     http://status.net/
 | 
					 * @link     http://status.net/
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * @see      PublicrssAction
 | 
					 * @see      PublicrssAction
 | 
				
			||||||
 * @see      PublicxrdsAction
 | 
					 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
class PublicAction extends ManagedAction
 | 
					class PublicAction extends SitestreamAction
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * page of the stream we're on; default = 1
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    var $page = null;
 | 
					 | 
				
			||||||
    var $notice;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    protected $stream = null;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    function isReadOnly($args)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        return true;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    protected function doPreparation()
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        $this->page = ($this->arg('page')) ? ($this->arg('page')+0) : 1;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if ($this->page > MAX_PUBLIC_PAGE) {
 | 
					 | 
				
			||||||
            // TRANS: Client error displayed when requesting a public timeline page beyond the page limit.
 | 
					 | 
				
			||||||
            // TRANS: %s is the page limit.
 | 
					 | 
				
			||||||
            $this->clientError(sprintf(_('Beyond the page limit (%s).'), MAX_PUBLIC_PAGE));
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        common_set_returnto($this->selfUrl());
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        $this->streamPrepare();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        $this->notice = $this->stream->getNotices(($this->page-1)*NOTICES_PER_PAGE,
 | 
					 | 
				
			||||||
                                            NOTICES_PER_PAGE + 1);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (!$this->notice) {
 | 
					 | 
				
			||||||
            // TRANS: Server error displayed when a public timeline cannot be retrieved.
 | 
					 | 
				
			||||||
            $this->serverError(_('Could not retrieve public timeline.'));
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if ($this->page > 1 && $this->notice->N == 0){
 | 
					 | 
				
			||||||
            // TRANS: Client error when page not found (404).
 | 
					 | 
				
			||||||
            $this->clientError(_('No such page.'), 404);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        return true;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    protected function streamPrepare()
 | 
					    protected function streamPrepare()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        if ($this->scoped instanceof Profile && $this->scoped->isLocal() && $this->scoped->getUser()->streamModeOnly()) {
 | 
					        if ($this->scoped instanceof Profile && $this->scoped->isLocal() && $this->scoped->getUser()->streamModeOnly()) {
 | 
				
			||||||
@@ -117,100 +68,6 @@ class PublicAction extends ManagedAction
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    function extraHead()
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        parent::extraHead();
 | 
					 | 
				
			||||||
        $this->element('meta', array('http-equiv' => 'X-XRDS-Location',
 | 
					 | 
				
			||||||
                                           'content' => common_local_url('publicxrds')));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        $rsd = common_local_url('rsd');
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // RSD, http://tales.phrasewise.com/rfc/rsd
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        $this->element('link', array('rel' => 'EditURI',
 | 
					 | 
				
			||||||
                                     'type' => 'application/rsd+xml',
 | 
					 | 
				
			||||||
                                     'href' => $rsd));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if ($this->page != 1) {
 | 
					 | 
				
			||||||
            $this->element('link', array('rel' => 'canonical',
 | 
					 | 
				
			||||||
                                         'href' => common_local_url('public')));
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * Output <head> elements for RSS and Atom feeds
 | 
					 | 
				
			||||||
     *
 | 
					 | 
				
			||||||
     * @return void
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    function getFeeds()
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        return array(new Feed(Feed::JSON,
 | 
					 | 
				
			||||||
                              common_local_url('ApiTimelinePublic',
 | 
					 | 
				
			||||||
                                               array('format' => 'as')),
 | 
					 | 
				
			||||||
                              // TRANS: Link description for public timeline feed.
 | 
					 | 
				
			||||||
                              _('Public Timeline Feed (Activity Streams JSON)')),
 | 
					 | 
				
			||||||
                    new Feed(Feed::RSS1, common_local_url('publicrss'),
 | 
					 | 
				
			||||||
                              // TRANS: Link description for public timeline feed.
 | 
					 | 
				
			||||||
                              _('Public Timeline Feed (RSS 1.0)')),
 | 
					 | 
				
			||||||
                     new Feed(Feed::RSS2,
 | 
					 | 
				
			||||||
                              common_local_url('ApiTimelinePublic',
 | 
					 | 
				
			||||||
                                               array('format' => 'rss')),
 | 
					 | 
				
			||||||
                              // TRANS: Link description for public timeline feed.
 | 
					 | 
				
			||||||
                              _('Public Timeline Feed (RSS 2.0)')),
 | 
					 | 
				
			||||||
                     new Feed(Feed::ATOM,
 | 
					 | 
				
			||||||
                              common_local_url('ApiTimelinePublic',
 | 
					 | 
				
			||||||
                                               array('format' => 'atom')),
 | 
					 | 
				
			||||||
                              // TRANS: Link description for public timeline feed.
 | 
					 | 
				
			||||||
                              _('Public Timeline Feed (Atom)')));
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    function showEmptyList()
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        // TRANS: Text displayed for public feed when there are no public notices.
 | 
					 | 
				
			||||||
        $message = _('This is the public timeline for %%site.name%% but no one has posted anything yet.') . ' ';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (common_logged_in()) {
 | 
					 | 
				
			||||||
            // TRANS: Additional text displayed for public feed when there are no public notices for a logged in user.
 | 
					 | 
				
			||||||
            $message .= _('Be the first to post!');
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        else {
 | 
					 | 
				
			||||||
            if (! (common_config('site','closed') || common_config('site','inviteonly'))) {
 | 
					 | 
				
			||||||
                // TRANS: Additional text displayed for public feed when there are no public notices for a not logged in user.
 | 
					 | 
				
			||||||
                $message .= _('Why not [register an account](%%action.register%%) and be the first to post!');
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        $this->elementStart('div', 'guide');
 | 
					 | 
				
			||||||
        $this->raw(common_markup_to_html($message));
 | 
					 | 
				
			||||||
        $this->elementEnd('div');
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * Fill the content area
 | 
					 | 
				
			||||||
     *
 | 
					 | 
				
			||||||
     * Shows a list of the notices in the public stream, with some pagination
 | 
					 | 
				
			||||||
     * controls.
 | 
					 | 
				
			||||||
     *
 | 
					 | 
				
			||||||
     * @return void
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    function showContent()
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        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, $this->scoped);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        $cnt = $nl->show();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if ($cnt == 0) {
 | 
					 | 
				
			||||||
            $this->showEmptyList();
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        $this->pagination($this->page > 1, $cnt > NOTICES_PER_PAGE,
 | 
					 | 
				
			||||||
                          $this->page, $this->action);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    function showSections()
 | 
					    function showSections()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        // Show invite button, as long as site isn't closed, and
 | 
					        // Show invite button, as long as site isn't closed, and
 | 
				
			||||||
@@ -239,23 +96,30 @@ class PublicAction extends ManagedAction
 | 
				
			|||||||
        $feat->show();
 | 
					        $feat->show();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    function showAnonymousMessage()
 | 
					    /**
 | 
				
			||||||
 | 
					     * Output <head> elements for RSS and Atom feeds
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return void
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    function getFeeds()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        if (! (common_config('site','closed') || common_config('site','inviteonly'))) {
 | 
					        return array(new Feed(Feed::JSON,
 | 
				
			||||||
            // TRANS: Message for not logged in users at an invite-only site trying to view the public feed of notices.
 | 
					                              common_local_url('ApiTimelinePublic',
 | 
				
			||||||
            // TRANS: This message contains Markdown links. Please mind the formatting.
 | 
					                                               array('format' => 'as')),
 | 
				
			||||||
            $m = _('This is %%site.name%%, a [micro-blogging](http://en.wikipedia.org/wiki/Micro-blogging) service ' .
 | 
					                              // TRANS: Link description for public timeline feed.
 | 
				
			||||||
                   'based on the Free Software [StatusNet](http://status.net/) tool. ' .
 | 
					                              _('Public Timeline Feed (Activity Streams JSON)')),
 | 
				
			||||||
                   '[Join now](%%action.register%%) to share notices about yourself with friends, family, and colleagues! ' .
 | 
					                    new Feed(Feed::RSS1, common_local_url('publicrss'),
 | 
				
			||||||
                   '([Read more](%%doc.help%%))');
 | 
					                              // TRANS: Link description for public timeline feed.
 | 
				
			||||||
        } else {
 | 
					                              _('Public Timeline Feed (RSS 1.0)')),
 | 
				
			||||||
            // TRANS: Message for not logged in users at a closed site trying to view the public feed of notices.
 | 
					                     new Feed(Feed::RSS2,
 | 
				
			||||||
            // TRANS: This message contains Markdown links. Please mind the formatting.
 | 
					                              common_local_url('ApiTimelinePublic',
 | 
				
			||||||
            $m = _('This is %%site.name%%, a [micro-blogging](http://en.wikipedia.org/wiki/Micro-blogging) service ' .
 | 
					                                               array('format' => 'rss')),
 | 
				
			||||||
                   'based on the Free Software [StatusNet](http://status.net/) tool.');
 | 
					                              // TRANS: Link description for public timeline feed.
 | 
				
			||||||
        }
 | 
					                              _('Public Timeline Feed (RSS 2.0)')),
 | 
				
			||||||
        $this->elementStart('div', array('id' => 'anon_notice'));
 | 
					                     new Feed(Feed::ATOM,
 | 
				
			||||||
        $this->raw(common_markup_to_html($m));
 | 
					                              common_local_url('ApiTimelinePublic',
 | 
				
			||||||
        $this->elementEnd('div');
 | 
					                                               array('format' => 'atom')),
 | 
				
			||||||
 | 
					                              // TRANS: Link description for public timeline feed.
 | 
				
			||||||
 | 
					                              _('Public Timeline Feed (Atom)')));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -272,10 +272,16 @@ class RecoverpasswordAction extends Action
 | 
				
			|||||||
        try {
 | 
					        try {
 | 
				
			||||||
            User::recoverPassword($nore);
 | 
					            User::recoverPassword($nore);
 | 
				
			||||||
            $this->mode = 'sent';
 | 
					            $this->mode = 'sent';
 | 
				
			||||||
 | 
					            if (common_is_email($nore) && common_config('site', 'fakeaddressrecovery')) {
 | 
				
			||||||
 | 
					                // TRANS: User notification when recovering password by giving email address,
 | 
				
			||||||
 | 
					                //        regardless if the mail was sent or not (to hide registered email status).
 | 
				
			||||||
 | 
					                $this->msg = _('If the email address you provided was found in the database, a recovery mail with instructions has been sent there.');
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
                // TRANS: User notification after an e-mail with instructions was sent from the password recovery form.
 | 
					                // TRANS: User notification after an e-mail with instructions was sent from the password recovery form.
 | 
				
			||||||
                $this->msg = _('Instructions for recovering your password ' .
 | 
					                $this->msg = _('Instructions for recovering your password ' .
 | 
				
			||||||
                               'have been sent to the email address registered to your ' .
 | 
					                               'have been sent to the email address registered to your ' .
 | 
				
			||||||
                               'account.');
 | 
					                               'account.');
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
            $this->success = true;
 | 
					            $this->success = true;
 | 
				
			||||||
        } catch (Exception $e) {
 | 
					        } catch (Exception $e) {
 | 
				
			||||||
            $this->success = false;
 | 
					            $this->success = false;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -116,14 +116,14 @@ class File extends Managed_DataObject
 | 
				
			|||||||
     *
 | 
					     *
 | 
				
			||||||
     * @fixme refactor this mess, it's gotten pretty scary.
 | 
					     * @fixme refactor this mess, it's gotten pretty scary.
 | 
				
			||||||
     * @param string $given_url the URL we're looking at
 | 
					     * @param string $given_url the URL we're looking at
 | 
				
			||||||
     * @param int $notice_id (optional)
 | 
					     * @param Notice $notice (optional)
 | 
				
			||||||
     * @param bool $followRedirects defaults to true
 | 
					     * @param bool $followRedirects defaults to true
 | 
				
			||||||
     *
 | 
					     *
 | 
				
			||||||
     * @return mixed File on success, -1 on some errors
 | 
					     * @return mixed File on success, -1 on some errors
 | 
				
			||||||
     *
 | 
					     *
 | 
				
			||||||
     * @throws ServerException on failure
 | 
					     * @throws ServerException on failure
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public static function processNew($given_url, $notice_id=null, $followRedirects=true) {
 | 
					    public static function processNew($given_url, Notice $notice=null, $followRedirects=true) {
 | 
				
			||||||
        if (empty($given_url)) {
 | 
					        if (empty($given_url)) {
 | 
				
			||||||
            throw new ServerException('No given URL to process');
 | 
					            throw new ServerException('No given URL to process');
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@@ -181,7 +181,7 @@ class File extends Managed_DataObject
 | 
				
			|||||||
                //
 | 
					                //
 | 
				
			||||||
                // Seen in the wild with clojure.org, which redirects through
 | 
					                // Seen in the wild with clojure.org, which redirects through
 | 
				
			||||||
                // wikispaces for auth and appends session data in the URL params.
 | 
					                // wikispaces for auth and appends session data in the URL params.
 | 
				
			||||||
                $file = self::processNew($redir_url, $notice_id, /*followRedirects*/false);
 | 
					                $file = self::processNew($redir_url, $notice, /*followRedirects*/false);
 | 
				
			||||||
                File_redirection::saveNew($redir_data, $file->id, $given_url);
 | 
					                File_redirection::saveNew($redir_data, $file->id, $given_url);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -193,8 +193,8 @@ class File extends Managed_DataObject
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (!empty($notice_id)) {
 | 
					        if ($notice instanceof Notice) {
 | 
				
			||||||
            File_to_post::processNew($file->id, $notice_id);
 | 
					            File_to_post::processNew($file, $notice);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        return $file;
 | 
					        return $file;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -249,6 +249,15 @@ class File extends Managed_DataObject
 | 
				
			|||||||
        return true;
 | 
					        return true;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function getFilename()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (!self::validFilename($this->filename)) {
 | 
				
			||||||
 | 
					            // TRANS: Client exception thrown if a file upload does not have a valid name.
 | 
				
			||||||
 | 
					            throw new ClientException(_("Invalid filename."));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return $this->filename;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // where should the file go?
 | 
					    // where should the file go?
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    static function filename(Profile $profile, $origname, $mimetype)
 | 
					    static function filename(Profile $profile, $origname, $mimetype)
 | 
				
			||||||
@@ -501,9 +510,9 @@ class File extends Managed_DataObject
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    function blowCache($last=false)
 | 
					    function blowCache($last=false)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        self::blow('file:notice-ids:%s', $this->urlhash);
 | 
					        self::blow('file:notice-ids:%s', $this->id);
 | 
				
			||||||
        if ($last) {
 | 
					        if ($last) {
 | 
				
			||||||
            self::blow('file:notice-ids:%s;last', $this->urlhash);
 | 
					            self::blow('file:notice-ids:%s;last', $this->id);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        self::blow('file:notice-count:%d', $this->id);
 | 
					        self::blow('file:notice-count:%d', $this->id);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -610,12 +619,45 @@ class File extends Managed_DataObject
 | 
				
			|||||||
            return;
 | 
					            return;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        echo "\nFound old $table table, upgrading it to contain 'urlhash' field...";
 | 
					        echo "\nFound old $table table, upgrading it to contain 'urlhash' field...";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $file = new File();
 | 
				
			||||||
 | 
					        $file->query(sprintf('SELECT id, LEFT(url, 191) AS shortenedurl, COUNT(*) AS c FROM %1$s WHERE LENGTH(url)>191 GROUP BY shortenedurl HAVING c > 1', $schema->quoteIdentifier($table)));
 | 
				
			||||||
 | 
					        print "\nFound {$file->N} URLs with too long entries in file table\n";
 | 
				
			||||||
 | 
					        while ($file->fetch()) {
 | 
				
			||||||
 | 
					            // We've got a URL that is too long for our future file table
 | 
				
			||||||
 | 
					            // so we'll cut it. We could save the original URL, but there is
 | 
				
			||||||
 | 
					            // no guarantee it is complete anyway since the previous max was 255 chars.
 | 
				
			||||||
 | 
					            $dupfile = new File();
 | 
				
			||||||
 | 
					            // First we find file entries that would be duplicates of this when shortened
 | 
				
			||||||
 | 
					            // ... and we'll just throw the dupes out the window for now! It's already so borken.
 | 
				
			||||||
 | 
					            $dupfile->query(sprintf('SELECT * FROM file WHERE LEFT(url, 191) = "%1$s"', $file->shortenedurl));
 | 
				
			||||||
 | 
					            // Leave one of the URLs in the database by using ->find(true) (fetches first entry)
 | 
				
			||||||
 | 
					            if ($dupfile->find(true)) {
 | 
				
			||||||
 | 
					                print "\nShortening url entry for $table id: {$file->id} [";
 | 
				
			||||||
 | 
					                $orig = clone($dupfile);
 | 
				
			||||||
 | 
					                $dupfile->url = $file->shortenedurl;    // make sure it's only 191 chars from now on
 | 
				
			||||||
 | 
					                $dupfile->update($orig);
 | 
				
			||||||
 | 
					                print "\nDeleting duplicate entries of too long URL on $table id: {$file->id} [";
 | 
				
			||||||
 | 
					                // only start deleting with this fetch.
 | 
				
			||||||
 | 
					                while($dupfile->fetch()) {
 | 
				
			||||||
 | 
					                    print ".";
 | 
				
			||||||
 | 
					                    $dupfile->delete();
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                print "]\n";
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                print "\nWarning! URL suddenly disappeared from database: {$file->url}\n";
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        echo "...and now all the non-duplicates which are longer than 191 characters...\n";
 | 
				
			||||||
 | 
					        $file->query('UPDATE file SET url=LEFT(url, 191) WHERE LENGTH(url)>191');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        echo "\n...now running hacky pre-schemaupdate change for $table:";
 | 
				
			||||||
        // We have to create a urlhash that is _not_ the primary key,
 | 
					        // We have to create a urlhash that is _not_ the primary key,
 | 
				
			||||||
        // transfer data and THEN run checkSchema
 | 
					        // transfer data and THEN run checkSchema
 | 
				
			||||||
        $schemadef['fields']['urlhash'] = array (
 | 
					        $schemadef['fields']['urlhash'] = array (
 | 
				
			||||||
                                              'type' => 'varchar',
 | 
					                                              'type' => 'varchar',
 | 
				
			||||||
                                              'length' => 64,
 | 
					                                              'length' => 64,
 | 
				
			||||||
                                              'not null' => true,
 | 
					                                              'not null' => false,  // this is because when adding column, all entries will _be_ NULL!
 | 
				
			||||||
                                              'description' => 'sha256 of destination URL (url field)',
 | 
					                                              'description' => 'sha256 of destination URL (url field)',
 | 
				
			||||||
                                            );
 | 
					                                            );
 | 
				
			||||||
        $schemadef['fields']['url'] = array (
 | 
					        $schemadef['fields']['url'] = array (
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -59,12 +59,7 @@ class File_redirection extends Managed_DataObject
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    static public function getByUrl($url)
 | 
					    static public function getByUrl($url)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $file = new File_redirection();
 | 
					        return self::getByPK(array('urlhash' => File::hashurl($url)));
 | 
				
			||||||
        $file->urlhash = File::hashurl($url);
 | 
					 | 
				
			||||||
        if (!$file->find(true)) {
 | 
					 | 
				
			||||||
            throw new NoResultException($file);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        return $file;
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    static function _commonHttp($url, $redirs) {
 | 
					    static function _commonHttp($url, $redirs) {
 | 
				
			||||||
@@ -261,7 +256,7 @@ class File_redirection extends Managed_DataObject
 | 
				
			|||||||
            // store it
 | 
					            // store it
 | 
				
			||||||
            $file = File::getKV('url', $long_url);
 | 
					            $file = File::getKV('url', $long_url);
 | 
				
			||||||
            if ($file instanceof File) {
 | 
					            if ($file instanceof File) {
 | 
				
			||||||
                $file_id = $file->id;
 | 
					                $file_id = $file->getID();
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
                // Check if the target URL is itself a redirect...
 | 
					                // Check if the target URL is itself a redirect...
 | 
				
			||||||
                $redir_data = File_redirection::where($long_url);
 | 
					                $redir_data = File_redirection::where($long_url);
 | 
				
			||||||
@@ -269,7 +264,7 @@ class File_redirection extends Managed_DataObject
 | 
				
			|||||||
                    // We haven't seen the target URL before.
 | 
					                    // We haven't seen the target URL before.
 | 
				
			||||||
                    // Save file and embedding data about it!
 | 
					                    // Save file and embedding data about it!
 | 
				
			||||||
                    $file = File::saveNew($redir_data, $long_url);
 | 
					                    $file = File::saveNew($redir_data, $long_url);
 | 
				
			||||||
                    $file_id = $file->id;
 | 
					                    $file_id = $file->getID();
 | 
				
			||||||
                } else if (is_string($redir_data)) {
 | 
					                } else if (is_string($redir_data)) {
 | 
				
			||||||
                    // The file is a known redirect target.
 | 
					                    // The file is a known redirect target.
 | 
				
			||||||
                    $file = File::getKV('url', $redir_data);
 | 
					                    $file = File::getKV('url', $redir_data);
 | 
				
			||||||
@@ -281,7 +276,7 @@ class File_redirection extends Managed_DataObject
 | 
				
			|||||||
                        // SSL sites with cert issues.
 | 
					                        // SSL sites with cert issues.
 | 
				
			||||||
                        return null;
 | 
					                        return null;
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    $file_id = $file->id;
 | 
					                    $file_id = $file->getID();
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            $file_redir = File_redirection::getKV('url', $short_url);
 | 
					            $file_redir = File_redirection::getKV('url', $short_url);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -82,9 +82,9 @@ class File_thumbnail extends Managed_DataObject
 | 
				
			|||||||
     * Fetch an entry by using a File's id
 | 
					     * Fetch an entry by using a File's id
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    static function byFile(File $file) {
 | 
					    static function byFile(File $file) {
 | 
				
			||||||
        $file_thumbnail = self::getKV('file_id', $file->id);
 | 
					        $file_thumbnail = self::getKV('file_id', $file->getID());
 | 
				
			||||||
        if (!$file_thumbnail instanceof File_thumbnail) {
 | 
					        if (!$file_thumbnail instanceof File_thumbnail) {
 | 
				
			||||||
            throw new ServerException(sprintf('No File_thumbnail entry for File id==%u', $file->id));
 | 
					            throw new ServerException(sprintf('No File_thumbnail entry for File id==%u', $file->getID()));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        return $file_thumbnail;
 | 
					        return $file_thumbnail;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -167,11 +167,6 @@ class File_thumbnail extends Managed_DataObject
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    public function getFile()
 | 
					    public function getFile()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $file = new File();
 | 
					        return File::getByID($this->file_id);
 | 
				
			||||||
        $file->id = $this->file_id;
 | 
					 | 
				
			||||||
        if (!$file->find(true)) {
 | 
					 | 
				
			||||||
            throw new NoResultException($file);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        return $file;
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -17,9 +17,7 @@
 | 
				
			|||||||
 * along with this program.     If not, see <http://www.gnu.org/licenses/>.
 | 
					 * along with this program.     If not, see <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
 | 
					if (!defined('GNUSOCIAL')) { exit(1); }
 | 
				
			||||||
 | 
					 | 
				
			||||||
require_once INSTALLDIR.'/classes/Memcached_DataObject.php';
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Table Definition for file_to_post
 | 
					 * Table Definition for file_to_post
 | 
				
			||||||
@@ -58,39 +56,59 @@ class File_to_post extends Managed_DataObject
 | 
				
			|||||||
        );
 | 
					        );
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    function processNew($file_id, $notice_id) {
 | 
					    function processNew(File $file, Notice $notice) {
 | 
				
			||||||
        static $seen = array();
 | 
					        static $seen = array();
 | 
				
			||||||
        if (empty($seen[$notice_id]) || !in_array($file_id, $seen[$notice_id])) {
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            $f2p = File_to_post::pkeyGet(array('post_id' => $notice_id,
 | 
					        $file_id = $file->getID();
 | 
				
			||||||
 | 
					        $notice_id = $notice->getID();
 | 
				
			||||||
 | 
					        if (!array_key_exists($notice_id, $seen)) {
 | 
				
			||||||
 | 
					            $seen[$notice_id] = array();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (empty($seen[$notice_id]) || !in_array($file_id, $seen[$notice_id])) {
 | 
				
			||||||
 | 
					            try {
 | 
				
			||||||
 | 
					                $f2p = File_to_post::getByPK(array('post_id' => $notice_id,
 | 
				
			||||||
                                                   'file_id' => $file_id));
 | 
					                                                   'file_id' => $file_id));
 | 
				
			||||||
            if (empty($f2p)) {
 | 
					            } catch (NoResultException $e) {
 | 
				
			||||||
                $f2p = new File_to_post;
 | 
					                $f2p = new File_to_post;
 | 
				
			||||||
                $f2p->file_id = $file_id;
 | 
					                $f2p->file_id = $file_id;
 | 
				
			||||||
                $f2p->post_id = $notice_id;
 | 
					                $f2p->post_id = $notice_id;
 | 
				
			||||||
                $f2p->insert();
 | 
					                $f2p->insert();
 | 
				
			||||||
                
 | 
					                
 | 
				
			||||||
                $f = File::getKV($file_id);
 | 
					                $file->blowCache();
 | 
				
			||||||
 | 
					 | 
				
			||||||
                if (!empty($f)) {
 | 
					 | 
				
			||||||
                    $f->blowCache();
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (empty($seen[$notice_id])) {
 | 
					 | 
				
			||||||
                $seen[$notice_id] = array($file_id);
 | 
					 | 
				
			||||||
            } else {
 | 
					 | 
				
			||||||
            $seen[$notice_id][] = $file_id;
 | 
					            $seen[$notice_id][] = $file_id;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    static function getNoticeIDsByFile(File $file)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $f2p = new File_to_post();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $f2p->selectAdd();
 | 
				
			||||||
 | 
					        $f2p->selectAdd('post_id');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $f2p->file_id = $file->getID();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $ids = array();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (!$f2p->find()) {
 | 
				
			||||||
 | 
					            throw new NoResultException($f2p);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return $f2p->fetchAll('post_id');
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    function delete($useWhere=false)
 | 
					    function delete($useWhere=false)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $f = File::getKV('id', $this->file_id);
 | 
					        try {
 | 
				
			||||||
        if ($f instanceof File) {
 | 
					            $f = File::getByID($this->file_id);
 | 
				
			||||||
            $f->blowCache();
 | 
					            $f->blowCache();
 | 
				
			||||||
 | 
					        } catch (NoResultException $e) {
 | 
				
			||||||
 | 
					            // ...alright, that's weird, but no File to delete anyway.
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return parent::delete($useWhere);
 | 
					        return parent::delete($useWhere);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -64,6 +64,11 @@ abstract class Managed_DataObject extends Memcached_DataObject
 | 
				
			|||||||
        return parent::pkeyGetClass(get_called_class(), $kv);
 | 
					        return parent::pkeyGetClass(get_called_class(), $kv);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    static function pkeyCols()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return parent::pkeyColsClass(get_called_class());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Get multiple items from the database by key
 | 
					     * Get multiple items from the database by key
 | 
				
			||||||
     *
 | 
					     *
 | 
				
			||||||
@@ -304,6 +309,53 @@ abstract class Managed_DataObject extends Memcached_DataObject
 | 
				
			|||||||
        return common_database_tablename($this->tableName());
 | 
					        return common_database_tablename($this->tableName());
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Returns an object by looking at the primary key column(s).
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * Will require all primary key columns to be defined in an associative array
 | 
				
			||||||
 | 
					     * and ignore any keys which are not part of the primary key.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * Will NOT accept NULL values as part of primary key.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param   array   $vals       Must match all primary key columns for the dataobject.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return  Managed_DataObject  of the get_called_class() type
 | 
				
			||||||
 | 
					     * @throws  NoResultException   if no object with that primary key
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    static function getByPK(array $vals)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $classname = get_called_class();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $pkey = static::pkeyCols();
 | 
				
			||||||
 | 
					        if (is_null($pkey)) {
 | 
				
			||||||
 | 
					            throw new ServerException("Failed to get primary key columns for class '{$classname}'");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $object = new $classname();
 | 
				
			||||||
 | 
					        foreach ($pkey as $col) {
 | 
				
			||||||
 | 
					            if (!array_key_exists($col, $vals)) {
 | 
				
			||||||
 | 
					                throw new ServerException("Missing primary key column '{$col}'");
 | 
				
			||||||
 | 
					            } elseif (is_null($vals[$col])) {
 | 
				
			||||||
 | 
					                throw new ServerException("NULL values not allowed in getByPK for column '{$col}'");
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            $object->$col = $vals[$col];
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (!$object->find(true)) {
 | 
				
			||||||
 | 
					            throw new NoResultException($object);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return $object;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    static function getByID($id)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (empty($id)) {
 | 
				
			||||||
 | 
					            throw new ServerException('Empty ID on lookup');
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        // getByPK throws exception if id is null
 | 
				
			||||||
 | 
					        // or if the class does not have a single 'id' column as primary key
 | 
				
			||||||
 | 
					        return static::getByPK(array('id' => $id));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Returns an ID, checked that it is set and reasonably valid
 | 
					     * Returns an ID, checked that it is set and reasonably valid
 | 
				
			||||||
     *
 | 
					     *
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -34,7 +34,7 @@ class Memcached_DataObject extends Safe_DataObject
 | 
				
			|||||||
    {
 | 
					    {
 | 
				
			||||||
        if (is_null($v)) {
 | 
					        if (is_null($v)) {
 | 
				
			||||||
            $v = $k;
 | 
					            $v = $k;
 | 
				
			||||||
            $keys = self::pkeyCols($cls);
 | 
					            $keys = static::pkeyCols();
 | 
				
			||||||
            if (count($keys) > 1) {
 | 
					            if (count($keys) > 1) {
 | 
				
			||||||
                // FIXME: maybe call pkeyGetClass() ourselves?
 | 
					                // FIXME: maybe call pkeyGetClass() ourselves?
 | 
				
			||||||
                throw new Exception('Use pkeyGetClass() for compound primary keys');
 | 
					                throw new Exception('Use pkeyGetClass() for compound primary keys');
 | 
				
			||||||
@@ -246,7 +246,7 @@ class Memcached_DataObject extends Safe_DataObject
 | 
				
			|||||||
        return $query;
 | 
					        return $query;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    static function pkeyCols($cls)
 | 
					    static function pkeyColsClass($cls)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $i = new $cls;
 | 
					        $i = new $cls;
 | 
				
			||||||
        $types = $i->keyTypes();
 | 
					        $types = $i->keyTypes();
 | 
				
			||||||
@@ -279,7 +279,7 @@ class Memcached_DataObject extends Safe_DataObject
 | 
				
			|||||||
        $pkeyMap = array_fill_keys($keyVals, array());
 | 
					        $pkeyMap = array_fill_keys($keyVals, array());
 | 
				
			||||||
        $result = array_fill_keys($keyVals, array());
 | 
					        $result = array_fill_keys($keyVals, array());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        $pkeyCols = self::pkeyCols($cls);
 | 
					        $pkeyCols = static::pkeyCols();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        $toFetch = array();
 | 
					        $toFetch = array();
 | 
				
			||||||
        $allPkeys = array();
 | 
					        $allPkeys = array();
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -84,7 +84,7 @@ class Notice extends Managed_DataObject
 | 
				
			|||||||
                'id' => array('type' => 'serial', 'not null' => true, 'description' => 'unique identifier'),
 | 
					                'id' => array('type' => 'serial', 'not null' => true, 'description' => 'unique identifier'),
 | 
				
			||||||
                'profile_id' => array('type' => 'int', 'not null' => true, 'description' => 'who made the update'),
 | 
					                'profile_id' => array('type' => 'int', 'not null' => true, 'description' => 'who made the update'),
 | 
				
			||||||
                'uri' => array('type' => 'varchar', 'length' => 191, 'description' => 'universally unique identifier, usually a tag URI'),
 | 
					                'uri' => array('type' => 'varchar', 'length' => 191, 'description' => 'universally unique identifier, usually a tag URI'),
 | 
				
			||||||
                'content' => array('type' => 'text', 'description' => 'update content', 'collate' => 'utf8_general_ci'),
 | 
					                'content' => array('type' => 'text', 'description' => 'update content', 'collate' => 'utf8mb4_general_ci'),
 | 
				
			||||||
                'rendered' => array('type' => 'text', 'description' => 'HTML version of the content'),
 | 
					                'rendered' => array('type' => 'text', 'description' => 'HTML version of the content'),
 | 
				
			||||||
                'url' => array('type' => 'varchar', 'length' => 191, 'description' => 'URL of any attachment (image, video, bookmark, whatever)'),
 | 
					                'url' => array('type' => 'varchar', 'length' => 191, 'description' => 'URL of any attachment (image, video, bookmark, whatever)'),
 | 
				
			||||||
                'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
 | 
					                'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
 | 
				
			||||||
@@ -313,16 +313,6 @@ class Notice extends Managed_DataObject
 | 
				
			|||||||
        return $notice;
 | 
					        return $notice;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public static function getById($id)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        $notice = new Notice();
 | 
					 | 
				
			||||||
        $notice->id = $id;
 | 
					 | 
				
			||||||
        if (!$notice->find(true)) {
 | 
					 | 
				
			||||||
            throw new NoResultException($notice);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        return $notice;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Extract #hashtags from this notice's content and save them to the database.
 | 
					     * Extract #hashtags from this notice's content and save them to the database.
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
@@ -1109,7 +1099,7 @@ class Notice extends Managed_DataObject
 | 
				
			|||||||
     */
 | 
					     */
 | 
				
			||||||
    function saveUrls() {
 | 
					    function saveUrls() {
 | 
				
			||||||
        if (common_config('attachments', 'process_links')) {
 | 
					        if (common_config('attachments', 'process_links')) {
 | 
				
			||||||
            common_replace_urls_callback($this->content, array($this, 'saveUrl'), $this->id);
 | 
					            common_replace_urls_callback($this->content, array($this, 'saveUrl'), $this);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1126,11 +1116,7 @@ class Notice extends Managed_DataObject
 | 
				
			|||||||
        if (common_config('attachments', 'process_links')) {
 | 
					        if (common_config('attachments', 'process_links')) {
 | 
				
			||||||
            // @fixme validation?
 | 
					            // @fixme validation?
 | 
				
			||||||
            foreach (array_unique($urls) as $url) {
 | 
					            foreach (array_unique($urls) as $url) {
 | 
				
			||||||
                try {
 | 
					                $this->saveUrl($url, $this);
 | 
				
			||||||
                    File::processNew($url, $this->id);
 | 
					 | 
				
			||||||
                } catch (ServerException $e) {
 | 
					 | 
				
			||||||
                    // Could not save URL. Log it?
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -1138,9 +1124,9 @@ class Notice extends Managed_DataObject
 | 
				
			|||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * @private callback
 | 
					     * @private callback
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    function saveUrl($url, $notice_id) {
 | 
					    function saveUrl($url, Notice $notice) {
 | 
				
			||||||
        try {
 | 
					        try {
 | 
				
			||||||
            File::processNew($url, $notice_id);
 | 
					            File::processNew($url, $notice);
 | 
				
			||||||
        } catch (ServerException $e) {
 | 
					        } catch (ServerException $e) {
 | 
				
			||||||
            // Could not save URL. Log it?
 | 
					            // Could not save URL. Log it?
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@@ -1311,7 +1297,7 @@ class Notice extends Managed_DataObject
 | 
				
			|||||||
                    $last = $parent;
 | 
					                    $last = $parent;
 | 
				
			||||||
                    continue;
 | 
					                    continue;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            } catch (Exception $e) {
 | 
					            } catch (NoParentNoticeException $e) {
 | 
				
			||||||
                // Latest notice has no parent
 | 
					                // Latest notice has no parent
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            // No parent, or parent out of scope
 | 
					            // No parent, or parent out of scope
 | 
				
			||||||
@@ -1617,7 +1603,7 @@ class Notice extends Managed_DataObject
 | 
				
			|||||||
            $this->saveReply($parentauthor->id);
 | 
					            $this->saveReply($parentauthor->id);
 | 
				
			||||||
            $replied[$parentauthor->id] = 1;
 | 
					            $replied[$parentauthor->id] = 1;
 | 
				
			||||||
            self::blow('reply:stream:%d', $parentauthor->id);
 | 
					            self::blow('reply:stream:%d', $parentauthor->id);
 | 
				
			||||||
        } catch (Exception $e) {
 | 
					        } catch (NoParentNoticeException $e) {
 | 
				
			||||||
            // Not a reply, since it has no parent!
 | 
					            // Not a reply, since it has no parent!
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1634,8 +1620,7 @@ class Notice extends Managed_DataObject
 | 
				
			|||||||
            foreach ($mention['mentioned'] as $mentioned) {
 | 
					            foreach ($mention['mentioned'] as $mentioned) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                // skip if they're already covered
 | 
					                // skip if they're already covered
 | 
				
			||||||
 | 
					                if (array_key_exists($mentioned->id, $replied)) {
 | 
				
			||||||
                if (!empty($replied[$mentioned->id])) {
 | 
					 | 
				
			||||||
                    continue;
 | 
					                    continue;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1852,8 +1837,8 @@ class Notice extends Managed_DataObject
 | 
				
			|||||||
            try {
 | 
					            try {
 | 
				
			||||||
                $reply = $this->getParent();
 | 
					                $reply = $this->getParent();
 | 
				
			||||||
                $ctx->replyToID  = $reply->getUri();
 | 
					                $ctx->replyToID  = $reply->getUri();
 | 
				
			||||||
                $ctx->replyToUrl = $reply->getUrl();
 | 
					                $ctx->replyToUrl = $reply->getUrl(true);    // true for fallback to local URL, less messy
 | 
				
			||||||
            } catch (Exception $e) {
 | 
					            } catch (NoParentNoticeException $e) {
 | 
				
			||||||
                // This is not a reply to something
 | 
					                // This is not a reply to something
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -2763,13 +2748,10 @@ class Notice extends Managed_DataObject
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    public function getParent()
 | 
					    public function getParent()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $parent = Notice::getKV('id', $this->reply_to);
 | 
					        if (empty($this->reply_to)) {
 | 
				
			||||||
 | 
					            throw new NoParentNoticeException($this);
 | 
				
			||||||
        if (!$parent instanceof Notice) {
 | 
					 | 
				
			||||||
            throw new ServerException('Notice has no parent');
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					        return self::getByID($this->reply_to);
 | 
				
			||||||
        return $parent;
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -48,12 +48,12 @@ class Profile extends Managed_DataObject
 | 
				
			|||||||
            'description' => 'local and remote users have profiles',
 | 
					            'description' => 'local and remote users have profiles',
 | 
				
			||||||
            'fields' => array(
 | 
					            'fields' => array(
 | 
				
			||||||
                'id' => array('type' => 'serial', 'not null' => true, 'description' => 'unique identifier'),
 | 
					                'id' => array('type' => 'serial', 'not null' => true, 'description' => 'unique identifier'),
 | 
				
			||||||
                'nickname' => array('type' => 'varchar', 'length' => 64, 'not null' => true, 'description' => 'nickname or username', 'collate' => 'utf8_general_ci'),
 | 
					                'nickname' => array('type' => 'varchar', 'length' => 64, 'not null' => true, 'description' => 'nickname or username', 'collate' => 'utf8mb4_general_ci'),
 | 
				
			||||||
                'fullname' => array('type' => 'varchar', 'length' => 191, 'description' => 'display name', 'collate' => 'utf8_general_ci'),
 | 
					                'fullname' => array('type' => 'varchar', 'length' => 191, 'description' => 'display name', 'collate' => 'utf8mb4_general_ci'),
 | 
				
			||||||
                'profileurl' => array('type' => 'varchar', 'length' => 191, 'description' => 'URL, cached so we dont regenerate'),
 | 
					                'profileurl' => array('type' => 'varchar', 'length' => 191, 'description' => 'URL, cached so we dont regenerate'),
 | 
				
			||||||
                'homepage' => array('type' => 'varchar', 'length' => 191, 'description' => 'identifying URL', 'collate' => 'utf8_general_ci'),
 | 
					                'homepage' => array('type' => 'varchar', 'length' => 191, 'description' => 'identifying URL', 'collate' => 'utf8mb4_general_ci'),
 | 
				
			||||||
                'bio' => array('type' => 'text', 'description' => 'descriptive biography', 'collate' => 'utf8_general_ci'),
 | 
					                'bio' => array('type' => 'text', 'description' => 'descriptive biography', 'collate' => 'utf8mb4_general_ci'),
 | 
				
			||||||
                'location' => array('type' => 'varchar', 'length' => 191, 'description' => 'physical location', 'collate' => 'utf8_general_ci'),
 | 
					                'location' => array('type' => 'varchar', 'length' => 191, 'description' => 'physical location', 'collate' => 'utf8mb4_general_ci'),
 | 
				
			||||||
                'lat' => array('type' => 'numeric', 'precision' => 10, 'scale' => 7, 'description' => 'latitude'),
 | 
					                'lat' => array('type' => 'numeric', 'precision' => 10, 'scale' => 7, 'description' => 'latitude'),
 | 
				
			||||||
                'lon' => array('type' => 'numeric', 'precision' => 10, 'scale' => 7, 'description' => 'longitude'),
 | 
					                'lon' => array('type' => 'numeric', 'precision' => 10, 'scale' => 7, 'description' => 'longitude'),
 | 
				
			||||||
                'location_id' => array('type' => 'int', 'description' => 'location id if possible'),
 | 
					                'location_id' => array('type' => 'int', 'description' => 'location id if possible'),
 | 
				
			||||||
@@ -880,6 +880,11 @@ class Profile extends Managed_DataObject
 | 
				
			|||||||
            $inst->delete();
 | 
					            $inst->delete();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $localuser = User::getKV('id', $this->id);
 | 
				
			||||||
 | 
					        if ($localuser instanceof User) {
 | 
				
			||||||
 | 
					            $localuser->delete();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return parent::delete($useWhere);
 | 
					        return parent::delete($useWhere);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -62,11 +62,11 @@ class Profile_prefs extends Managed_DataObject
 | 
				
			|||||||
    {
 | 
					    {
 | 
				
			||||||
        if (empty($topic)) {
 | 
					        if (empty($topic)) {
 | 
				
			||||||
            $prefs = new Profile_prefs();
 | 
					            $prefs = new Profile_prefs();
 | 
				
			||||||
            $prefs->profile_id = $profile->id;
 | 
					            $prefs->profile_id = $profile->getID();
 | 
				
			||||||
            $prefs->namespace  = $namespace;
 | 
					            $prefs->namespace  = $namespace;
 | 
				
			||||||
            $prefs->find();
 | 
					            $prefs->find();
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            $prefs = self::pivotGet('profile_id', $profile->id, array('namespace'=>$namespace, 'topic'=>$topic));
 | 
					            $prefs = self::pivotGet('profile_id', $profile->getID(), array('namespace'=>$namespace, 'topic'=>$topic));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (empty($prefs->N)) {
 | 
					        if (empty($prefs->N)) {
 | 
				
			||||||
@@ -85,7 +85,7 @@ class Profile_prefs extends Managed_DataObject
 | 
				
			|||||||
    static function getAll(Profile $profile)
 | 
					    static function getAll(Profile $profile)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        try {
 | 
					        try {
 | 
				
			||||||
            $prefs = self::listFind('profile_id', $profile->id);
 | 
					            $prefs = self::listFind('profile_id', $profile->getID());
 | 
				
			||||||
        } catch (NoResultException $e) {
 | 
					        } catch (NoResultException $e) {
 | 
				
			||||||
            return array();
 | 
					            return array();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@@ -101,15 +101,9 @@ class Profile_prefs extends Managed_DataObject
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    static function getTopic(Profile $profile, $namespace, $topic) {
 | 
					    static function getTopic(Profile $profile, $namespace, $topic) {
 | 
				
			||||||
        $pref = new Profile_prefs;
 | 
					        return Profile_prefs::getByPK(array('profile_id' => $profile->getID(),
 | 
				
			||||||
        $pref->profile_id = $profile->id;
 | 
					                                            'namespace'  => $namespace,
 | 
				
			||||||
        $pref->namespace  = $namespace;
 | 
					                                            'topic'      => $topic));
 | 
				
			||||||
        $pref->topic      = $topic;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (!$pref->find(true)) {
 | 
					 | 
				
			||||||
            throw new NoResultException($pref);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        return $pref;
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    static function getData(Profile $profile, $namespace, $topic, $def=null) {
 | 
					    static function getData(Profile $profile, $namespace, $topic, $def=null) {
 | 
				
			||||||
@@ -164,7 +158,7 @@ class Profile_prefs extends Managed_DataObject
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        $pref = new Profile_prefs();
 | 
					        $pref = new Profile_prefs();
 | 
				
			||||||
        $pref->profile_id = $profile->id;
 | 
					        $pref->profile_id = $profile->getID();
 | 
				
			||||||
        $pref->namespace  = $namespace;
 | 
					        $pref->namespace  = $namespace;
 | 
				
			||||||
        $pref->topic      = $topic;
 | 
					        $pref->topic      = $topic;
 | 
				
			||||||
        $pref->data       = $data;
 | 
					        $pref->data       = $data;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -63,7 +63,7 @@ class Queue_item extends Managed_DataObject
 | 
				
			|||||||
            // XXX: potential race condition
 | 
					            // XXX: potential race condition
 | 
				
			||||||
            // can we force it to only update if claimed is still null
 | 
					            // can we force it to only update if claimed is still null
 | 
				
			||||||
            // (or old)?
 | 
					            // (or old)?
 | 
				
			||||||
            common_log(LOG_INFO, 'claiming queue item id = ' . $qi->id .
 | 
					            common_log(LOG_INFO, 'claiming queue item id = ' . $qi->getID() .
 | 
				
			||||||
                ' for transport ' . $qi->transport);
 | 
					                ' for transport ' . $qi->transport);
 | 
				
			||||||
            $orig = clone($qi);
 | 
					            $orig = clone($qi);
 | 
				
			||||||
            $qi->claimed = common_sql_now();
 | 
					            $qi->claimed = common_sql_now();
 | 
				
			||||||
@@ -85,7 +85,7 @@ class Queue_item extends Managed_DataObject
 | 
				
			|||||||
    function releaseClaim()
 | 
					    function releaseClaim()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        // DB_DataObject doesn't let us save nulls right now
 | 
					        // DB_DataObject doesn't let us save nulls right now
 | 
				
			||||||
        $sql = sprintf("UPDATE queue_item SET claimed=NULL WHERE id=%d", $this->id);
 | 
					        $sql = sprintf("UPDATE queue_item SET claimed=NULL WHERE id=%d", $this->getID());
 | 
				
			||||||
        $this->query($sql);
 | 
					        $this->query($sql);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        $this->claimed = null;
 | 
					        $this->claimed = null;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -853,57 +853,59 @@ class User extends Managed_DataObject
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    static function recoverPassword($nore)
 | 
					    static function recoverPassword($nore)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
 | 
					        // $confirm_email will be used as a fallback if our user doesn't have a confirmed email
 | 
				
			||||||
 | 
					        $confirm_email = null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (common_is_email($nore)) {
 | 
				
			||||||
            $user = User::getKV('email', common_canonical_email($nore));
 | 
					            $user = User::getKV('email', common_canonical_email($nore));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (!$user) {
 | 
					 | 
				
			||||||
            try {
 | 
					 | 
				
			||||||
                $user = User::getKV('nickname', common_canonical_nickname($nore));
 | 
					 | 
				
			||||||
            } catch (NicknameException $e) {
 | 
					 | 
				
			||||||
                // invalid
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            // See if it's an unconfirmed email address
 | 
					            // See if it's an unconfirmed email address
 | 
				
			||||||
 | 
					            if (!$user instanceof User) {
 | 
				
			||||||
        if (!$user) {
 | 
					 | 
				
			||||||
                // Warning: it may actually be legit to have multiple folks
 | 
					                // Warning: it may actually be legit to have multiple folks
 | 
				
			||||||
                // who have claimed, but not yet confirmed, the same address.
 | 
					                // who have claimed, but not yet confirmed, the same address.
 | 
				
			||||||
                // We'll only send to the first one that comes up.
 | 
					                // We'll only send to the first one that comes up.
 | 
				
			||||||
                $confirm_email = new Confirm_address();
 | 
					                $confirm_email = new Confirm_address();
 | 
				
			||||||
                $confirm_email->address = common_canonical_email($nore);
 | 
					                $confirm_email->address = common_canonical_email($nore);
 | 
				
			||||||
                $confirm_email->address_type = 'email';
 | 
					                $confirm_email->address_type = 'email';
 | 
				
			||||||
            $confirm_email->find();
 | 
					                if ($confirm_email->find(true)) {
 | 
				
			||||||
            if ($confirm_email->fetch()) {
 | 
					                    $user = User::getKV('id', $confirm_email->user_id);
 | 
				
			||||||
                $user = User::getKV($confirm_email->user_id);
 | 
					 | 
				
			||||||
            } else {
 | 
					 | 
				
			||||||
                $confirm_email = null;
 | 
					 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
        } else {
 | 
					 | 
				
			||||||
            $confirm_email = null;
 | 
					 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (!$user) {
 | 
					            // No luck finding anyone by that email address.
 | 
				
			||||||
            // TRANS: Information on password recovery form if no known username or e-mail address was specified.
 | 
					            if (!$user instanceof User) {
 | 
				
			||||||
            throw new ClientException(_('No user with that email address or username.'));
 | 
					                if (common_config('site', 'fakeaddressrecovery')) {
 | 
				
			||||||
 | 
					                    // Return without actually doing anything! We fake address recovery
 | 
				
			||||||
 | 
					                    // to avoid revealing which email addresses are registered with the site.
 | 
				
			||||||
                    return;
 | 
					                    return;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					                // TRANS: Information on password recovery form if no known e-mail address was specified.
 | 
				
			||||||
 | 
					                throw new ClientException(_('No user with that email address exists here.'));
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            // This might throw a NicknameException on bad nicknames
 | 
				
			||||||
 | 
					            $user = User::getKV('nickname', common_canonical_nickname($nore));
 | 
				
			||||||
 | 
					            if (!$user instanceof User) {
 | 
				
			||||||
 | 
					                // TRANS: Information on password recovery form if no known username was specified.
 | 
				
			||||||
 | 
					                throw new ClientException(_('No user with that nickname exists here.'));
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Try to get an unconfirmed email address if they used a user name
 | 
					        // Try to get an unconfirmed email address if they used a user name
 | 
				
			||||||
 | 
					        if (empty($user->email) && $confirm_email === null) {
 | 
				
			||||||
        if (!$user->email && !$confirm_email) {
 | 
					 | 
				
			||||||
            $confirm_email = new Confirm_address();
 | 
					            $confirm_email = new Confirm_address();
 | 
				
			||||||
            $confirm_email->user_id = $user->id;
 | 
					            $confirm_email->user_id = $user->id;
 | 
				
			||||||
            $confirm_email->address_type = 'email';
 | 
					            $confirm_email->address_type = 'email';
 | 
				
			||||||
            $confirm_email->find();
 | 
					            $confirm_email->find();
 | 
				
			||||||
            if (!$confirm_email->fetch()) {
 | 
					            if (!$confirm_email->fetch()) {
 | 
				
			||||||
 | 
					                // Nothing found, so let's reset it to null
 | 
				
			||||||
                $confirm_email = null;
 | 
					                $confirm_email = null;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (!$user->email && !$confirm_email) {
 | 
					        if (empty($user->email) && !$confirm_email instanceof Confirm_address) {
 | 
				
			||||||
            // TRANS: Client error displayed on password recovery form if a user does not have a registered e-mail address.
 | 
					            // TRANS: Client error displayed on password recovery form if a user does not have a registered e-mail address.
 | 
				
			||||||
            throw new ClientException(_('No registered email address for that user.'));
 | 
					            throw new ClientException(_('No registered email address for that user.'));
 | 
				
			||||||
            return;
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Success! We have a valid user and a confirmed or unconfirmed email address
 | 
					        // Success! We have a valid user and a confirmed or unconfirmed email address
 | 
				
			||||||
@@ -912,13 +914,12 @@ class User extends Managed_DataObject
 | 
				
			|||||||
        $confirm->code = common_confirmation_code(128);
 | 
					        $confirm->code = common_confirmation_code(128);
 | 
				
			||||||
        $confirm->address_type = 'recover';
 | 
					        $confirm->address_type = 'recover';
 | 
				
			||||||
        $confirm->user_id = $user->id;
 | 
					        $confirm->user_id = $user->id;
 | 
				
			||||||
        $confirm->address = (!empty($user->email)) ? $user->email : $confirm_email->address;
 | 
					        $confirm->address = $user->email ?: $confirm_email->address;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (!$confirm->insert()) {
 | 
					        if (!$confirm->insert()) {
 | 
				
			||||||
            common_log_db_error($confirm, 'INSERT', __FILE__);
 | 
					            common_log_db_error($confirm, 'INSERT', __FILE__);
 | 
				
			||||||
            // TRANS: Server error displayed if e-mail address confirmation fails in the database on the password recovery form.
 | 
					            // TRANS: Server error displayed if e-mail address confirmation fails in the database on the password recovery form.
 | 
				
			||||||
            throw new ServerException(_('Error saving address confirmation.'));
 | 
					            throw new ServerException(_('Error saving address confirmation.'));
 | 
				
			||||||
            return;
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
         // @todo FIXME: needs i18n.
 | 
					         // @todo FIXME: needs i18n.
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										13
									
								
								js/extlib/jquery.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										13
									
								
								js/extlib/jquery.js
									
									
									
									
										vendored
									
									
								
							@@ -1,5 +1,5 @@
 | 
				
			|||||||
/*!
 | 
					/*!
 | 
				
			||||||
 * jQuery JavaScript Library v2.1.3
 | 
					 * jQuery JavaScript Library v2.1.4
 | 
				
			||||||
 * http://jquery.com/
 | 
					 * http://jquery.com/
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * Includes Sizzle.js
 | 
					 * Includes Sizzle.js
 | 
				
			||||||
@@ -9,7 +9,7 @@
 | 
				
			|||||||
 * Released under the MIT license
 | 
					 * Released under the MIT license
 | 
				
			||||||
 * http://jquery.org/license
 | 
					 * http://jquery.org/license
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * Date: 2014-12-18T15:11Z
 | 
					 * Date: 2015-04-28T16:01Z
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
(function( global, factory ) {
 | 
					(function( global, factory ) {
 | 
				
			||||||
@@ -67,7 +67,7 @@ var
 | 
				
			|||||||
	// Use the correct document accordingly with window argument (sandbox)
 | 
						// Use the correct document accordingly with window argument (sandbox)
 | 
				
			||||||
	document = window.document,
 | 
						document = window.document,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	version = "2.1.3",
 | 
						version = "2.1.4",
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Define a local copy of jQuery
 | 
						// Define a local copy of jQuery
 | 
				
			||||||
	jQuery = function( selector, context ) {
 | 
						jQuery = function( selector, context ) {
 | 
				
			||||||
@@ -531,7 +531,12 @@ jQuery.each("Boolean Number String Function Array Date RegExp Object Error".spli
 | 
				
			|||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function isArraylike( obj ) {
 | 
					function isArraylike( obj ) {
 | 
				
			||||||
	var length = obj.length,
 | 
					
 | 
				
			||||||
 | 
						// Support: iOS 8.2 (not reproducible in simulator)
 | 
				
			||||||
 | 
						// `in` check used to prevent JIT error (gh-2145)
 | 
				
			||||||
 | 
						// hasOwn isn't used here due to false negatives
 | 
				
			||||||
 | 
						// regarding Nodelist length in IE
 | 
				
			||||||
 | 
						var length = "length" in obj && obj.length,
 | 
				
			||||||
		type = jQuery.type( obj );
 | 
							type = jQuery.type( obj );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if ( type === "function" || jQuery.isWindow( obj ) ) {
 | 
						if ( type === "function" || jQuery.isWindow( obj ) ) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -328,7 +328,7 @@ class ApiAction extends Action
 | 
				
			|||||||
            // different story for parenting.
 | 
					            // different story for parenting.
 | 
				
			||||||
            $parent = $notice->getParent();
 | 
					            $parent = $notice->getParent();
 | 
				
			||||||
            $in_reply_to = $parent->id;
 | 
					            $in_reply_to = $parent->id;
 | 
				
			||||||
        } catch (Exception $e) {
 | 
					        } catch (NoParentNoticeException $e) {
 | 
				
			||||||
            $in_reply_to = null;
 | 
					            $in_reply_to = null;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        $twitter_status['in_reply_to_status_id'] = $in_reply_to;
 | 
					        $twitter_status['in_reply_to_status_id'] = $in_reply_to;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -36,6 +36,7 @@ class CommandInterpreter
 | 
				
			|||||||
        // StatusNet
 | 
					        // StatusNet
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        $cmd = strtolower($cmd);
 | 
					        $cmd = strtolower($cmd);
 | 
				
			||||||
 | 
					        $result = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (Event::handle('StartInterpretCommand', array($cmd, $arg, $user, &$result))) {
 | 
					        if (Event::handle('StartInterpretCommand', array($cmd, $arg, $user, &$result))) {
 | 
				
			||||||
            switch($cmd) {
 | 
					            switch($cmd) {
 | 
				
			||||||
@@ -297,8 +298,6 @@ class CommandInterpreter
 | 
				
			|||||||
                    $result = new TrackingCommand($user);
 | 
					                    $result = new TrackingCommand($user);
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                break;
 | 
					                break;
 | 
				
			||||||
            default:
 | 
					 | 
				
			||||||
                $result = false;
 | 
					 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            Event::handle('EndInterpretCommand', array($cmd, $arg, $user, &$result));
 | 
					            Event::handle('EndInterpretCommand', array($cmd, $arg, $user, &$result));
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -48,6 +48,7 @@ $default =
 | 
				
			|||||||
              'languages' => get_all_languages(),
 | 
					              'languages' => get_all_languages(),
 | 
				
			||||||
              'email' =>
 | 
					              'email' =>
 | 
				
			||||||
              array_key_exists('SERVER_ADMIN', $_SERVER) ? $_SERVER['SERVER_ADMIN'] : null,
 | 
					              array_key_exists('SERVER_ADMIN', $_SERVER) ? $_SERVER['SERVER_ADMIN'] : null,
 | 
				
			||||||
 | 
					              'fakeaddressrecovery' => true,
 | 
				
			||||||
              'broughtby' => null,
 | 
					              'broughtby' => null,
 | 
				
			||||||
              'timezone' => 'UTC',
 | 
					              'timezone' => 'UTC',
 | 
				
			||||||
              'broughtbyurl' => null,
 | 
					              'broughtbyurl' => null,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -23,7 +23,7 @@ define('GNUSOCIAL_ENGINE', 'GNU social');
 | 
				
			|||||||
define('GNUSOCIAL_ENGINE_URL', 'https://www.gnu.org/software/social/');
 | 
					define('GNUSOCIAL_ENGINE_URL', 'https://www.gnu.org/software/social/');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
define('GNUSOCIAL_BASE_VERSION', '1.2.0');
 | 
					define('GNUSOCIAL_BASE_VERSION', '1.2.0');
 | 
				
			||||||
define('GNUSOCIAL_LIFECYCLE', 'dev'); // 'dev', 'alpha[0-9]+', 'beta[0-9]+', 'rc[0-9]+', 'release'
 | 
					define('GNUSOCIAL_LIFECYCLE', 'alpha1'); // 'dev', 'alpha[0-9]+', 'beta[0-9]+', 'rc[0-9]+', 'release'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
define('GNUSOCIAL_VERSION', GNUSOCIAL_BASE_VERSION . '-' . GNUSOCIAL_LIFECYCLE);
 | 
					define('GNUSOCIAL_VERSION', GNUSOCIAL_BASE_VERSION . '-' . GNUSOCIAL_LIFECYCLE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -38,6 +38,9 @@ define('PROFILES_PER_PAGE', 20);
 | 
				
			|||||||
define('MESSAGES_PER_PAGE', 20);
 | 
					define('MESSAGES_PER_PAGE', 20);
 | 
				
			||||||
define('GROUPS_PER_PAGE', 20);
 | 
					define('GROUPS_PER_PAGE', 20);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					define('GROUPS_PER_MINILIST', 8);
 | 
				
			||||||
 | 
					define('PROFILES_PER_MINILIST', 8);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
define('FOREIGN_NOTICE_SEND', 1);
 | 
					define('FOREIGN_NOTICE_SEND', 1);
 | 
				
			||||||
define('FOREIGN_NOTICE_RECV', 2);
 | 
					define('FOREIGN_NOTICE_RECV', 2);
 | 
				
			||||||
define('FOREIGN_NOTICE_SEND_REPLY', 4);
 | 
					define('FOREIGN_NOTICE_SEND_REPLY', 4);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -33,8 +33,6 @@ if (!defined('STATUSNET') && !defined('LACONICA')) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
require_once INSTALLDIR.'/lib/grouplist.php';
 | 
					require_once INSTALLDIR.'/lib/grouplist.php';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
define('GROUPS_PER_MINILIST', 8);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Widget to show a list of groups, good for sidebar
 | 
					 * Widget to show a list of groups, good for sidebar
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -103,7 +103,7 @@ class GNUsocial_HTTPResponse extends HTTP_Request2_Response
 | 
				
			|||||||
 *
 | 
					 *
 | 
				
			||||||
 * This extends the PEAR HTTP_Request2 package:
 | 
					 * This extends the PEAR HTTP_Request2 package:
 | 
				
			||||||
 * - sends StatusNet-specific User-Agent header
 | 
					 * - sends StatusNet-specific User-Agent header
 | 
				
			||||||
 * - 'follow_redirects' config option, defaulting off
 | 
					 * - 'follow_redirects' config option, defaulting on
 | 
				
			||||||
 * - 'max_redirs' config option, defaulting to 10
 | 
					 * - 'max_redirs' config option, defaulting to 10
 | 
				
			||||||
 * - extended response class adds getRedirectCount() and getUrl() methods
 | 
					 * - extended response class adds getRedirectCount() and getUrl() methods
 | 
				
			||||||
 * - get() and post() convenience functions return body content directly
 | 
					 * - get() and post() convenience functions return body content directly
 | 
				
			||||||
@@ -205,12 +205,28 @@ class HTTPClient extends HTTP_Request2
 | 
				
			|||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Convenience function to run a HEAD request.
 | 
					     * Convenience function to run a HEAD request.
 | 
				
			||||||
     *
 | 
					     *
 | 
				
			||||||
 | 
					     * NOTE: Will probably turn into a GET request if you let it follow redirects!
 | 
				
			||||||
 | 
					     *       That option is only there to be flexible and may be removed in the future!
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
     * @return GNUsocial_HTTPResponse
 | 
					     * @return GNUsocial_HTTPResponse
 | 
				
			||||||
     * @throws HTTP_Request2_Exception
 | 
					     * @throws HTTP_Request2_Exception
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public function head($url, $headers=array())
 | 
					    public function head($url, $headers=array(), $follow_redirects=false)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
 | 
					        // Save the configured value for follow_redirects
 | 
				
			||||||
 | 
					        $old_follow = $this->config['follow_redirects'];
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					            // Temporarily (possibly) override the follow_redirects setting
 | 
				
			||||||
 | 
					            $this->config['follow_redirects'] = $follow_redirects;
 | 
				
			||||||
            return $this->doRequest($url, self::METHOD_HEAD, $headers);
 | 
					            return $this->doRequest($url, self::METHOD_HEAD, $headers);
 | 
				
			||||||
 | 
					        } catch (Exception $e) {
 | 
				
			||||||
 | 
					            // Let the exception go on its merry way.
 | 
				
			||||||
 | 
					            throw $e;
 | 
				
			||||||
 | 
					        } finally {
 | 
				
			||||||
 | 
					            // reset to the old value
 | 
				
			||||||
 | 
					            $this->config['follow_redirects'] = $old_follow;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        //we've either returned or thrown exception here
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -380,7 +380,7 @@ abstract class ImPlugin extends Plugin
 | 
				
			|||||||
            $parent = $notice->getParent();
 | 
					            $parent = $notice->getParent();
 | 
				
			||||||
            $orig_profile = $parent->getProfile();
 | 
					            $orig_profile = $parent->getProfile();
 | 
				
			||||||
            $nicknames = sprintf('%1$s => %2$s', $profile->nickname, $orig_profile->nickname);
 | 
					            $nicknames = sprintf('%1$s => %2$s', $profile->nickname, $orig_profile->nickname);
 | 
				
			||||||
        } catch (Exception $e) {
 | 
					        } catch (NoParentNoticeException $e) {
 | 
				
			||||||
            $nicknames = $profile->nickname;
 | 
					            $nicknames = $profile->nickname;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -402,9 +402,8 @@ abstract class ImPlugin extends Plugin
 | 
				
			|||||||
            $chan = new IMChannel($this);
 | 
					            $chan = new IMChannel($this);
 | 
				
			||||||
            $cmd->execute($chan);
 | 
					            $cmd->execute($chan);
 | 
				
			||||||
            return true;
 | 
					            return true;
 | 
				
			||||||
        } else {
 | 
					 | 
				
			||||||
            return false;
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					        return false;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -61,7 +61,7 @@ class MediaFile
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    public function attachToNotice(Notice $notice)
 | 
					    public function attachToNotice(Notice $notice)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        File_to_post::processNew($this->fileRecord->id, $notice->id);
 | 
					        File_to_post::processNew($this->fileRecord, $notice);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public function getPath()
 | 
					    public function getPath()
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										41
									
								
								lib/noparentnoticeexception.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								lib/noparentnoticeexception.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,41 @@
 | 
				
			|||||||
 | 
					<?php
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * StatusNet, the distributed open-source microblogging tool
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Class for an exception when a database lookup returns no results
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * PHP version 5
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * LICENCE: This program is free software: you can redistribute it and/or modify
 | 
				
			||||||
 | 
					 * it under the terms of the GNU Affero General Public License as published by
 | 
				
			||||||
 | 
					 * the Free Software Foundation, either version 3 of the License, or
 | 
				
			||||||
 | 
					 * (at your option) any later version.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This program is distributed in the hope that it will be useful,
 | 
				
			||||||
 | 
					 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
					 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
				
			||||||
 | 
					 * GNU Affero General Public License for more details.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * You should have received a copy of the GNU Affero General Public License
 | 
				
			||||||
 | 
					 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @category  Exception
 | 
				
			||||||
 | 
					 * @package   GNUsocial
 | 
				
			||||||
 | 
					 * @author    Mikael Nordfeldth <mmn@hethane.se>
 | 
				
			||||||
 | 
					 * @copyright 2013 Free Software Foundation, Inc.
 | 
				
			||||||
 | 
					 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPLv3
 | 
				
			||||||
 | 
					 * @link      http://www.gnu.org/software/social/
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if (!defined('GNUSOCIAL')) { exit(1); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class NoParentNoticeException extends ServerException
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public $notice;    // The notice which has no parent
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function __construct(Notice $notice)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $this->notice = $notice;
 | 
				
			||||||
 | 
					        parent::__construct(sprintf(_('No parent for notice with ID "%s".'), $this->notice->id));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -29,8 +29,6 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
if (!defined('GNUSOCIAL')) { exit(1); }
 | 
					if (!defined('GNUSOCIAL')) { exit(1); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
define('PROFILES_PER_MINILIST', 8);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Widget to show a list of profiles, good for sidebar
 | 
					 * Widget to show a list of profiles, good for sidebar
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -64,6 +64,13 @@ class PublicGroupNav extends Menu
 | 
				
			|||||||
                                     // TRANS: Menu item title in search group navigation panel.
 | 
					                                     // TRANS: Menu item title in search group navigation panel.
 | 
				
			||||||
                                     _('Public timeline'), $this->actionName == 'public', 'nav_timeline_public');
 | 
					                                     _('Public timeline'), $this->actionName == 'public', 'nav_timeline_public');
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					            if (!common_config('public', 'localonly') || $this->action->getScoped() instanceof Profile) {
 | 
				
			||||||
 | 
					                // Allow network wide view if you're logged in
 | 
				
			||||||
 | 
					                // TRANS: Menu item in search group navigation panel.
 | 
				
			||||||
 | 
					                $this->out->menuItem(common_local_url('networkpublic'), _m('MENU','Network'),
 | 
				
			||||||
 | 
					                                     // TRANS: Menu item title in search group navigation panel.
 | 
				
			||||||
 | 
					                                     _('Network public timeline'), $this->actionName == 'networkpublic', 'nav_timeline_networkpublic');
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // TRANS: Menu item in search group navigation panel.
 | 
					            // TRANS: Menu item in search group navigation panel.
 | 
				
			||||||
            $this->out->menuItem(common_local_url('groups'), _m('MENU','Groups'),
 | 
					            $this->out->menuItem(common_local_url('groups'), _m('MENU','Groups'),
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -535,6 +535,7 @@ class Schema
 | 
				
			|||||||
            $res = $this->conn->query($sql);
 | 
					            $res = $this->conn->query($sql);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if ($_PEAR->isError($res)) {
 | 
					            if ($_PEAR->isError($res)) {
 | 
				
			||||||
 | 
					                common_debug('PEAR exception on query: '.$sql);
 | 
				
			||||||
                PEAR_ErrorToPEAR_Exception($res);
 | 
					                PEAR_ErrorToPEAR_Exception($res);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										182
									
								
								lib/sitestreamaction.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										182
									
								
								lib/sitestreamaction.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,182 @@
 | 
				
			|||||||
 | 
					<?php
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if (!defined('GNUSOCIAL')) { exit(1); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Farther than any human will go
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					define('MAX_PUBLIC_PAGE', 100);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class SitestreamAction extends ManagedAction
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * page of the stream we're on; default = 1
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    var $page = null;
 | 
				
			||||||
 | 
					    var $notice;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    protected $stream = null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function isReadOnly($args)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    protected function doPreparation()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $this->page = ($this->arg('page')) ? ($this->arg('page')+0) : 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if ($this->page > MAX_PUBLIC_PAGE) {
 | 
				
			||||||
 | 
					            // TRANS: Client error displayed when requesting a public timeline page beyond the page limit.
 | 
				
			||||||
 | 
					            // TRANS: %s is the page limit.
 | 
				
			||||||
 | 
					            $this->clientError(sprintf(_('Beyond the page limit (%s).'), MAX_PUBLIC_PAGE));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        common_set_returnto($this->selfUrl());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->streamPrepare();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->notice = $this->stream->getNotices(($this->page-1)*NOTICES_PER_PAGE,
 | 
				
			||||||
 | 
					                                            NOTICES_PER_PAGE + 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (!$this->notice) {
 | 
				
			||||||
 | 
					            // TRANS: Server error displayed when a public timeline cannot be retrieved.
 | 
				
			||||||
 | 
					            $this->serverError(_('Could not retrieve public timeline.'));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if ($this->page > 1 && $this->notice->N == 0){
 | 
				
			||||||
 | 
					            // TRANS: Client error when page not found (404).
 | 
				
			||||||
 | 
					            $this->clientError(_('No such page.'), 404);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Title of the page
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return page title, including page number if over 1
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    function title()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if ($this->page > 1) {
 | 
				
			||||||
 | 
					            // TRANS: Title for all public timeline pages but the first.
 | 
				
			||||||
 | 
					            // TRANS: %d is the page number.
 | 
				
			||||||
 | 
					            return sprintf(_('Public timeline, page %d'), $this->page);
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            // TRANS: Title for the first public timeline page.
 | 
				
			||||||
 | 
					            return _('Public timeline');
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function extraHead()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        parent::extraHead();
 | 
				
			||||||
 | 
					        $rsd = common_local_url('rsd');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // RSD, http://tales.phrasewise.com/rfc/rsd
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->element('link', array('rel' => 'EditURI',
 | 
				
			||||||
 | 
					                                     'type' => 'application/rsd+xml',
 | 
				
			||||||
 | 
					                                     'href' => $rsd));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if ($this->page != 1) {
 | 
				
			||||||
 | 
					            $this->element('link', array('rel' => 'canonical',
 | 
				
			||||||
 | 
					                                         'href' => common_local_url('public')));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Output <head> elements for RSS and Atom feeds
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return void
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    function getFeeds()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return array(new Feed(Feed::JSON,
 | 
				
			||||||
 | 
					                              common_local_url('ApiTimelinePublic',
 | 
				
			||||||
 | 
					                                               array('format' => 'as')),
 | 
				
			||||||
 | 
					                              // TRANS: Link description for public timeline feed.
 | 
				
			||||||
 | 
					                              _('Public Timeline Feed (Activity Streams JSON)')),
 | 
				
			||||||
 | 
					                    new Feed(Feed::RSS1, common_local_url('publicrss'),
 | 
				
			||||||
 | 
					                              // TRANS: Link description for public timeline feed.
 | 
				
			||||||
 | 
					                              _('Public Timeline Feed (RSS 1.0)')),
 | 
				
			||||||
 | 
					                     new Feed(Feed::RSS2,
 | 
				
			||||||
 | 
					                              common_local_url('ApiTimelinePublic',
 | 
				
			||||||
 | 
					                                               array('format' => 'rss')),
 | 
				
			||||||
 | 
					                              // TRANS: Link description for public timeline feed.
 | 
				
			||||||
 | 
					                              _('Public Timeline Feed (RSS 2.0)')),
 | 
				
			||||||
 | 
					                     new Feed(Feed::ATOM,
 | 
				
			||||||
 | 
					                              common_local_url('ApiTimelinePublic',
 | 
				
			||||||
 | 
					                                               array('format' => 'atom')),
 | 
				
			||||||
 | 
					                              // TRANS: Link description for public timeline feed.
 | 
				
			||||||
 | 
					                              _('Public Timeline Feed (Atom)')));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function showEmptyList()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        // TRANS: Text displayed for public feed when there are no public notices.
 | 
				
			||||||
 | 
					        $message = _('This is the public timeline for %%site.name%% but no one has posted anything yet.') . ' ';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (common_logged_in()) {
 | 
				
			||||||
 | 
					            // TRANS: Additional text displayed for public feed when there are no public notices for a logged in user.
 | 
				
			||||||
 | 
					            $message .= _('Be the first to post!');
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else {
 | 
				
			||||||
 | 
					            if (! (common_config('site','closed') || common_config('site','inviteonly'))) {
 | 
				
			||||||
 | 
					                // TRANS: Additional text displayed for public feed when there are no public notices for a not logged in user.
 | 
				
			||||||
 | 
					                $message .= _('Why not [register an account](%%action.register%%) and be the first to post!');
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->elementStart('div', 'guide');
 | 
				
			||||||
 | 
					        $this->raw(common_markup_to_html($message));
 | 
				
			||||||
 | 
					        $this->elementEnd('div');
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Fill the content area
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * Shows a list of the notices in the public stream, with some pagination
 | 
				
			||||||
 | 
					     * controls.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return void
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    function showContent()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        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, $this->scoped);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $cnt = $nl->show();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if ($cnt == 0) {
 | 
				
			||||||
 | 
					            $this->showEmptyList();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->pagination($this->page > 1, $cnt > NOTICES_PER_PAGE,
 | 
				
			||||||
 | 
					                          $this->page, $this->action);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function showAnonymousMessage()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (! (common_config('site','closed') || common_config('site','inviteonly'))) {
 | 
				
			||||||
 | 
					            // TRANS: Message for not logged in users at an invite-only site trying to view the public feed of notices.
 | 
				
			||||||
 | 
					            // TRANS: This message contains Markdown links. Please mind the formatting.
 | 
				
			||||||
 | 
					            $m = _('This is %%site.name%%, a [micro-blogging](http://en.wikipedia.org/wiki/Micro-blogging) service ' .
 | 
				
			||||||
 | 
					                   'based on the Free Software [StatusNet](http://status.net/) tool. ' .
 | 
				
			||||||
 | 
					                   '[Join now](%%action.register%%) to share notices about yourself with friends, family, and colleagues! ' .
 | 
				
			||||||
 | 
					                   '([Read more](%%doc.help%%))');
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            // TRANS: Message for not logged in users at a closed site trying to view the public feed of notices.
 | 
				
			||||||
 | 
					            // TRANS: This message contains Markdown links. Please mind the formatting.
 | 
				
			||||||
 | 
					            $m = _('This is %%site.name%%, a [micro-blogging](http://en.wikipedia.org/wiki/Micro-blogging) service ' .
 | 
				
			||||||
 | 
					                   'based on the Free Software [StatusNet](http://status.net/) tool.');
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        $this->elementStart('div', array('id' => 'anon_notice'));
 | 
				
			||||||
 | 
					        $this->raw(common_markup_to_html($m));
 | 
				
			||||||
 | 
					        $this->elementEnd('div');
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										17
									
								
								lib/util.php
									
									
									
									
									
								
							
							
						
						
									
										17
									
								
								lib/util.php
									
									
									
									
									
								
							@@ -628,7 +628,7 @@ function common_render_content($text, Notice $notice)
 | 
				
			|||||||
 * @param Notice $notice in-progress or complete Notice object for context
 | 
					 * @param Notice $notice in-progress or complete Notice object for context
 | 
				
			||||||
 * @return string partially-rendered HTML
 | 
					 * @return string partially-rendered HTML
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
function common_linkify_mentions($text, $notice)
 | 
					function common_linkify_mentions($text, Notice $notice)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    $mentions = common_find_mentions($text, $notice);
 | 
					    $mentions = common_find_mentions($text, $notice);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -655,7 +655,7 @@ function common_linkify_mentions($text, $notice)
 | 
				
			|||||||
    return $text;
 | 
					    return $text;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function common_linkify_mention($mention)
 | 
					function common_linkify_mention(array $mention)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    $output = null;
 | 
					    $output = null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -695,13 +695,10 @@ function common_linkify_mention($mention)
 | 
				
			|||||||
 *
 | 
					 *
 | 
				
			||||||
 * @access private
 | 
					 * @access private
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
function common_find_mentions($text, $notice)
 | 
					function common_find_mentions($text, Notice $notice)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    try {
 | 
					    // The getProfile call throws NoProfileException on failure
 | 
				
			||||||
        $sender = Profile::getKV('id', $notice->profile_id);
 | 
					    $sender = $notice->getProfile();
 | 
				
			||||||
    } catch (NoProfileException $e) {
 | 
					 | 
				
			||||||
        return array();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    $mentions = array();
 | 
					    $mentions = array();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -728,8 +725,8 @@ function common_find_mentions($text, $notice)
 | 
				
			|||||||
                }
 | 
					                }
 | 
				
			||||||
            } catch (NoProfileException $e) {
 | 
					            } catch (NoProfileException $e) {
 | 
				
			||||||
                common_log(LOG_WARNING, sprintf('Notice %d author profile id %d does not exist', $origNotice->id, $origNotice->profile_id));
 | 
					                common_log(LOG_WARNING, sprintf('Notice %d author profile id %d does not exist', $origNotice->id, $origNotice->profile_id));
 | 
				
			||||||
            } catch (ServerException $e) {
 | 
					            } catch (NoParentNoticeException $e) {
 | 
				
			||||||
                // Probably just no parent. Should get a specific NoParentException
 | 
					                // This notice is not in reply to anything
 | 
				
			||||||
            } catch (Exception $e) {
 | 
					            } catch (Exception $e) {
 | 
				
			||||||
                common_log(LOG_WARNING, __METHOD__ . ' got exception ' . get_class($e) . ' : ' . $e->getMessage());
 | 
					                common_log(LOG_WARNING, __METHOD__ . ' got exception ' . get_class($e) . ' : ' . $e->getMessage());
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -50,7 +50,7 @@ class ActivityverbAction extends ManagedAction
 | 
				
			|||||||
            throw new ServerException('A verb has not been specified.');
 | 
					            throw new ServerException('A verb has not been specified.');
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        $this->notice = Notice::getById($this->trimmed('id'));
 | 
					        $this->notice = Notice::getByID($this->trimmed('id'));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (!$this->notice->inScope($this->scoped)) {
 | 
					        if (!$this->notice->inScope($this->scoped)) {
 | 
				
			||||||
            // TRANS: %1$s is a user nickname, %2$d is a notice ID (number).
 | 
					            // TRANS: %1$s is a user nickname, %2$d is a notice ID (number).
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,6 +9,13 @@ class AntiBrutePlugin extends Plugin {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    const FAILED_LOGIN_IP_SECTION = 'failed_login_ip';
 | 
					    const FAILED_LOGIN_IP_SECTION = 'failed_login_ip';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function initialize()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        // This probably needs some work. For example with IPv6 you can easily generate new IPs...
 | 
				
			||||||
 | 
					        $client_ip = common_client_ip();
 | 
				
			||||||
 | 
					        $this->client_ip = $client_ip[0] ?: $client_ip[1];   // [0] is proxy, [1] should be the real IP
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public function onStartCheckPassword($nickname, $password, &$authenticatedUser)
 | 
					    public function onStartCheckPassword($nickname, $password, &$authenticatedUser)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        if (common_is_email($nickname)) {
 | 
					        if (common_is_email($nickname)) {
 | 
				
			||||||
@@ -22,9 +29,6 @@ class AntiBrutePlugin extends Plugin {
 | 
				
			|||||||
            return true;
 | 
					            return true;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // This probably needs some work. For example with IPv6 you can easily generate new IPs...
 | 
					 | 
				
			||||||
        $client_ip = common_client_ip();
 | 
					 | 
				
			||||||
        $this->client_ip = $client_ip[0] ?: $client_ip[1];   // [0] is proxy, [1] should be the real IP
 | 
					 | 
				
			||||||
        $this->failed_attempts = (int)$this->unauthed_user->getPref(self::FAILED_LOGIN_IP_SECTION, $this->client_ip);
 | 
					        $this->failed_attempts = (int)$this->unauthed_user->getPref(self::FAILED_LOGIN_IP_SECTION, $this->client_ip);
 | 
				
			||||||
        switch (true) {
 | 
					        switch (true) {
 | 
				
			||||||
        case $this->failed_attempts >= 5:
 | 
					        case $this->failed_attempts >= 5:
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -691,8 +691,8 @@ class Ostatus_profile extends Managed_DataObject
 | 
				
			|||||||
                                     $options);
 | 
					                                     $options);
 | 
				
			||||||
            if ($saved instanceof Notice) {
 | 
					            if ($saved instanceof Notice) {
 | 
				
			||||||
                Ostatus_source::saveNew($saved, $this, $method);
 | 
					                Ostatus_source::saveNew($saved, $this, $method);
 | 
				
			||||||
                if (!empty($attachment)) {
 | 
					                if ($attachment instanceof File) {
 | 
				
			||||||
                    File_to_post::processNew($attachment->id, $saved->id);
 | 
					                    File_to_post::processNew($attachment, $saved);
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        } catch (Exception $e) {
 | 
					        } catch (Exception $e) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -154,7 +154,7 @@ class OpenIDPlugin extends Plugin
 | 
				
			|||||||
     *
 | 
					     *
 | 
				
			||||||
     * @return boolean hook return
 | 
					     * @return boolean hook return
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    function onEndPublicXRDS($action, &$xrdsOutputter)
 | 
					    function onEndPublicXRDS(Action $action, &$xrdsOutputter)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $xrdsOutputter->elementStart('XRD', array('xmlns' => 'xri://$xrd*($v*2.0)',
 | 
					        $xrdsOutputter->elementStart('XRD', array('xmlns' => 'xri://$xrd*($v*2.0)',
 | 
				
			||||||
                                                  'xmlns:simple' => 'http://xrds-simple.net/core/1.0',
 | 
					                                                  'xmlns:simple' => 'http://xrds-simple.net/core/1.0',
 | 
				
			||||||
@@ -174,37 +174,6 @@ class OpenIDPlugin extends Plugin
 | 
				
			|||||||
        $xrdsOutputter->elementEnd('XRD');
 | 
					        $xrdsOutputter->elementEnd('XRD');
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * User XRDS output hook
 | 
					 | 
				
			||||||
     *
 | 
					 | 
				
			||||||
     * Puts the bits of code needed to discover OpenID endpoints.
 | 
					 | 
				
			||||||
     *
 | 
					 | 
				
			||||||
     * @param Action       $action         Action being executed
 | 
					 | 
				
			||||||
     * @param XMLOutputter &$xrdsOutputter Output channel
 | 
					 | 
				
			||||||
     *
 | 
					 | 
				
			||||||
     * @return boolean hook return
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    function onEndUserXRDS($action, &$xrdsOutputter)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        $xrdsOutputter->elementStart('XRD', array('xmlns' => 'xri://$xrd*($v*2.0)',
 | 
					 | 
				
			||||||
                                                  'xml:id' => 'openid',
 | 
					 | 
				
			||||||
                                                  'xmlns:simple' => 'http://xrds-simple.net/core/1.0',
 | 
					 | 
				
			||||||
                                                  'version' => '2.0'));
 | 
					 | 
				
			||||||
        $xrdsOutputter->element('Type', null, 'xri://$xrds*simple');
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        //consumer
 | 
					 | 
				
			||||||
        $xrdsOutputter->showXrdsService('http://specs.openid.net/auth/2.0/return_to',
 | 
					 | 
				
			||||||
                                        common_local_url('finishopenidlogin'));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        //provider
 | 
					 | 
				
			||||||
        $xrdsOutputter->showXrdsService('http://specs.openid.net/auth/2.0/signon',
 | 
					 | 
				
			||||||
                                        common_local_url('openidserver'),
 | 
					 | 
				
			||||||
                                        null,
 | 
					 | 
				
			||||||
                                        null,
 | 
					 | 
				
			||||||
                                        common_profile_url($action->user->nickname));
 | 
					 | 
				
			||||||
        $xrdsOutputter->elementEnd('XRD');
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * If we're in OpenID-only mode, hide all the main menu except OpenID login.
 | 
					     * If we're in OpenID-only mode, hide all the main menu except OpenID login.
 | 
				
			||||||
     *
 | 
					     *
 | 
				
			||||||
@@ -415,7 +384,7 @@ class OpenIDPlugin extends Plugin
 | 
				
			|||||||
     *
 | 
					     *
 | 
				
			||||||
     * @return void
 | 
					     * @return void
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    function onEndShowHeadElements($action)
 | 
					    function onEndShowHeadElements(Action $action)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        if ($action instanceof ShowstreamAction) {
 | 
					        if ($action instanceof ShowstreamAction) {
 | 
				
			||||||
            $action->element('link', array('rel' => 'openid2.provider',
 | 
					            $action->element('link', array('rel' => 'openid2.provider',
 | 
				
			||||||
@@ -427,6 +396,11 @@ class OpenIDPlugin extends Plugin
 | 
				
			|||||||
            $action->element('link', array('rel' => 'openid.delegate',
 | 
					            $action->element('link', array('rel' => 'openid.delegate',
 | 
				
			||||||
                                           'href' => $action->profile->profileurl));
 | 
					                                           'href' => $action->profile->profileurl));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if ($action instanceof SitestreamAction) {
 | 
				
			||||||
 | 
					            $action->element('meta', array('http-equiv' => 'X-XRDS-Location',
 | 
				
			||||||
 | 
					                                         'content' => common_local_url('publicxrds')));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
        return true;
 | 
					        return true;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -30,12 +30,9 @@
 | 
				
			|||||||
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
					 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if (!defined('STATUSNET') && !defined('LACONICA')) {
 | 
					if (!defined('GNUSOCIAL')) { exit(1); }
 | 
				
			||||||
    exit(1);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
require_once INSTALLDIR.'/plugins/OpenID/openid.php';
 | 
					require_once __DIR__.'/../openid.php';
 | 
				
			||||||
require_once INSTALLDIR.'/lib/xrdsoutputter.php';
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Public XRDS
 | 
					 * Public XRDS
 | 
				
			||||||
@@ -48,8 +45,6 @@ require_once INSTALLDIR.'/lib/xrdsoutputter.php';
 | 
				
			|||||||
 * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
 | 
					 * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
 | 
				
			||||||
 * @license  http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
 | 
					 * @license  http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
 | 
				
			||||||
 * @link     http://status.net/
 | 
					 * @link     http://status.net/
 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * @todo factor out similarities with XrdsAction
 | 
					 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
class PublicxrdsAction extends Action
 | 
					class PublicxrdsAction extends Action
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -70,9 +65,9 @@ class PublicxrdsAction extends Action
 | 
				
			|||||||
     *
 | 
					     *
 | 
				
			||||||
     * @return nothing
 | 
					     * @return nothing
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    function handle($args)
 | 
					    protected function handle()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        parent::handle($args);
 | 
					        parent::handle();
 | 
				
			||||||
        $xrdsOutputter = new XRDSOutputter();
 | 
					        $xrdsOutputter = new XRDSOutputter();
 | 
				
			||||||
        $xrdsOutputter->startXRDS();
 | 
					        $xrdsOutputter->startXRDS();
 | 
				
			||||||
        Event::handle('StartPublicXRDS', array($this,&$xrdsOutputter));
 | 
					        Event::handle('StartPublicXRDS', array($this,&$xrdsOutputter));
 | 
				
			||||||
@@ -80,4 +75,3 @@ class PublicxrdsAction extends Action
 | 
				
			|||||||
        $xrdsOutputter->endXRDS();
 | 
					        $xrdsOutputter->endXRDS();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
@@ -28,11 +28,7 @@
 | 
				
			|||||||
 * @link      http://status.net/
 | 
					 * @link      http://status.net/
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if (!defined('STATUSNET') && !defined('LACONICA')) {
 | 
					if (!defined('GNUSOCIAL')) { exit(1); }
 | 
				
			||||||
    exit(1);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
require_once INSTALLDIR.'/lib/xmloutputter.php';
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Low-level generator for XRDS XML
 | 
					 * Low-level generator for XRDS XML
 | 
				
			||||||
@@ -161,7 +161,7 @@ class SharePlugin extends ActivityVerbHandlerPlugin
 | 
				
			|||||||
    public function extendActivity(Notice $stored, Activity $act, Profile $scoped=null)
 | 
					    public function extendActivity(Notice $stored, Activity $act, Profile $scoped=null)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        // TODO: How to handle repeats of deleted notices?
 | 
					        // TODO: How to handle repeats of deleted notices?
 | 
				
			||||||
        $target = Notice::getById($stored->repeat_of);
 | 
					        $target = Notice::getByID($stored->repeat_of);
 | 
				
			||||||
        // TRANS: A repeat activity's title. %1$s is repeater's nickname
 | 
					        // TRANS: A repeat activity's title. %1$s is repeater's nickname
 | 
				
			||||||
        //        and %2$s is the repeated user's nickname.
 | 
					        //        and %2$s is the repeated user's nickname.
 | 
				
			||||||
        $act->title = sprintf(_('%1$s repeated a notice by %2$s'),
 | 
					        $act->title = sprintf(_('%1$s repeated a notice by %2$s'),
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -564,13 +564,13 @@ class TwitterImport
 | 
				
			|||||||
     * @param Notice $notice
 | 
					     * @param Notice $notice
 | 
				
			||||||
     * @param object $status
 | 
					     * @param object $status
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    function saveStatusAttachments($notice, $status)
 | 
					    function saveStatusAttachments(Notice $notice, $status)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        if (common_config('attachments', 'process_links')) {
 | 
					        if (common_config('attachments', 'process_links')) {
 | 
				
			||||||
            if (!empty($status->entities) && !empty($status->entities->urls)) {
 | 
					            if (!empty($status->entities) && !empty($status->entities->urls)) {
 | 
				
			||||||
                foreach ($status->entities->urls as $url) {
 | 
					                foreach ($status->entities->urls as $url) {
 | 
				
			||||||
                    try {
 | 
					                    try {
 | 
				
			||||||
                        File::processNew($url->url, $notice->id);
 | 
					                        File::processNew($url->url, $notice);
 | 
				
			||||||
                    } catch (ServerException $e) {
 | 
					                    } catch (ServerException $e) {
 | 
				
			||||||
                        // Could not process attached URL
 | 
					                        // Could not process attached URL
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -31,6 +31,10 @@ if (!defined('GNUSOCIAL')) { exit(1); }
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
class WebFingerPlugin extends Plugin
 | 
					class WebFingerPlugin extends Plugin
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					    const OAUTH_ACCESS_TOKEN_REL    = 'http://apinamespace.org/oauth/access_token';
 | 
				
			||||||
 | 
					    const OAUTH_REQUEST_TOKEN_REL   = 'http://apinamespace.org/oauth/request_token';
 | 
				
			||||||
 | 
					    const OAUTH_AUTHORIZE_REL       = 'http://apinamespace.org/oauth/authorize';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public $http_alias = false;
 | 
					    public $http_alias = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public function initialize()
 | 
					    public function initialize()
 | 
				
			||||||
@@ -127,6 +131,11 @@ class WebFingerPlugin extends Plugin
 | 
				
			|||||||
                            $type,
 | 
					                            $type,
 | 
				
			||||||
                            true);    // isTemplate
 | 
					                            true);    // isTemplate
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // OAuth connections
 | 
				
			||||||
 | 
					        $links[] = new XML_XRD_Element_link(self::OAUTH_ACCESS_TOKEN_REL,  common_local_url('ApiOAuthAccessToken'));
 | 
				
			||||||
 | 
					        $links[] = new XML_XRD_Element_link(self::OAUTH_REQUEST_TOKEN_REL, common_local_url('ApiOAuthRequestToken'));
 | 
				
			||||||
 | 
					        $links[] = new XML_XRD_Element_link(self::OAUTH_AUTHORIZE_REL,     common_local_url('ApiOAuthAuthorize'));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -354,7 +354,7 @@ class XmppPlugin extends ImPlugin
 | 
				
			|||||||
            $xs->text(": ");
 | 
					            $xs->text(": ");
 | 
				
			||||||
        } catch (InvalidUrlException $e) {
 | 
					        } catch (InvalidUrlException $e) {
 | 
				
			||||||
            $xs->text(sprintf(' => %s', $orig_profile->nickname));
 | 
					            $xs->text(sprintf(' => %s', $orig_profile->nickname));
 | 
				
			||||||
        } catch (Exception $e) {
 | 
					        } catch (NoParentNoticeException $e) {
 | 
				
			||||||
            $xs->text(": ");
 | 
					            $xs->text(": ");
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        if (!empty($notice->rendered)) {
 | 
					        if (!empty($notice->rendered)) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -113,7 +113,7 @@ function readline_emulation($prompt)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
function console_help()
 | 
					function console_help()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    print "Welcome to StatusNet's interactive PHP console!\n";
 | 
					    print "Welcome to GNU social's interactive PHP console!\n";
 | 
				
			||||||
    print "Type some PHP code and it'll execute...\n";
 | 
					    print "Type some PHP code and it'll execute...\n";
 | 
				
			||||||
    print "\n";
 | 
					    print "\n";
 | 
				
			||||||
    print "Hint: return a value of any type to output it via var_export():\n";
 | 
					    print "Hint: return a value of any type to output it via var_export():\n";
 | 
				
			||||||
@@ -128,8 +128,8 @@ function console_help()
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if (CONSOLE_INTERACTIVE) {
 | 
					if (CONSOLE_INTERACTIVE) {
 | 
				
			||||||
    print "StatusNet interactive PHP console... type ctrl+D or enter 'exit' to exit.\n";
 | 
					    print "GNU social interactive PHP console... type ctrl+D or enter 'exit' to exit.\n";
 | 
				
			||||||
    $prompt = common_config('site', 'name') . '> ';
 | 
					    $prompt = common_slugify(common_config('site', 'name')) . '> ';
 | 
				
			||||||
} else {
 | 
					} else {
 | 
				
			||||||
    $prompt = '';
 | 
					    $prompt = '';
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										78
									
								
								scripts/nukefile.php
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										78
									
								
								scripts/nukefile.php
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,78 @@
 | 
				
			|||||||
 | 
					#!/usr/bin/env php
 | 
				
			||||||
 | 
					<?php
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * StatusNet - a distributed open-source microblogging tool
 | 
				
			||||||
 | 
					 * Copyright (C) 2008, 2009, StatusNet, Inc.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This program is free software: you can redistribute it and/or modify
 | 
				
			||||||
 | 
					 * it under the terms of the GNU Affero General Public License as published by
 | 
				
			||||||
 | 
					 * the Free Software Foundation, either version 3 of the License, or
 | 
				
			||||||
 | 
					 * (at your option) any later version.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This program is distributed in the hope that it will be useful,
 | 
				
			||||||
 | 
					 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
					 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
				
			||||||
 | 
					 * GNU Affero General Public License for more details.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * You should have received a copy of the GNU Affero General Public License
 | 
				
			||||||
 | 
					 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$shortoptions = 'i::yv';
 | 
				
			||||||
 | 
					$longoptions = array('id=', 'yes', 'verbose');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$helptext = <<<END_OF_HELP
 | 
				
			||||||
 | 
					nukefile.php [options]
 | 
				
			||||||
 | 
					deletes a file and related notices from the database
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  -i --id       ID of the file
 | 
				
			||||||
 | 
					  -v --verbose  Be verbose (print the contents of the notices deleted).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					END_OF_HELP;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					require_once INSTALLDIR.'/scripts/commandline.inc';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if (have_option('i', 'id')) {
 | 
				
			||||||
 | 
					    $id = get_option_value('i', 'id');
 | 
				
			||||||
 | 
					    $file = File::getKV('id', $id);
 | 
				
			||||||
 | 
					    if (!$file instanceof File) {
 | 
				
			||||||
 | 
					        print "Can't find file with ID $id\n";
 | 
				
			||||||
 | 
					        exit(1);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					} else {
 | 
				
			||||||
 | 
					    print "You must provide a file ID.\n";
 | 
				
			||||||
 | 
					    exit(1);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$verbose = have_option('v', 'verbose');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if (!have_option('y', 'yes')) {
 | 
				
			||||||
 | 
					    try {
 | 
				
			||||||
 | 
					        $filename = $file->getFilename();
 | 
				
			||||||
 | 
					    } catch (Exception $e) {
 | 
				
			||||||
 | 
					        $filename = '(remote file or no filename)';
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    print "About to PERMANENTLY delete file ($filename) ({$file->id}). Are you sure? [y/N] ";
 | 
				
			||||||
 | 
					    $response = fgets(STDIN);
 | 
				
			||||||
 | 
					    if (strtolower(trim($response)) != 'y') {
 | 
				
			||||||
 | 
					        print "Aborting.\n";
 | 
				
			||||||
 | 
					        exit(0);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					print "Finding notices...\n";
 | 
				
			||||||
 | 
					try {
 | 
				
			||||||
 | 
					    $ids = File_to_post::getNoticeIDsByFile($file);
 | 
				
			||||||
 | 
					    $notice = Notice::multiGet('id', $ids);
 | 
				
			||||||
 | 
					    while ($notice->fetch()) {
 | 
				
			||||||
 | 
					        print "Deleting notice {$notice->id}".($verbose ? ": $notice->content\n" : "\n");
 | 
				
			||||||
 | 
					        $notice->delete();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					} catch (NoResultException $e) {
 | 
				
			||||||
 | 
					    print "No notices found with this File attached.\n";
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					print "Deleting File object together with possibly locally stored copy.\n";
 | 
				
			||||||
 | 
					$file->delete();
 | 
				
			||||||
 | 
					print "DONE.\n";
 | 
				
			||||||
		Reference in New Issue
	
	Block a user