]> git.mxchange.org Git - quix0rs-gnu-social.git/commitdiff
Merge 1.1.x into master
authorEvan Prodromou <evan@e14n.com>
Tue, 16 Jul 2013 17:57:06 +0000 (10:57 -0700)
committerEvan Prodromou <evan@e14n.com>
Tue, 16 Jul 2013 17:57:06 +0000 (10:57 -0700)
18 files changed:
classes/Profile.php
classes/Profile_tag.php
classes/User.php
lib/oembedhelper.php
plugins/Bookmark/BookmarkPlugin.php
plugins/Bookmark/apitimelinebookmarks.php [new file with mode: 0644]
plugins/Bookmark/bookmarks.php [new file with mode: 0644]
plugins/Bookmark/bookmarksnoticestream.php [new file with mode: 0644]
plugins/Bookmark/bookmarksrss.php [new file with mode: 0644]
plugins/ModPlus/remoteprofileaction.php
plugins/TwitterBridge/TwitterBridgePlugin.php
plugins/TwitterBridge/daemons/twitterstatusfetcher.php
plugins/TwitterBridge/tweetinqueuehandler.php
plugins/TwitterBridge/twitterimport.php
plugins/TwitterBridge/twitteroauthclient.php
plugins/Xmpp/XmppPlugin.php
scripts/getvaliddaemons.php
theme/base/css/display.css

index 7005e776a59da542c91ee18fff2d8ff5e0e1ae71..8a5be5f358b58916662310e25e341cb702d8e183 100644 (file)
@@ -686,7 +686,7 @@ class Profile extends Managed_DataObject
         $profile = new Profile();
         $tagged = array();
 
-        $cnt = $profile->query(sprintf($qry, $this->id, $this->id, $tag));
+        $cnt = $profile->query(sprintf($qry, $this->id, $this->id, $profile->escape($tag)));
 
         while ($profile->fetch()) {
             $tagged[] = clone($profile);
index de91857eb878dc66eef896222b76f16495705259..75cca8c22c364e169967a41d749fb19566036391 100644 (file)
@@ -284,8 +284,11 @@ class Profile_tag extends Managed_DataObject
                'tag = "%s", tagger = "%s" ' .
                'WHERE tag = "%s" ' .
                'AND tagger = "%s"';
-        $result = $tags->query(sprintf($qry, $new->tag, $new->tagger,
-                                             $orig->tag, $orig->tagger));
+        $result = $tags->query(sprintf($qry,
+                                       $tags->escape($new->tag),
+                                       $tags->escape($new->tagger),
+                                       $tags->escape($orig->tag),
+                                       $tags->escape($orig->tagger)));
 
         if (!$result) {
             common_log_db_error($tags, 'UPDATE', __FILE__);
@@ -307,8 +310,8 @@ class Profile_tag extends Managed_DataObject
         $profile->query('SELECT profile.* ' .
                         'FROM profile JOIN profile_tag ' .
                         'ON profile.id = profile_tag.tagged ' .
-                        'WHERE profile_tag.tagger = ' . $tagger . ' ' .
-                        'AND profile_tag.tag = "' . $tag . '" ');
+                        'WHERE profile_tag.tagger = ' . $profile->escape($tagger) . ' ' .
+                        'AND profile_tag.tag = "' . $profile->escape($tag) . '" ');
         $tagged = array();
         while ($profile->fetch()) {
             $tagged[] = clone($profile);
index 8d21d2bc19f305b3e5a5d9946f99cd8df368e986..e8aaaf6a103c47d1d26a420a59b08b3354b2a67d 100644 (file)
@@ -736,7 +736,7 @@ class User extends Managed_DataObject
 
         $profile = new Profile();
 
-        $cnt = $profile->query(sprintf($qry, $this->id, $tag));
+        $cnt = $profile->query(sprintf($qry, $this->id, $profile->escape($tag)));
 
         return $profile;
     }
@@ -758,7 +758,7 @@ class User extends Managed_DataObject
 
         $profile = new Profile();
 
-        $profile->query(sprintf($qry, $this->id, $tag));
+        $profile->query(sprintf($qry, $this->id, $profile->escape($tag)));
 
         return $profile;
     }
index 903f80c581a03b92a17ec5f2a698809d9c307cab..6b5b8d34f2bd2139b82f2a817e0574a994df1675 100644 (file)
@@ -216,6 +216,10 @@ class oEmbedHelper
     {
         $params['url'] = $url;
         $params['format'] = 'json';
+        $key=common_config('oembed','apikey');
+        if(isset($key)) {
+            $params['key'] = common_config('oembed','apikey');
+        }
         $data = self::json($api, $params);
         return self::normalize($data);
     }
index 319366c19bae017ce8b427cae98d0f63a7904630..f644289ed45efdc30908660827c23dd2046a7f73 100644 (file)
@@ -148,6 +148,9 @@ class BookmarkPlugin extends MicroAppPlugin
 
         switch ($cls)
         {
+        case 'BookmarksAction':
+        case 'BookmarksrssAction':
+        case 'ApiTimelineBookmarksAction':
         case 'ShowbookmarkAction':
         case 'NewbookmarkAction':
         case 'BookmarkpopupAction':
@@ -180,6 +183,26 @@ class BookmarkPlugin extends MicroAppPlugin
      */
     function onRouterInitialized($m)
     {
+        if (common_config('singleuser', 'enabled')) {
+            $nickname = User::singleUserNickname();
+            $m->connect('bookmarks',
+                        array('action' => 'bookmarks', 'nickname' => $nickname));
+            $m->connect('bookmarks/rss',
+                        array('action' => 'bookmarksrss', 'nickname' => $nickname));
+        } else {
+            $m->connect(':nickname/bookmarks',
+                        array('action' => 'bookmarks'),
+                        array('nickname' => Nickname::DISPLAY_FMT));
+            $m->connect(':nickname/bookmarks/rss',
+                        array('action' => 'bookmarksrss'),
+                        array('nickname' => Nickname::DISPLAY_FMT));
+        }
+
+        $m->connect('api/bookmarks/:id.:format',
+                    array('action' => 'ApiTimelineBookmarks',
+                          'id' => Nickname::INPUT_FMT,
+                          'format' => '(xml|json|rss|atom|as)'));
+
         $m->connect('main/bookmark/new',
                     array('action' => 'newbookmark'),
                     array('id' => '[0-9]+'));
@@ -230,11 +253,13 @@ class BookmarkPlugin extends MicroAppPlugin
     {
         $versions[] = array('name' => 'Bookmark',
                             'version' => self::VERSION,
-                            'author' => 'Evan Prodromou',
+                            'author' => 'Evan Prodromou, Stephane Berube, Jean Baptiste Favre',
                             'homepage' => 'http://status.net/wiki/Plugin:Bookmark',
                             'description' =>
                             // TRANS: Plugin description.
-                            _m('Simple extension for supporting bookmarks.'));
+                            _m('Simple extension for supporting bookmarks. ') .
+                            'BookmarkList feature has been developped by Stephane Berube. ' .
+                            'Integration has been done by Jean Baptiste Favre.');
         return true;
     }
 
@@ -315,6 +340,41 @@ class BookmarkPlugin extends MicroAppPlugin
            return false;
     }
 
