/** * OLAT - Online Learning and Training<br> * http://www.olat.org * <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 * <p> * http://www.apache.org/licenses/LICENSE-2.0 * <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> * Copyright (c) since 2004 at Multimedia- & E-Learning Services (MELS),<br> * University of Zurich, Switzerland. * <hr> * <a href="http://www.openolat.org"> * OpenOLAT - Online Learning and Training</a><br> * This file has been modified by the OpenOLAT community. Changes are licensed * under the Apache 2.0 license as the original file. */ package org.olat.course.nodes.en; import java.util.ArrayList; import java.util.List; import org.olat.NewControllerFactory; import org.olat.basesecurity.GroupRoles; import org.olat.core.gui.UserRequest; import org.olat.core.gui.components.Component; import org.olat.core.gui.components.EscapeMode; import org.olat.core.gui.components.table.BooleanColumnDescriptor; import org.olat.core.gui.components.table.DefaultColumnDescriptor; import org.olat.core.gui.components.table.Table; import org.olat.core.gui.components.table.TableController; import org.olat.core.gui.components.table.TableEvent; import org.olat.core.gui.components.table.TableGuiConfiguration; import org.olat.core.gui.components.velocity.VelocityContainer; 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.gui.control.controller.BasicController; import org.olat.core.id.Identity; import org.olat.core.id.OLATResourceable; import org.olat.core.logging.OLog; import org.olat.core.logging.Tracing; import org.olat.core.util.StringHelper; import org.olat.core.util.coordinate.CoordinatorManager; import org.olat.core.util.event.GenericEventListener; import org.olat.core.util.resource.OLATResourceableJustBeforeDeletedEvent; import org.olat.core.util.resource.OresHelper; import org.olat.course.groupsandrights.CourseGroupManager; import org.olat.course.nodes.ENCourseNode; import org.olat.course.nodes.ObjectivesHelper; import org.olat.course.nodes.en.EnrollmentTableModelWithMaxSize.Stats; import org.olat.course.properties.CoursePropertyManager; import org.olat.course.run.userview.UserCourseEnvironment; import org.olat.group.BusinessGroup; import org.olat.group.BusinessGroupService; import org.olat.group.area.BGAreaManager; import org.olat.group.ui.edit.BusinessGroupModifiedEvent; import org.olat.modules.ModuleConfiguration; import org.olat.util.logging.activity.LoggingResourceable; import org.springframework.beans.factory.annotation.Autowired; /** * Description:<BR> * Run controller for the entrollment course node * <p> * Fires BusinessGroupModifiedEvent.IDENTITY_REMOVED_EVENT, and BusinessGroupModifiedEvent.IDENTITY_ADDED_EVENT via the * event agency (not controller events) * <P> * Initial Date: Sep 8, 2004 * * @author Felix Jost, gnaegi */ public class ENRunController extends BasicController implements GenericEventListener { private static final OLog log = Tracing.createLoggerFor(ENRunController.class); private static final String CMD_VISIT_CARD = "cmd.visit.card"; private static final String CMD_ENROLL_IN_GROUP = "cmd.enroll.in.group"; private static final String CMD_ENROLLED_CANCEL = "cmd.enrolled.cancel"; private ModuleConfiguration moduleConfig; private List<Long> enrollableGroupKeys; private List<Long> enrollableAreaKeys; private VelocityContainer enrollVC; private ENCourseNode enNode; private EnrollmentTableModelWithMaxSize groupListModel; private TableController tableCtr; @Autowired private BGAreaManager areaManager; @Autowired private EnrollmentManager enrollmentManager; @Autowired private BusinessGroupService businessGroupService; private final UserCourseEnvironment userCourseEnv; private CourseGroupManager courseGroupManager; private CoursePropertyManager coursePropertyManager; private boolean cancelEnrollEnabled; private int maxEnrollCount; //registered in event bus private List<Long> registeredGroupKeys; /** * @param moduleConfiguration * @param ureq * @param wControl * @param userCourseEnv * @param enNode */ public ENRunController(ModuleConfiguration moduleConfiguration, UserRequest ureq, WindowControl wControl, UserCourseEnvironment userCourseEnv, ENCourseNode enNode) { super(ureq, wControl); this.moduleConfig = moduleConfiguration; this.enNode = enNode; this.userCourseEnv = userCourseEnv; addLoggingResourceable(LoggingResourceable.wrap(enNode)); // init managers courseGroupManager = userCourseEnv.getCourseEnvironment().getCourseGroupManager(); coursePropertyManager = userCourseEnv.getCourseEnvironment().getCoursePropertyManager(); // Get groupnames from configuration enrollableGroupKeys = moduleConfig.getList(ENCourseNode.CONFIG_GROUP_IDS, Long.class); if(enrollableGroupKeys == null || enrollableGroupKeys.isEmpty()) { String groupNamesConfig = (String)moduleConfig.get(ENCourseNode.CONFIG_GROUPNAME); enrollableGroupKeys = businessGroupService.toGroupKeys(groupNamesConfig, courseGroupManager.getCourseEntry()); } enrollableAreaKeys = moduleConfig.getList(ENCourseNode.CONFIG_AREA_IDS, Long.class); if(enrollableAreaKeys == null || enrollableAreaKeys.isEmpty()) { String areaInitVal = (String) moduleConfig.get(ENCourseNode.CONFIG_AREANAME); enrollableAreaKeys = areaManager.toAreaKeys(areaInitVal, courseGroupManager.getCourseResource()); } maxEnrollCount = moduleConfiguration.getIntegerSafe(ENCourseNode.CONFIG_ALLOW_MULTIPLE_ENROLL_COUNT, 1); cancelEnrollEnabled = moduleConfig.getBooleanSafe(ENCourseNode.CONF_CANCEL_ENROLL_ENABLED); registerGroupChangedEvents(enrollableGroupKeys, enrollableAreaKeys, getIdentity()); // Set correct view enrollVC = createVelocityContainer("enrollmultiple"); List<EnrollmentRow> enrollmentRows = enrollmentManager.getEnrollments(getIdentity(), enrollableGroupKeys, enrollableAreaKeys, 256); groupListModel = new EnrollmentTableModelWithMaxSize(enrollmentRows, getTranslator(), getIdentity(), cancelEnrollEnabled, maxEnrollCount); Stats stats = groupListModel.getStats(); tableCtr = createTableController(ureq, stats.isSomeGroupWaitingListEnabled()); tableCtr.setTableDataModel(groupListModel); doEnrollView(stats); // push title and learning objectives, only visible on intro page enrollVC.contextPut("menuTitle", enNode.getShortTitle()); enrollVC.contextPut("displayTitle", enNode.getLongTitle()); // Adding learning objectives String learningObj = enNode.getLearningObjectives(); if (learningObj != null) { Component learningObjectives = ObjectivesHelper.createLearningObjectivesComponent(learningObj, ureq); enrollVC.put("learningObjectives", learningObjectives); enrollVC.contextPut("hasObjectives", learningObj); // dummy value, just an exists operator } putInitialPanel (enrollVC); } /** * @see org.olat.core.gui.control.DefaultController#event(org.olat.core.gui.UserRequest, org.olat.core.gui.components.Component, org.olat.core.gui.control.Event) */ @Override public void event(UserRequest ureq, Component source, Event event) { // } /** * @see org.olat.core.gui.control.DefaultController#event(org.olat.core.gui.UserRequest, org.olat.core.gui.control.Controller, org.olat.core.gui.control.Event) */ @Override public void event(UserRequest ureq, Controller source, Event event) { String cmd = event.getCommand(); if (source == tableCtr) { if (cmd.equals(Table.COMMANDLINK_ROWACTION_CLICKED)) { TableEvent te = (TableEvent) event; String actionid = te.getActionId(); int rowid = te.getRowId(); EnrollmentRow row = groupListModel.getObject(rowid); Long choosenGroupKey = row.getKey(); if (actionid.equals(CMD_ENROLL_IN_GROUP)) { BusinessGroup choosenGroup = businessGroupService.loadBusinessGroup(choosenGroupKey); addLoggingResourceable(LoggingResourceable.wrap(choosenGroup)); if(log.isDebug()) { log.debug("CMD_ENROLL_IN_GROUP ureq.getComponentID()=" + ureq.getComponentID() + " ureq.getComponentTimestamp()=" + ureq.getComponentTimestamp()); } EnrollStatus enrollStatus = enrollmentManager.doEnroll(ureq.getIdentity(), ureq.getUserSession().getRoles(), choosenGroup, enNode, coursePropertyManager, getWindowControl(), getTranslator(), enrollableGroupKeys, enrollableAreaKeys, courseGroupManager); if (enrollStatus.isEnrolled() || enrollStatus.isInWaitingList() ) { //OK } else { getWindowControl().setError(enrollStatus.getErrorMessage()); } // events are already fired BusinessGroupManager level :: BusinessGroupModifiedEvent.fireModifiedGroupEvents(BusinessGroupModifiedEvent.IDENTITY_ADDED_EVENT, choosenGroup, ureq.getIdentity()); // but async // fire event to indicate runmaincontroller that the menuview is to update doEnrollView(updateModel()); if (enrollStatus.isEnrolled() ) { fireEvent(ureq, new BusinessGroupModifiedEvent(BusinessGroupModifiedEvent.IDENTITY_ADDED_EVENT, choosenGroup, getIdentity())); } else { fireEvent(ureq, Event.DONE_EVENT); } } else if (actionid.equals(CMD_ENROLLED_CANCEL)) { BusinessGroup choosenGroup = businessGroupService.loadBusinessGroup(choosenGroupKey); addLoggingResourceable(LoggingResourceable.wrap(choosenGroup)); List<String> roles = businessGroupService .getIdentityRolesInBusinessGroup(getIdentity(), choosenGroup); if (roles.contains(GroupRoles.waiting.name())) { enrollmentManager.doCancelEnrollmentInWaitingList(ureq.getIdentity(), choosenGroup, enNode, coursePropertyManager, getWindowControl(), getTranslator()); } else if(roles.contains(GroupRoles.participant.name())) { enrollmentManager.doCancelEnrollment(ureq.getIdentity(), choosenGroup, enNode, coursePropertyManager, getWindowControl(), getTranslator()); } // fire event to indicate runmaincontroller that the menuview is to update fireEvent(ureq, new BusinessGroupModifiedEvent(BusinessGroupModifiedEvent.IDENTITY_REMOVED_EVENT, choosenGroup, getIdentity())); // events are already fired BusinessGroupManager level :: BusinessGroupModifiedEvent.fireModifiedGroupEvents(BusinessGroupModifiedEvent.IDENTITY_REMOVED_EVENT, group, ureq.getIdentity()); // but async doEnrollView(updateModel()); } else if(CMD_VISIT_CARD.equals(actionid)) { List<String> roles = businessGroupService.getIdentityRolesInBusinessGroup(getIdentity(), row); String businessPath; if(roles.contains(GroupRoles.coach.name()) || roles.contains(GroupRoles.participant.name())) { businessPath = "[BusinessGroup:" + choosenGroupKey + "]"; } else { businessPath = "[GroupCard:" + choosenGroupKey + "]"; } NewControllerFactory.getInstance().launch(businessPath, ureq, getWindowControl()); } } } } @Override public void event(Event event) { if (event instanceof OLATResourceableJustBeforeDeletedEvent) { dispose(); } } private void doEnrollView(Stats stats) { //num. of groups where the user is participant or in the waiting list int numOfParticipatingGroups = stats.getParticipantingGroupNames().size(); int numOfWaitingGroups = stats.getWaitingGroupNames().size(); enrollVC.contextPut("multiEnroll", (maxEnrollCount > 1 && numOfParticipatingGroups + numOfWaitingGroups < maxEnrollCount)); if(numOfParticipatingGroups > 0 || numOfWaitingGroups > 0){ String[] hintNumbers = new String[]{ String.valueOf(numOfParticipatingGroups + numOfWaitingGroups), String.valueOf(maxEnrollCount - numOfParticipatingGroups - numOfWaitingGroups) }; enrollVC.contextPut("multipleHint", translate("multiple.select.hint.outstanding", hintNumbers)); } else { enrollVC.contextPut("multipleHint", translate("multiple.select.hint", String.valueOf(maxEnrollCount))); } if (numOfParticipatingGroups > 0) { enrollVC.contextPut("isEnrolledView", Boolean.TRUE); List<String> groupnames = new ArrayList<String>(numOfParticipatingGroups); for(String groupName: stats.getParticipantingGroupNames()){ groupnames.add(StringHelper.escapeHtml(groupName)); } enrollVC.contextPut("groupNames", groupnames); } else { enrollVC.contextPut("isEnrolledView", Boolean.FALSE); } if (numOfWaitingGroups > 0){ enrollVC.contextPut("isInWaitingList", Boolean.TRUE); List<String> waitingListNames = new ArrayList<String>(numOfWaitingGroups); for(String groupName:stats.getWaitingGroupNames()){ waitingListNames.add(StringHelper.escapeHtml(groupName)); } enrollVC.contextPut("waitingListNames", waitingListNames); } else { enrollVC.contextPut("isInWaitingList", Boolean.FALSE); } // 3. Add group list to view enrollVC.put("grouplisttable", tableCtr.getInitialComponent()); } private Stats updateModel() { List<EnrollmentRow> enrollmentRows = enrollmentManager.getEnrollments(getIdentity(), enrollableGroupKeys, enrollableAreaKeys, 256); groupListModel = new EnrollmentTableModelWithMaxSize(enrollmentRows, getTranslator(), getIdentity(), cancelEnrollEnabled, maxEnrollCount); Stats stats = groupListModel.getStats(); tableCtr.setTableDataModel(groupListModel); return stats; } private TableController createTableController(UserRequest ureq, boolean hasAnyWaitingList) { TableGuiConfiguration tableConfig = new TableGuiConfiguration(); tableConfig.setTableEmptyMessage(translate("grouplist.no.groups")); removeAsListenerAndDispose(tableCtr); tableCtr = new TableController(tableConfig, ureq, getWindowControl(), getTranslator()); listenTo(tableCtr); tableCtr.addColumnDescriptor(new DefaultColumnDescriptor("grouplist.table.name", 0, CMD_VISIT_CARD, getLocale())); DefaultColumnDescriptor descCd = new DefaultColumnDescriptor("grouplist.table.desc", 1, null, getLocale()); descCd.setEscapeHtml(EscapeMode.antisamy); tableCtr.addColumnDescriptor(descCd); tableCtr.addColumnDescriptor(new DefaultColumnDescriptor("grouplist.table.partipiciant", 2, null, getLocale())); tableCtr.addColumnDescriptor(hasAnyWaitingList, new DefaultColumnDescriptor("grouplist.table.waitingList", 3, null, getLocale())); DefaultColumnDescriptor stateColdEsc = new DefaultColumnDescriptor("grouplist.table.state", 4, null, getLocale()); stateColdEsc.setEscapeHtml(EscapeMode.none); tableCtr.addColumnDescriptor(stateColdEsc); String enrollCmd = userCourseEnv.isCourseReadOnly() ? null : CMD_ENROLL_IN_GROUP; BooleanColumnDescriptor columnDesc = new BooleanColumnDescriptor("grouplist.table.enroll", 5, enrollCmd, translate(CMD_ENROLL_IN_GROUP), translate("grouplist.table.no_action")); columnDesc.setSortingAllowed(false); tableCtr.addColumnDescriptor(columnDesc); String cancelCmd = userCourseEnv.isCourseReadOnly() ? null : CMD_ENROLLED_CANCEL; tableCtr.addColumnDescriptor(new BooleanColumnDescriptor("grouplist.table.cancel_enroll", 6, cancelCmd, translate(CMD_ENROLLED_CANCEL), translate("grouplist.table.no_action"))); return tableCtr; } /** * * @see org.olat.core.gui.control.DefaultController#doDispose(boolean) */ @Override protected void doDispose() { deregisterGroupChangedEvents(); } /* * Add as listener to BusinessGroups so we are being notified about changes. */ private void registerGroupChangedEvents(List<Long> groupKeys, List<Long> areaKeys, Identity identity) { registeredGroupKeys = enrollmentManager.getBusinessGroupKeys(groupKeys, areaKeys); for (Long groupKey: registeredGroupKeys) { OLATResourceable ores = OresHelper.createOLATResourceableInstance(BusinessGroup.class, groupKey); CoordinatorManager.getInstance().getCoordinator().getEventBus().registerFor(this, identity, ores); } } private void deregisterGroupChangedEvents() { if(registeredGroupKeys != null) { for (Long groupKey:registeredGroupKeys) { OLATResourceable ores = OresHelper.createOLATResourceableInstance(BusinessGroup.class, groupKey); CoordinatorManager.getInstance().getCoordinator().getEventBus().deregisterFor(this, ores); } } } }