mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-26 16:52:41 +01:00
Allow the published version of a Phriction document to differ from the most recent version
Summary: Depends on D19620. Ref T13077. This adds a "Publish" operation which points the current version at some historical version of the document -- not necessarily the most recent version. Newer versions become "drafts". This is still quite rough and missing a lot of hinting in the UI, I'm just making it work so I can start making the UI understand it. Test Plan: Used the "Publish" action to publish older versions of a document, saw the document revert. Many UI hints are missing and this operation is puzzling and not yet usable for normal users. Reviewers: amckinley Maniphest Tasks: T13077 Differential Revision: https://secure.phabricator.com/D19621
This commit is contained in:
parent
50f4adef64
commit
349686319e
6 changed files with 200 additions and 3 deletions
|
@ -5029,6 +5029,7 @@ phutil_register_library_map(array(
|
||||||
'PhrictionDocumentPHIDType' => 'applications/phriction/phid/PhrictionDocumentPHIDType.php',
|
'PhrictionDocumentPHIDType' => 'applications/phriction/phid/PhrictionDocumentPHIDType.php',
|
||||||
'PhrictionDocumentPathHeraldField' => 'applications/phriction/herald/PhrictionDocumentPathHeraldField.php',
|
'PhrictionDocumentPathHeraldField' => 'applications/phriction/herald/PhrictionDocumentPathHeraldField.php',
|
||||||
'PhrictionDocumentPolicyCodex' => 'applications/phriction/codex/PhrictionDocumentPolicyCodex.php',
|
'PhrictionDocumentPolicyCodex' => 'applications/phriction/codex/PhrictionDocumentPolicyCodex.php',
|
||||||
|
'PhrictionDocumentPublishTransaction' => 'applications/phriction/xaction/PhrictionDocumentPublishTransaction.php',
|
||||||
'PhrictionDocumentQuery' => 'applications/phriction/query/PhrictionDocumentQuery.php',
|
'PhrictionDocumentQuery' => 'applications/phriction/query/PhrictionDocumentQuery.php',
|
||||||
'PhrictionDocumentSearchConduitAPIMethod' => 'applications/phriction/conduit/PhrictionDocumentSearchConduitAPIMethod.php',
|
'PhrictionDocumentSearchConduitAPIMethod' => 'applications/phriction/conduit/PhrictionDocumentSearchConduitAPIMethod.php',
|
||||||
'PhrictionDocumentSearchEngine' => 'applications/phriction/query/PhrictionDocumentSearchEngine.php',
|
'PhrictionDocumentSearchEngine' => 'applications/phriction/query/PhrictionDocumentSearchEngine.php',
|
||||||
|
@ -5046,6 +5047,7 @@ phutil_register_library_map(array(
|
||||||
'PhrictionMarkupPreviewController' => 'applications/phriction/controller/PhrictionMarkupPreviewController.php',
|
'PhrictionMarkupPreviewController' => 'applications/phriction/controller/PhrictionMarkupPreviewController.php',
|
||||||
'PhrictionMoveController' => 'applications/phriction/controller/PhrictionMoveController.php',
|
'PhrictionMoveController' => 'applications/phriction/controller/PhrictionMoveController.php',
|
||||||
'PhrictionNewController' => 'applications/phriction/controller/PhrictionNewController.php',
|
'PhrictionNewController' => 'applications/phriction/controller/PhrictionNewController.php',
|
||||||
|
'PhrictionPublishController' => 'applications/phriction/controller/PhrictionPublishController.php',
|
||||||
'PhrictionRemarkupRule' => 'applications/phriction/markup/PhrictionRemarkupRule.php',
|
'PhrictionRemarkupRule' => 'applications/phriction/markup/PhrictionRemarkupRule.php',
|
||||||
'PhrictionReplyHandler' => 'applications/phriction/mail/PhrictionReplyHandler.php',
|
'PhrictionReplyHandler' => 'applications/phriction/mail/PhrictionReplyHandler.php',
|
||||||
'PhrictionSchemaSpec' => 'applications/phriction/storage/PhrictionSchemaSpec.php',
|
'PhrictionSchemaSpec' => 'applications/phriction/storage/PhrictionSchemaSpec.php',
|
||||||
|
@ -11144,6 +11146,7 @@ phutil_register_library_map(array(
|
||||||
'PhrictionDocumentPHIDType' => 'PhabricatorPHIDType',
|
'PhrictionDocumentPHIDType' => 'PhabricatorPHIDType',
|
||||||
'PhrictionDocumentPathHeraldField' => 'PhrictionDocumentHeraldField',
|
'PhrictionDocumentPathHeraldField' => 'PhrictionDocumentHeraldField',
|
||||||
'PhrictionDocumentPolicyCodex' => 'PhabricatorPolicyCodex',
|
'PhrictionDocumentPolicyCodex' => 'PhabricatorPolicyCodex',
|
||||||
|
'PhrictionDocumentPublishTransaction' => 'PhrictionDocumentTransactionType',
|
||||||
'PhrictionDocumentQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
|
'PhrictionDocumentQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
|
||||||
'PhrictionDocumentSearchConduitAPIMethod' => 'PhabricatorSearchEngineAPIMethod',
|
'PhrictionDocumentSearchConduitAPIMethod' => 'PhabricatorSearchEngineAPIMethod',
|
||||||
'PhrictionDocumentSearchEngine' => 'PhabricatorApplicationSearchEngine',
|
'PhrictionDocumentSearchEngine' => 'PhabricatorApplicationSearchEngine',
|
||||||
|
@ -11161,6 +11164,7 @@ phutil_register_library_map(array(
|
||||||
'PhrictionMarkupPreviewController' => 'PhabricatorController',
|
'PhrictionMarkupPreviewController' => 'PhabricatorController',
|
||||||
'PhrictionMoveController' => 'PhrictionController',
|
'PhrictionMoveController' => 'PhrictionController',
|
||||||
'PhrictionNewController' => 'PhrictionController',
|
'PhrictionNewController' => 'PhrictionController',
|
||||||
|
'PhrictionPublishController' => 'PhrictionController',
|
||||||
'PhrictionRemarkupRule' => 'PhutilRemarkupRule',
|
'PhrictionRemarkupRule' => 'PhutilRemarkupRule',
|
||||||
'PhrictionReplyHandler' => 'PhabricatorApplicationTransactionReplyHandler',
|
'PhrictionReplyHandler' => 'PhabricatorApplicationTransactionReplyHandler',
|
||||||
'PhrictionSchemaSpec' => 'PhabricatorConfigSchemaSpec',
|
'PhrictionSchemaSpec' => 'PhabricatorConfigSchemaSpec',
|
||||||
|
|
|
@ -56,6 +56,8 @@ final class PhabricatorPhrictionApplication extends PhabricatorApplication {
|
||||||
|
|
||||||
'edit/(?:(?P<id>[1-9]\d*)/)?' => 'PhrictionEditController',
|
'edit/(?:(?P<id>[1-9]\d*)/)?' => 'PhrictionEditController',
|
||||||
'delete/(?P<id>[1-9]\d*)/' => 'PhrictionDeleteController',
|
'delete/(?P<id>[1-9]\d*)/' => 'PhrictionDeleteController',
|
||||||
|
'publish/(?P<documentID>[1-9]\d*)/(?P<contentID>[1-9]\d*)/'
|
||||||
|
=> 'PhrictionPublishController',
|
||||||
'new/' => 'PhrictionNewController',
|
'new/' => 'PhrictionNewController',
|
||||||
'move/(?P<id>[1-9]\d*)/' => 'PhrictionMoveController',
|
'move/(?P<id>[1-9]\d*)/' => 'PhrictionMoveController',
|
||||||
|
|
||||||
|
|
|
@ -203,7 +203,7 @@ final class PhrictionDocumentController
|
||||||
|
|
||||||
$curtain = null;
|
$curtain = null;
|
||||||
if ($document->getID()) {
|
if ($document->getID()) {
|
||||||
$curtain = $this->buildCurtain($document);
|
$curtain = $this->buildCurtain($document, $content);
|
||||||
}
|
}
|
||||||
|
|
||||||
$crumbs = $this->buildApplicationCrumbs();
|
$crumbs = $this->buildApplicationCrumbs();
|
||||||
|
@ -230,11 +230,11 @@ final class PhrictionDocumentController
|
||||||
$prop_list = phutil_tag_div('phui-document-view-pro-box', $prop_list);
|
$prop_list = phutil_tag_div('phui-document-view-pro-box', $prop_list);
|
||||||
|
|
||||||
$page_content = id(new PHUIDocumentView())
|
$page_content = id(new PHUIDocumentView())
|
||||||
|
->setBanner($version_note)
|
||||||
->setHeader($header)
|
->setHeader($header)
|
||||||
->setToc($toc)
|
->setToc($toc)
|
||||||
->appendChild(
|
->appendChild(
|
||||||
array(
|
array(
|
||||||
$version_note,
|
|
||||||
$move_notice,
|
$move_notice,
|
||||||
$core_content,
|
$core_content,
|
||||||
));
|
));
|
||||||
|
@ -277,7 +277,9 @@ final class PhrictionDocumentController
|
||||||
return $view;
|
return $view;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function buildCurtain(PhrictionDocument $document) {
|
private function buildCurtain(
|
||||||
|
PhrictionDocument $document,
|
||||||
|
PhrictionContent $content) {
|
||||||
$viewer = $this->getViewer();
|
$viewer = $this->getViewer();
|
||||||
|
|
||||||
$can_edit = PhabricatorPolicyFilter::hasCapability(
|
$can_edit = PhabricatorPolicyFilter::hasCapability(
|
||||||
|
@ -286,6 +288,7 @@ final class PhrictionDocumentController
|
||||||
PhabricatorPolicyCapability::CAN_EDIT);
|
PhabricatorPolicyCapability::CAN_EDIT);
|
||||||
|
|
||||||
$slug = PhabricatorSlug::normalize($this->slug);
|
$slug = PhabricatorSlug::normalize($this->slug);
|
||||||
|
$id = $document->getID();
|
||||||
|
|
||||||
$curtain = $this->newCurtainView($document);
|
$curtain = $this->newCurtainView($document);
|
||||||
|
|
||||||
|
@ -296,6 +299,26 @@ final class PhrictionDocumentController
|
||||||
->setIcon('fa-pencil')
|
->setIcon('fa-pencil')
|
||||||
->setHref('/phriction/edit/'.$document->getID().'/'));
|
->setHref('/phriction/edit/'.$document->getID().'/'));
|
||||||
|
|
||||||
|
$is_current = false;
|
||||||
|
$content_id = null;
|
||||||
|
if ($content) {
|
||||||
|
if ($content->getPHID() == $document->getContentPHID()) {
|
||||||
|
$is_current = true;
|
||||||
|
}
|
||||||
|
$content_id = $content->getID();
|
||||||
|
}
|
||||||
|
$can_publish = ($can_edit && $content && !$is_current);
|
||||||
|
|
||||||
|
$publish_uri = "/phriction/publish/{$id}/{$content_id}/";
|
||||||
|
|
||||||
|
$curtain->addAction(
|
||||||
|
id(new PhabricatorActionView())
|
||||||
|
->setName(pht('Publish'))
|
||||||
|
->setIcon('fa-upload')
|
||||||
|
->setDisabled(!$can_publish)
|
||||||
|
->setWorkflow(true)
|
||||||
|
->setHref($publish_uri));
|
||||||
|
|
||||||
if ($document->getStatus() == PhrictionDocumentStatus::STATUS_EXISTS) {
|
if ($document->getStatus() == PhrictionDocumentStatus::STATUS_EXISTS) {
|
||||||
$curtain->addAction(
|
$curtain->addAction(
|
||||||
id(new PhabricatorActionView())
|
id(new PhabricatorActionView())
|
||||||
|
|
|
@ -0,0 +1,86 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhrictionPublishController
|
||||||
|
extends PhrictionController {
|
||||||
|
|
||||||
|
public function handleRequest(AphrontRequest $request) {
|
||||||
|
$viewer = $request->getViewer();
|
||||||
|
$id = $request->getURIData('documentID');
|
||||||
|
$content_id = $request->getURIData('contentID');
|
||||||
|
|
||||||
|
$document = id(new PhrictionDocumentQuery())
|
||||||
|
->setViewer($viewer)
|
||||||
|
->withIDs(array($id))
|
||||||
|
->needContent(true)
|
||||||
|
->requireCapabilities(
|
||||||
|
array(
|
||||||
|
PhabricatorPolicyCapability::CAN_EDIT,
|
||||||
|
PhabricatorPolicyCapability::CAN_VIEW,
|
||||||
|
))
|
||||||
|
->executeOne();
|
||||||
|
if (!$document) {
|
||||||
|
return new Aphront404Response();
|
||||||
|
}
|
||||||
|
|
||||||
|
$document_uri = $document->getURI();
|
||||||
|
|
||||||
|
$content = id(new PhrictionContentQuery())
|
||||||
|
->setViewer($viewer)
|
||||||
|
->withIDs(array($content_id))
|
||||||
|
->executeOne();
|
||||||
|
if (!$content) {
|
||||||
|
return new Aphront404Response();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($content->getPHID() == $document->getContentPHID()) {
|
||||||
|
return $this->newDialog()
|
||||||
|
->setTitle(pht('Already Published'))
|
||||||
|
->appendChild(
|
||||||
|
pht(
|
||||||
|
'This version of the document is already the published '.
|
||||||
|
'version.'))
|
||||||
|
->addCancelButton($document_uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
$content_uri = $document_uri.'?v='.$content->getVersion();
|
||||||
|
|
||||||
|
if ($request->isFormPost()) {
|
||||||
|
$xactions = array();
|
||||||
|
|
||||||
|
$xactions[] = id(new PhrictionTransaction())
|
||||||
|
->setTransactionType(
|
||||||
|
PhrictionDocumentPublishTransaction::TRANSACTIONTYPE)
|
||||||
|
->setNewValue($content->getPHID());
|
||||||
|
|
||||||
|
id(new PhrictionTransactionEditor())
|
||||||
|
->setActor($viewer)
|
||||||
|
->setContentSourceFromRequest($request)
|
||||||
|
->setContinueOnNoEffect(true)
|
||||||
|
->setContinueOnMissingFields(true)
|
||||||
|
->applyTransactions($document, $xactions);
|
||||||
|
|
||||||
|
return id(new AphrontRedirectResponse())->setURI($document_uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($content->getVersion() < $document->getContent()->getVersion()) {
|
||||||
|
$title = pht('Revert Document?');
|
||||||
|
$body = pht(
|
||||||
|
'Revert the published version of this document to an older '.
|
||||||
|
'version?');
|
||||||
|
$button = pht('Revert');
|
||||||
|
} else {
|
||||||
|
$title = pht('Publish Draft?');
|
||||||
|
$body = pht(
|
||||||
|
'Update the published version of this document to this newer '.
|
||||||
|
'version?');
|
||||||
|
$button = pht('Publish');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->newDialog()
|
||||||
|
->setTitle($title)
|
||||||
|
->appendChild($body)
|
||||||
|
->addSubmitButton($button)
|
||||||
|
->addCancelButton($content_uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,71 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhrictionDocumentPublishTransaction
|
||||||
|
extends PhrictionDocumentTransactionType {
|
||||||
|
|
||||||
|
const TRANSACTIONTYPE = 'publish';
|
||||||
|
|
||||||
|
public function generateOldValue($object) {
|
||||||
|
return $object->getContentPHID();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function applyInternalEffects($object, $value) {
|
||||||
|
$object->setContentPHID($value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getActionName() {
|
||||||
|
return pht('Published');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTitle() {
|
||||||
|
return pht(
|
||||||
|
'%s published a new version of this document.',
|
||||||
|
$this->renderAuthor());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTitleForFeed() {
|
||||||
|
return pht(
|
||||||
|
'%s published a new version of %s.',
|
||||||
|
$this->renderAuthor(),
|
||||||
|
$this->renderObject());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function validateTransactions($object, array $xactions) {
|
||||||
|
$actor = $this->getActor();
|
||||||
|
$errors = array();
|
||||||
|
|
||||||
|
foreach ($xactions as $xaction) {
|
||||||
|
$content_phid = $xaction->getNewValue();
|
||||||
|
|
||||||
|
// If this isn't changing anything, skip it.
|
||||||
|
if ($content_phid === $object->getContentPHID()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$content = id(new PhrictionContentQuery())
|
||||||
|
->setViewer($actor)
|
||||||
|
->withPHIDs(array($content_phid))
|
||||||
|
->executeOne();
|
||||||
|
if (!$content) {
|
||||||
|
$errors[] = $this->newInvalidError(
|
||||||
|
pht(
|
||||||
|
'Unable to load Content object with PHID "%s".',
|
||||||
|
$content_phid),
|
||||||
|
$xaction);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($content->getDocumentPHID() !== $object->getPHID()) {
|
||||||
|
$errors[] = $this->newInvalidError(
|
||||||
|
pht(
|
||||||
|
'Content object "%s" can not be published because it belongs '.
|
||||||
|
'to a different document.',
|
||||||
|
$content_phid));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $errors;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -9,6 +9,7 @@ final class PHUIDocumentView extends AphrontTagView {
|
||||||
private $toc;
|
private $toc;
|
||||||
private $foot;
|
private $foot;
|
||||||
private $curtain;
|
private $curtain;
|
||||||
|
private $banner;
|
||||||
|
|
||||||
public function setHeader(PHUIHeaderView $header) {
|
public function setHeader(PHUIHeaderView $header) {
|
||||||
$header->setTall(true);
|
$header->setTall(true);
|
||||||
|
@ -46,6 +47,15 @@ final class PHUIDocumentView extends AphrontTagView {
|
||||||
return $this->curtain;
|
return $this->curtain;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function setBanner($banner) {
|
||||||
|
$this->banner = $banner;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getBanner() {
|
||||||
|
return $this->banner;
|
||||||
|
}
|
||||||
|
|
||||||
protected function getTagAttributes() {
|
protected function getTagAttributes() {
|
||||||
$classes = array();
|
$classes = array();
|
||||||
|
|
||||||
|
@ -160,6 +170,7 @@ final class PHUIDocumentView extends AphrontTagView {
|
||||||
array(
|
array(
|
||||||
$table_of_contents,
|
$table_of_contents,
|
||||||
$this->header,
|
$this->header,
|
||||||
|
$this->banner,
|
||||||
array(
|
array(
|
||||||
$curtain,
|
$curtain,
|
||||||
$main_content,
|
$main_content,
|
||||||
|
|
Loading…
Reference in a new issue