diff --git a/invenio_theme/ext.py b/invenio_theme/ext.py index b1940a86..e37c7875 100644 --- a/invenio_theme/ext.py +++ b/invenio_theme/ext.py @@ -9,20 +9,10 @@ """Invenio standard theme.""" -from flask import Blueprint +from flask_menu import Menu from . import config from .icons import ThemeIcons -from .proxies import current_theme_icons -from .shared import menu -from .views import ( - blueprint, - insufficient_permissions, - internal_error, - page_not_found, - too_many_requests, - unauthorized, -) class InvenioTheme(object): @@ -47,33 +37,9 @@ def init_app(self, app, **kwargs): """ self.init_config(app) - # Register blueprint in order to register template and static folder. - app.register_blueprint( - Blueprint( - "invenio_theme", - __name__, - template_folder="templates", - static_folder="static", - ) - ) - - # Register frontpage blueprint if enabled. - if app.config["THEME_FRONTPAGE"]: - app.register_blueprint(blueprint) - - # Register errors handlers. - app.register_error_handler(401, unauthorized) - app.register_error_handler(403, insufficient_permissions) - app.register_error_handler(404, page_not_found) - app.register_error_handler(429, too_many_requests) - app.register_error_handler(500, internal_error) - - # Register context processor - @app.context_processor - def _theme_icon_ctx_processor(): - return {"current_theme_icons": current_theme_icons} - - app.context_processor(lambda: {"menu": menu}) + self.menu_ext = Menu(app) + + app.context_processor(lambda: {"current_theme_icons": self.icons}) # Save reference to self on object app.extensions["invenio-theme"] = self diff --git a/invenio_theme/shared.py b/invenio_theme/shared.py index 2ee7ef67..68166a05 100644 --- a/invenio_theme/shared.py +++ b/invenio_theme/shared.py @@ -8,6 +8,6 @@ """Invenio standard theme.""" -from flask_menu.menu import MenuRoot +from flask_menu.menu import MenuNode -menu = MenuRoot("", None) +menu = MenuNode("", None) diff --git a/invenio_theme/views.py b/invenio_theme/views.py index 58ceeb15..ee7f64bc 100644 --- a/invenio_theme/views.py +++ b/invenio_theme/views.py @@ -2,7 +2,7 @@ # # This file is part of Invenio. # Copyright (C) 2015-2018 CERN. -# Copyright (C) 2022 Graz University of Technology. +# Copyright (C) 2022-2023 Graz University of Technology. # # Invenio is free software; you can redistribute it and/or modify it # under the terms of the MIT License; see LICENSE file for more details. @@ -11,10 +11,28 @@ from flask import Blueprint, current_app, render_template -blueprint = Blueprint("invenio_theme_frontpage", __name__) + +def create_blueprint(app): + """Create blueprint.""" + blueprint = Blueprint( + "invenio_theme_frontpage", + __name__, + template_folder="templates", + static_folder="static", + ) + + if app.config["THEME_FRONTPAGE"]: + blueprint.add_url_rule("/", "index", view_func=index) + + app.register_error_handler(401, unauthorized) + app.register_error_handler(403, insufficient_permissions) + app.register_error_handler(404, page_not_found) + app.register_error_handler(429, too_many_requests) + app.register_error_handler(500, internal_error) + + return blueprint -@blueprint.route("/") def index(): """Simplistic front page view.""" return render_template( diff --git a/setup.cfg b/setup.cfg index 24b61e68..b78aeb2c 100644 --- a/setup.cfg +++ b/setup.cfg @@ -27,7 +27,7 @@ packages = find: python_requires = >=3.7 zip_safe = False install_requires = - Flask-Menu>=1.0.0 + Flask-Menu>=0.5.0 invenio-assets>=1.2.7 invenio-base>=1.2.5 invenio-i18n>=2.0.0 @@ -46,6 +46,8 @@ invenio_assets.webpack = invenio_theme = invenio_theme.webpack:theme invenio_base.apps = invenio_theme = invenio_theme:InvenioTheme +invenio_base.blueprints = + invenio_theme = invenio_theme.views:create_blueprint invenio_i18n.translations = messages = invenio_theme diff --git a/tests/conftest.py b/tests/conftest.py index 121e8f33..683de503 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -2,7 +2,7 @@ # # This file is part of Invenio. # Copyright (C) 2015-2018 CERN. -# Copyright (C) 2022 Graz University of Technology. +# Copyright (C) 2022-2023 Graz University of Technology. # # Invenio is free software; you can redistribute it and/or modify it # under the terms of the MIT License; see LICENSE file for more details. @@ -10,19 +10,47 @@ """Pytest configuration.""" -import os + import shutil -import tempfile import jinja2 import pytest from flask import Flask +from flask_webpackext.manifest import ( + JinjaManifest, + JinjaManifestEntry, + JinjaManifestLoader, +) from helpers import make_fake_template from invenio_assets import InvenioAssets from invenio_i18n import Babel, InvenioI18N from invenio_i18n.views import create_blueprint_from_app from invenio_theme import InvenioTheme +from invenio_theme.views import create_blueprint + + +# +# Mock the webpack manifest to avoid having to compile the full assets. +# +class MockJinjaManifest(JinjaManifest): + """Mock manifest.""" + + def __getitem__(self, key): + """Get a manifest entry.""" + return JinjaManifestEntry(key, [key]) + + def __getattr__(self, name): + """Get a manifest entry.""" + return JinjaManifestEntry(name, [name]) + + +class MockManifestLoader(JinjaManifestLoader): + """Manifest loader creating a mocked manifest.""" + + def load(self, filepath): + """Load the manifest.""" + return MockJinjaManifest() @pytest.fixture() @@ -31,10 +59,15 @@ def app(): app = Flask("myapp") app.config.update( I18N_LANGUAGES=[("en", "English"), ("de", "German")], + THEME_FRONTPAGE=False, + APP_THEME=["semantic-ui"], + WEBPACKEXT_MANIFEST_LOADER=MockManifestLoader, ) Babel(app) InvenioI18N(app) + app.register_blueprint(create_blueprint_from_app(app)) + app.register_blueprint(create_blueprint(app)) def delete_locale_from_cache(exception): """Unset locale from `flask.g` when the request is tearing down.""" @@ -67,6 +100,8 @@ def app_error_handler(request): # Setting by default fake.html as a THEME_ERROR_TEMPLATE app.config["THEME_ERROR_TEMPLATE"] = "invenio_theme/fake.html" + app.config["APP_THEME"] = ["semantic-ui"] + # Tear down method to clean the temp directory. def tear_down(): shutil.rmtree(temp_dir) @@ -77,6 +112,8 @@ def tear_down(): Babel(app) InvenioI18N(app) InvenioTheme(app) + + app.register_blueprint(create_blueprint(app)) return app @@ -100,6 +137,7 @@ def app_frontpage_handler(request): # Setting by default fake.html as a BASE_TEMPLATE app.config["BASE_TEMPLATE"] = "invenio_theme/fake.html" app.config["THEME_FRONTPAGE"] = True + app.config["APP_THEME"] = ["semantic-ui"] # Tear down method to clean the temp directory. def tear_down(): @@ -112,4 +150,6 @@ def tear_down(): InvenioI18N(app) InvenioTheme(app) InvenioAssets(app) + + app.register_blueprint(create_blueprint(app)) return app diff --git a/tests/test_invenio_theme.py b/tests/test_invenio_theme.py index 59416052..8c0da25c 100644 --- a/tests/test_invenio_theme.py +++ b/tests/test_invenio_theme.py @@ -187,6 +187,8 @@ def index(): def test_frontpage_not_exists(app): """Test the frontpage that doesn't exist.""" # Before configure the frontpage + InvenioTheme(app) + InvenioAssets(app) with app.test_client() as client: response = client.get("/") assert response.status_code == 404