udata 12.0.2.dev10__py3-none-any.whl → 13.0.1.dev21__py3-none-any.whl

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.

Potentially problematic release.


This version of udata might be problematic. Click here for more details.

Files changed (272) hide show
  1. udata/api/__init__.py +1 -0
  2. udata/api_fields.py +10 -4
  3. udata/app.py +11 -10
  4. udata/auth/__init__.py +9 -10
  5. udata/auth/mails.py +137 -45
  6. udata/auth/views.py +5 -12
  7. udata/commands/__init__.py +2 -4
  8. udata/commands/info.py +1 -3
  9. udata/commands/tests/test_fixtures.py +6 -3
  10. udata/core/access_type/api.py +18 -0
  11. udata/core/access_type/constants.py +98 -0
  12. udata/core/access_type/models.py +44 -0
  13. udata/core/activity/models.py +1 -1
  14. udata/core/badges/models.py +1 -1
  15. udata/core/badges/tasks.py +35 -1
  16. udata/core/badges/tests/test_commands.py +2 -4
  17. udata/core/badges/tests/test_model.py +2 -2
  18. udata/core/badges/tests/test_tasks.py +55 -0
  19. udata/core/constants.py +1 -0
  20. udata/core/contact_point/models.py +8 -0
  21. udata/core/dataservices/api.py +10 -12
  22. udata/core/dataservices/apiv2.py +3 -1
  23. udata/core/dataservices/constants.py +0 -29
  24. udata/core/dataservices/models.py +44 -44
  25. udata/core/dataservices/rdf.py +2 -1
  26. udata/core/dataservices/search.py +5 -9
  27. udata/core/dataservices/tasks.py +33 -0
  28. udata/core/dataset/api.py +15 -24
  29. udata/core/dataset/api_fields.py +11 -0
  30. udata/core/dataset/apiv2.py +11 -0
  31. udata/core/dataset/constants.py +0 -1
  32. udata/core/dataset/forms.py +29 -0
  33. udata/core/dataset/models.py +24 -42
  34. udata/core/dataset/rdf.py +2 -1
  35. udata/core/dataset/search.py +2 -2
  36. udata/core/dataset/tasks.py +86 -8
  37. udata/core/discussions/mails.py +63 -0
  38. udata/core/discussions/tasks.py +4 -18
  39. udata/core/metrics/__init__.py +0 -6
  40. udata/core/organization/api.py +20 -14
  41. udata/core/organization/mails.py +144 -0
  42. udata/core/organization/models.py +2 -1
  43. udata/core/organization/rdf.py +3 -3
  44. udata/core/organization/search.py +1 -1
  45. udata/core/organization/tasks.py +21 -49
  46. udata/core/pages/tests/test_api.py +0 -2
  47. udata/core/reuse/api.py +29 -3
  48. udata/core/reuse/mails.py +21 -0
  49. udata/core/reuse/models.py +10 -1
  50. udata/core/reuse/search.py +1 -1
  51. udata/core/reuse/tasks.py +2 -3
  52. udata/core/site/api.py +27 -19
  53. udata/core/site/models.py +2 -6
  54. udata/core/site/rdf.py +2 -2
  55. udata/core/spatial/tests/test_api.py +17 -20
  56. udata/core/spatial/tests/test_models.py +3 -3
  57. udata/core/user/mails.py +54 -0
  58. udata/core/user/models.py +2 -3
  59. udata/core/user/tasks.py +8 -23
  60. udata/core/user/tests/test_user_model.py +2 -6
  61. udata/entrypoints.py +0 -6
  62. udata/features/identicon/tests/test_backends.py +3 -13
  63. udata/forms/fields.py +3 -3
  64. udata/forms/widgets.py +2 -2
  65. udata/frontend/__init__.py +3 -32
  66. udata/harvest/actions.py +4 -9
  67. udata/harvest/api.py +5 -14
  68. udata/harvest/backends/__init__.py +20 -11
  69. udata/harvest/backends/base.py +2 -2
  70. udata/harvest/backends/ckan/harvesters.py +2 -1
  71. udata/harvest/backends/dcat.py +3 -0
  72. udata/harvest/backends/maaf.py +1 -0
  73. udata/harvest/commands.py +6 -4
  74. udata/harvest/forms.py +9 -6
  75. udata/harvest/tasks.py +3 -5
  76. udata/harvest/tests/ckan/test_ckan_backend.py +300 -337
  77. udata/harvest/tests/ckan/test_ckan_backend_errors.py +94 -99
  78. udata/harvest/tests/ckan/test_ckan_backend_filters.py +128 -122
  79. udata/harvest/tests/ckan/test_dkan_backend.py +39 -51
  80. udata/harvest/tests/dcat/bnodes.xml +17 -1
  81. udata/harvest/tests/dcat/datara--5a26b0f6-0ccf-46ad-ac58-734054b91977.rdf.xml +255 -0
  82. udata/harvest/tests/dcat/datara--f40c3860-7236-4b30-a141-23b8ae33f7b2.rdf.xml +289 -0
  83. udata/harvest/tests/factories.py +1 -1
  84. udata/harvest/tests/test_actions.py +11 -9
  85. udata/harvest/tests/test_api.py +4 -5
  86. udata/harvest/tests/test_base_backend.py +5 -4
  87. udata/harvest/tests/test_dcat_backend.py +72 -16
  88. udata/harvest/tests/test_models.py +2 -4
  89. udata/harvest/tests/test_notifications.py +2 -4
  90. udata/harvest/tests/test_tasks.py +2 -3
  91. udata/mail.py +90 -53
  92. udata/migrations/2025-01-05-dataservices-fields-changes.py +8 -14
  93. udata/migrations/2025-10-21-remove-ckan-harvest-modified-at.py +28 -0
  94. udata/migrations/2025-10-29-harvesters-sources-integrity.py +27 -0
  95. udata/models/__init__.py +0 -2
  96. udata/mongo/extras_fields.py +4 -3
  97. udata/mongo/taglist_field.py +3 -3
  98. udata/rdf.py +65 -20
  99. udata/sentry.py +3 -4
  100. udata/settings.py +15 -13
  101. udata/tags.py +5 -5
  102. udata/tasks.py +3 -3
  103. udata/templates/mail/message.html +65 -0
  104. udata/templates/mail/message.txt +16 -0
  105. udata/tests/__init__.py +40 -58
  106. udata/tests/api/__init__.py +87 -2
  107. udata/tests/api/test_activities_api.py +17 -23
  108. udata/tests/api/test_auth_api.py +2 -4
  109. udata/tests/api/test_contact_points.py +48 -54
  110. udata/tests/api/test_dataservices_api.py +65 -97
  111. udata/tests/api/test_datasets_api.py +171 -56
  112. udata/tests/api/test_me_api.py +4 -6
  113. udata/tests/api/test_organizations_api.py +19 -38
  114. udata/tests/api/test_reports_api.py +0 -4
  115. udata/tests/api/test_reuses_api.py +99 -23
  116. udata/tests/api/test_security_api.py +124 -0
  117. udata/tests/api/test_swagger.py +2 -3
  118. udata/tests/api/test_tags_api.py +6 -7
  119. udata/tests/api/test_transfer_api.py +0 -2
  120. udata/tests/api/test_user_api.py +8 -10
  121. udata/tests/apiv2/test_datasets.py +0 -4
  122. udata/tests/apiv2/test_me_api.py +0 -2
  123. udata/tests/apiv2/test_organizations.py +0 -2
  124. udata/tests/apiv2/test_swagger.py +2 -3
  125. udata/tests/apiv2/test_topics.py +0 -2
  126. udata/tests/cli/test_cli_base.py +14 -12
  127. udata/tests/cli/test_db_cli.py +51 -54
  128. udata/tests/contact_point/test_contact_point_models.py +2 -2
  129. udata/tests/dataservice/test_csv_adapter.py +2 -5
  130. udata/tests/dataservice/test_dataservice_rdf.py +64 -4
  131. udata/tests/dataservice/test_dataservice_tasks.py +36 -38
  132. udata/tests/dataset/test_csv_adapter.py +2 -5
  133. udata/tests/dataset/test_dataset_actions.py +2 -4
  134. udata/tests/dataset/test_dataset_commands.py +2 -4
  135. udata/tests/dataset/test_dataset_events.py +3 -3
  136. udata/tests/dataset/test_dataset_model.py +6 -7
  137. udata/tests/dataset/test_dataset_rdf.py +205 -16
  138. udata/tests/dataset/test_dataset_recommendations.py +2 -2
  139. udata/tests/dataset/test_dataset_tasks.py +66 -68
  140. udata/tests/dataset/test_resource_preview.py +39 -48
  141. udata/tests/dataset/test_transport_tasks.py +2 -2
  142. udata/tests/features/territories/__init__.py +0 -6
  143. udata/tests/features/territories/test_territories_api.py +25 -24
  144. udata/tests/forms/test_current_user_field.py +2 -2
  145. udata/tests/forms/test_dict_field.py +2 -4
  146. udata/tests/forms/test_extras_fields.py +2 -3
  147. udata/tests/forms/test_image_field.py +2 -2
  148. udata/tests/forms/test_model_field.py +2 -4
  149. udata/tests/forms/test_publish_as_field.py +2 -4
  150. udata/tests/forms/test_user_forms.py +26 -29
  151. udata/tests/frontend/test_auth.py +2 -3
  152. udata/tests/frontend/test_csv.py +5 -6
  153. udata/tests/frontend/test_error_handlers.py +2 -3
  154. udata/tests/frontend/test_hooks.py +5 -7
  155. udata/tests/frontend/test_markdown.py +3 -4
  156. udata/tests/helpers.py +2 -7
  157. udata/tests/metrics/test_metrics.py +52 -48
  158. udata/tests/metrics/test_tasks.py +154 -150
  159. udata/tests/organization/test_csv_adapter.py +2 -5
  160. udata/tests/organization/test_notifications.py +2 -4
  161. udata/tests/organization/test_organization_model.py +3 -4
  162. udata/tests/organization/test_organization_rdf.py +6 -12
  163. udata/tests/plugin.py +6 -110
  164. udata/tests/reuse/test_reuse_model.py +3 -4
  165. udata/tests/site/test_site_api.py +0 -2
  166. udata/tests/site/test_site_csv_exports.py +0 -2
  167. udata/tests/site/test_site_metrics.py +2 -4
  168. udata/tests/site/test_site_model.py +2 -2
  169. udata/tests/site/test_site_rdf.py +85 -29
  170. udata/tests/test_activity.py +3 -3
  171. udata/tests/test_api_fields.py +6 -9
  172. udata/tests/test_cors.py +0 -2
  173. udata/tests/test_dcat_commands.py +2 -3
  174. udata/tests/test_discussions.py +2 -7
  175. udata/tests/test_mail.py +150 -114
  176. udata/tests/test_migrations.py +413 -419
  177. udata/tests/test_model.py +10 -11
  178. udata/tests/test_notifications.py +2 -3
  179. udata/tests/test_owned.py +3 -3
  180. udata/tests/test_rdf.py +19 -15
  181. udata/tests/test_routing.py +5 -5
  182. udata/tests/test_storages.py +6 -5
  183. udata/tests/test_tags.py +2 -4
  184. udata/tests/test_topics.py +2 -4
  185. udata/tests/test_transfer.py +4 -5
  186. udata/tests/topic/test_topic_tasks.py +25 -27
  187. udata/tests/user/test_user_rdf.py +2 -8
  188. udata/tests/user/test_user_tasks.py +3 -5
  189. udata/tests/workers/test_jobs_commands.py +2 -2
  190. udata/tests/workers/test_tasks_routing.py +27 -27
  191. udata/translations/ar/LC_MESSAGES/udata.mo +0 -0
  192. udata/translations/ar/LC_MESSAGES/udata.po +369 -435
  193. udata/translations/de/LC_MESSAGES/udata.mo +0 -0
  194. udata/translations/de/LC_MESSAGES/udata.po +371 -437
  195. udata/translations/es/LC_MESSAGES/udata.mo +0 -0
  196. udata/translations/es/LC_MESSAGES/udata.po +369 -435
  197. udata/translations/fr/LC_MESSAGES/udata.mo +0 -0
  198. udata/translations/fr/LC_MESSAGES/udata.po +381 -447
  199. udata/translations/it/LC_MESSAGES/udata.mo +0 -0
  200. udata/translations/it/LC_MESSAGES/udata.po +371 -437
  201. udata/translations/pt/LC_MESSAGES/udata.mo +0 -0
  202. udata/translations/pt/LC_MESSAGES/udata.po +371 -437
  203. udata/translations/sr/LC_MESSAGES/udata.mo +0 -0
  204. udata/translations/sr/LC_MESSAGES/udata.po +372 -438
  205. udata/translations/udata.pot +379 -440
  206. udata/utils.py +66 -4
  207. {udata-12.0.2.dev10.dist-info → udata-13.0.1.dev21.dist-info}/METADATA +1 -4
  208. {udata-12.0.2.dev10.dist-info → udata-13.0.1.dev21.dist-info}/RECORD +212 -256
  209. udata/linkchecker/__init__.py +0 -0
  210. udata/linkchecker/backends.py +0 -31
  211. udata/linkchecker/checker.py +0 -75
  212. udata/linkchecker/commands.py +0 -21
  213. udata/linkchecker/models.py +0 -9
  214. udata/linkchecker/tasks.py +0 -55
  215. udata/templates/mail/account_deleted.html +0 -5
  216. udata/templates/mail/account_deleted.txt +0 -6
  217. udata/templates/mail/account_inactivity.html +0 -40
  218. udata/templates/mail/account_inactivity.txt +0 -31
  219. udata/templates/mail/badge_added_association.html +0 -33
  220. udata/templates/mail/badge_added_association.txt +0 -11
  221. udata/templates/mail/badge_added_certified.html +0 -33
  222. udata/templates/mail/badge_added_certified.txt +0 -11
  223. udata/templates/mail/badge_added_company.html +0 -33
  224. udata/templates/mail/badge_added_company.txt +0 -11
  225. udata/templates/mail/badge_added_local_authority.html +0 -33
  226. udata/templates/mail/badge_added_local_authority.txt +0 -11
  227. udata/templates/mail/badge_added_public_service.html +0 -33
  228. udata/templates/mail/badge_added_public_service.txt +0 -11
  229. udata/templates/mail/discussion_closed.html +0 -47
  230. udata/templates/mail/discussion_closed.txt +0 -16
  231. udata/templates/mail/inactive_account_deleted.html +0 -5
  232. udata/templates/mail/inactive_account_deleted.txt +0 -6
  233. udata/templates/mail/membership_refused.html +0 -20
  234. udata/templates/mail/membership_refused.txt +0 -11
  235. udata/templates/mail/membership_request.html +0 -46
  236. udata/templates/mail/membership_request.txt +0 -12
  237. udata/templates/mail/new_discussion.html +0 -44
  238. udata/templates/mail/new_discussion.txt +0 -15
  239. udata/templates/mail/new_discussion_comment.html +0 -45
  240. udata/templates/mail/new_discussion_comment.txt +0 -16
  241. udata/templates/mail/new_member.html +0 -27
  242. udata/templates/mail/new_member.txt +0 -11
  243. udata/templates/mail/new_reuse.html +0 -37
  244. udata/templates/mail/new_reuse.txt +0 -9
  245. udata/templates/mail/test.html +0 -6
  246. udata/templates/mail/test.txt +0 -6
  247. udata/templates/mail/user_mail_card.html +0 -26
  248. udata/templates/security/email/base.html +0 -105
  249. udata/templates/security/email/base.txt +0 -6
  250. udata/templates/security/email/button.html +0 -3
  251. udata/templates/security/email/change_notice.html +0 -22
  252. udata/templates/security/email/change_notice.txt +0 -8
  253. udata/templates/security/email/confirmation_instructions.html +0 -20
  254. udata/templates/security/email/confirmation_instructions.txt +0 -7
  255. udata/templates/security/email/login_instructions.html +0 -19
  256. udata/templates/security/email/login_instructions.txt +0 -7
  257. udata/templates/security/email/reset_instructions.html +0 -24
  258. udata/templates/security/email/reset_instructions.txt +0 -9
  259. udata/templates/security/email/reset_notice.html +0 -11
  260. udata/templates/security/email/reset_notice.txt +0 -4
  261. udata/templates/security/email/welcome.html +0 -24
  262. udata/templates/security/email/welcome.txt +0 -9
  263. udata/templates/security/email/welcome_existing.html +0 -32
  264. udata/templates/security/email/welcome_existing.txt +0 -14
  265. udata/terms.md +0 -6
  266. udata/tests/frontend/__init__.py +0 -23
  267. udata/tests/metrics/conftest.py +0 -15
  268. udata/tests/test_linkchecker.py +0 -277
  269. {udata-12.0.2.dev10.dist-info → udata-13.0.1.dev21.dist-info}/WHEEL +0 -0
  270. {udata-12.0.2.dev10.dist-info → udata-13.0.1.dev21.dist-info}/entry_points.txt +0 -0
  271. {udata-12.0.2.dev10.dist-info → udata-13.0.1.dev21.dist-info}/licenses/LICENSE +0 -0
  272. {udata-12.0.2.dev10.dist-info → udata-13.0.1.dev21.dist-info}/top_level.txt +0 -0
