Changeset View
Changeset View
Standalone View
Standalone View
src/applications/herald/adapter/HeraldAdapter.php
Show All 24 Lines | abstract class HeraldAdapter extends Phobject { | ||||
const CONDITION_NOT_BIT = '!bit'; | const CONDITION_NOT_BIT = '!bit'; | ||||
const CONDITION_IS_TRUE = 'true'; | const CONDITION_IS_TRUE = 'true'; | ||||
const CONDITION_IS_FALSE = 'false'; | const CONDITION_IS_FALSE = 'false'; | ||||
const ACTION_ADD_CC = 'addcc'; | const ACTION_ADD_CC = 'addcc'; | ||||
const ACTION_REMOVE_CC = 'remcc'; | const ACTION_REMOVE_CC = 'remcc'; | ||||
const ACTION_EMAIL = 'email'; | const ACTION_EMAIL = 'email'; | ||||
const ACTION_AUDIT = 'audit'; | const ACTION_AUDIT = 'audit'; | ||||
const ACTION_FLAG = 'flag'; | |||||
const ACTION_ASSIGN_TASK = 'assigntask'; | const ACTION_ASSIGN_TASK = 'assigntask'; | ||||
const ACTION_ADD_PROJECTS = 'addprojects'; | const ACTION_ADD_PROJECTS = 'addprojects'; | ||||
const ACTION_REMOVE_PROJECTS = 'removeprojects'; | const ACTION_REMOVE_PROJECTS = 'removeprojects'; | ||||
const ACTION_ADD_REVIEWERS = 'addreviewers'; | const ACTION_ADD_REVIEWERS = 'addreviewers'; | ||||
const ACTION_ADD_BLOCKING_REVIEWERS = 'addblockingreviewers'; | const ACTION_ADD_BLOCKING_REVIEWERS = 'addblockingreviewers'; | ||||
const ACTION_APPLY_BUILD_PLANS = 'applybuildplans'; | const ACTION_APPLY_BUILD_PLANS = 'applybuildplans'; | ||||
const ACTION_BLOCK = 'block'; | const ACTION_BLOCK = 'block'; | ||||
const ACTION_REQUIRE_SIGNATURE = 'signature'; | const ACTION_REQUIRE_SIGNATURE = 'signature'; | ||||
▲ Show 20 Lines • Show All 623 Lines • ▼ Show 20 Lines | foreach ($actions as $key => $action) { | ||||
if (!$action->supportsRuleType($rule_type)) { | if (!$action->supportsRuleType($rule_type)) { | ||||
unset($actions[$key]); | unset($actions[$key]); | ||||
} | } | ||||
} | } | ||||
return $actions; | return $actions; | ||||
} | } | ||||
private function getActionImplementation($key) { | public function getActionImplementation($key) { | ||||
return idx($this->getActionImplementationMap(), $key); | return idx($this->getActionImplementationMap(), $key); | ||||
} | } | ||||
public function getActionKeys() { | public function getActionKeys() { | ||||
return array_keys($this->getActionImplementationMap()); | return array_keys($this->getActionImplementationMap()); | ||||
} | } | ||||
public function getActionGroupKey($action_key) { | public function getActionGroupKey($action_key) { | ||||
▲ Show 20 Lines • Show All 41 Lines • ▼ Show 20 Lines | public function getActionNameMap($rule_type) { | ||||
switch ($rule_type) { | switch ($rule_type) { | ||||
case HeraldRuleTypeConfig::RULE_TYPE_GLOBAL: | case HeraldRuleTypeConfig::RULE_TYPE_GLOBAL: | ||||
case HeraldRuleTypeConfig::RULE_TYPE_OBJECT: | case HeraldRuleTypeConfig::RULE_TYPE_OBJECT: | ||||
$standard = array( | $standard = array( | ||||
self::ACTION_ADD_CC => pht('Add Subscribers'), | self::ACTION_ADD_CC => pht('Add Subscribers'), | ||||
self::ACTION_REMOVE_CC => pht('Remove Subscribers'), | self::ACTION_REMOVE_CC => pht('Remove Subscribers'), | ||||
self::ACTION_EMAIL => pht('Send an email to'), | self::ACTION_EMAIL => pht('Send an email to'), | ||||
self::ACTION_AUDIT => pht('Trigger an Audit by'), | self::ACTION_AUDIT => pht('Trigger an Audit by'), | ||||
self::ACTION_FLAG => pht('Mark with flag'), | |||||
self::ACTION_ASSIGN_TASK => pht('Assign task to'), | self::ACTION_ASSIGN_TASK => pht('Assign task to'), | ||||
self::ACTION_ADD_PROJECTS => pht('Add projects'), | self::ACTION_ADD_PROJECTS => pht('Add projects'), | ||||
self::ACTION_REMOVE_PROJECTS => pht('Remove projects'), | self::ACTION_REMOVE_PROJECTS => pht('Remove projects'), | ||||
self::ACTION_ADD_REVIEWERS => pht('Add reviewers'), | self::ACTION_ADD_REVIEWERS => pht('Add reviewers'), | ||||
self::ACTION_ADD_BLOCKING_REVIEWERS => pht('Add blocking reviewers'), | self::ACTION_ADD_BLOCKING_REVIEWERS => pht('Add blocking reviewers'), | ||||
self::ACTION_APPLY_BUILD_PLANS => pht('Run build plans'), | self::ACTION_APPLY_BUILD_PLANS => pht('Run build plans'), | ||||
self::ACTION_REQUIRE_SIGNATURE => pht('Require legal signatures'), | self::ACTION_REQUIRE_SIGNATURE => pht('Require legal signatures'), | ||||
self::ACTION_BLOCK => pht('Block change with message'), | self::ACTION_BLOCK => pht('Block change with message'), | ||||
); | ); | ||||
break; | break; | ||||
case HeraldRuleTypeConfig::RULE_TYPE_PERSONAL: | case HeraldRuleTypeConfig::RULE_TYPE_PERSONAL: | ||||
$standard = array( | $standard = array( | ||||
self::ACTION_ADD_CC => pht('Add me as a subscriber'), | self::ACTION_ADD_CC => pht('Add me as a subscriber'), | ||||
self::ACTION_REMOVE_CC => pht('Remove me as a subscriber'), | self::ACTION_REMOVE_CC => pht('Remove me as a subscriber'), | ||||
self::ACTION_EMAIL => pht('Send me an email'), | self::ACTION_EMAIL => pht('Send me an email'), | ||||
self::ACTION_AUDIT => pht('Trigger an Audit by me'), | self::ACTION_AUDIT => pht('Trigger an Audit by me'), | ||||
self::ACTION_FLAG => pht('Mark with flag'), | |||||
self::ACTION_ASSIGN_TASK => pht('Assign task to me'), | self::ACTION_ASSIGN_TASK => pht('Assign task to me'), | ||||
self::ACTION_ADD_REVIEWERS => pht('Add me as a reviewer'), | self::ACTION_ADD_REVIEWERS => pht('Add me as a reviewer'), | ||||
self::ACTION_ADD_BLOCKING_REVIEWERS => | self::ACTION_ADD_BLOCKING_REVIEWERS => | ||||
pht('Add me as a blocking reviewer'), | pht('Add me as a blocking reviewer'), | ||||
); | ); | ||||
break; | break; | ||||
default: | default: | ||||
throw new Exception(pht("Unknown rule type '%s'!", $rule_type)); | throw new Exception(pht("Unknown rule type '%s'!", $rule_type)); | ||||
Show All 36 Lines | if ($rule_type == HeraldRuleTypeConfig::RULE_TYPE_PERSONAL) { | ||||
case self::ACTION_REMOVE_CC: | case self::ACTION_REMOVE_CC: | ||||
case self::ACTION_AUDIT: | case self::ACTION_AUDIT: | ||||
case self::ACTION_ASSIGN_TASK: | case self::ACTION_ASSIGN_TASK: | ||||
case self::ACTION_ADD_REVIEWERS: | case self::ACTION_ADD_REVIEWERS: | ||||
case self::ACTION_ADD_BLOCKING_REVIEWERS: | case self::ACTION_ADD_BLOCKING_REVIEWERS: | ||||
// For personal rules, force these actions to target the rule owner. | // For personal rules, force these actions to target the rule owner. | ||||
$target = array($author_phid); | $target = array($author_phid); | ||||
break; | break; | ||||
case self::ACTION_FLAG: | |||||
// Make sure flag color is valid; set to blue if not. | |||||
$color_map = PhabricatorFlagColor::getColorNameMap(); | |||||
if (empty($color_map[$target])) { | |||||
$target = PhabricatorFlagColor::COLOR_BLUE; | |||||
} | |||||
break; | |||||
case self::ACTION_BLOCK: | case self::ACTION_BLOCK: | ||||
break; | break; | ||||
default: | default: | ||||
throw new HeraldInvalidActionException( | throw new HeraldInvalidActionException( | ||||
pht( | pht( | ||||
'Unrecognized action type "%s"!', | 'Unrecognized action type "%s"!', | ||||
$action->getAction())); | $action->getAction())); | ||||
} | } | ||||
Show All 25 Lines | if ($is_personal) { | ||||
case self::ACTION_ADD_CC: | case self::ACTION_ADD_CC: | ||||
case self::ACTION_REMOVE_CC: | case self::ACTION_REMOVE_CC: | ||||
case self::ACTION_EMAIL: | case self::ACTION_EMAIL: | ||||
case self::ACTION_AUDIT: | case self::ACTION_AUDIT: | ||||
case self::ACTION_ASSIGN_TASK: | case self::ACTION_ASSIGN_TASK: | ||||
case self::ACTION_ADD_REVIEWERS: | case self::ACTION_ADD_REVIEWERS: | ||||
case self::ACTION_ADD_BLOCKING_REVIEWERS: | case self::ACTION_ADD_BLOCKING_REVIEWERS: | ||||
return new HeraldEmptyFieldValue(); | return new HeraldEmptyFieldValue(); | ||||
case self::ACTION_FLAG: | |||||
return $this->buildFlagColorFieldValue(); | |||||
case self::ACTION_ADD_PROJECTS: | case self::ACTION_ADD_PROJECTS: | ||||
case self::ACTION_REMOVE_PROJECTS: | case self::ACTION_REMOVE_PROJECTS: | ||||
return $this->buildTokenizerFieldValue( | return $this->buildTokenizerFieldValue( | ||||
new PhabricatorProjectDatasource()); | new PhabricatorProjectDatasource()); | ||||
} | } | ||||
} else { | } else { | ||||
switch ($action) { | switch ($action) { | ||||
case self::ACTION_ADD_CC: | case self::ACTION_ADD_CC: | ||||
case self::ACTION_REMOVE_CC: | case self::ACTION_REMOVE_CC: | ||||
case self::ACTION_EMAIL: | case self::ACTION_EMAIL: | ||||
return $this->buildTokenizerFieldValue( | return $this->buildTokenizerFieldValue( | ||||
new PhabricatorMetaMTAMailableDatasource()); | new PhabricatorMetaMTAMailableDatasource()); | ||||
case self::ACTION_ADD_PROJECTS: | case self::ACTION_ADD_PROJECTS: | ||||
case self::ACTION_REMOVE_PROJECTS: | case self::ACTION_REMOVE_PROJECTS: | ||||
return $this->buildTokenizerFieldValue( | return $this->buildTokenizerFieldValue( | ||||
new PhabricatorProjectDatasource()); | new PhabricatorProjectDatasource()); | ||||
case self::ACTION_FLAG: | |||||
return $this->buildFlagColorFieldValue(); | |||||
case self::ACTION_ASSIGN_TASK: | case self::ACTION_ASSIGN_TASK: | ||||
return $this->buildTokenizerFieldValue( | return $this->buildTokenizerFieldValue( | ||||
new PhabricatorPeopleDatasource()); | new PhabricatorPeopleDatasource()); | ||||
case self::ACTION_AUDIT: | case self::ACTION_AUDIT: | ||||
case self::ACTION_ADD_REVIEWERS: | case self::ACTION_ADD_REVIEWERS: | ||||
case self::ACTION_ADD_BLOCKING_REVIEWERS: | case self::ACTION_ADD_BLOCKING_REVIEWERS: | ||||
return $this->buildTokenizerFieldValue( | return $this->buildTokenizerFieldValue( | ||||
new PhabricatorProjectOrUserDatasource()); | new PhabricatorProjectOrUserDatasource()); | ||||
Show All 11 Lines | public function getValueTypeForAction($action, $rule_type) { | ||||
$custom_action = idx($this->getCustomActions(), $action); | $custom_action = idx($this->getCustomActions(), $action); | ||||
if ($custom_action !== null) { | if ($custom_action !== null) { | ||||
return $custom_action->getActionType(); | return $custom_action->getActionType(); | ||||
} | } | ||||
throw new Exception(pht("Unknown or invalid action '%s'.", $action)); | throw new Exception(pht("Unknown or invalid action '%s'.", $action)); | ||||
} | } | ||||
private function buildFlagColorFieldValue() { | |||||
return id(new HeraldSelectFieldValue()) | |||||
->setKey('flag.color') | |||||
->setOptions(PhabricatorFlagColor::getColorNameMap()) | |||||
->setDefault(PhabricatorFlagColor::COLOR_BLUE); | |||||
} | |||||
private function buildTokenizerFieldValue( | private function buildTokenizerFieldValue( | ||||
PhabricatorTypeaheadDatasource $datasource) { | PhabricatorTypeaheadDatasource $datasource) { | ||||
$key = 'action.'.get_class($datasource); | $key = 'action.'.get_class($datasource); | ||||
return id(new HeraldTokenizerFieldValue()) | return id(new HeraldTokenizerFieldValue()) | ||||
->setKey($key) | ->setKey($key) | ||||
->setDatasource($datasource); | ->setDatasource($datasource); | ||||
▲ Show 20 Lines • Show All 135 Lines • ▼ Show 20 Lines | public function renderRuleAsText( | ||||
foreach ($rule->getActions() as $action) { | foreach ($rule->getActions() as $action) { | ||||
$action_list[] = phutil_tag( | $action_list[] = phutil_tag( | ||||
'div', | 'div', | ||||
array( | array( | ||||
'class' => 'herald-list-item', | 'class' => 'herald-list-item', | ||||
), | ), | ||||
array( | array( | ||||
$icon, | $icon, | ||||
$this->renderActionAsText($action, $handles), | $this->renderActionAsText($viewer, $action, $handles), | ||||
)); | )); | ||||
} | } | ||||
return array( | return array( | ||||
$match_title, | $match_title, | ||||
$match_list, | $match_list, | ||||
$action_title, | $action_title, | ||||
$action_list, | $action_list, | ||||
Show All 15 Lines | private function renderConditionAsText( | ||||
$condition_name = idx($this->getConditionNameMap(), $condition_type); | $condition_name = idx($this->getConditionNameMap(), $condition_type); | ||||
$value = $this->renderConditionValueAsText($condition, $handles, $viewer); | $value = $this->renderConditionValueAsText($condition, $handles, $viewer); | ||||
return hsprintf(' %s %s %s', $field_name, $condition_name, $value); | return hsprintf(' %s %s %s', $field_name, $condition_name, $value); | ||||
} | } | ||||
private function renderActionAsText( | private function renderActionAsText( | ||||
PhabricatorUser $viewer, | |||||
HeraldActionRecord $action, | HeraldActionRecord $action, | ||||
PhabricatorHandleList $handles) { | PhabricatorHandleList $handles) { | ||||
$impl = $this->getActionImplementation($action->getAction()); | |||||
if ($impl) { | |||||
$value = $action->getTarget(); | |||||
return $impl->renderActionDescription($viewer, $value); | |||||
} | |||||
$rule_global = HeraldRuleTypeConfig::RULE_TYPE_GLOBAL; | $rule_global = HeraldRuleTypeConfig::RULE_TYPE_GLOBAL; | ||||
$action_type = $action->getAction(); | $action_type = $action->getAction(); | ||||
$default = pht('(Unknown Action "%s") equals', $action_type); | $default = pht('(Unknown Action "%s") equals', $action_type); | ||||
$action_name = idx( | $action_name = idx( | ||||
$this->getActionNameMap($rule_global), | $this->getActionNameMap($rule_global), | ||||
Show All 17 Lines | return $field->renderConditionValue( | ||||
$condition->getFieldCondition(), | $condition->getFieldCondition(), | ||||
$condition->getValue()); | $condition->getValue()); | ||||
} | } | ||||
private function renderActionTargetAsText( | private function renderActionTargetAsText( | ||||
HeraldActionRecord $action, | HeraldActionRecord $action, | ||||
PhabricatorHandleList $handles) { | PhabricatorHandleList $handles) { | ||||
// TODO: This should be driven through HeraldAction. | |||||
$target = $action->getTarget(); | $target = $action->getTarget(); | ||||
if (!is_array($target)) { | if (!is_array($target)) { | ||||
$target = array($target); | $target = array($target); | ||||
} | } | ||||
foreach ($target as $index => $val) { | foreach ($target as $index => $val) { | ||||
switch ($action->getAction()) { | switch ($action->getAction()) { | ||||
case self::ACTION_FLAG: | |||||
$target[$index] = PhabricatorFlagColor::getColorName($val); | |||||
break; | |||||
default: | default: | ||||
$handle = $handles->getHandleIfExists($val); | $handle = $handles->getHandleIfExists($val); | ||||
if ($handle) { | if ($handle) { | ||||
$target[$index] = $handle->renderLink(); | $target[$index] = $handle->renderLink(); | ||||
} | } | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
▲ Show 20 Lines • Show All 79 Lines • ▼ Show 20 Lines | protected function applyStandardEffect(HeraldEffect $effect) { | ||||
switch ($action) { | switch ($action) { | ||||
case self::ACTION_ADD_PROJECTS: | case self::ACTION_ADD_PROJECTS: | ||||
case self::ACTION_REMOVE_PROJECTS: | case self::ACTION_REMOVE_PROJECTS: | ||||
return $this->applyProjectsEffect($effect); | return $this->applyProjectsEffect($effect); | ||||
case self::ACTION_ADD_CC: | case self::ACTION_ADD_CC: | ||||
case self::ACTION_REMOVE_CC: | case self::ACTION_REMOVE_CC: | ||||
return $this->applySubscribersEffect($effect); | return $this->applySubscribersEffect($effect); | ||||
case self::ACTION_FLAG: | |||||
return $this->applyFlagEffect($effect); | |||||
case self::ACTION_EMAIL: | case self::ACTION_EMAIL: | ||||
return $this->applyEmailEffect($effect); | return $this->applyEmailEffect($effect); | ||||
default: | default: | ||||
break; | break; | ||||
} | } | ||||
$result = $this->handleCustomHeraldEffect($effect); | $result = $this->handleCustomHeraldEffect($effect); | ||||
▲ Show 20 Lines • Show All 124 Lines • ▼ Show 20 Lines | if ($is_add) { | ||||
$message = pht('Subscribed targets.'); | $message = pht('Subscribed targets.'); | ||||
} else { | } else { | ||||
$message = pht('Unsubscribed targets.'); | $message = pht('Unsubscribed targets.'); | ||||
} | } | ||||
return new HeraldApplyTranscript($effect, true, $message); | return new HeraldApplyTranscript($effect, true, $message); | ||||
} | } | ||||
/** | |||||
* @task apply | |||||
*/ | |||||
private function applyFlagEffect(HeraldEffect $effect) { | |||||
$phid = $this->getPHID(); | |||||
$color = $effect->getTarget(); | |||||
$rule = $effect->getRule(); | |||||
$user = $rule->getAuthor(); | |||||
$flag = PhabricatorFlagQuery::loadUserFlag($user, $phid); | |||||
if ($flag) { | |||||
return new HeraldApplyTranscript( | |||||
$effect, | |||||
false, | |||||
pht('Object already flagged.')); | |||||
} | |||||
$handle = id(new PhabricatorHandleQuery()) | |||||
->setViewer($user) | |||||
->withPHIDs(array($phid)) | |||||
->executeOne(); | |||||
$flag = new PhabricatorFlag(); | |||||
$flag->setOwnerPHID($user->getPHID()); | |||||
$flag->setType($handle->getType()); | |||||
$flag->setObjectPHID($handle->getPHID()); | |||||
// TOOD: Should really be transcript PHID, but it doesn't exist yet. | |||||
$flag->setReasonPHID($user->getPHID()); | |||||
$flag->setColor($color); | |||||
$flag->setNote( | |||||
pht('Flagged by Herald Rule "%s".', $rule->getName())); | |||||
$flag->save(); | |||||
return new HeraldApplyTranscript( | |||||
$effect, | |||||
true, | |||||
pht('Added flag.')); | |||||
} | |||||
/** | /** | ||||
* @task apply | * @task apply | ||||
*/ | */ | ||||
private function applyEmailEffect(HeraldEffect $effect) { | private function applyEmailEffect(HeraldEffect $effect) { | ||||
foreach ($effect->getTarget() as $phid) { | foreach ($effect->getTarget() as $phid) { | ||||
$this->emailPHIDs[$phid] = $phid; | $this->emailPHIDs[$phid] = $phid; | ||||
// If this is a personal rule, we'll force delivery of a real email. This | // If this is a personal rule, we'll force delivery of a real email. This | ||||
Show All 16 Lines |