X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=classes%2FProfile.php;h=494c697e425fab0fa9726cba9bf0aac41635e2ff;hb=3cb6b1670bd7e3860fdca217e4075f51378fe5e0;hp=a0ed6b3ca349e0da83dc161a409893f821cdb8af;hpb=612a107e09619b92d4614e2f3076ddca5c65824c;p=quix0rs-gnu-social.git diff --git a/classes/Profile.php b/classes/Profile.php index a0ed6b3ca3..494c697e42 100644 --- a/classes/Profile.php +++ b/classes/Profile.php @@ -1,7 +1,7 @@ . */ -if (!defined('LACONICA')) { exit(1); } +if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); } /** * Table Definition for profile @@ -35,18 +35,28 @@ class Profile extends Memcached_DataObject public $fullname; // varchar(255) multiple_key public $profileurl; // varchar(255) public $homepage; // varchar(255) multiple_key - public $bio; // varchar(140) multiple_key + public $bio; // text() multiple_key public $location; // varchar(255) multiple_key + public $lat; // decimal(10,7) + public $lon; // decimal(10,7) + public $location_id; // int(4) + public $location_ns; // int(4) public $created; // datetime() not_null public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP /* Static get */ - function staticGet($k,$v=null) - { return Memcached_DataObject::staticGet('Profile',$k,$v); } + function staticGet($k,$v=NULL) { + return Memcached_DataObject::staticGet('Profile',$k,$v); + } /* the code above is auto generated do not remove the tag below */ ###END_AUTOCODE + function getUser() + { + return User::staticGet('id', $this->id); + } + function getAvatar($width, $height=null) { if (is_null($height)) { @@ -199,7 +209,7 @@ class Profile extends Memcached_DataObject $query .= ' order by id DESC'; if (!is_null($offset)) { - $query .= " limit $offset, $limit"; + $query .= " LIMIT $limit OFFSET $offset"; } $notice->query($query); @@ -300,10 +310,12 @@ class Profile extends Memcached_DataObject 'AND subscription.subscribed != subscription.subscriber ' . 'ORDER BY subscription.created DESC '; - if (common_config('db','type') == 'pgsql') { - $qry .= ' LIMIT ' . $limit . ' OFFSET ' . $offset; - } else { - $qry .= ' LIMIT ' . $offset . ', ' . $limit; + if ($offset>0 && !is_null($limit)){ + if (common_config('db','type') == 'pgsql') { + $qry .= ' LIMIT ' . $limit . ' OFFSET ' . $offset; + } else { + $qry .= ' LIMIT ' . $offset . ', ' . $limit; + } } $profile = new Profile(); @@ -323,7 +335,34 @@ class Profile extends Memcached_DataObject 'AND subscription.subscribed != subscription.subscriber ' . 'ORDER BY subscription.created DESC '; - if ($offset) { + 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(); + + $cnt = $profile->query(sprintf($qry, $this->id)); + + return $profile; + } + + function getApplications($offset = 0, $limit = null) + { + $qry = + 'SELECT a.* ' . + '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 { @@ -331,10 +370,502 @@ class Profile extends Memcached_DataObject } } - $profile = new Profile(); + $application = new Oauth_application(); - $cnt = $profile->query(sprintf($qry, $this->id)); + $cnt = $application->query(sprintf($qry, $this->id)); - return $profile; + return $application; + } + + function subscriptionCount() + { + $c = common_memcache(); + + if (!empty($c)) { + $cnt = $c->get(common_cache_key('profile:subscription_count:'.$this->id)); + if (is_integer($cnt)) { + return (int) $cnt; + } + } + + $sub = new Subscription(); + $sub->subscriber = $this->id; + + $cnt = (int) $sub->count('distinct subscribed'); + + $cnt = ($cnt > 0) ? $cnt - 1 : $cnt; + + if (!empty($c)) { + $c->set(common_cache_key('profile:subscription_count:'.$this->id), $cnt); + } + + return $cnt; + } + + function subscriberCount() + { + $c = common_memcache(); + if (!empty($c)) { + $cnt = $c->get(common_cache_key('profile:subscriber_count:'.$this->id)); + if (is_integer($cnt)) { + return (int) $cnt; + } + } + + $sub = new Subscription(); + $sub->subscribed = $this->id; + + $cnt = (int) $sub->count('distinct subscriber'); + + $cnt = ($cnt > 0) ? $cnt - 1 : $cnt; + + if (!empty($c)) { + $c->set(common_cache_key('profile:subscriber_count:'.$this->id), $cnt); + } + + return $cnt; + } + + function faveCount() + { + $c = common_memcache(); + if (!empty($c)) { + $cnt = $c->get(common_cache_key('profile:fave_count:'.$this->id)); + if (is_integer($cnt)) { + return (int) $cnt; + } + } + + $faves = new Fave(); + $faves->user_id = $this->id; + $cnt = (int) $faves->count('distinct notice_id'); + + if (!empty($c)) { + $c->set(common_cache_key('profile:fave_count:'.$this->id), $cnt); + } + + return $cnt; + } + + function noticeCount() + { + $c = common_memcache(); + + if (!empty($c)) { + $cnt = $c->get(common_cache_key('profile:notice_count:'.$this->id)); + if (is_integer($cnt)) { + return (int) $cnt; + } + } + + $notices = new Notice(); + $notices->profile_id = $this->id; + $cnt = (int) $notices->count('distinct id'); + + if (!empty($c)) { + $c->set(common_cache_key('profile:notice_count:'.$this->id), $cnt); + } + + return $cnt; + } + + function blowSubscriberCount() + { + $c = common_memcache(); + if (!empty($c)) { + $c->delete(common_cache_key('profile:subscriber_count:'.$this->id)); + } + } + + function blowSubscriptionCount() + { + $c = common_memcache(); + if (!empty($c)) { + $c->delete(common_cache_key('profile:subscription_count:'.$this->id)); + } + } + + function blowFaveCount() + { + $c = common_memcache(); + if (!empty($c)) { + $c->delete(common_cache_key('profile:fave_count:'.$this->id)); + } + } + + function blowNoticeCount() + { + $c = common_memcache(); + if (!empty($c)) { + $c->delete(common_cache_key('profile:notice_count:'.$this->id)); + } + } + + static function maxBio() + { + $biolimit = common_config('profile', 'biolimit'); + // null => use global limit (distinct from 0!) + if (is_null($biolimit)) { + $biolimit = common_config('site', 'textlimit'); + } + return $biolimit; + } + + static function bioTooLong($bio) + { + $biolimit = self::maxBio(); + return ($biolimit > 0 && !empty($bio) && (mb_strlen($bio) > $biolimit)); + } + + function delete() + { + $this->_deleteNotices(); + $this->_deleteSubscriptions(); + $this->_deleteMessages(); + $this->_deleteTags(); + $this->_deleteBlocks(); + + $related = array('Avatar', + 'Reply', + 'Group_member', + ); + Event::handle('ProfileDeleteRelated', array($this, &$related)); + + foreach ($related as $cls) { + $inst = new $cls(); + $inst->profile_id = $this->id; + $inst->delete(); + } + + parent::delete(); + } + + function _deleteNotices() + { + $notice = new Notice(); + $notice->profile_id = $this->id; + + if ($notice->find()) { + while ($notice->fetch()) { + $other = clone($notice); + $other->delete(); + } + } } + + function _deleteSubscriptions() + { + $sub = new Subscription(); + $sub->subscriber = $this->id; + $sub->delete(); + + $subd = new Subscription(); + $subd->subscribed = $this->id; + $subd->delete(); + } + + function _deleteMessages() + { + $msg = new Message(); + $msg->from_profile = $this->id; + $msg->delete(); + + $msg = new Message(); + $msg->to_profile = $this->id; + $msg->delete(); + } + + function _deleteTags() + { + $tag = new Profile_tag(); + $tag->tagged = $this->id; + $tag->delete(); + } + + function _deleteBlocks() + { + $block = new Profile_block(); + $block->blocked = $this->id; + $block->delete(); + + $block = new Group_block(); + $block->blocked = $this->id; + $block->delete(); + } + + // XXX: identical to Notice::getLocation. + + function getLocation() + { + $location = null; + + if (!empty($this->location_id) && !empty($this->location_ns)) { + $location = Location::fromId($this->location_id, $this->location_ns); + } + + if (is_null($location)) { // no ID, or Location::fromId() failed + if (!empty($this->lat) && !empty($this->lon)) { + $location = Location::fromLatLon($this->lat, $this->lon); + } + } + + if (is_null($location)) { // still haven't found it! + if (!empty($this->location)) { + $location = Location::fromName($this->location); + } + } + + return $location; + } + + function hasRole($name) + { + $has_role = false; + if (Event::handle('StartHasRole', array($this, $name, &$has_role))) { + $role = Profile_role::pkeyGet(array('profile_id' => $this->id, + 'role' => $name)); + $has_role = !empty($role); + Event::handle('EndHasRole', array($this, $name, $has_role)); + } + return $has_role; + } + + function grantRole($name) + { + $role = new Profile_role(); + + $role->profile_id = $this->id; + $role->role = $name; + $role->created = common_sql_now(); + + $result = $role->insert(); + + if (!$result) { + common_log_db_error($role, 'INSERT', __FILE__); + return false; + } + + return true; + } + + function revokeRole($name) + { + $role = Profile_role::pkeyGet(array('profile_id' => $this->id, + 'role' => $name)); + + if (empty($role)) { + throw new Exception('Cannot revoke role "'.$name.'" for user #'.$this->id.'; does not exist.'); + } + + $result = $role->delete(); + + if (!$result) { + common_log_db_error($role, 'DELETE', __FILE__); + throw new Exception('Cannot revoke role "'.$name.'" for user #'.$this->id.'; database error.'); + } + + return true; + } + + function isSandboxed() + { + return $this->hasRole(Profile_role::SANDBOXED); + } + + function isSilenced() + { + return $this->hasRole(Profile_role::SILENCED); + } + + function sandbox() + { + $this->grantRole(Profile_role::SANDBOXED); + } + + function unsandbox() + { + $this->revokeRole(Profile_role::SANDBOXED); + } + + function silence() + { + $this->grantRole(Profile_role::SILENCED); + } + + function unsilence() + { + $this->revokeRole(Profile_role::SILENCED); + } + + /** + * Does this user have the right to do X? + * + * With our role-based authorization, this is merely a lookup for whether the user + * has a particular role. The implementation currently uses a switch statement + * to determine if the user has the pre-defined role to exercise the right. Future + * implementations may allow per-site roles, and different mappings of roles to rights. + * + * @param $right string Name of the right, usually a constant in class Right + * @return boolean whether the user has the right in question + */ + + function hasRight($right) + { + $result = 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: + $result = $this->hasRole(Profile_role::MODERATOR); + break; + case Right::CONFIGURESITE: + $result = $this->hasRole(Profile_role::ADMINISTRATOR); + break; + case Right::NEWNOTICE: + case Right::NEWMESSAGE: + case Right::SUBSCRIBE: + $result = !$this->isSilenced(); + break; + case Right::PUBLICNOTICE: + case Right::EMAILONREPLY: + case Right::EMAILONSUBSCRIBE: + case Right::EMAILONFAVE: + $result = !$this->isSandboxed(); + break; + default: + $result = false; + break; + } + } + return $result; + } + + function hasRepeated($notice_id) + { + // XXX: not really a pkey, but should work + + $notice = Memcached_DataObject::pkeyGet('Notice', + array('profile_id' => $this->id, + 'repeat_of' => $notice_id)); + + 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' namespace has been previously defined. + * + * @param string $element one of 'actor', 'subject', 'object', 'target' + * @return string + */ + function asActivityNoun($element) + { + $xs = new XMLStringer(true); + + $xs->elementStart('activity:' . $element); + $xs->element( + 'activity:object-type', + null, + 'http://activitystrea.ms/schema/1.0/person' + ); + $xs->element( + 'id', + null, + $this->getUri() + ); + $xs->element('title', null, $this->getBestName()); + + $avatar = $this->getAvatar(AVATAR_PROFILE_SIZE); + + $xs->element( + 'link', array( + 'type' => empty($avatar) ? 'image/png' : $avatar->mediatype, + 'rel' => 'avatar', + 'href' => empty($avatar) + ? Avatar::defaultImage(AVATAR_PROFILE_SIZE) + : $avatar->displayUrl() + ), + '' + ); + + $xs->elementEnd('activity:' . $element); + + return $xs->getString(); + } + + /** + * Returns the best URI for a profile. Plugins may override. + * + * @return string $uri + */ + function getUri() + { + $uri = null; + + // check for a local user first + $user = User::staticGet('id', $this->id); + + if (!empty($user)) { + $uri = common_local_url( + 'userbyid', + array('id' => $user->id) + ); + } else { + + // give plugins a chance to set the URI + if (Event::handle('StartGetProfileUri', array($this, &$uri))) { + + // 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; + } + }