mirror of
https://we.phorge.it/source/phorge.git
synced 2024-12-23 14:00:56 +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',
|
||||
'PhabricatorProjectWorkboardProfileMenuItem' => 'applications/project/menuitem/PhabricatorProjectWorkboardProfileMenuItem.php',
|
||||
'PhabricatorProjectWorkboardTransaction' => 'applications/project/xaction/PhabricatorProjectWorkboardTransaction.php',
|
||||
'PhabricatorProjectsAllPolicyRule' => 'applications/project/policyrule/PhabricatorProjectsAllPolicyRule.php',
|
||||
'PhabricatorProjectsAncestorsSearchEngineAttachment' => 'applications/project/engineextension/PhabricatorProjectsAncestorsSearchEngineAttachment.php',
|
||||
'PhabricatorProjectsBasePolicyRule' => 'applications/project/policyrule/PhabricatorProjectsBasePolicyRule.php',
|
||||
'PhabricatorProjectsCurtainExtension' => 'applications/project/engineextension/PhabricatorProjectsCurtainExtension.php',
|
||||
'PhabricatorProjectsEditEngineExtension' => 'applications/project/engineextension/PhabricatorProjectsEditEngineExtension.php',
|
||||
'PhabricatorProjectsEditField' => 'applications/transactions/editfield/PhabricatorProjectsEditField.php',
|
||||
|
@ -9893,7 +9895,9 @@ phutil_register_library_map(array(
|
|||
'PhabricatorProjectWorkboardBackgroundTransaction' => 'PhabricatorProjectTransactionType',
|
||||
'PhabricatorProjectWorkboardProfileMenuItem' => 'PhabricatorProfileMenuItem',
|
||||
'PhabricatorProjectWorkboardTransaction' => 'PhabricatorProjectTransactionType',
|
||||
'PhabricatorProjectsAllPolicyRule' => 'PhabricatorProjectsBasePolicyRule',
|
||||
'PhabricatorProjectsAncestorsSearchEngineAttachment' => 'PhabricatorSearchEngineAttachment',
|
||||
'PhabricatorProjectsBasePolicyRule' => 'PhabricatorPolicyRule',
|
||||
'PhabricatorProjectsCurtainExtension' => 'PHUICurtainExtension',
|
||||
'PhabricatorProjectsEditEngineExtension' => 'PhabricatorEditEngineExtension',
|
||||
'PhabricatorProjectsEditField' => 'PhabricatorTokenizerEditField',
|
||||
|
@ -9902,7 +9906,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorProjectsMailEngineExtension' => 'PhabricatorMailEngineExtension',
|
||||
'PhabricatorProjectsMembersSearchEngineAttachment' => 'PhabricatorSearchEngineAttachment',
|
||||
'PhabricatorProjectsMembershipIndexEngineExtension' => 'PhabricatorIndexEngineExtension',
|
||||
'PhabricatorProjectsPolicyRule' => 'PhabricatorPolicyRule',
|
||||
'PhabricatorProjectsPolicyRule' => 'PhabricatorProjectsBasePolicyRule',
|
||||
'PhabricatorProjectsSearchEngineAttachment' => 'PhabricatorSearchEngineAttachment',
|
||||
'PhabricatorProjectsSearchEngineExtension' => 'PhabricatorSearchEngineExtension',
|
||||
'PhabricatorProjectsWatchersSearchEngineAttachment' => 'PhabricatorSearchEngineAttachment',
|
||||
|
|
|
@ -1177,6 +1177,100 @@ final class PhabricatorProjectCoreTestCase extends PhabricatorTestCase {
|
|||
$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(
|
||||
PhabricatorUser $viewer,
|
||||
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
|
||||
|
||||
final class PhabricatorProjectsPolicyRule
|
||||
extends PhabricatorPolicyRule {
|
||||
|
||||
private $memberships = array();
|
||||
extends PhabricatorProjectsBasePolicyRule {
|
||||
|
||||
public function getRuleDescription() {
|
||||
return pht('members of projects');
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
return pht('members of any project');
|
||||
}
|
||||
|
||||
public function applyRule(
|
||||
|
@ -34,8 +12,9 @@ final class PhabricatorProjectsPolicyRule
|
|||
$value,
|
||||
PhabricatorPolicyInterface $object) {
|
||||
|
||||
$memberships = $this->getMemberships($viewer->getPHID());
|
||||
foreach ($value as $project_phid) {
|
||||
if (isset($this->memberships[$viewer->getPHID()][$project_phid])) {
|
||||
if (isset($memberships[$project_phid])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -43,40 +22,8 @@ final class PhabricatorProjectsPolicyRule
|
|||
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() {
|
||||
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