diff options
Diffstat (limited to 'classes')
-rw-r--r-- | classes/Fave.php | 38 | ||||
-rw-r--r-- | classes/Group_member.php | 43 | ||||
-rw-r--r-- | classes/Notice.php | 130 | ||||
-rw-r--r-- | classes/Profile.php | 77 | ||||
-rw-r--r-- | classes/Session.php | 12 | ||||
-rw-r--r-- | classes/Subscription.php | 160 | ||||
-rw-r--r-- | classes/User.php | 30 |
7 files changed, 373 insertions, 117 deletions
diff --git a/classes/Fave.php b/classes/Fave.php index 9922ae45c..3aa23e7b4 100644 --- a/classes/Fave.php +++ b/classes/Fave.php @@ -138,6 +138,9 @@ class Fave extends Memcached_DataObject $act = new Activity(); $act->verb = ActivityVerb::FAVORITE; + + // FIXME: rationalize this with URL below + $act->id = TagURI::mint('favor:%d:%d:%s', $profile->id, $notice->id, @@ -155,6 +158,41 @@ class Fave extends Memcached_DataObject $act->actor = ActivityObject::fromProfile($profile); $act->objects[] = ActivityObject::fromNotice($notice); + $url = common_local_url('AtomPubShowFavorite', + array('profile' => $this->user_id, + 'notice' => $this->notice_id)); + + $act->selfLink = $url; + $act->editLink = $url; + return $act; } + + /** + * 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() + */ + + static function byProfile($profileId, $offset, $limit) + { + $fav = new Fave(); + + $fav->user_id = $profileId; + + $fav->orderBy('modified DESC'); + + $fav->limit($offset, $limit); + + $fav->find(); + + return $fav; + } } diff --git a/classes/Group_member.php b/classes/Group_member.php index c40d06a1d..2cf31cf12 100644 --- a/classes/Group_member.php +++ b/classes/Group_member.php @@ -26,6 +26,15 @@ class Group_member extends Memcached_DataObject return Memcached_DataObject::pkeyGet('Group_member', $kv); } + /** + * Method to add a user to a group. + * + * @param integer $group_id Group to add to + * @param integer $profile_id Profile being added + * + * @return Group_member new membership object + */ + static function join($group_id, $profile_id) { $member = new Group_member(); @@ -42,7 +51,7 @@ class Group_member extends Memcached_DataObject throw new Exception(_("Group join failed.")); } - return true; + return $member; } static function leave($group_id, $profile_id) @@ -92,6 +101,31 @@ class Group_member extends Memcached_DataObject return $group; } + /** + * Get stream of memberships by member + * + * @param integer $memberId profile ID of the member to fetch for + * @param integer $offset offset from start of stream to get + * @param integer $limit number of memberships to get + * + * @return Group_member stream of memberships, use fetch() to iterate + */ + + static function byMember($memberId, $offset=0, $limit=GROUPS_PER_PAGE) + { + $membership = new Group_member(); + + $membership->profile_id = $memberId; + + $membership->orderBy('created DESC'); + + $membership->limit($offset, $limit); + + $membership->find(); + + return $membership; + } + function asActivity() { $member = $this->getMember(); @@ -118,6 +152,13 @@ class Group_member extends Memcached_DataObject $member->getBestName(), $group->getBestName()); + $url = common_local_url('AtomPubShowMembership', + array('profile' => $member->id, + 'group' => $group->id)); + + $act->selfLink = $url; + $act->editLink = $url; + return $act; } } diff --git a/classes/Notice.php b/classes/Notice.php index c36fb702b..c1150626b 100644 --- a/classes/Notice.php +++ b/classes/Notice.php @@ -1234,7 +1234,7 @@ class Notice extends Memcached_DataObject * @return Activity activity object representing this Notice. */ - function asActivity($cur = null, $source = false) + function asActivity() { $act = self::cacheGet(Cache::codeKey('notice:as-activity:'.$this->id)); @@ -1332,68 +1332,37 @@ class Notice extends Memcached_DataObject $act->context = $ctx; - $noticeInfoAttr = array('local_id' => $this->id); // local notice ID (useful to clients for ordering) + // Source - $ns = $this->getSource(); + $atom_feed = $profile->getAtomFeed(); - if (!empty($ns)) { - $noticeInfoAttr['source'] = $ns->code; - if (!empty($ns->url)) { - $noticeInfoAttr['source_link'] = $ns->url; - if (!empty($ns->name)) { - $noticeInfoAttr['source'] = '<a href="' - . htmlspecialchars($ns->url) - . '" rel="nofollow">' - . htmlspecialchars($ns->name) - . '</a>'; - } - } - } - - if (!empty($cur)) { - $noticeInfoAttr['favorite'] = ($cur->hasFave($this)) ? "true" : "false"; - $cp = $cur->getProfile(); - $noticeInfoAttr['repeated'] = ($cp->hasRepeated($this->id)) ? "true" : "false"; - } - - if (!empty($this->repeat_of)) { - $noticeInfoAttr['repeat_of'] = $this->repeat_of; - } - - $act->extra[] = array('statusnet:notice_info', $noticeInfoAttr, null); - - if ($source) { - - $atom_feed = $profile->getAtomFeed(); + if (!empty($atom_feed)) { - if (!empty($atom_feed)) { - - $act->source = new ActivitySource(); + $act->source = new ActivitySource(); - // XXX: we should store the actual feed ID + // XXX: we should store the actual feed ID - $act->source->id = $atom_feed; + $act->source->id = $atom_feed; - // XXX: we should store the actual feed title + // XXX: we should store the actual feed title - $act->source->title = $profile->getBestName(); + $act->source->title = $profile->getBestName(); - $act->source->links['alternate'] = $profile->profileurl; - $act->source->links['self'] = $atom_feed; + $act->source->links['alternate'] = $profile->profileurl; + $act->source->links['self'] = $atom_feed; - $act->source->icon = $profile->avatarUrl(AVATAR_PROFILE_SIZE); + $act->source->icon = $profile->avatarUrl(AVATAR_PROFILE_SIZE); - $notice = $profile->getCurrentNotice(); + $notice = $profile->getCurrentNotice(); - if (!empty($notice)) { - $act->source->updated = self::utcDate($notice->created); - } + if (!empty($notice)) { + $act->source->updated = self::utcDate($notice->created); + } - $user = User::staticGet('id', $profile->id); + $user = User::staticGet('id', $profile->id); - if (!empty($user)) { - $act->source->links['license'] = common_config('license', 'url'); - } + if (!empty($user)) { + $act->source->links['license'] = common_config('license', 'url'); } } @@ -1414,12 +1383,65 @@ class Notice extends Memcached_DataObject // This has gotten way too long. Needs to be sliced up into functional bits // or ideally exported to a utility class. - function asAtomEntry($namespace=false, $source=false, $author=true, $cur=null) + function asAtomEntry($namespace=false, + $source=false, + $author=true, + $cur=null) + { + $act = $this->asActivity(); + $act->extra[] = $this->noticeInfo($cur); + return $act->asString($namespace, $author, $source); + } + + /** + * Extra notice info for atom entries + * + * Clients use some extra notice info in the atom stream. + * This gives it to them. + * + * @param User $cur Current user + * + * @return array representation of <statusnet:notice_info> element + */ + + function noticeInfo($cur) { - $act = $this->asActivity($cur, $source); - return $act->asString($namespace, $author); + // local notice ID (useful to clients for ordering) + + $noticeInfoAttr = array('local_id' => $this->id); + + // notice source + + $ns = $this->getSource(); + + if (!empty($ns)) { + $noticeInfoAttr['source'] = $ns->code; + if (!empty($ns->url)) { + $noticeInfoAttr['source_link'] = $ns->url; + if (!empty($ns->name)) { + $noticeInfoAttr['source'] = '<a href="' + . htmlspecialchars($ns->url) + . '" rel="nofollow">' + . htmlspecialchars($ns->name) + . '</a>'; + } + } + } + + // favorite and repeated + + if (!empty($cur)) { + $noticeInfoAttr['favorite'] = ($cur->hasFave($this)) ? "true" : "false"; + $cp = $cur->getProfile(); + $noticeInfoAttr['repeated'] = ($cp->hasRepeated($this->id)) ? "true" : "false"; + } + + if (!empty($this->repeat_of)) { + $noticeInfoAttr['repeat_of'] = $this->repeat_of; + } + + return array('statusnet:notice_info', $noticeInfoAttr, null); } - /** * Returns an XML string fragment with a reference to a notice as an diff --git a/classes/Profile.php b/classes/Profile.php index 05df8899e..1f959eb0d 100644 --- a/classes/Profile.php +++ b/classes/Profile.php @@ -380,79 +380,32 @@ class Profile extends Memcached_DataObject function getSubscriptions($offset=0, $limit=null) { - $qry = - 'SELECT profile.* ' . - 'FROM profile JOIN subscription ' . - 'ON profile.id = subscription.subscribed ' . - 'WHERE subscription.subscriber = %d ' . - 'AND subscription.subscribed != subscription.subscriber ' . - 'ORDER BY subscription.created DESC '; - - if ($offset>0 && !is_null($limit)){ - if (common_config('db','type') == 'pgsql') { - $qry .= ' LIMIT ' . $limit . ' OFFSET ' . $offset; - } else { - $qry .= ' LIMIT ' . $offset . ', ' . $limit; - } - } + $subs = Subscription::bySubscriber($this->id, + $offset, + $limit); - $profile = new Profile(); + $profiles = array(); - $profile->query(sprintf($qry, $this->id)); + while ($subs->fetch()) { + $profiles[] = Profile::staticGet($subs->subscribed); + } - return $profile; + return new ArrayWrapper($profiles); } function getSubscribers($offset=0, $limit=null) { - $qry = - 'SELECT profile.* ' . - 'FROM profile JOIN subscription ' . - 'ON profile.id = subscription.subscriber ' . - 'WHERE subscription.subscribed = %d ' . - 'AND subscription.subscribed != subscription.subscriber ' . - 'ORDER BY subscription.created DESC '; - - if ($offset>0 && !is_null($limit)){ - if ($offset) { - if (common_config('db','type') == 'pgsql') { - $qry .= ' LIMIT ' . $limit . ' OFFSET ' . $offset; - } else { - $qry .= ' LIMIT ' . $offset . ', ' . $limit; - } - } - } - - $profile = new Profile(); + $subs = Subscription::bySubscribed($this->id, + $offset, + $limit); - $cnt = $profile->query(sprintf($qry, $this->id)); - - return $profile; - } + $profiles = array(); - function getConnectedApps($offset = 0, $limit = null) - { - $qry = - 'SELECT u.* ' . - 'FROM oauth_application_user u, oauth_application a ' . - 'WHERE u.profile_id = %d ' . - 'AND a.id = u.application_id ' . - 'AND u.access_type > 0 ' . - 'ORDER BY u.created DESC '; - - if ($offset > 0) { - if (common_config('db','type') == 'pgsql') { - $qry .= ' LIMIT ' . $limit . ' OFFSET ' . $offset; - } else { - $qry .= ' LIMIT ' . $offset . ', ' . $limit; - } + while ($subs->fetch()) { + $profiles[] = Profile::staticGet($subs->subscriber); } - $apps = new Oauth_application_user(); - - $cnt = $apps->query(sprintf($qry, $this->id)); - - return $apps; + return new ArrayWrapper($profiles); } function subscriptionCount() diff --git a/classes/Session.php b/classes/Session.php index 2422f8b68..e1c83ad4d 100644 --- a/classes/Session.php +++ b/classes/Session.php @@ -178,6 +178,18 @@ class Session extends Memcached_DataObject $result = session_set_save_handler('Session::open', 'Session::close', 'Session::read', 'Session::write', 'Session::destroy', 'Session::gc'); self::logdeb("save handlers result = $result"); + + // PHP 5.3 with APC ends up destroying a bunch of object stuff before the session + // save handlers get called on request teardown. + // Registering an explicit shutdown function should take care of this before + // everything breaks on us. + register_shutdown_function('Session::cleanup'); + return $result; } + + static function cleanup() + { + session_write_close(); + } } diff --git a/classes/Subscription.php b/classes/Subscription.php index e9ad2a5a2..1d4f37929 100644 --- a/classes/Subscription.php +++ b/classes/Subscription.php @@ -26,6 +26,8 @@ require_once INSTALLDIR.'/classes/Memcached_DataObject.php'; class Subscription extends Memcached_DataObject { + const CACHE_WINDOW = 201; + ###START_AUTOCODE /* the code below is auto generated do not remove the above tag */ @@ -91,6 +93,9 @@ class Subscription extends Memcached_DataObject self::blow('user:notices_with_friends:%d', $subscriber->id); + self::blow('subscription:by-subscriber:'.$subscriber->id); + self::blow('subscription:by-subscribed:'.$other->id); + $subscriber->blowSubscriptionCount(); $other->blowSubscriberCount(); @@ -220,6 +225,9 @@ class Subscription extends Memcached_DataObject self::blow('user:notices_with_friends:%d', $subscriber->id); + self::blow('subscription:by-subscriber:'.$subscriber->id); + self::blow('subscription:by-subscribed:'.$other->id); + $subscriber->blowSubscriptionCount(); $other->blowSubscriberCount(); @@ -245,6 +253,8 @@ class Subscription extends Memcached_DataObject $act->verb = ActivityVerb::FOLLOW; + // XXX: rationalize this with the URL + $act->id = TagURI::mint('follow:%d:%d:%s', $subscriber->id, $subscribed->id, @@ -262,6 +272,156 @@ class Subscription extends Memcached_DataObject $act->actor = ActivityObject::fromProfile($subscriber); $act->objects[] = ActivityObject::fromProfile($subscribed); + $url = common_local_url('AtomPubShowSubscription', + array('subscriber' => $subscriber->id, + 'subscribed' => $subscribed->id)); + + $act->selfLink = $url; + $act->editLink = $url; + return $act; } + + /** + * Stream of subscriptions with the same subscriber + * + * Useful for showing pages that list subscriptions in reverse + * chronological order. Has offset & limit to make paging + * easy. + * + * @param integer $subscriberId Profile ID of the subscriber + * @param integer $offset Offset from latest + * @param integer $limit Maximum number to fetch + * + * @return Subscription stream of subscriptions; use fetch() to iterate + */ + + static function bySubscriber($subscriberId, + $offset = 0, + $limit = PROFILES_PER_PAGE) + { + if ($offset + $limit > self::CACHE_WINDOW) { + return new ArrayWrapper(self::realBySubscriber($subscriberId, + $offset, + $limit)); + } else { + $key = 'subscription:by-subscriber:'.$subscriberId; + $window = self::cacheGet($key); + if ($window === false) { + $window = self::realBySubscriber($subscriberId, + 0, + self::CACHE_WINDOW); + self::cacheSet($key, $window); + } + return new ArrayWrapper(array_slice($window, + $offset, + $limit)); + } + } + + private static function realBySubscriber($subscriberId, + $offset, + $limit) + { + $sub = new Subscription(); + + $sub->subscriber = $subscriberId; + + $sub->whereAdd('subscribed != ' . $subscriberId); + + $sub->orderBy('created DESC'); + $sub->limit($offset, $limit); + + $sub->find(); + + $subs = array(); + + while ($sub->fetch()) { + $subs[] = clone($sub); + } + + return $subs; + } + + /** + * Stream of subscriptions with the same subscribed profile + * + * Useful for showing pages that list subscribers in reverse + * chronological order. Has offset & limit to make paging + * easy. + * + * @param integer $subscribedId Profile ID of the subscribed + * @param integer $offset Offset from latest + * @param integer $limit Maximum number to fetch + * + * @return Subscription stream of subscriptions; use fetch() to iterate + */ + + static function bySubscribed($subscribedId, + $offset = 0, + $limit = PROFILES_PER_PAGE) + { + if ($offset + $limit > self::CACHE_WINDOW) { + return new ArrayWrapper(self::realBySubscribed($subscribedId, + $offset, + $limit)); + } else { + $key = 'subscription:by-subscribed:'.$subscribedId; + $window = self::cacheGet($key); + if ($window === false) { + $window = self::realBySubscribed($subscribedId, + 0, + self::CACHE_WINDOW); + self::cacheSet($key, $window); + } + return new ArrayWrapper(array_slice($window, + $offset, + $limit)); + } + } + + private static function realBySubscribed($subscribedId, + $offset, + $limit) + { + $sub = new Subscription(); + + $sub->subscribed = $subscribedId; + + $sub->whereAdd('subscriber != ' . $subscribedId); + + $sub->orderBy('created DESC'); + $sub->limit($offset, $limit); + + $sub->find(); + + $subs = array(); + + while ($sub->fetch()) { + $subs[] = clone($sub); + } + + return $subs; + } + + /** + * Flush cached subscriptions when subscription is updated + * + * Because we cache subscriptions, it's useful to flush them + * here. + * + * @param mixed $orig Original version of object + * + * @return boolean success flag. + */ + + function update($orig=null) + { + $result = parent::update($orig); + + self::blow('subscription:by-subscriber:'.$this->subscriber); + self::blow('subscription:by-subscribed:'.$this->subscribed); + + return $result; + } } diff --git a/classes/User.php b/classes/User.php index d4f182f7e..4baa6d1b3 100644 --- a/classes/User.php +++ b/classes/User.php @@ -973,4 +973,34 @@ class User extends Memcached_DataObject { return common_shorten_links($text, $always, $this); } + + /* + * Get a list of OAuth client application that have access to this + * user's account. + */ + function getConnectedApps($offset = 0, $limit = null) + { + $qry = + 'SELECT u.* ' . + 'FROM oauth_application_user u, oauth_application a ' . + 'WHERE u.profile_id = %d ' . + 'AND a.id = u.application_id ' . + 'AND u.access_type > 0 ' . + 'ORDER BY u.created DESC '; + + if ($offset > 0) { + if (common_config('db','type') == 'pgsql') { + $qry .= ' LIMIT ' . $limit . ' OFFSET ' . $offset; + } else { + $qry .= ' LIMIT ' . $offset . ', ' . $limit; + } + } + + $apps = new Oauth_application_user(); + + $cnt = $apps->query(sprintf($qry, $this->id)); + + return $apps; + } + } |