From e669833576e7149cee9d5b45b792ec5035ce41ea Mon Sep 17 00:00:00 2001
From: srosse <none@none>
Date: Fri, 21 Aug 2015 14:54:52 +0200
Subject: [PATCH] OO-1644: add managed and externalId to calendar events, add
 configuration for managed calendars at the same place as groups and courses,
 block edition of managed events

---
 .../admin/restapi/RestapiAdminController.java | 39 ++++++++++++-------
 .../restapi/_i18n/LocalStrings_de.properties  |  1 +
 .../restapi/_i18n/LocalStrings_en.properties  |  1 +
 .../commons/calendar/CalendarManager.java     |  2 +
 .../olat/commons/calendar/CalendarModule.java | 18 +++++++++
 .../olat/commons/calendar/CalendarUtils.java  | 10 ++---
 .../calendar/ICalFileCalendarManager.java     | 26 +++++++++++--
 .../commons/calendar/model/KalendarEvent.java | 19 +++++++++
 .../commons/calendar/restapi/EventVO.java     | 21 ++++++++++
 .../ui/CalendarDetailsController.java         | 11 ++++--
 .../calendar/ui/WeeklyCalendarController.java |  2 +
 .../FullCalendarComponentRenderer.java        | 16 +-------
 .../resources/serviceconfig/olat.properties   |  3 ++
 13 files changed, 129 insertions(+), 40 deletions(-)

diff --git a/src/main/java/org/olat/admin/restapi/RestapiAdminController.java b/src/main/java/org/olat/admin/restapi/RestapiAdminController.java
index 58ce2e853a5..7f15212e89d 100644
--- a/src/main/java/org/olat/admin/restapi/RestapiAdminController.java
+++ b/src/main/java/org/olat/admin/restapi/RestapiAdminController.java
@@ -19,7 +19,7 @@
  */
 package org.olat.admin.restapi;
 
-import org.olat.core.CoreSpringFactory;
+import org.olat.commons.calendar.CalendarModule;
 import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.components.form.flexible.FormItem;
 import org.olat.core.gui.components.form.flexible.FormItemContainer;
@@ -34,36 +34,37 @@ import org.olat.group.BusinessGroupModule;
 import org.olat.repository.RepositoryModule;
 import org.olat.restapi.RestModule;
 import org.olat.restapi.security.RestSecurityHelper;
+import org.springframework.beans.factory.annotation.Autowired;
 
 /**
  * 
  * Description:<br>
- * This is a controller to configure the SimpleVersionConfig, the configuration
- * of the versioning system for briefcase.
+ * This is a controller to configure the REST API and the
+ * managed courses, groups and calendars.
  * 
  * <P>
  * Initial Date:  21 sept. 2009 <br>
  *
- * @author srosse
+ * @author srosse, stephane.rosse@frentix.com, https://ww.frentix.com
  */
 public class RestapiAdminController extends FormBasicController {
 	
-	private MultipleSelectionElement enabled, managedGroupsEl, managedRepoEl;
+	private MultipleSelectionElement enabled, managedGroupsEl, managedRepoEl, managedCalendarEl;
 	private FormLayoutContainer docLinkFlc;
 	
 	private static final String[] keys = {"on"};
 	
-	private final RestModule restModule;
-	private final BusinessGroupModule groupModule;
-	private final RepositoryModule repositoryModule;
+	@Autowired
+	private RestModule restModule;
+	@Autowired
+	private CalendarModule calendarModule;
+	@Autowired
+	private BusinessGroupModule groupModule;
+	@Autowired
+	private RepositoryModule repositoryModule;
 
 	public RestapiAdminController(UserRequest ureq, WindowControl wControl) {
 		super(ureq, wControl, "rest");
-
-		restModule = CoreSpringFactory.getImpl(RestModule.class);
-		groupModule = CoreSpringFactory.getImpl(BusinessGroupModule.class);
-		repositoryModule = CoreSpringFactory.getImpl(RepositoryModule.class);
-		
 		initForm(ureq);
 	}
 	
@@ -106,6 +107,11 @@ public class RestapiAdminController extends FormBasicController {
 			managedRepoEl = uifactory.addCheckboxesHorizontal("managed.repo", managedFlc, keys, valueRes);
 			managedRepoEl.addActionListener(FormEvent.ONCHANGE);
 			managedRepoEl.select(keys[0], repositoryModule.isManagedRepositoryEntries());
+			
+			String[] valueCal = new String[] { getTranslator().translate("rest.on") };
+			managedCalendarEl = uifactory.addCheckboxesHorizontal("managed.cal", managedFlc, keys, valueCal);
+			managedCalendarEl.addActionListener(FormEvent.ONCHANGE);
+			managedCalendarEl.select(keys[0], calendarModule.isManagedCalendars());
 		}
 	}
 
