mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-22 23:02:42 +01:00
Add a "members of all projects" (vs "...any project") custom policy rule to the upstream
Summary: Ref T13151. See PHI702. An install is interested in a "members of all projects" (vs "members of any project", which is currently implemented) rule. Although this is fairly niche, I think it's reasonable and doesn't have much of a maintenance cost. This could already be implemented as an extension, but it would have to copy/paste a bunch of code. Test Plan: - Ran unit tests. - Used the UI to select this policy for a task, with various values. Joined/left projects to satisfy/fail the rule. Behavior seemed correct. - Used the UI to select the existing policy rule ("any project"), joined/left projects to satisfy/fail the rule. Doesn't look like I broke anything. Reviewers: amckinley Reviewed By: amckinley Maniphest Tasks: T13151 Differential Revision: https://secure.phabricator.com/D19486
This commit is contained in:
parent
59b95f9397
commit
cbff913432
5 changed files with 196 additions and 58 deletions
|
@ -4026,7 +4026,9 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorProjectWorkboardBackgroundTransaction' => 'applications/project/xaction/PhabricatorProjectWorkboardBackgroundTransaction.php',
|
'PhabricatorProjectWorkboardBackgroundTransaction' => 'applications/project/xaction/PhabricatorProjectWorkboardBackgroundTransaction.php',
|
||||||
'PhabricatorProjectWorkboardProfileMenuItem' => 'applications/project/menuitem/PhabricatorProjectWorkboardProfileMenuItem.php',
|
'PhabricatorProjectWorkboardProfileMenuItem' => 'applications/project/menuitem/PhabricatorProjectWorkboardProfileMenuItem.php',
|
||||||
'PhabricatorProjectWorkboardTransaction' => 'applications/project/xaction/PhabricatorProjectWorkboardTransaction.php',
|
'PhabricatorProjectWorkboardTransaction' => 'applications/project/xaction/PhabricatorProjectWorkboardTransaction.php',
|
||||||
|
'PhabricatorProjectsAllPolicyRule' => 'applications/project/policyrule/PhabricatorProjectsAllPolicyRule.php',
|
||||||
'PhabricatorProjectsAncestorsSearchEngineAttachment' => 'applications/project/engineextension/PhabricatorProjectsAncestorsSearchEngineAttachment.php',
|
'PhabricatorProjectsAncestorsSearchEngineAttachment' => 'applications/project/engineextension/PhabricatorProjectsAncestorsSearchEngineAttachment.php',
|
||||||
|
'PhabricatorProjectsBasePolicyRule' => 'applications/project/policyrule/PhabricatorProjectsBasePolicyRule.php',
|
||||||
'PhabricatorProjectsCurtainExtension' => 'applications/project/engineextension/PhabricatorProjectsCurtainExtension.php',
|
'PhabricatorProjectsCurtainExtension' => 'applications/project/engineextension/PhabricatorProjectsCurtainExtension.php',
|
||||||
'PhabricatorProjectsEditEngineExtension' => 'applications/project/engineextension/PhabricatorProjectsEditEngineExtension.php',
|
'PhabricatorProjectsEditEngineExtension' => 'applications/project/engineextension/PhabricatorProjectsEditEngineExtension.php',
|
||||||
'PhabricatorProjectsEditField' => 'applications/transactions/editfield/PhabricatorProjectsEditField.php',
|
'PhabricatorProjectsEditField' => 'applications/transactions/editfield/PhabricatorProjectsEditField.php',
|
||||||
|
@ -9893,7 +9895,9 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorProjectWorkboardBackgroundTransaction' => 'PhabricatorProjectTransactionType',
|
'PhabricatorProjectWorkboardBackgroundTransaction' => 'PhabricatorProjectTransactionType',
|
||||||
'PhabricatorProjectWorkboardProfileMenuItem' => 'PhabricatorProfileMenuItem',
|
'PhabricatorProjectWorkboardProfileMenuItem' => 'PhabricatorProfileMenuItem',
|
||||||
'PhabricatorProjectWorkboardTransaction' => 'PhabricatorProjectTransactionType',
|
'PhabricatorProjectWorkboardTransaction' => 'PhabricatorProjectTransactionType',
|
||||||
|
'PhabricatorProjectsAllPolicyRule' => 'PhabricatorProjectsBasePolicyRule',
|
||||||
'PhabricatorProjectsAncestorsSearchEngineAttachment' => 'PhabricatorSearchEngineAttachment',
|
'PhabricatorProjectsAncestorsSearchEngineAttachment' => 'PhabricatorSearchEngineAttachment',
|
||||||
|
'PhabricatorProjectsBasePolicyRule' => 'PhabricatorPolicyRule',
|
||||||
'PhabricatorProjectsCurtainExtension' => 'PHUICurtainExtension',
|
'PhabricatorProjectsCurtainExtension' => 'PHUICurtainExtension',
|
||||||
'PhabricatorProjectsEditEngineExtension' => 'PhabricatorEditEngineExtension',
|
'PhabricatorProjectsEditEngineExtension' => 'PhabricatorEditEngineExtension',
|
||||||
'PhabricatorProjectsEditField' => 'PhabricatorTokenizerEditField',
|
'PhabricatorProjectsEditField' => 'PhabricatorTokenizerEditField',
|
||||||
|
@ -9902,7 +9906,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorProjectsMailEngineExtension' => 'PhabricatorMailEngineExtension',
|
'PhabricatorProjectsMailEngineExtension' => 'PhabricatorMailEngineExtension',
|
||||||
'PhabricatorProjectsMembersSearchEngineAttachment' => 'PhabricatorSearchEngineAttachment',
|
'PhabricatorProjectsMembersSearchEngineAttachment' => 'PhabricatorSearchEngineAttachment',
|
||||||
'PhabricatorProjectsMembershipIndexEngineExtension' => 'PhabricatorIndexEngineExtension',
|
'PhabricatorProjectsMembershipIndexEngineExtension' => 'PhabricatorIndexEngineExtension',
|
||||||
'PhabricatorProjectsPolicyRule' => 'PhabricatorPolicyRule',
|
'PhabricatorProjectsPolicyRule' => 'PhabricatorProjectsBasePolicyRule',
|
||||||
'PhabricatorProjectsSearchEngineAttachment' => 'PhabricatorSearchEngineAttachment',
|
'PhabricatorProjectsSearchEngineAttachment' => 'PhabricatorSearchEngineAttachment',
|
||||||
'PhabricatorProjectsSearchEngineExtension' => 'PhabricatorSearchEngineExtension',
|
'PhabricatorProjectsSearchEngineExtension' => 'PhabricatorSearchEngineExtension',
|
||||||
'PhabricatorProjectsWatchersSearchEngineAttachment' => 'PhabricatorSearchEngineAttachment',
|
'PhabricatorProjectsWatchersSearchEngineAttachment' => 'PhabricatorSearchEngineAttachment',
|
||||||
|
|
|
@ -1177,6 +1177,100 @@ final class PhabricatorProjectCoreTestCase extends PhabricatorTestCase {
|
||||||
$this->assertTrue($can_edit);
|
$this->assertTrue($can_edit);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testProjectPolicyRules() {
|
||||||
|
$author = $this->generateNewTestUser();
|
||||||
|
|
||||||
|
$proj_a = PhabricatorProject::initializeNewProject($author)
|
||||||
|
->setName('Policy A')
|
||||||
|
->save();
|
||||||
|
$proj_b = PhabricatorProject::initializeNewProject($author)
|
||||||
|
->setName('Policy B')
|
||||||
|
->save();
|
||||||
|
|
||||||
|
$user_none = $this->generateNewTestUser();
|
||||||
|
$user_any = $this->generateNewTestUser();
|
||||||
|
$user_all = $this->generateNewTestUser();
|
||||||
|
|
||||||
|
$this->joinProject($proj_a, $user_any);
|
||||||
|
$this->joinProject($proj_a, $user_all);
|
||||||
|
$this->joinProject($proj_b, $user_all);
|
||||||
|
|
||||||
|
$any_policy = id(new PhabricatorPolicy())
|
||||||
|
->setRules(
|
||||||
|
array(
|
||||||
|
array(
|
||||||
|
'action' => PhabricatorPolicy::ACTION_ALLOW,
|
||||||
|
'rule' => 'PhabricatorProjectsPolicyRule',
|
||||||
|
'value' => array(
|
||||||
|
$proj_a->getPHID(),
|
||||||
|
$proj_b->getPHID(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
))
|
||||||
|
->save();
|
||||||
|
|
||||||
|
$all_policy = id(new PhabricatorPolicy())
|
||||||
|
->setRules(
|
||||||
|
array(
|
||||||
|
array(
|
||||||
|
'action' => PhabricatorPolicy::ACTION_ALLOW,
|
||||||
|
'rule' => 'PhabricatorProjectsAllPolicyRule',
|
||||||
|
'value' => array(
|
||||||
|
$proj_a->getPHID(),
|
||||||
|
$proj_b->getPHID(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
))
|
||||||
|
->save();
|
||||||
|
|
||||||
|
$any_task = ManiphestTask::initializeNewTask($author)
|
||||||
|
->setViewPolicy($any_policy->getPHID())
|
||||||
|
->save();
|
||||||
|
|
||||||
|
$all_task = ManiphestTask::initializeNewTask($author)
|
||||||
|
->setViewPolicy($all_policy->getPHID())
|
||||||
|
->save();
|
||||||
|
|
||||||
|
$map = array(
|
||||||
|
array(
|
||||||
|
pht('Project policy rule; user in no projects'),
|
||||||
|
$user_none,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
pht('Project policy rule; user in some projects'),
|
||||||
|
$user_any,
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
pht('Project policy rule; user in all projects'),
|
||||||
|
$user_all,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
foreach ($map as $test_case) {
|
||||||
|
list($label, $user, $expect_any, $expect_all) = $test_case;
|
||||||
|
|
||||||
|
$can_any = PhabricatorPolicyFilter::hasCapability(
|
||||||
|
$user,
|
||||||
|
$any_task,
|
||||||
|
PhabricatorPolicyCapability::CAN_VIEW);
|
||||||
|
|
||||||
|
$can_all = PhabricatorPolicyFilter::hasCapability(
|
||||||
|
$user,
|
||||||
|
$all_task,
|
||||||
|
PhabricatorPolicyCapability::CAN_VIEW);
|
||||||
|
|
||||||
|
$this->assertEqual($expect_any, $can_any, pht('%s / Any', $label));
|
||||||
|
$this->assertEqual($expect_all, $can_all, pht('%s / All', $label));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private function moveToColumn(
|
private function moveToColumn(
|
||||||
PhabricatorUser $viewer,
|
PhabricatorUser $viewer,
|
||||||
PhabricatorProject $board,
|
PhabricatorProject $board,
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorProjectsAllPolicyRule
|
||||||
|
extends PhabricatorProjectsBasePolicyRule {
|
||||||
|
|
||||||
|
public function getRuleDescription() {
|
||||||
|
return pht('members of all projects');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function applyRule(
|
||||||
|
PhabricatorUser $viewer,
|
||||||
|
$value,
|
||||||
|
PhabricatorPolicyInterface $object) {
|
||||||
|
|
||||||
|
$memberships = $this->getMemberships($viewer->getPHID());
|
||||||
|
foreach ($value as $project_phid) {
|
||||||
|
if (empty($memberships[$project_phid])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getRuleOrder() {
|
||||||
|
return 205;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,64 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
abstract class PhabricatorProjectsBasePolicyRule
|
||||||
|
extends PhabricatorPolicyRule {
|
||||||
|
|
||||||
|
private $memberships = array();
|
||||||
|
|
||||||
|
protected function getMemberships($viewer_phid) {
|
||||||
|
return idx($this->memberships, $viewer_phid, array());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function willApplyRules(
|
||||||
|
PhabricatorUser $viewer,
|
||||||
|
array $values,
|
||||||
|
array $objects) {
|
||||||
|
|
||||||
|
$values = array_unique(array_filter(array_mergev($values)));
|
||||||
|
if (!$values) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$projects = id(new PhabricatorProjectQuery())
|
||||||
|
->setViewer(PhabricatorUser::getOmnipotentUser())
|
||||||
|
->withMemberPHIDs(array($viewer->getPHID()))
|
||||||
|
->withPHIDs($values)
|
||||||
|
->execute();
|
||||||
|
foreach ($projects as $project) {
|
||||||
|
$this->memberships[$viewer->getPHID()][$project->getPHID()] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getValueControlType() {
|
||||||
|
return self::CONTROL_TYPE_TOKENIZER;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getValueControlTemplate() {
|
||||||
|
$datasource = id(new PhabricatorProjectDatasource())
|
||||||
|
->setParameters(
|
||||||
|
array(
|
||||||
|
'policy' => 1,
|
||||||
|
));
|
||||||
|
|
||||||
|
return $this->getDatasourceTemplate($datasource);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getValueForStorage($value) {
|
||||||
|
PhutilTypeSpec::newFromString('list<string>')->check($value);
|
||||||
|
return array_values($value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getValueForDisplay(PhabricatorUser $viewer, $value) {
|
||||||
|
$handles = id(new PhabricatorHandleQuery())
|
||||||
|
->setViewer($viewer)
|
||||||
|
->withPHIDs($value)
|
||||||
|
->execute();
|
||||||
|
|
||||||
|
return mpull($handles, 'getFullName', 'getPHID');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function ruleHasEffect($value) {
|
||||||
|
return (bool)$value;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,32 +1,10 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
final class PhabricatorProjectsPolicyRule
|
final class PhabricatorProjectsPolicyRule
|
||||||
extends PhabricatorPolicyRule {
|
extends PhabricatorProjectsBasePolicyRule {
|
||||||
|
|
||||||
private $memberships = array();
|
|
||||||
|
|
||||||
public function getRuleDescription() {
|
public function getRuleDescription() {
|
||||||
return pht('members of projects');
|
return pht('members of any project');
|
||||||
}
|
|
||||||
|
|
||||||
public function willApplyRules(
|
|
||||||
PhabricatorUser $viewer,
|
|
||||||
array $values,
|
|
||||||
array $objects) {
|
|
||||||
|
|
||||||
$values = array_unique(array_filter(array_mergev($values)));
|
|
||||||
if (!$values) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$projects = id(new PhabricatorProjectQuery())
|
|
||||||
->setViewer(PhabricatorUser::getOmnipotentUser())
|
|
||||||
->withMemberPHIDs(array($viewer->getPHID()))
|
|
||||||
->withPHIDs($values)
|
|
||||||
->execute();
|
|
||||||
foreach ($projects as $project) {
|
|
||||||
$this->memberships[$viewer->getPHID()][$project->getPHID()] = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function applyRule(
|
public function applyRule(
|
||||||
|
@ -34,8 +12,9 @@ final class PhabricatorProjectsPolicyRule
|
||||||
$value,
|
$value,
|
||||||
PhabricatorPolicyInterface $object) {
|
PhabricatorPolicyInterface $object) {
|
||||||
|
|
||||||
|
$memberships = $this->getMemberships($viewer->getPHID());
|
||||||
foreach ($value as $project_phid) {
|
foreach ($value as $project_phid) {
|
||||||
if (isset($this->memberships[$viewer->getPHID()][$project_phid])) {
|
if (isset($memberships[$project_phid])) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -43,40 +22,8 @@ final class PhabricatorProjectsPolicyRule
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getValueControlType() {
|
|
||||||
return self::CONTROL_TYPE_TOKENIZER;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getValueControlTemplate() {
|
|
||||||
$datasource = id(new PhabricatorProjectDatasource())
|
|
||||||
->setParameters(
|
|
||||||
array(
|
|
||||||
'policy' => 1,
|
|
||||||
));
|
|
||||||
|
|
||||||
return $this->getDatasourceTemplate($datasource);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getRuleOrder() {
|
public function getRuleOrder() {
|
||||||
return 200;
|
return 200;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getValueForStorage($value) {
|
|
||||||
PhutilTypeSpec::newFromString('list<string>')->check($value);
|
|
||||||
return array_values($value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getValueForDisplay(PhabricatorUser $viewer, $value) {
|
|
||||||
$handles = id(new PhabricatorHandleQuery())
|
|
||||||
->setViewer($viewer)
|
|
||||||
->withPHIDs($value)
|
|
||||||
->execute();
|
|
||||||
|
|
||||||
return mpull($handles, 'getFullName', 'getPHID');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function ruleHasEffect($value) {
|
|
||||||
return (bool)$value;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue