Page MenuHomePhabricator

D14390.diff
No OneTemporary

D14390.diff

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
@@ -1570,6 +1570,7 @@
'PhabricatorApplicationDatasource' => 'applications/meta/typeahead/PhabricatorApplicationDatasource.php',
'PhabricatorApplicationDetailViewController' => 'applications/meta/controller/PhabricatorApplicationDetailViewController.php',
'PhabricatorApplicationEditController' => 'applications/meta/controller/PhabricatorApplicationEditController.php',
+ 'PhabricatorApplicationEditEngine' => 'applications/transactions/editengine/PhabricatorApplicationEditEngine.php',
'PhabricatorApplicationEmailCommandsController' => 'applications/meta/controller/PhabricatorApplicationEmailCommandsController.php',
'PhabricatorApplicationLaunchView' => 'applications/meta/view/PhabricatorApplicationLaunchView.php',
'PhabricatorApplicationPanelController' => 'applications/meta/controller/PhabricatorApplicationPanelController.php',
@@ -2063,6 +2064,7 @@
'PhabricatorDataCacheSpec' => 'applications/cache/spec/PhabricatorDataCacheSpec.php',
'PhabricatorDataNotAttachedException' => 'infrastructure/storage/lisk/PhabricatorDataNotAttachedException.php',
'PhabricatorDatabaseSetupCheck' => 'applications/config/check/PhabricatorDatabaseSetupCheck.php',
+ 'PhabricatorDatasourceEditField' => 'applications/transactions/editfield/PhabricatorDatasourceEditField.php',
'PhabricatorDateTimeSettingsPanel' => 'applications/settings/panel/PhabricatorDateTimeSettingsPanel.php',
'PhabricatorDebugController' => 'applications/system/controller/PhabricatorDebugController.php',
'PhabricatorDefaultRequestExceptionHandler' => 'aphront/handler/PhabricatorDefaultRequestExceptionHandler.php',
@@ -2097,6 +2099,7 @@
'PhabricatorEdgeTestCase' => 'infrastructure/edges/__tests__/PhabricatorEdgeTestCase.php',
'PhabricatorEdgeType' => 'infrastructure/edges/type/PhabricatorEdgeType.php',
'PhabricatorEdgeTypeTestCase' => 'infrastructure/edges/type/__tests__/PhabricatorEdgeTypeTestCase.php',
+ 'PhabricatorEditField' => 'applications/transactions/editfield/PhabricatorEditField.php',
'PhabricatorEditor' => 'infrastructure/PhabricatorEditor.php',
'PhabricatorElasticSearchEngine' => 'applications/search/engine/PhabricatorElasticSearchEngine.php',
'PhabricatorElasticSearchSetupCheck' => 'applications/config/check/PhabricatorElasticSearchSetupCheck.php',
@@ -2554,6 +2557,7 @@
'PhabricatorPasteController' => 'applications/paste/controller/PhabricatorPasteController.php',
'PhabricatorPasteDAO' => 'applications/paste/storage/PhabricatorPasteDAO.php',
'PhabricatorPasteEditController' => 'applications/paste/controller/PhabricatorPasteEditController.php',
+ 'PhabricatorPasteEditEngine' => 'applications/paste/editor/PhabricatorPasteEditEngine.php',
'PhabricatorPasteEditor' => 'applications/paste/editor/PhabricatorPasteEditor.php',
'PhabricatorPasteListController' => 'applications/paste/controller/PhabricatorPasteListController.php',
'PhabricatorPastePastePHIDType' => 'applications/paste/phid/PhabricatorPastePastePHIDType.php',
@@ -2654,6 +2658,7 @@
'PhabricatorPolicyDAO' => 'applications/policy/storage/PhabricatorPolicyDAO.php',
'PhabricatorPolicyDataTestCase' => 'applications/policy/__tests__/PhabricatorPolicyDataTestCase.php',
'PhabricatorPolicyEditController' => 'applications/policy/controller/PhabricatorPolicyEditController.php',
+ 'PhabricatorPolicyEditField' => 'applications/transactions/editfield/PhabricatorPolicyEditField.php',
'PhabricatorPolicyException' => 'applications/policy/exception/PhabricatorPolicyException.php',
'PhabricatorPolicyExplainController' => 'applications/policy/controller/PhabricatorPolicyExplainController.php',
'PhabricatorPolicyFilter' => 'applications/policy/filter/PhabricatorPolicyFilter.php',
@@ -2917,6 +2922,7 @@
'PhabricatorSearchWorker' => 'applications/search/worker/PhabricatorSearchWorker.php',
'PhabricatorSecurityConfigOptions' => 'applications/config/option/PhabricatorSecurityConfigOptions.php',
'PhabricatorSecuritySetupCheck' => 'applications/config/check/PhabricatorSecuritySetupCheck.php',
+ 'PhabricatorSelectEditField' => 'applications/transactions/editfield/PhabricatorSelectEditField.php',
'PhabricatorSendGridConfigOptions' => 'applications/config/option/PhabricatorSendGridConfigOptions.php',
'PhabricatorSessionsSettingsPanel' => 'applications/settings/panel/PhabricatorSessionsSettingsPanel.php',
'PhabricatorSettingsAddEmailAction' => 'applications/settings/action/PhabricatorSettingsAddEmailAction.php',
@@ -2957,6 +2963,7 @@
'PhabricatorSlugTestCase' => 'infrastructure/util/__tests__/PhabricatorSlugTestCase.php',
'PhabricatorSortTableUIExample' => 'applications/uiexample/examples/PhabricatorSortTableUIExample.php',
'PhabricatorSourceCodeView' => 'view/layout/PhabricatorSourceCodeView.php',
+ 'PhabricatorSpaceEditField' => 'applications/transactions/editfield/PhabricatorSpaceEditField.php',
'PhabricatorSpacesApplication' => 'applications/spaces/application/PhabricatorSpacesApplication.php',
'PhabricatorSpacesArchiveController' => 'applications/spaces/controller/PhabricatorSpacesArchiveController.php',
'PhabricatorSpacesCapabilityCreateSpaces' => 'applications/spaces/capability/PhabricatorSpacesCapabilityCreateSpaces.php',
@@ -3063,6 +3070,8 @@
'PhabricatorTestNoCycleEdgeType' => 'applications/transactions/edges/PhabricatorTestNoCycleEdgeType.php',
'PhabricatorTestStorageEngine' => 'applications/files/engine/PhabricatorTestStorageEngine.php',
'PhabricatorTestWorker' => 'infrastructure/daemon/workers/__tests__/PhabricatorTestWorker.php',
+ 'PhabricatorTextAreaEditField' => 'applications/transactions/editfield/PhabricatorTextAreaEditField.php',
+ 'PhabricatorTextEditField' => 'applications/transactions/editfield/PhabricatorTextEditField.php',
'PhabricatorTime' => 'infrastructure/time/PhabricatorTime.php',
'PhabricatorTimeGuard' => 'infrastructure/time/PhabricatorTimeGuard.php',
'PhabricatorTimeTestCase' => 'infrastructure/time/__tests__/PhabricatorTimeTestCase.php',
@@ -3084,6 +3093,7 @@
'PhabricatorTokenReceiverQuery' => 'applications/tokens/query/PhabricatorTokenReceiverQuery.php',
'PhabricatorTokenTokenPHIDType' => 'applications/tokens/phid/PhabricatorTokenTokenPHIDType.php',
'PhabricatorTokenUIEventListener' => 'applications/tokens/event/PhabricatorTokenUIEventListener.php',
+ 'PhabricatorTokenizerEditField' => 'applications/transactions/editfield/PhabricatorTokenizerEditField.php',
'PhabricatorTokensApplication' => 'applications/tokens/application/PhabricatorTokensApplication.php',
'PhabricatorTokensSettingsPanel' => 'applications/settings/panel/PhabricatorTokensSettingsPanel.php',
'PhabricatorTooltipUIExample' => 'applications/uiexample/examples/PhabricatorTooltipUIExample.php',
@@ -5489,6 +5499,7 @@
'PhabricatorApplicationDatasource' => 'PhabricatorTypeaheadDatasource',
'PhabricatorApplicationDetailViewController' => 'PhabricatorApplicationsController',
'PhabricatorApplicationEditController' => 'PhabricatorApplicationsController',
+ 'PhabricatorApplicationEditEngine' => 'Phobject',
'PhabricatorApplicationEmailCommandsController' => 'PhabricatorApplicationsController',
'PhabricatorApplicationLaunchView' => 'AphrontTagView',
'PhabricatorApplicationPanelController' => 'PhabricatorApplicationsController',
@@ -6080,6 +6091,7 @@
'PhabricatorDataCacheSpec' => 'PhabricatorCacheSpec',
'PhabricatorDataNotAttachedException' => 'Exception',
'PhabricatorDatabaseSetupCheck' => 'PhabricatorSetupCheck',
+ 'PhabricatorDatasourceEditField' => 'PhabricatorTokenizerEditField',
'PhabricatorDateTimeSettingsPanel' => 'PhabricatorSettingsPanel',
'PhabricatorDebugController' => 'PhabricatorController',
'PhabricatorDefaultRequestExceptionHandler' => 'PhabricatorRequestExceptionHandler',
@@ -6113,6 +6125,7 @@
'PhabricatorEdgeTestCase' => 'PhabricatorTestCase',
'PhabricatorEdgeType' => 'Phobject',
'PhabricatorEdgeTypeTestCase' => 'PhabricatorTestCase',
+ 'PhabricatorEditField' => 'Phobject',
'PhabricatorEditor' => 'Phobject',
'PhabricatorElasticSearchEngine' => 'PhabricatorSearchEngine',
'PhabricatorElasticSearchSetupCheck' => 'PhabricatorSetupCheck',
@@ -6647,6 +6660,7 @@
'PhabricatorPasteController' => 'PhabricatorController',
'PhabricatorPasteDAO' => 'PhabricatorLiskDAO',
'PhabricatorPasteEditController' => 'PhabricatorPasteController',
+ 'PhabricatorPasteEditEngine' => 'PhabricatorApplicationEditEngine',
'PhabricatorPasteEditor' => 'PhabricatorApplicationTransactionEditor',
'PhabricatorPasteListController' => 'PhabricatorPasteController',
'PhabricatorPastePastePHIDType' => 'PhabricatorPHIDType',
@@ -6762,6 +6776,7 @@
'PhabricatorPolicyDAO' => 'PhabricatorLiskDAO',
'PhabricatorPolicyDataTestCase' => 'PhabricatorTestCase',
'PhabricatorPolicyEditController' => 'PhabricatorPolicyController',
+ 'PhabricatorPolicyEditField' => 'PhabricatorEditField',
'PhabricatorPolicyException' => 'Exception',
'PhabricatorPolicyExplainController' => 'PhabricatorPolicyController',
'PhabricatorPolicyFilter' => 'Phobject',
@@ -7090,6 +7105,7 @@
'PhabricatorSearchWorker' => 'PhabricatorWorker',
'PhabricatorSecurityConfigOptions' => 'PhabricatorApplicationConfigOptions',
'PhabricatorSecuritySetupCheck' => 'PhabricatorSetupCheck',
+ 'PhabricatorSelectEditField' => 'PhabricatorEditField',
'PhabricatorSendGridConfigOptions' => 'PhabricatorApplicationConfigOptions',
'PhabricatorSessionsSettingsPanel' => 'PhabricatorSettingsPanel',
'PhabricatorSettingsAddEmailAction' => 'PhabricatorSystemAction',
@@ -7140,6 +7156,7 @@
'PhabricatorSlugTestCase' => 'PhabricatorTestCase',
'PhabricatorSortTableUIExample' => 'PhabricatorUIExample',
'PhabricatorSourceCodeView' => 'AphrontView',
+ 'PhabricatorSpaceEditField' => 'PhabricatorEditField',
'PhabricatorSpacesApplication' => 'PhabricatorApplication',
'PhabricatorSpacesArchiveController' => 'PhabricatorSpacesController',
'PhabricatorSpacesCapabilityCreateSpaces' => 'PhabricatorPolicyCapability',
@@ -7252,6 +7269,8 @@
'PhabricatorTestNoCycleEdgeType' => 'PhabricatorEdgeType',
'PhabricatorTestStorageEngine' => 'PhabricatorFileStorageEngine',
'PhabricatorTestWorker' => 'PhabricatorWorker',
+ 'PhabricatorTextAreaEditField' => 'PhabricatorEditField',
+ 'PhabricatorTextEditField' => 'PhabricatorEditField',
'PhabricatorTime' => 'Phobject',
'PhabricatorTimeGuard' => 'Phobject',
'PhabricatorTimeTestCase' => 'PhabricatorTestCase',
@@ -7278,6 +7297,7 @@
'PhabricatorTokenReceiverQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
'PhabricatorTokenTokenPHIDType' => 'PhabricatorPHIDType',
'PhabricatorTokenUIEventListener' => 'PhabricatorEventListener',
+ 'PhabricatorTokenizerEditField' => 'PhabricatorEditField',
'PhabricatorTokensApplication' => 'PhabricatorApplication',
'PhabricatorTokensSettingsPanel' => 'PhabricatorSettingsPanel',
'PhabricatorTooltipUIExample' => 'PhabricatorUIExample',
diff --git a/src/applications/base/controller/PhabricatorController.php b/src/applications/base/controller/PhabricatorController.php
--- a/src/applications/base/controller/PhabricatorController.php
+++ b/src/applications/base/controller/PhabricatorController.php
@@ -521,6 +521,14 @@
}
+ public function buildApplicationCrumbsForEditEngine() {
+ // TODO: This is kind of gross, I'm bascially just making this public so
+ // I can use it in EditEngine. We could do this without making it public
+ // by using controller delegation, or make it properly public.
+ return $this->buildApplicationCrumbs();
+ }
+
+
/* -( Deprecated )--------------------------------------------------------- */
diff --git a/src/applications/paste/conduit/PasteCreateConduitAPIMethod.php b/src/applications/paste/conduit/PasteCreateConduitAPIMethod.php
--- a/src/applications/paste/conduit/PasteCreateConduitAPIMethod.php
+++ b/src/applications/paste/conduit/PasteCreateConduitAPIMethod.php
@@ -44,16 +44,11 @@
$paste = PhabricatorPaste::initializeNewPaste($viewer);
- $file = PhabricatorPasteEditor::initializeFileForPaste(
- $viewer,
- $title,
- $content);
-
$xactions = array();
$xactions[] = id(new PhabricatorPasteTransaction())
->setTransactionType(PhabricatorPasteTransaction::TYPE_CONTENT)
- ->setNewValue($file->getPHID());
+ ->setNewValue($content);
$xactions[] = id(new PhabricatorPasteTransaction())
->setTransactionType(PhabricatorPasteTransaction::TYPE_TITLE)
diff --git a/src/applications/paste/controller/PhabricatorPasteEditController.php b/src/applications/paste/controller/PhabricatorPasteEditController.php
--- a/src/applications/paste/controller/PhabricatorPasteEditController.php
+++ b/src/applications/paste/controller/PhabricatorPasteEditController.php
@@ -3,248 +3,9 @@
final class PhabricatorPasteEditController extends PhabricatorPasteController {
public function handleRequest(AphrontRequest $request) {
- $viewer = $request->getViewer();
- $id = $request->getURIData('id');
-
- $parent = null;
- $parent_id = null;
- if (!$id) {
- $is_create = true;
-
- $paste = PhabricatorPaste::initializeNewPaste($viewer);
-
- $parent_id = $request->getStr('parent');
- if ($parent_id) {
- // NOTE: If the Paste is forked from a paste which the user no longer
- // has permission to see, we still let them edit it.
- $parent = id(new PhabricatorPasteQuery())
- ->setViewer($viewer)
- ->withIDs(array($parent_id))
- ->needContent(true)
- ->needRawContent(true)
- ->execute();
- $parent = head($parent);
-
- if ($parent) {
- $paste->setParentPHID($parent->getPHID());
- $paste->setViewPolicy($parent->getViewPolicy());
- }
- }
-
- $paste->setAuthorPHID($viewer->getPHID());
- $paste->attachRawContent('');
- } else {
- $is_create = false;
-
- $paste = id(new PhabricatorPasteQuery())
- ->setViewer($viewer)
- ->requireCapabilities(
- array(
- PhabricatorPolicyCapability::CAN_VIEW,
- PhabricatorPolicyCapability::CAN_EDIT,
- ))
- ->withIDs(array($id))
- ->needRawContent(true)
- ->executeOne();
- if (!$paste) {
- return new Aphront404Response();
- }
- }
-
- $v_space = $paste->getSpacePHID();
- if ($is_create && $parent) {
- $v_title = pht('Fork of %s', $parent->getFullName());
- $v_language = $parent->getLanguage();
- $v_text = $parent->getRawContent();
- $v_space = $parent->getSpacePHID();
- } else {
- $v_title = $paste->getTitle();
- $v_language = $paste->getLanguage();
- $v_text = $paste->getRawContent();
- }
- $v_view_policy = $paste->getViewPolicy();
- $v_edit_policy = $paste->getEditPolicy();
- $v_status = $paste->getStatus();
-
- if ($is_create) {
- $v_projects = array();
- } else {
- $v_projects = PhabricatorEdgeQuery::loadDestinationPHIDs(
- $paste->getPHID(),
- PhabricatorProjectObjectHasProjectEdgeType::EDGECONST);
- $v_projects = array_reverse($v_projects);
- }
-
- $validation_exception = null;
- if ($request->isFormPost()) {
- $xactions = array();
-
- $v_text = $request->getStr('text');
- $v_title = $request->getStr('title');
- $v_language = $request->getStr('language');
- $v_view_policy = $request->getStr('can_view');
- $v_edit_policy = $request->getStr('can_edit');
- $v_projects = $request->getArr('projects');
- $v_space = $request->getStr('spacePHID');
- $v_status = $request->getStr('status');
-
- // NOTE: The author is the only editor and can always view the paste,
- // so it's impossible for them to choose an invalid policy.
-
- if ($is_create || ($v_text !== $paste->getRawContent())) {
- $file = PhabricatorPasteEditor::initializeFileForPaste(
- $viewer,
- $v_title,
- $v_text);
-
- $xactions[] = id(new PhabricatorPasteTransaction())
- ->setTransactionType(PhabricatorPasteTransaction::TYPE_CONTENT)
- ->setNewValue($file->getPHID());
- }
-
- $xactions[] = id(new PhabricatorPasteTransaction())
- ->setTransactionType(PhabricatorPasteTransaction::TYPE_TITLE)
- ->setNewValue($v_title);
- $xactions[] = id(new PhabricatorPasteTransaction())
- ->setTransactionType(PhabricatorPasteTransaction::TYPE_LANGUAGE)
- ->setNewValue($v_language);
- $xactions[] = id(new PhabricatorPasteTransaction())
- ->setTransactionType(PhabricatorTransactions::TYPE_VIEW_POLICY)
- ->setNewValue($v_view_policy);
- $xactions[] = id(new PhabricatorPasteTransaction())
- ->setTransactionType(PhabricatorTransactions::TYPE_EDIT_POLICY)
- ->setNewValue($v_edit_policy);
- $xactions[] = id(new PhabricatorPasteTransaction())
- ->setTransactionType(PhabricatorTransactions::TYPE_SPACE)
- ->setNewValue($v_space);
- $xactions[] = id(new PhabricatorPasteTransaction())
- ->setTransactionType(PhabricatorPasteTransaction::TYPE_STATUS)
- ->setNewValue($v_status);
-
- $proj_edge_type = PhabricatorProjectObjectHasProjectEdgeType::EDGECONST;
- $xactions[] = id(new PhabricatorPasteTransaction())
- ->setTransactionType(PhabricatorTransactions::TYPE_EDGE)
- ->setMetadataValue('edge:type', $proj_edge_type)
- ->setNewValue(array('=' => array_fuse($v_projects)));
-
- $editor = id(new PhabricatorPasteEditor())
- ->setActor($viewer)
- ->setContentSourceFromRequest($request)
- ->setContinueOnNoEffect(true);
-
- try {
- $xactions = $editor->applyTransactions($paste, $xactions);
- return id(new AphrontRedirectResponse())->setURI($paste->getURI());
- } catch (PhabricatorApplicationTransactionValidationException $ex) {
- $validation_exception = $ex;
- }
- }
-
- $form = new AphrontFormView();
-
- $langs = array(
- '' => pht('(Detect From Filename in Title)'),
- ) + PhabricatorEnv::getEnvConfig('pygments.dropdown-choices');
-
- $form
- ->setUser($viewer)
- ->addHiddenInput('parent', $parent_id)
- ->appendChild(
- id(new AphrontFormTextControl())
- ->setLabel(pht('Title'))
- ->setValue($v_title)
- ->setName('title'))
- ->appendChild(
- id(new AphrontFormSelectControl())
- ->setLabel(pht('Language'))
- ->setName('language')
- ->setValue($v_language)
- ->setOptions($langs));
-
- $policies = id(new PhabricatorPolicyQuery())
- ->setViewer($viewer)
- ->setObject($paste)
- ->execute();
-
- $form->appendChild(
- id(new AphrontFormPolicyControl())
- ->setUser($viewer)
- ->setCapability(PhabricatorPolicyCapability::CAN_VIEW)
- ->setPolicyObject($paste)
- ->setPolicies($policies)
- ->setValue($v_view_policy)
- ->setSpacePHID($v_space)
- ->setName('can_view'));
-
- $form->appendChild(
- id(new AphrontFormPolicyControl())
- ->setUser($viewer)
- ->setCapability(PhabricatorPolicyCapability::CAN_EDIT)
- ->setPolicyObject($paste)
- ->setPolicies($policies)
- ->setValue($v_edit_policy)
- ->setName('can_edit'));
-
- $form->appendChild(
- id(new AphrontFormSelectControl())
- ->setLabel(pht('Status'))
- ->setName('status')
- ->setValue($v_status)
- ->setOptions($paste->getStatusNameMap()));
-
- $form->appendControl(
- id(new AphrontFormTokenizerControl())
- ->setLabel(pht('Projects'))
- ->setName('projects')
- ->setValue($v_projects)
- ->setDatasource(new PhabricatorProjectDatasource()));
-
- $form
- ->appendChild(
- id(new AphrontFormTextAreaControl())
- ->setLabel(pht('Text'))
- ->setValue($v_text)
- ->setHeight(AphrontFormTextAreaControl::HEIGHT_VERY_TALL)
- ->setCustomClass('PhabricatorMonospaced')
- ->setName('text'));
-
- $submit = new AphrontFormSubmitControl();
-
- if (!$is_create) {
- $submit->addCancelButton($paste->getURI());
- $submit->setValue(pht('Save Paste'));
- $title = pht('Edit %s', $paste->getFullName());
- $short = pht('Edit');
- } else {
- $submit->setValue(pht('Create Paste'));
- $title = pht('Create New Paste');
- $short = pht('Create');
- }
-
- $form->appendChild($submit);
-
- $form_box = id(new PHUIObjectBoxView())
- ->setHeaderText($title)
- ->setForm($form);
-
- if ($validation_exception) {
- $form_box->setValidationException($validation_exception);
- }
-
- $crumbs = $this->buildApplicationCrumbs();
- if (!$is_create) {
- $crumbs->addTextCrumb('P'.$paste->getID(), '/P'.$paste->getID());
- }
- $crumbs->addTextCrumb($short);
-
- return $this->buildApplicationPage(
- array(
- $crumbs,
- $form_box,
- ),
- array(
- 'title' => $title,
- ));
+ return id(new PhabricatorPasteEditEngine())
+ ->setController($this)
+ ->buildResponse();
}
}
diff --git a/src/applications/paste/controller/PhabricatorPasteViewController.php b/src/applications/paste/controller/PhabricatorPasteViewController.php
--- a/src/applications/paste/controller/PhabricatorPasteViewController.php
+++ b/src/applications/paste/controller/PhabricatorPasteViewController.php
@@ -137,9 +137,7 @@
$paste,
PhabricatorPolicyCapability::CAN_EDIT);
- $can_fork = $viewer->isLoggedIn();
$id = $paste->getID();
- $fork_uri = $this->getApplicationURI('/create/?parent='.$id);
return id(new PhabricatorActionListView())
->setUser($viewer)
@@ -154,13 +152,6 @@
->setHref($this->getApplicationURI("edit/{$id}/")))
->addAction(
id(new PhabricatorActionView())
- ->setName(pht('Fork This Paste'))
- ->setIcon('fa-code-fork')
- ->setDisabled(!$can_fork)
- ->setWorkflow(!$can_fork)
- ->setHref($fork_uri))
- ->addAction(
- id(new PhabricatorActionView())
->setName(pht('View Raw File'))
->setIcon('fa-file-text-o')
->setHref($this->getApplicationURI("raw/{$id}/")));
diff --git a/src/applications/paste/editor/PhabricatorPasteEditEngine.php b/src/applications/paste/editor/PhabricatorPasteEditEngine.php
new file mode 100644
--- /dev/null
+++ b/src/applications/paste/editor/PhabricatorPasteEditEngine.php
@@ -0,0 +1,69 @@
+<?php
+
+final class PhabricatorPasteEditEngine
+ extends PhabricatorApplicationEditEngine {
+
+ protected function newEditableObject() {
+ return PhabricatorPaste::initializeNewPaste($this->getViewer());
+ }
+
+ protected function newObjectQuery() {
+ return id(new PhabricatorPasteQuery())
+ ->needRawContent(true);
+ }
+
+ protected function getObjectCreateTitleText($object) {
+ return pht('Create New Paste');
+ }
+
+ protected function getObjectEditTitleText($object) {
+ return pht('Edit %s %s', $object->getMonogram(), $object->getTitle());
+ }
+
+ protected function getObjectEditShortText($object) {
+ return $object->getMonogram();
+ }
+
+ protected function getObjectCreateShortText($object) {
+ return pht('Create Paste');
+ }
+
+ protected function getObjectViewURI($object) {
+ return '/P'.$object->getID();
+ }
+
+ protected function buildCustomEditFields($object) {
+ $langs = array(
+ '' => pht('(Detect From Filename in Title)'),
+ ) + PhabricatorEnv::getEnvConfig('pygments.dropdown-choices');
+
+ return array(
+ id(new PhabricatorTextEditField())
+ ->setKey('title')
+ ->setLabel(pht('Title'))
+ ->setTransactionType(PhabricatorPasteTransaction::TYPE_TITLE)
+ ->setValue($object->getTitle()),
+ id(new PhabricatorSelectEditField())
+ ->setKey('language')
+ ->setLabel(pht('Language'))
+ ->setAliases(array('lang'))
+ ->setTransactionType(PhabricatorPasteTransaction::TYPE_LANGUAGE)
+ ->setValue($object->getLanguage())
+ ->setOptions($langs),
+ id(new PhabricatorSelectEditField())
+ ->setKey('status')
+ ->setLabel(pht('Status'))
+ ->setTransactionType(PhabricatorPasteTransaction::TYPE_STATUS)
+ ->setValue($object->getStatus())
+ ->setOptions(PhabricatorPaste::getStatusNameMap()),
+ id(new PhabricatorTextAreaEditField())
+ ->setKey('text')
+ ->setLabel(pht('Text'))
+ ->setTransactionType(PhabricatorPasteTransaction::TYPE_CONTENT)
+ ->setMonospaced(true)
+ ->setHeight(AphrontFormTextAreaControl::HEIGHT_VERY_TALL)
+ ->setValue($object->getRawContent()),
+ );
+ }
+
+}
diff --git a/src/applications/paste/editor/PhabricatorPasteEditor.php b/src/applications/paste/editor/PhabricatorPasteEditor.php
--- a/src/applications/paste/editor/PhabricatorPasteEditor.php
+++ b/src/applications/paste/editor/PhabricatorPasteEditor.php
@@ -3,6 +3,8 @@
final class PhabricatorPasteEditor
extends PhabricatorApplicationTransactionEditor {
+ private $fileName;
+
public function getEditorApplicationClass() {
return 'PhabricatorPasteApplication';
}
@@ -41,6 +43,35 @@
return $types;
}
+ protected function shouldApplyInitialEffects(
+ PhabricatorLiskDAO $object,
+ array $xactions) {
+ return true;
+ }
+
+ protected function applyInitialEffects(
+ PhabricatorLiskDAO $object,
+ array $xactions) {
+
+ // Find the most user-friendly filename we can by examining the title of
+ // the paste and the pending transactions. We'll use this if we create a
+ // new file to store raw content later.
+
+ $name = $object->getTitle();
+ if (!strlen($name)) {
+ $name = 'paste.raw';
+ }
+
+ $type_title = PhabricatorPasteTransaction::TYPE_TITLE;
+ foreach ($xactions as $xaction) {
+ if ($xaction->getTransactionType() == $type_title) {
+ $name = $xaction->getNewValue();
+ }
+ }
+
+ $this->fileName = $name;
+ }
+
protected function getCustomTransactionOldValue(
PhabricatorLiskDAO $object,
PhabricatorApplicationTransaction $xaction) {
@@ -62,11 +93,26 @@
PhabricatorApplicationTransaction $xaction) {
switch ($xaction->getTransactionType()) {
- case PhabricatorPasteTransaction::TYPE_CONTENT:
case PhabricatorPasteTransaction::TYPE_TITLE:
case PhabricatorPasteTransaction::TYPE_LANGUAGE:
case PhabricatorPasteTransaction::TYPE_STATUS:
return $xaction->getNewValue();
+ case PhabricatorPasteTransaction::TYPE_CONTENT:
+ // If this transaction does not really change the paste content, return
+ // the current file PHID so this transaction no-ops.
+ $new_content = $xaction->getNewValue();
+ $old_content = $object->getRawContent();
+ $file_phid = $object->getFilePHID();
+ if (($new_content === $old_content) && $file_phid) {
+ return $file_phid;
+ }
+
+ $file = self::initializeFileForPaste(
+ $this->getActor(),
+ $this->fileName,
+ $xaction->getNewValue());
+
+ return $file->getPHID();
}
}
diff --git a/src/applications/paste/mail/PasteCreateMailReceiver.php b/src/applications/paste/mail/PasteCreateMailReceiver.php
--- a/src/applications/paste/mail/PasteCreateMailReceiver.php
+++ b/src/applications/paste/mail/PasteCreateMailReceiver.php
@@ -21,16 +21,11 @@
$title = pht('Email Paste');
}
- $file = PhabricatorPasteEditor::initializeFileForPaste(
- $sender,
- $title,
- $mail->getCleanTextBody());
-
$xactions = array();
$xactions[] = id(new PhabricatorPasteTransaction())
->setTransactionType(PhabricatorPasteTransaction::TYPE_CONTENT)
- ->setNewValue($file->getPHID());
+ ->setNewValue($mail->getCleanTextBody());
$xactions[] = id(new PhabricatorPasteTransaction())
->setTransactionType(PhabricatorPasteTransaction::TYPE_TITLE)
diff --git a/src/applications/paste/storage/PhabricatorPaste.php b/src/applications/paste/storage/PhabricatorPaste.php
--- a/src/applications/paste/storage/PhabricatorPaste.php
+++ b/src/applications/paste/storage/PhabricatorPaste.php
@@ -45,7 +45,8 @@
->setAuthorPHID($actor->getPHID())
->setViewPolicy($view_policy)
->setEditPolicy($edit_policy)
- ->setSpacePHID($actor->getDefaultSpacePHID());
+ ->setSpacePHID($actor->getDefaultSpacePHID())
+ ->attachRawContent(null);
}
public static function getStatusNameMap() {
diff --git a/src/applications/transactions/editengine/PhabricatorApplicationEditEngine.php b/src/applications/transactions/editengine/PhabricatorApplicationEditEngine.php
new file mode 100644
--- /dev/null
+++ b/src/applications/transactions/editengine/PhabricatorApplicationEditEngine.php
@@ -0,0 +1,303 @@
+<?php
+
+abstract class PhabricatorApplicationEditEngine extends Phobject {
+
+ private $viewer;
+ private $controller;
+
+ final public function setViewer(PhabricatorUser $viewer) {
+ $this->viewer = $viewer;
+ return $this;
+ }
+
+ final public function getViewer() {
+ return $this->viewer;
+ }
+
+ final public function setController(PhabricatorController $controller) {
+ $this->controller = $controller;
+ $this->setViewer($controller->getViewer());
+ return $this;
+ }
+
+ final public function getController() {
+ return $this->controller;
+ }
+
+ final protected function buildEditFields($object) {
+ $viewer = $this->getViewer();
+ $editor = $object->getApplicationTransactionEditor();
+
+ $types = $editor->getTransactionTypesForObject($object);
+ $types = array_fuse($types);
+
+ $fields = $this->buildCustomEditFields($object);
+
+ if ($object instanceof PhabricatorPolicyInterface) {
+ $policies = id(new PhabricatorPolicyQuery())
+ ->setViewer($viewer)
+ ->setObject($object)
+ ->execute();
+
+ $map = array(
+ PhabricatorTransactions::TYPE_VIEW_POLICY => array(
+ 'key' => 'policy.view',
+ 'aliases' => array('view'),
+ 'capability' => PhabricatorPolicyCapability::CAN_VIEW,
+ ),
+ PhabricatorTransactions::TYPE_EDIT_POLICY => array(
+ 'key' => 'policy.edit',
+ 'aliases' => array('edit'),
+ 'capability' => PhabricatorPolicyCapability::CAN_EDIT,
+ ),
+ PhabricatorTransactions::TYPE_JOIN_POLICY => array(
+ 'key' => 'policy.join',
+ 'aliases' => array('join'),
+ 'capability' => PhabricatorPolicyCapability::CAN_JOIN,
+ ),
+ );
+
+ foreach ($map as $type => $spec) {
+ if (empty($types[$type])) {
+ continue;
+ }
+
+ $capability = $spec['capability'];
+ $key = $spec['key'];
+ $aliases = $spec['aliases'];
+
+ $policy_field = id(new PhabricatorPolicyEditField())
+ ->setKey($key)
+ ->setAliases($aliases)
+ ->setCapability($capability)
+ ->setPolicies($policies)
+ ->setTransactionType($type)
+ ->setValue($object->getPolicy($capability));
+ $fields[] = $policy_field;
+
+ if ($object instanceof PhabricatorSpacesInterface) {
+ if ($capability == PhabricatorPolicyCapability::CAN_VIEW) {
+ $type_space = PhabricatorTransactions::TYPE_SPACE;
+ if (isset($types[$type_space])) {
+ $space_field = id(new PhabricatorSpaceEditField())
+ ->setKey('spacePHID')
+ ->setAliases(array('space', 'policy.space'))
+ ->setTransactionType($type_space)
+ ->setValue($object->getSpacePHID());
+ $fields[] = $space_field;
+
+ $policy_field->setSpaceField($space_field);
+ }
+ }
+ }
+ }
+ }
+
+ $edge_type = PhabricatorTransactions::TYPE_EDGE;
+ $object_phid = $object->getPHID();
+
+ $project_edge_type = PhabricatorProjectObjectHasProjectEdgeType::EDGECONST;
+
+ if ($object instanceof PhabricatorProjectInterface) {
+ if (isset($types[$edge_type])) {
+ if ($object_phid) {
+ $project_phids = PhabricatorEdgeQuery::loadDestinationPHIDs(
+ $object_phid,
+ $project_edge_type);
+ $project_phids = array_reverse($project_phids);
+ } else {
+ $project_phids = array();
+ }
+
+ $edge_field = id(new PhabricatorDatasourceEditField())
+ ->setKey('projectPHIDs')
+ ->setLabel(pht('Projects'))
+ ->setDatasource(new PhabricatorProjectDatasource())
+ ->setAliases(array('project', 'projects'))
+ ->setTransactionType($edge_type)
+ ->setMetadataValue('edge:type', $project_edge_type)
+ ->setValue($project_phids);
+ $fields[] = $edge_field;
+ }
+ }
+
+ $subscribers_type = PhabricatorTransactions::TYPE_SUBSCRIBERS;
+
+ if ($object instanceof PhabricatorSubscribableInterface) {
+ if (isset($types[$subscribers_type])) {
+ if ($object_phid) {
+ $sub_phids = PhabricatorSubscribersQuery::loadSubscribersForPHID(
+ $object_phid);
+ } else {
+ // TODO: Allow applications to provide default subscribers; Maniphest
+ // does this at a minimum.
+ $sub_phids = array();
+ }
+
+ $subscribers_field = id(new PhabricatorDatasourceEditField())
+ ->setKey('subscriberPHIDs')
+ ->setLabel(pht('Subscribers'))
+ ->setDatasource(new PhabricatorMetaMTAMailableDatasource())
+ ->setAliases(array('subscriber', 'subscribers'))
+ ->setTransactionType($subscribers_type)
+ ->setValue($sub_phids);
+ $fields[] = $subscribers_field;
+ }
+ }
+
+ return $fields;
+ }
+
+ abstract protected function newEditableObject();
+ abstract protected function newObjectQuery();
+ abstract protected function buildCustomEditFields($object);
+
+ abstract protected function getObjectCreateTitleText($object);
+ abstract protected function getObjectEditTitleText($object);
+ abstract protected function getObjectCreateShortText($object);
+ abstract protected function getObjectEditShortText($object);
+ abstract protected function getObjectViewURI($object);
+
+ protected function getObjectCreateCancelURI($object) {
+ return $this->getController()->getApplicationURI();
+ }
+
+ protected function getObjectEditCancelURI($object) {
+ return $this->getObjectViewURI($object);
+ }
+
+ protected function getObjectCreateButtonText($object) {
+ return $this->getObjectCreateTitleText($object);
+ }
+
+ protected function getObjectEditButtonText($object) {
+ return pht('Save Changes');
+ }
+
+ final public function buildResponse() {
+ $controller = $this->getController();
+ $viewer = $this->getViewer();
+ $request = $controller->getRequest();
+
+ $id = $request->getURIData('id');
+ if ($id) {
+ $object = $this->newObjectQuery()
+ ->setViewer($viewer)
+ ->withIDs(array($id))
+ ->requireCapabilities(
+ array(
+ PhabricatorPolicyCapability::CAN_VIEW,
+ PhabricatorPolicyCapability::CAN_EDIT,
+ ))
+ ->executeOne();
+ if (!$object) {
+ return new Aphront404Response();
+ }
+
+ $is_create = false;
+ } else {
+ $object = $this->newEditableObject();
+
+ $is_create = true;
+ }
+
+ $fields = $this->buildEditFields($object);
+
+ foreach ($fields as $field) {
+ $field
+ ->setViewer($viewer)
+ ->setObject($object);
+ }
+
+ $validation_exception = null;
+ if ($request->isFormPost()) {
+ foreach ($fields as $field) {
+ $field->readValueFromSubmit($request);
+ }
+
+ $template = $object->getApplicationTransactionTemplate();
+
+ $xactions = array();
+ foreach ($fields as $field) {
+ $xactions[] = $field->generateTransaction(clone $template);
+ }
+
+ $editor = $object->getApplicationTransactionEditor()
+ ->setActor($viewer)
+ ->setContentSourceFromRequest($request)
+ ->setContinueOnNoEffect(true)
+ ->setContinueOnMissingFields(false);
+
+ try {
+
+ $editor->applyTransactions($object, $xactions);
+
+ return id(new AphrontRedirectResponse())
+ ->setURI($this->getObjectViewURI($object));
+ } catch (PhabricatorApplicationTransactionValidationException $ex) {
+ $validation_exception = $ex;
+ }
+ } else {
+ if ($is_create) {
+ foreach ($fields as $field) {
+ $field->readValueFromRequest($request);
+ }
+ } else {
+ foreach ($fields as $field) {
+ $field->readValueFromObject($object);
+ }
+ }
+ }
+
+ $box = id(new PHUIObjectBoxView())
+ ->setUser($viewer);
+
+ $crumbs = $controller->buildApplicationCrumbsForEditEngine();
+
+ if ($is_create) {
+ $header_text = $this->getObjectCreateTitleText($object);
+
+ $crumbs->addTextCrumb(
+ $this->getObjectCreateShortText($object));
+
+ $cancel_uri = $this->getObjectCreateCancelURI($object);
+ $submit_button = $this->getObjectCreateButtonText($object);
+ } else {
+ $header_text = $this->getObjectEditTitleText($object);
+
+ $crumbs->addTextCrumb(
+ $this->getObjectEditShortText($object),
+ $this->getObjectViewURI($object));
+
+ $cancel_uri = $this->getObjectEditCancelURI($object);
+ $submit_button = $this->getObjectEditButtonText($object);
+ }
+
+ $box->setHeaderText($header_text);
+
+ $form = id(new AphrontFormView())
+ ->setUser($viewer);
+
+ foreach ($fields as $field) {
+ $field->appendToForm($form);
+ }
+
+ $form->appendControl(
+ id(new AphrontFormSubmitControl())
+ ->addCancelButton($cancel_uri)
+ ->setValue($submit_button));
+
+ $box->appendChild($form);
+
+ if ($validation_exception) {
+ $box->setValidationException($validation_exception);
+ }
+
+ return $controller->newPage()
+ ->setTitle($header_text)
+ ->setCrumbs($crumbs)
+ ->appendChild($box);
+ }
+
+
+}
diff --git a/src/applications/transactions/editfield/PhabricatorDatasourceEditField.php b/src/applications/transactions/editfield/PhabricatorDatasourceEditField.php
new file mode 100644
--- /dev/null
+++ b/src/applications/transactions/editfield/PhabricatorDatasourceEditField.php
@@ -0,0 +1,21 @@
+<?php
+
+final class PhabricatorDatasourceEditField
+ extends PhabricatorTokenizerEditField {
+
+ private $datasource;
+
+ public function setDatasource(PhabricatorTypeaheadDatasource $datasource) {
+ $this->datasource = $datasource;
+ return $this;
+ }
+
+ public function getDatasource() {
+ return $this->datasource;
+ }
+
+ protected function newDatasource() {
+ return id(clone $this->getDatasource());
+ }
+
+}
diff --git a/src/applications/transactions/editfield/PhabricatorEditField.php b/src/applications/transactions/editfield/PhabricatorEditField.php
new file mode 100644
--- /dev/null
+++ b/src/applications/transactions/editfield/PhabricatorEditField.php
@@ -0,0 +1,212 @@
+<?php
+
+abstract class PhabricatorEditField extends Phobject {
+
+ private $key;
+ private $viewer;
+ private $label;
+ private $aliases = array();
+ private $value;
+ private $hasValue = false;
+ private $object;
+ private $transactionType;
+ private $metadata = array();
+
+ public function setKey($key) {
+ $this->key = $key;
+ return $this;
+ }
+
+ public function getKey() {
+ return $this->key;
+ }
+
+ public function setLabel($label) {
+ $this->label = $label;
+ return $this;
+ }
+
+ public function getLabel() {
+ return $this->label;
+ }
+
+ public function setViewer(PhabricatorUser $viewer) {
+ $this->viewer = $viewer;
+ return $this;
+ }
+
+ public function getViewer() {
+ return $this->viewer;
+ }
+
+ public function setAliases(array $aliases) {
+ $this->aliases = $aliases;
+ return $this;
+ }
+
+ public function getAliases() {
+ return $this->aliases;
+ }
+
+ public function setObject($object) {
+ $this->object = $object;
+ return $this;
+ }
+
+ public function getObject() {
+ return $this->object;
+ }
+
+ abstract protected function newControl();
+
+ protected function renderControl() {
+ $control = $this->newControl();
+ if ($control === null) {
+ return null;
+ }
+
+ $control
+ ->setValue($this->getValueForControl())
+ ->setName($this->getKey());
+
+ if (!$control->getLabel()) {
+ $control->setLabel($this->getLabel());
+ }
+
+ return $control;
+ }
+
+ public function appendToForm(AphrontFormView $form) {
+ $control = $this->renderControl();
+ if ($control !== null) {
+ $form->appendControl($control);
+ }
+ return $this;
+ }
+
+ protected function getValueForControl() {
+ return $this->getValue();
+ }
+
+ protected function getValue() {
+ return $this->value;
+ }
+
+ public function setValue($value) {
+ $this->hasValue = true;
+ $this->value = $value;
+ return $this;
+ }
+
+ public function generateTransaction(
+ PhabricatorApplicationTransaction $xaction) {
+
+ $xaction
+ ->setTransactionType($this->getTransactionType())
+ ->setNewValue($this->getValueForTransaction());
+
+ foreach ($this->metadata as $key => $value) {
+ $xaction->setMetadataValue($key, $value);
+ }
+
+ return $xaction;
+ }
+
+ public function setMetadataValue($key, $value) {
+ $this->metadata[$key] = $value;
+ return $this;
+ }
+
+ protected function getValueForTransaction() {
+ return $this->getValue();
+ }
+
+ public function getTransactionType() {
+ if (!$this->transactionType) {
+ throw new PhutilInvalidStateException('setTransactionType');
+ }
+ return $this->transactionType;
+ }
+
+ public function setTransactionType($type) {
+ $this->transactionType = $type;
+ return $this;
+ }
+
+ public function readValueFromRequest(AphrontRequest $request) {
+ $check = array_merge(array($this->getKey()), $this->getAliases());
+ foreach ($check as $key) {
+ if (!$this->getValueExistsInRequest($request, $key)) {
+ continue;
+ }
+
+ $this->value = $this->getValueFromRequest($request, $key);
+ return;
+ }
+
+ $this->readValueFromObject($this->getObject());
+
+ return $this;
+ }
+
+ public function readValueFromObject($object) {
+ $this->value = $this->getValueFromObject($object);
+ return $this;
+ }
+
+ protected function getValueFromObject($object) {
+ if ($this->hasValue) {
+ return $this->value;
+ } else {
+ return $this->getDefaultValue();
+ }
+ }
+
+ protected function getValueExistsInRequest(AphrontRequest $request, $key) {
+ return $this->getValueExistsInSubmit($request, $key);
+ }
+
+ protected function getValueFromRequest(AphrontRequest $request, $key) {
+ return $this->getValueFromSubmit($request, $key);
+ }
+
+ public function readValueFromSubmit(AphrontRequest $request) {
+ $key = $this->getKey();
+ if ($this->getValueExistsInSubmit($request, $key)) {
+ $value = $this->getValueFromSubmit($request, $key);
+ } else {
+ $value = $this->getDefaultValue();
+ }
+ $this->value = $value;
+ return $this;
+ }
+
+ protected function getValueExistsInSubmit(AphrontRequest $request, $key) {
+ return $request->getExists($key);
+ }
+
+ protected function getValueFromSubmit(AphrontRequest $request, $key) {
+ return $request->getStr($key);
+ }
+
+ protected function getDefaultValue() {
+ return null;
+ }
+
+ protected function getListFromRequest(
+ AphrontRequest $request,
+ $key) {
+
+ $list = $request->getArr($key, null);
+ if ($list === null) {
+ $list = $request->getStrList($key);
+ }
+
+ if (!$list) {
+ return array();
+ }
+
+ return $list;
+ }
+
+}
diff --git a/src/applications/transactions/editfield/PhabricatorPolicyEditField.php b/src/applications/transactions/editfield/PhabricatorPolicyEditField.php
new file mode 100644
--- /dev/null
+++ b/src/applications/transactions/editfield/PhabricatorPolicyEditField.php
@@ -0,0 +1,54 @@
+<?php
+
+final class PhabricatorPolicyEditField
+ extends PhabricatorEditField {
+
+ private $policies;
+ private $capability;
+ private $spaceField;
+
+ public function setPolicies(array $policies) {
+ $this->policies = $policies;
+ return $this;
+ }
+
+ public function getPolicies() {
+ if ($this->policies === null) {
+ throw new PhutilInvalidStateException('setPolicies');
+ }
+ return $this->policies;
+ }
+
+ public function setCapability($capability) {
+ $this->capability = $capability;
+ return $this;
+ }
+
+ public function getCapability() {
+ return $this->capability;
+ }
+
+ public function setSpaceField(PhabricatorSpaceEditField $space_field) {
+ $this->spaceField = $space_field;
+ return $this;
+ }
+
+ public function getSpaceField() {
+ return $this->spaceField;
+ }
+
+ protected function newControl() {
+ $control = id(new AphrontFormPolicyControl())
+ ->setCapability($this->getCapability())
+ ->setPolicyObject($this->getObject())
+ ->setPolicies($this->getPolicies());
+
+ $space_field = $this->getSpaceField();
+ if ($space_field) {
+ $control->setSpacePHID($space_field->getValueForControl());
+ }
+
+ return $control;
+ }
+
+}
diff --git a/src/applications/transactions/editfield/PhabricatorSelectEditField.php b/src/applications/transactions/editfield/PhabricatorSelectEditField.php
new file mode 100644
--- /dev/null
+++ b/src/applications/transactions/editfield/PhabricatorSelectEditField.php
@@ -0,0 +1,25 @@
+<?php
+
+final class PhabricatorSelectEditField
+ extends PhabricatorEditField {
+
+ private $options;
+
+ public function setOptions(array $options) {
+ $this->options = $options;
+ return $this;
+ }
+
+ public function getOptions() {
+ if ($this->options === null) {
+ throw new PhutilInvalidStateException('setOptions');
+ }
+ return $this->options;
+ }
+
+ protected function newControl() {
+ return id(new AphrontFormSelectControl())
+ ->setOptions($this->getOptions());
+ }
+
+}
diff --git a/src/applications/transactions/editfield/PhabricatorSpaceEditField.php b/src/applications/transactions/editfield/PhabricatorSpaceEditField.php
new file mode 100644
--- /dev/null
+++ b/src/applications/transactions/editfield/PhabricatorSpaceEditField.php
@@ -0,0 +1,12 @@
+<?php
+
+final class PhabricatorSpaceEditField
+ extends PhabricatorEditField {
+
+ protected function newControl() {
+ // NOTE: This field doesn't do anything on its own, it just serves as a
+ // companion to the associated View Policy field.
+ return null;
+ }
+
+}
diff --git a/src/applications/transactions/editfield/PhabricatorTextAreaEditField.php b/src/applications/transactions/editfield/PhabricatorTextAreaEditField.php
new file mode 100644
--- /dev/null
+++ b/src/applications/transactions/editfield/PhabricatorTextAreaEditField.php
@@ -0,0 +1,42 @@
+<?php
+
+final class PhabricatorTextAreaEditField
+ extends PhabricatorEditField {
+
+ private $monospaced;
+ private $height;
+
+ public function setMonospaced($monospaced) {
+ $this->monospaced = $monospaced;
+ return $this;
+ }
+
+ public function getMonospaced() {
+ return $this->monospaced;
+ }
+
+ public function setHeight($height) {
+ $this->height = $height;
+ return $this;
+ }
+
+ public function getHeight() {
+ return $this->height;
+ }
+
+ protected function newControl() {
+ $control = new AphrontFormTextAreaControl();
+
+ if ($this->getMonospaced()) {
+ $control->setCustomClass('PhabricatorMonospaced');
+ }
+
+ $height = $this->getHeight();
+ if ($height) {
+ $control->setHeight($height);
+ }
+
+ return $control;
+ }
+
+}
diff --git a/src/applications/transactions/editfield/PhabricatorTextEditField.php b/src/applications/transactions/editfield/PhabricatorTextEditField.php
new file mode 100644
--- /dev/null
+++ b/src/applications/transactions/editfield/PhabricatorTextEditField.php
@@ -0,0 +1,10 @@
+<?php
+
+final class PhabricatorTextEditField
+ extends PhabricatorEditField {
+
+ protected function newControl() {
+ return new AphrontFormTextControl();
+ }
+
+}
diff --git a/src/applications/transactions/editfield/PhabricatorTokenizerEditField.php b/src/applications/transactions/editfield/PhabricatorTokenizerEditField.php
new file mode 100644
--- /dev/null
+++ b/src/applications/transactions/editfield/PhabricatorTokenizerEditField.php
@@ -0,0 +1,90 @@
+<?php
+
+abstract class PhabricatorTokenizerEditField
+ extends PhabricatorEditField {
+
+ private $originalValue;
+
+ abstract protected function newDatasource();
+
+ protected function newControl() {
+ $control = id(new AphrontFormTokenizerControl())
+ ->setDatasource($this->newDatasource());
+
+ if ($this->originalValue !== null) {
+ $control->setOriginalValue($this->originalValue);
+ }
+
+ return $control;
+ }
+
+ public function setOriginalValue(array $value) {
+ $this->originalValue = $value;
+ return $this;
+ }
+
+ public function setValue($value) {
+ $this->originalValue = $value;
+ return parent::setValue($value);
+ }
+
+ protected function getValueFromSubmit(AphrontRequest $request, $key) {
+ // TODO: Maybe move this unusual read somewhere else so subclassing this
+ // correctly is easier?
+ $this->originalValue = $request->getArr($key.'.original');
+
+ return $this->getListFromRequest($request, $key);
+ }
+
+ protected function getDefaultValue() {
+ return array();
+ }
+
+ protected function getValueForTransaction() {
+ $new = parent::getValueForTransaction();
+
+ $edge_types = array(
+ PhabricatorTransactions::TYPE_EDGE => true,
+ PhabricatorTransactions::TYPE_SUBSCRIBERS => true,
+ );
+
+ if (isset($edge_types[$this->getTransactionType()])) {
+ if ($this->originalValue !== null) {
+ // If we're building an edge transaction and the request has data
+ // about the original value the user saw when they loaded the form,
+ // interpret the edit as a mixture of "+" and "-" operations instead
+ // of a single "=" operation. This limits our exposure to race
+ // conditions by making most concurrent edits merge correctly.
+
+ $new = parent::getValueForTransaction();
+ $old = $this->originalValue;
+
+ $add = array_diff($new, $old);
+ $rem = array_diff($old, $new);
+
+ $value = array();
+
+ if ($add) {
+ $value['+'] = array_fuse($add);
+ }
+ if ($rem) {
+ $value['-'] = array_fuse($rem);
+ }
+
+ return $value;
+ } else {
+
+ if (!is_array($new)) {
+ throw new Exception(print_r($new, true));
+ }
+
+ return array(
+ '=' => array_fuse($new),
+ );
+ }
+ }
+
+ return $new;
+ }
+
+}
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
@@ -242,6 +242,19 @@
return $this->applicationEmail;
}
+ public function getTransactionTypesForObject($object) {
+ $old = $this->object;
+ try {
+ $this->object = $object;
+ $result = $this->getTransactionTypes();
+ $this->object = $old;
+ } catch (Exception $ex) {
+ $this->object = $old;
+ throw $ex;
+ }
+ return $result;
+ }
+
public function getTransactionTypes() {
$types = array();
@@ -1650,7 +1663,7 @@
throw new Exception(
pht(
"Invalid '%s' value for PHID transaction. Value should contain only ".
- "keys '%s' (add PHIDs), '%' (remove PHIDs) and '%s' (set PHIDS).",
+ "keys '%s' (add PHIDs), '%s' (remove PHIDs) and '%s' (set PHIDS).",
'new',
'+',
'-',
diff --git a/src/view/control/AphrontTokenizerTemplateView.php b/src/view/control/AphrontTokenizerTemplateView.php
--- a/src/view/control/AphrontTokenizerTemplateView.php
+++ b/src/view/control/AphrontTokenizerTemplateView.php
@@ -6,6 +6,7 @@
private $name;
private $id;
private $browseURI;
+ private $originalValue;
public function setBrowseURI($browse_uri) {
$this->browseURI = $browse_uri;
@@ -36,6 +37,15 @@
return $this->name;
}
+ public function setOriginalValue(array $original_value) {
+ $this->originalValue = $original_value;
+ return $this;
+ }
+
+ public function getOriginalValue() {
+ return $this->originalValue;
+ }
+
public function render() {
require_celerity_resource('aphront-tokenizer-control-css');
@@ -85,6 +95,20 @@
$classes[] = 'has-browse';
}
+ $original = array();
+ $original_value = $this->getOriginalValue();
+ if ($original_value) {
+ foreach ($this->getOriginalValue() as $value) {
+ $original[] = phutil_tag(
+ 'input',
+ array(
+ 'type' => 'hidden',
+ 'name' => $name.'.original[]',
+ 'value' => $value,
+ ));
+ }
+ }
+
$frame = javelin_tag(
'div',
array(
@@ -94,6 +118,7 @@
array(
$container,
$browse,
+ $original,
));
return $frame;
diff --git a/src/view/form/control/AphrontFormTokenizerControl.php b/src/view/form/control/AphrontFormTokenizerControl.php
--- a/src/view/form/control/AphrontFormTokenizerControl.php
+++ b/src/view/form/control/AphrontFormTokenizerControl.php
@@ -7,6 +7,7 @@
private $limit;
private $placeholder;
private $handles;
+ private $originalValue;
public function setDatasource(PhabricatorTypeaheadDatasource $datasource) {
$this->datasource = $datasource;
@@ -32,6 +33,15 @@
return $this;
}
+ public function setOriginalValue(array $original_value) {
+ $this->originalValue = $original_value;
+ return $this;
+ }
+
+ public function getOriginalValue() {
+ return $this->originalValue;
+ }
+
public function willRender() {
// Load the handles now so we'll get a bulk load later on when we actually
// render them.
@@ -69,10 +79,15 @@
$token->setInputName($this->getName());
}
- $template = new AphrontTokenizerTemplateView();
- $template->setName($name);
- $template->setID($id);
- $template->setValue($tokens);
+ $template = id(new AphrontTokenizerTemplateView())
+ ->setName($name)
+ ->setID($id)
+ ->setValue($tokens);
+
+ $original_value = $this->getOriginalValue();
+ if ($original_value !== null) {
+ $template->setOriginalValue($original_value);
+ }
$username = null;
if ($this->user) {

File Metadata

Mime Type
text/plain
Expires
Sat, May 18, 5:16 AM (2 w, 1 d ago)
Storage Engine
amazon-s3
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
phabricator/secure/ls/ah/wj2xjwsodnn2iqk3
Default Alt Text
D14390.diff (54 KB)

Event Timeline