diff --git a/src/main/java/org/olat/_spring/mainContext.xml b/src/main/java/org/olat/_spring/mainContext.xml
index 9f281a42f91f42cbd438ab468aaabba805ee34a9..a9f827a6f326f12fd9521ea06e34ad8b313e1398 100644
--- a/src/main/java/org/olat/_spring/mainContext.xml
+++ b/src/main/java/org/olat/_spring/mainContext.xml
@@ -8,7 +8,7 @@
         http://www.springframework.org/schema/context 
         http://www.springframework.org/schema/context/spring-context.xsd">
   
-	<context:component-scan base-package="org.olat.note,org.olat.social,org.olat.commons.memberlist" />
+	<context:component-scan base-package="org.olat.note,org.olat.social,org.olat.commons.memberlist,org.olat.commons.info" />
 
 	<import resource="classpath:/org/olat/core/util/threadlog/_spring/threadlogCorecontext.xml"/>
 	<import resource="classpath:/org/olat/core/_spring/mainCorecontext.xml"/>
@@ -24,7 +24,6 @@
 	<import resource="classpath:/org/olat/basesecurity/_spring/baseSecurityContext.xml"/>
 	<import resource="classpath:/org/olat/collaboration/_spring/collaborationToolsContext.xml"/>
 	<import resource="classpath:/org/olat/commons/calendar/_spring/calendarContext.xml"/>
-	<import resource="classpath:/org/olat/commons/info/_spring/infoMessageContext.xml"/>
 	<import resource="classpath:/org/olat/commons/servlets/_spring/staticContext.xml"/>
 
 	<import resource="classpath:/org/olat/course/_spring/courseContext.xml"/>
diff --git a/src/main/java/org/olat/commons/info/model/InfoMessage.java b/src/main/java/org/olat/commons/info/InfoMessage.java
similarity index 93%
rename from src/main/java/org/olat/commons/info/model/InfoMessage.java
rename to src/main/java/org/olat/commons/info/InfoMessage.java
index b8de6b7f12a8b229cb5de796b541f7585599b6e0..d975bb12da44897ee4e1ade8a467505d7dd893ce 100644
--- a/src/main/java/org/olat/commons/info/model/InfoMessage.java
+++ b/src/main/java/org/olat/commons/info/InfoMessage.java
@@ -18,7 +18,7 @@
  * <p>
  */
 
-package org.olat.commons.info.model;
+package org.olat.commons.info;
 
 import java.util.Date;
 
@@ -26,9 +26,6 @@ import org.olat.core.id.Identity;
 import org.olat.core.id.OLATResourceable;
 
 /**
- * 
- * Description:<br>
- * TODO: srosse Class Description for InfoMessage
  * 
  * <P>
  * Initial Date:  27 jul. 2010 <br>
@@ -51,6 +48,10 @@ public interface InfoMessage {
 	public String getMessage();
 
 	public void setMessage(String message);
+	
+	public String getAttachmentPath();
+	
+	public void setAttachmentPath(String path);
 
 	public Long getResId();
 
diff --git a/src/main/java/org/olat/commons/info/manager/InfoMessageFrontendManager.java b/src/main/java/org/olat/commons/info/InfoMessageFrontendManager.java
similarity index 87%
rename from src/main/java/org/olat/commons/info/manager/InfoMessageFrontendManager.java
rename to src/main/java/org/olat/commons/info/InfoMessageFrontendManager.java
index a43fc80e807e7d5979cc444da3e4b8b73f366eff..f1b3131881c78621728b6d5a2654e13d13429fad 100644
--- a/src/main/java/org/olat/commons/info/manager/InfoMessageFrontendManager.java
+++ b/src/main/java/org/olat/commons/info/InfoMessageFrontendManager.java
@@ -18,17 +18,20 @@
  * <p>
  */
 
-package org.olat.commons.info.manager;
+package org.olat.commons.info;
 
+import java.io.File;
+import java.util.Collection;
 import java.util.Date;
 import java.util.List;
 import java.util.Locale;
 
 import org.olat.basesecurity.IdentityRef;
-import org.olat.commons.info.model.InfoMessage;
+import org.olat.commons.info.manager.MailFormatter;
 import org.olat.core.id.Identity;
 import org.olat.core.id.OLATResourceable;
 import org.olat.core.util.resource.OresHelper;
+import org.olat.core.util.vfs.VFSLeaf;
 import org.olat.group.BusinessGroup;
 import org.olat.group.BusinessGroupRef;
 
@@ -62,6 +65,12 @@ public interface InfoMessageFrontendManager {
 	
 	public void saveInfoMessage(InfoMessage msg);
 	
+	public VFSLeaf getAttachment(InfoMessage msg);
+	
+	public String storeAttachment(File file, String filename, OLATResourceable ores, String subPath);
+	
+	public void deleteAttachments(Collection<String> paths);
+	
 	public void deleteInfoMessage(InfoMessage infoMessage);
 	
 	public void updateInfoMessagesOfIdentity(BusinessGroupRef businessGroup, IdentityRef identity);
diff --git a/src/main/java/org/olat/commons/info/manager/InfoMessageManager.java b/src/main/java/org/olat/commons/info/InfoMessageManager.java
similarity index 55%
rename from src/main/java/org/olat/commons/info/manager/InfoMessageManager.java
rename to src/main/java/org/olat/commons/info/InfoMessageManager.java
index 24f4b65916e8a4fc406661a8847153195d47bd66..82b4604057036684629761d2d018a9923980c19d 100644
--- a/src/main/java/org/olat/commons/info/manager/InfoMessageManager.java
+++ b/src/main/java/org/olat/commons/info/InfoMessageManager.java
@@ -18,40 +18,31 @@
  * <p>
  */
 
-package org.olat.commons.info.manager;
+package org.olat.commons.info;
 
 import java.util.Date;
 import java.util.List;
 
 import org.olat.basesecurity.IdentityRef;
-import org.olat.commons.info.model.InfoMessage;
 import org.olat.core.id.Identity;
 import org.olat.core.id.OLATResourceable;
 import org.olat.group.BusinessGroupRef;
 
-public abstract class InfoMessageManager {
-
-	protected static InfoMessageManager INSTANCE;
-	
-	
-	public static InfoMessageManager getInstance() {
-		return INSTANCE;
-	}
-	
+public interface InfoMessageManager {
 	
-	public abstract InfoMessage createInfoMessage(OLATResourceable ores, String subPath, String businessPath, Identity author);
+	public InfoMessage createInfoMessage(OLATResourceable ores, String subPath, String businessPath, Identity author);
 	
-	public abstract void saveInfoMessage(InfoMessage infoMessage);
+	public void saveInfoMessage(InfoMessage infoMessage);
 	
-	public abstract void deleteInfoMessage(InfoMessage infoMessage);
+	public void deleteInfoMessage(InfoMessage infoMessage);
 	
-	public abstract List<InfoMessage> loadInfoMessagesOfIdentity(BusinessGroupRef businessGroup, IdentityRef identity);
+	public List<InfoMessage> loadInfoMessagesOfIdentity(BusinessGroupRef businessGroup, IdentityRef identity);
 	
-	public abstract InfoMessage loadInfoMessageByKey(Long key);
+	public InfoMessage loadInfoMessageByKey(Long key);
 	
-	public abstract List<InfoMessage> loadInfoMessageByResource(OLATResourceable ores, String subPath, String businessPath,
+	public List<InfoMessage> loadInfoMessageByResource(OLATResourceable ores, String subPath, String businessPath,
 			Date after, Date before, int firstResult, int maxReturn);
 	
-	public abstract int countInfoMessageByResource(OLATResourceable ores, String subPath, String businessPath,
+	public int countInfoMessageByResource(OLATResourceable ores, String subPath, String businessPath,
 			Date after, Date before);
 }
diff --git a/src/main/java/org/olat/commons/info/notification/InfoSubscriptionManager.java b/src/main/java/org/olat/commons/info/InfoSubscriptionManager.java
similarity index 56%
rename from src/main/java/org/olat/commons/info/notification/InfoSubscriptionManager.java
rename to src/main/java/org/olat/commons/info/InfoSubscriptionManager.java
index 210b10e83629630160edc9cb036cfaa257220d6a..0b010e065f8db2414844be0bdcb9742e87e9a80f 100644
--- a/src/main/java/org/olat/commons/info/notification/InfoSubscriptionManager.java
+++ b/src/main/java/org/olat/commons/info/InfoSubscriptionManager.java
@@ -18,10 +18,11 @@
  * <p>
  */
 
-package org.olat.commons.info.notification;
+package org.olat.commons.info;
 
 import java.util.List;
 
+import org.olat.commons.info.notification.InfoSubscription;
 import org.olat.core.commons.services.notifications.PublisherData;
 import org.olat.core.commons.services.notifications.Subscriber;
 import org.olat.core.commons.services.notifications.SubscriptionContext;
@@ -38,30 +39,24 @@ import org.olat.core.util.prefs.Preferences;
  * Initial Date:  27 jul. 2010 <br>
  * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
  */
-public abstract class InfoSubscriptionManager {
-
-	protected static InfoSubscriptionManager INSTANCE;
-	
-	public static InfoSubscriptionManager getInstance() {
-		return INSTANCE;
-	}
+public interface InfoSubscriptionManager {
 	
-	public abstract SubscriptionContext getInfoSubscriptionContext(OLATResourceable resource, String subPath);
+	public SubscriptionContext getInfoSubscriptionContext(OLATResourceable resource, String subPath);
 	
-	public abstract PublisherData getInfoPublisherData(OLATResourceable resource, String businessPath);
+	public PublisherData getInfoPublisherData(OLATResourceable resource, String businessPath);
 	
-	public abstract InfoSubscription getInfoSubscription(Preferences prefs);
+	public InfoSubscription getInfoSubscription(Preferences prefs);
 	
-	public abstract Subscriber getInfoSubscriber(Identity identity, OLATResourceable resource, String subPath);
+	public Subscriber getInfoSubscriber(Identity identity, OLATResourceable resource, String subPath);
 	
-	public abstract List<Identity> getInfoSubscribers(OLATResourceable resource, String subPath);
+	public List<Identity> getInfoSubscribers(OLATResourceable resource, String subPath);
 	
-	public abstract void subscribe(OLATResourceable resource, String resSubPath, String businessPath, Identity identity);
+	public void subscribe(OLATResourceable resource, String resSubPath, String businessPath, Identity identity);
 	
-	public abstract void unsubscribe(OLATResourceable resource, String subPath, Identity identity);
+	public void unsubscribe(OLATResourceable resource, String subPath, Identity identity);
 	
-	public abstract void markPublisherNews(OLATResourceable resource, String subPath);
+	public void markPublisherNews(OLATResourceable resource, String subPath);
 
-	public abstract void deleteSubscriptionContext(SubscriptionContext context);
+	public void deleteSubscriptionContext(SubscriptionContext context);
 	
 }
diff --git a/src/main/java/org/olat/commons/info/_spring/infoMessageContext.xml b/src/main/java/org/olat/commons/info/_spring/infoMessageContext.xml
deleted file mode 100644
index 202632f67995d66b0a0d61be6f35fc8a00cb0871..0000000000000000000000000000000000000000
--- a/src/main/java/org/olat/commons/info/_spring/infoMessageContext.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<beans xmlns="http://www.springframework.org/schema/beans"
-	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-	xmlns:context="http://www.springframework.org/schema/context" 
-	xsi:schemaLocation="http://www.springframework.org/schema/beans 
-                        http://www.springframework.org/schema/beans/spring-beans.xsd">
-                        
-	<bean id="infoMessageFrontendManager" class="org.olat.commons.info.manager.InfoMessageFrontendManagerImpl">
-		<property name="coordinatorManager" ref="coordinatorManager"/>
-		<property name="infoMessageManager" ref="infoMessageManager"/>
-		<property name="infoSubscriptionManager" ref="infoSubscriptionManager"/>
-		<property name="mailManager" ref="mailManager"/>
-	</bean>
-
-	<bean id="infoMessageManager" class="org.olat.commons.info.manager.InfoMessageManagerImpl">
-	  <property name="dbInstance" ref="database"/>
-	</bean>
-	
-	<bean id="infoSubscriptionManager" class="org.olat.commons.info.notification.InfoSubscriptionManagerImpl">
-	  <property name="notificationsManager" ref="notificationsManager"/>
-	</bean>
-	
-</beans>
diff --git a/src/main/java/org/olat/commons/info/manager/InfoMessageFrontendManagerImpl.java b/src/main/java/org/olat/commons/info/manager/InfoMessageFrontendManagerImpl.java
index 518e29124305dd3ff660df85219baa2da5cca634..4a49b5e002a3955c8dd34cefa92831fb1caccb07 100644
--- a/src/main/java/org/olat/commons/info/manager/InfoMessageFrontendManagerImpl.java
+++ b/src/main/java/org/olat/commons/info/manager/InfoMessageFrontendManagerImpl.java
@@ -20,6 +20,16 @@
 
 package org.olat.commons.info.manager;
 
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.StandardCopyOption;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
 import java.util.Date;
 import java.util.HashSet;
 import java.util.List;
@@ -27,9 +37,12 @@ import java.util.Locale;
 import java.util.Set;
 
 import org.olat.basesecurity.IdentityRef;
-import org.olat.commons.info.model.InfoMessage;
+import org.olat.commons.info.InfoMessage;
+import org.olat.commons.info.InfoMessageFrontendManager;
+import org.olat.commons.info.InfoMessageManager;
+import org.olat.commons.info.InfoSubscriptionManager;
 import org.olat.commons.info.model.InfoMessageImpl;
-import org.olat.commons.info.notification.InfoSubscriptionManager;
+import org.olat.core.commons.modules.bc.vfs.OlatRootFolderImpl;
 import org.olat.core.commons.services.notifications.SubscriptionContext;
 import org.olat.core.id.Identity;
 import org.olat.core.id.OLATResourceable;
@@ -44,8 +57,14 @@ import org.olat.core.util.mail.MailContext;
 import org.olat.core.util.mail.MailContextImpl;
 import org.olat.core.util.mail.MailManager;
 import org.olat.core.util.mail.MailerResult;
+import org.olat.core.util.vfs.VFSContainer;
+import org.olat.core.util.vfs.VFSItem;
+import org.olat.core.util.vfs.VFSLeaf;
 import org.olat.group.BusinessGroup;
 import org.olat.group.BusinessGroupRef;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
 
 /**
  * 
@@ -55,47 +74,21 @@ import org.olat.group.BusinessGroupRef;
  * Initial Date:  28 juil. 2010 <br>
  * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
  */
+@Service
 public class InfoMessageFrontendManagerImpl implements InfoMessageFrontendManager {
+
+	private final DateFormat formater = new SimpleDateFormat("yyyyMMdd'T'HHmmss");
+	private static final OLog log = Tracing.createLoggerFor(InfoMessageFrontendManagerImpl.class);
 	
-	private static final OLog log = Tracing.createLoggerFor(InfoMessageFrontendManagerImpl.class); 
-			
+	@Autowired
 	private MailManager mailManager;
+	@Autowired
 	private CoordinatorManager coordinatorManager;
+	@Autowired
 	private InfoMessageManager infoMessageManager;
+	@Autowired
 	private InfoSubscriptionManager infoSubscriptionManager;
 
-	/**
-	 * [used by Spring]
-	 * @param mailManager
-	 */
-	public void setMailManager(MailManager mailManager) {
-		this.mailManager = mailManager;
-	}
-
-	/**
-	 * [used by Spring]
-	 * @param coordinatorManager
-	 */
-	public void setCoordinatorManager(CoordinatorManager coordinatorManager) {
-		this.coordinatorManager = coordinatorManager;
-	}
-
-	/**
-	 * [used by Spring]
-	 * @param infoMessageManager
-	 */
-	public void setInfoMessageManager(InfoMessageManager infoMessageManager) {
-		this.infoMessageManager = infoMessageManager;
-	}
-
-	/**
-	 * [used by Spring]
-	 * @param infoSubscriptionManager
-	 */
-	public void setInfoSubscriptionManager(InfoSubscriptionManager infoSubscriptionManager) {
-		this.infoSubscriptionManager = infoSubscriptionManager;
-	}
-
 	@Override
 	public InfoMessage loadInfoMessage(Long key) {
 		return infoMessageManager.loadInfoMessageByKey(key);
@@ -110,6 +103,72 @@ public class InfoMessageFrontendManagerImpl implements InfoMessageFrontendManage
 	public void saveInfoMessage(InfoMessage infoMessage) {
 		infoMessageManager.saveInfoMessage(infoMessage);
 	}
+	
+	@Override
+	public VFSLeaf getAttachment(InfoMessage msg) {
+		VFSLeaf attachment = null;
+		if(StringHelper.containsNonWhitespace(msg.getAttachmentPath())) {
+			VFSItem item = getStoragePath().resolve(msg.getAttachmentPath());
+			if(item instanceof VFSLeaf) {
+				attachment = (VFSLeaf)item;
+			}
+		}
+		return attachment;
+	}
+	
+	@Override
+	public void deleteAttachments(Collection<String> paths) {
+		if(paths == null || paths.isEmpty()) return;
+		
+		VFSContainer ressourceContainer = getStoragePath();
+		for(String path:paths) {
+			VFSItem item = ressourceContainer.resolve(path);
+			if(item instanceof VFSLeaf) {
+				((VFSLeaf)item).delete();
+			}
+		}
+	}
+
+	@Override
+	public String storeAttachment(File file, String filename, OLATResourceable ores, String subPath) {
+		try {
+			File ressourceDir = getResourceDir(ores);
+
+			String datePart;
+			synchronized(formater) {
+				datePart = formater.format(new Date());
+			}
+			if(filename == null) {
+				filename = file.getName();
+			}
+			filename = datePart + "_" + filename;
+			File attachment = new File(ressourceDir, filename);
+			Files.copy(file.toPath(), attachment.toPath(), StandardCopyOption.REPLACE_EXISTING);
+			
+			File root = getStoragePath().getBasefile();
+			Path relativePath = root.toPath().relativize(attachment.toPath());
+			return relativePath.toString();
+		} catch (IOException e) {
+			log.error("", e);
+			return null;
+		}
+	}
+	
+	private File getResourceDir(OLATResourceable ores) {
+		File root = getStoragePath().getBasefile();
+		String type = ores.getResourceableTypeName().toLowerCase();
+		File typePath = new File(root, type);
+		String id = ores.getResourceableId().toString();
+		File resourceFile = new File(typePath, id);
+		if(!resourceFile.exists()) {
+			resourceFile.mkdirs();
+		}
+		return resourceFile;
+	}
+	
+    private OlatRootFolderImpl getStoragePath() {
+    		return new OlatRootFolderImpl("/infomessages/", null);
+	}
 
 	@Override
 	public boolean sendInfoMessage(InfoMessage infoMessage, MailFormatter mailFormatter, Locale locale, Identity from, List<Identity> tos) {
@@ -138,13 +197,22 @@ public class InfoMessageFrontendManagerImpl implements InfoMessageFrontendManage
 				if(!StringHelper.containsNonWhitespace(body)) {
 					body = infoMessage.getMessage();
 				}
-				//fxdiff VCRP-16: intern mail system
+				File attachment = null;
+				if(StringHelper.containsNonWhitespace(infoMessage.getAttachmentPath())) {
+					File root = getStoragePath().getBasefile();
+					attachment = new File(root, infoMessage.getAttachmentPath());
+				}
+				
 				MailContext context = new MailContextImpl(mailFormatter.getBusinessPath());
 				MailBundle bundle = new MailBundle();
 				bundle.setContext(context);
 				bundle.setFromId(from);
 				bundle.setContactList(contactList);
-				bundle.setContent(subject, body);
+				if(attachment != null) {
+					bundle.setContent(subject, body, attachment);
+				} else {
+					bundle.setContent(subject, body);
+				}
 				
 				MailerResult result = mailManager.sendMessage(bundle);
 				send = result.isSuccessful();
@@ -161,6 +229,9 @@ public class InfoMessageFrontendManagerImpl implements InfoMessageFrontendManage
 	
 	@Override
 	public void deleteInfoMessage(InfoMessage infoMessage) {
+		if(StringHelper.containsNonWhitespace(infoMessage.getAttachmentPath())) {
+			deleteAttachments(Collections.singletonList(infoMessage.getAttachmentPath()));
+		}
 		infoMessageManager.deleteInfoMessage(infoMessage);
 		infoSubscriptionManager.markPublisherNews(infoMessage.getOLATResourceable(), infoMessage.getResSubPath());
 	}
@@ -185,13 +256,18 @@ public class InfoMessageFrontendManagerImpl implements InfoMessageFrontendManage
 	public void removeInfoMessagesAndSubscriptionContext(BusinessGroup group) {
 		List<InfoMessage> messages = infoMessageManager.loadInfoMessageByResource(group,
 				InfoMessageFrontendManager.businessGroupResSubPath, null, null, null, 0, 0);
+		List<String> pathToDelete = new ArrayList<>();
 		for (InfoMessage im : messages) {
 			infoMessageManager.deleteInfoMessage(im);
+			if(StringHelper.containsNonWhitespace(im.getAttachmentPath())) {
+				pathToDelete.add(im.getAttachmentPath());
+			}
 		}			
 		String resName = group.getResourceableTypeName();
 		Long resId = group.getResourceableId();
 		SubscriptionContext subscriptionContext =  new SubscriptionContext(resName, resId, "");
 		infoSubscriptionManager.deleteSubscriptionContext(subscriptionContext);
+		deleteAttachments(pathToDelete);
 	}
 
 	@Override
diff --git a/src/main/java/org/olat/commons/info/manager/InfoMessageManagerImpl.java b/src/main/java/org/olat/commons/info/manager/InfoMessageManagerImpl.java
index 8e4668e3ceca0bc99f37263645670c3653d6d1b2..6b7223164f36c2fdb0724ff5ca8944843f832f07 100644
--- a/src/main/java/org/olat/commons/info/manager/InfoMessageManagerImpl.java
+++ b/src/main/java/org/olat/commons/info/manager/InfoMessageManagerImpl.java
@@ -26,7 +26,8 @@ import java.util.List;
 import java.util.StringTokenizer;
 
 import org.olat.basesecurity.IdentityRef;
-import org.olat.commons.info.model.InfoMessage;
+import org.olat.commons.info.InfoMessage;
+import org.olat.commons.info.InfoMessageManager;
 import org.olat.commons.info.model.InfoMessageImpl;
 import org.olat.core.commons.persistence.DB;
 import org.olat.core.commons.persistence.DBQuery;
@@ -34,6 +35,8 @@ import org.olat.core.id.Identity;
 import org.olat.core.id.OLATResourceable;
 import org.olat.core.util.StringHelper;
 import org.olat.group.BusinessGroupRef;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
 
 /**
  * 
@@ -44,24 +47,11 @@ import org.olat.group.BusinessGroupRef;
  * Initial Date:  26 jul. 2010 <br>
  * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
  */
-public class InfoMessageManagerImpl extends InfoMessageManager {
+@Service("infoMessageManager")
+public class InfoMessageManagerImpl implements InfoMessageManager {
 	
+	@Autowired
 	private DB dbInstance;
-	
-	/**
-	 * [used by Spring]
-	 */
-	private InfoMessageManagerImpl() {
-		INSTANCE = this;
-	}
-	
-	/**
-	 * [used by Spring]
-	 * @param dbInstance
-	 */
-	public void setDbInstance(DB dbInstance) {
-		this.dbInstance = dbInstance;
-	}
 
 	@Override
 	public InfoMessage createInfoMessage(OLATResourceable ores, String subPath, String businessPath, Identity author) {
diff --git a/src/main/java/org/olat/commons/info/manager/MailFormatter.java b/src/main/java/org/olat/commons/info/manager/MailFormatter.java
index 008d76323b95e59f7b5c8aa9ba7ac0a5fb93818b..a7035a7bdf84451dc6031956000923a877e7401b 100644
--- a/src/main/java/org/olat/commons/info/manager/MailFormatter.java
+++ b/src/main/java/org/olat/commons/info/manager/MailFormatter.java
@@ -21,7 +21,7 @@
 
 package org.olat.commons.info.manager;
 
-import org.olat.commons.info.model.InfoMessage;
+import org.olat.commons.info.InfoMessage;
 
 /**
  * 
@@ -37,6 +37,6 @@ public interface MailFormatter {
 		public String getSubject(InfoMessage msg);
 		
 		public String getBody(InfoMessage msg);
-		//fxdiff VCRP-16: intern mail system
+		
 		public String getBusinessPath();
 }
diff --git a/src/main/java/org/olat/commons/info/model/InfoMessageImpl.hbm.xml b/src/main/java/org/olat/commons/info/model/InfoMessageImpl.hbm.xml
deleted file mode 100644
index 8deb349cc00d3d959f7ce2181fd7472002f69f36..0000000000000000000000000000000000000000
--- a/src/main/java/org/olat/commons/info/model/InfoMessageImpl.hbm.xml
+++ /dev/null
@@ -1,34 +0,0 @@
-<?xml version="1.0"?>
-<!DOCTYPE hibernate-mapping PUBLIC
-	"-//Hibernate/Hibernate Mapping DTD//EN"
-	"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
-<hibernate-mapping default-lazy="false">
-  <class name="org.olat.commons.info.model.InfoMessageImpl" table="o_info_message">
-
-		<id name="key" type="long" column="info_id"	unsaved-value="null">
-		<generator class="enhanced-sequence">
-			<param name="sequence_name">hibernate_unique_key</param>
-			<param name="force_table_use">true</param>
-			<param name="optimizer">legacy-hilo</param>
-			<param name="value_column">next_hi</param>
-			<param name="increment_size">32767</param>
-			<param name="initial_value">32767</param>
-		</generator>
-		</id>
-	
-		<version name="version" access="field" column="version"/>
-		<property  name="creationDate" column="creationdate" type="timestamp" />
-		<property  name="modificationDate" column="modificationdate" type="timestamp" />
-		
-		<property name="title" column="title" type="string" length="2048" not-null="false"/>
-		<property name="message" column="message" type="string" length="2048" not-null="false"/>
-	 	
-		<property name="resName" column="resname" type="string"  not-null="true" length="50" index="mark_name_idx"/>
-		<property name="resId" column="resid" type="long" not-null="true" index="mark_id_idx" />
-		<property name="resSubPath" column="ressubpath" type="string"  length="2048" index="mark_subpath_idx"  not-null="false"/>
-		<property name="businessPath" column="businesspath" type="string" length="2048" index="mark_businesspath_idx"  not-null="false"/>
-		
-		<many-to-one name="author" class="org.olat.basesecurity.IdentityImpl" column="fk_author_id" outer-join="true" cascade="none" not-null="true"/>
-		<many-to-one name="modifier" class="org.olat.basesecurity.IdentityImpl" column="fk_modifier_id" outer-join="true" cascade="none" not-null="false"/>
-  </class>
-</hibernate-mapping>
\ No newline at end of file
diff --git a/src/main/java/org/olat/commons/info/model/InfoMessageImpl.java b/src/main/java/org/olat/commons/info/model/InfoMessageImpl.java
index 67690ee93dfe986dedc59c30517380cad63bc160..42ed3313bbaeb5336dc69a4016a0d0b87c05e344 100644
--- a/src/main/java/org/olat/commons/info/model/InfoMessageImpl.java
+++ b/src/main/java/org/olat/commons/info/model/InfoMessageImpl.java
@@ -36,6 +36,7 @@ import javax.persistence.TemporalType;
 import org.hibernate.annotations.GenericGenerator;
 import org.hibernate.annotations.Parameter;
 import org.olat.basesecurity.IdentityImpl;
+import org.olat.commons.info.InfoMessage;
 import org.olat.core.id.CreateInfo;
 import org.olat.core.id.Identity;
 import org.olat.core.id.OLATResourceable;
@@ -77,6 +78,8 @@ public class InfoMessageImpl implements InfoMessage, CreateInfo, Persistable {
 	private String title;
 	@Column(name="message", nullable=true, insertable=true, updatable=true)
 	private String message;
+	@Column(name="attachmentpath", nullable=true, insertable=true, updatable=true)
+	private String attachmentPath;
 	
 	@Column(name="resid", nullable=false, insertable=true, updatable=false)
 	private Long resId;
@@ -97,35 +100,63 @@ public class InfoMessageImpl implements InfoMessage, CreateInfo, Persistable {
 	public InfoMessageImpl() {
 		//
 	}
+
+	@Override
+	public Long getKey() {
+		return key;
+	}
+
 	
+	@Override
+	public Date getCreationDate() {
+		return creationDate;
+	}
+	
+	public void setCreationDate(Date creationDate) {
+		this.creationDate= creationDate;
+	}
+	
+	@Override
 	public Date getModificationDate() {
 		return modificationDate;
 	}
 
+	@Override
 	public void setModificationDate(Date modificationDate) {
 		this.modificationDate = modificationDate;
 	}
-	
-	public void setCreationDate(Date creationDate) {
-		this.creationDate= creationDate;
-	}
 
+	@Override
 	public String getTitle() {
 		return title;
 	}
 
+	@Override
 	public void setTitle(String title) {
 		this.title = title;
 	}
 
+	@Override
 	public String getMessage() {
 		return message;
 	}
 
+	@Override
 	public void setMessage(String message) {
 		this.message = message;
 	}
 
+	@Override
+	public String getAttachmentPath() {
+		return attachmentPath;
+	}
+
+	@Override
+	public void setAttachmentPath(String attachmentPath) {
+		this.attachmentPath = attachmentPath;
+	}
+
+	@Override
 	public Long getResId() {
 		return resId;
 	}
@@ -134,6 +165,7 @@ public class InfoMessageImpl implements InfoMessage, CreateInfo, Persistable {
 		this.resId = resId;
 	}
 
+	@Override
 	public String getResName() {
 		return resName;
 	}
@@ -142,6 +174,7 @@ public class InfoMessageImpl implements InfoMessage, CreateInfo, Persistable {
 		this.resName = resName;
 	}
 
+	@Override
 	public String getResSubPath() {
 		return resSubPath;
 	}
@@ -150,6 +183,7 @@ public class InfoMessageImpl implements InfoMessage, CreateInfo, Persistable {
 		this.resSubPath = subPath;
 	}
 
+	@Override
 	public String getBusinessPath() {
 		return businessPath;
 	}
@@ -158,6 +192,7 @@ public class InfoMessageImpl implements InfoMessage, CreateInfo, Persistable {
 		this.businessPath = businessPath;
 	}
 
+	@Override
 	public Identity getAuthor() {
 		return author;
 	}
@@ -166,14 +201,17 @@ public class InfoMessageImpl implements InfoMessage, CreateInfo, Persistable {
 		this.author = author;
 	}
 
+	@Override
 	public Identity getModifier() {
 		return modifier;
 	}
 
+	@Override
 	public void setModifier(Identity modifier) {
 		this.modifier = modifier;
 	}
 
+	@Override
 	public OLATResourceable getOLATResourceable() {
 		final String name = resName;
 		final Long id = resId;
@@ -210,15 +248,4 @@ public class InfoMessageImpl implements InfoMessage, CreateInfo, Persistable {
 	public boolean equalsByPersistableKey(Persistable persistable) {
 		return equals(persistable);
 	}
-
-	@Override
-	public Long getKey() {
-		return key;
-	}
-
-	
-	@Override
-	public Date getCreationDate() {
-		return creationDate;
-	}
 }
diff --git a/src/main/java/org/olat/commons/info/notification/InfoMessageNotificationHandler.java b/src/main/java/org/olat/commons/info/notification/InfoMessageNotificationHandler.java
index 2c6c8baca41c00d56605cfd3cc17e201eb1f5021..4bfd1c14fc5096fb764f6d5b7dba3921068cb0d4 100644
--- a/src/main/java/org/olat/commons/info/notification/InfoMessageNotificationHandler.java
+++ b/src/main/java/org/olat/commons/info/notification/InfoMessageNotificationHandler.java
@@ -24,8 +24,8 @@ import java.util.Date;
 import java.util.List;
 import java.util.Locale;
 
-import org.olat.commons.info.manager.InfoMessageManager;
-import org.olat.commons.info.model.InfoMessage;
+import org.olat.commons.info.InfoMessage;
+import org.olat.commons.info.InfoMessageManager;
 import org.olat.core.CoreSpringFactory;
 import org.olat.core.commons.services.notifications.NotificationHelper;
 import org.olat.core.commons.services.notifications.NotificationsHandler;
@@ -39,13 +39,16 @@ import org.olat.core.gui.translator.Translator;
 import org.olat.core.id.Identity;
 import org.olat.core.id.OLATResourceable;
 import org.olat.core.id.context.BusinessControlFactory;
-import org.olat.core.logging.LogDelegator;
+import org.olat.core.logging.OLog;
+import org.olat.core.logging.Tracing;
 import org.olat.core.util.Util;
 import org.olat.core.util.resource.OresHelper;
 import org.olat.group.BusinessGroup;
 import org.olat.group.BusinessGroupService;
 import org.olat.repository.RepositoryEntry;
 import org.olat.repository.RepositoryManager;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
 
 /**
  * 
@@ -56,10 +59,16 @@ import org.olat.repository.RepositoryManager;
  * Initial Date:  27 jul. 2010 <br>
  * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
  */
-public class InfoMessageNotificationHandler extends LogDelegator implements NotificationsHandler {
+@Service("org.olat.commons.info.notification.InfoMessageNotificationHandler")
+public class InfoMessageNotificationHandler implements NotificationsHandler {
+	
+	private static final OLog log = Tracing.createLoggerFor(InfoMessageNotificationHandler.class);
 
 	private static final String CSS_CLASS_ICON = "o_infomsg_icon";
 	
+	@Autowired
+	private InfoMessageManager infoMessageManager;
+	
 	@Override
 	public SubscriptionInfo createSubscriptionInfo(Subscriber subscriber, Locale locale, Date compareDate) {
 		SubscriptionInfo si = null;
@@ -96,7 +105,7 @@ public class InfoMessageNotificationHandler extends LogDelegator implements Noti
 				si = new SubscriptionInfo(subscriber.getKey(), p.getType(), new TitleItem(title, CSS_CLASS_ICON), null);
 				
 				OLATResourceable ores = OresHelper.createOLATResourceableInstance(resName, resId);
-				List<InfoMessage> infos = InfoMessageManager.getInstance().loadInfoMessageByResource(ores, resSubPath, null, compareDate, null, 0, 0);
+				List<InfoMessage> infos = infoMessageManager.loadInfoMessageByResource(ores, resSubPath, null, compareDate, null, 0, 0);
 				for(InfoMessage info:infos) {
 					Identity ident = info.getAuthor();
 					String desc = translator.translate("notifications.entry", new String[] { info.getTitle(), NotificationHelper.getFormatedName(ident) });
@@ -108,7 +117,7 @@ public class InfoMessageNotificationHandler extends LogDelegator implements Noti
 					si.addSubscriptionListItem(subListItem);
 				}
 			} catch (Exception e) {
-				logError("Unexpected exception", e);
+				log.error("Unexpected exception", e);
 				si = NotificationsManager.getInstance().getNoSubscriptionInfo();
 			}
 		} else {
diff --git a/src/main/java/org/olat/commons/info/notification/InfoSubscriptionManagerImpl.java b/src/main/java/org/olat/commons/info/notification/InfoSubscriptionManagerImpl.java
index 369d27aeb3b4c04b93873f15284fc9dffb0e3c5f..0e24fae845db538c1d1b02a7deab21b38912f68e 100644
--- a/src/main/java/org/olat/commons/info/notification/InfoSubscriptionManagerImpl.java
+++ b/src/main/java/org/olat/commons/info/notification/InfoSubscriptionManagerImpl.java
@@ -23,7 +23,8 @@ package org.olat.commons.info.notification;
 import java.util.Collections;
 import java.util.List;
 
-import org.olat.commons.info.model.InfoMessage;
+import org.olat.commons.info.InfoMessage;
+import org.olat.commons.info.InfoSubscriptionManager;
 import org.olat.core.commons.services.notifications.NotificationsManager;
 import org.olat.core.commons.services.notifications.Publisher;
 import org.olat.core.commons.services.notifications.PublisherData;
@@ -33,6 +34,8 @@ import org.olat.core.id.Identity;
 import org.olat.core.id.OLATResourceable;
 import org.olat.core.util.prefs.Preferences;
 import org.olat.core.util.resource.OresHelper;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
 
 /**
  * 
@@ -43,26 +46,13 @@ import org.olat.core.util.resource.OresHelper;
  * Initial Date:  27 jul. 2010 <br>
  * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
  */
-public class InfoSubscriptionManagerImpl extends InfoSubscriptionManager {
+@Service
+public class InfoSubscriptionManagerImpl implements InfoSubscriptionManager {
+	
+	private static final String PUBLISHER_TYPE = OresHelper.calculateTypeName(InfoMessage.class);
 
+	@Autowired
 	private NotificationsManager notificationsManager;
-	
-	private String PUBLISHER_TYPE = OresHelper.calculateTypeName(InfoMessage.class);
-	
-	/**
-	 * [used by Spring]
-	 */
-	private InfoSubscriptionManagerImpl() {
-		INSTANCE = this;
-	}
-	
-	/**
-	 * [user by Spring]
-	 * @param notificationsManager
-	 */
-	public void setNotificationsManager(NotificationsManager notificationsManager) {
-		this.notificationsManager = notificationsManager;
-	}
 
 	@Override
 	public SubscriptionContext getInfoSubscriptionContext(OLATResourceable resource, String subPath) {
diff --git a/src/main/java/org/olat/commons/info/portlet/InfoMessagePortletRunController.java b/src/main/java/org/olat/commons/info/portlet/InfoMessagePortletRunController.java
index 44293dc535dc9abad8dade68b7e8a82d1ca9df8d..1bfc7015b8698d05184a20e413b2c9c9ac0c14eb 100644
--- a/src/main/java/org/olat/commons/info/portlet/InfoMessagePortletRunController.java
+++ b/src/main/java/org/olat/commons/info/portlet/InfoMessagePortletRunController.java
@@ -28,8 +28,8 @@ import java.util.List;
 import java.util.Locale;
 
 import org.olat.NewControllerFactory;
-import org.olat.commons.info.manager.InfoMessageFrontendManager;
-import org.olat.commons.info.model.InfoMessage;
+import org.olat.commons.info.InfoMessage;
+import org.olat.commons.info.InfoMessageFrontendManager;
 import org.olat.core.commons.services.notifications.NotificationsManager;
 import org.olat.core.commons.services.notifications.SubscriptionInfo;
 import org.olat.core.commons.services.notifications.model.SubscriptionListItem;
@@ -120,9 +120,9 @@ public class InfoMessagePortletRunController extends AbstractPortletRunControlle
 
 	@Override
 	protected SortingCriteria createDefaultSortingCriteria() {
-		SortingCriteria sortingCriteria = new SortingCriteria(sortingTermsList, getDefaultMaxEntries());
-		sortingCriteria.setAscending(false);
-		return sortingCriteria;
+		SortingCriteria sortCriteria = new SortingCriteria(sortingTermsList, getDefaultMaxEntries());
+		sortCriteria.setAscending(false);
+		return sortCriteria;
 	}
 
 	@Override
diff --git a/src/main/java/org/olat/commons/info/restapi/InfoMessageVO.java b/src/main/java/org/olat/commons/info/restapi/InfoMessageVO.java
index 63bb5b12c24d53a04e9486da5a77d768c4dba007..8002ab65c9d8f88ab6bb7eb0803c3741890a7776 100644
--- a/src/main/java/org/olat/commons/info/restapi/InfoMessageVO.java
+++ b/src/main/java/org/olat/commons/info/restapi/InfoMessageVO.java
@@ -25,7 +25,7 @@ import javax.xml.bind.annotation.XmlAccessType;
 import javax.xml.bind.annotation.XmlAccessorType;
 import javax.xml.bind.annotation.XmlRootElement;
 
-import org.olat.commons.info.model.InfoMessage;
+import org.olat.commons.info.InfoMessage;
 
 
 @XmlAccessorType(XmlAccessType.FIELD)
diff --git a/src/main/java/org/olat/commons/info/restapi/InfoMessageWebService.java b/src/main/java/org/olat/commons/info/restapi/InfoMessageWebService.java
index 958b7a51d56c2f3946021de1f54bacffcd1f6d69..cf5907017c413a98c97565132fd674f78ca8710b 100644
--- a/src/main/java/org/olat/commons/info/restapi/InfoMessageWebService.java
+++ b/src/main/java/org/olat/commons/info/restapi/InfoMessageWebService.java
@@ -27,7 +27,7 @@ import javax.ws.rs.core.Context;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
 
-import org.olat.commons.info.model.InfoMessage;
+import org.olat.commons.info.InfoMessage;
 
 /**
  * 
diff --git a/src/main/java/org/olat/commons/info/restapi/InfoMessagesWebService.java b/src/main/java/org/olat/commons/info/restapi/InfoMessagesWebService.java
index 0fb513fc9e90eadf688649d9ea4f1dc3239c7dd3..27da63c69f2593851f8cd7dcae84de11610c057f 100644
--- a/src/main/java/org/olat/commons/info/restapi/InfoMessagesWebService.java
+++ b/src/main/java/org/olat/commons/info/restapi/InfoMessagesWebService.java
@@ -39,8 +39,8 @@ import javax.ws.rs.core.Response.Status;
 
 import org.olat.basesecurity.BaseSecurity;
 import org.olat.basesecurity.BaseSecurityManager;
-import org.olat.commons.info.manager.InfoMessageFrontendManager;
-import org.olat.commons.info.model.InfoMessage;
+import org.olat.commons.info.InfoMessage;
+import org.olat.commons.info.InfoMessageFrontendManager;
 import org.olat.core.CoreSpringFactory;
 import org.olat.core.gui.UserRequest;
 import org.olat.core.id.Identity;
diff --git a/src/main/java/org/olat/commons/info/ui/CreateInfoStep.java b/src/main/java/org/olat/commons/info/ui/CreateInfoStep.java
index c9eb9a331106b44a6a4de05ca3e8439d9ebf2225..02e42808380243588e621dd814ba0981c1dfe729 100644
--- a/src/main/java/org/olat/commons/info/ui/CreateInfoStep.java
+++ b/src/main/java/org/olat/commons/info/ui/CreateInfoStep.java
@@ -22,6 +22,7 @@ package org.olat.commons.info.ui;
 
 import java.util.List;
 
+import org.olat.commons.info.InfoMessage;
 import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.components.form.flexible.impl.Form;
 import org.olat.core.gui.control.WindowControl;
@@ -41,8 +42,11 @@ import org.olat.core.gui.control.generic.wizard.StepsRunContext;
  */
 public class CreateInfoStep extends BasicStep {
 	
-	public CreateInfoStep(UserRequest ureq, List<SendMailOption> options) {
+	private final InfoMessage message;
+	
+	public CreateInfoStep(UserRequest ureq, List<SendMailOption> options, InfoMessage message) {
 		super(ureq);
+		this.message = message;
 		setI18nTitleAndDescr("wizard.step0.title", "wizard.step0.description");
 		setNextStep(new SendMailStep(ureq, options));
 	}
@@ -54,6 +58,6 @@ public class CreateInfoStep extends BasicStep {
 
 	@Override
 	public StepFormController getStepController(UserRequest ureq, WindowControl wControl, StepsRunContext runContext, Form form) {
-		return new CreateInfoStepController(ureq, wControl, runContext, form);
+		return new CreateInfoStepController(ureq, wControl, runContext, form, message);
 	}
 }
diff --git a/src/main/java/org/olat/commons/info/ui/CreateInfoStepController.java b/src/main/java/org/olat/commons/info/ui/CreateInfoStepController.java
index ab8ffafcb685962b01b52dec4b72ec6032fd8752..cf626bf701cce990f283e45080da4eed7406a9b6 100644
--- a/src/main/java/org/olat/commons/info/ui/CreateInfoStepController.java
+++ b/src/main/java/org/olat/commons/info/ui/CreateInfoStepController.java
@@ -20,11 +20,13 @@
 
 package org.olat.commons.info.ui;
 
+import org.olat.commons.info.InfoMessage;
 import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.components.form.flexible.FormItem;
 import org.olat.core.gui.components.form.flexible.FormItemContainer;
 import org.olat.core.gui.components.form.flexible.impl.Form;
 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.gui.control.generic.wizard.StepFormBasicController;
 import org.olat.core.gui.control.generic.wizard.StepsEvent;
@@ -42,27 +44,26 @@ import org.olat.core.gui.control.generic.wizard.StepsRunContext;
 public class CreateInfoStepController extends StepFormBasicController {
 	
 	private final StepsRunContext runContext;
-	private final InfoEditFormController infoEditFormController;
+	private final InfoEditFormController editForm;
 	
-	public CreateInfoStepController(UserRequest ureq, WindowControl wControl, StepsRunContext runContext, Form rootForm) {
+	public CreateInfoStepController(UserRequest ureq, WindowControl wControl, StepsRunContext runContext, Form rootForm, InfoMessage message) {
 		super(ureq, wControl, rootForm, runContext, LAYOUT_VERTICAL, null);
 		
 		this.runContext = runContext;
-		
-		infoEditFormController = new InfoEditFormController(ureq, wControl, rootForm, true);
-		listenTo(infoEditFormController);
+		editForm = new InfoEditFormController(ureq, wControl, rootForm, true, message);
+		listenTo(editForm);
 		
 		initForm(ureq);
 	}
 	
 	@Override
 	public FormItem getStepFormItem() {
-		return infoEditFormController.getInitialFormItem();
+		return editForm.getInitialFormItem();
 	}
 
 	@Override
 	protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
-		formLayout.add(infoEditFormController.getInitialFormItem());
+		formLayout.add(editForm.getInitialFormItem());
 	}
 
 	@Override
@@ -70,15 +71,25 @@ public class CreateInfoStepController extends StepFormBasicController {
 		//
 	}
 
+	@Override
+	public void event(UserRequest ureq, Controller source, Event event) {
+		if(source == editForm) {
+			if(event == Event.CHANGED_EVENT) {
+				runContext.put(WizardConstants.PATH_TO_DELETE, editForm.getAttachmentPathToDelete());
+			}
+		}
+		super.event(ureq, source, event);
+	}
+
 	@Override
 	protected boolean validateFormLogic(UserRequest ureq) {
-		return infoEditFormController.validateFormLogic(ureq);
+		return editForm.validateFormLogic(ureq);
 	}
 
 	@Override
 	protected void formOK(UserRequest ureq) {
-		runContext.put(WizardConstants.MSG_TITLE, infoEditFormController.getTitle());
-		runContext.put(WizardConstants.MSG_MESSAGE, infoEditFormController.getMessage());
+		runContext.put(WizardConstants.MSG, editForm.getInfoMessage());
+		runContext.put(WizardConstants.PATH_TO_DELETE, editForm.getAttachmentPathToDelete());
 		fireEvent(ureq, StepsEvent.ACTIVATE_NEXT);
 	}
 }
diff --git a/src/main/java/org/olat/commons/info/ui/InfoDisplayController.java b/src/main/java/org/olat/commons/info/ui/InfoDisplayController.java
index efb93bb893293c52ffa2806dd6fd2ce3b6b8344d..7b5baf0fb7173936eac77c73573314288984fd1b 100644
--- a/src/main/java/org/olat/commons/info/ui/InfoDisplayController.java
+++ b/src/main/java/org/olat/commons/info/ui/InfoDisplayController.java
@@ -22,14 +22,21 @@ package org.olat.commons.info.ui;
 
 import java.util.ArrayList;
 import java.util.Calendar;
+import java.util.Collection;
 import java.util.Date;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 
-import org.olat.commons.info.manager.InfoMessageFrontendManager;
+import javax.servlet.http.HttpServletRequest;
+
+import org.olat.commons.info.InfoMessage;
+import org.olat.commons.info.InfoMessageFrontendManager;
 import org.olat.commons.info.manager.MailFormatter;
-import org.olat.commons.info.model.InfoMessage;
-import org.olat.core.CoreSpringFactory;
+import org.olat.core.commons.modules.bc.meta.MetaInfo;
+import org.olat.core.commons.modules.bc.meta.tagged.MetaTagged;
+import org.olat.core.dispatcher.mapper.Mapper;
 import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.components.date.DateComponentFactory;
 import org.olat.core.gui.components.date.DateElement;
@@ -38,6 +45,7 @@ import org.olat.core.gui.components.form.flexible.FormItemContainer;
 import org.olat.core.gui.components.form.flexible.elements.FormLink;
 import org.olat.core.gui.components.form.flexible.impl.FormBasicController;
 import org.olat.core.gui.components.form.flexible.impl.FormEvent;
+import org.olat.core.gui.components.form.flexible.impl.FormLayoutContainer;
 import org.olat.core.gui.components.link.Link;
 import org.olat.core.gui.control.Controller;
 import org.olat.core.gui.control.Event;
@@ -49,6 +57,8 @@ import org.olat.core.gui.control.generic.wizard.Step;
 import org.olat.core.gui.control.generic.wizard.StepRunnerCallback;
 import org.olat.core.gui.control.generic.wizard.StepsMainRunController;
 import org.olat.core.gui.control.generic.wizard.StepsRunContext;
+import org.olat.core.gui.media.MediaResource;
+import org.olat.core.gui.media.NotFoundMediaResource;
 import org.olat.core.id.Identity;
 import org.olat.core.id.OLATResourceable;
 import org.olat.core.id.User;
@@ -62,11 +72,14 @@ import org.olat.core.util.StringHelper;
 import org.olat.core.util.coordinate.CoordinatorManager;
 import org.olat.core.util.coordinate.LockResult;
 import org.olat.core.util.resource.OresHelper;
+import org.olat.core.util.vfs.VFSLeaf;
+import org.olat.core.util.vfs.VFSMediaResource;
 import org.olat.course.nodes.info.InfoCourseNodeConfiguration;
 import org.olat.group.BusinessGroup;
 import org.olat.modules.ModuleConfiguration;
 import org.olat.user.UserManager;
 import org.olat.util.logging.activity.LoggingResourceable;
+import org.springframework.beans.factory.annotation.Autowired;
 
 /**
  * 
@@ -95,6 +108,9 @@ public class InfoDisplayController extends FormBasicController {
 	private final OLATResourceable ores;
 	private final String resSubPath;
 	private final String businessPath;
+	private final String thumbnailMapper;
+	private final String attachmentMapper;
+	private Map<Long,VFSLeaf> infoKeyToAttachment;
 	
 	private int maxResults = 0;
 	private int maxResultsConfig = 0;
@@ -102,24 +118,26 @@ public class InfoDisplayController extends FormBasicController {
 	private Date after = null;
 	private Date afterConfig = null;
 	
-	private final UserManager userManager;
-	private final InfoMessageFrontendManager infoMessageManager;
+	@Autowired
+	private UserManager userManager;
+	@Autowired
+	private InfoMessageFrontendManager infoMessageManager;
 	
 	private LockResult lockEntry;
 	private MailFormatter sendMailFormatter;
-	private List<SendMailOption> sendMailOptions = new ArrayList<SendMailOption>();
+	private List<SendMailOption> sendMailOptions = new ArrayList<>();
 	
 	public InfoDisplayController(UserRequest ureq, WindowControl wControl, InfoSecurityCallback secCallback,
 			BusinessGroup businessGroup, String resSubPath, String businessPath) {
 		super(ureq, wControl, "display");
-		userManager = CoreSpringFactory.getImpl(UserManager.class);
-		infoMessageManager = CoreSpringFactory.getImpl(InfoMessageFrontendManager.class);
 		this.secCallback = secCallback;
 		this.ores = businessGroup.getResource();
 		this.resSubPath = resSubPath;
 		this.businessPath = businessPath;
 		// default show 10 messages for groups
 		maxResults = maxResultsConfig = 10;
+		thumbnailMapper = registerCacheableMapper(ureq, "InfoMessagesThumbnail", new ThumbnailMapper());
+		attachmentMapper = registerCacheableMapper(ureq, "InfoMessages", new AttachmentMapper());
 		
 		initForm(ureq);	
 		
@@ -135,10 +153,10 @@ public class InfoDisplayController extends FormBasicController {
 		this.resSubPath = resSubPath;
 		this.businessPath = businessPath;
 		
-		userManager = CoreSpringFactory.getImpl(UserManager.class);
-		infoMessageManager = CoreSpringFactory.getImpl(InfoMessageFrontendManager.class);
 		maxResults = maxResultsConfig = getConfigValue(config, InfoCourseNodeConfiguration.CONFIG_LENGTH, 10);
 		duration = getConfigValue(config, InfoCourseNodeConfiguration.CONFIG_DURATION, 90);
+		thumbnailMapper = registerCacheableMapper(ureq, "InfoMessagesThumbnail", new ThumbnailMapper());
+		attachmentMapper = registerCacheableMapper(ureq, "InfoMessages", new AttachmentMapper());
 		
 		if(duration > 0) {
 			Calendar cal = Calendar.getInstance();
@@ -182,7 +200,7 @@ public class InfoDisplayController extends FormBasicController {
 	}
 	
 	public List<SendMailOption> getSendMailOptions() {
-		return this.sendMailOptions;
+		return sendMailOptions;
 	}
 	
 	public void addSendMailOptions(SendMailOption sendMailOption) {
@@ -217,9 +235,14 @@ public class InfoDisplayController extends FormBasicController {
 
 		List<InfoMessage> msgs = infoMessageManager.loadInfoMessageByResource(ores, resSubPath, businessPath, after, null, 0, maxResults);
 		List<InfoMessageForDisplay> infoDisplays = new ArrayList<>(msgs.size());
+		Map<Long,VFSLeaf> keyToDisplay = new HashMap<>();
 		for(InfoMessage info:msgs) {
 			previousDisplayKeys.add(info.getKey());
-			infoDisplays.add(createInfoMessageForDisplay(info));
+			InfoMessageForDisplay infoDisplay = createInfoMessageForDisplay(info);
+			infoDisplays.add(infoDisplay);
+			if(infoDisplay.getAttachment() != null) {
+				keyToDisplay.put(info.getKey(), infoDisplay.getAttachment());
+			}
 			
 			String dateCmpName = "info.date." + info.getKey();
 			DateElement dateEl = DateComponentFactory.createDateElementWithYear(dateCmpName, info.getCreationDate());
@@ -243,6 +266,7 @@ public class InfoDisplayController extends FormBasicController {
 			}
 		}
 		flc.contextPut("infos", infoDisplays);
+		infoKeyToAttachment = keyToDisplay;
 
 		int numOfInfos = infoMessageManager.countInfoMessageByResource(ores, resSubPath, businessPath, null, null);
 		oldMsgsLink.setVisible((msgs.size() < numOfInfos));
@@ -275,9 +299,9 @@ public class InfoDisplayController extends FormBasicController {
 			infos = translate("display.info.noauthor", new String[]{creationDate});
 		} else {
 			infos = translate("display.info", new String[]{StringHelper.escapeHtml(authorName), creationDate});
-		}		
-
-		return new InfoMessageForDisplay(info.getKey(), info.getTitle(), message, infos, modifier);
+		}
+		VFSLeaf attachment = infoMessageManager.getAttachment(info);
+		return new InfoMessageForDisplay(info.getKey(), info.getTitle(), message, attachment, infos, modifier);
 	}
 	
 	@Override
@@ -291,6 +315,12 @@ public class InfoDisplayController extends FormBasicController {
 		oldMsgsLink.setElementCssClass("o_sel_course_info_old_msgs");
 		newMsgsLink = uifactory.addFormLink("display.new_messages", "display.new_messages", "display.new_messages", formLayout, Link.BUTTON);
 		newMsgsLink.setElementCssClass("o_sel_course_info_new_msgs");
+		
+		if(formLayout instanceof FormLayoutContainer) {
+			FormLayoutContainer layoutCont = (FormLayoutContainer)formLayout;
+			layoutCont.contextPut("thumbnailMapper", thumbnailMapper);
+			layoutCont.contextPut("attachmentMapper", attachmentMapper);
+		}
 	}
 	
 	@Override
@@ -356,7 +386,8 @@ public class InfoDisplayController extends FormBasicController {
 	@Override
 	protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) {
 		if(source == newInfoLink) {
-			start = new CreateInfoStep(ureq, sendMailOptions);
+			InfoMessage msg = infoMessageManager.createInfoMessage(ores, resSubPath, businessPath, getIdentity());
+			start = new CreateInfoStep(ureq, sendMailOptions, msg);
 			newInfoWizard = new StepsMainRunController(ureq, getWindowControl(), start, new FinishedCallback(),
 					new CancelCallback(), translate("create_message"), "o_sel_info_messages_create_wizard");
 			listenTo(newInfoWizard);
@@ -380,6 +411,11 @@ public class InfoDisplayController extends FormBasicController {
 		}
 	}
 	
+	@Override
+	protected void propagateDirtinessToContainer(FormItem fiSrc, FormEvent fe) {
+		//nothing to do
+	}
+	
 	protected void popupDelete(UserRequest ureq, InfoMessage msg) {
 		OLATResourceable mres = OresHelper.createOLATResourceableInstance(InfoMessage.class, msg.getKey());
 		lockEntry = CoordinatorManager.getInstance().getCoordinator().getLocker().acquireLock(mres, ureq.getIdentity(), "");
@@ -435,16 +471,13 @@ public class InfoDisplayController extends FormBasicController {
 		@Override
 		public Step execute(UserRequest ureq, WindowControl wControl, StepsRunContext runContext) {
 			
-			String title = (String)runContext.get(WizardConstants.MSG_TITLE);
-			String message = (String)runContext.get(WizardConstants.MSG_MESSAGE);
+			InfoMessage msg = (InfoMessage)runContext.get(WizardConstants.MSG);
 			@SuppressWarnings("unchecked")
 			Set<String> selectedOptions = (Set<String>)runContext.get(WizardConstants.SEND_MAIL);
-			
-			InfoMessage msg = infoMessageManager.createInfoMessage(ores, resSubPath, businessPath, ureq.getIdentity());
-			msg.setTitle(title);
-			msg.setMessage(message);
-			
-			List<Identity> identities = new ArrayList<Identity>();
+			@SuppressWarnings("unchecked")
+			Collection<String> pathToDelete = (Set<String>)runContext.get(WizardConstants.PATH_TO_DELETE);
+
+			List<Identity> identities = new ArrayList<>();
 			for(SendMailOption option:sendMailOptions) {
 				if(selectedOptions != null && selectedOptions.contains(option.getOptionKey())) {
 					identities.addAll(option.getSelectedIdentities());
@@ -452,6 +485,7 @@ public class InfoDisplayController extends FormBasicController {
 			}
 			
 			infoMessageManager.sendInfoMessage(msg, sendMailFormatter, ureq.getLocale(), ureq.getIdentity(), identities);
+			infoMessageManager.deleteAttachments(pathToDelete);
 			
 			ThreadLocalUserActivityLogger.log(CourseLoggingAction.INFO_MESSAGE_CREATED, getClass(),
 					LoggingResourceable.wrap(msg.getOLATResourceable(), OlatResourceableType.infoMessage));
@@ -463,7 +497,63 @@ public class InfoDisplayController extends FormBasicController {
 	protected class CancelCallback implements StepRunnerCallback {
 		@Override
 		public Step execute(UserRequest ureq, WindowControl wControl, StepsRunContext runContext) {
+			@SuppressWarnings("unchecked")
+			Collection<String> pathToDelete = (Set<String>)runContext.get(WizardConstants.PATH_TO_DELETE);
+			infoMessageManager.deleteAttachments(pathToDelete);
 			return Step.NOSTEP;
 		}
 	}
+	
+	private class AttachmentMapper implements Mapper {
+		@Override
+		public MediaResource handle(String relPath, HttpServletRequest request) {
+			if(infoKeyToAttachment == null) {
+				return new NotFoundMediaResource(relPath);
+			}
+			
+			String[] query = relPath.split("/");
+			if(query.length > 1) {
+				try {
+					Long infoKey = Long.valueOf(Long.parseLong(query[1]));
+					VFSLeaf attachment = infoKeyToAttachment.get(infoKey);
+					return new VFSMediaResource(attachment);	
+				} catch (NumberFormatException e) {
+					//ignore them
+				}
+			}
+			return new NotFoundMediaResource(relPath);
+		}
+	}
+	
+	private class ThumbnailMapper implements Mapper {
+		@Override
+		public MediaResource handle(String relPath, HttpServletRequest request) {
+			if(infoKeyToAttachment == null) {
+				return new NotFoundMediaResource(relPath);
+			}
+			
+			String[] query = relPath.split("/");
+			if(query.length > 2) {
+				try {
+					Long infoKey = Long.valueOf(Long.parseLong(query[1]));
+					VFSLeaf attachment = infoKeyToAttachment.get(infoKey);
+					if(attachment != null) {
+						MetaInfo meta = ((MetaTagged)attachment).getMetaInfo();
+						if (meta.getUUID().equals(query[2])) {
+							if (meta.isThumbnailAvailable()) {
+								VFSLeaf thumb = meta.getThumbnail(200, 200, false);
+								if(thumb != null) {
+									// Positive lookup, send as response
+									return new VFSMediaResource(thumb);
+								}
+							}
+						}
+					}	
+				} catch (NumberFormatException e) {
+					//ignore them
+				}
+			}
+			return new NotFoundMediaResource(relPath);
+		}
+	}
 }
diff --git a/src/main/java/org/olat/commons/info/ui/InfoDisplayHelper.java b/src/main/java/org/olat/commons/info/ui/InfoDisplayHelper.java
index 59872431cbbbeb2815cc85020b2a30c188db1d12..7df8af9f57cb5a5ecd33ae78faaf4b502f15ae77 100644
--- a/src/main/java/org/olat/commons/info/ui/InfoDisplayHelper.java
+++ b/src/main/java/org/olat/commons/info/ui/InfoDisplayHelper.java
@@ -20,7 +20,7 @@
 
 package org.olat.commons.info.ui;
 
-import org.olat.commons.info.model.InfoMessage;
+import org.olat.commons.info.InfoMessage;
 import org.olat.core.gui.translator.Translator;
 import org.olat.core.id.User;
 import org.olat.core.id.UserConstants;
diff --git a/src/main/java/org/olat/commons/info/ui/InfoEditController.java b/src/main/java/org/olat/commons/info/ui/InfoEditController.java
index b98ef00262bebaa7f4a6597e74ab97fd0a8ad8ab..bdc3164787e4c0f50ea5472562ff9d786ff992b8 100644
--- a/src/main/java/org/olat/commons/info/ui/InfoEditController.java
+++ b/src/main/java/org/olat/commons/info/ui/InfoEditController.java
@@ -20,11 +20,11 @@
 
 package org.olat.commons.info.ui;
 
+import java.util.Collection;
 import java.util.Date;
 
-import org.olat.commons.info.manager.InfoMessageFrontendManager;
-import org.olat.commons.info.model.InfoMessage;
-import org.olat.core.CoreSpringFactory;
+import org.olat.commons.info.InfoMessage;
+import org.olat.commons.info.InfoMessageFrontendManager;
 import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.components.form.flexible.FormItemContainer;
 import org.olat.core.gui.components.form.flexible.impl.FormBasicController;
@@ -36,11 +36,9 @@ import org.olat.core.logging.activity.CourseLoggingAction;
 import org.olat.core.logging.activity.OlatResourceableType;
 import org.olat.core.logging.activity.ThreadLocalUserActivityLogger;
 import org.olat.util.logging.activity.LoggingResourceable;
+import org.springframework.beans.factory.annotation.Autowired;
 
 /**
- * 
- * Description:<br>
- * TODO: srosse Class Description for InfoEditController
  * 
  * <P>
  * Initial Date:  24 aug. 2010 <br>
@@ -48,33 +46,29 @@ import org.olat.util.logging.activity.LoggingResourceable;
  */
 public class InfoEditController extends FormBasicController {
 	
-	private final InfoMessage messageToEdit;
+	private InfoMessage messageToEdit;
 	private final InfoEditFormController editForm;
-	private final InfoMessageFrontendManager infoFrontendManager;
+	
+	@Autowired
+	private InfoMessageFrontendManager infoFrontendManager;
 
 	public InfoEditController(UserRequest ureq, WindowControl wControl, InfoMessage messageToEdit) {
 		super(ureq, wControl, "edit");
-		
 		this.messageToEdit = messageToEdit;
-		infoFrontendManager = CoreSpringFactory.getImpl(InfoMessageFrontendManager.class);
-		editForm = new InfoEditFormController(ureq, wControl, mainForm, false);
-		editForm.setTitle(messageToEdit.getTitle());
-		editForm.setMessage(messageToEdit.getMessage());
+		editForm = new InfoEditFormController(ureq, wControl, mainForm, false, messageToEdit);
 		listenTo(editForm);
-		
 		initForm(ureq);
 	}
 
 	@Override
 	protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
 		FormLayoutContainer editCont = editForm.getInitialFormItem();
+		flc.add("edit", editCont);
 
 		final FormLayoutContainer buttonLayout = FormLayoutContainer.createButtonLayout("button_layout", getTranslator());
 		editCont.add(buttonLayout);
 		uifactory.addFormSubmitButton("submit", buttonLayout);
 		uifactory.addFormCancelButton("cancel", buttonLayout, ureq, getWindowControl());
-		
-		flc.add("edit", editCont);
 	}
 	
 	@Override
@@ -89,14 +83,13 @@ public class InfoEditController extends FormBasicController {
 
 	@Override
 	protected void formOK(UserRequest ureq) {
-		String title = editForm.getTitle();
-		String message = editForm.getMessage();
-		
-		messageToEdit.setTitle(title);
-		messageToEdit.setMessage(message);
+		messageToEdit = editForm.getInfoMessage();
 		messageToEdit.setModificationDate(new Date());
 		messageToEdit.setModifier(getIdentity());
-		infoFrontendManager.sendInfoMessage(messageToEdit, null, null, ureq.getIdentity(), null);
+		infoFrontendManager.sendInfoMessage(messageToEdit, null, null, getIdentity(), null);
+		
+		Collection<String> pathToDelete = editForm.getAttachmentPathToDelete();
+		infoFrontendManager.deleteAttachments(pathToDelete);
 		
 		ThreadLocalUserActivityLogger.log(CourseLoggingAction.INFO_MESSAGE_UPDATED, getClass(),
 				LoggingResourceable.wrap(messageToEdit.getOLATResourceable(), OlatResourceableType.infoMessage));
diff --git a/src/main/java/org/olat/commons/info/ui/InfoEditFormController.java b/src/main/java/org/olat/commons/info/ui/InfoEditFormController.java
index fbddbb7bc80014255935a8e70839ecf5b4b59359..a969747bd308ea3c81785c5ad5e235d6f7d6b67f 100644
--- a/src/main/java/org/olat/commons/info/ui/InfoEditFormController.java
+++ b/src/main/java/org/olat/commons/info/ui/InfoEditFormController.java
@@ -20,16 +20,31 @@
 
 package org.olat.commons.info.ui;
 
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.olat.commons.info.InfoMessage;
+import org.olat.commons.info.InfoMessageFrontendManager;
 import org.olat.core.gui.UserRequest;
+import org.olat.core.gui.components.form.flexible.FormItem;
 import org.olat.core.gui.components.form.flexible.FormItemContainer;
+import org.olat.core.gui.components.form.flexible.elements.FileElement;
 import org.olat.core.gui.components.form.flexible.elements.RichTextElement;
 import org.olat.core.gui.components.form.flexible.elements.TextElement;
 import org.olat.core.gui.components.form.flexible.impl.Form;
 import org.olat.core.gui.components.form.flexible.impl.FormBasicController;
+import org.olat.core.gui.components.form.flexible.impl.FormEvent;
 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.StringHelper;
+import org.olat.core.util.ValidationStatus;
+import org.springframework.beans.factory.annotation.Autowired;
 
 /**
  * 
@@ -41,13 +56,23 @@ import org.olat.core.util.StringHelper;
  */
 public class InfoEditFormController extends FormBasicController {
 
-	private TextElement title;
-	private RichTextElement message;
+	private TextElement titleEl;
+	private FileElement attachmentEl;
+	private RichTextElement messageEl;
+	
+	private String attachmentPath;
+	private Set<String> attachmentPathToDelete = new HashSet<>();
+	
 	private final boolean showTitle;
+	private final InfoMessage infoMessage;
+	
+	@Autowired
+	private InfoMessageFrontendManager infoMessageFrontendManager;
 	
-	public InfoEditFormController(UserRequest ureq, WindowControl wControl, Form mainForm, boolean showTitle) {
+	public InfoEditFormController(UserRequest ureq, WindowControl wControl, Form mainForm, boolean showTitle, InfoMessage infoMessage) {
 		super(ureq, wControl, LAYOUT_DEFAULT, null, mainForm);
 		this.showTitle = showTitle;
+		this.infoMessage = infoMessage;
 		initForm(ureq);
 	}
 
@@ -58,16 +83,27 @@ public class InfoEditFormController extends FormBasicController {
 			setFormTitle("edit.title");
 		}
 		
-		title = uifactory.addTextElement("info_title", "edit.info_title", 512, "", formLayout);
-		title.setElementCssClass("o_sel_info_title");
-		title.setMandatory(true);
-		
-		message = uifactory.addRichTextElementForStringDataMinimalistic("edit.info_message", "edit.info_message", "", 6, 80,
+		String title = infoMessage.getTitle();
+		titleEl = uifactory.addTextElement("info_title", "edit.info_title", 512, title, formLayout);
+		titleEl.setElementCssClass("o_sel_info_title");
+		titleEl.setMandatory(true);
+
+		String message = infoMessage.getMessage();
+		messageEl = uifactory.addRichTextElementForStringDataMinimalistic("edit.info_message", "edit.info_message", message, 6, 80,
 				formLayout, getWindowControl());
-		message.getEditorConfiguration().setRelativeUrls(false);
-		message.getEditorConfiguration().setRemoveScriptHost(false);
-		message.setMandatory(true);
-		message.setMaxLength(2000);
+		messageEl.getEditorConfiguration().setRelativeUrls(false);
+		messageEl.getEditorConfiguration().setRemoveScriptHost(false);
+		messageEl.setMandatory(true);
+		messageEl.setMaxLength(2000);
+		
+		attachmentEl = uifactory.addFileElement(getWindowControl(), "attachment", formLayout);
+		attachmentEl.setDeleteEnabled(true);
+		attachmentEl.setMaxUploadSizeKB(5000, "attachment.max.size", new String[] { "5000" });
+		attachmentEl.addActionListener(FormEvent.ONCHANGE);
+		if(infoMessage.getAttachmentPath() != null) {
+			attachmentPath = infoMessage.getAttachmentPath();
+			attachmentPathToDelete.add(infoMessage.getAttachmentPath());
+		}
 	}
 	
 	@Override
@@ -75,54 +111,76 @@ public class InfoEditFormController extends FormBasicController {
 		//
 	}
 	
-	public String getTitle() {
-		return title.getValue();
-	}
-	
-	public void setTitle(String titleStr) {
-		title.setValue(titleStr);
-	}
-	
-	public String getMessage() {
-		return message.getValue();
-	}
-	
-	public void setMessage(String messageStr) {
-		message.setValue(messageStr);
-	}
-	
 	@Override
 	protected void formOK(UserRequest ureq) {
 		//
 	}
 	
+	@Override
+	protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) {
+		if(attachmentEl == source) {
+			if (attachmentEl.isUploadSuccess()) {
+				File uploadedFile = attachmentEl.getUploadFile();
+				String uploadedFilename = attachmentEl.getUploadFileName();
+				if(attachmentPath != null) {
+					attachmentPathToDelete.add(attachmentPath);
+				}
+				attachmentPath = infoMessageFrontendManager.storeAttachment(uploadedFile, uploadedFilename, infoMessage.getOLATResourceable(), infoMessage.getResSubPath());
+			} else {
+				attachmentPathToDelete.add(attachmentPath);
+			}
+			this.fireEvent(ureq, Event.CHANGED_EVENT);
+		}
+		super.formInnerEvent(ureq, source, event);
+	}
+
 	@Override
 	protected boolean validateFormLogic(UserRequest ureq) {
-		title.clearError();
-		message.clearError();
+		titleEl.clearError();
+		messageEl.clearError();
 		boolean allOk = true;
 		
-		String t = title.getValue();
+		String t = titleEl.getValue();
 		if(!StringHelper.containsNonWhitespace(t)) {
-			title.setErrorKey("form.legende.mandatory", new String[] {});
+			titleEl.setErrorKey("form.legende.mandatory", new String[] {});
 			allOk = false;
 		} else if (t.length() > 500) {
-			title.setErrorKey("input.toolong", new String[] {"500", Integer.toString(t.length())});
+			titleEl.setErrorKey("input.toolong", new String[] {"500", Integer.toString(t.length())});
 			allOk = false;
 		}
 		
-		String m = message.getValue();
+		String m = messageEl.getValue();
 		if(!StringHelper.containsNonWhitespace(m)) {
-			message.setErrorKey("form.legende.mandatory", new String[] {});
+			messageEl.setErrorKey("form.legende.mandatory", new String[] {});
 			allOk = false;
 		} else if (m.length() > 2000) {
-			message.setErrorKey("input.toolong", new String[] {"2000", Integer.toString(m.length())});
+			messageEl.setErrorKey("input.toolong", new String[] {"2000", Integer.toString(m.length())});
 			allOk = false;
 		}
 		
-		return allOk && super.validateFormLogic(ureq);
+		List<ValidationStatus> validation = new ArrayList<>();
+		attachmentEl.validate(validation);
+		if(validation.size() > 0) {
+			allOk &= false;
+		}
+		return allOk & super.validateFormLogic(ureq);
+	}
+	
+	public InfoMessage getInfoMessage() {
+		infoMessage.setTitle(titleEl.getValue());
+		infoMessage.setMessage(messageEl.getValue());
+		infoMessage.setAttachmentPath(attachmentPath);
+		return infoMessage;
+	}
+	
+	public Collection<String> getAttachmentPathToDelete() {
+		if(attachmentPath != null) {
+			attachmentPathToDelete.remove(attachmentPath);
+		}
+		return attachmentPathToDelete;	
 	}
 
+	@Override
 	public FormLayoutContainer getInitialFormItem() {
 		return flc;
 	}
diff --git a/src/main/java/org/olat/commons/info/ui/InfoMessageForDisplay.java b/src/main/java/org/olat/commons/info/ui/InfoMessageForDisplay.java
index 1aa3d4f550ea1e72af9be2c9710238c045d12157..bcf541804c0c2eabbac6b4a90e6b70a8f1643492 100644
--- a/src/main/java/org/olat/commons/info/ui/InfoMessageForDisplay.java
+++ b/src/main/java/org/olat/commons/info/ui/InfoMessageForDisplay.java
@@ -21,6 +21,7 @@
 package org.olat.commons.info.ui;
 
 import org.olat.core.util.StringHelper;
+import org.olat.core.util.vfs.VFSLeaf;
 
 /**
  * 
@@ -38,13 +39,15 @@ public class InfoMessageForDisplay {
 	private final String message;
 	private final String infos;
 	private final String modifier;
+	private final VFSLeaf attachment;
 	
-	public InfoMessageForDisplay(Long key, String title, String message, String infos, String modifier) {
+	public InfoMessageForDisplay(Long key, String title, String message, VFSLeaf attachment, String infos, String modifier) {
 		this.key = key;
 		this.title = title;
 		this.infos = infos;
 		this.message = message;
 		this.modifier = modifier;
+		this.attachment = attachment;
 	}
 
 	public Long getKey() {
@@ -62,6 +65,10 @@ public class InfoMessageForDisplay {
 	public String getInfos() {
 		return infos;
 	}
+	
+	public VFSLeaf getAttachment() {
+		return attachment;
+	}
 
 	public boolean isModified() {
 		return StringHelper.containsNonWhitespace(modifier);
diff --git a/src/main/java/org/olat/commons/info/ui/InfoSecurityCallback.java b/src/main/java/org/olat/commons/info/ui/InfoSecurityCallback.java
index 562bed7e944b662618d4aa5557c757c60db2ce52..60d725499329bb2ec456b4210320f18332ad8bb9 100644
--- a/src/main/java/org/olat/commons/info/ui/InfoSecurityCallback.java
+++ b/src/main/java/org/olat/commons/info/ui/InfoSecurityCallback.java
@@ -20,7 +20,7 @@
 
 package org.olat.commons.info.ui;
 
-import org.olat.commons.info.model.InfoMessage;
+import org.olat.commons.info.InfoMessage;
 
 /**
  * 
diff --git a/src/main/java/org/olat/commons/info/ui/SendInfoMailFormatter.java b/src/main/java/org/olat/commons/info/ui/SendInfoMailFormatter.java
index edff133c6db5e5b50c675f49f07eb65ae914c1b2..b4fd472a2b01eea9d42f939fd685f85842fd2ce9 100644
--- a/src/main/java/org/olat/commons/info/ui/SendInfoMailFormatter.java
+++ b/src/main/java/org/olat/commons/info/ui/SendInfoMailFormatter.java
@@ -24,8 +24,8 @@ package org.olat.commons.info.ui;
 import java.text.DateFormat;
 import java.util.List;
 
+import org.olat.commons.info.InfoMessage;
 import org.olat.commons.info.manager.MailFormatter;
-import org.olat.commons.info.model.InfoMessage;
 import org.olat.core.gui.translator.Translator;
 import org.olat.core.helpers.Settings;
 import org.olat.core.id.UserConstants;
diff --git a/src/main/java/org/olat/commons/info/ui/SendMailOption.java b/src/main/java/org/olat/commons/info/ui/SendMailOption.java
index 4554d99b074b149500fb91ea32b5800beab6a556..c919d6f93fa7d5103eb74ac57e9f803af03390e4 100644
--- a/src/main/java/org/olat/commons/info/ui/SendMailOption.java
+++ b/src/main/java/org/olat/commons/info/ui/SendMailOption.java
@@ -21,7 +21,6 @@
 package org.olat.commons.info.ui;
 
 import java.util.List;
-import java.util.Locale;
 
 import org.olat.core.id.Identity;
 
@@ -37,7 +36,7 @@ public interface SendMailOption {
 	
 	public String getOptionKey();
 	
-	public String getOptionTranslatedName(Locale locale);
+	public String getOptionName();
 	
 	public List<Identity> getSelectedIdentities();
 
diff --git a/src/main/java/org/olat/commons/info/ui/SendMailStepController.java b/src/main/java/org/olat/commons/info/ui/SendMailStepController.java
index d503830da8df3aff630921177b564b9e904c295b..628d80e39e455574d64518a07a00d2e498ae62ea 100644
--- a/src/main/java/org/olat/commons/info/ui/SendMailStepController.java
+++ b/src/main/java/org/olat/commons/info/ui/SendMailStepController.java
@@ -57,7 +57,7 @@ public class SendMailStepController extends StepFormBasicController {
 		int count = 0;
 		for(SendMailOption option:options) {
 			sendOptionKeys[count] = option.getOptionKey();
-			sendOptionValues[count++] = option.getOptionTranslatedName(ureq.getLocale());
+			sendOptionValues[count++] = option.getOptionName();
 		}
 
 		initForm(ureq);
diff --git a/src/main/java/org/olat/commons/info/ui/SendSubscriberMailOption.java b/src/main/java/org/olat/commons/info/ui/SendSubscriberMailOption.java
index 2d568e7c6a5d4a1687a9bafaed93dbf77beacd27..927c1bdd0f8e0d8f08c0c75de0f40a138f664717 100644
--- a/src/main/java/org/olat/commons/info/ui/SendSubscriberMailOption.java
+++ b/src/main/java/org/olat/commons/info/ui/SendSubscriberMailOption.java
@@ -23,8 +23,8 @@ package org.olat.commons.info.ui;
 import java.util.List;
 import java.util.Locale;
 
-import org.olat.commons.info.manager.InfoMessageFrontendManager;
-import org.olat.core.gui.translator.Translator;
+import org.olat.commons.info.InfoMessageFrontendManager;
+import org.olat.core.CoreSpringFactory;
 import org.olat.core.id.Identity;
 import org.olat.core.id.OLATResourceable;
 import org.olat.core.util.Util;
@@ -40,14 +40,15 @@ import org.olat.core.util.Util;
  */
 public class SendSubscriberMailOption implements SendMailOption {
 
-	private final OLATResourceable ores;
+	private final String label;
 	private final String resSubPath;
-	private final InfoMessageFrontendManager messageManager;
+	private final OLATResourceable ores;
 	
-	public SendSubscriberMailOption(OLATResourceable ores, String resSubPath, InfoMessageFrontendManager messageManager) {
+	public SendSubscriberMailOption(OLATResourceable ores, String resSubPath, Locale locale) {
 		this.ores = ores;
 		this.resSubPath = resSubPath;
-		this.messageManager = messageManager;
+		label = Util.createPackageTranslator(SendSubscriberMailOption.class, locale)
+				.translate("wizard.step1.send_option.subscriber");
 	}
 	
 	@Override
@@ -56,14 +57,12 @@ public class SendSubscriberMailOption implements SendMailOption {
 	}
 
 	@Override
-	public String getOptionTranslatedName(Locale locale) {
-		Translator translator = Util.createPackageTranslator(SendSubscriberMailOption.class, locale);
-		return translator.translate("wizard.step1.send_option.subscriber");
+	public String getOptionName() {
+		return label;
 	}
 
 	@Override
 	public List<Identity> getSelectedIdentities() {
-		List<Identity> identities = messageManager.getInfoSubscribers(ores, resSubPath);
-		return identities;
+		return CoreSpringFactory.getImpl(InfoMessageFrontendManager.class).getInfoSubscribers(ores, resSubPath);
 	}
 }
diff --git a/src/main/java/org/olat/commons/info/ui/WizardConstants.java b/src/main/java/org/olat/commons/info/ui/WizardConstants.java
index b0a030737781a67a252ffdebdc39dfb15bc6df56..31843c5b509697c7377dcee82e6bf43b01e3675a 100644
--- a/src/main/java/org/olat/commons/info/ui/WizardConstants.java
+++ b/src/main/java/org/olat/commons/info/ui/WizardConstants.java
@@ -21,9 +21,7 @@
 package org.olat.commons.info.ui;
 
 /**
- * 
- * Description:<br>
- * TODO: srosse Class Description for WizardConstants
+
  * 
  * <P>
  * Initial Date:  28 jul. 2010 <br>
@@ -32,11 +30,9 @@ package org.olat.commons.info.ui;
 public class WizardConstants {
 
 	public static final String SEND_MAIL = "send";
-	public static final String SEND_MAIL_ALL = "all";
-	public static final String SEND_MAIL_GROUPS = "groups";
 	public static final String SEND_MAIL_SUBSCRIBERS = "subscribers";
 	
-	public static final String MSG_TITLE = "title";
-	public static final String MSG_MESSAGE = "message";
+	public static final String MSG = "message";
+	public static final String PATH_TO_DELETE = "pathToDelete";
 	
 }
diff --git a/src/main/java/org/olat/commons/info/ui/_content/display.html b/src/main/java/org/olat/commons/info/ui/_content/display.html
index 07f554e7046853ee365991164b6b56e8131211fa..630a35bf982eb0d5a0f57739da41793280b46a72 100644
--- a/src/main/java/org/olat/commons/info/ui/_content/display.html
+++ b/src/main/java/org/olat/commons/info/ui/_content/display.html
@@ -34,6 +34,24 @@
 			</div>
 			#if($info.getMessage())
 				<div class="o_content">$info.getMessage()</div>
+			#end 
+			
+			#if($r.isNotEmpty($info.attachment))
+			<div class="o_attachment">
+				#set($attachment = $info.attachment)
+				#set($fname = $attachment.name)
+				<a href="${attachmentMapper}/$info.key/$fname" target="_blank">
+					<div class="o_filename">$r.escapeHtml($fname)</div>
+					<div class="o_size">
+						<i class="o_icon o_icon-fw $r.getFiletypeIconCss($fname)"></i>
+						 $r.formatBytes($attachment.getSize())
+					</div>
+					#if ($attachment.getMetaInfo() && $attachment.getMetaInfo().isThumbnailAvailable())										
+					<img src="${thumbnailMapper}/$info.key/$attachment.getMetaInfo().getUUID()/$fname" class="img-thumbnail" alt="$r.escapeHtml("$fname")" title="$r.escapeHtml("$fname")"/>
+					<i class="o_icon o_icon-lg o_icon_enlarge"> </i>
+					#end
+				</a>	
+			</div>
 			#end
 			#if($r.available("info.delete.${info.getKey()}") or $r.available("info.edit.${info.getKey()}"))
 				<div class="o_button_group">
diff --git a/src/main/java/org/olat/commons/info/ui/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/commons/info/ui/_i18n/LocalStrings_de.properties
index e2bdfad10a7129d6c2b87a38aaa836c2aa28d55d..0736846e8d5b9992cd833babbca2f6769ddf4489 100644
--- a/src/main/java/org/olat/commons/info/ui/_i18n/LocalStrings_de.properties
+++ b/src/main/java/org/olat/commons/info/ui/_i18n/LocalStrings_de.properties
@@ -1,6 +1,8 @@
 #Mon Mar 02 09:54:04 CET 2009
 already.deleted=Diese Mitteilung wurde inzwischen durch einen anderen Benutzer gel\u00F6scht.
 already.edited=Diese Mitteilung wird zurzeit von Benutzer {0} bearbeitet. Versuchen Sie es sp\u00E4ter noch einmal.
+attachment=Datei
+attachment.max.size=$org.olat.commons.file.filechooser\:error.limit.exceeded
 new_message=Neue Mitteilung erstellen
 create_message=Mitteilung erstellen
 input.toolong=Leider ist Ihr gerade eingegebener Text mit {1} Zeichen zu lang. Bitte beschr\u00E4nken Sie sich auf maximal {0} Zeichen.
diff --git a/src/main/java/org/olat/commons/info/ui/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/commons/info/ui/_i18n/LocalStrings_en.properties
index 59c8bee1e71063c38ae7f6f74d0452dbe904c6aa..f043d1488b2981551e90b75d38ba57493285bfa1 100644
--- a/src/main/java/org/olat/commons/info/ui/_i18n/LocalStrings_en.properties
+++ b/src/main/java/org/olat/commons/info/ui/_i18n/LocalStrings_en.properties
@@ -1,6 +1,8 @@
 #Wed Jan 05 12:37:20 CET 2011
 already.deleted=This message has been deleted in the meantime by another user.
 already.edited=This message is being edited by user {0}. Please try again later.
+attachment=File
+attachment.max.size=$org.olat.commons.file.filechooser\:error.limit.exceeded
 create_message=Create message
 display.info=Published by {0} on {1}
 display.info.noauthor=Published on {0}
diff --git a/src/main/java/org/olat/commons/info/ui/_i18n/LocalStrings_fr.properties b/src/main/java/org/olat/commons/info/ui/_i18n/LocalStrings_fr.properties
index 95cac8ebadee20cedf0c8670b23f253771bca069..2b9eebd335c1d136bc225147c9e8527e2a9b84ef 100644
--- a/src/main/java/org/olat/commons/info/ui/_i18n/LocalStrings_fr.properties
+++ b/src/main/java/org/olat/commons/info/ui/_i18n/LocalStrings_fr.properties
@@ -1,6 +1,7 @@
 #Tue Apr 04 18:37:01 CEST 2017
 already.deleted=Entretemps, cette communication a \u00E9t\u00E9 effac\u00E9 par un autre utilisateur.
 already.edited=Cette communication est actuellement en cours d'\u00E9laboration par l'utilisateur {0}. R\u00E9essayez plus tard, svp.
+attachment.max.size=$org.olat.commons.file.filechooser\:error.limit.exceeded
 create_message=Cr\u00E9er communication
 display.info=Publi\u00E9 par {0} le {1}
 display.info.noauthor=Publi\u00E9 le {0}
diff --git a/src/main/java/org/olat/core/commons/services/notifications/_spring/notificationsContext.xml b/src/main/java/org/olat/core/commons/services/notifications/_spring/notificationsContext.xml
index 932c363c47e70c9ca92fb4da5b796c27d4fb45ce..3eeefcd69a1fe89539b3235b3ef5cce9d201a7ed 100644
--- a/src/main/java/org/olat/core/commons/services/notifications/_spring/notificationsContext.xml
+++ b/src/main/java/org/olat/core/commons/services/notifications/_spring/notificationsContext.xml
@@ -14,7 +14,6 @@
 	<bean id="org.olat.course.nodes.ta.SolutionFileUploadNotificationHandler" class="org.olat.course.nodes.ta.SolutionFileUploadNotificationHandler"/>
 	<bean id="org.olat.modules.wiki.WikiPageChangeOrCreateNotificationHandler" class="org.olat.modules.wiki.WikiPageChangeOrCreateNotificationHandler" />
 	<bean id="org.olat.user.notification.NewUsersNotificationHandler" class="org.olat.user.notification.NewUsersNotificationHandler" />
-	<bean id="org.olat.commons.info.notification.InfoMessageNotificationHandler" class="org.olat.commons.info.notification.InfoMessageNotificationHandler" />
 	
 	<bean id="notificationsManager" class="org.olat.core.commons.services.notifications.manager.NotificationsManagerImpl" >
 		<property name="dbInstance" ref="database"/>
diff --git a/src/main/java/org/olat/course/nodes/InfoCourseNode.java b/src/main/java/org/olat/course/nodes/InfoCourseNode.java
index b166086cbe814796802bd32c3a11e905b7b74ea2..c32b40ad660dfe1b615baa9ac09d728b952cb3a6 100644
--- a/src/main/java/org/olat/course/nodes/InfoCourseNode.java
+++ b/src/main/java/org/olat/course/nodes/InfoCourseNode.java
@@ -23,8 +23,8 @@ package org.olat.course.nodes;
 import java.util.ArrayList;
 import java.util.List;
 
-import org.olat.commons.info.manager.InfoMessageFrontendManager;
-import org.olat.commons.info.model.InfoMessage;
+import org.olat.commons.info.InfoMessage;
+import org.olat.commons.info.InfoMessageFrontendManager;
 import org.olat.core.CoreSpringFactory;
 import org.olat.core.commons.services.notifications.NotificationsManager;
 import org.olat.core.commons.services.notifications.SubscriptionContext;
diff --git a/src/main/java/org/olat/course/nodes/info/InfoPeekViewController.java b/src/main/java/org/olat/course/nodes/info/InfoPeekViewController.java
index 8e25a60a2773be2ad6e49889a99324f0767c2835..225d0551255f4558e53fa43c0e00ccc589ad14ee 100644
--- a/src/main/java/org/olat/course/nodes/info/InfoPeekViewController.java
+++ b/src/main/java/org/olat/course/nodes/info/InfoPeekViewController.java
@@ -25,9 +25,8 @@ import java.util.List;
 import java.util.Locale;
 
 import org.apache.commons.lang.StringEscapeUtils;
-import org.olat.commons.info.manager.InfoMessageFrontendManager;
-import org.olat.commons.info.model.InfoMessage;
-import org.olat.core.CoreSpringFactory;
+import org.olat.commons.info.InfoMessage;
+import org.olat.commons.info.InfoMessageFrontendManager;
 import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.components.Component;
 import org.olat.core.gui.components.table.BaseTableDataModelWithoutFilter;
@@ -51,6 +50,7 @@ import org.olat.core.util.resource.OresHelper;
 import org.olat.course.CourseModule;
 import org.olat.course.nodes.InfoCourseNode;
 import org.olat.course.run.userview.UserCourseEnvironment;
+import org.springframework.beans.factory.annotation.Autowired;
 
 /**
  * 
@@ -67,6 +67,9 @@ public class InfoPeekViewController extends BasicController {
 	private final InfoCourseNode courseNode;
 	
 	private TableController tableController;
+	
+	@Autowired
+	private InfoMessageFrontendManager infoService;
 
 	public InfoPeekViewController(UserRequest ureq, WindowControl wControl, UserCourseEnvironment userCourseEnv, 
 			InfoCourseNode courseNode) {
@@ -96,8 +99,7 @@ public class InfoPeekViewController extends BasicController {
 		tableController.addColumnDescriptor(new CustomRenderColumnDescriptor("peekview.title", 0,
 				null, ureq.getLocale(), ColumnDescriptor.ALIGNMENT_LEFT, new InfoNodeRenderer()));
 		
-		String resSubPath = this.courseNode.getIdent();
-		InfoMessageFrontendManager infoService = CoreSpringFactory.getImpl(InfoMessageFrontendManager.class);
+		String resSubPath = courseNode.getIdent();
 		List<InfoMessage> infos = infoService.loadInfoMessageByResource(ores, resSubPath, null, null, null, 0, 5);
 
 		InfosTableModel model = new InfosTableModel(infos);
diff --git a/src/main/java/org/olat/course/nodes/info/InfoRunController.java b/src/main/java/org/olat/course/nodes/info/InfoRunController.java
index 89278a096a943f5bebb27fcde164049a837cd40d..ad828dd2404132438ea45e8b63630dddadc4637c 100644
--- a/src/main/java/org/olat/course/nodes/info/InfoRunController.java
+++ b/src/main/java/org/olat/course/nodes/info/InfoRunController.java
@@ -24,16 +24,15 @@ import java.util.ArrayList;
 import java.util.List;
 import java.util.StringTokenizer;
 
-import org.olat.commons.info.manager.InfoMessageFrontendManager;
+import org.olat.basesecurity.GroupRoles;
+import org.olat.commons.info.InfoMessage;
+import org.olat.commons.info.InfoSubscriptionManager;
 import org.olat.commons.info.manager.MailFormatter;
-import org.olat.commons.info.model.InfoMessage;
 import org.olat.commons.info.notification.InfoSubscription;
-import org.olat.commons.info.notification.InfoSubscriptionManager;
 import org.olat.commons.info.ui.InfoDisplayController;
 import org.olat.commons.info.ui.InfoSecurityCallback;
 import org.olat.commons.info.ui.SendInfoMailFormatter;
 import org.olat.commons.info.ui.SendSubscriberMailOption;
-import org.olat.core.CoreSpringFactory;
 import org.olat.core.commons.services.notifications.PublisherData;
 import org.olat.core.commons.services.notifications.SubscriptionContext;
 import org.olat.core.commons.services.notifications.ui.ContextualSubscriptionController;
@@ -56,10 +55,9 @@ import org.olat.course.groupsandrights.CourseGroupManager;
 import org.olat.course.nodes.InfoCourseNode;
 import org.olat.course.run.userview.NodeEvaluation;
 import org.olat.course.run.userview.UserCourseEnvironment;
-import org.olat.group.BusinessGroupService;
 import org.olat.modules.ModuleConfiguration;
 import org.olat.repository.RepositoryManager;
-import org.olat.repository.RepositoryService;
+import org.springframework.beans.factory.annotation.Autowired;
 
 /**
  * 
@@ -77,27 +75,28 @@ public class InfoRunController extends BasicController {
 	private ContextualSubscriptionController subscriptionController;
 	
 	private final String businessPath;
-	private final InfoCourseNode courseNode;
-	private final ModuleConfiguration config;
+	
+	@Autowired
+	private RepositoryManager repositoryManager;
+	@Autowired
 	private InfoSubscriptionManager subscriptionManager;
 
 	public InfoRunController(UserRequest ureq, WindowControl wControl, UserCourseEnvironment userCourseEnv,
 			NodeEvaluation ne, InfoCourseNode courseNode) {
 		super(ureq, wControl);
-		
-		this.courseNode = courseNode;
-		this.config = courseNode.getModuleConfiguration();
+		ModuleConfiguration config = courseNode.getModuleConfiguration();
 		
 		Long resId = userCourseEnv.getCourseEnvironment().getCourseResourceableId();
-		ICourse course = CourseFactory.loadCourse(resId);
-		String resSubPath = this.courseNode.getIdent();
+		
+		String resSubPath = courseNode.getIdent();
 		OLATResourceable infoResourceable = new InfoOLATResourceable(resId);
 		businessPath = normalizeBusinessPath(wControl.getBusinessControl().getAsString());
+		ICourse course = CourseFactory.loadCourse(resId);
+		CourseGroupManager cgm = userCourseEnv.getCourseEnvironment().getCourseGroupManager();
 		
 		//manage opt-out subscription
 		UserSession usess = ureq.getUserSession();
 		if(!usess.getRoles().isGuestOnly()) {
-			subscriptionManager = InfoSubscriptionManager.getInstance();
 			SubscriptionContext subContext = subscriptionManager.getInfoSubscriptionContext(infoResourceable, resSubPath);
 			PublisherData pdata = subscriptionManager.getInfoPublisherData(infoResourceable, businessPath);
 			if(InfoCourseNodeEditController.getAutoSubscribe(config)) {
@@ -116,28 +115,23 @@ public class InfoRunController extends BasicController {
 		} else {
 			Identity identity = getIdentity();
 			Roles roles = usess.getRoles();
-			CourseGroupManager cgm = userCourseEnv.getCourseEnvironment().getCourseGroupManager();
-			boolean institutionalManager = RepositoryManager.getInstance().isInstitutionalRessourceManagerFor(identity, roles, cgm.getCourseEntry());
-			boolean courseAdmin = cgm.isIdentityCourseAdministrator(identity);
-			
-			canAdd = courseAdmin
-				|| ne.isCapabilityAccessible(InfoCourseNode.EDIT_CONDITION_ID)
-				|| institutionalManager
-				|| roles.isOLATAdmin();
 		
-			canAdmin = courseAdmin
-				|| ne.isCapabilityAccessible(InfoCourseNode.ADMIN_CONDITION_ID)
-				|| institutionalManager
-				|| roles.isOLATAdmin();
+			boolean isAdmin = roles.isOLATAdmin()
+					|| cgm.isIdentityCourseAdministrator(identity)
+					|| repositoryManager.isInstitutionalRessourceManagerFor(identity, roles, cgm.getCourseEntry());
+			
+			canAdd = isAdmin || ne.isCapabilityAccessible(InfoCourseNode.EDIT_CONDITION_ID);
+			canAdmin = isAdmin || ne.isCapabilityAccessible(InfoCourseNode.ADMIN_CONDITION_ID);
 		}
 
 		InfoSecurityCallback secCallback = new InfoCourseSecurityCallback(getIdentity(), canAdd, canAdmin);
-		RepositoryService repositoryService = CoreSpringFactory.getImpl(RepositoryService.class);
 		
 		infoDisplayController = new InfoDisplayController(ureq, wControl, config, secCallback, infoResourceable, resSubPath, businessPath);
-		infoDisplayController.addSendMailOptions(new SendSubscriberMailOption(infoResourceable, resSubPath, CoreSpringFactory.getImpl(InfoMessageFrontendManager.class)));
-		infoDisplayController.addSendMailOptions(new SendMembersMailOption(course.getCourseEnvironment().getCourseGroupManager().getCourseResource(),
-				RepositoryManager.getInstance(), repositoryService, CoreSpringFactory.getImpl(BusinessGroupService.class)));
+		infoDisplayController.addSendMailOptions(new SendSubscriberMailOption(infoResourceable, resSubPath, getLocale()));
+		infoDisplayController.addSendMailOptions(new SendMembersMailOption(cgm.getCourseEntry(), GroupRoles.owner, translate("wizard.step1.send_option.owner")));
+		infoDisplayController.addSendMailOptions(new SendMembersMailOption(cgm.getCourseEntry(), GroupRoles.coach, translate("wizard.step1.send_option.coach")));
+		infoDisplayController.addSendMailOptions(new SendMembersMailOption(cgm.getCourseEntry(), GroupRoles.participant, translate("wizard.step1.send_option.participant")));
+
 		MailFormatter mailFormatter = new SendInfoMailFormatter(course.getCourseTitle(), businessPath, getTranslator());
 		infoDisplayController.setSendMailFormatter(mailFormatter);
 		listenTo(infoDisplayController);
diff --git a/src/main/java/org/olat/course/nodes/info/SendMembersMailOption.java b/src/main/java/org/olat/course/nodes/info/SendMembersMailOption.java
index 68045c2f53d283d06fe2772aa1bdf4732719e570..1133893d1216a5de7c9b547812e6b91857dc893a 100644
--- a/src/main/java/org/olat/course/nodes/info/SendMembersMailOption.java
+++ b/src/main/java/org/olat/course/nodes/info/SendMembersMailOption.java
@@ -23,19 +23,15 @@ package org.olat.course.nodes.info;
 import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.List;
-import java.util.Locale;
 import java.util.Set;
 
 import org.olat.basesecurity.GroupRoles;
 import org.olat.commons.info.ui.SendMailOption;
-import org.olat.core.gui.translator.Translator;
+import org.olat.core.CoreSpringFactory;
 import org.olat.core.id.Identity;
-import org.olat.core.util.Util;
 import org.olat.group.BusinessGroupService;
 import org.olat.repository.RepositoryEntry;
-import org.olat.repository.RepositoryManager;
 import org.olat.repository.RepositoryService;
-import org.olat.resource.OLATResource;
 
 /**
  * 
@@ -48,38 +44,38 @@ import org.olat.resource.OLATResource;
  */
 public class SendMembersMailOption implements SendMailOption {
 	
-	private final OLATResource courseResource;
-	private final RepositoryManager rm;
-	private final RepositoryService repositoryService;
-	private final BusinessGroupService businessGroupService;
+	private final String label;
+	private final GroupRoles role;
+	private final RepositoryEntry repositoryEntry;
 	
-	public SendMembersMailOption(OLATResource courseResource, RepositoryManager rm, RepositoryService repositoryService, BusinessGroupService businessGroupService) {
-		this.courseResource = courseResource;
-		this.rm = rm;
-		this.repositoryService = repositoryService;
-		this.businessGroupService = businessGroupService;
+	public SendMembersMailOption(RepositoryEntry repositoryEntry, GroupRoles role, String label) {
+		this.role = role;
+		this.label = label;
+		this.repositoryEntry = repositoryEntry;
 	}
 
 	@Override
 	public String getOptionKey() {
-		return "send-mail-course-members";
+		return "send-mail-course-members-" + role.name();
 	}
 
 	@Override
-	public String getOptionTranslatedName(Locale locale) {
-		Translator translator = Util.createPackageTranslator(SendMembersMailOption.class, locale);
-		return translator.translate("wizard.step1.send_option.member");
+	public String getOptionName() {
+		return label;
 	}
 
 	@Override
 	public List<Identity> getSelectedIdentities() {
-		RepositoryEntry repositoryEntry = rm.lookupRepositoryEntry(courseResource, true);
+		Set<Identity> identities = new HashSet<Identity>();
+		if(role == GroupRoles.coach || role == GroupRoles.participant) {
+			List<Identity> members = CoreSpringFactory.getImpl(BusinessGroupService.class)
+					.getMembersOf(repositoryEntry, role == GroupRoles.coach, role == GroupRoles.participant);
+			identities.addAll(members);
+		}
 		
-		List<Identity> members = businessGroupService.getMembersOf(repositoryEntry, true, true);
-		Set<Identity> identities = new HashSet<Identity>(members);
-		List<Identity> reMembers = repositoryService.getMembers(repositoryEntry, GroupRoles.participant.name(), GroupRoles.coach.name(), GroupRoles.owner.name());
+		List<Identity> reMembers = CoreSpringFactory.getImpl(RepositoryService.class)
+				.getMembers(repositoryEntry, role.name());
 		identities.addAll(reMembers);
-
-		return new ArrayList<Identity>(identities);
+		return new ArrayList<>(identities);
 	}
 }
diff --git a/src/main/java/org/olat/course/nodes/info/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/course/nodes/info/_i18n/LocalStrings_de.properties
index 365c9347c77bcd5329e6d5f615332354bf53100c..cdef6e4d18a29bfe7509796b7cf303304bde8aae 100644
--- a/src/main/java/org/olat/course/nodes/info/_i18n/LocalStrings_de.properties
+++ b/src/main/java/org/olat/course/nodes/info/_i18n/LocalStrings_de.properties
@@ -20,7 +20,9 @@ pane.tab.infos_config.auto_subscribe.on=Diese Mitteilungen bei Ansicht automatis
 peekview.title=Title
 peekview.more=mehr...
 peekview.noInfos=Keine Mitteilungen
-wizard.step1.send_option.member=Mitglieder, Gruppenbetreuer und Kursbesitzer
+wizard.step1.send_option.participant=Mitglieder
+wizard.step1.send_option.coach=Betreuer
+wizard.step1.send_option.owner=Kursbesitzer
 
 
 
diff --git a/src/main/java/org/olat/course/nodes/info/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/course/nodes/info/_i18n/LocalStrings_en.properties
index 2a82e9884e32bc9c63e5a5635d99dbc04099f79a..617278a2e9a491ca9ddf4cb6555536b439649d61 100644
--- a/src/main/java/org/olat/course/nodes/info/_i18n/LocalStrings_en.properties
+++ b/src/main/java/org/olat/course/nodes/info/_i18n/LocalStrings_en.properties
@@ -20,4 +20,6 @@ peekview.more=more...
 peekview.noInfos=No notifications
 peekview.title=Title
 title_info=Notifications
-wizard.step1.send_option.member=Members, group tutors, and course owners
+wizard.step1.send_option.participant=Participants
+wizard.step1.send_option.coach=Tutors
+wizard.step1.send_option.owner=Course owners
diff --git a/src/main/java/org/olat/course/nodes/info/_i18n/LocalStrings_fr.properties b/src/main/java/org/olat/course/nodes/info/_i18n/LocalStrings_fr.properties
index 0999a110d4980681d8d3366f95f271c14183ad93..47f5cb49fca24e507ec54a9fb127d2a3c2016670 100644
--- a/src/main/java/org/olat/course/nodes/info/_i18n/LocalStrings_fr.properties
+++ b/src/main/java/org/olat/course/nodes/info/_i18n/LocalStrings_fr.properties
@@ -20,4 +20,6 @@ peekview.more=plus...
 peekview.noInfos=Aucune communication
 peekview.title=Titre
 title_info=Communications
-wizard.step1.send_option.member=Membres, tuteurs de groupes et propri\u00E9taires de cours
+wizard.step1.send_option.participant=Participants
+wizard.step1.send_option.coach=Tuteurs
+wizard.step1.send_option.owner=Propri\u00E9taires de cours
diff --git a/src/main/java/org/olat/course/nodes/info/_i18n/LocalStrings_it.properties b/src/main/java/org/olat/course/nodes/info/_i18n/LocalStrings_it.properties
index cf86794682dea3e1dcd549ff62c5cd723d409a36..1f0a8ae15c3e2520bf5516519f81294c767c1b35 100644
--- a/src/main/java/org/olat/course/nodes/info/_i18n/LocalStrings_it.properties
+++ b/src/main/java/org/olat/course/nodes/info/_i18n/LocalStrings_it.properties
@@ -20,4 +20,4 @@ peekview.more=di pi\u00F9...
 peekview.noInfos=Nessuna comunicazione
 peekview.title=Titolo
 title_info=Comunicazioni
-wizard.step1.send_option.member=Membri, tutori di gruppi e proprietari di corsi
+
diff --git a/src/main/java/org/olat/course/nodes/info/_i18n/LocalStrings_jp.properties b/src/main/java/org/olat/course/nodes/info/_i18n/LocalStrings_jp.properties
index 115c432b64f22c83af86d76b6c4d9122b31434c3..02da21e410a1619a926f07db444436cdeb133338 100644
--- a/src/main/java/org/olat/course/nodes/info/_i18n/LocalStrings_jp.properties
+++ b/src/main/java/org/olat/course/nodes/info/_i18n/LocalStrings_jp.properties
@@ -19,5 +19,4 @@ pane.tab.infos_config.title=$\:pane.tab.infos_config
 peekview.more=\u3055\u3089\u306B ...
 peekview.noInfos=\u901A\u77E5\u306A\u3057
 peekview.title=\u30BF\u30A4\u30C8\u30EB
-title_info=\u901A\u77E5
-wizard.step1.send_option.member=\u30E1\u30F3\u30D0\u30FC\u3001\u30B0\u30EB\u30FC\u30D7\u30C1\u30E5\u30FC\u30BF\u30FC\u304A\u3088\u3073\u30B3\u30FC\u30B9\u30AA\u30FC\u30CA\u30FC
+title_info=\u901A\u77E5
\ No newline at end of file
diff --git a/src/main/java/org/olat/course/nodes/info/_i18n/LocalStrings_nl_NL.properties b/src/main/java/org/olat/course/nodes/info/_i18n/LocalStrings_nl_NL.properties
index 7e00f0cb026cd9f46defa203e9384e1d3cf53316..3514fd80bb9f2a798536ce879c9d03e893d61319 100644
--- a/src/main/java/org/olat/course/nodes/info/_i18n/LocalStrings_nl_NL.properties
+++ b/src/main/java/org/olat/course/nodes/info/_i18n/LocalStrings_nl_NL.properties
@@ -19,5 +19,4 @@ pane.tab.infos_config.title=$\:pane.tab.infos_config
 peekview.more=meer...
 peekview.noInfos=Geen mededelingen
 peekview.title=Titel
-title_info=Mededelingen
-wizard.step1.send_option.member=Leden, groepsdocenten en cursuseigenaars
+title_info=Mededelingen
\ No newline at end of file
diff --git a/src/main/java/org/olat/course/nodes/info/_i18n/LocalStrings_pl.properties b/src/main/java/org/olat/course/nodes/info/_i18n/LocalStrings_pl.properties
index 4c8bd95655a6a6ba091d83a2bcf00b9d54716c94..0b270d1fac9ebc3bffb95eca6a70d1383666b8e3 100644
--- a/src/main/java/org/olat/course/nodes/info/_i18n/LocalStrings_pl.properties
+++ b/src/main/java/org/olat/course/nodes/info/_i18n/LocalStrings_pl.properties
@@ -19,5 +19,4 @@ pane.tab.infos_config.title=$\:pane.tab.infos_config
 peekview.more=wi\u0119cej...
 peekview.noInfos=Brak powiadomie\u0144
 peekview.title=Tytu\u0142
-title_info=Powiadomienia
-wizard.step1.send_option.member=Cz\u0142onkowie, nauczyciele w grupach i w\u0142a\u015Bciciele kurs\u00F3w
+title_info=Powiadomienia
\ No newline at end of file
diff --git a/src/main/java/org/olat/course/nodes/info/_i18n/LocalStrings_pt_BR.properties b/src/main/java/org/olat/course/nodes/info/_i18n/LocalStrings_pt_BR.properties
index b93a116462418a04995de942bf6ab0f07d0ab2a8..15bf506943706aa6a2c8d08085ed5d9d51f64366 100644
--- a/src/main/java/org/olat/course/nodes/info/_i18n/LocalStrings_pt_BR.properties
+++ b/src/main/java/org/olat/course/nodes/info/_i18n/LocalStrings_pt_BR.properties
@@ -19,5 +19,4 @@ pane.tab.infos_config.title=$\:pane.tab.infos_config
 peekview.more=mais...
 peekview.noInfos=Sem notifica\u00E7\u00F5es
 peekview.title=T\u00EDtulo
-title_info=Notifica\u00E7\u00F5es
-wizard.step1.send_option.member=Membros, tutores de grupo, e os propriet\u00E1rios de curso
+title_info=Notifica\u00E7\u00F5es
\ No newline at end of file
diff --git a/src/main/java/org/olat/group/manager/BusinessGroupMembershipProcessor.java b/src/main/java/org/olat/group/manager/BusinessGroupMembershipProcessor.java
index 5fe41b1e5b0b650f1eac7da0b55b1cab61289ee2..ad8d3141bd4b63f16cf9f24647b91b10a9ba3b81 100644
--- a/src/main/java/org/olat/group/manager/BusinessGroupMembershipProcessor.java
+++ b/src/main/java/org/olat/group/manager/BusinessGroupMembershipProcessor.java
@@ -25,7 +25,7 @@ import java.util.List;
 import org.olat.basesecurity.GroupRoles;
 import org.olat.basesecurity.IdentityRef;
 import org.olat.basesecurity.model.IdentityRefImpl;
-import org.olat.commons.info.manager.InfoMessageFrontendManager;
+import org.olat.commons.info.InfoMessageFrontendManager;
 import org.olat.core.commons.services.notifications.NotificationsManager;
 import org.olat.core.gui.control.Event;
 import org.olat.core.util.coordinate.CoordinatorManager;
diff --git a/src/main/java/org/olat/group/manager/BusinessGroupServiceImpl.java b/src/main/java/org/olat/group/manager/BusinessGroupServiceImpl.java
index 23bbd6bfc4cda6ac856cec8f8fc99e25a822cead..dbd5d5219fe71b5917ac9e4909fd5f025950e8bf 100644
--- a/src/main/java/org/olat/group/manager/BusinessGroupServiceImpl.java
+++ b/src/main/java/org/olat/group/manager/BusinessGroupServiceImpl.java
@@ -44,7 +44,7 @@ import org.olat.basesecurity.IdentityRef;
 import org.olat.basesecurity.SecurityGroup;
 import org.olat.collaboration.CollaborationTools;
 import org.olat.collaboration.CollaborationToolsFactory;
-import org.olat.commons.info.manager.InfoMessageFrontendManager;
+import org.olat.commons.info.InfoMessageFrontendManager;
 import org.olat.core.CoreSpringFactory;
 import org.olat.core.commons.persistence.DB;
 import org.olat.core.commons.services.notifications.NotificationsManager;
diff --git a/src/main/java/org/olat/group/ui/run/InfoGroupRunController.java b/src/main/java/org/olat/group/ui/run/InfoGroupRunController.java
index 102d4191933fad41a80fedc9d0d6bb303a076156..97311924edb9feef791f0a887f901bde3181e5f3 100644
--- a/src/main/java/org/olat/group/ui/run/InfoGroupRunController.java
+++ b/src/main/java/org/olat/group/ui/run/InfoGroupRunController.java
@@ -23,11 +23,12 @@ import java.util.ArrayList;
 import java.util.List;
 import java.util.StringTokenizer;
 
-import org.olat.commons.info.manager.InfoMessageFrontendManager;
+import org.olat.basesecurity.GroupRoles;
+import org.olat.commons.info.InfoMessage;
+import org.olat.commons.info.InfoMessageFrontendManager;
+import org.olat.commons.info.InfoSubscriptionManager;
 import org.olat.commons.info.manager.MailFormatter;
-import org.olat.commons.info.model.InfoMessage;
 import org.olat.commons.info.notification.InfoSubscription;
-import org.olat.commons.info.notification.InfoSubscriptionManager;
 import org.olat.commons.info.ui.InfoDisplayController;
 import org.olat.commons.info.ui.InfoSecurityCallback;
 import org.olat.commons.info.ui.SendInfoMailFormatter;
@@ -48,7 +49,6 @@ import org.olat.core.id.OLATResourceable;
 import org.olat.core.util.UserSession;
 import org.olat.core.util.resource.OresHelper;
 import org.olat.group.BusinessGroup;
-import org.olat.group.BusinessGroupService;
 import org.springframework.beans.factory.annotation.Autowired;
 
 /**
@@ -64,13 +64,9 @@ public class InfoGroupRunController extends BasicController {
 	private ContextualSubscriptionController subscriptionController;
 	
 	private final String businessPath;
-	private InfoSubscriptionManager subscriptionManager;
 	
 	@Autowired
-	private	BusinessGroupService groupService;
-	@Autowired
-	private InfoMessageFrontendManager messageManager;
-
+	private InfoSubscriptionManager subscriptionManager;
 
 	public InfoGroupRunController(UserRequest ureq, WindowControl wControl, BusinessGroup businessGroup, boolean canAccess, boolean isAdmin) {
 		super(ureq, wControl);
@@ -81,7 +77,6 @@ public class InfoGroupRunController extends BasicController {
 		
 		UserSession usess = ureq.getUserSession();
 		if(!usess.getRoles().isGuestOnly()) {
-			subscriptionManager = InfoSubscriptionManager.getInstance();
 			SubscriptionContext subContext = subscriptionManager.getInfoSubscriptionContext(infoResourceable, resSubPath);
 			PublisherData pdata = subscriptionManager.getInfoPublisherData(infoResourceable, businessPath);
 			subscriptionController = new ContextualSubscriptionController(ureq, getWindowControl(), subContext, pdata);
@@ -91,10 +86,13 @@ public class InfoGroupRunController extends BasicController {
 		boolean canAddAndEdit = isAdmin || canAccess;
 		InfoSecurityCallback secCallback = new InfoGroupSecurityCallback(getIdentity(), canAddAndEdit, isAdmin);
 		infoDisplayController = new InfoDisplayController(ureq, wControl, secCallback, businessGroup, resSubPath, businessPath);
-		SendMailOption subscribers = new SendSubscriberMailOption(infoResourceable, resSubPath, messageManager);
+		SendMailOption subscribers = new SendSubscriberMailOption(infoResourceable, resSubPath, getLocale());
 		infoDisplayController.addSendMailOptions(subscribers);
-		SendMailOption groupMembers = new SendGroupMembersMailOption(groupService, businessGroup);
-		infoDisplayController.addSendMailOptions(groupMembers);
+		SendMailOption coaches = new SendGroupMembersMailOption(businessGroup, GroupRoles.coach, translate("sendtochooser.form.radio.owners"));
+		infoDisplayController.addSendMailOptions(coaches);
+		SendMailOption participants = new SendGroupMembersMailOption(businessGroup, GroupRoles.participant, translate("sendtochooser.form.radio.partip"));
+		infoDisplayController.addSendMailOptions(participants);
+
 		MailFormatter mailFormatter = new SendInfoMailFormatter(businessGroup.getName(), businessPath, getTranslator());
 		infoDisplayController.setSendMailFormatter(mailFormatter);
 		listenTo(infoDisplayController);
diff --git a/src/main/java/org/olat/group/ui/run/SendGroupMembersMailOption.java b/src/main/java/org/olat/group/ui/run/SendGroupMembersMailOption.java
index aad0902a4d7695dbaed708348e5fe48dda19632a..6f079623f78c8d22cc65c479d3a0c2e72ea9bfe1 100644
--- a/src/main/java/org/olat/group/ui/run/SendGroupMembersMailOption.java
+++ b/src/main/java/org/olat/group/ui/run/SendGroupMembersMailOption.java
@@ -20,12 +20,11 @@
 package org.olat.group.ui.run;
 
 import java.util.List;
-import java.util.Locale;
 
+import org.olat.basesecurity.GroupRoles;
 import org.olat.commons.info.ui.SendMailOption;
-import org.olat.core.gui.translator.Translator;
+import org.olat.core.CoreSpringFactory;
 import org.olat.core.id.Identity;
-import org.olat.core.util.Util;
 import org.olat.group.BusinessGroup;
 import org.olat.group.BusinessGroupService;
 
@@ -35,30 +34,28 @@ import org.olat.group.BusinessGroupService;
  */
 public class SendGroupMembersMailOption implements SendMailOption {
 
-	private BusinessGroupService groupService;
+	private final String label;
+	private final GroupRoles role;
 	private BusinessGroup businessGroup;
 	
-	
-	public SendGroupMembersMailOption(BusinessGroupService groupService, BusinessGroup businessGroup) {
-		this.groupService = groupService;
+	public SendGroupMembersMailOption(BusinessGroup businessGroup, GroupRoles role, String label) {
+		this.role = role;
+		this.label = label;
 		this.businessGroup = businessGroup;
 	}
 
 	@Override
 	public String getOptionKey() {
-		return "send-mail-group-members";
+		return "send-mail-group-members-" + role.name();
 	}
 
 	@Override
-	public String getOptionTranslatedName(Locale locale) {
-		Translator translator = Util.createPackageTranslator(SendGroupMembersMailOption.class, locale);
-		return translator.translate("wizard.step1.send_option.member");
+	public String getOptionName() {
+		return label;
 	}
 
 	@Override
 	public List<Identity> getSelectedIdentities() {
-		List<Identity> groupMembers = groupService.getMembers(businessGroup);
-		return groupMembers;
+		return CoreSpringFactory.getImpl(BusinessGroupService.class).getMembers(businessGroup, role.name());
 	}
-
 }
diff --git a/src/main/java/org/olat/search/service/document/InfoMessageDocument.java b/src/main/java/org/olat/search/service/document/InfoMessageDocument.java
index 32dbc0368328cf71ed56d5a4d69d8189a8b5054b..dfa51e3aa66b3a0b1e83642e212de01ef690696f 100644
--- a/src/main/java/org/olat/search/service/document/InfoMessageDocument.java
+++ b/src/main/java/org/olat/search/service/document/InfoMessageDocument.java
@@ -20,7 +20,7 @@
 package org.olat.search.service.document;
 
 import org.apache.lucene.document.Document;
-import org.olat.commons.info.model.InfoMessage;
+import org.olat.commons.info.InfoMessage;
 import org.olat.core.logging.OLog;
 import org.olat.core.logging.Tracing;
 import org.olat.search.model.OlatDocument;
diff --git a/src/main/java/org/olat/search/service/indexer/group/GroupInfoIndexer.java b/src/main/java/org/olat/search/service/indexer/group/GroupInfoIndexer.java
index 85383e3020e9d1ece2cbdc5c5b8c2889f210b5a5..053630f8296ccb90673f07536906312f1ee68b0e 100644
--- a/src/main/java/org/olat/search/service/indexer/group/GroupInfoIndexer.java
+++ b/src/main/java/org/olat/search/service/indexer/group/GroupInfoIndexer.java
@@ -23,9 +23,9 @@ import java.io.IOException;
 import java.util.List;
 
 import org.apache.lucene.document.Document;
-import org.olat.commons.info.manager.InfoMessageFrontendManager;
-import org.olat.commons.info.manager.InfoMessageManager;
-import org.olat.commons.info.model.InfoMessage;
+import org.olat.commons.info.InfoMessage;
+import org.olat.commons.info.InfoMessageFrontendManager;
+import org.olat.commons.info.InfoMessageManager;
 import org.olat.core.id.OLATResourceable;
 import org.olat.core.logging.AssertException;
 import org.olat.core.logging.OLog;
diff --git a/src/main/java/org/olat/search/service/indexer/repository/course/InfoCourseNodeIndexer.java b/src/main/java/org/olat/search/service/indexer/repository/course/InfoCourseNodeIndexer.java
index 911f50bb9a1a00c6057be64ab6165e11fede5cd2..5e8f9f4457c00304d11dd60898abfa7cad486a57 100644
--- a/src/main/java/org/olat/search/service/indexer/repository/course/InfoCourseNodeIndexer.java
+++ b/src/main/java/org/olat/search/service/indexer/repository/course/InfoCourseNodeIndexer.java
@@ -29,8 +29,8 @@ import java.io.IOException;
 import java.util.List;
 
 import org.apache.lucene.document.Document;
-import org.olat.commons.info.manager.InfoMessageManager;
-import org.olat.commons.info.model.InfoMessage;
+import org.olat.commons.info.InfoMessage;
+import org.olat.commons.info.InfoMessageManager;
 import org.olat.core.id.OLATResourceable;
 import org.olat.core.logging.OLog;
 import org.olat.core.logging.Tracing;
diff --git a/src/main/java/org/olat/upgrade/OLATUpgrade_11_4_0.java b/src/main/java/org/olat/upgrade/OLATUpgrade_11_4_0.java
index b53359fe7228deb456f5f8d41deb9597766b80f2..194e20f6d7f1d1da8e6d63be13f7cf4aa824aef1 100644
--- a/src/main/java/org/olat/upgrade/OLATUpgrade_11_4_0.java
+++ b/src/main/java/org/olat/upgrade/OLATUpgrade_11_4_0.java
@@ -24,7 +24,7 @@ import java.util.List;
 import org.olat.basesecurity.GroupRoles;
 import org.olat.collaboration.CollaborationTools;
 import org.olat.collaboration.CollaborationToolsFactory;
-import org.olat.commons.info.manager.InfoMessageFrontendManager;
+import org.olat.commons.info.InfoMessageFrontendManager;
 import org.olat.commons.info.model.InfoMessageImpl;
 import org.olat.core.commons.persistence.DB;
 import org.olat.core.gui.translator.Translator;
diff --git a/src/main/resources/database/mysql/alter_11_5_x_to_12_0_0.sql b/src/main/resources/database/mysql/alter_11_5_x_to_12_0_0.sql
index f799c67ddf197b71d4ac73a317ca1b45ff1b2db2..e602d69a65b82b0926b18be3991119c82919a022 100644
--- a/src/main/resources/database/mysql/alter_11_5_x_to_12_0_0.sql
+++ b/src/main/resources/database/mysql/alter_11_5_x_to_12_0_0.sql
@@ -248,6 +248,7 @@ alter table o_gta_task add column fk_allow_reset_identity bigint default null;
 alter table o_gta_task add constraint gtaskreset_to_allower_idx foreign key (fk_allow_reset_identity) references o_bs_identity (id);
 
 
+alter table o_info_message add column attachmentpath varchar(1024) default null;
 
 
 
diff --git a/src/main/resources/database/mysql/setupDatabase.sql b/src/main/resources/database/mysql/setupDatabase.sql
index bcf6000daf67153f12b3874d0b58543d3aa8974c..d48bb6c9ac62fdb606176e64c3becf1c312335e3 100644
--- a/src/main/resources/database/mysql/setupDatabase.sql
+++ b/src/main/resources/database/mysql/setupDatabase.sql
@@ -783,6 +783,7 @@ create table if not exists o_info_message (
   modificationdate datetime,
   title varchar(2048),
   message longtext,
+  attachmentpath varchar(1024),
   resname varchar(50) NOT NULL,
   resid bigint NOT NULL,
   ressubpath varchar(2048),
diff --git a/src/main/resources/database/oracle/alter_11_5_x_to_12_0_0.sql b/src/main/resources/database/oracle/alter_11_5_x_to_12_0_0.sql
index 8bf3d7e7bd2c6be012b569ee8b34d2ec06741394..135895b75683adbcff3beebe3381a0cf6c15c4aa 100644
--- a/src/main/resources/database/oracle/alter_11_5_x_to_12_0_0.sql
+++ b/src/main/resources/database/oracle/alter_11_5_x_to_12_0_0.sql
@@ -250,3 +250,5 @@ alter table o_gta_task add constraint gtaskreset_to_allower_idx foreign key (fk_
 create index idx_gtaskreset_to_allower_idx on o_gta_task (fk_allow_reset_identity);
 
 
+alter table alter table o_info_message add attachmentpath varchar(1024) default null;
+
diff --git a/src/main/resources/database/oracle/setupDatabase.sql b/src/main/resources/database/oracle/setupDatabase.sql
index 4bcffaa396f0e9e4c7a18c5e6dec639e0302ea77..616cd6aa53004f5f388ea338fac516e0a18df0b7 100644
--- a/src/main/resources/database/oracle/setupDatabase.sql
+++ b/src/main/resources/database/oracle/setupDatabase.sql
@@ -701,6 +701,7 @@ CREATE TABLE o_info_message (
   modificationdate date,
   title varchar2(2048 char),
   message clob,
+  attachmentpath varchar(1024),
   resname varchar(50 char) NOT NULL,
   resid number(20) NOT NULL,
   ressubpath varchar2(2048 char),
diff --git a/src/main/resources/database/postgresql/alter_11_5_x_to_12_0_0.sql b/src/main/resources/database/postgresql/alter_11_5_x_to_12_0_0.sql
index d069ff1f39e62639f73dc29e2fd9cf847c9e531a..bc764ec42185e4eb869f9960bd150e16f29fc4e0 100644
--- a/src/main/resources/database/postgresql/alter_11_5_x_to_12_0_0.sql
+++ b/src/main/resources/database/postgresql/alter_11_5_x_to_12_0_0.sql
@@ -250,3 +250,9 @@ alter table o_gta_task add constraint gtaskreset_to_allower_idx foreign key (fk_
 create index idx_gtaskreset_to_allower_idx on o_gta_task (fk_allow_reset_identity);
 
 
+alter table o_info_message add column attachmentpath varchar(1024) default null;
+
+
+
+
+
diff --git a/src/main/resources/database/postgresql/setupDatabase.sql b/src/main/resources/database/postgresql/setupDatabase.sql
index e18ef22948b7e80b8e8e72d66ccfc09d1ba6aabd..c5f3bda9345097553f59bb78adff750fe353f633 100644
--- a/src/main/resources/database/postgresql/setupDatabase.sql
+++ b/src/main/resources/database/postgresql/setupDatabase.sql
@@ -629,6 +629,7 @@ create table o_info_message (
   modificationdate timestamp,
   title varchar(2048),
   message text,
+  attachmentpath varchar(1024),
   resname varchar(50) NOT NULL,
   resid int8 NOT NULL,
   ressubpath varchar(2048),
diff --git a/src/test/java/org/olat/commons/info/InfoManagerTest.java b/src/test/java/org/olat/commons/info/InfoManagerTest.java
index d57d2cb0115a01a1e74171c1a99ba1d1f4edc924..63d1f08e63af5303454d855234b221b9dd158cd4 100644
--- a/src/test/java/org/olat/commons/info/InfoManagerTest.java
+++ b/src/test/java/org/olat/commons/info/InfoManagerTest.java
@@ -33,8 +33,6 @@ import java.util.UUID;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
-import org.olat.commons.info.manager.InfoMessageManager;
-import org.olat.commons.info.model.InfoMessage;
 import org.olat.core.commons.persistence.DB;
 import org.olat.core.id.Identity;
 import org.olat.core.id.OLATResourceable;
diff --git a/src/test/java/org/olat/commons/info/InfoMessageFrontendManagerTest.java b/src/test/java/org/olat/commons/info/InfoMessageFrontendManagerTest.java
index f1fb12220c02a4818be6b92a074e7967d892a063..7099e96c8863580c829fef1b378a0baa2cc11c99 100644
--- a/src/test/java/org/olat/commons/info/InfoMessageFrontendManagerTest.java
+++ b/src/test/java/org/olat/commons/info/InfoMessageFrontendManagerTest.java
@@ -28,8 +28,6 @@ import java.util.UUID;
 
 import org.junit.Assert;
 import org.junit.Test;
-import org.olat.commons.info.manager.InfoMessageFrontendManager;
-import org.olat.commons.info.model.InfoMessage;
 import org.olat.core.commons.persistence.DB;
 import org.olat.core.commons.services.notifications.NotificationsManager;
 import org.olat.core.commons.services.notifications.Publisher;