mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-22 23:02:42 +01:00
Nuance - federate out the design of NuanceSource via NuanceSourceDefinition
Summary: ...and get the basic edit flow "working" for a new NuanceSourceDefinition - the Phabricator Form. ...and fix a dumb bug in the query class so when you redirect to the view page / try to edit an existing NuanceSource you don't fatal. Test Plan: played around with the edit form and it worked! Reviewers: epriestley Reviewed By: epriestley CC: Korvin, epriestley, aran Differential Revision: https://secure.phabricator.com/D7585
This commit is contained in:
parent
a07f444f2a
commit
7b718bb033
13 changed files with 557 additions and 82 deletions
11
resources/sql/patches/20131120.nuancesourcetype.sql
Normal file
11
resources/sql/patches/20131120.nuancesourcetype.sql
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
ALTER TABLE {$NAMESPACE}_nuance.nuance_source
|
||||||
|
DROP KEY key_type;
|
||||||
|
|
||||||
|
ALTER TABLE {$NAMESPACE}_nuance.nuance_source
|
||||||
|
DROP COLUMN type;
|
||||||
|
|
||||||
|
ALTER TABLE {$NAMESPACE}_nuance.nuance_source
|
||||||
|
ADD type VARCHAR(32) NOT NULL COLLATE utf8_bin AFTER name;
|
||||||
|
|
||||||
|
ALTER TABLE {$NAMESPACE}_nuance.nuance_source
|
||||||
|
ADD KEY `key_type` (type, dateModified);
|
|
@ -867,6 +867,7 @@ phutil_register_library_map(array(
|
||||||
'NuancePHIDTypeQueue' => 'applications/nuance/phid/NuancePHIDTypeQueue.php',
|
'NuancePHIDTypeQueue' => 'applications/nuance/phid/NuancePHIDTypeQueue.php',
|
||||||
'NuancePHIDTypeRequestor' => 'applications/nuance/phid/NuancePHIDTypeRequestor.php',
|
'NuancePHIDTypeRequestor' => 'applications/nuance/phid/NuancePHIDTypeRequestor.php',
|
||||||
'NuancePHIDTypeSource' => 'applications/nuance/phid/NuancePHIDTypeSource.php',
|
'NuancePHIDTypeSource' => 'applications/nuance/phid/NuancePHIDTypeSource.php',
|
||||||
|
'NuancePhabricatorFormSourceDefinition' => 'applications/nuance/source/NuancePhabricatorFormSourceDefinition.php',
|
||||||
'NuanceQuery' => 'applications/nuance/query/NuanceQuery.php',
|
'NuanceQuery' => 'applications/nuance/query/NuanceQuery.php',
|
||||||
'NuanceQueue' => 'applications/nuance/storage/NuanceQueue.php',
|
'NuanceQueue' => 'applications/nuance/storage/NuanceQueue.php',
|
||||||
'NuanceQueueEditController' => 'applications/nuance/controller/NuanceQueueEditController.php',
|
'NuanceQueueEditController' => 'applications/nuance/controller/NuanceQueueEditController.php',
|
||||||
|
@ -887,13 +888,13 @@ phutil_register_library_map(array(
|
||||||
'NuanceRequestorTransactionQuery' => 'applications/nuance/query/NuanceRequestorTransactionQuery.php',
|
'NuanceRequestorTransactionQuery' => 'applications/nuance/query/NuanceRequestorTransactionQuery.php',
|
||||||
'NuanceRequestorViewController' => 'applications/nuance/controller/NuanceRequestorViewController.php',
|
'NuanceRequestorViewController' => 'applications/nuance/controller/NuanceRequestorViewController.php',
|
||||||
'NuanceSource' => 'applications/nuance/storage/NuanceSource.php',
|
'NuanceSource' => 'applications/nuance/storage/NuanceSource.php',
|
||||||
|
'NuanceSourceDefinition' => 'applications/nuance/source/NuanceSourceDefinition.php',
|
||||||
'NuanceSourceEditController' => 'applications/nuance/controller/NuanceSourceEditController.php',
|
'NuanceSourceEditController' => 'applications/nuance/controller/NuanceSourceEditController.php',
|
||||||
'NuanceSourceEditor' => 'applications/nuance/editor/NuanceSourceEditor.php',
|
'NuanceSourceEditor' => 'applications/nuance/editor/NuanceSourceEditor.php',
|
||||||
'NuanceSourceQuery' => 'applications/nuance/query/NuanceSourceQuery.php',
|
'NuanceSourceQuery' => 'applications/nuance/query/NuanceSourceQuery.php',
|
||||||
'NuanceSourceTransaction' => 'applications/nuance/storage/NuanceSourceTransaction.php',
|
'NuanceSourceTransaction' => 'applications/nuance/storage/NuanceSourceTransaction.php',
|
||||||
'NuanceSourceTransactionComment' => 'applications/nuance/storage/NuanceSourceTransactionComment.php',
|
'NuanceSourceTransactionComment' => 'applications/nuance/storage/NuanceSourceTransactionComment.php',
|
||||||
'NuanceSourceTransactionQuery' => 'applications/nuance/query/NuanceSourceTransactionQuery.php',
|
'NuanceSourceTransactionQuery' => 'applications/nuance/query/NuanceSourceTransactionQuery.php',
|
||||||
'NuanceSourceType' => 'applications/nuance/constants/NuanceSourceType.php',
|
|
||||||
'NuanceSourceViewController' => 'applications/nuance/controller/NuanceSourceViewController.php',
|
'NuanceSourceViewController' => 'applications/nuance/controller/NuanceSourceViewController.php',
|
||||||
'NuanceTransaction' => 'applications/nuance/storage/NuanceTransaction.php',
|
'NuanceTransaction' => 'applications/nuance/storage/NuanceTransaction.php',
|
||||||
'OwnersPackageReplyHandler' => 'applications/owners/mail/OwnersPackageReplyHandler.php',
|
'OwnersPackageReplyHandler' => 'applications/owners/mail/OwnersPackageReplyHandler.php',
|
||||||
|
@ -3238,6 +3239,7 @@ phutil_register_library_map(array(
|
||||||
'NuancePHIDTypeQueue' => 'PhabricatorPHIDType',
|
'NuancePHIDTypeQueue' => 'PhabricatorPHIDType',
|
||||||
'NuancePHIDTypeRequestor' => 'PhabricatorPHIDType',
|
'NuancePHIDTypeRequestor' => 'PhabricatorPHIDType',
|
||||||
'NuancePHIDTypeSource' => 'PhabricatorPHIDType',
|
'NuancePHIDTypeSource' => 'PhabricatorPHIDType',
|
||||||
|
'NuancePhabricatorFormSourceDefinition' => 'NuanceSourceDefinition',
|
||||||
'NuanceQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
|
'NuanceQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
|
||||||
'NuanceQueue' =>
|
'NuanceQueue' =>
|
||||||
array(
|
array(
|
||||||
|
@ -3266,13 +3268,13 @@ phutil_register_library_map(array(
|
||||||
0 => 'NuanceDAO',
|
0 => 'NuanceDAO',
|
||||||
1 => 'PhabricatorPolicyInterface',
|
1 => 'PhabricatorPolicyInterface',
|
||||||
),
|
),
|
||||||
|
'NuanceSourceDefinition' => 'Phobject',
|
||||||
'NuanceSourceEditController' => 'NuanceController',
|
'NuanceSourceEditController' => 'NuanceController',
|
||||||
'NuanceSourceEditor' => 'PhabricatorApplicationTransactionEditor',
|
'NuanceSourceEditor' => 'PhabricatorApplicationTransactionEditor',
|
||||||
'NuanceSourceQuery' => 'NuanceQuery',
|
'NuanceSourceQuery' => 'NuanceQuery',
|
||||||
'NuanceSourceTransaction' => 'NuanceTransaction',
|
'NuanceSourceTransaction' => 'NuanceTransaction',
|
||||||
'NuanceSourceTransactionComment' => 'PhabricatorApplicationTransactionComment',
|
'NuanceSourceTransactionComment' => 'PhabricatorApplicationTransactionComment',
|
||||||
'NuanceSourceTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
|
'NuanceSourceTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
|
||||||
'NuanceSourceType' => 'NuanceConstants',
|
|
||||||
'NuanceSourceViewController' => 'NuanceController',
|
'NuanceSourceViewController' => 'NuanceController',
|
||||||
'NuanceTransaction' => 'PhabricatorApplicationTransaction',
|
'NuanceTransaction' => 'PhabricatorApplicationTransaction',
|
||||||
'OwnersPackageReplyHandler' => 'PhabricatorMailReplyHandler',
|
'OwnersPackageReplyHandler' => 'PhabricatorMailReplyHandler',
|
||||||
|
|
|
@ -23,6 +23,10 @@ final class PhabricatorApplicationNuance extends PhabricatorApplication {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getBaseURI() {
|
||||||
|
return '/nuance/';
|
||||||
|
}
|
||||||
|
|
||||||
public function getRoutes() {
|
public function getRoutes() {
|
||||||
return array(
|
return array(
|
||||||
'/nuance/' => array(
|
'/nuance/' => array(
|
||||||
|
|
|
@ -1,22 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
final class NuanceSourceType extends NuanceConstants {
|
|
||||||
|
|
||||||
/* internal source types */
|
|
||||||
const PHABRICATOR_FORM = 1;
|
|
||||||
|
|
||||||
/* social media source types */
|
|
||||||
const TWITTER = 101;
|
|
||||||
|
|
||||||
/* engineering media source types */
|
|
||||||
const GITHUB = 201;
|
|
||||||
|
|
||||||
|
|
||||||
public static function getSelectOptions() {
|
|
||||||
|
|
||||||
return array(
|
|
||||||
self::PHABRICATOR_FORM => pht('Phabricator Form'),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -28,7 +28,6 @@ final class NuanceSourceEditController extends NuanceController {
|
||||||
|
|
||||||
if ($is_new) {
|
if ($is_new) {
|
||||||
$source = NuanceSource::initializeNewSource($user);
|
$source = NuanceSource::initializeNewSource($user);
|
||||||
$title = pht('Create Source');
|
|
||||||
} else {
|
} else {
|
||||||
$source = id(new NuanceSourceQuery())
|
$source = id(new NuanceSourceQuery())
|
||||||
->setViewer($user)
|
->setViewer($user)
|
||||||
|
@ -39,71 +38,29 @@ final class NuanceSourceEditController extends NuanceController {
|
||||||
PhabricatorPolicyCapability::CAN_EDIT,
|
PhabricatorPolicyCapability::CAN_EDIT,
|
||||||
))
|
))
|
||||||
->executeOne();
|
->executeOne();
|
||||||
$title = pht('Edit Source');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$source) {
|
if (!$source) {
|
||||||
return new Aphront404Response();
|
return new Aphront404Response();
|
||||||
}
|
}
|
||||||
|
|
||||||
$error_view = null;
|
$definition = NuanceSourceDefinition::getDefinitionForSource($source);
|
||||||
$e_name = null;
|
$definition->setActor($user);
|
||||||
if ($request->isFormPost()) {
|
|
||||||
$error_view = id(new AphrontErrorView())
|
|
||||||
->setTitle(pht('This does not work at all yet.'));
|
|
||||||
}
|
|
||||||
|
|
||||||
$policies = id(new PhabricatorPolicyQuery())
|
$response = $definition->buildEditLayout($request);
|
||||||
->setViewer($user)
|
if ($response instanceof AphrontResponse) {
|
||||||
->setObject($source)
|
return $response;
|
||||||
->execute();
|
}
|
||||||
|
$layout = $response;
|
||||||
|
|
||||||
$crumbs = $this->buildApplicationCrumbs();
|
$crumbs = $this->buildApplicationCrumbs();
|
||||||
|
|
||||||
$form = id(new AphrontFormView())
|
|
||||||
->setUser($user)
|
|
||||||
->appendChild(
|
|
||||||
id(new AphrontFormTextControl())
|
|
||||||
->setLabel(pht('Name'))
|
|
||||||
->setName('name')
|
|
||||||
->setError($e_name)
|
|
||||||
->setValue($source->getName()))
|
|
||||||
->appendChild(
|
|
||||||
id(new AphrontFormSelectControl())
|
|
||||||
->setLabel(pht('Type'))
|
|
||||||
->setName('type')
|
|
||||||
->setOptions(NuanceSourceType::getSelectOptions())
|
|
||||||
->setValue($source->getType()))
|
|
||||||
->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())
|
|
||||||
->setValue(pht('Save')));
|
|
||||||
|
|
||||||
$layout = id(new PHUIObjectBoxView())
|
|
||||||
->setHeaderText($title)
|
|
||||||
->setFormError($error_view)
|
|
||||||
->setForm($form);
|
|
||||||
|
|
||||||
return $this->buildApplicationPage(
|
return $this->buildApplicationPage(
|
||||||
array(
|
array(
|
||||||
$crumbs,
|
$crumbs,
|
||||||
$layout,
|
$layout,
|
||||||
),
|
),
|
||||||
array(
|
array(
|
||||||
'title' => $title,
|
'title' => $definition->getEditTitle(),
|
||||||
'device' => true));
|
'device' => true));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,11 +18,11 @@ final class NuanceSourceViewController extends NuanceController {
|
||||||
|
|
||||||
public function processRequest() {
|
public function processRequest() {
|
||||||
$request = $this->getRequest();
|
$request = $this->getRequest();
|
||||||
$user = $request->getUser();
|
$viewer = $request->getUser();
|
||||||
|
|
||||||
$source_id = $this->getSourceID();
|
$source_id = $this->getSourceID();
|
||||||
$source = id(new NuanceSourceQuery())
|
$source = id(new NuanceSourceQuery())
|
||||||
->setViewer($user)
|
->setViewer($viewer)
|
||||||
->withIDs(array($source_id))
|
->withIDs(array($source_id))
|
||||||
->executeOne();
|
->executeOne();
|
||||||
|
|
||||||
|
@ -30,13 +30,107 @@ final class NuanceSourceViewController extends NuanceController {
|
||||||
return new Aphront404Response();
|
return new Aphront404Response();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$source_phid = $source->getPHID();
|
||||||
|
$xactions = id(new NuanceSourceTransactionQuery())
|
||||||
|
->setViewer($viewer)
|
||||||
|
->withObjectPHIDs(array($source_phid))
|
||||||
|
->execute();
|
||||||
|
|
||||||
|
$engine = id(new PhabricatorMarkupEngine())
|
||||||
|
->setViewer($viewer);
|
||||||
|
|
||||||
|
$timeline = id(new PhabricatorApplicationTransactionView())
|
||||||
|
->setUser($viewer)
|
||||||
|
->setObjectPHID($source_phid)
|
||||||
|
->setMarkupEngine($engine)
|
||||||
|
->setTransactions($xactions);
|
||||||
|
|
||||||
|
$title = pht('%s', $source->getName());
|
||||||
$crumbs = $this->buildApplicationCrumbs();
|
$crumbs = $this->buildApplicationCrumbs();
|
||||||
$title = 'TODO';
|
$crumbs->addCrumb(
|
||||||
|
id(new PhabricatorCrumbView())
|
||||||
|
->setName($title));
|
||||||
|
|
||||||
|
$header = $this->buildHeaderView($source);
|
||||||
|
$actions = $this->buildActionView($source);
|
||||||
|
$properties = $this->buildPropertyView($source, $actions);
|
||||||
|
|
||||||
|
$box = id(new PHUIObjectBoxView())
|
||||||
|
->setHeader($header)
|
||||||
|
->addPropertyList($properties);
|
||||||
|
|
||||||
return $this->buildApplicationPage(
|
return $this->buildApplicationPage(
|
||||||
$crumbs,
|
array(
|
||||||
|
$crumbs,
|
||||||
|
$box,
|
||||||
|
$timeline,
|
||||||
|
),
|
||||||
array(
|
array(
|
||||||
'title' => $title,
|
'title' => $title,
|
||||||
'device' => true));
|
'device' => true,
|
||||||
|
));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private function buildHeaderView(NuanceSource $source) {
|
||||||
|
$viewer = $this->getRequest()->getUser();
|
||||||
|
|
||||||
|
$header = id(new PHUIHeaderView())
|
||||||
|
->setUser($viewer)
|
||||||
|
->setHeader($source->getName())
|
||||||
|
->setPolicyObject($source);
|
||||||
|
|
||||||
|
return $header;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function buildActionView(NuanceSource $source) {
|
||||||
|
$viewer = $this->getRequest()->getUser();
|
||||||
|
$id = $source->getID();
|
||||||
|
|
||||||
|
$actions = id(new PhabricatorActionListView())
|
||||||
|
->setObjectURI($source->getURI())
|
||||||
|
->setUser($viewer);
|
||||||
|
|
||||||
|
$can_edit = PhabricatorPolicyFilter::hasCapability(
|
||||||
|
$viewer,
|
||||||
|
$source,
|
||||||
|
PhabricatorPolicyCapability::CAN_EDIT);
|
||||||
|
|
||||||
|
$actions->addAction(
|
||||||
|
id(new PhabricatorActionView())
|
||||||
|
->setName(pht('Edit Source'))
|
||||||
|
->setIcon('edit')
|
||||||
|
->setHref($this->getApplicationURI("source/edit/{$id}/"))
|
||||||
|
->setDisabled(!$can_edit)
|
||||||
|
->setWorkflow(!$can_edit));
|
||||||
|
|
||||||
|
return $actions;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function buildPropertyView(
|
||||||
|
NuanceSource $source,
|
||||||
|
PhabricatorActionListView $actions) {
|
||||||
|
$viewer = $this->getRequest()->getUser();
|
||||||
|
|
||||||
|
$properties = id(new PHUIPropertyListView())
|
||||||
|
->setUser($viewer)
|
||||||
|
->setObject($source)
|
||||||
|
->setActionList($actions);
|
||||||
|
|
||||||
|
$definition = NuanceSourceDefinition::getDefinitionForSource($source);
|
||||||
|
$properties->addProperty(
|
||||||
|
pht('Source Type'),
|
||||||
|
$definition->getName());
|
||||||
|
|
||||||
|
$descriptions = PhabricatorPolicyQuery::renderPolicyDescriptions(
|
||||||
|
$viewer,
|
||||||
|
$source);
|
||||||
|
|
||||||
|
$properties->addProperty(
|
||||||
|
pht('Editable By'),
|
||||||
|
$descriptions[PhabricatorPolicyCapability::CAN_EDIT]);
|
||||||
|
|
||||||
|
return $properties;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,8 @@ final class NuanceSourceEditor
|
||||||
public function getTransactionTypes() {
|
public function getTransactionTypes() {
|
||||||
$types = parent::getTransactionTypes();
|
$types = parent::getTransactionTypes();
|
||||||
|
|
||||||
|
$types[] = NuanceSourceTransaction::TYPE_NAME;
|
||||||
|
|
||||||
$types[] = PhabricatorTransactions::TYPE_EDGE;
|
$types[] = PhabricatorTransactions::TYPE_EDGE;
|
||||||
$types[] = PhabricatorTransactions::TYPE_COMMENT;
|
$types[] = PhabricatorTransactions::TYPE_COMMENT;
|
||||||
$types[] = PhabricatorTransactions::TYPE_VIEW_POLICY;
|
$types[] = PhabricatorTransactions::TYPE_VIEW_POLICY;
|
||||||
|
@ -14,4 +16,80 @@ final class NuanceSourceEditor
|
||||||
return $types;
|
return $types;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function getCustomTransactionOldValue(
|
||||||
|
PhabricatorLiskDAO $object,
|
||||||
|
PhabricatorApplicationTransaction $xaction) {
|
||||||
|
|
||||||
|
switch ($xaction->getTransactionType()) {
|
||||||
|
case NuanceSourceTransaction::TYPE_NAME:
|
||||||
|
return $object->getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
return parent::getCustomTransactionOldValue($object, $xaction);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getCustomTransactionNewValue(
|
||||||
|
PhabricatorLiskDAO $object,
|
||||||
|
PhabricatorApplicationTransaction $xaction) {
|
||||||
|
|
||||||
|
switch ($xaction->getTransactionType()) {
|
||||||
|
case NuanceSourceTransaction::TYPE_NAME:
|
||||||
|
return $xaction->getNewValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
return parent::getCustomTransactionNewValue($object, $xaction);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function applyCustomInternalTransaction(
|
||||||
|
PhabricatorLiskDAO $object,
|
||||||
|
PhabricatorApplicationTransaction $xaction) {
|
||||||
|
|
||||||
|
switch ($xaction->getTransactionType()) {
|
||||||
|
case NuanceSourceTransaction::TYPE_NAME:
|
||||||
|
$object->setName($xaction->getNewValue());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function applyCustomExternalTransaction(
|
||||||
|
PhabricatorLiskDAO $object,
|
||||||
|
PhabricatorApplicationTransaction $xaction) {
|
||||||
|
|
||||||
|
switch ($xaction->getTransactionType()) {
|
||||||
|
case NuanceSourceTransaction::TYPE_NAME:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
return parent::applyCustomExternalTransaction($object, $xaction);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function validateTransaction(
|
||||||
|
PhabricatorLiskDAO $object,
|
||||||
|
$type,
|
||||||
|
array $xactions) {
|
||||||
|
|
||||||
|
$errors = parent::validateTransaction($object, $type, $xactions);
|
||||||
|
|
||||||
|
switch ($type) {
|
||||||
|
case NuanceSourceTransaction::TYPE_NAME:
|
||||||
|
$missing = $this->validateIsEmptyTextField(
|
||||||
|
$object->getName(),
|
||||||
|
$xactions);
|
||||||
|
|
||||||
|
if ($missing) {
|
||||||
|
$error = new PhabricatorApplicationTransactionValidationError(
|
||||||
|
$type,
|
||||||
|
pht('Required'),
|
||||||
|
pht('Source name is required.'),
|
||||||
|
nonempty(last($xactions), null));
|
||||||
|
|
||||||
|
$error->setIsMissingFieldError(true);
|
||||||
|
$errors[] = $error;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $errors;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,7 +35,7 @@ final class NuanceSourceQuery
|
||||||
|
|
||||||
$data = queryfx_all(
|
$data = queryfx_all(
|
||||||
$conn_r,
|
$conn_r,
|
||||||
'SELECT FROM %T %Q %Q %Q',
|
'SELECT * FROM %T %Q %Q %Q',
|
||||||
$table->getTableName(),
|
$table->getTableName(),
|
||||||
$this->buildWhereClause($conn_r),
|
$this->buildWhereClause($conn_r),
|
||||||
$this->buildOrderClause($conn_r),
|
$this->buildOrderClause($conn_r),
|
||||||
|
|
|
@ -0,0 +1,43 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class NuancePhabricatorFormSourceDefinition
|
||||||
|
extends NuanceSourceDefinition {
|
||||||
|
|
||||||
|
public function getName() {
|
||||||
|
return pht('Phabricator Form');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getSourceTypeConstant() {
|
||||||
|
return 'phabricator-form';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function updateItems() {
|
||||||
|
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 defintion 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() {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
274
src/applications/nuance/source/NuanceSourceDefinition.php
Normal file
274
src/applications/nuance/source/NuanceSourceDefinition.php
Normal file
|
@ -0,0 +1,274 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
abstract class NuanceSourceDefinition extends Phobject {
|
||||||
|
|
||||||
|
private $actor;
|
||||||
|
private $sourceObject;
|
||||||
|
|
||||||
|
public function setActor(PhabricatorUser $actor) {
|
||||||
|
$this->actor = $actor;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
public function getActor() {
|
||||||
|
return $this->actor;
|
||||||
|
}
|
||||||
|
public function requireActor() {
|
||||||
|
$actor = $this->getActor();
|
||||||
|
if (!$actor) {
|
||||||
|
throw new Exception('You must "setActor()" first!');
|
||||||
|
}
|
||||||
|
return $actor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setSourceObject(NuanceSource $source) {
|
||||||
|
$source->setType($this->getSourceTypeConstant());
|
||||||
|
$this->sourceObject = $source;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
public function getSourceObject() {
|
||||||
|
return $this->sourceObject;
|
||||||
|
}
|
||||||
|
public function requireSourceObject() {
|
||||||
|
$source = $this->getSourceObject();
|
||||||
|
if (!$source) {
|
||||||
|
throw new Exception('You must "setSourceObject()" first!');
|
||||||
|
}
|
||||||
|
return $source;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getSelectOptions() {
|
||||||
|
$definitions = self::getAllDefinitions();
|
||||||
|
|
||||||
|
$options = array();
|
||||||
|
foreach ($definitions as $definition) {
|
||||||
|
$key = $definition->getSourceTypeConstant();
|
||||||
|
$name = $definition->getName();
|
||||||
|
$options[$key] = $name;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $options;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gives a @{class:NuanceSourceDefinition} object for a given
|
||||||
|
* @{class:NuanceSource}. Note you still need to @{method:setActor}
|
||||||
|
* before the @{class:NuanceSourceDefinition} object will be useful.
|
||||||
|
*/
|
||||||
|
public static function getDefinitionForSource(NuanceSource $source) {
|
||||||
|
$definitions = self::getAllDefinitions();
|
||||||
|
$map = mpull($definitions, null, 'getSourceTypeConstant');
|
||||||
|
$definition = $map[$source->getType()];
|
||||||
|
$definition->setSourceObject($source);
|
||||||
|
|
||||||
|
return $definition;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getAllDefinitions() {
|
||||||
|
static $definitions;
|
||||||
|
|
||||||
|
if ($definitions === null) {
|
||||||
|
$objects = id(new PhutilSymbolLoader())
|
||||||
|
->setAncestorClass(__CLASS__)
|
||||||
|
->loadObjects();
|
||||||
|
foreach ($objects as $definition) {
|
||||||
|
$key = $definition->getSourceTypeConstant();
|
||||||
|
$name = $definition->getName();
|
||||||
|
if (isset($definitions[$key])) {
|
||||||
|
$conflict = $definitions[$key];
|
||||||
|
throw new Exception(sprintf(
|
||||||
|
'Defintion %s conflicts with definition %s. This is a programming '.
|
||||||
|
'error.',
|
||||||
|
$conflict,
|
||||||
|
$name));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$definitions = $objects;
|
||||||
|
}
|
||||||
|
return $definitions;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A human readable string like "Twitter" or "Phabricator Form".
|
||||||
|
*/
|
||||||
|
abstract public function getName();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This should be a any VARCHAR(32).
|
||||||
|
*
|
||||||
|
* @{method:getAllDefinitions} will throw if you choose a string that
|
||||||
|
* collides with another @{class:NuanceSourceDefinition} class.
|
||||||
|
*/
|
||||||
|
abstract public function getSourceTypeConstant();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Code to create and update @{class:NuanceItem}s and
|
||||||
|
* @{class:NuanceRequestor}s via daemons goes here.
|
||||||
|
*
|
||||||
|
* If that does not make sense for the @{class:NuanceSource} you are
|
||||||
|
* defining, simply return null. For example,
|
||||||
|
* @{class:NuancePhabricatorFormSourceDefinition} since these are one-way
|
||||||
|
* contact forms.
|
||||||
|
*/
|
||||||
|
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)
|
||||||
|
->setForm($form);
|
||||||
|
if ($error_messages) {
|
||||||
|
$layout->setFormError($this->renderEditErrorView($error_messages));
|
||||||
|
}
|
||||||
|
|
||||||
|
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()))
|
||||||
|
->appendChild(
|
||||||
|
id(new AphrontFormSelectControl())
|
||||||
|
->setLabel(pht('Type'))
|
||||||
|
->setName('type')
|
||||||
|
->setOptions(self::getSelectOptions())
|
||||||
|
->setValue($source->getType()));
|
||||||
|
|
||||||
|
$form = $this->augmentEditForm($form, $ex);
|
||||||
|
|
||||||
|
$form
|
||||||
|
->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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* return @{class:AphrontErrorView}
|
||||||
|
*/
|
||||||
|
public function renderEditErrorView(array $errors) {
|
||||||
|
return id(new AphrontErrorView())
|
||||||
|
->setTitle(pht('Error with submission.'))
|
||||||
|
->setErrors($errors);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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'));
|
||||||
|
|
||||||
|
return $transactions;
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract public function renderView();
|
||||||
|
|
||||||
|
abstract public function renderListView();
|
||||||
|
}
|
||||||
|
|
|
@ -47,9 +47,14 @@ final class NuanceSource
|
||||||
$edit_policy = $app->getPolicy(
|
$edit_policy = $app->getPolicy(
|
||||||
NuanceCapabilitySourceDefaultEdit::CAPABILITY);
|
NuanceCapabilitySourceDefaultEdit::CAPABILITY);
|
||||||
|
|
||||||
|
$definitions = NuanceSourceDefinition::getAllDefinitions();
|
||||||
|
$lucky_definition = head($definitions);
|
||||||
|
|
||||||
return id(new NuanceSource())
|
return id(new NuanceSource())
|
||||||
->setViewPolicy($view_policy)
|
->setViewPolicy($view_policy)
|
||||||
->setEditPolicy($edit_policy);
|
->setEditPolicy($edit_policy)
|
||||||
|
->setType($lucky_definition->getSourceTypeConstant());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getCapabilities() {
|
public function getCapabilities() {
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
final class NuanceSourceTransaction
|
final class NuanceSourceTransaction
|
||||||
extends NuanceTransaction {
|
extends NuanceTransaction {
|
||||||
|
|
||||||
|
const TYPE_NAME = 'name-source';
|
||||||
|
|
||||||
public function getApplicationTransactionType() {
|
public function getApplicationTransactionType() {
|
||||||
return NuancePHIDTypeSource::TYPECONST;
|
return NuancePHIDTypeSource::TYPECONST;
|
||||||
}
|
}
|
||||||
|
@ -11,4 +13,27 @@ final class NuanceSourceTransaction
|
||||||
return new NuanceSourceTransactionComment();
|
return new NuanceSourceTransactionComment();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getTitle() {
|
||||||
|
$old = $this->getOldValue();
|
||||||
|
$new = $this->getNewValue();
|
||||||
|
$author_phid = $this->getAuthorPHID();
|
||||||
|
|
||||||
|
switch ($this->getTransactionType()) {
|
||||||
|
case self::TYPE_NAME:
|
||||||
|
if ($old === null) {
|
||||||
|
return pht(
|
||||||
|
'%s created this source.',
|
||||||
|
$this->renderHandleLink($author_phid));
|
||||||
|
} else {
|
||||||
|
return pht(
|
||||||
|
'%s renamed this source from "%s" to "%s".',
|
||||||
|
$this->renderHandleLink($author_phid),
|
||||||
|
$old,
|
||||||
|
$new);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1768,6 +1768,10 @@ final class PhabricatorBuiltinPatchList extends PhabricatorSQLPatchList {
|
||||||
'type' => 'sql',
|
'type' => 'sql',
|
||||||
'name' => $this->getPatchPath('20131119.passphrase.sql'),
|
'name' => $this->getPatchPath('20131119.passphrase.sql'),
|
||||||
),
|
),
|
||||||
|
'20131120.nuancesourcetype.sql' => array(
|
||||||
|
'type' => 'sql',
|
||||||
|
'name' => $this->getPatchPath('20131120.nuancesourcetype.sql'),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue