Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Release 0006 #160

Merged
merged 6 commits into from
Nov 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package edu.harvard.dbmi.avillach.data.entity;

public enum DataSharingStatus {
Unknown, Pending, Error, Complete, NotShared
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package edu.harvard.dbmi.avillach.data.entity;

import io.swagger.v3.oas.annotations.media.Schema;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Table;
import javax.persistence.UniqueConstraint;

@Schema(description = "A site that contains a PIC-SURE installation that we can send data to")
@Table(uniqueConstraints = {
@UniqueConstraint(name = "unique_code", columnNames = { "code" }),
@UniqueConstraint(name = "unique_email", columnNames = { "domain" })
})
@Entity(name = "site")
public class Site extends BaseEntity {

@Schema(description = "The site code. Ex: BCH")
@Column(length = 15)
private String code;

@Schema(description = "The site name. Ex: Boston Children's")
@Column(length = 255)
private String name;

@Schema(description = "The email domain of users for this site. Ex: childrens.harvard.edu")
@Column(length = 255)
private String domain;

public String getCode() {
return code;
}

public void setCode(String code) {
this.code = code;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getDomain() {
return domain;
}

public void setDomain(String domain) {
this.domain = domain;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package edu.harvard.dbmi.avillach.data.repository;

import edu.harvard.dbmi.avillach.data.entity.NamedDataset;
import edu.harvard.dbmi.avillach.data.entity.Site;

import javax.enterprise.context.ApplicationScoped;
import javax.transaction.Transactional;
import java.util.UUID;

@Transactional
@ApplicationScoped
public class SiteRepository extends BaseRepository<Site, UUID>{
protected SiteRepository() {super(Site.class);}
}
11 changes: 11 additions & 0 deletions pic-sure-api-data/src/main/resources/db/sql/V6__ADD_SITE_TABLE.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
USE `picsure`;

CREATE TABLE `site` (
`uuid` binary(16) NOT NULL,
`code` varchar(15) COLLATE utf8_bin DEFAULT NULL,
`name` varchar(255) COLLATE utf8_bin DEFAULT NULL,
`domain` varchar(255) COLLATE utf8_bin DEFAULT NULL,
PRIMARY KEY (`uuid`),
CONSTRAINT `unique_code` UNIQUE (`code`),
CONSTRAINT `unique_domain` UNIQUE (`domain`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,10 @@
import javax.ws.rs.core.Context;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.SecurityContext;

import edu.harvard.dbmi.avillach.domain.*;
import edu.harvard.dbmi.avillach.service.FormatService;
import edu.harvard.dbmi.avillach.service.PicsureInfoService;
import edu.harvard.dbmi.avillach.service.PicsureQueryService;
import edu.harvard.dbmi.avillach.service.PicsureSearchService;
import edu.harvard.dbmi.avillach.service.*;
import io.swagger.v3.oas.annotations.OpenAPIDefinition;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.info.Info;
Expand Down Expand Up @@ -41,6 +39,9 @@ public class PicsureRS {
@Inject
FormatService formatService;

@Inject
ProxyWebClient proxyWebClient;

@POST
@Path("/info/{resourceId}")
@Operation(
Expand Down Expand Up @@ -153,11 +154,16 @@ public QueryStatus query(

@Parameter
@QueryParam("isInstitute")
Boolean isInstitutionQuery
Boolean isInstitutionQuery,

@Context SecurityContext context
) {
return isInstitutionQuery == null || !isInstitutionQuery ?
queryService.query(dataQueryRequest, headers) :
queryService.institutionalQuery(dataQueryRequest, headers);
if (isInstitutionQuery == null || !isInstitutionQuery) {
return queryService.query(dataQueryRequest, headers);
} else {
String email = context.getUserPrincipal().getName();
return queryService.institutionalQuery((FederatedQueryRequest) dataQueryRequest, headers, email);
}
}

@POST
Expand Down Expand Up @@ -194,9 +200,11 @@ public QueryStatus queryStatus(
@QueryParam("isInstitute")
Boolean isInstitutionQuery
) {
return isInstitutionQuery == null || !isInstitutionQuery ?
queryService.queryStatus(queryId, credentialsQueryRequest, headers) :
queryService.institutionQueryStatus(queryId, credentialsQueryRequest, headers);
if (credentialsQueryRequest instanceof GeneralQueryRequest) {
return queryService.queryStatus(queryId, (GeneralQueryRequest) credentialsQueryRequest, headers);
} else {
return queryService.institutionQueryStatus(queryId, (FederatedQueryRequest) credentialsQueryRequest, headers);
}
}

@POST
Expand Down Expand Up @@ -271,5 +279,27 @@ public QueryStatus queryMetadata(@PathParam("queryId") UUID queryId, @Context Ht
public Response generateContinuousBin(QueryRequest continuousData, @Context HttpHeaders headers) {
return formatService.format(continuousData, headers);
}


@POST
@Path("/proxy/{container}/{request : .+}")
@Operation(hidden = true)
public Response postProxy(
@PathParam("container") String containerId,
@PathParam("request") String request,
String body
) {
return proxyWebClient.postProxy(containerId, request, body);
}

@GET
@Path("/proxy/{container}/{request : .+}")
@Operation(hidden = true)
public Response getProxy(
@PathParam("container") String containerId,
@PathParam("request") String request
) {
return proxyWebClient.getProxy(containerId, request);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import edu.harvard.dbmi.avillach.data.entity.AuthUser;
import edu.harvard.dbmi.avillach.data.repository.QueryRepository;
import edu.harvard.dbmi.avillach.data.repository.ResourceRepository;
import edu.harvard.dbmi.avillach.domain.QueryRequest;
import edu.harvard.dbmi.avillach.domain.GeneralQueryRequest;
import edu.harvard.dbmi.avillach.service.ResourceWebClient;
import edu.harvard.dbmi.avillach.util.exception.ApplicationException;
import edu.harvard.dbmi.avillach.util.response.PICSUREResponse;
Expand Down Expand Up @@ -204,7 +204,7 @@ private AuthUser callTokenIntroEndpoint(ContainerRequestContext requestContext,
edu.harvard.dbmi.avillach.data.entity.Resource resource = resourceRepo.getById(resourceUUID);
//logger.info("resource obj: " + resource + " path: " + resource.getResourceRSPath());
if (resource != null && resource.getResourceRSPath() != null){
QueryRequest queryRequest = new QueryRequest();
GeneralQueryRequest queryRequest = new GeneralQueryRequest();
queryRequest.getResourceCredentials().put(ResourceWebClient.BEARER_TOKEN_KEY, resource.getToken());
queryRequest.setResourceUUID(resourceUUID);
queryRequest.setQuery(((Map)queryObject).get("query"));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import com.fasterxml.jackson.databind.ObjectMapper;
import edu.harvard.dbmi.avillach.data.entity.Resource;
import edu.harvard.dbmi.avillach.data.repository.ResourceRepository;
import edu.harvard.dbmi.avillach.domain.GeneralQueryRequest;
import edu.harvard.dbmi.avillach.domain.QueryRequest;
import edu.harvard.dbmi.avillach.domain.ResourceInfo;
import edu.harvard.dbmi.avillach.util.Utilities;
Expand Down Expand Up @@ -46,7 +47,7 @@ public ResourceInfo info(UUID resourceId, QueryRequest credentialsQueryRequest,
throw new ApplicationException(ApplicationException.MISSING_RESOURCE_PATH);
}
if (credentialsQueryRequest == null){
credentialsQueryRequest = new QueryRequest();
credentialsQueryRequest = new GeneralQueryRequest();
}
if (credentialsQueryRequest.getResourceCredentials() == null){
credentialsQueryRequest.setResourceCredentials(new HashMap<String, String>());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,13 @@

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import edu.harvard.dbmi.avillach.data.entity.DataSharingStatus;
import edu.harvard.dbmi.avillach.data.entity.Query;
import edu.harvard.dbmi.avillach.data.entity.Resource;
import edu.harvard.dbmi.avillach.data.repository.QueryRepository;
import edu.harvard.dbmi.avillach.data.repository.ResourceRepository;
import edu.harvard.dbmi.avillach.domain.FederatedQueryRequest;
import edu.harvard.dbmi.avillach.domain.GeneralQueryRequest;
import edu.harvard.dbmi.avillach.domain.QueryRequest;
import edu.harvard.dbmi.avillach.domain.QueryStatus;
import edu.harvard.dbmi.avillach.security.JWTFilter;
Expand Down Expand Up @@ -47,6 +50,9 @@ public class PicsureQueryService {
@Inject
ResourceWebClient resourceWebClient;

@Inject
SiteParsingService siteParsingService;

/**
* Executes a query on a PIC-SURE resource and creates a Query entity in the
* database for the query.
Expand Down Expand Up @@ -88,7 +94,7 @@ public QueryStatus query(QueryRequest dataQueryRequest, HttpHeaders headers) {
* @return {@link QueryStatus}
*/
@Transactional
public QueryStatus queryStatus(UUID queryId, QueryRequest credentialsQueryRequest, HttpHeaders headers) {
public QueryStatus queryStatus(UUID queryId, GeneralQueryRequest credentialsQueryRequest, HttpHeaders headers) {
if (queryId == null){
throw new ProtocolException(ProtocolException.MISSING_QUERY_ID);
}
Expand Down Expand Up @@ -277,7 +283,9 @@ public QueryStatus queryMetadata(UUID queryId, HttpHeaders headers){
* and resource specific query (could be a string or a json object)
* @return {@link QueryStatus}
*/
public QueryStatus institutionalQuery(QueryRequest dataQueryRequest, HttpHeaders headers) {
public QueryStatus institutionalQuery(FederatedQueryRequest dataQueryRequest, HttpHeaders headers, String email) {
String siteCode = siteParsingService.parseSiteOfOrigin(email).orElseThrow(() -> new RuntimeException("Bad email"));
dataQueryRequest.setInstitutionOfOrigin(siteCode);
Resource resource = verifyQueryRequest(dataQueryRequest, headers);
dataQueryRequest.getResourceCredentials().put(ResourceWebClient.BEARER_TOKEN_KEY, resource.getToken());

Expand Down Expand Up @@ -307,11 +315,14 @@ private Query copyQuery(QueryRequest dataQueryRequest, Resource resource, QueryS
throw new ProtocolException(ProtocolException.INCORRECTLY_FORMATTED_REQUEST);
}
}

Map<String, Object> metaData = response.getResultMetadata();
metaData = metaData == null ? new HashMap<>() : metaData;
if (dataQueryRequest.getCommonAreaUUID() != null) {
metaData.put("commonAreaUUID", dataQueryRequest.getCommonAreaUUID());

if (dataQueryRequest instanceof FederatedQueryRequest) {
FederatedQueryRequest gicRequest = (FederatedQueryRequest) dataQueryRequest;
metaData.put("commonAreaUUID", gicRequest.getCommonAreaUUID());
metaData.put("site", gicRequest.getInstitutionOfOrigin());
metaData.put("sharingStatus", DataSharingStatus.Unknown);
}

queryEntity.setQuery(queryJson);
Expand All @@ -326,7 +337,7 @@ private Query copyQuery(QueryRequest dataQueryRequest, Resource resource, QueryS
return queryEntity;
}

public QueryStatus institutionQueryStatus(UUID queryId, QueryRequest credentialsQueryRequest, HttpHeaders headers) {
public QueryStatus institutionQueryStatus(UUID queryId, FederatedQueryRequest credentialsQueryRequest, HttpHeaders headers) {
if (queryId == null) {
throw new ProtocolException(ProtocolException.MISSING_QUERY_ID);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import edu.harvard.dbmi.avillach.data.entity.Resource;
import edu.harvard.dbmi.avillach.data.repository.ResourceRepository;
import edu.harvard.dbmi.avillach.domain.PaginatedSearchResult;
import edu.harvard.dbmi.avillach.domain.GeneralQueryRequest;
import edu.harvard.dbmi.avillach.domain.QueryRequest;
import edu.harvard.dbmi.avillach.domain.SearchResults;
import edu.harvard.dbmi.avillach.util.Utilities;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package edu.harvard.dbmi.avillach.service;

import edu.harvard.dbmi.avillach.data.entity.Site;
import edu.harvard.dbmi.avillach.data.repository.SiteRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.inject.Inject;
import java.util.List;
import java.util.Optional;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class SiteParsingService {

private static final Logger LOG = LoggerFactory.getLogger(SiteParsingService.class);

private static final Pattern emailRegex = Pattern.compile("^([^@]+)(@)(.*)$");

@Inject
SiteRepository repository;

public Optional<String> parseSiteOfOrigin(String email) {
Matcher matcher = emailRegex.matcher(email);
if (!matcher.find()) {
LOG.warn("Unable to parse domain for email: {}", email);
return Optional.empty();
}

List<Site> matchingDomains = repository.getByColumn("domain", matcher.group(3));
if (matchingDomains.isEmpty()) {
LOG.warn("Unable to match domain for email: {}, looked for domain: {}", email, matcher.group(3));
return Optional.empty();
}
if (matchingDomains.size() > 1) {
LOG.warn("Multiple domains match email. This should never happen! Email: {}", email);
return Optional.empty();
}
return Optional.of(matchingDomains.get(0).getCode());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
import edu.harvard.dbmi.avillach.PicSureWarInit;
import edu.harvard.dbmi.avillach.data.entity.Resource;
import edu.harvard.dbmi.avillach.data.repository.ResourceRepository;
import edu.harvard.dbmi.avillach.domain.QueryRequest;
import edu.harvard.dbmi.avillach.domain.GeneralQueryRequest;
import edu.harvard.dbmi.avillach.domain.ResourceInfo;
import edu.harvard.dbmi.avillach.util.exception.ApplicationException;

Expand Down Expand Up @@ -126,7 +126,7 @@ private boolean testPSAMAResponds() throws UnsupportedOperationException, IOExce

private boolean testResourcesRespond(List<Resource> resourcesToTest) {
for(Resource resource : resourcesToTest) {
ResourceInfo info = new ResourceWebClient().info(resource.getResourceRSPath(), new QueryRequest());
ResourceInfo info = new ResourceWebClient().info(resource.getResourceRSPath(), new GeneralQueryRequest());
if(info==null) {
return false;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
<class>edu.harvard.dbmi.avillach.data.entity.Query</class>
<class>edu.harvard.dbmi.avillach.data.entity.Resource</class>
<class>edu.harvard.dbmi.avillach.data.entity.NamedDataset</class>
<class>edu.harvard.dbmi.avillach.data.entity.Site</class>

<properties>
<property name="hibernate.archive.autodetection" value="class" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import edu.harvard.dbmi.avillach.data.entity.Resource;
import edu.harvard.dbmi.avillach.data.repository.ResourceRepository;
import edu.harvard.dbmi.avillach.domain.QueryRequest;
import edu.harvard.dbmi.avillach.domain.GeneralQueryRequest;
import edu.harvard.dbmi.avillach.domain.ResourceInfo;
import edu.harvard.dbmi.avillach.service.PicsureInfoService;
import edu.harvard.dbmi.avillach.service.ResourceWebClient;
Expand Down Expand Up @@ -60,7 +60,7 @@ public void setUp() {

@Test
public void testInfoEndpoints() {
QueryRequest infoRequest = new QueryRequest();
GeneralQueryRequest infoRequest = new GeneralQueryRequest();
Map<String, String> clientCredentials = new HashMap<String, String>();
infoRequest.setResourceCredentials(clientCredentials);

Expand Down
Loading