udata 9.1.2.dev30355__py2.py3-none-any.whl → 9.1.2.dev30382__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 (425) 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 +135 -124
  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 +56 -54
  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/db/tasks.py +2 -1
  199. udata/entrypoints.py +35 -31
  200. udata/errors.py +2 -1
  201. udata/event/values.py +6 -6
  202. udata/factories.py +2 -2
  203. udata/features/identicon/api.py +5 -6
  204. udata/features/identicon/backends.py +48 -55
  205. udata/features/identicon/tests/test_backends.py +4 -5
  206. udata/features/notifications/__init__.py +0 -1
  207. udata/features/notifications/actions.py +9 -9
  208. udata/features/notifications/api.py +17 -13
  209. udata/features/territories/__init__.py +12 -10
  210. udata/features/territories/api.py +14 -15
  211. udata/features/territories/models.py +23 -28
  212. udata/features/transfer/actions.py +8 -11
  213. udata/features/transfer/api.py +84 -77
  214. udata/features/transfer/factories.py +2 -1
  215. udata/features/transfer/models.py +11 -12
  216. udata/features/transfer/notifications.py +19 -15
  217. udata/features/transfer/permissions.py +5 -5
  218. udata/forms/__init__.py +5 -2
  219. udata/forms/fields.py +164 -172
  220. udata/forms/validators.py +19 -22
  221. udata/forms/widgets.py +9 -13
  222. udata/frontend/__init__.py +31 -26
  223. udata/frontend/csv.py +68 -58
  224. udata/frontend/markdown.py +40 -44
  225. udata/harvest/actions.py +89 -77
  226. udata/harvest/api.py +294 -238
  227. udata/harvest/backends/__init__.py +4 -4
  228. udata/harvest/backends/base.py +128 -111
  229. udata/harvest/backends/dcat.py +80 -66
  230. udata/harvest/commands.py +56 -60
  231. udata/harvest/csv.py +8 -8
  232. udata/harvest/exceptions.py +6 -3
  233. udata/harvest/filters.py +24 -23
  234. udata/harvest/forms.py +27 -28
  235. udata/harvest/models.py +88 -80
  236. udata/harvest/notifications.py +15 -10
  237. udata/harvest/signals.py +13 -13
  238. udata/harvest/tasks.py +11 -10
  239. udata/harvest/tests/factories.py +23 -24
  240. udata/harvest/tests/test_actions.py +136 -166
  241. udata/harvest/tests/test_api.py +220 -214
  242. udata/harvest/tests/test_base_backend.py +117 -112
  243. udata/harvest/tests/test_dcat_backend.py +380 -308
  244. udata/harvest/tests/test_filters.py +33 -22
  245. udata/harvest/tests/test_models.py +11 -14
  246. udata/harvest/tests/test_notifications.py +6 -7
  247. udata/harvest/tests/test_tasks.py +7 -6
  248. udata/i18n.py +237 -78
  249. udata/linkchecker/backends.py +5 -11
  250. udata/linkchecker/checker.py +23 -22
  251. udata/linkchecker/commands.py +4 -6
  252. udata/linkchecker/models.py +6 -6
  253. udata/linkchecker/tasks.py +18 -20
  254. udata/mail.py +21 -21
  255. udata/migrations/2020-07-24-remove-s-from-scope-oauth.py +9 -8
  256. udata/migrations/2020-08-24-add-fs-filename.py +9 -8
  257. udata/migrations/2020-09-28-update-reuses-datasets-metrics.py +5 -4
  258. udata/migrations/2020-10-16-migrate-ods-resources.py +9 -10
  259. udata/migrations/2021-04-08-update-schema-with-new-structure.py +8 -7
  260. udata/migrations/2021-05-27-fix-default-schema-name.py +7 -6
  261. udata/migrations/2021-07-05-remove-unused-badges.py +17 -15
  262. udata/migrations/2021-07-07-update-schema-for-community-resources.py +7 -6
  263. udata/migrations/2021-08-17-follow-integrity.py +5 -4
  264. udata/migrations/2021-08-17-harvest-integrity.py +13 -12
  265. udata/migrations/2021-08-17-oauth2client-integrity.py +5 -4
  266. udata/migrations/2021-08-17-transfer-integrity.py +5 -4
  267. udata/migrations/2021-08-17-users-integrity.py +9 -8
  268. udata/migrations/2021-12-14-reuse-topics.py +7 -6
  269. udata/migrations/2022-04-21-improve-extension-detection.py +8 -7
  270. udata/migrations/2022-09-22-clean-inactive-harvest-datasets.py +16 -14
  271. udata/migrations/2022-10-10-add-fs_uniquifier-to-user-model.py +6 -6
  272. udata/migrations/2022-10-10-migrate-harvest-extras.py +36 -26
  273. udata/migrations/2023-02-08-rename-internal-dates.py +46 -28
  274. udata/migrations/2024-01-29-fix-reuse-and-dataset-with-private-None.py +10 -8
  275. udata/migrations/2024-03-22-migrate-activity-kwargs-to-extras.py +6 -4
  276. udata/migrations/2024-06-11-fix-reuse-datasets-references.py +7 -6
  277. udata/migrations/__init__.py +123 -105
  278. udata/models/__init__.py +4 -4
  279. udata/mongo/__init__.py +13 -11
  280. udata/mongo/badges_field.py +3 -2
  281. udata/mongo/datetime_fields.py +13 -12
  282. udata/mongo/document.py +17 -16
  283. udata/mongo/engine.py +15 -16
  284. udata/mongo/errors.py +2 -1
  285. udata/mongo/extras_fields.py +30 -20
  286. udata/mongo/queryset.py +12 -12
  287. udata/mongo/slug_fields.py +38 -28
  288. udata/mongo/taglist_field.py +1 -2
  289. udata/mongo/url_field.py +5 -5
  290. udata/mongo/uuid_fields.py +4 -3
  291. udata/notifications/__init__.py +1 -1
  292. udata/notifications/mattermost.py +10 -9
  293. udata/rdf.py +167 -188
  294. udata/routing.py +40 -45
  295. udata/search/__init__.py +18 -19
  296. udata/search/adapter.py +17 -16
  297. udata/search/commands.py +44 -51
  298. udata/search/fields.py +13 -20
  299. udata/search/query.py +23 -18
  300. udata/search/result.py +9 -10
  301. udata/sentry.py +21 -19
  302. udata/settings.py +262 -198
  303. udata/sitemap.py +8 -6
  304. udata/static/chunks/{11.e9b9ca1f3e03d4020377.js → 11.52e531c19f8de80c00cf.js} +3 -3
  305. udata/static/chunks/{11.e9b9ca1f3e03d4020377.js.map → 11.52e531c19f8de80c00cf.js.map} +1 -1
  306. udata/static/chunks/{13.038c0d9aa0dfa0181c4b.js → 13.c3343a7f1070061c0e10.js} +2 -2
  307. udata/static/chunks/{13.038c0d9aa0dfa0181c4b.js.map → 13.c3343a7f1070061c0e10.js.map} +1 -1
  308. udata/static/chunks/{16.0baa2b64a74a2dcde25c.js → 16.8fa42440ad75ca172e6d.js} +2 -2
  309. udata/static/chunks/{16.0baa2b64a74a2dcde25c.js.map → 16.8fa42440ad75ca172e6d.js.map} +1 -1
  310. udata/static/chunks/{19.350a9f150b074b4ecefa.js → 19.9c6c8412729cd6d59cfa.js} +3 -3
  311. udata/static/chunks/{19.350a9f150b074b4ecefa.js.map → 19.9c6c8412729cd6d59cfa.js.map} +1 -1
  312. udata/static/chunks/{5.6ebbce2b9b3e696d3da5.js → 5.71d15c2e4f21feee2a9a.js} +3 -3
  313. udata/static/chunks/{5.6ebbce2b9b3e696d3da5.js.map → 5.71d15c2e4f21feee2a9a.js.map} +1 -1
  314. udata/static/chunks/{6.d8a5f7b017bcbd083641.js → 6.9139dc098b8ea640b890.js} +3 -3
  315. udata/static/chunks/{6.d8a5f7b017bcbd083641.js.map → 6.9139dc098b8ea640b890.js.map} +1 -1
  316. udata/static/common.js +1 -1
  317. udata/static/common.js.map +1 -1
  318. udata/storage/s3.py +20 -13
  319. udata/tags.py +4 -5
  320. udata/tasks.py +43 -42
  321. udata/tests/__init__.py +9 -6
  322. udata/tests/api/__init__.py +5 -6
  323. udata/tests/api/test_auth_api.py +395 -321
  324. udata/tests/api/test_base_api.py +31 -33
  325. udata/tests/api/test_contact_points.py +7 -9
  326. udata/tests/api/test_dataservices_api.py +211 -158
  327. udata/tests/api/test_datasets_api.py +823 -812
  328. udata/tests/api/test_follow_api.py +13 -15
  329. udata/tests/api/test_me_api.py +95 -112
  330. udata/tests/api/test_organizations_api.py +301 -339
  331. udata/tests/api/test_reports_api.py +35 -25
  332. udata/tests/api/test_reuses_api.py +134 -139
  333. udata/tests/api/test_swagger.py +5 -5
  334. udata/tests/api/test_tags_api.py +18 -25
  335. udata/tests/api/test_topics_api.py +94 -94
  336. udata/tests/api/test_transfer_api.py +53 -48
  337. udata/tests/api/test_user_api.py +128 -141
  338. udata/tests/apiv2/test_datasets.py +290 -198
  339. udata/tests/apiv2/test_me_api.py +10 -11
  340. udata/tests/apiv2/test_organizations.py +56 -74
  341. udata/tests/apiv2/test_swagger.py +5 -5
  342. udata/tests/apiv2/test_topics.py +69 -87
  343. udata/tests/cli/test_cli_base.py +8 -8
  344. udata/tests/cli/test_db_cli.py +21 -19
  345. udata/tests/dataservice/test_dataservice_tasks.py +8 -12
  346. udata/tests/dataset/test_csv_adapter.py +44 -35
  347. udata/tests/dataset/test_dataset_actions.py +2 -3
  348. udata/tests/dataset/test_dataset_commands.py +7 -8
  349. udata/tests/dataset/test_dataset_events.py +36 -29
  350. udata/tests/dataset/test_dataset_model.py +224 -217
  351. udata/tests/dataset/test_dataset_rdf.py +142 -131
  352. udata/tests/dataset/test_dataset_tasks.py +15 -15
  353. udata/tests/dataset/test_resource_preview.py +10 -13
  354. udata/tests/features/territories/__init__.py +9 -13
  355. udata/tests/features/territories/test_territories_api.py +71 -91
  356. udata/tests/forms/test_basic_fields.py +7 -7
  357. udata/tests/forms/test_current_user_field.py +39 -66
  358. udata/tests/forms/test_daterange_field.py +31 -39
  359. udata/tests/forms/test_dict_field.py +28 -26
  360. udata/tests/forms/test_extras_fields.py +102 -76
  361. udata/tests/forms/test_form_field.py +8 -8
  362. udata/tests/forms/test_image_field.py +33 -26
  363. udata/tests/forms/test_model_field.py +134 -123
  364. udata/tests/forms/test_model_list_field.py +7 -7
  365. udata/tests/forms/test_nested_model_list_field.py +117 -79
  366. udata/tests/forms/test_publish_as_field.py +36 -65
  367. udata/tests/forms/test_reference_field.py +34 -53
  368. udata/tests/forms/test_user_forms.py +23 -21
  369. udata/tests/forms/test_uuid_field.py +6 -10
  370. udata/tests/frontend/__init__.py +9 -6
  371. udata/tests/frontend/test_auth.py +7 -6
  372. udata/tests/frontend/test_csv.py +81 -96
  373. udata/tests/frontend/test_hooks.py +43 -43
  374. udata/tests/frontend/test_markdown.py +211 -191
  375. udata/tests/helpers.py +32 -37
  376. udata/tests/models.py +2 -2
  377. udata/tests/organization/test_csv_adapter.py +21 -16
  378. udata/tests/organization/test_notifications.py +11 -18
  379. udata/tests/organization/test_organization_model.py +13 -13
  380. udata/tests/organization/test_organization_rdf.py +29 -22
  381. udata/tests/organization/test_organization_tasks.py +16 -17
  382. udata/tests/plugin.py +76 -73
  383. udata/tests/reuse/test_reuse_model.py +21 -21
  384. udata/tests/reuse/test_reuse_task.py +11 -13
  385. udata/tests/search/__init__.py +11 -12
  386. udata/tests/search/test_adapter.py +60 -70
  387. udata/tests/search/test_query.py +16 -16
  388. udata/tests/search/test_results.py +10 -7
  389. udata/tests/site/test_site_api.py +11 -16
  390. udata/tests/site/test_site_metrics.py +20 -30
  391. udata/tests/site/test_site_model.py +4 -5
  392. udata/tests/site/test_site_rdf.py +94 -78
  393. udata/tests/test_activity.py +17 -17
  394. udata/tests/test_discussions.py +292 -299
  395. udata/tests/test_i18n.py +37 -40
  396. udata/tests/test_linkchecker.py +91 -85
  397. udata/tests/test_mail.py +13 -17
  398. udata/tests/test_migrations.py +219 -180
  399. udata/tests/test_model.py +164 -157
  400. udata/tests/test_notifications.py +17 -17
  401. udata/tests/test_owned.py +14 -14
  402. udata/tests/test_rdf.py +25 -23
  403. udata/tests/test_routing.py +89 -93
  404. udata/tests/test_storages.py +137 -128
  405. udata/tests/test_tags.py +44 -46
  406. udata/tests/test_topics.py +7 -7
  407. udata/tests/test_transfer.py +42 -49
  408. udata/tests/test_uris.py +160 -161
  409. udata/tests/test_utils.py +79 -71
  410. udata/tests/user/test_user_rdf.py +5 -9
  411. udata/tests/workers/test_jobs_commands.py +57 -58
  412. udata/tests/workers/test_tasks_routing.py +23 -29
  413. udata/tests/workers/test_workers_api.py +125 -131
  414. udata/tests/workers/test_workers_helpers.py +6 -6
  415. udata/tracking.py +4 -6
  416. udata/uris.py +45 -46
  417. udata/utils.py +68 -66
  418. udata/wsgi.py +1 -1
  419. {udata-9.1.2.dev30355.dist-info → udata-9.1.2.dev30382.dist-info}/METADATA +3 -2
  420. udata-9.1.2.dev30382.dist-info/RECORD +704 -0
  421. udata-9.1.2.dev30355.dist-info/RECORD +0 -704
  422. {udata-9.1.2.dev30355.dist-info → udata-9.1.2.dev30382.dist-info}/LICENSE +0 -0
  423. {udata-9.1.2.dev30355.dist-info → udata-9.1.2.dev30382.dist-info}/WHEEL +0 -0
  424. {udata-9.1.2.dev30355.dist-info → udata-9.1.2.dev30382.dist-info}/entry_points.txt +0 -0
  425. {udata-9.1.2.dev30355.dist-info → udata-9.1.2.dev30382.dist-info}/top_level.txt +0 -0
