/**
* <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.modules.assessment.ui;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.olat.basesecurity.BaseSecurity;
import org.olat.basesecurity.BaseSecurityModule;
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.FlexiTableElement;
import org.olat.core.gui.components.form.flexible.elements.FlexiTableFilter;
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.form.flexible.impl.elements.table.DefaultFlexiColumnModel;
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.FlexiTableSearchEvent;
import org.olat.core.gui.components.form.flexible.impl.elements.table.SelectionEvent;
import org.olat.core.gui.components.link.Link;
import org.olat.core.gui.components.link.LinkFactory;
import org.olat.core.gui.components.stack.BreadcrumbPanelAware;
import org.olat.core.gui.components.stack.TooledStackedPanel;
import org.olat.core.gui.components.stack.TooledStackedPanel.Align;
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.dtabs.Activateable2;
import org.olat.core.id.Identity;
import org.olat.core.id.context.ContextEntry;
import org.olat.core.id.context.StateEntry;
import org.olat.core.util.StringHelper;
import org.olat.core.util.Util;
import org.olat.course.assessment.AssessmentModule;
import org.olat.course.assessment.AssessmentToolManager;
import org.olat.course.assessment.bulk.PassedCellRenderer;
import org.olat.course.assessment.model.SearchAssessedIdentityParams;
import org.olat.course.assessment.ui.tool.AssessedIdentityListProvider;
import org.olat.course.assessment.ui.tool.AssessmentStatusCellRenderer;
import org.olat.course.assessment.ui.tool.AssessmentToolConstants;
import org.olat.group.BusinessGroup;
import org.olat.group.BusinessGroupService;
import org.olat.group.model.SearchBusinessGroupParams;
import org.olat.modules.assessment.AssessmentEntry;
import org.olat.modules.assessment.AssessmentToolOptions;
import org.olat.modules.assessment.model.AssessmentEntryStatus;
import org.olat.modules.assessment.ui.AssessedIdentityListTableModel.IdentityCourseElementCols;
import org.olat.repository.RepositoryEntry;
import org.olat.repository.handlers.RepositoryHandler;
import org.olat.repository.handlers.RepositoryHandlerFactory;
import org.olat.repository.ui.RepositoyUIFactory;
import org.olat.user.UserManager;
import org.olat.user.propertyhandlers.UserPropertyHandler;
import org.springframework.beans.factory.annotation.Autowired;
/**
*
* Initial date: 06.10.2015<br>
* @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
*
*/
public class AssessedIdentityListController extends FormBasicController implements Activateable2 {
private final RepositoryEntry testEntry;
private final AssessableResource element;
private final boolean isAdministrativeUser;
private SearchAssessedIdentityParams searchParams;
private final List<UserPropertyHandler> userPropertyHandlers;
private final AssessmentToolSecurityCallback assessmentCallback;
private Link nextLink, previousLink;
private FlexiTableElement tableEl;
private final TooledStackedPanel stackPanel;
private AssessedIdentityListTableModel usersTableModel;
private List<Controller> toolsCtrl;
private AssessedIdentityController currentIdentityCtrl;
@Autowired
private UserManager userManager;
@Autowired
private BaseSecurity securityManager;
@Autowired
private BaseSecurityModule securityModule;
@Autowired
private BusinessGroupService businessGroupService;
@Autowired
private AssessmentToolManager assessmentToolManager;
@Autowired
private RepositoryHandlerFactory repositoryHandlerFactory;
public AssessedIdentityListController(UserRequest ureq, WindowControl wControl, TooledStackedPanel stackPanel,
RepositoryEntry testEntry, AssessableResource element, AssessmentToolSecurityCallback assessmentCallback) {
super(ureq, wControl, "identity_element");
setTranslator(Util.createPackageTranslator(AssessmentModule.class, getLocale(), getTranslator()));
setTranslator(userManager.getPropertyHandlerTranslator(getTranslator()));
this.element = element;
this.testEntry = testEntry;
this.stackPanel = stackPanel;
this.assessmentCallback = assessmentCallback;
isAdministrativeUser = securityModule.isUserAllowedAdminProps(ureq.getUserSession().getRoles());
userPropertyHandlers = userManager.getUserPropertyHandlersFor(AssessmentToolConstants.usageIdentifyer, isAdministrativeUser);
initForm(ureq);
}
@Override
protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
if(formLayout instanceof FormLayoutContainer) {
FormLayoutContainer layoutCont = (FormLayoutContainer)formLayout;
layoutCont.contextPut("title", testEntry.getDisplayname());
RepositoryHandler handler = repositoryHandlerFactory.getRepositoryHandler(testEntry);
layoutCont.contextPut("cssClass", RepositoyUIFactory.getIconCssClass(handler.getSupportedType()));
}
//add the table
FlexiTableColumnModel columnsModel = FlexiTableDataModelFactory.createFlexiTableColumnModel();
if(isAdministrativeUser) {
columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(IdentityCourseElementCols.username, "select"));
}
int colIndex = AssessmentToolConstants.USER_PROPS_OFFSET;
for (int i = 0; i < userPropertyHandlers.size(); i++) {
UserPropertyHandler userPropertyHandler = userPropertyHandlers.get(i);
boolean visible = UserManager.getInstance().isMandatoryUserProperty(AssessmentToolConstants.usageIdentifyer , userPropertyHandler);
columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(visible, userPropertyHandler.i18nColumnDescriptorLabelKey(), colIndex, "select", true, "userProp-" + colIndex));
colIndex++;
}
if(element.hasAttemptsConfigured()) {
columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(IdentityCourseElementCols.attempts, "select"));
}
if(element.hasScoreConfigured()) {
columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(IdentityCourseElementCols.min, "select", new ScoreCellRenderer()));
columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(IdentityCourseElementCols.max, "select", new ScoreCellRenderer()));
columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(IdentityCourseElementCols.score, "select", new ScoreCellRenderer()));
}
if(element.hasPassedConfigured()) {
columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(IdentityCourseElementCols.passed, new PassedCellRenderer()));
}
columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(IdentityCourseElementCols.assessmentStatus, new AssessmentStatusCellRenderer(getLocale())));
columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(IdentityCourseElementCols.initialLaunchDate, "select"));
columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(IdentityCourseElementCols.lastScoreUpdate, "select"));
//columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(IdentityCourseElementCols.certificate, new DownloadCertificateCellRenderer()));
usersTableModel = new AssessedIdentityListTableModel(columnsModel, element);
usersTableModel.setCertificateMap(new ConcurrentHashMap<>());
tableEl = uifactory.addTableElement(getWindowControl(), "table", usersTableModel, 20, false, getTranslator(), formLayout);
tableEl.setExportEnabled(true);
tableEl.setSearchEnabled(new AssessedIdentityListProvider(getIdentity(), testEntry, testEntry, null, assessmentCallback), ureq.getUserSession());
List<FlexiTableFilter> filters = new ArrayList<>();
filters.add(new FlexiTableFilter(translate("filter.passed"), "passed"));
filters.add(new FlexiTableFilter(translate("filter.failed"), "failed"));
filters.add(new FlexiTableFilter(translate("filter.inProgress"), "inProgress"));
filters.add(new FlexiTableFilter(translate("filter.inReview"), "inReview"));
filters.add(new FlexiTableFilter(translate("filter.done"), "done"));
tableEl.setFilters("", filters, false);
if(assessmentCallback.canAssessBusinessGoupMembers()) {
List<BusinessGroup> coachedGroups;
if(assessmentCallback.isAdmin()) {
SearchBusinessGroupParams params = new SearchBusinessGroupParams();
coachedGroups = businessGroupService.findBusinessGroups(params, testEntry, 0, -1);
} else {
coachedGroups = assessmentCallback.getCoachedGroups();
}
if(coachedGroups.size() > 0) {
List<FlexiTableFilter> groupFilters = new ArrayList<>();
for(BusinessGroup coachedGroup:coachedGroups) {
String groupName = StringHelper.escapeHtml(coachedGroup.getName());
groupFilters.add(new FlexiTableFilter(groupName, coachedGroup.getKey().toString(), "o_icon o_icon_group"));
}
tableEl.setExtendedFilterButton(translate("filter.groups"), groupFilters);
}
}
}
public class AToolsOptions extends AssessmentToolOptions {
@Override
public List<Identity> getIdentities() {
return assessmentToolManager.getAssessedIdentities(getIdentity(), searchParams);
}
}
private void updateModel(UserRequest ureq, String searchString, List<FlexiTableFilter> filters, List<FlexiTableFilter> extendedFilters) {
SearchAssessedIdentityParams params = new SearchAssessedIdentityParams(testEntry, null, testEntry, assessmentCallback);
List<AssessmentEntryStatus> assessmentStatus = null;
if(filters != null && filters.size() > 0) {
assessmentStatus = new ArrayList<>(filters.size());
for(FlexiTableFilter filter:filters) {
if("passed".equals(filter.getFilter())) {
params.setPassed(true);
} else if("failed".equals(filter.getFilter())) {
params.setFailed(true);
} else if(AssessmentEntryStatus.isValueOf(filter.getFilter())){
assessmentStatus.add(AssessmentEntryStatus.valueOf(filter.getFilter()));
}
}
}
params.setAssessmentStatus(assessmentStatus);
List<Long> businessGroupKeys = null;
if(extendedFilters != null && extendedFilters.size() > 0) {
businessGroupKeys = new ArrayList<>(extendedFilters.size());
for(FlexiTableFilter extendedFilter:extendedFilters) {
if(StringHelper.isLong(extendedFilter.getFilter())) {
businessGroupKeys.add(Long.parseLong(extendedFilter.getFilter()));
}
}
}
params.setBusinessGroupKeys(businessGroupKeys);
params.setSearchString(searchString);
List<Identity> assessedIdentities = assessmentToolManager.getAssessedIdentities(getIdentity(), params);
List<AssessmentEntry> assessmentEntries = assessmentToolManager.getAssessmentEntries(getIdentity(), params, null);
Map<Long,AssessmentEntry> entryMap = new HashMap<>();
assessmentEntries.stream().filter((entry) -> entry.getIdentity() != null)
.forEach((entry) -> entryMap.put(entry.getIdentity().getKey(), entry));
List<AssessedIdentityElementRow> rows = new ArrayList<>(assessedIdentities.size());
for(Identity assessedIdentity:assessedIdentities) {
AssessmentEntry entry = entryMap.get(assessedIdentity.getKey());
rows.add(new AssessedIdentityElementRow(assessedIdentity, entry, userPropertyHandlers, getLocale()));
}
usersTableModel.setObjects(rows);
if(filters != null && filters.size() > 0 && filters.get(0) != null) {
usersTableModel.filter(Collections.singletonList(filters.get(0)));
}
tableEl.reloadData();
searchParams = params;
List<String> toolCmpNames = new ArrayList<>();
AssessmentToolOptions asOptions = new AssessmentToolOptions();
asOptions.setAdmin(assessmentCallback.isAdmin());
asOptions.setIdentities(assessedIdentities);
List<Controller> tools = element.createAssessmentTools(ureq, getWindowControl(), stackPanel,
testEntry, asOptions);
int count = 0;
if(tools.size() > 0) {
for(Controller tool:tools) {
listenTo(tool);
String toolCmpName = "ctrl_" + (count++);
flc.put(toolCmpName, tool.getInitialComponent());
toolCmpNames.add(toolCmpName);
if(tool instanceof BreadcrumbPanelAware) {
((BreadcrumbPanelAware)tool).setBreadcrumbPanel(stackPanel);
}
}
}
if(toolsCtrl != null) {
for(Controller toolCtrl:toolsCtrl) {
removeAsListenerAndDispose(toolCtrl);
}
}
toolsCtrl = tools;
flc.contextPut("toolCmpNames", toolCmpNames);
}
@Override
protected void doDispose() {
//
}
@Override
public void activate(UserRequest ureq, List<ContextEntry> entries, StateEntry state) {
String filter = null;
if(state instanceof AssessedIdentityListState) {
AssessedIdentityListState listState = (AssessedIdentityListState)state;
if(StringHelper.containsNonWhitespace(listState.getFilter())) {
filter = listState.getFilter();
}
}
tableEl.setSelectedFilterKey(filter);
updateModel(ureq, null, tableEl.getSelectedFilters(), null);
if(entries != null && entries.size() > 0) {
String resourceType = entries.get(0).getOLATResourceable().getResourceableTypeName();
if("Identity".equals(resourceType)) {
Long identityKey = entries.get(0).getOLATResourceable().getResourceableId();
for(int i=usersTableModel.getRowCount(); i--> 0; ) {
AssessedIdentityElementRow row = usersTableModel.getObject(i);
if(row.getIdentityKey().equals(identityKey)) {
doSelect(ureq, row);
}
}
}
}
}
@Override
protected void formOK(UserRequest ureq) {
//
}
@Override
public void event(UserRequest ureq, Component source, Event event) {
if(previousLink == source) {
doPrevious(ureq);
} else if(nextLink == source) {
doNext(ureq);
}
super.event(ureq, source, event);
}
@Override
public void event(UserRequest ureq, Controller source, Event event) {
if(currentIdentityCtrl == source) {
if(event == Event.CHANGED_EVENT) {
updateModel(ureq, null, null, null);
} else if(event == Event.DONE_EVENT) {
updateModel(ureq, null, null, null);
stackPanel.popController(currentIdentityCtrl);
} else if(event == Event.CANCELLED_EVENT) {
stackPanel.popController(currentIdentityCtrl);
}
} else if(toolsCtrl != null && toolsCtrl.contains(source)) {
if(event == Event.CHANGED_EVENT) {
updateModel(ureq, null, null, null);
}
}
super.event(ureq, source, event);
}
@Override
protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) {
if(tableEl == source) {
if(event instanceof SelectionEvent) {
SelectionEvent se = (SelectionEvent)event;
String cmd = se.getCommand();
AssessedIdentityElementRow row = usersTableModel.getObject(se.getIndex());
if("select".equals(cmd)) {
doSelect(ureq, row);
}
} else if(event instanceof FlexiTableSearchEvent) {
FlexiTableSearchEvent ftse = (FlexiTableSearchEvent)event;
updateModel(ureq, ftse.getSearch(), ftse.getFilters(), ftse.getExtendedFilters());
}
}
super.formInnerEvent(ureq, source, event);
}
private void doNext(UserRequest ureq) {
stackPanel.popController(currentIdentityCtrl);
Identity currentIdentity = currentIdentityCtrl.getAssessedIdentity();
int index = getIndexOf(currentIdentity);
if(index >= 0) {
int nextIndex = index + 1;//next
if(nextIndex >= 0 && nextIndex < usersTableModel.getRowCount()) {
doSelect(ureq, usersTableModel.getObject(nextIndex));
} else if(usersTableModel.getRowCount() > 0) {
doSelect(ureq, usersTableModel.getObject(0));
}
}
}
private void doPrevious(UserRequest ureq) {
stackPanel.popController(currentIdentityCtrl);
Identity currentIdentity = currentIdentityCtrl.getAssessedIdentity();
int index = getIndexOf(currentIdentity);
if(index >= 0) {
int previousIndex = index - 1;//next
if(previousIndex >= 0 && previousIndex < usersTableModel.getRowCount()) {
doSelect(ureq, usersTableModel.getObject(previousIndex));
} else if(usersTableModel.getRowCount() > 0) {
doSelect(ureq, usersTableModel.getObject(usersTableModel.getRowCount() - 1));
}
}
}
private int getIndexOf(Identity identity) {
for(int i=usersTableModel.getRowCount(); i-->0; ) {
Long rowIdentityKey = usersTableModel.getObject(i).getIdentityKey();
if(rowIdentityKey.equals(identity.getKey())) {
return i;
}
}
return -1;
}
private void doSelect(UserRequest ureq, AssessedIdentityElementRow row) {
removeAsListenerAndDispose(currentIdentityCtrl);
Identity assessedIdentity = securityManager.loadIdentityByKey(row.getIdentityKey());
String fullName = userManager.getUserDisplayName(assessedIdentity);
currentIdentityCtrl = new AssessedIdentityRepositoryEntryController(ureq, getWindowControl(), stackPanel,
testEntry, assessedIdentity, element);
listenTo(currentIdentityCtrl);
stackPanel.pushController(fullName, currentIdentityCtrl);
previousLink = LinkFactory.createToolLink("previouselement","", this, "o_icon_previous_toolbar");
previousLink.setTitle(translate("command.previous"));
stackPanel.addTool(previousLink, Align.rightEdge, false, "o_tool_previous");
nextLink = LinkFactory.createToolLink("nextelement","", this, "o_icon_next_toolbar");
nextLink.setTitle(translate("command.next"));
stackPanel.addTool(nextLink, Align.rightEdge, false, "o_tool_next");
}
}