From 7791afaeb651cbd5f48578d314fc833bca073be6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Alexandre=20Bult=C3=A9?=
Date: Mon, 9 Sep 2024 11:17:22 +0200
Subject: [PATCH 1/6] add connection step
---
ecospheres_migrator/app.py | 75 +++++++++++++++----
ecospheres_migrator/geonetwork.py | 5 ++
ecospheres_migrator/templates/base.html.j2 | 9 +++
.../fragments/transform_job_status.html.j2 | 4 +-
ecospheres_migrator/templates/header.html.j2 | 4 +-
ecospheres_migrator/templates/login.html.j2 | 33 ++++++++
ecospheres_migrator/templates/migrate.html.j2 | 4 +-
ecospheres_migrator/templates/select.html.j2 | 19 +----
.../templates/transform.html.j2 | 4 +-
9 files changed, 118 insertions(+), 39 deletions(-)
create mode 100644 ecospheres_migrator/templates/login.html.j2
diff --git a/ecospheres_migrator/app.py b/ecospheres_migrator/app.py
index 2d4d540..a2a12e2 100644
--- a/ecospheres_migrator/app.py
+++ b/ecospheres_migrator/app.py
@@ -3,7 +3,18 @@
from datetime import datetime
from pathlib import Path
-from flask import Flask, abort, redirect, render_template, request, send_file, session, url_for
+import requests
+from flask import (
+ Flask,
+ abort,
+ flash,
+ redirect,
+ render_template,
+ request,
+ send_file,
+ session,
+ url_for,
+)
from ecospheres_migrator.migrator import Migrator
from ecospheres_migrator.queue import get_job, get_queue
@@ -13,6 +24,46 @@
@app.route("/")
+def login_form():
+ return render_template(
+ "login.html.j2",
+ url=session.get("url", ""),
+ username=session.get("username", ""),
+ password=session.get("password", ""),
+ )
+
+
+# TODO: allow GET and skip form? or select is enough
+@app.route("/login", methods=["POST"])
+def login():
+ url = request.form.get("url")
+ username = request.form.get("username")
+ password = request.form.get("password")
+ if not username or not password or not url:
+ abort(400, "Missing login parameter(s)")
+
+ migrator = Migrator(url=url, username=username, password=password)
+ try:
+ gn_info = migrator.gn.info()
+ print("GN info", gn_info)
+ except requests.exceptions.HTTPError as e:
+ flash(f"Problème d'authentification ({e})", "error")
+ return redirect(url_for("login_form"))
+ else:
+ authenticated = gn_info.get("me", {}).get("@authenticated", "false") == "true"
+ if not authenticated:
+ flash("Problème d'authentification (retour api geonetwork)", "error")
+ return redirect(url_for("login_form"))
+
+ session["url"] = url
+ session["username"] = username
+ session["password"] = password
+ return redirect(url_for("select"))
+
+
+# TODO: protect route (@authenticated)
+# and maybe pass url, username, password from decorator or helper
+@app.route("/select")
def select():
return render_template(
"select.html.j2",
@@ -21,42 +72,36 @@ def select():
)
+# TODO: protect route (@authenticated)
@app.route("/select/preview", methods=["POST"])
def select_preview():
- url = request.form.get("url")
+ url = session.get("url")
+ username = session.get("username")
+ password = session.get("password")
if not url:
return "Veuillez entrer une URL de catalogue"
query = request.form.get("query")
if not query:
return "Veuillez entrer une requête de recherche"
- # Need auth to ensure the records retrieved in selection are consistent with
- # the records that'll be updated during the migration. Otherwise we might miss
- # things like workflow status.
- # TODO: required auth? or skip items with drafts in migration? ...?
- username = request.form.get("username")
- password = request.form.get("password")
migrator = Migrator(url=url, username=username, password=password)
results = migrator.select(query=query)
return render_template("fragments/select_preview.html.j2", results=results)
+# TODO: protect route (@authenticated)
@app.route("/transform", methods=["POST"])
def transform():
- url = request.form.get("url")
+ url = session.get("url")
+ username = session.get("username")
+ password = session.get("password")
if not url:
abort(400, "Missing `url` parameter")
- session["url"] = url
query = request.form.get("query")
if not query:
abort(400, "Missing `query` parameter")
transformation = request.form.get("transformation")
if not transformation:
abort(400, "Missing `transformation` parameter")
- username = request.form.get("username")
- password = request.form.get("password")
- if username and password:
- session["username"] = username
- session["password"] = password
migrator = Migrator(url=url, username=username, password=password)
selection = migrator.select(query=query)
job = get_queue().enqueue(migrator.transform, transformation, selection)
diff --git a/ecospheres_migrator/geonetwork.py b/ecospheres_migrator/geonetwork.py
index f5c0206..6e808c9 100644
--- a/ecospheres_migrator/geonetwork.py
+++ b/ecospheres_migrator/geonetwork.py
@@ -28,6 +28,11 @@ def __init__(self, url, username: str | None = None, password: str | None = None
log.debug(f"Authenticating as: {username}")
self.authenticate()
+ def info(self):
+ r = self.session.get(f"{self.api}/info?_content_type=json&type=me")
+ r.raise_for_status()
+ return r.json()
+
def authenticate(self):
r = self.session.post(f"{self.api}/info?_content_type=json&type=me")
# don't abort on error here, it's expected
diff --git a/ecospheres_migrator/templates/base.html.j2 b/ecospheres_migrator/templates/base.html.j2
index 4191173..6717896 100644
--- a/ecospheres_migrator/templates/base.html.j2
+++ b/ecospheres_migrator/templates/base.html.j2
@@ -13,6 +13,15 @@
{% include "header.html.j2" %}
+ {% with messages = get_flashed_messages(with_categories=true) %}
+ {% if messages %}
+ {% for category, message in messages %}
+
+ {% endfor %}
+ {% endif %}
+ {% endwith %}
{% block content %}
{% endblock content %}
diff --git a/ecospheres_migrator/templates/fragments/transform_job_status.html.j2 b/ecospheres_migrator/templates/fragments/transform_job_status.html.j2
index 909ef92..ddc151a 100644
--- a/ecospheres_migrator/templates/fragments/transform_job_status.html.j2
+++ b/ecospheres_migrator/templates/fragments/transform_job_status.html.j2
@@ -4,12 +4,12 @@
hx-trigger="load delay:1s"
hx-swap="outerHTML">{{ now }} — le job est en cours de traitement ({{ status }}).
{% elif status == "finished" %}
+ {# TODO: add normalized info about current connected catalog #}
Job terminé.
Vous pouvez télécharger le résultat
et appliquer vous-mêmes les modifications sur votre catalogue en important le fichier.
Vous pouvez également utiliser le formulaire ci-dessous pour appliquer les modifications automatiquement
- sur le catalogue {{ url }}. Pour ce faire, nous avons besoin d'identifiants privilégiés sur votre catalogue.
- Ces identifiants sont transmis de manière sécurisée et nous ne les stockons pas.
+ sur le catalogue {{ url }}.