/**
* <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.commons.memberlist.ui;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import org.olat.NewControllerFactory;
import org.olat.basesecurity.BaseSecurity;
import org.olat.commons.memberlist.manager.MembersExportManager;
import org.olat.core.commons.fullWebApp.popup.BaseFullWebappPopupLayoutFactory;
import org.olat.core.gui.UserRequest;
import org.olat.core.gui.components.Component;
import org.olat.core.gui.components.form.flexible.FormItem;
import org.olat.core.gui.components.form.flexible.FormItemContainer;
import org.olat.core.gui.components.form.flexible.elements.FormLink;
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.link.Link;
import org.olat.core.gui.components.link.LinkFactory;
import org.olat.core.gui.components.link.LinkPopupSettings;
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.creator.ControllerCreator;
import org.olat.core.gui.control.generic.closablewrapper.CloseableModalController;
import org.olat.core.gui.media.MediaResource;
import org.olat.core.gui.translator.Translator;
import org.olat.core.helpers.Settings;
import org.olat.core.id.Identity;
import org.olat.core.id.IdentityEnvironment;
import org.olat.core.id.Roles;
import org.olat.core.id.UserConstants;
import org.olat.core.id.context.BusinessControl;
import org.olat.core.id.context.BusinessControlFactory;
import org.olat.core.util.StringHelper;
import org.olat.core.util.mail.ContactList;
import org.olat.core.util.mail.ContactMessage;
import org.olat.core.util.session.UserSessionManager;
import org.olat.course.nodes.members.Member;
import org.olat.course.nodes.members.MembersCourseNodeRunController;
import org.olat.course.run.environment.CourseEnvironment;
import org.olat.group.BusinessGroup;
import org.olat.instantMessaging.InstantMessagingModule;
import org.olat.instantMessaging.InstantMessagingService;
import org.olat.instantMessaging.OpenInstantMessageEvent;
import org.olat.instantMessaging.model.Buddy;
import org.olat.instantMessaging.model.Presence;
import org.olat.modules.co.ContactFormController;
import org.olat.repository.RepositoryEntry;
import org.olat.user.DisplayPortraitManager;
import org.olat.user.UserAvatarMapper;
import org.olat.user.UserManager;
import org.olat.user.propertyhandlers.UserPropertyHandler;
import org.springframework.beans.factory.annotation.Autowired;
/**
*
* Description:<br>
* The run controller show the list of members of the course
*
* <P>
* Initial Date: 11 mars 2011 <br>
* @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
* @author fkiefer
*/
public class MembersAvatarDisplayRunController extends FormBasicController {
private final List<UserPropertyHandler> userPropertyHandlers;
public static final String USER_PROPS_ID = MembersCourseNodeRunController.class.getName();
private final CourseEnvironment courseEnv;
private final DisplayPortraitManager portraitManager;
private final String avatarBaseURL;
private Link printLink;
private FormLink allEmailLink;
private FormLink downloadLink;
private List<Member> ownerList;
private List<Member> coachList;
private List<Member> participantList;
private List<Member> waitingtList;
private List<Identity> owners;
private List<Identity> coaches;
private List<Identity> participants;
private List<Identity> waiting;
private final boolean canEmail;
private final boolean canDownload;
private final boolean showOwners;
private final boolean showCoaches;
private final boolean showParticipants;
private final boolean showWaiting;
private final boolean chatEnabled;
private final boolean editable;
private FormBasicController mailCtrl;
private ContactFormController emailController;
private CloseableModalController cmc;
private int count = 0;
private final boolean deduplicateList;
@Autowired
private UserManager userManager;
@Autowired
private BaseSecurity securityManager;
@Autowired
private InstantMessagingModule imModule;
@Autowired
private InstantMessagingService imService;
@Autowired
private UserSessionManager sessionManager;
@Autowired
private MembersExportManager exportManager;
private BusinessGroup businessGroup;
private RepositoryEntry repoEntry;
public MembersAvatarDisplayRunController(UserRequest ureq, WindowControl wControl, Translator translator, CourseEnvironment courseEnv, BusinessGroup businessGroup,
List<Identity> owners, List<Identity> coaches, List<Identity> participants, List<Identity> waiting, boolean canEmail, boolean canDownload,
boolean deduplicateList, boolean showOwners, boolean showCoaches, boolean showParticipants, boolean showWaiting, boolean editable) {
super(ureq, wControl, "members", translator);
setTranslator(translator);
this.courseEnv = courseEnv;
this.businessGroup = businessGroup;
this.repoEntry = courseEnv != null ? courseEnv.getCourseGroupManager().getCourseEntry() : null;
userPropertyHandlers = userManager.getUserPropertyHandlersFor(USER_PROPS_ID, false);
avatarBaseURL = registerCacheableMapper(ureq, "avatars-members", new UserAvatarMapper(true));
portraitManager = DisplayPortraitManager.getInstance();
chatEnabled = imModule.isEnabled() && imModule.isPrivateEnabled();
// lists
this.owners = owners;
this.coaches = coaches;
this.participants = participants;
this.waiting = waiting;
// flags
this.canEmail = canEmail;
this.canDownload = canDownload;
this.showOwners = showOwners;
this.showCoaches = showCoaches;
this.showParticipants = showParticipants;
this.showWaiting = showWaiting;
this.deduplicateList = deduplicateList;
this.editable = editable;
initForm(ureq);
}
@Override
protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
Comparator<Identity> idComparator = new IdentityComparator();
Collections.sort(owners, idComparator);
Collections.sort(coaches, idComparator);
Collections.sort(participants, idComparator);
Collections.sort(waiting, idComparator);
if(canEmail) {
allEmailLink = uifactory.addFormLink("email", "members.email.title", null, formLayout, Link.BUTTON);
allEmailLink.setIconLeftCSS("o_icon o_icon_mail");
}
IdentityEnvironment idEnv = ureq.getUserSession().getIdentityEnvironment();
Identity ownId = idEnv.getIdentity();
Roles roles = idEnv.getRoles();
if (editable && (roles.isOLATAdmin() || roles.isGroupManager() || owners.contains(ownId) || coaches.contains(ownId)
|| (canDownload && !waiting.contains(ownId)))) {
downloadLink = uifactory.addFormLink("download", "members.download", null, formLayout, Link.BUTTON);
downloadLink.setIconLeftCSS("o_icon o_icon_download");
if(formLayout instanceof FormLayoutContainer) {
printLink = LinkFactory.createButton("print", ((FormLayoutContainer)formLayout).getFormItemComponent(), this);
printLink.setIconLeftCSS("o_icon o_icon_print o_icon-lg");
printLink.setPopup(new LinkPopupSettings(700, 500, "print-members"));
((FormLayoutContainer)formLayout).getFormItemComponent().put("print", printLink);
}
}
Set<Long> duplicateCatcher = deduplicateList ? new HashSet<Long>() : null;
ownerList = initFormMemberList("owners", owners, duplicateCatcher, formLayout, canEmail);
coachList = initFormMemberList("coaches", coaches, duplicateCatcher, formLayout, canEmail);
participantList = initFormMemberList("participants", participants, duplicateCatcher, formLayout, canEmail);
waitingtList = initFormMemberList("waiting", waiting, duplicateCatcher, formLayout, canEmail);
if(formLayout instanceof FormLayoutContainer) {
FormLayoutContainer layoutCont = (FormLayoutContainer)formLayout;
layoutCont.contextPut("showOwners", showOwners);
layoutCont.contextPut("hasOwners", new Boolean(!ownerList.isEmpty()));
layoutCont.contextPut("showCoaches", showCoaches);
layoutCont.contextPut("hasCoaches", new Boolean(!coachList.isEmpty()));
layoutCont.contextPut("showParticipants", showParticipants);
layoutCont.contextPut("hasParticipants", new Boolean(!participantList.isEmpty()));
layoutCont.contextPut("showWaiting", showWaiting);
layoutCont.contextPut("hasWaiting", new Boolean(!waitingtList.isEmpty()));
}
}
private List<Member> initFormMemberList(String name, List<Identity> ids, Set<Long> duplicateCatcher, FormItemContainer formLayout, boolean withEmail) {
String page = velocity_root + "/memberList.html";
FormLayoutContainer container = FormLayoutContainer.createCustomFormLayout(name, getTranslator(), page);
formLayout.add(name, container);
container.setRootForm(mainForm);
List<Member> members = createMemberLinks(ids, duplicateCatcher, container, withEmail);
container.contextPut("members", members);
container.contextPut("avatarBaseURL", avatarBaseURL);
return members;
}
protected List<Member> createMemberLinks(List<Identity> identities, Set<Long> duplicateCatcher, FormLayoutContainer formLayout, boolean withEmail) {
List<Member> members = new ArrayList<>();
for(Identity identity:identities) {
if(duplicateCatcher != null && duplicateCatcher.contains(identity.getKey())) continue;
Member member = createMember(identity);
members.add(member);
String guiId = Integer.toString(++count);
String fullname = StringHelper.escapeHtml(member.getFullName());
FormLink idLink = uifactory.addFormLink("id_".concat(guiId), "id", fullname, null, formLayout, Link.NONTRANSLATED);
idLink.setUserObject(member);
formLayout.add(idLink.getComponent().getComponentName(), idLink);
member.setIdLink(idLink);
if(withEmail) {
FormLink emailLink = uifactory.addFormLink("mail_".concat(guiId), "mail", "", null, formLayout, Link.NONTRANSLATED);
emailLink.setUserObject(member);
emailLink.setIconLeftCSS("o_icon o_icon_mail o_icon-lg");
emailLink.setElementCssClass("o_mail");
formLayout.add(emailLink.getComponent().getComponentName(), emailLink);
member.setEmailLink(emailLink);
}
if(chatEnabled && editable) {
FormLink chatLink = uifactory.addFormLink("chat_".concat(guiId), "chat", "", null, formLayout, Link.NONTRANSLATED);
chatLink.setUserObject(member);
chatLink.setElementCssClass("o_chat");
formLayout.add(chatLink.getComponent().getComponentName(), chatLink);
member.setChatLink(chatLink);
}
if(duplicateCatcher != null) {
duplicateCatcher.add(identity.getKey());
}
}
if(chatEnabled && editable) {
Long me = getIdentity().getKey();
if(imModule.isOnlineStatusEnabled()) {
Map<Long,Member> loadStatus = new HashMap<>();
for(Member member:members) {
if(member.getKey().equals(me)) {
member.getChatLink().setVisible(false);
} else if(sessionManager.isOnline(member.getKey())) {
loadStatus.put(member.getKey(), member);
} else {
member.getChatLink().setIconLeftCSS("o_icon o_icon_status_unavailable");
}
}
if(loadStatus.size() > 0) {
List<Long> statusToLoadList = new ArrayList<>(loadStatus.keySet());
Map<Long,String> statusMap = imService.getBuddyStatus(statusToLoadList);
for(Long toLoad:statusToLoadList) {
String status = statusMap.get(toLoad);
Member member = loadStatus.get(toLoad);
if(status == null || Presence.available.name().equals(status)) {
member.getChatLink().setIconLeftCSS("o_icon o_icon_status_available");
} else if(Presence.dnd.name().equals(status)) {
member.getChatLink().setIconLeftCSS("o_icon o_icon_status_dnd");
} else {
member.getChatLink().setIconLeftCSS("o_icon o_icon_status_unavailable");
}
}
}
} else {
for(Member member:members) {
if(member.getKey().equals(me)) {
member.getChatLink().setVisible(false);
} else {
member.getChatLink().setIconLeftCSS("o_icon o_icon_status_chat");
}
}
}
}
return members;
}
private Member createMember(Identity identity) {
boolean hasPortrait = portraitManager.hasPortrait(identity.getName());
String portraitCssClass;
String gender = identity.getUser().getProperty(UserConstants.GENDER, Locale.ENGLISH);
if ("male".equalsIgnoreCase(gender)) {
portraitCssClass = DisplayPortraitManager.DUMMY_MALE_BIG_CSS_CLASS;
} else if ("female".equalsIgnoreCase(gender)) {
portraitCssClass = DisplayPortraitManager.DUMMY_FEMALE_BIG_CSS_CLASS;
} else {
portraitCssClass = DisplayPortraitManager.DUMMY_BIG_CSS_CLASS;
}
String fullname = userManager.getUserDisplayName(identity);
return new Member(identity, fullname, userPropertyHandlers, getLocale(), hasPortrait, portraitCssClass);
}
@Override
protected void doDispose() {
//
}
@Override
protected void formOK(UserRequest ureq) {
//
}
@Override
public void event(UserRequest ureq, Component source, Event event) {
if(source == printLink) {
doPrint(ureq);
}
super.event(ureq, source, event);
}
@Override
protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) {
if(source == allEmailLink) {
doEmail(ureq);
} else if (source == downloadLink) {
doExport(ureq);
} else if (source instanceof FormLink) {
FormLink link = (FormLink)source;
Object uobject = link.getUserObject();
if(uobject instanceof Member) {
Member member = (Member)uobject;
String cmd = link.getCmd();
if("id".equals(cmd)) {
doOpenHomePage(member, ureq);
} else if("mail".equals(cmd)) {
doSendEmailToMember(member, ureq);
} else if("chat".equals(cmd)) {
doOpenChat(member, ureq);
}
}
}
super.formInnerEvent(ureq, source, event);
}
@Override
protected void event(UserRequest ureq, Controller source, Event event) {
if(source == cmc) {
cleanUp();
} else if (source == emailController) {
cmc.deactivate();
cleanUp();
} else if(source == mailCtrl) {
cmc.deactivate();
cleanUp();
}
super.event(ureq, source, event);
}
private void cleanUp() {
removeAsListenerAndDispose(emailController);
removeAsListenerAndDispose(mailCtrl);
removeAsListenerAndDispose(cmc);
emailController = null;
mailCtrl = null;
cmc = null;
}
private void doEmail(UserRequest ureq) {
if(mailCtrl != null || cmc != null) return;
removeAsListenerAndDispose(cmc);
removeAsListenerAndDispose(mailCtrl);
mailCtrl = new MembersMailController(ureq, getWindowControl(), getTranslator(), courseEnv,
ownerList, coachList, participantList, waitingtList, createBodyTemplate());
listenTo(mailCtrl);
String title = translate("members.email.title");
cmc = new CloseableModalController(getWindowControl(), translate("close"), mailCtrl.getInitialComponent(), true, title);
listenTo(cmc);
cmc.activate();
}
private void doExport(UserRequest ureq) {
MediaResource resource = exportManager.getXlsMediaResource(showOwners, showCoaches, showParticipants, showWaiting,
owners, coaches, participants, waiting, getTranslator(), userPropertyHandlers, repoEntry, businessGroup);
ureq.getDispatchResult().setResultingMediaResource(resource);
}
private void doOpenChat(Member member, UserRequest ureq) {
Buddy buddy = imService.getBuddyById(member.getKey());
OpenInstantMessageEvent e = new OpenInstantMessageEvent(ureq, buddy);
ureq.getUserSession().getSingleUserEventCenter().fireEventToListenersOf(e, InstantMessagingService.TOWER_EVENT_ORES);
}
private void doSendEmailToMember(Member member, UserRequest ureq) {
if (!editable) return;
ContactList memberList;
if (courseEnv == null) {
memberList = new ContactList(translate("members.to", new String[]{ member.getFullName(), businessGroup.getName() }));
} else {
memberList = new ContactList(translate("members.to", new String[]{ member.getFullName(), courseEnv.getCourseTitle() }));
}
Identity identity = securityManager.loadIdentityByKey(member.getKey());
memberList.add(identity);
doSendEmailToMember(memberList, ureq);
}
private void doSendEmailToMember(ContactList contactList, UserRequest ureq) {
if (contactList.getEmailsAsStrings().size() > 0) {
removeAsListenerAndDispose(cmc);
removeAsListenerAndDispose(emailController);
ContactMessage cmsg = new ContactMessage(ureq.getIdentity());
cmsg.addEmailTo(contactList);
// preset body template from i18n
cmsg.setBodyText(createBodyTemplate());
emailController = new ContactFormController(ureq, getWindowControl(), true, false, false, cmsg);
listenTo(emailController);
String title = translate("members.email.title");
cmc = new CloseableModalController(getWindowControl(), translate("close"), emailController.getInitialComponent(), true, title);
listenTo(cmc);
cmc.activate();
}
}
private String createBodyTemplate() {
if (courseEnv == null) {
String groupName = businessGroup.getName();
// Build REST URL to business group,
StringBuilder groupLink = new StringBuilder();
groupLink.append(Settings.getServerContextPathURI())
.append("/url/BusinessGroup/").append(businessGroup.getKey());
return translate("email.body.template", new String[]{groupName, groupLink.toString()});
} else {
String courseName = courseEnv.getCourseTitle();
// Build REST URL to course element, use hack via group manager to access repo entry
StringBuilder courseLink = new StringBuilder();
RepositoryEntry entry = courseEnv.getCourseGroupManager().getCourseEntry();
courseLink.append(Settings.getServerContextPathURI())
.append("/url/RepositoryEntry/").append(entry.getKey());
return translate("email.body.template", new String[]{courseName, courseLink.toString()});
}
}
private void doOpenHomePage(Member member, UserRequest ureq) {
String url = "[HomePage:" + member.getKey() + "]";
BusinessControl bc = BusinessControlFactory.getInstance().createFromString(url);
WindowControl bwControl = BusinessControlFactory.getInstance().createBusinessWindowControl(bc, getWindowControl());
NewControllerFactory.getInstance().launch(ureq, bwControl);
}
private void doPrint(UserRequest ureq) {
ControllerCreator printControllerCreator = new ControllerCreator() {
@Override
public Controller createController(UserRequest lureq, WindowControl lwControl) {
lwControl.getWindowBackOffice().getChiefController().addBodyCssClass("o_cmembers_print");
return new MembersPrintController(lureq, lwControl, userPropertyHandlers, getTranslator(), ownerList, coachList,
participantList, waitingtList, showOwners, showCoaches, showParticipants, showWaiting,
courseEnv != null ? courseEnv.getCourseTitle() : businessGroup.getName());
}
};
ControllerCreator layoutCtrlr = BaseFullWebappPopupLayoutFactory.createPrintPopupLayout(printControllerCreator);
openInNewBrowserWindow(ureq, layoutCtrlr);
}
public static class IdentityComparator implements Comparator<Identity> {
@Override
public int compare(Identity id1, Identity id2) {
if(id1 == null) return -1;
if(id2 == null) return 1;
String l1 = id1.getUser().getProperty(UserConstants.LASTNAME, null);
String l2 = id2.getUser().getProperty(UserConstants.LASTNAME, null);
if(l1 == null) return -1;
if(l2 == null) return 1;
int result = l1.compareToIgnoreCase(l2);
if(result == 0) {
String f1 = id1.getUser().getProperty(UserConstants.FIRSTNAME, null);
String f2 = id2.getUser().getProperty(UserConstants.FIRSTNAME, null);
if(f1 == null) return -1;
if(f2 == null) return 1;
result = f1.compareToIgnoreCase(f2);
}
return result;
}
}
}