Commit 5bf5cac9 authored by femiadeyemi's avatar femiadeyemi
Browse files

add relationship between organisation and service entity

Motivation:

The services that will be part of the marketplace are hosted by
the helmholtz organisations. Hence, this relationship needs to
be modelled inside cerebrum

Modification:

- create a new relationship called 'HOSTED_BY' that will be
    linking services to organisations.
- add capability to add and delete the relationship inside
    the market-service controller, service and repository

Result:

HOSTED_BY relationship can now be added and deleted through the
restful api.

Target: master
Review-at: https://gitlab.hzdr.de/hifis-technical-platform/helmholtz-cerebrum/-/merge_requests/30
parent 42e2685e
......@@ -33,6 +33,7 @@ import javax.validation.constraints.Min;
import java.util.List;
import de.helmholtz.marketplace.cerebrum.entities.MarketService;
import de.helmholtz.marketplace.cerebrum.entities.relationship.ServiceProvider;
import de.helmholtz.marketplace.cerebrum.errorhandling.CerebrumApiError;
import de.helmholtz.marketplace.cerebrum.service.MarketServiceService;
import de.helmholtz.marketplace.cerebrum.utils.CerebrumControllerUtilities;
......@@ -87,7 +88,7 @@ public class MarketServiceController
@Parameter(description = "UUID of the service that needs to be fetched")
@PathVariable() String uuid)
{
return marketServiceService.getUser(uuid);
return marketServiceService.getService(uuid);
}
/* create Service */
......@@ -179,4 +180,26 @@ public class MarketServiceController
{
return marketServiceService.deleteService(uuid);
}
//serviceProvider
@PreAuthorize("isAuthenticated()")
@Operation(security = @SecurityRequirement(name = "hdf-aai"))
@PostMapping(path = "/providers",
consumes = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<MarketService> addProvider(@Valid @RequestBody ServiceProvider provider)
{
return marketServiceService.addProvider(provider);
}
@PreAuthorize("isAuthenticated()")
@Operation(security = @SecurityRequirement(name = "hdf-aai"))
@DeleteMapping(path = "/affiliations")
public ResponseEntity<MarketService> deleteProviders(
@RequestParam String serviceKey,
@RequestParam String serviceValue,
@RequestParam String organizationKey,
@RequestParam String organizationValue)
{
return marketServiceService.deleteProviders(serviceKey, serviceValue, organizationKey, organizationValue);
}
}
package de.helmholtz.marketplace.cerebrum.entities;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import io.swagger.v3.oas.annotations.media.Schema;
import org.neo4j.ogm.annotation.GeneratedValue;
import org.neo4j.ogm.annotation.Id;
import org.neo4j.ogm.annotation.Relationship;
import javax.validation.constraints.NotNull;
import java.util.Date;
import java.util.List;
import de.helmholtz.marketplace.cerebrum.entities.relationship.ServiceProvider;
import de.helmholtz.marketplace.cerebrum.utils.CerebrumEntityUuidGenerator;
import static de.helmholtz.marketplace.cerebrum.utils.CerebrumEntityUuidGenerator.generate;
public class MarketService {
public class MarketService
{
@Schema(description = "Unique identifier of the market service.",
example = "svc-01eac6d7-0d35-1812-a3ed-24aec4231940", required = true)
@Id @GeneratedValue(strategy = CerebrumEntityUuidGenerator.class)
private String uuid;
@NotNull
@Schema(description = "Name of a Service", example = "Sync+Share", required = true)
private String name;
@Schema(description = "Description of a Service", example = "A awesome Sync+Share Service provides by Helmholtz Zentrum xy")
@Schema(description = "Description of a Service",
example = "A awesome Sync+Share Service provides by Helmholtz Zentrum xy")
private String description;
@Schema(description = "Url to a Service", example = "serviceXy.helmholtz.de")
private String url;
@Schema(description = "Creation date of a Service", example = "2020-02-19")
private Date created;
@Schema(description = "Date of last modification", example = "2020-03-24")
private Date lastModified;
@Schema(description = "Specifies the current lifecycle")
private LifecycleStatus lifecycleStatus;
@Schema(description = "Specifies the authentication which a user can use to log in to a service")
private Authentication authentication;
@Schema(description = "Indicates who is providing the service")
private List<Organization> organizations;
@Schema(description = "List of services provided by this organisation")
@JsonIgnoreProperties({"marketService"})
@Relationship(type = "HOSTED_BY")
private List<ServiceProvider> serviceProviders;
public String getUuid()
{
......@@ -47,67 +62,83 @@ public class MarketService {
? uuid : generate("org");
}
public String getName() {
public String getName()
{
return name;
}
public void setName(String name) {
public void setName(String name)
{
this.name = name;
}
public String getDescription() {
public String getDescription()
{
return description;
}
public void setDescription(String description) {
public void setDescription(String description)
{
this.description = description;
}
public String getUrl() {
public String getUrl()
{
return url;
}
public void setUrl(String url) {
public void setUrl(String url)
{
this.url = url;
}
public Date getCreated() {
public Date getCreated()
{
return created;
}
public void setCreated(Date created) {
public void setCreated(Date created)
{
this.created = created;
}
public Date getLastModified() {
public Date getLastModified()
{
return lastModified;
}
public void setLastModified(Date lastModified) {
public void setLastModified(Date lastModified)
{
this.lastModified = lastModified;
}
public LifecycleStatus getLifecycleStatus() {
public LifecycleStatus getLifecycleStatus()
{
return lifecycleStatus;
}
public void setLifecycleStatus(LifecycleStatus lifecycleStatus) {
public void setLifecycleStatus(LifecycleStatus lifecycleStatus)
{
this.lifecycleStatus = lifecycleStatus;
}
public Authentication getAuthentication() {
public Authentication getAuthentication()
{
return authentication;
}
public void setAuthentication(Authentication authentication) {
public void setAuthentication(Authentication authentication)
{
this.authentication = authentication;
}
public List<Organization> getOrganizations() {
return organizations;
public List<ServiceProvider> getServiceProviders()
{
return serviceProviders;
}
public void setOrganizations(List<Organization> organizations) {
this.organizations = organizations;
public void setOrganizations(List<ServiceProvider> serviceProviders)
{
this.serviceProviders = serviceProviders;
}
}
......@@ -13,6 +13,7 @@ import java.util.List;
import java.util.Objects;
import de.helmholtz.marketplace.cerebrum.entities.relationship.Affiliation;
import de.helmholtz.marketplace.cerebrum.entities.relationship.ServiceProvider;
import de.helmholtz.marketplace.cerebrum.utils.CerebrumEntityUuidGenerator;
import static de.helmholtz.marketplace.cerebrum.utils.CerebrumEntityUuidGenerator.generate;
......@@ -47,8 +48,11 @@ public class Organization
@URL(message = "Web address")
@NotNull
private String url;
@JsonIgnoreProperties({"organization"})
@Schema(description = "A list of Services which are provided by the organization")
private Iterable<MarketService> serviceList;
@Relationship(type = "HOSTED_BY", direction = INCOMING)
private List<ServiceProvider> hostedServices;
@JsonIgnoreProperties("organization")
@Schema(description = "List of people that are affiliated with this organisation")
......@@ -107,14 +111,14 @@ public class Organization
this.url = url;
}
public Iterable<MarketService> getServiceList()
public List<ServiceProvider> getHostedServices()
{
return serviceList;
return hostedServices;
}
public void setServiceList(Iterable<MarketService> serviceList)
public void setHostedServices(List<ServiceProvider> serviceHosted)
{
this.serviceList = serviceList;
this.hostedServices = serviceHosted;
}
public List<Affiliation> getMembers()
......
package de.helmholtz.marketplace.cerebrum.entities.relationship;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import org.neo4j.ogm.annotation.EndNode;
import org.neo4j.ogm.annotation.GeneratedValue;
import org.neo4j.ogm.annotation.Id;
import org.neo4j.ogm.annotation.RelationshipEntity;
import org.neo4j.ogm.annotation.StartNode;
import java.util.Objects;
import de.helmholtz.marketplace.cerebrum.entities.MarketService;
import de.helmholtz.marketplace.cerebrum.entities.Organization;
@RelationshipEntity(type = "HOSTED_BY")
public class ServiceProvider
{
@Id @GeneratedValue Long id;
private String serviceTechnicalName;
@StartNode
@JsonIgnoreProperties("serviceProviders")
private MarketService marketService;
@EndNode
@JsonIgnoreProperties({"hostedServices", "members"})
private Organization organization;
public String getServiceTechnicalName()
{
return serviceTechnicalName;
}
public void setServiceTechnicalName(String serviceTechnicalName)
{
this.serviceTechnicalName = serviceTechnicalName;
}
public MarketService getMarketService()
{
return marketService;
}
public void setMarketService(MarketService marketService)
{
this.marketService = marketService;
}
public Organization getOrganization()
{
return organization;
}
public void setOrganization(Organization organization)
{
this.organization = organization;
}
@Override
public boolean equals(Object o)
{
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ServiceProvider serviceProvider = (ServiceProvider) o;
return Objects.equals(serviceTechnicalName, serviceProvider.serviceTechnicalName) &&
marketService.equals(serviceProvider.marketService) &&
organization.equals(serviceProvider.organization);
}
@Override
public int hashCode()
{
return Objects.hash(serviceTechnicalName, marketService, organization);
}
}
package de.helmholtz.marketplace.cerebrum.repository;
import org.springframework.data.neo4j.annotation.Query;
import org.springframework.data.neo4j.repository.Neo4jRepository;
import org.springframework.data.repository.query.Param;
import java.util.Optional;
......@@ -10,6 +12,24 @@ public interface MarketServiceRepository extends Neo4jRepository<MarketService,
{
Optional<MarketService> findByUuid(String uuid);
Optional<MarketService> findByName(@Param("name") String name);
Optional<MarketService> findByUrl(@Param("url") String url);
@Query("MATCH (service:MarketService),(org:Organization) " +
"WHERE service.uuid = $serviceUuid AND org.uuid = $orgUuid " +
"CREATE (service)-[r:HOSTED_BY { serviceTechnicalName : $serviceTechnicalName }]->(org) " +
"RETURN service, r")
MarketService createHostedInRelationship(@Param("serviceUuid") String serviceUuid,
@Param("orgUuid") String orgUuid,
@Param("serviceTechnicalName") String serviceTechnicalName);
@SuppressWarnings("UnusedReturnValue")
@Query("MATCH (service:MarketService)-[r:HOSTED_BY]->(org:Organization) " +
"WHERE service.uuid = $serviceUuid AND org.uuid = $orgUuid " +
"DELETE r")
Long deleteServiceProviders(@Param("serviceUuid") String serviceUuid, @Param("orgUuid") String orgUuid);
@SuppressWarnings("UnusedReturnValue")
Long deleteByUuid(String id);
}
......@@ -3,23 +3,34 @@ package de.helmholtz.marketplace.cerebrum.service;
import com.github.fge.jsonpatch.JsonPatch;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.server.ResponseStatusException;
import org.springframework.web.util.UriComponentsBuilder;
import java.lang.reflect.Field;
import de.helmholtz.marketplace.cerebrum.entities.MarketService;
import de.helmholtz.marketplace.cerebrum.entities.Organization;
import de.helmholtz.marketplace.cerebrum.entities.relationship.ServiceProvider;
import de.helmholtz.marketplace.cerebrum.repository.MarketServiceRepository;
import de.helmholtz.marketplace.cerebrum.service.common.CerebrumServiceBase;
import static de.helmholtz.marketplace.cerebrum.utils.CerebrumControllerUtilities.checkField;
@Service
public class MarketServiceService extends CerebrumServiceBase<MarketService, MarketServiceRepository>
{
private final MarketServiceRepository marketServiceRepository;
private final OrganizationService organizationService;
public MarketServiceService(MarketServiceRepository marketServiceRepository)
public MarketServiceService(MarketServiceRepository marketServiceRepository,
OrganizationService organizationService)
{
super(MarketService.class, MarketServiceRepository.class);
this.marketServiceRepository = marketServiceRepository;
this.organizationService = organizationService;
}
public Page<MarketService> getServices(PageRequest page)
......@@ -27,11 +38,16 @@ public class MarketServiceService extends CerebrumServiceBase<MarketService, Mar
return getAllEntities(page, marketServiceRepository);
}
public MarketService getUser(String uuid)
public MarketService getService(String uuid)
{
return getEntity(uuid, marketServiceRepository);
}
public MarketService getServiceByAttributes(String attr, String value)
{
return getEntity(attr, value, marketServiceRepository);
}
public ResponseEntity<MarketService> createService(
MarketService entity, UriComponentsBuilder uriComponentsBuilder)
{
......@@ -53,4 +69,58 @@ public class MarketServiceService extends CerebrumServiceBase<MarketService, Mar
{
return deleteEntity(uuid, marketServiceRepository);
}
//service-provider
public ResponseEntity<MarketService> addProvider(ServiceProvider serviceProvider)
{
MarketService inputService = serviceProvider.getMarketService();
Organization inputOrganization = serviceProvider.getOrganization();
if (inputService.getUuid() != null && inputOrganization.getUuid() != null) {
MarketService service = getServiceByAttributes("uuid", inputService.getUuid());
if (service.getServiceProviders() != null) {
for (ServiceProvider provider : service.getServiceProviders()) {
if (provider.equals(serviceProvider)) {
return ResponseEntity.noContent().build();
}
}
}
Organization organization = organizationService.getOrganization(inputOrganization.getUuid());
MarketService updatedService = marketServiceRepository.createHostedInRelationship(
service.getUuid(), organization.getUuid(), serviceProvider.getServiceTechnicalName());
return ResponseEntity.ok().body(updatedService);
} else {
throw new ResponseStatusException(HttpStatus.BAD_REQUEST,
"The uuid of either or both service and organisation entity is not supplied. " +
"Please check that the request body conform with the definition of " +
"host class.");
}
}
public ResponseEntity<MarketService> deleteProviders(
String serviceKey, String serviceValue, String organizationKey, String organizationValue)
{
Boolean serviceFieldExist = checkField(serviceKey, MarketService.class);
Boolean organizationFieldExist = checkField(organizationKey, Organization.class);
if (serviceFieldExist && organizationFieldExist) {
MarketService service = getServiceByAttributes(serviceKey, serviceValue);
if (service.getServiceProviders() != null) {
for (ServiceProvider provider: service.getServiceProviders()) {
try {
Field field = Organization.class.getDeclaredField(organizationKey);
field.setAccessible(true);
if (field.get(provider.getOrganization()).equals(organizationValue)) {
marketServiceRepository.deleteServiceProviders(
service.getUuid(), provider.getOrganization().getUuid());
break;
}
} catch (IllegalAccessException | NoSuchFieldException e) {
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, e.getMessage());
}
}
}
}
return ResponseEntity.noContent().build();
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment