*** Wartungsfenster jeden ersten Mittwoch vormittag im Monat ***

Skip to content
Snippets Groups Projects
views.py 10.5 KiB
Newer Older
Moser, Maximilian's avatar
Moser, Maximilian committed
# Copyright (C) 2020-2024 TU Wien.
#
# Invenio-Theme-TUW is free software; you can redistribute it and/or modify
# it under the terms of the MIT License; see LICENSE file for more details.

"""TU Wien theme for Invenio (RDM)."""

from flask import (
    Blueprint,
    abort,
    current_app,
    flash,
    g,
    redirect,
    render_template,
    request,
    url_for,
)
from flask_login import current_user, login_required
from invenio_accounts.proxies import current_datastore
from invenio_app_rdm.records_ui.views.deposits import deposit_create, deposit_edit
from invenio_communities.proxies import current_communities
from invenio_communities.views.communities import communities_new
from invenio_mail.tasks import send_email
from invenio_pidstore.errors import PIDDoesNotExistError
from invenio_rdm_records.proxies import current_rdm_records_service as rec_service
from invenio_rdm_records.resources.serializers import SchemaorgJSONLDSerializer
from sqlalchemy.exc import NoResultFound
from .search import FrontpageRecordsSearch
from .utils import (
    fetch_user_infos,
    get_admin_mail_addresses,
    records_serializer,
    resolve_record,
    resolve_user_owner,
    toggle_user_trust,
)
@login_required
def guarded_deposit_create(*args, **kwargs):
    """Guard the creation page for records, based on permissions."""
    if not rec_service.check_permission(g.identity, "create"):
        return (
            render_template("invenio_theme_tuw/guards/deposit.html", user=current_user),
            403,
        )

    return deposit_create(*args, **kwargs)


