diff --git a/resources/sql/autopatches/20150428.calendar.1.iscancelled.sql b/resources/sql/autopatches/20150428.calendar.1.iscancelled.sql new file mode 100644 index 0000000000..8b6d95dd67 --- /dev/null +++ b/resources/sql/autopatches/20150428.calendar.1.iscancelled.sql @@ -0,0 +1,2 @@ +ALTER TABLE {$NAMESPACE}_calendar.calendar_event + ADD isCancelled BOOL NOT NULL; diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 218487e23a..a64cae8f8f 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -1482,7 +1482,7 @@ phutil_register_library_map(array( 'PhabricatorCalendarController' => 'applications/calendar/controller/PhabricatorCalendarController.php', 'PhabricatorCalendarDAO' => 'applications/calendar/storage/PhabricatorCalendarDAO.php', 'PhabricatorCalendarEvent' => 'applications/calendar/storage/PhabricatorCalendarEvent.php', - 'PhabricatorCalendarEventDeleteController' => 'applications/calendar/controller/PhabricatorCalendarEventDeleteController.php', + 'PhabricatorCalendarEventCancelController' => 'applications/calendar/controller/PhabricatorCalendarEventCancelController.php', 'PhabricatorCalendarEventEditController' => 'applications/calendar/controller/PhabricatorCalendarEventEditController.php', 'PhabricatorCalendarEventEditor' => 'applications/calendar/editor/PhabricatorCalendarEventEditor.php', 'PhabricatorCalendarEventInvalidEpochException' => 'applications/calendar/exception/PhabricatorCalendarEventInvalidEpochException.php', @@ -4808,8 +4808,12 @@ phutil_register_library_map(array( 'PhabricatorMarkupInterface', 'PhabricatorApplicationTransactionInterface', 'PhabricatorSubscribableInterface', + 'PhabricatorTokenReceiverInterface', + 'PhabricatorDestructibleInterface', + 'PhabricatorMentionableInterface', + 'PhabricatorFlaggableInterface', ), - 'PhabricatorCalendarEventDeleteController' => 'PhabricatorCalendarController', + 'PhabricatorCalendarEventCancelController' => 'PhabricatorCalendarController', 'PhabricatorCalendarEventEditController' => 'PhabricatorCalendarController', 'PhabricatorCalendarEventEditor' => 'PhabricatorApplicationTransactionEditor', 'PhabricatorCalendarEventInvalidEpochException' => 'Exception', diff --git a/src/applications/calendar/application/PhabricatorCalendarApplication.php b/src/applications/calendar/application/PhabricatorCalendarApplication.php index 2eeb4f0fbe..629c7f59e2 100644 --- a/src/applications/calendar/application/PhabricatorCalendarApplication.php +++ b/src/applications/calendar/application/PhabricatorCalendarApplication.php @@ -51,8 +51,8 @@ final class PhabricatorCalendarApplication extends PhabricatorApplication { => 'PhabricatorCalendarEventEditController', 'edit/(?P[1-9]\d*)/' => 'PhabricatorCalendarEventEditController', - 'delete/(?P[1-9]\d*)/' - => 'PhabricatorCalendarEventDeleteController', + 'cancel/(?P[1-9]\d*)/' + => 'PhabricatorCalendarEventCancelController', ), ), ); diff --git a/src/applications/calendar/controller/PhabricatorCalendarEventCancelController.php b/src/applications/calendar/controller/PhabricatorCalendarEventCancelController.php new file mode 100644 index 0000000000..a3909e7207 --- /dev/null +++ b/src/applications/calendar/controller/PhabricatorCalendarEventCancelController.php @@ -0,0 +1,75 @@ +id = idx($data, 'id'); + } + + public function processRequest() { + $request = $this->getRequest(); + $user = $request->getUser(); + + $status = id(new PhabricatorCalendarEventQuery()) + ->setViewer($user) + ->withIDs(array($this->id)) + ->requireCapabilities( + array( + PhabricatorPolicyCapability::CAN_VIEW, + PhabricatorPolicyCapability::CAN_EDIT, + )) + ->executeOne(); + + if (!$status) { + return new Aphront404Response(); + } + + $cancel_uri = '/E'.$status->getID(); + $validation_exception = null; + $is_cancelled = $status->getIsCancelled(); + + if ($request->isFormPost()) { + $xactions = array(); + + $xaction = id(new PhabricatorCalendarEventTransaction()) + ->setTransactionType( + PhabricatorCalendarEventTransaction::TYPE_CANCEL) + ->setNewValue(!$is_cancelled); + + $editor = id(new PhabricatorCalendarEventEditor()) + ->setActor($user) + ->setContentSourceFromRequest($request) + ->setContinueOnNoEffect(true) + ->setContinueOnMissingFields(true); + + try { + $editor->applyTransactions($status, array($xaction)); + return id(new AphrontRedirectResponse())->setURI($cancel_uri); + } catch (PhabricatorApplicationTransactionValidationException $ex) { + $validation_exception = $ex; + } + } + + if ($is_cancelled) { + $title = pht('Reinstate Event'); + $paragraph = pht('Reinstate this event?'); + $cancel = pht('Don\'t Reinstate Event'); + $submit = pht('Reinstate Event'); + } else { + $title = pht('Cancel Event'); + $paragraph = pht('You can always reinstate the event later.'); + $cancel = pht('Don\'t Cancel Event'); + $submit = pht('Cancel Event'); + } + + return $this->newDialog() + ->setTitle($title) + ->setValidationException($validation_exception) + ->appendParagraph($paragraph) + ->addCancelButton($cancel_uri, $cancel) + ->addSubmitButton($submit); + } +} diff --git a/src/applications/calendar/controller/PhabricatorCalendarEventDeleteController.php b/src/applications/calendar/controller/PhabricatorCalendarEventDeleteController.php deleted file mode 100644 index a482f4e86b..0000000000 --- a/src/applications/calendar/controller/PhabricatorCalendarEventDeleteController.php +++ /dev/null @@ -1,54 +0,0 @@ -id = idx($data, 'id'); - } - - public function processRequest() { - $request = $this->getRequest(); - $user = $request->getUser(); - - $status = id(new PhabricatorCalendarEventQuery()) - ->setViewer($user) - ->withIDs(array($this->id)) - ->requireCapabilities( - array( - PhabricatorPolicyCapability::CAN_VIEW, - PhabricatorPolicyCapability::CAN_EDIT, - )) - ->executeOne(); - - if (!$status) { - return new Aphront404Response(); - } - - if ($request->isFormPost()) { - $status->delete(); - $uri = new PhutilURI($this->getApplicationURI()); - $uri->setQueryParams( - array( - 'deleted' => true, - )); - return id(new AphrontRedirectResponse()) - ->setURI($uri); - } - - $dialog = new AphrontDialogView(); - $dialog->setUser($user); - $dialog->setTitle(pht('Really delete status?')); - $dialog->appendChild( - pht('Permanently delete this status? This action can not be undone.')); - $dialog->addSubmitButton(pht('Delete')); - $dialog->addCancelButton( - $this->getApplicationURI('event/')); - - return id(new AphrontDialogResponse())->setDialog($dialog); - - } - -} diff --git a/src/applications/calendar/controller/PhabricatorCalendarEventEditController.php b/src/applications/calendar/controller/PhabricatorCalendarEventEditController.php index 2b215ccf1e..9580296b1f 100644 --- a/src/applications/calendar/controller/PhabricatorCalendarEventEditController.php +++ b/src/applications/calendar/controller/PhabricatorCalendarEventEditController.php @@ -19,7 +19,6 @@ final class PhabricatorCalendarEventEditController $error_name = true; $validation_exception = null; - $start_time = id(new AphrontFormDateControl()) ->setUser($user) ->setName('start') diff --git a/src/applications/calendar/controller/PhabricatorCalendarEventViewController.php b/src/applications/calendar/controller/PhabricatorCalendarEventViewController.php index e4b2cfcdb2..9214ff2cd0 100644 --- a/src/applications/calendar/controller/PhabricatorCalendarEventViewController.php +++ b/src/applications/calendar/controller/PhabricatorCalendarEventViewController.php @@ -56,16 +56,22 @@ final class PhabricatorCalendarEventViewController private function buildHeaderView(PhabricatorCalendarEvent $event) { $viewer = $this->getRequest()->getUser(); + $is_cancelled = $event->getIsCancelled(); + $icon = $is_cancelled ? ('fa-times') : ('fa-calendar'); + $color = $is_cancelled ? ('grey') : ('green'); + $status = $is_cancelled ? ('Cancelled') : ('Active'); return id(new PHUIHeaderView()) ->setUser($viewer) ->setHeader($event->getName()) + ->setStatus($icon, $color, $status) ->setPolicyObject($event); } private function buildActionView(PhabricatorCalendarEvent $event) { $viewer = $this->getRequest()->getUser(); $id = $event->getID(); + $is_cancelled = $event->getIsCancelled(); $actions = id(new PhabricatorActionListView()) ->setObjectURI($this->getApplicationURI('event/'.$id.'/')) @@ -85,13 +91,23 @@ final class PhabricatorCalendarEventViewController ->setDisabled(!$can_edit) ->setWorkflow(!$can_edit)); - $actions->addAction( - id(new PhabricatorActionView()) - ->setName(pht('Cancel Event')) - ->setIcon('fa-times') - ->setHref($this->getApplicationURI("event/delete/{$id}/")) - ->setDisabled(!$can_edit) - ->setWorkflow(true)); + if ($is_cancelled) { + $actions->addAction( + id(new PhabricatorActionView()) + ->setName(pht('Reinstate Event')) + ->setIcon('fa-plus') + ->setHref($this->getApplicationURI("event/cancel/{$id}/")) + ->setDisabled(!$can_edit) + ->setWorkflow(true)); + } else { + $actions->addAction( + id(new PhabricatorActionView()) + ->setName(pht('Cancel Event')) + ->setIcon('fa-times') + ->setHref($this->getApplicationURI("event/cancel/{$id}/")) + ->setDisabled(!$can_edit) + ->setWorkflow(true)); + } return $actions; } diff --git a/src/applications/calendar/editor/PhabricatorCalendarEventEditor.php b/src/applications/calendar/editor/PhabricatorCalendarEventEditor.php index 6dfed29666..b268738f27 100644 --- a/src/applications/calendar/editor/PhabricatorCalendarEventEditor.php +++ b/src/applications/calendar/editor/PhabricatorCalendarEventEditor.php @@ -19,6 +19,7 @@ final class PhabricatorCalendarEventEditor $types[] = PhabricatorCalendarEventTransaction::TYPE_END_DATE; $types[] = PhabricatorCalendarEventTransaction::TYPE_STATUS; $types[] = PhabricatorCalendarEventTransaction::TYPE_DESCRIPTION; + $types[] = PhabricatorCalendarEventTransaction::TYPE_CANCEL; $types[] = PhabricatorTransactions::TYPE_VIEW_POLICY; $types[] = PhabricatorTransactions::TYPE_EDIT_POLICY; @@ -44,6 +45,8 @@ final class PhabricatorCalendarEventEditor return (int)$status; case PhabricatorCalendarEventTransaction::TYPE_DESCRIPTION: return $object->getDescription(); + case PhabricatorCalendarEventTransaction::TYPE_CANCEL: + return $object->getIsCancelled(); } return parent::getCustomTransactionOldValue($object, $xaction); @@ -58,6 +61,7 @@ final class PhabricatorCalendarEventEditor case PhabricatorCalendarEventTransaction::TYPE_START_DATE: case PhabricatorCalendarEventTransaction::TYPE_END_DATE: case PhabricatorCalendarEventTransaction::TYPE_DESCRIPTION: + case PhabricatorCalendarEventTransaction::TYPE_CANCEL: return $xaction->getNewValue(); case PhabricatorCalendarEventTransaction::TYPE_STATUS: return (int)$xaction->getNewValue(); @@ -86,6 +90,9 @@ final class PhabricatorCalendarEventEditor case PhabricatorCalendarEventTransaction::TYPE_DESCRIPTION: $object->setDescription($xaction->getNewValue()); return; + case PhabricatorCalendarEventTransaction::TYPE_CANCEL: + $object->setIsCancelled((int)$xaction->getNewValue()); + return; case PhabricatorTransactions::TYPE_VIEW_POLICY: case PhabricatorTransactions::TYPE_EDIT_POLICY: case PhabricatorTransactions::TYPE_EDGE: @@ -106,6 +113,7 @@ final class PhabricatorCalendarEventEditor case PhabricatorCalendarEventTransaction::TYPE_END_DATE: case PhabricatorCalendarEventTransaction::TYPE_STATUS: case PhabricatorCalendarEventTransaction::TYPE_DESCRIPTION: + case PhabricatorCalendarEventTransaction::TYPE_CANCEL: case PhabricatorTransactions::TYPE_VIEW_POLICY: case PhabricatorTransactions::TYPE_EDIT_POLICY: case PhabricatorTransactions::TYPE_EDGE: diff --git a/src/applications/calendar/phid/PhabricatorCalendarEventPHIDType.php b/src/applications/calendar/phid/PhabricatorCalendarEventPHIDType.php index a2318465ed..6bf48e817d 100644 --- a/src/applications/calendar/phid/PhabricatorCalendarEventPHIDType.php +++ b/src/applications/calendar/phid/PhabricatorCalendarEventPHIDType.php @@ -30,11 +30,16 @@ final class PhabricatorCalendarEventPHIDType extends PhabricatorPHIDType { $id = $event->getID(); $name = $event->getName(); + $is_cancelled = $event->getIsCancelled(); $handle ->setName($name) ->setFullName(pht('E%d: %s', $id, $name)) ->setURI('/E'.$id); + + if ($is_cancelled) { + $handle->setStatus(PhabricatorObjectHandleStatus::STATUS_CLOSED); + } } } diff --git a/src/applications/calendar/query/PhabricatorCalendarEventQuery.php b/src/applications/calendar/query/PhabricatorCalendarEventQuery.php index cdfeb0ca43..44ebc127aa 100644 --- a/src/applications/calendar/query/PhabricatorCalendarEventQuery.php +++ b/src/applications/calendar/query/PhabricatorCalendarEventQuery.php @@ -9,6 +9,7 @@ final class PhabricatorCalendarEventQuery private $rangeEnd; private $invitedPHIDs; private $creatorPHIDs; + private $isCancelled; public function withIDs(array $ids) { $this->ids = $ids; @@ -36,6 +37,11 @@ final class PhabricatorCalendarEventQuery return $this; } + public function withIsCancelled($is_cancelled) { + $this->isCancelled = $is_cancelled; + return $this; + } + protected function loadPage() { $table = new PhabricatorCalendarEvent(); $conn_r = $table->establishConnection('r'); @@ -99,6 +105,13 @@ final class PhabricatorCalendarEventQuery $this->creatorPHIDs); } + if ($this->isCancelled !== null) { + $where[] = qsprintf( + $conn_r, + 'isCancelled = %d', + (int)$this->isCancelled); + } + $where[] = $this->buildPagingClause($conn_r); return $this->formatWhereClause($where); diff --git a/src/applications/calendar/query/PhabricatorCalendarEventSearchEngine.php b/src/applications/calendar/query/PhabricatorCalendarEventSearchEngine.php index 820cd3d621..c7409f3a04 100644 --- a/src/applications/calendar/query/PhabricatorCalendarEventSearchEngine.php +++ b/src/applications/calendar/query/PhabricatorCalendarEventSearchEngine.php @@ -34,6 +34,10 @@ final class PhabricatorCalendarEventSearchEngine 'creatorPHIDs', $this->readUsersFromRequest($request, 'creators')); + $saved->setParameter( + 'isCancelled', + $request->getStr('isCancelled')); + return $saved; } @@ -73,6 +77,16 @@ final class PhabricatorCalendarEventSearchEngine $query->withCreatorPHIDs($creator_phids); } + $is_cancelled = $saved->getParameter('isCancelled'); + switch ($is_cancelled) { + case 'active': + $query->withIsCancelled(false); + break; + case 'cancelled': + $query->withIsCancelled(true); + break; + } + return $query; } @@ -83,9 +97,15 @@ final class PhabricatorCalendarEventSearchEngine $range_start = $saved->getParameter('rangeStart'); $range_end = $saved->getParameter('rangeEnd'); $upcoming = $saved->getParameter('upcoming'); + $is_cancelled = $saved->getParameter('isCancelled', 'active'); $invited_phids = $saved->getParameter('invitedPHIDs', array()); $creator_phids = $saved->getParameter('creatorPHIDs', array()); + $resolution_types = array( + 'active' => pht('Active Events Only'), + 'cancelled' => pht('Cancelled Events Only'), + 'both' => pht('Both Cancelled and Active Events'), + ); $form ->appendControl( @@ -120,7 +140,13 @@ final class PhabricatorCalendarEventSearchEngine 'upcoming', 1, pht('Show only upcoming events.'), - $upcoming)); + $upcoming)) + ->appendChild( + id(new AphrontFormSelectControl()) + ->setLabel(pht('Cancelled Events')) + ->setName('isCancelled') + ->setValue($is_cancelled) + ->setOptions($resolution_types)); } protected function getURI($path) { diff --git a/src/applications/calendar/storage/PhabricatorCalendarEvent.php b/src/applications/calendar/storage/PhabricatorCalendarEvent.php index 4cb5996b02..b6a31f0325 100644 --- a/src/applications/calendar/storage/PhabricatorCalendarEvent.php +++ b/src/applications/calendar/storage/PhabricatorCalendarEvent.php @@ -6,6 +6,7 @@ final class PhabricatorCalendarEvent extends PhabricatorCalendarDAO PhabricatorApplicationTransactionInterface, PhabricatorSubscribableInterface, PhabricatorTokenReceiverInterface, + PhabricatorDestructibleInterface, PhabricatorMentionableInterface, PhabricatorFlaggableInterface { @@ -15,6 +16,7 @@ final class PhabricatorCalendarEvent extends PhabricatorCalendarDAO protected $dateTo; protected $status; protected $description; + protected $isCancelled; const STATUS_AWAY = 1; const STATUS_SPORADIC = 2; @@ -26,7 +28,8 @@ final class PhabricatorCalendarEvent extends PhabricatorCalendarDAO ->executeOne(); return id(new PhabricatorCalendarEvent()) - ->setUserPHID($actor->getPHID()); + ->setUserPHID($actor->getPHID()) + ->setIsCancelled(0); } private static $statusTexts = array( @@ -64,6 +67,7 @@ final class PhabricatorCalendarEvent extends PhabricatorCalendarDAO 'dateTo' => 'epoch', 'status' => 'uint32', 'description' => 'text', + 'isCancelled' => 'bool', ), self::CONFIG_KEY_SCHEMA => array( 'userPHID_dateFrom' => array( @@ -244,4 +248,15 @@ final class PhabricatorCalendarEvent extends PhabricatorCalendarDAO public function getUsersToNotifyOfTokenGiven() { return array($this->getUserPHID()); } + +/* -( PhabricatorDestructibleInterface )----------------------------------- */ + + + public function destroyObjectPermanently( + PhabricatorDestructionEngine $engine) { + + $this->openTransaction(); + $this->delete(); + $this->saveTransaction(); + } } diff --git a/src/applications/calendar/storage/PhabricatorCalendarEventTransaction.php b/src/applications/calendar/storage/PhabricatorCalendarEventTransaction.php index 4d6df565ee..4d3b7c5ffa 100644 --- a/src/applications/calendar/storage/PhabricatorCalendarEventTransaction.php +++ b/src/applications/calendar/storage/PhabricatorCalendarEventTransaction.php @@ -8,6 +8,7 @@ final class PhabricatorCalendarEventTransaction const TYPE_END_DATE = 'calendar.enddate'; const TYPE_STATUS = 'calendar.status'; const TYPE_DESCRIPTION = 'calendar.description'; + const TYPE_CANCEL = 'calendar.cancel'; const MAILTAG_CONTENT = 'calendar-content'; const MAILTAG_OTHER = 'calendar-other'; @@ -33,6 +34,7 @@ final class PhabricatorCalendarEventTransaction case self::TYPE_END_DATE: case self::TYPE_STATUS: case self::TYPE_DESCRIPTION: + case self::TYPE_CANCEL: $phids[] = $this->getObjectPHID(); break; } @@ -47,6 +49,7 @@ final class PhabricatorCalendarEventTransaction case self::TYPE_END_DATE: case self::TYPE_STATUS: case self::TYPE_DESCRIPTION: + case self::TYPE_CANCEL: return ($old === null); } return parent::shouldHide(); @@ -59,6 +62,7 @@ final class PhabricatorCalendarEventTransaction case self::TYPE_END_DATE: case self::TYPE_STATUS: case self::TYPE_DESCRIPTION: + case self::TYPE_CANCEL: return 'fa-pencil'; break; } @@ -115,6 +119,18 @@ final class PhabricatorCalendarEventTransaction "%s updated the event's description.", $this->renderHandleLink($author_phid)); break; + case self::TYPE_CANCEL: + if ($new) { + return pht( + '%s cancelled this event.', + $this->renderHandleLink($author_phid)); + break; + } else { + return pht( + '%s reinstated this event.', + $this->renderHandleLink($author_phid)); + break; + } } return parent::getTitle(); @@ -186,6 +202,20 @@ final class PhabricatorCalendarEventTransaction $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid)); break; + case self::TYPE_CANCEL: + if ($new) { + return pht( + '%s cancelled %s.', + $this->renderHandleLink($author_phid), + $this->renderHandleLink($object_phid)); + break; + } else { + return pht( + '%s reinstated %s.', + $this->renderHandleLink($author_phid), + $this->renderHandleLink($object_phid)); + break; + } } return parent::getTitleForFeed(); @@ -201,6 +231,7 @@ final class PhabricatorCalendarEventTransaction case self::TYPE_END_DATE: case self::TYPE_STATUS: case self::TYPE_DESCRIPTION: + case self::TYPE_CANCEL: return PhabricatorTransactions::COLOR_GREEN; } @@ -250,6 +281,9 @@ final class PhabricatorCalendarEventTransaction case self::TYPE_DESCRIPTION: $tags[] = self::MAILTAG_CONTENT; break; + case self::TYPE_CANCEL: + $tags[] = self::MAILTAG_CONTENT; + break; } return $tags; }