@@ -5,9 +5,10 @@ import pytest
5
5
  import requests
6
6
  from flask import url_for
7
7
  from rdflib import BNode, Graph, Literal, Namespace, URIRef
8
- from rdflib.namespace import FOAF, RDF, RDFS
8
+ from rdflib.namespace import FOAF, ORG, RDF, RDFS
9
9
  from rdflib.resource import Resource as RdfResource
10
10
 
11
+ from udata.core.constants import HVD
11
12
  from udata.core.contact_point.factories import ContactPointFactory
12
13
  from udata.core.dataservices.factories import DataserviceFactory
13
14
  from udata.core.dataset.constants import UpdateFrequency
@@ -52,11 +53,11 @@ from udata.rdf import (
52
53
  default_lang_value,
53
54
  primary_topic_identifier_from_rdf,
54
55
  )
56
+ from udata.tests import PytestOnlyTestCase
57
+ from udata.tests.api import PytestOnlyAPITestCase, PytestOnlyDBTestCase
55
58
  from udata.tests.helpers import assert200, assert_redirects
56
59
  from udata.utils import faker
57
60
 
58
- pytestmark = pytest.mark.usefixtures("app")
59
-
60
61
  GOV_UK_REF = "http://reference.data.gov.uk/id/year/2017"
61
62
 
