Пример #1
0
 static function setTags($tagger, $tagged, $newtags)
 {
     $newtags = array_unique($newtags);
     $oldtags = Profile_tag::getTags($tagger, $tagged);
     # Delete stuff that's old that not in new
     $to_delete = array_diff($oldtags, $newtags);
     # Insert stuff that's in new and not in old
     $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;
         }
     }
     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;
         }
     }
     $profile_tag->query('COMMIT');
     return true;
 }
Пример #2
0
 function showTags()
 {
     $tags = Profile_tag::getTags($this->owner->id, $this->profile->id);
     $this->out->elementStart('dl', 'entity_tags');
     $this->out->elementStart('dt');
     if ($this->isOwn()) {
         $this->out->element('a', array('href' => common_local_url('tagother', array('id' => $this->profile->id))), _('Tags'));
     } else {
         $this->out->text(_('Tags'));
     }
     $this->out->elementEnd('dt');
     $this->out->elementStart('dd');
     if ($tags) {
         $this->out->elementStart('ul', 'tags xoxo');
         foreach ($tags as $tag) {
             $this->out->elementStart('li');
             $this->out->element('span', 'mark_hash', '#');
             $this->out->element('a', array('rel' => 'tag', 'href' => common_local_url($this->action->trimmed('action'), array('nickname' => $this->owner->nickname, 'tag' => $tag))), $tag);
             $this->out->elementEnd('li');
         }
         $this->out->elementEnd('ul');
     } else {
         $this->out->text(_('(none)'));
     }
     $this->out->elementEnd('dd');
     $this->out->elementEnd('dl');
 }
Пример #3
0
 /**
  * Remove a user from a list (untag someone)
  *
  * @return boolean success
  */
 function handleDelete()
 {
     if ($this->auth_user->id != $this->list->tagger) {
         // TRANS: Client error displayed when trying to remove members from a list without having the right to do so.
         $this->clientError(_('You are not allowed to remove members from this list.'), 401);
     }
     if (!$this->target instanceof Profile) {
         // TRANS: Client error displayed when trying to modify list members without specifying them.
         $this->clientError(_('You must specify a member.'));
     }
     $args = array('tagger' => $this->auth_user->id, 'tagged' => $this->target->id, 'tag' => $this->list->tag);
     $ptag = Profile_tag::pkeyGet($args);
     if (empty($ptag)) {
         // TRANS: Client error displayed when trying to remove a list member that is not part of a list.
         $this->clientError(_('The user you are trying to remove from the list is not a member.'));
     }
     if (!$ptag->delete()) {
         // TRANS: Client error displayed when an unknown error occurs viewing list members.
         $this->clientError(_('An error occured.'), 500);
     }
     switch ($this->format) {
         case 'xml':
             $this->showSingleXmlList($this->list);
             break;
         case 'json':
             $this->showSingleJsonList($this->list);
             break;
         default:
             // TRANS: Client error displayed when coming across a non-supported API method.
             $this->clientError(_('API method not found.'), 404);
     }
     return true;
 }
Пример #4
0
 /**
  * Remove a user from a list (untag someone)
  *
  * @return boolean success
  */
 function handleDelete()
 {
     if ($this->auth_user->id != $this->list->tagger) {
         $this->clientError(_('You are not allowed to remove members from this list.'), 401, $this->format);
         return false;
     }
     if ($this->user === false) {
         $this->clientError(_('You must specify a member.'), 400, $this->format);
         return false;
     }
     $args = array('tagger' => $this->auth_user->id, 'tagged' => $this->user->id, 'tag' => $this->list->tag);
     $ptag = Profile_tag::pkeyGet($args);
     if (empty($ptag)) {
         $this->clientError(_('The user you are trying to remove from the list is not a member.'), 400, $this->format);
         return false;
     }
     $result = $ptag->delete();
     if (empty($result)) {
         $this->clientError(_('An error occured.'), 500, $this->format);
         return false;
     }
     switch ($this->format) {
         case 'xml':
             $this->showSingleXmlList($this->list);
             break;
         case 'json':
             $this->showSingleJsonList($this->list);
             break;
         default:
             $this->clientError(_('API method not found.'), 404, $this->format);
             return false;
             break;
     }
     return true;
 }
Пример #5
0
 function showTags()
 {
     $tags = Profile_tag::getTags($this->owner->id, $this->profile->id);
     $this->out->elementStart('dl', 'entity_tags');
     $this->out->elementStart('dt');
     if ($this->isOwn()) {
         $this->out->element('a', array('href' => common_local_url('tagother', array('id' => $this->profile->id))), _('Tags'));
     } else {
         $this->out->text(_('Tags'));
     }
     $this->out->elementEnd('dt');
     $this->out->elementStart('dd');
     if ($tags) {
         $this->out->elementStart('ul', 'tags xoxo');
         foreach ($tags as $tag) {
             $this->out->elementStart('li');
             // Avoid space by using raw output.
             $pt = '<span class="mark_hash">#</span><a rel="tag" href="' . common_local_url($this->action->trimmed('action'), array('nickname' => $this->owner->nickname, 'tag' => $tag)) . '">' . $tag . '</a>';
             $this->out->raw($pt);
             $this->out->elementEnd('li');
         }
         $this->out->elementEnd('ul');
     } else {
         $this->out->text(_('(None)'));
     }
     $this->out->elementEnd('dd');
     $this->out->elementEnd('dl');
 }
Пример #6
0
 function __construct($out, $tagger, $tagged)
 {
     parent::__construct($out);
     $this->user = common_current_user();
     $this->tag = Profile_tag::getTags($tagger->id, $tagged->id, $this->user);
     $this->tagger = $tagger;
     $this->tagged = $tagged;
 }
Пример #7
0
 /**
  * Handle the request
  *
  * @return boolean success flag
  */
 function handle($args)
 {
     parent::handle($args);
     $arr = array('tagger' => $this->list->tagger, 'tag' => $this->list->tag, 'tagged' => $this->user->id);
     $ptag = Profile_tag::pkeyGet($arr);
     if (empty($ptag)) {
         $this->clientError(_('The specified user is not a member of this list.'), 400, $this->format);
     }
     $user = $this->twitterUserArray($this->user->getProfile(), true);
     switch ($this->format) {
         case 'xml':
             $this->showTwitterXmlUser($user, 'user', true);
             break;
         case 'json':
             $this->showSingleJsonUser($user);
             break;
         default:
             $this->clientError(_('API method not found.'), 404, $this->format);
             break;
     }
     return true;
 }
