From bc65a53e4ff275710e3bc3e0d8482d90a6cc6699 Mon Sep 17 00:00:00 2001 From: Martin Obersteiner Date: Tue, 11 Jun 2024 13:57:15 +0200 Subject: [PATCH] guard views/dashboard by `tugraz_authenticated` --- .../js/invenio_theme_tugraz/unlock.js | 42 ++++++++++++++++ invenio_theme_tugraz/ext.py | 30 +++++++++++- .../invenio_theme_tugraz/overview.html | 48 ++++++++++++++++++- invenio_theme_tugraz/views.py | 32 ++++++++++++- invenio_theme_tugraz/webpack.py | 3 +- 5 files changed, 151 insertions(+), 4 deletions(-) create mode 100644 invenio_theme_tugraz/assets/semantic-ui/js/invenio_theme_tugraz/unlock.js diff --git a/invenio_theme_tugraz/assets/semantic-ui/js/invenio_theme_tugraz/unlock.js b/invenio_theme_tugraz/assets/semantic-ui/js/invenio_theme_tugraz/unlock.js new file mode 100644 index 00000000..2ef2f00f --- /dev/null +++ b/invenio_theme_tugraz/assets/semantic-ui/js/invenio_theme_tugraz/unlock.js @@ -0,0 +1,42 @@ +// Copyright (C) 2024 Graz University of Technology. +// +// invenio-theme-tugraz is free software; you can redistribute it and/or modify it +// under the terms of the MIT License; see LICENSE file for more details. + +import $ from "jquery"; + +async function generateForm() { + // get email from `/api/me` + let email = "???"; + const response = await fetch("/api/me"); + if (response.ok) { + const json = await response.json(); + email = json?.email || "???"; + } + + // show form + $.getScript("https://ub-support.tugraz.at/assets/form/form.js", () => { + $("#anchor-unlock-form").ZammadForm({ + attributes: [ + {}, + { defaultValue: email }, + { + defaultValue: `Could you unlock my account (${email}) for research-uploads?`, + // TODO: add to defaultValue once policy on how to get accepted is decided... + }, + ], + modal: false, + }); + + // focus first entry of now-shown form + document.getElementById("zammad-form-name-inline").focus(); + }); +} + +$(function () { + // called when DOM is ready + const generateFormElement = document.getElementById("generate-unlock-form"); + if (generateFormElement) { + generateFormElement.onclick = generateForm; + } +}); diff --git a/invenio_theme_tugraz/ext.py b/invenio_theme_tugraz/ext.py index 4746bacd..454829c5 100644 --- a/invenio_theme_tugraz/ext.py +++ b/invenio_theme_tugraz/ext.py @@ -8,11 +8,12 @@ """invenio module for TUGRAZ theme.""" +from flask_login import login_required from invenio_i18n import lazy_gettext as _ from invenio_records_marc21.ui.theme import current_identity_can_view from . import config -from .views import index, locked +from .views import index, locked, require_tugraz_authenticated class InvenioThemeTugraz(object): @@ -48,6 +49,7 @@ def init_config(self, app): def finalize_app(app): """Finalize app.""" modify_user_dashboard(app) + guard_view_functions(app) def modify_user_dashboard(app): @@ -66,3 +68,29 @@ def modify_user_dashboard(app): _("My dashboard"), order=1, ) + + +def guard_view_functions(app): + """Guard view-functions against unauthenticated access.""" + endpoints_to_guard = [ + "invenio_app_rdm_users.communities", + "invenio_app_rdm_users.requests", + "invenio_app_rdm_users.uploads", + ] + + for endpoint in endpoints_to_guard: + view_func = app.view_functions.get(endpoint) + if not view_func: + continue + + # decorate view-func + # same as if view-func were defined with: + # @login_required + # @require_tugraz_authenticated_user + view_func = login_required( + require_tugraz_authenticated( + view_func, + ), + ) + + app.view_functions[endpoint] = view_func diff --git a/invenio_theme_tugraz/templates/invenio_theme_tugraz/overview.html b/invenio_theme_tugraz/templates/invenio_theme_tugraz/overview.html index 02db9d4e..62d16bcd 100644 --- a/invenio_theme_tugraz/templates/invenio_theme_tugraz/overview.html +++ b/invenio_theme_tugraz/templates/invenio_theme_tugraz/overview.html @@ -11,6 +11,11 @@ {%- set active_dashboard_menu_item = "overview" %} {%- set title = _("Overview") %} +{% block javascript %} + {{ super() }} + {{ webpack['invenio-theme-tugraz-unlock.js'] }} +{% endblock javascript %} + {%- block page_body %} {%- block user_dashboard_header %} {% include "invenio_app_rdm/users/header.html" %} @@ -19,8 +24,9 @@

