Skip to content

Commit

Permalink
Merge pull request #142 from samply/fix/NeotiatorConnection
Browse files Browse the repository at this point in the history
Fix BBMRI neotiator connection
  • Loading branch information
patrickskowronekdkfz authored Oct 30, 2024
2 parents 3b92d17 + ef908ed commit 6898cc9
Show file tree
Hide file tree
Showing 10 changed files with 465 additions and 443 deletions.
1 change: 0 additions & 1 deletion packages/demo/src/AppCCP.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,6 @@
<lens-search-modified-display
>Diagramme repräsentieren nicht mehr die aktuelle Suche!</lens-search-modified-display
>
<lens-negotiate-button />
</div>
<div class="chart-wrapper">
<lens-chart
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import {
getHumanReadableQuery,
buildHumanReadableRecursively,
} from "../../stores/negotiate";
} from "../../stores/datarequests";
import { returnNestedValues } from "../../helpers/ast-transformer";
import type { AstElement } from "../../types/ast";
import type { QueryItem } from "../../types/queryData";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,18 @@
/>

<script lang="ts">
import { negotiate, negotiateStore } from "../../stores/negotiate";
import { datarequestsStore } from "../../stores/datarequests";
import { negotiate } from "../../services/bbmriNegotiate.ts";
export let title: string = "Negotiate with biobanks";
let disabled: boolean = false;
</script>

<button
part={`lens-negotiate-button lens-negotiate-button-${
disabled ? "disabled" : "active"
$datarequestsStore.length === 0 ? "disabled" : "active"
}`}
on:click={() => negotiate($negotiateStore)}
{disabled}
on:click={() => negotiate($datarequestsStore)}
disabled={$datarequestsStore.length === 0}
>
<div part="lens-negotiate-button-title">
{title}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

<script lang="ts">
import { uiSiteMappingsStore } from "../../stores/mappings";
import { negotiateStore } from "../../stores/negotiate";
import { datarequestsStore } from "../../stores/datarequests.ts";
import {
getSitePopulationForCode,
getSitePopulationForStratumCode,
Expand Down Expand Up @@ -134,21 +134,21 @@
);
/**
* watches the negotiateStore for changes to check or uncheck the checkbox
* watches the datarequestsStore for changes to check or uncheck the checkbox
*/
let allChecked: boolean = false;
$: allChecked =
$negotiateStore.length === tableRowData.length &&
$datarequestsStore.length === tableRowData.length &&
tableRowData.length !== 0;
/**
* checks or unchecks all biobanks
*/
const checkAllBiobanks = (): void => {
if (allChecked) {
$negotiateStore = [];
$datarequestsStore = [];
} else {
$negotiateStore = tableRowData.map(
$datarequestsStore = tableRowData.map(
(tableRow: (string | number)[]) => tableRow[0] as string,
);
}
Expand Down
8 changes: 4 additions & 4 deletions packages/lib/src/components/results/TableItemComponent.svelte
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
<script lang="ts">
import { negotiateStore } from "../../stores/negotiate";
import { datarequestsStore } from "../../stores/datarequests";
export let tableRow: (string | number)[];
let checked: boolean = false;
$: checked = $negotiateStore.includes(tableRow[0] as string);
$: checked = $datarequestsStore.includes(tableRow[0] as string);
/**
* adds and removes tableRows from the negotiateStore whenever the checkbox is checked or unchecked
*/
const updateStoreOnCheck = (): void => {
if (!checked) {
negotiateStore.update((store: string[]) => {
datarequestsStore.update((store: string[]) => {
return [...store, tableRow[0] as string];
});
}
if (checked) {
negotiateStore.update((store: string[]) => {
datarequestsStore.update((store: string[]) => {
return store.filter((site: string) => site !== tableRow[0]);
});
}
Expand Down
176 changes: 176 additions & 0 deletions packages/lib/src/services/bbmriNegotiate.ts
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",
},
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;
}
}
Loading

0 comments on commit 6898cc9

Please sign in to comment.