From 0f96e6a216710b390840762d97f9735cc0b1d343 Mon Sep 17 00:00:00 2001 From: uhensler <urs.hensler@frentix.com> Date: Wed, 31 Jul 2019 09:36:39 +0200 Subject: [PATCH] OO-4168: Course tool "information for participants" --- .../info/ui/InfoDisplayController.java | 23 +----- .../LearningResourceLoggingAction.java | 5 ++ .../org/olat/course/config/CourseConfig.java | 20 ++++- .../olat/course/config/CourseConfigEvent.java | 1 + .../config/ui/CourseToolbarController.java | 55 +++++++++---- .../ui/_i18n/LocalStrings_de.properties | 1 + .../ui/_i18n/LocalStrings_en.properties | 1 + .../course/nodes/info/InfoRunController.java | 79 +++++++++++++------ .../course/run/CourseRuntimeController.java | 65 +++++++++++++-- .../run/_i18n/LocalStrings_de.properties | 3 +- .../run/_i18n/LocalStrings_en.properties | 1 + .../RepositoryEntryManagedFlag.java | 3 +- .../ui/RepositoryEntryRuntimeController.java | 8 +- 13 files changed, 196 insertions(+), 69 deletions(-) diff --git a/src/main/java/org/olat/commons/info/ui/InfoDisplayController.java b/src/main/java/org/olat/commons/info/ui/InfoDisplayController.java index 101f9c47e1c..cdf14d6a1aa 100644 --- a/src/main/java/org/olat/commons/info/ui/InfoDisplayController.java +++ b/src/main/java/org/olat/commons/info/ui/InfoDisplayController.java @@ -75,9 +75,7 @@ import org.olat.core.util.resource.OresHelper; import org.olat.core.util.vfs.VFSConstants; import org.olat.core.util.vfs.VFSLeaf; import org.olat.core.util.vfs.VFSMediaResource; -import org.olat.course.nodes.info.InfoCourseNodeConfiguration; import org.olat.group.BusinessGroup; -import org.olat.modules.ModuleConfiguration; import org.olat.user.UserManager; import org.olat.util.logging.activity.LoggingResourceable; import org.springframework.beans.factory.annotation.Autowired; @@ -115,7 +113,6 @@ public class InfoDisplayController extends FormBasicController { private int maxResults = 0; private int maxResultsConfig = 0; - private int duration = -1; private Date after = null; private Date afterConfig = null; @@ -148,16 +145,16 @@ public class InfoDisplayController extends FormBasicController { loadMessages(); } - public InfoDisplayController(UserRequest ureq, WindowControl wControl, ModuleConfiguration config, + public InfoDisplayController(UserRequest ureq, WindowControl wControl, int maxResults, int duration, InfoSecurityCallback secCallback, OLATResourceable ores, String resSubPath, String businessPath) { super(ureq, wControl, "display"); this.secCallback = secCallback; this.ores = ores; this.resSubPath = resSubPath; this.businessPath = businessPath; + this.maxResults = maxResults; + this.maxResultsConfig = maxResults; - maxResults = maxResultsConfig = getConfigValue(config, InfoCourseNodeConfiguration.CONFIG_LENGTH, 10); - duration = getConfigValue(config, InfoCourseNodeConfiguration.CONFIG_DURATION, 90); thumbnailMapper = registerCacheableMapper(ureq, "InfoMessagesThumbnail", new ThumbnailMapper()); attachmentMapper = registerCacheableMapper(ureq, "InfoMessages", new AttachmentMapper()); @@ -189,19 +186,7 @@ public class InfoDisplayController extends FormBasicController { // now load with configuration loadMessages(); } - - private int getConfigValue(ModuleConfiguration config, String key, int def) { - String durationStr = (String)config.get(key); - if("\u221E".equals(durationStr)) { - return -1; - } else if(StringHelper.containsNonWhitespace(durationStr)) { - try { - return Integer.parseInt(durationStr); - } catch(NumberFormatException e) { /* fallback to default */ } - } - return def; - } - + public List<SendMailOption> getSendMailOptions() { return sendMailOptions; } diff --git a/src/main/java/org/olat/core/logging/activity/LearningResourceLoggingAction.java b/src/main/java/org/olat/core/logging/activity/LearningResourceLoggingAction.java index 07b8d608dda..4bd406986c9 100644 --- a/src/main/java/org/olat/core/logging/activity/LearningResourceLoggingAction.java +++ b/src/main/java/org/olat/core/logging/activity/LearningResourceLoggingAction.java @@ -95,6 +95,10 @@ public class LearningResourceLoggingAction extends BaseLoggingAction { new LearningResourceLoggingAction(ActionType.admin, CrudAction.update, ActionVerb.add, ActionObject.search).setTypeList(LEARNING_RESOURCE_OPEN_CLOSE_LIST); public static final ILoggingAction REPOSITORY_ENTRY_PROPERTIES_COURSESEARCH_DISABLED = new LearningResourceLoggingAction(ActionType.admin, CrudAction.update, ActionVerb.remove, ActionObject.search).setTypeList(LEARNING_RESOURCE_OPEN_CLOSE_LIST); + public static final ILoggingAction REPOSITORY_ENTRY_PROPERTIES_PARTICIPANTINFO_ENABLED = + new LearningResourceLoggingAction(ActionType.admin, CrudAction.update, ActionVerb.add, ActionObject.infomessage).setTypeList(LEARNING_RESOURCE_OPEN_CLOSE_LIST); + public static final ILoggingAction REPOSITORY_ENTRY_PROPERTIES_PARTICIPANTINFO_DISABLED = + new LearningResourceLoggingAction(ActionType.admin, CrudAction.update, ActionVerb.remove, ActionObject.infomessage).setTypeList(LEARNING_RESOURCE_OPEN_CLOSE_LIST); public static final ILoggingAction REPOSITORY_ENTRY_PROPERTIES_GLOSSARY_ENABLED = new LearningResourceLoggingAction(ActionType.admin, CrudAction.update, ActionVerb.add, ActionObject.glossar).setTypeList(LEARNING_RESOURCE_OPEN_CLOSE_LIST); public static final ILoggingAction REPOSITORY_ENTRY_PROPERTIES_GLOSSARY_DISABLED = @@ -169,6 +173,7 @@ public class LearningResourceLoggingAction extends BaseLoggingAction { * @see BaseLoggingAction#BaseLoggingAction(boolean, CrudAction, ActionVerb, String) * @deprecated */ + @Deprecated LearningResourceLoggingAction(ActionType resourceActionType, CrudAction action, ActionVerb actionVerb, String actionObject) { super(resourceActionType, action, actionVerb, actionObject); } diff --git a/src/main/java/org/olat/course/config/CourseConfig.java b/src/main/java/org/olat/course/config/CourseConfig.java index bb14583ccad..4010d011b6a 100644 --- a/src/main/java/org/olat/course/config/CourseConfig.java +++ b/src/main/java/org/olat/course/config/CourseConfig.java @@ -72,7 +72,7 @@ public class CourseConfig implements Serializable, Cloneable { /** * current config file version */ - private static final transient int CURRENTVERSION = 14; + private static final transient int CURRENTVERSION = 15; /** * Log levels */ @@ -119,6 +119,7 @@ public class CourseConfig implements Serializable, Cloneable { * The course search is enabled by default */ public static final transient String COURSESEARCH_ENABLED = "COURSESEARCH_ENABLED"; + public static final transient String PARTICIPANT_INFO_ENABLED = "PARTICIPANT_INFO_ENABLED"; /** * course calendar */ @@ -195,6 +196,7 @@ public class CourseConfig implements Serializable, Cloneable { configuration.put(TOOLBAR_ENABLED, Boolean.TRUE); configuration.put(COURSESEARCH_ENABLED, Boolean.TRUE); + configuration.put(PARTICIPANT_INFO_ENABLED, Boolean.FALSE); this.version = CURRENTVERSION; } @@ -293,6 +295,12 @@ public class CourseConfig implements Serializable, Cloneable { this.version = 14; } + + if (version == 14) { + if (!configuration.containsKey(PARTICIPANT_INFO_ENABLED)) configuration.put(PARTICIPANT_INFO_ENABLED, Boolean.FALSE); + + this.version = 15; + } /* @@ -618,6 +626,15 @@ public class CourseConfig implements Serializable, Cloneable { configuration.put(COURSESEARCH_ENABLED, Boolean.valueOf(b)); } + public boolean isParticipantInfoEnabled() { + Boolean bool = (Boolean) configuration.get(PARTICIPANT_INFO_ENABLED); + return bool.booleanValue(); + } + + public void setParticipantInfoEnabled(boolean b) { + configuration.put(PARTICIPANT_INFO_ENABLED, Boolean.valueOf(b)); + } + public boolean isToolbarEnabled() { Boolean bool = (Boolean) configuration.get(TOOLBAR_ENABLED); return bool.booleanValue(); @@ -665,6 +682,7 @@ public class CourseConfig implements Serializable, Cloneable { clone.setToolbarEnabled(isToolbarEnabled()); clone.setBreadCrumbEnabled(isBreadCrumbEnabled()); clone.setCourseSearchEnabled(isCourseSearchEnabled()); + clone.setParticipantInfoEnabled(isParticipantInfoEnabled()); return clone; } diff --git a/src/main/java/org/olat/course/config/CourseConfigEvent.java b/src/main/java/org/olat/course/config/CourseConfigEvent.java index f6622b66ba9..7b303753c49 100644 --- a/src/main/java/org/olat/course/config/CourseConfigEvent.java +++ b/src/main/java/org/olat/course/config/CourseConfigEvent.java @@ -58,6 +58,7 @@ public class CourseConfigEvent extends MultiUserEvent { public enum CourseConfigType { efficiencyStatement, + participantInfo, calendar, search, chat, diff --git a/src/main/java/org/olat/course/config/ui/CourseToolbarController.java b/src/main/java/org/olat/course/config/ui/CourseToolbarController.java index f5b47189220..30a571f8565 100644 --- a/src/main/java/org/olat/course/config/ui/CourseToolbarController.java +++ b/src/main/java/org/olat/course/config/ui/CourseToolbarController.java @@ -68,8 +68,9 @@ public class CourseToolbarController extends FormBasicController { private SelectionElement toolbarEl; private StaticTextElement explainEl; - private SelectionElement calendarEl; private SelectionElement searchEl; + private SelectionElement participantInfoEl; + private SelectionElement calendarEl; private SelectionElement chatEl; private SelectionElement glossaryEl; @@ -127,6 +128,25 @@ public class CourseToolbarController extends FormBasicController { explainEl = uifactory.addStaticTextElement("chkbx.toolbar.explain", "", formLayout); boolean canHideToolbar = true; + + boolean searchEnabled = courseConfig.isCourseSearchEnabled(); + boolean managedSearch = RepositoryEntryManagedFlag.isManaged(entry, RepositoryEntryManagedFlag.search); + searchEl = uifactory.addCheckboxesHorizontal("searchIsOn", "chkbx.search.onoff", formLayout, onKeys, onValues); + searchEl.select(onKeys[0], searchEnabled); + searchEl.setEnabled(editable && !managedSearch); + if(managedSearch && searchEnabled) { + canHideToolbar &= false; + } + + boolean participantInfoEnabled = courseConfig.isParticipantInfoEnabled(); + boolean managedInfo = RepositoryEntryManagedFlag.isManaged(entry, RepositoryEntryManagedFlag.participantInfo); + participantInfoEl = uifactory.addCheckboxesHorizontal("infoIsOn", "chkbx.participantinfo.onoff", formLayout, onKeys, onValues); + participantInfoEl.select(onKeys[0], participantInfoEnabled); + participantInfoEl.setEnabled(editable && !managedInfo); + if(managedInfo && participantInfoEnabled) { + canHideToolbar &= false; + } + if(calendarModule.isEnabled() && calendarModule.isEnableCourseToolCalendar()) { boolean calendarEnabled = courseConfig.isCalendarEnabled(); boolean managedCal = RepositoryEntryManagedFlag.isManaged(entry, RepositoryEntryManagedFlag.calendar); @@ -140,15 +160,6 @@ public class CourseToolbarController extends FormBasicController { } } - boolean searchEnabled = courseConfig.isCourseSearchEnabled(); - boolean managedSearch = RepositoryEntryManagedFlag.isManaged(entry, RepositoryEntryManagedFlag.search); - searchEl = uifactory.addCheckboxesHorizontal("searchIsOn", "chkbx.search.onoff", formLayout, onKeys, onValues); - searchEl.select(onKeys[0], searchEnabled); - searchEl.setEnabled(editable && !managedSearch); - if(managedSearch && searchEnabled) { - canHideToolbar &= false; - } - boolean chatEnabled = courseConfig.isChatEnabled(); boolean managedChat = RepositoryEntryManagedFlag.isManaged(entry, RepositoryEntryManagedFlag.chat); chatEl = uifactory.addCheckboxesHorizontal("chatIsOn", "chkbx.chat.onoff", formLayout, onKeys, onValues); @@ -191,20 +202,22 @@ public class CourseToolbarController extends FormBasicController { } private boolean isAnyToolSelected() { - return (calendarEl != null && calendarEl.isSelected(0)) + return searchEl.isSelected(0) + || participantInfoEl.isSelected(0) + || (calendarEl != null && calendarEl.isSelected(0)) || chatEl.isSelected(0) - || searchEl.isSelected(0) || glossaryEl.isSelected(0); } private void updateToolbar() { boolean enabled = toolbarEl.isSelected(0); explainEl.setVisible(enabled); + searchEl.setVisible(enabled); + participantInfoEl.setVisible(enabled); if(calendarEl != null) { calendarEl.setVisible(enabled); } chatEl.setVisible(enabled); - searchEl.setVisible(enabled); glossaryEl.setVisible(enabled); } @@ -221,6 +234,10 @@ public class CourseToolbarController extends FormBasicController { boolean updateSearch = courseConfig.isCourseSearchEnabled() != enableSearch; courseConfig.setCourseSearchEnabled(enableSearch && toolbarEnabled); + boolean enableParticipantInfo = searchEl.isSelected(0); + boolean updateParticipantInfo = courseConfig.isParticipantInfoEnabled() != enableParticipantInfo; + courseConfig.setParticipantInfoEnabled(enableParticipantInfo && toolbarEnabled); + boolean enableChat = chatEl.isSelected(0); boolean updateChat = courseConfig.isChatEnabled() != enableChat; courseConfig.setChatIsEnabled(enableChat && toolbarEnabled); @@ -237,7 +254,7 @@ public class CourseToolbarController extends FormBasicController { CourseFactory.closeCourseEditSession(course.getResourceableId(), true); if(updateSearch) { - ILoggingAction loggingAction =enableSearch ? + ILoggingAction loggingAction = enableSearch ? LearningResourceLoggingAction.REPOSITORY_ENTRY_PROPERTIES_COURSESEARCH_ENABLED: LearningResourceLoggingAction.REPOSITORY_ENTRY_PROPERTIES_COURSESEARCH_DISABLED; ThreadLocalUserActivityLogger.log(loggingAction, getClass()); @@ -245,6 +262,16 @@ public class CourseToolbarController extends FormBasicController { CoordinatorManager.getInstance().getCoordinator().getEventBus() .fireEventToListenersOf(new CourseConfigEvent(CourseConfigType.search, course.getResourceableId()), course); } + + if(updateParticipantInfo) { + ILoggingAction loggingAction = enableParticipantInfo ? + LearningResourceLoggingAction.REPOSITORY_ENTRY_PROPERTIES_PARTICIPANTINFO_ENABLED: + LearningResourceLoggingAction.REPOSITORY_ENTRY_PROPERTIES_PARTICIPANTINFO_DISABLED; + ThreadLocalUserActivityLogger.log(loggingAction, getClass()); + + CoordinatorManager.getInstance().getCoordinator().getEventBus() + .fireEventToListenersOf(new CourseConfigEvent(CourseConfigType.participantInfo, course.getResourceableId()), course); + } if(updateChat) { ILoggingAction loggingAction =enableChat ? diff --git a/src/main/java/org/olat/course/config/ui/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/course/config/ui/_i18n/LocalStrings_de.properties index 361685f2e48..fb2df7b6054 100644 --- a/src/main/java/org/olat/course/config/ui/_i18n/LocalStrings_de.properties +++ b/src/main/java/org/olat/course/config/ui/_i18n/LocalStrings_de.properties @@ -7,6 +7,7 @@ chkbx.glossary.inverse.explain=Glossar Menu in Toolbar muss unter "Toolbar" konf chkbx.glossary.onoff=Glossar chkbx.search.onoff=Kurssuche chkbx.menu.onoff=Menu sichtbar f\u00FCr Teilnehmer und Betreuer +chkbx.participantinfo.onoff=Teilnehmer Infos chkbx.toolbar.explain=Werkzeuge in Toolbar aktivieren: chkbx.toolbar.onoff=Toolbar sichtbar f\u00FCr Teilnehmer chkbx.toolbar.off.warning=Wenn sie die Toolbar abschalten, stehen die einzelnen Werkzeuge ebenfalls nicht mehr zur Verf\u00FCgung. diff --git a/src/main/java/org/olat/course/config/ui/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/course/config/ui/_i18n/LocalStrings_en.properties index f21a4a7831c..73df9d805f7 100644 --- a/src/main/java/org/olat/course/config/ui/_i18n/LocalStrings_en.properties +++ b/src/main/java/org/olat/course/config/ui/_i18n/LocalStrings_en.properties @@ -7,6 +7,7 @@ chkbx.glossary.explain=The glossary need to be configured under "Options". chkbx.glossary.inverse.explain=Glossary menu in toolbar is configured under "Toolbar". chkbx.glossary.onoff=Glossary chkbx.menu.onoff=Menu visible for participants and coaches +chkbx.participantinfo.onoff=Participant infos chkbx.toolbar.explain=Activate tools in toolbar: chkbx.toolbar.onoff=Toolbar visible for participants chkbx.toolbar.off.warning=If you disable the toolbar, the individual tools are also no longer available. diff --git a/src/main/java/org/olat/course/nodes/info/InfoRunController.java b/src/main/java/org/olat/course/nodes/info/InfoRunController.java index 0357267bb55..a14fdcdf600 100644 --- a/src/main/java/org/olat/course/nodes/info/InfoRunController.java +++ b/src/main/java/org/olat/course/nodes/info/InfoRunController.java @@ -45,6 +45,7 @@ import org.olat.core.gui.control.WindowControl; import org.olat.core.gui.control.controller.BasicController; import org.olat.core.id.Identity; import org.olat.core.id.OLATResourceable; +import org.olat.core.util.StringHelper; import org.olat.core.util.UserSession; import org.olat.core.util.resource.OresHelper; import org.olat.course.CourseFactory; @@ -55,6 +56,7 @@ import org.olat.course.nodes.InfoCourseNode; import org.olat.course.run.userview.NodeEvaluation; import org.olat.course.run.userview.UserCourseEnvironment; import org.olat.modules.ModuleConfiguration; +import org.olat.repository.RepositoryEntry; import org.springframework.beans.factory.annotation.Autowired; /** @@ -68,11 +70,11 @@ import org.springframework.beans.factory.annotation.Autowired; */ public class InfoRunController extends BasicController { - private final VelocityContainer runVc; - private final InfoDisplayController infoDisplayController; + private VelocityContainer runVc; + private InfoDisplayController infoDisplayController; private ContextualSubscriptionController subscriptionController; - private final String businessPath; + private String businessPath; @Autowired private InfoSubscriptionManager subscriptionManager; @@ -81,21 +83,49 @@ public class InfoRunController extends BasicController { NodeEvaluation ne, InfoCourseNode courseNode) { super(ureq, wControl); ModuleConfiguration config = courseNode.getModuleConfiguration(); - - Long resId = userCourseEnv.getCourseEnvironment().getCourseResourceableId(); - String resSubPath = courseNode.getIdent(); + + boolean canAdd; + boolean canAdmin; + if(userCourseEnv.isCourseReadOnly()) { + canAdd = false; + canAdmin = false; + } else { + boolean isAdmin = userCourseEnv.isAdmin(); + canAdd = isAdmin || ne.isCapabilityAccessible(InfoCourseNode.EDIT_CONDITION_ID); + canAdmin = isAdmin || ne.isCapabilityAccessible(InfoCourseNode.ADMIN_CONDITION_ID); + } + + boolean autoSubscribe = InfoCourseNodeEditController.getAutoSubscribe(config); + int maxResults = getConfigValue(config, InfoCourseNodeConfiguration.CONFIG_LENGTH, 10); + int duration = getConfigValue(config, InfoCourseNodeConfiguration.CONFIG_DURATION, 90); + + initVC(ureq, userCourseEnv, resSubPath, canAdd, canAdmin, autoSubscribe, maxResults, duration); + } + + public InfoRunController(UserRequest ureq, WindowControl wControl, UserCourseEnvironment userCourseEnv, + String resSubPath, boolean canAdd, boolean canAdmin, boolean autoSubscribe) { + super(ureq, wControl); + initVC(ureq, userCourseEnv, resSubPath, canAdd, canAdmin, autoSubscribe, -1, -1); + } + + private void initVC(UserRequest ureq, UserCourseEnvironment userCourseEnv, + String resSubPath, boolean canAdd, boolean canAdmin, boolean autoSubscribe, int maxResults, int duration) { + Long resId = userCourseEnv.getCourseEnvironment().getCourseResourceableId(); OLATResourceable infoResourceable = new InfoOLATResourceable(resId); - businessPath = normalizeBusinessPath(wControl.getBusinessControl().getAsString()); + businessPath = normalizeBusinessPath(getWindowControl().getBusinessControl().getAsString()); ICourse course = CourseFactory.loadCourse(resId); + CourseGroupManager cgm = userCourseEnv.getCourseEnvironment().getCourseGroupManager(); + RepositoryEntry courseEntry = cgm.getCourseEntry(); + String infoMailTitle = course.getCourseTitle(); //manage opt-out subscription UserSession usess = ureq.getUserSession(); if(!usess.getRoles().isGuestOnly()) { SubscriptionContext subContext = subscriptionManager.getInfoSubscriptionContext(infoResourceable, resSubPath); PublisherData pdata = subscriptionManager.getInfoPublisherData(infoResourceable, businessPath); - if(InfoCourseNodeEditController.getAutoSubscribe(config)) { + if(autoSubscribe) { InfoSubscription infoSubscription = subscriptionManager.getInfoSubscription(usess.getGuiPreferences()); if(infoSubscription.subscribed(businessPath, false)) { subscriptionManager.subscribe(infoResourceable, resSubPath, businessPath, getIdentity()); @@ -104,26 +134,17 @@ public class InfoRunController extends BasicController { subscriptionController = new ContextualSubscriptionController(ureq, getWindowControl(), subContext, pdata); listenTo(subscriptionController); } - boolean canAdd; - boolean canAdmin; - if(userCourseEnv.isCourseReadOnly()) { - canAdd = false; - canAdmin = false; - } else { - boolean isAdmin = userCourseEnv.isAdmin(); - canAdd = isAdmin || ne.isCapabilityAccessible(InfoCourseNode.EDIT_CONDITION_ID); - canAdmin = isAdmin || ne.isCapabilityAccessible(InfoCourseNode.ADMIN_CONDITION_ID); - } InfoSecurityCallback secCallback = new InfoCourseSecurityCallback(getIdentity(), canAdd, canAdmin); - infoDisplayController = new InfoDisplayController(ureq, wControl, config, secCallback, infoResourceable, resSubPath, businessPath); + + infoDisplayController = new InfoDisplayController(ureq, getWindowControl(), maxResults, duration, secCallback, infoResourceable, resSubPath, businessPath); infoDisplayController.addSendMailOptions(new SendSubscriberMailOption(infoResourceable, resSubPath, getLocale())); - infoDisplayController.addSendMailOptions(new SendMembersMailOption(cgm.getCourseEntry(), GroupRoles.owner, translate("wizard.step1.send_option.owner"))); - infoDisplayController.addSendMailOptions(new SendMembersMailOption(cgm.getCourseEntry(), GroupRoles.coach, translate("wizard.step1.send_option.coach"))); - infoDisplayController.addSendMailOptions(new SendMembersMailOption(cgm.getCourseEntry(), GroupRoles.participant, translate("wizard.step1.send_option.participant"))); + infoDisplayController.addSendMailOptions(new SendMembersMailOption(courseEntry, GroupRoles.owner, translate("wizard.step1.send_option.owner"))); + infoDisplayController.addSendMailOptions(new SendMembersMailOption(courseEntry, GroupRoles.coach, translate("wizard.step1.send_option.coach"))); + infoDisplayController.addSendMailOptions(new SendMembersMailOption(courseEntry, GroupRoles.participant, translate("wizard.step1.send_option.participant"))); - MailFormatter mailFormatter = new SendInfoMailFormatter(course.getCourseTitle(), businessPath, getTranslator()); + MailFormatter mailFormatter = new SendInfoMailFormatter(infoMailTitle, businessPath, getTranslator()); infoDisplayController.setSendMailFormatter(mailFormatter); listenTo(infoDisplayController); @@ -136,6 +157,18 @@ public class InfoRunController extends BasicController { putInitialPanel(runVc); } + private int getConfigValue(ModuleConfiguration config, String key, int def) { + String durationStr = (String)config.get(key); + if("\u221E".equals(durationStr)) { + return -1; + } else if(StringHelper.containsNonWhitespace(durationStr)) { + try { + return Integer.parseInt(durationStr); + } catch(NumberFormatException e) { /* fallback to default */ } + } + return def; + } + /** * Remove ROOT, remove identity context entry or duplicate, * @param url diff --git a/src/main/java/org/olat/course/run/CourseRuntimeController.java b/src/main/java/org/olat/course/run/CourseRuntimeController.java index a9cc8f1ceae..31303d86ca3 100644 --- a/src/main/java/org/olat/course/run/CourseRuntimeController.java +++ b/src/main/java/org/olat/course/run/CourseRuntimeController.java @@ -103,6 +103,7 @@ import org.olat.course.groupsandrights.CourseRights; import org.olat.course.member.MembersManagementMainController; import org.olat.course.nodes.CourseNode; import org.olat.course.nodes.ENCourseNode; +import org.olat.course.nodes.info.InfoRunController; import org.olat.course.reminder.ui.CourseRemindersController; import org.olat.course.run.calendar.CourseCalendarController; import org.olat.course.run.glossary.CourseGlossaryFactory; @@ -172,6 +173,7 @@ public class CourseRuntimeController extends RepositoryEntryRuntimeController im assessmentModeLink, lifeCycleChangeLink, //my course efficiencyStatementsLink, calendarLink, noteLink, chatLink, leaveLink, searchLink, + participantInfoLink, //glossary openGlossaryLink, enableGlossaryLink, lecturesLink; private Link currentUserCountLink; @@ -183,6 +185,7 @@ public class CourseRuntimeController extends RepositoryEntryRuntimeController im private ArchiverMainController archiverCtrl; private CustomDBMainController databasesCtrl; private FolderRunController courseFolderCtrl; + private InfoRunController participatInfoCtrl; private SearchInputController searchController; private StatisticMainController statisticsCtrl; private CourseRemindersController remindersCtrl; @@ -778,11 +781,17 @@ public class CourseRuntimeController extends RepositoryEntryRuntimeController im UserCourseEnvironment userCourseEnv = getUserCourseEnvironment(); CourseConfig cc = course.getCourseConfig(); - if (!assessmentLock && showInfos) { + if (!assessmentLock && showDetails) { detailsLink = LinkFactory.createToolLink("courseconfig",translate("command.courseconfig"), this, "o_icon_details"); toolbarPanel.addTool(detailsLink); } + if(!assessmentLock) { + participantInfoLink = LinkFactory.createToolLink("participantinfo", translate("command.participant.info"), this, "o_infomsg_icon"); + participantInfoLink.setVisible(cc.isParticipantInfoEnabled()); + toolbarPanel.addTool(participantInfoLink); + } + boolean calendarIsEnabled = !assessmentLock && !isGuestOnly && calendarModule.isEnabled() && calendarModule.isEnableCourseToolCalendar() && reSecurity.canLaunch(); if (calendarIsEnabled && userCourseEnv != null) { @@ -923,6 +932,8 @@ public class CourseRuntimeController extends RepositoryEntryRuntimeController im doAssessmentSurveyStatistics(ureq); } else if(assessmentLink == source) { doAssessmentTool(ureq); + } else if(participantInfoLink == source) { + doParticipantInfo(ureq); } else if(calendarLink == source) { launchCalendar(ureq); } else if(chatLink == source) { @@ -1024,6 +1035,7 @@ public class CourseRuntimeController extends RepositoryEntryRuntimeController im case orders: doOrders(ureq); break; case close: doClose(ureq); break; case pop: popToRoot(ureq); cleanUp(); break; + case participantInfo: doParticipantInfo(ureq); break; } delayedClose = null; } else { @@ -1090,6 +1102,8 @@ public class CourseRuntimeController extends RepositoryEntryRuntimeController im } else if("Settings".equalsIgnoreCase(type) || "EditDescription".equalsIgnoreCase(type)) { List<ContextEntry> subEntries = entries.subList(1, entries.size()); doSettings(ureq, subEntries); + } else if("ParticipantInfos".equalsIgnoreCase(type)) { + doParticipantInfo(ureq); } else if("Certification".equalsIgnoreCase(type)) { doEfficiencyStatements(ureq); } else if("Reminders".equalsIgnoreCase(type) || "RemindersLogs".equalsIgnoreCase(type)) { @@ -1622,12 +1636,41 @@ public class CourseRuntimeController extends RepositoryEntryRuntimeController im listenTo(courseSearchCalloutCtr); } + private void doParticipantInfo(UserRequest ureq) { + if(delayedClose == Delayed.participantInfo || requestForClose(ureq)) { + removeCustomCSS(); + + boolean autoSubscribe = false; + boolean canAdd; + boolean canAdmin; + if(getUserCourseEnvironment().isCourseReadOnly()) { + canAdd = false; + canAdmin = false; + } else { + boolean isAdmin = getUserCourseEnvironment().isAdmin(); + canAdd = isAdmin; + canAdmin = isAdmin; + } + + OLATResourceable ores = OresHelper.createOLATResourceableType("participantInfos"); + WindowControl swControl = addToHistory(ureq, ores, null); + participatInfoCtrl = new InfoRunController(ureq, swControl, getUserCourseEnvironment(), "participantInfos", + canAdd, canAdmin, autoSubscribe); + + pushController(ureq, translate("command.participant.info"), participatInfoCtrl); + setActiveTool(participantInfoLink); + currentToolCtr = participatInfoCtrl; + } else { + delayedClose = Delayed.participantInfo; + }; + } + private void launchCalendar(UserRequest ureq) { ControllerCreator ctrlCreator = (lureq, lwControl) -> { ICourse course = CourseFactory.loadCourse(getRepositoryEntry()); ContextEntry ce = BusinessControlFactory.getInstance().createContextEntry(getRepositoryEntry()); WindowControl llwControl = BusinessControlFactory.getInstance().createBusinessWindowControl(ce, lwControl); - CourseCalendarController calendarController = new CourseCalendarController(lureq, llwControl, getUserCourseEnvironment()); + CourseCalendarController calendarController = new CourseCalendarController(lureq, llwControl, getUserCourseEnvironment()); // use a one-column main layout LayoutMain3ColsController layoutCtr = new LayoutMain3ColsController(lureq, llwControl, calendarController); layoutCtr.setCustomCSS(CourseFactory.getCustomCourseCss(lureq.getUserSession(), course.getCourseEnvironment())); @@ -1729,6 +1772,15 @@ public class CourseRuntimeController extends RepositoryEntryRuntimeController im private void processCourseConfigEvent(CourseConfigEvent event) { switch(event.getType()) { + case search: { + if(searchLink != null) { + ICourse course = CourseFactory.loadCourse(getRepositoryEntry()); + CourseConfig cc = course.getCourseEnvironment().getCourseConfig(); + searchLink.setVisible(cc.isCourseSearchEnabled()); + toolbarPanel.setDirty(true); + } + break; + } case calendar: { if(calendarLink != null) { ICourse course = CourseFactory.loadCourse(getRepositoryEntry()); @@ -1738,11 +1790,11 @@ public class CourseRuntimeController extends RepositoryEntryRuntimeController im } break; } - case search: { - if(searchLink != null) { + case participantInfo: { + if(participantInfoLink != null) { ICourse course = CourseFactory.loadCourse(getRepositoryEntry()); CourseConfig cc = course.getCourseEnvironment().getCourseConfig(); - searchLink.setVisible(cc.isCourseSearchEnabled()); + calendarLink.setVisible(cc.isCalendarEnabled() && calendarModule.isEnabled() && calendarModule.isEnableCourseToolCalendar()); toolbarPanel.setDirty(true); } break; @@ -1883,6 +1935,7 @@ public class CourseRuntimeController extends RepositoryEntryRuntimeController im members, orders, close, - pop + pop, + participantInfo } } \ No newline at end of file diff --git a/src/main/java/org/olat/course/run/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/course/run/_i18n/LocalStrings_de.properties index f2a30ca4e58..d328a1db150 100644 --- a/src/main/java/org/olat/course/run/_i18n/LocalStrings_de.properties +++ b/src/main/java/org/olat/course/run/_i18n/LocalStrings_de.properties @@ -14,7 +14,7 @@ command.coursefolder=Ablageordner command.coursesearch=Kurssuche command.efficiencystatement=Leistungsnachweis command.glossary=Glossar -command.glossary.open=Glossar in separatem Fenster \u00f6ffnen +command.glossary.open=Glossar in separatem Fenster \u00F6ffnen command.glossary.off=aus command.glossary.off.alt=Glossarbegriffe von Lerninhalt ausblenden command.glossary.on=ein @@ -36,6 +36,7 @@ command.options=Optionen command.options.certificates=Leistungnachweis command.options.lectures.admin=Lektionen und Absenzen command.options.reminders=Erinnerung +command.participant.info=Teilnehmerinfos command.personalnote=Notizen command.previous=Zur\u00FCck zur letzten Seite command.reminders=Erinnerung diff --git a/src/main/java/org/olat/course/run/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/course/run/_i18n/LocalStrings_en.properties index 7869161e707..368375a782c 100644 --- a/src/main/java/org/olat/course/run/_i18n/LocalStrings_en.properties +++ b/src/main/java/org/olat/course/run/_i18n/LocalStrings_en.properties @@ -36,6 +36,7 @@ command.options=Options command.options.certificates=Evidence of achievement command.options.lectures.admin=Lectures and absences command.options.reminders=Reminders +command.participant.info=Participant infos command.personalnote=Notes command.previous=Go to previous page command.reminders=Reminders diff --git a/src/main/java/org/olat/repository/RepositoryEntryManagedFlag.java b/src/main/java/org/olat/repository/RepositoryEntryManagedFlag.java index 8335710926b..325d5bdbd6d 100644 --- a/src/main/java/org/olat/repository/RepositoryEntryManagedFlag.java +++ b/src/main/java/org/olat/repository/RepositoryEntryManagedFlag.java @@ -21,8 +21,8 @@ package org.olat.repository; import java.util.Arrays; -import org.olat.core.CoreSpringFactory; import org.apache.logging.log4j.Logger; +import org.olat.core.CoreSpringFactory; import org.olat.core.logging.Tracing; import org.olat.core.util.StringHelper; @@ -47,6 +47,7 @@ public enum RepositoryEntryManagedFlag { settings(all),//max num of participants... access(settings,all), search(settings, all), + participantInfo(settings, all), chat(settings,all), layout(settings,all), resourcefolder(settings,all), diff --git a/src/main/java/org/olat/repository/ui/RepositoryEntryRuntimeController.java b/src/main/java/org/olat/repository/ui/RepositoryEntryRuntimeController.java index 640b2d205fa..e13aad62a35 100644 --- a/src/main/java/org/olat/repository/ui/RepositoryEntryRuntimeController.java +++ b/src/main/java/org/olat/repository/ui/RepositoryEntryRuntimeController.java @@ -148,7 +148,7 @@ public class RepositoryEntryRuntimeController extends MainLayoutBasicController protected RepositoryEntrySecurity reSecurity; protected final Roles roles; - protected final boolean showInfos; + protected final boolean showDetails; protected final boolean allowBookmark; protected boolean corrupted; @@ -190,7 +190,7 @@ public class RepositoryEntryRuntimeController extends MainLayoutBasicController } public RepositoryEntryRuntimeController(UserRequest ureq, WindowControl wControl, RepositoryEntry re, - RepositoryEntrySecurity reSecurity, RuntimeControllerCreator runtimeControllerCreator, boolean allowBookmark, boolean showInfos) { + RepositoryEntrySecurity reSecurity, RuntimeControllerCreator runtimeControllerCreator, boolean allowBookmark, boolean showDetails) { super(ureq, wControl); setTranslator(Util.createPackageTranslator(RepositoryService.class, getLocale(), getTranslator())); @@ -208,7 +208,7 @@ public class RepositoryEntryRuntimeController extends MainLayoutBasicController } this.re = re; - this.showInfos = showInfos; + this.showDetails = showDetails; this.allowBookmark = allowBookmark; this.runtimeControllerCreator = runtimeControllerCreator; organisations = repositoryService.getOrganisationReferences(re); @@ -372,7 +372,7 @@ public class RepositoryEntryRuntimeController extends MainLayoutBasicController detailsLink = LinkFactory.createToolLink("details", translate("details.header"), this, "o_sel_repo_details"); detailsLink.setIconLeftCSS("o_icon o_icon-fw o_icon_details"); detailsLink.setElementCssClass("o_sel_author_details"); - detailsLink.setVisible(showInfos); + detailsLink.setVisible(showDetails); toolbarPanel.addTool(detailsLink); boolean marked = markManager.isMarked(re, getIdentity(), null); -- GitLab