SEBSERV-44 Controller implementation
This commit is contained in:
parent
e3d6426cc2
commit
4fe8034501
14 changed files with 414 additions and 100 deletions
|
@ -59,6 +59,18 @@ public final class API {
|
|||
|
||||
public static final String EXAM_INDICATOR_ENDPOINT = "/indicator";
|
||||
|
||||
public static final String CONFIGURATION_NODE_ENDPOINT = "/configuration_node";
|
||||
|
||||
public static final String CONFIGURATION_ENDPOINT = "/configuration";
|
||||
|
||||
public static final String CONFIGURATION_VALUE_ENDPOINT = "/configuration_value";
|
||||
|
||||
public static final String CONFIGURATION_ATTRIBUTE_ENDPOINT = "/configuration_attribute";
|
||||
|
||||
public static final String ORIENTATION_ENDPOINT = "/orientation";
|
||||
|
||||
public static final String EXAM_CONFIGURATION_MAP_ENDPOINT = "/exam_configuration_map";
|
||||
|
||||
public static final String USER_ACTIVITY_LOG_ENDPOINT = "/useractivity";
|
||||
|
||||
public static final String SELF_PATH_SEGMENT = "/self";
|
||||
|
|
|
@ -21,14 +21,13 @@ import com.fasterxml.jackson.annotation.JsonProperty;
|
|||
import ch.ethz.seb.sebserver.gbl.api.EntityType;
|
||||
import ch.ethz.seb.sebserver.gbl.api.POSTMapper;
|
||||
import ch.ethz.seb.sebserver.gbl.model.Domain;
|
||||
import ch.ethz.seb.sebserver.gbl.model.Domain.EXAM;
|
||||
import ch.ethz.seb.sebserver.gbl.model.Domain.INDICATOR;
|
||||
import ch.ethz.seb.sebserver.gbl.model.Domain.THRESHOLD;
|
||||
import ch.ethz.seb.sebserver.gbl.model.Entity;
|
||||
import ch.ethz.seb.sebserver.gbl.util.Utils;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.GrantEntity;
|
||||
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public final class Indicator implements GrantEntity {
|
||||
public final class Indicator implements Entity {
|
||||
|
||||
public static final String FILTER_ATTR_EXAM = "exam";
|
||||
|
||||
|
@ -40,10 +39,6 @@ public final class Indicator implements GrantEntity {
|
|||
@JsonProperty(INDICATOR.ATTR_ID)
|
||||
public final Long id;
|
||||
|
||||
@JsonProperty(EXAM.ATTR_INSTITUTION_ID)
|
||||
@NotNull
|
||||
public final Long institutionId;
|
||||
|
||||
@JsonProperty(INDICATOR.ATTR_EXAM_ID)
|
||||
@NotNull
|
||||
public final Long examId;
|
||||
|
@ -63,24 +58,17 @@ public final class Indicator implements GrantEntity {
|
|||
@JsonProperty(THRESHOLD.REFERENCE_NAME)
|
||||
public final List<Threshold> thresholds;
|
||||
|
||||
@JsonProperty(EXAM.ATTR_OWNER)
|
||||
public final String examOwner;
|
||||
|
||||
@JsonCreator
|
||||
public Indicator(
|
||||
@JsonProperty(INDICATOR.ATTR_ID) final Long id,
|
||||
@JsonProperty(EXAM.ATTR_INSTITUTION_ID) final Long institutionId,
|
||||
@JsonProperty(INDICATOR.ATTR_EXAM_ID) final Long examId,
|
||||
@JsonProperty(EXAM.ATTR_OWNER) final String examOwner,
|
||||
@JsonProperty(INDICATOR.ATTR_NAME) final String name,
|
||||
@JsonProperty(INDICATOR.ATTR_TYPE) final IndicatorType type,
|
||||
@JsonProperty(INDICATOR.ATTR_COLOR) final String defaultColor,
|
||||
@JsonProperty(THRESHOLD.REFERENCE_NAME) final Collection<Threshold> thresholds) {
|
||||
|
||||
this.id = id;
|
||||
this.institutionId = institutionId;
|
||||
this.examId = examId;
|
||||
this.examOwner = examOwner;
|
||||
this.name = name;
|
||||
this.type = type;
|
||||
this.defaultColor = defaultColor;
|
||||
|
@ -89,9 +77,7 @@ public final class Indicator implements GrantEntity {
|
|||
|
||||
public Indicator(final Exam exam, final POSTMapper postParams) {
|
||||
this.id = null;
|
||||
this.institutionId = exam.institutionId;
|
||||
this.examId = exam.id;
|
||||
this.examOwner = exam.owner;
|
||||
this.name = postParams.getString(Domain.INDICATOR.ATTR_NAME);
|
||||
this.type = postParams.getEnum(Domain.INDICATOR.ATTR_TYPE, IndicatorType.class);
|
||||
this.defaultColor = postParams.getString(Domain.INDICATOR.ATTR_COLOR);
|
||||
|
@ -117,17 +103,6 @@ public final class Indicator implements GrantEntity {
|
|||
return this.id;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
public Long getInstitutionId() {
|
||||
return this.institutionId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getOwnerId() {
|
||||
return this.examOwner;
|
||||
}
|
||||
|
||||
public Long getExamId() {
|
||||
return this.examId;
|
||||
}
|
||||
|
@ -151,8 +126,8 @@ public final class Indicator implements GrantEntity {
|
|||
+ this.defaultColor + ", thresholds=" + this.thresholds + "]";
|
||||
}
|
||||
|
||||
public static Indicator createNew(final Long institutionId, final Exam exam) {
|
||||
return new Indicator(null, institutionId, exam.id, exam.owner, null, null, null, null);
|
||||
public static Indicator createNew(final Exam exam) {
|
||||
return new Indicator(null, exam.id, null, null, null, null);
|
||||
}
|
||||
|
||||
public static final class Threshold {
|
||||
|
|
|
@ -16,6 +16,8 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
|||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.api.EntityType;
|
||||
import ch.ethz.seb.sebserver.gbl.api.POSTMapper;
|
||||
import ch.ethz.seb.sebserver.gbl.model.Domain;
|
||||
import ch.ethz.seb.sebserver.gbl.model.Domain.CONFIGURATION_ATTRIBUTE;
|
||||
import ch.ethz.seb.sebserver.gbl.model.Entity;
|
||||
|
||||
|
@ -73,6 +75,17 @@ public final class ConfigurationAttribute implements Entity {
|
|||
this.defaultValue = defaultValue;
|
||||
}
|
||||
|
||||
public ConfigurationAttribute(final POSTMapper postParams) {
|
||||
this.id = null;
|
||||
this.parentId = postParams.getLong(Domain.CONFIGURATION_ATTRIBUTE.ATTR_PARENT_ID);
|
||||
this.name = postParams.getString(Domain.CONFIGURATION_ATTRIBUTE.ATTR_NAME);
|
||||
this.type = postParams.getEnum(Domain.CONFIGURATION_ATTRIBUTE.ATTR_TYPE, AttributeType.class);
|
||||
this.resources = postParams.getString(Domain.CONFIGURATION_ATTRIBUTE.ATTR_RESOURCES);
|
||||
this.validator = postParams.getString(Domain.CONFIGURATION_ATTRIBUTE.ATTR_VALIDATOR);
|
||||
this.dependencies = postParams.getString(Domain.CONFIGURATION_ATTRIBUTE.ATTR_DEPENDENCIES);
|
||||
this.defaultValue = postParams.getString(Domain.CONFIGURATION_ATTRIBUTE.ATTR_DEFAULT_VALUE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getModelId() {
|
||||
return (this.id != null)
|
||||
|
|
|
@ -15,6 +15,8 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
|||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.api.EntityType;
|
||||
import ch.ethz.seb.sebserver.gbl.api.POSTMapper;
|
||||
import ch.ethz.seb.sebserver.gbl.model.Domain;
|
||||
import ch.ethz.seb.sebserver.gbl.model.Domain.ORIENTATION;
|
||||
import ch.ethz.seb.sebserver.gbl.model.Entity;
|
||||
|
||||
|
@ -76,6 +78,18 @@ public final class Orientation implements Entity {
|
|||
this.height = height;
|
||||
}
|
||||
|
||||
public Orientation(final ConfigurationAttribute attr, final POSTMapper postParams) {
|
||||
this.id = null;
|
||||
this.attributeId = attr.id;
|
||||
this.template = postParams.getString(Domain.ORIENTATION.ATTR_TEMPLATE);
|
||||
this.view = postParams.getString(Domain.ORIENTATION.ATTR_VIEW);
|
||||
this.group = postParams.getString(Domain.ORIENTATION.ATTR_GROUP);
|
||||
this.xPosition = postParams.getInteger(Domain.ORIENTATION.ATTR_X_POSITION);
|
||||
this.yPosition = postParams.getInteger(Domain.ORIENTATION.ATTR_Y_POSITION);
|
||||
this.width = postParams.getInteger(Domain.ORIENTATION.ATTR_WIDTH);
|
||||
this.height = postParams.getInteger(Domain.ORIENTATION.ATTR_HEIGHT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getModelId() {
|
||||
return (this.id != null)
|
||||
|
|
|
@ -81,7 +81,7 @@ public class IndicatorForm implements TemplateComposer {
|
|||
|
||||
// get data or create new. Handle error if happen
|
||||
final Indicator indicator = (isNew)
|
||||
? Indicator.createNew(exam.getInstitutionId(), exam)
|
||||
? Indicator.createNew(exam)
|
||||
: restService
|
||||
.getBuilder(GetIndicator.class)
|
||||
.withURIVariable(API.PARAM_MODEL_ID, entityKey.modelId)
|
||||
|
|
|
@ -105,20 +105,42 @@ public class AuthorizationServiceImpl implements AuthorizationService {
|
|||
.withInstitutionalPrivilege(PrivilegeType.READ)
|
||||
.andForRole(UserRole.EXAM_ADMIN)
|
||||
.withInstitutionalPrivilege(PrivilegeType.WRITE)
|
||||
.withOwnerPrivilege(PrivilegeType.WRITE)
|
||||
.andForRole(UserRole.EXAM_SUPPORTER)
|
||||
.withInstitutionalPrivilege(PrivilegeType.READ)
|
||||
.create();
|
||||
|
||||
// grants for indicators
|
||||
addPrivilege(EntityType.INDICATOR)
|
||||
// grants for configuration node
|
||||
addPrivilege(EntityType.CONFIGURATION_NODE)
|
||||
.forRole(UserRole.SEB_SERVER_ADMIN)
|
||||
.withBasePrivilege(PrivilegeType.READ)
|
||||
.andForRole(UserRole.INSTITUTIONAL_ADMIN)
|
||||
.withInstitutionalPrivilege(PrivilegeType.READ)
|
||||
.andForRole(UserRole.EXAM_ADMIN)
|
||||
.withInstitutionalPrivilege(PrivilegeType.WRITE)
|
||||
.withOwnerPrivilege(PrivilegeType.WRITE)
|
||||
.andForRole(UserRole.EXAM_SUPPORTER)
|
||||
.withInstitutionalPrivilege(PrivilegeType.MODIFY)
|
||||
.create();
|
||||
|
||||
// grants for configuration attributes
|
||||
addPrivilege(EntityType.CONFIGURATION_ATTRIBUTE)
|
||||
.forRole(UserRole.SEB_SERVER_ADMIN)
|
||||
.withBasePrivilege(PrivilegeType.WRITE)
|
||||
.andForRole(UserRole.INSTITUTIONAL_ADMIN)
|
||||
.withInstitutionalPrivilege(PrivilegeType.READ)
|
||||
.andForRole(UserRole.EXAM_ADMIN)
|
||||
.withInstitutionalPrivilege(PrivilegeType.READ)
|
||||
.andForRole(UserRole.EXAM_SUPPORTER)
|
||||
.withInstitutionalPrivilege(PrivilegeType.READ)
|
||||
.create();
|
||||
|
||||
// grants for configuration orientations
|
||||
addPrivilege(EntityType.ORIENTATION)
|
||||
.forRole(UserRole.SEB_SERVER_ADMIN)
|
||||
.withBasePrivilege(PrivilegeType.WRITE)
|
||||
.andForRole(UserRole.INSTITUTIONAL_ADMIN)
|
||||
.withInstitutionalPrivilege(PrivilegeType.READ)
|
||||
.andForRole(UserRole.EXAM_ADMIN)
|
||||
.withInstitutionalPrivilege(PrivilegeType.READ)
|
||||
.andForRole(UserRole.EXAM_SUPPORTER)
|
||||
.withInstitutionalPrivilege(PrivilegeType.READ)
|
||||
.create();
|
||||
|
|
|
@ -34,12 +34,10 @@ import ch.ethz.seb.sebserver.gbl.model.exam.Indicator.Threshold;
|
|||
import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
|
||||
import ch.ethz.seb.sebserver.gbl.util.Result;
|
||||
import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.ExamRecordDynamicSqlSupport;
|
||||
import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.ExamRecordMapper;
|
||||
import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.IndicatorRecordDynamicSqlSupport;
|
||||
import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.IndicatorRecordMapper;
|
||||
import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.ThresholdRecordDynamicSqlSupport;
|
||||
import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.ThresholdRecordMapper;
|
||||
import ch.ethz.seb.sebserver.webservice.datalayer.batis.model.ExamRecord;
|
||||
import ch.ethz.seb.sebserver.webservice.datalayer.batis.model.IndicatorRecord;
|
||||
import ch.ethz.seb.sebserver.webservice.datalayer.batis.model.ThresholdRecord;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.BulkAction;
|
||||
|
@ -56,16 +54,13 @@ public class IndicatorDAOImpl implements IndicatorDAO {
|
|||
|
||||
private final IndicatorRecordMapper indicatorRecordMapper;
|
||||
private final ThresholdRecordMapper thresholdRecordMapper;
|
||||
private final ExamRecordMapper examRecordMapper;
|
||||
|
||||
public IndicatorDAOImpl(
|
||||
final IndicatorRecordMapper indicatorRecordMapper,
|
||||
final ThresholdRecordMapper thresholdRecordMapper,
|
||||
final ExamRecordMapper examRecordMapper) {
|
||||
final ThresholdRecordMapper thresholdRecordMapper) {
|
||||
|
||||
this.indicatorRecordMapper = indicatorRecordMapper;
|
||||
this.thresholdRecordMapper = thresholdRecordMapper;
|
||||
this.examRecordMapper = examRecordMapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -175,6 +170,7 @@ public class IndicatorDAOImpl implements IndicatorDAO {
|
|||
// insert thresholds
|
||||
modified.thresholds
|
||||
.stream()
|
||||
.filter(threshold -> threshold.value != null && threshold.color != null)
|
||||
.map(threshold -> new ThresholdRecord(
|
||||
null,
|
||||
newRecord.getId(),
|
||||
|
@ -321,8 +317,6 @@ public class IndicatorDAOImpl implements IndicatorDAO {
|
|||
private Result<Indicator> toDomainModel(final IndicatorRecord record) {
|
||||
return Result.tryCatch(() -> {
|
||||
|
||||
final ExamRecord examRecord = this.examRecordMapper.selectByPrimaryKey(record.getExamId());
|
||||
|
||||
final List<Threshold> thresholds = this.thresholdRecordMapper.selectByExample()
|
||||
.where(ThresholdRecordDynamicSqlSupport.indicatorId, isEqualTo(record.getId()))
|
||||
.build()
|
||||
|
@ -335,9 +329,7 @@ public class IndicatorDAOImpl implements IndicatorDAO {
|
|||
|
||||
return new Indicator(
|
||||
record.getId(),
|
||||
examRecord.getInstitutionId(),
|
||||
record.getExamId(),
|
||||
examRecord.getOwner(),
|
||||
record.getName(),
|
||||
IndicatorType.valueOf(record.getType()),
|
||||
record.getColor(),
|
||||
|
|
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
* 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.weblayer.api;
|
||||
|
||||
import org.mybatis.dynamic.sql.SqlTable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.api.API;
|
||||
import ch.ethz.seb.sebserver.gbl.api.POSTMapper;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationAttribute;
|
||||
import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
|
||||
import ch.ethz.seb.sebserver.gbl.util.Result;
|
||||
import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.ConfigurationAttributeRecordDynamicSqlSupport;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.PaginationService;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.AuthorizationService;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.GrantEntity;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.BulkActionService;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ConfigurationAttributeDAO;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.UserActivityLogDAO;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.validation.BeanValidationService;
|
||||
|
||||
@WebServiceProfile
|
||||
@RestController
|
||||
@RequestMapping("/${sebserver.webservice.api.admin.endpoint}" + API.CONFIGURATION_ATTRIBUTE_ENDPOINT)
|
||||
public class ConfigurationAttributeController extends EntityController<ConfigurationAttribute, ConfigurationAttribute> {
|
||||
|
||||
protected ConfigurationAttributeController(
|
||||
final AuthorizationService authorization,
|
||||
final BulkActionService bulkActionService,
|
||||
final ConfigurationAttributeDAO entityDAO,
|
||||
final UserActivityLogDAO userActivityLogDAO,
|
||||
final PaginationService paginationService,
|
||||
final BeanValidationService beanValidationService) {
|
||||
|
||||
super(authorization,
|
||||
bulkActionService,
|
||||
entityDAO,
|
||||
userActivityLogDAO,
|
||||
paginationService,
|
||||
beanValidationService);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ConfigurationAttribute createNew(final POSTMapper postParams) {
|
||||
// TODO Auto-generated method stub
|
||||
return new ConfigurationAttribute(postParams);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SqlTable getSQLTableOfEntity() {
|
||||
return ConfigurationAttributeRecordDynamicSqlSupport.configurationAttributeRecord;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Result<ConfigurationAttribute> checkCreateAccess(final ConfigurationAttribute entity) {
|
||||
return Result.of(entity); // Skips the entity based grant check
|
||||
}
|
||||
|
||||
@Override
|
||||
protected GrantEntity toGrantEntity(final ConfigurationAttribute entity) {
|
||||
return null; // Skips the entity based grant check
|
||||
}
|
||||
|
||||
}
|
|
@ -135,7 +135,7 @@ public abstract class EntityController<T extends Entity, M extends Entity> {
|
|||
|
||||
// if current user has no read access for specified entity type within other institution
|
||||
// then the current users institutionId is put as a SQL filter criteria attribute to extends query performance
|
||||
if (!this.authorization.hasGrant(PrivilegeType.READ, this.entityDAO.entityType())) {
|
||||
if (!this.authorization.hasGrant(PrivilegeType.READ, getGrantEntityType())) {
|
||||
filterMap.putIfAbsent(API.PARAM_INSTITUTION_ID, String.valueOf(institutionId));
|
||||
}
|
||||
|
||||
|
@ -170,7 +170,7 @@ public abstract class EntityController<T extends Entity, M extends Entity> {
|
|||
|
||||
// if current user has no read access for specified entity type within other institution then its own institution,
|
||||
// then the current users institutionId is put as a SQL filter criteria attribute to extends query performance
|
||||
if (!this.authorization.hasGrant(PrivilegeType.READ, this.entityDAO.entityType())) {
|
||||
if (!this.authorization.hasGrant(PrivilegeType.READ, this.getGrantEntityType())) {
|
||||
filterMap.putIfAbsent(API.PARAM_INSTITUTION_ID, String.valueOf(institutionId));
|
||||
}
|
||||
|
||||
|
@ -266,10 +266,7 @@ public abstract class EntityController<T extends Entity, M extends Entity> {
|
|||
defaultValue = UserService.USERS_INSTITUTION_AS_DEFAULT) final Long institutionId) {
|
||||
|
||||
// check modify privilege for requested institution and concrete entityType
|
||||
this.authorization.check(
|
||||
PrivilegeType.MODIFY,
|
||||
this.entityDAO.entityType(),
|
||||
institutionId);
|
||||
this.checkModifyPrivilege(institutionId);
|
||||
|
||||
final POSTMapper postMap = new POSTMapper(allRequestParams)
|
||||
.putIfAbsent(API.PARAM_INSTITUTION_ID, String.valueOf(institutionId));
|
||||
|
@ -323,10 +320,23 @@ public abstract class EntityController<T extends Entity, M extends Entity> {
|
|||
.getOrThrow();
|
||||
}
|
||||
|
||||
protected void checkReadPrivilege() {
|
||||
this.authorization.check(
|
||||
PrivilegeType.READ,
|
||||
getGrantEntityType());
|
||||
}
|
||||
|
||||
protected void checkReadPrivilege(final Long institutionId) {
|
||||
this.authorization.check(
|
||||
PrivilegeType.READ,
|
||||
this.entityDAO.entityType(),
|
||||
getGrantEntityType(),
|
||||
institutionId);
|
||||
}
|
||||
|
||||
protected void checkModifyPrivilege(final Long institutionId) {
|
||||
this.authorization.check(
|
||||
PrivilegeType.MODIFY,
|
||||
getGrantEntityType(),
|
||||
institutionId);
|
||||
}
|
||||
|
||||
|
@ -361,7 +371,7 @@ public abstract class EntityController<T extends Entity, M extends Entity> {
|
|||
return Result.of(entity);
|
||||
}
|
||||
|
||||
private Result<T> checkReadAccess(final T entity) {
|
||||
protected Result<T> checkReadAccess(final T entity) {
|
||||
final GrantEntity grantEntity = toGrantEntity(entity);
|
||||
if (grantEntity != null) {
|
||||
this.authorization.checkRead(grantEntity);
|
||||
|
@ -369,7 +379,7 @@ public abstract class EntityController<T extends Entity, M extends Entity> {
|
|||
return Result.of(entity);
|
||||
}
|
||||
|
||||
private boolean hasReadAccess(final T entity) {
|
||||
protected boolean hasReadAccess(final T entity) {
|
||||
final GrantEntity grantEntity = toGrantEntity(entity);
|
||||
if (grantEntity != null) {
|
||||
return this.authorization.hasReadonlyGrant(grantEntity);
|
||||
|
@ -378,7 +388,7 @@ public abstract class EntityController<T extends Entity, M extends Entity> {
|
|||
return true;
|
||||
}
|
||||
|
||||
private Result<T> checkModifyAccess(final T entity) {
|
||||
protected Result<T> checkModifyAccess(final T entity) {
|
||||
final GrantEntity grantEntity = toGrantEntity(entity);
|
||||
if (grantEntity != null) {
|
||||
this.authorization.checkModify(grantEntity);
|
||||
|
@ -386,7 +396,7 @@ public abstract class EntityController<T extends Entity, M extends Entity> {
|
|||
return Result.of(entity);
|
||||
}
|
||||
|
||||
private Result<T> checkWriteAccess(final T entity) {
|
||||
protected Result<T> checkWriteAccess(final T entity) {
|
||||
final GrantEntity grantEntity = toGrantEntity(entity);
|
||||
if (grantEntity != null) {
|
||||
this.authorization.checkWrite(grantEntity);
|
||||
|
@ -394,15 +404,37 @@ public abstract class EntityController<T extends Entity, M extends Entity> {
|
|||
return Result.of(entity);
|
||||
}
|
||||
|
||||
private Result<M> checkCreateAccess(final M entity) {
|
||||
final GrantEntity grantEntity = toGrantEntity(entity);
|
||||
if (grantEntity != null) {
|
||||
this.authorization.checkWrite(grantEntity);
|
||||
/** Checks creation (write) privileges for a given Entity.
|
||||
* Usually the GrantEntity and the Entity instance are the same if the Entity extends from GrantEntity.
|
||||
* Otherwise the implementing EntityController must override this method and resolve the
|
||||
* related GrantEntity for a given Entity.
|
||||
* For example, the GrantEntity of Indicator is the related Exam
|
||||
*
|
||||
* @param entity the Entity to check creation/write access for
|
||||
* @return Result of the access check containing either the original entity or an error if no access granted */
|
||||
protected Result<M> checkCreateAccess(final M entity) {
|
||||
if (entity instanceof GrantEntity) {
|
||||
this.authorization.checkWrite((GrantEntity) entity);
|
||||
return Result.of(entity);
|
||||
}
|
||||
return Result.of(entity);
|
||||
|
||||
return Result.ofError(new IllegalArgumentException("Entity instance is not of type GrantEntity. "
|
||||
+ "Do override the checkCreateAccess method from EntityController within the specific -Controller implementation"));
|
||||
}
|
||||
|
||||
protected GrantEntity toGrantEntity(final Entity entity) {
|
||||
/** Gets the GrantEntity instance for a given Entity instance.
|
||||
* Usually the GrantEntity and the Entity instance are the same if the Entity extends from GrantEntity.
|
||||
* Otherwise the implementing EntityController must override this method and resolve the
|
||||
* related GrantEntity for a given Entity.
|
||||
* For example, the GrantEntity of Indicator is the related Exam
|
||||
*
|
||||
* @param entity the Entity to get the related GrantEntity for
|
||||
* @return the GrantEntity instance for a given Entity instance */
|
||||
protected GrantEntity toGrantEntity(final T entity) {
|
||||
if (entity == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (entity instanceof GrantEntity) {
|
||||
return (GrantEntity) entity;
|
||||
}
|
||||
|
@ -411,8 +443,25 @@ public abstract class EntityController<T extends Entity, M extends Entity> {
|
|||
+ "Do override the toGrantEntity method from EntityController within the specific -Controller implementation");
|
||||
}
|
||||
|
||||
/** Get the EntityType of the GrantEntity that is used for grant checks of the concrete Entity.
|
||||
*
|
||||
* NOTE: override this if the EntityType of the GrantEntity is not the same as the Entity itself.
|
||||
* For example, the Exam is the GrantEntity of a Indicator
|
||||
*
|
||||
* @return the EntityType of the GrantEntity that is used for grant checks of the concrete Entity */
|
||||
protected EntityType getGrantEntityType() {
|
||||
return this.entityDAO.entityType();
|
||||
}
|
||||
|
||||
/** Implements the creation of a new entity from the post parameters given within the POSTMapper
|
||||
*
|
||||
* @param postParams contains all post parameter from request
|
||||
* @return new created Entity instance */
|
||||
protected abstract M createNew(POSTMapper postParams);
|
||||
|
||||
/** Gets the MyBatis SqlTable for the concrete Entity
|
||||
*
|
||||
* @return the MyBatis SqlTable for the concrete Entity */
|
||||
protected abstract SqlTable getSQLTableOfEntity();
|
||||
|
||||
}
|
||||
|
|
|
@ -13,13 +13,16 @@ import org.springframework.web.bind.annotation.RequestMapping;
|
|||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.api.API;
|
||||
import ch.ethz.seb.sebserver.gbl.api.EntityType;
|
||||
import ch.ethz.seb.sebserver.gbl.api.POSTMapper;
|
||||
import ch.ethz.seb.sebserver.gbl.model.Domain;
|
||||
import ch.ethz.seb.sebserver.gbl.model.exam.Indicator;
|
||||
import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
|
||||
import ch.ethz.seb.sebserver.gbl.util.Result;
|
||||
import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.IndicatorRecordDynamicSqlSupport;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.PaginationService;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.AuthorizationService;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.GrantEntity;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.BulkActionService;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ExamDAO;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.IndicatorDAO;
|
||||
|
@ -67,4 +70,29 @@ public class IndicatorController extends EntityController<Indicator, Indicator>
|
|||
return IndicatorRecordDynamicSqlSupport.indicatorRecord;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Result<Indicator> checkCreateAccess(final Indicator entity) {
|
||||
if (entity == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
this.authorization.checkWrite(this.examDao.byPK(entity.examId).getOrThrow());
|
||||
return Result.of(entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected GrantEntity toGrantEntity(final Indicator entity) {
|
||||
if (entity == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return this.examDao.byPK(entity.examId)
|
||||
.getOrThrow();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected EntityType getGrantEntityType() {
|
||||
return EntityType.EXAM;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
* 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.weblayer.api;
|
||||
|
||||
import org.mybatis.dynamic.sql.SqlTable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.api.API;
|
||||
import ch.ethz.seb.sebserver.gbl.api.POSTMapper;
|
||||
import ch.ethz.seb.sebserver.gbl.model.Domain;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.Orientation;
|
||||
import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
|
||||
import ch.ethz.seb.sebserver.gbl.util.Result;
|
||||
import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.OrientationRecordDynamicSqlSupport;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.PaginationService;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.AuthorizationService;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.GrantEntity;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.BulkActionService;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ConfigurationAttributeDAO;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.OrientationDAO;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.UserActivityLogDAO;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.validation.BeanValidationService;
|
||||
|
||||
@WebServiceProfile
|
||||
@RestController
|
||||
@RequestMapping("/${sebserver.webservice.api.admin.endpoint}" + API.ORIENTATION_ENDPOINT)
|
||||
public class OrientationController extends EntityController<Orientation, Orientation> {
|
||||
|
||||
private final ConfigurationAttributeDAO configurationAttributeDAO;
|
||||
|
||||
protected OrientationController(
|
||||
final AuthorizationService authorization,
|
||||
final BulkActionService bulkActionService,
|
||||
final OrientationDAO entityDAO,
|
||||
final ConfigurationAttributeDAO configurationAttributeDAO,
|
||||
final UserActivityLogDAO userActivityLogDAO,
|
||||
final PaginationService paginationService,
|
||||
final BeanValidationService beanValidationService) {
|
||||
|
||||
super(authorization,
|
||||
bulkActionService,
|
||||
entityDAO,
|
||||
userActivityLogDAO,
|
||||
paginationService,
|
||||
beanValidationService);
|
||||
|
||||
this.configurationAttributeDAO = configurationAttributeDAO;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Orientation createNew(final POSTMapper postParams) {
|
||||
final Long attributeId = postParams.getLong(Domain.ORIENTATION.ATTR_CONFIG_ATTRIBUTE_ID);
|
||||
|
||||
return this.configurationAttributeDAO
|
||||
.byPK(attributeId)
|
||||
.map(attr -> new Orientation(attr, postParams))
|
||||
.getOrThrow();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SqlTable getSQLTableOfEntity() {
|
||||
return OrientationRecordDynamicSqlSupport.orientationRecord;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Result<Orientation> checkCreateAccess(final Orientation entity) {
|
||||
// Skips the entity based grant check
|
||||
return Result.of(entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected GrantEntity toGrantEntity(final Orientation entity) {
|
||||
// Skips the entity based grant check
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
|
@ -180,10 +180,16 @@ CREATE TABLE IF NOT EXISTS `configuration` (
|
|||
`version_date` DATETIME NULL,
|
||||
`followup` INT(1) NOT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
INDEX `configurationNodeRef_idx` (`configuration_node_id` ASC, `institution_id` ASC),
|
||||
CONSTRAINT `configurationNodeRef`
|
||||
FOREIGN KEY (`configuration_node_id` , `institution_id`)
|
||||
REFERENCES `configuration_node` (`id` , `institution_id`)
|
||||
INDEX `configurationNodeRef_idx` (`configuration_node_id` ASC),
|
||||
INDEX `config_institution_ref_idx` (`institution_id` ASC),
|
||||
CONSTRAINT `configuration_node_ref`
|
||||
FOREIGN KEY (`configuration_node_id`)
|
||||
REFERENCES `configuration_node` (`id`)
|
||||
ON DELETE NO ACTION
|
||||
ON UPDATE NO ACTION,
|
||||
CONSTRAINT `config_institution_ref`
|
||||
FOREIGN KEY (`institution_id`)
|
||||
REFERENCES `institution` (`id`)
|
||||
ON DELETE NO ACTION
|
||||
ON UPDATE NO ACTION)
|
||||
;
|
||||
|
@ -227,17 +233,23 @@ CREATE TABLE IF NOT EXISTS `configuration_value` (
|
|||
`value` VARCHAR(255) NULL,
|
||||
`text` MEDIUMTEXT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
INDEX `configuration_value_ref_idx` (`configuration_id` ASC, `institution_id` ASC),
|
||||
INDEX `configuration_value_ref_idx` (`configuration_id` ASC),
|
||||
INDEX `configuration_attribute_ref_idx` (`configuration_attribute_id` ASC),
|
||||
INDEX `configuration_value_institution_ref_idx` (`institution_id` ASC),
|
||||
CONSTRAINT `configuration_ref`
|
||||
FOREIGN KEY (`configuration_id` , `institution_id`)
|
||||
REFERENCES `configuration` (`id` , `institution_id`)
|
||||
FOREIGN KEY (`configuration_id`)
|
||||
REFERENCES `configuration` (`id`)
|
||||
ON DELETE NO ACTION
|
||||
ON UPDATE NO ACTION,
|
||||
CONSTRAINT `configuration_value_attribute_ref`
|
||||
FOREIGN KEY (`configuration_attribute_id`)
|
||||
REFERENCES `configuration_attribute` (`id`)
|
||||
ON DELETE NO ACTION
|
||||
ON UPDATE NO ACTION,
|
||||
CONSTRAINT `configuration_value_institution_ref`
|
||||
FOREIGN KEY (`institution_id`)
|
||||
REFERENCES `institution` (`id`)
|
||||
ON DELETE NO ACTION
|
||||
ON UPDATE NO ACTION)
|
||||
;
|
||||
|
||||
|
@ -279,16 +291,22 @@ CREATE TABLE IF NOT EXISTS `exam_configuration_map` (
|
|||
`configuration_node_id` BIGINT UNSIGNED NOT NULL,
|
||||
`user_names` VARCHAR(4000) NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
INDEX `exam_ref_idx` (`exam_id` ASC, `institution_id` ASC),
|
||||
INDEX `configuration_map_ref_idx` (`configuration_node_id` ASC, `institution_id` ASC),
|
||||
INDEX `exam_ref_idx` (`exam_id` ASC),
|
||||
INDEX `configuration_map_ref_idx` (`configuration_node_id` ASC),
|
||||
INDEX `exam_config_institution_ref_idx` (`institution_id` ASC),
|
||||
CONSTRAINT `exam_map_ref`
|
||||
FOREIGN KEY (`exam_id` , `institution_id`)
|
||||
REFERENCES `exam` (`id` , `institution_id`)
|
||||
FOREIGN KEY (`exam_id`)
|
||||
REFERENCES `exam` (`id`)
|
||||
ON DELETE NO ACTION
|
||||
ON UPDATE NO ACTION,
|
||||
CONSTRAINT `configuration_map_ref`
|
||||
FOREIGN KEY (`configuration_node_id` , `institution_id`)
|
||||
REFERENCES `configuration_node` (`id` , `institution_id`)
|
||||
FOREIGN KEY (`configuration_node_id`)
|
||||
REFERENCES `configuration_node` (`id`)
|
||||
ON DELETE NO ACTION
|
||||
ON UPDATE NO ACTION,
|
||||
CONSTRAINT `exam_config_institution_ref`
|
||||
FOREIGN KEY (`institution_id`)
|
||||
REFERENCES `institution` (`id`)
|
||||
ON DELETE NO ACTION
|
||||
ON UPDATE NO ACTION)
|
||||
;
|
||||
|
|
|
@ -185,10 +185,16 @@ CREATE TABLE IF NOT EXISTS `configuration` (
|
|||
`version_date` DATETIME NULL,
|
||||
`followup` INT(1) NOT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
INDEX `configurationNodeRef_idx` (`configuration_node_id` ASC, `institution_id` ASC),
|
||||
CONSTRAINT `configurationNodeRef`
|
||||
FOREIGN KEY (`configuration_node_id` , `institution_id`)
|
||||
REFERENCES `configuration_node` (`id` , `institution_id`)
|
||||
INDEX `configurationNodeRef_idx` (`configuration_node_id` ASC),
|
||||
INDEX `config_institution_ref_idx` (`institution_id` ASC),
|
||||
CONSTRAINT `configuration_node_ref`
|
||||
FOREIGN KEY (`configuration_node_id`)
|
||||
REFERENCES `configuration_node` (`id`)
|
||||
ON DELETE NO ACTION
|
||||
ON UPDATE NO ACTION,
|
||||
CONSTRAINT `config_institution_ref`
|
||||
FOREIGN KEY (`institution_id`)
|
||||
REFERENCES `institution` (`id`)
|
||||
ON DELETE NO ACTION
|
||||
ON UPDATE NO ACTION)
|
||||
;
|
||||
|
@ -232,17 +238,23 @@ CREATE TABLE IF NOT EXISTS `configuration_value` (
|
|||
`value` VARCHAR(255) NULL,
|
||||
`text` MEDIUMTEXT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
INDEX `configuration_value_ref_idx` (`configuration_id` ASC, `institution_id` ASC),
|
||||
INDEX `configuration_value_ref_idx` (`configuration_id` ASC),
|
||||
INDEX `configuration_attribute_ref_idx` (`configuration_attribute_id` ASC),
|
||||
INDEX `configuration_value_institution_ref_idx` (`institution_id` ASC),
|
||||
CONSTRAINT `configuration_ref`
|
||||
FOREIGN KEY (`configuration_id` , `institution_id`)
|
||||
REFERENCES `configuration` (`id` , `institution_id`)
|
||||
FOREIGN KEY (`configuration_id`)
|
||||
REFERENCES `configuration` (`id`)
|
||||
ON DELETE NO ACTION
|
||||
ON UPDATE NO ACTION,
|
||||
CONSTRAINT `configuration_value_attribute_ref`
|
||||
FOREIGN KEY (`configuration_attribute_id`)
|
||||
REFERENCES `configuration_attribute` (`id`)
|
||||
ON DELETE NO ACTION
|
||||
ON UPDATE NO ACTION,
|
||||
CONSTRAINT `configuration_value_institution_ref`
|
||||
FOREIGN KEY (`institution_id`)
|
||||
REFERENCES `institution` (`id`)
|
||||
ON DELETE NO ACTION
|
||||
ON UPDATE NO ACTION)
|
||||
;
|
||||
|
||||
|
@ -284,16 +296,22 @@ CREATE TABLE IF NOT EXISTS `exam_configuration_map` (
|
|||
`configuration_node_id` BIGINT UNSIGNED NOT NULL,
|
||||
`user_names` VARCHAR(4000) NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
INDEX `exam_ref_idx` (`exam_id` ASC, `institution_id` ASC),
|
||||
INDEX `configuration_map_ref_idx` (`configuration_node_id` ASC, `institution_id` ASC),
|
||||
INDEX `exam_ref_idx` (`exam_id` ASC),
|
||||
INDEX `configuration_map_ref_idx` (`configuration_node_id` ASC),
|
||||
INDEX `exam_config_institution_ref_idx` (`institution_id` ASC),
|
||||
CONSTRAINT `exam_map_ref`
|
||||
FOREIGN KEY (`exam_id` , `institution_id`)
|
||||
REFERENCES `exam` (`id` , `institution_id`)
|
||||
FOREIGN KEY (`exam_id`)
|
||||
REFERENCES `exam` (`id`)
|
||||
ON DELETE NO ACTION
|
||||
ON UPDATE NO ACTION,
|
||||
CONSTRAINT `configuration_map_ref`
|
||||
FOREIGN KEY (`configuration_node_id` , `institution_id`)
|
||||
REFERENCES `configuration_node` (`id` , `institution_id`)
|
||||
FOREIGN KEY (`configuration_node_id`)
|
||||
REFERENCES `configuration_node` (`id`)
|
||||
ON DELETE NO ACTION
|
||||
ON UPDATE NO ACTION,
|
||||
CONSTRAINT `exam_config_institution_ref`
|
||||
FOREIGN KEY (`institution_id`)
|
||||
REFERENCES `institution` (`id`)
|
||||
ON DELETE NO ACTION
|
||||
ON UPDATE NO ACTION)
|
||||
;
|
||||
|
|
|
@ -180,10 +180,16 @@ CREATE TABLE IF NOT EXISTS `configuration` (
|
|||
`version_date` DATETIME NULL,
|
||||
`followup` INT(1) NOT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
INDEX `configurationNodeRef_idx` (`configuration_node_id` ASC, `institution_id` ASC),
|
||||
CONSTRAINT `configurationNodeRef`
|
||||
FOREIGN KEY (`configuration_node_id` , `institution_id`)
|
||||
REFERENCES `configuration_node` (`id` , `institution_id`)
|
||||
INDEX `configurationNodeRef_idx` (`configuration_node_id` ASC),
|
||||
INDEX `config_institution_ref_idx` (`institution_id` ASC),
|
||||
CONSTRAINT `configuration_node_ref`
|
||||
FOREIGN KEY (`configuration_node_id`)
|
||||
REFERENCES `configuration_node` (`id`)
|
||||
ON DELETE NO ACTION
|
||||
ON UPDATE NO ACTION,
|
||||
CONSTRAINT `config_institution_ref`
|
||||
FOREIGN KEY (`institution_id`)
|
||||
REFERENCES `institution` (`id`)
|
||||
ON DELETE NO ACTION
|
||||
ON UPDATE NO ACTION)
|
||||
;
|
||||
|
@ -227,17 +233,23 @@ CREATE TABLE IF NOT EXISTS `configuration_value` (
|
|||
`value` VARCHAR(255) NULL,
|
||||
`text` MEDIUMTEXT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
INDEX `configuration_value_ref_idx` (`configuration_id` ASC, `institution_id` ASC),
|
||||
INDEX `configuration_value_ref_idx` (`configuration_id` ASC),
|
||||
INDEX `configuration_attribute_ref_idx` (`configuration_attribute_id` ASC),
|
||||
INDEX `configuration_value_institution_ref_idx` (`institution_id` ASC),
|
||||
CONSTRAINT `configuration_ref`
|
||||
FOREIGN KEY (`configuration_id` , `institution_id`)
|
||||
REFERENCES `configuration` (`id` , `institution_id`)
|
||||
FOREIGN KEY (`configuration_id`)
|
||||
REFERENCES `configuration` (`id`)
|
||||
ON DELETE NO ACTION
|
||||
ON UPDATE NO ACTION,
|
||||
CONSTRAINT `configuration_value_attribute_ref`
|
||||
FOREIGN KEY (`configuration_attribute_id`)
|
||||
REFERENCES `configuration_attribute` (`id`)
|
||||
ON DELETE NO ACTION
|
||||
ON UPDATE NO ACTION,
|
||||
CONSTRAINT `configuration_value_institution_ref`
|
||||
FOREIGN KEY (`institution_id`)
|
||||
REFERENCES `institution` (`id`)
|
||||
ON DELETE NO ACTION
|
||||
ON UPDATE NO ACTION)
|
||||
;
|
||||
|
||||
|
@ -279,16 +291,22 @@ CREATE TABLE IF NOT EXISTS `exam_configuration_map` (
|
|||
`configuration_node_id` BIGINT UNSIGNED NOT NULL,
|
||||
`user_names` VARCHAR(4000) NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
INDEX `exam_ref_idx` (`exam_id` ASC, `institution_id` ASC),
|
||||
INDEX `configuration_map_ref_idx` (`configuration_node_id` ASC, `institution_id` ASC),
|
||||
INDEX `exam_ref_idx` (`exam_id` ASC),
|
||||
INDEX `configuration_map_ref_idx` (`configuration_node_id` ASC),
|
||||
INDEX `exam_config_institution_ref_idx` (`institution_id` ASC),
|
||||
CONSTRAINT `exam_map_ref`
|
||||
FOREIGN KEY (`exam_id` , `institution_id`)
|
||||
REFERENCES `exam` (`id` , `institution_id`)
|
||||
FOREIGN KEY (`exam_id`)
|
||||
REFERENCES `exam` (`id`)
|
||||
ON DELETE NO ACTION
|
||||
ON UPDATE NO ACTION,
|
||||
CONSTRAINT `configuration_map_ref`
|
||||
FOREIGN KEY (`configuration_node_id` , `institution_id`)
|
||||
REFERENCES `configuration_node` (`id` , `institution_id`)
|
||||
FOREIGN KEY (`configuration_node_id`)
|
||||
REFERENCES `configuration_node` (`id`)
|
||||
ON DELETE NO ACTION
|
||||
ON UPDATE NO ACTION,
|
||||
CONSTRAINT `exam_config_institution_ref`
|
||||
FOREIGN KEY (`institution_id`)
|
||||
REFERENCES `institution` (`id`)
|
||||
ON DELETE NO ACTION
|
||||
ON UPDATE NO ACTION)
|
||||
;
|
||||
|
|
Loading…
Reference in a new issue