udata 9.1.2.dev30355__py2.py3-none-any.whl → 9.1.2.dev30454__py2.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 (413) hide show
  1. tasks/__init__.py +109 -107
  2. tasks/helpers.py +18 -18
  3. udata/__init__.py +4 -4
  4. udata/admin/views.py +5 -5
  5. udata/api/__init__.py +111 -134
  6. udata/api/commands.py +45 -37
  7. udata/api/errors.py +5 -4
  8. udata/api/fields.py +23 -21
  9. udata/api/oauth2.py +55 -74
  10. udata/api/parsers.py +15 -15
  11. udata/api/signals.py +1 -1
  12. udata/api_fields.py +137 -89
  13. udata/app.py +58 -55
  14. udata/assets.py +5 -5
  15. udata/auth/__init__.py +37 -26
  16. udata/auth/forms.py +23 -15
  17. udata/auth/helpers.py +1 -1
  18. udata/auth/mails.py +3 -3
  19. udata/auth/password_validation.py +19 -15
  20. udata/auth/views.py +94 -68
  21. udata/commands/__init__.py +71 -69
  22. udata/commands/cache.py +7 -7
  23. udata/commands/db.py +201 -140
  24. udata/commands/dcat.py +36 -30
  25. udata/commands/fixtures.py +100 -84
  26. udata/commands/images.py +21 -20
  27. udata/commands/info.py +17 -20
  28. udata/commands/init.py +10 -10
  29. udata/commands/purge.py +12 -13
  30. udata/commands/serve.py +41 -29
  31. udata/commands/static.py +16 -18
  32. udata/commands/test.py +20 -20
  33. udata/commands/tests/fixtures.py +26 -24
  34. udata/commands/worker.py +31 -33
  35. udata/core/__init__.py +12 -12
  36. udata/core/activity/__init__.py +0 -1
  37. udata/core/activity/api.py +59 -49
  38. udata/core/activity/models.py +28 -26
  39. udata/core/activity/signals.py +1 -1
  40. udata/core/activity/tasks.py +16 -10
  41. udata/core/badges/api.py +6 -6
  42. udata/core/badges/commands.py +14 -13
  43. udata/core/badges/fields.py +8 -5
  44. udata/core/badges/forms.py +7 -4
  45. udata/core/badges/models.py +16 -31
  46. udata/core/badges/permissions.py +1 -3
  47. udata/core/badges/signals.py +2 -2
  48. udata/core/badges/tasks.py +3 -2
  49. udata/core/badges/tests/test_commands.py +10 -10
  50. udata/core/badges/tests/test_model.py +24 -31
  51. udata/core/contact_point/api.py +19 -18
  52. udata/core/contact_point/api_fields.py +21 -14
  53. udata/core/contact_point/factories.py +2 -2
  54. udata/core/contact_point/forms.py +7 -6
  55. udata/core/contact_point/models.py +3 -5
  56. udata/core/dataservices/api.py +26 -21
  57. udata/core/dataservices/factories.py +13 -11
  58. udata/core/dataservices/models.py +35 -40
  59. udata/core/dataservices/permissions.py +4 -4
  60. udata/core/dataservices/rdf.py +40 -17
  61. udata/core/dataservices/tasks.py +4 -3
  62. udata/core/dataset/actions.py +10 -10
  63. udata/core/dataset/activities.py +21 -23
  64. udata/core/dataset/api.py +321 -298
  65. udata/core/dataset/api_fields.py +443 -271
  66. udata/core/dataset/apiv2.py +305 -229
  67. udata/core/dataset/commands.py +38 -36
  68. udata/core/dataset/constants.py +61 -54
  69. udata/core/dataset/csv.py +70 -74
  70. udata/core/dataset/events.py +39 -32
  71. udata/core/dataset/exceptions.py +8 -4
  72. udata/core/dataset/factories.py +57 -65
  73. udata/core/dataset/forms.py +87 -63
  74. udata/core/dataset/models.py +336 -280
  75. udata/core/dataset/permissions.py +9 -6
  76. udata/core/dataset/preview.py +15 -17
  77. udata/core/dataset/rdf.py +156 -122
  78. udata/core/dataset/search.py +92 -77
  79. udata/core/dataset/signals.py +1 -1
  80. udata/core/dataset/tasks.py +63 -54
  81. udata/core/discussions/actions.py +5 -5
  82. udata/core/discussions/api.py +124 -120
  83. udata/core/discussions/factories.py +2 -2
  84. udata/core/discussions/forms.py +9 -7
  85. udata/core/discussions/metrics.py +1 -3
  86. udata/core/discussions/models.py +25 -24
  87. udata/core/discussions/notifications.py +18 -14
  88. udata/core/discussions/permissions.py +3 -3
  89. udata/core/discussions/signals.py +4 -4
  90. udata/core/discussions/tasks.py +24 -28
  91. udata/core/followers/api.py +32 -33
  92. udata/core/followers/models.py +9 -9
  93. udata/core/followers/signals.py +3 -3
  94. udata/core/jobs/actions.py +7 -7
  95. udata/core/jobs/api.py +99 -92
  96. udata/core/jobs/commands.py +48 -49
  97. udata/core/jobs/forms.py +11 -11
  98. udata/core/jobs/models.py +6 -6
  99. udata/core/metrics/__init__.py +2 -2
  100. udata/core/metrics/commands.py +34 -30
  101. udata/core/metrics/models.py +2 -4
  102. udata/core/metrics/signals.py +1 -1
  103. udata/core/metrics/tasks.py +3 -3
  104. udata/core/organization/activities.py +12 -15
  105. udata/core/organization/api.py +167 -174
  106. udata/core/organization/api_fields.py +183 -124
  107. udata/core/organization/apiv2.py +32 -32
  108. udata/core/organization/commands.py +20 -22
  109. udata/core/organization/constants.py +11 -11
  110. udata/core/organization/csv.py +17 -15
  111. udata/core/organization/factories.py +8 -11
  112. udata/core/organization/forms.py +32 -26
  113. udata/core/organization/metrics.py +2 -1
  114. udata/core/organization/models.py +87 -67
  115. udata/core/organization/notifications.py +18 -14
  116. udata/core/organization/permissions.py +10 -11
  117. udata/core/organization/rdf.py +14 -14
  118. udata/core/organization/search.py +30 -28
  119. udata/core/organization/signals.py +7 -7
  120. udata/core/organization/tasks.py +42 -61
  121. udata/core/owned.py +38 -27
  122. udata/core/post/api.py +82 -81
  123. udata/core/post/constants.py +8 -5
  124. udata/core/post/factories.py +4 -4
  125. udata/core/post/forms.py +13 -14
  126. udata/core/post/models.py +20 -22
  127. udata/core/post/tests/test_api.py +30 -32
  128. udata/core/reports/api.py +8 -7
  129. udata/core/reports/constants.py +1 -3
  130. udata/core/reports/models.py +10 -10
  131. udata/core/reuse/activities.py +15 -19
  132. udata/core/reuse/api.py +123 -126
  133. udata/core/reuse/api_fields.py +120 -85
  134. udata/core/reuse/apiv2.py +11 -10
  135. udata/core/reuse/constants.py +23 -23
  136. udata/core/reuse/csv.py +18 -18
  137. udata/core/reuse/factories.py +5 -9
  138. udata/core/reuse/forms.py +24 -21
  139. udata/core/reuse/models.py +55 -51
  140. udata/core/reuse/permissions.py +2 -2
  141. udata/core/reuse/search.py +49 -46
  142. udata/core/reuse/signals.py +1 -1
  143. udata/core/reuse/tasks.py +4 -5
  144. udata/core/site/api.py +47 -50
  145. udata/core/site/factories.py +2 -2
  146. udata/core/site/forms.py +4 -5
  147. udata/core/site/models.py +94 -63
  148. udata/core/site/rdf.py +14 -14
  149. udata/core/spam/api.py +16 -9
  150. udata/core/spam/constants.py +4 -4
  151. udata/core/spam/fields.py +13 -7
  152. udata/core/spam/models.py +27 -20
  153. udata/core/spam/signals.py +1 -1
  154. udata/core/spam/tests/test_spam.py +6 -5
  155. udata/core/spatial/api.py +72 -80
  156. udata/core/spatial/api_fields.py +73 -58
  157. udata/core/spatial/commands.py +67 -64
  158. udata/core/spatial/constants.py +3 -3
  159. udata/core/spatial/factories.py +37 -54
  160. udata/core/spatial/forms.py +27 -26
  161. udata/core/spatial/geoids.py +17 -17
  162. udata/core/spatial/models.py +43 -47
  163. udata/core/spatial/tasks.py +2 -1
  164. udata/core/spatial/tests/test_api.py +115 -130
  165. udata/core/spatial/tests/test_fields.py +74 -77
  166. udata/core/spatial/tests/test_geoid.py +22 -22
  167. udata/core/spatial/tests/test_models.py +5 -7
  168. udata/core/spatial/translations.py +16 -16
  169. udata/core/storages/__init__.py +16 -18
  170. udata/core/storages/api.py +66 -64
  171. udata/core/storages/tasks.py +7 -7
  172. udata/core/storages/utils.py +15 -15
  173. udata/core/storages/views.py +5 -6
  174. udata/core/tags/api.py +17 -14
  175. udata/core/tags/csv.py +4 -4
  176. udata/core/tags/models.py +8 -5
  177. udata/core/tags/tasks.py +11 -13
  178. udata/core/tags/views.py +4 -4
  179. udata/core/topic/api.py +84 -73
  180. udata/core/topic/apiv2.py +157 -127
  181. udata/core/topic/factories.py +3 -4
  182. udata/core/topic/forms.py +12 -14
  183. udata/core/topic/models.py +14 -19
  184. udata/core/topic/parsers.py +26 -26
  185. udata/core/user/activities.py +30 -29
  186. udata/core/user/api.py +151 -152
  187. udata/core/user/api_fields.py +132 -100
  188. udata/core/user/apiv2.py +7 -7
  189. udata/core/user/commands.py +38 -38
  190. udata/core/user/factories.py +8 -9
  191. udata/core/user/forms.py +14 -11
  192. udata/core/user/metrics.py +2 -2
  193. udata/core/user/models.py +68 -69
  194. udata/core/user/permissions.py +4 -5
  195. udata/core/user/rdf.py +7 -8
  196. udata/core/user/tasks.py +2 -2
  197. udata/core/user/tests/test_user_model.py +24 -16
  198. udata/cors.py +99 -0
  199. udata/db/tasks.py +2 -1
  200. udata/entrypoints.py +35 -31
  201. udata/errors.py +2 -1
  202. udata/event/values.py +6 -6
  203. udata/factories.py +2 -2
  204. udata/features/identicon/api.py +5 -6
  205. udata/features/identicon/backends.py +48 -55
  206. udata/features/identicon/tests/test_backends.py +4 -5
  207. udata/features/notifications/__init__.py +0 -1
  208. udata/features/notifications/actions.py +9 -9
  209. udata/features/notifications/api.py +17 -13
  210. udata/features/territories/__init__.py +12 -10
  211. udata/features/territories/api.py +14 -15
  212. udata/features/territories/models.py +23 -28
  213. udata/features/transfer/actions.py +8 -11
  214. udata/features/transfer/api.py +84 -77
  215. udata/features/transfer/factories.py +2 -1
  216. udata/features/transfer/models.py +11 -12
  217. udata/features/transfer/notifications.py +19 -15
  218. udata/features/transfer/permissions.py +5 -5
  219. udata/forms/__init__.py +5 -2
  220. udata/forms/fields.py +164 -172
  221. udata/forms/validators.py +19 -22
  222. udata/forms/widgets.py +9 -13
  223. udata/frontend/__init__.py +31 -26
  224. udata/frontend/csv.py +68 -58
  225. udata/frontend/markdown.py +40 -44
  226. udata/harvest/actions.py +89 -77
  227. udata/harvest/api.py +294 -238
  228. udata/harvest/backends/__init__.py +4 -4
  229. udata/harvest/backends/base.py +128 -111
  230. udata/harvest/backends/dcat.py +80 -66
  231. udata/harvest/commands.py +56 -60
  232. udata/harvest/csv.py +8 -8
  233. udata/harvest/exceptions.py +6 -3
  234. udata/harvest/filters.py +24 -23
  235. udata/harvest/forms.py +27 -28
  236. udata/harvest/models.py +88 -80
  237. udata/harvest/notifications.py +15 -10
  238. udata/harvest/signals.py +13 -13
  239. udata/harvest/tasks.py +11 -10
  240. udata/harvest/tests/factories.py +23 -24
  241. udata/harvest/tests/test_actions.py +136 -166
  242. udata/harvest/tests/test_api.py +220 -214
  243. udata/harvest/tests/test_base_backend.py +117 -112
  244. udata/harvest/tests/test_dcat_backend.py +380 -308
  245. udata/harvest/tests/test_filters.py +33 -22
  246. udata/harvest/tests/test_models.py +11 -14
  247. udata/harvest/tests/test_notifications.py +6 -7
  248. udata/harvest/tests/test_tasks.py +7 -6
  249. udata/i18n.py +237 -78
  250. udata/linkchecker/backends.py +5 -11
  251. udata/linkchecker/checker.py +23 -22
  252. udata/linkchecker/commands.py +4 -6
  253. udata/linkchecker/models.py +6 -6
  254. udata/linkchecker/tasks.py +18 -20
  255. udata/mail.py +21 -21
  256. udata/migrations/2020-07-24-remove-s-from-scope-oauth.py +9 -8
  257. udata/migrations/2020-08-24-add-fs-filename.py +9 -8
  258. udata/migrations/2020-09-28-update-reuses-datasets-metrics.py +5 -4
  259. udata/migrations/2020-10-16-migrate-ods-resources.py +9 -10
  260. udata/migrations/2021-04-08-update-schema-with-new-structure.py +8 -7
  261. udata/migrations/2021-05-27-fix-default-schema-name.py +7 -6
  262. udata/migrations/2021-07-05-remove-unused-badges.py +17 -15
  263. udata/migrations/2021-07-07-update-schema-for-community-resources.py +7 -6
  264. udata/migrations/2021-08-17-follow-integrity.py +5 -4
  265. udata/migrations/2021-08-17-harvest-integrity.py +13 -12
  266. udata/migrations/2021-08-17-oauth2client-integrity.py +5 -4
  267. udata/migrations/2021-08-17-transfer-integrity.py +5 -4
  268. udata/migrations/2021-08-17-users-integrity.py +9 -8
  269. udata/migrations/2021-12-14-reuse-topics.py +7 -6
  270. udata/migrations/2022-04-21-improve-extension-detection.py +8 -7
  271. udata/migrations/2022-09-22-clean-inactive-harvest-datasets.py +16 -14
  272. udata/migrations/2022-10-10-add-fs_uniquifier-to-user-model.py +6 -6
  273. udata/migrations/2022-10-10-migrate-harvest-extras.py +36 -26
  274. udata/migrations/2023-02-08-rename-internal-dates.py +46 -28
  275. udata/migrations/2024-01-29-fix-reuse-and-dataset-with-private-None.py +10 -8
  276. udata/migrations/2024-03-22-migrate-activity-kwargs-to-extras.py +6 -4
  277. udata/migrations/2024-06-11-fix-reuse-datasets-references.py +7 -6
  278. udata/migrations/__init__.py +123 -105
  279. udata/models/__init__.py +4 -4
  280. udata/mongo/__init__.py +13 -11
  281. udata/mongo/badges_field.py +3 -2
  282. udata/mongo/datetime_fields.py +13 -12
  283. udata/mongo/document.py +17 -16
  284. udata/mongo/engine.py +15 -16
  285. udata/mongo/errors.py +2 -1
  286. udata/mongo/extras_fields.py +30 -20
  287. udata/mongo/queryset.py +12 -12
  288. udata/mongo/slug_fields.py +38 -28
  289. udata/mongo/taglist_field.py +1 -2
  290. udata/mongo/url_field.py +5 -5
  291. udata/mongo/uuid_fields.py +4 -3
  292. udata/notifications/__init__.py +1 -1
  293. udata/notifications/mattermost.py +10 -9
  294. udata/rdf.py +167 -188
  295. udata/routing.py +40 -45
  296. udata/search/__init__.py +18 -19
  297. udata/search/adapter.py +17 -16
  298. udata/search/commands.py +44 -51
  299. udata/search/fields.py +13 -20
  300. udata/search/query.py +23 -18
  301. udata/search/result.py +9 -10
  302. udata/sentry.py +21 -19
  303. udata/settings.py +262 -198
  304. udata/sitemap.py +8 -6
  305. udata/storage/s3.py +20 -13
  306. udata/tags.py +4 -5
  307. udata/tasks.py +43 -42
  308. udata/tests/__init__.py +9 -6
  309. udata/tests/api/__init__.py +8 -6
  310. udata/tests/api/test_auth_api.py +395 -321
  311. udata/tests/api/test_base_api.py +33 -35
  312. udata/tests/api/test_contact_points.py +7 -9
  313. udata/tests/api/test_dataservices_api.py +211 -158
  314. udata/tests/api/test_datasets_api.py +823 -812
  315. udata/tests/api/test_follow_api.py +13 -15
  316. udata/tests/api/test_me_api.py +95 -112
  317. udata/tests/api/test_organizations_api.py +301 -339
  318. udata/tests/api/test_reports_api.py +35 -25
  319. udata/tests/api/test_reuses_api.py +134 -139
  320. udata/tests/api/test_swagger.py +5 -5
  321. udata/tests/api/test_tags_api.py +18 -25
  322. udata/tests/api/test_topics_api.py +94 -94
  323. udata/tests/api/test_transfer_api.py +53 -48
  324. udata/tests/api/test_user_api.py +128 -141
  325. udata/tests/apiv2/test_datasets.py +290 -198
  326. udata/tests/apiv2/test_me_api.py +10 -11
  327. udata/tests/apiv2/test_organizations.py +56 -74
  328. udata/tests/apiv2/test_swagger.py +5 -5
  329. udata/tests/apiv2/test_topics.py +69 -87
  330. udata/tests/cli/test_cli_base.py +8 -8
  331. udata/tests/cli/test_db_cli.py +21 -19
  332. udata/tests/dataservice/test_dataservice_tasks.py +8 -12
  333. udata/tests/dataset/test_csv_adapter.py +44 -35
  334. udata/tests/dataset/test_dataset_actions.py +2 -3
  335. udata/tests/dataset/test_dataset_commands.py +7 -8
  336. udata/tests/dataset/test_dataset_events.py +36 -29
  337. udata/tests/dataset/test_dataset_model.py +224 -217
  338. udata/tests/dataset/test_dataset_rdf.py +142 -131
  339. udata/tests/dataset/test_dataset_tasks.py +15 -15
  340. udata/tests/dataset/test_resource_preview.py +10 -13
  341. udata/tests/features/territories/__init__.py +9 -13
  342. udata/tests/features/territories/test_territories_api.py +71 -91
  343. udata/tests/forms/test_basic_fields.py +7 -7
  344. udata/tests/forms/test_current_user_field.py +39 -66
  345. udata/tests/forms/test_daterange_field.py +31 -39
  346. udata/tests/forms/test_dict_field.py +28 -26
  347. udata/tests/forms/test_extras_fields.py +102 -76
  348. udata/tests/forms/test_form_field.py +8 -8
  349. udata/tests/forms/test_image_field.py +33 -26
  350. udata/tests/forms/test_model_field.py +134 -123
  351. udata/tests/forms/test_model_list_field.py +7 -7
  352. udata/tests/forms/test_nested_model_list_field.py +117 -79
  353. udata/tests/forms/test_publish_as_field.py +36 -65
  354. udata/tests/forms/test_reference_field.py +34 -53
  355. udata/tests/forms/test_user_forms.py +23 -21
  356. udata/tests/forms/test_uuid_field.py +6 -10
  357. udata/tests/frontend/__init__.py +9 -6
  358. udata/tests/frontend/test_auth.py +7 -6
  359. udata/tests/frontend/test_csv.py +81 -96
  360. udata/tests/frontend/test_hooks.py +43 -43
  361. udata/tests/frontend/test_markdown.py +211 -191
  362. udata/tests/helpers.py +32 -37
  363. udata/tests/models.py +2 -2
  364. udata/tests/organization/test_csv_adapter.py +21 -16
  365. udata/tests/organization/test_notifications.py +11 -18
  366. udata/tests/organization/test_organization_model.py +13 -13
  367. udata/tests/organization/test_organization_rdf.py +29 -22
  368. udata/tests/organization/test_organization_tasks.py +16 -17
  369. udata/tests/plugin.py +79 -73
  370. udata/tests/reuse/test_reuse_model.py +21 -21
  371. udata/tests/reuse/test_reuse_task.py +11 -13
  372. udata/tests/search/__init__.py +11 -12
  373. udata/tests/search/test_adapter.py +60 -70
  374. udata/tests/search/test_query.py +16 -16
  375. udata/tests/search/test_results.py +10 -7
  376. udata/tests/site/test_site_api.py +11 -16
  377. udata/tests/site/test_site_metrics.py +20 -30
  378. udata/tests/site/test_site_model.py +4 -5
  379. udata/tests/site/test_site_rdf.py +94 -78
  380. udata/tests/test_activity.py +17 -17
  381. udata/tests/test_cors.py +62 -0
  382. udata/tests/test_discussions.py +292 -299
  383. udata/tests/test_i18n.py +37 -40
  384. udata/tests/test_linkchecker.py +91 -85
  385. udata/tests/test_mail.py +13 -17
  386. udata/tests/test_migrations.py +219 -180
  387. udata/tests/test_model.py +164 -157
  388. udata/tests/test_notifications.py +17 -17
  389. udata/tests/test_owned.py +14 -14
  390. udata/tests/test_rdf.py +25 -23
  391. udata/tests/test_routing.py +89 -93
  392. udata/tests/test_storages.py +137 -128
  393. udata/tests/test_tags.py +44 -46
  394. udata/tests/test_topics.py +7 -7
  395. udata/tests/test_transfer.py +42 -49
  396. udata/tests/test_uris.py +160 -161
  397. udata/tests/test_utils.py +79 -71
  398. udata/tests/user/test_user_rdf.py +5 -9
  399. udata/tests/workers/test_jobs_commands.py +57 -58
  400. udata/tests/workers/test_tasks_routing.py +23 -29
  401. udata/tests/workers/test_workers_api.py +125 -131
  402. udata/tests/workers/test_workers_helpers.py +6 -6
  403. udata/tracking.py +4 -6
  404. udata/uris.py +45 -46
  405. udata/utils.py +68 -66
  406. udata/wsgi.py +1 -1
  407. {udata-9.1.2.dev30355.dist-info → udata-9.1.2.dev30454.dist-info}/METADATA +7 -3
  408. udata-9.1.2.dev30454.dist-info/RECORD +706 -0
  409. udata-9.1.2.dev30355.dist-info/RECORD +0 -704
  410. {udata-9.1.2.dev30355.dist-info → udata-9.1.2.dev30454.dist-info}/LICENSE +0 -0
  411. {udata-9.1.2.dev30355.dist-info → udata-9.1.2.dev30454.dist-info}/WHEEL +0 -0
  412. {udata-9.1.2.dev30355.dist-info → udata-9.1.2.dev30454.dist-info}/entry_points.txt +0 -0
  413. {udata-9.1.2.dev30355.dist-info → udata-9.1.2.dev30454.dist-info}/top_level.txt +0 -0
