From 0bdf218aa90df3a4df05cace67b1900a75222831 Mon Sep 17 00:00:00 2001
From: srosse <none@none>
Date: Wed, 10 Jan 2018 08:23:30 +0100
Subject: [PATCH] OO-3233: add the course calendar url in the callout

---
 .../collaboration/CollaborationTools.java     | 23 ++++--
 .../commons/calendar/CalendarManager.java     | 10 ++-
 .../olat/commons/calendar/ICalServlet.java    | 10 ++-
 .../calendar/_i18n/LocalStrings_de.properties |  2 +-
 .../calendar/_i18n/LocalStrings_en.properties |  2 +-
 .../calendar/_i18n/LocalStrings_fr.properties |  2 +-
 .../calendar/_i18n/LocalStrings_it.properties |  1 -
 .../_i18n/LocalStrings_pt_BR.properties       |  1 -
 .../manager/ICalFileCalendarManager.java      | 12 +++
 .../ui/CalendarAggregatedURLController.java   | 14 +++-
 .../calendar/ui/WeeklyCalendarController.java | 73 +++++++++++++++----
 .../ui/_content/calAggregatedFeed.html        | 13 +++-
 .../nodes/cal/CourseCalendarController.java   |  4 +-
 .../calendar/CourseCalendarController.java    |  6 +-
 .../ui/homepage/GroupInfoMainController.java  |  3 +-
 .../org/olat/home/HomeCalendarController.java |  2 +-
 .../org/olat/user/UserInfoMainController.java |  2 +-
 17 files changed, 133 insertions(+), 47 deletions(-)

diff --git a/src/main/java/org/olat/collaboration/CollaborationTools.java b/src/main/java/org/olat/collaboration/CollaborationTools.java
index 2dff99d23e7..8fa39d569c8 100644
--- a/src/main/java/org/olat/collaboration/CollaborationTools.java
+++ b/src/main/java/org/olat/collaboration/CollaborationTools.java
@@ -261,7 +261,6 @@ public class CollaborationTools implements Serializable {
 	}
 
 	/**
-	 * TODO: rename to getForumController and save instance?
 	 * 
 	 * @param ureq
 	 * @param wControl
@@ -344,8 +343,8 @@ public class CollaborationTools implements Serializable {
 		if(forumProperty != null) {
 			forum = fom.loadForum(forumProperty.getLongValue());
 		} else {
-			//TODO gsync
 			forum = coordinatorManager.getCoordinator().getSyncer().doInSync(ores, new SyncerCallback<Forum>(){
+				@Override
 				public Forum execute() {
 					Forum aforum;
 					Long forumKey;
@@ -449,7 +448,7 @@ public class CollaborationTools implements Serializable {
 		// add linking
 		List<RepositoryEntry> repoEntries = CoreSpringFactory.getImpl(BusinessGroupService.class).findRepositoryEntries(Collections.singleton(businessGroup), 0, -1);
 		
-		List<ICourse> courses = new ArrayList<ICourse>(repoEntries.size());
+		List<ICourse> courses = new ArrayList<>(repoEntries.size());
 		for (RepositoryEntry repoEntry:repoEntries) {
 			if (repoEntry.getOlatResource().getResourceableTypeName().equals(CourseModule.getCourseTypeName())) {
 				ICourse course = CourseFactory.loadCourse(repoEntry);
@@ -461,11 +460,11 @@ public class CollaborationTools implements Serializable {
 			calRenderWrapper.setLinkProvider(clp);
 		}
 
-		List<KalendarRenderWrapper> calendars = new ArrayList<KalendarRenderWrapper>();
+		List<KalendarRenderWrapper> calendars = new ArrayList<>();
 		calendars.add(calRenderWrapper);
 		
 		return new WeeklyCalendarController(ureq, wControl, calendars,
-				WeeklyCalendarController.CALLER_COLLAB, false);
+				WeeklyCalendarController.CALLER_COLLAB, businessGroup, false);
 	}
 
 	/**
@@ -535,7 +534,6 @@ public class CollaborationTools implements Serializable {
 		if(mapProperty != null) {
 			return createPortfolioController(ureq, wControl, stackPanel, mapProperty);
 		} else {
-			//TODO gsync
 			return coordinatorManager.getCoordinator().getSyncer().doInSync(ores, new SyncerCallback<Controller>() {
 				@Override
 				public Controller execute() {
@@ -744,8 +742,8 @@ public class CollaborationTools implements Serializable {
 		// handle Boolean Values via String Field in Property DB Table
 		final String toolValueStr = toolValue ? TRUE : FALSE;
 		final PropertyManager pm = PropertyManager.getInstance();
-		//TODO gsync
 		coordinatorManager.getCoordinator().getSyncer().doInSync(ores, new SyncerExecutor() {
+			@Override
 			public void execute() {				
 				//was: synchronized (CollaborationTools.class) {
 				Property property = getPropertyOf(selectedTool);
@@ -942,10 +940,12 @@ public class CollaborationTools implements Serializable {
 			}
 		}
 
+		@Override
 		public boolean canRead() {
 			return true;
 		}
 
+		@Override
 		public boolean canWrite() {
 			return write;
 		}
@@ -955,30 +955,37 @@ public class CollaborationTools implements Serializable {
 			return write;
 		}
 
+		@Override
 		public boolean canDelete() {
 			return write;
 		}
 
+		@Override
 		public boolean canList() {
 			return true;
 		}
 
+		@Override
 		public boolean canCopy() {
 			return true;
 		}
-		
+
+		@Override
 		public boolean canDeleteRevisionsPermanently() {
 			return write;
 		}
 
+		@Override
 		public Quota getQuota() {
 			return folderQuota;
 		}
 
+		@Override
 		public void setQuota(Quota quota) {
 			this.folderQuota = quota;
 		}
 
+		@Override
 		public SubscriptionContext getSubscriptionContext() {
 			return subsContext;
 		}
diff --git a/src/main/java/org/olat/commons/calendar/CalendarManager.java b/src/main/java/org/olat/commons/calendar/CalendarManager.java
index 0d12715d850..2650a09cf18 100644
--- a/src/main/java/org/olat/commons/calendar/CalendarManager.java
+++ b/src/main/java/org/olat/commons/calendar/CalendarManager.java
@@ -233,11 +233,19 @@ public interface CalendarManager {
 	
 	public CalendarUserConfiguration saveCalendarConfig(CalendarUserConfiguration configuration);
 	
+	/**
+	 * 
+	 * @param identity The user which want a token
+	 * @return A configuration with a security token
+	 */
 	public CalendarUserConfiguration createAggregatedCalendarConfig(Identity identity);
 	
