From 4fc6516a5127ebb8236f758568f3f9809ff598ad Mon Sep 17 00:00:00 2001
From: srosse <stephane.rosse@frentix.com>
Date: Tue, 12 Feb 2019 17:39:34 +0100
Subject: [PATCH] OO-3771: add templating with variables in mail course element

---
 .../den/DENManageParticipantsController.java  |  2 +-
 .../de/bps/course/nodes/den/DENManager.java   |  2 +-
 .../collaboration/CollaborationTools.java     |  2 +-
 .../ui/MembersAvatarDisplayRunController.java |  2 +-
 .../memberlist/ui/MembersTableController.java |  2 +-
 .../impressum/ContactController.java          |  6 +-
 .../olat/core/util/mail/ContactMessage.java   |  5 +-
 .../org/olat/core/util/mail/MailBundle.java   |  8 ++
 .../util/mail/manager/MailManagerImpl.java    |  8 +-
 ...icateAndEfficiencyStatementController.java |  2 +-
 .../olat/course/nodes/co/CORunController.java | 28 +++---
 .../course/nodes/co/CourseMailTemplate.java   | 77 +++++++++++++++
 .../nodes/gta/ui/GTACoachController.java      |  2 +-
 .../ui/homepage/GroupContactController.java   |  2 +-
 .../AbstractBusinessGroupListController.java  |  2 +-
 .../ui/main/AbstractMemberListController.java |  4 +-
 .../qti/editor/QTIEditorMainController.java   |  2 +-
 .../java/org/olat/modules/co/ContactForm.java | 23 ++---
 .../modules/co/ContactFormController.java     | 95 ++++++++++++-------
 .../coach/ui/StudentCoursesController.java    |  2 +-
 .../ParticipantLectureBlocksController.java   |  2 +-
 .../quality/ui/SuggestionController.java      |  2 +-
 .../registration/DisclaimerController.java    |  2 +-
 .../RequestAccountDeletionController.java     |  2 +-
 .../catalog/CatalogNodeManagerController.java |  2 +-
 .../ui/admin/UserSearchTableController.java   |  2 +-
 .../AbstractUserInfoMainController.java       |  2 +-
 27 files changed, 202 insertions(+), 88 deletions(-)
 create mode 100644 src/main/java/org/olat/course/nodes/co/CourseMailTemplate.java

