diff --git a/src/applications/calendar/controller/PhabricatorCalendarController.php b/src/applications/calendar/controller/PhabricatorCalendarController.php index 36a9bfbbe9..88ffba9380 100644 --- a/src/applications/calendar/controller/PhabricatorCalendarController.php +++ b/src/applications/calendar/controller/PhabricatorCalendarController.php @@ -18,4 +18,23 @@ abstract class PhabricatorCalendarController extends PhabricatorController { ->setContent($ics_data); } + protected function newImportedEventResponse(PhabricatorCalendarEvent $event) { + if (!$event->isImportedEvent()) { + return null; + } + + // Give the user a specific, detailed message if they try to edit an + // imported event via common web paths. Other edits (including those via + // the API) are blocked by the normal policy system, but this makes it more + // clear exactly why the event can't be edited. + + return $this->newDialog() + ->setTitle(pht('Can Not Edit Imported Event')) + ->appendParagraph( + pht( + 'This event has been imported from an external source and '. + 'can not be edited.')) + ->addCancelButton($event->getURI(), pht('Done')); + } + } diff --git a/src/applications/calendar/controller/PhabricatorCalendarEventCancelController.php b/src/applications/calendar/controller/PhabricatorCalendarEventCancelController.php index 63ce289970..fbf7f9d45e 100644 --- a/src/applications/calendar/controller/PhabricatorCalendarEventCancelController.php +++ b/src/applications/calendar/controller/PhabricatorCalendarEventCancelController.php @@ -7,19 +7,27 @@ final class PhabricatorCalendarEventCancelController $viewer = $request->getViewer(); $id = $request->getURIData('id'); + // Just check CAN_VIEW first. Then we'll check if this is an import so + // we can raise a better error. $event = id(new PhabricatorCalendarEventQuery()) ->setViewer($viewer) ->withIDs(array($id)) - ->requireCapabilities( - array( - PhabricatorPolicyCapability::CAN_VIEW, - PhabricatorPolicyCapability::CAN_EDIT, - )) ->executeOne(); if (!$event) { return new Aphront404Response(); } + $response = $this->newImportedEventResponse($event); + if ($response) { + return $response; + } + + // Now that we've done the import check, check for CAN_EDIT. + PhabricatorPolicyFilter::requireCapability( + $viewer, + $event, + PhabricatorPolicyCapability::CAN_EDIT); + $cancel_uri = $event->getURI(); $is_parent = $event->isParentEvent(); diff --git a/src/applications/calendar/controller/PhabricatorCalendarEventEditController.php b/src/applications/calendar/controller/PhabricatorCalendarEventEditController.php index b5beea9019..7c01e795b7 100644 --- a/src/applications/calendar/controller/PhabricatorCalendarEventEditController.php +++ b/src/applications/calendar/controller/PhabricatorCalendarEventEditController.php @@ -4,6 +4,20 @@ final class PhabricatorCalendarEventEditController extends PhabricatorCalendarController { public function handleRequest(AphrontRequest $request) { + $viewer = $this->getViewer(); + + $id = $request->getURIData('id'); + if ($id) { + $event = id(new PhabricatorCalendarEventQuery()) + ->setViewer($viewer) + ->withIDs(array($id)) + ->executeOne(); + $response = $this->newImportedEventResponse($event); + if ($response) { + return $response; + } + } + return id(new PhabricatorCalendarEventEditEngine()) ->setController($this) ->buildResponse(); diff --git a/src/applications/calendar/controller/PhabricatorCalendarEventJoinController.php b/src/applications/calendar/controller/PhabricatorCalendarEventJoinController.php index 9b58d39dec..52ad8cb133 100644 --- a/src/applications/calendar/controller/PhabricatorCalendarEventJoinController.php +++ b/src/applications/calendar/controller/PhabricatorCalendarEventJoinController.php @@ -15,6 +15,11 @@ final class PhabricatorCalendarEventJoinController return new Aphront404Response(); } + $response = $this->newImportedEventResponse($event); + if ($response) { + return $response; + } + $cancel_uri = $event->getURI(); $action = $request->getURIData('action'); diff --git a/src/applications/calendar/controller/PhabricatorCalendarEventViewController.php b/src/applications/calendar/controller/PhabricatorCalendarEventViewController.php index 89e8109a4c..c8bc9b5593 100644 --- a/src/applications/calendar/controller/PhabricatorCalendarEventViewController.php +++ b/src/applications/calendar/controller/PhabricatorCalendarEventViewController.php @@ -63,6 +63,19 @@ final class PhabricatorCalendarEventViewController ->setHeader(pht('Details')); $recurring_header = $this->buildRecurringHeader($event); + // NOTE: This is a bit hacky: for imported events, we're just hiding the + // comment form without actually preventing comments. Users could still + // submit a request to add comments to these events. This isn't really a + // major problem since they can't do anything truly bad and there isn't an + // easy way to selectively disable this or some other similar behaviors + // today, but it would probably be nice to fully disable these + // "pseudo-edits" (like commenting and probably subscribing and awarding + // tokens) at some point. + if ($event->isImportedEvent()) { + $comment_view = null; + $timeline->setShouldTerminate(true); + } + $view = id(new PHUITwoColumnView()) ->setHeader($header) ->setSubheader($subheader) @@ -105,6 +118,16 @@ final class PhabricatorCalendarEventViewController ->setPolicyObject($event) ->setHeaderIcon($event->getIcon()); + if ($event->isImportedEvent()) { + $header->addTag( + id(new PHUITagView()) + ->setType(PHUITagView::TYPE_SHADE) + ->setName(pht('Imported')) + ->setIcon('fa-download') + ->setHref($event->getImportSource()->getURI()) + ->setShade('orange')); + } + foreach ($this->buildRSVPActions($event) as $action) { $header->addActionLink($action); } @@ -141,12 +164,15 @@ final class PhabricatorCalendarEventViewController ->setWorkflow(!$can_edit)); } + $can_attend = !$event->isImportedEvent(); + if ($is_attending) { $curtain->addAction( id(new PhabricatorActionView()) ->setName(pht('Decline Event')) ->setIcon('fa-user-times') ->setHref($this->getApplicationURI("event/join/{$id}/")) + ->setDisabled(!$can_attend) ->setWorkflow(true)); } else { $curtain->addAction( @@ -154,6 +180,7 @@ final class PhabricatorCalendarEventViewController ->setName(pht('Join Event')) ->setIcon('fa-user-plus') ->setHref($this->getApplicationURI("event/join/{$id}/")) + ->setDisabled(!$can_attend) ->setWorkflow(true)); } @@ -261,6 +288,15 @@ final class PhabricatorCalendarEventViewController pht('None')); } + if ($event->isImportedEvent()) { + $properties->addProperty( + pht('Imported By'), + pht( + '%s from %s', + $viewer->renderHandle($event->getImportAuthorPHID()), + $viewer->renderHandle($event->getImportSourcePHID()))); + } + $properties->addProperty( pht('Invitees'), $invitee_list); diff --git a/src/applications/calendar/phid/PhabricatorCalendarImportPHIDType.php b/src/applications/calendar/phid/PhabricatorCalendarImportPHIDType.php index 05d1cc0bb9..876ec7acf7 100644 --- a/src/applications/calendar/phid/PhabricatorCalendarImportPHIDType.php +++ b/src/applications/calendar/phid/PhabricatorCalendarImportPHIDType.php @@ -33,7 +33,7 @@ final class PhabricatorCalendarImportPHIDType extends PhabricatorPHIDType { $import = $objects[$phid]; $id = $import->getID(); - $name = $import->getName(); + $name = $import->getDisplayName(); $uri = $import->getURI(); $handle diff --git a/src/applications/calendar/storage/PhabricatorCalendarEvent.php b/src/applications/calendar/storage/PhabricatorCalendarEvent.php index 7ad6d85881..6baa54e008 100644 --- a/src/applications/calendar/storage/PhabricatorCalendarEvent.php +++ b/src/applications/calendar/storage/PhabricatorCalendarEvent.php @@ -576,6 +576,10 @@ final class PhabricatorCalendarEvent extends PhabricatorCalendarDAO } } + if ($this->isImportedEvent()) { + return 'fa-download'; + } + return $this->getIcon(); } @@ -584,6 +588,10 @@ final class PhabricatorCalendarEvent extends PhabricatorCalendarDAO return 'red'; } + if ($this->isImportedEvent()) { + return 'orange'; + } + if ($viewer->isLoggedIn()) { $status = $this->getUserInviteStatus($viewer->getPHID()); switch ($status) {