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

Fix calendar display on profile.

Summary:
...maybe anyway because I can't reproduce it live. This diff does two things that should help with bugginess though - uses $viewer rather than $user (...$user is who we are looking at...) *AND* upgrades a Conpherence util class to Calendar, and said util class has unit tests and came about from fixing a similar bug in Conpherence back in the day.

Wrote some comments in the util class because I think it has a tendency to trip people up. These comments are not partciularly good however.

Test Plan: viewed user profile - looked good. viewed conpherence - looked good. ran unit tests - they passed. (note I would also like to push this live and verify Chad's profile is fixed on secure.phabricator.com)

Reviewers: epriestley, chad

Reviewed By: epriestley

CC: Korvin, epriestley, aran

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

+153 -105
+3 -3
src/__phutil_library_map__.php
··· 95 95 'BuildStepImplementation' => 'applications/harbormaster/step/BuildStepImplementation.php', 96 96 'CalendarColors' => 'applications/calendar/constants/CalendarColors.php', 97 97 'CalendarConstants' => 'applications/calendar/constants/CalendarConstants.php', 98 + 'CalendarTimeUtil' => 'applications/calendar/util/CalendarTimeUtil.php', 99 + 'CalendarTimeUtilTestCase' => 'applications/calendar/__tests__/CalendarTimeUtilTestCase.php', 98 100 'CelerityAPI' => 'infrastructure/celerity/CelerityAPI.php', 99 101 'CelerityManagementMapWorkflow' => 'infrastructure/celerity/management/CelerityManagementMapWorkflow.php', 100 102 'CelerityManagementWorkflow' => 'infrastructure/celerity/management/CelerityManagementWorkflow.php', ··· 291 293 'ConpherenceThreadListView' => 'applications/conpherence/view/ConpherenceThreadListView.php', 292 294 'ConpherenceThreadMailReceiver' => 'applications/conpherence/mail/ConpherenceThreadMailReceiver.php', 293 295 'ConpherenceThreadQuery' => 'applications/conpherence/query/ConpherenceThreadQuery.php', 294 - 'ConpherenceTimeUtil' => 'applications/conpherence/util/ConpherenceTimeUtil.php', 295 - 'ConpherenceTimeUtilTestCase' => 'applications/conpherence/__tests__/ConpherenceTimeUtilTestCase.php', 296 296 'ConpherenceTransaction' => 'applications/conpherence/storage/ConpherenceTransaction.php', 297 297 'ConpherenceTransactionComment' => 'applications/conpherence/storage/ConpherenceTransactionComment.php', 298 298 'ConpherenceTransactionQuery' => 'applications/conpherence/query/ConpherenceTransactionQuery.php', ··· 2658 2658 'AphrontWebpageResponse' => 'AphrontHTMLResponse', 2659 2659 'AuditActionMenuEventListener' => 'PhabricatorEventListener', 2660 2660 'CalendarColors' => 'CalendarConstants', 2661 + 'CalendarTimeUtilTestCase' => 'PhabricatorTestCase', 2661 2662 'CelerityManagementMapWorkflow' => 'CelerityManagementWorkflow', 2662 2663 'CelerityManagementWorkflow' => 'PhabricatorManagementWorkflow', 2663 2664 'CelerityPhabricatorResourceController' => 'CelerityResourceController', ··· 2852 2853 'ConpherenceThreadListView' => 'AphrontView', 2853 2854 'ConpherenceThreadMailReceiver' => 'PhabricatorObjectMailReceiver', 2854 2855 'ConpherenceThreadQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 2855 - 'ConpherenceTimeUtilTestCase' => 'PhabricatorTestCase', 2856 2856 'ConpherenceTransaction' => 'PhabricatorApplicationTransaction', 2857 2857 'ConpherenceTransactionComment' => 'PhabricatorApplicationTransactionComment', 2858 2858 'ConpherenceTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
+86
src/applications/calendar/util/CalendarTimeUtil.php
··· 1 + <?php 2 + /** 3 + * This class is useful for generating various time objects, relative to the 4 + * user and their timezone. 5 + * 6 + * For now, the class exposes two sets of static methods for the two main 7 + * calendar views - one for the conpherence calendar widget and one for the 8 + * user profile calendar view. These have slight differences such as 9 + * conpherence showing both a three day "today 'til 2 days from now" *and* 10 + * a Sunday -> Saturday list, whilest the profile view shows a more simple 11 + * seven day rolling list of events. 12 + */ 13 + final class CalendarTimeUtil { 14 + 15 + public static function getCalendarEventEpochs( 16 + PhabricatorUser $user, 17 + $start_day_str = 'Sunday', 18 + $days = 9) { 19 + 20 + $objects = self::getStartDateTimeObjects($user, $start_day_str); 21 + $start_day = $objects['start_day']; 22 + $end_day = clone $start_day; 23 + $end_day->modify('+'.$days.' days'); 24 + 25 + return array( 26 + 'start_epoch' => $start_day->format('U'), 27 + 'end_epoch' => $end_day->format('U')); 28 + } 29 + 30 + public static function getCalendarWeekTimestamps( 31 + PhabricatorUser $user) { 32 + return self::getTimestamps($user, 'Today', 7); 33 + } 34 + 35 + public static function getCalendarWidgetTimestamps( 36 + PhabricatorUser $user) { 37 + return self::getTimestamps($user, 'Sunday', 9); 38 + } 39 + 40 + /** 41 + * Public for testing purposes only. You should probably use one of the 42 + * functions above. 43 + */ 44 + public static function getTimestamps( 45 + PhabricatorUser $user, 46 + $start_day_str, 47 + $days) { 48 + 49 + $objects = self::getStartDateTimeObjects($user, $start_day_str); 50 + $start_day = $objects['start_day']; 51 + $timestamps = array(); 52 + for ($day = 0; $day < $days; $day++) { 53 + $timestamp = clone $start_day; 54 + $timestamp->modify(sprintf('+%d days', $day)); 55 + $timestamps[] = $timestamp; 56 + } 57 + return array( 58 + 'today' => $objects['today'], 59 + 'epoch_stamps' => $timestamps); 60 + } 61 + 62 + private static function getStartDateTimeObjects( 63 + PhabricatorUser $user, 64 + $start_day_str) { 65 + $timezone = new DateTimeZone($user->getTimezoneIdentifier()); 66 + 67 + $today_epoch = PhabricatorTime::parseLocalTime('today', $user); 68 + $today = new DateTime('@'.$today_epoch); 69 + $today->setTimeZone($timezone); 70 + 71 + if (strtolower($start_day_str) == 'today' || 72 + $today->format('l') == $start_day_str) { 73 + $start_day = clone $today; 74 + } else { 75 + $start_epoch = PhabricatorTime::parseLocalTime( 76 + 'last '.$start_day_str, 77 + $user); 78 + $start_day = new DateTime('@'.$start_epoch); 79 + $start_day->setTimeZone($timezone); 80 + } 81 + return array( 82 + 'today' => $today, 83 + 'start_day' => $start_day); 84 + } 85 + 86 + }
+10 -8
src/applications/conpherence/__tests__/ConpherenceTimeUtilTestCase.php src/applications/calendar/__tests__/CalendarTimeUtilTestCase.php
··· 1 1 <?php 2 2 3 - final class ConpherenceTimeUtilTestCase extends PhabricatorTestCase { 3 + final class CalendarTimeUtilTestCase extends PhabricatorTestCase { 4 4 5 - public function testWidgetTimestampsAtMidnight() { 5 + public function testTimestampsAtMidnight() { 6 6 $u = new PhabricatorUser(); 7 7 $u->setTimezoneIdentifier('America/Los_Angeles'); 8 8 $days = $this->getAllDays(); 9 9 foreach ($days as $day) { 10 - $data = ConpherenceTimeUtil::getCalendarWidgetTimestamps( 10 + $data = CalendarTimeUtil::getCalendarWidgetTimestamps( 11 11 $u, 12 12 $day); 13 13 ··· 17 17 } 18 18 } 19 19 20 - public function testWidgetTimestampsStartDay() { 20 + public function testTimestampsStartDay() { 21 21 $u = new PhabricatorUser(); 22 22 $u->setTimezoneIdentifier('America/Los_Angeles'); 23 23 $days = $this->getAllDays(); 24 24 foreach ($days as $day) { 25 - $data = ConpherenceTimeUtil::getCalendarWidgetTimestamps( 25 + $data = CalendarTimeUtil::getTimestamps( 26 26 $u, 27 - $day); 27 + $day, 28 + 1); 28 29 29 30 $this->assertEqual( 30 31 $day, ··· 34 35 $t = 1370202281; // 2013-06-02 12:44:41 -0700 -- a Sunday 35 36 $time = PhabricatorTime::pushTime($t, 'America/Los_Angeles'); 36 37 foreach ($days as $day) { 37 - $data = ConpherenceTimeUtil::getCalendarWidgetTimestamps( 38 + $data = CalendarTimeUtil::getTimestamps( 38 39 $u, 39 - $day); 40 + $day, 41 + 1); 40 42 41 43 $this->assertEqual( 42 44 $day,
+1 -1
src/applications/conpherence/controller/ConpherenceWidgetController.php
··· 200 200 $content = array(); 201 201 $layout = id(new AphrontMultiColumnView()) 202 202 ->setFluidLayout(true); 203 - $timestamps = ConpherenceTimeUtil::getCalendarWidgetTimestamps($user); 203 + $timestamps = CalendarTimeUtil::getCalendarWidgetTimestamps($user); 204 204 $today = $timestamps['today']; 205 205 $epoch_stamps = $timestamps['epoch_stamps']; 206 206 $one_day = 24 * 60 * 60;
+1 -1
src/applications/conpherence/query/ConpherenceThreadQuery.php
··· 217 217 $participant_phids = array_mergev($participant_phids); 218 218 $file_phids = array_mergev($file_phids); 219 219 220 - $epochs = ConpherenceTimeUtil::getCalendarEventEpochs( 220 + $epochs = CalendarTimeUtil::getCalendarEventEpochs( 221 221 $this->getViewer()); 222 222 $start_epoch = $epochs['start_epoch']; 223 223 $end_epoch = $epochs['end_epoch'];
-60
src/applications/conpherence/util/ConpherenceTimeUtil.php
··· 1 - <?php 2 - 3 - final class ConpherenceTimeUtil { 4 - 5 - public static function getCalendarEventEpochs( 6 - PhabricatorUser $user, 7 - $start_day_str = 'Sunday') { 8 - 9 - $objects = self::getStartDateTimeObjects($user, $start_day_str); 10 - $start_day = $objects['start_day']; 11 - $end_day = clone $start_day; 12 - $end_day->modify('+9 days'); 13 - 14 - return array( 15 - 'start_epoch' => $start_day->format('U'), 16 - 'end_epoch' => $end_day->format('U')); 17 - } 18 - 19 - public static function getCalendarWidgetTimestamps( 20 - PhabricatorUser $user, 21 - $start_day_str = 'Sunday') { 22 - 23 - $objects = self::getStartDateTimeObjects($user, $start_day_str); 24 - $start_day = $objects['start_day']; 25 - $timestamps = array(); 26 - for ($day = 0; $day < 9; $day++) { 27 - $timestamp = clone $start_day; 28 - $timestamp->modify(sprintf('+%d days', $day)); 29 - $timestamps[] = $timestamp; 30 - } 31 - return array( 32 - 'today' => $objects['today'], 33 - 'epoch_stamps' => $timestamps 34 - ); 35 - } 36 - 37 - private static function getStartDateTimeObjects( 38 - PhabricatorUser $user, 39 - $start_day_str) { 40 - $timezone = new DateTimeZone($user->getTimezoneIdentifier()); 41 - 42 - $today_epoch = PhabricatorTime::parseLocalTime('today', $user); 43 - $today = new DateTime('@'.$today_epoch); 44 - $today->setTimeZone($timezone); 45 - 46 - if ($today->format('l') == $start_day_str) { 47 - $start_day = clone $today; 48 - } else { 49 - $start_epoch = PhabricatorTime::parseLocalTime( 50 - 'last '.$start_day_str, 51 - $user); 52 - $start_day = new DateTime('@'.$start_epoch); 53 - $start_day->setTimeZone($timezone); 54 - } 55 - return array( 56 - 'today' => $today, 57 - 'start_day' => $start_day); 58 - } 59 - 60 - }
+52 -32
src/applications/people/controller/PhabricatorPeopleProfileController.php
··· 141 141 } 142 142 143 143 private function renderUserCalendar(PhabricatorUser $user) { 144 - $now = time(); 145 - $year = phabricator_format_local_time($now, $user, 'Y'); 146 - $month = phabricator_format_local_time($now, $user, 'm'); 147 - $day = phabricator_format_local_time($now, $user, 'j'); 144 + $viewer = $this->getRequest()->getUser(); 145 + $epochs = CalendarTimeUtil::getCalendarEventEpochs( 146 + $viewer, 147 + 'today', 148 + 7); 149 + $start_epoch = $epochs['start_epoch']; 150 + $end_epoch = $epochs['end_epoch']; 148 151 $statuses = id(new PhabricatorCalendarEventQuery()) 149 - ->setViewer($user) 152 + ->setViewer($viewer) 150 153 ->withInvitedPHIDs(array($user->getPHID())) 151 - ->withDateRange( 152 - strtotime("{$year}-{$month}-{$day}"), 153 - strtotime("{$year}-{$month}-{$day} +7 days")) 154 + ->withDateRange($start_epoch, $end_epoch) 154 155 ->execute(); 155 156 157 + $timestamps = CalendarTimeUtil::getCalendarWeekTimestamps( 158 + $viewer); 159 + $today = $timestamps['today']; 160 + $epoch_stamps = $timestamps['epoch_stamps']; 156 161 $events = array(); 157 - foreach ($statuses as $status) { 158 - $event = new AphrontCalendarEventView(); 159 - $event->setEpochRange($status->getDateFrom(), $status->getDateTo()); 160 162 161 - $status_text = $status->getHumanStatus(); 162 - $event->setUserPHID($status->getUserPHID()); 163 - $event->setName($status_text); 164 - $event->setDescription($status->getDescription()); 165 - $event->setEventID($status->getID()); 166 - $key = date('Y-m-d', $event->getEpochStart()); 167 - $events[$key][] = $event; 168 - // Populate multiday events 169 - // Better means? 170 - $next_day = strtotime("{$key} +1 day"); 171 - if ($event->getEpochEnd() >= $next_day) { 172 - $nextkey = date('Y-m-d', $next_day); 173 - $events[$nextkey][] = $event; 163 + foreach ($epoch_stamps as $day) { 164 + $epoch_start = $day->format('U'); 165 + $next_day = clone $day; 166 + $next_day->modify('+1 day'); 167 + $epoch_end = $next_day->format('U'); 168 + 169 + foreach ($statuses as $status) { 170 + if ($status->getDateFrom() >= $epoch_end) { 171 + // This list is sorted, so we can stop looking. 172 + break; 173 + } 174 + 175 + $event = new AphrontCalendarEventView(); 176 + $event->setEpochRange($status->getDateFrom(), $status->getDateTo()); 177 + 178 + $status_text = $status->getHumanStatus(); 179 + $event->setUserPHID($status->getUserPHID()); 180 + $event->setName($status_text); 181 + $event->setDescription($status->getDescription()); 182 + $event->setEventID($status->getID()); 183 + $key = date('Y-m-d', $event->getEpochStart()); 184 + $events[$epoch_start][] = $event; 185 + // check if this is a multi day event...! 186 + $day_iterator = clone $day; 187 + while (true) { 188 + $day_iterator->modify('+ 1 day'); 189 + $day_iterator_end = $day_iterator->format('U'); 190 + if ($event->getEpochEnd() > $day_iterator_end) { 191 + $events[$day_iterator_end][] = $event; 192 + } else { 193 + break; 194 + } 195 + } 174 196 } 175 197 } 176 198 177 - $i = 0; 178 199 $week = array(); 179 - for ($i = 0;$i <= 6;$i++) { 180 - $datetime = strtotime("{$year}-{$month}-{$day} +{$i} days"); 181 - $headertext = phabricator_format_local_time($datetime, $user, 'l, M d'); 182 - $this_day = date('Y-m-d', $datetime); 200 + foreach ($epoch_stamps as $day) { 201 + $epoch = $day->format('U'); 202 + $headertext = phabricator_format_local_time($epoch, $user, 'l, M d'); 183 203 184 204 $list = new PHUICalendarListView(); 185 - $list->setUser($user); 205 + $list->setUser($viewer); 186 206 $list->showBlankState(true); 187 - if (isset($events[$this_day])) { 188 - foreach ($events[$this_day] as $event) { 207 + if (isset($events[$epoch])) { 208 + foreach ($events[$epoch] as $event) { 189 209 $list->addEvent($event); 190 210 } 191 211 }