From 231cad86dee861232b7479ce86cfa98f9f3687bd Mon Sep 17 00:00:00 2001
From: srosse <stephane.rosse@frentix.com>
Date: Tue, 3 Nov 2020 10:35:29 +0100
Subject: [PATCH] OO-5017: allow override recording option in meeting

---
 .../ui/AppointmentEditController.java         | 22 ++++++++++++++--
 .../ui/RecurringAppointmentsController.java   | 16 ++++++++++--
 .../ui/TopicCreateController.java             | 16 ++++++++++--
 .../bigbluebutton/BigBlueButtonMeeting.java   |  4 +++
 .../manager/BigBlueButtonManagerImpl.java     |  8 ++++--
 .../model/BigBlueButtonMeetingImpl.java       | 12 +++++++++
 .../ui/BigBlueButtonUIHelper.java             | 25 +++++++++++++++++--
 .../EditBigBlueButtonMeetingController.java   | 20 ++++++++++++---
 .../ui/_i18n/LocalStrings_de.properties       |  1 +
 .../ui/_i18n/LocalStrings_en.properties       |  1 +
 .../_spring/databaseUpgradeContext.xml        |  4 +++
 .../database/mysql/alter_15_3_x_to_15_3_2.sql |  3 +++
 .../database/mysql/setupDatabase.sql          |  1 +
 .../oracle/alter_15_3_x_to_15_3_2.sql         |  3 +++
 .../database/oracle/setupDatabase.sql         |  1 +
 .../postgresql/alter_15_3_x_to_15_3_2.sql     |  3 +++
 .../database/postgresql/setupDatabase.sql     |  1 +
 17 files changed, 128 insertions(+), 13 deletions(-)
 create mode 100644 src/main/resources/database/mysql/alter_15_3_x_to_15_3_2.sql
 create mode 100644 src/main/resources/database/oracle/alter_15_3_x_to_15_3_2.sql
 create mode 100644 src/main/resources/database/postgresql/alter_15_3_x_to_15_3_2.sql

diff --git a/src/main/java/org/olat/modules/appointments/ui/AppointmentEditController.java b/src/main/java/org/olat/modules/appointments/ui/AppointmentEditController.java
index c9da03471a3..6db674ce3d9 100644
--- a/src/main/java/org/olat/modules/appointments/ui/AppointmentEditController.java
+++ b/src/main/java/org/olat/modules/appointments/ui/AppointmentEditController.java
@@ -73,6 +73,7 @@ public class AppointmentEditController extends FormBasicController {
 	
 	private static final String KEY_ON = "on";
 	private static final String[] KEYS_ON = new String[] { KEY_ON };
+	private static final String[] KEYS_YES_NO = new String[] { "yes", "no" };
 	
 	private DateChooser startEl;
 	private DateChooser endEl;
@@ -87,6 +88,7 @@ public class AppointmentEditController extends FormBasicController {
 	private TextElement followupTimeEl;
 	private TextElement welcomeEl;
 	private SingleSelection templateEl;
+	private SingleSelection recordEl;
 	private SingleSelection layoutEl;
 	
 	private BigBlueButtonMeetingsCalendarController calCtr;
@@ -203,6 +205,16 @@ public class AppointmentEditController extends FormBasicController {
 			if(isWebcamLayoutAvailable(getSelectedTemplate(templateEl, templates))) {
 				layoutKeyValues.add(KeyValues.entry(BigBlueButtonMeetingLayoutEnum.webcam.name(), translate("layout.webcam")));
 			}
+			
+			String[] yesNoValues = new String[] { translate("yes"), translate("no")  };
+			recordEl = uifactory.addRadiosVertical("meeting.record", formLayout, KEYS_YES_NO, yesNoValues);
+			recordEl.setEnabled(bbbEditable);
+			if(BigBlueButtonUIHelper.isRecord(meeting)) {
+				recordEl.select(KEYS_YES_NO[0], true);
+			} else {
+				recordEl.select(KEYS_YES_NO[1], true);
+			}
+			
 			layoutEl = uifactory.addDropdownSingleselect("meeting.layout", "meeting.layout", formLayout,
 					layoutKeyValues.keys(), layoutKeyValues.values());
 			layoutEl.setEnabled(bbbEditable);
@@ -230,7 +242,7 @@ public class AppointmentEditController extends FormBasicController {
 			
 			openCalLink = uifactory.addFormLink("calendar.open", formLayout);
 			openCalLink.setIconLeftCSS("o_icon o_icon-fw o_icon_calendar");
-			BigBlueButtonUIHelper.updateTemplateInformations(templateEl, externalLinkEl, templates);
+			BigBlueButtonUIHelper.updateTemplateInformations(templateEl, externalLinkEl, recordEl, templates);
 			
 			String leadtime = meeting == null ? null : Long.toString(meeting.getLeadTime());
 			leadTimeEl = uifactory.addTextElement("meeting.leadTime", 8, leadtime, formLayout);
@@ -292,7 +304,7 @@ public class AppointmentEditController extends FormBasicController {
 		} else if (source == bbbRoomEl) {
 			updateUI();
 		} else if (templateEl == source) {
-			BigBlueButtonUIHelper.updateTemplateInformations(templateEl, externalLinkEl, templates);
+			BigBlueButtonUIHelper.updateTemplateInformations(templateEl, externalLinkEl, recordEl, templates);
 			boolean webcamAvailable = isWebcamLayoutAvailable(getSelectedTemplate(templateEl, templates));
 			BigBlueButtonUIHelper.updateLayoutSelection(layoutEl, getTranslator(), webcamAvailable);
 		} else if (openCalLink == source) {
@@ -466,6 +478,12 @@ public class AppointmentEditController extends FormBasicController {
 			} else {
 				meeting.setMeetingLayout(BigBlueButtonMeetingLayoutEnum.standard);
 			}
+			
+			if(recordEl.isVisible() && recordEl.isOneSelected()) {
+				meeting.setRecord(Boolean.valueOf(KEYS_YES_NO[0].equals(recordEl.getSelectedKey())));
+			} else {
+				meeting.setRecord(null);
+			}
 		} else {
 			appointment = appointmentsService.removeMeeting(appointment);
 		}
diff --git a/src/main/java/org/olat/modules/appointments/ui/RecurringAppointmentsController.java b/src/main/java/org/olat/modules/appointments/ui/RecurringAppointmentsController.java
index 7702baae572..471b74dcee7 100644
--- a/src/main/java/org/olat/modules/appointments/ui/RecurringAppointmentsController.java
+++ b/src/main/java/org/olat/modules/appointments/ui/RecurringAppointmentsController.java
@@ -74,6 +74,7 @@ public class RecurringAppointmentsController extends FormBasicController {
 	
 	private static final String KEY_ON = "on";
 	private static final String[] KEYS_ON = new String[] { KEY_ON };
+	private static final String[] KEYS_YES_NO = new String[] { "yes", "no" };
 	
 	private TextElement locationEl;
 	private TextElement maxParticipationsEl;
@@ -88,6 +89,7 @@ public class RecurringAppointmentsController extends FormBasicController {
 	private TextElement followupTimeEl;
 	private TextElement welcomeEl;
 	private SingleSelection templateEl;
+	private SingleSelection recordEl;
 	private SingleSelection layoutEl;
 	
 	private BigBlueButtonMeetingsCalendarController calCtr;
@@ -151,6 +153,10 @@ public class RecurringAppointmentsController extends FormBasicController {
 					templatesKV.keys(), templatesKV.values());
 			templateEl.addActionListener(FormEvent.ONCHANGE);
 			templateEl.select(templateEl.getKeys()[0], true);
+			
+			String[] yesNoValues = new String[] { translate("yes"), translate("no")  };
+			recordEl = uifactory.addRadiosVertical("meeting.record", formLayout, KEYS_YES_NO, yesNoValues);
+			recordEl.select(KEYS_YES_NO[0], true);
 		
 			KeyValues layoutKeyValues = new KeyValues();
 			layoutKeyValues.add(KeyValues.entry(BigBlueButtonMeetingLayoutEnum.standard.name(), translate("layout.standard")));
@@ -174,7 +180,7 @@ public class RecurringAppointmentsController extends FormBasicController {
 			
 			openCalLink = uifactory.addFormLink("calendar.open", formLayout);
 			openCalLink.setIconLeftCSS("o_icon o_icon-fw o_icon_calendar");
-			BigBlueButtonUIHelper.updateTemplateInformations(templateEl, externalLinkEl, templates);
+			BigBlueButtonUIHelper.updateTemplateInformations(templateEl, externalLinkEl, recordEl, templates);
 			
 			leadTimeEl = uifactory.addTextElement("meeting.leadTime", 8, null, formLayout);
 			leadTimeEl.setExampleKey("meeting.leadTime.explain", null);
@@ -228,7 +234,7 @@ public class RecurringAppointmentsController extends FormBasicController {
 		if (source == bbbRoomEl) {
 			updateUI();
 		} else if (templateEl == source) {
-			BigBlueButtonUIHelper.updateTemplateInformations(templateEl, externalLinkEl, templates);
+			BigBlueButtonUIHelper.updateTemplateInformations(templateEl, externalLinkEl, recordEl, templates);
 			boolean webcamAvailable = isWebcamLayoutAvailable(getSelectedTemplate(templateEl, templates));
 			BigBlueButtonUIHelper.updateLayoutSelection(layoutEl, getTranslator(), webcamAvailable);
 		} else if (openCalLink == source) {
@@ -423,6 +429,12 @@ public class RecurringAppointmentsController extends FormBasicController {
 				} else {
 					meeting.setMeetingLayout(BigBlueButtonMeetingLayoutEnum.standard);
 				}
+				
+				if(recordEl.isVisible() && recordEl.isOneSelected()) {
+					meeting.setRecord(Boolean.valueOf(KEYS_YES_NO[0].equals(recordEl.getSelectedKey())));
+				} else {
+					meeting.setRecord(null);
+				}
 			} 
 			
 			appointmentsService.saveAppointment(appointment);
diff --git a/src/main/java/org/olat/modules/appointments/ui/TopicCreateController.java b/src/main/java/org/olat/modules/appointments/ui/TopicCreateController.java
index 207af04fe44..31d1df6f58e 100644
--- a/src/main/java/org/olat/modules/appointments/ui/TopicCreateController.java
+++ b/src/main/java/org/olat/modules/appointments/ui/TopicCreateController.java
@@ -85,6 +85,7 @@ public class TopicCreateController extends FormBasicController {
 	
 	private static final String KEY_ON = "on";
 	private static final String[] KEYS_ON = new String[] { KEY_ON };
+	private static final String[] KEYS_YES_NO = new String[] { "yes", "no" };
 	private static final String KEY_MULTI_PARTICIPATION = "multi.participation";
 	private static final String KEY_COACH_CONFIRMATION = "coach.confirmation";
 	private static final String CMD_REMOVE = "remove";
@@ -110,6 +111,7 @@ public class TopicCreateController extends FormBasicController {
 	private TextElement followupTimeEl;
 	private TextElement welcomeEl;
 	private SingleSelection templateEl;
+	private SingleSelection recordEl;
 	private SingleSelection layoutEl;
 	
 	private BigBlueButtonMeetingsCalendarController calCtr;
@@ -243,6 +245,10 @@ public class TopicCreateController extends FormBasicController {
 					templatesKV.keys(), templatesKV.values());
 			templateEl.addActionListener(FormEvent.ONCHANGE);
 			templateEl.select(templateEl.getKeys()[0], true);
+			
+			String[] yesNoValues = new String[] { translate("yes"), translate("no")  };
+			recordEl = uifactory.addRadiosVertical("meeting.record", formLayout, KEYS_YES_NO, yesNoValues);
+			recordEl.select(KEYS_YES_NO[0], true);
 		
 			KeyValues layoutKeyValues = new KeyValues();
 			layoutKeyValues.add(KeyValues.entry(BigBlueButtonMeetingLayoutEnum.standard.name(), translate("layout.standard")));
@@ -266,7 +272,7 @@ public class TopicCreateController extends FormBasicController {
 			
 			openCalLink = uifactory.addFormLink("calendar.open", formLayout);
 			openCalLink.setIconLeftCSS("o_icon o_icon-fw o_icon_calendar");
-			BigBlueButtonUIHelper.updateTemplateInformations(templateEl, externalLinkEl, templates);
+			BigBlueButtonUIHelper.updateTemplateInformations(templateEl, externalLinkEl, recordEl, templates);
 			
 			leadTimeEl = uifactory.addTextElement("meeting.leadTime", 8, null, formLayout);
 			leadTimeEl.setExampleKey("meeting.leadTime.explain", null);
@@ -347,7 +353,7 @@ public class TopicCreateController extends FormBasicController {
 		} else if (source == bbbRoomEl) {
 			updateUI();
 		} else if (templateEl == source) {
-			BigBlueButtonUIHelper.updateTemplateInformations(templateEl, externalLinkEl, templates);
+			BigBlueButtonUIHelper.updateTemplateInformations(templateEl, externalLinkEl, recordEl, templates);
 			boolean webcamAvailable = isWebcamLayoutAvailable(getSelectedTemplate(templateEl, templates));
 			BigBlueButtonUIHelper.updateLayoutSelection(layoutEl, getTranslator(), webcamAvailable);
 		} else if (openCalLink == source) {
@@ -689,6 +695,12 @@ public class TopicCreateController extends FormBasicController {
 			} else {
 				meeting.setMeetingLayout(BigBlueButtonMeetingLayoutEnum.standard);
 			}
+			
+			if(recordEl.isVisible() && recordEl.isOneSelected()) {
+				meeting.setRecord(Boolean.valueOf(KEYS_YES_NO[0].equals(recordEl.getSelectedKey())));
+			} else {
+				meeting.setRecord(null);
+			}
 		}
 		return appointment;
 	}
diff --git a/src/main/java/org/olat/modules/bigbluebutton/BigBlueButtonMeeting.java b/src/main/java/org/olat/modules/bigbluebutton/BigBlueButtonMeeting.java
index f7e4662fbaf..b6bf94b6f85 100644
--- a/src/main/java/org/olat/modules/bigbluebutton/BigBlueButtonMeeting.java
+++ b/src/main/java/org/olat/modules/bigbluebutton/BigBlueButtonMeeting.java
@@ -189,6 +189,10 @@ public interface BigBlueButtonMeeting extends ModifiedInfo, CreateInfo {
 
 	public void setRecordingsPublishingEnum(BigBlueButtonRecordingsPublishingEnum publishing);
 	
+	public Boolean getRecord();
+
+	public void setRecord(Boolean record);
+	
 	/**
 	 * The plain text name of the presenter or main organizer. By default the name
 	 * of the creator but can be change to anything. Metadata just for display
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 8746c562230..d2144bc3dad 100644
--- a/src/main/java/org/olat/modules/bigbluebutton/manager/BigBlueButtonManagerImpl.java
+++ b/src/main/java/org/olat/modules/bigbluebutton/manager/BigBlueButtonManagerImpl.java
@@ -915,11 +915,15 @@ public class BigBlueButtonManagerImpl implements BigBlueButtonManager,
 		}
 
 		if(template != null) {
+			boolean record = template.getRecord() != null && template.getRecord().booleanValue();
+			if(record && meeting.getRecord() != null) {
+				record = meeting.getRecord().booleanValue();
+			}
+
 			uriBuilder
 				.optionalParameter("maxParticipants", template.getMaxParticipants().intValue() + 1)
-				.optionalParameter("record", template.getRecord())
+				.optionalParameter("record", record)
 				.optionalParameter("breakoutRoomsEnabled", template.getBreakoutRoomsEnabled())
-				
 				// video options
 				.optionalParameter("muteOnStart", template.getMuteOnStart())
 				.optionalParameter("autoStartRecording", template.getAutoStartRecording())
diff --git a/src/main/java/org/olat/modules/bigbluebutton/model/BigBlueButtonMeetingImpl.java b/src/main/java/org/olat/modules/bigbluebutton/model/BigBlueButtonMeetingImpl.java
index 77309db86b8..dc12a7d513d 100644
--- a/src/main/java/org/olat/modules/bigbluebutton/model/BigBlueButtonMeetingImpl.java
+++ b/src/main/java/org/olat/modules/bigbluebutton/model/BigBlueButtonMeetingImpl.java
@@ -117,6 +117,8 @@ public class BigBlueButtonMeetingImpl implements Persistable, BigBlueButtonMeeti
 
 	@Column(name="b_recordings_publishing", nullable=true, insertable=true, updatable=true)
 	private String recordingsPublishing;
+	@Column(name="b_record", nullable=true, insertable=true, updatable=true)
+	private Boolean record;
 	
 	@ManyToOne(targetEntity=IdentityImpl.class, fetch=FetchType.LAZY, optional=true)
 	@JoinColumn(name="fk_creator_id", nullable=true, insertable=true, updatable=false)
@@ -368,6 +370,16 @@ public class BigBlueButtonMeetingImpl implements Persistable, BigBlueButtonMeeti
 		}
 	}
 
+	@Override
+	public Boolean getRecord() {
+		return record;
+	}
+
+	@Override
+	public void setRecord(Boolean record) {
+		this.record = record;
+	}
+
 	@Override
 	public String getMainPresenter() {
 		return mainPresenter;
diff --git a/src/main/java/org/olat/modules/bigbluebutton/ui/BigBlueButtonUIHelper.java b/src/main/java/org/olat/modules/bigbluebutton/ui/BigBlueButtonUIHelper.java
index a1b896ec1e9..bdb08ad216d 100644
--- a/src/main/java/org/olat/modules/bigbluebutton/ui/BigBlueButtonUIHelper.java
+++ b/src/main/java/org/olat/modules/bigbluebutton/ui/BigBlueButtonUIHelper.java
@@ -46,7 +46,7 @@ import org.olat.modules.bigbluebutton.BigBlueButtonMeetingTemplate;
  */
 public class BigBlueButtonUIHelper {
 	
-	public static void updateTemplateInformations(SingleSelection templateEl, TextElement externalLinkEl, List<BigBlueButtonMeetingTemplate> templates) {
+	public static void updateTemplateInformations(SingleSelection templateEl, TextElement externalLinkEl, SingleSelection recordEl, List<BigBlueButtonMeetingTemplate> templates) {
 		templateEl.setExampleKey(null, null);
 		if(templateEl.isOneSelected()) {
 			BigBlueButtonMeetingTemplate template = getSelectedTemplate(templateEl, templates);
@@ -65,8 +65,20 @@ public class BigBlueButtonUIHelper {
 			if(visible && !StringHelper.containsNonWhitespace(externalLinkEl.getValue())) {
 				externalLinkEl.setValue(Long.toString(CodeHelper.getForeverUniqueID()));
 			}
+			
+			if(recordEl != null) {
+				boolean recordVisible = template != null && template.getRecord() != null && template.getRecord().booleanValue();
+				boolean wasVisible = recordEl.isVisible();
+				recordEl.setVisible(recordVisible);
+				if(!recordEl.isOneSelected() || (recordVisible && !wasVisible)) {
+					recordEl.select("yes", true);	
+				}
+			}
 		} else {
 			externalLinkEl.setVisible(false);
+			if(recordEl != null) {
+				recordEl.setVisible(false);
+			}
 		}
 	}
 	
@@ -240,10 +252,19 @@ public class BigBlueButtonUIHelper {
 		return followupTime;
 	}
 	
+	public static boolean isRecord(BigBlueButtonMeetingTemplate template) {
+		return template != null && template.getRecord() != null && template.getRecord().booleanValue();
+	}
+	
 	public static boolean isRecord(BigBlueButtonMeeting meeting) {
-		return meeting != null && meeting.getTemplate() != null
+		boolean record = meeting != null && meeting.getTemplate() != null
 				&& meeting.getTemplate().getRecord() != null
 				&& meeting.getTemplate().getRecord().booleanValue();
+		// override only if template enables recording
+		if(record && meeting.getRecord() != null) {
+			record = meeting.getRecord().booleanValue();
+		}
+		return record;
 	}
 	
 	private static BigBlueButtonManager getBigBlueButtonManager() {
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 ad8d12bcefc..63d776c756a 100644
--- a/src/main/java/org/olat/modules/bigbluebutton/ui/EditBigBlueButtonMeetingController.java
+++ b/src/main/java/org/olat/modules/bigbluebutton/ui/EditBigBlueButtonMeetingController.java
@@ -67,6 +67,7 @@ import org.springframework.beans.factory.annotation.Autowired;
 public class EditBigBlueButtonMeetingController extends FormBasicController {
 	
 	private static final String[] onKeys = new String[] { "on" };
+	private static final String[] yesNoKeys = new String[] { "yes", "no" };
 
 	private FormLink openCalLink;
 	private TextElement nameEl;
@@ -79,6 +80,7 @@ public class EditBigBlueButtonMeetingController extends FormBasicController {
 	private DateChooser endDateEl;
 	private SingleSelection templateEl;
 	private SingleSelection layoutEl;
+	private SingleSelection recordEl;
 	private SingleSelection publishingEl;
 	private MultipleSelectionElement guestEl;
 	private TextElement externalLinkEl;
@@ -209,6 +211,14 @@ public class EditBigBlueButtonMeetingController extends FormBasicController {
 		BigBlueButtonRecordingsPublishingEnum publish = meeting == null ? BigBlueButtonRecordingsPublishingEnum.auto :  meeting.getRecordingsPublishingEnum();
 		publishingEl.select(publish.name(), true);
 		publishingEl.setEnabled(editable);
+		
+		String[] yesNoValues = new String[] { translate("yes"), translate("no")  };
+		recordEl = uifactory.addRadiosVertical("meeting.record", formLayout, yesNoKeys, yesNoValues);
+		if(meeting == null || BigBlueButtonUIHelper.isRecord(meeting)) {
+			recordEl.select(yesNoKeys[0], true);
+		} else {
+			recordEl.select(yesNoKeys[1], true);
+		}
 
 		KeyValues layoutKeyValues = new KeyValues();
 		layoutKeyValues.add(KeyValues.entry(BigBlueButtonMeetingLayoutEnum.standard.name(), translate("layout.standard")));
@@ -247,7 +257,7 @@ public class EditBigBlueButtonMeetingController extends FormBasicController {
 		
 		openCalLink = uifactory.addFormLink("calendar.open", formLayout);
 		openCalLink.setIconLeftCSS("o_icon o_icon-fw o_icon_calendar");
-		BigBlueButtonUIHelper.updateTemplateInformations(templateEl, externalLinkEl, templates);
+		BigBlueButtonUIHelper.updateTemplateInformations(templateEl, externalLinkEl, recordEl, templates);
 		
 		if(mode == Mode.dates) {
 			Date startDate = meeting == null ? new Date() : meeting.getStartDate();
@@ -404,7 +414,7 @@ public class EditBigBlueButtonMeetingController extends FormBasicController {
 	@Override
 	protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) {
 		if(templateEl == source) {
-			BigBlueButtonUIHelper.updateTemplateInformations(templateEl, externalLinkEl, templates);
+			BigBlueButtonUIHelper.updateTemplateInformations(templateEl, externalLinkEl, recordEl, templates);
 			boolean webcamAvailable = isWebcamLayoutAvailable(getSelectedTemplate(templateEl, templates));
 			BigBlueButtonUIHelper.updateLayoutSelection(layoutEl, getTranslator(), webcamAvailable);
 		} else if (openCalLink == source) {
@@ -466,7 +476,11 @@ public class EditBigBlueButtonMeetingController extends FormBasicController {
 		}
 		
 		meeting.setRecordingsPublishingEnum(BigBlueButtonRecordingsPublishingEnum.valueOf(publishingEl.getSelectedKey()));
-		
+		if(recordEl.isVisible() && recordEl.isOneSelected()) {
+			meeting.setRecord(Boolean.valueOf(yesNoKeys[0].equals(recordEl.getSelectedKey())));
+		} else {
+			meeting.setRecord(null);
+		}
 		meeting = bigBlueButtonManager.updateMeeting(meeting);
 
 		fireEvent(ureq, Event.DONE_EVENT);
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 6564961420b..9558dfcca32 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
@@ -93,6 +93,7 @@ meeting.permanent.on=Ohne Datum
 meeting.publishing=Aufzeichnung publizieren
 meeting.publishing.auto=Automatisch
 meeting.publishing.manual=Manuell
+meeting.record=$\:template.record
 meeting.recurring.end=Ende wiederkehrendes Datum
 meeting.recurring.start=Start wiederkehrendes Datum
 meeting.resource=Kontext
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 99867cf0eed..1ed3c882c6f 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
@@ -93,6 +93,7 @@ meeting.permanent.on=Without date
 meeting.publishing=Publish recording
 meeting.publishing.auto=Automatisch
 meeting.publishing.manual=Manual
+meeting.record=$\:template.record
 meeting.recurring.end=End recurring date
 meeting.recurring.start=Start recurring date
 meeting.resource=Context
diff --git a/src/main/java/org/olat/upgrade/_spring/databaseUpgradeContext.xml b/src/main/java/org/olat/upgrade/_spring/databaseUpgradeContext.xml
index eeba35e14a5..38502007c6b 100644
--- a/src/main/java/org/olat/upgrade/_spring/databaseUpgradeContext.xml
+++ b/src/main/java/org/olat/upgrade/_spring/databaseUpgradeContext.xml
@@ -312,6 +312,10 @@
 					<constructor-arg index="0" value="OLAT_15.3.1" />
 					<property name="alterDbStatements" value="alter_15_3_x_to_15_3_1.sql" />
 				</bean>
+				<bean id="database_upgrade_15_3_2" class="org.olat.upgrade.DatabaseUpgrade">
+					<constructor-arg index="0" value="OLAT_15.3.2" />
+					<property name="alterDbStatements" value="alter_15_3_x_to_15_3_2.sql" />
+				</bean>
 			</list>
 		</property>
 	</bean>
diff --git a/src/main/resources/database/mysql/alter_15_3_x_to_15_3_2.sql b/src/main/resources/database/mysql/alter_15_3_x_to_15_3_2.sql
new file mode 100644
index 00000000000..acea6a271b9
--- /dev/null
+++ b/src/main/resources/database/mysql/alter_15_3_x_to_15_3_2.sql
@@ -0,0 +1,3 @@
+-- BigBlueButton
+alter table o_bbb_meeting add column b_record bool default null;
+
diff --git a/src/main/resources/database/mysql/setupDatabase.sql b/src/main/resources/database/mysql/setupDatabase.sql
index 4a4bdb143e3..3d3b5414488 100644
--- a/src/main/resources/database/mysql/setupDatabase.sql
+++ b/src/main/resources/database/mysql/setupDatabase.sql
@@ -1225,6 +1225,7 @@ create table o_bbb_meeting (
    b_end_with_followuptime datetime,
    b_main_presenter varchar(255),
    b_recordings_publishing varchar(16) default 'auto',
+   b_record bool default null,
    fk_creator_id bigint default null,
    fk_entry_id bigint default null,
    a_sub_ident varchar(64) default null,
diff --git a/src/main/resources/database/oracle/alter_15_3_x_to_15_3_2.sql b/src/main/resources/database/oracle/alter_15_3_x_to_15_3_2.sql
new file mode 100644
index 00000000000..03490a2cb67
--- /dev/null
+++ b/src/main/resources/database/oracle/alter_15_3_x_to_15_3_2.sql
@@ -0,0 +1,3 @@
+-- BigBlueButton
+alter table o_bbb_meeting add b_record number default null;
+
diff --git a/src/main/resources/database/oracle/setupDatabase.sql b/src/main/resources/database/oracle/setupDatabase.sql
index 27b793ba482..6dd09e8a3da 100644
--- a/src/main/resources/database/oracle/setupDatabase.sql
+++ b/src/main/resources/database/oracle/setupDatabase.sql
@@ -1289,6 +1289,7 @@ create table o_bbb_meeting (
    b_end_with_followuptime timestamp,
    b_main_presenter varchar2(255),
    b_recordings_publishing varchar2(16) default 'auto',
+   b_record number default null,
    fk_creator_id number(20),
    fk_entry_id number(20) default null,
    a_sub_ident varchar(64) default null,
diff --git a/src/main/resources/database/postgresql/alter_15_3_x_to_15_3_2.sql b/src/main/resources/database/postgresql/alter_15_3_x_to_15_3_2.sql
new file mode 100644
index 00000000000..acea6a271b9
--- /dev/null
+++ b/src/main/resources/database/postgresql/alter_15_3_x_to_15_3_2.sql
@@ -0,0 +1,3 @@
+-- BigBlueButton
+alter table o_bbb_meeting add column b_record bool default null;
+
diff --git a/src/main/resources/database/postgresql/setupDatabase.sql b/src/main/resources/database/postgresql/setupDatabase.sql
index fa5cd9c10b5..00c08ace941 100644
--- a/src/main/resources/database/postgresql/setupDatabase.sql
+++ b/src/main/resources/database/postgresql/setupDatabase.sql
@@ -1247,6 +1247,7 @@ create table o_bbb_meeting (
    b_end_with_followuptime timestamp,
    b_main_presenter varchar(255),
    b_recordings_publishing varchar(16) default 'auto',
+   b_record bool default null,
    fk_creator_id int8,
    fk_entry_id int8 default null,
    a_sub_ident varchar(64) default null,
-- 
GitLab