@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 - move "move" to modern editor + transactions

Summary:
Ref T4029. Much like D10756, D10761 this does the bare minimum to get things in there. I have a sticky with "TODOs" about moving the error-checking business logic into the editor in all three cases.

Up next - policy...

Test Plan: moved a document and it worked! verified no feed story. verified both documents involved looked good

Reviewers: epriestley

Reviewed By: epriestley

Subscribers: epriestley, Korvin

Maniphest Tasks: T4029

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

+168 -50
+43 -45
src/applications/phriction/controller/PhrictionMoveController.php
··· 16 16 $document = id(new PhrictionDocumentQuery()) 17 17 ->setViewer($user) 18 18 ->withIDs(array($this->id)) 19 + ->needContent(true) 19 20 ->requireCapabilities( 20 21 array( 21 22 PhabricatorPolicyCapability::CAN_VIEW, ··· 32 33 $document = id(new PhrictionDocumentQuery()) 33 34 ->setViewer($user) 34 35 ->withSlugs(array($slug)) 36 + ->needContent(true) 35 37 ->requireCapabilities( 36 38 array( 37 39 PhabricatorPolicyCapability::CAN_VIEW, ··· 74 76 return id(new AphrontDialogResponse())->setDialog($error_dialog); 75 77 } 76 78 77 - $content = id(new PhrictionContent())->load($document->getContentID()); 79 + $content = $document->getContent(); 78 80 79 81 if ($request->isFormPost() && !count($errors)) { 80 - if (!count($errors)) { // First check if the target document exists 81 - 82 - // NOTE: We use the ominpotent user because we can't let users overwrite 83 - // documents even if they can't see them. 84 - $target_document = id(new PhrictionDocumentQuery()) 85 - ->setViewer(PhabricatorUser::getOmnipotentUser()) 86 - ->withSlugs(array($target_slug)) 87 - ->executeOne(); 88 82 89 - // Considering to overwrite existing docs? Nuke this! 90 - if ($target_document && $target_document->getStatus() == 91 - PhrictionDocumentStatus::STATUS_EXISTS) { 83 + // NOTE: We use the ominpotent user because we can't let users overwrite 84 + // documents even if they can't see them. 85 + $target_document = id(new PhrictionDocumentQuery()) 86 + ->setViewer(PhabricatorUser::getOmnipotentUser()) 87 + ->withSlugs(array($target_slug)) 88 + ->needContent(true) 89 + ->executeOne(); 92 90 93 - $errors[] = pht('Can not overwrite existing target document.'); 94 - $e_url = pht('Already exists.'); 95 - } 91 + // Considering to overwrite existing docs? Nuke this! 92 + $exists = PhrictionDocumentStatus::STATUS_EXISTS; 93 + if ($target_document && $target_document->getStatus() == $exists) { 94 + $errors[] = pht('Can not overwrite existing target document.'); 95 + $e_url = pht('Already exists.'); 96 96 } 97 97 98 - if (!count($errors)) { // I like to move it, move it! 99 - $from_editor = id(PhrictionDocumentEditor::newForSlug($slug)) 100 - ->setActor($user) 101 - ->setTitle($content->getTitle()) 102 - ->setContent($content->getContent()) 103 - ->setDescription($content->getDescription()); 98 + if (!count($errors)) { 104 99 105 - $target_editor = id(PhrictionDocumentEditor::newForSlug( 106 - $target_slug)) 100 + $editor = id(new PhrictionTransactionEditor()) 107 101 ->setActor($user) 108 - ->setTitle($content->getTitle()) 109 - ->setContent($content->getContent()) 110 - ->setDescription($content->getDescription()); 111 - 112 - // Move it! 113 - $target_editor->moveHere($document->getID(), $document->getPHID()); 102 + ->setContentSourceFromRequest($request) 103 + ->setContinueOnNoEffect(true) 104 + ->setDescription($request->getStr('description')); 114 105 115 - // Retrieve the target doc directly from the editor 116 - // No need to load it per Sql again 117 - $target_document = $target_editor->getDocument(); 118 - $from_editor->moveAway($target_document->getID()); 106 + $xactions = array(); 107 + $xactions[] = id(new PhrictionTransaction()) 108 + ->setTransactionType(PhrictionTransaction::TYPE_MOVE_TO) 109 + ->setNewValue($document); 110 + if (!$target_document) { 111 + $target_document = PhrictionDocument::initializeNewDocument( 112 + $user, 113 + $target_slug); 114 + } 115 + $editor->applyTransactions($target_document, $xactions); 119 116 120 - $redir_uri = PhrictionDocument::getSlugURI($target_document->getSlug()); 117 + $redir_uri = PhrictionDocument::getSlugURI( 118 + $target_document->getSlug()); 121 119 return id(new AphrontRedirectResponse())->setURI($redir_uri); 122 120 } 123 121 } ··· 131 129 ->setUser($user) 132 130 ->appendChild( 133 131 id(new AphrontFormStaticControl()) 134 - ->setLabel(pht('Title')) 135 - ->setValue($content->getTitle())) 132 + ->setLabel(pht('Title')) 133 + ->setValue($content->getTitle())) 136 134 ->appendChild( 137 135 id(new AphrontFormTextControl()) 138 - ->setLabel(pht('New URI')) 139 - ->setValue($target_slug) 140 - ->setError($e_url) 141 - ->setName('new-slug') 142 - ->setCaption(pht('The new location of the document.'))) 136 + ->setLabel(pht('New URI')) 137 + ->setValue($target_slug) 138 + ->setError($e_url) 139 + ->setName('new-slug') 140 + ->setCaption(pht('The new location of the document.'))) 143 141 ->appendChild( 144 142 id(new AphrontFormTextControl()) 145 - ->setLabel(pht('Edit Notes')) 146 - ->setValue($content->getDescription()) 147 - ->setError(null) 148 - ->setName('description')); 143 + ->setLabel(pht('Edit Notes')) 144 + ->setValue($content->getDescription()) 145 + ->setError(null) 146 + ->setName('description')); 149 147 150 148 $dialog = id(new AphrontDialogView()) 151 149 ->setUser($user)
+68 -5
src/applications/phriction/editor/PhrictionTransactionEditor.php
··· 6 6 private $description; 7 7 private $oldContent; 8 8 private $newContent; 9 + private $moveAwayDocument; 9 10 10 11 public function setDescription($description) { 11 12 $this->description = $description; ··· 49 50 $types[] = PhrictionTransaction::TYPE_TITLE; 50 51 $types[] = PhrictionTransaction::TYPE_CONTENT; 51 52 $types[] = PhrictionTransaction::TYPE_DELETE; 53 + $types[] = PhrictionTransaction::TYPE_MOVE_TO; 54 + $types[] = PhrictionTransaction::TYPE_MOVE_AWAY; 52 55 53 56 /* TODO 54 57 $types[] = PhabricatorTransactions::TYPE_VIEW_POLICY; ··· 74 77 } 75 78 return $this->getOldContent()->getContent(); 76 79 case PhrictionTransaction::TYPE_DELETE: 80 + case PhrictionTransaction::TYPE_MOVE_TO: 81 + case PhrictionTransaction::TYPE_MOVE_AWAY: 77 82 return null; 78 83 } 79 84 } ··· 87 92 case PhrictionTransaction::TYPE_CONTENT: 88 93 case PhrictionTransaction::TYPE_DELETE: 89 94 return $xaction->getNewValue(); 95 + case PhrictionTransaction::TYPE_MOVE_TO: 96 + $document = $xaction->getNewValue(); 97 + // grab the real object now for the sub-editor to come 98 + $this->moveAwayDocument = $document; 99 + $dict = array( 100 + 'id' => $document->getID(), 101 + 'phid' => $document->getPHID(), 102 + 'content' => $document->getContent()->getContent(),); 103 + return $dict; 104 + case PhrictionTransaction::TYPE_MOVE_AWAY: 105 + $document = $xaction->getNewValue(); 106 + $dict = array( 107 + 'id' => $document->getID(), 108 + 'phid' => $document->getPHID(), 109 + 'content' => $document->getContent()->getContent(),); 110 + return $dict; 90 111 } 91 112 } 92 113 ··· 99 120 case PhrictionTransaction::TYPE_TITLE: 100 121 case PhrictionTransaction::TYPE_CONTENT: 101 122 case PhrictionTransaction::TYPE_DELETE: 123 + case PhrictionTransaction::TYPE_MOVE_TO: 124 + case PhrictionTransaction::TYPE_MOVE_AWAY: 102 125 return true; 103 126 } 104 127 } ··· 120 143 switch ($xaction->getTransactionType()) { 121 144 case PhrictionTransaction::TYPE_TITLE: 122 145 case PhrictionTransaction::TYPE_CONTENT: 146 + case PhrictionTransaction::TYPE_MOVE_TO: 123 147 $object->setStatus(PhrictionDocumentStatus::STATUS_EXISTS); 124 148 return; 149 + case PhrictionTransaction::TYPE_MOVE_AWAY: 150 + $object->setStatus(PhrictionDocumentStatus::STATUS_MOVED); 151 + return; 125 152 } 126 153 } 127 154 ··· 141 168 $this->getNewContent()->setChangeType( 142 169 PhrictionChangeType::CHANGE_DELETE); 143 170 break; 171 + case PhrictionTransaction::TYPE_MOVE_TO: 172 + $dict = $xaction->getNewValue(); 173 + $this->getNewContent()->setContent($dict['content']); 174 + $this->getNewContent()->setChangeType( 175 + PhrictionChangeType::CHANGE_MOVE_HERE); 176 + $this->getNewContent()->setChangeRef($dict['id']); 177 + break; 178 + case PhrictionTransaction::TYPE_MOVE_AWAY: 179 + $dict = $xaction->getNewValue(); 180 + $this->getNewContent()->setContent(''); 181 + $this->getNewContent()->setChangeType( 182 + PhrictionChangeType::CHANGE_MOVE_AWAY); 183 + $this->getNewContent()->setChangeRef($dict['id']); 184 + break; 144 185 default: 145 186 break; 146 187 } ··· 156 197 case PhrictionTransaction::TYPE_TITLE: 157 198 case PhrictionTransaction::TYPE_CONTENT: 158 199 case PhrictionTransaction::TYPE_DELETE: 200 + case PhrictionTransaction::TYPE_MOVE_AWAY: 201 + case PhrictionTransaction::TYPE_MOVE_TO: 159 202 $save_content = true; 160 203 break; 161 204 default: ··· 196 239 } 197 240 } 198 241 } 242 + 243 + if ($this->moveAwayDocument !== null) { 244 + $move_away_xactions = array(); 245 + $move_away_xactions[] = id(new PhrictionTransaction()) 246 + ->setTransactionType(PhrictionTransaction::TYPE_MOVE_AWAY) 247 + ->setNewValue($object); 248 + $sub_editor = id(new PhrictionTransactionEditor()) 249 + ->setActor($this->getActor()) 250 + ->setContentSource($this->getContentSource()) 251 + ->setContinueOnNoEffect($this->getContinueOnNoEffect()) 252 + ->setDescription($this->getDescription()) 253 + ->applyTransactions($this->moveAwayDocument, $move_away_xactions); 254 + } 255 + 199 256 return $xactions; 200 257 } 201 258 202 259 protected function shouldSendMail( 203 260 PhabricatorLiskDAO $object, 204 261 array $xactions) { 205 - 206 - $xactions = mfilter($xactions, 'shouldHide', true); 207 - return $xactions; 262 + return true; 208 263 } 209 264 210 265 protected function getMailSubjectPrefix() { ··· 274 329 array $xactions) { 275 330 276 331 $phids = parent::getFeedRelatedPHIDs($object, $xactions); 277 - // TODO - once the editor supports moves, we'll need to surface the 278 - // "from document phid" to related phids. 332 + 333 + foreach ($xactions as $xaction) { 334 + switch ($xaction->getTransactionType()) { 335 + case PhrictionTransaction::TYPE_MOVE_TO: 336 + $dict = $xaction->getNewValue(); 337 + $phids[] = $dict['phid']; 338 + break; 339 + } 340 + } 341 + 279 342 return $phids; 280 343 } 281 344
+57
src/applications/phriction/storage/PhrictionTransaction.php
··· 6 6 const TYPE_TITLE = 'title'; 7 7 const TYPE_CONTENT = 'content'; 8 8 const TYPE_DELETE = 'delete'; 9 + const TYPE_MOVE_TO = 'move-to'; 10 + const TYPE_MOVE_AWAY = 'move-away'; 9 11 10 12 const MAILTAG_TITLE = 'phriction-title'; 11 13 const MAILTAG_CONTENT = 'phriction-content'; ··· 23 25 return new PhrictionTransactionComment(); 24 26 } 25 27 28 + public function getRequiredHandlePHIDs() { 29 + $phids = parent::getRequiredHandlePHIDs(); 30 + $new = $this->getNewValue(); 31 + switch ($this->getTransactionType()) { 32 + case self::TYPE_MOVE_TO: 33 + case self::TYPE_MOVE_AWAY: 34 + $phids[] = $new['phid']; 35 + break; 36 + } 37 + 38 + 39 + return $phids; 40 + } 41 + 26 42 public function getRemarkupBlocks() { 27 43 $blocks = parent::getRemarkupBlocks(); 28 44 ··· 49 65 return parent::shouldHide(); 50 66 } 51 67 68 + public function shouldHideForMail(array $xactions) { 69 + switch ($this->getTransactionType()) { 70 + case self::TYPE_MOVE_TO: 71 + case self::TYPE_MOVE_AWAY: 72 + return true; 73 + } 74 + return parent::shouldHideForMail($xactions); 75 + } 76 + 77 + public function shouldHideForFeed() { 78 + switch ($this->getTransactionType()) { 79 + case self::TYPE_MOVE_TO: 80 + case self::TYPE_MOVE_AWAY: 81 + return true; 82 + } 83 + return parent::shouldHideForFeed(); 84 + } 85 + 52 86 public function getActionStrength() { 53 87 switch ($this->getTransactionType()) { 54 88 case self::TYPE_TITLE: ··· 57 91 return 1.3; 58 92 case self::TYPE_DELETE: 59 93 return 1.5; 94 + case self::TYPE_MOVE_TO: 95 + case self::TYPE_MOVE_AWAY: 96 + return 1.0; 60 97 } 61 98 62 99 return parent::getActionStrength(); ··· 79 116 80 117 case self::TYPE_DELETE: 81 118 return pht('Deleted'); 119 + 120 + case self::TYPE_MOVE_TO: 121 + return pht('Moved'); 122 + 123 + case self::TYPE_MOVE_AWAY: 124 + return pht('Moved Away'); 82 125 83 126 } 84 127 ··· 95 138 return 'fa-pencil'; 96 139 case self::TYPE_DELETE: 97 140 return 'fa-times'; 141 + case self::TYPE_MOVE_TO: 142 + case self::TYPE_MOVE_AWAY: 143 + return 'fa-arrows'; 98 144 } 99 145 100 146 return parent::getIcon(); ··· 130 176 '%s deleted this document.', 131 177 $this->renderHandleLink($author_phid)); 132 178 179 + case self::TYPE_MOVE_TO: 180 + return pht( 181 + '%s moved this document from %s', 182 + $this->renderHandleLink($author_phid), 183 + $this->renderHandleLink($new['phid'])); 184 + 185 + case self::TYPE_MOVE_AWAY: 186 + return pht( 187 + '%s moved this document to %s', 188 + $this->renderHandleLink($author_phid), 189 + $this->renderHandleLink($new['phid'])); 133 190 134 191 } 135 192