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/assets.py CHANGED
@@ -3,16 +3,16 @@ from flask_cdn import url_for as cdn_url_for
3
3
 
4
4
 
5
5
  def cdn_for(endpoint, **kwargs):
6
- '''
6
+ """
7
7
  Get a CDN URL for a static assets.
8
8
 
9
9
  Do not use a replacement for all flask.url_for calls
10
10
  as it is only meant for CDN assets URLS.
11
11
  (There is some extra round trip which cost is justified
12
12
  by the CDN assets prformance improvements)
13
- '''
14
- if current_app.config['CDN_DOMAIN']:
15
- if not current_app.config.get('CDN_DEBUG'):
16
- kwargs.pop('_external', None) # Avoid the _external parameter in URL
13
+ """
14
+ if current_app.config["CDN_DOMAIN"]:
15
+ if not current_app.config.get("CDN_DEBUG"):
16
+ kwargs.pop("_external", None) # Avoid the _external parameter in URL
17
17
  return cdn_url_for(endpoint, **kwargs)
18
18
  return url_for(endpoint, **kwargs)
udata/auth/__init__.py CHANGED
@@ -1,16 +1,18 @@
1
1
  import logging
2
2
 
3
- from flask import current_app
4
- from flask import render_template
5
-
6
- from flask_principal import identity_loaded # noqa: facade pattern
3
+ from flask import current_app, render_template
7
4
  from flask_principal import Permission as BasePermission
8
- from flask_principal import PermissionDenied # noqa: facade pattern
9
- from flask_principal import RoleNeed
10
- from flask_principal import UserNeed # noqa: facade pattern
11
-
12
- from flask_security import ( # noqa
13
- Security, current_user, login_required, login_user # noqa
5
+ from flask_principal import (
6
+ PermissionDenied, # noqa: facade pattern
7
+ RoleNeed,
8
+ UserNeed, # noqa: facade pattern
9
+ identity_loaded, # noqa: facade pattern
10
+ )
11
+ from flask_security import ( # noqa
12
+ Security, # noqa
13
+ current_user,
14
+ login_required,
15
+ login_user,
14
16
  )
15
17
  from werkzeug.utils import import_string
16
18
 
@@ -19,7 +21,7 @@ log = logging.getLogger(__name__)
19
21
 
20
22
  def render_security_template(*args, **kwargs):
21
23
  try:
22
- render = import_string(current_app.config.get('SECURITY_RENDER'))
24
+ render = import_string(current_app.config.get("SECURITY_RENDER"))
23
25
  except Exception:
24
26
  render = render_template
25
27
  return render(*args, **kwargs)
@@ -30,29 +32,38 @@ security = Security()
30
32
 
31
33
  class Permission(BasePermission):
32
34
  def __init__(self, *needs):
33
- '''Let administrator bypass all permissions'''
34
- super(Permission, self).__init__(RoleNeed('admin'), *needs)
35
+ """Let administrator bypass all permissions"""
36
+ super(Permission, self).__init__(RoleNeed("admin"), *needs)
35
37
 
36
38
 
37
39
  admin_permission = Permission()
38
40
 
39
41
 
40
42
  def init_app(app):
41
- from .forms import ExtendedRegisterForm, ExtendedLoginForm, ExtendedResetPasswordForm
43
+ from udata.models import datastore
44
+
45
+ from .forms import (
46
+ ExtendedLoginForm,
47
+ ExtendedRegisterForm,
48
+ ExtendedResetPasswordForm,
49
+ )
42
50
  from .mails import UdataMailUtil
43
51
  from .password_validation import UdataPasswordUtil
44
52
  from .views import create_security_blueprint
45
- from udata.models import datastore
46
- security.init_app(app, datastore,
47
- register_blueprint=False,
48
- render_template=render_security_template,
49
- login_form=ExtendedLoginForm,
50
- confirm_register_form=ExtendedRegisterForm,
51
- register_form=ExtendedRegisterForm,
52
- reset_password_form=ExtendedResetPasswordForm,
53
- mail_util_cls=UdataMailUtil,
54
- password_util_cls=UdataPasswordUtil)
55
-
56
- security_bp = create_security_blueprint(app, app.extensions['security'], 'security_blueprint')
53
+
54
+ security.init_app(
55
+ app,
56
+ datastore,
57
+ register_blueprint=False,
58
+ render_template=render_security_template,
59
+ login_form=ExtendedLoginForm,
60
+ confirm_register_form=ExtendedRegisterForm,
61
+ register_form=ExtendedRegisterForm,
62
+ reset_password_form=ExtendedResetPasswordForm,
63
+ mail_util_cls=UdataMailUtil,
64
+ password_util_cls=UdataPasswordUtil,
65
+ )
66
+
67
+ security_bp = create_security_blueprint(app, app.extensions["security"], "security_blueprint")
57
68
 
58
69
  app.register_blueprint(security_bp)
udata/auth/forms.py CHANGED
@@ -2,23 +2,31 @@ import datetime
2
2
 
3
3
  from flask import current_app
4
4
  from flask_login import current_user
5
- from flask_security.forms import RegisterForm, LoginForm, ResetPasswordForm, Form
6
- from udata.forms import fields
7
- from udata.forms import validators
5
+ from flask_security.forms import Form, LoginForm, RegisterForm, ResetPasswordForm
6
+
7
+ from udata.forms import fields, validators
8
8
  from udata.i18n import lazy_gettext as _
9
9
 
10
10
 
11
11
  class ExtendedRegisterForm(RegisterForm):
12
12
  first_name = fields.StringField(
13
- _('First name'), [validators.DataRequired(_('First name is required')),
14
- validators.NoURLs(_('URLs not allowed in this field'))])
13
+ _("First name"),
14
+ [
15
+ validators.DataRequired(_("First name is required")),
16
+ validators.NoURLs(_("URLs not allowed in this field")),
17
+ ],
18
+ )
15
19
  last_name = fields.StringField(
16
- _('Last name'), [validators.DataRequired(_('Last name is required')),
17
- validators.NoURLs(_('URLs not allowed in this field'))])
20
+ _("Last name"),
21
+ [
22
+ validators.DataRequired(_("Last name is required")),
23
+ validators.NoURLs(_("URLs not allowed in this field")),
24
+ ],
25
+ )
18
26
 
19
27
  def validate(self):
20
28
  # no register allowed when read only mode is on
21
- if not super().validate() or current_app.config.get('READ_ONLY_MODE'):
29
+ if not super().validate() or current_app.config.get("READ_ONLY_MODE"):
22
30
  return False
23
31
 
24
32
  return True
@@ -30,7 +38,7 @@ class ExtendedLoginForm(LoginForm):
30
38
  return False
31
39
 
32
40
  if self.user.password_rotation_demanded:
33
- self.password.errors.append(_('Password must be changed for security reasons'))
41
+ self.password.errors.append(_("Password must be changed for security reasons"))
34
42
  return False
35
43
 
36
44
  return True
@@ -50,12 +58,12 @@ class ExtendedResetPasswordForm(ResetPasswordForm):
50
58
 
51
59
 
52
60
  class ChangeEmailForm(Form):
53
- new_email = fields.StringField(_('New email'), [validators.DataRequired(), validators.Email()])
61
+ new_email = fields.StringField(_("New email"), [validators.DataRequired(), validators.Email()])
54
62
  new_email_confirm = fields.StringField(
55
- _('Retype email'),
56
- [validators.EqualTo('new_email', message=_('Email does not match')), validators.Email()]
63
+ _("Retype email"),
64
+ [validators.EqualTo("new_email", message=_("Email does not match")), validators.Email()],
57
65
  )
58
- submit = fields.SubmitField(_('Change email'))
66
+ submit = fields.SubmitField(_("Change email"))
59
67
 
60
68
  def validate(self):
61
69
  if not super().validate():
@@ -65,7 +73,7 @@ class ChangeEmailForm(Form):
65
73
 
66
74
  if self.user.email.strip() == self.new_email.data.strip():
67
75
  self.new_email.errors.append(
68
- 'Your new email must be different than your '
69
- 'previous email')
76
+ "Your new email must be different than your " "previous email"
77
+ )
70
78
  return False
71
79
  return True
udata/auth/helpers.py CHANGED
@@ -5,6 +5,6 @@ from flask_security import current_user
5
5
  def current_user_is_admin_or_self() -> bool:
6
6
  if current_user.is_anonymous:
7
7
  return False
8
- if request.endpoint == 'api.me' or current_user.sysadmin:
8
+ if request.endpoint == "api.me" or current_user.sysadmin:
9
9
  return True
10
10
  return False
udata/auth/mails.py CHANGED
@@ -1,19 +1,19 @@
1
1
  import email_validator
2
2
  from flask import current_app
3
+
3
4
  from udata.tasks import task
4
5
 
5
6
 
6
7
  @task
7
8
  def sendmail(msg):
8
- debug = current_app.config.get('DEBUG', False)
9
- send_mail = current_app.config.get('SEND_MAIL', not debug)
9
+ debug = current_app.config.get("DEBUG", False)
10
+ send_mail = current_app.config.get("SEND_MAIL", not debug)
10
11
  if send_mail:
11
12
  mail = current_app.extensions.get("mail")
12
13
  mail.send(msg)
13
14
 
14
15
 
15
16
  class UdataMailUtil:
16
-
17
17
  def __init__(self, app):
18
18
  self.app = app
19
19
 
@@ -7,13 +7,12 @@ from udata.i18n import lazy_gettext as _
7
7
 
8
8
 
9
9
  class UdataPasswordUtil:
10
-
11
10
  def __init__(self, app):
12
11
  pass
13
12
 
14
13
  @staticmethod
15
14
  def normalize(password):
16
- cf = current_app.config.get('SECURITY_PASSWORD_NORMALIZE_FORM')
15
+ cf = current_app.config.get("SECURITY_PASSWORD_NORMALIZE_FORM")
17
16
  if cf:
18
17
  return unicodedata.normalize(cf, password)
19
18
  return password
@@ -22,28 +21,33 @@ class UdataPasswordUtil:
22
21
  pnorm = self.normalize(password)
23
22
 
24
23
  error_list = []
25
- pass_length = current_app.config.get('SECURITY_PASSWORD_LENGTH_MIN')
24
+ pass_length = current_app.config.get("SECURITY_PASSWORD_LENGTH_MIN")
26
25
  if len(pnorm) < pass_length:
27
- message = _('Password must be at least {pass_length} characters long')
26
+ message = _("Password must be at least {pass_length} characters long")
28
27
  error_list.append(message.format(pass_length=pass_length))
29
28
 
30
29
  # searching for lowercase
31
- if current_app.config.get('SECURITY_PASSWORD_REQUIREMENTS_LOWERCASE') and (
32
- re.search(r"[a-z]", pnorm) is None):
33
- error_list.append(_('Password must contain lowercases'))
30
+ if current_app.config.get("SECURITY_PASSWORD_REQUIREMENTS_LOWERCASE") and (
31
+ re.search(r"[a-z]", pnorm) is None
32
+ ):
33
+ error_list.append(_("Password must contain lowercases"))
34
34
 
35
35
  # searching for digits
36
- if current_app.config.get('SECURITY_PASSWORD_REQUIREMENTS_DIGITS') and (re.search(r"\d", pnorm) is None):
37
- error_list.append(_('Password must contain digits'))
36
+ if current_app.config.get("SECURITY_PASSWORD_REQUIREMENTS_DIGITS") and (
37
+ re.search(r"\d", pnorm) is None
38
+ ):
39
+ error_list.append(_("Password must contain digits"))
38
40
 
39
41
  # searching for uppercase
40
- if current_app.config.get('SECURITY_PASSWORD_REQUIREMENTS_UPPERCASE') and (
41
- re.search(r"[A-Z]", pnorm) is None):
42
- error_list.append(_('Password must contain uppercases'))
42
+ if current_app.config.get("SECURITY_PASSWORD_REQUIREMENTS_UPPERCASE") and (
43
+ re.search(r"[A-Z]", pnorm) is None
44
+ ):
45
+ error_list.append(_("Password must contain uppercases"))
43
46
 
44
47
  # searching for symbols
45
- if current_app.config.get('SECURITY_PASSWORD_REQUIREMENTS_SYMBOLS') and (
46
- re.search(r"[ !#$%&'()*+,-./[\\\]^_`{|}~" + r'"]', pnorm) is None):
47
- error_list.append(_('Password must contain symbols'))
48
+ if current_app.config.get("SECURITY_PASSWORD_REQUIREMENTS_SYMBOLS") and (
49
+ re.search(r"[ !#$%&'()*+,-./[\\\]^_`{|}~" + r'"]', pnorm) is None
50
+ ):
51
+ error_list.append(_("Password must contain symbols"))
48
52
 
49
53
  return error_list, pnorm
udata/auth/views.py CHANGED
@@ -1,56 +1,67 @@
1
- from flask import flash, redirect, current_app, url_for
1
+ from flask import current_app, flash, redirect, url_for
2
2
  from flask_login import current_user, login_required
3
- from flask_security.views import change_password
4
- from flask_security.views import confirm_email
5
- from flask_security.views import forgot_password
6
- from flask_security.views import login
7
- from flask_security.views import logout
8
- from flask_security.views import register
9
- from flask_security.views import reset_password
10
- from flask_security.views import send_confirmation
11
- from flask_security.views import send_login
12
- from flask_security.views import token_login
13
3
  from flask_security.utils import (
14
- check_and_get_token_status, do_flash, get_message, get_within_delta, hash_data,
15
- login_user, logout_user, send_mail, verify_hash)
4
+ check_and_get_token_status,
5
+ do_flash,
6
+ get_message,
7
+ get_within_delta,
8
+ hash_data,
9
+ login_user,
10
+ logout_user,
11
+ send_mail,
12
+ verify_hash,
13
+ )
14
+ from flask_security.views import (
15
+ change_password,
16
+ confirm_email,
17
+ forgot_password,
18
+ login,
19
+ logout,
20
+ register,
21
+ reset_password,
22
+ send_confirmation,
23
+ send_login,
24
+ token_login,
25
+ )
16
26
  from werkzeug.local import LocalProxy
27
+
17
28
  from udata.i18n import lazy_gettext as _
18
29
  from udata.uris import endpoint_for
19
30
 
20
31
  from .forms import ChangeEmailForm
21
32
 
22
-
23
- _security = LocalProxy(lambda: current_app.extensions['security'])
33
+ _security = LocalProxy(lambda: current_app.extensions["security"])
24
34
  _datastore = LocalProxy(lambda: _security.datastore)
25
35
 
26
36
 
27
37
  def slash_url_suffix(url, suffix):
28
38
  """Adds a slash either to the beginning or the end of a suffix
