SEBSERV-10 back-end implementation
This commit is contained in:
parent
d7f79fb3cc
commit
2a0afe902a
17 changed files with 349 additions and 32 deletions
|
@ -27,6 +27,7 @@ public final class API {
|
|||
public static final String PARAM_PARENT_MODEL_ID = "parentModelId";
|
||||
public static final String PARAM_ENTITY_TYPE = "entityType";
|
||||
public static final String PARAM_BULK_ACTION_TYPE = "bulkActionType";
|
||||
public static final String PARAM_BULK_ACTION_INCLUDES = "bulkActionIncludes";
|
||||
public static final String PARAM_VIEW_ID = "viewId";
|
||||
public static final String PARAM_INSTRUCTION_TYPE = "instructionType";
|
||||
public static final String PARAM_INSTRUCTION_ATTRIBUTES = "instructionAttributes";
|
||||
|
|
|
@ -28,6 +28,8 @@ import ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.impl.BulkAction;
|
|||
* / | \ \
|
||||
* LMS Setup | User-Account Client Configuration
|
||||
* | |
|
||||
* | ______________+______________/
|
||||
* |/ |/
|
||||
* Exam Exam Configuration
|
||||
* |\ /
|
||||
* | Exam Config Mapping
|
||||
|
|
|
@ -11,6 +11,7 @@ package ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.impl;
|
|||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
|
@ -35,6 +36,9 @@ public final class BulkAction {
|
|||
public final EntityType sourceType;
|
||||
/** A Set of EntityKey defining all source-entities of the BulkAction */
|
||||
public final Set<EntityKey> sources;
|
||||
/** A Set defining the types of dependencies to include into the bulk action
|
||||
* Null means all dependencies are included (ignore) and empty means no dependencies are included */
|
||||
public final EnumSet<EntityType> includeDependencies;
|
||||
/** A Set of EntityKey containing collected depending entities during dependency collection and processing phase */
|
||||
final Set<EntityKey> dependencies;
|
||||
/** A Set of EntityKey containing collected bulk action processing results during processing phase */
|
||||
|
@ -46,10 +50,19 @@ public final class BulkAction {
|
|||
final BulkActionType type,
|
||||
final EntityType sourceType,
|
||||
final Collection<EntityKey> sources) {
|
||||
this(type, sourceType, sources, null);
|
||||
}
|
||||
|
||||
public BulkAction(
|
||||
final BulkActionType type,
|
||||
final EntityType sourceType,
|
||||
final Collection<EntityKey> sources,
|
||||
final EnumSet<EntityType> includeDependencies) {
|
||||
|
||||
this.type = type;
|
||||
this.sourceType = sourceType;
|
||||
this.sources = Utils.immutableSetOf(sources);
|
||||
this.includeDependencies = includeDependencies;
|
||||
this.dependencies = new LinkedHashSet<>();
|
||||
this.result = new HashSet<>();
|
||||
|
||||
|
@ -64,6 +77,10 @@ public final class BulkAction {
|
|||
this(type, sourceType, (sources != null) ? Arrays.asList(sources) : Collections.emptyList());
|
||||
}
|
||||
|
||||
public boolean includesDependencyType(final EntityType type) {
|
||||
return this.includeDependencies == null || this.includeDependencies.contains(type);
|
||||
}
|
||||
|
||||
public Set<EntityKey> getDependencies() {
|
||||
return Collections.unmodifiableSet(this.dependencies);
|
||||
}
|
||||
|
|
|
@ -11,6 +11,8 @@ package ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.impl;
|
|||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.EnumMap;
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
@ -37,6 +39,9 @@ import ch.ethz.seb.sebserver.webservice.servicelayer.dao.UserActivityLogDAO;
|
|||
@WebServiceProfile
|
||||
public class BulkActionServiceImpl implements BulkActionService {
|
||||
|
||||
private final EnumMap<EntityType, EnumSet<EntityType>> directDependancyMap =
|
||||
new EnumMap<>(EntityType.class);
|
||||
|
||||
private final Map<EntityType, BulkActionSupportDAO<?>> supporter;
|
||||
private final UserActivityLogDAO userActivityLogDAO;
|
||||
private final ApplicationEventPublisher applicationEventPublisher;
|
||||
|
@ -55,6 +60,20 @@ public class BulkActionServiceImpl implements BulkActionService {
|
|||
this.userActivityLogDAO = userActivityLogDAO;
|
||||
this.applicationEventPublisher = applicationEventPublisher;
|
||||
this.jsonMapper = jsonMapper;
|
||||
|
||||
this.directDependancyMap.put(EntityType.INSTITUTION, EnumSet.of(
|
||||
EntityType.LMS_SETUP,
|
||||
EntityType.SEB_CLIENT_CONFIGURATION,
|
||||
EntityType.CONFIGURATION_NODE,
|
||||
EntityType.USER));
|
||||
this.directDependancyMap.put(EntityType.LMS_SETUP, EnumSet.of(
|
||||
EntityType.EXAM));
|
||||
this.directDependancyMap.put(EntityType.EXAM, EnumSet.of(
|
||||
EntityType.EXAM_CONFIGURATION_MAP,
|
||||
EntityType.INDICATOR,
|
||||
EntityType.CLIENT_CONNECTION));
|
||||
this.directDependancyMap.put(EntityType.CONFIGURATION_NODE,
|
||||
EnumSet.noneOf(EntityType.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -172,6 +191,8 @@ public class BulkActionServiceImpl implements BulkActionService {
|
|||
return dependantSupporterInHierarchicalOrder
|
||||
.stream()
|
||||
.filter(Objects::nonNull)
|
||||
.filter(dao -> action.includeDependencies == null ||
|
||||
action.includeDependencies.contains(dao.entityType()))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
default:
|
||||
|
@ -191,13 +212,13 @@ public class BulkActionServiceImpl implements BulkActionService {
|
|||
this.supporter.get(EntityType.EXAM_CONFIGURATION_MAP),
|
||||
this.supporter.get(EntityType.CLIENT_CONNECTION),
|
||||
this.supporter.get(EntityType.CONFIGURATION_NODE));
|
||||
// case USER:
|
||||
// return Arrays.asList(
|
||||
// this.supporter.get(EntityType.EXAM_CONFIGURATION_MAP),
|
||||
// this.supporter.get(EntityType.EXAM),
|
||||
// this.supporter.get(EntityType.INDICATOR),
|
||||
// this.supporter.get(EntityType.CLIENT_CONNECTION),
|
||||
// this.supporter.get(EntityType.CONFIGURATION_NODE));
|
||||
case USER:
|
||||
return Arrays.asList(
|
||||
this.supporter.get(EntityType.EXAM),
|
||||
this.supporter.get(EntityType.INDICATOR),
|
||||
this.supporter.get(EntityType.CLIENT_CONNECTION),
|
||||
this.supporter.get(EntityType.CONFIGURATION_NODE),
|
||||
this.supporter.get(EntityType.EXAM_CONFIGURATION_MAP));
|
||||
case LMS_SETUP:
|
||||
return Arrays.asList(
|
||||
this.supporter.get(EntityType.EXAM),
|
||||
|
@ -218,6 +239,15 @@ public class BulkActionServiceImpl implements BulkActionService {
|
|||
}
|
||||
|
||||
private void checkProcessing(final BulkAction action) {
|
||||
// complete this.directDependancyMap if needed
|
||||
if (action.includeDependencies != null) {
|
||||
this.directDependancyMap.entrySet().stream()
|
||||
.forEach(entry -> {
|
||||
if (action.includeDependencies.contains(entry.getKey())) {
|
||||
action.includeDependencies.addAll(entry.getValue());
|
||||
}
|
||||
});
|
||||
}
|
||||
if (action.alreadyProcessed) {
|
||||
throw new IllegalStateException("Given BulkAction has already been processed. Use a new one");
|
||||
}
|
||||
|
|
|
@ -17,8 +17,11 @@ import org.springframework.cache.annotation.Cacheable;
|
|||
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
|
||||
import ch.ethz.seb.sebserver.gbl.model.session.ClientConnection;
|
||||
import ch.ethz.seb.sebserver.gbl.util.Result;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.BulkActionSupportDAO;
|
||||
|
||||
public interface ClientConnectionDAO extends EntityDAO<ClientConnection, ClientConnection> {
|
||||
public interface ClientConnectionDAO extends
|
||||
EntityDAO<ClientConnection, ClientConnection>,
|
||||
BulkActionSupportDAO<ClientConnection> {
|
||||
|
||||
String CONNECTION_TOKENS_CACHE = "CONNECTION_TOKENS_CACHE";
|
||||
|
||||
|
|
|
@ -8,13 +8,14 @@
|
|||
|
||||
package ch.ethz.seb.sebserver.webservice.servicelayer.dao.impl;
|
||||
|
||||
import static org.mybatis.dynamic.sql.SqlBuilder.isEqualToWhenPresent;
|
||||
import static org.mybatis.dynamic.sql.SqlBuilder.isIn;
|
||||
import static org.mybatis.dynamic.sql.SqlBuilder.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
|
@ -23,6 +24,7 @@ import org.springframework.context.annotation.Lazy;
|
|||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.api.API.BulkActionType;
|
||||
import ch.ethz.seb.sebserver.gbl.api.EntityType;
|
||||
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
|
||||
import ch.ethz.seb.sebserver.gbl.model.session.ClientConnection;
|
||||
|
@ -34,7 +36,11 @@ import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.ClientConnectionR
|
|||
import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.ClientConnectionRecordMapper;
|
||||
import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.ClientEventRecordDynamicSqlSupport;
|
||||
import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.ClientEventRecordMapper;
|
||||
import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.ClientInstructionRecordDynamicSqlSupport;
|
||||
import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.ClientInstructionRecordMapper;
|
||||
import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.ExamRecordDynamicSqlSupport;
|
||||
import ch.ethz.seb.sebserver.webservice.datalayer.batis.model.ClientConnectionRecord;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.impl.BulkAction;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ClientConnectionDAO;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.DAOLoggingSupport;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.FilterMap;
|
||||
|
@ -49,13 +55,16 @@ public class ClientConnectionDAOImpl implements ClientConnectionDAO {
|
|||
|
||||
private final ClientConnectionRecordMapper clientConnectionRecordMapper;
|
||||
private final ClientEventRecordMapper clientEventRecordMapper;
|
||||
private final ClientInstructionRecordMapper clientInstructionRecordMapper;
|
||||
|
||||
protected ClientConnectionDAOImpl(
|
||||
final ClientConnectionRecordMapper clientConnectionRecordMapper,
|
||||
final ClientEventRecordMapper clientEventRecordMapper) {
|
||||
final ClientEventRecordMapper clientEventRecordMapper,
|
||||
final ClientInstructionRecordMapper clientInstructionRecordMapper) {
|
||||
|
||||
this.clientConnectionRecordMapper = clientConnectionRecordMapper;
|
||||
this.clientEventRecordMapper = clientEventRecordMapper;
|
||||
this.clientInstructionRecordMapper = clientInstructionRecordMapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -171,6 +180,39 @@ public class ClientConnectionDAOImpl implements ClientConnectionDAO {
|
|||
.onError(TransactionHandler::rollback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<EntityKey> getDependencies(final BulkAction bulkAction) {
|
||||
// only for deletion
|
||||
if (bulkAction.type == BulkActionType.ACTIVATE || bulkAction.type == BulkActionType.DEACTIVATE) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
// only if included
|
||||
if (!bulkAction.includesDependencyType(EntityType.CLIENT_CONNECTION)) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
// define the select function in case of source type
|
||||
Function<EntityKey, Result<Collection<EntityKey>>> selectionFunction;
|
||||
switch (bulkAction.sourceType) {
|
||||
case INSTITUTION:
|
||||
selectionFunction = this::allIdsOfInstitution;
|
||||
break;
|
||||
case LMS_SETUP:
|
||||
selectionFunction = this::allIdsOfLmsSetup;
|
||||
case USER:
|
||||
selectionFunction = this::allIdsOfUser;
|
||||
break;
|
||||
case EXAM:
|
||||
selectionFunction = this::allIdsOfExam;
|
||||
break;
|
||||
default:
|
||||
selectionFunction = key -> Result.of(Collections.emptyList()); //empty select function
|
||||
break;
|
||||
}
|
||||
|
||||
return getDependencies(bulkAction, selectionFunction);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public Result<Collection<EntityKey>> delete(final Set<EntityKey> all) {
|
||||
|
@ -186,6 +228,23 @@ public class ClientConnectionDAOImpl implements ClientConnectionDAO {
|
|||
.build()
|
||||
.execute();
|
||||
|
||||
// then delete all related client instructions
|
||||
final List<String> connectionTokens = this.clientConnectionRecordMapper.selectByExample()
|
||||
.where(
|
||||
ClientConnectionRecordDynamicSqlSupport.id,
|
||||
SqlBuilder.isIn(ids))
|
||||
.build()
|
||||
.execute()
|
||||
.stream()
|
||||
.map(r -> r.getConnectionToken())
|
||||
.collect(Collectors.toList());
|
||||
this.clientInstructionRecordMapper.deleteByExample()
|
||||
.where(
|
||||
ClientInstructionRecordDynamicSqlSupport.connectionToken,
|
||||
SqlBuilder.isIn(connectionTokens))
|
||||
.build()
|
||||
.execute();
|
||||
|
||||
// then delete all requested client-connections
|
||||
this.clientConnectionRecordMapper.deleteByExample()
|
||||
.where(
|
||||
|
@ -256,7 +315,62 @@ public class ClientConnectionDAOImpl implements ClientConnectionDAO {
|
|||
record.getVirtualClientAddress(),
|
||||
record.getCreationTime());
|
||||
});
|
||||
}
|
||||
|
||||
private Result<Collection<EntityKey>> allIdsOfInstitution(final EntityKey institutionKey) {
|
||||
return Result.tryCatch(() -> this.clientConnectionRecordMapper.selectIdsByExample()
|
||||
.where(
|
||||
ClientConnectionRecordDynamicSqlSupport.institutionId,
|
||||
isEqualTo(Long.parseLong(institutionKey.modelId)))
|
||||
.build()
|
||||
.execute()
|
||||
.stream()
|
||||
.map(id -> new EntityKey(id, EntityType.EXAM))
|
||||
.collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
private Result<Collection<EntityKey>> allIdsOfLmsSetup(final EntityKey lmsSetupKey) {
|
||||
return Result.tryCatch(() -> this.clientConnectionRecordMapper.selectIdsByExample()
|
||||
.leftJoin(ExamRecordDynamicSqlSupport.examRecord)
|
||||
.on(
|
||||
ExamRecordDynamicSqlSupport.id,
|
||||
equalTo(ClientConnectionRecordDynamicSqlSupport.examId))
|
||||
.where(
|
||||
ExamRecordDynamicSqlSupport.lmsSetupId,
|
||||
isEqualTo(Long.parseLong(lmsSetupKey.modelId)))
|
||||
.build()
|
||||
.execute()
|
||||
.stream()
|
||||
.map(id -> new EntityKey(id, EntityType.EXAM))
|
||||
.collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
private Result<Collection<EntityKey>> allIdsOfUser(final EntityKey userKey) {
|
||||
return Result.tryCatch(() -> this.clientConnectionRecordMapper.selectIdsByExample()
|
||||
.leftJoin(ExamRecordDynamicSqlSupport.examRecord)
|
||||
.on(
|
||||
ExamRecordDynamicSqlSupport.id,
|
||||
equalTo(ClientConnectionRecordDynamicSqlSupport.examId))
|
||||
.where(
|
||||
ExamRecordDynamicSqlSupport.owner,
|
||||
isEqualTo(userKey.modelId))
|
||||
.build()
|
||||
.execute()
|
||||
.stream()
|
||||
.map(id -> new EntityKey(id, EntityType.EXAM))
|
||||
.collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
private Result<Collection<EntityKey>> allIdsOfExam(final EntityKey examKey) {
|
||||
return Result.tryCatch(() -> this.clientConnectionRecordMapper.selectIdsByExample()
|
||||
.where(
|
||||
ClientConnectionRecordDynamicSqlSupport.examId,
|
||||
isEqualTo(Long.parseLong(examKey.modelId)))
|
||||
.build()
|
||||
.execute()
|
||||
.stream()
|
||||
.map(id -> new EntityKey(id, EntityType.EXAM))
|
||||
.collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@ import org.springframework.context.annotation.Lazy;
|
|||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.api.API.BulkActionType;
|
||||
import ch.ethz.seb.sebserver.gbl.api.APIMessage.FieldValidationException;
|
||||
import ch.ethz.seb.sebserver.gbl.api.EntityType;
|
||||
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
|
||||
|
@ -134,11 +135,24 @@ public class ConfigurationNodeDAOImpl implements ConfigurationNodeDAO {
|
|||
@Override
|
||||
@Transactional(readOnly = true)
|
||||
public Set<EntityKey> getDependencies(final BulkAction bulkAction) {
|
||||
// only if included
|
||||
if (!bulkAction.includesDependencyType(EntityType.CONFIGURATION_NODE)) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
// define the select function in case of source type
|
||||
final Function<EntityKey, Result<Collection<EntityKey>>> selectionFunction =
|
||||
(bulkAction.sourceType == EntityType.INSTITUTION)
|
||||
? this::allIdsOfInstitution
|
||||
: key -> Result.of(Collections.emptyList()); // else : empty select function
|
||||
Function<EntityKey, Result<Collection<EntityKey>>> selectionFunction =
|
||||
key -> Result.of(Collections.emptyList());
|
||||
|
||||
if (bulkAction.sourceType == EntityType.INSTITUTION) {
|
||||
selectionFunction = this::allIdsOfInstitution;
|
||||
}
|
||||
|
||||
// in case of user deletion with configuration dependency inclusion
|
||||
if (bulkAction.sourceType == EntityType.USER &&
|
||||
bulkAction.type == BulkActionType.HARD_DELETE) {
|
||||
selectionFunction = this::allIdsOfUser;
|
||||
}
|
||||
|
||||
return getDependencies(bulkAction, selectionFunction);
|
||||
}
|
||||
|
@ -252,6 +266,18 @@ public class ConfigurationNodeDAOImpl implements ConfigurationNodeDAO {
|
|||
.collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
private Result<Collection<EntityKey>> allIdsOfUser(final EntityKey userKey) {
|
||||
return Result.tryCatch(() -> this.configurationNodeRecordMapper.selectIdsByExample()
|
||||
.where(
|
||||
ConfigurationNodeRecordDynamicSqlSupport.owner,
|
||||
isEqualTo(userKey.modelId))
|
||||
.build()
|
||||
.execute()
|
||||
.stream()
|
||||
.map(id -> new EntityKey(id, EntityType.CONFIGURATION_NODE))
|
||||
.collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
private Result<ConfigurationNodeRecord> recordById(final Long id) {
|
||||
return Result.tryCatch(() -> {
|
||||
final ConfigurationNodeRecord record = this.configurationNodeRecordMapper
|
||||
|
|
|
@ -28,8 +28,8 @@ import org.springframework.transaction.annotation.Transactional;
|
|||
import ch.ethz.seb.sebserver.gbl.api.API.BulkActionType;
|
||||
import ch.ethz.seb.sebserver.gbl.api.APIMessage.APIMessageException;
|
||||
import ch.ethz.seb.sebserver.gbl.api.APIMessage.ErrorMessage;
|
||||
import ch.ethz.seb.sebserver.gbl.client.ClientCredentialService;
|
||||
import ch.ethz.seb.sebserver.gbl.api.EntityType;
|
||||
import ch.ethz.seb.sebserver.gbl.client.ClientCredentialService;
|
||||
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
|
||||
import ch.ethz.seb.sebserver.gbl.model.exam.Exam;
|
||||
import ch.ethz.seb.sebserver.gbl.model.exam.Exam.ExamType;
|
||||
|
@ -281,9 +281,14 @@ public class ExamConfigurationMapDAOImpl implements ExamConfigurationMapDAO {
|
|||
@Override
|
||||
@Transactional(readOnly = true)
|
||||
public Set<EntityKey> getDependencies(final BulkAction bulkAction) {
|
||||
// only deletion here
|
||||
if (bulkAction.type == BulkActionType.ACTIVATE || bulkAction.type == BulkActionType.DEACTIVATE) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
// only if included
|
||||
if (!bulkAction.includesDependencyType(EntityType.EXAM_CONFIGURATION_MAP)) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
// define the select function in case of source type
|
||||
Function<EntityKey, Result<Collection<EntityKey>>> selectionFunction;
|
||||
|
@ -291,6 +296,9 @@ public class ExamConfigurationMapDAOImpl implements ExamConfigurationMapDAO {
|
|||
case INSTITUTION:
|
||||
selectionFunction = this::allIdsOfInstitution;
|
||||
break;
|
||||
case USER:
|
||||
selectionFunction = this::allIdsOfUser;
|
||||
break;
|
||||
case LMS_SETUP:
|
||||
selectionFunction = this::allIdsOfLmsSetup;
|
||||
break;
|
||||
|
@ -424,6 +432,30 @@ public class ExamConfigurationMapDAOImpl implements ExamConfigurationMapDAO {
|
|||
.collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
private Result<Collection<EntityKey>> allIdsOfUser(final EntityKey userKey) {
|
||||
return Result.tryCatch(() -> {
|
||||
final List<Long> examsIds = this.examRecordMapper.selectByExample()
|
||||
.where(
|
||||
ExamRecordDynamicSqlSupport.owner,
|
||||
isEqualTo(userKey.modelId))
|
||||
.build()
|
||||
.execute()
|
||||
.stream()
|
||||
.map(r -> r.getId())
|
||||
.collect(Collectors.toList());
|
||||
|
||||
return this.examConfigurationMapRecordMapper.selectIdsByExample()
|
||||
.where(
|
||||
ExamConfigurationMapRecordDynamicSqlSupport.examId,
|
||||
isIn(examsIds))
|
||||
.build()
|
||||
.execute()
|
||||
.stream()
|
||||
.map(id -> new EntityKey(id, EntityType.EXAM_CONFIGURATION_MAP))
|
||||
.collect(Collectors.toList());
|
||||
});
|
||||
}
|
||||
|
||||
private Result<Collection<EntityKey>> allIdsOfLmsSetup(final EntityKey lmsSetupKey) {
|
||||
return Result.tryCatch(() -> this.examConfigurationMapRecordMapper.selectIdsByExample()
|
||||
.leftJoin(ExamRecordDynamicSqlSupport.examRecord)
|
||||
|
|
|
@ -588,6 +588,10 @@ public class ExamDAOImpl implements ExamDAO {
|
|||
@Override
|
||||
@Transactional(readOnly = true)
|
||||
public Set<EntityKey> getDependencies(final BulkAction bulkAction) {
|
||||
// only if included
|
||||
if (!bulkAction.includesDependencyType(EntityType.EXAM)) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
// define the select function in case of source type
|
||||
Function<EntityKey, Result<Collection<EntityKey>>> selectionFunction;
|
||||
|
@ -598,6 +602,9 @@ public class ExamDAOImpl implements ExamDAO {
|
|||
case LMS_SETUP:
|
||||
selectionFunction = this::allIdsOfLmsSetup;
|
||||
break;
|
||||
case USER:
|
||||
selectionFunction = this::allIdsOfUser;
|
||||
break;
|
||||
default:
|
||||
selectionFunction = key -> Result.of(Collections.emptyList()); //empty select function
|
||||
break;
|
||||
|
@ -651,6 +658,17 @@ public class ExamDAOImpl implements ExamDAO {
|
|||
.collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
private Result<Collection<EntityKey>> allIdsOfUser(final EntityKey userKey) {
|
||||
return Result.tryCatch(() -> this.examRecordMapper.selectIdsByExample()
|
||||
.where(ExamRecordDynamicSqlSupport.owner,
|
||||
isEqualTo(userKey.modelId))
|
||||
.build()
|
||||
.execute()
|
||||
.stream()
|
||||
.map(id -> new EntityKey(id, EntityType.EXAM))
|
||||
.collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
private Result<ExamRecord> recordById(final Long id) {
|
||||
return Result.tryCatch(() -> {
|
||||
final ExamRecord record = this.examRecordMapper.selectByPrimaryKey(id);
|
||||
|
|
|
@ -221,9 +221,14 @@ public class IndicatorDAOImpl implements IndicatorDAO {
|
|||
@Override
|
||||
@Transactional(readOnly = true)
|
||||
public Set<EntityKey> getDependencies(final BulkAction bulkAction) {
|
||||
// only for deletion
|
||||
if (bulkAction.type == BulkActionType.ACTIVATE || bulkAction.type == BulkActionType.DEACTIVATE) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
// only if included
|
||||
if (!bulkAction.includesDependencyType(EntityType.INDICATOR)) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
// define the select function in case of source type
|
||||
Function<EntityKey, Result<Collection<EntityKey>>> selectionFunction;
|
||||
|
@ -233,6 +238,8 @@ public class IndicatorDAOImpl implements IndicatorDAO {
|
|||
break;
|
||||
case LMS_SETUP:
|
||||
selectionFunction = this::allIdsOfLmsSetup;
|
||||
case USER:
|
||||
selectionFunction = this::allIdsOfUser;
|
||||
break;
|
||||
case EXAM:
|
||||
selectionFunction = this::allIdsOfExam;
|
||||
|
@ -277,6 +284,22 @@ public class IndicatorDAOImpl implements IndicatorDAO {
|
|||
.collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
private Result<Collection<EntityKey>> allIdsOfUser(final EntityKey userKey) {
|
||||
return Result.tryCatch(() -> this.indicatorRecordMapper.selectIdsByExample()
|
||||
.leftJoin(ExamRecordDynamicSqlSupport.examRecord)
|
||||
.on(
|
||||
ExamRecordDynamicSqlSupport.id,
|
||||
equalTo(IndicatorRecordDynamicSqlSupport.examId))
|
||||
.where(
|
||||
ExamRecordDynamicSqlSupport.owner,
|
||||
isEqualTo(userKey.modelId))
|
||||
.build()
|
||||
.execute()
|
||||
.stream()
|
||||
.map(id -> new EntityKey(id, EntityType.EXAM))
|
||||
.collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
private Result<Collection<EntityKey>> allIdsOfExam(final EntityKey examKey) {
|
||||
return Result.tryCatch(() -> this.indicatorRecordMapper.selectIdsByExample()
|
||||
.where(
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
package ch.ethz.seb.sebserver.webservice.weblayer.api;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.mybatis.dynamic.sql.SqlTable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
|
@ -52,7 +53,10 @@ public class ClientConnectionController extends ReadonlyEntityController<ClientC
|
|||
}
|
||||
|
||||
@Override
|
||||
public Collection<EntityKey> getDependencies(final String modelId, final BulkActionType bulkActionType) {
|
||||
public Collection<EntityKey> getDependencies(
|
||||
final String modelId,
|
||||
final BulkActionType bulkActionType,
|
||||
final List<String> includes) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
package ch.ethz.seb.sebserver.webservice.weblayer.api;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
|
@ -114,7 +115,10 @@ public class ClientEventController extends ReadonlyEntityController<ClientEvent,
|
|||
}
|
||||
|
||||
@Override
|
||||
public Collection<EntityKey> getDependencies(final String modelId, final BulkActionType bulkActionType) {
|
||||
public Collection<EntityKey> getDependencies(
|
||||
final String modelId,
|
||||
final BulkActionType bulkActionType,
|
||||
final List<String> includes) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
package ch.ethz.seb.sebserver.webservice.weblayer.api;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.mybatis.dynamic.sql.SqlTable;
|
||||
import org.slf4j.Logger;
|
||||
|
@ -110,7 +111,10 @@ public class ConfigurationController extends ReadonlyEntityController<Configurat
|
|||
}
|
||||
|
||||
@Override
|
||||
public Collection<EntityKey> getDependencies(final String modelId, final BulkActionType bulkActionType) {
|
||||
public Collection<EntityKey> getDependencies(
|
||||
final String modelId,
|
||||
final BulkActionType bulkActionType,
|
||||
final List<String> includes) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
package ch.ethz.seb.sebserver.webservice.weblayer.api;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import javax.validation.Valid;
|
||||
|
@ -87,7 +88,9 @@ public class ConfigurationValueController extends EntityController<Configuration
|
|||
}
|
||||
|
||||
@Override
|
||||
public EntityProcessingReport hardDelete(final String modelId) {
|
||||
public EntityProcessingReport hardDelete(
|
||||
final String modelId,
|
||||
final List<String> includes) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
|
|
|
@ -10,7 +10,9 @@ package ch.ethz.seb.sebserver.webservice.weblayer.api;
|
|||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
@ -209,7 +211,8 @@ public abstract class EntityController<T extends Entity, M extends Entity> {
|
|||
produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
|
||||
public Collection<EntityKey> getDependencies(
|
||||
@PathVariable final String modelId,
|
||||
@RequestParam(name = API.PARAM_BULK_ACTION_TYPE, required = true) final BulkActionType bulkActionType) {
|
||||
@RequestParam(name = API.PARAM_BULK_ACTION_TYPE, required = true) final BulkActionType bulkActionType,
|
||||
@RequestParam(name = API.PARAM_BULK_ACTION_INCLUDES, required = false) final List<String> includes) {
|
||||
|
||||
this.entityDAO
|
||||
.byModelId(modelId)
|
||||
|
@ -218,7 +221,8 @@ public abstract class EntityController<T extends Entity, M extends Entity> {
|
|||
final BulkAction bulkAction = new BulkAction(
|
||||
bulkActionType,
|
||||
this.entityDAO.entityType(),
|
||||
Arrays.asList(new EntityKey(modelId, this.entityDAO.entityType())));
|
||||
Arrays.asList(new EntityKey(modelId, this.entityDAO.entityType())),
|
||||
convertToEntityType(includes));
|
||||
|
||||
this.bulkActionService.collectDependencies(bulkAction);
|
||||
return bulkAction.getDependencies();
|
||||
|
@ -320,24 +324,48 @@ public abstract class EntityController<T extends Entity, M extends Entity> {
|
|||
path = API.MODEL_ID_VAR_PATH_SEGMENT,
|
||||
method = RequestMethod.DELETE,
|
||||
produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
|
||||
public EntityProcessingReport hardDelete(@PathVariable final String modelId) {
|
||||
public EntityProcessingReport hardDelete(
|
||||
@PathVariable final String modelId,
|
||||
@RequestParam(name = API.PARAM_BULK_ACTION_INCLUDES, required = false) final List<String> includes) {
|
||||
|
||||
return this.entityDAO.byModelId(modelId)
|
||||
.flatMap(this::checkWriteAccess)
|
||||
.flatMap(this::validForDelete)
|
||||
.flatMap(this::bulkDelete)
|
||||
.flatMap(entity -> bulkDelete(entity, convertToEntityType(includes)))
|
||||
.flatMap(this::notifyDeleted)
|
||||
.flatMap(pair -> this.logBulkAction(pair.b))
|
||||
.getOrThrow();
|
||||
}
|
||||
|
||||
protected Result<Pair<T, EntityProcessingReport>> bulkDelete(final T entity) {
|
||||
protected EnumSet<EntityType> convertToEntityType(final List<String> includes) {
|
||||
final EnumSet<EntityType> includeDependencies = (includes != null)
|
||||
? EnumSet.copyOf(includes.stream().map(name -> {
|
||||
try {
|
||||
return EntityType.valueOf(name);
|
||||
} catch (final Exception e) {
|
||||
return null;
|
||||
}
|
||||
})
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toSet()))
|
||||
: null;
|
||||
return includeDependencies;
|
||||
}
|
||||
|
||||
protected Result<Pair<T, EntityProcessingReport>> bulkDelete(
|
||||
final T entity,
|
||||
final EnumSet<EntityType> includeDependencies) {
|
||||
|
||||
final BulkAction bulkAction = new BulkAction(
|
||||
BulkActionType.HARD_DELETE,
|
||||
entity.entityType(),
|
||||
Arrays.asList(new EntityName(entity.getModelId(), entity.entityType(), entity.getName())),
|
||||
includeDependencies);
|
||||
|
||||
return Result.tryCatch(() -> new Pair<>(
|
||||
entity,
|
||||
this.bulkActionService.createReport(new BulkAction(
|
||||
BulkActionType.HARD_DELETE,
|
||||
entity.entityType(),
|
||||
new EntityName(entity.getModelId(), entity.entityType(), entity.getName())))
|
||||
this.bulkActionService
|
||||
.createReport(bulkAction)
|
||||
.getOrThrow()));
|
||||
}
|
||||
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
|
||||
package ch.ethz.seb.sebserver.webservice.weblayer.api;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.mybatis.dynamic.sql.SqlTable;
|
||||
|
@ -162,13 +164,15 @@ public class ExamConfigurationMappingController extends EntityController<ExamCon
|
|||
path = API.MODEL_ID_VAR_PATH_SEGMENT,
|
||||
method = RequestMethod.DELETE,
|
||||
produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
|
||||
public EntityProcessingReport hardDelete(@PathVariable final String modelId) {
|
||||
public EntityProcessingReport hardDelete(
|
||||
@PathVariable final String modelId,
|
||||
@RequestParam(name = API.PARAM_BULK_ACTION_INCLUDES, required = false) final List<String> includes) {
|
||||
|
||||
return this.entityDAO.byModelId(modelId)
|
||||
.flatMap(this::checkWriteAccess)
|
||||
.flatMap(entity -> this.examConfigUpdateService.processExamConfigurationMappingChange(
|
||||
entity,
|
||||
this::bulkDelete))
|
||||
e -> bulkDelete(e, convertToEntityType(includes))))
|
||||
.flatMap(this::notifyDeleted)
|
||||
.flatMap(pair -> this.logBulkAction(pair.b))
|
||||
.getOrThrow();
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
|
||||
package ch.ethz.seb.sebserver.webservice.weblayer.api;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.validation.Valid;
|
||||
|
||||
|
@ -59,7 +61,9 @@ public abstract class ReadonlyEntityController<T extends Entity, M extends Entit
|
|||
}
|
||||
|
||||
@Override
|
||||
public EntityProcessingReport hardDelete(final String modelId) {
|
||||
public EntityProcessingReport hardDelete(
|
||||
final String modelId,
|
||||
final List<String> includes) {
|
||||
throw new UnsupportedOperationException(ONLY_READ_ACCESS);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue