diff --git a/Makefile b/Makefile index 61a3bdd..682eeaf 100644 --- a/Makefile +++ b/Makefile @@ -175,18 +175,17 @@ create-namespace: @echo $@ (cat ${KUBE_DIR}/namespace.yaml | envsubst | kubectl apply -f -) && touch $@ -deploy-k8s-traefik: - helm upgrade --install --values ${KUBE_DIR}/traefik/values.yaml traefik traefik/traefik --namespace traefik - @cat ${KUBE_DIR}/traefik/ingress.yaml | envsubst | kubectl apply -f - +deploy-k8s-nginx: + helm upgrade --install --values ${KUBE_DIR}/nginx/values.yaml nginx ingress-nginx/ingress-nginx --namespace nginx + @cat ${KUBE_DIR}/nginx/ingress.yaml | envsubst | kubectl apply -f - deploy-k8s-configmap: create-namespace kubectl create configmap env-${INDEX_NAME} --from-env-file=${ENV_FILE} --namespace ridoc -o yaml --dry-run=client | kubectl apply -f - kubectl create configmap static-${INDEX_NAME} --from-file=${FRONTEND_STATIC_USER} --namespace ridoc -o yaml --dry-run=client | kubectl apply -f - - kubectl create configmap logstash-pipeline --from-file=logstash/pipeline/logstash.conf --namespace ridoc -o yaml --dry-run=client | kubectl apply -f - deploy-k8s-volume: create-namespace @cat ${KUBE_DIR}/volume.yaml | envsubst | kubectl apply -f - - {KUBE_DIR}/ingress.yaml | envsubst | kubectl apply -f - + {KUBE_DIR}/volume.yaml | envsubst | kubectl apply -f - deploy-k8s-ekl: create-namespace @echo $@ diff --git a/backend/requirements.txt b/backend/requirements.txt index 1fa2f83..9bd2b26 100644 --- a/backend/requirements.txt +++ b/backend/requirements.txt @@ -1,4 +1,4 @@ -Flask>=1.1.1 +Flask>=2.2.2 #flask-httpauth>=4.2.0 flask-jwt-extended>=3.25.0 #flask-cors==3.0.8 diff --git a/deployments/nginx/README.md b/deployments/nginx/README.md new file mode 100644 index 0000000..210540b --- /dev/null +++ b/deployments/nginx/README.md @@ -0,0 +1,27 @@ +# Install helm charts + +## Nginx +```bash +helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx +helm repo update +``` + +## Cert manager +```bash +helm repo add jetstack https://charts.jetstack.io +helm repo update +``` +From [docs](https://cert-manager.io/docs/tutorials/acme/nginx-ingress/) + +# Deploy +```bash +helm install \ + cert-manager jetstack/cert-manager \ + --namespace nginx \ + --set installCRDs=true + +helm upgrade --install nginx ingress-nginx/ingress-nginx --namespace nginx --create-namespace --values values.yaml + +kubectl apply -f issuer.yaml +kubectl apply -f ingress.yaml +``` diff --git a/deployments/nginx/ingress.yaml b/deployments/nginx/ingress.yaml new file mode 100644 index 0000000..21fe6d3 --- /dev/null +++ b/deployments/nginx/ingress.yaml @@ -0,0 +1,70 @@ +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: backend + namespace: ridoc # Namespace must be the same as that of target services below. + annotations: + # nginx.ingress.kubernetes.io/ssl-redirect: "false" # Set to true once SSL is set up. + cert-manager.io/cluster-issuer: "letsencrypt-prod" + nginx.ingress.kubernetes.io/use-regex: "true" + nginx.ingress.kubernetes.io/rewrite-target: /$1 + nginx.ingress.kubernetes.io/enable-access-log: "true" +spec: + ingressClassName: nginx + tls: + - hosts: + - kubernetes.ridoc.fr + secretName: letsencrypt-prod + rules: + - host: kubernetes.ridoc.fr + http: + paths: + - path: /backend/(.*) + pathType: ImplementationSpecific + backend: + service: + name: backend + port: + number: 5000 + # - path: / + # pathType: Prefix + # backend: + # service: + # name: frontend + # port: + # number: 3000 + +--- +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: frontend + namespace: ridoc # Namespace must be the same as that of target services below. + annotations: + cert-manager.io/cluster-issuer: "letsencrypt-prod" + nginx.ingress.kubernetes.io/enable-access-log: "false" + # nginx.ingress.kubernetes.io/ssl-redirect: "false" # Set to true once SSL is set up. +spec: + ingressClassName: nginx + tls: + - hosts: + - kubernetes.ridoc.fr + secretName: letsencrypt-prod + rules: + - host: kubernetes.ridoc.fr + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: frontend + port: + number: 3000 + - path: /kibana + pathType: Prefix + backend: + service: + name: kibana-kibana + port: + number: 5601 diff --git a/deployments/nginx/issuer.yaml b/deployments/nginx/issuer.yaml new file mode 100644 index 0000000..55dd8d7 --- /dev/null +++ b/deployments/nginx/issuer.yaml @@ -0,0 +1,40 @@ +apiVersion: cert-manager.io/v1 +kind: ClusterIssuer +metadata: + name: letsencrypt-staging + # namespace: nginx +spec: + acme: + # The ACME server URL + server: https://acme-staging-v02.api.letsencrypt.org/directory + # Email address used for ACME registration + email: datalab@interieur.gouv.fr + # Name of a secret used to store the ACME account private key + privateKeySecretRef: + name: letsencrypt-staging + # Enable the HTTP-01 challenge provider + solvers: + - http01: + ingress: + ingressClassName: nginx + +--- +apiVersion: cert-manager.io/v1 +kind: ClusterIssuer +metadata: + name: letsencrypt-prod + # namespace: nginx +spec: + acme: + # The ACME server URL + server: https://acme-v02.api.letsencrypt.org/directory + # Email address used for ACME registration + email: datalab@interieur.gouv.fr + # Name of a secret used to store the ACME account private key + privateKeySecretRef: + name: letsencrypt-prod + # Enable the HTTP-01 challenge provider + solvers: + - http01: + ingress: + ingressClassName: nginx \ No newline at end of file diff --git a/deployments/nginx/values.yaml b/deployments/nginx/values.yaml new file mode 100644 index 0000000..bdbc13c --- /dev/null +++ b/deployments/nginx/values.yaml @@ -0,0 +1,30 @@ +# controller: +# service: +# type: NodePort +# publishService: +# enabled: true + +controller: + kind: DaemonSet + hostNetwork: true + dnsPolicy: ClusterFirstWithHostNet + daemonset: + useHostPort: true + service: + type: ClusterIP + config: + access-log-path: "/tmp/nginx/access.log" + log-format-escape-json: true + log-format-upstream: '{"http_x_forwarded_for":"$http_x_forwarded_for","http_referer":"$http_referer","http_user_agent":"$http_user_agent","remote_addr":"$remote_addr","remote_user":"$remote_user","time_local":"$time_local","request":"$request","request_time":$request_time,"request_method":"$request_method","request_uri":"$request_uri","uri":"$uri","status":$status,"body_bytes_sent":$body_bytes_sent,"request_body": "$request_body"}' + + extraVolumes: + - name: nginx-logs + hostPath: + path: /tmp + + extraVolumeMounts: + - name: nginx-logs + mountPath: /tmp/nginx +rbac: + create: true + diff --git a/docker-compose-elasticsearch-huge.yml b/docker-compose-elasticsearch-huge.yml index 2d7661c..663dd52 100644 --- a/docker-compose-elasticsearch-huge.yml +++ b/docker-compose-elasticsearch-huge.yml @@ -30,8 +30,7 @@ services: #- ${DATA_PATH}:/data ports: - "9200:9200" - logging: - driver: none + networks: default: diff --git a/docker-compose-elasticsearch.yml b/docker-compose-elasticsearch.yml index c40c753..63d1b8c 100644 --- a/docker-compose-elasticsearch.yml +++ b/docker-compose-elasticsearch.yml @@ -30,8 +30,7 @@ services: #- ${DATA_PATH}:/data ports: - "9200:9200" - logging: - driver: none + networks: default: diff --git a/docker-compose-frontend-dev.yml b/docker-compose-frontend-dev.yml index 6c07821..465307f 100644 --- a/docker-compose-frontend-dev.yml +++ b/docker-compose-frontend-dev.yml @@ -11,7 +11,7 @@ services: no_proxy: ${no_proxy} VIEWERJS_VERSION: ${VIEWERJS_VERSION} stdin_open: true - image: ${FRONTEND_DEV_HOST} + image: ${FRONTEND_DEV_HOST}:${APP_VERSION} container_name: ${FRONTEND_DEV_HOST} volumes: - ${FRONTEND}/src:/app/src diff --git a/frontend/package.json b/frontend/package.json index d68505c..ec8a82d 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -19,7 +19,8 @@ "polka": "next", "simple-svelte-autocomplete": "1.2.4", "sirv": "^0.4.0", - "svelte-tags-input": "^2.6.5" + "svelte-tags-input": "^2.6.5", + "pdfjs-dist": "^4.0.3" }, "devDependencies": { "npm-run-all": "^4.1.5", diff --git a/frontend/src/routes/ResultPage.svelte b/frontend/src/routes/ResultPage.svelte index 0187214..9307da9 100644 --- a/frontend/src/routes/ResultPage.svelte +++ b/frontend/src/routes/ResultPage.svelte @@ -9,9 +9,22 @@ } from "../components/utils.js"; import { envJson, itemJson } from "../components/user-data.store"; import Ratesearch from "../components/ratesearch.svelte"; + import { user } from "../components/stores.js"; + + import * as pdfjsLib from "pdfjs-dist/build/pdf"; + import * as pdfjsWorker from "pdfjs-dist/build/pdf.worker.mjs"; + pdfjsLib.GlobalWorkerOptions.workerSrc = pdfjsWorker; + // import pdfjs from 'pdfjs-dist'; + // const pdfjsWorker = await import('pdfjs-dist/build/pdf.worker.entry'); + // import * as pdfjsLib from "pdfjs-dist"; + // import * as pdfjsWorker from "pdfjs-dist/build/pdf.worker.mjs"; + // import pdfjsWorker from "../../../../node_modules/pdfjs-dist/build/pdf.worker.entry"; + // pdfjsLib.GlobalWorkerOptions.workerSrc = pdfjsWorker; + import Entry from "../components/Entry.svelte"; - import { headers } from "../components/stores.js"; let titre = true; + let meta = undefined; + let display; let readonly = true; let required = false; let inputs = []; @@ -19,12 +32,53 @@ let filename; let link; - let iframe; + const displayPdf = (url) => { + // Asynchronous download of PDF + var loadingTask = pdfjsLib.getDocument({ + url: url, + httpHeaders: { Authorization: `Bearer ${$user.jwToken}` }, + withCredentials: true, + }); + loadingTask.promise.then( + function (pdf) { + console.log("PDF loaded"); + + // Fetch the first page + var pageNumber = 1; + pdf.getPage(pageNumber).then(function (page) { + console.log("Page loaded"); - let promiseIndex = new Promise(() => {}); + var scale = 1.5; + var viewport = page.getViewport({ scale: scale }); - onMount(async () => { - async function getMeta() { + // Prepare canvas using PDF page dimensions + var canvas = document.getElementById("the-canvas"); + var context = canvas.getContext("2d"); + canvas.height = viewport.height; + canvas.width = viewport.width; + + // Render PDF page into canvas context + var renderContext = { + canvasContext: context, + viewport: viewport, + }; + var renderTask = page.render(renderContext); + renderTask.promise.then(function () { + console.log("Page rendered"); + }); + }); + }, + function (reason) { + // PDF loading error + console.error(reason); + }, + ); + }; + onMount(() => { + // const pdfjs = await import('../node_modules/pdfjs-dist/build/pdf'); + // const pdfjsWorker = await import('../../node_modules/pdfjs-dist/build/pdf.worker.entry'); + + function getMeta() { // Filter entries in $itemJson with isDetailed at false inputs = $itemJson.inputs.filter( (entry) => @@ -32,45 +86,36 @@ entry.isDetailed == undefined, ); _source_includes = inputs.map((x) => x.key).join(); - const response = await httpClient().fetch( - "./backend/user/" + - $envJson["index_name"] + - "/_doc/" + - filename + - "?_source_includes=" + - _source_includes, - ); - - const data = await response.json(); - return createMeta(inputs, data, {}); + httpClient() + .fetch( + "./backend/user/" + + $envJson["index_name"] + + "/_doc/" + + filename + + "?_source_includes=" + + _source_includes, + ) + .then((response) => response.json()) + .then((data) => { + [meta, display] = createMeta(inputs, data, {}); + }); } - - async function waitindex() { + function waitindex() { //eviter les problèmes de undefined if ($envJson["index_name"] != undefined) { //const { page } = stores(); // sveltekit const urlParams = new URLSearchParams(window.location.search); filename = urlParams.get("filename"); link = `/ViewerJS/?zoom=page-width#../backend/user/files/${$envJson.dstDir}/${filename}`; - - const res = await fetch(link, { - method: "GET", - headers: $headers - }); - const blob = await res.blob(); - const urlObject = URL.createObjectURL(blob); - iframe.setAttribute("src", urlObject); - const [meta, display] = await getMeta(); - console.log(meta); - return meta; + const url = `/backend/user/files/${$envJson.dstDir}/${filename}`; + + getMeta(); + displayPdf(url); } else { - console.log("wait 100ms") - await new Promise((resolve) => setTimeout(resolve, 100)); - return await waitindex(); + setTimeout(waitindex, 100); } } - - promiseIndex = await waitindex(); + waitindex(); }); @@ -78,16 +123,14 @@ {filename} -
-
-
- +{#if meta != undefined && $itemJson != undefined && filename != undefined} +
+
+
+ - {#await promiseIndex} - Attente des meta données - {:then meta} {#each meta as { value, key, type, placeholder, innerHtml, highlight, metadata, rows, color } (key)} {#if !isEmpty(value) || (!readonly && metadata)} {/if} {/each} - {/await} -
+
+ - + +
-
+{/if}