29
- (which is to be appended to a URL), depending on whether or not
30
- the URL ends with a slash.
39
+ (which is to be appended to a URL), depending on whether or not
40
+ the URL ends with a slash.
31
41
  """
32
42
 
33
- return url.endswith('/') and ('%s/' % suffix) or ('/%s' % suffix)
43
+ return url.endswith("/") and ("%s/" % suffix) or ("/%s" % suffix)
34
44
 
35
45
 
36
46
  def send_change_email_confirmation_instructions(user, new_email):
37
47
  data = [str(current_user.fs_uniquifier), hash_data(current_user.email), new_email]
38
48
  token = _security.confirm_serializer.dumps(data)
39
- confirmation_link = url_for('security.confirm_change_email', token=token, _external=True)
49
+ confirmation_link = url_for("security.confirm_change_email", token=token, _external=True)
40
50
 
41
- subject = _('Confirm change of email instructions')
51
+ subject = _("Confirm change of email instructions")
42
52
  send_mail(
43
53
  subject=subject,
44
54
  recipient=new_email,
45
- template='confirmation_instructions',
55
+ template="confirmation_instructions",
46
56
  user=current_user,
47
- confirmation_link=confirmation_link
57
+ confirmation_link=confirmation_link,
48
58
  )
49
59
 
50
60
 
51
61
  def confirm_change_email_token_status(token):
52
62
  expired, invalid, token_data = check_and_get_token_status(
53
- token, 'confirm', get_within_delta('CONFIRM_EMAIL_WITHIN'))
63
+ token, "confirm", get_within_delta("CONFIRM_EMAIL_WITHIN")
64
+ )
54
65
  new_email = None
55
66
 
56
67
  if not invalid and token_data:
@@ -62,17 +73,21 @@ def confirm_change_email_token_status(token):
62
73
 
63
74
 
64
75
  def confirm_change_email(token):
65
- expired, invalid, user, new_email = (
66
- confirm_change_email_token_status(token))
76
+ expired, invalid, user, new_email = confirm_change_email_token_status(token)
67
77
 
68
78
  if not user or invalid:
69
79
  invalid = True
70
- do_flash(*get_message('INVALID_CONFIRMATION_TOKEN'))
80
+ do_flash(*get_message("INVALID_CONFIRMATION_TOKEN"))
71
81
  if expired:
72
82
  send_change_email_confirmation_instructions(user, new_email)
73
- do_flash(_('You did not confirm your change of email within {email_within}. New instructions to confirm your change of email have been sent to {new_email}.').format(email_within=_security.confirm_email_within, new_email=new_email), 'error')
83
+ do_flash(
84
+ _(
85
+ "You did not confirm your change of email within {email_within}. New instructions to confirm your change of email have been sent to {new_email}."
86
+ ).format(email_within=_security.confirm_email_within, new_email=new_email),
87
+ "error",
88
+ )
74
89
  if invalid or expired:
75
- return redirect(endpoint_for('site.home', 'admin.index'))
90
+ return redirect(endpoint_for("site.home", "admin.index"))
76
91
 
77
92
  if user != current_user:
78
93
  logout_user()
@@ -80,10 +95,10 @@ def confirm_change_email(token):
80
95
 
81
96
  user.email = new_email
82
97
  _datastore.put(user)
83
- msg = (_('Thank you. Your change of email has been confirmed.'), 'success')
98
+ msg = (_("Thank you. Your change of email has been confirmed."), "success")
84
99
 
85
100
  do_flash(*msg)
86
- return redirect(endpoint_for('site.home', 'admin.index'))
101
+ return redirect(endpoint_for("site.home", "admin.index"))
87
102
 
88
103
 
89
104
  @login_required
@@ -95,10 +110,15 @@ def change_email():
95
110
  if form.validate_on_submit():
96
111
  new_email = form.new_email.data
97
112
  send_change_email_confirmation_instructions(current_user, new_email)
98
- flash(_('Thank you. Confirmation instructions for changing your email have been sent to {new_email}.').format(new_email=new_email), 'success')
99
- return redirect(endpoint_for('site.home', 'admin.index'))
113
+ flash(
114
+ _(
115
+ "Thank you. Confirmation instructions for changing your email have been sent to {new_email}."
116
+ ).format(new_email=new_email),
117
+ "success",
118
+ )
119
+ return redirect(endpoint_for("site.home", "admin.index"))
100
120
 
101
- return _security.render_template('security/change_email.html', change_email_form=form)
121
+ return _security.render_template("security/change_email.html", change_email_form=form)
102
122
 
103
123
 
104
124
  def create_security_blueprint(app, state, import_name):
@@ -108,60 +128,66 @@ def create_security_blueprint(app, state, import_name):
108
128
  Creates the security extension blueprint
109
129
  This creates an I18nBlueprint to use as a base.
110
130
  """
