mirror of
https://we.phorge.it/source/phorge.git
synced 2024-12-24 06:20:56 +01:00
Phriction - consolidate edit business logic into Editor
Summary: Ref T4029. Some business logic lives outside the editor. This revision moves that logic from the edit controller into the editor proper. This makes re-using that business logic across other endpoints - say like a conduit end point - possible. This is also part of the general modernization quest for phriction I am on. This diff also restores the functionality where you can delete a document by wiping out the content and saving. Test Plan: tried to make a document with no title or content and saw errors. opened a document for edit with user 1, then made edits with user 2, then saw an error when i made the edit with user 1. clicking "overwrite changes" then worked. deleted a document by wiping out the body and clicking save. Reviewers: epriestley Reviewed By: epriestley Subscribers: Korvin, epriestley Maniphest Tasks: T4029 Differential Revision: https://secure.phabricator.com/D10795
This commit is contained in:
parent
9f8dde9cf6
commit
37bc0474fe
2 changed files with 223 additions and 123 deletions
|
@ -93,120 +93,6 @@ final class PhrictionEditController
|
||||||
$draft_key);
|
$draft_key);
|
||||||
}
|
}
|
||||||
|
|
||||||
require_celerity_resource('phriction-document-css');
|
|
||||||
|
|
||||||
$e_title = true;
|
|
||||||
$notes = null;
|
|
||||||
$errors = array();
|
|
||||||
|
|
||||||
if ($request->isFormPost()) {
|
|
||||||
|
|
||||||
$overwrite = $request->getBool('overwrite');
|
|
||||||
if (!$overwrite) {
|
|
||||||
$edit_version = $request->getStr('contentVersion');
|
|
||||||
if ($edit_version != $current_version) {
|
|
||||||
$dialog = $this->newDialog()
|
|
||||||
->setTitle(pht('Edit Conflict!'))
|
|
||||||
->appendParagraph(
|
|
||||||
pht(
|
|
||||||
'Another user made changes to this document after you began '.
|
|
||||||
'editing it. Do you want to overwrite their changes?'))
|
|
||||||
->appendParagraph(
|
|
||||||
pht(
|
|
||||||
'If you choose to overwrite their changes, you should review '.
|
|
||||||
'the document edit history to see what you overwrote, and '.
|
|
||||||
'then make another edit to merge the changes if necessary.'))
|
|
||||||
->addSubmitButton(pht('Overwrite Changes'))
|
|
||||||
->addCancelButton($request->getRequestURI());
|
|
||||||
|
|
||||||
$dialog->addHiddenInput('overwrite', 'true');
|
|
||||||
foreach ($request->getPassthroughRequestData() as $key => $value) {
|
|
||||||
$dialog->addHiddenInput($key, $value);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $dialog;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
$title = $request->getStr('title');
|
|
||||||
$notes = $request->getStr('description');
|
|
||||||
|
|
||||||
if (!strlen($title)) {
|
|
||||||
$e_title = pht('Required');
|
|
||||||
$errors[] = pht('Document title is required.');
|
|
||||||
} else {
|
|
||||||
$e_title = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($document->getID()) {
|
|
||||||
if ($content->getTitle() == $title &&
|
|
||||||
$content->getContent() == $request->getStr('content')) {
|
|
||||||
|
|
||||||
$dialog = new AphrontDialogView();
|
|
||||||
$dialog->setUser($user);
|
|
||||||
$dialog->setTitle(pht('No Edits'));
|
|
||||||
$dialog->appendChild(phutil_tag('p', array(), pht(
|
|
||||||
'You did not make any changes to the document.')));
|
|
||||||
$dialog->addCancelButton($request->getRequestURI());
|
|
||||||
|
|
||||||
return id(new AphrontDialogResponse())->setDialog($dialog);
|
|
||||||
}
|
|
||||||
} else if (!strlen($request->getStr('content'))) {
|
|
||||||
|
|
||||||
// We trigger this only for new pages. For existing pages, deleting
|
|
||||||
// all the content counts as deleting the page.
|
|
||||||
|
|
||||||
$dialog = new AphrontDialogView();
|
|
||||||
$dialog->setUser($user);
|
|
||||||
$dialog->setTitle(pht('Empty Page'));
|
|
||||||
$dialog->appendChild(phutil_tag('p', array(), pht(
|
|
||||||
'You can not create an empty document.')));
|
|
||||||
$dialog->addCancelButton($request->getRequestURI());
|
|
||||||
|
|
||||||
return id(new AphrontDialogResponse())->setDialog($dialog);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!count($errors)) {
|
|
||||||
|
|
||||||
$xactions = array();
|
|
||||||
$xactions[] = id(new PhrictionTransaction())
|
|
||||||
->setTransactionType(PhrictionTransaction::TYPE_TITLE)
|
|
||||||
->setNewValue($title);
|
|
||||||
$xactions[] = id(new PhrictionTransaction())
|
|
||||||
->setTransactionType(PhrictionTransaction::TYPE_CONTENT)
|
|
||||||
->setNewValue($request->getStr('content'));
|
|
||||||
|
|
||||||
$editor = id(new PhrictionTransactionEditor())
|
|
||||||
->setActor($user)
|
|
||||||
->setContentSourceFromRequest($request)
|
|
||||||
->setContinueOnNoEffect(true)
|
|
||||||
->setDescription($notes)
|
|
||||||
->applyTransactions($document, $xactions);
|
|
||||||
|
|
||||||
if ($draft) {
|
|
||||||
$draft->delete();
|
|
||||||
}
|
|
||||||
|
|
||||||
$uri = PhrictionDocument::getSlugURI($document->getSlug());
|
|
||||||
return id(new AphrontRedirectResponse())->setURI($uri);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($document->getID()) {
|
|
||||||
$panel_header = pht('Edit Phriction Document');
|
|
||||||
$submit_button = pht('Save Changes');
|
|
||||||
} else {
|
|
||||||
$panel_header = pht('Create New Phriction Document');
|
|
||||||
$submit_button = pht('Create Document');
|
|
||||||
}
|
|
||||||
|
|
||||||
$uri = $document->getSlug();
|
|
||||||
$uri = PhrictionDocument::getSlugURI($uri);
|
|
||||||
$uri = PhabricatorEnv::getProductionURI($uri);
|
|
||||||
|
|
||||||
$cancel_uri = PhrictionDocument::getSlugURI($document->getSlug());
|
|
||||||
|
|
||||||
if ($draft &&
|
if ($draft &&
|
||||||
strlen($draft->getDraft()) &&
|
strlen($draft->getDraft()) &&
|
||||||
($draft->getDraft() != $content->getContent())) {
|
($draft->getDraft() != $content->getContent())) {
|
||||||
|
@ -230,17 +116,94 @@ final class PhrictionEditController
|
||||||
$draft_note = null;
|
$draft_note = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
require_celerity_resource('phriction-document-css');
|
||||||
|
|
||||||
|
$e_title = true;
|
||||||
|
$e_content = true;
|
||||||
|
$validation_exception = null;
|
||||||
|
$notes = null;
|
||||||
|
$title = $content->getTitle();
|
||||||
|
$overwrite = false;
|
||||||
|
|
||||||
|
if ($request->isFormPost()) {
|
||||||
|
|
||||||
|
$title = $request->getStr('title');
|
||||||
|
$content_text = $request->getStr('content');
|
||||||
|
$notes = $request->getStr('description');
|
||||||
|
$current_version = $request->getInt('contentVersion');
|
||||||
|
|
||||||
|
$xactions = array();
|
||||||
|
$xactions[] = id(new PhrictionTransaction())
|
||||||
|
->setTransactionType(PhrictionTransaction::TYPE_TITLE)
|
||||||
|
->setNewValue($title);
|
||||||
|
$xactions[] = id(new PhrictionTransaction())
|
||||||
|
->setTransactionType(PhrictionTransaction::TYPE_CONTENT)
|
||||||
|
->setNewValue($content_text);
|
||||||
|
|
||||||
|
$editor = id(new PhrictionTransactionEditor())
|
||||||
|
->setActor($user)
|
||||||
|
->setContentSourceFromRequest($request)
|
||||||
|
->setContinueOnNoEffect(true)
|
||||||
|
->setDescription($notes)
|
||||||
|
->setProcessContentVersionError(!$request->getBool('overwrite'))
|
||||||
|
->setContentVersion($current_version);
|
||||||
|
|
||||||
|
try {
|
||||||
|
$editor->applyTransactions($document, $xactions);
|
||||||
|
|
||||||
|
if ($draft) {
|
||||||
|
$draft->delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
$uri = PhrictionDocument::getSlugURI($document->getSlug());
|
||||||
|
return id(new AphrontRedirectResponse())->setURI($uri);
|
||||||
|
} catch (PhabricatorApplicationTransactionValidationException $ex) {
|
||||||
|
$validation_exception = $ex;
|
||||||
|
$e_title = $ex->getShortMessage(
|
||||||
|
PhrictionTransaction::TYPE_TITLE);
|
||||||
|
$e_content = $ex->getShortMessage(
|
||||||
|
PhrictionTransaction::TYPE_CONTENT);
|
||||||
|
|
||||||
|
// if we're not supposed to process the content version error, then
|
||||||
|
// overwrite that content...!
|
||||||
|
if (!$editor->getProcessContentVersionError()) {
|
||||||
|
$overwrite = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO - remember to set policy to what the user tried to set it to
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($document->getID()) {
|
||||||
|
$panel_header = pht('Edit Phriction Document');
|
||||||
|
$page_title = pht('Edit Document');
|
||||||
|
if ($overwrite) {
|
||||||
|
$submit_button = pht('Overwrite Changes');
|
||||||
|
} else {
|
||||||
|
$submit_button = pht('Save Changes');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$panel_header = pht('Create New Phriction Document');
|
||||||
|
$submit_button = pht('Create Document');
|
||||||
|
$page_title = pht('Create Document');
|
||||||
|
}
|
||||||
|
|
||||||
|
$uri = $document->getSlug();
|
||||||
|
$uri = PhrictionDocument::getSlugURI($uri);
|
||||||
|
$uri = PhabricatorEnv::getProductionURI($uri);
|
||||||
|
|
||||||
|
$cancel_uri = PhrictionDocument::getSlugURI($document->getSlug());
|
||||||
|
|
||||||
$form = id(new AphrontFormView())
|
$form = id(new AphrontFormView())
|
||||||
->setUser($user)
|
->setUser($user)
|
||||||
->setWorkflow(true)
|
|
||||||
->setAction($request->getRequestURI()->getPath())
|
|
||||||
->addHiddenInput('slug', $document->getSlug())
|
->addHiddenInput('slug', $document->getSlug())
|
||||||
->addHiddenInput('nodraft', $request->getBool('nodraft'))
|
->addHiddenInput('nodraft', $request->getBool('nodraft'))
|
||||||
->addHiddenInput('contentVersion', $current_version)
|
->addHiddenInput('contentVersion', $current_version)
|
||||||
|
->addHiddenInput('overwrite', $overwrite)
|
||||||
->appendChild(
|
->appendChild(
|
||||||
id(new AphrontFormTextControl())
|
id(new AphrontFormTextControl())
|
||||||
->setLabel(pht('Title'))
|
->setLabel(pht('Title'))
|
||||||
->setValue($content->getTitle())
|
->setValue($title)
|
||||||
->setError($e_title)
|
->setError($e_title)
|
||||||
->setName('title'))
|
->setName('title'))
|
||||||
->appendChild(
|
->appendChild(
|
||||||
|
@ -251,6 +214,7 @@ final class PhrictionEditController
|
||||||
id(new PhabricatorRemarkupControl())
|
id(new PhabricatorRemarkupControl())
|
||||||
->setLabel(pht('Content'))
|
->setLabel(pht('Content'))
|
||||||
->setValue($content_text)
|
->setValue($content_text)
|
||||||
|
->setError($e_content)
|
||||||
->setHeight(AphrontFormTextAreaControl::HEIGHT_VERY_TALL)
|
->setHeight(AphrontFormTextAreaControl::HEIGHT_VERY_TALL)
|
||||||
->setName('content')
|
->setName('content')
|
||||||
->setID('document-textarea')
|
->setID('document-textarea')
|
||||||
|
@ -267,8 +231,8 @@ final class PhrictionEditController
|
||||||
->setValue($submit_button));
|
->setValue($submit_button));
|
||||||
|
|
||||||
$form_box = id(new PHUIObjectBoxView())
|
$form_box = id(new PHUIObjectBoxView())
|
||||||
->setHeaderText(pht('Edit Document'))
|
->setHeaderText($panel_header)
|
||||||
->setFormErrors($errors)
|
->setValidationException($validation_exception)
|
||||||
->setForm($form);
|
->setForm($form);
|
||||||
|
|
||||||
$preview = id(new PHUIRemarkupPreviewPanel())
|
$preview = id(new PHUIRemarkupPreviewPanel())
|
||||||
|
@ -295,7 +259,7 @@ final class PhrictionEditController
|
||||||
$preview,
|
$preview,
|
||||||
),
|
),
|
||||||
array(
|
array(
|
||||||
'title' => pht('Edit Document'),
|
'title' => $page_title,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,8 @@ final class PhrictionTransactionEditor
|
||||||
private $newContent;
|
private $newContent;
|
||||||
private $moveAwayDocument;
|
private $moveAwayDocument;
|
||||||
private $skipAncestorCheck;
|
private $skipAncestorCheck;
|
||||||
|
private $contentVersion;
|
||||||
|
private $processContentVersionError = true;
|
||||||
|
|
||||||
public function setDescription($description) {
|
public function setDescription($description) {
|
||||||
$this->description = $description;
|
$this->description = $description;
|
||||||
|
@ -45,6 +47,24 @@ final class PhrictionTransactionEditor
|
||||||
return $this->skipAncestorCheck;
|
return $this->skipAncestorCheck;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function setContentVersion($version) {
|
||||||
|
$this->contentVersion = $version;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getContentVersion() {
|
||||||
|
return $this->contentVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setProcessContentVersionError($process) {
|
||||||
|
$this->processContentVersionError = $process;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getProcessContentVersionError() {
|
||||||
|
return $this->processContentVersionError;
|
||||||
|
}
|
||||||
|
|
||||||
public function getEditorApplicationClass() {
|
public function getEditorApplicationClass() {
|
||||||
return 'PhabricatorPhrictionApplication';
|
return 'PhabricatorPhrictionApplication';
|
||||||
}
|
}
|
||||||
|
@ -162,6 +182,30 @@ final class PhrictionTransactionEditor
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function expandTransaction(
|
||||||
|
PhabricatorLiskDAO $object,
|
||||||
|
PhabricatorApplicationTransaction $xaction) {
|
||||||
|
|
||||||
|
$xactions = parent::expandTransaction($object, $xaction);
|
||||||
|
switch ($xaction->getTransactionType()) {
|
||||||
|
case PhrictionTransaction::TYPE_CONTENT:
|
||||||
|
if ($this->getIsNewObject()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
$content = $xaction->getNewValue();
|
||||||
|
if ($content === '') {
|
||||||
|
$xactions[] = id(new PhrictionTransaction())
|
||||||
|
->setTransactionType(PhrictionTransaction::TYPE_DELETE)
|
||||||
|
->setNewValue(true);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $xactions;
|
||||||
|
}
|
||||||
|
|
||||||
protected function applyCustomExternalTransaction(
|
protected function applyCustomExternalTransaction(
|
||||||
PhabricatorLiskDAO $object,
|
PhabricatorLiskDAO $object,
|
||||||
PhabricatorApplicationTransaction $xaction) {
|
PhabricatorApplicationTransaction $xaction) {
|
||||||
|
@ -251,7 +295,8 @@ final class PhrictionTransactionEditor
|
||||||
->setMetadataValue('stub:create:phid', $object->getPHID());
|
->setMetadataValue('stub:create:phid', $object->getPHID());
|
||||||
$stub_xactions[] = id(new PhrictionTransaction())
|
$stub_xactions[] = id(new PhrictionTransaction())
|
||||||
->setTransactionType(PhrictionTransaction::TYPE_CONTENT)
|
->setTransactionType(PhrictionTransaction::TYPE_CONTENT)
|
||||||
->setNewValue('');
|
->setNewValue('')
|
||||||
|
->setMetadataValue('stub:create:phid', $object->getPHID());
|
||||||
$sub_editor = id(new PhrictionTransactionEditor())
|
$sub_editor = id(new PhrictionTransactionEditor())
|
||||||
->setActor($this->getActor())
|
->setActor($this->getActor())
|
||||||
->setContentSource($this->getContentSource())
|
->setContentSource($this->getContentSource())
|
||||||
|
@ -366,6 +411,97 @@ final class PhrictionTransactionEditor
|
||||||
return $phids;
|
return $phids;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function validateTransaction(
|
||||||
|
PhabricatorLiskDAO $object,
|
||||||
|
$type,
|
||||||
|
array $xactions) {
|
||||||
|
|
||||||
|
$errors = parent::validateTransaction($object, $type, $xactions);
|
||||||
|
|
||||||
|
foreach ($xactions as $xaction) {
|
||||||
|
switch ($type) {
|
||||||
|
case PhrictionTransaction::TYPE_TITLE:
|
||||||
|
$title = $object->getContent()->getTitle();
|
||||||
|
$missing = $this->validateIsEmptyTextField(
|
||||||
|
$title,
|
||||||
|
$xactions);
|
||||||
|
|
||||||
|
if ($missing) {
|
||||||
|
$error = new PhabricatorApplicationTransactionValidationError(
|
||||||
|
$type,
|
||||||
|
pht('Required'),
|
||||||
|
pht('Document title is required.'),
|
||||||
|
nonempty(last($xactions), null));
|
||||||
|
|
||||||
|
$error->setIsMissingFieldError(true);
|
||||||
|
$errors[] = $error;
|
||||||
|
} else if ($this->getProcessContentVersionError()) {
|
||||||
|
$error = $this->validateContentVersion($object, $type, $xaction);
|
||||||
|
if ($error) {
|
||||||
|
$this->setProcessContentVersionError(false);
|
||||||
|
$errors[] = $error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PhrictionTransaction::TYPE_CONTENT:
|
||||||
|
if ($xaction->getMetadataValue('stub:create:phid')) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$missing = false;
|
||||||
|
if ($this->getIsNewObject()) {
|
||||||
|
$content = $object->getContent()->getContent();
|
||||||
|
$missing = $this->validateIsEmptyTextField(
|
||||||
|
$content,
|
||||||
|
$xactions);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($missing) {
|
||||||
|
$error = new PhabricatorApplicationTransactionValidationError(
|
||||||
|
$type,
|
||||||
|
pht('Required'),
|
||||||
|
pht('Document content is required.'),
|
||||||
|
nonempty(last($xactions), null));
|
||||||
|
|
||||||
|
$error->setIsMissingFieldError(true);
|
||||||
|
$errors[] = $error;
|
||||||
|
} else if ($this->getProcessContentVersionError()) {
|
||||||
|
$error = $this->validateContentVersion($object, $type, $xaction);
|
||||||
|
if ($error) {
|
||||||
|
$this->setProcessContentVersionError(false);
|
||||||
|
$errors[] = $error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $errors;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function validateContentVersion(
|
||||||
|
PhabricatorLiskDAO $object,
|
||||||
|
$type,
|
||||||
|
PhabricatorApplicationTransaction $xaction) {
|
||||||
|
|
||||||
|
$error = null;
|
||||||
|
if ($this->getContentVersion() &&
|
||||||
|
($object->getContent()->getVersion() != $this->getContentVersion())) {
|
||||||
|
$error = new PhabricatorApplicationTransactionValidationError(
|
||||||
|
$type,
|
||||||
|
pht('Edit Conflict'),
|
||||||
|
pht(
|
||||||
|
'Another user made changes to this document after you began '.
|
||||||
|
'editing it. Do you want to overwrite their changes? '.
|
||||||
|
'(If you choose to overwrite their changes, you should review '.
|
||||||
|
'the document edit history to see what you overwrote, and '.
|
||||||
|
'then make another edit to merge the changes if necessary.)'),
|
||||||
|
$xaction);
|
||||||
|
}
|
||||||
|
return $error;
|
||||||
|
}
|
||||||
|
|
||||||
protected function supportsSearch() {
|
protected function supportsSearch() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue