Until date of repeat must end after first event

pull/220/head
Francis Lachapelle 2016-08-29 14:06:46 -04:00
parent ce5cc6843e
commit 07c66563e8
4 changed files with 77 additions and 53 deletions

2
NEWS
View File

@ -5,7 +5,7 @@ New features
-
Enhancements
-
- [web] don't allow a recurrence rule to end before the first occurrence
Bug fixes
- [eas] properly generate the BusyStatus for normal events

View File

@ -379,6 +379,8 @@ validate_notitle = "No title is set, continue?";
validate_invalid_startdate = "Incorrect startdate field!";
validate_invalid_enddate = "Incorrect enddate field!";
validate_endbeforestart = "The end date that you entered occurs before the start date.";
validate_untilbeforeend = "The recurrence must end after the first occurrence.";
"Events" = "Events";
"Tasks" = "Tasks";
"Show completed tasks" = "Show completed tasks";

View File

@ -187,17 +187,19 @@
}
*/
- (void) _adjustRecurrentRules
- (NSException *) _adjustRecurrentRules
{
iCalEvent *event;
iCalRecurrenceRule *rule;
NSEnumerator *rules;
NSException *ex;
NSCalendarDate *untilDate;
SOGoUserDefaults *ud;
NSTimeZone *timeZone;
event = [self event];
rules = [[event recurrenceRules] objectEnumerator];
ex = nil;
ud = [[context activeUser] userDefaults];
timeZone = [ud timeZone];
@ -206,22 +208,33 @@
untilDate = [rule untilDate];
if (untilDate)
{
// The until date must match the time of the end date
NSCalendarDate *date;
if ([untilDate compare: [event endDate]] == NSOrderedAscending)
{
ex = [NSException exceptionWithHTTPStatus: 500
reason: [self labelForKey: @"validate_untilbeforeend"]];
break;
}
else
{
// The until date must match the time of the end date
NSCalendarDate *date;
date = [[event endDate] copy];
[date setTimeZone: timeZone];
[untilDate setTimeZone: timeZone];
untilDate = [untilDate dateByAddingYears:0
months:0
days:0
hours:[date hourOfDay]
minutes:[date minuteOfHour]
seconds:0];
[rule setUntilDate: untilDate];
[date release];
date = [[event endDate] copy];
[date setTimeZone: timeZone];
[untilDate setTimeZone: timeZone];
untilDate = [untilDate dateByAddingYears:0
months:0
days:0
hours:[date hourOfDay]
minutes:[date minuteOfHour]
seconds:0];
[rule setUntilDate: untilDate];
[date release];
}
}
}
return ex;
}
/**
@ -481,47 +494,50 @@
forceSave = [[params objectForKey: @"ignoreConflicts"] boolValue];
if ([event hasRecurrenceRules])
[self _adjustRecurrentRules];
ex = [self _adjustRecurrentRules];
if ([co isNew])
if (!ex)
{
if (componentCalendar
&& ![[componentCalendar ocsPath]
isEqualToString: [previousCalendar ocsPath]])
if ([co isNew])
{
// New event in a different calendar -- make sure the user can
// write to the selected calendar since the rights were verified
// on the calendar specified in the URL, not on the selected
// calendar of the popup menu.
if (![sm validatePermission: SoPerm_AddDocumentsImagesAndFiles
onObject: componentCalendar
inContext: context])
co = [componentCalendar lookupName: [co nameInContainer]
inContext: context
acquire: NO];
}
// Save the event.
ex = [co saveComponent: event force: forceSave];
}
else
{
// The event was modified -- save it.
ex = [co saveComponent: event force: forceSave];
if (componentCalendar
&& ![[componentCalendar ocsPath]
isEqualToString: [previousCalendar ocsPath]])
{
// The event was moved to a different calendar.
if (![sm validatePermission: SoPerm_DeleteObjects
onObject: previousCalendar
inContext: context])
if (componentCalendar
&& ![[componentCalendar ocsPath]
isEqualToString: [previousCalendar ocsPath]])
{
// New event in a different calendar -- make sure the user can
// write to the selected calendar since the rights were verified
// on the calendar specified in the URL, not on the selected
// calendar of the popup menu.
if (![sm validatePermission: SoPerm_AddDocumentsImagesAndFiles
onObject: componentCalendar
inContext: context])
ex = [co moveToFolder: componentCalendar];
co = [componentCalendar lookupName: [co nameInContainer]
inContext: context
acquire: NO];
}
// Save the event.
ex = [co saveComponent: event force: forceSave];
}
else
{
// The event was modified -- save it.
ex = [co saveComponent: event force: forceSave];
if (componentCalendar
&& ![[componentCalendar ocsPath]
isEqualToString: [previousCalendar ocsPath]])
{
// The event was moved to a different calendar.
if (![sm validatePermission: SoPerm_DeleteObjects
onObject: previousCalendar
inContext: context])
{
if (![sm validatePermission: SoPerm_AddDocumentsImagesAndFiles
onObject: componentCalendar
inContext: context])
ex = [co moveToFolder: componentCalendar];
}
}
}
}

View File

@ -214,9 +214,15 @@
<label><var:string label:value="times"/></label>
<input type="number" label:aria-label="times" ng-model="editor.component.repeat.count"/>
</md-input-container>
<md-datepicker ng-show="editor.component.repeat.end == 'until'"
ng-model="editor.component.repeat.until"
label:md-placeholder="On Date"><!-- date picker --></md-datepicker>
<md-input-container ng-show="editor.component.repeat.end == 'until'">
<md-datepicker name="repeat_until"
ng-model="editor.component.repeat.until"
md-min-date="editor.component.end"
label:md-placeholder="On Date"><!-- date picker --></md-datepicker>
<div ng-messages="eventForm.repeat_until.$error">
<div ng-message="mindate"><var:string label:value="validate_untilbeforeend"/></div>
</div>
</md-input-container>
</div>
</div>
<!-- attendees -->
@ -296,7 +302,7 @@
<var:string label:value="Reset"/>
</md-button>
<md-button class="md-primary" type="submit"
ng-disabled="editor.eventForm.$invalid">
ng-disabled="eventForm.$invalid">
<var:string label:value="Save"/>
</md-button>
</md-dialog-actions>