From 4d37712d2ce12c3296443a84a71c402851880bab Mon Sep 17 00:00:00 2001 From: MarvinDo Date: Sun, 3 Nov 2024 17:36:19 +0100 Subject: [PATCH] added create variant shortcut and added no_login option --- .env_example | 1 + src/frontend_celery/config.py | 2 + .../webapp/auth/auth_routes.py | 29 +++++++++- .../webapp/templates/index.html | 8 +++ .../webapp/templates/variant/create.html | 11 ++-- .../templates/variant/unknown_variant.html | 25 +++++++++ .../webapp/utils/decorators.py | 56 ++++++++++--------- .../webapp/variant/variant_routes.py | 11 +++- 8 files changed, 109 insertions(+), 34 deletions(-) create mode 100644 src/frontend_celery/webapp/templates/variant/unknown_variant.html diff --git a/.env_example b/.env_example index d21edb85..b3ad523b 100644 --- a/.env_example +++ b/.env_example @@ -7,6 +7,7 @@ HOST= PORT= NO_PROXY=localhost +LOGIN_REQUIRED=True ########## DB SETTINGS ######### DB_HOST= diff --git a/src/frontend_celery/config.py b/src/frontend_celery/config.py index 4b868aae..d130e975 100644 --- a/src/frontend_celery/config.py +++ b/src/frontend_celery/config.py @@ -30,6 +30,8 @@ class Config(object): HOST = os.environ.get('HOST') PORT = os.environ.get('PORT') + LOGIN_REQUIRED = os.environ.get('LOGIN_REQUIRED', "True").lower() in ["true"] + ##### production config #### TESTING = False DEBUG = False diff --git a/src/frontend_celery/webapp/auth/auth_routes.py b/src/frontend_celery/webapp/auth/auth_routes.py index 03c52094..062bd4bb 100644 --- a/src/frontend_celery/webapp/auth/auth_routes.py +++ b/src/frontend_celery/webapp/auth/auth_routes.py @@ -26,17 +26,42 @@ @auth_blueprint.route('/login') def login(): + + next_url = request.args.get('next_login', url_for('main.index')) + + if not current_app.config["LOGIN_REQUIRED"]: + return redirect(url_for("auth.auth", next_login=next_url)) + # construct redirect uri: first redirect to keycloak login page # then redirect to auth with the next param which defaults to the '/' route # auth itself redirects to next ie. the page which required a login - redirect_uri = url_for('auth.auth', _external=True, next_login=request.args.get('next_login', url_for('main.index'))) + redirect_uri = url_for('auth.auth', _external=True, next_login=next_url) return oauth.keycloak.authorize_redirect(redirect_uri) @auth_blueprint.route('/auth') def auth(): - token_response = oauth.keycloak.authorize_access_token() + + if not current_app.config["LOGIN_REQUIRED"]: + token_response = { + "access_token": "xxx", + "expires_in": 300, + "refresh_expires_in": 1800, + "refresh_token": "xxx", + "token_type": "bearer", + "not-before-policy": 0, + "session_state": "xxx", + "userinfo": { + "preferred_username": "anonymous", + "given_name": "Arno", + "family_name": "Nym", + "affiliation": "Anonymous", + "roles": ["super_user", "user", "read_only"] + } + } + else: + token_response = oauth.keycloak.authorize_access_token() #userinfo = oauth.keycloak.userinfo(request) #idToken = oauth.keycloak.parse_id_token(tokenResponse) diff --git a/src/frontend_celery/webapp/templates/index.html b/src/frontend_celery/webapp/templates/index.html index 8e1cbd15..abed0e6d 100644 --- a/src/frontend_celery/webapp/templates/index.html +++ b/src/frontend_celery/webapp/templates/index.html @@ -93,6 +93,14 @@

Overview

Changelog

+
v 1.14.4 (03.11.2024)
+
+ General changes: +
    +
  • Added shortcut to insert unknown variants from variant display page
  • +