Пример #8
0
 /**
  * Handle the request
  *
  * @return boolean success flag
  */
 protected function handle()
 {
     parent::handle();
     $arr = array('tagger' => $this->list->tagger, 'tag' => $this->list->tag, 'tagged' => $this->target->id);
     $ptag = Profile_tag::pkeyGet($arr);
     if (empty($ptag)) {
         // TRANS: Client error displayed when referring to a non-list member.
         $this->clientError(_('The specified user is not a member of this list.'));
     }
     $user = $this->twitterUserArray($this->target, true);
     switch ($this->format) {
         case 'xml':
             $this->showTwitterXmlUser($user, 'user', true);
             break;
         case 'json':
             $this->showSingleJsonUser($user);
             break;
         default:
             // TRANS: Client error displayed when coming across a non-supported API method.
             $this->clientError(_('API method not found.'), 404);
     }
     return true;
 }
Пример #9
0
 function handle($channel)
 {
     $profile = $this->getProfile($this->other);
     $cur = $this->user->getProfile();
     if (!$profile) {
         // TRANS: Client error displayed trying to perform an action related to a non-existing profile.
         $channel->error($cur, _('No such profile.'));
         return;
     }
     if (!$cur->canTag($profile)) {
         // TRANS: Error displayed when trying to tag a user that cannot be tagged.
         $channel->error($cur, _('You cannot tag this user.'));
         return;
     }
     $tags = array_map('common_canonical_tag', preg_split('/[\\s,]+/', $this->tags));
     foreach ($tags as $tag) {
         if (!common_valid_profile_tag($tag)) {
             // TRANS: Error displayed if a given tag is invalid.
             // TRANS: %s is the invalid tag.
             $channel->error($cur, sprintf(_('Invalid tag: "%s"'), $tag));
             return;
         }
     }
     try {
         foreach ($tags as $tag) {
             Profile_tag::unTag($cur->id, $profile->id, $tag);
         }
     } catch (Exception $e) {
         // TRANS: Error displayed if untagging a user fails.
         // TRANS: %1$s is the untagged user, %2$s is the error message (no punctuation).
         $channel->error($cur, sprintf(_('Error untagging %1$s: %2$s'), $profile->nickname, $e->getMessage()));
         return;
     }
     // TRANS: Succes message displayed if untagging a user succeeds.
     // TRANS: %1$s is the untagged user's nickname, %2$s is a list of tags.
     // TRANS: Plural is decided based on the number of tags removed (not part of message).
     $channel->output($cur, sprintf(_m('The following tag was removed from user %1$s: %2$s.', 'The following tags were removed from user %1$s: %2$s.', count($tags)), $profile->nickname, implode(_(', '), $tags)));
 }
Пример #10
0
 function showProfile()
 {
     $this->out->elementStart('li', array('class' => 'profile', 'id' => 'profile-' . $this->profile->id));
     $user = common_current_user();
     $is_own = !is_null($user) && isset($this->owner) && $user->id === $this->owner->id;
     $this->out->elementStart('div', 'entity_profile vcard');
     $avatar = $this->profile->getAvatar(AVATAR_STREAM_SIZE);
     $this->out->elementStart('a', array('href' => $this->profile->profileurl, 'class' => 'url'));
     $this->out->element('img', array('src' => $avatar ? $avatar->displayUrl() : Avatar::defaultImage(AVATAR_STREAM_SIZE), 'class' => 'photo avatar', 'width' => AVATAR_STREAM_SIZE, 'height' => AVATAR_STREAM_SIZE, 'alt' => $this->profile->fullname ? $this->profile->fullname : $this->profile->nickname));
     $hasFN = $this->profile->fullname !== '' ? 'nickname' : 'fn nickname';
     $this->out->elementStart('span', $hasFN);
     $this->out->raw($this->highlight($this->profile->nickname));
     $this->out->elementEnd('span');
     $this->out->elementEnd('a');
     if (!empty($this->profile->fullname)) {
         $this->out->elementStart('dl', 'entity_fn');
         $this->out->element('dt', null, 'Full name');
         $this->out->elementStart('dd');
         $this->out->elementStart('span', 'fn');
         $this->out->raw($this->highlight($this->profile->fullname));
         $this->out->elementEnd('span');
         $this->out->elementEnd('dd');
         $this->out->elementEnd('dl');
     }
     if (!empty($this->profile->location)) {
         $this->out->elementStart('dl', 'entity_location');
         $this->out->element('dt', null, _('Location'));
         $this->out->elementStart('dd', 'label');
         $this->out->raw($this->highlight($this->profile->location));
         $this->out->elementEnd('dd');
         $this->out->elementEnd('dl');
     }
     if (!empty($this->profile->homepage)) {
         $this->out->elementStart('dl', 'entity_url');
         $this->out->element('dt', null, _('URL'));
         $this->out->elementStart('dd');
         $this->out->elementStart('a', array('href' => $this->profile->homepage, 'class' => 'url'));
         $this->out->raw($this->highlight($this->profile->homepage));
         $this->out->elementEnd('a');
         $this->out->elementEnd('dd');
         $this->out->elementEnd('dl');
     }
     if (!empty($this->profile->bio)) {
         $this->out->elementStart('dl', 'entity_note');
         $this->out->element('dt', null, _('Note'));
         $this->out->elementStart('dd', 'note');
         $this->out->raw($this->highlight($this->profile->bio));
         $this->out->elementEnd('dd');
         $this->out->elementEnd('dl');
     }
     # If we're on a list with an owner (subscriptions or subscribers)...
     if ($this->owner) {
         # Get tags
         $tags = Profile_tag::getTags($this->owner->id, $this->profile->id);
         $this->out->elementStart('dl', 'entity_tags');
         $this->out->elementStart('dt');
         if ($is_own) {
             $this->out->element('a', array('href' => common_local_url('tagother', array('id' => $this->profile->id))), _('Tags'));
         } else {
             $this->out->text(_('Tags'));
         }
         $this->out->elementEnd('dt');
         $this->out->elementStart('dd');
         if ($tags) {
             $this->out->elementStart('ul', 'tags xoxo');
             foreach ($tags as $tag) {
                 $this->out->elementStart('li');
                 $this->out->element('span', 'mark_hash', '#');
                 $this->out->element('a', array('rel' => 'tag', 'href' => common_local_url($this->action->trimmed('action'), array('nickname' => $this->owner->nickname, 'tag' => $tag))), $tag);
                 $this->out->elementEnd('li');
             }
             $this->out->elementEnd('ul');
         } else {
             $this->out->text(_('(none)'));
         }
         $this->out->elementEnd('dd');
         $this->out->elementEnd('dl');
     }
     if ($is_own) {
         $this->showOwnerControls($this->profile);
     }
     $this->out->elementEnd('div');
     $this->out->elementStart('div', 'entity_actions');
     $this->out->elementStart('ul');
     // Is this a logged-in user, looking at someone else's
     // profile?
     if (!empty($user) && $this->profile->id != $user->id) {
         $this->out->elementStart('li', 'entity_subscribe');
         if ($user->isSubscribed($this->profile)) {
             $usf = new UnsubscribeForm($this->out, $this->profile);
             $usf->show();
         } else {
             $sf = new SubscribeForm($this->out, $this->profile);
             $sf->show();
         }
         $this->out->elementEnd('li');
         $this->out->elementStart('li', 'entity_block');
         if ($user->id == $this->owner->id) {
             $this->showBlockForm();
         }
         $this->out->elementEnd('li');
     }
     $this->out->elementEnd('ul');
     $this->out->elementEnd('div');
     $this->out->elementEnd('li');
 }
