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

Force date/time preferences to valid values

Summary:
Fixes T8601. To reproduce the problem:

- Set your time preference to `""` (the empty string). This isn't possible from the modern UI, but can be done with "Right Click > Inspect Element", or users may have carried it forward from an older setting (this is the case with me and @hach-que on this install).
- Load Calendar with some events.
- This parses an epoch, which sets `valueTime` to `""` (since there are no format characters in the preference) and then `getEpoch()` fails because `strlen($time)` is 0.
- Since `getEpoch()` failed, `getDateTime()` also fails.

To fix this:

- Only permit the date and time preferences to have valid values.

Test Plan:
- Loaded page before patch, saw fatal.
- Applied patch.
- No more fatal.
- Viewed tooltips, dates/times, dates/times in other apps.
- Changed my preferences, saw them respected.

Reviewers: lpriestley

Reviewed By: lpriestley

Subscribers: epriestley, hach-que

Maniphest Tasks: T8601

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

+68 -59
-1
src/__phutil_library_map__.php
··· 3290 3290 'phabricator_format_local_time' => 'view/viewutils.php', 3291 3291 'phabricator_relative_date' => 'view/viewutils.php', 3292 3292 'phabricator_time' => 'view/viewutils.php', 3293 - 'phabricator_time_format' => 'view/viewutils.php', 3294 3293 'phid_get_subtype' => 'applications/phid/utils.php', 3295 3294 'phid_get_type' => 'applications/phid/utils.php', 3296 3295 'phid_group_by_type' => 'applications/phid/utils.php',
+35
src/applications/people/storage/PhabricatorUser.php
··· 738 738 return new DateTimeZone($this->getTimezoneIdentifier()); 739 739 } 740 740 741 + public function getPreference($key) { 742 + $preferences = $this->loadPreferences(); 743 + 744 + // TODO: After T4103 and T7707 this should eventually be pushed down the 745 + // stack into modular preference definitions and role profiles. This is 746 + // just fixing T8601 and mildly anticipating those changes. 747 + $value = $preferences->getPreference($key); 748 + 749 + $allowed_values = null; 750 + switch ($key) { 751 + case PhabricatorUserPreferences::PREFERENCE_TIME_FORMAT: 752 + $allowed_values = array( 753 + 'g:i A', 754 + 'H:i', 755 + ); 756 + break; 757 + case PhabricatorUserPreferences::PREFERENCE_DATE_FORMAT: 758 + $allowed_values = array( 759 + 'Y-m-d', 760 + 'n/j/Y', 761 + 'd-m-Y', 762 + ); 763 + break; 764 + } 765 + 766 + if ($allowed_values !== null) { 767 + $allowed_values = array_fuse($allowed_values); 768 + if (empty($allowed_values[$value])) { 769 + $value = head($allowed_values); 770 + } 771 + } 772 + 773 + return $value; 774 + } 775 + 741 776 public function __toString() { 742 777 return $this->getUsername(); 743 778 }
+4 -10
src/view/form/control/AphrontFormDateControl.php
··· 137 137 } 138 138 139 139 private function getTimeFormat() { 140 - $viewer = $this->getUser(); 141 - $preferences = $viewer->loadPreferences(); 142 - $pref_time_format = PhabricatorUserPreferences::PREFERENCE_TIME_FORMAT; 143 - 144 - return $preferences->getPreference($pref_time_format, 'g:i A'); 140 + return $this->getUser() 141 + ->getPreference(PhabricatorUserPreferences::PREFERENCE_TIME_FORMAT); 145 142 } 146 143 147 144 private function getDateFormat() { 148 - $viewer = $this->getUser(); 149 - $preferences = $viewer->loadPreferences(); 150 - $pref_date_format = PhabricatorUserPreferences::PREFERENCE_DATE_FORMAT; 151 - 152 - return $preferences->getPreference($pref_date_format, 'Y-m-d'); 145 + return $this->getUser() 146 + ->getPreference(PhabricatorUserPreferences::PREFERENCE_DATE_FORMAT); 153 147 } 154 148 155 149 private function getTimeInputValue() {
+23 -28
src/view/form/control/AphrontFormDateControlValue.php
··· 10 10 private $zone; 11 11 private $optional; 12 12 13 - 14 13 public function getValueDate() { 15 14 return $this->valueDate; 16 15 } ··· 56 55 return $this->optional; 57 56 } 58 57 58 + public function getViewer() { 59 + return $this->viewer; 60 + } 61 + 59 62 public static function newFromParts( 60 63 PhabricatorUser $viewer, 61 64 $year, ··· 71 74 $year, 72 75 $month, 73 76 $day, 74 - coalesce($time, '12:00 AM'), 75 - $value); 77 + coalesce($time, '12:00 AM')); 76 78 $value->valueEnabled = $enabled; 77 79 78 80 return $value; ··· 85 87 list($value->valueDate, $value->valueTime) = 86 88 $value->getFormattedDateFromDate( 87 89 $request->getStr($key.'_d'), 88 - $request->getStr($key.'_t'), 89 - $value); 90 + $request->getStr($key.'_t')); 90 91 91 92 $value->valueEnabled = $request->getStr($key.'_e'); 92 93 return $value; ··· 108 109 $year, 109 110 $month, 110 111 $day, 111 - $time, 112 - $value); 112 + $time); 113 113 114 114 return $value; 115 115 } ··· 123 123 list($value->valueDate, $value->valueTime) = 124 124 $value->getFormattedDateFromDate( 125 125 idx($dictionary, 'd'), 126 - idx($dictionary, 't'), 127 - $value); 126 + idx($dictionary, 't')); 128 127 129 128 $value->valueEnabled = idx($dictionary, 'e'); 130 129 ··· 205 204 } 206 205 207 206 private function getTimeFormat() { 208 - $preferences = $this->viewer->loadPreferences(); 209 - $pref_time_format = PhabricatorUserPreferences::PREFERENCE_TIME_FORMAT; 210 - 211 - return $preferences->getPreference($pref_time_format, 'g:i A'); 207 + return $this->getViewer() 208 + ->getPreference(PhabricatorUserPreferences::PREFERENCE_TIME_FORMAT); 212 209 } 213 210 214 211 private function getDateFormat() { 215 - $preferences = $this->viewer->loadPreferences(); 216 - $pref_date_format = PhabricatorUserPreferences::PREFERENCE_DATE_FORMAT; 217 - 218 - return $preferences->getPreference($pref_date_format, 'Y-m-d'); 212 + return $this->getViewer() 213 + ->getPreference(PhabricatorUserPreferences::PREFERENCE_DATE_FORMAT); 219 214 } 220 215 221 - private function getFormattedDateFromDate($date, $time, $value) { 216 + private function getFormattedDateFromDate($date, $time) { 222 217 $original_input = $date; 223 - $zone = $value->getTimezone(); 224 - $separator = $value->getFormatSeparator(); 218 + $zone = $this->getTimezone(); 219 + $separator = $this->getFormatSeparator(); 225 220 $parts = preg_split('@[,./:-]@', $date); 226 221 $date = implode($separator, $parts); 227 222 $date = id(new DateTime($date, $zone)); 228 223 229 224 if ($date) { 230 - $date = $date->format($value->getDateFormat()); 225 + $date = $date->format($this->getDateFormat()); 231 226 } else { 232 227 $date = $original_input; 233 228 } ··· 235 230 $date = id(new DateTime("{$date} {$time}", $zone)); 236 231 237 232 return array( 238 - $date->format($value->getDateFormat()), 239 - $date->format($value->getTimeFormat()), 233 + $date->format($this->getDateFormat()), 234 + $date->format($this->getTimeFormat()), 240 235 ); 241 236 } 242 237 ··· 244 239 $year, 245 240 $month, 246 241 $day, 247 - $time, 248 - $value) { 249 - $zone = $value->getTimezone(); 242 + $time) { 243 + 244 + $zone = $this->getTimezone(); 250 245 $date_time = id(new DateTime("{$year}-{$month}-{$day} {$time}", $zone)); 251 246 252 247 return array( 253 - $date_time->format($value->getDateFormat()), 254 - $date_time->format($value->getTimeFormat()), 248 + $date_time->format($this->getDateFormat()), 249 + $date_time->format($this->getTimeFormat()), 255 250 ); 256 251 } 257 252
+2 -5
src/view/phui/calendar/PHUICalendarListView.php
··· 141 141 } 142 142 143 143 private function getEventTooltip(AphrontCalendarEventView $event) { 144 - $viewer = $this->getUser(); 145 - $preferences = $viewer->loadPreferences(); 146 - $time_pref = $preferences->getPreference( 147 - PhabricatorUserPreferences::PREFERENCE_TIME_FORMAT, 148 - 'g:i A'); 144 + $time_pref = $this->getUser() 145 + ->getPreference(PhabricatorUserPreferences::PREFERENCE_TIME_FORMAT); 149 146 150 147 Javelin::initBehavior('phabricator-tooltips'); 151 148
+4 -15
src/view/viewutils.php
··· 31 31 } 32 32 33 33 function phabricator_time($epoch, $user) { 34 + $time_key = PhabricatorUserPreferences::PREFERENCE_TIME_FORMAT; 34 35 return phabricator_format_local_time( 35 36 $epoch, 36 37 $user, 37 - phabricator_time_format($user)); 38 + $user->getPreference($time_key)); 38 39 } 39 40 40 41 function phabricator_datetime($epoch, $user) { 42 + $time_key = PhabricatorUserPreferences::PREFERENCE_TIME_FORMAT; 41 43 return phabricator_format_local_time( 42 44 $epoch, 43 45 $user, 44 46 pht('%s, %s', 45 47 phutil_date_format($epoch), 46 - phabricator_time_format($user))); 47 - } 48 - 49 - function phabricator_time_format($user) { 50 - $prefs = $user->loadPreferences(); 51 - 52 - $pref = $prefs->getPreference( 53 - PhabricatorUserPreferences::PREFERENCE_TIME_FORMAT); 54 - 55 - if (strlen($pref)) { 56 - return $pref; 57 - } 58 - 59 - return pht('g:i A'); 48 + $user->getPreference($time_key))); 60 49 } 61 50 62 51 /**