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)