udata/core/user/api.py CHANGED
@@ -1,23 +1,22 @@
1
1
  from flask_security import current_user, logout_user
2
2
  from slugify import slugify
3
3
 
4
- from udata.api import api, API
4
+ from udata.api import API, api
5
5
  from udata.api.parsers import ModelApiParser
6
- from udata.core import storages
7
6
  from udata.auth import admin_permission
8
- from udata.models import CommunityResource, Dataset, Reuse, User
9
-
10
- from udata.core.dataset.api_fields import (
11
- community_resource_fields, dataset_fields
12
- )
13
- from udata.core.followers.api import FollowAPI
7
+ from udata.core import storages
8
+ from udata.core.dataset.api_fields import community_resource_fields, dataset_fields
14
9
  from udata.core.discussions.actions import discussions_for
15
10
  from udata.core.discussions.api import discussion_fields
11
+ from udata.core.followers.api import FollowAPI
16
12
  from udata.core.reuse.api_fields import reuse_fields
17
13
  from udata.core.storages.api import (
18
- uploaded_image_fields, image_parser, parse_uploaded_image
14
+ image_parser,
15
+ parse_uploaded_image,
16
+ uploaded_image_fields,
19
17
  )
20
18
  from udata.core.user.models import Role
19
+ from udata.models import CommunityResource, Dataset, Reuse, User
21
20
 
