mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-27 09:12:41 +01:00
Respect "End Date" for recurring Calendar events in detail UI
Summary: Fixes T11396. Currently, you can keep clicking "Next >" forever to generate infinite instances of an event, even if it has a set end date. Likewise, you can visit `/E123/999999` or whatever to stub out the 999999th instance of an event. Instead: - Before creating a new stub, make sure it happens before any end date. - 404 stubs if we can't create them. - Disable the "Next >" button if it isn't valid. Test Plan: - Visited `/E123/9999` for an event with a recurrence end date, got 404. - Clicked "Next >" on an event with an end date, got new events until I hit the end date. Reviewers: chad Reviewed By: chad Maniphest Tasks: T11396 Differential Revision: https://secure.phabricator.com/D16517
This commit is contained in:
parent
5a33a6743e
commit
25bd14a9b1
2 changed files with 62 additions and 18 deletions
|
@ -278,7 +278,14 @@ final class PhabricatorCalendarEventViewController
|
|||
$parent = $event->getParentEvent();
|
||||
}
|
||||
|
||||
$next_uri = $parent->getURI().'/'.($sequence + 1);
|
||||
if ($parent->isValidSequenceIndex($viewer, $sequence + 1)) {
|
||||
$next_uri = $parent->getURI().'/'.($sequence + 1);
|
||||
$has_next = true;
|
||||
} else {
|
||||
$next_uri = null;
|
||||
$has_next = false;
|
||||
}
|
||||
|
||||
if ($sequence) {
|
||||
if ($sequence > 1) {
|
||||
$previous_uri = $parent->getURI().'/'.($sequence - 1);
|
||||
|
@ -302,6 +309,7 @@ final class PhabricatorCalendarEventViewController
|
|||
->setTag('a')
|
||||
->setIcon('fa-chevron-right')
|
||||
->setHref($next_uri)
|
||||
->setDisabled(!$has_next)
|
||||
->setText(pht('Next'));
|
||||
|
||||
$header
|
||||
|
@ -450,9 +458,11 @@ final class PhabricatorCalendarEventViewController
|
|||
'it.'));
|
||||
}
|
||||
|
||||
$instance = $event->newStub($viewer, $sequence);
|
||||
if (!$event->isValidSequenceIndex($viewer, $sequence)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $instance;
|
||||
return $event->newStub($viewer, $sequence);
|
||||
}
|
||||
|
||||
private function buildSubheaderView(PhabricatorCalendarEvent $event) {
|
||||
|
|
|
@ -137,7 +137,8 @@ final class PhabricatorCalendarEvent extends PhabricatorCalendarDAO
|
|||
);
|
||||
|
||||
// Read these fields from the parent event instead of this event. For
|
||||
// example, we want any changes to the parent event's name to
|
||||
// example, we want any changes to the parent event's name to apply to
|
||||
// the child.
|
||||
if (isset($inherit[$field])) {
|
||||
if ($this->getIsStub()) {
|
||||
// TODO: This should be unconditional, but the execution order of
|
||||
|
@ -171,33 +172,66 @@ final class PhabricatorCalendarEvent extends PhabricatorCalendarDAO
|
|||
->setName($parent->getName())
|
||||
->setDescription($parent->getDescription());
|
||||
|
||||
$frequency = $parent->getFrequencyUnit();
|
||||
$modify_key = '+'.$this->getSequenceIndex().' '.$frequency;
|
||||
$sequence = $this->getSequenceIndex();
|
||||
$duration = $this->getDuration();
|
||||
$epochs = $parent->getSequenceIndexEpochs($actor, $sequence, $duration);
|
||||
|
||||
$date = $parent->getDateFrom();
|
||||
$date_time = PhabricatorTime::getDateTimeFromEpoch($date, $actor);
|
||||
$this
|
||||
->setDateFrom($epochs['dateFrom'])
|
||||
->setDateTo($epochs['dateTo'])
|
||||
->setAllDayDateFrom($epochs['allDayDateFrom'])
|
||||
->setAllDayDateTo($epochs['allDayDateTo']);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function isValidSequenceIndex(PhabricatorUser $viewer, $sequence) {
|
||||
try {
|
||||
$this->getSequenceIndexEpochs($viewer, $sequence, $this->getDuration());
|
||||
return true;
|
||||
} catch (Exception $ex) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private function getSequenceIndexEpochs(
|
||||
PhabricatorUser $viewer,
|
||||
$sequence,
|
||||
$duration) {
|
||||
|
||||
$frequency = $this->getFrequencyUnit();
|
||||
$modify_key = '+'.$sequence.' '.$frequency;
|
||||
|
||||
$date = $this->getDateFrom();
|
||||
$date_time = PhabricatorTime::getDateTimeFromEpoch($date, $viewer);
|
||||
$date_time->modify($modify_key);
|
||||
$date = $date_time->format('U');
|
||||
|
||||
$duration = $this->getDuration();
|
||||
$end_date = $this->getRecurrenceEndDate();
|
||||
if ($end_date && $date > $end_date) {
|
||||
throw new Exception(
|
||||
pht(
|
||||
'Sequence "%s" is invalid for this event: it would occur after '.
|
||||
'the event stops repeating.',
|
||||
$sequence));
|
||||
}
|
||||
|
||||
$utc = new DateTimeZone('UTC');
|
||||
|
||||
$allday_from = $parent->getAllDayDateFrom();
|
||||
$allday_from = $this->getAllDayDateFrom();
|
||||
$allday_date = new DateTime('@'.$allday_from, $utc);
|
||||
$allday_date->setTimeZone($utc);
|
||||
$allday_date->modify($modify_key);
|
||||
|
||||
$allday_min = $allday_date->format('U');
|
||||
$allday_duration = ($parent->getAllDayDateTo() - $allday_from);
|
||||
$allday_duration = ($this->getAllDayDateTo() - $allday_from);
|
||||
|
||||
$this
|
||||
->setDateFrom($date)
|
||||
->setDateTo($date + $duration)
|
||||
->setAllDayDateFrom($allday_min)
|
||||
->setAllDayDateTo($allday_min + $allday_duration);
|
||||
|
||||
return $this;
|
||||
return array(
|
||||
'dateFrom' => $date,
|
||||
'dateTo' => $date + $duration,
|
||||
'allDayDateFrom' => $allday_min,
|
||||
'allDayDateTo' => $allday_min + $allday_duration,
|
||||
);
|
||||
}
|
||||
|
||||
public function newStub(PhabricatorUser $actor, $sequence) {
|
||||
|
|
Loading…
Reference in a new issue