1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-09-19 16:58:48 +02:00

Make translation, timezone and pronoun into real settings

Summary:
Ref T4103. These are currently stored on the user, for historic/performance reasons.

Since I want administrators to be able to set defaults for translations and timezones at a minimum and there's no longer a meaningful performance penalty for moving them off the user record, turn them into real preferences and then nuke the columns.

Test Plan:
  - Set settings to unusual values.
  - Ran migrations.
  - Verified my unusual settings survived.
  - Created a new user.
  - Edited all settings with old and new UIs.
  - Reconciled client/server timezone disagreement.

Reviewers: chad

Reviewed By: chad

Maniphest Tasks: T4103

Differential Revision: https://secure.phabricator.com/D16005
This commit is contained in:
epriestley 2016-06-01 16:17:30 -07:00
parent edfc6a6934
commit ebd8f3c987
19 changed files with 422 additions and 66 deletions

View file

@ -0,0 +1,59 @@
<?php
// Move timezone, translation and pronoun from the user object to preferences
// so they can be defaulted and edited like other settings.
$table = new PhabricatorUser();
$conn_w = $table->establishConnection('w');
$table_name = $table->getTableName();
$prefs_table = new PhabricatorUserPreferences();
foreach (new LiskRawMigrationIterator($conn_w, $table_name) as $row) {
$phid = $row['phid'];
$pref_row = queryfx_one(
$conn_w,
'SELECT preferences FROM %T WHERE userPHID = %s',
$prefs_table->getTableName(),
$phid);
if ($pref_row) {
try {
$prefs = phutil_json_decode($pref_row['preferences']);
} catch (Exception $ex) {
$prefs = array();
}
} else {
$prefs = array();
}
$zone = $row['timezoneIdentifier'];
if (strlen($zone)) {
$prefs[PhabricatorTimezoneSetting::SETTINGKEY] = $zone;
}
$pronoun = $row['sex'];
if (strlen($pronoun)) {
$prefs[PhabricatorPronounSetting::SETTINGKEY] = $pronoun;
}
$translation = $row['translation'];
if (strlen($translation)) {
$prefs[PhabricatorTranslationSetting::SETTINGKEY] = $translation;
}
if ($prefs) {
queryfx(
$conn_w,
'INSERT INTO %T (phid, userPHID, preferences, dateModified, dateCreated)
VALUES (%s, %s, %s, UNIX_TIMESTAMP(), UNIX_TIMESTAMP())
ON DUPLICATE KEY UPDATE preferences = VALUES(preferences)',
$prefs_table->getTableName(),
$prefs_table->generatePHID(),
$phid,
phutil_json_encode($prefs));
}
}
$prefs_key = PhabricatorUserPreferencesCacheType::KEY_PREFERENCES;
PhabricatorUserCache::clearCacheForAllUsers($prefs_key);

View file

@ -0,0 +1,2 @@
ALTER TABLE {$NAMESPACE}_user.user
DROP COLUMN timezoneIdentifier;

View file

@ -0,0 +1,2 @@
ALTER TABLE {$NAMESPACE}_user.user
DROP COLUMN translation;

View file

@ -0,0 +1,2 @@
ALTER TABLE {$NAMESPACE}_user.user
DROP COLUMN sex;

View file

