From 02a95b4f1ace475af3d864611bcab4bfe1455b9a Mon Sep 17 00:00:00 2001 From: Peter Vorman Date: Mon, 5 May 2025 17:25:33 +0300 Subject: [PATCH 1/4] markdown view for any resource --- ckanext/markdown_view/plugin.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/ckanext/markdown_view/plugin.py b/ckanext/markdown_view/plugin.py index 81a5cd3..74b6026 100644 --- a/ckanext/markdown_view/plugin.py +++ b/ckanext/markdown_view/plugin.py @@ -24,11 +24,11 @@ def info(self): 'icon': 'file-text-o', 'filterable': False, 'iframed': False, - 'schema': {'page_url': [ignore_empty, unicode_safe, url_validator]}, + 'schema': {'page_url': [ignore_empty, unicode_safe, url_validator, url_to_md_file]}, } def can_view(self, data_dict): - return data_dict['resource'].get('format', '').lower() in ('text/markdown', 'markdown', 'md') + return True def setup_template_variables(self, context, data_dict): resource = data_dict['resource'] @@ -44,3 +44,12 @@ def view_template(self, context, data_dict): def form_template(self, context, data_dict): return 'markdown_form.html' + + +def url_to_md_file(value): + if value: + if value.endswith('.md'): + return value + else: + raise tk.Invalid(tk._('Url should point to markdown file (endswith .md)')) + return value From 047d48a93fee7da477fe37a86e00252439d458f5 Mon Sep 17 00:00:00 2001 From: Peter Vorman Date: Tue, 13 May 2025 17:12:35 +0300 Subject: [PATCH 2/4] markdown view for not markdown resources --- ckanext/markdown_view/plugin.py | 19 +++++++++++-------- .../templates/markdown_view.html | 10 +++++++++- 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/ckanext/markdown_view/plugin.py b/ckanext/markdown_view/plugin.py index 74b6026..41994d2 100644 --- a/ckanext/markdown_view/plugin.py +++ b/ckanext/markdown_view/plugin.py @@ -24,11 +24,14 @@ def info(self): 'icon': 'file-text-o', 'filterable': False, 'iframed': False, - 'schema': {'page_url': [ignore_empty, unicode_safe, url_validator, url_to_md_file]}, + 'always_available': True, + 'schema': { + 'page_url': [unicode_safe, url_validator, url_to_md_file] + }, } def can_view(self, data_dict): - return True + return data_dict.get('resource', {}).get('format', '').lower() in ('text/markdown', 'markdown', 'md') def setup_template_variables(self, context, data_dict): resource = data_dict['resource'] @@ -47,9 +50,9 @@ def form_template(self, context, data_dict): def url_to_md_file(value): - if value: - if value.endswith('.md'): - return value - else: - raise tk.Invalid(tk._('Url should point to markdown file (endswith .md)')) - return value + if not value: + return None + elif value.endswith('.md'): + return value + else: + raise tk.Invalid(tk._('Url should point to markdown file (endswith .md)')) diff --git a/ckanext/markdown_view/templates/markdown_view.html b/ckanext/markdown_view/templates/markdown_view.html index 0ae860c..e90ac34 100644 --- a/ckanext/markdown_view/templates/markdown_view.html +++ b/ckanext/markdown_view/templates/markdown_view.html @@ -1,2 +1,10 @@ {% asset 'md_view_assets/md_view_js' %} -
+ +{% set page_url = resource_view.get('page_url') %} +{% if page_url and page_url.endswith('.md') %} +
+{% elif not page_url and resource_url.endswith('.md') %} +
+{% else %} + +{% endif %} From d065ac6c3845069ef6b9ea552ca03c7b079d7059 Mon Sep 17 00:00:00 2001 From: Peter Vorman Date: Tue, 13 May 2025 17:20:03 +0300 Subject: [PATCH 3/4] tests --- ckanext/markdown_view/plugin.py | 2 +- .../templates/markdown_view.html | 2 +- ckanext/markdown_view/tests/test_view.py | 38 +++++++++++++------ 3 files changed, 29 insertions(+), 13 deletions(-) diff --git a/ckanext/markdown_view/plugin.py b/ckanext/markdown_view/plugin.py index 41994d2..167900c 100644 --- a/ckanext/markdown_view/plugin.py +++ b/ckanext/markdown_view/plugin.py @@ -55,4 +55,4 @@ def url_to_md_file(value): elif value.endswith('.md'): return value else: - raise tk.Invalid(tk._('Url should point to markdown file (endswith .md)')) + raise tk.Invalid(tk._('Url should point to a markdown file (ends with .md)')) diff --git a/ckanext/markdown_view/templates/markdown_view.html b/ckanext/markdown_view/templates/markdown_view.html index e90ac34..aa886b5 100644 --- a/ckanext/markdown_view/templates/markdown_view.html +++ b/ckanext/markdown_view/templates/markdown_view.html @@ -3,7 +3,7 @@ {% set page_url = resource_view.get('page_url') %} {% if page_url and page_url.endswith('.md') %}
-{% elif not page_url and resource_url.endswith('.md') %} +{% elif resource_url.endswith('.md') %}
{% else %} diff --git a/ckanext/markdown_view/tests/test_view.py b/ckanext/markdown_view/tests/test_view.py index abac3ea..5b746d5 100644 --- a/ckanext/markdown_view/tests/test_view.py +++ b/ckanext/markdown_view/tests/test_view.py @@ -1,29 +1,45 @@ # encoding: utf-8 import pytest -import responses from ckan.tests import factories import ckan.plugins as p -from ckan.plugins import toolkit as tk -def _add_responses_solr_passthru(): - responses.add_passthru(tk.config.get('solr_url')) +@pytest.mark.usefixtures('clean_db', 'clean_index', 'with_plugins', 'with_request_context') +@pytest.mark.ckan_config('ckan.plugins', 'markdown_view') +def test_view_create_for_md_resource(): + org = factories.Organization() + dataset = factories.Dataset(owner_org=org['id'],) + sysadmin = factories.Sysadmin() + resource = factories.Resource( + package_id=dataset['id'], + url='http://some.website.md', + format='md' + ) + + resource_view = factories.ResourceView( + resource_id=resource['id'], + view_type='Markdown' + ) + + response = p.toolkit.get_action('resource_view_show')( + {'user': sysadmin.get('name')}, + {'id': resource_view.get('id')} + ) + + assert response.get('view_type') == 'Markdown' @pytest.mark.usefixtures('clean_db', 'clean_index', 'with_plugins', 'with_request_context') -@pytest.mark.ckan_config('ckan.plugins', 'datastore markdown_view') -def test_view_create(): +@pytest.mark.ckan_config('ckan.plugins', 'markdown_view') +def test_view_create_for_csv_resource(): org = factories.Organization() dataset = factories.Dataset(owner_org=org['id'],) sysadmin = factories.Sysadmin() resource = factories.Resource( package_id=dataset['id'], - url='http://some.website.html',) - - p.toolkit.get_action('datastore_create')( - {'user': sysadmin.get('name')}, - {'resource_id': resource.get('id'), 'force': True} + url='http://some.website.csv', + format='csv' ) resource_view = factories.ResourceView( From 7d6dcbd40753561c856259fb3eea9f626f35e6c6 Mon Sep 17 00:00:00 2001 From: Peter Vorman Date: Wed, 14 May 2025 17:05:47 +0300 Subject: [PATCH 4/4] tests page --- ckanext/markdown_view/tests/test_view.py | 71 +++++++++++++++++++++++- 1 file changed, 69 insertions(+), 2 deletions(-) diff --git a/ckanext/markdown_view/tests/test_view.py b/ckanext/markdown_view/tests/test_view.py index 5b746d5..831d550 100644 --- a/ckanext/markdown_view/tests/test_view.py +++ b/ckanext/markdown_view/tests/test_view.py @@ -3,11 +3,12 @@ from ckan.tests import factories import ckan.plugins as p +from ckan.logic import ValidationError @pytest.mark.usefixtures('clean_db', 'clean_index', 'with_plugins', 'with_request_context') @pytest.mark.ckan_config('ckan.plugins', 'markdown_view') -def test_view_create_for_md_resource(): +def test_view_create_for_md_resource(app): org = factories.Organization() dataset = factories.Dataset(owner_org=org['id'],) sysadmin = factories.Sysadmin() @@ -28,11 +29,17 @@ def test_view_create_for_md_resource(): ) assert response.get('view_type') == 'Markdown' + env = {"REMOTE_USER": sysadmin['name'].encode('ascii')} + resp = app.get(f"/dataset/{dataset['id']}/resource/{resource['id']}?view_id={resource_view['id']}", + extra_environ=env) + + assert resp.status_code == 200 + assert f'
' in resp.body @pytest.mark.usefixtures('clean_db', 'clean_index', 'with_plugins', 'with_request_context') @pytest.mark.ckan_config('ckan.plugins', 'markdown_view') -def test_view_create_for_csv_resource(): +def test_view_create_for_csv_resource(app): org = factories.Organization() dataset = factories.Dataset(owner_org=org['id'],) sysadmin = factories.Sysadmin() @@ -53,3 +60,63 @@ def test_view_create_for_csv_resource(): ) assert response.get('view_type') == 'Markdown' + + env = {"REMOTE_USER": sysadmin['name'].encode('ascii')} + resp = app.get(f"/dataset/{dataset['id']}/resource/{resource['id']}?view_id={resource_view['id']}", extra_environ=env) + + assert resp.status_code == 200 + assert 'This Resource cannot be processed by markdown view.' in resp.body + + +@pytest.mark.usefixtures('clean_db', 'clean_index', 'with_plugins', 'with_request_context') +@pytest.mark.ckan_config('ckan.plugins', 'markdown_view') +def test_view_create_for_csv_resource_with_correct_page_url(app): + org = factories.Organization() + dataset = factories.Dataset(owner_org=org['id'],) + sysadmin = factories.Sysadmin() + resource = factories.Resource( + package_id=dataset['id'], + url='http://some.website.csv', + format='csv' + ) + page_url = 'http://some.website.md' + + resource_view = factories.ResourceView( + resource_id=resource['id'], + view_type='Markdown', + page_url=page_url, + ) + + response = p.toolkit.get_action('resource_view_show')( + {'user': sysadmin.get('name')}, + {'id': resource_view.get('id')} + ) + + assert response.get('view_type') == 'Markdown' + + env = {"REMOTE_USER": sysadmin['name'].encode('ascii')} + resp = app.get(f"/dataset/{dataset['id']}/resource/{resource['id']}?view_id={resource_view['id']}", + extra_environ=env) + + assert resp.status_code == 200 + assert f'
' in resp.body + + +@pytest.mark.usefixtures('clean_db', 'clean_index', 'with_plugins', 'with_request_context') +@pytest.mark.ckan_config('ckan.plugins', 'markdown_view') +def test_view_create_for_csv_resource_with_incorrect_page_url(app): + org = factories.Organization() + dataset = factories.Dataset(owner_org=org['id'], ) + resource = factories.Resource( + package_id=dataset['id'], + url='http://some.website.csv', + format='csv' + ) + page_url = 'http://some.website.html' + + with pytest.raises(ValidationError): + factories.ResourceView( + resource_id=resource['id'], + view_type='Markdown', + page_url=page_url, + )