@@ -127,11 +133,14 @@ public class RestapiAdminController extends FormBasicController {
 			docLinkFlc.setVisible(on);
 			getWindowControl().setInfo("saved");
 		} else if(source == managedGroupsEl) {
-			boolean enabled = managedGroupsEl.isAtLeastSelected(1);
-			groupModule.setManagedBusinessGroups(enabled);
+			boolean enable = managedGroupsEl.isAtLeastSelected(1);
+			groupModule.setManagedBusinessGroups(enable);
 		} else if (source == managedRepoEl) {
 			boolean enable = managedRepoEl.isAtLeastSelected(1);
 			repositoryModule.setManagedRepositoryEntries(enable);
+		} else if (source == managedCalendarEl) {
+			boolean enable = managedCalendarEl.isAtLeastSelected(1);
+			calendarModule.setManagedCalendars(enable);
 		}
 		super.formInnerEvent(ureq, source, event);
 	}
diff --git a/src/main/java/org/olat/admin/restapi/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/admin/restapi/_i18n/LocalStrings_de.properties
index e112e2352b1..38648b766b6 100644
--- a/src/main/java/org/olat/admin/restapi/_i18n/LocalStrings_de.properties
+++ b/src/main/java/org/olat/admin/restapi/_i18n/LocalStrings_de.properties
@@ -13,6 +13,7 @@ chelp.managed.title=Extern verwaltete Kurse und Gruppen
 chelp.managed.ID=Über das REST API können für Kurse und Gruppen die ID des externen Systems hinterlegt werden. Bei Kursen ist kann zudem eine externe Referenz verwendet werden, die aus Benutzersicht eine Identifikation des Kurses ermöglicht. 
 chelp.managed.flags=Verwendet man die externen ID's für Kurse oder Gruppen, so ist zusätzlich zu definieren welche Elemente einer sochen extern erstellten Ressource in OpenOLAT nicht verwaltet werden dürfen. Dies wird mit sogenannten "managed Flags" definiert. Es können entweder alle Elemente von extern verwaltet sein oder feingranular z.B. nur die Metadaten und die Benutzerverwaltung. Die Konfiguration der "managed Flags" entnehmen Sie der technischen dokumentation des REST API. 
 chelp.managed.enabled=Ist die externe Verwaltung eingeschaltet, so werden in der OpenOLAT Benutzerschnittstelle für entsprechende Ressourcen die mit den "managed Flags" konfigurierten Elemente als nicht editierbar dargestellt. Zudem werden die externen Id's in Suchfeldern, Anzeigen und Tabellen verwendet. Andere, nicht extern erstellte Ressourcen können parallell dazu normal verwendet und verwaltet werden. 
+managed.cal=Managed Kalender
 managed.objects=Extern verwaltete Kurse und Gruppen
 managed.intro=Kurse und Gruppen können über das REST API erstellt werden. Solch extern erstellt Kurse und Gruppen werden als "managed" bezeichnet da ein externes System das datenführende System ist. Die Verwendung dieser Funktion können Sie hier ein- und ausschalten.
 managed.group=Managed Gruppen
diff --git a/src/main/java/org/olat/admin/restapi/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/admin/restapi/_i18n/LocalStrings_en.properties
index 16fb9c48b2f..f5a0a57c8e3 100644
--- a/src/main/java/org/olat/admin/restapi/_i18n/LocalStrings_en.properties
+++ b/src/main/java/org/olat/admin/restapi/_i18n/LocalStrings_en.properties
@@ -7,6 +7,7 @@ chelp.rest.intro=With this form you can activate or deactivate the REST API. $\:
 chelp.rest.title=REST API
 help.hover.managed=Help about externally managed courses and groups
 help.hover.rest=Configure REST API
+managed.cal=Managed calendars
 managed.flags.course.access=Access configuration
 managed.flags.course.all=Fully externally managed
 managed.flags.course.bookings=Booking rules
