Correct Aphlict websocket URI construction after PHP8 compatibility changes
[phabricator.git] / src / applications / settings / controller / PhabricatorSettingsTimezoneController.php
blob8ae27041612c8830fc2bd582f056501c3490a528
1 <?php
3 final class PhabricatorSettingsTimezoneController
4 extends PhabricatorController {
6 public function handleRequest(AphrontRequest $request) {
7 $viewer = $this->getViewer();
9 $client_offset = $request->getURIData('offset');
10 $client_offset = (int)$client_offset;
12 $timezones = DateTimeZone::listIdentifiers();
13 $now = new DateTime('@'.PhabricatorTime::getNow());
15 $options = array(
16 'ignore' => pht('Ignore Conflict'),
19 foreach ($timezones as $identifier) {
20 $zone = new DateTimeZone($identifier);
21 $offset = -($zone->getOffset($now) / 60);
22 if ($offset == $client_offset) {
23 $name = PhabricatorTime::getTimezoneDisplayName($identifier);
24 $options[$identifier] = $name;
28 $settings_help = pht(
29 'You can change your date and time preferences in Settings.');
31 $did_calibrate = false;
32 if ($request->isFormPost()) {
33 $timezone = $request->getStr('timezone');
35 $pref_ignore = PhabricatorTimezoneIgnoreOffsetSetting::SETTINGKEY;
36 $pref_timezone = PhabricatorTimezoneSetting::SETTINGKEY;
38 if ($timezone == 'ignore') {
39 $this->writeSettings(
40 array(
41 $pref_ignore => $client_offset,
42 ));
44 return $this->newDialog()
45 ->setTitle(pht('Conflict Ignored'))
46 ->appendParagraph(
47 pht(
48 'The conflict between your browser and profile timezone '.
49 'settings will be ignored.'))
50 ->appendParagraph($settings_help)
51 ->addCancelButton('/', pht('Done'));
54 if (isset($options[$timezone])) {
55 $this->writeSettings(
56 array(
57 $pref_ignore => null,
58 $pref_timezone => $timezone,
59 ));
61 $did_calibrate = true;
65 $server_offset = $viewer->getTimeZoneOffset();
67 if (($client_offset == $server_offset) || $did_calibrate) {
68 return $this->newDialog()
69 ->setTitle(pht('Timezone Calibrated'))
70 ->appendParagraph(
71 pht(
72 'Your browser timezone and profile timezone are now '.
73 'in agreement (%s).',
74 $this->formatOffset($client_offset)))
75 ->appendParagraph($settings_help)
76 ->addCancelButton('/', pht('Done'));
79 // If we have a guess at the timezone from the client, select it as the
80 // default.
81 $guess = $request->getStr('guess');
82 if (empty($options[$guess])) {
83 $guess = 'ignore';
86 $current_zone = $viewer->getTimezoneIdentifier();
87 $current_zone = phutil_tag('strong', array(), $current_zone);
89 $form = id(new AphrontFormView())
90 ->appendChild(
91 id(new AphrontFormMarkupControl())
92 ->setLabel(pht('Current Setting'))
93 ->setValue($current_zone))
94 ->appendChild(
95 id(new AphrontFormSelectControl())
96 ->setName('timezone')
97 ->setLabel(pht('New Setting'))
98 ->setOptions($options)
99 ->setValue($guess));
101 return $this->newDialog()
102 ->setTitle(pht('Adjust Timezone'))
103 ->setWidth(AphrontDialogView::WIDTH_FORM)
104 ->appendParagraph(
105 pht(
106 'Your browser timezone (%s) differs from your profile timezone '.
107 '(%s). You can ignore this conflict or adjust your profile setting '.
108 'to match your client.',
109 $this->formatOffset($client_offset),
110 $this->formatOffset($server_offset)))
111 ->appendForm($form)
112 ->addCancelButton(pht('Cancel'))
113 ->addSubmitButton(pht('Change Timezone'));
116 private function formatOffset($offset) {
117 // This controller works with client-side (Javascript) offsets, which have
118 // the opposite sign we might expect -- for example "UTC-3" is a positive
119 // offset. Invert the sign before rendering the offset.
120 $offset = -1 * $offset;
122 $hours = $offset / 60;
123 // Non-integer number of hours off UTC?
124 if ($offset % 60) {
125 $minutes = abs($offset % 60);
126 return pht('UTC%+d:%02d', $hours, $minutes);
127 } else {
128 return pht('UTC%+d', $hours);
132 private function writeSettings(array $map) {
133 $request = $this->getRequest();
134 $viewer = $this->getViewer();
136 $preferences = PhabricatorUserPreferences::loadUserPreferences($viewer);
138 $editor = id(new PhabricatorUserPreferencesEditor())
139 ->setActor($viewer)
140 ->setContentSourceFromRequest($request)
141 ->setContinueOnNoEffect(true)
142 ->setContinueOnMissingFields(true);
144 $xactions = array();
145 foreach ($map as $key => $value) {
146 $xactions[] = $preferences->newTransaction($key, $value);
149 $editor->applyTransactions($preferences, $xactions);