Skip to content

Commit

Permalink
SEBSP-116 fixes and better group handling (TODOs for performance impr…
Browse files Browse the repository at this point in the history
…ovements)
  • Loading branch information
anhefti committed Nov 14, 2024
1 parent 02f8388 commit 7cfc327
Show file tree
Hide file tree
Showing 33 changed files with 580 additions and 387 deletions.
3 changes: 3 additions & 0 deletions src/main/java/ch/ethz/seb/sebserver/gbl/Constants.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@

/** Global Constants used in SEB Server web-service as well as in web-gui component */
public final class Constants {

public static final String UNICODE_LOWEST = Character.toString(0x00);
public static final String UNICODE_HIGHEST = Character.toString(0x10FFFF);

public static final String FILE_EXT_CSV = ".csv";

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import java.util.Objects;
import java.util.stream.Collectors;

import ch.ethz.seb.sebserver.gbl.util.Result;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.hibernate.validator.constraints.URL;
Expand All @@ -32,6 +33,7 @@
@ValidProctoringSettings
public class ProctoringServiceSettings implements Entity {


public enum ProctoringServerType {
JITSI_MEET,
ZOOM
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -233,4 +233,5 @@ public String toString() {
", bundled=" + bundled +
'}';
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/*
* Copyright (c) 2019 ETH Zürich, IT Services
*
* 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.gbl.model.session;

import ch.ethz.seb.sebserver.gbl.model.Domain;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;

@JsonIgnoreProperties(ignoreUnknown = true)
public record ProctoringGroupMonitoringData(
@JsonProperty(Domain.SCREEN_PROCTORING_GROUP.ATTR_UUID) String uuid,
@JsonProperty(Domain.SCREEN_PROCTORING_GROUP.ATTR_NAME) String name,
@JsonProperty(Domain.SCREEN_PROCTORING_GROUP.ATTR_SIZE) Integer size) {
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

package ch.ethz.seb.sebserver.gbl.monitoring;

import ch.ethz.seb.sebserver.gbl.Constants;
import ch.ethz.seb.sebserver.gbl.model.exam.ClientGroup;
import ch.ethz.seb.sebserver.gbl.model.exam.ClientGroupData;
import ch.ethz.seb.sebserver.gbl.model.session.ClientConnection;
Expand All @@ -33,7 +34,11 @@ public boolean isInGroup(final ClientConnection clientConnection, final ClientGr
final String start = group.nameRangeStartLetter != null ? group.nameRangeStartLetter.substring(0, 1) : "A";
final String end = group.nameRangeStartLetter != null ? group.nameRangeEndLetter.substring(0, 1) : "Z";

return isInRange(name, start, end);
}

public boolean isInRange(final String name, final String start, final String end) {
return name.compareToIgnoreCase(start) >= 0 &&
name.compareToIgnoreCase(end) <= 0;
name.compareToIgnoreCase(end + Constants.UNICODE_HIGHEST) <= 0;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

import java.util.Collection;

import ch.ethz.seb.sebserver.gbl.model.session.ProctoringGroupMonitoringData;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;

Expand All @@ -28,20 +29,20 @@ public class MonitoringFullPageData {
public final Long examId;
@JsonProperty(ATTR_CONNECTIONS_DATA)
public final MonitoringSEBConnectionData monitoringConnectionData;
@JsonProperty(ATTR_PROCTORING_DATA)
public final Collection<RemoteProctoringRoom> proctoringData;
// @JsonProperty(ATTR_PROCTORING_DATA)
// public final Collection<RemoteProctoringRoom> proctoringData;
@JsonProperty(ATTR_SCREEN_PROCTORING_DATA)
final Collection<ScreenProctoringGroup> screenProctoringData;
final Collection<ProctoringGroupMonitoringData> screenProctoringData;

public MonitoringFullPageData(
@JsonProperty(Domain.CLIENT_CONNECTION.ATTR_EXAM_ID) final Long examId,
@JsonProperty(ATTR_CONNECTIONS_DATA) final MonitoringSEBConnectionData monitoringConnectionData,
@JsonProperty(ATTR_PROCTORING_DATA) final Collection<RemoteProctoringRoom> proctoringData,
@JsonProperty(ATTR_SCREEN_PROCTORING_DATA) final Collection<ScreenProctoringGroup> screenProctoringData) {
// @JsonProperty(ATTR_PROCTORING_DATA) final Collection<RemoteProctoringRoom> proctoringData,
@JsonProperty(ATTR_SCREEN_PROCTORING_DATA) final Collection<ProctoringGroupMonitoringData> screenProctoringData) {

this.examId = examId;
this.monitoringConnectionData = monitoringConnectionData;
this.proctoringData = proctoringData;
// this.proctoringData = proctoringData;
this.screenProctoringData = screenProctoringData;
}

Expand All @@ -53,11 +54,11 @@ public MonitoringSEBConnectionData getMonitoringConnectionData() {
return this.monitoringConnectionData;
}

public Collection<RemoteProctoringRoom> getProctoringData() {
return this.proctoringData;
}
// public Collection<RemoteProctoringRoom> getProctoringData() {
// return this.proctoringData;
// }

public Collection<ScreenProctoringGroup> getScreenProctoringData() {
public Collection<ProctoringGroupMonitoringData> getScreenProctoringData() {
return this.screenProctoringData;
}

Expand Down Expand Up @@ -88,17 +89,13 @@ public boolean equals(final Object obj) {

@Override
public String toString() {
final StringBuilder builder = new StringBuilder();
builder.append("MonitoringFullPageData [examId=");
builder.append(this.examId);
builder.append(", monitoringConnectionData=");
builder.append(this.monitoringConnectionData);
builder.append(", proctoringData=");
builder.append(this.proctoringData);
builder.append(", screenProctoringData=");
builder.append(this.screenProctoringData);
builder.append("]");
return builder.toString();
return "MonitoringFullPageData [examId=" +
this.examId +
", monitoringConnectionData=" +
this.monitoringConnectionData +
", screenProctoringData=" +
this.screenProctoringData +
"]";
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,8 @@ public class ClientGroupTemplateForm implements TemplateComposer {
new LocTextKey("sebserver.exam.clientgroup.form.type");
private static final LocTextKey FORM_NAME_TEXT_KEY =
new LocTextKey("sebserver.exam.clientgroup.form.name");
private static final LocTextKey FORM_EXAM_TEXT_KEY =
new LocTextKey("sebserver.exam.clientgroup.form.exam");
private static final LocTextKey FORM_EXAM_TEMPLATE_TEXT_KEY =
new LocTextKey("sebserver.exam.clientgroup.form.exam-template");
private static final LocTextKey FORM_DESC_TEXT_KEY =
new LocTextKey("sebserver.exam.clientgroup.form.description");
private static final LocTextKey FORM_IP_START_KEY =
Expand Down Expand Up @@ -164,26 +164,32 @@ private void buildFormAccordingToSelection(
final PageContext pageContext,
final boolean init) {


final String name = init
? clientGroupTemplate.getName()
: formHandleAnchor.formHandle.getForm().getFieldValue(Domain.CLIENT_GROUP.ATTR_NAME);
final String color = init
? clientGroupTemplate.getColor()
: formHandleAnchor.formHandle.getForm().getFieldValue(Domain.CLIENT_GROUP.ATTR_COLOR);

if (!init) {
PageService.clearComposite(formHandleAnchor.formContext.getParent());
}

final ClientGroupData.ClientGroupType type = selection != null ? ClientGroupData.ClientGroupType.valueOf(selection) : null;
final String typeDescription = (type != null)
? Utils.formatLineBreaks(
this.i18nSupport.getText(CLIENT_GROUP_TYPE_DESC_PREFIX + type.name()))
: Constants.EMPTY_NOTE;

final RestService restService = this.resourceService.getRestService();
final WidgetFactory widgetFactory = this.pageService.getWidgetFactory();
final EntityKey entityKey = pageContext.getEntityKey();
final EntityKey parentEntityKey = pageContext.getParentEntityKey();
final boolean isNew = entityKey == null;
final boolean isReadonly = pageContext.isReadonly();

final ClientGroupData.ClientGroupType type = selection != null
? ClientGroupData.ClientGroupType.valueOf(selection)
: null;
final String typeDescription = (type != null)
? Utils.formatLineBreaks(
this.i18nSupport.getText(CLIENT_GROUP_TYPE_DESC_PREFIX + clientGroupTemplate.type.name()))
: Constants.EMPTY_NOTE;

final FormHandle<ClientGroupTemplate> formHandle = this.pageService.formBuilder(formHandleAnchor.formContext)
formHandleAnchor.formHandle = this.pageService.formBuilder(formHandleAnchor.formContext)
.readonly(isReadonly)
.putStaticValueIf(() -> !isNew,
Domain.CLIENT_GROUP.ATTR_ID,
Expand All @@ -196,26 +202,27 @@ private void buildFormAccordingToSelection(
parentEntityKey.getModelId())

.addField(FormBuilder.text(
Domain.EXAM_TEMPLATE.ATTR_NAME,
FORM_EXAM_TEXT_KEY,
"templateName",
FORM_EXAM_TEMPLATE_TEXT_KEY,
examTemplate.name)
.readonly(true))

.addField(FormBuilder.text(
Domain.CLIENT_GROUP.ATTR_NAME,
FORM_NAME_TEXT_KEY,
clientGroupTemplate.name)
name)
.mandatory(!isReadonly))

.addField(FormBuilder.colorSelection(
Domain.CLIENT_GROUP.ATTR_COLOR,
FORM_COLOR_TEXT_KEY,
clientGroupTemplate.color)
color)
.withEmptyCellSeparation(false))

.addField(FormBuilder.singleSelection(
Domain.CLIENT_GROUP.ATTR_TYPE,
FORM_TYPE_TEXT_KEY,
(clientGroupTemplate.type != null) ? clientGroupTemplate.type.name() : null,
type != null ? type.name() : null,
this.resourceService::clientGroupTypeResources)
.withSelectionListener(form -> buildFormAccordingToSelection(
form.getFieldValue(Domain.CLIENT_GROUP.ATTR_TYPE),
Expand Down Expand Up @@ -272,6 +279,8 @@ private void buildFormAccordingToSelection(
.buildFor((isNew)
? restService.getRestCall(NewClientGroupTemplate.class)
: restService.getRestCall(SaveClientGroupTemplate.class));

formHandleAnchor.formContext.getParent().layout();
}

static final class FormHandleAnchor {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,8 @@ public void compose(final PageContext pageContext) {
final boolean modifyGrant = entityGrantCheck.m();
final boolean writeGrant = entityGrantCheck.w();
final boolean editable = modifyGrant && Exam.ACTIVE_STATES.contains(exam.getStatus());


final boolean signatureKeyCheckEnabled = BooleanUtils.toBoolean(
exam.additionalAttributes.get(Exam.ADDITIONAL_ATTR_SIGNATURE_KEY_CHECK_ENABLED));
final boolean sebRestrictionAvailable = readonly && hasSEBRestrictionAPI(exam);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@
import java.util.function.BiConsumer;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collectors;

import ch.ethz.seb.sebserver.gbl.api.APIMessage;
import ch.ethz.seb.sebserver.gui.service.i18n.I18nSupport;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCallError;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
Expand All @@ -30,7 +30,6 @@
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.Entity;
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
import ch.ethz.seb.sebserver.gbl.model.exam.CollectingStrategy;
import ch.ethz.seb.sebserver.gbl.model.exam.ScreenProctoringSettings;
Expand Down Expand Up @@ -94,6 +93,9 @@ public class ScreenProctoringSettingsPopup {
new LocTextKey("sebserver.exam.sps.form.saveSettings.error");
private final static LocTextKey SAVE_TEXT_KEY =
new LocTextKey("sebserver.exam.sps.form.saveSettings");

private final static LocTextKey ACTIVE_SEB_CLIENT_MSG =
new LocTextKey("sebserver.exam.sps.form.active-seb-clients");

Function<PageAction, PageAction> settingsFunction(final PageService pageService, final boolean modifyGrant) {
return action -> {
Expand Down Expand Up @@ -215,15 +217,23 @@ private boolean doSaveSettings(
action.pageContext());
return true;
} else {
Exception error = saveRequest.getError();
final Exception error = saveRequest.getError();
boolean onlyFieldErrors = false;
if (error instanceof RestCallError) {
onlyFieldErrors = ((RestCallError) error)
final List<APIMessage> noneFieldErrors = ((RestCallError) error)
.getAPIMessages()
.stream()
.filter(message -> !APIMessage.ErrorMessage.FIELD_VALIDATION.isOf(message))
.toList()
.isEmpty();
.toList();

if (!noneFieldErrors.isEmpty()) {
if (APIMessage.ErrorMessage.CLIENT_CONNECTION_INTEGRITY_VIOLATION.isOf(noneFieldErrors.get(0))) {
pageContext.publishInfo(ACTIVE_SEB_CLIENT_MSG);
return false;
}
}

onlyFieldErrors = noneFieldErrors.isEmpty();
}

if (onlyFieldErrors) {
Expand All @@ -238,7 +248,6 @@ private boolean doSaveSettings(
}
}
}

return false;
}

Expand All @@ -260,6 +269,7 @@ private ScreenProctoringPropertiesForm(
public Supplier<FormHandle<?>> compose(final Composite parent) {
final RestService restService = this.pageService.getRestService();
final EntityKey entityKey = this.pageContext.getEntityKey();
final I18nSupport i18nSupport = this.pageService.getI18nSupport();

final Composite content = this.pageService
.getWidgetFactory()
Expand All @@ -277,6 +287,7 @@ public Supplier<FormHandle<?>> compose(final Composite parent) {
.withURIVariable(API.PARAM_MODEL_ID, entityKey.modelId)
.call()
.getOrThrow();


final Composite formRoot = this.pageService.getWidgetFactory().voidComposite(content);
final FormHandleAnchor formHandleAnchor = new FormHandleAnchor();
Expand All @@ -285,6 +296,7 @@ public Supplier<FormHandle<?>> compose(final Composite parent) {
.clearEntityKeys();

buildFormForCollectingStrategy(
entityKey,
settings.collectingStrategy.name(),
formHandleAnchor,
settings,
Expand All @@ -294,13 +306,18 @@ public Supplier<FormHandle<?>> compose(final Composite parent) {
}

private void buildFormForCollectingStrategy(
final EntityKey entityKey,
final String selection,
final FormHandleAnchor formHandleAnchor,
final ScreenProctoringSettings settings,
final boolean init
) {

Boolean enableScreenProctoring = settings.enableScreenProctoring;

if (!init) {
enableScreenProctoring = BooleanUtils.toBoolean(formHandleAnchor.formHandle.getForm().getFieldValue(
ScreenProctoringSettings.ATTR_ENABLE_SCREEN_PROCTORING));
PageService.clearComposite(formHandleAnchor.formContext.getParent());
}

Expand All @@ -327,7 +344,7 @@ private void buildFormForCollectingStrategy(
.addField(FormBuilder.checkbox(
ScreenProctoringSettings.ATTR_ENABLE_SCREEN_PROCTORING,
FORM_ENABLE,
String.valueOf(settings.enableScreenProctoring)))
String.valueOf(enableScreenProctoring)))

.addField(FormBuilder.text(
ScreenProctoringSettings.ATTR_SPS_SERVICE_URL,
Expand Down Expand Up @@ -376,6 +393,7 @@ private void buildFormForCollectingStrategy(
selection,
() -> this.pageService.getResourceService().getCollectingStrategySelection())
.withSelectionListener(f -> buildFormForCollectingStrategy(
entityKey,
f.getFieldValue(ScreenProctoringSettings.ATTR_COLLECTING_STRATEGY),
formHandleAnchor,
settings,
Expand All @@ -392,7 +410,7 @@ private void buildFormForCollectingStrategy(
ScreenProctoringSettings.ATT_SEB_GROUPS_SELECTION,
FORM_SEB_CLIENT_GROUPS,
settings.sebGroupsSelection,
() -> this.pageService.getResourceService().getSEBGroupSelection(String.valueOf(settings.examId))))
() -> this.pageService.getResourceService().getSEBGroupSelection(entityKey)))
.addFieldIf(
() -> CollectingStrategy.APPLY_SEB_GROUPS.name().equals(selection),
() -> FormBuilder.text(
Expand Down
Loading

0 comments on commit 7cfc327

Please sign in to comment.