+    /**
+     * Modify the default menu to link to our custom action
+     *
+     * Using event handlers, it's possible to modify the default UI for pages
+     * almost without limit. In this method, we add a menu item to the default
+     * primary menu for the interface to link to our action.
+     *
+     * The Action class provides a rich set of events to hook, as well as output
+     * methods.
+     *
+     * @param Action $action The current action handler. Use this to
+     * do any output.
+     *
+     * @return boolean hook value; true means continue processing, false means stop.
+     *
+     * @see Action
+     */
+    function onEndPersonalGroupNav($action)
+    {
+        $this->user = common_current_user();
+
+        if (!$this->user) {
+            // TRANS: Client error displayed when trying to display bookmarks for a non-existing user.
+            $this->clientError(_('No such user.'));
+            return false;
+        }
+
+        $action->menuItem(common_local_url('bookmarks', array('nickname' => $this->user->nickname)),
+                          // TRANS: Menu item in sample plugin.
+                          _m('Bookmarks'),
+                          // TRANS: Menu item title in sample plugin.
+                          _m('A list of your bookmarks'), false, 'nav_timeline_bookmarks');
+        return true;
+    }
+
     /**
      * Save a remote bookmark (from Salmon or PuSH)
      *
diff --git a/plugins/Bookmark/apitimelinebookmarks.php b/plugins/Bookmark/apitimelinebookmarks.php
new file mode 100644 (file)
index 0000000..1753462
--- /dev/null
@@ -0,0 +1,268 @@
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Show a user's favorite notices
+ *
+ * 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  API
+ * @package   StatusNet
+ * @author    Craig Andrews <candrews@integralblue.com>
+ * @author    Evan Prodromou <evan@status.net>
+ * @author    Zach Copley <zach@status.net>
+ * @copyright 2009-2010 StatusNet, Inc.
+ * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
+ * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link      http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+    exit(1);
+}
+
+require_once INSTALLDIR.'/lib/apibareauth.php';
+require_once 'bookmarksnoticestream.php';
+
+/**
+ * Returns the 20 most recent favorite notices for the authenticating user or user
+ * specified by the ID parameter in the requested format.
+ *
+ * @category API
+ * @package  StatusNet
+ * @author   Craig Andrews <candrews@integralblue.com>
+ * @author   Evan Prodromou <evan@status.net>
+ * @author   Zach Copley <zach@status.net>
+ * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link     http://status.net/
+ */
+class ApiTimelineBookmarksAction extends ApiBareAuthAction
+{
+    var $notices  = null;
+
+    /**
+     * Take arguments for running
+     *
+     * @param array $args $_REQUEST args
+     *
+     * @return boolean success flag
+     */
+    function prepare($args)
+    {
+        parent::prepare($args);
+
+        $this->user = $this->getTargetUser($this->arg('id'));
+
+        if (empty($this->user)) {
+            // TRANS: Client error displayed when requesting most recent favourite notices by a user for a non-existing user.
+            $this->clientError(_('No such user.'), 404, $this->format);
+            return;
+        }
+
+        $this->notices = $this->getNotices();
+
+        return true;
+    }
+
+    /**
+     * Handle the request
+     *
+     * Just show the notices
+     *
+     * @param array $args $_REQUEST data (unused)
+     *
+     * @return void
+     */
+    function handle($args)
+    {
+        parent::handle($args);
+        $this->showTimeline();
+    }
+
+    /**
+     * Show the timeline of notices
+     *
+     * @return void
+     */
+    function showTimeline()
+    {
+        $profile  = $this->user->getProfile();
+        $avatar   = $profile->getAvatar(AVATAR_PROFILE_SIZE);
+
+        $sitename = common_config('site', 'name');
+        $title    = sprintf(
+            // TRANS: Title for timeline of most recent favourite notices by a user.
+            // TRANS: %1$s is the StatusNet sitename, %2$s is a user nickname.
+            _('%1$s / Bookmarks from %2$s'),
+            $sitename,
+            $this->user->nickname
+        );
+
+        $taguribase = TagURI::base();
+        $id         = "tag:$taguribase:Bookmarks:" . $this->user->id;
+
+        $subtitle = sprintf(
+            // TRANS: Subtitle for timeline of most recent favourite notices by a user.
+            // TRANS: %1$s is the StatusNet sitename, %2$s is a user's full name,
+            // TRANS: %3$s is a user nickname.
+            _('%1$s updates bookmarked by %2$s / %3$s.'),
+            $sitename,
+            $profile->getBestName(),
+            $this->user->nickname
+        );
+        $logo = !empty($avatar)
+            ? $avatar->displayUrl()
+            : Avatar::defaultImage(AVATAR_PROFILE_SIZE);
+
+        $link = common_local_url(
+            'bookmarks',
+            array('nickname' => $this->user->nickname)
+        );
+
+        $self = $this->getSelfUri();
+
+        switch($this->format) {
+        case 'xml':
+            $this->showXmlTimeline($this->notices);
+            break;
+        case 'rss':
+            $this->showRssTimeline(
+                $this->notices,
+                $title,
+                $link,
+                $subtitle,
+                null,
+                $logo,
+                $self
+            );
+            break;
+        case 'atom':
+            header('Content-Type: application/atom+xml; charset=utf-8');
+
+            $atom = new AtomNoticeFeed($this->auth_user);
+
+            $atom->setId($id);
+            $atom->setTitle($title);
+            $atom->setSubtitle($subtitle);
+            $atom->setLogo($logo);
+            $atom->setUpdated('now');
+
+            $atom->addLink($link);
+            $atom->setSelfLink($self);
+
+            $atom->addEntryFromNotices($this->notices);
+
+            $this->raw($atom->getString());
+            break;
+        case 'json':
+            $this->showJsonTimeline($this->notices);
+            break;
+        case 'as':
+            header('Content-Type: ' . ActivityStreamJSONDocument::CONTENT_TYPE);
+            $doc = new ActivityStreamJSONDocument($this->auth_user);
+            $doc->setTitle($title);
+            $doc->addLink($link,'alternate', 'text/html');
+            $doc->addItemsFromNotices($this->notices);
+            $this->raw($doc->asString());
+            break;
+        default:
+            // TRANS: Client error displayed when coming across a non-supported API method.
+            $this->clientError(_('API method not found.'), $code = 404);
+            break;
+        }
+    }
+
+    /**
+     * Get notices
+     *
+     * @return array notices
+     */
+    function getNotices()
+    {
+        $notices = array();
+
+        common_debug("since id = " . $this->since_id . " max id = " . $this->max_id);
+
+        $notice = new BookmarksNoticeStream($this->user->id, true);
+        $notice = $notice->getNotices(
+            ($this->page-1) * $this->count,
+            $this->count,
+            $this->since_id,
+            $this->max_id
+        );
+
+        while ($notice->fetch()) {
+            $notices[] = clone($notice);
+        }
+
+        return $notices;
+    }
+
+    /**
+     * Is this action read only?
+     *
+     * @param array $args other arguments
+     *
+     * @return boolean true
+     */
+    function isReadOnly($args)
+    {
+        return true;
+    }
+
+    /**
+     * When was this feed last modified?
+     *
+     * @return string datestamp of the latest notice in the stream
+     */
+    function lastModified()
+    {
+        if (!empty($this->notices) && (count($this->notices) > 0)) {
+            return strtotime($this->notices[0]->created);
+        }
+
+        return null;
+    }
+
+    /**
+     * An entity tag for this stream
+     *
+     * Returns an Etag based on the action name, language, user ID, and
+     * timestamps of the first and last notice in the timeline
+     *
+     * @return string etag
+     */
+    function etag()
+    {
+        if (!empty($this->notices) && (count($this->notices) > 0)) {
+
+            $last = count($this->notices) - 1;
+
+            return '"' . implode(
+                ':',
+                array($this->arg('action'),
+                      common_user_cache_hash($this->auth_user),
+                      common_language(),
+                      $this->user->id,
+                      strtotime($this->notices[0]->created),
+                      strtotime($this->notices[$last]->created))
+            )
+            . '"';
+        }
+
+        return null;
+    }
+}
diff --git a/plugins/Bookmark/bookmarks.php b/plugins/Bookmark/bookmarks.php
new file mode 100644 (file)
index 0000000..6faf999
--- /dev/null
@@ -0,0 +1,233 @@
+<?php
+/**
+ * Give a warm greeting to our friendly user
+ *
+ * PHP version 5
+ *
+ * @category Bookmark
+ * @package  StatusNet
+ * @author   Evan Prodromou <evan@status.net>
+ * @license  http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
+ * @link     http://status.net/
+ *
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 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/>.
+ */
+
+if (!defined('STATUSNET')) {
+    exit(1);
+}
+
+require_once 'bookmarksnoticestream.php';
+
+/**
+ * List currently logged-in user's bookmakrs
+ *
+ * @category Bookmark
+ * @package  StatusNet
+ * @author   Stephane Berube <chimo@chromic.org>
+ * @license  http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
+ * @link     https://github.com/chimo/BookmarkList
+ */
+class BookmarksAction extends Action
+{
+    var $user = null;
+    var $gc   = null;
+
+    /**
+     * Take arguments for running
+     *
+     * This method is called first, and it lets the action class get
+     * all its arguments and validate them. It's also the time
+     * to fetch any relevant data from the database.
+     *
+     * Action classes should run parent::prepare($args) as the first
+     * line of this method to make sure the default argument-processing
+     * happens.
+     *
+     * @param array $args $_REQUEST args
+     *
+     * @return boolean success flag
+     */
+    function prepare($args)
+    {
+        parent::prepare($args);
+
+        if (common_config('singleuser', 'enabled')) {
+            $nickname = User::singleUserNickname();
+        } else {
+            // PHP 5.4
+            // $nickname = $this->returnToArgs()[1]['nickname'];
+
+            // PHP < 5.4
+            $nickname = $this->returnToArgs();
+            $nickname = $nickname[1]['nickname'];
+        }
+        
+        $this->user = User::staticGet('nickname', $nickname);
+
+        if (!$this->user) {
+            // TRANS: Client error displayed when trying to display bookmarks for a non-existing user.
+            $this->clientError(_('No such user.'));
+            return false;
+        }
+
+        $this->page = ($this->arg('page')) ? ($this->arg('page')+0) : 1;
+
+        $stream = new BookmarksNoticeStream($this->user->id, true);
+        $this->notices = $stream->getNotices(($this->page-1)*NOTICES_PER_PAGE,
+                                                NOTICES_PER_PAGE + 1); 
+
+        if($this->page > 1 && $this->notices->N == 0) {
+            throw new ClientException(_('No such page.'), 404);
+        }
+
+        return true;
+    }
+
+    /**
+     * Handle request
+     *
+     * This is the main method for handling a request. Note that
+     * most preparation should be done in the prepare() method;
+     * by the time handle() is called the action should be
+     * more or less ready to go.
+     *
+     * @param array $args $_REQUEST args; handled in prepare()
+     *
+     * @return void
+     */
+    function handle($args)
+    {
+        parent::handle($args);
+        $this->showPage();
+    }
+
+    /**
+     * Title of this page
+     *
+     * Override this method to show a custom title.
+     *
+     * @return string Title of the page
+     */
+    function title()
+    {
+
+        if (empty($this->user)) {
+            // TRANS: Page title for sample plugin.
+            return _m('Log in');
+        } else {
+            // TRANS: Page title for sample plugin. %s is a user nickname.
+            return sprintf(_m('%s\'s bookmarks'), $this->user->nickname);
+        }
+    }
+
+    /**
+     * Feeds for the <head> section
+     *
+     * @return array Feed objects to show
+     */
+    function getFeeds()
+    {
+        return array(new Feed(Feed::JSON,
+                              common_local_url('ApiTimelineBookmarks',
+                                               array(
+                                                    'id' => $this->user->nickname,
+                                                    'format' => 'as')),
+                              // TRANS: Feed link text. %s is a username.
+                              sprintf(_('Feed for favorites of %s (Activity Streams JSON)'),
+                                      $this->user->nickname)),
+                     new Feed(Feed::RSS1,
+                              common_local_url('bookmarksrss',
+                                               array('nickname' => $this->user->nickname)),
+                              // TRANS: Feed link text. %s is a username.
+                              sprintf(_('Feed for favorites of %s (RSS 1.0)'),
+                                      $this->user->nickname)),
+                     new Feed(Feed::RSS2,
+                              common_local_url('ApiTimelineBookmarks',
+                                               array(
+                                                    'id' => $this->user->nickname,
+                                                    'format' => 'rss')),
+                              // TRANS: Feed link text. %s is a username.
+                              sprintf(_('Feed for favorites of %s (RSS 2.0)'),
+                                      $this->user->nickname)),
+                     new Feed(Feed::ATOM,
+                              common_local_url('ApiTimelineBookmarks',
+                                               array(
+                                                    'id' => $this->user->nickname,
+                                                    'format' => 'atom')),
+                              // TRANS: Feed link text. %s is a username.
+                              sprintf(_('Feed for favorites of %s (Atom)'),
+                                      $this->user->nickname)));
+    }
+
+    /**
+     * Show content in the content area
+     *
+     * The default StatusNet page has a lot of decorations: menus,
+     * logos, tabs, all that jazz. This method is used to show
+     * content in the content area of the page; it's the main
+     * thing you want to overload.
+     *
+     * This method also demonstrates use of a plural localized string.
+     *
+     * @return void
+     */
+    function showContent()
+    {
+
+        $nl = new NoticeList($this->notices, $this);
+
+        $cnt = $nl->show();
+
+        if ($cnt == 0) {
+            $this->showEmptyList();
+        }
+
+        $this->pagination($this->page > 1,
+                $cnt > NOTICES_PER_PAGE,
+                $this->page, 'bookmarks',
+                array('nickname' => $this->user->nickname));
+    }
+
+    function showEmptyList() {
+        $message = sprintf(_('This is %1$s\'s bookmark stream, but %1$s hasn\'t bookmarked anything yet.'), $this->user->nickname) . ' ';
+
+        $this->elementStart('div', 'guide');
+        $this->raw(common_markup_to_html($message));
+        $this->elementEnd('div');
+    }
+
+    /**
+     * Return true if read only.
+     *
+     * Some actions only read from the database; others read and write.
+     * The simple database load-balancer built into StatusNet will
+     * direct read-only actions to database mirrors (if they are configured),
+     * and read-write actions to the master database.
+     *
+     * This defaults to false to avoid data integrity issues, but you
+     * should make sure to overload it for performance gains.
+     *
+     * @param array $args other arguments, if RO/RW status depends on them.
+     *
+     * @return boolean is read only action?
+     */
+    function isReadOnly($args)
+    {
+        return true;
+    }
+}
diff --git a/plugins/Bookmark/bookmarksnoticestream.php b/plugins/Bookmark/bookmarksnoticestream.php
new file mode 100644 (file)
index 0000000..a3ac035
--- /dev/null
@@ -0,0 +1,80 @@
+<?php
+
+class RawBookmarksNoticeStream extends NoticeStream
+{
+    protected $user_id;
+    protected $own;
+
+    function __construct($user_id, $own)
+    {
+        $this->user_id = $user_id;
+        $this->own     = $own;
+    }
+
+    function getNoticeIds($offset, $limit, $since_id, $max_id)
+    {
+        $notice = new Notice();
+        $qry = null;
+
+        $qry =  'SELECT notice.* FROM notice ';
+        $qry .= 'INNER JOIN bookmark ON bookmark.uri = notice.uri ';
+        $qry .= 'WHERE bookmark.profile_id = ' . $this->user_id . ' ';
+        $qry .= 'AND notice.is_local != ' . Notice::GATEWAY . ' ';
+
+        if ($since_id != 0) {
+            $qry .= 'AND notice.id > ' . $since_id . ' ';
+        }
+
+        if ($max_id != 0) {
+            $qry .= 'AND notice.id <= ' . $max_id . ' ';
+        }
+
+        // NOTE: we sort by bookmark time, not by notice time!
+        $qry .= 'ORDER BY created DESC ';
+        if (!is_null($offset)) {
+            $qry .= "LIMIT $limit OFFSET $offset";
+        }
+
+        $notice->query($qry);
+        $ids = array();
+        while ($notice->fetch()) {
+            $ids[] = $notice->id;
+        }
+
+        $notice->free();
+        unset($notice);
+        return $ids;
+    }
+}
+
+/**
+ * Notice stream for bookmarks
+ *
+ * @category  Stream
+ * @package   StatusNet
+ * @author    Stephane Berube <chimo@chromic.org>
+ * @copyright 2011 StatusNet, Inc.
+ * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link      http://status.net/
+ */
+
+class BookmarksNoticeStream extends ScopingNoticeStream
+{
+    function __construct($user_id, $own, $profile = -1)
+    {
+        $stream = new RawBookmarksNoticeStream($user_id, $own);
+
+        if ($own) {
+            $key = 'bookmark:ids_by_user_own:'.$user_id;
+        } else {
+            $key = 'bookmark:ids_by_user:'.$user_id;
+        }
+
+        if (is_int($profile) && $profile == -1) {
+            $profile = Profile::current();
+        }
+
+        parent::__construct(new CachingNoticeStream($stream, $key),
+                            $profile);
+    }
+}
diff --git a/plugins/Bookmark/bookmarksrss.php b/plugins/Bookmark/bookmarksrss.php
new file mode 100644 (file)
index 0000000..63534ca
--- /dev/null
@@ -0,0 +1,137 @@
+<?php
+/**
+ * RSS feed for user bookmarks action class.
+ *
+ * PHP version 5
+ *
+ * @category Action
+ * @package  StatusNet
+ * @author   Evan Prodromou <evan@status.net>
+ * @author   Robin Millette <millette@status.net>
+ * @license  http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
+ * @link     http://status.net/
+ *
+ * StatusNet - the 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/>.
+ */
+
+if (!defined('STATUSNET') && !defined('LACONICA')) {
+    exit(1);
+}
+
+require_once INSTALLDIR.'/lib/rssaction.php';
+require_once 'bookmarksnoticestream.php';
+
+/**
+ * RSS feed for user bookmarks action class.
+ *
+ * Formatting of RSS handled by Rss10Action
+ *
+ * @category Action
+ * @package  StatusNet
+ * @author   Evan Prodromou <evan@status.net>
+ * @author   Robin Millette <millette@status.net>
+ * @author   Zach Copley <zach@status.net>
+ * @author   Stephane Berube <chimo@chromic.org> (modified 'favoritesrss.php' to show bookmarks instead)
+ * @license  http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
+ * @link     http://status.net/
+ */
+class BookmarksrssAction extends Rss10Action
+{
+    /** The user whose bookmarks to display */
+
+    var $user = null;
+
+    /**
+     * Find the user to display by supplied nickname
+     *
+     * @param array $args Arguments from $_REQUEST
+     *
+     * @return boolean success
+     */
+    function prepare($args)
+    {        
+        parent::prepare($args);
+
+        $nickname   = $this->trimmed('nickname');
+        $this->user = User::staticGet('nickname', $nickname);
+
+        if (!$this->user) {
+            // TRANS: Client error displayed when trying to get the RSS feed with bookmarks of a user that does not exist.
+            $this->clientError(_('No such user.'));
+            return false;
+        } else {
+            $this->notices = $this->getNotices($this->limit);
+            return true;
+        }
+    }
+
+    /**
+     * Get notices
+     *
+     * @param integer $limit max number of notices to return
+     *
+     * @return array notices
+     */
+    function getNotices($limit=0)
+    {
+        $user    = $this->user;
+
+        $notice = new BookmarksNoticeStream($this->user->id, true);
+        $notice = $notice->getNotices(0, NOTICES_PER_PAGE);
+
+        $notices = array();
+        while ($notice->fetch()) {
+            $notices[] = clone($notice);
+        }
+        return $notices;
+    }
+
+     /**
+     * Get channel.
+     *
+     * @return array associative array on channel information
+     */
+    function getChannel()
+    {
+        $user = $this->user;
+        $c    = array('url' => common_local_url('bookmarksrss',
+                                        array('nickname' =>
+                                        $user->nickname)),
+                   // TRANS: Title of RSS feed with bookmarks of a user.
+                   // TRANS: %s is a user's nickname.
+                   'title' => sprintf(_("%s's bookmarks"), $user->nickname),
+                   'link' => common_local_url('bookmarks',
+                                        array('nickname' =>
+                                        $user->nickname)),
+                   // TRANS: Desciption of RSS feed with bookmarks of a user.
+                   // TRANS: %1$s is a user's nickname, %2$s is the name of the StatusNet site.
+                   'description' => sprintf(_('Bookmarks posted by %1$s on %2$s!'),
+                                        $user->nickname, common_config('site', 'name')));
+        return $c;
+    }
+
+    /**
+     * Get image.
+     *
+     * @return void
+    */
+    function getImage()
+    {
+        return null;
+    }
+
+}
index 7c9a4d14739bc23b7d7ed369064046efc1ea9d55..1d7a84d9f3dffad7e3c485638eacd4b3c78ba155 100644 (file)
@@ -31,6 +31,15 @@ class RemoteProfileAction extends ShowstreamAction
         $this->tag = $this->trimmed('tag');
         $this->page = ($this->arg('page')) ? ($this->arg('page')+0) : 1;
         common_set_returnto($this->selfUrl());