111
- bp = I18nBlueprint(state.blueprint_name, import_name,
112
- url_prefix=state.url_prefix,
113
- subdomain=state.subdomain,
114
- template_folder='templates')
131
+ bp = I18nBlueprint(
132
+ state.blueprint_name,
133
+ import_name,
134
+ url_prefix=state.url_prefix,
135
+ subdomain=state.subdomain,
136
+ template_folder="templates",
137
+ )
115
138
 
116
- bp.route(app.config['SECURITY_LOGOUT_URL'], endpoint='logout')(logout)
139
+ bp.route(app.config["SECURITY_LOGOUT_URL"], endpoint="logout")(logout)
117
140
 
118
141
  if state.passwordless:
119
- bp.route(app.config['SECURITY_LOGIN_URL'],
120
- methods=['GET', 'POST'],
121
- endpoint='login')(send_login)
142
+ bp.route(app.config["SECURITY_LOGIN_URL"], methods=["GET", "POST"], endpoint="login")(
143
+ send_login
144
+ )
122
145
  bp.route(
123
- app.config['SECURITY_LOGIN_URL'] + slash_url_suffix(app.config['SECURITY_LOGIN_URL'], '<token>'),
124
- endpoint='token_login'
146
+ app.config["SECURITY_LOGIN_URL"]
147
+ + slash_url_suffix(app.config["SECURITY_LOGIN_URL"], "<token>"),
148
+ endpoint="token_login",
125
149
  )(token_login)
126
150
  else:
127
- bp.route(app.config['SECURITY_LOGIN_URL'],
128
- methods=['GET', 'POST'],
129
- endpoint='login')(login)
151
+ bp.route(app.config["SECURITY_LOGIN_URL"], methods=["GET", "POST"], endpoint="login")(login)
130
152
 
131
153
  if state.registerable:
132
- bp.route(app.config['SECURITY_REGISTER_URL'],
133
- methods=['GET', 'POST'],
134
- endpoint='register')(register)
154
+ bp.route(app.config["SECURITY_REGISTER_URL"], methods=["GET", "POST"], endpoint="register")(
155
+ register
156
+ )
135
157
 
136
158
  if state.recoverable:
137
- bp.route(app.config['SECURITY_RESET_URL'],
138
- methods=['GET', 'POST'],
139
- endpoint='forgot_password')(forgot_password)
140
159
  bp.route(
141
- app.config['SECURITY_RESET_URL'] + slash_url_suffix(app.config['SECURITY_RESET_URL'], '<token>'),
142
- methods=['GET', 'POST'],
143
- endpoint='reset_password'
160
+ app.config["SECURITY_RESET_URL"], methods=["GET", "POST"], endpoint="forgot_password"
161
+ )(forgot_password)
162
+ bp.route(
163
+ app.config["SECURITY_RESET_URL"]
164
+ + slash_url_suffix(app.config["SECURITY_RESET_URL"], "<token>"),
165
+ methods=["GET", "POST"],
166
+ endpoint="reset_password",
144
167
  )(reset_password)