62
63
  try:
@@ -67,8 +68,7 @@ else:
67
68
  GOV_UK_REF_IS_UP = True
68
69
 
69
70
 
70
- @pytest.mark.frontend
71
- class DatasetToRdfTest:
71
+ class DatasetToRdfTest(PytestOnlyAPITestCase):
72
72
  def test_minimal(self):
73
73
  dataset = DatasetFactory.build() # Does not have an URL
74
74
  d = dataset_to_rdf(dataset)
@@ -167,8 +167,8 @@ class DatasetToRdfTest:
167
167
  d = dataset_to_rdf(dataset)
168
168
 
169
169
  contact_rdf = d.value(DCT.publisher)
170
- assert contact_rdf.value(RDF.type).identifier == VCARD.Kind
171
- assert contact_rdf.value(VCARD.fn) == Literal("Publisher Contact")
170
+ assert contact_rdf.value(RDF.type).identifier == FOAF.Agent
171
+ assert contact_rdf.value(FOAF.name) == Literal("Publisher Contact")
172
172
 
173
173
  org_rdf = d.value(GEODCAT.distributor)
174
174
  assert org_rdf.value(RDF.type).identifier == FOAF.Organization
@@ -332,6 +332,7 @@ class DatasetToRdfTest:
332
332
  dataset = DatasetFactory(
333
333
  resources=ResourceFactory.build_batch(3), tags=["hvd", "mobilite", "test"]
334
334
  )
