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

Translate "All Day" events into the viewer's time

Summary:
Ref T8021.

- When "All Day" events are loaded, convert them into the viewer's time.
- When "All Day" events are saved, convert them into a +24 hour range.

Test Plan:
- Created and updated "All Day" events.
- Created and updated normal events.
- Changed timezones, edited and viewed "All Day" events and normal events.
- In all cases, "All Day" events appeared to be 12:00AM - 11:59:59PM to the viewer, on the correct day.
- Normal events shifted around properly according to timezones.

Reviewers: lpriestley

Reviewed By: lpriestley

Subscribers: epriestley

Maniphest Tasks: T8021

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

+142 -2
+15
src/applications/calendar/controller/PhabricatorCalendarEventEditController.php
··· 74 74 $name = $event->getName(); 75 75 $description = $event->getDescription(); 76 76 $type = $event->getStatus(); 77 + $is_all_day = $event->getIsAllDay(); 77 78 78 79 $current_policies = id(new PhabricatorPolicyQuery()) 79 80 ->setViewer($user) ··· 95 96 $subscribers = $request->getArr('subscribers'); 96 97 $edit_policy = $request->getStr('editPolicy'); 97 98 $view_policy = $request->getStr('viewPolicy'); 99 + $is_all_day = $request->getStr('isAllDay'); 98 100 99 101 $invitees = $request->getArr('invitees'); 100 102 $new_invitees = $this->getNewInviteeList($invitees, $event); ··· 110 112 ->setTransactionType( 111 113 PhabricatorCalendarEventTransaction::TYPE_NAME) 112 114 ->setNewValue($name); 115 + 116 + $xactions[] = id(new PhabricatorCalendarEventTransaction()) 117 + ->setTransactionType( 118 + PhabricatorCalendarEventTransaction::TYPE_ALL_DAY) 119 + ->setNewValue($is_all_day); 113 120 114 121 $xactions[] = id(new PhabricatorCalendarEventTransaction()) 115 122 ->setTransactionType( ··· 184 191 ->setValue($type) 185 192 ->setOptions($event->getStatusOptions()); 186 193 194 + $all_day_select = id(new AphrontFormCheckboxControl()) 195 + ->addCheckbox( 196 + 'isAllDay', 197 + 1, 198 + pht('All Day Event'), 199 + $is_all_day); 200 + 187 201 $start_control = id(new AphrontFormDateControl()) 188 202 ->setUser($user) 189 203 ->setName('start') ··· 234 248 ->setUser($user) 235 249 ->appendChild($name) 236 250 ->appendChild($status_select) 251 + ->appendChild($all_day_select) 237 252 ->appendChild($start_control) 238 253 ->appendChild($end_control) 239 254 ->appendControl($view_policies)
+10
src/applications/calendar/editor/PhabricatorCalendarEventEditor.php
··· 183 183 return parent::applyCustomExternalTransaction($object, $xaction); 184 184 } 185 185 186 + protected function didApplyInternalEffects( 187 + PhabricatorLiskDAO $object, 188 + array $xactions) { 189 + 190 + $object->removeViewerTimezone($this->requireActor()); 191 + 192 + return $xactions; 193 + } 194 + 195 + 186 196 protected function validateAllTransactions( 187 197 PhabricatorLiskDAO $object, 188 198 array $xactions) {
+7 -1
src/applications/calendar/query/PhabricatorCalendarEventQuery.php
··· 56 56 $this->buildOrderClause($conn_r), 57 57 $this->buildLimitClause($conn_r)); 58 58 59 - return $table->loadAllFromArray($data); 59 + $events = $table->loadAllFromArray($data); 60 + 61 + foreach ($events as $event) { 62 + $event->applyViewerTimezone($this->getViewer()); 63 + } 64 + 65 + return $events; 60 66 } 61 67 62 68 protected function buildJoinClauseParts(AphrontDatabaseConnection $conn_r) {
+99 -1
src/applications/calendar/storage/PhabricatorCalendarEvent.php
··· 24 24 protected $editPolicy; 25 25 26 26 private $invitees = self::ATTACHABLE; 27 + private $appliedViewer; 27 28 28 29 const STATUS_AWAY = 1; 29 30 const STATUS_SPORADIC = 2; ··· 37 38 return id(new PhabricatorCalendarEvent()) 38 39 ->setUserPHID($actor->getPHID()) 39 40 ->setIsCancelled(0) 41 + ->setIsAllDay(0) 40 42 ->setViewPolicy($actor->getPHID()) 41 43 ->setEditPolicy($actor->getPHID()) 42 - ->attachInvitees(array()); 44 + ->attachInvitees(array()) 45 + ->applyViewerTimezone($actor); 46 + } 47 + 48 + public function applyViewerTimezone(PhabricatorUser $viewer) { 49 + if ($this->appliedViewer) { 50 + throw new Exception(pht('Viewer timezone is already applied!')); 51 + } 52 + 53 + $this->appliedViewer = $viewer; 54 + 55 + if (!$this->getIsAllDay()) { 56 + return $this; 57 + } 58 + 59 + $zone = $viewer->getTimeZone(); 60 + 61 + 62 + $this->setDateFrom( 63 + $this->getDateEpochForTimeZone( 64 + $this->getDateFrom(), 65 + new DateTimeZone('GMT+12'), 66 + 'Y-m-d', 67 + null, 68 + $zone)); 69 + 70 + $this->setDateTo( 71 + $this->getDateEpochForTimeZone( 72 + $this->getDateTo(), 73 + new DateTimeZone('GMT-12'), 74 + 'Y-m-d 23:59:59', 75 + '-1 day', 76 + $zone)); 77 + 78 + return $this; 79 + } 80 + 81 + 82 + public function removeViewerTimezone(PhabricatorUser $viewer) { 83 + if (!$this->appliedViewer) { 84 + throw new Exception(pht('Viewer timezone is not applied!')); 85 + } 86 + 87 + if ($viewer->getPHID() != $this->appliedViewer->getPHID()) { 88 + throw new Exception(pht('Removed viewer must match applied viewer!')); 89 + } 90 + 91 + $this->appliedViewer = null; 92 + 93 + if (!$this->getIsAllDay()) { 94 + return $this; 95 + } 96 + 97 + $zone = $viewer->getTimeZone(); 98 + 99 + $this->setDateFrom( 100 + $this->getDateEpochForTimeZone( 101 + $this->getDateFrom(), 102 + $zone, 103 + 'Y-m-d', 104 + null, 105 + new DateTimeZone('GMT+12'))); 106 + 107 + $this->setDateTo( 108 + $this->getDateEpochForTimeZone( 109 + $this->getDateTo(), 110 + $zone, 111 + 'Y-m-d', 112 + '+1 day', 113 + new DateTimeZone('GMT-12'))); 114 + 115 + return $this; 116 + } 117 + 118 + private function getDateEpochForTimeZone( 119 + $epoch, 120 + $src_zone, 121 + $format, 122 + $adjust, 123 + $dst_zone) { 124 + 125 + $src = new DateTime('@'.$epoch); 126 + $src->setTimeZone($src_zone); 127 + 128 + if (strlen($adjust)) { 129 + $adjust = ' '.$adjust; 130 + } 131 + 132 + $dst = new DateTime($src->format($format).$adjust, $dst_zone); 133 + return $dst->format('U'); 43 134 } 44 135 45 136 public function save() { 137 + if ($this->appliedViewer) { 138 + throw new Exception( 139 + pht( 140 + 'Can not save event with viewer timezone still applied!')); 141 + } 142 + 46 143 if (!$this->mailKey) { 47 144 $this->mailKey = Filesystem::readRandomCharacters(20); 48 145 } 146 + 49 147 return parent::save(); 50 148 } 51 149
+4
src/applications/people/storage/PhabricatorUser.php
··· 682 682 } 683 683 } 684 684 685 + public function getTimeZone() { 686 + return new DateTimeZone($this->getTimezoneIdentifier()); 687 + } 688 + 685 689 public function __toString() { 686 690 return $this->getUsername(); 687 691 }
+7
src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php
··· 569 569 return $xaction; 570 570 } 571 571 572 + protected function didApplyInternalEffects( 573 + PhabricatorLiskDAO $object, 574 + array $xactions) { 575 + return $xactions; 576 + } 572 577 573 578 protected function applyFinalEffects( 574 579 PhabricatorLiskDAO $object, ··· 730 735 foreach ($xactions as $xaction) { 731 736 $this->applyInternalEffects($object, $xaction); 732 737 } 738 + 739 + $xactions = $this->didApplyInternalEffects($object, $xactions); 733 740 734 741 $object->save(); 735 742