public function processRequest()
 {
     $request = $this->getRequest();
     $viewer = $request->getUser();
     $xscript = id(new HeraldTranscriptQuery())->setViewer($viewer)->withIDs(array($this->id))->executeOne();
     if (!$xscript) {
         return new Aphront404Response();
     }
     require_celerity_resource('herald-test-css');
     $nav = $this->buildSideNav();
     $object_xscript = $xscript->getObjectTranscript();
     if (!$object_xscript) {
         $notice = id(new PHUIInfoView())->setSeverity(PHUIInfoView::SEVERITY_NOTICE)->setTitle(pht('Old Transcript'))->appendChild(phutil_tag('p', array(), pht('Details of this transcript have been garbage collected.')));
         $nav->appendChild($notice);
     } else {
         $map = HeraldAdapter::getEnabledAdapterMap($viewer);
         $object_type = $object_xscript->getType();
         if (empty($map[$object_type])) {
             // TODO: We should filter these out in the Query, but we have to load
             // the objectTranscript right now, which is potentially enormous. We
             // should denormalize the object type, or move the data into a separate
             // table, and then filter this earlier (and thus raise a better error).
             // For now, just block access so we don't violate policies.
             throw new Exception(pht('This transcript has an invalid or inaccessible adapter.'));
         }
         $this->adapter = HeraldAdapter::getAdapterForContentType($object_type);
         $filter = $this->getFilterPHIDs();
         $this->filterTranscript($xscript, $filter);
         $phids = array_merge($filter, $this->getTranscriptPHIDs($xscript));
         $phids = array_unique($phids);
         $phids = array_filter($phids);
         $handles = $this->loadViewerHandles($phids);
         $this->handles = $handles;
         if ($xscript->getDryRun()) {
             $notice = new PHUIInfoView();
             $notice->setSeverity(PHUIInfoView::SEVERITY_NOTICE);
             $notice->setTitle(pht('Dry Run'));
             $notice->appendChild(pht('This was a dry run to test Herald rules, ' . 'no actions were executed.'));
             $nav->appendChild($notice);
         }
         $warning_panel = $this->buildWarningPanel($xscript);
         $nav->appendChild($warning_panel);
         $apply_xscript_panel = $this->buildApplyTranscriptPanel($xscript);
         $nav->appendChild($apply_xscript_panel);
         $action_xscript_panel = $this->buildActionTranscriptPanel($xscript);
         $nav->appendChild($action_xscript_panel);
         $object_xscript_panel = $this->buildObjectTranscriptPanel($xscript);
         $nav->appendChild($object_xscript_panel);
     }
     $crumbs = id($this->buildApplicationCrumbs())->addTextCrumb(pht('Transcripts'), $this->getApplicationURI('/transcript/'))->addTextCrumb($xscript->getID());
     $nav->setCrumbs($crumbs);
     return $this->buildApplicationPage($nav, array('title' => pht('Transcript')));
 }
 private function buildDescriptionView(HeraldRule $rule)
 {
     $viewer = $this->getRequest()->getUser();
     $view = id(new PHUIPropertyListView())->setUser($viewer);
     $adapter = HeraldAdapter::getAdapterForContentType($rule->getContentType());
     if ($adapter) {
         $handles = $viewer->loadHandles(HeraldAdapter::getHandlePHIDs($rule));
         $rule_text = $adapter->renderRuleAsText($rule, $handles, $viewer);
         $view->addTextContent($rule_text);
         return $view;
     }
     return null;
 }
 private function buildPropertyView(HeraldRule $rule, PhabricatorActionListView $actions)
 {
     $viewer = $this->getRequest()->getUser();
     $view = id(new PHUIPropertyListView())->setUser($viewer)->setObject($rule)->setActionList($actions);
     $view->addProperty(pht('Rule Type'), idx(HeraldRuleTypeConfig::getRuleTypeMap(), $rule->getRuleType()));
     if ($rule->isPersonalRule()) {
         $view->addProperty(pht('Author'), $viewer->renderHandle($rule->getAuthorPHID()));
     }
     $adapter = HeraldAdapter::getAdapterForContentType($rule->getContentType());
     if ($adapter) {
         $view->addProperty(pht('Applies To'), idx(HeraldAdapter::getEnabledAdapterMap($viewer), $rule->getContentType()));
         if ($rule->isObjectRule()) {
             $view->addProperty(pht('Trigger Object'), $viewer->renderHandle($rule->getTriggerObjectPHID()));
         }
         $view->invokeWillRenderEvent();
         $view->addSectionHeader(pht('Rule Description'), PHUIPropertyListView::ICON_SUMMARY);
         $handles = $viewer->loadHandles(HeraldAdapter::getHandlePHIDs($rule));
         $view->addTextContent($adapter->renderRuleAsText($rule, $handles));
     }
     return $view;
 }
 public function processRequest()
 {
     $request = $this->getRequest();
     $user = $request->getUser();
     $content_type_map = HeraldAdapter::getEnabledAdapterMap($user);
     $rule_type_map = HeraldRuleTypeConfig::getRuleTypeMap();
     if ($this->id) {
         $id = $this->id;
         $rule = id(new HeraldRuleQuery())->setViewer($user)->withIDs(array($id))->requireCapabilities(array(PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT))->executeOne();
         if (!$rule) {
             return new Aphront404Response();
         }
         $cancel_uri = $this->getApplicationURI("rule/{$id}/");
     } else {
         $rule = new HeraldRule();
         $rule->setAuthorPHID($user->getPHID());
         $rule->setMustMatchAll(1);
         $content_type = $request->getStr('content_type');
         $rule->setContentType($content_type);
         $rule_type = $request->getStr('rule_type');
         if (!isset($rule_type_map[$rule_type])) {
             $rule_type = HeraldRuleTypeConfig::RULE_TYPE_PERSONAL;
         }
         $rule->setRuleType($rule_type);
         $adapter = HeraldAdapter::getAdapterForContentType($rule->getContentType());
         if (!$adapter->supportsRuleType($rule->getRuleType())) {
             throw new Exception(pht("This rule's content type does not support the selected rule " . "type."));
         }
         if ($rule->isObjectRule()) {
             $rule->setTriggerObjectPHID($request->getStr('targetPHID'));
             $object = id(new PhabricatorObjectQuery())->setViewer($user)->withPHIDs(array($rule->getTriggerObjectPHID()))->requireCapabilities(array(PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT))->executeOne();
             if (!$object) {
                 throw new Exception(pht('No valid object provided for object rule!'));
             }
             if (!$adapter->canTriggerOnObject($object)) {
                 throw new Exception(pht('Object is of wrong type for adapter!'));
             }
         }
         $cancel_uri = $this->getApplicationURI();
     }
     if ($rule->isGlobalRule()) {
         $this->requireApplicationCapability(HeraldManageGlobalRulesCapability::CAPABILITY);
     }
     $adapter = HeraldAdapter::getAdapterForContentType($rule->getContentType());
     $local_version = id(new HeraldRule())->getConfigVersion();
     if ($rule->getConfigVersion() > $local_version) {
         throw new Exception(pht('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($adapter, $rule, $request);
         if (!$errors) {
             $id = $rule->getID();
             $uri = $this->getApplicationURI("rule/{$id}/");
             return id(new AphrontRedirectResponse())->setURI($uri);
         }
     }
     $must_match_selector = $this->renderMustMatchSelector($rule);
     $repetition_selector = $this->renderRepetitionSelector($rule, $adapter);
     $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_tag('input', array('type' => 'hidden', 'name' => 'rule', 'sigil' => 'rule')))->appendChild(id(new AphrontFormTextControl())->setLabel(pht('Rule Name'))->setName('name')->setError($e_name)->setValue($rule->getName()));
     $trigger_object_control = false;
     if ($rule->isObjectRule()) {
         $trigger_object_control = id(new AphrontFormStaticControl())->setValue(pht('This rule triggers for %s.', $handles[$rule->getTriggerObjectPHID()]->renderLink()));
     }
     $form->appendChild(id(new AphrontFormMarkupControl())->setValue(pht('This %s rule triggers for %s.', phutil_tag('strong', array(), $rule_type_name), phutil_tag('strong', array(), $content_type_name))))->appendChild($trigger_object_control)->appendChild(id(new PHUIFormInsetView())->setTitle(pht('Conditions'))->setRightButton(javelin_tag('a', array('href' => '#', 'class' => 'button green', 'sigil' => 'create-condition', 'mustcapture' => true), pht('New Condition')))->setDescription(pht('When %s these conditions are met:', $must_match_selector))->setContent(javelin_tag('table', array('sigil' => 'rule-conditions', 'class' => 'herald-condition-table'), '')))->appendChild(id(new PHUIFormInsetView())->setTitle(pht('Action'))->setRightButton(javelin_tag('a', array('href' => '#', 'class' => 'button green', 'sigil' => 'create-action', 'mustcapture' => true), pht('New Action')))->setDescription(pht('Take these actions %s this rule matches:', $repetition_selector))->setContent(javelin_tag('table', array('sigil' => 'rule-actions', 'class' => 'herald-action-table'), '')))->appendChild(id(new AphrontFormSubmitControl())->setValue(pht('Save Rule'))->addCancelButton($cancel_uri));
     $this->setupEditorBehavior($rule, $handles, $adapter);
     $title = $rule->getID() ? pht('Edit Herald Rule') : pht('Create Herald Rule');
     $form_box = id(new PHUIObjectBoxView())->setHeaderText($title)->setFormErrors($errors)->setForm($form);
     $crumbs = $this->buildApplicationCrumbs()->addTextCrumb($title);
     return $this->buildApplicationPage(array($crumbs, $form_box), array('title' => pht('Edit Rule')));
 }
 private function renderRuleTypeControl(array $rule_type_map, $e_rule)
 {
     $request = $this->getRequest();
     // Reorder array to put less powerful rules first.
     $rule_type_map = array_select_keys($rule_type_map, array(HeraldRuleTypeConfig::RULE_TYPE_PERSONAL, HeraldRuleTypeConfig::RULE_TYPE_OBJECT, HeraldRuleTypeConfig::RULE_TYPE_GLOBAL)) + $rule_type_map;
     list($can_global, $global_link) = $this->explainApplicationCapability(HeraldManageGlobalRulesCapability::CAPABILITY, pht('You have permission to create and manage global rules.'), pht('You do not have permission to create or manage global rules.'));
     $captions = array(HeraldRuleTypeConfig::RULE_TYPE_PERSONAL => pht('Personal rules notify you about events. You own them, but they can ' . 'only affect you. Personal rules only trigger for objects you have ' . 'permission to see.'), HeraldRuleTypeConfig::RULE_TYPE_OBJECT => pht('Object rules notify anyone about events. They are bound to an ' . 'object (like a repository) and can only act on that object. You ' . 'must be able to edit an object to create object rules for it. ' . 'Other users who can edit the object can edit its rules.'), HeraldRuleTypeConfig::RULE_TYPE_GLOBAL => array(pht('Global rules notify anyone about events. Global rules can ' . 'bypass access control policies and act on any object.'), $global_link));
     $radio = id(new AphrontFormRadioButtonControl())->setLabel(pht('Rule Type'))->setName('rule_type')->setValue($request->getStr('rule_type'))->setError($e_rule);
     $adapter = HeraldAdapter::getAdapterForContentType($request->getStr('content_type'));
     foreach ($rule_type_map as $value => $name) {
         $caption = idx($captions, $value);
         $disabled = $value == HeraldRuleTypeConfig::RULE_TYPE_GLOBAL && !$can_global;
         if (!$adapter->supportsRuleType($value)) {
             $disabled = true;
             $caption = array($caption, "\n\n", phutil_tag('em', array(), pht('This rule type is not supported by the selected content type.')));
         }
         $radio->addButton($value, $name, phutil_escape_html_newlines($caption), $disabled ? 'disabled' : null, $disabled);
     }
     return $radio;
 }