Page MenuHomePhabricator

D13145.id31753.diff
No OneTemporary

D13145.id31753.diff

diff --git a/src/applications/calendar/application/PhabricatorCalendarApplication.php b/src/applications/calendar/application/PhabricatorCalendarApplication.php
--- a/src/applications/calendar/application/PhabricatorCalendarApplication.php
+++ b/src/applications/calendar/application/PhabricatorCalendarApplication.php
@@ -57,7 +57,7 @@
=> 'PhabricatorCalendarEventEditController',
'drag/(?P<id>[1-9]\d*)/'
=> 'PhabricatorCalendarEventDragController',
- 'cancel/(?P<id>[1-9]\d*)/'
+ 'cancel/(?P<id>[1-9]\d*)/(?:(?P<sequence>\d+)/)?'
=> 'PhabricatorCalendarEventCancelController',
'(?P<action>join|decline|accept)/(?P<id>[1-9]\d*)/'
=> 'PhabricatorCalendarEventJoinController',
diff --git a/src/applications/calendar/controller/PhabricatorCalendarEventCancelController.php b/src/applications/calendar/controller/PhabricatorCalendarEventCancelController.php
--- a/src/applications/calendar/controller/PhabricatorCalendarEventCancelController.php
+++ b/src/applications/calendar/controller/PhabricatorCalendarEventCancelController.php
@@ -12,8 +12,9 @@
public function processRequest() {
$request = $this->getRequest();
$user = $request->getUser();
+ $sequence = $request->getURIData('sequence');
- $status = id(new PhabricatorCalendarEventQuery())
+ $event = id(new PhabricatorCalendarEventQuery())
->setViewer($user)
->withIDs(array($this->id))
->requireCapabilities(
@@ -23,15 +24,27 @@
))
->executeOne();
- if (!$status) {
+ if (!$event) {
return new Aphront404Response();
}
- $cancel_uri = '/E'.$status->getID();
+ if (!$sequence) {
+ $cancel_uri = '/E'.$event->getID();
+ $is_cancelled = $event->getIsCancelled();
+ } else {
+ $cancel_uri = '/E'.$event->getID().'/'.$sequence;
+ $is_cancelled = $event->getIsCancelled();
+ }
+
$validation_exception = null;
- $is_cancelled = $status->getIsCancelled();
if ($request->isFormPost()) {
+ if ($is_cancelled && $sequence) {
+ return id(new AphrontRedirectResponse())->setURI($cancel_uri);
+ } else if ($sequence) {
+ $this->cancelGhostEvent($event, $sequence, $user, $request);
+ }
+
$xactions = array();
$xaction = id(new PhabricatorCalendarEventTransaction())
@@ -46,7 +59,7 @@
->setContinueOnMissingFields(true);
try {
- $editor->applyTransactions($status, array($xaction));
+ $editor->applyTransactions($event, array($xaction));
return id(new AphrontRedirectResponse())->setURI($cancel_uri);
} catch (PhabricatorApplicationTransactionValidationException $ex) {
$validation_exception = $ex;
@@ -54,15 +67,34 @@
}
if ($is_cancelled) {
- $title = pht('Reinstate Event');
- $paragraph = pht('Reinstate this event?');
- $cancel = pht('Don\'t Reinstate Event');
- $submit = pht('Reinstate Event');
+ if ($sequence || $event->getIsParentCancelled()) {
+ $title = pht('Cannot Reinstate Instance');
+ $paragraph = pht('Cannot reinstate an instance of a cancelled recurring event.');
+ $cancel = pht('Cancel');
+ $submit = null;
+ } else {
+ $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');
+ if ($sequence) {
+ $title = pht('Cancel Instance');
+ $paragraph = pht('Cancel just this instance of a recurring event.');
+ $cancel = pht('Don\'t Cancel Instance');
+ $submit = pht('Cancel Instance');
+ } else if ($event->getIsRecurring()) {
+ $title = pht('Cancel Recurrence');
+ $paragraph = pht('Cancel the entire series of recurring events.');
+ $cancel = pht('Don\'t Cancel Recurrence');
+ $submit = pht('Cancel Recurrence');
+ } 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()
@@ -72,4 +104,75 @@
->addCancelButton($cancel_uri, $cancel)
->addSubmitButton($submit);
}
+
+ private function cancelGhostEvent($event, $sequence, $user, $request) {
+ if ($sequence == null) {
+ return new Aphront404Response();
+ } else {
+ $result = id(new PhabricatorCalendarEventQuery())
+ ->setViewer($user)
+ ->withInstanceSequencePairs(
+ array(
+ array(
+ $event->getPHID(),
+ $sequence,
+ ),
+ ))
+ ->requireCapabilities(
+ array(
+ PhabricatorPolicyCapability::CAN_VIEW,
+ PhabricatorPolicyCapability::CAN_EDIT,
+ ))
+ ->executeOne();
+
+ if ($result) {
+ $cancel_uri = '/E'.$result->getID();
+
+ $xactions = array();
+
+ $xaction = id(new PhabricatorCalendarEventTransaction())
+ ->setTransactionType(
+ PhabricatorCalendarEventTransaction::TYPE_CANCEL)
+ ->setNewValue(true);
+
+ $editor = id(new PhabricatorCalendarEventEditor())
+ ->setActor($user)
+ ->setContentSourceFromRequest($request)
+ ->setContinueOnNoEffect(true)
+ ->setContinueOnMissingFields(true);
+
+ try {
+ $editor->applyTransactions($result, array($xaction));
+ return id(new AphrontRedirectResponse())->setURI($cancel_uri);
+ } catch (PhabricatorApplicationTransactionValidationException $ex) {
+ $validation_exception = $ex;
+ }
+ }
+
+ $new_ghost = $this->generateGhost($event, $sequence, $user);
+
+ return id(new AphrontRedirectResponse())
+ ->setURI('/E'.$new_ghost->getID().'/');
+ }
+ }
+ private function generateGhost($event, $sequence, $user) {
+ $invitees = $event->getInvitees();
+ $new_ghost = $event->generateNthGhost($sequence, $user);
+ $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
+ $new_ghost
+ ->setID(null)
+ ->setPHID(null)
+ ->removeViewerTimezone($user)
+ ->save();
+ $ghost_invitees = array();
+ foreach ($invitees as $invitee) {
+ $ghost_invitee = clone $invitee;
+ $ghost_invitee
+ ->setID(null)
+ ->setEventPHID($new_ghost->getPHID())
+ ->save();
+ }
+ unset($unguarded);
+ return $new_ghost;
+ }
}
diff --git a/src/applications/calendar/controller/PhabricatorCalendarEventViewController.php b/src/applications/calendar/controller/PhabricatorCalendarEventViewController.php
--- a/src/applications/calendar/controller/PhabricatorCalendarEventViewController.php
+++ b/src/applications/calendar/controller/PhabricatorCalendarEventViewController.php
@@ -27,14 +27,39 @@
return new Aphront404Response();
}
- if ($sequence && $event->getIsRecurring()) {
- $parent_event = $event;
- $event = $event->generateNthGhost($sequence, $viewer);
- $event->attachParentEvent($parent_event);
- } else if ($sequence) {
- return new Aphront404Response();
+ if ($sequence) {
+ $result = id(new PhabricatorCalendarEventQuery())
+ ->setViewer($viewer)
+ ->withInstanceSequencePairs(array(
+ array(
+ $event->getPHID(),
+ $sequence,
+ ),
+ ))
+ ->requireCapabilities(
+ array(
+ PhabricatorPolicyCapability::CAN_VIEW,
+ PhabricatorPolicyCapability::CAN_EDIT,
+ ))
+ ->executeOne();
+ if ($result) {
+ $parent_event = $event;
+ $event = $result;
+ $event->attachParentEvent($parent_event);
+ return id(new AphrontRedirectResponse())
+ ->setURI('/E'.$result->getID());
+ } else if ($sequence && $event->getIsRecurring()) {
+ $parent_event = $event;
+ $event = $event->generateNthGhost($sequence, $viewer);
+ $event->attachParentEvent($parent_event);
+ } else if ($sequence) {
+ return new Aphront404Response();
+ }
+
}
+
+
$title = 'E'.$event->getID();
$page_title = $title.' '.$event->getName();
$crumbs = $this->buildApplicationCrumbs();
@@ -178,21 +203,45 @@
->setWorkflow(true));
}
+ $cancel_uri = $this->getApplicationURI("event/cancel/{$id}/");
+
+ if ($event->getIsGhostEvent()) {
+ $index = $event->getSequenceIndex();
+ $can_reinstate = $event->getIsParentCancelled();
+
+ $cancel_label = pht('Cancel This Instance');
+ $reinstate_label = pht('Reinstate This Instance');
+ $cancel_disabled = (!$can_edit || $can_reinstate);
+ $cancel_uri = $this->getApplicationURI("event/cancel/{$id}/{$index}/");
+ } else if ($event->getInstanceOfEventPHID()) {
+ $can_reinstate = $event->getIsParentCancelled();
+ $cancel_label = pht('Cancel This Instance');
+ $reinstate_label = pht('Reinstate This Instance');
+ $cancel_disabled = (!$can_edit || $can_reinstate);
+ } else if ($event->getIsRecurring()) {
+ $cancel_label = pht('Cancel Recurrence');
+ $reinstate_label = pht('Reinstate Recurrence');
+ $cancel_disabled = !$can_edit;
+ } else {
+ $cancel_label = pht('Cancel Event');
+ $reinstate_label = pht('Reinstate Event');
+ }
+
if ($is_cancelled) {
$actions->addAction(
id(new PhabricatorActionView())
- ->setName(pht('Reinstate Event'))
+ ->setName($reinstate_label)
->setIcon('fa-plus')
- ->setHref($this->getApplicationURI("event/cancel/{$id}/"))
- ->setDisabled(!$can_edit)
+ ->setHref($cancel_uri)
+ ->setDisabled($cancel_disabled)
->setWorkflow(true));
} else {
$actions->addAction(
id(new PhabricatorActionView())
- ->setName(pht('Cancel Event'))
+ ->setName($cancel_label)
->setIcon('fa-times')
- ->setHref($this->getApplicationURI("event/cancel/{$id}/"))
- ->setDisabled(!$can_edit)
+ ->setHref($cancel_uri)
+ ->setDisabled($cancel_disabled)
->setWorkflow(true));
}
diff --git a/src/applications/calendar/storage/PhabricatorCalendarEvent.php b/src/applications/calendar/storage/PhabricatorCalendarEvent.php
--- a/src/applications/calendar/storage/PhabricatorCalendarEvent.php
+++ b/src/applications/calendar/storage/PhabricatorCalendarEvent.php
@@ -348,6 +348,10 @@
}
public function getIsParentCancelled() {
+ if ($this->instanceOfEventPHID == null) {
+ return false;
+ }
+
$recurring_event = $this->getParentEvent();
if ($recurring_event->getIsCancelled()) {
return true;

File Metadata

Mime Type
text/plain
Expires
Sun, Mar 16, 2:27 AM (1 w, 2 d ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
7386093
Default Alt Text
D13145.id31753.diff (10 KB)

Event Timeline