Пример #11
0
function common_find_mentions($text, $notice)
{
    $mentions = array();
    $sender = Profile::staticGet('id', $notice->profile_id);
    if (empty($sender)) {
        return $mentions;
    }
    if (Event::handle('StartFindMentions', array($sender, $text, &$mentions))) {
        // Get the context of the original notice, if any
        $originalAuthor = null;
        $originalNotice = null;
        $originalMentions = array();
        // Is it a reply?
        if (!empty($notice) && !empty($notice->reply_to)) {
            $originalNotice = Notice::staticGet('id', $notice->reply_to);
            if (!empty($originalNotice)) {
                $originalAuthor = Profile::staticGet('id', $originalNotice->profile_id);
                $ids = $originalNotice->getReplies();
                foreach ($ids as $id) {
                    $repliedTo = Profile::staticGet('id', $id);
                    if (!empty($repliedTo)) {
                        $originalMentions[$repliedTo->nickname] = $repliedTo;
                    }
                }
            }
        }
        preg_match_all('/^T ([A-Z0-9]{1,64}) /u', $text, $tmatches, PREG_OFFSET_CAPTURE);
        preg_match_all('/(?:^|\\s+)@([' . NICKNAME_FMT . ']{1,64})/', $text, $atmatches, PREG_OFFSET_CAPTURE);
        $matches = array_merge($tmatches[1], $atmatches[1]);
        foreach ($matches as $match) {
            $nickname = common_canonical_nickname($match[0]);
            // Try to get a profile for this nickname.
            // Start with conversation context, then go to
            // sender context.
            if (!empty($originalAuthor) && $originalAuthor->nickname == $nickname) {
                $mentioned = $originalAuthor;
            } else {
                if (!empty($originalMentions) && array_key_exists($nickname, $originalMentions)) {
                    $mentioned = $originalMentions[$nickname];
                } else {
                    $mentioned = common_relative_profile($sender, $nickname);
                }
            }
            if (!empty($mentioned)) {
                $user = User::staticGet('id', $mentioned->id);
                if ($user) {
                    $url = common_local_url('userbyid', array('id' => $user->id));
                } else {
                    $url = $mentioned->profileurl;
                }
                $mention = array('mentioned' => array($mentioned), 'text' => $match[0], 'position' => $match[1], 'url' => $url);
                if (!empty($mentioned->fullname)) {
                    $mention['title'] = $mentioned->fullname;
                }
                $mentions[] = $mention;
            }
        }
        // @#tag => mention of all subscriptions tagged 'tag'
        preg_match_all('/(?:^|[\\s\\.\\,\\:\\;]+)@#([\\pL\\pN_\\-\\.]{1,64})/u', $text, $hmatches, PREG_OFFSET_CAPTURE);
        foreach ($hmatches[1] as $hmatch) {
            $tag = common_canonical_tag($hmatch[0]);
            $tagged = Profile_tag::getTagged($sender->id, $tag);
            $url = common_local_url('subscriptions', array('nickname' => $sender->nickname, 'tag' => $tag));
            $mentions[] = array('mentioned' => $tagged, 'text' => $hmatch[0], 'position' => $hmatch[1], 'url' => $url);
        }
        Event::handle('EndFindMentions', array($sender, $text, &$mentions));
    }
    return $mentions;
}
Пример #12
0
 /**
  * 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)
 {
     $keypart = sprintf('profile_list:tagged_count:%d:%s', $this->tagger, $this->tag);
     $count = self::cacheGet($keypart);
     if ($count === false) {
         $tags = new Profile_tag();
         $tags->tag = $this->tag;
         $tags->tagger = $this->tagger;
         $count = $tags->count('distinct tagged');
         self::cacheSet($keypart, $count);
     }
     return $count;
 }
Пример #13
0
 /**
  * Data elements
  *
  * @return void
  */
 function formData()
 {
     if (Event::handle('StartShowTagProfileFormData', array($this))) {
         $this->hidden('token', common_session_token());
         $this->hidden('id', $this->target->id);
         $this->elementStart('ul', 'form_data');
         $this->elementStart('li');
         $tags = Profile_tag::getTagsArray($this->out->getScoped()->id, $this->target->id, $this->out->getScoped()->id);
         // TRANS: Field label on list form.
         $this->input('tags', _m('LABEL', 'Lists'), $this->arg('tags') ? $this->arg('tags') : implode(' ', $tags), _('Lists for this user (letters, numbers, -, ., and _), comma- or space- separated.'));
         $this->elementEnd('li');
         $this->elementEnd('ul');
         Event::handle('EndShowTagProfileFormData', array($this));
     }
 }
 function showContent()
 {
     // XXX: cache this
     $tags = new Profile_tag();
     $plist = new Profile_list();
     $plist->private = false;
     $tags->joinAdd($plist);
     $tags->selectAdd();
     $tags->selectAdd('profile_tag.tag');
     $tags->selectAdd('count(profile_tag.tag) as weight');
     $tags->groupBy('profile_tag.tag');
     $tags->orderBy('weight DESC');
     $tags->limit(TAGS_PER_PAGE);
     $cnt = $tags->find();
     if ($cnt > 0) {
         $this->elementStart('div', array('id' => 'tagcloud', 'class' => 'section'));
         $tw = array();
         $sum = 0;
         while ($tags->fetch()) {
             $tw[$tags->tag] = $tags->weight;
             $sum += $tags->weight;
         }
         ksort($tw);
         $this->elementStart('dl');
         // TRANS: DT element on on page with public list cloud.
         $this->element('dt', null, _('List cloud'));
         $this->elementStart('dd');
         $this->elementStart('ul', 'tags xoxo tag-cloud');
         foreach ($tw as $tag => $weight) {
             if ($sum) {
                 $weightedSum = $weight / $sum;
             } else {
                 $weightedSum = 0.5;
             }
             $this->showTag($tag, $weight, $weightedSum);
         }
         $this->elementEnd('ul');
         $this->elementEnd('dd');
         $this->elementEnd('dl');
         $this->elementEnd('div');
     } else {
         $this->showEmptyList();
     }
 }
