Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
109 changes: 109 additions & 0 deletions invenio.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ from zenodo_rdm.custom_fields import (
NAMESPACES,
)
from zenodo_rdm.custom_schemes import is_edmo
from zenodo_rdm.db import routed_bind
from zenodo_rdm.files import storage_factory
from zenodo_rdm.github.schemas import CitationMetadataSchema
from zenodo_rdm.metrics.config import METRICS_CACHE_UPDATE_INTERVAL
Expand Down Expand Up @@ -161,6 +162,114 @@ if _parse_env_bool("INVENIO_PGBOUNCER_ENABLED", False):
else:
SQLALCHEMY_DATABASE_URI = "postgresql+psycopg2://zenodo:zenodo@localhost/zenodo"

# fmt: off
ZENODO_UI_READ_ONLY_ENDPOINTS = [
"invenio_app_rdm.frontpage_view_function", # /
"invenio_app_rdm_records.record_from_pid", # /<any(doi,oai):pid_scheme>/<path:pid_value>
"invenio_redirector.redirect_about", # /about
"invenio_formatter_badges.badge", # png):ext>
"invenio_github_badge.index", # /badge/<int:repo_github_id>.svg
"invenio_github_badge.index_old", # /badge/<int:user_id>/<path:repo_name>.svg
"invenio_github_badge.latest_doi", # /badge/latestdoi/<int:github_id>
"invenio_github_badge.latest_doi_old", # /badge/latestdoi/<int:user_id>/<path:repo_name>
"invenio_redirector.redirect_communities_search_legacy", # /collection/<type>
"invenio_redirector.redirect_collections_about", # /collection/user-<id>
"invenio_communities.communities_frontpage", # /communities
"invenio_communities.communities_search", # /communities-search
"invenio_redirector.redirect_communities_curate", # /communities/<community_id>/curate
"invenio_redirector.redirect_communities_edt", # /communities/<community_id>/edit
"invenio_redirector.redirect_communities_search", # /communities/<community_id>/search
"invenio_app_rdm_communities.communities_home", # /communities/<pid_value>/
"invenio_communities.communities_about", # /communities/<pid_value>/about
"invenio_app_rdm_communities.communities_browse", # /communities/<pid_value>/browse
"invenio_communities.communities_subcommunities", # /communities/<pid_value>/browse/subcommunities
"invenio_app_rdm_communities.community_collection", # /communities/<pid_value>/collections/<tree_slug>/<collection_slug>
"invenio_communities.community_theme_css_config", # /communities/<pid_value>/community-theme-<revision>.css
"invenio_communities.communities_curation_policy", # /communities/<pid_value>/curation-policy
"invenio_communities.members", # /communities/<pid_value>/members
"invenio_app_rdm_communities.community_static_page", # /communities/<pid_value>/pages/<path:page_slug>
"invenio_app_rdm_communities.communities_detail", # /communities/<pid_value>/records
"invenio_redirector.redirect_communities_about_legacy", # /communities/about/<id>
"invenio_communities.deprecated_communities_search", # /communities/search
"invenio_redirector.redirect_contact", # /contact
"invenio_redirector.redirect_dev", # /dev
"invenio_redirector.redirect_donate", # /donate
"invenio_redirector.redirect_faq", # /faq
"invenio_redirector.redirect_features", # /features
"invenio_app_rdm.help_search", # /help/search
"invenio_app_rdm.help_statistics", # /help/statistics
"invenio_app_rdm.help_versioning", # /help/versioning
"invenio_redirector.redirect_policies", # /policies
"invenio_redirector.redirect_privacy-policy", # /privacy-policy
"invenio_redirector.redirect_record_detail", # /record/<pid_value>
"invenio_redirector.redirect_record_export", # /record/<pid_value>/export/<export_format>
"invenio_redirector.redirect_record_file_download", # /record/<pid_value>/files/<path:filename>
"invenio_redirector.redirect_formats_to_media_files", # /record/<pid_value>/formats
"invenio_redirector.redirect_record_file_preview", # /record/<pid_value>/preview/<path:filename>
"invenio_redirector.redirect_record_thumbnail", # /record/<pid_value>/thumb<size>
"invenio_app_rdm_records.record_detail", # /records/<pid_value>
"invenio_app_rdm_records.record_export", # /records/<pid_value>/export/<export_format>
"invenio_redirector.redirect_legacy_record_export_view_dcat", # /records/<pid_value>/export/dcat
"invenio_redirector.redirect_legacy_record_export_view_dcite4", # /records/<pid_value>/export/dcite4
"invenio_redirector.redirect_legacy_record_export_view_hx", # /records/<pid_value>/export/hx
"invenio_redirector.redirect_legacy_record_export_view_xd", # /records/<pid_value>/export/xd
"invenio_redirector.redirect_legacy_record_export_view_xm", # /records/<pid_value>/export/xm
"invenio_app_rdm_records.record_file_download", # /records/<pid_value>/files/<path:filename>
"invenio_app_rdm_records.record_latest", # /records/<pid_value>/latest
"invenio_app_rdm_records.record_media_file_download", # /records/<pid_value>/media-files/<path:filename>
"invenio_app_rdm_records.record_file_preview", # /records/<pid_value>/preview/<path:filename>
"invenio_app_rdm_records.record_thumbnail", # /records/<pid_value>/thumb<int:size>
"invenio_search_ui.search", # /search
"invenio_redirector.redirect_terms", # /terms
]

ZENODO_API_READ_ONLY_ENDPOINTS = [
"collections.search_records", # /collections/<id>/records
"communities.search", # /communities
"communities.read", # /communities/<pid_value>
"communities.featured_list", # /communities/<pid_value>/featured
"communities.read_logo", # /communities/<pid_value>/logo
"community_members.search", # /communities/<pid_value>/members
"community_members.search_public", # /communities/<pid_value>/members/public
"community-records.search", # /communities/<pid_value>/records
"communities.search_subcommunities", # /communities/<pid_value>/subcommunities
"communities.featured_communities_search", # /communities/featured
"exporter.list_object_versions", # /exporter
"exporter.get_object_version_content", # /exporter/<path:key>
"exporter.get_object_version_content", # /exporter/<path:key>/<uuid:version_id>
"iiif.base", # /iiif/<path:uuid>
"iiif.image_api", # /iiif/<path:uuid>/<region>/<size>/<rotation>/<quality>.<image_format>
"iiif.canvas", # /iiif/<path:uuid>/canvas/<path:file_name>
"iiif.info", # /iiif/<path:uuid>/info.json
"iiif.manifest", # /iiif/<path:uuid>/manifest
"iiif.sequence", # /iiif/<path:uuid>/sequence/default
"records.search", # /records
"zenodo_api_redirector.redirect_records_search_slash", # /records/
"records.read", # /records/<pid_value>
"record_files.search", # /records/<pid_value>/files
"record_files.read_archive", # /records/<pid_value>/files-archive
"record_files.read", # /records/<pid_value>/files/<path:key>
"record_files.read_content", # /records/<pid_value>/files/<path:key>/content
"record_media_files.search", # /records/<pid_value>/media-files
"record_media_files.read_archive", # /records/<pid_value>/media-files-archive
"record_media_files.read", # /records/<pid_value>/media-files/<key>
"record_media_files.read_content", # /records/<pid_value>/media-files/<key>/content
"records.search_versions", # /records/<pid_value>/versions
"records.read_latest", # /records/<pid_value>/versions/latest
]
# fmt: on

ZENODO_READ_REPLICA_ENDPOINTS = (
ZENODO_UI_READ_ONLY_ENDPOINTS + ZENODO_API_READ_ONLY_ENDPOINTS
)
if IS_LOCAL_DEV:
SQLALCHEMY_BINDS = {
"read_replica": "postgresql+psycopg2://zenodo_ro:zenodo_ro@localhost/zenodo"
}

DB_SESSION_BIND_FUNC = routed_bind


# Invenio-App
# ===========
# See https://invenio-app.readthedocs.io/en/latest/configuration.html
Expand Down
22 changes: 22 additions & 0 deletions site/zenodo_rdm/db.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2025 CERN.
#
# ZenodoRDM is free software; you can redistribute it and/or modify it
# under the terms of the MIT License; see LICENSE file for more details.
"""Database helpers."""

from flask import current_app, request
from flask_login import current_user


def routed_bind(session, *args, **kwargs):
"""Route session to the appropriate database depending on the request context.

Routes unauthenticated/anonymous GET and HEAD requests of configured endpoints to
the configured read replica SQLAlchemy bind.
"""
if request and request.method in ["GET", "HEAD"]:
read_endpoints = current_app.config.get("ZENODO_READ_REPLICA_ENDPOINTS", [])
if current_user.is_anonymous and request.endpoint in read_endpoints:
return session._db.engines["read_replica"]
Loading