| 
									
										
										
										
											2008-08-13 10:26:37 -04:00
										 |  |  | <?php | 
					
						
							| 
									
										
										
										
											2020-06-29 01:41:46 +03:00
										 |  |  | // This file is part of GNU social - https://www.gnu.org/software/social
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // GNU social 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.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // GNU social 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 GNU social.  If not, see <http://www.gnu.org/licenses/>.
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-08-13 10:26:37 -04:00
										 |  |  | /** | 
					
						
							|  |  |  |  * Table Definition for fave | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-29 01:41:46 +03:00
										 |  |  | defined('GNUSOCIAL') || die(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-08-22 17:52:02 -04:00
										 |  |  | class Fave extends Managed_DataObject | 
					
						
							| 
									
										
										
										
											2008-08-13 10:26:37 -04:00
										 |  |  | { | 
					
						
							|  |  |  |     public $__table = 'fave';                            // table name
 | 
					
						
							|  |  |  |     public $notice_id;                       // int(4)  primary_key not_null
 | 
					
						
							|  |  |  |     public $user_id;                         // int(4)  primary_key not_null
 | 
					
						
							| 
									
										
										
										
											2015-02-12 18:18:55 +01:00
										 |  |  |     public $uri;                             // varchar(191)   not 255 because utf8mb4 takes more space   not 255 because utf8mb4 takes more space
 | 
					
						
							| 
									
										
										
										
											2014-07-01 23:25:58 +02:00
										 |  |  |     public $created;                         // datetime  multiple_key not_null
 | 
					
						
							| 
									
										
										
										
											2008-08-13 10:26:37 -04:00
										 |  |  |     public $modified;                        // timestamp()   not_null default_CURRENT_TIMESTAMP
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-08-22 17:52:02 -04:00
										 |  |  |     public static function schemaDef() | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         return array( | 
					
						
							|  |  |  |             'fields' => array( | 
					
						
							|  |  |  |                 'notice_id' => array('type' => 'int', 'not null' => true, 'description' => 'notice that is the favorite'), | 
					
						
							|  |  |  |                 'user_id' => array('type' => 'int', 'not null' => true, 'description' => 'user who likes this notice'), | 
					
						
							| 
									
										
										
										
											2015-02-12 18:18:55 +01:00
										 |  |  |                 'uri' => array('type' => 'varchar', 'length' => 191, 'description' => 'universally unique identifier, usually a tag URI'), | 
					
						
							| 
									
										
										
										
											2020-06-29 01:41:46 +03:00
										 |  |  |                 'created' => array('type' => 'datetime', 'description' => 'date this record was created'), | 
					
						
							| 
									
										
										
										
											2011-08-22 17:52:02 -04:00
										 |  |  |                 'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'), | 
					
						
							|  |  |  |             ), | 
					
						
							|  |  |  |             'primary key' => array('notice_id', 'user_id'), | 
					
						
							| 
									
										
										
										
											2011-08-22 18:13:02 -04:00
										 |  |  |             'unique keys' => array( | 
					
						
							|  |  |  |                 'fave_uri_key' => array('uri'), | 
					
						
							|  |  |  |             ), | 
					
						
							| 
									
										
										
										
											2011-08-22 17:52:02 -04:00
										 |  |  |             'foreign keys' => array( | 
					
						
							|  |  |  |                 'fave_notice_id_fkey' => array('notice', array('notice_id' => 'id')), | 
					
						
							|  |  |  |                 'fave_user_id_fkey' => array('profile', array('user_id' => 'id')), // note: formerly referenced notice.id, but we can now record remote users' favorites
 | 
					
						
							|  |  |  |             ), | 
					
						
							|  |  |  |             'indexes' => array( | 
					
						
							| 
									
										
										
										
											2020-09-15 16:59:27 +03:00
										 |  |  |                 'fave_user_id_modified_notice_id_idx' => array('user_id', 'modified', 'notice_id'), | 
					
						
							|  |  |  |                 'fave_notice_id_modified_user_id_idx' => array('notice_id', 'modified', 'user_id'), | 
					
						
							| 
									
										
										
										
											2011-08-22 17:52:02 -04:00
										 |  |  |             ), | 
					
						
							|  |  |  |         ); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-03-23 11:06:37 -07:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * Save a favorite record. | 
					
						
							|  |  |  |      * @fixme post-author notification should be moved here | 
					
						
							|  |  |  |      * | 
					
						
							| 
									
										
										
										
											2015-02-03 15:12:29 +01:00
										 |  |  |      * @param Profile $actor  the local or remote Profile who favorites | 
					
						
							|  |  |  |      * @param Notice  $target the notice that is favorited | 
					
						
							| 
									
										
										
										
											2015-01-12 02:23:23 +01:00
										 |  |  |      * @return Fave record on success | 
					
						
							|  |  |  |      * @throws Exception on failure | 
					
						
							| 
									
										
										
										
											2010-03-23 11:06:37 -07:00
										 |  |  |      */ | 
					
						
							| 
									
										
										
										
											2020-06-29 01:41:46 +03:00
										 |  |  |     public static function addNew(Profile $actor, Notice $target) | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2015-03-10 11:50:16 +01:00
										 |  |  |         if (self::existsForProfile($target, $actor)) { | 
					
						
							|  |  |  |             // TRANS: Client error displayed when trying to mark a notice as favorite that already is a favorite.
 | 
					
						
							|  |  |  |             throw new AlreadyFulfilledException(_('You have already favorited this!')); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-03 16:28:33 +01:00
										 |  |  |         $act = new Activity(); | 
					
						
							| 
									
										
										
										
											2015-02-03 16:53:51 +01:00
										 |  |  |         $act->type    = ActivityObject::ACTIVITY; | 
					
						
							| 
									
										
										
										
											2015-02-03 16:28:33 +01:00
										 |  |  |         $act->verb    = ActivityVerb::FAVORITE; | 
					
						
							|  |  |  |         $act->time    = time(); | 
					
						
							|  |  |  |         $act->id      = self::newUri($actor, $target, common_sql_date($act->time)); | 
					
						
							|  |  |  |         $act->title   = _("Favor"); | 
					
						
							|  |  |  |         // TRANS: Message that is the "content" of a favorite (%1$s is the actor's nickname, %2$ is the favorited
 | 
					
						
							|  |  |  |         //        notice's nickname and %3$s is the content of the favorited notice.)
 | 
					
						
							| 
									
										
										
										
											2020-06-29 01:41:46 +03:00
										 |  |  |         $act->content = sprintf( | 
					
						
							|  |  |  |             _('%1$s favorited something by %2$s: %3$s'), | 
					
						
							|  |  |  |             $actor->getNickname(), | 
					
						
							|  |  |  |             $target->getProfile()->getNickname(), | 
					
						
							|  |  |  |             $target->getRendered() | 
					
						
							|  |  |  |         ); | 
					
						
							| 
									
										
										
										
											2015-02-03 16:28:33 +01:00
										 |  |  |         $act->actor   = $actor->asActivityObject(); | 
					
						
							|  |  |  |         $act->target  = $target->asActivityObject(); | 
					
						
							|  |  |  |         $act->objects = array(clone($act->target)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         $url = common_local_url('AtomPubShowFavorite', array('profile'=>$actor->id, 'notice'=>$target->id)); | 
					
						
							|  |  |  |         $act->selfLink = $url; | 
					
						
							|  |  |  |         $act->editLink = $url; | 
					
						
							| 
									
										
										
										
											2010-02-20 12:03:32 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-03 16:28:33 +01:00
										 |  |  |         // saveActivity will in turn also call Fave::saveActivityObject which does
 | 
					
						
							|  |  |  |         // what this function used to do before this commit.
 | 
					
						
							|  |  |  |         $stored = Notice::saveActivity($act, $actor); | 
					
						
							| 
									
										
										
										
											2010-02-20 12:03:32 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-03 16:28:33 +01:00
										 |  |  |         return $stored; | 
					
						
							| 
									
										
										
										
											2008-12-23 14:19:07 -05:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2009-05-01 12:01:28 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-29 01:41:46 +03:00
										 |  |  |     public static function removeEntry(Profile $actor, Notice $target) | 
					
						
							| 
									
										
										
										
											2015-03-10 15:39:35 +01:00
										 |  |  |     { | 
					
						
							|  |  |  |         $fave            = new Fave(); | 
					
						
							|  |  |  |         $fave->user_id   = $actor->getID(); | 
					
						
							|  |  |  |         $fave->notice_id = $target->getID(); | 
					
						
							|  |  |  |         if (!$fave->find(true)) { | 
					
						
							|  |  |  |             // TRANS: Client error displayed when trying to remove a 'favor' when there is none in the first place.
 | 
					
						
							|  |  |  |             throw new AlreadyFulfilledException(_('This is already not favorited.')); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         $result = $fave->delete(); | 
					
						
							|  |  |  |         if ($result === false) { | 
					
						
							|  |  |  |             common_log_db_error($fave, 'DELETE', __FILE__); | 
					
						
							|  |  |  |             // TRANS: Server error displayed when removing a favorite from the database fails.
 | 
					
						
							|  |  |  |             throw new ServerException(_('Could not delete favorite.')); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         Fave::blowCacheForProfileId($actor->getID()); | 
					
						
							|  |  |  |         Fave::blowCacheForNoticeId($target->getID()); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-01 23:25:58 +02:00
										 |  |  |     // exception throwing takeover!
 | 
					
						
							| 
									
										
										
										
											2014-07-02 00:22:27 +02:00
										 |  |  |     public function insert() | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2015-02-03 14:58:22 +01:00
										 |  |  |         if (parent::insert()===false) { | 
					
						
							|  |  |  |             common_log_db_error($this, 'INSERT', __FILE__); | 
					
						
							| 
									
										
										
										
											2014-07-01 23:25:58 +02:00
										 |  |  |             throw new ServerException(sprintf(_m('Could not store new object of type %s'), get_called_class())); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         self::blowCacheForProfileId($this->user_id); | 
					
						
							|  |  |  |         self::blowCacheForNoticeId($this->notice_id); | 
					
						
							|  |  |  |         return $this; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     public function delete($useWhere=false) | 
					
						
							| 
									
										
										
										
											2010-02-20 12:03:32 -05:00
										 |  |  |     { | 
					
						
							|  |  |  |         $result = null; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-03 22:35:49 +01:00
										 |  |  |         try { | 
					
						
							| 
									
										
										
										
											2020-08-04 13:23:31 +03:00
										 |  |  |             $profile = $this->getActor(); | 
					
						
							|  |  |  |             $notice  = $this->getTarget(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if (Event::handle('StartDisfavorNotice', [$profile, $notice, &$result])) { | 
					
						
							|  |  |  |                 $result = parent::delete($useWhere); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 if ($result !== false) { | 
					
						
							|  |  |  |                     Event::handle('EndDisfavorNotice', [$profile, $notice]); | 
					
						
							| 
									
										
										
										
											2016-01-03 22:35:49 +01:00
										 |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } catch (NoResultException $e) { | 
					
						
							| 
									
										
										
										
											2016-01-03 22:57:28 +01:00
										 |  |  |             // In case there's some inconsistency where the profile or notice was deleted without losing the fave db entry
 | 
					
						
							| 
									
										
										
										
											2016-01-03 22:35:49 +01:00
										 |  |  |             common_log(LOG_INFO, '"'.get_class($e->obj).'" with id=='.var_export($e->obj->id, true).' object not found when deleting favorite, ignoring...'); | 
					
						
							| 
									
										
										
										
											2016-06-25 11:50:59 +02:00
										 |  |  |         } catch (EmptyPkeyValueException $e) { | 
					
						
							| 
									
										
										
										
											2016-01-16 21:12:53 +01:00
										 |  |  |             // Some buggy instances of GNU social have had favorites with notice id==0 stored in the database
 | 
					
						
							|  |  |  |             common_log(LOG_INFO, _ve($e->getMessage())); | 
					
						
							| 
									
										
										
										
											2016-01-03 22:57:28 +01:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2010-02-20 12:03:32 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-03 22:57:28 +01:00
										 |  |  |         // If we catch an exception above, then $result===null because parent::delete only returns an int>=0 or boolean false
 | 
					
						
							|  |  |  |         if (is_null($result)) { | 
					
						
							| 
									
										
										
										
											2016-01-03 22:35:49 +01:00
										 |  |  |             // Delete it without the event, as something is wrong and we don't want it anyway.
 | 
					
						
							| 
									
										
										
										
											2013-10-29 10:20:57 +01:00
										 |  |  |             $result = parent::delete($useWhere); | 
					
						
							| 
									
										
										
										
											2010-02-20 12:03:32 -05:00
										 |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-03 22:57:28 +01:00
										 |  |  |         // Err, apparently we can reference $this->user_id after parent::delete,
 | 
					
						
							|  |  |  |         // I guess it's safe because this is the order it was before!
 | 
					
						
							|  |  |  |         self::blowCacheForProfileId($this->user_id); | 
					
						
							|  |  |  |         self::blowCacheForNoticeId($this->notice_id); | 
					
						
							|  |  |  |         self::blow('popular'); | 
					
						
							| 
									
										
										
										
											2016-01-03 22:35:49 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-02-20 12:03:32 -05:00
										 |  |  |         return $result; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-29 01:41:46 +03:00
										 |  |  |     // FIXME: Instead of $own, send the scoped Profile so we can pass it along
 | 
					
						
							|  |  |  |     // directly to FaveNoticeStream and preferrably we should get a Profile
 | 
					
						
							|  |  |  |     // instead of $user_id
 | 
					
						
							|  |  |  |     public static function stream( | 
					
						
							|  |  |  |         $user_id, | 
					
						
							|  |  |  |         $offset   = 0, | 
					
						
							|  |  |  |         $limit    = NOTICES_PER_PAGE, | 
					
						
							|  |  |  |         $own      = false, | 
					
						
							|  |  |  |         $since_id = 0, | 
					
						
							|  |  |  |         $max_id   = 0 | 
					
						
							|  |  |  |     ) { | 
					
						
							| 
									
										
										
										
											2016-03-01 14:51:47 +01:00
										 |  |  |         $target = Profile::getByID($user_id); | 
					
						
							|  |  |  |         $stream = new FaveNoticeStream($target, ($own ? $target : null)); | 
					
						
							| 
									
										
										
										
											2011-03-23 11:29:55 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |         return $stream->getNotices($offset, $limit, $since_id, $max_id); | 
					
						
							| 
									
										
										
										
											2009-05-01 12:01:28 -07:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-29 01:41:46 +03:00
										 |  |  |     // FIXME: Instead of $own, send the scoped Profile so we can pass it along
 | 
					
						
							|  |  |  |     // directly to FaveNoticeStream and preferrably we should get a Profile
 | 
					
						
							|  |  |  |     // instead of $user_id
 | 
					
						
							|  |  |  |     public function idStream( | 
					
						
							|  |  |  |         $user_id, | 
					
						
							|  |  |  |         $offset   = 0, | 
					
						
							|  |  |  |         $limit    = NOTICES_PER_PAGE, | 
					
						
							|  |  |  |         $own      = false, | 
					
						
							|  |  |  |         $since_id = 0, | 
					
						
							|  |  |  |         $max_id   = 0 | 
					
						
							|  |  |  |     ) { | 
					
						
							| 
									
										
										
										
											2016-03-01 14:51:47 +01:00
										 |  |  |         $target = Profile::getByID($user_id); | 
					
						
							|  |  |  |         $stream = new FaveNoticeStream($target, ($own ? $target : null)); | 
					
						
							| 
									
										
										
										
											2011-03-23 11:59:01 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |         return $stream->getNoticeIds($offset, $limit, $since_id, $max_id); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-29 01:41:46 +03:00
										 |  |  |     public function asActivity() | 
					
						
							| 
									
										
										
										
											2010-08-04 12:07:49 -07:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2014-07-14 13:25:26 +02:00
										 |  |  |         $target = $this->getTarget(); | 
					
						
							|  |  |  |         $actor  = $this->getActor(); | 
					
						
							| 
									
										
										
										
											2013-05-24 09:26:58 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-08-04 12:07:49 -07:00
										 |  |  |         $act = new Activity(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         $act->verb = ActivityVerb::FAVORITE; | 
					
						
							| 
									
										
										
										
											2010-12-10 18:50:50 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |         // FIXME: rationalize this with URL below
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-05 23:39:17 +02:00
										 |  |  |         $act->id   = $this->getUri(); | 
					
						
							| 
									
										
										
										
											2010-08-04 12:07:49 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-14 13:25:26 +02:00
										 |  |  |         $act->time    = strtotime($this->created); | 
					
						
							| 
									
										
										
										
											2010-09-28 23:21:09 +02:00
										 |  |  |         // TRANS: Activity title when marking a notice as favorite.
 | 
					
						
							| 
									
										
										
										
											2010-08-04 12:07:49 -07:00
										 |  |  |         $act->title   = _("Favor"); | 
					
						
							| 
									
										
										
										
											2015-02-03 16:28:33 +01:00
										 |  |  |         // TRANS: Message that is the "content" of a favorite (%1$s is the actor's nickname, %2$ is the favorited
 | 
					
						
							|  |  |  |         //        notice's nickname and %3$s is the content of the favorited notice.)
 | 
					
						
							| 
									
										
										
										
											2020-06-29 01:41:46 +03:00
										 |  |  |         $act->content = sprintf( | 
					
						
							|  |  |  |             _('%1$s favorited something by %2$s: %3$s'), | 
					
						
							|  |  |  |             $actor->getNickname(), | 
					
						
							|  |  |  |             $target->getProfile()->getNickname(), | 
					
						
							|  |  |  |             $target->getRendered() | 
					
						
							|  |  |  |         ); | 
					
						
							| 
									
										
										
										
											2016-04-01 23:21:57 +02:00
										 |  |  |         $act->context = new ActivityContext(); | 
					
						
							|  |  |  |         $act->context->replyToID = $target->getUri(); | 
					
						
							|  |  |  |         try { | 
					
						
							|  |  |  |             $act->context->replyToURL = $target->getUrl(); | 
					
						
							|  |  |  |         } catch (InvalidUrlException $e) { | 
					
						
							|  |  |  |             // ok, no replyToURL, i.e. the href="" in <thr:in-reply-to/>
 | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2010-08-04 12:07:49 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-14 13:25:26 +02:00
										 |  |  |         $act->actor     = $actor->asActivityObject(); | 
					
						
							|  |  |  |         $act->target    = $target->asActivityObject(); | 
					
						
							|  |  |  |         $act->objects   = array(clone($act->target)); | 
					
						
							| 
									
										
										
										
											2010-08-04 12:07:49 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-29 01:41:46 +03:00
										 |  |  |         $url = common_local_url( | 
					
						
							|  |  |  |             'AtomPubShowFavorite', | 
					
						
							|  |  |  |             [ | 
					
						
							|  |  |  |                 'profile' => $actor->id, | 
					
						
							|  |  |  |                 'notice'  => $target->id, | 
					
						
							|  |  |  |             ] | 
					
						
							|  |  |  |         ); | 
					
						
							| 
									
										
										
										
											2010-12-10 18:50:50 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |         $act->selfLink = $url; | 
					
						
							|  |  |  |         $act->editLink = $url; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-08-04 12:07:49 -07:00
										 |  |  |         return $act; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2010-12-12 12:22:04 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-29 01:41:46 +03:00
										 |  |  |     public static function existsForProfile($notice, Profile $scoped) | 
					
						
							| 
									
										
										
										
											2014-07-02 00:22:27 +02:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2014-06-27 13:58:35 +02:00
										 |  |  |         $fave = self::pkeyGet(array('user_id'=>$scoped->id, 'notice_id'=>$notice->id)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return ($fave instanceof Fave); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-12-12 12:22:04 -05:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * Fetch a stream of favorites by profile | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * @param integer $profileId Profile that faved | 
					
						
							|  |  |  |      * @param integer $offset    Offset from last | 
					
						
							|  |  |  |      * @param integer $limit     Number to get | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * @return mixed stream of faves, use fetch() to iterate | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * @todo Cache results | 
					
						
							|  |  |  |      * @todo integrate with Fave::stream() | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-29 01:41:46 +03:00
										 |  |  |     public static function byProfile($profileId, $offset, $limit) | 
					
						
							| 
									
										
										
										
											2010-12-12 12:22:04 -05:00
										 |  |  |     { | 
					
						
							|  |  |  |         $fav = new Fave(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         $fav->user_id = $profileId; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-15 16:59:27 +03:00
										 |  |  |         $fav->orderBy('modified DESC, notice_id DESC'); | 
					
						
							| 
									
										
										
										
											2010-12-12 12:22:04 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |         $fav->limit($offset, $limit); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         $fav->find(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return $fav; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2011-08-22 16:36:23 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-29 01:41:46 +03:00
										 |  |  |     public static function countByProfile(Profile $profile) | 
					
						
							| 
									
										
										
										
											2014-06-28 13:11:03 +02:00
										 |  |  |     { | 
					
						
							|  |  |  |         $c = Cache::instance(); | 
					
						
							|  |  |  |         if (!empty($c)) { | 
					
						
							|  |  |  |             $cnt = $c->get(Cache::key('fave:count_by_profile:'.$profile->id)); | 
					
						
							|  |  |  |             if (is_integer($cnt)) { | 
					
						
							|  |  |  |                 return $cnt; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         $faves = new Fave(); | 
					
						
							|  |  |  |         $faves->user_id = $profile->id; | 
					
						
							|  |  |  |         $cnt = (int) $faves->count('notice_id'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (!empty($c)) { | 
					
						
							|  |  |  |             $c->set(Cache::key('fave:count_by_profile:'.$profile->id), $cnt); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return $cnt; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-29 01:41:46 +03:00
										 |  |  |     protected static $_faves = []; | 
					
						
							| 
									
										
										
										
											2014-06-27 13:58:35 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * All faves of this notice | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * @param Notice $notice A notice we wish to get faves for (may still be ArrayWrapper) | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * @return array Array of Fave objects | 
					
						
							|  |  |  |      */ | 
					
						
							| 
									
										
										
										
											2020-06-29 01:41:46 +03:00
										 |  |  |     public static function byNotice($notice) | 
					
						
							| 
									
										
										
										
											2014-06-27 13:58:35 +02:00
										 |  |  |     { | 
					
						
							|  |  |  |         if (!isset(self::$_faves[$notice->id])) { | 
					
						
							|  |  |  |             self::fillFaves(array($notice->id)); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         return self::$_faves[$notice->id]; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-29 01:41:46 +03:00
										 |  |  |     public static function fillFaves(array $notice_ids) | 
					
						
							| 
									
										
										
										
											2014-06-27 13:58:35 +02:00
										 |  |  |     { | 
					
						
							|  |  |  |         $faveMap = Fave::listGet('notice_id', $notice_ids); | 
					
						
							|  |  |  |         self::$_faves = array_replace(self::$_faves, $faveMap); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2014-06-28 13:11:03 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-29 01:41:46 +03:00
										 |  |  |     public static function blowCacheForProfileId($profile_id) | 
					
						
							| 
									
										
										
										
											2014-06-28 13:11:03 +02:00
										 |  |  |     { | 
					
						
							|  |  |  |         $cache = Cache::instance(); | 
					
						
							|  |  |  |         if ($cache) { | 
					
						
							|  |  |  |             // Faves don't happen chronologically, so we need to blow
 | 
					
						
							|  |  |  |             // ;last cache, too
 | 
					
						
							|  |  |  |             $cache->delete(Cache::key('fave:ids_by_user:'.$profile_id)); | 
					
						
							|  |  |  |             $cache->delete(Cache::key('fave:ids_by_user:'.$profile_id.';last')); | 
					
						
							|  |  |  |             $cache->delete(Cache::key('fave:ids_by_user_own:'.$profile_id)); | 
					
						
							|  |  |  |             $cache->delete(Cache::key('fave:ids_by_user_own:'.$profile_id.';last')); | 
					
						
							|  |  |  |             $cache->delete(Cache::key('fave:count_by_profile:'.$profile_id)); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-06-29 01:41:46 +03:00
										 |  |  |     public static function blowCacheForNoticeId($notice_id) | 
					
						
							| 
									
										
										
										
											2014-07-01 22:13:11 +02:00
										 |  |  |     { | 
					
						
							|  |  |  |         $cache = Cache::instance(); | 
					
						
							|  |  |  |         if ($cache) { | 
					
						
							|  |  |  |             $cache->delete(Cache::key('fave:list-ids:notice_id:'.$notice_id)); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2014-07-01 23:25:58 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // Remember that we want the _activity_ notice here, not faves applied
 | 
					
						
							|  |  |  |     // to the supplied Notice (as with byNotice)!
 | 
					
						
							| 
									
										
										
										
											2020-06-29 01:41:46 +03:00
										 |  |  |     public static function fromStored(Notice $stored) | 
					
						
							| 
									
										
										
										
											2014-07-02 00:22:27 +02:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2014-07-01 23:25:58 +02:00
										 |  |  |         $class = get_called_class(); | 
					
						
							|  |  |  |         $object = new $class; | 
					
						
							|  |  |  |         $object->uri = $stored->uri; | 
					
						
							|  |  |  |         if (!$object->find(true)) { | 
					
						
							|  |  |  |             throw new NoResultException($object); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         return $object; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-28 10:02:53 +02:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * Retrieves the _targeted_ notice of a verb (such as the notice that was | 
					
						
							|  |  |  |      * _favorited_, but not the favorite activity itself). | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * @param Notice $stored    The activity notice. | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * @throws NoResultException when it can't find what it's looking for. | 
					
						
							|  |  |  |      */ | 
					
						
							| 
									
										
										
										
											2020-06-29 01:41:46 +03:00
										 |  |  |     public static function getTargetFromStored(Notice $stored) | 
					
						
							| 
									
										
										
										
											2014-07-28 10:02:53 +02:00
										 |  |  |     { | 
					
						
							|  |  |  |         return self::fromStored($stored)->getTarget(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-29 01:41:46 +03:00
										 |  |  |     public static function getObjectType() | 
					
						
							| 
									
										
										
										
											2014-07-01 23:25:58 +02:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2016-01-21 02:10:34 +01:00
										 |  |  |         return ActivityObject::ACTIVITY; | 
					
						
							| 
									
										
										
										
											2014-07-01 23:25:58 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-02 00:22:27 +02:00
										 |  |  |     public function asActivityObject(Profile $scoped=null) | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2014-07-01 23:25:58 +02:00
										 |  |  |         $actobj = new ActivityObject(); | 
					
						
							|  |  |  |         $actobj->id = $this->getUri(); | 
					
						
							| 
									
										
										
										
											2014-07-05 23:39:17 +02:00
										 |  |  |         $actobj->type = ActivityUtils::resolveUri(self::getObjectType()); | 
					
						
							| 
									
										
										
										
											2014-07-01 23:25:58 +02:00
										 |  |  |         $actobj->actor = $this->getActorObject(); | 
					
						
							| 
									
										
										
										
											2014-07-14 13:25:26 +02:00
										 |  |  |         $actobj->target = $this->getTargetObject(); | 
					
						
							| 
									
										
										
										
											2014-07-01 23:25:58 +02:00
										 |  |  |         $actobj->objects = array(clone($actobj->target)); | 
					
						
							| 
									
										
										
										
											2014-07-05 00:15:22 +02:00
										 |  |  |         $actobj->verb = ActivityVerb::FAVORITE; | 
					
						
							| 
									
										
										
										
											2014-07-05 23:39:17 +02:00
										 |  |  |         $actobj->title = ActivityUtils::verbToTitle($actobj->verb); | 
					
						
							| 
									
										
										
										
											2016-01-06 15:32:00 +01:00
										 |  |  |         $actobj->content = $this->getTarget()->getRendered(); | 
					
						
							| 
									
										
										
										
											2014-07-01 23:25:58 +02:00
										 |  |  |         return $actobj; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-05 23:39:17 +02:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * @param ActivityObject $actobj The _favored_ notice (which we're "in-reply-to") | 
					
						
							|  |  |  |      * @param Notice         $stored The _activity_ notice, i.e. the favor itself. | 
					
						
							|  |  |  |      */ | 
					
						
							| 
									
										
										
										
											2020-06-29 01:41:46 +03:00
										 |  |  |     public static function parseActivityObject(ActivityObject $actobj, Notice $stored) | 
					
						
							| 
									
										
										
										
											2014-07-02 00:22:27 +02:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2016-01-05 15:00:07 +01:00
										 |  |  |         // throws exception if nothing was found, but it could also be a non-Notice...
 | 
					
						
							|  |  |  |         // FIXME: This should only test _one_ URI (and not the links etc.) though a function like this could be useful in other cases
 | 
					
						
							| 
									
										
										
										
											2014-07-05 23:39:17 +02:00
										 |  |  |         $local = ActivityUtils::findLocalObject($actobj->getIdentifiers()); | 
					
						
							| 
									
										
										
										
											2014-07-02 00:22:27 +02:00
										 |  |  |         if (!$local instanceof Notice) { | 
					
						
							|  |  |  |             // $local always returns something, but this was not what we expected. Something is wrong.
 | 
					
						
							|  |  |  |             throw new Exception('Something other than a Notice was returned from findLocalObject'); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |   | 
					
						
							| 
									
										
										
										
											2014-07-01 23:25:58 +02:00
										 |  |  |         $actor = $stored->getProfile(); | 
					
						
							|  |  |  |         $object = new Fave(); | 
					
						
							| 
									
										
										
										
											2014-07-02 00:22:27 +02:00
										 |  |  |         $object->user_id = $stored->getProfile()->id; | 
					
						
							|  |  |  |         $object->notice_id = $local->id; | 
					
						
							|  |  |  |         $object->uri = $stored->uri; | 
					
						
							| 
									
										
										
										
											2014-07-01 23:25:58 +02:00
										 |  |  |         $object->created = $stored->created; | 
					
						
							| 
									
										
										
										
											2014-07-02 00:22:27 +02:00
										 |  |  |         $object->modified = $stored->modified; | 
					
						
							| 
									
										
										
										
											2014-07-01 23:25:58 +02:00
										 |  |  |         return $object; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-29 01:41:46 +03:00
										 |  |  |     public static function extendActivity( | 
					
						
							|  |  |  |         Notice   $stored, | 
					
						
							|  |  |  |         Activity $act, | 
					
						
							|  |  |  |         Profile  $scoped = null | 
					
						
							|  |  |  |     ) { | 
					
						
							| 
									
										
										
										
											2014-07-28 10:02:53 +02:00
										 |  |  |         $target = self::getTargetFromStored($stored); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-28 10:58:24 +02:00
										 |  |  |         // The following logic was copied from StatusNet's Activity plugin
 | 
					
						
							| 
									
										
										
										
											2015-09-10 15:27:40 +02:00
										 |  |  |         if (ActivityUtils::compareVerbs($target->verb, array(ActivityVerb::POST))) { | 
					
						
							| 
									
										
										
										
											2014-07-28 10:58:24 +02:00
										 |  |  |             // "I like the thing you posted"
 | 
					
						
							|  |  |  |             $act->objects = $target->asActivity()->objects; | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |             // "I like that you did whatever you did"
 | 
					
						
							|  |  |  |             $act->target = $target->asActivityObject(); | 
					
						
							|  |  |  |             $act->objects = array(clone($act->target)); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2014-07-28 10:02:53 +02:00
										 |  |  |         $act->context->replyToID = $target->getUri(); | 
					
						
							|  |  |  |         $act->context->replyToUrl = $target->getUrl(); | 
					
						
							|  |  |  |         $act->title = ActivityUtils::verbToTitle($act->verb); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-29 01:41:46 +03:00
										 |  |  |     public static function saveActivityObject(ActivityObject $actobj, Notice $stored) | 
					
						
							| 
									
										
										
										
											2014-07-02 00:22:27 +02:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2014-07-01 23:25:58 +02:00
										 |  |  |         $object = self::parseActivityObject($actobj, $stored); | 
					
						
							| 
									
										
										
										
											2015-02-03 16:28:33 +01:00
										 |  |  |         $object->insert();  // exception throwing in Fave's case!
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-03 16:43:56 +01:00
										 |  |  |         self::blowCacheForProfileId($object->user_id); | 
					
						
							|  |  |  |         self::blowCacheForNoticeId($object->notice_id); | 
					
						
							| 
									
										
										
										
											2015-02-03 16:28:33 +01:00
										 |  |  |         self::blow('popular'); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-05 23:39:17 +02:00
										 |  |  |         Event::handle('EndFavorNotice', array($stored->getProfile(), $object->getTarget())); | 
					
						
							| 
									
										
										
										
											2014-07-01 23:25:58 +02:00
										 |  |  |         return $object; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-02 00:22:27 +02:00
										 |  |  |     public function getTarget() | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2016-01-03 22:35:49 +01:00
										 |  |  |         return Notice::getByID($this->notice_id); | 
					
						
							| 
									
										
										
										
											2014-07-01 23:25:58 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-02 00:22:27 +02:00
										 |  |  |     public function getTargetObject() | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2014-07-01 23:25:58 +02:00
										 |  |  |         return $this->getTarget()->asActivityObject(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     protected $_stored = array(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-02 00:22:27 +02:00
										 |  |  |     public function getStored() | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2014-07-01 23:25:58 +02:00
										 |  |  |         if (!isset($this->_stored[$this->uri])) { | 
					
						
							|  |  |  |             $stored = new Notice(); | 
					
						
							|  |  |  |             $stored->uri = $this->uri; | 
					
						
							|  |  |  |             if (!$stored->find(true)) { | 
					
						
							|  |  |  |                 throw new NoResultException($stored); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             $this->_stored[$this->uri] = $stored; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         return $this->_stored[$this->uri]; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-02 00:22:27 +02:00
										 |  |  |     public function getActor() | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2015-10-03 00:43:34 +02:00
										 |  |  |         return Profile::getByID($this->user_id); | 
					
						
							| 
									
										
										
										
											2014-07-01 23:25:58 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-02 00:22:27 +02:00
										 |  |  |     public function getActorObject() | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2014-07-01 23:25:58 +02:00
										 |  |  |         return $this->getActor()->asActivityObject(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-05 23:39:17 +02:00
										 |  |  |     public function getUri() | 
					
						
							| 
									
										
										
										
											2014-07-01 23:25:58 +02:00
										 |  |  |     { | 
					
						
							|  |  |  |         if (!empty($this->uri)) { | 
					
						
							|  |  |  |             return $this->uri; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // We (should've in this case) created it ourselves, so we tag it ourselves
 | 
					
						
							| 
									
										
										
										
											2014-07-05 23:39:17 +02:00
										 |  |  |         return self::newUri($this->getActor(), $this->getTarget(), $this->created); | 
					
						
							| 
									
										
										
										
											2014-07-01 23:25:58 +02:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2008-08-13 10:26:37 -04:00
										 |  |  | } |