added institution column to quiz-, exam- and log-list pages

This commit is contained in:
anhefti 2019-08-22 13:00:14 +02:00
parent dd826a3770
commit 0c2c592d79
7 changed files with 173 additions and 10 deletions

View file

@ -22,6 +22,14 @@ public class Tuple<T> {
this._2 = _2;
}
public T get_1() {
return this._1;
}
public T get_2() {
return this._2;
}
@Override
public int hashCode() {
final int prime = 31;

View file

@ -8,6 +8,7 @@
package ch.ethz.seb.sebserver.gui.content;
import java.util.function.BooleanSupplier;
import java.util.function.Function;
import org.eclipse.swt.widgets.Composite;
@ -19,9 +20,11 @@ import org.springframework.stereotype.Component;
import ch.ethz.seb.sebserver.gbl.api.EntityType;
import ch.ethz.seb.sebserver.gbl.model.Domain;
import ch.ethz.seb.sebserver.gbl.model.Entity;
import ch.ethz.seb.sebserver.gbl.model.exam.Exam;
import ch.ethz.seb.sebserver.gbl.model.exam.QuizData;
import ch.ethz.seb.sebserver.gbl.model.institution.LmsSetup;
import ch.ethz.seb.sebserver.gbl.model.user.UserRole;
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
import ch.ethz.seb.sebserver.gbl.util.Utils;
import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition;
@ -55,7 +58,9 @@ public class ExamList implements TemplateComposer {
new LocTextKey("sebserver.exam.list.action.no.modify.privilege");
private final static LocTextKey EMPTY_SELECTION_TEXT_KEY =
new LocTextKey("sebserver.exam.info.pleaseSelect");
private final static LocTextKey COLUMN_TITLE_KEY =
private final static LocTextKey COLUMN_TITLE_INSTITUTION_KEY =
new LocTextKey("sebserver.exam.list.column.institution");
private final static LocTextKey COLUMN_TITLE_LMS_KEY =
new LocTextKey("sebserver.exam.list.column.lmssetup");
private final static LocTextKey COLUMN_TITLE_NAME_KEY =
new LocTextKey("sebserver.exam.list.column.name");
@ -66,6 +71,7 @@ public class ExamList implements TemplateComposer {
private final static LocTextKey EMPTY_LIST_TEXT_KEY =
new LocTextKey("sebserver.exam.list.empty");
private final TableFilterAttribute institutionFilter;
private final TableFilterAttribute lmsFilter;
private final TableFilterAttribute nameFilter =
new TableFilterAttribute(CriteriaType.TEXT, QuizData.FILTER_ATTR_NAME);
@ -84,6 +90,11 @@ public class ExamList implements TemplateComposer {
this.resourceService = resourceService;
this.pageSize = pageSize;
this.institutionFilter = new TableFilterAttribute(
CriteriaType.SINGLE_SELECTION,
Entity.FILTER_ATTR_INSTITUTION,
this.resourceService::institutionResource);
this.lmsFilter = new TableFilterAttribute(
CriteriaType.SINGLE_SELECTION,
LmsSetup.FILTER_ATTR_LMS_SETUP,
@ -111,23 +122,41 @@ public class ExamList implements TemplateComposer {
final PageActionBuilder actionBuilder = this.pageService
.pageActionBuilder(pageContext.clearEntityKeys());
final BooleanSupplier isSebAdmin =
() -> currentUser.get().hasRole(UserRole.SEB_SERVER_ADMIN);
final Function<String, String> institutionNameFunction =
this.resourceService.getInstitutionNameFunction();
// table
final EntityTable<Exam> table =
this.pageService.entityTableBuilder(restService.getRestCall(GetExamPage.class))
.withEmptyMessage(EMPTY_LIST_TEXT_KEY)
.withPaging(this.pageSize)
.withColumnIf(
isSebAdmin,
() -> new ColumnDefinition<Exam>(
Domain.EXAM.ATTR_INSTITUTION_ID,
COLUMN_TITLE_INSTITUTION_KEY,
exam -> institutionNameFunction
.apply(String.valueOf(exam.getInstitutionId())))
.withFilter(this.institutionFilter))
.withColumn(new ColumnDefinition<>(
Domain.EXAM.ATTR_LMS_SETUP_ID,
COLUMN_TITLE_KEY,
COLUMN_TITLE_LMS_KEY,
examLmsSetupNameFunction(this.resourceService))
.withFilter(this.lmsFilter)
.sortable())
.withColumn(new ColumnDefinition<>(
QuizData.QUIZ_ATTR_NAME,
COLUMN_TITLE_NAME_KEY,
Exam::getName)
.withFilter(this.nameFilter)
.sortable())
.withColumn(new ColumnDefinition<>(
QuizData.QUIZ_ATTR_START_TIME,
new LocTextKey(
@ -141,15 +170,18 @@ public class ExamList implements TemplateComposer {
.minusYears(1)
.toString()))
.sortable())
.withColumn(new ColumnDefinition<>(
Domain.EXAM.ATTR_TYPE,
COLUMN_TITLE_TYPE_KEY,
this.resourceService::localizedExamTypeName)
.withFilter(this.typeFilter)
.sortable())
.withDefaultAction(actionBuilder
.newAction(ActionDefinition.EXAM_VIEW_FROM_LIST)
.create())
.compose(pageContext.copyOf(content));
// propagate content actions to action-pane

View file

@ -8,6 +8,7 @@
package ch.ethz.seb.sebserver.gui.content;
import java.util.function.BooleanSupplier;
import java.util.function.Function;
import org.eclipse.swt.widgets.Composite;
@ -18,9 +19,11 @@ import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
import ch.ethz.seb.sebserver.gbl.api.EntityType;
import ch.ethz.seb.sebserver.gbl.model.Entity;
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
import ch.ethz.seb.sebserver.gbl.model.exam.QuizData;
import ch.ethz.seb.sebserver.gbl.model.institution.LmsSetup;
import ch.ethz.seb.sebserver.gbl.model.user.UserRole;
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition;
import ch.ethz.seb.sebserver.gui.form.FormBuilder;
@ -61,6 +64,8 @@ public class QuizDiscoveryList implements TemplateComposer {
new LocTextKey("sebserver.quizdiscovery.quiz.details.description");
private static final LocTextKey QUIZ_DETAILS_NAME_TEXT_KEY =
new LocTextKey("sebserver.quizdiscovery.quiz.details.name");
private static final LocTextKey QUIZ_DETAILS_INSTITUION_TEXT_KEY =
new LocTextKey("sebserver.quizdiscovery.quiz.details.institution");
private static final LocTextKey QUIZ_DETAILS_LMS_TEXT_KEY =
new LocTextKey("sebserver.quizdiscovery.quiz.details.lms");
private static final LocTextKey TITLE_TEXT_KEY =
@ -69,6 +74,8 @@ public class QuizDiscoveryList implements TemplateComposer {
new LocTextKey("sebserver.quizdiscovery.list.empty");
private final static LocTextKey EMPTY_SELECTION_TEXT =
new LocTextKey("sebserver.quizdiscovery.info.pleaseSelect");
private final static LocTextKey INSTITUION_TEXT_KEY =
new LocTextKey("sebserver.quizdiscovery.list.column.institution");
private final static LocTextKey LMS_TEXT_KEY =
new LocTextKey("sebserver.quizdiscovery.list.column.lmssetup");
private final static LocTextKey NAME_TEXT_KEY =
@ -79,6 +86,7 @@ public class QuizDiscoveryList implements TemplateComposer {
new LocTextKey("sebserver.quizdiscovery.quiz.import.out.dated");
// filter attribute models
private final TableFilterAttribute institutionFilter;
private final TableFilterAttribute lmsFilter;
private final TableFilterAttribute nameFilter =
new TableFilterAttribute(CriteriaType.TEXT, QuizData.FILTER_ATTR_NAME);
@ -101,6 +109,11 @@ public class QuizDiscoveryList implements TemplateComposer {
this.resourceService = resourceService;
this.pageSize = pageSize;
this.institutionFilter = new TableFilterAttribute(
CriteriaType.SINGLE_SELECTION,
Entity.FILTER_ATTR_INSTITUTION,
this.resourceService::institutionResource);
this.lmsFilter = new TableFilterAttribute(
CriteriaType.SINGLE_SELECTION,
LmsSetup.FILTER_ATTR_LMS_SETUP,
@ -118,25 +131,44 @@ public class QuizDiscoveryList implements TemplateComposer {
pageContext.getParent(),
TITLE_TEXT_KEY);
final PageActionBuilder actionBuilder = this.pageService.pageActionBuilder(pageContext.clearEntityKeys());
final PageActionBuilder actionBuilder =
this.pageService.pageActionBuilder(pageContext.clearEntityKeys());
final BooleanSupplier isSebAdmin =
() -> currentUser.get().hasRole(UserRole.SEB_SERVER_ADMIN);
final Function<String, String> institutionNameFunction =
this.resourceService.getInstitutionNameFunction();
// table
final EntityTable<QuizData> table =
this.pageService.entityTableBuilder(restService.getRestCall(GetQuizPage.class))
.withEmptyMessage(EMPTY_LIST_TEXT_KEY)
.withPaging(this.pageSize)
.withColumnIf(
isSebAdmin,
() -> new ColumnDefinition<QuizData>(
QuizData.QUIZ_ATTR_INSTITUION_ID,
INSTITUION_TEXT_KEY,
quiz -> institutionNameFunction
.apply(String.valueOf(quiz.institutionId)))
.withFilter(this.institutionFilter))
.withColumn(new ColumnDefinition<>(
QuizData.QUIZ_ATTR_LMS_SETUP_ID,
LMS_TEXT_KEY,
quizDataLmsSetupNameFunction(this.resourceService))
.withFilter(this.lmsFilter)
.sortable())
.withColumn(new ColumnDefinition<>(
QuizData.QUIZ_ATTR_NAME,
NAME_TEXT_KEY,
QuizData::getName)
.withFilter(this.nameFilter)
.sortable())
.withColumn(new ColumnDefinition<>(
QuizData.QUIZ_ATTR_START_TIME,
new LocTextKey(
@ -145,6 +177,7 @@ public class QuizDiscoveryList implements TemplateComposer {
QuizData::getStartTime)
.withFilter(this.startTimeFilter)
.sortable())
.withColumn(new ColumnDefinition<>(
QuizData.QUIZ_ATTR_END_TIME,
new LocTextKey(
@ -152,11 +185,16 @@ public class QuizDiscoveryList implements TemplateComposer {
i18nSupport.getUsersTimeZoneTitleSuffix()),
QuizData::getEndTime)
.sortable())
.withDefaultAction(t -> actionBuilder
.newAction(ActionDefinition.QUIZ_DISCOVERY_SHOW_DETAILS)
.withExec(action -> this.showDetails(action, t.getSelectedROWData()))
.withExec(action -> this.showDetails(
action,
t.getSelectedROWData(),
institutionNameFunction))
.noEventPropagation()
.create())
.compose(pageContext.copyOf(content));
// propagate content actions to action-pane
@ -170,7 +208,10 @@ public class QuizDiscoveryList implements TemplateComposer {
.newAction(ActionDefinition.QUIZ_DISCOVERY_SHOW_DETAILS)
.withSelect(
table::getSelection,
action -> this.showDetails(action, table.getSelectedROWData()),
action -> this.showDetails(
action,
table.getSelectedROWData(),
institutionNameFunction),
EMPTY_SELECTION_TEXT)
.noEventPropagation()
.publishIf(table::hasAnyContent)
@ -205,7 +246,11 @@ public class QuizDiscoveryList implements TemplateComposer {
.withAttribute(AttributeKeys.IMPORT_FROM_QUIZ_DATA, "true");
}
private PageAction showDetails(final PageAction action, final QuizData quizData) {
private PageAction showDetails(
final PageAction action,
final QuizData quizData,
final Function<String, String> institutionNameFunction) {
action.getSingleSelection();
final ModalInputDialog<Void> dialog = new ModalInputDialog<>(
@ -215,12 +260,15 @@ public class QuizDiscoveryList implements TemplateComposer {
dialog.open(
DETAILS_TITLE_TEXT_KEY,
action.pageContext(),
pc -> createDetailsForm(quizData, pc));
pc -> createDetailsForm(quizData, pc, institutionNameFunction));
return action;
}
private void createDetailsForm(final QuizData quizData, final PageContext pc) {
private void createDetailsForm(
final QuizData quizData,
final PageContext pc,
final Function<String, String> institutionNameFunction) {
final Composite parent = pc.getParent();
final Composite grid = this.widgetFactory.createPopupScrollComposite(parent);
@ -228,6 +276,12 @@ public class QuizDiscoveryList implements TemplateComposer {
this.pageService.formBuilder(pc.copyOf(grid), 3)
.withEmptyCellSeparation(false)
.readonly(true)
.addFieldIf(
() -> this.resourceService.getCurrentUser().get().hasRole(UserRole.SEB_SERVER_ADMIN),
() -> FormBuilder.text(
QuizData.QUIZ_ATTR_INSTITUION_ID,
QUIZ_DETAILS_INSTITUION_TEXT_KEY,
institutionNameFunction.apply(quizData.getModelId())))
.addField(FormBuilder.singleSelection(
QuizData.QUIZ_ATTR_LMS_SETUP_ID,
QUIZ_DETAILS_LMS_TEXT_KEY,

View file

@ -9,6 +9,7 @@
package ch.ethz.seb.sebserver.gui.content;
import java.util.Map;
import java.util.function.BooleanSupplier;
import java.util.function.Function;
import org.eclipse.swt.widgets.Composite;
@ -26,6 +27,7 @@ import ch.ethz.seb.sebserver.gbl.model.exam.QuizData;
import ch.ethz.seb.sebserver.gbl.model.session.ClientConnection;
import ch.ethz.seb.sebserver.gbl.model.session.ClientEvent;
import ch.ethz.seb.sebserver.gbl.model.session.ExtendedClientEvent;
import ch.ethz.seb.sebserver.gbl.model.user.UserRole;
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
import ch.ethz.seb.sebserver.gbl.util.Utils;
import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition;
@ -43,6 +45,7 @@ import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.GetExam;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.logs.GetExtendedClientEventPage;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.session.GetClientConnection;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser;
import ch.ethz.seb.sebserver.gui.table.ColumnDefinition;
import ch.ethz.seb.sebserver.gui.table.ColumnDefinition.TableFilterAttribute;
import ch.ethz.seb.sebserver.gui.table.EntityTable;
@ -64,6 +67,8 @@ public class SebClientLogs implements TemplateComposer {
private static final LocTextKey EMPTY_TEXT_KEY =
new LocTextKey("sebserver.seblogs.list.empty");
private static final LocTextKey INSTITUTION_TEXT_KEY =
new LocTextKey("sebserver.seblogs.list.column.institution");
private static final LocTextKey EXAM_TEXT_KEY =
new LocTextKey("sebserver.seblogs.list.column.exam");
private static final LocTextKey CLIENT_SESSION_TEXT_KEY =
@ -155,6 +160,7 @@ public class SebClientLogs implements TemplateComposer {
@Override
public void compose(final PageContext pageContext) {
final CurrentUser currentUser = this.resourceService.getCurrentUser();
final WidgetFactory widgetFactory = this.pageService.getWidgetFactory();
final RestService restService = this.resourceService.getRestService();
// content page layout with title
@ -167,12 +173,35 @@ public class SebClientLogs implements TemplateComposer {
.clearEntityKeys()
.clearAttributes());
final BooleanSupplier isSebAdmin =
() -> currentUser.get().hasRole(UserRole.SEB_SERVER_ADMIN);
final Function<ExtendedClientEvent, String> institutionNameFunction =
this.resourceService.getInstitutionNameFunction()
.compose(log -> {
try {
final ClientConnection connection = restService.getBuilder(GetClientConnection.class)
.withURIVariable(API.PARAM_MODEL_ID, String.valueOf(log.getConnectionId()))
.call().getOrThrow();
return String.valueOf(connection.getInstitutionId());
} catch (final Exception e) {
return Constants.EMPTY_NOTE;
}
});
// table
final EntityTable<ExtendedClientEvent> table = this.pageService.entityTableBuilder(
restService.getRestCall(GetExtendedClientEventPage.class))
.withEmptyMessage(EMPTY_TEXT_KEY)
.withPaging(this.pageSize)
.withColumnIf(
isSebAdmin,
() -> new ColumnDefinition<>(
Domain.INSTITUTION.ATTR_NAME,
INSTITUTION_TEXT_KEY,
institutionNameFunction)
.widthProportion(2))
.withColumn(new ColumnDefinition<>(
Domain.CLIENT_CONNECTION.ATTR_EXAM_ID,
EXAM_TEXT_KEY,

View file

@ -8,14 +8,20 @@
package ch.ethz.seb.sebserver.gui.content;
import java.util.function.BooleanSupplier;
import java.util.function.Function;
import org.eclipse.swt.widgets.Composite;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
import ch.ethz.seb.sebserver.gbl.Constants;
import ch.ethz.seb.sebserver.gbl.api.API;
import ch.ethz.seb.sebserver.gbl.model.Domain;
import ch.ethz.seb.sebserver.gbl.model.user.UserActivityLog;
import ch.ethz.seb.sebserver.gbl.model.user.UserInfo;
import ch.ethz.seb.sebserver.gbl.model.user.UserRole;
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
import ch.ethz.seb.sebserver.gbl.util.Utils;
import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition;
@ -31,6 +37,8 @@ import ch.ethz.seb.sebserver.gui.service.page.impl.ModalInputDialog;
import ch.ethz.seb.sebserver.gui.service.page.impl.PageAction;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.logs.GetUserLogPage;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.useraccount.GetUserAccount;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser;
import ch.ethz.seb.sebserver.gui.table.ColumnDefinition;
import ch.ethz.seb.sebserver.gui.table.ColumnDefinition.TableFilterAttribute;
import ch.ethz.seb.sebserver.gui.table.EntityTable;
@ -48,6 +56,8 @@ public class UserActivityLogs implements TemplateComposer {
new LocTextKey("sebserver.userlogs.list.title");
private static final LocTextKey EMPTY_TEXT_KEY =
new LocTextKey("sebserver.userlogs.list.empty");
private static final LocTextKey INSTITUTION_TEXT_KEY =
new LocTextKey("sebserver.userlogs.list.column.institution");
private static final LocTextKey USER_TEXT_KEY =
new LocTextKey("sebserver.userlogs.list.column.user");
private static final LocTextKey DATE_TEXT_KEY =
@ -101,6 +111,7 @@ public class UserActivityLogs implements TemplateComposer {
@Override
public void compose(final PageContext pageContext) {
final CurrentUser currentUser = this.resourceService.getCurrentUser();
final WidgetFactory widgetFactory = this.pageService.getWidgetFactory();
final RestService restService = this.resourceService.getRestService();
// content page layout with title
@ -113,12 +124,35 @@ public class UserActivityLogs implements TemplateComposer {
.clearEntityKeys()
.clearAttributes());
final BooleanSupplier isSebAdmin =
() -> currentUser.get().hasRole(UserRole.SEB_SERVER_ADMIN);
final Function<UserActivityLog, String> institutionNameFunction =
this.resourceService.getInstitutionNameFunction()
.compose(log -> {
try {
final UserInfo user = restService.getBuilder(GetUserAccount.class)
.withURIVariable(API.PARAM_MODEL_ID, log.getUserUuid())
.call().getOrThrow();
return String.valueOf(user.getInstitutionId());
} catch (final Exception e) {
return Constants.EMPTY_NOTE;
}
});
// table
final EntityTable<UserActivityLog> table = this.pageService.entityTableBuilder(
restService.getRestCall(GetUserLogPage.class))
.withEmptyMessage(EMPTY_TEXT_KEY)
.withPaging(this.pageSize)
.withColumnIf(
isSebAdmin,
() -> new ColumnDefinition<>(
UserActivityLog.FILTER_ATTR_INSTITUTION,
INSTITUTION_TEXT_KEY,
institutionNameFunction))
.withColumn(new ColumnDefinition<>(
UserActivityLog.ATTR_USER_NAME,
USER_TEXT_KEY,

View file

@ -85,8 +85,12 @@ public class QuizController {
EntityType.EXAM,
institutionId);
final FilterMap filterMap = new FilterMap(allRequestParams)
.putIfAbsent(Entity.FILTER_ATTR_INSTITUTION, String.valueOf(institutionId));
final FilterMap filterMap = new FilterMap(allRequestParams);
// if current user has no read access for specified entity type within other institution
// then the current users institutionId is put as a SQL filter criteria attribute to extends query performance
if (!this.authorization.hasGrant(PrivilegeType.READ, EntityType.EXAM)) {
filterMap.putIfAbsent(API.PARAM_INSTITUTION_ID, String.valueOf(institutionId));
}
return this.lmsAPIService.requestQuizDataPage(
(pageNumber != null)

View file

@ -254,6 +254,7 @@ sebserver.quizdiscovery.action.details=Show Details
sebserver.quizdiscovery.quiz.details.title=Quiz Details
sebserver.quizdiscovery.quiz.details.lms=LMS
sebserver.quizdiscovery.quiz.details.institution=Institution
sebserver.quizdiscovery.quiz.details.name=Name
sebserver.quizdiscovery.quiz.details.description=Description
sebserver.quizdiscovery.quiz.details.starttime=Start Time
@ -980,6 +981,7 @@ sebserver.seblogs.list.actions=Selected Log
sebserver.seblogs.list.empty=No SEB client logs has been found. Please adapt or clear the filter
sebserver.seblogs.info.pleaseSelect=Please select a log from the list
sebserver.seblogs.list.column.institution=Institution
sebserver.seblogs.list.column.exam=Exam
sebserver.seblogs.list.column.client-session=User Session-ID
sebserver.seblogs.list.column.type=Event Type