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

Add mail/feed to Slowvote

Summary: Adds mailkeys, basic structure for publishing to feed, sending mail.

Test Plan: New Poll, vote, comment, etc.

Reviewers: epriestley

Reviewed By: epriestley

Subscribers: epriestley, Korvin

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

+250 -1
+2
resources/sql/autopatches/20150725.slowvote.mailkey.1.sql
··· 1 + ALTER TABLE {$NAMESPACE}_slowvote.slowvote_poll 2 + ADD mailKey binary(20) NOT NULL;
+18
resources/sql/autopatches/20150725.slowvote.mailkey.2.php
··· 1 + <?php 2 + 3 + $table = new PhabricatorSlowvotePoll(); 4 + $conn_w = $table->establishConnection('w'); 5 + $iterator = new LiskMigrationIterator($table); 6 + foreach ($iterator as $slowvote) { 7 + $id = $slowvote->getID(); 8 + 9 + echo pht('Adding mail key for Slowvote %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 + }
+4
src/__phutil_library_map__.php
··· 2792 2792 'PhabricatorSlowvoteEditController' => 'applications/slowvote/controller/PhabricatorSlowvoteEditController.php', 2793 2793 'PhabricatorSlowvoteEditor' => 'applications/slowvote/editor/PhabricatorSlowvoteEditor.php', 2794 2794 'PhabricatorSlowvoteListController' => 'applications/slowvote/controller/PhabricatorSlowvoteListController.php', 2795 + 'PhabricatorSlowvoteMailReceiver' => 'applications/slowvote/mail/PhabricatorSlowvoteMailReceiver.php', 2795 2796 'PhabricatorSlowvoteOption' => 'applications/slowvote/storage/PhabricatorSlowvoteOption.php', 2796 2797 'PhabricatorSlowvotePoll' => 'applications/slowvote/storage/PhabricatorSlowvotePoll.php', 2797 2798 'PhabricatorSlowvotePollController' => 'applications/slowvote/controller/PhabricatorSlowvotePollController.php', 2798 2799 'PhabricatorSlowvotePollPHIDType' => 'applications/slowvote/phid/PhabricatorSlowvotePollPHIDType.php', 2799 2800 'PhabricatorSlowvoteQuery' => 'applications/slowvote/query/PhabricatorSlowvoteQuery.php', 2801 + 'PhabricatorSlowvoteReplyHandler' => 'applications/slowvote/mail/PhabricatorSlowvoteReplyHandler.php', 2800 2802 'PhabricatorSlowvoteSchemaSpec' => 'applications/slowvote/storage/PhabricatorSlowvoteSchemaSpec.php', 2801 2803 'PhabricatorSlowvoteSearchEngine' => 'applications/slowvote/query/PhabricatorSlowvoteSearchEngine.php', 2802 2804 'PhabricatorSlowvoteTransaction' => 'applications/slowvote/storage/PhabricatorSlowvoteTransaction.php', ··· 6782 6784 'PhabricatorSlowvoteEditController' => 'PhabricatorSlowvoteController', 6783 6785 'PhabricatorSlowvoteEditor' => 'PhabricatorApplicationTransactionEditor', 6784 6786 'PhabricatorSlowvoteListController' => 'PhabricatorSlowvoteController', 6787 + 'PhabricatorSlowvoteMailReceiver' => 'PhabricatorObjectMailReceiver', 6785 6788 'PhabricatorSlowvoteOption' => 'PhabricatorSlowvoteDAO', 6786 6789 'PhabricatorSlowvotePoll' => array( 6787 6790 'PhabricatorSlowvoteDAO', ··· 6797 6800 'PhabricatorSlowvotePollController' => 'PhabricatorSlowvoteController', 6798 6801 'PhabricatorSlowvotePollPHIDType' => 'PhabricatorPHIDType', 6799 6802 'PhabricatorSlowvoteQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 6803 + 'PhabricatorSlowvoteReplyHandler' => 'PhabricatorApplicationTransactionReplyHandler', 6800 6804 'PhabricatorSlowvoteSchemaSpec' => 'PhabricatorConfigSchemaSpec', 6801 6805 'PhabricatorSlowvoteSearchEngine' => 'PhabricatorApplicationSearchEngine', 6802 6806 'PhabricatorSlowvoteTransaction' => 'PhabricatorApplicationTransaction',
+68 -1
src/applications/slowvote/editor/PhabricatorSlowvoteEditor.php
··· 8 8 } 9 9 10 10 public function getEditorObjectsDescription() { 11 - return pht('Slowvotes'); 11 + return pht('Slowvote'); 12 12 } 13 13 14 14 public function getTransactionTypes() { ··· 109 109 PhabricatorLiskDAO $object, 110 110 PhabricatorApplicationTransaction $xaction) { 111 111 return; 112 + } 113 + 114 + protected function shouldSendMail( 115 + PhabricatorLiskDAO $object, 116 + array $xactions) { 117 + return true; 118 + } 119 + 120 + public function getMailTagsMap() { 121 + return array( 122 + PhabricatorSlowvoteTransaction::MAILTAG_DETAILS => 123 + pht('Someone changes the poll details.'), 124 + PhabricatorSlowvoteTransaction::MAILTAG_RESPONSES => 125 + pht('Someone votes on a poll.'), 126 + PhabricatorSlowvoteTransaction::MAILTAG_OTHER => 127 + pht('Other poll activity not listed above occurs.'), 128 + ); 129 + } 130 + 131 + protected function buildMailTemplate(PhabricatorLiskDAO $object) { 132 + $monogram = $object->getMonogram(); 133 + $name = $object->getQuestion(); 134 + 135 + return id(new PhabricatorMetaMTAMail()) 136 + ->setSubject("{$monogram}: {$name}") 137 + ->addHeader('Thread-Topic', $monogram); 138 + } 139 + 140 + protected function buildMailBody( 141 + PhabricatorLiskDAO $object, 142 + array $xactions) { 143 + 144 + $body = parent::buildMailBody($object, $xactions); 145 + $description = $object->getDescription(); 146 + 147 + if (strlen($description)) { 148 + $body->addTextSection( 149 + pht('SLOWVOTE DESCRIPTION'), 150 + $object->getDescription()); 151 + } 152 + 153 + $body->addLinkSection( 154 + pht('SLOWVOTE DETAIL'), 155 + PhabricatorEnv::getProductionURI('/'.$object->getMonogram())); 156 + 157 + return $body; 158 + } 159 + 160 + protected function getMailTo(PhabricatorLiskDAO $object) { 161 + return array( 162 + $object->getAuthorPHID(), 163 + $this->requireActor()->getPHID(), 164 + ); 165 + } 166 + protected function getMailSubjectPrefix() { 167 + return '[Slowvote]'; 168 + } 169 + 170 + protected function buildReplyHandler(PhabricatorLiskDAO $object) { 171 + return id(new PhabricatorSlowvoteReplyHandler()) 172 + ->setMailReceiver($object); 173 + } 174 + 175 + protected function shouldPublishFeedStory( 176 + PhabricatorLiskDAO $object, 177 + array $xactions) { 178 + return true; 112 179 } 113 180 114 181 }
+28
src/applications/slowvote/mail/PhabricatorSlowvoteMailReceiver.php
··· 1 + <?php 2 + 3 + final class PhabricatorSlowvoteMailReceiver 4 + extends PhabricatorObjectMailReceiver { 5 + 6 + public function isEnabled() { 7 + return PhabricatorApplication::isClassInstalled( 8 + 'PhabricatorSlowvoteApplication'); 9 + } 10 + 11 + protected function getObjectPattern() { 12 + return 'V[1-9]\d*'; 13 + } 14 + 15 + protected function loadObject($pattern, PhabricatorUser $viewer) { 16 + $id = (int)substr($pattern, 4); 17 + 18 + return id(new PhabricatorSlowvoteQuery()) 19 + ->setViewer($viewer) 20 + ->withIDs(array($id)) 21 + ->executeOne(); 22 + } 23 + 24 + protected function getTransactionReplyHandler() { 25 + return new PhabricatorSlowvoteReplyHandler(); 26 + } 27 + 28 + }
+16
src/applications/slowvote/mail/PhabricatorSlowvoteReplyHandler.php
··· 1 + <?php 2 + 3 + final class PhabricatorSlowvoteReplyHandler 4 + extends PhabricatorApplicationTransactionReplyHandler { 5 + 6 + public function validateMailReceiver($mail_receiver) { 7 + if (!($mail_receiver instanceof PhabricatorSlowvotePoll)) { 8 + throw new Exception(pht('Mail receiver is not a %s!', 'Slowvote')); 9 + } 10 + } 11 + 12 + public function getObjectPrefix() { 13 + return 'V'; 14 + } 15 + 16 + }
+13
src/applications/slowvote/storage/PhabricatorSlowvotePoll.php
··· 24 24 protected $responseVisibility; 25 25 protected $shuffle; 26 26 protected $method; 27 + protected $mailKey; 27 28 protected $viewPolicy; 28 29 protected $isClosed = 0; 29 30 protected $spacePHID; ··· 57 58 'method' => 'uint32', 58 59 'description' => 'text', 59 60 'isClosed' => 'bool', 61 + 'mailKey' => 'bytes20', 60 62 ), 61 63 self::CONFIG_KEY_SCHEMA => array( 62 64 'key_phid' => null, ··· 104 106 assert_instances_of($choices, 'PhabricatorSlowvoteChoice'); 105 107 $this->viewerChoices[$viewer->getPHID()] = $choices; 106 108 return $this; 109 + } 110 + 111 + public function getMonogram() { 112 + return 'V'.$this->getID(); 113 + } 114 + 115 + public function save() { 116 + if (!$this->getMailKey()) { 117 + $this->setMailKey(Filesystem::readRandomCharacters(20)); 118 + } 119 + return parent::save(); 107 120 } 108 121 109 122
+101
src/applications/slowvote/storage/PhabricatorSlowvoteTransaction.php
··· 9 9 const TYPE_SHUFFLE = 'vote:shuffle'; 10 10 const TYPE_CLOSE = 'vote:close'; 11 11 12 + const MAILTAG_DETAILS = 'vote:details'; 13 + const MAILTAG_RESPONSES = 'vote:responses'; 14 + const MAILTAG_OTHER = 'vote:vote'; 15 + 12 16 public function getApplicationName() { 13 17 return 'slowvote'; 14 18 } ··· 93 97 return parent::getTitle(); 94 98 } 95 99 100 + public function getTitleForFeed() { 101 + $author_phid = $this->getAuthorPHID(); 102 + $object_phid = $this->getObjectPHID(); 103 + 104 + $old = $this->getOldValue(); 105 + $new = $this->getNewValue(); 106 + 107 + $type = $this->getTransactionType(); 108 + switch ($type) { 109 + case self::TYPE_QUESTION: 110 + if ($old === null) { 111 + return pht( 112 + '%s created %s.', 113 + $this->renderHandleLink($author_phid), 114 + $this->renderHandleLink($object_phid)); 115 + 116 + } else { 117 + return pht( 118 + '%s renamed %s.', 119 + $this->renderHandleLink($author_phid), 120 + $this->renderHandleLink($object_phid)); 121 + } 122 + break; 123 + case self::TYPE_DESCRIPTION: 124 + if ($old === null) { 125 + return pht( 126 + '%s set the description of %s.', 127 + $this->renderHandleLink($author_phid), 128 + $this->renderHandleLink($object_phid)); 129 + 130 + } else { 131 + return pht( 132 + '%s edited the description of %s.', 133 + $this->renderHandleLink($author_phid), 134 + $this->renderHandleLink($object_phid)); 135 + } 136 + break; 137 + case self::TYPE_RESPONSES: 138 + // TODO: This could be more detailed 139 + return pht( 140 + '%s changed who can see the responses of %s.', 141 + $this->renderHandleLink($author_phid), 142 + $this->renderHandleLink($object_phid)); 143 + 144 + case self::TYPE_SHUFFLE: 145 + if ($new) { 146 + return pht( 147 + '%s made %s responses appear in a random order.', 148 + $this->renderHandleLink($author_phid), 149 + $this->renderHandleLink($object_phid)); 150 + 151 + } else { 152 + return pht( 153 + '%s made %s responses appear in a fixed order.', 154 + $this->renderHandleLink($author_phid), 155 + $this->renderHandleLink($object_phid)); 156 + } 157 + case self::TYPE_CLOSE: 158 + if ($new) { 159 + return pht( 160 + '%s closed %s.', 161 + $this->renderHandleLink($author_phid), 162 + $this->renderHandleLink($object_phid)); 163 + 164 + } else { 165 + return pht( 166 + '%s reopened %s.', 167 + $this->renderHandleLink($author_phid), 168 + $this->renderHandleLink($object_phid)); 169 + } 170 + break; 171 + } 172 + 173 + return parent::getTitleForFeed(); 174 + } 175 + 96 176 public function getIcon() { 97 177 $old = $this->getOldValue(); 98 178 $new = $this->getNewValue(); ··· 150 230 $viewer, 151 231 $this->getOldValue(), 152 232 $this->getNewValue()); 233 + } 234 + 235 + public function getMailTags() { 236 + $tags = parent::getMailTags(); 237 + 238 + switch ($this->getTransactionType()) { 239 + case self::TYPE_QUESTION: 240 + case self::TYPE_DESCRIPTION: 241 + case self::TYPE_SHUFFLE: 242 + case self::TYPE_CLOSE: 243 + $tags[] = self::MAILTAG_DETAILS; 244 + break; 245 + case self::TYPE_RESPONSES: 246 + $tags[] = self::MAILTAG_RESPONSES; 247 + break; 248 + default: 249 + $tags[] = self::MAILTAG_OTHER; 250 + break; 251 + } 252 + 253 + return $tags; 153 254 } 154 255 155 256