SEBSERV-17 #implementation of ExamDAO and improvements for bulk actions

This commit is contained in:
anhefti 2019-01-16 10:47:12 +01:00
parent 1ba0345178
commit 2f8b796b86
16 changed files with 349 additions and 271 deletions

View file

@ -27,15 +27,15 @@ import ch.ethz.seb.sebserver.webservice.servicelayer.dao.UserActivityLogDAO;
@WebServiceProfile
public class BulkActionService {
private final Map<EntityType, BulkActionSupport> supporter;
private final Map<EntityType, BulkActionSupportDAO<?>> supporter;
private final UserActivityLogDAO userActivityLogDAO;
public BulkActionService(
final Collection<BulkActionSupport> supporter,
final Collection<BulkActionSupportDAO<?>> supporter,
final UserActivityLogDAO userActivityLogDAO) {
this.supporter = new HashMap<>();
for (final BulkActionSupport support : supporter) {
for (final BulkActionSupportDAO<?> support : supporter) {
this.supporter.put(support.entityType(), support);
}
this.userActivityLogDAO = userActivityLogDAO;
@ -43,7 +43,7 @@ public class BulkActionService {
public void collectDependencies(final BulkAction action) {
checkProcessing(action);
for (final BulkActionSupport sup : this.supporter.values()) {
for (final BulkActionSupportDAO<?> sup : this.supporter.values()) {
action.dependencies.addAll(sup.getDependencies(action));
}
action.alreadyProcessed = true;
@ -52,7 +52,7 @@ public class BulkActionService {
public void doBulkAction(final BulkAction action) {
checkProcessing(action);
final BulkActionSupport supportForSource = this.supporter.get(action.sourceType);
final BulkActionSupportDAO<?> supportForSource = this.supporter.get(action.sourceType);
if (supportForSource == null) {
action.alreadyProcessed = true;
return;
@ -62,10 +62,10 @@ public class BulkActionService {
if (!action.dependencies.isEmpty()) {
// process dependencies first...
final List<BulkActionSupport> dependancySupporter =
final List<BulkActionSupportDAO<?>> dependancySupporter =
getDependancySupporter(action);
for (final BulkActionSupport support : dependancySupporter) {
for (final BulkActionSupportDAO<?> support : dependancySupporter) {
action.result.addAll(support.processBulkAction(action));
}
}
@ -111,12 +111,12 @@ public class BulkActionService {
}
}
private List<BulkActionSupport> getDependancySupporter(final BulkAction action) {
private List<BulkActionSupportDAO<?>> getDependancySupporter(final BulkAction action) {
switch (action.type) {
case ACTIVATE:
case DEACTIVATE:
case HARD_DELETE: {
final List<BulkActionSupport> dependantSupporterInHierarchicalOrder =
final List<BulkActionSupportDAO<?>> dependantSupporterInHierarchicalOrder =
getDependantSupporterInHierarchicalOrder(action);
Collections.reverse(dependantSupporterInHierarchicalOrder);
return dependantSupporterInHierarchicalOrder;
@ -126,7 +126,7 @@ public class BulkActionService {
}
}
private List<BulkActionSupport> getDependantSupporterInHierarchicalOrder(final BulkAction action) {
private List<BulkActionSupportDAO<?>> getDependantSupporterInHierarchicalOrder(final BulkAction action) {
switch (action.sourceType) {
case INSTITUTION:
return Arrays.asList(

View file

@ -1,50 +0,0 @@
/*
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction;
import java.util.Collection;
import java.util.Set;
import java.util.stream.Collectors;
import org.springframework.transaction.annotation.Transactional;
import ch.ethz.seb.sebserver.gbl.model.Entity;
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
import ch.ethz.seb.sebserver.gbl.model.EntityKeyAndName;
import ch.ethz.seb.sebserver.gbl.model.EntityType;
import ch.ethz.seb.sebserver.gbl.util.Result;
public interface BulkActionSupport {
/** Get the entity type for a concrete EntityDAO implementation.
*
* @return The EntityType for a concrete EntityDAO implementation */
EntityType entityType();
Set<EntityKey> getDependencies(BulkAction bulkAction);
Result<Collection<Entity>> bulkLoadEntities(Collection<EntityKey> keys);
@Transactional(readOnly = true)
default Result<Collection<EntityKeyAndName>> bulkLoadEntityNames(final Collection<EntityKey> keys) {
return Result.tryCatch(() -> {
return bulkLoadEntities(keys)
.getOrThrow()
.stream()
.map(entity -> new EntityKeyAndName(
EntityType.INSTITUTION,
entity.getModelId(),
entity.getName()))
.collect(Collectors.toList());
});
}
Collection<Result<EntityKey>> processBulkAction(BulkAction bulkAction);
}

View file

@ -0,0 +1,93 @@
/*
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction;
import java.util.Collection;
import java.util.Collections;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.transaction.annotation.Transactional;
import ch.ethz.seb.sebserver.gbl.model.Entity;
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
import ch.ethz.seb.sebserver.gbl.model.EntityKeyAndName;
import ch.ethz.seb.sebserver.gbl.model.EntityType;
import ch.ethz.seb.sebserver.gbl.util.Result;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ActivatableEntityDAO;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.EntityDAO;
public interface BulkActionSupportDAO<T extends Entity> {
Logger log = LoggerFactory.getLogger(BulkActionSupportDAO.class);
/** Get the entity type for a concrete EntityDAO implementation.
*
* @return The EntityType for a concrete EntityDAO implementation */
EntityType entityType();
Set<EntityKey> getDependencies(BulkAction bulkAction);
Result<Collection<T>> bulkLoadEntities(Collection<EntityKey> keys);
@Transactional(readOnly = true)
default Result<Collection<EntityKeyAndName>> bulkLoadEntityNames(final Collection<EntityKey> keys) {
return Result.tryCatch(() -> {
return bulkLoadEntities(keys)
.getOrThrow()
.stream()
.map(entity -> new EntityKeyAndName(
EntityType.INSTITUTION,
entity.getModelId(),
entity.getName()))
.collect(Collectors.toList());
});
}
@Transactional
default Collection<Result<EntityKey>> processBulkAction(final BulkAction bulkAction) {
final Set<EntityKey> all = bulkAction.extractKeys(entityType());
switch (bulkAction.type) {
case ACTIVATE:
return (this instanceof ActivatableEntityDAO)
? ((ActivatableEntityDAO<?>) this).setActive(all, true)
: Collections.emptyList();
case DEACTIVATE:
return (this instanceof ActivatableEntityDAO)
? ((ActivatableEntityDAO<?>) this).setActive(all, false)
: Collections.emptyList();
case HARD_DELETE:
return (this instanceof EntityDAO)
? ((EntityDAO<?>) this).delete(all)
: Collections.emptyList();
}
// should never happen
throw new UnsupportedOperationException("Unsupported Bulk Action: " + bulkAction);
}
@Transactional(readOnly = true)
default Set<EntityKey> getDependencies(
final BulkAction bulkAction,
final Function<EntityKey, Result<Collection<EntityKey>>> selectionFunction) {
return bulkAction.sources
.stream()
.map(selectionFunction) // apply select function for each source key
.peek(result -> result.onErrorDo(error -> log.error("Unexpected error: ", error)))
.flatMap(Result::skipOnError) // handle and skip results with error
.flatMap(Collection::stream) // Flatten stream of Collection in to one stream
.collect(Collectors.toSet());
}
}

View file

@ -8,12 +8,12 @@
package ch.ethz.seb.sebserver.webservice.servicelayer.dao;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import ch.ethz.seb.sebserver.gbl.model.Entity;
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
@ -73,7 +73,7 @@ public interface EntityDAO<T extends Entity> {
* happened */
Collection<Result<EntityKey>> delete(Set<EntityKey> all);
/** Utility method to extract an expected single resource entry form a Collection of specified type.
/** Context based utility method to extract an expected single resource entry form a Collection of specified type.
* Gets a Result refer to an expected single resource entry form a Collection of specified type or refer
* to a ResourceNotFoundException if specified collection is null or empty or refer to a
* unexpected RuntimeException if there are more then the expected single element in the given collection
@ -95,28 +95,27 @@ public interface EntityDAO<T extends Entity> {
return Result.of(resources.iterator().next());
}
default List<Long> extractIdsFromKeys(
final Collection<EntityKey> keys,
final Collection<Result<EntityKey>> result) {
/** Context based utility method to extract a list of id's (PK) from a collection of various EntityKey
* This uses the EntityType defined by this instance to filter all EntityKey by the given type and
* convert the matching EntityKey's to id's (PK's)
*
* Use this if you need to transform a Collection of EntityKey into a extracted List of id's of a specified
* EntityType
*
* @param keys Collection of EntityKey of various types
* @return List of id's (PK's) from the given key collection that match the concrete EntityType */
default List<Long> extractIdsFromKeys(final Collection<EntityKey> keys) {
if (keys == null) {
return Collections.emptyList();
}
final EntityType entityType = entityType();
final List<Long> ids = new ArrayList<>();
for (final EntityKey key : keys) {
if (key.entityType == entityType) {
try {
ids.add(Long.valueOf(key.entityId));
} catch (final Exception e) {
result.add(Result.ofError(new IllegalArgumentException("Invalid id for EntityKey: " + key)));
}
}
}
return ids;
return keys
.stream()
.filter(key -> key.entityType == entityType)
.map(key -> Long.valueOf(key.entityId))
.collect(Collectors.toList());
}
}

View file

@ -13,8 +13,9 @@ import java.util.Collection;
import ch.ethz.seb.sebserver.gbl.model.exam.Exam;
import ch.ethz.seb.sebserver.gbl.model.exam.QuizData;
import ch.ethz.seb.sebserver.gbl.util.Result;
import ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.BulkActionSupportDAO;
public interface ExamDAO extends ActivatableEntityDAO<Exam> {
public interface ExamDAO extends ActivatableEntityDAO<Exam>, BulkActionSupportDAO<Exam> {
Result<Exam> importFromQuizData(QuizData quizData);

View file

@ -12,8 +12,9 @@ import java.util.Collection;
import ch.ethz.seb.sebserver.gbl.model.institution.Institution;
import ch.ethz.seb.sebserver.gbl.util.Result;
import ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.BulkActionSupportDAO;
public interface InstitutionDAO extends ActivatableEntityDAO<Institution> {
public interface InstitutionDAO extends ActivatableEntityDAO<Institution>, BulkActionSupportDAO<Institution> {
Result<Collection<Institution>> allMatching(String name, Boolean active);

View file

@ -15,8 +15,9 @@ import org.springframework.transaction.annotation.Transactional;
import ch.ethz.seb.sebserver.gbl.model.institution.LmsSetup;
import ch.ethz.seb.sebserver.gbl.model.institution.LmsSetup.LmsType;
import ch.ethz.seb.sebserver.gbl.util.Result;
import ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.BulkActionSupportDAO;
public interface LmsSetupDAO extends ActivatableEntityDAO<LmsSetup> {
public interface LmsSetupDAO extends ActivatableEntityDAO<LmsSetup>, BulkActionSupportDAO<LmsSetup> {
@Transactional(readOnly = true)
default Result<Collection<LmsSetup>> allOfInstitution(final Long institutionId, final Boolean active) {

View file

@ -19,11 +19,12 @@ import ch.ethz.seb.sebserver.gbl.model.user.UserInfo;
import ch.ethz.seb.sebserver.gbl.model.user.UserMod;
import ch.ethz.seb.sebserver.gbl.util.Result;
import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.SEBServerUser;
import ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.BulkActionSupportDAO;
/** The Data Access Object for all User related data like get user data within UserInfo,
* save and modify user related data within UserMod and get internal user principal data
* within SEBServerUser. */
public interface UserDAO extends ActivatableEntityDAO<UserInfo> {
public interface UserDAO extends ActivatableEntityDAO<UserInfo>, BulkActionSupportDAO<UserInfo> {
/** Use this to get UserInfo by users UUID
*
@ -87,6 +88,6 @@ public interface UserDAO extends ActivatableEntityDAO<UserInfo> {
*
* @param uuid The UUID of the user
* @return a Collection containing EntityKey's of all entities that belongs to a given User */
Collection<EntityKey> getAllUserData(String uuid);
Collection<EntityKey> getAllUserRelatedData(String uuid);
}

View file

@ -8,8 +8,7 @@
package ch.ethz.seb.sebserver.webservice.servicelayer.dao.impl;
import static org.mybatis.dynamic.sql.SqlBuilder.isEqualTo;
import static org.mybatis.dynamic.sql.SqlBuilder.isEqualToWhenPresent;
import static org.mybatis.dynamic.sql.SqlBuilder.*;
import java.util.Arrays;
import java.util.Collection;
@ -17,6 +16,7 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Set;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
@ -29,7 +29,6 @@ import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import ch.ethz.seb.sebserver.gbl.Constants;
import ch.ethz.seb.sebserver.gbl.model.Entity;
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
import ch.ethz.seb.sebserver.gbl.model.EntityType;
import ch.ethz.seb.sebserver.gbl.model.exam.Exam;
@ -42,14 +41,13 @@ import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.ExamRecordDynamic
import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.ExamRecordMapper;
import ch.ethz.seb.sebserver.webservice.datalayer.batis.model.ExamRecord;
import ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.BulkAction;
import ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.BulkActionSupport;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ExamDAO;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ResourceNotFoundException;
import ch.ethz.seb.sebserver.webservice.servicelayer.lms.LmsAPIService;
@Lazy
@Component
public class ExamDAOImpl implements ExamDAO, BulkActionSupport {
public class ExamDAOImpl implements ExamDAO {
private final ExamRecordMapper examRecordMapper;
private final LmsAPIService lmsAPIService;
@ -162,20 +160,6 @@ public class ExamDAOImpl implements ExamDAO, BulkActionSupport {
});
}
@Override
@Transactional
public Collection<Result<EntityKey>> setActive(final Set<EntityKey> all, final boolean active) {
// TODO Auto-generated method stub
return Collections.emptyList();
}
@Override
@Transactional
public Collection<Result<EntityKey>> delete(final Set<EntityKey> all) {
// TODO Auto-generated method stub
return Collections.emptyList();
}
@Override
@Transactional
public Result<Exam> importFromQuizData(final QuizData quizData) {
@ -184,24 +168,105 @@ public class ExamDAOImpl implements ExamDAO, BulkActionSupport {
}
@Override
@Transactional(readOnly = true)
public Set<EntityKey> getDependencies(final BulkAction bulkAction) {
// TODO Auto-generated method stub
return Collections.emptySet();
}
@Transactional
public Collection<Result<EntityKey>> setActive(final Set<EntityKey> all, final boolean active) {
final List<Long> ids = extractIdsFromKeys(all);
final ExamRecord examRecord = new ExamRecord(null, null, null, null, null,
null, null, null, BooleanUtils.toInteger(active));
@Override
@Transactional(readOnly = true)
public Result<Collection<Entity>> bulkLoadEntities(final Collection<EntityKey> keys) {
// TODO Auto-generated method stub
return Result.ofTODO();
try {
this.examRecordMapper.updateByExampleSelective(examRecord)
.where(ExamRecordDynamicSqlSupport.id, isIn(ids))
.build()
.execute();
return ids.stream()
.map(id -> Result.of(new EntityKey(id, EntityType.EXAM)))
.collect(Collectors.toList());
} catch (final Exception e) {
return ids.stream()
.map(id -> Result.<EntityKey> ofError(new RuntimeException(
"Activation failed on unexpected exception for Exam of id: " + id, e)))
.collect(Collectors.toList());
}
}
@Override
@Transactional
public Collection<Result<EntityKey>> processBulkAction(final BulkAction bulkAction) {
// TODO Auto-generated method stub
return Collections.emptyList();
public Collection<Result<EntityKey>> delete(final Set<EntityKey> all) {
final List<Long> ids = extractIdsFromKeys(all);
try {
this.examRecordMapper.deleteByExample()
.where(ExamRecordDynamicSqlSupport.id, isIn(ids))
.build()
.execute();
return ids.stream()
.map(id -> Result.of(new EntityKey(id, EntityType.EXAM)))
.collect(Collectors.toList());
} catch (final Exception e) {
return ids.stream()
.map(id -> Result.<EntityKey> ofError(new RuntimeException(
"Deletion failed on unexpected exception for Exam of id: " + id, e)))
.collect(Collectors.toList());
}
}
@Override
@Transactional(readOnly = true)
public Set<EntityKey> getDependencies(final BulkAction bulkAction) {
// define the select function in case of source type
final Function<EntityKey, Result<Collection<EntityKey>>> selectionFunction =
(bulkAction.sourceType == EntityType.INSTITUTION)
? this::allIdsOfInstitution
: (bulkAction.sourceType == EntityType.LMS_SETUP)
? this::allIdsOfLmsSetup
: key -> Result.of(Collections.emptyList()); // else : empty select function
return getDependencies(bulkAction, selectionFunction);
}
@Override
@Transactional(readOnly = true)
public Result<Collection<Exam>> bulkLoadEntities(final Collection<EntityKey> keys) {
return Result.tryCatch(() -> {
final List<Long> ids = extractIdsFromKeys(keys);
return this.examRecordMapper.selectByExample()
.where(ExamRecordDynamicSqlSupport.id, isIn(ids))
.build()
.execute();
}).flatMap(this::toDomainModel);
}
private Result<Collection<EntityKey>> allIdsOfInstitution(final EntityKey institutionKey) {
return Result.tryCatch(() -> {
return this.examRecordMapper.selectIdsByExample()
.where(ExamRecordDynamicSqlSupport.institutionId,
isEqualTo(Long.valueOf(institutionKey.entityId)))
.build()
.execute()
.stream()
.map(id -> new EntityKey(id, EntityType.LMS_SETUP))
.collect(Collectors.toList());
});
}
private Result<Collection<EntityKey>> allIdsOfLmsSetup(final EntityKey lmsSetupKey) {
return Result.tryCatch(() -> {
return this.examRecordMapper.selectIdsByExample()
.where(ExamRecordDynamicSqlSupport.lmsSetupId,
isEqualTo(Long.valueOf(lmsSetupKey.entityId)))
.build()
.execute()
.stream()
.map(id -> new EntityKey(id, EntityType.LMS_SETUP))
.collect(Collectors.toList());
});
}
private Result<ExamRecord> recordById(final Long id) {

View file

@ -11,7 +11,6 @@ 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 java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
@ -27,7 +26,6 @@ import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import ch.ethz.seb.sebserver.gbl.model.Entity;
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
import ch.ethz.seb.sebserver.gbl.model.EntityType;
import ch.ethz.seb.sebserver.gbl.model.institution.Institution;
@ -37,14 +35,13 @@ import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.InstitutionRecord
import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.InstitutionRecordMapper;
import ch.ethz.seb.sebserver.webservice.datalayer.batis.model.InstitutionRecord;
import ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.BulkAction;
import ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.BulkActionSupport;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.InstitutionDAO;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ResourceNotFoundException;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.TransactionHandler;
@Lazy
@Component
public class InstitutionDAOImpl implements InstitutionDAO, BulkActionSupport {
public class InstitutionDAOImpl implements InstitutionDAO {
private final InstitutionRecordMapper institutionRecordMapper;
@ -126,9 +123,7 @@ public class InstitutionDAOImpl implements InstitutionDAO, BulkActionSupport {
@Override
@Transactional
public Collection<Result<EntityKey>> setActive(final Set<EntityKey> all, final boolean active) {
final Collection<Result<EntityKey>> result = new ArrayList<>();
final List<Long> ids = extractIdsFromKeys(all, result);
final List<Long> ids = extractIdsFromKeys(all);
final InstitutionRecord institutionRecord = new InstitutionRecord(
null, null, null, BooleanUtils.toInteger(active), null);
@ -152,8 +147,7 @@ public class InstitutionDAOImpl implements InstitutionDAO, BulkActionSupport {
@Override
@Transactional
public Collection<Result<EntityKey>> delete(final Set<EntityKey> all) {
final Collection<Result<EntityKey>> result = new ArrayList<>();
final List<Long> ids = extractIdsFromKeys(all, result);
final List<Long> ids = extractIdsFromKeys(all);
try {
this.institutionRecordMapper.deleteByExample()
@ -181,10 +175,9 @@ public class InstitutionDAOImpl implements InstitutionDAO, BulkActionSupport {
@Override
@Transactional(readOnly = true)
public Result<Collection<Entity>> bulkLoadEntities(final Collection<EntityKey> keys) {
public Result<Collection<Institution>> bulkLoadEntities(final Collection<EntityKey> keys) {
return Result.tryCatch(() -> {
final Collection<Result<EntityKey>> result = new ArrayList<>();
final List<Long> ids = extractIdsFromKeys(keys, result);
final List<Long> ids = extractIdsFromKeys(keys);
return this.institutionRecordMapper.selectByExample()
.where(InstitutionRecordDynamicSqlSupport.id, isIn(ids))
@ -197,25 +190,6 @@ public class InstitutionDAOImpl implements InstitutionDAO, BulkActionSupport {
});
}
@Override
@Transactional
public Collection<Result<EntityKey>> processBulkAction(final BulkAction bulkAction) {
final Set<EntityKey> all = bulkAction.extractKeys(EntityType.INSTITUTION);
switch (bulkAction.type) {
case ACTIVATE:
return setActive(all, true);
case DEACTIVATE:
return setActive(all, false);
case HARD_DELETE:
return delete(all);
}
// should never happen
throw new UnsupportedOperationException("Unsupported Bulk Action: " + bulkAction);
}
private Result<InstitutionRecord> recordById(final Long id) {
return Result.tryCatch(() -> {
final InstitutionRecord record = this.institutionRecordMapper.selectByPrimaryKey(id);

View file

@ -11,10 +11,8 @@ package ch.ethz.seb.sebserver.webservice.servicelayer.dao.impl;
import static ch.ethz.seb.sebserver.gbl.util.Utils.toSQLWildcard;
import static org.mybatis.dynamic.sql.SqlBuilder.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.function.Predicate;
@ -23,13 +21,10 @@ import java.util.stream.Collectors;
import org.apache.commons.lang3.BooleanUtils;
import org.mybatis.dynamic.sql.select.MyBatis3SelectModelAdapter;
import org.mybatis.dynamic.sql.select.QueryExpressionDSL;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import ch.ethz.seb.sebserver.gbl.model.Entity;
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
import ch.ethz.seb.sebserver.gbl.model.EntityType;
import ch.ethz.seb.sebserver.gbl.model.institution.LmsSetup;
@ -39,16 +34,13 @@ import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.LmsSetupRecordDyn
import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.LmsSetupRecordMapper;
import ch.ethz.seb.sebserver.webservice.datalayer.batis.model.LmsSetupRecord;
import ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.BulkAction;
import ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.BulkActionSupport;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.LmsSetupDAO;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ResourceNotFoundException;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.TransactionHandler;
@Lazy
@Component
public class LmsSetupDAOImpl implements LmsSetupDAO, BulkActionSupport {
private static final Logger log = LoggerFactory.getLogger(LmsSetupDAOImpl.class);
public class LmsSetupDAOImpl implements LmsSetupDAO {
private final LmsSetupRecordMapper lmsSetupRecordMapper;
@ -105,9 +97,15 @@ public class LmsSetupDAOImpl implements LmsSetupDAO, BulkActionSupport {
final String _lmsType = (lmsType != null) ? lmsType.name() : null;
return this.lmsSetupRecordMapper
.selectByExample()
.where(LmsSetupRecordDynamicSqlSupport.institutionId, isEqualToWhenPresent(institutionId))
.and(LmsSetupRecordDynamicSqlSupport.name, isLikeWhenPresent(toSQLWildcard(name)))
.and(LmsSetupRecordDynamicSqlSupport.lmsType, isEqualToWhenPresent(_lmsType))
.where(
LmsSetupRecordDynamicSqlSupport.institutionId,
isEqualToWhenPresent(institutionId))
.and(
LmsSetupRecordDynamicSqlSupport.name,
isLikeWhenPresent(toSQLWildcard(name)))
.and(
LmsSetupRecordDynamicSqlSupport.lmsType,
isEqualToWhenPresent(_lmsType))
.and(
LmsSetupRecordDynamicSqlSupport.active,
isEqualToWhenPresent(BooleanUtils.toIntegerObject(active)))
@ -139,9 +137,7 @@ public class LmsSetupDAOImpl implements LmsSetupDAO, BulkActionSupport {
@Override
@Transactional
public Collection<Result<EntityKey>> setActive(final Set<EntityKey> all, final boolean active) {
final Collection<Result<EntityKey>> result = new ArrayList<>();
final List<Long> ids = extractIdsFromKeys(all, result);
final List<Long> ids = extractIdsFromKeys(all);
final LmsSetupRecord lmsSetupRecord = new LmsSetupRecord(
null, null, null, null, null, null, null, null, null, null,
BooleanUtils.toIntegerObject(active));
@ -166,9 +162,7 @@ public class LmsSetupDAOImpl implements LmsSetupDAO, BulkActionSupport {
@Override
@Transactional
public Collection<Result<EntityKey>> delete(final Set<EntityKey> all) {
final Collection<Result<EntityKey>> result = new ArrayList<>();
final List<Long> ids = extractIdsFromKeys(all, result);
final List<Long> ids = extractIdsFromKeys(all);
try {
this.lmsSetupRecordMapper.deleteByExample()
@ -192,23 +186,7 @@ public class LmsSetupDAOImpl implements LmsSetupDAO, BulkActionSupport {
public Set<EntityKey> getDependencies(final BulkAction bulkAction) {
// all of institution
if (bulkAction.sourceType == EntityType.INSTITUTION) {
final Set<EntityKey> result = new HashSet<>();
for (final EntityKey sourceKey : bulkAction.sources) {
try {
result.addAll(this.lmsSetupRecordMapper.selectIdsByExample()
.where(LmsSetupRecordDynamicSqlSupport.institutionId,
isEqualTo(Long.valueOf(sourceKey.entityId)))
.build()
.execute()
.stream()
.map(id -> new EntityKey(id, EntityType.LMS_SETUP))
.collect(Collectors.toList()));
} catch (final Exception e) {
log.error("Unexpected error: ", e);
return Collections.emptySet();
}
}
return result;
return getDependencies(bulkAction, this::allIdsOfInstitution);
}
return Collections.emptySet();
@ -216,10 +194,9 @@ public class LmsSetupDAOImpl implements LmsSetupDAO, BulkActionSupport {
@Override
@Transactional(readOnly = true)
public Result<Collection<Entity>> bulkLoadEntities(final Collection<EntityKey> keys) {
public Result<Collection<LmsSetup>> bulkLoadEntities(final Collection<EntityKey> keys) {
return Result.tryCatch(() -> {
final Collection<Result<EntityKey>> result = new ArrayList<>();
final List<Long> ids = extractIdsFromKeys(keys, result);
final List<Long> ids = extractIdsFromKeys(keys);
return this.lmsSetupRecordMapper.selectByExample()
.where(LmsSetupRecordDynamicSqlSupport.id, isIn(ids))
@ -232,22 +209,17 @@ public class LmsSetupDAOImpl implements LmsSetupDAO, BulkActionSupport {
});
}
@Override
@Transactional
public Collection<Result<EntityKey>> processBulkAction(final BulkAction bulkAction) {
final Set<EntityKey> all = bulkAction.extractKeys(EntityType.LMS_SETUP);
switch (bulkAction.type) {
case ACTIVATE:
return setActive(all, true);
case DEACTIVATE:
return setActive(all, false);
case HARD_DELETE:
return delete(all);
}
// should never happen
throw new UnsupportedOperationException("Unsupported Bulk Action: " + bulkAction);
private Result<Collection<EntityKey>> allIdsOfInstitution(final EntityKey institutionKey) {
return Result.tryCatch(() -> {
return this.lmsSetupRecordMapper.selectIdsByExample()
.where(LmsSetupRecordDynamicSqlSupport.institutionId,
isEqualTo(Long.valueOf(institutionKey.entityId)))
.build()
.execute()
.stream()
.map(id -> new EntityKey(id, EntityType.LMS_SETUP))
.collect(Collectors.toList());
});
}
private Result<LmsSetupRecord> recordById(final Long id) {

View file

@ -10,7 +10,6 @@ package ch.ethz.seb.sebserver.webservice.servicelayer.dao.impl;
import static org.mybatis.dynamic.sql.SqlBuilder.isIn;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Set;
@ -181,9 +180,7 @@ public class UserActivityLogDAOImpl implements UserActivityLogDAO {
@Override
@Transactional
public Collection<Result<EntityKey>> delete(final Set<EntityKey> all) {
final Collection<Result<EntityKey>> result = new ArrayList<>();
final List<Long> ids = extractIdsFromKeys(all, result);
final List<Long> ids = extractIdsFromKeys(all);
try {
this.userLogRecordMapper.deleteByExample()
@ -231,11 +228,14 @@ public class UserActivityLogDAOImpl implements UserActivityLogDAO {
return (institutionId == null)
? this.userLogRecordMapper.selectByExample()
.where(UserActivityLogRecordDynamicSqlSupport.userUuid,
.where(
UserActivityLogRecordDynamicSqlSupport.userUuid,
SqlBuilder.isEqualToWhenPresent(userId))
.and(UserActivityLogRecordDynamicSqlSupport.timestamp,
.and(
UserActivityLogRecordDynamicSqlSupport.timestamp,
SqlBuilder.isGreaterThanOrEqualToWhenPresent(from))
.and(UserActivityLogRecordDynamicSqlSupport.timestamp,
.and(
UserActivityLogRecordDynamicSqlSupport.timestamp,
SqlBuilder.isLessThanWhenPresent(to))
.build()
.execute()
@ -247,15 +247,20 @@ public class UserActivityLogDAOImpl implements UserActivityLogDAO {
: this.userLogRecordMapper.selectByExample()
.join(UserRecordDynamicSqlSupport.userRecord)
.on(UserRecordDynamicSqlSupport.uuid,
.on(
UserRecordDynamicSqlSupport.uuid,
SqlBuilder.equalTo(UserActivityLogRecordDynamicSqlSupport.userUuid))
.where(UserActivityLogRecordDynamicSqlSupport.userUuid,
.where(
UserActivityLogRecordDynamicSqlSupport.userUuid,
SqlBuilder.isEqualToWhenPresent(userId))
.and(UserRecordDynamicSqlSupport.institutionId,
.and(
UserRecordDynamicSqlSupport.institutionId,
SqlBuilder.isEqualToWhenPresent(institutionId))
.and(UserActivityLogRecordDynamicSqlSupport.timestamp,
.and(
UserActivityLogRecordDynamicSqlSupport.timestamp,
SqlBuilder.isGreaterThanOrEqualToWhenPresent(from))
.and(UserActivityLogRecordDynamicSqlSupport.timestamp,
.and(
UserActivityLogRecordDynamicSqlSupport.timestamp,
SqlBuilder.isLessThanWhenPresent(to))
.build()
.execute()
@ -295,7 +300,8 @@ public class UserActivityLogDAOImpl implements UserActivityLogDAO {
public Result<Integer> overwriteUserReferences(final String userUuid, final boolean deactivate) {
return Result.tryCatch(() -> {
final List<UserActivityLogRecord> records = this.userLogRecordMapper.selectByExample()
.where(UserActivityLogRecordDynamicSqlSupport.userUuid,
.where(
UserActivityLogRecordDynamicSqlSupport.userUuid,
SqlBuilder.isEqualTo(userUuid))
.build()
.execute();
@ -317,7 +323,8 @@ public class UserActivityLogDAOImpl implements UserActivityLogDAO {
public Result<Integer> deleteUserEnities(final String userUuid) {
return Result.tryCatch(() -> {
return this.userLogRecordMapper.deleteByExample()
.where(UserActivityLogRecordDynamicSqlSupport.userUuid,
.where(
UserActivityLogRecordDynamicSqlSupport.userUuid,
SqlBuilder.isEqualToWhenPresent(userUuid))
.build()
.execute();

View file

@ -11,10 +11,8 @@ package ch.ethz.seb.sebserver.webservice.servicelayer.dao.impl;
import static ch.ethz.seb.sebserver.gbl.util.Utils.toSQLWildcard;
import static org.mybatis.dynamic.sql.SqlBuilder.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Set;
@ -39,7 +37,6 @@ import org.springframework.transaction.annotation.Transactional;
import ch.ethz.seb.sebserver.WebSecurityConfig;
import ch.ethz.seb.sebserver.gbl.model.APIMessage.APIMessageException;
import ch.ethz.seb.sebserver.gbl.model.APIMessage.ErrorMessage;
import ch.ethz.seb.sebserver.gbl.model.Entity;
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
import ch.ethz.seb.sebserver.gbl.model.EntityType;
import ch.ethz.seb.sebserver.gbl.model.user.UserFilter;
@ -55,13 +52,12 @@ import ch.ethz.seb.sebserver.webservice.datalayer.batis.model.RoleRecord;
import ch.ethz.seb.sebserver.webservice.datalayer.batis.model.UserRecord;
import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.SEBServerUser;
import ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.BulkAction;
import ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.BulkActionSupport;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.TransactionHandler;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.UserDAO;
@Lazy
@Component
public class UserDaoImpl implements UserDAO, BulkActionSupport {
public class UserDaoImpl implements UserDAO {
private static final Logger log = LoggerFactory.getLogger(UserDaoImpl.class);
private static final UserFilter ALL_ACTIVE_ONLY_FILTER = new UserFilter(null, null, null, null, true, null);
@ -195,9 +191,7 @@ public class UserDaoImpl implements UserDAO, BulkActionSupport {
@Override
@Transactional
public Collection<Result<EntityKey>> setActive(final Set<EntityKey> all, final boolean active) {
final Collection<Result<EntityKey>> result = new ArrayList<>();
final List<Long> ids = extractIdsFromKeys(all, result);
final List<Long> ids = extractIdsFromKeys(all);
final UserRecord userRecord = new UserRecord(
null, null, null, null, null, null, null, null, null,
BooleanUtils.toIntegerObject(active));
@ -222,9 +216,7 @@ public class UserDaoImpl implements UserDAO, BulkActionSupport {
@Override
@Transactional
public Collection<Result<EntityKey>> delete(final Set<EntityKey> all) {
final Collection<Result<EntityKey>> result = new ArrayList<>();
final List<Long> ids = extractIdsFromKeys(all, result);
final List<Long> ids = extractIdsFromKeys(all);
try {
this.userRecordMapper.deleteByExample()
@ -245,9 +237,9 @@ public class UserDaoImpl implements UserDAO, BulkActionSupport {
@Override
@Transactional(readOnly = true)
public Collection<EntityKey> getAllUserData(final String uuid) {
public Collection<EntityKey> getAllUserRelatedData(final String uuid) {
// TODO
// TODO get
return Collections.emptyList();
}
@ -257,23 +249,7 @@ public class UserDaoImpl implements UserDAO, BulkActionSupport {
public Set<EntityKey> getDependencies(final BulkAction bulkAction) {
// all of institution
if (bulkAction.sourceType == EntityType.INSTITUTION) {
final Set<EntityKey> result = new HashSet<>();
for (final EntityKey sourceKey : bulkAction.sources) {
try {
result.addAll(this.userRecordMapper.selectIdsByExample()
.where(UserRecordDynamicSqlSupport.institutionId,
isEqualTo(Long.valueOf(sourceKey.entityId)))
.build()
.execute()
.stream()
.map(id -> new EntityKey(id, EntityType.LMS_SETUP))
.collect(Collectors.toList()));
} catch (final Exception e) {
log.error("Unexpected error: ", e);
return Collections.emptySet();
}
}
return result;
return getDependencies(bulkAction, this::allIdsOfInstitution);
}
return Collections.emptySet();
@ -281,10 +257,9 @@ public class UserDaoImpl implements UserDAO, BulkActionSupport {
@Override
@Transactional(readOnly = true)
public Result<Collection<Entity>> bulkLoadEntities(final Collection<EntityKey> keys) {
public Result<Collection<UserInfo>> bulkLoadEntities(final Collection<EntityKey> keys) {
return Result.tryCatch(() -> {
final Collection<Result<EntityKey>> result = new ArrayList<>();
final List<Long> ids = extractIdsFromKeys(keys, result);
final List<Long> ids = extractIdsFromKeys(keys);
return this.userRecordMapper.selectByExample()
.where(InstitutionRecordDynamicSqlSupport.id, isIn(ids))
@ -298,40 +273,21 @@ public class UserDaoImpl implements UserDAO, BulkActionSupport {
}
@Override
@Transactional
public Collection<Result<EntityKey>> processBulkAction(final BulkAction bulkAction) {
final Set<EntityKey> all = bulkAction.extractKeys(EntityType.USER);
switch (bulkAction.type) {
case ACTIVATE:
return setActive(all, true);
case DEACTIVATE:
return setActive(all, false);
case HARD_DELETE:
return delete(all);
}
// should never happen
throw new UnsupportedOperationException("Unsupported Bulk Action: " + bulkAction);
}
@Override
public List<Long> extractIdsFromKeys(
final Collection<EntityKey> keys,
final Collection<Result<EntityKey>> result) {
public List<Long> extractIdsFromKeys(final Collection<EntityKey> keys) {
if (keys == null || keys.isEmpty() || keys.iterator().next().isIdPK) {
return UserDAO.super.extractIdsFromKeys(keys, result);
return UserDAO.super.extractIdsFromKeys(keys);
} else {
final List<String> uuids = keys.stream()
.map(key -> key.entityId)
.collect(Collectors.toList());
try {
return this.userRecordMapper.selectIdsByExample()
.where(UserRecordDynamicSqlSupport.uuid, isIn(uuids))
.build()
.execute();
} catch (final Exception e) {
log.error("Unexpected error: ", e);
return Collections.emptyList();
@ -339,6 +295,19 @@ public class UserDaoImpl implements UserDAO, BulkActionSupport {
}
}
private Result<Collection<EntityKey>> allIdsOfInstitution(final EntityKey institutionKey) {
return Result.tryCatch(() -> {
return this.userRecordMapper.selectIdsByExample()
.where(UserRecordDynamicSqlSupport.institutionId,
isEqualTo(Long.valueOf(institutionKey.entityId)))
.build()
.execute()
.stream()
.map(id -> new EntityKey(id, EntityType.USER))
.collect(Collectors.toList());
});
}
private Result<UserRecord> updateUser(final UserMod userMod) {
return recordByUUID(userMod.uuid)
.map(record -> {

View file

@ -17,4 +17,8 @@ public interface LmsAPIService {
Result<LmsAPITemplate> createLmsAPITemplate(LmsSetup lmsSetup);
Result<byte[]> createSEBStartConfiguration(Long lmsSetupId);
Result<byte[]> createSEBStartConfiguration(LmsSetup lmsSetup);
}

View file

@ -45,4 +45,25 @@ public class LmsAPIServiceImpl implements LmsAPIService {
}
}
@Override
public Result<byte[]> createSEBStartConfiguration(final Long lmsSetupId) {
return this.lmsSetupDAO
.byId(lmsSetupId)
.flatMap(this::createSEBStartConfiguration);
}
@Override
public Result<byte[]> createSEBStartConfiguration(final LmsSetup lmsSetup) {
// TODO implementation of creation of SEB start configuration for specified LmsSetup
// A SEB start configuration should at least contain the SEB-Client-Credentials to access the SEB Server API
// and the SEB Server URL
//
// To Clarify : The format of a SEB start configuration
// To Clarify : How the file should be encrypted (use case) maybe we need another encryption-secret for this that can be given by
// an administrator on SEB start configuration creation time
return Result.ofTODO();
}
}

View file

@ -13,6 +13,7 @@ import java.util.stream.Collectors;
import javax.validation.Valid;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
@ -38,6 +39,7 @@ import ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.BulkActionServic
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.LmsSetupDAO;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.UserActivityLogDAO;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.UserActivityLogDAO.ActivityType;
import ch.ethz.seb.sebserver.webservice.servicelayer.lms.LmsAPIService;
@WebServiceProfile
@RestController
@ -48,17 +50,20 @@ public class LmsSetupController {
private final AuthorizationGrantService authorizationGrantService;
private final UserActivityLogDAO userActivityLogDAO;
private final BulkActionService bulkActionService;
private final LmsAPIService lmsAPIService;
public LmsSetupController(
final LmsSetupDAO lmsSetupDAO,
final AuthorizationGrantService authorizationGrantService,
final UserActivityLogDAO userActivityLogDAO,
final BulkActionService bulkActionService) {
final BulkActionService bulkActionService,
final LmsAPIService lmsAPIService) {
this.lmsSetupDAO = lmsSetupDAO;
this.authorizationGrantService = authorizationGrantService;
this.userActivityLogDAO = userActivityLogDAO;
this.bulkActionService = bulkActionService;
this.lmsAPIService = lmsAPIService;
}
@RequestMapping(method = RequestMethod.GET)
@ -118,6 +123,21 @@ public class LmsSetupController {
.getOrThrow();
}
@RequestMapping(
path = "/create_seb_config/{id}",
method = RequestMethod.GET,
produces = MediaType.APPLICATION_OCTET_STREAM_VALUE) // TODO check if this is the right format
public byte[] createSEBConfig(@PathVariable final Long id) {
this.authorizationGrantService.checkHasAnyPrivilege(
EntityType.LMS_SETUP,
PrivilegeType.WRITE);
return this.lmsAPIService
.createSEBStartConfiguration(id)
.getOrThrow();
}
@RequestMapping(path = "/create", method = RequestMethod.PUT)
public LmsSetup create(@Valid @RequestBody final LmsSetup lmsSetup) {
return save(lmsSetup, PrivilegeType.WRITE)