22
21
  from .api_fields import (
23
22
  apikey_fields,
@@ -26,331 +25,332 @@ from .api_fields import (
26
25
  user_fields,
27
26
  user_page_fields,
28
27
  user_role_fields,
29
- user_suggestion_fields
28
+ user_suggestion_fields,
30
29
  )
31
- from .forms import UserProfileForm, UserProfileAdminForm
32
-
30
+ from .forms import UserProfileAdminForm, UserProfileForm
33
31
 
34
- DEFAULT_SORTING = '-created_at'
32
+ DEFAULT_SORTING = "-created_at"
35
33
 
36
34
 
37
35
  class UserApiParser(ModelApiParser):
38
36
  sorts = {
39
- 'last_name': 'last_name',
40
- 'first_name': 'first_name',
41
- 'datasets': 'metrics.datasets',
42
- 'reuses': 'metrics.reuses',
43
- 'followers': 'metrics.followers',
44
- 'views': 'metrics.views',
45
- 'created': 'created_at',
37
+ "last_name": "last_name",
38
+ "first_name": "first_name",
39
+ "datasets": "metrics.datasets",
40
+ "reuses": "metrics.reuses",
41
+ "followers": "metrics.followers",
42
+ "views": "metrics.views",
43
+ "created": "created_at",
46
44
  }
47
45
 
48
46
 
49
- ns = api.namespace('users', 'User related operations')
50
- me = api.namespace('me', 'Connected user related operations')
47
+ ns = api.namespace("users", "User related operations")
48
+ me = api.namespace("me", "Connected user related operations")
51
49
 
52
50
  user_parser = UserApiParser()
53
51
 
54
52
  filter_parser = api.parser()
55
53
  filter_parser.add_argument(
56
- 'q', type=str, help='The string to filter items',
57
- location='args', required=False)
54
+ "q", type=str, help="The string to filter items", location="args", required=False
55
+ )
58
56
 
