@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.

Phriction Documents can be moved

Summary: Refs T1575

Test Plan:
created plenty of pages, did all kind of stuff with them, moved them around, verified expected behaviour.

{F34453}

{F34455}

Reviewers: epriestley, chad, btrahan

Reviewed By: epriestley

CC: aran, epriestley, Korvin

Maniphest Tasks: T1575

Differential Revision: https://secure.phabricator.com/D5198

authored by

Anh Nhan Nguyen and committed by
epriestley
911d02e2 cd99850c

+274 -21
+2
src/__phutil_library_map__.php
··· 1497 1497 'PhrictionEditController' => 'applications/phriction/controller/PhrictionEditController.php', 1498 1498 'PhrictionHistoryController' => 'applications/phriction/controller/PhrictionHistoryController.php', 1499 1499 'PhrictionListController' => 'applications/phriction/controller/PhrictionListController.php', 1500 + 'PhrictionMoveController' => 'applications/phriction/controller/PhrictionMoveController.php', 1500 1501 'PhrictionNewController' => 'applications/phriction/controller/PhrictionNewController.php', 1501 1502 'PhrictionRemarkupRule' => 'applications/phriction/remarkup/PhrictionRemarkupRule.php', 1502 1503 'PhrictionSearchIndexer' => 'applications/phriction/search/PhrictionSearchIndexer.php', ··· 3003 3004 'PhrictionEditController' => 'PhrictionController', 3004 3005 'PhrictionHistoryController' => 'PhrictionController', 3005 3006 'PhrictionListController' => 'PhrictionController', 3007 + 'PhrictionMoveController' => 'PhrictionController', 3006 3008 'PhrictionNewController' => 'PhrictionController', 3007 3009 'PhrictionRemarkupRule' => 'PhutilRemarkupRule', 3008 3010 'PhrictionSearchIndexer' => 'PhabricatorSearchDocumentIndexer',
+1 -1
src/applications/phriction/application/PhabricatorApplicationPhriction.php
··· 43 43 'edit/(?:(?P<id>[1-9]\d*)/)?' => 'PhrictionEditController', 44 44 'delete/(?P<id>[1-9]\d*)/' => 'PhrictionDeleteController', 45 45 'new/' => 'PhrictionNewController', 46 - 'move/(?P<id>[1-9]\d*)/' => 'PhrictionMoveController', 46 + 'move/(?:(?P<id>[1-9]\d*)/)?' => 'PhrictionMoveController', 47 47 48 48 'preview/' => 'PhrictionDocumentPreviewController', 49 49 'diff/(?P<id>[1-9]\d*)/' => 'PhrictionDiffController',
+4
src/applications/phriction/constants/PhrictionActionConstants.php
··· 8 8 const ACTION_CREATE = 'create'; 9 9 const ACTION_EDIT = 'edit'; 10 10 const ACTION_DELETE = 'delete'; 11 + const ACTION_MOVE_AWAY = 'move to'; 12 + const ACTION_MOVE_HERE = 'move here'; 11 13 12 14 public static function getActionPastTenseVerb($action) { 13 15 static $map = array( 14 16 self::ACTION_CREATE => 'created', 15 17 self::ACTION_EDIT => 'edited', 16 18 self::ACTION_DELETE => 'deleted', 19 + self::ACTION_MOVE_AWAY => 'moved a document to', 20 + self::ACTION_MOVE_HERE => 'moved a document from', 17 21 ); 18 22 19 23 return idx($map, $action, "brazenly {$action}'d");
+2 -1
src/applications/phriction/constants/PhrictionDocumentStatus.php
··· 12 12 13 13 public static function getConduitConstant($const) { 14 14 static $map = array( 15 - self::STATUS_EXISTS => 'exists', 15 + self::STATUS_EXISTS => 'exists', 16 16 self::STATUS_DELETED => 'deleted', 17 + self::STATUS_MOVED => 'moved', 17 18 self::STATUS_STUB => 'stubbed', 18 19 ); 19 20
+37 -2
src/applications/phriction/controller/PhrictionDocumentController.php
··· 13 13 } 14 14 15 15 public function processRequest() { 16 - 17 16 $request = $this->getRequest(); 18 17 $user = $request->getUser(); 19 18 ··· 148 147 pht('This document is empty. You can edit it to put some proper '. 149 148 'content here.')); 150 149 $core_content = $notice->render(); 150 + } else if ($doc_status == PhrictionDocumentStatus::STATUS_MOVED) { 151 + $new_doc_id = $content->getChangeRef(); 152 + $new_doc = new PhrictionDocument(); 153 + $new_doc->load($new_doc_id); 154 + 155 + $slug_uri = PhrictionDocument::getSlugURI($new_doc->getSlug()); 156 + 157 + $notice = new AphrontErrorView(); 158 + $notice->setSeverity(AphrontErrorView::SEVERITY_NOTICE); 159 + $notice->setTitle(pht('Document Moved')); 160 + $notice->appendChild(phutil_tag('p', array(), 161 + pht('This document has been moved to %s. You can edit it to put new '. 162 + 'content here, or use history to revert to an earlier version.', 163 + phutil_tag('a', array('href' => $slug_uri), $slug_uri)))); 164 + $core_content = $notice->render(); 151 165 } else { 152 166 throw new Exception("Unknown document status '{$doc_status}'!"); 153 167 } 154 168 169 + $move_notice = null; 170 + if ($content->getChangeType() == PhrictionChangeType::CHANGE_MOVE_HERE) { 171 + $from_doc_id = $content->getChangeRef(); 172 + $from_doc = id(new PhrictionDocument())->load($from_doc_id); 173 + $slug_uri = PhrictionDocument::getSlugURI($from_doc->getSlug()); 174 + 175 + $move_notice = id(new AphrontErrorView()) 176 + ->setSeverity(AphrontErrorView::SEVERITY_NOTICE) 177 + ->appendChild(pht('This document was moved from %s', 178 + phutil_tag('a', array('href' => $slug_uri), $slug_uri))) 179 + ->render(); 180 + } 181 + 155 182 $page_content = hsprintf( 156 - '<div class="phriction-content">%s%s%s</div>', 183 + '<div class="phriction-content">%s%s%s%s</div>', 157 184 $index_link, 158 185 $byline, 186 + $move_notice, 159 187 $core_content); 160 188 } 161 189 ··· 221 249 ->setHref('/phriction/edit/'.$document->getID().'/')); 222 250 223 251 if ($document->getStatus() == PhrictionDocumentStatus::STATUS_EXISTS) { 252 + $action_view->addAction( 253 + id(new PhabricatorActionView()) 254 + ->setName(pht('Move Document')) 255 + ->setIcon('move') 256 + ->setHref('/phriction/move/'.$document->getID().'/') 257 + ->setWorkflow(true)); 258 + 224 259 $action_view->addAction( 225 260 id(new PhabricatorActionView()) 226 261 ->setName(pht('Delete Document'))
+6 -2
src/applications/phriction/controller/PhrictionListController.php
··· 115 115 case 'active': 116 116 $data = queryfx_all( 117 117 $conn, 118 - 'SELECT * FROM %T WHERE status != %d ORDER BY id DESC LIMIT %d, %d', 118 + 'SELECT * FROM %T WHERE status NOT IN (%Ld) ORDER BY id DESC '. 119 + 'LIMIT %d, %d', 119 120 $document_dao->getTableName(), 120 - PhrictionDocumentStatus::STATUS_DELETED, 121 + array( 122 + PhrictionDocumentStatus::STATUS_DELETED, 123 + PhrictionDocumentStatus::STATUS_MOVED, 124 + ), 121 125 $pager->getOffset(), 122 126 $pager->getPageSize() + 1); 123 127 break;
+188
src/applications/phriction/controller/PhrictionMoveController.php
··· 1 + <?php 2 + 3 + /** 4 + * @group phriction 5 + */ 6 + final class PhrictionMoveController 7 + extends PhrictionController { 8 + 9 + private $id; 10 + 11 + public function willProcessRequest(array $data) { 12 + $this->id = idx($data, 'id'); 13 + } 14 + 15 + public function processRequest() { 16 + $request = $this->getRequest(); 17 + $user = $request->getUser(); 18 + $is_serious = PhabricatorEnv::getEnvConfig('phabricator.serious-business'); 19 + 20 + if ($this->id) { 21 + $document = id(new PhrictionDocument())->load($this->id); 22 + } else { 23 + $slug = PhabricatorSlug::normalize( 24 + $request->getStr('slug')); 25 + if (!$slug) { 26 + return new Aphront404Response(); 27 + } 28 + 29 + $document = id(new PhrictionDocument())->loadOneWhere( 30 + 'slug = %s', 31 + $slug); 32 + } 33 + 34 + if (!$document) { 35 + return new Aphront404Response(); 36 + } 37 + 38 + if (!isset($slug)) { 39 + $slug = $document->getSlug(); 40 + } 41 + 42 + $target_slug = PhabricatorSlug::normalize( 43 + $request->getStr('new-slug', $slug)); 44 + 45 + $submit_uri = $request->getRequestURI()->getPath(); 46 + $cancel_uri = PhrictionDocument::getSlugURI($slug); 47 + 48 + $errors = array(); 49 + $error_view = null; 50 + $e_url = null; 51 + $e_block = false; 52 + 53 + $disallowed_statuses = array( 54 + PhrictionDocumentStatus::STATUS_DELETED, // Stupid 55 + PhrictionDocumentStatus::STATUS_MOVED, // Plain stupid 56 + ); 57 + if (in_array($document->getStatus(), $disallowed_statuses)) { 58 + $error_view = new AphrontErrorView(); 59 + $error_view->setSeverity(AphrontErrorView::SEVERITY_ERROR); 60 + $error_view->appendChild(pht('An already moved or deleted document '. 61 + 'can not be moved again.')); 62 + 63 + $error_dialog = new AphrontDialogView(); 64 + $error_dialog->setUser($user); 65 + $error_dialog->setTitle(""); 66 + $error_dialog->appendChild($error_view); 67 + $error_dialog->addCancelButton($cancel_uri, pht('I understand')); 68 + 69 + return id(new AphrontDialogResponse())->setDialog($error_dialog); 70 + } 71 + 72 + $content = id(new PhrictionContent())->load($document->getContentID()); 73 + 74 + if ($request->isFormPost() && !count($errors)) { 75 + if (!count($errors)) { // First check if the target document exists 76 + $target_document = id(new PhrictionDocument())->loadOneWhere( 77 + 'slug = %s', 78 + $target_slug); 79 + 80 + // Considering to overwrite existing docs? Nuke this! 81 + if ($target_document && $target_document->getStatus() == 82 + PhrictionDocumentStatus::STATUS_EXISTS) { 83 + 84 + $errors[] = pht('Can not overwrite existing target document.'); 85 + $e_url = pht('Already exists.'); 86 + } 87 + } 88 + 89 + if (!count($errors)) { // I like to move it, move it! 90 + $from_editor = id(PhrictionDocumentEditor::newForSlug($slug)) 91 + ->setActor($user) 92 + ->setTitle($content->getTitle()) 93 + ->setContent($content->getContent()) 94 + ->setDescription($content->getDescription()); 95 + 96 + $target_editor = id(PhrictionDocumentEditor::newForSlug( 97 + $target_slug)) 98 + ->setActor($user) 99 + ->setTitle($content->getTitle()) 100 + ->setContent($content->getContent()) 101 + ->setDescription($content->getDescription()); 102 + 103 + // Move it! 104 + $target_editor->moveHere($document->getID()); 105 + 106 + // Retrieve the target doc directly from the editor 107 + // No need to load it per Sql again 108 + $target_document = $target_editor->getDocument(); 109 + $from_editor->moveAway($target_document->getID()); 110 + 111 + $redir_uri = PhrictionDocument::getSlugURI($target_document->getSlug()); 112 + return id(new AphrontRedirectResponse())->setURI($redir_uri); 113 + } 114 + } 115 + 116 + if ($errors) { 117 + $error_view = id(new AphrontErrorView()) 118 + ->setTitle(pht('Form Errors')) 119 + ->setErrors($errors); 120 + } 121 + 122 + $descr_caption = $is_serious ? pht('A reason for the move.') : 123 + pht('You better give a good reason for this.'); 124 + 125 + if ($request->isAjax()) { 126 + $form = new AphrontFormLayoutView(); 127 + } else { 128 + $form = new AphrontFormView(); 129 + $form->setAction($submit_uri) 130 + // Append title so the user can verify that he's touching 131 + // the right document 132 + ->appendChild( 133 + id(new AphrontFormStaticControl()) 134 + ->setLabel(pht('Title')) 135 + ->setValue($content->getTitle())); 136 + } 137 + 138 + $form 139 + ->setUser($user) 140 + ->appendChild( 141 + id(new AphrontFormTextControl()) 142 + ->setLabel(pht('New URI')) 143 + ->setValue($target_slug) 144 + ->setError($e_url) 145 + ->setName('new-slug') 146 + ->setCaption(pht('The new location of the document.'))) 147 + ->appendChild( 148 + id(new AphrontFormTextControl()) 149 + ->setLabel(pht('Edit Notes')) 150 + ->setValue($content->getDescription()) 151 + ->setError(null) 152 + ->setName('description') 153 + ->setCaption($descr_caption)); 154 + 155 + if ($request->isAjax()) { 156 + $dialog = new AphrontDialogView(); 157 + $dialog->setUser($user); 158 + $dialog->setTitle(pht('Move Document')); 159 + $dialog->appendChild($form); 160 + $dialog->setSubmitURI($submit_uri); 161 + $dialog->addSubmitButton(pht('Move Document')); 162 + $dialog->addCancelButton($cancel_uri); 163 + 164 + return id(new AphrontDialogResponse())->setDialog($dialog); 165 + } else { 166 + $form->appendChild( 167 + id(new AphrontFormSubmitControl()) 168 + ->addCancelButton($cancel_uri) 169 + ->setValue(pht('Move Document')) 170 + ->setDisabled($e_block)); 171 + 172 + $panel = id(new AphrontPanelView()) 173 + ->setNoBackground() 174 + ->setHeader(pht('Move Phriction Document')) 175 + ->appendChild($form); 176 + 177 + return $this->buildApplicationPage( 178 + array( 179 + $error_view, 180 + $panel, 181 + ), 182 + array( 183 + 'title' => pht('Move Document'), 184 + 'device' => true, 185 + )); 186 + } 187 + } 188 + }
+34 -15
src/applications/phriction/editor/PhrictionDocumentEditor.php
··· 66 66 return $this->document; 67 67 } 68 68 69 - public function delete() { 70 - $actor = $this->requireActor(); 69 + public function moveAway($new_doc_id) { 70 + return $this->execute( 71 + PhrictionChangeType::CHANGE_MOVE_AWAY, true, $new_doc_id); 72 + } 73 + 74 + public function moveHere($old_doc_id) { 75 + return $this->execute( 76 + PhrictionChangeType::CHANGE_MOVE_HERE, false, $old_doc_id); 77 + } 78 + 79 + private function execute( 80 + $change_type, $del_new_content = true, $doc_ref = null) { 71 81 72 - // TODO: Should we do anything about deleting an already-deleted document? 73 - // We currently allow it. 82 + $actor = $this->requireActor(); 74 83 75 84 $document = $this->document; 76 85 $content = $this->content; 77 86 78 87 $new_content = $this->buildContentTemplate($document, $content); 88 + $new_content->setChangeType($change_type); 79 89 80 - $new_content->setChangeType(PhrictionChangeType::CHANGE_DELETE); 81 - $new_content->setContent(''); 90 + if ($del_new_content) { 91 + $new_content->setContent(''); 92 + } 93 + 94 + if ($doc_ref) { 95 + $new_content->setChangeRef($doc_ref); 96 + } 82 97 83 98 return $this->updateDocument($document, $content, $new_content); 84 99 } 85 100 86 - private function stub() { 87 - $actor = $this->requireActor(); 88 - $document = $this->document; 89 - $content = $this->content; 90 - $new_content = $this->buildContentTemplate($document, $content); 91 - 92 - $new_content->setChangeType(PhrictionChangeType::CHANGE_STUB); 93 - $new_content->setContent(''); 101 + public function delete() { 102 + return $this->execute(PhrictionChangeType::CHANGE_DELETE, true); 103 + } 94 104 95 - return $this->updateDocument($document, $content, $new_content); 105 + private function stub() { 106 + return $this->execute(PhrictionChangeType::CHANGE_STUB, true); 96 107 } 97 108 98 109 public function save() { ··· 166 177 break; 167 178 case PhrictionChangeType::CHANGE_STUB: 168 179 $doc_status = PhrictionDocumentStatus::STATUS_STUB; 180 + $feed_action = null; 181 + break; 182 + case PhrictionChangeType::CHANGE_MOVE_AWAY: 183 + $doc_status = PhrictionDocumentStatus::STATUS_MOVED; 184 + $feed_action = PhrictionActionConstants::ACTION_MOVE_AWAY; 185 + break; 186 + case PhrictionChangeType::CHANGE_MOVE_HERE: 187 + $doc_status = PhrictionDocumentStatus::STATUS_EXISTS; 169 188 $feed_action = null; 170 189 break; 171 190 default: