Changeset View
Changeset View
Standalone View
Standalone View
src/applications/herald/adapter/HeraldAdapter.php
Show All 23 Lines | abstract class HeraldAdapter extends Phobject { | ||||
const CONDITION_HAS_BIT = 'bit'; | const CONDITION_HAS_BIT = 'bit'; | ||||
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_NOTHING = 'nothing'; | |||||
const ACTION_AUDIT = 'audit'; | const ACTION_AUDIT = 'audit'; | ||||
const ACTION_FLAG = 'flag'; | 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'; | ||||
private $contentSource; | private $contentSource; | ||||
private $isNewObject; | private $isNewObject; | ||||
private $applicationEmail; | private $applicationEmail; | ||||
private $customActions = null; | private $customActions = null; | ||||
private $queuedTransactions = array(); | private $queuedTransactions = array(); | ||||
private $emailPHIDs = array(); | private $emailPHIDs = array(); | ||||
private $forcedEmailPHIDs = array(); | private $forcedEmailPHIDs = array(); | ||||
private $unsubscribedPHIDs; | private $unsubscribedPHIDs; | ||||
private $fieldMap; | private $fieldMap; | ||||
private $actionMap; | |||||
public function getEmailPHIDs() { | public function getEmailPHIDs() { | ||||
return array_values($this->emailPHIDs); | return array_values($this->emailPHIDs); | ||||
} | } | ||||
public function getForcedEmailPHIDs() { | public function getForcedEmailPHIDs() { | ||||
return array_values($this->forcedEmailPHIDs); | return array_values($this->forcedEmailPHIDs); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 549 Lines • ▼ Show 20 Lines | switch ($condition_type) { | ||||
'Unknown condition "%s"!', | 'Unknown condition "%s"!', | ||||
$condition_type)); | $condition_type)); | ||||
} | } | ||||
} | } | ||||
/* -( Actions )------------------------------------------------------------ */ | /* -( Actions )------------------------------------------------------------ */ | ||||
private function getActionImplementationMap() { | |||||
if ($this->actionMap === null) { | |||||
// We can't use PhutilClassMapQuery here because action expansion | |||||
// depends on the adapter and object. | |||||
$object = $this->getObject(); | |||||
$map = array(); | |||||
$all = HeraldAction::getAllActions(); | |||||
foreach ($all as $key => $action) { | |||||
$action = id(clone $action)->setAdapter($this); | |||||
if (!$action->supportsObject($object)) { | |||||
continue; | |||||
} | |||||
$subactions = $action->getActionsForObject($object); | |||||
foreach ($subactions as $subkey => $subaction) { | |||||
if (isset($map[$subkey])) { | |||||
throw new Exception( | |||||
pht( | |||||
'Two HeraldActions (of classes "%s" and "%s") have the same '. | |||||
'action key ("%s") after expansion for an object of class '. | |||||
'"%s" inside adapter "%s". Each action must have a unique '. | |||||
'action key.', | |||||
get_class($subaction), | |||||
get_class($map[$subkey]), | |||||
$subkey, | |||||
get_class($object), | |||||
get_class($this))); | |||||
} | |||||
$subaction = id(clone $subaction)->setAdapter($this); | |||||
$map[$subkey] = $subaction; | |||||
} | |||||
} | |||||
$this->actionMap = $map; | |||||
} | |||||
return $this->actionMap; | |||||
} | |||||
private function getActionsForRuleType($rule_type) { | |||||
$actions = $this->getActionImplementationMap(); | |||||
foreach ($actions as $key => $action) { | |||||
if (!$action->supportsRuleType($rule_type)) { | |||||
unset($actions[$key]); | |||||
} | |||||
} | |||||
return $actions; | |||||
} | |||||
private function getActionImplementation($key) { | |||||
return idx($this->getActionImplementationMap(), $key); | |||||
} | |||||
public function getActionKeys() { | |||||
return array_keys($this->getActionImplementationMap()); | |||||
} | |||||
public function getActionGroupKey($action_key) { | |||||
$action = $this->getActionImplementation($action_key); | |||||
if (!$action) { | |||||
return null; | |||||
} | |||||
return $action->getActionGroupKey(); | |||||
} | |||||
public function getCustomActionsForRuleType($rule_type) { | public function getCustomActionsForRuleType($rule_type) { | ||||
$results = array(); | $results = array(); | ||||
foreach ($this->getCustomActions() as $custom_action) { | foreach ($this->getCustomActions() as $custom_action) { | ||||
if ($custom_action->appliesToRuleType($rule_type)) { | if ($custom_action->appliesToRuleType($rule_type)) { | ||||
$results[] = $custom_action; | $results[] = $custom_action; | ||||
} | } | ||||
} | } | ||||
return $results; | return $results; | ||||
Show All 9 Lines | public function getActions($rule_type) { | ||||
if (($object instanceof PhabricatorProjectInterface)) { | if (($object instanceof PhabricatorProjectInterface)) { | ||||
if ($rule_type == HeraldRuleTypeConfig::RULE_TYPE_GLOBAL) { | if ($rule_type == HeraldRuleTypeConfig::RULE_TYPE_GLOBAL) { | ||||
$actions[] = self::ACTION_ADD_PROJECTS; | $actions[] = self::ACTION_ADD_PROJECTS; | ||||
$actions[] = self::ACTION_REMOVE_PROJECTS; | $actions[] = self::ACTION_REMOVE_PROJECTS; | ||||
} | } | ||||
} | } | ||||
foreach ($this->getActionsForRuleType($rule_type) as $key => $action) { | |||||
$actions[] = $key; | |||||
} | |||||
return $actions; | return $actions; | ||||
} | } | ||||
public function getActionNameMap($rule_type) { | 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_NOTHING => pht('Do nothing'), | |||||
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_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_NOTHING => pht('Do nothing'), | |||||
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_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)); | ||||
} | } | ||||
$custom_actions = $this->getCustomActionsForRuleType($rule_type); | $custom_actions = $this->getCustomActionsForRuleType($rule_type); | ||||
$standard += mpull($custom_actions, 'getActionName', 'getActionKey'); | $standard += mpull($custom_actions, 'getActionName', 'getActionKey'); | ||||
foreach ($this->getActionsForRuleType($rule_type) as $key => $action) { | |||||
$standard[$key] = $action->getHeraldActionName(); | |||||
} | |||||
return $standard; | return $standard; | ||||
} | } | ||||
public function willSaveAction( | public function willSaveAction( | ||||
HeraldRule $rule, | HeraldRule $rule, | ||||
HeraldActionRecord $action) { | HeraldActionRecord $action) { | ||||
$impl = $this->getActionImplementation($action->getAction()); | |||||
if ($impl) { | |||||
$target = $action->getTarget(); | |||||
$target = $impl->willSaveActionValue($target); | |||||
$action->setTarget($target); | |||||
return; | |||||
} | |||||
$target = $action->getTarget(); | $target = $action->getTarget(); | ||||
if (is_array($target)) { | if (is_array($target)) { | ||||
$target = array_keys($target); | $target = array_keys($target); | ||||
} | } | ||||
$author_phid = $rule->getAuthorPHID(); | $author_phid = $rule->getAuthorPHID(); | ||||
$rule_type = $rule->getRuleType(); | $rule_type = $rule->getRuleType(); | ||||
Show All 12 Lines | if ($rule_type == HeraldRuleTypeConfig::RULE_TYPE_PERSONAL) { | ||||
case self::ACTION_FLAG: | case self::ACTION_FLAG: | ||||
// Make sure flag color is valid; set to blue if not. | // Make sure flag color is valid; set to blue if not. | ||||
$color_map = PhabricatorFlagColor::getColorNameMap(); | $color_map = PhabricatorFlagColor::getColorNameMap(); | ||||
if (empty($color_map[$target])) { | if (empty($color_map[$target])) { | ||||
$target = PhabricatorFlagColor::COLOR_BLUE; | $target = PhabricatorFlagColor::COLOR_BLUE; | ||||
} | } | ||||
break; | break; | ||||
case self::ACTION_BLOCK: | case self::ACTION_BLOCK: | ||||
case self::ACTION_NOTHING: | |||||
break; | break; | ||||
default: | default: | ||||
throw new HeraldInvalidActionException( | throw new HeraldInvalidActionException( | ||||
pht( | pht( | ||||
'Unrecognized action type "%s"!', | 'Unrecognized action type "%s"!', | ||||
$action->getAction())); | $action->getAction())); | ||||
} | } | ||||
} | } | ||||
$action->setTarget($target); | $action->setTarget($target); | ||||
} | } | ||||
/* -( Values )------------------------------------------------------------- */ | /* -( Values )------------------------------------------------------------- */ | ||||
public function getValueTypeForFieldAndCondition($field, $condition) { | public function getValueTypeForFieldAndCondition($field, $condition) { | ||||
return $this->requireFieldImplementation($field) | return $this->requireFieldImplementation($field) | ||||
->getHeraldFieldValueType($condition); | ->getHeraldFieldValueType($condition); | ||||
} | } | ||||
public function getValueTypeForAction($action, $rule_type) { | public function getValueTypeForAction($action, $rule_type) { | ||||
$impl = $this->getActionImplementation($action); | |||||
if ($impl) { | |||||
return $impl->getHeraldActionValueType(); | |||||
} | |||||
$is_personal = ($rule_type == HeraldRuleTypeConfig::RULE_TYPE_PERSONAL); | $is_personal = ($rule_type == HeraldRuleTypeConfig::RULE_TYPE_PERSONAL); | ||||
if ($is_personal) { | if ($is_personal) { | ||||
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: | ||||
case self::ACTION_NOTHING: | |||||
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: | case self::ACTION_FLAG: | ||||
return $this->buildFlagColorFieldValue(); | 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_NOTHING: | |||||
return new HeraldEmptyFieldValue(); | |||||
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: | case self::ACTION_FLAG: | ||||
return $this->buildFlagColorFieldValue(); | return $this->buildFlagColorFieldValue(); | ||||
case self::ACTION_ASSIGN_TASK: | case self::ACTION_ASSIGN_TASK: | ||||
return $this->buildTokenizerFieldValue( | return $this->buildTokenizerFieldValue( | ||||
▲ Show 20 Lines • Show All 319 Lines • ▼ Show 20 Lines | /* -( Applying Effects )--------------------------------------------------- */ | ||||
/** | /** | ||||
* @task apply | * @task apply | ||||
*/ | */ | ||||
protected function applyStandardEffect(HeraldEffect $effect) { | protected function applyStandardEffect(HeraldEffect $effect) { | ||||
$action = $effect->getAction(); | $action = $effect->getAction(); | ||||
$impl = $this->getActionImplementation($action); | |||||
if ($impl) { | |||||
$impl->applyEffect($this->getObject(), $effect); | |||||
return $impl->getApplyTranscript($effect); | |||||
} | |||||
$rule_type = $effect->getRule()->getRuleType(); | $rule_type = $effect->getRule()->getRuleType(); | ||||
$supported = $this->getActions($rule_type); | $supported = $this->getActions($rule_type); | ||||
$supported = array_fuse($supported); | $supported = array_fuse($supported); | ||||
if (empty($supported[$action])) { | if (empty($supported[$action])) { | ||||
return new HeraldApplyTranscript( | return new HeraldApplyTranscript( | ||||
$effect, | $effect, | ||||
false, | false, | ||||
pht( | pht( | ||||
Show All 9 Lines | switch ($action) { | ||||
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: | case self::ACTION_FLAG: | ||||
return $this->applyFlagEffect($effect); | return $this->applyFlagEffect($effect); | ||||
case self::ACTION_EMAIL: | case self::ACTION_EMAIL: | ||||
return $this->applyEmailEffect($effect); | return $this->applyEmailEffect($effect); | ||||
case self::ACTION_NOTHING: | |||||
return $this->applyNothingEffect($effect); | |||||
default: | default: | ||||
break; | break; | ||||
} | } | ||||
$result = $this->handleCustomHeraldEffect($effect); | $result = $this->handleCustomHeraldEffect($effect); | ||||
if (!$result) { | if (!$result) { | ||||
return new HeraldApplyTranscript( | return new HeraldApplyTranscript( | ||||
$effect, | $effect, | ||||
false, | false, | ||||
pht( | pht( | ||||
'No custom action exists to handle rule action "%s".', | 'No custom action exists to handle rule action "%s".', | ||||
$action)); | $action)); | ||||
} | } | ||||
return $result; | return $result; | ||||
} | } | ||||
private function applyNothingEffect(HeraldEffect $effect) { | |||||
return new HeraldApplyTranscript( | |||||
$effect, | |||||
true, | |||||
pht('Did nothing.')); | |||||
} | |||||
/** | /** | ||||
* @task apply | * @task apply | ||||
*/ | */ | ||||
private function applyProjectsEffect(HeraldEffect $effect) { | private function applyProjectsEffect(HeraldEffect $effect) { | ||||
if ($effect->getAction() == self::ACTION_ADD_PROJECTS) { | if ($effect->getAction() == self::ACTION_ADD_PROJECTS) { | ||||
$kind = '+'; | $kind = '+'; | ||||
} else { | } else { | ||||
▲ Show 20 Lines • Show All 180 Lines • Show Last 20 Lines |