Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F2891231
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Award Token
Flag For Later
Advanced/Developer...
View Handle
View Hovercard
Size
15 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/src/applications/herald/controller/HeraldRuleViewController.php b/src/applications/herald/controller/HeraldRuleViewController.php
index 818eb7560f..9e696c23c4 100644
--- a/src/applications/herald/controller/HeraldRuleViewController.php
+++ b/src/applications/herald/controller/HeraldRuleViewController.php
@@ -1,158 +1,162 @@
<?php
final class HeraldRuleViewController extends HeraldController {
+ public function shouldAllowPublic() {
+ return true;
+ }
+
public function handleRequest(AphrontRequest $request) {
$viewer = $request->getViewer();
$id = $request->getURIData('id');
$rule = id(new HeraldRuleQuery())
->setViewer($viewer)
->withIDs(array($id))
->needConditionsAndActions(true)
->executeOne();
if (!$rule) {
return new Aphront404Response();
}
$header = id(new PHUIHeaderView())
->setUser($viewer)
->setHeader($rule->getName())
->setPolicyObject($rule)
->setHeaderIcon('fa-bullhorn');
if ($rule->getIsDisabled()) {
$header->setStatus(
'fa-ban',
'red',
pht('Archived'));
} else {
$header->setStatus(
'fa-check',
'bluegrey',
pht('Active'));
}
$curtain = $this->buildCurtain($rule);
$details = $this->buildPropertySectionView($rule);
$description = $this->buildDescriptionView($rule);
$id = $rule->getID();
$crumbs = $this->buildApplicationCrumbs();
$crumbs->addTextCrumb("H{$id}");
$crumbs->setBorder(true);
$timeline = $this->buildTransactionTimeline(
$rule,
new HeraldTransactionQuery());
$timeline->setShouldTerminate(true);
$title = $rule->getName();
$view = id(new PHUITwoColumnView())
->setHeader($header)
->setCurtain($curtain)
->setMainColumn($timeline)
->addPropertySection(pht('Details'), $details)
->addPropertySection(pht('Description'), $description);
return $this->newPage()
->setTitle($title)
->setCrumbs($crumbs)
->appendChild($view);
}
private function buildCurtain(HeraldRule $rule) {
$viewer = $this->getViewer();
$id = $rule->getID();
$can_edit = PhabricatorPolicyFilter::hasCapability(
$viewer,
$rule,
PhabricatorPolicyCapability::CAN_EDIT);
$curtain = $this->newCurtainView($rule);
$curtain->addAction(
id(new PhabricatorActionView())
->setName(pht('Edit Rule'))
->setHref($this->getApplicationURI("edit/{$id}/"))
->setIcon('fa-pencil')
->setDisabled(!$can_edit)
->setWorkflow(!$can_edit));
if ($rule->getIsDisabled()) {
$disable_uri = "disable/{$id}/enable/";
$disable_icon = 'fa-check';
$disable_name = pht('Activate Rule');
} else {
$disable_uri = "disable/{$id}/disable/";
$disable_icon = 'fa-ban';
$disable_name = pht('Archive Rule');
}
$curtain->addAction(
id(new PhabricatorActionView())
->setName(pht('Disable Rule'))
->setHref($this->getApplicationURI($disable_uri))
->setIcon($disable_icon)
->setName($disable_name)
->setDisabled(!$can_edit)
->setWorkflow(true));
return $curtain;
}
private function buildPropertySectionView(
HeraldRule $rule) {
$viewer = $this->getRequest()->getUser();
$view = id(new PHUIPropertyListView())
->setUser($viewer);
$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()));
}
}
return $view;
}
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;
}
}
diff --git a/src/applications/herald/storage/HeraldRule.php b/src/applications/herald/storage/HeraldRule.php
index 19f9b95507..cf00e046b7 100644
--- a/src/applications/herald/storage/HeraldRule.php
+++ b/src/applications/herald/storage/HeraldRule.php
@@ -1,346 +1,347 @@
<?php
final class HeraldRule extends HeraldDAO
implements
PhabricatorApplicationTransactionInterface,
PhabricatorFlaggableInterface,
PhabricatorPolicyInterface,
PhabricatorDestructibleInterface,
PhabricatorSubscribableInterface {
const TABLE_RULE_APPLIED = 'herald_ruleapplied';
protected $name;
protected $authorPHID;
protected $contentType;
protected $mustMatchAll;
protected $repetitionPolicy;
protected $ruleType;
protected $isDisabled = 0;
protected $triggerObjectPHID;
protected $configVersion = 38;
// PHIDs for which this rule has been applied
private $ruleApplied = self::ATTACHABLE;
private $validAuthor = self::ATTACHABLE;
private $author = self::ATTACHABLE;
private $conditions;
private $actions;
private $triggerObject = self::ATTACHABLE;
protected function getConfiguration() {
return array(
self::CONFIG_AUX_PHID => true,
self::CONFIG_COLUMN_SCHEMA => array(
'name' => 'sort255',
'contentType' => 'text255',
'mustMatchAll' => 'bool',
'configVersion' => 'uint32',
'ruleType' => 'text32',
'isDisabled' => 'uint32',
'triggerObjectPHID' => 'phid?',
// T6203/NULLABILITY
// This should not be nullable.
'repetitionPolicy' => 'uint32?',
),
self::CONFIG_KEY_SCHEMA => array(
'key_name' => array(
'columns' => array('name(128)'),
),
'key_author' => array(
'columns' => array('authorPHID'),
),
'key_ruletype' => array(
'columns' => array('ruleType'),
),
'key_trigger' => array(
'columns' => array('triggerObjectPHID'),
),
),
) + parent::getConfiguration();
}
public function generatePHID() {
return PhabricatorPHID::generateNewPHID(HeraldRulePHIDType::TYPECONST);
}
public function getRuleApplied($phid) {
return $this->assertAttachedKey($this->ruleApplied, $phid);
}
public function setRuleApplied($phid, $applied) {
if ($this->ruleApplied === self::ATTACHABLE) {
$this->ruleApplied = array();
}
$this->ruleApplied[$phid] = $applied;
return $this;
}
public function loadConditions() {
if (!$this->getID()) {
return array();
}
return id(new HeraldCondition())->loadAllWhere(
'ruleID = %d',
$this->getID());
}
public function attachConditions(array $conditions) {
assert_instances_of($conditions, 'HeraldCondition');
$this->conditions = $conditions;
return $this;
}
public function getConditions() {
// TODO: validate conditions have been attached.
return $this->conditions;
}
public function loadActions() {
if (!$this->getID()) {
return array();
}
return id(new HeraldActionRecord())->loadAllWhere(
'ruleID = %d',
$this->getID());
}
public function attachActions(array $actions) {
// TODO: validate actions have been attached.
assert_instances_of($actions, 'HeraldActionRecord');
$this->actions = $actions;
return $this;
}
public function getActions() {
return $this->actions;
}
public function saveConditions(array $conditions) {
assert_instances_of($conditions, 'HeraldCondition');
return $this->saveChildren(
id(new HeraldCondition())->getTableName(),
$conditions);
}
public function saveActions(array $actions) {
assert_instances_of($actions, 'HeraldActionRecord');
return $this->saveChildren(
id(new HeraldActionRecord())->getTableName(),
$actions);
}
protected function saveChildren($table_name, array $children) {
assert_instances_of($children, 'HeraldDAO');
if (!$this->getID()) {
throw new PhutilInvalidStateException('save');
}
foreach ($children as $child) {
$child->setRuleID($this->getID());
}
$this->openTransaction();
queryfx(
$this->establishConnection('w'),
'DELETE FROM %T WHERE ruleID = %d',
$table_name,
$this->getID());
foreach ($children as $child) {
$child->save();
}
$this->saveTransaction();
}
public function delete() {
$this->openTransaction();
queryfx(
$this->establishConnection('w'),
'DELETE FROM %T WHERE ruleID = %d',
id(new HeraldCondition())->getTableName(),
$this->getID());
queryfx(
$this->establishConnection('w'),
'DELETE FROM %T WHERE ruleID = %d',
id(new HeraldActionRecord())->getTableName(),
$this->getID());
$result = parent::delete();
$this->saveTransaction();
return $result;
}
public function hasValidAuthor() {
return $this->assertAttached($this->validAuthor);
}
public function attachValidAuthor($valid) {
$this->validAuthor = $valid;
return $this;
}
public function getAuthor() {
return $this->assertAttached($this->author);
}
public function attachAuthor(PhabricatorUser $user) {
$this->author = $user;
return $this;
}
public function isGlobalRule() {
return ($this->getRuleType() === HeraldRuleTypeConfig::RULE_TYPE_GLOBAL);
}
public function isPersonalRule() {
return ($this->getRuleType() === HeraldRuleTypeConfig::RULE_TYPE_PERSONAL);
}
public function isObjectRule() {
return ($this->getRuleType() == HeraldRuleTypeConfig::RULE_TYPE_OBJECT);
}
public function attachTriggerObject($trigger_object) {
$this->triggerObject = $trigger_object;
return $this;
}
public function getTriggerObject() {
return $this->assertAttached($this->triggerObject);
}
/**
* Get a sortable key for rule execution order.
*
* Rules execute in a well-defined order: personal rules first, then object
* rules, then global rules. Within each rule type, rules execute from lowest
* ID to highest ID.
*
* This ordering allows more powerful rules (like global rules) to override
* weaker rules (like personal rules) when multiple rules exist which try to
* affect the same field. Executing from low IDs to high IDs makes
* interactions easier to understand when adding new rules, because the newest
* rules always happen last.
*
* @return string A sortable key for this rule.
*/
public function getRuleExecutionOrderSortKey() {
$rule_type = $this->getRuleType();
switch ($rule_type) {
case HeraldRuleTypeConfig::RULE_TYPE_PERSONAL:
$type_order = 1;
break;
case HeraldRuleTypeConfig::RULE_TYPE_OBJECT:
$type_order = 2;
break;
case HeraldRuleTypeConfig::RULE_TYPE_GLOBAL:
$type_order = 3;
break;
default:
throw new Exception(pht('Unknown rule type "%s"!', $rule_type));
}
return sprintf('~%d%010d', $type_order, $this->getID());
}
public function getMonogram() {
return 'H'.$this->getID();
}
/* -( PhabricatorApplicationTransactionInterface )------------------------- */
public function getApplicationTransactionEditor() {
return new HeraldRuleEditor();
}
public function getApplicationTransactionObject() {
return $this;
}
public function getApplicationTransactionTemplate() {
return new HeraldRuleTransaction();
}
public function willRenderTimeline(
PhabricatorApplicationTransactionView $timeline,
AphrontRequest $request) {
return $timeline;
}
/* -( PhabricatorPolicyInterface )----------------------------------------- */
public function getCapabilities() {
return array(
PhabricatorPolicyCapability::CAN_VIEW,
PhabricatorPolicyCapability::CAN_EDIT,
);
}
public function getPolicy($capability) {
+ if ($capability == PhabricatorPolicyCapability::CAN_VIEW) {
+ return PhabricatorPolicies::getMostOpenPolicy();
+ }
+
if ($this->isGlobalRule()) {
- switch ($capability) {
- case PhabricatorPolicyCapability::CAN_VIEW:
- return PhabricatorPolicies::POLICY_USER;
- case PhabricatorPolicyCapability::CAN_EDIT:
- $app = 'PhabricatorHeraldApplication';
- $herald = PhabricatorApplication::getByClass($app);
- $global = HeraldManageGlobalRulesCapability::CAPABILITY;
- return $herald->getPolicy($global);
- }
+ $app = 'PhabricatorHeraldApplication';
+ $herald = PhabricatorApplication::getByClass($app);
+ $global = HeraldManageGlobalRulesCapability::CAPABILITY;
+ return $herald->getPolicy($global);
} else if ($this->isObjectRule()) {
return $this->getTriggerObject()->getPolicy($capability);
} else {
- return PhabricatorPolicies::POLICY_NOONE;
+ return $this->getAuthorPHID();
}
}
public function hasAutomaticCapability($capability, PhabricatorUser $viewer) {
- if ($this->isPersonalRule()) {
- return ($viewer->getPHID() == $this->getAuthorPHID());
- } else {
- return false;
- }
+ return false;
}
public function describeAutomaticCapability($capability) {
- if ($this->isPersonalRule()) {
- return pht("A personal rule's owner can always view and edit it.");
- } else if ($this->isObjectRule()) {
- return pht('Object rules inherit the policies of their objects.');
+ if ($capability == PhabricatorPolicyCapability::CAN_VIEW) {
+ return null;
}
- return null;
+ if ($this->isGlobalRule()) {
+ return pht(
+ 'Global Herald rules can be edited by users with the "Can Manage '.
+ 'Global Rules" Herald application permission.');
+ } else if ($this->isObjectRule()) {
+ return pht('Object rules inherit the edit policies of their objects.');
+ } else {
+ return pht('A personal rule can only be edited by its owner.');
+ }
}
/* -( PhabricatorSubscribableInterface )----------------------------------- */
public function isAutomaticallySubscribed($phid) {
return $this->isPersonalRule() && $phid == $this->getAuthorPHID();
}
/* -( PhabricatorDestructibleInterface )----------------------------------- */
public function destroyObjectPermanently(
PhabricatorDestructionEngine $engine) {
$this->openTransaction();
$this->delete();
$this->saveTransaction();
}
}
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Sun, Jan 19, 14:52 (3 w, 2 d ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1125687
Default Alt Text
(15 KB)
Attached To
Mode
rP Phorge
Attached
Detach File
Event Timeline
Log In to Comment