+
+        $p = Profile::current();
+        if (empty($this->tag)) {
+            $stream = new ProfileNoticeStream($this->profile, $p);
+        } else {
+            $stream = new TaggedProfileNoticeStream($this->profile, $this->tag, $p);
+        }
+        $this->notice = $stream->getNotices(($this->page-1)*NOTICES_PER_PAGE, NOTICES_PER_PAGE + 1);
+
         return true;
     }
 
@@ -71,6 +80,25 @@ class RemoteProfileAction extends ShowstreamAction
             // TRANS: Message on blocked remote profile page.
             $markdown = _m('Site moderators have silenced this profile, which prevents delivery of new messages to any users on this site.');
             $this->raw(common_markup_to_html($markdown));
+        }else{
+
+            $pnl = null;
+            if (Event::handle('ShowStreamNoticeList', array($this->notice, $this, &$pnl))) {
+                $pnl = new ProfileNoticeList($this->notice, $this);
+            }
+            $cnt = $pnl->show();
+            if (0 == $cnt) {
+                $this->showEmptyListMessage();
+            }
+
+            $args = array('id' => $this->profile->id);
+            if (!empty($this->tag))
+            {
+                $args['tag'] = $this->tag;
+            }
+            $this->pagination($this->page>1, $cnt>NOTICES_PER_PAGE, $this->page,
+                              'remoteprofile', $args);
+
         }
     }
 
