diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/impl/proctoring/ScreenProctoringAPIBinding.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/impl/proctoring/ScreenProctoringAPIBinding.java index e2f934dee..8ff1cb2a2 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/impl/proctoring/ScreenProctoringAPIBinding.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/impl/proctoring/ScreenProctoringAPIBinding.java @@ -8,13 +8,16 @@ package ch.ethz.seb.sebserver.webservice.servicelayer.session.impl.proctoring; +import javax.validation.constraints.Size; import java.util.*; +import java.util.stream.Collectors; import ch.ethz.seb.sebserver.gbl.model.Page; import ch.ethz.seb.sebserver.gbl.model.exam.SPSAPIAccessData; import ch.ethz.seb.sebserver.gbl.model.user.UserRole; import ch.ethz.seb.sebserver.webservice.WebserviceInfo; import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.UserService; +import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ScreenProctoringGroupDAO; import org.apache.commons.lang3.BooleanUtils; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; @@ -71,7 +74,7 @@ class ScreenProctoringAPIBinding { private static final Logger log = LoggerFactory.getLogger(ScreenProctoringAPIBinding.class); private static final String SEB_SERVER_SCREEN_PROCTORING_SEB_ACCESS_PREFIX = "SEBServer_SEB_Access_"; - + interface SPS_API { enum SPSUserRole { @@ -86,7 +89,6 @@ enum SPSUserRole { String USER_ACCOUNT_ENDPOINT = "/admin-api/v1/useraccount/"; String USERSYNC_SEBSERVER_ENDPOINT = USER_ACCOUNT_ENDPOINT + "usersync/sebserver"; -// String ENTITY_PRIVILEGES_ENDPOINT = USER_ACCOUNT_ENDPOINT + "entityprivilege"; String EXAM_ENDPOINT = "/admin-api/v1/exam"; String EXAM_DELETE_REQUEST_ENDPOINT = "/request"; String SEB_ACCESS_ENDPOINT = "/admin-api/v1/clientaccess"; @@ -95,21 +97,6 @@ enum SPSUserRole { String ACTIVE_PATH_SEGMENT = "/active"; String INACTIVE_PATH_SEGMENT = "/inactive"; - -// interface ENTITY_PRIVILEGE { -// String ATTR_ENTITY_TYPE = "entityType"; -// String ATTR_ENTITY_ID = "entityId"; -// String ATTR_USER_UUID = "userUuid"; -// String ATTR_USERNAME = "username"; -// String ATTR_PRIVILEGES = "privileges"; -// } -// -// interface PRIVILEGE_FLAGS { -// String READ = "r"; -// String MODIFY = "m"; -// String WRITE = "w"; -// } - /** The screen proctoring service client-access API attribute names */ interface SEB_ACCESS { String ATTR_UUID = "uuid"; @@ -210,12 +197,30 @@ public GroupSessionCount( } } + @JsonIgnoreProperties(ignoreUnknown = true) + static final class GroupName { + @JsonProperty("uuid") + public final String modelId; + @JsonProperty("name") + public final String name; + + @JsonCreator + public GroupName( + @JsonProperty("modelId") final String modelId, + @JsonProperty("name") final String name) { + + this.modelId = modelId; + this.name = name; + } + } + private final UserDAO userDAO; private final Cryptor cryptor; private final AsyncService asyncService; private final JSONMapper jsonMapper; private final ProctoringSettingsDAO proctoringSettingsDAO; private final AdditionalAttributesDAO additionalAttributesDAO; + private final ScreenProctoringGroupDAO screenProctoringGroupDAO; private final WebserviceInfo webserviceInfo; ScreenProctoringAPIBinding( @@ -225,6 +230,7 @@ public GroupSessionCount( final JSONMapper jsonMapper, final ProctoringSettingsDAO proctoringSettingsDAO, final AdditionalAttributesDAO additionalAttributesDAO, + final ScreenProctoringGroupDAO screenProctoringGroupDAO, final WebserviceInfo webserviceInfo) { this.userDAO = userDAO; @@ -233,6 +239,7 @@ public GroupSessionCount( this.jsonMapper = jsonMapper; this.proctoringSettingsDAO = proctoringSettingsDAO; this.additionalAttributesDAO = additionalAttributesDAO; + this.screenProctoringGroupDAO = screenProctoringGroupDAO; this.webserviceInfo = webserviceInfo; } @@ -446,6 +453,46 @@ void deleteSPSUser(final String userUUID) { } } + public void synchronizeGroups(final Exam exam) { + try { + + // TODO try to sync groups for exam with SPS Service. + // If some group on SPS service has been delete, + // delete (or mark) it also locally + +// Set localGroupIds = this.screenProctoringGroupDAO +// .getCollectingGroups(exam.id) +// .getOrThrow() +// .stream() +// .map(g -> g.uuid) +// .collect(Collectors.toSet()); +// +// final ScreenProctoringServiceOAuthTemplate apiTemplate = this.getAPITemplate(exam.id); +// final SPSData spsData = this.getSPSData(exam.id); +// final String groupRequestURI = UriComponentsBuilder +// .fromUriString(apiTemplate.spsAPIAccessData.getSpsServiceURL()) +// .path(SPS_API.GROUP_ENDPOINT + "/names") +// .queryParam(SPS_API.GROUP.ATTR_UUID, exam.externalId) +// .build() +// .toUriString(); +// final ResponseEntity exchangeGroups = apiTemplate.exchange(groupRequestURI, HttpMethod.GET); +// +// final Collection groups = this.jsonMapper.readValue( +// exchangeGroups.getBody(), +// new TypeReference>() { +// }); +// +// for (final GroupName group : groups) { +// if (!localGroupIds.contains(group.modelId)) { +// System.out.println("************* TODO delete local group"); +// } +// } + + } catch (final Exception e) { + log.error("Failed to synchronize groups for exam: {} error: {}", exam.name, e.getMessage()); + } + } + /** This is called when an exam has changed its parameter and needs data update on SPS side * * @param exam The exam*/ @@ -830,10 +877,12 @@ public Collection getActiveGroupSessionCounts() { return Collections.emptyList(); } - return this.jsonMapper.readValue( + Collection groupSessionCounts = this.jsonMapper.readValue( exchange.getBody(), new TypeReference>() { }); + + return groupSessionCounts; } catch (final Exception e) { log.error("Failed to get active group session counts: {}", e.getMessage()); @@ -904,7 +953,8 @@ private static UserMod getUserModifications(final UserInfo userInfo, final SEBSe final Set spsUserRoles = new HashSet<>(); spsUserRoles.add(SPS_API.SPSUserRole.PROCTOR.name()); if (userInfo.roles.contains(UserRole.SEB_SERVER_ADMIN.name()) || - userInfo.roles.contains(UserRole.INSTITUTIONAL_ADMIN.name())) { + userInfo.roles.contains(UserRole.INSTITUTIONAL_ADMIN.name()) || + userInfo.roles.contains(UserRole.EXAM_ADMIN.name())) { spsUserRoles.add(SPS_API.SPSUserRole.ADMIN.name()); } diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/impl/proctoring/ScreenProctoringServiceImpl.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/impl/proctoring/ScreenProctoringServiceImpl.java index e009944fb..c936915dd 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/impl/proctoring/ScreenProctoringServiceImpl.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/impl/proctoring/ScreenProctoringServiceImpl.java @@ -102,6 +102,7 @@ public ScreenProctoringServiceImpl( jsonMapper, proctoringSettingsDAO, additionalAttributesDAO, + screenProctoringGroupDAO, webserviceInfo); } @@ -237,6 +238,7 @@ private Exam createExamGroups(final Exam exam, final Collection> getCollectingGroups(final Long examId) { return this.screenProctoringGroupDAO.getCollectingGroups(examId); @@ -306,6 +308,7 @@ public void notifyExamSaved(final Exam exam) { this.screenProctoringAPIBinding.synchronizeUserAccounts(exam); this.screenProctoringAPIBinding.updateExam(exam); + this.screenProctoringAPIBinding.synchronizeGroups(exam); } @Override diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/UserAccountController.java b/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/UserAccountController.java index 1d8f5be26..57adfce29 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/UserAccountController.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/UserAccountController.java @@ -16,6 +16,7 @@ import ch.ethz.seb.sebserver.gbl.api.EntityType; import ch.ethz.seb.sebserver.gbl.api.POSTMapper; import ch.ethz.seb.sebserver.gbl.api.authorization.Privilege; +import ch.ethz.seb.sebserver.gbl.model.Activatable; import ch.ethz.seb.sebserver.gbl.model.Domain; import ch.ethz.seb.sebserver.gbl.model.EntityKey; import ch.ethz.seb.sebserver.gbl.model.EntityProcessingReport; @@ -179,8 +180,11 @@ protected Result validForSave(final UserInfo userInfo) { } @Override - protected Result notifySaved(final UserInfo entity) { - final Result userInfoResult = super.notifySaved(entity); + protected Result notifySaved( + final UserInfo entity, + final Activatable.ActivationAction activationAction) { + + final Result userInfoResult = super.notifySaved(entity, activationAction); this.synchronizeUserWithSPS(entity); return userInfoResult; } diff --git a/src/main/resources/config/application-dev.properties b/src/main/resources/config/application-dev.properties index 8b2cff58a..080a49ed1 100644 --- a/src/main/resources/config/application-dev.properties +++ b/src/main/resources/config/application-dev.properties @@ -1,6 +1,6 @@ sebserver.test.property=This is the development Setup -server.address=129.132.182.122 +server.address=localhost server.port=8080 server.servlet.context-path=/ server.tomcat.uri-encoding=UTF-8 @@ -17,7 +17,7 @@ logging.level.ch.ethz.seb.sebserver.webservice.servicelayer=DEBUG sebserver.gui.http.external.scheme=http sebserver.gui.entrypoint=/gui sebserver.gui.webservice.protocol=http -sebserver.gui.webservice.address=129.132.182.122 +sebserver.gui.webservice.address=localhost sebserver.gui.webservice.port=8080 sebserver.gui.webservice.apipath=/admin-api/v1 # defines the polling interval that is used to poll the webservice for client connection data on a monitored exam page @@ -66,7 +66,7 @@ sebserver.webservice.light.setup=false sebserver.webservice.distributed=false #sebserver.webservice.master.delay.threshold=10000 sebserver.webservice.http.external.scheme=http -sebserver.webservice.http.external.servername=129.132.182.122 +sebserver.webservice.http.external.servername=localhost sebserver.webservice.http.external.port=${server.port} sebserver.webservice.http.redirect.gui=/gui sebserver.webservice.ping.service.strategy=BATCH @@ -110,7 +110,7 @@ springdoc.paths-to-exclude=/exam-api,/exam-api/discovery,/sebserver/error,/sebse sebserver.feature.exam.seb.screenProctoring.enabled=true sebserver.feature.exam.seb.screenProctoring.bundled=true -sebserver.feature.exam.seb.screenProctoring.bundled.url=http://129.132.182.122:8090 +sebserver.feature.exam.seb.screenProctoring.bundled.url=http://localhost:8090 sebserver.feature.exam.seb.screenProctoring.bundled.clientId=sebserverClient sebserver.feature.exam.seb.screenProctoring.bundled.sebserveraccount.username=SEBServerAPIAccount