diff --git a/src/applications/calendar/controller/PhabricatorCalendarEventCancelController.php b/src/applications/calendar/controller/PhabricatorCalendarEventCancelController.php index 4be5a77d11..81736436a0 100644 --- a/src/applications/calendar/controller/PhabricatorCalendarEventCancelController.php +++ b/src/applications/calendar/controller/PhabricatorCalendarEventCancelController.php @@ -1,123 +1,124 @@ getViewer(); $id = $request->getURIData('id'); $sequence = $request->getURIData('sequence'); $event = id(new PhabricatorCalendarEventQuery()) ->setViewer($viewer) ->withIDs(array($id)) ->requireCapabilities( array( PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT, )) ->executeOne(); if ($sequence) { $parent_event = $event; $event = $parent_event->generateNthGhost($sequence, $viewer); $event->attachParentEvent($parent_event); } if (!$event) { return new Aphront404Response(); } if (!$sequence) { $cancel_uri = '/E'.$event->getID(); } else { $cancel_uri = '/E'.$event->getID().'/'.$sequence; } $is_cancelled = $event->getIsCancelled(); $is_parent_cancelled = $event->getIsParentCancelled(); $is_parent = $event->getIsRecurrenceParent(); $validation_exception = null; if ($request->isFormPost()) { if ($is_cancelled && $sequence) { return id(new AphrontRedirectResponse())->setURI($cancel_uri); } else if ($sequence) { $event = $this->createEventFromGhost( $viewer, $event, $sequence); $event->applyViewerTimezone($viewer); } $xactions = array(); $xaction = id(new PhabricatorCalendarEventTransaction()) ->setTransactionType( PhabricatorCalendarEventTransaction::TYPE_CANCEL) ->setNewValue(!$is_cancelled); $editor = id(new PhabricatorCalendarEventEditor()) ->setActor($viewer) ->setContentSourceFromRequest($request) ->setContinueOnNoEffect(true) ->setContinueOnMissingFields(true); try { $editor->applyTransactions($event, array($xaction)); return id(new AphrontRedirectResponse())->setURI($cancel_uri); } catch (PhabricatorApplicationTransactionValidationException $ex) { $validation_exception = $ex; } } if ($is_cancelled) { if ($sequence || $is_parent_cancelled) { $title = pht('Cannot Reinstate Instance'); $paragraph = pht( 'Cannot reinstate an instance of a cancelled recurring event.'); $cancel = pht('Cancel'); $submit = null; } else if ($is_parent) { $title = pht('Reinstate Recurrence'); $paragraph = pht( - 'Reinstate the entire series of recurring events?'); + 'Reinstate all instances of this recurrence + that have not been individually cancelled?'); $cancel = pht("Don't Reinstate Recurrence"); $submit = pht('Reinstate Recurrence'); } else { $title = pht('Reinstate Event'); $paragraph = pht('Reinstate this event?'); $cancel = pht("Don't Reinstate Event"); $submit = pht('Reinstate Event'); } } else { 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 ($is_parent) { $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() ->setTitle($title) ->setValidationException($validation_exception) ->appendParagraph($paragraph) ->addCancelButton($cancel_uri, $cancel) ->addSubmitButton($submit); } } diff --git a/src/applications/calendar/controller/PhabricatorCalendarEventViewController.php b/src/applications/calendar/controller/PhabricatorCalendarEventViewController.php index 7c3b34bc09..98d3a2fe74 100644 --- a/src/applications/calendar/controller/PhabricatorCalendarEventViewController.php +++ b/src/applications/calendar/controller/PhabricatorCalendarEventViewController.php @@ -1,388 +1,388 @@ getViewer(); $id = $request->getURIData('id'); $sequence = $request->getURIData('sequence'); $timeline = null; $event = id(new PhabricatorCalendarEventQuery()) ->setViewer($viewer) ->withIDs(array($id)) ->executeOne(); if (!$event) { return new Aphront404Response(); } if ($sequence) { $result = $this->getEventAtIndexForGhostPHID( $viewer, $event->getPHID(), $sequence); 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 = $event->getMonogram().' ('.$sequence.')'; $page_title = $title.' '.$event->getName(); $crumbs = $this->buildApplicationCrumbs(); $crumbs->addTextCrumb($title, '/'.$event->getMonogram().'/'.$sequence); } else { $title = 'E'.$event->getID(); $page_title = $title.' '.$event->getName(); $crumbs = $this->buildApplicationCrumbs(); $crumbs->addTextCrumb($title); $crumbs->setBorder(true); } if (!$event->getIsGhostEvent()) { $timeline = $this->buildTransactionTimeline( $event, new PhabricatorCalendarEventTransactionQuery()); } $header = $this->buildHeaderView($event); $curtain = $this->buildCurtain($event); $details = $this->buildPropertySection($event); $description = $this->buildDescriptionView($event); $is_serious = PhabricatorEnv::getEnvConfig('phabricator.serious-business'); $add_comment_header = $is_serious ? pht('Add Comment') : pht('Add To Plate'); $draft = PhabricatorDraft::newFromUserAndKey($viewer, $event->getPHID()); if ($sequence) { $comment_uri = $this->getApplicationURI( '/event/comment/'.$event->getID().'/'.$sequence.'/'); } else { $comment_uri = $this->getApplicationURI( '/event/comment/'.$event->getID().'/'); } $add_comment_form = id(new PhabricatorApplicationTransactionCommentView()) ->setUser($viewer) ->setObjectPHID($event->getPHID()) ->setDraft($draft) ->setHeaderText($add_comment_header) ->setAction($comment_uri) ->setSubmitButtonName(pht('Add Comment')); $view = id(new PHUITwoColumnView()) ->setHeader($header) ->setMainColumn(array( $timeline, $add_comment_form, )) ->setCurtain($curtain) ->addPropertySection(pht('Details'), $details) ->addPropertySection(pht('Description'), $description); return $this->newPage() ->setTitle($page_title) ->setCrumbs($crumbs) ->setPageObjectPHIDs(array($event->getPHID())) ->appendChild( array( $view, )); } private function buildHeaderView( PhabricatorCalendarEvent $event) { $viewer = $this->getViewer(); $id = $event->getID(); $is_cancelled = $event->getIsCancelled(); $icon = $is_cancelled ? ('fa-ban') : ('fa-check'); $color = $is_cancelled ? ('red') : ('bluegrey'); $status = $is_cancelled ? pht('Cancelled') : pht('Active'); $invite_status = $event->getUserInviteStatus($viewer->getPHID()); $status_invited = PhabricatorCalendarEventInvitee::STATUS_INVITED; $is_invite_pending = ($invite_status == $status_invited); $header = id(new PHUIHeaderView()) ->setUser($viewer) ->setHeader($event->getName()) ->setStatus($icon, $color, $status) ->setPolicyObject($event) ->setHeaderIcon('fa-calendar'); if ($is_invite_pending) { $decline_button = id(new PHUIButtonView()) ->setTag('a') ->setIcon('fa-times grey') ->setHref($this->getApplicationURI("/event/decline/{$id}/")) ->setWorkflow(true) ->setText(pht('Decline')); $accept_button = id(new PHUIButtonView()) ->setTag('a') ->setIcon('fa-check green') ->setHref($this->getApplicationURI("/event/accept/{$id}/")) ->setWorkflow(true) ->setText(pht('Accept')); $header->addActionLink($decline_button) ->addActionLink($accept_button); } return $header; } private function buildCurtain(PhabricatorCalendarEvent $event) { $viewer = $this->getRequest()->getUser(); $id = $event->getID(); $is_cancelled = $event->getIsCancelled(); $is_attending = $event->getIsUserAttending($viewer->getPHID()); $can_edit = PhabricatorPolicyFilter::hasCapability( $viewer, $event, PhabricatorPolicyCapability::CAN_EDIT); $edit_label = false; $edit_uri = false; if ($event->getIsGhostEvent()) { $index = $event->getSequenceIndex(); $edit_label = pht('Edit This Instance'); $edit_uri = "event/edit/{$id}/{$index}/"; } else if ($event->getIsRecurrenceException()) { $edit_label = pht('Edit This Instance'); $edit_uri = "event/edit/{$id}/"; } else { $edit_label = pht('Edit'); $edit_uri = "event/edit/{$id}/"; } $curtain = $this->newCurtainView($event); if ($edit_label && $edit_uri) { $curtain->addAction( id(new PhabricatorActionView()) ->setName($edit_label) ->setIcon('fa-pencil') ->setHref($this->getApplicationURI($edit_uri)) ->setDisabled(!$can_edit) ->setWorkflow(!$can_edit)); } if ($is_attending) { $curtain->addAction( id(new PhabricatorActionView()) ->setName(pht('Decline Event')) ->setIcon('fa-user-times') ->setHref($this->getApplicationURI("event/join/{$id}/")) ->setWorkflow(true)); } else { $curtain->addAction( id(new PhabricatorActionView()) ->setName(pht('Join Event')) ->setIcon('fa-user-plus') ->setHref($this->getApplicationURI("event/join/{$id}/")) ->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->getIsRecurrenceException()) { $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->getIsRecurrenceParent()) { - $cancel_label = pht('Cancel Recurrence'); - $reinstate_label = pht('Reinstate Recurrence'); + $cancel_label = pht('Cancel All'); + $reinstate_label = pht('Reinstate All'); $cancel_disabled = !$can_edit; } else { $cancel_label = pht('Cancel Event'); $reinstate_label = pht('Reinstate Event'); $cancel_disabled = !$can_edit; } if ($is_cancelled) { $curtain->addAction( id(new PhabricatorActionView()) ->setName($reinstate_label) ->setIcon('fa-plus') ->setHref($cancel_uri) ->setDisabled($cancel_disabled) ->setWorkflow(true)); } else { $curtain->addAction( id(new PhabricatorActionView()) ->setName($cancel_label) ->setIcon('fa-times') ->setHref($cancel_uri) ->setDisabled($cancel_disabled) ->setWorkflow(true)); } return $curtain; } private function buildPropertySection( PhabricatorCalendarEvent $event) { $viewer = $this->getViewer(); $properties = id(new PHUIPropertyListView()) ->setUser($viewer); if ($event->getIsAllDay()) { $date_start = phabricator_date($event->getDateFrom(), $viewer); $date_end = phabricator_date($event->getDateTo(), $viewer); if ($date_start == $date_end) { $properties->addProperty( pht('Time'), phabricator_date($event->getDateFrom(), $viewer)); } else { $properties->addProperty( pht('Starts'), phabricator_date($event->getDateFrom(), $viewer)); $properties->addProperty( pht('Ends'), phabricator_date($event->getDateTo(), $viewer)); } } else { $properties->addProperty( pht('Starts'), phabricator_datetime($event->getDateFrom(), $viewer)); $properties->addProperty( pht('Ends'), phabricator_datetime($event->getDateTo(), $viewer)); } if ($event->getIsRecurring()) { $properties->addProperty( pht('Recurs'), ucwords(idx($event->getRecurrenceFrequency(), 'rule'))); if ($event->getRecurrenceEndDate()) { $properties->addProperty( pht('Recurrence Ends'), phabricator_datetime($event->getRecurrenceEndDate(), $viewer)); } if ($event->getInstanceOfEventPHID()) { $properties->addProperty( pht('Recurrence of Event'), pht('%s of %s', $event->getSequenceIndex(), $viewer->renderHandle($event->getInstanceOfEventPHID())->render())); } } $properties->addProperty( pht('Host'), $viewer->renderHandle($event->getUserPHID())); $invitees = $event->getInvitees(); foreach ($invitees as $key => $invitee) { if ($invitee->isUninvited()) { unset($invitees[$key]); } } if ($invitees) { $invitee_list = new PHUIStatusListView(); $icon_invited = PHUIStatusItemView::ICON_OPEN; $icon_attending = PHUIStatusItemView::ICON_ACCEPT; $icon_declined = PHUIStatusItemView::ICON_REJECT; $status_invited = PhabricatorCalendarEventInvitee::STATUS_INVITED; $status_attending = PhabricatorCalendarEventInvitee::STATUS_ATTENDING; $status_declined = PhabricatorCalendarEventInvitee::STATUS_DECLINED; $icon_map = array( $status_invited => $icon_invited, $status_attending => $icon_attending, $status_declined => $icon_declined, ); $icon_color_map = array( $status_invited => null, $status_attending => 'green', $status_declined => 'red', ); foreach ($invitees as $invitee) { $item = new PHUIStatusItemView(); $invitee_phid = $invitee->getInviteePHID(); $status = $invitee->getStatus(); $target = $viewer->renderHandle($invitee_phid); $icon = $icon_map[$status]; $icon_color = $icon_color_map[$status]; $item->setIcon($icon, $icon_color) ->setTarget($target); $invitee_list->addItem($item); } } else { $invitee_list = phutil_tag( 'em', array(), pht('None')); } $properties->addProperty( pht('Invitees'), $invitee_list); $properties->invokeWillRenderEvent(); $properties->addProperty( pht('Icon'), id(new PhabricatorCalendarIconSet()) ->getIconLabel($event->getIcon())); return $properties; } private function buildDescriptionView( PhabricatorCalendarEvent $event) { $viewer = $this->getViewer(); $properties = id(new PHUIPropertyListView()) ->setUser($viewer); if (strlen($event->getDescription())) { $description = new PHUIRemarkupView($viewer, $event->getDescription()); $properties->addTextContent($description); return $properties; } return null; } }