1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-11-09 16:32:39 +01:00

Add optional "Re:" prefix to all threaded mail and allow disabling mail about

your own actions

Summary:
  - Mail.app on Lion has cumbersome threading rules, see T782. Add an option to
stick "Re: " in front of all threaded mail so it behaves. This is horrible, but
apparently the least-horrible option.
  - While I was in there, I added an option for T228.

Test Plan:
  - Sent a bunch of threaded and unthreaded mail with varous "Re:" settings,
seemed to get "Re:" in the right places.
  - Disabled email about my stuff, created a task with just me, got voided mail,
added a CC, got mail to just the CC.

Reviewers: btrahan, jungejason

Reviewed By: btrahan

CC: aran, mkjones

Maniphest Tasks: T228, T782

Differential Revision: https://secure.phabricator.com/D1448
This commit is contained in:
epriestley 2012-01-17 20:32:28 -08:00
parent 0402e4e06e
commit ad36865e50
13 changed files with 346 additions and 108 deletions

View file

@ -294,6 +294,11 @@ return array(
// of any affected mail.
'metamta.precedence-bulk' => false,
// Mail.app on OS X Lion won't respect threading headers unless the subject
// is prefixed with "Re:". If you enable this option, Phabricator will add
// "Re:" to the subject line of all mail which is expected to thread.
'metamta.re-prefix' => false,
// -- Auth ------------------------------------------------------------------ //

View file

@ -711,6 +711,7 @@ phutil_register_library_map(array(
'PhabricatorUserAccountSettingsPanelController' => 'applications/people/controller/settings/panels/account',
'PhabricatorUserConduitSettingsPanelController' => 'applications/people/controller/settings/panels/conduit',
'PhabricatorUserDAO' => 'applications/people/storage/base',
'PhabricatorUserEmailPreferenceSettingsPanelController' => 'applications/people/controller/settings/panels/emailpref',
'PhabricatorUserEmailSettingsPanelController' => 'applications/people/controller/settings/panels/email',
'PhabricatorUserLog' => 'applications/people/storage/log',
'PhabricatorUserOAuthInfo' => 'applications/people/storage/useroauthinfo',
@ -1357,6 +1358,7 @@ phutil_register_library_map(array(
'PhabricatorUserAccountSettingsPanelController' => 'PhabricatorUserSettingsPanelController',
'PhabricatorUserConduitSettingsPanelController' => 'PhabricatorUserSettingsPanelController',
'PhabricatorUserDAO' => 'PhabricatorLiskDAO',
'PhabricatorUserEmailPreferenceSettingsPanelController' => 'PhabricatorUserSettingsPanelController',
'PhabricatorUserEmailSettingsPanelController' => 'PhabricatorUserSettingsPanelController',
'PhabricatorUserLog' => 'PhabricatorUserDAO',
'PhabricatorUserOAuthInfo' => 'PhabricatorUserDAO',

View file

@ -1,7 +1,7 @@
<?php
/*
* Copyright 2011 Facebook, Inc.
* Copyright 2012 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -90,9 +90,12 @@ Phabricator
EOBODY;
}
// NOTE: Don't set the user as 'from', or they may not receive the
// mail if they have the "don't send me email about my own actions"
// preference set.
$mail = new PhabricatorMetaMTAMail();
$mail->setSubject('[Phabricator] Password Reset');
$mail->setFrom($target_user->getPHID());
$mail->addTos(
array(
$target_user->getPHID(),

View file

@ -24,6 +24,7 @@ class PhabricatorMetaMTAMail extends PhabricatorMetaMTADAO {
const STATUS_QUEUE = 'queued';
const STATUS_SENT = 'sent';
const STATUS_FAIL = 'fail';
const STATUS_VOID = 'void';
const MAX_RETRIES = 250;
const RETRY_DELAY = 5;
@ -264,29 +265,54 @@ class PhabricatorMetaMTAMail extends PhabricatorMetaMTADAO {
$handles = id(new PhabricatorObjectHandleData($phids))
->loadHandles();
$exclude = array();
$params = $this->parameters;
$default = PhabricatorEnv::getEnvConfig('metamta.default-address');
if (empty($params['from'])) {
$mailer->setFrom($default);
} else if (!PhabricatorEnv::getEnvConfig('metamta.can-send-as-user')) {
} else {
$from = $params['from'];
$handle = $handles[$from];
if (empty($params['reply-to'])) {
$params['reply-to'] = $handle->getEmail();
$params['reply-to-name'] = $handle->getFullName();
// If the user has set their preferences to not send them email about
// things they do, exclude them from being on To or Cc.
$from_user = id(new PhabricatorUser())->loadOneWhere(
'phid = %s',
$from);
if ($from_user) {
$pref_key = PhabricatorUserPreferences::PREFERENCE_NO_SELF_MAIL;
$exclude_self = $from_user
->loadPreferences()
->getPreference($pref_key);
if ($exclude_self) {
$exclude[$from] = true;
}
}
if (!PhabricatorEnv::getEnvConfig('metamta.can-send-as-user')) {
$handle = $handles[$from];
if (empty($params['reply-to'])) {
$params['reply-to'] = $handle->getEmail();
$params['reply-to-name'] = $handle->getFullName();
}
$mailer->setFrom(
$default,
$handle->getFullName());
unset($params['from']);
}
$mailer->setFrom(
$default,
$handle->getFullName());
unset($params['from']);
}
$is_first = !empty($params['is-first-message']);
$is_first = idx($params, 'is-first-message');
unset($params['is-first-message']);
$is_threaded = (bool)idx($params, 'thread-id');
$reply_to_name = idx($params, 'reply-to-name', '');
unset($params['reply-to-name']);
$add_cc = null;
$add_to = null;
foreach ($params as $key => $value) {
switch ($key) {
case 'from':
@ -296,22 +322,21 @@ class PhabricatorMetaMTAMail extends PhabricatorMetaMTADAO {
$mailer->addReplyTo($value, $reply_to_name);
break;
case 'to':
$emails = $this->getDeliverableEmailsFromHandles($value, $handles);
$emails = $this->getDeliverableEmailsFromHandles(
$value,
$handles,
$exclude);
if ($emails) {
$mailer->addTos($emails);
} else {
if ($value) {
throw new Exception(
"All 'To' objects are undeliverable (e.g., disabled users).");
} else {
throw new Exception("No 'To' specified!");
}
$add_to = $emails;
}
break;
case 'cc':
$emails = $this->getDeliverableEmailsFromHandles($value, $handles);
$emails = $this->getDeliverableEmailsFromHandles(
$value,
$handles,
$exclude);
if ($emails) {
$mailer->addCCs($emails);
$add_cc = $emails;
}
break;
case 'headers':
@ -335,6 +360,30 @@ class PhabricatorMetaMTAMail extends PhabricatorMetaMTADAO {
$mailer->setBody($value);
break;
case 'subject':
if ($is_threaded) {
$add_re = PhabricatorEnv::getEnvConfig('metamta.re-prefix');
// If this message has a single recipient, respect their "Re:"
// preference. Otherwise, use the global setting.
$to = idx($params, 'to', array());
$cc = idx($params, 'cc', array());
if (count($to) == 1 && count($cc) == 0) {
$user = id(new PhabricatorUser())->loadOneWhere(
'phid = %s',
head($to));
if ($user) {
$prefs = $user->loadPreferences();
$pref_key = PhabricatorUserPreferences::PREFERENCE_RE_PREFIX;
$add_re = $prefs->getPreference($pref_key, $add_re);
}
}
if ($add_re) {
$value = 'Re: '.$value;
}
}
$mailer->setSubject($value);
break;
case 'is-html':
@ -376,6 +425,23 @@ class PhabricatorMetaMTAMail extends PhabricatorMetaMTADAO {
$mailer->addHeader('X-Mail-Transport-Agent', 'MetaMTA');
if ($add_to) {
$mailer->addTos($add_to);
if ($add_cc) {
$mailer->addCCs($add_cc);
}
} else if ($add_cc) {
// If we have CC addresses but no "to" address, promote the CCs to
// "to".
$mailer->addTos($add_cc);
} else {
$this->setStatus(self::STATUS_VOID);
$this->setMessage(
"Message has no valid recipients: all To/CC are disabled or ".
"configured not to receive this mail.");
return $this->save();
}
} catch (Exception $ex) {
$this->setStatus(self::STATUS_FAIL);
$this->setMessage($ex->getMessage());
@ -416,6 +482,7 @@ class PhabricatorMetaMTAMail extends PhabricatorMetaMTADAO {
self::STATUS_QUEUE => "Queued for Delivery",
self::STATUS_FAIL => "Delivery Failed",
self::STATUS_SENT => "Sent",
self::STATUS_VOID => "Void",
);
$status_code = coalesce($status_code, '?');
return idx($readable, $status_code, $status_code);
@ -454,7 +521,8 @@ class PhabricatorMetaMTAMail extends PhabricatorMetaMTADAO {
private function getDeliverableEmailsFromHandles(
array $phids,
array $handles) {
array $handles,
array $exclude) {
$emails = array();
foreach ($phids as $phid) {
@ -464,6 +532,9 @@ class PhabricatorMetaMTAMail extends PhabricatorMetaMTADAO {
if (!$handles[$phid]->isComplete()) {
continue;
}
if (isset($exclude[$phid])) {
continue;
}
$emails[] = $handles[$phid]->getEmail();
}

View file

@ -7,6 +7,8 @@
phutil_require_module('phabricator', 'applications/metamta/storage/base');
phutil_require_module('phabricator', 'applications/people/storage/preferences');
phutil_require_module('phabricator', 'applications/people/storage/user');
phutil_require_module('phabricator', 'applications/phid/handle/data');
phutil_require_module('phabricator', 'infrastructure/env');

View file

@ -1,7 +1,7 @@
<?php
/*
* Copyright 2011 Facebook, Inc.
* Copyright 2012 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -29,37 +29,9 @@ class PhabricatorUserSettingsController extends PhabricatorPeopleController {
$request = $this->getRequest();
$this->pages = array(
'account' => 'Account',
'profile' => 'Profile',
'email' => 'Email',
'password' => 'Password',
'preferences' => 'Preferences',
'conduit' => 'Conduit Certificate',
);
if (!PhabricatorEnv::getEnvConfig('account.editable') ||
!PhabricatorEnv::getEnvConfig('auth.password-auth-enabled')) {
unset($this->pages['password']);
}
if (PhabricatorUserSSHKeysSettingsPanelController::isEnabled()) {
$this->pages['sshkeys'] = 'SSH Public Keys';
}
$oauth_providers = PhabricatorOAuthProvider::getAllProviders();
foreach ($oauth_providers as $provider) {
if (!$provider->isProviderEnabled()) {
continue;
}
$key = $provider->getProviderKey();
$name = $provider->getProviderName();
$this->pages[$key] = $name.' Account';
}
if (empty($this->pages[$this->page])) {
$this->page = key($this->pages);
}
$sidenav = $this->renderSideNav($oauth_providers);
$this->page = $sidenav->selectFilter($this->page, 'account');
switch ($this->page) {
case 'account':
@ -71,6 +43,10 @@ class PhabricatorUserSettingsController extends PhabricatorPeopleController {
case 'email':
$delegate = new PhabricatorUserEmailSettingsPanelController($request);
break;
case 'emailpref':
$delegate = new PhabricatorUserEmailPreferenceSettingsPanelController(
$request);
break;
case 'password':
$delegate = new PhabricatorUserPasswordSettingsPanelController(
$request);
@ -86,17 +62,14 @@ class PhabricatorUserSettingsController extends PhabricatorPeopleController {
$request);
break;
default:
if (empty($this->pages[$this->page])) {
return new Aphront404Response();
}
$delegate = new PhabricatorUserOAuthSettingsPanelController($request);
$delegate->setOAuthProvider($oauth_providers[$this->page]);
break;
}
$response = $this->delegateToController($delegate);
if ($response instanceof AphrontView) {
$sidenav = $this->renderSideNav();
$sidenav->appendChild($response);
return $this->buildStandardPageResponse(
$sidenav,
@ -108,20 +81,53 @@ class PhabricatorUserSettingsController extends PhabricatorPeopleController {
}
}
private function renderSideNav() {
$sidenav = new AphrontSideNavView();
foreach ($this->pages as $page => $name) {
$sidenav->addNavItem(
phutil_render_tag(
'a',
array(
'href' => '/settings/page/'.$page.'/',
'class' => ($page == $this->page)
? 'aphront-side-nav-selected'
: null,
),
phutil_escape_html($name)));
private function renderSideNav($oauth_providers) {
$sidenav = new AphrontSideNavFilterView();
$sidenav
->setBaseURI(new PhutilURI('/settings/page/'))
->addLabel('Account Information')
->addFilter('account', 'Account')
->addFilter('profile', 'Profile')
->addSpacer()
->addLabel('Email')
->addFilter('email', 'Email Address')
->addFilter('emailpref', 'Email Preferences')
->addSpacer()
->addLabel('Authentication');
if (PhabricatorEnv::getEnvConfig('account.editable') &&
PhabricatorEnv::getEnvConfig('auth.password-auth-enabled')) {
$sidenav->addFilter('password', 'Password');
}
$sidenav->addFilter('conduit', 'Conduit Certificate');
if (PhabricatorUserSSHKeysSettingsPanelController::isEnabled()) {
$sidenav->addFilter('sshkeys', 'SSH Public Keys');
}
$sidenav->addSpacer();
$sidenav->addLabel('Application Settings');
$sidenav->addFilter('preferences', 'Display Preferences');
$items = array();
foreach ($oauth_providers as $provider) {
if (!$provider->isProviderEnabled()) {
continue;
}
$key = $provider->getProviderKey();
$name = $provider->getProviderName();
$items[$key] = $name.' Account';
}
if ($items) {
$sidenav->addSpacer();
$sidenav->addLabel('Linked Accounts');
foreach ($items as $key => $name) {
$sidenav->addFilter($key, $name);
}
}
return $sidenav;
}
}

View file

@ -6,21 +6,21 @@
phutil_require_module('phabricator', 'aphront/response/404');
phutil_require_module('phabricator', 'applications/auth/oauth/provider/base');
phutil_require_module('phabricator', 'applications/people/controller/base');
phutil_require_module('phabricator', 'applications/people/controller/settings/panels/account');
phutil_require_module('phabricator', 'applications/people/controller/settings/panels/conduit');
phutil_require_module('phabricator', 'applications/people/controller/settings/panels/email');
phutil_require_module('phabricator', 'applications/people/controller/settings/panels/emailpref');
phutil_require_module('phabricator', 'applications/people/controller/settings/panels/oauth');
phutil_require_module('phabricator', 'applications/people/controller/settings/panels/password');
phutil_require_module('phabricator', 'applications/people/controller/settings/panels/preferences');
phutil_require_module('phabricator', 'applications/people/controller/settings/panels/profile');
phutil_require_module('phabricator', 'applications/people/controller/settings/panels/sshkeys');
phutil_require_module('phabricator', 'infrastructure/env');
phutil_require_module('phabricator', 'view/layout/sidenav');
phutil_require_module('phabricator', 'view/layout/sidenavfilter');
phutil_require_module('phutil', 'markup');
phutil_require_module('phutil', 'parser/uri');
phutil_require_module('phutil', 'utils');

View file

@ -0,0 +1,125 @@
<?php
/*
* Copyright 2012 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class PhabricatorUserEmailPreferenceSettingsPanelController
extends PhabricatorUserSettingsPanelController {
public function processRequest() {
$request = $this->getRequest();
$user = $request->getUser();
$preferences = $user->loadPreferences();
$pref_re_prefix = PhabricatorUserPreferences::PREFERENCE_RE_PREFIX;
$pref_no_self_mail = PhabricatorUserPreferences::PREFERENCE_NO_SELF_MAIL;
$errors = array();
if ($request->isFormPost()) {
if ($request->getStr($pref_re_prefix) == 'default') {
$preferences->unsetPreference($pref_re_prefix);
} else {
$preferences->setPreference(
$pref_re_prefix,
$request->getBool($pref_re_prefix));
}
$preferences->setPreference(
$pref_no_self_mail,
$request->getStr($pref_no_self_mail));
$preferences->save();
return id(new AphrontRedirectResponse())
->setURI('/settings/page/emailpref/?saved=true');
}
$notice = null;
if (!$errors) {
if ($request->getStr('saved')) {
$notice = new AphrontErrorView();
$notice->setSeverity(AphrontErrorView::SEVERITY_NOTICE);
$notice->setTitle('Changes Saved');
$notice->appendChild('<p>Your changes have been saved.</p>');
}
} else {
$notice = new AphrontErrorView();
$notice->setTitle('Form Errors');
$notice->setErrors($errors);
}
$re_prefix_default = PhabricatorEnv::getEnvConfig('metamta.re-prefix')
? 'Enabled'
: 'Disabled';
$re_prefix_value = $preferences->getPreference($pref_re_prefix);
if ($re_prefix_value === null) {
$re_prefix_value = 'defualt';
} else {
$re_prefix_value = $re_prefix_value
? 'true'
: 'false';
}
$form = new AphrontFormView();
$form
->setUser($user)
->appendChild(
id(new AphrontFormSelectControl())
->setLabel('Self Actions')
->setName($pref_no_self_mail)
->setOptions(
array(
'0' => 'Send me an email when I take an action',
'1' => 'Do not send me an email when I take an action',
))
->setCaption('You can disable email about your own actions.')
->setValue($preferences->getPreference($pref_no_self_mail, 0)))
->appendChild(
id(new AphrontFormSelectControl())
->setLabel('Add "Re:" Prefix')
->setName($pref_re_prefix)
->setCaption(
'Enable this option to fix threading in Mail.app on OS X Lion, '.
'or if you like "Re:" in your email subjects.')
->setOptions(
array(
'default' => 'Use Server Default ('.$re_prefix_default.')',
'true' => 'Enable "Re:" prefix',
'false' => 'Disable "Re:" prefix',
))
->setValue($re_prefix_value));
$form
->appendChild(
id(new AphrontFormSubmitControl())
->setValue('Save'));
$panel = new AphrontPanelView();
$panel->setHeader('Email Preferences');
$panel->setWidth(AphrontPanelView::WIDTH_FORM);
$panel->appendChild($form);
return id(new AphrontNullView())
->appendChild(
array(
$notice,
$panel,
));
}
}

View file

@ -0,0 +1,23 @@
<?php
/**
* This file is automatically generated. Lint this module to rebuild it.
* @generated
*/
phutil_require_module('phabricator', 'aphront/response/redirect');
phutil_require_module('phabricator', 'applications/people/controller/settings/panels/base');
phutil_require_module('phabricator', 'applications/people/storage/preferences');
phutil_require_module('phabricator', 'infrastructure/env');
phutil_require_module('phabricator', 'view/form/base');
phutil_require_module('phabricator', 'view/form/control/select');
phutil_require_module('phabricator', 'view/form/control/submit');
phutil_require_module('phabricator', 'view/form/error');
phutil_require_module('phabricator', 'view/layout/panel');
phutil_require_module('phabricator', 'view/null');
phutil_require_module('phutil', 'utils');
phutil_require_source('PhabricatorUserEmailPreferenceSettingsPanelController.php');

View file

@ -1,7 +1,7 @@
<?php
/*
* Copyright 2011 Facebook, Inc.
* Copyright 2012 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -56,15 +56,6 @@ class PhabricatorUserOAuthSettingsPanelController
'can link an account, which will allow you to use it to log into '.
'Phabricator.</p>');
switch ($provider_key) {
case PhabricatorOAuthProvider::PROVIDER_GITHUB:
$form->appendChild(
'<p class="aphront-form-instructions">Additionally, you must '.
'link your Github account before Phabricator can access any '.
'information about hosted repositories.</p>');
break;
}
$auth_uri = $provider->getAuthURI();
$client_id = $provider->getClientID();
$redirect_uri = $provider->getRedirectURI();

View file

@ -6,7 +6,6 @@
phutil_require_module('phabricator', 'applications/auth/oauth/provider/base');
phutil_require_module('phabricator', 'applications/people/controller/settings/panels/base');
phutil_require_module('phabricator', 'applications/people/storage/useroauthinfo');
phutil_require_module('phabricator', 'view/form/base');

View file

@ -1,7 +1,7 @@
<?php
/*
* Copyright 2011 Facebook, Inc.
* Copyright 2012 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -15,6 +15,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class PhabricatorUserPreferenceSettingsPanelController
extends PhabricatorUserSettingsPanelController {
@ -24,20 +25,18 @@ class PhabricatorUserPreferenceSettingsPanelController
$user = $request->getUser();
$preferences = $user->loadPreferences();
$pref_monospaced = PhabricatorUserPreferences::PREFERENCE_MONOSPACED;
$pref_titles = PhabricatorUserPreferences::PREFERENCE_TITLES;
if ($request->isFormPost()) {
$monospaced = $request->getStr(
PhabricatorUserPreferences::PREFERENCE_MONOSPACED);
$monospaced = $request->getStr($pref_monospaced);
// Prevent the user from doing stupid things.
$monospaced = preg_replace('/[^a-z0-9 ,"]+/i', '', $monospaced);
$pref_dict = array(
PhabricatorUserPreferences::PREFERENCE_TITLES =>
$request->getStr(PhabricatorUserPreferences::PREFERENCE_TITLES),
PhabricatorUserPreferences::PREFERENCE_MONOSPACED =>
$monospaced);
$preferences->setPreference($pref_titles, $request->getStr($pref_titles));
$preferences->setPreference($pref_monospaced, $monospaced);
$preferences->setPreferences($pref_dict);
$preferences->save();
return id(new AphrontRedirectResponse())
->setURI('/settings/page/preferences/?saved=true');
@ -56,9 +55,8 @@ EXAMPLE;
->appendChild(
id(new AphrontFormSelectControl())
->setLabel('Page Titles')
->setName(PhabricatorUserPreferences::PREFERENCE_TITLES)
->setValue($preferences->getPreference(
PhabricatorUserPreferences::PREFERENCE_TITLES))
->setName($pref_titles)
->setValue($preferences->getPreference($pref_titles))
->setOptions(
array(
'glyph' =>
@ -69,13 +67,12 @@ EXAMPLE;
->appendChild(
id(new AphrontFormTextControl())
->setLabel('Monospaced Font')
->setName(PhabricatorUserPreferences::PREFERENCE_MONOSPACED)
->setName($pref_monospaced)
->setCaption(
'Overrides default fonts in tools like Differential. '.
'(Default: 10px "Menlo", "Consolas", "Monaco", '.
'monospace)')
->setValue($preferences->getPreference(
PhabricatorUserPreferences::PREFERENCE_MONOSPACED)))
->setValue($preferences->getPreference($pref_monospaced)))
->appendChild(
id(new AphrontFormMarkupControl())
->setValue(
@ -88,7 +85,7 @@ EXAMPLE;
$panel = new AphrontPanelView();
$panel->setWidth(AphrontPanelView::WIDTH_WIDE);
$panel->setHeader('Phabricator Preferences');
$panel->setHeader('Display Preferences');
$panel->appendChild($form);
$error_view = null;

View file

@ -1,7 +1,7 @@
<?php
/*
* Copyright 2011 Facebook, Inc.
* Copyright 2012 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -18,11 +18,14 @@
class PhabricatorUserPreferences extends PhabricatorUserDAO {
const PREFERENCE_MONOSPACED = 'monospaced';
const PREFERENCE_TITLES = 'titles';
const PREFERENCE_MONOSPACED = 'monospaced';
const PREFERENCE_TITLES = 'titles';
const PREFERENCE_RE_PREFIX = 're-prefix';
const PREFERENCE_NO_SELF_MAIL = 'self-mail';
protected $userPHID;
protected $preferences;
protected $preferences = array();
public function getConfiguration() {
return array(
@ -33,7 +36,18 @@ class PhabricatorUserPreferences extends PhabricatorUserDAO {
) + parent::getConfiguration();
}
public function getPreference($key) {
return idx($this->getPreferences(), $key);
public function getPreference($key, $default = null) {
return idx($this->preferences, $key, $default);
}
public function setPreference($key, $value) {
$this->preferences[$key] = $value;
return $this;
}
public function unsetPreference($key) {
unset($this->preferences[$key]);
return $this;
}
}