public function processRequest()
 {
     $request = $this->getRequest();
     $user = $request->getUser();
     $content_type_map = HeraldContentTypeConfig::getContentTypeMap();
     if (empty($content_type_map[$this->contentType])) {
         $this->contentType = head_key($content_type_map);
     }
     $rule_type_map = HeraldRuleTypeConfig::getRuleTypeMap();
     if (empty($rule_type_map[$this->ruleType])) {
         $this->ruleType = HeraldRuleTypeConfig::RULE_TYPE_PERSONAL;
     }
     // Reorder array to put "personal" first.
     $rule_type_map = array_select_keys($rule_type_map, array(HeraldRuleTypeConfig::RULE_TYPE_PERSONAL)) + $rule_type_map;
     $captions = array(HeraldRuleTypeConfig::RULE_TYPE_PERSONAL => 'Personal rules notify you about events. You own them, but they can ' . 'only affect you.', HeraldRuleTypeConfig::RULE_TYPE_GLOBAL => 'Global rules notify anyone about events. No one owns them, and ' . 'anyone can edit them. Usually, Global rules are used to notify ' . 'mailing lists.');
     $radio = id(new AphrontFormRadioButtonControl())->setLabel('Type')->setName('rule_type')->setValue($this->ruleType);
     foreach ($rule_type_map as $value => $name) {
         $radio->addButton($value, $name, idx($captions, $value));
     }
     $form = id(new AphrontFormView())->setUser($user)->setAction('/herald/rule/')->appendChild(id(new AphrontFormSelectControl())->setLabel('New rule for')->setName('content_type')->setValue($this->contentType)->setOptions($content_type_map))->appendChild($radio)->appendChild(id(new AphrontFormSubmitControl())->setValue('Create Rule')->addCancelButton('/herald/view/' . $this->contentType . '/'));
     $panel = new AphrontPanelView();
     $panel->setHeader('Create New Herald Rule');
     $panel->setWidth(AphrontPanelView::WIDTH_FULL);
     $panel->appendChild($form);
     $nav = $this->renderNav();
     $nav->selectFilter('new');
     $nav->appendChild($panel);
     return $this->buildStandardPageResponse($nav, array('title' => 'Create Herald Rule'));
 }
 public function buildStandardPageResponse($view, array $data)
 {
     $page = $this->buildStandardPageView();
     $page->setApplicationName('Herald');
     $page->setBaseURI('/herald/');
     $page->setTitle(idx($data, 'title'));
     $page->setGlyph("☿");
     $doclink = PhabricatorEnv::getDoclink('article/Herald_User_Guide.html');
     $nav = new AphrontSideNavFilterView();
     $nav->setBaseURI(new PhutilURI('/herald/'))->addLabel('Rules')->addFilter('new', 'Create Rule');
     $rules_map = HeraldContentTypeConfig::getContentTypeMap();
     $first_filter = null;
     foreach ($rules_map as $key => $value) {
         $nav->addFilter('view/' . $key, $value);
         if (!$first_filter) {
             $first_filter = 'view/' . $key;
         }
     }
     $nav->addSpacer()->addLabel('Utilities')->addFilter('test', 'Test Console')->addFilter('transcript', 'Transcripts');
     $user = $this->getRequest()->getUser();
     if ($user->getIsAdmin()) {
         $nav->addSpacer()->addLabel('Admin');
         $view_PHID = nonempty($this->getRequest()->getStr('phid'), null);
         foreach ($rules_map as $key => $value) {
             $nav->addFilter('all/view/' . $key, $value);
         }
     }
     $nav->selectFilter($this->getFilter(), $first_filter);
     $nav->appendChild($view);
     $page->appendChild($nav);
     $tabs = array('help' => array('href' => $doclink, 'name' => 'Help'));
     $page->setTabs($tabs, null);
     $response = new AphrontWebpageResponse();
     return $response->setContent($page->render());
 }
 public function processRequest()
 {
     $request = $this->getRequest();
     $user = $request->getUser();
     $map = HeraldContentTypeConfig::getContentTypeMap();
     if (empty($map[$this->type])) {
         reset($map);
         $this->type = key($map);
     }
     $form = id(new AphrontFormView())->setUser($user)->setAction('/herald/rule/')->appendChild(id(new AphrontFormSelectControl())->setLabel('New rule for')->setName('type')->setValue($this->type)->setOptions($map))->appendChild(id(new AphrontFormSubmitControl())->setValue('Create Rule')->addCancelButton('/herald/view/' . $this->type . '/'));
     $panel = new AphrontPanelView();
     $panel->setHeader('Create New Herald Rule');
     $panel->setWidth(AphrontPanelView::WIDTH_FULL);
     $panel->appendChild($form);
     return $this->buildStandardPageResponse($panel, array('title' => 'Create Herald Rule'));
 }
 public function processRequest()
 {
     $request = $this->getRequest();
     $user = $request->getUser();
     $map = HeraldContentTypeConfig::getContentTypeMap();
     if (empty($map[$this->view])) {
         reset($map);
         $this->view = key($map);
     }
     $rules = id(new HeraldRule())->loadAllWhere('contentType = %s AND authorPHID = %s', $this->view, $user->getPHID());
     $need_phids = mpull($rules, 'getAuthorPHID');
     $handles = id(new PhabricatorObjectHandleData($need_phids))->loadHandles();
     $list_view = id(new HeraldRuleListView())->setRules($rules)->setHandles($handles)->setMap($map)->setAllowCreation(true)->setView($this->view);
     $panel = $list_view->render();
     return $this->buildStandardPageResponse($panel, array('title' => 'Herald'));
 }
 public function processRequest()
 {
     $request = $this->getRequest();
     $user = $request->getUser();
     $this->viewPHID = nonempty($request->getStr('phid'), null);
     if ($request->isFormPost()) {
         $phid_arr = $request->getArr('view_user');
         $view_target = head($phid_arr);
         return id(new AphrontRedirectResponse())->setURI($request->getRequestURI()->alter('phid', $view_target));
     }
     $map = HeraldContentTypeConfig::getContentTypeMap();
     if (empty($map[$this->view])) {
         reset($map);
         $this->view = key($map);
     }
     $offset = $request->getInt('offset', 0);
     $pager = new AphrontPagerView();
     $pager->setPageSize(50);
     $pager->setOffset($offset);
     $pager->setURI($request->getRequestURI(), 'offset');
     list($rules, $handles) = $this->queryRules($pager);
     if (!$this->viewPHID) {
         $view_users = array();
     } else {
         $view_users = array($this->viewPHID => $handles[$this->viewPHID]->getFullName());
     }
     $filter_form = id(new AphrontFormView())->setUser($user)->appendChild(id(new AphrontFormTokenizerControl())->setDatasource('/typeahead/common/users/')->setLabel('View User')->setName('view_user')->setValue($view_users)->setLimit(1));
     $filter_view = new AphrontListFilterView();
     $filter_view->appendChild($filter_form);
     $list_view = id(new HeraldRuleListView())->setRules($rules)->setHandles($handles)->setMap($map)->setAllowCreation(false)->setView($this->view);
     $panel = $list_view->render();
     $panel->appendChild($pager);
     $sidenav = new AphrontSideNavView();
     $sidenav->appendChild($filter_view);
     $sidenav->appendChild($panel);
     $query = '';
     if ($this->viewPHID) {
         $query = '?phid=' . $this->viewPHID;
     }
     foreach ($map as $key => $value) {
         $sidenav->addNavItem(phutil_render_tag('a', array('href' => '/herald/all/view/' . $key . '/' . $query, 'class' => $key == $this->view ? 'aphront-side-nav-selected' : null), phutil_escape_html($value)));
     }
     return $this->buildStandardPageResponse(array($filter_view, $panel), array('title' => 'Herald', 'tab' => 'all'));
 }
 protected function renderNav()
 {
     $nav = id(new AphrontSideNavFilterView())->setBaseURI(new PhutilURI('/herald/'))->addLabel('My Rules')->addFilter('new', 'Create Rule');
     $rules_map = HeraldContentTypeConfig::getContentTypeMap();
     foreach ($rules_map as $key => $value) {
         $nav->addFilter("view/{$key}/personal", $value);
     }
     $nav->addSpacer()->addLabel('Global Rules');
     foreach ($rules_map as $key => $value) {
         $nav->addFilter("view/{$key}/global", $value);
     }
     $nav->addSpacer()->addLabel('Utilities')->addFilter('test', 'Test Console')->addFilter('transcript', 'Transcripts')->addFilter('history', 'Edit Log');
     if ($this->getRequest()->getUser()->getIsAdmin()) {
         $nav->addSpacer()->addLabel('Admin');
         foreach ($rules_map as $key => $value) {
             $nav->addFilter("view/{$key}/all", $value);
         }
     }
     return $nav;
 }
 public function processRequest()
 {
     $request = $this->getRequest();
     $user = $request->getUser();
     $map = HeraldContentTypeConfig::getContentTypeMap();
     if (empty($map[$this->view])) {
         reset($map);
         $this->view = key($map);
     }
     $rules = id(new HeraldRule())->loadAllWhere('contentType = %s AND authorPHID = %s', $this->view, $user->getPHID());
     $need_phids = mpull($rules, 'getAuthorPHID');
     $handles = id(new PhabricatorObjectHandleData($need_phids))->loadHandles();
     $type = 'differential';
     $rows = array();
     foreach ($rules as $rule) {
         $owner = $handles[$rule->getAuthorPHID()]->renderLink();
         $name = phutil_render_tag('a', array('href' => '/herald/rule/' . $rule->getID() . '/'), phutil_escape_html($rule->getName()));
         $delete = 'delete';
         $delete = javelin_render_tag('a', array('href' => '/herald/delete/' . $rule->getID() . '/', 'sigil' => 'workflow', 'class' => 'button small grey'), 'Delete');
         $rows[] = array($map[$rule->getContentType()], $owner, $name, $delete);
     }
     $rules_for = phutil_escape_html($map[$this->view]);
     $table = new AphrontTableView($rows);
     $table->setNoDataString("No matching subscription rules for {$rules_for}.");
     $table->setHeaders(array('Type', 'Owner', 'Rule Name', ''));
     $table->setColumnClasses(array('', '', 'wide wrap pri', 'action'));
     $panel = new AphrontPanelView();
     $panel->setHeader("Herald Rules for {$rules_for}");
     $panel->setCreateButton('Create New Herald Rule', '/herald/new/' . $this->view . '/');
     $panel->appendChild($table);
     $sidenav = new AphrontSideNavView();
     $sidenav->appendChild($panel);
     foreach ($map as $key => $value) {
         $sidenav->addNavItem(phutil_render_tag('a', array('href' => '/herald/view/' . $key . '/', 'class' => $key == $this->view ? 'aphront-side-nav-selected' : null), phutil_escape_html($value)));
     }
     return $this->buildStandardPageResponse($sidenav, array('title' => 'Herald', 'tab' => 'rules'));
 }
 public function processRequest()
 {
     $request = $this->getRequest();
     $user = $request->getUser();
     $content_type_map = HeraldContentTypeConfig::getContentTypeMap();
     $rule_type_map = HeraldRuleTypeConfig::getRuleTypeMap();
     if ($this->id) {
         $rule = id(new HeraldRule())->load($this->id);
         if (!$rule) {
             return new Aphront404Response();
         }
         if (!$this->canEditRule($rule, $user)) {
             throw new Exception("You don't own this rule and can't edit it.");
         }
     } else {
         $rule = new HeraldRule();
         $rule->setAuthorPHID($user->getPHID());
         $rule->setMustMatchAll(true);
         $content_type = $request->getStr('content_type');
         if (!isset($content_type_map[$content_type])) {
             $content_type = HeraldContentTypeConfig::CONTENT_TYPE_DIFFERENTIAL;
         }
         $rule->setContentType($content_type);
         $rule_type = $request->getStr('rule_type');
         if (!isset($rule_type_map[$rule_type])) {
             $rule_type = HeraldRuleTypeConfig::RULE_TYPE_GLOBAL;
         }
         $rule->setRuleType($rule_type);
     }
     $local_version = id(new HeraldRule())->getConfigVersion();
     if ($rule->getConfigVersion() > $local_version) {
         throw new Exception("This rule was created with a newer version of Herald. You can not " . "view or edit it in this older version. Upgrade your Phabricator " . "deployment.");
     }
     // Upgrade rule version to our version, since we might add newly-defined
     // conditions, etc.
     $rule->setConfigVersion($local_version);
     $rule_conditions = $rule->loadConditions();
     $rule_actions = $rule->loadActions();
     $rule->attachConditions($rule_conditions);
     $rule->attachActions($rule_actions);
     $e_name = true;
     $errors = array();
     if ($request->isFormPost() && $request->getStr('save')) {
         list($e_name, $errors) = $this->saveRule($rule, $request);
         if (!$errors) {
             $uri = '/herald/view/' . $rule->getContentType() . '/' . $rule->getRuleType() . '/';
             return id(new AphrontRedirectResponse())->setURI($uri);
         }
     }
     if ($errors) {
         $error_view = new AphrontErrorView();
         $error_view->setTitle('Form Errors');
         $error_view->setErrors($errors);
     } else {
         $error_view = null;
     }
     $must_match_selector = $this->renderMustMatchSelector($rule);
     $repetition_selector = $this->renderRepetitionSelector($rule);
     $handles = $this->loadHandlesForRule($rule);
     require_celerity_resource('herald-css');
     $content_type_name = $content_type_map[$rule->getContentType()];
     $rule_type_name = $rule_type_map[$rule->getRuleType()];
     $form = id(new AphrontFormView())->setUser($user)->setID('herald-rule-edit-form')->addHiddenInput('content_type', $rule->getContentType())->addHiddenInput('rule_type', $rule->getRuleType())->addHiddenInput('save', 1)->appendChild(javelin_render_tag('input', array('type' => 'hidden', 'name' => 'rule', 'sigil' => 'rule')))->appendChild(id(new AphrontFormTextControl())->setLabel('Rule Name')->setName('name')->setError($e_name)->setValue($rule->getName()));
     $form->appendChild(id(new AphrontFormMarkupControl())->setValue("This <strong>{$rule_type_name}</strong> rule triggers for " . "<strong>{$content_type_name}</strong>."))->appendChild(id(new AphrontFormInsetView())->setTitle('Conditions')->setRightButton(javelin_render_tag('a', array('href' => '#', 'class' => 'button green', 'sigil' => 'create-condition', 'mustcapture' => true), 'Create New Condition'))->setDescription('When ' . $must_match_selector . ' these conditions are met:')->setContent(javelin_render_tag('table', array('sigil' => 'rule-conditions', 'class' => 'herald-condition-table'), '')))->appendChild(id(new AphrontFormInsetView())->setTitle('Action')->setRightButton(javelin_render_tag('a', array('href' => '#', 'class' => 'button green', 'sigil' => 'create-action', 'mustcapture' => true), 'Create New Action'))->setDescription('Take these actions ' . $repetition_selector . ' this rule matches:')->setContent(javelin_render_tag('table', array('sigil' => 'rule-actions', 'class' => 'herald-action-table'), '')))->appendChild(id(new AphrontFormSubmitControl())->setValue('Save Rule')->addCancelButton('/herald/view/' . $rule->getContentType() . '/'));
     $this->setupEditorBehavior($rule, $handles);
     $panel = new AphrontPanelView();
     $panel->setHeader($rule->getID() ? 'Edit Herald Rule' : 'Create Herald Rule');
     $panel->setWidth(AphrontPanelView::WIDTH_WIDE);
     $panel->appendChild($form);
     $nav = $this->renderNav();
     $nav->selectFilter('view/' . $rule->getContentType() . '/' . $rule->getRuleType());
     $nav->appendChild(array($error_view, $panel));
     return $this->buildStandardPageResponse($nav, array('title' => 'Edit Rule'));
 }
 public function processRequest()
 {
     $request = $this->getRequest();
     $user = $request->getUser();
     if ($request->isFormPost()) {
         $phids = $request->getArr('set_phid');
         $phid = head($phids);
         $uri = $request->getRequestURI();
         if ($phid) {
             $uri = $uri->alter('phid', nonempty($phid, null));
         }
         return id(new AphrontRedirectResponse())->setURI($uri);
     }
     $query = new HeraldRuleQuery();
     $content_type_map = HeraldContentTypeConfig::getContentTypeMap();
     if (empty($content_type_map[$this->contentType])) {
         $this->contentType = head_key($content_type_map);
     }
     $content_desc = $content_type_map[$this->contentType];
     $query->withContentTypes(array($this->contentType));
     $is_admin_page = false;
     $show_author = false;
     $show_rule_type = false;
     $can_create = false;
     $has_author_filter = false;
     $author_filter_phid = null;
     switch ($this->ruleType) {
         case 'all':
             if (!$user->getIsAdmin()) {
                 return new Aphront400Response();
             }
             $is_admin_page = true;
             $show_rule_type = true;
             $show_author = true;
             $has_author_filter = true;
             $author_filter_phid = $request->getStr('phid');
             if ($author_filter_phid) {
                 $query->withAuthorPHIDs(array($author_filter_phid));
             }
             $rule_desc = 'All';
             break;
         case HeraldRuleTypeConfig::RULE_TYPE_GLOBAL:
             $query->withRuleTypes(array(HeraldRuleTypeConfig::RULE_TYPE_GLOBAL));
             $can_create = true;
             $rule_desc = 'Global';
             break;
         case HeraldRuleTypeConfig::RULE_TYPE_PERSONAL:
         default:
             $this->ruleType = HeraldRuleTypeConfig::RULE_TYPE_PERSONAL;
             $query->withRuleTypes(array(HeraldRuleTypeConfig::RULE_TYPE_PERSONAL));
             $query->withAuthorPHIDs(array($user->getPHID()));
             $can_create = true;
             $rule_desc = 'Personal';
             break;
     }
     $pager = new AphrontPagerView();
     $pager->setURI($request->getRequestURI(), 'offset');
     $pager->setOffset($request->getStr('offset'));
     $rules = $query->executeWithOffsetPager($pager);
     $need_phids = mpull($rules, 'getAuthorPHID');
     $handles = $this->loadViewerHandles($need_phids);
     $list_view = id(new HeraldRuleListView())->setRules($rules)->setShowAuthor($show_author)->setShowRuleType($show_rule_type)->setHandles($handles)->setUser($user);
     $panel = new AphrontPanelView();
     $panel->appendChild($list_view);
     $panel->appendChild($pager);
     $panel->setHeader("Herald: {$rule_desc} Rules for {$content_desc}");
     if ($can_create) {
         $panel->addButton(phutil_render_tag('a', array('href' => '/herald/new/' . $this->contentType . '/' . $this->ruleType . '/', 'class' => 'green button'), 'Create New Herald Rule'));
     }
     $nav = $this->renderNav();
     $nav->selectFilter('view/' . $this->contentType . '/' . $this->ruleType);
     if ($has_author_filter) {
         $nav->appendChild($this->renderAuthorFilter($author_filter_phid));
     }
     $nav->appendChild($panel);
     return $this->buildStandardPageResponse($nav, array('title' => 'Herald', 'admin' => $is_admin_page));
 }
 public function processRequest()
 {
     $request = $this->getRequest();
     $user = $request->getUser();
     $content_type_map = HeraldContentTypeConfig::getContentTypeMap();
     if ($this->id) {
         $rule = id(new HeraldRule())->load($this->id);
         if (!$rule) {
             return new Aphront404Response();
         }
         if ($rule->getAuthorPHID() != $user->getPHID()) {
             throw new Exception("You don't own this rule and can't edit it.");
         }
     } else {
         $rule = new HeraldRule();
         $rule->setAuthorPHID($user->getPHID());
         $rule->setMustMatchAll(true);
         $type = $request->getStr('type');
         if (!isset($content_type_map[$type])) {
             $type = HeraldContentTypeConfig::CONTENT_TYPE_DIFFERENTIAL;
         }
         $rule->setContentType($type);
     }
     $local_version = id(new HeraldRule())->getConfigVersion();
     if ($rule->getConfigVersion() > $local_version) {
         throw new Exception("This rule was created with a newer version of Herald. You can not " . "view or edit it in this older version. Try dev or wait for a push.");
     }
     // Upgrade rule version to our version, since we might add newly-defined
     // conditions, etc.
     $rule->setConfigVersion($local_version);
     $rule_conditions = $rule->loadConditions();
     $rule_actions = $rule->loadActions();
     $rule->attachConditions($rule_conditions);
     $rule->attachActions($rule_actions);
     $e_name = true;
     $errors = array();
     if ($request->isFormPost() && $request->getStr('save')) {
         $rule->setName($request->getStr('name'));
         $rule->setMustMatchAll($request->getStr('must_match') == 'all');
         $repetition_policy_param = $request->getStr('repetition_policy');
         $rule->setRepetitionPolicy(HeraldRepetitionPolicyConfig::toInt($repetition_policy_param));
         if (!strlen($rule->getName())) {
             $e_name = "Required";
             $errors[] = "Rule must have a name.";
         }
         $data = json_decode($request->getStr('rule'), true);
         if (!is_array($data) || !$data['conditions'] || !$data['actions']) {
             throw new Exception("Failed to decode rule data.");
         }
         $conditions = array();
         foreach ($data['conditions'] as $condition) {
             if ($condition === null) {
                 // We manage this as a sparse array on the client, so may receive
                 // NULL if conditions have been removed.
                 continue;
             }
             $obj = new HeraldCondition();
             $obj->setFieldName($condition[0]);
             $obj->setFieldCondition($condition[1]);
             if (is_array($condition[2])) {
                 $obj->setValue(array_keys($condition[2]));
             } else {
                 $obj->setValue($condition[2]);
             }
             $cond_type = $obj->getFieldCondition();
             if ($cond_type == HeraldConditionConfig::CONDITION_REGEXP) {
                 if (@preg_match($obj->getValue(), '') === false) {
                     $errors[] = 'The regular expression "' . $obj->getValue() . '" is not valid. ' . 'Regular expressions must have enclosing characters (e.g. ' . '"@/path/to/file@", not "/path/to/file") and be syntactically ' . 'correct.';
                 }
             }
             if ($cond_type == HeraldConditionConfig::CONDITION_REGEXP_PAIR) {
                 $json = json_decode($obj->getValue(), true);
                 if (!is_array($json)) {
                     $errors[] = 'The regular expression pair "' . $obj->getValue() . '" is not ' . 'valid JSON. Enter a valid JSON array with two elements.';
                 } else {
                     if (count($json) != 2) {
                         $errors[] = 'The regular expression pair "' . $obj->getValue() . '" must have ' . 'exactly two elements.';
                     } else {
                         $key_regexp = array_shift($json);
                         $val_regexp = array_shift($json);
                         if (@preg_match($key_regexp, '') === false) {
                             $errors[] = 'The first regexp, "' . $key_regexp . '" in the regexp pair ' . 'is not a valid regexp.';
                         }
                         if (@preg_match($val_regexp, '') === false) {
                             $errors[] = 'The second regexp, "' . $val_regexp . '" in the regexp pair ' . 'is not a valid regexp.';
                         }
                     }
                 }
             }
             $conditions[] = $obj;
         }
         $actions = array();
         foreach ($data['actions'] as $action) {
             if ($action === null) {
                 // Sparse on the client; removals can give us NULLs.
                 continue;
             }
             $obj = new HeraldAction();
             $obj->setAction($action[0]);
             if (!isset($action[1])) {
                 // Legitimate for any action which doesn't need a target, like
                 // "Do nothing".
                 $action[1] = null;
             }
             if (is_array($action[1])) {
                 $obj->setTarget(array_keys($action[1]));
             } else {
                 $obj->setTarget($action[1]);
             }
             $actions[] = $obj;
         }
         $rule->attachConditions($conditions);
         $rule->attachActions($actions);
         if (!$errors) {
             try {
                 // TODO
                 //          $rule->openTransaction();
                 $rule->save();
                 $rule->saveConditions($conditions);
                 $rule->saveActions($actions);
                 //          $rule->saveTransaction();
                 $uri = '/herald/view/' . $rule->getContentType() . '/';
                 return id(new AphrontRedirectResponse())->setURI($uri);
             } catch (AphrontQueryDuplicateKeyException $ex) {
                 $e_name = "Not Unique";
                 $errors[] = "Rule name is not unique. Choose a unique name.";
             }
         }
     }
     $phids = array();
     $phids[] = $rule->getAuthorPHID();
     foreach ($rule->getActions() as $action) {
         if (!is_array($action->getTarget())) {
             continue;
         }
         foreach ($action->getTarget() as $target) {
             $target = (array) $target;
             foreach ($target as $phid) {
                 $phids[] = $phid;
             }
         }
     }
     foreach ($rule->getConditions() as $condition) {
         $value = $condition->getValue();
         if (is_array($value)) {
             foreach ($value as $phid) {
                 $phids[] = $phid;
             }
         }
     }
     $handles = id(new PhabricatorObjectHandleData($phids))->loadHandles();
     if ($errors) {
         $error_view = new AphrontErrorView();
         $error_view->setTitle('Form Errors');
         $error_view->setErrors($errors);
     } else {
         $error_view = null;
     }
     $options = array('all' => 'all of', 'any' => 'any of');
     $selected = $rule->getMustMatchAll() ? 'all' : 'any';
     $must_match = array();
     foreach ($options as $key => $option) {
         $must_match[] = phutil_render_tag('option', array('selected' => $selected == $key ? 'selected' : null, 'value' => $key), phutil_escape_html($option));
     }
     $must_match = '<select name="must_match">' . implode("\n", $must_match) . '</select>';
     if ($rule->getID()) {
         $action = '/herald/rule/' . $rule->getID() . '/';
     } else {
         $action = '/herald/rule/' . $rule->getID() . '/';
     }
     // Make the selector for choosing how often this rule should be repeated
     $repetition_selector = "";
     $repetition_policy = HeraldRepetitionPolicyConfig::toString($rule->getRepetitionPolicy());
     $repetition_options = HeraldRepetitionPolicyConfig::getMapForContentType($rule->getContentType());
     if (empty($repetition_options)) {
         // default option is 'every time'
         $repetition_selector = idx(HeraldRepetitionPolicyConfig::getMap(), HeraldRepetitionPolicyConfig::EVERY);
     } else {
         if (count($repetition_options) == 1) {
             // if there's only 1 option, just pick it for the user
             $repetition_selector = reset($repetition_options);
         } else {
             // give the user all the options for this rule type
             $tags = array();
             foreach ($repetition_options as $name => $option) {
                 $tags[] = phutil_render_tag('option', array('selected' => $repetition_policy == $name ? 'selected' : null, 'value' => $name), phutil_escape_html($option));
             }
             $repetition_selector = '<select name="repetition_policy">' . implode("\n", $tags) . '</select>';
         }
     }
     require_celerity_resource('herald-css');
     $type_name = $content_type_map[$rule->getContentType()];
     $form = id(new AphrontFormView())->setUser($user)->setID('herald-rule-edit-form')->addHiddenInput('type', $rule->getContentType())->addHiddenInput('save', 1)->appendChild(javelin_render_tag('input', array('type' => 'hidden', 'name' => 'rule', 'sigil' => 'rule')))->appendChild(id(new AphrontFormTextControl())->setLabel('Rule Name')->setName('name')->setError($e_name)->setValue($rule->getName()))->appendChild(id(new AphrontFormStaticControl())->setLabel('Author')->setValue($handles[$rule->getAuthorPHID()]->getName()))->appendChild(id(new AphrontFormMarkupControl())->setValue("This rule triggers for <strong>{$type_name}</strong>."))->appendChild('<h1>Conditions</h1>' . '<div class="aphront-form-inset">' . '<div style="float: right;">' . javelin_render_tag('a', array('href' => '#', 'class' => 'button green', 'sigil' => 'create-condition', 'mustcapture' => true), 'Create New Condition') . '</div>' . '<p>When ' . $must_match . ' these conditions are met:</p>' . '<div style="clear: both;"></div>' . javelin_render_tag('table', array('sigil' => 'rule-conditions', 'class' => 'herald-condition-table'), '') . '</div>')->appendChild('<h1>Action</h1>' . '<div class="aphront-form-inset">' . '<div style="float: right;">' . javelin_render_tag('a', array('href' => '#', 'class' => 'button green', 'sigil' => 'create-action', 'mustcapture' => true), 'Create New Action') . '</div>' . '<p>' . 'Take these actions ' . $repetition_selector . ' this rule matches:' . '</p>' . '<div style="clear: both;"></div>' . javelin_render_tag('table', array('sigil' => 'rule-actions', 'class' => 'herald-action-table'), '') . '</div>')->appendChild(id(new AphrontFormSubmitControl())->setValue('Save Rule')->addCancelButton('/herald/view/' . $rule->getContentType() . '/'));
     $serial_conditions = array(array('default', 'default', ''));
     if ($rule->getConditions()) {
         $serial_conditions = array();
         foreach ($rule->getConditions() as $condition) {
             $value = $condition->getValue();
             if (is_array($value)) {
                 $value_map = array();
                 foreach ($value as $k => $fbid) {
                     $value_map[$fbid] = $handles[$fbid]->getName();
                 }
                 $value = $value_map;
             }
             $serial_conditions[] = array($condition->getFieldName(), $condition->getFieldCondition(), $value);
         }
     }
     $serial_actions = array(array('default', ''));
     if ($rule->getActions()) {
         $serial_actions = array();
         foreach ($rule->getActions() as $action) {
             $target_map = array();
             foreach ((array) $action->getTarget() as $fbid) {
                 $target_map[$fbid] = $handles[$fbid]->getName();
             }
             $serial_actions[] = array($action->getAction(), $target_map);
         }
     }
     $all_rules = id(new HeraldRule())->loadAllWhere('authorPHID = %d AND contentType = %s', $rule->getAuthorPHID(), $rule->getContentType());
     $all_rules = mpull($all_rules, 'getName', 'getID');
     asort($all_rules);
     unset($all_rules[$rule->getID()]);
     $config_info = array();
     $config_info['fields'] = HeraldFieldConfig::getFieldMapForContentType($rule->getContentType());
     $config_info['conditions'] = HeraldConditionConfig::getConditionMap();
     foreach ($config_info['fields'] as $field => $name) {
         $config_info['conditionMap'][$field] = array_keys(HeraldConditionConfig::getConditionMapForField($field));
     }
     foreach ($config_info['fields'] as $field => $fname) {
         foreach ($config_info['conditions'] as $condition => $cname) {
             $config_info['values'][$field][$condition] = HeraldValueTypeConfig::getValueTypeForFieldAndCondition($field, $condition);
         }
     }
     $config_info['actions'] = HeraldActionConfig::getActionMapForContentType($rule->getContentType());
     foreach ($config_info['actions'] as $action => $name) {
         $config_info['targets'][$action] = HeraldValueTypeConfig::getValueTypeForAction($action);
     }
     Javelin::initBehavior('herald-rule-editor', array('root' => 'herald-rule-edit-form', 'conditions' => (object) $serial_conditions, 'actions' => (object) $serial_actions, 'template' => $this->buildTokenizerTemplates() + array('rules' => $all_rules), 'info' => $config_info));
     $panel = new AphrontPanelView();
     $panel->setHeader('Edit Herald Rule');
     $panel->setWidth(AphrontPanelView::WIDTH_WIDE);
     $panel->appendChild($form);
     return $this->buildStandardPageResponse(array($error_view, $panel), array('title' => 'Edit Rule'));
 }