diff --git a/UI/Scheduler/UIxAppointmentEditor.m b/UI/Scheduler/UIxAppointmentEditor.m index 54ff083dc..1731f3810 100644 --- a/UI/Scheduler/UIxAppointmentEditor.m +++ b/UI/Scheduler/UIxAppointmentEditor.m @@ -672,7 +672,8 @@ * @apiSuccess (Success 200) {String} endDate End date (ISO8601) * @apiSuccess (Success 200) {String} localizedEndDate Formatted end date * @apiSuccess (Success 200) {String} [localizedEndTime] Formatted end time - * @apiSuccess (Success 200) {Number} isReadOnly 1 if event is read-only + * @apiSuccess (Success 200) {Number} isEditable 1 if event can be edited by the active user + * @apiSuccess (Success 200) {Number} isErasable 1 if event can be deleted by the active user * @apiSuccess (Success 200) {Number} userHasRSVP 1 if owner is invited * @apiSuccess (Success 200) {Number} [reply] 0 if needs-action, 1 if accepted, 2 if declined, 3 if tentative, 4 if delegated * @apiSuccess (Success 200) {Object[]} [attachUrls] Attached URLs @@ -826,7 +827,8 @@ [componentCalendar nameInContainer], @"pid", [componentCalendar displayName], @"calendar", [NSNumber numberWithBool: isAllDay], @"isAllDay", - [NSNumber numberWithBool: [self isReadOnly]], @"isReadOnly", + [NSNumber numberWithBool: [self isEditable]], @"isEditable", + [NSNumber numberWithBool: [self isErasable]], @"isErasable", [NSNumber numberWithBool: [self userHasRSVP]], @"userHasRSVP", [eventStartDate iso8601DateString], @"startDate", [eventEndDate iso8601DateString], @"endDate", diff --git a/UI/Scheduler/UIxComponentEditor.h b/UI/Scheduler/UIxComponentEditor.h index 44adb4ccc..35b94a037 100644 --- a/UI/Scheduler/UIxComponentEditor.h +++ b/UI/Scheduler/UIxComponentEditor.h @@ -1,6 +1,6 @@ /* UIxComponentEditor.h - this file is part of SOGo * - * Copyright (C) 2006-2015 Inverse inc. + * Copyright (C) 2006-2022 Inverse inc. * * This file is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -33,7 +33,8 @@ SOGoAppointmentFolder *componentCalendar; } -- (BOOL) isReadOnly; +- (BOOL) isEditable; +- (BOOL) isErasable; - (BOOL) userHasRSVP; - (NSNumber *) reply; - (BOOL) isChildOccurrence; diff --git a/UI/Scheduler/UIxComponentEditor.m b/UI/Scheduler/UIxComponentEditor.m index f45f35160..ea16510bb 100644 --- a/UI/Scheduler/UIxComponentEditor.m +++ b/UI/Scheduler/UIxComponentEditor.m @@ -837,10 +837,21 @@ static NSArray *reminderValues = nil; return rc; } -- (BOOL) isReadOnly +- (BOOL) isEditable { - return [self getEventRWType] != componentReadableWritable; + return [self getEventRWType] == componentReadableWritable; } + +- (BOOL) isErasable +{ + NSString *owner, *userLogin; + + userLogin = [[context activeUser] login]; + owner = [componentCalendar ownerInContext: context]; + + return ([owner isEqualToString: userLogin] || [[componentCalendar aclsForUser: userLogin] containsObject: SOGoRole_ObjectEraser]); +} + // //- (NSString *) emailAlarmsEnabled //{ diff --git a/UI/Scheduler/UIxTaskEditor.m b/UI/Scheduler/UIxTaskEditor.m index 0cb4d39eb..ad86e5c8f 100644 --- a/UI/Scheduler/UIxTaskEditor.m +++ b/UI/Scheduler/UIxTaskEditor.m @@ -431,7 +431,8 @@ * @apiSuccess (Success 200) {String} localizedDueTime Formatted due time * @apiSuccess (Success 200) {String} localizedCompletedDate Formatted completed date * @apiSuccess (Success 200) {String} localizedCompletedTime Formatted completed time - * @apiSuccess (Success 200) {Number} isReadOnly 1 if task is read-only + * @apiSuccess (Success 200) {Number} isEditable 1 if task can be edited by the active user + * @apiSuccess (Success 200) {Number} isErasable 1 if task can be deleted by the active user * @apiSuccess (Success 200) {Object[]} [attachUrls] Attached URLs * @apiSuccess (Success 200) {String} attachUrls.value URL * @@ -561,7 +562,8 @@ data = [NSMutableDictionary dictionaryWithObjectsAndKeys: [componentCalendar nameInContainer], @"pid", [componentCalendar displayName], @"calendar", - [NSNumber numberWithBool: [self isReadOnly]], @"isReadOnly", + [NSNumber numberWithBool: [self isEditable]], @"isEditable", + [NSNumber numberWithBool: [self isErasable]], @"isErasable", [self alarm], @"alarm", nil]; diff --git a/UI/Templates/SchedulerUI/UIxAppointmentEditorTemplate.wox b/UI/Templates/SchedulerUI/UIxAppointmentEditorTemplate.wox index 3bcd0a151..9a8692124 100644 --- a/UI/Templates/SchedulerUI/UIxAppointmentEditorTemplate.wox +++ b/UI/Templates/SchedulerUI/UIxAppointmentEditorTemplate.wox @@ -35,7 +35,7 @@ -
- + @@ -272,20 +272,23 @@ - +
- +
- - + +
- + diff --git a/UI/Templates/SchedulerUI/UIxTaskEditorTemplate.wox b/UI/Templates/SchedulerUI/UIxTaskEditorTemplate.wox index f11bdc014..bdcc202c4 100644 --- a/UI/Templates/SchedulerUI/UIxTaskEditorTemplate.wox +++ b/UI/Templates/SchedulerUI/UIxTaskEditorTemplate.wox @@ -34,7 +34,7 @@ -
- +
- +
- - + +
- + diff --git a/UI/WebServerResources/js/Scheduler/Calendar.service.js b/UI/WebServerResources/js/Scheduler/Calendar.service.js index 97982682a..2f31847f2 100644 --- a/UI/WebServerResources/js/Scheduler/Calendar.service.js +++ b/UI/WebServerResources/js/Scheduler/Calendar.service.js @@ -116,7 +116,7 @@ * @param {bool} [writable] - if true, returns only the list of writable calendars * @returns the list of calendars */ - Calendar.$findAll = function(data, writable) { + Calendar.$findAll = function(data, writable, contextId) { var _this = this; if (data) { this.$calendars = []; @@ -144,7 +144,7 @@ if (writable) { return _.union(this.$calendars, _.filter(this.$subscriptions, function(calendar) { - return calendar.isOwned || calendar.acls.objectCreator; + return calendar.isOwned || calendar.acls.objectCreator || calendar.id == contextId; })); } diff --git a/UI/WebServerResources/js/Scheduler/Component.service.js b/UI/WebServerResources/js/Scheduler/Component.service.js index 71a296b93..dc0bf5290 100644 --- a/UI/WebServerResources/js/Scheduler/Component.service.js +++ b/UI/WebServerResources/js/Scheduler/Component.service.js @@ -672,8 +672,8 @@ * @desc Check if the component is editable and not an occurrence of a recurrent component * @returns true or false */ - Component.prototype.isEditable = function() { - return (!this.occurrenceId && !this.isReadOnly); + Component.prototype.isActionable = function() { + return (!this.occurrenceId && !this.userHasRSVP && (this.isEditable || this.isErasable)); }; /** @@ -682,8 +682,8 @@ * @desc Check if the component is editable and an occurrence of a recurrent component * @returns true or false */ - Component.prototype.isEditableOccurrence = function() { - return (this.occurrenceId && !this.isReadOnly); + Component.prototype.isActionableOccurrence = function() { + return (this.occurrenceId && !this.userHasRSVP && (this.isEditable || this.isErasable)); }; /** @@ -706,18 +706,6 @@ return (this.occurrenceId && this.userHasRSVP); }; - /** - * @function isMovable - * @memberof Component.prototype - * @desc Return true if the component can be moved to a different calendar which occurs in two cases: - * - the component is editable, ie is owned by the current user; - * - the component is an invitation and the current user is an attendee. - * @returns true or false - */ - Component.prototype.isMovable = function() { - return (!this.isReadOnly || this.userHasRSVP); - }; - /** * @function showPercentComplete * @memberof Component.prototype @@ -810,7 +798,7 @@ */ Component.prototype.canRemindAttendeesByEmail = function() { return this.alarm.action == 'email' && - !this.isReadOnly && + this.isEditable && this.attendees && this.attendees.length > 0; }; diff --git a/UI/WebServerResources/js/Scheduler/ComponentController.js b/UI/WebServerResources/js/Scheduler/ComponentController.js index fe2cbdfd9..5da26e917 100644 --- a/UI/WebServerResources/js/Scheduler/ComponentController.js +++ b/UI/WebServerResources/js/Scheduler/ComponentController.js @@ -278,6 +278,13 @@ this.showRecurrenceEditor = true; }; + this.destinationCalendars = function () { + if (this.component.isErasable) + return Calendar.$findAll(null, true, this.component.pid); + else + return [Calendar.$get(this.component.pid)]; + }; + this.changeCalendar = function () { var updateRequired = (this.component.attendees && this.component.attendees.length > 0); if (updateRequired)