@@ -90,14 +118,12 @@ class RemoteProfileAction extends ShowstreamAction
 
     function showLocalNav()
     {
-        $nav = new PublicGroupNav($this);
-        $nav->show();
+        // skip
     }
 
     function showSections()
     {
-        ProfileAction::showSections();
-        // skip tag cloud
+        // skip
     }
 
     function showStatistics()
index 25d8a423ca403a960fe39a51f6a368364c21663f..cae0dbfcac889144c14abef0fcff31c496c983f5 100644 (file)
@@ -204,6 +204,7 @@ class TwitterBridgePlugin extends Plugin
             return false;
         case 'TwitterOAuthClient':
         case 'TwitterQueueHandler':
+        case 'TweetInQueueHandler':
         case 'TwitterImport':
         case 'JsonStreamReader':
         case 'TwitterStreamReader':
index 06ce430371858b364d22c7fa819278f18146f504..47a44597be532add9a8d5418c15a794fb0fa721f 100755 (executable)
@@ -136,7 +136,8 @@ class TwitterStatusFetcher extends ParallelizingDaemon
         // a new connection if there isn't one already
         $conn = &$flink->getDatabaseConnection();
 
-        $this->getTimeline($flink);
+        $this->getTimeline($flink, 'home_timeline');
+        $this->getTimeline($flink, 'mentions_timeline');
 
         $flink->last_friendsync = common_sql_now();
         $flink->update();
@@ -149,65 +150,68 @@ class TwitterStatusFetcher extends ParallelizingDaemon
         unset($_DB_DATAOBJECT['CONNECTIONS']);
     }
 
-    function getTimeline($flink)
+    function getTimeline($flink, $timelineUri = 'home_timeline')
     {
         if (empty($flink)) {
-            common_log(LOG_WARNING, $this->name() .
+            common_log(LOG_ERR, $this->name() .
                        " - Can't retrieve Foreign_link for foreign ID $fid");
             return;
         }
 
-        common_debug($this->name() . ' - Trying to get timeline for Twitter user ' .
-                     $flink->foreign_id);
+        common_log(LOG_DEBUG, $this->name() . ' - Trying to get ' . $timelineUri .
+                   ' timeline for Twitter user ' . $flink->foreign_id);
 
         $client = null;
 
         if (TwitterOAuthClient::isPackedToken($flink->credentials)) {
             $token = TwitterOAuthClient::unpackToken($flink->credentials);
             $client = new TwitterOAuthClient($token->key, $token->secret);
-            common_debug($this->name() . ' - Grabbing friends timeline with OAuth.');
+            common_log(LOG_DEBUG, $this->name() . ' - Grabbing ' . $timelineUri . ' timeline with OAuth.');
         } else {
-            common_debug("Skipping friends timeline for $flink->foreign_id since not OAuth.");
+            common_log(LOG_ERR, "Skipping " . $timelineUri . " timeline for " .
+                       $flink->foreign_id . " since not OAuth.");
         }
 
         $timeline = null;
 
-        $lastId = Twitter_synch_status::getLastId($flink->foreign_id, 'home_timeline');
+        $lastId = Twitter_synch_status::getLastId($flink->foreign_id, $timelineUri);
 
-        common_debug("Got lastId value '{$lastId}' for foreign id '{$flink->foreign_id}' and timeline 'home_timeline'");
+        common_log(LOG_DEBUG, "Got lastId value '" . $lastId . "' for foreign id '" .
+                     $flink->foreign_id . "' and timeline '" . $timelineUri. "'");
 
         try {
-            $timeline = $client->statusesHomeTimeline($lastId);
+            $timeline = $client->statusesTimeline($lastId, $timelineUri);
         } catch (Exception $e) {
-            common_log(LOG_WARNING, $this->name() .
-                       ' - Twitter client unable to get friends timeline for user ' .
-                       $flink->user_id . ' - code: ' .
-                       $e->getCode() . 'msg: ' . $e->getMessage());
+            common_log(LOG_ERR, $this->name() .
+                       ' - Unable to get ' . $timelineUri . ' timeline for user ' . $flink->user_id .
+                       ' - code: ' . $e->getCode() . 'msg: ' . $e->getMessage());
         }
 
         if (empty($timeline)) {
-            common_log(LOG_WARNING, $this->name() .  " - Empty timeline.");
+            common_log(LOG_WARNING, $this->name() .  " - Empty '" . $timelineUri . "' timeline.");
             return;
         }
 
-        common_debug(LOG_INFO, $this->name() . ' - Retrieved ' . sizeof($timeline) . ' statuses from Twitter.');
+        common_log(LOG_INFO, $this->name() .
+                   ' - Retrieved ' . sizeof($timeline) . ' statuses from ' . $timelineUri . ' timeline' .
+                   ' - for user ' . $flink->user_id);
 
-        $importer = new TwitterImport();
-
-        // Reverse to preserve order
-
-        foreach (array_reverse($timeline) as $status) {
-            $notice = $importer->importStatus($status);
-
-            if (!empty($notice)) {
-                Inbox::insertNotice($flink->user_id, $notice->id);
+        if (!empty($timeline)) {
+            $qm = QueueManager::get();
+
+            // Reverse to preserve order
+            foreach (array_reverse($timeline) as $status) {
+                $data = array(
+                    'status' => $status,
+                    'for_user' => $flink->foreign_id,
+                );
+                $qm->enqueue($data, 'tweetin');
             }
-        }
 
-        if (!empty($timeline)) {
             $lastId = twitter_id($timeline[0]);
-            Twitter_synch_status::setLastId($flink->foreign_id, 'home_timeline', $lastId);
-            common_debug("Set lastId value '$lastId' for foreign id '{$flink->foreign_id}' and timeline 'home_timeline'");
+            Twitter_synch_status::setLastId($flink->foreign_id, $timelineUri, $lastId);
+            common_debug("Set lastId value '$lastId' for foreign id '{$flink->foreign_id}' and timeline '" .
+                         $timelineUri . "'");
         }
 
         // Okay, record the time we synced with Twitter for posterity
@@ -233,5 +237,5 @@ if (have_option('d') || have_option('debug')) {
     $debug = true;
 }
 
-$fetcher = new TwitterStatusFetcher($id, 60, 2, $debug);
+$fetcher = new TwitterStatusFetcher($id, POLL_INTERVAL, MAXCHILDREN, $debug);
 $fetcher->runOnce();
index ff6b2cc861336f51ea4574a0466918f4d9e1c2c3..7f34ade23b8c5f1d58ecf7a10e5ea327efa9ce27 100644 (file)
@@ -51,10 +51,14 @@ class TweetInQueueHandler extends QueueHandler
         $importer = new TwitterImport();
         $notice = $importer->importStatus($status);
         if ($notice) {
-            $flink = Foreign_link::getByForeignID(TWITTER_SERVICE, $receiver);
+            $flink = Foreign_link::getByForeignID($receiver, TWITTER_SERVICE);
             if ($flink) {
+                common_log(LOG_DEBUG, "TweetInQueueHandler - Got flink so add notice ".
+                           $notice->id." to inbox ".$flink->user_id);
                 // @fixme this should go through more regular channels?
                 Inbox::insertNotice($flink->user_id, $notice->id);
+            }else {
+               common_log(LOG_DEBUG, "TweetInQueueHandler - No flink found for foreign user ".$receiver);
             }
         }
 
index e3b51c0908b6f509513fa8eafff820b2a8384d8d..dc7277caf9168931fe519a075cc70306aa174065 100644 (file)
@@ -339,10 +339,7 @@ class TwitterImport
     {
         global $config;
 
-        $path_parts = pathinfo($twitter_user->profile_image_url);
-
-        $newname = 'Twitter_' . $twitter_user->id . '_' .
-            $path_parts['basename'];
+        $newname = 'Twitter_' . $twitter_user->id . '_' . basename($twitter_user->profile_image_url);
 
         $oldname = $profile->getAvatar(48)->filename;
 
@@ -370,15 +367,15 @@ class TwitterImport
 
         $path_parts = pathinfo($twitter_user->profile_image_url);
 
-        $img_root = substr($path_parts['basename'], 0, -11);
-        $ext = $path_parts['extension'];
-        $mediatype = $this->getMediatype($ext);
+        $ext = (isset($path_parts['extension']) ? '.'.$path_parts['extension'] : '');  // some lack extension
+        $img_root = basename($path_parts['basename'], '_normal'.$ext); // cut off extension
+        $mediatype = $this->getMediatype(substr($ext, 1));
 
         foreach (array('mini', 'normal', 'bigger') as $size) {
             $url = $path_parts['dirname'] . '/' .
-                $img_root . '_' . $size . ".$ext";
+                $img_root . '_' . $size . $ext;
             $filename = 'Twitter_' . $twitter_user->id . '_' .
-                $img_root . "_$size.$ext";
+                $img_root . '_' . $size . $ext;
 
             $this->updateAvatar($profile->id, $size, $mediatype, $filename);
             $this->fetchAvatar($url, $filename);
@@ -401,8 +398,9 @@ class TwitterImport
         $mediatype = null;
 
         switch (strtolower($ext)) {
+        case 'jpeg':
         case 'jpg':
-            $mediatype = 'image/jpg';
+            $mediatype = 'image/jpeg';
             break;
         case 'gif':
             $mediatype = 'image/gif';
@@ -419,16 +417,15 @@ class TwitterImport
         global $config;
 
         $path_parts = pathinfo($user->profile_image_url);
-        $ext = $path_parts['extension'];
-        $end = strlen('_normal' . $ext);
-        $img_root = substr($path_parts['basename'], 0, -($end+1));
-        $mediatype = $this->getMediatype($ext);
+        $ext = (isset($path_parts['extension']) ? '.'.$path_parts['extension'] : '');
+        $img_root = basename($path_parts['basename'], '_normal'.$ext);
+        $mediatype = $this->getMediatype(substr($ext, 1));
 
         foreach (array('mini', 'normal', 'bigger') as $size) {
             $url = $path_parts['dirname'] . '/' .
-                $img_root . '_' . $size . ".$ext";
+                $img_root . '_' . $size . $ext;
             $filename = 'Twitter_' . $user->id . '_' .
-                $img_root . "_$size.$ext";
+                $img_root . '_' . $size . $ext;
 
             if ($this->fetchAvatar($url, $filename)) {
                 $this->newAvatar($id, $size, $mediatype, $filename);
index a17911b03eb062623e9c4bb2e5a807d4938bcd23..720844211a0af26030a0b608a5ebcbdbb45c7a3b 100644 (file)
@@ -157,7 +157,7 @@ class TwitterOAuthClient extends OAuthClient
      */
     function verifyCredentials()
     {
-        $url          = 'https://api.twitter.com/1/account/verify_credentials.json';
+        $url          = 'https://api.twitter.com/1.1/account/verify_credentials.json';
         $response     = $this->oAuthGet($url);
         $twitter_user = json_decode($response);
         return $twitter_user;
@@ -175,7 +175,7 @@ class TwitterOAuthClient extends OAuthClient
      */
     function statusesUpdate($status, $params=array())
     {
-        $url      = 'https://api.twitter.com/1/statuses/update.json';
+        $url      = 'https://api.twitter.com/1.1/statuses/update.json';
         if (is_numeric($params)) {
             $params = array('in_reply_to_status_id' => intval($params));
         }
@@ -190,19 +190,21 @@ class TwitterOAuthClient extends OAuthClient
     /**
      * Calls Twitter's /statuses/home_timeline API method
      *
-     * @param int $since_id show statuses after this id
-     * @param int $max_id   show statuses before this id
-     * @param int $cnt      number of statuses to show
-     * @param int $page     page number
+     * @param int    $since_id    show statuses after this id
+     * @param string $timelineUri timeline to poll statuses from
+     * @param int    $max_id      show statuses before this id
+     * @param int    $cnt         number of statuses to show
+     * @param int    $page        page number
      *
      * @return mixed an array of statuses
      */
-    function statusesHomeTimeline($since_id = null, $max_id = null,
-                                  $cnt = null, $page = null)
+    function statusesTimeline($since_id = null, $timelineUri = 'home_timeline',
+                              $max_id = null, $cnt = 200, $page = null)
     {
-        $url    = 'https://api.twitter.com/1/statuses/home_timeline.json';
+        $url    = 'https://api.twitter.com/1.1/statuses/'.$timelineUri.'.json';
 
-        $params = array('include_entities' => 'true');
+        $params = array('include_entities' => 'true',
+                        'include_rts'      => 'true');
 
         if (!empty($since_id)) {
             $params['since_id'] = $since_id;
@@ -235,7 +237,7 @@ class TwitterOAuthClient extends OAuthClient
     function statusesFriends($id = null, $user_id = null, $screen_name = null,
                              $page = null)
     {
-        $url = "https://api.twitter.com/1/statuses/friends.json";
+        $url = "https://api.twitter.com/1.1/friends/list.json";
 
         $params = array();
 
@@ -273,7 +275,7 @@ class TwitterOAuthClient extends OAuthClient
     function friendsIds($id = null, $user_id = null, $screen_name = null,
                          $page = null)
     {
-        $url = "https://api.twitter.com/1/friends/ids.json";
+        $url = "https://api.twitter.com/1.1/friends/ids.json";
 
         $params = array();
 
@@ -308,7 +310,7 @@ class TwitterOAuthClient extends OAuthClient
 
     function statusesRetweet($id)
     {
-        $url = "http://api.twitter.com/1/statuses/retweet/$id.json";
+        $url = "http://api.twitter.com/1.1/statuses/retweet/$id.json";
         $response = $this->oAuthPost($url);
         $status = json_decode($response);
         return $status;
@@ -324,8 +326,10 @@ class TwitterOAuthClient extends OAuthClient
 
     function favoritesCreate($id)
     {
-        $url = "http://api.twitter.com/1/favorites/create/$id.json";
-        $response = $this->oAuthPost($url);
+        $url = "http://api.twitter.com/1.1/favorites/create.json";
+        $params=array();
+        $params['id'] = $id;
+        $response = $this->oAuthPost($url, $params);
         $status = json_decode($response);
         return $status;
     }
@@ -340,8 +344,10 @@ class TwitterOAuthClient extends OAuthClient
 
     function favoritesDestroy($id)
     {
-        $url = "http://api.twitter.com/1/favorites/destroy/$id.json";
-        $response = $this->oAuthPost($url);
+        $url = "http://api.twitter.com/1.1/favorites/destroy.json";
+        $params=array();
+        $params['id'] = $id;
+        $response = $this->oAuthPost($url,$params);
         $status = json_decode($response);
         return $status;
     }
@@ -356,7 +362,7 @@ class TwitterOAuthClient extends OAuthClient
 
     function statusesDestroy($id)
     {
-        $url = "http://api.twitter.com/1/statuses/destroy/$id.json";
+        $url = "http://api.twitter.com/1.1/statuses/destroy/$id.json";
         $response = $this->oAuthPost($url);
         $status = json_decode($response);
         return $status;
index 0f82ed041c8685ba5461ca9f910b5ea2a34e21c4..74e104d974b2785c5473f969ddc965571333abfb 100644 (file)
@@ -433,6 +433,31 @@ class XmppPlugin extends ImPlugin
                                     );
     }
 
+    /**
+     * Add XMPP plugin daemon to the list of daemon to start
+     *
+     * @param array $daemons the list of daemons to run
+     *
+     * @return boolean hook return
+     */
+    function onGetValidDaemons($daemons)
+    {
+        if( isset($this->server) &&
+            isset($this->port)   &&
+            isset($this->user)   &&
+            isset($this->password) ){
+
+            array_push(
+                $daemons,
+                INSTALLDIR
+                . '/scripts/imdaemon.php'
+            );
+        }
+
+        return true;
+    }
+
+
     function onPluginVersion(&$versions)
     {
         $versions[] = array('name' => 'XMPP',
index 80c21bce581c3c0dcb65cc60b52f0985e4ef329c..78cbba8c079fbe3a1f01a05602a7eb99d0c9bc48 100755 (executable)
@@ -39,8 +39,6 @@ $daemons = array();
 
 $daemons[] = INSTALLDIR.'/scripts/queuedaemon.php';
 
-$daemons[] = INSTALLDIR.'/scripts/imdaemon.php';
-
 if (Event::handle('GetValidDaemons', array(&$daemons))) {
     foreach ($daemons as $daemon) {
         print $daemon . ' ';
index 483aa15ff7594651c8c5e1fe4d0ddcfae18c4f40..b73078295e757b6e5a9ea9bb2b3be9a874dde486 100644 (file)
@@ -688,18 +688,22 @@ font-style:italic;
     display:none;
 }
 
+#remoteprofile .notice .entry-title, #remoteprofile .notice div.entry-content,
 #showstream .notice .entry-title, #showstream .notice div.entry-content {
     margin-left: 0;
 }
 
+#remoteprofile .notice .entry-title,
 #showstream .notice .entry-title {
     min-height: 1px;
 }
 
+#remoteprofile #content .notice .author,
 #showstream #content .notice .author {
     display: none;
 }
 
+#remoteprofile .notice,
 #showstream .notice {
     min-height: 1em; 
 }