Page MenuHomePhabricator

D13075.id31542.diff
No OneTemporary

D13075.id31542.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
@@ -53,7 +53,7 @@
'event/' => array(
'create/'
=> 'PhabricatorCalendarEventEditController',
- 'edit/(?P<id>[1-9]\d*)/'
+ 'edit/(?P<id>[1-9]\d*)/(?:(?P<sequence>\d+)/)?'
=> 'PhabricatorCalendarEventEditController',
'drag/(?P<id>[1-9]\d*)/'
=> 'PhabricatorCalendarEventDragController',
diff --git a/src/applications/calendar/controller/PhabricatorCalendarEventEditController.php b/src/applications/calendar/controller/PhabricatorCalendarEventEditController.php
--- a/src/applications/calendar/controller/PhabricatorCalendarEventEditController.php
+++ b/src/applications/calendar/controller/PhabricatorCalendarEventEditController.php
@@ -86,6 +86,52 @@
return new Aphront404Response();
}
+ if ($request->getURIData('sequence')) {
+ $index = $request->getURIData('sequence');
+
+ $result = id(new PhabricatorCalendarEventQuery())
+ ->setViewer($viewer)
+ ->withInstanceSequencePairs(
+ array(
+ array(
+ $event->getPHID(),
+ $index,
+ ),
+ ))
+ ->requireCapabilities(
+ array(
+ PhabricatorPolicyCapability::CAN_VIEW,
+ PhabricatorPolicyCapability::CAN_EDIT,
+ ))
+ ->executeOne();
+
+ if ($result) {
+ return id(new AphrontRedirectResponse())
+ ->setURI('/calendar/event/edit/'.$result->getID().'/');
+ }
+
+ $invitees = $event->getInvitees();
+
+ $new_ghost = $event->generateNthGhost($index, $viewer);
+ $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
+ $new_ghost
+ ->setID(null)
+ ->setPHID(null)
+ ->removeViewerTimezone($viewer)
+ ->save();
+ $ghost_invitees = array();
+ foreach ($invitees as $invitee) {
+ $ghost_invitee = clone $invitee;
+ $ghost_invitee
+ ->setID(null)
+ ->setEventPHID($new_ghost->getPHID())
+ ->save();
+ }
+ unset($unguarded);
+ return id(new AphrontRedirectResponse())
+ ->setURI('/calendar/event/edit/'.$new_ghost->getID().'/');
+ }
+
$end_value = AphrontFormDateControlValue::newFromEpoch(
$viewer,
$event->getDateTo());
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
@@ -135,7 +135,19 @@
$event,
PhabricatorPolicyCapability::CAN_EDIT);
- if (!$event->getIsGhostEvent()) {
+ if (($event->getIsRecurring() && $event->getIsGhostEvent())) {
+ $index = $event->getSequenceIndex();
+
+ $actions->addAction(
+ id(new PhabricatorActionView())
+ ->setName(pht('Edit This Instance'))
+ ->setIcon('fa-pencil')
+ ->setHref($this->getApplicationURI("event/edit/{$id}/{$index}/"))
+ ->setDisabled(!$can_edit)
+ ->setWorkflow(!$can_edit));
+ }
+
+ if (!$event->getIsRecurring() && !$event->getIsGhostEvent()) {
$actions->addAction(
id(new PhabricatorActionView())
->setName(pht('Edit Event'))
@@ -219,7 +231,7 @@
$properties->addProperty(
pht('Recurs'),
ucwords(idx($event->getRecurrenceFrequency(), 'rule')));
- if ($event->getIsGhostEvent()) {
+ if ($event->getInstanceOfEventPHID()) {
$properties->addProperty(
pht('Recurrence of Event'),
$viewer->renderHandle($event->getInstanceOfEventPHID()));
diff --git a/src/applications/calendar/query/PhabricatorCalendarEventQuery.php b/src/applications/calendar/query/PhabricatorCalendarEventQuery.php
--- a/src/applications/calendar/query/PhabricatorCalendarEventQuery.php
+++ b/src/applications/calendar/query/PhabricatorCalendarEventQuery.php
@@ -10,6 +10,8 @@
private $inviteePHIDs;
private $creatorPHIDs;
private $isCancelled;
+ private $instanceSequencePairs;
+
private $generateGhosts = false;
@@ -49,6 +51,11 @@
return $this;
}
+ public function withInstanceSequencePairs(array $pairs) {
+ $this->instanceSequencePairs = $pairs;
+ return $this;
+ }
+
protected function getDefaultOrderVector() {
return array('start', 'id');
}
@@ -98,12 +105,15 @@
return $events;
}
+ $map = array();
+ $instance_sequence_pairs = array();
+
foreach ($events as $event) {
$sequence_start = 0;
$instance_count = null;
$duration = $event->getDateTo() - $event->getDateFrom();
- if ($event->getIsRecurring()) {
+ if ($event->getIsRecurring() && !$event->getInstanceOfEventPHID()) {
$frequency = $event->getFrequencyUnit();
$modify_key = '+1 '.$frequency;
@@ -147,7 +157,37 @@
$max_sequence = $sequence_start + $instance_count;
for ($index = $sequence_start; $index < $max_sequence; $index++) {
+ $instance_sequence_pairs[] = array($event->getPHID(), $index);
$events[] = $event->generateNthGhost($index, $viewer);
+
+ $key = last_key($events);
+ $map[$event->getPHID()][$index] = $key;
+ }
+ }
+ }
+
+ if (count($instance_sequence_pairs) > 0) {
+ $sub_query = id(new PhabricatorCalendarEventQuery())
+ ->setViewer($viewer)
+ ->setParentQuery($this)
+ ->withInstanceSequencePairs($instance_sequence_pairs)
+ ->execute();
+
+ foreach ($sub_query as $edited_ghost) {
+ $indexes = idx($map, $edited_ghost->getInstanceOfEventPHID());
+ $key = idx($indexes, $edited_ghost->getSequenceIndex());
+ $events[$key] = $edited_ghost;
+ }
+
+ $id_map = array();
+ foreach ($events as $key => $event) {
+ if ($event->getIsGhostEvent()) {
+ continue;
+ }
+ if (isset($id_map[$event->getID()])) {
+ unset($events[$key]);
+ } else {
+ $id_map[$event->getID()] = true;
}
}
}
@@ -220,6 +260,22 @@
(int)$this->isCancelled);
}
+ if ($this->instanceSequencePairs !== null) {
+ $sql = array();
+
+ foreach ($this->instanceSequencePairs as $pair) {
+ $sql[] = qsprintf(
+ $conn_r,
+ '(event.instanceOfEventPHID = %s AND event.sequenceIndex = %d)',
+ $pair[0],
+ $pair[1]);
+ }
+ $where[] = qsprintf(
+ $conn_r,
+ '%Q',
+ implode(' OR ', $sql));
+ }
+
$where[] = $this->buildPagingClause($conn_r);
return $this->formatWhereClause($where);
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
@@ -203,6 +203,10 @@
'userPHID_dateFrom' => array(
'columns' => array('userPHID', 'dateTo'),
),
+ 'key_instance' => array(
+ 'columns' => array('instanceOfEventPHID', 'sequenceIndex'),
+ 'unique' => true,
+ ),
),
self::CONFIG_SERIALIZATION => array(
'recurrenceFrequency' => self::SERIALIZATION_JSON,
@@ -391,9 +395,6 @@
public function hasAutomaticCapability($capability, PhabricatorUser $viewer) {
// The owner of a task can always view and edit it.
$user_phid = $this->getUserPHID();
- if ($this->isGhostEvent) {
- return false;
- }
if ($user_phid) {
$viewer_phid = $viewer->getPHID();
if ($viewer_phid == $user_phid) {

File Metadata

Mime Type
text/plain
Expires
Fri, Apr 4, 6:02 AM (2 w, 5 d ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
7388710
Default Alt Text
D13075.id31542.diff (7 KB)

Event Timeline