refactoring EntityController

This commit is contained in:
anhefti 2019-04-11 14:26:05 +02:00
parent 2b3d4aa27d
commit 201e37914e
6 changed files with 107 additions and 46 deletions

View file

@ -104,7 +104,7 @@ public class AuthorizationServiceImpl implements AuthorizationService {
.andForRole(UserRole.INSTITUTIONAL_ADMIN)
.withInstitutionalPrivilege(PrivilegeType.READ)
.andForRole(UserRole.EXAM_ADMIN)
.withInstitutionalPrivilege(PrivilegeType.MODIFY)
.withInstitutionalPrivilege(PrivilegeType.WRITE)
.withOwnerPrivilege(PrivilegeType.WRITE)
.andForRole(UserRole.EXAM_SUPPORTER)
.withInstitutionalPrivilege(PrivilegeType.READ)
@ -117,7 +117,7 @@ public class AuthorizationServiceImpl implements AuthorizationService {
.andForRole(UserRole.INSTITUTIONAL_ADMIN)
.withInstitutionalPrivilege(PrivilegeType.READ)
.andForRole(UserRole.EXAM_ADMIN)
.withInstitutionalPrivilege(PrivilegeType.MODIFY)
.withInstitutionalPrivilege(PrivilegeType.WRITE)
.withOwnerPrivilege(PrivilegeType.WRITE)
.andForRole(UserRole.EXAM_SUPPORTER)
.withInstitutionalPrivilege(PrivilegeType.READ)

View file

@ -11,12 +11,49 @@ package ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction;
import ch.ethz.seb.sebserver.gbl.model.EntityProcessingReport;
import ch.ethz.seb.sebserver.gbl.util.Result;
/** Service to address bulk actions like activation or deletion where the action
* or state-change of one Entity has an effect on other entities that that has
* a relation to the source entity.
* <p>
* A bulk action for a specified entity instance will be first applied to all its dependent
* child-entities. For example if one is going to delete/deactivate a particular LMS Setup, all
* Exams imported from this LMSSetup are first deactivated and all Exam Config Mapping and
* all Client Connection are of all the Exams are deactivated first.
* <p>
* below is the relation-tree of known node-entities of the SEB Server application
* <code>
* Institution
* ____________ / | \______________
* / | \
* LMS Setup | User-Account
* | |
* Exam Configuration
* |\ /
* | Exam Config Mapping
* |
* Client Connection
* </code> */
public interface BulkActionService {
/** Use this to collect all EntityKey's of all dependent entities for a given BulkAction.
*
* @param action the BulkAction defining the source entity keys and acts also as the
* dependency collector */
void collectDependencies(BulkAction action);
/** This executes a given BulkAction by first getting all dependencies and applying
* the action to that first and then applying the action to the source entities of
* the BulkAction.
*
* @param action the BulkAction that defines at least the type and the source entity keys
* @return The BulkAction containing the result of the execution */
Result<BulkAction> doBulkAction(BulkAction action);
/** Creates a EntityProcessingReport from a given BulkAction result.
* If the given BulkAction has not already been executed, it will be executed first
*
* @param action the BulkAction of a concrete type
* @return EntityProcessingReport extracted form an executed BulkAxtion */
Result<EntityProcessingReport> createReport(BulkAction action);
}

View file

@ -336,14 +336,17 @@ public class UserActivityLogDAOImpl implements UserActivityLogDAO {
@Override
@Transactional
public Result<UserActivityLog> save(final UserActivityLog modified) {
// TODO Auto-generated method stub
return Result.ofTODO();
throw new UnsupportedOperationException();
}
@Override
public Result<UserActivityLog> createNew(final UserActivityLog data) {
// TODO Auto-generated method stub
return Result.ofTODO();
return log(
data.activityType,
data.entityType,
data.entityId,
data.message,
data);
}
@Override

View file

@ -40,7 +40,7 @@ import ch.ethz.seb.sebserver.webservice.servicelayer.validation.BeanValidationSe
* @param <T> The concrete Entity domain-model type used on all GET, PUT
* @param <M> The concrete Entity domain-model type used for POST methods (new) */
public abstract class ActivatableEntityController<T extends GrantEntity, M extends GrantEntity>
extends GrantEntityController<T, M> {
extends EntityController<T, M> {
public ActivatableEntityController(
final AuthorizationService authorizationGrantService,

View file

@ -55,7 +55,7 @@ import ch.ethz.seb.sebserver.webservice.servicelayer.validation.BeanValidationSe
*
* @param <T> The concrete Entity domain-model type used on all GET, PUT
* @param <M> The concrete Entity domain-model type used for POST methods (new) */
public abstract class GrantEntityController<T extends GrantEntity, M extends GrantEntity> {
public abstract class EntityController<T extends Entity, M extends Entity> {
protected final AuthorizationService authorization;
protected final BulkActionService bulkActionService;
@ -64,7 +64,7 @@ public abstract class GrantEntityController<T extends GrantEntity, M extends Gra
protected final PaginationService paginationService;
protected final BeanValidationService beanValidationService;
protected GrantEntityController(
protected EntityController(
final AuthorizationService authorization,
final BulkActionService bulkActionService,
final EntityDAO<T, M> entityDAO,
@ -196,7 +196,7 @@ public abstract class GrantEntityController<T extends GrantEntity, M extends Gra
this.entityDAO
.byModelId(modelId)
.flatMap(this.authorization::checkRead);
.map(this::checkReadAccess);
final BulkAction bulkAction = new BulkAction(
bulkActionType,
@ -220,7 +220,7 @@ public abstract class GrantEntityController<T extends GrantEntity, M extends Gra
return this.entityDAO
.byModelId(modelId)
.flatMap(this.authorization::checkRead)
.flatMap(this::checkReadAccess)
.getOrThrow();
}
@ -246,7 +246,7 @@ public abstract class GrantEntityController<T extends GrantEntity, M extends Gra
.flatMap(this.entityDAO::byEntityKeys)
.getOrThrow()
.stream()
.filter(this.authorization::hasReadonlyGrant)
.filter(this::hasReadAccess)
.collect(Collectors.toList());
}
@ -276,7 +276,7 @@ public abstract class GrantEntityController<T extends GrantEntity, M extends Gra
final M requestModel = this.createNew(postMap);
return this.authorization.checkWrite(requestModel)
return this.checkCreateAccess(requestModel)
.flatMap(this::validForCreate)
.flatMap(this.entityDAO::createNew)
.flatMap(this.userActivityLogDAO::logCreate)
@ -294,7 +294,7 @@ public abstract class GrantEntityController<T extends GrantEntity, M extends Gra
produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public T savePut(@Valid @RequestBody final T modifyData) {
return this.authorization.checkModify(modifyData)
return this.checkModifyAccess(modifyData)
.flatMap(this::validForSave)
.flatMap(this.entityDAO::save)
.flatMap(this.userActivityLogDAO::logModify)
@ -302,35 +302,6 @@ public abstract class GrantEntityController<T extends GrantEntity, M extends Gra
.getOrThrow();
}
// ******************
// * PATCH (save)
// ******************
// NOTE: not supported yet because of difficulties on conversion of params-map to json object
// @RequestMapping(
// path = "/{id}",
// method = RequestMethod.PATCH,
// consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE,
// produces = MediaType.APPLICATION_JSON_VALUE)
// public T savePost(
// @PathVariable final String id,
// @RequestParam final MultiValueMap<String, String> allRequestParams,
// @RequestParam(
// name = Entity.FILTER_ATTR_INSTITUTION,
// required = true,
// defaultValue = UserService.USERS_INSTITUTION_AS_DEFAULT) final Long institutionId) {
//
// allRequestParams.putIfAbsent(
// Domain.ATTR_INSTITUTION_ID,
// Arrays.asList(String.valueOf(institutionId)));
// final M requestModel = this.toRequestModel(null, allRequestParams);
//
// return this.entityDAO.save(id, requestModel)
// .flatMap(entity -> this.userActivityLogDAO.log(ActivityType.MODIFY, entity))
// .flatMap(entity -> notifySaved(requestModel, entity))
// .getOrThrow();
// }
// ******************
// * DELETE (delete)
// ******************
@ -347,7 +318,7 @@ public abstract class GrantEntityController<T extends GrantEntity, M extends Gra
new EntityKey(modelId, entityType));
return this.entityDAO.byModelId(modelId)
.flatMap(this.authorization::checkWrite)
.flatMap(this::checkWriteAccess)
.flatMap(entity -> this.bulkActionService.createReport(bulkAction))
.getOrThrow();
}
@ -362,7 +333,7 @@ public abstract class GrantEntityController<T extends GrantEntity, M extends Gra
protected Result<Collection<T>> getAll(final FilterMap filterMap) {
return this.entityDAO.allMatching(
filterMap,
this.authorization::hasReadonlyGrant);
this::hasReadAccess);
}
protected Result<T> notifyCreated(final T entity) {
@ -390,6 +361,56 @@ public abstract class GrantEntityController<T extends GrantEntity, M extends Gra
return Result.of(entity);
}
private Result<T> checkReadAccess(final T entity) {
final GrantEntity grantEntity = toGrantEntity(entity);
if (grantEntity != null) {
this.authorization.checkRead(grantEntity);
}
return Result.of(entity);
}
private boolean hasReadAccess(final T entity) {
final GrantEntity grantEntity = toGrantEntity(entity);
if (grantEntity != null) {
return this.authorization.hasReadonlyGrant(grantEntity);
}
return true;
}
private Result<T> checkModifyAccess(final T entity) {
final GrantEntity grantEntity = toGrantEntity(entity);
if (grantEntity != null) {
this.authorization.checkModify(grantEntity);
}
return Result.of(entity);
}
private Result<T> checkWriteAccess(final T entity) {
final GrantEntity grantEntity = toGrantEntity(entity);
if (grantEntity != null) {
this.authorization.checkWrite(grantEntity);
}
return Result.of(entity);
}
private Result<M> checkCreateAccess(final M entity) {
final GrantEntity grantEntity = toGrantEntity(entity);
if (grantEntity != null) {
this.authorization.checkWrite(grantEntity);
}
return Result.of(entity);
}
protected GrantEntity toGrantEntity(final Entity entity) {
if (entity instanceof GrantEntity) {
return (GrantEntity) entity;
}
throw new IllegalArgumentException("Entity instance is not of type GrantEntity. "
+ "Do override the toGrantEntity method from EntityController within the specific -Controller implementation");
}
protected abstract M createNew(POSTMapper postParams);
protected abstract SqlTable getSQLTableOfEntity();

View file

@ -29,7 +29,7 @@ import ch.ethz.seb.sebserver.webservice.servicelayer.validation.BeanValidationSe
@WebServiceProfile
@RestController
@RequestMapping("/${sebserver.webservice.api.admin.endpoint}" + API.EXAM_INDICATOR_ENDPOINT)
public class IndicatorController extends GrantEntityController<Indicator, Indicator> {
public class IndicatorController extends EntityController<Indicator, Indicator> {
private final ExamDAO examDao;