[ Index ]

PHP Cross Reference of Phabricator

title

Body

[close]

/src/applications/people/markup/ -> PhabricatorMentionRemarkupRule.php (source)

   1  <?php
   2  
   3  final class PhabricatorMentionRemarkupRule extends PhutilRemarkupRule {
   4  
   5    const KEY_RULE_MENTION          = 'rule.mention';
   6    const KEY_RULE_MENTION_ORIGINAL = 'rule.mention.original';
   7  
   8    const KEY_MENTIONED = 'phabricator.mentioned-user-phids';
   9  
  10  
  11    // NOTE: The negative lookbehind prevents matches like "mail@lists", while
  12    // allowing constructs like "@tomo/@mroch". Since we now allow periods in
  13    // usernames, we can't resonably distinguish that "@company.com" isn't a
  14    // username, so we'll incorrectly pick it up, but there's little to be done
  15    // about that. We forbid terminal periods so that we can correctly capture
  16    // "@joe" instead of "@joe." in "Hey, @joe.".
  17    //
  18    // We disallow "@@joe" because it creates a false positive in the common
  19    // construction "l@@k", made popular by eBay.
  20    const REGEX = '/(?<!\w|@)@([a-zA-Z0-9._-]*[a-zA-Z0-9_-])/';
  21  
  22    public function apply($text) {
  23      return preg_replace_callback(
  24        self::REGEX,
  25        array($this, 'markupMention'),
  26        $text);
  27    }
  28  
  29    protected function markupMention($matches) {
  30      $engine = $this->getEngine();
  31  
  32      if ($engine->isTextMode()) {
  33        return $engine->storeText($matches[0]);
  34      }
  35  
  36      $token = $engine->storeText('');
  37  
  38      // Store the original text exactly so we can preserve casing if it doesn't
  39      // resolve into a username.
  40      $original_key = self::KEY_RULE_MENTION_ORIGINAL;
  41      $original = $engine->getTextMetadata($original_key, array());
  42      $original[$token] = $matches[1];
  43      $engine->setTextMetadata($original_key, $original);
  44  
  45      $metadata_key = self::KEY_RULE_MENTION;
  46      $metadata = $engine->getTextMetadata($metadata_key, array());
  47      $username = strtolower($matches[1]);
  48      if (empty($metadata[$username])) {
  49        $metadata[$username] = array();
  50      }
  51      $metadata[$username][] = $token;
  52      $engine->setTextMetadata($metadata_key, $metadata);
  53  
  54      return $token;
  55    }
  56  
  57    public function didMarkupText() {
  58      $engine = $this->getEngine();
  59  
  60      $metadata_key = self::KEY_RULE_MENTION;
  61      $metadata = $engine->getTextMetadata($metadata_key, array());
  62      if (empty($metadata)) {
  63        // No mentions, or we already processed them.
  64        return;
  65      }
  66  
  67      $original_key = self::KEY_RULE_MENTION_ORIGINAL;
  68      $original = $engine->getTextMetadata($original_key, array());
  69  
  70      $usernames = array_keys($metadata);
  71  
  72      $users = id(new PhabricatorPeopleQuery())
  73        ->setViewer($this->getEngine()->getConfig('viewer'))
  74        ->withUsernames($usernames)
  75        ->execute();
  76  
  77      if ($users) {
  78        $user_statuses = id(new PhabricatorCalendarEvent())
  79          ->loadCurrentStatuses(mpull($users, 'getPHID'));
  80        $user_statuses = mpull($user_statuses, null, 'getUserPHID');
  81      } else {
  82        $user_statuses = array();
  83      }
  84  
  85      $actual_users = array();
  86  
  87      $mentioned_key = self::KEY_MENTIONED;
  88      $mentioned = $engine->getTextMetadata($mentioned_key, array());
  89      foreach ($users as $row) {
  90        $actual_users[strtolower($row->getUserName())] = $row;
  91        $mentioned[$row->getPHID()] = $row->getPHID();
  92      }
  93  
  94      $engine->setTextMetadata($mentioned_key, $mentioned);
  95  
  96      foreach ($metadata as $username => $tokens) {
  97        $exists = isset($actual_users[$username]);
  98  
  99        if ($exists) {
 100          $user = $actual_users[$username];
 101          Javelin::initBehavior('phabricator-hovercards');
 102  
 103          $user_href = '/p/'.$user->getUserName().'/';
 104  
 105          if ($engine->isHTMLMailMode()) {
 106            $user_href = PhabricatorEnv::getProductionURI($user_href);
 107            $tag = phutil_tag(
 108              'a',
 109              array(
 110                'href' => $user_href,
 111                'style' => 'background-color: #f1f7ff;
 112                  border-color: #f1f7ff;
 113                  border: 1px solid transparent;
 114                  border-radius: 3px;
 115                  color: #19558d;
 116                  font-weight: bold;
 117                  padding: 0 4px;',
 118              ),
 119              '@'.$user->getUserName());
 120          } else {
 121            $tag = id(new PHUITagView())
 122              ->setType(PHUITagView::TYPE_PERSON)
 123              ->setPHID($user->getPHID())
 124              ->setName('@'.$user->getUserName())
 125              ->setHref($user_href);
 126  
 127            if (!$user->isUserActivated()) {
 128              $tag->setDotColor(PHUITagView::COLOR_GREY);
 129            } else {
 130              $status = idx($user_statuses, $user->getPHID());
 131              if ($status) {
 132                $status = $status->getStatus();
 133                if ($status == PhabricatorCalendarEvent::STATUS_AWAY) {
 134                  $tag->setDotColor(PHUITagView::COLOR_RED);
 135                } else if ($status == PhabricatorCalendarEvent::STATUS_AWAY) {
 136                  $tag->setDotColor(PHUITagView::COLOR_ORANGE);
 137                }
 138              }
 139            }
 140          }
 141  
 142          foreach ($tokens as $token) {
 143            $engine->overwriteStoredText($token, $tag);
 144          }
 145        } else {
 146          // NOTE: The structure here is different from the 'exists' branch,
 147          // because we want to preserve the original text capitalization and it
 148          // may differ for each token.
 149          foreach ($tokens as $token) {
 150            $tag = phutil_tag(
 151              'span',
 152              array(
 153                'class' => 'phabricator-remarkup-mention-unknown',
 154              ),
 155              '@'.idx($original, $token, $username));
 156            $engine->overwriteStoredText($token, $tag);
 157          }
 158        }
 159      }
 160  
 161      // Don't re-process these mentions.
 162      $engine->setTextMetadata($metadata_key, array());
 163    }
 164  
 165  }


Generated: Sun Nov 30 09:20:46 2014 Cross-referenced by PHPXref 0.7.1