From 289e869e0eb1b4708f6cc8b1beb253b26d17ca24 Mon Sep 17 00:00:00 2001
From: srosse <stephane.rosse@frentix.com>
Date: Wed, 26 Jun 2019 15:52:47 +0200
Subject: [PATCH] OO-4092: reset calendar, deleted imported calendars

---
 .../commons/calendar/CalendarManager.java     |   2 +
 .../calendar/_i18n/LocalStrings_de.properties |  13 ++
 .../calendar/_i18n/LocalStrings_en.properties |  13 ++
 .../calendar/_i18n/LocalStrings_fr.properties |   1 +
 .../manager/ICalFileCalendarManager.java      |  37 +++--
 .../manager/ImportToCalendarManager.java      |  43 +++++-
 .../calendar/restapi/CalendarWSHelper.java    |  14 +-
 ...lendarPersonalConfigurationController.java |  68 +++++++++
 .../calendar/ui/CalendarToolsController.java  |  41 +++++-
 .../ui/ConfirmCalendarResetController.java    | 101 +++++++++++++
 ...irmDeleteImportedToCalendarController.java | 134 ++++++++++++++++++
 .../calendar/ui/WeeklyCalendarController.java |   3 +-
 .../ui/_content/confirm_delete_import_to.html |   4 +
 .../calendar/ui/_content/confirm_reset.html   |   4 +
 .../commons/calendar/ui/_content/tools.html   |   6 +
 .../calendar/ui/events/CalendarGUIEvent.java  |   2 +
 16 files changed, 451 insertions(+), 35 deletions(-)
 create mode 100644 src/main/java/org/olat/commons/calendar/ui/ConfirmCalendarResetController.java
 create mode 100644 src/main/java/org/olat/commons/calendar/ui/ConfirmDeleteImportedToCalendarController.java
 create mode 100644 src/main/java/org/olat/commons/calendar/ui/_content/confirm_delete_import_to.html
 create mode 100644 src/main/java/org/olat/commons/calendar/ui/_content/confirm_reset.html

diff --git a/src/main/java/org/olat/commons/calendar/CalendarManager.java b/src/main/java/org/olat/commons/calendar/CalendarManager.java
index 06b1c7d3122..3ba09530a15 100644
--- a/src/main/java/org/olat/commons/calendar/CalendarManager.java
+++ b/src/main/java/org/olat/commons/calendar/CalendarManager.java
@@ -304,6 +304,8 @@ public interface CalendarManager {
 	 */
 	public boolean removeEventFrom(Kalendar cal, KalendarEvent kalendarEvent);
 	
+	public boolean removeEventsFrom(Kalendar cal, List<KalendarEvent> kalendarEvents);
+	
 	/**
 	 * Remove an occurence of a recurring event.
 	 * 
diff --git a/src/main/java/org/olat/commons/calendar/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/commons/calendar/_i18n/LocalStrings_de.properties
index 321aff1d451..091f73461a1 100644
--- a/src/main/java/org/olat/commons/calendar/_i18n/LocalStrings_de.properties
+++ b/src/main/java/org/olat/commons/calendar/_i18n/LocalStrings_de.properties
@@ -5,6 +5,14 @@ cal.color.choose=Farbe w\u00E4hlen
 cal.color.title=Farbe w\u00E4hlen
 cal.configuration.list=Kalender Liste
 cal.configuration.tooltip=Einstellungen
+cal.confirm=Best\u00E4tigung
+cal.confirm.delete.imported.to.check=Alle Termine werden definitiv gel\u00F6scht und k\u00F6nnen nicht mehr wiederhergestellt werden.
+cal.confirm.delete.imported.to.title=Importierte Kalender in "{0}" l\u00F6schen
+cal.confirm.delete.imported.to.calendars=Kalendar
+cal.confirm.delete.imported.to.confirmation_message=Wollen sie wirklich die unten gew\u00E4hlte importierte Kalender l\u00F6schen?
+cal.confirm.reset.title=Kalender "{0}" zur\u00FCcksetzen
+cal.confirm.reset.confirmation_message=Wollen sie wirklich alle Termine und alle importierte Kalender l\u00F6schen?
+cal.confirm.reset.check=Alle Dateien werden definitiv gel\u00F6scht und k\u00F6nnen nicht mehr wiederhergestellt werden.
 cal.copy.rootnode=Verf\u00FCgbare Kalender
 cal.copy.submit=Termin kopieren
 cal.copy.title=Termin in mehrere Kalender kopieren
@@ -12,6 +20,8 @@ cal.day=Tag
 cal.delete.dialogtext=Wollen Sie diesen Termin wirklich l\u00F6schen?
 cal.delete.dialogtext.sequence=Wollen Sie diese Terminserie wirklich l\u00F6schen?
 cal.delete.imported.calendar=Importierte Kalender l\u00F6schen
+cal.delete.imported.to.calendar=Importierte Kalender l\u00F6schen
+cal.delete.imported.to.info=Gew\u00E4hlte importierte Kalender wurde erfolgreich gel\u00F6scht.
 cal.delete.no=Nein
 cal.delete.yes=Ja
 cal.disable=Eintr\u00E4ge dieses Kalenders verbergen
@@ -123,6 +133,8 @@ cal.notifications.title=
 cal.previousweek=<< Vorherige Woche
 cal.print.desc=W\u00E4hlen Sie Start- und Enddatum.
 cal.print.title=Ereignisse
+cal.reset.calendar=Kalender zur\u00FCcksetzen
+cal.reset.info=Kalender erfolgreich zur\u00FCckgesetzt.
 cal.sat=Samstag
 cal.search.beginPeriod=Von (Datum)
 cal.search.button=Terminsuche
@@ -175,6 +187,7 @@ delete.future=Alle zuk\u00FCnftige Termine l\u00F6schen
 delete.all=Alle Termine l\u00F6schen
 delete.one=Nur die Okkurenz l\u00F6schen
 error.goto.date=Falsche Datumseingabe (dd.mm.yyyy)
+error.atleast.one=Mindestens ein Kalender ausw\u00e4hlen
 menu.admin.calendar=Kalender
 menu.admin.calendar.alt=Kalender
 month.long.apr=$org.olat.core.gui.components.form.flexible.impl.elements\:month.long.apr
diff --git a/src/main/java/org/olat/commons/calendar/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/commons/calendar/_i18n/LocalStrings_en.properties
index d546dbb6c4e..d4464613a69 100644
--- a/src/main/java/org/olat/commons/calendar/_i18n/LocalStrings_en.properties
+++ b/src/main/java/org/olat/commons/calendar/_i18n/LocalStrings_en.properties
@@ -5,6 +5,14 @@ cal.color.choose=Choose color
 cal.color.title=Choose color
 cal.configuration.list=Calendar list
 cal.configuration.tooltip=Settings
+cal.confirm=Confirmation
+cal.confirm.delete.imported.to.check=All data will be permanently deleted and cannot be recovered.
+cal.confirm.delete.imported.to.title=Delete imported calendar(s) in "{0}"
+cal.confirm.delete.imported.to.calendars=Calendar
+cal.confirm.delete.imported.to.confirmation_message=Do you really want to delete all imported calendars which you selected above?
+cal.confirm.reset.title=Reset calendar "{0}"
+cal.confirm.reset.confirmation_message=Do you really want to delete all events and all imported calendars?
+cal.confirm.reset.check=All data will be permanently deleted and cannot be recovered.
 cal.copy.rootnode=Calendars available
 cal.copy.submit=Copy event
 cal.copy.title=Copy event to more than one calendar
@@ -12,6 +20,8 @@ cal.day=Day
 cal.delete.dialogtext=Do you really want to delete this event?
 cal.delete.dialogtext.sequence=Do you really want to delete this series of events?
 cal.delete.imported.calendar=Delete imported calendar
+cal.delete.imported.to.calendar=Delete imported calendars
+cal.delete.imported.to.info=The selected imported calendars was successfully deleted.
 cal.delete.no=No
 cal.delete.yes=Yes
 cal.disable=Hide this calendar's entries
@@ -123,6 +133,8 @@ cal.notifications.title=
 cal.previousweek=<< Previous week
 cal.print.title=Events
 cal.print.desc=Select a start and end date
+cal.reset.calendar=Reset calendar
+cal.reset.info=Calendar successfully reseted.
 cal.sat=Saturday
 cal.search.beginPeriod=From (date)
 cal.search.button=Search events
@@ -175,6 +187,7 @@ delete.all=Delete all events
 delete.future=Delete all future events
 delete.one=Delete only this occurence
 error.goto.date=Wrong date format (dd.mm.yyyy)
+error.atleast.one=Choose at least one calendar
 menu.admin.calendar=Calendar
 menu.admin.calendar.alt=Calendar
 month.long.apr=$org.olat.core.gui.components.form.flexible.impl.elements\:month.long.apr
diff --git a/src/main/java/org/olat/commons/calendar/_i18n/LocalStrings_fr.properties b/src/main/java/org/olat/commons/calendar/_i18n/LocalStrings_fr.properties
index 9bb844915e7..b86ab8eb6e2 100644
--- a/src/main/java/org/olat/commons/calendar/_i18n/LocalStrings_fr.properties
+++ b/src/main/java/org/olat/commons/calendar/_i18n/LocalStrings_fr.properties
@@ -5,6 +5,7 @@ cal.color.choose=Choisir la couleur
 cal.color.title=Choisir la couleur
 cal.configuration.list=Liste des calendriers
 cal.configuration.tooltip=Pr\u00E9f\u00E9rences
+cal.confirm.reset.check=Toutes les donn\u00E9es seront d\u00E9finitivement effac\u00E9es et ne pourront pas \u00EAtre r\u00E9cup\u00E9r\u00E9es.
 cal.copy.rootnode=Calendriers disponibles
 cal.copy.submit=Copier rendez-vous 
 cal.copy.title=Copier le rendez-vous dans plusieurs calendriers
diff --git a/src/main/java/org/olat/commons/calendar/manager/ICalFileCalendarManager.java b/src/main/java/org/olat/commons/calendar/manager/ICalFileCalendarManager.java
index 562ada3c111..ba2f8e27e32 100644
--- a/src/main/java/org/olat/commons/calendar/manager/ICalFileCalendarManager.java
+++ b/src/main/java/org/olat/commons/calendar/manager/ICalFileCalendarManager.java
@@ -1012,25 +1012,27 @@ public class ICalFileCalendarManager implements CalendarManager, InitializingBea
 		CoordinatorManager.getInstance().getCoordinator().getEventBus().fireEventToListenersOf(new CalendarGUIModifiedEvent(cal), OresHelper.lookupType(CalendarManager.class));
 		return persistSuccessful.booleanValue();
 	}
-
+	
 	@Override
-	public boolean removeEventFrom(final Kalendar cal, final KalendarEvent kalendarEvent) {
+	public boolean removeEventsFrom(final Kalendar cal, final List<KalendarEvent> kalendarEvents) {
 		OLATResourceable calOres = getOresHelperFor(cal);
 		Boolean removeSuccessful = CoordinatorManager.getInstance().getCoordinator().getSyncer().doInSync( calOres, () -> {
-			String uid = kalendarEvent.getID();
-			String recurrenceId = kalendarEvent.getRecurrenceID();
 			Kalendar loadedCal = getCalendarFromCache(cal.getType(), cal.getCalendarID());
-			if(StringHelper.containsNonWhitespace(recurrenceId)) {
-				loadedCal.removeEvent(kalendarEvent);
-				KalendarEvent rootEvent = loadedCal.getEvent(kalendarEvent.getID(), null);
-				if(rootEvent != null && kalendarEvent instanceof KalendarRecurEvent) {
-					Date recurrenceDate = ((KalendarRecurEvent)kalendarEvent).getOccurenceDate();
-					rootEvent.addRecurrenceExc(recurrenceDate);
-				}
-			} else {
-				for(KalendarEvent kEvent:loadedCal.getEvents()) {
-					if(uid.equals(kEvent.getID())) {
-						loadedCal.removeEvent(kEvent);
+			for(KalendarEvent kalendarEvent:kalendarEvents) {
+				String uid = kalendarEvent.getID();
+				String recurrenceId = kalendarEvent.getRecurrenceID();
+				if(StringHelper.containsNonWhitespace(recurrenceId)) {
+					loadedCal.removeEvent(kalendarEvent);
+					KalendarEvent rootEvent = loadedCal.getEvent(kalendarEvent.getID(), null);
+					if(rootEvent != null && kalendarEvent instanceof KalendarRecurEvent) {
+						Date recurrenceDate = ((KalendarRecurEvent)kalendarEvent).getOccurenceDate();
+						rootEvent.addRecurrenceExc(recurrenceDate);
+					}
+				} else {
+					for(KalendarEvent kEvent:loadedCal.getEvents()) {
+						if(uid.equals(kEvent.getID())) {
+							loadedCal.removeEvent(kEvent);
+						}
 					}
 				}
 			}
@@ -1041,6 +1043,11 @@ public class ICalFileCalendarManager implements CalendarManager, InitializingBea
 		CoordinatorManager.getInstance().getCoordinator().getEventBus().fireEventToListenersOf(new CalendarGUIModifiedEvent(cal), OresHelper.lookupType(CalendarManager.class));
 		return removeSuccessful.booleanValue();
     }
+
+	@Override
+	public boolean removeEventFrom(final Kalendar cal, final KalendarEvent kalendarEvent) {
+		return removeEventsFrom(cal, Collections.singletonList(kalendarEvent));
+    }
 	
 	@Override
 	public boolean removeOccurenceOfEvent(final Kalendar cal, final KalendarRecurEvent kalendarEvent) {
diff --git a/src/main/java/org/olat/commons/calendar/manager/ImportToCalendarManager.java b/src/main/java/org/olat/commons/calendar/manager/ImportToCalendarManager.java
index 1e28477b2d8..252b4f199d8 100644
--- a/src/main/java/org/olat/commons/calendar/manager/ImportToCalendarManager.java
+++ b/src/main/java/org/olat/commons/calendar/manager/ImportToCalendarManager.java
@@ -30,17 +30,21 @@ import java.io.InputStream;
 import java.net.URL;
 import java.util.Date;
 import java.util.List;
+import java.util.Set;
+import java.util.UUID;
 import java.util.concurrent.atomic.AtomicInteger;
+import java.util.stream.Collectors;
 
+import org.apache.logging.log4j.Logger;
 import org.olat.basesecurity.BaseSecurity;
 import org.olat.commons.calendar.CalendarManager;
 import org.olat.commons.calendar.model.ImportedToCalendar;
 import org.olat.commons.calendar.model.Kalendar;
+import org.olat.commons.calendar.model.KalendarEvent;
 import org.olat.commons.calendar.ui.components.KalendarRenderWrapper;
 import org.olat.core.commons.persistence.DBFactory;
 import org.olat.core.id.Identity;
 import org.olat.core.id.OLATResourceable;
-import org.apache.logging.log4j.Logger;
 import org.olat.core.logging.Tracing;
 import org.olat.group.BusinessGroup;
 import org.olat.group.manager.BusinessGroupDAO;
@@ -121,7 +125,36 @@ public class ImportToCalendarManager {
 		}
 		return false;
 	}
+	public void deleteImportedCalendarsAndEvents(Kalendar cal) {
+		List<ImportedToCalendar> importedToCalendars = importedToCalendarDao
+				.getImportedToCalendars(cal.getCalendarID(), cal.getType());
+		for(ImportedToCalendar importedToCalendar:importedToCalendars) {
+			deleteImportedCalendarsAndEvents(importedToCalendar);	
+		}
+	}
 	
+	public void deleteImportedCalendarsAndEvents(ImportedToCalendar importedToCalendar) {
+		String type = importedToCalendar.getToType();
+		String id = importedToCalendar.getToCalendarId();
+		String importUrl = importedToCalendar.getUrl();
+		
+		try(InputStream in = new URL(importUrl).openStream()) {
+			Kalendar importedKalendar = calendarManager.buildKalendarFrom(in, "TEMP", UUID.randomUUID().toString());
+			List<KalendarEvent> importedEvents = importedKalendar.getEvents();
+			Set<String>  importedEventsIds = importedEvents.stream().map(KalendarEvent::getID).collect(Collectors.toSet());
+			if(!importedEventsIds.isEmpty()) {
+				Kalendar cal = calendarManager.getCalendar(type, id);
+				List<KalendarEvent> allEvents = cal.getEvents();
+				List<KalendarEvent> importedEventsToDelete = allEvents.stream()
+					.filter(e -> importedEventsIds.contains(e.getID()))
+					.collect(Collectors.toList());
+				calendarManager.removeEventsFrom(cal, importedEventsToDelete);
+			}
+		} catch(Exception e) {
+			log.error("", e);
+		}
+		importedToCalendarDao.delete(importedToCalendar);
+	}
 	
 	private boolean check(ImportedToCalendar importedToCalendar) {
 		String id = importedToCalendar.getToCalendarId();
@@ -131,12 +164,12 @@ public class ImportToCalendarManager {
 			return identity != null && identity.getStatus() != null && identity.getStatus().intValue() < Identity.STATUS_DELETED;
 		}
 		if(CalendarManager.TYPE_COURSE.equals(type)) {
-			Long resourceId = new Long(id);
+			Long resourceId = Long.valueOf(id);
 			RepositoryEntry entry = repositoryEntryDao.loadByResourceId("CourseModule", resourceId);
 			return entry != null;
 		}
 		if(CalendarManager.TYPE_GROUP.equals(type)) {
-			Long resourceId = new Long(id);
+			Long resourceId = Long.valueOf(id);
 			BusinessGroup group = businessGroupDao.loadByResourceId(resourceId);
 			return group != null;
 		}
@@ -189,6 +222,10 @@ public class ImportToCalendarManager {
 		}
 	}
 	
+	public List<ImportedToCalendar> getImportedCalendarsIn(Kalendar cal) {
+		return importedToCalendarDao.getImportedToCalendars(cal.getCalendarID(), cal.getType());
+	}
+	
 	public void deletePersonalImportedCalendars(Identity identity) {
 		deleteImportedCalendars(CalendarManager.TYPE_USER, identity.getName());
 	}
diff --git a/src/main/java/org/olat/commons/calendar/restapi/CalendarWSHelper.java b/src/main/java/org/olat/commons/calendar/restapi/CalendarWSHelper.java
index 1eca4069e6c..d38923e85e9 100644
--- a/src/main/java/org/olat/commons/calendar/restapi/CalendarWSHelper.java
+++ b/src/main/java/org/olat/commons/calendar/restapi/CalendarWSHelper.java
@@ -57,20 +57,12 @@ public class CalendarWSHelper {
 	}
 	
 	static boolean hasReadAccess(KalendarRenderWrapper wrapper) {
-		if(wrapper.getAccess() == KalendarRenderWrapper.ACCESS_READ_ONLY) {
-			return true;
-		}
-		if(wrapper.getAccess() == KalendarRenderWrapper.ACCESS_READ_WRITE) {
-			return true;
-		}
-		return false;
+		return wrapper.getAccess() == KalendarRenderWrapper.ACCESS_READ_ONLY
+				|| wrapper.getAccess() == KalendarRenderWrapper.ACCESS_READ_WRITE;
 	}
 	
 	protected static boolean hasWriteAccess(KalendarRenderWrapper wrapper) {
-		if(wrapper.getAccess() == KalendarRenderWrapper.ACCESS_READ_WRITE) {
-			return true;
-		}
-		return false;
+		return wrapper.getAccess() == KalendarRenderWrapper.ACCESS_READ_WRITE;
 	}
 	
 	protected static Response processEvents(List<EventVO> events, Boolean onlyFuture, int firstResult, int maxReturns,
diff --git a/src/main/java/org/olat/commons/calendar/ui/CalendarPersonalConfigurationController.java b/src/main/java/org/olat/commons/calendar/ui/CalendarPersonalConfigurationController.java
index dca744ab459..fa82c3fb15b 100644
--- a/src/main/java/org/olat/commons/calendar/ui/CalendarPersonalConfigurationController.java
+++ b/src/main/java/org/olat/commons/calendar/ui/CalendarPersonalConfigurationController.java
@@ -21,11 +21,15 @@ package org.olat.commons.calendar.ui;
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.stream.Collectors;
 
 import org.apache.commons.lang.RandomStringUtils;
 import org.olat.commons.calendar.CalendarManager;
 import org.olat.commons.calendar.manager.ImportCalendarManager;
+import org.olat.commons.calendar.manager.ImportToCalendarManager;
+import org.olat.commons.calendar.model.ImportedToCalendar;
 import org.olat.commons.calendar.model.Kalendar;
+import org.olat.commons.calendar.model.KalendarEvent;
 import org.olat.commons.calendar.ui.CalendarPersonalConfigurationDataModel.ConfigCols;
 import org.olat.commons.calendar.ui.components.KalendarRenderWrapper;
 import org.olat.commons.calendar.ui.events.CalendarGUIEvent;
@@ -80,6 +84,8 @@ public class CalendarPersonalConfigurationController extends FormBasicController
 	private InjectCalendarFileController injectCalendarFileCtrl;
 	private SynchronizedCalendarUrlController synchronizedCalendarUrlCtrl;
 	private CalendarColorChooserController colorChooserCtrl;
+	private ConfirmCalendarResetController confirmResetCalendarDialog;
+	private ConfirmDeleteImportedToCalendarController confirmDeleteImportedToCalendarDialog;
 
 	private int counter;
 	private final boolean allowImport;
@@ -90,6 +96,8 @@ public class CalendarPersonalConfigurationController extends FormBasicController
 	private CalendarManager calendarManager;
 	@Autowired
 	private ImportCalendarManager importCalendarManager;
+	@Autowired
+	private ImportToCalendarManager importToCalendarManager;
 
 	public CalendarPersonalConfigurationController(UserRequest ureq, WindowControl wControl,
 			List<KalendarRenderWrapper> calendars, List<KalendarRenderWrapper> alwaysVisibleKalendars, boolean allowImport) {
@@ -209,6 +217,22 @@ public class CalendarPersonalConfigurationController extends FormBasicController
 				showInfo("cal.import.remove.info");
 				fireEvent(ureq, Event.CHANGED_EVENT);
 			}
+		} else if(source == confirmResetCalendarDialog) {
+			if(event == Event.DONE_EVENT) {
+				doResetCalendar(confirmResetCalendarDialog.getCalendarRow());
+				showInfo("cal.reset.info");
+				fireEvent(ureq, Event.CHANGED_EVENT); 
+			}
+			cmc.deactivate();
+			cleanUp();
+		} else if(source == confirmDeleteImportedToCalendarDialog) {
+			if(event == Event.DONE_EVENT) {
+				doDeleteImportedToCalendar(confirmDeleteImportedToCalendarDialog.getSelectedImportedToCalendars());
+				showInfo("cal.delete.imported.to.info");
+				fireEvent(ureq, Event.CHANGED_EVENT); 
+			}
+			cmc.deactivate();
+			cleanUp();
 		} else if(calendarFileUploadCtrl == source) {
 			KalendarRenderWrapper calendar = calendarFileUploadCtrl.getImportedCalendar();
 			cmc.deactivate();
@@ -239,6 +263,10 @@ public class CalendarPersonalConfigurationController extends FormBasicController
 				doConfirmDeleteToken(ureq, row);
 			} else if(CalendarGUIEvent.DELETE_CALENDAR.equals(event.getCommand())) {
 				doConfirmDeleteCalendar(ureq, row);
+			} else if(CalendarGUIEvent.RESET_CALENDAR.equals(event.getCommand())) {
+				doConfirmResetCalendar(ureq, row);
+			} else if(CalendarGUIEvent.DELETE_IMPORTED_TO.equals(event.getCommand())) {
+				doConfirmDeleteImportedToCalendar(ureq, row);
 			}
 
 		} else if(injectCalendarFileCtrl == source || synchronizedCalendarUrlCtrl == source) {
@@ -255,6 +283,7 @@ public class CalendarPersonalConfigurationController extends FormBasicController
 	}
 	
 	private void cleanUp() {
+		removeAsListenerAndDispose(confirmResetCalendarDialog);
 		removeAsListenerAndDispose(calendarFileUploadCtrl);
 		removeAsListenerAndDispose(calendarUrlImportCtrl);
 		removeAsListenerAndDispose(calendarToolsCtrl);
@@ -262,6 +291,7 @@ public class CalendarPersonalConfigurationController extends FormBasicController
 		removeAsListenerAndDispose(calloutCtrl);
 		removeAsListenerAndDispose(feedUrlCtrl);
 		removeAsListenerAndDispose(cmc);
+		confirmResetCalendarDialog = null;
 		calendarFileUploadCtrl = null;
 		calendarUrlImportCtrl = null;
 		calendarToolsCtrl = null;
@@ -389,6 +419,44 @@ public class CalendarPersonalConfigurationController extends FormBasicController
 		tableEl.reloadData();
 		fireEvent(ureq, new CalendarGUIRemoveEvent(row.getWrapper()));
 	}
+	
+	private void doConfirmResetCalendar(UserRequest ureq, CalendarPersonalConfigurationRow row) {
+		confirmResetCalendarDialog = new ConfirmCalendarResetController(ureq, getWindowControl(), row);
+		listenTo(confirmResetCalendarDialog);
+		
+		String title = translate("cal.confirm.reset.title", new String[] { StringHelper.escapeHtml(row.getDisplayName() )});
+		cmc = new CloseableModalController(getWindowControl(), "close", confirmResetCalendarDialog.getInitialComponent(), true, title);
+		cmc.activate();
+		listenTo(cmc);
+	}
+	
+	private void doResetCalendar(CalendarPersonalConfigurationRow row) {
+		Kalendar kalendar = row.getWrapper().getKalendar();
+		importToCalendarManager.deleteImportedCalendarsAndEvents(kalendar);
+		// reload the calendar without the deleted imported calendars
+		kalendar = calendarManager.getCalendar(kalendar.getType(), kalendar.getCalendarID());
+		List<KalendarEvent> events = kalendar.getEvents();
+		// filter managed events
+		List<KalendarEvent> eventsToDelete = events.stream()
+				.filter(e -> !e.isManaged()).collect(Collectors.toList());
+		calendarManager.removeEventsFrom(kalendar, eventsToDelete);
+	}
+	
+	private void doConfirmDeleteImportedToCalendar(UserRequest ureq, CalendarPersonalConfigurationRow row) {
+		confirmDeleteImportedToCalendarDialog = new ConfirmDeleteImportedToCalendarController(ureq, getWindowControl(), row);
+		listenTo(confirmDeleteImportedToCalendarDialog);
+		
+		String title = translate("cal.confirm.delete.imported.to.title", new String[] { StringHelper.escapeHtml(row.getDisplayName() )});
+		cmc = new CloseableModalController(getWindowControl(), "close", confirmDeleteImportedToCalendarDialog.getInitialComponent(), true, title);
+		cmc.activate();
+		listenTo(cmc);
+	}
+	
+	private void doDeleteImportedToCalendar(List<ImportedToCalendar> calendarsToDelete) {
+		for(ImportedToCalendar calendar:calendarsToDelete) {
+			importToCalendarManager.deleteImportedCalendarsAndEvents(calendar);
+		}
+	}
 
 	private void doOpenImportCalendarFile(UserRequest ureq) {
 		calendarFileUploadCtrl = new ImportCalendarFileController(ureq, getWindowControl());
diff --git a/src/main/java/org/olat/commons/calendar/ui/CalendarToolsController.java b/src/main/java/org/olat/commons/calendar/ui/CalendarToolsController.java
index 19d2149b6cc..2fca0ab37b0 100644
--- a/src/main/java/org/olat/commons/calendar/ui/CalendarToolsController.java
+++ b/src/main/java/org/olat/commons/calendar/ui/CalendarToolsController.java
@@ -19,7 +19,12 @@
  */
 package org.olat.commons.calendar.ui;
 
+import java.util.List;
+
 import org.olat.commons.calendar.CalendarManager;
+import org.olat.commons.calendar.manager.ImportToCalendarManager;
+import org.olat.commons.calendar.model.ImportedToCalendar;
+import org.olat.commons.calendar.ui.components.KalendarRenderWrapper;
 import org.olat.commons.calendar.ui.events.CalendarGUIEvent;
 import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.components.Component;
@@ -31,6 +36,7 @@ import org.olat.core.gui.control.WindowControl;
 import org.olat.core.gui.control.controller.BasicController;
 import org.olat.core.util.StringHelper;
 import org.olat.core.util.Util;
+import org.springframework.beans.factory.annotation.Autowired;
 
 /**
  * 
@@ -40,30 +46,51 @@ import org.olat.core.util.Util;
  */
 public class CalendarToolsController extends BasicController {
 	
-	private Link injectFileLink, injectSynchronizedUrlLink, deleteTokenLink, deleteCalendarLink;
+	private Link injectFileLink;
+	private Link deleteTokenLink;
+	private Link resetCalendarLink;
+	private Link deleteCalendarLink;
+	private Link injectSynchronizedUrlLink;
+	private Link deleteImportedToCalendarLink;
 	
 	private final CalendarPersonalConfigurationRow row;
 	
+	@Autowired
+	private ImportToCalendarManager importToCalendarManager;
+	
 	public CalendarToolsController(UserRequest ureq, WindowControl wControl, CalendarPersonalConfigurationRow row) {
 		super(ureq, wControl);
 		this.row = row;
 		setTranslator(Util.createPackageTranslator(CalendarManager.class, getLocale(), getTranslator()));
 		
 		VelocityContainer mainVC = createVelocityContainer("tools");
-		if(row.getAccess() == 0 && !row.isImported()) {
+		if(row.getAccess() == KalendarRenderWrapper.ACCESS_READ_WRITE && !row.isImported()) {
 			injectFileLink = LinkFactory.createLink("cal.import.type.file", mainVC, this);
 			injectFileLink.setIconLeftCSS("o_icon o_icon_import");
 			injectSynchronizedUrlLink = LinkFactory.createLink("cal.synchronize.type.url", mainVC, this);
 			injectSynchronizedUrlLink.setIconLeftCSS("o_icon o_icon_calendar_sync");
+			
+			List<ImportedToCalendar> importedToCalendars = importToCalendarManager
+					.getImportedCalendarsIn(row.getWrapper().getKalendar());
+			if(!importedToCalendars.isEmpty()) {
+				deleteImportedToCalendarLink = LinkFactory.createLink("cal.delete.imported.to.calendar", mainVC, this);
+				deleteImportedToCalendarLink.setIconLeftCSS("o_icon o_icon_delete_item");
+			}
 		}
 		
 		if(StringHelper.containsNonWhitespace(row.getToken())) {
 			deleteTokenLink = LinkFactory.createLink("cal.icalfeed.subscribe.remove", mainVC, this);
 			deleteTokenLink.setIconLeftCSS("o_icon o_icon_delete");
 		}
-		if(row.isImported()) {
-			deleteCalendarLink = LinkFactory.createLink("cal.delete.imported.calendar", mainVC, this);
-			deleteCalendarLink.setIconLeftCSS("o_icon o_icon_remove");
+		
+		if(row.getAccess() == KalendarRenderWrapper.ACCESS_READ_WRITE) {
+			if(row.isImported()) {
+				deleteCalendarLink = LinkFactory.createLink("cal.delete.imported.calendar", mainVC, this);
+				deleteCalendarLink.setIconLeftCSS("o_icon o_icon_delete_item");
+			} else {
+				resetCalendarLink = LinkFactory.createLink("cal.reset.calendar", mainVC, this);
+				resetCalendarLink.setIconLeftCSS("o_icon o_icon_delete_item");
+			}
 		}
 		
 		putInitialPanel(mainVC);
@@ -83,6 +110,10 @@ public class CalendarToolsController extends BasicController {
 			fireEvent(ureq, new CalendarGUIEvent(CalendarGUIEvent.DELETE_TOKEN));
 		} else if(deleteCalendarLink == source) {
 			fireEvent(ureq, new CalendarGUIEvent(CalendarGUIEvent.DELETE_CALENDAR));
+		} else if(resetCalendarLink == source) {
+			fireEvent(ureq, new CalendarGUIEvent(CalendarGUIEvent.RESET_CALENDAR));
+		} else if(deleteImportedToCalendarLink == source) {
+			fireEvent(ureq, new CalendarGUIEvent(CalendarGUIEvent.DELETE_IMPORTED_TO));
 		}
 	}
 
diff --git a/src/main/java/org/olat/commons/calendar/ui/ConfirmCalendarResetController.java b/src/main/java/org/olat/commons/calendar/ui/ConfirmCalendarResetController.java
new file mode 100644
index 00000000000..762e4c0baa5
--- /dev/null
+++ b/src/main/java/org/olat/commons/calendar/ui/ConfirmCalendarResetController.java
@@ -0,0 +1,101 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.commons.calendar.ui;
+
+import org.olat.commons.calendar.CalendarManager;
+import org.olat.core.gui.UserRequest;
+import org.olat.core.gui.components.form.flexible.FormItemContainer;
+import org.olat.core.gui.components.form.flexible.elements.MultipleSelectionElement;
+import org.olat.core.gui.components.form.flexible.impl.FormBasicController;
+import org.olat.core.gui.components.form.flexible.impl.FormLayoutContainer;
+import org.olat.core.gui.control.Controller;
+import org.olat.core.gui.control.Event;
+import org.olat.core.gui.control.WindowControl;
+import org.olat.core.util.Util;
+
+/**
+ * 
+ * Initial date: 25 juin 2019<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class ConfirmCalendarResetController extends FormBasicController {
+	
+	private static final String[] confirmKeys = new String[] { "confirm" };
+	
+	private MultipleSelectionElement confirmEl;
+
+	private final CalendarPersonalConfigurationRow calendarRow;
+	
+	public ConfirmCalendarResetController(UserRequest ureq, WindowControl wControl, CalendarPersonalConfigurationRow calendarRow) {
+		super(ureq, wControl, "confirm_reset");
+		this.calendarRow = calendarRow;
+		setTranslator(Util.createPackageTranslator(CalendarManager.class, getLocale(), getTranslator()));
+		
+		initForm(ureq);
+	}
+	
+	public CalendarPersonalConfigurationRow getCalendarRow() {
+		return calendarRow;
+	}
+
+	@Override
+	protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
+		FormLayoutContainer layoutCont = FormLayoutContainer.createDefaultFormLayout("confirm", getTranslator());
+		formLayout.add("confirm", layoutCont);
+		layoutCont.setRootForm(mainForm);
+		
+		String confirmValue = translate("cal.confirm.reset.check");
+		confirmEl = uifactory.addCheckboxesHorizontal("confirm", "cal.confirm", layoutCont, confirmKeys, new String[] { confirmValue });
+		
+		FormLayoutContainer buttonsCont = FormLayoutContainer.createButtonLayout("buttons", getTranslator());
+		layoutCont.add(buttonsCont);
+		uifactory.addFormCancelButton("cancel", buttonsCont, ureq, getWindowControl());
+		uifactory.addFormSubmitButton("cal.reset.calendar", buttonsCont);
+	}
+
+	@Override
+	protected void doDispose() {
+		//
+	}
+
+	@Override
+	protected boolean validateFormLogic(UserRequest ureq) {
+		boolean allOk = super.validateFormLogic(ureq);
+		
+		confirmEl.clearError();
+		if(!confirmEl.isAtLeastSelected(1)) {
+			confirmEl.setErrorKey("form.legende.mandatory", null);
+			allOk &= false;
+		}
+		
+		return allOk;
+	}
+
+	@Override
+	protected void formOK(UserRequest ureq) {
+		fireEvent(ureq, Event.DONE_EVENT);
+	}
+
+	@Override
+	protected void formCancelled(UserRequest ureq) {
+		fireEvent(ureq, Event.CANCELLED_EVENT);
+	}
+}
diff --git a/src/main/java/org/olat/commons/calendar/ui/ConfirmDeleteImportedToCalendarController.java b/src/main/java/org/olat/commons/calendar/ui/ConfirmDeleteImportedToCalendarController.java
new file mode 100644
index 00000000000..d44f166d661
--- /dev/null
+++ b/src/main/java/org/olat/commons/calendar/ui/ConfirmDeleteImportedToCalendarController.java
@@ -0,0 +1,134 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.commons.calendar.ui;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import org.olat.commons.calendar.CalendarManager;
+import org.olat.commons.calendar.manager.ImportToCalendarManager;
+import org.olat.commons.calendar.model.ImportedToCalendar;
+import org.olat.core.gui.UserRequest;
+import org.olat.core.gui.components.form.flexible.FormItemContainer;
+import org.olat.core.gui.components.form.flexible.elements.MultipleSelectionElement;
+import org.olat.core.gui.components.form.flexible.impl.FormBasicController;
+import org.olat.core.gui.components.form.flexible.impl.FormLayoutContainer;
+import org.olat.core.gui.components.util.KeyValues;
+import org.olat.core.gui.control.Controller;
+import org.olat.core.gui.control.Event;
+import org.olat.core.gui.control.WindowControl;
+import org.olat.core.util.Util;
+import org.springframework.beans.factory.annotation.Autowired;
+
+/**
+ * 
+ * Initial date: 25 juin 2019<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class ConfirmDeleteImportedToCalendarController extends FormBasicController {
+	
+	private static final String[] confirmKeys = new String[] { "confirm" };
+
+	private MultipleSelectionElement confirmEl;
+	private MultipleSelectionElement calendarEl;
+
+	private final List<ImportedToCalendar> importedCalendars;
+	private final CalendarPersonalConfigurationRow calendarRow;
+	
+	@Autowired
+	private ImportToCalendarManager importToCalendarManager;
+	
+	public ConfirmDeleteImportedToCalendarController(UserRequest ureq, WindowControl wControl, CalendarPersonalConfigurationRow calendarRow) {
+		super(ureq, wControl, "confirm_delete_import_to");
+		setTranslator(Util.createPackageTranslator(CalendarManager.class, getLocale(), getTranslator()));
+		this.calendarRow = calendarRow;
+		importedCalendars = importToCalendarManager.getImportedCalendarsIn(calendarRow.getWrapper().getKalendar());
+		initForm(ureq);
+	}
+	
+	public CalendarPersonalConfigurationRow getCalendarRow() {
+		return calendarRow;
+	}
+	
+	public List<ImportedToCalendar> getSelectedImportedToCalendars() {
+		Collection<String> selectedKeys = calendarEl.getSelectedKeys();
+		return importedCalendars.stream()
+				.filter(cal -> selectedKeys.contains(cal.getKey().toString()))
+				.collect(Collectors.toList());
+	}
+
+	@Override
+	protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
+		FormLayoutContainer layoutCont = FormLayoutContainer.createDefaultFormLayout("confirm", getTranslator());
+		formLayout.add("confirm", layoutCont);
+		layoutCont.setRootForm(mainForm);
+		
+		KeyValues calendarKeyValues = new KeyValues();
+		for(ImportedToCalendar importedCalendar:importedCalendars) {
+			calendarKeyValues.add(KeyValues.entry(importedCalendar.getKey().toString(), importedCalendar.getUrl()));
+		}
+		calendarEl = uifactory.addCheckboxesVertical("calendars", "cal.confirm.delete.imported.to.calendars", layoutCont,
+				calendarKeyValues.keys(), calendarKeyValues.values(), 1);
+		
+		String confirmValue = translate("cal.confirm.delete.imported.to.check");
+		confirmEl = uifactory.addCheckboxesHorizontal("confirm", "cal.confirm", layoutCont, confirmKeys, new String[] { confirmValue });
+		
+		FormLayoutContainer buttonsCont = FormLayoutContainer.createButtonLayout("buttons", getTranslator());
+		layoutCont.add(buttonsCont);
+		uifactory.addFormCancelButton("cancel", buttonsCont, ureq, getWindowControl());
+		uifactory.addFormSubmitButton("cal.delete.imported.to.calendar", buttonsCont);
+	}
+
+	@Override
+	protected void doDispose() {
+		//
+	}
+
+	@Override
+	protected boolean validateFormLogic(UserRequest ureq) {
+		boolean allOk = super.validateFormLogic(ureq);
+		
+		confirmEl.clearError();
+		if(!confirmEl.isAtLeastSelected(1)) {
+			confirmEl.setErrorKey("form.legende.mandatory", null);
+			allOk &= false;
+		}
+		
+		calendarEl.clearError();
+		if(!calendarEl.isAtLeastSelected(1)) {
+			calendarEl.setErrorKey("error.atleast.one", null);
+			allOk &= false;
+		}
+		
+		return allOk;
+	}
+
+	@Override
+	protected void formOK(UserRequest ureq) {
+		fireEvent(ureq, Event.DONE_EVENT);
+	}
+
+	@Override
+	protected void formCancelled(UserRequest ureq) {
+		fireEvent(ureq, Event.CANCELLED_EVENT);
+	}
+}
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 2dbd6b9dde6..6b30d04764d 100644
--- a/src/main/java/org/olat/commons/calendar/ui/WeeklyCalendarController.java
+++ b/src/main/java/org/olat/commons/calendar/ui/WeeklyCalendarController.java
@@ -118,7 +118,8 @@ public class WeeklyCalendarController extends FormBasicController implements Act
 	 * 3. delete whole sequence
 	 */
 	private DialogBoxController dbcSequence;
-	private DialogBoxController deleteSingleYesNoController, deleteSequenceYesNoController;
+	private DialogBoxController deleteSingleYesNoController;
+	private DialogBoxController deleteSequenceYesNoController;
 	private String modifiedCalendarId;
 	private boolean modifiedCalenderDirty = false;
 	
diff --git a/src/main/java/org/olat/commons/calendar/ui/_content/confirm_delete_import_to.html b/src/main/java/org/olat/commons/calendar/ui/_content/confirm_delete_import_to.html
new file mode 100644
index 00000000000..5c06e33f194
--- /dev/null
+++ b/src/main/java/org/olat/commons/calendar/ui/_content/confirm_delete_import_to.html
@@ -0,0 +1,4 @@
+<div class="o_error">
+	<i class="o_icon o_icon-lg o_icon_important"> </i> $r.translate("cal.confirm.delete.imported.to.confirmation_message")
+</div>
+$r.render("confirm")
\ No newline at end of file
diff --git a/src/main/java/org/olat/commons/calendar/ui/_content/confirm_reset.html b/src/main/java/org/olat/commons/calendar/ui/_content/confirm_reset.html
new file mode 100644
index 00000000000..d18ec69ae68
--- /dev/null
+++ b/src/main/java/org/olat/commons/calendar/ui/_content/confirm_reset.html
@@ -0,0 +1,4 @@
+<div class="o_error">
+	<i class="o_icon o_icon-lg o_icon_important"> </i> $r.translate("cal.confirm.reset.confirmation_message")
+</div>
+$r.render("confirm")
\ No newline at end of file
diff --git a/src/main/java/org/olat/commons/calendar/ui/_content/tools.html b/src/main/java/org/olat/commons/calendar/ui/_content/tools.html
index ea9cd479e89..378654906ef 100644
--- a/src/main/java/org/olat/commons/calendar/ui/_content/tools.html
+++ b/src/main/java/org/olat/commons/calendar/ui/_content/tools.html
@@ -2,6 +2,9 @@
 #if($r.available("cal.import.type.file") && $r.available("cal.import.type.file"))
 	<li>$r.render("cal.import.type.file")</li>
 	<li>$r.render("cal.synchronize.type.url")</li>
+	#if($r.available("cal.delete.imported.to.calendar"))
+	<li>$r.render("cal.delete.imported.to.calendar")</li>
+	#end
 	<li class="divider"></li>
 #end
 #if($r.available("cal.icalfeed.subscribe.remove"))
@@ -10,4 +13,7 @@
 #if($r.available("cal.delete.imported.calendar"))
 	<li>$r.render("cal.delete.imported.calendar")</li>
 #end
+#if($r.available("cal.reset.calendar"))
+	<li>$r.render("cal.reset.calendar")</li>
+#end
 </ul>
\ No newline at end of file
diff --git a/src/main/java/org/olat/commons/calendar/ui/events/CalendarGUIEvent.java b/src/main/java/org/olat/commons/calendar/ui/events/CalendarGUIEvent.java
index 33210ef3adf..e88d338f281 100644
--- a/src/main/java/org/olat/commons/calendar/ui/events/CalendarGUIEvent.java
+++ b/src/main/java/org/olat/commons/calendar/ui/events/CalendarGUIEvent.java
@@ -35,6 +35,8 @@ public class CalendarGUIEvent extends Event {
 	public static final String IMPORT_SYNCHRONIZED_URL = "import-url";
 	public static final String DELETE_TOKEN = "delete-token";
 	public static final String DELETE_CALENDAR = "delete-calendar";
+	public static final String RESET_CALENDAR = "reset-calendar";
+	public static final String DELETE_IMPORTED_TO = "delete-imported-to";
 	
 	public CalendarGUIEvent(String cmd) {
 		super(cmd);
-- 
GitLab