Page MenuHomePhabricator

D14259.diff
No OneTemporary

D14259.diff

diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php
--- a/src/__phutil_library_map__.php
+++ b/src/__phutil_library_map__.php
@@ -688,6 +688,7 @@
'DiffusionRepositoryDefaultController' => 'applications/diffusion/controller/DiffusionRepositoryDefaultController.php',
'DiffusionRepositoryEditActionsController' => 'applications/diffusion/controller/DiffusionRepositoryEditActionsController.php',
'DiffusionRepositoryEditActivateController' => 'applications/diffusion/controller/DiffusionRepositoryEditActivateController.php',
+ 'DiffusionRepositoryEditAutomationController' => 'applications/diffusion/controller/DiffusionRepositoryEditAutomationController.php',
'DiffusionRepositoryEditBasicController' => 'applications/diffusion/controller/DiffusionRepositoryEditBasicController.php',
'DiffusionRepositoryEditBranchesController' => 'applications/diffusion/controller/DiffusionRepositoryEditBranchesController.php',
'DiffusionRepositoryEditController' => 'applications/diffusion/controller/DiffusionRepositoryEditController.php',
@@ -875,6 +876,7 @@
'DrydockManagementUpdateLeaseWorkflow' => 'applications/drydock/management/DrydockManagementUpdateLeaseWorkflow.php',
'DrydockManagementUpdateResourceWorkflow' => 'applications/drydock/management/DrydockManagementUpdateResourceWorkflow.php',
'DrydockManagementWorkflow' => 'applications/drydock/management/DrydockManagementWorkflow.php',
+ 'DrydockObjectAuthorizationView' => 'applications/drydock/view/DrydockObjectAuthorizationView.php',
'DrydockQuery' => 'applications/drydock/query/DrydockQuery.php',
'DrydockResource' => 'applications/drydock/storage/DrydockResource.php',
'DrydockResourceActivationFailureLogType' => 'applications/drydock/logtype/DrydockResourceActivationFailureLogType.php',
@@ -4424,6 +4426,7 @@
'DiffusionRepositoryDefaultController' => 'DiffusionController',
'DiffusionRepositoryEditActionsController' => 'DiffusionRepositoryEditController',
'DiffusionRepositoryEditActivateController' => 'DiffusionRepositoryEditController',
+ 'DiffusionRepositoryEditAutomationController' => 'DiffusionRepositoryEditController',
'DiffusionRepositoryEditBasicController' => 'DiffusionRepositoryEditController',
'DiffusionRepositoryEditBranchesController' => 'DiffusionRepositoryEditController',
'DiffusionRepositoryEditController' => 'DiffusionController',
@@ -4645,6 +4648,7 @@
'DrydockManagementUpdateLeaseWorkflow' => 'DrydockManagementWorkflow',
'DrydockManagementUpdateResourceWorkflow' => 'DrydockManagementWorkflow',
'DrydockManagementWorkflow' => 'PhabricatorManagementWorkflow',
+ 'DrydockObjectAuthorizationView' => 'AphrontView',
'DrydockQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
'DrydockResource' => array(
'DrydockDAO',
diff --git a/src/applications/diffusion/application/PhabricatorDiffusionApplication.php b/src/applications/diffusion/application/PhabricatorDiffusionApplication.php
--- a/src/applications/diffusion/application/PhabricatorDiffusionApplication.php
+++ b/src/applications/diffusion/application/PhabricatorDiffusionApplication.php
@@ -102,6 +102,7 @@
'update/' => 'DiffusionRepositoryEditUpdateController',
'symbol/' => 'DiffusionRepositorySymbolsController',
'staging/' => 'DiffusionRepositoryEditStagingController',
+ 'automation/' => 'DiffusionRepositoryEditAutomationController',
),
'pathtree/(?P<dblob>.*)' => 'DiffusionPathTreeController',
'mirror/' => array(
diff --git a/src/applications/diffusion/controller/DiffusionRepositoryEditAutomationController.php b/src/applications/diffusion/controller/DiffusionRepositoryEditAutomationController.php
new file mode 100644
--- /dev/null
+++ b/src/applications/diffusion/controller/DiffusionRepositoryEditAutomationController.php
@@ -0,0 +1,94 @@
+<?php
+
+final class DiffusionRepositoryEditAutomationController
+ extends DiffusionRepositoryEditController {
+
+ protected function processDiffusionRequest(AphrontRequest $request) {
+ $viewer = $request->getUser();
+ $drequest = $this->diffusionRequest;
+ $repository = $drequest->getRepository();
+
+ $repository = id(new PhabricatorRepositoryQuery())
+ ->setViewer($viewer)
+ ->requireCapabilities(
+ array(
+ PhabricatorPolicyCapability::CAN_VIEW,
+ PhabricatorPolicyCapability::CAN_EDIT,
+ ))
+ ->withIDs(array($repository->getID()))
+ ->executeOne();
+ if (!$repository) {
+ return new Aphront404Response();
+ }
+
+ if (!$repository->supportsAutomation()) {
+ return new Aphront404Response();
+ }
+
+ $edit_uri = $this->getRepositoryControllerURI($repository, 'edit/');
+
+ $v_blueprints = $repository->getHumanReadableDetail(
+ 'automation.blueprintPHIDs');
+
+ if ($request->isFormPost()) {
+ $v_blueprints = $request->getArr('blueprintPHIDs');
+
+ $xactions = array();
+ $template = id(new PhabricatorRepositoryTransaction());
+
+ $type_blueprints =
+ PhabricatorRepositoryTransaction::TYPE_AUTOMATION_BLUEPRINTS;
+
+ $xactions[] = id(clone $template)
+ ->setTransactionType($type_blueprints)
+ ->setNewValue($v_blueprints);
+
+ id(new PhabricatorRepositoryEditor())
+ ->setContinueOnNoEffect(true)
+ ->setContentSourceFromRequest($request)
+ ->setActor($viewer)
+ ->applyTransactions($repository, $xactions);
+
+ return id(new AphrontRedirectResponse())->setURI($edit_uri);
+ }
+
+ $crumbs = $this->buildApplicationCrumbs();
+ $crumbs->addTextCrumb(pht('Edit Automation'));
+
+ $title = pht('Edit %s', $repository->getName());
+
+ $form = id(new AphrontFormView())
+ ->setUser($viewer)
+ ->appendRemarkupInstructions(
+ pht(
+ "Configure **Repository Automation** to allow Phabricator to ".
+ "write to this repository.".
+ "\n\n".
+ "IMPORTANT: This feature is new, experimental, and not supported. ".
+ "Use it at your own risk."))
+ ->appendControl(
+ id(new AphrontFormTokenizerControl())
+ ->setLabel(pht('Use Blueprints'))
+ ->setName('blueprintPHIDs')
+ ->setValue($v_blueprints)
+ ->setDatasource(new DrydockBlueprintDatasource()))
+ ->appendChild(
+ id(new AphrontFormSubmitControl())
+ ->setValue(pht('Save'))
+ ->addCancelButton($edit_uri));
+
+ $object_box = id(new PHUIObjectBoxView())
+ ->setHeaderText($title)
+ ->setForm($form);
+
+ return $this->buildApplicationPage(
+ array(
+ $crumbs,
+ $object_box,
+ ),
+ array(
+ 'title' => $title,
+ ));
+ }
+
+}
diff --git a/src/applications/diffusion/controller/DiffusionRepositoryEditMainController.php b/src/applications/diffusion/controller/DiffusionRepositoryEditMainController.php
--- a/src/applications/diffusion/controller/DiffusionRepositoryEditMainController.php
+++ b/src/applications/diffusion/controller/DiffusionRepositoryEditMainController.php
@@ -31,6 +31,7 @@
$has_branches = ($is_git || $is_hg);
$has_local = $repository->usesLocalWorkingCopy();
$supports_staging = $repository->supportsStaging();
+ $supports_automation = $repository->supportsAutomation();
$crumbs = $this->buildApplicationCrumbs($is_main = true);
@@ -100,6 +101,13 @@
$this->buildStagingActions($repository));
}
+ $automation_properties = null;
+ if ($supports_automation) {
+ $automation_properties = $this->buildAutomationProperties(
+ $repository,
+ $this->buildAutomationActions($repository));
+ }
+
$actions_properties = $this->buildActionsProperties(
$repository,
$this->buildActionsActions($repository));
@@ -171,6 +179,12 @@
->addPropertyList($staging_properties);
}
+ if ($automation_properties) {
+ $boxes[] = id(new PHUIObjectBoxView())
+ ->setHeaderText(pht('Automation'))
+ ->addPropertyList($automation_properties);
+ }
+
$boxes[] = id(new PHUIObjectBoxView())
->setHeaderText(pht('Text Encoding'))
->addPropertyList($encoding_properties);
@@ -622,7 +636,6 @@
return $view;
}
-
private function buildStagingActions(PhabricatorRepository $repository) {
$viewer = $this->getViewer();
@@ -661,6 +674,47 @@
return $view;
}
+ private function buildAutomationActions(PhabricatorRepository $repository) {
+ $viewer = $this->getViewer();
+
+ $view = id(new PhabricatorActionListView())
+ ->setObjectURI($this->getRequest()->getRequestURI())
+ ->setUser($viewer);
+
+ $edit = id(new PhabricatorActionView())
+ ->setIcon('fa-pencil')
+ ->setName(pht('Edit Automation'))
+ ->setHref(
+ $this->getRepositoryControllerURI($repository, 'edit/automation/'));
+ $view->addAction($edit);
+
+ return $view;
+ }
+
+ private function buildAutomationProperties(
+ PhabricatorRepository $repository,
+ PhabricatorActionListView $actions) {
+ $viewer = $this->getViewer();
+
+ $view = id(new PHUIPropertyListView())
+ ->setUser($viewer)
+ ->setActionList($actions);
+
+ $blueprint_phids = $repository->getAutomationBlueprintPHIDs();
+ if (!$blueprint_phids) {
+ $blueprint_view = phutil_tag('em', array(), pht('Not Configured'));
+ } else {
+ $blueprint_view = id(new DrydockObjectAuthorizationView())
+ ->setUser($viewer)
+ ->setObjectPHID($repository->getPHID())
+ ->setBlueprintPHIDs($blueprint_phids);
+ }
+
+ $view->addProperty(pht('Automation'), $blueprint_view);
+
+ return $view;
+ }
+
private function buildHostingActions(PhabricatorRepository $repository) {
$user = $this->getRequest()->getUser();
diff --git a/src/applications/drydock/storage/DrydockAuthorization.php b/src/applications/drydock/storage/DrydockAuthorization.php
--- a/src/applications/drydock/storage/DrydockAuthorization.php
+++ b/src/applications/drydock/storage/DrydockAuthorization.php
@@ -93,6 +93,86 @@
return idx($map, $state, pht('<Unknown: %s>', $state));
}
+ /**
+ * Apply external authorization effects after a user chagnes the value of a
+ * blueprint selector control an object.
+ *
+ * @param PhabricatorUser User applying the change.
+ * @param phid Object PHID change is being applied to.
+ * @param list<phid> Old blueprint PHIDs.
+ * @param list<phid> New blueprint PHIDs.
+ * @return void
+ */
+ public static function applyAuthorizationChanges(
+ PhabricatorUser $viewer,
+ $object_phid,
+ array $old,
+ array $new) {
+
+ $old_phids = array_fuse($old);
+ $new_phids = array_fuse($new);
+
+ $rem_phids = array_diff_key($old_phids, $new_phids);
+ $add_phids = array_diff_key($new_phids, $old_phids);
+
+ $altered_phids = $rem_phids + $add_phids;
+
+ if (!$altered_phids) {
+ return;
+ }
+
+ $authorizations = id(new DrydockAuthorizationQuery())
+ ->setViewer(PhabricatorUser::getOmnipotentUser())
+ ->withObjectPHIDs(array($object_phid))
+ ->withBlueprintPHIDs($altered_phids)
+ ->execute();
+ $authorizations = mpull($authorizations, null, 'getBlueprintPHID');
+
+ $state_active = self::OBJECTAUTH_ACTIVE;
+ $state_inactive = self::OBJECTAUTH_INACTIVE;
+
+ $state_requested = self::BLUEPRINTAUTH_REQUESTED;
+
+ // Disable the object side of the authorization for any existing
+ // authorizations.
+ foreach ($rem_phids as $rem_phid) {
+ $authorization = idx($authorizations, $rem_phid);
+ if (!$authorization) {
+ continue;
+ }
+
+ $authorization
+ ->setObjectAuthorizationState($state_inactive)
+ ->save();
+ }
+
+ // For new authorizations, either add them or reactivate them depending
+ // on the current state.
+ foreach ($add_phids as $add_phid) {
+ $needs_update = false;
+
+ $authorization = idx($authorizations, $add_phid);
+ if (!$authorization) {
+ $authorization = id(new DrydockAuthorization())
+ ->setObjectPHID($object_phid)
+ ->setObjectAuthorizationState($state_active)
+ ->setBlueprintPHID($add_phid)
+ ->setBlueprintAuthorizationState($state_requested);
+
+ $needs_update = true;
+ } else {
+ $current_state = $authorization->getObjectAuthorizationState();
+ if ($current_state != $state_active) {
+ $authorization->setObjectAuthorizationState($state_active);
+ $needs_update = true;
+ }
+ }
+
+ if ($needs_update) {
+ $authorization->save();
+ }
+ }
+ }
/* -( PhabricatorPolicyInterface )----------------------------------------- */
diff --git a/src/applications/drydock/view/DrydockObjectAuthorizationView.php b/src/applications/drydock/view/DrydockObjectAuthorizationView.php
new file mode 100644
--- /dev/null
+++ b/src/applications/drydock/view/DrydockObjectAuthorizationView.php
@@ -0,0 +1,79 @@
+<?php
+
+final class DrydockObjectAuthorizationView extends AphrontView {
+
+ private $objectPHID;
+ private $blueprintPHIDs;
+
+ public function setObjectPHID($object_phid) {
+ $this->objectPHID = $object_phid;
+ return $this;
+ }
+
+ public function getObjectPHID() {
+ return $this->objectPHID;
+ }
+
+ public function setBlueprintPHIDs(array $blueprint_phids) {
+ $this->blueprintPHIDs = $blueprint_phids;
+ return $this;
+ }
+
+ public function getBlueprintPHIDs() {
+ return $this->blueprintPHIDs;
+ }
+
+ public function render() {
+ $viewer = $this->getUser();
+ $blueprint_phids = $this->getBlueprintPHIDs();
+ $object_phid = $this->getObjectPHID();
+
+ // NOTE: We're intentionally letting you see the authorization state on
+ // blueprints you can't see because this has a tremendous potential to
+ // be extremely confusing otherwise. You still can't see the blueprints
+ // themselves, but you can know if the object is authorized on something.
+
+ if ($blueprint_phids) {
+ $handles = $viewer->loadHandles($blueprint_phids);
+
+ $authorizations = id(new DrydockAuthorizationQuery())
+ ->setViewer(PhabricatorUser::getOmnipotentUser())
+ ->withObjectPHIDs(array($object_phid))
+ ->withBlueprintPHIDs($blueprint_phids)
+ ->execute();
+ $authorizations = mpull($authorizations, null, 'getBlueprintPHID');
+ } else {
+ $handles = array();
+ $authorizations = array();
+ }
+
+ $items = array();
+ foreach ($blueprint_phids as $phid) {
+ $authorization = idx($authorizations, $phid);
+ if (!$authorization) {
+ continue;
+ }
+
+ $handle = $handles[$phid];
+
+ $item = id(new PHUIStatusItemView())
+ ->setTarget($handle->renderLink());
+
+ $state = $authorization->getBlueprintAuthorizationState();
+ $item->setIcon(
+ DrydockAuthorization::getBlueprintStateIcon($state),
+ null,
+ DrydockAuthorization::getBlueprintStateName($state));
+
+ $items[] = $item;
+ }
+
+ $status = new PHUIStatusListView();
+ foreach ($items as $item) {
+ $status->addItem($item);
+ }
+
+ return $status;
+ }
+
+}
diff --git a/src/applications/phid/query/PhabricatorObjectQuery.php b/src/applications/phid/query/PhabricatorObjectQuery.php
--- a/src/applications/phid/query/PhabricatorObjectQuery.php
+++ b/src/applications/phid/query/PhabricatorObjectQuery.php
@@ -178,4 +178,40 @@
return null;
}
+
+ /**
+ * Select invalid or restricted PHIDs from a list.
+ *
+ * PHIDs are invalid if their objects do not exist or can not be seen by the
+ * viewer. This method is generally used to validate that PHIDs affected by
+ * a transaction are valid.
+ *
+ * @param PhabricatorUser Viewer.
+ * @param list<phid> List of ostensibly valid PHIDs.
+ * @return list<phid> List of invalid or restricted PHIDs.
+ */
+ public static function loadInvalidPHIDsForViewer(
+ PhabricatorUser $viewer,
+ array $phids) {
+
+ if (!$phids) {
+ return array();
+ }
+
+ $objects = id(new PhabricatorObjectQuery())
+ ->setViewer($viewer)
+ ->withPHIDs($phids)
+ ->execute();
+ $objects = mpull($objects, null, 'getPHID');
+
+ $invalid = array();
+ foreach ($phids as $phid) {
+ if (empty($objects[$phid])) {
+ $invalid[] = $phid;
+ }
+ }
+
+ return $invalid;
+ }
+
}
diff --git a/src/applications/repository/editor/PhabricatorRepositoryEditor.php b/src/applications/repository/editor/PhabricatorRepositoryEditor.php
--- a/src/applications/repository/editor/PhabricatorRepositoryEditor.php
+++ b/src/applications/repository/editor/PhabricatorRepositoryEditor.php
@@ -44,6 +44,7 @@
$types[] = PhabricatorRepositoryTransaction::TYPE_SYMBOLS_LANGUAGE;
$types[] = PhabricatorRepositoryTransaction::TYPE_SYMBOLS_SOURCES;
$types[] = PhabricatorRepositoryTransaction::TYPE_STAGING_URI;
+ $types[] = PhabricatorRepositoryTransaction::TYPE_AUTOMATION_BLUEPRINTS;
$types[] = PhabricatorTransactions::TYPE_EDGE;
$types[] = PhabricatorTransactions::TYPE_VIEW_POLICY;
@@ -107,6 +108,8 @@
return $object->getSymbolSources();
case PhabricatorRepositoryTransaction::TYPE_STAGING_URI:
return $object->getDetail('staging-uri');
+ case PhabricatorRepositoryTransaction::TYPE_AUTOMATION_BLUEPRINTS:
+ return $object->getDetail('automation.blueprintPHIDs', array());
}
}
@@ -143,6 +146,7 @@
case PhabricatorRepositoryTransaction::TYPE_SYMBOLS_LANGUAGE:
case PhabricatorRepositoryTransaction::TYPE_SYMBOLS_SOURCES:
case PhabricatorRepositoryTransaction::TYPE_STAGING_URI:
+ case PhabricatorRepositoryTransaction::TYPE_AUTOMATION_BLUEPRINTS:
return $xaction->getNewValue();
case PhabricatorRepositoryTransaction::TYPE_NOTIFY:
case PhabricatorRepositoryTransaction::TYPE_AUTOCLOSE:
@@ -226,6 +230,11 @@
case PhabricatorRepositoryTransaction::TYPE_STAGING_URI:
$object->setDetail('staging-uri', $xaction->getNewValue());
return;
+ case PhabricatorRepositoryTransaction::TYPE_AUTOMATION_BLUEPRINTS:
+ $object->setDetail(
+ 'automation.blueprintPHIDs',
+ $xaction->getNewValue());
+ return;
case PhabricatorRepositoryTransaction::TYPE_ENCODING:
// Make sure the encoding is valid by converting to UTF-8. This tests
// that the user has mbstring installed, and also that they didn't type
@@ -276,33 +285,17 @@
$editor->save();
break;
+ case PhabricatorRepositoryTransaction::TYPE_AUTOMATION_BLUEPRINTS:
+ DrydockAuthorization::applyAuthorizationChanges(
+ $this->getActor(),
+ $object->getPHID(),
+ $xaction->getOldValue(),
+ $xaction->getNewValue());
+ break;
}
}
- protected function mergeTransactions(
- PhabricatorApplicationTransaction $u,
- PhabricatorApplicationTransaction $v) {
-
- $type = $u->getTransactionType();
- switch ($type) {}
-
- return parent::mergeTransactions($u, $v);
- }
-
- protected function transactionHasEffect(
- PhabricatorLiskDAO $object,
- PhabricatorApplicationTransaction $xaction) {
-
- $old = $xaction->getOldValue();
- $new = $xaction->getNewValue();
-
- $type = $xaction->getTransactionType();
- switch ($type) {}
-
- return parent::transactionHasEffect($object, $xaction);
- }
-
protected function requireCapabilities(
PhabricatorLiskDAO $object,
PhabricatorApplicationTransaction $xaction) {
@@ -338,6 +331,7 @@
case PhabricatorRepositoryTransaction::TYPE_SYMBOLS_SOURCES:
case PhabricatorRepositoryTransaction::TYPE_SYMBOLS_LANGUAGE:
case PhabricatorRepositoryTransaction::TYPE_STAGING_URI:
+ case PhabricatorRepositoryTransaction::TYPE_AUTOMATION_BLUEPRINTS:
PhabricatorPolicyFilter::requireCapability(
$this->requireActor(),
$object,
@@ -431,6 +425,29 @@
}
}
break;
+
+ case PhabricatorRepositoryTransaction::TYPE_AUTOMATION_BLUEPRINTS:
+ foreach ($xactions as $xaction) {
+ $old = nonempty($xaction->getOldValue(), array());
+ $new = nonempty($xaction->getNewValue(), array());
+
+ $add = array_diff($new, $old);
+
+ $invalid = PhabricatorObjectQuery::loadInvalidPHIDsForViewer(
+ $this->getActor(),
+ $add);
+ if ($invalid) {
+ $errors[] = new PhabricatorApplicationTransactionValidationError(
+ $type,
+ pht('Invalid'),
+ pht(
+ 'Some of the selected automation blueprints are invalid '.
+ 'or restricted: %s.',
+ implode(', ', $invalid)),
+ $xaction);
+ }
+ }
+ break;
}
return $errors;
diff --git a/src/applications/repository/storage/PhabricatorRepository.php b/src/applications/repository/storage/PhabricatorRepository.php
--- a/src/applications/repository/storage/PhabricatorRepository.php
+++ b/src/applications/repository/storage/PhabricatorRepository.php
@@ -1799,7 +1799,7 @@
}
-/* -( Staging )-------------------------------------------------------------*/
+/* -( Staging )------------------------------------------------------------ */
public function supportsStaging() {
@@ -1815,6 +1815,22 @@
}
+/* -( Automation )--------------------------------------------------------- */
+
+
+ public function supportsAutomation() {
+ return $this->isGit();
+ }
+
+
+ public function getAutomationBlueprintPHIDs() {
+ if (!$this->supportsAutomation()) {
+ return array();
+ }
+ return $this->getDetail('automation.blueprintPHIDs', array());
+ }
+
+
/* -( PhabricatorApplicationTransactionInterface )------------------------- */
diff --git a/src/applications/repository/storage/PhabricatorRepositoryTransaction.php b/src/applications/repository/storage/PhabricatorRepositoryTransaction.php
--- a/src/applications/repository/storage/PhabricatorRepositoryTransaction.php
+++ b/src/applications/repository/storage/PhabricatorRepositoryTransaction.php
@@ -28,6 +28,7 @@
const TYPE_SYMBOLS_SOURCES = 'repo:symbol-source';
const TYPE_SYMBOLS_LANGUAGE = 'repo:symbol-language';
const TYPE_STAGING_URI = 'repo:staging-uri';
+ const TYPE_AUTOMATION_BLUEPRINTS = 'repo:automation-blueprints';
// TODO: Clean up these legacy transaction types.
const TYPE_SSH_LOGIN = 'repo:ssh-login';
@@ -65,6 +66,7 @@
}
break;
case self::TYPE_SYMBOLS_SOURCES:
+ case self::TYPE_AUTOMATION_BLUEPRINTS:
if ($old) {
$phids = array_merge($phids, $old);
}
@@ -436,6 +438,34 @@
$old,
$new);
}
+
+ case self::TYPE_AUTOMATION_BLUEPRINTS:
+ $add = array_diff($new, $old);
+ $rem = array_diff($old, $new);
+
+ if ($add && $rem) {
+ return pht(
+ '%s changed %s automation blueprint(s), '.
+ 'added %s: %s; removed %s: %s.',
+ $this->renderHandleLink($author_phid),
+ new PhutilNumber(count($add) + count($rem)),
+ new PhutilNumber(count($add)),
+ $this->renderHandleList($add),
+ new PhutilNumber(count($rem)),
+ $this->renderHandleList($rem));
+ } else if ($add) {
+ return pht(
+ '%s added %s automation blueprint(s): %s.',
+ $this->renderHandleLink($author_phid),
+ new PhutilNumber(count($add)),
+ $this->renderHandleList($add));
+ } else {
+ return pht(
+ '%s removed %s automation blueprint(s): %s.',
+ $this->renderHandleLink($author_phid),
+ new PhutilNumber(count($rem)),
+ $this->renderHandleList($rem));
+ }
}
return parent::getTitle();
diff --git a/src/infrastructure/customfield/standard/PhabricatorStandardCustomFieldBlueprints.php b/src/infrastructure/customfield/standard/PhabricatorStandardCustomFieldBlueprints.php
--- a/src/infrastructure/customfield/standard/PhabricatorStandardCustomFieldBlueprints.php
+++ b/src/infrastructure/customfield/standard/PhabricatorStandardCustomFieldBlueprints.php
@@ -14,75 +14,14 @@
public function applyApplicationTransactionExternalEffects(
PhabricatorApplicationTransaction $xaction) {
- $object_phid = $xaction->getObjectPHID();
-
$old = $this->decodeValue($xaction->getOldValue());
$new = $this->decodeValue($xaction->getNewValue());
- $old_phids = array_fuse($old);
- $new_phids = array_fuse($new);
-
- $rem_phids = array_diff_key($old_phids, $new_phids);
- $add_phids = array_diff_key($new_phids, $old_phids);
-
- $altered_phids = $rem_phids + $add_phids;
-
- if (!$altered_phids) {
- return;
- }
-
- $authorizations = id(new DrydockAuthorizationQuery())
- ->setViewer(PhabricatorUser::getOmnipotentUser())
- ->withObjectPHIDs(array($object_phid))
- ->withBlueprintPHIDs($altered_phids)
- ->execute();
- $authorizations = mpull($authorizations, null, 'getBlueprintPHID');
-
- $state_active = DrydockAuthorization::OBJECTAUTH_ACTIVE;
- $state_inactive = DrydockAuthorization::OBJECTAUTH_INACTIVE;
-
- $state_requested = DrydockAuthorization::BLUEPRINTAUTH_REQUESTED;
-
- // Disable the object side of the authorization for any existing
- // authorizations.
- foreach ($rem_phids as $rem_phid) {
- $authorization = idx($authorizations, $rem_phid);
- if (!$authorization) {
- continue;
- }
-
- $authorization
- ->setObjectAuthorizationState($state_inactive)
- ->save();
- }
-
- // For new authorizations, either add them or reactivate them depending
- // on the current state.
- foreach ($add_phids as $add_phid) {
- $needs_update = false;
-
- $authorization = idx($authorizations, $add_phid);
- if (!$authorization) {
- $authorization = id(new DrydockAuthorization())
- ->setObjectPHID($object_phid)
- ->setObjectAuthorizationState($state_active)
- ->setBlueprintPHID($add_phid)
- ->setBlueprintAuthorizationState($state_requested);
-
- $needs_update = true;
- } else {
- $current_state = $authorization->getObjectAuthorizationState();
- if ($current_state != $state_active) {
- $authorization->setObjectAuthorizationState($state_active);
- $needs_update = true;
- }
- }
-
- if ($needs_update) {
- $authorization->save();
- }
- }
-
+ DrydockAuthorization::applyAuthorizationChanges(
+ $this->getViewer(),
+ $xaction->getObjectPHID(),
+ $old,
+ $new);
}
public function renderPropertyViewValue(array $handles) {
@@ -91,55 +30,10 @@
return phutil_tag('em', array(), pht('No authorized blueprints.'));
}
- $object = $this->getObject();
- $object_phid = $object->getPHID();
-
- // NOTE: We're intentionally letting you see the authorization state on
- // blueprints you can't see because this has a tremendous potential to
- // be extremely confusing otherwise. You still can't see the blueprints
- // themselves, but you can know if the object is authorized on something.
-
- if ($value) {
- $handles = $this->getViewer()->loadHandles($value);
-
- $authorizations = id(new DrydockAuthorizationQuery())
- ->setViewer(PhabricatorUser::getOmnipotentUser())
- ->withObjectPHIDs(array($object_phid))
- ->withBlueprintPHIDs($value)
- ->execute();
- $authorizations = mpull($authorizations, null, 'getBlueprintPHID');
- } else {
- $handles = array();
- $authorizations = array();
- }
-
- $items = array();
- foreach ($value as $phid) {
- $authorization = idx($authorizations, $phid);
- if (!$authorization) {
- continue;
- }
-
- $handle = $handles[$phid];
-
- $item = id(new PHUIStatusItemView())
- ->setTarget($handle->renderLink());
-
- $state = $authorization->getBlueprintAuthorizationState();
- $item->setIcon(
- DrydockAuthorization::getBlueprintStateIcon($state),
- null,
- DrydockAuthorization::getBlueprintStateName($state));
-
- $items[] = $item;
- }
-
- $status = new PHUIStatusListView();
- foreach ($items as $item) {
- $status->addItem($item);
- }
-
- return $status;
+ return id(new DrydockObjectAuthorizationView())
+ ->setUser($this->getViewer())
+ ->setObjectPHID($this->getObject()->getPHID())
+ ->setBlueprintPHIDs($value);
}
diff --git a/src/infrastructure/customfield/standard/PhabricatorStandardCustomFieldPHIDs.php b/src/infrastructure/customfield/standard/PhabricatorStandardCustomFieldPHIDs.php
--- a/src/infrastructure/customfield/standard/PhabricatorStandardCustomFieldPHIDs.php
+++ b/src/infrastructure/customfield/standard/PhabricatorStandardCustomFieldPHIDs.php
@@ -158,22 +158,9 @@
$add = array_diff($new, $old);
- if (!$add) {
- continue;
- }
-
- $objects = id(new PhabricatorObjectQuery())
- ->setViewer($editor->getActor())
- ->withPHIDs($add)
- ->execute();
- $objects = mpull($objects, null, 'getPHID');
-
- $invalid = array();
- foreach ($add as $phid) {
- if (empty($objects[$phid])) {
- $invalid[] = $phid;
- }
- }
+ $invalid = PhabricatorObjectQuery::loadInvalidPHIDsForViewer(
+ $editor->getActor(),
+ $add);
if ($invalid) {
$error = new PhabricatorApplicationTransactionValidationError(
diff --git a/src/infrastructure/internationalization/translation/PhabricatorUSEnglishTranslation.php b/src/infrastructure/internationalization/translation/PhabricatorUSEnglishTranslation.php
--- a/src/infrastructure/internationalization/translation/PhabricatorUSEnglishTranslation.php
+++ b/src/infrastructure/internationalization/translation/PhabricatorUSEnglishTranslation.php
@@ -1403,6 +1403,23 @@
'Waiting %s seconds for lease to activate.',
),
+ '%s changed %s automation blueprint(s), added %s: %s; removed %s: %s.' =>
+ '%s changed automation blueprints, added: %4$s; removed: %6$s.',
+
+ '%s added %s automation blueprint(s): %s.' => array(
+ array(
+ '%s added an automation blueprint: %3$s.',
+ '%s added automation blueprints: %3$s.',
+ ),
+ ),
+
+ '%s removed %s automation blueprint(s): %s.' => array(
+ array(
+ '%s removed an automation blueprint: %3$s.',
+ '%s removed automation blueprints: %3$s.',
+ ),
+ ),
+
);
}

File Metadata

Mime Type
text/plain
Expires
Sat, Apr 5, 1:23 PM (2 w, 4 d ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
7328172
Default Alt Text
D14259.diff (30 KB)

Event Timeline