2008-05-08 02:15:42 +09:00
|
|
|
<?php
|
2008-05-21 04:14:12 +09:00
|
|
|
/*
|
2009-08-26 07:14:12 +09:00
|
|
|
* StatusNet - the distributed open-source microblogging tool
|
2009-08-26 07:12:20 +09:00
|
|
|
* Copyright (C) 2008, 2009, StatusNet, Inc.
|
2008-05-21 04:14:12 +09:00
|
|
|
*
|
2008-05-15 04:26:48 +09:00
|
|
|
* 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.
|
2008-05-21 04:14:12 +09:00
|
|
|
*
|
2008-05-15 04:26:48 +09:00
|
|
|
* 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.
|
2008-05-21 04:14:12 +09:00
|
|
|
*
|
2008-05-15 04:26:48 +09:00
|
|
|
* 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/>.
|
|
|
|
*/
|
|
|
|
|
2009-08-26 23:41:36 +09:00
|
|
|
if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
|
2008-05-15 04:26:48 +09:00
|
|
|
|
2008-05-08 02:15:42 +09:00
|
|
|
/**
|
|
|
|
* Table Definition for profile
|
|
|
|
*/
|
2008-09-27 01:18:24 +09:00
|
|
|
require_once INSTALLDIR.'/classes/Memcached_DataObject.php';
|
2008-05-08 02:15:42 +09:00
|
|
|
|
2008-12-11 02:47:22 +09:00
|
|
|
class Profile extends Memcached_DataObject
|
2008-05-08 02:15:42 +09:00
|
|
|
{
|
|
|
|
###START_AUTOCODE
|
|
|
|
/* the code below is auto generated do not remove the above tag */
|
|
|
|
|
|
|
|
public $__table = 'profile'; // table name
|
|
|
|
public $id; // int(4) primary_key not_null
|
2008-07-10 13:51:26 +09:00
|
|
|
public $nickname; // varchar(64) multiple_key not_null
|
|
|
|
public $fullname; // varchar(255) multiple_key
|
2008-12-11 02:47:22 +09:00
|
|
|
public $profileurl; // varchar(255)
|
2008-07-10 13:51:26 +09:00
|
|
|
public $homepage; // varchar(255) multiple_key
|
2009-08-21 06:09:04 +09:00
|
|
|
public $bio; // text() multiple_key
|
2008-07-10 13:51:26 +09:00
|
|
|
public $location; // varchar(255) multiple_key
|
2009-09-16 07:28:44 +09:00
|
|
|
public $lat; // decimal(10,7)
|
|
|
|
public $lon; // decimal(10,7)
|
|
|
|
public $location_id; // int(4)
|
|
|
|
public $location_ns; // int(4)
|
2008-05-08 02:15:42 +09:00
|
|
|
public $created; // datetime() not_null
|
|
|
|
public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP
|
|
|
|
|
|
|
|
/* Static get */
|
2009-09-16 07:28:44 +09:00
|
|
|
function staticGet($k,$v=NULL) {
|
|
|
|
return Memcached_DataObject::staticGet('Profile',$k,$v);
|
|
|
|
}
|
2008-05-08 02:15:42 +09:00
|
|
|
|
|
|
|
/* the code above is auto generated do not remove the tag below */
|
|
|
|
###END_AUTOCODE
|
2008-05-21 04:14:12 +09:00
|
|
|
|
2009-10-15 18:16:37 +09:00
|
|
|
function getUser()
|
|
|
|
{
|
|
|
|
return User::staticGet('id', $this->id);
|
|
|
|
}
|
|
|
|
|
2008-12-24 04:33:23 +09:00
|
|
|
function getAvatar($width, $height=null)
|
|
|
|
{
|
2008-12-24 04:19:07 +09:00
|
|
|
if (is_null($height)) {
|
|
|
|
$height = $width;
|
|
|
|
}
|
|
|
|
return Avatar::pkeyGet(array('profile_id' => $this->id,
|
|
|
|
'width' => $width,
|
|
|
|
'height' => $height));
|
|
|
|
}
|
|
|
|
|
2008-12-24 04:33:23 +09:00
|
|
|
function getOriginalAvatar()
|
|
|
|
{
|
2008-12-24 04:19:07 +09:00
|
|
|
$avatar = DB_DataObject::factory('avatar');
|
|
|
|
$avatar->profile_id = $this->id;
|
|
|
|
$avatar->original = true;
|
|
|
|
if ($avatar->find(true)) {
|
|
|
|
return $avatar;
|
|
|
|
} else {
|
2008-12-24 04:21:29 +09:00
|
|
|
return null;
|
2008-12-24 04:19:07 +09:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-02-05 09:32:15 +09:00
|
|
|
function setOriginal($filename)
|
2008-12-24 04:33:23 +09:00
|
|
|
{
|
2009-02-06 17:13:08 +09:00
|
|
|
$imagefile = new ImageFile($this->id, Avatar::path($filename));
|
2008-12-24 04:19:07 +09:00
|
|
|
|
|
|
|
$avatar = new Avatar();
|
|
|
|
$avatar->profile_id = $this->id;
|
2009-02-05 09:32:15 +09:00
|
|
|
$avatar->width = $imagefile->width;
|
|
|
|
$avatar->height = $imagefile->height;
|
|
|
|
$avatar->mediatype = image_type_to_mime_type($imagefile->type);
|
2008-12-24 04:19:07 +09:00
|
|
|
$avatar->filename = $filename;
|
|
|
|
$avatar->original = true;
|
2009-02-06 17:13:08 +09:00
|
|
|
$avatar->url = Avatar::url($filename);
|
2008-12-24 04:19:07 +09:00
|
|
|
$avatar->created = DB_DataObject_Cast::dateTime(); # current time
|
|
|
|
|
|
|
|
# XXX: start a transaction here
|
|
|
|
|
2009-02-05 09:32:15 +09:00
|
|
|
if (!$this->delete_avatars() || !$avatar->insert()) {
|
2009-02-06 17:13:08 +09:00
|
|
|
@unlink(Avatar::path($filename));
|
2008-12-24 04:21:29 +09:00
|
|
|
return null;
|
2008-12-24 04:19:07 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
foreach (array(AVATAR_PROFILE_SIZE, AVATAR_STREAM_SIZE, AVATAR_MINI_SIZE) as $size) {
|
2009-11-10 04:01:46 +09:00
|
|
|
# We don't do a scaled one if original is our scaled size
|
2008-12-24 04:19:07 +09:00
|
|
|
if (!($avatar->width == $size && $avatar->height == $size)) {
|
2009-02-06 17:13:08 +09:00
|
|
|
|
2009-02-05 09:32:15 +09:00
|
|
|
$scaled_filename = $imagefile->resize($size);
|
2009-02-06 17:13:08 +09:00
|
|
|
|
2009-02-05 09:32:15 +09:00
|
|
|
//$scaled = DB_DataObject::factory('avatar');
|
|
|
|
$scaled = new Avatar();
|
|
|
|
$scaled->profile_id = $this->id;
|
|
|
|
$scaled->width = $size;
|
|
|
|
$scaled->height = $size;
|
|
|
|
$scaled->original = false;
|
|
|
|
$scaled->mediatype = image_type_to_mime_type($imagefile->type);
|
|
|
|
$scaled->filename = $scaled_filename;
|
2009-02-06 17:13:08 +09:00
|
|
|
$scaled->url = Avatar::url($scaled_filename);
|
2009-02-05 09:32:15 +09:00
|
|
|
$scaled->created = DB_DataObject_Cast::dateTime(); # current time
|
|
|
|
|
|
|
|
if (!$scaled->insert()) {
|
2008-12-24 04:21:29 +09:00
|
|
|
return null;
|
2008-12-24 04:19:07 +09:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return $avatar;
|
|
|
|
}
|
|
|
|
|
2009-01-22 03:57:18 +09:00
|
|
|
function delete_avatars($original=true)
|
2008-12-25 23:46:01 +09:00
|
|
|
{
|
|
|
|
$avatar = new Avatar();
|
|
|
|
$avatar->profile_id = $this->id;
|
|
|
|
$avatar->find();
|
|
|
|
while ($avatar->fetch()) {
|
|
|
|
if ($avatar->original) {
|
|
|
|
if ($original == false) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
$avatar->delete();
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
2008-12-24 04:19:07 +09:00
|
|
|
|
2008-12-24 04:33:23 +09:00
|
|
|
function getBestName()
|
|
|
|
{
|
2008-12-24 04:19:07 +09:00
|
|
|
return ($this->fullname) ? $this->fullname : $this->nickname;
|
|
|
|
}
|
2008-07-07 14:43:58 +09:00
|
|
|
|
|
|
|
# Get latest notice on or before date; default now
|
2008-12-24 04:33:23 +09:00
|
|
|
function getCurrentNotice($dt=null)
|
|
|
|
{
|
2008-12-24 04:19:07 +09:00
|
|
|
$notice = new Notice();
|
|
|
|
$notice->profile_id = $this->id;
|
|
|
|
if ($dt) {
|
|
|
|
$notice->whereAdd('created < "' . $dt . '"');
|
|
|
|
}
|
|
|
|
$notice->orderBy('created DESC, notice.id DESC');
|
|
|
|
$notice->limit(1);
|
|
|
|
if ($notice->find(true)) {
|
|
|
|
return $notice;
|
|
|
|
}
|
2008-12-24 04:21:29 +09:00
|
|
|
return null;
|
2008-12-24 04:19:07 +09:00
|
|
|
}
|
|
|
|
|
2009-06-18 07:04:57 +09:00
|
|
|
function getTaggedNotices($tag, $offset=0, $limit=NOTICES_PER_PAGE, $since_id=0, $max_id=0, $since=null)
|
2009-05-19 06:18:57 +09:00
|
|
|
{
|
|
|
|
$ids = Notice::stream(array($this, '_streamTaggedDirect'),
|
2009-06-18 07:04:57 +09:00
|
|
|
array($tag),
|
|
|
|
'profile:notice_ids_tagged:' . $this->id . ':' . $tag,
|
|
|
|
$offset, $limit, $since_id, $max_id, $since);
|
2009-05-19 06:18:57 +09:00
|
|
|
return Notice::getStreamByIds($ids);
|
|
|
|
}
|
|
|
|
|
2009-06-18 07:04:57 +09:00
|
|
|
function getNotices($offset=0, $limit=NOTICES_PER_PAGE, $since_id=0, $max_id=0, $since=null)
|
2008-12-24 04:33:23 +09:00
|
|
|
{
|
2009-11-10 04:01:46 +09:00
|
|
|
// XXX: I'm not sure this is going to be any faster. It probably isn't.
|
2009-05-02 03:27:57 +09:00
|
|
|
$ids = Notice::stream(array($this, '_streamDirect'),
|
|
|
|
array(),
|
|
|
|
'profile:notice_ids:' . $this->id,
|
2009-06-09 03:55:32 +09:00
|
|
|
$offset, $limit, $since_id, $max_id, $since);
|
2009-05-02 03:27:57 +09:00
|
|
|
|
|
|
|
return Notice::getStreamByIds($ids);
|
|
|
|
}
|
|
|
|
|
2009-06-18 07:04:57 +09:00
|
|
|
function _streamTaggedDirect($tag, $offset, $limit, $since_id, $max_id, $since)
|
2009-05-19 06:18:57 +09:00
|
|
|
{
|
2009-06-18 07:04:57 +09:00
|
|
|
// XXX It would be nice to do this without a join
|
|
|
|
|
2009-05-19 06:18:57 +09:00
|
|
|
$notice = new Notice();
|
2009-06-18 07:04:57 +09:00
|
|
|
|
|
|
|
$query =
|
|
|
|
"select id from notice join notice_tag on id=notice_id where tag='".
|
|
|
|
$notice->escape($tag) .
|
|
|
|
"' and profile_id=" . $notice->escape($this->id);
|
|
|
|
|
2009-05-19 06:18:57 +09:00
|
|
|
if ($since_id != 0) {
|
|
|
|
$query .= " and id > $since_id";
|
|
|
|
}
|
|
|
|
|
2009-06-18 07:04:57 +09:00
|
|
|
if ($max_id != 0) {
|
|
|
|
$query .= " and id < $max_id";
|
2009-05-19 06:18:57 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!is_null($since)) {
|
|
|
|
$query .= " and created > '" . date('Y-m-d H:i:s', $since) . "'";
|
|
|
|
}
|
|
|
|
|
|
|
|
$query .= ' order by id DESC';
|
|
|
|
|
|
|
|
if (!is_null($offset)) {
|
2009-07-23 12:07:28 +09:00
|
|
|
$query .= " LIMIT $limit OFFSET $offset";
|
2009-05-19 06:18:57 +09:00
|
|
|
}
|
2009-06-18 07:04:57 +09:00
|
|
|
|
2009-05-19 06:18:57 +09:00
|
|
|
$notice->query($query);
|
2009-06-18 07:04:57 +09:00
|
|
|
|
2009-05-19 06:18:57 +09:00
|
|
|
$ids = array();
|
|
|
|
|
|
|
|
while ($notice->fetch()) {
|
|
|
|
$ids[] = $notice->id;
|
|
|
|
}
|
|
|
|
|
|
|
|
return $ids;
|
|
|
|
}
|
|
|
|
|
2009-06-18 07:04:57 +09:00
|
|
|
function _streamDirect($offset, $limit, $since_id, $max_id, $since = null)
|
2009-05-02 03:27:57 +09:00
|
|
|
{
|
|
|
|
$notice = new Notice();
|
|
|
|
|
|
|
|
$notice->profile_id = $this->id;
|
|
|
|
|
|
|
|
$notice->selectAdd();
|
|
|
|
$notice->selectAdd('id');
|
|
|
|
|
|
|
|
if ($since_id != 0) {
|
|
|
|
$notice->whereAdd('id > ' . $since_id);
|
|
|
|
}
|
|
|
|
|
2009-05-30 08:54:24 +09:00
|
|
|
if ($max_id != 0) {
|
|
|
|
$notice->whereAdd('id <= ' . $max_id);
|
2009-05-02 03:27:57 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!is_null($since)) {
|
|
|
|
$notice->whereAdd('created > \'' . date('Y-m-d H:i:s', $since) . '\'');
|
|
|
|
}
|
|
|
|
|
|
|
|
$notice->orderBy('id DESC');
|
|
|
|
|
|
|
|
if (!is_null($offset)) {
|
|
|
|
$notice->limit($offset, $limit);
|
|
|
|
}
|
|
|
|
|
|
|
|
$ids = array();
|
|
|
|
|
|
|
|
if ($notice->find()) {
|
|
|
|
while ($notice->fetch()) {
|
|
|
|
$ids[] = $notice->id;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return $ids;
|
2008-12-24 04:19:07 +09:00
|
|
|
}
|
2009-01-22 03:57:18 +09:00
|
|
|
|
|
|
|
function isMember($group)
|
|
|
|
{
|
|
|
|
$mem = new Group_member();
|
|
|
|
|
|
|
|
$mem->group_id = $group->id;
|
|
|
|
$mem->profile_id = $this->id;
|
|
|
|
|
|
|
|
if ($mem->find()) {
|
|
|
|
return true;
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function isAdmin($group)
|
|
|
|
{
|
|
|
|
$mem = new Group_member();
|
|
|
|
|
|
|
|
$mem->group_id = $group->id;
|
|
|
|
$mem->profile_id = $this->id;
|
|
|
|
$mem->is_admin = 1;
|
|
|
|
|
|
|
|
if ($mem->find()) {
|
|
|
|
return true;
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-02-06 17:13:08 +09:00
|
|
|
function avatarUrl($size=AVATAR_PROFILE_SIZE)
|
|
|
|
{
|
|
|
|
$avatar = $this->getAvatar($size);
|
|
|
|
if ($avatar) {
|
|
|
|
return $avatar->displayUrl();
|
|
|
|
} else {
|
|
|
|
return Avatar::defaultImage($size);
|
|
|
|
}
|
|
|
|
}
|
2009-06-26 15:00:46 +09:00
|
|
|
|
|
|
|
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 ';
|
|
|
|
|
2009-11-16 14:19:19 +09:00
|
|
|
if ($offset>0 && !is_null($limit)){
|
|
|
|
if (common_config('db','type') == 'pgsql') {
|
|
|
|
$qry .= ' LIMIT ' . $limit . ' OFFSET ' . $offset;
|
|
|
|
} else {
|
|
|
|
$qry .= ' LIMIT ' . $offset . ', ' . $limit;
|
|
|
|
}
|
2009-06-26 15:00:46 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
$profile = new Profile();
|
|
|
|
|
|
|
|
$profile->query(sprintf($qry, $this->id));
|
|
|
|
|
|
|
|
return $profile;
|
|
|
|
}
|
|
|
|
|
|
|
|
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 ';
|
|
|
|
|
2009-11-16 14:19:19 +09:00
|
|
|
if ($offset>0 && !is_null($limit)){
|
|
|
|
if ($offset) {
|
|
|
|
if (common_config('db','type') == 'pgsql') {
|
|
|
|
$qry .= ' LIMIT ' . $limit . ' OFFSET ' . $offset;
|
|
|
|
} else {
|
|
|
|
$qry .= ' LIMIT ' . $offset . ', ' . $limit;
|
|
|
|
}
|
2009-06-26 15:00:46 +09:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
$profile = new Profile();
|
|
|
|
|
|
|
|
$cnt = $profile->query(sprintf($qry, $this->id));
|
|
|
|
|
|
|
|
return $profile;
|
|
|
|
}
|
2009-07-10 09:28:38 +09:00
|
|
|
|
2009-11-13 12:42:18 +09:00
|
|
|
function getApplications($offset = 0, $limit = null)
|
|
|
|
{
|
|
|
|
$qry =
|
2010-01-12 07:11:43 +09:00
|
|
|
'SELECT a.* ' .
|
|
|
|
'FROM oauth_application_user u, oauth_application a ' .
|
|
|
|
'WHERE u.profile_id = %d ' .
|
2010-01-14 06:11:08 +09:00
|
|
|
'AND a.id = u.application_id ' .
|
|
|
|
'AND u.access_type > 0 ' .
|
2010-01-12 07:11:43 +09:00
|
|
|
'ORDER BY u.created DESC ';
|
2009-11-13 12:42:18 +09:00
|
|
|
|
|
|
|
if ($offset > 0) {
|
|
|
|
if (common_config('db','type') == 'pgsql') {
|
|
|
|
$qry .= ' LIMIT ' . $limit . ' OFFSET ' . $offset;
|
|
|
|
} else {
|
|
|
|
$qry .= ' LIMIT ' . $offset . ', ' . $limit;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
$application = new Oauth_application();
|
|
|
|
|
|
|
|
$cnt = $application->query(sprintf($qry, $this->id));
|
|
|
|
|
|
|
|
return $application;
|
|
|
|
}
|
|
|
|
|
2009-07-10 09:28:38 +09:00
|
|
|
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));
|
|
|
|
}
|
|
|
|
}
|
2009-08-21 20:40:46 +09:00
|
|
|
|
|
|
|
static function maxBio()
|
|
|
|
{
|
2009-08-21 20:48:14 +09:00
|
|
|
$biolimit = common_config('profile', 'biolimit');
|
2009-08-21 20:40:46 +09:00
|
|
|
// 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));
|
|
|
|
}
|
2009-10-04 16:07:37 +09:00
|
|
|
|
2009-07-27 04:06:38 +09:00
|
|
|
function delete()
|
|
|
|
{
|
|
|
|
$this->_deleteNotices();
|
|
|
|
$this->_deleteSubscriptions();
|
|
|
|
$this->_deleteMessages();
|
|
|
|
$this->_deleteTags();
|
|
|
|
$this->_deleteBlocks();
|
|
|
|
|
|
|
|
$related = array('Avatar',
|
|
|
|
'Reply',
|
|
|
|
'Group_member',
|
|
|
|
);
|
2010-01-07 04:10:33 +09:00
|
|
|
Event::handle('ProfileDeleteRelated', array($this, &$related));
|
2009-07-27 04:06:38 +09:00
|
|
|
|
|
|
|
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;
|
2009-10-03 04:42:34 +09:00
|
|
|
$tag->delete();
|
2009-07-27 04:06:38 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
function _deleteBlocks()
|
|
|
|
{
|
|
|
|
$block = new Profile_block();
|
|
|
|
$block->blocked = $this->id;
|
|
|
|
$block->delete();
|
|
|
|
|
|
|
|
$block = new Group_block();
|
|
|
|
$block->blocked = $this->id;
|
|
|
|
$block->delete();
|
|
|
|
}
|
2009-10-30 03:43:25 +09:00
|
|
|
|
|
|
|
// 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;
|
|
|
|
}
|
2009-11-16 23:52:33 +09:00
|
|
|
|
|
|
|
function hasRole($name)
|
|
|
|
{
|
2009-11-19 04:19:43 +09:00
|
|
|
$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;
|
2009-11-16 23:52:33 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
function grantRole($name)
|
|
|
|
{
|
2009-11-17 00:06:52 +09:00
|
|
|
$role = new Profile_role();
|
2009-11-16 23:52:33 +09:00
|
|
|
|
2009-11-17 00:06:52 +09:00
|
|
|
$role->profile_id = $this->id;
|
|
|
|
$role->role = $name;
|
|
|
|
$role->created = common_sql_now();
|
2009-11-16 23:52:33 +09:00
|
|
|
|
|
|
|
$result = $role->insert();
|
|
|
|
|
|
|
|
if (!$result) {
|
|
|
|
common_log_db_error($role, 'INSERT', __FILE__);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
function revokeRole($name)
|
|
|
|
{
|
2009-11-17 00:06:52 +09:00
|
|
|
$role = Profile_role::pkeyGet(array('profile_id' => $this->id,
|
|
|
|
'role' => $name));
|
2009-11-16 23:52:33 +09:00
|
|
|
|
|
|
|
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()
|
|
|
|
{
|
2009-11-17 00:06:52 +09:00
|
|
|
return $this->hasRole(Profile_role::SANDBOXED);
|
2009-11-16 23:52:33 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
function isSilenced()
|
|
|
|
{
|
2009-11-17 00:06:52 +09:00
|
|
|
return $this->hasRole(Profile_role::SILENCED);
|
2009-11-16 23:52:33 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
function sandbox()
|
|
|
|
{
|
2009-11-17 00:06:52 +09:00
|
|
|
$this->grantRole(Profile_role::SANDBOXED);
|
2009-11-16 23:52:33 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
function unsandbox()
|
|
|
|
{
|
2009-11-17 00:06:52 +09:00
|
|
|
$this->revokeRole(Profile_role::SANDBOXED);
|
2009-11-16 23:52:33 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
function silence()
|
|
|
|
{
|
2009-11-17 00:06:52 +09:00
|
|
|
$this->grantRole(Profile_role::SILENCED);
|
2009-11-16 23:52:33 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
function unsilence()
|
|
|
|
{
|
2009-11-17 00:06:52 +09:00
|
|
|
$this->revokeRole(Profile_role::SILENCED);
|
2009-11-16 23:52:33 +09:00
|
|
|
}
|
2009-11-17 03:03:59 +09:00
|
|
|
|
|
|
|
/**
|
|
|
|
* 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:
|
2010-02-06 19:36:59 +09:00
|
|
|
case Right::MAKEGROUPADMIN:
|
2009-11-17 03:03:59 +09:00
|
|
|
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:
|
2009-11-17 03:46:08 +09:00
|
|
|
case Right::NEWMESSAGE:
|
|
|
|
case Right::SUBSCRIBE:
|
2009-11-17 03:03:59 +09:00
|
|
|
$result = !$this->isSilenced();
|
|
|
|
break;
|
2009-11-17 03:22:22 +09:00
|
|
|
case Right::PUBLICNOTICE:
|
2009-11-17 03:46:08 +09:00
|
|
|
case Right::EMAILONREPLY:
|
|
|
|
case Right::EMAILONSUBSCRIBE:
|
2009-11-17 04:28:55 +09:00
|
|
|
case Right::EMAILONFAVE:
|
2009-11-17 03:22:22 +09:00
|
|
|
$result = !$this->isSandboxed();
|
|
|
|
break;
|
2009-11-17 03:03:59 +09:00
|
|
|
default:
|
|
|
|
$result = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return $result;
|
|
|
|
}
|
2009-12-12 00:49:26 +09:00
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
2010-02-11 11:55:14 +09:00
|
|
|
|
2010-02-13 03:54:48 +09:00
|
|
|
/**
|
|
|
|
* Returns an XML string fragment with limited profile information
|
|
|
|
* as an Atom <author> element.
|
|
|
|
*
|
|
|
|
* Assumes that Atom has been previously set up as the base namespace.
|
|
|
|
*
|
|
|
|
* @return string
|
|
|
|
*/
|
2010-02-11 11:55:14 +09:00
|
|
|
function asAtomAuthor()
|
|
|
|
{
|
|
|
|
$xs = new XMLStringer(true);
|
|
|
|
|
|
|
|
$xs->elementStart('author');
|
|
|
|
$xs->element('name', null, $this->nickname);
|
2010-02-17 13:13:39 +09:00
|
|
|
$xs->element('uri', null, $this->getUri());
|
2010-02-11 11:55:14 +09:00
|
|
|
$xs->elementEnd('author');
|
|
|
|
|
|
|
|
return $xs->getString();
|
|
|
|
}
|
|
|
|
|
2010-02-13 03:54:48 +09:00
|
|
|
/**
|
|
|
|
* Returns an XML string fragment with profile information as an
|
|
|
|
* Activity Streams <activity:actor> element.
|
|
|
|
*
|
|
|
|
* Assumes that 'activity' namespace has been previously defined.
|
|
|
|
*
|
|
|
|
* @return string
|
|
|
|
*/
|
2010-02-11 11:55:14 +09:00
|
|
|
function asActivityActor()
|
2010-02-13 03:54:48 +09:00
|
|
|
{
|
|
|
|
return $this->asActivityNoun('actor');
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns an XML string fragment with profile information as an
|
|
|
|
* Activity Streams noun object with the given element type.
|
|
|
|
*
|
2010-02-22 18:21:34 +09:00
|
|
|
* Assumes that 'activity', 'georss', and 'poco' namespace has been
|
|
|
|
* previously defined.
|
2010-02-13 03:54:48 +09:00
|
|
|
*
|
|
|
|
* @param string $element one of 'actor', 'subject', 'object', 'target'
|
2010-02-22 18:21:34 +09:00
|
|
|
*
|
2010-02-13 03:54:48 +09:00
|
|
|
* @return string
|
|
|
|
*/
|
|
|
|
function asActivityNoun($element)
|
2010-02-11 11:55:14 +09:00
|
|
|
{
|
|
|
|
$xs = new XMLStringer(true);
|
|
|
|
|
2010-02-13 03:54:48 +09:00
|
|
|
$xs->elementStart('activity:' . $element);
|
2010-02-11 11:55:14 +09:00
|
|
|
$xs->element(
|
|
|
|
'activity:object-type',
|
|
|
|
null,
|
|
|
|
'http://activitystrea.ms/schema/1.0/person'
|
|
|
|
);
|
|
|
|
$xs->element(
|
|
|
|
'id',
|
|
|
|
null,
|
2010-02-17 09:22:58 +09:00
|
|
|
$this->getUri()
|
2010-02-22 18:21:34 +09:00
|
|
|
);
|
|
|
|
|
|
|
|
// title should contain fullname
|
2010-02-11 11:55:14 +09:00
|
|
|
$xs->element('title', null, $this->getBestName());
|
|
|
|
|
2010-02-22 21:40:20 +09:00
|
|
|
$xs->element('link', array('rel' => 'alternate',
|
|
|
|
'type' => 'text/html'),
|
|
|
|
$this->profileurl);
|
|
|
|
|
2010-02-22 21:43:12 +09:00
|
|
|
$xs->element('poco:preferredUsername', null, $this->nickname);
|
|
|
|
|
2010-02-22 18:21:34 +09:00
|
|
|
// Portable Contacts stuff
|
|
|
|
|
|
|
|
if (isset($this->bio)) {
|
|
|
|
|
|
|
|
// XXX: Possible to use OpenSocial's aboutMe?
|
|
|
|
|
|
|
|
$xs->element('poco:note', null, $this->bio);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (isset($this->homepage)) {
|
|
|
|
|
|
|
|
$xs->elementStart('poco:urls');
|
|
|
|
$xs->element('poco:value', null, $this->homepage);
|
|
|
|
$xs->element('poco:type', null, 'homepage');
|
|
|
|
$xs->element('poco:primary', null, 'true');
|
|
|
|
$xs->elementEnd('poco:urls');
|
|
|
|
}
|
|
|
|
|
|
|
|
if (isset($this->location)) {
|
|
|
|
$xs->elementStart('poco:address');
|
|
|
|
$xs->element('poco:formatted', null, $this->location);
|
|
|
|
$xs->elementEnd('poco:address');
|
|
|
|
}
|
|
|
|
|
|
|
|
if (isset($this->lat) && isset($this->lon)) {
|
|
|
|
$this->element(
|
|
|
|
'georss:point',
|
|
|
|
null,
|
|
|
|
(float)$this->lat . ' ' . (float)$this->lon
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
// XXX: Should we send all avatar sizes we have? I think
|
|
|
|
// cliqset does -Z
|
|
|
|
|
2010-02-11 11:55:14 +09:00
|
|
|
$avatar = $this->getAvatar(AVATAR_PROFILE_SIZE);
|
|
|
|
|
|
|
|
$xs->element(
|
|
|
|
'link', array(
|
|
|
|
'type' => empty($avatar) ? 'image/png' : $avatar->mediatype,
|
2010-02-17 04:32:10 +09:00
|
|
|
'rel' => 'avatar',
|
2010-02-11 11:55:14 +09:00
|
|
|
'href' => empty($avatar)
|
|
|
|
? Avatar::defaultImage(AVATAR_PROFILE_SIZE)
|
|
|
|
: $avatar->displayUrl()
|
|
|
|
),
|
|
|
|
''
|
|
|
|
);
|
|
|
|
|
2010-02-13 03:54:48 +09:00
|
|
|
$xs->elementEnd('activity:' . $element);
|
2010-02-11 11:55:14 +09:00
|
|
|
|
2010-02-22 18:21:34 +09:00
|
|
|
// XXX: Add people tags with <poco:tags> plural?
|
|
|
|
|
2010-02-11 11:55:14 +09:00
|
|
|
return $xs->getString();
|
|
|
|
}
|
2010-02-12 08:24:18 +09:00
|
|
|
|
2010-02-17 13:13:39 +09:00
|
|
|
/**
|
|
|
|
* Returns the best URI for a profile. Plugins may override.
|
|
|
|
*
|
|
|
|
* @return string $uri
|
|
|
|
*/
|
2010-02-17 09:22:58 +09:00
|
|
|
function getUri()
|
2010-02-12 08:24:18 +09:00
|
|
|
{
|
2010-02-17 13:13:39 +09:00
|
|
|
$uri = null;
|
2010-02-17 09:22:58 +09:00
|
|
|
|
2010-02-22 12:52:27 +09:00
|
|
|
// give plugins a chance to set the URI
|
|
|
|
if (Event::handle('StartGetProfileUri', array($this, &$uri))) {
|
2010-02-17 09:22:58 +09:00
|
|
|
|
2010-02-22 12:52:27 +09:00
|
|
|
// check for a local user first
|
|
|
|
$user = User::staticGet('id', $this->id);
|
2010-02-17 13:13:39 +09:00
|
|
|
|
2010-02-22 12:52:27 +09:00
|
|
|
if (!empty($user)) {
|
|
|
|
$uri = $user->uri;
|
|
|
|
} else {
|
2010-02-17 13:13:39 +09:00
|
|
|
// return OMB profile if any
|
|
|
|
$remote = Remote_profile::staticGet('id', $this->id);
|
|
|
|
if (!empty($remote)) {
|
|
|
|
$uri = $remote->uri;
|
|
|
|
}
|
2010-02-17 09:22:58 +09:00
|
|
|
}
|
2010-02-22 12:52:27 +09:00
|
|
|
Event::handle('EndGetProfileUri', array($this, &$uri));
|
2010-02-17 09:22:58 +09:00
|
|
|
}
|
2010-02-17 13:13:39 +09:00
|
|
|
|
|
|
|
return $uri;
|
2010-02-12 08:24:18 +09:00
|
|
|
}
|
|
|
|
|
2010-02-19 22:16:45 +09:00
|
|
|
function hasBlocked($other)
|
|
|
|
{
|
|
|
|
$block = Profile_block::get($this->id, $other->id);
|
|
|
|
|
|
|
|
if (empty($block)) {
|
|
|
|
$result = false;
|
|
|
|
} else {
|
|
|
|
$result = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return $result;
|
|
|
|
}
|
2008-05-08 02:15:42 +09:00
|
|
|
}
|