udata/core/reuse/api.py CHANGED
@@ -1,176 +1,175 @@
1
- from bson.objectid import ObjectId
2
1
  from datetime import datetime
3
2
 
3
+ from bson.objectid import ObjectId
4
4
  from flask import request
5
5
 
6
- from udata.api import api, API, errors
6
+ from udata.api import API, api, errors
7
7
  from udata.api.parsers import ModelApiParser
8
8
  from udata.auth import admin_permission
9
- from udata.models import Dataset
10
- from udata.utils import id_or_404
11
-
12
9
  from udata.core.badges import api as badges_api
13
10
  from udata.core.badges.fields import badge_fields
14
11
  from udata.core.dataset.api_fields import dataset_ref_fields
15
12
  from udata.core.followers.api import FollowAPI
16
13
  from udata.core.storages.api import (
17
- uploaded_image_fields, image_parser, parse_uploaded_image
14
+ image_parser,
15
+ parse_uploaded_image,
16
+ uploaded_image_fields,
18
17
  )
18
+ from udata.models import Dataset
19
+ from udata.utils import id_or_404
19
20
 
20
21
  from .api_fields import (
21
- reuse_fields, reuse_page_fields,
22
- reuse_type_fields,
22
+ reuse_fields,
23
+ reuse_page_fields,
23
24
  reuse_suggestion_fields,
24
- reuse_topic_fields
25
+ reuse_topic_fields,
26
+ reuse_type_fields,
25
27
  )
28
+ from .constants import REUSE_TOPICS, REUSE_TYPES
26
29
  from .forms import ReuseForm
27
30
  from .models import Reuse
28
- from .constants import REUSE_TYPES, REUSE_TOPICS
29
31
  from .permissions import ReuseEditPermission
30
32
 
31
-
32
- DEFAULT_SORTING = '-created_at'
33
- SUGGEST_SORTING = '-metrics.followers'
33
+ DEFAULT_SORTING = "-created_at"
34
+ SUGGEST_SORTING = "-metrics.followers"
34
35
 
35
36
 
36
37
  class ReuseApiParser(ModelApiParser):
37
38
  sorts = {
38
- 'title': 'title',
39
- 'created': 'created_at',
40
- 'last_modified': 'last_modified',
41
- 'datasets': 'metrics.datasets',
42
- 'followers': 'metrics.followers',
43
- 'views': 'metrics.views',
39
+ "title": "title",
40
+ "created": "created_at",
41
+ "last_modified": "last_modified",
42
+ "datasets": "metrics.datasets",
43
+ "followers": "metrics.followers",
44
+ "views": "metrics.views",
44
45
  }
45
46
 
46
47
  def __init__(self):
47
48
  super().__init__()
48
- self.parser.add_argument('dataset', type=str, location='args')
49
- self.parser.add_argument('tag', type=str, location='args')
50
- self.parser.add_argument('organization', type=str, location='args')
51
- self.parser.add_argument('owner', type=str, location='args')
52
- self.parser.add_argument('type', type=str, location='args')
53
- self.parser.add_argument('topic', type=str, location='args')
54
- self.parser.add_argument('featured', type=bool, location='args')
49
+ self.parser.add_argument("dataset", type=str, location="args")
50
+ self.parser.add_argument("tag", type=str, location="args")
51
+ self.parser.add_argument("organization", type=str, location="args")
52
+ self.parser.add_argument("owner", type=str, location="args")
53
+ self.parser.add_argument("type", type=str, location="args")
54
+ self.parser.add_argument("topic", type=str, location="args")
55
+ self.parser.add_argument("featured", type=bool, location="args")
55
56
 
56
57
  @staticmethod
57
58
  def parse_filters(reuses, args):
58
- if args.get('q'):
59
+ if args.get("q"):
59
60
  # Following code splits the 'q' argument by spaces to surround
60
61
  # every word in it with quotes before rebuild it.
61
62
  # This allows the search_text method to tokenise with an AND
62
63
  # between tokens whereas an OR is used without it.
63
- phrase_query = ' '.join([f'"{elem}"' for elem in args['q'].split(' ')])
64
+ phrase_query = " ".join([f'"{elem}"' for elem in args["q"].split(" ")])
64
65
  reuses = reuses.search_text(phrase_query)
65
- if args.get('dataset'):
66
- if not ObjectId.is_valid(args['dataset']):
67
- api.abort(400, 'Dataset arg must be an identifier')
68
- reuses = reuses.filter(datasets=args['dataset'])
69
- if args.get('featured'):
70
- reuses = reuses.filter(featured=args['featured'])
71
- if args.get('topic'):
72
- reuses = reuses.filter(topic=args['topic'])
73
- if args.get('type'):
74
- reuses = reuses.filter(type=args['type'])
75
- if args.get('tag'):
76
- reuses = reuses.filter(tags=args['tag'])
77
- if args.get('organization'):
78
- if not ObjectId.is_valid(args['organization']):
79
- api.abort(400, 'Organization arg must be an identifier')
80
- reuses = reuses.filter(organization=args['organization'])
81
- if args.get('owner'):
82
- if not ObjectId.is_valid(args['owner']):
83
- api.abort(400, 'Owner arg must be an identifier')
84
- reuses = reuses.filter(owner=args['owner'])
66
+ if args.get("dataset"):
67
+ if not ObjectId.is_valid(args["dataset"]):
68
+ api.abort(400, "Dataset arg must be an identifier")
69
+ reuses = reuses.filter(datasets=args["dataset"])
70
+ if args.get("featured"):
71
+ reuses = reuses.filter(featured=args["featured"])
72
+ if args.get("topic"):
73
+ reuses = reuses.filter(topic=args["topic"])
74
+ if args.get("type"):
75
+ reuses = reuses.filter(type=args["type"])
76
+ if args.get("tag"):
77
+ reuses = reuses.filter(tags=args["tag"])
78
+ if args.get("organization"):
79
+ if not ObjectId.is_valid(args["organization"]):
80
+ api.abort(400, "Organization arg must be an identifier")
81
+ reuses = reuses.filter(organization=args["organization"])
82
+ if args.get("owner"):
83
+ if not ObjectId.is_valid(args["owner"]):
84
+ api.abort(400, "Owner arg must be an identifier")
85
+ reuses = reuses.filter(owner=args["owner"])
85
86
  return reuses
86
87
 
87
88
 
88
- ns = api.namespace('reuses', 'Reuse related operations')
89
+ ns = api.namespace("reuses", "Reuse related operations")
89
90
 
90
- common_doc = {
91
- 'params': {'reuse': 'The reuse ID or slug'}
92
- }
91
+ common_doc = {"params": {"reuse": "The reuse ID or slug"}}
93
92
 
94
93
  reuse_parser = ReuseApiParser()
95
94
 
96
95
 
97
- @ns.route('/', endpoint='reuses')
96
+ @ns.route("/", endpoint="reuses")
98
97
  class ReuseListAPI(API):
99
- @api.doc('list_reuses')
98
+ @api.doc("list_reuses")
100
99
  @api.expect(reuse_parser.parser)
101
100
  @api.marshal_with(reuse_page_fields)
102
101
  def get(self):
103
102
  args = reuse_parser.parse()
104
103
  reuses = Reuse.objects(deleted=None, private__ne=True)
105
104
  reuses = reuse_parser.parse_filters(reuses, args)
106
- sort = args['sort'] or ('$text_score' if args['q'] else None) or DEFAULT_SORTING
107
- return reuses.order_by(sort).paginate(args['page'], args['page_size'])
105
+ sort = args["sort"] or ("$text_score" if args["q"] else None) or DEFAULT_SORTING
106
+ return reuses.order_by(sort).paginate(args["page"], args["page_size"])
108
107
 
109
108
  @api.secure
110
- @api.doc('create_reuse')
109
+ @api.doc("create_reuse")
111
110
  @api.expect(reuse_fields)
112
- @api.response(400, 'Validation error')
111
+ @api.response(400, "Validation error")
113
112
  @api.marshal_with(reuse_fields)
114
113
  def post(self):
115
- '''Create a new object'''
114
+ """Create a new object"""
116
115
  form = api.validate(ReuseForm)
117
116
  return form.save(), 201
118
117
 
119
118
 
120
- @ns.route('/<reuse:reuse>/', endpoint='reuse', doc=common_doc)
121
- @api.response(404, 'Reuse not found')
122
- @api.response(410, 'Reuse has been deleted')
119
+ @ns.route("/<reuse:reuse>/", endpoint="reuse", doc=common_doc)
120
+ @api.response(404, "Reuse not found")
121
+ @api.response(410, "Reuse has been deleted")
123
122
  class ReuseAPI(API):
124
- @api.doc('get_reuse')
123
+ @api.doc("get_reuse")
125
124
  @api.marshal_with(reuse_fields)
126
125
  def get(self, reuse):
127
- '''Fetch a given reuse'''
126
+ """Fetch a given reuse"""
128
127
  if reuse.deleted and not ReuseEditPermission(reuse).can():
129
- api.abort(410, 'This reuse has been deleted')
128
+ api.abort(410, "This reuse has been deleted")
130
129
  return reuse
131
130
 
132
131
  @api.secure
133
- @api.doc('update_reuse')
132
+ @api.doc("update_reuse")
134
133
  @api.expect(reuse_fields)
135
134
  @api.marshal_with(reuse_fields)
136
135
  @api.response(400, errors.VALIDATION_ERROR)
137
136
  def put(self, reuse):
138
- '''Update a given reuse'''
139
- request_deleted = request.json.get('deleted', True)
137
+ """Update a given reuse"""
138
+ request_deleted = request.json.get("deleted", True)
140
139
  if reuse.deleted and request_deleted is not None:
141
- api.abort(410, 'This reuse has been deleted')
140
+ api.abort(410, "This reuse has been deleted")
142
141
  ReuseEditPermission(reuse).test()
143
142
  form = api.validate(ReuseForm, reuse)
144
143
  return form.save()
145
144
 
146
145
  @api.secure
147
- @api.doc('delete_reuse')
148
- @api.response(204, 'Reuse deleted')
146
+ @api.doc("delete_reuse")
147
+ @api.response(204, "Reuse deleted")
149
148
  def delete(self, reuse):
150
- '''Delete a given reuse'''
149
+ """Delete a given reuse"""
151
150
  if reuse.deleted:
152
- api.abort(410, 'This reuse has been deleted')
151
+ api.abort(410, "This reuse has been deleted")
153
152
  ReuseEditPermission(reuse).test()
154
153
  reuse.deleted = datetime.utcnow()
155
154
  reuse.save()
156
- return '', 204
155
+ return "", 204
157
156
 
158
157
 
159
- @ns.route('/<reuse:reuse>/datasets/', endpoint='reuse_add_dataset')
158
+ @ns.route("/<reuse:reuse>/datasets/", endpoint="reuse_add_dataset")
160
159
  class ReuseDatasetsAPI(API):
161
160
  @api.secure
162
- @api.doc('reuse_add_dataset', **common_doc)
161
+ @api.doc("reuse_add_dataset", **common_doc)
163
162
  @api.expect(dataset_ref_fields)
164
- @api.response(200, 'The dataset is already present', reuse_fields)
163
+ @api.response(200, "The dataset is already present", reuse_fields)
165
164
  @api.marshal_with(reuse_fields, code=201)
166
165
  def post(self, reuse):
167
- '''Add a dataset to a given reuse'''
168
- if 'id' not in request.json:
169
- api.abort(400, 'Expect a dataset identifier')
166
+ """Add a dataset to a given reuse"""
167
+ if "id" not in request.json:
168
+ api.abort(400, "Expect a dataset identifier")
170
169
  try:
171
- dataset = Dataset.objects.get_or_404(id=id_or_404(request.json['id']))
170
+ dataset = Dataset.objects.get_or_404(id=id_or_404(request.json["id"]))
172
171
  except Dataset.DoesNotExist:
173
- msg = 'Dataset {0} does not exists'.format(request.json['id'])
172
+ msg = "Dataset {0} does not exists".format(request.json["id"])
174
173
  api.abort(404, msg)
175
174
  if dataset in reuse.datasets:
176
175
  return reuse
@@ -179,102 +178,102 @@ class ReuseDatasetsAPI(API):
179
178
  return reuse, 201
180
179
 
181
180
 
182
- @ns.route('/badges/', endpoint='available_reuse_badges')
181
+ @ns.route("/badges/", endpoint="available_reuse_badges")
183
182
  class AvailableDatasetBadgesAPI(API):
184
- @api.doc('available_reuse_badges')
183
+ @api.doc("available_reuse_badges")
185
184
  def get(self):
186
- '''List all available reuse badges and their labels'''
185
+ """List all available reuse badges and their labels"""
187
186
  return Reuse.__badges__
188
187
 
189
188
 
190
- @ns.route('/<reuse:reuse>/badges/', endpoint='reuse_badges')
189
+ @ns.route("/<reuse:reuse>/badges/", endpoint="reuse_badges")
191
190
  class ReuseBadgesAPI(API):
192
- @api.doc('add_reuse_badge', **common_doc)
191
+ @api.doc("add_reuse_badge", **common_doc)
193
192
  @api.expect(badge_fields)
194
193
  @api.marshal_with(badge_fields)
195
194
  @api.secure(admin_permission)
196
195
  def post(self, reuse):
197
- '''Create a new badge for a given reuse'''
196
+ """Create a new badge for a given reuse"""
198
197
  return badges_api.add(reuse)
199
198
 
200
199
 
201
- @ns.route('/<reuse:reuse>/badges/<badge_kind>/', endpoint='reuse_badge')
200
+ @ns.route("/<reuse:reuse>/badges/<badge_kind>/", endpoint="reuse_badge")
202
201
  class ReuseBadgeAPI(API):
203
- @api.doc('delete_reuse_badge', **common_doc)
202
+ @api.doc("delete_reuse_badge", **common_doc)
204
203
  @api.secure(admin_permission)
205
204
  def delete(self, reuse, badge_kind):
206
- '''Delete a badge for a given reuse'''
205
+ """Delete a badge for a given reuse"""
207
206
  return badges_api.remove(reuse, badge_kind)
208
207
 
209
208
 
210
- @ns.route('/<reuse:reuse>/featured/', endpoint='reuse_featured')
209
+ @ns.route("/<reuse:reuse>/featured/", endpoint="reuse_featured")
211
210
  @api.doc(**common_doc)
212
211
  class ReuseFeaturedAPI(API):
213
- @api.doc('feature_reuse')
212
+ @api.doc("feature_reuse")
214
213
  @api.secure(admin_permission)
215
214
  @api.marshal_with(reuse_fields)
216
215
  def post(self, reuse):
217
- '''Mark a reuse as featured'''
216
+ """Mark a reuse as featured"""
218
217
  reuse.featured = True
219
218
  reuse.save()
220
219
  return reuse
221
220
 
222
- @api.doc('unfeature_reuse')
221
+ @api.doc("unfeature_reuse")
223
222
  @api.secure(admin_permission)
224
223
  @api.marshal_with(reuse_fields)
225
224
  def delete(self, reuse):
226
- '''Unmark a reuse as featured'''
225
+ """Unmark a reuse as featured"""
227
226
  reuse.featured = False
228
227
  reuse.save()
229
228
  return reuse
230
229
 
231
230
 
232
- @ns.route('/<id>/followers/', endpoint='reuse_followers')
233
- @ns.doc(get={'id': 'list_reuse_followers'},
234
- post={'id': 'follow_reuse'},
235
- delete={'id': 'unfollow_reuse'})
231
+ @ns.route("/<id>/followers/", endpoint="reuse_followers")
232
+ @ns.doc(
233
+ get={"id": "list_reuse_followers"}, post={"id": "follow_reuse"}, delete={"id": "unfollow_reuse"}
234
+ )
236
235
  class FollowReuseAPI(FollowAPI):
237
236
  model = Reuse
238
237
 
239
238
 
240
239
  suggest_parser = api.parser()
241
240
  suggest_parser.add_argument(
242
- 'q', help='The string to autocomplete/suggest', location='args',
243
- required=True)
241
+ "q", help="The string to autocomplete/suggest", location="args", required=True
242
+ )
244
243
  suggest_parser.add_argument(
245
- 'size', type=int, help='The amount of suggestion to fetch',
246
- location='args', default=10)
244
+ "size", type=int, help="The amount of suggestion to fetch", location="args", default=10
245
+ )
247
246
 
248
247
 
249
- @ns.route('/suggest/', endpoint='suggest_reuses')
248
+ @ns.route("/suggest/", endpoint="suggest_reuses")
250
249
  class ReusesSuggestAPI(API):
251
- @api.doc('suggest_reuses')
250
+ @api.doc("suggest_reuses")
252
251
  @api.expect(suggest_parser)
253
252
  @api.marshal_list_with(reuse_suggestion_fields)
254
253
  def get(self):
255
- '''Reuses suggest endpoint using mongoDB contains'''
254
+ """Reuses suggest endpoint using mongoDB contains"""
256
255
  args = suggest_parser.parse_args()
257
- reuses = Reuse.objects(deleted=None, private__ne=True, title__icontains=args['q'])
256
+ reuses = Reuse.objects(deleted=None, private__ne=True, title__icontains=args["q"])
258
257
  return [
259
258
  {
260
- 'id': reuse.id,
261
- 'title': reuse.title,
262
- 'slug': reuse.slug,
263
- 'image_url': reuse.image,
259
+ "id": reuse.id,
260
+ "title": reuse.title,
261
+ "slug": reuse.slug,
262
+ "image_url": reuse.image,
264
263
  }
265
- for reuse in reuses.order_by(SUGGEST_SORTING).limit(args['size'])
264
+ for reuse in reuses.order_by(SUGGEST_SORTING).limit(args["size"])
266
265
  ]
267
266
 
268
267
 
269
- @ns.route('/<reuse:reuse>/image', endpoint='reuse_image')
268
+ @ns.route("/<reuse:reuse>/image", endpoint="reuse_image")
270
269
  @api.doc(**common_doc)
271
270
  class ReuseImageAPI(API):
272
271
  @api.secure
273
- @api.doc('reuse_image')
272
+ @api.doc("reuse_image")
274
273
  @api.expect(image_parser) # Swagger 2.0 does not support formData at path level
275
274
  @api.marshal_with(uploaded_image_fields)
276
275
  def post(self, reuse):
277
- '''Upload a new reuse image'''
276
+ """Upload a new reuse image"""
278
277
  ReuseEditPermission(reuse).test()
279
278
  parse_uploaded_image(reuse.image)
280
279
  reuse.save()
@@ -282,21 +281,19 @@ class ReuseImageAPI(API):
282
281
  return reuse
283
282
 
284
283
 
285
- @ns.route('/types/', endpoint='reuse_types')
284
+ @ns.route("/types/", endpoint="reuse_types")
286
285
  class ReuseTypesAPI(API):
287
- @api.doc('reuse_types')
286
+ @api.doc("reuse_types")
288
287
  @api.marshal_list_with(reuse_type_fields)
289
288
  def get(self):
290
- '''List all reuse types'''
291
- return [{'id': id, 'label': label}
292
- for id, label in REUSE_TYPES.items()]
289
+ """List all reuse types"""
290
+ return [{"id": id, "label": label} for id, label in REUSE_TYPES.items()]
293
291
 
294
292
 
295
- @ns.route('/topics/', endpoint='reuse_topics')
293
+ @ns.route("/topics/", endpoint="reuse_topics")
296
294
  class ReuseTopicsAPI(API):
297
- @api.doc('reuse_topics')
295
+ @api.doc("reuse_topics")
298
296
  @api.marshal_list_with(reuse_topic_fields)
299
297
  def get(self):
300
- '''List all reuse topics'''
301
- return [{'id': id, 'label': label}
302
- for id, label in REUSE_TOPICS.items()]
298
+ """List all reuse topics"""
299
+ return [{"id": id, "label": label} for id, label in REUSE_TOPICS.items()]