Commit 748ea6ff authored by femiadeyemi's avatar femiadeyemi
Browse files

redesign of cerebrum

Modification:

- introduce an anotation called ForeignKey. This can be use to ensure
    that the uuid reference in another entity is valid and cascading
    effect are maintained.
- modify some entities and added some new entities like Image, Person
    and Software. Also, corresponding repositories and services.
- redesign the base service and create a kind of base repository

Target: master
parent 71b35f59
Pipeline #78256 failed with stages
in 1 minute and 29 seconds
package de.helmholtz.marketplace.cerebrum.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface ForeignKey
{
public String key() default "";
}
package de.helmholtz.marketplace.cerebrum.controller;
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.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.SneakyThrows;
import org.bson.BsonBinarySubType;
import org.bson.types.Binary;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.util.UriComponentsBuilder;
import javax.validation.constraints.Min;
import java.util.Base64;
import java.util.List;
import de.helmholtz.marketplace.cerebrum.entity.Image;
import de.helmholtz.marketplace.cerebrum.errorhandling.CerebrumApiError;
import de.helmholtz.marketplace.cerebrum.service.ImageService;
import de.helmholtz.marketplace.cerebrum.utils.CerebrumControllerUtilities;
@RestController
@Validated
@RequestMapping(produces = MediaType.APPLICATION_JSON_VALUE,
path = "${spring.data.rest.base-path}/images")
@Tag(name = "images", description = "The Image API")
public class ImageController
{
private final ImageService imageService;
public ImageController(ImageService imageService)
{
this.imageService = imageService;
}
/* get Images */
@Operation(summary = "get array list of all images")
@ApiResponses(value = {
@ApiResponse(responseCode = "200",
description = "successful operation",
content = @Content(array = @ArraySchema(
schema = @Schema(implementation = Image.class)))),
@ApiResponse(responseCode = "400", description = "invalid request",
content = @Content(array = @ArraySchema(
schema = @Schema(implementation = CerebrumApiError.class))))
})
@GetMapping(path = "")
public Iterable<Image> getImages(
@Parameter(description = "specify the name of the image to search for")
@RequestParam(value = "name") String name,
@Parameter(description = "specify the page number")
@RequestParam(value = "page", defaultValue = "0") @Min(0) Integer page,
@Parameter(description = "limit the number of records returned in one page")
@RequestParam(value = "size", defaultValue = "20") @Min(1) Integer size,
@Parameter(description = "sort the fetched data in either ascending (asc) " +
"or descending (desc) according to one or more of the images " +
"properties. Eg. to sort the list in ascending order base on the " +
"name property; the value will be set to name.asc")
@RequestParam(value = "sort", defaultValue = "name.asc") List<String> sorts)
{
return (name == null || name.isEmpty()) ?
imageService.getImages(PageRequest.of(page, size,
Sort.by(CerebrumControllerUtilities.getOrders(sorts)))) :
imageService.getImages(name, PageRequest.of(page, size,
Sort.by(CerebrumControllerUtilities.getOrders(sorts))));
}
/* get Image */
@Operation(summary = "find image by ID",
description = "Returns a detailed image information " +
"corresponding to the ID")
@ApiResponses(value = {
@ApiResponse(responseCode = "200",
description = "successful operation",
content = @Content(schema = @Schema(implementation = Image.class))),
@ApiResponse(responseCode = "400", description = "invalid image ID supplied",
content = @Content(schema = @Schema(implementation = CerebrumApiError.class))),
@ApiResponse(responseCode = "404", description = "image not found",
content = @Content(schema = @Schema(implementation = CerebrumApiError.class)))
})
@GetMapping(path = "/{uuid}")
public Image getImage(
@Parameter(description = "ID of the image that needs to be fetched")
@PathVariable(name = "uuid") String uuid)
{
return imageService.getImage(uuid);
}
/* create image */
@SneakyThrows
@PreAuthorize("isAuthenticated()")
@Operation(summary = "add a new image",
security = @SecurityRequirement(name = "hdf-aai"))
@ApiResponses(value = {
@ApiResponse(responseCode = "201", description = "image created",
content = @Content(schema = @Schema(implementation = Image.class))),
@ApiResponse(responseCode = "400", description = "invalid ID supplied",
content = @Content(schema = @Schema(implementation = CerebrumApiError.class))),
@ApiResponse(responseCode = "401", description = "unauthorised", content = @Content())
})
@PostMapping("")
public ResponseEntity<Image> createImage(
@Parameter(description = "name of the image")
@RequestParam("name") String name,
@RequestParam("image") MultipartFile image,
UriComponentsBuilder uriComponentsBuilder)
{
Image img = new Image();
img.setName(name);
img.setImage(
Base64.getEncoder().encodeToString(new Binary(BsonBinarySubType.BINARY, image.getBytes()).getData()));
return imageService.createImage(img, uriComponentsBuilder);
}
/* update image */
@SneakyThrows
@PreAuthorize("isAuthenticated()")
@Operation(summary = "update an existing image",
description = "Update part (or all) of an image information",
security = @SecurityRequirement(name = "hdf-aai"))
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "successful operation",
content = @Content(schema = @Schema(implementation = Image.class))),
@ApiResponse(responseCode = "201", description = "image created",
content = @Content(schema = @Schema(implementation = Image.class))),
@ApiResponse(responseCode = "400", description = "invalid ID supplied",
content = @Content(schema = @Schema(implementation = CerebrumApiError.class))),
@ApiResponse(responseCode = "401", description = "unauthorised", content = @Content())
})
@PutMapping(path = "/{uuid}", consumes = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Image> updateImage(
@Parameter(description = "Unique identifier of the image that needs to be updated")
@PathVariable(name = "uuid") String uuid,
@Parameter(description = "name of the image")
@RequestParam("name") String name,
@Parameter(description = "")
@RequestParam("image") MultipartFile image, UriComponentsBuilder uriComponentsBuilder)
{
Image img = new Image();
img.setName(name);
img.setImage(Base64.getEncoder().encodeToString(
new Binary(BsonBinarySubType.BINARY, image.getBytes()).getData()));
return imageService.updateImage(uuid, img, uriComponentsBuilder);
}
/* delete Image */
@PreAuthorize("isAuthenticated()")
@Operation(summary = "deletes an image",
description = "Removes the record of the specified " +
"image id from the database. The image " +
"unique identification number cannot be null or empty",
security = @SecurityRequirement(name = "hdf-aai"))
@ApiResponses(value = {
@ApiResponse(responseCode = "204", description = "successful operation", content = @Content()),
@ApiResponse(responseCode = "401", description = "unauthorised", content = @Content())
})
@DeleteMapping(path = "/{uuid}")
public ResponseEntity<Image> deleteImage(
@Parameter(description="Image id to delete", required=true)
@PathVariable(name = "uuid") String uuid)
{
return imageService.deleteImage(uuid);
}
}
......@@ -11,6 +11,7 @@ import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.SneakyThrows;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.http.MediaType;
......@@ -92,6 +93,7 @@ public class MarketServiceController
}
/* create Service */
@SneakyThrows
@PreAuthorize("isAuthenticated()")
@Operation(summary = "add a new service", security = @SecurityRequirement(name = "hdf-aai"))
@ApiResponses(value = {
......
......@@ -267,10 +267,9 @@ public class MarketUserController {
newPerson.setFirstName(user.get("given_name").asText());
newPerson.setLastName(user.get("family_name").asText());
newPerson.addEmail(user.get("email").asText());
Person details = personService.createPerson(newPerson);
newUser.setProfile(details);
newUser.setProfileId(personService.createPerson(newPerson).getUuid());
} else {
newUser.setProfile(p);
newUser.setProfileId(p.getUuid());
}
newUser.setSub(user.get("sub").asText());
return marketUserService.createUser(newUser);
......
package de.helmholtz.marketplace.cerebrum.controller;
import com.github.fge.jsonpatch.JsonPatch;
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.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.util.UriComponentsBuilder;
import javax.validation.Valid;
import javax.validation.constraints.Min;
import java.util.List;
import de.helmholtz.marketplace.cerebrum.entity.Person;
import de.helmholtz.marketplace.cerebrum.errorhandling.CerebrumApiError;
import de.helmholtz.marketplace.cerebrum.service.PersonService;
import de.helmholtz.marketplace.cerebrum.utils.CerebrumControllerUtilities;
@RestController
@Validated
@RequestMapping(produces = MediaType.APPLICATION_JSON_VALUE,
path = "${spring.data.rest.base-path}/persons")
@Tag(name = "persons", description = "The Person API")
public class PersonController
{
private final PersonService personService;
public PersonController(PersonService personService)
{
this.personService = personService;
}
/* get persons */
@Operation(summary = "get array list of all persons")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "successful operation",
content = @Content(array = @ArraySchema(
schema = @Schema(implementation = Person.class)))),
@ApiResponse(responseCode = "400", description = "invalid request",
content = @Content(array = @ArraySchema(schema = @Schema(implementation = CerebrumApiError.class))))
})
@GetMapping(path = "")
public Iterable<Person> getPersons(
@Parameter(description = "specify the page number")
@RequestParam(value = "page", defaultValue = "0") @Min(0) Integer page,
@Parameter(description = "limit the number of records returned in one page")
@RequestParam(value = "size", defaultValue = "20") @Min(1) Integer size,
@Parameter(description = "sort the fetched data in either ascending (asc) " +
"or descending (desc) according to one or more of the person " +
"properties. Eg. to sort the list in ascending order base on the " +
"firstName property; the value will be set to firstName.asc")
@RequestParam(value = "sort", defaultValue = "firstName.asc") List<String> sorts)
{
return personService.getPersons(
PageRequest.of(page, size, Sort.by(CerebrumControllerUtilities.getOrders(sorts))));
}
/* get person */
@Operation(summary = "find person by UUID", description = "Returns a detailed person information corresponding to the UUID")
@ApiResponses(value = {
@ApiResponse(responseCode = "200",
description = "successful operation",
content = @Content(schema = @Schema(implementation = Person.class))),
@ApiResponse(responseCode = "400", description = "invalid person UUID supplied",
content = @Content(schema = @Schema(implementation = CerebrumApiError.class))),
@ApiResponse(responseCode = "404", description = "person not found",
content = @Content(schema = @Schema(implementation = CerebrumApiError.class)))
})
@GetMapping(path = "/{uuid}")
public Person getPerson(
@Parameter(description = "UUID of the person that needs to be fetched")
@PathVariable() String uuid)
{
return personService.getPerson(uuid);
}
/* create a person */
@PreAuthorize("isAuthenticated()")
@Operation(summary = "add a new person",
security = @SecurityRequirement(name = "hdf-aai"))
@ApiResponses(value = {
@ApiResponse(responseCode = "201", description = "person created",
content = @Content(schema = @Schema(implementation = Person.class))),
@ApiResponse(responseCode = "400", description = "invalid UUID supplied",
content = @Content(schema = @Schema(implementation = CerebrumApiError.class))),
@ApiResponse(responseCode = "401", description = "unauthorised", content = @Content()),
@ApiResponse(responseCode = "403", description = "forbidden", content = @Content())
})
@PostMapping(path = "", consumes = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Person> createPerson(
@Parameter(description = "Person object that needs to be added to the marketplace",
required = true, schema = @Schema(implementation = Person.class))
@Valid @RequestBody Person person, UriComponentsBuilder uriComponentsBuilder)
{
return personService.createPerson(person, uriComponentsBuilder);
}
/* update person */
@PreAuthorize("isAuthenticated()")
@Operation(summary = "update an existing person",
description = "Update part (or all) of a person information",
security = @SecurityRequirement(name = "hdf-aai"))
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "successful operation",
content = @Content(schema = @Schema(implementation = Person.class))),
@ApiResponse(responseCode = "201", description = "person created",
content = @Content(schema = @Schema(implementation = Person.class))),
@ApiResponse(responseCode = "400", description = "invalid UUID supplied",
content = @Content(schema = @Schema(implementation = CerebrumApiError.class))),
@ApiResponse(responseCode = "401", description = "unauthorised", content = @Content()),
@ApiResponse(responseCode = "403", description = "forbidden", content = @Content())
})
@PutMapping(path = "/{uuid}", consumes = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Person> updatePers(
@Parameter(
description = "Person to update or replace. This cannot be null or empty.",
schema = @Schema(implementation = Person.class),
required = true) @Valid @RequestBody Person person,
@Parameter(description = "UUID of the person that needs to be updated")
@PathVariable() String uuid, UriComponentsBuilder uriComponentsBuilder)
{
return personService.updatePerson(uuid, person, uriComponentsBuilder);
}
/* JSON PATCH person */
@PreAuthorize("isAuthenticated()")
@Operation(summary = "partially update an existing person",
security = @SecurityRequirement(name = "hdf-aai"))
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "successful operation",
content = @Content(schema = @Schema(implementation = Person.class))),
@ApiResponse(responseCode = "400", description = "invalid UUID or json patch body",
content = @Content(schema = @Schema(implementation = CerebrumApiError.class))),
@ApiResponse(responseCode = "401", description = "unauthorised", content = @Content()),
@ApiResponse(responseCode = "403", description = "forbidden", content = @Content()),
@ApiResponse(responseCode = "404", description = "person not found",
content = @Content(schema = @Schema(implementation = CerebrumApiError.class))),
@ApiResponse(responseCode = "500", description = "internal server error",
content = @Content(schema = @Schema(implementation = CerebrumApiError.class)))
})
@PatchMapping(path = "/{uuid}", consumes = "application/json-patch+json")
public ResponseEntity<Person> partialUpdatePerson(
@Parameter(description = "JSON Patch document structured as a JSON " +
"array of objects where each object contains one of the six " +
"JSON Patch operations: add, remove, replace, move, copy, and test",
schema = @Schema(implementation = JsonPatch.class),
required = true) @Valid @RequestBody JsonPatch patch,
@Parameter(description = "UUID of the person that needs to be partially updated")
@PathVariable() String uuid)
{
return personService.partiallyUpdatePerson(uuid, patch);
}
/* delete person */
@PreAuthorize("isAuthenticated()")
@Operation(summary = "deletes a person",
description = "Removes the record of the specified " +
"person UUID from the database. The person " +
"unique identification number cannot be null or empty",
security = @SecurityRequirement(name = "hdf-aai"))
@ApiResponses(value = {
@ApiResponse(responseCode = "204", description = "successful operation", content = @Content()),
@ApiResponse(responseCode = "401", description = "unauthorised", content = @Content()),
@ApiResponse(responseCode = "403", description = "forbidden", content = @Content()),
})
@DeleteMapping(path = "/{uuid}")
public ResponseEntity<Person> deletePerson(
@Parameter(description = "person UUID to delete", required = true)
@PathVariable(name = "uuid") String uuid)
{
return personService.deletePerson(uuid);
}
}
package de.helmholtz.marketplace.cerebrum.controller;
import com.github.fge.jsonpatch.JsonPatch;
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.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.util.UriComponentsBuilder;
import javax.validation.Valid;
import javax.validation.constraints.Min;
import java.util.List;
import de.helmholtz.marketplace.cerebrum.entity.Software;
import de.helmholtz.marketplace.cerebrum.errorhandling.CerebrumApiError;
import de.helmholtz.marketplace.cerebrum.service.SoftwareService;
import de.helmholtz.marketplace.cerebrum.utils.CerebrumControllerUtilities;
@RestController
@Validated
@RequestMapping(produces = MediaType.APPLICATION_JSON_VALUE,
path = "${spring.data.rest.base-path}/software")
@Tag(name = "software", description = "The Software API")
public class SoftwareController
{
private final SoftwareService softwareService;
public SoftwareController(SoftwareService softwareService)
{
this.softwareService = softwareService;
}
/* get list of software */
@Operation(summary = "get array list of all software")
@ApiResponses(value = {
@ApiResponse(responseCode = "200",
description = "successful operation",
content = @Content(array = @ArraySchema(
schema = @Schema(implementation = Software.class)))),
@ApiResponse(responseCode = "400", description = "invalid request",
content = @Content(array = @ArraySchema(
schema = @Schema(implementation = CerebrumApiError.class))))
})
@GetMapping(path = "")
public Iterable<Software> getSoftware(
@Parameter(description = "specify the name of the software to search for")
@RequestParam(value = "name") String name,
@Parameter(description = "specify the page number")
@RequestParam(value = "page", defaultValue = "0") @Min(0) Integer page,
@Parameter(description = "limit the number of records returned in one page")
@RequestParam(value = "size", defaultValue = "20") @Min(1) Integer size,
@Parameter(description = "sort the fetched data in either ascending (asc) " +
"or descending (desc) according to one or more of the software " +
"properties. Eg. to sort the list in ascending order base on the " +
"name property; the value will be set to name.asc")
@RequestParam(value = "sort", defaultValue = "name.asc") List<String> sorts)
{
return (name == null || name.isEmpty()) ?
softwareService.getSoftware(PageRequest.of(page, size,
Sort.by(CerebrumControllerUtilities.getOrders(sorts)))) :
softwareService.getSoftware(name, PageRequest.of(page, size,
Sort.by(CerebrumControllerUtilities.getOrders(sorts))));
}
/* get Software */
@Operation(summary = "find software by ID",
description = "Returns a detailed software information " +
"corresponding to the ID")
@ApiResponses(value = {
@ApiResponse(responseCode = "200",
description = "successful operation",
content = @Content(schema = @Schema(implementation = Software.class))),
@ApiResponse(responseCode = "400", description = "invalid software ID supplied",
content = @Content(schema = @Schema(implementation = CerebrumApiError.class))),
@ApiResponse(responseCode = "404", description = "software not found",
content = @Content(schema = @Schema(implementation = CerebrumApiError.class)))
})
@GetMapping(path = "/{uuid}")
public Software getSoftware(
@Parameter(description = "ID of the software that needs to be fetched")
@PathVariable(name = "uuid") String uuid)
{
return softwareService.getSoftware(uuid);
}
/* create Software */
@PreAuthorize("isAuthenticated()")
@Operation(summary = "add a new software",
security = @SecurityRequirement(name = "hdf-aai"))
@ApiResponses(value = {
@ApiResponse(responseCode = "201", description = "software created",
content = @Content(schema = @Schema(implementation = Software.class))),
@ApiResponse(responseCode = "400", description = "invalid ID supplied",
content = @Content(schema = @Schema(implementation = CerebrumApiError.class))),
@ApiResponse(responseCode = "401", description = "unauthorised", content = @Content())
})
@PostMapping(path = "", consumes = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Software> createSoftware(
@Parameter(description = "software object that needs to be added to the marketplace",
required = true, schema = @Schema(implementation = Software.class))
@Valid @RequestBody Software software, UriComponentsBuilder uriComponentsBuilder)
{