Added swagger docs for users, principal and locks

This commit is contained in:
Thomas Georgios Giannos 2024-07-08 10:00:37 +03:00
parent a2540e5300
commit bba4834e21
8 changed files with 1002 additions and 59 deletions

View File

@ -1,10 +1,9 @@
package org.opencdmp.query.lookup; package org.opencdmp.query.lookup;
import org.opencdmp.commons.enums.LockTargetType;
import org.opencdmp.query.LockQuery;
import gr.cite.tools.data.query.Lookup; import gr.cite.tools.data.query.Lookup;
import gr.cite.tools.data.query.QueryFactory; import gr.cite.tools.data.query.QueryFactory;
import org.opencdmp.commons.enums.LockTargetType;
import org.opencdmp.query.LockQuery;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
@ -20,8 +19,8 @@ public class LockLookup extends Lookup {
private List<LockTargetType> targetTypes; private List<LockTargetType> targetTypes;
private List<UUID> excludedIds; private List<UUID> excludedIds;
private List<UUID> userIds;
private List<UUID> userIds;
public String getLike() { public String getLike() {
return like; return like;
@ -73,12 +72,18 @@ public class LockLookup extends Lookup {
public LockQuery enrich(QueryFactory queryFactory) { public LockQuery enrich(QueryFactory queryFactory) {
LockQuery query = queryFactory.query(LockQuery.class); LockQuery query = queryFactory.query(LockQuery.class);
if (this.like != null) query.like(this.like); if (this.like != null)
if (this.ids != null) query.ids(this.ids); query.like(this.like);
if (this.targetIds != null) query.targetIds(this.targetIds); if (this.ids != null)
if (this.targetTypes != null) query.targetTypes(this.targetTypes); query.ids(this.ids);
if (this.excludedIds != null) query.excludedIds(this.excludedIds); if (this.targetIds != null)
if (this.userIds != null) query.userIds(this.userIds); query.targetIds(this.targetIds);
if (this.targetTypes != null)
query.targetTypes(this.targetTypes);
if (this.excludedIds != null)
query.excludedIds(this.excludedIds);
if (this.userIds != null)
query.userIds(this.userIds);
this.enrichCommon(query); this.enrichCommon(query);

View File

@ -1,9 +1,9 @@
package org.opencdmp.query.lookup; package org.opencdmp.query.lookup;
import org.opencdmp.commons.enums.IsActive;
import org.opencdmp.query.UserQuery;
import gr.cite.tools.data.query.Lookup; import gr.cite.tools.data.query.Lookup;
import gr.cite.tools.data.query.QueryFactory; import gr.cite.tools.data.query.QueryFactory;
import org.opencdmp.commons.enums.IsActive;
import org.opencdmp.query.UserQuery;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
@ -13,11 +13,15 @@ public class UserLookup extends Lookup {
private String like; private String like;
private List<UUID> ids; private List<UUID> ids;
private List<String> emails; private List<String> emails;
private List<UUID> excludedIds; private List<UUID> excludedIds;
private List<IsActive> isActive; private List<IsActive> isActive;
private UserRoleLookup userRoleSubQuery; private UserRoleLookup userRoleSubQuery;
private TenantUserLookup tenantUserSubQuery; private TenantUserLookup tenantUserSubQuery;
public String getLike() { public String getLike() {
@ -78,13 +82,20 @@ public class UserLookup extends Lookup {
public UserQuery enrich(QueryFactory queryFactory) { public UserQuery enrich(QueryFactory queryFactory) {
UserQuery query = queryFactory.query(UserQuery.class); UserQuery query = queryFactory.query(UserQuery.class);
if (this.like != null) query.like(this.like); if (this.like != null)
if (this.ids != null) query.ids(this.ids); query.like(this.like);
if (this.emails != null) query.emails(this.emails); if (this.ids != null)
if (this.userRoleSubQuery != null) query.userRoleSubQuery(this.userRoleSubQuery.enrich(queryFactory)); query.ids(this.ids);
if (this.tenantUserSubQuery != null) query.tenantUserSubQuery(this.tenantUserSubQuery.enrich(queryFactory)); if (this.emails != null)
if (this.excludedIds != null) query.excludedIds(this.excludedIds); query.emails(this.emails);
if (this.isActive != null) query.isActive(this.isActive); if (this.userRoleSubQuery != null)
query.userRoleSubQuery(this.userRoleSubQuery.enrich(queryFactory));
if (this.tenantUserSubQuery != null)
query.tenantUserSubQuery(this.tenantUserSubQuery.enrich(queryFactory));
if (this.excludedIds != null)
query.excludedIds(this.excludedIds);
if (this.isActive != null)
query.isActive(this.isActive);
this.enrichCommon(query); this.enrichCommon(query);

View File

@ -12,6 +12,13 @@ import gr.cite.tools.fieldset.FieldSet;
import gr.cite.tools.logging.LoggerService; import gr.cite.tools.logging.LoggerService;
import gr.cite.tools.logging.MapLogEntry; import gr.cite.tools.logging.MapLogEntry;
import gr.cite.tools.validation.ValidationFilterAnnotation; import gr.cite.tools.validation.ValidationFilterAnnotation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.ArraySchema;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.ExampleObject;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.transaction.Transactional; import jakarta.transaction.Transactional;
import org.opencdmp.audit.AuditableAction; import org.opencdmp.audit.AuditableAction;
import org.opencdmp.authorization.AffiliatedResource; import org.opencdmp.authorization.AffiliatedResource;
@ -19,6 +26,11 @@ import org.opencdmp.authorization.AuthorizationFlags;
import org.opencdmp.authorization.Permission; import org.opencdmp.authorization.Permission;
import org.opencdmp.authorization.authorizationcontentresolver.AuthorizationContentResolver; import org.opencdmp.authorization.authorizationcontentresolver.AuthorizationContentResolver;
import org.opencdmp.commons.enums.LockTargetType; import org.opencdmp.commons.enums.LockTargetType;
import org.opencdmp.controllers.swagger.SwaggerHelpers;
import org.opencdmp.controllers.swagger.annotation.OperationWithTenantHeader;
import org.opencdmp.controllers.swagger.annotation.Swagger400;
import org.opencdmp.controllers.swagger.annotation.Swagger404;
import org.opencdmp.controllers.swagger.annotation.SwaggerCommonErrorResponses;
import org.opencdmp.data.LockEntity; import org.opencdmp.data.LockEntity;
import org.opencdmp.model.Lock; import org.opencdmp.model.Lock;
import org.opencdmp.model.LockStatus; import org.opencdmp.model.LockStatus;
@ -26,6 +38,7 @@ import org.opencdmp.model.builder.LockBuilder;
import org.opencdmp.model.censorship.LockCensor; import org.opencdmp.model.censorship.LockCensor;
import org.opencdmp.model.persist.LockPersist; import org.opencdmp.model.persist.LockPersist;
import org.opencdmp.model.result.QueryResult; import org.opencdmp.model.result.QueryResult;
import org.opencdmp.model.user.User;
import org.opencdmp.query.LockQuery; import org.opencdmp.query.LockQuery;
import org.opencdmp.query.lookup.LockLookup; import org.opencdmp.query.lookup.LockLookup;
import org.opencdmp.service.lock.LockService; import org.opencdmp.service.lock.LockService;
@ -49,6 +62,8 @@ import java.util.UUID;
@RestController @RestController
@RequestMapping(path = "api/lock") @RequestMapping(path = "api/lock")
@Tag(name = "Locks", description = "Manage locked entities")
@SwaggerCommonErrorResponses
public class LockController { public class LockController {
private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(LockController.class)); private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(LockController.class));
@ -66,7 +81,9 @@ public class LockController {
private final MessageSource messageSource; private final MessageSource messageSource;
private final AuthorizationService authService; private final AuthorizationService authService;
private final AuthorizationContentResolver authorizationContentResolver; private final AuthorizationContentResolver authorizationContentResolver;
@Autowired @Autowired
public LockController(BuilderFactory builderFactory, public LockController(BuilderFactory builderFactory,
AuditService auditService, AuditService auditService,
@ -81,10 +98,29 @@ public class LockController {
this.queryFactory = queryFactory; this.queryFactory = queryFactory;
this.messageSource = messageSource; this.messageSource = messageSource;
this.authService = authService; this.authService = authService;
this.authorizationContentResolver = authorizationContentResolver; this.authorizationContentResolver = authorizationContentResolver;
} }
@PostMapping("query") @PostMapping("query")
@OperationWithTenantHeader(summary = "Query all locked entities", description = SwaggerHelpers.Lock.endpoint_query, requestBody = @io.swagger.v3.oas.annotations.parameters.RequestBody(description = SwaggerHelpers.Lock.endpoint_query_request_body, content = @Content(
examples = {
@ExampleObject(
name = "Pagination and projection",
description = "Simple paginated request using a property projection list and pagination info",
value = SwaggerHelpers.Lock.endpoint_query_request_body_example
)
}
)), responses = @ApiResponse(description = "OK", responseCode = "200", content = @Content(
array = @ArraySchema(
schema = @Schema(
implementation = Lock.class
)
),
examples = @ExampleObject(
name = "First page",
description = "Example with the first page of paginated results",
value = SwaggerHelpers.Lock.endpoint_query_response_example
))))
public QueryResult<Lock> query(@RequestBody LockLookup lookup) throws MyApplicationException, MyForbiddenException, InvalidAlgorithmParameterException, NoSuchPaddingException, IllegalBlockSizeException, NoSuchAlgorithmException, BadPaddingException, InvalidKeyException { public QueryResult<Lock> query(@RequestBody LockLookup lookup) throws MyApplicationException, MyForbiddenException, InvalidAlgorithmParameterException, NoSuchPaddingException, IllegalBlockSizeException, NoSuchAlgorithmException, BadPaddingException, InvalidKeyException {
logger.debug("querying {}", Lock.class.getSimpleName()); logger.debug("querying {}", Lock.class.getSimpleName());
@ -101,7 +137,17 @@ public class LockController {
} }
@GetMapping("{id}") @GetMapping("{id}")
public Lock get(@PathVariable("id") UUID id, FieldSet fieldSet) throws MyApplicationException, MyForbiddenException, MyNotFoundException { @OperationWithTenantHeader(summary = "Fetch a specific lock by id", description = "",
responses = @ApiResponse(description = "OK", responseCode = "200", content = @Content(
schema = @Schema(
implementation = Lock.class
))
))
@Swagger404
public Lock get(
@Parameter(name = "id", description = "The id of a user to fetch", example = "c0c163dc-2965-45a5-9608-f76030578609", required = true) @PathVariable("id") UUID id,
@Parameter(name = "fieldSet", description = SwaggerHelpers.Commons.fieldset_description, required = true) FieldSet fieldSet
) throws MyApplicationException, MyForbiddenException, MyNotFoundException {
logger.debug(new MapLogEntry("retrieving" + Lock.class.getSimpleName()).And("id", id).And("fields", fieldSet)); logger.debug(new MapLogEntry("retrieving" + Lock.class.getSimpleName()).And("id", id).And("fields", fieldSet));
this.censorFactory.censor(LockCensor.class).censor(fieldSet, null); this.censorFactory.censor(LockCensor.class).censor(fieldSet, null);
@ -120,9 +166,20 @@ public class LockController {
} }
@PostMapping("persist") @PostMapping("persist")
@OperationWithTenantHeader(summary = "Create a new or update an existing lock", description = "",
responses = @ApiResponse(description = "OK", responseCode = "200", content = @Content(
schema = @Schema(
implementation = Lock.class
))
))
@Swagger400
@Swagger404
@Transactional @Transactional
@ValidationFilterAnnotation(validator = LockPersist.LockPersistValidator.ValidatorName, argumentName = "model") @ValidationFilterAnnotation(validator = LockPersist.LockPersistValidator.ValidatorName, argumentName = "model")
public Lock persist(@RequestBody LockPersist model, FieldSet fieldSet) throws MyApplicationException, MyForbiddenException, MyNotFoundException, InvalidApplicationException { public Lock persist(
@RequestBody LockPersist model,
@Parameter(name = "fieldSet", description = SwaggerHelpers.Commons.fieldset_description, required = true) FieldSet fieldSet
) throws MyApplicationException, MyForbiddenException, MyNotFoundException, InvalidApplicationException {
logger.debug(new MapLogEntry("persisting" + Lock.class.getSimpleName()).And("model", model).And("fieldSet", fieldSet)); logger.debug(new MapLogEntry("persisting" + Lock.class.getSimpleName()).And("model", model).And("fieldSet", fieldSet));
this.censorFactory.censor(LockCensor.class).censor(fieldSet, null); this.censorFactory.censor(LockCensor.class).censor(fieldSet, null);
@ -137,7 +194,17 @@ public class LockController {
} }
@GetMapping("target/{id}") @GetMapping("target/{id}")
public Lock getWithTarget(@PathVariable("id") UUID targetId, FieldSet fieldSet) throws MyApplicationException, MyForbiddenException, MyNotFoundException { @OperationWithTenantHeader(summary = "Fetch a specific lock by target id", description = "",
responses = @ApiResponse(description = "OK", responseCode = "200", content = @Content(
schema = @Schema(
implementation = Lock.class
))
))
@Swagger404
public Lock getWithTarget(
@Parameter(name = "id", description = "The target id of a lock to fetch", example = "c0c163dc-2965-45a5-9608-f76030578609", required = true) @PathVariable("id") UUID targetId,
@Parameter(name = "fieldSet", description = SwaggerHelpers.Commons.fieldset_description, required = true) FieldSet fieldSet
) throws MyApplicationException, MyForbiddenException, MyNotFoundException {
logger.debug(new MapLogEntry("retrieving" + Lock.class.getSimpleName()).And("targetId", targetId).And("fields", fieldSet)); logger.debug(new MapLogEntry("retrieving" + Lock.class.getSimpleName()).And("targetId", targetId).And("fields", fieldSet));
this.censorFactory.censor(LockCensor.class).censor(fieldSet, null); this.censorFactory.censor(LockCensor.class).censor(fieldSet, null);
@ -157,7 +224,16 @@ public class LockController {
@Transactional @Transactional
@GetMapping("target/status/{id}") @GetMapping("target/status/{id}")
public LockStatus getLocked(@PathVariable("id") UUID targetId, FieldSet fieldSet) throws Exception { @OperationWithTenantHeader(summary = "Fetch a lock status by target id", description = "",
responses = @ApiResponse(description = "OK", responseCode = "200", content = @Content(
schema = @Schema(
implementation = LockStatus.class
))
))
public LockStatus getLocked(
@Parameter(name = "id", description = "The target id of a lock to fetch the status", example = "c0c163dc-2965-45a5-9608-f76030578609", required = true) @PathVariable("id") UUID targetId,
@Parameter(name = "fieldSet", description = SwaggerHelpers.Commons.fieldset_description, required = true) FieldSet fieldSet
) throws Exception {
logger.debug(new MapLogEntry("is locked" + Lock.class.getSimpleName()).And("targetId", targetId).And("fields", fieldSet)); logger.debug(new MapLogEntry("is locked" + Lock.class.getSimpleName()).And("targetId", targetId).And("fields", fieldSet));
this.authService.authorizeForce(Permission.BrowseLock); this.authService.authorizeForce(Permission.BrowseLock);
@ -171,7 +247,16 @@ public class LockController {
@Transactional @Transactional
@GetMapping("target/lock/{id}/{targetType}") @GetMapping("target/lock/{id}/{targetType}")
public boolean lock(@PathVariable("id") UUID targetId, @PathVariable("targetType") int targetType) throws Exception { @OperationWithTenantHeader(summary = "Lock a target", description = "",
responses = @ApiResponse(description = "OK", responseCode = "200", content = @Content(
schema = @Schema(
implementation = Boolean.class
))
))
public boolean lock(
@Parameter(name = "id", description = "The target id to be locked", example = "c0c163dc-2965-45a5-9608-f76030578609", required = true) @PathVariable("id") UUID targetId,
@Parameter(name = "targetType", description = "The target type to be locked", example = "0", required = true) @PathVariable("targetType") int targetType
) throws Exception {
AffiliatedResource affiliatedResourcePlan = this.authorizationContentResolver.planAffiliation(targetId); AffiliatedResource affiliatedResourcePlan = this.authorizationContentResolver.planAffiliation(targetId);
AffiliatedResource affiliatedResourceDescription = this.authorizationContentResolver.descriptionAffiliation(targetId); AffiliatedResource affiliatedResourceDescription = this.authorizationContentResolver.descriptionAffiliation(targetId);
AffiliatedResource affiliatedResourceDescriptionTemplate = this.authorizationContentResolver.descriptionTemplateAffiliation(targetId); AffiliatedResource affiliatedResourceDescriptionTemplate = this.authorizationContentResolver.descriptionTemplateAffiliation(targetId);
@ -187,7 +272,15 @@ public class LockController {
@Transactional @Transactional
@GetMapping("target/touch/{id}") @GetMapping("target/touch/{id}")
public boolean touch(@PathVariable("id") UUID targetId) throws Exception { @OperationWithTenantHeader(summary = "Touch a locked target", description = "",
responses = @ApiResponse(description = "OK", responseCode = "200", content = @Content(
schema = @Schema(
implementation = Boolean.class
))
))
public boolean touch(
@Parameter(name = "id", description = "The target id to be touched", example = "c0c163dc-2965-45a5-9608-f76030578609", required = true) @PathVariable("id") UUID targetId
) throws Exception {
AffiliatedResource affiliatedResourcePlan = this.authorizationContentResolver.planAffiliation(targetId); AffiliatedResource affiliatedResourcePlan = this.authorizationContentResolver.planAffiliation(targetId);
AffiliatedResource affiliatedResourceDescription = this.authorizationContentResolver.descriptionAffiliation(targetId); AffiliatedResource affiliatedResourceDescription = this.authorizationContentResolver.descriptionAffiliation(targetId);
AffiliatedResource affiliatedResourceDescriptionTemplate = this.authorizationContentResolver.descriptionTemplateAffiliation(targetId); AffiliatedResource affiliatedResourceDescriptionTemplate = this.authorizationContentResolver.descriptionTemplateAffiliation(targetId);
@ -202,7 +295,15 @@ public class LockController {
@Transactional @Transactional
@DeleteMapping("target/unlock/{id}") @DeleteMapping("target/unlock/{id}")
public boolean unlock(@PathVariable("id") UUID targetId) throws Exception { @OperationWithTenantHeader(summary = "Unlock a target", description = "",
responses = @ApiResponse(description = "OK", responseCode = "200", content = @Content(
schema = @Schema(
implementation = Boolean.class
))
))
public boolean unlock(
@Parameter(name = "id", description = "The target id to be unlocked", example = "c0c163dc-2965-45a5-9608-f76030578609", required = true) @PathVariable("id") UUID targetId
) throws Exception {
AffiliatedResource affiliatedResourcePlan = this.authorizationContentResolver.planAffiliation(targetId); AffiliatedResource affiliatedResourcePlan = this.authorizationContentResolver.planAffiliation(targetId);
AffiliatedResource affiliatedResourceDescription = this.authorizationContentResolver.descriptionAffiliation(targetId); AffiliatedResource affiliatedResourceDescription = this.authorizationContentResolver.descriptionAffiliation(targetId);
AffiliatedResource affiliatedResourceDescriptionTemplate = this.authorizationContentResolver.descriptionTemplateAffiliation(targetId); AffiliatedResource affiliatedResourceDescriptionTemplate = this.authorizationContentResolver.descriptionTemplateAffiliation(targetId);
@ -216,8 +317,13 @@ public class LockController {
} }
@DeleteMapping("{id}/{target}") @DeleteMapping("{id}/{target}")
@OperationWithTenantHeader(summary = "Delete a lock by id and target", description = "",
responses = @ApiResponse(description = "OK", responseCode = "200"))
@Transactional @Transactional
public void delete(@PathVariable("id") UUID id, @PathVariable("target") UUID target) throws MyForbiddenException, InvalidApplicationException { public void delete(
@Parameter(name = "id", description = "The id of the lock to be deleted", example = "c0c163dc-2965-45a5-9608-f76030578609", required = true) @PathVariable("id") UUID id,
@Parameter(name = "target", description = "The target id of the lock", example = "c0c163dc-2965-45a5-9608-f76030578609", required = true) @PathVariable("target") UUID target
) throws MyForbiddenException, InvalidApplicationException {
logger.debug(new MapLogEntry("retrieving" + Lock.class.getSimpleName()).And("id", id)); logger.debug(new MapLogEntry("retrieving" + Lock.class.getSimpleName()).And("id", id));
this.lockService.deleteAndSave(id, target); this.lockService.deleteAndSave(id, target);

View File

@ -502,7 +502,7 @@ public class PlanController {
public PreprocessingPlanModel preprocessing( public PreprocessingPlanModel preprocessing(
@RequestParam("fileId") UUID fileId, @RequestParam("fileId") UUID fileId,
@RequestParam("repositoryId") String repositoryId @RequestParam("repositoryId") String repositoryId
) throws InvalidAlgorithmParameterException, JAXBException, NoSuchPaddingException, IllegalBlockSizeException, InvalidApplicationException, IOException, NoSuchAlgorithmException, BadPaddingException, InvalidKeyException { ) throws InvalidAlgorithmParameterException, NoSuchPaddingException, IllegalBlockSizeException, InvalidApplicationException, IOException, NoSuchAlgorithmException, BadPaddingException, InvalidKeyException {
logger.debug(new MapLogEntry("preprocessing plan" + Plan.class.getSimpleName()).And("transformerId", repositoryId).And("fileId", fileId)); logger.debug(new MapLogEntry("preprocessing plan" + Plan.class.getSimpleName()).And("transformerId", repositoryId).And("fileId", fileId));
PreprocessingPlanModel model = this.planService.preprocessingPlan(fileId, repositoryId); PreprocessingPlanModel model = this.planService.preprocessingPlan(fileId, repositoryId);

View File

@ -6,7 +6,15 @@ import gr.cite.tools.auditing.AuditService;
import gr.cite.tools.fieldset.BaseFieldSet; import gr.cite.tools.fieldset.BaseFieldSet;
import gr.cite.tools.fieldset.FieldSet; import gr.cite.tools.fieldset.FieldSet;
import gr.cite.tools.logging.LoggerService; import gr.cite.tools.logging.LoggerService;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.opencdmp.audit.AuditableAction; import org.opencdmp.audit.AuditableAction;
import org.opencdmp.controllers.swagger.SwaggerHelpers;
import org.opencdmp.controllers.swagger.annotation.OperationWithTenantHeader;
import org.opencdmp.model.Lock;
import org.opencdmp.model.Tenant; import org.opencdmp.model.Tenant;
import org.opencdmp.models.Account; import org.opencdmp.models.Account;
import org.opencdmp.models.AccountBuilder; import org.opencdmp.models.AccountBuilder;
@ -23,6 +31,7 @@ import java.util.List;
@RestController @RestController
@RequestMapping("/api/principal/") @RequestMapping("/api/principal/")
@Tag(name = "Principal", description = "Get user account information")
public class PrincipalController { public class PrincipalController {
private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(PrincipalController.class)); private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(PrincipalController.class));
private final AuditService auditService; private final AuditService auditService;
@ -43,7 +52,15 @@ public class PrincipalController {
} }
@RequestMapping(path = "me", method = RequestMethod.GET ) @RequestMapping(path = "me", method = RequestMethod.GET )
public Account me(FieldSet fieldSet) throws InvalidApplicationException { @OperationWithTenantHeader(summary = "Fetch auth information of the logged in user", description = "",
responses = @ApiResponse(description = "OK", responseCode = "200", content = @Content(
schema = @Schema(
implementation = Account.class
))
))
public Account me(
@Parameter(name = "fieldSet", description = SwaggerHelpers.Commons.fieldset_description, required = true) FieldSet fieldSet
) throws InvalidApplicationException {
logger.debug("me"); logger.debug("me");
if (fieldSet == null || fieldSet.isEmpty()) { if (fieldSet == null || fieldSet.isEmpty()) {
@ -80,7 +97,11 @@ public class PrincipalController {
} }
@GetMapping("my-tenants") @GetMapping("my-tenants")
public List<Tenant> myTenants(FieldSet fieldSet) { @OperationWithTenantHeader(summary = "Fetch a list with the tenants the user belongs to", description = "",
responses = @ApiResponse(description = "OK", responseCode = "200"))
public List<Tenant> myTenants(
@Parameter(name = "fieldSet", description = SwaggerHelpers.Commons.fieldset_description, required = true) FieldSet fieldSet
) {
logger.debug("my-tenants"); logger.debug("my-tenants");
List<Tenant> models = this.tenantService.myTenants(fieldSet); List<Tenant> models = this.tenantService.myTenants(fieldSet);

View File

@ -12,11 +12,24 @@ import gr.cite.tools.fieldset.FieldSet;
import gr.cite.tools.logging.LoggerService; import gr.cite.tools.logging.LoggerService;
import gr.cite.tools.logging.MapLogEntry; import gr.cite.tools.logging.MapLogEntry;
import gr.cite.tools.validation.ValidationFilterAnnotation; import gr.cite.tools.validation.ValidationFilterAnnotation;
import io.swagger.v3.oas.annotations.Hidden;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.ArraySchema;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.ExampleObject;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.xml.bind.JAXBException; import jakarta.xml.bind.JAXBException;
import org.opencdmp.audit.AuditableAction; import org.opencdmp.audit.AuditableAction;
import org.opencdmp.authorization.AuthorizationFlags; import org.opencdmp.authorization.AuthorizationFlags;
import org.opencdmp.commons.enums.IsActive; import org.opencdmp.commons.enums.IsActive;
import org.opencdmp.commons.scope.user.UserScope; import org.opencdmp.commons.scope.user.UserScope;
import org.opencdmp.controllers.swagger.SwaggerHelpers;
import org.opencdmp.controllers.swagger.annotation.OperationWithTenantHeader;
import org.opencdmp.controllers.swagger.annotation.Swagger400;
import org.opencdmp.controllers.swagger.annotation.Swagger404;
import org.opencdmp.controllers.swagger.annotation.SwaggerCommonErrorResponses;
import org.opencdmp.data.UserEntity; import org.opencdmp.data.UserEntity;
import org.opencdmp.model.PlanAssociatedUser; import org.opencdmp.model.PlanAssociatedUser;
import org.opencdmp.model.UserRole; import org.opencdmp.model.UserRole;
@ -26,6 +39,7 @@ import org.opencdmp.model.censorship.PlanAssociatedUserCensor;
import org.opencdmp.model.censorship.UserCensor; import org.opencdmp.model.censorship.UserCensor;
import org.opencdmp.model.persist.*; import org.opencdmp.model.persist.*;
import org.opencdmp.model.persist.actionconfirmation.RemoveCredentialRequestPersist; import org.opencdmp.model.persist.actionconfirmation.RemoveCredentialRequestPersist;
import org.opencdmp.model.plan.Plan;
import org.opencdmp.model.result.QueryResult; import org.opencdmp.model.result.QueryResult;
import org.opencdmp.model.user.User; import org.opencdmp.model.user.User;
import org.opencdmp.query.UserQuery; import org.opencdmp.query.UserQuery;
@ -51,6 +65,8 @@ import java.util.UUID;
@RestController @RestController
@RequestMapping(path = "api/user") @RequestMapping(path = "api/user")
@Tag(name = "Users", description = "Manage users")
@SwaggerCommonErrorResponses
public class UserController { public class UserController {
private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(UserController.class)); private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(UserController.class));
@ -91,6 +107,25 @@ public class UserController {
} }
@PostMapping("query") @PostMapping("query")
@OperationWithTenantHeader(summary = "Query all users", description = SwaggerHelpers.User.endpoint_query, requestBody = @io.swagger.v3.oas.annotations.parameters.RequestBody(description = SwaggerHelpers.User.endpoint_query_request_body, content = @Content(
examples = {
@ExampleObject(
name = "Pagination and projection",
description = "Simple paginated request using a property projection list and pagination info",
value = SwaggerHelpers.User.endpoint_query_request_body_example
)
}
)), responses = @ApiResponse(description = "OK", responseCode = "200", content = @Content(
array = @ArraySchema(
schema = @Schema(
implementation = User.class
)
),
examples = @ExampleObject(
name = "First page",
description = "Example with the first page of paginated results",
value = SwaggerHelpers.User.endpoint_query_response_example
))))
public QueryResult<User> query(@RequestBody UserLookup lookup) throws MyApplicationException, MyForbiddenException { public QueryResult<User> query(@RequestBody UserLookup lookup) throws MyApplicationException, MyForbiddenException {
logger.debug("querying {}", User.class.getSimpleName()); logger.debug("querying {}", User.class.getSimpleName());
@ -108,6 +143,7 @@ public class UserController {
} }
@PostMapping("plan-associated/query") @PostMapping("plan-associated/query")
@Hidden
public QueryResult<PlanAssociatedUser> queryPlanAssociated(@RequestBody UserLookup lookup) throws MyApplicationException, MyForbiddenException { public QueryResult<PlanAssociatedUser> queryPlanAssociated(@RequestBody UserLookup lookup) throws MyApplicationException, MyForbiddenException {
logger.debug("querying {}", User.class.getSimpleName()); logger.debug("querying {}", User.class.getSimpleName());
@ -125,7 +161,17 @@ public class UserController {
} }
@GetMapping("{id}") @GetMapping("{id}")
public User get(@PathVariable("id") UUID id, FieldSet fieldSet) throws MyApplicationException, MyForbiddenException, MyNotFoundException { @OperationWithTenantHeader(summary = "Fetch a specific user by id", description = "",
responses = @ApiResponse(description = "OK", responseCode = "200", content = @Content(
schema = @Schema(
implementation = User.class
))
))
@Swagger404
public User get(
@Parameter(name = "id", description = "The id of a user to fetch", example = "c0c163dc-2965-45a5-9608-f76030578609", required = true) @PathVariable("id") UUID id,
@Parameter(name = "fieldSet", description = SwaggerHelpers.Commons.fieldset_description, required = true) FieldSet fieldSet
) throws MyApplicationException, MyForbiddenException, MyNotFoundException {
logger.debug(new MapLogEntry("retrieving" + User.class.getSimpleName()).And("id", id).And("fields", fieldSet)); logger.debug(new MapLogEntry("retrieving" + User.class.getSimpleName()).And("id", id).And("fields", fieldSet));
this.censorFactory.censor(UserCensor.class).censor(fieldSet, id); this.censorFactory.censor(UserCensor.class).censor(fieldSet, id);
@ -144,7 +190,17 @@ public class UserController {
} }
@GetMapping("/by-email/{email}") @GetMapping("/by-email/{email}")
public User get(@PathVariable("email") String email, FieldSet fieldSet) throws MyApplicationException, MyForbiddenException, MyNotFoundException { @OperationWithTenantHeader(summary = "Fetch a specific user by email", description = "",
responses = @ApiResponse(description = "OK", responseCode = "200", content = @Content(
schema = @Schema(
implementation = User.class
))
))
@Swagger404
public User get(
@Parameter(name = "email", description = "The email of a user to fetch", example = "admin@cite.gr", required = true) @PathVariable("email") String email,
@Parameter(name = "fieldSet", description = SwaggerHelpers.Commons.fieldset_description, required = true) FieldSet fieldSet
) throws MyApplicationException, MyForbiddenException, MyNotFoundException {
logger.debug(new MapLogEntry("retrieving" + User.class.getSimpleName()).And("email", email).And("fields", fieldSet)); logger.debug(new MapLogEntry("retrieving" + User.class.getSimpleName()).And("email", email).And("fields", fieldSet));
this.censorFactory.censor(UserCensor.class).censor(fieldSet, null); this.censorFactory.censor(UserCensor.class).censor(fieldSet, null);
@ -163,6 +219,7 @@ public class UserController {
} }
@GetMapping("/export/csv/{hasTenantAdminMode}") @GetMapping("/export/csv/{hasTenantAdminMode}")
@Hidden
public ResponseEntity<byte[]> exportCsv(@PathVariable("hasTenantAdminMode") Boolean hasTenantAdminMode) throws MyApplicationException, MyForbiddenException, MyNotFoundException, IOException, InvalidApplicationException { public ResponseEntity<byte[]> exportCsv(@PathVariable("hasTenantAdminMode") Boolean hasTenantAdminMode) throws MyApplicationException, MyForbiddenException, MyNotFoundException, IOException, InvalidApplicationException {
logger.debug(new MapLogEntry("export" + User.class.getSimpleName()).And("hasTenantAdminMode", hasTenantAdminMode)); logger.debug(new MapLogEntry("export" + User.class.getSimpleName()).And("hasTenantAdminMode", hasTenantAdminMode));
@ -177,7 +234,16 @@ public class UserController {
} }
@GetMapping("mine") @GetMapping("mine")
public User getMine(FieldSet fieldSet) throws MyApplicationException, MyForbiddenException, MyNotFoundException, InvalidApplicationException { @OperationWithTenantHeader(summary = "Fetch information for the logged in user", description = "",
responses = @ApiResponse(description = "OK", responseCode = "200", content = @Content(
schema = @Schema(
implementation = User.class
))
))
@Swagger404
public User getMine(
@Parameter(name = "fieldSet", description = SwaggerHelpers.Commons.fieldset_description, required = true) FieldSet fieldSet
) throws MyApplicationException, MyForbiddenException, MyNotFoundException, InvalidApplicationException {
logger.debug(new MapLogEntry("retrieving me" + User.class.getSimpleName()).And("fields", fieldSet)); logger.debug(new MapLogEntry("retrieving me" + User.class.getSimpleName()).And("fields", fieldSet));
this.censorFactory.censor(UserCensor.class).censor(fieldSet, this.userScope.getUserId()); this.censorFactory.censor(UserCensor.class).censor(fieldSet, this.userScope.getUserId());
@ -195,8 +261,12 @@ public class UserController {
} }
@GetMapping("mine/language/{language}") @GetMapping("mine/language/{language}")
@OperationWithTenantHeader(summary = "Update the language for the logged in user", description = "",
responses = @ApiResponse(description = "OK", responseCode = "200"))
@Transactional @Transactional
public void updateLanguageMine(@PathVariable("language") String language) throws MyApplicationException, MyForbiddenException, MyNotFoundException, InvalidApplicationException, JsonProcessingException { public void updateLanguageMine(
@Parameter(name = "language", description = "The updated language", example = "en", required = true) @PathVariable("language") String language
) throws MyApplicationException, MyForbiddenException, MyNotFoundException, InvalidApplicationException, JsonProcessingException {
logger.debug(new MapLogEntry("persisting" + User.class.getSimpleName()).And("language", language)); logger.debug(new MapLogEntry("persisting" + User.class.getSimpleName()).And("language", language));
this.userTypeService.updateLanguageMine(language); this.userTypeService.updateLanguageMine(language);
@ -206,8 +276,12 @@ public class UserController {
} }
@GetMapping("mine/timezone/{timezone}") @GetMapping("mine/timezone/{timezone}")
@OperationWithTenantHeader(summary = "Update the timezone for the logged in user", description = "",
responses = @ApiResponse(description = "OK", responseCode = "200"))
@Transactional @Transactional
public void updateTimezoneMine(@PathVariable("timezone") String timezone) throws MyApplicationException, MyForbiddenException, MyNotFoundException, InvalidApplicationException, JsonProcessingException { public void updateTimezoneMine(
@Parameter(name = "timezone", description = "The updated timezone", example = "Europe/Budapest", required = true) @PathVariable("timezone") String timezone
) throws MyApplicationException, MyForbiddenException, MyNotFoundException, InvalidApplicationException, JsonProcessingException {
logger.debug(new MapLogEntry("persisting" + User.class.getSimpleName()).And("timezone", timezone)); logger.debug(new MapLogEntry("persisting" + User.class.getSimpleName()).And("timezone", timezone));
this.userTypeService.updateTimezoneMine(timezone); this.userTypeService.updateTimezoneMine(timezone);
@ -217,8 +291,12 @@ public class UserController {
} }
@GetMapping("mine/culture/{culture}") @GetMapping("mine/culture/{culture}")
@OperationWithTenantHeader(summary = "Update the culture for the logged in user", description = "",
responses = @ApiResponse(description = "OK", responseCode = "200"))
@Transactional @Transactional
public void updateCultureMine(@PathVariable("culture") String culture) throws MyApplicationException, MyForbiddenException, MyNotFoundException, InvalidApplicationException, JsonProcessingException { public void updateCultureMine(
@Parameter(name = "culture", description = "The updated culture", example = "en-US", required = true) @PathVariable("culture") String culture
) throws MyApplicationException, MyForbiddenException, MyNotFoundException, InvalidApplicationException, JsonProcessingException {
logger.debug(new MapLogEntry("persisting" + User.class.getSimpleName()).And("culture", culture)); logger.debug(new MapLogEntry("persisting" + User.class.getSimpleName()).And("culture", culture));
this.userTypeService.updateCultureMine(culture); this.userTypeService.updateCultureMine(culture);
@ -228,9 +306,20 @@ public class UserController {
} }
@PostMapping("persist") @PostMapping("persist")
@OperationWithTenantHeader(summary = "Create a new or update an existing user", description = "",
responses = @ApiResponse(description = "OK", responseCode = "200", content = @Content(
schema = @Schema(
implementation = User.class
))
))
@Swagger400
@Swagger404
@Transactional @Transactional
@ValidationFilterAnnotation(validator = UserPersist.UserPersistValidator.ValidatorName, argumentName = "model") @ValidationFilterAnnotation(validator = UserPersist.UserPersistValidator.ValidatorName, argumentName = "model")
public User persist(@RequestBody UserPersist model, FieldSet fieldSet) throws MyApplicationException, MyForbiddenException, MyNotFoundException, InvalidApplicationException, JAXBException, ParserConfigurationException, JsonProcessingException, TransformerException { public User persist(
@RequestBody UserPersist model,
@Parameter(name = "fieldSet", description = SwaggerHelpers.Commons.fieldset_description, required = true) FieldSet fieldSet
) throws MyApplicationException, MyForbiddenException, MyNotFoundException, InvalidApplicationException, JAXBException, ParserConfigurationException, JsonProcessingException, TransformerException {
logger.debug(new MapLogEntry("persisting" + User.class.getSimpleName()).And("model", model).And("fieldSet", fieldSet)); logger.debug(new MapLogEntry("persisting" + User.class.getSimpleName()).And("model", model).And("fieldSet", fieldSet));
User persisted = this.userTypeService.persist(model, fieldSet); User persisted = this.userTypeService.persist(model, fieldSet);
@ -243,9 +332,20 @@ public class UserController {
} }
@PostMapping("persist/roles") @PostMapping("persist/roles")
@OperationWithTenantHeader(summary = "Update user roles", description = "",
responses = @ApiResponse(description = "OK", responseCode = "200", content = @Content(
schema = @Schema(
implementation = User.class
))
))
@Swagger400
@Swagger404
@Transactional @Transactional
@ValidationFilterAnnotation(validator = UserRolePatchPersist.UserRolePatchPersistValidator.ValidatorName, argumentName = "model") @ValidationFilterAnnotation(validator = UserRolePatchPersist.UserRolePatchPersistValidator.ValidatorName, argumentName = "model")
public User persistRoles(@RequestBody UserRolePatchPersist model, FieldSet fieldSet) throws MyApplicationException, MyForbiddenException, MyNotFoundException, InvalidApplicationException, JAXBException, ParserConfigurationException, JsonProcessingException, TransformerException { public User persistRoles(
@RequestBody UserRolePatchPersist model,
@Parameter(name = "fieldSet", description = SwaggerHelpers.Commons.fieldset_description, required = true) FieldSet fieldSet
) throws MyApplicationException, MyForbiddenException, MyNotFoundException, InvalidApplicationException, JAXBException, ParserConfigurationException, JsonProcessingException, TransformerException {
logger.debug(new MapLogEntry("persisting" + UserRole.class.getSimpleName()).And("model", model).And("fieldSet", fieldSet)); logger.debug(new MapLogEntry("persisting" + UserRole.class.getSimpleName()).And("model", model).And("fieldSet", fieldSet));
User persisted = this.userTypeService.patchRoles(model, fieldSet); User persisted = this.userTypeService.patchRoles(model, fieldSet);
@ -258,8 +358,13 @@ public class UserController {
} }
@DeleteMapping("{id}") @DeleteMapping("{id}")
@OperationWithTenantHeader(summary = "Delete a user by id", description = "",
responses = @ApiResponse(description = "OK", responseCode = "200"))
@Swagger404
@Transactional @Transactional
public void delete(@PathVariable("id") UUID id) throws MyForbiddenException, InvalidApplicationException { public void delete(
@Parameter(name = "id", description = "The id of a user to delete", example = "c0c163dc-2965-45a5-9608-f76030578609", required = true) @PathVariable("id") UUID id
) throws MyForbiddenException, InvalidApplicationException {
logger.debug(new MapLogEntry("retrieving" + User.class.getSimpleName()).And("id", id)); logger.debug(new MapLogEntry("retrieving" + User.class.getSimpleName()).And("id", id));
this.userTypeService.deleteAndSave(id); this.userTypeService.deleteAndSave(id);
@ -268,6 +373,10 @@ public class UserController {
} }
@PostMapping("mine/merge-account-request") @PostMapping("mine/merge-account-request")
@OperationWithTenantHeader(summary = "Merge user accounts", description = "",
responses = @ApiResponse(description = "OK", responseCode = "200"))
@Swagger400
@Swagger404
@Transactional @Transactional
@ValidationFilterAnnotation(validator = UserMergeRequestPersist.UserMergeRequestPersistValidator.ValidatorName, argumentName = "model") @ValidationFilterAnnotation(validator = UserMergeRequestPersist.UserMergeRequestPersistValidator.ValidatorName, argumentName = "model")
public Boolean mergeAccount(@RequestBody UserMergeRequestPersist model) throws InvalidApplicationException, JAXBException { public Boolean mergeAccount(@RequestBody UserMergeRequestPersist model) throws InvalidApplicationException, JAXBException {
@ -283,8 +392,12 @@ public class UserController {
} }
@GetMapping("mine/confirm-merge-account/token/{token}") @GetMapping("mine/confirm-merge-account/token/{token}")
@OperationWithTenantHeader(summary = "Confirm the merge of user accounts", description = "",
responses = @ApiResponse(description = "OK", responseCode = "200"))
@Transactional @Transactional
public Boolean confirmMergeAccount(@PathVariable("token") String token) throws InvalidApplicationException, IOException { public Boolean confirmMergeAccount(
@Parameter(name = "token", description = "The token for the action", example = "c0c163dc-2965-45a5-9608-f76030578609", required = true) @PathVariable("token") String token
) throws InvalidApplicationException, IOException {
logger.debug(new MapLogEntry("confirm merge account to user").And("token", token)); logger.debug(new MapLogEntry("confirm merge account to user").And("token", token));
this.userTypeService.confirmMergeAccount(token); this.userTypeService.confirmMergeAccount(token);
@ -297,7 +410,11 @@ public class UserController {
} }
@GetMapping("mine/allow-merge-account/token/{token}") @GetMapping("mine/allow-merge-account/token/{token}")
public Boolean getUserTokenPermission(@PathVariable("token") String token) throws InvalidApplicationException, IOException { @OperationWithTenantHeader(summary = "Allow the merge of user accounts", description = "",
responses = @ApiResponse(description = "OK", responseCode = "200"))
public Boolean getUserTokenPermission(
@Parameter(name = "token", description = "The token for the action", example = "c0c163dc-2965-45a5-9608-f76030578609", required = true) @PathVariable("token") String token
) throws InvalidApplicationException, IOException {
logger.debug(new MapLogEntry("allow merge account to user").And("token", token)); logger.debug(new MapLogEntry("allow merge account to user").And("token", token));
this.auditService.track(AuditableAction.User_AllowMergeAccount); this.auditService.track(AuditableAction.User_AllowMergeAccount);
@ -306,6 +423,9 @@ public class UserController {
} }
@PostMapping("mine/remove-credential-request") @PostMapping("mine/remove-credential-request")
@OperationWithTenantHeader(summary = "Remove user credentials", description = "",
responses = @ApiResponse(description = "OK", responseCode = "200"))
@Swagger400
@Transactional @Transactional
@ValidationFilterAnnotation(validator = RemoveCredentialRequestPersist.RemoveCredentialRequestPersistValidator.ValidatorName, argumentName = "model") @ValidationFilterAnnotation(validator = RemoveCredentialRequestPersist.RemoveCredentialRequestPersistValidator.ValidatorName, argumentName = "model")
public Boolean removeCredentialAccount(@RequestBody RemoveCredentialRequestPersist model) throws InvalidApplicationException, JAXBException { public Boolean removeCredentialAccount(@RequestBody RemoveCredentialRequestPersist model) throws InvalidApplicationException, JAXBException {
@ -321,8 +441,12 @@ public class UserController {
} }
@GetMapping("mine/confirm-remove-credential/token/{token}") @GetMapping("mine/confirm-remove-credential/token/{token}")
@OperationWithTenantHeader(summary = "Confirm the removal of user credentials", description = "",
responses = @ApiResponse(description = "OK", responseCode = "200"))
@Transactional @Transactional
public Boolean confirmRemoveCredentialAccount(@PathVariable("token") String token) throws InvalidApplicationException, JAXBException { public Boolean confirmRemoveCredentialAccount(
@Parameter(name = "token", description = "The token for the action", example = "c0c163dc-2965-45a5-9608-f76030578609", required = true) @PathVariable("token") String token
) throws InvalidApplicationException, JAXBException {
logger.debug(new MapLogEntry("confirm remove credential to user").And("token", token)); logger.debug(new MapLogEntry("confirm remove credential to user").And("token", token));
this.userTypeService.confirmRemoveCredential(token); this.userTypeService.confirmRemoveCredential(token);
@ -335,6 +459,9 @@ public class UserController {
} }
@PostMapping("invite-users-to-tenant") @PostMapping("invite-users-to-tenant")
@OperationWithTenantHeader(summary = "Invite users to a tenant", description = "",
responses = @ApiResponse(description = "OK", responseCode = "200"))
@Swagger400
@Transactional @Transactional
@ValidationFilterAnnotation(validator = UserTenantUsersInviteRequest.UserTenantUsersInviteRequestValidator.ValidatorName, argumentName = "model") @ValidationFilterAnnotation(validator = UserTenantUsersInviteRequest.UserTenantUsersInviteRequestValidator.ValidatorName, argumentName = "model")
public Boolean inviteUsersToTenant(@RequestBody UserTenantUsersInviteRequest users) throws InvalidApplicationException, JAXBException { public Boolean inviteUsersToTenant(@RequestBody UserTenantUsersInviteRequest users) throws InvalidApplicationException, JAXBException {
@ -350,8 +477,13 @@ public class UserController {
} }
@GetMapping("confirm-invite-user-to-tenant/token/{token}") @GetMapping("confirm-invite-user-to-tenant/token/{token}")
@OperationWithTenantHeader(summary = "Confirm user tenant invitation", description = "",
responses = @ApiResponse(description = "OK", responseCode = "200"))
@Swagger400
@Transactional @Transactional
public Boolean confirmInviteUserToTenant(@PathVariable("token") String token) throws InvalidApplicationException { public Boolean confirmInviteUserToTenant(
@Parameter(name = "token", description = "The token for the action", example = "c0c163dc-2965-45a5-9608-f76030578609", required = true) @PathVariable("token") String token
) throws InvalidApplicationException {
logger.debug(new MapLogEntry("confirm merge account to user").And("token", token)); logger.debug(new MapLogEntry("confirm merge account to user").And("token", token));
this.userTypeService.confirmUserInviteToTenant(token); this.userTypeService.confirmUserInviteToTenant(token);

View File

@ -1,8 +1,8 @@
package org.opencdmp.controllers.swagger; package org.opencdmp.controllers.swagger;
public class SwaggerHelpers { public final class SwaggerHelpers {
public static class Commons { public static final class Commons {
public static final String fieldset_description = public static final String fieldset_description =
""" """
@ -10,7 +10,7 @@ public class SwaggerHelpers {
"""; """;
} }
public static class Errors { public static final class Errors {
public static final String message_400 = public static final String message_400 =
""" """
@ -51,7 +51,7 @@ public class SwaggerHelpers {
} }
public static class Plan { public static final class Plan {
public static final String endpoint_query = public static final String endpoint_query =
""" """
@ -905,7 +905,7 @@ public class SwaggerHelpers {
"""; """;
} }
public static class Description { public static final class Description {
public static final String endpoint_query = public static final String endpoint_query =
""" """
@ -1760,7 +1760,7 @@ public class SwaggerHelpers {
"""; """;
} }
public static class DescriptionTemplate { public static final class DescriptionTemplate {
public static final String endpoint_query = public static final String endpoint_query =
""" """
@ -2144,7 +2144,7 @@ public class SwaggerHelpers {
"""; """;
} }
public static class DescriptionTemplateType { public static final class DescriptionTemplateType {
public static final String endpoint_query = public static final String endpoint_query =
""" """
@ -2307,7 +2307,7 @@ public class SwaggerHelpers {
} }
public static class PlanBlueprint { public static final class PlanBlueprint {
public static final String endpoint_query = public static final String endpoint_query =
""" """
@ -2548,7 +2548,7 @@ public class SwaggerHelpers {
} }
public static class FileTransformer { public static final class FileTransformer {
public static final String endpoint_get_available_transformers = public static final String endpoint_get_available_transformers =
""" """
@ -2569,7 +2569,7 @@ public class SwaggerHelpers {
} }
public static class EntityDoi { public static final class EntityDoi {
public static final String endpoint_query = public static final String endpoint_query =
""" """
@ -2835,7 +2835,7 @@ public class SwaggerHelpers {
} }
public static class Deposit { public static final class Deposit {
public static final String endpoint_get_available_repos = public static final String endpoint_get_available_repos =
""" """
@ -2859,7 +2859,7 @@ public class SwaggerHelpers {
} }
public static class Tag { public static final class Tag {
public static final String endpoint_query = public static final String endpoint_query =
""" """
@ -3086,7 +3086,7 @@ public class SwaggerHelpers {
} }
public static class Reference { public static final class Reference {
public static final String endpoint_query = public static final String endpoint_query =
""" """
@ -3348,7 +3348,7 @@ public class SwaggerHelpers {
} }
public static class ReferenceType { public static final class ReferenceType {
public static final String endpoint_query = public static final String endpoint_query =
""" """
@ -3579,4 +3579,672 @@ public class SwaggerHelpers {
} }
public static final class Lock {
public static final String endpoint_query =
"""
This endpoint is used to fetch all the current entity locks.<br/>
It also allows to restrict the results using a query object passed in the request body.<br/>
""";
public static final String endpoint_query_request_body =
"""
Let's explore the options this object gives us.
### <u>General query parameters:</u>
<ul>
<li><b>page:</b>
This is an object controlling the pagination of the results. It contains two properties.
</li>
<ul>
<li><b>offset:</b>
How many records to omit.
</li>
<li><b>size:</b>
How many records to include in each page.
</li>
</ul>
</ul>
For example, if we want the third page, and our pages to contain 15 elements, we would pass the following object:
```JSON
{
"offset": 30,
"size": 15
}
```
<ul>
<li><b>order:</b>
This is an object controlling the ordering of the results.
It contains a list of strings called <i>items</i> with the names of the properties to use.
<br/>If the name of the property is prefixed with a <b>'-'</b>, the ordering direction is <b>DESC</b>. Otherwise, it is <b>ASC</b>.
</li>
</ul>
For example, if we wanted to order based on the field 'createdAt' in descending order, we would pass the following object:
```JSON
{
"items": [
"-createdAt"
],
}
```
<ul>
<li><b>metadata:</b>
This is an object containing metadata for the request. There is only one available option.
<ul>
<li><b>countAll:</b>
If this is set to true, the count property included in the response will account for all the records regardless the pagination,
with all the rest of filtering options applied of course.
Otherwise, if it is set to false or not present, only the returned results will be counted.
<br/>The first option is useful for the UI clients to calculate how many result pages are available.
</li>
</ul>
</li>
<li><b>project:</b>
This is an object controlling the data projection of the results.
It contains a list of strings called <i>fields</i> with the names of the properties to project.
<br/>You can also include properties that are deeper in the object tree by prefixing them with dots.
</li>
</ul>
### <u>Lock specific query parameters:</u>
<ul>
<li><b>like:</b>
If there is a like parameter present in the query, only the locks locking the provided target id will be in the response.
</li>
<li><b>ids:</b>
This is a list and contains the ids we want to include in the response. <br/>If empty, every record is included.
</li>
<li><b>excludedIds:</b>
This is a list and contains the ids we want to exclude from the response. <br/>If empty, no record gets excluded.
</li>
<li><b>targetIds:</b>
This is a list and contains the ids of the locked targets of the locks we want to include in the response. <br/>If empty, every record is included.
</li>
<li><b>userIds:</b>
This is a list and contains the ids of the users of the locks we want to include in the response. <br/>If empty, every record is included.
</li>
<li><b>targetTypes:</b>
This is a list and determines which records we want to include in the response, based on their target type.
The target type can be <i>Plan</i>, <i>Description</i>, <i>PlanBlueprint</i> or <i>DescriptionTemplate</i>. We add 0, 1, 2 or 3 to the list respectively.
<br/>If not present, every record is included.
</li>
</ul>
""";
public static final String endpoint_query_request_body_example =
"""
{
"project":{
"fields":[
"id",
"target",
"targetType",
"lockedAt",
"lockedBy.name",
"touchedAt",
"hash",
"belongsToCurrentTenant"
]
},
"metadata":{
"countAll":true
},
"page":{
"offset":0,
"size":10
},
"isActive":[
1
],
"order":{
"items":[
"-lockedAt"
]
}
}
""";
public static final String endpoint_query_response_example =
"""
{
"items":[
{
"id":"d0423a02-abe8-4210-8ee3-504deb79d8c6",
"target":"39fabf73-546c-49a3-8789-6401f65d56b6",
"targetType":1,
"lockedBy":{
"name":"admin admin"
},
"lockedAt":"2024-06-28T08:47:03.784241Z",
"touchedAt":"2024-07-04T11:01:10.762955Z",
"hash":"1720090870",
"belongsToCurrentTenant":true
},
{
"id":"74b2ae7e-0a28-4ebc-aec9-3f849ccb3e60",
"target":"37701076-e0ff-4e4f-95aa-9f3d6a23083a",
"targetType":2,
"lockedBy":{
"name":"admin admin"
},
"lockedAt":"2024-07-04T08:29:46.591493Z",
"touchedAt":"2024-07-04T08:33:13.451444Z",
"hash":"1720081993",
"belongsToCurrentTenant":true
},
{
"id":"642d6756-bf62-4555-9ca5-bec50c5cdb85",
"target":"212342fe-ab6f-4604-b80e-ac23aca93c76",
"targetType":3,
"lockedBy":{
"name":"admin admin"
},
"lockedAt":"2024-07-02T11:36:17.926775Z",
"touchedAt":"2024-07-02T11:39:24.278433Z",
"hash":"1719920364",
"belongsToCurrentTenant":true
},
{
"id":"4a7fd0b4-1b2e-4148-a5fc-152f73caa7e5",
"target":"0e58f8b7-a91e-432a-8de2-edf03679c313",
"targetType":1,
"lockedBy":{
"name":"admin"
},
"lockedAt":"2024-07-01T11:16:14.806474Z",
"touchedAt":"2024-07-01T11:23:21.922533Z",
"hash":"1719833001",
"belongsToCurrentTenant":true
}
],
"count":4
}
""";
}
public static final class User {
public static final String endpoint_query =
"""
This endpoint is used to fetch all the available users.<br/>
It also allows to restrict the results using a query object passed in the request body.<br/>
""";
public static final String endpoint_query_request_body =
"""
Let's explore the options this object gives us.
### <u>General query parameters:</u>
<ul>
<li><b>page:</b>
This is an object controlling the pagination of the results. It contains two properties.
</li>
<ul>
<li><b>offset:</b>
How many records to omit.
</li>
<li><b>size:</b>
How many records to include in each page.
</li>
</ul>
</ul>
For example, if we want the third page, and our pages to contain 15 elements, we would pass the following object:
```JSON
{
"offset": 30,
"size": 15
}
```
<ul>
<li><b>order:</b>
This is an object controlling the ordering of the results.
It contains a list of strings called <i>items</i> with the names of the properties to use.
<br/>If the name of the property is prefixed with a <b>'-'</b>, the ordering direction is <b>DESC</b>. Otherwise, it is <b>ASC</b>.
</li>
</ul>
For example, if we wanted to order based on the field 'createdAt' in descending order, we would pass the following object:
```JSON
{
"items": [
"-createdAt"
],
}
```
<ul>
<li><b>metadata:</b>
This is an object containing metadata for the request. There is only one available option.
<ul>
<li><b>countAll:</b>
If this is set to true, the count property included in the response will account for all the records regardless the pagination,
with all the rest of filtering options applied of course.
Otherwise, if it is set to false or not present, only the returned results will be counted.
<br/>The first option is useful for the UI clients to calculate how many result pages are available.
</li>
</ul>
</li>
<li><b>project:</b>
This is an object controlling the data projection of the results.
It contains a list of strings called <i>fields</i> with the names of the properties to project.
<br/>You can also include properties that are deeper in the object tree by prefixing them with dots.
</li>
</ul>
### <u>User specific query parameters:</u>
<ul>
<li><b>like:</b>
If there is a like parameter present in the query, only the users that include the contents of the parameter in their names will be in the response.
</li>
<li><b>ids:</b>
This is a list and contains the ids we want to include in the response. <br/>If empty, every record is included.
</li>
<li><b>excludedIds:</b>
This is a list and contains the ids we want to exclude from the response. <br/>If empty, no record gets excluded.
</li>
<li><b>isActive:</b>
This is a list and determines which records we want to include in the response, based on if they are deleted or not.
This filter works like this. If we want to view only the active records we pass [1] and for only the deleted records we pass [0].
<br/>If not present or if we pass [0,1], every record is included.
</li>
<li><b>emails:</b>
This is a list and determines which records we want to include in the response, based on their emails.
<br/>If not present, every record is included.
</li>
</ul>
""";
public static final String endpoint_query_request_body_example =
"""
{
"project":{
"fields":[
"id",
"name",
"contacts.id",
"contacts.type",
"contacts.value",
"globalRoles.id",
"globalRoles.role",
"tenantRoles.id",
"tenantRoles.role",
"additionalInfo.avatarUrl",
"updatedAt",
"createdAt",
"hash",
"isActive"
]
},
"metadata":{
"countAll":true
},
"page":{
"offset":0,
"size":10
},
"isActive":[
1
],
"order":{
"items":[
"-createdAt"
]
}
}
""";
public static final String endpoint_query_response_example =
"""
{
"items":[
{
"id":"fc97ad11-2c73-4fc4-835e-e1ca0cf7b918",
"name":"user5 user5",
"createdAt":"2024-07-03T09:59:05.005425Z",
"updatedAt":"2024-07-03T09:59:05.005425Z",
"isActive":1,
"hash":"1720000745",
"additionalInfo":{
\s
},
"contacts":[
{
"id":"8b0972d2-e9d8-4c61-b69b-907ee452dade",
"value":"user5@user5.gr",
"type":0,
"ordinal":0,
"user":{
\s
}
}
],
"globalRoles":[
{
"id":"50b8e8e8-eb02-40cb-aa6f-a99eb0f48721",
"role":"User",
"user":{
\s
}
}
],
"tenantRoles":[
{
"id":"cc0307e5-4421-4e46-b7a1-b1326e6e786b",
"role":"TenantUser",
"user":{
\s
}
}
]
},
{
"id":"b494c989-60f1-4584-bc52-b56c40c66ade",
"name":"installationadmin installationadmin",
"createdAt":"2024-06-28T13:23:24.957340Z",
"updatedAt":"2024-06-28T13:23:24.957340Z",
"isActive":1,
"hash":"1719581004",
"additionalInfo":{
\s
},
"contacts":[
{
"id":"cd281a02-f851-400f-ba7f-391e16884051",
"value":"installationadmin@dmp.gr",
"type":0,
"ordinal":0,
"user":{
\s
}
}
],
"globalRoles":[
{
"id":"1d4088c3-7d42-4227-93d9-ee46ead5f500",
"role":"InstallationAdmin",
"user":{
\s
}
}
],
"tenantRoles":[
{
"id":"b606b428-f404-4232-81fa-a313fcbab25a",
"role":"TenantUser",
"user":{
\s
}
}
]
},
{
"id":"5119e0a6-53ee-4cad-ae58-aa3c1fc79683",
"name":"user3 user3",
"createdAt":"2024-06-28T11:23:22.962858Z",
"updatedAt":"2024-06-28T11:23:22.962858Z",
"isActive":1,
"hash":"1719573802",
"additionalInfo":{
\s
},
"contacts":[
{
"id":"18f1f3f2-77d6-4258-a7d0-1623d7282b82",
"value":"user3@dmp.gr",
"type":0,
"ordinal":0,
"user":{
\s
}
}
],
"globalRoles":[
{
"id":"116ec22c-3b3a-44ae-9de0-be31c8d621c2",
"role":"User",
"user":{
\s
}
}
],
"tenantRoles":[
{
"id":"618b266b-ecdb-46cd-a5c5-686dc76bba12",
"role":"TenantUser",
"user":{
\s
}
}
]
},
{
"id":"d1873841-3ae3-4a1c-8cfc-841327552313",
"name":"dmproot dmproot",
"createdAt":"2024-06-28T07:19:37.150149Z",
"updatedAt":"2024-06-28T07:19:37.150149Z",
"isActive":1,
"hash":"1719559177",
"additionalInfo":{
\s
},
"contacts":[
{
"id":"20d108c6-8277-40d0-a2b8-e6d8c9c332f0",
"value":"dmproot@cite.gr",
"type":0,
"ordinal":0,
"user":{
\s
}
}
],
"globalRoles":[
{
"id":"209b7b67-5374-4b11-a1cf-ecfba6da5f16",
"role":"Admin",
"user":{
\s
}
},
{
"id":"5d7ee923-5456-456c-b46f-b53458b0e10a",
"role":"User",
"user":{
\s
}
}
],
"tenantRoles":[
{
"id":"4a14b1fd-2e35-4817-89fa-9d8bf741aee7",
"role":"TenantUser",
"user":{
\s
}
}
]
},
{
"id":"890667ae-7efd-49d9-8ab5-3d48b84a48d1",
"name":"admin admin",
"createdAt":"2024-06-28T07:07:18.589432Z",
"updatedAt":"2024-06-28T07:07:18.589432Z",
"isActive":1,
"hash":"1719558438",
"additionalInfo":{
\s
},
"contacts":[
{
"id":"9739739b-b5d9-4e13-bc47-637b3760b340",
"value":"admin@dmp.gr",
"type":0,
"ordinal":0,
"user":{
\s
}
}
],
"globalRoles":[
{
"id":"718dd2d0-cbda-4b33-b8be-a25ec30a53f3",
"role":"User",
"user":{
\s
}
},
{
"id":"c2c4129e-dcec-448a-8e7c-e4dd7cbc3d9d",
"role":"Admin",
"user":{
\s
}
}
],
"tenantRoles":[
{
"id":"6961542d-6ea7-4064-a0ad-20d82896b9de",
"role":"TenantAdmin",
"user":{
\s
}
}
]
},
{
"id":"1f709343-353b-4787-a8e0-f71020b53f94",
"name":"user5847",
"createdAt":"2024-06-26T22:46:43Z",
"updatedAt":"2024-06-26T22:46:43Z",
"isActive":1,
"hash":"1719442003",
"additionalInfo":{
"avatarUrl":"null"
},
"contacts":[
{
"id":"b8c17fa6-c8e1-49d8-9c7b-173dad43d995",
"value":"user5847@dmp.gr",
"type":0,
"ordinal":0,
"user":{
\s
}
}
]
},
{
"id":"ac633bd9-ac0b-4258-adc5-24246e1dacbc",
"name":"user5846",
"createdAt":"2024-06-26T22:08:44Z",
"updatedAt":"2024-06-26T22:08:44Z",
"isActive":1,
"hash":"1719439724",
"additionalInfo":{
"avatarUrl":"null"
},
"contacts":[
{
"id":"0126a7d6-c2f3-4f2e-85cc-9c999d74fa85",
"value":"user5846@dmp.gr",
"type":0,
"ordinal":0,
"user":{
\s
}
}
]
},
{
"id":"2b4e633b-5451-46fb-a1ad-34c1f8fb8fe7",
"name":"user5844",
"createdAt":"2024-06-26T17:04:01Z",
"updatedAt":"2024-06-26T17:04:01Z",
"isActive":1,
"hash":"1719421441",
"additionalInfo":{
"avatarUrl":"null"
},
"contacts":[
{
"id":"138b9b60-8bfb-4900-8f0f-32dd70c8841c",
"value":"user5844@dmp.gr",
"type":0,
"ordinal":0,
"user":{
\s
}
}
]
},
{
"id":"d9d0ae8b-8037-403e-a155-28d2387d6d7f",
"name":"user5842",
"createdAt":"2024-06-26T13:38:58Z",
"updatedAt":"2024-06-26T13:38:58Z",
"isActive":1,
"hash":"1719409138",
"additionalInfo":{
"avatarUrl":"null"
},
"contacts":[
{
"id":"12bb3f67-941c-4731-8de0-b8d43ff6e17a",
"value":"user5842@dmp.gr",
"type":0,
"ordinal":0,
"user":{
\s
}
}
]
},
{
"id":"3748e22c-3760-4ada-88ef-8addd247fc76",
"name":"user5841",
"createdAt":"2024-06-26T13:19:52Z",
"updatedAt":"2024-06-26T13:22:19Z",
"isActive":1,
"hash":"1719408139",
"additionalInfo":{
"avatarUrl":"null"
},
"contacts":[
{
"id":"d536278f-9714-43f8-846c-cb5c6bcf2f59",
"value":"user5841@dmp.gr",
"type":0,
"ordinal":0,
"user":{
\s
}
}
]
}
],
"count":5821
}
""";
}
public static final class Principal {
}
} }

View File

@ -11,7 +11,7 @@ springdoc:
displayName: Current displayName: Current
packagesToScan: org.opencdmp.controllers packagesToScan: org.opencdmp.controllers
packagesToExclude: org.opencdmp.controllers.publicapi packagesToExclude: org.opencdmp.controllers.publicapi
pathsToMatch: "/api/plan/**, /api/description/**, /api/description-template/**, /api/description-template-type/**, /api/plan-blueprint/**, /api/entity-doi/**, /api/deposit/**, /api/file-transformer/**, /api/tag/**, /api/reference/**, /api/reference-type/**" pathsToMatch: "/api/plan/**, /api/description/**, /api/description-template/**, /api/description-template-type/**, /api/plan-blueprint/**, /api/entity-doi/**, /api/deposit/**, /api/file-transformer/**, /api/tag/**, /api/reference/**, /api/reference-type/**, /api/lock/**, /api/user/**, /api/principal/**"
swaggerUi: swaggerUi:
enabled: true enabled: true
useRootPath: true useRootPath: true