Пример #15
0
 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, $tags->escape($new->tag), $tags->escape($new->tagger), $tags->escape($orig->tag), $tags->escape($orig->tagger)));
     if ($result === false) {
         common_log_db_error($tags, 'UPDATE', __FILE__);
         throw new Exception('Could not move Profile_tag, see db log for details.');
     }
     return $result;
 }
Пример #16
0
 /**
  * Get a the self-tags associated with this profile
  *
  * @return string the concatenated string of tags
  */
 function getTags()
 {
     return implode(' ', Profile_tag::getSelfTagsArray($this->profile));
 }
Пример #17
0
 /**
  * Handle request
  *
  * Does the tagging and returns results.
  *
  * @param Array $args unused.
  *
  * @return void
  */
 function handle($args)
 {
     // Throws exception on error
     $ptag = Profile_tag::setTag($this->user->id, $this->tagged->id, $this->peopletag->tag);
     if (!$ptag) {
         $user = User::staticGet('id', $id);
         if ($user) {
             $this->clientError(sprintf(_('There was an unexpected error while listing %s.'), $user->nickname));
         } else {
             // TRANS: Client error displayed when an unknown error occurs when adding a user to a list.
             // TRANS: %s is a profile URL.
             $this->clientError(sprintf(_('There was a problem listing %s. ' . 'The remote server is probably not responding correctly. ' . 'Please try retrying later.'), $this->profile->profileurl));
         }
         return false;
     }
     if ($this->boolean('ajax')) {
         $this->startHTML('text/xml;charset=utf-8');
         $this->elementStart('head');
         // TRANS: Title after adding a user to a list.
         $this->element('title', null, _m('TITLE', 'Listed'));
         $this->elementEnd('head');
         $this->elementStart('body');
         $unsubscribe = new UntagButton($this, $this->tagged, $this->peopletag);
         $unsubscribe->show();
         $this->elementEnd('body');
         $this->elementEnd('html');
     } else {
         $url = common_local_url('subscriptions', array('nickname' => $this->user->nickname));
         common_redirect($url, 303);
     }
 }
 /**
  * Save fields that should be stored in the main profile object
  *
  * XXX: There's a lot of dupe code here from ProfileSettingsAction.
  *      Do not want.
  */
 function saveStandardProfileDetails()
 {
     $fullname = $this->trimmed('extprofile-fullname');
     $location = $this->trimmed('extprofile-location');
     $tagstring = $this->trimmed('extprofile-tags');
     $bio = $this->trimmed('extprofile-bio');
     if ($tagstring) {
         $tags = array_map('common_canonical_tag', preg_split('/[\\s,]+/', $tagstring));
     } else {
         $tags = array();
     }
     foreach ($tags as $tag) {
         if (!common_valid_profile_tag($tag)) {
             // TRANS: Validation error in form for profile settings.
             // TRANS: %s is an invalid tag.
             throw new Exception(sprintf(_m('Invalid tag: "%s".'), $tag));
         }
     }
     $oldTags = Profile_tag::getSelfTagsArray($this->scoped);
     $newTags = array_diff($tags, $oldTags);
     if ($fullname != $this->scoped->getFullname() || $location != $this->scoped->location || !empty($newTags) || $bio != $this->scoped->getDescription()) {
         $orig = clone $this->scoped;
         // Skipping nickname change here until we add logic for when the site allows it or not
         // old Profilesettings will still let us do that.
         $this->scoped->fullname = $fullname;
         $this->scoped->bio = $bio;
         $this->scoped->location = $location;
         $loc = Location::fromName($location);
         if (empty($loc)) {
             $this->scoped->lat = null;
             $this->scoped->lon = null;
             $this->scoped->location_id = null;
             $this->scoped->location_ns = null;
         } else {
             $this->scoped->lat = $loc->lat;
             $this->scoped->lon = $loc->lon;
             $this->scoped->location_id = $loc->location_id;
             $this->scoped->location_ns = $loc->location_ns;
         }
         $result = $this->scoped->update($orig);
         if ($result === false) {
             common_log_db_error($this->scoped, 'UPDATE', __FILE__);
             // TRANS: Server error thrown when user profile settings could not be saved.
             throw new ServerException(_m('Could not save profile.'));
         }
         // Set the user tags
         $result = Profile_tag::setSelfTags($this->scoped, $tags);
         Event::handle('EndProfileSaveForm', array($this));
     }
 }
Пример #19
0
 protected function doPost()
 {
     $tagstring = $this->trimmed('tags');
     $token = $this->trimmed('token');
     if (Event::handle('StartSavePeopletags', array($this, $tagstring))) {
         $tags = array();
         $tag_priv = array();
         if (is_string($tagstring) && strlen($tagstring) > 0) {
             $tags = preg_split('/[\\s,]+/', $tagstring);
             foreach ($tags as &$tag) {
                 $private = @$tag[0] === '.';
                 $tag = common_canonical_tag($tag);
                 if (!common_valid_profile_tag($tag)) {
                     // TRANS: Form validation error displayed if a given tag is invalid.
                     // TRANS: %s is the invalid tag.
                     throw new ClientException(sprintf(_('Invalid tag: "%s".'), $tag));
                 }
                 $tag_priv[$tag] = $private;
             }
         }
         $result = Profile_tag::setTags($this->scoped->getID(), $this->target->getID(), $tags, $tag_priv);
         if (!$result) {
             throw new ServerException('The tags could not be saved.');
         }
         if ($this->boolean('ajax')) {
             $this->startHTML('text/xml;charset=utf-8');
             $this->elementStart('head');
             $this->element('title', null, _m('TITLE', 'Tags'));
             $this->elementEnd('head');
             $this->elementStart('body');
             if ($this->scoped->id == $this->target->id) {
                 $widget = new SelftagsWidget($this, $this->scoped, $this->target);
                 $widget->show();
             } else {
                 $widget = new PeopletagsWidget($this, $this->scoped, $this->target);
                 $widget->show();
             }
             $this->elementEnd('body');
             $this->endHTML();
         } else {
             // TRANS: Success message if lists are saved.
             $this->msg = _('Lists saved.');
             $this->showForm();
         }
         Event::handle('EndSavePeopletags', array($this, $tagstring));
     }
 }
Пример #20
0
 function saveTags()
 {
     $id = $this->trimmed('id');
     $tagstring = $this->trimmed('tags');
     $token = $this->trimmed('token');
     if (!$token || $token != common_session_token()) {
         $this->showForm(_('There was a problem with your session token.' . ' Try again, please.'));
         return;
     }
     if (is_string($tagstring) && strlen($tagstring) > 0) {
         $tags = array_map('common_canonical_tag', preg_split('/[\\s,]+/', $tagstring));
         foreach ($tags as $tag) {
             if (!common_valid_profile_tag($tag)) {
                 $this->showForm(sprintf(_('Invalid tag: "%s"'), $tag));
                 return;
             }
         }
     } else {
         $tags = array();
     }
     $user = common_current_user();
     if (!Subscription::pkeyGet(array('subscriber' => $user->id, 'subscribed' => $this->profile->id)) && !Subscription::pkeyGet(array('subscriber' => $this->profile->id, 'subscribed' => $user->id))) {
         $this->clientError(_('You can only tag people you are subscribed to or who are subscribed to you.'));
         return;
     }
     $result = Profile_tag::setTags($user->id, $this->profile->id, $tags);
     if (!$result) {
         $this->clientError(_('Could not save tags.'));
         return;
     }
     $action = $user->isSubscribed($this->profile) ? 'subscriptions' : 'subscribers';
     if ($this->boolean('ajax')) {
         $this->startHTML('text/xml;charset=utf-8');
         $this->elementStart('head');
         $this->element('title', null, _('Tags'));
         $this->elementEnd('head');
         $this->elementStart('body');
         $this->elementStart('p', 'subtags');
         foreach ($tags as $tag) {
             $this->element('a', array('href' => common_local_url($action, array('nickname' => $user->nickname, 'tag' => $tag))), $tag);
         }
         $this->elementEnd('p');
         $this->elementEnd('body');
         $this->elementEnd('html');
     } else {
         common_redirect(common_local_url($action, array('nickname' => $user->nickname)));
     }
 }
Пример #21
0
 function _deleteTags()
 {
     $tag = new Profile_tag();
     $tag->tagger = $this->id;
     $tag->delete();
 }
Пример #22
0
 function handleUntag()
 {
     if ($this->activity->target->type == ActivityObject::_LIST) {
         if ($this->activity->objects[0]->type != ActivityObject::PERSON) {
             // TRANS: Client exception.
             throw new ClientException(_m('Not a person object.'));
             return false;
         }
         // this is a peopletag
         $tagged = User::staticGet('uri', $this->activity->objects[0]->id);
         if (empty($tagged)) {
             // TRANS: Client exception.
             throw new ClientException(_m('Unidentified profile being untagged.'));
         }
         if ($tagged->id !== $this->user->id) {
             // TRANS: Client exception.
             throw new ClientException(_m('This user is not the one being untagged.'));
         }
         // save the list
         $tagger = $this->ensureProfile();
         $list = Ostatus_profile::ensureActivityObjectProfile($this->activity->target);
         $ptag = $list->localPeopletag();
         $result = Profile_tag::unTag($ptag->tagger, $tagged->id, $ptag->tag);
         if (!$result) {
             // TRANS: Client exception.
             throw new ClientException(_m('The tag could not be deleted.'));
         }
     }
 }
Пример #23
0
 function showProfileTags()
 {
     if (Event::handle('StartProfilePageProfileTags', array($this->out, $this->profile))) {
         $tags = Profile_tag::getTags($this->profile->id, $this->profile->id);
         if (count($tags) > 0) {
             $this->out->elementStart('dl', 'entity_tags');
             $this->out->element('dt', null, _('Tags'));
             $this->out->elementStart('dd');
             $this->out->elementStart('ul', 'tags xoxo');
             foreach ($tags as $tag) {
                 $this->out->elementStart('li');
                 // Avoid space by using raw output.
                 $pt = '<span class="mark_hash">#</span><a rel="tag" href="' . common_local_url('peopletag', array('tag' => $tag)) . '">' . $tag . '</a>';
                 $this->out->raw($pt);
                 $this->out->elementEnd('li');
             }
             $this->out->elementEnd('ul');
             $this->out->elementEnd('dd');
             $this->out->elementEnd('dl');
         }
         Event::handle('EndProfilePageProfileTags', array($this->out, $this->profile));
     }
 }
Пример #24
0
 /**
  * Handle a post
  *
  * Validate input and save changes. Reload the form with a success
  * or error message.
  *
  * @return void
  */
 protected function doPost()
 {
     if (Event::handle('StartProfileSaveForm', array($this))) {
         // $nickname will only be set if this changenick value is true.
         if (common_config('profile', 'changenick') == true) {
             try {
                 $nickname = Nickname::normalize($this->trimmed('nickname'), true);
             } catch (NicknameTakenException $e) {
                 // Abort only if the nickname is occupied by _another_ local user profile
                 if (!$this->scoped->sameAs($e->profile)) {
                     throw $e;
                 }
                 // Since the variable wasn't set before the exception was thrown, let's run
                 // the normalize sequence again, but without in-use check this time.
                 $nickname = Nickname::normalize($this->trimmed('nickname'));
             }
         }
         $fullname = $this->trimmed('fullname');
         $homepage = $this->trimmed('homepage');
         $bio = $this->trimmed('bio');
         $location = $this->trimmed('location');
         $autosubscribe = $this->booleanintstring('autosubscribe');
         $subscribe_policy = $this->trimmed('subscribe_policy');
         $private_stream = $this->booleanintstring('private_stream');
         $language = $this->trimmed('language');
         $timezone = $this->trimmed('timezone');
         $tagstring = $this->trimmed('tags');
         // Some validation
         if (!is_null($homepage) && strlen($homepage) > 0 && !common_valid_http_url($homepage)) {
             // TRANS: Validation error in form for profile settings.
             throw new ClientException(_('Homepage is not a valid URL.'));
         } else {
             if (!is_null($fullname) && mb_strlen($fullname) > 191) {
                 // TRANS: Validation error in form for profile settings.
                 throw new ClientException(_('Full name is too long (maximum 191 characters).'));
             } else {
                 if (Profile::bioTooLong($bio)) {
                     // TRANS: Validation error in form for profile settings.
                     // TRANS: Plural form is used based on the maximum number of allowed
                     // TRANS: characters for the biography (%d).
                     throw new ClientException(sprintf(_m('Bio is too long (maximum %d character).', 'Bio is too long (maximum %d characters).', Profile::maxBio()), Profile::maxBio()));
                 } else {
                     if (!is_null($location) && mb_strlen($location) > 191) {
                         // TRANS: Validation error in form for profile settings.
                         throw new ClientException(_('Location is too long (maximum 191 characters).'));
                     } else {
                         if (is_null($timezone) || !in_array($timezone, DateTimeZone::listIdentifiers())) {
                             // TRANS: Validation error in form for profile settings.
                             throw new ClientException(_('Timezone not selected.'));
                         } else {
                             if (!is_null($language) && strlen($language) > 50) {
                                 // TRANS: Validation error in form for profile settings.
                                 throw new ClientException(_('Language is too long (maximum 50 characters).'));
                             }
                         }
                     }
                 }
             }
         }
         $tags = array();
         $tag_priv = array();
         if (is_string($tagstring) && strlen($tagstring) > 0) {
             $tags = preg_split('/[\\s,]+/', $tagstring);
             foreach ($tags as &$tag) {
                 $private = @$tag[0] === '.';
                 $tag = common_canonical_tag($tag);
                 if (!common_valid_profile_tag($tag)) {
                     // TRANS: Validation error in form for profile settings.
                     // TRANS: %s is an invalid tag.
                     throw new ClientException(sprintf(_('Invalid tag: "%s".'), $tag));
                 }
                 $tag_priv[$tag] = $private;
             }
         }
         $user = $this->scoped->getUser();
         $user->query('BEGIN');
         // $user->nickname is updated through Profile->update();
         // XXX: XOR
         if ($user->autosubscribe ^ $autosubscribe || $user->private_stream ^ $private_stream || $user->timezone != $timezone || $user->language != $language || $user->subscribe_policy != $subscribe_policy) {
             $original = clone $user;
             $user->autosubscribe = $autosubscribe;
             $user->language = $language;
             $user->private_stream = $private_stream;
             $user->subscribe_policy = $subscribe_policy;
             $user->timezone = $timezone;
             $result = $user->update($original);
             if ($result === false) {
                 common_log_db_error($user, 'UPDATE', __FILE__);
                 $user->query('ROLLBACK');
                 // TRANS: Server error thrown when user profile settings could not be updated to
                 // TRANS: automatically subscribe to any subscriber.
                 throw new ServerException(_('Could not update user for autosubscribe or subscribe_policy.'));
             }
             // Re-initialize language environment if it changed
             common_init_language();
         }
         $original = clone $this->scoped;
         if (common_config('profile', 'changenick') == true && $this->scoped->getNickname() !== $nickname) {
             assert(Nickname::normalize($nickname) === $nickname);
             common_debug("Changing user nickname from '{$this->scoped->getNickname()}' to '{$nickname}'.");
             $this->scoped->nickname = $nickname;
             $this->scoped->profileurl = common_profile_url($this->scoped->getNickname());
         }
         $this->scoped->fullname = $fullname;
         $this->scoped->homepage = $homepage;
         $this->scoped->bio = $bio;
         $this->scoped->location = $location;
         $loc = Location::fromName($location);
         if (empty($loc)) {
             $this->scoped->lat = null;
             $this->scoped->lon = null;
             $this->scoped->location_id = null;
             $this->scoped->location_ns = null;
         } else {
             $this->scoped->lat = $loc->lat;
             $this->scoped->lon = $loc->lon;
             $this->scoped->location_id = $loc->location_id;
             $this->scoped->location_ns = $loc->location_ns;
         }
         if (common_config('location', 'share') == 'user') {
             $exists = false;
             $prefs = User_location_prefs::getKV('user_id', $this->scoped->getID());
             if (empty($prefs)) {
                 $prefs = new User_location_prefs();
                 $prefs->user_id = $this->scoped->getID();
                 $prefs->created = common_sql_now();
             } else {
                 $exists = true;
                 $orig = clone $prefs;
             }
             $prefs->share_location = $this->booleanintstring('sharelocation');
             if ($exists) {
                 $result = $prefs->update($orig);
             } else {
                 $result = $prefs->insert();
             }
             if ($result === false) {
                 common_log_db_error($prefs, $exists ? 'UPDATE' : 'INSERT', __FILE__);
                 $user->query('ROLLBACK');
                 // TRANS: Server error thrown when user profile location preference settings could not be updated.
                 throw new ServerException(_('Could not save location prefs.'));
             }
         }
         common_debug('Old profile: ' . common_log_objstring($original), __FILE__);
         common_debug('New profile: ' . common_log_objstring($this->scoped), __FILE__);
         $result = $this->scoped->update($original);
         if ($result === false) {
             common_log_db_error($this->scoped, 'UPDATE', __FILE__);
             $user->query('ROLLBACK');
             // TRANS: Server error thrown when user profile settings could not be saved.
             throw new ServerException(_('Could not save profile.'));
         }
         // Set the user tags
         $result = Profile_tag::setSelfTags($this->scoped, $tags, $tag_priv);
         $user->query('COMMIT');
         Event::handle('EndProfileSaveForm', array($this));
         // TRANS: Confirmation shown when user profile settings are saved.
         return _('Settings saved.');
     }
 }
