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_NOTIFICATION_ENDPOINT = "/notification";
 | 
				
			||||||
    public static final String EXAM_MONITORING_DISABLE_CONNECTION_ENDPOINT = "/disable-connection";
 | 
					    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_STATE_FILTER = "hidden-states";
 | 
				
			||||||
 | 
					    public static final String EXAM_MONITORING_FINISHED_ENDPOINT = "/finishedexams";
 | 
				
			||||||
    public static final String EXAM_MONITORING_SEB_CONNECTION_TOKEN_PATH_SEGMENT =
 | 
					    public static final String EXAM_MONITORING_SEB_CONNECTION_TOKEN_PATH_SEGMENT =
 | 
				
			||||||
            "/{" + EXAM_API_SEB_CONNECTION_TOKEN + "}";
 | 
					            "/{" + EXAM_API_SEB_CONNECTION_TOKEN + "}";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -35,7 +35,9 @@ public enum ActionCategory {
 | 
				
			||||||
    LOGS_SEB_CLIENT_LIST(new LocTextKey("sebserver.userlogs.list.actions"), 1),
 | 
					    LOGS_SEB_CLIENT_LIST(new LocTextKey("sebserver.userlogs.list.actions"), 1),
 | 
				
			||||||
    VARIA(new LocTextKey("sebserver.overall.action.category.varia"), 0),
 | 
					    VARIA(new LocTextKey("sebserver.overall.action.category.varia"), 0),
 | 
				
			||||||
    FILTER(new LocTextKey("sebserver.exam.monitoring.action.category.filter"), 50),
 | 
					    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 LocTextKey title;
 | 
				
			||||||
    public final int slotPosition;
 | 
					    public final int slotPosition;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -832,6 +832,15 @@ public enum ActionDefinition {
 | 
				
			||||||
            PageStateDefinitionImpl.MONITORING_RUNNING_EXAM,
 | 
					            PageStateDefinitionImpl.MONITORING_RUNNING_EXAM,
 | 
				
			||||||
            ActionCategory.PROCTORING),
 | 
					            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(
 | 
					    LOGS_USER_ACTIVITY_LIST(
 | 
				
			||||||
            new LocTextKey("sebserver.logs.activity.userlogs"),
 | 
					            new LocTextKey("sebserver.logs.activity.userlogs"),
 | 
				
			||||||
            PageStateDefinitionImpl.USER_ACTIVITY_LOGS),
 | 
					            PageStateDefinitionImpl.USER_ACTIVITY_LOGS),
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -339,14 +339,25 @@ public class ActivitiesPane implements TemplateComposer {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // Monitoring exams
 | 
					            // Monitoring exams
 | 
				
			||||||
            if (isSupporter) {
 | 
					            if (isSupporter) {
 | 
				
			||||||
                final TreeItem clientConfig = this.widgetFactory.treeItemLocalized(
 | 
					
 | 
				
			||||||
 | 
					                final TreeItem monitoringExams = this.widgetFactory.treeItemLocalized(
 | 
				
			||||||
                        monitoring,
 | 
					                        monitoring,
 | 
				
			||||||
                        ActivityDefinition.MONITORING_EXAMS.displayName);
 | 
					                        ActivityDefinition.MONITORING_EXAMS.displayName);
 | 
				
			||||||
                injectActivitySelection(
 | 
					                injectActivitySelection(
 | 
				
			||||||
                        clientConfig,
 | 
					                        monitoringExams,
 | 
				
			||||||
                        actionBuilder
 | 
					                        actionBuilder
 | 
				
			||||||
                                .newAction(ActionDefinition.RUNNING_EXAM_VIEW_LIST)
 | 
					                                .newAction(ActionDefinition.RUNNING_EXAM_VIEW_LIST)
 | 
				
			||||||
                                .create());
 | 
					                                .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
 | 
					            // SEB Client Logs
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -28,6 +28,7 @@ public enum ActivityDefinition implements Activity {
 | 
				
			||||||
    SEB_CERTIFICATE_MANAGEMENT(new LocTextKey("sebserver.certificate.action.list")),
 | 
					    SEB_CERTIFICATE_MANAGEMENT(new LocTextKey("sebserver.certificate.action.list")),
 | 
				
			||||||
    MONITORING(new LocTextKey("sebserver.overall.activity.title.monitoring")),
 | 
					    MONITORING(new LocTextKey("sebserver.overall.activity.title.monitoring")),
 | 
				
			||||||
    MONITORING_EXAMS(new LocTextKey("sebserver.monitoring.action.list")),
 | 
					    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"));
 | 
					    SEB_CLIENT_LOGS(new LocTextKey("sebserver.logs.activity.seblogs"));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public final LocTextKey displayName;
 | 
					    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.LmsSetupForm;
 | 
				
			||||||
import ch.ethz.seb.sebserver.gui.content.exam.LmsSetupList;
 | 
					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.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.MonitoringClientConnection;
 | 
				
			||||||
import ch.ethz.seb.sebserver.gui.content.monitoring.MonitoringRunningExam;
 | 
					import ch.ethz.seb.sebserver.gui.content.monitoring.MonitoringRunningExam;
 | 
				
			||||||
import ch.ethz.seb.sebserver.gui.content.monitoring.MonitoringRunningExamList;
 | 
					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_RUNNING_EXAM(Type.FORM_VIEW, MonitoringRunningExam.class, ActivityDefinition.MONITORING_EXAMS),
 | 
				
			||||||
    MONITORING_CLIENT_CONNECTION(Type.FORM_VIEW, MonitoringClientConnection.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),
 | 
					    USER_ACTIVITY_LOGS(Type.LIST_VIEW, UserActivityLogs.class, ActivityDefinition.USER_ACTIVITY_LOGS),
 | 
				
			||||||
    SEB_CLIENT_LOGS(Type.LIST_VIEW, SEBClientEvents.class, ActivityDefinition.SEB_CLIENT_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 boolean distributedSetup;
 | 
				
			||||||
    private final long pollInterval;
 | 
					    private final long pollInterval;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    protected MonitoringRunningExam(
 | 
					    public MonitoringRunningExam(
 | 
				
			||||||
            final ServerPushService serverPushService,
 | 
					            final ServerPushService serverPushService,
 | 
				
			||||||
            final PageService pageService,
 | 
					            final PageService pageService,
 | 
				
			||||||
            final AsyncRunner asyncRunner,
 | 
					            final AsyncRunner asyncRunner,
 | 
				
			||||||
| 
						 | 
					@ -122,10 +122,9 @@ public class MonitoringRunningExam implements TemplateComposer {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public void compose(final PageContext pageContext) {
 | 
					    public void compose(final PageContext pageContext) {
 | 
				
			||||||
        final RestService restService = this.resourceService.getRestService();
 | 
					 | 
				
			||||||
        final EntityKey entityKey = pageContext.getEntityKey();
 | 
					        final EntityKey entityKey = pageContext.getEntityKey();
 | 
				
			||||||
        final CurrentUser currentUser = this.resourceService.getCurrentUser();
 | 
					        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)
 | 
					                .withURIVariable(API.PARAM_MODEL_ID, entityKey.modelId)
 | 
				
			||||||
                .call()
 | 
					                .call()
 | 
				
			||||||
                .getOrThrow();
 | 
					                .getOrThrow();
 | 
				
			||||||
| 
						 | 
					@ -134,7 +133,7 @@ public class MonitoringRunningExam implements TemplateComposer {
 | 
				
			||||||
                exam.supporter.contains(user.uuid);
 | 
					                exam.supporter.contains(user.uuid);
 | 
				
			||||||
        final BooleanSupplier isExamSupporter = () -> supporting || user.hasRole(UserRole.EXAM_ADMIN);
 | 
					        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)
 | 
					                .withQueryParam(Indicator.FILTER_ATTR_EXAM_ID, entityKey.modelId)
 | 
				
			||||||
                .call()
 | 
					                .call()
 | 
				
			||||||
                .getOrThrow();
 | 
					                .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,
 | 
					            FilterMap filterMap,
 | 
				
			||||||
            Predicate<Exam> predicate);
 | 
					            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.
 | 
					    /** Streams the default SEB Exam Configuration to a ClientConnection with given connectionToken.
 | 
				
			||||||
     *
 | 
					     *
 | 
				
			||||||
     * @param institutionId the Institution identifier
 | 
					     * @param institutionId the Institution identifier
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -254,6 +254,15 @@ public class ExamSessionServiceImpl implements ExamSessionService {
 | 
				
			||||||
                        .collect(Collectors.toList()));
 | 
					                        .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
 | 
					    @Override
 | 
				
			||||||
    public void streamDefaultExamConfig(
 | 
					    public void streamDefaultExamConfig(
 | 
				
			||||||
            final Long institutionId,
 | 
					            final Long institutionId,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -174,6 +174,67 @@ public class ExamMonitoringController {
 | 
				
			||||||
                ExamAdministrationController.pageSort(sort));
 | 
					                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(
 | 
					    @RequestMapping(
 | 
				
			||||||
            path = API.PARENT_MODEL_ID_VAR_PATH_SEGMENT,
 | 
					            path = API.PARENT_MODEL_ID_VAR_PATH_SEGMENT,
 | 
				
			||||||
            method = RequestMethod.GET,
 | 
					            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.ABORTED=Aborted
 | 
				
			||||||
sebserver.monitoring.exam.connection.status.DISABLED=Canceled
 | 
					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
 | 
					# Logs
 | 
				
			||||||
################################
 | 
					################################
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		
		Reference in a new issue