335
+ dataset.add_badge(HVD)
335
336
  d = dataset_to_rdf(dataset)
336
337
 
337
338
  assert d.value(DCATAP.applicableLegislation).identifier == URIRef(HVD_LEGISLATION)
@@ -349,7 +350,9 @@ class DatasetToRdfTest:
349
350
  dataset = DatasetFactory(
350
351
  resources=ResourceFactory.build_batch(3), tags=["hvd", "mobilite", "test"]
351
352
  )
353
+ dataset.add_badge(HVD)
352
354
  dataservice = DataserviceFactory(datasets=[dataset], tags=["hvd"])
355
+ dataservice.add_badge(HVD)
353
356
  d = dataset_to_rdf(dataset)
354
357
  g = d.graph
355
358
 
@@ -367,8 +370,7 @@ class DatasetToRdfTest:
367
370
  assert dataservice_as_distribution.value(DCAT.accessService).identifier == dataservice_uri
368
371
 
369
372
 
370
- @pytest.mark.usefixtures("clean_db")
371
- class RdfToDatasetTest:
373
+ class RdfToDatasetTest(PytestOnlyDBTestCase):
372
374
  def test_minimal(self):
373
375
  node = BNode()
374
376
  g = Graph()
@@ -516,6 +518,194 @@ class RdfToDatasetTest:
516
518
  assert isinstance(dataset, Dataset)
517
519
  assert dataset.harvest.modified_at is None
518
520
 
