1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-12-18 19:40:55 +01:00

Edit recurring ghost events, not recurring event.

Summary: Closes T8358, Edit recurring ghost events, not recurring event.

Test Plan: Create recurring event, original event should not be editable, but ghost events should be editable.

Reviewers: #blessed_reviewers, epriestley

Reviewed By: #blessed_reviewers, epriestley

Subscribers: Korvin, epriestley

Maniphest Tasks: T8358

Differential Revision: https://secure.phabricator.com/D13075
This commit is contained in:
lkassianik 2015-05-31 15:04:48 -07:00
parent 9708f68e58
commit 65d9c0ea24
5 changed files with 122 additions and 7 deletions

View file

@ -53,7 +53,7 @@ final class PhabricatorCalendarApplication extends PhabricatorApplication {
'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',

View file

@ -86,6 +86,52 @@ final class PhabricatorCalendarEventEditController
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());

View file

@ -135,7 +135,19 @@ final class PhabricatorCalendarEventViewController
$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 @@ final class PhabricatorCalendarEventViewController
$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()));

View file

@ -10,6 +10,8 @@ final class PhabricatorCalendarEventQuery
private $inviteePHIDs;
private $creatorPHIDs;
private $isCancelled;
private $instanceSequencePairs;
private $generateGhosts = false;
@ -49,6 +51,11 @@ final class PhabricatorCalendarEventQuery
return $this;
}
public function withInstanceSequencePairs(array $pairs) {
$this->instanceSequencePairs = $pairs;
return $this;
}
protected function getDefaultOrderVector() {
return array('start', 'id');
}
@ -98,12 +105,15 @@ final class PhabricatorCalendarEventQuery
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 @@ final class PhabricatorCalendarEventQuery
$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 @@ final class PhabricatorCalendarEventQuery
(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);

View file

@ -203,6 +203,10 @@ final class PhabricatorCalendarEvent extends PhabricatorCalendarDAO
'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 @@ final class PhabricatorCalendarEvent extends PhabricatorCalendarDAO
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) {