/**
* <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.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import org.olat.NewControllerFactory;
import org.olat.basesecurity.BaseSecurity;
import org.olat.core.commons.persistence.SortKey;
import org.olat.core.gui.UserRequest;
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.FlexiTableElement;
import org.olat.core.gui.components.form.flexible.elements.FlexiTableSortOptions;
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.elements.table.DefaultFlexiColumnModel;
import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiColumnModel;
import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableColumnModel;
import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableDataModelFactory;
import org.olat.core.gui.components.form.flexible.impl.elements.table.SelectionEvent;
import org.olat.core.gui.components.form.flexible.impl.elements.table.StaticFlexiCellRenderer;
import org.olat.core.gui.components.form.flexible.impl.elements.table.TextFlexiCellRenderer;
import org.olat.core.gui.components.link.Link;
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.generic.closablewrapper.CloseableModalController;
import org.olat.core.gui.translator.Translator;
import org.olat.core.helpers.Settings;
import org.olat.core.id.Identity;
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.mail.ContactList;
import org.olat.core.util.mail.ContactMessage;
import org.olat.course.nodes.members.MembersCourseNodeRunController;
import org.olat.course.run.environment.CourseEnvironment;
import org.olat.group.BusinessGroup;
import org.olat.group.BusinessGroupMembership;
import org.olat.group.ui.main.MemberListTableModel;
import org.olat.group.ui.main.MemberListTableModel.Cols;
import org.olat.group.ui.main.MemberView;
import org.olat.instantMessaging.InstantMessagingModule;
import org.olat.instantMessaging.InstantMessagingService;
import org.olat.instantMessaging.OpenInstantMessageEvent;
import org.olat.instantMessaging.model.Buddy;
import org.olat.modules.co.ContactFormController;
import org.olat.repository.RepositoryEntry;
import org.olat.user.UserManager;
import org.olat.user.propertyhandlers.UserPropertyHandler;
import org.springframework.beans.factory.annotation.Autowired;
/**
* Initial Date: 30.03.2017
* @author fkiefer, fabian.kiefer@frentix.com, www.frentix.com
*/
public class MembersTableController extends FormBasicController {
public static final String USER_PROPS_ID = MembersCourseNodeRunController.class.getName();
public static final int USER_PROPS_OFFSET = 500;
protected FlexiTableElement membersTable;
protected MemberListTableModel membersModel;
private ContactFormController emailController;
private CloseableModalController cmc;
private final AtomicInteger counter = new AtomicInteger();
private final boolean chatEnabled, canEmail, deduplicateList, editable, userLastTimeVisible;
private final List<UserPropertyHandler> userPropertyHandlers;
private final List<MemberView> membersList;
private final RepositoryEntry repoEntry;
private Set<MemberView> duplicateCatcher;
@Autowired
private UserManager userManager;
@Autowired
private InstantMessagingModule imModule;
@Autowired
private InstantMessagingService imService;
@Autowired
private BaseSecurity securityManager;
private BusinessGroup businessGroup;
private CourseEnvironment courseEnv;
private int pageSize = 20;
public MembersTableController(UserRequest ureq, WindowControl wControl, List<Identity> members, Set<MemberView> duplicateCatcher, Map<Long,Date> recentLaunches, Map<Long,Date> initialLaunches,
List<UserPropertyHandler> userPropertyHandlers, Map<Long,BusinessGroupMembership> groupmemberships, RepositoryEntry repoEntry, BusinessGroup businessGroup,
CourseEnvironment courseEnv, boolean deduplicateList, Translator translator, boolean editable, boolean canEmail, boolean userLastTimeVisible) {
super(ureq, wControl, "table");
setTranslator(translator);
chatEnabled = imModule.isEnabled() && imModule.isPrivateEnabled();
this.userPropertyHandlers = userPropertyHandlers;
this.duplicateCatcher = duplicateCatcher;
this.repoEntry = repoEntry;
this.deduplicateList = deduplicateList;
this.editable = editable;
this.canEmail = canEmail;
this.userLastTimeVisible = userLastTimeVisible;
this.businessGroup = businessGroup;
this.courseEnv = courseEnv;
this.membersList = getMembersFromIdentity(ureq, members, groupmemberships, recentLaunches, initialLaunches);
initForm(ureq);
}
@Override
protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
FlexiTableColumnModel columnsModel = FlexiTableDataModelFactory.createFlexiTableColumnModel();
SortKey defaultSortKey = initColumns(columnsModel);
membersModel = new MemberListTableModel(columnsModel, imModule.isOnlineStatusEnabled());
membersModel.setObjects(membersList);
membersTable = uifactory.addTableElement(getWindowControl(), "table", membersModel, pageSize, false, getTranslator(), formLayout);
membersTable.setEmtpyTableMessageKey("nomembers");
membersTable.setAndLoadPersistedPreferences(ureq, this.getClass().getSimpleName());
membersTable.setExportEnabled(false);
membersTable.setElementCssClass("o_sel_member_list");
if(defaultSortKey != null) {
FlexiTableSortOptions options = new FlexiTableSortOptions();
options.setDefaultOrderBy(defaultSortKey);
membersTable.setSortSettings(options);
}
}
@Override
protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) {
if (source == membersTable) {
if(event instanceof SelectionEvent) {
SelectionEvent se = (SelectionEvent)event;
String cmd = se.getCommand();
if ("vcard".equals(cmd)) {
MemberView row = membersModel.getObject(se.getIndex());
doOpenHomePage(row, ureq);
} else if ("email".equals(cmd)) {
MemberView row = membersModel.getObject(se.getIndex());
doSendEmailToMember(row, ureq);
}
}
} else if (source instanceof FormLink) {
FormLink link = (FormLink)source;
String cmd = link.getCmd();
MemberView row = (MemberView)link.getUserObject();
if ("im".equals(cmd)) {
doOpenChat(row, 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();
}
super.event(ureq, source, event);
}
private void cleanUp() {
removeAsListenerAndDispose(emailController);
removeAsListenerAndDispose(cmc);
emailController = null;
cmc = null;
}
@Override
protected void formOK(UserRequest ureq) {
//
}
@Override
protected void doDispose() {
//
}
private List<MemberView> getMembersFromIdentity(UserRequest ureq, List<Identity> identities,
Map<Long,BusinessGroupMembership> groupmemberships, Map<Long,Date> recentLaunches, Map<Long,Date> initialLaunches) {
if (!deduplicateList) {
duplicateCatcher = new HashSet<>();
}
List<MemberView> memberList = new ArrayList<>();
for (Identity identity : identities) {
MemberView member = new MemberView(identity, userPropertyHandlers, getLocale());
if (userLastTimeVisible) {
if (repoEntry == null) {
BusinessGroupMembership groupmembership = groupmemberships.get(identity.getKey());
if(groupmembership != null) {
member.setFirstTime(groupmembership.getCreationDate());
member.setLastTime(groupmembership.getLastModified());
}
} else {
member.setFirstTime(initialLaunches.get(identity.getKey()));
member.setLastTime(recentLaunches.get(identity.getKey()));
}
}
if (!duplicateCatcher.contains(member)) {
memberList.add(member);
if (!identity.equals(ureq.getIdentity())){
forgeChatLink(member);
}
}
duplicateCatcher.add(member);
}
return memberList;
}
protected void forgeChatLink(MemberView row) {
FormLink chatLink = uifactory.addFormLink("tools_" + counter.incrementAndGet(), "im", "", null, null, Link.NONTRANSLATED);
chatLink.setIconLeftCSS("o_icon o_icon_status_unavailable");
chatLink.setUserObject(row);
row.setChatLink(chatLink);
}
private SortKey initColumns(FlexiTableColumnModel columnsModel) {
SortKey defaultSortKey = null;
String editAction = "vcard";
if (chatEnabled && editable) {
DefaultFlexiColumnModel chatCol = new DefaultFlexiColumnModel(Cols.online.i18n(), Cols.online.ordinal());
chatCol.setExportable(false);
columnsModel.addFlexiColumnModel(chatCol);
}
int colPos = USER_PROPS_OFFSET;
for (UserPropertyHandler userPropertyHandler : userPropertyHandlers) {
if (userPropertyHandler == null) continue;
String propName = userPropertyHandler.getName();
boolean visible = userManager.isMandatoryUserProperty(USER_PROPS_ID , userPropertyHandler);
String myEditAction = editAction;
FlexiColumnModel col;
if(UserConstants.FIRSTNAME.equals(propName) || UserConstants.LASTNAME.equals(propName) || UserConstants.EMAIL.equals(propName)) {
if (UserConstants.EMAIL.equals(propName)) {
myEditAction = "email";
if (!canEmail) {
continue;
}
}
col = new DefaultFlexiColumnModel(userPropertyHandler.i18nColumnDescriptorLabelKey(),
colPos, myEditAction, true, propName,
new StaticFlexiCellRenderer(myEditAction, new TextFlexiCellRenderer()));
} else {
col = new DefaultFlexiColumnModel(visible, userPropertyHandler.i18nColumnDescriptorLabelKey(), colPos, true, propName);
}
columnsModel.addFlexiColumnModel(col);
colPos++;
if(defaultSortKey == null) {
defaultSortKey = new SortKey(propName, true);
}
}
if (userLastTimeVisible) {
columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Cols.firstTime.i18n(), Cols.firstTime.ordinal(), true, Cols.firstTime.name()));
columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Cols.lastTime.i18n(), Cols.lastTime.ordinal(), true, Cols.lastTime.name()));
}
return defaultSortKey;
}
private void doSendEmailToMember(MemberView member, UserRequest ureq) {
if (!editable) return;
ContactList memberList;
Identity identity = securityManager.loadIdentityByKey(member.getIdentityKey());
String fullName = userManager.getUserDisplayName(identity);
if (courseEnv == null) {
memberList = new ContactList(translate("members.to", new String[]{ fullName, businessGroup.getName() }));
} else {
memberList = new ContactList(translate("members.to", new String[]{ fullName, courseEnv.getCourseTitle() }));
}
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 courseName = businessGroup.getName();
// Build REST URL to business group, use hack via group manager to access
StringBuilder courseLink = new StringBuilder();
courseLink.append(Settings.getServerContextPathURI())
.append("/auth/BusinessGroup/").append(businessGroup.getKey());
return translate("email.body.template", new String[]{courseName, courseLink.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(MemberView member, UserRequest ureq) {
String url = "[HomePage:" + member.getIdentityKey() + "]";
BusinessControl bc = BusinessControlFactory.getInstance().createFromString(url);
WindowControl bwControl = BusinessControlFactory.getInstance().createBusinessWindowControl(bc, getWindowControl());
NewControllerFactory.getInstance().launch(ureq, bwControl);
}
private void doOpenChat(MemberView member, UserRequest ureq) {
Buddy buddy = imService.getBuddyById(member.getIdentityKey());
OpenInstantMessageEvent e = new OpenInstantMessageEvent(ureq, buddy);
ureq.getUserSession().getSingleUserEventCenter().fireEventToListenersOf(e, InstantMessagingService.TOWER_EVENT_ORES);
}
}