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

Phame - move over post creation and edit to use an editor

Summary: This adds the bare minimum transaction set for editing posts. Fixes T7626 because now files will be correctly attached to phame posts on subsequent edits. Future work here should be adding transaction types like `TYPE_BLOG` for when posts are moved between blogs, `TYPE_VISIBILITY` for when posts are moved to published, etc. Nothing too tricky there but keeping this diff relatively small seems prudent.

Test Plan: made posts successfully. also made errors like no title, no phame title, and duplicate phame title and got correct errors. added a file to a post and verified file has phame post in "attached" tab, which should fix T7626.

Reviewers: epriestley

Reviewed By: epriestley

Subscribers: Korvin, epriestley

Maniphest Tasks: T7626

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

+490 -94
+2 -2
resources/celerity/map.php
··· 122 122 'rsrc/css/layout/phabricator-source-code-view.css' => '2ceee894', 123 123 'rsrc/css/phui/calendar/phui-calendar-day.css' => '3b4a65d8', 124 124 'rsrc/css/phui/calendar/phui-calendar-list.css' => '840baa8d', 125 - 'rsrc/css/phui/calendar/phui-calendar-month.css' => '4fba442e', 125 + 'rsrc/css/phui/calendar/phui-calendar-month.css' => 'a6993b38', 126 126 'rsrc/css/phui/calendar/phui-calendar.css' => '8345be98', 127 127 'rsrc/css/phui/phui-action-header-view.css' => '89c497e7', 128 128 'rsrc/css/phui/phui-action-list.css' => '4f4d09f2', ··· 763 763 'phui-calendar-css' => '8345be98', 764 764 'phui-calendar-day-css' => '3b4a65d8', 765 765 'phui-calendar-list-css' => '840baa8d', 766 - 'phui-calendar-month-css' => '4fba442e', 766 + 'phui-calendar-month-css' => 'a6993b38', 767 767 'phui-crumbs-view-css' => '594d719e', 768 768 'phui-document-view-css' => '94d5dcd8', 769 769 'phui-feed-story-css' => 'c9f3a0b5',
+19
resources/sql/autopatches/20150515.phame.post.xaction.sql
··· 1 + CREATE TABLE {$NAMESPACE}_phame.phame_posttransaction ( 2 + id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, 3 + phid VARBINARY(64) NOT NULL, 4 + authorPHID VARBINARY(64) NOT NULL, 5 + objectPHID VARBINARY(64) NOT NULL, 6 + viewPolicy VARBINARY(64) NOT NULL, 7 + editPolicy VARBINARY(64) NOT NULL, 8 + commentPHID VARBINARY(64) DEFAULT NULL, 9 + commentVersion INT UNSIGNED NOT NULL, 10 + transactionType VARCHAR(32) COLLATE {$COLLATE_TEXT} NOT NULL, 11 + oldValue LONGTEXT COLLATE {$COLLATE_TEXT} NOT NULL, 12 + newValue LONGTEXT COLLATE {$COLLATE_TEXT} NOT NULL, 13 + contentSource LONGTEXT COLLATE {$COLLATE_TEXT} NOT NULL, 14 + metadata LONGTEXT COLLATE {$COLLATE_TEXT} 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 {$COLLATE_TEXT};
+7
src/__phutil_library_map__.php
··· 2791 2791 'PhamePost' => 'applications/phame/storage/PhamePost.php', 2792 2792 'PhamePostDeleteController' => 'applications/phame/controller/post/PhamePostDeleteController.php', 2793 2793 'PhamePostEditController' => 'applications/phame/controller/post/PhamePostEditController.php', 2794 + 'PhamePostEditor' => 'applications/phame/editor/PhamePostEditor.php', 2794 2795 'PhamePostFramedController' => 'applications/phame/controller/post/PhamePostFramedController.php', 2795 2796 'PhamePostListController' => 'applications/phame/controller/post/PhamePostListController.php', 2796 2797 'PhamePostNewController' => 'applications/phame/controller/post/PhamePostNewController.php', ··· 2798 2799 'PhamePostPreviewController' => 'applications/phame/controller/post/PhamePostPreviewController.php', 2799 2800 'PhamePostPublishController' => 'applications/phame/controller/post/PhamePostPublishController.php', 2800 2801 'PhamePostQuery' => 'applications/phame/query/PhamePostQuery.php', 2802 + 'PhamePostTransaction' => 'applications/phame/storage/PhamePostTransaction.php', 2803 + 'PhamePostTransactionQuery' => 'applications/phame/query/PhamePostTransactionQuery.php', 2801 2804 'PhamePostUnpublishController' => 'applications/phame/controller/post/PhamePostUnpublishController.php', 2802 2805 'PhamePostView' => 'applications/phame/view/PhamePostView.php', 2803 2806 'PhamePostViewController' => 'applications/phame/controller/post/PhamePostViewController.php', ··· 6269 6272 'PhameDAO', 6270 6273 'PhabricatorPolicyInterface', 6271 6274 'PhabricatorMarkupInterface', 6275 + 'PhabricatorApplicationTransactionInterface', 6272 6276 'PhabricatorTokenReceiverInterface', 6273 6277 ), 6274 6278 'PhamePostDeleteController' => 'PhameController', 6275 6279 'PhamePostEditController' => 'PhameController', 6280 + 'PhamePostEditor' => 'PhabricatorApplicationTransactionEditor', 6276 6281 'PhamePostFramedController' => 'PhameController', 6277 6282 'PhamePostListController' => 'PhameController', 6278 6283 'PhamePostNewController' => 'PhameController', ··· 6280 6285 'PhamePostPreviewController' => 'PhameController', 6281 6286 'PhamePostPublishController' => 'PhameController', 6282 6287 'PhamePostQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 6288 + 'PhamePostTransaction' => 'PhabricatorApplicationTransaction', 6289 + 'PhamePostTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 6283 6290 'PhamePostUnpublishController' => 'PhameController', 6284 6291 'PhamePostView' => 'AphrontView', 6285 6292 'PhamePostViewController' => 'PhameController',
+2 -9
src/applications/phame/controller/post/PhamePostDeleteController.php
··· 2 2 3 3 final class PhamePostDeleteController extends PhameController { 4 4 5 - private $id; 6 - 7 - public function willProcessRequest(array $data) { 8 - $this->id = $data['id']; 9 - } 10 - 11 - public function processRequest() { 12 - $request = $this->getRequest(); 5 + public function handleRequest(AphrontRequest $request) { 13 6 $user = $request->getUser(); 14 7 15 8 $post = id(new PhamePostQuery()) 16 9 ->setViewer($user) 17 - ->withIDs(array($this->id)) 10 + ->withIDs(array($request->getURIData('id'))) 18 11 ->requireCapabilities( 19 12 array( 20 13 PhabricatorPolicyCapability::CAN_EDIT,
+52 -50
src/applications/phame/controller/post/PhamePostEditController.php
··· 2 2 3 3 final class PhamePostEditController extends PhameController { 4 4 5 - private $id; 5 + public function handleRequest(AphrontRequest $request) { 6 + $user = $request->getUser(); 7 + $id = $request->getURIData('id'); 6 8 7 - public function willProcessRequest(array $data) { 8 - $this->id = idx($data, 'id'); 9 - } 10 - 11 - public function processRequest() { 12 - $request = $this->getRequest(); 13 - $user = $request->getUser(); 14 - 15 - if ($this->id) { 9 + if ($id) { 16 10 $post = id(new PhamePostQuery()) 17 11 ->setViewer($user) 18 - ->withIDs(array($this->id)) 12 + ->withIDs(array($id)) 19 13 ->requireCapabilities( 20 14 array( 21 15 PhabricatorPolicyCapability::CAN_EDIT, ··· 25 19 return new Aphront404Response(); 26 20 } 27 21 28 - $cancel_uri = $this->getApplicationURI('/post/view/'.$this->id.'/'); 22 + $cancel_uri = $this->getApplicationURI('/post/view/'.$id.'/'); 29 23 $submit_button = pht('Save Changes'); 30 24 $page_title = pht('Edit Post'); 31 25 } else { ··· 49 43 $page_title = pht('Create Post'); 50 44 } 51 45 52 - $e_phame_title = null; 46 + $title = $post->getTitle(); 47 + $phame_title = $post->getPhameTitle(); 48 + $body = $post->getBody(); 49 + $comments_widget = $post->getCommentsWidget(); 50 + 53 51 $e_title = true; 54 - $errors = array(); 55 - 52 + $e_phame_title = true; 53 + $validation_exception = null; 56 54 if ($request->isFormPost()) { 57 - $comments = $request->getStr('comments_widget'); 58 - $data = array('comments_widget' => $comments); 59 - $phame_title = $request->getStr('phame_title'); 60 - $phame_title = PhabricatorSlug::normalize($phame_title); 61 - $title = $request->getStr('title'); 62 - $post->setTitle($title); 63 - $post->setPhameTitle($phame_title); 64 - $post->setBody($request->getStr('body')); 65 - $post->setConfigData($data); 55 + $title = $request->getStr('title'); 56 + $phame_title = $request->getStr('phame_title'); 57 + $phame_title = PhabricatorSlug::normalize($phame_title); 58 + $body = $request->getStr('body'); 59 + $comments_widget = $request->getStr('comments_widget'); 66 60 67 - if ($phame_title == '/') { 68 - $errors[] = pht('Phame title must be nonempty.'); 69 - $e_phame_title = pht('Required'); 70 - } 61 + $xactions = array( 62 + id(new PhamePostTransaction()) 63 + ->setTransactionType(PhamePostTransaction::TYPE_TITLE) 64 + ->setNewValue($title), 65 + id(new PhamePostTransaction()) 66 + ->setTransactionType(PhamePostTransaction::TYPE_PHAME_TITLE) 67 + ->setNewValue($phame_title), 68 + id(new PhamePostTransaction()) 69 + ->setTransactionType(PhamePostTransaction::TYPE_BODY) 70 + ->setNewValue($body), 71 + id(new PhamePostTransaction()) 72 + ->setTransactionType(PhamePostTransaction::TYPE_COMMENTS_WIDGET) 73 + ->setNewValue($comments_widget), 74 + ); 71 75 72 - if (!strlen($title)) { 73 - $errors[] = pht('Title must be nonempty.'); 74 - $e_title = pht('Required'); 75 - } else { 76 - $e_title = null; 77 - } 76 + $editor = id(new PhamePostEditor()) 77 + ->setActor($user) 78 + ->setContentSourceFromRequest($request) 79 + ->setContinueOnNoEffect(true); 78 80 79 - if (!$errors) { 80 - try { 81 - $post->save(); 81 + try { 82 + $editor->applyTransactions($post, $xactions); 82 83 83 - $uri = $this->getApplicationURI('/post/view/'.$post->getID().'/'); 84 - return id(new AphrontRedirectResponse())->setURI($uri); 85 - } catch (AphrontDuplicateKeyQueryException $e) { 86 - $e_phame_title = pht('Not Unique'); 87 - $errors[] = pht('Another post already uses this slug. '. 88 - 'Each post must have a unique slug.'); 89 - } 84 + $uri = $this->getApplicationURI('/post/view/'.$post->getID().'/'); 85 + return id(new AphrontRedirectResponse())->setURI($uri); 86 + } catch (PhabricatorApplicationTransactionValidationException $ex) { 87 + $validation_exception = $ex; 88 + $e_title = $validation_exception->getShortMessage( 89 + PhamePostTransaction::TYPE_TITLE); 90 + $e_phame_title = $validation_exception->getShortMessage( 91 + PhamePostTransaction::TYPE_PHAME_TITLE); 90 92 } 91 93 } 92 94 ··· 106 108 id(new AphrontFormTextControl()) 107 109 ->setLabel(pht('Title')) 108 110 ->setName('title') 109 - ->setValue($post->getTitle()) 111 + ->setValue($title) 110 112 ->setID('post-title') 111 113 ->setError($e_title)) 112 114 ->appendChild( 113 115 id(new AphrontFormTextControl()) 114 116 ->setLabel(pht('Phame Title')) 115 117 ->setName('phame_title') 116 - ->setValue(rtrim($post->getPhameTitle(), '/')) 118 + ->setValue(rtrim($phame_title, '/')) 117 119 ->setID('post-phame-title') 118 120 ->setCaption(pht('Up to 64 alphanumeric characters '. 119 121 'with underscores for spaces. '. ··· 123 125 id(new PhabricatorRemarkupControl()) 124 126 ->setLabel(pht('Body')) 125 127 ->setName('body') 126 - ->setValue($post->getBody()) 128 + ->setValue($body) 127 129 ->setHeight(AphrontFormTextAreaControl::HEIGHT_VERY_TALL) 128 130 ->setID('post-body') 129 131 ->setUser($user) ··· 132 134 id(new AphrontFormSelectControl()) 133 135 ->setLabel(pht('Comments Widget')) 134 136 ->setName('comments_widget') 135 - ->setvalue($post->getCommentsWidget()) 137 + ->setvalue($comments_widget) 136 138 ->setOptions($post->getCommentsWidgetOptionsForSelect())) 137 139 ->appendChild( 138 140 id(new AphrontFormSubmitControl()) ··· 161 163 162 164 $form_box = id(new PHUIObjectBoxView()) 163 165 ->setHeaderText($page_title) 164 - ->setFormErrors($errors) 166 + ->setValidationException($validation_exception) 165 167 ->setForm($form); 166 168 167 169 $crumbs = $this->buildApplicationCrumbs(); 168 170 $crumbs->addTextCrumb( 169 171 $page_title, 170 - $this->getApplicationURI('/post/view/'.$this->id.'/')); 172 + $this->getApplicationURI('/post/view/'.$id.'/')); 171 173 172 174 $nav = $this->renderSideNavFilterView(null); 173 175 $nav->appendChild(
+4 -10
src/applications/phame/controller/post/PhamePostNewController.php
··· 2 2 3 3 final class PhamePostNewController extends PhameController { 4 4 5 - private $id; 6 - 7 - public function willProcessRequest(array $data) { 8 - $this->id = idx($data, 'id'); 9 - } 10 - 11 - public function processRequest() { 12 - $request = $this->getRequest(); 5 + public function handleRequest(AphrontRequest $request) { 13 6 $user = $request->getUser(); 7 + $id = $request->getURIData('id'); 14 8 15 9 $post = null; 16 10 $view_uri = null; 17 - if ($this->id) { 11 + if ($id) { 18 12 $post = id(new PhamePostQuery()) 19 13 ->setViewer($user) 20 - ->withIDs(array($this->id)) 14 + ->withIDs(array($id)) 21 15 ->requireCapabilities( 22 16 array( 23 17 PhabricatorPolicyCapability::CAN_EDIT,
+10 -14
src/applications/phame/controller/post/PhamePostViewController.php
··· 2 2 3 3 final class PhamePostViewController extends PhameController { 4 4 5 - private $id; 6 - 7 - public function willProcessRequest(array $data) { 8 - $this->id = $data['id']; 9 - } 10 - 11 - public function processRequest() { 12 - $request = $this->getRequest(); 5 + public function handleRequest(AphrontRequest $request) { 13 6 $user = $request->getUser(); 14 7 15 8 $post = id(new PhamePostQuery()) 16 9 ->setViewer($user) 17 - ->withIDs(array($this->id)) 10 + ->withIDs(array($request->getURIData('id'))) 18 11 ->executeOne(); 19 12 20 13 if (!$post) { ··· 65 58 $nav->appendChild( 66 59 array( 67 60 $object_box, 68 - )); 61 + $this->buildTransactionTimeline( 62 + $post, 63 + new PhamePostTransactionQuery()), 64 + )); 69 65 70 66 return $this->buildApplicationPage( 71 67 $nav, ··· 78 74 PhamePost $post, 79 75 PhabricatorUser $user) { 80 76 81 - $actions = id(new PhabricatorActionListView()) 82 - ->setObject($post) 83 - ->setObjectURI($this->getRequest()->getRequestURI()) 84 - ->setUser($user); 77 + $actions = id(new PhabricatorActionListView()) 78 + ->setObject($post) 79 + ->setObjectURI($this->getRequest()->getRequestURI()) 80 + ->setUser($user); 85 81 86 82 $can_edit = PhabricatorPolicyFilter::hasCapability( 87 83 $user,
-3
src/applications/phame/editor/PhameBlogEditor.php
··· 76 76 case PhabricatorTransactions::TYPE_JOIN_POLICY: 77 77 $object->setJoinPolicy($xaction->getNewValue()); 78 78 return; 79 - case PhabricatorTransactions::TYPE_COMMENT: 80 - return; 81 79 } 82 80 83 81 return parent::applyCustomInternalTransaction($object, $xaction); ··· 95 93 case PhabricatorTransactions::TYPE_VIEW_POLICY: 96 94 case PhabricatorTransactions::TYPE_EDIT_POLICY: 97 95 case PhabricatorTransactions::TYPE_JOIN_POLICY: 98 - case PhabricatorTransactions::TYPE_COMMENT: 99 96 return; 100 97 } 101 98
+165
src/applications/phame/editor/PhamePostEditor.php
··· 1 + <?php 2 + 3 + final class PhamePostEditor 4 + extends PhabricatorApplicationTransactionEditor { 5 + 6 + public function getEditorApplicationClass() { 7 + return 'PhabricatorPhameApplication'; 8 + } 9 + 10 + public function getEditorObjectsDescription() { 11 + return pht('Blog Posts'); 12 + } 13 + 14 + public function getTransactionTypes() { 15 + $types = parent::getTransactionTypes(); 16 + 17 + $types[] = PhamePostTransaction::TYPE_TITLE; 18 + $types[] = PhamePostTransaction::TYPE_PHAME_TITLE; 19 + $types[] = PhamePostTransaction::TYPE_BODY; 20 + $types[] = PhamePostTransaction::TYPE_COMMENTS_WIDGET; 21 + 22 + return $types; 23 + } 24 + 25 + protected function getCustomTransactionOldValue( 26 + PhabricatorLiskDAO $object, 27 + PhabricatorApplicationTransaction $xaction) { 28 + 29 + switch ($xaction->getTransactionType()) { 30 + case PhamePostTransaction::TYPE_TITLE: 31 + return $object->getTitle(); 32 + case PhamePostTransaction::TYPE_PHAME_TITLE: 33 + return $object->getPhameTitle(); 34 + case PhamePostTransaction::TYPE_BODY: 35 + return $object->getBody(); 36 + case PhamePostTransaction::TYPE_COMMENTS_WIDGET: 37 + return $object->getCommentsWidget(); 38 + } 39 + } 40 + 41 + protected function getCustomTransactionNewValue( 42 + PhabricatorLiskDAO $object, 43 + PhabricatorApplicationTransaction $xaction) { 44 + 45 + switch ($xaction->getTransactionType()) { 46 + case PhamePostTransaction::TYPE_TITLE: 47 + case PhamePostTransaction::TYPE_PHAME_TITLE: 48 + case PhamePostTransaction::TYPE_BODY: 49 + case PhamePostTransaction::TYPE_COMMENTS_WIDGET: 50 + return $xaction->getNewValue(); 51 + } 52 + } 53 + 54 + protected function applyCustomInternalTransaction( 55 + PhabricatorLiskDAO $object, 56 + PhabricatorApplicationTransaction $xaction) { 57 + 58 + switch ($xaction->getTransactionType()) { 59 + case PhamePostTransaction::TYPE_TITLE: 60 + return $object->setTitle($xaction->getNewValue()); 61 + case PhamePostTransaction::TYPE_PHAME_TITLE: 62 + return $object->setPhameTitle($xaction->getNewValue()); 63 + case PhamePostTransaction::TYPE_BODY: 64 + return $object->setBody($xaction->getNewValue()); 65 + case PhamePostTransaction::TYPE_COMMENTS_WIDGET: 66 + return $object->setCommentsWidget($xaction->getNewValue()); 67 + } 68 + 69 + return parent::applyCustomInternalTransaction($object, $xaction); 70 + } 71 + 72 + protected function applyCustomExternalTransaction( 73 + PhabricatorLiskDAO $object, 74 + PhabricatorApplicationTransaction $xaction) { 75 + 76 + switch ($xaction->getTransactionType()) { 77 + case PhamePostTransaction::TYPE_TITLE: 78 + case PhamePostTransaction::TYPE_PHAME_TITLE: 79 + case PhamePostTransaction::TYPE_BODY: 80 + case PhamePostTransaction::TYPE_COMMENTS_WIDGET: 81 + return; 82 + } 83 + 84 + return parent::applyCustomExternalTransaction($object, $xaction); 85 + } 86 + 87 + protected function validateTransaction( 88 + PhabricatorLiskDAO $object, 89 + $type, 90 + array $xactions) { 91 + 92 + $errors = parent::validateTransaction($object, $type, $xactions); 93 + 94 + switch ($type) { 95 + case PhamePostTransaction::TYPE_TITLE: 96 + $missing = $this->validateIsEmptyTextField( 97 + $object->getTitle(), 98 + $xactions); 99 + 100 + if ($missing) { 101 + $error = new PhabricatorApplicationTransactionValidationError( 102 + $type, 103 + pht('Required'), 104 + pht('Title is required.'), 105 + nonempty(last($xactions), null)); 106 + 107 + $error->setIsMissingFieldError(true); 108 + $errors[] = $error; 109 + } 110 + break; 111 + case PhamePostTransaction::TYPE_PHAME_TITLE: 112 + $missing = $this->validateIsEmptyTextField( 113 + $object->getPhameTitle(), 114 + $xactions); 115 + $phame_title = last($xactions)->getNewValue(); 116 + 117 + if ($missing || $phame_title == '/') { 118 + $error = new PhabricatorApplicationTransactionValidationError( 119 + $type, 120 + pht('Required'), 121 + pht('Phame title is required.'), 122 + nonempty(last($xactions), null)); 123 + 124 + $error->setIsMissingFieldError(true); 125 + $errors[] = $error; 126 + } 127 + 128 + $duplicate_post = id(new PhamePostQuery()) 129 + ->setViewer(PhabricatorUser::getOmnipotentUser()) 130 + ->withPhameTitles(array($phame_title)) 131 + ->executeOne(); 132 + if ($duplicate_post && $duplicate_post->getID() != $object->getID()) { 133 + $error_text = pht( 134 + 'Phame title must be unique; another post already has this phame '. 135 + 'title.'); 136 + $error = new PhabricatorApplicationTransactionValidationError( 137 + $type, 138 + pht('Not Unique'), 139 + $error_text, 140 + nonempty(last($xactions), null)); 141 + $errors[] = $error; 142 + } 143 + 144 + break; 145 + } 146 + return $errors; 147 + } 148 + 149 + protected function shouldSendMail( 150 + PhabricatorLiskDAO $object, 151 + array $xactions) { 152 + return false; 153 + } 154 + 155 + protected function shouldPublishFeedStory( 156 + PhabricatorLiskDAO $object, 157 + array $xactions) { 158 + return false; 159 + } 160 + 161 + protected function supportsSearch() { 162 + return false; 163 + } 164 + 165 + }
+10
src/applications/phame/query/PhamePostTransactionQuery.php
··· 1 + <?php 2 + 3 + final class PhamePostTransactionQuery 4 + extends PhabricatorApplicationTransactionQuery { 5 + 6 + public function getTemplateApplicationTransaction() { 7 + return new PhamePostTransaction(); 8 + } 9 + 10 + }
+32 -6
src/applications/phame/storage/PhamePost.php
··· 4 4 implements 5 5 PhabricatorPolicyInterface, 6 6 PhabricatorMarkupInterface, 7 + PhabricatorApplicationTransactionInterface, 7 8 PhabricatorTokenReceiverInterface { 8 9 9 10 const MARKUP_FIELD_BODY = 'markup:body'; ··· 72 73 } 73 74 74 75 return $name; 76 + } 77 + 78 + public function setCommentsWidget($widget) { 79 + $config_data = $this->getConfigData(); 80 + $config_data['comments_widget'] = $widget; 81 + return $this; 75 82 } 76 83 77 84 public function getCommentsWidget() { ··· 181 188 ); 182 189 } 183 190 184 - 185 191 public function getPolicy($capability) { 186 192 // Draft posts are visible only to the author. Published posts are visible 187 193 // to whoever the blog is visible to. ··· 199 205 } 200 206 } 201 207 202 - 203 208 public function hasAutomaticCapability($capability, PhabricatorUser $user) { 204 209 // A blog post's author can always view it, and is the only user allowed 205 210 // to edit it. ··· 210 215 return ($user->getPHID() == $this->getBloggerPHID()); 211 216 } 212 217 } 213 - 214 218 215 219 public function describeAutomaticCapability($capability) { 216 220 return pht( ··· 226 230 return $this->getPHID().':'.$field.':'.$hash; 227 231 } 228 232 229 - 230 233 public function newMarkupEngine($field) { 231 234 return PhabricatorMarkupEngine::newPhameMarkupEngine(); 232 235 } 233 - 234 236 235 237 public function getMarkupText($field) { 236 238 switch ($field) { ··· 248 250 return $output; 249 251 } 250 252 251 - 252 253 public function shouldUseMarkupCache($field) { 253 254 return (bool)$this->getPHID(); 254 255 } 255 256 257 + 258 + /* -( PhabricatorApplicationTransactionInterface )------------------------- */ 259 + 260 + 261 + public function getApplicationTransactionEditor() { 262 + return new PhamePostEditor(); 263 + } 264 + 265 + public function getApplicationTransactionObject() { 266 + return $this; 267 + } 268 + 269 + public function getApplicationTransactionTemplate() { 270 + return new PhamePostTransaction(); 271 + } 272 + 273 + public function willRenderTimeline( 274 + PhabricatorApplicationTransactionView $timeline, 275 + AphrontRequest $request) { 276 + 277 + return $timeline; 278 + } 279 + 280 + 256 281 /* -( PhabricatorTokenReceiverInterface )---------------------------------- */ 282 + 257 283 258 284 public function getUsersToNotifyOfTokenGiven() { 259 285 return array(
+187
src/applications/phame/storage/PhamePostTransaction.php
··· 1 + <?php 2 + 3 + final class PhamePostTransaction 4 + extends PhabricatorApplicationTransaction { 5 + 6 + const TYPE_TITLE = 'phame.post.title'; 7 + const TYPE_PHAME_TITLE = 'phame.post.phame.title'; 8 + const TYPE_BODY = 'phame.post.body'; 9 + const TYPE_COMMENTS_WIDGET = 'phame.post.comments.widget'; 10 + 11 + public function getApplicationName() { 12 + return 'phame'; 13 + } 14 + 15 + public function getApplicationTransactionType() { 16 + return PhabricatorPhamePostPHIDType::TYPECONST; 17 + } 18 + 19 + public function getRemarkupBlocks() { 20 + $blocks = parent::getRemarkupBlocks(); 21 + 22 + switch ($this->getTransactionType()) { 23 + case self::TYPE_BODY: 24 + $blocks[] = $this->getNewValue(); 25 + break; 26 + } 27 + 28 + return $blocks; 29 + } 30 + 31 + public function shouldHide() { 32 + $old = $this->getOldValue(); 33 + switch ($this->getTransactionType()) { 34 + case self::TYPE_PHAME_TITLE: 35 + case self::TYPE_BODY: 36 + return ($old === null); 37 + } 38 + return parent::shouldHide(); 39 + } 40 + 41 + public function getIcon() { 42 + $old = $this->getOldValue(); 43 + switch ($this->getTransactionType()) { 44 + case self::TYPE_TITLE: 45 + if ($old === null) { 46 + return 'fa-plus'; 47 + } else { 48 + return 'fa-pencil'; 49 + } 50 + break; 51 + case self::TYPE_PHAME_TITLE: 52 + case self::TYPE_BODY: 53 + case self::TYPE_COMMENTS_WIDGET: 54 + return 'fa-pencil'; 55 + break; 56 + } 57 + return parent::getIcon(); 58 + } 59 + 60 + public function getTitle() { 61 + $author_phid = $this->getAuthorPHID(); 62 + $object_phid = $this->getObjectPHID(); 63 + 64 + $old = $this->getOldValue(); 65 + $new = $this->getNewValue(); 66 + 67 + $type = $this->getTransactionType(); 68 + switch ($type) { 69 + case self::TYPE_TITLE: 70 + if ($old === null) { 71 + return pht( 72 + '%s created this post.', 73 + $this->renderHandleLink($author_phid)); 74 + } else { 75 + return pht( 76 + '%s updated the post\'s name to "%s".', 77 + $this->renderHandleLink($author_phid), 78 + $new); 79 + } 80 + break; 81 + case self::TYPE_BODY: 82 + return pht( 83 + '%s updated the post\'s body.', 84 + $this->renderHandleLink($author_phid)); 85 + break; 86 + case self::TYPE_PHAME_TITLE: 87 + return pht( 88 + '%s updated the post\'s phame title to "%s".', 89 + $this->renderHandleLink($author_phid), 90 + rtrim($new, '/')); 91 + break; 92 + case self::TYPE_COMMENTS_WIDGET: 93 + return pht( 94 + '%s updated the post\'s comment widget to "%s".', 95 + $this->renderHandleLink($author_phid), 96 + $new); 97 + break; 98 + } 99 + 100 + return parent::getTitle(); 101 + } 102 + 103 + public function getTitleForFeed() { 104 + $author_phid = $this->getAuthorPHID(); 105 + $object_phid = $this->getObjectPHID(); 106 + 107 + $old = $this->getOldValue(); 108 + $new = $this->getNewValue(); 109 + 110 + $type = $this->getTransactionType(); 111 + switch ($type) { 112 + case self::TYPE_TITLE: 113 + if ($old === null) { 114 + return pht( 115 + '%s created %s.', 116 + $this->renderHandleLink($author_phid), 117 + $this->renderHandleLink($object_phid)); 118 + } else { 119 + return pht( 120 + '%s updated the name for %s.', 121 + $this->renderHandleLink($author_phid), 122 + $this->renderHandleLink($object_phid)); 123 + } 124 + break; 125 + case self::TYPE_BODY: 126 + return pht( 127 + '%s updated the body for %s.', 128 + $this->renderHandleLink($author_phid), 129 + $this->renderHandleLink($object_phid)); 130 + break; 131 + case self::TYPE_PHAME_TITLE: 132 + return pht( 133 + '%s updated the phame title for %s.', 134 + $this->renderHandleLink($author_phid), 135 + $this->renderHandleLink($object_phid)); 136 + break; 137 + case self::TYPE_COMMENTS_WIDGET: 138 + return pht( 139 + '%s updated the comments widget for %s.', 140 + $this->renderHandleLink($author_phid), 141 + $this->renderHandleLink($object_phid)); 142 + break; 143 + } 144 + 145 + return parent::getTitleForFeed(); 146 + } 147 + 148 + public function getColor() { 149 + $old = $this->getOldValue(); 150 + 151 + switch ($this->getTransactionType()) { 152 + case self::TYPE_TITLE: 153 + if ($old === null) { 154 + return PhabricatorTransactions::COLOR_GREEN; 155 + } 156 + break; 157 + } 158 + 159 + return parent::getColor(); 160 + } 161 + 162 + 163 + public function hasChangeDetails() { 164 + switch ($this->getTransactionType()) { 165 + case self::TYPE_BODY: 166 + return ($this->getOldValue() !== null); 167 + } 168 + 169 + return parent::hasChangeDetails(); 170 + } 171 + 172 + public function renderChangeDetails(PhabricatorUser $viewer) { 173 + switch ($this->getTransactionType()) { 174 + case self::TYPE_BODY: 175 + $old = $this->getOldValue(); 176 + $new = $this->getNewValue(); 177 + 178 + return $this->renderTextCorpusChangeDetails( 179 + $viewer, 180 + $old, 181 + $new); 182 + } 183 + 184 + return parent::renderChangeDetails($viewer); 185 + } 186 + 187 + }