SEBSERV-240 implementation
This commit is contained in:
parent
51e27ff4e5
commit
6d56e71dbe
14 changed files with 459 additions and 7 deletions
|
@ -193,6 +193,7 @@ public final class API {
|
|||
public static final String EXAM_MONITORING_NOTIFICATION_ENDPOINT = "/notification";
|
||||
public static final String EXAM_MONITORING_DISABLE_CONNECTION_ENDPOINT = "/disable-connection";
|
||||
public static final String EXAM_MONITORING_STATE_FILTER = "hidden-states";
|
||||
public static final String EXAM_MONITORING_FINISHED_ENDPOINT = "/finishedexams";
|
||||
public static final String EXAM_MONITORING_SEB_CONNECTION_TOKEN_PATH_SEGMENT =
|
||||
"/{" + EXAM_API_SEB_CONNECTION_TOKEN + "}";
|
||||
|
||||
|
|
|
@ -35,7 +35,9 @@ public enum ActionCategory {
|
|||
LOGS_SEB_CLIENT_LIST(new LocTextKey("sebserver.userlogs.list.actions"), 1),
|
||||
VARIA(new LocTextKey("sebserver.overall.action.category.varia"), 0),
|
||||
FILTER(new LocTextKey("sebserver.exam.monitoring.action.category.filter"), 50),
|
||||
PROCTORING(new LocTextKey("sebserver.exam.overall.action.category.proctoring"), 60);
|
||||
PROCTORING(new LocTextKey("sebserver.exam.overall.action.category.proctoring"), 60),
|
||||
|
||||
FINISHED_EXAM_LIST(new LocTextKey("sebserver.finished.exam.list.actions"), 1);
|
||||
|
||||
public final LocTextKey title;
|
||||
public final int slotPosition;
|
||||
|
|
|
@ -832,6 +832,15 @@ public enum ActionDefinition {
|
|||
PageStateDefinitionImpl.MONITORING_RUNNING_EXAM,
|
||||
ActionCategory.PROCTORING),
|
||||
|
||||
FINISHED_EXAM_VIEW_LIST(
|
||||
new LocTextKey("sebserver.finished.action.list"),
|
||||
PageStateDefinitionImpl.FINISHED_EXAM_LIST),
|
||||
VIEW_EXAM_FROM_FINISHED_LIST(
|
||||
new LocTextKey("sebserver.finished.exam.action.list.view"),
|
||||
ImageIcon.SHOW,
|
||||
PageStateDefinitionImpl.FINISHED_EXAM,
|
||||
ActionCategory.FINISHED_EXAM_LIST),
|
||||
|
||||
LOGS_USER_ACTIVITY_LIST(
|
||||
new LocTextKey("sebserver.logs.activity.userlogs"),
|
||||
PageStateDefinitionImpl.USER_ACTIVITY_LOGS),
|
||||
|
|
|
@ -339,14 +339,25 @@ public class ActivitiesPane implements TemplateComposer {
|
|||
|
||||
// Monitoring exams
|
||||
if (isSupporter) {
|
||||
final TreeItem clientConfig = this.widgetFactory.treeItemLocalized(
|
||||
|
||||
final TreeItem monitoringExams = this.widgetFactory.treeItemLocalized(
|
||||
monitoring,
|
||||
ActivityDefinition.MONITORING_EXAMS.displayName);
|
||||
injectActivitySelection(
|
||||
clientConfig,
|
||||
monitoringExams,
|
||||
actionBuilder
|
||||
.newAction(ActionDefinition.RUNNING_EXAM_VIEW_LIST)
|
||||
.create());
|
||||
|
||||
final TreeItem clientConfig = this.widgetFactory.treeItemLocalized(
|
||||
monitoring,
|
||||
ActivityDefinition.FINISHED_EXAMS.displayName);
|
||||
injectActivitySelection(
|
||||
clientConfig,
|
||||
actionBuilder
|
||||
.newAction(ActionDefinition.FINISHED_EXAM_VIEW_LIST)
|
||||
.create());
|
||||
|
||||
}
|
||||
|
||||
// SEB Client Logs
|
||||
|
|
|
@ -28,6 +28,7 @@ public enum ActivityDefinition implements Activity {
|
|||
SEB_CERTIFICATE_MANAGEMENT(new LocTextKey("sebserver.certificate.action.list")),
|
||||
MONITORING(new LocTextKey("sebserver.overall.activity.title.monitoring")),
|
||||
MONITORING_EXAMS(new LocTextKey("sebserver.monitoring.action.list")),
|
||||
FINISHED_EXAMS(new LocTextKey("sebserver.finished.action.list")),
|
||||
SEB_CLIENT_LOGS(new LocTextKey("sebserver.logs.activity.seblogs"));
|
||||
|
||||
public final LocTextKey displayName;
|
||||
|
|
|
@ -33,6 +33,8 @@ import ch.ethz.seb.sebserver.gui.content.exam.IndicatorTemplateForm;
|
|||
import ch.ethz.seb.sebserver.gui.content.exam.LmsSetupForm;
|
||||
import ch.ethz.seb.sebserver.gui.content.exam.LmsSetupList;
|
||||
import ch.ethz.seb.sebserver.gui.content.exam.QuizLookupList;
|
||||
import ch.ethz.seb.sebserver.gui.content.monitoring.FinishedExam;
|
||||
import ch.ethz.seb.sebserver.gui.content.monitoring.FinishedExamList;
|
||||
import ch.ethz.seb.sebserver.gui.content.monitoring.MonitoringClientConnection;
|
||||
import ch.ethz.seb.sebserver.gui.content.monitoring.MonitoringRunningExam;
|
||||
import ch.ethz.seb.sebserver.gui.content.monitoring.MonitoringRunningExamList;
|
||||
|
@ -96,6 +98,10 @@ public enum PageStateDefinitionImpl implements PageStateDefinition {
|
|||
MONITORING_RUNNING_EXAM(Type.FORM_VIEW, MonitoringRunningExam.class, ActivityDefinition.MONITORING_EXAMS),
|
||||
MONITORING_CLIENT_CONNECTION(Type.FORM_VIEW, MonitoringClientConnection.class, ActivityDefinition.MONITORING_EXAMS),
|
||||
|
||||
FINISHED_EXAM_LIST(Type.LIST_VIEW, FinishedExamList.class, ActivityDefinition.FINISHED_EXAMS),
|
||||
FINISHED_EXAM(Type.FORM_VIEW, FinishedExam.class, ActivityDefinition.FINISHED_EXAMS),
|
||||
FINISHED_CLIENT_CONNECTION(Type.FORM_VIEW, MonitoringClientConnection.class, ActivityDefinition.FINISHED_EXAMS),
|
||||
|
||||
USER_ACTIVITY_LOGS(Type.LIST_VIEW, UserActivityLogs.class, ActivityDefinition.USER_ACTIVITY_LOGS),
|
||||
SEB_CLIENT_LOGS(Type.LIST_VIEW, SEBClientEvents.class, ActivityDefinition.SEB_CLIENT_LOGS)
|
||||
|
||||
|
|
|
@ -0,0 +1,127 @@
|
|||
/*
|
||||
* Copyright (c) 2022 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.gui.content.monitoring;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.model.Domain;
|
||||
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
|
||||
import ch.ethz.seb.sebserver.gbl.model.exam.Indicator;
|
||||
import ch.ethz.seb.sebserver.gbl.model.session.ClientConnection;
|
||||
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
||||
import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition;
|
||||
import ch.ethz.seb.sebserver.gui.service.ResourceService;
|
||||
import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.PageContext;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.PageService;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.PageService.PageActionBuilder;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer;
|
||||
import ch.ethz.seb.sebserver.gui.service.push.ServerPushService;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.GetIndicators;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.session.GetClientConnectionPage;
|
||||
import ch.ethz.seb.sebserver.gui.table.ColumnDefinition;
|
||||
import ch.ethz.seb.sebserver.gui.table.ColumnDefinition.TableFilterAttribute;
|
||||
import ch.ethz.seb.sebserver.gui.table.TableBuilder;
|
||||
import ch.ethz.seb.sebserver.gui.table.TableFilter.CriteriaType;
|
||||
|
||||
@Lazy
|
||||
@Component
|
||||
@GuiProfile
|
||||
public class FinishedExam implements TemplateComposer {
|
||||
|
||||
private static final LocTextKey TITLE_TEXT_KEY =
|
||||
new LocTextKey("sebserver.finished.exam.connections.title");
|
||||
private static final LocTextKey EMPTY_LIST_TEXT_KEY =
|
||||
new LocTextKey("sebserver.finished.exam.connections.empty");
|
||||
private static final LocTextKey TABLE_COLUMN_NAME =
|
||||
new LocTextKey("sebserver.finished.exam.connections.name");
|
||||
private static final LocTextKey TABLE_COLUMN_INFO =
|
||||
new LocTextKey("sebserver.finished.exam.connections.info");
|
||||
private static final LocTextKey TABLE_COLUMN_STATUS =
|
||||
new LocTextKey("sebserver.finished.exam.connections.status");
|
||||
|
||||
private final TableFilterAttribute nameFilter =
|
||||
new TableFilterAttribute(CriteriaType.TEXT, ClientConnection.FILTER_ATTR_SESSION_ID);
|
||||
private final TableFilterAttribute infoFilter =
|
||||
new TableFilterAttribute(CriteriaType.TEXT, ClientConnection.ATTR_INFO);
|
||||
private final TableFilterAttribute statusFilter;
|
||||
|
||||
private final PageService pageService;
|
||||
private final RestService restService;
|
||||
private final ResourceService resourceService;
|
||||
private final int pageSize;
|
||||
|
||||
public FinishedExam(
|
||||
final ServerPushService serverPushService,
|
||||
final PageService pageService,
|
||||
@Value("${sebserver.gui.list.page.size:20}") final Integer pageSize) {
|
||||
|
||||
this.pageService = pageService;
|
||||
this.restService = pageService.getRestService();
|
||||
this.resourceService = pageService.getResourceService();
|
||||
this.pageSize = pageSize;
|
||||
|
||||
this.statusFilter = new TableFilterAttribute(
|
||||
CriteriaType.SINGLE_SELECTION,
|
||||
ClientConnection.FILTER_ATTR_STATUS,
|
||||
pageService.getResourceService()::localizedClientConnectionStatusResources);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void compose(final PageContext pageContext) {
|
||||
final EntityKey examKey = pageContext.getEntityKey();
|
||||
|
||||
final RestService restService = this.pageService.getRestService();
|
||||
final PageActionBuilder actionBuilder = this.pageService
|
||||
.pageActionBuilder(pageContext.clearEntityKeys());
|
||||
|
||||
final Collection<Indicator> indicators = restService.getBuilder(GetIndicators.class)
|
||||
.withQueryParam(Indicator.FILTER_ATTR_EXAM_ID, examKey.modelId)
|
||||
.call()
|
||||
.getOrThrow();
|
||||
|
||||
final TableBuilder<ClientConnection> tableBuilder =
|
||||
this.pageService.entityTableBuilder(restService.getRestCall(GetClientConnectionPage.class))
|
||||
.withEmptyMessage(EMPTY_LIST_TEXT_KEY)
|
||||
.withPaging(10)
|
||||
.withStaticFilter(ClientConnection.FILTER_ATTR_EXAM_ID, examKey.modelId)
|
||||
|
||||
.withColumn(new ColumnDefinition<>(
|
||||
Domain.CLIENT_CONNECTION.ATTR_EXAM_USER_SESSION_ID,
|
||||
TABLE_COLUMN_NAME,
|
||||
ClientConnection::getUserSessionId)
|
||||
.withFilter(this.nameFilter))
|
||||
|
||||
.withColumn(new ColumnDefinition<>(
|
||||
ClientConnection.ATTR_INFO,
|
||||
TABLE_COLUMN_INFO,
|
||||
ClientConnection::getInfo)
|
||||
.withFilter(this.infoFilter))
|
||||
|
||||
.withColumn(new ColumnDefinition<ClientConnection>(
|
||||
Domain.CLIENT_CONNECTION.ATTR_STATUS,
|
||||
TABLE_COLUMN_STATUS,
|
||||
row -> this.pageService.getResourceService()
|
||||
.localizedClientConnectionStatusName(row.getStatus()))
|
||||
.withFilter(this.statusFilter))
|
||||
|
||||
.withDefaultAction(t -> actionBuilder
|
||||
.newAction(ActionDefinition.MONITOR_EXAM_CLIENT_CONNECTION)
|
||||
.withParentEntityKey(examKey)
|
||||
.create());
|
||||
|
||||
tableBuilder.compose(pageContext);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,149 @@
|
|||
/*
|
||||
* Copyright (c) 2022 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.gui.content.monitoring;
|
||||
|
||||
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.model.Domain;
|
||||
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.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.content.exam.ExamList;
|
||||
import ch.ethz.seb.sebserver.gui.service.ResourceService;
|
||||
import ch.ethz.seb.sebserver.gui.service.i18n.I18nSupport;
|
||||
import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.PageContext;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.PageService;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.PageService.PageActionBuilder;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer;
|
||||
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.session.GetFinishedExamPage;
|
||||
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;
|
||||
import ch.ethz.seb.sebserver.gui.table.TableFilter.CriteriaType;
|
||||
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
|
||||
|
||||
@Lazy
|
||||
@Component
|
||||
@GuiProfile
|
||||
public class FinishedExamList implements TemplateComposer {
|
||||
|
||||
private static final LocTextKey PAGE_TITLE_KEY =
|
||||
new LocTextKey("sebserver.finished.exam.list.title");
|
||||
private final static LocTextKey EMPTY_SELECTION_TEXT_KEY =
|
||||
new LocTextKey("sebserver.finished.exam.info.pleaseSelect");
|
||||
private final static LocTextKey COLUMN_TITLE_NAME_KEY =
|
||||
new LocTextKey("sebserver.finished.exam.list.column.name");
|
||||
private final static LocTextKey COLUMN_TITLE_TYPE_KEY =
|
||||
new LocTextKey("sebserver.finished.exam.list.column.type");
|
||||
private final static LocTextKey EMPTY_LIST_TEXT_KEY =
|
||||
new LocTextKey("sebserver.finished.exam.list.empty");
|
||||
|
||||
private final TableFilterAttribute nameFilter =
|
||||
new TableFilterAttribute(CriteriaType.TEXT, QuizData.FILTER_ATTR_NAME);
|
||||
private final TableFilterAttribute typeFilter;
|
||||
|
||||
private final PageService pageService;
|
||||
private final ResourceService resourceService;
|
||||
private final int pageSize;
|
||||
|
||||
protected FinishedExamList(
|
||||
final PageService pageService,
|
||||
@Value("${sebserver.gui.list.page.size:20}") final Integer pageSize) {
|
||||
|
||||
this.pageService = pageService;
|
||||
this.resourceService = pageService.getResourceService();
|
||||
this.pageSize = pageSize;
|
||||
|
||||
this.typeFilter = new TableFilterAttribute(
|
||||
CriteriaType.SINGLE_SELECTION,
|
||||
Exam.FILTER_ATTR_TYPE,
|
||||
this.resourceService::examTypeResources);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void compose(final PageContext pageContext) {
|
||||
final WidgetFactory widgetFactory = this.pageService.getWidgetFactory();
|
||||
final CurrentUser currentUser = this.resourceService.getCurrentUser();
|
||||
final RestService restService = this.resourceService.getRestService();
|
||||
final I18nSupport i18nSupport = this.resourceService.getI18nSupport();
|
||||
|
||||
// content page layout with title
|
||||
final Composite content = widgetFactory.defaultPageLayout(
|
||||
pageContext.getParent(),
|
||||
PAGE_TITLE_KEY);
|
||||
|
||||
final PageActionBuilder actionBuilder = this.pageService
|
||||
.pageActionBuilder(pageContext.clearEntityKeys());
|
||||
|
||||
// table
|
||||
final EntityTable<Exam> table =
|
||||
this.pageService.entityTableBuilder(restService.getRestCall(GetFinishedExamPage.class))
|
||||
.withEmptyMessage(EMPTY_LIST_TEXT_KEY)
|
||||
.withPaging(this.pageSize)
|
||||
.withRowDecorator(ExamList.decorateOnExamConsistency(this.pageService))
|
||||
.withDefaultSort(QuizData.QUIZ_ATTR_NAME)
|
||||
|
||||
.withColumn(new ColumnDefinition<>(
|
||||
QuizData.QUIZ_ATTR_NAME,
|
||||
COLUMN_TITLE_NAME_KEY,
|
||||
Exam::getName)
|
||||
.withFilter(this.nameFilter)
|
||||
.sortable())
|
||||
|
||||
.withColumn(new ColumnDefinition<Exam>(
|
||||
Domain.EXAM.ATTR_TYPE,
|
||||
COLUMN_TITLE_TYPE_KEY,
|
||||
this.resourceService::localizedExamTypeName)
|
||||
.withFilter(this.typeFilter)
|
||||
.sortable())
|
||||
|
||||
.withColumn(new ColumnDefinition<>(
|
||||
QuizData.QUIZ_ATTR_START_TIME,
|
||||
new LocTextKey(
|
||||
"sebserver.finished.exam.list.column.startTime",
|
||||
i18nSupport.getUsersTimeZoneTitleSuffix()),
|
||||
Exam::getStartTime)
|
||||
.sortable())
|
||||
|
||||
.withColumn(new ColumnDefinition<>(
|
||||
QuizData.QUIZ_ATTR_END_TIME,
|
||||
new LocTextKey(
|
||||
"sebserver.finished.exam.list.column.endTime",
|
||||
i18nSupport.getUsersTimeZoneTitleSuffix()),
|
||||
Exam::getEndTime)
|
||||
.sortable())
|
||||
|
||||
.withDefaultAction(actionBuilder
|
||||
.newAction(ActionDefinition.VIEW_EXAM_FROM_FINISHED_LIST)
|
||||
.create())
|
||||
|
||||
.withSelectionListener(this.pageService.getSelectionPublisher(
|
||||
pageContext,
|
||||
ActionDefinition.VIEW_EXAM_FROM_FINISHED_LIST))
|
||||
|
||||
.compose(pageContext.copyOf(content));
|
||||
|
||||
actionBuilder
|
||||
|
||||
.newAction(ActionDefinition.VIEW_EXAM_FROM_FINISHED_LIST)
|
||||
.withSelect(table::getSelection, PageAction::applySingleSelectionAsEntityKey, EMPTY_SELECTION_TEXT_KEY)
|
||||
.publishIf(() -> currentUser.get().hasRole(UserRole.EXAM_SUPPORTER), false);
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -98,7 +98,7 @@ public class MonitoringRunningExam implements TemplateComposer {
|
|||
private final boolean distributedSetup;
|
||||
private final long pollInterval;
|
||||
|
||||
protected MonitoringRunningExam(
|
||||
public MonitoringRunningExam(
|
||||
final ServerPushService serverPushService,
|
||||
final PageService pageService,
|
||||
final AsyncRunner asyncRunner,
|
||||
|
@ -122,10 +122,9 @@ public class MonitoringRunningExam implements TemplateComposer {
|
|||
|
||||
@Override
|
||||
public void compose(final PageContext pageContext) {
|
||||
final RestService restService = this.resourceService.getRestService();
|
||||
final EntityKey entityKey = pageContext.getEntityKey();
|
||||
final CurrentUser currentUser = this.resourceService.getCurrentUser();
|
||||
final Exam exam = restService.getBuilder(GetExam.class)
|
||||
final Exam exam = this.restService.getBuilder(GetExam.class)
|
||||
.withURIVariable(API.PARAM_MODEL_ID, entityKey.modelId)
|
||||
.call()
|
||||
.getOrThrow();
|
||||
|
@ -134,7 +133,7 @@ public class MonitoringRunningExam implements TemplateComposer {
|
|||
exam.supporter.contains(user.uuid);
|
||||
final BooleanSupplier isExamSupporter = () -> supporting || user.hasRole(UserRole.EXAM_ADMIN);
|
||||
|
||||
final Collection<Indicator> indicators = restService.getBuilder(GetIndicators.class)
|
||||
final Collection<Indicator> indicators = this.restService.getBuilder(GetIndicators.class)
|
||||
.withQueryParam(Indicator.FILTER_ATTR_EXAM_ID, entityKey.modelId)
|
||||
.call()
|
||||
.getOrThrow();
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* Copyright (c) 2022 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.gui.service.remote.webservice.api.session;
|
||||
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.api.API;
|
||||
import ch.ethz.seb.sebserver.gbl.api.EntityType;
|
||||
import ch.ethz.seb.sebserver.gbl.model.Page;
|
||||
import ch.ethz.seb.sebserver.gbl.model.exam.Exam;
|
||||
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall;
|
||||
|
||||
@Lazy
|
||||
@Component
|
||||
@GuiProfile
|
||||
public class GetFinishedExamPage extends RestCall<Page<Exam>> {
|
||||
|
||||
public GetFinishedExamPage() {
|
||||
super(new TypeKey<>(
|
||||
CallType.GET_PAGE,
|
||||
EntityType.EXAM,
|
||||
new TypeReference<Page<Exam>>() {
|
||||
}),
|
||||
HttpMethod.GET,
|
||||
MediaType.APPLICATION_FORM_URLENCODED,
|
||||
API.EXAM_MONITORING_ENDPOINT + API.EXAM_MONITORING_FINISHED_ENDPOINT);
|
||||
}
|
||||
|
||||
}
|
|
@ -134,6 +134,15 @@ public interface ExamSessionService {
|
|||
FilterMap filterMap,
|
||||
Predicate<Exam> predicate);
|
||||
|
||||
/** Gets all finished Exams for a particular FilterMap.
|
||||
*
|
||||
* @param filterMap the FilterMap containing the filter attributes
|
||||
* @param predicate additional filter predicate
|
||||
* @return Result referencing the list of all currently finished Exams or to an error if happened. */
|
||||
Result<Collection<Exam>> getFilteredFinishedExams(
|
||||
FilterMap filterMap,
|
||||
Predicate<Exam> predicate);
|
||||
|
||||
/** Streams the default SEB Exam Configuration to a ClientConnection with given connectionToken.
|
||||
*
|
||||
* @param institutionId the Institution identifier
|
||||
|
|
|
@ -254,6 +254,15 @@ public class ExamSessionServiceImpl implements ExamSessionService {
|
|||
.collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<Collection<Exam>> getFilteredFinishedExams(
|
||||
final FilterMap filterMap,
|
||||
final Predicate<Exam> predicate) {
|
||||
|
||||
filterMap.putIfAbsent(Exam.FILTER_ATTR_STATUS, ExamStatus.FINISHED.name());
|
||||
return this.examDAO.allMatching(filterMap, predicate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void streamDefaultExamConfig(
|
||||
final Long institutionId,
|
||||
|
|
|
@ -174,6 +174,67 @@ public class ExamMonitoringController {
|
|||
ExamAdministrationController.pageSort(sort));
|
||||
}
|
||||
|
||||
/** Get a page of all currently finished exams
|
||||
*
|
||||
* GET /{api}/{entity-type-endpoint-name}
|
||||
*
|
||||
* GET /admin-api/v1/monitoring
|
||||
* GET /admin-api/v1/monitoring?page_number=2&page_size=10&sort=-name
|
||||
* GET /admin-api/v1/monitoring?name=seb&active=true
|
||||
*
|
||||
* @param institutionId The institution identifier of the request.
|
||||
* Default is the institution identifier of the institution of the current user
|
||||
* @param pageNumber the number of the page that is requested
|
||||
* @param pageSize the size of the page that is requested
|
||||
* @param sort the sort parameter to sort the list of entities before paging
|
||||
* the sort parameter is the name of the entity-model attribute to sort with a leading '-' sign for
|
||||
* descending sort order
|
||||
* @param allRequestParams a MultiValueMap of all request parameter that is used for filtering
|
||||
* @return Page of domain-model-entities of specified type */
|
||||
@RequestMapping(
|
||||
path = API.EXAM_MONITORING_FINISHED_ENDPOINT,
|
||||
method = RequestMethod.GET,
|
||||
consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE,
|
||||
produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
public Page<Exam> getFinishedExamsPage(
|
||||
@RequestParam(
|
||||
name = API.PARAM_INSTITUTION_ID,
|
||||
required = true,
|
||||
defaultValue = UserService.USERS_INSTITUTION_AS_DEFAULT) final Long institutionId,
|
||||
@RequestParam(name = Page.ATTR_PAGE_NUMBER, required = false) final Integer pageNumber,
|
||||
@RequestParam(name = Page.ATTR_PAGE_SIZE, required = false) final Integer pageSize,
|
||||
@RequestParam(name = Page.ATTR_SORT, required = false) final String sort,
|
||||
@RequestParam final MultiValueMap<String, String> allRequestParams,
|
||||
final HttpServletRequest request) {
|
||||
|
||||
this.authorization.checkRole(
|
||||
institutionId,
|
||||
EntityType.EXAM,
|
||||
UserRole.EXAM_SUPPORTER,
|
||||
UserRole.EXAM_ADMIN);
|
||||
|
||||
final FilterMap filterMap = new FilterMap(allRequestParams, request.getQueryString());
|
||||
|
||||
// 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));
|
||||
}
|
||||
|
||||
final Collection<Exam> exams = this.examSessionService
|
||||
.getFilteredFinishedExams(
|
||||
filterMap,
|
||||
exam -> this.hasRunningExamPrivilege(exam, institutionId))
|
||||
.getOrThrow();
|
||||
|
||||
return this.paginationService.buildPageFromList(
|
||||
pageNumber,
|
||||
pageSize,
|
||||
sort,
|
||||
exams,
|
||||
ExamAdministrationController.pageSort(sort));
|
||||
}
|
||||
|
||||
@RequestMapping(
|
||||
path = API.PARENT_MODEL_ID_VAR_PATH_SEGMENT,
|
||||
method = RequestMethod.GET,
|
||||
|
|
|
@ -1868,6 +1868,33 @@ sebserver.monitoring.exam.connection.status.CLOSED=Closed
|
|||
sebserver.monitoring.exam.connection.status.ABORTED=Aborted
|
||||
sebserver.monitoring.exam.connection.status.DISABLED=Canceled
|
||||
|
||||
################################
|
||||
# Finished Exams
|
||||
################################
|
||||
sebserver.finished.action.list=Finished Exams
|
||||
sebserver.finished.exam.list.title=Finished Exams
|
||||
sebserver.finished.exam.list.actions=
|
||||
|
||||
sebserver.finished.exam.info.pleaseSelect=At first please select an Exam from the list
|
||||
sebserver.finished.exam.list.empty=There are currently no finished exams
|
||||
|
||||
sebserver.finished.exam.list.column.name=Name
|
||||
sebserver.finished.exam.list.column.name.tooltip=The name of the exam<br/><br/>Use the filter above to narrow down to a specific exam name<br/>{0}
|
||||
sebserver.finished.exam.list.column.type=Type
|
||||
sebserver.finished.exam.list.column.type.tooltip=The type of the exam<br/><br/>Use the filter above to set a specific exam type<br/>{0}
|
||||
sebserver.finished.exam.list.column.startTime=Start Time {0}
|
||||
sebserver.finished.exam.list.column.startTime.tooltip=The start date and time of the exam<br/><br/>{0}
|
||||
sebserver.finished.exam.list.column.endTime=End Time {0}
|
||||
sebserver.finished.exam.list.column.endTime.tooltip=The end date and time of the exam<br/><br/>{0}
|
||||
sebserver.finished.exam.action.list.view=View Finished Exam
|
||||
|
||||
sebserver.finished.exam.connections.title=Search Connections
|
||||
sebserver.finished.exam.connections.action=Search
|
||||
sebserver.finished.exam.connections.empty=No Client Connections available
|
||||
sebserver.finished.exam.connections.name=Session or User Name
|
||||
sebserver.finished.exam.connections.info=Connection Info
|
||||
sebserver.finished.exam.connections.status=Status
|
||||
|
||||
################################
|
||||
# Logs
|
||||
################################
|
||||
|
|
Loading…
Reference in a new issue