59
57
 
60
- @me.route('/', endpoint='me')
58
+ @me.route("/", endpoint="me")
61
59
  class MeAPI(API):
62
60
  @api.secure
63
- @api.doc('get_me')
61
+ @api.doc("get_me")
64
62
  @api.marshal_with(me_fields)
65
63
  def get(self):
66
- '''Fetch the current user (me) identity'''
64
+ """Fetch the current user (me) identity"""
67
65
  return current_user._get_current_object()
68
66
 
69
67
  @api.secure
70
- @api.doc('update_me')
68
+ @api.doc("update_me")
71
69
  @api.expect(me_fields)
72
70
  @api.marshal_with(me_fields)
73
- @api.response(400, 'Validation error')
71
+ @api.response(400, "Validation error")
74
72
  def put(self, **kwargs):
75
- '''Update my profile'''
73
+ """Update my profile"""
76
74
  user = current_user._get_current_object()
77
75
  form = api.validate(UserProfileForm, user)
78
76
  return form.save()
79
77
 
80
78
  @api.secure
81
- @api.doc('delete_me')
82
- @api.response(204, 'Object deleted')
79
+ @api.doc("delete_me")
80
+ @api.response(204, "Object deleted")
83
81
  def delete(self, **kwargs):
84
- '''Delete my profile'''
82
+ """Delete my profile"""
85
83
  user = current_user._get_current_object()
