@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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

+200 -3
+4
src/__phutil_library_map__.php
··· 5029 5029 'PhrictionDocumentPHIDType' => 'applications/phriction/phid/PhrictionDocumentPHIDType.php', 5030 5030 'PhrictionDocumentPathHeraldField' => 'applications/phriction/herald/PhrictionDocumentPathHeraldField.php', 5031 5031 'PhrictionDocumentPolicyCodex' => 'applications/phriction/codex/PhrictionDocumentPolicyCodex.php', 5032 + 'PhrictionDocumentPublishTransaction' => 'applications/phriction/xaction/PhrictionDocumentPublishTransaction.php', 5032 5033 'PhrictionDocumentQuery' => 'applications/phriction/query/PhrictionDocumentQuery.php', 5033 5034 'PhrictionDocumentSearchConduitAPIMethod' => 'applications/phriction/conduit/PhrictionDocumentSearchConduitAPIMethod.php', 5034 5035 'PhrictionDocumentSearchEngine' => 'applications/phriction/query/PhrictionDocumentSearchEngine.php', ··· 5046 5047 'PhrictionMarkupPreviewController' => 'applications/phriction/controller/PhrictionMarkupPreviewController.php', 5047 5048 'PhrictionMoveController' => 'applications/phriction/controller/PhrictionMoveController.php', 5048 5049 'PhrictionNewController' => 'applications/phriction/controller/PhrictionNewController.php', 5050 + 'PhrictionPublishController' => 'applications/phriction/controller/PhrictionPublishController.php', 5049 5051 'PhrictionRemarkupRule' => 'applications/phriction/markup/PhrictionRemarkupRule.php', 5050 5052 'PhrictionReplyHandler' => 'applications/phriction/mail/PhrictionReplyHandler.php', 5051 5053 'PhrictionSchemaSpec' => 'applications/phriction/storage/PhrictionSchemaSpec.php', ··· 11144 11146 'PhrictionDocumentPHIDType' => 'PhabricatorPHIDType', 11145 11147 'PhrictionDocumentPathHeraldField' => 'PhrictionDocumentHeraldField', 11146 11148 'PhrictionDocumentPolicyCodex' => 'PhabricatorPolicyCodex', 11149 + 'PhrictionDocumentPublishTransaction' => 'PhrictionDocumentTransactionType', 11147 11150 'PhrictionDocumentQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 11148 11151 'PhrictionDocumentSearchConduitAPIMethod' => 'PhabricatorSearchEngineAPIMethod', 11149 11152 'PhrictionDocumentSearchEngine' => 'PhabricatorApplicationSearchEngine', ··· 11161 11164 'PhrictionMarkupPreviewController' => 'PhabricatorController', 11162 11165 'PhrictionMoveController' => 'PhrictionController', 11163 11166 'PhrictionNewController' => 'PhrictionController', 11167 + 'PhrictionPublishController' => 'PhrictionController', 11164 11168 'PhrictionRemarkupRule' => 'PhutilRemarkupRule', 11165 11169 'PhrictionReplyHandler' => 'PhabricatorApplicationTransactionReplyHandler', 11166 11170 'PhrictionSchemaSpec' => 'PhabricatorConfigSchemaSpec',
+2
src/applications/phriction/application/PhabricatorPhrictionApplication.php
··· 56 56 57 57 'edit/(?:(?P<id>[1-9]\d*)/)?' => 'PhrictionEditController', 58 58 'delete/(?P<id>[1-9]\d*)/' => 'PhrictionDeleteController', 59 + 'publish/(?P<documentID>[1-9]\d*)/(?P<contentID>[1-9]\d*)/' 60 + => 'PhrictionPublishController', 59 61 'new/' => 'PhrictionNewController', 60 62 'move/(?P<id>[1-9]\d*)/' => 'PhrictionMoveController', 61 63
+26 -3
src/applications/phriction/controller/PhrictionDocumentController.php
··· 203 203 204 204 $curtain = null; 205 205 if ($document->getID()) { 206 - $curtain = $this->buildCurtain($document); 206 + $curtain = $this->buildCurtain($document, $content); 207 207 } 208 208 209 209 $crumbs = $this->buildApplicationCrumbs(); ··· 230 230 $prop_list = phutil_tag_div('phui-document-view-pro-box', $prop_list); 231 231 232 232 $page_content = id(new PHUIDocumentView()) 233 + ->setBanner($version_note) 233 234 ->setHeader($header) 234 235 ->setToc($toc) 235 236 ->appendChild( 236 237 array( 237 - $version_note, 238 238 $move_notice, 239 239 $core_content, 240 240 )); ··· 277 277 return $view; 278 278 } 279 279 280 - private function buildCurtain(PhrictionDocument $document) { 280 + private function buildCurtain( 281 + PhrictionDocument $document, 282 + PhrictionContent $content) { 281 283 $viewer = $this->getViewer(); 282 284 283 285 $can_edit = PhabricatorPolicyFilter::hasCapability( ··· 286 288 PhabricatorPolicyCapability::CAN_EDIT); 287 289 288 290 $slug = PhabricatorSlug::normalize($this->slug); 291 + $id = $document->getID(); 289 292 290 293 $curtain = $this->newCurtainView($document); 291 294 ··· 295 298 ->setDisabled(!$can_edit) 296 299 ->setIcon('fa-pencil') 297 300 ->setHref('/phriction/edit/'.$document->getID().'/')); 301 + 302 + $is_current = false; 303 + $content_id = null; 304 + if ($content) { 305 + if ($content->getPHID() == $document->getContentPHID()) { 306 + $is_current = true; 307 + } 308 + $content_id = $content->getID(); 309 + } 310 + $can_publish = ($can_edit && $content && !$is_current); 311 + 312 + $publish_uri = "/phriction/publish/{$id}/{$content_id}/"; 313 + 314 + $curtain->addAction( 315 + id(new PhabricatorActionView()) 316 + ->setName(pht('Publish')) 317 + ->setIcon('fa-upload') 318 + ->setDisabled(!$can_publish) 319 + ->setWorkflow(true) 320 + ->setHref($publish_uri)); 298 321 299 322 if ($document->getStatus() == PhrictionDocumentStatus::STATUS_EXISTS) { 300 323 $curtain->addAction(
+86
src/applications/phriction/controller/PhrictionPublishController.php
··· 1 + <?php 2 + 3 + final class PhrictionPublishController 4 + extends PhrictionController { 5 + 6 + public function handleRequest(AphrontRequest $request) { 7 + $viewer = $request->getViewer(); 8 + $id = $request->getURIData('documentID'); 9 + $content_id = $request->getURIData('contentID'); 10 + 11 + $document = id(new PhrictionDocumentQuery()) 12 + ->setViewer($viewer) 13 + ->withIDs(array($id)) 14 + ->needContent(true) 15 + ->requireCapabilities( 16 + array( 17 + PhabricatorPolicyCapability::CAN_EDIT, 18 + PhabricatorPolicyCapability::CAN_VIEW, 19 + )) 20 + ->executeOne(); 21 + if (!$document) { 22 + return new Aphront404Response(); 23 + } 24 + 25 + $document_uri = $document->getURI(); 26 + 27 + $content = id(new PhrictionContentQuery()) 28 + ->setViewer($viewer) 29 + ->withIDs(array($content_id)) 30 + ->executeOne(); 31 + if (!$content) { 32 + return new Aphront404Response(); 33 + } 34 + 35 + if ($content->getPHID() == $document->getContentPHID()) { 36 + return $this->newDialog() 37 + ->setTitle(pht('Already Published')) 38 + ->appendChild( 39 + pht( 40 + 'This version of the document is already the published '. 41 + 'version.')) 42 + ->addCancelButton($document_uri); 43 + } 44 + 45 + $content_uri = $document_uri.'?v='.$content->getVersion(); 46 + 47 + if ($request->isFormPost()) { 48 + $xactions = array(); 49 + 50 + $xactions[] = id(new PhrictionTransaction()) 51 + ->setTransactionType( 52 + PhrictionDocumentPublishTransaction::TRANSACTIONTYPE) 53 + ->setNewValue($content->getPHID()); 54 + 55 + id(new PhrictionTransactionEditor()) 56 + ->setActor($viewer) 57 + ->setContentSourceFromRequest($request) 58 + ->setContinueOnNoEffect(true) 59 + ->setContinueOnMissingFields(true) 60 + ->applyTransactions($document, $xactions); 61 + 62 + return id(new AphrontRedirectResponse())->setURI($document_uri); 63 + } 64 + 65 + if ($content->getVersion() < $document->getContent()->getVersion()) { 66 + $title = pht('Revert Document?'); 67 + $body = pht( 68 + 'Revert the published version of this document to an older '. 69 + 'version?'); 70 + $button = pht('Revert'); 71 + } else { 72 + $title = pht('Publish Draft?'); 73 + $body = pht( 74 + 'Update the published version of this document to this newer '. 75 + 'version?'); 76 + $button = pht('Publish'); 77 + } 78 + 79 + return $this->newDialog() 80 + ->setTitle($title) 81 + ->appendChild($body) 82 + ->addSubmitButton($button) 83 + ->addCancelButton($content_uri); 84 + } 85 + 86 + }
+71
src/applications/phriction/xaction/PhrictionDocumentPublishTransaction.php
··· 1 + <?php 2 + 3 + final class PhrictionDocumentPublishTransaction 4 + extends PhrictionDocumentTransactionType { 5 + 6 + const TRANSACTIONTYPE = 'publish'; 7 + 8 + public function generateOldValue($object) { 9 + return $object->getContentPHID(); 10 + } 11 + 12 + public function applyInternalEffects($object, $value) { 13 + $object->setContentPHID($value); 14 + } 15 + 16 + public function getActionName() { 17 + return pht('Published'); 18 + } 19 + 20 + public function getTitle() { 21 + return pht( 22 + '%s published a new version of this document.', 23 + $this->renderAuthor()); 24 + } 25 + 26 + public function getTitleForFeed() { 27 + return pht( 28 + '%s published a new version of %s.', 29 + $this->renderAuthor(), 30 + $this->renderObject()); 31 + } 32 + 33 + public function validateTransactions($object, array $xactions) { 34 + $actor = $this->getActor(); 35 + $errors = array(); 36 + 37 + foreach ($xactions as $xaction) { 38 + $content_phid = $xaction->getNewValue(); 39 + 40 + // If this isn't changing anything, skip it. 41 + if ($content_phid === $object->getContentPHID()) { 42 + continue; 43 + } 44 + 45 + $content = id(new PhrictionContentQuery()) 46 + ->setViewer($actor) 47 + ->withPHIDs(array($content_phid)) 48 + ->executeOne(); 49 + if (!$content) { 50 + $errors[] = $this->newInvalidError( 51 + pht( 52 + 'Unable to load Content object with PHID "%s".', 53 + $content_phid), 54 + $xaction); 55 + continue; 56 + } 57 + 58 + if ($content->getDocumentPHID() !== $object->getPHID()) { 59 + $errors[] = $this->newInvalidError( 60 + pht( 61 + 'Content object "%s" can not be published because it belongs '. 62 + 'to a different document.', 63 + $content_phid)); 64 + continue; 65 + } 66 + } 67 + 68 + return $errors; 69 + } 70 + 71 + }
+11
src/view/phui/PHUIDocumentView.php
··· 9 9 private $toc; 10 10 private $foot; 11 11 private $curtain; 12 + private $banner; 12 13 13 14 public function setHeader(PHUIHeaderView $header) { 14 15 $header->setTall(true); ··· 44 45 45 46 public function getCurtain() { 46 47 return $this->curtain; 48 + } 49 + 50 + public function setBanner($banner) { 51 + $this->banner = $banner; 52 + return $this; 53 + } 54 + 55 + public function getBanner() { 56 + return $this->banner; 47 57 } 48 58 49 59 protected function getTagAttributes() { ··· 160 170 array( 161 171 $table_of_contents, 162 172 $this->header, 173 + $this->banner, 163 174 array( 164 175 $curtain, 165 176 $main_content,