diff --git a/backend/web/src/main/java/org/opencdmp/controllers/DmpBlueprintController.java b/backend/web/src/main/java/org/opencdmp/controllers/PlanBlueprintController.java similarity index 96% rename from backend/web/src/main/java/org/opencdmp/controllers/DmpBlueprintController.java rename to backend/web/src/main/java/org/opencdmp/controllers/PlanBlueprintController.java index bc344b6e5..90fa400f0 100644 --- a/backend/web/src/main/java/org/opencdmp/controllers/DmpBlueprintController.java +++ b/backend/web/src/main/java/org/opencdmp/controllers/PlanBlueprintController.java @@ -59,9 +59,9 @@ import java.util.UUID; @RequestMapping(path = "api/dmp-blueprint") @Tag(name = "Plan Blueprints", description = "Manage plan blueprints") @SwaggerCommonErrorResponses -public class DmpBlueprintController { +public class PlanBlueprintController { - private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(DmpBlueprintController.class)); + private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(PlanBlueprintController.class)); private final BuilderFactory builderFactory; @@ -75,7 +75,7 @@ public class DmpBlueprintController { private final MessageSource messageSource; - public DmpBlueprintController( + public PlanBlueprintController( BuilderFactory builderFactory, AuditService auditService, DmpBlueprintService dmpBlueprintService, @@ -91,12 +91,12 @@ public class DmpBlueprintController { } @PostMapping("query") - @OperationWithTenantHeader(summary = "Query all plan blueprints", description = SwaggerHelpers.DmpBlueprint.endpoint_query, requestBody = @io.swagger.v3.oas.annotations.parameters.RequestBody(description = SwaggerHelpers.DmpBlueprint.endpoint_query_request_body, content = @Content( + @OperationWithTenantHeader(summary = "Query all plan blueprints", description = SwaggerHelpers.PlanBlueprint.endpoint_query, requestBody = @io.swagger.v3.oas.annotations.parameters.RequestBody(description = SwaggerHelpers.PlanBlueprint.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.DmpBlueprint.endpoint_query_request_body_example + value = SwaggerHelpers.PlanBlueprint.endpoint_query_request_body_example ) } )), responses = @ApiResponse(description = "OK", responseCode = "200", content = @Content( @@ -108,7 +108,7 @@ public class DmpBlueprintController { examples = @ExampleObject( name = "First page", description = "Example with the first page of paginated results", - value = SwaggerHelpers.DmpBlueprint.endpoint_query_response_example + value = SwaggerHelpers.PlanBlueprint.endpoint_query_response_example )))) public QueryResult query(@RequestBody DmpBlueprintLookup lookup) throws MyApplicationException, MyForbiddenException { logger.debug("querying {}", DmpBlueprint.class.getSimpleName()); diff --git a/backend/web/src/main/java/org/opencdmp/controllers/DmpController.java b/backend/web/src/main/java/org/opencdmp/controllers/PlanController.java similarity index 98% rename from backend/web/src/main/java/org/opencdmp/controllers/DmpController.java rename to backend/web/src/main/java/org/opencdmp/controllers/PlanController.java index 51fde57a4..f0111f630 100644 --- a/backend/web/src/main/java/org/opencdmp/controllers/DmpController.java +++ b/backend/web/src/main/java/org/opencdmp/controllers/PlanController.java @@ -73,9 +73,9 @@ import static org.opencdmp.authorization.AuthorizationFlags.Public; @RequestMapping(path = "api/dmp") @Tag(name = "Plans", description = "Manage plans") @SwaggerCommonErrorResponses -public class DmpController { +public class PlanController { - private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(DmpController.class)); + private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(PlanController.class)); private final BuilderFactory builderFactory; @@ -91,7 +91,7 @@ public class DmpController { private final ElasticQueryHelperService elasticQueryHelperService; - public DmpController( + public PlanController( BuilderFactory builderFactory, AuditService auditService, DmpService dmpService, @@ -147,12 +147,12 @@ public class DmpController { } @PostMapping("query") - @OperationWithTenantHeader(summary = "Query all plans", description = SwaggerHelpers.Dmp.endpoint_query, requestBody = @io.swagger.v3.oas.annotations.parameters.RequestBody(description = SwaggerHelpers.Dmp.endpoint_query_request_body, content = @Content( + @OperationWithTenantHeader(summary = "Query all plans", description = SwaggerHelpers.Plan.endpoint_query, requestBody = @io.swagger.v3.oas.annotations.parameters.RequestBody(description = SwaggerHelpers.Plan.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.Dmp.endpoint_query_request_body_example + value = SwaggerHelpers.Plan.endpoint_query_request_body_example ) } )), responses = @ApiResponse(description = "OK", responseCode = "200", content = @Content( @@ -164,7 +164,7 @@ public class DmpController { examples = @ExampleObject( name = "First page", description = "Example with the first page of paginated results", - value = SwaggerHelpers.Dmp.endpoint_query_response_example + value = SwaggerHelpers.Plan.endpoint_query_response_example )))) public QueryResult Query(@RequestBody DmpLookup lookup) throws MyApplicationException, MyForbiddenException { logger.debug("querying {}", Dmp.class.getSimpleName()); diff --git a/backend/web/src/main/java/org/opencdmp/controllers/TagController.java b/backend/web/src/main/java/org/opencdmp/controllers/TagController.java index f45248617..5bde81889 100644 --- a/backend/web/src/main/java/org/opencdmp/controllers/TagController.java +++ b/backend/web/src/main/java/org/opencdmp/controllers/TagController.java @@ -11,8 +11,19 @@ import gr.cite.tools.fieldset.FieldSet; import gr.cite.tools.logging.LoggerService; import gr.cite.tools.logging.MapLogEntry; 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 org.opencdmp.audit.AuditableAction; import org.opencdmp.authorization.AuthorizationFlags; +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.TagEntity; import org.opencdmp.model.Tag; import org.opencdmp.model.builder.TagBuilder; @@ -33,6 +44,8 @@ import java.util.*; @RestController @RequestMapping(path = "api/tag") +@io.swagger.v3.oas.annotations.tags.Tag(name = "Tags", description = "Manage tags") +@SwaggerCommonErrorResponses public class TagController { private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(TagController.class)); @@ -65,6 +78,25 @@ public class TagController { } @PostMapping("query") + @OperationWithTenantHeader(summary = "Query all tags", description = SwaggerHelpers.Tag.endpoint_query, requestBody = @io.swagger.v3.oas.annotations.parameters.RequestBody(description = SwaggerHelpers.Tag.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.Tag.endpoint_query_request_body_example + ) + } + )), responses = @ApiResponse(description = "OK", responseCode = "200", content = @Content( + array = @ArraySchema( + schema = @Schema( + implementation = Tag.class + ) + ), + examples = @ExampleObject( + name = "First page", + description = "Example with the first page of paginated results", + value = SwaggerHelpers.Tag.endpoint_query_response_example + )))) public QueryResult Query(@RequestBody TagLookup lookup) throws MyApplicationException, MyForbiddenException { logger.debug("querying {}", Tag.class.getSimpleName()); @@ -82,7 +114,18 @@ public class TagController { } @GetMapping("{id}") - public Tag Get(@PathVariable("id") UUID id, FieldSet fieldSet, Locale locale) throws MyApplicationException, MyForbiddenException, MyNotFoundException { + @OperationWithTenantHeader(summary = "Fetch a specific tag by id", description = "", + responses = @ApiResponse(description = "OK", responseCode = "200", content = @Content( + schema = @Schema( + implementation = Tag.class + )) + )) + @Swagger404 + public Tag Get( + @Parameter(name = "id", description = "The id of a tag 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, + Locale locale + ) throws MyApplicationException, MyForbiddenException, MyNotFoundException { logger.debug(new MapLogEntry("retrieving" + Tag.class.getSimpleName()).And("id", id).And("fields", fieldSet)); this.censorFactory.censor(TagCensor.class).censor(fieldSet, null); @@ -101,9 +144,20 @@ public class TagController { } @PostMapping("persist") + @OperationWithTenantHeader(summary = "Create a new or update an existing tag", description = "", + responses = @ApiResponse(description = "OK", responseCode = "200", content = @Content( + schema = @Schema( + implementation = Tag.class + )) + )) + @Swagger400 + @Swagger404 @Transactional @ValidationFilterAnnotation(validator = TagPersist.TagPersistValidator.ValidatorName, argumentName = "model") - public Tag Persist(@RequestBody TagPersist model, FieldSet fieldSet) throws MyApplicationException, MyForbiddenException, MyNotFoundException, InvalidApplicationException { + public Tag Persist( + @RequestBody TagPersist model, + @Parameter(name = "fieldSet", description = SwaggerHelpers.Commons.fieldset_description, required = true) FieldSet fieldSet + ) throws MyApplicationException, MyForbiddenException, MyNotFoundException, InvalidApplicationException { logger.debug(new MapLogEntry("persisting" + Tag.class.getSimpleName()).And("model", model).And("fieldSet", fieldSet)); Tag persisted = this.tagService.persist(model, fieldSet); @@ -116,8 +170,13 @@ public class TagController { } @DeleteMapping("{id}") + @OperationWithTenantHeader(summary = "Delete a tag by id", description = "", + responses = @ApiResponse(description = "OK", responseCode = "200")) + @Swagger404 @Transactional - public void Delete(@PathVariable("id") UUID id) throws MyForbiddenException, InvalidApplicationException { + public void Delete( + @Parameter(name = "id", description = "The id of a tag to delete", example = "c0c163dc-2965-45a5-9608-f76030578609", required = true) @PathVariable("id") UUID id + ) throws MyForbiddenException, InvalidApplicationException { logger.debug(new MapLogEntry("retrieving" + Tag.class.getSimpleName()).And("id", id)); this.tagService.deleteAndSave(id); diff --git a/backend/web/src/main/java/org/opencdmp/controllers/swagger/SwaggerHelpers.java b/backend/web/src/main/java/org/opencdmp/controllers/swagger/SwaggerHelpers.java index ee20f7032..20cea798b 100644 --- a/backend/web/src/main/java/org/opencdmp/controllers/swagger/SwaggerHelpers.java +++ b/backend/web/src/main/java/org/opencdmp/controllers/swagger/SwaggerHelpers.java @@ -51,7 +51,7 @@ public class SwaggerHelpers { } - public static class Dmp { + public static class Plan { public static final String endpoint_query = """ @@ -2307,7 +2307,7 @@ public class SwaggerHelpers { } - public static class DmpBlueprint { + public static class PlanBlueprint { public static final String endpoint_query = """ @@ -2859,4 +2859,231 @@ public class SwaggerHelpers { } + public static class Tag { + + public static final String endpoint_query = + """ + This endpoint is used to fetch all the available tags.
+ It also allows to restrict the results using a query object passed in the request body.
+ """; + + public static final String endpoint_query_request_body = + """ + Let's explore the options this object gives us. + + ### General query parameters: + +
    +
  • page: + This is an object controlling the pagination of the results. It contains two properties. +
  • +
      +
    • offset: + How many records to omit. +
    • +
    • size: + How many records to include in each page. +
    • +
    +
+ + 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 + } + ``` + +
    +
  • order: + This is an object controlling the ordering of the results. + It contains a list of strings called items with the names of the properties to use. +
    If the name of the property is prefixed with a '-', the ordering direction is DESC. Otherwise, it is ASC. +
  • +
+ + For example, if we wanted to order based on the field 'createdAt' in descending order, we would pass the following object: + + ```JSON + { + "items": [ + "-createdAt" + ], + } + ``` + +
    +
  • metadata: + This is an object containing metadata for the request. There is only one available option. +
      +
    • countAll: + 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. +
      The first option is useful for the UI clients to calculate how many result pages are available. +
    • +
    +
  • +
  • project: + This is an object controlling the data projection of the results. + It contains a list of strings called fields with the names of the properties to project. +
    You can also include properties that are deeper in the object tree by prefixing them with dots. +
  • +
+ + ### Tag specific query parameters: + +
    +
  • like: + If there is a like parameter present in the query, only the tag entities that include the contents of the parameter in their labels will be in the response. +
  • +
  • ids: + This is a list and contains the ids we want to include in the response.
    If empty, every record is included. +
  • +
  • excludedIds: + This is a list and contains the ids we want to exclude from the response.
    If empty, no record gets excluded. +
  • +
  • createdByIds: + This is a list and contains the ids of the users who's tags we want to exclude from the response.
    If empty, every record is included. +
  • +
  • isActive: + 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]. +
    If not present or if we pass [0,1], every record is included. +
  • +
  • tags: + This is a list and determines which records we want to include in the response, based on their tag string. +
    If not present, every record is included. +
  • +
  • excludedTags: + This is a list and determines which records we want to exclude from the response, based on their tag string. +
    If not present, no record is excluded. +
  • +
+ """; + + public static final String endpoint_query_request_body_example = + """ + { + "project":{ + "fields":[ + "id", + "label", + "createdAt", + "updatedAt", + "isActive", + "belongsToCurrentTenant" + ] + }, + "metadata":{ + "countAll":true + }, + "page":{ + "offset":0, + "size":10 + }, + "isActive":[ + 1 + ], + "order":{ + "items":[ + "-createdAt" + ] + } + } + """; + + public static final String endpoint_query_response_example = + """ + { + "items":[ + { + "id":"abd9d15e-4c70-4700-bce8-e90b8d99ecd5", + "label":"PCM", + "createdAt":"2024-06-27T13:52:48.417255Z", + "updatedAt":"2024-06-27T13:52:48.417255Z", + "isActive":1, + "belongsToCurrentTenant":true + }, + { + "id":"de185ef7-8d9a-458e-9af6-c7c1c9ea39e0", + "label":"Phase change material", + "createdAt":"2024-06-27T13:52:48.417255Z", + "updatedAt":"2024-06-27T13:52:48.417255Z", + "isActive":1, + "belongsToCurrentTenant":true + }, + { + "id":"7b74fc3e-b283-4203-8b2c-2b9999b96ce7", + "label":"heat transfer enhancement in PCM", + "createdAt":"2024-06-27T13:52:48.417255Z", + "updatedAt":"2024-06-27T13:52:48.417255Z", + "isActive":1, + "belongsToCurrentTenant":true + }, + { + "id":"d5cd61ff-26c8-4abb-a605-9400c8e6f453", + "label":"energy", + "createdAt":"2024-06-27T13:52:48.328879Z", + "updatedAt":"2024-06-27T13:52:48.328879Z", + "isActive":1, + "belongsToCurrentTenant":true + }, + { + "id":"a8ab80af-dcf4-4221-85d6-3c9ef304f52d", + "label":" indicators", + "createdAt":"2024-06-27T13:52:48.328879Z", + "updatedAt":"2024-06-27T13:52:48.328879Z", + "isActive":1, + "belongsToCurrentTenant":true + }, + { + "id":"b27cf507-296a-407e-87f2-e6245d60a622", + "label":"district heating", + "createdAt":"2024-06-27T13:52:48.328879Z", + "updatedAt":"2024-06-27T13:52:48.328879Z", + "isActive":1, + "belongsToCurrentTenant":true + }, + { + "id":"40eea91d-e3ef-4284-8a70-76cfb544e71b", + "label":" energy resilience", + "createdAt":"2024-06-27T13:52:48.328879Z", + "updatedAt":"2024-06-27T13:52:48.328879Z", + "isActive":1, + "belongsToCurrentTenant":true + }, + { + "id":"aa955ed9-7d40-486b-aec3-05515be36297", + "label":"biomass", + "createdAt":"2024-06-27T13:52:48.169676Z", + "updatedAt":"2024-06-27T13:52:48.169676Z", + "isActive":1, + "belongsToCurrentTenant":true + }, + { + "id":"a777b696-f861-4eba-8bb0-60951cf3cc8f", + "label":"laboratory", + "createdAt":"2024-06-27T13:52:48.169676Z", + "updatedAt":"2024-06-27T13:52:48.169676Z", + "isActive":1, + "belongsToCurrentTenant":true + }, + { + "id":"03ed72bc-af6e-47ea-b775-90674f50bdc2", + "label":"pellets", + "createdAt":"2024-06-27T13:52:48.169676Z", + "updatedAt":"2024-06-27T13:52:48.169676Z", + "isActive":1, + "belongsToCurrentTenant":true + } + ], + "count":2789 + } + """; + + } + } diff --git a/backend/web/src/main/resources/config/swagger.yml b/backend/web/src/main/resources/config/swagger.yml index 72d70a5b0..73ffb5983 100644 --- a/backend/web/src/main/resources/config/swagger.yml +++ b/backend/web/src/main/resources/config/swagger.yml @@ -11,7 +11,7 @@ springdoc: displayName: Current packagesToScan: org.opencdmp.controllers packagesToExclude: org.opencdmp.controllers.publicapi - pathsToMatch: "/api/dmp/**, /api/description/**, /api/description-template/**, /api/description-template-type/**, /api/dmp-blueprint/**, /api/entity-doi/**, /api/deposit/**, /api/file-transformer/**" + pathsToMatch: "/api/dmp/**, /api/description/**, /api/description-template/**, /api/description-template-type/**, /api/dmp-blueprint/**, /api/entity-doi/**, /api/deposit/**, /api/file-transformer/**, /api/tag/**" swaggerUi: enabled: true useRootPath: true