Page MenuHomePhabricator

D7638.id17246.diff
No OneTemporary

D7638.id17246.diff

Index: resources/sql/patches/20131123.drydockblueprintpolicy.sql
===================================================================
--- /dev/null
+++ resources/sql/patches/20131123.drydockblueprintpolicy.sql
@@ -0,0 +1,17 @@
+CREATE TABLE {$NAMESPACE}_drydock.drydock_blueprintwithpolicy (
+ id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
+ phid VARCHAR(64) NOT NULL COLLATE utf8_bin,
+ blueprintClass VARCHAR(255) NOT NULL COLLATE utf8_bin,
+ viewPolicy VARCHAR(64) NOT NULL,
+ editPolicy VARCHAR(64) NOT NULL,
+ resourcePolicy VARCHAR(64) NOT NULL,
+ defaultResourceViewPolicy VARCHAR(64) NOT NULL,
+ defaultResourceEditPolicy VARCHAR(64) NOT NULL,
+ defaultResourceLeasePolicy VARCHAR(64) NOT NULL,
+ defaultResourceClosePolicy VARCHAR(64) NOT NULL,
+ defaultLeaseViewPolicy VARCHAR(64) NOT NULL,
+ defaultLeaseEditPolicy VARCHAR(64) NOT NULL,
+ defaultLeaseReleasePolicy VARCHAR(64) NOT NULL,
+ dateCreated INT UNSIGNED NOT NULL,
+ dateModified INT UNSIGNED NOT NULL
+) ENGINE=InnoDB, COLLATE utf8_general_ci;
Index: src/__phutil_library_map__.php
===================================================================
--- src/__phutil_library_map__.php
+++ src/__phutil_library_map__.php
@@ -625,7 +625,22 @@
'DrydockAllocatorWorker' => 'applications/drydock/worker/DrydockAllocatorWorker.php',
'DrydockApacheWebrootInterface' => 'applications/drydock/interface/webroot/DrydockApacheWebrootInterface.php',
'DrydockBlueprint' => 'applications/drydock/blueprint/DrydockBlueprint.php',
+ 'DrydockBlueprintEditController' => 'applications/drydock/controller/DrydockBlueprintEditController.php',
+ 'DrydockBlueprintListController' => 'applications/drydock/controller/DrydockBlueprintListController.php',
+ 'DrydockBlueprintQuery' => 'applications/drydock/query/DrydockBlueprintQuery.php',
'DrydockBlueprintScopeGuard' => 'applications/drydock/util/DrydockBlueprintScopeGuard.php',
+ 'DrydockBlueprintWithPolicy' => 'applications/drydock/storage/DrydockBlueprintWithPolicy.php',
+ 'DrydockCapabilityDefaultLeaseEdit' => 'applications/drydock/capability/DrydockCapabilityDefaultLeaseEdit.php',
+ 'DrydockCapabilityDefaultLeaseRelease' => 'applications/drydock/capability/DrydockCapabilityDefaultLeaseRelease.php',
+ 'DrydockCapabilityDefaultLeaseView' => 'applications/drydock/capability/DrydockCapabilityDefaultLeaseView.php',
+ 'DrydockCapabilityDefaultResourceClose' => 'applications/drydock/capability/DrydockCapabilityDefaultResourceClose.php',
+ 'DrydockCapabilityDefaultResourceEdit' => 'applications/drydock/capability/DrydockCapabilityDefaultResourceEdit.php',
+ 'DrydockCapabilityDefaultResourceLease' => 'applications/drydock/capability/DrydockCapabilityDefaultResourceLease.php',
+ 'DrydockCapabilityDefaultResourceView' => 'applications/drydock/capability/DrydockCapabilityDefaultResourceView.php',
+ 'DrydockCapabilityLease' => 'applications/drydock/capability/DrydockCapabilityLease.php',
+ 'DrydockCapabilityLeaseRelease' => 'applications/drydock/capability/DrydockCapabilityLeaseRelease.php',
+ 'DrydockCapabilityResource' => 'applications/drydock/capability/DrydockCapabilityResource.php',
+ 'DrydockCapabilityResourceClose' => 'applications/drydock/capability/DrydockCapabilityResourceClose.php',
'DrydockCommandInterface' => 'applications/drydock/interface/command/DrydockCommandInterface.php',
'DrydockConstants' => 'applications/drydock/constants/DrydockConstants.php',
'DrydockController' => 'applications/drydock/controller/DrydockController.php',
@@ -648,6 +663,7 @@
'DrydockManagementReleaseWorkflow' => 'applications/drydock/management/DrydockManagementReleaseWorkflow.php',
'DrydockManagementWaitForLeaseWorkflow' => 'applications/drydock/management/DrydockManagementWaitForLeaseWorkflow.php',
'DrydockManagementWorkflow' => 'applications/drydock/management/DrydockManagementWorkflow.php',
+ 'DrydockPHIDTypeBlueprintWithPolicy' => 'applications/drydock/phid/DrydockPHIDTypeBlueprintWithPolicy.php',
'DrydockPreallocatedHostBlueprint' => 'applications/drydock/blueprint/DrydockPreallocatedHostBlueprint.php',
'DrydockResource' => 'applications/drydock/storage/DrydockResource.php',
'DrydockResourceCloseController' => 'applications/drydock/controller/DrydockResourceCloseController.php',
@@ -2947,6 +2963,26 @@
'DoorkeeperTagsController' => 'PhabricatorController',
'DrydockAllocatorWorker' => 'PhabricatorWorker',
'DrydockApacheWebrootInterface' => 'DrydockWebrootInterface',
+ 'DrydockBlueprint' => 'PhabricatorPolicyInterface',
+ 'DrydockBlueprintEditController' => 'DrydockController',
+ 'DrydockBlueprintListController' => 'DrydockController',
+ 'DrydockBlueprintQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
+ 'DrydockBlueprintWithPolicy' =>
+ array(
+ 0 => 'DrydockDAO',
+ 1 => 'PhabricatorPolicyInterface',
+ ),
+ 'DrydockCapabilityDefaultLeaseEdit' => 'PhabricatorPolicyCapability',
+ 'DrydockCapabilityDefaultLeaseRelease' => 'PhabricatorPolicyCapability',
+ 'DrydockCapabilityDefaultLeaseView' => 'PhabricatorPolicyCapability',
+ 'DrydockCapabilityDefaultResourceClose' => 'PhabricatorPolicyCapability',
+ 'DrydockCapabilityDefaultResourceEdit' => 'PhabricatorPolicyCapability',
+ 'DrydockCapabilityDefaultResourceLease' => 'PhabricatorPolicyCapability',
+ 'DrydockCapabilityDefaultResourceView' => 'PhabricatorPolicyCapability',
+ 'DrydockCapabilityLease' => 'PhabricatorPolicyCapability',
+ 'DrydockCapabilityLeaseRelease' => 'PhabricatorPolicyCapability',
+ 'DrydockCapabilityResource' => 'PhabricatorPolicyCapability',
+ 'DrydockCapabilityResourceClose' => 'PhabricatorPolicyCapability',
'DrydockCommandInterface' => 'DrydockInterface',
'DrydockController' => 'PhabricatorController',
'DrydockDAO' => 'PhabricatorLiskDAO',
@@ -2967,6 +3003,7 @@
'DrydockManagementReleaseWorkflow' => 'DrydockManagementWorkflow',
'DrydockManagementWaitForLeaseWorkflow' => 'DrydockManagementWorkflow',
'DrydockManagementWorkflow' => 'PhutilArgumentWorkflow',
+ 'DrydockPHIDTypeBlueprintWithPolicy' => 'PhabricatorPHIDType',
'DrydockPreallocatedHostBlueprint' => 'DrydockBlueprint',
'DrydockResource' =>
array(
Index: src/applications/drydock/application/PhabricatorApplicationDrydock.php
===================================================================
--- src/applications/drydock/application/PhabricatorApplicationDrydock.php
+++ src/applications/drydock/application/PhabricatorApplicationDrydock.php
@@ -34,6 +34,10 @@
return array(
'/drydock/' => array(
'' => 'DrydockResourceListController',
+ 'blueprint/' => array(
+ '' => 'DrydockBlueprintListController',
+ 'edit/(?P<phid>[^/]+)/' => 'DrydockBlueprintEditController',
+ ),
'resource/' => array(
'' => 'DrydockResourceListController',
'(?P<id>[1-9]\d*)/' => 'DrydockResourceViewController',
Index: src/applications/drydock/blueprint/DrydockBlueprint.php
===================================================================
--- src/applications/drydock/blueprint/DrydockBlueprint.php
+++ src/applications/drydock/blueprint/DrydockBlueprint.php
@@ -5,11 +5,14 @@
* @task resource Resource Allocation
* @task log Logging
*/
-abstract class DrydockBlueprint {
+abstract class DrydockBlueprint implements PhabricatorPolicyInterface {
private $activeResource;
private $activeLease;
+ private $policiesLoaded;
+ private $policiesObject;
+
abstract public function getType();
abstract public function getInterface(
DrydockResource $resource,
@@ -18,6 +21,8 @@
abstract public function isEnabled();
+ abstract public function getDescription();
+
public function getBlueprintClass() {
return get_class($this);
}
@@ -37,6 +42,21 @@
return $lease;
}
+ public function attachPolicies(DrydockBlueprintWithPolicy $policy) {
+ $this->policiesLoaded = true;
+ $this->policiesObject = $policy;
+ }
+
+ public function getPolicies() {
+ if (!$this->policiesLoaded) {
+ throw new Exception(
+ "Policies must be attached to the blueprint with ".
+ "`attachPolicies` before they can be returned.");
+ }
+
+ return $this->policiesObject;
+ }
+
/* -( Lease Acquisition )-------------------------------------------------- */
@@ -361,6 +381,55 @@
return $list;
}
+ public static function getAllBlueprintsWithPolicies() {
+ $blueprints = self::getAllBlueprints();
+
+ $blueprint_policies = id(new DrydockBlueprintWithPolicy())->loadAll();
+
+ // Match the policies up with the blueprints.
+ foreach ($blueprints as $blueprint) {
+ $selected_policy = null;
+
+ foreach ($blueprint_policies as $policy) {
+ if ($policy->getBlueprintClass() == $blueprint->getBlueprintClass()) {
+ $selected_policy = $policy;
+ break;
+ }
+ }
+
+ if ($selected_policy === null) {
+ // Create a new policy entry for this blueprint and save it.
+ $selected_policy = new DrydockBlueprintWithPolicy();
+ $selected_policy->setBlueprintClass($blueprint->getBlueprintClass());
+ $selected_policy->setViewPolicy(PhabricatorPolicies::POLICY_ADMIN);
+ $selected_policy->setEditPolicy(PhabricatorPolicies::POLICY_ADMIN);
+ $selected_policy->setResourcePolicy(PhabricatorPolicies::POLICY_ADMIN);
+ $selected_policy->setDefaultResourceViewPolicy(
+ PhabricatorPolicies::POLICY_ADMIN);
+ $selected_policy->setDefaultResourceEditPolicy(
+ PhabricatorPolicies::POLICY_ADMIN);
+ $selected_policy->setDefaultResourceLeasePolicy(
+ PhabricatorPolicies::POLICY_ADMIN);
+ $selected_policy->setDefaultResourceClosePolicy(
+ PhabricatorPolicies::POLICY_ADMIN);
+ $selected_policy->setDefaultLeaseViewPolicy(
+ PhabricatorPolicies::POLICY_ADMIN);
+ $selected_policy->setDefaultLeaseEditPolicy(
+ PhabricatorPolicies::POLICY_ADMIN);
+ $selected_policy->setDefaultLeaseReleasePolicy(
+ PhabricatorPolicies::POLICY_ADMIN);
+
+ $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
+ $selected_policy->save();
+ unset($unguarded);
+ }
+
+ $blueprint->attachPolicies($selected_policy);
+ }
+
+ return $blueprints;
+ }
+
public static function getAllBlueprintsForResource($type) {
static $groups = null;
if ($groups === null) {
@@ -433,4 +502,62 @@
$this->activeLease = null;
}
+
+/* -( PhabricatorPHIDInterface )----------------------------------------- */
+
+
+ public function getPHID() {
+ if (!$this->policiesLoaded) {
+ throw new Exception(
+ "Policies must be attached to the blueprint with ".
+ "`attachPolicies` before the PHID can be returned.");
+ }
+
+ return $this->policiesObject->getPHID();
+ }
+
+
+/* -( PhabricatorPolicyInterface )----------------------------------------- */
+
+
+ public function getCapabilities() {
+ if (!$this->policiesLoaded) {
+ throw new Exception(
+ "Policies must be attached to the blueprint with ".
+ "`attachPolicies` before being evaluated.");
+ }
+
+ return $this->policiesObject->getCapabilities();
+ }
+
+ public function getPolicy($capability) {
+ if (!$this->policiesLoaded) {
+ throw new Exception(
+ "Policies must be attached to the blueprint with ".
+ "`attachPolicies` before being evaluated.");
+ }
+
+ return $this->policiesObject->getPolicy($capability);
+ }
+
+ public function hasAutomaticCapability($capability, PhabricatorUser $viewer) {
+ if (!$this->policiesLoaded) {
+ throw new Exception(
+ "Policies must be attached to the blueprint with ".
+ "`attachPolicies` before being evaluated.");
+ }
+
+ return $this->policiesObject->hasAutomaticCapability($capability, $viewer);
+ }
+
+ public function describeAutomaticCapability($capability) {
+ if (!$this->policiesLoaded) {
+ throw new Exception(
+ "Policies must be attached to the blueprint with ".
+ "`attachPolicies` before being evaluated.");
+ }
+
+ return $this->policiesObject->describeAutomaticCapability($capability);
+ }
+
}
Index: src/applications/drydock/blueprint/DrydockLocalHostBlueprint.php
===================================================================
--- src/applications/drydock/blueprint/DrydockLocalHostBlueprint.php
+++ src/applications/drydock/blueprint/DrydockLocalHostBlueprint.php
@@ -6,6 +6,10 @@
return false;
}
+ public function getDescription() {
+ return pht('Allocates storage on the local host.');
+ }
+
public function canAllocateMoreResources(array $pool) {
assert_instances_of($pool, 'DrydockResource');
Index: src/applications/drydock/blueprint/DrydockPreallocatedHostBlueprint.php
===================================================================
--- src/applications/drydock/blueprint/DrydockPreallocatedHostBlueprint.php
+++ src/applications/drydock/blueprint/DrydockPreallocatedHostBlueprint.php
@@ -6,6 +6,10 @@
return true;
}
+ public function getDescription() {
+ return pht('Leases out preallocated, remote hosts.');
+ }
+
public function canAllocateMoreResources(array $pool) {
return false;
}
Index: src/applications/drydock/blueprint/DrydockWorkingCopyBlueprint.php
===================================================================
--- src/applications/drydock/blueprint/DrydockWorkingCopyBlueprint.php
+++ src/applications/drydock/blueprint/DrydockWorkingCopyBlueprint.php
@@ -6,6 +6,10 @@
return true;
}
+ public function getDescription() {
+ return pht('Allocates out working copies of repositories.');
+ }
+
protected function canAllocateLease(
DrydockResource $resource,
DrydockLease $lease) {
Index: src/applications/drydock/capability/DrydockCapabilityDefaultLeaseEdit.php
===================================================================
--- /dev/null
+++ src/applications/drydock/capability/DrydockCapabilityDefaultLeaseEdit.php
@@ -0,0 +1,21 @@
+<?php
+
+final class DrydockCapabilityDefaultLeaseEdit
+ extends PhabricatorPolicyCapability {
+
+ const CAPABILITY = 'drydock.blueprint.default.lease.edit';
+
+ public function getCapabilityKey() {
+ return self::CAPABILITY;
+ }
+
+ public function getCapabilityName() {
+ return pht('Editable By');
+ }
+
+ public function describeCapabilityRejection() {
+ return pht(
+ 'You do not have permission to edit this lease.');
+ }
+
+}
Index: src/applications/drydock/capability/DrydockCapabilityDefaultLeaseRelease.php
===================================================================
--- /dev/null
+++ src/applications/drydock/capability/DrydockCapabilityDefaultLeaseRelease.php
@@ -0,0 +1,21 @@
+<?php
+
+final class DrydockCapabilityDefaultLeaseRelease
+ extends PhabricatorPolicyCapability {
+
+ const CAPABILITY = 'drydock.blueprint.default.lease.release';
+
+ public function getCapabilityKey() {
+ return self::CAPABILITY;
+ }
+
+ public function getCapabilityName() {
+ return pht('Releasable By');
+ }
+
+ public function describeCapabilityRejection() {
+ return pht(
+ 'You do not have permission to release this lease.');
+ }
+
+}
Index: src/applications/drydock/capability/DrydockCapabilityDefaultLeaseView.php
===================================================================
--- /dev/null
+++ src/applications/drydock/capability/DrydockCapabilityDefaultLeaseView.php
@@ -0,0 +1,21 @@
+<?php
+
+final class DrydockCapabilityDefaultLeaseView
+ extends PhabricatorPolicyCapability {
+
+ const CAPABILITY = 'drydock.blueprint.default.lease.view';
+
+ public function getCapabilityKey() {
+ return self::CAPABILITY;
+ }
+
+ public function getCapabilityName() {
+ return pht('Visible To');
+ }
+
+ public function describeCapabilityRejection() {
+ return pht(
+ 'You do not have permission to view this lease.');
+ }
+
+}
Index: src/applications/drydock/capability/DrydockCapabilityDefaultResourceClose.php
===================================================================
--- /dev/null
+++ src/applications/drydock/capability/DrydockCapabilityDefaultResourceClose.php
@@ -0,0 +1,21 @@
+<?php
+
+final class DrydockCapabilityDefaultResourceClose
+ extends PhabricatorPolicyCapability {
+
+ const CAPABILITY = 'drydock.blueprint.default.resource.close';
+
+ public function getCapabilityKey() {
+ return self::CAPABILITY;
+ }
+
+ public function getCapabilityName() {
+ return pht('Closable By');
+ }
+
+ public function describeCapabilityRejection() {
+ return pht(
+ 'You do not have permission to close this resource.');
+ }
+
+}
Index: src/applications/drydock/capability/DrydockCapabilityDefaultResourceEdit.php
===================================================================
--- /dev/null
+++ src/applications/drydock/capability/DrydockCapabilityDefaultResourceEdit.php
@@ -0,0 +1,21 @@
+<?php
+
+final class DrydockCapabilityDefaultResourceEdit
+ extends PhabricatorPolicyCapability {
+
+ const CAPABILITY = 'drydock.blueprint.default.resource.edit';
+
+ public function getCapabilityKey() {
+ return self::CAPABILITY;
+ }
+
+ public function getCapabilityName() {
+ return pht('Editable By');
+ }
+
+ public function describeCapabilityRejection() {
+ return pht(
+ 'You do not have permission to edit this resource.');
+ }
+
+}
Index: src/applications/drydock/capability/DrydockCapabilityDefaultResourceLease.php
===================================================================
--- /dev/null
+++ src/applications/drydock/capability/DrydockCapabilityDefaultResourceLease.php
@@ -0,0 +1,21 @@
+<?php
+
+final class DrydockCapabilityDefaultResourceLease
+ extends PhabricatorPolicyCapability {
+
+ const CAPABILITY = 'drydock.blueprint.default.resource.lease';
+
+ public function getCapabilityKey() {
+ return self::CAPABILITY;
+ }
+
+ public function getCapabilityName() {
+ return pht('Leasable By');
+ }
+
+ public function describeCapabilityRejection() {
+ return pht(
+ 'You do not have permission to lease this resource.');
+ }
+
+}
Index: src/applications/drydock/capability/DrydockCapabilityDefaultResourceView.php
===================================================================
--- /dev/null
+++ src/applications/drydock/capability/DrydockCapabilityDefaultResourceView.php
@@ -0,0 +1,21 @@
+<?php
+
+final class DrydockCapabilityDefaultResourceView
+ extends PhabricatorPolicyCapability {
+
+ const CAPABILITY = 'drydock.blueprint.default.resource.view';
+
+ public function getCapabilityKey() {
+ return self::CAPABILITY;
+ }
+
+ public function getCapabilityName() {
+ return pht('Visible To');
+ }
+
+ public function describeCapabilityRejection() {
+ return pht(
+ 'You do not have permission to view this resource.');
+ }
+
+}
Index: src/applications/drydock/capability/DrydockCapabilityLease.php
===================================================================
--- /dev/null
+++ src/applications/drydock/capability/DrydockCapabilityLease.php
@@ -0,0 +1,21 @@
+<?php
+
+final class DrydockCapabilityLease
+ extends PhabricatorPolicyCapability {
+
+ const CAPABILITY = 'drydock.lease';
+
+ public function getCapabilityKey() {
+ return self::CAPABILITY;
+ }
+
+ public function getCapabilityName() {
+ return pht('Leasable By');
+ }
+
+ public function describeCapabilityRejection() {
+ return pht(
+ 'You do not have permission to lease this resource.');
+ }
+
+}
Index: src/applications/drydock/capability/DrydockCapabilityLeaseRelease.php
===================================================================
--- /dev/null
+++ src/applications/drydock/capability/DrydockCapabilityLeaseRelease.php
@@ -0,0 +1,21 @@
+<?php
+
+final class DrydockCapabilityLeaseRelease
+ extends PhabricatorPolicyCapability {
+
+ const CAPABILITY = 'drydock.lease.release';
+
+ public function getCapabilityKey() {
+ return self::CAPABILITY;
+ }
+
+ public function getCapabilityName() {
+ return pht('Releasable By');
+ }
+
+ public function describeCapabilityRejection() {
+ return pht(
+ 'You do not have permission to release this lease.');
+ }
+
+}
Index: src/applications/drydock/capability/DrydockCapabilityResource.php
===================================================================
--- /dev/null
+++ src/applications/drydock/capability/DrydockCapabilityResource.php
@@ -0,0 +1,21 @@
+<?php
+
+final class DrydockCapabilityResource
+ extends PhabricatorPolicyCapability {
+
+ const CAPABILITY = 'drydock.resource';
+
+ public function getCapabilityKey() {
+ return self::CAPABILITY;
+ }
+
+ public function getCapabilityName() {
+ return pht('Resourcable By');
+ }
+
+ public function describeCapabilityRejection() {
+ return pht(
+ 'You do not have permission to create resources from this blueprint.');
+ }
+
+}
Index: src/applications/drydock/capability/DrydockCapabilityResourceClose.php
===================================================================
--- /dev/null
+++ src/applications/drydock/capability/DrydockCapabilityResourceClose.php
@@ -0,0 +1,22 @@
+<?php
+
+final class DrydockCapabilityResourceClose
+ extends PhabricatorPolicyCapability {
+
+ const CAPABILITY = 'drydock.resource.close';
+
+ public function getCapabilityKey() {
+ return self::CAPABILITY;
+ }
+
+ public function getCapabilityName() {
+ return pht('Closable By');
+ }
+
+ public function describeCapabilityRejection() {
+ return pht(
+ 'You do not have permission to close this resource '.
+ 'and release it\'s leases.');
+ }
+
+}
Index: src/applications/drydock/controller/DrydockBlueprintEditController.php
===================================================================
--- /dev/null
+++ src/applications/drydock/controller/DrydockBlueprintEditController.php
@@ -0,0 +1,211 @@
+<?php
+
+final class DrydockBlueprintEditController extends DrydockController {
+
+ private $phid;
+
+ public function willProcessRequest(array $data) {
+ $this->phid = idx($data, 'phid');
+ }
+
+ public function processRequest() {
+ $request = $this->getRequest();
+ $viewer = $request->getUser();
+
+ if (!$this->phid) {
+ return new Aphront404Response();
+ }
+
+ $blueprint = id(new DrydockBlueprintQuery())
+ ->setViewer($viewer)
+ ->withPHIDs(array($this->phid))
+ ->requireCapabilities(
+ array(
+ PhabricatorPolicyCapability::CAN_VIEW,
+ PhabricatorPolicyCapability::CAN_EDIT,
+ ))
+ ->executeOne();
+ if (!$blueprint) {
+ return new Aphront404Response();
+ }
+
+ if ($request->isFormPost()) {
+ $v_view_policy = $request->getStr('viewPolicy');
+ $v_edit_policy = $request->getStr('editPolicy');
+ $v_resource_policy = $request->getStr('resourcePolicy');
+ $v_default_resource_view_policy =
+ $request->getStr('defaultResourceViewPolicy');
+ $v_default_resource_edit_policy =
+ $request->getStr('defaultResourceEditPolicy');
+ $v_default_resource_lease_policy =
+ $request->getStr('defaultResourceLeasePolicy');
+ $v_default_resource_close_policy =
+ $request->getStr('defaultResourceClosePolicy');
+ $v_default_lease_view_policy =
+ $request->getStr('defaultLeaseViewPolicy');
+ $v_default_lease_edit_policy =
+ $request->getStr('defaultLeaseEditPolicy');
+ $v_default_lease_release_policy =
+ $request->getStr('defaultLeaseReleasePolicy');
+
+ // TODO: Should we use transactions here?
+ $blueprint_policies = $blueprint->getPolicies();
+
+ $blueprint_policies->setViewPolicy($v_view_policy);
+ $blueprint_policies->setEditPolicy($v_edit_policy);
+ $blueprint_policies->setResourcePolicy($v_resource_policy);
+ $blueprint_policies->setDefaultResourceViewPolicy(
+ $v_default_resource_view_policy);
+ $blueprint_policies->setDefaultResourceEditPolicy(
+ $v_default_resource_edit_policy);
+ $blueprint_policies->setDefaultResourceLeasePolicy(
+ $v_default_resource_lease_policy);
+ $blueprint_policies->setDefaultResourceClosePolicy(
+ $v_default_resource_close_policy);
+ $blueprint_policies->setDefaultLeaseViewPolicy(
+ $v_default_lease_view_policy);
+ $blueprint_policies->setDefaultLeaseEditPolicy(
+ $v_default_lease_edit_policy);
+ $blueprint_policies->setDefaultLeaseReleasePolicy(
+ $v_default_lease_release_policy);
+
+ $blueprint_policies->save();
+
+ if ($request->isAjax()) {
+ return id(new AphrontRedirectResponse());
+ } else {
+ return id(new AphrontRedirectResponse())
+ ->setURI('/drydock/blueprint/');
+ }
+ }
+
+ $policies = id(new PhabricatorPolicyQuery())
+ ->setViewer($viewer)
+ ->setObject($blueprint)
+ ->execute();
+
+ if ($request->isAjax()) {
+ $form = id(new PHUIFormLayoutView())
+ ->setViewer($viewer);
+ } else {
+ $form = id(new AphrontFormView())
+ ->setUser($viewer);
+ }
+
+ $form
+ ->appendChild(
+ id(new AphrontFormPolicyControl())
+ ->setName('viewPolicy')
+ ->setPolicyObject($blueprint)
+ ->setCapability(PhabricatorPolicyCapability::CAN_VIEW)
+ ->setPolicies($policies))
+ ->appendChild(
+ id(new AphrontFormPolicyControl())
+ ->setName('editPolicy')
+ ->setPolicyObject($blueprint)
+ ->setCapability(PhabricatorPolicyCapability::CAN_EDIT)
+ ->setPolicies($policies))
+ ->appendChild(
+ id(new AphrontFormPolicyControl())
+ ->setName('resourcePolicy')
+ ->setPolicyObject($blueprint)
+ ->setCapability(DrydockCapabilityResource::CAPABILITY)
+ ->setPolicies($policies))
+ ->appendRemarkupInstructions(
+ pht(
+ 'Select the default policies to be applied to resources created '.
+ 'by this blueprint:'))
+ ->appendChild(
+ id(new AphrontFormPolicyControl())
+ ->setName('defaultResourceViewPolicy')
+ ->setPolicyObject($blueprint)
+ ->setCapability(DrydockCapabilityDefaultResourceView::CAPABILITY)
+ ->setPolicies($policies))
+ ->appendChild(
+ id(new AphrontFormPolicyControl())
+ ->setName('defaultResourceEditPolicy')
+ ->setPolicyObject($blueprint)
+ ->setCapability(DrydockCapabilityDefaultResourceEdit::CAPABILITY)
+ ->setPolicies($policies))
+ ->appendChild(
+ id(new AphrontFormPolicyControl())
+ ->setName('defaultResourceLeasePolicy')
+ ->setPolicyObject($blueprint)
+ ->setCapability(DrydockCapabilityDefaultResourceLease::CAPABILITY)
+ ->setPolicies($policies)
+ ->setCaption(pht('The creator of a resource can always lease it.')))
+ ->appendChild(
+ id(new AphrontFormPolicyControl())
+ ->setName('defaultResourceClosePolicy')
+ ->setPolicyObject($blueprint)
+ ->setCapability(DrydockCapabilityDefaultResourceClose::CAPABILITY)
+ ->setPolicies($policies)
+ ->setCaption(pht('The creator of a resource can always close it.')))
+ ->appendRemarkupInstructions(
+ pht(
+ 'Select the default policies to be applied to leases created '.
+ 'by this blueprint:'))
+ ->appendChild(
+ id(new AphrontFormPolicyControl())
+ ->setName('defaultLeaseViewPolicy')
+ ->setPolicyObject($blueprint)
+ ->setCapability(DrydockCapabilityDefaultLeaseView::CAPABILITY)
+ ->setPolicies($policies))
+ ->appendChild(
+ id(new AphrontFormPolicyControl())
+ ->setName('defaultLeaseEditPolicy')
+ ->setPolicyObject($blueprint)
+ ->setCapability(DrydockCapabilityDefaultLeaseEdit::CAPABILITY)
+ ->setPolicies($policies))
+ ->appendChild(
+ id(new AphrontFormPolicyControl())
+ ->setName('defaultLeaseReleasePolicy')
+ ->setPolicyObject($blueprint)
+ ->setCapability(DrydockCapabilityDefaultLeaseRelease::CAPABILITY)
+ ->setPolicies($policies)
+ ->setCaption(pht('The leaser of a resource can always release it.')));
+
+ $crumbs = $this->buildApplicationCrumbs();
+
+ $title = pht('Edit Blueprint');
+ $header = pht('Edit %s', $blueprint->getBlueprintClass());
+ $crumbs->addCrumb(
+ id(new PhabricatorCrumbView())
+ ->setName($blueprint->getBlueprintClass()));
+ $crumbs->addCrumb(
+ id(new PhabricatorCrumbView())
+ ->setName(pht('Edit')));
+
+ if ($request->isAjax()) {
+ $dialog = id(new AphrontDialogView())
+ ->setUser($viewer)
+ ->setWidth(AphrontDialogView::WIDTH_FORM)
+ ->setTitle($title)
+ ->appendChild($form)
+ ->addSubmitButton(pht('Edit Blueprint'))
+ ->addCancelButton($this->getApplicationURI());
+
+ return id(new AphrontDialogResponse())->setDialog($dialog);
+ }
+
+ $form->appendChild(
+ id(new AphrontFormSubmitControl())
+ ->setValue(pht('Save'))
+ ->addCancelButton($this->getApplicationURI()));
+
+ $box = id(new PHUIObjectBoxView())
+ ->setHeaderText($header)
+ ->setForm($form);
+
+ return $this->buildApplicationPage(
+ array(
+ $crumbs,
+ $box,
+ ),
+ array(
+ 'title' => $title,
+ 'device' => true,
+ ));
+ }
+
+}
Index: src/applications/drydock/controller/DrydockBlueprintListController.php
===================================================================
--- /dev/null
+++ src/applications/drydock/controller/DrydockBlueprintListController.php
@@ -0,0 +1,77 @@
+<?php
+
+final class DrydockBlueprintListController extends DrydockController {
+
+ public function processRequest() {
+ $request = $this->getRequest();
+ $user = $request->getUser();
+
+ $title = pht('Blueprints');
+
+ $blueprint_header = id(new PHUIHeaderView())
+ ->setHeader($title);
+
+ $blueprints = id(new DrydockBlueprintQuery())
+ ->setViewer($user)
+ ->execute();
+
+ $blueprint_list = $this->buildBlueprintListView($blueprints);
+
+ $crumbs = $this->buildApplicationCrumbs();
+ $crumbs->addCrumb(
+ id(new PhabricatorCrumbView())
+ ->setName($title)
+ ->setHref($request->getRequestURI()));
+
+ $nav = $this->buildSideNav('blueprint');
+ $nav->setCrumbs($crumbs);
+ $nav->appendChild(
+ array(
+ $blueprint_header,
+ $blueprint_list
+ ));
+
+ return $this->buildApplicationPage(
+ $nav,
+ array(
+ 'title' => $title,
+ 'device' => true,
+ ));
+
+ }
+
+ protected function buildBlueprintListView(array $blueprints) {
+ assert_instances_of($blueprints, 'DrydockBlueprint');
+
+ $user = $this->getRequest()->getUser();
+ $view = new PHUIObjectItemListView();
+
+ foreach ($blueprints as $blueprint) {
+ $item = id(new PHUIObjectItemView())
+ ->setHeader($blueprint->getBlueprintClass());
+
+ if ($blueprint->isEnabled()) {
+ $item->addAttribute(pht('Enabled'));
+ $item->setBarColor('green');
+ } else {
+ $item->addAttribute(pht('Disabled'));
+ $item->setBarColor('red');
+ }
+
+ $item->addAttribute($blueprint->getDescription());
+
+ $item->addAction(
+ id(new PHUIListItemView())
+ ->setIcon('edit')
+ ->addSigil('blueprint-edit-task')
+ ->setWorkflow(true)
+ ->setHref(
+ '/drydock/blueprint/edit/'.$blueprint->getPHID().'/'));
+
+ $view->addItem($item);
+ }
+
+ return $view;
+ }
+
+}
Index: src/applications/drydock/controller/DrydockController.php
===================================================================
--- src/applications/drydock/controller/DrydockController.php
+++ src/applications/drydock/controller/DrydockController.php
@@ -5,9 +5,10 @@
final protected function buildSideNav($selected) {
$nav = new AphrontSideNavFilterView();
$nav->setBaseURI(new PhutilURI('/drydock/'));
- $nav->addFilter('resource', 'Resources');
- $nav->addFilter('lease', 'Leases');
- $nav->addFilter('log', 'Logs');
+ $nav->addFilter('blueprint', 'Blueprints');
+ $nav->addFilter('resource', 'Resources');
+ $nav->addFilter('lease', 'Leases');
+ $nav->addFilter('log', 'Logs');
$nav->selectFilter($selected, 'resource');
Index: src/applications/drydock/phid/DrydockPHIDTypeBlueprintWithPolicy.php
===================================================================
--- /dev/null
+++ src/applications/drydock/phid/DrydockPHIDTypeBlueprintWithPolicy.php
@@ -0,0 +1,34 @@
+<?php
+
+final class DrydockPHIDTypeBlueprintWithPolicy extends PhabricatorPHIDType {
+
+ const TYPECONST = 'DBWP';
+
+ public function getTypeConstant() {
+ return self::TYPECONST;
+ }
+
+ public function getTypeName() {
+ return pht('Blueprint');
+ }
+
+ public function newObject() {
+ return new DrydockBlueprintWithPolicy();
+ }
+
+ protected function buildQueryForObjects(
+ PhabricatorObjectQuery $query,
+ array $phids) {
+
+ return id(new DrydockBlueprintQuery())
+ ->withPHIDs($phids);
+ }
+
+ public function loadHandles(
+ PhabricatorHandleQuery $query,
+ array $handles,
+ array $objects) {
+
+ }
+
+}
Index: src/applications/drydock/query/DrydockBlueprintQuery.php
===================================================================
--- /dev/null
+++ src/applications/drydock/query/DrydockBlueprintQuery.php
@@ -0,0 +1,36 @@
+<?php
+
+final class DrydockBlueprintQuery
+ extends PhabricatorCursorPagedPolicyAwareQuery {
+
+ private $phids;
+
+ public function withPHIDs(array $phids) {
+ $this->phids = $phids;
+ return $this;
+ }
+
+ public function loadPage() {
+ $table = new DrydockResource();
+ $conn_r = $table->establishConnection('r');
+
+ $blueprints = DrydockBlueprint::getAllBlueprintsWithPolicies();
+
+ if ($this->phids !== null) {
+ $filtered_blueprints = array();
+ foreach ($blueprints as $key => $blueprint) {
+ if (in_array($blueprint->getPHID(), $this->phids)) {
+ $filtered_blueprints[$key] = $blueprint;
+ }
+ }
+ $blueprints = $filtered_blueprints;
+ }
+
+ return $blueprints;
+ }
+
+ public function getQueryApplicationClass() {
+ return 'PhabricatorApplicationDrydock';
+ }
+
+}
Index: src/applications/drydock/storage/DrydockBlueprintWithPolicy.php
===================================================================
--- /dev/null
+++ src/applications/drydock/storage/DrydockBlueprintWithPolicy.php
@@ -0,0 +1,94 @@
+<?php
+
+final class DrydockBlueprintWithPolicy extends DrydockDAO
+ implements PhabricatorPolicyInterface {
+
+ protected $phid;
+ protected $blueprintClass;
+ protected $viewPolicy;
+ protected $editPolicy;
+ protected $resourcePolicy;
+ protected $defaultResourceViewPolicy;
+ protected $defaultResourceEditPolicy;
+ protected $defaultResourceLeasePolicy;
+ protected $defaultResourceClosePolicy;
+ protected $defaultLeaseViewPolicy;
+ protected $defaultLeaseEditPolicy;
+ protected $defaultLeaseReleasePolicy;
+
+ public function getConfiguration() {
+ return array(
+ self::CONFIG_AUX_PHID => true,
+ ) + parent::getConfiguration();
+ }
+
+ public function generatePHID() {
+ return PhabricatorPHID::generateNewPHID(
+ DrydockPHIDTypeBlueprintWithPolicy::TYPECONST);
+ }
+
+
+/* -( PhabricatorPolicyInterface )----------------------------------------- */
+
+
+ public function getCapabilities() {
+ return array(
+ PhabricatorPolicyCapability::CAN_VIEW,
+ PhabricatorPolicyCapability::CAN_EDIT,
+ DrydockCapabilityResource::CAPABILITY,
+ DrydockCapabilityDefaultResourceView::CAPABILITY,
+ DrydockCapabilityDefaultResourceEdit::CAPABILITY,
+ DrydockCapabilityDefaultResourceLease::CAPABILITY,
+ DrydockCapabilityDefaultResourceClose::CAPABILITY,
+ DrydockCapabilityDefaultLeaseView::CAPABILITY,
+ DrydockCapabilityDefaultLeaseEdit::CAPABILITY,
+ DrydockCapabilityDefaultLeaseRelease::CAPABILITY,
+ );
+ }
+
+ public function getPolicy($capability) {
+ switch ($capability) {
+ case PhabricatorPolicyCapability::CAN_VIEW:
+ return $this->getViewPolicy();
+ case PhabricatorPolicyCapability::CAN_EDIT:
+ return $this->getEditPolicy();
+ case DrydockCapabilityResource::CAPABILITY:
+ return $this->getResourcePolicy();
+ case DrydockCapabilityDefaultResourceView::CAPABILITY:
+ return $this->getDefaultResourceViewPolicy();
+ case DrydockCapabilityDefaultResourceEdit::CAPABILITY:
+ return $this->getDefaultResourceEditPolicy();
+ case DrydockCapabilityDefaultResourceLease::CAPABILITY:
+ return $this->getDefaultResourceLeasePolicy();
+ case DrydockCapabilityDefaultResourceClose::CAPABILITY:
+ return $this->getDefaultResourceClosePolicy();
+ case DrydockCapabilityDefaultLeaseView::CAPABILITY:
+ return $this->getDefaultLeaseViewPolicy();
+ case DrydockCapabilityDefaultLeaseEdit::CAPABILITY:
+ return $this->getDefaultLeaseEditPolicy();
+ case DrydockCapabilityDefaultLeaseRelease::CAPABILITY:
+ return $this->getDefaultLeaseReleasePolicy();
+ }
+ }
+
+ public function hasAutomaticCapability($capability, PhabricatorUser $viewer) {
+ switch ($capability) {
+ case PhabricatorPolicyCapability::CAN_VIEW:
+ case PhabricatorPolicyCapability::CAN_EDIT:
+ return $viewer->getIsAdmin();
+ default:
+ return false;
+ }
+ }
+
+ public function describeAutomaticCapability($capability) {
+ switch ($capability) {
+ case PhabricatorPolicyCapability::CAN_VIEW:
+ return pht('Administrators can always view blueprints.');
+ case PhabricatorPolicyCapability::CAN_EDIT:
+ return pht('Administrators can always edit blueprints.');
+ default:
+ return null;
+ }
+ }
+}
Index: src/infrastructure/storage/patch/PhabricatorBuiltinPatchList.php
===================================================================
--- src/infrastructure/storage/patch/PhabricatorBuiltinPatchList.php
+++ src/infrastructure/storage/patch/PhabricatorBuiltinPatchList.php
@@ -1788,6 +1788,10 @@
'type' => 'sql',
'name' => $this->getPatchPath('20131122.repomirror.sql'),
),
+ '20131123.drydockblueprintpolicy.sql' => array(
+ 'type' => 'sql',
+ 'name' => $this->getPatchPath('20131123.drydockblueprintpolicy.sql'),
+ ),
);
}
}
Index: src/view/form/PHUIFormLayoutView.php
===================================================================
--- src/view/form/PHUIFormLayoutView.php
+++ src/view/form/PHUIFormLayoutView.php
@@ -7,13 +7,42 @@
*/
final class PHUIFormLayoutView extends AphrontView {
+ private $viewer;
private $fullWidth;
+ public function setViewer($viewer) {
+ $this->viewer = $viewer;
+ return $this;
+ }
+
public function setFullWidth($width) {
$this->fullWidth = $width;
return $this;
}
+ public function appendInstructions($text) {
+ return $this->appendChild(
+ phutil_tag(
+ 'div',
+ array(
+ 'class' => 'aphront-form-instructions',
+ ),
+ $text));
+ }
+
+ public function appendRemarkupInstructions($remarkup) {
+ if ($this->viewer === null) {
+ throw new Exception(
+ "Call `setViewer` before appending Remarkup to PHUIFormLayoutView.");
+ }
+
+ return $this->appendInstructions(
+ PhabricatorMarkupEngine::renderOneObject(
+ id(new PhabricatorMarkupOneOff())->setContent($remarkup),
+ 'default',
+ $this->viewer));
+ }
+
public function render() {
$classes = array('phui-form-view');

File Metadata

Mime Type
text/plain
Expires
Fri, Apr 25, 8:23 AM (2 d, 17 h ago)
Storage Engine
amazon-s3
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
phabricator/secure/2z/km/z4xnskb23r7aiwvw
Default Alt Text
D7638.id17246.diff (39 KB)

Event Timeline