86
84
  user.mark_as_deleted()
87
85
  logout_user()
88
- return '', 204
86
+ return "", 204
89
87
 
90
88
 
91
- @me.route('/avatar', endpoint='my_avatar')
89
+ @me.route("/avatar", endpoint="my_avatar")
92
90
  class AvatarAPI(API):
93
91
  @api.secure
94
- @api.doc('my_avatar')
92
+ @api.doc("my_avatar")
95
93
  @api.expect(image_parser)
96
94
  @api.marshal_with(uploaded_image_fields)
97
95
  def post(self):
98
- '''Upload a new avatar'''
96
+ """Upload a new avatar"""
99
97
  parse_uploaded_image(current_user.avatar)
100
98
  current_user.save()
101
- return {'image': current_user.avatar}
99
+ return {"image": current_user.avatar}
102
100
 
103
101
 
104
- @me.route('/reuses/', endpoint='my_reuses')
102
+ @me.route("/reuses/", endpoint="my_reuses")
105
103
  class MyReusesAPI(API):
106
104
  @api.secure
107
- @api.doc('my_reuses')
105
+ @api.doc("my_reuses")
108
106
  @api.marshal_list_with(reuse_fields)
109
107
  def get(self):
110
- '''List all my reuses (including private ones)'''
108
+ """List all my reuses (including private ones)"""
111
109
  return list(Reuse.objects.owned_by(current_user.id))
112
110
 
113
111
 
114
- @me.route('/datasets/', endpoint='my_datasets')
112
+ @me.route("/datasets/", endpoint="my_datasets")
115
113
  class MyDatasetsAPI(API):
116
114
  @api.secure
117
- @api.doc('my_datasets')
115
+ @api.doc("my_datasets")
118
116
  @api.marshal_list_with(dataset_fields)
119
117
  def get(self):
120
- '''List all my datasets (including private ones)'''
118
+ """List all my datasets (including private ones)"""
121
119
  return list(Dataset.objects.owned_by(current_user.id))
122
120
 
123
121
 
124
- @me.route('/metrics/', endpoint='my_metrics')
122
+ @me.route("/metrics/", endpoint="my_metrics")
125
123
  class MyMetricsAPI(API):
126
124
  @api.secure
127
- @api.doc('my_metrics')
125
+ @api.doc("my_metrics")
128
126
  @api.marshal_list_with(me_metrics_fields)
129
127
  def get(self):
130
- '''Fetch the current user (me) metrics'''
128
+ """Fetch the current user (me) metrics"""
131
129
  return current_user._get_current_object()
132
130
 
133
131
 
134
- @me.route('/org_datasets/', endpoint='my_org_datasets')
132
+ @me.route("/org_datasets/", endpoint="my_org_datasets")
135
133
  class MyOrgDatasetsAPI(API):
136
134
  @api.secure
137
- @api.doc('my_org_datasets')
135
+ @api.doc("my_org_datasets")
138
136
  @api.expect(filter_parser)
139
137
  @api.marshal_list_with(dataset_fields)
140
138
  def get(self):
141
- '''List all datasets related to me and my organizations.'''
142
- q = filter_parser.parse_args().get('q')
139
+ """List all datasets related to me and my organizations."""
140
+ q = filter_parser.parse_args().get("q")
143
141
  owners = list(current_user.organizations) + [current_user.id]
144
- datasets = Dataset.objects.owned_by(*owners).order_by('-last_modified')
142
+ datasets = Dataset.objects.owned_by(*owners).order_by("-last_modified")
145
143
  if q:
146
144
  datasets = datasets.filter(title__icontains=q)
147
145
  return list(datasets)
148
146
 
149
147
 
150
- @me.route('/org_community_resources/', endpoint='my_org_community_resources')
148
+ @me.route("/org_community_resources/", endpoint="my_org_community_resources")
151
149
  class MyOrgCommunityResourcesAPI(API):
152
150
  @api.secure
153
- @api.doc('my_org_community_resources')
151
+ @api.doc("my_org_community_resources")
154
152
  @api.expect(filter_parser)
155
153
  @api.marshal_list_with(community_resource_fields)
156
154
  def get(self):
157
- '''List all community resources related to me and my organizations.'''
158
- q = filter_parser.parse_args().get('q')
155
+ """List all community resources related to me and my organizations."""
156
+ q = filter_parser.parse_args().get("q")
159
157
  owners = list(current_user.organizations) + [current_user.id]
