[ Index ]

PHP Cross Reference of Phabricator

title

Body

[close]

/src/infrastructure/daemon/bot/handler/ -> PhabricatorBotFeedNotificationHandler.php (source)

   1  <?php
   2  
   3  /**
   4   * Watches the feed and puts notifications into channel(s) of choice.
   5   */
   6  final class PhabricatorBotFeedNotificationHandler
   7    extends PhabricatorBotHandler {
   8  
   9    private $startupDelay = 30;
  10    private $lastSeenChronoKey = 0;
  11  
  12    private $typesNeedURI = array('DREV', 'TASK');
  13  
  14    private function shouldShowStory($story) {
  15      $story_objectphid = $story['objectPHID'];
  16      $story_text = $story['text'];
  17  
  18      $show = $this->getConfig('notification.types');
  19  
  20      if ($show) {
  21        $obj_type = phid_get_type($story_objectphid);
  22        if (!in_array(strtolower($obj_type), $show)) {
  23          return false;
  24        }
  25      }
  26  
  27      $verbosity = $this->getConfig('notification.verbosity', 3);
  28  
  29      $verbs = array();
  30  
  31      switch ($verbosity) {
  32        case 2:
  33          $verbs[] = array(
  34            'commented',
  35            'added',
  36            'changed',
  37            'resigned',
  38            'explained',
  39            'modified',
  40            'attached',
  41            'edited',
  42            'joined',
  43            'left',
  44            'removed',
  45          );
  46        // fallthrough
  47        case 1:
  48          $verbs[] = array(
  49            'updated',
  50            'accepted',
  51            'requested',
  52            'planned',
  53            'claimed',
  54            'summarized',
  55            'commandeered',
  56            'assigned',
  57          );
  58        // fallthrough
  59        case 0:
  60          $verbs[] = array(
  61            'created',
  62            'closed',
  63            'raised',
  64            'committed',
  65            'abandoned',
  66            'reclaimed',
  67            'reopened',
  68            'deleted',
  69          );
  70          break;
  71  
  72        case 3:
  73        default:
  74          return true;
  75      }
  76  
  77      $verbs = '/('.implode('|', array_mergev($verbs)).')/';
  78  
  79      if (preg_match($verbs, $story_text)) {
  80        return true;
  81      }
  82  
  83      return false;
  84    }
  85  
  86    public function receiveMessage(PhabricatorBotMessage $message) {
  87      return;
  88    }
  89  
  90    public function runBackgroundTasks() {
  91      if ($this->startupDelay > 0) {
  92        // the event loop runs every 1s so delay enough to fully conenct
  93        $this->startupDelay--;
  94  
  95        return;
  96      }
  97      if ($this->lastSeenChronoKey == 0) {
  98        // Since we only want to post notifications about new stories, skip
  99        // everything that's happened in the past when we start up so we'll
 100        // only process real-time stories.
 101        $latest = $this->getConduit()->callMethodSynchronous(
 102          'feed.query',
 103          array(
 104            'limit' => 1,
 105          ));
 106  
 107        foreach ($latest as $story) {
 108          if ($story['chronologicalKey'] > $this->lastSeenChronoKey) {
 109            $this->lastSeenChronoKey = $story['chronologicalKey'];
 110          }
 111        }
 112  
 113        return;
 114      }
 115  
 116      $config_max_pages = $this->getConfig('notification.max_pages', 5);
 117      $config_page_size = $this->getConfig('notification.page_size', 10);
 118  
 119      $last_seen_chrono_key = $this->lastSeenChronoKey;
 120      $chrono_key_cursor = 0;
 121  
 122      // Not efficient but works due to feed.query API
 123      for ($max_pages = $config_max_pages; $max_pages > 0; $max_pages--) {
 124        $stories = $this->getConduit()->callMethodSynchronous(
 125          'feed.query',
 126          array(
 127            'limit' => $config_page_size,
 128            'after' => $chrono_key_cursor,
 129            'view' => 'text',
 130          ));
 131  
 132        foreach ($stories as $story) {
 133          if ($story['chronologicalKey'] == $last_seen_chrono_key) {
 134            // Caught up on feed
 135            return;
 136          }
 137          if ($story['chronologicalKey'] > $this->lastSeenChronoKey) {
 138            // Keep track of newest seen story
 139            $this->lastSeenChronoKey = $story['chronologicalKey'];
 140          }
 141          if (!$chrono_key_cursor ||
 142              $story['chronologicalKey'] < $chrono_key_cursor) {
 143            // Keep track of oldest story on this page
 144            $chrono_key_cursor = $story['chronologicalKey'];
 145          }
 146  
 147          if (!$story['text'] ||
 148              !$this->shouldShowStory($story)) {
 149            continue;
 150          }
 151  
 152          $message = $story['text'];
 153  
 154          $story_object_type = phid_get_type($story['objectPHID']);
 155          if (in_array($story_object_type, $this->typesNeedURI)) {
 156            $objects = $this->getConduit()->callMethodSynchronous(
 157              'phid.lookup',
 158              array(
 159                'names' => array($story['objectPHID']),
 160              ));
 161            $message .= ' '.$objects[$story['objectPHID']]['uri'];
 162          }
 163  
 164          $channels = $this->getConfig('join');
 165          foreach ($channels as $channel_name) {
 166  
 167            $channel = id(new PhabricatorBotChannel())
 168              ->setName($channel_name);
 169  
 170            $this->writeMessage(
 171              id(new PhabricatorBotMessage())
 172              ->setCommand('MESSAGE')
 173              ->setTarget($channel)
 174              ->setBody($message));
 175          }
 176        }
 177      }
 178    }
 179  
 180  }


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