Page MenuHomePhabricator

D14453.id34953.diff
No OneTemporary

D14453.id34953.diff

diff --git a/resources/sql/autopatches/20151106.editengine.1.table.sql b/resources/sql/autopatches/20151106.editengine.1.table.sql
new file mode 100644
--- /dev/null
+++ b/resources/sql/autopatches/20151106.editengine.1.table.sql
@@ -0,0 +1,17 @@
+CREATE TABLE {$NAMESPACE}_search.search_editengineconfiguration (
+ id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
+ phid VARBINARY(64) NOT NULL,
+ engineKey VARCHAR(64) NOT NULL COLLATE {$COLLATE_TEXT},
+ builtinKey VARCHAR(64) COLLATE {$COLLATE_TEXT},
+ name VARCHAR(255) NOT NULL COLLATE {$COLLATE_TEXT},
+ viewPolicy VARBINARY(64) NOT NULL,
+ editPolicy VARBINARY(64) NOT NULL,
+ properties LONGTEXT NOT NULL COLLATE {$COLLATE_TEXT},
+ isDisabled BOOL NOT NULL DEFAULT 0,
+ isDefault BOOL NOT NULL DEFAULT 0,
+ dateCreated INT UNSIGNED NOT NULL,
+ dateModified INT UNSIGNED NOT NULL,
+ UNIQUE KEY `key_phid` (phid),
+ UNIQUE KEY `key_engine` (engineKey, builtinKey),
+ KEY `key_default` (engineKey, isDefault, isDisabled)
+) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT};
diff --git a/resources/sql/autopatches/20151106.editengine.2.xactions.sql b/resources/sql/autopatches/20151106.editengine.2.xactions.sql
new file mode 100644
--- /dev/null
+++ b/resources/sql/autopatches/20151106.editengine.2.xactions.sql
@@ -0,0 +1,19 @@
+CREATE TABLE {$NAMESPACE}_search.search_editengineconfigurationtransaction (
+ id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
+ phid VARBINARY(64) NOT NULL,
+ authorPHID VARBINARY(64) NOT NULL,
+ objectPHID VARBINARY(64) NOT NULL,
+ viewPolicy VARBINARY(64) NOT NULL,
+ editPolicy VARBINARY(64) NOT NULL,
+ commentPHID VARBINARY(64) DEFAULT NULL,
+ commentVersion INT UNSIGNED NOT NULL,
+ transactionType VARCHAR(32) COLLATE {$COLLATE_TEXT} NOT NULL,
+ oldValue LONGTEXT COLLATE {$COLLATE_TEXT} NOT NULL,
+ newValue LONGTEXT COLLATE {$COLLATE_TEXT} NOT NULL,
+ contentSource LONGTEXT COLLATE {$COLLATE_TEXT} NOT NULL,
+ metadata LONGTEXT COLLATE {$COLLATE_TEXT} NOT NULL,
+ dateCreated INT UNSIGNED NOT NULL,
+ dateModified INT UNSIGNED NOT NULL,
+ UNIQUE KEY `key_phid` (`phid`),
+ KEY `key_object` (`objectPHID`)
+) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT};
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
@@ -1579,8 +1579,6 @@
'PhabricatorApplicationDatasource' => 'applications/meta/typeahead/PhabricatorApplicationDatasource.php',
'PhabricatorApplicationDetailViewController' => 'applications/meta/controller/PhabricatorApplicationDetailViewController.php',
'PhabricatorApplicationEditController' => 'applications/meta/controller/PhabricatorApplicationEditController.php',
- 'PhabricatorApplicationEditEngine' => 'applications/transactions/editengine/PhabricatorApplicationEditEngine.php',
- 'PhabricatorApplicationEditEngineAPIMethod' => 'applications/transactions/editengine/PhabricatorApplicationEditEngineAPIMethod.php',
'PhabricatorApplicationEditHTTPParameterHelpView' => 'applications/transactions/view/PhabricatorApplicationEditHTTPParameterHelpView.php',
'PhabricatorApplicationEmailCommandsController' => 'applications/meta/controller/PhabricatorApplicationEmailCommandsController.php',
'PhabricatorApplicationLaunchView' => 'applications/meta/view/PhabricatorApplicationLaunchView.php',
@@ -2110,6 +2108,24 @@
'PhabricatorEdgeTestCase' => 'infrastructure/edges/__tests__/PhabricatorEdgeTestCase.php',
'PhabricatorEdgeType' => 'infrastructure/edges/type/PhabricatorEdgeType.php',
'PhabricatorEdgeTypeTestCase' => 'infrastructure/edges/type/__tests__/PhabricatorEdgeTypeTestCase.php',
+ 'PhabricatorEditEngine' => 'applications/transactions/editengine/PhabricatorEditEngine.php',
+ 'PhabricatorEditEngineAPIMethod' => 'applications/transactions/editengine/PhabricatorEditEngineAPIMethod.php',
+ 'PhabricatorEditEngineConfiguration' => 'applications/transactions/storage/PhabricatorEditEngineConfiguration.php',
+ 'PhabricatorEditEngineConfigurationEditController' => 'applications/transactions/controller/PhabricatorEditEngineConfigurationEditController.php',
+ 'PhabricatorEditEngineConfigurationEditEngine' => 'applications/transactions/editor/PhabricatorEditEngineConfigurationEditEngine.php',
+ 'PhabricatorEditEngineConfigurationEditor' => 'applications/transactions/editor/PhabricatorEditEngineConfigurationEditor.php',
+ 'PhabricatorEditEngineConfigurationListController' => 'applications/transactions/controller/PhabricatorEditEngineConfigurationListController.php',
+ 'PhabricatorEditEngineConfigurationPHIDType' => 'applications/transactions/phid/PhabricatorEditEngineConfigurationPHIDType.php',
+ 'PhabricatorEditEngineConfigurationQuery' => 'applications/transactions/query/PhabricatorEditEngineConfigurationQuery.php',
+ 'PhabricatorEditEngineConfigurationSaveController' => 'applications/transactions/controller/PhabricatorEditEngineConfigurationSaveController.php',
+ 'PhabricatorEditEngineConfigurationSearchEngine' => 'applications/transactions/query/PhabricatorEditEngineConfigurationSearchEngine.php',
+ 'PhabricatorEditEngineConfigurationTransaction' => 'applications/transactions/storage/PhabricatorEditEngineConfigurationTransaction.php',
+ 'PhabricatorEditEngineConfigurationTransactionQuery' => 'applications/transactions/query/PhabricatorEditEngineConfigurationTransactionQuery.php',
+ 'PhabricatorEditEngineConfigurationViewController' => 'applications/transactions/controller/PhabricatorEditEngineConfigurationViewController.php',
+ 'PhabricatorEditEngineController' => 'applications/transactions/controller/PhabricatorEditEngineController.php',
+ 'PhabricatorEditEngineListController' => 'applications/transactions/controller/PhabricatorEditEngineListController.php',
+ 'PhabricatorEditEngineQuery' => 'applications/transactions/query/PhabricatorEditEngineQuery.php',
+ 'PhabricatorEditEngineSearchEngine' => 'applications/transactions/query/PhabricatorEditEngineSearchEngine.php',
'PhabricatorEditField' => 'applications/transactions/editfield/PhabricatorEditField.php',
'PhabricatorEditType' => 'applications/transactions/edittype/PhabricatorEditType.php',
'PhabricatorEditor' => 'infrastructure/PhabricatorEditor.php',
@@ -2294,6 +2310,7 @@
'PhabricatorInlineCommentInterface' => 'infrastructure/diff/interface/PhabricatorInlineCommentInterface.php',
'PhabricatorInlineCommentPreviewController' => 'infrastructure/diff/PhabricatorInlineCommentPreviewController.php',
'PhabricatorInlineSummaryView' => 'infrastructure/diff/view/PhabricatorInlineSummaryView.php',
+ 'PhabricatorInstructionsEditField' => 'applications/transactions/editfield/PhabricatorInstructionsEditField.php',
'PhabricatorInternationalizationManagementExtractWorkflow' => 'infrastructure/internationalization/management/PhabricatorInternationalizationManagementExtractWorkflow.php',
'PhabricatorInternationalizationManagementWorkflow' => 'infrastructure/internationalization/management/PhabricatorInternationalizationManagementWorkflow.php',
'PhabricatorInvalidConfigSetupCheck' => 'applications/config/check/PhabricatorInvalidConfigSetupCheck.php',
@@ -5500,7 +5517,7 @@
'PasteCreateMailReceiver' => 'PhabricatorMailReceiver',
'PasteDefaultEditCapability' => 'PhabricatorPolicyCapability',
'PasteDefaultViewCapability' => 'PhabricatorPolicyCapability',
- 'PasteEditConduitAPIMethod' => 'PhabricatorApplicationEditEngineAPIMethod',
+ 'PasteEditConduitAPIMethod' => 'PhabricatorEditEngineAPIMethod',
'PasteEmbedView' => 'AphrontView',
'PasteInfoConduitAPIMethod' => 'PasteConduitAPIMethod',
'PasteMailReceiver' => 'PhabricatorObjectMailReceiver',
@@ -5544,8 +5561,6 @@
'PhabricatorApplicationDatasource' => 'PhabricatorTypeaheadDatasource',
'PhabricatorApplicationDetailViewController' => 'PhabricatorApplicationsController',
'PhabricatorApplicationEditController' => 'PhabricatorApplicationsController',
- 'PhabricatorApplicationEditEngine' => 'Phobject',
- 'PhabricatorApplicationEditEngineAPIMethod' => 'ConduitAPIMethod',
'PhabricatorApplicationEditHTTPParameterHelpView' => 'AphrontView',
'PhabricatorApplicationEmailCommandsController' => 'PhabricatorApplicationsController',
'PhabricatorApplicationLaunchView' => 'AphrontTagView',
@@ -6172,6 +6187,31 @@
'PhabricatorEdgeTestCase' => 'PhabricatorTestCase',
'PhabricatorEdgeType' => 'Phobject',
'PhabricatorEdgeTypeTestCase' => 'PhabricatorTestCase',
+ 'PhabricatorEditEngine' => array(
+ 'Phobject',
+ 'PhabricatorPolicyInterface',
+ ),
+ 'PhabricatorEditEngineAPIMethod' => 'ConduitAPIMethod',
+ 'PhabricatorEditEngineConfiguration' => array(
+ 'PhabricatorSearchDAO',
+ 'PhabricatorApplicationTransactionInterface',
+ 'PhabricatorPolicyInterface',
+ ),
+ 'PhabricatorEditEngineConfigurationEditController' => 'PhabricatorEditEngineController',
+ 'PhabricatorEditEngineConfigurationEditEngine' => 'PhabricatorEditEngine',
+ 'PhabricatorEditEngineConfigurationEditor' => 'PhabricatorApplicationTransactionEditor',
+ 'PhabricatorEditEngineConfigurationListController' => 'PhabricatorEditEngineController',
+ 'PhabricatorEditEngineConfigurationPHIDType' => 'PhabricatorPHIDType',
+ 'PhabricatorEditEngineConfigurationQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
+ 'PhabricatorEditEngineConfigurationSaveController' => 'PhabricatorEditEngineController',
+ 'PhabricatorEditEngineConfigurationSearchEngine' => 'PhabricatorApplicationSearchEngine',
+ 'PhabricatorEditEngineConfigurationTransaction' => 'PhabricatorApplicationTransaction',
+ 'PhabricatorEditEngineConfigurationTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
+ 'PhabricatorEditEngineConfigurationViewController' => 'PhabricatorEditEngineController',
+ 'PhabricatorEditEngineController' => 'PhabricatorApplicationTransactionController',
+ 'PhabricatorEditEngineListController' => 'PhabricatorEditEngineController',
+ 'PhabricatorEditEngineQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
+ 'PhabricatorEditEngineSearchEngine' => 'PhabricatorApplicationSearchEngine',
'PhabricatorEditField' => 'Phobject',
'PhabricatorEditType' => 'Phobject',
'PhabricatorEditor' => 'Phobject',
@@ -6392,6 +6432,7 @@
'PhabricatorInlineCommentInterface' => 'PhabricatorMarkupInterface',
'PhabricatorInlineCommentPreviewController' => 'PhabricatorController',
'PhabricatorInlineSummaryView' => 'AphrontView',
+ 'PhabricatorInstructionsEditField' => 'PhabricatorEditField',
'PhabricatorInternationalizationManagementExtractWorkflow' => 'PhabricatorInternationalizationManagementWorkflow',
'PhabricatorInternationalizationManagementWorkflow' => 'PhabricatorManagementWorkflow',
'PhabricatorInvalidConfigSetupCheck' => 'PhabricatorSetupCheck',
@@ -6710,7 +6751,7 @@
'PhabricatorPasteController' => 'PhabricatorController',
'PhabricatorPasteDAO' => 'PhabricatorLiskDAO',
'PhabricatorPasteEditController' => 'PhabricatorPasteController',
- 'PhabricatorPasteEditEngine' => 'PhabricatorApplicationEditEngine',
+ 'PhabricatorPasteEditEngine' => 'PhabricatorEditEngine',
'PhabricatorPasteEditor' => 'PhabricatorApplicationTransactionEditor',
'PhabricatorPasteListController' => 'PhabricatorPasteController',
'PhabricatorPastePastePHIDType' => 'PhabricatorPHIDType',
diff --git a/src/applications/base/PhabricatorApplication.php b/src/applications/base/PhabricatorApplication.php
--- a/src/applications/base/PhabricatorApplication.php
+++ b/src/applications/base/PhabricatorApplication.php
@@ -635,8 +635,12 @@
return array();
}
- protected function getEditRoutePattern($base) {
+ protected function getEditRoutePattern($base = null) {
return $base.'(?:(?P<id>[0-9]\d*)/)?(?:(?P<editAction>parameters)/)?';
}
+ protected function getQueryRoutePattern($base = null) {
+ return $base.'(?:query/(?P<queryKey>[^/]+)/)?';
+ }
+
}
diff --git a/src/applications/paste/conduit/PasteEditConduitAPIMethod.php b/src/applications/paste/conduit/PasteEditConduitAPIMethod.php
--- a/src/applications/paste/conduit/PasteEditConduitAPIMethod.php
+++ b/src/applications/paste/conduit/PasteEditConduitAPIMethod.php
@@ -1,7 +1,7 @@
<?php
final class PasteEditConduitAPIMethod
- extends PhabricatorApplicationEditEngineAPIMethod {
+ extends PhabricatorEditEngineAPIMethod {
public function getAPIMethodName() {
return 'paste.edit';
diff --git a/src/applications/paste/editor/PhabricatorPasteEditEngine.php b/src/applications/paste/editor/PhabricatorPasteEditEngine.php
--- a/src/applications/paste/editor/PhabricatorPasteEditEngine.php
+++ b/src/applications/paste/editor/PhabricatorPasteEditEngine.php
@@ -1,7 +1,13 @@
<?php
final class PhabricatorPasteEditEngine
- extends PhabricatorApplicationEditEngine {
+ extends PhabricatorEditEngine {
+
+ const ENGINECONST = 'paste.paste';
+
+ public function getEngineName() {
+ return pht('Pastes');
+ }
protected function newEditableObject() {
return PhabricatorPaste::initializeNewPaste($this->getViewer());
@@ -24,7 +30,7 @@
return $object->getMonogram();
}
- protected function getObjectCreateShortText($object) {
+ protected function getObjectCreateShortText() {
return pht('Create Paste');
}
diff --git a/src/applications/transactions/application/PhabricatorTransactionsApplication.php b/src/applications/transactions/application/PhabricatorTransactionsApplication.php
--- a/src/applications/transactions/application/PhabricatorTransactionsApplication.php
+++ b/src/applications/transactions/application/PhabricatorTransactionsApplication.php
@@ -33,6 +33,20 @@
=> 'PhabricatorApplicationTransactionShowOlderController',
'(?P<value>old|new)/(?<phid>[^/]+)/'
=> 'PhabricatorApplicationTransactionValueController',
+ 'editengine/' => array(
+ $this->getQueryRoutePattern()
+ => 'PhabricatorEditEngineListController',
+ '(?P<engineKey>[^/]+)/' => array(
+ $this->getQueryRoutePattern() =>
+ 'PhabricatorEditEngineConfigurationListController',
+ $this->getEditRoutePattern('edit/') =>
+ 'PhabricatorEditEngineConfigurationEditController',
+ 'view/(?P<key>[^/]+)/' =>
+ 'PhabricatorEditEngineConfigurationViewController',
+ 'save/(?P<key>[^/]+)/' =>
+ 'PhabricatorEditEngineConfigurationSaveController',
+ ),
+ ),
),
);
}
diff --git a/src/applications/transactions/controller/PhabricatorEditEngineConfigurationEditController.php b/src/applications/transactions/controller/PhabricatorEditEngineConfigurationEditController.php
new file mode 100644
--- /dev/null
+++ b/src/applications/transactions/controller/PhabricatorEditEngineConfigurationEditController.php
@@ -0,0 +1,26 @@
+<?php
+
+final class PhabricatorEditEngineConfigurationEditController
+ extends PhabricatorEditEngineController {
+
+ public function handleRequest(AphrontRequest $request) {
+ $viewer = $this->getViewer();
+
+ $target_engine_key = $request->getURIData('engineKey');
+
+ $target_engine = PhabricatorEditEngine::getByKey(
+ $viewer,
+ $target_engine_key);
+ if (!$target_engine) {
+ return new Aphront404Response();
+ }
+
+ $this->setEngineKey($target_engine->getEngineKey());
+
+ return id(new PhabricatorEditEngineConfigurationEditEngine())
+ ->setTargetEngine($target_engine)
+ ->setController($this)
+ ->buildResponse();
+ }
+
+}
diff --git a/src/applications/transactions/controller/PhabricatorEditEngineConfigurationListController.php b/src/applications/transactions/controller/PhabricatorEditEngineConfigurationListController.php
new file mode 100644
--- /dev/null
+++ b/src/applications/transactions/controller/PhabricatorEditEngineConfigurationListController.php
@@ -0,0 +1,34 @@
+<?php
+
+final class PhabricatorEditEngineConfigurationListController
+ extends PhabricatorEditEngineController {
+
+ public function shouldAllowPublic() {
+ return true;
+ }
+
+ public function handleRequest(AphrontRequest $request) {
+ $this->setEngineKey($request->getURIData('engineKey'));
+
+ return id(new PhabricatorEditEngineConfigurationSearchEngine())
+ ->setController($this)
+ ->setEngineKey($this->getEngineKey())
+ ->buildResponse();
+ }
+
+ protected function buildApplicationCrumbs() {
+ $crumbs = parent::buildApplicationCrumbs();
+
+ $engine_key = $this->getEngineKey();
+ $edit_uri = "/transactions/editengine/{$engine_key}/edit/";
+
+ $crumbs->addAction(
+ id(new PHUIListItemView())
+ ->setName(pht('New Form'))
+ ->setHref($edit_uri)
+ ->setIcon('fa-plus-square'));
+
+ return $crumbs;
+ }
+
+}
diff --git a/src/applications/transactions/controller/PhabricatorEditEngineConfigurationSaveController.php b/src/applications/transactions/controller/PhabricatorEditEngineConfigurationSaveController.php
new file mode 100644
--- /dev/null
+++ b/src/applications/transactions/controller/PhabricatorEditEngineConfigurationSaveController.php
@@ -0,0 +1,55 @@
+<?php
+
+final class PhabricatorEditEngineConfigurationSaveController
+ extends PhabricatorEditEngineController {
+
+ public function handleRequest(AphrontRequest $request) {
+ $engine_key = $request->getURIData('engineKey');
+ $this->setEngineKey($engine_key);
+
+ $key = $request->getURIData('key');
+ $viewer = $this->getViewer();
+
+ $config = id(new PhabricatorEditEngineConfigurationQuery())
+ ->setViewer($viewer)
+ ->withEngineKeys(array($engine_key))
+ ->withIdentifiers(array($key))
+ ->executeOne();
+ if (!$config) {
+ return id(new Aphront404Response());
+ }
+
+ $view_uri = $config->getURI();
+
+ if ($config->getID()) {
+ return $this->newDialog()
+ ->setTitle(pht('Already Editable'))
+ ->appendParagraph(
+ pht('This form configuration is already editable.'))
+ ->addCancelButton($view_uri);
+ }
+
+ if ($request->isFormPost()) {
+ $editor = id(new PhabricatorEditEngineConfigurationEditor())
+ ->setActor($viewer)
+ ->setContentSourceFromRequest($request)
+ ->setContinueOnNoEffect(true);
+
+ $editor->applyTransactions($config, array());
+
+ return id(new AphrontRedirectResponse())
+ ->setURI($config->getURI());
+ }
+
+ // TODO: Explain what this means in more detail once the implications are
+ // more clear, or just link to some docs or something.
+
+ return $this->newDialog()
+ ->setTitle(pht('Make Builtin Editable'))
+ ->appendParagraph(
+ pht('Make this builtin form editable?'))
+ ->addSubmitButton(pht('Make Editable'))
+ ->addCancelButton($view_uri);
+ }
+
+}
diff --git a/src/applications/transactions/controller/PhabricatorEditEngineConfigurationViewController.php b/src/applications/transactions/controller/PhabricatorEditEngineConfigurationViewController.php
new file mode 100644
--- /dev/null
+++ b/src/applications/transactions/controller/PhabricatorEditEngineConfigurationViewController.php
@@ -0,0 +1,125 @@
+<?php
+
+final class PhabricatorEditEngineConfigurationViewController
+ extends PhabricatorEditEngineController {
+
+ public function shouldAllowPublic() {
+ return true;
+ }
+
+ public function handleRequest(AphrontRequest $request) {
+ $engine_key = $request->getURIData('engineKey');
+ $this->setEngineKey($engine_key);
+
+ $key = $request->getURIData('key');
+ $viewer = $this->getViewer();
+
+ $config = id(new PhabricatorEditEngineConfigurationQuery())
+ ->setViewer($viewer)
+ ->withEngineKeys(array($engine_key))
+ ->withIdentifiers(array($key))
+ ->executeOne();
+ if (!$config) {
+ return id(new Aphront404Response());
+ }
+
+ $is_concrete = (bool)$config->getID();
+
+ $actions = $this->buildActionView($config);
+
+ $properties = $this->buildPropertyView($config)
+ ->setActionList($actions);
+
+ $header = id(new PHUIHeaderView())
+ ->setUser($viewer)
+ ->setPolicyObject($config)
+ ->setHeader(pht('Edit Form: %s', $config->getDisplayName()));
+
+ $box = id(new PHUIObjectBoxView())
+ ->setHeader($header)
+ ->addPropertyList($properties);
+
+ $crumbs = $this->buildApplicationCrumbs();
+
+ if ($is_concrete) {
+ $crumbs->addTextCrumb(pht('Form %d', $config->getID()));
+ } else {
+ $crumbs->addTextCrumb(pht('Builtin'));
+ }
+
+ if ($is_concrete) {
+ $timeline = $this->buildTransactionTimeline(
+ $config,
+ new PhabricatorEditEngineConfigurationTransactionQuery());
+
+ $timeline->setShouldTerminate(true);
+ } else {
+ $timeline = null;
+ }
+
+ return $this->newPage()
+ ->setCrumbs($crumbs)
+ ->appendChild(
+ array(
+ $box,
+ $timeline,
+ ));
+ }
+
+ private function buildActionView(
+ PhabricatorEditEngineConfiguration $config) {
+ $viewer = $this->getViewer();
+ $engine_key = $this->getEngineKey();
+
+ $can_edit = PhabricatorPolicyFilter::hasCapability(
+ $viewer,
+ $config,
+ PhabricatorPolicyCapability::CAN_EDIT);
+
+ $view = id(new PhabricatorActionListView())
+ ->setUser($viewer);
+
+ $key = $config->getIdentifier();
+
+ $base_uri = "/transactions/editengine/{$engine_key}";
+
+ $is_concrete = (bool)$config->getID();
+ if (!$is_concrete) {
+ $save_uri = "{$base_uri}/save/{$key}/";
+
+ $view->addAction(
+ id(new PhabricatorActionView())
+ ->setName(pht('Make Editable'))
+ ->setIcon('fa-pencil')
+ ->setDisabled(!$can_edit)
+ ->setWorkflow(true)
+ ->setHref($save_uri));
+
+ $can_edit = false;
+ } else {
+ $edit_uri = "{$base_uri}/edit/{$key}/";
+ $view->addAction(
+ id(new PhabricatorActionView())
+ ->setName(pht('Edit Form Configuration'))
+ ->setIcon('fa-pencil')
+ ->setDisabled(!$can_edit)
+ ->setWorkflow(!$can_edit)
+ ->setHref($edit_uri));
+ }
+
+ return $view;
+ }
+
+ private function buildPropertyView(
+ PhabricatorEditEngineConfiguration $config) {
+ $viewer = $this->getViewer();
+
+ $properties = id(new PHUIPropertyListView())
+ ->setUser($viewer)
+ ->setObject($config);
+
+ return $properties;
+ }
+
+
+}
diff --git a/src/applications/transactions/controller/PhabricatorEditEngineController.php b/src/applications/transactions/controller/PhabricatorEditEngineController.php
new file mode 100644
--- /dev/null
+++ b/src/applications/transactions/controller/PhabricatorEditEngineController.php
@@ -0,0 +1,37 @@
+<?php
+
+abstract class PhabricatorEditEngineController
+ extends PhabricatorApplicationTransactionController {
+
+ private $engineKey;
+
+ public function setEngineKey($engine_key) {
+ $this->engineKey = $engine_key;
+ return $this;
+ }
+
+ public function getEngineKey() {
+ return $this->engineKey;
+ }
+
+ protected function buildApplicationCrumbs() {
+ $crumbs = parent::buildApplicationCrumbs();
+
+ $crumbs->addTextCrumb(pht('Edit Engines'), '/transactions/editengine/');
+
+ $engine_key = $this->getEngineKey();
+ if ($engine_key !== null) {
+ $engine = PhabricatorEditEngine::getByKey(
+ $this->getViewer(),
+ $engine_key);
+ if ($engine) {
+ $crumbs->addTextCrumb(
+ $engine->getEngineName(),
+ "/transactions/editengine/{$engine_key}/");
+ }
+ }
+
+ return $crumbs;
+ }
+
+}
diff --git a/src/applications/transactions/controller/PhabricatorEditEngineListController.php b/src/applications/transactions/controller/PhabricatorEditEngineListController.php
new file mode 100644
--- /dev/null
+++ b/src/applications/transactions/controller/PhabricatorEditEngineListController.php
@@ -0,0 +1,16 @@
+<?php
+
+final class PhabricatorEditEngineListController
+ extends PhabricatorEditEngineController {
+
+ public function shouldAllowPublic() {
+ return true;
+ }
+
+ public function handleRequest(AphrontRequest $request) {
+ return id(new PhabricatorEditEngineSearchEngine())
+ ->setController($this)
+ ->buildResponse();
+ }
+
+}
diff --git a/src/applications/transactions/editengine/PhabricatorApplicationEditEngine.php b/src/applications/transactions/editengine/PhabricatorEditEngine.php
rename from src/applications/transactions/editengine/PhabricatorApplicationEditEngine.php
rename to src/applications/transactions/editengine/PhabricatorEditEngine.php
--- a/src/applications/transactions/editengine/PhabricatorApplicationEditEngine.php
+++ b/src/applications/transactions/editengine/PhabricatorEditEngine.php
@@ -4,6 +4,7 @@
/**
* @task fields Managing Fields
* @task text Display Text
+ * @task config Edit Engine Configuration
* @task uri Managing URIs
* @task load Creating and Loading Objects
* @task web Responding to Web Requests
@@ -11,11 +12,16 @@
* @task http Responding to HTTP Parameter Requests
* @task conduit Responding to Conduit Requests
*/
-abstract class PhabricatorApplicationEditEngine extends Phobject {
+abstract class PhabricatorEditEngine
+ extends Phobject
+ implements PhabricatorPolicyInterface {
+
+ const EDITENGINECONFIG_DEFAULT = 'default';
private $viewer;
private $controller;
private $isCreate;
+ private $editEngineConfiguration;
final public function setViewer(PhabricatorUser $viewer) {
$this->viewer = $viewer;
@@ -36,6 +42,10 @@
return $this->controller;
}
+ final public function getEngineKey() {
+ return $this->getPhobjectClassConstant('ENGINECONST', 64);
+ }
+
/* -( Managing Fields )---------------------------------------------------- */
@@ -184,6 +194,9 @@
}
}
+ $config = $this->getEditEngineConfiguration();
+ $fields = $config->applyConfigurationToFields($this, $fields);
+
foreach ($fields as $field) {
$field
->setViewer($viewer)
@@ -200,6 +213,12 @@
/**
* @task text
*/
+ abstract public function getEngineName();
+
+
+ /**
+ * @task text
+ */
abstract protected function getObjectCreateTitleText($object);
@@ -212,7 +231,7 @@
/**
* @task text
*/
- abstract protected function getObjectCreateShortText($object);
+ abstract protected function getObjectCreateShortText();
/**
@@ -237,6 +256,121 @@
}
+/* -( Edit Engine Configuration )------------------------------------------ */
+
+
+ protected function supportsEditEngineConfiguration() {
+ return true;
+ }
+
+ final protected function getEditEngineConfiguration() {
+ return $this->editEngineConfiguration;
+ }
+
+ private function loadEditEngineConfiguration($key) {
+ if ($key === null) {
+ $key = self::EDITENGINECONFIG_DEFAULT;
+ }
+
+ $config = id(new PhabricatorEditEngineConfigurationQuery())
+ ->setViewer($this->getViewer())
+ ->withEngineKeys(array($this->getEngineKey()))
+ ->withIdentifiers(array($key))
+ ->executeOne();
+ if (!$config) {
+ return null;
+ }
+
+ $this->editEngineConfiguration = $config;
+
+ return $config;
+ }
+
+ final public function getBuiltinEngineConfigurations() {
+ $configurations = $this->newBuiltinEngineConfigurations();
+
+ if (!$configurations) {
+ throw new Exception(
+ pht(
+ 'EditEngine ("%s") returned no builtin engine configurations, but '.
+ 'an edit engine must have at least one configuration.',
+ get_class($this)));
+ }
+
+ assert_instances_of($configurations, 'PhabricatorEditEngineConfiguration');
+
+ $has_default = false;
+ foreach ($configurations as $config) {
+ if ($config->getBuiltinKey() == self::EDITENGINECONFIG_DEFAULT) {
+ $has_default = true;
+ }
+ }
+
+ if (!$has_default) {
+ $first = head($configurations);
+ if (!$first->getBuiltinKey()) {
+ $first->setBuiltinKey(self::EDITENGINECONFIG_DEFAULT);
+
+ if (!strlen($first->getName())) {
+ $first->setName($this->getObjectCreateShortText());
+ }
+ } else {
+ throw new Exception(
+ pht(
+ 'EditEngine ("%s") returned builtin engine configurations, '.
+ 'but none are marked as default and the first configuration has '.
+ 'a different builtin key already. Mark a builtin as default or '.
+ 'omit the key from the first configuration',
+ get_class($this)));
+ }
+ }
+
+ $builtins = array();
+ foreach ($configurations as $key => $config) {
+ $builtin_key = $config->getBuiltinKey();
+
+ if ($builtin_key === null) {
+ throw new Exception(
+ pht(
+ 'EditEngine ("%s") returned builtin engine configurations, '.
+ 'but one (with key "%s") is missing a builtin key. Provide a '.
+ 'builtin key for each configuration (you can omit it from the '.
+ 'first configuration in the list to automatically assign the '.
+ 'default key).',
+ get_class($this),
+ $key));
+ }
+
+ if (isset($builtins[$builtin_key])) {
+ throw new Exception(
+ pht(
+ 'EditEngine ("%s") returned builtin engine configurations, '.
+ 'but at least two specify the same builtin key ("%s"). Engines '.
+ 'must have unique builtin keys.',
+ get_class($this),
+ $builtin_key));
+ }
+
+ $builtins[$builtin_key] = $config;
+ }
+
+
+ return $builtins;
+ }
+
+ protected function newBuiltinEngineConfigurations() {
+ return array(
+ $this->newConfiguration(),
+ );
+ }
+
+ final protected function newConfiguration() {
+ return PhabricatorEditEngineConfiguration::initializeNewConfiguration(
+ $this->getViewer(),
+ $this);
+ }
+
+
/* -( Managing URIs )------------------------------------------------------ */
@@ -317,7 +451,7 @@
* @return bool True if a new object is being created.
* @task load
*/
- final protected function getIsCreate() {
+ final public function getIsCreate() {
return $this->isCreate;
}
@@ -391,6 +525,35 @@
}
+ /**
+ * Verify that an object is appropriate for editing.
+ *
+ * @param wild Loaded value.
+ * @return void
+ * @task load
+ */
+ private function validateObject($object) {
+ if (!$object || !is_object($object)) {
+ throw new Exception(
+ pht(
+ 'EditEngine "%s" created or loaded an invalid object: object must '.
+ 'actually be an object, but is of some other type ("%s").',
+ get_class($this),
+ gettype($object)));
+ }
+
+ if (!($object instanceof PhabricatorApplicationTransactionInterface)) {
+ throw new Exception(
+ pht(
+ 'EditEngine "%s" created or loaded an invalid object: object (of '.
+ 'class "%s") must implement "%s", but does not.',
+ get_class($this),
+ get_class($object),
+ 'PhabricatorApplicationTransactionInterface'));
+ }
+ }
+
+
/* -( Responding to Web Requests )----------------------------------------- */
@@ -399,6 +562,11 @@
$controller = $this->getController();
$request = $controller->getRequest();
+ $config = $this->loadEditEngineConfiguration($request->getURIData('form'));
+ if (!$config) {
+ return new Aphront404Response();
+ }
+
$id = $request->getURIData('id');
if ($id) {
$this->setIsCreate(false);
@@ -411,6 +579,8 @@
$object = $this->newEditableObject();
}
+ $this->validateObject($object);
+
$action = $request->getURIData('editAction');
switch ($action) {
case 'parameters':
@@ -425,7 +595,7 @@
$crumbs = $controller->buildApplicationCrumbsForEditEngine();
if ($this->getIsCreate()) {
- $create_text = $this->getObjectCreateShortText($object);
+ $create_text = $this->getObjectCreateShortText();
if ($final) {
$crumbs->addTextCrumb($create_text);
} else {
@@ -570,6 +740,20 @@
private function buildEditFormActions($object) {
$actions = array();
+ if ($this->supportsEditEngineConfiguration()) {
+ $engine_key = $this->getEngineKey();
+ $config = $this->getEditEngineConfiguration();
+
+ $actions[] = id(new PhabricatorActionView())
+ ->setName(pht('Manage Form Configurations'))
+ ->setIcon('fa-list-ul')
+ ->setHref("/transactions/editengine/{$engine_key}/");
+ $actions[] = id(new PhabricatorActionView())
+ ->setName(pht('Edit Form Configuration'))
+ ->setIcon('fa-pencil')
+ ->setHref($config->getURI());
+ }
+
$actions[] = id(new PhabricatorActionView())
->setName(pht('Show HTTP Parameters'))
->setIcon('fa-crosshairs')
@@ -601,7 +785,7 @@
$header_text = pht(
'HTTP Parameters: %s',
- $this->getObjectCreateShortText($object));
+ $this->getObjectCreateShortText());
$header = id(new PHUIHeaderView())
->setHeader($header_text);
@@ -637,6 +821,14 @@
final public function buildConduitResponse(ConduitAPIRequest $request) {
$viewer = $this->getViewer();
+ $config = $this->loadEditEngineConfiguration(null);
+ if (!$config) {
+ throw new Exception(
+ pht(
+ 'Unable to load configuration for this EditEngine ("%s").',
+ get_class($this)));
+ }
+
$phid = $request->getValue('objectPHID');
if ($phid) {
$this->setIsCreate(false);
@@ -649,6 +841,8 @@
$object = $this->newEditableObject();
}
+ $this->validateObject($object);
+
$fields = $this->buildEditFields($object);
$types = $this->getAllEditTypesFromFields($fields);
@@ -772,5 +966,46 @@
return $this->getAllEditTypesFromFields($fields);
}
+ final public static function getAllEditEngines() {
+ return id(new PhutilClassMapQuery())
+ ->setAncestorClass(__CLASS__)
+ ->setUniqueMethod('getEngineKey')
+ ->execute();
+ }
+
+ final public static function getByKey(PhabricatorUser $viewer, $key) {
+ return id(new PhabricatorEditEngineQuery())
+ ->setViewer($viewer)
+ ->withEngineKeys(array($key))
+ ->executeOne();
+ }
+
+
+/* -( PhabricatorPolicyInterface )----------------------------------------- */
+
+
+ public function getPHID() {
+ return get_class($this);
+ }
+
+ public function getCapabilities() {
+ return array(
+ PhabricatorPolicyCapability::CAN_VIEW,
+ );
+ }
+ public function getPolicy($capability) {
+ switch ($capability) {
+ case PhabricatorPolicyCapability::CAN_VIEW:
+ return PhabricatorPolicies::getMostOpenPolicy();
+ }
+ }
+
+ public function hasAutomaticCapability($capability, PhabricatorUser $viewer) {
+ return false;
+ }
+
+ public function describeAutomaticCapability($capability) {
+ return null;
+ }
}
diff --git a/src/applications/transactions/editengine/PhabricatorApplicationEditEngineAPIMethod.php b/src/applications/transactions/editengine/PhabricatorEditEngineAPIMethod.php
rename from src/applications/transactions/editengine/PhabricatorApplicationEditEngineAPIMethod.php
rename to src/applications/transactions/editengine/PhabricatorEditEngineAPIMethod.php
--- a/src/applications/transactions/editengine/PhabricatorApplicationEditEngineAPIMethod.php
+++ b/src/applications/transactions/editengine/PhabricatorEditEngineAPIMethod.php
@@ -1,6 +1,6 @@
<?php
-abstract class PhabricatorApplicationEditEngineAPIMethod
+abstract class PhabricatorEditEngineAPIMethod
extends ConduitAPIMethod {
abstract public function newEditEngine();
diff --git a/src/applications/transactions/editfield/PhabricatorEditField.php b/src/applications/transactions/editfield/PhabricatorEditField.php
--- a/src/applications/transactions/editfield/PhabricatorEditField.php
+++ b/src/applications/transactions/editfield/PhabricatorEditField.php
@@ -13,7 +13,7 @@
private $metadata = array();
private $description;
private $editTypeKey;
-
+ private $isLocked;
public function setKey($key) {
$this->key = $key;
@@ -69,7 +69,18 @@
return $this->description;
}
- abstract protected function newControl();
+ public function setIsLocked($is_locked) {
+ $this->isLocked = $is_locked;
+ return $this;
+ }
+
+ public function getIsLocked() {
+ return $this->isLocked;
+ }
+
+ protected function newControl() {
+ throw new PhutilMethodNotImplementedException();
+ }
protected function renderControl() {
$control = $this->newControl();
@@ -85,6 +96,10 @@
$control->setLabel($this->getLabel());
}
+ if ($this->getIsLocked()) {
+ $control->setDisabled(true);
+ }
+
return $control;
}
@@ -166,6 +181,15 @@
return $this;
}
+ public function readDefaultValueFromConfiguration($value) {
+ $this->value = $this->getDefaultValueFromConfiguration($value);
+ return $this;
+ }
+
+ protected function getDefaultValueFromConfiguration($value) {
+ return $value;
+ }
+
protected function getValueFromObject($object) {
if ($this->hasValue) {
return $this->value;
diff --git a/src/applications/transactions/editfield/PhabricatorInstructionsEditField.php b/src/applications/transactions/editfield/PhabricatorInstructionsEditField.php
new file mode 100644
--- /dev/null
+++ b/src/applications/transactions/editfield/PhabricatorInstructionsEditField.php
@@ -0,0 +1,10 @@
+<?php
+
+final class PhabricatorInstructionsEditField
+ extends PhabricatorEditField {
+
+ public function appendToForm(AphrontFormView $form) {
+ return $form->appendRemarkupInstructions($this->getValue());
+ }
+
+}
diff --git a/src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php b/src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php
--- a/src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php
+++ b/src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php
@@ -815,18 +815,6 @@
$xactions = $this->filterTransactions($object, $xactions);
- if (!$xactions) {
- if ($read_locking) {
- $object->endReadLocking();
- $read_locking = false;
- }
- if ($transaction_open) {
- $object->killTransaction();
- $transaction_open = false;
- }
- return array();
- }
-
// Now that we've merged, filtered, and combined transactions, check for
// required capabilities.
foreach ($xactions as $xaction) {
diff --git a/src/applications/transactions/editor/PhabricatorEditEngineConfigurationEditEngine.php b/src/applications/transactions/editor/PhabricatorEditEngineConfigurationEditEngine.php
new file mode 100644
--- /dev/null
+++ b/src/applications/transactions/editor/PhabricatorEditEngineConfigurationEditEngine.php
@@ -0,0 +1,78 @@
+<?php
+
+final class PhabricatorEditEngineConfigurationEditEngine
+ extends PhabricatorEditEngine {
+
+ const ENGINECONST = 'transactions.editengine.config';
+
+ private $targetEngine;
+
+ public function setTargetEngine(PhabricatorEditEngine $target_engine) {
+ $this->targetEngine = $target_engine;
+ return $this;
+ }
+
+ public function getTargetEngine() {
+ return $this->targetEngine;
+ }
+
+ public function getEngineName() {
+ return pht('Edit Configurations');
+ }
+
+ protected function newEditableObject() {
+ return PhabricatorEditEngineConfiguration::initializeNewConfiguration(
+ $this->getViewer(),
+ $this->getTargetEngine());
+ }
+
+ protected function newObjectQuery() {
+ return id(new PhabricatorEditEngineConfigurationQuery());
+ }
+
+ protected function getObjectCreateTitleText($object) {
+ return pht('Create New Form');
+ }
+
+ protected function getObjectEditTitleText($object) {
+ return pht('Edit Form %d: %s', $object->getID(), $object->getDisplayName());
+ }
+
+ protected function getObjectEditShortText($object) {
+ return pht('Form %d', $object->getID());
+ }
+
+ protected function getObjectCreateShortText() {
+ return pht('Create Form');
+ }
+
+ protected function getObjectViewURI($object) {
+ $engine_key = $this->getTargetEngine()->getEngineKey();
+ $id = $object->getID();
+ return "/transactions/editengine/{$engine_key}/view/{$id}/";
+ }
+
+ protected function getObjectEditURI($object) {
+ $engine_key = $this->getTargetEngine()->getEngineKey();
+ $id = $object->getID();
+ return "/transactions/editengine/{$engine_key}/edit/{$id}/";
+ }
+
+ protected function getObjectCreateCancelURI($object) {
+ $engine_key = $this->getTargetEngine()->getEngineKey();
+ return "/transactions/editengine/{$engine_key}/";
+ }
+
+ protected function buildCustomEditFields($object) {
+ return array(
+ id(new PhabricatorTextEditField())
+ ->setKey('name')
+ ->setLabel(pht('Name'))
+ ->setDescription(pht('Name of the form.'))
+ ->setTransactionType(
+ PhabricatorEditEngineConfigurationTransaction::TYPE_NAME)
+ ->setValue($object->getName()),
+ );
+ }
+
+}
diff --git a/src/applications/transactions/editor/PhabricatorEditEngineConfigurationEditor.php b/src/applications/transactions/editor/PhabricatorEditEngineConfigurationEditor.php
new file mode 100644
--- /dev/null
+++ b/src/applications/transactions/editor/PhabricatorEditEngineConfigurationEditor.php
@@ -0,0 +1,98 @@
+<?php
+
+final class PhabricatorEditEngineConfigurationEditor
+ extends PhabricatorApplicationTransactionEditor {
+
+ public function getEditorApplicationClass() {
+ return 'PhabricatorTransactionsApplication';
+ }
+
+ public function getEditorObjectsDescription() {
+ return pht('Edit Configurations');
+ }
+
+ public function getTransactionTypes() {
+ $types = parent::getTransactionTypes();
+
+ $types[] = PhabricatorTransactions::TYPE_VIEW_POLICY;
+ $types[] = PhabricatorTransactions::TYPE_EDIT_POLICY;
+
+ $types[] = PhabricatorEditEngineConfigurationTransaction::TYPE_NAME;
+
+ return $types;
+ }
+
+ protected function validateTransaction(
+ PhabricatorLiskDAO $object,
+ $type,
+ array $xactions) {
+
+ $errors = parent::validateTransaction($object, $type, $xactions);
+ switch ($type) {
+ case PhabricatorEditEngineConfigurationTransaction::TYPE_NAME:
+ $missing = $this->validateIsEmptyTextField(
+ $object->getName(),
+ $xactions);
+
+ if ($missing) {
+ $error = new PhabricatorApplicationTransactionValidationError(
+ $type,
+ pht('Required'),
+ pht('Form name is required.'),
+ nonempty(last($xactions), null));
+
+ $error->setIsMissingFieldError(true);
+ $errors[] = $error;
+ }
+ break;
+ }
+
+ return $errors;
+ }
+
+ protected function getCustomTransactionOldValue(
+ PhabricatorLiskDAO $object,
+ PhabricatorApplicationTransaction $xaction) {
+
+ switch ($xaction->getTransactionType()) {
+ case PhabricatorEditEngineConfigurationTransaction::TYPE_NAME:
+ return $object->getName();
+ }
+ }
+
+ protected function getCustomTransactionNewValue(
+ PhabricatorLiskDAO $object,
+ PhabricatorApplicationTransaction $xaction) {
+
+ switch ($xaction->getTransactionType()) {
+ case PhabricatorEditEngineConfigurationTransaction::TYPE_NAME:
+ return $xaction->getNewValue();
+ }
+ }
+
+ protected function applyCustomInternalTransaction(
+ PhabricatorLiskDAO $object,
+ PhabricatorApplicationTransaction $xaction) {
+
+ switch ($xaction->getTransactionType()) {
+ case PhabricatorEditEngineConfigurationTransaction::TYPE_NAME:
+ $object->setName($xaction->getNewValue());
+ return;
+ }
+
+ return parent::applyCustomInternalTransaction($object, $xaction);
+ }
+
+ protected function applyCustomExternalTransaction(
+ PhabricatorLiskDAO $object,
+ PhabricatorApplicationTransaction $xaction) {
+
+ switch ($xaction->getTransactionType()) {
+ case PhabricatorEditEngineConfigurationTransaction::TYPE_NAME:
+ return;
+ }
+
+ return parent::applyCustomExternalTransaction($object, $xaction);
+ }
+
+}
diff --git a/src/applications/transactions/phid/PhabricatorEditEngineConfigurationPHIDType.php b/src/applications/transactions/phid/PhabricatorEditEngineConfigurationPHIDType.php
new file mode 100644
--- /dev/null
+++ b/src/applications/transactions/phid/PhabricatorEditEngineConfigurationPHIDType.php
@@ -0,0 +1,43 @@
+<?php
+
+final class PhabricatorEditEngineConfigurationPHIDType
+ extends PhabricatorPHIDType {
+
+ const TYPECONST = 'FORM';
+
+ public function getTypeName() {
+ return pht('Edit Configuration');
+ }
+
+ public function newObject() {
+ return new PhabricatorEditEngineConfiguration();
+ }
+
+ public function getPHIDTypeApplicationClass() {
+ return 'PhabricatorTransactionsApplication';
+ }
+
+ protected function buildQueryForObjects(
+ PhabricatorObjectQuery $object_query,
+ array $phids) {
+ return id(new PhabricatorEditEngineConfigurationQuery())
+ ->withPHIDs($phids);
+ }
+
+ public function loadHandles(
+ PhabricatorHandleQuery $query,
+ array $handles,
+ array $objects) {
+
+ foreach ($handles as $phid => $handle) {
+ $config = $objects[$phid];
+
+ $id = $config->getID();
+ $name = $config->getName();
+
+ $handle->setName($name);
+ $handle->setURI($config->getURI());
+ }
+ }
+
+}
diff --git a/src/applications/transactions/query/PhabricatorEditEngineConfigurationQuery.php b/src/applications/transactions/query/PhabricatorEditEngineConfigurationQuery.php
new file mode 100644
--- /dev/null
+++ b/src/applications/transactions/query/PhabricatorEditEngineConfigurationQuery.php
@@ -0,0 +1,183 @@
+<?php
+
+final class PhabricatorEditEngineConfigurationQuery
+ extends PhabricatorCursorPagedPolicyAwareQuery {
+
+ private $ids;
+ private $phids;
+ private $engineKeys;
+ private $builtinKeys;
+ private $identifiers;
+
+ public function withIDs(array $ids) {
+ $this->ids = $ids;
+ return $this;
+ }
+
+ public function withPHIDs(array $phids) {
+ $this->phids = $phids;
+ return $this;
+ }
+
+ public function withEngineKeys(array $engine_keys) {
+ $this->engineKeys = $engine_keys;
+ return $this;
+ }
+
+ public function withBuiltinKeys(array $builtin_keys) {
+ $this->builtinKeys = $builtin_keys;
+ return $this;
+ }
+
+ public function withIdentifiers(array $identifiers) {
+ $this->identifiers = $identifiers;
+ return $this;
+ }
+
+ public function newResultObject() {
+ return new PhabricatorEditEngineConfiguration();
+ }
+
+ protected function loadPage() {
+ // TODO: The logic here is a little flimsy and won't survive pagination.
+ // For now, I'm just not bothering with pagination since I believe it will
+ // take some time before any install manages to produce a large enough
+ // number of edit forms for any particular engine for the lack of UI
+ // pagination to become a problem.
+
+ $page = $this->loadStandardPage($this->newResultObject());
+
+ // Now that we've loaded the real results from the database, we're going
+ // to load builtins from the edit engines and add them to the list.
+
+ $engines = PhabricatorEditEngine::getAllEditEngines();
+
+ if ($this->engineKeys) {
+ $engines = array_select_keys($engines, $this->engineKeys);
+ }
+
+ foreach ($engines as $engine) {
+ $engine->setViewer($this->getViewer());
+ }
+
+ // List all the builtins which have already been saved to the database as
+ // real objects.
+ $concrete = array();
+ foreach ($page as $config) {
+ $builtin_key = $config->getBuiltinKey();
+ if ($builtin_key !== null) {
+ $engine_key = $config->getEngineKey();
+ $concrete[$engine_key][$builtin_key] = $config;
+ }
+ }
+
+ $builtins = array();
+ foreach ($engines as $engine_key => $engine) {
+ $engine_builtins = $engine->getBuiltinEngineConfigurations();
+ foreach ($engine_builtins as $engine_builtin) {
+ $builtin_key = $engine_builtin->getBuiltinKey();
+ if (isset($concrete[$engine_key][$builtin_key])) {
+ continue;
+ } else {
+ $builtins[] = $engine_builtin;
+ }
+ }
+ }
+
+ foreach ($builtins as $builtin) {
+ $page[] = $builtin;
+ }
+
+ // Now we have to do some extra filtering to make sure everything we're
+ // about to return really satisfies the query.
+
+ if ($this->ids !== null) {
+ $ids = array_fuse($this->ids);
+ foreach ($page as $key => $config) {
+ if (empty($ids[$config->getID()])) {
+ unset($page[$key]);
+ }
+ }
+ }
+
+ if ($this->phids !== null) {
+ $phids = array_fuse($this->phids);
+ foreach ($page as $key => $config) {
+ if (empty($phids[$config->getPHID()])) {
+ unset($page[$key]);
+ }
+ }
+ }
+
+ if ($this->builtinKeys !== null) {
+ $builtin_keys = array_fuse($this->builtinKeys);
+ foreach ($page as $key => $config) {
+ if (empty($builtin_keys[$config->getBuiltinKey()])) {
+ unset($page[$key]);
+ }
+ }
+ }
+
+ if ($this->identifiers !== null) {
+ $identifiers = array_fuse($this->identifiers);
+ foreach ($page as $key => $config) {
+ if (isset($identifiers[$config->getBuiltinKey()])) {
+ continue;
+ }
+ if (isset($identifiers[$config->getID()])) {
+ continue;
+ }
+ unset($page[$key]);
+ }
+ }
+
+ return $page;
+ }
+
+ protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) {
+ $where = parent::buildWhereClauseParts($conn);
+
+ if ($this->ids !== null) {
+ $where[] = qsprintf(
+ $conn,
+ 'id IN (%Ld)',
+ $this->ids);
+ }
+
+ if ($this->phids !== null) {
+ $where[] = qsprintf(
+ $conn,
+ 'phid IN (%Ls)',
+ $this->phids);
+ }
+
+ if ($this->engineKeys !== null) {
+ $where[] = qsprintf(
+ $conn,
+ 'engineKey IN (%Ls)',
+ $this->engineKeys);
+ }
+
+ if ($this->builtinKeys !== null) {
+ $where[] = qsprintf(
+ $conn,
+ 'builtinKey IN (%Ls)',
+ $this->builtinKeys);
+ }
+
+ if ($this->identifiers !== null) {
+ $where[] = qsprintf(
+ $conn,
+ '(id IN (%Ls) OR builtinKey IN (%Ls))',
+ $this->identifiers,
+ $this->identifiers);
+ }
+
+ return $where;
+ }
+
+ public function getQueryApplicationClass() {
+ return 'PhabricatorTransactionsApplication';
+ }
+
+}
diff --git a/src/applications/transactions/query/PhabricatorEditEngineConfigurationSearchEngine.php b/src/applications/transactions/query/PhabricatorEditEngineConfigurationSearchEngine.php
new file mode 100644
--- /dev/null
+++ b/src/applications/transactions/query/PhabricatorEditEngineConfigurationSearchEngine.php
@@ -0,0 +1,102 @@
+<?php
+
+final class PhabricatorEditEngineConfigurationSearchEngine
+ extends PhabricatorApplicationSearchEngine {
+
+ private $engineKey;
+
+ public function setEngineKey($engine_key) {
+ $this->engineKey = $engine_key;
+ return $this;
+ }
+
+ public function getEngineKey() {
+ return $this->engineKey;
+ }
+
+ public function canUseInPanelContext() {
+ return false;
+ }
+
+ public function getResultTypeDescription() {
+ return pht('Forms');
+ }
+
+ public function getApplicationClassName() {
+ return 'PhabricatorTransactionsApplication';
+ }
+
+ public function newQuery() {
+ return id(new PhabricatorEditEngineConfigurationQuery())
+ ->withEngineKeys(array($this->getEngineKey()));
+ }
+
+ protected function buildQueryFromParameters(array $map) {
+ $query = $this->newQuery();
+ return $query;
+ }
+
+ protected function buildCustomSearchFields() {
+ return array();
+ }
+
+ protected function getDefaultFieldOrder() {
+ return array();
+ }
+
+ protected function getURI($path) {
+ return '/transactions/editengine/'.$this->getEngineKey().'/'.$path;
+ }
+
+ protected function getBuiltinQueryNames() {
+ $names = array(
+ 'all' => pht('All Forms'),
+ );
+
+ return $names;
+ }
+
+ public function buildSavedQueryFromBuiltin($query_key) {
+ $query = $this->newSavedQuery();
+ $query->setQueryKey($query_key);
+
+ switch ($query_key) {
+ case 'all':
+ return $query;
+ }
+
+ return parent::buildSavedQueryFromBuiltin($query_key);
+ }
+
+ protected function renderResultList(
+ array $configs,
+ PhabricatorSavedQuery $query,
+ array $handles) {
+ assert_instances_of($configs, 'PhabricatorEditEngineConfiguration');
+ $viewer = $this->requireViewer();
+ $engine_key = $this->getEngineKey();
+
+ $list = id(new PHUIObjectItemListView())
+ ->setUser($viewer);
+ foreach ($configs as $config) {
+ $item = id(new PHUIObjectItemView())
+ ->setHeader($config->getDisplayName());
+
+ $id = $config->getID();
+ if ($id) {
+ $item->setObjectName(pht('Form %d', $id));
+ $key = $id;
+ } else {
+ $item->setObjectName(pht('Builtin'));
+ $key = $config->getBuiltinKey();
+ }
+ $item->setHref("/transactions/editengine/{$engine_key}/view/{$key}/");
+
+
+ $list->addItem($item);
+ }
+
+ return id(new PhabricatorApplicationSearchResultView())
+ ->setObjectList($list);
+ }
+}
diff --git a/src/applications/transactions/query/PhabricatorEditEngineConfigurationTransactionQuery.php b/src/applications/transactions/query/PhabricatorEditEngineConfigurationTransactionQuery.php
new file mode 100644
--- /dev/null
+++ b/src/applications/transactions/query/PhabricatorEditEngineConfigurationTransactionQuery.php
@@ -0,0 +1,10 @@
+<?php
+
+final class PhabricatorEditEngineConfigurationTransactionQuery
+ extends PhabricatorApplicationTransactionQuery {
+
+ public function getTemplateApplicationTransaction() {
+ return new PhabricatorEditEngineConfigurationTransaction();
+ }
+
+}
diff --git a/src/applications/transactions/query/PhabricatorEditEngineQuery.php b/src/applications/transactions/query/PhabricatorEditEngineQuery.php
new file mode 100644
--- /dev/null
+++ b/src/applications/transactions/query/PhabricatorEditEngineQuery.php
@@ -0,0 +1,31 @@
+<?php
+
+final class PhabricatorEditEngineQuery
+ extends PhabricatorCursorPagedPolicyAwareQuery {
+
+ private $engineKeys;
+
+ public function withEngineKeys(array $keys) {
+ $this->engineKeys = $keys;
+ return $this;
+ }
+
+ protected function loadPage() {
+ $engines = PhabricatorEditEngine::getAllEditEngines();
+
+ if ($this->engineKeys !== null) {
+ $engines = array_select_keys($engines, $this->engineKeys);
+ }
+
+ return $engines;
+ }
+
+ public function getQueryApplicationClass() {
+ return 'PhabricatorTransactionsApplication';
+ }
+
+ protected function getResultCursor($object) {
+ return null;
+ }
+
+}
diff --git a/src/applications/transactions/query/PhabricatorEditEngineSearchEngine.php b/src/applications/transactions/query/PhabricatorEditEngineSearchEngine.php
new file mode 100644
--- /dev/null
+++ b/src/applications/transactions/query/PhabricatorEditEngineSearchEngine.php
@@ -0,0 +1,78 @@
+<?php
+
+final class PhabricatorEditEngineSearchEngine
+ extends PhabricatorApplicationSearchEngine {
+
+ public function getResultTypeDescription() {
+ return pht('Edit Engines');
+ }
+
+ public function getApplicationClassName() {
+ return 'PhabricatorTransactionsApplication';
+ }
+
+ public function newQuery() {
+ return id(new PhabricatorEditEngineQuery());
+ }
+
+ protected function buildQueryFromParameters(array $map) {
+ $query = $this->newQuery();
+ return $query;
+ }
+
+ protected function buildCustomSearchFields() {
+ return array();
+ }
+
+ protected function getDefaultFieldOrder() {
+ return array();
+ }
+
+ protected function getURI($path) {
+ return '/transactions/editengine/'.$path;
+ }
+
+ protected function getBuiltinQueryNames() {
+ $names = array(
+ 'all' => pht('All Edit Engines'),
+ );
+
+ return $names;
+ }
+
+ public function buildSavedQueryFromBuiltin($query_key) {
+ $query = $this->newSavedQuery();
+ $query->setQueryKey($query_key);
+
+ switch ($query_key) {
+ case 'all':
+ return $query;
+ }
+
+ return parent::buildSavedQueryFromBuiltin($query_key);
+ }
+
+ protected function renderResultList(
+ array $engines,
+ PhabricatorSavedQuery $query,
+ array $handles) {
+ assert_instances_of($engines, 'PhabricatorEditEngine');
+ $viewer = $this->requireViewer();
+
+ $list = id(new PHUIObjectItemListView())
+ ->setUser($viewer);
+ foreach ($engines as $engine) {
+ $engine_key = $engine->getEngineKey();
+ $query_uri = "/transactions/editengine/{$engine_key}/";
+
+ $item = id(new PHUIObjectItemView())
+ ->setHeader($engine->getEngineName())
+ ->setHref($query_uri);
+
+ $list->addItem($item);
+ }
+
+ return id(new PhabricatorApplicationSearchResultView())
+ ->setObjectList($list);
+ }
+}
diff --git a/src/applications/transactions/storage/PhabricatorEditEngineConfiguration.php b/src/applications/transactions/storage/PhabricatorEditEngineConfiguration.php
new file mode 100644
--- /dev/null
+++ b/src/applications/transactions/storage/PhabricatorEditEngineConfiguration.php
@@ -0,0 +1,211 @@
+<?php
+
+final class PhabricatorEditEngineConfiguration
+ extends PhabricatorSearchDAO
+ implements
+ PhabricatorApplicationTransactionInterface,
+ PhabricatorPolicyInterface {
+
+ protected $engineKey;
+ protected $builtinKey;
+ protected $name;
+ protected $viewPolicy;
+ protected $editPolicy;
+ protected $properties = array();
+ protected $isDisabled = 0;
+ protected $isDefault = 0;
+
+ private $engine = self::ATTACHABLE;
+
+ public function getTableName() {
+ return 'search_editengineconfiguration';
+ }
+
+ public static function initializeNewConfiguration(
+ PhabricatorUser $actor,
+ PhabricatorEditEngine $engine) {
+
+ // TODO: This should probably be controlled by a new defualt capability.
+ $edit_policy = PhabricatorPolicies::POLICY_ADMIN;
+
+ return id(new PhabricatorEditEngineConfiguration())
+ ->setEngineKey($engine->getEngineKey())
+ ->attachEngine($engine)
+ ->setViewPolicy(PhabricatorPolicies::getMostOpenPolicy())
+ ->setEditPolicy($edit_policy);
+ }
+
+ public function generatePHID() {
+ return PhabricatorPHID::generateNewPHID(
+ PhabricatorEditEngineConfigurationPHIDType::TYPECONST);
+ }
+
+ protected function getConfiguration() {
+ return array(
+ self::CONFIG_AUX_PHID => true,
+ self::CONFIG_SERIALIZATION => array(
+ 'properties' => self::SERIALIZATION_JSON,
+ ),
+ self::CONFIG_COLUMN_SCHEMA => array(
+ 'engineKey' => 'text64',
+ 'builtinKey' => 'text64?',
+ 'name' => 'text255',
+ 'isDisabled' => 'bool',
+ 'isDefault' => 'bool',
+ ),
+ self::CONFIG_KEY_SCHEMA => array(
+ 'key_engine' => array(
+ 'columns' => array('engineKey', 'builtinKey'),
+ 'unique' => true,
+ ),
+ 'key_default' => array(
+ 'columns' => array('engineKey', 'isDefault', 'isDisabled'),
+ ),
+ ),
+ ) + parent::getConfiguration();
+ }
+
+ public function getProperty($key, $default = null) {
+ return idx($this->properties, $key, $default);
+ }
+
+ public function setProperty($key, $value) {
+ $this->properties[$key] = $value;
+ return $this;
+ }
+
+ public function attachEngine(PhabricatorEditEngine $engine) {
+ $this->engine = $engine;
+ return $this;
+ }
+
+ public function getEngine() {
+ return $this->assertAttached($this->engine);
+ }
+
+ public function applyConfigurationToFields(
+ PhabricatorEditEngine $engine,
+ array $fields) {
+ $fields = mpull($fields, null, 'getKey');
+
+ $values = $this->getProperty('defaults', array());
+ foreach ($fields as $key => $field) {
+ if ($engine->getIsCreate()) {
+ if (array_key_exists($key, $values)) {
+ $field->readDefaultValueFromConfiguration($values[$key]);
+ }
+ }
+ }
+
+ $fields = $this->reorderFields($fields);
+
+ $head_instructions = $this->getProperty('instructions.head');
+ if (strlen($head_instructions)) {
+ $fields = array(
+ 'config.instructions.head' => id(new PhabricatorInstructionsEditField())
+ ->setKey('config.instructions.head')
+ ->setValue($head_instructions),
+ ) + $fields;
+ }
+
+ return $fields;
+ }
+
+ private function reorderFields(array $fields) {
+ $keys = array();
+ $fields = array_select_keys($fields, $keys) + $fields;
+
+ // Now, move locked fields to the bottom.
+ $head = array();
+ $tail = array();
+ foreach ($fields as $key => $field) {
+ if (!$field->getIsLocked()) {
+ $head[$key] = $field;
+ } else {
+ $tail[$key] = $field;
+ }
+ }
+
+ return $head + $tail;
+ }
+
+ public function getURI() {
+ $engine_key = $this->getEngineKey();
+ $key = $this->getIdentifier();
+
+ return "/transactions/editengine/{$engine_key}/view/{$key}/";
+ }
+
+ public function getIdentifier() {
+ $key = $this->getID();
+ if (!$key) {
+ $key = $this->getBuiltinKey();
+ }
+ return $key;
+ }
+
+ public function getDisplayName() {
+ $name = $this->getName();
+ if (strlen($name)) {
+ return $name;
+ }
+
+ $builtin = $this->getBuiltinKey();
+ if ($builtin !== null) {
+ return pht('Builtin Form "%s"', $builtin);
+ }
+
+ return pht('Untitled Form');
+ }
+
+
+/* -( PhabricatorPolicyInterface )----------------------------------------- */
+
+
+ public function getCapabilities() {
+ return array(
+ PhabricatorPolicyCapability::CAN_VIEW,
+ PhabricatorPolicyCapability::CAN_EDIT,
+ );
+ }
+
+ public function getPolicy($capability) {
+ switch ($capability) {
+ case PhabricatorPolicyCapability::CAN_VIEW:
+ return $this->getViewPolicy();
+ case PhabricatorPolicyCapability::CAN_EDIT:
+ return $this->getEditPolicy();
+ }
+ }
+
+ public function hasAutomaticCapability($capability, PhabricatorUser $viewer) {
+ return false;
+ }
+
+ public function describeAutomaticCapability($capability) {
+ return null;
+ }
+
+
+/* -( PhabricatorApplicationTransactionInterface )------------------------- */
+
+
+ public function getApplicationTransactionEditor() {
+ return new PhabricatorEditEngineConfigurationEditor();
+ }
+
+ public function getApplicationTransactionObject() {
+ return $this;
+ }
+
+ public function getApplicationTransactionTemplate() {
+ return new PhabricatorEditEngineConfigurationTransaction();
+ }
+
+ public function willRenderTimeline(
+ PhabricatorApplicationTransactionView $timeline,
+ AphrontRequest $request) {
+ return $timeline;
+ }
+
+}
diff --git a/src/applications/transactions/storage/PhabricatorEditEngineConfigurationTransaction.php b/src/applications/transactions/storage/PhabricatorEditEngineConfigurationTransaction.php
new file mode 100644
--- /dev/null
+++ b/src/applications/transactions/storage/PhabricatorEditEngineConfigurationTransaction.php
@@ -0,0 +1,20 @@
+<?php
+
+final class PhabricatorEditEngineConfigurationTransaction
+ extends PhabricatorApplicationTransaction {
+
+ const TYPE_NAME = 'editengine.config.name';
+
+ public function getApplicationName() {
+ return 'search';
+ }
+
+ public function getApplicationTransactionType() {
+ return PhabricatorEditEngineConfigurationPHIDType::TYPECONST;
+ }
+
+ public function getApplicationTransactionCommentObject() {
+ return null;
+ }
+
+}
diff --git a/src/applications/transactions/view/PhabricatorApplicationEditHTTPParameterHelpView.php b/src/applications/transactions/view/PhabricatorApplicationEditHTTPParameterHelpView.php
--- a/src/applications/transactions/view/PhabricatorApplicationEditHTTPParameterHelpView.php
+++ b/src/applications/transactions/view/PhabricatorApplicationEditHTTPParameterHelpView.php
@@ -4,7 +4,7 @@
* Renders the "HTTP Parameters" help page for edit engines.
*
* This page has a ton of text and specialized rendering on it, this class
- * just pulls it out of the main @{class:PhabricatorApplicationEditEngine}.
+ * just pulls it out of the main @{class:PhabricatorEditEngine}.
*/
final class PhabricatorApplicationEditHTTPParameterHelpView
extends AphrontView {

File Metadata

Mime Type
text/plain
Expires
Sun, May 12, 10:41 AM (1 w, 4 d ago)
Storage Engine
amazon-s3
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
phabricator/secure/kj/fo/he7w2xm6xmwanhrt
Default Alt Text
D14453.id34953.diff (63 KB)

Event Timeline