/** * <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.admin.user.groups; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import org.olat.NewControllerFactory; import org.olat.admin.user.groups.BusinessGroupTableModelWithType.Cols; import org.olat.basesecurity.GroupRoles; import org.olat.core.CoreSpringFactory; import org.olat.core.gui.UserRequest; import org.olat.core.gui.components.Component; import org.olat.core.gui.components.link.Link; import org.olat.core.gui.components.link.LinkFactory; import org.olat.core.gui.components.table.BooleanColumnDescriptor; import org.olat.core.gui.components.table.ColumnDescriptor; import org.olat.core.gui.components.table.CustomCellRenderer; import org.olat.core.gui.components.table.CustomRenderColumnDescriptor; 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.TableMultiSelectEvent; 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.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.Identity; import org.olat.core.util.Util; import org.olat.core.util.mail.MailHelper; import org.olat.core.util.mail.MailPackage; import org.olat.group.BusinessGroup; import org.olat.group.BusinessGroupMembership; import org.olat.group.BusinessGroupModule; import org.olat.group.BusinessGroupService; import org.olat.group.model.AddToGroupsEvent; import org.olat.group.model.BusinessGroupMembershipChange; import org.olat.group.model.SearchBusinessGroupParams; import org.olat.group.ui.main.BGRoleCellRenderer; /** * Description:<br> * GroupOverviewController creates a model and displays a table with all groups a user is in. * The following rows are shown: type of group, groupname, * role of user in group (participant, owner, on waiting list), date of joining the group * * <P> * Initial Date: 22.09.2008 <br> * @author Roman Haag, frentix GmbH, roman.haag@frentix.com */ public class GroupOverviewController extends BasicController { private static final String TABLE_ACTION_LAUNCH = "bgTblLaunch"; private static final String TABLE_ACTION_UNSUBSCRIBE = "unsubscribe"; private VelocityContainer vc; private TableController groupListCtr; private BusinessGroupTableModelWithType tableDataModel; private Link addGroups; private DialogBoxController confirmSendMailBox; private CloseableModalController cmc; private GroupSearchController groupsCtrl; private GroupLeaveDialogBoxController removeFromGrpDlg; private final BusinessGroupModule groupModule; private final BusinessGroupService businessGroupService; private final Identity identity; public GroupOverviewController(UserRequest ureq, WindowControl control, Identity identity, Boolean canStartGroups) { super(ureq, control, Util.createPackageTranslator(BusinessGroupTableModelWithType.class, ureq.getLocale())); setTranslator(Util.createPackageTranslator(BGRoleCellRenderer.class, getLocale(), getTranslator())); this.identity = identity; groupModule = CoreSpringFactory.getImpl(BusinessGroupModule.class); businessGroupService = CoreSpringFactory.getImpl(BusinessGroupService.class); vc = createVelocityContainer("groupoverview"); groupListCtr = new TableController(null, ureq, control, getTranslator()); listenTo(groupListCtr); groupListCtr.addColumnDescriptor(new BusinessGroupNameColumnDescriptor(canStartGroups ? TABLE_ACTION_LAUNCH : null, getLocale())); groupListCtr.addColumnDescriptor(false, new DefaultColumnDescriptor(Cols.key.i18n(), Cols.key.ordinal(), null, getLocale())); groupListCtr.addColumnDescriptor(new DefaultColumnDescriptor(Cols.firstTime.i18n(), Cols.firstTime.ordinal(), null, getLocale())); groupListCtr.addColumnDescriptor(new DefaultColumnDescriptor(Cols.lastTime.i18n(), Cols.lastTime.ordinal(), null, getLocale())); CustomCellRenderer roleRenderer = new BGRoleCellRenderer(getLocale()); groupListCtr.addColumnDescriptor(new CustomRenderColumnDescriptor(Cols.role.i18n(), Cols.role.ordinal(), null, getLocale(), ColumnDescriptor.ALIGNMENT_LEFT, roleRenderer)); groupListCtr.addColumnDescriptor(new BooleanColumnDescriptor(Cols.allowLeave.i18n(), Cols.allowLeave.ordinal(), TABLE_ACTION_UNSUBSCRIBE, translate("table.header.leave"), null)); groupListCtr.setMultiSelect(true); groupListCtr.addMultiSelectAction("table.leave", TABLE_ACTION_UNSUBSCRIBE); tableDataModel = new BusinessGroupTableModelWithType(getTranslator(), 4); groupListCtr.setTableDataModel(tableDataModel); updateModel(); addGroups = LinkFactory.createButton("add.groups", vc, this); vc.put("table.groups", groupListCtr.getInitialComponent()); putInitialPanel(vc); } /** * @param ureq * @param control * @param identity * @return */ private void updateModel() { SearchBusinessGroupParams params = new SearchBusinessGroupParams(); params.setIdentity(identity); params.setOwner(true); params.setAttendee(true); params.setWaiting(true); List<BusinessGroup> groups = businessGroupService.findBusinessGroups(params, null, 0, -1); List<Long> groupKeysWithMembers; if(groups.size() > 50) { groupKeysWithMembers = null; } else { groupKeysWithMembers = new ArrayList<Long>(groups.size()); for(BusinessGroup view:groups) { groupKeysWithMembers.add(view.getKey()); } } //retrieve all user's membership if there are more than 50 groups List<BusinessGroupMembership> groupsAsOwner = businessGroupService.getBusinessGroupMembership(groupKeysWithMembers, identity); Map<Long, BusinessGroupMembership> memberships = new HashMap<Long, BusinessGroupMembership>(); for(BusinessGroupMembership membership: groupsAsOwner) { memberships.put(membership.getGroupKey(), membership); } List<GroupOverviewRow> items = new ArrayList<GroupOverviewRow>(); for(BusinessGroup group:groups) { BusinessGroupMembership membership = memberships.get(group.getKey()); GroupOverviewRow tableItem = new GroupOverviewRow(group, membership, Boolean.TRUE); items.add(tableItem); } tableDataModel.setEntries(items); groupListCtr.modelChanged(); } /** * @see org.olat.core.gui.control.DefaultController#doDispose() */ @Override protected void doDispose() { // } /** * @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 protected void event( UserRequest ureq, Component source, Event event) { if (source == addGroups){ groupsCtrl = new GroupSearchController(ureq, getWindowControl()); listenTo(groupsCtrl); cmc = new CloseableModalController(getWindowControl(), translate("add.groups"), groupsCtrl.getInitialComponent(), true, translate("add.groups"), true); listenTo(cmc); cmc.activate(); } } /** * @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 protected void event(UserRequest ureq, Controller source, Event event) { super.event(ureq, source, event); if (source == groupListCtr){ if (event.getCommand().equals(Table.COMMANDLINK_ROWACTION_CLICKED)) { TableEvent te = (TableEvent) event; GroupOverviewRow item = tableDataModel.getObject(te.getRowId()); BusinessGroup currBusinessGroup = businessGroupService.loadBusinessGroup(item.getKey()); if (currBusinessGroup==null) { //group seems to be removed meanwhile, reload table and show error showError("group.removed"); updateModel(); } else if (TABLE_ACTION_LAUNCH.equals(te.getActionId())) { NewControllerFactory.getInstance().launch("[BusinessGroup:" + currBusinessGroup.getKey() + "]", ureq, getWindowControl()); } else if (TABLE_ACTION_UNSUBSCRIBE.equals(te.getActionId())){ doLeave(ureq, Collections.singletonList(currBusinessGroup)); } } else if (event instanceof TableMultiSelectEvent) { TableMultiSelectEvent mse = (TableMultiSelectEvent)event; List<GroupOverviewRow> items = tableDataModel.getObjects(mse.getSelection()); if (TABLE_ACTION_UNSUBSCRIBE.equals(mse.getAction())){ List<BusinessGroup> groups = toBusinessGroups(items); doLeave(ureq, groups); } } } else if (source == groupsCtrl && event instanceof AddToGroupsEvent){ AddToGroupsEvent groupsEv = (AddToGroupsEvent) event; if (groupsEv.isEmpty()) { // no groups selected showWarning("group.add.result.none"); } else { if (cmc != null) { cmc.deactivate(); } boolean mailMandatory = groupModule.isMandatoryEnrolmentEmail(ureq.getUserSession().getRoles()); if(mailMandatory) { doAddToGroups(groupsEv, true); updateModel(); } else { confirmSendMailBox = activateYesNoDialog(ureq, null, translate("dialog.modal.bg.send.mail"), confirmSendMailBox); confirmSendMailBox.setUserObject(groupsEv); } } cleanUpPopups(); } else if(source == confirmSendMailBox) { boolean sendMail = DialogBoxUIFactory.isYesEvent(event) || DialogBoxUIFactory.isOkEvent(event); AddToGroupsEvent groupsEv = (AddToGroupsEvent)confirmSendMailBox.getUserObject(); doAddToGroups(groupsEv, sendMail); updateModel(); } else if (source == removeFromGrpDlg){ if(event == Event.DONE_EVENT) { boolean sendMail = removeFromGrpDlg.isSendMail(); List<BusinessGroup> groupsToDelete = removeFromGrpDlg.getGroupsToDelete(); List<BusinessGroup> groupsToLeave = removeFromGrpDlg.getGroupsToLeave(); removeUserFromGroup(ureq, groupsToLeave, groupsToDelete, sendMail); } cmc.deactivate(); cleanUpPopups(); } else if (source == cmc) { cleanUpPopups(); } } private void cleanUpPopups() { removeAsListenerAndDispose(cmc); removeAsListenerAndDispose(removeFromGrpDlg); removeAsListenerAndDispose(groupsCtrl); cmc = null; groupsCtrl = null; removeFromGrpDlg = null; } private void doAddToGroups(AddToGroupsEvent e, boolean sendMail) { List<BusinessGroupMembershipChange> changes = new ArrayList<BusinessGroupMembershipChange>(); if(e.getOwnerGroupKeys() != null && !e.getOwnerGroupKeys().isEmpty()) { for(Long tutorGroupKey:e.getOwnerGroupKeys()) { BusinessGroupMembershipChange change = new BusinessGroupMembershipChange(identity, tutorGroupKey); change.setTutor(Boolean.TRUE); changes.add(change); } } if(e.getParticipantGroupKeys() != null && !e.getParticipantGroupKeys().isEmpty()) { for(Long partGroupKey:e.getParticipantGroupKeys()) { BusinessGroupMembershipChange change = new BusinessGroupMembershipChange(identity, partGroupKey); change.setParticipant(Boolean.TRUE); changes.add(change); } } MailPackage mailing = new MailPackage(sendMail); businessGroupService.updateMemberships(getIdentity(), changes, mailing); } private void doLeave(UserRequest ureq, List<BusinessGroup> groupsToLeave) { List<BusinessGroup> groupsToDelete = new ArrayList<BusinessGroup>(1); for(BusinessGroup group:groupsToLeave) { int numOfOwners = businessGroupService.countMembers(group, GroupRoles.coach.name()); int numOfParticipants = businessGroupService.countMembers(group, GroupRoles.participant.name()); if ((numOfOwners == 1 && numOfParticipants == 0) || (numOfOwners == 0 && numOfParticipants == 1)) { groupsToDelete.add(group); } } removeFromGrpDlg = new GroupLeaveDialogBoxController(ureq, getWindowControl(), identity, groupsToLeave, groupsToDelete); listenTo(removeFromGrpDlg); cmc = new CloseableModalController(getWindowControl(), translate("close"), removeFromGrpDlg.getInitialComponent(), true, translate("unsubscribe.title")); cmc.activate(); listenTo(cmc); } /** * * @param ureq * @param doSendMail */ private void removeUserFromGroup(UserRequest ureq, List<BusinessGroup> groupsToLeave, List<BusinessGroup> groupsToDelete, boolean doSendMail) { for(BusinessGroup group:groupsToLeave) { if (groupsToDelete.contains(group)) { // really delete the group as it has no more owners/participants if(doSendMail) { String businessPath = getWindowControl().getBusinessControl().getAsString(); businessGroupService.deleteBusinessGroupWithMail(group, businessPath, getIdentity(), getLocale()); } else { businessGroupService.deleteBusinessGroup(group); } } else { // 1) remove as owner if (businessGroupService.hasRoles(identity, group, GroupRoles.coach.name())) { businessGroupService.removeOwners(ureq.getIdentity(), Collections.singletonList(identity), group); } MailPackage mailing = new MailPackage(doSendMail); // 2) remove as participant businessGroupService.removeParticipants(getIdentity(), Collections.singletonList(identity), group, mailing); MailHelper.printErrorsAndWarnings(mailing.getResult(), getWindowControl(), getLocale()); } } updateModel(); StringBuilder groupNames = new StringBuilder(); for(BusinessGroup group:groupsToLeave) { if(groupNames.length() > 0) groupNames.append(", "); groupNames.append(group.getName()); } showInfo("unsubscribe.successful", groupNames.toString()); } private List<BusinessGroup> toBusinessGroups(List<GroupOverviewRow> items) { List<Long> groupKeys = new ArrayList<Long>(); for(GroupOverviewRow item:items) { groupKeys.add(item.getKey()); } List<BusinessGroup> groups = businessGroupService.loadBusinessGroups(groupKeys); return groups; } }