diff --git a/src/main/java/org/olat/modules/bigbluebutton/BigBlueButtonMeeting.java b/src/main/java/org/olat/modules/bigbluebutton/BigBlueButtonMeeting.java index 0534275e6e6d9a9e68dff632d36c4709a95f18dc..48a8f07bfa73ec053da42ee4d003a311b51b47c1 100644 --- a/src/main/java/org/olat/modules/bigbluebutton/BigBlueButtonMeeting.java +++ b/src/main/java/org/olat/modules/bigbluebutton/BigBlueButtonMeeting.java @@ -54,6 +54,10 @@ public interface BigBlueButtonMeeting extends ModifiedInfo, CreateInfo { public void setWelcome(String welcome); + public BigBlueButtonMeetingLayoutEnum getMeetingLayout(); + + public void setMeetingLayout(BigBlueButtonMeetingLayoutEnum layout); + public boolean isPermanent(); public void setPermanent(boolean permanent); diff --git a/src/main/java/org/olat/modules/bigbluebutton/BigBlueButtonMeetingLayoutEnum.java b/src/main/java/org/olat/modules/bigbluebutton/BigBlueButtonMeetingLayoutEnum.java new file mode 100644 index 0000000000000000000000000000000000000000..6c7da91b2548a4a015b2d8bbe50f1a37553b652a --- /dev/null +++ b/src/main/java/org/olat/modules/bigbluebutton/BigBlueButtonMeetingLayoutEnum.java @@ -0,0 +1,46 @@ +/** + * <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; + +import org.olat.core.util.StringHelper; + +/** + * + * Initial date: 9 juin 2020<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public enum BigBlueButtonMeetingLayoutEnum { + + standard, + webcam; + + public static final BigBlueButtonMeetingLayoutEnum secureValueOf(String val) { + BigBlueButtonMeetingLayoutEnum layout = BigBlueButtonMeetingLayoutEnum.standard; + if(StringHelper.containsNonWhitespace(val)) { + for(BigBlueButtonMeetingLayoutEnum l:values()) { + if(l.name().equals(val)) { + layout = l; + } + } + } + return layout; + } +} 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 25d827b755de01d2979dd727ec365a06d6993c3e..3cca3082d0bd284333a9257b34513bb0b87e9394 100644 --- a/src/main/java/org/olat/modules/bigbluebutton/manager/BigBlueButtonManagerImpl.java +++ b/src/main/java/org/olat/modules/bigbluebutton/manager/BigBlueButtonManagerImpl.java @@ -60,6 +60,7 @@ import org.olat.group.BusinessGroupService; import org.olat.group.DeletableGroupData; import org.olat.modules.bigbluebutton.BigBlueButtonManager; import org.olat.modules.bigbluebutton.BigBlueButtonMeeting; +import org.olat.modules.bigbluebutton.BigBlueButtonMeetingLayoutEnum; import org.olat.modules.bigbluebutton.BigBlueButtonMeetingTemplate; import org.olat.modules.bigbluebutton.BigBlueButtonModule; import org.olat.modules.bigbluebutton.BigBlueButtonRecording; @@ -735,12 +736,21 @@ public class BigBlueButtonManagerImpl implements BigBlueButtonManager, } BigBlueButtonUriBuilder uriBuilder = getUriBuilder(server); - return uriBuilder + uriBuilder .operation("join") .parameter("meetingID", meeting.getMeetingId()) .parameter("fullName", getFullName(identity)) .parameter("password", password) - .optionalParameter("userID", userId) + .optionalParameter("userID", userId); + + if(BigBlueButtonMeetingLayoutEnum.webcam.equals(meeting.getMeetingLayout())) { + uriBuilder + .optionalParameter("userdata-bbb_auto_swap_layout", "true") + .optionalParameter("userdata-bbb_auto_share_webcam", "true") + .optionalParameter("userdata-bbb_show_participants_on_login", "false"); + } + + return uriBuilder .build() .toString(); } 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 abe4aa8ac966c1414563baa106848962027e5b52..0e6a8ad7811160fec984275c0c02f103a6b36df6 100644 --- a/src/main/java/org/olat/modules/bigbluebutton/manager/BigBlueButtonMeetingDAO.java +++ b/src/main/java/org/olat/modules/bigbluebutton/manager/BigBlueButtonMeetingDAO.java @@ -33,6 +33,7 @@ import org.olat.core.commons.persistence.QueryBuilder; import org.olat.core.util.StringHelper; import org.olat.group.BusinessGroup; import org.olat.modules.bigbluebutton.BigBlueButtonMeeting; +import org.olat.modules.bigbluebutton.BigBlueButtonMeetingLayoutEnum; import org.olat.modules.bigbluebutton.BigBlueButtonMeetingTemplate; import org.olat.modules.bigbluebutton.BigBlueButtonServer; import org.olat.modules.bigbluebutton.model.BigBlueButtonMeetingImpl; @@ -62,6 +63,7 @@ public class BigBlueButtonMeetingDAO { meeting.setMeetingId(UUID.randomUUID().toString()); meeting.setAttendeePassword(UUID.randomUUID().toString()); meeting.setModeratorPassword(UUID.randomUUID().toString()); + meeting.setMeetingLayout(BigBlueButtonMeetingLayoutEnum.standard); meeting.setEntry(entry); meeting.setSubIdent(subIdent); 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 146482c3d057df5a6e9a6a54c9dabe69e082b7ec..538468e1cfd0368b20b48227d1335c259697d858 100644 --- a/src/main/java/org/olat/modules/bigbluebutton/model/BigBlueButtonMeetingImpl.java +++ b/src/main/java/org/olat/modules/bigbluebutton/model/BigBlueButtonMeetingImpl.java @@ -37,6 +37,7 @@ import org.olat.core.id.Persistable; import org.olat.group.BusinessGroup; import org.olat.group.BusinessGroupImpl; import org.olat.modules.bigbluebutton.BigBlueButtonMeeting; +import org.olat.modules.bigbluebutton.BigBlueButtonMeetingLayoutEnum; import org.olat.modules.bigbluebutton.BigBlueButtonMeetingTemplate; import org.olat.modules.bigbluebutton.BigBlueButtonServer; import org.olat.repository.RepositoryEntry; @@ -90,6 +91,9 @@ public class BigBlueButtonMeetingImpl implements Persistable, BigBlueButtonMeeti @Column(name="b_permanent", nullable=false, insertable=true, updatable=true) private boolean permanent; + + @Column(name="b_layout", nullable=false, insertable=true, updatable=true) + private String layout; @Column(name="b_meeting_id", nullable=false, insertable=true, updatable=false) private String meetingId; @@ -200,6 +204,30 @@ public class BigBlueButtonMeetingImpl implements Persistable, BigBlueButtonMeeti public void setWelcome(String welcome) { this.welcome = welcome; } + + + + public String getLayout() { + return layout; + } + + public void setLayout(String layout) { + this.layout = layout; + } + + @Override + public BigBlueButtonMeetingLayoutEnum getMeetingLayout() { + return BigBlueButtonMeetingLayoutEnum.secureValueOf(layout); + } + + @Override + public void setMeetingLayout(BigBlueButtonMeetingLayoutEnum meetingLayout) { + if(meetingLayout == null) { + layout = BigBlueButtonMeetingLayoutEnum.standard.name(); + } else { + layout = meetingLayout.name(); + } + } @Override public boolean isPermanent() { 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 baa43adcda0032f54ed9ddf37e3a7c197f2915d0..e0a24061f8c56dfc9209795123c460106e80f094 100644 --- a/src/main/java/org/olat/modules/bigbluebutton/ui/EditBigBlueButtonMeetingController.java +++ b/src/main/java/org/olat/modules/bigbluebutton/ui/EditBigBlueButtonMeetingController.java @@ -42,6 +42,7 @@ import org.olat.core.util.StringHelper; import org.olat.group.BusinessGroup; import org.olat.modules.bigbluebutton.BigBlueButtonManager; import org.olat.modules.bigbluebutton.BigBlueButtonMeeting; +import org.olat.modules.bigbluebutton.BigBlueButtonMeetingLayoutEnum; import org.olat.modules.bigbluebutton.BigBlueButtonMeetingTemplate; import org.olat.modules.bigbluebutton.BigBlueButtonModule; import org.olat.modules.bigbluebutton.BigBlueButtonTemplatePermissions; @@ -65,6 +66,7 @@ public class EditBigBlueButtonMeetingController extends FormBasicController { private DateChooser startDateEl; private DateChooser endDateEl; private SingleSelection templateEl; + private SingleSelection layoutEl; private final Mode mode; private final String subIdent; @@ -171,7 +173,27 @@ public class EditBigBlueButtonMeetingController extends FormBasicController { if(!templateSelected && templatesKeys.length > 0) { templateEl.select(templatesKeys[0], true); } - + + KeyValues layoutKeyValues = new KeyValues(); + layoutKeyValues.add(KeyValues.entry(BigBlueButtonMeetingLayoutEnum.standard.name(), translate("layout.standard"))); + if(isWebcamLayoutAvailable()) { + layoutKeyValues.add(KeyValues.entry(BigBlueButtonMeetingLayoutEnum.webcam.name(), translate("layout.webcam"))); + } + layoutEl = uifactory.addDropdownSingleselect("meeting.layout", "meeting.layout", formLayout, + layoutKeyValues.keys(), layoutKeyValues.values()); + boolean layoutSelected = false; + String selectedLayout = meeting == null ? BigBlueButtonMeetingLayoutEnum.standard.name() : meeting.getMeetingLayout().name(); + for(String layoutKey:layoutKeyValues.keys()) { + if(layoutKey.equals(selectedLayout)) { + layoutEl.select(layoutKey, true); + layoutSelected = true; + } + } + if(!layoutSelected) { + layoutEl.select(BigBlueButtonMeetingLayoutEnum.standard.name(), true); + } + layoutEl.setVisible(layoutEl.getKeys().length > 1); + openCalLink = uifactory.addFormLink("calendar.open", formLayout); openCalLink.setIconLeftCSS("o_icon o_icon-fw o_icon_calendar"); updateTemplateInformations(); @@ -217,6 +239,14 @@ public class EditBigBlueButtonMeetingController extends FormBasicController { } } + private boolean isWebcamLayoutAvailable() { + if(!templateEl.isOneSelected()) { + return true; + } + BigBlueButtonMeetingTemplate template = getSelectedTemplate(); + return template != null && (template.getWebcamsOnlyForModerator() == null || !template.getWebcamsOnlyForModerator().booleanValue()); + } + private void updateTemplateInformations() { templateEl.setExampleKey(null, null); if(templateEl.isOneSelected()) { @@ -234,6 +264,24 @@ public class EditBigBlueButtonMeetingController extends FormBasicController { } } + private void updateLayoutSelection() { + boolean webcamAvailable = isWebcamLayoutAvailable(); + if(webcamAvailable && layoutEl.getKeys().length == 1) { + KeyValues layoutKeyValues = new KeyValues(); + layoutKeyValues.add(KeyValues.entry(BigBlueButtonMeetingLayoutEnum.standard.name(), translate("layout.standard"))); + layoutKeyValues.add(KeyValues.entry(BigBlueButtonMeetingLayoutEnum.webcam.name(), translate("layout.webcam"))); + layoutEl.setKeysAndValues(layoutKeyValues.keys(), layoutKeyValues.values(), null); + } else if(!webcamAvailable && layoutEl.getKeys().length > 1) { + layoutEl.select(BigBlueButtonMeetingLayoutEnum.standard.name(), true); + + KeyValues layoutKeyValues = new KeyValues(); + layoutKeyValues.add(KeyValues.entry(BigBlueButtonMeetingLayoutEnum.standard.name(), translate("layout.standard"))); + layoutEl.setKeysAndValues(layoutKeyValues.keys(), layoutKeyValues.values(), null); + } + + layoutEl.setVisible(layoutEl.getKeys().length > 1); + } + private void doOpenCalendar(UserRequest ureq) { removeAsListenerAndDispose(calCtr); removeAsListenerAndDispose(cmc); @@ -428,6 +476,7 @@ public class EditBigBlueButtonMeetingController extends FormBasicController { protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) { if(templateEl == source) { updateTemplateInformations(); + updateLayoutSelection(); } else if (openCalLink == source) { doOpenCalendar(ureq); } @@ -465,6 +514,13 @@ public class EditBigBlueButtonMeetingController extends FormBasicController { meeting.setFollowupTime(followupTime); } + if(layoutEl.isVisible() && layoutEl.isOneSelected()) { + BigBlueButtonMeetingLayoutEnum layout = BigBlueButtonMeetingLayoutEnum.secureValueOf(layoutEl.getSelectedKey()); + meeting.setMeetingLayout(layout); + } else { + meeting.setMeetingLayout(BigBlueButtonMeetingLayoutEnum.standard); + } + 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 c7c2064e0a3f27f43da7e7f079512f22f6ebb6fe..c7e1d7a82a7b15e7e5612e33800f3ead6db930de 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 @@ -56,6 +56,8 @@ error.too.long.time=Zeit ist zu lang. Es sind maximal {0} Minuten erlaubt. error.url.invalid=Ung\u00FCltige Serveradresse filter.all.instances=Alle OpenOlats filter.this.instance=Dieses OpenOlat +layout.standard=Standard +layout.webcam=Webcam Termin meeting.create.intro=Der Online-Termin wurde vom Betreuer noch nicht er\u00F6ffnet. Teilnehmer k\u00F6nnen den Raum noch nicht betreten. meeting.day=Datum des Meetings meeting.deleted=Das Meeting wurde erfolgreich gel\u00F6scht. @@ -65,6 +67,7 @@ meeting.ended=Der Online-Termin wurde bereits beendet. meeting.followupTime=Nachlaufzeit (Min.) meeting.go.button=Zum Online-Termin Raum meeting.join.button=Meeting beitreten +meeting.layout=Darstellung meeting.leadTime=Vorlaufzeit (Min.) meeting.leadTime.explain=Die Vorlaufzeit ist nur f\u00FCr Moderatoren relevant. meeting.name=Name 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 048640dc3bf17aedb164dca808d999980d73532e..dbb087ec630ceb6ddd9a1200fbcd76faaade93cc 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 @@ -56,6 +56,8 @@ error.too.long.time=Time is too long. It is limited to {0} minutes. error.url.invalid=Invalid server URL filter.all.instances=All OpenOlats filter.this.instance=This OpenOlat +layout.standard=Standard +layout.webcam=Webcam meeting meeting.create.intro=The meeting has not yet been started by the coach. Participants are not able to enter the classroom. meeting.day=Date of the meeting meeting.deleted=The meeting was successfully deleted. @@ -65,6 +67,7 @@ meeting.ended=The online-meeting has already ended. meeting.followupTime=Follow-up (min.) meeting.go.button=Go to the onlin-meeting room meeting.join.button=Join the meeting +meeting.layout=Layout meeting.leadTime=Prep time (min.) meeting.leadTime.explain=Prep time is only relevant for moderators. meeting.name=Name diff --git a/src/main/resources/database/mysql/alter_15_0_x_to_15_1_0.sql b/src/main/resources/database/mysql/alter_15_0_x_to_15_1_0.sql index 6a7674dc2cc67e3f163cfedb3baed33afe2cde6e..6398b3f4d96534aaf386eda78abc8b2ed8b2e460 100644 --- a/src/main/resources/database/mysql/alter_15_0_x_to_15_1_0.sql +++ b/src/main/resources/database/mysql/alter_15_0_x_to_15_1_0.sql @@ -4,6 +4,10 @@ alter table o_bs_identity add column inactivationemaildate datetime; alter table o_bs_identity add column deletionemaildate datetime; +-- BigBlueButton +alter table o_bbb_meeting add column b_layout varchar(16) default 'standard'; + + -- Appointments create table o_ap_topic ( id bigint not null auto_increment, diff --git a/src/main/resources/database/mysql/setupDatabase.sql b/src/main/resources/database/mysql/setupDatabase.sql index b982291c05789fb7553ea3d31c0eab3819cd6094..fdf1d8bcba3f16df3158a0626f2f74e6b56f01c4 100644 --- a/src/main/resources/database/mysql/setupDatabase.sql +++ b/src/main/resources/database/mysql/setupDatabase.sql @@ -1204,6 +1204,7 @@ create table o_bbb_meeting ( b_name varchar(128) not null, b_description varchar(2000) default null, b_welcome mediumtext, + b_layout varchar(16) default 'standard', b_permanent bool default false not null, b_start_date datetime default null, b_leadtime bigint default 0 not null, diff --git a/src/main/resources/database/oracle/alter_15_0_x_to_15_1_0.sql b/src/main/resources/database/oracle/alter_15_0_x_to_15_1_0.sql index 262344bd5be535ab449f66dab207552a5384e399..d4f33987e8c755ef844ef449640dd802ff7637dc 100644 --- a/src/main/resources/database/oracle/alter_15_0_x_to_15_1_0.sql +++ b/src/main/resources/database/oracle/alter_15_0_x_to_15_1_0.sql @@ -4,6 +4,10 @@ alter table o_bs_identity add inactivationemaildate date; alter table o_bs_identity add deletionemaildate date; +-- BigBlueButton +alter table o_bbb_meeting add b_layout varchar2(16) default 'standard'; + + -- Appointments create table o_ap_topic ( id number(20) generated always as identity, diff --git a/src/main/resources/database/oracle/setupDatabase.sql b/src/main/resources/database/oracle/setupDatabase.sql index 71a69295b52ffb614677871aaa0e665073593644..4af0597b96efff6f4565cce1fd038c820d7fe29e 100644 --- a/src/main/resources/database/oracle/setupDatabase.sql +++ b/src/main/resources/database/oracle/setupDatabase.sql @@ -1267,6 +1267,7 @@ create table o_bbb_meeting ( b_name varchar(128) not null, b_description varchar(2000) default null, b_welcome CLOB, + b_layout varchar2(16) default 'standard', b_permanent number default 0 not null, b_start_date timestamp default null, b_leadtime number(20) default 0 not null, diff --git a/src/main/resources/database/postgresql/alter_15_0_x_to_15_1_0.sql b/src/main/resources/database/postgresql/alter_15_0_x_to_15_1_0.sql index fbcdb8fd1b6090932aeb66e546422f4e4ca97fd0..57add3c0a5f21c5cc8dd190e427642c512e20d1a 100644 --- a/src/main/resources/database/postgresql/alter_15_0_x_to_15_1_0.sql +++ b/src/main/resources/database/postgresql/alter_15_0_x_to_15_1_0.sql @@ -4,6 +4,10 @@ alter table o_bs_identity add column inactivationemaildate timestamp; alter table o_bs_identity add column deletionemaildate timestamp; +-- BigBlueButton +alter table o_bbb_meeting add column b_layout varchar(16) default 'standard'; + + -- Appointments create table o_ap_topic ( id bigserial, diff --git a/src/main/resources/database/postgresql/setupDatabase.sql b/src/main/resources/database/postgresql/setupDatabase.sql index fddc7eff2aafbc308104459d6f8a2118523b2e77..a4ea3b26c7d791e3481623a5e395ea87efd84597 100644 --- a/src/main/resources/database/postgresql/setupDatabase.sql +++ b/src/main/resources/database/postgresql/setupDatabase.sql @@ -1226,6 +1226,7 @@ create table o_bbb_meeting ( b_name varchar(128) not null, b_description varchar(2000) default null, b_welcome text, + b_layout varchar(16) default 'standard', b_permanent bool default false not null, b_start_date timestamp default null, b_leadtime bigint default 0 not null,