summaryrefslogtreecommitdiff
path: root/classes
diff options
context:
space:
mode:
Diffstat (limited to 'classes')
-rw-r--r--classes/Fave.php38
-rw-r--r--classes/Group_member.php43
-rw-r--r--classes/Notice.php130
-rw-r--r--classes/Profile.php77
-rw-r--r--classes/Session.php12
-rw-r--r--classes/Subscription.php160
-rw-r--r--classes/User.php30
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;
+ }
+
}