diff --git a/src/main/java/org/olat/commons/calendar/CalendarManager.java b/src/main/java/org/olat/commons/calendar/CalendarManager.java
index 9b48c3b5b91..641d1bbe5d9 100644
--- a/src/main/java/org/olat/commons/calendar/CalendarManager.java
+++ b/src/main/java/org/olat/commons/calendar/CalendarManager.java
@@ -53,6 +53,8 @@ public interface CalendarManager {
 	public static final String ICAL_X_OLAT_NUMPARTICIPANTS = "X-OLAT-NUMPARTICIPANTS";
 	public static final String ICAL_X_OLAT_PARTICIPANTS = "X-OLAT-PARTICIPANTS";
 	public static final String ICAL_X_OLAT_SOURCENODEID = "X-OLAT-SOURCENODEID";
+	public static final String ICAL_X_OLAT_MANAGED = "X-OLAT-MANAGED";
+	public static final String ICAL_X_OLAT_EXTERNAL_ID = "X-OLAT-EXTERNAL-ID";
 	
 	public static final int MAX_SUBJECT_DISPLAY_LENGTH = 30;
 
diff --git a/src/main/java/org/olat/commons/calendar/CalendarModule.java b/src/main/java/org/olat/commons/calendar/CalendarModule.java
index 4da0476193c..d8626c47d2d 100644
--- a/src/main/java/org/olat/commons/calendar/CalendarModule.java
+++ b/src/main/java/org/olat/commons/calendar/CalendarModule.java
@@ -52,6 +52,7 @@ public class CalendarModule extends AbstractSpringModule {
 	private static final String CALENDAR_GROUP_ENABLED = "calendar.group.enabled";
 	private static final String CALENDAR_COURSE_TOOL_ENABLED = "calendar.course.tool.enabled";
 	private static final String CALENDAR_COURSE_ELEMENT_ENABLED = "calendar.course.element.enabled";
+	private static final String MANAGED_CAL_ENABLED = "managedCalendars";
 	
 	private TimeZone defaultTimeZone;
 	private TimeZoneRegistry timeZoneRegistry;
@@ -66,6 +67,9 @@ public class CalendarModule extends AbstractSpringModule {
 	private boolean enableCourseToolCalendar;
 	@Value("${calendar.course.element.enabled:true}")
 	private boolean enableCourseElementCalendar;
+
+	@Value("${calendar.managed:false}")
+	private boolean managedCalendars;
 	
 	@Autowired
 	public CalendarModule(CoordinatorManager coordinatorManager) {
@@ -118,6 +122,11 @@ public class CalendarModule extends AbstractSpringModule {
 		if(StringHelper.containsNonWhitespace(courseElementEnabledObj)) {
 			enableCourseElementCalendar = "true".equals(courseElementEnabledObj);
 		}
+		
+		String managedCalEnabledObj = getStringPropertyValue(MANAGED_CAL_ENABLED, true);
+		if(StringHelper.containsNonWhitespace(managedCalEnabledObj)) {
+			managedCalendars = "true".equals(managedCalEnabledObj);
+		}
 	}
 	
 	public TimeZone getDefaultTimeZone() {
@@ -168,4 +177,13 @@ public class CalendarModule extends AbstractSpringModule {
 		this.enableCourseElementCalendar = enableCourseElementCalendar;
 		setStringProperty(CALENDAR_COURSE_ELEMENT_ENABLED, Boolean.toString(enableCourseElementCalendar), true);
 	}
+	
+	public boolean isManagedCalendars() {
+		return managedCalendars;
+	}
+
+	public void setManagedCalendars(boolean enabled) {
+		this.managedCalendars = enabled;
+		setStringProperty(MANAGED_CAL_ENABLED, Boolean.toString(enabled), true);
+	}
 }
\ No newline at end of file
diff --git a/src/main/java/org/olat/commons/calendar/CalendarUtils.java b/src/main/java/org/olat/commons/calendar/CalendarUtils.java
index 4ba4ceb9d42..29cd1b4ae8c 100644
--- a/src/main/java/org/olat/commons/calendar/CalendarUtils.java
+++ b/src/main/java/org/olat/commons/calendar/CalendarUtils.java
@@ -54,7 +54,7 @@ import org.olat.core.logging.OLog;
 import org.olat.core.logging.Tracing;
 
 public class CalendarUtils {
-	static OLog log = Tracing.createLoggerFor(CalendarUtils.class);
+	private static final OLog log = Tracing.createLoggerFor(CalendarUtils.class);
 	private static final SimpleDateFormat ical4jFormatter = new SimpleDateFormat("yyyyMMdd");
 
 	public static String getTimeAsString(Date date, Locale locale) {
@@ -291,7 +291,7 @@ public class CalendarUtils {
 					return frequency;
 				}
 			} catch (ParseException e) {
-				Tracing.createLoggerFor(CalendarUtils.class).error("cannot restore recurrence rule", e);
+				log.error("cannot restore recurrence rule", e);
 			}
 		}
 		
@@ -317,7 +317,7 @@ public class CalendarUtils {
 					return dtUntil;
 				}
 			} catch (ParseException e) {
-				Tracing.createLoggerFor(CalendarUtils.class).error("cannot restore recurrence rule", e);
+				log.error("cannot restore recurrence rule", e);
 			}
 		}
 		
@@ -366,7 +366,7 @@ public class CalendarUtils {
 				RRule rrule = new RRule(recur);
 				return rrule.getValue();
 			} catch (ParseException e) {
-				Tracing.createLoggerFor(CalendarUtils.class).error("cannot create recurrence rule: " + recurrence.toString(), e);
+				log.error("cannot create recurrence rule: " + recurrence.toString(), e);
 			}
 		}
 		
@@ -390,7 +390,7 @@ public class CalendarUtils {
 					recurExcDates.add(excDate);
 				}
 			} catch (ParseException e) {
-				Tracing.createLoggerFor(CalendarUtils.class).error("cannot restore recurrence exceptions", e);
+				log.error("cannot restore recurrence exceptions", e);
 			}
 		}
 		
