From 7f25273c51e087bdebdb57ae03b3c434d3bc5333 Mon Sep 17 00:00:00 2001
From: srosse <stephane.rosse@frentix.com>
Date: Tue, 24 Mar 2020 18:41:39 +0100
Subject: [PATCH] OO-4584: add more options to big blue button templates

---
 .../bigbluebutton/BigBlueButtonManager.java   |   2 +-
 .../BigBlueButtonMeetingTemplate.java         |  36 ++++
 .../bigbluebutton/BigBlueButtonModule.java    |  30 ----
 ...leanupJob.java => BigBlueButtonRoles.java} |  25 +--
 .../_spring/bigBlueButtonContext.xml          |  10 --
 .../manager/BigBlueButtonManagerImpl.java     |  35 +++-
 .../manager/BigBlueButtonMeetingDAO.java      |   7 +-
 .../BigBlueButtonMeetingTemplateDAO.java      |   1 +
 .../BigBlueButtonMeetingTemplateImpl.java     | 107 +++++++++++-
 ...BigBlueButtonAdminTemplatesController.java |   3 +
 .../BigBlueButtonConfigurationController.java |  33 +---
 .../ui/BigBlueButtonTemplateTableModel.java   |   4 +
 .../EditBigBlueButtonMeetingController.java   |  47 ++++-
 .../EditBigBlueButtonTemplateController.java  | 165 +++++++++++++-----
 .../ui/TemplateMinuteCellRenderer.java        |  50 ++++++
 .../ui/_i18n/LocalStrings_de.properties       |  12 +-
 .../ui/_i18n/LocalStrings_en.properties       |  12 +-
 .../database/mysql/alter_14_2_x_to_14_2_5.sql |   7 +
 .../database/mysql/setupDatabase.sql          |   9 +-
 .../oracle/alter_14_2_x_to_14_2_5.sql         |   7 +
 .../database/oracle/setupDatabase.sql         |   9 +-
 .../postgresql/alter_14_2_x_to_14_2_5.sql     |   7 +
 .../database/postgresql/setupDatabase.sql     |  11 +-
 .../manager/BigBlueButtonMeetingDAOTest.java  |  18 +-
 24 files changed, 479 insertions(+), 168 deletions(-)
 rename src/main/java/org/olat/modules/bigbluebutton/{manager/BigBlueButtonCleanupJob.java => BigBlueButtonRoles.java} (57%)
 create mode 100644 src/main/java/org/olat/modules/bigbluebutton/ui/TemplateMinuteCellRenderer.java