521
+ def test_contact_point_individual_vcard(self):
522
+ g = Graph()
523
+ node = URIRef("https://test.org/dataset")
524
+ g.set((node, RDF.type, DCAT.Dataset))
525
+ g.set((node, DCT.identifier, Literal(faker.uuid4())))
526
+ g.set((node, DCT.title, Literal(faker.sentence())))
527
+
528
+ contact = BNode()
529
+ g.add((contact, RDF.type, VCARD.Individual))
530
+ g.add((contact, VCARD.fn, Literal("foo")))
531
+ g.add((contact, VCARD.email, Literal("foo@example.com")))
532
+ g.add((node, DCAT.contactPoint, contact))
533
+
534
+ # Dataset needs an owner/organization for contact_points_from_rdf() to work
535
+ d = DatasetFactory.build()
536
+ d.organization = OrganizationFactory(name="organization")
537
+
538
+ dataset = dataset_from_rdf(g, d)
539
+ dataset.validate()
540
+
541
+ assert len(dataset.contact_points) == 1
542
+ assert dataset.contact_points[0].role == "contact"
543
+ assert dataset.contact_points[0].name == "foo"
544
+ assert dataset.contact_points[0].email == "foo@example.com"
545
+
546
+ def test_contact_point_individual_foaf(self):
547
+ g = Graph()
548
+ node = URIRef("https://test.org/dataset")
549
+ g.set((node, RDF.type, DCAT.Dataset))
550
+ g.set((node, DCT.identifier, Literal(faker.uuid4())))
551
+ g.set((node, DCT.title, Literal(faker.sentence())))
552
+
553
+ contact = BNode()
554
+ contact_name = Literal("foo")
555
+ contact_email = Literal("foo@example.com")
556
+ g.add((contact, RDF.type, FOAF.Person))
557
+ g.add((contact, FOAF.name, contact_name))
558
+ g.add((contact, FOAF.mbox, contact_email))
559
+ g.add((node, DCT.creator, contact))
560
+
561
+ # Dataset needs an owner/organization for contact_points_from_rdf() to work
562
+ d = DatasetFactory.build()
563
+ d.organization = OrganizationFactory(name="organization")
564
+
565
+ dataset = dataset_from_rdf(g, d)
566
+ dataset.validate()
567
+
568
+ assert len(dataset.contact_points) == 1
569
+ assert dataset.contact_points[0].role == "creator"
570
+ assert dataset.contact_points[0].name == "foo"
571
+ assert dataset.contact_points[0].email == "foo@example.com"
572
+
573
+ def test_contact_point_organization_vcard(self):
574
+ g = Graph()
575
+ node = URIRef("https://test.org/dataset")
576
+ g.set((node, RDF.type, DCAT.Dataset))
577
+ g.set((node, DCT.identifier, Literal(faker.uuid4())))
578
+ g.set((node, DCT.title, Literal(faker.sentence())))
579
+
580
+ contact = BNode()
581
+ g.add((contact, RDF.type, VCARD.Organization))
582
+ g.add((contact, VCARD.fn, Literal("foo")))
583
+ g.add((contact, VCARD.email, Literal("foo@example.com")))
584
+ g.add((node, DCAT.contactPoint, contact))
585
+
586
+ # Dataset needs an owner/organization for contact_points_from_rdf() to work
587
+ d = DatasetFactory.build()
588
+ d.organization = OrganizationFactory(name="organization")
589
+
590
+ dataset = dataset_from_rdf(g, d)
591
+ dataset.validate()
592
+
593
+ assert len(dataset.contact_points) == 1
594
+ assert dataset.contact_points[0].role == "contact"
595
+ assert dataset.contact_points[0].name == "foo"
596
+ assert dataset.contact_points[0].email == "foo@example.com"
597
+
598
+ def test_contact_point_organization_foaf(self):
599
+ g = Graph()
600
+ node = URIRef("https://test.org/dataset")
601
+ g.set((node, RDF.type, DCAT.Dataset))
602
+ g.set((node, DCT.identifier, Literal(faker.uuid4())))
603
+ g.set((node, DCT.title, Literal(faker.sentence())))
604
+
605
+ contact = BNode()
606
+ g.add((contact, RDF.type, FOAF.Organization))
607
+ g.add((contact, FOAF.name, Literal("foo")))
608
+ g.add((contact, FOAF.mbox, Literal("foo@example.com")))
609
+ g.add((node, DCT.creator, contact))
610
+
611
+ # Dataset needs an owner/organization for contact_points_from_rdf() to work
612
+ d = DatasetFactory.build()
613
+ d.organization = OrganizationFactory(name="organization")
614
+
615
+ dataset = dataset_from_rdf(g, d)
616
+ dataset.validate()
617
+
618
+ assert len(dataset.contact_points) == 1
619
+ assert dataset.contact_points[0].role == "creator"
620
+ assert dataset.contact_points[0].name == "foo"
621
+ assert dataset.contact_points[0].email == "foo@example.com"
622
+
623
+ def test_contact_point_organization_member_vcard(self):
624
+ g = Graph()
625
+ node = URIRef("https://test.org/dataset")
626
+ g.set((node, RDF.type, DCAT.Dataset))
627
+ g.set((node, DCT.identifier, Literal(faker.uuid4())))
628
+ g.set((node, DCT.title, Literal(faker.sentence())))
629
+
630
+ contact = BNode()
631
+ g.add((contact, RDF.type, VCARD.Organization))
632
+ g.add((contact, VCARD.fn, Literal("foo")))
633
+ g.add((contact, VCARD["organization-name"], Literal("bar")))
634
+ g.add((contact, VCARD.email, Literal("foo@example.com")))
635
+ g.add((node, DCAT.contactPoint, contact))
636
+
637
+ # Dataset needs an owner/organization for contact_points_from_rdf() to work
638
+ d = DatasetFactory.build()
639
+ d.organization = OrganizationFactory(name="organization")
640
+
641
+ dataset = dataset_from_rdf(g, d)
642
+ dataset.validate()
643
+
644
+ assert len(dataset.contact_points) == 1
645
+ assert dataset.contact_points[0].role == "contact"
646
+ assert dataset.contact_points[0].name == "foo"
647
+ assert dataset.contact_points[0].email == "foo@example.com"
648
+
649
+ def test_contact_point_organization_member_foaf(self):
650
+ g = Graph()
651
+ node = URIRef("https://test.org/dataset")
652
+ g.set((node, RDF.type, DCAT.Dataset))
653
+ g.set((node, DCT.identifier, Literal(faker.uuid4())))
654
+ g.set((node, DCT.title, Literal(faker.sentence())))
655
+
656
+ org = BNode()
657
+ g.add((org, RDF.type, FOAF.Organization))
658
+ g.add((org, FOAF.name, Literal("bar")))
659
+ g.add((org, FOAF.mbox, Literal("bar@example.com")))
660
+ contact = BNode()
661
+ g.add((contact, RDF.type, FOAF.Person))
662
+ g.add((contact, FOAF.name, Literal("foo")))
663
+ g.add((contact, FOAF.mbox, Literal("foo@example.com")))
664
+ g.add((contact, ORG.memberOf, org))
665
+ g.add((node, DCT.creator, contact))
666
+
667
+ # Dataset needs an owner/organization for contact_points_from_rdf() to work
668
+ d = DatasetFactory.build()
669
+ d.organization = OrganizationFactory(name="organization")
670
+
671
+ dataset = dataset_from_rdf(g, d)
672
+ dataset.validate()
673
+
674
+ assert len(dataset.contact_points) == 1
675
+ assert dataset.contact_points[0].role == "creator"
676
+ assert dataset.contact_points[0].name == "foo"
677
+ assert dataset.contact_points[0].email == "foo@example.com"
678
+
679
+ def test_contact_point_organization_member_foaf_no_mail(self):
680
+ g = Graph()
681
+ node = URIRef("https://test.org/dataset")
682
+ g.set((node, RDF.type, DCAT.Dataset))
683
+ g.set((node, DCT.identifier, Literal(faker.uuid4())))
684
+ g.set((node, DCT.title, Literal(faker.sentence())))
685
+
686
+ org = BNode()
687
+ g.add((org, RDF.type, FOAF.Organization))
688
+ g.add((org, FOAF.name, Literal("bar")))
689
+ # no organization email
690
+ contact = BNode()
691
+ g.add((contact, RDF.type, FOAF.Person))
692
+ g.add((contact, FOAF.name, Literal("foo")))
693
+ g.add((contact, FOAF.mbox, Literal("foo@example.com")))
694
+ g.add((contact, ORG.memberOf, org))
695
+ g.add((node, DCT.creator, contact))
696
+
697
+ # Dataset needs an owner/organization for contact_points_from_rdf() to work
698
+ d = DatasetFactory.build()
699
+ d.organization = OrganizationFactory(name="organization")
700
+
701
+ dataset = dataset_from_rdf(g, d)
702
+ dataset.validate()
703
+
704
+ assert len(dataset.contact_points) == 1
705
+ assert dataset.contact_points[0].role == "creator"
706
+ assert dataset.contact_points[0].name == "foo"
707
+ assert dataset.contact_points[0].email == "foo@example.com"
708
+
519
709
  def test_theme_and_tags(self):