Пример #25
0
 /**
  * Notify remote user that a people tag has been removed
  *   - untag verb is queued
  *   - the subscription is undone immediately if not required
  *     i.e garbageCollect()'d
  *
  * @param Profile_tag $ptag the people tag that was deleted
  * @return hook return value
  */
 function onEndUntagProfile($ptag)
 {
     $oprofile = Ostatus_profile::staticGet('profile_id', $ptag->tagged);
     if (empty($oprofile)) {
         return true;
     }
     $plist = $ptag->getMeta();
     if ($plist->private) {
         return true;
     }
     $act = new Activity();
     $tagger = $plist->getTagger();
     $tagged = Profile::staticGet('id', $ptag->tagged);
     $act->verb = ActivityVerb::UNTAG;
     $act->id = TagURI::mint('untag_profile:%d:%d:%s', $plist->tagger, $plist->id, common_date_iso8601(time()));
     $act->time = time();
     // TRANS: Title for unlisting a remote profile.
     $act->title = _m('TITLE', 'Unlist');
     // TRANS: Success message for remote list removal through OStatus.
     // TRANS: %1$s is the list creator's name, %2$s is the removed list member, %3$s is the list name.
     $act->content = sprintf(_m('%1$s removed %2$s from the list %3$s.'), $tagger->getBestName(), $tagged->getBestName(), $plist->getBestName());
     $act->actor = ActivityObject::fromProfile($tagger);
     $act->objects = array(ActivityObject::fromProfile($tagged));
     $act->target = ActivityObject::fromPeopletag($plist);
     $oprofile->notifyDeferred($act, $tagger);
     // unsubscribe to PuSH feed if no more required
     $oprofile->garbageCollect();
     return true;
 }
Пример #26
0
function common_at_hash_link($sender_id, $tag)
{
    $user = User::staticGet($sender_id);
    if (!$user) {
        return $tag;
    }
    $tagged = Profile_tag::getTagged($user->id, common_canonical_tag($tag));
    if ($tagged) {
        $url = common_local_url('subscriptions', array('nickname' => $user->nickname, 'tag' => $tag));
        $xs = new XMLStringer();
        $xs->elementStart('span', 'tag');
        $xs->element('a', array('href' => $url, 'rel' => $tag), $tag);
        $xs->elementEnd('span');
        return $xs->getString();
    } else {
        return $tag;
    }
}
Пример #27
0
 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;
 }
Пример #28
0
function initProfileLists()
{
    printfnq("Ensuring all profile tags have a corresponding list...");
    $ptag = new Profile_tag();
    $ptag->selectAdd();
    $ptag->selectAdd('tagger, tag, count(*) as tagged_count');
    $ptag->whereAdd('NOT EXISTS (SELECT tagger, tagged from profile_list ' . 'where profile_tag.tagger = profile_list.tagger ' . 'and profile_tag.tag = profile_list.tag)');
    $ptag->groupBy('tagger, tag');
    $ptag->orderBy('tagger, tag');
    if ($ptag->find()) {
        while ($ptag->fetch()) {
            $plist = new Profile_list();
            $plist->tagger = $ptag->tagger;
            $plist->tag = $ptag->tag;
            $plist->private = 0;
            $plist->created = common_sql_now();
            $plist->modified = $plist->created;
            $plist->mainpage = common_local_url('showprofiletag', array('tagger' => $plist->getTagger()->nickname, 'tag' => $plist->tag));
            $plist->tagged_count = $ptag->tagged_count;
            $plist->subscriber_count = 0;
            $plist->insert();
            $orig = clone $plist;
            // After insert since it uses auto-generated ID
            $plist->uri = common_local_url('profiletagbyid', array('id' => $plist->id, 'tagger_id' => $plist->tagger));
            $plist->update($orig);
        }
    }
    printfnq("DONE.\n");
}
Пример #29
0
 function showProfile()
 {
     $this->elementStart('div', 'entity_profile vcard author');
     $this->element('h2', null, _('User profile'));
     $avatar = $this->profile->getAvatar(AVATAR_PROFILE_SIZE);
     $this->elementStart('dl', 'entity_depiction');
     $this->element('dt', null, _('Photo'));
     $this->elementStart('dd');
     $this->element('img', array('src' => $avatar ? $avatar->displayUrl() : Avatar::defaultImage(AVATAR_PROFILE_SIZE), 'class' => 'photo avatar', 'width' => AVATAR_PROFILE_SIZE, 'height' => AVATAR_PROFILE_SIZE, 'alt' => $this->profile->nickname));
     $this->elementEnd('dd');
     $user = User::staticGet('id', $this->profile->id);
     $cur = common_current_user();
     if ($cur && $cur->id == $user->id) {
         $this->elementStart('dd');
         $this->element('a', array('href' => common_local_url('avatarsettings')), _('Edit Avatar'));
         $this->elementEnd('dd');
     }
     $this->elementEnd('dl');
     $this->elementStart('dl', 'entity_nickname');
     $this->element('dt', null, _('Nickname'));
     $this->elementStart('dd');
     $hasFN = $this->profile->fullname ? 'nickname url uid' : 'fn nickname url uid';
     $this->element('a', array('href' => $this->profile->profileurl, 'rel' => 'me', 'class' => $hasFN), $this->profile->nickname);
     $this->elementEnd('dd');
     $this->elementEnd('dl');
     if ($this->profile->fullname) {
         $this->elementStart('dl', 'entity_fn');
         $this->element('dt', null, _('Full name'));
         $this->elementStart('dd');
         $this->element('span', 'fn', $this->profile->fullname);
         $this->elementEnd('dd');
         $this->elementEnd('dl');
     }
     if ($this->profile->location) {
         $this->elementStart('dl', 'entity_location');
         $this->element('dt', null, _('Location'));
         $this->element('dd', 'label', $this->profile->location);
         $this->elementEnd('dl');
     }
     if ($this->profile->homepage) {
         $this->elementStart('dl', 'entity_url');
         $this->element('dt', null, _('URL'));
         $this->elementStart('dd');
         $this->element('a', array('href' => $this->profile->homepage, 'rel' => 'me', 'class' => 'url'), $this->profile->homepage);
         $this->elementEnd('dd');
         $this->elementEnd('dl');
     }
     if ($this->profile->bio) {
         $this->elementStart('dl', 'entity_note');
         $this->element('dt', null, _('Note'));
         $this->element('dd', 'note', $this->profile->bio);
         $this->elementEnd('dl');
     }
     $tags = Profile_tag::getTags($this->profile->id, $this->profile->id);
     if (count($tags) > 0) {
         $this->elementStart('dl', 'entity_tags');
         $this->element('dt', null, _('Tags'));
         $this->elementStart('dd');
         $this->elementStart('ul', 'tags xoxo');
         foreach ($tags as $tag) {
             $this->elementStart('li');
             // Avoid space by using raw output.
             $pt = '<span class="mark_hash">#</span><a rel="tag" href="' . common_local_url('peopletag', array('tag' => $tag)) . '">' . $tag . '</a>';
             $this->raw($pt);
             $this->elementEnd('li');
         }
         $this->elementEnd('ul');
         $this->elementEnd('dd');
         $this->elementEnd('dl');
     }
     $this->elementEnd('div');
     $this->elementStart('div', 'entity_actions');
     $this->element('h2', null, _('User actions'));
     $this->elementStart('ul');
     $cur = common_current_user();
     if ($cur && $cur->id == $this->profile->id) {
         $this->elementStart('li', 'entity_edit');
         $this->element('a', array('href' => common_local_url('profilesettings'), 'title' => _('Edit profile settings')), _('Edit'));
         $this->elementEnd('li');
     }
     if ($cur) {
         if ($cur->id != $this->profile->id) {
             $this->elementStart('li', 'entity_subscribe');
             if ($cur->isSubscribed($this->profile)) {
                 $usf = new UnsubscribeForm($this, $this->profile);
                 $usf->show();
             } else {
                 $sf = new SubscribeForm($this, $this->profile);
                 $sf->show();
             }
             $this->elementEnd('li');
         }
     } else {
         $this->elementStart('li', 'entity_subscribe');
         $this->showRemoteSubscribeLink();
         $this->elementEnd('li');
     }
     if ($cur && $cur->id != $user->id && $cur->mutuallySubscribed($user)) {
         $this->elementStart('li', 'entity_send-a-message');
         $this->element('a', array('href' => common_local_url('newmessage', array('to' => $user->id)), 'title' => _('Send a direct message to this user')), _('Message'));
         $this->elementEnd('li');
         if ($user->email && $user->emailnotifynudge) {
             $this->elementStart('li', 'entity_nudge');
             $nf = new NudgeForm($this, $user);
             $nf->show();
             $this->elementEnd('li');
         }
     }
     if ($cur && $cur->id != $this->profile->id) {
         $blocked = $cur->hasBlocked($this->profile);
         $this->elementStart('li', 'entity_block');
         if ($blocked) {
             $ubf = new UnblockForm($this, $this->profile);
             $ubf->show();
         } else {
             $bf = new BlockForm($this, $this->profile);
             $bf->show();
         }
         $this->elementEnd('li');
     }
     $this->elementEnd('ul');
     $this->elementEnd('div');
 }
