ckanext-actor-registry 0.3.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (124) hide show
  1. ckanext_actor_registry-0.3.0/AI_ASSISTANCE.md +19 -0
  2. ckanext_actor_registry-0.3.0/CHANGELOG.md +341 -0
  3. ckanext_actor_registry-0.3.0/CODE_OF_CONDUCT.md +16 -0
  4. ckanext_actor_registry-0.3.0/CONTRIBUTING.md +76 -0
  5. ckanext_actor_registry-0.3.0/LICENSE +21 -0
  6. ckanext_actor_registry-0.3.0/MANIFEST.in +9 -0
  7. ckanext_actor_registry-0.3.0/PKG-INFO +624 -0
  8. ckanext_actor_registry-0.3.0/README.md +603 -0
  9. ckanext_actor_registry-0.3.0/SECURITY.md +19 -0
  10. ckanext_actor_registry-0.3.0/ckanext/actor_registry/__init__.py +1 -0
  11. ckanext_actor_registry-0.3.0/ckanext/actor_registry/actions.py +278 -0
  12. ckanext_actor_registry-0.3.0/ckanext/actor_registry/assets/js/actor-merge-select.js +37 -0
  13. ckanext_actor_registry-0.3.0/ckanext/actor_registry/assets/js/actor-quick-create.js +196 -0
  14. ckanext_actor_registry-0.3.0/ckanext/actor_registry/assets/js/quick-create.js +213 -0
  15. ckanext_actor_registry-0.3.0/ckanext/actor_registry/assets/webassets.yml +21 -0
  16. ckanext_actor_registry-0.3.0/ckanext/actor_registry/auth.py +31 -0
  17. ckanext_actor_registry-0.3.0/ckanext/actor_registry/cleanup.py +138 -0
  18. ckanext_actor_registry-0.3.0/ckanext/actor_registry/config_declaration.yaml +14 -0
  19. ckanext_actor_registry-0.3.0/ckanext/actor_registry/contact_migration.py +534 -0
  20. ckanext_actor_registry-0.3.0/ckanext/actor_registry/examples/__init__.py +0 -0
  21. ckanext_actor_registry-0.3.0/ckanext/actor_registry/examples/actor_registry_migration_schema.yaml +91 -0
  22. ckanext_actor_registry-0.3.0/ckanext/actor_registry/examples/actor_registry_schema.yaml +70 -0
  23. ckanext_actor_registry-0.3.0/ckanext/actor_registry/examples/contact_points_only_schema.yaml +61 -0
  24. ckanext_actor_registry-0.3.0/ckanext/actor_registry/helpers.py +170 -0
  25. ckanext_actor_registry-0.3.0/ckanext/actor_registry/i18n/ckanext-actor-registry.pot +1620 -0
  26. ckanext_actor_registry-0.3.0/ckanext/actor_registry/i18n/sv/LC_MESSAGES/ckanext-actor-registry.mo +0 -0
  27. ckanext_actor_registry-0.3.0/ckanext/actor_registry/i18n/sv/LC_MESSAGES/ckanext-actor-registry.po +1787 -0
  28. ckanext_actor_registry-0.3.0/ckanext/actor_registry/i18n/sv_SE/LC_MESSAGES/ckanext-actor-registry.mo +0 -0
  29. ckanext_actor_registry-0.3.0/ckanext/actor_registry/i18n/sv_SE/LC_MESSAGES/ckanext-actor-registry.po +1787 -0
  30. ckanext_actor_registry-0.3.0/ckanext/actor_registry/migration/__init__.py +1 -0
  31. ckanext_actor_registry-0.3.0/ckanext/actor_registry/migration/actor_registry/__init__.py +1 -0
  32. ckanext_actor_registry-0.3.0/ckanext/actor_registry/migration/actor_registry/alembic.ini +30 -0
  33. ckanext_actor_registry-0.3.0/ckanext/actor_registry/migration/actor_registry/env.py +46 -0
  34. ckanext_actor_registry-0.3.0/ckanext/actor_registry/migration/actor_registry/script.py.mako +22 -0
  35. ckanext_actor_registry-0.3.0/ckanext/actor_registry/migration/actor_registry/versions/001_create_contact_points.py +35 -0
  36. ckanext_actor_registry-0.3.0/ckanext/actor_registry/migration/actor_registry/versions/002_create_actor_registry.py +47 -0
  37. ckanext_actor_registry-0.3.0/ckanext/actor_registry/migration/actor_registry/versions/003_user_publisher_preference.py +32 -0
  38. ckanext_actor_registry-0.3.0/ckanext/actor_registry/migration/actor_registry/versions/004_recent_contact_points.py +40 -0
  39. ckanext_actor_registry-0.3.0/ckanext/actor_registry/migration/actor_registry/versions/005_actor_merged_into.py +42 -0
  40. ckanext_actor_registry-0.3.0/ckanext/actor_registry/migration/actor_registry/versions/006_unique_actor_identifier.py +36 -0
  41. ckanext_actor_registry-0.3.0/ckanext/actor_registry/migration/actor_registry/versions/007_migration_decision.py +45 -0
  42. ckanext_actor_registry-0.3.0/ckanext/actor_registry/migration/actor_registry/versions/008_migration_decision_values.py +26 -0
  43. ckanext_actor_registry-0.3.0/ckanext/actor_registry/migration/actor_registry/versions/__init__.py +1 -0
  44. ckanext_actor_registry-0.3.0/ckanext/actor_registry/model.py +518 -0
  45. ckanext_actor_registry-0.3.0/ckanext/actor_registry/plugin.py +121 -0
  46. ckanext_actor_registry-0.3.0/ckanext/actor_registry/profiles.py +171 -0
  47. ckanext_actor_registry-0.3.0/ckanext/actor_registry/rdf.py +12 -0
  48. ckanext_actor_registry-0.3.0/ckanext/actor_registry/templates/actor_registry/actor_delete_confirm.html +53 -0
  49. ckanext_actor_registry-0.3.0/ckanext/actor_registry/templates/actor_registry/actor_form.html +20 -0
  50. ckanext_actor_registry-0.3.0/ckanext/actor_registry/templates/actor_registry/actor_show.html +31 -0
  51. ckanext_actor_registry-0.3.0/ckanext/actor_registry/templates/actor_registry/actors_index.html +37 -0
  52. ckanext_actor_registry-0.3.0/ckanext/actor_registry/templates/actor_registry/actors_merge.html +45 -0
  53. ckanext_actor_registry-0.3.0/ckanext/actor_registry/templates/actor_registry/cleanup.html +90 -0
  54. ckanext_actor_registry-0.3.0/ckanext/actor_registry/templates/actor_registry/contactpoint_delete_confirm.html +38 -0
  55. ckanext_actor_registry-0.3.0/ckanext/actor_registry/templates/actor_registry/contactpoint_form.html +19 -0
  56. ckanext_actor_registry-0.3.0/ckanext/actor_registry/templates/actor_registry/contactpoint_show.html +18 -0
  57. ckanext_actor_registry-0.3.0/ckanext/actor_registry/templates/actor_registry/contactpoints_index.html +31 -0
  58. ckanext_actor_registry-0.3.0/ckanext/actor_registry/templates/actor_registry/linked_datasets.html +34 -0
  59. ckanext_actor_registry-0.3.0/ckanext/actor_registry/templates/actor_registry/migrate.html +277 -0
  60. ckanext_actor_registry-0.3.0/ckanext/actor_registry/templates/actor_registry/snippets/dataset_actor_link_prompt.html +37 -0
  61. ckanext_actor_registry-0.3.0/ckanext/actor_registry/templates/actor_registry/snippets/dataset_list.html +23 -0
  62. ckanext_actor_registry-0.3.0/ckanext/actor_registry/templates/actor_registry/snippets/help_texts.html +31 -0
  63. ckanext_actor_registry-0.3.0/ckanext/actor_registry/templates/actor_registry/snippets/row_actions.html +12 -0
  64. ckanext_actor_registry-0.3.0/ckanext/actor_registry/templates/admin/base.html +35 -0
  65. ckanext_actor_registry-0.3.0/ckanext/actor_registry/templates/scheming/display_snippets/actor.html +15 -0
  66. ckanext_actor_registry-0.3.0/ckanext/actor_registry/templates/scheming/display_snippets/contactpoints.html +12 -0
  67. ckanext_actor_registry-0.3.0/ckanext/actor_registry/templates/scheming/display_snippets/legacy_contact.html +11 -0
  68. ckanext_actor_registry-0.3.0/ckanext/actor_registry/templates/scheming/form_snippets/actors_multiple_select.html +37 -0
  69. ckanext_actor_registry-0.3.0/ckanext/actor_registry/templates/scheming/form_snippets/contactpoints_multiple_select.html +93 -0
  70. ckanext_actor_registry-0.3.0/ckanext/actor_registry/templates/scheming/form_snippets/legacy_contact.html +12 -0
  71. ckanext_actor_registry-0.3.0/ckanext/actor_registry/templates/scheming/package/read.html +14 -0
  72. ckanext_actor_registry-0.3.0/ckanext/actor_registry/templates/scheming/package/snippets/additional_info.html +40 -0
  73. ckanext_actor_registry-0.3.0/ckanext/actor_registry/tests/__init__.py +0 -0
  74. ckanext_actor_registry-0.3.0/ckanext/actor_registry/tests/conftest.py +7 -0
  75. ckanext_actor_registry-0.3.0/ckanext/actor_registry/tests/fixtures/__init__.py +0 -0
  76. ckanext_actor_registry-0.3.0/ckanext/actor_registry/tests/fixtures/dcat_test_schema.yaml +33 -0
  77. ckanext_actor_registry-0.3.0/ckanext/actor_registry/tests/fixtures/form_schema.yaml +36 -0
  78. ckanext_actor_registry-0.3.0/ckanext/actor_registry/tests/fixtures/legacy_contact_schema.yaml +66 -0
  79. ckanext_actor_registry-0.3.0/ckanext/actor_registry/tests/test_actor_merge.py +245 -0
  80. ckanext_actor_registry-0.3.0/ckanext/actor_registry/tests/test_cleanup.py +292 -0
  81. ckanext_actor_registry-0.3.0/ckanext/actor_registry/tests/test_contact_migration.py +770 -0
  82. ckanext_actor_registry-0.3.0/ckanext/actor_registry/tests/test_contact_points_only_schema.py +92 -0
  83. ckanext_actor_registry-0.3.0/ckanext/actor_registry/tests/test_contactpoint_organization.py +128 -0
  84. ckanext_actor_registry-0.3.0/ckanext/actor_registry/tests/test_dataset_display.py +222 -0
  85. ckanext_actor_registry-0.3.0/ckanext/actor_registry/tests/test_example_schema.py +114 -0
  86. ckanext_actor_registry-0.3.0/ckanext/actor_registry/tests/test_field_validation.py +226 -0
  87. ckanext_actor_registry-0.3.0/ckanext/actor_registry/tests/test_help_texts_i18n.py +109 -0
  88. ckanext_actor_registry-0.3.0/ckanext/actor_registry/tests/test_i18n_extraction.py +143 -0
  89. ckanext_actor_registry-0.3.0/ckanext/actor_registry/tests/test_identifier_uniqueness.py +220 -0
  90. ckanext_actor_registry-0.3.0/ckanext/actor_registry/tests/test_input_limits.py +149 -0
  91. ckanext_actor_registry-0.3.0/ckanext/actor_registry/tests/test_integration_flows.py +185 -0
  92. ckanext_actor_registry-0.3.0/ckanext/actor_registry/tests/test_legacy_contact_fields.py +204 -0
  93. ckanext_actor_registry-0.3.0/ckanext/actor_registry/tests/test_linked_datasets.py +440 -0
  94. ckanext_actor_registry-0.3.0/ckanext/actor_registry/tests/test_migration_close.py +245 -0
  95. ckanext_actor_registry-0.3.0/ckanext/actor_registry/tests/test_migrations.py +158 -0
  96. ckanext_actor_registry-0.3.0/ckanext/actor_registry/tests/test_model_integration.py +232 -0
  97. ckanext_actor_registry-0.3.0/ckanext/actor_registry/tests/test_model_unit.py +42 -0
  98. ckanext_actor_registry-0.3.0/ckanext/actor_registry/tests/test_page_matches_export.py +114 -0
  99. ckanext_actor_registry-0.3.0/ckanext/actor_registry/tests/test_plugin.py +32 -0
  100. ckanext_actor_registry-0.3.0/ckanext/actor_registry/tests/test_rdf.py +209 -0
  101. ckanext_actor_registry-0.3.0/ckanext/actor_registry/tests/test_rdf_endpoint.py +184 -0
  102. ckanext_actor_registry-0.3.0/ckanext/actor_registry/tests/test_validation_layer.py +135 -0
  103. ckanext_actor_registry-0.3.0/ckanext/actor_registry/tests/test_views.py +238 -0
  104. ckanext_actor_registry-0.3.0/ckanext/actor_registry/tests/test_worklist_filter.py +140 -0
  105. ckanext_actor_registry-0.3.0/ckanext/actor_registry/validation.py +275 -0
  106. ckanext_actor_registry-0.3.0/ckanext/actor_registry/validators.py +66 -0
  107. ckanext_actor_registry-0.3.0/ckanext/actor_registry/views.py +876 -0
  108. ckanext_actor_registry-0.3.0/ckanext_actor_registry.egg-info/PKG-INFO +624 -0
  109. ckanext_actor_registry-0.3.0/ckanext_actor_registry.egg-info/SOURCES.txt +122 -0
  110. ckanext_actor_registry-0.3.0/ckanext_actor_registry.egg-info/dependency_links.txt +1 -0
  111. ckanext_actor_registry-0.3.0/ckanext_actor_registry.egg-info/entry_points.txt +5 -0
  112. ckanext_actor_registry-0.3.0/ckanext_actor_registry.egg-info/top_level.txt +1 -0
  113. ckanext_actor_registry-0.3.0/docs/BACKLOG.md +92 -0
  114. ckanext_actor_registry-0.3.0/docs/CATALOGUE_SETUPS.md +76 -0
  115. ckanext_actor_registry-0.3.0/docs/CKAN_COMMUNITY_ANNOUNCEMENT.md +58 -0
  116. ckanext_actor_registry-0.3.0/docs/ECOSYSTEM_CATALOG_SUBMISSION.md +72 -0
  117. ckanext_actor_registry-0.3.0/docs/INSTALLATION.md +175 -0
  118. ckanext_actor_registry-0.3.0/docs/PUBLISHING.md +88 -0
  119. ckanext_actor_registry-0.3.0/docs/RDF_AND_INTEROPERABILITY.md +63 -0
  120. ckanext_actor_registry-0.3.0/docs/RELEASE_NOTES_0.1.0.md +23 -0
  121. ckanext_actor_registry-0.3.0/docs/RELEASE_NOTES_0.2.0.md +51 -0
  122. ckanext_actor_registry-0.3.0/docs/TRANSLATIONS.md +74 -0
  123. ckanext_actor_registry-0.3.0/setup.cfg +4 -0
  124. ckanext_actor_registry-0.3.0/setup.py +52 -0
