diff --git a/CHANGES.rst b/CHANGES.rst index 90067c5c..cbe9e04e 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -1,3 +1,11 @@ +2.1.1 (01-08-2023) +------------------ + +- ConceptVisitLog has an integer concept_id in the ConceptVisitLog class #906 +- skosprovider route /expand does not work #903 +- Manual ID text box not writable #902 + + 2.1.0 (22-07-2023) ------------------ diff --git a/CITATION.cff b/CITATION.cff index 4997dc38..0a7484f7 100644 --- a/CITATION.cff +++ b/CITATION.cff @@ -88,5 +88,5 @@ keywords: - vocabulary - python license: GPL-3.0 -version: 2.1.0 +version: 2.1.1 date-released: '2024-06-20' diff --git a/atramhasis/__init__.py b/atramhasis/__init__.py index a74f60df..15cd5a36 100644 --- a/atramhasis/__init__.py +++ b/atramhasis/__init__.py @@ -34,6 +34,8 @@ def includeme(config): for key, value in DEFAULT_SETTINGS.items(): if key not in settings: settings[key] = value + # Regexes in path params clash with this validation. + settings["pyramid_openapi3.enable_endpoint_validation"] = False configure_session(config) config.include('pyramid_jinja2') config.include('pyramid_tm') @@ -44,9 +46,10 @@ def includeme(config): config.include('pyramid_rewrite') config.include("pyramid_openapi3") config.include('atramhasis.routes') + # pyramid_skosprovider must be included after the atramhasis routes + # because it contains a regex in the path which consumes a lot of routes. config.include('pyramid_skosprovider') config.include('atramhasis.cache') - config.scan('pyramid_skosprovider') config.add_translation_dirs('atramhasis:locale/') diff --git a/atramhasis/alembic/versions/29306f749043_alter_conceptvisitlog_concept_id_to_.py b/atramhasis/alembic/versions/29306f749043_alter_conceptvisitlog_concept_id_to_.py new file mode 100644 index 00000000..6b2059b3 --- /dev/null +++ b/atramhasis/alembic/versions/29306f749043_alter_conceptvisitlog_concept_id_to_.py @@ -0,0 +1,30 @@ +"""alter ConceptVisitLog concept_id to string + +Revision ID: 29306f749043 +Revises: b2a7d7614973 +Create Date: 2024-07-30 09:12:37.521748 + +""" + +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = '29306f749043' +down_revision = 'b2a7d7614973' + + +def upgrade(): + with op.batch_alter_table('concept_visit_log') as batch_op: + batch_op.alter_column('concept_id', type_=sa.String, existing_type=sa.Integer) + + +def downgrade(): + # Drop concept_visit_log which have non-integer concept_id + op.execute( + "DELETE FROM concept_visit_log " + "WHERE cast(cast(concept_id AS INTEGER) AS TEXT) != concept_id" + ) + with op.batch_alter_table('concept_visit_log') as batch_op: + batch_op.alter_column('concept_id', type_=sa.Integer, existing_type=sa.String) diff --git a/atramhasis/data/models.py b/atramhasis/data/models.py index a00bcf84..ca3b3876 100644 --- a/atramhasis/data/models.py +++ b/atramhasis/data/models.py @@ -39,7 +39,7 @@ class ConceptschemeVisitLog(Base): class ConceptVisitLog(Base): __tablename__ = 'concept_visit_log' id = Column(Integer, primary_key=True, autoincrement=True) - concept_id = Column(Integer, nullable=False) + concept_id = Column(String, nullable=False) conceptscheme_id = Column(String(25), nullable=False) visited_at = Column(DateTime, default=func.now(), nullable=False) origin = Column(String(25), nullable=False) diff --git a/atramhasis/openapi.yaml b/atramhasis/openapi.yaml index 5bb4ef7b..637beb82 100644 --- a/atramhasis/openapi.yaml +++ b/atramhasis/openapi.yaml @@ -2,7 +2,7 @@ openapi: 3.0.3 info: title: Atramhasis API - version: 2.1.0 + version: 2.1.1 servers: - url: '/' @@ -142,7 +142,7 @@ paths: description: The identifier for a certain concept or collection. required: true schema: - type: integer + type: string responses: 200: description: The concept was found in the conceptscheme. @@ -172,7 +172,7 @@ paths: description: The identifier for a certain concept or collection. required: true schema: - type: integer + type: string requestBody: required: true description: Data to create concept or collection @@ -222,7 +222,7 @@ paths: description: The identifier for a certain concept or collection. required: true schema: - type: integer + type: string responses: 200: @@ -692,7 +692,7 @@ paths: description: The identifier for a certain concept or collection. required: true schema: - type: integer + type: string - name: language in: query description: Returns the label with the corresponding language-tag if present. @@ -748,7 +748,7 @@ paths: description: The identifier for a certain concept or collection. required: true schema: - type: integer + type: string responses: 200: description: The concept/collection was found in the conceptscheme. @@ -900,7 +900,7 @@ components: type: object properties: id: - type: integer + type: string Label: type: object properties: @@ -952,7 +952,7 @@ components: type: object properties: id: - type: integer + type: string type: type: string labels: @@ -990,7 +990,7 @@ components: - type: object properties: id: - type: integer + type: string uri: type: string ConceptTree: diff --git a/atramhasis/rdf.py b/atramhasis/rdf.py index ea45d58c..4232b556 100644 --- a/atramhasis/rdf.py +++ b/atramhasis/rdf.py @@ -76,12 +76,12 @@ def _add_provider(graph, provider, dataseturi, request): graph.add((dataseturi, VOID.subset, pd)) graph.add((pd, DCTERMS.identifier, Literal(pid))) graph.add((pd, VOID.rootResource, URIRef(provider.concept_scheme.uri))) - graph.add((pd, FOAF.homepage, URIRef(request.route_url('conceptscheme', scheme_id=pid)))) + graph.add((pd, FOAF.homepage, URIRef(request.route_url('skosprovider.conceptscheme', scheme_id=pid)))) _add_labels(graph, provider.concept_scheme, pd) _add_metadataset(graph, pd, metadataset) fmap = [ - ('rdf', FORMATS.RDF_XML, 'atramhasis.rdf_full_export_ext'), - ('ttl', FORMATS.Turtle, 'atramhasis.rdf_full_export_turtle_ext') + ('rdf', FORMATS.RDF_XML, 'skosprovider.conceptscheme.cs.rdf'), + ('ttl', FORMATS.Turtle, 'skosprovider.conceptscheme.cs.ttl') ] for f in fmap: graph.add((pd, VOID.feature, f[1])) diff --git a/atramhasis/routes.py b/atramhasis/routes.py index 7af7751b..f5d98938 100644 --- a/atramhasis/routes.py +++ b/atramhasis/routes.py @@ -27,38 +27,22 @@ def includeme(config): config.add_static_view('static', 'static', cache_max_age=3600) config.add_route("sitemap", "/sitemap_index.xml") + # APIs with extensions instead of accept headers config.add_route('atramhasis.rdf_void_turtle_ext', pattern='/void.ttl', accept='text/turtle') - config.add_route('atramhasis.rdf_full_export_ext', pattern='/conceptschemes/{scheme_id}/c.rdf') - config.add_route('atramhasis.rdf_full_export_turtle_ext', pattern='/conceptschemes/{scheme_id}/c.ttl') - config.add_route('atramhasis.rdf_conceptscheme_export_ext', pattern='/conceptschemes/{scheme_id}.rdf') - config.add_route('atramhasis.rdf_conceptscheme_export_turtle_ext', pattern='/conceptschemes/{scheme_id}.ttl') - config.add_route('atramhasis.rdf_individual_export_ext', pattern='/conceptschemes/{scheme_id}/c/{c_id:.*}.rdf') - config.add_route('atramhasis.rdf_individual_export_turtle_ext', pattern='/conceptschemes/{scheme_id}/c/{c_id:.*}.ttl') - config.add_route('atramhasis.rdf_conceptscheme_jsonld_ext', pattern='/conceptschemes/{scheme_id}.jsonld') - config.add_route('atramhasis.rdf_individual_jsonld_ext', pattern='/conceptschemes/{scheme_id}/c/{c_id:.*}.jsonld') + # The routes below extend the existing skosprovider routes with extensions + config.add_route('skosprovider.conceptscheme.cs.rdf', pattern='/conceptschemes/{scheme_id}/c.rdf') + config.add_route('skosprovider.conceptscheme.cs.ttl', pattern='/conceptschemes/{scheme_id}/c.ttl') + config.add_route('skosprovider.conceptscheme.rdf', pattern='/conceptschemes/{scheme_id}.rdf') + config.add_route('skosprovider.conceptscheme.ttl', pattern='/conceptschemes/{scheme_id}.ttl') + config.add_route('skosprovider.conceptscheme.csv', pattern='/conceptschemes/{scheme_id}/c.csv') + config.add_route('skosprovider.c.rdf', pattern='/conceptschemes/{scheme_id}/c/{c_id:.*}.rdf') + config.add_route('skosprovider.c.ttl', pattern='/conceptschemes/{scheme_id}/c/{c_id:.*}.ttl') - config.add_route('conceptschemes', pattern='/conceptschemes', accept='text/html', request_method="GET") - config.add_route('conceptscheme', pattern='/conceptschemes/{scheme_id}', accept='text/html', request_method="GET") - config.add_route('concept', pattern='/conceptschemes/{scheme_id}/c/{c_id:.*}', accept='text/html', - request_method="GET") - config.add_route('search_result', pattern='/conceptschemes/{scheme_id}/c', accept='text/html') - config.add_route('scheme_root', pattern='/conceptschemes/{scheme_id}/c/', accept='text/html') + # tree config.add_route('scheme_tree_html', pattern='/conceptschemes/{scheme_id}/tree', accept='text/html') config.add_route('scheme_tree', pattern='/conceptschemes/{scheme_id}/tree', accept='application/json') - config.add_route('search_result_export', pattern='/conceptschemes/{scheme_id}/c.csv') - config.add_route('atramhasis.edit_conceptscheme', pattern='/conceptschemes/{scheme_id}', - accept='application/json', request_method='PUT') - config.add_route('atramhasis.get_conceptscheme', pattern='/conceptschemes/{scheme_id}', accept='application/json') - config.add_route('atramhasis.get_conceptschemes', pattern='/conceptschemes', accept='application/json') - config.add_route('atramhasis.get_concept', pattern='/conceptschemes/{scheme_id}/c/{c_id:.*}', - accept='application/json', request_method="GET") - config.add_route('atramhasis.add_concept', pattern='/conceptschemes/{scheme_id}/c', accept='application/json', - request_method="POST") - config.add_route('atramhasis.edit_concept', pattern='/conceptschemes/{scheme_id}/c/{c_id:.*}', - accept='application/json', request_method="PUT") - config.add_route('atramhasis.delete_concept', pattern='/conceptschemes/{scheme_id}/c/{c_id:.*}', - accept='application/json', request_method="DELETE") + # language config.add_route('atramhasis.list_languages', pattern='/languages', accept='application/json', request_method="GET") config.add_route('atramhasis.get_language', pattern='/languages/{l_id}', accept='application/json', @@ -68,33 +52,16 @@ def includeme(config): config.add_route('atramhasis.delete_language', pattern='/languages/{l_id}', accept='application/json', request_method="DELETE") config.add_route('locale', '/locale') - config.add_route('labeltypes', '/labeltypes', accept='application/json', request_method="GET") - config.add_route('notetypes', '/notetypes', accept='application/json', request_method="GET") + # admin config.add_route('admin', '/admin') config.add_route('scheme_tree_invalidate', pattern='/admin/tree/invalidate/{scheme_id}', accept='application/json') config.add_route('tree_invalidate', pattern='/admin/tree/invalidate', accept='application/json') - config.add_route('atramhasis.rdf_full_export_turtle', pattern='/conceptschemes/{scheme_id}/c', accept='text/turtle') - config.add_route('atramhasis.rdf_full_export_turtle_x', pattern='/conceptschemes/{scheme_id}/c', - accept='application/x-turtle') - config.add_route('atramhasis.rdf_full_export', pattern='/conceptschemes/{scheme_id}/c', - accept='application/rdf+xml') - config.add_route('atramhasis.rdf_conceptscheme_export', pattern='/conceptschemes/{scheme_id}', - accept='application/rdf+xml') - config.add_route('atramhasis.rdf_conceptscheme_export_turtle', pattern='/conceptschemes/{scheme_id}', - accept='text/turtle') - config.add_route('atramhasis.rdf_conceptscheme_export_turtle_x', pattern='/conceptschemes/{scheme_id}', - accept='application/x-turtle') - config.add_route('atramhasis.rdf_individual_export', pattern='/conceptschemes/{scheme_id}/c/{c_id:.*}', - accept='application/rdf+xml') - config.add_route('atramhasis.rdf_individual_export_turtle', pattern='/conceptschemes/{scheme_id}/c/{c_id:.*}', - accept='text/turtle') - config.add_route('atramhasis.rdf_individual_export_turtle_x', pattern='/conceptschemes/{scheme_id}/c/{c_id:.*}', - accept='application/x-turtle') - config.add_route('atramhasis.rdf_conceptscheme_jsonld', pattern='/conceptschemes/{scheme_id}', - accept='application/ld+json') - config.add_route('atramhasis.rdf_individual_jsonld', pattern='/conceptschemes/{scheme_id}/c/{c_id:.*}', - accept='application/ld+json') + # providers config.add_route('atramhasis.providers', pattern='/providers') config.add_route('atramhasis.provider', pattern='/providers/{id}') + + # other + config.add_route('labeltypes', '/labeltypes', accept='application/json', request_method="GET") + config.add_route('notetypes', '/notetypes', accept='application/json', request_method="GET") diff --git a/atramhasis/static/admin/package-lock.json b/atramhasis/static/admin/package-lock.json index d53b031c..fc2ab86a 100644 --- a/atramhasis/static/admin/package-lock.json +++ b/atramhasis/static/admin/package-lock.json @@ -1,12 +1,12 @@ { "name": "atramhasis", - "version": "2.1.0", + "version": "2.1.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "atramhasis", - "version": "2.1.0", + "version": "2.1.1", "dependencies": { "dgrid": "~1.2.1", "dGrowl": "https://github.com/stratease/dGrowl#0.1.3", diff --git a/atramhasis/static/admin/package.json b/atramhasis/static/admin/package.json index 2ec1da6f..4913e87a 100644 --- a/atramhasis/static/admin/package.json +++ b/atramhasis/static/admin/package.json @@ -1,6 +1,6 @@ { "name": "atramhasis", - "version": "2.1.0", + "version": "2.1.1", "description": "Node packages for building Atramhasis.", "repository": { "type": "git", diff --git a/atramhasis/static/admin/src/app/ui/dialogs/ManageProvidersDialog.js b/atramhasis/static/admin/src/app/ui/dialogs/ManageProvidersDialog.js index ad1c2945..1993f8ce 100644 --- a/atramhasis/static/admin/src/app/ui/dialogs/ManageProvidersDialog.js +++ b/atramhasis/static/admin/src/app/ui/dialogs/ManageProvidersDialog.js @@ -349,8 +349,18 @@ define([ 'sticky': false, 'channel': 'info' }); - this._reset(true); - this.parentNode.refresh_conceptschemes(); + // Update the provider lists with the new data + this.providerController.loadProviders().then(lang.hitch(this, function() { + this._reset(true); + this.parentNode.refresh_conceptschemes(); + }), lang.hitch(this, function (error) { + var message = this._parseError(error); + topic.publish('dGrowl', message, { + 'title': 'Error updating provider list', + 'sticky': true, + 'channel': 'error' + }); + })); }), lang.hitch(this, function (error) { var message = this._parseError(error); @@ -372,7 +382,17 @@ define([ 'sticky': false, 'channel': 'info' }); - this._reset(); + // Update the provider lists with the updated data + this.providerController.loadProviders().then(lang.hitch(this, function() { + this._reset(); + }), lang.hitch(this, function (error) { + var message = this._parseError(error); + topic.publish('dGrowl', message, { + 'title': 'Error updating provider list', + 'sticky': true, + 'channel': 'error' + }); + })); }), lang.hitch(this, function (error) { var message = this._parseError(error); diff --git a/atramhasis/static/package-lock.json b/atramhasis/static/package-lock.json index 835a6c60..655ebb1e 100644 --- a/atramhasis/static/package-lock.json +++ b/atramhasis/static/package-lock.json @@ -1,12 +1,12 @@ { "name": "atramhasis", - "version": "2.1.0", + "version": "2.1.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "atramhasis", - "version": "2.1.0", + "version": "2.1.1", "dependencies": { "d3": "~3.5.17", "font-awesome": "~4.7.0", diff --git a/atramhasis/static/package.json b/atramhasis/static/package.json index da9683a4..2f2cad79 100644 --- a/atramhasis/static/package.json +++ b/atramhasis/static/package.json @@ -1,6 +1,6 @@ { "name": "atramhasis", - "version": "2.1.0", + "version": "2.1.1", "description": "Node packages for public part of Atramhasis.", "repository": { "type": "git", diff --git a/atramhasis/templates/concept.jinja2 b/atramhasis/templates/concept.jinja2 index eac6df5e..53db291d 100644 --- a/atramhasis/templates/concept.jinja2 +++ b/atramhasis/templates/concept.jinja2 @@ -2,7 +2,7 @@ {% block head %} {{ super() }} - + {% if concept.notes|length > 0 %} @@ -13,7 +13,7 @@ {% if concept.notes|length > 0 %} {% endif %} - + {% endblock %} {% block html_title %}{{ concept.label(locale).label|title }}{% endblock %} @@ -31,9 +31,9 @@
{% if concept %} @@ -53,7 +53,7 @@
{{ concept.uri }}
{% endif %}
schema
-
{{ get_conceptscheme_label(concept.conceptscheme, request.locale_name) }}
+
{{ get_conceptscheme_label(concept.conceptscheme, request.locale_name) }}
{% if concept.labels %} {{ print_labels(concept.labels) }} {% endif %} diff --git a/atramhasis/templates/conceptscheme.jinja2 b/atramhasis/templates/conceptscheme.jinja2 index 27625ab5..f0591c06 100644 --- a/atramhasis/templates/conceptscheme.jinja2 +++ b/atramhasis/templates/conceptscheme.jinja2 @@ -2,7 +2,7 @@ {% block head %} {{ super() }} - + {% if conceptscheme.notes|length > 0 %} @@ -13,7 +13,7 @@ {% if conceptscheme.notes|length > 0 %} {% endif %} - + {% endblock %} {% block html_title %}{{ conceptscheme.title }}{% endblock %} @@ -29,11 +29,11 @@
diff --git a/atramhasis/templates/conceptschemes.jinja2 b/atramhasis/templates/conceptschemes.jinja2 index 493de4db..b1626b39 100644 --- a/atramhasis/templates/conceptschemes.jinja2 +++ b/atramhasis/templates/conceptschemes.jinja2 @@ -12,7 +12,7 @@

