From d3b7071e70f75766cce54f6868222ffc5176374d Mon Sep 17 00:00:00 2001 From: lkassianik Date: Mon, 15 Jun 2015 09:26:33 -0700 Subject: [PATCH 1/9] Add date format preference and respect it in date selection controls Summary: Ref T8362, Add date format preference and respect it in date selection controls Test Plan: Set date format preference in the user settings panels, create new event, select new start date in the correct format. Reviewers: epriestley, #blessed_reviewers Reviewed By: epriestley, #blessed_reviewers Subscribers: jasonrumney, eadler, epriestley, Korvin Maniphest Tasks: T8362 Differential Revision: https://secure.phabricator.com/D13262 --- .../PhabricatorDateTimeSettingsPanel.php | 29 ++++- .../storage/PhabricatorUserPreferences.php | 1 + .../form/control/AphrontFormDateControl.php | 20 +++- .../control/AphrontFormDateControlValue.php | 64 ++++++++++- .../rsrc/js/core/behavior-fancy-datepicker.js | 108 ++++++++++++++++-- 5 files changed, 199 insertions(+), 23 deletions(-) diff --git a/src/applications/settings/panel/PhabricatorDateTimeSettingsPanel.php b/src/applications/settings/panel/PhabricatorDateTimeSettingsPanel.php index 45f9f3fa01..7c70089836 100644 --- a/src/applications/settings/panel/PhabricatorDateTimeSettingsPanel.php +++ b/src/applications/settings/panel/PhabricatorDateTimeSettingsPanel.php @@ -19,6 +19,7 @@ final class PhabricatorDateTimeSettingsPanel extends PhabricatorSettingsPanel { $username = $user->getUsername(); $pref_time = PhabricatorUserPreferences::PREFERENCE_TIME_FORMAT; + $pref_date = PhabricatorUserPreferences::PREFERENCE_DATE_FORMAT; $pref_week_start = PhabricatorUserPreferences::PREFERENCE_WEEK_START_DAY; $preferences = $user->loadPreferences(); @@ -31,12 +32,16 @@ final class PhabricatorDateTimeSettingsPanel extends PhabricatorSettingsPanel { $errors[] = pht('The selected timezone is not a valid timezone.'); } - $preferences->setPreference( - $pref_time, - $request->getStr($pref_time)); - $preferences->setPreference( - $pref_week_start, - $request->getStr($pref_week_start)); + $preferences + ->setPreference( + $pref_time, + $request->getStr($pref_time)) + ->setPreference( + $pref_date, + $request->getStr($pref_date)) + ->setPreference( + $pref_week_start, + $request->getStr($pref_week_start)); if (!$errors) { $preferences->save(); @@ -69,6 +74,18 @@ final class PhabricatorDateTimeSettingsPanel extends PhabricatorSettingsPanel { ->setCaption( pht('Format used when rendering a time of day.')) ->setValue($preferences->getPreference($pref_time))) + ->appendChild( + id(new AphrontFormSelectControl()) + ->setLabel(pht('Date Format')) + ->setName($pref_date) + ->setOptions(array( + 'Y-m-d' => pht('ISO 8601 (2000-02-28)'), + 'n/j/Y' => pht('US (2/28/2000)'), + 'd-m-Y' => pht('European (28-02-2000)'), + )) + ->setCaption( + pht('Format used when rendering a date.')) + ->setValue($preferences->getPreference($pref_date))) ->appendChild( id(new AphrontFormSelectControl()) ->setLabel(pht('Week Starts On')) diff --git a/src/applications/settings/storage/PhabricatorUserPreferences.php b/src/applications/settings/storage/PhabricatorUserPreferences.php index d54cf6cb46..cb04f59392 100644 --- a/src/applications/settings/storage/PhabricatorUserPreferences.php +++ b/src/applications/settings/storage/PhabricatorUserPreferences.php @@ -8,6 +8,7 @@ final class PhabricatorUserPreferences extends PhabricatorUserDAO { const PREFERENCE_MULTIEDIT = 'multiedit'; const PREFERENCE_TITLES = 'titles'; const PREFERENCE_MONOSPACED_TEXTAREAS = 'monospaced-textareas'; + const PREFERENCE_DATE_FORMAT = 'date-format'; const PREFERENCE_TIME_FORMAT = 'time-format'; const PREFERENCE_WEEK_START_DAY = 'week-start-day'; diff --git a/src/view/form/control/AphrontFormDateControl.php b/src/view/form/control/AphrontFormDateControl.php index 6f826cf830..4bf7619875 100644 --- a/src/view/form/control/AphrontFormDateControl.php +++ b/src/view/form/control/AphrontFormDateControl.php @@ -127,7 +127,21 @@ final class AphrontFormDateControl extends AphrontFormControl { } private function getDateInputValue() { - return $this->valueDate; + $date_format = $this->getDateFormat(); + $timezone = $this->getTimezone(); + + $datetime = new DateTime($this->valueDate, $timezone); + $date = $datetime->format($date_format); + + return $date; + } + + private function getDateFormat() { + $viewer = $this->getUser(); + $preferences = $viewer->loadPreferences(); + $pref_date_format = PhabricatorUserPreferences::PREFERENCE_DATE_FORMAT; + + return $preferences->getPreference($pref_date_format, 'Y-m-d'); } private function getTimeInputValue() { @@ -242,7 +256,9 @@ final class AphrontFormDateControl extends AphrontFormControl { ), $time_sel); - Javelin::initBehavior('fancy-datepicker', array()); + Javelin::initBehavior('fancy-datepicker', array( + 'format' => $this->getDateFormat(), + )); $classes = array(); $classes[] = 'aphront-form-date-container'; diff --git a/src/view/form/control/AphrontFormDateControlValue.php b/src/view/form/control/AphrontFormDateControlValue.php index 43fb42664e..c084eecf2a 100644 --- a/src/view/form/control/AphrontFormDateControlValue.php +++ b/src/view/form/control/AphrontFormDateControlValue.php @@ -10,6 +10,7 @@ final class AphrontFormDateControlValue extends Phobject { private $zone; private $optional; + public function getValueDate() { return $this->valueDate; } @@ -65,7 +66,11 @@ final class AphrontFormDateControlValue extends Phobject { $value = new AphrontFormDateControlValue(); $value->viewer = $viewer; - $value->valueDate = $month.'/'.$day.'/'.$year; + $value->valueDate = $value->getFormattedDateFromParts( + $year, + $month, + $day, + $value); $value->valueTime = coalesce($time, '12:00 AM'); $value->valueEnabled = $enabled; @@ -75,10 +80,13 @@ final class AphrontFormDateControlValue extends Phobject { public static function newFromRequest(AphrontRequest $request, $key) { $value = new AphrontFormDateControlValue(); $value->viewer = $request->getViewer(); - $value->valueDate = $request->getStr($key.'_d'); + + $value->valueDate = $value->getFormattedDateFromDate( + $request->getStr($key.'_d'), + $value); + $value->valueTime = $request->getStr($key.'_t'); $value->valueEnabled = $request->getStr($key.'_e'); - return $value; } @@ -92,7 +100,11 @@ final class AphrontFormDateControlValue extends Phobject { $month = $readable[1]; $day = $readable[2]; - $value->valueDate = $month.'/'.$day.'/'.$year; + $value->valueDate = $value->getFormattedDateFromParts( + $year, + $month, + $day, + $value); $value->valueTime = $readable[3]; @@ -105,7 +117,10 @@ final class AphrontFormDateControlValue extends Phobject { $value = new AphrontFormDateControlValue(); $value->viewer = $viewer; - $value->valueDate = idx($dictionary, 'd'); + $value->valueDate = $value->getFormattedDateFromDate( + idx($dictionary, 'd'), + $value); + $value->valueTime = idx($dictionary, 't'); $value->valueEnabled = idx($dictionary, 'e'); @@ -185,6 +200,45 @@ final class AphrontFormDateControlValue extends Phobject { return $value; } + private function getDateFormat() { + $preferences = $this->viewer->loadPreferences(); + $pref_date_format = PhabricatorUserPreferences::PREFERENCE_DATE_FORMAT; + + return $preferences->getPreference($pref_date_format, 'Y-m-d'); + } + + private function getFormattedDateFromDate($date, $value) { + $original_input = $date; + $zone = $value->getTimezone(); + $separator = $value->getFormatSeparator(); + $parts = preg_split('@[,./:-]@', $date); + $date = implode($separator, $parts); + $date = id(new DateTime($date, $zone)); + + if ($date) { + return $date->format($value->getDateFormat()); + } else { + return $original_input; + } + } + + private function getFormattedDateFromParts($year, $month, $day, $value) { + $zone = $value->getTimezone(); + + return id(new DateTime("{$year}-{$month}-{$day}", $zone)) + ->format($value->getDateFormat()); + } + + private function getFormatSeparator() { + $format = $this->getDateFormat(); + switch ($format) { + case 'n/j/Y': + return '/'; + default: + return '-'; + } + } + public function getDateTime() { $epoch = $this->getEpoch(); $date = null; diff --git a/webroot/rsrc/js/core/behavior-fancy-datepicker.js b/webroot/rsrc/js/core/behavior-fancy-datepicker.js index d00f6cc77f..99feaa31f2 100644 --- a/webroot/rsrc/js/core/behavior-fancy-datepicker.js +++ b/webroot/rsrc/js/core/behavior-fancy-datepicker.js @@ -7,7 +7,11 @@ * javelin-vector */ -JX.behavior('fancy-datepicker', function() { +JX.behavior('fancy-datepicker', function(config, statics) { + if (statics.initialized) { + return; + } + statics.initialized = true; var picker; var root; @@ -16,6 +20,32 @@ JX.behavior('fancy-datepicker', function() { var value_m; var value_d; + var get_format_separator = function() { + var format = get_format(); + switch (format.toLowerCase()) { + case 'n/j/y': + return '/'; + default: + return '-'; + } + }; + + var get_key_maps = function() { + var format = get_format(); + var regex = new RegExp('[./ -]'); + return format.split(regex); + }; + + var get_format = function() { + var format = config.format; + + if (format === null) { + format = 'Y-m-d'; + } + + return format; + }; + var onopen = function(e) { e.kill(); @@ -85,18 +115,76 @@ JX.behavior('fancy-datepicker', function() { }; }; - var read_date = function() { - var i = get_inputs(); - var date = i.d.value; - var parts = date.split('/'); - value_y = +parts[2]; - value_m = +parts[0]; - value_d = +parts[1]; + var read_date = function(){ + var inputs = get_inputs(); + var date = inputs.d.value; + var regex = new RegExp('[./ -]'); + var date_parts = date.split(regex); + var map = get_key_maps(); + + for (var i=0; i < date_parts.length; i++) { + var key = map[i].toLowerCase(); + + switch (key) { + case 'y': + value_y = date_parts[i]; + break; + case 'm': + value_m = date_parts[i]; + break; + case 'd': + value_d = date_parts[i]; + break; + } + } }; var write_date = function() { - var i = get_inputs(); - i.d.value = value_m + '/' + value_d + '/' + value_y; + var inputs = get_inputs(); + var map = get_key_maps(); + var arr_values = []; + + for(var i=0; i < map.length; i++) { + switch (map[i].toLowerCase()) { + case 'y': + arr_values[i] = value_y; + break; + case 'm': + arr_values[i] = value_m; + break; + case 'n': + arr_values[i] = value_m; + break; + case 'd': + arr_values[i] = value_d; + break; + case 'j': + arr_values[i] = value_d; + break; + } + } + + var text_value = ''; + var separator = get_format_separator(); + + for(var j=0; j < arr_values.length; j++) { + var element = arr_values[j]; + var format = get_format(); + + if ((format.toLowerCase() === 'd-m-y' || + format.toLowerCase() === 'y-m-d') && + element < 10) { + element = '0' + element; + } + + if (text_value.length === 0) { + text_value += element; + } else { + text_value = text_value + separator + element; + } + } + + inputs.d.value = text_value; }; var render = function() { From e6b6c42f76f89e8419501ccd58644a42cac69528 Mon Sep 17 00:00:00 2001 From: lkassianik Date: Mon, 15 Jun 2015 10:02:43 -0700 Subject: [PATCH 2/9] Make event lists respect the user preference for time format. Summary: Ref T8362, Make event lists respect the user preference for time format Test Plan: Set time format preference to 24-hour format, open Calendar month view, all events should show time tips in 24-hour format. Reviewers: epriestley, #blessed_reviewers Reviewed By: epriestley, #blessed_reviewers Subscribers: epriestley, Korvin Maniphest Tasks: T8362 Differential Revision: https://secure.phabricator.com/D13290 --- src/view/phui/calendar/PHUICalendarListView.php | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/view/phui/calendar/PHUICalendarListView.php b/src/view/phui/calendar/PHUICalendarListView.php index 1e0639262d..80468dcb62 100644 --- a/src/view/phui/calendar/PHUICalendarListView.php +++ b/src/view/phui/calendar/PHUICalendarListView.php @@ -141,6 +141,12 @@ final class PHUICalendarListView extends AphrontTagView { } private function getEventTooltip(AphrontCalendarEventView $event) { + $viewer = $this->getUser(); + $preferences = $viewer->loadPreferences(); + $time_pref = $preferences->getPreference( + PhabricatorUserPreferences::PREFERENCE_TIME_FORMAT, + 'g:i A'); + Javelin::initBehavior('phabricator-tooltips'); $start = id(AphrontFormDateControlValue::newFromEpoch( @@ -166,13 +172,13 @@ final class PHUICalendarListView extends AphrontTagView { if ($start->getValueDate() == $end->getValueDate()) { $tip = pht( '%s - %s', - $start->getValueAsFormat('g:i A'), - $end->getValueAsFormat('g:i A')); + $start->getValueAsFormat($time_pref), + $end->getValueAsFormat($time_pref)); } else { $tip = pht( '%s - %s', - $start->getValueAsFormat('M j, Y, g:i A'), - $end->getValueAsFormat('M j, Y, g:i A')); + $start->getValueAsFormat('M j, Y, '.$time_pref), + $end->getValueAsFormat('M j, Y, '.$time_pref)); } } return $tip; From 86a908d3b9ed7b4374243f6c265a630a23e83221 Mon Sep 17 00:00:00 2001 From: lkassianik Date: Mon, 15 Jun 2015 10:11:10 -0700 Subject: [PATCH 3/9] Date controls should respect user time preferences Summary: Ref T8362, Date controls should respect user time preferences Test Plan: Set user time preference to 24-hour format, create an event, type 23 in time input, 23:00 should be suggested. Saveing a 24-hour format time should save correctly. Reviewers: #blessed_reviewers, epriestley Reviewed By: #blessed_reviewers, epriestley Subscribers: epriestley, Korvin Maniphest Tasks: T8362 Differential Revision: https://secure.phabricator.com/D13291 --- .../form/control/AphrontFormDateControl.php | 32 ++++++-- .../control/AphrontFormDateControlValue.php | 80 ++++++++++++------- .../rsrc/js/core/behavior-time-typeahead.js | 71 ++++++++++------ 3 files changed, 127 insertions(+), 56 deletions(-) diff --git a/src/view/form/control/AphrontFormDateControl.php b/src/view/form/control/AphrontFormDateControl.php index 4bf7619875..20172593e9 100644 --- a/src/view/form/control/AphrontFormDateControl.php +++ b/src/view/form/control/AphrontFormDateControl.php @@ -136,6 +136,14 @@ final class AphrontFormDateControl extends AphrontFormControl { return $date; } + private function getTimeFormat() { + $viewer = $this->getUser(); + $preferences = $viewer->loadPreferences(); + $pref_time_format = PhabricatorUserPreferences::PREFERENCE_TIME_FORMAT; + + return $preferences->getPreference($pref_time_format, 'g:i A'); + } + private function getDateFormat() { $viewer = $this->getUser(); $preferences = $viewer->loadPreferences(); @@ -233,6 +241,7 @@ final class AphrontFormDateControl extends AphrontFormControl { 'startTimeID' => $time_id, 'endTimeID' => $this->endDateID, 'timeValues' => $values, + 'format' => $this->getTimeFormat(), )); @@ -335,20 +344,31 @@ final class AphrontFormDateControl extends AphrontFormControl { } private function getTimeTypeaheadValues() { + $time_format = $this->getTimeFormat(); $times = array(); - $am_pm_list = array('AM', 'PM'); - foreach ($am_pm_list as $am_pm) { - for ($hour = 0; $hour < 12; $hour++) { - $actual_hour = ($hour == 0) ? 12 : $hour; - $times[] = $actual_hour.':00 '.$am_pm; - $times[] = $actual_hour.':30 '.$am_pm; + if ($time_format == 'g:i A') { + $am_pm_list = array('AM', 'PM'); + + foreach ($am_pm_list as $am_pm) { + for ($hour = 0; $hour < 12; $hour++) { + $actual_hour = ($hour == 0) ? 12 : $hour; + $times[] = $actual_hour.':00 '.$am_pm; + $times[] = $actual_hour.':30 '.$am_pm; + } + } + } else if ($time_format == 'H:i') { + for ($hour = 0; $hour < 24; $hour++) { + $written_hour = ($hour > 9) ? $hour : '0'.$hour; + $times[] = $written_hour.':00'; + $times[] = $written_hour.':30'; } } foreach ($times as $key => $time) { $times[$key] = array($key, $time); } + return $times; } diff --git a/src/view/form/control/AphrontFormDateControlValue.php b/src/view/form/control/AphrontFormDateControlValue.php index c084eecf2a..c5d7e81852 100644 --- a/src/view/form/control/AphrontFormDateControlValue.php +++ b/src/view/form/control/AphrontFormDateControlValue.php @@ -66,12 +66,13 @@ final class AphrontFormDateControlValue extends Phobject { $value = new AphrontFormDateControlValue(); $value->viewer = $viewer; - $value->valueDate = $value->getFormattedDateFromParts( - $year, - $month, - $day, - $value); - $value->valueTime = coalesce($time, '12:00 AM'); + list($value->valueDate, $value->valueTime) = + $value->getFormattedDateFromParts( + $year, + $month, + $day, + coalesce($time, '12:00 AM'), + $value); $value->valueEnabled = $enabled; return $value; @@ -81,11 +82,12 @@ final class AphrontFormDateControlValue extends Phobject { $value = new AphrontFormDateControlValue(); $value->viewer = $request->getViewer(); - $value->valueDate = $value->getFormattedDateFromDate( - $request->getStr($key.'_d'), - $value); + list($value->valueDate, $value->valueTime) = + $value->getFormattedDateFromDate( + $request->getStr($key.'_d'), + $request->getStr($key.'_t'), + $value); - $value->valueTime = $request->getStr($key.'_t'); $value->valueEnabled = $request->getStr($key.'_e'); return $value; } @@ -99,14 +101,15 @@ final class AphrontFormDateControlValue extends Phobject { $year = $readable[0]; $month = $readable[1]; $day = $readable[2]; + $time = $readable[3]; - $value->valueDate = $value->getFormattedDateFromParts( - $year, - $month, - $day, - $value); - $value->valueTime = $readable[3]; - + list($value->valueDate, $value->valueTime) = + $value->getFormattedDateFromParts( + $year, + $month, + $day, + $time, + $value); return $value; } @@ -117,11 +120,12 @@ final class AphrontFormDateControlValue extends Phobject { $value = new AphrontFormDateControlValue(); $value->viewer = $viewer; - $value->valueDate = $value->getFormattedDateFromDate( - idx($dictionary, 'd'), - $value); + list($value->valueDate, $value->valueTime) = + $value->getFormattedDateFromDate( + idx($dictionary, 'd'), + idx($dictionary, 't'), + $value); - $value->valueTime = idx($dictionary, 't'); $value->valueEnabled = idx($dictionary, 'e'); return $value; @@ -200,6 +204,13 @@ final class AphrontFormDateControlValue extends Phobject { return $value; } + private function getTimeFormat() { + $preferences = $this->viewer->loadPreferences(); + $pref_time_format = PhabricatorUserPreferences::PREFERENCE_TIME_FORMAT; + + return $preferences->getPreference($pref_time_format, 'g:i A'); + } + private function getDateFormat() { $preferences = $this->viewer->loadPreferences(); $pref_date_format = PhabricatorUserPreferences::PREFERENCE_DATE_FORMAT; @@ -207,7 +218,7 @@ final class AphrontFormDateControlValue extends Phobject { return $preferences->getPreference($pref_date_format, 'Y-m-d'); } - private function getFormattedDateFromDate($date, $value) { + private function getFormattedDateFromDate($date, $time, $value) { $original_input = $date; $zone = $value->getTimezone(); $separator = $value->getFormatSeparator(); @@ -216,17 +227,32 @@ final class AphrontFormDateControlValue extends Phobject { $date = id(new DateTime($date, $zone)); if ($date) { - return $date->format($value->getDateFormat()); + $date = $date->format($value->getDateFormat()); } else { - return $original_input; + $date = $original_input; } + + $date = id(new DateTime("{$date} {$time}", $zone)); + + return array( + $date->format($value->getDateFormat()), + $date->format($value->getTimeFormat()), + ); } - private function getFormattedDateFromParts($year, $month, $day, $value) { + private function getFormattedDateFromParts( + $year, + $month, + $day, + $time, + $value) { $zone = $value->getTimezone(); + $date_time = id(new DateTime("{$year}-{$month}-{$day} {$time}", $zone)); - return id(new DateTime("{$year}-{$month}-{$day}", $zone)) - ->format($value->getDateFormat()); + return array( + $date_time->format($value->getDateFormat()), + $date_time->format($value->getTimeFormat()), + ); } private function getFormatSeparator() { diff --git a/webroot/rsrc/js/core/behavior-time-typeahead.js b/webroot/rsrc/js/core/behavior-time-typeahead.js index 381eea7f36..bbd5e08699 100644 --- a/webroot/rsrc/js/core/behavior-time-typeahead.js +++ b/webroot/rsrc/js/core/behavior-time-typeahead.js @@ -11,6 +11,7 @@ JX.behavior('time-typeahead', function(config) { var start_date_control = JX.$(config.startTimeID); var end_date_control = config.endTimeID ? JX.$(config.endTimeID) : null; + var format = config.format; var end_date_tampered = false; @@ -79,7 +80,7 @@ JX.behavior('time-typeahead', function(config) { function getNewValue(time) { - var regex = /^([01]?\d)(?::([0-5]\d))?\s*((am|pm))?$/i; + var regex = /^([0-2]?\d)(?::([0-5]\d))?\s*((am|pm))?$/i; if (!regex.test(time)) { return null; @@ -90,32 +91,56 @@ JX.behavior('time-typeahead', function(config) { var minutes = parseInt(results[2], 10) ? parseInt(results[2], 10) : 0; var real_time = 0; + var end_value = ''; - if (/pm/i.test(results[3])) { - real_time = 12*60; - } else if (/am/i.test(results[3]) && hours == 12) { - hours = 0; + var end_hours; + var end_minutes; + + if (format === 'H:i' && hours < 23) { + end_hours = hours + 1; + + if (end_hours > 9) { + end_hours = end_hours.toString(); + } else { + end_hours = '0' + end_hours.toString(); + } + + if (minutes > 9) { + end_minutes = minutes.toString(); + } else { + end_minutes = '0' + minutes.toString(); + } + + end_value = end_hours + ':' + end_minutes; + } else if (format === 'g:i A') { + if (/pm/i.test(results[3])) { + real_time = 12*60; + } else if (/am/i.test(results[3]) && hours == 12) { + hours = 0; + } + + real_time = real_time + (hours * 60) + minutes; + + var end_time = real_time + 60; + + var end_meridian = 'AM'; + end_hours = Math.floor(end_time / 60); + + if (end_hours == 12) { + end_meridian = 'PM'; + } else if (end_hours > 12 && end_hours < 24) { + end_hours = end_hours - 12; + end_meridian = 'PM'; + } else if (end_hours == 24) { + end_hours = end_hours - 12; + } + + end_minutes = end_time%60; + end_minutes = (end_minutes < 9) ? end_minutes : ('0' + end_minutes); + end_value = end_hours + ':' + end_minutes + ' ' + end_meridian; } - real_time = real_time + (hours * 60) + minutes; - var end_time = real_time + 60; - - var end_meridian = 'AM'; - var end_hours = Math.floor(end_time / 60); - - if (end_hours == 12) { - end_meridian = 'PM'; - } else if (end_hours > 12 && end_hours < 24) { - end_hours = end_hours - 12; - end_meridian = 'PM'; - } else if (end_hours == 24) { - end_hours = end_hours - 12; - } - - var end_minutes = end_time%60; - end_minutes = (end_minutes > 9) ? end_minutes : ('0' + end_minutes); - var end_value = end_hours + ':' + end_minutes + ' ' + end_meridian; return end_value; } From 30e6203d8c453e74a8c40c9bc561151d45c07030 Mon Sep 17 00:00:00 2001 From: lkassianik Date: Mon, 15 Jun 2015 11:52:57 -0700 Subject: [PATCH 4/9] Creating a recurring event should save it as a recurring event. Summary: Fixes T8551, Creating a recurring event should save it as a recurring event Test Plan: Before patch: -create an event -flag as recurring -save -Result: event is not recurring -After patch Result: event saves as recurring. Reviewers: #blessed_reviewers, epriestley Reviewed By: #blessed_reviewers, epriestley Subscribers: epriestley, Korvin Maniphest Tasks: T8551 Differential Revision: https://secure.phabricator.com/D13302 --- .../controller/PhabricatorCalendarEventEditController.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/applications/calendar/controller/PhabricatorCalendarEventEditController.php b/src/applications/calendar/controller/PhabricatorCalendarEventEditController.php index 218fe17371..47736f38fe 100644 --- a/src/applications/calendar/controller/PhabricatorCalendarEventEditController.php +++ b/src/applications/calendar/controller/PhabricatorCalendarEventEditController.php @@ -191,7 +191,7 @@ final class PhabricatorCalendarEventEditController PhabricatorCalendarEventTransaction::TYPE_NAME) ->setNewValue($name); - if ($is_parent && $this->isCreate()) { + if ($is_recurring && $this->isCreate()) { $xactions[] = id(new PhabricatorCalendarEventTransaction()) ->setTransactionType( PhabricatorCalendarEventTransaction::TYPE_RECURRING) @@ -210,7 +210,7 @@ final class PhabricatorCalendarEventEditController } } - if (($is_parent && $this->isCreate()) || !$is_parent) { + if (($is_recurring && $this->isCreate()) || !$is_parent) { $xactions[] = id(new PhabricatorCalendarEventTransaction()) ->setTransactionType( PhabricatorCalendarEventTransaction::TYPE_ALL_DAY) From 6aa494bd25239beda88f956a426cfd0d34bd2e9e Mon Sep 17 00:00:00 2001 From: epriestley Date: Mon, 15 Jun 2015 12:21:25 -0700 Subject: [PATCH 5/9] Fix missing property on HarbormasterBuildStepImplementation Auditors: joshuaspence --- .../harbormaster/step/HarbormasterBuildStepImplementation.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/applications/harbormaster/step/HarbormasterBuildStepImplementation.php b/src/applications/harbormaster/step/HarbormasterBuildStepImplementation.php index 26450722b9..64219b84c4 100644 --- a/src/applications/harbormaster/step/HarbormasterBuildStepImplementation.php +++ b/src/applications/harbormaster/step/HarbormasterBuildStepImplementation.php @@ -2,6 +2,8 @@ abstract class HarbormasterBuildStepImplementation extends Phobject { + private $settings; + public static function getImplementations() { return id(new PhutilSymbolLoader()) ->setAncestorClass(__CLASS__) From 9f1235d87512606fbaa8bba46257707513c48e4f Mon Sep 17 00:00:00 2001 From: epriestley Date: Mon, 15 Jun 2015 13:51:36 -0700 Subject: [PATCH 6/9] Fix a fatal in Calendar widget in Conpherence Summary: Fixes T8548. This needs to be cleaned up more generally at some point, but stop the bleeding for now. If a thread member is invited to an event with a non-thread-member host, we try to render the host but don't have their handle (this is a holdover from the bygone days of events as statuses). For now, just don't render anything. In the future, it might be nice to render (some of?) the attendees who are thread members, but I suspect we may revisit this widget more generally. Test Plan: - As a non thread-member, created an event and invited a thread member. - Viewed thread as thread-member. - Saw widget fatal. - Applied patch. - As thread-member, saw widget render with just "9AM-10AM", instead of "host, 9AM-10AM". Reviewers: btrahan Reviewed By: btrahan Subscribers: epriestley Maniphest Tasks: T8548 Differential Revision: https://secure.phabricator.com/D13299 --- .../controller/ConpherenceWidgetController.php | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/applications/conpherence/controller/ConpherenceWidgetController.php b/src/applications/conpherence/controller/ConpherenceWidgetController.php index 01a36f6ea1..28bcf4520e 100644 --- a/src/applications/conpherence/controller/ConpherenceWidgetController.php +++ b/src/applications/conpherence/controller/ConpherenceWidgetController.php @@ -310,8 +310,14 @@ final class ConpherenceWidgetController extends ConpherenceController { $user, $time_str); - $secondary_info = pht('%s, %s', - $handles[$status->getUserPHID()]->getName(), $epoch_range); + if (isset($handles[$status->getUserPHID()])) { + $secondary_info = pht( + '%s, %s', + $handles[$status->getUserPHID()]->getName(), + $epoch_range); + } else { + $secondary_info = $epoch_range; + } $content[] = phutil_tag( 'div', From a1561a4d3a07013f44b54a16d03aa849fdf7e7c5 Mon Sep 17 00:00:00 2001 From: epriestley Date: Mon, 15 Jun 2015 13:52:00 -0700 Subject: [PATCH 7/9] Fix a fatal in Diviner when atoms extend ghosts Summary: Fixes T8547. I wasn't immediately able to reproduce this locally (although I didn't try too hard), but I think the issue is that when atoms extend ghosts (probably they are usually ghosts themselves?), we try to check the ghost language and fatal. Instead, don't match ghosts when figuring out what an atom extends. This could maybe be a little cleaner (match the ghosts, at lower priority, and show that they're ghosts?) but I'm not sure there's a real product use case for it, and this looks like a safer way to stop the bleeding for now. Test Plan: Poked around Diviner locally. Reviewers: joshuaspence Reviewed By: joshuaspence Subscribers: epriestley Maniphest Tasks: T8547 Differential Revision: https://secure.phabricator.com/D13300 --- src/applications/diviner/query/DivinerAtomQuery.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/applications/diviner/query/DivinerAtomQuery.php b/src/applications/diviner/query/DivinerAtomQuery.php index e01df2022d..2daa9bc3a7 100644 --- a/src/applications/diviner/query/DivinerAtomQuery.php +++ b/src/applications/diviner/query/DivinerAtomQuery.php @@ -179,6 +179,7 @@ final class DivinerAtomQuery extends PhabricatorCursorPagedPolicyAwareQuery { $xatoms = id(new DivinerAtomQuery()) ->setViewer($this->getViewer()) ->withNames($names) + ->withGhosts(false) ->needExtends(true) ->needAtoms(true) ->needChildren($this->needChildren) From 600a3e3b7c2de5d93644e0410cd354ea6752949d Mon Sep 17 00:00:00 2001 From: Joshua Spence Date: Tue, 16 Jun 2015 06:51:51 +1000 Subject: [PATCH 8/9] Only index documentable atoms for search Summary: Ref T7458. Only index documentable atoms in the search index. In particular, this prevents files and methods from being returned in search results (clicking on these search results doesn't actually work anyway). Test Plan: Actually, to get this to work I had to destroy the search index and recreate it... is this expected? Reviewers: epriestley, #blessed_reviewers Reviewed By: epriestley, #blessed_reviewers Subscribers: epriestley, Korvin Maniphest Tasks: T7458 Differential Revision: https://secure.phabricator.com/D13298 --- src/applications/diviner/search/DivinerAtomSearchIndexer.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/applications/diviner/search/DivinerAtomSearchIndexer.php b/src/applications/diviner/search/DivinerAtomSearchIndexer.php index 0e77c6e64c..ea134058f6 100644 --- a/src/applications/diviner/search/DivinerAtomSearchIndexer.php +++ b/src/applications/diviner/search/DivinerAtomSearchIndexer.php @@ -10,6 +10,10 @@ final class DivinerAtomSearchIndexer extends PhabricatorSearchDocumentIndexer { $atom = $this->loadDocumentByPHID($phid); $book = $atom->getBook(); + if (!$atom->getIsDocumentable()) { + return null; + } + $doc = $this->newDocument($phid) ->setDocumentTitle($atom->getTitle()) ->setDocumentCreated($book->getDateCreated()) From c2a2933848b6cdd18ed25dfde46a90eb9039f406 Mon Sep 17 00:00:00 2001 From: epriestley Date: Mon, 15 Jun 2015 13:52:39 -0700 Subject: [PATCH 9/9] Add missing property on PhabricatorBot Auditors: joshuaspence --- src/infrastructure/daemon/bot/PhabricatorBot.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/infrastructure/daemon/bot/PhabricatorBot.php b/src/infrastructure/daemon/bot/PhabricatorBot.php index ce66338111..6c4bfafc8a 100644 --- a/src/infrastructure/daemon/bot/PhabricatorBot.php +++ b/src/infrastructure/daemon/bot/PhabricatorBot.php @@ -15,6 +15,7 @@ final class PhabricatorBot extends PhabricatorDaemon { private $conduit; private $config; private $pollFrequency; + private $protocolAdapter; protected function run() { $argv = $this->getArgv();