-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: seperate bbmri and ccp data requests
- Loading branch information
1 parent
f9f25c5
commit b48490c
Showing
3 changed files
with
434 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,176 @@ | ||
import { queryStore } from "../stores/query"; | ||
|
||
import { lensOptions } from "../stores/options"; | ||
import { v4 as uuidv4 } from "uuid"; | ||
import type { QueryItem, SendableQuery } from "../types/queryData"; | ||
import type { | ||
LensOptions, | ||
NegotiateOptions, | ||
NegotiateOptionsSiteMapping, | ||
} from "../types/options"; | ||
import { getHumanReadableQuery } from "../stores/datarequests"; | ||
|
||
type NegotiatorResponse = Response & { | ||
url?: string; | ||
redirect_uri?: string; | ||
id?: string; | ||
status: number; | ||
}; | ||
|
||
let negotiateOptions: NegotiateOptions; | ||
const siteCollectionMap: Map<string, NegotiateOptionsSiteMapping> = new Map(); | ||
|
||
lensOptions.subscribe((options: LensOptions) => { | ||
if (!options) return; | ||
|
||
/** | ||
* TODO: implement multiple collections per site | ||
* need to know how multiple collections are returned from the backend | ||
*/ | ||
|
||
negotiateOptions = options.negotiateOptions as NegotiateOptions; | ||
negotiateOptions?.siteMappings?.forEach((site) => { | ||
siteCollectionMap.set(site.site, site); | ||
}); | ||
}); | ||
|
||
/** | ||
* @param sitesToNegotiate the sites to negotiate with | ||
* @returns an array of Collection objects | ||
*/ | ||
export const getCollections = ( | ||
sitesToNegotiate: string[], | ||
): NegotiateOptionsSiteMapping[] => { | ||
const siteCollections: NegotiateOptionsSiteMapping[] = []; | ||
|
||
sitesToNegotiate.forEach((site: string) => { | ||
// TODO: Why is site id mapped to Uppercase? | ||
if (siteCollectionMap.has(site) && siteCollectionMap.get(site) !== "") { | ||
siteCollections.push(siteCollectionMap.get(site)); | ||
} | ||
}); | ||
|
||
return siteCollections; | ||
}; | ||
|
||
/** | ||
* builds a sendable query object from the current query | ||
* sends query to negotiator | ||
* redirects to negotiator | ||
* @param sitesToNegotiate the sites to negotiate with | ||
*/ | ||
export const negotiate = async (sitesToNegotiate: string[]): Promise<void> => { | ||
let sendableQuery!: SendableQuery; | ||
queryStore.subscribe((value: QueryItem[][]) => { | ||
const uuid = uuidv4(); | ||
sendableQuery = { | ||
query: value, | ||
id: `${uuid}__search__${uuid}`, | ||
}; | ||
}); | ||
|
||
const humanReadable: string = getHumanReadableQuery(); | ||
const collections: NegotiateOptionsSiteMapping[] = | ||
getCollections(sitesToNegotiate); | ||
const negotiatorResponse = await sendRequestToNegotiator( | ||
sendableQuery, | ||
humanReadable, | ||
collections, | ||
); | ||
|
||
switch (negotiatorResponse.status) { | ||
case 201: { | ||
if (!negotiatorResponse.url) { | ||
console.error( | ||
"Negotiator response does not contain redirect uri", | ||
); | ||
return; | ||
} else { | ||
const data = await negotiatorResponse.json(); | ||
window.location.href = data.redirectUrl; | ||
} | ||
break; | ||
} | ||
case 401: { | ||
alert( | ||
"An unexpected error has occurred. Please contact support if the issue persists.", | ||
); | ||
break; | ||
} | ||
case 400: | ||
case 500: { | ||
alert( | ||
"The service is temporarily unavailable. Please try again in a few minutes.", | ||
); | ||
break; | ||
} | ||
} | ||
}; | ||
|
||
interface BbmriCollectionResource { | ||
id: string; | ||
name: string; | ||
organization: { | ||
id: number; | ||
externalId: string; | ||
name: string; | ||
}; | ||
} | ||
|
||
/** | ||
* | ||
* @param sendableQuery the query to be sent to the negotiator | ||
* @param humanReadable a human readable query string to view in the negotiator project | ||
* @param collections the collections to negotiate with | ||
* @returns the redirect uri from the negotiator | ||
*/ | ||
async function sendRequestToNegotiator( | ||
sendableQuery: SendableQuery, | ||
humanReadable: string, | ||
collections: NegotiateOptionsSiteMapping[], | ||
): Promise<NegotiatorResponse> { | ||
const base64Query: string = btoa(JSON.stringify(sendableQuery.query)); | ||
|
||
/** | ||
* handle redirect to negotiator url | ||
*/ | ||
const returnURL: string = `${window.location.protocol}//${window.location.host}/?nToken=${sendableQuery.id}&query=${base64Query}`; | ||
|
||
let response!: Response; | ||
|
||
const BBMRI_collection_resource: BbmriCollectionResource[] = []; | ||
|
||
collections.forEach(function (collection) { | ||
BBMRI_collection_resource.push({ | ||
id: collection.collection, | ||
name: collection.collection, | ||
organization: { | ||
id: 0, | ||
externalId: collection.site_id, | ||
name: collection.site, | ||
}, | ||
}); | ||
}); | ||
|
||
try { | ||
response = await fetch(`${negotiateOptions.newProjectUrl}`, { | ||
method: "POST", | ||
headers: { | ||
Accept: "application/json; charset=utf-8", | ||
"Content-Type": "application/json", | ||
Authorization: | ||
"Basic YmJtcmktZGlyZWN0b3J5Omw5RFJLVUROcTBTbDAySXhaUGQ2", | ||
Check failure Code scanning / CodeQL Hard-coded credentials Critical
The hard-coded value "Basic YmJtcmktZGlyZWN0b3J5Omw5RFJLVUROcTBTbDAySXhaUGQ2" is used as
authorization header Error loading related location Loading |
||
}, | ||
body: JSON.stringify({ | ||
humanReadable: humanReadable, | ||
url: returnURL, | ||
resources: BBMRI_collection_resource, | ||
}), | ||
}); | ||
|
||
return response as NegotiatorResponse; | ||
} catch (error) { | ||
console.error(error); | ||
return new Response() as NegotiatorResponse; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,175 @@ | ||
// const urlParams: URLSearchParams = new URLSearchParams(window.location.search); | ||
// const collectionParams: string | null = urlParams.get("collections"); | ||
|
||
// if ( | ||
// collectionParams !== null && | ||
// collectionParams.split(",").includes(collection) | ||
// ) { | ||
// negotiateStore.update((value) => { | ||
// return [...value, site]; | ||
// }); | ||
// } | ||
|
||
// let sendableQuery!: SendableQuery; | ||
// queryStore.subscribe((value: QueryItem[][]) => { | ||
// const uuid = uuidv4(); | ||
// sendableQuery = { | ||
// query: value, | ||
// id: `${uuid}__search__${uuid}`, | ||
// }; | ||
// }); | ||
|
||
// : await sendRequestToProjectManager( | ||
// sendableQuery, | ||
// humanReadable, | ||
// collections, | ||
// queryBase64String, | ||
// ); | ||
|
||
/** | ||
* handle redirect to project manager url | ||
*/ | ||
// if (negotiateOptions.negotiateApp === "project-manager") { | ||
// // project manager | ||
|
||
// if (!negotiatorResponse.redirect_uri) { | ||
// console.error("Negotiator response does not contain redirect uri"); | ||
// return; | ||
// } | ||
|
||
// const indexOfQuestionMark: number = negotiatorResponse.redirect_uri | ||
// .toString() | ||
// .indexOf("?"); | ||
|
||
// const subpage = "/project-view"; | ||
// const negotiationURI = | ||
// negotiatorResponse.redirect_uri | ||
// .toString() | ||
// .slice(0, indexOfQuestionMark) + | ||
// `${subpage}` + | ||
// negotiatorResponse.redirect_uri | ||
// .toString() | ||
// .slice(indexOfQuestionMark); | ||
|
||
// window.location.href = negotiationURI; | ||
// }, | ||
|
||
/** | ||
* | ||
* @param sendableQuery the query to be sent to the negotiator | ||
* @param humanReadable a human readable query string to view in the negotiator project | ||
* @param collections the collections to negotiate with | ||
* @param queryBase64String the query in base64 string format | ||
* @returns a promise containing the response from the project manager. The response contains the redirect uri | ||
*/ | ||
// async function sendRequestToProjectManager( | ||
// sendableQuery: SendableQuery, | ||
// humanReadable: string, | ||
// collections: NegotiateOptionsSiteMapping[], | ||
// queryBase64String: string, | ||
// ): Promise<NegotiatorResponse> { | ||
// /** | ||
// * get temporary token from oauth2 | ||
// */ | ||
// let temporaryToken: string | null = ""; | ||
|
||
// try { | ||
// const res = await fetch(`/oauth2/auth`, { | ||
// method: "GET", | ||
// credentials: "include", | ||
// }); | ||
|
||
// temporaryToken = res.headers.get("Authorization"); | ||
// } catch (error) { | ||
// console.log("error", error); | ||
// return new Response() as Response & { redirect_uri: string }; | ||
// } | ||
|
||
// /** | ||
// * build query params | ||
// */ | ||
// const queryParam: string = | ||
// queryBase64String != "" ? `&query=${queryBase64String}` : ""; | ||
|
||
// const negotiationPartners = collections | ||
// .map((collection) => collection.collection_id.toLocaleLowerCase()) | ||
// .join(","); | ||
// const returnURL: string = `${window.location.protocol}//${window.location.host}/?collections=${negotiationPartners}${queryParam}`; | ||
// const urlParams: URLSearchParams = new URLSearchParams( | ||
// window.location.search, | ||
// ); | ||
// const projectCode: string | null = urlParams.get("project-code"); | ||
// const projectCodeParam: string = projectCode | ||
// ? `&project-code=${projectCode}` | ||
// : ""; | ||
// const negotiateUrl = projectCode | ||
// ? negotiateOptions.editProjectUrl | ||
// : negotiateOptions.newProjectUrl; | ||
|
||
// let response!: NegotiatorResponse; | ||
|
||
// /** | ||
// * send request to project manager | ||
// */ | ||
// try { | ||
// response = await fetch( | ||
// `${negotiateUrl}?explorer-ids=${negotiationPartners}&query-format=CQL_DATA&human-readable=${humanReadable}&explorer-url=${encodeURIComponent(returnURL)}${projectCodeParam}`, | ||
// { | ||
// method: "POST", | ||
// headers: { | ||
// returnAccept: "application/json; charset=utf-8", | ||
// "Content-Type": "application/json", | ||
// Authorization: temporaryToken ? temporaryToken : "", | ||
// }, | ||
// body: getCql(), | ||
// }, | ||
// ).then((response) => response.json()); | ||
|
||
// /** | ||
// * replace query-code with project-code | ||
// * TODO: remove when backend bug is fixed | ||
// */ | ||
// if (response?.redirect_uri) { | ||
// response.redirect_uri = response.redirect_uri.replace( | ||
// "query-code", | ||
// "project-code", | ||
// ); | ||
// } | ||
|
||
// return response; | ||
// } catch (error) { | ||
// console.log("error", error); | ||
// return new Response() as NegotiatorResponse; | ||
// } | ||
// } | ||
|
||
/** | ||
* @returns a base64 encoded CQL query | ||
*/ | ||
// function getCql(): string { | ||
// const ast = buildAstFromQuery(currentQuery); | ||
|
||
// /** | ||
// * TODO: | ||
// * For now backenMeasures is hardcoded because | ||
// * this function only needed for dktk project manager so far. | ||
// * Change if needed for negotiator. | ||
// * | ||
// * should be configurable via options other than spot/blaze, so custom backends can be used | ||
// */ | ||
// const cql = translateAstToCql( | ||
// ast, | ||
// false, | ||
// "DKTK_STRAT_DEF_IN_INITIAL_POPULATION", | ||
// currentMeasures[0].measures, | ||
// ); | ||
|
||
// const library = buildLibrary(`${cql}`); | ||
// const measure = buildMeasure( | ||
// library.url, | ||
// currentMeasures[0].measures.map((measureItem) => measureItem.measure), | ||
// ); | ||
// const query = { lang: "cql", lib: library, measure: measure }; | ||
|
||
// return btoa(decodeURI(JSON.stringify(query))); | ||
// } |
Oops, something went wrong.