Пример #30
0
 function saveReplies()
 {
     // Alternative reply format
     $tname = false;
     if (preg_match('/^T ([A-Z0-9]{1,64}) /', $this->content, $match)) {
         $tname = $match[1];
     }
     // extract all @messages
     $cnt = preg_match_all('/(?:^|\\s)@([a-z0-9]{1,64})/', $this->content, $match);
     $names = array();
     if ($cnt || $tname) {
         // XXX: is there another way to make an array copy?
         $names = $tname ? array_unique(array_merge(array(strtolower($tname)), $match[1])) : array_unique($match[1]);
     }
     $sender = Profile::staticGet($this->profile_id);
     $replied = array();
     // store replied only for first @ (what user/notice what the reply directed,
     // we assume first @ is it)
     for ($i = 0; $i < count($names); $i++) {
         $nickname = $names[$i];
         $recipient = common_relative_profile($sender, $nickname, $this->created);
         if (!$recipient) {
             continue;
         }
         if ($i == 0 && $recipient->id != $sender->id && !$this->reply_to) {
             // Don't save reply to self
             $reply_for = $recipient;
             $recipient_notice = $reply_for->getCurrentNotice();
             if ($recipient_notice) {
                 $orig = clone $this;
                 $this->reply_to = $recipient_notice->id;
                 $this->update($orig);
             }
         }
         // Don't save replies from blocked profile to local user
         $recipient_user = User::staticGet('id', $recipient->id);
         if ($recipient_user && $recipient_user->hasBlocked($sender)) {
             continue;
         }
         $reply = new Reply();
         $reply->notice_id = $this->id;
         $reply->profile_id = $recipient->id;
         $id = $reply->insert();
         if (!$id) {
             $last_error =& PEAR::getStaticProperty('DB_DataObject', 'lastError');
             common_log(LOG_ERR, 'DB error inserting reply: ' . $last_error->message);
             common_server_error(sprintf(_('DB error inserting reply: %s'), $last_error->message));
             return;
         } else {
             $replied[$recipient->id] = 1;
         }
     }
     // Hash format replies, too
     $cnt = preg_match_all('/(?:^|\\s)@#([a-z0-9]{1,64})/', $this->content, $match);
     if ($cnt) {
         foreach ($match[1] as $tag) {
             $tagged = Profile_tag::getTagged($sender->id, $tag);
             foreach ($tagged as $t) {
                 if (!$replied[$t->id]) {
                     // Don't save replies from blocked profile to local user
                     $t_user = User::staticGet('id', $t->id);
                     if ($t_user && $t_user->hasBlocked($sender)) {
                         continue;
                     }
                     $reply = new Reply();
                     $reply->notice_id = $this->id;
                     $reply->profile_id = $t->id;
                     $id = $reply->insert();
                     if (!$id) {
                         common_log_db_error($reply, 'INSERT', __FILE__);
                         return;
                     } else {
                         $replied[$recipient->id] = 1;
                     }
                 }
             }
         }
     }
     foreach (array_keys($replied) as $recipient) {
         $user = User::staticGet('id', $recipient);
         if ($user) {
             mail_notify_attn($user, $this);
         }
     }
 }