diff --git a/src/applications/herald/controller/rule/HeraldRuleController.php b/src/applications/herald/controller/rule/HeraldRuleController.php index b2d0a73440..cb0c997513 100644 --- a/src/applications/herald/controller/rule/HeraldRuleController.php +++ b/src/applications/herald/controller/rule/HeraldRuleController.php @@ -71,165 +71,15 @@ class HeraldRuleController extends HeraldController { $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); + list($e_name, $errors) = $this->saveRule($rule, $request); 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; - } + $uri = '/herald/view/'.$rule->getContentType().'/'; + return id(new AphrontRedirectResponse()) + ->setURI($uri); } } - 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'); @@ -238,72 +88,10 @@ class HeraldRuleController extends HeraldController { $error_view = null; } - $options = array( - 'all' => 'all of', - 'any' => 'any of', - ); + $must_match_selector = $this->getMustMatchSelector($rule); + $repetition_selector = $this->getRepetitionSelector($rule); - $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 = - ''; - - 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 = - ''; - } + $handles = $this->loadHandles($rule); require_celerity_resource('herald-css'); @@ -351,7 +139,7 @@ class HeraldRuleController extends HeraldController { ), 'Create New Condition'). ''. - '
When '.$must_match.' these conditions are met:
'. + 'When '.$must_match_selector.' these conditions are met:
'. ''. javelin_render_tag( 'table', @@ -392,6 +180,157 @@ class HeraldRuleController extends HeraldController { ->setValue('Save Rule') ->addCancelButton('/herald/view/'.$rule->getContentType().'/')); + $this->setupEditorBehavior($rule, $handles); + + $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', + )); + } + + private function saveRule($rule, $request) { + $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) + ); + + $e_name = true; + $errors = array(); + + 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(); + + } catch (AphrontQueryDuplicateKeyException $ex) { + $e_name = "Not Unique"; + $errors[] = "Rule name is not unique. Choose a unique name."; + } + } + + return array($e_name, $errors); + } + + private function setupEditorBehavior($rule, $handles) { $serial_conditions = array( array('default', 'default', ''), ); @@ -474,27 +413,111 @@ class HeraldRuleController extends HeraldController { 'herald-rule-editor', array( 'root' => 'herald-rule-edit-form', - 'conditions' => (object) $serial_conditions, - 'actions' => (object) $serial_actions, + '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); + private function loadHandles($rule) { + $phids = array(); + $phids[] = $rule->getAuthorPHID(); - return $this->buildStandardPageResponse( - array( - $error_view, - $panel, - ), - array( - 'title' => 'Edit Rule', - )); + 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(); + return $handles; + } + + private function getMustMatchSelector($rule) { + $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 = + ''; + return $must_match; + } + + private function getRepetitionSelector($rule) { + // Make the selector for choosing how often this rule should be repeated + $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 + ); + return $repetition_selector; + } else if (count($repetition_options) == 1) { + // if there's only 1 option, just pick it for the user + $repetition_selector = reset($repetition_options); + return $repetition_selector; + } 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 = + ''; + return $repetition_selector; + } } protected function buildTokenizerTemplates() {