+
+
v 1.14.3 (15.10.2024)
General changes: diff --git a/src/frontend_celery/webapp/templates/variant/create.html b/src/frontend_celery/webapp/templates/variant/create.html index f48a6d93..08b0f43c 100644 --- a/src/frontend_celery/webapp/templates/variant/create.html +++ b/src/frontend_celery/webapp/templates/variant/create.html @@ -31,7 +31,7 @@

{% block title %} Create a new variant {% endblock %}

@@ -43,7 +43,8 @@

{% block title %} Create a new variant {% endblock %}

+ value={% if request.form.get('pos') is not none %}"{{ request.form.get('pos', '') }}"{% else %}"{{ request.args.get('pos', '') }}"{% endif %} + required>
Please provide a chromosomal position!
@@ -53,7 +54,8 @@

{% block title %} Create a new variant {% endblock %}

+ value={% if request.form.get('ref') is not none %}"{{ request.form.get('ref', '') }}"{% else %}"{{ request.args.get('ref', '') }}"{% endif %} + id="Reference" required>
Please provide a reference sequence!
@@ -63,7 +65,8 @@

{% block title %} Create a new variant {% endblock %}

+ value={% if request.form.get('alt') is not none %}"{{ request.form.get('alt', '') }}"{% else %}"{{ request.args.get('alt', '') }}"{% endif %} + id="Alternative" required>
Please provide an alternative sequence!
diff --git a/src/frontend_celery/webapp/templates/variant/unknown_variant.html b/src/frontend_celery/webapp/templates/variant/unknown_variant.html new file mode 100644 index 00000000..27b56118 --- /dev/null +++ b/src/frontend_celery/webapp/templates/variant/unknown_variant.html @@ -0,0 +1,25 @@ +{% extends 'base.html' %} + +{% block content %} +
+ + + +

{% block title %} Unknown variant {% endblock %}

+ + +
+
The variant you are trying to access is unknown by HerediVar. Please click to following button to request a new variant:
+ +
+ + +
+ +{% endblock %} + +{% block special_scripts %} + +{% endblock%} \ No newline at end of file diff --git a/src/frontend_celery/webapp/utils/decorators.py b/src/frontend_celery/webapp/utils/decorators.py index 4eb9f585..14886722 100644 --- a/src/frontend_celery/webapp/utils/decorators.py +++ b/src/frontend_celery/webapp/utils/decorators.py @@ -74,34 +74,35 @@ def decorated_function(*args, **kwargs): if session.get('user') is None: return redirect(url_for('auth.login', next_login=request.url)) - # user is logged in -> check if access token is still valid using introspect endpoint --> introspect endpoint can be omitted if token is validated locally using some jwt lib + if current_app.config["LOGIN_REQUIRED"]: + # user is logged in -> check if access token is still valid using introspect endpoint --> introspect endpoint can be omitted if token is validated locally using some jwt lib - token = session['tokenResponse'] + token = session['tokenResponse'] - #print(session['user']) - #print(token) + #print(session['user']) + #print(token) - # maybe also add: - # state=5AzjFWCkQzjmh4YozUfuE8pHytJj3i - # nonce=fvdZHHR1mmAHBIbCQtgZ - # code_challenge=hoiDWU7Vf4tOreIeYyIi7IKcw2BseRW7j5wwXROJtPA - # code_challenge_method=S256 + # maybe also add: + # state=5AzjFWCkQzjmh4YozUfuE8pHytJj3i + # nonce=fvdZHHR1mmAHBIbCQtgZ + # code_challenge=hoiDWU7Vf4tOreIeYyIi7IKcw2BseRW7j5wwXROJtPA + # code_challenge_method=S256 - issuer = current_app.config['ISSUER'] - url = f'{issuer}/protocol/openid-connect/token/introspect' - data = {'token': token.get("access_token"), 'token_type_hint': 'access_token', 'username': session['user']['preferred_username'], 'client_secret': current_app.config['CLIENTSECRET'], 'client_id': current_app.config['CLIENTID']} - header = {'Authorization': f'Bearer {token.get("access_token")}'} - resp = requests.post(url, data=data, headers=header) - resp.raise_for_status() - resp = resp.json() - - # if access token is not valid request a new one using the refresh token - if not resp['active']: - print('access token invalid refreshing token') - refresh_status_code = refresh_token() - # if the refresh token is expired as well promt a new login by invalidating the client session - if refresh_status_code != 200: - return redirect(url_for('auth.logout', auto_logout='True', next_logout=url_for('auth.login', next_login=request.url))) # logout and return to login page! with next= page which you wanted to access in the first place + issuer = current_app.config['ISSUER'] + url = f'{issuer}/protocol/openid-connect/token/introspect' + data = {'token': token.get("access_token"), 'token_type_hint': 'access_token', 'username': session['user']['preferred_username'], 'client_secret': current_app.config['CLIENTSECRET'], 'client_id': current_app.config['CLIENTID']} + header = {'Authorization': f'Bearer {token.get("access_token")}'} + resp = requests.post(url, data=data, headers=header) + resp.raise_for_status() + resp = resp.json() + + # if access token is not valid request a new one using the refresh token + if not resp['active']: + print('access token invalid refreshing token') + refresh_status_code = refresh_token() + # if the refresh token is expired as well promt a new login by invalidating the client session + if refresh_status_code != 200: + return redirect(url_for('auth.logout', auto_logout='True', next_logout=url_for('auth.login', next_login=request.url))) # logout and return to login page! with next= page which you wanted to access in the first place return f(*args, **kwargs) return decorated_function @@ -113,9 +114,10 @@ def decorator(f): @require_login @wraps(f) def wrapper(*args, **kwargs): - grant_access, status_code = request_uma_ticket(resources) - if not grant_access: - abort(status_code) + if current_app.config["LOGIN_REQUIRED"]: + grant_access, status_code = request_uma_ticket(resources) + if not grant_access: + abort(status_code) return f(*args, **kwargs) return wrapper return decorator diff --git a/src/frontend_celery/webapp/variant/variant_routes.py b/src/frontend_celery/webapp/variant/variant_routes.py index 8b5758bf..d90e5f65 100644 --- a/src/frontend_celery/webapp/variant/variant_routes.py +++ b/src/frontend_celery/webapp/variant/variant_routes.py @@ -75,7 +75,7 @@ def create(): if do_redirect: return redirect(url_for('variant.create')) - return render_template('variant/create.html', chrs=chroms, vcf_file_import_active=current_app.config["VCF_FILE_IMPORT_ACTIVE"]) + return render_template('variant/create.html', chrs=chroms, vcf_file_import_active=current_app.config["VCF_FILE_IMPORT_ACTIVE"], **request.args) @@ -125,12 +125,15 @@ def create_sv(): @variant_blueprint.route('/display/chr=&pos=&ref=&alt=', methods=['GET']) # alternative url using vcf information @require_permission(['read_resources']) def display(variant_id=None, chr=None, pos=None, ref=None, alt=None): + conn = get_connection() # get variant id from parameters or pull from genomic coordinates if variant_id is None: require_set(chr, pos, ref, alt) variant_id = conn.get_variant_id(chr, pos, ref, alt) + if variant_id is None and any([e is not None for e in [chr, pos, ref, alt]]): + return redirect(url_for('variant.unknown_variant', chrom=chr, pos=pos, ref=ref, alt=alt)) require_valid(variant_id, "variant", conn) # get available lists for user @@ -146,6 +149,12 @@ def display(variant_id=None, chr=None, pos=None, ref=None, alt=None): ) +@variant_blueprint.route('/unknown_variant', methods=["GET"]) +@require_permission(['read_resources']) +def unknown_variant(): + return render_template('variant/unknown_variant.html', **request.args) + + @variant_blueprint.route('/get_clinvar_upload_status', methods=['GET']) @require_permission(['read_resources']) def get_clinvar_upload_status():