Merge remote-tracking branch 'origin/dev-1.4' into development
This commit is contained in:
		
						commit
						40689d5781
					
				
					 10 changed files with 68 additions and 41 deletions
				
			
		
							
								
								
									
										2
									
								
								pom.xml
									
										
									
									
									
								
							
							
						
						
									
										2
									
								
								pom.xml
									
										
									
									
									
								
							|  | @ -18,7 +18,7 @@ | |||
|   <packaging>jar</packaging> | ||||
| 
 | ||||
|   <properties> | ||||
|     <sebserver-version>1.4-rc1</sebserver-version> | ||||
|     <sebserver-version>1.4.0-SNAPSHOT</sebserver-version> | ||||
|     <build-version>${sebserver-version}</build-version> | ||||
|     <revision>${sebserver-version}</revision> | ||||
|     <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> | ||||
|  |  | |||
|  | @ -11,6 +11,7 @@ package ch.ethz.seb.sebserver.gbl.model.session; | |||
| import com.fasterxml.jackson.annotation.JsonCreator; | ||||
| import com.fasterxml.jackson.annotation.JsonProperty; | ||||
| 
 | ||||
| import ch.ethz.seb.sebserver.gbl.Constants; | ||||
| import ch.ethz.seb.sebserver.gbl.model.exam.Exam; | ||||
| import ch.ethz.seb.sebserver.gbl.model.institution.LmsSetup.LmsType; | ||||
| 
 | ||||
|  | @ -47,7 +48,7 @@ public final class RunningExamInfo { | |||
|         this.examId = exam.getModelId(); | ||||
|         this.name = exam.name; | ||||
|         this.url = exam.getStartURL(); | ||||
|         this.lmsType = (lmsType == null) ? "" : lmsType.name(); | ||||
|         this.lmsType = (lmsType == null) ? Constants.EMPTY_NOTE : lmsType.name(); | ||||
|     } | ||||
| 
 | ||||
|     public String getExamId() { | ||||
|  |  | |||
|  | @ -340,7 +340,7 @@ public class ConfigTemplateForm implements TemplateComposer { | |||
|                 .withEntityKey(entityKey) | ||||
|                 .publishIf(() -> modifyGrant && isReadonly) | ||||
| 
 | ||||
|                 .newAction(ActionDefinition.SEB_EXAM_CONFIG_DELETE) | ||||
|                 .newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_DELETE) | ||||
|                 .withEntityKey(entityKey) | ||||
|                 .withConfirm(() -> CONFIRM_DELETE) | ||||
|                 .withExec(this::deleteConfiguration) | ||||
|  |  | |||
|  | @ -648,6 +648,9 @@ public class ExamDAOImpl implements ExamDAO { | |||
|                 .and( | ||||
|                         ExamRecordDynamicSqlSupport.status, | ||||
|                         isEqualTo(ExamStatus.RUNNING.name())) | ||||
|                 .and( | ||||
|                         ExamRecordDynamicSqlSupport.lmsAvailable, | ||||
|                         isEqualToWhenPresent(BooleanUtils.toIntegerObject(true))) | ||||
|                 .build() | ||||
|                 .execute()); | ||||
|     } | ||||
|  |  | |||
|  | @ -77,7 +77,7 @@ public interface ExamSessionService { | |||
|     /** Use this to check if a specified Exam has currently active SEB Client connections. | ||||
|      * | ||||
|      * Active SEB Client connections are established connections that are not yet closed and | ||||
|      * connection attempts that are older the a defined time interval. | ||||
|      * open connection attempts. | ||||
|      * | ||||
|      * @param examId The Exam identifier | ||||
|      * @return true if the given Exam has currently no active client connection, false otherwise. */ | ||||
|  | @ -86,7 +86,7 @@ public interface ExamSessionService { | |||
|             return false; | ||||
|         } | ||||
| 
 | ||||
|         return !this.getActiveConnectionTokens(examId) | ||||
|         return !this.getAllActiveConnectionTokens(examId) | ||||
|                 .getOrThrow() | ||||
|                 .isEmpty(); | ||||
|     } | ||||
|  | @ -184,13 +184,21 @@ public interface ExamSessionService { | |||
|             final Long examId, | ||||
|             final Predicate<ClientConnectionData> filter); | ||||
| 
 | ||||
