X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=classes%2FProfile.php;h=54f557ea7cee40201f631ca7aa1416731b3693b4;hb=fa4a2d34855da5eca29d81409cb5fbd64f13faba;hp=1076fb2cb3e09f8b95b1915b36f1b6bb5ffbcef6;hpb=c9c7bb3234f8ede65c328ecf9f713b189a81faad;p=quix0rs-gnu-social.git diff --git a/classes/Profile.php b/classes/Profile.php index 1076fb2cb3..54f557ea7c 100644 --- a/classes/Profile.php +++ b/classes/Profile.php @@ -147,14 +147,16 @@ class Profile extends Memcached_DataObject return ($this->fullname) ? $this->fullname : $this->nickname; } - # Get latest notice on or before date; default now - function getCurrentNotice($dt=null) + /** + * Get the most recent notice posted by this user, if any. + * + * @return mixed Notice or null + */ + function getCurrentNotice() { $notice = new Notice(); $notice->profile_id = $this->id; - if ($dt) { - $notice->whereAdd('created < "' . $dt . '"'); - } + // @fixme change this to sort on notice.id only when indexes are updated $notice->orderBy('created DESC, notice.id DESC'); $notice->limit(1); if ($notice->find(true)) { @@ -163,27 +165,27 @@ class Profile extends Memcached_DataObject return null; } - function getTaggedNotices($tag, $offset=0, $limit=NOTICES_PER_PAGE, $since_id=0, $max_id=0, $since=null) + function getTaggedNotices($tag, $offset=0, $limit=NOTICES_PER_PAGE, $since_id=0, $max_id=0) { $ids = Notice::stream(array($this, '_streamTaggedDirect'), array($tag), 'profile:notice_ids_tagged:' . $this->id . ':' . $tag, - $offset, $limit, $since_id, $max_id, $since); + $offset, $limit, $since_id, $max_id); return Notice::getStreamByIds($ids); } - function getNotices($offset=0, $limit=NOTICES_PER_PAGE, $since_id=0, $max_id=0, $since=null) + function getNotices($offset=0, $limit=NOTICES_PER_PAGE, $since_id=0, $max_id=0) { // XXX: I'm not sure this is going to be any faster. It probably isn't. $ids = Notice::stream(array($this, '_streamDirect'), array(), 'profile:notice_ids:' . $this->id, - $offset, $limit, $since_id, $max_id, $since); + $offset, $limit, $since_id, $max_id); return Notice::getStreamByIds($ids); } - function _streamTaggedDirect($tag, $offset, $limit, $since_id, $max_id, $since) + function _streamTaggedDirect($tag, $offset, $limit, $since_id, $max_id) { // XXX It would be nice to do this without a join @@ -202,10 +204,6 @@ class Profile extends Memcached_DataObject $query .= " and id < $max_id"; } - if (!is_null($since)) { - $query .= " and created > '" . date('Y-m-d H:i:s', $since) . "'"; - } - $query .= ' order by id DESC'; if (!is_null($offset)) { @@ -223,39 +221,66 @@ class Profile extends Memcached_DataObject return $ids; } - function _streamDirect($offset, $limit, $since_id, $max_id, $since = null) + function _streamDirect($offset, $limit, $since_id, $max_id) { $notice = new Notice(); - $notice->profile_id = $this->id; + // Temporary hack until notice_profile_id_idx is updated + // to (profile_id, id) instead of (profile_id, created, id). + // It's been falling back to PRIMARY instead, which is really + // very inefficient for a profile that hasn't posted in a few + // months. Even though forcing the index will cause a filesort, + // it's usually going to be better. + if (common_config('db', 'type') == 'mysql') { + $index = ''; + $query = + "select id from notice force index (notice_profile_id_idx) ". + "where profile_id=" . $notice->escape($this->id); + + if ($since_id != 0) { + $query .= " and id > $since_id"; + } - $notice->selectAdd(); - $notice->selectAdd('id'); + if ($max_id != 0) { + $query .= " and id < $max_id"; + } - if ($since_id != 0) { - $notice->whereAdd('id > ' . $since_id); - } + $query .= ' order by id DESC'; - if ($max_id != 0) { - $notice->whereAdd('id <= ' . $max_id); - } + if (!is_null($offset)) { + $query .= " LIMIT $limit OFFSET $offset"; + } - if (!is_null($since)) { - $notice->whereAdd('created > \'' . date('Y-m-d H:i:s', $since) . '\''); - } + $notice->query($query); + } else { + $index = ''; - $notice->orderBy('id DESC'); + $notice->profile_id = $this->id; - if (!is_null($offset)) { - $notice->limit($offset, $limit); + $notice->selectAdd(); + $notice->selectAdd('id'); + + if ($since_id != 0) { + $notice->whereAdd('id > ' . $since_id); + } + + if ($max_id != 0) { + $notice->whereAdd('id <= ' . $max_id); + } + + $notice->orderBy('id DESC'); + + if (!is_null($offset)) { + $notice->limit($offset, $limit); + } + + $notice->find(); } $ids = array(); - if ($notice->find()) { - while ($notice->fetch()) { - $ids[] = $notice->id; - } + while ($notice->fetch()) { + $ids[] = $notice->id; } return $ids; @@ -290,6 +315,32 @@ class Profile extends Memcached_DataObject } } + function getGroups($offset=0, $limit=null) + { + $qry = + 'SELECT user_group.* ' . + 'FROM user_group JOIN group_member '. + 'ON user_group.id = group_member.group_id ' . + 'WHERE group_member.profile_id = %d ' . + 'ORDER BY group_member.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; + } + } + } + + $groups = new User_group(); + + $cnt = $groups->query(sprintf($qry, $this->id)); + + return $groups; + } + function avatarUrl($size=AVATAR_PROFILE_SIZE) { $avatar = $this->getAvatar($size); @@ -557,11 +608,41 @@ class Profile extends Memcached_DataObject { $sub = new Subscription(); $sub->subscriber = $this->id; - $sub->delete(); + + $sub->find(); + + while ($sub->fetch()) { + $other = Profile::staticGet('id', $sub->subscribed); + if (empty($other)) { + continue; + } + if ($other->id == $this->id) { + continue; + } + Subscription::cancel($this, $other); + } $subd = new Subscription(); $subd->subscribed = $this->id; - $subd->delete(); + $subd->find(); + + while ($subd->fetch()) { + $other = Profile::staticGet('id', $subd->subscriber); + if (empty($other)) { + continue; + } + if ($other->id == $this->id) { + continue; + } + Subscription::cancel($other, $this); + } + + $self = new Subscription(); + + $self->subscriber = $this->id; + $self->subscribed = $this->id; + + $self->delete(); } function _deleteMessages() @@ -712,10 +793,14 @@ class Profile extends Memcached_DataObject function hasRight($right) { $result = false; + if ($this->hasRole(Profile_role::DELETED)) { + return false; + } if (Event::handle('UserRightsCheck', array($this, $right, &$result))) { switch ($right) { case Right::DELETEOTHERSNOTICE: + case Right::MAKEGROUPADMIN: case Right::SANDBOXUSER: case Right::SILENCEUSER: case Right::DELETEUSER: @@ -724,6 +809,10 @@ class Profile extends Memcached_DataObject case Right::CONFIGURESITE: $result = $this->hasRole(Profile_role::ADMINISTRATOR); break; + case Right::GRANTROLE: + case Right::REVOKEROLE: + $result = $this->hasRole(Profile_role::OWNER); + break; case Right::NEWNOTICE: case Right::NEWMESSAGE: case Right::SUBSCRIBE: @@ -753,4 +842,97 @@ class Profile extends Memcached_DataObject return !empty($notice); } + + /** + * Returns an XML string fragment with limited profile information + * as an Atom element. + * + * Assumes that Atom has been previously set up as the base namespace. + * + * @return string + */ + function asAtomAuthor() + { + $xs = new XMLStringer(true); + + $xs->elementStart('author'); + $xs->element('name', null, $this->nickname); + $xs->element('uri', null, $this->getUri()); + $xs->elementEnd('author'); + + return $xs->getString(); + } + + /** + * Returns an XML string fragment with profile information as an + * Activity Streams element. + * + * Assumes that 'activity' namespace has been previously defined. + * + * @return string + */ + function asActivityActor() + { + return $this->asActivityNoun('actor'); + } + + /** + * Returns an XML string fragment with profile information as an + * Activity Streams noun object with the given element type. + * + * 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) + { + $noun = ActivityObject::fromProfile($this); + return $noun->asString('activity:' . $element); + } + + /** + * Returns the best URI for a profile. Plugins may override. + * + * @return string $uri + */ + function getUri() + { + $uri = null; + + // 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 hasBlocked($other) + { + $block = Profile_block::get($this->id, $other->id); + + if (empty($block)) { + $result = false; + } else { + $result = true; + } + + return $result; + } }