160
- community_resources = (CommunityResource.objects.owned_by(*owners)
161
- .order_by('-last_modified'))
158
+ community_resources = CommunityResource.objects.owned_by(*owners).order_by("-last_modified")
162
159
  if q:
163
- community_resources = community_resources.filter(
164
- title__icontains=q)
160
+ community_resources = community_resources.filter(title__icontains=q)
165
161
  return list(community_resources)
166
162
 
167
163
 
168
- @me.route('/org_reuses/', endpoint='my_org_reuses')
164
+ @me.route("/org_reuses/", endpoint="my_org_reuses")
169
165
  class MyOrgReusesAPI(API):
170
166
  @api.secure
171
- @api.doc('my_org_reuses')
167
+ @api.doc("my_org_reuses")
172
168
  @api.expect(filter_parser)
173
169
  @api.marshal_list_with(reuse_fields)
174
170
  def get(self):
175
- '''List all reuses related to me and my organizations.'''
176
- q = filter_parser.parse_args().get('q')
171
+ """List all reuses related to me and my organizations."""
172
+ q = filter_parser.parse_args().get("q")
177
173
  owners = list(current_user.organizations) + [current_user.id]
178
- reuses = Reuse.objects.owned_by(*owners).order_by('-last_modified')
174
+ reuses = Reuse.objects.owned_by(*owners).order_by("-last_modified")
179
175
  if q:
180
176
  reuses = reuses.filter(title__icontains=q)
181
177
  return list(reuses)
182
178
 
183
179
 
184
- @me.route('/org_discussions/', endpoint='my_org_discussions')
180
+ @me.route("/org_discussions/", endpoint="my_org_discussions")
185
181
  class MyOrgDiscussionsAPI(API):
186
182
  @api.secure
187
- @api.doc('my_org_discussions')
183
+ @api.doc("my_org_discussions")
188
184
  @api.expect(filter_parser)
189
185
  @api.marshal_list_with(discussion_fields)
190
186
  def get(self):
191
- '''List all discussions related to my organizations.'''
192
- q = filter_parser.parse_args().get('q')
187
+ """List all discussions related to my organizations."""
188
+ q = filter_parser.parse_args().get("q")
193
189
  discussions = discussions_for(current_user._get_current_object())
194
- discussions = discussions.order_by('-created')
190
+ discussions = discussions.order_by("-created")
195
191
  if q:
196
192
  decoded = q
197
193
  discussions = discussions.filter(title__icontains=decoded)
198
194
  return list(discussions)
199
195
 
200
196
 
201
- @me.route('/apikey', endpoint='my_apikey')
197
+ @me.route("/apikey", endpoint="my_apikey")
202
198
  class ApiKeyAPI(API):
203
199
  @api.secure
204
- @api.doc('generate_apikey')
200
+ @api.doc("generate_apikey")
205
201
  @api.marshal_with(apikey_fields)
206
- @api.response(201, 'API Key generated')
202
+ @api.response(201, "API Key generated")
207
203
  def post(self):
208
- '''(Re)Generate my API Key'''
204
+ """(Re)Generate my API Key"""
209
205
  current_user.generate_api_key()
210
206
  current_user.save()
211
207
  return current_user, 201
212
208
 
213
209
  @api.secure
214
- @api.doc('clear_apikey')
215
- @api.response(204, 'API Key deleted/cleared')
210
+ @api.doc("clear_apikey")
211
+ @api.response(204, "API Key deleted/cleared")
216
212
  def delete(self):
217
- '''Clear/destroy an apikey'''
213
+ """Clear/destroy an apikey"""
218
214
  current_user.apikey = None
219
215
  current_user.save()
220
- return '', 204
216
+ return "", 204
221
217
 
222
218
 
223
- @ns.route('/', endpoint='users')
219
+ @ns.route("/", endpoint="users")
224
220
  class UserListAPI(API):
225
221
  model = User
226
222
  fields = user_fields
227
223
  form = UserProfileForm
228
224
 
229
225
  @api.secure(admin_permission)
230
- @api.doc('list_users')
226
+ @api.doc("list_users")
231
227
  @api.expect(user_parser.parser)
232
228
  @api.marshal_with(user_page_fields)
233
229
  def get(self):
234
- '''List all users'''
230
+ """List all users"""
235
231
  args = user_parser.parse()
236
232
  users = User.objects(deleted=None)
237
- if args['q']:
238
- search_users = users.search_text(args['q'])
239
- if args['sort']:
240
- return search_users.order_by(args['sort']).paginate(args['page'], args['page_size'])
233
+ if args["q"]:
234
+ search_users = users.search_text(args["q"])
235
+ if args["sort"]:
236
+ return search_users.order_by(args["sort"]).paginate(args["page"], args["page_size"])
241
237
  else:
