From 417a6e39f2a840a34a04c9a7a5109c12f941ab2e Mon Sep 17 00:00:00 2001 From: Mirek Simek Date: Fri, 29 Dec 2023 17:44:20 +0100 Subject: [PATCH] Adding template page resource (#123) * Adding template page resource * Fixed sonarcloud issue --- oarepo_ui/resources/catalog.py | 2 +- oarepo_ui/resources/config.py | 4 +++ oarepo_ui/resources/resource.py | 61 ++++++++++++++++++++++++++------- setup.cfg | 2 +- tests/conftest.py | 11 +++++- tests/model.py | 14 ++++++++ tests/templates/TitlePage.jinja | 4 +++ tests/test_template_page.py | 10 ++++++ tests/test_templating.py | 23 ------------- 9 files changed, 93 insertions(+), 38 deletions(-) create mode 100644 tests/templates/TitlePage.jinja create mode 100644 tests/test_template_page.py delete mode 100644 tests/test_templating.py diff --git a/oarepo_ui/resources/catalog.py b/oarepo_ui/resources/catalog.py index b19905c7..fbd4f5d7 100644 --- a/oarepo_ui/resources/catalog.py +++ b/oarepo_ui/resources/catalog.py @@ -112,7 +112,7 @@ def _get_component_path( if name in paths: return paths[name] - raise ComponentNotFound(f"Unable to find a file named {name}") + raise ComponentNotFound(name) def list_templates(self): searchpath = [] diff --git a/oarepo_ui/resources/config.py b/oarepo_ui/resources/config.py index 78223248..af37be58 100644 --- a/oarepo_ui/resources/config.py +++ b/oarepo_ui/resources/config.py @@ -41,6 +41,10 @@ def get_template_folder(self): request_view_args = {} +class TemplatePageUIResourceConfig(UIResourceConfig): + routes = {} + + class RecordsUIResourceConfig(UIResourceConfig): routes = { "search": "", diff --git a/oarepo_ui/resources/resource.py b/oarepo_ui/resources/resource.py index d3266e58..263d53cc 100644 --- a/oarepo_ui/resources/resource.py +++ b/oarepo_ui/resources/resource.py @@ -53,7 +53,9 @@ def as_blueprint(self, **options): template_folder = self.config.get_template_folder() if template_folder: options["template_folder"] = template_folder - return super().as_blueprint(**options) + blueprint = super().as_blueprint(**options) + blueprint.app_context_processor(lambda: self.fill_jinja_context()) + return blueprint # # Pluggable components @@ -70,6 +72,12 @@ def run_components(self, action, *args, **kwargs): if hasattr(component, action): getattr(component, action)(*args, **kwargs) + def fill_jinja_context(self): + """function providing flask template app context processors""" + ret = {} + self.run_components("fill_jinja_context", context=ret) + return ret + class RecordsUIResource(UIResource): config: RecordsUIResourceConfig @@ -113,17 +121,6 @@ def empty_record(self, resource_requestctx, **kwargs): ) return empty_data - def as_blueprint(self, **options): - blueprint = super().as_blueprint(**options) - blueprint.app_context_processor(lambda: self.fill_jinja_context()) - return blueprint - - def fill_jinja_context(self): - """function providing flask template app context processors""" - ret = {} - self.run_components("fill_jinja_context", context=ret) - return ret - @request_read_args @request_view_args def detail(self): @@ -430,3 +427,43 @@ def expand_search_links(self, identity, pagination, args): {"config": self.config, "url_prefix": self.config.url_prefix, "args": args}, ) return tpl.expand(identity, pagination) + + +class TemplatePageUIResource(UIResource): + + def create_url_rules(self): + """Create the URL rules for the record resource.""" + route_config = self.config.routes + routes = [] + for route_name, route_path in route_config.items(): + handler = getattr(self, route_name, None) or partial(self.render, page=route_name) + if not hasattr(handler, '__name__'): + handler.__name__ = self.render.__name__ + if not hasattr(handler, '__self__'): + handler.__self__ = self + + routes.append( + route("GET", route_path, handler), + ) + return routes + + @request_view_args + def render(self, page, *args, **kwargs): + extra_context = dict() + + self.run_components( + "before_render", + identity=g.identity, + args=resource_requestctx.args, + view_args=resource_requestctx.view_args, + ui_config=self.config, + extra_context=extra_context, + page=page, + ) + + return current_oarepo_ui.catalog.render( + page, + ui_config=self.config, + ui_resource=self, + extra_context=extra_context, + ) diff --git a/setup.cfg b/setup.cfg index 7a600a22..c570ffe2 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,6 @@ [metadata] name = oarepo-ui -version = 5.0.94 +version = 5.0.95 description = UI module for invenio 3.5+ long_description = file: README.md long_description_content_type = text/markdown diff --git a/tests/conftest.py b/tests/conftest.py index 37285799..750bec41 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -10,7 +10,7 @@ from invenio_accounts.testutils import login_user_via_session from invenio_app.factory import create_app as _create_app -from tests.model import ModelUIResource, ModelUIResourceConfig +from tests.model import ModelUIResource, ModelUIResourceConfig, TitlePageUIResource, TitlePageUIResourceConfig @pytest.fixture(scope="module") @@ -69,6 +69,15 @@ def record_ui_resource(app, record_ui_resource_config, record_service): return ui_resource +@pytest.fixture(scope="module") +def titlepage_ui_resource(app, ): + ui_resource = TitlePageUIResource(TitlePageUIResourceConfig()) + app.register_blueprint( + ui_resource.as_blueprint(template_folder=Path(__file__).parent / "templates") + ) + return ui_resource + + @pytest.fixture() def fake_manifest(app): python_path = Path(sys.executable) diff --git a/tests/model.py b/tests/model.py index 901eed0a..563e3878 100644 --- a/tests/model.py +++ b/tests/model.py @@ -24,6 +24,8 @@ RecordsUIResourceConfig, ) from oarepo_ui.resources.components import PermissionsComponent +from oarepo_ui.resources.config import TemplatePageUIResourceConfig +from oarepo_ui.resources.resource import TemplatePageUIResource class ModelRecordIdProvider(RecordIdProviderV2): @@ -109,3 +111,15 @@ def _get_record(self, resource_requestctx, allow_draft=False): # we are not testing drafts here, so always return published record # tests for drafts should be in oarepo-model-builder-drafts return super()._get_record(resource_requestctx, allow_draft=False) + + +class TitlePageUIResourceConfig(TemplatePageUIResourceConfig): + blueprint_name = 'titlepage' + url_prefix = '/' + routes = { + 'TitlePage': '' + } + + +class TitlePageUIResource(TemplatePageUIResource): + pass \ No newline at end of file diff --git a/tests/templates/TitlePage.jinja b/tests/templates/TitlePage.jinja new file mode 100644 index 00000000..ea9a1d79 --- /dev/null +++ b/tests/templates/TitlePage.jinja @@ -0,0 +1,4 @@ +{# def #} +{ + "ok": "true" +} \ No newline at end of file diff --git a/tests/test_template_page.py b/tests/test_template_page.py new file mode 100644 index 00000000..a9532a29 --- /dev/null +++ b/tests/test_template_page.py @@ -0,0 +1,10 @@ +import json + + +def test_template_page( + app, titlepage_ui_resource, client, fake_manifest +): + with client.get("/") as c: + assert c.status_code == 200 + data = json.loads(c.text) + assert 'ok' in data diff --git a/tests/test_templating.py b/tests/test_templating.py deleted file mode 100644 index 792e6005..00000000 --- a/tests/test_templating.py +++ /dev/null @@ -1,23 +0,0 @@ -import re - -from flask import render_template_string # noqa - -from oarepo_ui.resources.templating import TemplateRegistry # noqa - - -def strip_ws(x): - return re.sub(r"\s+", "", x) - - -# def test_process_template(app): -# ui = app.extensions["oarepo_ui"] -# env = ui.templates.jinja_env -# template = env.from_string('

{% value "metadata.title" %}

') -# rendered = template.render( -# ui={"metadata": {"title": "Hello world!"}}, -# layout={ -# "children": {"metadata": {"children": {"title": {"detail": "fulltext"}}}} -# }, -# component_key="search", -# ) -# assert strip_ws(rendered) == strip_ws("""

Hello world!

""")