diff --git a/src/main/java/org/olat/commons/calendar/ICalFileCalendarManager.java b/src/main/java/org/olat/commons/calendar/ICalFileCalendarManager.java
index 29a4c4519ad..89ee961fcfc 100644
--- a/src/main/java/org/olat/commons/calendar/ICalFileCalendarManager.java
+++ b/src/main/java/org/olat/commons/calendar/ICalFileCalendarManager.java
@@ -452,6 +452,14 @@ public class ICalFileCalendarManager implements CalendarManager {
 			vEventProperties.add(new XProperty(ICAL_X_OLAT_SOURCENODEID, kEvent.getSourceNodeId()));
 		}
 		
+		if(kEvent.isManaged()) {
+			vEventProperties.add(new XProperty(ICAL_X_OLAT_MANAGED, "true"));
+		}
+		
+		if(StringHelper.containsNonWhitespace(kEvent.getExternalId())) {
+			vEventProperties.add(new XProperty(ICAL_X_OLAT_EXTERNAL_ID, kEvent.getExternalId()));
+		}
+		
 		// recurrence
 		String recurrence = kEvent.getRecurrenceRule();
 		if(recurrence != null && !recurrence.equals("")) {
@@ -460,9 +468,10 @@ public class ICalFileCalendarManager implements CalendarManager {
 				RRule rrule = new RRule(recur);
 				vEventProperties.add(rrule);
 			} catch (ParseException e) {
-				Tracing.createLoggerFor(getClass()).error("cannot create recurrence rule: " + recurrence.toString(), e);
+				log.error("cannot create recurrence rule: " + recurrence.toString(), e);
 			}
 		}
+		
 		// recurrence exclusions
 		String recurrenceExc = kEvent.getRecurrenceExc();
 		if(recurrenceExc != null && !recurrenceExc.equals("")) {
@@ -471,7 +480,7 @@ public class ICalFileCalendarManager implements CalendarManager {
 				exdate.setValue(recurrenceExc);
 				vEventProperties.add(exdate);
 			} catch (ParseException e) {
-				e.printStackTrace();
+				log.error("", e);
 			}
 		}
 		
@@ -603,8 +612,19 @@ public class ICalFileCalendarManager implements CalendarManager {
 		}
 		
 		Property sourceNodId = event.getProperty(ICAL_X_OLAT_SOURCENODEID);
