Skip to content

Commit

Permalink
feat(negotiate): add config to change negotiation service
Browse files Browse the repository at this point in the history
bbmri still wip
  • Loading branch information
MatsJohansen87 committed Sep 5, 2024
1 parent 353533e commit 02a3502
Show file tree
Hide file tree
Showing 7 changed files with 104 additions and 50 deletions.
2 changes: 1 addition & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ services:
CATALOGUE_URL: "${CATALOGUE_URL}"
BIND_ADDR: 0.0.0.0:8055
PRISM_URL: http://prism:8066
RUST_LOG: "info"
# RUST_LOG: "info"
LOG_FILE: /requests.log
volumes:
- ./requests.log:/requests.log
Expand Down
1 change: 1 addition & 0 deletions packages/demo/public/options-dev.json
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,7 @@
]
},
"negotiateOptions": {
"negotiateApp": "project-manager",
"newProjectUrl": "http://localhost:8097/create-query-and-design-project",
"editProjectUrl": "http://localhost:8097/edit-project",
"siteMapping": [
Expand Down
2 changes: 1 addition & 1 deletion packages/demo/src/AppCCP.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@
>Diagramme repräsentieren nicht mehr die aktuelle Suche!</lens-search-modified-display
>
<!-- TODO: comment in when backend is ready -->
<!-- <lens-negotiator-button /> -->
<!-- <lens-negotiate-button /> -->
</div>
<div class="chart-wrapper">
<lens-chart
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<svelte:options
customElement={{
tag: "lens-negotiator-button",
tag: "lens-negotiate-button",
}}
/>

Expand Down
134 changes: 91 additions & 43 deletions packages/lib/src/stores/negotiate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,12 +106,14 @@ export const getHumanReadableQuery = (): string => {
* sets all options needed for the negotiator
*/
type NegotiateOptions = {
negotiateApp: "negotiator" | "project-manager";
siteMapping: { site: string; collection: string }[];
negotiatorURL: string;
newProjectUrl: string;
editProjectUrl: string;
};

type NegotiatorResponse = Response & { url?: string; redirect_uri?: string };

let negotiateOptions: NegotiateOptions;
const siteCollectionMap: Map<string, string> = new Map();
const urlParams: URLSearchParams = new URLSearchParams(window.location.search);
Expand Down Expand Up @@ -181,8 +183,9 @@ export const getCollections = (sitesToNegotiate: string[]): Collection[] => {
* @param sitesToNegotiate the sites to negotiate with
*/
export const negotiate = async (sitesToNegotiate: string[]): Promise<void> => {
//TODO: get auth token here
console.log("enter negotiate");
console.log("currentMeasures", currentMeasures);

let sendableQuery!: SendableQuery;
queryStore.subscribe((value: QueryItem[][]) => {
const uuid = uuidv4();
Expand All @@ -196,7 +199,7 @@ export const negotiate = async (sitesToNegotiate: string[]): Promise<void> => {
const humanReadable: string = getHumanReadableQuery();
const collections: Collection[] = getCollections(sitesToNegotiate);
// TODO: Implement proper configuration option for the switch between negotiator and project manager
const negotiatorResponse = false
const negotiatorResponse = true
? await sendRequestToNegotiator(
sendableQuery,
humanReadable,
Expand All @@ -210,24 +213,48 @@ export const negotiate = async (sitesToNegotiate: string[]): Promise<void> => {
queryBase64String,
);

const indexOfQuestionMark: number = negotiatorResponse.redirect_uri
.toString()
.indexOf("?");
console.log(negotiatorResponse);

if (!negotiatorResponse.redirect_uri) {
console.error("Negotiator response does not contain redirect uri");
return;
}
/**
* 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 subpage = "/project-view";
const negotiationURI =
negotiatorResponse.redirect_uri
const indexOfQuestionMark: number = negotiatorResponse.redirect_uri
.toString()
.slice(0, indexOfQuestionMark) +
`${subpage}` +
negotiatorResponse.redirect_uri.toString().slice(indexOfQuestionMark);
.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;
}

window.location.href = negotiationURI;
/**
* handle redirect to negotiator url
*/
if (negotiateOptions.negotiateApp === "negotiator") {
// negotiator
if (!negotiatorResponse.url) {
console.error("Negotiator response does not contain redirect uri");
return;
}

window.location.href = `https://negotiator.bbmri-eric.eu/requests/${sendableQuery.id}`;
}
};

/**
Expand All @@ -243,31 +270,39 @@ async function sendRequestToNegotiator(
humanReadable: string,
collections: Collection[],
queryBase64String: string,
): Promise<Response & { redirect_uri: string }> {
): Promise<NegotiatorResponse> {
const base64Query: string = btoa(JSON.stringify(sendableQuery.query));

const returnURL: string = `${window.location.protocol}//${window.location.host}/?nToken=${sendableQuery.id}&query=${base64Query}`;

const response: Response & { redirect_uri: string } = (await fetch(
`${negotiateOptions.negotiatorURL}?nToken=${sendableQuery.id}`,
{
method: "POST",
headers: {
Accept: "application/json; charset=utf-8",
"Content-Type": "application/json",
Authorization:
"Basic YmJtcmktZGlyZWN0b3J5Omw5RFJLVUROcTBTbDAySXhaUGQ2",
let response!: Response;

try {
response = await fetch(
`${negotiateOptions.newProjectUrl}?nToken=${sendableQuery.id}`,
{
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
.
},
body: JSON.stringify({
humanReadable: humanReadable,
URL: returnURL,
collections: collections,
nToken: sendableQuery.id,
query: queryBase64String,
}),
},
body: JSON.stringify({
humanReadable: humanReadable,
URL: returnURL,
collections: collections,
nToken: sendableQuery.id,
query: queryBase64String,
}),
},
)) as Response & { redirect_uri: string };
return response;
);

return response as NegotiatorResponse;
} catch (error) {
console.log("error", error);
return new Response() as NegotiatorResponse;
}
}

/**
Expand All @@ -283,7 +318,7 @@ async function sendRequestToProjectManager(
humanReadable: string,
collections: Collection[],
queryBase64String: string,
): Promise<Response & { redirect_uri: string }> {
): Promise<NegotiatorResponse> {
/**
* get temporary token from oauth2
*/
Expand Down Expand Up @@ -322,7 +357,7 @@ async function sendRequestToProjectManager(
? negotiateOptions.editProjectUrl
: negotiateOptions.newProjectUrl;

let response!: Response & { redirect_uri: string };
let response!: NegotiatorResponse;

/**
* send request to project manager
Expand Down Expand Up @@ -355,22 +390,35 @@ async function sendRequestToProjectManager(
return response;
} catch (error) {
console.log("error", error);
return new Response() as Response & { redirect_uri: string };
return new Response() as NegotiatorResponse;
}
}

/**
* @returns a base64 encoded CQL query
*/
function getCql(): string {
// NOTE: $ only works within svelte components
const ast = buildAstFromQuery(currentQuery);
const cql = translateAstToCql(ast, false, backendMeasures);

/**
* 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.map((measureItem) => measureItem.measure),
currentMeasures[0].measures.map((measureItem) => measureItem.measure),
);
const query = { lang: "cql", lib: library, measure: measure };

Expand Down
8 changes: 4 additions & 4 deletions packages/lib/src/styles/negotiate-button.css
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* stand alone result button
*/

lens-result-summary::part(lens-negotiate-button) {
lens-negotiate-button::part(lens-negotiate-button) {
color: var(--white);
border: none;
border-radius: var(--border-radius-small);
Expand All @@ -15,14 +15,14 @@ lens-result-summary::part(lens-negotiate-button) {
font-family: var(--font-family);
}

lens-result-summary::part(lens-negotiate-button-active) {
lens-negotiate-button::part(lens-negotiate-button-active) {
background-color: var(--blue);
}

lens-result-summary::part(lens-negotiate-button-disabled) {
lens-negotiate-button::part(lens-negotiate-button-disabled) {
background-color: var(--gray);
}

lens-result-summary::part(lens-negotiate-button-active):hover {
lens-negotiate-button::part(lens-negotiate-button-active):hover {
background-color: var(--light-blue);
}
5 changes: 5 additions & 0 deletions packages/lib/src/types/options.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,11 @@
"negotiateOptions": {
"type": "object",
"properties": {
"negotiateApp": {
"type": "string",
"pattern": "^.+$",
"description": "The URL of the negotiate app"
},
"newProjectUrl": {
"type": "string",
"pattern": "^.+$",
Expand Down

0 comments on commit 02a3502

Please sign in to comment.