+	public CalendarUserConfiguration createCalendarConfig(Identity identity, Kalendar calendar);
+	
 	public List<CalendarUserConfiguration> getCalendarUserConfigurationsList(IdentityRef identity, String... types);
 	
-
+	public CalendarUserConfiguration getCalendarUserConfiguration(IdentityRef identity, Kalendar calendar);
+	
 	public CalendarUserConfiguration getCalendarUserConfiguration(Long key);
 
 	/**
diff --git a/src/main/java/org/olat/commons/calendar/ICalServlet.java b/src/main/java/org/olat/commons/calendar/ICalServlet.java
index 860cb4d2497..ad8ee92c983 100644
--- a/src/main/java/org/olat/commons/calendar/ICalServlet.java
+++ b/src/main/java/org/olat/commons/calendar/ICalServlet.java
@@ -214,7 +214,7 @@ public class ICalServlet extends HttpServlet {
 		if(CalendarManager.TYPE_USER_AGGREGATED.equals(calendarType)) {
 			// check the authentication token
 			CalendarUserConfiguration config = calendarManager.getCalendarUserConfiguration(Long.parseLong(userName));
-			String savedToken = config.getToken();
+			String savedToken = config == null ? null : config.getToken();
 			if (authToken == null || savedToken == null || !savedToken.equals(authToken)) {
 				log.warn("Authenticity Check failed for the ical feed path: " + pathInfo);
 				response.sendError(HttpServletResponse.SC_UNAUTHORIZED, requestUrl);
@@ -223,7 +223,13 @@ public class ICalServlet extends HttpServlet {
 			}
 		} else if (calendarManager.calendarExists(calendarType, calendarID)) {
 			// check the authentication token
-			String savedToken = calendarManager.getCalendarToken(calendarType, calendarID, userName);
+			String savedToken = null;
+			if(StringHelper.isLong(userName)) {
+				CalendarUserConfiguration config = calendarManager.getCalendarUserConfiguration(Long.parseLong(userName));
+				savedToken = config == null ? null : config.getToken();
+			} else {
+				savedToken = calendarManager.getCalendarToken(calendarType, calendarID, userName);
+			}
 			if (authToken == null || savedToken == null || !savedToken.equals(authToken)) {
 				log.warn("Authenticity Check failed for the ical feed path: " + pathInfo);
 				response.sendError(HttpServletResponse.SC_UNAUTHORIZED, requestUrl);
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 307bbabc12e..cb7ea9701cc 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
@@ -67,7 +67,7 @@ cal.fri=Freitag
 cal.from=Von
 cal.goto.event=Gehe zu gew\u00E4hltem Termin
 cal.icalfeed.aggregated.info=Bitte benutzen Sie die folgende URL, um diesen Kalender (inklusive aller aggregierten Kalender) von anderen Anwendungen aus aufzurufen. Sie k\u00F6nnen die URL kopieren und in jede andere Kalenderanwendung einf\u00FCgen, welche das iCal-Format unterst\u00FCtzt.
-cal.icalfeed.aggregated.title=Aggregiertes iCal Feed-Link
+cal.icalfeed.aggregated.title=Pers\u00F6nliches aggregiertes iCal Feed-Link
 cal.icalfeed.aggregated.tooltip=$\:cal.icalfeed.aggregated.title
 cal.icalfeed.info=Bitte benutzen Sie die folgende URL, um diesen Kalender von anderen Anwendungen aus aufzurufen. Sie k\u00F6nnen die URL kopieren und in jede andere Kalenderanwendung einf\u00FCgen, welche das iCal-Format unterst\u00FCtzt.
 cal.icalfeed.regenerate.info=iCal Feed-Link wurde neu generiert.
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 e81977c4279..ec0a8664afa 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
@@ -67,7 +67,7 @@ cal.fri=Friday
 cal.from=From
 cal.goto.event=Go to selected event
 cal.icalfeed.aggregated.info=Please use the following URL in order to call this calendar (including all aggregated calendars) from other applications. You can copy and paste the URL into any calendar application supporting the iCal format.
-cal.icalfeed.aggregated.title=Aggregated iCal Feed-Link
+cal.icalfeed.aggregated.title=Personal aggregated iCal Feed-Link
 cal.icalfeed.aggregated.tooltip=$\:cal.icalfeed.aggregated.title
 cal.icalfeed.info=Please use the following URL to access your calendar from other applications. You can copy and paste this to any other application supporting the iCal format.
 cal.icalfeed.regenerate.info=ICal Feed Link has been regenerated.
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 3c84e04a0cd..953e9741b17 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
@@ -67,7 +67,7 @@ cal.fri=Vendredi
 cal.from=De
 cal.goto.event=Aller au rdv. s\u00E9lectionn\u00E9
 cal.icalfeed.aggregated.info=Utilisez le lien suivant pour l'acc\u00E8s de votre calendrier  (tous les calendriers agr\u00E9g\u00E9 inclus) \u00E0 partir d'autres applications. Vous pouvez copier le lien et le coller dans une application qui prend en charge le format iCal.
-cal.icalfeed.aggregated.title=Flux iCal des calendriers agr\u00E9g\u00E9s
+cal.icalfeed.aggregated.title=Flux agr\u00E9g\u00E9 et personalis\u00E9 des calendriers iCal
 cal.icalfeed.aggregated.tooltip=$\:cal.icalfeed.aggregated.title
 cal.icalfeed.info=Veuillez utiliser l'URL suivante pour appeler ce calendrier depuis une autre application. Vous pouvez copier l'URL et l'ins\u00E9rer dans toute autre application de calendrier qui supporte le format iCal.
 cal.icalfeed.regenerate.info=Le lien iCal Feed a \u00E9t\u00E9 r\u00E9actualis\u00E9.
diff --git a/src/main/java/org/olat/commons/calendar/_i18n/LocalStrings_it.properties b/src/main/java/org/olat/commons/calendar/_i18n/LocalStrings_it.properties
index 9830903553b..8797b41ef60 100644
--- a/src/main/java/org/olat/commons/calendar/_i18n/LocalStrings_it.properties
+++ b/src/main/java/org/olat/commons/calendar/_i18n/LocalStrings_it.properties
@@ -67,7 +67,6 @@ cal.fri=Venerd\u00EC
 cal.from=Da
 cal.goto.event=Vai all'impegno selezionato
 cal.icalfeed.aggregated.info=Utilizzare il seguente URL per richiamare questo calendario (inclusi tutti i calendari aggregati) da altre applicazioni. \u00C8 possibile copiare e incollare l'URL all'interno di qualsiasi applicazione di calendario che supporti il formato iCal.
-cal.icalfeed.aggregated.title=Feed-link iCal aggregato
 cal.icalfeed.aggregated.tooltip=$\:cal.icalfeed.aggregated.title
 cal.icalfeed.info=Utilizzi questo URL per accedere a questo calendario da altre applicazioni. La pu\u00F2 copiare e incollare in qualsiasi altra applicazione calendario che supporta il formato iCal.
 cal.icalfeed.regenerate.info=Il feed link iCal \u00E8 stato rigenerato.
diff --git a/src/main/java/org/olat/commons/calendar/_i18n/LocalStrings_pt_BR.properties b/src/main/java/org/olat/commons/calendar/_i18n/LocalStrings_pt_BR.properties
index 530193a9d73..e42ab131f52 100644
--- a/src/main/java/org/olat/commons/calendar/_i18n/LocalStrings_pt_BR.properties
+++ b/src/main/java/org/olat/commons/calendar/_i18n/LocalStrings_pt_BR.properties
@@ -67,7 +67,6 @@ cal.fri=Sexta
 cal.from=De
 cal.goto.event=Ir para evento selecionado
 cal.icalfeed.aggregated.info=Utilize a seguinte URL, a fim de chamar este calend\u00E1rio (incluindo todos os calend\u00E1rios agregados) a partir de outras aplica\u00E7\u00F5es. Voc\u00EA pode copiar e colar a URL em qualquer aplica\u00E7\u00E3o de calend\u00E1rio que suporte o formato iCal.
-cal.icalfeed.aggregated.title=Feed-Link iCal agragado
 cal.icalfeed.aggregated.tooltip=$\:cal.icalfeed.aggregated.title
 cal.icalfeed.info=Por favor, use a seguinte URL para acessar sua agenda de outras aplica\u00E7\u00F5es. Voc\u00EA pode copiar e colar este para qualquer outra aplica\u00E7\u00E3o de suporte ao formato iCal.
 cal.icalfeed.regenerate.info=ICal Feed-Link foi regenerado.
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 dcd2f430b35..e5b3d11bd17 100644
--- a/src/main/java/org/olat/commons/calendar/manager/ICalFileCalendarManager.java
+++ b/src/main/java/org/olat/commons/calendar/manager/ICalFileCalendarManager.java
@@ -429,6 +429,13 @@ public class ICalFileCalendarManager implements CalendarManager, InitializingBea
 				token, false, false);
 	}
 
+	@Override
+	public CalendarUserConfiguration createCalendarConfig(Identity identity, Kalendar calendar) {
+		String token = RandomStringUtils.randomAlphanumeric(6);
+		return calendarUserConfigDao.createCalendarUserConfiguration(calendar, identity,
+				token, false, false);
+	}
+
 	@Override
 	public CalendarUserConfiguration saveCalendarConfig(CalendarUserConfiguration configuration) {
 		return calendarUserConfigDao.update(configuration);
@@ -444,6 +451,11 @@ public class ICalFileCalendarManager implements CalendarManager, InitializingBea
 		return calendarUserConfigDao.getCalendarUserConfigurations(identity, types);
 	}
 	
+	@Override
+	public CalendarUserConfiguration getCalendarUserConfiguration(IdentityRef identity, Kalendar calendar) {
+		return calendarUserConfigDao.getCalendarUserConfiguration(identity, calendar.getCalendarID(), calendar.getType());
+	}
+
 	@Override
 	public Map<CalendarKey,CalendarUserConfiguration> getCalendarUserConfigurationsMap(IdentityRef identity, String... types) {
 		List<CalendarUserConfiguration> list = calendarUserConfigDao.getCalendarUserConfigurations(identity, types);
diff --git a/src/main/java/org/olat/commons/calendar/ui/CalendarAggregatedURLController.java b/src/main/java/org/olat/commons/calendar/ui/CalendarAggregatedURLController.java
index 8ce24a9d892..c9451c3c4ce 100644
--- a/src/main/java/org/olat/commons/calendar/ui/CalendarAggregatedURLController.java
+++ b/src/main/java/org/olat/commons/calendar/ui/CalendarAggregatedURLController.java
@@ -26,6 +26,7 @@ import org.olat.core.gui.components.velocity.VelocityContainer;
 import org.olat.core.gui.control.Event;
 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;
 
 /**
@@ -36,13 +37,18 @@ import org.olat.core.util.Util;
  */
 public class CalendarAggregatedURLController extends BasicController {
 
-	public CalendarAggregatedURLController(UserRequest ureq, WindowControl wControl, String icalFeedLink) {
+	public CalendarAggregatedURLController(UserRequest ureq, WindowControl wControl, String icalFeedLink, String icalAggregatedFeedLink) {
 		super(ureq, wControl);
 		setTranslator(Util.createPackageTranslator(CalendarManager.class, getLocale(), getTranslator()));
 		
-		VelocityContainer colorVC = createVelocityContainer("calAggregatedFeed");
-		colorVC.contextPut("icalFeedLink", icalFeedLink);
-		putInitialPanel(colorVC);
+		VelocityContainer mainVC = createVelocityContainer("calAggregatedFeed");
+		if(StringHelper.containsNonWhitespace(icalFeedLink)) {
+			mainVC.contextPut("icalFeedLink", icalFeedLink);
+		}
+		if(StringHelper.containsNonWhitespace(icalAggregatedFeedLink)) {
+			mainVC.contextPut("icalAggregatedFeedLink", icalAggregatedFeedLink);
+		}
+		putInitialPanel(mainVC);
 	}
 	
 	@Override
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 e46702e1e28..ede144f93f2 100644
--- a/src/main/java/org/olat/commons/calendar/ui/WeeklyCalendarController.java
+++ b/src/main/java/org/olat/commons/calendar/ui/WeeklyCalendarController.java
@@ -77,6 +77,7 @@ import org.olat.core.gui.control.generic.modal.DialogBoxController;
 import org.olat.core.gui.control.generic.modal.DialogBoxUIFactory;
 import org.olat.core.gui.control.winmgr.JSCommand;
 import org.olat.core.helpers.Settings;
+import org.olat.core.id.OLATResourceable;
 import org.olat.core.id.UserConstants;
 import org.olat.core.id.context.BusinessControlFactory;
 import org.olat.core.id.context.ContextEntry;
@@ -124,6 +125,7 @@ public class WeeklyCalendarController extends FormBasicController implements Act
 	private final String caller;
 	private boolean dirty = false;
 	private final boolean allowImport;
+	private final OLATResourceable callerOres;
 
 	private List<KalendarRenderWrapper> calendarWrappers;
 	
@@ -149,13 +151,14 @@ public class WeeklyCalendarController extends FormBasicController implements Act
 	 * @param eventAlwaysVisible  When true, the 'isVis()' check is disabled and events will be displayed always.
 	 */
 	public WeeklyCalendarController(UserRequest ureq, WindowControl wControl, List<KalendarRenderWrapper> calendarWrappers,
-			String caller, boolean allowImport) {
+			String caller, OLATResourceable callerOres, boolean allowImport) {
 		super(ureq,wControl, "indexWeekly");
 		setTranslator(Util.createPackageTranslator(CalendarManager.class, ureq.getLocale(), getTranslator()));
-		
+
+		this.caller = caller;
 		this.allowImport = allowImport;
 		this.calendarWrappers = calendarWrappers;
-		this.caller = caller;
+		this.callerOres = callerOres == null ? null : OresHelper.clone(callerOres);
 		
 		String themeBaseUri = wControl.getWindowBackOffice().getWindow().getGuiTheme().getBaseURI();
 		printMapper = new CalendarPrintMapper(themeBaseUri, getTranslator());
@@ -315,7 +318,7 @@ public class WeeklyCalendarController extends FormBasicController implements Act
 					doConfigure(ureq);
 				} else if(CalendarGUIFormEvent.AGGREGATED_FEED.equals(cmd)) {
 					CalendarGUIFormEvent guiEvent = (CalendarGUIFormEvent)event;
-					doOpenAggregatedFeelUrl(ureq, guiEvent.getTargetDomId());
+					doOpenAggregatedFeedUrl(ureq, guiEvent.getTargetDomId());
 				}
 			} else if (event instanceof CalendarGUIPrintEvent) {
 				CalendarGUIPrintEvent printEvent = (CalendarGUIPrintEvent)event;
@@ -486,7 +489,54 @@ public class WeeklyCalendarController extends FormBasicController implements Act
 		}
 	}
 	
-	private void doOpenAggregatedFeelUrl(UserRequest ureq, String targetDomId) {
+	private void doOpenAggregatedFeedUrl(UserRequest ureq, String targetDomId) {
+		String callerUrl = getCallerCalendarUrl();
+		String aggregatedUrl = getAggregatedCalendarUrl();
+		feedUrlCtrl = new CalendarAggregatedURLController(ureq, getWindowControl(), callerUrl, aggregatedUrl);
+		listenTo(feedUrlCtrl);
+		
+		eventCalloutCtr = new CloseableCalloutWindowController(ureq, getWindowControl(), feedUrlCtrl.getInitialComponent(), targetDomId,
+				translate("print"), true, "o_cal_event_callout");
+		listenTo(eventCalloutCtr);
+		eventCalloutCtr.activate();
+	}
+	
+	private String getCallerCalendarUrl() {
+		if(callerOres == null) return null;
+		
+		String url = null;
+		if(WeeklyCalendarController.CALLER_COLLAB.equals(caller)) {
+			url = getCallerCalendarUrl(CalendarManager.TYPE_GROUP, callerOres.getResourceableId().toString());
+		} else if(WeeklyCalendarController.CALLER_COURSE.equals(caller)) {
+			url = getCallerCalendarUrl(CalendarManager.TYPE_COURSE, callerOres.getResourceableId().toString());
+		}
+		return url;
+	}
+	
+	private String getCallerCalendarUrl(String type, String calendarId) {
+		Kalendar callerKalendar = null;
+		for(KalendarRenderWrapper calendarWrapper:calendarWrappers) {
+			if(calendarWrapper.getKalendar().getType().equals(type) && calendarWrapper.getKalendar().getCalendarID().equals(calendarId)) {
+				callerKalendar = calendarWrapper.getKalendar();
+				break;
+			}
+		}
+		
+		if(callerKalendar != null) {
+			CalendarUserConfiguration config = calendarManager.getCalendarUserConfiguration(getIdentity(), callerKalendar);
+			if(config == null) {
+				config = calendarManager.createCalendarConfig(getIdentity(), callerKalendar);
+			} else if(!StringHelper.containsNonWhitespace(config.getToken())) {
+				config.setToken(RandomStringUtils.randomAlphanumeric(6));
+				config = calendarManager.saveCalendarConfig(config);
+			}
+			return Settings.getServerContextPathURI() + "/ical/" + type + "/" + config.getKey()
+				+ "/" + config.getToken() + "/" + callerKalendar.getCalendarID() + ".ics";
+		}
+		return null;
+	}
+	
+	private String getAggregatedCalendarUrl() {
 		List<CalendarUserConfiguration> configurations = calendarManager
 				.getCalendarUserConfigurationsList(getIdentity(), CalendarManager.TYPE_USER_AGGREGATED);
 
@@ -500,17 +550,8 @@ public class WeeklyCalendarController extends FormBasicController implements Act
 			config.setToken(RandomStringUtils.randomAlphanumeric(6));
 			config = calendarManager.saveCalendarConfig(config);
 		}
-		
-		String token = config.getToken();
-		Long configKey = config.getKey();
-		String url = Settings.getServerContextPathURI() + "/ical/" + CalendarManager.TYPE_USER_AGGREGATED + "/" + configKey + "/" + token + ".ics"; 	
-		feedUrlCtrl = new CalendarAggregatedURLController(ureq, getWindowControl(), url);
-		listenTo(feedUrlCtrl);
-		
-		eventCalloutCtr = new CloseableCalloutWindowController(ureq, getWindowControl(), feedUrlCtrl.getInitialComponent(), targetDomId,
-				translate("print"), true, "o_cal_event_callout");
-		listenTo(eventCalloutCtr);
-		eventCalloutCtr.activate();
+		return Settings.getServerContextPathURI() + "/ical/" + CalendarManager.TYPE_USER_AGGREGATED
+				+ "/" + config.getKey() + "/" + config.getToken() + ".ics";
 	}
 	
 	private void doConfigure(UserRequest ureq) {
diff --git a/src/main/java/org/olat/commons/calendar/ui/_content/calAggregatedFeed.html b/src/main/java/org/olat/commons/calendar/ui/_content/calAggregatedFeed.html
index 938702f0775..84cc75d8401 100644
--- a/src/main/java/org/olat/commons/calendar/ui/_content/calAggregatedFeed.html
+++ b/src/main/java/org/olat/commons/calendar/ui/_content/calAggregatedFeed.html
@@ -1,3 +1,10 @@
-<h4>$r.translate("cal.icalfeed.aggregated.title")</h4>
-<div class="o_info">$r.translate("cal.icalfeed.aggregated.info")</div>
-<div class="clearfix"><input type="text" value="$icalFeedLink" style="width:100%;" onclick="this.select();"/></div>
\ No newline at end of file
+#if($r.isNotEmpty($icalFeedLink))
+	<h4>$r.translate("cal.icalfeed.title")</h4>
+	<div class="o_info">$r.translate("cal.icalfeed.info")</div>
+	<div class="clearfix"><input type="text" value="$icalFeedLink" style="width:100%;" onclick="this.select();"/></div>
+#end
+#if($r.isNotEmpty($icalAggregatedFeedLink))
+	<h4>$r.translate("cal.icalfeed.aggregated.title")</h4>
+	<div class="o_info">$r.translate("cal.icalfeed.aggregated.info")</div>
+	<div class="clearfix"><input type="text" value="$icalAggregatedFeedLink" style="width:100%;" onclick="this.select();"/></div>
+#end
\ No newline at end of file
diff --git a/src/main/java/org/olat/course/nodes/cal/CourseCalendarController.java b/src/main/java/org/olat/course/nodes/cal/CourseCalendarController.java
index 9128ed7bf8f..4c1ff4122ce 100644
--- a/src/main/java/org/olat/course/nodes/cal/CourseCalendarController.java
+++ b/src/main/java/org/olat/course/nodes/cal/CourseCalendarController.java
@@ -64,8 +64,8 @@ public class CourseCalendarController extends DefaultController implements Clone
 		this.nodeEvaluation = ne;
 		calendars = myCal.getCalendars();
 		courseKalendarWrapper = myCal.getCourseKalendarWrapper();
-		calendarController = new WeeklyCalendarController(ureq, wControl, calendars,
-				WeeklyCalendarController.CALLER_COURSE, false);
+		calendarController = new WeeklyCalendarController(ureq, wControl, calendars, WeeklyCalendarController.CALLER_COURSE,
+				courseEnv.getCourseEnvironment().getCourseGroupManager().getCourseResource(), false);
 		calendarController.setDifferentiateManagedEvent(needToDifferentiateManagedEvents(calendars));
 		setInitialComponent(calendarController.getInitialComponent());
 	}
