SEBSERV-240 implementation

This commit is contained in:
anhefti 2022-03-24 08:24:03 +01:00
parent ebbbf56314
commit 5b3648bcee
12 changed files with 389 additions and 44 deletions

View file

@ -32,7 +32,7 @@ public interface IndicatorValue extends IndicatorValueHolder {
return Constants.EMPTY_NOTE;
}
if (type.integerValue) {
return String.valueOf((int) indicatorValue.getValue());
return String.valueOf((long) indicatorValue.getValue());
} else {
return String.valueOf(indicatorValue.getValue());
}

View file

@ -835,11 +835,21 @@ public enum ActionDefinition {
FINISHED_EXAM_VIEW_LIST(
new LocTextKey("sebserver.finished.action.list"),
PageStateDefinitionImpl.FINISHED_EXAM_LIST),
VIEW_EXAM_FROM_FINISHED_LIST(
VIEW_FINISHED_EXAM_FROM_LIST(
new LocTextKey("sebserver.finished.exam.action.list.view"),
ImageIcon.SHOW,
PageStateDefinitionImpl.FINISHED_EXAM,
ActionCategory.FINISHED_EXAM_LIST),
VIEW_FINISHED_EXAM_CLIENT_CONNECTION(
new LocTextKey("sebserver.finished.exam.connection.action.view"),
ImageIcon.SHOW,
PageStateDefinitionImpl.FINISHED_CLIENT_CONNECTION,
ActionCategory.CLIENT_EVENT_LIST),
FINISHED_EXAM_BACK_TO_OVERVIEW(
new LocTextKey("sebserver.finished.exam.action.detail.view"),
ImageIcon.SHOW,
PageStateDefinitionImpl.FINISHED_EXAM,
ActionCategory.FORM),
LOGS_USER_ACTIVITY_LIST(
new LocTextKey("sebserver.logs.activity.userlogs"),

View file

@ -34,6 +34,7 @@ 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.FinishedExamClientConnection;
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;
@ -100,7 +101,7 @@ public enum PageStateDefinitionImpl implements PageStateDefinition {
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),
FINISHED_CLIENT_CONNECTION(Type.FORM_VIEW, FinishedExamClientConnection.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)

View file

@ -244,10 +244,9 @@ public class ExamForm implements TemplateComposer {
final boolean modifyGrant = userGrantCheck.m();
final boolean writeGrant = userGrantCheck.w();
final ExamStatus examStatus = exam.getStatus();
final boolean editable = modifyGrant && (examStatus == ExamStatus.UP_COMING ||
examStatus == ExamStatus.RUNNING);
final boolean editable = modifyGrant &&
(examStatus == ExamStatus.UP_COMING || examStatus == ExamStatus.RUNNING);
// TODO this is not performat try to improve by doing one check with the CheckExamConsistency above
final boolean sebRestrictionAvailable = testSEBRestrictionAPI(exam);
final boolean isRestricted = readonly && sebRestrictionAvailable && this.restService
.getBuilder(CheckSEBRestriction.class)
@ -408,6 +407,11 @@ public class ExamForm implements TemplateComposer {
.withEntityKey(entityKey)
.publishIf(() -> modifyGrant && readonly && editable)
.newAction(ActionDefinition.EXAM_DELETE)
.withEntityKey(entityKey)
.withExec(this.examDeletePopup.deleteWizardFunction(pageContext))
.publishIf(() -> writeGrant && readonly)
.newAction(ActionDefinition.EXAM_SAVE)
.withExec(action -> (importFromQuizData)
? importExam(action, formHandle, sebRestrictionAvailable && exam.status == ExamStatus.RUNNING)
@ -451,20 +455,15 @@ public class ExamForm implements TemplateComposer {
.newAction(ActionDefinition.EXAM_PROCTORING_ON)
.withEntityKey(entityKey)
.withExec(this.examProctoringSettings.settingsFunction(this.pageService, modifyGrant))
.withExec(this.examProctoringSettings.settingsFunction(this.pageService, modifyGrant && editable))
.noEventPropagation()
.publishIf(() -> editable && proctoringEnabled && readonly)
.publishIf(() -> proctoringEnabled && readonly)
.newAction(ActionDefinition.EXAM_PROCTORING_OFF)
.withEntityKey(entityKey)
.withExec(this.examProctoringSettings.settingsFunction(this.pageService, modifyGrant))
.withExec(this.examProctoringSettings.settingsFunction(this.pageService, modifyGrant && editable))
.noEventPropagation()
.publishIf(() -> editable && !proctoringEnabled && readonly)
.newAction(ActionDefinition.EXAM_DELETE)
.withEntityKey(entityKey)
.withExec(this.examDeletePopup.deleteWizardFunction(pageContext))
.publishIf(() -> writeGrant && readonly);
.publishIf(() -> !proctoringEnabled && readonly);
// additional data in read-only view
if (readonly && !importFromQuizData) {

View file

@ -9,6 +9,7 @@
package ch.ethz.seb.sebserver.gui.content.monitoring;
import java.util.Collection;
import java.util.function.BooleanSupplier;
import java.util.function.Function;
import org.eclipse.swt.widgets.Composite;
@ -17,26 +18,34 @@ 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.EntityKey;
import ch.ethz.seb.sebserver.gbl.model.exam.Exam;
import ch.ethz.seb.sebserver.gbl.model.exam.Indicator;
import ch.ethz.seb.sebserver.gbl.model.exam.Indicator.IndicatorType;
import ch.ethz.seb.sebserver.gbl.model.session.ClientConnection;
import ch.ethz.seb.sebserver.gbl.model.session.ClientConnectionData;
import ch.ethz.seb.sebserver.gbl.model.session.IndicatorValue;
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.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.page.impl.PageAction;
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.GetExam;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.GetIndicators;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.session.GetFinishedExamClientConnectionPage;
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.TableBuilder;
import ch.ethz.seb.sebserver.gui.table.TableFilter.CriteriaType;
@ -45,6 +54,8 @@ import ch.ethz.seb.sebserver.gui.table.TableFilter.CriteriaType;
@GuiProfile
public class FinishedExam implements TemplateComposer {
private static final LocTextKey EMPTY_SELECTION_TEXT_KEY =
new LocTextKey("sebserver.finished.exam.connection.emptySelection");
private static final LocTextKey TITLE_TEXT_KEY =
new LocTextKey("sebserver.finished.exam.connections.title");
private static final LocTextKey EMPTY_LIST_TEXT_KEY =
@ -64,7 +75,6 @@ public class FinishedExam implements TemplateComposer {
private final PageService pageService;
private final RestService restService;
private final ResourceService resourceService;
private final int pageSize;
public FinishedExam(
@ -74,7 +84,6 @@ public class FinishedExam implements TemplateComposer {
this.pageService = pageService;
this.restService = pageService.getRestService();
this.resourceService = pageService.getResourceService();
this.pageSize = pageSize;
this.statusFilter = new TableFilterAttribute(
@ -86,19 +95,29 @@ public class FinishedExam implements TemplateComposer {
@Override
public void compose(final PageContext pageContext) {
final EntityKey examKey = pageContext.getEntityKey();
final CurrentUser currentUser = this.pageService.getResourceService().getCurrentUser();
final UserInfo user = currentUser.get();
final RestService restService = this.pageService.getRestService();
final RestService restService = this.pageService
.getRestService();
final PageActionBuilder actionBuilder = this.pageService
.pageActionBuilder(pageContext.clearEntityKeys());
final Collection<Indicator> indicators = restService.getBuilder(GetIndicators.class)
final Collection<Indicator> indicators = restService
.getBuilder(GetIndicators.class)
.withQueryParam(Indicator.FILTER_ATTR_EXAM_ID, examKey.modelId)
.call()
.getOrThrow();
final Exam exam = this.restService.getBuilder(GetExam.class)
.withURIVariable(API.PARAM_MODEL_ID, examKey.modelId)
.call()
.getOrThrow();
final boolean supporting = user.hasRole(UserRole.EXAM_SUPPORTER) &&
exam.supporter.contains(user.uuid);
final BooleanSupplier isExamSupporter = () -> supporting || user.hasRole(UserRole.EXAM_ADMIN);
final Composite content = this.pageService.getWidgetFactory().defaultPageLayout(
pageContext.getParent(),
TITLE_TEXT_KEY);
new LocTextKey(TITLE_TEXT_KEY.name, exam.getName()));
final TableBuilder<ClientConnectionData> tableBuilder =
this.pageService.entityTableBuilder(restService.getRestCall(GetFinishedExamClientConnectionPage.class))
@ -126,21 +145,30 @@ public class FinishedExam implements TemplateComposer {
.withFilter(this.statusFilter))
.withDefaultAction(t -> actionBuilder
.newAction(ActionDefinition.MONITOR_EXAM_CLIENT_CONNECTION)
.newAction(ActionDefinition.VIEW_FINISHED_EXAM_CLIENT_CONNECTION)
.withParentEntityKey(examKey)
.create());
indicators.stream().forEach(indicator -> {
tableBuilder.withColumn(new ColumnDefinition<>(
indicator.name,
new LocTextKey(indicator.name),
indicatorValueFunction(indicator)));
if (indicator.type != IndicatorType.LAST_PING) {
tableBuilder.withColumn(new ColumnDefinition<>(
indicator.name,
new LocTextKey(indicator.name),
indicatorValueFunction(indicator)));
}
});
tableBuilder.compose(pageContext.copyOf(content));
final EntityTable<ClientConnectionData> table = tableBuilder.compose(pageContext.copyOf(content));
actionBuilder
.newAction(ActionDefinition.VIEW_FINISHED_EXAM_CLIENT_CONNECTION)
.withParentEntityKey(examKey)
.withSelect(table::getSelection, PageAction::applySingleSelectionAsEntityKey, EMPTY_SELECTION_TEXT_KEY)
.publishIf(isExamSupporter, false);
}
private Function<ClientConnectionData, String> indicatorValueFunction(final Indicator indicator) {
public Function<ClientConnectionData, String> indicatorValueFunction(final Indicator indicator) {
return clientConnectionData -> {
return clientConnectionData.indicatorValues
.stream()

View file

@ -0,0 +1,283 @@
/*
* 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 java.util.function.BooleanSupplier;
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.api.EntityType;
import ch.ethz.seb.sebserver.gbl.model.Domain;
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
import ch.ethz.seb.sebserver.gbl.model.exam.Exam;
import ch.ethz.seb.sebserver.gbl.model.exam.Indicator;
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.ClientConnectionData;
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.session.IndicatorValue;
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;
import ch.ethz.seb.sebserver.gui.form.FormBuilder;
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.TemplateComposer;
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.exam.GetIndicators;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.logs.GetExtendedClientEventPage;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.session.GetFinishedExamClientConnection;
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.TableFilter.CriteriaType;
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
@Lazy
@Component
@GuiProfile
public class FinishedExamClientConnection implements TemplateComposer {
private static final LocTextKey PAGE_TITLE_KEY =
new LocTextKey("sebserver.finished.exam.connection.title");
private final static LocTextKey EXAM_NAME_TEXT_KEY =
new LocTextKey("sebserver.finished.connection.form.exam");
private final static LocTextKey CONNECTION_ID_TEXT_KEY =
new LocTextKey("sebserver.finished.connection.form.id");
private final static LocTextKey CONNECTION_INFO_TEXT_KEY =
new LocTextKey("sebserver.finished.connection.form.info");
private final static LocTextKey CONNECTION_STATUS_TEXT_KEY =
new LocTextKey("sebserver.finished.connection.form.status");
private static final LocTextKey EVENT_LIST_TITLE_KEY =
new LocTextKey("sebserver.finished.exam.connection.eventlist.title");
private static final LocTextKey EVENT_LIST_TITLE_TOOLTIP_KEY =
new LocTextKey("sebserver.finished.exam.connection.eventlist.title.tooltip");
private static final LocTextKey EMPTY_LIST_TEXT_KEY =
new LocTextKey("sebserver.finished.exam.connection.eventlist.empty");
private static final LocTextKey LIST_COLUMN_TYPE_KEY =
new LocTextKey("sebserver.finished.exam.connection.eventlist.type");
private static final LocTextKey LIST_COLUMN_CLIENT_TIME_KEY =
new LocTextKey("sebserver.finished.exam.connection.eventlist.clienttime");
private static final LocTextKey LIST_COLUMN_SERVER_TIME_KEY =
new LocTextKey("sebserver.finished.exam.connection.eventlist.servertime");
private static final LocTextKey LIST_COLUMN_VALUE_KEY =
new LocTextKey("sebserver.finished.exam.connection.eventlist.value");
private static final LocTextKey LIST_COLUMN_TEXT_KEY =
new LocTextKey("sebserver.finished.exam.connection.eventlist.text");
private final PageService pageService;
private final ResourceService resourceService;
private final I18nSupport i18nSupport;
private final SEBClientEventDetailsPopup sebClientLogDetailsPopup;
private final int pageSize;
private final TableFilterAttribute typeFilter;
private final TableFilterAttribute textFilter =
new TableFilterAttribute(CriteriaType.TEXT, ClientEvent.FILTER_ATTR_TEXT);
protected FinishedExamClientConnection(
final PageService pageService,
final SEBClientEventDetailsPopup sebClientLogDetailsPopup,
@Value("${sebserver.gui.list.page.size:20}") final Integer pageSize) {
this.pageService = pageService;
this.resourceService = pageService.getResourceService();
this.i18nSupport = this.resourceService.getI18nSupport();
this.sebClientLogDetailsPopup = sebClientLogDetailsPopup;
this.pageSize = pageSize;
this.typeFilter = new TableFilterAttribute(
CriteriaType.SINGLE_SELECTION,
Domain.CLIENT_EVENT.ATTR_TYPE,
this.resourceService::clientEventTypeResources);
}
@Override
public void compose(final PageContext pageContext) {
final RestService restService = this.resourceService.getRestService();
final WidgetFactory widgetFactory = this.pageService.getWidgetFactory();
final CurrentUser currentUser = this.resourceService.getCurrentUser();
final EntityKey parentEntityKey = pageContext.getParentEntityKey();
final EntityKey entityKey = pageContext.getEntityKey();
// content page layout with title
final Composite content = widgetFactory.defaultPageLayout(
pageContext.getParent(),
PAGE_TITLE_KEY);
final Exam exam = restService
.getBuilder(GetExam.class)
.withURIVariable(API.PARAM_MODEL_ID, parentEntityKey.modelId)
.call()
.onError(error -> pageContext.notifyLoadError(EntityType.EXAM, error))
.getOrThrow();
final UserInfo user = currentUser.get();
final boolean supporting = user.hasRole(UserRole.EXAM_SUPPORTER) &&
exam.supporter.contains(user.uuid);
final BooleanSupplier isExamSupporter = () -> supporting || user.hasRole(UserRole.EXAM_ADMIN);
final Collection<Indicator> indicators = restService
.getBuilder(GetIndicators.class)
.withQueryParam(Indicator.FILTER_ATTR_EXAM_ID, parentEntityKey.modelId)
.call()
.getOrThrow();
final ClientConnectionData connectionData = restService
.getBuilder(GetFinishedExamClientConnection.class)
.withURIVariable(API.PARAM_MODEL_ID, entityKey.modelId)
.call()
.getOrThrow();
final FormBuilder formBuilder = this.pageService.formBuilder(pageContext.copyOf(content))
.readonly(true)
.addField(FormBuilder.text(
QuizData.QUIZ_ATTR_NAME,
EXAM_NAME_TEXT_KEY,
exam.getName()))
.addField(FormBuilder.text(
Domain.CLIENT_CONNECTION.ATTR_EXAM_USER_SESSION_ID,
CONNECTION_ID_TEXT_KEY,
connectionData.clientConnection.userSessionId))
.addField(FormBuilder.text(
ClientConnection.ATTR_INFO,
CONNECTION_INFO_TEXT_KEY,
connectionData.clientConnection.info))
.withDefaultSpanInput(3)
.addField(FormBuilder.text(
Domain.CLIENT_CONNECTION.ATTR_STATUS,
CONNECTION_STATUS_TEXT_KEY,
this.resourceService.localizedClientConnectionStatusName(
connectionData.clientConnection.status))
.asColorBox())
.addEmptyCell();
indicators.forEach(indicator -> formBuilder.addField(FormBuilder.text(
indicator.name,
new LocTextKey(indicator.name),
connectionData.indicatorValues
.stream()
.filter(indicatorValue -> indicatorValue.getIndicatorId().equals(indicator.id))
.findFirst()
.map(iv -> IndicatorValue.getDisplayValue(iv, indicator.type))
.orElse(Constants.EMPTY_NOTE))
.asColorBox()
.withDefaultLabel(indicator.name))
.addEmptyCell());
formBuilder.build();
// CLIENT EVENTS
final PageService.PageActionBuilder actionBuilder = this.pageService
.pageActionBuilder(
pageContext
.clearAttributes()
.clearEntityKeys());
widgetFactory.addFormSubContextHeader(
content,
EVENT_LIST_TITLE_KEY,
EVENT_LIST_TITLE_TOOLTIP_KEY);
// client event table for this connection
this.pageService
.entityTableBuilder(
"seb-client-" + connectionData.getModelId(),
restService.getRestCall(GetExtendedClientEventPage.class))
.withEmptyMessage(EMPTY_LIST_TEXT_KEY)
.withPaging(this.pageSize)
.withRestCallAdapter(restCallBuilder -> restCallBuilder.withQueryParam(
ClientEvent.FILTER_ATTR_CONNECTION_ID,
entityKey.modelId))
.withColumn(new ColumnDefinition<ExtendedClientEvent>(
Domain.CLIENT_EVENT.ATTR_TYPE,
LIST_COLUMN_TYPE_KEY,
this.resourceService::getEventTypeName)
.withFilter(this.typeFilter)
.sortable()
.widthProportion(2))
.withColumn(new ColumnDefinition<ExtendedClientEvent>(
Domain.CLIENT_EVENT.ATTR_TEXT,
LIST_COLUMN_TEXT_KEY,
ClientEvent::getText)
.withFilter(this.textFilter)
.sortable()
.withCellTooltip()
.widthProportion(4))
.withColumn(new ColumnDefinition<ExtendedClientEvent>(
Domain.CLIENT_EVENT.ATTR_NUMERIC_VALUE,
LIST_COLUMN_VALUE_KEY,
ClientEvent::getValue)
.widthProportion(1))
.withColumn(new ColumnDefinition<ExtendedClientEvent>(
Domain.CLIENT_EVENT.ATTR_CLIENT_TIME,
new LocTextKey(LIST_COLUMN_CLIENT_TIME_KEY.name,
this.i18nSupport.getUsersTimeZoneTitleSuffix()),
this::getClientTime)
.sortable()
.widthProportion(1))
.withColumn(new ColumnDefinition<ExtendedClientEvent>(
Domain.CLIENT_EVENT.ATTR_SERVER_TIME,
new LocTextKey(LIST_COLUMN_SERVER_TIME_KEY.name,
this.i18nSupport.getUsersTimeZoneTitleSuffix()),
this::getServerTime)
.sortable()
.widthProportion(1))
.withDefaultAction(t -> actionBuilder
.newAction(ActionDefinition.LOGS_SEB_CLIENT_SHOW_DETAILS)
.withExec(action -> this.sebClientLogDetailsPopup.showDetails(action,
t.getSingleSelectedROWData()))
.noEventPropagation()
.create())
.compose(pageContext.copyOf(content));
actionBuilder
.newAction(ActionDefinition.FINISHED_EXAM_BACK_TO_OVERVIEW)
.withEntityKey(parentEntityKey)
.publishIf(isExamSupporter);
}
private String getClientTime(final ClientEvent event) {
if (event == null || event.getClientTime() == null) {
return Constants.EMPTY_NOTE;
}
return this.i18nSupport
.formatDisplayTime(Utils.toDateTimeUTC(event.getClientTime()));
}
private String getServerTime(final ClientEvent event) {
if (event == null || event.getServerTime() == null) {
return Constants.EMPTY_NOTE;
}
return this.i18nSupport
.formatDisplayTime(Utils.toDateTimeUTC(event.getServerTime()));
}
}

View file

@ -129,18 +129,18 @@ public class FinishedExamList implements TemplateComposer {
.sortable())
.withDefaultAction(actionBuilder
.newAction(ActionDefinition.VIEW_EXAM_FROM_FINISHED_LIST)
.newAction(ActionDefinition.VIEW_FINISHED_EXAM_FROM_LIST)
.create())
.withSelectionListener(this.pageService.getSelectionPublisher(
pageContext,
ActionDefinition.VIEW_EXAM_FROM_FINISHED_LIST))
ActionDefinition.VIEW_FINISHED_EXAM_FROM_LIST))
.compose(pageContext.copyOf(content));
actionBuilder
.newAction(ActionDefinition.VIEW_EXAM_FROM_FINISHED_LIST)
.newAction(ActionDefinition.VIEW_FINISHED_EXAM_FROM_LIST)
.withSelect(table::getSelection, PageAction::applySingleSelectionAsEntityKey, EMPTY_SELECTION_TEXT_KEY)
.publishIf(() -> currentUser.get().hasRole(UserRole.EXAM_SUPPORTER), false);

View file

@ -90,6 +90,11 @@ public class MonitoringClientConnection implements TemplateComposer {
private static final LocTextKey NOTIFICATION_LIST_COLUMN_TYPE_KEY =
new LocTextKey("sebserver.monitoring.exam.connection.notificationlist.type");
private static final LocTextKey CONFIRM_QUIT =
new LocTextKey("sebserver.monitoring.exam.connection.action.instruction.quit.confirm");
private static final LocTextKey CONFIRM_OPEN_SINGLE_ROOM =
new LocTextKey("sebserver.monitoring.exam.connection.action.singleroom.confirm");
private static final LocTextKey EVENT_LIST_TITLE_KEY =
new LocTextKey("sebserver.monitoring.exam.connection.eventlist.title");
private static final LocTextKey EVENT_LIST_TITLE_TOOLTIP_KEY =
@ -107,10 +112,6 @@ public class MonitoringClientConnection implements TemplateComposer {
new LocTextKey("sebserver.monitoring.exam.connection.eventlist.value");
private static final LocTextKey LIST_COLUMN_TEXT_KEY =
new LocTextKey("sebserver.monitoring.exam.connection.eventlist.text");
private static final LocTextKey CONFIRM_QUIT =
new LocTextKey("sebserver.monitoring.exam.connection.action.instruction.quit.confirm");
private static final LocTextKey CONFIRM_OPEN_SINGLE_ROOM =
new LocTextKey("sebserver.monitoring.exam.connection.action.singleroom.confirm");
private final ServerPushService serverPushService;
private final PageService pageService;

View file

@ -70,8 +70,6 @@ import ch.ethz.seb.sebserver.gui.service.session.proctoring.ProctoringGUIService
@GuiProfile
public class MonitoringRunningExam implements TemplateComposer {
//private static final Logger log = LoggerFactory.getLogger(MonitoringRunningExam.class);
private static final LocTextKey EMPTY_SELECTION_TEXT_KEY =
new LocTextKey("sebserver.monitoring.exam.connection.emptySelection");
private static final LocTextKey EMPTY_ACTIVE_SELECTION_TEXT_KEY =

View file

@ -55,8 +55,8 @@ public abstract class AbstractLogLevelCountIndicator extends AbstractLogIndicato
@Override
public double computeValueAt(final long timestamp) {
if (log.isDebugEnabled()) {
log.debug("computeValueAt: {}", timestamp);
if (log.isTraceEnabled()) {
log.trace("computeValueAt: {}", timestamp);
}
try {

View file

@ -73,8 +73,8 @@ public abstract class AbstractLogNumberIndicator extends AbstractLogIndicator {
@Override
public double computeValueAt(final long timestamp) {
if (log.isDebugEnabled()) {
log.debug("computeValueAt: {}", timestamp);
if (log.isTraceEnabled()) {
log.trace("computeValueAt: {}", timestamp);
}
try {

View file

@ -1831,7 +1831,6 @@ sebserver.monitoring.exam.connection.notificationlist.pleaseSelect=At first plea
sebserver.monitoring.exam.connection.notificationlist.title=Pending Notification
sebserver.monitoring.exam.connection.notificationlist.title.tooltip=All pending notifications sent by the SEB Client
sebserver.monitoring.exam.connection.eventlist.title=Events
sebserver.monitoring.exam.connection.eventlist.title.tooltip=All events and logs sent by the SEB Client
sebserver.monitoring.exam.connection.eventlist.empty=No event found
@ -1888,12 +1887,38 @@ 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.title=Finished Exam ({0})
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
sebserver.finished.exam.connection.emptySelection=At first please select a Connection from the list
sebserver.finished.exam.connection.title=SEB Client Connection
sebserver.finished.connection.form.id=User Name or Session
sebserver.finished.connection.form.id.tooltip=The user session identifier or username sent by the SEB client after LMS login
sebserver.finished.connection.form.info=Connection Info
sebserver.finished.connection.form.info.tooltip=Format: IP Address,SEB Version, OSName
sebserver.finished.connection.form.status=Status
sebserver.finished.connection.form.status.tooltip=The current connection status
sebserver.finished.connection.form.exam=Exam
sebserver.finished.connection.form.exam.tooltip=The exam name
sebserver.finished.exam.connection.eventlist.title=Events
sebserver.finished.exam.connection.eventlist.title.tooltip=All events and logs sent by the SEB Client
sebserver.finished.exam.connection.eventlist.empty=No event found
sebserver.finished.exam.connection.eventlist.type=Event Type
sebserver.finished.exam.connection.eventlist.type.tooltip=The type of the log event<br/><br/>Use the filter above to set a specific event type<br/>{0}
sebserver.finished.exam.connection.eventlist.clienttime=Client Time {0}
sebserver.finished.exam.connection.eventlist.clienttime.tooltip=The time the SEB client has sent within the log event<br/><br/>{0}
sebserver.finished.exam.connection.eventlist.servertime=Server Time {0}
sebserver.finished.exam.connection.eventlist.servertime.tooltip=The exact time (UTC) the SEB Server has received the log event<br/><br/>{0}
sebserver.finished.exam.connection.eventlist.value=Value
sebserver.finished.exam.connection.eventlist.value.tooltip=The value of the log event<br/><br/>{0}
sebserver.finished.exam.connection.eventlist.text=Text
sebserver.finished.exam.connection.eventlist.text.tooltip=The text of the log event<br/><br/>{0}
sebserver.finished.exam.action.detail.view=Back To Exam
################################
# Logs