242
- return search_users.order_by('$text_score').paginate(args['page'], args['page_size'])
243
- if args['sort']:
244
- return users.order_by(args['sort']).paginate(args['page'], args['page_size'])
245
- return users.order_by(DEFAULT_SORTING).paginate(args['page'], args['page_size'])
246
-
238
+ return search_users.order_by("$text_score").paginate(
239
+ args["page"], args["page_size"]
240
+ )
241
+ if args["sort"]:
242
+ return users.order_by(args["sort"]).paginate(args["page"], args["page_size"])
243
+ return users.order_by(DEFAULT_SORTING).paginate(args["page"], args["page_size"])
247
244
 
248
245
  @api.secure(admin_permission)
249
- @api.doc('create_user')
246
+ @api.doc("create_user")
250
247
  @api.expect(user_fields)
251
248
  @api.marshal_with(user_fields, code=201)
252
- @api.response(400, 'Validation error')
249
+ @api.response(400, "Validation error")
253
250
  def post(self):
254
- '''Create a new object'''
251
+ """Create a new object"""
255
252
  form = api.validate(UserProfileAdminForm)
256
253
  user = form.save()
257
254
  return user, 201
258
255
 
259
256
 
260
- @ns.route('/<user:user>/avatar', endpoint='user_avatar')
257
+ @ns.route("/<user:user>/avatar", endpoint="user_avatar")
261
258
  class UserAvatarAPI(API):
262
259
  @api.secure(admin_permission)
263
- @api.doc('user_avatar')
260
+ @api.doc("user_avatar")
264
261
  @api.expect(image_parser)
265
262
  @api.marshal_with(uploaded_image_fields)
266
263
  def post(self, user):
267
- '''Upload a new avatar for a given user'''
264
+ """Upload a new avatar for a given user"""
268
265
  parse_uploaded_image(user.avatar)
269
266
  user.save()
270
- return {'image': user.avatar}
271
-
267
+ return {"image": user.avatar}
272
268
 
273
269
 
274
270
  delete_parser = api.parser()
275
271
  delete_parser.add_argument(
276
- 'no_mail', type=bool, help='Do not send a mail to notify the user of the deletion',
277
- location='args', default=False)
272
+ "no_mail",
273
+ type=bool,
274
+ help="Do not send a mail to notify the user of the deletion",
275
+ location="args",
276
+ default=False,
277
+ )
278
278
 
279
- @ns.route('/<user:user>/', endpoint='user')
280
- @api.response(404, 'User not found')
281
- @api.response(410, 'User is not active or has been deleted')
282
- class UserAPI(API):
283
279
 
284
- @api.doc('get_user')
280
+ @ns.route("/<user:user>/", endpoint="user")
281
+ @api.response(404, "User not found")
282
+ @api.response(410, "User is not active or has been deleted")
283
+ class UserAPI(API):
284
+ @api.doc("get_user")
285
285
  @api.marshal_with(user_fields)
286
286
  def get(self, user):
287
- '''Get a user given its identifier'''
287
+ """Get a user given its identifier"""
288
288
  if current_user.is_anonymous or not current_user.sysadmin:
289
289
  if not user.active:
290
- api.abort(410, 'User is not active')
290
+ api.abort(410, "User is not active")
291
291
  if user.deleted:
292
- api.abort(410, 'User has been deleted')
292
+ api.abort(410, "User has been deleted")
293
293
  return user
294
294
 
295
295
  @api.secure(admin_permission)
296
- @api.doc('update_user')
296
+ @api.doc("update_user")
297
297
  @api.expect(user_fields)
298
298
  @api.marshal_with(user_fields)
299
- @api.response(400, 'Validation error')
299
+ @api.response(400, "Validation error")
300
300
  def put(self, user):
301
- '''Update a user given its identifier'''
301
+ """Update a user given its identifier"""
302
302
  form = api.validate(UserProfileAdminForm, user)
303
303
  return form.save()
304
304
 
305
305
  @api.secure(admin_permission)
306
- @api.doc('delete_user')
306
+ @api.doc("delete_user")
307
307
  @api.expect(delete_parser)
308
- @api.response(204, 'Object deleted')
309
- @api.response(403, 'When trying to delete yourself')
308
+ @api.response(204, "Object deleted")
309
+ @api.response(403, "When trying to delete yourself")
310
310
  def delete(self, user):
311
- '''Delete a user given its identifier'''
311
+ """Delete a user given its identifier"""
312
312
  args = delete_parser.parse_args()
313
313
  if user.deleted:
314
- api.abort(410, 'User has already been deleted')
314
+ api.abort(410, "User has already been deleted")
315
315
  if user == current_user._get_current_object():
316
- api.abort(403, 'You cannot delete yourself with this API. ' +
317
- 'Use the "me" API instead.')
318
-
319
- user.mark_as_deleted(notify=not args['no_mail'])
320
- return '', 204
316
+ api.abort(
317
+ 403, "You cannot delete yourself with this API. " + 'Use the "me" API instead.'
318
+ )
319
+
320
+ user.mark_as_deleted(notify=not args["no_mail"])
321
+ return "", 204
321
322
 