520
710
  node = BNode()
521
711
  g = Graph()
@@ -1122,17 +1312,16 @@ class RdfToDatasetTest:
1122
1312
  assert value.language == "es"
1123
1313
 
1124
1314
 
1125
- @pytest.mark.frontend
1126
- class DatasetRdfViewsTest:
1315
+ class DatasetRdfViewsTest(PytestOnlyAPITestCase):
1127
1316
  def test_rdf_default_to_jsonld(self, client):
1128
1317
  dataset = DatasetFactory()
1129
- expected = url_for("api.dataset_rdf_format", dataset=dataset.id, format="json")
1318
+ expected = url_for("api.dataset_rdf_format", dataset=dataset.id, _format="json")
1130
1319
  response = client.get(url_for("api.dataset_rdf", dataset=dataset))
1131
1320
  assert_redirects(response, expected)
1132
1321
 
1133
1322
  def test_rdf_perform_content_negociation(self, client):
1134
1323
  dataset = DatasetFactory()
1135
- expected = url_for("api.dataset_rdf_format", dataset=dataset.id, format="xml")
1324
+ expected = url_for("api.dataset_rdf_format", dataset=dataset.id, _format="xml")
1136
1325
  url = url_for("api.dataset_rdf", dataset=dataset)
1137
1326
  headers = {"accept": "application/xml"}
1138
1327
  response = client.get(url, headers=headers)
@@ -1150,7 +1339,7 @@ class DatasetRdfViewsTest:
1150
1339
  def test_dataset_rdf_json_ld(self, client):
1151
1340
  dataset = DatasetFactory()
1152
1341
  for fmt in "json", "jsonld":
1153
- url = url_for("api.dataset_rdf_format", dataset=dataset, format=fmt)
1342
+ url = url_for("api.dataset_rdf_format", dataset=dataset, _format=fmt)
1154
1343
  response = client.get(url, headers={"Accept": "application/ld+json"})
1155
1344
  assert200(response)
1156
1345
  assert response.content_type == "application/ld+json"
@@ -1170,13 +1359,13 @@ class DatasetRdfViewsTest:
1170
1359
  )
1171
1360
  def test_dataset_rdf_formats(self, client, fmt, mime):
1172
1361
  dataset = DatasetFactory()
1173
- url = url_for("api.dataset_rdf_format", dataset=dataset, format=fmt)
1362
+ url = url_for("api.dataset_rdf_format", dataset=dataset, _format=fmt)
1174
1363
  response = client.get(url, headers={"Accept": mime})
1175
1364
  assert200(response)
1176
1365
  assert response.content_type == mime
1177
1366
 
1178
1367
 
1179
- class DatasetFromRdfUtilsTest:
1368
+ class DatasetFromRdfUtilsTest(PytestOnlyTestCase):
1180
1369
  def test_licenses_from_rdf(self):
1181
1370
  """Test a bunch of cases of licenses detection from RDF"""
