@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

Add mail/feed support to PhamePost

Summary: Allows feed stories and mail for new Phame Posts.

Test Plan: Write Post, Get Mail

Reviewers: epriestley

Reviewed By: epriestley

Subscribers: Korvin

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

+169 -14
+2
resources/sql/autopatches/20151106.phame.post.mailkey.1.sql
··· 1 + ALTER TABLE {$NAMESPACE}_phame.phame_post 2 + ADD mailKey binary(20) NOT NULL;
+18
resources/sql/autopatches/20151106.phame.post.mailkey.2.php
··· 1 + <?php 2 + 3 + $table = new PhamePost(); 4 + $conn_w = $table->establishConnection('w'); 5 + $iterator = new LiskMigrationIterator($table); 6 + foreach ($iterator as $post) { 7 + $id = $post->getID(); 8 + 9 + echo pht('Adding mail key for Post %d...', $id); 10 + echo "\n"; 11 + 12 + queryfx( 13 + $conn_w, 14 + 'UPDATE %T SET mailKey = %s WHERE id = %d', 15 + $table->getTableName(), 16 + Filesystem::readRandomCharacters(20), 17 + $id); 18 + }
+2
src/__phutil_library_map__.php
··· 3275 3275 'PhamePostPreviewController' => 'applications/phame/controller/post/PhamePostPreviewController.php', 3276 3276 'PhamePostPublishController' => 'applications/phame/controller/post/PhamePostPublishController.php', 3277 3277 'PhamePostQuery' => 'applications/phame/query/PhamePostQuery.php', 3278 + 'PhamePostReplyHandler' => 'applications/phame/mail/PhamePostReplyHandler.php', 3278 3279 'PhamePostSearchEngine' => 'applications/phame/query/PhamePostSearchEngine.php', 3279 3280 'PhamePostTransaction' => 'applications/phame/storage/PhamePostTransaction.php', 3280 3281 'PhamePostTransactionQuery' => 'applications/phame/query/PhamePostTransactionQuery.php', ··· 7544 7545 'PhamePostPreviewController' => 'PhamePostController', 7545 7546 'PhamePostPublishController' => 'PhamePostController', 7546 7547 'PhamePostQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 7548 + 'PhamePostReplyHandler' => 'PhabricatorApplicationTransactionReplyHandler', 7547 7549 'PhamePostSearchEngine' => 'PhabricatorApplicationSearchEngine', 7548 7550 'PhamePostTransaction' => 'PhabricatorApplicationTransaction', 7549 7551 'PhamePostTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
+1 -1
src/applications/phame/editor/PhameBlogEditor.php
··· 8 8 } 9 9 10 10 public function getEditorObjectsDescription() { 11 - return pht('Blogs'); 11 + return pht('Phame Blogs'); 12 12 } 13 13 14 14 public function getTransactionTypes() {
+64 -3
src/applications/phame/editor/PhamePostEditor.php
··· 8 8 } 9 9 10 10 public function getEditorObjectsDescription() { 11 - return pht('Blog Posts'); 11 + return pht('Phame Posts'); 12 12 } 13 13 14 14 public function getTransactionTypes() { ··· 149 149 protected function shouldSendMail( 150 150 PhabricatorLiskDAO $object, 151 151 array $xactions) { 152 - return false; 152 + if ($object->isDraft()) { 153 + return false; 154 + } 155 + return true; 153 156 } 154 157 155 158 protected function shouldPublishFeedStory( 156 159 PhabricatorLiskDAO $object, 157 160 array $xactions) { 158 - return false; 161 + if ($object->isDraft()) { 162 + return false; 163 + } 164 + return true; 165 + } 166 + 167 + protected function getMailTo(PhabricatorLiskDAO $object) { 168 + $phids = array(); 169 + $phids[] = $object->getBloggerPHID(); 170 + $phids[] = $this->requireActor()->getPHID(); 171 + 172 + $blog_phid = $object->getBlogPHID(); 173 + if ($blog_phid) { 174 + $phids[] = PhabricatorSubscribersQuery::loadSubscribersForPHID( 175 + $blog_phid); 176 + } 177 + return $phids; 178 + } 179 + 180 + protected function buildMailTemplate(PhabricatorLiskDAO $object) { 181 + $phid = $object->getPHID(); 182 + $title = $object->getTitle(); 183 + 184 + return id(new PhabricatorMetaMTAMail()) 185 + ->setSubject($title) 186 + ->addHeader('Thread-Topic', $phid); 187 + } 188 + 189 + protected function buildReplyHandler(PhabricatorLiskDAO $object) { 190 + return id(new PhamePostReplyHandler()) 191 + ->setMailReceiver($object); 192 + } 193 + 194 + protected function buildMailBody( 195 + PhabricatorLiskDAO $object, 196 + array $xactions) { 197 + 198 + $body = parent::buildMailBody($object, $xactions); 199 + 200 + $body->addLinkSection( 201 + pht('POST DETAIL'), 202 + PhabricatorEnv::getProductionURI($object->getViewURI())); 203 + 204 + return $body; 205 + } 206 + 207 + public function getMailTagsMap() { 208 + return array( 209 + PhamePostTransaction::MAILTAG_CONTENT => 210 + pht("A post's content changes."), 211 + PhamePostTransaction::MAILTAG_COMMENT => 212 + pht('Someone comments on a post.'), 213 + PhamePostTransaction::MAILTAG_OTHER => 214 + pht('Other post activity not listed above occurs.'), 215 + ); 216 + } 217 + 218 + protected function getMailSubjectPrefix() { 219 + return '[Phame]'; 159 220 } 160 221 161 222 protected function supportsSearch() {
+21
src/applications/phame/mail/PhamePostReplyHandler.php
··· 1 + <?php 2 + 3 + final class PhamePostReplyHandler 4 + extends PhabricatorApplicationTransactionReplyHandler { 5 + 6 + public function validateMailReceiver($mail_receiver) { 7 + if (!($mail_receiver instanceof PhamePost)) { 8 + throw new Exception( 9 + pht('Mail receiver is not a %s.', 'PhamePost')); 10 + } 11 + } 12 + 13 + public function getObjectPrefix() { 14 + return PhabricatorPhamePostPHIDType::TYPECONST; 15 + } 16 + 17 + protected function shouldCreateCommentFromMailBody() { 18 + return false; 19 + } 20 + 21 + }
+9
src/applications/phame/storage/PhamePost.php
··· 24 24 protected $configData; 25 25 protected $datePublished; 26 26 protected $blogPHID; 27 + protected $mailKey; 27 28 28 29 private $blog; 29 30 ··· 102 103 'title' => 'text255', 103 104 'phameTitle' => 'sort64', 104 105 'visibility' => 'uint32', 106 + 'mailKey' => 'bytes20', 105 107 106 108 // T6203/NULLABILITY 107 109 // These seem like they should always be non-null? ··· 133 135 ), 134 136 ), 135 137 ) + parent::getConfiguration(); 138 + } 139 + 140 + public function save() { 141 + if (!$this->getMailKey()) { 142 + $this->setMailKey(Filesystem::readRandomCharacters(20)); 143 + } 144 + return parent::save(); 136 145 } 137 146 138 147 public function generatePHID() {
+52 -10
src/applications/phame/storage/PhamePostTransaction.php
··· 3 3 final class PhamePostTransaction 4 4 extends PhabricatorApplicationTransaction { 5 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'; 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 + const MAILTAG_CONTENT = 'phame-post-content'; 12 + const MAILTAG_COMMENT = 'phame-post-comment'; 13 + const MAILTAG_OTHER = 'phame-post-other'; 10 14 11 15 public function getApplicationName() { 12 16 return 'phame'; ··· 57 61 return parent::getIcon(); 58 62 } 59 63 64 + public function getMailTags() { 65 + $tags = parent::getMailTags(); 66 + 67 + switch ($this->getTransactionType()) { 68 + case self::TYPE_COMMENTS_WIDGET: 69 + case PhabricatorTransactions::TYPE_COMMENT: 70 + $tags[] = self::MAILTAG_COMMENT; 71 + break; 72 + case self::TYPE_TITLE: 73 + case self::TYPE_PHAME_TITLE: 74 + case self::TYPE_BODY: 75 + $tags[] = self::MAILTAG_CONTENT; 76 + break; 77 + default: 78 + $tags[] = self::MAILTAG_OTHER; 79 + break; 80 + } 81 + return $tags; 82 + } 83 + 84 + 60 85 public function getTitle() { 61 86 $author_phid = $this->getAuthorPHID(); 62 87 $object_phid = $this->getObjectPHID(); ··· 69 94 case self::TYPE_TITLE: 70 95 if ($old === null) { 71 96 return pht( 72 - '%s created this post.', 97 + '%s authored this post.', 73 98 $this->renderHandleLink($author_phid)); 74 99 } else { 75 100 return pht( ··· 80 105 break; 81 106 case self::TYPE_BODY: 82 107 return pht( 83 - '%s updated the post\'s body.', 108 + '%s updated the blog post.', 84 109 $this->renderHandleLink($author_phid)); 85 110 break; 86 111 case self::TYPE_PHAME_TITLE: 87 112 return pht( 88 - '%s updated the post\'s phame title to "%s".', 113 + '%s updated the post\'s Phame title to "%s".', 89 114 $this->renderHandleLink($author_phid), 90 115 rtrim($new, '/')); 91 116 break; ··· 112 137 case self::TYPE_TITLE: 113 138 if ($old === null) { 114 139 return pht( 115 - '%s created %s.', 140 + '%s authored %s.', 116 141 $this->renderHandleLink($author_phid), 117 142 $this->renderHandleLink($object_phid)); 118 143 } else { ··· 124 149 break; 125 150 case self::TYPE_BODY: 126 151 return pht( 127 - '%s updated the body for %s.', 152 + '%s updated the blog post %s.', 128 153 $this->renderHandleLink($author_phid), 129 154 $this->renderHandleLink($object_phid)); 130 155 break; 131 156 case self::TYPE_PHAME_TITLE: 132 157 return pht( 133 - '%s updated the phame title for %s.', 158 + '%s updated the Phame title for %s.', 134 159 $this->renderHandleLink($author_phid), 135 160 $this->renderHandleLink($object_phid)); 136 161 break; ··· 143 168 } 144 169 145 170 return parent::getTitleForFeed(); 171 + } 172 + 173 + public function getBodyForFeed(PhabricatorFeedStory $story) { 174 + $new = $this->getNewValue(); 175 + 176 + $body = null; 177 + 178 + switch ($this->getTransactionType()) { 179 + case self::TYPE_TITLE: 180 + case self::TYPE_BODY: 181 + return phutil_escape_html_newlines( 182 + id(new PhutilUTF8StringTruncator()) 183 + ->setMaximumGlyphs(128) 184 + ->truncateString($new)); 185 + break; 186 + } 187 + return parent::getBodyForFeed($story); 146 188 } 147 189 148 190 public function getColor() {