Merge branch '0.9.x' into noactor
This commit is contained in:
		
							
								
								
									
										22
									
								
								EVENTS.txt
									
									
									
									
									
								
							
							
						
						
									
										22
									
								
								EVENTS.txt
									
									
									
									
									
								
							@@ -969,9 +969,12 @@ EndRevokeRole: when a role has been revoked
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
StartAtomPubNewActivity: When a new activity comes in through Atom Pub API
 | 
					StartAtomPubNewActivity: When a new activity comes in through Atom Pub API
 | 
				
			||||||
- &$activity: received activity
 | 
					- &$activity: received activity
 | 
				
			||||||
 | 
					- $user: user publishing the entry
 | 
				
			||||||
 | 
					- &$notice: notice created; initially null, can be set
 | 
				
			||||||
 | 
					
 | 
				
			||||||
EndAtomPubNewActivity: When a new activity comes in through Atom Pub API
 | 
					EndAtomPubNewActivity: When a new activity comes in through Atom Pub API
 | 
				
			||||||
- $activity: received activity
 | 
					- $activity: received activity
 | 
				
			||||||
 | 
					- $user: user publishing the entry
 | 
				
			||||||
- $notice: notice that was created
 | 
					- $notice: notice that was created
 | 
				
			||||||
 | 
					
 | 
				
			||||||
StartXrdActionAliases: About to set aliases for the XRD object for a user
 | 
					StartXrdActionAliases: About to set aliases for the XRD object for a user
 | 
				
			||||||
@@ -1023,3 +1026,22 @@ StartActivityObjectFromGroup: When converting a group to an activity:object
 | 
				
			|||||||
EndActivityObjectFromGroup:  After converting a group to an activity:object
 | 
					EndActivityObjectFromGroup:  After converting a group to an activity:object
 | 
				
			||||||
- $group:  The group being converted
 | 
					- $group:  The group being converted
 | 
				
			||||||
