diff options
Diffstat (limited to 'classes')
-rwxr-xr-x | classes/Conversation.php | 78 | ||||
-rw-r--r-- | classes/Fave.php | 44 | ||||
-rw-r--r-- | classes/Memcached_DataObject.php | 6 | ||||
-rw-r--r-- | classes/Notice.php | 316 | ||||
-rw-r--r-- | classes/Profile.php | 80 | ||||
-rw-r--r-- | classes/Subscription.php | 154 | ||||
-rw-r--r-- | classes/User.php | 19 | ||||
-rw-r--r-- | classes/User_group.php | 18 | ||||
-rw-r--r-- | classes/statusnet.ini | 10 |
9 files changed, 571 insertions, 154 deletions
diff --git a/classes/Conversation.php b/classes/Conversation.php new file mode 100755 index 000000000..ea8bd87b5 --- /dev/null +++ b/classes/Conversation.php @@ -0,0 +1,78 @@ +<?php +/** + * StatusNet, the distributed open-source microblogging tool + * + * Data class for Conversations + * + * 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 Data + * @package StatusNet + * @author Zach Copley <zach@status.net> + * @copyright 2010 StatusNet Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://status.net/ + */ + +require_once INSTALLDIR . '/classes/Memcached_DataObject.php'; + +class Conversation extends Memcached_DataObject +{ + ###START_AUTOCODE + /* the code below is auto generated do not remove the above tag */ + + public $__table = 'conversation'; // table name + public $id; // int(4) primary_key not_null + public $uri; // varchar(225) unique_key + public $created; // datetime not_null + public $modified; // timestamp not_null default_CURRENT_TIMESTAMP + + /* Static get */ + function staticGet($k,$v=NULL) { return Memcached_DataObject::staticGet('conversation',$k,$v); } + + /* the code above is auto generated do not remove the tag below */ + ###END_AUTOCODE + + /** + * Factory method for creating a new conversation + * + * @return Conversation the new conversation DO + */ + static function create() + { + $conv = new Conversation(); + $conv->created = common_sql_now(); + $id = $conv->insert(); + + if (empty($id)) { + common_log_db_error($conv, 'INSERT', __FILE__); + return null; + } + + $orig = clone($conv); + $orig->uri = common_local_url('conversation', array('id' => $id)); + $result = $orig->update($conv); + + if (empty($result)) { + common_log_db_error($conv, 'UPDATE', __FILE__); + return null; + } + + return $conv; + } + +} + diff --git a/classes/Fave.php b/classes/Fave.php index 8113c8e16..0b6eec2bc 100644 --- a/classes/Fave.php +++ b/classes/Fave.php @@ -21,17 +21,47 @@ class Fave extends Memcached_DataObject /* the code above is auto generated do not remove the tag below */ ###END_AUTOCODE - static function addNew($user, $notice) { - $fave = new Fave(); - $fave->user_id = $user->id; - $fave->notice_id = $notice->id; - if (!$fave->insert()) { - common_log_db_error($fave, 'INSERT', __FILE__); - return false; + static function addNew($profile, $notice) { + + $fave = null; + + if (Event::handle('StartFavorNotice', array($profile, $notice, &$fave))) { + + $fave = new Fave(); + + $fave->user_id = $profile->id; + $fave->notice_id = $notice->id; + + if (!$fave->insert()) { + common_log_db_error($fave, 'INSERT', __FILE__); + return false; + } + + Event::handle('EndFavorNotice', array($profile, $notice)); } + return $fave; } + function delete() + { + $profile = Profile::staticGet('id', $this->user_id); + $notice = Notice::staticGet('id', $this->notice_id); + + $result = null; + + if (Event::handle('StartDisfavorNotice', array($profile, $notice, &$result))) { + + $result = parent::delete(); + + if ($result) { + Event::handle('EndDisfavorNotice', array($profile, $notice)); + } + } + + return $result; + } + function pkeyGet($kv) { return Memcached_DataObject::pkeyGet('Fave', $kv); diff --git a/classes/Memcached_DataObject.php b/classes/Memcached_DataObject.php index 40576dc71..bc4c3a000 100644 --- a/classes/Memcached_DataObject.php +++ b/classes/Memcached_DataObject.php @@ -501,7 +501,11 @@ class Memcached_DataObject extends Safe_DataObject function raiseError($message, $type = null, $behaviour = null) { - throw new ServerException("DB_DataObject error [$type]: $message"); + $id = get_class($this); + if ($this->id) { + $id .= ':' . $this->id; + } + throw new ServerException("[$id] DB_DataObject error [$type]: $message"); } static function cacheGet($keyPart) diff --git a/classes/Notice.php b/classes/Notice.php index 73b22d58a..e8d5c45cb 100644 --- a/classes/Notice.php +++ b/classes/Notice.php @@ -187,13 +187,21 @@ class Notice extends Memcached_DataObject * int 'location_ns' geoname namespace to interpret location_id * int 'reply_to'; notice ID this is a reply to * int 'repeat_of'; notice ID this is a repeat of - * string 'uri' permalink to notice; defaults to local notice URL + * string 'uri' unique ID for notice; defaults to local notice URL + * string 'url' permalink to notice; defaults to local notice URL + * string 'rendered' rendered HTML version of content + * array 'replies' list of profile URIs for reply delivery in + * place of extracting @-replies from content. + * array 'groups' list of group IDs to deliver to, in place of + * extracting ! tags from content + * @fixme tag override * * @return Notice * @throws ClientException */ static function saveNew($profile_id, $content, $source, $options=null) { $defaults = array('uri' => null, + 'url' => null, 'reply_to' => null, 'repeat_of' => null); @@ -256,9 +264,16 @@ class Notice extends Memcached_DataObject } $notice->content = $final; - $notice->rendered = common_render_content($final, $notice); + + if (!empty($rendered)) { + $notice->rendered = $rendered; + } else { + $notice->rendered = common_render_content($final, $notice); + } + $notice->source = $source; $notice->uri = $uri; + $notice->url = $url; // Handle repeat case @@ -309,7 +324,8 @@ class Notice extends Memcached_DataObject // the beginning of a new conversation. if (empty($notice->conversation)) { - $notice->conversation = $notice->id; + $conv = Conversation::create(); + $notice->conversation = $conv->id; $changed = true; } @@ -324,21 +340,35 @@ class Notice extends Memcached_DataObject # Clear the cache for subscribed users, so they'll update at next request # XXX: someone clever could prepend instead of clearing the cache + $notice->blowOnInsert(); + if (isset($replies)) { + $notice->saveKnownReplies($replies); + } else { + $notice->saveReplies(); + } + + if (isset($groups)) { + $notice->saveKnownGroups($groups); + } else { + $notice->saveGroups(); + } + $notice->distribute(); return $notice; } - function blowOnInsert() + function blowOnInsert($conversation = false) { self::blow('profile:notice_ids:%d', $this->profile_id); self::blow('public'); - if ($this->conversation != $this->id) { - self::blow('notice:conversation_ids:%d', $this->conversation); - } + // XXX: Before we were blowing the casche only if the notice id + // was not the root of the conversation. What to do now? + + self::blow('notice:conversation_ids:%d', $this->conversation); if (!empty($this->repeat_of)) { self::blow('notice:repeats:%d', $this->repeat_of); @@ -675,11 +705,39 @@ class Notice extends Memcached_DataObject return $ni; } - function addToInboxes($groups, $recipients) + /** + * Adds this notice to the inboxes of each local user who should receive + * it, based on author subscriptions, group memberships, and @-replies. + * + * Warning: running a second time currently will make items appear + * multiple times in users' inboxes. + * + * @fixme make more robust against errors + * @fixme break up massive deliveries to smaller background tasks + * + * @param array $groups optional list of Group objects; + * if left empty, will be loaded from group_inbox records + * @param array $recipient optional list of reply profile ids + * if left empty, will be loaded from reply records + */ + function addToInboxes($groups=null, $recipients=null) { $ni = $this->whoGets($groups, $recipients); - Inbox::bulkInsert($this->id, array_keys($ni)); + $ids = array_keys($ni); + + // We remove the author (if they're a local user), + // since we'll have already done this in distribute() + + $i = array_search($this->profile_id, $ids); + + if ($i !== false) { + unset($ids[$i]); + } + + // Bulk insert + + Inbox::bulkInsert($this->id, $ids); return; } @@ -712,6 +770,42 @@ class Notice extends Memcached_DataObject } /** + * Record this notice to the given group inboxes for delivery. + * Overrides the regular parsing of !group markup. + * + * @param string $group_ids + * @fixme might prefer URIs as identifiers, as for replies? + * best with generalizations on user_group to support + * remote groups better. + */ + function saveKnownGroups($group_ids) + { + if (!is_array($group_ids)) { + throw new ServerException("Bad type provided to saveKnownGroups"); + } + + $groups = array(); + foreach ($group_ids as $id) { + $group = User_group::staticGet('id', $id); + if ($group) { + common_log(LOG_ERR, "Local delivery to group id $id, $group->nickname"); + $result = $this->addToGroupInbox($group); + if (!$result) { + common_log_db_error($gi, 'INSERT', __FILE__); + } + + // @fixme should we save the tags here or not? + $groups[] = clone($group); + } else { + common_log(LOG_ERR, "Local delivery to group id $id skipped, doesn't exist"); + } + } + + return $groups; + } + + /** + * Parse !group delivery and record targets into group_inbox. * @return array of Group objects */ function saveGroups() @@ -795,8 +889,49 @@ class Notice extends Memcached_DataObject } /** + * Save reply records indicating that this notice needs to be + * delivered to the local users with the given URIs. + * + * Since this is expected to be used when saving foreign-sourced + * messages, we won't deliver to any remote targets as that's the + * source service's responsibility. + * + * @fixme Unlike saveReplies() there's no mail notification here. + * Move that to distrib queue handler? + * + * @param array of unique identifier URIs for recipients + */ + function saveKnownReplies($uris) + { + foreach ($uris as $uri) { + + $user = User::staticGet('uri', $uri); + + if (!empty($user)) { + + $reply = new Reply(); + + $reply->notice_id = $this->id; + $reply->profile_id = $user->id; + + $id = $reply->insert(); + } + } + + return; + } + + /** + * Pull @-replies from this message's content in StatusNet markup format + * and save reply records indicating that this message needs to be + * delivered to those users. + * + * Side effect: local recipients get e-mail notifications here. + * @fixme move mail notifications to distrib? + * * @return array of integer profile IDs */ + function saveReplies() { // Don't save reply data for repeats @@ -805,76 +940,44 @@ class Notice extends Memcached_DataObject return array(); } - // Alternative reply format - $tname = false; - if (preg_match('/^T ([A-Z0-9]{1,64}) /', $this->content, $match)) { - $tname = $match[1]; - } - // extract all @messages - $cnt = preg_match_all('/(?:^|\s)@([a-z0-9]{1,64})/', $this->content, $match); - - $names = array(); - - if ($cnt || $tname) { - // XXX: is there another way to make an array copy? - $names = ($tname) ? array_unique(array_merge(array(strtolower($tname)), $match[1])) : array_unique($match[1]); - } - $sender = Profile::staticGet($this->profile_id); + $mentions = common_find_mentions($this->profile_id, $this->content); + $replied = array(); // store replied only for first @ (what user/notice what the reply directed, // we assume first @ is it) - for ($i=0; $i<count($names); $i++) { - $nickname = $names[$i]; - $recipient = common_relative_profile($sender, $nickname, $this->created); - if (empty($recipient)) { - continue; - } - // Don't save replies from blocked profile to local user - $recipient_user = User::staticGet('id', $recipient->id); - if (!empty($recipient_user) && $recipient_user->hasBlocked($sender)) { - continue; - } - $reply = new Reply(); - $reply->notice_id = $this->id; - $reply->profile_id = $recipient->id; - $id = $reply->insert(); - if (!$id) { - $last_error = &PEAR::getStaticProperty('DB_DataObject','lastError'); - common_log(LOG_ERR, 'DB error inserting reply: ' . $last_error->message); - common_server_error(sprintf(_('DB error inserting reply: %s'), $last_error->message)); - return array(); - } else { - $replied[$recipient->id] = 1; - } - } + foreach ($mentions as $mention) { - // Hash format replies, too - $cnt = preg_match_all('/(?:^|\s)@#([a-z0-9]{1,64})/', $this->content, $match); - if ($cnt) { - foreach ($match[1] as $tag) { - $tagged = Profile_tag::getTagged($sender->id, $tag); - foreach ($tagged as $t) { - if (!$replied[$t->id]) { - // Don't save replies from blocked profile to local user - $t_user = User::staticGet('id', $t->id); - if ($t_user && $t_user->hasBlocked($sender)) { - continue; - } - $reply = new Reply(); - $reply->notice_id = $this->id; - $reply->profile_id = $t->id; - $id = $reply->insert(); - if (!$id) { - common_log_db_error($reply, 'INSERT', __FILE__); - return array(); - } else { - $replied[$recipient->id] = 1; - } - } + foreach ($mention['mentioned'] as $mentioned) { + + // skip if they're already covered + + if (!empty($replied[$mentioned->id])) { + continue; + } + + // Don't save replies from blocked profile to local user + + $mentioned_user = User::staticGet('id', $mentioned->id); + if (!empty($mentioned_user) && $mentioned_user->hasBlocked($sender)) { + continue; + } + + $reply = new Reply(); + + $reply->notice_id = $this->id; + $reply->profile_id = $mentioned->id; + + $id = $reply->insert(); + + if (!$id) { + common_log_db_error($reply, 'INSERT', __FILE__); + throw new ServerException("Couldn't save reply for {$this->id}, {$mentioned->id}"); + } else { + $replied[$mentioned->id] = 1; } } } @@ -915,9 +1018,10 @@ class Notice extends Memcached_DataObject } /** - * Same calculation as saveGroups but without the saving - * @fixme merge the functions - * @return array of Group_inbox objects + * Pull list of groups this notice needs to be delivered to, + * as previously recorded by saveGroups() or saveKnownGroups(). + * + * @return array of Group objects */ function getGroups() { @@ -940,7 +1044,10 @@ class Notice extends Memcached_DataObject if ($gi->find()) { while ($gi->fetch()) { - $groups[] = clone($gi); + $group = User_group::staticGet('id', $gi->group_id); + if ($group) { + $groups[] = $group; + } } } @@ -960,6 +1067,7 @@ class Notice extends Memcached_DataObject 'xmlns:thr' => 'http://purl.org/syndication/thread/1.0', 'xmlns:georss' => 'http://www.georss.org/georss', 'xmlns:activity' => 'http://activitystrea.ms/spec/1.0/', + 'xmlns:poco' => 'http://portablecontacts.net/spec/1.0', 'xmlns:ostatus' => 'http://ostatus.org/schema/1.0'); } else { $attrs = array(); @@ -997,6 +1105,7 @@ class Notice extends Memcached_DataObject $xs->raw($profile->asActivityActor()); $xs->element('link', array('rel' => 'alternate', + 'type' => 'text/html', 'href' => $this->bestUrl())); $xs->element('id', null, $this->uri); @@ -1015,33 +1124,45 @@ class Notice extends Memcached_DataObject } } - if (!empty($this->conversation) - && $this->conversation != $this->id) { - $xs->element( - 'link', array( - 'rel' => 'ostatus:conversation', - 'href' => common_local_url( - 'conversation', - array('id' => $this->conversation) - ) + if (!empty($this->conversation)) { + + $conv = Conversation::staticGet('id', $this->conversation); + + if (!empty($conv)) { + $xs->element( + 'link', array( + 'rel' => 'ostatus:conversation', + 'href' => $conv->uri ) ); + } } $reply_ids = $this->getReplies(); foreach ($reply_ids as $id) { $profile = Profile::staticGet('id', $id); - if (!empty($profile)) { + if (!empty($profile)) { $xs->element( 'link', array( 'rel' => 'ostatus:attention', - 'href' => $profile->getAcctUri() + 'href' => $profile->getUri() ) ); } } + $groups = $this->getGroups(); + + foreach ($groups as $group) { + $xs->element( + 'link', array( + 'rel' => 'ostatus:attention', + 'href' => $group->permalink() + ) + ); + } + if (!empty($this->repeat_of)) { $repeat = Notice::staticGet('id', $this->repeat_of); if (!empty($repeat)) { @@ -1087,6 +1208,21 @@ class Notice extends Memcached_DataObject return $xs->getString(); } + /** + * Returns an XML string fragment with a reference to a notice as an + * Activity Streams noun object with the given element type. + * + * Assumes that 'activity' namespace has been previously defined. + * + * @param string $element one of 'subject', 'object', 'target' + * @return string + */ + function asActivityNoun($element) + { + $noun = ActivityObject::fromNotice($this); + return $noun->asString('activity:' . $element); + } + function bestUrl() { if (!empty($this->url)) { @@ -1484,6 +1620,14 @@ class Notice extends Memcached_DataObject function distribute() { + // We always insert for the author so they don't + // have to wait + + $user = User::staticGet('id', $this->profile_id); + if (!empty($user)) { + Inbox::insertNotice($user->id, $this->id); + } + if (common_config('queue', 'inboxes')) { // If there's a failure, we want to _force_ // distribution at this point. diff --git a/classes/Profile.php b/classes/Profile.php index ab05bb854..78223b34a 100644 --- a/classes/Profile.php +++ b/classes/Profile.php @@ -769,7 +769,7 @@ class Profile extends Memcached_DataObject $xs->elementStart('author'); $xs->element('name', null, $this->nickname); - $xs->element('uri', null, $this->profileurl); + $xs->element('uri', null, $this->getUri()); $xs->elementEnd('author'); return $xs->getString(); @@ -792,51 +792,59 @@ class Profile extends Memcached_DataObject * Returns an XML string fragment with profile information as an * Activity Streams noun object with the given element type. * - * Assumes that 'activity' namespace has been previously defined. + * Assumes that 'activity', 'georss', and 'poco' namespace has been + * previously defined. * * @param string $element one of 'actor', 'subject', 'object', 'target' + * * @return string */ function asActivityNoun($element) { - $xs = new XMLStringer(true); + $noun = ActivityObject::fromProfile($this); + return $noun->asString('activity:' . $element); + } - $xs->elementStart('activity:' . $element); - $xs->element( - 'activity:object-type', - null, - 'http://activitystrea.ms/schema/1.0/person' - ); - $xs->element( - 'id', - null, - common_local_url( - 'userbyid', - array('id' => $this->id) - ) - ); - $xs->element('title', null, $this->getBestName()); - - $avatar = $this->getAvatar(AVATAR_PROFILE_SIZE); - - $xs->element( - 'link', array( - 'type' => empty($avatar) ? 'image/png' : $avatar->mediatype, - 'href' => empty($avatar) - ? Avatar::defaultImage(AVATAR_PROFILE_SIZE) - : $avatar->displayUrl() - ), - '' - ); - - $xs->elementEnd('activity:' . $element); + /** + * Returns the best URI for a profile. Plugins may override. + * + * @return string $uri + */ + function getUri() + { + $uri = null; - return $xs->getString(); + // give plugins a chance to set the URI + if (Event::handle('StartGetProfileUri', array($this, &$uri))) { + + // check for a local user first + $user = User::staticGet('id', $this->id); + + if (!empty($user)) { + $uri = $user->uri; + } else { + // return OMB profile if any + $remote = Remote_profile::staticGet('id', $this->id); + if (!empty($remote)) { + $uri = $remote->uri; + } + } + Event::handle('EndGetProfileUri', array($this, &$uri)); + } + + return $uri; } - function getAcctUri() + function hasBlocked($other) { - return $this->nickname . '@' . common_config('site', 'server'); - } + $block = Profile_block::get($this->id, $other->id); + if (empty($block)) { + $result = false; + } else { + $result = true; + } + + return $result; + } } diff --git a/classes/Subscription.php b/classes/Subscription.php index faf1331cd..d6fb3fcbd 100644 --- a/classes/Subscription.php +++ b/classes/Subscription.php @@ -24,7 +24,7 @@ if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); } */ require_once INSTALLDIR.'/classes/Memcached_DataObject.php'; -class Subscription extends Memcached_DataObject +class Subscription extends Memcached_DataObject { ###START_AUTOCODE /* the code below is auto generated do not remove the above tag */ @@ -34,8 +34,8 @@ class Subscription extends Memcached_DataObject public $subscribed; // int(4) primary_key not_null public $jabber; // tinyint(1) default_1 public $sms; // tinyint(1) default_1 - public $token; // varchar(255) - public $secret; // varchar(255) + public $token; // varchar(255) + public $secret; // varchar(255) public $created; // datetime() not_null public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP @@ -45,9 +45,155 @@ class Subscription extends Memcached_DataObject /* the code above is auto generated do not remove the tag below */ ###END_AUTOCODE - + function pkeyGet($kv) { return Memcached_DataObject::pkeyGet('Subscription', $kv); } + + /** + * Make a new subscription + * + * @param Profile $subscriber party to receive new notices + * @param Profile $other party sending notices; publisher + * + * @return Subscription new subscription + */ + + static function start($subscriber, $other) + { + if (!$subscriber->hasRight(Right::SUBSCRIBE)) { + throw new Exception(_('You have been banned from subscribing.')); + } + + if (self::exists($subscriber, $other)) { + throw new Exception(_('Already subscribed!')); + } + + if ($other->hasBlocked($subscriber)) { + throw new Exception(_('User has blocked you.')); + } + + if (Event::handle('StartSubscribe', array($subscriber, $other))) { + + $sub = new Subscription(); + + $sub->subscriber = $subscriber->id; + $sub->subscribed = $other->id; + $sub->created = common_sql_now(); + + $result = $sub->insert(); + + if (!$result) { + common_log_db_error($sub, 'INSERT', __FILE__); + throw new Exception(_('Could not save subscription.')); + } + + $sub->notify(); + + self::blow('user:notices_with_friends:%d', $subscriber->id); + + $subscriber->blowSubscriptionsCount(); + $other->blowSubscribersCount(); + + $otherUser = User::staticGet('id', $other->id); + + if (!empty($otherUser) && + $otherUser->autosubscribe && + !self::exists($other, $subscriber) && + !$subscriber->hasBlocked($other)) { + + $auto = new Subscription(); + + $auto->subscriber = $subscriber->id; + $auto->subscribed = $other->id; + $auto->created = common_sql_now(); + + $result = $auto->insert(); + + if (!$result) { + common_log_db_error($auto, 'INSERT', __FILE__); + throw new Exception(_('Could not save subscription.')); + } + + $auto->notify(); + } + + Event::handle('EndSubscribe', array($subscriber, $other)); + } + + return true; + } + + function notify() + { + # XXX: add other notifications (Jabber, SMS) here + # XXX: queue this and handle it offline + # XXX: Whatever happens, do it in Twitter-like API, too + + $this->notifyEmail(); + } + + function notifyEmail() + { + $subscribedUser = User::staticGet('id', $this->subscribed); + + if (!empty($subscribedUser)) { + + $subscriber = Profile::staticGet('id', $this->subscriber); + + mail_subscribe_notify_profile($subscribedUser, $subscriber); + } + } + + /** + * Cancel a subscription + * + */ + + function cancel($subscriber, $other) + { + if (!self::exists($subscriber, $other)) { + throw new Exception(_('Not subscribed!')); + } + + // Don't allow deleting self subs + + if ($subscriber->id == $other->id) { + throw new Exception(_('Couldn\'t delete self-subscription.')); + } + + if (Event::handle('StartUnsubscribe', array($subscriber, $other))) { + + $sub = Subscription::pkeyGet(array('subscriber' => $subscriber->id, + 'subscribed' => $other->id)); + + // note we checked for existence above + + assert(!empty($sub)); + + $result = $sub->delete(); + + if (!$result) { + common_log_db_error($sub, 'DELETE', __FILE__); + throw new Exception(_('Couldn\'t delete subscription.')); + } + + self::blow('user:notices_with_friends:%d', $subscriber->id); + + $subscriber->blowSubscriptionsCount(); + $other->blowSubscribersCount(); + + Event::handle('EndUnsubscribe', array($subscriber, $other)); + } + + return; + } + + function exists($subscriber, $other) + { + $sub = Subscription::pkeyGet(array('subscriber' => $subscriber->id, + 'subscribed' => $other->id)); + return (empty($sub)) ? false : true; + } } diff --git a/classes/User.php b/classes/User.php index 1c967b527..0f84ed813 100644 --- a/classes/User.php +++ b/classes/User.php @@ -75,11 +75,7 @@ class User extends Memcached_DataObject function isSubscribed($other) { - assert(!is_null($other)); - // XXX: cache results of this query - $sub = Subscription::pkeyGet(array('subscriber' => $this->id, - 'subscribed' => $other->id)); - return (is_null($sub)) ? false : true; + return Subscription::exists($this->getProfile(), $other); } // 'update' won't write key columns, so we have to do it ourselves. @@ -162,17 +158,8 @@ class User extends Memcached_DataObject function hasBlocked($other) { - - $block = Profile_block::get($this->id, $other->id); - - if (is_null($block)) { - $result = false; - } else { - $result = true; - $block->free(); - } - - return $result; + $profile = $this->getProfile(); + return $profile->hasBlocked($other); } /** diff --git a/classes/User_group.php b/classes/User_group.php index 379e6b721..1382aa407 100644 --- a/classes/User_group.php +++ b/classes/User_group.php @@ -39,14 +39,24 @@ class User_group extends Memcached_DataObject function homeUrl() { - return common_local_url('showgroup', - array('nickname' => $this->nickname)); + $url = null; + if (Event::handle('StartUserGroupHomeUrl', array($this, &$url))) { + $url = common_local_url('showgroup', + array('nickname' => $this->nickname)); + } + Event::handle('EndUserGroupHomeUrl', array($this, &$url)); + return $url; } function permalink() { - return common_local_url('groupbyid', - array('id' => $this->id)); + $url = null; + if (Event::handle('StartUserGroupPermalink', array($this, &$url))) { + $url = common_local_url('groupbyid', + array('id' => $this->id)); + } + Event::handle('EndUserGroupPermalink', array($this, &$url)); + return $url; } function getNotices($offset, $limit, $since_id=null, $max_id=null) diff --git a/classes/statusnet.ini b/classes/statusnet.ini index bcff744bd..d116b16a3 100644 --- a/classes/statusnet.ini +++ b/classes/statusnet.ini @@ -47,6 +47,16 @@ modified = 384 [consumer__keys] consumer_key = K +[conversation] +id = 129 +uri = 2 +created = 142 +modified = 384 + +[conversation__keys] +id = N +uri = U + [deleted_notice] id = 129 profile_id = 129 |