diff --git a/src/main/java/org/olat/course/run/calendar/CourseCalendarController.java b/src/main/java/org/olat/course/run/calendar/CourseCalendarController.java
index 566558401b4..ef5ab9a8d36 100644
--- a/src/main/java/org/olat/course/run/calendar/CourseCalendarController.java
+++ b/src/main/java/org/olat/course/run/calendar/CourseCalendarController.java
@@ -71,8 +71,8 @@ public class CourseCalendarController extends BasicController {
 		super(ureq, wControl);
 		this.userCourseEnv = userCourseEnv;
 		List<KalendarRenderWrapper> calendars = getListOfCalendarWrappers(ureq);
-		calendarController = new WeeklyCalendarController(ureq, wControl, calendars,
-				WeeklyCalendarController.CALLER_COURSE, false);
+		calendarController = new WeeklyCalendarController(ureq, wControl, calendars, WeeklyCalendarController.CALLER_COURSE,
+				userCourseEnv.getCourseEnvironment().getCourseGroupManager().getCourseResource(), false);
 		calendarController.setDifferentiateManagedEvent(needToDifferentiateManagedEvents(calendars));
 		listenTo(calendarController);
 		putInitialPanel(calendarController.getInitialComponent());
@@ -88,7 +88,7 @@ public class CourseCalendarController extends BasicController {
 	}
 
 	private List<KalendarRenderWrapper> getListOfCalendarWrappers(UserRequest ureq) {
-		List<KalendarRenderWrapper> calendars = new ArrayList<KalendarRenderWrapper>();
+		List<KalendarRenderWrapper> calendars = new ArrayList<>();
 		// add course calendar
 		ICourse course = CourseFactory.loadCourse(userCourseEnv.getCourseEnvironment().getCourseGroupManager().getCourseEntry());
 		courseKalendarWrapper = calendarManager.getCourseCalendar(course);
diff --git a/src/main/java/org/olat/group/ui/homepage/GroupInfoMainController.java b/src/main/java/org/olat/group/ui/homepage/GroupInfoMainController.java
index 280d59c4934..7a953bde5a5 100644
--- a/src/main/java/org/olat/group/ui/homepage/GroupInfoMainController.java
+++ b/src/main/java/org/olat/group/ui/homepage/GroupInfoMainController.java
@@ -218,7 +218,8 @@ public class GroupInfoMainController extends MainLayoutBasicController implement
 			KalendarRenderWrapper groupCalendar = calendarManager.getGroupCalendar(businessGroup);
 			groupCalendar.setPrivateEventsVisible(false);
 			calendarWrappers.add(groupCalendar);
-			calendarController = new WeeklyCalendarController(ureq, bwControl, calendarWrappers, WeeklyCalendarController.CALLER_COLLAB, false);
+			calendarController = new WeeklyCalendarController(ureq, bwControl, calendarWrappers,
+					WeeklyCalendarController.CALLER_COLLAB, businessGroup, false);
 			listenTo(calendarController);
 		}
 		
diff --git a/src/main/java/org/olat/home/HomeCalendarController.java b/src/main/java/org/olat/home/HomeCalendarController.java
index 9e605999f8d..a41fc592b3f 100644
--- a/src/main/java/org/olat/home/HomeCalendarController.java
+++ b/src/main/java/org/olat/home/HomeCalendarController.java
@@ -63,7 +63,7 @@ public class HomeCalendarController extends BasicController implements Activatea
 		
 		List<KalendarRenderWrapper> calendars = homeCalendarManager.getListOfCalendarWrappers(ureq, windowControl);
 		calendarController = new WeeklyCalendarController(ureq, windowControl, calendars,
-				WeeklyCalendarController.CALLER_HOME, true);
+				WeeklyCalendarController.CALLER_HOME, null, true);
 		listenTo(calendarController);
 
 		putInitialPanel(calendarController.getInitialComponent());
diff --git a/src/main/java/org/olat/user/UserInfoMainController.java b/src/main/java/org/olat/user/UserInfoMainController.java
index e5ae1449d68..e1c367cb292 100644
--- a/src/main/java/org/olat/user/UserInfoMainController.java
+++ b/src/main/java/org/olat/user/UserInfoMainController.java
@@ -344,7 +344,7 @@ public class UserInfoMainController extends MainLayoutBasicController implements
 		OLATResourceable ores = OresHelper.createOLATResourceableType(CMD_CALENDAR);
 		WindowControl bwControl = addToHistory(ureq, ores, null);
 		calendarController = new WeeklyCalendarController(ureq, bwControl, calendars,
-				WeeklyCalendarController.CALLER_PROFILE, false);
+				WeeklyCalendarController.CALLER_PROFILE, null, false);
 		listenTo(calendarController);
 		return calendarController;
 	}
-- 
GitLab