Merge branch 'dmp-refactoring' of https://code-repo.d4science.org/MaDgiK-CITE/argos into dmp-refactoring

This commit is contained in:
Sofia Papacharalampous 2024-06-21 13:43:14 +03:00
commit 9de176d3eb
5 changed files with 115 additions and 49 deletions

View File

@ -14,8 +14,11 @@ import gr.cite.tools.validation.ValidationFilterAnnotation;
import io.swagger.v3.oas.annotations.Hidden;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.enums.ParameterIn;
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;
@ -27,7 +30,8 @@ import org.opencdmp.commons.enums.IsActive;
import org.opencdmp.controllers.swagger.SwaggerHelpers;
import org.opencdmp.controllers.swagger.annotation.Swagger400;
import org.opencdmp.controllers.swagger.annotation.Swagger404;
import org.opencdmp.controllers.swagger.annotation.SwaggerErrorResponses;
import org.opencdmp.controllers.swagger.annotation.SwaggerCommonErrorResponses;
import org.opencdmp.controllers.swagger.annotation.OperationWithTenantHeader;
import org.opencdmp.convention.ConventionService;
import org.opencdmp.data.StorageFileEntity;
import org.opencdmp.model.DescriptionValidationResult;
@ -76,7 +80,7 @@ import static org.opencdmp.authorization.AuthorizationFlags.Public;
@RestController
@RequestMapping(path = "api/description")
@Tag(name = "Descriptions", description = "Manage descriptions")
@SwaggerErrorResponses
@SwaggerCommonErrorResponses
public class DescriptionController {
private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(DescriptionController.class));
@ -117,7 +121,7 @@ public class DescriptionController {
}
@PostMapping("public/query")
@Operation(summary = "Query public descriptions")
@OperationWithTenantHeader(summary = "Query public descriptions")
@Hidden
public QueryResult<PublicDescription> publicQuery(@RequestBody DescriptionLookup lookup) throws MyApplicationException, MyForbiddenException {
logger.debug("querying {}", PublicDescription.class.getSimpleName());
@ -133,7 +137,7 @@ public class DescriptionController {
}
@GetMapping("public/{id}")
@Operation(summary = "Fetch a specific public description by id")
@OperationWithTenantHeader(summary = "Fetch a specific public description by id")
@Hidden
public PublicDescription publicGet(@PathVariable("id") UUID id, FieldSet fieldSet) throws MyApplicationException, MyForbiddenException, MyNotFoundException {
logger.debug(new MapLogEntry("retrieving" + PublicDescription.class.getSimpleName()).And("id", id).And("fields", fieldSet));
@ -155,7 +159,7 @@ public class DescriptionController {
}
@PostMapping("query")
@Operation(summary = "Query all descriptions", description = SwaggerHelpers.Description.endpoint_query, requestBody = @io.swagger.v3.oas.annotations.parameters.RequestBody(description = SwaggerHelpers.Description.endpoint_query_request_body, content = @Content(
@OperationWithTenantHeader(summary = "Query all descriptions", description = SwaggerHelpers.Description.endpoint_query, requestBody = @io.swagger.v3.oas.annotations.parameters.RequestBody(description = SwaggerHelpers.Description.endpoint_query_request_body, content = @Content(
examples = {
@ExampleObject(
name = "Pagination and projection",
@ -182,7 +186,7 @@ public class DescriptionController {
@GetMapping("{id}")
@Operation(summary = "Fetch a specific description by id")
@OperationWithTenantHeader(summary = "Fetch a specific description by id")
@Swagger404
public Description get(
@Parameter(name = "id", description = "The id of a description to fetch", example = "c0c163dc-2965-45a5-9608-f76030578609", required = true) @PathVariable("id") UUID id,
@ -207,7 +211,7 @@ public class DescriptionController {
}
@PostMapping("persist")
@Operation(summary = "Create a new or update an existing description")
@OperationWithTenantHeader(summary = "Create a new or update an existing description")
@Swagger400
@Swagger404
@Transactional
@ -230,7 +234,7 @@ public class DescriptionController {
}
@PostMapping("persist-status")
@Operation(summary = "Update the status of an existing description")
@OperationWithTenantHeader(summary = "Update the status of an existing description")
@Swagger400
@Swagger404
@Transactional
@ -253,7 +257,7 @@ public class DescriptionController {
}
@PostMapping("get-description-section-permissions")
@Operation(summary = "Fetch the section specific user permissions")
@OperationWithTenantHeader(summary = "Fetch the section specific user permissions")
@Hidden
@ValidationFilterAnnotation(validator = DescriptionSectionPermissionResolver.DescriptionSectionPermissionResolverPersistValidator.ValidatorName, argumentName = "model")
public Map<UUID, List<String>> getDescriptionSectionPermissions(@RequestBody DescriptionSectionPermissionResolver model) {
@ -268,7 +272,7 @@ public class DescriptionController {
}
@GetMapping("validate")
@Operation(summary = "Validate if a description is ready for finalization by id")
@OperationWithTenantHeader(summary = "Validate if a description is ready for finalization by id")
@Hidden
public List<DescriptionValidationResult> validate(@RequestParam("descriptionIds") List<UUID> descriptionIds) throws MyApplicationException, MyForbiddenException, MyNotFoundException, InvalidApplicationException {
logger.debug(new MapLogEntry("validating" + Description.class.getSimpleName()).And("descriptionIds", descriptionIds));
@ -285,7 +289,7 @@ public class DescriptionController {
}
@DeleteMapping("{id}")
@Operation(summary = "Delete a description by id")
@OperationWithTenantHeader(summary = "Delete a description by id")
@Swagger404
@Transactional
public void delete(
@ -299,7 +303,7 @@ public class DescriptionController {
}
@GetMapping("{id}/export/{type}")
@Operation(summary = "Export a description in various formats by id")
@OperationWithTenantHeader(summary = "Export a description in various formats by id")
@Swagger404
public ResponseEntity<byte[]> export(
@Parameter(name = "id", description = "The id of a description to export", example = "c0c163dc-2965-45a5-9608-f76030578609", required = true) @PathVariable("id") UUID id,
@ -311,7 +315,7 @@ public class DescriptionController {
}
@PostMapping("field-file/upload")
@Operation(summary = "Upload a file attachment on a field that supports it")
@OperationWithTenantHeader(summary = "Upload a file attachment on a field that supports it")
@Swagger400
@Swagger404
@Transactional
@ -335,7 +339,7 @@ public class DescriptionController {
}
@GetMapping("{id}/field-file/{fileId}")
@Operation(summary = "Fetch a field file attachment as byte array")
@OperationWithTenantHeader(summary = "Fetch a field file attachment as byte array")
@Swagger404
public ResponseEntity<ByteArrayResource> getFieldFile(
@Parameter(name = "id", description = "The id of a description", example = "c0c163dc-2965-45a5-9608-f76030578609", required = true) @PathVariable("id") UUID id,
@ -362,7 +366,7 @@ public class DescriptionController {
}
@PostMapping("update-description-template")
@Operation(summary = "Change the template of a description")
@OperationWithTenantHeader(summary = "Change the template of a description")
@Swagger400
@Swagger404
@Transactional
@ -379,7 +383,7 @@ public class DescriptionController {
}
@RequestMapping(method = RequestMethod.GET, value = "/xml/export/{id}", produces = "application/xml")
@Operation(summary = "Export a description in xml format by id")
@OperationWithTenantHeader(summary = "Export a description in xml format by id")
@Swagger404
public @ResponseBody ResponseEntity<byte[]> getXml(
@Parameter(name = "id", description = "The id of a description to export", example = "c0c163dc-2965-45a5-9608-f76030578609", required = true) @PathVariable UUID id

View File

@ -11,11 +11,14 @@ 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.annotations.ApiImplicitParam;
import io.swagger.v3.oas.annotations.Hidden;
import io.swagger.v3.oas.annotations.Operation;
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;
@ -25,9 +28,10 @@ import org.opencdmp.commons.enums.DmpAccessType;
import org.opencdmp.commons.enums.DmpStatus;
import org.opencdmp.commons.enums.IsActive;
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.SwaggerErrorResponses;
import org.opencdmp.controllers.swagger.annotation.SwaggerCommonErrorResponses;
import org.opencdmp.filetransformerbase.models.misc.PreprocessingDmpModel;
import org.opencdmp.model.DescriptionsToBeFinalized;
import org.opencdmp.model.DmpUser;
@ -70,7 +74,7 @@ import static org.opencdmp.authorization.AuthorizationFlags.Public;
@RestController
@RequestMapping(path = "api/dmp")
@Tag(name = "Plans", description = "Manage plans")
@SwaggerErrorResponses
@SwaggerCommonErrorResponses
public class DmpController {
private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(DmpController.class));
@ -107,7 +111,7 @@ public class DmpController {
}
@PostMapping("public/query")
@Operation(summary = "Query public published plans")
@OperationWithTenantHeader(summary = "Query public published plans")
@Hidden
public QueryResult<PublicDmp> publicQuery(@RequestBody DmpLookup lookup) throws MyApplicationException, MyForbiddenException {
logger.debug("querying {}", Dmp.class.getSimpleName());
@ -123,7 +127,7 @@ public class DmpController {
}
@GetMapping("public/{id}")
@Operation(summary = "Fetch a specific public published plan by id")
@OperationWithTenantHeader(summary = "Fetch a specific public published plan by id")
@Hidden
public PublicDmp publicGet(@PathVariable("id") UUID id, FieldSet fieldSet, Locale locale) throws MyApplicationException, MyForbiddenException, MyNotFoundException {
logger.debug(new MapLogEntry("retrieving" + Dmp.class.getSimpleName()).And("id", id).And("fields", fieldSet));
@ -145,11 +149,17 @@ public class DmpController {
}
@PostMapping("query")
@Operation(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(examples = @ExampleObject(
@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(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
))), responses = @ApiResponse(description = "OK", responseCode = "200", content = @Content(examples = @ExampleObject(
))), responses = @ApiResponse(description = "OK", responseCode = "200", content = @Content(
array = @ArraySchema(
schema = @Schema(
implementation = Dmp.class
)
),
examples = @ExampleObject(
name = "First page",
description = "Example with the first page of paginated results",
value = SwaggerHelpers.Dmp.endpoint_query_response_example
@ -167,7 +177,7 @@ public class DmpController {
}
@GetMapping("{id}")
@Operation(summary = "Fetch a specific plan by id")
@OperationWithTenantHeader(summary = "Fetch a specific plan by id")
@Swagger404
public Dmp Get(
@Parameter(name = "id", description = "The id of a plan to fetch", example = "c0c163dc-2965-45a5-9608-f76030578609", required = true) @PathVariable("id") UUID id,
@ -192,7 +202,7 @@ public class DmpController {
}
@PostMapping("persist")
@Operation(summary = "Create a new or update an existing plan")
@OperationWithTenantHeader(summary = "Create a new or update an existing plan")
@Swagger400
@Swagger404
@Transactional
@ -214,7 +224,7 @@ public class DmpController {
}
@DeleteMapping("{id}")
@Operation(summary = "Delete a plan by id")
@OperationWithTenantHeader(summary = "Delete a plan by id")
@Swagger404
@Transactional
public void Delete(
@ -228,7 +238,7 @@ public class DmpController {
}
@PostMapping("finalize/{id}")
@Operation(summary = "Finalize a plan by id")
@OperationWithTenantHeader(summary = "Finalize a plan by id")
@Swagger404
@Transactional
public boolean finalize(
@ -248,7 +258,7 @@ public class DmpController {
}
@GetMapping("undo-finalize/{id}")
@Operation(summary = "Undo the finalization of a plan by id (only possible if it is not already deposited)")
@OperationWithTenantHeader(summary = "Undo the finalization of a plan by id (only possible if it is not already deposited)")
@Swagger404
@Transactional
public boolean undoFinalize(
@ -269,7 +279,7 @@ public class DmpController {
}
@GetMapping("validate/{id}")
@Operation(summary = "Validate if a plan is ready for finalization by id")
@OperationWithTenantHeader(summary = "Validate if a plan is ready for finalization by id")
@Hidden
public DmpValidationResult validate(@PathVariable("id") UUID id) throws MyApplicationException, MyForbiddenException, MyNotFoundException, InvalidApplicationException {
logger.debug(new MapLogEntry("validating" + Dmp.class.getSimpleName()).And("id", id));
@ -286,7 +296,7 @@ public class DmpController {
}
@PostMapping("clone")
@Operation(summary = "Create a clone of an existing plan")
@OperationWithTenantHeader(summary = "Create a clone of an existing plan")
@Swagger400
@Swagger404
@Transactional
@ -310,7 +320,7 @@ public class DmpController {
}
@PostMapping("new-version")
@Operation(summary = "Create a new version of an existing plan")
@OperationWithTenantHeader(summary = "Create a new version of an existing plan")
@Swagger400
@Swagger404
@Transactional
@ -332,7 +342,7 @@ public class DmpController {
}
@PostMapping("{id}/assign-users")
@Operation(summary = "Assign users to the plan by id")
@OperationWithTenantHeader(summary = "Assign users to the plan by id")
@Transactional
@ValidationFilterAnnotation(validator = DmpUserPersist.DmpUserPersistValidator.ValidatorName, argumentName = "model")
@Hidden
@ -350,7 +360,7 @@ public class DmpController {
}
@PostMapping("remove-user")
@Operation(summary = "Remove a user association with the plan")
@OperationWithTenantHeader(summary = "Remove a user association with the plan")
@Transactional
@ValidationFilterAnnotation(validator = DmpUserRemovePersist.DmpUserRemovePersistValidator.ValidatorName, argumentName = "model")
@Hidden
@ -368,7 +378,7 @@ public class DmpController {
}
@GetMapping("{id}/export/{transformerId}/{type}")
@Operation(summary = "Export a plan in various formats by id")
@OperationWithTenantHeader(summary = "Export a plan in various formats by id")
@Swagger404
public ResponseEntity<byte[]> export(
@Parameter(name = "id", description = "The id of a plan to export", example = "c0c163dc-2965-45a5-9608-f76030578609", required = true) @PathVariable("id") UUID id,
@ -387,7 +397,7 @@ public class DmpController {
}
@PostMapping("{id}/invite-users")
@Operation(summary = "Send user invitations for the plan by id")
@OperationWithTenantHeader(summary = "Send user invitations for the plan by id")
@Transactional
@ValidationFilterAnnotation(validator = DmpUserInvitePersist.DmpUserInvitePersistValidator.ValidatorName, argumentName = "model")
@Hidden
@ -404,7 +414,7 @@ public class DmpController {
}
@GetMapping("{id}/token/{token}/invite-accept")
@Operation(summary = "Accept an invitation token for a plan by id")
@OperationWithTenantHeader(summary = "Accept an invitation token for a plan by id")
@Transactional
@Hidden
public boolean acceptInvitation(@PathVariable("id") UUID id, @PathVariable("token") String token) throws InvalidApplicationException, JAXBException, IOException {
@ -420,7 +430,7 @@ public class DmpController {
}
@RequestMapping(method = RequestMethod.GET, value = "/xml/export/{id}", produces = "application/xml")
@Operation(summary = "Export a plan in xml format by id")
@OperationWithTenantHeader(summary = "Export a plan in xml format by id")
@Swagger404
public @ResponseBody ResponseEntity<byte[]> getXml(
@Parameter(name = "id", description = "The id of a plan to export", example = "c0c163dc-2965-45a5-9608-f76030578609", required = true) @PathVariable UUID id
@ -436,7 +446,7 @@ public class DmpController {
}
@RequestMapping(method = RequestMethod.POST, value = "/xml/import")
@Operation(summary = "Import a plan from an xml file")
@OperationWithTenantHeader(summary = "Import a plan from an xml file")
@Transactional
public Dmp importXml(
@RequestParam("file") MultipartFile file,
@ -455,7 +465,7 @@ public class DmpController {
}
@PostMapping("json/preprocessing")
@Operation(summary = "preprocessing a plan from an json file")
@OperationWithTenantHeader(summary = "preprocessing a plan from an json file")
@Transactional
public PreprocessingDmpModel preprocessing(
@RequestParam("fileId") UUID fileId,
@ -474,7 +484,7 @@ public class DmpController {
}
@PostMapping("json/import")
@Operation(summary = "Import a plan from an json file")
@OperationWithTenantHeader(summary = "Import a plan from an json file")
@ValidationFilterAnnotation(validator = DmpCommonModelConfig.DmpCommonModelConfigValidator.ValidatorName, argumentName = "model")
@Transactional
public Dmp importJson(

View File

@ -0,0 +1,48 @@
package org.opencdmp.controllers.swagger.annotation;
import io.swagger.v3.oas.annotations.ExternalDocumentation;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.enums.ParameterIn;
import io.swagger.v3.oas.annotations.extensions.Extension;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.parameters.RequestBody;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import io.swagger.v3.oas.annotations.servers.Server;
import org.springframework.core.annotation.AliasFor;
import java.lang.annotation.*;
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.FIELD, ElementType.METHOD})
@Operation
public @interface OperationWithTenantHeader {
@AliasFor(annotation = Operation.class, attribute = "method") String method() default "";
@AliasFor(annotation = Operation.class, attribute = "tags") String[] tags() default {};
@AliasFor(annotation = Operation.class, attribute = "summary") String summary() default "";
@AliasFor(annotation = Operation.class, attribute = "description") String description() default "";
@AliasFor(annotation = Operation.class, attribute = "requestBody") RequestBody requestBody() default @RequestBody;
@AliasFor(annotation = Operation.class, attribute = "externalDocs") ExternalDocumentation externalDocs() default @ExternalDocumentation;
@AliasFor(annotation = Operation.class, attribute = "operationId") String operationId() default "";
@AliasFor(annotation = Operation.class, attribute = "parameters") Parameter[] parameters() default {
@Parameter(
name = "x-tenant",
description = "This is a header containing the tenant scope of the request. " +
"It is required on every authenticated request. " +
"If the request does not target a specific tenant resource, this header should be set to the value 'default'.",
required = true,
in = ParameterIn.HEADER,
schema = @Schema(implementation = String.class),
example = "default"
)
};
@AliasFor(annotation = Operation.class, attribute = "responses") ApiResponse[] responses() default {};
@AliasFor(annotation = Operation.class, attribute = "deprecated") boolean deprecated() default false;
@AliasFor(annotation = Operation.class, attribute = "security") SecurityRequirement[] security() default {};
@AliasFor(annotation = Operation.class, attribute = "servers") Server[] servers() default {};
@AliasFor(annotation = Operation.class, attribute = "extensions") Extension[] extensions() default {};
@AliasFor(annotation = Operation.class, attribute = "hidden") boolean hidden() default false;
@AliasFor(annotation = Operation.class, attribute = "ignoreJsonView") boolean ignoreJsonView() default false;
}

View File

@ -7,6 +7,6 @@ import java.lang.annotation.*;
@Target({ElementType.TYPE, ElementType.FIELD, ElementType.METHOD})
@Swagger500
@Swagger403
public @interface SwaggerErrorResponses {
public @interface SwaggerCommonErrorResponses {
}

View File

@ -12,13 +12,17 @@ import Admonition from '@theme/Admonition';
The swagger UI is available at the `/swagger-ui/index.html` url. It contains documentation for the following API endpoints.
<Tabs>
<TabItem value="public" label="Public API">
<TabItem value="public" label="Legacy">
- **/api/public/dmps/\*\***
- **/api/public/descriptions/\*\***
<Admonition type="info">
<p>These endpoints do not require authentication.</p>
</Admonition>
</TabItem>
<TabItem value="internal" label="Internal API">
<TabItem value="internal" label="Current">
- **/api/dmp/\*\***
- **/api/description/\*\***