-		if (sourceNodId != null)
+		if (sourceNodId != null) {
 			calEvent.setSourceNodeId(sourceNodId.getValue());
+		}
+		
+		Property managed = event.getProperty(ICAL_X_OLAT_MANAGED);
+		if(managed != null) {
+			calEvent.setManaged("true".equals(managed.getValue()));
+		}
+		
+		Property externalId = event.getProperty(ICAL_X_OLAT_EXTERNAL_ID);
+		if(externalId != null) {
+			calEvent.setExternalId(externalId.getValue());
+		}
 		
 		// recurrence
 		if (event.getProperty(ICAL_RRULE) != null) {
diff --git a/src/main/java/org/olat/commons/calendar/model/KalendarEvent.java b/src/main/java/org/olat/commons/calendar/model/KalendarEvent.java
index 1eec100ad2d..d3a24d52250 100644
--- a/src/main/java/org/olat/commons/calendar/model/KalendarEvent.java
+++ b/src/main/java/org/olat/commons/calendar/model/KalendarEvent.java
@@ -69,6 +69,9 @@ public class KalendarEvent implements Cloneable, Comparable<KalendarEvent> {
 
 	private String recurrenceRule;
 	private String recurrenceExc;
+	
+	private boolean managed;
+	private String externalId;
 
 	public KalendarEvent() {
 		// save no-args constructor for XStream
@@ -165,6 +168,22 @@ public class KalendarEvent implements Cloneable, Comparable<KalendarEvent> {
 		this.subject = subject;
 	}
 
+	public boolean isManaged() {
+		return managed;
+	}
+
+	public void setManaged(boolean managed) {
+		this.managed = managed;
+	}
+
+	public String getExternalId() {
+		return externalId;
+	}
+
+	public void setExternalId(String externalId) {
+		this.externalId = externalId;
+	}
+
 	public int getClassification() {
 		return classification;
 	}
diff --git a/src/main/java/org/olat/commons/calendar/restapi/EventVO.java b/src/main/java/org/olat/commons/calendar/restapi/EventVO.java
index 888417458f5..ec9b5433ae9 100644
--- a/src/main/java/org/olat/commons/calendar/restapi/EventVO.java
+++ b/src/main/java/org/olat/commons/calendar/restapi/EventVO.java
@@ -41,6 +41,9 @@ public class EventVO {
 	private Date end;
 	private boolean allDayEvent;
 	
+	private boolean managed;
+	private String externalId;
+	
 	public EventVO() {
 		//
 	}
@@ -54,6 +57,8 @@ public class EventVO {
 		end = event.getEnd();
 		allDayEvent = event.isAllDayEvent();
 		calendarId = event.getCalendar().getType() + "_" + event.getCalendar().getCalendarID();
+		managed = event.isManaged();
+		externalId = event.getExternalId();
 	}
 
 	public String getId() {
@@ -119,4 +124,20 @@ public class EventVO {
 	public void setCalendarId(String calendarId) {
 		this.calendarId = calendarId;
 	}
+
+	public boolean isManaged() {
+		return managed;
+	}
+
+	public void setManaged(boolean managed) {
+		this.managed = managed;
+	}
+
+	public String getExternalId() {
+		return externalId;
+	}
+
+	public void setExternalId(String externalId) {
+		this.externalId = externalId;
+	}
 }
diff --git a/src/main/java/org/olat/commons/calendar/ui/CalendarDetailsController.java b/src/main/java/org/olat/commons/calendar/ui/CalendarDetailsController.java
index 040b4aec506..221ae2433e7 100644
--- a/src/main/java/org/olat/commons/calendar/ui/CalendarDetailsController.java
+++ b/src/main/java/org/olat/commons/calendar/ui/CalendarDetailsController.java
@@ -28,6 +28,7 @@ import java.util.Locale;
 import org.apache.commons.lang.StringEscapeUtils;
 import org.apache.commons.lang.time.DateUtils;
 import org.olat.commons.calendar.CalendarManager;
+import org.olat.commons.calendar.CalendarModule;
 import org.olat.commons.calendar.CalendarUtils;
 import org.olat.commons.calendar.model.KalendarEvent;
 import org.olat.commons.calendar.model.KalendarEventLink;
@@ -45,6 +46,7 @@ import org.olat.core.gui.util.CSSHelper;
 import org.olat.core.helpers.Settings;
 import org.olat.core.util.StringHelper;
 import org.olat.core.util.Util;
+import org.springframework.beans.factory.annotation.Autowired;
 
 /**
  * 
@@ -58,19 +60,22 @@ public class CalendarDetailsController extends BasicController {
 	private final KalendarRenderWrapper calWrapper;
 	
 	private Link editButton;
-	private final VelocityContainer mainVC;
 	
 	private final boolean isGuestOnly;
 	
+	@Autowired
+	private CalendarModule calendarModule;
+	
 	public CalendarDetailsController(UserRequest ureq, WindowControl wControl,
 			KalendarEvent event, KalendarRenderWrapper calWrapper) {
 		super(ureq, wControl, Util.createPackageTranslator(CalendarManager.class, ureq.getLocale()));
 		this.calEvent = event;
 		this.calWrapper = calWrapper;
 		isGuestOnly = ureq.getUserSession().getRoles().isGuestOnly();
-		mainVC = createVelocityContainer("event_details");
+		VelocityContainer mainVC = createVelocityContainer("event_details");
 		
-		if(!isGuestOnly) {
+		if(!isGuestOnly &&
+				!(calendarModule.isManagedCalendars() && event.isManaged())) {
 			editButton = LinkFactory.createButton("edit", mainVC, this);
 			mainVC.put("edit", editButton);
 		}
diff --git a/src/main/java/org/olat/commons/calendar/ui/WeeklyCalendarController.java b/src/main/java/org/olat/commons/calendar/ui/WeeklyCalendarController.java
index c1928865222..bd0e77fdedc 100644
--- a/src/main/java/org/olat/commons/calendar/ui/WeeklyCalendarController.java
+++ b/src/main/java/org/olat/commons/calendar/ui/WeeklyCalendarController.java
@@ -342,6 +342,7 @@ public class WeeklyCalendarController extends FormBasicController implements Act
 		super.formInnerEvent(ureq, source, event);
 	}
 
+	@Override
 	public void event(UserRequest ureq, Component source, Event event) {
 		if (event == ComponentUtil.VALIDATE_EVENT && dirty) {
 			dirty = false;
@@ -353,6 +354,7 @@ public class WeeklyCalendarController extends FormBasicController implements Act
 		super.event(ureq, source, event);
 	}
 
+	@Override
 	public void event(UserRequest ureq, Controller source, Event event) {
 		Kalendar affectedCal = null;
 		if (dirty) {
diff --git a/src/main/java/org/olat/commons/calendar/ui/components/FullCalendarComponentRenderer.java b/src/main/java/org/olat/commons/calendar/ui/components/FullCalendarComponentRenderer.java
index fad92b10423..27c96938754 100644
--- a/src/main/java/org/olat/commons/calendar/ui/components/FullCalendarComponentRenderer.java
+++ b/src/main/java/org/olat/commons/calendar/ui/components/FullCalendarComponentRenderer.java
@@ -25,12 +25,11 @@ import java.text.DateFormat;
 import java.util.Calendar;
 
 import org.olat.core.gui.components.Component;
-import org.olat.core.gui.components.ComponentRenderer;
+import org.olat.core.gui.components.DefaultComponentRenderer;
 import org.olat.core.gui.components.form.flexible.impl.Form;
 import org.olat.core.gui.components.form.flexible.impl.FormJSHelper;
 import org.olat.core.gui.render.RenderResult;
 import org.olat.core.gui.render.Renderer;
-import org.olat.core.gui.render.RenderingState;
 import org.olat.core.gui.render.StringOutput;
 import org.olat.core.gui.render.URLBuilder;
 import org.olat.core.gui.translator.Translator;
@@ -42,7 +41,7 @@ import org.olat.core.util.StringHelper;
  * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
  *
  */
-public class FullCalendarComponentRenderer implements ComponentRenderer {
+public class FullCalendarComponentRenderer extends DefaultComponentRenderer {
 
 	@Override
 	public void render(Renderer renderer, StringOutput sb, Component source, URLBuilder ubu, Translator translator,
@@ -224,15 +223,4 @@ public class FullCalendarComponentRenderer implements ComponentRenderer {
       .append(escapeJavaScript(translator.translate("month.short.dec"))).append("']");
 		return sb.toString();
 	}
-
-	@Override
-	public void renderHeaderIncludes(Renderer renderer, StringOutput sb, Component source, URLBuilder ubu, Translator translator,
-			RenderingState rstate) {
-		//
-	}
-
-	@Override
-	public void renderBodyOnLoadJSFunctionCall(Renderer renderer, StringOutput sb, Component source, RenderingState rstate) {
-		//
-	}
 }
\ No newline at end of file
diff --git a/src/main/resources/serviceconfig/olat.properties b/src/main/resources/serviceconfig/olat.properties
index 3827de71edd..4edf019c67b 100644
--- a/src/main/resources/serviceconfig/olat.properties
+++ b/src/main/resources/serviceconfig/olat.properties
@@ -606,6 +606,9 @@ calendar.course.tool.enabled.values=true,false
 # Enable the calendar course element in course (if calendar is enabled)
 calendar.course.element.enabled=true
 calendar.course.element.enabled.values=true,false
+# Enable managed calendars
+calendar.managed=false
+calendar.managed.values=true,false
 
 ########################################################################
 # Social sharing options
-- 
GitLab