1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2025-01-17 18:21:11 +01:00

Add View, Edit and Join policies to PhabricatorProject

Summary:
  - In ProjectQuery, always load the viewer's membership in the project because we need it to perform a CAN_VIEW test.
  - Add storage for the view, edit and join policies.
  - A user can always view a project if they are a member.
  - A user can always join a project if they can edit it.
  - Editing a project requires both "view" and "edit" permissions, and edit does not imply view.
  - This has no effect on the application yet.

Test Plan: See next diff.

Reviewers: vrana, btrahan

Reviewed By: btrahan

CC: aran

Maniphest Tasks: T603

Differential Revision: https://secure.phabricator.com/D3219
This commit is contained in:
epriestley 2012-08-11 07:05:01 -07:00
parent 6cbc67ea75
commit bd0be1c650
4 changed files with 106 additions and 16 deletions

View file

@ -0,0 +1,8 @@
ALTER TABLE `{$NAMESPACE}_project`.`project`
ADD `viewPolicy` varchar(64) COLLATE utf8_bin;
ALTER TABLE `{$NAMESPACE}_project`.`project`
ADD `editPolicy` varchar(64) COLLATE utf8_bin;
ALTER TABLE `{$NAMESPACE}_project`.`project`
ADD `joinPolicy` varchar(64) COLLATE utf8_bin;

View file

@ -68,19 +68,32 @@ final class PhabricatorProjectQuery extends PhabricatorCursorPagedPolicyQuery {
$table = new PhabricatorProject();
$conn_r = $table->establishConnection('r');
// NOTE: Because visibility checks for projects depend on whether or not
// the user is a project member, we always load their membership. If we're
// loading all members anyway we can piggyback on that; otherwise we
// do an explicit join.
$select_clause = '';
if (!$this->needMembers) {
$select_clause = ', vm.dst viewerIsMember';
}
$data = queryfx_all(
$conn_r,
'SELECT p.* FROM %T p %Q %Q %Q %Q %Q',
'SELECT p.* %Q FROM %T p %Q %Q %Q %Q %Q',
$select_clause,
$table->getTableName(),
$this->buildJoinClause($conn_r),
$this->buildWhereClause($conn_r),
$this->buildGroupClause($conn_r),
'ORDER BY name',
$this->buildOrderClause($conn_r),
$this->buildLimitClause($conn_r));
$projects = $table->loadAllFromArray($data);
if ($projects && $this->needMembers) {
if ($projects) {
$viewer_phid = $this->getViewer()->getPHID();
if ($this->needMembers) {
$etype = PhabricatorEdgeConfig::TYPE_PROJ_MEMBER;
$members = id(new PhabricatorEdgeQuery())
->withSourcePHIDs(mpull($projects, 'getPHID'))
@ -89,6 +102,16 @@ final class PhabricatorProjectQuery extends PhabricatorCursorPagedPolicyQuery {
foreach ($projects as $project) {
$phid = $project->getPHID();
$project->attachMemberPHIDs(array_keys($members[$phid][$etype]));
$project->setIsUserMember(
$viewer_phid,
isset($members[$phid][$etype][$viewer_phid]));
}
} else {
foreach ($data as $row) {
$projects[$row['id']]->setIsUserMember(
$viewer_phid,
($row['viewerIsMember'] !== null));
}
}
}
@ -139,8 +162,7 @@ final class PhabricatorProjectQuery extends PhabricatorCursorPagedPolicyQuery {
if ($this->memberPHIDs) {
$where[] = qsprintf(
$conn_r,
'e.type = %s AND e.dst IN (%Ls)',
PhabricatorEdgeConfig::TYPE_PROJ_MEMBER,
'e.dst IN (%Ls)',
$this->memberPHIDs);
}
@ -160,11 +182,21 @@ final class PhabricatorProjectQuery extends PhabricatorCursorPagedPolicyQuery {
private function buildJoinClause($conn_r) {
$joins = array();
if (!$this->needMembers) {
$joins[] = qsprintf(
$conn_r,
'LEFT JOIN %T vm ON vm.src = p.phid AND vm.type = %d AND vm.dst = %s',
PhabricatorEdgeConfig::TABLE_NAME_EDGE,
PhabricatorEdgeConfig::TYPE_PROJ_MEMBER,
$this->getViewer()->getPHID());
}
if ($this->memberPHIDs) {
$joins[] = qsprintf(
$conn_r,
'JOIN %T e ON e.src = p.phid',
PhabricatorEdgeConfig::TABLE_NAME_EDGE);
'JOIN %T e ON e.src = p.phid AND e.type = %d',
PhabricatorEdgeConfig::TABLE_NAME_EDGE,
PhabricatorEdgeConfig::TYPE_PROJ_MEMBER);
}
return implode(' ', $joins);

View file

@ -26,23 +26,69 @@ final class PhabricatorProject extends PhabricatorProjectDAO
protected $subprojectPHIDs = array();
protected $phrictionSlug;
protected $viewPolicy;
protected $editPolicy;
protected $joinPolicy;
private $subprojectsNeedUpdate;
private $memberPHIDs;
private $sparseMembers = array();
public function getCapabilities() {
return array(
PhabricatorPolicyCapability::CAN_VIEW,
PhabricatorPolicyCapability::CAN_EDIT,
PhabricatorPolicyCapability::CAN_JOIN,
);
}
public function getPolicy($capability) {
return PhabricatorPolicies::POLICY_USER;
switch ($capability) {
case PhabricatorPolicyCapability::CAN_VIEW:
return $this->getViewPolicy();
case PhabricatorPolicyCapability::CAN_EDIT:
return $this->getEditPolicy();
case PhabricatorPolicyCapability::CAN_JOIN:
return $this->getJoinPolicy();
}
}
public function hasAutomaticCapability($capability, PhabricatorUser $viewer) {
switch ($capability) {
case PhabricatorPolicyCapability::CAN_VIEW:
if ($this->isUserMember($viewer->getPHID())) {
// Project members can always view a project.
return true;
}
break;
case PhabricatorPolicyCapability::CAN_EDIT:
break;
case PhabricatorPolicyCapability::CAN_JOIN:
$can_edit = PhabricatorPolicyCapability::CAN_EDIT;
if (PhabricatorPolicyFilter::hasCapability($viewer, $this, $can_edit)) {
// Project editors can always join a project.
return true;
}
break;
}
return false;
}
public function isUserMember($user_phid) {
if (!isset($this->sparseMembers[$user_phid])) {
throw new Exception(
"Call setIsUserMember() before isUserMember()!");
}
return $this->sparseMembers[$user_phid];
}
public function setIsUserMember($user_phid, $is_member) {
$this->sparseMembers[$user_phid] = $is_member;
return $this;
}
public function getConfiguration() {
return array(
self::CONFIG_AUX_PHID => true,

View file

@ -960,6 +960,10 @@ final class PhabricatorBuiltinPatchList extends PhabricatorSQLPatchList {
'type' => 'sql',
'name' => $this->getPatchPath('ponder.sql')
),
'policy-project.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('policy-project.sql'),
),
);
}