- &$object: The finished object. Tweak as needed.
 | 
					- &$object: The finished object. Tweak as needed.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					StartImportActivity: when we start to import an activity
 | 
				
			||||||
 | 
					- $user: User to make the author import
 | 
				
			||||||
 | 
					- $author: Author of the feed; good for comparisons
 | 
				
			||||||
 | 
					- $activity: The current activity
 | 
				
			||||||
 | 
					- $trusted: How "trusted" the process is
 | 
				
			||||||
 | 
					- &$done: Return value; whether to continue
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					EndImportActivity: when we finish importing an activity
 | 
				
			||||||
 | 
					- $user: User to make the author import
 | 
				
			||||||
 | 
					- $author: Author of the feed; good for comparisons
 | 
				
			||||||
 | 
					- $activity: The current activity
 | 
				
			||||||
 | 
					- $trusted: How "trusted" the process is
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					StartProfileSettingsActions: when we're showing account-management action list
 | 
				
			||||||
 | 
					- $action: Action being shown (use for output)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					EndProfileSettingsActions: when we're showing account-management action list
 | 
				
			||||||
 | 
					- $action: Action being shown (use for output)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -324,7 +324,9 @@ class ApiTimelineUserAction extends ApiBareAuthAction
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        $activity = new Activity($dom->documentElement);
 | 
					        $activity = new Activity($dom->documentElement);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (Event::handle('StartAtomPubNewActivity', array(&$activity))) {
 | 
					        $saved = null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (Event::handle('StartAtomPubNewActivity', array(&$activity, $this->user, &$saved))) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if ($activity->verb != ActivityVerb::POST) {
 | 
					            if ($activity->verb != ActivityVerb::POST) {
 | 
				
			||||||
                // TRANS: Client error displayed when not using the POST verb.
 | 
					                // TRANS: Client error displayed when not using the POST verb.
 | 
				
			||||||
@@ -347,7 +349,7 @@ class ApiTimelineUserAction extends ApiBareAuthAction
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            $saved = $this->postNote($activity);
 | 
					            $saved = $this->postNote($activity);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            Event::handle('EndAtomPubNewActivity', array($activity, $saved));
 | 
					            Event::handle('EndAtomPubNewActivity', array($activity, $this->user, $saved));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (!empty($saved)) {
 | 
					        if (!empty($saved)) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -66,6 +66,13 @@ class NewgroupAction extends Action
 | 
				
			|||||||
            return false;
 | 
					            return false;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $user = common_current_user();
 | 
				
			||||||
 | 
					        $profile = $user->getProfile();
 | 
				
			||||||
 | 
					        if (!$profile->hasRight(Right::CREATEGROUP)) {
 | 
				
			||||||
 | 
					            // TRANS: Client exception thrown when a user tries to create a group while banned.
 | 
				
			||||||
 | 
					            throw new ClientException(_('You are not allowed to create groups on this site.'), 403);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return true;
 | 
					        return true;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -458,6 +458,8 @@ class ProfilesettingsAction extends AccountSettingsAction
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        $this->elementStart('div', array('id' => 'aside_primary',
 | 
					        $this->elementStart('div', array('id' => 'aside_primary',
 | 
				
			||||||
                                         'class' => 'aside'));
 | 
					                                         'class' => 'aside'));
 | 
				
			||||||
 | 
					        $this->elementStart('ul');
 | 
				
			||||||
 | 
					        if (Event::handle('StartProfileSettingsActions', array($this))) {
 | 
				
			||||||
            if ($user->hasRight(Right::BACKUPACCOUNT)) {
 | 
					            if ($user->hasRight(Right::BACKUPACCOUNT)) {
 | 
				
			||||||
                $this->elementStart('li');
 | 
					                $this->elementStart('li');
 | 
				
			||||||
                $this->element('a',
 | 
					                $this->element('a',
 | 
				
			||||||
@@ -479,6 +481,9 @@ class ProfilesettingsAction extends AccountSettingsAction
 | 
				
			|||||||
                               _('Restore account'));
 | 
					                               _('Restore account'));
 | 
				
			||||||
                $this->elementEnd('li');
 | 
					                $this->elementEnd('li');
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					            Event::handle('EndProfileSettingsActions', array($this));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        $this->elementEnd('ul');
 | 
				
			||||||
        $this->elementEnd('div');
 | 
					        $this->elementEnd('div');
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -412,4 +412,102 @@ class File extends Memcached_DataObject
 | 
				
			|||||||
    {
 | 
					    {
 | 
				
			||||||
        return File_thumbnail::staticGet('file_id', $this->id);
 | 
					        return File_thumbnail::staticGet('file_id', $this->id);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Blow the cache of notices that link to this URL
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param boolean $last Whether to blow the "last" cache too
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return void
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function blowCache($last=false)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        self::blow('file:notice-ids:%s', $this->url);
 | 
				
			||||||
 | 
					        if ($last) {
 | 
				
			||||||
 | 
					            self::blow('file:notice-ids:%s;last', $this->url);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        self::blow('file:notice-count:%d', $this->id);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Stream of notices linking to this URL
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param integer $offset   Offset to show; default is 0
 | 
				
			||||||
 | 
					     * @param integer $limit    Limit of notices to show
 | 
				
			||||||
 | 
					     * @param integer $since_id Since this notice
 | 
				
			||||||
 | 
					     * @param integer $max_id   Before this notice
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return array ids of notices that link to this file
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function stream($offset=0, $limit=NOTICES_PER_PAGE, $since_id=0, $max_id=0)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $ids = Notice::stream(array($this, '_streamDirect'),
 | 
				
			||||||
 | 
					                              array(),
 | 
				
			||||||
 | 
					                              'file:notice-ids:'.$this->url,
 | 
				
			||||||
 | 
					                              $offset, $limit, $since_id, $max_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return Notice::getStreamByIds($ids);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Stream of notices linking to this URL
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param integer $offset   Offset to show; default is 0
 | 
				
			||||||
 | 
					     * @param integer $limit    Limit of notices to show
 | 
				
			||||||
 | 
					     * @param integer $since_id Since this notice
 | 
				
			||||||
 | 
					     * @param integer $max_id   Before this notice
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return array ids of notices that link to this file
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function _streamDirect($offset, $limit, $since_id, $max_id)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $f2p = new File_to_post();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $f2p->selectAdd();
 | 
				
			||||||
 | 
					        $f2p->selectAdd('post_id');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $f2p->file_id = $this->id;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Notice::addWhereSinceId($f2p, $since_id, 'post_id', 'modified');
 | 
				
			||||||
 | 
					        Notice::addWhereMaxId($f2p, $max_id, 'post_id', 'modified');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $f2p->orderBy('modified DESC, post_id DESC');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (!is_null($offset)) {
 | 
				
			||||||
 | 
					            $f2p->limit($offset, $limit);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $ids = array();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if ($f2p->find()) {
 | 
				
			||||||
 | 
					            while ($f2p->fetch()) {
 | 
				
			||||||
 | 
					                $ids[] = $f2p->post_id;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return $ids;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function noticeCount()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $cacheKey = sprintf('file:notice-count:%d', $this->id);
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        $count = self::cacheGet($cacheKey);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if ($count === false) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            $f2p = new File_to_post();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            $f2p->file_id = $this->id;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            $count = $f2p->count();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            self::cacheSet($cacheKey, $count);
 | 
				
			||||||
 | 
					        } 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return $count;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -52,6 +52,12 @@ class File_to_post extends Memcached_DataObject
 | 
				
			|||||||
                $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::staticGet($file_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if (!empty($f)) {
 | 
				
			||||||
 | 
					                    $f->blowCache();
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (empty($seen[$notice_id])) {
 | 
					            if (empty($seen[$notice_id])) {
 | 
				
			||||||
@@ -66,4 +72,13 @@ class File_to_post extends Memcached_DataObject
 | 
				
			|||||||
    {
 | 
					    {
 | 
				
			||||||
        return Memcached_DataObject::pkeyGet('File_to_post', $kv);
 | 
					        return Memcached_DataObject::pkeyGet('File_to_post', $kv);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function delete()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $f = File::staticGet('id', $this->file_id);
 | 
				
			||||||
 | 
					        if (!empty($f)) {
 | 
				
			||||||
 | 
					            $f->blowCache();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return parent::delete();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -74,7 +74,7 @@ class Memcached_DataObject extends Safe_DataObject
 | 
				
			|||||||
            return $i;
 | 
					            return $i;
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            $i = DB_DataObject::factory($cls);
 | 
					            $i = DB_DataObject::factory($cls);
 | 
				
			||||||
            if (empty($i)) {
 | 
					            if (empty($i) || PEAR::isError($i)) {
 | 
				
			||||||
                return false;
 | 
					                return false;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            foreach ($kv as $k => $v) {
 | 
					            foreach ($kv as $k => $v) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -109,6 +109,11 @@ class Notice extends Memcached_DataObject
 | 
				
			|||||||
        // @fixme we have some cases where things get re-run and so the
 | 
					        // @fixme we have some cases where things get re-run and so the
 | 
				
			||||||
        // insert fails.
 | 
					        // insert fails.
 | 
				
			||||||
        $deleted = Deleted_notice::staticGet('id', $this->id);
 | 
					        $deleted = Deleted_notice::staticGet('id', $this->id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (!$deleted) {
 | 
				
			||||||
 | 
					            $deleted = Deleted_notice::staticGet('uri', $this->uri);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (!$deleted) {
 | 
					        if (!$deleted) {
 | 
				
			||||||
            $deleted = new Deleted_notice();
 | 
					            $deleted = new Deleted_notice();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -130,6 +135,7 @@ class Notice extends Memcached_DataObject
 | 
				
			|||||||
            $this->clearFaves();
 | 
					            $this->clearFaves();
 | 
				
			||||||
            $this->clearTags();
 | 
					            $this->clearTags();
 | 
				
			||||||
            $this->clearGroupInboxes();
 | 
					            $this->clearGroupInboxes();
 | 
				
			||||||
 | 
					            $this->clearFiles();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // NOTE: we don't clear inboxes
 | 
					            // NOTE: we don't clear inboxes
 | 
				
			||||||
            // NOTE: we don't clear queue items
 | 
					            // NOTE: we don't clear queue items
 | 
				
			||||||
@@ -1780,6 +1786,21 @@ class Notice extends Memcached_DataObject
 | 
				
			|||||||
        $reply->free();
 | 
					        $reply->free();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function clearFiles()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $f2p = new File_to_post();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $f2p->post_id = $this->id;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if ($f2p->find()) {
 | 
				
			||||||
 | 
					            while ($f2p->fetch()) {
 | 
				
			||||||
 | 
					                $f2p->delete();
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        // FIXME: decide whether to delete File objects
 | 
				
			||||||
 | 
					        // ...and related (actual) files
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    function clearRepeats()
 | 
					    function clearRepeats()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $repeatNotice = new Notice();
 | 
					        $repeatNotice = new Notice();
 | 
				
			||||||
@@ -2033,7 +2054,7 @@ class Notice extends Memcached_DataObject
 | 
				
			|||||||
     */
 | 
					     */
 | 
				
			||||||
    public static function addWhereSinceId(DB_DataObject $obj, $id, $idField='id', $createdField='created')
 | 
					    public static function addWhereSinceId(DB_DataObject $obj, $id, $idField='id', $createdField='created')
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $since = self::whereSinceId($id);
 | 
					        $since = self::whereSinceId($id, $idField, $createdField);
 | 
				
			||||||
        if ($since) {
 | 
					        if ($since) {
 | 
				
			||||||
            $obj->whereAdd($since);
 | 
					            $obj->whereAdd($since);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@@ -2072,7 +2093,7 @@ class Notice extends Memcached_DataObject
 | 
				
			|||||||
     */
 | 
					     */
 | 
				
			||||||
    public static function addWhereMaxId(DB_DataObject $obj, $id, $idField='id', $createdField='created')
 | 
					    public static function addWhereMaxId(DB_DataObject $obj, $id, $idField='id', $createdField='created')
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $max = self::whereMaxId($id);
 | 
					        $max = self::whereMaxId($id, $idField, $createdField);
 | 
				
			||||||
        if ($max) {
 | 
					        if ($max) {
 | 
				
			||||||
            $obj->whereAdd($max);
 | 
					            $obj->whereAdd($max);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -87,4 +87,19 @@ class Notice_tag extends Memcached_DataObject
 | 
				
			|||||||
    {
 | 
					    {
 | 
				
			||||||
        return Memcached_DataObject::pkeyGet('Notice_tag', $kv);
 | 
					        return Memcached_DataObject::pkeyGet('Notice_tag', $kv);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static function url($tag)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							if (common_config('singleuser', 'enabled')) {
 | 
				
			||||||
 | 
								// regular TagAction isn't set up in 1user mode
 | 
				
			||||||
 | 
								$nickname = User::singleUserNickname();
 | 
				
			||||||
 | 
								$url = common_local_url('showstream',
 | 
				
			||||||
 | 
														array('nickname' => $nickname,
 | 
				
			||||||
 | 
															  'tag' => $tag));
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								$url = common_local_url('tag', array('tag' => $tag));
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return $url;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -850,6 +850,7 @@ class Profile extends Memcached_DataObject
 | 
				
			|||||||
            case Right::NEWNOTICE:
 | 
					            case Right::NEWNOTICE:
 | 
				
			||||||
            case Right::NEWMESSAGE:
 | 
					            case Right::NEWMESSAGE:
 | 
				
			||||||
            case Right::SUBSCRIBE:
 | 
					            case Right::SUBSCRIBE:
 | 
				
			||||||
 | 
					            case Right::CREATEGROUP:
 | 
				
			||||||
                $result = !$this->isSilenced();
 | 
					                $result = !$this->isSilenced();
 | 
				
			||||||
                break;
 | 
					                break;
 | 
				
			||||||
            case Right::PUBLICNOTICE:
 | 
					            case Right::PUBLICNOTICE:
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -476,6 +476,16 @@ class User_group extends Memcached_DataObject
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    static function register($fields) {
 | 
					    static function register($fields) {
 | 
				
			||||||
 | 
					        if (!empty($fields['userid'])) {
 | 
				
			||||||
 | 
					            $profile = Profile::staticGet('id', $fields['userid']);
 | 
				
			||||||
 | 
					            if ($profile && !$profile->hasRight(Right::CREATEGROUP)) {
 | 
				
			||||||
 | 
					                common_log(LOG_WARNING, "Attempted group creation from banned user: " . $profile->nickname);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                // TRANS: Client exception thrown when a user tries to create a group while banned.
 | 
				
			||||||
 | 
					                throw new ClientException(_('You are not allowed to create groups on this site.'), 403);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // MAGICALLY put fields into current scope
 | 
					        // MAGICALLY put fields into current scope
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        extract($fields);
 | 
					        extract($fields);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -63,6 +63,11 @@ class ActivityImporter extends QueueHandler
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        $this->trusted = $trusted;
 | 
					        $this->trusted = $trusted;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $done = null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (Event::handle('StartImportActivity', 
 | 
				
			||||||
 | 
					                          array($user, $author, $activity, $trusted, &$done))) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            try {
 | 
					            try {
 | 
				
			||||||
                switch ($activity->verb) {
 | 
					                switch ($activity->verb) {
 | 
				
			||||||
                case ActivityVerb::FOLLOW:
 | 
					                case ActivityVerb::FOLLOW:
 | 
				
			||||||
@@ -75,19 +80,23 @@ class ActivityImporter extends QueueHandler
 | 
				
			|||||||
                    $this->postNote($user, $author, $activity);
 | 
					                    $this->postNote($user, $author, $activity);
 | 
				
			||||||
                    break;
 | 
					                    break;
 | 
				
			||||||
                default:
 | 
					                default:
 | 
				
			||||||
                throw new Exception("Unknown verb: {$activity->verb}");
 | 
					                    throw new ClientException("Unknown verb: {$activity->verb}");
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					                Event::handle('EndImportActivity', 
 | 
				
			||||||
 | 
					                              array($user, $author, $activity, $trusted));
 | 
				
			||||||
 | 
					                $done = true;
 | 
				
			||||||
            } catch (ClientException $ce) {
 | 
					            } catch (ClientException $ce) {
 | 
				
			||||||
                common_log(LOG_WARNING, $ce->getMessage());
 | 
					                common_log(LOG_WARNING, $ce->getMessage());
 | 
				
			||||||
            return true;
 | 
					                $done = true;
 | 
				
			||||||
            } catch (ServerException $se) {
 | 
					            } catch (ServerException $se) {
 | 
				
			||||||
                common_log(LOG_ERR, $se->getMessage());
 | 
					                common_log(LOG_ERR, $se->getMessage());
 | 
				
			||||||
            return false;
 | 
					                $done = false;
 | 
				
			||||||
            } catch (Exception $e) {
 | 
					            } catch (Exception $e) {
 | 
				
			||||||
                common_log(LOG_ERR, $e->getMessage());
 | 
					                common_log(LOG_ERR, $e->getMessage());
 | 
				
			||||||
            return false;
 | 
					                $done = false;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        return true;
 | 
					        }
 | 
				
			||||||
 | 
					        return $done;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    function subscribeProfile($user, $author, $activity)
 | 
					    function subscribeProfile($user, $author, $activity)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -299,6 +299,10 @@ class oEmbedHelper
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
class oEmbedHelper_Exception extends Exception
 | 
					class oEmbedHelper_Exception extends Exception
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					    public function __construct($message = "", $code = 0, $previous = null)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        parent::__construct($message, $code);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class oEmbedHelper_BadHtmlException extends oEmbedHelper_Exception
 | 
					class oEmbedHelper_BadHtmlException extends oEmbedHelper_Exception
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -65,5 +65,6 @@ class Right
 | 
				
			|||||||
    const RESTOREACCOUNT     = 'restoreaccount';
 | 
					    const RESTOREACCOUNT     = 'restoreaccount';
 | 
				
			||||||
    const DELETEACCOUNT      = 'deleteaccount';
 | 
					    const DELETEACCOUNT      = 'deleteaccount';
 | 
				
			||||||
    const MOVEACCOUNT        = 'moveaccount';
 | 
					    const MOVEACCOUNT        = 'moveaccount';
 | 
				
			||||||
 | 
					    const CREATEGROUP        = 'creategroup';
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										351
									
								
								plugins/Bookmark/Bookmark.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										351
									
								
								plugins/Bookmark/Bookmark.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,351 @@
 | 
				
			|||||||
 | 
					<?php
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Data class to mark notices as bookmarks
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * PHP version 5
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @category Data
 | 
				
			||||||
 | 
					 * @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);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * For storing the fact that a notice is a bookmark
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @category Bookmark
 | 
				
			||||||
 | 
					 * @package  StatusNet
 | 
				
			||||||
 | 
					 * @author   Evan Prodromou <evan@status.net>
 | 
				
			||||||
 | 
					 * @license  http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
 | 
				
			||||||
 | 
					 * @link     http://status.net/
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @see      DB_DataObject
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Bookmark extends Memcached_DataObject
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public $__table = 'bookmark'; // table name
 | 
				
			||||||
 | 
					    public $profile_id;           // int(4)  primary_key not_null
 | 
				
			||||||
 | 
					    public $url;                  // varchar(255) primary_key not_null
 | 
				
			||||||
 | 
					    public $title;                // varchar(255)
 | 
				
			||||||
 | 
					    public $description;          // text
 | 
				
			||||||
 | 
					    public $uri;                  // varchar(255)
 | 
				
			||||||
 | 
					    public $url_crc32;            // int(4) not_null
 | 
				
			||||||
 | 
					    public $created;              // datetime
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Get an instance by key
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * This is a utility method to get a single instance with a given key value.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param string $k Key to use to lookup (usually 'user_id' for this class)
 | 
				
			||||||
 | 
					     * @param mixed  $v Value to lookup
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return User_greeting_count object found, or null for no hits
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function staticGet($k, $v=null)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return Memcached_DataObject::staticGet('Bookmark', $k, $v);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Get an instance by compound key
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * This is a utility method to get a single instance with a given set of
 | 
				
			||||||
 | 
					     * key-value pairs. Usually used for the primary key for a compound key; thus
 | 
				
			||||||
 | 
					     * the name.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param array $kv array of key-value mappings
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return Bookmark object found, or null for no hits
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function pkeyGet($kv)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return Memcached_DataObject::pkeyGet('Bookmark', $kv);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * return table definition for DB_DataObject
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * DB_DataObject needs to know something about the table to manipulate
 | 
				
			||||||
 | 
					     * instances. This method provides all the DB_DataObject needs to know.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return array array of column definitions
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function table()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return array('profile_id' => DB_DATAOBJECT_INT + DB_DATAOBJECT_NOTNULL,
 | 
				
			||||||
 | 
					                     'url' => DB_DATAOBJECT_STR,
 | 
				
			||||||
 | 
					                     'title' => DB_DATAOBJECT_STR,
 | 
				
			||||||
 | 
					                     'description' => DB_DATAOBJECT_STR,
 | 
				
			||||||
 | 
					                     'uri' => DB_DATAOBJECT_STR,
 | 
				
			||||||
 | 
					                     'url_crc32' => DB_DATAOBJECT_INT + DB_DATAOBJECT_NOTNULL,
 | 
				
			||||||
 | 
					                     'created' => DB_DATAOBJECT_STR + DB_DATAOBJECT_DATE + 
 | 
				
			||||||
 | 
					                     DB_DATAOBJECT_TIME + DB_DATAOBJECT_NOTNULL);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * return key definitions for DB_DataObject
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return array list of key field names
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function keys()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return array_keys($this->keyTypes());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * return key definitions for Memcached_DataObject
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return array associative array of key definitions
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function keyTypes()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return array('profile_id' => 'K',
 | 
				
			||||||
 | 
					                     'url' => 'K',
 | 
				
			||||||
 | 
					                     'uri' => 'U');
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Magic formula for non-autoincrementing integer primary keys
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return array magic three-false array that stops auto-incrementing.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function sequenceKey()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return array(false, false, false);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Get a bookmark based on a notice
 | 
				
			||||||
 | 
					     * 
 | 
				
			||||||
 | 
					     * @param Notice $notice Notice to check for
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return Bookmark found bookmark or null
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    function getByNotice($notice)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return self::staticGet('uri', $notice->uri);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Get the bookmark that a user made for an URL
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param Profile $profile Profile to check for
 | 
				
			||||||
 | 
					     * @param string  $url     URL to check for
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return Bookmark bookmark found or null
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					     
 | 
				
			||||||
 | 
					    static function getByURL($profile, $url)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return self::pkeyGet(array('profile_id' => $profile->id,
 | 
				
			||||||
 | 
					                                   'url' => $url));
 | 
				
			||||||
 | 
					        return null;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Get the bookmark that a user made for an URL
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param Profile $profile Profile to check for
 | 
				
			||||||
 | 
					     * @param integer $crc32   CRC-32 of URL to check for
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return array Bookmark objects found (usually 1 or 0)
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					     
 | 
				
			||||||
 | 
					    static function getByCRC32($profile, $crc32)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $bookmarks = array();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $nb = new Bookmark();
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        $nb->profile_id = $profile->id;
 | 
				
			||||||
 | 
					        $nb->url_crc32  = $crc32;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if ($nb->find()) {
 | 
				
			||||||
 | 
					            while ($nb->fetch()) {
 | 
				
			||||||
 | 
					                $bookmarks[] = clone($nb);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return $bookmarks;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Save a new notice bookmark
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param Profile $profile     To save the bookmark for
 | 
				
			||||||
 | 
					     * @param string  $title       Title of the bookmark
 | 
				
			||||||
 | 
					     * @param string  $url         URL of the bookmark
 | 
				
			||||||
 | 
					     * @param mixed   $rawtags     array of tags or string
 | 
				
			||||||
 | 
					     * @param string  $description Description of the bookmark
 | 
				
			||||||
 | 
					     * @param array   $options     Options for the Notice::saveNew()
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return Notice saved notice
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    static function saveNew($profile, $title, $url, $rawtags, $description,
 | 
				
			||||||
 | 
					                            $options=null)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $nb = self::getByURL($profile, $url);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (!empty($nb)) {
 | 
				
			||||||
 | 
					            throw new ClientException(_('Bookmark already exists.'));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (empty($options)) {
 | 
				
			||||||
 | 
					            $options = array();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (array_key_exists('uri', $options)) {
 | 
				
			||||||
 | 
					            $other = Bookmark::staticGet('uri', $options['uri']);
 | 
				
			||||||
 | 
					            if (!empty($other)) {
 | 
				
			||||||
 | 
					                throw new ClientException(_('Bookmark already exists.'));
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (is_string($rawtags)) {
 | 
				
			||||||
 | 
					            $rawtags = preg_split('/[\s,]+/', $rawtags);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $nb = new Bookmark();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $nb->profile_id  = $profile->id;
 | 
				
			||||||
 | 
					        $nb->url         = $url;
 | 
				
			||||||
 | 
					        $nb->title       = $title;
 | 
				
			||||||
 | 
					        $nb->description = $description;
 | 
				
			||||||
 | 
					        $nb->url_crc32   = crc32($nb->url);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (array_key_exists('created', $options)) {
 | 
				
			||||||
 | 
					            $nb->created = $options['created'];
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            $nb->created = common_sql_now();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (array_key_exists('uri', $options)) {
 | 
				
			||||||
 | 
					            $nb->uri = $options['uri'];
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            $dt = new DateTime($nb->created, new DateTimeZone('UTC'));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // I posit that it's sufficiently impossible
 | 
				
			||||||
 | 
					            // for the same user to generate two CRC-32-clashing
 | 
				
			||||||
 | 
					            // URLs in the same second that this is a safe unique identifier.
 | 
				
			||||||
 | 
					            // If you find a real counterexample, contact me at acct:evan@status.net
 | 
				
			||||||
 | 
					            // and I will publicly apologize for my hubris.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            $created = $dt->format('YmdHis');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            $crc32 = sprintf('%08x', $nb->url_crc32);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            $nb->uri = common_local_url('showbookmark',
 | 
				
			||||||
 | 
					                                        array('user' => $profile->id,
 | 
				
			||||||
 | 
					                                              'created' => $created,
 | 
				
			||||||
 | 
					                                              'crc32' => $crc32));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $nb->insert();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $tags    = array();
 | 
				
			||||||
 | 
					        $replies = array();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // filter "for:nickname" tags
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        foreach ($rawtags as $tag) {
 | 
				
			||||||
 | 
					            if (strtolower(mb_substr($tag, 0, 4)) == 'for:') {
 | 
				
			||||||
 | 
					                // skip if done by caller
 | 
				
			||||||
 | 
					                if (!array_key_exists('replies', $options)) {
 | 
				
			||||||
 | 
					                    $nickname = mb_substr($tag, 4);
 | 
				
			||||||
 | 
					                    $other    = common_relative_profile($profile,
 | 
				
			||||||
 | 
					                                                        $nickname);
 | 
				
			||||||
 | 
					                    if (!empty($other)) {
 | 
				
			||||||
 | 
					                        $replies[] = $other->getUri();
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                $tags[] = common_canonical_tag($tag);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $hashtags = array();
 | 
				
			||||||
 | 
					        $taglinks = array();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        foreach ($tags as $tag) {
 | 
				
			||||||
 | 
					            $hashtags[] = '#'.$tag;
 | 
				
			||||||
 | 
					            $attrs      = array('href' => Notice_tag::url($tag),
 | 
				
			||||||
 | 
					                                'rel'  => $tag,
 | 
				
			||||||
 | 
					                                'class' => 'tag');
 | 
				
			||||||
 | 
					            $taglinks[] = XMLStringer::estring('a', $attrs, $tag);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Use user's preferences for short URLs, if possible
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $user = User::staticGet('id', $profile->id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $shortUrl = File_redirection::makeShort($url, 
 | 
				
			||||||
 | 
					                                                empty($user) ? null : $user);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $content = sprintf(_('"%s" %s %s %s'),
 | 
				
			||||||
 | 
					                           $title,
 | 
				
			||||||
 | 
					                           $shortUrl,
 | 
				
			||||||
 | 
					                           $description,
 | 
				
			||||||
 | 
					                           implode(' ', $hashtags));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $rendered = sprintf(_('<span class="xfolkentry">'.
 | 
				
			||||||
 | 
					                              '<a class="taggedlink" href="%s">%s</a> '.
 | 
				
			||||||
 | 
					                              '<span class="description">%s</span> '.
 | 
				
			||||||
 | 
					                              '<span class="meta">%s</span>'.
 | 
				
			||||||
 | 
					                              '</span>'),
 | 
				
			||||||
 | 
					                            htmlspecialchars($url),
 | 
				
			||||||
 | 
					                            htmlspecialchars($title),
 | 
				
			||||||
 | 
					                            htmlspecialchars($description),
 | 
				
			||||||
 | 
					                            implode(' ', $taglinks));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $options = array_merge(array('urls' => array($url),
 | 
				
			||||||
 | 
					                                     'rendered' => $rendered,
 | 
				
			||||||
 | 
					                                     'tags' => $tags,
 | 
				
			||||||
 | 
					                                     'replies' => $replies),
 | 
				
			||||||
 | 
					                               $options);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (!array_key_exists('uri', $options)) {
 | 
				
			||||||
 | 
					            $options['uri'] = $nb->uri;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $saved = Notice::saveNew($profile->id,
 | 
				
			||||||
 | 
					                                 $content,
 | 
				
			||||||
 | 
					                                 array_key_exists('source', $options) ?
 | 
				
			||||||
 | 
					                                 $options['source'] : 'web',
 | 
				
			||||||
 | 
					                                 $options);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return $saved;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										772
									
								
								plugins/Bookmark/BookmarkPlugin.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										772
									
								
								plugins/Bookmark/BookmarkPlugin.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,772 @@
 | 
				
			|||||||
 | 
					<?php
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * StatusNet - the distributed open-source microblogging tool
 | 
				
			||||||
 | 
					 * Copyright (C) 2010, StatusNet, Inc.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * A plugin to enable social-bookmarking functionality
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * PHP version 5
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * 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  SocialBookmark
 | 
				
			||||||
 | 
					 * @package   StatusNet
 | 
				
			||||||
 | 
					 * @author    Evan Prodromou <evan@status.net>
 | 
				
			||||||
 | 
					 * @copyright 2010 StatusNet, Inc.
 | 
				
			||||||
 | 
					 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
 | 
				
			||||||
 | 
					 * @link      http://status.net/
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if (!defined('STATUSNET')) {
 | 
				
			||||||
 | 
					    exit(1);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Bookmark plugin main class
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @category  Bookmark
 | 
				
			||||||
 | 
					 * @package   StatusNet
 | 
				
			||||||
 | 
					 * @author    Brion Vibber <brionv@status.net>
 | 
				
			||||||
 | 
					 * @author    Evan Prodromou <evan@status.net>
 | 
				
			||||||
 | 
					 * @copyright 2010 StatusNet, Inc.
 | 
				
			||||||
 | 
					 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
 | 
				
			||||||
 | 
					 * @link      http://status.net/
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class BookmarkPlugin extends Plugin
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    const VERSION         = '0.1';
 | 
				
			||||||
 | 
					    const IMPORTDELICIOUS = 'BookmarkPlugin:IMPORTDELICIOUS';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Authorization for importing delicious bookmarks
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * By default, everyone can import bookmarks except silenced people.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param Profile $profile Person whose rights to check
 | 
				
			||||||
 | 
					     * @param string  $right   Right to check; const value
 | 
				
			||||||
 | 
					     * @param boolean &$result Result of the check, writeable
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return boolean hook value
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function onUserRightsCheck($profile, $right, &$result)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if ($right == self::IMPORTDELICIOUS) {
 | 
				
			||||||
 | 
					            $result = !$profile->isSilenced();
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Database schema setup
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @see Schema
 | 
				
			||||||
 | 
					     * @see ColumnDef
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return boolean hook value; true means continue processing, false means stop.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function onCheckSchema()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $schema = Schema::get();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // For storing user-submitted flags on profiles
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $schema->ensureTable('bookmark',
 | 
				
			||||||
 | 
					                             array(new ColumnDef('profile_id',
 | 
				
			||||||
 | 
					                                                 'integer',
 | 
				
			||||||
 | 
					                                                 null,
 | 
				
			||||||
 | 
					                                                 false,
 | 
				
			||||||
 | 
					                                                 'PRI'),
 | 
				
			||||||
 | 
					                                   new ColumnDef('url',
 | 
				
			||||||
 | 
					                                                 'varchar',
 | 
				
			||||||
 | 
					                                                 255,
 | 
				
			||||||
 | 
					                                                 false,
 | 
				
			||||||
 | 
					                                                 'PRI'),
 | 
				
			||||||
 | 
					                                   new ColumnDef('title',
 | 
				
			||||||
 | 
					                                                 'varchar',
 | 
				
			||||||
 | 
					                                                 255),
 | 
				
			||||||
 | 
					                                   new ColumnDef('description',
 | 
				
			||||||
 | 
					                                                 'text'),
 | 
				
			||||||
 | 
					                                   new ColumnDef('uri',
 | 
				
			||||||
 | 
					                                                 'varchar',
 | 
				
			||||||
 | 
					                                                 255,
 | 
				
			||||||
 | 
					                                                 false,
 | 
				
			||||||
 | 
					                                                 'UNI'),
 | 
				
			||||||
 | 
					                                   new ColumnDef('url_crc32',
 | 
				
			||||||
 | 
					                                                 'integer unsigned',
 | 
				
			||||||
 | 
					                                                 null,
 | 
				
			||||||
 | 
					                                                 false,
 | 
				
			||||||
 | 
					                                                 'MUL'),
 | 
				
			||||||
 | 
					                                   new ColumnDef('created',
 | 
				
			||||||
 | 
					                                                 'datetime',
 | 
				
			||||||
 | 
					                                                 null,
 | 
				
			||||||
 | 
					                                                 false,
 | 
				
			||||||
 | 
					                                                 'MUL')));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					            $schema->createIndex('bookmark', 
 | 
				
			||||||
 | 
					                                 array('profile_id', 
 | 
				
			||||||
 | 
					                                       'url_crc32'),
 | 
				
			||||||
 | 
					                                 'bookmark_profile_url_idx');
 | 
				
			||||||
 | 
					        } catch (Exception $e) {
 | 
				
			||||||
 | 
					            common_log(LOG_ERR, $e->getMessage());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * When a notice is deleted, delete the related Bookmark
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param Notice $notice Notice being deleted
 | 
				
			||||||
 | 
					     * 
 | 
				
			||||||
 | 
					     * @return boolean hook value
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function onNoticeDeleteRelated($notice)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $nb = Bookmark::getByNotice($notice);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (!empty($nb)) {
 | 
				
			||||||
 | 
					            $nb->delete();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Show the CSS necessary for this plugin
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param Action $action the action being run
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return boolean hook value
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function onEndShowStyles($action)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $action->cssLink('plugins/Bookmark/bookmark.css');
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Load related modules when needed
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param string $cls Name of the class to be loaded
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return boolean hook value; true means continue processing, false means stop.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function onAutoload($cls)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $dir = dirname(__FILE__);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        switch ($cls)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					        case 'ShowbookmarkAction':
 | 
				
			||||||
 | 
					        case 'NewbookmarkAction':
 | 
				
			||||||
 | 
					        case 'BookmarkpopupAction':
 | 
				
			||||||
 | 
					        case 'NoticebyurlAction':
 | 
				
			||||||
 | 
					        case 'ImportdeliciousAction':
 | 
				
			||||||
 | 
					            include_once $dir . '/' . strtolower(mb_substr($cls, 0, -6)) . '.php';
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
 | 
					        case 'Bookmark':
 | 
				
			||||||
 | 
					            include_once $dir.'/'.$cls.'.php';
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
 | 
					        case 'BookmarkForm':
 | 
				
			||||||
 | 
					        case 'DeliciousBackupImporter':
 | 
				
			||||||
 | 
					        case 'DeliciousBookmarkImporter':
 | 
				
			||||||
 | 
					            include_once $dir.'/'.strtolower($cls).'.php';
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
 | 
					        default:
 | 
				
			||||||
 | 
					            return true;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Map URLs to actions
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param Net_URL_Mapper $m path-to-action mapper
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return boolean hook value; true means continue processing, false means stop.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function onRouterInitialized($m)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $m->connect('main/bookmark/new',
 | 
				
			||||||
 | 
					                    array('action' => 'newbookmark'),
 | 
				
			||||||
 | 
					                    array('id' => '[0-9]+'));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $m->connect('main/bookmark/popup',
 | 
				
			||||||
 | 
					                    array('action' => 'bookmarkpopup'));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $m->connect('main/bookmark/import',
 | 
				
			||||||
 | 
					                    array('action' => 'importdelicious'));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $m->connect('bookmark/:user/:created/:crc32',
 | 
				
			||||||
 | 
					                    array('action' => 'showbookmark'),
 | 
				
			||||||
 | 
					                    array('user' => '[0-9]+',
 | 
				
			||||||
 | 
					                          'created' => '[0-9]{14}',
 | 
				
			||||||
 | 
					                          'crc32' => '[0-9a-f]{8}'));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $m->connect('notice/by-url/:id',
 | 
				
			||||||
 | 
					                    array('action' => 'noticebyurl'),
 | 
				
			||||||
 | 
					                    array('id' => '[0-9]+'));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Output the HTML for a bookmark in a list
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param NoticeListItem $nli The list item being shown.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return boolean hook value
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function onStartShowNoticeItem($nli)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $nb = Bookmark::getByNotice($nli->notice);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (!empty($nb)) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            $out     = $nli->out;
 | 
				
			||||||
 | 
					            $notice  = $nli->notice;
 | 
				
			||||||
 | 
					            $profile = $nli->profile;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            $atts = $notice->attachments();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (count($atts) < 1) {
 | 
				
			||||||
 | 
					                // Something wrong; let default code deal with it.
 | 
				
			||||||
 | 
					                return true;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            $att = $atts[0];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // XXX: only show the bookmark URL for non-single-page stuff
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if ($out instanceof ShowbookmarkAction) {
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                $out->elementStart('h3');
 | 
				
			||||||
 | 
					                $out->element('a',
 | 
				
			||||||
 | 
					                              array('href' => $att->url),
 | 
				
			||||||
 | 
					                              $nb->title);
 | 
				
			||||||
 | 
					                $out->elementEnd('h3');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                $countUrl = common_local_url('noticebyurl',
 | 
				
			||||||
 | 
					                                             array('id' => $att->id));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                $out->element('a', array('class' => 'bookmark_notice_count',
 | 
				
			||||||
 | 
					                                         'href' => $countUrl),
 | 
				
			||||||
 | 
					                              $att->noticeCount());
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            $out->elementStart('ul', array('class' => 'bookmark_tags'));
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					            // Replies look like "for:" tags
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            $replies = $nli->notice->getReplies();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (!empty($replies)) {
 | 
				
			||||||
 | 
					                foreach ($replies as $reply) {
 | 
				
			||||||
 | 
					                    $other = Profile::staticGet('id', $reply);
 | 
				
			||||||
 | 
					                    $out->elementStart('li');
 | 
				
			||||||
 | 
					                    $out->element('a', array('rel' => 'tag',
 | 
				
			||||||
 | 
					                                             'href' => $other->profileurl,
 | 
				
			||||||
 | 
					                                             'title' => $other->getBestName()),
 | 
				
			||||||
 | 
					                                  sprintf('for:%s', $other->nickname));
 | 
				
			||||||
 | 
					                    $out->elementEnd('li');
 | 
				
			||||||
 | 
					                    $out->text(' ');
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            $tags = $nli->notice->getTags();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            foreach ($tags as $tag) {
 | 
				
			||||||
 | 
					                $out->elementStart('li');
 | 
				
			||||||
 | 
					                $out->element('a', 
 | 
				
			||||||
 | 
					                              array('rel' => 'tag',
 | 
				
			||||||
 | 
					                                    'href' => Notice_tag::url($tag)),
 | 
				
			||||||
 | 
					                              $tag);
 | 
				
			||||||
 | 
					                $out->elementEnd('li');
 | 
				
			||||||
 | 
					                $out->text(' ');
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            $out->elementEnd('ul');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            $out->element('p',
 | 
				
			||||||
 | 
					                          array('class' => 'bookmark_description'),
 | 
				
			||||||
 | 
					                          $nb->description);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (common_config('attachments', 'show_thumbs')) {
 | 
				
			||||||
 | 
					                $al = new InlineAttachmentList($notice, $out);
 | 
				
			||||||
 | 
					                $al->show();
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            $out->elementStart('p', array('style' => 'float: left'));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            $avatar = $profile->getAvatar(AVATAR_MINI_SIZE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            $out->element('img', array('src' => ($avatar) ?
 | 
				
			||||||
 | 
					                                       $avatar->displayUrl() :
 | 
				
			||||||
 | 
					                                       Avatar::defaultImage(AVATAR_MINI_SIZE),
 | 
				
			||||||
 | 
					                                       'class' => 'avatar photo bookmark_avatar',
 | 
				
			||||||
 | 
					                                       'width' => AVATAR_MINI_SIZE,
 | 
				
			||||||
 | 
					                                       'height' => AVATAR_MINI_SIZE,
 | 
				
			||||||
 | 
					                                       'alt' => $profile->getBestName()));
 | 
				
			||||||
 | 
					            $out->raw(' ');
 | 
				
			||||||
 | 
					            $out->element('a', array('href' => $profile->profileurl,
 | 
				
			||||||
 | 
					                                     'title' => $profile->getBestName()),
 | 
				
			||||||
 | 
					                          $profile->nickname);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            $nli->showNoticeLink();
 | 
				
			||||||
 | 
					            $nli->showNoticeSource();
 | 
				
			||||||
 | 
					            $nli->showNoticeLocation();
 | 
				
			||||||
 | 
					            $nli->showContext();
 | 
				
			||||||
 | 
					            $nli->showRepeat();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            $out->elementEnd('p');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            $nli->showNoticeOptions();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Render a notice as a Bookmark object
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param Notice         $notice  Notice to render
 | 
				
			||||||
 | 
					     * @param ActivityObject &$object Empty object to fill
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return boolean hook value
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					     
 | 
				
			||||||
 | 
					    function onStartActivityObjectFromNotice($notice, &$object)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        common_log(LOG_INFO,
 | 
				
			||||||
 | 
					                   "Checking {$notice->uri} to see if it's a bookmark.");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $nb = Bookmark::getByNotice($notice);
 | 
				
			||||||
 | 
					                                         
 | 
				
			||||||
 | 
					        if (!empty($nb)) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            common_log(LOG_INFO,
 | 
				
			||||||
 | 
					                       "Formatting notice {$notice->uri} as a bookmark.");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            $object->id      = $notice->uri;
 | 
				
			||||||
 | 
					            $object->type    = ActivityObject::BOOKMARK;
 | 
				
			||||||
 | 
					            $object->title   = $nb->title;
 | 
				
			||||||
 | 
					            $object->summary = $nb->description;
 | 
				
			||||||
 | 
					            $object->link    = $notice->bestUrl();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Attributes of the URL
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            $attachments = $notice->attachments();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (count($attachments) != 1) {
 | 
				
			||||||
 | 
					                throw new ServerException(_('Bookmark notice with the '.
 | 
				
			||||||
 | 
					                                            'wrong number of attachments.'));
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            $target = $attachments[0];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            $attrs = array('rel' => 'related',
 | 
				
			||||||
 | 
					                           'href' => $target->url);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (!empty($target->title)) {
 | 
				
			||||||
 | 
					                $attrs['title'] = $target->title;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            $object->extra[] = array('link', $attrs, null);
 | 
				
			||||||
 | 
					                                                   
 | 
				
			||||||
 | 
					            // Attributes of the thumbnail, if any
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            $thumbnail = $target->getThumbnail();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (!empty($thumbnail)) {
 | 
				
			||||||
 | 
					                $tattrs = array('rel' => 'preview',
 | 
				
			||||||
 | 
					                                'href' => $thumbnail->url);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if (!empty($thumbnail->width)) {
 | 
				
			||||||
 | 
					                    $tattrs['media:width'] = $thumbnail->width;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if (!empty($thumbnail->height)) {
 | 
				
			||||||
 | 
					                    $tattrs['media:height'] = $thumbnail->height;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                $object->extra[] = array('link', $attrs, null);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Add our two queue handlers to the queue manager
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param QueueManager $qm current queue manager
 | 
				
			||||||
 | 
					     * 
 | 
				
			||||||
 | 
					     * @return boolean hook value
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function onEndInitializeQueueManager($qm)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $qm->connect('dlcsback', 'DeliciousBackupImporter');
 | 
				
			||||||
 | 
					        $qm->connect('dlcsbkmk', 'DeliciousBookmarkImporter');
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Plugin version data
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param array &$versions array of version data
 | 
				
			||||||
 | 
					     * 
 | 
				
			||||||
 | 
					     * @return value
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function onPluginVersion(&$versions)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $versions[] = array('name' => 'Sample',
 | 
				
			||||||
 | 
					                            'version' => self::VERSION,
 | 
				
			||||||
 | 
					                            'author' => 'Evan Prodromou',
 | 
				
			||||||
 | 
					                            'homepage' => 'http://status.net/wiki/Plugin:Bookmark',
 | 
				
			||||||
 | 
					                            'rawdescription' =>
 | 
				
			||||||
 | 
					                            _m('Simple extension for supporting bookmarks.'));
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Load our document if requested
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param string &$title  Title to fetch
 | 
				
			||||||
 | 
					     * @param string &$output HTML to output
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return boolean hook value
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function onStartLoadDoc(&$title, &$output)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if ($title == 'bookmarklet') {
 | 
				
			||||||
 | 
					            $filename = INSTALLDIR.'/plugins/Bookmark/bookmarklet';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            $c      = file_get_contents($filename);
 | 
				
			||||||
 | 
					            $output = common_markup_to_html($c);
 | 
				
			||||||
 | 
					            return false; // success!
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Handle a posted bookmark from PuSH
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param Activity        $activity activity to handle
 | 
				
			||||||
 | 
					     * @param Ostatus_profile $oprofile Profile for the feed
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return boolean hook value
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function onStartHandleFeedEntryWithProfile($activity, $oprofile)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        common_log(LOG_INFO, "BookmarkPlugin called for new feed entry.");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (self::_isPostBookmark($activity)) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            common_log(LOG_INFO, 
 | 
				
			||||||
 | 
					                       "Importing activity {$activity->id} as a bookmark.");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            $author = $oprofile->checkAuthorship($activity);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (empty($author)) {
 | 
				
			||||||
 | 
					                throw new ClientException(_('Can\'t get author for activity.'));
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            self::_postRemoteBookmark($author,
 | 
				
			||||||
 | 
					                                      $activity);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Handle a posted bookmark from Salmon
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param Activity $activity activity to handle
 | 
				
			||||||
 | 
					     * @param mixed    $target   user or group targeted
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return boolean hook value
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function onStartHandleSalmonTarget($activity, $target)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (self::_isPostBookmark($activity)) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            $this->log(LOG_INFO, "Checking {$activity->id} as a valid Salmon slap.");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if ($target instanceof User_group) {
 | 
				
			||||||
 | 
					                $uri = $target->getUri();
 | 
				
			||||||
 | 
					                if (!in_array($uri, $activity->context->attention)) {
 | 
				
			||||||
 | 
					                    throw new ClientException(_("Bookmark not posted ".
 | 
				
			||||||
 | 
					                                                "to this group."));
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            } else if ($target instanceof User) {
 | 
				
			||||||
 | 
					                $uri      = $target->uri;
 | 
				
			||||||
 | 
					                $original = null;
 | 
				
			||||||
 | 
					                if (!empty($activity->context->replyToID)) {
 | 
				
			||||||
 | 
					                    $original = Notice::staticGet('uri', 
 | 
				
			||||||
 | 
					                                                  $activity->context->replyToID); 
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                if (!in_array($uri, $activity->context->attention) &&
 | 
				
			||||||
 | 
					                    (empty($original) ||
 | 
				
			||||||
 | 
					                     $original->profile_id != $target->id)) {
 | 
				
			||||||
 | 
					                    throw new ClientException(_("Bookmark not posted ".
 | 
				
			||||||
 | 
					                                                "to this user."));
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                throw new ServerException(_("Don't know how to handle ".
 | 
				
			||||||
 | 
					                                            "this kind of target."));
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            $author = Ostatus_profile::ensureActivityObjectProfile($activity->actor);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            self::_postRemoteBookmark($author,
 | 
				
			||||||
 | 
					                                      $activity);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Handle bookmark posted via AtomPub
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param Activity &$activity Activity that was posted
 | 
				
			||||||
 | 
					     * @param User     $user      User that posted it
 | 
				
			||||||
 | 
					     * @param Notice   &$notice   Resulting notice
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return boolean hook value
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function onStartAtomPubNewActivity(&$activity, $user, &$notice)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (self::_isPostBookmark($activity)) {
 | 
				
			||||||
 | 
					            $options = array('source' => 'atompub');
 | 
				
			||||||
 | 
					            $notice  = self::_postBookmark($user->getProfile(),
 | 
				
			||||||
 | 
					                                           $activity,
 | 
				
			||||||
 | 
					                                           $options);
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Handle bookmark imported from a backup file
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param User           $user     User to import for
 | 
				
			||||||
 | 
					     * @param ActivityObject $author   Original author per import file
 | 
				
			||||||
 | 
					     * @param Activity       $activity Activity to import
 | 
				
			||||||
 | 
					     * @param boolean        $trusted  Is this a trusted user?
 | 
				
			||||||
 | 
					     * @param boolean        &$done    Is this done (success or unrecoverable error)
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return boolean hook value
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function onStartImportActivity($user, $author, $activity, $trusted, &$done)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (self::_isPostBookmark($activity)) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            $bookmark = $activity->objects[0];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            $this->log(LOG_INFO,
 | 
				
			||||||
 | 
					                       'Importing Bookmark ' . $bookmark->id . 
 | 
				
			||||||
 | 
					                       ' for user ' . $user->nickname);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            $options = array('uri' => $bookmark->id,
 | 
				
			||||||
 | 
					                             'url' => $bookmark->link,
 | 
				
			||||||
 | 
					                             'source' => 'restore');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            $saved = self::_postBookmark($user->getProfile(), $activity, $options);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (!empty($saved)) {
 | 
				
			||||||
 | 
					                $done = true;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Show a link to our delicious import page on profile settings form
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param Action $action Profile settings action being shown
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return boolean hook value
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function onEndProfileSettingsActions($action)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $user = common_current_user();
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        if (!empty($user) && $user->hasRight(self::IMPORTDELICIOUS)) {
 | 
				
			||||||
 | 
					            $action->elementStart('li');
 | 
				
			||||||
 | 
					            $action->element('a',
 | 
				
			||||||
 | 
					                             array('href' => common_local_url('importdelicious')),
 | 
				
			||||||
 | 
					                             _('Import del.icio.us bookmarks'));
 | 
				
			||||||
 | 
					            $action->elementEnd('li');
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Save a remote bookmark (from Salmon or PuSH)
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param Ostatus_profile $author   Author of the bookmark
 | 
				
			||||||
 | 
					     * @param Activity        $activity Activity to save
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return Notice resulting notice.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    static private function _postRemoteBookmark(Ostatus_profile $author,
 | 
				
			||||||
 | 
					                                                Activity $activity)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $bookmark = $activity->objects[0];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $options = array('uri' => $bookmark->id,
 | 
				
			||||||
 | 
					                         'url' => $bookmark->link,
 | 
				
			||||||
 | 
					                         'is_local' => Notice::REMOTE_OMB,
 | 
				
			||||||
 | 
					                         'source' => 'ostatus');
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        return self::_postBookmark($author->localProfile(), $activity, $options);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Save a bookmark from an activity
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param Profile  $profile  Profile to use as author
 | 
				
			||||||
 | 
					     * @param Activity $activity Activity to save
 | 
				
			||||||
 | 
					     * @param array    $options  Options to pass to bookmark-saving code
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return Notice resulting notice
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    static private function _postBookmark(Profile $profile,
 | 
				
			||||||
 | 
					                                          Activity $activity,
 | 
				
			||||||
 | 
					                                          $options=array())
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $bookmark = $activity->objects[0];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $relLinkEls = ActivityUtils::getLinks($bookmark->element, 'related');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (count($relLinkEls) < 1) {
 | 
				
			||||||
 | 
					            throw new ClientException(_('Expected exactly 1 link '.
 | 
				
			||||||
 | 
					                                        'rel=related in a Bookmark.'));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (count($relLinkEls) > 1) {
 | 
				
			||||||
 | 
					            common_log(LOG_WARNING,
 | 
				
			||||||
 | 
					                       "Got too many link rel=related in a Bookmark.");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $linkEl = $relLinkEls[0];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $url = $linkEl->getAttribute('href');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $tags = array();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        foreach ($activity->categories as $category) {
 | 
				
			||||||
 | 
					            $tags[] = common_canonical_tag($category->term);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (!empty($activity->time)) {
 | 
				
			||||||
 | 
					            $options['created'] = common_sql_date($activity->time);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Fill in location if available
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $location = $activity->context->location;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if ($location) {
 | 
				
			||||||
 | 
					            $options['lat'] = $location->lat;
 | 
				
			||||||
 | 
					            $options['lon'] = $location->lon;
 | 
				
			||||||
 | 
					            if ($location->location_id) {
 | 
				
			||||||
 | 
					                $options['location_ns'] = $location->location_ns;
 | 
				
			||||||
 | 
					                $options['location_id'] = $location->location_id;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $replies = $activity->context->attention;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $options['groups']  = array();
 | 
				
			||||||
 | 
					        $options['replies'] = array();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        foreach ($replies as $replyURI) {
 | 
				
			||||||
 | 
					            $other = Profile::fromURI($replyURI);
 | 
				
			||||||
 | 
					            if (!empty($other)) {
 | 
				
			||||||
 | 
					                $options['replies'][] = $replyURI;
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                $group = User_group::staticGet('uri', $replyURI);
 | 
				
			||||||
 | 
					                if (!empty($group)) {
 | 
				
			||||||
 | 
					                    $options['groups'][] = $replyURI;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Maintain direct reply associations
 | 
				
			||||||
 | 
					        // @fixme what about conversation ID?
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (!empty($activity->context->replyToID)) {
 | 
				
			||||||
 | 
					            $orig = Notice::staticGet('uri',
 | 
				
			||||||
 | 
					                                      $activity->context->replyToID);
 | 
				
			||||||
 | 
					            if (!empty($orig)) {
 | 
				
			||||||
 | 
					                $options['reply_to'] = $orig->id;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return Bookmark::saveNew($profile,
 | 
				
			||||||
 | 
					                                 $bookmark->title,
 | 
				
			||||||
 | 
					                                 $url,
 | 
				
			||||||
 | 
					                                 $tags,
 | 
				
			||||||
 | 
					                                 $bookmark->summary,
 | 
				
			||||||
 | 
					                                 $options);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Test if an activity represents posting a bookmark
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param Activity $activity Activity to test
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return true if it's a Post of a Bookmark, else false
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    static private function _isPostBookmark($activity)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return ($activity->verb == ActivityVerb::POST &&
 | 
				
			||||||
 | 
					                $activity->objects[0]->type == ActivityObject::BOOKMARK);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										4
									
								
								plugins/Bookmark/bookmark.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								plugins/Bookmark/bookmark.css
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,4 @@
 | 
				
			|||||||
 | 
					.bookmark_tags li { display: inline; }
 | 
				
			||||||
 | 
					.bookmark_mentions li { display: inline; }
 | 
				
			||||||
 | 
					.bookmark_avatar { float: left }
 | 
				
			||||||
 | 
					.bookmark_notice_count { float: right }
 | 
				
			||||||
							
								
								
									
										164
									
								
								plugins/Bookmark/bookmarkform.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										164
									
								
								plugins/Bookmark/bookmarkform.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,164 @@
 | 
				
			|||||||
 | 
					<?php
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * StatusNet - the distributed open-source microblogging tool
 | 
				
			||||||
 | 
					 * Copyright (C) 2010, StatusNet, Inc.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Form for adding a new bookmark
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * PHP version 5
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * 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  Bookmark
 | 
				
			||||||
 | 
					 * @package   StatusNet
 | 
				
			||||||
 | 
					 * @author    Evan Prodromou <evan@status.net>
 | 
				
			||||||
 | 
					 * @copyright 2010 StatusNet, Inc.
 | 
				
			||||||
 | 
					 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
 | 
				
			||||||
 | 
					 * @link      http://status.net/
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if (!defined('STATUSNET')) {
 | 
				
			||||||
 | 
					    // This check helps protect against security problems;
 | 
				
			||||||
 | 
					    // your code file can't be executed directly from the web.
 | 
				
			||||||
 | 
					    exit(1);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Form to add a new bookmark
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @category  Bookmark
 | 
				
			||||||
 | 
					 * @package   StatusNet
 | 
				
			||||||
 | 
					 * @author    Evan Prodromou <evan@status.net>
 | 
				
			||||||
 | 
					 * @copyright 2010 StatusNet, Inc.
 | 
				
			||||||
 | 
					 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
 | 
				
			||||||
 | 
					 * @link      http://status.net/
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class BookmarkForm extends Form
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    private $_title       = null;
 | 
				
			||||||
 | 
					    private $_url         = null;
 | 
				
			||||||
 | 
					    private $_tags        = null;
 | 
				
			||||||
 | 
					    private $_description = null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Construct a bookmark form
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param HTMLOutputter $out         output channel
 | 
				
			||||||
 | 
					     * @param string        $title       Title of the bookmark
 | 
				
			||||||
 | 
					     * @param string        $url         URL of the bookmark
 | 
				
			||||||
 | 
					     * @param string        $tags        Tags to show
 | 
				
			||||||
 | 
					     * @param string        $description Description of the bookmark
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return void
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function __construct($out=null, $title=null, $url=null, $tags=null,
 | 
				
			||||||
 | 
					                         $description=null)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        parent::__construct($out);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->_title       = $title;
 | 
				
			||||||
 | 
					        $this->_url         = $url;
 | 
				
			||||||
 | 
					        $this->_tags        = $tags;
 | 
				
			||||||
 | 
					        $this->_description = $description;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * ID of the form
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return int ID of the form
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function id()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return 'form_new_bookmark';
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * class of the form
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return string class of the form
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function formClass()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return 'form_settings';
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Action of the form
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return string URL of the action
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function action()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return common_local_url('newbookmark');
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Data elements of the form
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return void
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function formData()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $this->out->elementStart('fieldset', array('id' => 'new_bookmark_data'));
 | 
				
			||||||
 | 
					        $this->out->elementStart('ul', 'form_data');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->li();
 | 
				
			||||||
 | 
					        $this->out->input('title',
 | 
				
			||||||
 | 
					                          _('Title'),
 | 
				
			||||||
 | 
					                          $this->_title,
 | 
				
			||||||
 | 
					                          _('Title of the bookmark'));
 | 
				
			||||||
 | 
					        $this->unli();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->li();
 | 
				
			||||||
 | 
					        $this->out->input('url',
 | 
				
			||||||
 | 
					                          _('URL'),
 | 
				
			||||||
 | 
					                          $this->_url,   
 | 
				
			||||||
 | 
					                          _('URL to bookmark'));
 | 
				
			||||||
 | 
					        $this->unli();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->li();
 | 
				
			||||||
 | 
					        $this->out->input('tags',
 | 
				
			||||||
 | 
					                          _('Tags'),
 | 
				
			||||||
 | 
					                          $this->_tags,   
 | 
				
			||||||
 | 
					                          _('Comma- or space-separated list of tags'));
 | 
				
			||||||
 | 
					        $this->unli();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->li();
 | 
				
			||||||
 | 
					        $this->out->input('description',
 | 
				
			||||||
 | 
					                          _('Description'),
 | 
				
			||||||
 | 
					                          $this->_description,   
 | 
				
			||||||
 | 
					                          _('Description of the URL'));
 | 
				
			||||||
 | 
					        $this->unli();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->out->elementEnd('ul');
 | 
				
			||||||
 | 
					        $this->out->elementEnd('fieldset');
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Action elements
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return void
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function formActions()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $this->out->submit('submit', _m('BUTTON', 'Save'));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										9
									
								
								plugins/Bookmark/bookmarklet
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								plugins/Bookmark/bookmarklet
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
				
			|||||||
 | 
					<!-- Copyright 2008-2010 StatusNet Inc. and contributors. -->
 | 
				
			||||||
 | 
					<!-- Document licensed under Creative Commons Attribution 3.0 Unported. See -->
 | 
				
			||||||
 | 
					<!-- http://creativecommons.org/licenses/by/3.0/ for details. -->
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					A bookmarklet is a small piece of javascript code used as a bookmark. This one will let you post to %%site.name%% simply by selecting some text on a page and pressing the bookmarklet.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Drag-and-drop the following link to your bookmarks bar or right-click it and add it to your browser favorites to keep it handy.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<a href="javascript:(function(){var%20d=document,w=window,e=w.getSelection,k=d.getSelection,x=d.selection,s=(e?e():(k)?k():(x?x.createRange().text:0)),f='http://%%site.server%%/%%site.path%%/index.php?action=bookmarkpopup',l=d.location,e=encodeURIComponent,g=f+'&title='+((e(s))?e(s):e(document.title))+'&url='+e(l.href);function%20a(){if(!w.open(g,'t','toolbar=0,resizable=0,scrollbars=1,status=1,width=650,height=470')){l.href=g;}}a();})()">Bookmark on %%site.name%%</a>
 | 
				
			||||||
							
								
								
									
										23
									
								
								plugins/Bookmark/bookmarkpopup.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								plugins/Bookmark/bookmarkpopup.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,23 @@
 | 
				
			|||||||
 | 
					$(document).ready(
 | 
				
			||||||
 | 
					    function() {
 | 
				
			||||||
 | 
						var form = $('#form_new_bookmark');
 | 
				
			||||||
 | 
					        form.append('<input type="hidden" name="ajax" value="1"/>');
 | 
				
			||||||
 | 
					        form.ajaxForm({dataType: 'xml',
 | 
				
			||||||
 | 
							       timeout: '60000',
 | 
				
			||||||
 | 
					                       beforeSend: function(formData) {
 | 
				
			||||||
 | 
								   form.addClass('processing');
 | 
				
			||||||
 | 
								   form.find('#submit').addClass('disabled');
 | 
				
			||||||
 | 
							       },
 | 
				
			||||||
 | 
					                       error: function (xhr, textStatus, errorThrown) {
 | 
				
			||||||
 | 
								   form.removeClass('processing');
 | 
				
			||||||
 | 
								   form.find('#submit').removeClass('disabled');
 | 
				
			||||||
 | 
								   self.close();
 | 
				
			||||||
 | 
							       },
 | 
				
			||||||
 | 
					                       success: function(data, textStatus) {
 | 
				
			||||||
 | 
								   form.removeClass('processing');
 | 
				
			||||||
 | 
								   form.find('#submit').removeClass('disabled');
 | 
				
			||||||
 | 
					                           self.close();
 | 
				
			||||||
 | 
					                       }});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
							
								
								
									
										112
									
								
								plugins/Bookmark/bookmarkpopup.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										112
									
								
								plugins/Bookmark/bookmarkpopup.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,112 @@
 | 
				
			|||||||
 | 
					<?php
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * StatusNet, the distributed open-source microblogging tool
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Post a new bookmark in a popup window
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * 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  Bookmark
 | 
				
			||||||
 | 
					 * @package   StatusNet
 | 
				
			||||||
 | 
					 * @author    Sarven Capadisli <csarven@status.net>
 | 
				
			||||||
 | 
					 * @author    Evan Prodromou <evan@status.net>
 | 
				
			||||||
 | 
					 * @copyright 2008-2010 StatusNet, Inc.
 | 
				
			||||||
 | 
					 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
 | 
				
			||||||
 | 
					 * @link      http://status.net/
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if (!defined('STATUSNET')) {
 | 
				
			||||||
 | 
					    exit(1);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Action for posting a new bookmark
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @category Bookmark
 | 
				
			||||||
 | 
					 * @package  StatusNet
 | 
				
			||||||
 | 
					 * @author   Sarven Capadisli <csarven@status.net>
 | 
				
			||||||
 | 
					 * @author   Evan Prodromou <evan@status.net>
 | 
				
			||||||
 | 
					 * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
 | 
				
			||||||
 | 
					 * @link     http://status.net/
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					class BookmarkpopupAction extends NewbookmarkAction
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Show the title section of the window
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return void
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function showTitle()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        // TRANS: Title for mini-posting window loaded from bookmarklet.
 | 
				
			||||||
 | 
					        // TRANS: %s is the StatusNet site name.
 | 
				
			||||||
 | 
					        $this->element('title', 
 | 
				
			||||||
 | 
					                       null, sprintf(_('Bookmark on %s'), 
 | 
				
			||||||
 | 
					                                     common_config('site', 'name')));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Show the header section of the page
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * Shows a stub page and the bookmark form.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return void
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function showHeader()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $this->elementStart('div', array('id' => 'header'));
 | 
				
			||||||
 | 
					        $this->elementStart('address');
 | 
				
			||||||
 | 
					        $this->element('a', array('class' => 'url',
 | 
				
			||||||
 | 
					                                  'href' => common_local_url('public')),
 | 
				
			||||||
 | 
					                         '');
 | 
				
			||||||
 | 
					        $this->elementEnd('address');
 | 
				
			||||||
 | 
					        if (common_logged_in()) {
 | 
				
			||||||
 | 
					            $form = new BookmarkForm($this,
 | 
				
			||||||
 | 
					                                     $this->title,
 | 
				
			||||||
 | 
					                                     $this->url);
 | 
				
			||||||
 | 
					            $form->show();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        $this->elementEnd('div');
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Hide the core section of the page
 | 
				
			||||||
 | 
					     * 
 | 
				
			||||||
 | 
					     * @return void
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function showCore()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Hide the footer section of the page
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return void
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function showFooter()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function showScripts()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        parent::showScripts();
 | 
				
			||||||
 | 
					        $this->script(common_path('plugins/Bookmark/bookmarkpopup.js'));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										196
									
								
								plugins/Bookmark/deliciousbackupimporter.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										196
									
								
								plugins/Bookmark/deliciousbackupimporter.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,196 @@
 | 
				
			|||||||
 | 
					<?php
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * StatusNet - the distributed open-source microblogging tool
 | 
				
			||||||
 | 
					 * Copyright (C) 2010, StatusNet, Inc.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Importer class for Delicious.com backups
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * PHP version 5
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * 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  Bookmark
 | 
				
			||||||
 | 
					 * @package   StatusNet
 | 
				
			||||||
 | 
					 * @author    Evan Prodromou <evan@status.net>
 | 
				
			||||||
 | 
					 * @copyright 2010 StatusNet, Inc.
 | 
				
			||||||
 | 
					 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
 | 
				
			||||||
 | 
					 * @link      http://status.net/
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if (!defined('STATUSNET')) {
 | 
				
			||||||
 | 
					    // This check helps protect against security problems;
 | 
				
			||||||
 | 
					    // your code file can't be executed directly from the web.
 | 
				
			||||||
 | 
					    exit(1);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Importer class for Delicious bookmarks
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @category  Bookmark
 | 
				
			||||||
 | 
					 * @package   StatusNet
 | 
				
			||||||
 | 
					 * @author    Evan Prodromou <evan@status.net>
 | 
				
			||||||
 | 
					 * @copyright 2010 StatusNet, Inc.
 | 
				
			||||||
 | 
					 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
 | 
				
			||||||
 | 
					 * @link      http://status.net/
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class DeliciousBackupImporter extends QueueHandler
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Transport of the importer
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return string transport string
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function transport()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return 'dlcsback';
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Import an in-memory bookmark list to a user's account
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * Take a delicious.com backup file (same as Netscape bookmarks.html)
 | 
				
			||||||
 | 
					     * and import to StatusNet as Bookmark activities.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * The document format is terrible. It consists of a <dl> with
 | 
				
			||||||
 | 
					     * a bunch of <dt>'s, occasionally with <dd>'s.
 | 
				
			||||||
 | 
					     * There are sometimes <p>'s lost inside.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param array $data pair of user, text
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return boolean success value
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function handle($data)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        list($user, $body) = $data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $doc = $this->importHTML($body);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $dls = $doc->getElementsByTagName('dl');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if ($dls->length != 1) {
 | 
				
			||||||
 | 
					            throw new ClientException(_("Bad import file."));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $dl = $dls->item(0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $children = $dl->childNodes;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $dt = null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for ($i = 0; $i < $children->length; $i++) {
 | 
				
			||||||
 | 
					            try {
 | 
				
			||||||
 | 
					                $child = $children->item($i);
 | 
				
			||||||
 | 
					                if ($child->nodeType != XML_ELEMENT_NODE) {
 | 
				
			||||||
 | 
					                    continue;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                switch (strtolower($child->tagName)) {
 | 
				
			||||||
 | 
					                case 'dt':
 | 
				
			||||||
 | 
					                    if (!empty($dt)) {
 | 
				
			||||||
 | 
					                        // No DD provided
 | 
				
			||||||
 | 
					                        $this->importBookmark($user, $dt);
 | 
				
			||||||
 | 
					                        $dt = null;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    $dt = $child;
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					                case 'dd':
 | 
				
			||||||
 | 
					                    $dd = $child;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    $saved = $this->importBookmark($user, $dt, $dd);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    $dt = null;
 | 
				
			||||||
 | 
					                    $dd = null;
 | 
				
			||||||
 | 
					                case 'p':
 | 
				
			||||||
 | 
					                    common_log(LOG_INFO, 'Skipping the <p> in the <dl>.');
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					                default:
 | 
				
			||||||
 | 
					                    common_log(LOG_WARNING, 
 | 
				
			||||||
 | 
					                               "Unexpected element $child->tagName ".
 | 
				
			||||||
 | 
					                               " found in import.");
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            } catch (Exception $e) {
 | 
				
			||||||
 | 
					                common_log(LOG_ERR, $e->getMessage());
 | 
				
			||||||
 | 
					                $dt = $dd = null;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Import a single bookmark
 | 
				
			||||||
 | 
					     * 
 | 
				
			||||||
 | 
					     * Takes a <dt>/<dd> pair. The <dt> has a single
 | 
				
			||||||
 | 
					     * <a> in it with some non-standard attributes.
 | 
				
			||||||
 | 
					     * 
 | 
				
			||||||
 | 
					     * A <dt><dt><dd> sequence will appear as a <dt> with
 | 
				
			||||||
 | 
					     * anothe <dt> as a child. We handle this case recursively. 
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param User       $user User to import data as
 | 
				
			||||||
 | 
					     * @param DOMElement $dt   <dt> element
 | 
				
			||||||
 | 
					     * @param DOMElement $dd   <dd> element
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return Notice imported notice
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function importBookmark($user, $dt, $dd = null)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        // We have to go squirrelling around in the child nodes
 | 
				
			||||||
 | 
					        // on the off chance that we've received another <dt>
 | 
				
			||||||
 | 
					        // as a child.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for ($i = 0; $i < $dt->childNodes->length; $i++) {
 | 
				
			||||||
 | 
					            $child = $dt->childNodes->item($i);
 | 
				
			||||||
 | 
					            if ($child->nodeType == XML_ELEMENT_NODE) {
 | 
				
			||||||
 | 
					                if ($child->tagName == 'dt' && !is_null($dd)) {
 | 
				
			||||||
 | 
					                    $this->importBookmark($user, $dt);
 | 
				
			||||||
 | 
					                    $this->importBookmark($user, $child, $dd);
 | 
				
			||||||
 | 
					                    return;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $qm = QueueManager::get();
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        $qm->enqueue(array($user, $dt, $dd), 'dlcsbkmk');
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Parse some HTML
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * Hides the errors that the dom parser returns
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param string $body Data to import
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return DOMDocument parsed document
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function importHTML($body)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        // DOMDocument::loadHTML may throw warnings on unrecognized elements,
 | 
				
			||||||
 | 
					        // and notices on unrecognized namespaces.
 | 
				
			||||||
 | 
					        $old = error_reporting(error_reporting() & ~(E_WARNING | E_NOTICE));
 | 
				
			||||||
 | 
					        $dom = new DOMDocument();
 | 
				
			||||||
 | 
					        $ok  = $dom->loadHTML($body);
 | 
				
			||||||
 | 
					        error_reporting($old);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if ($ok) {
 | 
				
			||||||
 | 
					            return $dom;
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            return null;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										109
									
								
								plugins/Bookmark/deliciousbookmarkimporter.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										109
									
								
								plugins/Bookmark/deliciousbookmarkimporter.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,109 @@
 | 
				
			|||||||
 | 
					<?php
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * StatusNet - the distributed open-source microblogging tool
 | 
				
			||||||
 | 
					 * Copyright (C) 2010, StatusNet, Inc.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Importer class for Delicious.com bookmarks
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * PHP version 5
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * 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  Bookmark
 | 
				
			||||||
 | 
					 * @package   StatusNet
 | 
				
			||||||
 | 
					 * @author    Evan Prodromou <evan@status.net>
 | 
				
			||||||
 | 
					 * @copyright 2010 StatusNet, Inc.
 | 
				
			||||||
 | 
					 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
 | 
				
			||||||
 | 
					 * @link      http://status.net/
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if (!defined('STATUSNET')) {
 | 
				
			||||||
 | 
					    // This check helps protect against security problems;
 | 
				
			||||||
 | 
					    // your code file can't be executed directly from the web.
 | 
				
			||||||
 | 
					    exit(1);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Importer class for Delicious bookmarks
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @category  Bookmark
 | 
				
			||||||
 | 
					 * @package   StatusNet
 | 
				
			||||||
 | 
					 * @author    Evan Prodromou <evan@status.net>
 | 
				
			||||||
 | 
					 * @copyright 2010 StatusNet, Inc.
 | 
				
			||||||
 | 
					 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
 | 
				
			||||||
 | 
					 * @link      http://status.net/
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class DeliciousBookmarkImporter extends QueueHandler
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Return the transport for this queue handler
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return string 'dlcsbkmk'
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function transport()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return 'dlcsbkmk';
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Handle the data
 | 
				
			||||||
 | 
					     * 
 | 
				
			||||||
 | 
					     * @param array $data array of user, dt, dd
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return boolean success value
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function handle($data)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        list($user, $dt, $dd) = $data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $as = $dt->getElementsByTagName('a');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if ($as->length == 0) {
 | 
				
			||||||
 | 
					            throw new ClientException(_("No <A> tag in a <DT>."));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $a = $as->item(0);
 | 
				
			||||||
 | 
					                    
 | 
				
			||||||
 | 
					        $private = $a->getAttribute('private');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if ($private != 0) {
 | 
				
			||||||
 | 
					            throw new ClientException(_('Skipping private bookmark.'));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (!empty($dd)) {
 | 
				
			||||||
 | 
					            $description = $dd->nodeValue;
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            $description = null;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $title   = $a->nodeValue;
 | 
				
			||||||
 | 
					        $url     = $a->getAttribute('href');
 | 
				
			||||||
 | 
					        $tags    = $a->getAttribute('tags');
 | 
				
			||||||
 | 
					        $addDate = $a->getAttribute('add_date');
 | 
				
			||||||
 | 
					        $created = common_sql_date(intval($addDate));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $saved = Bookmark::saveNew($user->getProfile(),
 | 
				
			||||||
 | 
					                                   $title,
 | 
				
			||||||
 | 
					                                   $url,
 | 
				
			||||||
 | 
					                                   $tags,
 | 
				
			||||||
 | 
					                                   $description,
 | 
				
			||||||
 | 
					                                   array('created' => $created,
 | 
				
			||||||
 | 
					                                         'distribute' => false));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										96
									
								
								plugins/Bookmark/importbookmarks.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										96
									
								
								plugins/Bookmark/importbookmarks.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,96 @@
 | 
				
			|||||||
 | 
					<?php
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * StatusNet - the distributed open-source microblogging tool
 | 
				
			||||||
 | 
					 * Copyright (C) 2010 StatusNet, Inc.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Import a bookmarks file as notices
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * PHP version 5
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * 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  Bookmark
 | 
				
			||||||
 | 
					 * @package   StatusNet
 | 
				
			||||||
 | 
					 * @author    Evan Prodromou <evan@status.net>
 | 
				
			||||||
 | 
					 * @copyright 2010 StatusNet, Inc.
 | 
				
			||||||
 | 
					 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
 | 
				
			||||||
 | 
					 * @link      http://status.net/
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					define('INSTALLDIR', realpath(dirname(__FILE__) . '/../..'));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$shortoptions = 'i:n:f:';
 | 
				
			||||||
 | 
					$longoptions  = array('id=', 'nickname=', 'file=');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$helptext = <<<END_OF_IMPORTBOOKMARKS_HELP
 | 
				
			||||||
 | 
					importbookmarks.php [options]
 | 
				
			||||||
 | 
					Restore a backed-up Delicious.com bookmark file
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-i --id       ID of user to import bookmarks for
 | 
				
			||||||
 | 
					-n --nickname nickname of the user to import for
 | 
				
			||||||
 | 
					-f --file     file to read from (STDIN by default)
 | 
				
			||||||
 | 
					END_OF_IMPORTBOOKMARKS_HELP;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					require_once INSTALLDIR.'/scripts/commandline.inc';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Get the bookmarks file as a string
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * Uses the -f or --file parameter to open and read a
 | 
				
			||||||
 | 
					 * a bookmarks file
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @return string Contents of the file
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function getBookmarksFile()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    $filename = get_option_value('f', 'file');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (empty($filename)) {
 | 
				
			||||||
 | 
					        show_help();
 | 
				
			||||||
 | 
					        exit(1);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!file_exists($filename)) {
 | 
				
			||||||
 | 
					        throw new Exception("No such file '$filename'.");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!is_file($filename)) {
 | 
				
			||||||
 | 
					        throw new Exception("Not a regular file: '$filename'.");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!is_readable($filename)) {
 | 
				
			||||||
 | 
					        throw new Exception("File '$filename' not readable.");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // TRANS: %s is the filename that contains a backup for a user.
 | 
				
			||||||
 | 
					    printfv(_("Getting backup from file '%s'.")."\n", $filename);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    $html = file_get_contents($filename);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return $html;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					try {
 | 
				
			||||||
 | 
					    $user = getUser();
 | 
				
			||||||
 | 
					    $html = getBookmarksFile();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    $qm = QueueManager::get();
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    $qm->enqueue(array($user, $html), 'dlcsback');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} catch (Exception $e) {
 | 
				
			||||||
 | 
					    print $e->getMessage()."\n";
 | 
				
			||||||
 | 
					    exit(1);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										336
									
								
								plugins/Bookmark/importdelicious.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										336
									
								
								plugins/Bookmark/importdelicious.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,336 @@
 | 
				
			|||||||
 | 
					<?php
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * StatusNet - the distributed open-source microblogging tool
 | 
				
			||||||
 | 
					 * Copyright (C) 2010, StatusNet, Inc.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Import del.icio.us bookmarks backups
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * PHP version 5
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * 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  Bookmark
 | 
				
			||||||
 | 
					 * @package   StatusNet
 | 
				
			||||||
 | 
					 * @author    Evan Prodromou <evan@status.net>
 | 
				
			||||||
 | 
					 * @copyright 2010 StatusNet, Inc.
 | 
				
			||||||
 | 
					 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
 | 
				
			||||||
 | 
					 * @link      http://status.net/
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if (!defined('STATUSNET')) {
 | 
				
			||||||
 | 
					    // This check helps protect against security problems;
 | 
				
			||||||
 | 
					    // your code file can't be executed directly from the web.
 | 
				
			||||||
 | 
					    exit(1);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * UI for importing del.icio.us bookmark backups
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @category  Bookmark
 | 
				
			||||||
 | 
					 * @package   StatusNet
 | 
				
			||||||
 | 
					 * @author    Evan Prodromou <evan@status.net>
 | 
				
			||||||
 | 
					 * @copyright 2010 StatusNet, Inc.
 | 
				
			||||||
 | 
					 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
 | 
				
			||||||
 | 
					 * @link      http://status.net/
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ImportdeliciousAction extends Action
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    protected $success = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Return the title of the page
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return string page title
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function title()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return _("Import del.icio.us bookmarks");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * For initializing members of the class.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param array $argarray misc. arguments
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return boolean true
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function prepare($argarray)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        parent::prepare($argarray);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $cur = common_current_user();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (empty($cur)) {
 | 
				
			||||||
 | 
					            throw new ClientException(_('Only logged-in users can '.
 | 
				
			||||||
 | 
					                                        'import del.icio.us backups.'),
 | 
				
			||||||
 | 
					                                      403);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (!$cur->hasRight(BookmarkPlugin::IMPORTDELICIOUS)) {
 | 
				
			||||||
 | 
					            throw new ClientException(_('You may not restore your account.'), 403);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Handler method
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param array $argarray is ignored since it's now passed in in prepare()
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return void
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function handle($argarray=null)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        parent::handle($argarray);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if ($this->isPost()) {
 | 
				
			||||||
 | 
					            $this->importDelicious();
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            $this->showPage();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Queue a file for importation
 | 
				
			||||||
 | 
					     * 
 | 
				
			||||||
 | 
					     * Uses the DeliciousBackupImporter class; may take a long time!
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return void
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function importDelicious()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $this->checkSessionToken();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (!isset($_FILES[ImportDeliciousForm::FILEINPUT]['error'])) {
 | 
				
			||||||
 | 
					            throw new ClientException(_('No uploaded file.'));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        switch ($_FILES[ImportDeliciousForm::FILEINPUT]['error']) {
 | 
				
			||||||
 | 
					        case UPLOAD_ERR_OK: // success, jump out
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        case UPLOAD_ERR_INI_SIZE:
 | 
				
			||||||
 | 
					            // TRANS: Client exception thrown when an uploaded file is too large.
 | 
				
			||||||
 | 
					            throw new ClientException(_('The uploaded file exceeds the ' .
 | 
				
			||||||
 | 
					                'upload_max_filesize directive in php.ini.'));
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        case UPLOAD_ERR_FORM_SIZE:
 | 
				
			||||||
 | 
					            throw new ClientException(
 | 
				
			||||||
 | 
					                // TRANS: Client exception.
 | 
				
			||||||
 | 
					                _('The uploaded file exceeds the MAX_FILE_SIZE directive' .
 | 
				
			||||||
 | 
					                ' that was specified in the HTML form.'));
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        case UPLOAD_ERR_PARTIAL:
 | 
				
			||||||
 | 
					            @unlink($_FILES[ImportDeliciousForm::FILEINPUT]['tmp_name']);
 | 
				
			||||||
 | 
					            // TRANS: Client exception.
 | 
				
			||||||
 | 
					            throw new ClientException(_('The uploaded file was only' .
 | 
				
			||||||
 | 
					                ' partially uploaded.'));
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        case UPLOAD_ERR_NO_FILE:
 | 
				
			||||||
 | 
					            // No file; probably just a non-AJAX submission.
 | 
				
			||||||
 | 
					            throw new ClientException(_('No uploaded file.'));
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        case UPLOAD_ERR_NO_TMP_DIR:
 | 
				
			||||||
 | 
					            // TRANS: Client exception thrown when a temporary folder is not present
 | 
				
			||||||
 | 
					            throw new ClientException(_('Missing a temporary folder.'));
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        case UPLOAD_ERR_CANT_WRITE:
 | 
				
			||||||
 | 
					            // TRANS: Client exception thrown when writing to disk is not possible
 | 
				
			||||||
 | 
					            throw new ClientException(_('Failed to write file to disk.'));
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        case UPLOAD_ERR_EXTENSION:
 | 
				
			||||||
 | 
					            // TRANS: Client exception thrown when a file upload has been stopped
 | 
				
			||||||
 | 
					            throw new ClientException(_('File upload stopped by extension.'));
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        default:
 | 
				
			||||||
 | 
					            common_log(LOG_ERR, __METHOD__ . ": Unknown upload error " .
 | 
				
			||||||
 | 
					                $_FILES[ImportDeliciousForm::FILEINPUT]['error']);
 | 
				
			||||||
 | 
					            // TRANS: Client exception thrown when a file upload operation has failed
 | 
				
			||||||
 | 
					            throw new ClientException(_('System error uploading file.'));
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $filename = $_FILES[ImportDeliciousForm::FILEINPUT]['tmp_name'];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					            if (!file_exists($filename)) {
 | 
				
			||||||
 | 
					                throw new ServerException("No such file '$filename'.");
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					            if (!is_file($filename)) {
 | 
				
			||||||
 | 
					                throw new ServerException("Not a regular file: '$filename'.");
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					            if (!is_readable($filename)) {
 | 
				
			||||||
 | 
					                throw new ServerException("File '$filename' not readable.");
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					            common_debug(sprintf(_("Getting backup from file '%s'."), $filename));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            $html = file_get_contents($filename);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Enqueue for processing.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            $qm = QueueManager::get();
 | 
				
			||||||
 | 
					            $qm->enqueue(array(common_current_user(), $html), 'dlcsback');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            $this->success = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            $this->showPage();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        } catch (Exception $e) {
 | 
				
			||||||
 | 
					            // Delete the file and re-throw
 | 
				
			||||||
 | 
					            @unlink($_FILES[ImportDeliciousForm::FILEINPUT]['tmp_name']);
 | 
				
			||||||
 | 
					            throw $e;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Show the content of the page
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return void
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function showContent()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if ($this->success) {
 | 
				
			||||||
 | 
					            $this->element('p', null,
 | 
				
			||||||
 | 
					                           _('Feed will be restored. '.
 | 
				
			||||||
 | 
					                             'Please wait a few minutes for results.'));
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            $form = new ImportDeliciousForm($this);
 | 
				
			||||||
 | 
					            $form->show();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Return true if read only.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * MAY override
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param array $args other arguments
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return boolean is read only action?
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function isReadOnly($args)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return !$this->isPost();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * A form for backing up the account.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @category  Account
 | 
				
			||||||
 | 
					 * @package   StatusNet
 | 
				
			||||||
 | 
					 * @author    Evan Prodromou <evan@status.net>
 | 
				
			||||||
 | 
					 * @copyright 2010 StatusNet, Inc.
 | 
				
			||||||
 | 
					 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
 | 
				
			||||||
 | 
					 * @link      http://status.net/
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ImportDeliciousForm extends Form
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    const FILEINPUT = 'deliciousbackupfile';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Constructor
 | 
				
			||||||
 | 
					     * 
 | 
				
			||||||
 | 
					     * Set the encoding type, since this is a file upload.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param HTMLOutputter $out output channel
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return ImportDeliciousForm this
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function __construct($out=null)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        parent::__construct($out);
 | 
				
			||||||
 | 
					        $this->enctype = 'multipart/form-data';
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Class of the form.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return string the form's class
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function formClass()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return 'form_import_delicious';
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * URL the form posts to
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return string the form's action URL
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function action()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return common_local_url('importdelicious');
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Output form data
 | 
				
			||||||
 | 
					     * 
 | 
				
			||||||
 | 
					     * Really, just instructions for doing a backup.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return void
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function formData()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $this->out->elementStart('p', 'instructions');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->out->raw(_('You can upload a backed-up '.
 | 
				
			||||||
 | 
					                          'delicious.com bookmarks file.'));
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        $this->out->elementEnd('p');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->out->elementStart('ul', 'form_data');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->out->elementStart('li', array ('id' => 'settings_attach'));
 | 
				
			||||||
 | 
					        $this->out->element('input', array('name' => self::FILEINPUT,
 | 
				
			||||||
 | 
					                                           'type' => 'file',
 | 
				
			||||||
 | 
					                                           'id' => self::FILEINPUT));
 | 
				
			||||||
 | 
					        $this->out->elementEnd('li');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->out->elementEnd('ul');
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Buttons for the form
 | 
				
			||||||
 | 
					     * 
 | 
				
			||||||
 | 
					     * In this case, a single submit button
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return void
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function formActions()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $this->out->submit('submit',
 | 
				
			||||||
 | 
					                           _m('BUTTON', 'Upload'),
 | 
				
			||||||
 | 
					                           'submit',
 | 
				
			||||||
 | 
					                           null,
 | 
				
			||||||
 | 
					                           _('Upload the file'));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										196
									
								
								plugins/Bookmark/newbookmark.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										196
									
								
								plugins/Bookmark/newbookmark.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,196 @@
 | 
				
			|||||||
 | 
					<?php
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * StatusNet - the distributed open-source microblogging tool
 | 
				
			||||||
 | 
					 * Copyright (C) 2010, StatusNet, Inc.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Add a new bookmark
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * PHP version 5
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * 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  Bookmark
 | 
				
			||||||
 | 
					 * @package   StatusNet
 | 
				
			||||||
 | 
					 * @author    Evan Prodromou <evan@status.net>
 | 
				
			||||||
 | 
					 * @copyright 2010 StatusNet, Inc.
 | 
				
			||||||
 | 
					 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
 | 
				
			||||||
 | 
					 * @link      http://status.net/
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					if (!defined('STATUSNET')) {
 | 
				
			||||||
 | 
					    // This check helps protect against security problems;
 | 
				
			||||||
 | 
					    // your code file can't be executed directly from the web.
 | 
				
			||||||
 | 
					    exit(1);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Add a new bookmark
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @category  Bookmark
 | 
				
			||||||
 | 
					 * @package   StatusNet
 | 
				
			||||||
 | 
					 * @author    Evan Prodromou <evan@status.net>
 | 
				
			||||||
 | 
					 * @copyright 2010 StatusNet, Inc.
 | 
				
			||||||
 | 
					 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
 | 
				
			||||||
 | 
					 * @link      http://status.net/
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class NewbookmarkAction extends Action
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    protected $user        = null;
 | 
				
			||||||
 | 
					    protected $error       = null;
 | 
				
			||||||
 | 
					    protected $complete    = null;
 | 
				
			||||||
 | 
					    protected $title       = null;
 | 
				
			||||||
 | 
					    protected $url         = null;
 | 
				
			||||||
 | 
					    protected $tags        = null;
 | 
				
			||||||
 | 
					    protected $description = null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Returns the title of the action
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return string Action title
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function title()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return _('New bookmark');
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * For initializing members of the class.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param array $argarray misc. arguments
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return boolean true
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function prepare($argarray)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        parent::prepare($argarray);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->user = common_current_user();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (empty($this->user)) {
 | 
				
			||||||
 | 
					            throw new ClientException(_("Must be logged in to post a bookmark."),
 | 
				
			||||||
 | 
					                                      403);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if ($this->isPost()) {
 | 
				
			||||||
 | 
					            $this->checkSessionToken();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->title       = $this->trimmed('title');
 | 
				
			||||||
 | 
					        $this->url         = $this->trimmed('url');
 | 
				
			||||||
 | 
					        $this->tags        = $this->trimmed('tags');
 | 
				
			||||||
 | 
					        $this->description = $this->trimmed('description');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Handler method
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param array $argarray is ignored since it's now passed in in prepare()
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return void
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function handle($argarray=null)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        parent::handle($argarray);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if ($this->isPost()) {
 | 
				
			||||||
 | 
					            $this->newBookmark();
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            $this->showPage();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Add a new bookmark
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return void
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function newBookmark()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					            if (empty($this->title)) {
 | 
				
			||||||
 | 
					                throw new ClientException(_('Bookmark must have a title.'));
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (empty($this->url)) {
 | 
				
			||||||
 | 
					                throw new ClientException(_('Bookmark must have an URL.'));
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            $saved = Bookmark::saveNew($this->user->getProfile(),
 | 
				
			||||||
 | 
					                                              $this->title,
 | 
				
			||||||
 | 
					                                              $this->url,
 | 
				
			||||||
 | 
					                                              $this->tags,
 | 
				
			||||||
 | 
					                                              $this->description);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        } catch (ClientException $ce) {
 | 
				
			||||||
 | 
					            $this->error = $ce->getMessage();
 | 
				
			||||||
 | 
					            $this->showPage();
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        common_redirect($saved->bestUrl(), 303);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Show the bookmark form
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return void
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function showContent()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (!empty($this->error)) {
 | 
				
			||||||
 | 
					            $this->element('p', 'error', $this->error);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $form = new BookmarkForm($this,
 | 
				
			||||||
 | 
					                                 $this->title,
 | 
				
			||||||
 | 
					                                 $this->url,
 | 
				
			||||||
 | 
					                                 $this->tags,
 | 
				
			||||||
 | 
					                                 $this->description);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $form->show();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Return true if read only.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * MAY override
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param array $args other arguments
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return boolean is read only action?
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function isReadOnly($args)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if ($_SERVER['REQUEST_METHOD'] == 'GET' ||
 | 
				
			||||||
 | 
					            $_SERVER['REQUEST_METHOD'] == 'HEAD') {
 | 
				
			||||||
 | 
					            return true;
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
							
								
								
									
										177
									
								
								plugins/Bookmark/noticebyurl.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										177
									
								
								plugins/Bookmark/noticebyurl.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,177 @@
 | 
				
			|||||||
 | 
					<?php
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * StatusNet - the distributed open-source microblogging tool
 | 
				
			||||||
 | 
					 * Copyright (C) 2010, StatusNet, Inc.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Notice stream of notices with a given attachment
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * PHP version 5
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * 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  Bookmark
 | 
				
			||||||
 | 
					 * @package   StatusNet
 | 
				
			||||||
 | 
					 * @author    Evan Prodromou <evan@status.net>
 | 
				
			||||||
 | 
					 * @copyright 2010 StatusNet, Inc.
 | 
				
			||||||
 | 
					 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
 | 
				
			||||||
 | 
					 * @link      http://status.net/
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if (!defined('STATUSNET')) {
 | 
				
			||||||
 | 
					    // This check helps protect against security problems;
 | 
				
			||||||
 | 
					    // your code file can't be executed directly from the web.
 | 
				
			||||||
 | 
					    exit(1);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * List notices that contain/link to/use a given URL
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @category  Bookmark
 | 
				
			||||||
 | 
					 * @package   StatusNet
 | 
				
			||||||
 | 
					 * @author    Evan Prodromou <evan@status.net>
 | 
				
			||||||
 | 
					 * @copyright 2010 StatusNet, Inc.
 | 
				
			||||||
 | 
					 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
 | 
				
			||||||
 | 
					 * @link      http://status.net/
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class NoticebyurlAction extends Action
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    protected $url     = null;
 | 
				
			||||||
 | 
					    protected $file    = null;
 | 
				
			||||||
 | 
					    protected $notices = null;
 | 
				
			||||||
 | 
					    protected $page    = null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * For initializing members of the class.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param array $argarray misc. arguments
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return boolean true
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function prepare($argarray)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        parent::prepare($argarray);
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        $this->file = File::staticGet('id', $this->trimmed('id'));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (empty($this->file)) {
 | 
				
			||||||
 | 
					            throw new ClientException(_('Unknown URL'));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $pageArg = $this->trimmed('page');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->page = (empty($pageArg)) ? 1 : intval($pageArg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->notices = $this->file->stream(($this->page - 1) * NOTICES_PER_PAGE,
 | 
				
			||||||
 | 
					                                             NOTICES_PER_PAGE + 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Title of the page
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return string page title
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function title()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if ($this->page == 1) {
 | 
				
			||||||
 | 
					            return sprintf(_("Notices linking to %s"), $this->file->url);
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            return sprintf(_("Notices linking to %s, page %d"),
 | 
				
			||||||
 | 
					                           $this->file->url,
 | 
				
			||||||
 | 
					                           $this->page);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Handler method
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param array $argarray is ignored since it's now passed in in prepare()
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return void
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function handle($argarray=null)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $this->showPage();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Show main page content.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * Shows a list of the notices that link to the given URL
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return void
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function showContent()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $nl = new NoticeList($this->notices, $this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $nl->show();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $cnt = $nl->show();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->pagination($this->page > 1,
 | 
				
			||||||
 | 
					                          $cnt > NOTICES_PER_PAGE,
 | 
				
			||||||
 | 
					                          $this->page,
 | 
				
			||||||
 | 
					                          'noticebyurl',
 | 
				
			||||||
 | 
					                          array('id' => $this->file->id));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Return true if read only.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * MAY override
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param array $args other arguments
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return boolean is read only action?
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function isReadOnly($args)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Return last modified, if applicable.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * MAY override
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return string last modified http header
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    function lastModified()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        // For comparison with If-Last-Modified
 | 
				
			||||||
 | 
					        // If not applicable, return null
 | 
				
			||||||
 | 
					        return null;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Return etag, if applicable.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * MAY override
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return string etag http header
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function etag()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return null;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										145
									
								
								plugins/Bookmark/showbookmark.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										145
									
								
								plugins/Bookmark/showbookmark.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,145 @@
 | 
				
			|||||||
 | 
					<?php
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * StatusNet - the distributed open-source microblogging tool
 | 
				
			||||||
 | 
					 * Copyright (C) 2010, StatusNet, Inc.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Show a single bookmark
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * PHP version 5
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * 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  Bookmark
 | 
				
			||||||
 | 
					 * @package   StatusNet
 | 
				
			||||||
 | 
					 * @author    Evan Prodromou <evan@status.net>
 | 
				
			||||||
 | 
					 * @copyright 2010 StatusNet, Inc.
 | 
				
			||||||
 | 
					 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
 | 
				
			||||||
 | 
					 * @link      http://status.net/
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if (!defined('STATUSNET')) {
 | 
				
			||||||
 | 
					    // This check helps protect against security problems;
 | 
				
			||||||
 | 
					    // your code file can't be executed directly from the web.
 | 
				
			||||||
 | 
					    exit(1);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Show a single bookmark, with associated information
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @category  Bookmark
 | 
				
			||||||
 | 
					 * @package   StatusNet
 | 
				
			||||||
 | 
					 * @author    Evan Prodromou <evan@status.net>
 | 
				
			||||||
 | 
					 * @copyright 2010 StatusNet, Inc.
 | 
				
			||||||
 | 
					 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
 | 
				
			||||||
 | 
					 * @link      http://status.net/
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ShowbookmarkAction extends ShownoticeAction
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    protected $bookmark = null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * For initializing members of the class.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param array $argarray misc. arguments
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return boolean true
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function prepare($argarray)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        OwnerDesignAction::prepare($argarray);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->user = User::staticGet('id', $this->trimmed('user'));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (empty($this->user)) {
 | 
				
			||||||
 | 
					            throw new ClientException(_('No such user.'), 404);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->profile = $this->user->getProfile();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (empty($this->profile)) {
 | 
				
			||||||
 | 
					            throw new ServerException(_('User without a profile.'));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->avatar = $this->profile->getAvatar(AVATAR_PROFILE_SIZE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        sscanf($this->trimmed('crc32'), '%08x', $crc32);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (empty($crc32)) {
 | 
				
			||||||
 | 
					            throw new ClientException(_('No such URL.'), 404);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        $dt = new DateTime($this->trimmed('created'),
 | 
				
			||||||
 | 
					                           new DateTimeZone('UTC'));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (empty($dt)) {
 | 
				
			||||||
 | 
					            throw new ClientException(_('No such create date.'), 404);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $bookmarks = Bookmark::getByCRC32($this->profile,
 | 
				
			||||||
 | 
					                                          $crc32);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        foreach ($bookmarks as $bookmark) {
 | 
				
			||||||
 | 
					            $bdt = new DateTime($bookmark->created, new DateTimeZone('UTC'));
 | 
				
			||||||
 | 
					            if ($bdt->format('U') == $dt->format('U')) {
 | 
				
			||||||
 | 
					                $this->bookmark = $bookmark;
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        } 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (empty($this->bookmark)) {
 | 
				
			||||||
 | 
					            throw new ClientException(_('No such bookmark.'), 404);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->notice = Notice::staticGet('uri', $this->bookmark->uri);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (empty($this->notice)) {
 | 
				
			||||||
 | 
					            // Did we used to have it, and it got deleted?
 | 
				
			||||||
 | 
					            throw new ClientException(_('No such bookmark.'), 404);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Title of the page
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * Used by Action class for layout.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return string page tile
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function title()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return sprintf(_('%s\'s bookmark for "%s"'),
 | 
				
			||||||
 | 
					                       $this->user->nickname,
 | 
				
			||||||
 | 
					                       $this->bookmark->title);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Overload page title display to show bookmark link
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return void
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function showPageTitle()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $this->elementStart('h1');
 | 
				
			||||||
 | 
					        $this->element('a',
 | 
				
			||||||
 | 
					                       array('href' => $this->bookmark->url),
 | 
				
			||||||
 | 
					                       $this->bookmark->title);
 | 
				
			||||||
 | 
					        $this->elementEnd('h1');
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -47,6 +47,9 @@ class GroupsalmonAction extends SalmonAction
 | 
				
			|||||||
            $this->clientError(_m('No such group.'));
 | 
					            $this->clientError(_m('No such group.'));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->target = $this->group;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        $oprofile = Ostatus_profile::staticGet('group_id', $id);
 | 
					        $oprofile = Ostatus_profile::staticGet('group_id', $id);
 | 
				
			||||||
        if ($oprofile) {
 | 
					        if ($oprofile) {
 | 
				
			||||||
            // TRANS: Client error.
 | 
					            // TRANS: Client error.
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -43,6 +43,8 @@ class UsersalmonAction extends SalmonAction
 | 
				
			|||||||
            $this->clientError(_m('No such user.'));
 | 
					            $this->clientError(_m('No such user.'));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->target = $this->user;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return true;
 | 
					        return true;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -457,7 +457,8 @@ class Ostatus_profile extends Memcached_DataObject
 | 
				
			|||||||
    {
 | 
					    {
 | 
				
			||||||
        $activity = new Activity($entry, $feed);
 | 
					        $activity = new Activity($entry, $feed);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (Event::handle('StartHandleFeedEntry', array($activity))) {
 | 
					        if (Event::handle('StartHandleFeedEntryWithProfile', array($activity, $this)) &&
 | 
				
			||||||
 | 
					            Event::handle('StartHandleFeedEntry', array($activity))) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // @todo process all activity objects
 | 
					            // @todo process all activity objects
 | 
				
			||||||
            switch ($activity->objects[0]->type) {
 | 
					            switch ($activity->objects[0]->type) {
 | 
				
			||||||
@@ -479,6 +480,7 @@ class Ostatus_profile extends Memcached_DataObject
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            Event::handle('EndHandleFeedEntry', array($activity));
 | 
					            Event::handle('EndHandleFeedEntry', array($activity));
 | 
				
			||||||
 | 
					            Event::handle('EndHandleFeedEntryWithProfile', array($activity, $this));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -491,37 +493,11 @@ class Ostatus_profile extends Memcached_DataObject
 | 
				
			|||||||
     */
 | 
					     */
 | 
				
			||||||
    public function processPost($activity, $method)
 | 
					    public function processPost($activity, $method)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        if ($this->isGroup()) {
 | 
					        $oprofile = $this->checkAuthorship($activity);
 | 
				
			||||||
            // A group feed will contain posts from multiple authors.
 | 
					
 | 
				
			||||||
            // @fixme validate these profiles in some way!
 | 
					        if (empty($oprofile)) {
 | 
				
			||||||
            $oprofile = self::ensureActorProfile($activity);
 | 
					 | 
				
			||||||
            if ($oprofile->isGroup()) {
 | 
					 | 
				
			||||||
                // Groups can't post notices in StatusNet.
 | 
					 | 
				
			||||||
                common_log(LOG_WARNING, "OStatus: skipping post with group listed as author: $oprofile->uri in feed from $this->uri");
 | 
					 | 
				
			||||||
            return false;
 | 
					            return false;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        } else {
 | 
					 | 
				
			||||||
            $actor = $activity->actor;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if (empty($actor)) {
 | 
					 | 
				
			||||||
                // OK here! assume the default
 | 
					 | 
				
			||||||
            } else if ($actor->id == $this->uri || $actor->link == $this->uri) {
 | 
					 | 
				
			||||||
                $this->updateFromActivityObject($actor);
 | 
					 | 
				
			||||||
            } else if ($actor->id) {
 | 
					 | 
				
			||||||
                // We have an ActivityStreams actor with an explicit ID that doesn't match the feed owner.
 | 
					 | 
				
			||||||
                // This isn't what we expect from mainline OStatus person feeds!
 | 
					 | 
				
			||||||
                // Group feeds go down another path, with different validation...
 | 
					 | 
				
			||||||
                // Most likely this is a plain ol' blog feed of some kind which
 | 
					 | 
				
			||||||
                // doesn't match our expectations. We'll take the entry, but ignore
 | 
					 | 
				
			||||||
                // the <author> info.
 | 
					 | 
				
			||||||
                common_log(LOG_WARNING, "Got an actor '{$actor->title}' ({$actor->id}) on single-user feed for {$this->uri}");
 | 
					 | 
				
			||||||
            } else {
 | 
					 | 
				
			||||||
                // Plain <author> without ActivityStreams actor info.
 | 
					 | 
				
			||||||
                // We'll just ignore this info for now and save the update under the feed's identity.
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            $oprofile = $this;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // It's not always an ActivityObject::NOTE, but... let's just say it is.
 | 
					        // It's not always an ActivityObject::NOTE, but... let's just say it is.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1810,6 +1786,45 @@ class Ostatus_profile extends Memcached_DataObject
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
        return $oprofile;
 | 
					        return $oprofile;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function checkAuthorship($activity)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if ($this->isGroup()) {
 | 
				
			||||||
 | 
					            // A group feed will contain posts from multiple authors.
 | 
				
			||||||
 | 
					            // @fixme validate these profiles in some way!
 | 
				
			||||||
 | 
					            $oprofile = self::ensureActorProfile($activity);
 | 
				
			||||||
 | 
					            if ($oprofile->isGroup()) {
 | 
				
			||||||
 | 
					                // Groups can't post notices in StatusNet.
 | 
				
			||||||
 | 
					                common_log(LOG_WARNING, 
 | 
				
			||||||
 | 
					                           "OStatus: skipping post with group listed as author: ".
 | 
				
			||||||
 | 
					                           "$oprofile->uri in feed from $this->uri");
 | 
				
			||||||
 | 
					                return false;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            $actor = $activity->actor;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (empty($actor)) {
 | 
				
			||||||
 | 
					                // OK here! assume the default
 | 
				
			||||||
 | 
					            } else if ($actor->id == $this->uri || $actor->link == $this->uri) {
 | 
				
			||||||
 | 
					                $this->updateFromActivityObject($actor);
 | 
				
			||||||
 | 
					            } else if ($actor->id) {
 | 
				
			||||||
 | 
					                // We have an ActivityStreams actor with an explicit ID that doesn't match the feed owner.
 | 
				
			||||||
 | 
					                // This isn't what we expect from mainline OStatus person feeds!
 | 
				
			||||||
 | 
					                // Group feeds go down another path, with different validation...
 | 
				
			||||||
 | 
					                // Most likely this is a plain ol' blog feed of some kind which
 | 
				
			||||||
 | 
					                // doesn't match our expectations. We'll take the entry, but ignore
 | 
				
			||||||
 | 
					                // the <author> info.
 | 
				
			||||||
 | 
					                common_log(LOG_WARNING, "Got an actor '{$actor->title}' ({$actor->id}) on single-user feed for {$this->uri}");
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                // Plain <author> without ActivityStreams actor info.
 | 
				
			||||||
 | 
					                // We'll just ignore this info for now and save the update under the feed's identity.
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            $oprofile = $this;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return $oprofile;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -30,6 +30,7 @@ class SalmonAction extends Action
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    var $xml      = null;
 | 
					    var $xml      = null;
 | 
				
			||||||
    var $activity = null;
 | 
					    var $activity = null;
 | 
				
			||||||
 | 
					    var $target   = null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    function prepare($args)
 | 
					    function prepare($args)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
@@ -82,7 +83,8 @@ class SalmonAction extends Action
 | 
				
			|||||||
        StatusNet::setApi(true); // Send smaller error pages
 | 
					        StatusNet::setApi(true); // Send smaller error pages
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        common_log(LOG_DEBUG, "Got a " . $this->activity->verb);
 | 
					        common_log(LOG_DEBUG, "Got a " . $this->activity->verb);
 | 
				
			||||||
        if (Event::handle('StartHandleSalmon', array($this->activity))) {
 | 
					        if (Event::handle('StartHandleSalmonTarget', array($this->activity, $this->target)) &&
 | 
				
			||||||
 | 
					            Event::handle('StartHandleSalmon', array($this->activity))) {
 | 
				
			||||||
            switch ($this->activity->verb)
 | 
					            switch ($this->activity->verb)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
            case ActivityVerb::POST:
 | 
					            case ActivityVerb::POST:
 | 
				
			||||||
@@ -118,6 +120,7 @@ class SalmonAction extends Action
 | 
				
			|||||||
                throw new ClientException(_m("Unrecognized activity type."));
 | 
					                throw new ClientException(_m("Unrecognized activity type."));
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            Event::handle('EndHandleSalmon', array($this->activity));
 | 
					            Event::handle('EndHandleSalmon', array($this->activity));
 | 
				
			||||||
 | 
					            Event::handle('EndHandleSalmonTarget', array($this->activity, $this->target));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user