322
323
 
323
- from udata.models import ContactPoint
324
324
  from udata.core.contact_point.api import ContactPointApiParser
325
325
  from udata.core.contact_point.api_fields import contact_point_page_fields
326
-
326
+ from udata.models import ContactPoint
327
327
 
328
328
  contact_point_parser = ContactPointApiParser()
329
329
 
330
330
 
331
- @ns.route('/<user:user>/contacts/', endpoint='user_contact_points')
331
+ @ns.route("/<user:user>/contacts/", endpoint="user_contact_points")
332
332
  class OrgContactAPI(API):
333
- @api.doc('get_user_contact_point')
333
+ @api.doc("get_user_contact_point")
334
334
  @api.marshal_with(contact_point_page_fields)
335
335
  def get(self, user):
336
- '''List all user contact points'''
336
+ """List all user contact points"""
337
337
  args = contact_point_parser.parse()
338
338
  contact_points = ContactPoint.objects.owned_by(user)
339
- return contact_points.paginate(args['page'], args['page_size'])
339
+ return contact_points.paginate(args["page"], args["page_size"])
340
340
 
341
341
 
342
- @ns.route('/<id>/followers/', endpoint='user_followers')
343
- @ns.doc(get={'id': 'list_user_followers'},
344
- post={'id': 'follow_user'},
345
- delete={'id': 'unfollow_user'})
342
+ @ns.route("/<id>/followers/", endpoint="user_followers")
343
+ @ns.doc(
344
+ get={"id": "list_user_followers"}, post={"id": "follow_user"}, delete={"id": "unfollow_user"}
345
+ )
346
346
  class FollowUserAPI(FollowAPI):
347
347
  model = User
348
348
 
349
349
  @api.secure
350
350
  @api.doc(notes="You can't follow yourself.")
351
- @api.response(403, 'When trying to follow yourself')
351
+ @api.response(403, "When trying to follow yourself")
352
352
  def post(self, id):
353
- '''Follow a user given its ID'''
353
+ """Follow a user given its ID"""
354
354
  if id == str(current_user.id):
355
355
  api.abort(403, "You can't follow yourself")
356
356
  return super(FollowUserAPI, self).post(id)
@@ -358,41 +358,40 @@ class FollowUserAPI(FollowAPI):
358
358
 
359
359
  suggest_parser = api.parser()
360
360
  suggest_parser.add_argument(
361
- 'q', help='The string to autocomplete/suggest', location='args',
362
- required=True)
361
+ "q", help="The string to autocomplete/suggest", location="args", required=True
362
+ )
363
363
  suggest_parser.add_argument(
364
- 'size', type=int, help='The amount of suggestion to fetch',
365
- location='args', default=10)
364
+ "size", type=int, help="The amount of suggestion to fetch", location="args", default=10
365
+ )
366
366
 
367
367
 
368
- @ns.route('/suggest/', endpoint='suggest_users')
368
+ @ns.route("/suggest/", endpoint="suggest_users")
369
369
  class SuggestUsersAPI(API):
370
- @api.doc('suggest_users')
370
+ @api.doc("suggest_users")
371
371
  @api.expect(suggest_parser)
372
372
  @api.marshal_list_with(user_suggestion_fields)
373
373
  def get(self):
374
- '''Suggest users'''
374
+ """Suggest users"""
375
375
  args = suggest_parser.parse_args()
376
376
  users = User.objects(
377
- deleted=None,
378
- slug__icontains=slugify(args['q'], separator='-', to_lower=True)
377
+ deleted=None, slug__icontains=slugify(args["q"], separator="-", to_lower=True)
379
378
  )
380
379
  return [
381
380
  {
382
- 'id': user.id,
383
- 'first_name': user.first_name,
384
- 'last_name': user.last_name,
385
- 'avatar_url': user.avatar,
386
- 'slug': user.slug,
381
+ "id": user.id,
382
+ "first_name": user.first_name,
383
+ "last_name": user.last_name,
384
+ "avatar_url": user.avatar,
385
+ "slug": user.slug,
387
386
  }
388
- for user in users.order_by(DEFAULT_SORTING).limit(args['size'])
387
+ for user in users.order_by(DEFAULT_SORTING).limit(args["size"])
389
388
  ]
390
389
 
391
390
 
392
- @ns.route('/roles/', endpoint='user_roles')
391
+ @ns.route("/roles/", endpoint="user_roles")
393
392
  class UserRolesAPI(API):
394
- @api.doc('user_roles')
393
+ @api.doc("user_roles")
395
394
  @api.marshal_list_with(user_role_fields)
396
395
  def get(self):
397
- '''List all possible user roles'''
398
- return [{'name': role.name} for role in Role.objects()]
396
+ """List all possible user roles"""
397
+ return [{"name": role.name} for role in Role.objects()]