1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-11-10 08:52:39 +01:00

Move Almanac Services to EditEngine

Summary: Ref T10449. This modernizes the service creation/editing flow and updates the list view code a little bit.

Test Plan:
  - Created a service.
  - Edited a service.
  - Browsed services.
  - Hit policy exception for editing cluster services with no permission.

Reviewers: chad

Reviewed By: chad

Maniphest Tasks: T10449

Differential Revision: https://secure.phabricator.com/D15398
This commit is contained in:
epriestley 2016-03-04 16:08:38 -08:00
parent 13813d2268
commit 167da4ec52
7 changed files with 151 additions and 201 deletions

View file

@ -106,6 +106,7 @@ phutil_register_library_map(array(
'AlmanacServiceController' => 'applications/almanac/controller/AlmanacServiceController.php',
'AlmanacServiceDatasource' => 'applications/almanac/typeahead/AlmanacServiceDatasource.php',
'AlmanacServiceEditController' => 'applications/almanac/controller/AlmanacServiceEditController.php',
'AlmanacServiceEditEngine' => 'applications/almanac/editor/AlmanacServiceEditEngine.php',
'AlmanacServiceEditor' => 'applications/almanac/editor/AlmanacServiceEditor.php',
'AlmanacServiceListController' => 'applications/almanac/controller/AlmanacServiceListController.php',
'AlmanacServiceNameNgrams' => 'applications/almanac/storage/AlmanacServiceNameNgrams.php',
@ -4145,6 +4146,7 @@ phutil_register_library_map(array(
'AlmanacServiceController' => 'AlmanacController',
'AlmanacServiceDatasource' => 'PhabricatorTypeaheadDatasource',
'AlmanacServiceEditController' => 'AlmanacServiceController',
'AlmanacServiceEditEngine' => 'PhabricatorEditEngine',
'AlmanacServiceEditor' => 'AlmanacEditor',
'AlmanacServiceListController' => 'AlmanacServiceController',
'AlmanacServiceNameNgrams' => 'PhabricatorSearchNgrams',

View file

@ -45,7 +45,7 @@ final class PhabricatorAlmanacApplication extends PhabricatorApplication {
'' => 'AlmanacConsoleController',
'(?P<objectType>service)/' => array(
$this->getQueryRoutePattern() => 'AlmanacServiceListController',
'edit/(?:(?P<id>\d+)/)?' => 'AlmanacServiceEditController',
$this->getEditRoutePattern('edit/') => 'AlmanacServiceEditController',
'view/(?P<name>[^/]+)/' => 'AlmanacServiceViewController',
),
'(?P<objectType>device)/' => array(

View file

@ -11,6 +11,11 @@ abstract class AlmanacServiceController extends AlmanacController {
return $crumbs;
}
public function buildApplicationMenu() {
return $this->newApplicationMenu()
->setSearchEngine(new AlmanacServiceSearchEngine());
}
protected function getPropertyDeleteURI($object) {
$id = $object->getID();
return "/almanac/service/delete/{$id}/";

View file

@ -4,175 +4,28 @@ final class AlmanacServiceEditController
extends AlmanacServiceController {
public function handleRequest(AphrontRequest $request) {
$viewer = $request->getViewer();
$list_uri = $this->getApplicationURI('service/');
$engine = id(new AlmanacServiceEditEngine())
->setController($this);
$id = $request->getURIData('id');
if ($id) {
$service = id(new AlmanacServiceQuery())
->setViewer($viewer)
->withIDs(array($id))
->requireCapabilities(
array(
PhabricatorPolicyCapability::CAN_VIEW,
PhabricatorPolicyCapability::CAN_EDIT,
))
->executeOne();
if (!$service) {
return new Aphront404Response();
}
$is_new = false;
$service_uri = $service->getURI();
$cancel_uri = $service_uri;
$title = pht('Edit Service');
$save_button = pht('Save Changes');
} else {
$cancel_uri = $list_uri;
if (!$id) {
$this->requireApplicationCapability(
AlmanacCreateServicesCapability::CAPABILITY);
$list_uri = $this->getApplicationURI('service/');
$service_type = $request->getStr('serviceType');
try {
$service = AlmanacService::initializeNewService($service_type);
} catch (Exception $ex) {
return $this->buildServiceTypeResponse($cancel_uri);
$service_types = AlmanacServiceType::getAllServiceTypes();
if (empty($service_types[$service_type])) {
return $this->buildServiceTypeResponse($list_uri);
}
if ($service->isClusterService()) {
$this->requireApplicationCapability(
AlmanacManageClusterServicesCapability::CAPABILITY);
}
$is_new = true;
$title = pht('Create Service');
$save_button = pht('Create Service');
$engine
->addContextParameter('serviceType', $service_type)
->setServiceType($service_type);
}
$v_name = $service->getName();
$e_name = true;
$validation_exception = null;
if ($is_new) {
$v_projects = array();
} else {
$v_projects = PhabricatorEdgeQuery::loadDestinationPHIDs(
$service->getPHID(),
PhabricatorProjectObjectHasProjectEdgeType::EDGECONST);
$v_projects = array_reverse($v_projects);
}
if ($request->isFormPost() && $request->getStr('edit')) {
$v_name = $request->getStr('name');
$v_view = $request->getStr('viewPolicy');
$v_edit = $request->getStr('editPolicy');
$v_projects = $request->getArr('projects');
$type_name = AlmanacServiceTransaction::TYPE_NAME;
$type_view = PhabricatorTransactions::TYPE_VIEW_POLICY;
$type_edit = PhabricatorTransactions::TYPE_EDIT_POLICY;
$xactions = array();
$xactions[] = id(new AlmanacServiceTransaction())
->setTransactionType($type_name)
->setNewValue($v_name);
$xactions[] = id(new AlmanacServiceTransaction())
->setTransactionType($type_view)
->setNewValue($v_view);
$xactions[] = id(new AlmanacServiceTransaction())
->setTransactionType($type_edit)
->setNewValue($v_edit);
$proj_edge_type = PhabricatorProjectObjectHasProjectEdgeType::EDGECONST;
$xactions[] = id(new AlmanacServiceTransaction())
->setTransactionType(PhabricatorTransactions::TYPE_EDGE)
->setMetadataValue('edge:type', $proj_edge_type)
->setNewValue(array('=' => array_fuse($v_projects)));
$editor = id(new AlmanacServiceEditor())
->setActor($viewer)
->setContentSourceFromRequest($request)
->setContinueOnNoEffect(true);
try {
$editor->applyTransactions($service, $xactions);
$service_uri = $service->getURI();
return id(new AphrontRedirectResponse())->setURI($service_uri);
} catch (PhabricatorApplicationTransactionValidationException $ex) {
$validation_exception = $ex;
$e_name = $ex->getShortMessage($type_name);
$service->setViewPolicy($v_view);
$service->setEditPolicy($v_edit);
}
}
$policies = id(new PhabricatorPolicyQuery())
->setViewer($viewer)
->setObject($service)
->execute();
$form = id(new AphrontFormView())
->setUser($viewer)
->addHiddenInput('edit', true)
->addHiddenInput('serviceType', $service->getServiceType())
->appendChild(
id(new AphrontFormTextControl())
->setLabel(pht('Name'))
->setName('name')
->setValue($v_name)
->setError($e_name))
->appendChild(
id(new AphrontFormPolicyControl())
->setName('viewPolicy')
->setPolicyObject($service)
->setCapability(PhabricatorPolicyCapability::CAN_VIEW)
->setPolicies($policies))
->appendChild(
id(new AphrontFormPolicyControl())
->setName('editPolicy')
->setPolicyObject($service)
->setCapability(PhabricatorPolicyCapability::CAN_EDIT)
->setPolicies($policies))
->appendControl(
id(new AphrontFormTokenizerControl())
->setLabel(pht('Projects'))
->setName('projects')
->setValue($v_projects)
->setDatasource(new PhabricatorProjectDatasource()))
->appendChild(
id(new AphrontFormSubmitControl())
->addCancelButton($cancel_uri)
->setValue($save_button));
$box = id(new PHUIObjectBoxView())
->setValidationException($validation_exception)
->setHeaderText($title)
->appendChild($form);
$crumbs = $this->buildApplicationCrumbs();
if ($is_new) {
$crumbs->addTextCrumb(pht('Create Service'));
} else {
$crumbs->addTextCrumb($service->getName(), $service_uri);
$crumbs->addTextCrumb(pht('Edit'));
}
return $this->newPage()
->setTitle($title)
->setCrumbs($crumbs)
->appendChild(
array(
$box,
));
return $engine->buildResponse();
}
private function buildServiceTypeResponse($cancel_uri) {
@ -194,7 +47,6 @@ final class AlmanacServiceEditController
pht('You have permission to create cluster services.'),
pht('You do not have permission to create new cluster services.'));
$type_control = id(new AphrontFormRadioButtonControl())
->setLabel(pht('Service Type'))
->setName('serviceType')
@ -239,14 +91,10 @@ final class AlmanacServiceEditController
->setHeaderText($title)
->setForm($form);
return $this->buildApplicationPage(
array(
$crumbs,
$box,
),
array(
'title' => $title,
));
return $this->newPage()
->setTitle($title)
->setCrumbs($crumbs)
->appendChild($box);
}
}

View file

@ -8,45 +8,19 @@ final class AlmanacServiceListController
}
public function handleRequest(AphrontRequest $request) {
$controller = id(new PhabricatorApplicationSearchController())
->setQueryKey($request->getURIData('queryKey'))
->setSearchEngine(new AlmanacServiceSearchEngine())
->setNavigation($this->buildSideNavView());
return $this->delegateToController($controller);
return id(new AlmanacServiceSearchEngine())
->setController($this)
->buildResponse();
}
protected function buildApplicationCrumbs() {
$crumbs = parent::buildApplicationCrumbs();
$can_create = $this->hasApplicationCapability(
AlmanacCreateServicesCapability::CAPABILITY);
$crumbs->addAction(
id(new PHUIListItemView())
->setName(pht('Create Service'))
->setHref($this->getApplicationURI('service/edit/'))
->setIcon('fa-plus-square')
->setDisabled(!$can_create)
->setWorkflow(!$can_create));
id(new AlmanacServiceEditEngine())
->setViewer($this->getViewer())
->addActionToCrumbs($crumbs);
return $crumbs;
}
public function buildSideNavView() {
$viewer = $this->getViewer();
$nav = new AphrontSideNavFilterView();
$nav->setBaseURI(new PhutilURI($this->getApplicationURI()));
id(new AlmanacServiceSearchEngine())
->setViewer($viewer)
->addNavigationItems($nav->getMenu());
$nav->selectFilter(null);
return $nav;
}
}

View file

@ -0,0 +1,97 @@
<?php
final class AlmanacServiceEditEngine
extends PhabricatorEditEngine {
const ENGINECONST = 'almanac.service';
private $serviceType;
public function setServiceType($service_type) {
$this->serviceType = $service_type;
return $this;
}
public function getServiceType() {
return $this->serviceType;
}
public function isEngineConfigurable() {
return false;
}
public function getEngineName() {
return pht('Almanac Services');
}
public function getSummaryHeader() {
return pht('Edit Almanac Service Configurations');
}
public function getSummaryText() {
return pht('This engine is used to edit Almanac services.');
}
public function getEngineApplicationClass() {
return 'PhabricatorAlmanacApplication';
}
protected function newEditableObject() {
$service_type = $this->getServiceType();
return AlmanacService::initializeNewService($service_type);
}
protected function newObjectQuery() {
return new AlmanacServiceQuery();
}
protected function getObjectCreateTitleText($object) {
return pht('Create Service');
}
protected function getObjectCreateButtonText($object) {
return pht('Create Service');
}
protected function getObjectEditTitleText($object) {
return pht('Edit Service: %s', $object->getName());
}
protected function getObjectEditShortText($object) {
return pht('Edit Service');
}
protected function getObjectCreateShortText() {
return pht('Create Service');
}
protected function getEditorURI() {
return '/almanac/service/edit/';
}
protected function getObjectCreateCancelURI($object) {
return '/almanac/service/';
}
protected function getObjectViewURI($object) {
return $object->getURI();
}
protected function getCreateNewObjectPolicy() {
return $this->getApplication()->getPolicy(
AlmanacCreateServicesCapability::CAPABILITY);
}
protected function buildCustomEditFields($object) {
return array(
id(new PhabricatorTextEditField())
->setKey('name')
->setLabel(pht('Name'))
->setDescription(pht('Name of the service.'))
->setTransactionType(AlmanacServiceTransaction::TYPE_NAME)
->setIsRequired(true)
->setValue($object->getName()),
);
}
}

View file

@ -152,4 +152,28 @@ final class AlmanacServiceEditor
return $errors;
}
protected function validateAllTransactions(
PhabricatorLiskDAO $object,
array $xactions) {
$errors = parent::validateAllTransactions($object, $xactions);
if ($object->isClusterService()) {
$can_manage = PhabricatorPolicyFilter::hasCapability(
$this->getActor(),
new PhabricatorAlmanacApplication(),
AlmanacManageClusterServicesCapability::CAPABILITY);
if (!$can_manage) {
$errors[] = new PhabricatorApplicationTransactionValidationError(
null,
pht('Restricted'),
pht('You do not have permission to manage cluster services.'),
null);
}
}
return $errors;
}
}