@@ -0,0 +1,19 @@
1
+ # AI assistance disclosure
2
+
3
+ The implementation and documentation of ckanext-actor-registry were developed by
4
+ Björn Hagström with assistance from OpenAI's ChatGPT and Codex and, from version
5
+ 0.2.0, from Anthropic's Claude Code.
6
+
7
+ AI tools assisted with research, design discussion, code drafting, refactoring,
8
+ documentation and operational verification. Product decisions, deployment
9
+ authorization and acceptance of the resulting work remain human decisions.
10
+
11
+ The human maintainer is the author, copyright holder and accountable project
12
+ maintainer. AI systems are not listed as authors or maintainers. Before a public
13
+ release, the maintainer is expected to review the released diff, verify the
14
+ documented behavior and accept responsibility for correctness, security,
15
+ licensing and provenance.
16
+
17
+ Contributors should disclose material generative-AI assistance in their pull
18
+ request description. Disclosure does not replace review, tests or the
19
+ contributor's responsibility for the submitted material.
@@ -0,0 +1,341 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file. The format
4
+ is based on Keep a Changelog, and the project follows Semantic Versioning.
5
+
6
+ ## [Unreleased]
7
+
8
+ ## [0.3.0] - 2026-10-07
9
+
10
+ ### Upgrading from 0.2.x
11
+
12
+ - Run `ckan db upgrade -p actor_registry` (new tables, migrations 007 and 008).
13
+ - **List `actor_registry` before `scheming_datasets` in `ckan.plugins`.** 0.2.x
14
+ documented the opposite order. CKAN takes a template from the plugin listed
15
+ first, and the new `additional_info.html` override only applies when
16
+ `actor_registry` comes first. In the old order the dataset page keeps showing
17
+ Maintainer and Author while the DCAT export leaves them out, so the page and the
18
+ export disagree.
19
+
20
+ ### Added
21
+
22
+ - A shown Author is exported as `dct:creator` (DCAT-AP-SE: *producent*), so
23
+ the export says what the dataset page says.
24
+ - *Cleanup* page (`/actor-registry/cleanup`): inactive publishers and contact
25
+ points still used by datasets, and references to records that no longer
26
+ exist; replace or remove them on the datasets you may edit.
27
+ - "Migrate to Actor Registry" (`/actor-registry/migrate`, a new tab): turns the
28
+ contact details in CKAN's Maintainer and Author fields into shared contact
29
+ points. Groups by email address, shows name variants and matching contact
30
+ points; create, link to existing or skip, in rounds. Original fields are
31
+ never changed; editors migrate their own datasets. Decisions are logged in
32
+ a new table (migration `actor_registry_007`).
33
+ - The migration page shows a group of more than 25 datasets compactly: all of them are included, and
34
+ the datasets to leave out are ticked in a scrollable list. Only those are posted, so a group of
35
+ thousands of datasets is not refused by the web framework's form-size limit.
36
+ - Migration: *Changed since linking* lists linked datasets whose Maintainer or
37
+ Author changed afterwards, with old and new values; update the contact
38
+ point, link another, create a new one or keep it (migration
39
+ `actor_registry_008` stores the values a decision was made on).
40
+ - Migration: *Close the migration* (sysadmins) hides Maintainer and Author in
41
+ forms and on dataset pages and stops exporting them, at runtime and without
42
+ deleting anything; it can be reopened. Asks for confirmation while datasets
43
+ still lack a contact point. New `legacy_contact.html` form and display
44
+ snippets for those fields.
45
+ - Setting `ckanext.actor_registry.legacy_contact_fields` (default `true`):
46
+ when `false`, the DCAT export never uses CKAN's free-text contact fields
47
+ (Maintainer, Author, ckanext-dcat's `contact_*` extras). Stored values are
48
+ not changed.
49
+ - `docs/CATALOGUE_SETUPS.md`: common ways catalogues relate organizations,
50
+ publishers and contact points, with a recommendation for each.
51
+ - A second example schema, `contact_points_only_schema.yaml`: organization and
52
+ contact points without a publisher field, for catalogues where the owner
53
+ organization is the publisher. With tests, including that the DCAT export
54
+ then uses the organization as publisher.
55
+ - README section "Choosing your fields": why and how to choose between
56
+ organization, publisher and contact points, how CKAN's own Author/Maintainer
57
+ fields map, and that the schema decides which fields a dataset has (the
58
+ optional legacy contact snippets can hide Maintainer and Author).
59
+
60
+ ### Changed
61
+
62
+ - What visitors see is what is exported: the dataset page now shows an
63
+ inactive publisher or contact point (the export already contained it), the
64
+ export follows a merged publisher to its target (as the page did), and
65
+ Maintainer/Author are not shown when the dataset has registry contact
66
+ points (they were not exported). README: "What visitors see is what is
67
+ exported", with the deliberate exceptions.
68
+ - The publisher is optional in `actor_registry_schema.yaml`. When it is
69
+ optional and empty, the form explains that the organization is given as
70
+ publisher in the DCAT export; the dataset page shows no publisher.
71
+ - The "missing" prompt on a dataset page follows the schema: it asks for a
72
+ publisher only when the schema requires one, never for a field the schema
73
+ lacks, and its heading names what is missing.
74
+ - The Edit and Delete buttons in the publisher and contact point lists are
75
+ spaced, kept on one line, aligned with the row and identical in both lists;
76
+ Delete is outlined instead of filled. Identifiers no longer wrap.
77
+ - The publisher and contact point pages are tidier: empty fields are no longer
78
+ shown as "–", the dataset counts use real plural forms ("Linked to 1
79
+ dataset", "Linked to 4 datasets", also on the delete and merge pages), each
80
+ linked dataset shows its organization and when it was last updated, and the
81
+ contact point breadcrumb names the contact point. The pages use the full
82
+ width.
83
+
84
+ ### Fixed
85
+
86
+ - Maintainer and Author that the schema does not show on the dataset page are
87
+ no longer exported (ckanext-dcat used them as a contact point anyway).
88
+ - A deactivated publisher no longer locks the datasets that use it, the same
89
+ way as for contact points; the form shows it marked inactive, and choosing
90
+ an inactive or missing publisher gives a message that names it. Inactive
91
+ publishers are no longer offered as "Belongs to organization" for a new
92
+ contact point.
93
+ - A deactivated contact point no longer locks the datasets that use it: they
94
+ can be saved, and the form shows it, marked inactive, instead of dropping it
95
+ silently. Choosing an inactive contact point anew, or one that no longer
96
+ exists, gives a message that names it.
97
+ - `ckanext.actor_registry.legacy_contact_fields` set to false in the ini file
98
+ is read correctly after CKAN reloads its runtime settings (it can then be an
99
+ empty string).
100
+ - A dataset with a broken stored `contact_point_ids` value (invalid JSON, as old
101
+ imports can have) no longer makes the Publishers page and the worklist fail;
102
+ such a value counts as no contact point, and a bare id as one.
103
+ - The DCAT export no longer adds Maintainer or Author as a second contact point
104
+ when a dataset has registry contact points.
105
+ - Contact point and publisher references stored as JSON text are resolved like
106
+ lists.
107
+ - Visitors who are not logged in no longer see the administration tabs
108
+ (Sysadmins, Config, Trash) or the registry tabs on a publisher's or contact
109
+ point's public page; logged-in users see only the registry tabs, sysadmins
110
+ see all.
111
+
112
+ ## [0.2.3] - 2026-10-01
113
+
114
+ ### Changed
115
+
116
+ - The phone help text no longer refers to DCAT-AP-SE: "Include the country code, e.g. +46
117
+ or +49, so the number works from other countries too." The README and the profile
118
+ describe the telephone export as the usual vCard form, which ckanext-dcat itself lacks.
119
+ - The documentation speaks of DCAT-AP and national profiles based on it, with the Swedish
120
+ DCAT-AP-SE only as an example of a national validator.
121
+ - A new language needs only its catalogue: the plugin offers every locale with a compiled
122
+ `.mo` file in `i18n/` instead of a fixed list. A contributed language may be partial
123
+ (untranslated strings show in English); only the maintained Swedish catalogues must be
124
+ complete. A test checks that every `.mo` matches its `.po`, and CONTRIBUTING.md says how
125
+ to contribute a language.
126
+
127
+ ## [0.2.2] - 2026-10-01
128
+
129
+ ### Fixed
130
+
131
+ - Swedish translations for the 13 strings added with contact point deletion
132
+ (confirmation page, list filter, messages). They were missing from the
133
+ `.pot` and `.po` files and showed in English on Swedish pages.
134
+ - New test: every string a fresh extraction finds must be translated in every
135
+ shipped catalogue.
136
+
137
+ ## [0.2.1] - 2026-09-22
138
+
139
+ ### Fixed
140
+
141
+ - `examples/ckan-2.12/smoke_check.py`: the resource-creation step's POST response was
142
+ discarded, so a server error there could still end in "All checks passed." The
143
+ underlying cause was in the script itself: its hidden-field parser assumed
144
+ `type="hidden"` came first in the tag, which is not true of CKAN 2.12's resource
145
+ form, so the required (and CKAN-mandated) `id` field was silently dropped from the
146
+ submission, causing a real HTTP 500 (`KeyError: 'id'` in CKAN core). The parser is
147
+ now attribute-order independent, and the step's response is checked like every
148
+ other step.
149
+ - `examples/ckan-2.12/smoke_check.py`: `CKAN_SITE_URL` is now read from the process
150
+ environment first, falling back to `.env`, so a one-off `CKAN_SITE_URL=... python3
151
+ smoke_check.py` (for a non-default port) is honoured instead of silently testing
152
+ the wrong server.
153
+
154
+ ### Added
155
+
156
+ - a regression test confirming that migration `006` fails clearly, and does not drop
157
+ data, when a database already has active publishers with a duplicate
158
+ (identifier_scheme, identifier) pair -- the behaviour the migration's own docstring
159
+ and this changelog already documented, now exercised.
160
+
161
+ ## [0.2.0] - 2026-09-21
162
+
163
+ The first tagged release. It follows the initial source-only snapshot (0.1.0, below) and contains
164
+ breaking changes: translation keys changed with the UI text ("actor" is now "publisher"), migration
165
+ `006` adds a unique index, and CKAN 2.11.0 and older are not supported.
166
+
167
+ ### Added
168
+
169
+ - an initial automated test suite for registry behavior, dataset projection and
170
+ DCAT-AP 3 RDF serialization;
171
+ - a migration rehearsal that preserves records from the unpublished contact
172
+ point prototype;
173
+ - Action API end-to-end tests for Turtle, RDF/XML and JSON-LD plus optional
174
+ validation with the official DCAT-AP 3 SHACL shapes;
175
+ - documented RDF and interoperability design decisions;
176
+ - cross-registry validation preventing actors and contact points from sharing a
177
+ URI.
178
+ - a GitHub Actions CI workflow running the automated test suite and the
179
+ dependency-free JS regression tests on every push and pull request;
180
+ - a README section documenting how to activate the extension on an existing
181
+ installation that already has datasets (the `/actors` worklist and the
182
+ inline per-dataset fix-it prompt);
183
+ - `setup.py` project metadata (`url`, `author`, `project_urls`) now that the
184
+ project has a public repository.
185
+ - permanent actor deletion (`actor_registry_actor_delete`, sysadmin-only),
186
+ for actors -- active or already merged/retired -- that are no longer
187
+ needed. Clears the actor as publisher on any dataset that had it, and
188
+ decouples (does not delete) any contact points it owned;
189
+ - merged/retired actors are now hidden by default on `/actors`, with a
190
+ checkbox to show them again.
191
+ - permanent contact point deletion (`actor_registry_contactpoint_delete`,
192
+ sysadmin-only), mirroring actor deletion: removes the contact point
193
+ from any dataset's `contact_point_ids`, leaves an owning actor
194
+ unaffected;
195
+ - inactive contact points are now hidden by default on `/contactpoints`,
196
+ with a checkbox to show them again.
197
+ - public dataset display snippets (`actor.html`, `contactpoints.html`) showing
198
+ readable publisher and contact point details instead of stored ids; merged
199
+ actors resolve to their survivor, inactive or missing references render
200
+ nothing;
201
+ - `(identifier_scheme, identifier)` uniqueness among active actors, with
202
+ server-side validation in forms and inline dialogs, a localised conflict
203
+ message naming the existing actor, and a partial unique index (migration
204
+ `006`; upgrading fails if duplicates already exist);
205
+ - email, URL, phone and kind validation/normalisation in every form and dialog. Emails are
206
+ checked with CKAN's own `email_validator` (plus a dot in the domain, which CKAN itself does
207
+ not require); a value that is unchanged from what is stored is not re-validated, so records
208
+ saved before a rule existed can still be edited;
209
+ - opt-in validators `actor_registry_actor_exists` and
210
+ `actor_registry_contactpoints_exist` for dataset schemas;
211
+ - localised field help texts shared by the admin forms and inline dialogs,
212
+ a `sv_SE` catalogue, and a localised example schema
213
+ (`ckanext/actor_registry/examples/`);
214
+ - `docs/INSTALLATION.md`, an install and compatibility guide for CKAN 2.11 and 2.12;
215
+ - `docs/TRANSLATIONS.md`, a guide to the translation catalogues and how to change or add strings
216
+ (it replaces the internal `I18N_PLAN.md`);
217
+ - `examples/ckan-2.12/`, a runnable Docker Compose example (CKAN 2.11 or 2.12, PostgreSQL,
218
+ Solr, Redis, ckanext-scheming 3.1.0 and this extension) with a smoke test;
219
+ - supported CKAN releases: 2.11.1 and later 2.11 patches, and 2.12. CI runs the full suite on
220
+ 2.11.1 (the oldest supported), the newest 2.11 patch and 2.12 with ckanext-scheming 3.1.0,
221
+ and on 2.12 against scheming `master` (allowed to fail); `Dockerfile.test` and
222
+ `docker-compose.test.yml` take the CKAN and scheming versions as build arguments.
223
+ - Swedish translations for the delete-confirmation pages (they were English-only);
224
+ - "Belongs to organization" can now be set in the inline contact point dialog
225
+ (previously only in the admin form), with the same help text; a link must
226
+ point at an existing, active actor.
227
+ - a contact point's page lists the datasets it is linked to, and an actor's page
228
+ previews its first 10 (as publisher, and via its contact points) with a
229
+ "Show all N" link to a paginated list (20 per page, A-Z) at
230
+ `/actors/<id>/datasets` and `/contactpoints/<id>/datasets`. The lists are read
231
+ from the database, not the search index, and respect dataset visibility:
232
+ private datasets are shown only to sysadmins and members of the owning
233
+ organisation.
234
+
235
+ ### Changed
236
+
237
+ - documentation brought up to date for 0.2.0: the README is rewritten for the "publisher"
238
+ wording, with a Documentation index and a note on each screenshot link (the screenshots are
239
+ being retaken); `docs/BACKLOG.md` is now a short English backlog; CONTRIBUTING, SECURITY,
240
+ TESTING, the release notes, the community announcement draft and the catalog submission
241
+ draft are updated;
242
+ - validation now lives in ONE shared layer (`validation.py`) instead of in the views: the rules are
243
+ CKAN validators collected in schemas that CKAN's own `navl` machinery runs, giving ordinary CKAN
244
+ error dicts. The full forms, the inline dialogs and the merge action all use it, and an API added
245
+ later would too;
246
+ - telephone URI normalization is shared by HTML helpers and RDF serialization;
247
+ - controlled theme and publisher-type URIs are explicitly typed as
248
+ `skos:Concept` in RDF output;
249
+ - `CONTRIBUTING.md`'s development priorities no longer list a full Action API;
250
+ see `docs/BACKLOG.md` for why that was deliberately deprioritized rather
251
+ than deferred.
252
+ - the worklist of datasets that lack something, on `/actors`, previews 10 with an exact total and a
253
+ "Show all" link to a paginated page (`/actors/unlinked-datasets`). A *Missing:* choice picks
254
+ which datasets it lists: missing both a publisher and a contact point (the default), only a
255
+ publisher, only a contact point, or either (`?missing=both|publisher|contact_point|either`).
256
+ Like the other registry lists it reads from the database, not the search index;
257
+ - the contact point list links each name to the contact point's page, like the publisher list;
258
+ - a publisher is no longer presented as a contact point: its page, its "show all"
259
+ page, the delete confirmation and the merge summary list only the datasets it
260
+ publishes, not datasets that merely use a contact point that belongs to it;
261
+ - the contact point field "Belongs to actor" is now "Belongs to organization"
262
+ (sv: "Tillhör organisation"), and the row is hidden on the public contact
263
+ point page when no link is set;
264
+ - several contact points on a dataset page are visually separated.
265
+ - on the dataset page a publisher's type, web address, email and description are
266
+ shown on their own lines under its name (values only, like the contact points)
267
+ instead of the web address in parentheses;
268
+ - UI text now says "publisher" instead of "actor" throughout, in English and
269
+ Swedish ("utgivare", not "aktör"), matching the dataset form. Only visible
270
+ text changes; URLs, action names and code identifiers keep "actor". The
271
+ translation catalogue keys change with the English text, so out-of-tree
272
+ translations of the old strings need updating;
273
+
274
+ ### Fixed
275
+
276
+ - `actor_registry_actor_merge` wrote the chosen field values (email, URL, identifier, ...) onto the
277
+ surviving publisher without validating them, and an identifier that clashed with a third
278
+ publisher's surfaced as a database error. The chosen values now pass the same rules as any other
279
+ edit, and a violation is a `ValidationError` on `fields`, with nothing changed;
280
+ - an input longer than its database column (a name or identifier over 255 characters, an email
281
+ over 320, a phone number over 100) crashed with a database error, i.e. an HTTP 500. Every
282
+ field now has a maximum length and shows a translated message instead;
283
+ - the Persistent URI and Type fields of a publisher, and the URI of a contact point, were not
284
+ validated on the server; they must now be absolute URIs (`http://`, `https://` or `urn:`);
285
+ - stored web addresses and URIs are only turned into links when CKAN's own `h.is_url` accepts
286
+ them (also in the JavaScript previews, which allow only http(s)); anything else, e.g. a `javascript:` value from a
287
+ row saved before validation existed, is shown as plain text instead of a clickable link;
288
+ - the queries that find the datasets linked to a publisher or contact point read the
289
+ dataset's extras from `package.extras`, a jsonb column that only exists in CKAN 2.12;
290
+ on CKAN 2.11 (where extras live in the `package_extra` table) they failed with
291
+ `column "extras" does not exist`. Both layouts are now supported;
292
+ - the test image no longer needs `wget` (it is gone from the CKAN 2.12 images) and no
293
+ longer depends on the host's file modes.
294
+ - merging actors would have failed to hand the surviving actor the merged
295
+ actor's identifier once identifiers became unique; the merged actor is now
296
+ retired first;
297
+ - `MANIFEST.in` now packages the translation catalogues and the example schema.
298
+
299
+ ### Known limitations
300
+
301
+ - the dataset lists on publisher and contact point pages only include private datasets
302
+ that the visitor may see as a sysadmin or as a member of the dataset's organization.
303
+ Users who can see a private dataset only as a CKAN *dataset collaborator*
304
+ (`ckan.auth.allow_dataset_collaborators`, off by default) do not see it in these lists;
305
+ nothing is revealed to anyone who should not see it.
306
+
307
+ ## [0.1.0] - 2026-09-18
308
+
309
+ Published as source only (the initial standalone snapshot); no release or tag was created.
310
+
311
+ ### Added
312
+
313
+ - reusable actor and contact point registries;
314
+ - sysadmin management pages and inline creation from Scheming forms;
315
+ - publisher and contact point selectors with record previews;
316
+ - per-user latest-publisher and recent-contact-point convenience choices;
317
+ - stable dataset references resolved at display and export time;
318
+ - optional European DCAT-AP 3 profile extension with VCARD telephone output;
319
+ - Alembic migrations for all extension-owned tables;
320
+ - documentation for installation, integration, security and contribution;
321
+ - English source strings throughout templates, Python and JavaScript, with a
322
+ compiled Swedish translation catalog using CKAN's own gettext-based
323
+ translation mechanism (`ITranslation`), the same one `ckanext-skelleftea`
324
+ uses.
325
+
326
+ ### Known limitations
327
+
328
+ - automated verification covers CKAN 2.11.1 and later 2.11 patches and CKAN 2.12 (see
329
+ `docs/INSTALLATION.md`; this line said "2.11.6 only" before CI was extended);
330
+ - browser and multi-version compatibility tests and a formal security review
331
+ remain work for a later release. A full registry Action API was
332
+ deliberately deprioritized rather than deferred -- see
333
+ `docs/BACKLOG.md` and `CONTRIBUTING.md`.
334
+
335
+ [Unreleased]: https://github.com/bjornhagstrom/ckanext-actor-registry/compare/v0.3.0...HEAD
336
+ [0.3.0]: https://github.com/bjornhagstrom/ckanext-actor-registry/compare/v0.2.3...v0.3.0
337
+ [0.2.3]: https://github.com/bjornhagstrom/ckanext-actor-registry/releases/tag/v0.2.3
338
+ [0.2.2]: https://github.com/bjornhagstrom/ckanext-actor-registry/releases/tag/v0.2.2
339
+ [0.2.1]: https://github.com/bjornhagstrom/ckanext-actor-registry/releases/tag/v0.2.1
340
+ [0.2.0]: https://github.com/bjornhagstrom/ckanext-actor-registry/releases/tag/v0.2.0
341
+ [0.1.0]: https://github.com/bjornhagstrom/ckanext-actor-registry/tree/df14240
@@ -0,0 +1,16 @@
1
+ # Code of conduct
2
+
3
+ We want participation in this project to be safe, respectful and constructive.
4
+
5
+ Be considerate, assume good intent, welcome questions and critique ideas rather
6
+ than people. Harassment, discriminatory language, threats, deliberate
7
+ disruption and publication of another person's private information are not
8
+ acceptable.
9
+
10
+ Project maintainers may edit or remove contributions and restrict participation
11
+ when this code of conduct is violated. Reports should be made privately to a
12
+ maintainer through the repository's available private contact channel. Reports
13
+ will be handled as confidentially as practical.
14
+
15
+ This code applies in the repository and in public spaces where someone is
16
+ representing the project.
@@ -0,0 +1,76 @@
1
+ # Contributing
2
+
3
+ Thank you for helping improve ckanext-actor-registry. Version 0.2 is an alpha,
4
+ so bug reports, compatibility results and design feedback are especially useful.
5
+
6
+ ## Before opening an issue
7
+
8
+ - search existing issues;
9
+ - include the CKAN, Python, ckanext-scheming and ckanext-dcat versions used;
10
+ - describe the expected and actual result;
11
+ - include reproducible steps and relevant logs with credentials and personal
12
+ data removed.
13
+
14
+ Use a private security report instead of a public issue for vulnerabilities; see
15
+ [SECURITY.md](SECURITY.md).
16
+
17
+ ## Translations
18
+
19
+ A new language is welcome as a pull request: add
20
+ `ckanext/actor_registry/i18n/<locale>/LC_MESSAGES/ckanext-actor-registry.po` and its
21
+ compiled `.mo`. No code change is needed; the plugin offers every compiled catalogue.
22
+ A partial translation is fine: strings not yet translated show in English. The tests
23
+ check that the `.mo` matches the `.po`; only the maintained Swedish catalogues must be
24
+ complete.
25
+ See [docs/TRANSLATIONS.md](docs/TRANSLATIONS.md).
26
+
27
+ ## Pull requests
28
+
29
+ 1. Discuss substantial behavior or data-model changes in an issue first.
30
+ 2. Keep each pull request focused.
31
+ 3. Add or update tests when changing behavior. [TESTING.md](TESTING.md) shows how to run the
32
+ suite; continuous integration runs it on CKAN 2.11.1, the newest 2.11 patch and 2.12.
33
+ 4. Update the README and changelog when user-visible behavior changes.
34
+ 5. Internationalize all new user-visible strings: wrap them in `_(...)`
35
+ with English source text (`from ckan.common import _` in Python,
36
+ `{{ _("...") }}` in templates; JavaScript strings go through a
37
+ `data-i18n-*` attribute rendered server-side instead, see
38
+ `assets/js/actor-quick-create.js` for the pattern), then add the
39
+ Swedish `msgstr` to
40
+ `ckanext/actor_registry/i18n/sv/LC_MESSAGES/ckanext-actor-registry.po`,
41
+ copy the same entry to `.../i18n/sv_SE/LC_MESSAGES/ckanext-actor-registry.po` (the
42
+ `sv_SE` catalogue is a copy of `sv`, and a test fails if they differ) and recompile with `pybabel compile -d ckanext/actor_registry/i18n -D
43
+ ckanext-actor-registry` (also wired into `dev-install-extras.sh`, so a
44
+ dev-stack rebuild picks it up too). To re-extract the full catalog
45
+ from scratch, run `pybabel extract -F babel.cfg -o ckanext/actor_registry/i18n/ckanext-actor-registry.pot .` from this
46
+ repo's root -- see `babel_ckan_tag_shims.py` first if that ever
47
+ silently drops a template's strings again.
48
+ 6. Confirm that migrations preserve existing data and provide a downgrade where
49
+ practical.
50
+ 7. State whether and how generative AI tools assisted the contribution. The
51
+ contributor remains responsible for reviewing the work and for its license
52
+ and provenance.
53
+
54
+ By submitting a contribution, you agree that it may be released under the MIT
55
+ license used by this repository and confirm that you have the right to submit
56
+ it.
57
+
58
+ ## Development priorities
59
+
60
+ - browser-based (end-to-end) tests;
61
+ - documented import and export workflows;
62
+ - screenshots and a short walkthrough for the README.
63
+
64
+ The automated model, authorization, form, validation and RDF serialization tests, and
65
+ compatibility testing on CKAN 2.11.1+ and 2.12, are in place.
66
+
67
+ A full `ckan.logic.action` CRUD API for registry management (create/read/
68
+ update/delete actors and contact points programmatically) was considered and
69
+ deliberately deprioritized: it is uncommon among comparable CKAN registry/
70
+ metadata extensions, and the admin GUI plus the existing merge and delete
71
+ actions already cover this extension's actual use cases. All validation lives in
72
+ one shared layer (`validation.py`), so an API added later would reuse it. See `docs/BACKLOG.md` for the full rationale. This is an
73
+ intentional design decision, not an open gap -- please raise it in an issue
74
+ first if you think it should be revisited.
75
+
76
+ All contributors must follow [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md).
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Björn Hagström
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,9 @@
1
+ recursive-include ckanext/actor_registry/templates *
2
+ recursive-include ckanext/actor_registry/assets *
3
+ recursive-include ckanext/actor_registry/migration *
4
+ recursive-include ckanext/actor_registry/i18n *
5
+ include ckanext/actor_registry/config_declaration.yaml
6
+ recursive-include ckanext/actor_registry/examples *.yaml
7
+ recursive-include ckanext/actor_registry/tests/fixtures *.yaml
8
+ include README.md LICENSE CHANGELOG.md CONTRIBUTING.md SECURITY.md CODE_OF_CONDUCT.md AI_ASSISTANCE.md
9
+ recursive-include docs *.md