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

Conpherence - add per thread notification setting

Summary: Introduces a new settings panel for Conpherence specific settings.

Test Plan:
started a thread with a test user, thus two participants total. Replied to conpherence, toggling notification settings in between. Verified 1 or 2 emails were sent as appropos to the current toggle.

Toggled global setting and verified setting was updated in conpherences where nothing was specified. Verified setting conpherence setting overrides global setting.

Reviewers: epriestley, chad

Reviewed By: epriestley

CC: aran, Korvin

Maniphest Tasks: T2521

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

+284 -17
+2
resources/sql/patches/20130319.conpherence.sql
··· 1 + ALTER TABLE {$NAMESPACE}_conpherence.conpherence_participant 2 + ADD settings LONGTEXT NOT NULL COLLATE utf8_bin AFTER behindTransactionPHID;
+6 -3
src/__celerity_resource_map__.php
··· 840 840 ), 841 841 'conpherence-widget-pane-css' => 842 842 array( 843 - 'uri' => '/res/0e4a8ded/rsrc/css/application/conpherence/widget-pane.css', 843 + 'uri' => '/res/bd8ca250/rsrc/css/application/conpherence/widget-pane.css', 844 844 'type' => 'css', 845 845 'requires' => 846 846 array( ··· 1206 1206 ), 1207 1207 'javelin-behavior-conpherence-pontificate' => 1208 1208 array( 1209 - 'uri' => '/res/15263692/rsrc/js/application/conpherence/behavior-pontificate.js', 1209 + 'uri' => '/res/fe634761/rsrc/js/application/conpherence/behavior-pontificate.js', 1210 1210 'type' => 'js', 1211 1211 'requires' => 1212 1212 array( ··· 1219 1219 ), 1220 1220 'javelin-behavior-conpherence-widget-pane' => 1221 1221 array( 1222 - 'uri' => '/res/43a0fe1b/rsrc/js/application/conpherence/behavior-widget-pane.js', 1222 + 'uri' => '/res/52b80633/rsrc/js/application/conpherence/behavior-widget-pane.js', 1223 1223 'type' => 'js', 1224 1224 'requires' => 1225 1225 array( 1226 1226 0 => 'javelin-behavior', 1227 1227 1 => 'javelin-dom', 1228 1228 2 => 'javelin-stratcom', 1229 + 3 => 'javelin-workflow', 1230 + 4 => 'javelin-util', 1231 + 5 => 'phabricator-notification', 1229 1232 ), 1230 1233 'disk' => '/rsrc/js/application/conpherence/behavior-widget-pane.js', 1231 1234 ),
+4
src/__phutil_library_map__.php
··· 240 240 'ConpherencePeopleMenuEventListener' => 'applications/conpherence/events/ConpherencePeopleMenuEventListener.php', 241 241 'ConpherencePontificateControl' => 'applications/conpherence/view/ConpherencePontificateControl.php', 242 242 'ConpherenceReplyHandler' => 'applications/conpherence/mail/ConpherenceReplyHandler.php', 243 + 'ConpherenceSettings' => 'applications/conpherence/constants/ConpherenceSettings.php', 243 244 'ConpherenceThread' => 'applications/conpherence/storage/ConpherenceThread.php', 244 245 'ConpherenceThreadQuery' => 'applications/conpherence/query/ConpherenceThreadQuery.php', 245 246 'ConpherenceTransaction' => 'applications/conpherence/storage/ConpherenceTransaction.php', ··· 1301 1302 'PhabricatorSettingsPanel' => 'applications/settings/panel/PhabricatorSettingsPanel.php', 1302 1303 'PhabricatorSettingsPanelAccount' => 'applications/settings/panel/PhabricatorSettingsPanelAccount.php', 1303 1304 'PhabricatorSettingsPanelConduit' => 'applications/settings/panel/PhabricatorSettingsPanelConduit.php', 1305 + 'PhabricatorSettingsPanelConpherencePreferences' => 'applications/settings/panel/PhabricatorSettingsPanelConpherencePreferences.php', 1304 1306 'PhabricatorSettingsPanelDiffPreferences' => 'applications/settings/panel/PhabricatorSettingsPanelDiffPreferences.php', 1305 1307 'PhabricatorSettingsPanelDisplayPreferences' => 'applications/settings/panel/PhabricatorSettingsPanelDisplayPreferences.php', 1306 1308 'PhabricatorSettingsPanelEmailAddresses' => 'applications/settings/panel/PhabricatorSettingsPanelEmailAddresses.php', ··· 1907 1909 'ConpherencePeopleMenuEventListener' => 'PhutilEventListener', 1908 1910 'ConpherencePontificateControl' => 'AphrontFormControl', 1909 1911 'ConpherenceReplyHandler' => 'PhabricatorMailReplyHandler', 1912 + 'ConpherenceSettings' => 'ConpherenceConstants', 1910 1913 'ConpherenceThread' => 1911 1914 array( 1912 1915 0 => 'ConpherenceDAO', ··· 2907 2910 'PhabricatorSettingsMainController' => 'PhabricatorController', 2908 2911 'PhabricatorSettingsPanelAccount' => 'PhabricatorSettingsPanel', 2909 2912 'PhabricatorSettingsPanelConduit' => 'PhabricatorSettingsPanel', 2913 + 'PhabricatorSettingsPanelConpherencePreferences' => 'PhabricatorSettingsPanel', 2910 2914 'PhabricatorSettingsPanelDiffPreferences' => 'PhabricatorSettingsPanel', 2911 2915 'PhabricatorSettingsPanelDisplayPreferences' => 'PhabricatorSettingsPanel', 2912 2916 'PhabricatorSettingsPanelEmailAddresses' => 'PhabricatorSettingsPanel',
+22
src/applications/conpherence/constants/ConpherenceSettings.php
··· 1 + <?php 2 + 3 + final class ConpherenceSettings extends ConpherenceConstants { 4 + 5 + const EMAIL_ALWAYS = 0; 6 + const NOTIFICATIONS_ONLY = 1; 7 + 8 + public static function getHumanString($constant) { 9 + $string = pht('Unknown setting.'); 10 + 11 + switch ($constant) { 12 + case self::EMAIL_ALWAYS: 13 + $string = pht('Email me every update.'); 14 + break; 15 + case self::NOTIFICATIONS_ONLY: 16 + $string = pht('Notifications only.'); 17 + break; 18 + } 19 + 20 + return $string; 21 + } 22 + }
+11
src/applications/conpherence/controller/ConpherenceUpdateController.php
··· 60 60 $conpherence, 61 61 $message); 62 62 break; 63 + case 'notifications': 64 + $notifications = $request->getStr('notifications'); 65 + $participant = $conpherence->getParticipant($user->getPHID()); 66 + $participant->setSettings(array('notifications' => $notifications)); 67 + $participant->save(); 68 + $result = pht( 69 + 'Updated notification settings to "%s".', 70 + ConpherenceSettings::getHumanString($notifications)); 71 + return id(new AphrontAjaxResponse()) 72 + ->setContent($result); 73 + break; 63 74 case 'metadata': 64 75 $xactions = array(); 65 76 $top = $request->getInt('image_y');
+69 -2
src/applications/conpherence/controller/ConpherenceWidgetController.php
··· 8 8 9 9 private $conpherenceID; 10 10 private $conpherence; 11 + private $userPreferences; 12 + 13 + public function setUserPreferences(PhabricatorUserPreferences $pref) { 14 + $this->userPreferences = $pref; 15 + return $this; 16 + } 17 + public function getUserPreferences() { 18 + return $this->userPreferences; 19 + } 11 20 12 21 public function setConpherence(ConpherenceThread $conpherence) { 13 22 $this->conpherence = $conpherence; ··· 44 53 ->executeOne(); 45 54 $this->setConpherence($conpherence); 46 55 56 + $this->setUserPreferences($user->loadPreferences()); 57 + 47 58 $widgets = $this->renderWidgetPaneContent(); 48 59 $content = $widgets; 49 60 return id(new AphrontAjaxResponse())->setContent($content); ··· 57 68 Javelin::initBehavior( 58 69 'conpherence-widget-pane', 59 70 array( 60 - 'form_pane' => 'conpherence-form', 61 71 'file_widget' => 'widgets-files', 72 + 'settings_widget' => 'widgets-settings', 62 73 'widgetRegistery' => array( 63 74 'widgets-conpherence-list' => $cant_toggle, 64 75 'widgets-conversation' => $cant_toggle, ··· 201 212 } 202 213 203 214 private function renderSettingsWidgetPaneContent() { 204 - return 'TODO - settings'; 215 + $user = $this->getRequest()->getUser(); 216 + $conpherence = $this->getConpherence(); 217 + $participants = $conpherence->getParticipants(); 218 + $participant = $participants[$user->getPHID()]; 219 + $default = ConpherenceSettings::EMAIL_ALWAYS; 220 + $preference = $this->getUserPreferences(); 221 + if ($preference) { 222 + $default = $preference->getPreference( 223 + PhabricatorUserPreferences::PREFERENCE_CONPH_NOTIFICATIONS, 224 + ConpherenceSettings::EMAIL_ALWAYS); 225 + } 226 + $settings = $participant->getSettings(); 227 + $notifications = idx( 228 + $settings, 229 + 'notifications', 230 + $default); 231 + $options = id(new AphrontFormRadioButtonControl()) 232 + ->addButton( 233 + ConpherenceSettings::EMAIL_ALWAYS, 234 + ConpherenceSettings::getHumanString( 235 + ConpherenceSettings::EMAIL_ALWAYS), 236 + '') 237 + ->addButton( 238 + ConpherenceSettings::NOTIFICATIONS_ONLY, 239 + ConpherenceSettings::getHumanString( 240 + ConpherenceSettings::NOTIFICATIONS_ONLY), 241 + '') 242 + ->setName('notifications') 243 + ->setValue($notifications); 244 + 245 + $href = $this->getApplicationURI( 246 + 'update/'.$conpherence->getID().'/'); 247 + $layout = array( 248 + $options, 249 + phutil_tag( 250 + 'input', 251 + array( 252 + 'type' => 'hidden', 253 + 'name' => 'action', 254 + 'value' => 'notifications' 255 + )), 256 + javelin_tag( 257 + 'button', 258 + array( 259 + 'sigil' => 'notifications-update', 260 + 'class' => 'notifications-update grey', 261 + ), 262 + pht('Update Notifications')) 263 + ); 264 + 265 + return phabricator_form( 266 + $user, 267 + array( 268 + 'method' => 'POST', 269 + 'action' => $href, 270 + ), 271 + $layout); 205 272 } 206 273 207 274 private function renderCalendarWidgetPaneContent() {
+27 -3
src/applications/conpherence/editor/ConpherenceEditor.php
··· 159 159 } 160 160 break; 161 161 case ConpherenceTransactionType::TYPE_PARTICIPANTS: 162 + $participants = array(); 162 163 foreach ($xaction->getNewValue() as $participant) { 163 164 if ($participant == $this->getActor()->getPHID()) { 164 165 $status = ConpherenceParticipationStatus::UP_TO_DATE; 165 166 } else { 166 167 $status = ConpherenceParticipationStatus::BEHIND; 167 168 } 168 - id(new ConpherenceParticipant()) 169 + $participants[] = 170 + id(new ConpherenceParticipant()) 169 171 ->setConpherencePHID($object->getPHID()) 170 172 ->setParticipantPHID($participant) 171 173 ->setParticipationStatus($status) ··· 173 175 ->setBehindTransactionPHID($xaction->getPHID()) 174 176 ->save(); 175 177 } 178 + $participants = mpull($participants, null, 'getParticipantPHID'); 179 + $object->attachParticipants($participants); 176 180 break; 177 181 } 178 182 } ··· 221 225 222 226 protected function getMailTo(PhabricatorLiskDAO $object) { 223 227 $participants = $object->getParticipants(); 224 - return array_keys($participants); 228 + $preferences = id(new PhabricatorUserPreferences()) 229 + ->loadAllWhere('userPHID in (%Ls)', array_keys($participants)); 230 + $preferences = mpull($preferences, null, 'getUserPHID'); 231 + $to_phids = array(); 232 + foreach ($participants as $phid => $participant) { 233 + $default = ConpherenceSettings::EMAIL_ALWAYS; 234 + $preference = idx($preferences, $phid); 235 + if ($preference) { 236 + $default = $preference->getPreference( 237 + PhabricatorUserPreferences::PREFERENCE_CONPH_NOTIFICATIONS, 238 + ConpherenceSettings::EMAIL_ALWAYS); 239 + } 240 + $settings = $participant->getSettings(); 241 + $notifications = idx( 242 + $settings, 243 + 'notifications', 244 + $default); 245 + if ($notifications == ConpherenceSettings::EMAIL_ALWAYS) { 246 + $to_phids[] = $phid; 247 + } 248 + } 249 + return $to_phids; 225 250 } 226 251 227 252 protected function getMailCC(PhabricatorLiskDAO $object) { ··· 251 276 protected function supportsSearch() { 252 277 return false; 253 278 } 254 - 255 279 }
+13
src/applications/conpherence/storage/ConpherenceParticipant.php
··· 10 10 protected $participationStatus; 11 11 protected $behindTransactionPHID; 12 12 protected $dateTouched; 13 + protected $settings = array(); 14 + 15 + public function getConfiguration() { 16 + return array( 17 + self::CONFIG_SERIALIZATION => array( 18 + 'settings' => self::SERIALIZATION_JSON, 19 + ), 20 + ) + parent::getConfiguration(); 21 + } 22 + 23 + public function getSettings() { 24 + return nonempty($this->settings, array()); 25 + } 13 26 14 27 public function markUpToDate(ConpherenceTransaction $xaction) { 15 28 if (!$this->isUpToDate()) {
+84
src/applications/settings/panel/PhabricatorSettingsPanelConpherencePreferences.php
··· 1 + <?php 2 + 3 + final class PhabricatorSettingsPanelConpherencePreferences 4 + extends PhabricatorSettingsPanel { 5 + 6 + public function isEnabled() { 7 + // TODO - epriestley - resolve isBeta and isInstalled for 8 + // PhabricatorApplication 9 + $app = PhabricatorApplication::getByClass( 10 + 'PhabricatorApplicationConpherence'); 11 + $is_prod = !$app->isBeta(); 12 + $allow_beta = 13 + PhabricatorEnv::getEnvConfig('phabricator.show-beta-applications'); 14 + return ($is_prod || $allow_beta) && $app->isInstalled(); 15 + } 16 + 17 + public function getPanelKey() { 18 + return 'conpherence'; 19 + } 20 + 21 + public function getPanelName() { 22 + return pht('Conpherence Preferences'); 23 + } 24 + 25 + public function getPanelGroup() { 26 + return pht('Application Settings'); 27 + } 28 + 29 + public function processRequest(AphrontRequest $request) { 30 + $user = $request->getUser(); 31 + $preferences = $user->loadPreferences(); 32 + 33 + $pref = PhabricatorUserPreferences::PREFERENCE_CONPH_NOTIFICATIONS; 34 + 35 + if ($request->isFormPost()) { 36 + $notifications = $request->getInt($pref); 37 + $preferences->setPreference($pref, $notifications); 38 + $preferences->save(); 39 + return id(new AphrontRedirectResponse()) 40 + ->setURI($this->getPanelURI('?saved=true')); 41 + } 42 + 43 + $form = id(new AphrontFormView()) 44 + ->setUser($user) 45 + ->appendChild( 46 + id(new AphrontFormSelectControl()) 47 + ->setLabel(pht('Conpherence Notifications')) 48 + ->setName($pref) 49 + ->setValue($preferences->getPreference($pref)) 50 + ->setOptions( 51 + array( 52 + ConpherenceSettings::EMAIL_ALWAYS 53 + => pht('Email Always'), 54 + ConpherenceSettings::NOTIFICATIONS_ONLY 55 + => pht('Notifications Only'), 56 + )) 57 + ->setCaption( 58 + pht('Should Conpherence send emails for updates or '. 59 + 'notifications only? This global setting can be overridden '. 60 + 'on a per-thread basis within Conpherence.'))) 61 + ->appendChild( 62 + id(new AphrontFormSubmitControl()) 63 + ->setValue(pht('Save Preferences'))); 64 + 65 + $panel = new AphrontPanelView(); 66 + $panel->setHeader(pht('Conpherence Preferences')); 67 + $panel->appendChild($form); 68 + $panel->setNoBackground(); 69 + 70 + $error_view = null; 71 + if ($request->getBool('saved')) { 72 + $error_view = id(new AphrontErrorView()) 73 + ->setTitle(pht('Preferences Saved')) 74 + ->setSeverity(AphrontErrorView::SEVERITY_NOTICE) 75 + ->setErrors(array(pht('Your preferences have been saved.'))); 76 + } 77 + 78 + return array( 79 + $error_view, 80 + $panel, 81 + ); 82 + } 83 + } 84 +
+2
src/applications/settings/storage/PhabricatorUserPreferences.php
··· 25 25 26 26 const PREFERENCE_DIFF_FILETREE = 'diff-filetree'; 27 27 28 + const PREFERENCE_CONPH_NOTIFICATIONS = 'conph-notifications'; 29 + 28 30 protected $userPHID; 29 31 protected $preferences = array(); 30 32
+5 -1
src/infrastructure/storage/patch/PhabricatorBuiltinPatchList.php
··· 1180 1180 '20130319.phabricatorfileexplicitupload.sql' => array( 1181 1181 'type' => 'sql', 1182 1182 'name' => $this->getPatchPath( 1183 - '20130319.phabricatorfileexplicitupload.sql'), 1183 + '20130319.phabricatorfileexplicitupload.sql') 1184 + ), 1185 + '20130319.conpherence.sql' => array( 1186 + 'type' => 'sql', 1187 + 'name' => $this->getPatchPath('20130319.conpherence.sql'), 1184 1188 ), 1185 1189 '20130320.phlux.sql' => array( 1186 1190 'type' => 'sql',
+10
webroot/rsrc/css/application/conpherence/widget-pane.css
··· 26 26 width: 100%; 27 27 } 28 28 29 + .conpherence-widget-pane .aphront-form-inset { 30 + border: 0; 31 + background: url('/rsrc/image/texture/dust_background.jpg'); 32 + } 33 + 29 34 .conpherence-widget-pane .widgets-header { 30 35 background-color: #d8dce2; 31 36 box-shadow: 0px 2px 2px rgba(0,0,0,0.15); ··· 186 191 .conpherence-widget-pane .phabricator-remarkup-embed-layout-link { 187 192 padding-bottom: 1px; 188 193 } 194 + 195 + /* settings widget */ 196 + .conpherence-widget-pane .notifications-update { 197 + margin: 2px 0px 0px 8px; 198 + }
-7
webroot/rsrc/js/application/conpherence/behavior-pontificate.js
··· 52 52 53 53 JX.DOM.listen( 54 54 root, 55 - ['submit', 'didSyntheticSubmit'], 56 - null, 57 - onsubmit 58 - ); 59 - 60 - JX.DOM.listen( 61 - root, 62 55 ['click'], 63 56 'conpherence-pontificate', 64 57 onsubmit
+29 -1
webroot/rsrc/js/application/conpherence/behavior-widget-pane.js
··· 1 1 /** 2 - * @provides javelin-behavior-conpherence-widget-pane 3 2 * @requires javelin-behavior 4 3 * javelin-dom 5 4 * javelin-stratcom 5 + * javelin-workflow 6 + * javelin-util 7 + * phabricator-notification 8 + * @provides javelin-behavior-conpherence-widget-pane 6 9 */ 7 10 8 11 JX.behavior('conpherence-widget-pane', function(config) { ··· 34 37 } 35 38 } 36 39 } 40 + ); 41 + 42 + var settingsRoot = JX.$(config.settings_widget); 43 + 44 + var onsubmitSettings = function (e) { 45 + e.kill(); 46 + var form = JX.DOM.find(settingsRoot, 'form'); 47 + var button = JX.DOM.find(form, 'button'); 48 + JX.Workflow.newFromForm(form) 49 + .setHandler(JX.bind(this, function (r) { 50 + new JX.Notification() 51 + .setDuration(6000) 52 + .setContent(r) 53 + .show(); 54 + button.disabled = ''; 55 + JX.DOM.alterClass(button, 'disabled', false); 56 + })) 57 + .start(); 58 + }; 59 + 60 + JX.DOM.listen( 61 + settingsRoot, 62 + ['click'], 63 + 'notifications-update', 64 + onsubmitSettings 37 65 ); 38 66 39 67 });