diff --git a/src/test/java/ch/ethz/seb/sebserver/gui/integration/UseCasesIntegrationTest.java b/src/test/java/ch/ethz/seb/sebserver/gui/integration/UseCasesIntegrationTest.java index 065b624a..509d2d6b 100644 --- a/src/test/java/ch/ethz/seb/sebserver/gui/integration/UseCasesIntegrationTest.java +++ b/src/test/java/ch/ethz/seb/sebserver/gui/integration/UseCasesIntegrationTest.java @@ -1,1499 +1,1503 @@ -/* - * Copyright (c) 2019 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.integration; - -import static org.junit.Assert.*; - -import java.io.IOException; -import java.io.InputStream; -import java.util.Collection; -import java.util.Collections; -import java.util.Iterator; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.function.Function; -import java.util.stream.Collectors; - -import org.apache.commons.codec.Charsets; -import org.apache.commons.io.IOUtils; -import org.apache.commons.lang3.BooleanUtils; -import org.apache.tomcat.util.buf.StringUtils; -import org.joda.time.DateTimeZone; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.springframework.core.annotation.Order; -import org.springframework.core.io.ClassPathResource; -import org.springframework.test.context.jdbc.Sql; -import org.springframework.util.StreamUtils; - -import ch.ethz.seb.sebserver.gbl.Constants; -import ch.ethz.seb.sebserver.gbl.api.API; -import ch.ethz.seb.sebserver.gbl.api.JSONMapper; -import ch.ethz.seb.sebserver.gbl.model.Domain; -import ch.ethz.seb.sebserver.gbl.model.Domain.SEB_CLIENT_CONFIGURATION; -import ch.ethz.seb.sebserver.gbl.model.EntityName; -import ch.ethz.seb.sebserver.gbl.model.EntityProcessingReport; -import ch.ethz.seb.sebserver.gbl.model.Page; -import ch.ethz.seb.sebserver.gbl.model.exam.Exam; -import ch.ethz.seb.sebserver.gbl.model.exam.Exam.ExamStatus; -import ch.ethz.seb.sebserver.gbl.model.exam.Exam.ExamType; -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.exam.Indicator.Threshold; -import ch.ethz.seb.sebserver.gbl.model.exam.QuizData; -import ch.ethz.seb.sebserver.gbl.model.institution.Institution; -import ch.ethz.seb.sebserver.gbl.model.institution.LmsSetup; -import ch.ethz.seb.sebserver.gbl.model.institution.LmsSetup.LmsType; -import ch.ethz.seb.sebserver.gbl.model.sebconfig.Configuration; -import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationAttribute; -import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationNode; -import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationNode.ConfigurationStatus; -import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationNode.ConfigurationType; -import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationTableValues; -import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationTableValues.TableValue; -import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationValue; -import ch.ethz.seb.sebserver.gbl.model.sebconfig.Orientation; -import ch.ethz.seb.sebserver.gbl.model.sebconfig.SebClientConfig; -import ch.ethz.seb.sebserver.gbl.model.sebconfig.View; -import ch.ethz.seb.sebserver.gbl.model.user.PasswordChange; -import ch.ethz.seb.sebserver.gbl.model.user.UserInfo; -import ch.ethz.seb.sebserver.gbl.model.user.UserRole; -import ch.ethz.seb.sebserver.gbl.util.Result; -import ch.ethz.seb.sebserver.gbl.util.Utils; -import ch.ethz.seb.sebserver.gui.service.examconfig.impl.AttributeMapping; -import ch.ethz.seb.sebserver.gui.service.examconfig.impl.ExamConfigurationServiceImpl; -import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCallError; -import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestServiceImpl; -import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.ExportExamConfig; -import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.GetExam; -import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.GetExamNames; -import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.GetExamPage; -import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.GetIndicator; -import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.GetIndicatorPage; -import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.NewIndicator; -import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.SaveExam; -import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.SaveIndicator; -import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.institution.ActivateInstitution; -import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.institution.GetInstitution; -import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.institution.GetInstitutionNames; -import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.institution.NewInstitution; -import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.lmssetup.ActivateLmsSetup; -import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.lmssetup.DeactivateLmsSetup; -import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.lmssetup.GetLmsSetup; -import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.lmssetup.GetLmsSetupNames; -import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.lmssetup.NewLmsSetup; -import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.lmssetup.SaveLmsSetup; -import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.quiz.GetQuizData; -import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.quiz.GetQuizPage; -import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.quiz.ImportAsExam; -import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.clientconfig.ActivateClientConfig; -import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.clientconfig.DeactivateClientConfig; -import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.clientconfig.ExportClientConfig; -import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.clientconfig.GetClientConfig; -import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.clientconfig.GetClientConfigPage; -import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.clientconfig.NewClientConfig; -import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.clientconfig.SaveClientConfig; -import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.ExportPlainXML; -import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.GetConfigAttributes; -import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.GetConfigurationPage; -import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.GetConfigurationTableValues; -import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.GetConfigurationValuePage; -import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.GetConfigurationValues; -import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.GetConfigurations; -import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.GetExamConfigNode; -import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.GetExamConfigNodePage; -import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.GetFollowupConfiguration; -import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.GetOrientationPage; -import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.GetOrientations; -import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.GetViewList; -import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.GetViewPage; -import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.GetViews; -import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.ImportExamConfigOnExistingConfig; -import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.ImportNewExamConfig; -import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.NewExamConfig; -import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.SaveExamConfig; -import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.SaveExamConfigHistory; -import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.SaveExamConfigTableValues; -import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.SaveExamConfigValue; -import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.SebExamConfigUndo; -import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.useraccount.ActivateUserAccount; -import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.useraccount.ChangePassword; -import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.useraccount.GetUserAccount; -import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.useraccount.GetUserAccountNames; -import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.useraccount.NewUserAccount; -import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.useraccount.SaveUserAccount; - -public class UseCasesIntegrationTest extends GuiIntegrationTest { - - @Before - @Sql(scripts = { "classpath:schema-test.sql", "classpath:data-test.sql" }) - public void init() { - - } - - @After - @Sql(scripts = { "classpath:schema-test.sql", "classpath:data-test.sql" }) - public void cleanup() { - - } - - @Test - @Order(1) - // ************************************* - // Use Case 1: SEB Administrator creates a new institution and activate this new institution - - public void testUsecase1() { - final RestServiceImpl restService = createRestServiceForUser( - "admin", - "admin", - new NewInstitution(), - new ActivateInstitution(), - new GetInstitution()); - - final Result result = restService.getBuilder(NewInstitution.class) - .withFormParam(Domain.INSTITUTION.ATTR_NAME, "Test Institution") - .call(); - - assertNotNull(result); - assertFalse(result.hasError()); - Institution institution = result.get(); - assertEquals("Test Institution", institution.name); - assertFalse(institution.active); - - final Result resultActivation = restService.getBuilder(ActivateInstitution.class) - .withURIVariable(API.PARAM_MODEL_ID, String.valueOf(institution.id)) - .call(); - - assertNotNull(resultActivation); - assertFalse(resultActivation.hasError()); - - final Result resultGet = restService.getBuilder(GetInstitution.class) - .withURIVariable(API.PARAM_MODEL_ID, String.valueOf(institution.id)) - .call(); - - assertNotNull(resultGet); - assertFalse(resultGet.hasError()); - institution = resultGet.get(); - assertEquals("Test Institution", institution.name); - assertTrue(institution.active); - - } - - @Test - @Order(2) - // ************************************* - // Use Case 2: SEB Administrator creates a new Institutional Administrator user for the - // newly created institution and activate this user - public void testUsecase2() { - final RestServiceImpl restService = createRestServiceForUser( - "admin", - "admin", - new GetInstitution(), - new GetInstitutionNames(), - new NewUserAccount(), - new ActivateUserAccount(), - new GetUserAccount()); - - final String instId = restService.getBuilder(GetInstitutionNames.class) - .call() - .getOrThrow() - .stream() - .filter(inst -> "Test Institution".equals(inst.name)) - .findFirst() - .get().modelId; - - assertNotNull(instId); - - Result result = restService.getBuilder(NewUserAccount.class) - .withFormParam(Domain.USER.ATTR_INSTITUTION_ID, instId) - .withFormParam(Domain.USER.ATTR_NAME, "TestInstAdmin") - .withFormParam(Domain.USER.ATTR_USERNAME, "TestInstAdmin") - .withFormParam(Domain.USER.ATTR_EMAIL, "test@test.ch") - .withFormParam(Domain.USER_ROLE.REFERENCE_NAME, UserRole.INSTITUTIONAL_ADMIN.name()) - .withFormParam(PasswordChange.ATTR_NAME_NEW_PASSWORD, "12345678") - .withFormParam(PasswordChange.ATTR_NAME_CONFIRM_NEW_PASSWORD, "12345678") - .withFormParam(Domain.USER.ATTR_LANGUAGE, Locale.ENGLISH.getLanguage()) - .withFormParam(Domain.USER.ATTR_TIMEZONE, DateTimeZone.UTC.getID()) - .call(); - - assertFalse(result.hasError()); - UserInfo userInfo = result.get(); - assertNotNull(userInfo); - assertEquals(instId, String.valueOf(userInfo.institutionId)); - assertEquals("TestInstAdmin", userInfo.name); - assertEquals("TestInstAdmin", userInfo.username); - assertEquals("test@test.ch", userInfo.email); - assertEquals("[INSTITUTIONAL_ADMIN]", String.valueOf(userInfo.getRoles())); - assertEquals(Locale.ENGLISH, userInfo.language); - assertEquals(DateTimeZone.UTC, userInfo.timeZone); - assertFalse(userInfo.isActive()); - - final Result activation = restService.getBuilder(ActivateUserAccount.class) - .withURIVariable(API.PARAM_MODEL_ID, String.valueOf(userInfo.uuid)) - .call(); - - assertFalse(activation.hasError()); - final EntityProcessingReport entityProcessingReport = activation.get(); - assertTrue(entityProcessingReport.getErrors().isEmpty()); - - result = restService.getBuilder(GetUserAccount.class) - .withURIVariable(API.PARAM_MODEL_ID, String.valueOf(userInfo.uuid)) - .call(); - - assertFalse(result.hasError()); - userInfo = result.get(); - assertTrue(userInfo.isActive()); - } - - @Test - @Order(3) - // ************************************* - // Use Case 3: Login with the new TestInstAdmin and check that only its institution is available - // check also that it is not possible to change to SEB Administrator role - // check also this it is possible to change the password and after that a new login is needed - // check also that property changes are possible. E.g: email - public void testUsecase3() { - RestServiceImpl restService = createRestServiceForUser( - "TestInstAdmin", - "12345678", - new GetInstitutionNames(), - new SaveUserAccount(), - new ChangePassword(), - new GetUserAccount(), - new GetUserAccountNames()); - - final List institutions = restService - .getBuilder(GetInstitutionNames.class) - .call() - .getOrThrow(); - - assertTrue(institutions.size() == 1); - assertEquals("Test Institution", institutions.get(0).name); - - final List userNames = restService - .getBuilder(GetUserAccountNames.class) - .call() - .getOrThrow(); - - assertTrue(userNames.size() == 1); - assertEquals("TestInstAdmin", userNames.get(0).name); - - final String userId = userNames.get(0).modelId; - - UserInfo userInfo = restService.getBuilder(GetUserAccount.class) - .withURIVariable(API.PARAM_MODEL_ID, userId) - .call() - .getOrThrow(); - - // change email (should work properly) - assertEquals("test@test.ch", userInfo.email); - userInfo = UserInfo.withEMail(userInfo, "newMail@test.ch"); - userInfo = restService.getBuilder(SaveUserAccount.class) - .withBody(userInfo) - .call() - .getOrThrow(); - - assertEquals("newMail@test.ch", userInfo.email); - - // adding new role that is lower should work (example Exam Admin) - userInfo = UserInfo.withRoles(userInfo, UserRole.INSTITUTIONAL_ADMIN.name(), UserRole.EXAM_ADMIN.name()); - userInfo = restService.getBuilder(SaveUserAccount.class) - .withBody(userInfo) - .call() - .getOrThrow(); - - assertEquals( - "[EXAM_ADMIN, INSTITUTIONAL_ADMIN]", - String.valueOf(new LinkedHashSet<>(userInfo.getRoles()))); - - // adding new role that is higher shouldn't work - userInfo = UserInfo.withRoles(userInfo, UserRole.INSTITUTIONAL_ADMIN.name(), UserRole.SEB_SERVER_ADMIN.name()); - final Result call = restService.getBuilder(SaveUserAccount.class) - .withBody(userInfo) - .call(); - - assertTrue(call.hasError()); - //assertEquals("Unexpected error while rest call", call.getError().getMessage()); - RestCallError error = (RestCallError) call.getError(); - assertEquals( - "[APIMessage [messageCode=1001, systemMessage=FORBIDDEN, details=No edit right grant for user: TestInstAdmin, attributes=[]]]", - String.valueOf(error.getErrorMessages())); - - // change password - final Result passwordChange = restService - .getBuilder(ChangePassword.class) - .withBody(new PasswordChange(userId, "12345678", "987654321", "987654321")) - .call(); - - assertFalse(passwordChange.hasError()); - userInfo = passwordChange.get(); - - // is the login still valid (should not) - final Result> instNames = restService - .getBuilder(GetInstitutionNames.class) - .call(); - assertTrue(instNames.hasError()); - error = (RestCallError) instNames.getError(); - assertEquals( - "UNAUTHORIZED", - String.valueOf(error.getErrorMessages().get(0).getSystemMessage())); - - // login again with the new password and check roles - restService = createRestServiceForUser( - "TestInstAdmin", - "987654321", - new GetInstitutionNames(), - new SaveUserAccount(), - new ChangePassword(), - new GetUserAccount(), - new GetUserAccountNames()); - - userInfo = restService.getBuilder(GetUserAccount.class) - .withURIVariable(API.PARAM_MODEL_ID, userId) - .call() - .getOrThrow(); - - assertNotNull(userInfo); - assertEquals("[EXAM_ADMIN, INSTITUTIONAL_ADMIN]", String.valueOf(userInfo.getRoles())); - } - - @Test - @Order(4) - // ************************************* - // Use Case 4: - // - login as TestInstAdmin - // - create a new user-account (examAdmin2) with Exam Administrator role - // - create a new user-account (examSupport1) with Exam Supporter role - // - create a new user-account (examSupport2) with Exam Administrator and Exam Supporter role - public void testUsecase4() { - final RestServiceImpl restService = createRestServiceForUser( - "TestInstAdmin", - "987654321", - new GetInstitutionNames(), - new NewUserAccount(), - new ActivateUserAccount()); - - final String instId = restService.getBuilder(GetInstitutionNames.class) - .call() - .getOrThrow() - .stream() - .filter(inst -> "Test Institution".equals(inst.name)) - .findFirst() - .get().modelId; - - assertNotNull(instId); - - Result result = restService.getBuilder(NewUserAccount.class) - .withFormParam(Domain.USER.ATTR_INSTITUTION_ID, instId) - .withFormParam(Domain.USER.ATTR_NAME, "examAdmin2") - .withFormParam(Domain.USER.ATTR_USERNAME, "examAdmin2") - .withFormParam(Domain.USER.ATTR_EMAIL, "test@test.ch") - .withFormParam(Domain.USER_ROLE.REFERENCE_NAME, UserRole.EXAM_ADMIN.name()) - .withFormParam(PasswordChange.ATTR_NAME_NEW_PASSWORD, "examAdmin2") - .withFormParam(PasswordChange.ATTR_NAME_CONFIRM_NEW_PASSWORD, "examAdmin2") - .withFormParam(Domain.USER.ATTR_LANGUAGE, Locale.ENGLISH.getLanguage()) - .withFormParam(Domain.USER.ATTR_TIMEZONE, DateTimeZone.UTC.getID()) - .call(); - - assertNotNull(result); - assertFalse(result.hasError()); - - Result activation = restService.getBuilder(ActivateUserAccount.class) - .withURIVariable(API.PARAM_MODEL_ID, result.get().uuid) - .call(); - assertNotNull(activation); - assertFalse(activation.hasError()); - - result = restService.getBuilder(NewUserAccount.class) - .withFormParam(Domain.USER.ATTR_INSTITUTION_ID, instId) - .withFormParam(Domain.USER.ATTR_NAME, "examSupport2") - .withFormParam(Domain.USER.ATTR_USERNAME, "examSupport2") - .withFormParam(Domain.USER.ATTR_EMAIL, "test@test.ch") - .withFormParam(Domain.USER_ROLE.REFERENCE_NAME, UserRole.EXAM_SUPPORTER.name()) - .withFormParam(PasswordChange.ATTR_NAME_NEW_PASSWORD, "examSupport2") - .withFormParam(PasswordChange.ATTR_NAME_CONFIRM_NEW_PASSWORD, "examSupport2") - .withFormParam(Domain.USER.ATTR_LANGUAGE, Locale.ENGLISH.getLanguage()) - .withFormParam(Domain.USER.ATTR_TIMEZONE, DateTimeZone.UTC.getID()) - .call(); - - assertNotNull(result); - assertFalse(result.hasError()); - - activation = restService.getBuilder(ActivateUserAccount.class) - .withURIVariable(API.PARAM_MODEL_ID, result.get().uuid) - .call(); - assertNotNull(activation); - assertFalse(activation.hasError()); - - result = restService.getBuilder(NewUserAccount.class) - .withFormParam(Domain.USER.ATTR_INSTITUTION_ID, instId) - .withFormParam(Domain.USER.ATTR_NAME, "examSupport1") - .withFormParam(Domain.USER.ATTR_USERNAME, "examSupport1") - .withFormParam(Domain.USER.ATTR_EMAIL, "test@test.ch") - .withFormParam(Domain.USER_ROLE.REFERENCE_NAME, UserRole.EXAM_SUPPORTER.name()) - .withFormParam(PasswordChange.ATTR_NAME_NEW_PASSWORD, "examSupport1") - .withFormParam(PasswordChange.ATTR_NAME_CONFIRM_NEW_PASSWORD, "examSupport1") - .withFormParam(Domain.USER.ATTR_LANGUAGE, Locale.ENGLISH.getLanguage()) - .withFormParam(Domain.USER.ATTR_TIMEZONE, DateTimeZone.UTC.getID()) - .call(); - - assertNotNull(result); - assertFalse(result.hasError()); - - activation = restService.getBuilder(ActivateUserAccount.class) - .withURIVariable(API.PARAM_MODEL_ID, result.get().uuid) - .call(); - assertNotNull(activation); - assertFalse(activation.hasError()); - - } - - @Test - @Order(5) - // ************************************* - // Use Case 5: Login as TestInstAdmin and create new LMS Mockup and activate - // - login as TestInstAdmin : 987654321 - // - check there are no LMS Setup and Quizzes currently available for the user - // - create new LMS Setup Mockup (no activation) - // - check the LMS Setup was created but there are still no quizzes available - // - activate LMS Setup - // - check now active and quizzes are available - // - change name of active LMS and check modification update - // - deactivate LMS Setup and check no quizzes are available - // - activate again for following tests - public void testUsecase5() { - final RestServiceImpl restService = createRestServiceForUser( - "TestInstAdmin", - "987654321", - new NewLmsSetup(), - new GetLmsSetupNames(), - new GetLmsSetup(), - new SaveLmsSetup(), - new ActivateLmsSetup(), - new DeactivateLmsSetup(), - new GetQuizPage()); - - // check there are currently no LMS Setup defined for this user - Result> lmsNames = restService - .getBuilder(GetLmsSetupNames.class) - .call(); - assertNotNull(lmsNames); - assertFalse(lmsNames.hasError()); - List list = lmsNames.get(); - assertTrue(list.isEmpty()); - - // check also there are currently no quizzes available for this user - Result> quizPageCall = restService - .getBuilder(GetQuizPage.class) - .call(); - assertNotNull(quizPageCall); - assertFalse(quizPageCall.hasError()); - Page quizPage = quizPageCall.get(); - assertTrue(quizPage.isEmpty()); - - // create new LMS Setup Mockup - Result newLMSCall = restService - .getBuilder(NewLmsSetup.class) - .withFormParam(Domain.LMS_SETUP.ATTR_NAME, "Test LMS Mockup") - .withFormParam(Domain.LMS_SETUP.ATTR_LMS_TYPE, LmsType.MOCKUP.name()) - .withFormParam(Domain.LMS_SETUP.ATTR_LMS_URL, "http://") - .withFormParam(Domain.LMS_SETUP.ATTR_LMS_CLIENTNAME, "test") - .withFormParam(Domain.LMS_SETUP.ATTR_LMS_CLIENTSECRET, "test") - .call(); - - assertNotNull(newLMSCall); - assertFalse(newLMSCall.hasError()); - LmsSetup lmsSetup = newLMSCall.get(); - assertEquals("Test LMS Mockup", lmsSetup.name); - assertFalse(lmsSetup.isActive()); - - // check is available now - lmsNames = restService - .getBuilder(GetLmsSetupNames.class) - .call(); - - assertNotNull(lmsNames); - assertFalse(lmsNames.hasError()); - list = lmsNames.get(); - assertFalse(list.isEmpty()); - - // check still no quizzes available form the LMS (not active now) - quizPageCall = restService - .getBuilder(GetQuizPage.class) - .call(); - assertNotNull(quizPageCall); - assertFalse(quizPageCall.hasError()); - quizPage = quizPageCall.get(); - assertTrue(quizPage.isEmpty()); - - // activate lms setup - Result activation = restService - .getBuilder(ActivateLmsSetup.class) - .withURIVariable(API.PARAM_MODEL_ID, lmsSetup.getModelId()) - .call(); - - assertNotNull(activation); - assertFalse(activation.hasError()); - - // check lms setup is now active - newLMSCall = restService - .getBuilder(GetLmsSetup.class) - .withURIVariable(API.PARAM_MODEL_ID, lmsSetup.getModelId()) - .call(); - - assertNotNull(newLMSCall); - assertFalse(newLMSCall.hasError()); - lmsSetup = newLMSCall.get(); - assertEquals("Test LMS Mockup", lmsSetup.name); - assertTrue(lmsSetup.isActive()); - - // check quizzes are available now - quizPageCall = restService - .getBuilder(GetQuizPage.class) - .call(); - assertNotNull(quizPageCall); - assertFalse(quizPageCall.hasError()); - quizPage = quizPageCall.get(); - assertFalse(quizPage.isEmpty()); - - // change the name of LMS Setup and check modification update - newLMSCall = restService - .getBuilder(SaveLmsSetup.class) - .withBody(new LmsSetup( - lmsSetup.id, - lmsSetup.institutionId, - "Test LMS Name Changed", - lmsSetup.lmsType, - lmsSetup.lmsAuthName, - lmsSetup.lmsAuthSecret, - lmsSetup.lmsApiUrl, - lmsSetup.lmsRestApiToken, - lmsSetup.proxyHost, - lmsSetup.proxyPort, - lmsSetup.proxyAuthUsername, - lmsSetup.proxyAuthSecret, - lmsSetup.active)) - .call(); - - assertNotNull(newLMSCall); - assertFalse(newLMSCall.hasError()); - lmsSetup = newLMSCall.get(); - assertEquals("Test LMS Name Changed", lmsSetup.name); - assertTrue(lmsSetup.isActive()); - - // check quizzes are still available - quizPageCall = restService - .getBuilder(GetQuizPage.class) - .call(); - assertNotNull(quizPageCall); - assertFalse(quizPageCall.hasError()); - quizPage = quizPageCall.get(); - assertFalse(quizPage.isEmpty()); - - // deactivate - final Result deactivation = restService - .getBuilder(DeactivateLmsSetup.class) - .withURIVariable(API.PARAM_MODEL_ID, lmsSetup.getModelId()) - .call(); - - assertNotNull(deactivation); - assertFalse(deactivation.hasError()); - - // check lms setup is now active - newLMSCall = restService - .getBuilder(GetLmsSetup.class) - .withURIVariable(API.PARAM_MODEL_ID, lmsSetup.getModelId()) - .call(); - - assertNotNull(newLMSCall); - assertFalse(newLMSCall.hasError()); - lmsSetup = newLMSCall.get(); - assertEquals("Test LMS Name Changed", lmsSetup.name); - assertFalse(lmsSetup.isActive()); - - // check quizzes are not available anymore - quizPageCall = restService - .getBuilder(GetQuizPage.class) - .call(); - assertNotNull(quizPageCall); - assertFalse(quizPageCall.hasError()); - quizPage = quizPageCall.get(); - assertTrue(quizPage.isEmpty()); - - // activate LMS Setup again for following tests - activation = restService - .getBuilder(ActivateLmsSetup.class) - .withURIVariable(API.PARAM_MODEL_ID, lmsSetup.getModelId()) - .call(); - - assertNotNull(activation); - assertFalse(activation.hasError()); - - // check lms setup is now active - newLMSCall = restService - .getBuilder(GetLmsSetup.class) - .withURIVariable(API.PARAM_MODEL_ID, lmsSetup.getModelId()) - .call(); - } - - @Test - @Order(6) - // ************************************* - // Use Case 6: Login as examAdmin2 - // - Check if there are some quizzes form previous LMS Setup - // - Import a quiz as Exam - // - get exam page and check the exam is there - // - edit exam property and save again - public void testUsecase6() { - final RestServiceImpl restService = createRestServiceForUser( - "examAdmin2", - "examAdmin2", - new GetUserAccountNames(), - new NewLmsSetup(), - new GetQuizPage(), - new GetQuizData(), - new ImportAsExam(), - new SaveExam(), - new GetExam(), - new GetExamPage()); - - final Result> userNamesResult = restService - .getBuilder(GetUserAccountNames.class) - .call(); - - assertNotNull(userNamesResult); - assertFalse(userNamesResult.hasError()); - - final String userId = userNamesResult.get() - .stream() - .filter(userName -> "examSupport2".equals(userName.name)) - .findFirst() - .map(EntityName::getModelId) - .orElse(null); - - // check quizzes are defines - final Result> quizPageCall = restService - .getBuilder(GetQuizPage.class) - .call(); - - assertNotNull(quizPageCall); - assertFalse(quizPageCall.hasError()); - final Page quizzes = quizPageCall.get(); - assertFalse(quizzes.isEmpty()); - final QuizData quizData = quizzes.content.get(0); - assertNotNull(quizData); - assertEquals("Demo Quiz 1 (MOCKUP)", quizData.name); - - // import quiz as exam - final Result newExamResult = restService - .getBuilder(ImportAsExam.class) - .withFormParam(QuizData.QUIZ_ATTR_LMS_SETUP_ID, String.valueOf(quizData.lmsSetupId)) - .withFormParam(QuizData.QUIZ_ATTR_ID, quizData.id) - .withFormParam(Domain.EXAM.ATTR_SUPPORTER, userId) - .call(); - - assertNotNull(newExamResult); - assertFalse(newExamResult.hasError()); - final Exam newExam = newExamResult.get(); - - assertEquals("Demo Quiz 1 (MOCKUP)", newExam.name); - assertEquals(ExamType.UNDEFINED, newExam.type); - assertFalse(newExam.supporter.isEmpty()); - - // create Exam with type and supporter examSupport2 - final Exam examForSave = new Exam( - newExam.id, - newExam.institutionId, - newExam.lmsSetupId, - newExam.externalId, - newExam.name, - newExam.description, - newExam.startTime, - newExam.endTime, - newExam.startURL, - ExamType.MANAGED, - null, null, - Utils.immutableCollectionOf(userId), - ExamStatus.RUNNING, - true, - null, - true, - null); - - final Result savedExamResult = restService - .getBuilder(SaveExam.class) - .withBody(examForSave) - .call(); - - assertNotNull(savedExamResult); - assertFalse(savedExamResult.hasError()); - final Exam savedExam = savedExamResult.get(); - - assertEquals(ExamType.MANAGED, savedExam.type); - assertFalse(savedExam.supporter.isEmpty()); - } - - @Test - @Order(7) - // ************************************* - // Use Case 7: Login as examAdmin2 - // - Get imported exam - // - add new indicator for exam - // - save exam with new indicator and test - // - create some thresholds for the new indicator - public void testUsecase7() { - final RestServiceImpl restService = createRestServiceForUser( - "examAdmin2", - "examAdmin2", - new GetExam(), - new GetExamNames(), - new NewIndicator(), - new SaveIndicator(), - new GetIndicator(), - new GetIndicatorPage()); - - final Result> examNamesResult = restService - .getBuilder(GetExamNames.class) - .call(); - - assertNotNull(examNamesResult); - assertFalse(examNamesResult.hasError()); - final List exams = examNamesResult.get(); - assertFalse(exams.isEmpty()); - final EntityName examName = exams.get(0); - assertEquals("Demo Quiz 1 (MOCKUP)", examName.name); - - final Result examResult = restService - .getBuilder(GetExam.class) - .withURIVariable(API.PARAM_MODEL_ID, examName.modelId) - .call(); - - assertNotNull(examResult); - assertFalse(examResult.hasError()); - final Exam exam = examResult.get(); - - final Result newIndicatorResult = restService - .getBuilder(NewIndicator.class) - .withFormParam(Domain.INDICATOR.ATTR_EXAM_ID, exam.getModelId()) - .withFormParam(Domain.INDICATOR.ATTR_NAME, "Ping") - .withFormParam(Domain.INDICATOR.ATTR_TYPE, IndicatorType.LAST_PING.name) - .withFormParam(Domain.INDICATOR.ATTR_COLOR, "000001") - .call(); - - assertNotNull(newIndicatorResult); - assertFalse(newIndicatorResult.hasError()); - final Indicator newIndicator = newIndicatorResult.get(); - - assertEquals("Ping", newIndicator.name); - assertEquals("000001", newIndicator.defaultColor); - - final Indicator indicatorToSave = new Indicator( - newIndicator.id, newIndicator.examId, newIndicator.name, newIndicator.type, newIndicator.defaultColor, - Utils.immutableCollectionOf( - new Indicator.Threshold(2000d, "000011"), - new Indicator.Threshold(5000d, "001111"))); - - final Result savedIndicatorResult = restService - .getBuilder(SaveIndicator.class) - .withBody(indicatorToSave) - .call(); - - assertNotNull(savedIndicatorResult); - assertFalse(savedIndicatorResult.hasError()); - final Indicator savedIndicator = savedIndicatorResult.get(); - - assertEquals("Ping", savedIndicator.name); - assertEquals("000001", savedIndicator.defaultColor); - final Collection thresholds = savedIndicator.getThresholds(); - assertFalse(thresholds.isEmpty()); - assertTrue(thresholds.size() == 2); - final Iterator iterator = thresholds.iterator(); - final Threshold t1 = iterator.next(); - final Threshold t2 = iterator.next(); - - assertTrue(2000d - t1.value < .0001); - assertEquals("000011", t1.color); - assertTrue(5000d - t2.value < .0001); - assertEquals("001111", t2.color); - } - - @Test - @Order(8) - // ************************************* - // Use Case 8: Login as TestInstAdmin and create a SEB Client Configuration - // - create one with and one without password - // - activate one config - // - export both configurations - public void testUsecase8() throws IOException { - final RestServiceImpl restService = createRestServiceForUser( - "TestInstAdmin", - "987654321", - new GetClientConfig(), - new GetClientConfigPage(), - new NewClientConfig(), - new SaveClientConfig(), - new ActivateClientConfig(), - new DeactivateClientConfig(), - new ExportClientConfig()); - - // create SEB Client Config without password protection - final Result newConfigResponse = restService - .getBuilder(NewClientConfig.class) - .withFormParam(Domain.SEB_CLIENT_CONFIGURATION.ATTR_NAME, "No Password Protection") - .withFormParam(SebClientConfig.ATTR_FALLBACK_START_URL, "http://fallback.com/fallback") - .call(); - - assertNotNull(newConfigResponse); - assertFalse(newConfigResponse.hasError()); - final SebClientConfig sebClientConfig = newConfigResponse.get(); - assertEquals("No Password Protection", sebClientConfig.name); - assertFalse(sebClientConfig.isActive()); - assertEquals("http://fallback.com/fallback", sebClientConfig.fallbackStartURL); - - // activate the new Client Configuration - final Result activationResponse = restService - .getBuilder(ActivateClientConfig.class) - .withURIVariable(API.PARAM_MODEL_ID, sebClientConfig.getModelId()) - .call(); - - assertNotNull(activationResponse); - assertFalse(activationResponse.hasError()); - - final Result getConfigResponse = restService - .getBuilder(GetClientConfig.class) - .withURIVariable(API.PARAM_MODEL_ID, sebClientConfig.getModelId()) - .call(); - - assertNotNull(getConfigResponse); - assertFalse(getConfigResponse.hasError()); - final SebClientConfig activeConfig = getConfigResponse.get(); - assertTrue(activeConfig.isActive()); - - // create a config with password protection - final Result configWithPasswordResponse = restService - .getBuilder(NewClientConfig.class) - .withFormParam(Domain.SEB_CLIENT_CONFIGURATION.ATTR_NAME, "With Password Protection") - .withFormParam(SebClientConfig.ATTR_FALLBACK_START_URL, "http://fallback.com/fallback") - .withFormParam(SEB_CLIENT_CONFIGURATION.ATTR_ENCRYPT_SECRET, "123") - .withFormParam(SebClientConfig.ATTR_CONFIRM_ENCRYPT_SECRET, "123") - .call(); - - assertNotNull(configWithPasswordResponse); - assertFalse(configWithPasswordResponse.hasError()); - final SebClientConfig configWithPassword = configWithPasswordResponse.get(); - assertEquals("With Password Protection", configWithPassword.name); - assertFalse(configWithPassword.isActive()); - assertEquals("http://fallback.com/fallback", configWithPassword.fallbackStartURL); - - // export client config No Password Protection - Result exportResponse = restService - .getBuilder(ExportClientConfig.class) - .withURIVariable(API.PARAM_MODEL_ID, sebClientConfig.getModelId()) - .call(); - - assertNotNull(exportResponse); - assertFalse(exportResponse.hasError()); - - List readLines = IOUtils.readLines(exportResponse.get(), "UTF-8"); - assertNotNull(readLines); - assertFalse(readLines.isEmpty()); - assertTrue(readLines.get(0).startsWith("plnd")); - - // export client config With Password Protection - exportResponse = restService - .getBuilder(ExportClientConfig.class) - .withURIVariable(API.PARAM_MODEL_ID, configWithPassword.getModelId()) - .call(); - - assertNotNull(exportResponse); - assertFalse(exportResponse.hasError()); - - readLines = IOUtils.readLines(exportResponse.get(), "UTF-8"); - assertNotNull(readLines); - assertFalse(readLines.isEmpty()); - assertTrue(readLines.get(0).startsWith("pswd")); - - // get page - final Result> pageResponse = restService - .getBuilder(GetClientConfigPage.class) - .call(); - - assertNotNull(pageResponse); - assertFalse(pageResponse.hasError()); - final Page page = pageResponse.get(); - assertFalse(page.content.isEmpty()); - assertTrue(page.content.size() == 2); - } - - @Test - @Order(9) - // ************************************* - // Use Case 9: Login as examAdmin2 and test Exam Configuration data basis - // - get all Views for the default template - // - get all Attributes and and Orientations for the default view - @Sql(scripts = { "classpath:data-test-additional.sql" }) - public void testUsecase9() throws IOException { - final RestServiceImpl restService = createRestServiceForUser( - "examAdmin2", - "examAdmin2", - new GetViewList(), - new GetConfigAttributes(), - new GetOrientations(), - new GetOrientationPage()); - - final ExamConfigurationServiceImpl examConfigurationService = new ExamConfigurationServiceImpl( - restService, - new JSONMapper(), - null, null, - Collections.emptyList()); - - final Result attributes = examConfigurationService.getAttributes(0l); - assertNotNull(attributes); - assertFalse(attributes.hasError()); - final AttributeMapping attributeMapping = attributes.get(); - assertEquals(192, attributeMapping.attributeIdMapping.size()); - assertEquals("[active, audio, backToStart, browserSecurity, browserViewMode, " - + "exitSequence, functionKeys, kioskMode, logging, macSettings, " - + "newBrowserWindow, newwinsize, proxies, quitLink, registry, " - + "servicePolicy, specialKeys, spellcheck, taskbar, urlFilter, " - + "userAgentDesktop, userAgentMac, userAgentTouch, winsize, wintoolbar, zoom, zoomMode]", - attributeMapping.attributeGroupMapping.keySet() - .stream() - .sorted() - .collect(Collectors.toList()) - .toString()); - - final String viewIds = StringUtils.join(attributeMapping.getViewIds().stream().map(String::valueOf) - .collect(Collectors.toList()), - Constants.LIST_SEPARATOR_CHAR); - - assertEquals("1,2,3,4,5,6,8,9,10,11", viewIds); - final Result> viewsResponse = restService - .getBuilder(GetViewList.class) - .withQueryParam(API.PARAM_MODEL_ID_LIST, viewIds) - .call(); - - assertNotNull(viewsResponse); - assertFalse(viewsResponse.hasError()); - } - - @Test - @Order(10) - // ************************************* - // Use Case 10: Login as examAdmin2 and create a new SEB Exam Configuration - // - test creation - // - save configuration in history - // - change some attribute - // - process an undo - public void testUsecase10() throws IOException { - final RestServiceImpl restService = createRestServiceForUser( - "examAdmin2", - "examAdmin2", - new NewExamConfig(), - new GetExamConfigNode(), - new GetExamConfigNodePage(), - new GetConfigurationPage(), - new GetConfigurations(), - new SaveExamConfigHistory(), - new GetConfigurationTableValues(), - new SebExamConfigUndo(), - new SaveExamConfigValue(), - new SaveExamConfigTableValues(), - new GetConfigurationValuePage(), - new GetConfigurationValues(), - new GetConfigAttributes(), - new GetUserAccountNames()); - - // get user id - final String userId = restService - .getBuilder(GetUserAccountNames.class) - .call() - .getOrThrow() - .stream() - .filter(userName -> "examAdmin2".equals(userName.name)) - .map(EntityName::getModelId) - .findFirst() - .orElse(null); - - assertNotNull(userId); - - // get configuration page - final Result> pageResponse = restService - .getBuilder(GetExamConfigNodePage.class) - .call(); - - // there should be not configuration (for this institution of examAdmin2) now - assertNotNull(pageResponse); - assertFalse(pageResponse.hasError()); - final Page page = pageResponse.get(); - assertTrue(page.content.isEmpty()); - - final Result newConfigResponse = restService - .getBuilder(NewExamConfig.class) - .withFormParam(Domain.CONFIGURATION_NODE.ATTR_NAME, "New Exam Config") - .withFormParam(Domain.CONFIGURATION_NODE.ATTR_DESCRIPTION, "This is a New Exam Config") - .call(); - - assertNotNull(newConfigResponse); - assertFalse(newConfigResponse.hasError()); - final ConfigurationNode newConfig = newConfigResponse.get(); - assertEquals("New Exam Config", newConfig.name); - assertEquals(Long.valueOf(0), newConfig.templateId); - assertEquals(userId, newConfig.owner); - - // get follow-up configuration - Result> configHistoryResponse = restService - .getBuilder(GetConfigurations.class) - .withQueryParam(Configuration.FILTER_ATTR_CONFIGURATION_NODE_ID, newConfig.getModelId()) - .call(); - - assertNotNull(configHistoryResponse); - assertFalse(configHistoryResponse.hasError()); - List configHistory = configHistoryResponse.get(); - assertFalse(configHistory.isEmpty()); - assertTrue(2 == configHistory.size()); - final Configuration initConfig = configHistory.get(0); - Configuration followup = configHistory.get(1); - assertEquals("v0", initConfig.version); - assertFalse(initConfig.followup); - assertNull(followup.version); - assertTrue(followup.followup); - - // get all configuration values - Result> valuesResponse = restService - .getBuilder(GetConfigurationValues.class) - .withQueryParam(ConfigurationValue.FILTER_ATTR_CONFIGURATION_ID, followup.getModelId()) - .call(); - - assertNotNull(valuesResponse); - assertFalse(valuesResponse.hasError()); - List values = valuesResponse.get(); - assertFalse(values.isEmpty()); - - UsecaseTestUtils.testProhibitedProcessesInit( - followup.getModelId(), - restService); - UsecaseTestUtils.testPermittedProcessesInit( - followup.getModelId(), - restService); - - // update a value -- grab first - final ConfigurationValue value = values.get(0); - ConfigurationValue newValue = new ConfigurationValue( - null, value.institutionId, value.configurationId, - value.attributeId, value.listIndex, "2"); - Result newValueResponse = restService - .getBuilder(SaveExamConfigValue.class) - .withBody(newValue) - .call(); - - assertNotNull(newValueResponse); - assertFalse(newValueResponse.hasError()); - ConfigurationValue savedValue = newValueResponse.get(); - assertEquals("2", savedValue.value); - - // save to history - final Result saveHistoryResponse = restService - .getBuilder(SaveExamConfigHistory.class) - .withURIVariable(API.PARAM_MODEL_ID, followup.getModelId()) - .call(); - - assertNotNull(saveHistoryResponse); - assertFalse(saveHistoryResponse.hasError()); - Configuration configuration = saveHistoryResponse.get(); - assertTrue(configuration.followup); - - configHistoryResponse = restService - .getBuilder(GetConfigurations.class) - .withQueryParam(Configuration.FILTER_ATTR_CONFIGURATION_NODE_ID, newConfig.getModelId()) - .call(); - - assertNotNull(configHistoryResponse); - assertFalse(configHistoryResponse.hasError()); - configHistory = configHistoryResponse.get(); - assertFalse(configHistory.isEmpty()); - assertTrue(3 == configHistory.size()); - - configHistoryResponse = restService - .getBuilder(GetConfigurations.class) - .withQueryParam(Configuration.FILTER_ATTR_CONFIGURATION_NODE_ID, newConfig.getModelId()) - .withQueryParam(Configuration.FILTER_ATTR_FOLLOWUP, "true") - .call(); - - assertNotNull(configHistoryResponse); - assertFalse(configHistoryResponse.hasError()); - followup = configHistoryResponse.get().get(0); - assertNotNull(followup); - assertTrue(followup.followup); - - // change value again - newValue = new ConfigurationValue( - null, value.institutionId, followup.id, - value.attributeId, value.listIndex, "3"); - newValueResponse = restService - .getBuilder(SaveExamConfigValue.class) - .withBody(newValue) - .call(); - - assertNotNull(newValueResponse); - assertFalse(newValueResponse.hasError()); - savedValue = newValueResponse.get(); - assertEquals("3", savedValue.value); - - // get current value - valuesResponse = restService - .getBuilder(GetConfigurationValues.class) - .withQueryParam(ConfigurationValue.FILTER_ATTR_CONFIGURATION_ID, followup.getModelId()) - .call(); - - assertNotNull(valuesResponse); - assertFalse(valuesResponse.hasError()); - values = valuesResponse.get(); - assertFalse(values.isEmpty()); - assertNotNull(newValueResponse); - assertFalse(newValueResponse.hasError()); - savedValue = newValueResponse.get(); - assertEquals("3", savedValue.value); - - // undo - final Result undoResponse = restService - .getBuilder(SebExamConfigUndo.class) - .withURIVariable(API.PARAM_MODEL_ID, followup.getModelId()) - .call(); - - assertNotNull(undoResponse); - assertFalse(undoResponse.hasError()); - configuration = undoResponse.get(); - assertTrue(configuration.followup); - - // check value has been reset - valuesResponse = restService - .getBuilder(GetConfigurationValues.class) - .withQueryParam(ConfigurationValue.FILTER_ATTR_CONFIGURATION_ID, configuration.getModelId()) - .call(); - - assertNotNull(valuesResponse); - assertFalse(valuesResponse.hasError()); - values = valuesResponse.get(); - final ConfigurationValue currentValue = - values.stream().filter(v -> v.attributeId == value.attributeId).findFirst().orElse(null); - assertNotNull(currentValue); - assertEquals("2", currentValue.value); - } - - @Test - @Order(11) - // ************************************* - // Use Case 11: Login as examAdmin2 and get newly created exam configuration - // - get permitted processes table values - // - modify permitted processes table values - // - save permitted processes table values - // - check save OK - public void testUsecase11() throws IOException { - final RestServiceImpl restService = createRestServiceForUser( - "examAdmin2", - "examAdmin2", - new GetConfigAttributes(), - new GetExamConfigNodePage(), - new GetConfigurations(), - new GetConfigurationPage(), - new SaveExamConfigHistory(), - new GetConfigurationTableValues(), - new SaveExamConfigTableValues()); - - // get configuration page - final Result> pageResponse = restService - .getBuilder(GetExamConfigNodePage.class) - .call(); - - assertNotNull(pageResponse); - assertFalse(pageResponse.hasError()); - final Page page = pageResponse.get(); - assertFalse(page.content.isEmpty()); - - final ConfigurationNode configurationNode = page.content.get(0); - assertEquals("New Exam Config", configurationNode.name); - - // get follow-up configuration - final Result> configHistoryResponse = restService - .getBuilder(GetConfigurations.class) - .withQueryParam(Configuration.FILTER_ATTR_CONFIGURATION_NODE_ID, configurationNode.getModelId()) - .call(); - - final List configHistory = configHistoryResponse.get(); - final Configuration followup = configHistory - .stream() - .filter(config -> BooleanUtils.isTrue(config.followup)) - .findFirst() - .orElseThrow(() -> new RuntimeException("Followup Node not found")); - - final ConfigurationTableValues permittedProcessValues = UsecaseTestUtils.getTableValues( - "73", - followup.getModelId(), - restService); - - assertNotNull(permittedProcessValues); - assertFalse(permittedProcessValues.values.isEmpty()); - - // get all configuration attributes - final Map attributes = restService - .getBuilder(GetConfigAttributes.class) - .call() - .getOrThrow() - .stream() - .collect(Collectors.toMap(attr -> attr.id, Function.identity())); - - // create new row by copy the values - final List newTableValues = permittedProcessValues.values - .stream() - .map(attr -> new TableValue(attr.attributeId, 1, attributes.get(attr.attributeId).defaultValue)) - .collect(Collectors.toList()); - newTableValues.addAll(permittedProcessValues.values); - - // test institutional integrity violation - try { - final ConfigurationTableValues newTableValue = new ConfigurationTableValues( - 1000L, - followup.id, - 73L, - newTableValues); - - restService.getBuilder(SaveExamConfigTableValues.class) - .withBody(newTableValue) - .call() - .getOrThrow(); - - fail("Exception expected here"); - } catch (final Exception e) { - assertEquals("Unexpected error while rest call", e.getMessage()); - } - - // test follow-up integrity violation - try { - final ConfigurationTableValues newTableValue = new ConfigurationTableValues( - configHistory.get(0).id, - followup.id, - 73L, - newTableValues); - - restService.getBuilder(SaveExamConfigTableValues.class) - .withBody(newTableValue) - .call() - .getOrThrow(); - - fail("Exception expected here"); - } catch (final Exception e) { - assertEquals("Unexpected error while rest call", e.getMessage()); - } - - final ConfigurationTableValues newTableValue = new ConfigurationTableValues( - followup.institutionId, - followup.id, - 73L, - newTableValues); - - final ConfigurationTableValues savedValues = restService.getBuilder(SaveExamConfigTableValues.class) - .withBody(newTableValue) - .call() - .getOrThrow(); - - assertNotNull(savedValues); - assertFalse(savedValues.values.isEmpty()); - assertTrue(savedValues.values.size() == newTableValues.size()); - } - - @Test - @Order(12) - // ************************************* - // Use Case 12: Login as examAdmin2 and use newly created configuration - // - get follow-up configuration by API - // - import - // - export - public void testUsecase12() throws IOException { - final RestServiceImpl restService = createRestServiceForUser( - "examAdmin2", - "examAdmin2", - new GetConfigAttributes(), - new GetExamConfigNodePage(), - new SaveExamConfigHistory(), - new ExportExamConfig(), - new ImportNewExamConfig(), - new ImportExamConfigOnExistingConfig(), - new ExportPlainXML(), - new GetFollowupConfiguration()); - - // get all configuration attributes - final Collection attributes = restService - .getBuilder(GetConfigAttributes.class) - .call() - .getOrThrow() - .stream() - .collect(Collectors.toList()); - - // get configuration page - final Result> pageResponse = restService - .getBuilder(GetExamConfigNodePage.class) - .call(); - - assertNotNull(pageResponse); - assertFalse(pageResponse.hasError()); - final Page page = pageResponse.get(); - assertFalse(page.content.isEmpty()); - - final ConfigurationNode configurationNode = page.content.get(0); - assertEquals("New Exam Config", configurationNode.name); - - final Configuration followup = restService - .getBuilder(GetFollowupConfiguration.class) - .withURIVariable(API.PARAM_MODEL_ID, configurationNode.getModelId()) - .call() - .getOrThrow(); - - assertNotNull(followup); - assertTrue(followup.followup); - - // export1 - final InputStream input = restService - .getBuilder(ExportPlainXML.class) - .withURIVariable(API.PARAM_MODEL_ID, configurationNode.getModelId()) - .call() - .getOrThrow(); - - final String xmlString = StreamUtils.copyToString(input, Charsets.UTF_8); - assertNotNull(xmlString); - for (final ConfigurationAttribute attribute : attributes) { - if (attribute.name.contains(".") || attribute.name.equals("kioskMode")) { - continue; - } - if (!xmlString.contains(attribute.name)) { - fail("missing attribute: " + attribute.name); - } - } - - // import plain config - InputStream inputStream = new ClassPathResource("importTest.seb").getInputStream(); - Configuration importedConfig = restService - .getBuilder(ImportNewExamConfig.class) - .withBody(inputStream) - .withHeader(Domain.CONFIGURATION_NODE.ATTR_NAME, "Imported Test Configuration") - .call() - .getOrThrow(); - - assertNotNull(importedConfig); - - // import with the same name should cause an exception - try { - restService - .getBuilder(ImportNewExamConfig.class) - .withBody(inputStream) - .withHeader(Domain.CONFIGURATION_NODE.ATTR_NAME, "Imported Test Configuration") - .withHeader(API.IMPORT_PASSWORD_ATTR_NAME, "123") - .call() - .getOrThrow(); - fail("Expecting an exception here"); - } catch (final Exception e) { - - } - - // import encrypted config with password encryption - inputStream = new ClassPathResource("importTest_123.seb").getInputStream(); - importedConfig = restService - .getBuilder(ImportNewExamConfig.class) - .withBody(inputStream) - .withHeader(Domain.CONFIGURATION_NODE.ATTR_NAME, "Imported Encrypted Test Configuration") - .withHeader(API.IMPORT_PASSWORD_ATTR_NAME, "123") - .call() - .getOrThrow(); - - assertNotNull(importedConfig); - - // import config within existing configuration - inputStream = new ClassPathResource("importTest.seb").getInputStream(); - importedConfig = restService - .getBuilder(ImportExamConfigOnExistingConfig.class) - .withBody(inputStream) - .withURIVariable(API.PARAM_MODEL_ID, String.valueOf(importedConfig.getConfigurationNodeId())) - .call() - .getOrThrow(); - } - - @Test - @Order(13) - // ************************************* - // Use Case 13: Login as examAdmin2 and use newly created configuration - // - change configuration status to "Ready to Use" - public void testUsecase13() throws IOException { - final RestServiceImpl restService = createRestServiceForUser( - "examAdmin2", - "examAdmin2", - new GetConfigAttributes(), - new GetExamConfigNodePage(), - new SaveExamConfig()); - - // get configuration from page - final ConfigurationNode config = restService - .getBuilder(GetExamConfigNodePage.class) - .call() - .getOrThrow().content - .get(0); - assertEquals("New Exam Config", config.name); - - final ConfigurationNode newConfig = new ConfigurationNode( - config.id, - config.institutionId, - config.templateId, - config.name, - config.description, - ConfigurationType.EXAM_CONFIG, - config.owner, - ConfigurationStatus.READY_TO_USE); - - final ConfigurationNode savedConfig = restService - .getBuilder(SaveExamConfig.class) - .withBody(newConfig) - .call() - .getOrThrow(); - - assertTrue(savedConfig.status == ConfigurationStatus.READY_TO_USE); - } - - @Test - @Order(15) - // ************************************* - // Use Case 15: Login as examAdmin2 and get views and orientations - // - test Views API - public void testUsecase15() throws IOException { - final RestServiceImpl restService = createRestServiceForUser( - "examAdmin2", - "examAdmin2", - new GetViews(), - new GetViewPage(), - new GetOrientationPage(), - new GetOrientations()); - - final List views = restService - .getBuilder(GetViews.class) - .call() - .getOrThrow(); - - assertNotNull(views); - assertTrue(views.size() == 11); - - final List orientations = restService - .getBuilder(GetOrientations.class) - .call() - .getOrThrow(); - - assertNotNull(orientations); - } - -} +/* + * Copyright (c) 2019 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.integration; + +import static org.junit.Assert.*; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; + +import org.apache.commons.codec.Charsets; +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.BooleanUtils; +import org.apache.tomcat.util.buf.StringUtils; +import org.joda.time.DateTimeZone; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.springframework.core.annotation.Order; +import org.springframework.core.io.ClassPathResource; +import org.springframework.test.context.jdbc.Sql; +import org.springframework.util.StreamUtils; + +import ch.ethz.seb.sebserver.gbl.Constants; +import ch.ethz.seb.sebserver.gbl.api.API; +import ch.ethz.seb.sebserver.gbl.api.JSONMapper; +import ch.ethz.seb.sebserver.gbl.model.Domain; +import ch.ethz.seb.sebserver.gbl.model.Domain.SEB_CLIENT_CONFIGURATION; +import ch.ethz.seb.sebserver.gbl.model.EntityName; +import ch.ethz.seb.sebserver.gbl.model.EntityProcessingReport; +import ch.ethz.seb.sebserver.gbl.model.Page; +import ch.ethz.seb.sebserver.gbl.model.exam.Exam; +import ch.ethz.seb.sebserver.gbl.model.exam.Exam.ExamStatus; +import ch.ethz.seb.sebserver.gbl.model.exam.Exam.ExamType; +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.exam.Indicator.Threshold; +import ch.ethz.seb.sebserver.gbl.model.exam.QuizData; +import ch.ethz.seb.sebserver.gbl.model.institution.Institution; +import ch.ethz.seb.sebserver.gbl.model.institution.LmsSetup; +import ch.ethz.seb.sebserver.gbl.model.institution.LmsSetup.LmsType; +import ch.ethz.seb.sebserver.gbl.model.sebconfig.Configuration; +import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationAttribute; +import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationNode; +import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationNode.ConfigurationStatus; +import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationNode.ConfigurationType; +import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationTableValues; +import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationTableValues.TableValue; +import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationValue; +import ch.ethz.seb.sebserver.gbl.model.sebconfig.Orientation; +import ch.ethz.seb.sebserver.gbl.model.sebconfig.SebClientConfig; +import ch.ethz.seb.sebserver.gbl.model.sebconfig.View; +import ch.ethz.seb.sebserver.gbl.model.user.PasswordChange; +import ch.ethz.seb.sebserver.gbl.model.user.UserInfo; +import ch.ethz.seb.sebserver.gbl.model.user.UserRole; +import ch.ethz.seb.sebserver.gbl.util.Result; +import ch.ethz.seb.sebserver.gbl.util.Utils; +import ch.ethz.seb.sebserver.gui.service.examconfig.impl.AttributeMapping; +import ch.ethz.seb.sebserver.gui.service.examconfig.impl.ExamConfigurationServiceImpl; +import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCallError; +import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestServiceImpl; +import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.ExportExamConfig; +import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.GetExam; +import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.GetExamNames; +import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.GetExamPage; +import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.GetIndicator; +import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.GetIndicatorPage; +import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.NewIndicator; +import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.SaveExam; +import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.SaveIndicator; +import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.institution.ActivateInstitution; +import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.institution.GetInstitution; +import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.institution.GetInstitutionNames; +import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.institution.NewInstitution; +import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.lmssetup.ActivateLmsSetup; +import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.lmssetup.DeactivateLmsSetup; +import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.lmssetup.GetLmsSetup; +import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.lmssetup.GetLmsSetupNames; +import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.lmssetup.NewLmsSetup; +import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.lmssetup.SaveLmsSetup; +import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.quiz.GetQuizData; +import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.quiz.GetQuizPage; +import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.quiz.ImportAsExam; +import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.clientconfig.ActivateClientConfig; +import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.clientconfig.DeactivateClientConfig; +import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.clientconfig.ExportClientConfig; +import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.clientconfig.GetClientConfig; +import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.clientconfig.GetClientConfigPage; +import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.clientconfig.NewClientConfig; +import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.clientconfig.SaveClientConfig; +import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.ExportPlainXML; +import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.GetConfigAttributes; +import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.GetConfigurationPage; +import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.GetConfigurationTableValues; +import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.GetConfigurationValuePage; +import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.GetConfigurationValues; +import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.GetConfigurations; +import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.GetExamConfigNode; +import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.GetExamConfigNodePage; +import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.GetFollowupConfiguration; +import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.GetOrientationPage; +import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.GetOrientations; +import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.GetViewList; +import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.GetViewPage; +import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.GetViews; +import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.ImportExamConfigOnExistingConfig; +import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.ImportNewExamConfig; +import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.NewExamConfig; +import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.SaveExamConfig; +import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.SaveExamConfigHistory; +import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.SaveExamConfigTableValues; +import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.SaveExamConfigValue; +import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.SebExamConfigUndo; +import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.useraccount.ActivateUserAccount; +import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.useraccount.ChangePassword; +import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.useraccount.GetUserAccount; +import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.useraccount.GetUserAccountNames; +import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.useraccount.NewUserAccount; +import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.useraccount.SaveUserAccount; + +public class UseCasesIntegrationTest extends GuiIntegrationTest { + + @Before + @Sql(scripts = { "classpath:schema-test.sql", "classpath:data-test.sql" }) + public void init() { + + } + + @After + @Sql(scripts = { "classpath:schema-test.sql", "classpath:data-test.sql" }) + public void cleanup() { + + } + + @Test + @Order(1) + // ************************************* + // Use Case 1: SEB Administrator creates a new institution and activate this new institution + + public void testUsecase1() { + final RestServiceImpl restService = createRestServiceForUser( + "admin", + "admin", + new NewInstitution(), + new ActivateInstitution(), + new GetInstitution()); + + final Result result = restService.getBuilder(NewInstitution.class) + .withFormParam(Domain.INSTITUTION.ATTR_NAME, "Test Institution") + .call(); + + assertNotNull(result); + assertFalse(result.hasError()); + Institution institution = result.get(); + assertEquals("Test Institution", institution.name); + assertFalse(institution.active); + + final Result resultActivation = restService.getBuilder(ActivateInstitution.class) + .withURIVariable(API.PARAM_MODEL_ID, String.valueOf(institution.id)) + .call(); + + assertNotNull(resultActivation); + assertFalse(resultActivation.hasError()); + + final Result resultGet = restService.getBuilder(GetInstitution.class) + .withURIVariable(API.PARAM_MODEL_ID, String.valueOf(institution.id)) + .call(); + + assertNotNull(resultGet); + assertFalse(resultGet.hasError()); + institution = resultGet.get(); + assertEquals("Test Institution", institution.name); + assertTrue(institution.active); + + } + + @Test + @Order(2) + // ************************************* + // Use Case 2: SEB Administrator creates a new Institutional Administrator user for the + // newly created institution and activate this user + public void testUsecase2() { + final RestServiceImpl restService = createRestServiceForUser( + "admin", + "admin", + new GetInstitution(), + new GetInstitutionNames(), + new NewUserAccount(), + new ActivateUserAccount(), + new GetUserAccount()); + + final String instId = restService.getBuilder(GetInstitutionNames.class) + .call() + .getOrThrow() + .stream() + .filter(inst -> "Test Institution".equals(inst.name)) + .findFirst() + .get().modelId; + + assertNotNull(instId); + + Result result = restService.getBuilder(NewUserAccount.class) + .withFormParam(Domain.USER.ATTR_INSTITUTION_ID, instId) + .withFormParam(Domain.USER.ATTR_NAME, "TestInstAdmin") + .withFormParam(Domain.USER.ATTR_USERNAME, "TestInstAdmin") + .withFormParam(Domain.USER.ATTR_SURNAME, "TestInstAdmin") + .withFormParam(Domain.USER.ATTR_EMAIL, "test@test.ch") + .withFormParam(Domain.USER_ROLE.REFERENCE_NAME, UserRole.INSTITUTIONAL_ADMIN.name()) + .withFormParam(PasswordChange.ATTR_NAME_NEW_PASSWORD, "12345678") + .withFormParam(PasswordChange.ATTR_NAME_CONFIRM_NEW_PASSWORD, "12345678") + .withFormParam(Domain.USER.ATTR_LANGUAGE, Locale.ENGLISH.getLanguage()) + .withFormParam(Domain.USER.ATTR_TIMEZONE, DateTimeZone.UTC.getID()) + .call(); + + assertFalse(result.hasError()); + UserInfo userInfo = result.get(); + assertNotNull(userInfo); + assertEquals(instId, String.valueOf(userInfo.institutionId)); + assertEquals("TestInstAdmin", userInfo.name); + assertEquals("TestInstAdmin", userInfo.username); + assertEquals("test@test.ch", userInfo.email); + assertEquals("[INSTITUTIONAL_ADMIN]", String.valueOf(userInfo.getRoles())); + assertEquals(Locale.ENGLISH, userInfo.language); + assertEquals(DateTimeZone.UTC, userInfo.timeZone); + assertFalse(userInfo.isActive()); + + final Result activation = restService.getBuilder(ActivateUserAccount.class) + .withURIVariable(API.PARAM_MODEL_ID, String.valueOf(userInfo.uuid)) + .call(); + + assertFalse(activation.hasError()); + final EntityProcessingReport entityProcessingReport = activation.get(); + assertTrue(entityProcessingReport.getErrors().isEmpty()); + + result = restService.getBuilder(GetUserAccount.class) + .withURIVariable(API.PARAM_MODEL_ID, String.valueOf(userInfo.uuid)) + .call(); + + assertFalse(result.hasError()); + userInfo = result.get(); + assertTrue(userInfo.isActive()); + } + + @Test + @Order(3) + // ************************************* + // Use Case 3: Login with the new TestInstAdmin and check that only its institution is available + // check also that it is not possible to change to SEB Administrator role + // check also this it is possible to change the password and after that a new login is needed + // check also that property changes are possible. E.g: email + public void testUsecase3() { + RestServiceImpl restService = createRestServiceForUser( + "TestInstAdmin", + "12345678", + new GetInstitutionNames(), + new SaveUserAccount(), + new ChangePassword(), + new GetUserAccount(), + new GetUserAccountNames()); + + final List institutions = restService + .getBuilder(GetInstitutionNames.class) + .call() + .getOrThrow(); + + assertTrue(institutions.size() == 1); + assertEquals("Test Institution", institutions.get(0).name); + + final List userNames = restService + .getBuilder(GetUserAccountNames.class) + .call() + .getOrThrow(); + + assertTrue(userNames.size() == 1); + assertEquals("TestInstAdmin", userNames.get(0).name); + + final String userId = userNames.get(0).modelId; + + UserInfo userInfo = restService.getBuilder(GetUserAccount.class) + .withURIVariable(API.PARAM_MODEL_ID, userId) + .call() + .getOrThrow(); + + // change email (should work properly) + assertEquals("test@test.ch", userInfo.email); + userInfo = UserInfo.withEMail(userInfo, "newMail@test.ch"); + userInfo = restService.getBuilder(SaveUserAccount.class) + .withBody(userInfo) + .call() + .getOrThrow(); + + assertEquals("newMail@test.ch", userInfo.email); + + // adding new role that is lower should work (example Exam Admin) + userInfo = UserInfo.withRoles(userInfo, UserRole.INSTITUTIONAL_ADMIN.name(), UserRole.EXAM_ADMIN.name()); + userInfo = restService.getBuilder(SaveUserAccount.class) + .withBody(userInfo) + .call() + .getOrThrow(); + + assertEquals( + "[EXAM_ADMIN, INSTITUTIONAL_ADMIN]", + String.valueOf(new LinkedHashSet<>(userInfo.getRoles()))); + + // adding new role that is higher shouldn't work + userInfo = UserInfo.withRoles(userInfo, UserRole.INSTITUTIONAL_ADMIN.name(), UserRole.SEB_SERVER_ADMIN.name()); + final Result call = restService.getBuilder(SaveUserAccount.class) + .withBody(userInfo) + .call(); + + assertTrue(call.hasError()); + //assertEquals("Unexpected error while rest call", call.getError().getMessage()); + RestCallError error = (RestCallError) call.getError(); + assertEquals( + "[APIMessage [messageCode=1001, systemMessage=FORBIDDEN, details=No edit right grant for user: TestInstAdmin, attributes=[]]]", + String.valueOf(error.getErrorMessages())); + + // change password + final Result passwordChange = restService + .getBuilder(ChangePassword.class) + .withBody(new PasswordChange(userId, "12345678", "987654321", "987654321")) + .call(); + + assertFalse(passwordChange.hasError()); + userInfo = passwordChange.get(); + + // is the login still valid (should not) + final Result> instNames = restService + .getBuilder(GetInstitutionNames.class) + .call(); + assertTrue(instNames.hasError()); + error = (RestCallError) instNames.getError(); + assertEquals( + "UNAUTHORIZED", + String.valueOf(error.getErrorMessages().get(0).getSystemMessage())); + + // login again with the new password and check roles + restService = createRestServiceForUser( + "TestInstAdmin", + "987654321", + new GetInstitutionNames(), + new SaveUserAccount(), + new ChangePassword(), + new GetUserAccount(), + new GetUserAccountNames()); + + userInfo = restService.getBuilder(GetUserAccount.class) + .withURIVariable(API.PARAM_MODEL_ID, userId) + .call() + .getOrThrow(); + + assertNotNull(userInfo); + assertEquals("[EXAM_ADMIN, INSTITUTIONAL_ADMIN]", String.valueOf(userInfo.getRoles())); + } + + @Test + @Order(4) + // ************************************* + // Use Case 4: + // - login as TestInstAdmin + // - create a new user-account (examAdmin2) with Exam Administrator role + // - create a new user-account (examSupport1) with Exam Supporter role + // - create a new user-account (examSupport2) with Exam Administrator and Exam Supporter role + public void testUsecase4() { + final RestServiceImpl restService = createRestServiceForUser( + "TestInstAdmin", + "987654321", + new GetInstitutionNames(), + new NewUserAccount(), + new ActivateUserAccount()); + + final String instId = restService.getBuilder(GetInstitutionNames.class) + .call() + .getOrThrow() + .stream() + .filter(inst -> "Test Institution".equals(inst.name)) + .findFirst() + .get().modelId; + + assertNotNull(instId); + + Result result = restService.getBuilder(NewUserAccount.class) + .withFormParam(Domain.USER.ATTR_INSTITUTION_ID, instId) + .withFormParam(Domain.USER.ATTR_NAME, "examAdmin2") + .withFormParam(Domain.USER.ATTR_USERNAME, "examAdmin2") + .withFormParam(Domain.USER.ATTR_SURNAME, "examAdmin2") + .withFormParam(Domain.USER.ATTR_EMAIL, "test@test.ch") + .withFormParam(Domain.USER_ROLE.REFERENCE_NAME, UserRole.EXAM_ADMIN.name()) + .withFormParam(PasswordChange.ATTR_NAME_NEW_PASSWORD, "examAdmin2") + .withFormParam(PasswordChange.ATTR_NAME_CONFIRM_NEW_PASSWORD, "examAdmin2") + .withFormParam(Domain.USER.ATTR_LANGUAGE, Locale.ENGLISH.getLanguage()) + .withFormParam(Domain.USER.ATTR_TIMEZONE, DateTimeZone.UTC.getID()) + .call(); + + assertNotNull(result); + assertFalse(result.hasError()); + + Result activation = restService.getBuilder(ActivateUserAccount.class) + .withURIVariable(API.PARAM_MODEL_ID, result.get().uuid) + .call(); + assertNotNull(activation); + assertFalse(activation.hasError()); + + result = restService.getBuilder(NewUserAccount.class) + .withFormParam(Domain.USER.ATTR_INSTITUTION_ID, instId) + .withFormParam(Domain.USER.ATTR_NAME, "examSupport2") + .withFormParam(Domain.USER.ATTR_USERNAME, "examSupport2") + .withFormParam(Domain.USER.ATTR_SURNAME, "examSupport2") + .withFormParam(Domain.USER.ATTR_EMAIL, "test@test.ch") + .withFormParam(Domain.USER_ROLE.REFERENCE_NAME, UserRole.EXAM_SUPPORTER.name()) + .withFormParam(PasswordChange.ATTR_NAME_NEW_PASSWORD, "examSupport2") + .withFormParam(PasswordChange.ATTR_NAME_CONFIRM_NEW_PASSWORD, "examSupport2") + .withFormParam(Domain.USER.ATTR_LANGUAGE, Locale.ENGLISH.getLanguage()) + .withFormParam(Domain.USER.ATTR_TIMEZONE, DateTimeZone.UTC.getID()) + .call(); + + assertNotNull(result); + assertFalse(result.hasError()); + + activation = restService.getBuilder(ActivateUserAccount.class) + .withURIVariable(API.PARAM_MODEL_ID, result.get().uuid) + .call(); + assertNotNull(activation); + assertFalse(activation.hasError()); + + result = restService.getBuilder(NewUserAccount.class) + .withFormParam(Domain.USER.ATTR_INSTITUTION_ID, instId) + .withFormParam(Domain.USER.ATTR_NAME, "examSupport1") + .withFormParam(Domain.USER.ATTR_USERNAME, "examSupport1") + .withFormParam(Domain.USER.ATTR_SURNAME, "examSupport1") + .withFormParam(Domain.USER.ATTR_EMAIL, "test@test.ch") + .withFormParam(Domain.USER_ROLE.REFERENCE_NAME, UserRole.EXAM_SUPPORTER.name()) + .withFormParam(PasswordChange.ATTR_NAME_NEW_PASSWORD, "examSupport1") + .withFormParam(PasswordChange.ATTR_NAME_CONFIRM_NEW_PASSWORD, "examSupport1") + .withFormParam(Domain.USER.ATTR_LANGUAGE, Locale.ENGLISH.getLanguage()) + .withFormParam(Domain.USER.ATTR_TIMEZONE, DateTimeZone.UTC.getID()) + .call(); + + assertNotNull(result); + assertFalse(result.hasError()); + + activation = restService.getBuilder(ActivateUserAccount.class) + .withURIVariable(API.PARAM_MODEL_ID, result.get().uuid) + .call(); + assertNotNull(activation); + assertFalse(activation.hasError()); + + } + + @Test + @Order(5) + // ************************************* + // Use Case 5: Login as TestInstAdmin and create new LMS Mockup and activate + // - login as TestInstAdmin : 987654321 + // - check there are no LMS Setup and Quizzes currently available for the user + // - create new LMS Setup Mockup (no activation) + // - check the LMS Setup was created but there are still no quizzes available + // - activate LMS Setup + // - check now active and quizzes are available + // - change name of active LMS and check modification update + // - deactivate LMS Setup and check no quizzes are available + // - activate again for following tests + public void testUsecase5() { + final RestServiceImpl restService = createRestServiceForUser( + "TestInstAdmin", + "987654321", + new NewLmsSetup(), + new GetLmsSetupNames(), + new GetLmsSetup(), + new SaveLmsSetup(), + new ActivateLmsSetup(), + new DeactivateLmsSetup(), + new GetQuizPage()); + + // check there are currently no LMS Setup defined for this user + Result> lmsNames = restService + .getBuilder(GetLmsSetupNames.class) + .call(); + assertNotNull(lmsNames); + assertFalse(lmsNames.hasError()); + List list = lmsNames.get(); + assertTrue(list.isEmpty()); + + // check also there are currently no quizzes available for this user + Result> quizPageCall = restService + .getBuilder(GetQuizPage.class) + .call(); + assertNotNull(quizPageCall); + assertFalse(quizPageCall.hasError()); + Page quizPage = quizPageCall.get(); + assertTrue(quizPage.isEmpty()); + + // create new LMS Setup Mockup + Result newLMSCall = restService + .getBuilder(NewLmsSetup.class) + .withFormParam(Domain.LMS_SETUP.ATTR_NAME, "Test LMS Mockup") + .withFormParam(Domain.LMS_SETUP.ATTR_LMS_TYPE, LmsType.MOCKUP.name()) + .withFormParam(Domain.LMS_SETUP.ATTR_LMS_URL, "http://") + .withFormParam(Domain.LMS_SETUP.ATTR_LMS_CLIENTNAME, "test") + .withFormParam(Domain.LMS_SETUP.ATTR_LMS_CLIENTSECRET, "test") + .call(); + + assertNotNull(newLMSCall); + assertFalse(newLMSCall.hasError()); + LmsSetup lmsSetup = newLMSCall.get(); + assertEquals("Test LMS Mockup", lmsSetup.name); + assertFalse(lmsSetup.isActive()); + + // check is available now + lmsNames = restService + .getBuilder(GetLmsSetupNames.class) + .call(); + + assertNotNull(lmsNames); + assertFalse(lmsNames.hasError()); + list = lmsNames.get(); + assertFalse(list.isEmpty()); + + // check still no quizzes available form the LMS (not active now) + quizPageCall = restService + .getBuilder(GetQuizPage.class) + .call(); + assertNotNull(quizPageCall); + assertFalse(quizPageCall.hasError()); + quizPage = quizPageCall.get(); + assertTrue(quizPage.isEmpty()); + + // activate lms setup + Result activation = restService + .getBuilder(ActivateLmsSetup.class) + .withURIVariable(API.PARAM_MODEL_ID, lmsSetup.getModelId()) + .call(); + + assertNotNull(activation); + assertFalse(activation.hasError()); + + // check lms setup is now active + newLMSCall = restService + .getBuilder(GetLmsSetup.class) + .withURIVariable(API.PARAM_MODEL_ID, lmsSetup.getModelId()) + .call(); + + assertNotNull(newLMSCall); + assertFalse(newLMSCall.hasError()); + lmsSetup = newLMSCall.get(); + assertEquals("Test LMS Mockup", lmsSetup.name); + assertTrue(lmsSetup.isActive()); + + // check quizzes are available now + quizPageCall = restService + .getBuilder(GetQuizPage.class) + .call(); + assertNotNull(quizPageCall); + assertFalse(quizPageCall.hasError()); + quizPage = quizPageCall.get(); + assertFalse(quizPage.isEmpty()); + + // change the name of LMS Setup and check modification update + newLMSCall = restService + .getBuilder(SaveLmsSetup.class) + .withBody(new LmsSetup( + lmsSetup.id, + lmsSetup.institutionId, + "Test LMS Name Changed", + lmsSetup.lmsType, + lmsSetup.lmsAuthName, + lmsSetup.lmsAuthSecret, + lmsSetup.lmsApiUrl, + lmsSetup.lmsRestApiToken, + lmsSetup.proxyHost, + lmsSetup.proxyPort, + lmsSetup.proxyAuthUsername, + lmsSetup.proxyAuthSecret, + lmsSetup.active)) + .call(); + + assertNotNull(newLMSCall); + assertFalse(newLMSCall.hasError()); + lmsSetup = newLMSCall.get(); + assertEquals("Test LMS Name Changed", lmsSetup.name); + assertTrue(lmsSetup.isActive()); + + // check quizzes are still available + quizPageCall = restService + .getBuilder(GetQuizPage.class) + .call(); + assertNotNull(quizPageCall); + assertFalse(quizPageCall.hasError()); + quizPage = quizPageCall.get(); + assertFalse(quizPage.isEmpty()); + + // deactivate + final Result deactivation = restService + .getBuilder(DeactivateLmsSetup.class) + .withURIVariable(API.PARAM_MODEL_ID, lmsSetup.getModelId()) + .call(); + + assertNotNull(deactivation); + assertFalse(deactivation.hasError()); + + // check lms setup is now active + newLMSCall = restService + .getBuilder(GetLmsSetup.class) + .withURIVariable(API.PARAM_MODEL_ID, lmsSetup.getModelId()) + .call(); + + assertNotNull(newLMSCall); + assertFalse(newLMSCall.hasError()); + lmsSetup = newLMSCall.get(); + assertEquals("Test LMS Name Changed", lmsSetup.name); + assertFalse(lmsSetup.isActive()); + + // check quizzes are not available anymore + quizPageCall = restService + .getBuilder(GetQuizPage.class) + .call(); + assertNotNull(quizPageCall); + assertFalse(quizPageCall.hasError()); + quizPage = quizPageCall.get(); + assertTrue(quizPage.isEmpty()); + + // activate LMS Setup again for following tests + activation = restService + .getBuilder(ActivateLmsSetup.class) + .withURIVariable(API.PARAM_MODEL_ID, lmsSetup.getModelId()) + .call(); + + assertNotNull(activation); + assertFalse(activation.hasError()); + + // check lms setup is now active + newLMSCall = restService + .getBuilder(GetLmsSetup.class) + .withURIVariable(API.PARAM_MODEL_ID, lmsSetup.getModelId()) + .call(); + } + + @Test + @Order(6) + // ************************************* + // Use Case 6: Login as examAdmin2 + // - Check if there are some quizzes form previous LMS Setup + // - Import a quiz as Exam + // - get exam page and check the exam is there + // - edit exam property and save again + public void testUsecase6() { + final RestServiceImpl restService = createRestServiceForUser( + "examAdmin2", + "examAdmin2", + new GetUserAccountNames(), + new NewLmsSetup(), + new GetQuizPage(), + new GetQuizData(), + new ImportAsExam(), + new SaveExam(), + new GetExam(), + new GetExamPage()); + + final Result> userNamesResult = restService + .getBuilder(GetUserAccountNames.class) + .call(); + + assertNotNull(userNamesResult); + assertFalse(userNamesResult.hasError()); + + final String userId = userNamesResult.get() + .stream() + .filter(userName -> "examSupport2".equals(userName.name)) + .findFirst() + .map(EntityName::getModelId) + .orElse(null); + + // check quizzes are defines + final Result> quizPageCall = restService + .getBuilder(GetQuizPage.class) + .call(); + + assertNotNull(quizPageCall); + assertFalse(quizPageCall.hasError()); + final Page quizzes = quizPageCall.get(); + assertFalse(quizzes.isEmpty()); + final QuizData quizData = quizzes.content.get(0); + assertNotNull(quizData); + assertEquals("Demo Quiz 1 (MOCKUP)", quizData.name); + + // import quiz as exam + final Result newExamResult = restService + .getBuilder(ImportAsExam.class) + .withFormParam(QuizData.QUIZ_ATTR_LMS_SETUP_ID, String.valueOf(quizData.lmsSetupId)) + .withFormParam(QuizData.QUIZ_ATTR_ID, quizData.id) + .withFormParam(Domain.EXAM.ATTR_SUPPORTER, userId) + .call(); + + assertNotNull(newExamResult); + assertFalse(newExamResult.hasError()); + final Exam newExam = newExamResult.get(); + + assertEquals("Demo Quiz 1 (MOCKUP)", newExam.name); + assertEquals(ExamType.UNDEFINED, newExam.type); + assertFalse(newExam.supporter.isEmpty()); + + // create Exam with type and supporter examSupport2 + final Exam examForSave = new Exam( + newExam.id, + newExam.institutionId, + newExam.lmsSetupId, + newExam.externalId, + newExam.name, + newExam.description, + newExam.startTime, + newExam.endTime, + newExam.startURL, + ExamType.MANAGED, + null, null, + Utils.immutableCollectionOf(userId), + ExamStatus.RUNNING, + true, + null, + true, + null); + + final Result savedExamResult = restService + .getBuilder(SaveExam.class) + .withBody(examForSave) + .call(); + + assertNotNull(savedExamResult); + assertFalse(savedExamResult.hasError()); + final Exam savedExam = savedExamResult.get(); + + assertEquals(ExamType.MANAGED, savedExam.type); + assertFalse(savedExam.supporter.isEmpty()); + } + + @Test + @Order(7) + // ************************************* + // Use Case 7: Login as examAdmin2 + // - Get imported exam + // - add new indicator for exam + // - save exam with new indicator and test + // - create some thresholds for the new indicator + public void testUsecase7() { + final RestServiceImpl restService = createRestServiceForUser( + "examAdmin2", + "examAdmin2", + new GetExam(), + new GetExamNames(), + new NewIndicator(), + new SaveIndicator(), + new GetIndicator(), + new GetIndicatorPage()); + + final Result> examNamesResult = restService + .getBuilder(GetExamNames.class) + .call(); + + assertNotNull(examNamesResult); + assertFalse(examNamesResult.hasError()); + final List exams = examNamesResult.get(); + assertFalse(exams.isEmpty()); + final EntityName examName = exams.get(0); + assertEquals("Demo Quiz 1 (MOCKUP)", examName.name); + + final Result examResult = restService + .getBuilder(GetExam.class) + .withURIVariable(API.PARAM_MODEL_ID, examName.modelId) + .call(); + + assertNotNull(examResult); + assertFalse(examResult.hasError()); + final Exam exam = examResult.get(); + + final Result newIndicatorResult = restService + .getBuilder(NewIndicator.class) + .withFormParam(Domain.INDICATOR.ATTR_EXAM_ID, exam.getModelId()) + .withFormParam(Domain.INDICATOR.ATTR_NAME, "Ping") + .withFormParam(Domain.INDICATOR.ATTR_TYPE, IndicatorType.LAST_PING.name) + .withFormParam(Domain.INDICATOR.ATTR_COLOR, "000001") + .call(); + + assertNotNull(newIndicatorResult); + assertFalse(newIndicatorResult.hasError()); + final Indicator newIndicator = newIndicatorResult.get(); + + assertEquals("Ping", newIndicator.name); + assertEquals("000001", newIndicator.defaultColor); + + final Indicator indicatorToSave = new Indicator( + newIndicator.id, newIndicator.examId, newIndicator.name, newIndicator.type, newIndicator.defaultColor, + Utils.immutableCollectionOf( + new Indicator.Threshold(2000d, "000011"), + new Indicator.Threshold(5000d, "001111"))); + + final Result savedIndicatorResult = restService + .getBuilder(SaveIndicator.class) + .withBody(indicatorToSave) + .call(); + + assertNotNull(savedIndicatorResult); + assertFalse(savedIndicatorResult.hasError()); + final Indicator savedIndicator = savedIndicatorResult.get(); + + assertEquals("Ping", savedIndicator.name); + assertEquals("000001", savedIndicator.defaultColor); + final Collection thresholds = savedIndicator.getThresholds(); + assertFalse(thresholds.isEmpty()); + assertTrue(thresholds.size() == 2); + final Iterator iterator = thresholds.iterator(); + final Threshold t1 = iterator.next(); + final Threshold t2 = iterator.next(); + + assertTrue(2000d - t1.value < .0001); + assertEquals("000011", t1.color); + assertTrue(5000d - t2.value < .0001); + assertEquals("001111", t2.color); + } + + @Test + @Order(8) + // ************************************* + // Use Case 8: Login as TestInstAdmin and create a SEB Client Configuration + // - create one with and one without password + // - activate one config + // - export both configurations + public void testUsecase8() throws IOException { + final RestServiceImpl restService = createRestServiceForUser( + "TestInstAdmin", + "987654321", + new GetClientConfig(), + new GetClientConfigPage(), + new NewClientConfig(), + new SaveClientConfig(), + new ActivateClientConfig(), + new DeactivateClientConfig(), + new ExportClientConfig()); + + // create SEB Client Config without password protection + final Result newConfigResponse = restService + .getBuilder(NewClientConfig.class) + .withFormParam(Domain.SEB_CLIENT_CONFIGURATION.ATTR_NAME, "No Password Protection") + .withFormParam(SebClientConfig.ATTR_FALLBACK_START_URL, "http://fallback.com/fallback") + .call(); + + assertNotNull(newConfigResponse); + assertFalse(newConfigResponse.hasError()); + final SebClientConfig sebClientConfig = newConfigResponse.get(); + assertEquals("No Password Protection", sebClientConfig.name); + assertFalse(sebClientConfig.isActive()); + assertEquals("http://fallback.com/fallback", sebClientConfig.fallbackStartURL); + + // activate the new Client Configuration + final Result activationResponse = restService + .getBuilder(ActivateClientConfig.class) + .withURIVariable(API.PARAM_MODEL_ID, sebClientConfig.getModelId()) + .call(); + + assertNotNull(activationResponse); + assertFalse(activationResponse.hasError()); + + final Result getConfigResponse = restService + .getBuilder(GetClientConfig.class) + .withURIVariable(API.PARAM_MODEL_ID, sebClientConfig.getModelId()) + .call(); + + assertNotNull(getConfigResponse); + assertFalse(getConfigResponse.hasError()); + final SebClientConfig activeConfig = getConfigResponse.get(); + assertTrue(activeConfig.isActive()); + + // create a config with password protection + final Result configWithPasswordResponse = restService + .getBuilder(NewClientConfig.class) + .withFormParam(Domain.SEB_CLIENT_CONFIGURATION.ATTR_NAME, "With Password Protection") + .withFormParam(SebClientConfig.ATTR_FALLBACK_START_URL, "http://fallback.com/fallback") + .withFormParam(SEB_CLIENT_CONFIGURATION.ATTR_ENCRYPT_SECRET, "123") + .withFormParam(SebClientConfig.ATTR_CONFIRM_ENCRYPT_SECRET, "123") + .call(); + + assertNotNull(configWithPasswordResponse); + assertFalse(configWithPasswordResponse.hasError()); + final SebClientConfig configWithPassword = configWithPasswordResponse.get(); + assertEquals("With Password Protection", configWithPassword.name); + assertFalse(configWithPassword.isActive()); + assertEquals("http://fallback.com/fallback", configWithPassword.fallbackStartURL); + + // export client config No Password Protection + Result exportResponse = restService + .getBuilder(ExportClientConfig.class) + .withURIVariable(API.PARAM_MODEL_ID, sebClientConfig.getModelId()) + .call(); + + assertNotNull(exportResponse); + assertFalse(exportResponse.hasError()); + + List readLines = IOUtils.readLines(exportResponse.get(), "UTF-8"); + assertNotNull(readLines); + assertFalse(readLines.isEmpty()); + assertTrue(readLines.get(0).startsWith("plnd")); + + // export client config With Password Protection + exportResponse = restService + .getBuilder(ExportClientConfig.class) + .withURIVariable(API.PARAM_MODEL_ID, configWithPassword.getModelId()) + .call(); + + assertNotNull(exportResponse); + assertFalse(exportResponse.hasError()); + + readLines = IOUtils.readLines(exportResponse.get(), "UTF-8"); + assertNotNull(readLines); + assertFalse(readLines.isEmpty()); + assertTrue(readLines.get(0).startsWith("pswd")); + + // get page + final Result> pageResponse = restService + .getBuilder(GetClientConfigPage.class) + .call(); + + assertNotNull(pageResponse); + assertFalse(pageResponse.hasError()); + final Page page = pageResponse.get(); + assertFalse(page.content.isEmpty()); + assertTrue(page.content.size() == 2); + } + + @Test + @Order(9) + // ************************************* + // Use Case 9: Login as examAdmin2 and test Exam Configuration data basis + // - get all Views for the default template + // - get all Attributes and and Orientations for the default view + @Sql(scripts = { "classpath:data-test-additional.sql" }) + public void testUsecase9() throws IOException { + final RestServiceImpl restService = createRestServiceForUser( + "examAdmin2", + "examAdmin2", + new GetViewList(), + new GetConfigAttributes(), + new GetOrientations(), + new GetOrientationPage()); + + final ExamConfigurationServiceImpl examConfigurationService = new ExamConfigurationServiceImpl( + restService, + new JSONMapper(), + null, null, + Collections.emptyList()); + + final Result attributes = examConfigurationService.getAttributes(0l); + assertNotNull(attributes); + assertFalse(attributes.hasError()); + final AttributeMapping attributeMapping = attributes.get(); + assertEquals(192, attributeMapping.attributeIdMapping.size()); + assertEquals("[active, audio, backToStart, browserSecurity, browserViewMode, " + + "exitSequence, functionKeys, kioskMode, logging, macSettings, " + + "newBrowserWindow, newwinsize, proxies, quitLink, registry, " + + "servicePolicy, specialKeys, spellcheck, taskbar, urlFilter, " + + "userAgentDesktop, userAgentMac, userAgentTouch, winsize, wintoolbar, zoom, zoomMode]", + attributeMapping.attributeGroupMapping.keySet() + .stream() + .sorted() + .collect(Collectors.toList()) + .toString()); + + final String viewIds = StringUtils.join(attributeMapping.getViewIds().stream().map(String::valueOf) + .collect(Collectors.toList()), + Constants.LIST_SEPARATOR_CHAR); + + assertEquals("1,2,3,4,5,6,8,9,10,11", viewIds); + final Result> viewsResponse = restService + .getBuilder(GetViewList.class) + .withQueryParam(API.PARAM_MODEL_ID_LIST, viewIds) + .call(); + + assertNotNull(viewsResponse); + assertFalse(viewsResponse.hasError()); + } + + @Test + @Order(10) + // ************************************* + // Use Case 10: Login as examAdmin2 and create a new SEB Exam Configuration + // - test creation + // - save configuration in history + // - change some attribute + // - process an undo + public void testUsecase10() throws IOException { + final RestServiceImpl restService = createRestServiceForUser( + "examAdmin2", + "examAdmin2", + new NewExamConfig(), + new GetExamConfigNode(), + new GetExamConfigNodePage(), + new GetConfigurationPage(), + new GetConfigurations(), + new SaveExamConfigHistory(), + new GetConfigurationTableValues(), + new SebExamConfigUndo(), + new SaveExamConfigValue(), + new SaveExamConfigTableValues(), + new GetConfigurationValuePage(), + new GetConfigurationValues(), + new GetConfigAttributes(), + new GetUserAccountNames()); + + // get user id + final String userId = restService + .getBuilder(GetUserAccountNames.class) + .call() + .getOrThrow() + .stream() + .filter(userName -> "examAdmin2".equals(userName.name)) + .map(EntityName::getModelId) + .findFirst() + .orElse(null); + + assertNotNull(userId); + + // get configuration page + final Result> pageResponse = restService + .getBuilder(GetExamConfigNodePage.class) + .call(); + + // there should be not configuration (for this institution of examAdmin2) now + assertNotNull(pageResponse); + assertFalse(pageResponse.hasError()); + final Page page = pageResponse.get(); + assertTrue(page.content.isEmpty()); + + final Result newConfigResponse = restService + .getBuilder(NewExamConfig.class) + .withFormParam(Domain.CONFIGURATION_NODE.ATTR_NAME, "New Exam Config") + .withFormParam(Domain.CONFIGURATION_NODE.ATTR_DESCRIPTION, "This is a New Exam Config") + .call(); + + assertNotNull(newConfigResponse); + assertFalse(newConfigResponse.hasError()); + final ConfigurationNode newConfig = newConfigResponse.get(); + assertEquals("New Exam Config", newConfig.name); + assertEquals(Long.valueOf(0), newConfig.templateId); + assertEquals(userId, newConfig.owner); + + // get follow-up configuration + Result> configHistoryResponse = restService + .getBuilder(GetConfigurations.class) + .withQueryParam(Configuration.FILTER_ATTR_CONFIGURATION_NODE_ID, newConfig.getModelId()) + .call(); + + assertNotNull(configHistoryResponse); + assertFalse(configHistoryResponse.hasError()); + List configHistory = configHistoryResponse.get(); + assertFalse(configHistory.isEmpty()); + assertTrue(2 == configHistory.size()); + final Configuration initConfig = configHistory.get(0); + Configuration followup = configHistory.get(1); + assertEquals("v0", initConfig.version); + assertFalse(initConfig.followup); + assertNull(followup.version); + assertTrue(followup.followup); + + // get all configuration values + Result> valuesResponse = restService + .getBuilder(GetConfigurationValues.class) + .withQueryParam(ConfigurationValue.FILTER_ATTR_CONFIGURATION_ID, followup.getModelId()) + .call(); + + assertNotNull(valuesResponse); + assertFalse(valuesResponse.hasError()); + List values = valuesResponse.get(); + assertFalse(values.isEmpty()); + + UsecaseTestUtils.testProhibitedProcessesInit( + followup.getModelId(), + restService); + UsecaseTestUtils.testPermittedProcessesInit( + followup.getModelId(), + restService); + + // update a value -- grab first + final ConfigurationValue value = values.get(0); + ConfigurationValue newValue = new ConfigurationValue( + null, value.institutionId, value.configurationId, + value.attributeId, value.listIndex, "2"); + Result newValueResponse = restService + .getBuilder(SaveExamConfigValue.class) + .withBody(newValue) + .call(); + + assertNotNull(newValueResponse); + assertFalse(newValueResponse.hasError()); + ConfigurationValue savedValue = newValueResponse.get(); + assertEquals("2", savedValue.value); + + // save to history + final Result saveHistoryResponse = restService + .getBuilder(SaveExamConfigHistory.class) + .withURIVariable(API.PARAM_MODEL_ID, followup.getModelId()) + .call(); + + assertNotNull(saveHistoryResponse); + assertFalse(saveHistoryResponse.hasError()); + Configuration configuration = saveHistoryResponse.get(); + assertTrue(configuration.followup); + + configHistoryResponse = restService + .getBuilder(GetConfigurations.class) + .withQueryParam(Configuration.FILTER_ATTR_CONFIGURATION_NODE_ID, newConfig.getModelId()) + .call(); + + assertNotNull(configHistoryResponse); + assertFalse(configHistoryResponse.hasError()); + configHistory = configHistoryResponse.get(); + assertFalse(configHistory.isEmpty()); + assertTrue(3 == configHistory.size()); + + configHistoryResponse = restService + .getBuilder(GetConfigurations.class) + .withQueryParam(Configuration.FILTER_ATTR_CONFIGURATION_NODE_ID, newConfig.getModelId()) + .withQueryParam(Configuration.FILTER_ATTR_FOLLOWUP, "true") + .call(); + + assertNotNull(configHistoryResponse); + assertFalse(configHistoryResponse.hasError()); + followup = configHistoryResponse.get().get(0); + assertNotNull(followup); + assertTrue(followup.followup); + + // change value again + newValue = new ConfigurationValue( + null, value.institutionId, followup.id, + value.attributeId, value.listIndex, "3"); + newValueResponse = restService + .getBuilder(SaveExamConfigValue.class) + .withBody(newValue) + .call(); + + assertNotNull(newValueResponse); + assertFalse(newValueResponse.hasError()); + savedValue = newValueResponse.get(); + assertEquals("3", savedValue.value); + + // get current value + valuesResponse = restService + .getBuilder(GetConfigurationValues.class) + .withQueryParam(ConfigurationValue.FILTER_ATTR_CONFIGURATION_ID, followup.getModelId()) + .call(); + + assertNotNull(valuesResponse); + assertFalse(valuesResponse.hasError()); + values = valuesResponse.get(); + assertFalse(values.isEmpty()); + assertNotNull(newValueResponse); + assertFalse(newValueResponse.hasError()); + savedValue = newValueResponse.get(); + assertEquals("3", savedValue.value); + + // undo + final Result undoResponse = restService + .getBuilder(SebExamConfigUndo.class) + .withURIVariable(API.PARAM_MODEL_ID, followup.getModelId()) + .call(); + + assertNotNull(undoResponse); + assertFalse(undoResponse.hasError()); + configuration = undoResponse.get(); + assertTrue(configuration.followup); + + // check value has been reset + valuesResponse = restService + .getBuilder(GetConfigurationValues.class) + .withQueryParam(ConfigurationValue.FILTER_ATTR_CONFIGURATION_ID, configuration.getModelId()) + .call(); + + assertNotNull(valuesResponse); + assertFalse(valuesResponse.hasError()); + values = valuesResponse.get(); + final ConfigurationValue currentValue = + values.stream().filter(v -> v.attributeId == value.attributeId).findFirst().orElse(null); + assertNotNull(currentValue); + assertEquals("2", currentValue.value); + } + + @Test + @Order(11) + // ************************************* + // Use Case 11: Login as examAdmin2 and get newly created exam configuration + // - get permitted processes table values + // - modify permitted processes table values + // - save permitted processes table values + // - check save OK + public void testUsecase11() throws IOException { + final RestServiceImpl restService = createRestServiceForUser( + "examAdmin2", + "examAdmin2", + new GetConfigAttributes(), + new GetExamConfigNodePage(), + new GetConfigurations(), + new GetConfigurationPage(), + new SaveExamConfigHistory(), + new GetConfigurationTableValues(), + new SaveExamConfigTableValues()); + + // get configuration page + final Result> pageResponse = restService + .getBuilder(GetExamConfigNodePage.class) + .call(); + + assertNotNull(pageResponse); + assertFalse(pageResponse.hasError()); + final Page page = pageResponse.get(); + assertFalse(page.content.isEmpty()); + + final ConfigurationNode configurationNode = page.content.get(0); + assertEquals("New Exam Config", configurationNode.name); + + // get follow-up configuration + final Result> configHistoryResponse = restService + .getBuilder(GetConfigurations.class) + .withQueryParam(Configuration.FILTER_ATTR_CONFIGURATION_NODE_ID, configurationNode.getModelId()) + .call(); + + final List configHistory = configHistoryResponse.get(); + final Configuration followup = configHistory + .stream() + .filter(config -> BooleanUtils.isTrue(config.followup)) + .findFirst() + .orElseThrow(() -> new RuntimeException("Followup Node not found")); + + final ConfigurationTableValues permittedProcessValues = UsecaseTestUtils.getTableValues( + "73", + followup.getModelId(), + restService); + + assertNotNull(permittedProcessValues); + assertFalse(permittedProcessValues.values.isEmpty()); + + // get all configuration attributes + final Map attributes = restService + .getBuilder(GetConfigAttributes.class) + .call() + .getOrThrow() + .stream() + .collect(Collectors.toMap(attr -> attr.id, Function.identity())); + + // create new row by copy the values + final List newTableValues = permittedProcessValues.values + .stream() + .map(attr -> new TableValue(attr.attributeId, 1, attributes.get(attr.attributeId).defaultValue)) + .collect(Collectors.toList()); + newTableValues.addAll(permittedProcessValues.values); + + // test institutional integrity violation + try { + final ConfigurationTableValues newTableValue = new ConfigurationTableValues( + 1000L, + followup.id, + 73L, + newTableValues); + + restService.getBuilder(SaveExamConfigTableValues.class) + .withBody(newTableValue) + .call() + .getOrThrow(); + + fail("Exception expected here"); + } catch (final Exception e) { + assertEquals("Unexpected error while rest call", e.getMessage()); + } + + // test follow-up integrity violation + try { + final ConfigurationTableValues newTableValue = new ConfigurationTableValues( + configHistory.get(0).id, + followup.id, + 73L, + newTableValues); + + restService.getBuilder(SaveExamConfigTableValues.class) + .withBody(newTableValue) + .call() + .getOrThrow(); + + fail("Exception expected here"); + } catch (final Exception e) { + assertEquals("Unexpected error while rest call", e.getMessage()); + } + + final ConfigurationTableValues newTableValue = new ConfigurationTableValues( + followup.institutionId, + followup.id, + 73L, + newTableValues); + + final ConfigurationTableValues savedValues = restService.getBuilder(SaveExamConfigTableValues.class) + .withBody(newTableValue) + .call() + .getOrThrow(); + + assertNotNull(savedValues); + assertFalse(savedValues.values.isEmpty()); + assertTrue(savedValues.values.size() == newTableValues.size()); + } + + @Test + @Order(12) + // ************************************* + // Use Case 12: Login as examAdmin2 and use newly created configuration + // - get follow-up configuration by API + // - import + // - export + public void testUsecase12() throws IOException { + final RestServiceImpl restService = createRestServiceForUser( + "examAdmin2", + "examAdmin2", + new GetConfigAttributes(), + new GetExamConfigNodePage(), + new SaveExamConfigHistory(), + new ExportExamConfig(), + new ImportNewExamConfig(), + new ImportExamConfigOnExistingConfig(), + new ExportPlainXML(), + new GetFollowupConfiguration()); + + // get all configuration attributes + final Collection attributes = restService + .getBuilder(GetConfigAttributes.class) + .call() + .getOrThrow() + .stream() + .collect(Collectors.toList()); + + // get configuration page + final Result> pageResponse = restService + .getBuilder(GetExamConfigNodePage.class) + .call(); + + assertNotNull(pageResponse); + assertFalse(pageResponse.hasError()); + final Page page = pageResponse.get(); + assertFalse(page.content.isEmpty()); + + final ConfigurationNode configurationNode = page.content.get(0); + assertEquals("New Exam Config", configurationNode.name); + + final Configuration followup = restService + .getBuilder(GetFollowupConfiguration.class) + .withURIVariable(API.PARAM_MODEL_ID, configurationNode.getModelId()) + .call() + .getOrThrow(); + + assertNotNull(followup); + assertTrue(followup.followup); + + // export1 + final InputStream input = restService + .getBuilder(ExportPlainXML.class) + .withURIVariable(API.PARAM_MODEL_ID, configurationNode.getModelId()) + .call() + .getOrThrow(); + + final String xmlString = StreamUtils.copyToString(input, Charsets.UTF_8); + assertNotNull(xmlString); + for (final ConfigurationAttribute attribute : attributes) { + if (attribute.name.contains(".") || attribute.name.equals("kioskMode")) { + continue; + } + if (!xmlString.contains(attribute.name)) { + fail("missing attribute: " + attribute.name); + } + } + + // import plain config + InputStream inputStream = new ClassPathResource("importTest.seb").getInputStream(); + Configuration importedConfig = restService + .getBuilder(ImportNewExamConfig.class) + .withBody(inputStream) + .withHeader(Domain.CONFIGURATION_NODE.ATTR_NAME, "Imported Test Configuration") + .call() + .getOrThrow(); + + assertNotNull(importedConfig); + + // import with the same name should cause an exception + try { + restService + .getBuilder(ImportNewExamConfig.class) + .withBody(inputStream) + .withHeader(Domain.CONFIGURATION_NODE.ATTR_NAME, "Imported Test Configuration") + .withHeader(API.IMPORT_PASSWORD_ATTR_NAME, "123") + .call() + .getOrThrow(); + fail("Expecting an exception here"); + } catch (final Exception e) { + + } + + // import encrypted config with password encryption + inputStream = new ClassPathResource("importTest_123.seb").getInputStream(); + importedConfig = restService + .getBuilder(ImportNewExamConfig.class) + .withBody(inputStream) + .withHeader(Domain.CONFIGURATION_NODE.ATTR_NAME, "Imported Encrypted Test Configuration") + .withHeader(API.IMPORT_PASSWORD_ATTR_NAME, "123") + .call() + .getOrThrow(); + + assertNotNull(importedConfig); + + // import config within existing configuration + inputStream = new ClassPathResource("importTest.seb").getInputStream(); + importedConfig = restService + .getBuilder(ImportExamConfigOnExistingConfig.class) + .withBody(inputStream) + .withURIVariable(API.PARAM_MODEL_ID, String.valueOf(importedConfig.getConfigurationNodeId())) + .call() + .getOrThrow(); + } + + @Test + @Order(13) + // ************************************* + // Use Case 13: Login as examAdmin2 and use newly created configuration + // - change configuration status to "Ready to Use" + public void testUsecase13() throws IOException { + final RestServiceImpl restService = createRestServiceForUser( + "examAdmin2", + "examAdmin2", + new GetConfigAttributes(), + new GetExamConfigNodePage(), + new SaveExamConfig()); + + // get configuration from page + final ConfigurationNode config = restService + .getBuilder(GetExamConfigNodePage.class) + .call() + .getOrThrow().content + .get(0); + assertEquals("New Exam Config", config.name); + + final ConfigurationNode newConfig = new ConfigurationNode( + config.id, + config.institutionId, + config.templateId, + config.name, + config.description, + ConfigurationType.EXAM_CONFIG, + config.owner, + ConfigurationStatus.READY_TO_USE); + + final ConfigurationNode savedConfig = restService + .getBuilder(SaveExamConfig.class) + .withBody(newConfig) + .call() + .getOrThrow(); + + assertTrue(savedConfig.status == ConfigurationStatus.READY_TO_USE); + } + + @Test + @Order(15) + // ************************************* + // Use Case 15: Login as examAdmin2 and get views and orientations + // - test Views API + public void testUsecase15() throws IOException { + final RestServiceImpl restService = createRestServiceForUser( + "examAdmin2", + "examAdmin2", + new GetViews(), + new GetViewPage(), + new GetOrientationPage(), + new GetOrientations()); + + final List views = restService + .getBuilder(GetViews.class) + .call() + .getOrThrow(); + + assertNotNull(views); + assertTrue(views.size() == 11); + + final List orientations = restService + .getBuilder(GetOrientations.class) + .call() + .getOrThrow(); + + assertNotNull(orientations); + } + +} diff --git a/src/test/java/ch/ethz/seb/sebserver/webservice/integration/api/admin/UserAPITest.java b/src/test/java/ch/ethz/seb/sebserver/webservice/integration/api/admin/UserAPITest.java index ddfddfaa..ceb77971 100644 --- a/src/test/java/ch/ethz/seb/sebserver/webservice/integration/api/admin/UserAPITest.java +++ b/src/test/java/ch/ethz/seb/sebserver/webservice/integration/api/admin/UserAPITest.java @@ -1,1246 +1,1248 @@ -/* - * Copyright (c) 2018 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.webservice.integration.api.admin; - -import static org.junit.Assert.*; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - -import java.util.Arrays; -import java.util.Collection; -import java.util.HashSet; -import java.util.List; -import java.util.Locale; -import java.util.NoSuchElementException; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -import org.joda.time.DateTime; -import org.joda.time.DateTimeZone; -import org.junit.Test; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpMethod; -import org.springframework.http.HttpStatus; -import org.springframework.http.MediaType; -import org.springframework.test.context.jdbc.Sql; - -import com.fasterxml.jackson.core.type.TypeReference; - -import ch.ethz.seb.sebserver.gbl.Constants; -import ch.ethz.seb.sebserver.gbl.api.API; -import ch.ethz.seb.sebserver.gbl.api.APIMessage; -import ch.ethz.seb.sebserver.gbl.model.Domain; -import ch.ethz.seb.sebserver.gbl.model.Entity; -import ch.ethz.seb.sebserver.gbl.model.EntityKey; -import ch.ethz.seb.sebserver.gbl.model.EntityName; -import ch.ethz.seb.sebserver.gbl.model.EntityProcessingReport; -import ch.ethz.seb.sebserver.gbl.model.Page; -import ch.ethz.seb.sebserver.gbl.model.institution.Institution; -import ch.ethz.seb.sebserver.gbl.model.user.PasswordChange; -import ch.ethz.seb.sebserver.gbl.model.user.UserActivityLog; -import ch.ethz.seb.sebserver.gbl.model.user.UserInfo; -import ch.ethz.seb.sebserver.gbl.model.user.UserLogActivityType; -import ch.ethz.seb.sebserver.gbl.model.user.UserRole; - -@Sql(scripts = { "classpath:schema-test.sql", "classpath:data-test.sql" }) -public class UserAPITest extends AdministrationAPIIntegrationTester { - - @Test - public void getMyUserInfo() throws Exception { - String contentAsString = new RestAPITestHelper() - .withAccessToken(getSebAdminAccess()) - .withPath(API.USER_ACCOUNT_ENDPOINT + "/me") - .withExpectedStatus(HttpStatus.OK) - .getAsString(); - - assertEquals( - "{\"uuid\":\"user1\"," - + "\"institutionId\":1," - + "\"creationDate\":\"2019-01-01T00:00:00.000Z\"," - + "\"name\":\"SEBAdmin\"," - + "\"surname\":\"\"," - + "\"username\":\"admin\"," - + "\"email\":\"admin@nomail.nomail\"," - + "\"active\":true," - + "\"language\":\"en\"," - + "\"timezone\":\"UTC\"," - + "\"userRoles\":[\"EXAM_ADMIN\",\"EXAM_SUPPORTER\",\"SEB_SERVER_ADMIN\",\"INSTITUTIONAL_ADMIN\"]}", - contentAsString); - - contentAsString = new RestAPITestHelper() - .withAccessToken(getAdminInstitution1Access()) - .withPath(API.USER_ACCOUNT_ENDPOINT + "/me") - .withExpectedStatus(HttpStatus.OK) - .getAsString(); - - assertEquals( - "{\"uuid\":\"user2\"," - + "\"institutionId\":1," - + "\"creationDate\":\"2019-01-01T00:00:00.000Z\"," - + "\"name\":\"Institutional1 Admin\"," - + "\"surname\":\"\"," - + "\"username\":\"inst1Admin\"," - + "\"email\":\"admin@nomail.nomail\"," - + "\"active\":true," - + "\"language\":\"en\"," - + "\"timezone\":\"UTC\"," - + "\"userRoles\":[\"INSTITUTIONAL_ADMIN\"]}", - contentAsString); - } - - @Test - public void getUserInfoWithUUID() throws Exception { - final String sebAdminAccessToken = getSebAdminAccess(); - String contentAsString = this.mockMvc - .perform(get(this.endpoint + API.USER_ACCOUNT_ENDPOINT + "/user2") - .contentType(MediaType.APPLICATION_FORM_URLENCODED) - .header("Authorization", "Bearer " + sebAdminAccessToken)) - .andExpect(status().isOk()) - .andReturn().getResponse().getContentAsString(); - - assertEquals( - "{\"uuid\":\"user2\"," - + "\"institutionId\":1," - + "\"creationDate\":\"2019-01-01T00:00:00.000Z\"," - + "\"name\":\"Institutional1 Admin\"," - + "\"surname\":\"\"," - + "\"username\":\"inst1Admin\"," - + "\"email\":\"admin@nomail.nomail\"," - + "\"active\":true," - + "\"language\":\"en\"," - + "\"timezone\":\"UTC\"," - + "\"userRoles\":[\"INSTITUTIONAL_ADMIN\"]}", - contentAsString); - - final String adminInstitution2AccessToken = getAdminInstitution2Access(); - contentAsString = this.mockMvc - .perform(get(this.endpoint + API.USER_ACCOUNT_ENDPOINT + "/user1") - .contentType(MediaType.APPLICATION_FORM_URLENCODED) - .header("Authorization", "Bearer " + adminInstitution2AccessToken)) - .andExpect(status().isForbidden()) - .andReturn().getResponse().getContentAsString(); - - assertEquals( - "[{\"messageCode\":\"1001\"," - + "\"systemMessage\":\"FORBIDDEN\"," - + "\"details\":\"No grant: READ on type: USER entity institution: 1 entity owner: user1 for user: user3\"," - + "\"attributes\":[]}]", - contentAsString); - } - - @Test - public void institutionalAdminNotAllowedToSeeUsersOfOtherInstitution() throws Exception { - new RestAPITestHelper() - .withAccessToken(getAdminInstitution1Access()) - .withPath(API.USER_ACCOUNT_ENDPOINT + "?institutionId=2") - .withExpectedStatus(HttpStatus.FORBIDDEN) - .getAsString(); - } - - @Test - public void getAllUserInfoNoFilter() throws Exception { - Page userInfos = new RestAPITestHelper() - .withAccessToken(getSebAdminAccess()) - .withPath(API.USER_ACCOUNT_ENDPOINT + "?institutionId=1") - .withExpectedStatus(HttpStatus.OK) - .getAsObject(new TypeReference>() { - }); - - // expecting all users for a SEBAdmin except inactive. - assertNotNull(userInfos); - assertTrue(userInfos.content.size() == 3); - assertNotNull(getUserInfo("admin", userInfos.content)); - assertNotNull(getUserInfo("inst1Admin", userInfos.content)); - assertNotNull(getUserInfo("examSupporter", userInfos.content)); - - userInfos = new RestAPITestHelper() - .withAccessToken(getAdminInstitution2Access()) - .withPath(API.USER_ACCOUNT_ENDPOINT) - .withAttribute("institutionId", "2") - .withExpectedStatus(HttpStatus.OK) - .getAsObject(new TypeReference>() { - }); - - // expecting all users of institution 2 also inactive when active flag is not set - assertNotNull(userInfos); - assertTrue(userInfos.content.size() == 4); - assertNotNull(getUserInfo("inst2Admin", userInfos.content)); - assertNotNull(getUserInfo("examAdmin1", userInfos.content)); - assertNotNull(getUserInfo("deactivatedUser", userInfos.content)); - assertNotNull(getUserInfo("user1", userInfos.content)); - - //.. and without inactive, if active flag is set to true - userInfos = new RestAPITestHelper() - .withAccessToken(getAdminInstitution2Access()) - .withPath(API.USER_ACCOUNT_ENDPOINT) - .withAttribute(Entity.FILTER_ATTR_INSTITUTION, "2") - .withAttribute(Entity.FILTER_ATTR_ACTIVE, "true") - .withExpectedStatus(HttpStatus.OK) - .getAsObject(new TypeReference>() { - }); - - assertNotNull(userInfos); - assertTrue(userInfos.content.size() == 3); - assertNotNull(getUserInfo("inst2Admin", userInfos.content)); - assertNotNull(getUserInfo("examAdmin1", userInfos.content)); - assertNotNull(getUserInfo("user1", userInfos.content)); - - //.. and only inactive, if active flag is set to false - userInfos = new RestAPITestHelper() - .withAccessToken(getAdminInstitution2Access()) - .withPath(API.USER_ACCOUNT_ENDPOINT) - .withAttribute(Entity.FILTER_ATTR_INSTITUTION, "2") - .withAttribute(Entity.FILTER_ATTR_ACTIVE, "false") - .withExpectedStatus(HttpStatus.OK) - .getAsObject(new TypeReference>() { - }); - - assertNotNull(userInfos); - assertTrue(userInfos.content.size() == 1); - assertNotNull(getUserInfo("deactivatedUser", userInfos.content)); - - } - - @Test - public void getPageNoFilterNoPageAttributes() throws Exception { - - // expecting all user accounts of the institution of SEBAdmin - - final String token = getSebAdminAccess(); - final Page userInfos = this.jsonMapper.readValue( - this.mockMvc.perform(get(this.endpoint + API.USER_ACCOUNT_ENDPOINT + "?institutionId=1") - .contentType(MediaType.APPLICATION_FORM_URLENCODED) - .header("Authorization", "Bearer " + token)) - .andExpect(status().isOk()) - .andReturn().getResponse().getContentAsString(), - new TypeReference>() { - }); - - assertNotNull(userInfos); - assertTrue(userInfos.numberOfPages == 1); - assertNotNull(userInfos.content); - assertTrue(userInfos.content.size() == 3); - assertEquals("[user1, user2, user5]", getOrderedUUIDs(userInfos.content)); - } - - @Test - public void getPageNoFilterNoPageAttributesFromOtherInstitution() throws Exception { - - // expecting all user accounts of institution 2 - - final String token = getSebAdminAccess(); - final Page userInfos = this.jsonMapper.readValue( - this.mockMvc - .perform(get(this.endpoint + API.USER_ACCOUNT_ENDPOINT + "?institutionId=2") - .contentType(MediaType.APPLICATION_FORM_URLENCODED) - .header("Authorization", "Bearer " + token)) - .andExpect(status().isOk()) - .andReturn().getResponse().getContentAsString(), - new TypeReference>() { - }); - - assertNotNull(userInfos); - assertTrue(userInfos.numberOfPages == 1); - assertNotNull(userInfos.content); - assertTrue(userInfos.content.size() == 4); - assertEquals("[user3, user4, user6, user7]", getOrderedUUIDs(userInfos.content)); - } - - @Test - public void getPageNoFilterNoPageAttributesDescendingOrder() throws Exception { - final String token = getSebAdminAccess(); - final Page userInfos = this.jsonMapper.readValue( - this.mockMvc.perform(get(this.endpoint + API.USER_ACCOUNT_ENDPOINT + "?sort=-&institutionId=1") - .contentType(MediaType.APPLICATION_FORM_URLENCODED) - .header("Authorization", "Bearer " + token)) - .andExpect(status().isOk()) - .andReturn().getResponse().getContentAsString(), - new TypeReference>() { - }); - - assertNotNull(userInfos); - assertTrue(userInfos.numberOfPages == 1); - assertNotNull(userInfos.content); - assertTrue(userInfos.content.size() == 3); - assertEquals("[user5, user2, user1]", getOrderedUUIDs(userInfos.content)); - } - - @Test - public void getPageOfSize3NoFilter() throws Exception { - final String token = getSebAdminAccess(); - - // first page default sort order - Page userInfos = this.jsonMapper.readValue( - this.mockMvc - .perform(get(this.endpoint + API.USER_ACCOUNT_ENDPOINT - + "?page_number=1&page_size=3&institutionId=2") - .contentType(MediaType.APPLICATION_FORM_URLENCODED) - .header("Authorization", "Bearer " + token)) - .andExpect(status().isOk()) - .andReturn().getResponse().getContentAsString(), - new TypeReference>() { - }); - - assertNotNull(userInfos); - assertTrue(userInfos.numberOfPages == 2); - assertNotNull(userInfos.content); - assertTrue(userInfos.content.size() == 3); - assertEquals("[user3, user4, user6]", getOrderedUUIDs(userInfos.content)); - - // second page default sort order - userInfos = this.jsonMapper.readValue( - this.mockMvc - .perform(get(this.endpoint + API.USER_ACCOUNT_ENDPOINT - + "?page_number=2&page_size=3&institutionId=2") - .contentType(MediaType.APPLICATION_FORM_URLENCODED) - .header("Authorization", "Bearer " + token)) - .andExpect(status().isOk()) - .andReturn().getResponse().getContentAsString(), - new TypeReference>() { - }); - - assertNotNull(userInfos); - assertTrue(userInfos.numberOfPages == 2); - assertNotNull(userInfos.content); - assertTrue(userInfos.pageSize == 1); - assertTrue(userInfos.content.size() == 1); - assertEquals("[user7]", getOrderedUUIDs(userInfos.content)); - - // invalid page number should refer to last page - userInfos = this.jsonMapper.readValue( - this.mockMvc - .perform(get(this.endpoint + API.USER_ACCOUNT_ENDPOINT - + "?page_number=3&page_size=3&institutionId=2") - .contentType(MediaType.APPLICATION_FORM_URLENCODED) - .header("Authorization", "Bearer " + token)) - .andExpect(status().isOk()) - .andReturn().getResponse().getContentAsString(), - new TypeReference>() { - }); - - assertNotNull(userInfos); - assertTrue(userInfos.numberOfPages == 2); - assertTrue(userInfos.pageNumber == 2); - assertNotNull(userInfos.content); - assertTrue(userInfos.content.size() == 1); - assertEquals("[user7]", getOrderedUUIDs(userInfos.content)); - - // first page descending sort order - userInfos = this.jsonMapper.readValue( - this.mockMvc - .perform(get(this.endpoint + API.USER_ACCOUNT_ENDPOINT - + "?page_number=1&page_size=3&sort=-&institutionId=2") - .contentType(MediaType.APPLICATION_FORM_URLENCODED) - .header("Authorization", "Bearer " + token)) - .andExpect(status().isOk()) - .andReturn().getResponse().getContentAsString(), - new TypeReference>() { - }); - - assertNotNull(userInfos); - assertTrue(userInfos.numberOfPages == 2); - assertNotNull(userInfos.content); - assertTrue(userInfos.content.size() == 3); - assertEquals("[user7, user6, user4]", getOrderedUUIDs(userInfos.content)); - } - - @Test - public void getAllUserInfo() throws Exception { - final String token = getSebAdminAccess(); - final Page userInfos = this.jsonMapper.readValue( - this.mockMvc.perform(get(this.endpoint + API.USER_ACCOUNT_ENDPOINT + "?institutionId=1") - .contentType(MediaType.APPLICATION_FORM_URLENCODED) - .header("Authorization", "Bearer " + token)) - .andExpect(status().isOk()) - .andReturn().getResponse().getContentAsString(), - new TypeReference>() { - }); - - assertNotNull(userInfos); - assertTrue(userInfos.content.size() == 3); - } - - @Test - public void getAllUserInfoWithOnlyActive() throws Exception { - final String token = getSebAdminAccess(); - final Page userInfos = this.jsonMapper.readValue( - this.mockMvc - .perform(get(this.endpoint + API.USER_ACCOUNT_ENDPOINT - + "?active=true&institutionId=2") - .contentType(MediaType.APPLICATION_FORM_URLENCODED) - .header("Authorization", "Bearer " + token)) - .andExpect(status().isOk()) - .andReturn().getResponse().getContentAsString(), - new TypeReference>() { - }); - - assertNotNull(userInfos); - assertTrue(userInfos.content.size() == 3); - assertNull(getUserInfo("deactivatedUser", userInfos.content)); - } - - @Test - public void getAllUserInfoOnlyInactive() throws Exception { - - // expecting none for SEBAdmins institution - final String token = getSebAdminAccess(); - Page userInfos = this.jsonMapper.readValue( - this.mockMvc.perform(get(this.endpoint + API.USER_ACCOUNT_ENDPOINT + "?active=false&institutionId=1") - .contentType(MediaType.APPLICATION_FORM_URLENCODED) - .header("Authorization", "Bearer " + token)) - .andExpect(status().isOk()) - .andReturn().getResponse().getContentAsString(), - new TypeReference>() { - }); - - assertNotNull(userInfos); - assertTrue(userInfos.content.size() == 0); - - // expecting one for institution 2 - userInfos = this.jsonMapper.readValue( - this.mockMvc - .perform(get(this.endpoint + API.USER_ACCOUNT_ENDPOINT - + "?active=false&institutionId=2") - .contentType(MediaType.APPLICATION_FORM_URLENCODED) - .header("Authorization", "Bearer " + token)) - .andExpect(status().isOk()) - .andReturn().getResponse().getContentAsString(), - new TypeReference>() { - }); - - assertNotNull(userInfos); - assertTrue(userInfos.content.size() == 1); - assertNotNull(getUserInfo("deactivatedUser", userInfos.content)); - } - - @Test - public void getAllUserInfoWithSearchUsernameLike() throws Exception { - final String token = getSebAdminAccess(); - final Page userInfos = this.jsonMapper.readValue( - this.mockMvc - .perform(get(this.endpoint + API.USER_ACCOUNT_ENDPOINT + "?username=exam&institutionId=1") - .contentType(MediaType.APPLICATION_FORM_URLENCODED) - .header("Authorization", "Bearer " + token)) - .andExpect(status().isOk()) - .andReturn().getResponse().getContentAsString(), - new TypeReference>() { - }); - - assertNotNull(userInfos); - assertTrue(userInfos.content.size() == 1); - assertNotNull(getUserInfo("examSupporter", userInfos.content)); - } - - @Test - public void testOwnerGet() throws Exception { - final String examAdminToken1 = getExamAdmin1(); - this.mockMvc.perform(get(this.endpoint + API.USER_ACCOUNT_ENDPOINT + "/me") - .header("Authorization", "Bearer " + examAdminToken1)) - .andExpect(status().isOk()) - .andReturn().getResponse().getContentAsString(); - } - - @Test - public void createUserTest() throws Exception { - final String token = getSebAdminAccess(); - final UserInfo createdUser = this.jsonMapper.readValue( - this.mockMvc.perform(post(this.endpoint + API.USER_ACCOUNT_ENDPOINT) - .header("Authorization", "Bearer " + token) - .contentType(MediaType.APPLICATION_FORM_URLENCODED) - .param(Domain.USER.ATTR_NAME, "NewTestUser") - .param(Domain.USER.ATTR_USERNAME, "NewTestUser") - .param(Domain.USER.ATTR_LANGUAGE, Locale.ENGLISH.toLanguageTag()) - .param(Domain.USER.ATTR_TIMEZONE, DateTimeZone.UTC.getID()) - .param(Domain.USER_ROLE.REFERENCE_NAME, UserRole.EXAM_ADMIN.name()) - .param(PasswordChange.ATTR_NAME_NEW_PASSWORD, "12345678") - .param(PasswordChange.ATTR_NAME_CONFIRM_NEW_PASSWORD, "12345678")) - .andExpect(status().isOk()) - .andReturn().getResponse().getContentAsString(), - new TypeReference() { - }); - - assertNotNull(createdUser); - assertEquals("NewTestUser", createdUser.name); - - // get newly created user and check equality - final UserInfo createdUserGet = this.jsonMapper.readValue( - this.mockMvc.perform( - get(this.endpoint + API.USER_ACCOUNT_ENDPOINT + "/" + createdUser.uuid) - .contentType(MediaType.APPLICATION_FORM_URLENCODED) - .header("Authorization", "Bearer " + token) - .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_FORM_URLENCODED_VALUE)) - .andExpect(status().isOk()) - .andReturn().getResponse().getContentAsString(), - new TypeReference() { - }); - - assertNotNull(createdUserGet); - assertEquals(createdUser.getEntityKey(), createdUserGet.getEntityKey()); - assertFalse(createdUserGet.isActive()); - - // check user activity log for newly created user - final Page logs = this.jsonMapper.readValue( - this.mockMvc - .perform( - get(this.endpoint + API.USER_ACTIVITY_LOG_ENDPOINT - + "?username=admin&activity_types=CREATE") - .header("Authorization", "Bearer " + token) - .header(HttpHeaders.CONTENT_TYPE, - MediaType.APPLICATION_FORM_URLENCODED_VALUE)) - .andExpect(status().isOk()) - .andReturn().getResponse().getContentAsString(), - new TypeReference>() { - }); - - assertNotNull(logs); - assertTrue(1 == logs.content.size()); - final UserActivityLog userActivityLog = logs.content.iterator().next(); - assertEquals("user1", userActivityLog.userUUID); - assertEquals("USER", userActivityLog.entityType.name()); - assertEquals("CREATE", userActivityLog.activityType.name()); - assertEquals(createdUserGet.uuid, userActivityLog.entityId); - } - -// NOTE: this tests transaction rollback is working but for now only if a runtime exception is thrown on -// UserDaoImpl.updateUser after the main record (UserRecord) is stored but the new roles are not -// updated so far. -// TODO: make this test running separately in an test with UserDaoImpl mockup - -// @Test -// public void modifyUserTestTransaction() throws Exception { -// final String token = getSebAdminAccess(); -// final UserInfo user = this.jsonMapper.readValue( -// this.mockMvc.perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "/user7") -// .header("Authorization", "Bearer " + token)) -// .andExpect(status().isOk()) -// .andReturn().getResponse().getContentAsString(), -// new TypeReference() { -// }); -// -// assertNotNull(user); -// assertEquals("User", user.name); -// assertEquals("user1", user.userName); -// assertEquals("user@nomail.nomail", user.email); -// assertEquals("[EXAM_SUPPORTER]", String.valueOf(user.roles)); -// -// // change userName, email and roles -// final UserMod modifyUser = new UserMod(new UserInfo( -// user.getUuid(), -// user.getInstitutionId(), -// user.getName(), -// "newUser1", -// "newUser@nomail.nomail", -// user.getActive(), -// user.getLocale(), -// user.getTimeZone(), -// Stream.of(UserRole.EXAM_ADMIN.name(), UserRole.EXAM_SUPPORTER.name()).collect(Collectors.toSet())), -// null, null); -// final String modifyUserJson = this.jsonMapper.writeValueAsString(modifyUser); -// -// final String contentAsString = this.mockMvc -// .perform(post(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "/save") -// .header("Authorization", "Bearer " + token) -// .contentType(MediaType.APPLICATION_JSON_UTF8) -// .content(modifyUserJson)) -// .andReturn().getResponse().getContentAsString(); -// -// // double check by getting the user by UUID -// final UserInfo unmodifiedUserResult = this.jsonMapper.readValue( -// this.mockMvc.perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "/" + user.uuid) -// .header("Authorization", "Bearer " + token)) -// .andExpect(status().isOk()) -// .andReturn().getResponse().getContentAsString(), -// new TypeReference() { -// }); -// -// assertNotNull(unmodifiedUserResult); -// assertEquals("User", unmodifiedUserResult.name); -// assertEquals("user1", unmodifiedUserResult.userName); -// assertEquals("user@nomail.nomail", unmodifiedUserResult.email); -// assertEquals("[EXAM_SUPPORTER]", String.valueOf(unmodifiedUserResult.roles)); -// } - - @Test - public void modifyUserWithPUTMethod() throws Exception { - final String token = getSebAdminAccess(); - final UserInfo user = this.jsonMapper.readValue( - this.mockMvc.perform(get(this.endpoint + API.USER_ACCOUNT_ENDPOINT + "/user7") - .contentType(MediaType.APPLICATION_FORM_URLENCODED) - .header("Authorization", "Bearer " + token)) - .andExpect(status().isOk()) - .andReturn().getResponse().getContentAsString(), - new TypeReference() { - }); - - assertNotNull(user); - assertEquals("User", user.name); - assertEquals("user1", user.username); - assertEquals("user@nomail.nomail", user.email); - assertEquals("[EXAM_SUPPORTER]", String.valueOf(user.roles)); - - // change userName, email and roles - final UserInfo modifyUser = new UserInfo( - user.uuid, - user.getInstitutionId(), - new DateTime(0, DateTimeZone.UTC), - user.getName(), - user.getSurname(), - "newUser1", - "newUser@nomail.nomail", - user.getActive(), - user.getLanguage(), - user.getTimeZone(), - Stream.of(UserRole.EXAM_ADMIN.name(), UserRole.EXAM_SUPPORTER.name()).collect(Collectors.toSet())); - final String modifyUserJson = this.jsonMapper.writeValueAsString(modifyUser); - - UserInfo modifiedUserResult = this.jsonMapper.readValue( - this.mockMvc.perform(put(this.endpoint + API.USER_ACCOUNT_ENDPOINT) - .header("Authorization", "Bearer " + token) - .contentType(MediaType.APPLICATION_JSON_UTF8) - .content(modifyUserJson)) - .andExpect(status().isOk()) - .andReturn().getResponse().getContentAsString(), - new TypeReference() { - }); - - assertNotNull(modifiedUserResult); - assertEquals(user.uuid, modifiedUserResult.uuid); - assertEquals("User", modifiedUserResult.name); - assertEquals("newUser1", modifiedUserResult.username); - assertEquals("newUser@nomail.nomail", modifiedUserResult.email); - assertEquals("[EXAM_ADMIN, EXAM_SUPPORTER]", String.valueOf(modifiedUserResult.roles)); - - // double check by getting the user by UUID - modifiedUserResult = this.jsonMapper.readValue( - this.mockMvc - .perform(get(this.endpoint + API.USER_ACCOUNT_ENDPOINT + "/" - + modifiedUserResult.uuid) - .contentType(MediaType.APPLICATION_FORM_URLENCODED) - .header("Authorization", "Bearer " + token)) - .andExpect(status().isOk()) - .andReturn().getResponse().getContentAsString(), - new TypeReference() { - }); - - assertNotNull(modifiedUserResult); - assertEquals("User", modifiedUserResult.name); - assertEquals("newUser1", modifiedUserResult.username); - assertEquals("newUser@nomail.nomail", modifiedUserResult.email); - assertEquals("[EXAM_ADMIN, EXAM_SUPPORTER]", String.valueOf(modifiedUserResult.roles)); - } - - @Test - public void testModifyUserOnInactiveInstitutionNotAllowed() throws Exception { - // create new institution with seb-admin that is not active - final Institution institution = new RestAPITestHelper() - .withAccessToken(getSebAdminAccess()) - .withPath(API.INSTITUTION_ENDPOINT) - .withMethod(HttpMethod.POST) - .withAttribute("name", "new institution") - .withAttribute("urlSuffix", "new_inst") - .withAttribute("active", "false") - .withExpectedStatus(HttpStatus.OK) - .getAsObject(new TypeReference() { - }); - - assertNotNull(institution); - assertNotNull(institution.id); - assertEquals("new institution", institution.name); - - // try to create a user for this institution should not be possible - final Collection errors = this.jsonMapper.readValue( - this.mockMvc.perform(post(this.endpoint + API.USER_ACCOUNT_ENDPOINT) - .header("Authorization", "Bearer " + getSebAdminAccess()) - .contentType(MediaType.APPLICATION_FORM_URLENCODED) - .param(Domain.USER.ATTR_INSTITUTION_ID, String.valueOf(institution.id)) - .param(Domain.USER.ATTR_NAME, "NewTestUser") - .param(Domain.USER.ATTR_USERNAME, "NewTestUser") - .param(Domain.USER.ATTR_LANGUAGE, Locale.ENGLISH.toLanguageTag()) - .param(Domain.USER.ATTR_TIMEZONE, DateTimeZone.UTC.getID()) - .param(Domain.USER_ROLE.REFERENCE_NAME, UserRole.EXAM_ADMIN.name()) - .param(PasswordChange.ATTR_NAME_NEW_PASSWORD, "12345678") - .param(PasswordChange.ATTR_NAME_CONFIRM_NEW_PASSWORD, "12345678")) - .andExpect(status().isBadRequest()) - .andReturn().getResponse().getContentAsString(), - new TypeReference>() { - }); - - assertNotNull(errors); - assertTrue(errors.size() == 1); - assertEquals( - "Illegal API request argument", - errors.iterator().next().systemMessage); - assertEquals( - "User within an inactive institution cannot be created nor modified", - errors.iterator().next().details); - } - -// @Test -// public void modifyUserWithPOSTMethod() throws Exception { -// final String token = getSebAdminAccess(); -// -// final UserInfo modifiedUser = this.jsonMapper.readValue( -// this.mockMvc.perform(patch(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "/user4") -// .header("Authorization", "Bearer " + token) -// .contentType(MediaType.APPLICATION_FORM_URLENCODED) -// .param("name", "PostModifyTest")) -// .andExpect(status().isOk()) -// .andReturn().getResponse().getContentAsString(), -// new TypeReference() { -// }); -// -// assertNotNull(modifiedUser); -// assertEquals("PostModifyTest", modifiedUser.name); -// -// // check validation -// final Collection errors = this.jsonMapper.readValue( -// this.mockMvc.perform(patch(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "/user4") -// .header("Authorization", "Bearer " + token) -// .contentType(MediaType.APPLICATION_FORM_URLENCODED) -// .param("name", "P")) -// .andExpect(status().isBadRequest()) -// .andReturn().getResponse().getContentAsString(), -// new TypeReference>() { -// }); -// -// assertNotNull(errors); -// assertFalse(errors.isEmpty()); -// final APIMessage error = errors.iterator().next(); -// assertEquals("1200", error.messageCode); -// } - - @Test - public void testOwnerModifyPossibleForExamAdmin() throws Exception { - final String examAdminToken1 = getExamAdmin1(); - final UserInfo examAdmin = this.jsonMapper.readValue( - this.mockMvc.perform(get(this.endpoint + API.USER_ACCOUNT_ENDPOINT + "/me") - .header("Authorization", "Bearer " + examAdminToken1)) - .andExpect(status().isOk()) - .andReturn().getResponse().getContentAsString(), - new TypeReference() { - }); - - final String modifiedUserJson = this.jsonMapper.writeValueAsString(examAdmin); - - this.mockMvc.perform(put(this.endpoint + API.USER_ACCOUNT_ENDPOINT) - .header("Authorization", "Bearer " + examAdminToken1) - .contentType(MediaType.APPLICATION_JSON_UTF8) - .content(modifiedUserJson)) - .andExpect(status().isOk()) - .andReturn().getResponse().getContentAsString(); - } - - @Test - public void institutionalAdminTryToCreateOrModifyUserForOtherInstituionNotPossible() throws Exception { - - final String token = getAdminInstitution1Access(); - this.mockMvc.perform(post(this.endpoint + API.USER_ACCOUNT_ENDPOINT) - .header("Authorization", "Bearer " + token) - .contentType(MediaType.APPLICATION_FORM_URLENCODED) - .param(Domain.USER.ATTR_INSTITUTION_ID, "2") - .param(Domain.USER.ATTR_NAME, "NewTestUser") - .param(PasswordChange.ATTR_NAME_NEW_PASSWORD, "12345678") - .param(PasswordChange.ATTR_NAME_CONFIRM_NEW_PASSWORD, "12345678")) - .andExpect(status().isForbidden()) - .andReturn().getResponse().getContentAsString(); - - final UserInfo userInfo = new UserInfo( - "NewTestUser", 2L, new DateTime(0, DateTimeZone.UTC), "NewTestUser", "", "NewTestUser", - "", true, Locale.CANADA, DateTimeZone.UTC, - new HashSet<>(Arrays.asList(UserRole.EXAM_ADMIN.name()))); - final String newUserJson = this.jsonMapper.writeValueAsString(userInfo); - this.mockMvc.perform(put(this.endpoint + API.USER_ACCOUNT_ENDPOINT) - .header("Authorization", "Bearer " + token) - .contentType(MediaType.APPLICATION_JSON_UTF8) - .content(newUserJson)) - .andExpect(status().isForbidden()) - .andReturn().getResponse().getContentAsString(); - } - - @Test - public void unauthorizedAdminTryToCreateUserNotPossible() throws Exception { - - final String token = getExamAdmin1(); - this.mockMvc.perform(post(this.endpoint + API.USER_ACCOUNT_ENDPOINT) - .header("Authorization", "Bearer " + token) - .contentType(MediaType.APPLICATION_FORM_URLENCODED) - .param(Domain.USER.ATTR_INSTITUTION_ID, "2") - .param(Domain.USER.ATTR_NAME, "NewTestUser") - .param(PasswordChange.ATTR_NAME_NEW_PASSWORD, "12345678") - .param(PasswordChange.ATTR_NAME_CONFIRM_NEW_PASSWORD, "12345678")) - .andExpect(status().isForbidden()) - .andReturn().getResponse().getContentAsString(); - - final UserInfo userInfo = new UserInfo( - "NewTestUser", 2L, new DateTime(0, DateTimeZone.UTC), "NewTestUser", "", "NewTestUser", - "", true, Locale.CANADA, DateTimeZone.UTC, - new HashSet<>(Arrays.asList(UserRole.EXAM_ADMIN.name()))); - //final UserMod newUser = new UserMod(userInfo, "12345678", "12345678"); - final String newUserJson = this.jsonMapper.writeValueAsString(userInfo); - this.mockMvc.perform(put(this.endpoint + API.USER_ACCOUNT_ENDPOINT) - .header("Authorization", "Bearer " + token) - .contentType(MediaType.APPLICATION_JSON_UTF8) - .content(newUserJson)) - .andExpect(status().isForbidden()) - .andReturn().getResponse().getContentAsString(); - } - - @Test - public void modifyUserPassword() throws Exception { - final String examAdminToken1 = getExamAdmin1(); - assertNotNull(examAdminToken1); - - // a SEB Server Admin now changes the password of ExamAdmin1 - final String sebAdminToken = getSebAdminAccess(); - final UserInfo examAdmin1 = this.jsonMapper.readValue( - this.mockMvc.perform(get(this.endpoint + API.USER_ACCOUNT_ENDPOINT + "/user4") - .contentType(MediaType.APPLICATION_FORM_URLENCODED) - .header("Authorization", "Bearer " + sebAdminToken)) - .andExpect(status().isOk()) - .andReturn().getResponse().getContentAsString(), - new TypeReference() { - }); - - final PasswordChange passwordChange = new PasswordChange( - examAdmin1.uuid, - "admin", - "newPassword", - "newPassword"); - final String modifiedUserJson = this.jsonMapper.writeValueAsString(passwordChange); - - this.mockMvc.perform( - put(this.endpoint + API.USER_ACCOUNT_ENDPOINT + API.PASSWORD_PATH_SEGMENT) - .header("Authorization", "Bearer " + sebAdminToken) - .contentType(MediaType.APPLICATION_JSON_UTF8) - .content(modifiedUserJson)) - .andExpect(status().isOk()) - .andReturn().getResponse().getContentAsString(); - - // now it should not be possible to get a access token for ExamAdmin1 with the standard password - try { - getExamAdmin1(); - fail("AssertionError expected here"); - } catch (final AssertionError e) { - assertEquals("Status expected:<200> but was:<400>", e.getMessage()); - } - - // it should also not be possible to use an old token again after password change - this.mockMvc.perform(get(this.endpoint + API.USER_ACCOUNT_ENDPOINT + "/me") - .header("Authorization", "Bearer " + examAdminToken1)) - .andExpect(status().isUnauthorized()) - .andReturn().getResponse().getContentAsString(); - - // but it should be possible to get a new access token and request again - final String examAdminToken2 = obtainAccessToken("examAdmin1", "newPassword"); - this.mockMvc.perform(get(this.endpoint + API.USER_ACCOUNT_ENDPOINT + "/me") - .header("Authorization", "Bearer " + examAdminToken2)) - .andExpect(status().isOk()) - .andReturn().getResponse().getContentAsString(); - } - - @Test - public void modifyUserPasswordInvalidPasswords() throws Exception { - final String sebAdminToken = getSebAdminAccess(); - final UserInfo examAdmin1 = this.jsonMapper.readValue( - this.mockMvc.perform(get(this.endpoint + API.USER_ACCOUNT_ENDPOINT + "/user4") - .contentType(MediaType.APPLICATION_FORM_URLENCODED) - .header("Authorization", "Bearer " + sebAdminToken)) - .andExpect(status().isOk()) - .andReturn().getResponse().getContentAsString(), - new TypeReference() { - }); - - // must be longer then 8 chars - PasswordChange passwordChange = new PasswordChange( - examAdmin1.uuid, - "admin", - "new", - "new"); - String modifiedUserJson = this.jsonMapper.writeValueAsString(passwordChange); - - List messages = this.jsonMapper.readValue( - this.mockMvc.perform( - put(this.endpoint + API.USER_ACCOUNT_ENDPOINT + API.PASSWORD_PATH_SEGMENT) - .header("Authorization", "Bearer " + sebAdminToken) - .contentType(MediaType.APPLICATION_JSON_UTF8) - .content(modifiedUserJson)) - .andExpect(status().isBadRequest()) - .andReturn().getResponse().getContentAsString(), - new TypeReference>() { - }); - - assertNotNull(messages); - assertTrue(1 == messages.size()); - assertEquals("1200", messages.get(0).messageCode); - assertEquals("[user, newPassword, size, 8, 255, new]", String.valueOf(messages.get(0).getAttributes())); - - // wrong password retype - passwordChange = new PasswordChange( - examAdmin1.uuid, - "admin", - "12345678", - "87654321"); - modifiedUserJson = this.jsonMapper.writeValueAsString(passwordChange); - - messages = this.jsonMapper.readValue( - this.mockMvc.perform( - put(this.endpoint + API.USER_ACCOUNT_ENDPOINT + API.PASSWORD_PATH_SEGMENT) - .header("Authorization", "Bearer " + sebAdminToken) - .contentType(MediaType.APPLICATION_JSON_UTF8) - .content(modifiedUserJson)) - .andExpect(status().isBadRequest()) - .andReturn().getResponse().getContentAsString(), - new TypeReference>() { - }); - - assertNotNull(messages); - assertTrue(1 == messages.size()); - assertEquals("1200", messages.get(0).messageCode); - } - - @Test - public void deactivateUserAccount() throws Exception { - final String timeNow = DateTime.now(DateTimeZone.UTC).toString(Constants.STANDARD_DATE_TIME_FORMATTER); - // only a SEB Administrator or an Institutional administrator should be able to deactivate a user-account - final String examAdminToken = getExamAdmin1(); - this.mockMvc.perform(post(this.endpoint + API.USER_ACCOUNT_ENDPOINT + "/user4/inactive") - .contentType(MediaType.APPLICATION_FORM_URLENCODED) - .header("Authorization", "Bearer " + examAdminToken)) - .andExpect(status().isForbidden()); - - // With SEB Administrator it should work - final String sebAdminToken = getSebAdminAccess(); - final EntityProcessingReport report = this.jsonMapper.readValue( - this.mockMvc - .perform(post(this.endpoint + API.USER_ACCOUNT_ENDPOINT + "/user4/inactive") - .contentType(MediaType.APPLICATION_FORM_URLENCODED) - .header("Authorization", "Bearer " + sebAdminToken)) - .andExpect(status().isOk()) - .andReturn().getResponse().getContentAsString(), - new TypeReference() { - }); - - assertNotNull(report); - assertNotNull(report.source); - assertTrue(report.dependencies.isEmpty()); // TODO - assertTrue(report.errors.isEmpty()); - assertTrue(report.source.size() == 1); - - // get user and check activity - final EntityKey key = report.source.iterator().next(); - final UserInfo user = this.jsonMapper.readValue( - this.mockMvc - .perform(get(this.endpoint + API.USER_ACCOUNT_ENDPOINT + "/" + key.modelId) - .contentType(MediaType.APPLICATION_FORM_URLENCODED) - .header("Authorization", "Bearer " + sebAdminToken)) - .andExpect(status().isOk()) - .andReturn().getResponse().getContentAsString(), - new TypeReference() { - }); - - assertNotNull(user); - assertFalse(user.isActive()); - - // check also user activity log - final Page userLogs = this.jsonMapper.readValue( - this.mockMvc - .perform( - get(this.endpoint + API.USER_ACTIVITY_LOG_ENDPOINT - + "/?user=user1&from=" + timeNow) - .contentType(MediaType.APPLICATION_FORM_URLENCODED) - .header("Authorization", "Bearer " + sebAdminToken)) - .andExpect(status().isOk()) - .andReturn().getResponse().getContentAsString(), - new TypeReference>() { - }); - - assertNotNull(userLogs); - assertTrue(userLogs.content.size() == 1); - final UserActivityLog userLog = userLogs.content.iterator().next(); - assertEquals(UserLogActivityType.DEACTIVATE, userLog.activityType); - assertEquals("user4", userLog.entityId); - } - - @Test - public void activateUserAccount() throws Exception { - final String timeNow = DateTime.now(DateTimeZone.UTC).toString(Constants.STANDARD_DATE_TIME_FORMATTER); - // only a SEB Administrator or an Institutional administrator should be able to deactivate a user-account - final String examAdminToken = getExamAdmin1(); - this.mockMvc.perform(post(this.endpoint + API.USER_ACCOUNT_ENDPOINT + "/user6/active") - .contentType(MediaType.APPLICATION_FORM_URLENCODED) - .header("Authorization", "Bearer " + examAdminToken)) - .andExpect(status().isForbidden()); - - // With SEB Administrator it should work - final String sebAdminToken = getSebAdminAccess(); - final EntityProcessingReport report = this.jsonMapper.readValue( - this.mockMvc - .perform(post(this.endpoint + API.USER_ACCOUNT_ENDPOINT + "/user6/active") - .contentType(MediaType.APPLICATION_FORM_URLENCODED) - .header("Authorization", "Bearer " + sebAdminToken)) - .andExpect(status().isOk()) - .andReturn().getResponse().getContentAsString(), - new TypeReference() { - }); - - assertNotNull(report); - assertNotNull(report.source); - assertTrue(report.dependencies.isEmpty()); // TODO - assertTrue(report.errors.isEmpty()); - assertTrue(report.source.size() == 1); - - // get user and check activity - final EntityKey key = report.source.iterator().next(); - final UserInfo user = this.jsonMapper.readValue( - this.mockMvc - .perform(get(this.endpoint + API.USER_ACCOUNT_ENDPOINT + "/" + key.modelId) - .contentType(MediaType.APPLICATION_FORM_URLENCODED) - .header("Authorization", "Bearer " + sebAdminToken)) - .andExpect(status().isOk()) - .andReturn().getResponse().getContentAsString(), - new TypeReference() { - }); - - assertNotNull(user); - assertTrue(user.isActive()); - - // check also user activity log - final Page userLogs = this.jsonMapper.readValue( - this.mockMvc - .perform(get(this.endpoint + API.USER_ACTIVITY_LOG_ENDPOINT - + "?user=user1&from=" + timeNow) - .header("Authorization", "Bearer " + sebAdminToken) - .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_FORM_URLENCODED_VALUE)) - .andExpect(status().isOk()) - .andReturn().getResponse().getContentAsString(), - new TypeReference>() { - }); - - assertNotNull(userLogs); - assertTrue(userLogs.content.size() == 1); - final UserActivityLog userLog = userLogs.content.iterator().next(); - assertEquals(UserLogActivityType.ACTIVATE, userLog.activityType); - assertEquals("user6", userLog.entityId); - } - - @Test - public void testGeneralAllActiveInactiveEndpoint() throws Exception { - final String sebAdminToken = getSebAdminAccess(); - - // all active for the own institution - Page usersPage = this.jsonMapper.readValue( - this.mockMvc.perform(get(this.endpoint + API.USER_ACCOUNT_ENDPOINT + "/active") - .contentType(MediaType.APPLICATION_FORM_URLENCODED) - .header("Authorization", "Bearer " + sebAdminToken)) - .andExpect(status().isOk()) - .andReturn().getResponse().getContentAsString(), - new TypeReference>() { - }); - - assertNotNull(usersPage); - assertTrue(usersPage.pageSize == 3); - assertEquals("[user1, user2, user5]", getOrderedUUIDs(usersPage.content)); - - // all inactive of the own institution - usersPage = this.jsonMapper.readValue( - this.mockMvc.perform(get(this.endpoint + API.USER_ACCOUNT_ENDPOINT + "/inactive") - .contentType(MediaType.APPLICATION_FORM_URLENCODED) - .header("Authorization", "Bearer " + sebAdminToken)) - .andExpect(status().isOk()) - .andReturn().getResponse().getContentAsString(), - new TypeReference>() { - }); - - assertNotNull(usersPage); - assertTrue(usersPage.pageSize == 0); - assertEquals("[]", getOrderedUUIDs(usersPage.content)); - - // all active of institution 2 - usersPage = this.jsonMapper.readValue( - this.mockMvc - .perform(get(this.endpoint + API.USER_ACCOUNT_ENDPOINT - + "/active?institutionId=2") - .contentType(MediaType.APPLICATION_FORM_URLENCODED) - .header("Authorization", "Bearer " + sebAdminToken)) - .andExpect(status().isOk()) - .andReturn().getResponse().getContentAsString(), - new TypeReference>() { - }); - - assertNotNull(usersPage); - assertTrue(usersPage.pageSize == 3); - assertEquals("[user3, user4, user7]", getOrderedUUIDs(usersPage.content)); - - // all inactive of institution 2 - usersPage = this.jsonMapper.readValue( - this.mockMvc - .perform(get(this.endpoint + API.USER_ACCOUNT_ENDPOINT - + "/inactive?institutionId=2") - .contentType(MediaType.APPLICATION_FORM_URLENCODED) - .header("Authorization", "Bearer " + sebAdminToken)) - .andExpect(status().isOk()) - .andReturn().getResponse().getContentAsString(), - new TypeReference>() { - }); - - assertNotNull(usersPage); - assertTrue(usersPage.pageSize == 1); - assertEquals("[user6]", getOrderedUUIDs(usersPage.content)); - } - - @Test - public void testGeneralListEndpoint() throws Exception { - final String sebAdminToken = getSebAdminAccess(); - - // for SEB Admin it should be possible to get from different institutions - Collection users = this.jsonMapper.readValue( - this.mockMvc - .perform( - get(this.endpoint + API.USER_ACCOUNT_ENDPOINT - + "/list?modelIds=user1,user2,user6,user7") - .contentType(MediaType.APPLICATION_FORM_URLENCODED) - .header("Authorization", "Bearer " + sebAdminToken)) - .andExpect(status().isOk()) - .andReturn().getResponse().getContentAsString(), - new TypeReference>() { - }); - - assertNotNull(users); - assertTrue(users.size() == 4); - assertEquals("[user1, user2, user6, user7]", getOrderedUUIDs(users)); - - // for an institutional admin it should only be possible to get from own institution - final String instAdminToken = getAdminInstitution2Access(); - users = this.jsonMapper.readValue( - this.mockMvc - .perform( - get(this.endpoint + API.USER_ACCOUNT_ENDPOINT - + "/list?modelIds=user1,user2,user6,user7") - .contentType(MediaType.APPLICATION_FORM_URLENCODED) - .header("Authorization", "Bearer " + instAdminToken)) - .andExpect(status().isOk()) - .andReturn().getResponse().getContentAsString(), - new TypeReference>() { - }); - - assertNotNull(users); - assertTrue(users.size() == 2); - assertEquals("[user6, user7]", getOrderedUUIDs(users)); - } - - @Test - public void testGeneralNamesEndpoint() throws Exception { - final String sebAdminToken = getSebAdminAccess(); - - // for SEB Admin - Collection names = this.jsonMapper.readValue( - this.mockMvc - .perform(get(this.endpoint + API.USER_ACCOUNT_ENDPOINT + "/names" + "?institutionId=1") - .contentType(MediaType.APPLICATION_FORM_URLENCODED) - .header("Authorization", "Bearer " + sebAdminToken)) - .andExpect(status().isOk()) - .andReturn().getResponse().getContentAsString(), - new TypeReference>() { - }); - - assertNotNull(names); - assertTrue(names.size() == 3); - assertEquals("[EntityName [entityType=USER, modelId=user1, name=SEBAdmin], " - + "EntityName [entityType=USER, modelId=user2, name=Institutional1 Admin], " - + "EntityName [entityType=USER, modelId=user5, name=Exam Supporter]]", names.toString()); - - // for an institutional admin 2 - final String instAdminToken = getAdminInstitution2Access(); - names = this.jsonMapper.readValue( - this.mockMvc - .perform(get(this.endpoint + API.USER_ACCOUNT_ENDPOINT + "/names" + "?institutionId=2") - .contentType(MediaType.APPLICATION_FORM_URLENCODED) - .header("Authorization", "Bearer " + instAdminToken)) - .andExpect(status().isOk()) - .andReturn().getResponse().getContentAsString(), - new TypeReference>() { - }); - - assertNotNull(names); - assertTrue(names.size() == 4); - assertEquals("[EntityName [entityType=USER, modelId=user3, name=Institutional2 Admin], " - + "EntityName [entityType=USER, modelId=user4, name=ExamAdmin1], " - + "EntityName [entityType=USER, modelId=user6, name=Deactivated], " - + "EntityName [entityType=USER, modelId=user7, name=User]]", names.toString()); - - // for an institutional admin 2 only active - names = this.jsonMapper.readValue( - this.mockMvc - .perform( - get(this.endpoint + API.USER_ACCOUNT_ENDPOINT + "/names?active=true&institutionId=2") - .contentType(MediaType.APPLICATION_FORM_URLENCODED) - .header("Authorization", "Bearer " + instAdminToken)) - .andExpect(status().isOk()) - .andReturn().getResponse().getContentAsString(), - new TypeReference>() { - }); - - assertNotNull(names); - assertTrue(names.size() == 3); - assertEquals("[EntityName [entityType=USER, modelId=user3, name=Institutional2 Admin], " - + "EntityName [entityType=USER, modelId=user4, name=ExamAdmin1], " - + "EntityName [entityType=USER, modelId=user7, name=User]]", names.toString()); - } - -// @Test -// public void createWithRoleAddRoleDeleteRole() throws Exception { -// final String token = getSebAdminAccess(); -// UserInfo createdUser = this.jsonMapper.readValue( -// this.mockMvc.perform(post(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT) -// .header("Authorization", "Bearer " + token) -// .contentType(MediaType.APPLICATION_FORM_URLENCODED) -// .param(Domain.USER.ATTR_NAME, "NewTestUser") -// .param(Domain.USER.ATTR_USERNAME, "NewTestUser") -// .param(Domain.USER.ATTR_LOCALE, Locale.ENGLISH.toLanguageTag()) -// .param(Domain.USER.ATTR_TIMEZONE, DateTimeZone.UTC.getID()) -// .param(UserMod.ATTR_NAME_NEW_PASSWORD, "12345678") -// .param(UserMod.ATTR_NAME_RETYPED_NEW_PASSWORD, "12345678")) -// .andExpect(status().isOk()) -// .andReturn().getResponse().getContentAsString(), -// new TypeReference() { -// }); -// -// assertNotNull(createdUser); -// assertEquals("NewTestUser", createdUser.name); -// assertEquals("[]", String.valueOf(createdUser.roles)); -// -// // add two roles -// createdUser = this.jsonMapper.readValue( -// this.mockMvc.perform(patch(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "/" + createdUser.uuid) -// .header("Authorization", "Bearer " + token) -// .contentType(MediaType.APPLICATION_FORM_URLENCODED) -// .param(USER_ROLE.REFERENCE_NAME, "EXAM_SUPPORTER", "EXAM_ADMIN")) -// .andExpect(status().isOk()) -// .andReturn().getResponse().getContentAsString(), -// new TypeReference() { -// }); -// -// assertNotNull(createdUser); -// assertEquals("NewTestUser", createdUser.name); -// assertEquals("[]", String.valueOf(createdUser.roles)); -// } - - private UserInfo getUserInfo(final String name, final Collection infos) { - try { - return infos - .stream() - .filter(ui -> ui.username.equals(name)) - .findFirst() - .orElseThrow(NoSuchElementException::new); - } catch (final Exception e) { - return null; - } - } - -} +/* + * Copyright (c) 2018 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.webservice.integration.api.admin; + +import static org.junit.Assert.*; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import java.util.Arrays; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Locale; +import java.util.NoSuchElementException; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import org.joda.time.DateTime; +import org.joda.time.DateTimeZone; +import org.junit.Test; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.test.context.jdbc.Sql; + +import com.fasterxml.jackson.core.type.TypeReference; + +import ch.ethz.seb.sebserver.gbl.Constants; +import ch.ethz.seb.sebserver.gbl.api.API; +import ch.ethz.seb.sebserver.gbl.api.APIMessage; +import ch.ethz.seb.sebserver.gbl.model.Domain; +import ch.ethz.seb.sebserver.gbl.model.Entity; +import ch.ethz.seb.sebserver.gbl.model.EntityKey; +import ch.ethz.seb.sebserver.gbl.model.EntityName; +import ch.ethz.seb.sebserver.gbl.model.EntityProcessingReport; +import ch.ethz.seb.sebserver.gbl.model.Page; +import ch.ethz.seb.sebserver.gbl.model.institution.Institution; +import ch.ethz.seb.sebserver.gbl.model.user.PasswordChange; +import ch.ethz.seb.sebserver.gbl.model.user.UserActivityLog; +import ch.ethz.seb.sebserver.gbl.model.user.UserInfo; +import ch.ethz.seb.sebserver.gbl.model.user.UserLogActivityType; +import ch.ethz.seb.sebserver.gbl.model.user.UserRole; + +@Sql(scripts = { "classpath:schema-test.sql", "classpath:data-test.sql" }) +public class UserAPITest extends AdministrationAPIIntegrationTester { + + @Test + public void getMyUserInfo() throws Exception { + String contentAsString = new RestAPITestHelper() + .withAccessToken(getSebAdminAccess()) + .withPath(API.USER_ACCOUNT_ENDPOINT + "/me") + .withExpectedStatus(HttpStatus.OK) + .getAsString(); + + assertEquals( + "{\"uuid\":\"user1\"," + + "\"institutionId\":1," + + "\"creationDate\":\"2019-01-01T00:00:00.000Z\"," + + "\"name\":\"SEBAdmin\"," + + "\"surname\":\"\"," + + "\"username\":\"admin\"," + + "\"email\":\"admin@nomail.nomail\"," + + "\"active\":true," + + "\"language\":\"en\"," + + "\"timezone\":\"UTC\"," + + "\"userRoles\":[\"EXAM_ADMIN\",\"EXAM_SUPPORTER\",\"SEB_SERVER_ADMIN\",\"INSTITUTIONAL_ADMIN\"]}", + contentAsString); + + contentAsString = new RestAPITestHelper() + .withAccessToken(getAdminInstitution1Access()) + .withPath(API.USER_ACCOUNT_ENDPOINT + "/me") + .withExpectedStatus(HttpStatus.OK) + .getAsString(); + + assertEquals( + "{\"uuid\":\"user2\"," + + "\"institutionId\":1," + + "\"creationDate\":\"2019-01-01T00:00:00.000Z\"," + + "\"name\":\"Institutional1 Admin\"," + + "\"surname\":\"\"," + + "\"username\":\"inst1Admin\"," + + "\"email\":\"admin@nomail.nomail\"," + + "\"active\":true," + + "\"language\":\"en\"," + + "\"timezone\":\"UTC\"," + + "\"userRoles\":[\"INSTITUTIONAL_ADMIN\"]}", + contentAsString); + } + + @Test + public void getUserInfoWithUUID() throws Exception { + final String sebAdminAccessToken = getSebAdminAccess(); + String contentAsString = this.mockMvc + .perform(get(this.endpoint + API.USER_ACCOUNT_ENDPOINT + "/user2") + .contentType(MediaType.APPLICATION_FORM_URLENCODED) + .header("Authorization", "Bearer " + sebAdminAccessToken)) + .andExpect(status().isOk()) + .andReturn().getResponse().getContentAsString(); + + assertEquals( + "{\"uuid\":\"user2\"," + + "\"institutionId\":1," + + "\"creationDate\":\"2019-01-01T00:00:00.000Z\"," + + "\"name\":\"Institutional1 Admin\"," + + "\"surname\":\"\"," + + "\"username\":\"inst1Admin\"," + + "\"email\":\"admin@nomail.nomail\"," + + "\"active\":true," + + "\"language\":\"en\"," + + "\"timezone\":\"UTC\"," + + "\"userRoles\":[\"INSTITUTIONAL_ADMIN\"]}", + contentAsString); + + final String adminInstitution2AccessToken = getAdminInstitution2Access(); + contentAsString = this.mockMvc + .perform(get(this.endpoint + API.USER_ACCOUNT_ENDPOINT + "/user1") + .contentType(MediaType.APPLICATION_FORM_URLENCODED) + .header("Authorization", "Bearer " + adminInstitution2AccessToken)) + .andExpect(status().isForbidden()) + .andReturn().getResponse().getContentAsString(); + + assertEquals( + "[{\"messageCode\":\"1001\"," + + "\"systemMessage\":\"FORBIDDEN\"," + + "\"details\":\"No grant: READ on type: USER entity institution: 1 entity owner: user1 for user: user3\"," + + "\"attributes\":[]}]", + contentAsString); + } + + @Test + public void institutionalAdminNotAllowedToSeeUsersOfOtherInstitution() throws Exception { + new RestAPITestHelper() + .withAccessToken(getAdminInstitution1Access()) + .withPath(API.USER_ACCOUNT_ENDPOINT + "?institutionId=2") + .withExpectedStatus(HttpStatus.FORBIDDEN) + .getAsString(); + } + + @Test + public void getAllUserInfoNoFilter() throws Exception { + Page userInfos = new RestAPITestHelper() + .withAccessToken(getSebAdminAccess()) + .withPath(API.USER_ACCOUNT_ENDPOINT + "?institutionId=1") + .withExpectedStatus(HttpStatus.OK) + .getAsObject(new TypeReference>() { + }); + + // expecting all users for a SEBAdmin except inactive. + assertNotNull(userInfos); + assertTrue(userInfos.content.size() == 3); + assertNotNull(getUserInfo("admin", userInfos.content)); + assertNotNull(getUserInfo("inst1Admin", userInfos.content)); + assertNotNull(getUserInfo("examSupporter", userInfos.content)); + + userInfos = new RestAPITestHelper() + .withAccessToken(getAdminInstitution2Access()) + .withPath(API.USER_ACCOUNT_ENDPOINT) + .withAttribute("institutionId", "2") + .withExpectedStatus(HttpStatus.OK) + .getAsObject(new TypeReference>() { + }); + + // expecting all users of institution 2 also inactive when active flag is not set + assertNotNull(userInfos); + assertTrue(userInfos.content.size() == 4); + assertNotNull(getUserInfo("inst2Admin", userInfos.content)); + assertNotNull(getUserInfo("examAdmin1", userInfos.content)); + assertNotNull(getUserInfo("deactivatedUser", userInfos.content)); + assertNotNull(getUserInfo("user1", userInfos.content)); + + //.. and without inactive, if active flag is set to true + userInfos = new RestAPITestHelper() + .withAccessToken(getAdminInstitution2Access()) + .withPath(API.USER_ACCOUNT_ENDPOINT) + .withAttribute(Entity.FILTER_ATTR_INSTITUTION, "2") + .withAttribute(Entity.FILTER_ATTR_ACTIVE, "true") + .withExpectedStatus(HttpStatus.OK) + .getAsObject(new TypeReference>() { + }); + + assertNotNull(userInfos); + assertTrue(userInfos.content.size() == 3); + assertNotNull(getUserInfo("inst2Admin", userInfos.content)); + assertNotNull(getUserInfo("examAdmin1", userInfos.content)); + assertNotNull(getUserInfo("user1", userInfos.content)); + + //.. and only inactive, if active flag is set to false + userInfos = new RestAPITestHelper() + .withAccessToken(getAdminInstitution2Access()) + .withPath(API.USER_ACCOUNT_ENDPOINT) + .withAttribute(Entity.FILTER_ATTR_INSTITUTION, "2") + .withAttribute(Entity.FILTER_ATTR_ACTIVE, "false") + .withExpectedStatus(HttpStatus.OK) + .getAsObject(new TypeReference>() { + }); + + assertNotNull(userInfos); + assertTrue(userInfos.content.size() == 1); + assertNotNull(getUserInfo("deactivatedUser", userInfos.content)); + + } + + @Test + public void getPageNoFilterNoPageAttributes() throws Exception { + + // expecting all user accounts of the institution of SEBAdmin + + final String token = getSebAdminAccess(); + final Page userInfos = this.jsonMapper.readValue( + this.mockMvc.perform(get(this.endpoint + API.USER_ACCOUNT_ENDPOINT + "?institutionId=1") + .contentType(MediaType.APPLICATION_FORM_URLENCODED) + .header("Authorization", "Bearer " + token)) + .andExpect(status().isOk()) + .andReturn().getResponse().getContentAsString(), + new TypeReference>() { + }); + + assertNotNull(userInfos); + assertTrue(userInfos.numberOfPages == 1); + assertNotNull(userInfos.content); + assertTrue(userInfos.content.size() == 3); + assertEquals("[user1, user2, user5]", getOrderedUUIDs(userInfos.content)); + } + + @Test + public void getPageNoFilterNoPageAttributesFromOtherInstitution() throws Exception { + + // expecting all user accounts of institution 2 + + final String token = getSebAdminAccess(); + final Page userInfos = this.jsonMapper.readValue( + this.mockMvc + .perform(get(this.endpoint + API.USER_ACCOUNT_ENDPOINT + "?institutionId=2") + .contentType(MediaType.APPLICATION_FORM_URLENCODED) + .header("Authorization", "Bearer " + token)) + .andExpect(status().isOk()) + .andReturn().getResponse().getContentAsString(), + new TypeReference>() { + }); + + assertNotNull(userInfos); + assertTrue(userInfos.numberOfPages == 1); + assertNotNull(userInfos.content); + assertTrue(userInfos.content.size() == 4); + assertEquals("[user3, user4, user6, user7]", getOrderedUUIDs(userInfos.content)); + } + + @Test + public void getPageNoFilterNoPageAttributesDescendingOrder() throws Exception { + final String token = getSebAdminAccess(); + final Page userInfos = this.jsonMapper.readValue( + this.mockMvc.perform(get(this.endpoint + API.USER_ACCOUNT_ENDPOINT + "?sort=-&institutionId=1") + .contentType(MediaType.APPLICATION_FORM_URLENCODED) + .header("Authorization", "Bearer " + token)) + .andExpect(status().isOk()) + .andReturn().getResponse().getContentAsString(), + new TypeReference>() { + }); + + assertNotNull(userInfos); + assertTrue(userInfos.numberOfPages == 1); + assertNotNull(userInfos.content); + assertTrue(userInfos.content.size() == 3); + assertEquals("[user5, user2, user1]", getOrderedUUIDs(userInfos.content)); + } + + @Test + public void getPageOfSize3NoFilter() throws Exception { + final String token = getSebAdminAccess(); + + // first page default sort order + Page userInfos = this.jsonMapper.readValue( + this.mockMvc + .perform(get(this.endpoint + API.USER_ACCOUNT_ENDPOINT + + "?page_number=1&page_size=3&institutionId=2") + .contentType(MediaType.APPLICATION_FORM_URLENCODED) + .header("Authorization", "Bearer " + token)) + .andExpect(status().isOk()) + .andReturn().getResponse().getContentAsString(), + new TypeReference>() { + }); + + assertNotNull(userInfos); + assertTrue(userInfos.numberOfPages == 2); + assertNotNull(userInfos.content); + assertTrue(userInfos.content.size() == 3); + assertEquals("[user3, user4, user6]", getOrderedUUIDs(userInfos.content)); + + // second page default sort order + userInfos = this.jsonMapper.readValue( + this.mockMvc + .perform(get(this.endpoint + API.USER_ACCOUNT_ENDPOINT + + "?page_number=2&page_size=3&institutionId=2") + .contentType(MediaType.APPLICATION_FORM_URLENCODED) + .header("Authorization", "Bearer " + token)) + .andExpect(status().isOk()) + .andReturn().getResponse().getContentAsString(), + new TypeReference>() { + }); + + assertNotNull(userInfos); + assertTrue(userInfos.numberOfPages == 2); + assertNotNull(userInfos.content); + assertTrue(userInfos.pageSize == 1); + assertTrue(userInfos.content.size() == 1); + assertEquals("[user7]", getOrderedUUIDs(userInfos.content)); + + // invalid page number should refer to last page + userInfos = this.jsonMapper.readValue( + this.mockMvc + .perform(get(this.endpoint + API.USER_ACCOUNT_ENDPOINT + + "?page_number=3&page_size=3&institutionId=2") + .contentType(MediaType.APPLICATION_FORM_URLENCODED) + .header("Authorization", "Bearer " + token)) + .andExpect(status().isOk()) + .andReturn().getResponse().getContentAsString(), + new TypeReference>() { + }); + + assertNotNull(userInfos); + assertTrue(userInfos.numberOfPages == 2); + assertTrue(userInfos.pageNumber == 2); + assertNotNull(userInfos.content); + assertTrue(userInfos.content.size() == 1); + assertEquals("[user7]", getOrderedUUIDs(userInfos.content)); + + // first page descending sort order + userInfos = this.jsonMapper.readValue( + this.mockMvc + .perform(get(this.endpoint + API.USER_ACCOUNT_ENDPOINT + + "?page_number=1&page_size=3&sort=-&institutionId=2") + .contentType(MediaType.APPLICATION_FORM_URLENCODED) + .header("Authorization", "Bearer " + token)) + .andExpect(status().isOk()) + .andReturn().getResponse().getContentAsString(), + new TypeReference>() { + }); + + assertNotNull(userInfos); + assertTrue(userInfos.numberOfPages == 2); + assertNotNull(userInfos.content); + assertTrue(userInfos.content.size() == 3); + assertEquals("[user7, user6, user4]", getOrderedUUIDs(userInfos.content)); + } + + @Test + public void getAllUserInfo() throws Exception { + final String token = getSebAdminAccess(); + final Page userInfos = this.jsonMapper.readValue( + this.mockMvc.perform(get(this.endpoint + API.USER_ACCOUNT_ENDPOINT + "?institutionId=1") + .contentType(MediaType.APPLICATION_FORM_URLENCODED) + .header("Authorization", "Bearer " + token)) + .andExpect(status().isOk()) + .andReturn().getResponse().getContentAsString(), + new TypeReference>() { + }); + + assertNotNull(userInfos); + assertTrue(userInfos.content.size() == 3); + } + + @Test + public void getAllUserInfoWithOnlyActive() throws Exception { + final String token = getSebAdminAccess(); + final Page userInfos = this.jsonMapper.readValue( + this.mockMvc + .perform(get(this.endpoint + API.USER_ACCOUNT_ENDPOINT + + "?active=true&institutionId=2") + .contentType(MediaType.APPLICATION_FORM_URLENCODED) + .header("Authorization", "Bearer " + token)) + .andExpect(status().isOk()) + .andReturn().getResponse().getContentAsString(), + new TypeReference>() { + }); + + assertNotNull(userInfos); + assertTrue(userInfos.content.size() == 3); + assertNull(getUserInfo("deactivatedUser", userInfos.content)); + } + + @Test + public void getAllUserInfoOnlyInactive() throws Exception { + + // expecting none for SEBAdmins institution + final String token = getSebAdminAccess(); + Page userInfos = this.jsonMapper.readValue( + this.mockMvc.perform(get(this.endpoint + API.USER_ACCOUNT_ENDPOINT + "?active=false&institutionId=1") + .contentType(MediaType.APPLICATION_FORM_URLENCODED) + .header("Authorization", "Bearer " + token)) + .andExpect(status().isOk()) + .andReturn().getResponse().getContentAsString(), + new TypeReference>() { + }); + + assertNotNull(userInfos); + assertTrue(userInfos.content.size() == 0); + + // expecting one for institution 2 + userInfos = this.jsonMapper.readValue( + this.mockMvc + .perform(get(this.endpoint + API.USER_ACCOUNT_ENDPOINT + + "?active=false&institutionId=2") + .contentType(MediaType.APPLICATION_FORM_URLENCODED) + .header("Authorization", "Bearer " + token)) + .andExpect(status().isOk()) + .andReturn().getResponse().getContentAsString(), + new TypeReference>() { + }); + + assertNotNull(userInfos); + assertTrue(userInfos.content.size() == 1); + assertNotNull(getUserInfo("deactivatedUser", userInfos.content)); + } + + @Test + public void getAllUserInfoWithSearchUsernameLike() throws Exception { + final String token = getSebAdminAccess(); + final Page userInfos = this.jsonMapper.readValue( + this.mockMvc + .perform(get(this.endpoint + API.USER_ACCOUNT_ENDPOINT + "?username=exam&institutionId=1") + .contentType(MediaType.APPLICATION_FORM_URLENCODED) + .header("Authorization", "Bearer " + token)) + .andExpect(status().isOk()) + .andReturn().getResponse().getContentAsString(), + new TypeReference>() { + }); + + assertNotNull(userInfos); + assertTrue(userInfos.content.size() == 1); + assertNotNull(getUserInfo("examSupporter", userInfos.content)); + } + + @Test + public void testOwnerGet() throws Exception { + final String examAdminToken1 = getExamAdmin1(); + this.mockMvc.perform(get(this.endpoint + API.USER_ACCOUNT_ENDPOINT + "/me") + .header("Authorization", "Bearer " + examAdminToken1)) + .andExpect(status().isOk()) + .andReturn().getResponse().getContentAsString(); + } + + @Test + public void createUserTest() throws Exception { + final String token = getSebAdminAccess(); + final UserInfo createdUser = this.jsonMapper.readValue( + this.mockMvc.perform(post(this.endpoint + API.USER_ACCOUNT_ENDPOINT) + .header("Authorization", "Bearer " + token) + .contentType(MediaType.APPLICATION_FORM_URLENCODED) + .param(Domain.USER.ATTR_NAME, "NewTestUser") + .param(Domain.USER.ATTR_USERNAME, "NewTestUser") + .param(Domain.USER.ATTR_SURNAME, "NewTestUser") + .param(Domain.USER.ATTR_LANGUAGE, Locale.ENGLISH.toLanguageTag()) + .param(Domain.USER.ATTR_TIMEZONE, DateTimeZone.UTC.getID()) + .param(Domain.USER_ROLE.REFERENCE_NAME, UserRole.EXAM_ADMIN.name()) + .param(PasswordChange.ATTR_NAME_NEW_PASSWORD, "12345678") + .param(PasswordChange.ATTR_NAME_CONFIRM_NEW_PASSWORD, "12345678")) + .andExpect(status().isOk()) + .andReturn().getResponse().getContentAsString(), + new TypeReference() { + }); + + assertNotNull(createdUser); + assertEquals("NewTestUser", createdUser.name); + + // get newly created user and check equality + final UserInfo createdUserGet = this.jsonMapper.readValue( + this.mockMvc.perform( + get(this.endpoint + API.USER_ACCOUNT_ENDPOINT + "/" + createdUser.uuid) + .contentType(MediaType.APPLICATION_FORM_URLENCODED) + .header("Authorization", "Bearer " + token) + .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_FORM_URLENCODED_VALUE)) + .andExpect(status().isOk()) + .andReturn().getResponse().getContentAsString(), + new TypeReference() { + }); + + assertNotNull(createdUserGet); + assertEquals(createdUser.getEntityKey(), createdUserGet.getEntityKey()); + assertFalse(createdUserGet.isActive()); + + // check user activity log for newly created user + final Page logs = this.jsonMapper.readValue( + this.mockMvc + .perform( + get(this.endpoint + API.USER_ACTIVITY_LOG_ENDPOINT + + "?username=admin&activity_types=CREATE") + .header("Authorization", "Bearer " + token) + .header(HttpHeaders.CONTENT_TYPE, + MediaType.APPLICATION_FORM_URLENCODED_VALUE)) + .andExpect(status().isOk()) + .andReturn().getResponse().getContentAsString(), + new TypeReference>() { + }); + + assertNotNull(logs); + assertTrue(1 == logs.content.size()); + final UserActivityLog userActivityLog = logs.content.iterator().next(); + assertEquals("user1", userActivityLog.userUUID); + assertEquals("USER", userActivityLog.entityType.name()); + assertEquals("CREATE", userActivityLog.activityType.name()); + assertEquals(createdUserGet.uuid, userActivityLog.entityId); + } + +// NOTE: this tests transaction rollback is working but for now only if a runtime exception is thrown on +// UserDaoImpl.updateUser after the main record (UserRecord) is stored but the new roles are not +// updated so far. +// TODO: make this test running separately in an test with UserDaoImpl mockup + +// @Test +// public void modifyUserTestTransaction() throws Exception { +// final String token = getSebAdminAccess(); +// final UserInfo user = this.jsonMapper.readValue( +// this.mockMvc.perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "/user7") +// .header("Authorization", "Bearer " + token)) +// .andExpect(status().isOk()) +// .andReturn().getResponse().getContentAsString(), +// new TypeReference() { +// }); +// +// assertNotNull(user); +// assertEquals("User", user.name); +// assertEquals("user1", user.userName); +// assertEquals("user@nomail.nomail", user.email); +// assertEquals("[EXAM_SUPPORTER]", String.valueOf(user.roles)); +// +// // change userName, email and roles +// final UserMod modifyUser = new UserMod(new UserInfo( +// user.getUuid(), +// user.getInstitutionId(), +// user.getName(), +// "newUser1", +// "newUser@nomail.nomail", +// user.getActive(), +// user.getLocale(), +// user.getTimeZone(), +// Stream.of(UserRole.EXAM_ADMIN.name(), UserRole.EXAM_SUPPORTER.name()).collect(Collectors.toSet())), +// null, null); +// final String modifyUserJson = this.jsonMapper.writeValueAsString(modifyUser); +// +// final String contentAsString = this.mockMvc +// .perform(post(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "/save") +// .header("Authorization", "Bearer " + token) +// .contentType(MediaType.APPLICATION_JSON_UTF8) +// .content(modifyUserJson)) +// .andReturn().getResponse().getContentAsString(); +// +// // double check by getting the user by UUID +// final UserInfo unmodifiedUserResult = this.jsonMapper.readValue( +// this.mockMvc.perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "/" + user.uuid) +// .header("Authorization", "Bearer " + token)) +// .andExpect(status().isOk()) +// .andReturn().getResponse().getContentAsString(), +// new TypeReference() { +// }); +// +// assertNotNull(unmodifiedUserResult); +// assertEquals("User", unmodifiedUserResult.name); +// assertEquals("user1", unmodifiedUserResult.userName); +// assertEquals("user@nomail.nomail", unmodifiedUserResult.email); +// assertEquals("[EXAM_SUPPORTER]", String.valueOf(unmodifiedUserResult.roles)); +// } + + @Test + public void modifyUserWithPUTMethod() throws Exception { + final String token = getSebAdminAccess(); + final UserInfo user = this.jsonMapper.readValue( + this.mockMvc.perform(get(this.endpoint + API.USER_ACCOUNT_ENDPOINT + "/user7") + .contentType(MediaType.APPLICATION_FORM_URLENCODED) + .header("Authorization", "Bearer " + token)) + .andExpect(status().isOk()) + .andReturn().getResponse().getContentAsString(), + new TypeReference() { + }); + + assertNotNull(user); + assertEquals("User", user.name); + assertEquals("user1", user.username); + assertEquals("user@nomail.nomail", user.email); + assertEquals("[EXAM_SUPPORTER]", String.valueOf(user.roles)); + + // change userName, email and roles + final UserInfo modifyUser = new UserInfo( + user.uuid, + user.getInstitutionId(), + new DateTime(0, DateTimeZone.UTC), + user.getName(), + user.getSurname(), + "newUser1", + "newUser@nomail.nomail", + user.getActive(), + user.getLanguage(), + user.getTimeZone(), + Stream.of(UserRole.EXAM_ADMIN.name(), UserRole.EXAM_SUPPORTER.name()).collect(Collectors.toSet())); + final String modifyUserJson = this.jsonMapper.writeValueAsString(modifyUser); + + UserInfo modifiedUserResult = this.jsonMapper.readValue( + this.mockMvc.perform(put(this.endpoint + API.USER_ACCOUNT_ENDPOINT) + .header("Authorization", "Bearer " + token) + .contentType(MediaType.APPLICATION_JSON_UTF8) + .content(modifyUserJson)) + .andExpect(status().isOk()) + .andReturn().getResponse().getContentAsString(), + new TypeReference() { + }); + + assertNotNull(modifiedUserResult); + assertEquals(user.uuid, modifiedUserResult.uuid); + assertEquals("User", modifiedUserResult.name); + assertEquals("newUser1", modifiedUserResult.username); + assertEquals("newUser@nomail.nomail", modifiedUserResult.email); + assertEquals("[EXAM_ADMIN, EXAM_SUPPORTER]", String.valueOf(modifiedUserResult.roles)); + + // double check by getting the user by UUID + modifiedUserResult = this.jsonMapper.readValue( + this.mockMvc + .perform(get(this.endpoint + API.USER_ACCOUNT_ENDPOINT + "/" + + modifiedUserResult.uuid) + .contentType(MediaType.APPLICATION_FORM_URLENCODED) + .header("Authorization", "Bearer " + token)) + .andExpect(status().isOk()) + .andReturn().getResponse().getContentAsString(), + new TypeReference() { + }); + + assertNotNull(modifiedUserResult); + assertEquals("User", modifiedUserResult.name); + assertEquals("newUser1", modifiedUserResult.username); + assertEquals("newUser@nomail.nomail", modifiedUserResult.email); + assertEquals("[EXAM_ADMIN, EXAM_SUPPORTER]", String.valueOf(modifiedUserResult.roles)); + } + + @Test + public void testModifyUserOnInactiveInstitutionNotAllowed() throws Exception { + // create new institution with seb-admin that is not active + final Institution institution = new RestAPITestHelper() + .withAccessToken(getSebAdminAccess()) + .withPath(API.INSTITUTION_ENDPOINT) + .withMethod(HttpMethod.POST) + .withAttribute("name", "new institution") + .withAttribute("urlSuffix", "new_inst") + .withAttribute("active", "false") + .withExpectedStatus(HttpStatus.OK) + .getAsObject(new TypeReference() { + }); + + assertNotNull(institution); + assertNotNull(institution.id); + assertEquals("new institution", institution.name); + + // try to create a user for this institution should not be possible + final Collection errors = this.jsonMapper.readValue( + this.mockMvc.perform(post(this.endpoint + API.USER_ACCOUNT_ENDPOINT) + .header("Authorization", "Bearer " + getSebAdminAccess()) + .contentType(MediaType.APPLICATION_FORM_URLENCODED) + .param(Domain.USER.ATTR_INSTITUTION_ID, String.valueOf(institution.id)) + .param(Domain.USER.ATTR_NAME, "NewTestUser") + .param(Domain.USER.ATTR_USERNAME, "NewTestUser") + .param(Domain.USER.ATTR_SURNAME, "NewTestUser") + .param(Domain.USER.ATTR_LANGUAGE, Locale.ENGLISH.toLanguageTag()) + .param(Domain.USER.ATTR_TIMEZONE, DateTimeZone.UTC.getID()) + .param(Domain.USER_ROLE.REFERENCE_NAME, UserRole.EXAM_ADMIN.name()) + .param(PasswordChange.ATTR_NAME_NEW_PASSWORD, "12345678") + .param(PasswordChange.ATTR_NAME_CONFIRM_NEW_PASSWORD, "12345678")) + .andExpect(status().isBadRequest()) + .andReturn().getResponse().getContentAsString(), + new TypeReference>() { + }); + + assertNotNull(errors); + assertTrue(errors.size() == 1); + assertEquals( + "Illegal API request argument", + errors.iterator().next().systemMessage); + assertEquals( + "User within an inactive institution cannot be created nor modified", + errors.iterator().next().details); + } + +// @Test +// public void modifyUserWithPOSTMethod() throws Exception { +// final String token = getSebAdminAccess(); +// +// final UserInfo modifiedUser = this.jsonMapper.readValue( +// this.mockMvc.perform(patch(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "/user4") +// .header("Authorization", "Bearer " + token) +// .contentType(MediaType.APPLICATION_FORM_URLENCODED) +// .param("name", "PostModifyTest")) +// .andExpect(status().isOk()) +// .andReturn().getResponse().getContentAsString(), +// new TypeReference() { +// }); +// +// assertNotNull(modifiedUser); +// assertEquals("PostModifyTest", modifiedUser.name); +// +// // check validation +// final Collection errors = this.jsonMapper.readValue( +// this.mockMvc.perform(patch(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "/user4") +// .header("Authorization", "Bearer " + token) +// .contentType(MediaType.APPLICATION_FORM_URLENCODED) +// .param("name", "P")) +// .andExpect(status().isBadRequest()) +// .andReturn().getResponse().getContentAsString(), +// new TypeReference>() { +// }); +// +// assertNotNull(errors); +// assertFalse(errors.isEmpty()); +// final APIMessage error = errors.iterator().next(); +// assertEquals("1200", error.messageCode); +// } + + @Test + public void testOwnerModifyPossibleForExamAdmin() throws Exception { + final String examAdminToken1 = getExamAdmin1(); + final UserInfo examAdmin = this.jsonMapper.readValue( + this.mockMvc.perform(get(this.endpoint + API.USER_ACCOUNT_ENDPOINT + "/me") + .header("Authorization", "Bearer " + examAdminToken1)) + .andExpect(status().isOk()) + .andReturn().getResponse().getContentAsString(), + new TypeReference() { + }); + + final String modifiedUserJson = this.jsonMapper.writeValueAsString(examAdmin); + + this.mockMvc.perform(put(this.endpoint + API.USER_ACCOUNT_ENDPOINT) + .header("Authorization", "Bearer " + examAdminToken1) + .contentType(MediaType.APPLICATION_JSON_UTF8) + .content(modifiedUserJson)) + .andExpect(status().isOk()) + .andReturn().getResponse().getContentAsString(); + } + + @Test + public void institutionalAdminTryToCreateOrModifyUserForOtherInstituionNotPossible() throws Exception { + + final String token = getAdminInstitution1Access(); + this.mockMvc.perform(post(this.endpoint + API.USER_ACCOUNT_ENDPOINT) + .header("Authorization", "Bearer " + token) + .contentType(MediaType.APPLICATION_FORM_URLENCODED) + .param(Domain.USER.ATTR_INSTITUTION_ID, "2") + .param(Domain.USER.ATTR_NAME, "NewTestUser") + .param(PasswordChange.ATTR_NAME_NEW_PASSWORD, "12345678") + .param(PasswordChange.ATTR_NAME_CONFIRM_NEW_PASSWORD, "12345678")) + .andExpect(status().isForbidden()) + .andReturn().getResponse().getContentAsString(); + + final UserInfo userInfo = new UserInfo( + "NewTestUser", 2L, new DateTime(0, DateTimeZone.UTC), "NewTestUser", "", "NewTestUser", + "", true, Locale.CANADA, DateTimeZone.UTC, + new HashSet<>(Arrays.asList(UserRole.EXAM_ADMIN.name()))); + final String newUserJson = this.jsonMapper.writeValueAsString(userInfo); + this.mockMvc.perform(put(this.endpoint + API.USER_ACCOUNT_ENDPOINT) + .header("Authorization", "Bearer " + token) + .contentType(MediaType.APPLICATION_JSON_UTF8) + .content(newUserJson)) + .andExpect(status().isForbidden()) + .andReturn().getResponse().getContentAsString(); + } + + @Test + public void unauthorizedAdminTryToCreateUserNotPossible() throws Exception { + + final String token = getExamAdmin1(); + this.mockMvc.perform(post(this.endpoint + API.USER_ACCOUNT_ENDPOINT) + .header("Authorization", "Bearer " + token) + .contentType(MediaType.APPLICATION_FORM_URLENCODED) + .param(Domain.USER.ATTR_INSTITUTION_ID, "2") + .param(Domain.USER.ATTR_NAME, "NewTestUser") + .param(PasswordChange.ATTR_NAME_NEW_PASSWORD, "12345678") + .param(PasswordChange.ATTR_NAME_CONFIRM_NEW_PASSWORD, "12345678")) + .andExpect(status().isForbidden()) + .andReturn().getResponse().getContentAsString(); + + final UserInfo userInfo = new UserInfo( + "NewTestUser", 2L, new DateTime(0, DateTimeZone.UTC), "NewTestUser", "", "NewTestUser", + "", true, Locale.CANADA, DateTimeZone.UTC, + new HashSet<>(Arrays.asList(UserRole.EXAM_ADMIN.name()))); + //final UserMod newUser = new UserMod(userInfo, "12345678", "12345678"); + final String newUserJson = this.jsonMapper.writeValueAsString(userInfo); + this.mockMvc.perform(put(this.endpoint + API.USER_ACCOUNT_ENDPOINT) + .header("Authorization", "Bearer " + token) + .contentType(MediaType.APPLICATION_JSON_UTF8) + .content(newUserJson)) + .andExpect(status().isForbidden()) + .andReturn().getResponse().getContentAsString(); + } + + @Test + public void modifyUserPassword() throws Exception { + final String examAdminToken1 = getExamAdmin1(); + assertNotNull(examAdminToken1); + + // a SEB Server Admin now changes the password of ExamAdmin1 + final String sebAdminToken = getSebAdminAccess(); + final UserInfo examAdmin1 = this.jsonMapper.readValue( + this.mockMvc.perform(get(this.endpoint + API.USER_ACCOUNT_ENDPOINT + "/user4") + .contentType(MediaType.APPLICATION_FORM_URLENCODED) + .header("Authorization", "Bearer " + sebAdminToken)) + .andExpect(status().isOk()) + .andReturn().getResponse().getContentAsString(), + new TypeReference() { + }); + + final PasswordChange passwordChange = new PasswordChange( + examAdmin1.uuid, + "admin", + "newPassword", + "newPassword"); + final String modifiedUserJson = this.jsonMapper.writeValueAsString(passwordChange); + + this.mockMvc.perform( + put(this.endpoint + API.USER_ACCOUNT_ENDPOINT + API.PASSWORD_PATH_SEGMENT) + .header("Authorization", "Bearer " + sebAdminToken) + .contentType(MediaType.APPLICATION_JSON_UTF8) + .content(modifiedUserJson)) + .andExpect(status().isOk()) + .andReturn().getResponse().getContentAsString(); + + // now it should not be possible to get a access token for ExamAdmin1 with the standard password + try { + getExamAdmin1(); + fail("AssertionError expected here"); + } catch (final AssertionError e) { + assertEquals("Status expected:<200> but was:<400>", e.getMessage()); + } + + // it should also not be possible to use an old token again after password change + this.mockMvc.perform(get(this.endpoint + API.USER_ACCOUNT_ENDPOINT + "/me") + .header("Authorization", "Bearer " + examAdminToken1)) + .andExpect(status().isUnauthorized()) + .andReturn().getResponse().getContentAsString(); + + // but it should be possible to get a new access token and request again + final String examAdminToken2 = obtainAccessToken("examAdmin1", "newPassword"); + this.mockMvc.perform(get(this.endpoint + API.USER_ACCOUNT_ENDPOINT + "/me") + .header("Authorization", "Bearer " + examAdminToken2)) + .andExpect(status().isOk()) + .andReturn().getResponse().getContentAsString(); + } + + @Test + public void modifyUserPasswordInvalidPasswords() throws Exception { + final String sebAdminToken = getSebAdminAccess(); + final UserInfo examAdmin1 = this.jsonMapper.readValue( + this.mockMvc.perform(get(this.endpoint + API.USER_ACCOUNT_ENDPOINT + "/user4") + .contentType(MediaType.APPLICATION_FORM_URLENCODED) + .header("Authorization", "Bearer " + sebAdminToken)) + .andExpect(status().isOk()) + .andReturn().getResponse().getContentAsString(), + new TypeReference() { + }); + + // must be longer then 8 chars + PasswordChange passwordChange = new PasswordChange( + examAdmin1.uuid, + "admin", + "new", + "new"); + String modifiedUserJson = this.jsonMapper.writeValueAsString(passwordChange); + + List messages = this.jsonMapper.readValue( + this.mockMvc.perform( + put(this.endpoint + API.USER_ACCOUNT_ENDPOINT + API.PASSWORD_PATH_SEGMENT) + .header("Authorization", "Bearer " + sebAdminToken) + .contentType(MediaType.APPLICATION_JSON_UTF8) + .content(modifiedUserJson)) + .andExpect(status().isBadRequest()) + .andReturn().getResponse().getContentAsString(), + new TypeReference>() { + }); + + assertNotNull(messages); + assertTrue(1 == messages.size()); + assertEquals("1200", messages.get(0).messageCode); + assertEquals("[user, newPassword, size, 8, 255, new]", String.valueOf(messages.get(0).getAttributes())); + + // wrong password retype + passwordChange = new PasswordChange( + examAdmin1.uuid, + "admin", + "12345678", + "87654321"); + modifiedUserJson = this.jsonMapper.writeValueAsString(passwordChange); + + messages = this.jsonMapper.readValue( + this.mockMvc.perform( + put(this.endpoint + API.USER_ACCOUNT_ENDPOINT + API.PASSWORD_PATH_SEGMENT) + .header("Authorization", "Bearer " + sebAdminToken) + .contentType(MediaType.APPLICATION_JSON_UTF8) + .content(modifiedUserJson)) + .andExpect(status().isBadRequest()) + .andReturn().getResponse().getContentAsString(), + new TypeReference>() { + }); + + assertNotNull(messages); + assertTrue(1 == messages.size()); + assertEquals("1200", messages.get(0).messageCode); + } + + @Test + public void deactivateUserAccount() throws Exception { + final String timeNow = DateTime.now(DateTimeZone.UTC).toString(Constants.STANDARD_DATE_TIME_FORMATTER); + // only a SEB Administrator or an Institutional administrator should be able to deactivate a user-account + final String examAdminToken = getExamAdmin1(); + this.mockMvc.perform(post(this.endpoint + API.USER_ACCOUNT_ENDPOINT + "/user4/inactive") + .contentType(MediaType.APPLICATION_FORM_URLENCODED) + .header("Authorization", "Bearer " + examAdminToken)) + .andExpect(status().isForbidden()); + + // With SEB Administrator it should work + final String sebAdminToken = getSebAdminAccess(); + final EntityProcessingReport report = this.jsonMapper.readValue( + this.mockMvc + .perform(post(this.endpoint + API.USER_ACCOUNT_ENDPOINT + "/user4/inactive") + .contentType(MediaType.APPLICATION_FORM_URLENCODED) + .header("Authorization", "Bearer " + sebAdminToken)) + .andExpect(status().isOk()) + .andReturn().getResponse().getContentAsString(), + new TypeReference() { + }); + + assertNotNull(report); + assertNotNull(report.source); + assertTrue(report.dependencies.isEmpty()); // TODO + assertTrue(report.errors.isEmpty()); + assertTrue(report.source.size() == 1); + + // get user and check activity + final EntityKey key = report.source.iterator().next(); + final UserInfo user = this.jsonMapper.readValue( + this.mockMvc + .perform(get(this.endpoint + API.USER_ACCOUNT_ENDPOINT + "/" + key.modelId) + .contentType(MediaType.APPLICATION_FORM_URLENCODED) + .header("Authorization", "Bearer " + sebAdminToken)) + .andExpect(status().isOk()) + .andReturn().getResponse().getContentAsString(), + new TypeReference() { + }); + + assertNotNull(user); + assertFalse(user.isActive()); + + // check also user activity log + final Page userLogs = this.jsonMapper.readValue( + this.mockMvc + .perform( + get(this.endpoint + API.USER_ACTIVITY_LOG_ENDPOINT + + "/?user=user1&from=" + timeNow) + .contentType(MediaType.APPLICATION_FORM_URLENCODED) + .header("Authorization", "Bearer " + sebAdminToken)) + .andExpect(status().isOk()) + .andReturn().getResponse().getContentAsString(), + new TypeReference>() { + }); + + assertNotNull(userLogs); + assertTrue(userLogs.content.size() == 1); + final UserActivityLog userLog = userLogs.content.iterator().next(); + assertEquals(UserLogActivityType.DEACTIVATE, userLog.activityType); + assertEquals("user4", userLog.entityId); + } + + @Test + public void activateUserAccount() throws Exception { + final String timeNow = DateTime.now(DateTimeZone.UTC).toString(Constants.STANDARD_DATE_TIME_FORMATTER); + // only a SEB Administrator or an Institutional administrator should be able to deactivate a user-account + final String examAdminToken = getExamAdmin1(); + this.mockMvc.perform(post(this.endpoint + API.USER_ACCOUNT_ENDPOINT + "/user6/active") + .contentType(MediaType.APPLICATION_FORM_URLENCODED) + .header("Authorization", "Bearer " + examAdminToken)) + .andExpect(status().isForbidden()); + + // With SEB Administrator it should work + final String sebAdminToken = getSebAdminAccess(); + final EntityProcessingReport report = this.jsonMapper.readValue( + this.mockMvc + .perform(post(this.endpoint + API.USER_ACCOUNT_ENDPOINT + "/user6/active") + .contentType(MediaType.APPLICATION_FORM_URLENCODED) + .header("Authorization", "Bearer " + sebAdminToken)) + .andExpect(status().isOk()) + .andReturn().getResponse().getContentAsString(), + new TypeReference() { + }); + + assertNotNull(report); + assertNotNull(report.source); + assertTrue(report.dependencies.isEmpty()); // TODO + assertTrue(report.errors.isEmpty()); + assertTrue(report.source.size() == 1); + + // get user and check activity + final EntityKey key = report.source.iterator().next(); + final UserInfo user = this.jsonMapper.readValue( + this.mockMvc + .perform(get(this.endpoint + API.USER_ACCOUNT_ENDPOINT + "/" + key.modelId) + .contentType(MediaType.APPLICATION_FORM_URLENCODED) + .header("Authorization", "Bearer " + sebAdminToken)) + .andExpect(status().isOk()) + .andReturn().getResponse().getContentAsString(), + new TypeReference() { + }); + + assertNotNull(user); + assertTrue(user.isActive()); + + // check also user activity log + final Page userLogs = this.jsonMapper.readValue( + this.mockMvc + .perform(get(this.endpoint + API.USER_ACTIVITY_LOG_ENDPOINT + + "?user=user1&from=" + timeNow) + .header("Authorization", "Bearer " + sebAdminToken) + .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_FORM_URLENCODED_VALUE)) + .andExpect(status().isOk()) + .andReturn().getResponse().getContentAsString(), + new TypeReference>() { + }); + + assertNotNull(userLogs); + assertTrue(userLogs.content.size() == 1); + final UserActivityLog userLog = userLogs.content.iterator().next(); + assertEquals(UserLogActivityType.ACTIVATE, userLog.activityType); + assertEquals("user6", userLog.entityId); + } + + @Test + public void testGeneralAllActiveInactiveEndpoint() throws Exception { + final String sebAdminToken = getSebAdminAccess(); + + // all active for the own institution + Page usersPage = this.jsonMapper.readValue( + this.mockMvc.perform(get(this.endpoint + API.USER_ACCOUNT_ENDPOINT + "/active") + .contentType(MediaType.APPLICATION_FORM_URLENCODED) + .header("Authorization", "Bearer " + sebAdminToken)) + .andExpect(status().isOk()) + .andReturn().getResponse().getContentAsString(), + new TypeReference>() { + }); + + assertNotNull(usersPage); + assertTrue(usersPage.pageSize == 3); + assertEquals("[user1, user2, user5]", getOrderedUUIDs(usersPage.content)); + + // all inactive of the own institution + usersPage = this.jsonMapper.readValue( + this.mockMvc.perform(get(this.endpoint + API.USER_ACCOUNT_ENDPOINT + "/inactive") + .contentType(MediaType.APPLICATION_FORM_URLENCODED) + .header("Authorization", "Bearer " + sebAdminToken)) + .andExpect(status().isOk()) + .andReturn().getResponse().getContentAsString(), + new TypeReference>() { + }); + + assertNotNull(usersPage); + assertTrue(usersPage.pageSize == 0); + assertEquals("[]", getOrderedUUIDs(usersPage.content)); + + // all active of institution 2 + usersPage = this.jsonMapper.readValue( + this.mockMvc + .perform(get(this.endpoint + API.USER_ACCOUNT_ENDPOINT + + "/active?institutionId=2") + .contentType(MediaType.APPLICATION_FORM_URLENCODED) + .header("Authorization", "Bearer " + sebAdminToken)) + .andExpect(status().isOk()) + .andReturn().getResponse().getContentAsString(), + new TypeReference>() { + }); + + assertNotNull(usersPage); + assertTrue(usersPage.pageSize == 3); + assertEquals("[user3, user4, user7]", getOrderedUUIDs(usersPage.content)); + + // all inactive of institution 2 + usersPage = this.jsonMapper.readValue( + this.mockMvc + .perform(get(this.endpoint + API.USER_ACCOUNT_ENDPOINT + + "/inactive?institutionId=2") + .contentType(MediaType.APPLICATION_FORM_URLENCODED) + .header("Authorization", "Bearer " + sebAdminToken)) + .andExpect(status().isOk()) + .andReturn().getResponse().getContentAsString(), + new TypeReference>() { + }); + + assertNotNull(usersPage); + assertTrue(usersPage.pageSize == 1); + assertEquals("[user6]", getOrderedUUIDs(usersPage.content)); + } + + @Test + public void testGeneralListEndpoint() throws Exception { + final String sebAdminToken = getSebAdminAccess(); + + // for SEB Admin it should be possible to get from different institutions + Collection users = this.jsonMapper.readValue( + this.mockMvc + .perform( + get(this.endpoint + API.USER_ACCOUNT_ENDPOINT + + "/list?modelIds=user1,user2,user6,user7") + .contentType(MediaType.APPLICATION_FORM_URLENCODED) + .header("Authorization", "Bearer " + sebAdminToken)) + .andExpect(status().isOk()) + .andReturn().getResponse().getContentAsString(), + new TypeReference>() { + }); + + assertNotNull(users); + assertTrue(users.size() == 4); + assertEquals("[user1, user2, user6, user7]", getOrderedUUIDs(users)); + + // for an institutional admin it should only be possible to get from own institution + final String instAdminToken = getAdminInstitution2Access(); + users = this.jsonMapper.readValue( + this.mockMvc + .perform( + get(this.endpoint + API.USER_ACCOUNT_ENDPOINT + + "/list?modelIds=user1,user2,user6,user7") + .contentType(MediaType.APPLICATION_FORM_URLENCODED) + .header("Authorization", "Bearer " + instAdminToken)) + .andExpect(status().isOk()) + .andReturn().getResponse().getContentAsString(), + new TypeReference>() { + }); + + assertNotNull(users); + assertTrue(users.size() == 2); + assertEquals("[user6, user7]", getOrderedUUIDs(users)); + } + + @Test + public void testGeneralNamesEndpoint() throws Exception { + final String sebAdminToken = getSebAdminAccess(); + + // for SEB Admin + Collection names = this.jsonMapper.readValue( + this.mockMvc + .perform(get(this.endpoint + API.USER_ACCOUNT_ENDPOINT + "/names" + "?institutionId=1") + .contentType(MediaType.APPLICATION_FORM_URLENCODED) + .header("Authorization", "Bearer " + sebAdminToken)) + .andExpect(status().isOk()) + .andReturn().getResponse().getContentAsString(), + new TypeReference>() { + }); + + assertNotNull(names); + assertTrue(names.size() == 3); + assertEquals("[EntityName [entityType=USER, modelId=user1, name=SEBAdmin], " + + "EntityName [entityType=USER, modelId=user2, name=Institutional1 Admin], " + + "EntityName [entityType=USER, modelId=user5, name=Exam Supporter]]", names.toString()); + + // for an institutional admin 2 + final String instAdminToken = getAdminInstitution2Access(); + names = this.jsonMapper.readValue( + this.mockMvc + .perform(get(this.endpoint + API.USER_ACCOUNT_ENDPOINT + "/names" + "?institutionId=2") + .contentType(MediaType.APPLICATION_FORM_URLENCODED) + .header("Authorization", "Bearer " + instAdminToken)) + .andExpect(status().isOk()) + .andReturn().getResponse().getContentAsString(), + new TypeReference>() { + }); + + assertNotNull(names); + assertTrue(names.size() == 4); + assertEquals("[EntityName [entityType=USER, modelId=user3, name=Institutional2 Admin], " + + "EntityName [entityType=USER, modelId=user4, name=ExamAdmin1], " + + "EntityName [entityType=USER, modelId=user6, name=Deactivated], " + + "EntityName [entityType=USER, modelId=user7, name=User]]", names.toString()); + + // for an institutional admin 2 only active + names = this.jsonMapper.readValue( + this.mockMvc + .perform( + get(this.endpoint + API.USER_ACCOUNT_ENDPOINT + "/names?active=true&institutionId=2") + .contentType(MediaType.APPLICATION_FORM_URLENCODED) + .header("Authorization", "Bearer " + instAdminToken)) + .andExpect(status().isOk()) + .andReturn().getResponse().getContentAsString(), + new TypeReference>() { + }); + + assertNotNull(names); + assertTrue(names.size() == 3); + assertEquals("[EntityName [entityType=USER, modelId=user3, name=Institutional2 Admin], " + + "EntityName [entityType=USER, modelId=user4, name=ExamAdmin1], " + + "EntityName [entityType=USER, modelId=user7, name=User]]", names.toString()); + } + +// @Test +// public void createWithRoleAddRoleDeleteRole() throws Exception { +// final String token = getSebAdminAccess(); +// UserInfo createdUser = this.jsonMapper.readValue( +// this.mockMvc.perform(post(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT) +// .header("Authorization", "Bearer " + token) +// .contentType(MediaType.APPLICATION_FORM_URLENCODED) +// .param(Domain.USER.ATTR_NAME, "NewTestUser") +// .param(Domain.USER.ATTR_USERNAME, "NewTestUser") +// .param(Domain.USER.ATTR_LOCALE, Locale.ENGLISH.toLanguageTag()) +// .param(Domain.USER.ATTR_TIMEZONE, DateTimeZone.UTC.getID()) +// .param(UserMod.ATTR_NAME_NEW_PASSWORD, "12345678") +// .param(UserMod.ATTR_NAME_RETYPED_NEW_PASSWORD, "12345678")) +// .andExpect(status().isOk()) +// .andReturn().getResponse().getContentAsString(), +// new TypeReference() { +// }); +// +// assertNotNull(createdUser); +// assertEquals("NewTestUser", createdUser.name); +// assertEquals("[]", String.valueOf(createdUser.roles)); +// +// // add two roles +// createdUser = this.jsonMapper.readValue( +// this.mockMvc.perform(patch(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "/" + createdUser.uuid) +// .header("Authorization", "Bearer " + token) +// .contentType(MediaType.APPLICATION_FORM_URLENCODED) +// .param(USER_ROLE.REFERENCE_NAME, "EXAM_SUPPORTER", "EXAM_ADMIN")) +// .andExpect(status().isOk()) +// .andReturn().getResponse().getContentAsString(), +// new TypeReference() { +// }); +// +// assertNotNull(createdUser); +// assertEquals("NewTestUser", createdUser.name); +// assertEquals("[]", String.valueOf(createdUser.roles)); +// } + + private UserInfo getUserInfo(final String name, final Collection infos) { + try { + return infos + .stream() + .filter(ui -> ui.username.equals(name)) + .findFirst() + .orElseThrow(NoSuchElementException::new); + } catch (final Exception e) { + return null; + } + } + +}