{% trans %}select_scheme{% endtrans %}

{% for item in conceptschemes %} -
{{ get_conceptscheme_label(item.conceptscheme, request.locale_name) }}
[ ID : {{ item.id }} ]
{{ item.type }}
+
{{ get_conceptscheme_label(item.conceptscheme, request.locale_name) }}
[ ID : {{ item.id }} ]
{{ item.type }}
{% endfor %}
diff --git a/atramhasis/templates/conceptschemes_overview.jinja2 b/atramhasis/templates/conceptschemes_overview.jinja2 index 7da99264..481f701c 100644 --- a/atramhasis/templates/conceptschemes_overview.jinja2 +++ b/atramhasis/templates/conceptschemes_overview.jinja2 @@ -6,7 +6,7 @@
{% for item in conceptschemes %} - + {% endfor %}
\ No newline at end of file diff --git a/atramhasis/templates/header-page.jinja2 b/atramhasis/templates/header-page.jinja2 index f0fefa0e..e3b6436e 100644 --- a/atramhasis/templates/header-page.jinja2 +++ b/atramhasis/templates/header-page.jinja2 @@ -22,7 +22,7 @@ {% for item in conceptschemes %} - {% endfor %} diff --git a/atramhasis/templates/search_result.jinja2 b/atramhasis/templates/search_result.jinja2 index 39d9b58e..bcd1ec81 100644 --- a/atramhasis/templates/search_result.jinja2 +++ b/atramhasis/templates/search_result.jinja2 @@ -15,7 +15,7 @@ {%- for c in concepts %} -
{{ c.label }}
[ ID : {{ c.id }} ]
{{ c.type }}
+
{{ c.label }}
[ ID : {{ c.id }} ]
{{ c.type }}
{%- endfor %} diff --git a/atramhasis/templates/subfooter-page.jinja2 b/atramhasis/templates/subfooter-page.jinja2 index 81393169..2705abd5 100644 --- a/atramhasis/templates/subfooter-page.jinja2 +++ b/atramhasis/templates/subfooter-page.jinja2 @@ -22,7 +22,7 @@
{% trans %}select_scheme{% endtrans %}
diff --git a/atramhasis/templates/tree.jinja2 b/atramhasis/templates/tree.jinja2 index c9a1a9b5..0ac83d76 100644 --- a/atramhasis/templates/tree.jinja2 +++ b/atramhasis/templates/tree.jinja2 @@ -213,7 +213,7 @@ function openConcept(d) { d3.event.preventDefault(); if (d.concept_id) { - var basepath = '{{ request.route_path('concept', scheme_id= scheme_id, c_id = '') }}'; + var basepath = '{{ request.route_path('skosprovider.c', scheme_id= scheme_id, c_id = '') }}'; window.location.href = basepath + d.concept_id +'?view_tree'; } else { diff --git a/atramhasis/views/crud.py b/atramhasis/views/crud.py index 94eab295..cee2b94e 100644 --- a/atramhasis/views/crud.py +++ b/atramhasis/views/crud.py @@ -104,14 +104,12 @@ def _validate_conceptscheme(self, json_conceptscheme): ) @audit - @view_config(route_name='atramhasis.get_conceptscheme', permission='view') + @view_config(route_name='skosprovider.conceptscheme', permission='view', request_method='GET') def get_conceptscheme(self): - if self.request.method == 'DELETE': - raise HTTPMethodNotAllowed - # is the same as the pyramid_skosprovider get_conceptscheme function, but wrapped with the audit function + # is the same as pyramid_skosprovider but wrapped with the audit decorator return ProviderView(self.request).get_conceptscheme() - @view_config(route_name='atramhasis.edit_conceptscheme', permission='edit') + @view_config(route_name='skosprovider.conceptscheme', permission='edit', request_method='PUT') def edit_conceptscheme(self): """ Edit an existing concept @@ -125,16 +123,8 @@ def edit_conceptscheme(self): self.request.response.status = '200' return conceptscheme - @view_config(route_name='atramhasis.get_conceptschemes', permission='view') - def get_conceptschemes(self): - if self.request.method == 'POST': - raise HTTPMethodNotAllowed - # is the same as the pyramid_skosprovider get_conceptscheme function, method not allowed included - from pyramid_skosprovider.views import ProviderView - return ProviderView(self.request).get_conceptschemes() - @audit - @view_config(route_name='atramhasis.get_concept', permission='view') + @view_config(route_name='skosprovider.c', permission='view', request_method='GET') def get_concept(self): """ Get an existing concept @@ -156,7 +146,7 @@ def get_concept(self): return concept @internal_providers_only - @view_config(route_name='atramhasis.add_concept', permission='edit') + @view_config(route_name='skosprovider.conceptscheme.cs', permission='edit', request_method='POST') def add_concept(self): """ Add a new concept to a conceptscheme @@ -217,7 +207,7 @@ def add_concept(self): return from_thing(concept) @internal_providers_only - @view_config(route_name='atramhasis.edit_concept', permission='edit') + @view_config(route_name='skosprovider.c', permission='edit', request_method='PUT') def edit_concept(self): """ Edit an existing concept @@ -242,7 +232,7 @@ def edit_concept(self): @internal_providers_only @protected_operation - @view_config(route_name='atramhasis.delete_concept', permission='delete') + @view_config(route_name='skosprovider.c', permission='delete', request_method='DELETE') def delete_concept(self): """ Delete an existing concept diff --git a/atramhasis/views/rdf.py b/atramhasis/views/rdf.py index f68b6d14..826e9429 100644 --- a/atramhasis/views/rdf.py +++ b/atramhasis/views/rdf.py @@ -53,8 +53,8 @@ def __init__(self, request): raise ConceptNotFoundException(self.c_id) @audit - @view_config(route_name='atramhasis.rdf_full_export') - @view_config(route_name='atramhasis.rdf_full_export_ext') + @view_config(route_name='skosprovider.conceptscheme.cs', accept='application/rdf+xml') + @view_config(route_name='skosprovider.conceptscheme.cs.rdf') def rdf_full_export(self): dump_location = self.request.registry.settings['atramhasis.dump_location'] filename = os.path.join(dump_location, '%s-full.rdf' % self.scheme_id) @@ -66,9 +66,9 @@ def rdf_full_export(self): ) @audit - @view_config(route_name='atramhasis.rdf_full_export_turtle') - @view_config(route_name='atramhasis.rdf_full_export_turtle_x') - @view_config(route_name='atramhasis.rdf_full_export_turtle_ext') + @view_config(route_name='skosprovider.conceptscheme.cs', accept='text/turtle') + @view_config(route_name='skosprovider.conceptscheme.cs', accept='application/x-turtle') + @view_config(route_name='skosprovider.conceptscheme.cs.ttl') def rdf_full_export_turtle(self): dump_location = self.request.registry.settings['atramhasis.dump_location'] filename = os.path.join(dump_location, '%s-full.ttl' % self.scheme_id) @@ -80,8 +80,8 @@ def rdf_full_export_turtle(self): ) @audit - @view_config(route_name='atramhasis.rdf_conceptscheme_export') - @view_config(route_name='atramhasis.rdf_conceptscheme_export_ext') + @view_config(route_name='skosprovider.conceptscheme', accept='application/rdf+xml') + @view_config(route_name='skosprovider.conceptscheme.rdf') def rdf_conceptscheme_export(self): graph = utils.rdf_conceptscheme_dumper(self.provider) response = Response(content_type='application/rdf+xml') @@ -89,9 +89,9 @@ def rdf_conceptscheme_export(self): response.content_disposition = 'attachment; filename="{}.rdf"'.format(str(self.scheme_id)) return response - @view_config(route_name='atramhasis.rdf_conceptscheme_export_turtle') - @view_config(route_name='atramhasis.rdf_conceptscheme_export_turtle_x') - @view_config(route_name='atramhasis.rdf_conceptscheme_export_turtle_ext') + @view_config(route_name='skosprovider.conceptscheme', accept='text/turtle') + @view_config(route_name='skosprovider.conceptscheme', accept='application/x-turtle') + @view_config(route_name='skosprovider.conceptscheme.ttl') def rdf_conceptscheme_export_turtle(self): graph = utils.rdf_conceptscheme_dumper(self.provider) response = Response(content_type='text/turtle') @@ -100,8 +100,8 @@ def rdf_conceptscheme_export_turtle(self): return response @audit - @view_config(route_name='atramhasis.rdf_individual_export') - @view_config(route_name='atramhasis.rdf_individual_export_ext') + @view_config(route_name='skosprovider.c', accept='application/rdf+xml') + @view_config(route_name='skosprovider.c.rdf') def rdf_individual_export(self): graph = utils.rdf_c_dumper(self.provider, self.c_id) response = Response(content_type='application/rdf+xml') @@ -110,9 +110,9 @@ def rdf_individual_export(self): return response @audit - @view_config(route_name='atramhasis.rdf_individual_export_turtle') - @view_config(route_name='atramhasis.rdf_individual_export_turtle_x') - @view_config(route_name='atramhasis.rdf_individual_export_turtle_ext') + @view_config(route_name='skosprovider.c', accept='text/turtle') + @view_config(route_name='skosprovider.c', accept='application/x-turtle') + @view_config(route_name='skosprovider.c.ttl') def rdf_individual_export_turtle(self): graph = utils.rdf_c_dumper(self.provider, self.c_id) response = Response(content_type='text/turtle') @@ -121,8 +121,8 @@ def rdf_individual_export_turtle(self): return response @audit - @view_config(route_name='atramhasis.rdf_conceptscheme_jsonld', permission='view') - @view_config(route_name='atramhasis.rdf_conceptscheme_jsonld_ext', permission='view') + @view_config(route_name='skosprovider.conceptscheme', permission='view', accept='application/ld+json') + @view_config(route_name='skosprovider.conceptscheme.jsonld', permission='view') def get_conceptscheme_jsonld(self): conceptscheme = ProviderView(self.request).get_conceptscheme_jsonld() response = Response(content_type='application/ld+json') @@ -131,8 +131,8 @@ def get_conceptscheme_jsonld(self): return response @audit - @view_config(route_name='atramhasis.rdf_individual_jsonld', permission='view') - @view_config(route_name='atramhasis.rdf_individual_jsonld_ext', permission='view') + @view_config(route_name='skosprovider.c', permission='view', accept='application/ld+json') + @view_config(route_name='skosprovider.c.jsonld', permission='view') def get_concept(self): concept = ProviderView(self.request).get_concept() response = Response(content_type='application/ld+json') diff --git a/atramhasis/views/views.py b/atramhasis/views/views.py index 7ab2d789..1d0f30ee 100644 --- a/atramhasis/views/views.py +++ b/atramhasis/views/views.py @@ -57,7 +57,8 @@ def get_public_conceptschemes(skos_registry): return conceptschemes -@view_defaults(accept='text/html') + +@view_defaults(accept='text/html', request_method='GET') class AtramhasisView: """ This object groups HTML views part of the public user interface. @@ -102,7 +103,7 @@ def home_view(self): """ return {'conceptschemes': get_public_conceptschemes(self.skos_registry)} - @view_config(route_name='conceptschemes', renderer='atramhasis:templates/conceptschemes.jinja2') + @view_config(route_name='skosprovider.conceptschemes', renderer='atramhasis:templates/conceptschemes.jinja2') def conceptschemes_view(self): """ Display a list of available conceptschemes. @@ -110,7 +111,7 @@ def conceptschemes_view(self): return {'conceptschemes': get_public_conceptschemes(self.skos_registry)} @audit - @view_config(route_name='conceptscheme', renderer='atramhasis:templates/conceptscheme.jinja2') + @view_config(route_name='skosprovider.conceptscheme', renderer='atramhasis:templates/conceptscheme.jinja2') def conceptscheme_view(self): """ Display a single conceptscheme. @@ -141,7 +142,7 @@ def conceptscheme_view(self): 'locale': locale} @audit - @view_config(route_name='concept', renderer='atramhasis:templates/concept.jinja2') + @view_config(route_name='skosprovider.c', renderer='atramhasis:templates/concept.jinja2') def concept_view(self): """ Display all about a single concept or collection. @@ -173,7 +174,7 @@ def concept_view(self): concept_type = "Collection" else: return Response('Thing without type: ' + str(c_id), status_int=500) - url = self.request.route_url('concept', scheme_id=scheme_id, c_id=c_id) + url = self.request.route_url('skosprovider.c', scheme_id=scheme_id, c_id=c_id) update_last_visited_concepts(self.request, {'label': c.label(locale).label, 'url': url}) return {'concept': c, 'conceptType': concept_type, 'scheme_id': scheme_id, 'conceptschemes': conceptschemes, 'provider': provider, @@ -181,7 +182,7 @@ def concept_view(self): except NoResultFound: raise ConceptNotFoundException(c_id) - @view_config(route_name='search_result', renderer='atramhasis:templates/search_result.jinja2') + @view_config(route_name='skosprovider.conceptscheme.cs', renderer='atramhasis:templates/search_result.jinja2') def search_result(self): """ Display search results @@ -248,7 +249,7 @@ def set_locale_cookie(self): return response @audit - @view_config(route_name='search_result_export', renderer='csv') + @view_config(route_name='skosprovider.conceptscheme.csv', renderer='csv') def results_csv(self): """ Download search results in CSV format, allowing further processing. @@ -353,11 +354,6 @@ def create_treeid(parent_tree_id, concept_id): else: return parent_tree_id + "|" + urllib.parse.quote(str(concept_id), safe="") - @view_config(route_name='scheme_root', renderer='atramhasis:templates/concept.jinja2') - def results_tree_html(self): - scheme_id = self.request.matchdict['scheme_id'] - return {'concept': None, 'conceptType': None, 'scheme_id': scheme_id} - @view_defaults(accept='application/json', renderer='json') class AtramhasisListView: diff --git a/docs/source/conf.py b/docs/source/conf.py index d9719bc0..90bf6bed 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -58,7 +58,7 @@ # The short X.Y version. version = '2.1' # The full version, including alpha/beta/rc tags. -release = '2.1.0' +release = '2.1.1' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/docs/source/customisation.rst b/docs/source/customisation.rst index dcb1a131..380bd030 100644 --- a/docs/source/customisation.rst +++ b/docs/source/customisation.rst @@ -1053,14 +1053,18 @@ expanded and edited. SessionFactory ============== -You can change the default session factory in the __init__.py file. +If you don't provide a session factory in your Pyramid application, Atramhasis will use its default session factory, +which is a SignedCookieSessionFactory. -.. code-block:: python +You can change the default session factory in the __init__.py file within the load_app function. To do this, +ensure you pass the settings variable to the load_app function from within the main() function. - # set default session factory - from pyramid.session import SignedCookieSessionFactory - atramhasis_session_factory = SignedCookieSessionFactory(settings['atramhasis.session_factory.secret']) - config.set_session_factory(atramhasis_session_factory) +.. code-block:: python + def load_app(config, settings): + # Override default session factory + from pyramid.session import SignedCookieSessionFactory + atramhasis_session_factory = SignedCookieSessionFactory(settings['atramhasis.session_factory.secret']) + config.set_session_factory(atramhasis_session_factory) .. _upgrading_providers: diff --git a/pyproject.toml b/pyproject.toml index 0c00bc77..059181bd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -3,7 +3,7 @@ requires = ["hatchling", "hatch-fancy-pypi-readme"] build-backend = "hatchling.build" [project] -version = "2.1.0" +version = "2.1.1" name = "atramhasis" dynamic = ["readme"] authors = [ @@ -33,7 +33,7 @@ dependencies = [ "skosprovider_sqlalchemy>=2.1.1", "skosprovider_rdf", "skosprovider_getty", - "pyramid_skosprovider", + "pyramid_skosprovider>=1.2.2", "language_tags", "jinja2 >= 3.0.0", "markupsafe", diff --git a/requirements-dev.txt b/requirements-dev.txt index f915485d..442684e2 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -175,7 +175,7 @@ pyramid-openapi3==0.19 # via atramhasis (pyproject.toml) pyramid-rewrite==0.2 # via atramhasis (pyproject.toml) -pyramid-skosprovider==1.2.1 +pyramid-skosprovider==1.2.2 # via atramhasis (pyproject.toml) pyramid-tm==2.5 # via atramhasis (pyproject.toml) diff --git a/requirements.txt b/requirements.txt index 7e768c63..40e9e22d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -120,7 +120,7 @@ pyramid-openapi3==0.19 # via atramhasis (pyproject.toml) pyramid-rewrite==0.2 # via atramhasis (pyproject.toml) -pyramid-skosprovider==1.2.1 +pyramid-skosprovider==1.2.2 # via atramhasis (pyproject.toml) pyramid-tm==2.5 # via atramhasis (pyproject.toml) diff --git a/tests/test_datamanagers.py b/tests/test_datamanagers.py index b06d57b2..ec70fc17 100644 --- a/tests/test_datamanagers.py +++ b/tests/test_datamanagers.py @@ -178,36 +178,34 @@ def test_get_first_day(self): @patch('atramhasis.data.datamanagers.date', Mock(today=Mock(return_value=date(2015, 9, 15)))) def test_get_most_popular_concepts_for_conceptscheme(self): self.session.add( - ConceptVisitLog(concept_id=1, conceptscheme_id='1', origin='REST', + ConceptVisitLog(concept_id='1', conceptscheme_id='1', origin='REST', visited_at=datetime(2015, 8, 27, 10, 58, 3)) ) self.session.add( - ConceptVisitLog(concept_id=1, conceptscheme_id='1', origin='REST', + ConceptVisitLog(concept_id='1', conceptscheme_id='1', origin='REST', visited_at=datetime(2015, 8, 27, 11, 58, 3)) ) self.session.add( - ConceptVisitLog(concept_id=2, conceptscheme_id='1', origin='REST', + ConceptVisitLog(concept_id='2', conceptscheme_id='1', origin='REST', visited_at=datetime(2015, 8, 27, 10, 58, 3)) ) self.session.add( - ConceptVisitLog(concept_id=2, conceptscheme_id='2', origin='REST', + ConceptVisitLog(concept_id='2', conceptscheme_id='2', origin='REST', visited_at=datetime(2015, 8, 27, 10, 58, 3)) ) - self.assertListEqual( - [ - {'concept_id': 1, 'scheme_id': 1}, - {'concept_id': 2, 'scheme_id': 1} - ], - self.audit_manager.get_most_popular_concepts_for_conceptscheme( - 1, 5, 'last_month' - ) - ) - self.assertListEqual([{'concept_id': 2, 'scheme_id': 2}], - self.audit_manager.get_most_popular_concepts_for_conceptscheme(2, 5, 'last_month')) - self.assertListEqual([{'concept_id': 1, 'scheme_id': 1}], - self.audit_manager.get_most_popular_concepts_for_conceptscheme(1, 1, 'last_month')) - self.assertListEqual([], - self.audit_manager.get_most_popular_concepts_for_conceptscheme(1, 5, 'last_day')) + + manager = self.audit_manager + result = manager.get_most_popular_concepts_for_conceptscheme(1, 5, 'last_month') + expected = [ + {'concept_id': '1', 'scheme_id': 1}, {'concept_id': '2', 'scheme_id': 1} + ] + self.assertListEqual(expected, result) + result = manager.get_most_popular_concepts_for_conceptscheme(2, 5, 'last_month') + self.assertListEqual([{'concept_id': '2', 'scheme_id': 2}], result) + result = manager.get_most_popular_concepts_for_conceptscheme(1, 1, 'last_month') + self.assertListEqual([{'concept_id': '1', 'scheme_id': 1}], result) + result = manager.get_most_popular_concepts_for_conceptscheme(1, 5, 'last_day') + self.assertListEqual([], result) class CountsManagerTest(DbTest): diff --git a/tests/test_functional.py b/tests/test_functional.py index 5ea779c5..4258f442 100644 --- a/tests/test_functional.py +++ b/tests/test_functional.py @@ -380,9 +380,6 @@ def test_delete_concept(self): self.assertEqual('200 OK', res.status) self.assertIsNotNone(res.json['id']) self.assertEqual(new_id, res.json['id']) - from skosprovider_sqlalchemy.models import Concept - concepten = self.session.query(Concept).all() - print() def test_delete_concept_not_found(self): res = self.testapp.delete('/conceptschemes/TREES/c/7895', @@ -572,12 +569,6 @@ def mock_event_handler(event): "referenced_in": ["urn:someobject", "http://test.test.org/object/2"] }) - def test_method_not_allowed(self): - self.testapp.delete('/conceptschemes/TREES', headers=self._get_default_headers(), - status=405) - self.testapp.post('/conceptschemes', headers=self._get_default_headers(), - status=405) - def test_get_conceptschemes(self): self.testapp.get('/conceptschemes', headers=self._get_default_headers(), status=200) @@ -836,6 +827,13 @@ def test_get_provider(self): response.json ) + def test_expand_concept(self): + res = self.testapp.get( + '/conceptschemes/TREES/c/1/expand', headers=self._get_default_headers(), + status=200, + ) + self.assertEqual(res.json, ['1']) + class TestCookieView(FunctionalTests): def _get_default_headers(self): diff --git a/tests/test_views.py b/tests/test_views.py index 5d79157b..45dd9dc6 100644 --- a/tests/test_views.py +++ b/tests/test_views.py @@ -249,7 +249,7 @@ class TestConceptView(unittest.TestCase): def setUp(self): self.config = testing.setUp() self.config.add_route( - "concept", + "skosprovider.c", pattern="/conceptschemes/{scheme_id}/c/{c_id}", accept="text/html", request_method="GET", @@ -532,15 +532,6 @@ def setUp(self): def tearDown(self): testing.tearDown() - def test_passing_view(self): - self.request.skos_registry = self.regis - self.request.matchdict["scheme_id"] = "TREES" - atramhasisview = AtramhasisView(self.request) - response = atramhasisview.results_tree_html() - self.assertEqual(response["conceptType"], None) - self.assertEqual(response["concept"], None) - self.assertEqual(response["scheme_id"], "TREES") - class TestAdminView(unittest.TestCase): def setUp(self):