@ -2837,6 +2837,7 @@ phutil_register_library_map(array(
'PhabricatorOlderInlinesSetting' => 'applications/settings/setting/PhabricatorOlderInlinesSetting.php',
'PhabricatorOneTimeTriggerClock' => 'infrastructure/daemon/workers/clock/PhabricatorOneTimeTriggerClock.php',
'PhabricatorOpcodeCacheSpec' => 'applications/cache/spec/PhabricatorOpcodeCacheSpec.php',
'PhabricatorOptionGroupSetting' => 'applications/settings/setting/PhabricatorOptionGroupSetting.php',
'PhabricatorOwnerPathQuery' => 'applications/owners/query/PhabricatorOwnerPathQuery.php',
'PhabricatorOwnersApplication' => 'applications/owners/application/PhabricatorOwnersApplication.php',
'PhabricatorOwnersArchiveController' => 'applications/owners/controller/PhabricatorOwnersArchiveController.php',
@ -3168,6 +3169,7 @@ phutil_register_library_map(array(
'PhabricatorProjectsSearchEngineAttachment' => 'applications/project/engineextension/PhabricatorProjectsSearchEngineAttachment.php',
'PhabricatorProjectsSearchEngineExtension' => 'applications/project/engineextension/PhabricatorProjectsSearchEngineExtension.php',
'PhabricatorProjectsWatchersSearchEngineAttachment' => 'applications/project/engineextension/PhabricatorProjectsWatchersSearchEngineAttachment.php',
'PhabricatorPronounSetting' => 'applications/settings/setting/PhabricatorPronounSetting.php',
'PhabricatorProtocolAdapter' => 'infrastructure/daemon/bot/adapter/PhabricatorProtocolAdapter.php',
'PhabricatorPygmentSetupCheck' => 'applications/config/check/PhabricatorPygmentSetupCheck.php',
'PhabricatorQuery' => 'infrastructure/query/PhabricatorQuery.php',
@ -3535,6 +3537,7 @@ phutil_register_library_map(array(
'PhabricatorTimeFormatSetting' => 'applications/settings/setting/PhabricatorTimeFormatSetting.php',
'PhabricatorTimeGuard' => 'infrastructure/time/PhabricatorTimeGuard.php',
'PhabricatorTimeTestCase' => 'infrastructure/time/__tests__/PhabricatorTimeTestCase.php',
'PhabricatorTimezoneSetting' => 'applications/settings/setting/PhabricatorTimezoneSetting.php',
'PhabricatorTimezoneSetupCheck' => 'applications/config/check/PhabricatorTimezoneSetupCheck.php',
'PhabricatorTitleGlyphsSetting' => 'applications/settings/setting/PhabricatorTitleGlyphsSetting.php',
'PhabricatorToken' => 'applications/tokens/storage/PhabricatorToken.php',
@ -3565,6 +3568,7 @@ phutil_register_library_map(array(
'PhabricatorTransactionsDestructionEngineExtension' => 'applications/transactions/engineextension/PhabricatorTransactionsDestructionEngineExtension.php',
'PhabricatorTransactionsFulltextEngineExtension' => 'applications/transactions/engineextension/PhabricatorTransactionsFulltextEngineExtension.php',
'PhabricatorTransformedFile' => 'applications/files/storage/PhabricatorTransformedFile.php',
'PhabricatorTranslationSetting' => 'applications/settings/setting/PhabricatorTranslationSetting.php',
'PhabricatorTranslationsConfigOptions' => 'applications/config/option/PhabricatorTranslationsConfigOptions.php',
'PhabricatorTriggerAction' => 'infrastructure/daemon/workers/action/PhabricatorTriggerAction.php',
'PhabricatorTriggerClock' => 'infrastructure/daemon/workers/clock/PhabricatorTriggerClock.php',
@ -7455,6 +7459,7 @@ phutil_register_library_map(array(
'PhabricatorOlderInlinesSetting' => 'PhabricatorSelectSetting',
'PhabricatorOneTimeTriggerClock' => 'PhabricatorTriggerClock',
'PhabricatorOpcodeCacheSpec' => 'PhabricatorCacheSpec',
'PhabricatorOptionGroupSetting' => 'PhabricatorSetting',
'PhabricatorOwnerPathQuery' => 'Phobject',
'PhabricatorOwnersApplication' => 'PhabricatorApplication',
'PhabricatorOwnersArchiveController' => 'PhabricatorOwnersController',
@ -7858,6 +7863,7 @@ phutil_register_library_map(array(
'PhabricatorProjectsSearchEngineAttachment' => 'PhabricatorSearchEngineAttachment',
'PhabricatorProjectsSearchEngineExtension' => 'PhabricatorSearchEngineExtension',
'PhabricatorProjectsWatchersSearchEngineAttachment' => 'PhabricatorSearchEngineAttachment',
'PhabricatorPronounSetting' => 'PhabricatorSelectSetting',
'PhabricatorProtocolAdapter' => 'Phobject',
'PhabricatorPygmentSetupCheck' => 'PhabricatorSetupCheck',
'PhabricatorQuery' => 'Phobject',
@ -8294,6 +8300,7 @@ phutil_register_library_map(array(
'PhabricatorTimeFormatSetting' => 'PhabricatorSelectSetting',
'PhabricatorTimeGuard' => 'Phobject',
'PhabricatorTimeTestCase' => 'PhabricatorTestCase',
'PhabricatorTimezoneSetting' => 'PhabricatorOptionGroupSetting',
'PhabricatorTimezoneSetupCheck' => 'PhabricatorSetupCheck',
'PhabricatorTitleGlyphsSetting' => 'PhabricatorSelectSetting',
'PhabricatorToken' => array(
@ -8329,6 +8336,7 @@ phutil_register_library_map(array(
'PhabricatorTransactionsDestructionEngineExtension' => 'PhabricatorDestructionEngineExtension',
'PhabricatorTransactionsFulltextEngineExtension' => 'PhabricatorFulltextEngineExtension',
'PhabricatorTransformedFile' => 'PhabricatorFileDAO',
'PhabricatorTranslationSetting' => 'PhabricatorOptionGroupSetting',
'PhabricatorTranslationsConfigOptions' => 'PhabricatorApplicationConfigOptions',
'PhabricatorTriggerAction' => 'Phobject',
'PhabricatorTriggerClock' => 'Phobject',

View file

@ -4,7 +4,7 @@ final class CalendarTimeUtilTestCase extends PhabricatorTestCase {
public function testTimestampsAtMidnight() {
$u = new PhabricatorUser();
$u->setTimezoneIdentifier('America/Los_Angeles');
$u->overrideTimezoneIdentifier('America/Los_Angeles');
$days = $this->getAllDays();
foreach ($days as $day) {
$data = CalendarTimeUtil::getCalendarWidgetTimestamps(
@ -19,7 +19,7 @@ final class CalendarTimeUtilTestCase extends PhabricatorTestCase {
public function testTimestampsStartDay() {
$u = new PhabricatorUser();
$u->setTimezoneIdentifier('America/Los_Angeles');
$u->overrideTimezoneIdentifier('America/Los_Angeles');
$days = $this->getAllDays();
foreach ($days as $day) {
$data = CalendarTimeUtil::getTimestamps(

View file

@ -164,33 +164,6 @@ final class PhabricatorMetaMTAMail
return $this->getParam('herald-force-recipients', array());
}
public function getTranslation(array $objects) {
$default_translation = PhabricatorEnv::getEnvConfig('translation.provider');
$return = null;
$recipients = array_merge(
idx($this->parameters, 'to', array()),
idx($this->parameters, 'cc', array()));
foreach (array_select_keys($objects, $recipients) as $object) {
$translation = null;
if ($object instanceof PhabricatorUser) {
$translation = $object->getTranslation();
}
if (!$translation) {
$translation = $default_translation;
}
if ($return && $translation != $return) {
return $default_translation;
}
$return = $translation;
}
if (!$return) {
$return = $default_translation;
}
return $return;
}
public function addPHIDHeaders($name, array $phids) {
$phids = array_unique($phids);
foreach ($phids as $phid) {

View file

@ -5,6 +5,7 @@
* @task image-cache Profile Image Cache
* @task factors Multi-Factor Authentication
* @task handles Managing Handles
* @task settings Settings
* @task cache User Cache
*/
final class PhabricatorUser
@ -26,15 +27,12 @@ final class PhabricatorUser
protected $userName;
protected $realName;
protected $sex;
protected $translation;
protected $passwordSalt;
protected $passwordHash;
protected $profileImagePHID;
protected $profileImageCache;
protected $availabilityCache;
protected $availabilityCacheTTL;
protected $timezoneIdentifier = '';
protected $consoleEnabled = 0;
protected $consoleVisible = 0;
@ -68,14 +66,10 @@ final class PhabricatorUser
private $authorities = array();
private $handlePool;
private $csrfSalt;
private $timezoneOverride;
protected function readField($field) {
switch ($field) {
case 'timezoneIdentifier':
// If the user hasn't set one, guess the server's time.
return nonempty(
$this->timezoneIdentifier,
date_default_timezone_get());
// Make sure these return booleans.
case 'isAdmin':
return (bool)$this->isAdmin;
@ -191,8 +185,6 @@ final class PhabricatorUser
self::CONFIG_COLUMN_SCHEMA => array(
'userName' => 'sort64',
'realName' => 'text128',
'sex' => 'text4?',
'translation' => 'text64?',
'passwordSalt' => 'text32?',
'passwordHash' => 'text128?',
'profileImagePHID' => 'phid?',
@ -204,7 +196,6 @@ final class PhabricatorUser
'isMailingList' => 'bool',
'isDisabled' => 'bool',
'isAdmin' => 'bool',
'timezoneIdentifier' => 'text255',
'isEmailVerified' => 'uint32',
'isApproved' => 'uint32',
'accountSecret' => 'bytes64',
@ -261,11 +252,6 @@ final class PhabricatorUser
return $this;
}
// To satisfy PhutilPerson.
public function getSex() {
return $this->sex;
}
public function getMonogram() {
return '@'.$this->getUsername();
}
@ -490,6 +476,10 @@ final class PhabricatorUser
'(isPrimary = 1)');
}
/* -( Settings )----------------------------------------------------------- */
public function getUserSetting($key) {
$settings_key = PhabricatorUserPreferencesCacheType::KEY_PREFERENCES;
$settings = $this->requireCacheData($settings_key);
@ -506,11 +496,51 @@ final class PhabricatorUser
return null;
}
/**
* Test if a given setting is set to a particular value.
*
* @param const Setting key.
* @param wild Value to compare.
* @return bool True if the setting has the specified value.
* @task settings
*/
public function compareUserSetting($key, $value) {
$actual = $this->getUserSetting($key);
return ($actual == $value);
}
public function getTranslation() {
return $this->getUserSetting(PhabricatorTranslationSetting::SETTINGKEY);
}
public function getTimezoneIdentifier() {
if ($this->timezoneOverride) {
return $this->timezoneOverride;
}
return $this->getUserSetting(PhabricatorTimezoneSetting::SETTINGKEY);
}
/**
* Override the user's timezone identifier.
*
* This is primarily useful for unit tests.
*
* @param string New timezone identifier.
* @return this
* @task settings
*/
public function overrideTimezoneIdentifier($identifier) {
$this->timezoneOverride = $identifier;
return $this;
}
public function getSex() {
return $this->getUserSetting(PhabricatorPronounSetting::SETTINGKEY);
}
public function loadPreferences() {
if ($this->preferences) {
return $this->preferences;
@ -1539,4 +1569,14 @@ final class PhabricatorUser
return $usable_value;
}
/**
* @task cache
*/
public function clearCacheData($key) {
unset($this->rawCacheData[$key]);
unset($this->usableCacheData[$key]);
return $this;
}
}

View file

@ -31,6 +31,7 @@ final class PhabricatorSettingsTimezoneController
$timezone = $request->getStr('timezone');
$pref_ignore = PhabricatorUserPreferences::PREFERENCE_IGNORE_OFFSET;
$pref_timezone = PhabricatorTimezoneSetting::SETTINGKEY;
$preferences = $viewer->loadPreferences();
@ -52,11 +53,11 @@ final class PhabricatorSettingsTimezoneController
if (isset($options[$timezone])) {
$preferences
->setPreference($pref_ignore, null)
->setPreference($pref_timezone, $timezone)
->save();
$viewer
->setTimezoneIdentifier($timezone)
->save();
$viewer->clearCacheData(
PhabricatorUserPreferencesCacheType::KEY_PREFERENCES);
}
}
@ -115,9 +116,9 @@ final class PhabricatorSettingsTimezoneController
$offset = $offset / 60;
if ($offset >= 0) {
return pht('GMT-%d', $offset);
return pht('UTC-%d', $offset);
} else {
return pht('GMT+%d', -$offset);
return pht('UTC+%d', -$offset);
}
}

View file

@ -78,6 +78,12 @@ final class PhabricatorSettingsEditEngine
$viewer = $this->getViewer();
$settings = PhabricatorSetting::getAllEnabledSettings($viewer);
foreach ($settings as $key => $setting) {
$setting = clone $setting;
$setting->setViewer($viewer);
$settings[$key] = $setting;
}
$fields = array();
foreach ($settings as $setting) {
foreach ($setting->newCustomEditFields($object) as $field) {

View file

@ -23,21 +23,29 @@ final class PhabricatorAccountSettingsPanel extends PhabricatorSettingsPanel {
$user = $this->getUser();
$username = $user->getUsername();
$preferences = $user->loadPreferences();
$errors = array();
if ($request->isFormPost()) {
$sex = $request->getStr('sex');
$sexes = array(PhutilPerson::SEX_MALE, PhutilPerson::SEX_FEMALE);
if (in_array($sex, $sexes)) {
$user->setSex($sex);
$new_value = $sex;
} else {
$user->setSex(null);
$new_value = null;
}
// Checked in runtime.
$user->setTranslation($request->getStr('translation'));
$preferences->setPreference(
PhabricatorPronounSetting::SETTINGKEY,
$new_value);
$preferences->setPreference(
PhabricatorTranslationSetting::SETTINGKEY,
$request->getStr('translation'));
if (!$errors) {
$user->save();
$preferences->save();
return id(new AphrontRedirectResponse())
->setURI($this->getPanelURI('?saved=true'));
}

View file

@ -18,6 +18,7 @@ final class PhabricatorDateTimeSettingsPanel extends PhabricatorSettingsPanel {
$user = $request->getUser();
$username = $user->getUsername();
$pref_timezone = PhabricatorTimezoneSetting::SETTINGKEY;
$pref_time = PhabricatorUserPreferences::PREFERENCE_TIME_FORMAT;
$pref_date = PhabricatorUserPreferences::PREFERENCE_DATE_FORMAT;
$pref_week_start = PhabricatorUserPreferences::PREFERENCE_WEEK_START_DAY;
@ -27,13 +28,12 @@ final class PhabricatorDateTimeSettingsPanel extends PhabricatorSettingsPanel {
$errors = array();
if ($request->isFormPost()) {
$new_timezone = $request->getStr('timezone');
if (in_array($new_timezone, DateTimeZone::listIdentifiers(), true)) {
$user->setTimezoneIdentifier($new_timezone);
} else {
if (!in_array($new_timezone, DateTimeZone::listIdentifiers(), true)) {
$errors[] = pht('The selected timezone is not a valid timezone.');
}
$preferences
->setPreference($pref_timezone, $new_timezone)
->setPreference(
$pref_time,
$request->getStr($pref_time))
@ -47,7 +47,7 @@ final class PhabricatorDateTimeSettingsPanel extends PhabricatorSettingsPanel {
if (!$errors) {
$preferences->save();
$user->save();
return id(new AphrontRedirectResponse())
->setURI($this->getPanelURI('?saved=true'));
}

View file

@ -0,0 +1,73 @@
<?php
abstract class PhabricatorOptionGroupSetting
extends PhabricatorSetting {
abstract protected function getSelectOptionGroups();
final protected function getSelectOptionMap() {
$groups = $this->getSelectOptionGroups();
$map = array();
foreach ($groups as $group) {
$map += $group['options'];
}
return $map;
}
final protected function newCustomEditField($object) {
$setting_key = $this->getSettingKey();
$default_value = $object->getDefaultValue($setting_key);
$options = $this->getSelectOptionGroups();
$map = $this->getSelectOptionMap();
if (isset($map[$default_value])) {
$default_label = pht('Default (%s)', $map[$default_value]);
} else {
$default_label = pht('Default (Unknown, "%s")', $default_value);
}
$head_key = head_key($options);
$options[$head_key]['options'] = array(
'' => $default_label,
) + $options[$head_key]['options'];
$flat_options = array();
foreach ($options as $group) {
$flat_options[$group['label']] = $group['options'];
}
return $this->newEditField($object, new PhabricatorSelectEditField())
->setOptions($flat_options);
}
final public function validateTransactionValue($value) {
if (!strlen($value)) {
return;
}
$map = $this->getSelectOptionMap();
if (!isset($map[$value])) {
throw new Exception(
pht(
'Value "%s" is not valid for setting "%s": valid values are %s.',
$value,
$this->getSettingName(),
implode(', ', array_keys($map))));
}
return;
}
public function getTransactionNewValue($value) {
if (!strlen($value)) {
return null;
}
return (string)$value;
}
}

View file

@ -0,0 +1,35 @@
<?php
final class PhabricatorPronounSetting
extends PhabricatorSelectSetting {
const SETTINGKEY = 'pronoun';
public function getSettingName() {
return pht('Pronoun');
}
protected function getControlInstructions() {
return pht('Choose the pronoun you prefer.');
}
public function getSettingDefaultValue() {
return PhutilPerson::SEX_UNKNOWN;
}
protected function getSelectOptions() {
$viewer = $this->getViewer();
$username = $viewer->getUsername();
$label_unknown = pht('%s updated their profile', $username);
$label_her = pht('%s updated her profile', $username);
$label_his = pht('%s updated his profile', $username);
return array(
PhutilPerson::SEX_UNKNOWN => $label_unknown,
PhutilPerson::SEX_MALE => $label_his,
PhutilPerson::SEX_FEMALE => $label_her,
);
}
}

View file

@ -17,9 +17,11 @@ abstract class PhabricatorSelectSetting
$default_label = pht('Default (Unknown, "%s")', $default_value);
}
$options = array(
'' => $default_label,
) + $options;
if (empty($options[''])) {
$options = array(
'' => $default_label,
) + $options;
}
return $this->newEditField($object, new PhabricatorSelectEditField())
->setOptions($options);

View file

@ -0,0 +1,53 @@
<?php
final class PhabricatorTimezoneSetting
extends PhabricatorOptionGroupSetting {
const SETTINGKEY = 'timezone';
public function getSettingName() {
return pht('Timezone');
}
public function getSettingDefaultValue() {
return date_default_timezone_get();
}
protected function getSelectOptionGroups() {
$timezones = DateTimeZone::listIdentifiers();
$now = new DateTime('@'.PhabricatorTime::getNow());
$groups = array();
foreach ($timezones as $timezone) {
$zone = new DateTimeZone($timezone);
$offset = -($zone->getOffset($now) / (60 * 60));
$groups[$offset][] = $timezone;
}
krsort($groups);
$option_groups = array(
array(
'label' => pht('Default'),
'options' => array(),
),
);
foreach ($groups as $offset => $group) {
if ($offset >= 0) {
$label = pht('UTC-%d', $offset);
} else {
$label = pht('UTC+%d', -$offset);
}
sort($group);
$option_groups[] = array(
'label' => $label,
'options' => array_fuse($group),
);
}
return $option_groups;
}
}

View file

@ -0,0 +1,92 @@
<?php
final class PhabricatorTranslationSetting
extends PhabricatorOptionGroupSetting {
const SETTINGKEY = 'translation';
public function getSettingName() {
return pht('Translation');
}
public function getSettingDefaultValue() {
return 'en_US';
}
protected function getSelectOptionGroups() {
$is_serious = PhabricatorEnv::getEnvConfig('phabricator.serious-business');
$locales = PhutilLocale::loadAllLocales();
$group_labels = array(
'normal' => pht('Translations'),
'limited' => pht('Limited Translations'),
'silly' => pht('Silly Translations'),
'test' => pht('Developer/Test Translations'),
);
$groups = array_fill_keys(array_keys($group_labels), array());
$translations = array();
foreach ($locales as $locale) {
$code = $locale->getLocaleCode();
// Get the locale's localized name if it's available. For example,
// "Deutsch" instead of "German". This helps users who do not speak the
// current language to find the correct setting.
$raw_scope = PhabricatorEnv::beginScopedLocale($code);
$name = $locale->getLocaleName();
unset($raw_scope);
if ($locale->isSillyLocale()) {
if ($is_serious) {
// Omit silly locales on serious business installs.
continue;
}
$groups['silly'][$code] = $name;
continue;
}
if ($locale->isTestLocale()) {
$groups['test'][$code] = $name;
continue;
}
$strings = PhutilTranslation::getTranslationMapForLocale($code);
$size = count($strings);
// If a translation is English, assume it can fall back to the default
// strings and don't caveat its completeness.
$is_english = (substr($code, 0, 3) == 'en_');
// Arbitrarily pick some number of available strings to promote a
// translation out of the "limited" group. The major goal is just to
// keep locales with very few strings out of the main group, so users
// aren't surprised if a locale has no upstream translations available.
if ($size > 512 || $is_english) {
$type = 'normal';
} else {
$type = 'limited';
}
$groups[$type][$code] = $name;
}
$results = array();
foreach ($groups as $key => $group) {
$label = $group_labels[$key];
if (!$group) {
continue;
}
asort($group);
$results[] = array(
'label' => $label,
'options' => $group,
);
}
return $results;
}
}

View file

@ -15,10 +15,10 @@ final class PhabricatorTimeTestCase extends PhabricatorTestCase {
public function testParseLocalTime() {
$u = new PhabricatorUser();
$u->setTimezoneIdentifier('UTC');
$u->overrideTimezoneIdentifier('UTC');
$v = new PhabricatorUser();
$v->setTimezoneIdentifier('America/Los_Angeles');
$v->overrideTimezoneIdentifier('America/Los_Angeles');
$t = 1370202281; // 2013-06-02 12:44:41 -0700
$time = PhabricatorTime::pushTime($t, 'America/Los_Angeles');

View file

@ -4,10 +4,10 @@ final class PhabricatorLocalTimeTestCase extends PhabricatorTestCase {
public function testLocalTimeFormatting() {
$user = new PhabricatorUser();
$user->setTimezoneIdentifier('America/Los_Angeles');
$user->overrideTimezoneIdentifier('America/Los_Angeles');
$utc = new PhabricatorUser();
$utc->setTimezoneIdentifier('UTC');
$utc->overrideTimezoneIdentifier('UTC');
$this->assertEqual(
'Jan 1 2000, 12:00 AM',