1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-12-19 20:10:55 +01:00

Convert Nuance Sources to EditEngine

Summary: Ref T10537. Converts sources to EditEngine.

Test Plan:
  - Created a new source.
  - Edited an existing source.
  - Submitted a complaint with the complaint form.

Reviewers: chad

Reviewed By: chad

Maniphest Tasks: T10537

Differential Revision: https://secure.phabricator.com/D15434
This commit is contained in:
epriestley 2016-03-08 05:09:25 -08:00
parent 8a7c963908
commit aa5df5fb07
14 changed files with 235 additions and 379 deletions

View file

@ -1460,12 +1460,12 @@ phutil_register_library_map(array(
'NuanceSource' => 'applications/nuance/storage/NuanceSource.php',
'NuanceSourceActionController' => 'applications/nuance/controller/NuanceSourceActionController.php',
'NuanceSourceController' => 'applications/nuance/controller/NuanceSourceController.php',
'NuanceSourceCreateController' => 'applications/nuance/controller/NuanceSourceCreateController.php',
'NuanceSourceDefaultEditCapability' => 'applications/nuance/capability/NuanceSourceDefaultEditCapability.php',
'NuanceSourceDefaultViewCapability' => 'applications/nuance/capability/NuanceSourceDefaultViewCapability.php',
'NuanceSourceDefinition' => 'applications/nuance/source/NuanceSourceDefinition.php',
'NuanceSourceDefinitionTestCase' => 'applications/nuance/source/__tests__/NuanceSourceDefinitionTestCase.php',
'NuanceSourceEditController' => 'applications/nuance/controller/NuanceSourceEditController.php',
'NuanceSourceEditEngine' => 'applications/nuance/editor/NuanceSourceEditEngine.php',
'NuanceSourceEditor' => 'applications/nuance/editor/NuanceSourceEditor.php',
'NuanceSourceListController' => 'applications/nuance/controller/NuanceSourceListController.php',
'NuanceSourceManageCapability' => 'applications/nuance/capability/NuanceSourceManageCapability.php',
@ -5716,12 +5716,12 @@ phutil_register_library_map(array(
),
'NuanceSourceActionController' => 'NuanceController',
'NuanceSourceController' => 'NuanceController',
'NuanceSourceCreateController' => 'NuanceSourceController',
'NuanceSourceDefaultEditCapability' => 'PhabricatorPolicyCapability',
'NuanceSourceDefaultViewCapability' => 'PhabricatorPolicyCapability',
'NuanceSourceDefinition' => 'Phobject',
'NuanceSourceDefinitionTestCase' => 'PhabricatorTestCase',
'NuanceSourceEditController' => 'NuanceSourceController',
'NuanceSourceEditEngine' => 'PhabricatorEditEngine',
'NuanceSourceEditor' => 'PhabricatorApplicationTransactionEditor',
'NuanceSourceListController' => 'NuanceSourceController',
'NuanceSourceManageCapability' => 'PhabricatorPolicyCapability',

View file

@ -46,16 +46,13 @@ final class PhabricatorNuanceApplication extends PhabricatorApplication {
),
'source/' => array(
$this->getQueryRoutePattern() => 'NuanceSourceListController',
$this->getEditRoutePattern('edit/') => 'NuanceSourceEditController',
'view/(?P<id>[1-9]\d*)/' => 'NuanceSourceViewController',
'edit/(?P<id>[1-9]\d*)/' => 'NuanceSourceEditController',
'new/(?P<type>[^/]+)/' => 'NuanceSourceEditController',
'create/' => 'NuanceSourceCreateController',
),
'queue/' => array(
$this->getQueryRoutePattern() => 'NuanceQueueListController',
$this->getEditRoutePattern('edit/') => 'NuanceQueueEditController',
'view/(?P<id>[1-9]\d*)/' => 'NuanceQueueViewController',
'new/' => 'NuanceQueueEditController',
),
'requestor/' => array(
'view/(?P<id>[1-9]\d*)/' => 'NuanceRequestorViewController',

View file

@ -49,7 +49,7 @@ final class NuanceItemViewController extends NuanceController {
phabricator_datetime($item->getDateCreated(), $viewer));
$source = $item->getSource();
$definition = $source->requireDefinition();
$definition = $source->getDefinition();
$definition->renderItemViewProperties(
$viewer,

View file

@ -12,16 +12,9 @@ final class NuanceQueueListController
protected function buildApplicationCrumbs() {
$crumbs = parent::buildApplicationCrumbs();
// TODO: Maybe use SourceManage capability?
$can_create = true;
$crumbs->addAction(
id(new PHUIListItemView())
->setName(pht('Create Queue'))
->setHref($this->getApplicationURI('queue/new/'))
->setIcon('fa-plus-square')
->setDisabled(!$can_create)
->setWorkflow(!$can_create));
id(new NuanceQueueEditEngine())
->setViewer($this->getViewer())
->addActionToCrumbs($crumbs);
return $crumbs;
}

View file

@ -13,8 +13,11 @@ final class NuanceSourceActionController extends NuanceController {
return new Aphront404Response();
}
$def = $source->requireDefinition();
$def->setActor($viewer);
$def = $source->getDefinition();
$def
->setViewer($viewer)
->setSource($source);
$response = $def->handleActionRequest($request);
if ($response instanceof AphrontResponse) {
@ -25,14 +28,10 @@ final class NuanceSourceActionController extends NuanceController {
$crumbs = $this->buildApplicationCrumbs();
$crumbs->addTextCrumb($title);
return $this->buildApplicationPage(
array(
$crumbs,
$response,
),
array(
'title' => $title,
));
return $this->newPage()
->setTitle($title)
->setCrumbs($crumbs)
->appendChild($response);
}
}

View file

@ -1,58 +0,0 @@
<?php
final class NuanceSourceCreateController
extends NuanceSourceController {
public function handleRequest(AphrontRequest $request) {
$can_edit = $this->requireApplicationCapability(
NuanceSourceManageCapability::CAPABILITY);
$viewer = $this->getViewer();
$map = NuanceSourceDefinition::getAllDefinitions();
$cancel_uri = $this->getApplicationURI('source/');
if ($request->isFormPost()) {
$type = $request->getStr('type');
if (isset($map[$type])) {
$uri = $this->getApplicationURI('source/new/'.$type.'/');
return id(new AphrontRedirectResponse())->setURI($uri);
}
}
$source_types = id(new AphrontFormRadioButtonControl())
->setName('type')
->setLabel(pht('Source Type'));
foreach ($map as $type => $definition) {
$source_types->addButton(
$type,
$definition->getName(),
$definition->getSourceDescription());
}
$form = id(new AphrontFormView())
->setUser($viewer)
->appendChild($source_types)
->appendChild(
id(new AphrontFormSubmitControl())
->setValue(pht('Continue'))
->addCancelButton($cancel_uri));
$box = id(new PHUIObjectBoxView())
->setHeaderText(pht('Choose Source Type'))
->appendChild($form);
$crumbs = $this->buildApplicationCrumbs();
$crumbs->addTextCrumb(pht('Sources'), $cancel_uri);
$crumbs->addTextCrumb(pht('New'));
return $this->buildApplicationPage(
array(
$crumbs,
$box,
),
array(
'title' => pht('Choose Source Type'),
));
}
}

View file

@ -4,70 +4,73 @@ final class NuanceSourceEditController
extends NuanceSourceController {
public function handleRequest(AphrontRequest $request) {
$can_edit = $this->requireApplicationCapability(
NuanceSourceManageCapability::CAPABILITY);
$engine = id(new NuanceSourceEditEngine())
->setController($this);
$viewer = $this->getViewer();
$id = $request->getURIData('id');
if (!$id) {
$this->requireApplicationCapability(
NuanceSourceManageCapability::CAPABILITY);
$sources_uri = $this->getApplicationURI('source/');
$source_id = $request->getURIData('id');
$is_new = !$source_id;
if ($is_new) {
$source = NuanceSource::initializeNewSource($viewer);
$type = $request->getURIData('type');
$cancel_uri = $this->getApplicationURI('source/');
$map = NuanceSourceDefinition::getAllDefinitions();
if (empty($map[$type])) {
return new Aphront404Response();
$source_type = $request->getStr('sourceType');
if (!isset($map[$source_type])) {
return $this->buildSourceTypeResponse($cancel_uri);
}
$source->setType($type);
$cancel_uri = $sources_uri;
} else {
$source = id(new NuanceSourceQuery())
->setViewer($viewer)
->withIDs(array($source_id))
->requireCapabilities(
array(
PhabricatorPolicyCapability::CAN_VIEW,
PhabricatorPolicyCapability::CAN_EDIT,
))
->executeOne();
if (!$source) {
return new Aphront404Response();
}
$cancel_uri = $source->getURI();
$engine
->setSourceDefinition($map[$source_type])
->addContextParameter('sourceType', $source_type);
}
$definition = $source->requireDefinition();
$definition->setActor($viewer);
return $engine->buildResponse();
}
$response = $definition->buildEditLayout($request);
if ($response instanceof AphrontResponse) {
return $response;
private function buildSourceTypeResponse($cancel_uri) {
$viewer = $this->getViewer();
$request = $this->getRequest();
$map = NuanceSourceDefinition::getAllDefinitions();
$errors = array();
$e_source = null;
if ($request->isFormPost()) {
$errors[] = pht('You must choose a source type.');
$e_source = pht('Required');
}
$layout = $response;
$source_types = id(new AphrontFormRadioButtonControl())
->setName('sourceType')
->setLabel(pht('Source Type'));
foreach ($map as $type => $definition) {
$source_types->addButton(
$type,
$definition->getName(),
$definition->getSourceDescription());
}
$form = id(new AphrontFormView())
->setUser($viewer)
->appendChild($source_types)
->appendChild(
id(new AphrontFormSubmitControl())
->setValue(pht('Continue'))
->addCancelButton($cancel_uri));
$box = id(new PHUIObjectBoxView())
->setFormErrors($errors)
->setHeaderText(pht('Choose Source Type'))
->appendChild($form);
$crumbs = $this->buildApplicationCrumbs();
$crumbs->addTextCrumb(pht('Sources'), $sources_uri);
$crumbs->addTextCrumb(pht('Sources'), $cancel_uri);
$crumbs->addTextCrumb(pht('New'));
if ($is_new) {
$crumbs->addTextCrumb(pht('New'));
} else {
$crumbs->addTextCrumb($source->getName(), $cancel_uri);
$crumbs->addTextCrumb(pht('Edit'));
}
return $this->buildApplicationPage(
array(
$crumbs,
$layout,
),
array(
'title' => $definition->getEditTitle(),
));
return $this->newPage()
->setTitle(pht('Choose Source Type'))
->setCrumbs($crumbs)
->appendChild($box);
}
}

View file

@ -12,16 +12,9 @@ final class NuanceSourceListController
protected function buildApplicationCrumbs() {
$crumbs = parent::buildApplicationCrumbs();
$can_create = $this->hasApplicationCapability(
NuanceSourceManageCapability::CAPABILITY);
$crumbs->addAction(
id(new PHUIListItemView())
->setName(pht('Create Source'))
->setHref($this->getApplicationURI('source/create/'))
->setIcon('fa-plus-square')
->setDisabled(!$can_create)
->setWorkflow(!$can_create));
id(new NuanceSourceEditEngine())
->setViewer($this->getViewer())
->addActionToCrumbs($crumbs);
return $crumbs;
}

View file

@ -84,7 +84,12 @@ final class NuanceSourceViewController
->setWorkflow(!$can_edit));
$request = $this->getRequest();
$definition = $source->requireDefinition();
$definition = $source->getDefinition();
$definition
->setViewer($viewer)
->setSource($source);
$source_actions = $definition->getSourceViewActions($request);
foreach ($source_actions as $source_action) {
$curtain->addAction($source_action);
@ -100,7 +105,8 @@ final class NuanceSourceViewController
$properties = id(new PHUIPropertyListView())
->setViewer($viewer);
$definition = $source->requireDefinition();
$definition = $source->getDefinition();
$properties->addProperty(
pht('Source Type'),
$definition->getName());

View file

@ -0,0 +1,108 @@
<?php
final class NuanceSourceEditEngine
extends PhabricatorEditEngine {
const ENGINECONST = 'nuance.source';
private $sourceDefinition;
public function setSourceDefinition(
NuanceSourceDefinition $source_definition) {
$this->sourceDefinition = $source_definition;
return $this;
}
public function getSourceDefinition() {
return $this->sourceDefinition;
}
public function isEngineConfigurable() {
return false;
}
public function getEngineName() {
return pht('Nuance Sources');
}
public function getSummaryHeader() {
return pht('Edit Nuance Source Configurations');
}
public function getSummaryText() {
return pht('This engine is used to edit Nuance sources.');
}
public function getEngineApplicationClass() {
return 'PhabricatorNuanceApplication';
}
protected function newEditableObject() {
$viewer = $this->getViewer();
$definition = $this->getSourceDefinition();
if (!$definition) {
throw new PhutilInvalidStateException('setSourceDefinition');
}
return NuanceSource::initializeNewSource(
$viewer,
$definition);
}
protected function newObjectQuery() {
return new NuanceSourceQuery();
}
protected function getObjectCreateTitleText($object) {
return pht('Create Source');
}
protected function getObjectCreateButtonText($object) {
return pht('Create Source');
}
protected function getObjectEditTitleText($object) {
return pht('Edit Source: %s', $object->getName());
}
protected function getObjectEditShortText($object) {
return pht('Edit Source');
}
protected function getObjectCreateShortText() {
return pht('Create Source');
}
protected function getEditorURI() {
return '/nuance/source/edit/';
}
protected function getObjectCreateCancelURI($object) {
return '/nuance/source/';
}
protected function getObjectViewURI($object) {
return $object->getURI();
}
protected function buildCustomEditFields($object) {
return array(
id(new PhabricatorTextEditField())
->setKey('name')
->setLabel(pht('Name'))
->setDescription(pht('Name of the source.'))
->setTransactionType(NuanceSourceTransaction::TYPE_NAME)
->setIsRequired(true)
->setValue($object->getName()),
id(new PhabricatorDatasourceEditField())
->setKey('defaultQueue')
->setLabel(pht('Default Queue'))
->setDescription(pht('Default queue.'))
->setTransactionType(NuanceSourceTransaction::TYPE_DEFAULT_QUEUE)
->setDatasource(new NuanceQueueDatasource())
->setSingleValue($object->getDefaultQueuePHID()),
);
}
}

View file

@ -30,6 +30,23 @@ final class NuanceSourceQuery
return $this->loadStandardPage($this->newResultObject());
}
protected function willFilterPage(array $sources) {
$all_types = NuanceSourceDefinition::getAllDefinitions();
foreach ($sources as $key => $source) {
$definition = idx($all_types, $source->getType());
if (!$definition) {
$this->didRejectResult($source);
unset($sources[$key]);
continue;
}
$source->attachDefinition($definition);
}
return $sources;
}
protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) {
$where = parent::buildWhereClauseParts($conn);

View file

@ -30,25 +30,6 @@ final class NuancePhabricatorFormSourceDefinition
return null;
}
protected function augmentEditForm(
AphrontFormView $form,
PhabricatorApplicationTransactionValidationException $ex = null) {
/* TODO - add a box to allow for custom fields to be defined here, so that
* these NuanceSource objects made from this definition can be used to
* capture arbitrary data */
return $form;
}
protected function buildTransactions(AphrontRequest $request) {
$transactions = parent::buildTransactions($request);
// TODO -- as above
return $transactions;
}
public function renderView() {}
public function renderListView() {}

View file

@ -5,42 +5,31 @@
*/
abstract class NuanceSourceDefinition extends Phobject {
private $actor;
private $sourceObject;
private $viewer;
private $source;
public function setActor(PhabricatorUser $actor) {
$this->actor = $actor;
public function setViewer(PhabricatorUser $viewer) {
$this->viewer = $viewer;
return $this;
}
public function getActor() {
return $this->actor;
}
public function requireActor() {
$actor = $this->getActor();
if (!$actor) {
throw new PhutilInvalidStateException('setActor');
public function getViewer() {
if (!$this->viewer) {
throw new PhutilInvalidStateException('setViewer');
}
return $actor;
return $this->viewer;
}
public function setSourceObject(NuanceSource $source) {
$source->setType($this->getSourceTypeConstant());
$this->sourceObject = $source;
public function setSource(NuanceSource $source) {
$this->source = $source;
return $this;
}
public function getSourceObject() {
return $this->sourceObject;
}
public function requireSourceObject() {
$source = $this->getSourceObject();
if (!$source) {
throw new PhutilInvalidStateException('setSourceObject');
public function getSource() {
if (!$this->source) {
throw new PhutilInvalidStateException('setSource');
}
return $source;
return $this->source;
}
public function getSourceViewActions(AphrontRequest $request) {
@ -84,165 +73,6 @@ abstract class NuanceSourceDefinition extends Phobject {
*/
abstract public function updateItems();
private function loadSourceObjectPolicies(
PhabricatorUser $user,
NuanceSource $source) {
$user = $this->requireActor();
$source = $this->requireSourceObject();
return id(new PhabricatorPolicyQuery())
->setViewer($user)
->setObject($source)
->execute();
}
final public function getEditTitle() {
$source = $this->requireSourceObject();
if ($source->getPHID()) {
$title = pht('Edit "%s" source.', $source->getName());
} else {
$title = pht('Create a new "%s" source.', $this->getName());
}
return $title;
}
final public function buildEditLayout(AphrontRequest $request) {
$actor = $this->requireActor();
$source = $this->requireSourceObject();
$form_errors = array();
$error_messages = array();
$transactions = array();
$validation_exception = null;
if ($request->isFormPost()) {
$transactions = $this->buildTransactions($request);
try {
$editor = id(new NuanceSourceEditor())
->setActor($actor)
->setContentSourceFromRequest($request)
->setContinueOnNoEffect(true)
->applyTransactions($source, $transactions);
return id(new AphrontRedirectResponse())
->setURI($source->getURI());
} catch (PhabricatorApplicationTransactionValidationException $ex) {
$validation_exception = $ex;
}
}
$form = $this->renderEditForm($validation_exception);
$layout = id(new PHUIObjectBoxView())
->setHeaderText($this->getEditTitle())
->setValidationException($validation_exception)
->setFormErrors($error_messages)
->setForm($form);
return $layout;
}
/**
* Code to create a form to edit the @{class:NuanceItem} you are defining.
*
* return @{class:AphrontFormView}
*/
private function renderEditForm(
PhabricatorApplicationTransactionValidationException $ex = null) {
$user = $this->requireActor();
$source = $this->requireSourceObject();
$policies = $this->loadSourceObjectPolicies($user, $source);
$e_name = null;
if ($ex) {
$e_name = $ex->getShortMessage(NuanceSourceTransaction::TYPE_NAME);
}
$form = id(new AphrontFormView())
->setUser($user)
->appendChild(
id(new AphrontFormTextControl())
->setLabel(pht('Name'))
->setName('name')
->setError($e_name)
->setValue($source->getName()));
$form = $this->augmentEditForm($form, $ex);
$default_phid = $source->getDefaultQueuePHID();
if ($default_phid) {
$default_queues = array($default_phid);
} else {
$default_queues = array();
}
$form
->appendControl(
id(new AphrontFormTokenizerControl())
->setLabel(pht('Default Queue'))
->setName('defaultQueuePHIDs')
->setLimit(1)
->setDatasource(new NuanceQueueDatasource())
->setValue($default_queues))
->appendChild(
id(new AphrontFormPolicyControl())
->setUser($user)
->setCapability(PhabricatorPolicyCapability::CAN_VIEW)
->setPolicyObject($source)
->setPolicies($policies)
->setName('viewPolicy'))
->appendChild(
id(new AphrontFormPolicyControl())
->setUser($user)
->setCapability(PhabricatorPolicyCapability::CAN_EDIT)
->setPolicyObject($source)
->setPolicies($policies)
->setName('editPolicy'))
->appendChild(
id(new AphrontFormSubmitControl())
->addCancelButton($source->getURI())
->setValue(pht('Save')));
return $form;
}
/**
* return @{class:AphrontFormView}
*/
protected function augmentEditForm(
AphrontFormView $form,
PhabricatorApplicationTransactionValidationException $ex = null) {
return $form;
}
/**
* Hook to build up @{class:PhabricatorTransactions}.
*
* return array $transactions
*/
protected function buildTransactions(AphrontRequest $request) {
$transactions = array();
$transactions[] = id(new NuanceSourceTransaction())
->setTransactionType(PhabricatorTransactions::TYPE_EDIT_POLICY)
->setNewValue($request->getStr('editPolicy'));
$transactions[] = id(new NuanceSourceTransaction())
->setTransactionType(PhabricatorTransactions::TYPE_VIEW_POLICY)
->setNewValue($request->getStr('viewPolicy'));
$transactions[] = id(new NuanceSourceTransaction())
->setTransactionType(NuanceSourceTransaction::TYPE_NAME)
->setNewvalue($request->getStr('name'));
$transactions[] = id(new NuanceSourceTransaction())
->setTransactionType(NuanceSourceTransaction::TYPE_DEFAULT_QUEUE)
->setNewvalue(head($request->getArr('defaultQueuePHIDs')));
return $transactions;
}
abstract public function renderView();
abstract public function renderListView();
@ -256,8 +86,7 @@ abstract class NuanceSourceDefinition extends Phobject {
// TODO: Should we have a tighter actor/viewer model? Requestors will
// often have no real user associated with them...
$actor = PhabricatorUser::getOmnipotentUser();
$source = $this->requireSourceObject();
$source = $this->getSource();
$item = NuanceItem::initializeNewItem();
@ -317,7 +146,7 @@ abstract class NuanceSourceDefinition extends Phobject {
}
public function getActionURI($path = null) {
$source_id = $this->getSourceObject()->getID();
$source_id = $this->getSource()->getID();
return '/action/'.$source_id.'/'.ltrim($path, '/');
}

View file

@ -13,7 +13,7 @@ final class NuanceSource extends NuanceDAO
protected $editPolicy;
protected $defaultQueuePHID;
private $definition;
private $definition = self::ATTACHABLE;
protected function getConfiguration() {
return array(
@ -49,7 +49,9 @@ final class NuanceSource extends NuanceDAO
return '/nuance/source/view/'.$this->getID().'/';
}
public static function initializeNewSource(PhabricatorUser $actor) {
public static function initializeNewSource(
PhabricatorUser $actor,
NuanceSourceDefinition $definition) {
$app = id(new PhabricatorApplicationQuery())
->setViewer($actor)
->withClasses(array('PhabricatorNuanceApplication'))
@ -62,32 +64,18 @@ final class NuanceSource extends NuanceDAO
return id(new NuanceSource())
->setViewPolicy($view_policy)
->setEditPolicy($edit_policy);
->setEditPolicy($edit_policy)
->setType($definition->getSourceTypeConstant())
->attachDefinition($definition);
}
public function getDefinition() {
if ($this->definition === null) {
$definitions = NuanceSourceDefinition::getAllDefinitions();
if (isset($definitions[$this->getType()])) {
$definition = clone $definitions[$this->getType()];
$definition->setSourceObject($this);
$this->definition = $definition;
}
}
return $this->definition;
return $this->assertAttached($this->definition);
}
public function requireDefinition() {
$definition = $this->getDefinition();
if (!$definition) {
throw new Exception(
pht(
'Unable to load source definition implementation for source '.
'type "%s".',
$this->getType()));
}
return $definition;
public function attachDefinition(NuanceSourceDefinition $definition) {
$this->definition = $definition;
return $this;
}