Overview

-
+ {% if is_tugraz_authenticated %} + {# 3 columns: Research-Uploads, Communities, and Requests #}

{{ _("Research Results") }}

@@ -54,6 +60,46 @@

{{ _("Requests") }}

+ {% else %} {# not is_tugraz_authenticated #} + {# 1 column: greyed out Research-Uploads #} +
+ {# a modal's HTML can be placed anywhere, so I placed it here, right before it's used #} + + + {# actual column contents start here #} +
+

{{ _("Research Results") }}

+
+ Research Results +
+
+ {{ _("Overview: Description for research results") }} +
+
+
+ {% endif %} {% if can_view_marc21 %}
diff --git a/invenio_theme_tugraz/views.py b/invenio_theme_tugraz/views.py index 1f374967..614d18e0 100644 --- a/invenio_theme_tugraz/views.py +++ b/invenio_theme_tugraz/views.py @@ -8,10 +8,12 @@ """invenio module for TUGRAZ theme.""" +from functools import wraps from typing import Dict -from flask import Blueprint, g, render_template +from flask import Blueprint, g, redirect, render_template, url_for from flask_login import current_user, login_required +from invenio_rdm_records.proxies import current_rdm_records from invenio_records_global_search.resources.serializers import ( GlobalSearchJSONSerializer, ) @@ -28,6 +30,32 @@ ) +def current_identity_is_tugraz_authenticated() -> bool: + """Checks whether current identity has tugraz-authentication. + + NOTE: Default permission-policy has no field for `tugraz_authenticated`. + Should the field not exist, the service checks against admin-permissions instead. + You probably meant to configure a custom permission-policy. + """ + rdm_service = current_rdm_records.records_service + return rdm_service.check_permission(g.identity, "tugraz_authenticated") + + +def require_tugraz_authenticated(view_func): + """Decorator for guarding view-functions against unauthenticated users. + + Redirects un-authenticated users to their personal dashboard's overview. + """ + + @wraps(view_func) + def decorated_view(*args, **kwargs): + if not current_identity_is_tugraz_authenticated(): + return redirect(url_for("invenio_theme_tugraz.overview")) + return view_func(*args, **kwargs) + + return decorated_view + + @blueprint.route("/me/overview") @login_required def overview(): @@ -35,8 +63,10 @@ def overview(): url = current_user_resources.users_service.links_item_tpl.expand( g.identity, current_user )["avatar"] + is_tugraz_authenticated = current_identity_is_tugraz_authenticated() return render_template( "invenio_theme_tugraz/overview.html", + is_tugraz_authenticated=is_tugraz_authenticated, user_avatar=url, ) diff --git a/invenio_theme_tugraz/webpack.py b/invenio_theme_tugraz/webpack.py index a0be4cc5..a302aac9 100644 --- a/invenio_theme_tugraz/webpack.py +++ b/invenio_theme_tugraz/webpack.py @@ -17,9 +17,10 @@ entry={ "invenio-theme-tugraz-theme": "./less/invenio_theme_tugraz/theme.less", "invenio-theme-tugraz-js": "./js/invenio_theme_tugraz/theme.js", + "invenio-theme-tugraz-unlock": "./js/invenio_theme_tugraz/unlock.js", }, dependencies={ - # add any additional npm dependencies here... + "jquery": "^3.2.1", # zammad-form, semantic-ui's modals }, ) },