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