Newer
Older
# -*- coding: utf-8 -*-
#
#
# 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:
owner = owner.resolve()
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,
form_values=form_values,
)
return response, 200 if not captcha_failed else 428
"""Page showing the available repository policies."""
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")
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(),
)
else:
abort(403)
@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)