@login_required
def guarded_deposit_edit(*args, **kwargs):
    """Guard the edit page for records, based on permissions."""
    # NOTE: this extra loading of the draft introduces an extra DB query, but i think
    #       it should not make too much of a difference for us
    try:
        draft = rec_service.draft_cls.pid.resolve(
            kwargs["pid_value"], registered_only=False
        )
    except (PIDDoesNotExistError, NoResultFound):
        return render_template(current_app.config["THEME_404_TEMPLATE"]), 404

    if not rec_service.check_permission(g.identity, "update_draft", record=draft):
        if not rec_service.check_permission(g.identity, "preview", record=draft):
            return (
                render_template(
                    "invenio_theme_tuw/guards/deposit.html", user=current_user
                ),
                403,
            )
        else:
            # if the user has permission to preview the draft but not to edit it,
            # redirect them to the preview page
            return redirect(
                url_for(
                    "invenio_app_rdm_records.record_detail",
                    pid_value=draft.pid.pid_value,
                    preview=1,
                )

    return deposit_edit(*args, **kwargs)


@login_required
def guarded_communities_create(*args, **kwargs):
    """Guard the communities creation page, based on permissions."""
    if not current_communities.service.check_permission(g.identity, "create"):
        return (
            render_template(
                "invenio_theme_tuw/guards/community.html", user=current_user
            ),
            403,
        )

    return communities_new(*args, **kwargs)


def tuw_index():
    """Custom landing page showing the latest 5 records."""
    try:
        records = FrontpageRecordsSearch()[:5].sort("-created").execute()
    except Exception as e:
        current_app.logger.error(e)
        records = []

    return render_template(
        "invenio_theme_tuw/overrides/frontpage.html",
        records=records_serializer(records),
    )


def create_blueprint(app):
    """Create a blueprint with routes and resources."""
    blueprint = Blueprint(
        "invenio_theme_tuw",
        __name__,
        template_folder="theme/templates",
        static_folder="theme/static",

    @blueprint.app_template_filter("tuw_doi_identifier")
    def tuw_doi_identifier(identifiers):
        """Extract DOI from sequence of identifiers."""
        if identifiers is not None:
            for identifier in identifiers:
                if identifier.get("scheme") == "doi":
                    return identifier.get("identifier")

    @blueprint.app_template_global("tuw_create_schemaorg_metadata")
    def tuw_create_schemaorg_metadata(record):
        """Create schema.org metadata to include in a <script> tag."""
        try:
            return SchemaorgJSONLDSerializer().serialize_object(record)
        except Exception as e:
            current_app.logger.error(e)
            return '{"@context": "http://schema.org"}'
    @blueprint.app_template_global("record_count")
    def record_count():
        try:
            return FrontpageRecordsSearch().count()
        except Exception:
            return "all"
    @blueprint.route("/tuw/contact-uploader/<recid>", methods=["GET", "POST"])
    def contact_uploader(recid):
        """Contact page for the contact's uploader."""
        if not current_app.config.get("THEME_TUW_CONTACT_UPLOADER_ENABLED", False):
            abort(404)

        captcha = current_app.extensions["invenio-theme-tuw"].captcha
        record = resolve_record(recid)
        form_values = request.form.to_dict()
        if current_user and not current_user.is_anonymous:
            form_values.setdefault("name", current_user.user_profile.get("full_name"))
            form_values.setdefault("email", current_user.email)

        if record is None:
            abort(404)

        owner = record.parent.access.owned_by
        if not owner:

        submitted = False
        captcha_failed = False
        if request.method == "POST":
            # NOTE: the captcha is a simple spam prevention measure, and it also
            #       prevents the form from being accidentally resubmitted wia refresh
            if not current_app.config["CAPTCHA_ENABLE"] or captcha.validate():
                sitename = current_app.config["THEME_SITENAME"]
                sender_name = request.form["name"]
                sender_email = request.form["email"]
                inquiry = request.form["message"] or "<Empty Message>"
                html_message = render_template(
                    "invenio_theme_tuw/mails/contact.html",
                    sender_name=sender_name,
                    sender_email=sender_email,
                    message=inquiry,
                    uploader=owner,
                    record=record,
                )
                message = render_template(
                    "invenio_theme_tuw/mails/contact.txt",
                    sender_name=sender_name,
                    sender_email=sender_email,
                    message=inquiry,
                    uploader=owner,
                    record=record,
                )

                add_sender_to_cc = current_app.config.get(
                    "THEME_TUW_CONTACT_UPLOADER_ADD_EMAIL_TO_CC", False
                )
                record_title = record.metadata["title"]
                send_email(
                    {
                        "subject": f'{sitename}: Inquiry about your record "{record_title}" from {sender_name}',
                        "html": html_message,
                        "body": message,
                        "recipients": [owner.email],
                        "cc": [sender_email] if add_sender_to_cc else [],
                        "bcc": get_admin_mail_addresses(current_app),
                        "reply_to": sender_email,
                    }
                )

                submitted = True

            else:
                captcha_failed = True

        response = render_template(
            "invenio_theme_tuw/contact_uploader.html",
            uploader=owner,
            submitted=submitted,
            record=record,
            captcha_failed=captcha_failed,
        )
        return response, 200 if not captcha_failed else 428

Moser, Maximilian's avatar
Moser, Maximilian committed
    @blueprint.route("/tuw/policies")
Wörister, Florian's avatar
Wörister, Florian committed
    def tuw_policies():
        """Page showing the available repository policies."""
Moser, Maximilian's avatar
Moser, Maximilian committed
        return render_template("invenio_theme_tuw/policies.html")
    @blueprint.route("/tuw/terms-of-use")
    def tuw_terms_of_use():
        """Page showing the repository's terms of use documents."""
        return render_template("invenio_theme_tuw/terms_of_use.html")

Moser, Maximilian's avatar
Moser, Maximilian committed
    @blueprint.route("/tuw/contact")
Wörister, Florian's avatar
Wörister, Florian committed
    def tuw_contact():
        """Contact page."""
Moser, Maximilian's avatar
Moser, Maximilian committed
        return render_template("invenio_theme_tuw/contact.html")
    @blueprint.route("/tuw/admin/users", methods=["GET", "POST"])
    def list_user_info():
        """Hacky endpoint for listing user information."""
        admin_role = current_datastore.find_role("admin")
        if current_user and current_user.has_role(admin_role):

            # handle trusting of user
            if request.method == "POST":
                if (user_id := request.form.get("user_id", None)) is not None:
                    try:
                        flash(toggle_user_trust(user_id))
                    except Exception as e:
                        flash(e)

            return render_template(
                "invenio_theme_tuw/users_infos.html",
                user_infos=fetch_user_infos(),
    @blueprint.route("/tuw/admin/users/welcome")
    def show_user_welcome_text():
        """Show the welcome text for new users, to be sent to them via email."""
        admin_role = current_datastore.find_role("admin")
        if current_user and current_user.has_role(admin_role):
            uid = request.args.get("uid", None)

            if user := current_datastore.get_user(uid):
                return render_template(
                    "invenio_theme_tuw/users_welcome.html",
                    user=user,
                )
            else:
                # if the user can't be found, redirect to the overview
                return redirect(url_for(".list_user_info"))

        else:
            abort(403)

    @blueprint.route("/tuwstones/florian.woerister")
    def tuw_tombstone_florian():
        """Tombstone page for Florian Wörister."""
        return render_template("invenio_theme_tuw/tuwstones/florian_woerister.html")

    @blueprint.route("/tuwstones/derek.molnar")
    def tuw_tombstone_derek():
        """Tombstone page for Derek Molnar."""
        return render_template("invenio_theme_tuw/tuwstones/derek_molnar.html")

    # register filters for showing uploaders
    blueprint.add_app_template_filter(resolve_record)
    blueprint.add_app_template_filter(resolve_user_owner)