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

Canceling calendar events should deactivate the event

Summary: Closes T7943, Canceling calendar event should deactivate the event instead of destroying data.

Test Plan: Create an event, cancel it, see changed status icon, query for active events, event should not appear, query for deactivated events, event should appear in results.

Reviewers: #blessed_reviewers, epriestley

Reviewed By: #blessed_reviewers, epriestley

Subscribers: Korvin, epriestley

Maniphest Tasks: T7943

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

+211 -68
+2
resources/sql/autopatches/20150428.calendar.1.iscancelled.sql
··· 1 + ALTER TABLE {$NAMESPACE}_calendar.calendar_event 2 + ADD isCancelled BOOL NOT NULL;
+6 -2
src/__phutil_library_map__.php
··· 1482 1482 'PhabricatorCalendarController' => 'applications/calendar/controller/PhabricatorCalendarController.php', 1483 1483 'PhabricatorCalendarDAO' => 'applications/calendar/storage/PhabricatorCalendarDAO.php', 1484 1484 'PhabricatorCalendarEvent' => 'applications/calendar/storage/PhabricatorCalendarEvent.php', 1485 - 'PhabricatorCalendarEventDeleteController' => 'applications/calendar/controller/PhabricatorCalendarEventDeleteController.php', 1485 + 'PhabricatorCalendarEventCancelController' => 'applications/calendar/controller/PhabricatorCalendarEventCancelController.php', 1486 1486 'PhabricatorCalendarEventEditController' => 'applications/calendar/controller/PhabricatorCalendarEventEditController.php', 1487 1487 'PhabricatorCalendarEventEditor' => 'applications/calendar/editor/PhabricatorCalendarEventEditor.php', 1488 1488 'PhabricatorCalendarEventInvalidEpochException' => 'applications/calendar/exception/PhabricatorCalendarEventInvalidEpochException.php', ··· 4808 4808 'PhabricatorMarkupInterface', 4809 4809 'PhabricatorApplicationTransactionInterface', 4810 4810 'PhabricatorSubscribableInterface', 4811 + 'PhabricatorTokenReceiverInterface', 4812 + 'PhabricatorDestructibleInterface', 4813 + 'PhabricatorMentionableInterface', 4814 + 'PhabricatorFlaggableInterface', 4811 4815 ), 4812 - 'PhabricatorCalendarEventDeleteController' => 'PhabricatorCalendarController', 4816 + 'PhabricatorCalendarEventCancelController' => 'PhabricatorCalendarController', 4813 4817 'PhabricatorCalendarEventEditController' => 'PhabricatorCalendarController', 4814 4818 'PhabricatorCalendarEventEditor' => 'PhabricatorApplicationTransactionEditor', 4815 4819 'PhabricatorCalendarEventInvalidEpochException' => 'Exception',
+2 -2
src/applications/calendar/application/PhabricatorCalendarApplication.php
··· 51 51 => 'PhabricatorCalendarEventEditController', 52 52 'edit/(?P<id>[1-9]\d*)/' 53 53 => 'PhabricatorCalendarEventEditController', 54 - 'delete/(?P<id>[1-9]\d*)/' 55 - => 'PhabricatorCalendarEventDeleteController', 54 + 'cancel/(?P<id>[1-9]\d*)/' 55 + => 'PhabricatorCalendarEventCancelController', 56 56 ), 57 57 ), 58 58 );
+75
src/applications/calendar/controller/PhabricatorCalendarEventCancelController.php
··· 1 + <?php 2 + 3 + final class PhabricatorCalendarEventCancelController 4 + extends PhabricatorCalendarController { 5 + 6 + private $id; 7 + 8 + public function willProcessRequest(array $data) { 9 + $this->id = idx($data, 'id'); 10 + } 11 + 12 + public function processRequest() { 13 + $request = $this->getRequest(); 14 + $user = $request->getUser(); 15 + 16 + $status = id(new PhabricatorCalendarEventQuery()) 17 + ->setViewer($user) 18 + ->withIDs(array($this->id)) 19 + ->requireCapabilities( 20 + array( 21 + PhabricatorPolicyCapability::CAN_VIEW, 22 + PhabricatorPolicyCapability::CAN_EDIT, 23 + )) 24 + ->executeOne(); 25 + 26 + if (!$status) { 27 + return new Aphront404Response(); 28 + } 29 + 30 + $cancel_uri = '/E'.$status->getID(); 31 + $validation_exception = null; 32 + $is_cancelled = $status->getIsCancelled(); 33 + 34 + if ($request->isFormPost()) { 35 + $xactions = array(); 36 + 37 + $xaction = id(new PhabricatorCalendarEventTransaction()) 38 + ->setTransactionType( 39 + PhabricatorCalendarEventTransaction::TYPE_CANCEL) 40 + ->setNewValue(!$is_cancelled); 41 + 42 + $editor = id(new PhabricatorCalendarEventEditor()) 43 + ->setActor($user) 44 + ->setContentSourceFromRequest($request) 45 + ->setContinueOnNoEffect(true) 46 + ->setContinueOnMissingFields(true); 47 + 48 + try { 49 + $editor->applyTransactions($status, array($xaction)); 50 + return id(new AphrontRedirectResponse())->setURI($cancel_uri); 51 + } catch (PhabricatorApplicationTransactionValidationException $ex) { 52 + $validation_exception = $ex; 53 + } 54 + } 55 + 56 + if ($is_cancelled) { 57 + $title = pht('Reinstate Event'); 58 + $paragraph = pht('Reinstate this event?'); 59 + $cancel = pht('Don\'t Reinstate Event'); 60 + $submit = pht('Reinstate Event'); 61 + } else { 62 + $title = pht('Cancel Event'); 63 + $paragraph = pht('You can always reinstate the event later.'); 64 + $cancel = pht('Don\'t Cancel Event'); 65 + $submit = pht('Cancel Event'); 66 + } 67 + 68 + return $this->newDialog() 69 + ->setTitle($title) 70 + ->setValidationException($validation_exception) 71 + ->appendParagraph($paragraph) 72 + ->addCancelButton($cancel_uri, $cancel) 73 + ->addSubmitButton($submit); 74 + } 75 + }
-54
src/applications/calendar/controller/PhabricatorCalendarEventDeleteController.php
··· 1 - <?php 2 - 3 - final class PhabricatorCalendarEventDeleteController 4 - extends PhabricatorCalendarController { 5 - 6 - private $id; 7 - 8 - public function willProcessRequest(array $data) { 9 - $this->id = idx($data, 'id'); 10 - } 11 - 12 - public function processRequest() { 13 - $request = $this->getRequest(); 14 - $user = $request->getUser(); 15 - 16 - $status = id(new PhabricatorCalendarEventQuery()) 17 - ->setViewer($user) 18 - ->withIDs(array($this->id)) 19 - ->requireCapabilities( 20 - array( 21 - PhabricatorPolicyCapability::CAN_VIEW, 22 - PhabricatorPolicyCapability::CAN_EDIT, 23 - )) 24 - ->executeOne(); 25 - 26 - if (!$status) { 27 - return new Aphront404Response(); 28 - } 29 - 30 - if ($request->isFormPost()) { 31 - $status->delete(); 32 - $uri = new PhutilURI($this->getApplicationURI()); 33 - $uri->setQueryParams( 34 - array( 35 - 'deleted' => true, 36 - )); 37 - return id(new AphrontRedirectResponse()) 38 - ->setURI($uri); 39 - } 40 - 41 - $dialog = new AphrontDialogView(); 42 - $dialog->setUser($user); 43 - $dialog->setTitle(pht('Really delete status?')); 44 - $dialog->appendChild( 45 - pht('Permanently delete this status? This action can not be undone.')); 46 - $dialog->addSubmitButton(pht('Delete')); 47 - $dialog->addCancelButton( 48 - $this->getApplicationURI('event/')); 49 - 50 - return id(new AphrontDialogResponse())->setDialog($dialog); 51 - 52 - } 53 - 54 - }
-1
src/applications/calendar/controller/PhabricatorCalendarEventEditController.php
··· 19 19 $error_name = true; 20 20 $validation_exception = null; 21 21 22 - 23 22 $start_time = id(new AphrontFormDateControl()) 24 23 ->setUser($user) 25 24 ->setName('start')
+23 -7
src/applications/calendar/controller/PhabricatorCalendarEventViewController.php
··· 56 56 57 57 private function buildHeaderView(PhabricatorCalendarEvent $event) { 58 58 $viewer = $this->getRequest()->getUser(); 59 + $is_cancelled = $event->getIsCancelled(); 60 + $icon = $is_cancelled ? ('fa-times') : ('fa-calendar'); 61 + $color = $is_cancelled ? ('grey') : ('green'); 62 + $status = $is_cancelled ? ('Cancelled') : ('Active'); 59 63 60 64 return id(new PHUIHeaderView()) 61 65 ->setUser($viewer) 62 66 ->setHeader($event->getName()) 67 + ->setStatus($icon, $color, $status) 63 68 ->setPolicyObject($event); 64 69 } 65 70 66 71 private function buildActionView(PhabricatorCalendarEvent $event) { 67 72 $viewer = $this->getRequest()->getUser(); 68 73 $id = $event->getID(); 74 + $is_cancelled = $event->getIsCancelled(); 69 75 70 76 $actions = id(new PhabricatorActionListView()) 71 77 ->setObjectURI($this->getApplicationURI('event/'.$id.'/')) ··· 85 91 ->setDisabled(!$can_edit) 86 92 ->setWorkflow(!$can_edit)); 87 93 88 - $actions->addAction( 89 - id(new PhabricatorActionView()) 90 - ->setName(pht('Cancel Event')) 91 - ->setIcon('fa-times') 92 - ->setHref($this->getApplicationURI("event/delete/{$id}/")) 93 - ->setDisabled(!$can_edit) 94 - ->setWorkflow(true)); 94 + if ($is_cancelled) { 95 + $actions->addAction( 96 + id(new PhabricatorActionView()) 97 + ->setName(pht('Reinstate Event')) 98 + ->setIcon('fa-plus') 99 + ->setHref($this->getApplicationURI("event/cancel/{$id}/")) 100 + ->setDisabled(!$can_edit) 101 + ->setWorkflow(true)); 102 + } else { 103 + $actions->addAction( 104 + id(new PhabricatorActionView()) 105 + ->setName(pht('Cancel Event')) 106 + ->setIcon('fa-times') 107 + ->setHref($this->getApplicationURI("event/cancel/{$id}/")) 108 + ->setDisabled(!$can_edit) 109 + ->setWorkflow(true)); 110 + } 95 111 96 112 return $actions; 97 113 }
+8
src/applications/calendar/editor/PhabricatorCalendarEventEditor.php
··· 19 19 $types[] = PhabricatorCalendarEventTransaction::TYPE_END_DATE; 20 20 $types[] = PhabricatorCalendarEventTransaction::TYPE_STATUS; 21 21 $types[] = PhabricatorCalendarEventTransaction::TYPE_DESCRIPTION; 22 + $types[] = PhabricatorCalendarEventTransaction::TYPE_CANCEL; 22 23 23 24 $types[] = PhabricatorTransactions::TYPE_VIEW_POLICY; 24 25 $types[] = PhabricatorTransactions::TYPE_EDIT_POLICY; ··· 44 45 return (int)$status; 45 46 case PhabricatorCalendarEventTransaction::TYPE_DESCRIPTION: 46 47 return $object->getDescription(); 48 + case PhabricatorCalendarEventTransaction::TYPE_CANCEL: 49 + return $object->getIsCancelled(); 47 50 } 48 51 49 52 return parent::getCustomTransactionOldValue($object, $xaction); ··· 58 61 case PhabricatorCalendarEventTransaction::TYPE_START_DATE: 59 62 case PhabricatorCalendarEventTransaction::TYPE_END_DATE: 60 63 case PhabricatorCalendarEventTransaction::TYPE_DESCRIPTION: 64 + case PhabricatorCalendarEventTransaction::TYPE_CANCEL: 61 65 return $xaction->getNewValue(); 62 66 case PhabricatorCalendarEventTransaction::TYPE_STATUS: 63 67 return (int)$xaction->getNewValue(); ··· 86 90 case PhabricatorCalendarEventTransaction::TYPE_DESCRIPTION: 87 91 $object->setDescription($xaction->getNewValue()); 88 92 return; 93 + case PhabricatorCalendarEventTransaction::TYPE_CANCEL: 94 + $object->setIsCancelled((int)$xaction->getNewValue()); 95 + return; 89 96 case PhabricatorTransactions::TYPE_VIEW_POLICY: 90 97 case PhabricatorTransactions::TYPE_EDIT_POLICY: 91 98 case PhabricatorTransactions::TYPE_EDGE: ··· 106 113 case PhabricatorCalendarEventTransaction::TYPE_END_DATE: 107 114 case PhabricatorCalendarEventTransaction::TYPE_STATUS: 108 115 case PhabricatorCalendarEventTransaction::TYPE_DESCRIPTION: 116 + case PhabricatorCalendarEventTransaction::TYPE_CANCEL: 109 117 case PhabricatorTransactions::TYPE_VIEW_POLICY: 110 118 case PhabricatorTransactions::TYPE_EDIT_POLICY: 111 119 case PhabricatorTransactions::TYPE_EDGE:
+5
src/applications/calendar/phid/PhabricatorCalendarEventPHIDType.php
··· 30 30 31 31 $id = $event->getID(); 32 32 $name = $event->getName(); 33 + $is_cancelled = $event->getIsCancelled(); 33 34 34 35 $handle 35 36 ->setName($name) 36 37 ->setFullName(pht('E%d: %s', $id, $name)) 37 38 ->setURI('/E'.$id); 39 + 40 + if ($is_cancelled) { 41 + $handle->setStatus(PhabricatorObjectHandleStatus::STATUS_CLOSED); 42 + } 38 43 } 39 44 } 40 45
+13
src/applications/calendar/query/PhabricatorCalendarEventQuery.php
··· 9 9 private $rangeEnd; 10 10 private $invitedPHIDs; 11 11 private $creatorPHIDs; 12 + private $isCancelled; 12 13 13 14 public function withIDs(array $ids) { 14 15 $this->ids = $ids; ··· 33 34 34 35 public function withCreatorPHIDs(array $phids) { 35 36 $this->creatorPHIDs = $phids; 37 + return $this; 38 + } 39 + 40 + public function withIsCancelled($is_cancelled) { 41 + $this->isCancelled = $is_cancelled; 36 42 return $this; 37 43 } 38 44 ··· 97 103 $conn_r, 98 104 'userPHID IN (%Ls)', 99 105 $this->creatorPHIDs); 106 + } 107 + 108 + if ($this->isCancelled !== null) { 109 + $where[] = qsprintf( 110 + $conn_r, 111 + 'isCancelled = %d', 112 + (int)$this->isCancelled); 100 113 } 101 114 102 115 $where[] = $this->buildPagingClause($conn_r);
+27 -1
src/applications/calendar/query/PhabricatorCalendarEventSearchEngine.php
··· 34 34 'creatorPHIDs', 35 35 $this->readUsersFromRequest($request, 'creators')); 36 36 37 + $saved->setParameter( 38 + 'isCancelled', 39 + $request->getStr('isCancelled')); 40 + 37 41 return $saved; 38 42 } 39 43 ··· 71 75 $creator_phids = $saved->getParameter('creatorPHIDs'); 72 76 if ($creator_phids) { 73 77 $query->withCreatorPHIDs($creator_phids); 78 + } 79 + 80 + $is_cancelled = $saved->getParameter('isCancelled'); 81 + switch ($is_cancelled) { 82 + case 'active': 83 + $query->withIsCancelled(false); 84 + break; 85 + case 'cancelled': 86 + $query->withIsCancelled(true); 87 + break; 74 88 } 75 89 76 90 return $query; ··· 83 97 $range_start = $saved->getParameter('rangeStart'); 84 98 $range_end = $saved->getParameter('rangeEnd'); 85 99 $upcoming = $saved->getParameter('upcoming'); 100 + $is_cancelled = $saved->getParameter('isCancelled', 'active'); 86 101 87 102 $invited_phids = $saved->getParameter('invitedPHIDs', array()); 88 103 $creator_phids = $saved->getParameter('creatorPHIDs', array()); 104 + $resolution_types = array( 105 + 'active' => pht('Active Events Only'), 106 + 'cancelled' => pht('Cancelled Events Only'), 107 + 'both' => pht('Both Cancelled and Active Events'), 108 + ); 89 109 90 110 $form 91 111 ->appendControl( ··· 120 140 'upcoming', 121 141 1, 122 142 pht('Show only upcoming events.'), 123 - $upcoming)); 143 + $upcoming)) 144 + ->appendChild( 145 + id(new AphrontFormSelectControl()) 146 + ->setLabel(pht('Cancelled Events')) 147 + ->setName('isCancelled') 148 + ->setValue($is_cancelled) 149 + ->setOptions($resolution_types)); 124 150 } 125 151 126 152 protected function getURI($path) {
+16 -1
src/applications/calendar/storage/PhabricatorCalendarEvent.php
··· 6 6 PhabricatorApplicationTransactionInterface, 7 7 PhabricatorSubscribableInterface, 8 8 PhabricatorTokenReceiverInterface, 9 + PhabricatorDestructibleInterface, 9 10 PhabricatorMentionableInterface, 10 11 PhabricatorFlaggableInterface { 11 12 ··· 15 16 protected $dateTo; 16 17 protected $status; 17 18 protected $description; 19 + protected $isCancelled; 18 20 19 21 const STATUS_AWAY = 1; 20 22 const STATUS_SPORADIC = 2; ··· 26 28 ->executeOne(); 27 29 28 30 return id(new PhabricatorCalendarEvent()) 29 - ->setUserPHID($actor->getPHID()); 31 + ->setUserPHID($actor->getPHID()) 32 + ->setIsCancelled(0); 30 33 } 31 34 32 35 private static $statusTexts = array( ··· 64 67 'dateTo' => 'epoch', 65 68 'status' => 'uint32', 66 69 'description' => 'text', 70 + 'isCancelled' => 'bool', 67 71 ), 68 72 self::CONFIG_KEY_SCHEMA => array( 69 73 'userPHID_dateFrom' => array( ··· 243 247 244 248 public function getUsersToNotifyOfTokenGiven() { 245 249 return array($this->getUserPHID()); 250 + } 251 + 252 + /* -( PhabricatorDestructibleInterface )----------------------------------- */ 253 + 254 + 255 + public function destroyObjectPermanently( 256 + PhabricatorDestructionEngine $engine) { 257 + 258 + $this->openTransaction(); 259 + $this->delete(); 260 + $this->saveTransaction(); 246 261 } 247 262 }
+34
src/applications/calendar/storage/PhabricatorCalendarEventTransaction.php
··· 8 8 const TYPE_END_DATE = 'calendar.enddate'; 9 9 const TYPE_STATUS = 'calendar.status'; 10 10 const TYPE_DESCRIPTION = 'calendar.description'; 11 + const TYPE_CANCEL = 'calendar.cancel'; 11 12 12 13 const MAILTAG_CONTENT = 'calendar-content'; 13 14 const MAILTAG_OTHER = 'calendar-other'; ··· 33 34 case self::TYPE_END_DATE: 34 35 case self::TYPE_STATUS: 35 36 case self::TYPE_DESCRIPTION: 37 + case self::TYPE_CANCEL: 36 38 $phids[] = $this->getObjectPHID(); 37 39 break; 38 40 } ··· 47 49 case self::TYPE_END_DATE: 48 50 case self::TYPE_STATUS: 49 51 case self::TYPE_DESCRIPTION: 52 + case self::TYPE_CANCEL: 50 53 return ($old === null); 51 54 } 52 55 return parent::shouldHide(); ··· 59 62 case self::TYPE_END_DATE: 60 63 case self::TYPE_STATUS: 61 64 case self::TYPE_DESCRIPTION: 65 + case self::TYPE_CANCEL: 62 66 return 'fa-pencil'; 63 67 break; 64 68 } ··· 115 119 "%s updated the event's description.", 116 120 $this->renderHandleLink($author_phid)); 117 121 break; 122 + case self::TYPE_CANCEL: 123 + if ($new) { 124 + return pht( 125 + '%s cancelled this event.', 126 + $this->renderHandleLink($author_phid)); 127 + break; 128 + } else { 129 + return pht( 130 + '%s reinstated this event.', 131 + $this->renderHandleLink($author_phid)); 132 + break; 133 + } 118 134 } 119 135 120 136 return parent::getTitle(); ··· 186 202 $this->renderHandleLink($author_phid), 187 203 $this->renderHandleLink($object_phid)); 188 204 break; 205 + case self::TYPE_CANCEL: 206 + if ($new) { 207 + return pht( 208 + '%s cancelled %s.', 209 + $this->renderHandleLink($author_phid), 210 + $this->renderHandleLink($object_phid)); 211 + break; 212 + } else { 213 + return pht( 214 + '%s reinstated %s.', 215 + $this->renderHandleLink($author_phid), 216 + $this->renderHandleLink($object_phid)); 217 + break; 218 + } 189 219 } 190 220 191 221 return parent::getTitleForFeed(); ··· 201 231 case self::TYPE_END_DATE: 202 232 case self::TYPE_STATUS: 203 233 case self::TYPE_DESCRIPTION: 234 + case self::TYPE_CANCEL: 204 235 return PhabricatorTransactions::COLOR_GREEN; 205 236 } 206 237 ··· 248 279 $tags[] = self::MAILTAG_OTHER; 249 280 break; 250 281 case self::TYPE_DESCRIPTION: 282 + $tags[] = self::MAILTAG_CONTENT; 283 + break; 284 + case self::TYPE_CANCEL: 251 285 $tags[] = self::MAILTAG_CONTENT; 252 286 break; 253 287 }