Page MenuHomePhabricator

D3219.id6288.diff
No OneTemporary

D3219.id6288.diff

Index: resources/sql/patches/policy-project.sql
===================================================================
--- /dev/null
+++ resources/sql/patches/policy-project.sql
@@ -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;
Index: src/applications/project/query/PhabricatorProjectQuery.php
===================================================================
--- src/applications/project/query/PhabricatorProjectQuery.php
+++ src/applications/project/query/PhabricatorProjectQuery.php
@@ -68,27 +68,50 @@
$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) {
- $etype = PhabricatorEdgeConfig::TYPE_PROJ_MEMBER;
- $members = id(new PhabricatorEdgeQuery())
- ->withSourcePHIDs(mpull($projects, 'getPHID'))
- ->withEdgeTypes(array($etype))
- ->execute();
- foreach ($projects as $project) {
- $phid = $project->getPHID();
- $project->attachMemberPHIDs(array_keys($members[$phid][$etype]));
+ if ($projects) {
+ $viewer_phid = $this->getViewer()->getPHID();
+ if ($this->needMembers) {
+ $etype = PhabricatorEdgeConfig::TYPE_PROJ_MEMBER;
+ $members = id(new PhabricatorEdgeQuery())
+ ->withSourcePHIDs(mpull($projects, 'getPHID'))
+ ->withEdgeTypes(array($etype))
+ ->execute();
+ 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 @@
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 @@
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);
Index: src/applications/project/storage/PhabricatorProject.php
===================================================================
--- src/applications/project/storage/PhabricatorProject.php
+++ src/applications/project/storage/PhabricatorProject.php
@@ -26,23 +26,69 @@
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,
Index: src/infrastructure/storage/patch/PhabricatorBuiltinPatchList.php
===================================================================
--- src/infrastructure/storage/patch/PhabricatorBuiltinPatchList.php
+++ src/infrastructure/storage/patch/PhabricatorBuiltinPatchList.php
@@ -960,6 +960,10 @@
'type' => 'sql',
'name' => $this->getPatchPath('ponder.sql')
),
+ 'policy-project.sql' => array(
+ 'type' => 'sql',
+ 'name' => $this->getPatchPath('policy-project.sql'),
+ ),
);
}

File Metadata

Mime Type
text/plain
Expires
Sun, Mar 30, 1:14 AM (2 w, 5 h ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
7723772
Default Alt Text
D3219.id6288.diff (6 KB)

Event Timeline