diff --git a/src/main/java/org/olat/modules/bigbluebutton/BigBlueButtonManager.java b/src/main/java/org/olat/modules/bigbluebutton/BigBlueButtonManager.java
index 766368dadb0..e0a3030259b 100644
--- a/src/main/java/org/olat/modules/bigbluebutton/BigBlueButtonManager.java
+++ b/src/main/java/org/olat/modules/bigbluebutton/BigBlueButtonManager.java
@@ -58,7 +58,7 @@ public interface BigBlueButtonManager {
 	 * @param followupTime Follow-up time
 	 * @return true if the meeting can be reserved
 	 */
-	public boolean isSlotAvailable(BigBlueButtonMeetingTemplate template, Date start, long leadTime, Date end, long followupTime);
+	public boolean isSlotAvailable(BigBlueButtonMeeting meeting, BigBlueButtonMeetingTemplate template, Date start, long leadTime, Date end, long followupTime);
 
 	public BigBlueButtonMeeting getMeeting(BigBlueButtonMeeting meeting);
 	
diff --git a/src/main/java/org/olat/modules/bigbluebutton/BigBlueButtonMeetingTemplate.java b/src/main/java/org/olat/modules/bigbluebutton/BigBlueButtonMeetingTemplate.java
index 7e3f5f72bcf..3d963472499 100644
--- a/src/main/java/org/olat/modules/bigbluebutton/BigBlueButtonMeetingTemplate.java
+++ b/src/main/java/org/olat/modules/bigbluebutton/BigBlueButtonMeetingTemplate.java
@@ -19,6 +19,8 @@
  */
 package org.olat.modules.bigbluebutton;
 
+import java.util.List;
+
 import org.olat.core.id.CreateInfo;
 import org.olat.core.id.ModifiedInfo;
 
@@ -34,6 +36,10 @@ public interface BigBlueButtonMeetingTemplate extends ModifiedInfo, CreateInfo {
 	
 	public boolean isSystem();
 	
+	public boolean isEnabled();
+
+	public void setEnabled(boolean enabled);
+	
 	public String getExternalId();
 	
 	public String getName();
@@ -52,6 +58,20 @@ public interface BigBlueButtonMeetingTemplate extends ModifiedInfo, CreateInfo {
 
 	public void setMaxParticipants(Integer maxParticipants);
 	
+	/**
+	 * @return The maximum duration of a meeting in minutes
+	 */
+	public Integer getMaxDuration();
+
+	/**
+	 * @param maxDuration Set the maximum duration of a meeting in minutes
+	 */
+	public void setMaxDuration(Integer maxDuration);
+	
+	public Boolean getRecord();
+
+	public void setRecord(Boolean record);
+	
 	public Boolean getMuteOnStart();
 
 	public void setMuteOnStart(Boolean muteOnStart);
@@ -96,6 +116,22 @@ public interface BigBlueButtonMeetingTemplate extends ModifiedInfo, CreateInfo {
 
 	public void setLockSettingsLockedLayout(Boolean lockSettingsLockedLayout);
 	
+	public Boolean getLockSettingsHideUserList();
+
+	public void setLockSettingsHideUserList(Boolean lockSettingsHideUserList);
+
+	public Boolean getLockSettingsLockOnJoin();
+
+	public void setLockSettingsLockOnJoin(Boolean lockSettingsLockOnJoin);
+
+	public Boolean getLockSettingsLockOnJoinConfigurable();
+
+	public void setLockSettingsLockOnJoinConfigurable(Boolean lockSettingsLockOnJoinConfigurable);
+	
+	public List<BigBlueButtonRoles> getPermittedRolesEnum();
+	
+	public void setPermittedRolesEnum(List<BigBlueButtonRoles> roles);
+	
 	public GuestPolicyEnum getGuestPolicyEnum();
 
 	public void setGuestPolicyEnum(GuestPolicyEnum guestPolicy);
diff --git a/src/main/java/org/olat/modules/bigbluebutton/BigBlueButtonModule.java b/src/main/java/org/olat/modules/bigbluebutton/BigBlueButtonModule.java
index 232c98d797b..2825e7950a4 100644
--- a/src/main/java/org/olat/modules/bigbluebutton/BigBlueButtonModule.java
+++ b/src/main/java/org/olat/modules/bigbluebutton/BigBlueButtonModule.java
@@ -43,8 +43,6 @@ public class BigBlueButtonModule extends AbstractSpringModule implements ConfigO
 	private static final String PROP_ENABLED = "vc.bigbluebutton.enabled";
 	private static final String PROP_GROUP_ENABLED = "vc.bigbluebutton.groups";
 	private static final String PROP_COURSE_ENABLED = "vc.bigbluebutton.courses";
-	private static final String PROP_CLEAN_MEETINGS = "vc.bigbluebutton.cleanupMeetings";
-	private static final String PROP_DAYS_TO_KEEP = "vc.bigbluebutton.daysToKeep";
 	private static final String PROP_SECRET = "vc.bigbluebutton.secret";
 	private static final String PROP_SHARED_SECRET = "vc.bigbluebutton.shared.secret";
 	private static final String PROP_PROTOCOL = "vc.bigbluebutton.protocol";
@@ -71,10 +69,6 @@ public class BigBlueButtonModule extends AbstractSpringModule implements ConfigO
 	private String groupsEnabled;
 	@Value("${vc.bigbluebutton.courses:true}")
 	private String coursesEnabled;	
-	@Value("${vc.bigbluebutton.cleanupMeetings:false}")
-	private String cleanupMeetings;
-	@Value("${vc.bigbluebutton.daysToKeep:}")
-	private String daysToKeep;
 	@Value("${vc.bigbluebutton.secret}")
 	private String secret;
 	@Value("${vc.bigbluebutton.shared.secret}")
@@ -107,8 +101,6 @@ public class BigBlueButtonModule extends AbstractSpringModule implements ConfigO
 		}
 		baseUrl = getStringPropertyValue(PROP_BASEURL, baseUrl);
 		contextPath = getStringPropertyValue(PROP_CONTEXTPATH, contextPath);
-		cleanupMeetings = getStringPropertyValue(PROP_CLEAN_MEETINGS, cleanupMeetings);
-		daysToKeep = getStringPropertyValue(PROP_DAYS_TO_KEEP, daysToKeep);
 		secret = getStringPropertyValue(PROP_SECRET, secret);
 		sharedSecret = getStringPropertyValue(PROP_SHARED_SECRET, sharedSecret);
 		
@@ -260,28 +252,6 @@ public class BigBlueButtonModule extends AbstractSpringModule implements ConfigO
 		setStringProperty(PROP_SHARED_SECRET, sharedSecret, true);
 	}
 
-	public boolean isCleanupMeetings() {
-		return "true".equals(cleanupMeetings);
-	}
-
-	public void setCleanupMeetings(boolean enable) {
-		cleanupMeetings = enable ? "true" : "false";
-		setStringProperty(PROP_CLEAN_MEETINGS, cleanupMeetings, true);
-	}
-	
-	public long getDaysToKeep() {
-		if(StringHelper.isLong(daysToKeep)) {
-			return Long.parseLong(daysToKeep);
-		}
-		return -1l;
-	}
-	
-	public void setDaysToKeep(String days) {
-		this.daysToKeep = days;
-		setStringProperty(PROP_DAYS_TO_KEEP, days, true);
-		
-	}
-
 	public Double getUserBandwidhtRequirement() {
 		return userBandwidhtRequirement;
 	}
diff --git a/src/main/java/org/olat/modules/bigbluebutton/manager/BigBlueButtonCleanupJob.java b/src/main/java/org/olat/modules/bigbluebutton/BigBlueButtonRoles.java
similarity index 57%
rename from src/main/java/org/olat/modules/bigbluebutton/manager/BigBlueButtonCleanupJob.java
rename to src/main/java/org/olat/modules/bigbluebutton/BigBlueButtonRoles.java
index 262bbb2437c..53c3192410b 100644
--- a/src/main/java/org/olat/modules/bigbluebutton/manager/BigBlueButtonCleanupJob.java
+++ b/src/main/java/org/olat/modules/bigbluebutton/BigBlueButtonRoles.java
@@ -17,28 +17,19 @@
  * frentix GmbH, http://www.frentix.com
  * <p>
  */
-package org.olat.modules.bigbluebutton.manager;
-
-import org.apache.logging.log4j.Logger;
-import org.olat.core.commons.services.scheduler.JobWithDB;
-import org.olat.core.logging.Tracing;
-import org.quartz.DisallowConcurrentExecution;
-import org.quartz.JobExecutionContext;
-import org.quartz.JobExecutionException;
+package org.olat.modules.bigbluebutton;
 
 /**
  * 
- * Initial date: 18 mars 2020<br>
+ * Initial date: 24 mars 2020<br>
  * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
  *
  */
-@DisallowConcurrentExecution
-public class BigBlueButtonCleanupJob extends JobWithDB {
-
-	private static final Logger log = Tracing.createLoggerFor(BigBlueButtonCleanupJob.class);
+public enum BigBlueButtonRoles {
 	
-	@Override
-	public void executeWithDB(JobExecutionContext arg0) throws JobExecutionException {
-		log.info("", "Clean BigBlueButton meetings");
-	}
+	coach,
+	owner,
+	author,
+	administrator
+
 }
diff --git a/src/main/java/org/olat/modules/bigbluebutton/_spring/bigBlueButtonContext.xml b/src/main/java/org/olat/modules/bigbluebutton/_spring/bigBlueButtonContext.xml
index 78d18bf756a..f4ed2086e49 100644
--- a/src/main/java/org/olat/modules/bigbluebutton/_spring/bigBlueButtonContext.xml
+++ b/src/main/java/org/olat/modules/bigbluebutton/_spring/bigBlueButtonContext.xml
@@ -27,14 +27,4 @@
 		</property>
 	</bean>
 	
-	<bean id="bigbluebuttonCleanupTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
-    	<property name="jobDetail" ref="bigbluebuttonConnectCleanupJob" />
-    	<property name="cronExpression" value="0 47 2 * * ?"/>
-    	<property name="startDelay" value="45000" />
-	</bean>
-	
-	<bean id="bigbluebuttonConnectCleanupJob" class="org.springframework.scheduling.quartz.JobDetailFactoryBean" lazy-init="true">
-		<property name="jobClass" value="org.olat.modules.bigbluebutton.manager.BigBlueButtonCleanupJob" />
-	</bean>
-	
 </beans>
\ No newline at end of file
diff --git a/src/main/java/org/olat/modules/bigbluebutton/manager/BigBlueButtonManagerImpl.java b/src/main/java/org/olat/modules/bigbluebutton/manager/BigBlueButtonManagerImpl.java
index 938bb5dc874..1a40c108ea8 100644
--- a/src/main/java/org/olat/modules/bigbluebutton/manager/BigBlueButtonManagerImpl.java
+++ b/src/main/java/org/olat/modules/bigbluebutton/manager/BigBlueButtonManagerImpl.java
@@ -88,37 +88,42 @@ public class BigBlueButtonManagerImpl implements BigBlueButtonManager, Initializ
 		List<BigBlueButtonMeetingTemplate> templates = bigBlueButtonMeetingTemplateDao.getTemplates();
 		
 		// Web conferen
-		defaultTemplate("sys-meetings", "Meetings", 5, 5,
+		defaultTemplate("sys-meetings", "Meetings", 5, 5, 240,
 				Boolean.FALSE, Boolean.FALSE, Boolean.TRUE, // recording
 				Boolean.FALSE, Boolean.TRUE, // webcams moderator only, unmute
 				Boolean.FALSE, Boolean.FALSE, // cam, mic
 				Boolean.FALSE, Boolean.TRUE, // chat
 				Boolean.FALSE, Boolean.FALSE, // node, layout
+				Boolean.FALSE, Boolean.TRUE, Boolean.FALSE,
 				GuestPolicyEnum.ALWAYS_ACCEPT, templates);
 		
-		defaultTemplate("sys-classes", "Classes", 20, 30,
+		defaultTemplate("sys-classes", "Classes", 20, 30, 240,
 				Boolean.FALSE, Boolean.FALSE, Boolean.TRUE, // recording
 				Boolean.TRUE, Boolean.TRUE, // webcamsmoderator only, unmute
 				Boolean.TRUE, Boolean.TRUE, // cam, mic
 				Boolean.FALSE, Boolean.FALSE, // chat
 				Boolean.FALSE, Boolean.FALSE, // node, layout
+				Boolean.FALSE, Boolean.TRUE, Boolean.FALSE,
 				GuestPolicyEnum.ALWAYS_ACCEPT, templates);
 		
-		defaultTemplate("sys-cafe", "Cafe", 10, 10,
+		defaultTemplate("sys-cafe", "Cafe", 10, 10, 240,
 				Boolean.FALSE, Boolean.FALSE, Boolean.TRUE, // recording
 				Boolean.FALSE, Boolean.TRUE, // webcams moderator only, unmute
 				Boolean.FALSE, Boolean.FALSE, // cam, mic
 				Boolean.TRUE, Boolean.FALSE, // chat
 				Boolean.FALSE, Boolean.FALSE, // node, layout
+				Boolean.FALSE, Boolean.TRUE, Boolean.FALSE,
 				GuestPolicyEnum.ALWAYS_ACCEPT, templates);
 	}
 	
-	private void defaultTemplate(String externalId, String name, Integer maxConcurrentMeetings, Integer maxParticipants,
+	private void defaultTemplate(String externalId, String name,
+			Integer maxConcurrentMeetings, Integer maxParticipants, Integer maxDuration,
 			Boolean muteOnStart, Boolean autoStartRecording, Boolean allowStartStopRecording,
 			Boolean webcamsOnlyForModerator, Boolean allowModsToUnmuteUsers,
 			Boolean lockSettingsDisableCam, Boolean lockSettingsDisableMic,
 			Boolean lockSettingsDisablePrivateChat, Boolean lockSettingsDisablePublicChat,
 			Boolean lockSettingsDisableNote, Boolean lockSettingsLockedLayout,
+			Boolean lockSettingsHideUserList, Boolean lockSettingsLockOnJoin, Boolean lockSettingsLockOnJoinConfigurable,
 			GuestPolicyEnum guestPolicy, List<BigBlueButtonMeetingTemplate> templates) {
 		
 		BigBlueButtonMeetingTemplate template = templates.stream()
@@ -131,17 +136,24 @@ public class BigBlueButtonManagerImpl implements BigBlueButtonManager, Initializ
 		template = bigBlueButtonMeetingTemplateDao.createTemplate(name, externalId, true);
 		template.setMaxConcurrentMeetings(maxConcurrentMeetings);
 		template.setMaxParticipants(maxParticipants);
+		template.setMaxDuration(maxDuration);
 		template.setMuteOnStart(muteOnStart);
 		template.setAutoStartRecording(autoStartRecording);
 		template.setAllowStartStopRecording(allowStartStopRecording);
 		template.setWebcamsOnlyForModerator(webcamsOnlyForModerator);
 		template.setAllowModsToUnmuteUsers(allowModsToUnmuteUsers);
+		
 		template.setLockSettingsDisableCam(lockSettingsDisableCam);
 		template.setLockSettingsDisableMic(lockSettingsDisableMic);
 		template.setLockSettingsDisablePrivateChat(lockSettingsDisablePrivateChat);
 		template.setLockSettingsDisablePublicChat(lockSettingsDisablePublicChat);
 		template.setLockSettingsDisableNote(lockSettingsDisableNote);
 		template.setLockSettingsLockedLayout(lockSettingsLockedLayout);
+		
+		template.setLockSettingsHideUserList(lockSettingsHideUserList);
+		template.setLockSettingsLockOnJoin(lockSettingsLockOnJoin);
+		template.setLockSettingsLockOnJoinConfigurable(lockSettingsLockOnJoinConfigurable);
+
 		template.setGuestPolicyEnum(guestPolicy);
 		bigBlueButtonMeetingTemplateDao.updateTemplate(template);
 	}
@@ -152,15 +164,18 @@ public class BigBlueButtonManagerImpl implements BigBlueButtonManager, Initializ
 	}
 	
 	@Override
-	public boolean isSlotAvailable(BigBlueButtonMeetingTemplate template, Date startDate, long leadTime, Date endDate, long followupTime) {
+	public boolean isSlotAvailable(BigBlueButtonMeeting meeting, BigBlueButtonMeetingTemplate template, Date startDate, long leadTime, Date endDate, long followupTime) {
 		if(template == null) return false; // template are mandatory
 		if(template.getMaxConcurrentMeetings() == null) {
 			return true;
 		}
 		Date start = bigBlueButtonMeetingDao.calculateStartWithLeadTime(startDate, leadTime);
 		Date end = bigBlueButtonMeetingDao.calculateEndWithFollowupTime(endDate, followupTime);
-		int numOfCurrentMeetings = bigBlueButtonMeetingDao.getConcurrentMeetings(template, start, end);
-		return numOfCurrentMeetings < template.getMaxConcurrentMeetings().intValue();
+		List<Long> currentMeetings = bigBlueButtonMeetingDao.getConcurrentMeetings(template, start, end);
+		if(meeting != null && currentMeetings.contains(meeting.getKey())) {
+			return true; // it's my slot
+		}
+		return currentMeetings.size() < template.getMaxConcurrentMeetings().intValue();
 	}
 
 	@Override
@@ -380,7 +395,7 @@ public class BigBlueButtonManagerImpl implements BigBlueButtonManager, Initializ
 		if(template != null) {
 			uriBuilder
 				.optionalParameter("maxParticipants", template.getMaxParticipants().intValue() + 1)
-				.optionalParameter("record", "true")
+				.optionalParameter("record", template.getRecord())
 				// video options
 				.optionalParameter("muteOnStart", template.getMuteOnStart())
 				.optionalParameter("autoStartRecording", template.getAutoStartRecording())
@@ -394,6 +409,10 @@ public class BigBlueButtonManagerImpl implements BigBlueButtonManager, Initializ
 				.optionalParameter("lockSettingsDisablePublicChat", template.getLockSettingsDisablePublicChat())
 				.optionalParameter("lockSettingsDisableNote", template.getLockSettingsDisableNote())
 				.optionalParameter("lockSettingsLockedLayout", template.getLockSettingsLockedLayout())
+				// lock settings undocumented
+				.optionalParameter("lockSettingsHideUserList", template.getLockSettingsHideUserList())
+				.optionalParameter("lockSettingsLockOnJoin", template.getLockSettingsLockOnJoin())
+				.optionalParameter("lockSettingsLockOnJoinConfigurable", template.getLockSettingsLockOnJoinConfigurable())
 				// guest policy
 				.optionalParameter("guestPolicy", GuestPolicyEnum.ALWAYS_ACCEPT.name());
 		}
diff --git a/src/main/java/org/olat/modules/bigbluebutton/manager/BigBlueButtonMeetingDAO.java b/src/main/java/org/olat/modules/bigbluebutton/manager/BigBlueButtonMeetingDAO.java
index 58fbf824e11..2b14f332bc9 100644
--- a/src/main/java/org/olat/modules/bigbluebutton/manager/BigBlueButtonMeetingDAO.java
+++ b/src/main/java/org/olat/modules/bigbluebutton/manager/BigBlueButtonMeetingDAO.java
@@ -161,9 +161,9 @@ public class BigBlueButtonMeetingDAO {
 				.getResultList();
 	}
 	
-	public int getConcurrentMeetings(BigBlueButtonMeetingTemplate template, Date start, Date end) {
+	public List<Long> getConcurrentMeetings(BigBlueButtonMeetingTemplate template, Date start, Date end) {
 		QueryBuilder sb = new QueryBuilder();
-		sb.append("select count(distinct meeting.key) from bigbluebuttonmeeting as meeting")
+		sb.append("select distinct meeting.key from bigbluebuttonmeeting as meeting")
 		  .append(" inner join meeting.template as template")
 		  .append(" where template.key=:templateKey")
 		  .append(" and (")
@@ -175,13 +175,12 @@ public class BigBlueButtonMeetingDAO {
 		  .append("  or")
 		  .append("  (meeting.startWithLeadTime<=:startDate and meeting.endWithFollowupTime>=:endDate)")
 		  .append(")");
-		List<Long> count = dbInstance.getCurrentEntityManager()
+		return dbInstance.getCurrentEntityManager()
 				.createQuery(sb.toString(), Long.class)
 				.setParameter("templateKey", template.getKey())
 				.setParameter("startDate", start)
 				.setParameter("endDate", end)
 				.getResultList();
-		return count == null || count.isEmpty() || count.get(0) == null ? 0 : count.get(0).intValue();
 	}
 	
 	public List<BigBlueButtonMeeting> getMeetings(RepositoryEntryRef entry, String subIdent, BusinessGroup businessGroup) {
diff --git a/src/main/java/org/olat/modules/bigbluebutton/manager/BigBlueButtonMeetingTemplateDAO.java b/src/main/java/org/olat/modules/bigbluebutton/manager/BigBlueButtonMeetingTemplateDAO.java
index 065eae80974..82c3ee6a0af 100644
--- a/src/main/java/org/olat/modules/bigbluebutton/manager/BigBlueButtonMeetingTemplateDAO.java
+++ b/src/main/java/org/olat/modules/bigbluebutton/manager/BigBlueButtonMeetingTemplateDAO.java
@@ -47,6 +47,7 @@ public class BigBlueButtonMeetingTemplateDAO {
 		template.setLastModified(template.getCreationDate());
 		template.setName(name);
 		template.setSystem(system);
+		template.setEnabled(true);
 		template.setExternalId(externalId);
 		dbInstance.getCurrentEntityManager().persist(template);
 		return template;
diff --git a/src/main/java/org/olat/modules/bigbluebutton/model/BigBlueButtonMeetingTemplateImpl.java b/src/main/java/org/olat/modules/bigbluebutton/model/BigBlueButtonMeetingTemplateImpl.java
index ccef9cdc0b2..328155bd453 100644
--- a/src/main/java/org/olat/modules/bigbluebutton/model/BigBlueButtonMeetingTemplateImpl.java
+++ b/src/main/java/org/olat/modules/bigbluebutton/model/BigBlueButtonMeetingTemplateImpl.java
@@ -20,6 +20,7 @@
 package org.olat.modules.bigbluebutton.model;
 
 import java.util.Date;
+import java.util.List;
 
 import javax.persistence.Column;
 import javax.persistence.Entity;
@@ -33,6 +34,7 @@ import javax.persistence.TemporalType;
 import org.olat.core.id.Persistable;
 import org.olat.core.util.StringHelper;
 import org.olat.modules.bigbluebutton.BigBlueButtonMeetingTemplate;
+import org.olat.modules.bigbluebutton.BigBlueButtonRoles;
 import org.olat.modules.bigbluebutton.GuestPolicyEnum;
 
 /**
@@ -65,6 +67,8 @@ public class BigBlueButtonMeetingTemplateImpl implements Persistable, BigBlueBut
 	private String description;
 	@Column(name="b_system", nullable=false, insertable=true, updatable=false)
 	private boolean system;
+	@Column(name="b_enabled", nullable=false, insertable=true, updatable=true)
+	private boolean enabled;
 	@Column(name="b_external_id", nullable=true, insertable=true, updatable=true)
 	private String externalId;
 	
@@ -73,9 +77,14 @@ public class BigBlueButtonMeetingTemplateImpl implements Persistable, BigBlueBut
 	
 	@Column(name="b_max_participants", nullable=true, insertable=true, updatable=true)
 	private Integer maxParticipants;
-
+	@Column(name="b_max_duration", nullable=true, insertable=true, updatable=true)
+	private Integer maxDuration;
+	
 	@Column(name="b_mute_on_start", nullable=true, insertable=true, updatable=true)
 	private Boolean muteOnStart;
+	
+	@Column(name="b_record", nullable=true, insertable=true, updatable=true)
+	private Boolean record;
 	@Column(name="b_auto_start_recording", nullable=true, insertable=true, updatable=true)
 	private Boolean autoStartRecording;
 	@Column(name="b_allow_start_stop_recording", nullable=true, insertable=true, updatable=true)
@@ -98,6 +107,16 @@ public class BigBlueButtonMeetingTemplateImpl implements Persistable, BigBlueBut
 	@Column(name="b_lock_set_locked_layout", nullable=true, insertable=true, updatable=true)
 	private Boolean lockSettingsLockedLayout;
 	
+	@Column(name="b_lock_set_hide_user_list", nullable=true, insertable=true, updatable=true)
+	private Boolean lockSettingsHideUserList;
+	@Column(name="b_lock_set_lock_on_join", nullable=true, insertable=true, updatable=true)
+	private Boolean lockSettingsLockOnJoin;
+	@Column(name="b_lock_set_lock_on_join_conf", nullable=true, insertable=true, updatable=true)
+	private Boolean lockSettingsLockOnJoinConfigurable;
+	
+	@Column(name="b_permitted_roles", nullable=true, insertable=true, updatable=true)
+	private String permittedRoles;
+
 	@Column(name="b_guest_policy", nullable=true, insertable=true, updatable=true)
 	private String guestPolicy;
 	
@@ -159,6 +178,16 @@ public class BigBlueButtonMeetingTemplateImpl implements Persistable, BigBlueBut
 		this.system = system;
 	}
 
+	@Override
+	public boolean isEnabled() {
+		return enabled;
+	}
+
+	@Override
+	public void setEnabled(boolean enabled) {
+		this.enabled = enabled;
+	}
+
 	@Override
 	public String getExternalId() {
 		return externalId;
@@ -188,6 +217,26 @@ public class BigBlueButtonMeetingTemplateImpl implements Persistable, BigBlueBut
 		this.maxParticipants = maxParticipants;
 	}
 
+	@Override
+	public Integer getMaxDuration() {
+		return maxDuration;
+	}
+
+	@Override
+	public void setMaxDuration(Integer maxDuration) {
+		this.maxDuration = maxDuration;
+	}
+
+	@Override
+	public Boolean getRecord() {
+		return record;
+	}
+
+	@Override
+	public void setRecord(Boolean record) {
+		this.record = record;
+	}
+
 	@Override
 	public Boolean getMuteOnStart() {
 		return muteOnStart;
@@ -297,6 +346,58 @@ public class BigBlueButtonMeetingTemplateImpl implements Persistable, BigBlueBut
 	public void setLockSettingsLockedLayout(Boolean lockSettingsLockedLayout) {
 		this.lockSettingsLockedLayout = lockSettingsLockedLayout;
 	}
+	
+	@Override
+	public Boolean getLockSettingsHideUserList() {
+		return lockSettingsHideUserList;
+	}
+
+	@Override
+	public void setLockSettingsHideUserList(Boolean lockSettingsHideUserList) {
+		this.lockSettingsHideUserList = lockSettingsHideUserList;
+	}
+
+	@Override
+	public Boolean getLockSettingsLockOnJoin() {
+		return lockSettingsLockOnJoin;
+	}
+
+	@Override
+	public void setLockSettingsLockOnJoin(Boolean lockSettingsLockOnJoin) {
+		this.lockSettingsLockOnJoin = lockSettingsLockOnJoin;
+	}
+
+	@Override
+	public Boolean getLockSettingsLockOnJoinConfigurable() {
+		return lockSettingsLockOnJoinConfigurable;
+	}
+
+	@Override
+	public void setLockSettingsLockOnJoinConfigurable(Boolean lockSettingsLockOnJoinConfigurable) {
+		this.lockSettingsLockOnJoinConfigurable = lockSettingsLockOnJoinConfigurable;
+	}
+
+	public String getPermittedRoles() {
+		return permittedRoles;
+	}
+
+	public void setPermittedRoles(String permittedRoles) {
+		this.permittedRoles = permittedRoles;
+	}
+
+	@Override
+	public List<BigBlueButtonRoles> getPermittedRolesEnum() {
+		return null;
+	}
+
+	@Override
+	public void setPermittedRolesEnum(List<BigBlueButtonRoles> roles) {
+		if(roles == null || roles.isEmpty()) {
+			setPermittedRoles(null);
+		} else {
+			
+		}
+	}
 
 	public String getGuestPolicy() {
 		return guestPolicy;
@@ -305,7 +406,8 @@ public class BigBlueButtonMeetingTemplateImpl implements Persistable, BigBlueBut
 	public void setGuestPolicy(String guestPolicy) {
 		this.guestPolicy = guestPolicy;
 	}
-	
+
+	@Override
 	public GuestPolicyEnum getGuestPolicyEnum() {
 		if(StringHelper.containsNonWhitespace(guestPolicy)) {
 			return GuestPolicyEnum.valueOf(guestPolicy);
@@ -313,6 +415,7 @@ public class BigBlueButtonMeetingTemplateImpl implements Persistable, BigBlueBut
 		return GuestPolicyEnum.ALWAYS_DENY;
 	}
 
+	@Override
 	public void setGuestPolicyEnum(GuestPolicyEnum guestPolicy) {
 		if(guestPolicy == null) {
 			this.guestPolicy = GuestPolicyEnum.ALWAYS_DENY.name();
diff --git a/src/main/java/org/olat/modules/bigbluebutton/ui/BigBlueButtonAdminTemplatesController.java b/src/main/java/org/olat/modules/bigbluebutton/ui/BigBlueButtonAdminTemplatesController.java
index 58a22151c9e..2924526e8a6 100644
--- a/src/main/java/org/olat/modules/bigbluebutton/ui/BigBlueButtonAdminTemplatesController.java
+++ b/src/main/java/org/olat/modules/bigbluebutton/ui/BigBlueButtonAdminTemplatesController.java
@@ -83,8 +83,11 @@ public class BigBlueButtonAdminTemplatesController extends FormBasicController {
 		FlexiTableColumnModel columnsModel = FlexiTableDataModelFactory.createFlexiTableColumnModel();
 		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(BTemplatesCols.name));
 		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(BTemplatesCols.system));
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(BTemplatesCols.enabled));
 		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(BTemplatesCols.maxConcurrentMeetings));
 		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(BTemplatesCols.maxParticipants));
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(BTemplatesCols.maxDuration,
+				new TemplateMinuteCellRenderer(getTranslator())));
 		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(BTemplatesCols.webcamsOnlyForModerator));
 		if(readOnly) {
 			columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel("view", translate("view"), "view"));
diff --git a/src/main/java/org/olat/modules/bigbluebutton/ui/BigBlueButtonConfigurationController.java b/src/main/java/org/olat/modules/bigbluebutton/ui/BigBlueButtonConfigurationController.java
index 4f745ec6585..7687ed7b942 100644
--- a/src/main/java/org/olat/modules/bigbluebutton/ui/BigBlueButtonConfigurationController.java
+++ b/src/main/java/org/olat/modules/bigbluebutton/ui/BigBlueButtonConfigurationController.java
@@ -21,7 +21,6 @@ package org.olat.modules.bigbluebutton.ui;
 
 import java.net.URI;
 import java.net.URISyntaxException;
-import java.util.Arrays;
 
 import org.olat.collaboration.CollaborationToolsFactory;
 import org.olat.core.gui.UserRequest;
@@ -29,7 +28,6 @@ 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.FormLink;
 import org.olat.core.gui.components.form.flexible.elements.MultipleSelectionElement;
-import org.olat.core.gui.components.form.flexible.elements.SingleSelection;
 import org.olat.core.gui.components.form.flexible.elements.SpacerElement;
 import org.olat.core.gui.components.form.flexible.elements.TextElement;
 import org.olat.core.gui.components.form.flexible.impl.FormBasicController;
@@ -53,7 +51,6 @@ import org.springframework.beans.factory.annotation.Autowired;
  */
 public class BigBlueButtonConfigurationController extends FormBasicController {
 
-	private static final String[] CLEAN_KEYS = { "-", "1", "2", "3", "4", "5", "7", "14", "21", "30" };
 	private static final String[] FOR_KEYS = { "courses", "groups" };
 	private static final String PLACEHOLDER = "xxx-placeholder-xxx";
 	
@@ -61,7 +58,6 @@ public class BigBlueButtonConfigurationController extends FormBasicController {
 	private TextElement urlEl;
 	private SpacerElement spacerEl;
 	private TextElement sharedSecretEl;
-	private SingleSelection cleanMeetingsEl;
 	private MultipleSelectionElement moduleEnabled;
 	private MultipleSelectionElement enabledForEl;
 	private MultipleSelectionElement permanentForEl;
@@ -106,7 +102,8 @@ public class BigBlueButtonConfigurationController extends FormBasicController {
 		
 		adhocForEl = uifactory.addCheckboxesHorizontal("enable.adhoc.meeting", formLayout, enabledKeys, enabledValues);
 		adhocForEl.select(enabledKeys[0], bigBlueButtonModule.isAdhocMeetingEnabled());
-
+		adhocForEl.setVisible(false);//TODO bbb
+		
 		//spacer
 		spacerEl = uifactory.addSpacerElement("spacer", formLayout, false);
 
@@ -123,22 +120,7 @@ public class BigBlueButtonConfigurationController extends FormBasicController {
 		}
 		sharedSecretEl = uifactory.addPasswordElement("shared.secret", "option.bigbluebutton.shared.secret", 255, sharedSecret, formLayout);
 		sharedSecretEl.setAutocomplete("new-password");
-		
-		// delete meeting
-		String[] cleanValues = Arrays.copyOf(CLEAN_KEYS, CLEAN_KEYS.length);
-		cleanValues[0] = translate("option.dont.clean.meetings");
-		cleanMeetingsEl = uifactory.addDropdownSingleselect("option.clean.meetings", formLayout, CLEAN_KEYS, cleanValues);
-		if(bigBlueButtonModule.isCleanupMeetings()) {
-			long days = bigBlueButtonModule.getDaysToKeep();
-			String dayStr = Long.toString(days);
-			for(String key:CLEAN_KEYS) {
-				if(dayStr.equals(key)) {
-					cleanMeetingsEl.select(key, true);
-				}
-			}
-		} else {
-			cleanMeetingsEl.select(CLEAN_KEYS[0], true);
-		}
+
 		
 		//buttons save - check
 		FormLayoutContainer buttonLayout = FormLayoutContainer.createButtonLayout("save", getTranslator());
@@ -161,7 +143,6 @@ public class BigBlueButtonConfigurationController extends FormBasicController {
 		urlEl.setVisible(enabled);
 		sharedSecretEl.setVisible(enabled);
 		spacerEl.setVisible(enabled);
-		cleanMeetingsEl.setVisible(enabled);
 	}
 	
 	@Override
@@ -249,14 +230,6 @@ public class BigBlueButtonConfigurationController extends FormBasicController {
 				bigBlueButtonModule.setGroupsEnabled(enabledForEl.isSelected(1));
 				bigBlueButtonModule.setPermanentMeetingEnabled(permanentForEl.isAtLeastSelected(1));
 				bigBlueButtonModule.setAdhocMeetingEnabled(adhocForEl.isAtLeastSelected(1));
-
-				if(cleanMeetingsEl.isSelected(0)) {
-					bigBlueButtonModule.setCleanupMeetings(false);
-					bigBlueButtonModule.setDaysToKeep(null);
-				} else {
-					bigBlueButtonModule.setCleanupMeetings(true);
-					bigBlueButtonModule.setDaysToKeep(cleanMeetingsEl.getSelectedKey());
-				}
 				
 				String sharedSecret = sharedSecretEl.getValue();
 				if(!PLACEHOLDER.equals(sharedSecret)) {
diff --git a/src/main/java/org/olat/modules/bigbluebutton/ui/BigBlueButtonTemplateTableModel.java b/src/main/java/org/olat/modules/bigbluebutton/ui/BigBlueButtonTemplateTableModel.java
index 65f46b2dadc..eb48b4f28b9 100644
--- a/src/main/java/org/olat/modules/bigbluebutton/ui/BigBlueButtonTemplateTableModel.java
+++ b/src/main/java/org/olat/modules/bigbluebutton/ui/BigBlueButtonTemplateTableModel.java
@@ -67,8 +67,10 @@ implements SortableFlexiTableDataModel<BigBlueButtonMeetingTemplate> {
 		switch(COLS[col]) {
 			case name: return row.getName();
 			case system: return Boolean.valueOf(row.isSystem());
+			case enabled: return Boolean.valueOf(row.isEnabled());
 			case maxConcurrentMeetings: return row.getMaxConcurrentMeetings();
 			case maxParticipants: return row.getMaxParticipants();
+			case maxDuration: return row.getMaxDuration();
 			case webcamsOnlyForModerator: return row.getWebcamsOnlyForModerator();
 			default: return "ERROR";
 		}
@@ -83,8 +85,10 @@ implements SortableFlexiTableDataModel<BigBlueButtonMeetingTemplate> {
 		
 		name("meeting.name"),
 		system("table.header.system"),
+		enabled("table.header.enabled"),
 		maxConcurrentMeetings("table.header.max.concurrent.meetings"),
 		maxParticipants("table.header.max.participants"),
+		maxDuration("table.header.max.duration"),
 		webcamsOnlyForModerator("table.header.webcams.only.moderator");
 		
 		private final String i18nHeaderKey;
diff --git a/src/main/java/org/olat/modules/bigbluebutton/ui/EditBigBlueButtonMeetingController.java b/src/main/java/org/olat/modules/bigbluebutton/ui/EditBigBlueButtonMeetingController.java
index 6d0bbd2a586..d4d9e4d5a5d 100644
--- a/src/main/java/org/olat/modules/bigbluebutton/ui/EditBigBlueButtonMeetingController.java
+++ b/src/main/java/org/olat/modules/bigbluebutton/ui/EditBigBlueButtonMeetingController.java
@@ -115,9 +115,13 @@ public class EditBigBlueButtonMeetingController extends FormBasicController {
 		String welcome = meeting == null ? "" : meeting.getWelcome();
 		welcomeEl = uifactory.addRichTextElementForStringDataMinimalistic("meeting.welcome", "meeting.welcome", welcome, 8, 60, formLayout, getWindowControl());
 		
+		Long selectedTemplateKey = meeting == null || meeting.getTemplate() == null
+				? null : meeting.getTemplate().getKey();
 		KeyValues templatesKeyValues = new KeyValues();
 		for(BigBlueButtonMeetingTemplate template:templates) {
-			templatesKeyValues.add(KeyValues.entry(template.getKey().toString(), template.getName()));
+			if(template.isEnabled() || template.getKey().equals(selectedTemplateKey)) {
+				templatesKeyValues.add(KeyValues.entry(template.getKey().toString(), template.getName()));
+			}
 		}
 		String[] templatesKeys = templatesKeyValues.keys();
 		templateEl = uifactory.addDropdownSingleselect("meeting.template", "meeting.template", formLayout,
@@ -125,8 +129,8 @@ public class EditBigBlueButtonMeetingController extends FormBasicController {
 		templateEl.addActionListener(FormEvent.ONCHANGE);
 		templateEl.setMandatory(true);
 		boolean templateSelected = false;
-		if(meeting != null && meeting.getTemplate() != null) {
-			String currentTemplateId = meeting.getTemplate().getKey().toString();
+		if(selectedTemplateKey != null) {
+			String currentTemplateId = selectedTemplateKey.toString();
 			for(String key:templatesKeys) {
 				if(currentTemplateId.equals(key)) {
 					templateEl.select(currentTemplateId, true);
@@ -241,11 +245,8 @@ public class EditBigBlueButtonMeetingController extends FormBasicController {
 		
 		// dates ok
 		if(allOk && (!permanentEl.isVisible() || !permanentEl.isAtLeastSelected(1))) {
-			boolean canMeeting = validateSlot();
-			if(!canMeeting) {
-				startDateEl.setErrorKey("server.overloaded", null);
-				allOk &= false;
-			}
+			allOk &= validateDuration();
+			allOk &= validateSlot();
 		}
 		
 		nameEl.clearError();
@@ -269,10 +270,38 @@ public class EditBigBlueButtonMeetingController extends FormBasicController {
 		return allOk;
 	}
 	
+	private boolean validateDuration() {
+		boolean allOk = true;
+		
+		BigBlueButtonMeetingTemplate template = getSelectedTemplate();
+		Date start = startDateEl.getDate();
+		Date end = endDateEl.getDate();
+		if(template != null && template.getMaxDuration() != null && start != null && end != null) {
+			// all calculation in milli-seconds
+			long realStart = start.getTime() - (60 * 1000 * getLeadTime());
+			long realEnd = end.getTime() + (60 * 1000 * getFollowupTime());
+			long duration = realEnd - realStart;
+			long maxDuration  = (60 * 1000 * template.getMaxDuration());
+			if(duration > maxDuration) {
+				endDateEl.setErrorKey("error.duration", new String[] { template.getMaxDuration().toString() });
+				allOk &= false;
+			}
+		}
+		return allOk;
+	}
+	
 	private boolean validateSlot() {
+		boolean allOk = true;
+		
 		BigBlueButtonMeetingTemplate template = getSelectedTemplate();
-		return bigBlueButtonManager.isSlotAvailable(template,
+		boolean slotFree = bigBlueButtonManager.isSlotAvailable(meeting, template,
 				startDateEl.getDate(), getLeadTime(), endDateEl.getDate(), getFollowupTime());
+		if(!slotFree) {
+			startDateEl.setErrorKey("server.overloaded", null);
+			allOk &= false;
+		}
+		
+		return allOk;
 	}
 	
 	private BigBlueButtonMeetingTemplate getSelectedTemplate() {
diff --git a/src/main/java/org/olat/modules/bigbluebutton/ui/EditBigBlueButtonTemplateController.java b/src/main/java/org/olat/modules/bigbluebutton/ui/EditBigBlueButtonTemplateController.java
index e995361f8df..de560d92bf2 100644
--- a/src/main/java/org/olat/modules/bigbluebutton/ui/EditBigBlueButtonTemplateController.java
+++ b/src/main/java/org/olat/modules/bigbluebutton/ui/EditBigBlueButtonTemplateController.java
@@ -20,12 +20,14 @@
 package org.olat.modules.bigbluebutton.ui;
 
 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.MultipleSelectionElement;
 import org.olat.core.gui.components.form.flexible.elements.SingleSelection;
 import org.olat.core.gui.components.form.flexible.elements.TextElement;
 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.util.KeyValues;
 import org.olat.core.gui.control.Controller;
 import org.olat.core.gui.control.Event;
 import org.olat.core.gui.control.WindowControl;
@@ -42,18 +44,25 @@ import org.springframework.beans.factory.annotation.Autowired;
  */
 public class EditBigBlueButtonTemplateController extends FormBasicController {
 
-	private static final String[] maxParticipantsKeys = new String[] { "2", "5", "10", "25", "50", "100" };
-	private static final String[] onKeys = new String[] { "yes", "no" };
+	private static final String[] yesNoKeys = new String[] { "yes", "no" };
+	private static final String[] onKeys = new String[] { "on" };
 	
 	private TextElement nameEl;
 	private TextElement descriptionEl;
+	
+	private MultipleSelectionElement enableEl;
+	
 	private TextElement maxConcurrentMeetingsEl;
+	private TextElement maxParticipantsEl;
+	private TextElement maxDurationEl;
+	
+	private SingleSelection recordEl;
 	private SingleSelection muteOnStartEl;
-	private SingleSelection maxParticipantsEl;
 	private SingleSelection autoStartRecordingEl;
 	private SingleSelection allowStartStopRecordingEl;
 	private SingleSelection webcamsOnlyForModeratorEl;
 	private SingleSelection allowModsToUnmuteUsersEl;
+	
 	private SingleSelection lockSettingsDisableCamEl;
 	private SingleSelection lockSettingsDisableMicEl;
 	private SingleSelection lockSettingsDisablePrivateChatEl;
@@ -61,6 +70,10 @@ public class EditBigBlueButtonTemplateController extends FormBasicController {
 	private SingleSelection lockSettingsDisableNoteEl;
 	private SingleSelection lockSettingsLockedLayoutEl;
 	
+	private SingleSelection lockSettingsHideUserListEl;
+	private SingleSelection lockSettingsLockOnJoinEl;
+	private SingleSelection lockSettingsLockOnJoinConfigurableEl;
+	
 	private final boolean readOnly;
 	private BigBlueButtonMeetingTemplate template;
 	
@@ -71,6 +84,7 @@ public class EditBigBlueButtonTemplateController extends FormBasicController {
 		super(ureq, wControl);
 		readOnly = false;
 		initForm(ureq);
+		updateUI();
 	}
 	
 	public EditBigBlueButtonTemplateController(UserRequest ureq, WindowControl wControl,
@@ -79,6 +93,7 @@ public class EditBigBlueButtonTemplateController extends FormBasicController {
 		this.readOnly = readOnly;
 		this.template = template;
 		initForm(ureq);
+		updateUI();
 	}
 
 	@Override
@@ -93,67 +108,84 @@ public class EditBigBlueButtonTemplateController extends FormBasicController {
 		String description = template == null ? "" : template.getDescription();
 		descriptionEl = uifactory.addTextAreaElement("template.description", "template.description", 2000, 4, 72, false, false, description, formLayout);
 		
+		boolean enable = template == null || template.isEnabled();
+		enableEl = uifactory.addCheckboxesHorizontal("template.enabled", "template.enabled", formLayout, onKeys, new String[] { "" });
+		enableEl.select(onKeys[0], enable);
+		
 		String maxConcurrentMeetings = template == null || template.getMaxConcurrentMeetings() == null ? "" : template.getMaxConcurrentMeetings().toString();
 		maxConcurrentMeetingsEl = uifactory.addTextElement("template.max.concurrent.meetings", "template.max.concurrent.meetings", 8, maxConcurrentMeetings, formLayout);
 		
-		String maxParticipants = template == null || template.getMaxParticipants() == null ? "5" : template.getMaxParticipants().toString();
-		KeyValues maxParticipantsKeyValues = new KeyValues();
-		for(String maxParticipantsKey:maxParticipantsKeys) {
-			maxParticipantsKeyValues.add(KeyValues.entry(maxParticipantsKey, maxParticipantsKey));
-		}
-		if(!maxParticipantsKeyValues.containsKey(maxParticipants)) {
-			maxParticipantsKeyValues.add(KeyValues.entry(maxParticipants, maxParticipants));
-		}
-		maxParticipantsEl = uifactory.addDropdownSingleselect("template.maxParticipants", formLayout,
-				maxParticipantsKeyValues.keys(), maxParticipantsKeyValues.values());
-		maxParticipantsEl.select(maxParticipants, true);
+		String maxParticipants = template == null || template.getMaxParticipants() == null ? null : template.getMaxParticipants().toString();
+		maxParticipantsEl = uifactory.addTextElement("template.maxParticipants", "template.maxParticipants", 8, maxParticipants, formLayout);
+		maxParticipantsEl.setMandatory(true);
 		
+		String maxDuration = template == null || template.getMaxDuration() == null ? null : template.getMaxDuration().toString();
+		maxDurationEl = uifactory.addTextElement("template.maxDuration", "template.maxDuration", 8, maxDuration, formLayout);
+
 		String[] onValues = new String[] { translate("yes"), translate("no")  };
 		
-		Boolean muteOnStart = template == null ? null : template.getMuteOnStart();
-		muteOnStartEl = uifactory.addRadiosHorizontal("template.muteOnStart", formLayout, onKeys, onValues);
-		select(muteOnStart, muteOnStartEl, false);
+		Boolean record = template == null ? null : template.getRecord();
+		recordEl = uifactory.addRadiosHorizontal("template.record", formLayout, yesNoKeys, onValues);
+		recordEl.addActionListener(FormEvent.ONCHANGE);
+		select(record, recordEl, false);
 		
 		Boolean autoStartRecording = template == null ? null : template.getAutoStartRecording();
-		autoStartRecordingEl = uifactory.addRadiosHorizontal("template.autoStartRecording", formLayout, onKeys, onValues);
+		autoStartRecordingEl = uifactory.addRadiosHorizontal("template.autoStartRecording", formLayout, yesNoKeys, onValues);
 		select(autoStartRecording, autoStartRecordingEl, false);
 		
 		Boolean allowStartStopRecording = template == null ? null : template.getAllowStartStopRecording();
-		allowStartStopRecordingEl = uifactory.addRadiosHorizontal("template.allowStartStopRecording", formLayout, onKeys, onValues);
+		allowStartStopRecordingEl = uifactory.addRadiosHorizontal("template.allowStartStopRecording", formLayout, yesNoKeys, onValues);
 		select(allowStartStopRecording, allowStartStopRecordingEl, true);
 		
+		Boolean muteOnStart = template == null ? null : template.getMuteOnStart();
+		muteOnStartEl = uifactory.addRadiosHorizontal("template.muteOnStart", formLayout, yesNoKeys, onValues);
+		select(muteOnStart, muteOnStartEl, false);
+		
 		Boolean webcamsOnlyForModerator = template == null ? null : template.getWebcamsOnlyForModerator();
-		webcamsOnlyForModeratorEl = uifactory.addRadiosHorizontal("template.webcamsOnlyForModerator", formLayout, onKeys, onValues);
+		webcamsOnlyForModeratorEl = uifactory.addRadiosHorizontal("template.webcamsOnlyForModerator", formLayout, yesNoKeys, onValues);
 		select(webcamsOnlyForModerator, webcamsOnlyForModeratorEl, true);
 		
 		Boolean allowModsToUnmuteUsers = template == null ? null : template.getAllowModsToUnmuteUsers();
-		allowModsToUnmuteUsersEl = uifactory.addRadiosHorizontal("template.allowModsToUnmuteUsers", formLayout, onKeys, onValues);
+		allowModsToUnmuteUsersEl = uifactory.addRadiosHorizontal("template.allowModsToUnmuteUsers", formLayout, yesNoKeys, onValues);
 		select(allowModsToUnmuteUsers, allowModsToUnmuteUsersEl, false);
 		
 		Boolean lockSettingsDisableCam = template == null ? null : template.getLockSettingsDisableCam();
-		lockSettingsDisableCamEl = uifactory.addRadiosHorizontal("template.lockSettingsDisableCam", formLayout, onKeys, onValues);
+		lockSettingsDisableCamEl = uifactory.addRadiosHorizontal("template.lockSettingsDisableCam", formLayout, yesNoKeys, onValues);
 		select(lockSettingsDisableCam, lockSettingsDisableCamEl, false);
 		
 		Boolean lockSettingsDisableMic = template == null ? null : template.getLockSettingsDisableMic();
-		lockSettingsDisableMicEl = uifactory.addRadiosHorizontal("template.lockSettingsDisableMic", formLayout, onKeys, onValues);
+		lockSettingsDisableMicEl = uifactory.addRadiosHorizontal("template.lockSettingsDisableMic", formLayout, yesNoKeys, onValues);
 		select(lockSettingsDisableMic, lockSettingsDisableMicEl, false);
 		
 		Boolean lockSettingsDisablePrivateChat = template == null ? null : template.getLockSettingsDisablePrivateChat();
-		lockSettingsDisablePrivateChatEl =  uifactory.addRadiosHorizontal("template.lockSettingsDisablePrivateChat", formLayout, onKeys, onValues);
+		lockSettingsDisablePrivateChatEl =  uifactory.addRadiosHorizontal("template.lockSettingsDisablePrivateChat", formLayout, yesNoKeys, onValues);
 		select(lockSettingsDisablePrivateChat, lockSettingsDisablePrivateChatEl, false);
 		
 		Boolean lockSettingsDisablePublicChat = template == null ? null : template.getLockSettingsDisablePublicChat();
-		lockSettingsDisablePublicChatEl =  uifactory.addRadiosHorizontal("template.lockSettingsDisablePublicChat", formLayout, onKeys, onValues);
+		lockSettingsDisablePublicChatEl =  uifactory.addRadiosHorizontal("template.lockSettingsDisablePublicChat", formLayout, yesNoKeys, onValues);
 		select(lockSettingsDisablePublicChat, lockSettingsDisablePublicChatEl, false);
 		
 		Boolean lockSettingsDisableNote = template == null ? null : template.getLockSettingsDisableNote();
-		lockSettingsDisableNoteEl =  uifactory.addRadiosHorizontal("template.lockSettingsDisableNote", formLayout, onKeys, onValues);
+		lockSettingsDisableNoteEl =  uifactory.addRadiosHorizontal("template.lockSettingsDisableNote", formLayout, yesNoKeys, onValues);
 		select(lockSettingsDisableNote, lockSettingsDisableNoteEl, false);
 		
 		Boolean lockSettingsLockedLayout = template == null ? null : template.getLockSettingsLockedLayout();
-		lockSettingsLockedLayoutEl = uifactory.addRadiosHorizontal("template.lockSettingsLockedLayout", formLayout, onKeys, onValues);
+		lockSettingsLockedLayoutEl = uifactory.addRadiosHorizontal("template.lockSettingsLockedLayout", formLayout, yesNoKeys, onValues);
 		select(lockSettingsLockedLayout, lockSettingsLockedLayoutEl, false);
 		
+		Boolean lockSettingsHideUserList = template == null ? null : template.getLockSettingsHideUserList();
+		lockSettingsHideUserListEl = uifactory.addRadiosHorizontal("template.lockSettingsHideUserList", formLayout, yesNoKeys, onValues);
+		select(lockSettingsHideUserList, lockSettingsHideUserListEl, false);
+		
+		Boolean lockSettingsLockOnJoin = template == null ? null : template.getLockSettingsLockOnJoin();
+		lockSettingsLockOnJoinEl = uifactory.addRadiosHorizontal("template.lockSettingsLockOnJoin", formLayout, yesNoKeys, onValues);
+		lockSettingsLockOnJoinEl.addActionListener(FormEvent.ONCHANGE);
+		select(lockSettingsLockOnJoin, lockSettingsLockOnJoinEl, true);
+		
+		Boolean lockSettingsLockOnJoinConfigurable = template == null ? null : template.getLockSettingsLockOnJoinConfigurable();
+		lockSettingsLockOnJoinConfigurableEl = uifactory.addRadiosHorizontal("template.lockSettingsLockOnJoinConfigurable", formLayout, yesNoKeys, onValues);
+		select(lockSettingsLockOnJoinConfigurable, lockSettingsLockOnJoinConfigurableEl, false);
+	
 		FormLayoutContainer buttonLayout = FormLayoutContainer.createButtonLayout("buttons", getTranslator());
 		formLayout.add("buttons", buttonLayout);
 		uifactory.addFormCancelButton("cancel", buttonLayout, ureq, getWindowControl());
@@ -165,12 +197,24 @@ public class EditBigBlueButtonTemplateController extends FormBasicController {
 		}
 	}
 	
+	private void updateUI() {
+		boolean record = recordEl.isOneSelected() && recordEl.isSelected(0);
+		autoStartRecordingEl.setVisible(record);
+		allowStartStopRecordingEl.setVisible(record);
+		
+		boolean lockOnJoin = lockSettingsLockOnJoinEl.isOneSelected() && lockSettingsLockOnJoinEl.isSelected(0);
+		lockSettingsLockOnJoinConfigurableEl.setVisible(lockOnJoin);	
+	}
+	
 	private void disableSystemTemplate() {
 		nameEl.setEnabled(false);
 		descriptionEl.setEnabled(false);
+		enableEl.setEnabled(false);
+		recordEl.setEnabled(false);
 		muteOnStartEl.setEnabled(false);
 		maxConcurrentMeetingsEl.setEnabled(false);
 		maxParticipantsEl.setEnabled(false);
+		maxDurationEl.setEnabled(false);
 		autoStartRecordingEl.setEnabled(false);
 		allowStartStopRecordingEl.setEnabled(false);
 		webcamsOnlyForModeratorEl.setEnabled(false);
@@ -181,6 +225,9 @@ public class EditBigBlueButtonTemplateController extends FormBasicController {
 		lockSettingsDisablePublicChatEl.setEnabled(false);
 		lockSettingsDisableNoteEl.setEnabled(false);
 		lockSettingsLockedLayoutEl.setEnabled(false);
+		lockSettingsHideUserListEl.setEnabled(false);
+		lockSettingsLockOnJoinEl.setEnabled(false);
+		lockSettingsLockOnJoinConfigurableEl.setEnabled(false);
 	}
 	
 	private void select(Boolean val, SingleSelection selectEl, boolean defaultValue) {
@@ -188,9 +235,9 @@ public class EditBigBlueButtonTemplateController extends FormBasicController {
 			val = Boolean.valueOf(defaultValue);
 		}
 		if(val.booleanValue()) {
-			selectEl.select(onKeys[0], true);
+			selectEl.select(yesNoKeys[0], true);
 		} else {
-			selectEl.select(onKeys[1], true);
+			selectEl.select(yesNoKeys[1], true);
 		}
 	}
 	
@@ -217,18 +264,39 @@ public class EditBigBlueButtonTemplateController extends FormBasicController {
 			descriptionEl.setErrorKey("form.error.toolong", new String[] { "2000" });
 			allOk &= false;
 		}
+
+		allOk &= validateLong(maxConcurrentMeetingsEl, false);
+		allOk &= validateLong(maxParticipantsEl, true);
+		allOk &= validateLong(maxDurationEl, false);
+				
+		return allOk;
+	}
+	
+	private boolean validateLong(TextElement el, boolean mandatory) {
+		boolean allOk = true;
 		
-		maxConcurrentMeetingsEl.clearError();
-		if(StringHelper.containsNonWhitespace(maxConcurrentMeetingsEl.getValue())
-				&& (!StringHelper.isLong(maxConcurrentMeetingsEl.getValue())
-						|| Long.valueOf(maxConcurrentMeetingsEl.getValue()).longValue() <= 0)) {
-			maxConcurrentMeetingsEl.setErrorKey("form.error.nointeger", null);
+		el.clearError();
+		if(mandatory && !StringHelper.containsNonWhitespace(el.getValue())) {
+			el.setErrorKey("form.legende.mandatory", null);
+			allOk &= false;
+		} else if(StringHelper.containsNonWhitespace(el.getValue())
+				&& (!StringHelper.isLong(el.getValue())
+						|| Long.parseLong(el.getValue()) <= 1)) {
+			el.setErrorKey("form.error.nointeger", null);
 			allOk &= false;
 		}
 		
 		return allOk;
 	}
 
+	@Override
+	protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) {
+		if(recordEl == source) {
+			updateUI();
+		}
+		super.formInnerEvent(ureq, source, event);
+	}
+
 	@Override
 	protected void formOK(UserRequest ureq) {
 		if(template == null) {
@@ -237,6 +305,7 @@ public class EditBigBlueButtonTemplateController extends FormBasicController {
 			template.setName(nameEl.getValue());
 		}
 		template.setDescription(descriptionEl.getValue());
+		template.setEnabled(enableEl.isAtLeastSelected(1));
 		
 		if(StringHelper.containsNonWhitespace(maxConcurrentMeetingsEl.getValue())
 				&& StringHelper.isLong(maxConcurrentMeetingsEl.getValue())) {
@@ -244,24 +313,40 @@ public class EditBigBlueButtonTemplateController extends FormBasicController {
 		} else {
 			template.setMaxConcurrentMeetings(null);
 		}
-
-		if(maxParticipantsEl.isOneSelected() && !"-".equals(maxParticipantsEl.getSelectedKey())) {
-			template.setMaxParticipants(Integer.parseInt(maxParticipantsEl.getSelectedKey()));
+		
+		if(StringHelper.containsNonWhitespace(maxParticipantsEl.getValue())
+				&& StringHelper.isLong(maxParticipantsEl.getValue())) {
+			template.setMaxParticipants(Long.valueOf(maxParticipantsEl.getValue()).intValue());
 		} else {
 			template.setMaxParticipants(null);
 		}
 		
+		if(StringHelper.containsNonWhitespace(maxDurationEl.getValue())
+				&& StringHelper.isLong(maxDurationEl.getValue())) {
+			template.setMaxDuration(Long.valueOf(maxDurationEl.getValue()).intValue());
+		} else {
+			template.setMaxDuration(null);
+		}
+
+		boolean record = getSelected(recordEl);
+		template.setRecord(record);
 		template.setMuteOnStart(getSelected(muteOnStartEl));
-		template.setAutoStartRecording(getSelected(autoStartRecordingEl));
-		template.setAllowStartStopRecording(getSelected(allowStartStopRecordingEl));
+		template.setAutoStartRecording(record && getSelected(autoStartRecordingEl));
+		template.setAllowStartStopRecording(record && getSelected(allowStartStopRecordingEl));
 		template.setWebcamsOnlyForModerator(getSelected(webcamsOnlyForModeratorEl));
 		template.setAllowModsToUnmuteUsers(getSelected(allowModsToUnmuteUsersEl));
+		
 		template.setLockSettingsDisableCam(getSelected(lockSettingsDisableCamEl));
 		template.setLockSettingsDisableMic(getSelected(lockSettingsDisableMicEl));
 		template.setLockSettingsDisablePrivateChat(getSelected(lockSettingsDisablePrivateChatEl));
 		template.setLockSettingsDisablePublicChat(getSelected(lockSettingsDisablePublicChatEl));
 		template.setLockSettingsDisableNote(getSelected(lockSettingsDisableNoteEl));
 		template.setLockSettingsLockedLayout(getSelected(lockSettingsLockedLayoutEl));
+		
+		template.setLockSettingsHideUserList(getSelected(lockSettingsHideUserListEl));
+		template.setLockSettingsLockOnJoin(getSelected(lockSettingsLockOnJoinEl));
+		template.setLockSettingsLockOnJoinConfigurable(getSelected(lockSettingsLockOnJoinConfigurableEl));
+		
 		template = bigBlueButtonManager.updateTemplate(template);
 		fireEvent(ureq, Event.DONE_EVENT);
 	}
diff --git a/src/main/java/org/olat/modules/bigbluebutton/ui/TemplateMinuteCellRenderer.java b/src/main/java/org/olat/modules/bigbluebutton/ui/TemplateMinuteCellRenderer.java
new file mode 100644
index 00000000000..e2a2ebff59f
--- /dev/null
+++ b/src/main/java/org/olat/modules/bigbluebutton/ui/TemplateMinuteCellRenderer.java
@@ -0,0 +1,50 @@
+/**
+ * <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.modules.bigbluebutton.ui;
+
+import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiCellRenderer;
+import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableComponent;
+import org.olat.core.gui.render.Renderer;
+import org.olat.core.gui.render.StringOutput;
+import org.olat.core.gui.render.URLBuilder;
+import org.olat.core.gui.translator.Translator;
+
+/**
+ * 
+ * Initial date: 24 mars 2020<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class TemplateMinuteCellRenderer implements FlexiCellRenderer {
+
+	private final Translator translator;
+	
+	public TemplateMinuteCellRenderer(Translator translator) {
+		this.translator = translator;
+	}
+
+	@Override
+	public void render(Renderer renderer, StringOutput target, Object cellValue, int row, FlexiTableComponent source,
+			URLBuilder ubu, Translator transl) {
+		if(cellValue instanceof Number) {
+			translator.translate("minutes", new String[] { Integer.toString(((Number)cellValue).intValue()) });
+		}
+	}
+}
diff --git a/src/main/java/org/olat/modules/bigbluebutton/ui/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/modules/bigbluebutton/ui/_i18n/LocalStrings_de.properties
index 18399cec0a8..81c6f0db29b 100644
--- a/src/main/java/org/olat/modules/bigbluebutton/ui/_i18n/LocalStrings_de.properties
+++ b/src/main/java/org/olat/modules/bigbluebutton/ui/_i18n/LocalStrings_de.properties
@@ -20,6 +20,7 @@ connection.successful=Login erfolgreich\!
 edit.template=Vorlage "{0}" bearbeiten
 enable.permanent.meeting=Dauernd Meeting einschalten
 enable.adhoc.meeting=Adhoc Meeting einschalten
+error.duration=Meeting dauert zu lange. Maximal Dauer ist {0} Minuten.
 error.end.past=Meeting kann nicht in Vergangenheit geplant werden.
 error.prefix=Ein Fehler ist aufgetreten\:
 error.server.raw={1} <small>Schl\u00FCssel\: {0}</small>
@@ -49,6 +50,7 @@ meetings.admin.title=Konfiguration
 meetings.past=Alte Meetings
 meetings.title=Meetings
 meetings.upcoming=Zuk\u00FCnftige Meetings
+minutes={0} Min.
 no.meeting.configured=Es sind noch keine Meetings konfiguriert.
 no.template.configured=Es sind noch keine Vorlage konfiguriert.
 no.recordings=Es sind noch keine Aufzeichnungen vorhanden.
@@ -57,16 +59,16 @@ option.baseurl=URL BigBlueButton Server
 option.baseurl.example=https\://bigbluebutton.openolat.com/bigbluebutton/
 option.bigbluebutton.secret=Secret
 option.bigbluebutton.shared.secret=Shared secret
-option.clean.meetings=Meetings aufra\u00FCmen (Tage)
-option.dont.clean.meetings=Nie
 recordings=Aufzeichnungen
 recording.browser.infos=Aufzeichnungen k\u00F6nnen nur mit Google Chrome und Firefox gesehen werden.
 recording.type.podcast=Podcast
 recording.type.presentation=Vorstellung
 server.overloaded=Es gibt kein Platz verf\u00FCgbar auf dem Server an den gew\u00E4hlten Datum.
+table.header.enabled=Eingeschaltet
 table.header.permanent=Dauernd
 table.header.system=System
 table.header.max.concurrent.meetings=Gleichseitig Meetings
+table.header.max.duration=Max. Dauer
 table.header.max.participants=Max. Teilnehmer
 table.header.recording.name=Name
 table.header.recording.type=Typ
@@ -79,6 +81,7 @@ template.allowModsToUnmuteUsers=Allow moderators to unmute users
 template.allowStartStopRecording=Allow to start / stop recording
 template.autoStartRecording=Auto start recording
 template.description=Beschreibung
+template.enabled=Vorlage einschalten
 template.explain.max.participants=Max. Anzhal von Teilnehmer: {0}
 template.explain.max.participants.with.webcams.mod=Max. Anzhal von Teilnehmer: {0}, Webcams f\u00FCr Moderatoren
 template.guestPolicy=Guest policy
@@ -88,11 +91,16 @@ template.lockSettingsDisableNote=Lock settings disable note
 template.lockSettingsDisablePrivateChat=Lock settings disable private chat
 template.lockSettingsDisablePublicChat=Lock settings disable public chat
 template.lockSettingsLockedLayout=Lock settings locked layout
+template.lockSettingsHideUserList=Hide user list for locked users
+template.lockSettingsLockOnJoin=Put viewer into lock mode on join
+template.lockSettingsLockOnJoinConfigurable=Moderator cannot change setting above
+template.maxDuration=Max. L\u00E4nge des Meeting (Minuten)
 template.maxParticipants=Max. Teilnehmer
 template.maxParticipants.default=Standard
 template.max.concurrent.meetings=Max. gleichzeitige Meetings
 template.muteOnStart=Mute on start
 template.name=Name
+template.record=Aufzeichnen
 template.webcamsOnlyForModerator=Webcams only for moderators
 templates.title=Vorlagen
 view=Ansehen
diff --git a/src/main/java/org/olat/modules/bigbluebutton/ui/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/modules/bigbluebutton/ui/_i18n/LocalStrings_en.properties
index 05e5f6873ff..d48e6e196e6 100644
--- a/src/main/java/org/olat/modules/bigbluebutton/ui/_i18n/LocalStrings_en.properties
+++ b/src/main/java/org/olat/modules/bigbluebutton/ui/_i18n/LocalStrings_en.properties
@@ -20,6 +20,7 @@ connection.successful=Login successful\!
 edit.template=Edit template "{0}"
 enable.permanent.meeting=Enable permanent meeting
 enable.adhoc.meeting=Enable adhoc meeting
+error.duration=Meeting is too long. Maximal duration is {0} minutes.
 error.end.past=Meeting cannot be planned in the past.
 error.prefix=An error happened\:
 error.server.raw={1} <small>Key {0}</small>
@@ -49,6 +50,7 @@ meetings.admin.title=Configuration
 meetings.past=Old meetings
 meetings.title=Meetings
 meetings.upcoming=Upcoming meetings
+minutes={0} min.
 no.meeting.configured=No meetings have been configured yet.
 no.recordings=There is no recording available for the moment.
 no.template.configured=No templates have been configured yet.
@@ -57,16 +59,16 @@ option.baseurl=URL BigBlueButton Server
 option.baseurl.example=https\://bigbluebutton.openolat.com/bigbluebutton/
 option.bigbluebutton.secret=Secret
 option.bigbluebutton.shared.secret=Shared secret
-option.clean.meetings=Clean-up meetings (days)
-option.dont.clean.meetings=Never
 recordings=Recordings
 recording.browser.infos=Recordings can only be viewed with Google Chrome or Firefox.
 recording.type.podcast=Podcast
 recording.type.presentation=Presentation
 server.overloaded=There is no place available on the server for the choosen dates.
+table.header.enabled=Enabled
 table.header.permanent=Permanent
 table.header.system=System
 table.header.max.concurrent.meetings=Concurrent meetings
+table.header.max.duration=Max. duration
 table.header.max.participants=Max. participants
 table.header.recording.name=Name
 table.header.recording.type=Type
@@ -79,6 +81,7 @@ template.allowModsToUnmuteUsers=Allow moderators to unmute users
 template.allowStartStopRecording=Allow to start / stop recording
 template.autoStartRecording=Auto start recording
 template.description=Description
+template.enabled=Enable template
 template.explain.max.participants=Max. number of participants: {0}
 template.explain.max.participants.with.webcams.mod=Max. number of participants: {0}, webcams for moderators
 template.guestPolicy=Guest policy
@@ -88,11 +91,16 @@ template.lockSettingsDisableNote=Lock settings disable note
 template.lockSettingsDisablePrivateChat=Lock settings disable private chat
 template.lockSettingsDisablePublicChat=Lock settings disable public chat
 template.lockSettingsLockedLayout=Lock settings locked layout
+template.lockSettingsHideUserList=Hide user list for locked users
+template.lockSettingsLockOnJoin=Put viewer into lock mode on join
+template.lockSettingsLockOnJoinConfigurable=Moderator cannot change setting above
+template.maxDuration=Max. duration of the meeting (minutes)
 template.maxParticipants=Max. participants
 template.maxParticipants.default=Default
 template.max.concurrent.meetings=Max. concurrent meetings
 template.muteOnStart=Mute on start
 template.name=Name
+template.record=Record
 template.webcamsOnlyForModerator=Webcams only for moderators
 templates.title=Templates
 view=View
diff --git a/src/main/resources/database/mysql/alter_14_2_x_to_14_2_5.sql b/src/main/resources/database/mysql/alter_14_2_x_to_14_2_5.sql
index 8ee52760d87..1f8f18bef29 100644
--- a/src/main/resources/database/mysql/alter_14_2_x_to_14_2_5.sql
+++ b/src/main/resources/database/mysql/alter_14_2_x_to_14_2_5.sql
@@ -5,9 +5,12 @@ create table o_bbb_template (
    b_name varchar(128) not null,
    b_description varchar(2000) default null,
    b_system bool default false not null,
+   b_enabled bool default true not null,
    b_external_id varchar(255) default null,
    b_max_concurrent_meetings int default null,
    b_max_participants int default null,
+   b_max_duration bigint default null,
+   b_record bool default null,
    b_mute_on_start bool default null,
    b_auto_start_recording bool default null,
    b_allow_start_stop_recording bool default null,
@@ -19,6 +22,10 @@ create table o_bbb_template (
    b_lock_set_disable_public_chat bool default null,
    b_lock_set_disable_note bool default null,
    b_lock_set_locked_layout bool default null,
+   b_lock_set_hide_user_list bool default null,
+   b_lock_set_lock_on_join bool default null,
+   b_lock_set_lock_on_join_conf bool default null,
+   b_permitted_roles varchar(255) default null,
    b_guest_policy varchar(32) default null,
    primary key (id)
 );
diff --git a/src/main/resources/database/mysql/setupDatabase.sql b/src/main/resources/database/mysql/setupDatabase.sql
index e86cafd52be..4216edafe04 100644
--- a/src/main/resources/database/mysql/setupDatabase.sql
+++ b/src/main/resources/database/mysql/setupDatabase.sql
@@ -1217,7 +1217,7 @@ create table o_aconnect_user (
    primary key (id)
 );
 
--- Bigbluebutton
+-- BigBlueButton
 create table o_bbb_template (
    id bigint not null auto_increment,
    creationdate datetime not null,
@@ -1225,9 +1225,12 @@ create table o_bbb_template (
    b_name varchar(128) not null,
    b_description varchar(2000) default null,
    b_system bool default false not null,
+   b_enabled bool default true not null,
    b_external_id varchar(255) default null,
    b_max_concurrent_meetings int default null,
    b_max_participants int default null,
+   b_max_duration bigint default null,
+   b_record bool default null,
    b_mute_on_start bool default null,
    b_auto_start_recording bool default null,
    b_allow_start_stop_recording bool default null,
@@ -1239,6 +1242,10 @@ create table o_bbb_template (
    b_lock_set_disable_public_chat bool default null,
    b_lock_set_disable_note bool default null,
    b_lock_set_locked_layout bool default null,
+   b_lock_set_hide_user_list bool default null,
+   b_lock_set_lock_on_join bool default null,
+   b_lock_set_lock_on_join_conf bool default null,
+   b_permitted_roles varchar(255) default null,
    b_guest_policy varchar(32) default null,
    primary key (id)
 );
diff --git a/src/main/resources/database/oracle/alter_14_2_x_to_14_2_5.sql b/src/main/resources/database/oracle/alter_14_2_x_to_14_2_5.sql
index 54f3de70ad5..ea53dae9ed2 100644
--- a/src/main/resources/database/oracle/alter_14_2_x_to_14_2_5.sql
+++ b/src/main/resources/database/oracle/alter_14_2_x_to_14_2_5.sql
@@ -5,9 +5,12 @@ create table o_bbb_template (
    b_name varchar(128) not null,
    b_description varchar(2000) default null,
    b_system number default 0 not null,
+   b_enabled number default 1 not null,
    b_external_id varchar(255) default null,
    b_max_concurrent_meetings int default null,
    b_max_participants int default null,
+   b_max_duration number default null,
+   b_record number default null,
    b_mute_on_start number default null,
    b_auto_start_recording number default null,
    b_allow_start_stop_recording number default null,
@@ -19,6 +22,10 @@ create table o_bbb_template (
    b_lock_set_disable_public_chat number default null,
    b_lock_set_disable_note number default null,
    b_lock_set_locked_layout number default null,
+   b_lock_set_hide_user_list number default null,
+   b_lock_set_lock_on_join number default null,
+   b_lock_set_lock_on_join_conf number default null,
+   b_permitted_roles varchar(255) default null,
    b_guest_policy varchar(32) default null,
    primary key (id)
 );
diff --git a/src/main/resources/database/oracle/setupDatabase.sql b/src/main/resources/database/oracle/setupDatabase.sql
index 98c4c3d7eef..d761f591f3f 100644
--- a/src/main/resources/database/oracle/setupDatabase.sql
+++ b/src/main/resources/database/oracle/setupDatabase.sql
@@ -1283,7 +1283,7 @@ create table o_aconnect_user (
    primary key (id)
 );
 
--- Bigbluebutton
+-- BigBlueButton
 create table o_bbb_template (
    id number(20) generated always as identity,
    creationdate timestamp not null,
@@ -1291,9 +1291,12 @@ create table o_bbb_template (
    b_name varchar(128) not null,
    b_description varchar(2000) default null,
    b_system number default 0 not null,
+   b_enabled number default 1 not null,
    b_external_id varchar(255) default null,
    b_max_concurrent_meetings int default null,
    b_max_participants int default null,
+   b_max_duration number default null,
+   b_record number default null,
    b_mute_on_start number default null,
    b_auto_start_recording number default null,
    b_allow_start_stop_recording number default null,
@@ -1305,6 +1308,10 @@ create table o_bbb_template (
    b_lock_set_disable_public_chat number default null,
    b_lock_set_disable_note number default null,
    b_lock_set_locked_layout number default null,
+   b_lock_set_hide_user_list number default null,
+   b_lock_set_lock_on_join number default null,
+   b_lock_set_lock_on_join_conf number default null,
+   b_permitted_roles varchar(255) default null,
    b_guest_policy varchar(32) default null,
    primary key (id)
 );
diff --git a/src/main/resources/database/postgresql/alter_14_2_x_to_14_2_5.sql b/src/main/resources/database/postgresql/alter_14_2_x_to_14_2_5.sql
index ea80879cd60..d354b512c6c 100644
--- a/src/main/resources/database/postgresql/alter_14_2_x_to_14_2_5.sql
+++ b/src/main/resources/database/postgresql/alter_14_2_x_to_14_2_5.sql
@@ -5,9 +5,12 @@ create table o_bbb_template (
    b_name varchar(128) not null,
    b_description varchar(2000) default null,
    b_system bool default false not null,
+   b_enabled bool default true not null,
    b_external_id varchar(255) default null,
    b_max_concurrent_meetings int default null,
    b_max_participants int8 default null,
+   b_max_duration int8 default null,
+   b_record bool default null,
    b_mute_on_start bool default null,
    b_auto_start_recording bool default null,
    b_allow_start_stop_recording bool default null,
@@ -19,6 +22,10 @@ create table o_bbb_template (
    b_lock_set_disable_public_chat bool default null,
    b_lock_set_disable_note bool default null,
    b_lock_set_locked_layout bool default null,
+   b_lock_set_hide_user_list bool default null,
+   b_lock_set_lock_on_join bool default null,
+   b_lock_set_lock_on_join_conf bool default null,
+   b_permitted_roles varchar(255) default null,
    b_guest_policy varchar(32) default null,
    primary key (id)
 );
diff --git a/src/main/resources/database/postgresql/setupDatabase.sql b/src/main/resources/database/postgresql/setupDatabase.sql
index 8aa8395f4db..438b55748e5 100644
--- a/src/main/resources/database/postgresql/setupDatabase.sql
+++ b/src/main/resources/database/postgresql/setupDatabase.sql
@@ -1242,7 +1242,7 @@ create table o_aconnect_user (
    primary key (id)
 );
 
--- Bigbluebutton
+-- BigBlueButton
 create table o_bbb_template (
    id bigserial,
    creationdate timestamp not null,
@@ -1250,9 +1250,12 @@ create table o_bbb_template (
    b_name varchar(128) not null,
    b_description varchar(2000) default null,
    b_system bool default false not null,
+   b_enabled bool default true not null,
    b_external_id varchar(255) default null,
    b_max_concurrent_meetings int default null,
-   b_max_participants int default null,
+   b_max_participants int8 default null,
+   b_max_duration int8 default null,
+   b_record bool default null,
    b_mute_on_start bool default null,
    b_auto_start_recording bool default null,
    b_allow_start_stop_recording bool default null,
@@ -1264,6 +1267,10 @@ create table o_bbb_template (
    b_lock_set_disable_public_chat bool default null,
    b_lock_set_disable_note bool default null,
    b_lock_set_locked_layout bool default null,
+   b_lock_set_hide_user_list bool default null,
+   b_lock_set_lock_on_join bool default null,
+   b_lock_set_lock_on_join_conf bool default null,
+   b_permitted_roles varchar(255) default null,
    b_guest_policy varchar(32) default null,
    primary key (id)
 );
diff --git a/src/test/java/org/olat/modules/bigbluebutton/manager/BigBlueButtonMeetingDAOTest.java b/src/test/java/org/olat/modules/bigbluebutton/manager/BigBlueButtonMeetingDAOTest.java
index 8adeda0b061..bc6596e9243 100644
--- a/src/test/java/org/olat/modules/bigbluebutton/manager/BigBlueButtonMeetingDAOTest.java
+++ b/src/test/java/org/olat/modules/bigbluebutton/manager/BigBlueButtonMeetingDAOTest.java
@@ -142,7 +142,7 @@ public class BigBlueButtonMeetingDAOTest extends OlatTestCase {
 		
 		List<BigBlueButtonMeeting> meetings = bigBlueButtonMeetingDao.getAllMeetings();
 		Assert.assertNotNull(meetings);
-		Assert.assertEquals(1, meetings.size());
+		Assert.assertTrue(!meetings.isEmpty());
 		Assert.assertTrue(meetings.contains(meeting));
 	}
 	
@@ -161,17 +161,17 @@ public class BigBlueButtonMeetingDAOTest extends OlatTestCase {
 		createMeeting("BigBlueButton - 7", date(2, 12), 15, date(2, 15), 15, template, group);
 		dbInstance.commit();
 
-		int concurrent = bigBlueButtonMeetingDao.getConcurrentMeetings(template, date(1, 15), date(1, 19));
-		Assert.assertEquals(2, concurrent);
+		List<Long> concurrent = bigBlueButtonMeetingDao.getConcurrentMeetings(template, date(1, 15), date(1, 19));
+		Assert.assertEquals(2, concurrent.size());
 		
-		int concurrentFollowup = bigBlueButtonMeetingDao.getConcurrentMeetings(template, date(1, 20), date(1, 21));
-		Assert.assertEquals(1, concurrentFollowup);
+		List<Long>  concurrentFollowup = bigBlueButtonMeetingDao.getConcurrentMeetings(template, date(1, 20), date(1, 21));
+		Assert.assertEquals(1, concurrentFollowup.size());
 		
-		int concurrentWidePeriod = bigBlueButtonMeetingDao.getConcurrentMeetings(template, date(0, 10), date(3, 21));
-		Assert.assertEquals(4, concurrentWidePeriod);
+		List<Long>  concurrentWidePeriod = bigBlueButtonMeetingDao.getConcurrentMeetings(template, date(0, 10), date(3, 21));
+		Assert.assertEquals(4, concurrentWidePeriod.size());
 		
-		int concurrentWithin = bigBlueButtonMeetingDao.getConcurrentMeetings(template, date(2, 13), date(2, 14));
-		Assert.assertEquals(1, concurrentWithin);
+		List<Long>  concurrentWithin = bigBlueButtonMeetingDao.getConcurrentMeetings(template, date(2, 13), date(2, 14));
+		Assert.assertEquals(1, concurrentWithin.size());
 	}
 	
 	private BigBlueButtonMeeting createMeeting(String name, Date start, int leadTime, Date end, int followupTime,
-- 
GitLab