diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/UserActivityLogDAO.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/UserActivityLogDAO.java index 299caaa2..1586410e 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/UserActivityLogDAO.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/UserActivityLogDAO.java @@ -12,6 +12,7 @@ import java.util.Collection; import java.util.function.Predicate; import ch.ethz.seb.sebserver.gbl.model.Entity; +import ch.ethz.seb.sebserver.gbl.model.EntityType; import ch.ethz.seb.sebserver.gbl.model.user.UserActivityLog; import ch.ethz.seb.sebserver.gbl.util.Result; import ch.ethz.seb.sebserver.webservice.datalayer.batis.model.UserActivityLogRecord; @@ -30,41 +31,48 @@ public interface UserActivityLogDAO extends UserRelatedEntityDAO Result logUserActivity(ActivityType actionType, E entity, String message); + Result log(ActivityType activityType, E entity, String message); /** Creates a user activity log entry for the current user. * * @param actionType the action type * @param entity the Entity */ - Result logUserActivity(ActivityType actionType, E entity); + Result log(ActivityType activityType, E entity); + + /** Creates a user activity log entry for the current user. + * + * @param activityType the activity type + * @param entityType the EntityType + * @param message the message */ + void log(ActivityType activityType, EntityType entityType, String entityId, String message); /** Creates a user activity log entry. * * @param user for specified SEBServerUser instance - * @param actionType the action type + * @param activityType the activity type * @param entity the Entity * @param message an optional message */ - Result logUserActivity( + Result log( SEBServerUser user, - ActivityType actionType, + ActivityType activityType, E entity, String message); /** Creates a user activity log entry. * * @param user for specified SEBServerUser instance - * @param actionType the action type + * @param activityType the activity type * @param entityType the entity type * @param entityId the entity id (primary key or UUID) */ - default Result logUserActivity( + default Result log( final SEBServerUser user, - final ActivityType actionType, + final ActivityType activityType, final E entity) { - return logUserActivity(user, actionType, entity, null); + return log(user, activityType, entity, null); } Result> all( diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/UserActivityLogDAOImpl.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/UserActivityLogDAOImpl.java index 28acc387..2c357b96 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/UserActivityLogDAOImpl.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/UserActivityLogDAOImpl.java @@ -19,11 +19,10 @@ import org.slf4j.LoggerFactory; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; -import org.springframework.transaction.interceptor.TransactionInterceptor; import org.springframework.util.CollectionUtils; -import ch.ethz.seb.sebserver.gbl.model.EntityProcessingReport; import ch.ethz.seb.sebserver.gbl.model.Entity; +import ch.ethz.seb.sebserver.gbl.model.EntityProcessingReport; import ch.ethz.seb.sebserver.gbl.model.EntityType; import ch.ethz.seb.sebserver.gbl.model.user.UserActivityLog; import ch.ethz.seb.sebserver.gbl.util.Result; @@ -64,55 +63,85 @@ public class UserActivityLogDAOImpl implements UserActivityLogDAO { } @Override - public Result logUserActivity( - final ActivityType actionType, + @Transactional + public Result log( + final ActivityType activityType, final E entity, final String message) { - return logUserActivity(this.userService.getCurrentUser(), actionType, entity, message); - } - - @Override - public Result logUserActivity(final ActivityType actionType, final E entity) { - return logUserActivity(this.userService.getCurrentUser(), actionType, entity, null); + return log(this.userService.getCurrentUser(), activityType, entity, message); } @Override @Transactional - public Result logUserActivity( + public Result log(final ActivityType activityType, final E entity) { + return log(this.userService.getCurrentUser(), activityType, entity, null); + } + + @Override + @Transactional + public void log( + final ActivityType activityType, + final EntityType entityType, + final String entityId, + final String message) { + + try { + log( + this.userService.getCurrentUser(), + activityType, + entityType, + entityId, + message); + } catch (final Exception e) { + log.error( + "Unexpected error while trying to log user activity for user {}, action-type: {} entity-type: {} entity-id: {}", + this.userService.getCurrentUser(), + activityType, + entityType, + entityId, + e); + TransactionHandler.rollback(); + } + } + + @Override + @Transactional + public Result log( final SEBServerUser user, final ActivityType activityType, final E entity, final String message) { - try { + return Result.tryCatch(() -> { + log(user, activityType, entity.entityType(), entity.getModelId(), message); + return entity; + }) + .onErrorDo(TransactionHandler::rollback) + .onErrorDo(t -> log.error( + "Unexpected error while trying to log user activity for user {}, action-type: {} entity-type: {} entity-id: {}", + user.getUserInfo().uuid, + activityType, + entity.entityType().name(), + entity.getModelId(), + t)); + } - this.userLogRecordMapper.insertSelective(new UserActivityLogRecord( - null, - user.getUserInfo().uuid, - System.currentTimeMillis(), - activityType.name(), - entity.entityType().name(), - entity.getModelId(), - message)); + private void log( + final SEBServerUser user, + final ActivityType activityType, + final EntityType entityType, + final String entityId, + final String message) { - return Result.of(entity); - - } catch (final Throwable t) { - - log.error( - "Unexpected error while trying to log user activity for user {}, action-type: {} entity-type: {} entity-id: {}", - user.getUserInfo().uuid, - activityType, - entity.entityType().name(), - entity.getModelId(), - t); - TransactionInterceptor - .currentTransactionStatus() - .setRollbackOnly(); - return Result.ofError(t); - - } + this.userLogRecordMapper.insertSelective(new UserActivityLogRecord( + null, + user.getUserInfo().uuid, + System.currentTimeMillis(), + activityType.name(), + entityType.name(), + entityId, + message)); } @Override @@ -169,7 +198,8 @@ public class UserActivityLogDAOImpl implements UserActivityLogDAO { SqlBuilder.isEqualToWhenPresent(userId)) .and(UserActivityLogRecordDynamicSqlSupport.timestamp, SqlBuilder.isGreaterThanOrEqualToWhenPresent(from)) - .and(UserActivityLogRecordDynamicSqlSupport.timestamp, SqlBuilder.isLessThanWhenPresent(to)) + .and(UserActivityLogRecordDynamicSqlSupport.timestamp, + SqlBuilder.isLessThanWhenPresent(to)) .build() .execute() .stream() @@ -188,7 +218,8 @@ public class UserActivityLogDAOImpl implements UserActivityLogDAO { SqlBuilder.isEqualToWhenPresent(institutionId)) .and(UserActivityLogRecordDynamicSqlSupport.timestamp, SqlBuilder.isGreaterThanOrEqualToWhenPresent(from)) - .and(UserActivityLogRecordDynamicSqlSupport.timestamp, SqlBuilder.isLessThanWhenPresent(to)) + .and(UserActivityLogRecordDynamicSqlSupport.timestamp, + SqlBuilder.isLessThanWhenPresent(to)) .build() .execute() .stream() @@ -215,7 +246,8 @@ public class UserActivityLogDAOImpl implements UserActivityLogDAO { public Result overwriteUserReferences(final String userUuid, final boolean deactivate) { return Result.tryCatch(() -> { final List records = this.userLogRecordMapper.selectByExample() - .where(UserActivityLogRecordDynamicSqlSupport.userUuid, SqlBuilder.isEqualTo(userUuid)) + .where(UserActivityLogRecordDynamicSqlSupport.userUuid, + SqlBuilder.isEqualTo(userUuid)) .build() .execute(); @@ -236,7 +268,8 @@ public class UserActivityLogDAOImpl implements UserActivityLogDAO { public Result deleteUserEnities(final String userUuid) { return Result.tryCatch(() -> { return this.userLogRecordMapper.deleteByExample() - .where(UserActivityLogRecordDynamicSqlSupport.userUuid, SqlBuilder.isEqualToWhenPresent(userUuid)) + .where(UserActivityLogRecordDynamicSqlSupport.userUuid, + SqlBuilder.isEqualToWhenPresent(userUuid)) .build() .execute(); }); diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/UserAccountController.java b/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/UserAccountController.java index 526b3bf3..abf7127a 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/UserAccountController.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/UserAccountController.java @@ -148,18 +148,22 @@ public class UserAccountController { @RequestMapping(value = "/{uuid}/activate", method = RequestMethod.POST) public UserInfo activateUser(@PathVariable final String uuid) { - return setActivity(uuid, true); + return setActive(uuid, true); } @RequestMapping(value = "/{uuid}/deactivate", method = RequestMethod.POST) public UserInfo deactivateUser(@PathVariable final String uuid) { - return setActivity(uuid, false); + return setActive(uuid, false); } @RequestMapping(value = "/{uuid}/delete", method = RequestMethod.DELETE) public EntityProcessingReport deleteUser(@PathVariable final String uuid) { return this.userDao.pkForUUID(uuid) .flatMap(pk -> this.userDao.delete(pk, true)) + .map(report -> { + this.userActivityLogDAO.log(ActivityType.DELETE, EntityType.USER, uuid, "soft"); + return report; + }) .getOrThrow(); } @@ -167,6 +171,10 @@ public class UserAccountController { public EntityProcessingReport hardDeleteUser(@PathVariable final String uuid) { return this.userDao.pkForUUID(uuid) .flatMap(pk -> this.userDao.delete(pk, false)) + .map(report -> { + this.userActivityLogDAO.log(ActivityType.DELETE, EntityType.USER, uuid, "hard"); + return report; + }) .getOrThrow(); } @@ -176,27 +184,33 @@ public class UserAccountController { .getOrThrow(); } - private UserInfo setActivity(final String uuid, final boolean activity) { + private UserInfo setActive(final String uuid, final boolean active) { + + final ActivityType activityType = (active) + ? ActivityType.ACTIVATE + : ActivityType.DEACTIVATE; + return this.userDao.byUuid(uuid) .flatMap(userInfo -> this.authorizationGrantService.checkGrantOnEntity(userInfo, PrivilegeType.WRITE)) - .flatMap(userInfo -> this.userDao.setActive(userInfo.uuid, activity)) + .flatMap(userInfo -> this.userDao.setActive(userInfo.uuid, active)) .map(userInfo -> { - this.applicationEventPublisher.publishEvent(new EntityActivationEvent(userInfo, activity)); + this.applicationEventPublisher.publishEvent(new EntityActivationEvent(userInfo, active)); return userInfo; }) + .flatMap(userInfo -> this.userActivityLogDAO.log(activityType, userInfo)) .getOrThrow(); } private Result _saveUser(final UserMod userData, final PrivilegeType privilegeType) { - final ActivityType actionType = (userData.uuid == null) + final ActivityType activityType = (userData.uuid == null) ? ActivityType.CREATE : ActivityType.MODIFY; return this.authorizationGrantService .checkGrantOnEntity(userData, privilegeType) .flatMap(this.userDao::save) - .flatMap(userInfo -> this.userActivityLogDAO.logUserActivity(actionType, userInfo)) + .flatMap(userInfo -> this.userActivityLogDAO.log(activityType, userInfo)) .flatMap(userInfo -> { // handle password change; revoke access tokens if password has changed if (userData.passwordChangeRequest() && userData.newPasswordMatch()) {