SEBSERV-16 #Interfaces and mock-up implementation

This commit is contained in:
anhefti 2019-01-14 17:00:02 +01:00
parent bcc423bd2e
commit 8f15e760a9
12 changed files with 358 additions and 43 deletions

View file

@ -6,7 +6,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package ch.ethz.seb.sebserver.gbl.model.institution;
package ch.ethz.seb.sebserver.gbl.model.exam;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
@ -17,7 +17,7 @@ import com.fasterxml.jackson.annotation.JsonProperty;
import ch.ethz.seb.sebserver.gbl.Constants;
import ch.ethz.seb.sebserver.gbl.model.Domain;
public final class CourseData {
public final class QuizData {
@JsonProperty(Domain.ATTR_ID)
public final String uuid;
@ -37,7 +37,7 @@ public final class CourseData {
@JsonProperty("enrollmentURL")
public final String enrollmentURL;
public CourseData(
public QuizData(
final String uuid,
final String name,
final String description,
@ -53,7 +53,7 @@ public final class CourseData {
this.enrollmentURL = enrollmentURL;
}
public CourseData(
public QuizData(
final String uuid,
final String name,
final String description,
@ -123,7 +123,7 @@ public final class CourseData {
return false;
if (getClass() != obj.getClass())
return false;
final CourseData other = (CourseData) obj;
final QuizData other = (QuizData) obj;
if (this.uuid == null) {
if (other.uuid != null)
return false;
@ -134,7 +134,7 @@ public final class CourseData {
@Override
public String toString() {
return "CourseData [uuid=" + this.uuid + ", name=" + this.name + ", description=" + this.description
return "QuizData [uuid=" + this.uuid + ", name=" + this.name + ", description=" + this.description
+ ", startTime="
+ this.startTime + ", endTime=" + this.endTime + ", enrollmentURL=" + this.enrollmentURL + "]";
}

View file

@ -30,7 +30,7 @@ public final class LmsSetup implements GrantEntity, Activatable {
public static final String FILTER_ATTR_LMS_TYPE = "lms_type";
public static final String FILTER_ATTR_ACTIVE = "active";
public enum LMSType {
public enum LmsType {
MOCKUP,
MOODLE,
OPEN_EDX
@ -50,7 +50,7 @@ public final class LmsSetup implements GrantEntity, Activatable {
@JsonProperty(LMS_SETUP.ATTR_LMS_TYPE)
@NotNull
public final LMSType lmsType;
public final LmsType lmsType;
@JsonProperty(LMS_SETUP.ATTR_LMS_CLIENTNAME)
@Size(min = 3, max = 255, message = "lmsSetup:lmsAuthName:size:{min}:{max}:${validatedValue}")
@ -84,7 +84,7 @@ public final class LmsSetup implements GrantEntity, Activatable {
@JsonProperty(Domain.ATTR_ID) final Long id,
@JsonProperty(LMS_SETUP.ATTR_INSTITUTION_ID) final Long institutionId,
@JsonProperty(LMS_SETUP.ATTR_NAME) final String name,
@JsonProperty(LMS_SETUP.ATTR_LMS_TYPE) final LMSType lmsType,
@JsonProperty(LMS_SETUP.ATTR_LMS_TYPE) final LmsType lmsType,
@JsonProperty(LMS_SETUP.ATTR_LMS_CLIENTNAME) final String lmsAuthName,
@JsonProperty(LMS_SETUP.ATTR_LMS_CLIENTSECRET) final String lmsAuthSecret,
@JsonProperty(LMS_SETUP.ATTR_LMS_URL) final String lmsApiUrl,
@ -144,7 +144,7 @@ public final class LmsSetup implements GrantEntity, Activatable {
return this.name;
}
public LMSType getLmsType() {
public LmsType getLmsType() {
return this.lmsType;
}

View file

@ -0,0 +1,31 @@
/*
* 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.gbl.model.institution;
import javax.validation.constraints.NotNull;
import com.fasterxml.jackson.annotation.JsonProperty;
public class LmsSetupTestResult {
public static final String ATTR_OK = "ok";
@JsonProperty(ATTR_OK)
@NotNull
public final Boolean ok;
// TODO
public LmsSetupTestResult(
@JsonProperty(value = ATTR_OK, required = true) final Boolean ok) {
this.ok = ok;
}
}

View file

@ -0,0 +1,69 @@
/*
* 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.gbl.model.user;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
public class ExamineeAccountDetails {
public static final String ATTR_ID = "id";
public static final String ATTR_NAME = "name";
public static final String ATTR_USER_NAME = "username";
public static final String ATTR_EMAIL = "email";
@JsonProperty(ATTR_ID)
public final String id;
@JsonProperty(ATTR_NAME)
public final String name;
@JsonProperty(ATTR_USER_NAME)
public final String username;
@JsonProperty(ATTR_EMAIL)
public final String email;
@JsonCreator
public ExamineeAccountDetails(
@JsonProperty(ATTR_ID) final String id,
@JsonProperty(ATTR_NAME) final String name,
@JsonProperty(ATTR_USER_NAME) final String username,
@JsonProperty(ATTR_EMAIL) final String email) {
this.id = id;
this.name = name;
this.username = username;
this.email = email;
}
public String getId() {
return this.id;
}
public String getName() {
return this.name;
}
public String getUsername() {
return this.username;
}
public String getEmail() {
return this.email;
}
@Override
public String toString() {
return "ExamineeAccountDetails [id=" + this.id + ", name=" + this.name + ", username=" + this.username
+ ", email=" + this.email
+ "]";
}
}

View file

@ -13,7 +13,7 @@ import java.util.Collection;
import org.springframework.transaction.annotation.Transactional;
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.institution.LmsSetup.LmsType;
import ch.ethz.seb.sebserver.gbl.util.Result;
public interface LmsSetupDAO extends ActivatableEntityDAO<LmsSetup> {
@ -23,7 +23,7 @@ public interface LmsSetupDAO extends ActivatableEntityDAO<LmsSetup> {
return allMatching(institutionId, null, null, active);
}
Result<Collection<LmsSetup>> allMatching(Long institutionId, String name, LMSType lmsType, Boolean active);
Result<Collection<LmsSetup>> allMatching(Long institutionId, String name, LmsType lmsType, Boolean active);
Result<LmsSetup> save(LmsSetup lmsSetup);

View file

@ -33,7 +33,7 @@ import ch.ethz.seb.sebserver.gbl.model.Entity;
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
import ch.ethz.seb.sebserver.gbl.model.EntityType;
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.institution.LmsSetup.LmsType;
import ch.ethz.seb.sebserver.gbl.util.Result;
import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.InstitutionRecordDynamicSqlSupport;
import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.LmsSetupRecordDynamicSqlSupport;
@ -96,7 +96,7 @@ public class LmsSetupDAOImpl implements LmsSetupDAO, BulkActionSupport {
public Result<Collection<LmsSetup>> allMatching(
final Long institutionId,
final String name,
final LMSType lmsType,
final LmsType lmsType,
final Boolean active) {
return Result.tryCatch(() -> {
@ -265,7 +265,7 @@ public class LmsSetupDAOImpl implements LmsSetupDAO, BulkActionSupport {
record.getId(),
record.getInstitutionId(),
record.getName(),
LMSType.valueOf(record.getLmsType()),
LmsType.valueOf(record.getLmsType()),
record.getLmsClientname(),
record.getLmsClientsecret(),
record.getLmsUrl(),

View file

@ -1,15 +0,0 @@
/*
* 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.servicelayer.lms;
public interface LMSConnectionService {
LMSConnectionTemplate createConnectionTemplate(Long lmsSetupId);
}

View file

@ -8,19 +8,13 @@
package ch.ethz.seb.sebserver.webservice.servicelayer.lms;
import java.util.Collection;
import ch.ethz.seb.sebserver.gbl.model.institution.CourseData;
import ch.ethz.seb.sebserver.gbl.model.institution.LmsSetup;
import ch.ethz.seb.sebserver.gbl.util.Result;
public interface LMSConnectionTemplate {
public interface LmsAPIService {
LmsSetup lmsSetup();
Result<LmsAPITemplate> createConnectionTemplate(Long lmsSetupId);
Collection<String> courseNames();
Collection<CourseData> searchCourses(String name, Long from, Long to);
CourseData course(String uuid);
Result<LmsAPITemplate> createConnectionTemplate(LmsSetup lmsSetup);
}

View file

@ -0,0 +1,48 @@
/*
* 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.servicelayer.lms;
import java.util.Collection;
import ch.ethz.seb.sebserver.gbl.model.Page;
import ch.ethz.seb.sebserver.gbl.model.Page.SortOrder;
import ch.ethz.seb.sebserver.gbl.model.exam.QuizData;
import ch.ethz.seb.sebserver.gbl.model.institution.LmsSetup;
import ch.ethz.seb.sebserver.gbl.model.institution.LmsSetupTestResult;
import ch.ethz.seb.sebserver.gbl.model.user.ExamineeAccountDetails;
import ch.ethz.seb.sebserver.gbl.util.Result;
public interface LmsAPITemplate {
enum OrderBy {
NAME,
FROM,
TO
}
LmsSetup lmsSetup();
LmsSetupTestResult testLmsSetup();
Collection<QuizData> getQuizzes(String name, Long from, Long to, OrderBy orderBy, SortOrder sortOrder);
Page<QuizData> getQuizzesPage(
String name,
Long from,
Long to,
OrderBy orderBy,
SortOrder sortOrder,
int pageNumber,
int pageSize);
Collection<Result<QuizData>> getQuizzes(Collection<String> ids);
Result<ExamineeAccountDetails> getExamineeAccountDetails(String examineeUserId);
}

View file

@ -0,0 +1,48 @@
/*
* 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.webservice.servicelayer.lms.impl;
import org.springframework.stereotype.Service;
import ch.ethz.seb.sebserver.gbl.model.institution.LmsSetup;
import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
import ch.ethz.seb.sebserver.gbl.util.Result;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.LmsSetupDAO;
import ch.ethz.seb.sebserver.webservice.servicelayer.lms.LmsAPIService;
import ch.ethz.seb.sebserver.webservice.servicelayer.lms.LmsAPITemplate;
@Service
@WebServiceProfile
public class LmsAPIServiceImpl implements LmsAPIService {
private final LmsSetupDAO lmsSetupDAO;
public LmsAPIServiceImpl(final LmsSetupDAO lmsSetupDAO) {
this.lmsSetupDAO = lmsSetupDAO;
}
@Override
public Result<LmsAPITemplate> createConnectionTemplate(final Long lmsSetupId) {
return this.lmsSetupDAO
.byId(lmsSetupId)
.flatMap(this::createConnectionTemplate);
}
@Override
public Result<LmsAPITemplate> createConnectionTemplate(final LmsSetup lmsSetup) {
switch (lmsSetup.lmsType) {
case MOCKUP:
return Result.of(new MockupLmsAPITemplate(lmsSetup));
default:
return Result.ofError(
new UnsupportedOperationException("No support for LMS Type: " + lmsSetup.lmsType));
}
}
}

View file

@ -0,0 +1,140 @@
/*
* 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.webservice.servicelayer.lms.impl;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.stream.Collectors;
import ch.ethz.seb.sebserver.gbl.model.Page;
import ch.ethz.seb.sebserver.gbl.model.Page.SortOrder;
import ch.ethz.seb.sebserver.gbl.model.exam.QuizData;
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.institution.LmsSetupTestResult;
import ch.ethz.seb.sebserver.gbl.model.user.ExamineeAccountDetails;
import ch.ethz.seb.sebserver.gbl.util.Result;
import ch.ethz.seb.sebserver.webservice.servicelayer.lms.LmsAPITemplate;
public class MockupLmsAPITemplate implements LmsAPITemplate {
private final LmsSetup setup;
private final Collection<QuizData> mockups;
public MockupLmsAPITemplate(final LmsSetup setup) {
if (!setup.isActive() || setup.lmsType != LmsType.MOCKUP) {
throw new IllegalArgumentException();
}
this.setup = setup;
this.mockups = new ArrayList<>();
this.mockups.add(new QuizData(
"quiz1", "Demo Quiz 1", "Demo Quit Mockup",
"2020-01-01 09:00:00", "2021-01-01 09:00:00", "http://lms.mockup.com/api/"));
this.mockups.add(new QuizData(
"quiz2", "Demo Quiz 2", "Demo Quit Mockup",
"2020-01-01 09:00:00", "2021-01-01 09:00:00", "http://lms.mockup.com/api/"));
this.mockups.add(new QuizData(
"quiz3", "Demo Quiz 3", "Demo Quit Mockup",
"2018-07-30 09:00:00", "2018-08-01 00:00:00", "http://lms.mockup.com/api/"));
this.mockups.add(new QuizData(
"quiz4", "Demo Quiz 4", "Demo Quit Mockup",
"2018-01-01 00:00:00", "2019-01-01 00:00:00", "http://lms.mockup.com/api/"));
this.mockups.add(new QuizData(
"quiz5", "Demo Quiz 5", "Demo Quit Mockup",
"2018-01-01 09:00:00", "2021-01-01 09:00:00", "http://lms.mockup.com/api/"));
this.mockups.add(new QuizData(
"quiz6", "Demo Quiz 6", "Demo Quit Mockup",
"2018-01-01 09:00:00", "2021-01-01 09:00:00", "http://lms.mockup.com/api/"));
this.mockups.add(new QuizData(
"quiz7", "Demo Quiz 7", "Demo Quit Mockup",
"2018-01-01 09:00:00", "2021-01-01 09:00:00", "http://lms.mockup.com/api/"));
}
@Override
public LmsSetup lmsSetup() {
return this.setup;
}
@Override
public LmsSetupTestResult testLmsSetup() {
if (this.setup.lmsApiUrl.equals("mockup") &&
this.setup.lmsAuthName.equals("mockup") &&
this.setup.lmsAuthSecret.equals("mockup")) {
return new LmsSetupTestResult(true);
} else {
return new LmsSetupTestResult(false);
}
}
@Override
public Collection<QuizData> getQuizzes(
final String name,
final Long from,
final Long to,
final OrderBy orderBy,
final SortOrder sortOrder) {
return this.mockups.stream()
.filter(mockup -> (name != null)
? mockup.name.contains(name)
: true && (from != null)
? mockup.startTime.getMillis() >= from
: true && (to != null)
? mockup.startTime.getMillis() < to
: true)
.collect(Collectors.toList());
}
@Override
public Page<QuizData> getQuizzesPage(
final String name,
final Long from,
final Long to,
final OrderBy orderBy,
final SortOrder sortOrder,
final int pageNumber,
final int pageSize) {
final int startIndex = pageNumber * pageSize;
final int endIndex = startIndex + pageSize;
int index = 0;
final Collection<QuizData> quizzes = getQuizzes(name, from, to, orderBy, sortOrder);
final int numberOfPages = quizzes.size() / pageSize;
final Iterator<QuizData> iterator = quizzes.iterator();
final List<QuizData> pageContent = new ArrayList<>();
while (iterator.hasNext() && index < endIndex) {
final QuizData next = iterator.next();
if (index >= startIndex) {
pageContent.add(next);
}
index++;
}
return new Page<>(numberOfPages, pageNumber, orderBy.name(), sortOrder, pageContent);
}
@Override
public Collection<Result<QuizData>> getQuizzes(final Collection<String> ids) {
return this.mockups.stream()
.filter(mockup -> ids.contains(mockup.uuid))
.map(mockup -> Result.of(mockup))
.collect(Collectors.toList());
}
@Override
public Result<ExamineeAccountDetails> getExamineeAccountDetails(final String examineeUserId) {
return Result.of(new ExamineeAccountDetails(examineeUserId, "mockup", "mockup", "mockup"));
}
}

View file

@ -25,7 +25,7 @@ import ch.ethz.seb.sebserver.gbl.model.EntityKey;
import ch.ethz.seb.sebserver.gbl.model.EntityProcessingReport;
import ch.ethz.seb.sebserver.gbl.model.EntityType;
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.institution.LmsSetup.LmsType;
import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
import ch.ethz.seb.sebserver.gbl.util.Result;
import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.AuthorizationGrantService;
@ -65,7 +65,7 @@ public class LmsSetupController {
public Collection<LmsSetup> getAll(
@RequestParam(name = LmsSetup.FILTER_ATTR_INSTITUTION, required = false) final Long institutionId,
@RequestParam(name = LmsSetup.FILTER_ATTR_NAME, required = false) final String name,
@RequestParam(name = LmsSetup.FILTER_ATTR_LMS_TYPE, required = false) final LMSType lmsType,
@RequestParam(name = LmsSetup.FILTER_ATTR_LMS_TYPE, required = false) final LmsType lmsType,
@RequestParam(name = LmsSetup.FILTER_ATTR_ACTIVE, required = false) final Boolean active) {
checkBaseReadPrivilege();
@ -96,7 +96,7 @@ public class LmsSetupController {
public Collection<EntityKeyAndName> getNames(
@RequestParam(name = LmsSetup.FILTER_ATTR_INSTITUTION, required = false) final Long institutionId,
@RequestParam(name = LmsSetup.FILTER_ATTR_NAME, required = false) final String name,
@RequestParam(name = LmsSetup.FILTER_ATTR_LMS_TYPE, required = false) final LMSType lmsType,
@RequestParam(name = LmsSetup.FILTER_ATTR_LMS_TYPE, required = false) final LmsType lmsType,
@RequestParam(name = LmsSetup.FILTER_ATTR_ACTIVE, required = false) final Boolean active) {
return getAll(institutionId, name, lmsType, active)