1182
1371
  rdf_xml_data = """<?xml version="1.0" encoding="UTF-8"?>
@@ -4,6 +4,7 @@ import pytest
4
4
  from udata.core.dataset.factories import DatasetFactory
5
5
  from udata.core.dataset.recommendations import recommendations_add, recommendations_clean
6
6
  from udata.core.reuse.factories import ReuseFactory
7
+ from udata.tests.api import PytestOnlyDBTestCase
7
8
 
8
9
  MOCK_URL = "http://reco.net"
9
10
 
@@ -64,8 +65,7 @@ def mock_response(datasets, reuses):
64
65
  ]
65
66
 
66
67
 
67
- @pytest.mark.usefixtures("clean_db")
68
- class DatasetRecommendationsTest:
68
+ class DatasetRecommendationsTest(PytestOnlyDBTestCase):
69
69
  def test_clean(self):
70
70
  ds1 = DatasetFactory(
71
71
  extras={
@@ -16,71 +16,69 @@ from udata.harvest.csv import HarvestSourceCsvAdapter # noqa
16
16
  from udata.harvest.models import HarvestItem, HarvestJob
17
17
  from udata.harvest.tests.factories import HarvestJobFactory
18
18
  from udata.models import CommunityResource, Dataset, Discussion, Follow, Topic, Transfer
19
-
20
- pytestmark = pytest.mark.usefixtures("clean_db")
21
-
22
-
23
- def test_purge_datasets():
24
- datasets = [
25
- Dataset.objects.create(title="delete me", deleted="2016-01-01"),
26
- Dataset.objects.create(title="keep me"),
27
- ]
28
-
29
- topic = Topic.objects.create(name="test topic")
30
- for d in datasets:
31
- topic_element = TopicElement(element=d, topic=topic)
32
- topic_element.save()
33
-
34
- user = UserFactory()
35
- transfer = Transfer.objects.create(
36
- owner=user,
37
- recipient=user,
38
- subject=datasets[0],
39
- comment="comment",
40
- )
41
-
42
- discussion = DiscussionFactory(subject=datasets[0])
43
-
44
- follower = Follow.objects.create(follower=user, following=datasets[0])
45
-
46
- HarvestJobFactory(items=[HarvestItem(dataset=datasets[0])])
47
-
48
- Dataservice.objects.create(title="test", datasets=datasets)
49
-
50
- tasks.purge_datasets()
51
-
52
- assert Transfer.objects.filter(id=transfer.id).count() == 0
53
-
54
- topic = Topic.objects(name="test topic").first()
55
- topic_element = topic.elements.first()
56
- assert topic_element.element is None
57
-
58
- assert Discussion.objects.filter(id=discussion.id).count() == 0
59
- assert Follow.objects.filter(id=follower.id).count() == 0
60
- assert HarvestJob.objects.filter(items__dataset=datasets[0].id).count() == 0
61
- assert Dataservice.objects.filter(datasets=datasets[0].id).count() == 0
62
-
63
-
64
- def test_purge_datasets_community():
65
- dataset = Dataset.objects.create(title="delete me", deleted="2016-01-01")
66
- community_resource1 = CommunityResourceFactory()
67
- community_resource1.dataset = dataset
68
- community_resource1.save()
69
-
70
- tasks.purge_datasets()
71
- assert CommunityResource.objects.count() == 0
72
-
73
-
74
- @pytest.mark.usefixtures("instance_path")
75
- def test_export_csv(app):
76
- dataset = DatasetFactory()
77
- app.config["EXPORT_CSV_DATASET_ID"] = dataset.id
78
- models = app.config["EXPORT_CSV_MODELS"]
79
- tasks.export_csv()
80
- dataset = Dataset.objects.get(id=dataset.id)
81
- assert len(dataset.resources) == len(models)
82
- extras = [r.extras.get("csv-export:model") for r in dataset.resources]
83
- for model in models:
84
- assert model in extras
85
- fs_filenames = [r.fs_filename for r in dataset.resources if r.url.endswith(r.fs_filename)]
86
- assert len(fs_filenames) == len(dataset.resources)
19
+ from udata.tests.api import PytestOnlyDBTestCase
20
+
21
+
22
+ class DatasetTasksTest(PytestOnlyDBTestCase):
23
+ def test_purge_datasets(self):
24
+ datasets = [
25
+ Dataset.objects.create(title="delete me", deleted="2016-01-01"),
26
+ Dataset.objects.create(title="keep me"),
27
+ ]
28
+
29
+ topic = Topic.objects.create(name="test topic")
30
+ for d in datasets:
31
+ topic_element = TopicElement(element=d, topic=topic)
32
+ topic_element.save()
33
+
34
+ user = UserFactory()
35
+ transfer = Transfer.objects.create(
36
+ owner=user,
37
+ recipient=user,
38
+ subject=datasets[0],
39
+ comment="comment",
40
+ )
41
+
42
+ discussion = DiscussionFactory(subject=datasets[0])
43
+
44
+ follower = Follow.objects.create(follower=user, following=datasets[0])
45
+
46
+ HarvestJobFactory(items=[HarvestItem(dataset=datasets[0])])
47
+
48
+ Dataservice.objects.create(title="test", datasets=datasets)
49
+
50
+ tasks.purge_datasets()
51
+
52
+ assert Transfer.objects.filter(id=transfer.id).count() == 0
53
+
54
+ topic = Topic.objects(name="test topic").first()
55
+ topic_element = topic.elements.first()
56
+ assert topic_element.element is None
57
+
58
+ assert Discussion.objects.filter(id=discussion.id).count() == 0
59
+ assert Follow.objects.filter(id=follower.id).count() == 0
60
+ assert HarvestJob.objects.filter(items__dataset=datasets[0].id).count() == 0
61
+ assert Dataservice.objects.filter(datasets=datasets[0].id).count() == 0
62
+
63
+ def test_purge_datasets_community(self):
64
+ dataset = Dataset.objects.create(title="delete me", deleted="2016-01-01")
65
+ community_resource1 = CommunityResourceFactory()
66
+ community_resource1.dataset = dataset
67
+ community_resource1.save()
68
+
69
+ tasks.purge_datasets()
70
+ assert CommunityResource.objects.count() == 0
71
+
72
+ @pytest.mark.usefixtures("instance_path")
73
+ def test_export_csv(self, app):
74
+ dataset = DatasetFactory()
75
+ app.config["EXPORT_CSV_DATASET_ID"] = dataset.id
76
+ models = app.config["EXPORT_CSV_MODELS"]
77
+ tasks.export_csv()
78
+ dataset = Dataset.objects.get(id=dataset.id)
79
+ assert len(dataset.resources) == len(models)
80
+ extras = [r.extras.get("csv-export:model") for r in dataset.resources]
81
+ for model in models:
82
+ assert model in extras
83
+ fs_filenames = [r.fs_filename for r in dataset.resources if r.url.endswith(r.fs_filename)]
84
+ assert len(fs_filenames) == len(dataset.resources)
@@ -1,6 +1,7 @@
1
1
  import pytest
2
2
 
3
3
  from udata.core.dataset.factories import ResourceFactory
4
+ from udata.tests.api import PytestOnlyAPITestCase
4
5
 
5
6
  DUMMY_EXTRAS = {
6
7
  "analysis:parsing:finished_at": "1987-12-23T10:55:00.000000+00:00",
@@ -8,62 +9,52 @@ DUMMY_EXTRAS = {
8
9
  }
9
10
  MAX_SIZE = 50000
10
11
 
11
- pytestmark = [
12
- pytest.mark.usefixtures("clean_db"),
13
- pytest.mark.options(PLUGINS=["tabular"]),
14
- pytest.mark.frontend,
15
- ]
16
12
 
13
+ @pytest.mark.options(PLUGINS=["tabular"])
14
+ class ResourcePreviewTest(PytestOnlyAPITestCase):
15
+ def expected_url(self, rid):
16
+ return "http://preview.me/resources/{0}".format(rid)
17
17
 
18
- def expected_url(rid):
19
- return "http://preview.me/resources/{0}".format(rid)
18
+ @pytest.mark.options(TABULAR_EXPLORE_URL="http://preview.me")
19
+ def test_display_preview_for_tabular_resources(self):
20
+ resource = ResourceFactory(extras=DUMMY_EXTRAS)
21
+ assert resource.preview_url == self.expected_url(resource.id)
20
22
 
23
+ @pytest.mark.options(TABULAR_EXPLORE_URL=None)
24
+ def test_no_preview_if_no_conf(self):
25
+ assert ResourceFactory(extras=DUMMY_EXTRAS).preview_url is None
21
26
 
22
- @pytest.mark.options(TABULAR_EXPLORE_URL="http://preview.me")
23
- def test_display_preview_for_tabular_resources():
24
- resource = ResourceFactory(extras=DUMMY_EXTRAS)
25
- assert resource.preview_url == expected_url(resource.id)
27
+ @pytest.mark.options(TABULAR_EXPLORE_URL="http://preview.me")
28
+ def test_default_allow_remote_preview(self):
29
+ resources = [
30
+ ResourceFactory(extras=DUMMY_EXTRAS),
31
+ ResourceFactory(filetype="remote", extras=DUMMY_EXTRAS),
32
+ ]
26
33
 
34
+ for resource in resources:
35
+ assert resource.preview_url == self.expected_url(resource.id)
27
36
 
28
- @pytest.mark.options(TABULAR_EXPLORE_URL=None)
29
- def test_no_preview_if_no_conf():
30
- assert ResourceFactory(extras=DUMMY_EXTRAS).preview_url is None
37
+ @pytest.mark.options(
38
+ TABULAR_EXPLORE_URL="http://preview.me",
39
+ TABULAR_ALLOW_REMOTE=False,
40
+ )
41
+ def test_allow_remote_preview_false(self):
42
+ local = ResourceFactory(extras=DUMMY_EXTRAS)
43
+ remote = ResourceFactory(filetype="remote", extras=DUMMY_EXTRAS)
31
44
 
45
+ assert local.preview_url == self.expected_url(local.id)
46
+ assert remote.preview_url is None
32
47
 
33
- @pytest.mark.options(TABULAR_EXPLORE_URL="http://preview.me")
34
- def test_default_allow_remote_preview():
35
- resources = [
36
- ResourceFactory(extras=DUMMY_EXTRAS),
37
- ResourceFactory(filetype="remote", extras=DUMMY_EXTRAS),
38
- ]
48
+ @pytest.mark.options(TABULAR_EXPLORE_URL="http://preview.me")
49
+ def test_display_preview_without_max_size(self):
50
+ resource = ResourceFactory(extras=DUMMY_EXTRAS, filesize=2 * MAX_SIZE)
39
51
 
40
- for resource in resources:
41
- assert resource.preview_url == expected_url(resource.id)
52
+ assert resource.preview_url == self.expected_url(resource.id)
42
53
 
54
+ @pytest.mark.options(TABULAR_EXPLORE_URL="http://preview.me")
55
+ def test_no_preview_if_no_parsing_table_info(self):
56
+ extras = DUMMY_EXTRAS
57
+ del extras["analysis:parsing:parsing_table"]
43
58
 
44
- @pytest.mark.options(
45
- TABULAR_EXPLORE_URL="http://preview.me",
46
- TABULAR_ALLOW_REMOTE=False,
47
- )
48
- def test_allow_remote_preview_false():
49
- local = ResourceFactory(extras=DUMMY_EXTRAS)
50
- remote = ResourceFactory(filetype="remote", extras=DUMMY_EXTRAS)
51
-
52
- assert local.preview_url == expected_url(local.id)
53
- assert remote.preview_url is None
54
-
55
-
56
- @pytest.mark.options(TABULAR_EXPLORE_URL="http://preview.me")
57
- def test_display_preview_without_max_size():
58
- resource = ResourceFactory(extras=DUMMY_EXTRAS, filesize=2 * MAX_SIZE)
59
-
60
- assert resource.preview_url == expected_url(resource.id)
61
-
62
-
63
- @pytest.mark.options(TABULAR_EXPLORE_URL="http://preview.me")
64
- def test_no_preview_if_no_parsing_table_info():
65
- extras = DUMMY_EXTRAS
66
- del extras["analysis:parsing:parsing_table"]
67
-
68
- resource = ResourceFactory(extras=extras, filesize=2 * MAX_SIZE)
69
- assert resource.preview_url is None
59
+ resource = ResourceFactory(extras=extras, filesize=2 * MAX_SIZE)
60
+ assert resource.preview_url is None
@@ -3,6 +3,7 @@ import requests_mock
3
3
 
4
4
  from udata.core.dataset.factories import DatasetFactory
5
5
  from udata.core.dataset.transport import clear_datasets, map_transport_datasets
6
+ from udata.tests.api import PytestOnlyDBTestCase
6
7
 
7
8
 
8
9
  @pytest.fixture
@@ -25,8 +26,7 @@ def mock_response():
25
26
  ]
26
27
 
27
28
 
28
- @pytest.mark.usefixtures("clean_db")
29
- class TransportTasksTest:
29
+ class TransportTasksTest(PytestOnlyDBTestCase):
30
30
  @pytest.mark.options(TRANSPORT_DATASETS_URL="http://local.test/api/datasets")
31
31
  def test_map_transport_datasets(self, mock_response):
32
32
  ds1 = DatasetFactory(id="61fd29da29ea95c7bc0e1211")
@@ -1,5 +1,4 @@
1
1
  from udata.core.spatial.factories import GeoZoneFactory
2
- from udata.settings import Testing
3
2
 
4
3
 
5
4
  def create_geozones_fixtures():
@@ -19,8 +18,3 @@ def create_old_new_regions_fixtures():
19
18
  id="fr:region:76", level="fr:region", name="Languedoc-Rousillon et Midi-Pyrénées", code="76"
20
19
  )
21
20
  return lr, occitanie
22
-
23
-
24
- class TerritoriesSettings(Testing):
25
- ACTIVATE_TERRITORIES = True
26
- HANDLED_LEVELS = ("fr:commune", "fr:departement", "fr:region", "country")