Skip to content

Commit 9e7b14e

Browse files
committed
Move oasis calls to backend
1 parent e9d1942 commit 9e7b14e

10 files changed

Lines changed: 60 additions & 112 deletions

File tree

backend/src/acidwatch_api/app.py

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from __future__ import annotations
22

33
from collections import defaultdict
4-
from typing import Annotated
4+
from typing import Annotated, Any
55
from uuid import UUID, uuid4
66
from acidwatch_api.models.datamodel import (
77
ModelInfo,
@@ -14,7 +14,7 @@
1414
from fastapi.middleware.cors import CORSMiddleware
1515
from traceback import format_exception, print_exception
1616
from pydantic import ValidationError
17-
17+
import requests
1818
from opentelemetry import trace
1919
from opentelemetry.instrumentation.fastapi import FastAPIInstrumentor
2020
from opentelemetry.instrumentation.httpx import HTTPXClientInstrumentor
@@ -26,6 +26,7 @@
2626
confidential_app,
2727
swagger_ui_init_oauth_config,
2828
get_jwt_token,
29+
acquire_token_for_downstream_api,
2930
)
3031
from acidwatch_api.models.base import (
3132
BaseAdapter,
@@ -87,6 +88,21 @@ def get_models(
8788
return models
8889

8990

91+
@fastapi_app.get("/oasis")
92+
async def get_oasis(
93+
jwt_token: str | None = Depends(get_jwt_token),
94+
) -> list[dict[str, Any]]:
95+
token = acquire_token_for_downstream_api(
96+
f"{SETTINGS.oasis_uri}/.default", jwt_token
97+
)
98+
response = requests.get(
99+
f"{SETTINGS.oasis_uri}/CO2LabResults",
100+
headers={"Authorization": f"Bearer {token}"},
101+
)
102+
response.raise_for_status()
103+
return response.json()
104+
105+
90106
RESULTS: dict[UUID, RunResponse | BaseException] = {}
91107

92108

backend/src/acidwatch_api/configuration.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ class Settings(BaseSettings):
1818

1919
applicationinsights_connection_string: str | None = None
2020

21+
oasis_uri: str = "https://api-oasis-test.radix.equinor.com"
22+
2123
@property
2224
def authority(self) -> str:
2325
return f"https://login.microsoftonline.com/{self.tenant_id}"

frontend/env.example

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,3 @@ VITE_TENANT_ID=3aa4a235-b6e2-48d5-9195-7fcf05b459b0
55
VITE_APPINSIGHTS_CONNECTIONSTRING=<leave empty for local development>
66
VITE_BACKEND_CLIENT_ID=456cc109-08d7-4c11-bf2e-a7b26660f99e
77
VITE_BACKEND_CLIENT_SECRET=<get from azure portal, acidwatch_backend_dev>
8-
VITE_OASIS_URL=https://api-oasis-test.radix.equinor.com/

frontend/nginx-conf/injectEnvVars.sh

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
envsubst < /app/www/inject-env-template.js > /app/www/inject-env.js
2-
envsubst '${OASIS_URL} ${OASIS_HOST}' < /etc/nginx/conf.d/default.conf.template > /etc/nginx/conf.d/default.conf
32
echo "===== Rendered /etc/nginx/conf.d/default.conf ====="
43
cat /etc/nginx/conf.d/default.conf
54
echo "===================================================="

frontend/nginx-conf/nginx.conf

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,5 @@ server {
1010
location / {
1111
try_files $uri $uri/ /index.html;
1212
}
13-
location /oasis/ {
14-
proxy_pass ${OASIS_URL};
15-
proxy_set_header Host ${OASIS_HOST};
16-
proxy_set_header X-Real-IP $remote_addr;
17-
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
18-
proxy_set_header X-Forwarded-Proto $scheme;
19-
}
13+
2014
}

frontend/src/api/api.tsx

Lines changed: 19 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import { Project } from "../dto/Project";
44
import { Simulation } from "../dto/Simulation";
55
import { ModelConfig } from "../dto/FormConfig";
66
import { ExperimentResult } from "../dto/ExperimentResult";
7-
import { getUserToken } from "../services/auth";
87
import { getAccessToken } from "../services/auth";
98
import { ModelInput } from "../dto/ModelInput";
109

@@ -199,70 +198,26 @@ export async function switchPublicity(projectId: string): Promise<any> {
199198
}
200199
}
201200

202-
export const extractAndReplaceKeys = (pattern: string, replacement: string, dictionary: Record<string, any>) => {
203-
return Object.keys(dictionary)
204-
.filter((key) => key.startsWith(pattern))
205-
.reduce<Record<string, number>>((acc, key) => {
206-
acc[key.replace(pattern, replacement)] = dictionary[key];
207-
return acc;
208-
}, {});
209-
};
210-
211-
const processData = (response: any): ExperimentResult[] => {
212-
const experimentResults: ExperimentResult[] = response.flatMap((item: any) => {
213-
const experimentResult = item.data.labData.concentrations.entries.map((entry: any) => {
214-
const species = entry.species;
215-
216-
const inputConcentrations = extractAndReplaceKeys("In_", "", species);
217-
const inputConcentrationsCapitalized = Object.fromEntries(
218-
Object.entries(inputConcentrations).map(([key, value]) => [key.toUpperCase(), value])
219-
);
220-
const outputConcentrations = extractAndReplaceKeys("Out_", "", species);
221-
const outputConcentrationsCapitalized = Object.fromEntries(
222-
Object.entries(outputConcentrations).map(([key, value]) => [key.toUpperCase(), value])
223-
);
224-
const experimentResult: ExperimentResult = {
225-
name: item.data.general.name + "-" + entry.step,
226-
initialConcentrations: inputConcentrationsCapitalized,
227-
finalConcentrations: outputConcentrationsCapitalized,
228-
pressure: entry.pressure ?? null,
229-
temperature: entry.temperature ?? null,
230-
time: entry.time ?? null,
231-
};
232-
return experimentResult;
233-
});
234-
235-
return experimentResult;
236-
});
237-
238-
return experimentResults;
239-
};
240-
export async function getLabResults(): Promise<ExperimentResult[]> {
241-
const token = await getUserToken(config.OASIS_SCOPE);
242-
const response = await apiRequest(
243-
"GET",
244-
"/oasis/CO2LabResults",
245-
{
246-
headers: {
247-
Authorization: `Bearer ${token}`,
248-
},
249-
},
250-
true
201+
export const getKeyValuesFromPrefix = (pattern: string, dict: Record<string, any>) =>
202+
Object.fromEntries(
203+
Object.keys(dict)
204+
.filter((key) => key.startsWith(pattern))
205+
.map((key) => [key.slice(pattern.length).toUpperCase(), dict[key]])
251206
);
252207

253-
if (!response.ok) {
254-
if (response.status === 401) {
255-
throw new Error("Unauthorized: Apply for access to CO2 lab results in AccessIT");
256-
} else if (response.status === 403) {
257-
throw new Error(
258-
"You do not have permission to access this resource. Apply for access to CO2 lab results in AccessIT"
259-
);
260-
} else {
261-
throw new Error("Network response was not ok");
262-
}
263-
}
264-
const data = await response.json();
208+
const formatLabData = (response: any): ExperimentResult[] =>
209+
response.flatMap((item: any) =>
210+
item.data.labData.concentrations.entries.map((entry: any) => ({
211+
name: `${item.data.general.name}-${entry.step}`,
212+
initialConcentrations: getKeyValuesFromPrefix("In_", entry.species),
213+
finalConcentrations: getKeyValuesFromPrefix("Out_", entry.species),
214+
pressure: entry.pressure ?? null,
215+
temperature: entry.temperature ?? null,
216+
time: entry.time ?? null,
217+
}))
218+
);
265219

266-
const transformedData = processData(data);
267-
return transformedData;
220+
export async function getLabResults(): Promise<ExperimentResult[]> {
221+
const data = await apiRequest<any[]>("GET", "/oasis");
222+
return formatLabData(data);
268223
}

frontend/src/configuration.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ interface Configuration {
66
APPINSIGHTS_CONNECTIONSTRING: string;
77
REDIRECT_URI: string;
88
AUTHORITY: string;
9-
OASIS_SCOPE: string;
109
}
1110

1211
declare global {
@@ -26,7 +25,6 @@ function getEnvVars(): Configuration {
2625
APPINSIGHTS_CONNECTIONSTRING: import.meta.env.VITE_APPINSIGHTS_CONNECTIONSTRING,
2726
REDIRECT_URI: window.location.origin,
2827
AUTHORITY: "https://login.microsoftonline.com/3aa4a235-b6e2-48d5-9195-7fcf05b459b0",
29-
OASIS_SCOPE: import.meta.env.VITE_OASIS_SCOPE,
3028
};
3129
return config;
3230
}

frontend/src/inject-env-template.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,4 @@ window.injectEnv = {
44
CLIENT_ID: "${CLIENT_ID}",
55
TENANT_ID: "${TENANT_ID}",
66
APPINSIGHTS_CONNECTIONSTRING: "${APPINSIGHTS_CONNECTIONSTRING}",
7-
OASIS_SCOPE: "${OASIS_SCOPE}",
87
};

frontend/tests/functions/Formatting.test.tsx

Lines changed: 19 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { describe, expect, it } from "vitest";
22
import { convertToSubscripts, convertSimulationsToChartData } from "../../src/functions/Formatting";
3-
import { extractAndReplaceKeys } from "../../src/api/api";
3+
import { getKeyValuesFromPrefix } from "../../src/api/api";
44
import { SimulationResults } from "../../src/dto/SimulationResults";
55

66
describe("convertToSubscripts", () => {
@@ -27,32 +27,26 @@ describe("convertToSubscripts", () => {
2727
});
2828
});
2929

30-
describe("extractAndReplaceKeys", () => {
31-
it("should extract entries with given prefix and replace it with empty string", () => {
32-
const prefix_1 = "foo";
33-
const prefix_2 = "bar";
34-
const inputDict = {
35-
[`${prefix_1}A`]: 1,
36-
[`${prefix_1}B`]: 2,
37-
[`${prefix_2}A`]: 3,
38-
[`${prefix_2}B`]: 4,
39-
};
40-
41-
let res = extractAndReplaceKeys(prefix_1, "", inputDict);
42-
let expectedOutput = {
43-
A: 1,
44-
B: 2,
45-
};
46-
47-
expect(expectedOutput).toEqual(res);
48-
49-
res = extractAndReplaceKeys(prefix_2, "", inputDict);
50-
expectedOutput = {
51-
A: 3,
52-
B: 4,
30+
describe("getKeyValuesFromPrefix", () => {
31+
it("returns an object with keys matching the prefix, uppercased and stripped of the prefix", () => {
32+
const input = {
33+
In_H2O: 1,
34+
In_SO2: 2,
35+
Out_H2O: 3,
36+
foo: 4,
5337
};
38+
expect(getKeyValuesFromPrefix("In_", input)).toEqual({
39+
H2O: 1,
40+
SO2: 2,
41+
});
42+
expect(getKeyValuesFromPrefix("Out_", input)).toEqual({
43+
H2O: 3,
44+
});
45+
});
5446

55-
expect(expectedOutput).toEqual(res);
47+
it("returns an empty object if no keys match the prefix", () => {
48+
const input = { foo: 1, bar: 2 };
49+
expect(getKeyValuesFromPrefix("In_", input)).toEqual({});
5650
});
5751
});
5852

frontend/vite.config.ts

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,7 @@ export default defineConfig({
77
esbuild: {
88
target: "esnext",
99
},
10-
server: {
11-
proxy: {
12-
"/oasis": {
13-
target: "https://api-oasis-prod.radix.equinor.com",
14-
changeOrigin: true,
15-
rewrite: (path) => path.replace(/^\/oasis/, ""),
16-
},
17-
},
18-
},
10+
1911
build: {
2012
target: "esnext",
2113
},

0 commit comments

Comments
 (0)