From f17431b61ed19e6dbe1856a8837abe650a339a61 Mon Sep 17 00:00:00 2001 From: srosse <stephane.rosse@frentix.com> Date: Wed, 25 Mar 2020 09:28:26 +0100 Subject: [PATCH] OO-4584: limit templates by roles --- .../course/nodes/BigBlueButtonCourseNode.java | 3 - .../bigbluebutton/BigBlueButtonRoles.java | 64 ++++++++++++++++++- .../manager/BigBlueButtonManagerImpl.java | 2 + .../BigBlueButtonMeetingTemplateImpl.java | 4 +- .../BigBlueButtonEditMeetingsController.java | 49 +++++++++++++- .../EditBigBlueButtonMeetingController.java | 28 ++++++-- .../EditBigBlueButtonTemplateController.java | 33 +++++++++- .../ui/_i18n/LocalStrings_de.properties | 5 ++ .../ui/_i18n/LocalStrings_en.properties | 5 ++ 9 files changed, 177 insertions(+), 16 deletions(-) diff --git a/src/main/java/org/olat/course/nodes/BigBlueButtonCourseNode.java b/src/main/java/org/olat/course/nodes/BigBlueButtonCourseNode.java index 8a2cc327697..c0056ddb349 100644 --- a/src/main/java/org/olat/course/nodes/BigBlueButtonCourseNode.java +++ b/src/main/java/org/olat/course/nodes/BigBlueButtonCourseNode.java @@ -21,7 +21,6 @@ package org.olat.course.nodes; import java.util.List; -import org.apache.logging.log4j.Logger; import org.olat.core.gui.UserRequest; import org.olat.core.gui.components.stack.BreadcrumbPanel; import org.olat.core.gui.control.Controller; @@ -30,7 +29,6 @@ import org.olat.core.gui.control.generic.messages.MessageUIFactory; import org.olat.core.gui.control.generic.tabbable.TabbableController; import org.olat.core.gui.translator.Translator; import org.olat.core.id.Roles; -import org.olat.core.logging.Tracing; import org.olat.core.util.Util; import org.olat.course.ICourse; import org.olat.course.condition.ConditionEditController; @@ -57,7 +55,6 @@ import org.olat.repository.RepositoryEntry; public class BigBlueButtonCourseNode extends AbstractAccessableCourseNode { private static final long serialVersionUID = 7965344505304490859L; - private static final Logger log = Tracing.createLoggerFor(BigBlueButtonCourseNode.class); private static final String TYPE = "bigbluebutton"; // configuration diff --git a/src/main/java/org/olat/modules/bigbluebutton/BigBlueButtonRoles.java b/src/main/java/org/olat/modules/bigbluebutton/BigBlueButtonRoles.java index 53c3192410b..b161539fc50 100644 --- a/src/main/java/org/olat/modules/bigbluebutton/BigBlueButtonRoles.java +++ b/src/main/java/org/olat/modules/bigbluebutton/BigBlueButtonRoles.java @@ -19,6 +19,13 @@ */ package org.olat.modules.bigbluebutton; +import java.util.ArrayList; +import java.util.List; + +import org.olat.core.util.StringHelper; + +import edu.emory.mathcs.backport.java.util.Collections; + /** * * Initial date: 24 mars 2020<br> @@ -30,6 +37,59 @@ public enum BigBlueButtonRoles { coach, owner, author, - administrator - + administrator; + + public boolean accept(BigBlueButtonRoles role) { + if(role == null) return false; + if(this == role) { + return true; + } + if(role == administrator) { + return true; + } + if(role == author) { + return (this == author || this == owner || this == coach); + } + return false; + } + + public static List<BigBlueButtonRoles> valuesAsList() { + List<BigBlueButtonRoles> roles = new ArrayList<>(); + Collections.addAll(roles, BigBlueButtonRoles.values()); + return roles; + } + + public static List<BigBlueButtonRoles> toList(String val) { + List<BigBlueButtonRoles> roles = new ArrayList<>(); + if(StringHelper.containsNonWhitespace(val)) { + String[] valArray = val.split("[,]"); + if(valArray != null && valArray.length > 0) { + for(String v:valArray) { + BigBlueButtonRoles role = BigBlueButtonRoles.valueOfSecure(v); + if(role != null) { + roles.add(role); + } + } + } + } + return roles; + } + + public static BigBlueButtonRoles valueOfSecure(String val) { + for(BigBlueButtonRoles role:BigBlueButtonRoles.values()) { + if(role.name().equals(val)) { + return role; + } + } + return null; + } + + public static String toString(List<BigBlueButtonRoles> roles) { + StringBuilder sb = new StringBuilder(); + for(BigBlueButtonRoles role:roles) { + if(sb.length() > 0) sb.append(","); + sb.append(role.name()); + } + return sb.toString(); + } } 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 1a40c108ea8..5e21ba35451 100644 --- a/src/main/java/org/olat/modules/bigbluebutton/manager/BigBlueButtonManagerImpl.java +++ b/src/main/java/org/olat/modules/bigbluebutton/manager/BigBlueButtonManagerImpl.java @@ -49,6 +49,7 @@ import org.olat.modules.bigbluebutton.BigBlueButtonMeeting; import org.olat.modules.bigbluebutton.BigBlueButtonMeetingTemplate; import org.olat.modules.bigbluebutton.BigBlueButtonModule; import org.olat.modules.bigbluebutton.BigBlueButtonRecording; +import org.olat.modules.bigbluebutton.BigBlueButtonRoles; import org.olat.modules.bigbluebutton.GuestPolicyEnum; import org.olat.modules.bigbluebutton.model.BigBlueButtonError; import org.olat.modules.bigbluebutton.model.BigBlueButtonErrorCodes; @@ -137,6 +138,7 @@ public class BigBlueButtonManagerImpl implements BigBlueButtonManager, Initializ template.setMaxConcurrentMeetings(maxConcurrentMeetings); template.setMaxParticipants(maxParticipants); template.setMaxDuration(maxDuration); + template.setPermittedRolesEnum(BigBlueButtonRoles.valuesAsList()); template.setMuteOnStart(muteOnStart); template.setAutoStartRecording(autoStartRecording); template.setAllowStartStopRecording(allowStartStopRecording); 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 328155bd453..14e9816315e 100644 --- a/src/main/java/org/olat/modules/bigbluebutton/model/BigBlueButtonMeetingTemplateImpl.java +++ b/src/main/java/org/olat/modules/bigbluebutton/model/BigBlueButtonMeetingTemplateImpl.java @@ -387,7 +387,7 @@ public class BigBlueButtonMeetingTemplateImpl implements Persistable, BigBlueBut @Override public List<BigBlueButtonRoles> getPermittedRolesEnum() { - return null; + return BigBlueButtonRoles.toList(permittedRoles); } @Override @@ -395,7 +395,7 @@ public class BigBlueButtonMeetingTemplateImpl implements Persistable, BigBlueBut if(roles == null || roles.isEmpty()) { setPermittedRoles(null); } else { - + setPermittedRoles(BigBlueButtonRoles.toString(roles)); } } diff --git a/src/main/java/org/olat/modules/bigbluebutton/ui/BigBlueButtonEditMeetingsController.java b/src/main/java/org/olat/modules/bigbluebutton/ui/BigBlueButtonEditMeetingsController.java index ffaf19c6c2f..84834a12e79 100644 --- a/src/main/java/org/olat/modules/bigbluebutton/ui/BigBlueButtonEditMeetingsController.java +++ b/src/main/java/org/olat/modules/bigbluebutton/ui/BigBlueButtonEditMeetingsController.java @@ -19,6 +19,7 @@ */ package org.olat.modules.bigbluebutton.ui; +import java.util.ArrayList; import java.util.List; import org.olat.core.commons.persistence.SortKey; @@ -41,14 +42,19 @@ import org.olat.core.gui.control.WindowControl; import org.olat.core.gui.control.generic.closablewrapper.CloseableModalController; import org.olat.core.gui.control.generic.modal.DialogBoxController; import org.olat.core.gui.control.generic.modal.DialogBoxUIFactory; +import org.olat.core.id.Roles; import org.olat.group.BusinessGroup; +import org.olat.group.BusinessGroupService; import org.olat.modules.bigbluebutton.BigBlueButtonManager; import org.olat.modules.bigbluebutton.BigBlueButtonMeeting; import org.olat.modules.bigbluebutton.BigBlueButtonModule; +import org.olat.modules.bigbluebutton.BigBlueButtonRoles; import org.olat.modules.bigbluebutton.model.BigBlueButtonErrors; import org.olat.modules.bigbluebutton.ui.BigBlueButtonMeetingTableModel.BMeetingsCols; import org.olat.modules.gotomeeting.ui.GoToMeetingTableModel.MeetingsCols; import org.olat.repository.RepositoryEntry; +import org.olat.repository.RepositoryManager; +import org.olat.repository.model.RepositoryEntrySecurity; import org.springframework.beans.factory.annotation.Autowired; /** @@ -72,10 +78,14 @@ public class BigBlueButtonEditMeetingsController extends FormBasicController { private final RepositoryEntry entry; private final BusinessGroup businessGroup; + @Autowired + private RepositoryManager repositoryManager; @Autowired private BigBlueButtonModule bigBlueButtonModule; @Autowired private BigBlueButtonManager bigBlueButtonManager; + @Autowired + private BusinessGroupService businessGroupService; public BigBlueButtonEditMeetingsController(UserRequest ureq, WindowControl wControl, RepositoryEntry entry, String subIdentifier, BusinessGroup group, boolean readOnly) { @@ -183,8 +193,10 @@ public class BigBlueButtonEditMeetingsController extends FormBasicController { private void doAddMeeting(UserRequest ureq) { if(guardModalController(editMeetingCtlr)) return; - - editMeetingCtlr = new EditBigBlueButtonMeetingController(ureq, getWindowControl(), entry, subIdent, businessGroup); + + List<BigBlueButtonRoles> editionRoles= getPermittedRoles(ureq); + editMeetingCtlr = new EditBigBlueButtonMeetingController(ureq, getWindowControl(), + entry, subIdent, businessGroup, editionRoles); listenTo(editMeetingCtlr); cmc = new CloseableModalController(getWindowControl(), "close", editMeetingCtlr.getInitialComponent(), @@ -196,7 +208,9 @@ public class BigBlueButtonEditMeetingsController extends FormBasicController { private void doEditMeeting(UserRequest ureq, BigBlueButtonMeeting meeting) { if(guardModalController(editMeetingCtlr)) return; - editMeetingCtlr = new EditBigBlueButtonMeetingController(ureq, getWindowControl(), meeting); + List<BigBlueButtonRoles> editionRoles= getPermittedRoles(ureq); + editMeetingCtlr = new EditBigBlueButtonMeetingController(ureq, getWindowControl(), + meeting, editionRoles); listenTo(editMeetingCtlr); cmc = new CloseableModalController(getWindowControl(), "close", editMeetingCtlr.getInitialComponent(), @@ -205,6 +219,35 @@ public class BigBlueButtonEditMeetingsController extends FormBasicController { listenTo(cmc); } + private List<BigBlueButtonRoles> getPermittedRoles(UserRequest ureq) { + Roles roles = ureq.getUserSession().getRoles(); + + List<BigBlueButtonRoles> editionRoles = new ArrayList<>(); + if(businessGroup != null) { + if(roles.isAdministrator()) { + editionRoles.add(BigBlueButtonRoles.administrator); + } + if(businessGroupService.isIdentityInBusinessGroup(getIdentity(), businessGroup.getKey(), true, false, null)) { + editionRoles.add(BigBlueButtonRoles.coach); + } + } else if(entry != null) { + RepositoryEntrySecurity reSecurity = repositoryManager.isAllowed(getIdentity(), roles, entry); + if(roles.isAdministrator()) { + editionRoles.add(BigBlueButtonRoles.administrator); + } + if(reSecurity.isAuthor()) { + editionRoles.add(BigBlueButtonRoles.author); + } + if(reSecurity.isEntryAdmin()) { + editionRoles.add(BigBlueButtonRoles.owner); + } + if(reSecurity.isCourseCoach()) { + editionRoles.add(BigBlueButtonRoles.coach); + } + } + return editionRoles; + } + private void doConfirmDelete(UserRequest ureq, BigBlueButtonMeeting meeting) { String confirmDeleteTitle = translate("confirm.delete.meeting.title", new String[]{ meeting.getName() }); String confirmDeleteText = translate("confirm.delete.meeting", new String[]{ meeting.getName() }); 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 5d190b387a2..bace9acb687 100644 --- a/src/main/java/org/olat/modules/bigbluebutton/ui/EditBigBlueButtonMeetingController.java +++ b/src/main/java/org/olat/modules/bigbluebutton/ui/EditBigBlueButtonMeetingController.java @@ -44,6 +44,7 @@ import org.olat.modules.bigbluebutton.BigBlueButtonManager; import org.olat.modules.bigbluebutton.BigBlueButtonMeeting; import org.olat.modules.bigbluebutton.BigBlueButtonMeetingTemplate; import org.olat.modules.bigbluebutton.BigBlueButtonModule; +import org.olat.modules.bigbluebutton.BigBlueButtonRoles; import org.olat.repository.RepositoryEntry; import org.springframework.beans.factory.annotation.Autowired; @@ -71,6 +72,7 @@ public class EditBigBlueButtonMeetingController extends FormBasicController { private final RepositoryEntry entry; private final BusinessGroup businessGroup; private BigBlueButtonMeeting meeting; + private final List<BigBlueButtonRoles> editionRoles; private List<BigBlueButtonMeetingTemplate> templates; private FormLink openCalLink; @@ -83,23 +85,26 @@ public class EditBigBlueButtonMeetingController extends FormBasicController { private BigBlueButtonManager bigBlueButtonManager; public EditBigBlueButtonMeetingController(UserRequest ureq, WindowControl wControl, - RepositoryEntry entry, String subIdent, BusinessGroup businessGroup) { + RepositoryEntry entry, String subIdent, BusinessGroup businessGroup, List<BigBlueButtonRoles> editionRoles) { super(ureq, wControl); this.entry = entry; this.subIdent = subIdent; this.businessGroup = businessGroup; + this.editionRoles = editionRoles; templates = bigBlueButtonManager.getTemplates(); initForm(ureq); updateUI(); } - public EditBigBlueButtonMeetingController(UserRequest ureq, WindowControl wControl, BigBlueButtonMeeting meeting) { + public EditBigBlueButtonMeetingController(UserRequest ureq, WindowControl wControl, + BigBlueButtonMeeting meeting, List<BigBlueButtonRoles> editionRoles) { super(ureq, wControl); entry = meeting.getEntry(); subIdent = meeting.getSubIdent(); businessGroup = meeting.getBusinessGroup(); this.meeting = meeting; + this.editionRoles = editionRoles; templates = bigBlueButtonManager.getTemplates(); initForm(ureq); @@ -125,7 +130,7 @@ public class EditBigBlueButtonMeetingController extends FormBasicController { ? null : meeting.getTemplate().getKey(); KeyValues templatesKeyValues = new KeyValues(); for(BigBlueButtonMeetingTemplate template:templates) { - if(template.isEnabled() || template.getKey().equals(selectedTemplateKey)) { + if(accept(template) || template.getKey().equals(selectedTemplateKey)) { templatesKeyValues.add(KeyValues.entry(template.getKey().toString(), template.getName())); } } @@ -145,7 +150,7 @@ public class EditBigBlueButtonMeetingController extends FormBasicController { } } } - if(!templateSelected) { + if(!templateSelected && templatesKeys.length > 0) { templateEl.select(templatesKeys[0], true); } openCalLink = uifactory.addFormLink("calendar.open", formLayout); @@ -169,7 +174,6 @@ public class EditBigBlueButtonMeetingController extends FormBasicController { String leadtime = meeting == null ? null : Long.toString(meeting.getLeadTime()); leadTimeEl = uifactory.addTextElement("meeting.leadTime", 8, leadtime, formLayout); - Date endDate = meeting == null ? null : meeting.getEndDate(); endDateEl = uifactory.addDateChooser("meeting.end", "meeting.end", endDate, formLayout); endDateEl.setMandatory(!permanent); @@ -185,6 +189,20 @@ public class EditBigBlueButtonMeetingController extends FormBasicController { uifactory.addFormSubmitButton("save", buttonLayout); } + private boolean accept(BigBlueButtonMeetingTemplate template) { + if(!template.isEnabled()) return false; + + List<BigBlueButtonRoles> roles = template.getPermittedRolesEnum(); + for(BigBlueButtonRoles role:roles) { + for(BigBlueButtonRoles editionRole:editionRoles) { + if(role.accept(editionRole)) { + return true; + } + } + } + return false; + } + private void updateUI() { boolean permanent = permanentEl.isAtLeastSelected(1); startDateEl.setVisible(!permanent); 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 90bc2fb3e92..802ffbf2a3b 100644 --- a/src/main/java/org/olat/modules/bigbluebutton/ui/EditBigBlueButtonTemplateController.java +++ b/src/main/java/org/olat/modules/bigbluebutton/ui/EditBigBlueButtonTemplateController.java @@ -19,6 +19,9 @@ */ package org.olat.modules.bigbluebutton.ui; +import java.util.List; +import java.util.stream.Collectors; + import org.olat.core.commons.persistence.DB; import org.olat.core.gui.UserRequest; import org.olat.core.gui.components.form.flexible.FormItem; @@ -29,12 +32,14 @@ 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; import org.olat.core.util.StringHelper; import org.olat.modules.bigbluebutton.BigBlueButtonManager; import org.olat.modules.bigbluebutton.BigBlueButtonMeetingTemplate; +import org.olat.modules.bigbluebutton.BigBlueButtonRoles; import org.springframework.beans.factory.annotation.Autowired; /** @@ -52,6 +57,7 @@ public class EditBigBlueButtonTemplateController extends FormBasicController { private TextElement descriptionEl; private MultipleSelectionElement enableEl; + private MultipleSelectionElement rolesEl; private TextElement maxConcurrentMeetingsEl; private TextElement maxParticipantsEl; @@ -115,6 +121,22 @@ public class EditBigBlueButtonTemplateController extends FormBasicController { enableEl = uifactory.addCheckboxesHorizontal("template.enabled", "template.enabled", formLayout, onKeys, new String[] { "" }); enableEl.select(onKeys[0], enable); + KeyValues rolesKeyValues = new KeyValues(); + for(BigBlueButtonRoles role:BigBlueButtonRoles.values()) { + rolesKeyValues.add(KeyValues.entry(role.name(), translate("role.".concat(role.name())))); + } + rolesEl = uifactory.addCheckboxesVertical("template.roles", "template.roles", formLayout, + rolesKeyValues.keys(), rolesKeyValues.values(), 1); + List<BigBlueButtonRoles> roles; + if(template != null) { + roles = template.getPermittedRolesEnum(); + } else { + roles = BigBlueButtonRoles.valuesAsList(); + } + for(BigBlueButtonRoles role:roles) { + rolesEl.select(role.name(), true); + } + String maxConcurrentMeetings = template == null || template.getMaxConcurrentMeetings() == null ? "" : template.getMaxConcurrentMeetings().toString(); maxConcurrentMeetingsEl = uifactory.addTextElement("template.max.concurrent.meetings", "template.max.concurrent.meetings", 8, maxConcurrentMeetings, formLayout); @@ -122,7 +144,12 @@ public class EditBigBlueButtonTemplateController extends FormBasicController { maxParticipantsEl = uifactory.addTextElement("template.maxParticipants", "template.maxParticipants", 8, maxParticipants, formLayout); maxParticipantsEl.setMandatory(true); - String maxDuration = template == null || template.getMaxDuration() == null ? null : template.getMaxDuration().toString(); + String maxDuration = null; + if(template == null) { + maxDuration = "240"; + } else if(template.getMaxDuration() != null) { + maxDuration = template.getMaxDuration().toString(); + } maxDurationEl = uifactory.addTextElement("template.maxDuration", "template.maxDuration", 8, maxDuration, formLayout); String[] onValues = new String[] { translate("yes"), translate("no") }; @@ -310,6 +337,10 @@ public class EditBigBlueButtonTemplateController extends FormBasicController { template.setDescription(descriptionEl.getValue()); template.setEnabled(enableEl.isAtLeastSelected(1)); + List<BigBlueButtonRoles> roles = rolesEl.getSelectedKeys().stream() + .map(BigBlueButtonRoles::valueOf).collect(Collectors.toList()); + template.setPermittedRolesEnum(roles); + if(StringHelper.containsNonWhitespace(maxConcurrentMeetingsEl.getValue()) && StringHelper.isLong(maxConcurrentMeetingsEl.getValue())) { template.setMaxConcurrentMeetings(Long.valueOf(maxConcurrentMeetingsEl.getValue()).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 d77f29c756f..7c4725999d2 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 @@ -66,6 +66,10 @@ recordings=Aufzeichnungen recording.browser.infos=Aufzeichnungen k\u00F6nnen nur mit Google Chrome und Firefox gesehen werden. recording.type.podcast=Podcast recording.type.presentation=Vorstellung +role.administrator=Administrator +role.author=Autor +role.coach=Coach +role.owner=Course owner server.overloaded=Es gibt kein Platz verf\u00FCgbar auf dem Server an den gew\u00E4hlten Datum. table.header.enabled=Eingeschaltet table.header.permanent=Dauernd @@ -104,6 +108,7 @@ template.max.concurrent.meetings=Max. gleichzeitige Meetings template.muteOnStart=Mute on start template.name=Name template.record=Aufzeichnen +template.roles=Erlaubt Vorlage zu verwenden 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 65544ffa033..1728d68cdd7 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 @@ -66,6 +66,10 @@ recordings=Recordings recording.browser.infos=Recordings can only be viewed with Google Chrome or Firefox. recording.type.podcast=Podcast recording.type.presentation=Presentation +role.administrator=Administrator +role.author=Author +role.coach=coach +role.owner=Kursbesitzer server.overloaded=There is no place available on the server for the choosen dates. table.header.enabled=Enabled table.header.permanent=Permanent @@ -104,6 +108,7 @@ template.max.concurrent.meetings=Max. concurrent meetings template.muteOnStart=Mute on start template.name=Name template.record=Record +template.roles=Allow to use the template template.webcamsOnlyForModerator=Webcams only for moderators templates.title=Templates view=View -- GitLab