|     /** Gets all connection tokens of active client connection that are related to a specified exam | ||||
|     /** Gets all connection tokens of client connection that are in ACTIVE state and related to a specified exam | ||||
|      * from persistence storage without caching involved. | ||||
|      * | ||||
|      * @param examId the exam identifier | ||||
|      * @return Result refer to the collection of connection tokens or to an error when happened. */ | ||||
|     Result<Collection<String>> getActiveConnectionTokens(Long examId); | ||||
| 
 | ||||
|     /** Gets all connection tokens of client connections that are in an active state. See <code>ClientConnection</code> | ||||
|      * And that are related to a specified exam. | ||||
|      * There is no caching involved here, gets actual data from persistent storage | ||||
|      * | ||||
|      * @param examId the exam identifier | ||||
|      * @return Result refer to the collection of connection tokens or to an error when happened. */ | ||||
|     Result<Collection<String>> getAllActiveConnectionTokens(Long examId); | ||||
| 
 | ||||
|     /** Use this to check if the current cached running exam is up to date | ||||
|      * and if not to flush the cache. | ||||
|      * | ||||
|  |  | |||
|  | @ -430,6 +430,12 @@ public class ExamSessionServiceImpl implements ExamSessionService { | |||
|                 .getActiveConnectionTokens(examId); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public Result<Collection<String>> getAllActiveConnectionTokens(final Long examId) { | ||||
|         return this.clientConnectionDAO | ||||
|                 .getAllActiveConnectionTokens(examId); | ||||
|     } | ||||
| 
 | ||||
|     @EventListener | ||||
|     public void notifyExamFinished(final ExamFinishedEvent event) { | ||||
| 
 | ||||
|  |  | |||
|  | @ -137,6 +137,7 @@ public class ExamAPI_V1_Controller { | |||
|                                 .getOrThrow() | ||||
|                                 .stream() | ||||
|                                 .map(this::createRunningExamInfo) | ||||
|                                 .filter(this::checkConsistency) | ||||
|                                 .collect(Collectors.toList()); | ||||
|                     } else { | ||||
|                         final Exam exam = this.examSessionService.getExamDAO() | ||||
|  | @ -158,6 +159,18 @@ public class ExamAPI_V1_Controller { | |||
|                 this.executor); | ||||
|     } | ||||
| 
 | ||||
|     private boolean checkConsistency(final RunningExamInfo info) { | ||||
|         if (StringUtils.isNotBlank(info.name) && | ||||
|                 StringUtils.isNotBlank(info.url) && | ||||
|                 StringUtils.isNotBlank(info.examId)) { | ||||
| 
 | ||||
|             return true; | ||||
|         } | ||||
| 
 | ||||
|         log.warn("Invalid running exam detected. Filter out exam : {}", info); | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     @RequestMapping( | ||||
|             path = API.EXAM_API_HANDSHAKE_ENDPOINT, | ||||
|             method = RequestMethod.PATCH, | ||||
|  |  | |||
|  | @ -568,7 +568,6 @@ public class ExamAdministrationController extends EntityController<Exam, Exam> { | |||
|                                     .of("Exam currently has active SEB Client connections.")); | ||||
|                 } | ||||
| 
 | ||||
|                 // TODO double check before setSEBRestriction | ||||
|                 return this.checkNoActiveSEBClientConnections(exam) | ||||
|                         .flatMap(this.sebRestrictionService::applySEBClientRestriction) | ||||
|                         .flatMap(e -> this.examDAO.setSEBRestriction(exam.id, restrict)) | ||||
|  |  | |||
|  | @ -95,6 +95,7 @@ import ch.ethz.seb.sebserver.gbl.model.sebconfig.SEBClientConfig; | |||
| import ch.ethz.seb.sebserver.gbl.model.sebconfig.TemplateAttribute; | ||||
| import ch.ethz.seb.sebserver.gbl.model.sebconfig.View; | ||||
| import ch.ethz.seb.sebserver.gbl.model.session.ClientConnection; | ||||
| import ch.ethz.seb.sebserver.gbl.model.session.ClientConnection.ConnectionStatus; | ||||
| import ch.ethz.seb.sebserver.gbl.model.session.ClientConnectionData; | ||||
| import ch.ethz.seb.sebserver.gbl.model.session.ClientInstruction; | ||||
| import ch.ethz.seb.sebserver.gbl.model.session.ClientInstruction.InstructionType; | ||||
|  | @ -254,35 +255,6 @@ public class UseCasesIntegrationTest extends GuiIntegrationTest { | |||
|         // Nothing | ||||
|     } | ||||
| 
 | ||||
| //    @Test | ||||
| //    @Order(0) | ||||
| //    public void testUsecase00_cleanupAllExams() { | ||||
| //        final RestServiceImpl restService = createRestServiceForUser( | ||||
| //                "admin", | ||||
| //                "admin", | ||||
| //                new GetExamNames(), | ||||
| //                new DeleteExam()); | ||||
| // | ||||
| //        final Result<List<EntityName>> call = restService | ||||
| //                .getBuilder(GetExamNames.class) | ||||
| //                .call(); | ||||
| // | ||||
| //        if (!call.hasError()) { | ||||
| //            call.get().stream().forEach(key -> { | ||||
| //                final Result<EntityProcessingReport> deleted = restService | ||||
| //                        .getBuilder(DeleteExam.class) | ||||
| //                        .withURIVariable(API.PARAM_MODEL_ID, key.modelId) | ||||
| //                        .call(); | ||||
| // | ||||
| //                if (deleted.hasError()) { | ||||
| //                    System.out.println("%%%%%%%%%%%%%%%%%%%%%%%%%% deletion failed: " + key); | ||||
| //                } else { | ||||
| //                    System.out.println("%%%%%%%%%%%%%%%%%%%%%%%%%% deleted: " + key); | ||||
| //                } | ||||
| //            }); | ||||
| //        } | ||||
| //    } | ||||
| 
 | ||||
|     @Test | ||||
|     @Order(1) | ||||
|     // ************************************* | ||||
|  | @ -815,6 +787,7 @@ public class UseCasesIntegrationTest extends GuiIntegrationTest { | |||
|     // - Check if there are some quizzes from previous LMS Setup | ||||
|     // - Import a quiz as Exam | ||||
|     // - get exam page and check the exam is there | ||||
|     // - get exam page with none native sort attribute to test this | ||||
|     // - edit exam property and save again | ||||
|     public void testUsecase07_ImportExam() { | ||||
|         final RestServiceImpl restService = createRestServiceForUser( | ||||
|  | @ -922,6 +895,13 @@ public class UseCasesIntegrationTest extends GuiIntegrationTest { | |||
|                 .filter(exam -> exam.name.equals(newExam.name)) | ||||
|                 .findFirst().isPresent()); | ||||
| 
 | ||||
|         final Result<Page<Exam>> examsSorted = restService | ||||
|                 .getBuilder(GetExamPage.class) | ||||
|                 .withQueryParam(Page.ATTR_SORT, LmsSetup.FILTER_ATTR_LMS_SETUP) | ||||
|                 .call(); | ||||
| 
 | ||||
|         assertNotNull(examsSorted); | ||||
|         assertFalse(examsSorted.hasError()); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|  | @ -2169,7 +2149,7 @@ public class UseCasesIntegrationTest extends GuiIntegrationTest { | |||
|         assertTrue(connections.isEmpty()); | ||||
| 
 | ||||
|         // get MonitoringFullPageData | ||||
|         final Result<MonitoringFullPageData> fullPageData = restService.getBuilder(GetMonitoringFullPageData.class) | ||||
|         Result<MonitoringFullPageData> fullPageData = restService.getBuilder(GetMonitoringFullPageData.class) | ||||
|                 .withURIVariable(API.PARAM_PARENT_MODEL_ID, exam.getModelId()) | ||||
|                 .call(); | ||||
|         assertNotNull(fullPageData); | ||||
|  | @ -2221,6 +2201,22 @@ public class UseCasesIntegrationTest extends GuiIntegrationTest { | |||
|             iterator.next(); | ||||
|             final ClientConnectionData con = iterator.next(); | ||||
| 
 | ||||
|             fullPageData = restService.getBuilder(GetMonitoringFullPageData.class) | ||||
|                     .withURIVariable(API.PARAM_PARENT_MODEL_ID, exam.getModelId()) | ||||
|                     .withHeader(API.EXAM_MONITORING_STATE_FILTER, ConnectionStatus.DISABLED.name()) | ||||
|                     .call(); | ||||
|             assertNotNull(fullPageData); | ||||
|             assertFalse(fullPageData.hasError()); | ||||
| 
 | ||||
|             fullPageData = restService.getBuilder(GetMonitoringFullPageData.class) | ||||
|                     .withURIVariable(API.PARAM_PARENT_MODEL_ID, exam.getModelId()) | ||||
|                     .withHeader( | ||||
|                             API.EXAM_MONITORING_STATE_FILTER, | ||||
|                             ConnectionStatus.DISABLED.name() + "," + ConnectionStatus.ACTIVE.name()) | ||||
|                     .call(); | ||||
|             assertNotNull(fullPageData); | ||||
|             assertFalse(fullPageData.hasError()); | ||||
| 
 | ||||
|             // get single client connection | ||||
|             final Result<ClientConnection> ccCall = restService.getBuilder(GetClientConnection.class) | ||||
|                     .withURIVariable(API.PARAM_MODEL_ID, con.clientConnection.getModelId()) | ||||
|  |  | |||
|  | @ -9,13 +9,14 @@ INSERT IGNORE INTO seb_client_configuration VALUES | |||
|      | ||||
| INSERT IGNORE INTO additional_attributes VALUES | ||||
|     (1, 'SEB_CLIENT_CONFIGURATION', 2, 'vdiSetup', 'VM_WARE'), | ||||
|     (2, 'SEB_CLIENT_CONFIGURATION', 2, 'vdiExecutable', 'vmware-view.exe') | ||||
|     (2, 'SEB_CLIENT_CONFIGURATION', 2, 'vdiExecutable', 'vmware-view.exe'), | ||||
|     (3, 'EXAM', 2, 'quiz_start_url', 'https://test.lms.mockup') | ||||
|     ; | ||||
|      | ||||
| INSERT IGNORE INTO exam VALUES | ||||
|     (1, 1, 1, 'quiz1', 'admin', 'admin', 'MANAGED', null, null, 'UP_COMING', 1, 0, null, 1, null, null, null, null, null, null), | ||||
|     (2, 1, 1, 'quiz6', 'admin', 'admin', 'MANAGED', null, null, 'RUNNING', 1, 0, null, 1, null, null, null, null, null, null), | ||||
|     (3, 1, 1, 'quiz3', 'admin', 'admin', 'MANAGED', null, null, 'FINISHED', 1, 0, null, 1, null, null, null, null, null, null) | ||||
|     (1, 1, 1, 'quiz1', 'admin', 'admin', 'MANAGED', null, null, 'UP_COMING', 1, 0, null, 1, null, null, 'quiz1', null, null, 1), | ||||
|     (2, 1, 1, 'quiz6', 'admin', 'admin', 'MANAGED', null, null, 'RUNNING', 1, 0, null, 1, null, null, 'quiz6', null, null, 1), | ||||
|     (3, 1, 1, 'quiz3', 'admin', 'admin', 'MANAGED', null, null, 'FINISHED', 1, 0, null, 1, null, null, 'quiz3', null, null, 1) | ||||
|     ; | ||||
|      | ||||
| INSERT IGNORE INTO indicator VALUES | ||||
|  |  | |||
		Loading…
	
	Add table
		
		Reference in a new issue
	
	 anhefti
						anhefti