forked from GNUsocial/gnu-social
DB_DataObjects for people tags
This commit is contained in:
parent
32a00059fa
commit
1b1a427237
@ -429,6 +429,12 @@ class Notice extends Memcached_DataObject
|
||||
$notice->saveGroups();
|
||||
}
|
||||
|
||||
if (isset($peopletags)) {
|
||||
$notice->saveProfileTags($peopletags);
|
||||
} else {
|
||||
$notice->saveProfileTags();
|
||||
}
|
||||
|
||||
if (isset($urls)) {
|
||||
$notice->saveKnownUrls($urls);
|
||||
} else {
|
||||
@ -797,6 +803,7 @@ class Notice extends Memcached_DataObject
|
||||
}
|
||||
|
||||
$users = $this->getSubscribedUsers();
|
||||
$ptags = $this->getProfileTags();
|
||||
|
||||
// FIXME: kind of ignoring 'transitional'...
|
||||
// we'll probably stop supporting inboxless mode
|
||||
@ -817,6 +824,18 @@ class Notice extends Memcached_DataObject
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($ptags as $ptag) {
|
||||
$users = $ptag->getUserSubscribers();
|
||||
foreach ($users as $id) {
|
||||
if (!array_key_exists($id, $ni)) {
|
||||
$user = User::staticGet('id', $id);
|
||||
if (!$user->hasBlocked($profile)) {
|
||||
$ni[$id] = NOTICE_INBOX_SOURCE_PROFILE_TAG;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($recipients as $recipient) {
|
||||
if (!array_key_exists($recipient, $ni)) {
|
||||
$ni[$recipient] = NOTICE_INBOX_SOURCE_REPLY;
|
||||
@ -913,6 +932,39 @@ class Notice extends Memcached_DataObject
|
||||
return $ids;
|
||||
}
|
||||
|
||||
function getProfileTags()
|
||||
{
|
||||
// Don't save ptags for repeats, for now.
|
||||
|
||||
if (!empty($this->repeat_of)) {
|
||||
return array();
|
||||
}
|
||||
|
||||
// XXX: cache me
|
||||
|
||||
$ptags = array();
|
||||
|
||||
$ptagi = new Profile_tag_inbox();
|
||||
|
||||
$ptagi->selectAdd();
|
||||
$ptagi->selectAdd('profile_tag_id');
|
||||
|
||||
$ptagi->notice_id = $this->id;
|
||||
|
||||
if ($ptagi->find()) {
|
||||
while ($ptagi->fetch()) {
|
||||
$profile_list = Profile_list::staticGet('id', $ptagi->profile_tag_id);
|
||||
if ($profile_list) {
|
||||
$ptags[] = $profile_list;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$ptagi->free();
|
||||
|
||||
return $ptags;
|
||||
}
|
||||
|
||||
/**
|
||||
* Record this notice to the given group inboxes for delivery.
|
||||
* Overrides the regular parsing of !group markup.
|
||||
@ -1034,6 +1086,69 @@ class Notice extends Memcached_DataObject
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* record targets into profile_tag_inbox.
|
||||
* @return array of Profile_list objects
|
||||
*/
|
||||
function saveProfileTags($known=array())
|
||||
{
|
||||
// Don't save ptags for repeats, for now
|
||||
|
||||
if (!empty($this->repeat_of)) {
|
||||
return array();
|
||||
}
|
||||
|
||||
if (is_array($known)) {
|
||||
$ptags = $known;
|
||||
} else {
|
||||
$ptags = array();
|
||||
}
|
||||
|
||||
$ptag = new Profile_tag();
|
||||
$ptag->tagged = $this->profile_id;
|
||||
|
||||
if($ptag->find()) {
|
||||
while($ptag->fetch()) {
|
||||
$plist = Profile_list::getByTaggerAndTag($ptag->tagger, $ptag->tag);
|
||||
$ptags[] = clone($plist);
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($ptags as $target) {
|
||||
$this->addToProfileTagInbox($target);
|
||||
}
|
||||
|
||||
return $ptags;
|
||||
}
|
||||
|
||||
function addToProfileTagInbox($plist)
|
||||
{
|
||||
$ptagi = Profile_tag_inbox::pkeyGet(array('profile_tag_id' => $plist->id,
|
||||
'notice_id' => $this->id));
|
||||
|
||||
if (empty($ptagi)) {
|
||||
|
||||
$ptagi = new Profile_tag_inbox();
|
||||
|
||||
$ptagi->query('BEGIN');
|
||||
$ptagi->profile_tag_id = $plist->id;
|
||||
$ptagi->notice_id = $this->id;
|
||||
$ptagi->created = $this->created;
|
||||
|
||||
$result = $ptagi->insert();
|
||||
if (!$result) {
|
||||
common_log_db_error($ptagi, 'INSERT', __FILE__);
|
||||
throw new ServerException(_('Problem saving profile_tag inbox.'));
|
||||
}
|
||||
|
||||
$ptagi->query('COMMIT');
|
||||
|
||||
self::blow('profile_tag:notice_ids:%d', $ptagi->profile_tag_id);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save reply records indicating that this notice needs to be
|
||||
* delivered to the local users with the given URIs.
|
||||
|
@ -339,6 +339,183 @@ class Profile extends Memcached_DataObject
|
||||
return $groups;
|
||||
}
|
||||
|
||||
function isTagged($peopletag)
|
||||
{
|
||||
$tag = Profile_tag::pkeyGet(array('tagger' => $peopletag->tagger,
|
||||
'tagged' => $this->id,
|
||||
'tag' => $peopletag->tag));
|
||||
return !empty($tag);
|
||||
}
|
||||
|
||||
function canTag($tagged)
|
||||
{
|
||||
if (empty($tagged)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($tagged->id == $this->id) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$all = common_config('peopletag', 'allow_tagging', 'all');
|
||||
$local = common_config('peopletag', 'allow_tagging', 'local');
|
||||
$remote = common_config('peopletag', 'allow_tagging', 'remote');
|
||||
$subs = common_config('peopletag', 'allow_tagging', 'subs');
|
||||
|
||||
if ($all) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$tagged_user = $tagged->getUser();
|
||||
if (!empty($tagged_user)) {
|
||||
if ($local) {
|
||||
return true;
|
||||
}
|
||||
} else if ($subs) {
|
||||
return (Subscription::exists($this, $tagged) ||
|
||||
Subscription::exists($tagged, $this));
|
||||
} else if ($remote) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function getOwnedTags($auth_user, $offset=0, $limit=null, $since_id=0, $max_id=0)
|
||||
{
|
||||
$tags = new Profile_list();
|
||||
$tags->tagger = $this->id;
|
||||
|
||||
if (($auth_user instanceof User || $auth_user instanceof Profile) &&
|
||||
$auth_user->id === $this->id) {
|
||||
// no condition, get both private and public tags
|
||||
} else {
|
||||
$tags->private = false;
|
||||
}
|
||||
|
||||
$tags->selectAdd('id as "cursor"');
|
||||
|
||||
if ($since_id>0) {
|
||||
$tags->whereAdd('id > '.$since_id);
|
||||
}
|
||||
|
||||
if ($max_id>0) {
|
||||
$tags->whereAdd('id <= '.$max_id);
|
||||
}
|
||||
|
||||
if($offset>=0 && !is_null($limit)) {
|
||||
$tags->limit($offset, $limit);
|
||||
}
|
||||
|
||||
$tags->orderBy('id DESC');
|
||||
$tags->find();
|
||||
|
||||
return $tags;
|
||||
}
|
||||
|
||||
function getOtherTags($auth_user=null, $offset=0, $limit=null, $since_id=0, $max_id=0)
|
||||
{
|
||||
$lists = new Profile_list();
|
||||
|
||||
$tags = new Profile_tag();
|
||||
$tags->tagged = $this->id;
|
||||
|
||||
$lists->joinAdd($tags);
|
||||
#@fixme: postgres (round(date_part('epoch', my_date)))
|
||||
$lists->selectAdd('unix_timestamp(profile_tag.modified) as "cursor"');
|
||||
|
||||
if ($auth_user instanceof User || $auth_user instanceof Profile) {
|
||||
$lists->whereAdd('( ( profile_list.private = false ) ' .
|
||||
'OR ( profile_list.tagger = ' . $auth_user->id . ' AND ' .
|
||||
'profile_list.private = true ) )');
|
||||
} else {
|
||||
$lists->private = false;
|
||||
}
|
||||
|
||||
if ($since_id>0) {
|
||||
$lists->whereAdd('cursor > '.$since_id);
|
||||
}
|
||||
|
||||
if ($max_id>0) {
|
||||
$lists->whereAdd('cursor <= '.$max_id);
|
||||
}
|
||||
|
||||
if($offset>=0 && !is_null($limit)) {
|
||||
$lists->limit($offset, $limit);
|
||||
}
|
||||
|
||||
$lists->orderBy('profile_tag.modified DESC');
|
||||
$lists->find();
|
||||
|
||||
return $lists;
|
||||
}
|
||||
|
||||
function getPrivateTags($offset=0, $limit=null, $since_id=0, $max_id=0)
|
||||
{
|
||||
$tags = new Profile_list();
|
||||
$tags->private = true;
|
||||
$tags->tagger = $this->id;
|
||||
|
||||
if ($since_id>0) {
|
||||
$tags->whereAdd('id > '.$since_id);
|
||||
}
|
||||
|
||||
if ($max_id>0) {
|
||||
$tags->whereAdd('id <= '.$max_id);
|
||||
}
|
||||
|
||||
if($offset>=0 && !is_null($limit)) {
|
||||
$tags->limit($offset, $limit);
|
||||
}
|
||||
|
||||
$tags->orderBy('id DESC');
|
||||
$tags->find();
|
||||
|
||||
return $tags;
|
||||
}
|
||||
|
||||
function hasLocalTags()
|
||||
{
|
||||
$tags = new Profile_tag();
|
||||
|
||||
$tags->joinAdd(array('tagger', 'user:id'));
|
||||
$tags->whereAdd('tagged = '.$this->id);
|
||||
$tags->whereAdd('tagger != '.$this->id);
|
||||
|
||||
$tags->limit(0, 1);
|
||||
$tags->fetch();
|
||||
|
||||
return ($tags->N == 0) ? false : true;
|
||||
}
|
||||
|
||||
function getTagSubscriptions($offset=0, $limit=null, $since_id=0, $max_id=0)
|
||||
{
|
||||
$lists = new Profile_list();
|
||||
$subs = new Profile_tag_subscription();
|
||||
|
||||
$lists->joinAdd($subs);
|
||||
#@fixme: postgres (round(date_part('epoch', my_date)))
|
||||
$lists->selectAdd('unix_timestamp(profile_tag_subscription.created) as "cursor"');
|
||||
|
||||
$lists->whereAdd('profile_tag_subscription.profile_id = '.$this->id);
|
||||
|
||||
if ($since_id>0) {
|
||||
$lists->whereAdd('cursor > '.$since_id);
|
||||
}
|
||||
|
||||
if ($max_id>0) {
|
||||
$lists->whereAdd('cursor <= '.$max_id);
|
||||
}
|
||||
|
||||
if($offset>=0 && !is_null($limit)) {
|
||||
$lists->limit($offset, $limit);
|
||||
}
|
||||
|
||||
$lists->orderBy('"cursor" DESC');
|
||||
$lists->find();
|
||||
|
||||
return $lists;
|
||||
}
|
||||
|
||||
function avatarUrl($size=AVATAR_PROFILE_SIZE)
|
||||
{
|
||||
$avatar = $this->getAvatar($size);
|
||||
@ -385,6 +562,32 @@ class Profile extends Memcached_DataObject
|
||||
return new ArrayWrapper($profiles);
|
||||
}
|
||||
|
||||
|
||||
function getTaggedSubscribers($tag)
|
||||
{
|
||||
$qry =
|
||||
'SELECT profile.* ' .
|
||||
'FROM profile JOIN (subscription, profile_tag, profile_list) ' .
|
||||
'ON profile.id = subscription.subscriber ' .
|
||||
'AND profile.id = profile_tag.tagged ' .
|
||||
'AND profile_tag.tagger = profile_list.tagger AND profile_tag.tag = profile_list.tag ' .
|
||||
'WHERE subscription.subscribed = %d ' .
|
||||
'AND subscription.subscribed != subscription.subscriber ' .
|
||||
'AND profile_tag.tagger = %d AND profile_tag.tag = "%s" ' .
|
||||
'AND profile_list.private = false ' .
|
||||
'ORDER BY subscription.created DESC';
|
||||
|
||||
$profile = new Profile();
|
||||
$tagged = array();
|
||||
|
||||
$cnt = $profile->query(sprintf($qry, $this->id, $this->id, $tag));
|
||||
|
||||
while ($profile->fetch()) {
|
||||
$tagged[] = clone($profile);
|
||||
}
|
||||
return $tagged;
|
||||
}
|
||||
|
||||
function subscriptionCount()
|
||||
{
|
||||
$c = Cache::instance();
|
||||
|
929
classes/Profile_list.php
Normal file
929
classes/Profile_list.php
Normal file
@ -0,0 +1,929 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet - the distributed open-source microblogging tool
|
||||
*
|
||||
* 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 Notices
|
||||
* @package StatusNet
|
||||
* @author Shashi Gowda <connect2shashi@gmail.com>
|
||||
* @license GNU Affero General Public License http://www.gnu.org/licenses/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET') && !defined('LACONICA')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Table Definition for profile_list
|
||||
*/
|
||||
require_once INSTALLDIR.'/classes/Memcached_DataObject.php';
|
||||
|
||||
class Profile_list extends Memcached_DataObject
|
||||
{
|
||||
###START_AUTOCODE
|
||||
/* the code below is auto generated do not remove the above tag */
|
||||
|
||||
public $__table = 'profile_list'; // table name
|
||||
public $id; // int(4) primary_key not_null
|
||||
public $tagger; // int(4)
|
||||
public $tag; // varchar(64)
|
||||
public $description; // text
|
||||
public $private; // tinyint(1)
|
||||
public $created; // datetime not_null default_0000-00-00%2000%3A00%3A00
|
||||
public $modified; // timestamp not_null default_CURRENT_TIMESTAMP
|
||||
public $uri; // varchar(255) unique_key
|
||||
public $mainpage; // varchar(255)
|
||||
public $tagged_count; // smallint
|
||||
public $subscriber_count; // smallint
|
||||
|
||||
/* Static get */
|
||||
function staticGet($k,$v=NULL) { return DB_DataObject::staticGet('Profile_list',$k,$v); }
|
||||
|
||||
/* the code above is auto generated do not remove the tag below */
|
||||
###END_AUTOCODE
|
||||
|
||||
/**
|
||||
* return a profile_list record, given its tag and tagger.
|
||||
*
|
||||
* @param array $kv ideally array('tag' => $tag, 'tagger' => $tagger)
|
||||
*
|
||||
* @return Profile_list a Profile_list object with the given tag and tagger.
|
||||
*/
|
||||
|
||||
function pkeyGet($kv)
|
||||
{
|
||||
return Memcached_DataObject::pkeyGet('Profile_list', $kv);
|
||||
}
|
||||
|
||||
/**
|
||||
* get the tagger of this profile_list object
|
||||
*
|
||||
* @return Profile the tagger
|
||||
*/
|
||||
|
||||
function getTagger()
|
||||
{
|
||||
return Profile::staticGet('id', $this->tagger);
|
||||
}
|
||||
|
||||
/**
|
||||
* return a string to identify this
|
||||
* profile_list in the user interface etc.
|
||||
*
|
||||
* @return String
|
||||
*/
|
||||
|
||||
function getBestName()
|
||||
{
|
||||
return $this->tag;
|
||||
}
|
||||
|
||||
/**
|
||||
* return a uri string for this profile_list
|
||||
*
|
||||
* @return String uri
|
||||
*/
|
||||
|
||||
function getUri()
|
||||
{
|
||||
$uri = null;
|
||||
if (Event::handle('StartProfiletagGetUri', array($this, &$uri))) {
|
||||
if (!empty($this->uri)) {
|
||||
$uri = $this->uri;
|
||||
} else {
|
||||
$uri = common_local_url('profiletagbyid',
|
||||
array('id' => $this->id, 'tagger_id' => $this->tagger));
|
||||
}
|
||||
}
|
||||
Event::handle('EndProfiletagGetUri', array($this, &$uri));
|
||||
return $uri;
|
||||
}
|
||||
|
||||
/**
|
||||
* return a url to the homepage of this item
|
||||
*
|
||||
* @return String home url
|
||||
*/
|
||||
|
||||
function homeUrl()
|
||||
{
|
||||
$url = null;
|
||||
if (Event::handle('StartUserPeopletagHomeUrl', array($this, &$url))) {
|
||||
// normally stored in mainpage, but older ones may be null
|
||||
if (!empty($this->mainpage)) {
|
||||
$url = $this->mainpage;
|
||||
} else {
|
||||
$url = common_local_url('showprofiletag',
|
||||
array('tagger' => $this->getTagger()->nickname,
|
||||
'tag' => $this->tag));
|
||||
}
|
||||
}
|
||||
Event::handle('EndUserPeopletagHomeUrl', array($this, &$url));
|
||||
return $url;
|
||||
}
|
||||
|
||||
/**
|
||||
* return an immutable url for this object
|
||||
*
|
||||
* @return String permalink
|
||||
*/
|
||||
|
||||
function permalink()
|
||||
{
|
||||
$url = null;
|
||||
if (Event::handle('StartProfiletagPermalink', array($this, &$url))) {
|
||||
$url = common_local_url('profiletagbyid',
|
||||
array('id' => $this->id));
|
||||
}
|
||||
Event::handle('EndProfiletagPermalink', array($this, &$url));
|
||||
return $url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Query notices by users associated with this tag,
|
||||
* but first check the cache before hitting the DB.
|
||||
*
|
||||
* @param integer $offset offset
|
||||
* @param integer $limit maximum no of results
|
||||
* @param integer $since_id=null since this id
|
||||
* @param integer $max_id=null maximum id in result
|
||||
*
|
||||
* @return Notice the query
|
||||
*/
|
||||
|
||||
function getNotices($offset, $limit, $since_id=null, $max_id=null)
|
||||
{
|
||||
$ids = Notice::stream(array($this, '_streamDirect'),
|
||||
array(),
|
||||
'profile_tag:notice_ids:' . $this->id,
|
||||
$offset, $limit, $since_id, $max_id);
|
||||
|
||||
return Notice::getStreamByIds($ids);
|
||||
}
|
||||
|
||||
/**
|
||||
* Query notices by users associated with this tag from the database.
|
||||
*
|
||||
* @param integer $offset offset
|
||||
* @param integer $limit maximum no of results
|
||||
* @param integer $since_id=null since this id
|
||||
* @param integer $max_id=null maximum id in result
|
||||
*
|
||||
* @return array array of notice ids.
|
||||
*/
|
||||
|
||||
function _streamDirect($offset, $limit, $since_id, $max_id)
|
||||
{
|
||||
$inbox = new Profile_tag_inbox();
|
||||
|
||||
$inbox->profile_tag_id = $this->id;
|
||||
|
||||
$inbox->selectAdd();
|
||||
$inbox->selectAdd('notice_id');
|
||||
|
||||
if ($since_id != 0) {
|
||||
$inbox->whereAdd('notice_id > ' . $since_id);
|
||||
}
|
||||
|
||||
if ($max_id != 0) {
|
||||
$inbox->whereAdd('notice_id <= ' . $max_id);
|
||||
}
|
||||
|
||||
$inbox->orderBy('notice_id DESC');
|
||||
|
||||
if (!is_null($offset)) {
|
||||
$inbox->limit($offset, $limit);
|
||||
}
|
||||
|
||||
$ids = array();
|
||||
|
||||
if ($inbox->find()) {
|
||||
while ($inbox->fetch()) {
|
||||
$ids[] = $inbox->notice_id;
|
||||
}
|
||||
}
|
||||
|
||||
return $ids;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get subscribers (local and remote) to this people tag
|
||||
* Order by reverse chronology
|
||||
*
|
||||
* @param integer $offset offset
|
||||
* @param integer $limit maximum no of results
|
||||
* @param integer $since_id=null since unix timestamp
|
||||
* @param integer $upto=null maximum unix timestamp when subscription was made
|
||||
*
|
||||
* @return Profile results
|
||||
*/
|
||||
|
||||
function getSubscribers($offset=0, $limit=null, $since=0, $upto=0)
|
||||
{
|
||||
$subs = new Profile();
|
||||
$sub = new Profile_tag_subscription();
|
||||
$sub->profile_tag_id = $this->id;
|
||||
|
||||
$subs->joinAdd($sub);
|
||||
$subs->selectAdd('unix_timestamp(profile_tag_subscription.' .
|
||||
'created) as "cursor"');
|
||||
|
||||
if ($since != 0) {
|
||||
$subs->whereAdd('cursor > ' . $since);
|
||||
}
|
||||
|
||||
if ($upto != 0) {
|
||||
$subs->whereAdd('cursor <= ' . $upto);
|
||||
}
|
||||
|
||||
if ($limit != null) {
|
||||
$subs->limit($offset, $limit);
|
||||
}
|
||||
|
||||
$subs->orderBy('profile_tag_subscription.created DESC');
|
||||
$subs->find();
|
||||
|
||||
return $subs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all and only local subscribers to this people tag
|
||||
* used for distributing notices to user inboxes.
|
||||
*
|
||||
* @return array ids of users
|
||||
*/
|
||||
|
||||
function getUserSubscribers()
|
||||
{
|
||||
// XXX: cache this
|
||||
|
||||
$user = new User();
|
||||
if(common_config('db','quote_identifiers'))
|
||||
$user_table = '"user"';
|
||||
else $user_table = 'user';
|
||||
|
||||
$qry =
|
||||
'SELECT id ' .
|
||||
'FROM '. $user_table .' JOIN profile_tag_subscription '.
|
||||
'ON '. $user_table .'.id = profile_tag_subscription.profile_id ' .
|
||||
'WHERE profile_tag_subscription.profile_tag_id = %d ';
|
||||
|
||||
$user->query(sprintf($qry, $this->id));
|
||||
|
||||
$ids = array();
|
||||
|
||||
while ($user->fetch()) {
|
||||
$ids[] = $user->id;
|
||||
}
|
||||
|
||||
$user->free();
|
||||
|
||||
return $ids;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check to see if a given profile has
|
||||
* subscribed to this people tag's timeline
|
||||
*
|
||||
* @param mixed $id User or Profile object or integer id
|
||||
*
|
||||
* @return boolean subscription status
|
||||
*/
|
||||
|
||||
function hasSubscriber($id)
|
||||
{
|
||||
if (!is_numeric($id)) {
|
||||
$id = $id->id;
|
||||
}
|
||||
|
||||
$sub = Profile_tag_subscription::pkeyGet(array('profile_tag_id' => $this->id,
|
||||
'profile_id' => $id));
|
||||
return !empty($sub);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get profiles tagged with this people tag,
|
||||
* include modified timestamp as a "cursor" field
|
||||
* order by descending order of modified time
|
||||
*
|
||||
* @param integer $offset offset
|
||||
* @param integer $limit maximum no of results
|
||||
* @param integer $since_id=null since unix timestamp
|
||||
* @param integer $upto=null maximum unix timestamp when subscription was made
|
||||
*
|
||||
* @return Profile results
|
||||
*/
|
||||
|
||||
function getTagged($offset=0, $limit=null, $since=0, $upto=0)
|
||||
{
|
||||
$tagged = new Profile();
|
||||
$tagged->joinAdd(array('id', 'profile_tag:tagged'));
|
||||
|
||||
#@fixme: postgres
|
||||
$tagged->selectAdd('unix_timestamp(profile_tag.modified) as "cursor"');
|
||||
$tagged->whereAdd('profile_tag.tagger = '.$this->tagger);
|
||||
$tagged->whereAdd("profile_tag.tag = '{$this->tag}'");
|
||||
|
||||
if ($since != 0) {
|
||||
$tagged->whereAdd('cursor > ' . $since);
|
||||
}
|
||||
|
||||
if ($upto != 0) {
|
||||
$tagged->whereAdd('cursor <= ' . $upto);
|
||||
}
|
||||
|
||||
if ($limit != null) {
|
||||
$tagged->limit($offset, $limit);
|
||||
}
|
||||
|
||||
$tagged->orderBy('profile_tag.modified DESC');
|
||||
$tagged->find();
|
||||
|
||||
return $tagged;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gracefully delete one or many people tags
|
||||
* along with their members and subscriptions data
|
||||
*
|
||||
* @return boolean success
|
||||
*/
|
||||
|
||||
function delete()
|
||||
{
|
||||
// force delete one item at a time.
|
||||
if (empty($this->id)) {
|
||||
$this->find();
|
||||
while ($this->fetch()) {
|
||||
$this->delete();
|
||||
}
|
||||
}
|
||||
|
||||
Profile_tag::cleanup($this);
|
||||
Profile_tag_subscription::cleanup($this);
|
||||
|
||||
return parent::delete();
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a people tag gracefully
|
||||
* also change "tag" fields in profile_tag table
|
||||
*
|
||||
* @param Profile_list $orig Object's original form
|
||||
*
|
||||
* @return boolean success
|
||||
*/
|
||||
|
||||
function update($orig=null)
|
||||
{
|
||||
$result = true;
|
||||
|
||||
if (!is_object($orig) && !$orig instanceof Profile_list) {
|
||||
parent::update($orig);
|
||||
}
|
||||
|
||||
// if original tag was different
|
||||
// check to see if the new tag already exists
|
||||
// if not, rename the tag correctly
|
||||
if($orig->tag != $this->tag || $orig->tagger != $this->tagger) {
|
||||
$existing = Profile_list::getByTaggerAndTag($this->tagger, $this->tag);
|
||||
if(!empty($existing)) {
|
||||
throw new ServerException(_('The tag you are trying to rename ' .
|
||||
'to already exists.'));
|
||||
}
|
||||
// move the tag
|
||||
// XXX: allow OStatus plugin to send out profile tag
|
||||
$result = Profile_tag::moveTag($orig, $this);
|
||||
}
|
||||
parent::update($orig);
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* return an xml string representing this people tag
|
||||
* as the author of an atom feed
|
||||
*
|
||||
* @return string atom author element
|
||||
*/
|
||||
|
||||
function asAtomAuthor()
|
||||
{
|
||||
$xs = new XMLStringer(true);
|
||||
|
||||
$tagger = $this->getTagger();
|
||||
$xs->elementStart('author');
|
||||
$xs->element('name', null, '@' . $tagger->nickname . '/' . $this->tag);
|
||||
$xs->element('uri', null, $this->permalink());
|
||||
$xs->elementEnd('author');
|
||||
|
||||
return $xs->getString();
|
||||
}
|
||||
|
||||
/**
|
||||
* return an xml string to represent this people tag
|
||||
* as the subject of an activitystreams feed.
|
||||
*
|
||||
* @return string activitystreams subject
|
||||
*/
|
||||
|
||||
function asActivitySubject()
|
||||
{
|
||||
return $this->asActivityNoun('subject');
|
||||
}
|
||||
|
||||
/**
|
||||
* return an xml string to represent this people tag
|
||||
* as a noun in an activitystreams feed.
|
||||
*
|
||||
* @param string $element the xml tag
|
||||
*
|
||||
* @return string activitystreams noun
|
||||
*/
|
||||
|
||||
function asActivityNoun($element)
|
||||
{
|
||||
$noun = ActivityObject::fromPeopletag($this);
|
||||
return $noun->asString('activity:' . $element);
|
||||
}
|
||||
|
||||
/**
|
||||
* get the cached number of profiles tagged with this
|
||||
* people tag, re-count if the argument is true.
|
||||
*
|
||||
* @param boolean $recount whether to ignore cache
|
||||
*
|
||||
* @return integer count
|
||||
*/
|
||||
|
||||
function taggedCount($recount=false)
|
||||
{
|
||||
if (!$recount) {
|
||||
return $this->tagged_count;
|
||||
}
|
||||
|
||||
$tags = new Profile_tag();
|
||||
$tags->tag = $this->tag;
|
||||
$tags->tagger = $this->tagger;
|
||||
$orig = clone($this);
|
||||
$this->tagged_count = (int) $tags->count('distinct tagged');
|
||||
$this->update($orig);
|
||||
|
||||
return $this->tagged_count;
|
||||
}
|
||||
|
||||
/**
|
||||
* get the cached number of profiles subscribed to this
|
||||
* people tag, re-count if the argument is true.
|
||||
*
|
||||
* @param boolean $recount whether to ignore cache
|
||||
*
|
||||
* @return integer count
|
||||
*/
|
||||
|
||||
function subscriberCount($recount=false)
|
||||
{
|
||||
if ($recount) {
|
||||
return $this->subscriber_count;
|
||||
}
|
||||
|
||||
$sub = new Profile_tag_subscription();
|
||||
$sub->profile_tag_id = $this->id;
|
||||
$orig = clone($this);
|
||||
$this->subscriber_count = (int) $sub->count('distinct profile_id');
|
||||
$this->update($orig);
|
||||
|
||||
return $this->subscriber_count;
|
||||
}
|
||||
|
||||
/**
|
||||
* get the Profile_list object by the
|
||||
* given tagger and with given tag
|
||||
*
|
||||
* @param integer $tagger the id of the creator profile
|
||||
* @param integer $tag the tag
|
||||
*
|
||||
* @return integer count
|
||||
*/
|
||||
|
||||
static function getByTaggerAndTag($tagger, $tag)
|
||||
{
|
||||
$ptag = Profile_list::pkeyGet(array('tagger' => $tagger, 'tag' => $tag));
|
||||
return $ptag;
|
||||
}
|
||||
|
||||
/**
|
||||
* create a profile_list record for a tag, tagger pair
|
||||
* if it doesn't exist, return it.
|
||||
*
|
||||
* @param integer $tagger the tagger
|
||||
* @param string $tag the tag
|
||||
* @param string $description description
|
||||
* @param boolean $private protected or not
|
||||
*
|
||||
* @return Profile_list the people tag object
|
||||
*/
|
||||
|
||||
static function ensureTag($tagger, $tag, $description=null, $private=false)
|
||||
{
|
||||
$ptag = Profile_list::getByTaggerAndTag($tagger, $tag);
|
||||
|
||||
if(empty($ptag->id)) {
|
||||
$args = array(
|
||||
'tag' => $tag,
|
||||
'tagger' => $tagger,
|
||||
'description' => $description,
|
||||
'private' => $private
|
||||
);
|
||||
|
||||
$new_tag = Profile_list::saveNew($args);
|
||||
|
||||
return $new_tag;
|
||||
}
|
||||
return $ptag;
|
||||
}
|
||||
|
||||
/**
|
||||
* get the maximum number of characters
|
||||
* that can be used in the description of
|
||||
* a people tag.
|
||||
*
|
||||
* determined by $config['peopletag']['desclimit']
|
||||
* if not set, falls back to $config['site']['textlimit']
|
||||
*
|
||||
* @return integer maximum number of characters
|
||||
*/
|
||||
|
||||
static function maxDescription()
|
||||
{
|
||||
$desclimit = common_config('peopletag', 'desclimit');
|
||||
// null => use global limit (distinct from 0!)
|
||||
if (is_null($desclimit)) {
|
||||
$desclimit = common_config('site', 'textlimit');
|
||||
}
|
||||
return $desclimit;
|
||||
}
|
||||
|
||||
/**
|
||||
* check if the length of given text exceeds
|
||||
* character limit.
|
||||
*
|
||||
* @param string $desc the description
|
||||
*
|
||||
* @return boolean is the descripition too long?
|
||||
*/
|
||||
|
||||
static function descriptionTooLong($desc)
|
||||
{
|
||||
$desclimit = self::maxDescription();
|
||||
return ($desclimit > 0 && !empty($desc) && (mb_strlen($desc) > $desclimit));
|
||||
}
|
||||
|
||||
/**
|
||||
* save a new people tag, this should be always used
|
||||
* since it makes uri, homeurl, created and modified
|
||||
* timestamps and performs checks.
|
||||
*
|
||||
* @param array $fields an array with fields and their values
|
||||
*
|
||||
* @return mixed Profile_list on success, false on fail
|
||||
*/
|
||||
static function saveNew($fields) {
|
||||
|
||||
extract($fields);
|
||||
|
||||
$ptag = new Profile_list();
|
||||
|
||||
$ptag->query('BEGIN');
|
||||
|
||||
if (empty($tagger)) {
|
||||
throw new Exception(_('No tagger specified.'));
|
||||
}
|
||||
|
||||
if (empty($tag)) {
|
||||
throw new Exception(_('No tag specified.'));
|
||||
}
|
||||
|
||||
if (empty($mainpage)) {
|
||||
$mainpage = null;
|
||||
}
|
||||
|
||||
if (empty($uri)) {
|
||||
// fill in later...
|
||||
$uri = null;
|
||||
}
|
||||
|
||||
if (empty($mainpage)) {
|
||||
$mainpage = null;
|
||||
}
|
||||
|
||||
if (empty($description)) {
|
||||
$description = null;
|
||||
}
|
||||
|
||||
if (empty($private)) {
|
||||
$private = false;
|
||||
}
|
||||
|
||||
$ptag->tagger = $tagger;
|
||||
$ptag->tag = $tag;
|
||||
$ptag->description = $description;
|
||||
$ptag->private = $private;
|
||||
$ptag->uri = $uri;
|
||||
$ptag->mainpage = $mainpage;
|
||||
$ptag->created = common_sql_now();
|
||||
$ptag->modified = common_sql_now();
|
||||
|
||||
$result = $ptag->insert();
|
||||
|
||||
if (!$result) {
|
||||
common_log_db_error($ptag, 'INSERT', __FILE__);
|
||||
throw new ServerException(_('Could not create profile tag.'));
|
||||
}
|
||||
|
||||
if (!isset($uri) || empty($uri)) {
|
||||
$orig = clone($ptag);
|
||||
$ptag->uri = common_local_url('profiletagbyid', array('id' => $ptag->id, 'tagger_id' => $ptag->tagger));
|
||||
$result = $ptag->update($orig);
|
||||
if (!$result) {
|
||||
common_log_db_error($ptag, 'UPDATE', __FILE__);
|
||||
throw new ServerException(_('Could not set profile tag URI.'));
|
||||
}
|
||||
}
|
||||
|
||||
if (!isset($mainpage) || empty($mainpage)) {
|
||||
$orig = clone($ptag);
|
||||
$user = User::staticGet('id', $ptag->tagger);
|
||||
if(!empty($user)) {
|
||||
$ptag->mainpage = common_local_url('showprofiletag', array('tag' => $ptag->tag, 'tagger' => $user->nickname));
|
||||
} else {
|
||||
$ptag->mainpage = $uri; // assume this is a remote peopletag and the uri works
|
||||
}
|
||||
|
||||
$result = $ptag->update($orig);
|
||||
if (!$result) {
|
||||
common_log_db_error($ptag, 'UPDATE', __FILE__);
|
||||
throw new ServerException(_('Could not set profile tag mainpage.'));
|
||||
}
|
||||
}
|
||||
return $ptag;
|
||||
}
|
||||
|
||||
/**
|
||||
* get all items at given cursor position for api
|
||||
*
|
||||
* @param callback $fn a function that takes the following arguments in order:
|
||||
* $offset, $limit, $since_id, $max_id
|
||||
* and returns a Profile_list object after making the DB query
|
||||
* @param array $args arguments required for $fn
|
||||
* @param integer $cursor the cursor
|
||||
* @param integer $count max. number of results
|
||||
*
|
||||
* Algorithm:
|
||||
* - if cursor is 0, return empty list
|
||||
* - if cursor is -1, get first 21 items, next_cursor = 20th prev_cursor = 0
|
||||
* - if cursor is +ve get 22 consecutive items before starting at cursor
|
||||
* - return items[1..20] if items[0] == cursor else return items[0..21]
|
||||
* - prev_cursor = items[1]
|
||||
* - next_cursor = id of the last item being returned
|
||||
*
|
||||
* - if cursor is -ve get 22 consecutive items after cursor starting at cursor
|
||||
* - return items[1..20]
|
||||
*
|
||||
* @returns array (array (mixed items), int next_cursor, int previous_cursor)
|
||||
*/
|
||||
|
||||
// XXX: This should be in Memcached_DataObject... eventually.
|
||||
|
||||
static function getAtCursor($fn, $args, $cursor, $count=20)
|
||||
{
|
||||
$items = array();
|
||||
|
||||
$since_id = 0;
|
||||
$max_id = 0;
|
||||
$next_cursor = 0;
|
||||
$prev_cursor = 0;
|
||||
|
||||
if($cursor > 0) {
|
||||
// if cursor is +ve fetch $count+2 items before cursor starting at cursor
|
||||
$max_id = $cursor;
|
||||
$fn_args = array_merge($args, array(0, $count+2, 0, $max_id));
|
||||
$list = call_user_func_array($fn, $fn_args);
|
||||
while($list->fetch()) {
|
||||
$items[] = clone($list);
|
||||
}
|
||||
|
||||
if ((isset($items[0]->cursor) && $items[0]->cursor == $cursor) ||
|
||||
$items[0]->id == $cursor) {
|
||||
array_shift($items);
|
||||
$prev_cursor = isset($items[0]->cursor) ?
|
||||
-$items[0]->cursor : -$items[0]->id;
|
||||
} else {
|
||||
if (count($items) > $count+1) {
|
||||
array_shift($items);
|
||||
}
|
||||
// this means the cursor item has been deleted, check to see if there are more
|
||||
$fn_args = array_merge($args, array(0, 1, $cursor));
|
||||
$more = call_user_func($fn, $fn_args);
|
||||
if (!$more->fetch() || empty($more)) {
|
||||
// no more items.
|
||||
$prev_cursor = 0;
|
||||
} else {
|
||||
$prev_cursor = isset($items[0]->cursor) ?
|
||||
-$items[0]->cursor : -$items[0]->id;
|
||||
}
|
||||
}
|
||||
|
||||
if (count($items)==$count+1) {
|
||||
// this means there is a next page.
|
||||
$next = array_pop($items);
|
||||
$next_cursor = isset($next->cursor) ?
|
||||
$items[$count-1]->cursor : $items[$count-1]->id;
|
||||
}
|
||||
|
||||
} else if($cursor < -1) {
|
||||
// if cursor is -ve fetch $count+2 items created after -$cursor-1
|
||||
$cursor = abs($cursor);
|
||||
$since_id = $cursor-1;
|
||||
|
||||
$fn_args = array_merge($args, array(0, $count+2, $since_id));
|
||||
$list = call_user_func_array($fn, $fn_args);
|
||||
while($list->fetch()) {
|
||||
$items[] = clone($list);
|
||||
}
|
||||
|
||||
$end = count($items)-1;
|
||||
if ((isset($items[$end]->cursor) && $items[$end]->cursor == $cursor) ||
|
||||
$items[$end]->id == $cursor) {
|
||||
array_pop($items);
|
||||
$next_cursor = isset($items[$end-1]->cursor) ?
|
||||
$items[$end-1]->cursor : $items[$end-1]->id;
|
||||
} else {
|
||||
$next_cursor = isset($items[$end]->cursor) ?
|
||||
$items[$end]->cursor : $items[$end]->id;
|
||||
if ($end > $count) array_pop($items); // excess item.
|
||||
|
||||
// check if there are more items for next page
|
||||
$fn_args = array_merge($args, array(0, 1, 0, $cursor));
|
||||
$more = call_user_func_array($fn, $fn_args);
|
||||
if (!$more->fetch() || empty($more)) {
|
||||
$next_cursor = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (count($items) == $count+1) {
|
||||
// this means there is a previous page.
|
||||
$prev = array_shift($items);
|
||||
$prev_cursor = isset($prev->cursor) ?
|
||||
-$items[0]->cursor : -$items[0]->id;
|
||||
}
|
||||
} else if($cursor == -1) {
|
||||
$fn_args = array_merge($args, array(0, $count+1));
|
||||
$list = call_user_func_array($fn, $fn_args);
|
||||
|
||||
while($list->fetch()) {
|
||||
$items[] = clone($list);
|
||||
}
|
||||
|
||||
if (count($items)==$count+1) {
|
||||
$next = array_pop($items);
|
||||
if(isset($next->cursor)) {
|
||||
$next_cursor = $items[$count-1]->cursor;
|
||||
} else {
|
||||
$next_cursor = $items[$count-1]->id;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return array($items, $next_cursor, $prev_cursor);
|
||||
}
|
||||
|
||||
/**
|
||||
* save a collection of people tags into the cache
|
||||
*
|
||||
* @param string $ckey cache key
|
||||
* @param Profile_list &$tag the results to store
|
||||
* @param integer $offset offset for slicing results
|
||||
* @param integer $limit maximum number of results
|
||||
*
|
||||
* @return boolean success
|
||||
*/
|
||||
|
||||
static function setCache($ckey, &$tag, $offset=0, $limit=null) {
|
||||
$cache = Cache::instance();
|
||||
if (empty($cache)) {
|
||||
return false;
|
||||
}
|
||||
$str = '';
|
||||
$tags = array();
|
||||
while ($tag->fetch()) {
|
||||
$str .= $tag->tagger . ':' . $tag->tag . ';';
|
||||
$tags[] = clone($tag);
|
||||
}
|
||||
$str = substr($str, 0, -1);
|
||||
if ($offset>=0 && !is_null($limit)) {
|
||||
$tags = array_slice($tags, $offset, $limit);
|
||||
}
|
||||
|
||||
$tag = new ArrayWrapper($tags);
|
||||
|
||||
return self::cacheSet($ckey, $str);
|
||||
}
|
||||
|
||||
/**
|
||||
* get people tags from the cache
|
||||
*
|
||||
* @param string $ckey cache key
|
||||
* @param integer $offset offset for slicing
|
||||
* @param integer $limit limit
|
||||
*
|
||||
* @return Profile_list results
|
||||
*/
|
||||
|
||||
static function getCached($ckey, $offset=0, $limit=null) {
|
||||
|
||||
$keys_str = self::cacheGet($ckey);
|
||||
if ($keys_str === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$pairs = explode(';', $keys_str);
|
||||
$keys = array();
|
||||
foreach ($pairs as $pair) {
|
||||
$keys[] = explode(':', $pair);
|
||||
}
|
||||
|
||||
if ($offset>=0 && !is_null($limit)) {
|
||||
$keys = array_slice($keys, $offset, $limit);
|
||||
}
|
||||
return self::getByKeys($keys);
|
||||
}
|
||||
|
||||
/**
|
||||
* get Profile_list objects from the database
|
||||
* given their (tag, tagger) key pairs.
|
||||
*
|
||||
* @param array $keys array of array(tagger, tag)
|
||||
*
|
||||
* @return Profile_list results
|
||||
*/
|
||||
|
||||
static function getByKeys($keys) {
|
||||
$cache = Cache::instance();
|
||||
|
||||
if (!empty($cache)) {
|
||||
$tags = array();
|
||||
|
||||
foreach ($keys as $key) {
|
||||
$t = Profile_list::getByTaggerAndTag($key[0], $key[1]);
|
||||
if (!empty($t)) {
|
||||
$tags[] = $t;
|
||||
}
|
||||
}
|
||||
return new ArrayWrapper($tags);
|
||||
} else {
|
||||
$tag = new Profile_list();
|
||||
if (empty($keys)) {
|
||||
//if no IDs requested, just return the tag object
|
||||
return $tag;
|
||||
}
|
||||
|
||||
$pairs = array();
|
||||
foreach ($keys as $key) {
|
||||
$pairs[] = '(' . $key[0] . ', "' . $key[1] . '")';
|
||||
}
|
||||
|
||||
$tag->whereAdd('(tagger, tag) in (' . implode(', ', $pairs) . ')');
|
||||
|
||||
$tag->find();
|
||||
|
||||
$temp = array();
|
||||
|
||||
while ($tag->fetch()) {
|
||||
$temp[$tag->tagger.'-'.$tag->tag] = clone($tag);
|
||||
}
|
||||
|
||||
$wrapped = array();
|
||||
|
||||
foreach ($keys as $key) {
|
||||
$id = $key[0].'-'.$key[1];
|
||||
if (array_key_exists($id, $temp)) {
|
||||
$wrapped[] = $temp[$id];
|
||||
}
|
||||
}
|
||||
|
||||
return new ArrayWrapper($wrapped);
|
||||
}
|
||||
}
|
||||
}
|
@ -22,31 +22,91 @@ class Profile_tag extends Memcached_DataObject
|
||||
/* the code above is auto generated do not remove the tag below */
|
||||
###END_AUTOCODE
|
||||
|
||||
static function getTags($tagger, $tagged) {
|
||||
$tags = array();
|
||||
function pkeyGet($kv) {
|
||||
return Memcached_DataObject::pkeyGet('Profile_tag', $kv);
|
||||
}
|
||||
|
||||
# XXX: store this in memcached
|
||||
function links()
|
||||
{
|
||||
return array('tagger,tag' => 'profile_list:tagger,tag');
|
||||
}
|
||||
|
||||
$profile_tag = new Profile_tag();
|
||||
$profile_tag->tagger = $tagger;
|
||||
$profile_tag->tagged = $tagged;
|
||||
function getMeta()
|
||||
{
|
||||
return Profile_list::pkeyGet(array('tagger' => $this->tagger, 'tag' => $this->tag));
|
||||
}
|
||||
|
||||
$profile_tag->find();
|
||||
static function getTags($tagger, $tagged, $auth_user=null) {
|
||||
|
||||
while ($profile_tag->fetch()) {
|
||||
$tags[] = $profile_tag->tag;
|
||||
$profile_list = new Profile_list();
|
||||
$include_priv = 1;
|
||||
|
||||
if (!($auth_user instanceof User ||
|
||||
$auth_user instanceof Profile) ||
|
||||
($auth_user->id !== $tagger)) {
|
||||
|
||||
$profile_list->private = false;
|
||||
$include_priv = 0;
|
||||
}
|
||||
|
||||
$profile_tag->free();
|
||||
$key = sprintf('profile_tag:tagger_tagged_privacy:%d-%d-%d', $tagger, $tagged, $include_priv);
|
||||
$tags = Profile_list::getCached($key);
|
||||
if ($tags !== false) {
|
||||
return $tags;
|
||||
}
|
||||
|
||||
$profile_tag = new Profile_tag();
|
||||
$profile_list->tagger = $tagger;
|
||||
$profile_tag->tagged = $tagged;
|
||||
|
||||
$profile_list->selectAdd();
|
||||
|
||||
// only fetch id, tag, mainpage and
|
||||
// private hoping this will be faster
|
||||
$profile_list->selectAdd('profile_list.id, ' .
|
||||
'profile_list.tag, ' .
|
||||
'profile_list.mainpage, ' .
|
||||
'profile_list.private');
|
||||
$profile_list->joinAdd($profile_tag);
|
||||
$profile_list->find();
|
||||
|
||||
Profile_list::setCache($key, $profile_list);
|
||||
|
||||
return $profile_list;
|
||||
}
|
||||
|
||||
static function getTagsArray($tagger, $tagged, $auth_user_id=null)
|
||||
{
|
||||
$ptag = new Profile_tag();
|
||||
$ptag->tagger = $tagger;
|
||||
$ptag->tagged = $tagged;
|
||||
|
||||
if ($tagger != $auth_user_id) {
|
||||
$list = new Profile_list();
|
||||
$list->private = false;
|
||||
$ptag->joinAdd($list);
|
||||
$ptag->selectAdd();
|
||||
$ptag->selectAdd('profile_tag.tag');
|
||||
}
|
||||
|
||||
$tags = array();
|
||||
$ptag->find();
|
||||
while ($ptag->fetch()) {
|
||||
$tags[] = $ptag->tag;
|
||||
}
|
||||
$ptag->free();
|
||||
|
||||
return $tags;
|
||||
}
|
||||
|
||||
static function setTags($tagger, $tagged, $newtags) {
|
||||
$newtags = array_unique($newtags);
|
||||
$oldtags = Profile_tag::getTags($tagger, $tagged);
|
||||
static function setTags($tagger, $tagged, $newtags, $privacy=array()) {
|
||||
|
||||
# Delete stuff that's old that not in new
|
||||
$newtags = array_unique($newtags);
|
||||
$oldtags = self::getTagsArray($tagger, $tagged, $tagger);
|
||||
|
||||
$ptag = new Profile_tag();
|
||||
|
||||
# Delete stuff that's in old and not in new
|
||||
|
||||
$to_delete = array_diff($oldtags, $newtags);
|
||||
|
||||
@ -54,48 +114,161 @@ class Profile_tag extends Memcached_DataObject
|
||||
|
||||
$to_insert = array_diff($newtags, $oldtags);
|
||||
|
||||
$profile_tag = new Profile_tag();
|
||||
|
||||
$profile_tag->tagger = $tagger;
|
||||
$profile_tag->tagged = $tagged;
|
||||
|
||||
$profile_tag->query('BEGIN');
|
||||
|
||||
foreach ($to_delete as $deltag) {
|
||||
$profile_tag->tag = $deltag;
|
||||
$result = $profile_tag->delete();
|
||||
if (!$result) {
|
||||
common_log_db_error($profile_tag, 'DELETE', __FILE__);
|
||||
return false;
|
||||
}
|
||||
self::unTag($tagger, $tagged, $deltag);
|
||||
}
|
||||
|
||||
foreach ($to_insert as $instag) {
|
||||
$profile_tag->tag = $instag;
|
||||
$result = $profile_tag->insert();
|
||||
if (!$result) {
|
||||
common_log_db_error($profile_tag, 'INSERT', __FILE__);
|
||||
return false;
|
||||
}
|
||||
$private = isset($privacy[$instag]) ? $privacy[$instag] : false;
|
||||
self::setTag($tagger, $tagged, $instag, null, $private);
|
||||
}
|
||||
|
||||
$profile_tag->query('COMMIT');
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
# Return profiles with a given tag
|
||||
static function getTagged($tagger, $tag) {
|
||||
$profile = new Profile();
|
||||
$profile->query('SELECT profile.* ' .
|
||||
'FROM profile JOIN profile_tag ' .
|
||||
'ON profile.id = profile_tag.tagged ' .
|
||||
'WHERE profile_tag.tagger = ' . $tagger . ' ' .
|
||||
'AND profile_tag.tag = "' . $tag . '" ');
|
||||
$tagged = array();
|
||||
while ($profile->fetch()) {
|
||||
$tagged[] = clone($profile);
|
||||
# set a single tag
|
||||
static function setTag($tagger, $tagged, $tag, $desc=null, $private=false) {
|
||||
|
||||
$ptag = Profile_tag::pkeyGet(array('tagger' => $tagger,
|
||||
'tagged' => $tagged,
|
||||
'tag' => $tag));
|
||||
|
||||
# if tag already exists, return it
|
||||
if(!empty($ptag)) {
|
||||
return $ptag;
|
||||
}
|
||||
return $tagged;
|
||||
|
||||
$tagger_profile = Profile::staticGet('id', $tagger);
|
||||
$tagged_profile = Profile::staticGet('id', $tagged);
|
||||
|
||||
if (Event::handle('StartTagProfile', array($tagger_profile, $tagged_profile, $tag))) {
|
||||
|
||||
if (!$tagger_profile->canTag($tagged_profile)) {
|
||||
throw new ClientException(_('You cannot tag this user.'));
|
||||
return false;
|
||||
}
|
||||
|
||||
$tags = new Profile_list();
|
||||
$tags->tagger = $tagger;
|
||||
$count = (int) $tags->count('distinct tag');
|
||||
|
||||
if ($count >= common_config('peopletag', 'maxtags')) {
|
||||
throw new ClientException(sprintf(_('You already have created %d or more tags ' .
|
||||
'which is the maximum allowed number of tags. ' .
|
||||
'Try using or deleting some existing tags.'),
|
||||
common_config('peopletag', 'maxtags')));
|
||||
return false;
|
||||
}
|
||||
|
||||
$plist = new Profile_list();
|
||||
$plist->query('BEGIN');
|
||||
|
||||
$profile_list = Profile_list::ensureTag($tagger, $tag, $desc, $private);
|
||||
|
||||
if ($profile_list->taggedCount() >= common_config('peopletag', 'maxpeople')) {
|
||||
throw new ClientException(sprintf(_('You already have %d or more people tagged %s ' .
|
||||
'which is the maximum allowed number.' .
|
||||
'Try untagging others with the same tag first.'),
|
||||
common_config('peopletag', 'maxpeople'), $tag));
|
||||
return false;
|
||||
}
|
||||
|
||||
$newtag = new Profile_tag();
|
||||
|
||||
$newtag->tagger = $tagger;
|
||||
$newtag->tagged = $tagged;
|
||||
$newtag->tag = $tag;
|
||||
|
||||
$result = $newtag->insert();
|
||||
|
||||
|
||||
if (!$result) {
|
||||
common_log_db_error($newtag, 'INSERT', __FILE__);
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
$plist->query('COMMIT');
|
||||
Event::handle('EndTagProfile', array($newtag));
|
||||
} catch (Exception $e) {
|
||||
$newtag->delete();
|
||||
$profile_list->delete();
|
||||
throw $e;
|
||||
return false;
|
||||
}
|
||||
|
||||
$profile_list->taggedCount(true);
|
||||
self::blowCaches($tagger, $tagged);
|
||||
}
|
||||
|
||||
return $newtag;
|
||||
}
|
||||
|
||||
static function unTag($tagger, $tagged, $tag) {
|
||||
$ptag = Profile_tag::pkeyGet(array('tagger' => $tagger,
|
||||
'tagged' => $tagged,
|
||||
'tag' => $tag));
|
||||
if (!$ptag) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (Event::handle('StartUntagProfile', array($ptag))) {
|
||||
$orig = clone($ptag);
|
||||
$result = $ptag->delete();
|
||||
if (!$result) {
|
||||
common_log_db_error($this, 'DELETE', __FILE__);
|
||||
return false;
|
||||
}
|
||||
Event::handle('EndUntagProfile', array($orig));
|
||||
if ($result) {
|
||||
$profile_list = Profile_list::pkeyGet(array('tag' => $tag, 'tagger' => $tagger));
|
||||
$profile_list->taggedCount(true);
|
||||
self::blowCaches($tagger, $tagged);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// @fixme: move this to Profile_list?
|
||||
static function cleanup($profile_list) {
|
||||
$ptag = new Profile_tag();
|
||||
$ptag->tagger = $profile_list->tagger;
|
||||
$ptag->tag = $profile_list->tag;
|
||||
$ptag->find();
|
||||
|
||||
while($ptag->fetch()) {
|
||||
if (Event::handle('StartUntagProfile', array($ptag))) {
|
||||
$orig = clone($ptag);
|
||||
$result = $ptag->delete();
|
||||
if (!$result) {
|
||||
common_log_db_error($this, 'DELETE', __FILE__);
|
||||
}
|
||||
Event::handle('EndUntagProfile', array($orig));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// move a tag!
|
||||
static function moveTag($orig, $new) {
|
||||
$tags = new Profile_tag();
|
||||
$qry = 'UPDATE profile_tag SET ' .
|
||||
'tag = "%s", tagger = "%s" ' .
|
||||
'WHERE tag = "%s" ' .
|
||||
'AND tagger = "%s"';
|
||||
$result = $tags->query(sprintf($qry, $new->tag, $new->tagger,
|
||||
$orig->tag, $orig->tagger));
|
||||
|
||||
if (!$result) {
|
||||
common_log_db_error($tags, 'UPDATE', __FILE__);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static function blowCaches($tagger, $tagged) {
|
||||
foreach (array(0, 1) as $perm) {
|
||||
self::blow(sprintf('profile_tag:tagger_tagged_privacy:%d-%d-%d', $tagger, $tagged, $perm));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
27
classes/Profile_tag_inbox.php
Normal file
27
classes/Profile_tag_inbox.php
Normal file
@ -0,0 +1,27 @@
|
||||
<?php
|
||||
/**
|
||||
* Table Definition for profile_tag_inbox
|
||||
*/
|
||||
|
||||
class Profile_tag_inbox extends Memcached_DataObject
|
||||
{
|
||||
###START_AUTOCODE
|
||||
/* the code below is auto generated do not remove the above tag */
|
||||
|
||||
public $__table = 'profile_tag_inbox'; // table name
|
||||
public $profile_tag_id; // int(4) primary_key not_null
|
||||
public $notice_id; // int(4) primary_key not_null
|
||||
public $created; // datetime() not_null
|
||||
|
||||
/* Static get */
|
||||
|
||||
function staticGet($k,$v=NULL) { return Memcached_DataObject::staticGet('Profile_tag_inbox',$k,$v); }
|
||||
|
||||
/* the code above is auto generated do not remove the tag below */
|
||||
###END_AUTOCODE
|
||||
|
||||
function pkeyGet($kv)
|
||||
{
|
||||
return Memcached_DataObject::pkeyGet('Profile_tag_inbox', $kv);
|
||||
}
|
||||
}
|
103
classes/Profile_tag_subscription.php
Normal file
103
classes/Profile_tag_subscription.php
Normal file
@ -0,0 +1,103 @@
|
||||
<?php
|
||||
/**
|
||||
* Table Definition for profile_tag_subscription
|
||||
*/
|
||||
require_once INSTALLDIR.'/classes/Memcached_DataObject.php';
|
||||
|
||||
class Profile_tag_subscription extends Memcached_DataObject
|
||||
{
|
||||
###START_AUTOCODE
|
||||
/* the code below is auto generated do not remove the above tag */
|
||||
|
||||
public $__table = 'profile_tag_subscription'; // table name
|
||||
public $profile_tag_id; // int(4) not_null
|
||||
public $profile_id; // int(4) not_null
|
||||
public $created; // datetime not_null default_0000-00-00%2000%3A00%3A00
|
||||
public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP
|
||||
|
||||
/* Static get */
|
||||
function staticGet($k,$v=null)
|
||||
{ return Memcached_DataObject::staticGet('Profile_tag_subscription',$k,$v); }
|
||||
|
||||
/* the code above is auto generated do not remove the tag below */
|
||||
###END_AUTOCODE
|
||||
|
||||
function pkeyGet($kv)
|
||||
{
|
||||
return Memcached_DataObject::pkeyGet('Profile_tag_subscription', $kv);
|
||||
}
|
||||
|
||||
static function add($peopletag, $profile)
|
||||
{
|
||||
if ($peopletag->private) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Event::handle('StartSubscribePeopletag', array($peopletag, $profile))) {
|
||||
$args = array('profile_tag_id' => $peopletag->id,
|
||||
'profile_id' => $profile->id);
|
||||
$existing = Profile_tag_subscription::pkeyGet($args);
|
||||
if(!empty($existing)) {
|
||||
return $existing;
|
||||
}
|
||||
|
||||
$sub = new Profile_tag_subscription();
|
||||
$sub->profile_tag_id = $peopletag->id;
|
||||
$sub->profile_id = $profile->id;
|
||||
$sub->created = common_sql_now();
|
||||
|
||||
$result = $sub->insert();
|
||||
|
||||
if (!$result) {
|
||||
common_log_db_error($sub, 'INSERT', __FILE__);
|
||||
throw new Exception(_("Adding people tag subscription failed."));
|
||||
}
|
||||
|
||||
$ptag = Profile_list::staticGet('id', $peopletag->id);
|
||||
$ptag->subscriberCount(true);
|
||||
|
||||
Event::handle('EndSubscribePeopletag', array($peopletag, $profile));
|
||||
return $ptag;
|
||||
}
|
||||
}
|
||||
|
||||
static function remove($peopletag, $profile)
|
||||
{
|
||||
$sub = Profile_tag_subscription::pkeyGet(array('profile_tag_id' => $peopletag->id,
|
||||
'profile_id' => $profile->id));
|
||||
|
||||
if (empty($sub)) {
|
||||
// silence is golden?
|
||||
return true;
|
||||
}
|
||||
|
||||
if (Event::handle('StartUnsubscribePeopletag', array($peopletag, $profile))) {
|
||||
$result = $sub->delete();
|
||||
|
||||
if (!$result) {
|
||||
common_log_db_error($sub, 'DELETE', __FILE__);
|
||||
throw new Exception(_("Removing people tag subscription failed."));
|
||||
}
|
||||
|
||||
$peopletag->subscriberCount(true);
|
||||
|
||||
Event::handle('EndUnsubscribePeopletag', array($peopletag, $profile));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// called if a tag gets deleted / made private
|
||||
static function cleanup($profile_list) {
|
||||
$subs = new self();
|
||||
$subs->profile_tag_id = $profile_list->id;
|
||||
$subs->find();
|
||||
|
||||
while($subs->fetch()) {
|
||||
$profile = Profile::staticGet('id', $subs->profile_id);
|
||||
Event::handle('StartUnsubscribePeopletag', array($profile_list, $profile));
|
||||
// Delete anyway
|
||||
$subs->delete();
|
||||
Event::handle('StartUnsubscribePeopletag', array($profile_list, $profile));
|
||||
}
|
||||
}
|
||||
}
|
@ -504,12 +504,12 @@ class User extends Memcached_DataObject
|
||||
|
||||
function getSelfTags()
|
||||
{
|
||||
return Profile_tag::getTags($this->id, $this->id);
|
||||
return Profile_tag::getTagsArray($this->id, $this->id, $this->id);
|
||||
}
|
||||
|
||||
function setSelfTags($newtags)
|
||||
function setSelfTags($newtags, $privacy)
|
||||
{
|
||||
return Profile_tag::setTags($this->id, $this->id, $newtags);
|
||||
return Profile_tag::setTags($this->id, $this->id, $newtags, $privacy);
|
||||
}
|
||||
|
||||
function block($other)
|
||||
|
@ -460,6 +460,43 @@ tagger = K
|
||||
tagged = K
|
||||
tag = K
|
||||
|
||||
[profile_list]
|
||||
id = 129
|
||||
tagger = 129
|
||||
tag = 130
|
||||
description = 34
|
||||
private = 17
|
||||
created = 142
|
||||
modified = 384
|
||||
uri = 130
|
||||
mainpage = 130
|
||||
tagged_count = 129
|
||||
subscriber_count = 129
|
||||
|
||||
[profile_list__keys]
|
||||
id = U
|
||||
tagger = K
|
||||
tag = K
|
||||
|
||||
[profile_tag_inbox]
|
||||
profile_tag_id = 129
|
||||
notice_id = 129
|
||||
created = 142
|
||||
|
||||
[profile_tag_inbox__keys]
|
||||
profile_tag_id = K
|
||||
notice_id = K
|
||||
|
||||
[profile_tag_subscription]
|
||||
profile_tag_id = 129
|
||||
profile_id = 129
|
||||
created = 142
|
||||
modified = 384
|
||||
|
||||
[profile_tag_subscription__keys]
|
||||
profile_tag_id = K
|
||||
profile_id = K
|
||||
|
||||
[queue_item]
|
||||
id = 129
|
||||
frame = 194
|
||||
|
@ -55,3 +55,23 @@ file_id = file:id
|
||||
file_id = file:id
|
||||
post_id = notice:id
|
||||
|
||||
[profile_list]
|
||||
tagger = profile:id
|
||||
|
||||
[profile_tag]
|
||||
tagger = profile:id
|
||||
tagged = profile:id
|
||||
; in class definition:
|
||||
;tag,tagger = profile_list:tag,tagger
|
||||
|
||||
[profile_list]
|
||||
tagger = profile:id
|
||||
|
||||
[profile_tag_inbox]
|
||||
profile_tag_id = profile_list:id
|
||||
notice_id = notice:id
|
||||
|
||||
[profile_tag_subscription]
|
||||
profile_tag_id = profile_list:id
|
||||
profile_id = profile:id
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user