145
168
 
146
169
  if state.changeable:
147
- bp.route(app.config['SECURITY_CHANGE_URL'],
148
- methods=['GET', 'POST'],
149
- endpoint='change_password')(change_password)
170
+ bp.route(
171
+ app.config["SECURITY_CHANGE_URL"], methods=["GET", "POST"], endpoint="change_password"
172
+ )(change_password)
150
173
 
151
174
  if state.confirmable:
152
- bp.route(app.config['SECURITY_CONFIRM_URL'],
153
- methods=['GET', 'POST'],
154
- endpoint='send_confirmation')(send_confirmation)
155
175
  bp.route(
156
- app.config['SECURITY_CONFIRM_URL'] + slash_url_suffix(app.config['SECURITY_CONFIRM_URL'], '<token>'),
157
- methods=['GET', 'POST'],
158
- endpoint='confirm_email'
176
+ app.config["SECURITY_CONFIRM_URL"],
177
+ methods=["GET", "POST"],
178
+ endpoint="send_confirmation",
179
+ )(send_confirmation)
180
+ bp.route(
181
+ app.config["SECURITY_CONFIRM_URL"]
182
+ + slash_url_suffix(app.config["SECURITY_CONFIRM_URL"], "<token>"),
183
+ methods=["GET", "POST"],
184
+ endpoint="confirm_email",
159
185
  )(confirm_email)
160
186
 
161
- bp.route('/confirm-change-email/<token>',
162
- methods=['GET', 'POST'],
163
- endpoint='confirm_change_email')(confirm_change_email)
187
+ bp.route(
188
+ "/confirm-change-email/<token>", methods=["GET", "POST"], endpoint="confirm_change_email"
189
+ )(confirm_change_email)
164
190
 
165
- bp.route('/change-email', methods=['GET', 'POST'], endpoint='change_email')(change_email)
191
+ bp.route("/change-email", methods=["GET", "POST"], endpoint="change_email")(change_email)
166
192
 
167
193
  return bp