diff --git a/src/main/java/ch/ethz/seb/sebserver/gbl/authorization/PrivilegeType.java b/src/main/java/ch/ethz/seb/sebserver/gbl/authorization/PrivilegeType.java index b59da376..43c1464b 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gbl/authorization/PrivilegeType.java +++ b/src/main/java/ch/ethz/seb/sebserver/gbl/authorization/PrivilegeType.java @@ -12,8 +12,8 @@ package ch.ethz.seb.sebserver.gbl.authorization; public enum PrivilegeType { /** No privilege type at all (placeholder) */ NONE, - /** The read-only privilege type for read access */ - READ_ONLY, + /** The read privilege type for read access */ + READ, /** The modify privilege type includes read-only type privilege plus privilege for editing right but without create * and delete * rights */ @@ -24,8 +24,8 @@ public enum PrivilegeType { /** Use this to check implicit privilege. * * Implicit in this case means: if the privilegeType is of type PrivilegeType.WRITE, - * PrivilegeType.MODIFY and PrivilegeType.READ_ONLY are implicitly included. - * If the privilegeType is of type PrivilegeType.MODIFY, the PrivilegeType.READ_ONLY are implicitly included + * PrivilegeType.MODIFY and PrivilegeType.READ are implicitly included. + * If the privilegeType is of type PrivilegeType.MODIFY, the PrivilegeType.READ are implicitly included * and so on. * * @param type the PrivilegeType @@ -38,12 +38,12 @@ public enum PrivilegeType { switch (this) { case NONE: return false; - case READ_ONLY: - return type == READ_ONLY; + case READ: + return type == READ; case MODIFY: - return type == READ_ONLY || type == MODIFY; + return type == READ || type == MODIFY; case WRITE: - return type == READ_ONLY || type == MODIFY || type == WRITE; + return type == READ || type == MODIFY || type == WRITE; default: return false; } diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/activity/ActivitiesPane.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/activity/ActivitiesPane.java index deb8a76f..b9a8ee58 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/content/activity/ActivitiesPane.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/activity/ActivitiesPane.java @@ -108,7 +108,7 @@ public class ActivitiesPane implements TemplateComposer { // User Account // if current user has base or institutional read privilege for User Account, show list - if (this.currentUser.hasInstitutionalPrivilege(PrivilegeType.READ_ONLY, EntityType.USER)) { + if (this.currentUser.hasInstitutionalPrivilege(PrivilegeType.READ, EntityType.USER)) { final TreeItem userAccounts = this.widgetFactory.treeItemLocalized( navigation, ActivityDefinition.USER_ACCOUNT.displayName); @@ -131,7 +131,7 @@ public class ActivitiesPane implements TemplateComposer { } // LMS Setup - if (this.currentUser.hasInstitutionalPrivilege(PrivilegeType.READ_ONLY, EntityType.LMS_SETUP)) { + if (this.currentUser.hasInstitutionalPrivilege(PrivilegeType.READ, EntityType.LMS_SETUP)) { final TreeItem lmsSetup = this.widgetFactory.treeItemLocalized( navigation, ActivityDefinition.LMS_SETUP.displayName); @@ -143,7 +143,7 @@ public class ActivitiesPane implements TemplateComposer { } // Exam (Quiz Discovery) - if (this.currentUser.hasInstitutionalPrivilege(PrivilegeType.READ_ONLY, EntityType.EXAM)) { + if (this.currentUser.hasInstitutionalPrivilege(PrivilegeType.READ, EntityType.EXAM)) { // Quiz Discovery // TODO discussion if this should be visible on Activity Pane or just over the Exam activity and Import action diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/auth/CurrentUser.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/auth/CurrentUser.java index 75cc04fc..d8642219 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/auth/CurrentUser.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/auth/CurrentUser.java @@ -226,7 +226,7 @@ public class CurrentUser { * * @return true on read-only privilege grant on wrapped EntityType */ public boolean r() { - return hasBasePrivilege(PrivilegeType.READ_ONLY, this.entityType); + return hasBasePrivilege(PrivilegeType.READ, this.entityType); } /** Checks the base modify privilege grant @@ -247,7 +247,7 @@ public class CurrentUser { * * @return true institutional read-only privilege grant on wrapped EntityType */ public boolean ir() { - return hasInstitutionalPrivilege(PrivilegeType.READ_ONLY, this.entityType); + return hasInstitutionalPrivilege(PrivilegeType.READ, this.entityType); } /** Checks the institutional modify privilege grant @@ -277,7 +277,7 @@ public class CurrentUser { * * @return true on read-only privilege grant for wrapped grantEntity */ public boolean r() { - return hasPrivilege(PrivilegeType.READ_ONLY, this.grantEntity); + return hasPrivilege(PrivilegeType.READ, this.grantEntity); } /** Checks the modify privilege grant for wrapped grantEntity diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/authorization/AuthorizationService.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/authorization/AuthorizationService.java index 7cba82c7..a49d4d84 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/authorization/AuthorizationService.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/authorization/AuthorizationService.java @@ -23,7 +23,7 @@ import ch.ethz.seb.sebserver.gbl.util.Result; * * If there is one or more GrantEntity objects within an authenticated user-request, this service * can be used check the authenticated user access grant within the object. Check if a given user - * has write, modify or even read-only rights on an entity instance or on an entity type. */ + * has write, modify or even read rights on an entity instance or on an entity type. */ public interface AuthorizationService { /** Gets the UserService that is bundled within the AuthorizationGrantService @@ -138,7 +138,7 @@ public interface AuthorizationService { * @param grantEntity Entity instance * @return true if the current user has read-only grant on given Entity instance or false on deny */ default boolean hasReadonlyGrant(final GrantEntity grantEntity) { - return hasGrant(PrivilegeType.READ_ONLY, grantEntity); + return hasGrant(PrivilegeType.READ, grantEntity); } /** Check modify grant for a given Entity instance and current user. @@ -199,14 +199,14 @@ public interface AuthorizationService { return Result.of(grantEntity); } - /** Check read-only grant by using corresponding hasGrant(XY) method and throws PermissionDeniedException + /** Check read grant by using corresponding hasGrant(XY) method and throws PermissionDeniedException * on deny or returns the given grantEntity within a Result on successful grant. * This is useful to use with a Result based functional chain. * * @param entityType the type of the entity to check the given privilege type on * @param institutionId the institution identifier for institutional privilege grant check */ - default Result checkReadonly(final E grantEntity) { - return check(PrivilegeType.READ_ONLY, grantEntity); + default Result checkRead(final E grantEntity) { + return check(PrivilegeType.READ, grantEntity); } /** Check modify grant by using corresponding hasGrant(XY) method and throws PermissionDeniedException diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/authorization/AuthorizationServiceImpl.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/authorization/AuthorizationServiceImpl.java index 27462b25..dab26f88 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/authorization/AuthorizationServiceImpl.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/authorization/AuthorizationServiceImpl.java @@ -60,9 +60,9 @@ public class AuthorizationServiceImpl implements AuthorizationService { .andForRole(UserRole.INSTITUTIONAL_ADMIN) .withInstitutionalPrivilege(PrivilegeType.MODIFY) .andForRole(UserRole.EXAM_ADMIN) - .withInstitutionalPrivilege(PrivilegeType.READ_ONLY) + .withInstitutionalPrivilege(PrivilegeType.READ) .andForRole(UserRole.EXAM_SUPPORTER) - .withInstitutionalPrivilege(PrivilegeType.READ_ONLY) + .withInstitutionalPrivilege(PrivilegeType.READ) .create(); // grants for user account @@ -88,39 +88,39 @@ public class AuthorizationServiceImpl implements AuthorizationService { // grants for lms setup addPrivilege(EntityType.LMS_SETUP) .forRole(UserRole.SEB_SERVER_ADMIN) - .withBasePrivilege(PrivilegeType.READ_ONLY) + .withBasePrivilege(PrivilegeType.READ) .andForRole(UserRole.INSTITUTIONAL_ADMIN) .withInstitutionalPrivilege(PrivilegeType.WRITE) .andForRole(UserRole.EXAM_ADMIN) .withInstitutionalPrivilege(PrivilegeType.MODIFY) .andForRole(UserRole.EXAM_SUPPORTER) - .withInstitutionalPrivilege(PrivilegeType.READ_ONLY) + .withInstitutionalPrivilege(PrivilegeType.READ) .create(); // grants for exam addPrivilege(EntityType.EXAM) .forRole(UserRole.SEB_SERVER_ADMIN) - .withBasePrivilege(PrivilegeType.READ_ONLY) + .withBasePrivilege(PrivilegeType.READ) .andForRole(UserRole.INSTITUTIONAL_ADMIN) - .withInstitutionalPrivilege(PrivilegeType.READ_ONLY) + .withInstitutionalPrivilege(PrivilegeType.READ) .andForRole(UserRole.EXAM_ADMIN) .withInstitutionalPrivilege(PrivilegeType.MODIFY) .withOwnerPrivilege(PrivilegeType.WRITE) .andForRole(UserRole.EXAM_SUPPORTER) - .withInstitutionalPrivilege(PrivilegeType.READ_ONLY) + .withInstitutionalPrivilege(PrivilegeType.READ) .create(); // grants for indicators addPrivilege(EntityType.INDICATOR) .forRole(UserRole.SEB_SERVER_ADMIN) - .withBasePrivilege(PrivilegeType.READ_ONLY) + .withBasePrivilege(PrivilegeType.READ) .andForRole(UserRole.INSTITUTIONAL_ADMIN) - .withInstitutionalPrivilege(PrivilegeType.READ_ONLY) + .withInstitutionalPrivilege(PrivilegeType.READ) .andForRole(UserRole.EXAM_ADMIN) .withInstitutionalPrivilege(PrivilegeType.MODIFY) .withOwnerPrivilege(PrivilegeType.WRITE) .andForRole(UserRole.EXAM_SUPPORTER) - .withInstitutionalPrivilege(PrivilegeType.READ_ONLY) + .withInstitutionalPrivilege(PrivilegeType.READ) .create(); // TODO other entities @@ -128,9 +128,9 @@ public class AuthorizationServiceImpl implements AuthorizationService { // grants for user activity logs addPrivilege(EntityType.USER_ACTIVITY_LOG) .forRole(UserRole.SEB_SERVER_ADMIN) - .withBasePrivilege(PrivilegeType.READ_ONLY) + .withBasePrivilege(PrivilegeType.READ) .andForRole(UserRole.INSTITUTIONAL_ADMIN) - .withInstitutionalPrivilege(PrivilegeType.READ_ONLY) + .withInstitutionalPrivilege(PrivilegeType.READ) .create(); } diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/EntityController.java b/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/EntityController.java index 84bb4c06..c209b360 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/EntityController.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/EntityController.java @@ -135,7 +135,7 @@ public abstract class EntityController { private final ExamDAO examDAO; + private final UserDAO userDAO; private final LmsAPIService lmsAPIService; public ExamAdministrationController( @@ -58,7 +68,8 @@ public class ExamAdministrationController extends ActivatableEntityController { + this.authorization.checkRead(template.lmsSetup()); + return template; + }) .flatMap(template -> template.getQuiz(quizId)) .map(quiz -> new Exam(null, quiz, postParams)) .getOrThrow(); } + @Override + protected Result validForSave(final Exam entity) { + return super.validForSave(entity) + .map(this::checkExamSupporterRole); + } + + private Exam checkExamSupporterRole(final Exam exam) { + final Set examSupporter = this.userDAO.all( + this.authorization.getUserService().getCurrentUser().getUserInfo().institutionId, + true) + .map(users -> users.stream() + .filter(user -> user.getRoles().contains(UserRole.EXAM_SUPPORTER.name())) + .map(user -> user.uuid) + .collect(Collectors.toSet())) + .getOrThrow(); + + for (final String supporterUUID : exam.getSupporter()) { + if (!examSupporter.contains(supporterUUID)) { + throw new APIMessageException(APIMessage.fieldValidationError( + new FieldError( + Domain.EXAM.TYPE_NAME, + Domain.EXAM.ATTR_SUPPORTER, + "exam:supporter:grantDenied:" + supporterUUID))); + } + } + return exam; + } + } diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/QuizController.java b/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/QuizController.java index 8895828a..5761ccd4 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/QuizController.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/QuizController.java @@ -81,7 +81,7 @@ public class QuizController { @RequestParam final MultiValueMap allRequestParams) { this.authorization.check( - PrivilegeType.READ_ONLY, + PrivilegeType.READ, EntityType.EXAM, institutionId); @@ -115,7 +115,7 @@ public class QuizController { .getLmsAPITemplate(lmsSetupId) .getOrThrow() .getQuiz(modelId) - .flatMap(this.authorization::checkReadonly) + .flatMap(this.authorization::checkRead) .getOrThrow(); } diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/UserActivityLogController.java b/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/UserActivityLogController.java index dd45fe39..d4afa70c 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/UserActivityLogController.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/UserActivityLogController.java @@ -134,7 +134,7 @@ public class UserActivityLogController { private void checkBaseReadPrivilege(final Long institutionId) { this.authorization.check( - PrivilegeType.READ_ONLY, + PrivilegeType.READ, EntityType.USER_ACTIVITY_LOG, institutionId); } diff --git a/src/main/resources/messages.properties b/src/main/resources/messages.properties index c9805e61..2db78ae4 100644 --- a/src/main/resources/messages.properties +++ b/src/main/resources/messages.properties @@ -89,7 +89,7 @@ sebserver.institution.action.export.sebconfig=SEB Client Config sebserver.institution.info.pleaseSelect=Please Select an Institution first. sebserver.institution.form.title.new=New Institution -sebserver.institution.form.title=Institution : {0} +sebserver.institution.form.title=Institution sebserver.institution.form.name=Name sebserver.institution.form.urlSuffix=URL Suffix diff --git a/src/main/resources/messages_en.properties b/src/main/resources/messages_en.properties new file mode 100644 index 00000000..c4f88f98 --- /dev/null +++ b/src/main/resources/messages_en.properties @@ -0,0 +1,295 @@ +################################ +# Overall +################################ + +sebserver.overall.version=SEB Server Version : {0} +sebserver.overall.imprint=Imprint +sebserver.overall.about=About + +sebserver.overall.message.leave.without.save=You have unsaved changes!\nAre you sure you want to leave the page?\The changes will be lost. +sebserver.overall.upload=Please Select +sebserver.overall.action.modify.cancel=Cancel +sebserver.overall.action.modify.cancel.confirm=Are you sure you want to cancel? Modifications will be lost. +sebserver.overall.action.filter=Apply filter +sebserver.overall.action.filter.clear=Clear filter criteria +sebserver.overall.action.ok=OK +sebserver.overall.action.cancel=Cancel +sebserver.overall.action.close=Close +sebserver.overall.action.goAwayFromEditPageConfirm=Are you sure you want to leave this page? Unsaved data will be lost. +sebserver.overall.action.category.varia=Varia + +################################ +# Form validation and messages +################################ + +sebserver.form.validation.error.title=Form data validation failed +sebserver.form.validation.error.message=There is missing or incorrect form data. +sebserver.form.validation.fieldError.size=The size must be between {3} and {4} +sebserver.form.validation.fieldError.name=The Name is mandatory and must have a size between {3} and {4} character +sebserver.form.validation.fieldError.urlSuffix=The URL Suffix must have a size between {3} and {4} character +sebserver.form.validation.fieldError.notNull=This field is mandatory +sebserver.form.validation.fieldError.username.notunique=This Username is already in use. Please choose another one. +sebserver.form.validation.fieldError.password.wrong=The old password is wrong +sebserver.form.validation.fieldError.password.mismatch=The re-typed password doesn't match the new password +sebserver.form.validation.fieldError.invalidURL=The input does not match the URL pattern. +sebserver.form.validation.fieldError.exists=This name already exists. Please choose another one. +sebserver.error.unexpected=Unexpected Error +sebserver.page.message=Information +sebserver.dialog.confirm.title=Confirmation + +sebserver.dialog.confirm.deactivation=Note that there are {0} other entities that belong to this entity.
These will also be deactivated by deactivating this entity.

Are You sure you want to deactivate this entity? +sebserver.dialog.confirm.deactivation.noDependencies=Are You sure you want to deactivate? + +################################ +# Login Page +################################ + +sebserver.login.username=User Name +sebserver.login.pwd=Password +sebserver.login.login=Sign In +sebserver.login.failed.title=Login failed +sebserver.login.failed.message=Access denied: wrong username or password +sebserver.logout=Sign out +sebserver.logout.success.message=You have been successfully signed out. +sebserver.login.password.change=Information +sebserver.login.password.change.success=The password was successfully changed. Please sign in with your new password + +################################ +# Main Page +################################ + +sebserver.logout=Logout +sebserver.mainpage.maximize.tooltip=Maximize +sebserver.mainpage.minimize.tooltip=Minimize +sebserver.activitiespane.title=Administration +sebserver.actionpane.title=Actions + +################################ +# Institution +################################ + +sebserver.institution.list.actions=Selected Institution +sebserver.institution.list.empty=No institution has been found. Please adapt the filter or create a new institution +sebserver.institution.list.title=Institutions +sebserver.institution.list.column.name=Name +sebserver.institution.list.column.urlSuffix=URL Suffix +sebserver.institution.list.column.active=Active + +sebserver.institution.action.list=Institution +sebserver.institution.action.form=Institution +sebserver.institution.action.new=Add Institution +sebserver.institution.action.list.view=View Institution +sebserver.institution.action.list.modify=Edit Institution +sebserver.institution.action.modify=Edit +sebserver.institution.action.save=Save Institution +sebserver.institution.action.activate=Activate +sebserver.institution.action.deactivate=Deactivate +sebserver.institution.action.delete=Delete Institution +sebserver.institution.action.export.sebconfig=SEB Client Config + +sebserver.institution.info.pleaseSelect=Please select an institution first. +sebserver.institution.form.title.new=Add Institution +sebserver.institution.form.title=Institution + +sebserver.institution.form.name=Name +sebserver.institution.form.urlSuffix=URL Suffix +sebserver.institution.form.logoImage=Logo Image + + +################################ +# User Account +################################ + +sebserver.useraccount.list.actions=Selected User Account +sebserver.useraccount.role.SEB_SERVER_ADMIN=SEB Server Administrator +sebserver.useraccount.role.INSTITUTIONAL_ADMIN=Institutional Administrator +sebserver.useraccount.role.EXAM_ADMIN=Exam Administrator +sebserver.useraccount.role.EXAM_SUPPORTER=Exam Supporter + +sebserver.useraccount.list.empty=No user account has been found. Please adapt the filter or create a new user account +sebserver.useraccount.list.title=User Accounts +sebserver.useraccount.list.column.institution=Institution +sebserver.useraccount.list.column.name=Name +sebserver.useraccount.list.column.username=User Name +sebserver.useraccount.list.column.email=Mail +sebserver.useraccount.list.column.language=Language +sebserver.useraccount.list.column.active=Active + +sebserver.useraccount.action.list=User Account +sebserver.useraccount.action.form=User Account of {0} +sebserver.useraccount.action.new=Add User Account +sebserver.useraccount.action.view=View User Account +sebserver.useraccount.action.list.modify=Edit User Account +sebserver.useraccount.action.modify=Edit +sebserver.useraccount.action.save=Save User Account +sebserver.useraccount.action.activate=Activate +sebserver.useraccount.action.deactivate=Deactivate +sebserver.useraccount.action.delete=Delete User Account +sebserver.useraccount.action.change.password=Change Password +sebserver.useraccount.action.change.password.save=Save New Password + +sebserver.useraccount.info.pleaseSelect=Please select a user account first. + +sebserver.useraccount.form.title=User Account +sebserver.useraccount.form.title.new=Add User Account +sebserver.useraccount.form.institution=Institution +sebserver.useraccount.form.name=Name +sebserver.useraccount.form.username=Username +sebserver.useraccount.form.mail=E-Mail +sebserver.useraccount.form.language=Language +sebserver.useraccount.form.timezone=Time Zone +sebserver.useraccount.form.roles=User Roles +sebserver.useraccount.form.password=Password +sebserver.useraccount.form.password.confirm=Confirm Password + +sebserver.useraccount.form.pwchange.title=Change Password : {0} +sebserver.useraccount.form.password=Password +sebserver.useraccount.form.password.new=New Password +sebserver.useraccount.form.password.new.confirm=Confirm New Password + +################################ +# LMS Setup +################################ + +sebserver.lmssetup.type.MOCKUP=Mock-up +sebserver.lmssetup.type.MOODLE=Moodle +sebserver.lmssetup.type.OPEN_EDX=Open edX + +sebserver.lmssetup.list.actions=Selected LMS Setup +sebserver.lmssetup.list.empty=No LMS Setup has been found. Please adapt the filter or create a new LMS Setup +sebserver.lmssetup.list.title=Learning Management System Setups +sebserver.lmssetup.list.column.institution=Institution +sebserver.lmssetup.list.column.name=Name +sebserver.lmssetup.list.column.type=LMS Type +sebserver.lmssetup.list.column.active=Active + +sebserver.lmssetup.action.list=LMS Setup +sebserver.lmssetup.action.form=LMS Setup +sebserver.lmssetup.action.new=Add LMS Setup +sebserver.lmssetup.action.list.view=View LMS Setup +sebserver.lmssetup.action.list.modify=Edit LMS Setup +sebserver.lmssetup.action.modify=Edit +sebserver.lmssetup.action.test=Test Setup +sebserver.lmssetup.action.test.ok=Successfully connected to the course API +sebserver.lmssetup.action.test.tokenRequestError=The API access was denied: {0} +sebserver.lmssetup.action.test.quizRequestError=Unable to request courses or quizzes from the course API of the LMS. {0} +sebserver.lmssetup.action.test.missingParameter=There is one or more missing connection parameter.
Please check the connection parameter for this LMS Setup +sebserver.lmssetup.action.test.unknownError=An unexpected error happened while trying to connect to the LMS course API. {0} +sebserver.lmssetup.action.save=Save LMS Setup +sebserver.lmssetup.action.activate=Activate +sebserver.lmssetup.action.deactivate=Deactivate +sebserver.lmssetup.action.delete=Delete LMS Setup + +sebserver.lmssetup.info.pleaseSelect=Please Select a LMS Setup first + +sebserver.lmssetup.form.title=Learning Management System Setup +sebserver.lmssetup.form.title.new=Add Learning Management System Setup +sebserver.lmssetup.form.institution=Institution +sebserver.lmssetup.form.name=Name +sebserver.lmssetup.form.type=Type +sebserver.lmssetup.form.clientname.seb=SEB Auth. Name +sebserver.lmssetup.form.secret.seb=SEB Auth. Password +sebserver.lmssetup.form.url=LMS Server Address +sebserver.lmssetup.form.clientname.lms=LMS Server Username +sebserver.lmssetup.form.secret.lms=LMS Server Password + +################################ +# Quiz Discovery +################################ + +sebserver.quizdiscovery.list.actions=Selected Quiz + +sebserver.quizdiscovery.list.title=Quizzes +sebserver.quizdiscovery.list.empty=No Quiz has been found. Please adapt the filter or create a new LMS Setup +sebserver.quizdiscovery.list.column.institution=Institution +sebserver.quizdiscovery.list.column.lmssetup=LMS +sebserver.quizdiscovery.list.column.name=Name +sebserver.quizdiscovery.list.column.starttime=Start Time {0} +sebserver.quizdiscovery.list.column.endtime=End Time {0} +sebserver.quizdiscovery.info.pleaseSelect=Please Select a Quiz first + +sebserver.quizdiscovery.action.list=Quiz Discovery +sebserver.quizdiscovery.action.import=Import as Exam +sebserver.quizdiscovery.action.details=Show Details + +sebserver.quizdiscovery.quiz.details.title=Quiz Details +sebserver.quizdiscovery.quiz.details.lms=LMS +sebserver.quizdiscovery.quiz.details.name=Name +sebserver.quizdiscovery.quiz.details.description=Description +sebserver.quizdiscovery.quiz.details.starttime=Start Time +sebserver.quizdiscovery.quiz.details.endtime=End Time +sebserver.quizdiscovery.quiz.details.url=Start URL + +################################ +# Exam +################################ + +sebserver.exam.list.actions=Selected Exam +sebserver.exam.list.title=Exams +sebserver.exam.list.column.institution=Institution +sebserver.exam.list.column.lmssetup=LMS +sebserver.exam.list.column.name=Name +sebserver.exam.list.column.starttime=Start Time {0} +sebserver.exam.list.column.type=Type + +sebserver.exam.list.empty=No Exam has been found. Please adapt the filter or import one from Quiz + +sebserver.exam.action.list=Exam +sebserver.exam.action.list.view=View Exam +sebserver.exam.action.list.modify=Edit Exam +sebserver.exam.action.modify=Edit Exam +sebserver.exam.action.import=Import From Quizzes +sebserver.exam.action.save=Save Exam +sebserver.exam.action.activate=Activate Exam +sebserver.exam.action.deactivate=Deactivate Exam + +sebserver.exam.info.pleaseSelect=Please Select an Exam first + +sebserver.exam.form.title.import=New Exam +sebserver.exam.form.title=Exam +sebserver.exam.form.lmssetup=LMS Setup +sebserver.exam.form.quizid=Quiz Identifier +sebserver.exam.form.name=Name +sebserver.exam.form.description=Description +sebserver.exam.form.starttime=Start Time +sebserver.exam.form.endtime=End Time +sebserver.exam.form.status=Status +sebserver.exam.form.type=Exam Type +sebserver.exam.form.supporter=Exam Supporter + +sebserver.exam.type.UNDEFINED=Not Defined +sebserver.exam.type.MANAGED=Managed Devices +sebserver.exam.type.BYOD=Bring Your Own Device +sebserver.exam.type.VDI=VDI (Virtual Desktop Infrastructure) + +sebserver.exam.indicator.list.actions=Selected Indicator +sebserver.exam.indicator.list.title=Indicators +sebserver.exam.indicator.list.column.type=Type +sebserver.exam.indicator.list.column.name=Name +sebserver.exam.indicator.list.column.thresholds=Thresholds +sebserver.exam.indicator.list.empty=There is currently no indicator defined for this exam. Please create a new one +sebserver.exam.indicator.list.pleaseSelect=Please select an indicator first + +sebserver.exam.indicator.type.LAST_PING=Last Ping +sebserver.exam.indicator.type.ERROR_COUNT=Error Count + +sebserver.exam.indicator.info.pleaseSelect=Please select an indicator first + +sebserver.exam.indicator.action.list.new=New Indicator +sebserver.exam.indicator.action.list.modify=Edit +sebserver.exam.indicator.action.list.delete=Delete +sebserver.exam.indicator.action.save=Save + +sebserver.exam.indicator.form.title=Indicator +sebserver.exam.indicator.form.title.new=Add Indicator +sebserver.exam.indicator.form.exam=Exam +sebserver.exam.indicator.form.name=Name +sebserver.exam.indicator.form.type=Type +sebserver.exam.indicator.form.color=Default Color +sebserver.exam.indicator.form.thresholds=Thresholds + +sebserver.exam.indicator.thresholds.list.title=Thresholds +sebserver.exam.indicator.thresholds.list.value=Value +sebserver.exam.indicator.thresholds.list.color=Color +sebserver.exam.indicator.thresholds.list.add=Add Threshold +sebserver.exam.indicator.thresholds.list.remove=Delete Threshold diff --git a/src/test/java/ch/ethz/seb/sebserver/gui/integration/CurrentUserTest.java b/src/test/java/ch/ethz/seb/sebserver/gui/integration/CurrentUserTest.java index 950352c0..20c5b4f7 100644 --- a/src/test/java/ch/ethz/seb/sebserver/gui/integration/CurrentUserTest.java +++ b/src/test/java/ch/ethz/seb/sebserver/gui/integration/CurrentUserTest.java @@ -47,7 +47,7 @@ public class CurrentUserTest extends GuiIntegrationTest { // login as SEB Administrator authorizationContextHolder.getAuthorizationContext().login("admin", "admin"); - assertTrue(currentUser.hasBasePrivilege(PrivilegeType.READ_ONLY, EntityType.INSTITUTION)); + assertTrue(currentUser.hasBasePrivilege(PrivilegeType.READ, EntityType.INSTITUTION)); assertTrue(currentUser.hasPrivilege(PrivilegeType.WRITE, currentUser.get())); assertTrue(currentUser.hasBasePrivilege(PrivilegeType.WRITE, EntityType.INSTITUTION)); assertTrue(currentUser.hasInstitutionalPrivilege(PrivilegeType.MODIFY, EntityType.INSTITUTION)); diff --git a/src/test/java/ch/ethz/seb/sebserver/webservice/integration/api/admin/ExamAPITest.java b/src/test/java/ch/ethz/seb/sebserver/webservice/integration/api/admin/ExamAPITest.java new file mode 100644 index 00000000..93a94b44 --- /dev/null +++ b/src/test/java/ch/ethz/seb/sebserver/webservice/integration/api/admin/ExamAPITest.java @@ -0,0 +1,105 @@ +/* + * 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.integration.api.admin; + +import static org.junit.Assert.*; + +import java.util.Arrays; +import java.util.List; + +import org.junit.Test; +import org.springframework.http.HttpMethod; +import org.springframework.http.HttpStatus; +import org.springframework.test.context.jdbc.Sql; + +import com.fasterxml.jackson.core.type.TypeReference; + +import ch.ethz.seb.sebserver.gbl.api.API; +import ch.ethz.seb.sebserver.gbl.api.APIMessage; +import ch.ethz.seb.sebserver.gbl.model.exam.Exam; +import ch.ethz.seb.sebserver.gbl.model.exam.Exam.ExamType; + +@Sql(scripts = { "classpath:schema-test.sql", "classpath:data-test.sql" }) +public class ExamAPITest extends AdministrationAPIIntegrationTester { + + @Test + public void testModify() throws Exception { + final String sebAdminAccess = getSebAdminAccess(); + final Exam exam = ExamImportTest.createImportedExamFromLmsSetupMock( + this, + sebAdminAccess, + sebAdminAccess, + "LmsSetupMock", + "quiz2", + ExamType.MANAGED); + + assertNotNull(exam); + assertEquals("quiz2", exam.getExternalId()); + assertEquals(ExamType.MANAGED, exam.getType()); + assertTrue(exam.getSupporter().isEmpty()); + + // add ExamSupporter + final Exam newExam = new RestAPITestHelper() + .withAccessToken(sebAdminAccess) + .withPath(API.EXAM_ADMINISTRATION_ENDPOINT) + .withMethod(HttpMethod.PUT) + .withBodyJson(new Exam( + exam.id, + exam.institutionId, + exam.lmsSetupId, + exam.externalId, + exam.name, + exam.description, + exam.startTime, + exam.endTime, + exam.startURL, + exam.type, + exam.quitPassword, + exam.owner, + Arrays.asList("user5"), + false)) + .withExpectedStatus(HttpStatus.OK) + .getAsObject(new TypeReference() { + }); + + assertFalse(newExam.getSupporter().isEmpty()); + assertTrue(newExam.getSupporter().size() == 1); + assertEquals("user5", newExam.getSupporter().iterator().next()); + + // try to add a user as exam supporter with no exam support role should not be possible + final List error = new RestAPITestHelper() + .withAccessToken(sebAdminAccess) + .withPath(API.EXAM_ADMINISTRATION_ENDPOINT) + .withMethod(HttpMethod.PUT) + .withBodyJson(new Exam( + exam.id, + exam.institutionId, + exam.lmsSetupId, + exam.externalId, + exam.name, + exam.description, + exam.startTime, + exam.endTime, + exam.startURL, + exam.type, + exam.quitPassword, + exam.owner, + Arrays.asList("user2"), + false)) + .withExpectedStatus(HttpStatus.BAD_REQUEST) + .getAsObject(new TypeReference>() { + }); + + assertNotNull(error); + assertTrue(error.size() == 1); + final APIMessage error1 = error.iterator().next(); + assertEquals("[exam, supporter, grantDenied, user2]", String.valueOf(error1.attributes)); + } + +} diff --git a/src/test/java/ch/ethz/seb/sebserver/webservice/integration/api/admin/ExamImportTest.java b/src/test/java/ch/ethz/seb/sebserver/webservice/integration/api/admin/ExamImportTest.java index 0cf54fbc..91b9e865 100644 --- a/src/test/java/ch/ethz/seb/sebserver/webservice/integration/api/admin/ExamImportTest.java +++ b/src/test/java/ch/ethz/seb/sebserver/webservice/integration/api/admin/ExamImportTest.java @@ -8,8 +8,7 @@ package ch.ethz.seb.sebserver.webservice.integration.api.admin; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.*; import org.junit.Test; import org.springframework.http.HttpMethod; @@ -19,7 +18,9 @@ import org.springframework.test.context.jdbc.Sql; import com.fasterxml.jackson.core.type.TypeReference; import ch.ethz.seb.sebserver.gbl.api.API; +import ch.ethz.seb.sebserver.gbl.model.Domain; import ch.ethz.seb.sebserver.gbl.model.exam.Exam; +import ch.ethz.seb.sebserver.gbl.model.exam.Exam.ExamType; import ch.ethz.seb.sebserver.gbl.model.exam.QuizData; import ch.ethz.seb.sebserver.gbl.model.institution.LmsSetup; @@ -27,9 +28,9 @@ import ch.ethz.seb.sebserver.gbl.model.institution.LmsSetup; public class ExamImportTest extends AdministrationAPIIntegrationTester { @Test - public void testImportFromQuizz() throws Exception { + public void testImportFromQuiz() throws Exception { // create new active LmsSetup Mock with seb-admin - final LmsSetup lmsSetup1 = QuizDataTest.createLmsSetupMockWith( + final LmsSetup lmsSetup1 = QuizDataTest.createLmsSetupMock( this, getSebAdminAccess(), "new LmsSetup 1", @@ -49,6 +50,95 @@ public class ExamImportTest extends AdministrationAPIIntegrationTester { assertNotNull(exam); assertEquals("quiz1", exam.getExternalId()); assertEquals(lmsSetup1.id, exam.getLmsSetupId()); + assertEquals(ExamType.UNDEFINED, exam.getType()); + + final Exam exam2 = createImportedExamFromLmsSetupMock( + this, + getSebAdminAccess(), + getSebAdminAccess(), + "LmsSetupMock", + "quiz2", + ExamType.MANAGED); + + assertNotNull(exam2); + assertEquals("quiz2", exam2.getExternalId()); + assertEquals(ExamType.MANAGED, exam2.getType()); + } + + @Test + public void testImportFromQuizWithInstitutionalAdmin2() throws Exception { + // Institutional administrators are able to create LMS Setups but not to import quizzes + // as Exams. Only Exam administrators should be allowed to import Exams from quizzes + try { + createImportedExamFromLmsSetupMock( + this, + getAdminInstitution2Access(), + getAdminInstitution2Access(), + "LmsSetupMock", + "quiz2", + ExamType.MANAGED); + fail("AssertionError expected here"); + } catch (final AssertionError ae) { + assertEquals("Response status expected:<200> but was:<403>", ae.getMessage()); + } + + // Only Exam administrators should be allowed to import Exams from quizzes + final Exam exam2 = createImportedExamFromLmsSetupMock( + this, + getAdminInstitution2Access(), + getExamAdmin1(), // this exam administrator is on Institution 2 + "LmsSetupMock", + "quiz2", + ExamType.MANAGED); + + assertNotNull(exam2); + assertEquals("quiz2", exam2.getExternalId()); + assertEquals(ExamType.MANAGED, exam2.getType()); + } + + @Test + public void testImportFromQuizWithInstitutional() throws Exception { + // and creation between different institutions should also not be possible + try { + createImportedExamFromLmsSetupMock( + this, + getAdminInstitution1Access(), + getExamAdmin1(), // this exam administrator is on Institution 2 + "LmsSetupMock", + "quiz2", + ExamType.MANAGED); + fail("AssertionError expected here"); + } catch (final AssertionError ae) { + assertEquals("Response status expected:<200> but was:<403>", ae.getMessage()); + } + } + + public static final Exam createImportedExamFromLmsSetupMock( + final AdministrationAPIIntegrationTester tester, + final String tokenForLmsSetupCreation, + final String tokenForExamImport, + final String lmsSetupName, + final String importQuizName, + final ExamType examType) throws Exception { + + // create new active LmsSetup Mock with seb-admin + final LmsSetup lmsSetup1 = QuizDataTest.createLmsSetupMock( + tester, + tokenForLmsSetupCreation, + lmsSetupName, + true); + + // import Exam from quiz1 + return tester.restAPITestHelper() + .withAccessToken(tokenForExamImport) + .withPath(API.EXAM_ADMINISTRATION_ENDPOINT) + .withMethod(HttpMethod.POST) + .withAttribute(QuizData.QUIZ_ATTR_LMS_SETUP_ID, lmsSetup1.getModelId()) + .withAttribute(QuizData.QUIZ_ATTR_ID, importQuizName) + .withAttribute(Domain.EXAM.ATTR_TYPE, examType.name()) + .withExpectedStatus(HttpStatus.OK) + .getAsObject(new TypeReference() { + }); } } diff --git a/src/test/java/ch/ethz/seb/sebserver/webservice/integration/api/admin/QuizDataTest.java b/src/test/java/ch/ethz/seb/sebserver/webservice/integration/api/admin/QuizDataTest.java index a491be46..bc797b1e 100644 --- a/src/test/java/ch/ethz/seb/sebserver/webservice/integration/api/admin/QuizDataTest.java +++ b/src/test/java/ch/ethz/seb/sebserver/webservice/integration/api/admin/QuizDataTest.java @@ -31,7 +31,7 @@ public class QuizDataTest extends AdministrationAPIIntegrationTester { @Test public void testGetInstitutionalQuizPage() throws Exception { // create new active LmsSetup Mock with seb-admin - final LmsSetup lmsSetup1 = createLmsSetupMockWith( + final LmsSetup lmsSetup1 = createLmsSetupMock( this, getSebAdminAccess(), "new LmsSetup 1", @@ -41,7 +41,7 @@ public class QuizDataTest extends AdministrationAPIIntegrationTester { assertTrue(lmsSetup1.isActive()); // create new inactive LmsSetup Mock with institution 2 admin - final LmsSetup lmsSetup2 = createLmsSetupMockWith( + final LmsSetup lmsSetup2 = createLmsSetupMock( this, getAdminInstitution2Access(), "new LmsSetup 2", @@ -116,7 +116,7 @@ public class QuizDataTest extends AdministrationAPIIntegrationTester { @Test public void testGetQuiz() throws Exception { // create new active LmsSetup Mock with seb-admin - final LmsSetup lmsSetup = createLmsSetupMockWith( + final LmsSetup lmsSetup = createLmsSetupMock( this, getSebAdminAccess(), "new LmsSetup 1", @@ -135,7 +135,7 @@ public class QuizDataTest extends AdministrationAPIIntegrationTester { assertNotNull(quizData); } - public static final LmsSetup createLmsSetupMockWith( + public static final LmsSetup createLmsSetupMock( final AdministrationAPIIntegrationTester tester, final String token, final String name, diff --git a/src/test/java/ch/ethz/seb/sebserver/webservice/servicelayer/authorization/AuthorizationServiceTest.java b/src/test/java/ch/ethz/seb/sebserver/webservice/servicelayer/authorization/AuthorizationServiceTest.java index dc056c27..d8b8e53a 100644 --- a/src/test/java/ch/ethz/seb/sebserver/webservice/servicelayer/authorization/AuthorizationServiceTest.java +++ b/src/test/java/ch/ethz/seb/sebserver/webservice/servicelayer/authorization/AuthorizationServiceTest.java @@ -32,7 +32,7 @@ public class AuthorizationServiceTest { public void testInstitutionGrantForSEB_SERVER_ADMIN() { final AuthorizationServiceImpl service = getTestServiceWithUserWithRoles(UserRole.SEB_SERVER_ADMIN); - assertTrue(service.hasGrant(PrivilegeType.READ_ONLY, EntityType.INSTITUTION)); + assertTrue(service.hasGrant(PrivilegeType.READ, EntityType.INSTITUTION)); assertTrue(service.hasGrant(PrivilegeType.MODIFY, EntityType.INSTITUTION)); assertTrue(service.hasGrant(PrivilegeType.WRITE, EntityType.INSTITUTION)); @@ -47,7 +47,7 @@ public class AuthorizationServiceTest { public void testInstitutionGrantsForINSTITUTIONAL_ADMIN() { final AuthorizationServiceImpl service = getTestServiceWithUserWithRoles(UserRole.INSTITUTIONAL_ADMIN); - assertFalse(service.hasGrant(PrivilegeType.READ_ONLY, EntityType.INSTITUTION)); + assertFalse(service.hasGrant(PrivilegeType.READ, EntityType.INSTITUTION)); assertFalse(service.hasGrant(PrivilegeType.MODIFY, EntityType.INSTITUTION)); assertFalse(service.hasGrant(PrivilegeType.WRITE, EntityType.INSTITUTION));