@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 - start the move towards transactions and an editor

Summary:
This implements as little as possible to stick a working transactions + editor codepath in the basic create / edit flow. Aside from the transaction tables, this also required adding a mailKey to a phrictionDocument.

Future work would include adding more transactions types for things like "move" and all the pertinent support. Even future work is to add things like policies which will work easily in the transaction framework. Ref T4029.

Test Plan:
- made a wiki doc
- edit a wiki doc
- had someone subscribe to a wiki doc and edited it

For all three, the edits worked, a reasonable email was sent out, and feed stories were generated.

- made a wiki doc at a /location/like/this

document "stubs" were made as expected in /location and /location/like

Reviewers: epriestley

Reviewed By: epriestley

Subscribers: chad, Korvin, epriestley

Maniphest Tasks: T4029

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

+631 -15
+19
resources/sql/autopatches/20141025.phriction.1.xaction.sql
··· 1 + CREATE TABLE {$NAMESPACE}_phriction.phriction_transaction ( 2 + id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, 3 + phid VARCHAR(64) COLLATE utf8_bin NOT NULL, 4 + authorPHID VARCHAR(64) COLLATE utf8_bin NOT NULL, 5 + objectPHID VARCHAR(64) COLLATE utf8_bin NOT NULL, 6 + viewPolicy VARCHAR(64) COLLATE utf8_bin NOT NULL, 7 + editPolicy VARCHAR(64) COLLATE utf8_bin NOT NULL, 8 + commentPHID VARCHAR(64) COLLATE utf8_bin DEFAULT NULL, 9 + commentVersion INT UNSIGNED NOT NULL, 10 + transactionType VARCHAR(32) COLLATE utf8_bin NOT NULL, 11 + oldValue LONGTEXT COLLATE utf8_bin NOT NULL, 12 + newValue LONGTEXT COLLATE utf8_bin NOT NULL, 13 + contentSource LONGTEXT COLLATE utf8_bin NOT NULL, 14 + metadata LONGTEXT COLLATE utf8_bin NOT NULL, 15 + dateCreated INT UNSIGNED NOT NULL, 16 + dateModified INT UNSIGNED NOT NULL, 17 + UNIQUE KEY `key_phid` (`phid`), 18 + KEY `key_object` (`objectPHID`) 19 + ) ENGINE=InnoDB, COLLATE utf8_general_ci;
+16
resources/sql/autopatches/20141025.phriction.2.xaction.sql
··· 1 + CREATE TABLE {$NAMESPACE}_phriction.phriction_transaction_comment ( 2 + id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, 3 + phid VARCHAR(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL, 4 + transactionPHID VARCHAR(64) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL, 5 + authorPHID VARCHAR(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL, 6 + viewPolicy VARCHAR(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL, 7 + editPolicy VARCHAR(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL, 8 + commentVersion INT UNSIGNED NOT NULL, 9 + content LONGTEXT CHARACTER SET utf8 COLLATE utf8_bin NOT NULL, 10 + contentSource LONGTEXT CHARACTER SET utf8 COLLATE utf8_bin NOT NULL, 11 + isDeleted TINYINT(1) NOT NULL, 12 + dateCreated INT UNSIGNED NOT NULL, 13 + dateModified INT UNSIGNED NOT NULL, 14 + UNIQUE KEY `key_phid` (`phid`), 15 + UNIQUE KEY `key_version` (`transactionPHID`,`commentVersion`) 16 + ) ENGINE=InnoDB DEFAULT CHARSET=utf8
+2
resources/sql/autopatches/20141025.phriction.mailkey.sql
··· 1 + ALTER TABLE {$NAMESPACE}_phriction.phriction_document 2 + ADD mailKey VARCHAR(20) NOT NULL COLLATE utf8_bin;
+10
src/__phutil_library_map__.php
··· 2771 2771 'PhrictionMoveController' => 'applications/phriction/controller/PhrictionMoveController.php', 2772 2772 'PhrictionNewController' => 'applications/phriction/controller/PhrictionNewController.php', 2773 2773 'PhrictionRemarkupRule' => 'applications/phriction/markup/PhrictionRemarkupRule.php', 2774 + 'PhrictionReplyHandler' => 'applications/phriction/mail/PhrictionReplyHandler.php', 2774 2775 'PhrictionSchemaSpec' => 'applications/phriction/storage/PhrictionSchemaSpec.php', 2775 2776 'PhrictionSearchEngine' => 'applications/phriction/query/PhrictionSearchEngine.php', 2776 2777 'PhrictionSearchIndexer' => 'applications/phriction/search/PhrictionSearchIndexer.php', 2778 + 'PhrictionTransaction' => 'applications/phriction/storage/PhrictionTransaction.php', 2779 + 'PhrictionTransactionComment' => 'applications/phriction/storage/PhrictionTransactionComment.php', 2780 + 'PhrictionTransactionEditor' => 'applications/phriction/editor/PhrictionTransactionEditor.php', 2781 + 'PhrictionTransactionQuery' => 'applications/phriction/query/PhrictionTransactionQuery.php', 2777 2782 'PonderAddAnswerView' => 'applications/ponder/view/PonderAddAnswerView.php', 2778 2783 'PonderAnswer' => 'applications/ponder/storage/PonderAnswer.php', 2779 2784 'PonderAnswerCommentController' => 'applications/ponder/controller/PonderAnswerCommentController.php', ··· 5948 5953 'PhrictionMoveController' => 'PhrictionController', 5949 5954 'PhrictionNewController' => 'PhrictionController', 5950 5955 'PhrictionRemarkupRule' => 'PhutilRemarkupRule', 5956 + 'PhrictionReplyHandler' => 'PhabricatorMailReplyHandler', 5951 5957 'PhrictionSchemaSpec' => 'PhabricatorConfigSchemaSpec', 5952 5958 'PhrictionSearchEngine' => 'PhabricatorApplicationSearchEngine', 5953 5959 'PhrictionSearchIndexer' => 'PhabricatorSearchDocumentIndexer', 5960 + 'PhrictionTransaction' => 'PhabricatorApplicationTransaction', 5961 + 'PhrictionTransactionComment' => 'PhabricatorApplicationTransactionComment', 5962 + 'PhrictionTransactionEditor' => 'PhabricatorApplicationTransactionEditor', 5963 + 'PhrictionTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 5954 5964 'PonderAddAnswerView' => 'AphrontView', 5955 5965 'PonderAnswer' => array( 5956 5966 'PonderDAO',
+16 -14
src/applications/phriction/controller/PhrictionEditController.php
··· 73 73 return new Aphront404Response(); 74 74 } 75 75 } 76 - $document = new PhrictionDocument(); 77 - $document->setSlug($slug); 78 - 79 - $content = new PhrictionContent(); 80 - $content->setSlug($slug); 81 - 82 - $default_title = PhabricatorSlug::getDefaultTitle($slug); 83 - $content->setTitle($default_title); 76 + $document = PhrictionDocument::initializeNewDocument($user, $slug); 77 + $content = $document->getContent(); 84 78 } 85 79 } 86 80 ··· 174 168 } 175 169 176 170 if (!count($errors)) { 177 - $editor = id(PhrictionDocumentEditor::newForSlug($document->getSlug())) 178 - ->setActor($user) 179 - ->setTitle($title) 180 - ->setContent($request->getStr('content')) 181 - ->setDescription($notes); 182 171 183 - $editor->save(); 172 + $xactions = array(); 173 + $xactions[] = id(new PhrictionTransaction()) 174 + ->setTransactionType(PhrictionTransaction::TYPE_TITLE) 175 + ->setNewValue($title); 176 + $xactions[] = id(new PhrictionTransaction()) 177 + ->setTransactionType(PhrictionTransaction::TYPE_CONTENT) 178 + ->setNewValue($request->getStr('content')); 179 + 180 + $editor = id(new PhrictionTransactionEditor()) 181 + ->setActor($user) 182 + ->setContentSourceFromRequest($request) 183 + ->setContinueOnNoEffect(true) 184 + ->setDescription($notes) 185 + ->applyTransactions($document, $xactions); 184 186 185 187 if ($draft) { 186 188 $draft->delete();
+1 -1
src/applications/phriction/editor/PhrictionDocumentEditor.php
··· 106 106 return $this->execute(PhrictionChangeType::CHANGE_DELETE, true); 107 107 } 108 108 109 - private function stub() { 109 + public function stub() { 110 110 return $this->execute(PhrictionChangeType::CHANGE_STUB, true); 111 111 } 112 112
+298
src/applications/phriction/editor/PhrictionTransactionEditor.php
··· 1 + <?php 2 + 3 + final class PhrictionTransactionEditor 4 + extends PhabricatorApplicationTransactionEditor { 5 + 6 + private $description; 7 + private $oldContent; 8 + private $newContent; 9 + 10 + public function setDescription($description) { 11 + $this->description = $description; 12 + return $this; 13 + } 14 + 15 + private function getDescription() { 16 + return $this->description; 17 + } 18 + 19 + private function setOldContent(PhrictionContent $content) { 20 + $this->oldContent = $content; 21 + return $this; 22 + } 23 + 24 + private function getOldContent() { 25 + return $this->oldContent; 26 + } 27 + 28 + private function setNewContent(PhrictionContent $content) { 29 + $this->newContent = $content; 30 + return $this; 31 + } 32 + 33 + private function getNewContent() { 34 + return $this->newContent; 35 + } 36 + 37 + public function getEditorApplicationClass() { 38 + return 'PhabricatorPhrictionApplication'; 39 + } 40 + 41 + public function getEditorObjectsDescription() { 42 + return pht('Phriction Documents'); 43 + } 44 + 45 + public function getTransactionTypes() { 46 + $types = parent::getTransactionTypes(); 47 + 48 + $types[] = PhabricatorTransactions::TYPE_COMMENT; 49 + $types[] = PhrictionTransaction::TYPE_TITLE; 50 + $types[] = PhrictionTransaction::TYPE_CONTENT; 51 + 52 + /* TODO 53 + $types[] = PhabricatorTransactions::TYPE_VIEW_POLICY; 54 + $types[] = PhabricatorTransactions::TYPE_EDIT_POLICY; 55 + */ 56 + 57 + return $types; 58 + } 59 + 60 + protected function getCustomTransactionOldValue( 61 + PhabricatorLiskDAO $object, 62 + PhabricatorApplicationTransaction $xaction) { 63 + 64 + switch ($xaction->getTransactionType()) { 65 + case PhrictionTransaction::TYPE_TITLE: 66 + if ($this->getIsNewObject()) { 67 + return null; 68 + } 69 + return $this->getOldContent()->getTitle(); 70 + case PhrictionTransaction::TYPE_CONTENT: 71 + if ($this->getIsNewObject()) { 72 + return null; 73 + } 74 + return $this->getOldContent()->getContent(); 75 + } 76 + } 77 + 78 + protected function getCustomTransactionNewValue( 79 + PhabricatorLiskDAO $object, 80 + PhabricatorApplicationTransaction $xaction) { 81 + 82 + switch ($xaction->getTransactionType()) { 83 + case PhrictionTransaction::TYPE_TITLE: 84 + case PhrictionTransaction::TYPE_CONTENT: 85 + return $xaction->getNewValue(); 86 + } 87 + } 88 + 89 + protected function shouldApplyInitialEffects( 90 + PhabricatorLiskDAO $object, 91 + array $xactions) { 92 + 93 + foreach ($xactions as $xaction) { 94 + switch ($xaction->getTransactionType()) { 95 + case PhrictionTransaction::TYPE_TITLE: 96 + case PhrictionTransaction::TYPE_CONTENT: 97 + return true; 98 + } 99 + } 100 + return parent::shouldApplyInitialEffects($object, $xactions); 101 + } 102 + 103 + protected function applyInitialEffects( 104 + PhabricatorLiskDAO $object, 105 + array $xactions) { 106 + 107 + $this->setOldContent($object->getContent()); 108 + $this->setNewContent($this->buildNewContentTemplate($object)); 109 + } 110 + 111 + protected function applyCustomInternalTransaction( 112 + PhabricatorLiskDAO $object, 113 + PhabricatorApplicationTransaction $xaction) { 114 + 115 + switch ($xaction->getTransactionType()) { 116 + case PhrictionTransaction::TYPE_TITLE: 117 + case PhrictionTransaction::TYPE_CONTENT: 118 + $object->setStatus(PhrictionDocumentStatus::STATUS_EXISTS); 119 + return; 120 + } 121 + } 122 + 123 + protected function applyCustomExternalTransaction( 124 + PhabricatorLiskDAO $object, 125 + PhabricatorApplicationTransaction $xaction) { 126 + 127 + switch ($xaction->getTransactionType()) { 128 + case PhrictionTransaction::TYPE_TITLE: 129 + $this->getNewContent()->setTitle($xaction->getNewValue()); 130 + break; 131 + case PhrictionTransaction::TYPE_CONTENT: 132 + $this->getNewContent()->setContent($xaction->getNewValue()); 133 + break; 134 + default: 135 + break; 136 + } 137 + } 138 + 139 + protected function applyFinalEffects( 140 + PhabricatorLiskDAO $object, 141 + array $xactions) { 142 + 143 + $save_content = false; 144 + foreach ($xactions as $xaction) { 145 + switch ($xaction->getTransactionType()) { 146 + case PhrictionTransaction::TYPE_TITLE: 147 + case PhrictionTransaction::TYPE_CONTENT: 148 + $save_content = true; 149 + break; 150 + default: 151 + break; 152 + } 153 + } 154 + 155 + if ($save_content) { 156 + $content = $this->getNewContent(); 157 + $content->setDocumentID($object->getID()); 158 + $content->save(); 159 + 160 + $object->setContentID($content->getID()); 161 + $object->save(); 162 + $object->attachContent($content); 163 + } 164 + 165 + if ($this->getIsNewObject()) { 166 + // Stub out empty parent documents if they don't exist 167 + $ancestral_slugs = PhabricatorSlug::getAncestry($object->getSlug()); 168 + if ($ancestral_slugs) { 169 + $ancestors = id(new PhrictionDocument())->loadAllWhere( 170 + 'slug IN (%Ls)', 171 + $ancestral_slugs); 172 + $ancestors = mpull($ancestors, null, 'getSlug'); 173 + foreach ($ancestral_slugs as $slug) { 174 + // We check for change type to prevent near-infinite recursion 175 + if (!isset($ancestors[$slug]) && 176 + $content->getChangeType() != 177 + PhrictionChangeType::CHANGE_STUB) { 178 + id(PhrictionDocumentEditor::newForSlug($slug)) 179 + ->setActor($this->getActor()) 180 + ->setTitle(PhabricatorSlug::getDefaultTitle($slug)) 181 + ->setContent('') 182 + ->setDescription(pht('Empty Parent Document')) 183 + ->stub(); 184 + } 185 + } 186 + } 187 + } 188 + return $xactions; 189 + } 190 + 191 + protected function shouldSendMail( 192 + PhabricatorLiskDAO $object, 193 + array $xactions) { 194 + 195 + $xactions = mfilter($xactions, 'shouldHide', true); 196 + return $xactions; 197 + } 198 + 199 + protected function getMailSubjectPrefix() { 200 + return '[Phriction]'; 201 + } 202 + 203 + protected function getMailTo(PhabricatorLiskDAO $object) { 204 + return array( 205 + $object->getContent()->getAuthorPHID(), 206 + $this->getActingAsPHID(), 207 + ); 208 + } 209 + 210 + public function getMailTagsMap() { 211 + return array( 212 + PhrictionTransaction::MAILTAG_TITLE => 213 + pht("A document's title changes."), 214 + PhrictionTransaction::MAILTAG_CONTENT => 215 + pht("A document's content changes."), 216 + ); 217 + } 218 + 219 + protected function buildReplyHandler(PhabricatorLiskDAO $object) { 220 + return id(new PhrictionReplyHandler()) 221 + ->setMailReceiver($object); 222 + } 223 + 224 + protected function buildMailTemplate(PhabricatorLiskDAO $object) { 225 + $id = $object->getID(); 226 + $title = $object->getContent()->getTitle(); 227 + 228 + return id(new PhabricatorMetaMTAMail()) 229 + ->setSubject($title) 230 + ->addHeader('Thread-Topic', $object->getPHID()); 231 + } 232 + 233 + protected function buildMailBody( 234 + PhabricatorLiskDAO $object, 235 + array $xactions) { 236 + 237 + $body = parent::buildMailBody($object, $xactions); 238 + 239 + if ($this->getIsNewObject()) { 240 + $body->addTextSection( 241 + pht('DOCUMENT CONTENT'), 242 + $object->getContent()->getContent()); 243 + } 244 + 245 + $body->addTextSection( 246 + pht('DOCUMENT DETAIL'), 247 + PhabricatorEnv::getProductionURI( 248 + PhrictionDocument::getSlugURI($object->getSlug()))); 249 + 250 + return $body; 251 + } 252 + 253 + protected function shouldPublishFeedStory( 254 + PhabricatorLiskDAO $object, 255 + array $xactions) { 256 + return $this->shouldSendMail($object, $xactions); 257 + } 258 + 259 + protected function getFeedRelatedPHIDs( 260 + PhabricatorLiskDAO $object, 261 + array $xactions) { 262 + 263 + $phids = parent::getFeedRelatedPHIDs($object, $xactions); 264 + // TODO - once the editor supports moves, we'll need to surface the 265 + // "from document phid" to related phids. 266 + return $phids; 267 + } 268 + 269 + protected function supportsSearch() { 270 + return true; 271 + } 272 + 273 + protected function shouldApplyHeraldRules( 274 + PhabricatorLiskDAO $object, 275 + array $xactions) { 276 + return false; 277 + } 278 + 279 + private function buildNewContentTemplate( 280 + PhrictionDocument $document) { 281 + 282 + $new_content = new PhrictionContent(); 283 + $new_content->setSlug($document->getSlug()); 284 + $new_content->setAuthorPHID($this->getActor()->getPHID()); 285 + $new_content->setChangeType(PhrictionChangeType::CHANGE_EDIT); 286 + 287 + $new_content->setTitle($this->getOldContent()->getTitle()); 288 + $new_content->setContent($this->getOldContent()->getContent()); 289 + 290 + if (strlen($this->getDescription())) { 291 + $new_content->setDescription($this->getDescription()); 292 + } 293 + $new_content->setVersion($this->getOldContent()->getVersion() + 1); 294 + 295 + return $new_content; 296 + } 297 + 298 + }
+41
src/applications/phriction/mail/PhrictionReplyHandler.php
··· 1 + <?php 2 + 3 + final class PhrictionReplyHandler extends PhabricatorMailReplyHandler { 4 + 5 + public function validateMailReceiver($mail_receiver) { 6 + if (!($mail_receiver instanceof PhrictionDocument)) { 7 + throw new Exception('Mail receiver is not a PhrictionDocument!'); 8 + } 9 + } 10 + 11 + public function getPrivateReplyHandlerEmailAddress( 12 + PhabricatorObjectHandle $handle) { 13 + return $this->getDefaultPrivateReplyHandlerEmailAddress( 14 + $handle, 15 + PhrictionDocumentPHIDType::TYPECONST); 16 + } 17 + 18 + public function getPublicReplyHandlerEmailAddress() { 19 + return $this->getDefaultPublicReplyHandlerEmailAddress( 20 + PhrictionDocumentPHIDType::TYPECONST); 21 + } 22 + 23 + public function getReplyHandlerDomain() { 24 + return PhabricatorEnv::getEnvConfig('metamta.reply-handler-domain'); 25 + } 26 + 27 + public function getReplyHandlerInstructions() { 28 + if ($this->supportsReplies()) { 29 + // TODO: Implement. 30 + return null; 31 + } else { 32 + return null; 33 + } 34 + } 35 + 36 + protected function receiveEmail(PhabricatorMetaMTAReceivedMail $mail) { 37 + // TODO: Implement. 38 + return null; 39 + } 40 + 41 + }
+10
src/applications/phriction/query/PhrictionTransactionQuery.php
··· 1 + <?php 2 + 3 + final class PhrictionTransactionQuery 4 + extends PhabricatorApplicationTransactionQuery { 5 + 6 + public function getTemplateApplicationTransaction() { 7 + return new PhrictionTransaction(); 8 + } 9 + 10 + }
+22
src/applications/phriction/storage/PhrictionDocument.php
··· 12 12 protected $depth; 13 13 protected $contentID; 14 14 protected $status; 15 + protected $mailKey; 15 16 16 17 private $contentObject = self::ATTACHABLE; 17 18 private $ancestors = array(); ··· 51 52 public function generatePHID() { 52 53 return PhabricatorPHID::generateNewPHID( 53 54 PhrictionDocumentPHIDType::TYPECONST); 55 + } 56 + 57 + public static function initializeNewDocument(PhabricatorUser $actor, $slug) { 58 + $document = new PhrictionDocument(); 59 + $document->setSlug($slug); 60 + 61 + $content = new PhrictionContent(); 62 + $content->setSlug($slug); 63 + 64 + $default_title = PhabricatorSlug::getDefaultTitle($slug); 65 + $content->setTitle($default_title); 66 + $document->attachContent($content); 67 + 68 + return $document; 69 + } 70 + 71 + public function save() { 72 + if (!$this->getMailKey()) { 73 + $this->setMailKey(Filesystem::readRandomCharacters(20)); 74 + } 75 + return parent::save(); 54 76 } 55 77 56 78 public static function getSlugURI($slug, $type = 'document') {
+186
src/applications/phriction/storage/PhrictionTransaction.php
··· 1 + <?php 2 + 3 + final class PhrictionTransaction 4 + extends PhabricatorApplicationTransaction { 5 + 6 + const TYPE_TITLE = 'title'; 7 + const TYPE_CONTENT = 'content'; 8 + 9 + const MAILTAG_TITLE = 'phriction-title'; 10 + const MAILTAG_CONTENT = 'phriction-content'; 11 + 12 + public function getApplicationName() { 13 + return 'phriction'; 14 + } 15 + 16 + public function getApplicationTransactionType() { 17 + return PhrictionDocumentPHIDType::TYPECONST; 18 + } 19 + 20 + public function getApplicationTransactionCommentObject() { 21 + return new PhrictionTransactionComment(); 22 + } 23 + 24 + public function getRemarkupBlocks() { 25 + $blocks = parent::getRemarkupBlocks(); 26 + 27 + switch ($this->getTransactionType()) { 28 + case self::TYPE_CONTENT: 29 + $blocks[] = $this->getNewValue(); 30 + break; 31 + } 32 + 33 + return $blocks; 34 + } 35 + 36 + public function shouldHide() { 37 + switch ($this->getTransactionType()) { 38 + case self::TYPE_CONTENT: 39 + if ($this->getOldValue() === null) { 40 + return true; 41 + } else { 42 + return false; 43 + } 44 + break; 45 + } 46 + 47 + return parent::shouldHide(); 48 + } 49 + 50 + public function getActionStrength() { 51 + switch ($this->getTransactionType()) { 52 + case self::TYPE_TITLE: 53 + return 1.4; 54 + case self::TYPE_CONTENT: 55 + return 1.3; 56 + } 57 + 58 + return parent::getActionStrength(); 59 + } 60 + 61 + public function getActionName() { 62 + $old = $this->getOldValue(); 63 + $new = $this->getNewValue(); 64 + 65 + switch ($this->getTransactionType()) { 66 + case self::TYPE_TITLE: 67 + if ($old === null) { 68 + return pht('Created'); 69 + } 70 + 71 + return pht('Retitled'); 72 + 73 + case self::TYPE_CONTENT: 74 + return pht('Edited'); 75 + 76 + } 77 + 78 + return parent::getActionName(); 79 + } 80 + 81 + public function getIcon() { 82 + $old = $this->getOldValue(); 83 + $new = $this->getNewValue(); 84 + 85 + switch ($this->getTransactionType()) { 86 + case self::TYPE_TITLE: 87 + case self::TYPE_CONTENT: 88 + return 'fa-pencil'; 89 + } 90 + 91 + return parent::getIcon(); 92 + } 93 + 94 + 95 + 96 + public function getTitle() { 97 + $author_phid = $this->getAuthorPHID(); 98 + 99 + $old = $this->getOldValue(); 100 + $new = $this->getNewValue(); 101 + 102 + switch ($this->getTransactionType()) { 103 + case self::TYPE_TITLE: 104 + if ($old === null) { 105 + return pht( 106 + '%s created this document.', 107 + $this->renderHandleLink($author_phid)); 108 + } 109 + return pht( 110 + '%s changed the title from "%s" to "%s".', 111 + $this->renderHandleLink($author_phid), 112 + $old, 113 + $new); 114 + 115 + case self::TYPE_CONTENT: 116 + return pht( 117 + '%s edited the document content.', 118 + $this->renderHandleLink($author_phid)); 119 + 120 + } 121 + 122 + return parent::getTitle(); 123 + } 124 + 125 + public function getTitleForFeed(PhabricatorFeedStory $story) { 126 + $author_phid = $this->getAuthorPHID(); 127 + $object_phid = $this->getObjectPHID(); 128 + 129 + $old = $this->getOldValue(); 130 + $new = $this->getNewValue(); 131 + 132 + switch ($this->getTransactionType()) { 133 + case self::TYPE_TITLE: 134 + if ($old === null) { 135 + return pht( 136 + '%s created %s.', 137 + $this->renderHandleLink($author_phid), 138 + $this->renderHandleLink($object_phid)); 139 + } 140 + 141 + return pht( 142 + '%s renamed %s from "%s" to "%s".', 143 + $this->renderHandleLink($author_phid), 144 + $this->renderHandleLink($object_phid), 145 + $old, 146 + $new); 147 + 148 + case self::TYPE_CONTENT: 149 + return pht( 150 + '%s edited the content of %s.', 151 + $this->renderHandleLink($author_phid), 152 + $this->renderHandleLink($object_phid)); 153 + 154 + } 155 + return parent::getTitleForFeed($story); 156 + } 157 + 158 + public function hasChangeDetails() { 159 + switch ($this->getTransactionType()) { 160 + case self::TYPE_CONTENT: 161 + return true; 162 + } 163 + return parent::hasChangeDetails(); 164 + } 165 + 166 + public function renderChangeDetails(PhabricatorUser $viewer) { 167 + return $this->renderTextCorpusChangeDetails( 168 + $viewer, 169 + $this->getOldValue(), 170 + $this->getNewValue()); 171 + } 172 + 173 + public function getMailTags() { 174 + $tags = array(); 175 + switch ($this->getTransactionType()) { 176 + case self::TYPE_TITLE: 177 + $tags[] = self::MAILTAG_TITLE; 178 + break; 179 + case self::TYPE_CONTENT: 180 + $tags[] = self::MAILTAG_CONTENT; 181 + break; 182 + } 183 + return $tags; 184 + } 185 + 186 + }
+10
src/applications/phriction/storage/PhrictionTransactionComment.php
··· 1 + <?php 2 + 3 + final class PhrictionTransactionComment 4 + extends PhabricatorApplicationTransactionComment { 5 + 6 + public function getApplicationTransactionObject() { 7 + return new PhrictionTransaction(); 8 + } 9 + 10 + }