Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F15469465
D14259.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
30 KB
Referenced Files
None
Subscribers
None
D14259.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D14259: Allow "Repository Automation" to be configured for repositories
Attached
Detach File
Event Timeline
Log In to Comment