public function onEndUserRegister(Profile $profile) { foreach ($this->join as $nickname) { $group = User_group::getForNickname($nickname); if ($group && !$profile->isMember($group)) { try { $profile->joinGroup($group); } catch (Exception $e) { // TRANS: Server exception. // TRANS: %1$s is a user nickname, %2$s is a group nickname. throw new ServerException(sprintf(_m('Could not join user %1$s to group %2$s.'), $profile->nickname, $group->nickname)); } } } }
function onEndUserRegister($profile, $user) { $profile = $user->getProfile(); foreach ($this->join as $nickname) { $group = User_group::getForNickname($nickname); if ($group && !$profile->isMember($group)) { try { if (Event::handle('StartJoinGroup', array($group, $user))) { Group_member::join($group->id, $user->id); Event::handle('EndJoinGroup', array($group, $user)); } } catch (Exception $e) { // TRANS: Server exception. // TRANS: %1$s is a user nickname, %2$s is a group nickname. throw new ServerException(sprintf(_m('Could not join user %1$s to group %2$s.'), $user->nickname, $group->nickname)); } } } }
function getTargetGroup($id) { if (empty($id)) { if (self::is_decimal($this->arg('id'))) { return User_group::staticGet('id', $this->arg('id')); } else { if ($this->arg('id')) { return User_group::getForNickname($this->arg('id')); } else { if ($this->arg('group_id')) { // This is to ensure that a non-numeric group_id still // overrides group_name even if it doesn't get used if (self::is_decimal($this->arg('group_id'))) { return User_group::staticGet('id', $this->arg('group_id')); } } else { if ($this->arg('group_name')) { return User_group::getForNickname($this->arg('group_name')); } } } } } else { if (self::is_decimal($id)) { return User_group::staticGet('id', $id); } else { return User_group::getForNickname($id); } } }
function common_group_link($sender_id, $nickname) { $sender = Profile::staticGet($sender_id); $group = User_group::getForNickname($nickname, $sender); if ($sender && $group && $sender->isMember($group)) { $attrs = array('href' => $group->permalink(), 'class' => 'url'); if (!empty($group->fullname)) { $attrs['title'] = $group->fullname . ' (' . $group->nickname . ')'; } $xs = new XMLStringer(); $xs->elementStart('span', 'vcard'); $xs->elementStart('a', $attrs); $xs->element('span', 'fn nickname', $nickname); $xs->elementEnd('a'); $xs->elementEnd('span'); return $xs->getString(); } else { return $nickname; } }
/** * Get a local or remote group by name. * @return User_group * @throws CommandException */ function getGroup($arg) { $group = null; if (Event::handle('StartCommandGetGroup', array($this, $arg, &$group))) { $group = User_group::getForNickname($arg, $this->user->getProfile()); } Event::handle('EndCommandGetGroup', array($this, $arg, &$group)); if (!$group) { throw new CommandException(_('No such group.')); } return $group; }
/** * Find @-mentions in the given text, using the given notice object as context. * References will be resolved with common_relative_profile() against the user * who posted the notice. * * Note the return data format is internal, to be used for building links and * such. Should not be used directly; rather, call common_linkify_mentions(). * * @param string $text * @param Profile $sender the Profile that is sending the current text * @param Notice $parent the Notice this text is in reply to, if any * * @return array * * @access private */ function common_find_mentions($text, Profile $sender, Notice $parent = null) { $mentions = array(); if (Event::handle('StartFindMentions', array($sender, $text, &$mentions))) { // Get the context of the original notice, if any $origMentions = array(); // Does it have a parent notice for context? if ($parent instanceof Notice) { $ids = $parent->getReplies(); // replied-to _profile ids_ foreach ($ids as $id) { try { $repliedTo = Profile::getByID($id); $origMentions[$repliedTo->getNickname()] = $repliedTo; } catch (NoResultException $e) { // continue foreach } } } $matches = common_find_mentions_raw($text); foreach ($matches as $match) { try { $nickname = Nickname::normalize($match[0]); } catch (NicknameException $e) { // Bogus match? Drop it. continue; } // Try to get a profile for this nickname. // Start with conversation context, then go to // sender context. if ($parent instanceof Notice && $parent->getProfile()->getNickname() === $nickname) { $mentioned = $parent->getProfile(); } else { if (!empty($origMentions) && array_key_exists($nickname, $origMentions)) { $mentioned = $origMentions[$nickname]; } else { // sets to null if no match $mentioned = common_relative_profile($sender, $nickname); } } if ($mentioned instanceof Profile) { $user = User::getKV('id', $mentioned->id); try { $url = $mentioned->getUrl(); } catch (InvalidUrlException $e) { $url = common_local_url('userbyid', array('id' => $mentioned->getID())); } $mention = array('mentioned' => array($mentioned), 'type' => 'mention', 'text' => $match[0], 'position' => $match[1], 'length' => mb_strlen($match[0]), 'title' => $mentioned->getFullname(), 'url' => $url); $mentions[] = $mention; } } // @#tag => mention of all subscriptions tagged 'tag' preg_match_all('/(?:^|[\\s\\.\\,\\:\\;]+)@#([\\pL\\pN_\\-\\.]{1,64})/', $text, $hmatches, PREG_OFFSET_CAPTURE); foreach ($hmatches[1] as $hmatch) { $tag = common_canonical_tag($hmatch[0]); $plist = Profile_list::getByTaggerAndTag($sender->getID(), $tag); if (!$plist instanceof Profile_list || $plist->private) { continue; } $tagged = $sender->getTaggedSubscribers($tag); $url = common_local_url('showprofiletag', array('nickname' => $sender->getNickname(), 'tag' => $tag)); $mentions[] = array('mentioned' => $tagged, 'type' => 'list', 'text' => $hmatch[0], 'position' => $hmatch[1], 'length' => mb_strlen($hmatch[0]), 'url' => $url); } preg_match_all('/(?:^|[\\s\\.\\,\\:\\;]+)!(' . Nickname::DISPLAY_FMT . ')/', $text, $hmatches, PREG_OFFSET_CAPTURE); foreach ($hmatches[1] as $hmatch) { $nickname = Nickname::normalize($hmatch[0]); $group = User_group::getForNickname($nickname, $sender); if (!$group instanceof User_group || !$sender->isMember($group)) { continue; } $profile = $group->getProfile(); $mentions[] = array('mentioned' => array($profile), 'type' => 'group', 'text' => $hmatch[0], 'position' => $hmatch[1], 'length' => mb_strlen($hmatch[0]), 'url' => $group->permalink(), 'title' => $group->getFancyName()); } Event::handle('EndFindMentions', array($sender, $text, &$mentions)); } return $mentions; }
/** * Get a local or remote group by name. * @return User_group * @throws CommandException */ function getGroup($arg) { $group = null; if (Event::handle('StartCommandGetGroup', array($this, $arg, &$group))) { $group = User_group::getForNickname($arg, $this->user->getProfile()); } Event::handle('EndCommandGetGroup', array($this, $arg, &$group)); if (!$group) { // TRANS: Command exception text shown when a group is requested that does not exist. throw new CommandException(_('No such group.')); } return $group; }
/** * Find @-mentions in the given text, using the given notice object as context. * References will be resolved with common_relative_profile() against the user * who posted the notice. * * Note the return data format is internal, to be used for building links and * such. Should not be used directly; rather, call common_linkify_mentions(). * * @param string $text * @param Notice $notice notice in whose context we're building links * * @return array * * @access private */ function common_find_mentions($text, Notice $notice) { // The getProfile call throws NoProfileException on failure $sender = $notice->getProfile(); $mentions = array(); if (Event::handle('StartFindMentions', array($sender, $text, &$mentions))) { // Get the context of the original notice, if any $origAuthor = null; $origNotice = null; $origMentions = array(); // Is it a reply? if ($notice instanceof Notice) { try { $origNotice = $notice->getParent(); $origAuthor = $origNotice->getProfile(); $ids = $origNotice->getReplies(); foreach ($ids as $id) { $repliedTo = Profile::getKV('id', $id); if ($repliedTo instanceof Profile) { $origMentions[$repliedTo->nickname] = $repliedTo; } } } catch (NoProfileException $e) { common_log(LOG_WARNING, sprintf('Notice %d author profile id %d does not exist', $origNotice->id, $origNotice->profile_id)); } catch (NoParentNoticeException $e) { // This notice is not in reply to anything } catch (Exception $e) { common_log(LOG_WARNING, __METHOD__ . ' got exception ' . get_class($e) . ' : ' . $e->getMessage()); } } $matches = common_find_mentions_raw($text); foreach ($matches as $match) { try { $nickname = Nickname::normalize($match[0]); } catch (NicknameException $e) { // Bogus match? Drop it. continue; } // Try to get a profile for this nickname. // Start with conversation context, then go to // sender context. if ($origAuthor instanceof Profile && $origAuthor->nickname == $nickname) { $mentioned = $origAuthor; } else { if (!empty($origMentions) && array_key_exists($nickname, $origMentions)) { $mentioned = $origMentions[$nickname]; } else { $mentioned = common_relative_profile($sender, $nickname); } } if ($mentioned instanceof Profile) { $user = User::getKV('id', $mentioned->id); if ($user instanceof User) { $url = common_local_url('userbyid', array('id' => $user->id)); } else { $url = $mentioned->profileurl; } $mention = array('mentioned' => array($mentioned), 'type' => 'mention', '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})/', $text, $hmatches, PREG_OFFSET_CAPTURE); foreach ($hmatches[1] as $hmatch) { $tag = common_canonical_tag($hmatch[0]); $plist = Profile_list::getByTaggerAndTag($sender->id, $tag); if (!$plist instanceof Profile_list || $plist->private) { continue; } $tagged = $sender->getTaggedSubscribers($tag); $url = common_local_url('showprofiletag', array('tagger' => $sender->nickname, 'tag' => $tag)); $mentions[] = array('mentioned' => $tagged, 'type' => 'list', 'text' => $hmatch[0], 'position' => $hmatch[1], 'url' => $url); } preg_match_all('/(?:^|[\\s\\.\\,\\:\\;]+)!(' . Nickname::DISPLAY_FMT . ')/', $text, $hmatches, PREG_OFFSET_CAPTURE); foreach ($hmatches[1] as $hmatch) { $nickname = Nickname::normalize($hmatch[0]); $group = User_group::getForNickname($nickname, $sender); if (!$group instanceof User_group || !$sender->isMember($group)) { continue; } $profile = $group->getProfile(); $mentions[] = array('mentioned' => array($profile), 'type' => 'group', 'text' => $hmatch[0], 'position' => $hmatch[1], 'url' => $group->permalink(), 'title' => $group->getFancyName()); } Event::handle('EndFindMentions', array($sender, $text, &$mentions)); } return $mentions; }
function getTargetGroup($id) { if (empty($id)) { if (self::is_decimal($this->arg('id'))) { return User_group::getKV('id', $this->arg('id')); } else { if ($this->arg('id')) { return User_group::getForNickname($this->arg('id')); } else { if ($this->arg('group_id')) { // This is to ensure that a non-numeric group_id still // overrides group_name even if it doesn't get used if (self::is_decimal($this->arg('group_id'))) { return User_group::getKV('id', $this->arg('group_id')); } } else { if ($this->arg('group_name')) { return User_group::getForNickname($this->arg('group_name')); } } } } } else { if (self::is_decimal($id)) { return User_group::getKV('id', $id); } else { if ($this->arg('uri')) { // FIXME: move this into empty($id) check? return User_group::getKV('uri', urldecode($this->arg('uri'))); } else { return User_group::getForNickname($id); } } } }
/** * Parse !group delivery and record targets into group_inbox. * @return array of Group objects */ function saveGroups() { // Don't save groups for repeats if (!empty($this->repeat_of)) { return array(); } $groups = array(); /* extract all !group */ $count = preg_match_all('/(?:^|\\s)!([A-Za-z0-9]{1,64})/', strtolower($this->content), $match); if (!$count) { return $groups; } $profile = $this->getProfile(); /* Add them to the database */ foreach (array_unique($match[1]) as $nickname) { /* XXX: remote groups. */ $group = User_group::getForNickname($nickname, $profile); if (empty($group)) { continue; } // we automatically add a tag for every group name, too $tag = Notice_tag::pkeyGet(array('tag' => common_canonical_tag($nickname), 'notice_id' => $this->id)); if (is_null($tag)) { $this->saveTag($nickname); } if ($profile->isMember($group)) { $result = $this->addToGroupInbox($group); if (!$result) { common_log_db_error($gi, 'INSERT', __FILE__); } $groups[] = clone $group; } } return $groups; }
static function groupsFromText($text, $profile) { $groups = array(); /* extract all !group */ $count = preg_match_all('/(?:^|\\s)!(' . Nickname::DISPLAY_FMT . ')/', strtolower($text), $match); if (!$count) { return $groups; } foreach (array_unique($match[1]) as $nickname) { $group = User_group::getForNickname($nickname, $profile); if (!empty($group) && $profile->isMember($group)) { $groups[] = $group->id; } } return $groups; }
/** * When saving a notice, check its groups. If any of them has * privacy == always, force a group private message to all mentioned groups. * If any of the groups disallows private messages, skip it. * * @param * */ function onStartNoticeSave(&$notice) { // Look for group tags // FIXME: won't work for remote groups // @fixme if Notice::saveNew is refactored so we can just pull its list // of groups between processing and saving, make use of it $count = preg_match_all('/(?:^|\\s)!(' . Nickname::DISPLAY_FMT . ')/', strtolower($notice->content), $match); $groups = array(); $ignored = array(); $forcePrivate = false; if ($count > 0) { /* Add them to the database */ foreach (array_unique($match[1]) as $nickname) { $group = User_group::getForNickname($nickname, $profile); if (empty($group)) { continue; } $gps = Group_privacy_settings::forGroup($group); switch ($gps->allow_privacy) { case Group_privacy_settings::ALWAYS: $forcePrivate = true; // fall through // fall through case Group_privacy_settings::SOMETIMES: $groups[] = $group; break; case Group_privacy_settings::NEVER: $ignored[] = $group; break; } } if ($forcePrivate) { foreach ($ignored as $group) { common_log(LOG_NOTICE, "Notice forced to group direct message " . "but group " . $group->nickname . " does not allow them."); } $user = User::staticGet('id', $notice->profile_id); if (empty($user)) { common_log(LOG_WARNING, "Notice forced to group direct message " . "but profile " . $notice->profile_id . " is not a local user."); } else { foreach ($groups as $group) { Group_message::send($user, $group, $notice->content); } } // Don't save the notice! // FIXME: this is probably cheating. throw new ClientException(sprintf(_('Forced notice to private group message.')), 200); } } return true; }