diff --git a/src/main/java/de/bps/course/nodes/den/DENManageParticipantsController.java b/src/main/java/de/bps/course/nodes/den/DENManageParticipantsController.java
index 4a91e7eb42f..c5ea6a8cb49 100644
--- a/src/main/java/de/bps/course/nodes/den/DENManageParticipantsController.java
+++ b/src/main/java/de/bps/course/nodes/den/DENManageParticipantsController.java
@@ -319,7 +319,7 @@ public class DENManageParticipantsController extends BasicController {
 		cmsg.addEmailTo(contactList);
 		
 		removeAsListenerAndDispose(contactCtr);
-		contactCtr = new ContactFormController(ureq, getWindowControl(), false, false, false, cmsg);
+		contactCtr = new ContactFormController(ureq, getWindowControl(), false, false, false, cmsg, null);
 		listenTo(contactCtr);
 		
 		sendMessageVC.contextPut("title", translate("participants.message"));
diff --git a/src/main/java/de/bps/course/nodes/den/DENManager.java b/src/main/java/de/bps/course/nodes/den/DENManager.java
index 697c06e4c8e..1b0d9bbd4ab 100644
--- a/src/main/java/de/bps/course/nodes/den/DENManager.java
+++ b/src/main/java/de/bps/course/nodes/den/DENManager.java
@@ -764,7 +764,7 @@ public class DENManager {
 		}
 		contactList.addAllIdentites(participants);
 		cmsg.addEmailTo(contactList);
-		ContactFormController contactCtr = new ContactFormController(ureq, wControl, false, false, false, cmsg);
+		ContactFormController contactCtr = new ContactFormController(ureq, wControl, false, false, false, cmsg, null);
 		contactCtr.addControllerListener(listener);
 		sendMessageVC.contextPut("title", trans.translate("participants.message"));
 		sendMessageVC.put("contactForm", contactCtr.getInitialComponent());
diff --git a/src/main/java/org/olat/collaboration/CollaborationTools.java b/src/main/java/org/olat/collaboration/CollaborationTools.java
index c701d8759b7..40a3b9e6f06 100644
--- a/src/main/java/org/olat/collaboration/CollaborationTools.java
+++ b/src/main/java/org/olat/collaboration/CollaborationTools.java
@@ -473,7 +473,7 @@ public class CollaborationTools implements Serializable {
 	 * @return a contact form controller
 	 */
 	public ContactFormController createContactFormController(UserRequest ureq, WindowControl wControl, ContactMessage cmsg) {
-		return new ContactFormController(ureq, wControl, true, false, false, cmsg);
+		return new ContactFormController(ureq, wControl, true, false, false, cmsg, null);
 	}
 
 	
diff --git a/src/main/java/org/olat/commons/memberlist/ui/MembersAvatarDisplayRunController.java b/src/main/java/org/olat/commons/memberlist/ui/MembersAvatarDisplayRunController.java
index 0d4b2acbcce..348b0cd9d38 100644
--- a/src/main/java/org/olat/commons/memberlist/ui/MembersAvatarDisplayRunController.java
+++ b/src/main/java/org/olat/commons/memberlist/ui/MembersAvatarDisplayRunController.java
@@ -486,7 +486,7 @@ public class MembersAvatarDisplayRunController extends FormBasicController {
 			cmsg.addEmailTo(contactList);
 			// preset body template from i18n
 			cmsg.setBodyText(createBodyTemplate());
-			emailController = new ContactFormController(ureq, getWindowControl(), true, false, false, cmsg);
+			emailController = new ContactFormController(ureq, getWindowControl(), true, false, false, cmsg, null);
 			listenTo(emailController);
 			
 			String title = translate("members.email.title");
diff --git a/src/main/java/org/olat/commons/memberlist/ui/MembersTableController.java b/src/main/java/org/olat/commons/memberlist/ui/MembersTableController.java
index abccf92b6ca..c67cf7dcc31 100644
--- a/src/main/java/org/olat/commons/memberlist/ui/MembersTableController.java
+++ b/src/main/java/org/olat/commons/memberlist/ui/MembersTableController.java
@@ -326,7 +326,7 @@ public class MembersTableController extends FormBasicController {
 			cmsg.addEmailTo(contactList);
 			// preset body template from i18n
 			cmsg.setBodyText(createBodyTemplate());
-			emailController = new ContactFormController(ureq, getWindowControl(), true, false, false, cmsg);
+			emailController = new ContactFormController(ureq, getWindowControl(), true, false, false, cmsg, null);
 			listenTo(emailController);
 			
 			String title = translate("members.email.title");
diff --git a/src/main/java/org/olat/core/commons/controllers/impressum/ContactController.java b/src/main/java/org/olat/core/commons/controllers/impressum/ContactController.java
index 86ca8943e40..10afb676290 100644
--- a/src/main/java/org/olat/core/commons/controllers/impressum/ContactController.java
+++ b/src/main/java/org/olat/core/commons/controllers/impressum/ContactController.java
@@ -90,9 +90,9 @@ public class ContactController extends BasicController implements GenericEventLi
 		contactMessage.addEmailTo(contactList);
 
 		// Show GUI
-		this.contactForm = new ContactFormController(ureq, getWindowControl(), false, false, false, contactMessage);
-		listenTo(this.contactForm);
-		this.content.put("contactForm", this.contactForm.getInitialComponent());
+		contactForm = new ContactFormController(ureq, getWindowControl(), false, false, false, contactMessage, null);
+		listenTo(contactForm);
+		content.put("contactForm", contactForm.getInitialComponent());
 		putInitialPanel(content);
 	}
 
diff --git a/src/main/java/org/olat/core/util/mail/ContactMessage.java b/src/main/java/org/olat/core/util/mail/ContactMessage.java
index 7e2c3116276..4abd7ca4dea 100644
--- a/src/main/java/org/olat/core/util/mail/ContactMessage.java
+++ b/src/main/java/org/olat/core/util/mail/ContactMessage.java
@@ -49,7 +49,7 @@ public class ContactMessage {
 	 * 
 	 * @param from
 	 */
-	public ContactMessage(Identity from){
+	public ContactMessage(Identity from) {
 		this.from = from;
 		disabledIdentities = new ArrayList<>();
 	}
@@ -61,12 +61,15 @@ public class ContactMessage {
 	public void setSubject(String subject){
 		this.subject=subject;
 	}
+	
 	public String getSubject(){
 		return subject;
 	}
+	
 	public void setBodyText(String bodyText){
 		this.bodyText=bodyText;
 	}
+	
 	public String getBodyText(){
 		return bodyText;
 	}
diff --git a/src/main/java/org/olat/core/util/mail/MailBundle.java b/src/main/java/org/olat/core/util/mail/MailBundle.java
index 1ec7904d545..f2b726e05b7 100644
--- a/src/main/java/org/olat/core/util/mail/MailBundle.java
+++ b/src/main/java/org/olat/core/util/mail/MailBundle.java
@@ -45,6 +45,14 @@ public class MailBundle {
 	private String metaId;
 	private MailContent content;
 	
+	public MailBundle() {
+		//
+	}
+	
+	public MailBundle(MailContext context) {
+		this.context = context;
+	}
+	
 	public MailContext getContext() {
 		return context;
 	}
diff --git a/src/main/java/org/olat/core/util/mail/manager/MailManagerImpl.java b/src/main/java/org/olat/core/util/mail/manager/MailManagerImpl.java
index c5603550a58..bbfe593cc19 100644
--- a/src/main/java/org/olat/core/util/mail/manager/MailManagerImpl.java
+++ b/src/main/java/org/olat/core/util/mail/manager/MailManagerImpl.java
@@ -667,20 +667,20 @@ public class MailManagerImpl implements MailManager, InitializingBean  {
 	}
 
 	@Override
-	public MailBundle makeMailBundle(MailContext ctxt, Identity recipientTO,
+	public MailBundle makeMailBundle(MailContext ctxt, Identity recipientTo,
 			MailTemplate template, Identity sender, String metaId, MailerResult result) {	
 
 		MailBundle bundle;
-		if(MailHelper.isDisabledMailAddress(recipientTO, result)) {
+		if(recipientTo != null && MailHelper.isDisabledMailAddress(recipientTo, result)) {
 			bundle = null;//email disabled, nothing to do
 		} else {
-			MailContent msg = createWithContext(recipientTO, template, result);
+			MailContent msg = createWithContext(recipientTo, template, result);
 			if(msg != null && result.getReturnCode() == MailerResult.OK){
 				// send mail
 				bundle = new MailBundle();
 				bundle.setContext(ctxt);
 				bundle.setFromId(sender);
-				bundle.setToId(recipientTO);
+				bundle.setToId(recipientTo);
 				bundle.setMetaId(metaId);
 				bundle.setContent(msg);
 			} else {
diff --git a/src/main/java/org/olat/course/certificate/ui/CertificateAndEfficiencyStatementController.java b/src/main/java/org/olat/course/certificate/ui/CertificateAndEfficiencyStatementController.java
index 9f229f90332..4115db1d5f1 100644
--- a/src/main/java/org/olat/course/certificate/ui/CertificateAndEfficiencyStatementController.java
+++ b/src/main/java/org/olat/course/certificate/ui/CertificateAndEfficiencyStatementController.java
@@ -345,7 +345,7 @@ public class CertificateAndEfficiencyStatementController extends BasicController
 		ContactList contactList = new ContactList("to");
 		contactList.add(statementOwner);
 		cmsg.addEmailTo(contactList);
-		contactCtrl = new ContactFormController(ureq, getWindowControl(), true, false, false, cmsg);
+		contactCtrl = new ContactFormController(ureq, getWindowControl(), true, false, false, cmsg, null);
 		listenTo(contactCtrl);
 		cmc = new CloseableModalController(getWindowControl(), translate("close"), contactCtrl.getInitialComponent());
 		cmc.activate();
diff --git a/src/main/java/org/olat/course/nodes/co/CORunController.java b/src/main/java/org/olat/course/nodes/co/CORunController.java
index 1e15a482fd0..df6e82cebc6 100755
--- a/src/main/java/org/olat/course/nodes/co/CORunController.java
+++ b/src/main/java/org/olat/course/nodes/co/CORunController.java
@@ -53,6 +53,7 @@ import org.olat.group.BusinessGroupService;
 import org.olat.group.area.BGAreaManager;
 import org.olat.modules.ModuleConfiguration;
 import org.olat.modules.co.ContactFormController;
+import org.olat.repository.RepositoryEntry;
 import org.olat.repository.RepositoryEntryRelationType;
 import org.olat.repository.RepositoryService;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -153,13 +154,13 @@ public class CORunController extends BasicController {
 			ContactList cl = retrieveCoachesFromCourse();
 			contactLists.push(cl);
 			List<BusinessGroup> groups = cgm.getAllBusinessGroups();
-			List<Long> grp_keys = new ArrayList<>();
+			List<Long> groupKeys = new ArrayList<>();
 			for(BusinessGroup group:groups){
-				grp_keys.add(group.getKey());
+				groupKeys.add(group.getKey());
 			}
-			cl = retrieveCoachesFromGroups(grp_keys);
+			cl = retrieveCoachesFromGroups(groupKeys);
 			contactLists.push(cl);
-			cl = retrieveCoachesFromAreas(grp_keys);
+			cl = retrieveCoachesFromAreas(groupKeys);
 			contactLists.push(cl);
 		} else if (coachesCourseConfigured != null && coachesCourseConfigured.booleanValue()){
 			ContactList cl = retrieveCoachesFromCourse();
@@ -170,13 +171,13 @@ public class CORunController extends BasicController {
 			ContactList cl = retrieveParticipantsFromCourse();
 			contactLists.push(cl);
 			List<BusinessGroup> groups = cgm.getAllBusinessGroups();
-			List<Long> grp_keys = new ArrayList<>();
+			List<Long> groupKeys = new ArrayList<>();
 			for(BusinessGroup group:groups){
-				grp_keys.add(group.getKey());
+				groupKeys.add(group.getKey());
 			}
-			cl = retrieveParticipantsFromGroups(grp_keys);
+			cl = retrieveParticipantsFromGroups(groupKeys);
 			contactLists.push(cl);
-			cl = retrieveParticipantsFromAreas(grp_keys);
+			cl = retrieveParticipantsFromAreas(groupKeys);
 			contactLists.push(cl);
 		} else if (participantsCourseConfigured != null && participantsCourseConfigured.booleanValue()){
 			ContactList cl = retrieveParticipantsFromCourse();
@@ -213,17 +214,18 @@ public class CORunController extends BasicController {
 			contactLists.push(emailList);
 		}
 
-		if (contactLists.size() > 0) { 
+		if (!contactLists.isEmpty()) { 
 			ContactMessage cmsg = new ContactMessage(ureq.getIdentity());
-			
 			while (!contactLists.empty()) {
 				ContactList cl = contactLists.pop();
 				cmsg.addEmailTo(cl);	
 			}
 			
-			cmsg.setBodyText(mBody);
-			cmsg.setSubject(mSubject);
-			coFoCtr = new ContactFormController(ureq, getWindowControl(), false, false, false, cmsg);
+			RepositoryEntry entry = userCourseEnv.getCourseEnvironment().getCourseGroupManager().getCourseEntry();
+			CourseMailTemplate template = new CourseMailTemplate(entry, getIdentity(), getLocale());
+			template.setBodyTemplate(mBody);
+			template.setSubjectTemplate(mSubject);
+			coFoCtr = new ContactFormController(ureq, getWindowControl(), false, false, false, cmsg, template);
 			listenTo(coFoCtr);//dispose as this controller is disposed
 			putInitialPanel(coFoCtr.getInitialComponent());
 		} else { // no email adresses at all
diff --git a/src/main/java/org/olat/course/nodes/co/CourseMailTemplate.java b/src/main/java/org/olat/course/nodes/co/CourseMailTemplate.java
new file mode 100644
index 00000000000..e1bc6a0432e
--- /dev/null
+++ b/src/main/java/org/olat/course/nodes/co/CourseMailTemplate.java
@@ -0,0 +1,77 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.course.nodes.co;
+
+import java.util.Locale;
+
+import org.apache.velocity.VelocityContext;
+import org.olat.core.CoreSpringFactory;
+import org.olat.core.helpers.Settings;
+import org.olat.core.id.Identity;
+import org.olat.core.id.User;
+import org.olat.core.id.UserConstants;
+import org.olat.core.util.mail.MailTemplate;
+import org.olat.repository.RepositoryEntry;
+import org.olat.user.UserManager;
+
+/**
+ * 
+ * Initial date: 12 févr. 2019<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class CourseMailTemplate extends MailTemplate {
+	
+	private final Locale locale;
+	private final Identity sender;
+	private final RepositoryEntry entry;
+	
+	public CourseMailTemplate(RepositoryEntry entry, Identity sender, Locale locale) {
+		super(null, null, null);
+		this.entry = entry;
+		this.sender = sender;
+		this.locale = locale;
+	}
+
+	@Override
+	public void putVariablesInMailContext(VelocityContext vContext, Identity recipient) {
+		if(entry != null) {
+			String url = Settings.getServerContextPathURI() + "/url/RepositoryEntry/" + entry.getKey();
+			vContext.put("courseurl", url);
+			vContext.put("coursename", entry.getDisplayname());
+			vContext.put("coursedescription", entry.getDescription());
+		}
+		if(sender != null) {
+			User user = sender.getUser();
+			UserManager userManager = CoreSpringFactory.getImpl(UserManager.class);
+			
+			vContext.put("firstname", user.getProperty(UserConstants.FIRSTNAME, null));
+			vContext.put(UserConstants.FIRSTNAME, user.getProperty(UserConstants.FIRSTNAME, null));
+			vContext.put("lastname", user.getProperty(UserConstants.LASTNAME, null));
+			vContext.put(UserConstants.LASTNAME, user.getProperty(UserConstants.LASTNAME, null));
+			String fullName = userManager.getUserDisplayName(sender);
+			vContext.put("fullname", fullName);
+			vContext.put("fullName", fullName); 
+			vContext.put("mail", userManager.getUserDisplayEmail(user, locale));
+			vContext.put("email", userManager.getUserDisplayEmail(user, locale));
+			vContext.put("username", sender.getName());
+		}
+	}
+}
diff --git a/src/main/java/org/olat/course/nodes/gta/ui/GTACoachController.java b/src/main/java/org/olat/course/nodes/gta/ui/GTACoachController.java
index dee4fa8d058..59b9b68d45f 100644
--- a/src/main/java/org/olat/course/nodes/gta/ui/GTACoachController.java
+++ b/src/main/java/org/olat/course/nodes/gta/ui/GTACoachController.java
@@ -831,7 +831,7 @@ public class GTACoachController extends GTAAbstractController implements Assessm
 			ContactMessage cmsg = new ContactMessage(ureq.getIdentity());
 			cmsg.addEmailTo(contactList);
 			
-			emailController = new ContactFormController(ureq, getWindowControl(), true, false, false, cmsg);
+			emailController = new ContactFormController(ureq, getWindowControl(), true, false, false, cmsg, null);
 			listenTo(emailController);
 			
 			removeAsListenerAndDispose(cmc);
diff --git a/src/main/java/org/olat/group/ui/homepage/GroupContactController.java b/src/main/java/org/olat/group/ui/homepage/GroupContactController.java
index 3afd9908606..ba1d873b0f0 100644
--- a/src/main/java/org/olat/group/ui/homepage/GroupContactController.java
+++ b/src/main/java/org/olat/group/ui/homepage/GroupContactController.java
@@ -57,7 +57,7 @@ public class GroupContactController extends BasicController {
 		// per default contact the group owners.
 		if (businessGroupService.countMembers(businessGroup, GroupRoles.coach.name()) != 0) {
 			ContactMessage contactMessage = createContactMessage(ureq.getIdentity(), "form.to.owners", businessGroup);
-			contactForm = new ContactFormController(ureq, getWindowControl(), false, false, false, contactMessage);
+			contactForm = new ContactFormController(ureq, getWindowControl(), false, false, false, contactMessage, null);
 			listenTo(contactForm);
 			content.put("contactForm",	contactForm.getInitialComponent());
 		} else {
diff --git a/src/main/java/org/olat/group/ui/main/AbstractBusinessGroupListController.java b/src/main/java/org/olat/group/ui/main/AbstractBusinessGroupListController.java
index 1aab3523bdc..95f970a0ed0 100644
--- a/src/main/java/org/olat/group/ui/main/AbstractBusinessGroupListController.java
+++ b/src/main/java/org/olat/group/ui/main/AbstractBusinessGroupListController.java
@@ -592,7 +592,7 @@ public abstract class AbstractBusinessGroupListController extends FormBasicContr
 		msg.setBodyText(translate("request.leaving.body", args));
 		msg.addEmailTo(contacts);
 		
-		contactCtrl = new ContactFormController(ureq, getWindowControl(), true, false, true, msg);
+		contactCtrl = new ContactFormController(ureq, getWindowControl(), true, false, true, msg, null);
 		listenTo(contactCtrl);
 		cmc = new CloseableModalController(getWindowControl(), "close", contactCtrl.getInitialComponent(),
 				true, translate("dialog.modal.bg.asktoleave.title"));
diff --git a/src/main/java/org/olat/group/ui/main/AbstractMemberListController.java b/src/main/java/org/olat/group/ui/main/AbstractMemberListController.java
index 50bd296854b..4562db84bd6 100644
--- a/src/main/java/org/olat/group/ui/main/AbstractMemberListController.java
+++ b/src/main/java/org/olat/group/ui/main/AbstractMemberListController.java
@@ -671,7 +671,7 @@ public abstract class AbstractMemberListController extends FormBasicController i
 		contactList.addAllIdentites(identities);
 		contactMessage.addEmailTo(contactList);
 		
-		contactCtrl = new ContactFormController(ureq, getWindowControl(), true, false, false, contactMessage);
+		contactCtrl = new ContactFormController(ureq, getWindowControl(), true, false, false, contactMessage, null);
 		listenTo(contactCtrl);
 
 		cmc = new CloseableModalController(getWindowControl(), translate("close"), contactCtrl.getInitialComponent(),
@@ -745,7 +745,7 @@ public abstract class AbstractMemberListController extends FormBasicController i
 		
 		OLATResourceable ores = OresHelper.createOLATResourceableType("Contact");
 		WindowControl bwControl = addToHistory(ureq, ores, null);
-		contactCtrl = new ContactFormController(ureq, bwControl, true, false, false, cmsg);
+		contactCtrl = new ContactFormController(ureq, bwControl, true, false, false, cmsg, null);
 		listenTo(contactCtrl);
 		
 		toolbarPanel.pushController(fullname, contactCtrl);
diff --git a/src/main/java/org/olat/ims/qti/editor/QTIEditorMainController.java b/src/main/java/org/olat/ims/qti/editor/QTIEditorMainController.java
index 31dc902eaf5..170419232c7 100644
--- a/src/main/java/org/olat/ims/qti/editor/QTIEditorMainController.java
+++ b/src/main/java/org/olat/ims/qti/editor/QTIEditorMainController.java
@@ -813,7 +813,7 @@ public class QTIEditorMainController extends MainLayoutBasicController implement
 					changeEmail.setBodyText("<p>" + userMsg + "</p>\n<pre>" + changeLog + "</pre>");
 				}// else nothing was added!
 				changeEmail.setSubject("Change log for " + startedWithTitle);
-				cfc = new ContactFormController(ureq, getWindowControl(), true, false, false, changeEmail);
+				cfc = new ContactFormController(ureq, getWindowControl(), true, false, false, changeEmail, null);
 				listenTo(cfc);
 				exitPanel.setContent(cfc.getInitialComponent());
 				return;
diff --git a/src/main/java/org/olat/modules/co/ContactForm.java b/src/main/java/org/olat/modules/co/ContactForm.java
index ba00778686d..0f33193f5e8 100644
--- a/src/main/java/org/olat/modules/co/ContactForm.java
+++ b/src/main/java/org/olat/modules/co/ContactForm.java
@@ -85,27 +85,27 @@ import org.olat.user.UserManager;
 
 public class ContactForm extends FormBasicController {
 	//
-	private final static String NLS_CONTACT_TO = "contact.to";
+	private static final String NLS_CONTACT_TO = "contact.to";
 	private TextElement tto = null;
 	private TextElement ttoBig = null;
-	private final static String NLS_CONTACT_FROM = "contact.from";
+	private static final String NLS_CONTACT_FROM = "contact.from";
 	private TextElement tfrom;
-	private final static String NLS_CONTACT_SUBJECT = "contact.subject";
+	private static final String NLS_CONTACT_SUBJECT = "contact.subject";
 	private TextElement tsubject;
-	private final static String NLS_CONTACT_BODY = "contact.body";
+	private static final String NLS_CONTACT_BODY = "contact.body";
 	private RichTextElement tbody;
-	private final static String NLS_CONTACT_ATTACHMENT = "contact.attachment";
-	private final static String NLS_CONTACT_ATTACHMENT_EXPL = "contact.attachment.maxsize";
+	private static final String NLS_CONTACT_ATTACHMENT = "contact.attachment";
+	private static final String NLS_CONTACT_ATTACHMENT_EXPL = "contact.attachment.maxsize";
 	private int contactAttachmentMaxSizeInMb = 5;
 	private FileElement attachmentEl;
 	private List<FormLink> attachmentLinks = new ArrayList<>();
 	private FormLayoutContainer uploadCont;
 	private boolean recipientsAreEditable = false;
-	private final static int emailCols = 60;
+	private static final int emailCols = 60;
 	private boolean readOnly=false;
 	private boolean hasMsgCancel=false;
 	private boolean hasMsgSave=true;
-	private final static String NLS_CONTACT_SEND_CP_FROM = "contact.cp.from";
+	private static final String NLS_CONTACT_SEND_CP_FROM = "contact.cp.from";
 	private SelectionElement tcpfrom;
 	private Identity emailFrom;
 	private File attachementTempDir;
@@ -199,17 +199,11 @@ public class ContactForm extends FormBasicController {
 		}
 		boolean subjectOk = !tsubject.isEmpty("error.field.not.empty");
 		boolean bodyOk = !tbody.isEmpty("error.field.not.empty");
-		// the body message may not be longer than about 4 pages or 10000
-		// characters
-		//bodyOk = bodyOk && tbody.notLongerThan(10000, "input.toolong");
 		boolean toOk = false;
 		if (tto != null) {
 			toOk = !tto.isEmpty("error.field.not.empty");
 		} else {
 			toOk = !ttoBig.isEmpty("error.field.not.empty");
-			// limit of recipients about 700 (1 emailaddress medial 40
-			// characters)
-			//toOk = toOk && ttoBig.notLongerThan(30000, "input.toolong");
 		}
 		boolean fromOk = !tfrom.isEmpty("error.field.not.empty");
 		return subjectOk && bodyOk && toOk && fromOk && fromMailAddOk;
@@ -328,7 +322,6 @@ public class ContactForm extends FormBasicController {
 				attachmentEl.reset();
 			} else {
 				File attachment = attachmentEl.moveUploadFileTo(attachementTempDir);
-//				attachment = null;
 				// OO-48  somehow file-move can fail, check for it, display error-dialog if it failed
 				if(attachment == null){
 					attachmentEl.reset();
diff --git a/src/main/java/org/olat/modules/co/ContactFormController.java b/src/main/java/org/olat/modules/co/ContactFormController.java
index e2c3526097c..142c326ed73 100644
--- a/src/main/java/org/olat/modules/co/ContactFormController.java
+++ b/src/main/java/org/olat/modules/co/ContactFormController.java
@@ -25,7 +25,6 @@
 
 package org.olat.modules.co;
 
-import java.io.File;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -41,6 +40,7 @@ import org.olat.core.gui.control.generic.modal.DialogBoxUIFactory;
 import org.olat.core.id.Identity;
 import org.olat.core.id.Roles;
 import org.olat.core.logging.activity.ThreadLocalUserActivityLogger;
+import org.olat.core.util.StringHelper;
 import org.olat.core.util.mail.ContactList;
 import org.olat.core.util.mail.ContactMessage;
 import org.olat.core.util.mail.MailBundle;
@@ -49,6 +49,7 @@ import org.olat.core.util.mail.MailContextImpl;
 import org.olat.core.util.mail.MailHelper;
 import org.olat.core.util.mail.MailLoggingAction;
 import org.olat.core.util.mail.MailManager;
+import org.olat.core.util.mail.MailTemplate;
 import org.olat.core.util.mail.MailerResult;
 import org.springframework.beans.factory.annotation.Autowired;
 
@@ -90,19 +91,31 @@ import org.springframework.beans.factory.annotation.Autowired;
  */
 public class ContactFormController extends BasicController {
 
-	private Identity emailFrom;
-	
 	private ContactForm cntctForm;
 	private DialogBoxController noUsersErrorCtr;
-	private List<String> myButtons;
+
 	private Object userObject;
+	private Identity emailFrom;
+	private MailTemplate template;
 	
 	@Autowired
 	private MailManager mailService;
 	
-	public ContactFormController(UserRequest ureq, WindowControl windowControl, boolean isCanceable, boolean isReadonly, boolean hasRecipientsEditable, ContactMessage cmsg) {
+	/**
+	 * 
+	 * @param ureq The user request
+	 * @param windowControl The window control
+	 * @param isCanceable true if the user can cancel
+	 * @param isReadonly true if the panel is read only and mail cannot be send
+	 * @param hasRecipientsEditable true if the user can edit the recipients
+	 * @param cmsg The message (mandatory)
+	 * @param template A template filled with variables (optional)
+	 */
+	public ContactFormController(UserRequest ureq, WindowControl windowControl, boolean isCanceable, boolean isReadonly, boolean hasRecipientsEditable,
+			ContactMessage cmsg, MailTemplate template) {
 		super(ureq, windowControl);
 		
+		this.template = template;
 		//init email form
 		emailFrom = cmsg.getFrom();
 		
@@ -111,8 +124,17 @@ public class ContactFormController extends BasicController {
 		
 		List<ContactList> recipList = cmsg.getEmailToContactLists();
 		boolean hasAtLeastOneAddress = hasAtLeastOneAddress(recipList);
-		cntctForm.setBody(cmsg.getBodyText());
-		cntctForm.setSubject(cmsg.getSubject());
+		if(StringHelper.containsNonWhitespace(cmsg.getBodyText())) {
+			cntctForm.setBody(cmsg.getBodyText());
+		} else if(template != null && StringHelper.containsNonWhitespace(template.getBodyTemplate())) {
+			cntctForm.setBody(template.getBodyTemplate());
+		}
+		
+		if(StringHelper.containsNonWhitespace(cmsg.getSubject())) {
+			cntctForm.setSubject(cmsg.getSubject());
+		} else if(template != null && StringHelper.containsNonWhitespace(template.getSubjectTemplate())) {
+			cntctForm.setSubject(template.getSubjectTemplate());
+		}
 		
 		//init display component
 		init(ureq, hasAtLeastOneAddress, cmsg.getDisabledIdentities());
@@ -175,13 +197,13 @@ public class ContactFormController extends BasicController {
 			listenTo(mCtr);// to be disposed as this controller gets disposed
 			putInitialPanel(mCtr.getInitialComponent());
 		}
-		if(!hasAtLeastOneAddress | disabledIdentities.size() > 0){
+		if(!hasAtLeastOneAddress || !disabledIdentities.isEmpty()){
 			//show error that message can not be sent
-			myButtons = new ArrayList<>();
+			List<String> myButtons = new ArrayList<>();
 			myButtons.add(translate("back"));
 			String title = "";
 			String message = "";
-			if(disabledIdentities.size() > 0) {
+			if(!disabledIdentities.isEmpty()) {
 				title = MailHelper.getTitleForFailedUsersError(ureq.getLocale());
 				message = MailHelper.getMessageForFailedUsersError(ureq.getLocale(), disabledIdentities);
 			} else {
@@ -215,15 +237,27 @@ public class ContactFormController extends BasicController {
 		}
 	}
 	
+	private MailBundle createBundle(MailerResult result) {
+		MailContext context = new MailContextImpl(getWindowControl().getBusinessControl().getAsString());
+		MailBundle bundle;
+		if(template == null) {
+			bundle = new MailBundle(context);
+			bundle.setContent(cntctForm.getSubject(), cntctForm.getBody(), cntctForm.getAttachments());
+		} else {
+			template.setSubjectTemplate(cntctForm.getSubject());
+			template.setBodyTemplate(cntctForm.getBody());
+			template.setAttachments(cntctForm.getAttachments());
+			bundle = mailService.makeMailBundle(context, null, template, null, null, result);
+		}
+		return bundle;
+	}
+	
 	private void doSend(UserRequest ureq) {
 
-		MailerResult result;
+		MailerResult result = new MailerResult();
 		try {
-			File[] attachments = cntctForm.getAttachments();
-			MailContext context = new MailContextImpl(getWindowControl().getBusinessControl().getAsString());
-			
-			MailBundle bundle = new MailBundle();
-			bundle.setContext(context);
+
+			MailBundle bundle = createBundle(result);
 			if (emailFrom == null) {
 				// in case the user provides his own email in form
 				bundle.setFrom(cntctForm.getEmailFrom()); 
@@ -231,12 +265,12 @@ public class ContactFormController extends BasicController {
 				bundle.setFromId(emailFrom);
 			}
 			bundle.setContactLists(cntctForm.getEmailToContactLists());
-			bundle.setContent(cntctForm.getSubject(), cntctForm.getBody(), attachments);
 			
-			result = mailService.sendMessage(bundle);
+			MailerResult sendResult = mailService.sendMessage(bundle);
+			result.append(sendResult);
+			
 			if(cntctForm.isTcpFrom()) {
-				MailBundle ccBundle = new MailBundle();
-				ccBundle.setContext(context);
+				MailBundle ccBundle = createBundle(result);
 				if (emailFrom == null) {
 					// in case the user provides his own email in form
 					ccBundle.setFrom(cntctForm.getEmailFrom()); 
@@ -245,22 +279,19 @@ public class ContactFormController extends BasicController {
 					ccBundle.setFromId(emailFrom); 
 					ccBundle.setCc(emailFrom);							
 				}
-				ccBundle.setContent(cntctForm.getSubject(), cntctForm.getBody(), attachments);
 				
 				MailerResult ccResult = mailService.sendMessage(ccBundle);
 				result.append(ccResult);
 			}
-			
-			if(result != null) {
-				if (result.isSuccessful()) {
-					showInfo("msg.send.ok");
-					// do logging
-					ThreadLocalUserActivityLogger.log(MailLoggingAction.MAIL_SENT, getClass());
-					fireEvent(ureq, Event.DONE_EVENT);
-				} else {
-					showError(ureq, result);
-					fireEvent(ureq, Event.FAILED_EVENT);
-				}
+
+			if (result.isSuccessful()) {
+				showInfo("msg.send.ok");
+				// do logging
+				ThreadLocalUserActivityLogger.log(MailLoggingAction.MAIL_SENT, getClass());
+				fireEvent(ureq, Event.DONE_EVENT);
+			} else {
+				showError(ureq, result);
+				fireEvent(ureq, Event.FAILED_EVENT);
 			}
 		} catch (Exception e) {
 			logError("", e);
diff --git a/src/main/java/org/olat/modules/coach/ui/StudentCoursesController.java b/src/main/java/org/olat/modules/coach/ui/StudentCoursesController.java
index fd7cd47ec95..9eabe360757 100644
--- a/src/main/java/org/olat/modules/coach/ui/StudentCoursesController.java
+++ b/src/main/java/org/olat/modules/coach/ui/StudentCoursesController.java
@@ -381,7 +381,7 @@ public class StudentCoursesController extends FormBasicController implements Act
 		ContactList contactList = new ContactList(fullName);
 		contactList.add(student);
 		cmsg.addEmailTo(contactList);
-		contactCtrl = new ContactFormController(ureq, getWindowControl(), true, false, false, cmsg);
+		contactCtrl = new ContactFormController(ureq, getWindowControl(), true, false, false, cmsg, null);
 		listenTo(contactCtrl);
 		cmc = new CloseableModalController(getWindowControl(), translate("close"), contactCtrl.getInitialComponent());
 		cmc.activate();
diff --git a/src/main/java/org/olat/modules/lecture/ui/ParticipantLectureBlocksController.java b/src/main/java/org/olat/modules/lecture/ui/ParticipantLectureBlocksController.java
index 302dea76153..4f522c15873 100644
--- a/src/main/java/org/olat/modules/lecture/ui/ParticipantLectureBlocksController.java
+++ b/src/main/java/org/olat/modules/lecture/ui/ParticipantLectureBlocksController.java
@@ -381,7 +381,7 @@ public class ParticipantLectureBlocksController extends FormBasicController {
 		cmsg.addEmailTo(contactList);
 		cmsg.setSubject(translate("appeal.subject", args));
 		cmsg.setBodyText(body.toString());
-		appealCtrl = new ContactFormController(ureq, getWindowControl(), true, false, false, cmsg);
+		appealCtrl = new ContactFormController(ureq, getWindowControl(), true, false, false, cmsg, null);
 		appealCtrl.setUserObject(row);
 		appealCtrl.setContactFormTitle(translate("new.appeal.title"));
 		listenTo(appealCtrl);
diff --git a/src/main/java/org/olat/modules/quality/ui/SuggestionController.java b/src/main/java/org/olat/modules/quality/ui/SuggestionController.java
index 3587b4bf352..f39222d9ef0 100644
--- a/src/main/java/org/olat/modules/quality/ui/SuggestionController.java
+++ b/src/main/java/org/olat/modules/quality/ui/SuggestionController.java
@@ -63,7 +63,7 @@ public class SuggestionController extends BasicController {
 		String emailBody = qualityModule.getSuggestionEmailBody();
 		contactMessage.setBodyText(emailBody);
 
-		contactFormCtrl = new ContactFormController(ureq, getWindowControl(), false, false, false, contactMessage);
+		contactFormCtrl = new ContactFormController(ureq, getWindowControl(), false, false, false, contactMessage, null);
 		contactFormCtrl.setContactFormTitle(translate("suggestion.title"));
 		contactFormCtrl.setContactFormDescription(translate("suggestion.description"));
 		listenTo(contactFormCtrl);
diff --git a/src/main/java/org/olat/registration/DisclaimerController.java b/src/main/java/org/olat/registration/DisclaimerController.java
index 826425fbb2d..3fef4dc6e3a 100644
--- a/src/main/java/org/olat/registration/DisclaimerController.java
+++ b/src/main/java/org/olat/registration/DisclaimerController.java
@@ -263,7 +263,7 @@ public class DisclaimerController extends BasicController {
 		contact.add(mailAddress);
 		contactMessage.addEmailTo(contact);
 
-		contactCtrl = new ContactFormController(ureq, getWindowControl(), true, false, false, contactMessage);
+		contactCtrl = new ContactFormController(ureq, getWindowControl(), true, false, false, contactMessage, null);
 		listenTo(contactCtrl);
 		
 		String title = translate("request.delete.account");
diff --git a/src/main/java/org/olat/registration/RequestAccountDeletionController.java b/src/main/java/org/olat/registration/RequestAccountDeletionController.java
index da3dbc0a82d..4fdcc77f6b8 100644
--- a/src/main/java/org/olat/registration/RequestAccountDeletionController.java
+++ b/src/main/java/org/olat/registration/RequestAccountDeletionController.java
@@ -146,7 +146,7 @@ public class RequestAccountDeletionController extends FormBasicController {
 		contact.add(mailAddress);
 		contactMessage.addEmailTo(contact);
 
-		contactCtrl = new ContactFormController(ureq, getWindowControl(), true, false, false, contactMessage);
+		contactCtrl = new ContactFormController(ureq, getWindowControl(), true, false, false, contactMessage, null);
 		listenTo(contactCtrl);
 		
 		String title = translate("request.delete.account");
diff --git a/src/main/java/org/olat/repository/ui/catalog/CatalogNodeManagerController.java b/src/main/java/org/olat/repository/ui/catalog/CatalogNodeManagerController.java
index c93a54a055e..20fc71ec6a6 100644
--- a/src/main/java/org/olat/repository/ui/catalog/CatalogNodeManagerController.java
+++ b/src/main/java/org/olat/repository/ui/catalog/CatalogNodeManagerController.java
@@ -853,7 +853,7 @@ public class CatalogNodeManagerController extends FormBasicController implements
 		//create e-mail Message
 		ContactMessage cmsg = new ContactMessage(ureq.getIdentity());
 		cmsg.addEmailTo(caretaker);
-		contactCtrl = new ContactFormController(ureq, getWindowControl(), true, false, false, cmsg);
+		contactCtrl = new ContactFormController(ureq, getWindowControl(), true, false, false, cmsg, null);
 		listenTo(contactCtrl);
 		
 		// open form in dialog
diff --git a/src/main/java/org/olat/user/ui/admin/UserSearchTableController.java b/src/main/java/org/olat/user/ui/admin/UserSearchTableController.java
index 602fdc84403..68d4a9b0a4b 100644
--- a/src/main/java/org/olat/user/ui/admin/UserSearchTableController.java
+++ b/src/main/java/org/olat/user/ui/admin/UserSearchTableController.java
@@ -381,7 +381,7 @@ public class UserSearchTableController extends FormBasicController implements Ac
 		cmsg.addEmailTo(contacts);
 
 		// create contact form controller with ContactMessage
-		contactCtr = new ContactFormController(ureq, getWindowControl(), true, false, false, cmsg);
+		contactCtr = new ContactFormController(ureq, getWindowControl(), true, false, false, cmsg, null);
 		listenTo(contactCtr);
 		
 		cmc = new CloseableModalController(getWindowControl(), "close", contactCtr.getInitialComponent(),
diff --git a/src/main/java/org/olat/user/ui/identity/AbstractUserInfoMainController.java b/src/main/java/org/olat/user/ui/identity/AbstractUserInfoMainController.java
index 30c8a9393b8..a78fd886a84 100644
--- a/src/main/java/org/olat/user/ui/identity/AbstractUserInfoMainController.java
+++ b/src/main/java/org/olat/user/ui/identity/AbstractUserInfoMainController.java
@@ -166,7 +166,7 @@ public abstract class AbstractUserInfoMainController extends BasicController {
 		
 		OLATResourceable ores = OresHelper.createOLATResourceableType(CMD_CONTACT);
 		WindowControl bwControl = addToHistory(ureq, ores, null);
-		contactFormController = new ContactFormController(ureq, bwControl, true, false, false, cmsg);
+		contactFormController = new ContactFormController(ureq, bwControl, true, false, false, cmsg, null);
 		listenTo(contactFormController);
 		return contactFormController;
 	}
-- 
GitLab