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.
- tasks/__init__.py +109 -107
- tasks/helpers.py +18 -18
- udata/__init__.py +4 -4
- udata/admin/views.py +5 -5
- udata/api/__init__.py +135 -124
- udata/api/commands.py +45 -37
- udata/api/errors.py +5 -4
- udata/api/fields.py +23 -21
- udata/api/oauth2.py +55 -74
- udata/api/parsers.py +15 -15
- udata/api/signals.py +1 -1
- udata/api_fields.py +137 -89
- udata/app.py +56 -54
- udata/assets.py +5 -5
- udata/auth/__init__.py +37 -26
- udata/auth/forms.py +23 -15
- udata/auth/helpers.py +1 -1
- udata/auth/mails.py +3 -3
- udata/auth/password_validation.py +19 -15
- udata/auth/views.py +94 -68
- udata/commands/__init__.py +71 -69
- udata/commands/cache.py +7 -7
- udata/commands/db.py +201 -140
- udata/commands/dcat.py +36 -30
- udata/commands/fixtures.py +100 -84
- udata/commands/images.py +21 -20
- udata/commands/info.py +17 -20
- udata/commands/init.py +10 -10
- udata/commands/purge.py +12 -13
- udata/commands/serve.py +41 -29
- udata/commands/static.py +16 -18
- udata/commands/test.py +20 -20
- udata/commands/tests/fixtures.py +26 -24
- udata/commands/worker.py +31 -33
- udata/core/__init__.py +12 -12
- udata/core/activity/__init__.py +0 -1
- udata/core/activity/api.py +59 -49
- udata/core/activity/models.py +28 -26
- udata/core/activity/signals.py +1 -1
- udata/core/activity/tasks.py +16 -10
- udata/core/badges/api.py +6 -6
- udata/core/badges/commands.py +14 -13
- udata/core/badges/fields.py +8 -5
- udata/core/badges/forms.py +7 -4
- udata/core/badges/models.py +16 -31
- udata/core/badges/permissions.py +1 -3
- udata/core/badges/signals.py +2 -2
- udata/core/badges/tasks.py +3 -2
- udata/core/badges/tests/test_commands.py +10 -10
- udata/core/badges/tests/test_model.py +24 -31
- udata/core/contact_point/api.py +19 -18
- udata/core/contact_point/api_fields.py +21 -14
- udata/core/contact_point/factories.py +2 -2
- udata/core/contact_point/forms.py +7 -6
- udata/core/contact_point/models.py +3 -5
- udata/core/dataservices/api.py +26 -21
- udata/core/dataservices/factories.py +13 -11
- udata/core/dataservices/models.py +35 -40
- udata/core/dataservices/permissions.py +4 -4
- udata/core/dataservices/rdf.py +40 -17
- udata/core/dataservices/tasks.py +4 -3
- udata/core/dataset/actions.py +10 -10
- udata/core/dataset/activities.py +21 -23
- udata/core/dataset/api.py +321 -298
- udata/core/dataset/api_fields.py +443 -271
- udata/core/dataset/apiv2.py +305 -229
- udata/core/dataset/commands.py +38 -36
- udata/core/dataset/constants.py +61 -54
- udata/core/dataset/csv.py +70 -74
- udata/core/dataset/events.py +39 -32
- udata/core/dataset/exceptions.py +8 -4
- udata/core/dataset/factories.py +57 -65
- udata/core/dataset/forms.py +87 -63
- udata/core/dataset/models.py +336 -280
- udata/core/dataset/permissions.py +9 -6
- udata/core/dataset/preview.py +15 -17
- udata/core/dataset/rdf.py +156 -122
- udata/core/dataset/search.py +92 -77
- udata/core/dataset/signals.py +1 -1
- udata/core/dataset/tasks.py +63 -54
- udata/core/discussions/actions.py +5 -5
- udata/core/discussions/api.py +124 -120
- udata/core/discussions/factories.py +2 -2
- udata/core/discussions/forms.py +9 -7
- udata/core/discussions/metrics.py +1 -3
- udata/core/discussions/models.py +25 -24
- udata/core/discussions/notifications.py +18 -14
- udata/core/discussions/permissions.py +3 -3
- udata/core/discussions/signals.py +4 -4
- udata/core/discussions/tasks.py +24 -28
- udata/core/followers/api.py +32 -33
- udata/core/followers/models.py +9 -9
- udata/core/followers/signals.py +3 -3
- udata/core/jobs/actions.py +7 -7
- udata/core/jobs/api.py +99 -92
- udata/core/jobs/commands.py +48 -49
- udata/core/jobs/forms.py +11 -11
- udata/core/jobs/models.py +6 -6
- udata/core/metrics/__init__.py +2 -2
- udata/core/metrics/commands.py +34 -30
- udata/core/metrics/models.py +2 -4
- udata/core/metrics/signals.py +1 -1
- udata/core/metrics/tasks.py +3 -3
- udata/core/organization/activities.py +12 -15
- udata/core/organization/api.py +167 -174
- udata/core/organization/api_fields.py +183 -124
- udata/core/organization/apiv2.py +32 -32
- udata/core/organization/commands.py +20 -22
- udata/core/organization/constants.py +11 -11
- udata/core/organization/csv.py +17 -15
- udata/core/organization/factories.py +8 -11
- udata/core/organization/forms.py +32 -26
- udata/core/organization/metrics.py +2 -1
- udata/core/organization/models.py +87 -67
- udata/core/organization/notifications.py +18 -14
- udata/core/organization/permissions.py +10 -11
- udata/core/organization/rdf.py +14 -14
- udata/core/organization/search.py +30 -28
- udata/core/organization/signals.py +7 -7
- udata/core/organization/tasks.py +42 -61
- udata/core/owned.py +38 -27
- udata/core/post/api.py +82 -81
- udata/core/post/constants.py +8 -5
- udata/core/post/factories.py +4 -4
- udata/core/post/forms.py +13 -14
- udata/core/post/models.py +20 -22
- udata/core/post/tests/test_api.py +30 -32
- udata/core/reports/api.py +8 -7
- udata/core/reports/constants.py +1 -3
- udata/core/reports/models.py +10 -10
- udata/core/reuse/activities.py +15 -19
- udata/core/reuse/api.py +123 -126
- udata/core/reuse/api_fields.py +120 -85
- udata/core/reuse/apiv2.py +11 -10
- udata/core/reuse/constants.py +23 -23
- udata/core/reuse/csv.py +18 -18
- udata/core/reuse/factories.py +5 -9
- udata/core/reuse/forms.py +24 -21
- udata/core/reuse/models.py +55 -51
- udata/core/reuse/permissions.py +2 -2
- udata/core/reuse/search.py +49 -46
- udata/core/reuse/signals.py +1 -1
- udata/core/reuse/tasks.py +4 -5
- udata/core/site/api.py +47 -50
- udata/core/site/factories.py +2 -2
- udata/core/site/forms.py +4 -5
- udata/core/site/models.py +94 -63
- udata/core/site/rdf.py +14 -14
- udata/core/spam/api.py +16 -9
- udata/core/spam/constants.py +4 -4
- udata/core/spam/fields.py +13 -7
- udata/core/spam/models.py +27 -20
- udata/core/spam/signals.py +1 -1
- udata/core/spam/tests/test_spam.py +6 -5
- udata/core/spatial/api.py +72 -80
- udata/core/spatial/api_fields.py +73 -58
- udata/core/spatial/commands.py +67 -64
- udata/core/spatial/constants.py +3 -3
- udata/core/spatial/factories.py +37 -54
- udata/core/spatial/forms.py +27 -26
- udata/core/spatial/geoids.py +17 -17
- udata/core/spatial/models.py +43 -47
- udata/core/spatial/tasks.py +2 -1
- udata/core/spatial/tests/test_api.py +115 -130
- udata/core/spatial/tests/test_fields.py +74 -77
- udata/core/spatial/tests/test_geoid.py +22 -22
- udata/core/spatial/tests/test_models.py +5 -7
- udata/core/spatial/translations.py +16 -16
- udata/core/storages/__init__.py +16 -18
- udata/core/storages/api.py +66 -64
- udata/core/storages/tasks.py +7 -7
- udata/core/storages/utils.py +15 -15
- udata/core/storages/views.py +5 -6
- udata/core/tags/api.py +17 -14
- udata/core/tags/csv.py +4 -4
- udata/core/tags/models.py +8 -5
- udata/core/tags/tasks.py +11 -13
- udata/core/tags/views.py +4 -4
- udata/core/topic/api.py +84 -73
- udata/core/topic/apiv2.py +157 -127
- udata/core/topic/factories.py +3 -4
- udata/core/topic/forms.py +12 -14
- udata/core/topic/models.py +14 -19
- udata/core/topic/parsers.py +26 -26
- udata/core/user/activities.py +30 -29
- udata/core/user/api.py +151 -152
- udata/core/user/api_fields.py +132 -100
- udata/core/user/apiv2.py +7 -7
- udata/core/user/commands.py +38 -38
- udata/core/user/factories.py +8 -9
- udata/core/user/forms.py +14 -11
- udata/core/user/metrics.py +2 -2
- udata/core/user/models.py +68 -69
- udata/core/user/permissions.py +4 -5
- udata/core/user/rdf.py +7 -8
- udata/core/user/tasks.py +2 -2
- udata/core/user/tests/test_user_model.py +24 -16
- udata/db/tasks.py +2 -1
- udata/entrypoints.py +35 -31
- udata/errors.py +2 -1
- udata/event/values.py +6 -6
- udata/factories.py +2 -2
- udata/features/identicon/api.py +5 -6
- udata/features/identicon/backends.py +48 -55
- udata/features/identicon/tests/test_backends.py +4 -5
- udata/features/notifications/__init__.py +0 -1
- udata/features/notifications/actions.py +9 -9
- udata/features/notifications/api.py +17 -13
- udata/features/territories/__init__.py +12 -10
- udata/features/territories/api.py +14 -15
- udata/features/territories/models.py +23 -28
- udata/features/transfer/actions.py +8 -11
- udata/features/transfer/api.py +84 -77
- udata/features/transfer/factories.py +2 -1
- udata/features/transfer/models.py +11 -12
- udata/features/transfer/notifications.py +19 -15
- udata/features/transfer/permissions.py +5 -5
- udata/forms/__init__.py +5 -2
- udata/forms/fields.py +164 -172
- udata/forms/validators.py +19 -22
- udata/forms/widgets.py +9 -13
- udata/frontend/__init__.py +31 -26
- udata/frontend/csv.py +68 -58
- udata/frontend/markdown.py +40 -44
- udata/harvest/actions.py +89 -77
- udata/harvest/api.py +294 -238
- udata/harvest/backends/__init__.py +4 -4
- udata/harvest/backends/base.py +128 -111
- udata/harvest/backends/dcat.py +80 -66
- udata/harvest/commands.py +56 -60
- udata/harvest/csv.py +8 -8
- udata/harvest/exceptions.py +6 -3
- udata/harvest/filters.py +24 -23
- udata/harvest/forms.py +27 -28
- udata/harvest/models.py +88 -80
- udata/harvest/notifications.py +15 -10
- udata/harvest/signals.py +13 -13
- udata/harvest/tasks.py +11 -10
- udata/harvest/tests/factories.py +23 -24
- udata/harvest/tests/test_actions.py +136 -166
- udata/harvest/tests/test_api.py +220 -214
- udata/harvest/tests/test_base_backend.py +117 -112
- udata/harvest/tests/test_dcat_backend.py +380 -308
- udata/harvest/tests/test_filters.py +33 -22
- udata/harvest/tests/test_models.py +11 -14
- udata/harvest/tests/test_notifications.py +6 -7
- udata/harvest/tests/test_tasks.py +7 -6
- udata/i18n.py +237 -78
- udata/linkchecker/backends.py +5 -11
- udata/linkchecker/checker.py +23 -22
- udata/linkchecker/commands.py +4 -6
- udata/linkchecker/models.py +6 -6
- udata/linkchecker/tasks.py +18 -20
- udata/mail.py +21 -21
- udata/migrations/2020-07-24-remove-s-from-scope-oauth.py +9 -8
- udata/migrations/2020-08-24-add-fs-filename.py +9 -8
- udata/migrations/2020-09-28-update-reuses-datasets-metrics.py +5 -4
- udata/migrations/2020-10-16-migrate-ods-resources.py +9 -10
- udata/migrations/2021-04-08-update-schema-with-new-structure.py +8 -7
- udata/migrations/2021-05-27-fix-default-schema-name.py +7 -6
- udata/migrations/2021-07-05-remove-unused-badges.py +17 -15
- udata/migrations/2021-07-07-update-schema-for-community-resources.py +7 -6
- udata/migrations/2021-08-17-follow-integrity.py +5 -4
- udata/migrations/2021-08-17-harvest-integrity.py +13 -12
- udata/migrations/2021-08-17-oauth2client-integrity.py +5 -4
- udata/migrations/2021-08-17-transfer-integrity.py +5 -4
- udata/migrations/2021-08-17-users-integrity.py +9 -8
- udata/migrations/2021-12-14-reuse-topics.py +7 -6
- udata/migrations/2022-04-21-improve-extension-detection.py +8 -7
- udata/migrations/2022-09-22-clean-inactive-harvest-datasets.py +16 -14
- udata/migrations/2022-10-10-add-fs_uniquifier-to-user-model.py +6 -6
- udata/migrations/2022-10-10-migrate-harvest-extras.py +36 -26
- udata/migrations/2023-02-08-rename-internal-dates.py +46 -28
- udata/migrations/2024-01-29-fix-reuse-and-dataset-with-private-None.py +10 -8
- udata/migrations/2024-03-22-migrate-activity-kwargs-to-extras.py +6 -4
- udata/migrations/2024-06-11-fix-reuse-datasets-references.py +7 -6
- udata/migrations/__init__.py +123 -105
- udata/models/__init__.py +4 -4
- udata/mongo/__init__.py +13 -11
- udata/mongo/badges_field.py +3 -2
- udata/mongo/datetime_fields.py +13 -12
- udata/mongo/document.py +17 -16
- udata/mongo/engine.py +15 -16
- udata/mongo/errors.py +2 -1
- udata/mongo/extras_fields.py +30 -20
- udata/mongo/queryset.py +12 -12
- udata/mongo/slug_fields.py +38 -28
- udata/mongo/taglist_field.py +1 -2
- udata/mongo/url_field.py +5 -5
- udata/mongo/uuid_fields.py +4 -3
- udata/notifications/__init__.py +1 -1
- udata/notifications/mattermost.py +10 -9
- udata/rdf.py +167 -188
- udata/routing.py +40 -45
- udata/search/__init__.py +18 -19
- udata/search/adapter.py +17 -16
- udata/search/commands.py +44 -51
- udata/search/fields.py +13 -20
- udata/search/query.py +23 -18
- udata/search/result.py +9 -10
- udata/sentry.py +21 -19
- udata/settings.py +262 -198
- udata/sitemap.py +8 -6
- udata/static/chunks/{11.e9b9ca1f3e03d4020377.js → 11.52e531c19f8de80c00cf.js} +3 -3
- udata/static/chunks/{11.e9b9ca1f3e03d4020377.js.map → 11.52e531c19f8de80c00cf.js.map} +1 -1
- udata/static/chunks/{13.038c0d9aa0dfa0181c4b.js → 13.c3343a7f1070061c0e10.js} +2 -2
- udata/static/chunks/{13.038c0d9aa0dfa0181c4b.js.map → 13.c3343a7f1070061c0e10.js.map} +1 -1
- udata/static/chunks/{16.0baa2b64a74a2dcde25c.js → 16.8fa42440ad75ca172e6d.js} +2 -2
- udata/static/chunks/{16.0baa2b64a74a2dcde25c.js.map → 16.8fa42440ad75ca172e6d.js.map} +1 -1
- udata/static/chunks/{19.350a9f150b074b4ecefa.js → 19.9c6c8412729cd6d59cfa.js} +3 -3
- udata/static/chunks/{19.350a9f150b074b4ecefa.js.map → 19.9c6c8412729cd6d59cfa.js.map} +1 -1
- udata/static/chunks/{5.6ebbce2b9b3e696d3da5.js → 5.71d15c2e4f21feee2a9a.js} +3 -3
- udata/static/chunks/{5.6ebbce2b9b3e696d3da5.js.map → 5.71d15c2e4f21feee2a9a.js.map} +1 -1
- udata/static/chunks/{6.d8a5f7b017bcbd083641.js → 6.9139dc098b8ea640b890.js} +3 -3
- udata/static/chunks/{6.d8a5f7b017bcbd083641.js.map → 6.9139dc098b8ea640b890.js.map} +1 -1
- udata/static/common.js +1 -1
- udata/static/common.js.map +1 -1
- udata/storage/s3.py +20 -13
- udata/tags.py +4 -5
- udata/tasks.py +43 -42
- udata/tests/__init__.py +9 -6
- udata/tests/api/__init__.py +5 -6
- udata/tests/api/test_auth_api.py +395 -321
- udata/tests/api/test_base_api.py +31 -33
- udata/tests/api/test_contact_points.py +7 -9
- udata/tests/api/test_dataservices_api.py +211 -158
- udata/tests/api/test_datasets_api.py +823 -812
- udata/tests/api/test_follow_api.py +13 -15
- udata/tests/api/test_me_api.py +95 -112
- udata/tests/api/test_organizations_api.py +301 -339
- udata/tests/api/test_reports_api.py +35 -25
- udata/tests/api/test_reuses_api.py +134 -139
- udata/tests/api/test_swagger.py +5 -5
- udata/tests/api/test_tags_api.py +18 -25
- udata/tests/api/test_topics_api.py +94 -94
- udata/tests/api/test_transfer_api.py +53 -48
- udata/tests/api/test_user_api.py +128 -141
- udata/tests/apiv2/test_datasets.py +290 -198
- udata/tests/apiv2/test_me_api.py +10 -11
- udata/tests/apiv2/test_organizations.py +56 -74
- udata/tests/apiv2/test_swagger.py +5 -5
- udata/tests/apiv2/test_topics.py +69 -87
- udata/tests/cli/test_cli_base.py +8 -8
- udata/tests/cli/test_db_cli.py +21 -19
- udata/tests/dataservice/test_dataservice_tasks.py +8 -12
- udata/tests/dataset/test_csv_adapter.py +44 -35
- udata/tests/dataset/test_dataset_actions.py +2 -3
- udata/tests/dataset/test_dataset_commands.py +7 -8
- udata/tests/dataset/test_dataset_events.py +36 -29
- udata/tests/dataset/test_dataset_model.py +224 -217
- udata/tests/dataset/test_dataset_rdf.py +142 -131
- udata/tests/dataset/test_dataset_tasks.py +15 -15
- udata/tests/dataset/test_resource_preview.py +10 -13
- udata/tests/features/territories/__init__.py +9 -13
- udata/tests/features/territories/test_territories_api.py +71 -91
- udata/tests/forms/test_basic_fields.py +7 -7
- udata/tests/forms/test_current_user_field.py +39 -66
- udata/tests/forms/test_daterange_field.py +31 -39
- udata/tests/forms/test_dict_field.py +28 -26
- udata/tests/forms/test_extras_fields.py +102 -76
- udata/tests/forms/test_form_field.py +8 -8
- udata/tests/forms/test_image_field.py +33 -26
- udata/tests/forms/test_model_field.py +134 -123
- udata/tests/forms/test_model_list_field.py +7 -7
- udata/tests/forms/test_nested_model_list_field.py +117 -79
- udata/tests/forms/test_publish_as_field.py +36 -65
- udata/tests/forms/test_reference_field.py +34 -53
- udata/tests/forms/test_user_forms.py +23 -21
- udata/tests/forms/test_uuid_field.py +6 -10
- udata/tests/frontend/__init__.py +9 -6
- udata/tests/frontend/test_auth.py +7 -6
- udata/tests/frontend/test_csv.py +81 -96
- udata/tests/frontend/test_hooks.py +43 -43
- udata/tests/frontend/test_markdown.py +211 -191
- udata/tests/helpers.py +32 -37
- udata/tests/models.py +2 -2
- udata/tests/organization/test_csv_adapter.py +21 -16
- udata/tests/organization/test_notifications.py +11 -18
- udata/tests/organization/test_organization_model.py +13 -13
- udata/tests/organization/test_organization_rdf.py +29 -22
- udata/tests/organization/test_organization_tasks.py +16 -17
- udata/tests/plugin.py +76 -73
- udata/tests/reuse/test_reuse_model.py +21 -21
- udata/tests/reuse/test_reuse_task.py +11 -13
- udata/tests/search/__init__.py +11 -12
- udata/tests/search/test_adapter.py +60 -70
- udata/tests/search/test_query.py +16 -16
- udata/tests/search/test_results.py +10 -7
- udata/tests/site/test_site_api.py +11 -16
- udata/tests/site/test_site_metrics.py +20 -30
- udata/tests/site/test_site_model.py +4 -5
- udata/tests/site/test_site_rdf.py +94 -78
- udata/tests/test_activity.py +17 -17
- udata/tests/test_discussions.py +292 -299
- udata/tests/test_i18n.py +37 -40
- udata/tests/test_linkchecker.py +91 -85
- udata/tests/test_mail.py +13 -17
- udata/tests/test_migrations.py +219 -180
- udata/tests/test_model.py +164 -157
- udata/tests/test_notifications.py +17 -17
- udata/tests/test_owned.py +14 -14
- udata/tests/test_rdf.py +25 -23
- udata/tests/test_routing.py +89 -93
- udata/tests/test_storages.py +137 -128
- udata/tests/test_tags.py +44 -46
- udata/tests/test_topics.py +7 -7
- udata/tests/test_transfer.py +42 -49
- udata/tests/test_uris.py +160 -161
- udata/tests/test_utils.py +79 -71
- udata/tests/user/test_user_rdf.py +5 -9
- udata/tests/workers/test_jobs_commands.py +57 -58
- udata/tests/workers/test_tasks_routing.py +23 -29
- udata/tests/workers/test_workers_api.py +125 -131
- udata/tests/workers/test_workers_helpers.py +6 -6
- udata/tracking.py +4 -6
- udata/uris.py +45 -46
- udata/utils.py +68 -66
- udata/wsgi.py +1 -1
- {udata-9.1.2.dev30355.dist-info → udata-9.1.2.dev30382.dist-info}/METADATA +3 -2
- udata-9.1.2.dev30382.dist-info/RECORD +704 -0
- udata-9.1.2.dev30355.dist-info/RECORD +0 -704
- {udata-9.1.2.dev30355.dist-info → udata-9.1.2.dev30382.dist-info}/LICENSE +0 -0
- {udata-9.1.2.dev30355.dist-info → udata-9.1.2.dev30382.dist-info}/WHEEL +0 -0
- {udata-9.1.2.dev30355.dist-info → udata-9.1.2.dev30382.dist-info}/entry_points.txt +0 -0
- {udata-9.1.2.dev30355.dist-info → udata-9.1.2.dev30382.dist-info}/top_level.txt +0 -0
udata/tests/test_i18n.py
CHANGED
|
@@ -1,32 +1,31 @@
|
|
|
1
|
-
from flask import g,
|
|
1
|
+
from flask import g, render_template_string, url_for
|
|
2
2
|
from werkzeug.routing import BuildError
|
|
3
3
|
|
|
4
|
-
from udata.i18n import I18nBlueprint, language
|
|
5
|
-
|
|
6
|
-
from . import DBTestMixin, WebTestMixin, TestCase
|
|
7
4
|
from udata.core.user.factories import UserFactory
|
|
5
|
+
from udata.i18n import I18nBlueprint, language
|
|
8
6
|
|
|
7
|
+
from . import DBTestMixin, TestCase, WebTestMixin
|
|
9
8
|
|
|
10
|
-
bp = I18nBlueprint(
|
|
9
|
+
bp = I18nBlueprint("i18nbp", __name__, static_folder="static")
|
|
11
10
|
|
|
12
11
|
|
|
13
|
-
@bp.route(
|
|
12
|
+
@bp.route("/lang/<msg>/")
|
|
14
13
|
def lang(msg):
|
|
15
14
|
return g.lang_code
|
|
16
15
|
|
|
17
16
|
|
|
18
|
-
@bp.route(
|
|
17
|
+
@bp.route("/hardcoded/")
|
|
19
18
|
def hardcoded():
|
|
20
|
-
out = g.lang_code +
|
|
21
|
-
with language(
|
|
19
|
+
out = g.lang_code + "-"
|
|
20
|
+
with language("fr"):
|
|
22
21
|
out += g.lang_code
|
|
23
22
|
return out
|
|
24
23
|
|
|
25
24
|
|
|
26
|
-
@bp.route(
|
|
25
|
+
@bp.route("/not-localized/", localize=False)
|
|
27
26
|
def not_localized():
|
|
28
|
-
out = g.lang_code +
|
|
29
|
-
with language(
|
|
27
|
+
out = g.lang_code + "-"
|
|
28
|
+
with language("fr"):
|
|
30
29
|
out += g.lang_code
|
|
31
30
|
return out
|
|
32
31
|
|
|
@@ -34,63 +33,61 @@ def not_localized():
|
|
|
34
33
|
class I18nBlueprintTest(WebTestMixin, DBTestMixin, TestCase):
|
|
35
34
|
def create_app(self):
|
|
36
35
|
app = super(I18nBlueprintTest, self).create_app()
|
|
37
|
-
app.config[
|
|
38
|
-
app.config[
|
|
39
|
-
|
|
40
|
-
|
|
36
|
+
app.config["DEFAULT_LANGUAGE"] = "en"
|
|
37
|
+
app.config["LANGUAGES"] = {
|
|
38
|
+
"en": "English",
|
|
39
|
+
"fr": "Français",
|
|
41
40
|
}
|
|
42
41
|
app.register_blueprint(bp)
|
|
43
42
|
return app
|
|
44
43
|
|
|
45
44
|
def test_lang_inserted_url_for(self):
|
|
46
|
-
self.assertEqual(url_for(
|
|
45
|
+
self.assertEqual(url_for("i18nbp.lang", msg="test"), "/en/lang/test/")
|
|
47
46
|
|
|
48
47
|
def test_redirect_url_for(self):
|
|
49
|
-
self.assertEqual(
|
|
50
|
-
url_for('i18nbp.lang_redirect', msg='test'), '/lang/test/')
|
|
48
|
+
self.assertEqual(url_for("i18nbp.lang_redirect", msg="test"), "/lang/test/")
|
|
51
49
|
|
|
52
50
|
def test_lang_ignored_for_static(self):
|
|
53
|
-
self.assertEqual(url_for(
|
|
54
|
-
'/static/test.jpg')
|
|
51
|
+
self.assertEqual(url_for("i18nbp.static", filename="test.jpg"), "/static/test.jpg")
|
|
55
52
|
with self.assertRaises(BuildError):
|
|
56
|
-
url_for(
|
|
53
|
+
url_for("i18nbp.static_redirect", filename="test.jpg")
|
|
57
54
|
|
|
58
55
|
def test_redirect_on_missing_lang(self):
|
|
59
|
-
response = self.get(
|
|
60
|
-
self.assertRedirects(response,
|
|
56
|
+
response = self.get("/lang/test/?q=test")
|
|
57
|
+
self.assertRedirects(response, "/en/lang/test/?q=test")
|
|
61
58
|
|
|
62
59
|
def test_do_not_redirect_and_set_lang(self):
|
|
63
|
-
self.assertEqual(self.get(
|
|
64
|
-
self.assertEqual(self.get(
|
|
60
|
+
self.assertEqual(self.get("/fr/lang/test/").data, b"fr")
|
|
61
|
+
self.assertEqual(self.get("/en/lang/test/").data, b"en")
|
|
65
62
|
|
|
66
63
|
def test_redirect_on_default_lang_for_unknown_lang(self):
|
|
67
|
-
self.assertRedirects(self.get(
|
|
64
|
+
self.assertRedirects(self.get("/sk/lang/test/"), "/en/lang/test/")
|
|
68
65
|
|
|
69
66
|
def test_404_on_default_lang_for_unknown_lang(self):
|
|
70
|
-
self.assert404(self.get(
|
|
67
|
+
self.assert404(self.get("/sk/not-found/"))
|
|
71
68
|
|
|
72
69
|
def test_language_contact_manager(self):
|
|
73
|
-
self.assertEqual(self.get(
|
|
74
|
-
self.assertEqual(self.get(
|
|
70
|
+
self.assertEqual(self.get("/fr/hardcoded/").data, b"fr-fr")
|
|
71
|
+
self.assertEqual(self.get("/en/hardcoded/").data, b"en-fr")
|
|
75
72
|
|
|
76
73
|
def test_redirect_user_prefered_lang(self):
|
|
77
|
-
self.login(UserFactory(prefered_language=
|
|
74
|
+
self.login(UserFactory(prefered_language="fr"))
|
|
78
75
|
|
|
79
|
-
response = self.get(
|
|
80
|
-
self.assertRedirects(response,
|
|
76
|
+
response = self.get("/lang/test/?q=test")
|
|
77
|
+
self.assertRedirects(response, "/fr/lang/test/?q=test")
|
|
81
78
|
|
|
82
79
|
def test_lang_ignored_for_localize_false(self):
|
|
83
|
-
url = url_for(
|
|
84
|
-
self.assertEqual(url,
|
|
80
|
+
url = url_for("i18nbp.not_localized")
|
|
81
|
+
self.assertEqual(url, "/not-localized/")
|
|
85
82
|
|
|
86
83
|
def test_localized_url_redirect_for_localize_false(self):
|
|
87
|
-
url = url_for(
|
|
88
|
-
self.assertEqual(url,
|
|
84
|
+
url = url_for("i18nbp.not_localized_redirect")
|
|
85
|
+
self.assertEqual(url, "/en/not-localized/")
|
|
89
86
|
|
|
90
87
|
response = self.get(url)
|
|
91
|
-
self.assertRedirects(response,
|
|
88
|
+
self.assertRedirects(response, "/not-localized/")
|
|
92
89
|
|
|
93
90
|
def test_render_template_translation(self):
|
|
94
|
-
|
|
95
|
-
self.app.config[
|
|
91
|
+
"""It should render the dataset page"""
|
|
92
|
+
self.app.config["DEFAULT_LANGUAGE"] = "fr"
|
|
96
93
|
self.assertEqual("Bienvenue", render_template_string('{{ _("Welcome") }}'))
|
udata/tests/test_linkchecker.py
CHANGED
|
@@ -1,21 +1,22 @@
|
|
|
1
|
+
from datetime import datetime, timedelta
|
|
2
|
+
|
|
1
3
|
import mock
|
|
2
4
|
import pytest
|
|
3
|
-
from datetime import datetime, timedelta
|
|
4
5
|
|
|
5
6
|
from udata.auth import login_user
|
|
6
|
-
from udata.tests import TestCase
|
|
7
7
|
from udata.core.activity import init_app as init_activity
|
|
8
8
|
from udata.core.activity.models import Activity
|
|
9
9
|
from udata.core.dataset.factories import DatasetFactory, ResourceFactory
|
|
10
10
|
from udata.core.user.factories import UserFactory
|
|
11
11
|
from udata.linkchecker.checker import check_resource
|
|
12
12
|
from udata.settings import Testing
|
|
13
|
+
from udata.tests import TestCase
|
|
13
14
|
|
|
14
15
|
|
|
15
16
|
class LinkcheckerTestSettings(Testing):
|
|
16
17
|
LINKCHECKING_ENABLED = True
|
|
17
|
-
LINKCHECKING_IGNORE_DOMAINS = [
|
|
18
|
-
LINKCHECKING_IGNORE_PATTERNS = [
|
|
18
|
+
LINKCHECKING_IGNORE_DOMAINS = ["example-ignore.com"]
|
|
19
|
+
LINKCHECKING_IGNORE_PATTERNS = ["format=shp"]
|
|
19
20
|
LINKCHECKING_MIN_CACHE_DURATION = 0.5
|
|
20
21
|
LINKCHECKING_UNAVAILABLE_THRESHOLD = 100
|
|
21
22
|
LINKCHECKING_MAX_CACHE_DURATION = 100
|
|
@@ -32,14 +33,13 @@ def test_check_resource_creates_no_activity(activity_app, mocker):
|
|
|
32
33
|
dataset = DatasetFactory(resources=[resource])
|
|
33
34
|
user = UserFactory()
|
|
34
35
|
login_user(user)
|
|
35
|
-
check_res = {
|
|
36
|
-
'check:date': datetime.utcnow()}
|
|
36
|
+
check_res = {"check:status": 200, "check:available": True, "check:date": datetime.utcnow()}
|
|
37
37
|
|
|
38
38
|
class DummyLinkchecker:
|
|
39
39
|
def check(self, _):
|
|
40
40
|
return check_res
|
|
41
|
-
|
|
42
|
-
|
|
41
|
+
|
|
42
|
+
mocker.patch("udata.linkchecker.checker.get_linkchecker", return_value=DummyLinkchecker)
|
|
43
43
|
|
|
44
44
|
check_resource(resource)
|
|
45
45
|
|
|
@@ -54,95 +54,98 @@ class LinkcheckerTest(TestCase):
|
|
|
54
54
|
self.resource = ResourceFactory()
|
|
55
55
|
self.dataset = DatasetFactory(resources=[self.resource])
|
|
56
56
|
|
|
57
|
-
@mock.patch(
|
|
57
|
+
@mock.patch("udata.linkchecker.checker.get_linkchecker")
|
|
58
58
|
def test_check_resource_no_linkchecker(self, mock_fn):
|
|
59
59
|
mock_fn.return_value = None
|
|
60
60
|
res = check_resource(self.resource)
|
|
61
|
-
self.assertEqual(res, ({
|
|
61
|
+
self.assertEqual(res, ({"error": "No linkchecker configured."}, 503))
|
|
62
62
|
|
|
63
|
-
@mock.patch(
|
|
63
|
+
@mock.patch("udata.linkchecker.checker.get_linkchecker")
|
|
64
64
|
def test_check_resource_linkchecker_ok(self, mock_fn):
|
|
65
|
-
check_res = {
|
|
66
|
-
'check:date': datetime.utcnow()}
|
|
65
|
+
check_res = {"check:status": 200, "check:available": True, "check:date": datetime.utcnow()}
|
|
67
66
|
|
|
68
67
|
class DummyLinkchecker:
|
|
69
68
|
def check(self, _):
|
|
70
69
|
return check_res
|
|
70
|
+
|
|
71
71
|
mock_fn.return_value = DummyLinkchecker
|
|
72
72
|
|
|
73
73
|
res = check_resource(self.resource)
|
|
74
74
|
self.assertEqual(res, check_res)
|
|
75
|
-
check_res.update({
|
|
75
|
+
check_res.update({"check:count-availability": 1})
|
|
76
76
|
self.assertEqual(self.resource.extras, check_res)
|
|
77
77
|
|
|
78
|
-
@mock.patch(
|
|
78
|
+
@mock.patch("udata.linkchecker.checker.get_linkchecker")
|
|
79
79
|
def test_check_resource_filter_result(self, mock_fn):
|
|
80
|
-
check_res = {
|
|
80
|
+
check_res = {"check:status": 200, "dummy": "dummy"}
|
|
81
81
|
|
|
82
82
|
class DummyLinkchecker:
|
|
83
83
|
def check(self, _):
|
|
84
84
|
return check_res
|
|
85
|
+
|
|
85
86
|
mock_fn.return_value = DummyLinkchecker
|
|
86
87
|
|
|
87
88
|
res = check_resource(self.resource)
|
|
88
89
|
self.assertEqual(res, check_res)
|
|
89
|
-
self.assertNotIn(
|
|
90
|
+
self.assertNotIn("dummy", self.resource.extras)
|
|
90
91
|
|
|
91
|
-
@mock.patch(
|
|
92
|
+
@mock.patch("udata.linkchecker.checker.get_linkchecker")
|
|
92
93
|
def test_check_resource_linkchecker_no_status(self, mock_fn):
|
|
93
94
|
class DummyLinkchecker:
|
|
94
95
|
def check(self, _):
|
|
95
|
-
return {
|
|
96
|
+
return {"check:available": True}
|
|
97
|
+
|
|
96
98
|
mock_fn.return_value = DummyLinkchecker
|
|
97
99
|
res = check_resource(self.resource)
|
|
98
|
-
self.assertEqual(res,
|
|
99
|
-
({'error': 'No status in response from linkchecker'},
|
|
100
|
-
503))
|
|
100
|
+
self.assertEqual(res, ({"error": "No status in response from linkchecker"}, 503))
|
|
101
101
|
|
|
102
|
-
@mock.patch(
|
|
102
|
+
@mock.patch("udata.linkchecker.checker.get_linkchecker")
|
|
103
103
|
def test_check_resource_linkchecker_check_error(self, mock_fn):
|
|
104
104
|
class DummyLinkchecker:
|
|
105
105
|
def check(self, _):
|
|
106
|
-
return {
|
|
106
|
+
return {"check:error": "ERROR"}
|
|
107
|
+
|
|
107
108
|
mock_fn.return_value = DummyLinkchecker
|
|
108
109
|
res = check_resource(self.resource)
|
|
109
|
-
self.assertEqual(res, ({
|
|
110
|
+
self.assertEqual(res, ({"error": "ERROR"}, 500))
|
|
110
111
|
|
|
111
|
-
@mock.patch(
|
|
112
|
+
@mock.patch("udata.linkchecker.checker.get_linkchecker")
|
|
112
113
|
def test_check_resource_linkchecker_in_resource(self, mock_fn):
|
|
113
|
-
self.resource.extras[
|
|
114
|
+
self.resource.extras["check:checker"] = "another_linkchecker"
|
|
114
115
|
self.resource.save()
|
|
115
116
|
check_resource(self.resource)
|
|
116
117
|
args, kwargs = mock_fn.call_args
|
|
117
|
-
self.assertEqual(args, (
|
|
118
|
+
self.assertEqual(args, ("another_linkchecker",))
|
|
118
119
|
|
|
119
120
|
def test_check_resource_linkchecker_no_check(self):
|
|
120
|
-
self.resource.extras[
|
|
121
|
+
self.resource.extras["check:checker"] = "no_check"
|
|
121
122
|
self.resource.save()
|
|
122
123
|
res = check_resource(self.resource)
|
|
123
|
-
self.assertEqual(res.get(
|
|
124
|
-
self.assertEqual(res.get(
|
|
124
|
+
self.assertEqual(res.get("check:status"), 204)
|
|
125
|
+
self.assertEqual(res.get("check:available"), True)
|
|
125
126
|
|
|
126
127
|
def test_check_resource_ignored_domain(self):
|
|
127
128
|
self.resource.extras = {}
|
|
128
|
-
self.resource.url =
|
|
129
|
+
self.resource.url = "http://example-ignore.com/url"
|
|
129
130
|
self.resource.save()
|
|
130
131
|
res = check_resource(self.resource)
|
|
131
|
-
self.assertEqual(res.get(
|
|
132
|
-
self.assertEqual(res.get(
|
|
132
|
+
self.assertEqual(res.get("check:status"), 204)
|
|
133
|
+
self.assertEqual(res.get("check:available"), True)
|
|
133
134
|
|
|
134
135
|
def test_check_resource_ignored_pattern(self):
|
|
135
136
|
self.resource.extras = {}
|
|
136
|
-
self.resource.url =
|
|
137
|
+
self.resource.url = "http://example.com/url?format=shp"
|
|
137
138
|
self.resource.save()
|
|
138
139
|
res = check_resource(self.resource)
|
|
139
|
-
self.assertEqual(res.get(
|
|
140
|
-
self.assertEqual(res.get(
|
|
140
|
+
self.assertEqual(res.get("check:status"), 204)
|
|
141
|
+
self.assertEqual(res.get("check:available"), True)
|
|
141
142
|
|
|
142
143
|
def test_is_need_check(self):
|
|
143
|
-
self.resource.extras = {
|
|
144
|
-
|
|
145
|
-
|
|
144
|
+
self.resource.extras = {
|
|
145
|
+
"check:available": True,
|
|
146
|
+
"check:date": datetime.utcnow(),
|
|
147
|
+
"check:status": 42,
|
|
148
|
+
}
|
|
146
149
|
self.assertFalse(self.resource.need_check())
|
|
147
150
|
|
|
148
151
|
def test_is_need_check_unknown_status(self):
|
|
@@ -151,56 +154,56 @@ class LinkcheckerTest(TestCase):
|
|
|
151
154
|
|
|
152
155
|
def test_is_need_check_cache_expired(self):
|
|
153
156
|
self.resource.extras = {
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
+
"check:available": True,
|
|
158
|
+
"check:date": datetime.utcnow() - timedelta(seconds=3600),
|
|
159
|
+
"check:status": 42,
|
|
157
160
|
}
|
|
158
161
|
self.assertTrue(self.resource.need_check())
|
|
159
162
|
|
|
160
163
|
def test_is_need_check_date_string(self):
|
|
161
164
|
check_date = (datetime.utcnow() - timedelta(seconds=3600)).isoformat()
|
|
162
165
|
self.resource.extras = {
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
+
"check:available": True,
|
|
167
|
+
"check:date": check_date,
|
|
168
|
+
"check:status": 42,
|
|
166
169
|
}
|
|
167
170
|
self.assertTrue(self.resource.need_check())
|
|
168
171
|
|
|
169
172
|
def test_is_need_check_wrong_check_date(self):
|
|
170
|
-
check_date =
|
|
173
|
+
check_date = "123azerty"
|
|
171
174
|
self.resource.extras = {
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
+
"check:available": True,
|
|
176
|
+
"check:date": check_date,
|
|
177
|
+
"check:status": 42,
|
|
175
178
|
}
|
|
176
179
|
self.assertTrue(self.resource.need_check())
|
|
177
180
|
|
|
178
181
|
def test_is_need_check_wrong_check_date_int(self):
|
|
179
182
|
check_date = 42
|
|
180
183
|
self.resource.extras = {
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
+
"check:available": True,
|
|
185
|
+
"check:date": check_date,
|
|
186
|
+
"check:status": 42,
|
|
184
187
|
}
|
|
185
188
|
self.assertTrue(self.resource.need_check())
|
|
186
189
|
|
|
187
190
|
def test_is_need_check_count_availability(self):
|
|
188
191
|
self.resource.extras = {
|
|
189
192
|
# should need a new check after 100 * 30s = 3000s < 3600s
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
193
|
+
"check:count-availability": 100,
|
|
194
|
+
"check:available": True,
|
|
195
|
+
"check:date": datetime.utcnow() - timedelta(seconds=3600),
|
|
196
|
+
"check:status": 42,
|
|
194
197
|
}
|
|
195
198
|
self.assertTrue(self.resource.need_check())
|
|
196
199
|
|
|
197
200
|
def test_is_need_check_count_availability_expired(self):
|
|
198
201
|
self.resource.extras = {
|
|
199
202
|
# should need a new check after 150 * 30s = 4500s > 3600s
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
203
|
+
"check:count-availability": 150,
|
|
204
|
+
"check:available": True,
|
|
205
|
+
"check:date": datetime.utcnow() - timedelta(seconds=3600),
|
|
206
|
+
"check:status": 42,
|
|
204
207
|
}
|
|
205
208
|
self.assertFalse(self.resource.need_check())
|
|
206
209
|
|
|
@@ -208,64 +211,67 @@ class LinkcheckerTest(TestCase):
|
|
|
208
211
|
self.resource.extras = {
|
|
209
212
|
# should need a new check after 30s < 3600S
|
|
210
213
|
# count-availability is below threshold
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
214
|
+
"check:count-availability": 95,
|
|
215
|
+
"check:available": False,
|
|
216
|
+
"check:date": datetime.utcnow() - timedelta(seconds=3600),
|
|
217
|
+
"check:status": 42,
|
|
215
218
|
}
|
|
216
219
|
self.assertTrue(self.resource.need_check())
|
|
217
220
|
|
|
218
|
-
@mock.patch(
|
|
221
|
+
@mock.patch("udata.linkchecker.checker.get_linkchecker")
|
|
219
222
|
def test_count_availability_increment(self, mock_fn):
|
|
220
|
-
check_res = {
|
|
221
|
-
'check:date': datetime.utcnow()}
|
|
223
|
+
check_res = {"check:status": 200, "check:available": True, "check:date": datetime.utcnow()}
|
|
222
224
|
|
|
223
225
|
class DummyLinkchecker:
|
|
224
226
|
def check(self, _):
|
|
225
227
|
return check_res
|
|
228
|
+
|
|
226
229
|
mock_fn.return_value = DummyLinkchecker
|
|
227
230
|
|
|
228
231
|
check_resource(self.resource)
|
|
229
|
-
self.assertEqual(self.resource.extras[
|
|
232
|
+
self.assertEqual(self.resource.extras["check:count-availability"], 1)
|
|
230
233
|
|
|
231
234
|
check_resource(self.resource)
|
|
232
|
-
self.assertEqual(self.resource.extras[
|
|
235
|
+
self.assertEqual(self.resource.extras["check:count-availability"], 2)
|
|
233
236
|
|
|
234
|
-
@mock.patch(
|
|
237
|
+
@mock.patch("udata.linkchecker.checker.get_linkchecker")
|
|
235
238
|
def test_count_availability_reset(self, mock_fn):
|
|
236
|
-
self.resource.extras = {
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
239
|
+
self.resource.extras = {
|
|
240
|
+
"check:status": 200,
|
|
241
|
+
"check:available": True,
|
|
242
|
+
"check:date": datetime.utcnow(),
|
|
243
|
+
"check:count-availability": 2,
|
|
244
|
+
}
|
|
245
|
+
check_res = {"check:status": 200, "check:available": False, "check:date": datetime.utcnow()}
|
|
241
246
|
|
|
242
247
|
class DummyLinkchecker:
|
|
243
248
|
def check(self, _):
|
|
244
249
|
return check_res
|
|
250
|
+
|
|
245
251
|
mock_fn.return_value = DummyLinkchecker
|
|
246
252
|
|
|
247
253
|
check_resource(self.resource)
|
|
248
|
-
self.assertEqual(self.resource.extras[
|
|
254
|
+
self.assertEqual(self.resource.extras["check:count-availability"], 1)
|
|
249
255
|
|
|
250
256
|
def test_count_availability_threshold(self):
|
|
251
257
|
self.resource.extras = {
|
|
252
|
-
|
|
253
|
-
|
|
258
|
+
"check:status": 404,
|
|
259
|
+
"check:available": False,
|
|
254
260
|
# if it weren't above threshold, should need check (>30s)
|
|
255
261
|
# and we're still below max_cache 101 * 0.5 < 100
|
|
256
|
-
|
|
257
|
-
|
|
262
|
+
"check:date": datetime.utcnow() - timedelta(seconds=60),
|
|
263
|
+
"check:count-availability": 101,
|
|
258
264
|
}
|
|
259
265
|
self.assertFalse(self.resource.need_check())
|
|
260
266
|
|
|
261
267
|
def test_count_availability_max_cache_duration(self):
|
|
262
268
|
self.resource.extras = {
|
|
263
|
-
|
|
264
|
-
|
|
269
|
+
"check:status": 200,
|
|
270
|
+
"check:available": True,
|
|
265
271
|
# next check should be at 300 * 0.5 = 150min
|
|
266
272
|
# but we are above max cache duration 150min > 100min
|
|
267
273
|
# and 120m > 100 min so we should need a new check
|
|
268
|
-
|
|
269
|
-
|
|
274
|
+
"check:date": datetime.utcnow() - timedelta(minutes=120),
|
|
275
|
+
"check:count-availability": 300,
|
|
270
276
|
}
|
|
271
277
|
self.assertTrue(self.resource.need_check())
|
udata/tests/test_mail.py
CHANGED
|
@@ -4,25 +4,21 @@ from smtplib import SMTPRecipientsRefused
|
|
|
4
4
|
import pytest
|
|
5
5
|
|
|
6
6
|
from udata.core.user.factories import UserFactory
|
|
7
|
-
from udata.mail import
|
|
8
|
-
from udata.tests import
|
|
7
|
+
from udata.mail import mail_sent, send
|
|
8
|
+
from udata.tests import DBTestMixin, TestCase
|
|
9
9
|
from udata.tests.helpers import assert_emit, assert_not_emit
|
|
10
10
|
|
|
11
|
+
SMTPRecipientsRefusedList = ["not-found@udata", "not-found-either@udata"]
|
|
11
12
|
|
|
12
|
-
SMTPRecipientsRefusedList = [
|
|
13
|
-
'not-found@udata',
|
|
14
|
-
'not-found-either@udata'
|
|
15
|
-
]
|
|
16
13
|
|
|
17
|
-
|
|
18
|
-
class FakeSender():
|
|
14
|
+
class FakeSender:
|
|
19
15
|
def send(self, msg):
|
|
20
16
|
if all(recipient in SMTPRecipientsRefusedList for recipient in msg.recipients):
|
|
21
17
|
raise SMTPRecipientsRefused(msg.recipients)
|
|
22
18
|
mail_sent.send(msg)
|
|
23
19
|
|
|
24
20
|
|
|
25
|
-
class FakeMail
|
|
21
|
+
class FakeMail:
|
|
26
22
|
@contextmanager
|
|
27
23
|
def connect(*args, **kw):
|
|
28
24
|
yield FakeSender()
|
|
@@ -31,26 +27,26 @@ class FakeMail():
|
|
|
31
27
|
class MailSendTest(TestCase, DBTestMixin):
|
|
32
28
|
def create_app(self):
|
|
33
29
|
app = super().create_app()
|
|
34
|
-
app.config[
|
|
30
|
+
app.config["SEND_MAIL"] = True
|
|
35
31
|
return app
|
|
36
32
|
|
|
37
33
|
@pytest.fixture(autouse=True)
|
|
38
34
|
def patch_mail(self, mocker):
|
|
39
|
-
mocker.patch(
|
|
35
|
+
mocker.patch("udata.mail.mail", FakeMail())
|
|
40
36
|
|
|
41
37
|
def test_send_mail(self):
|
|
42
38
|
with assert_emit(mail_sent):
|
|
43
|
-
send(
|
|
39
|
+
send("subject", [UserFactory(email="recipient@udata")], "base")
|
|
44
40
|
|
|
45
41
|
def test_send_mail_to_not_found_recipients(self):
|
|
46
42
|
with assert_not_emit(mail_sent):
|
|
47
|
-
send(
|
|
43
|
+
send("subject", [UserFactory(email="not-found@udata")], "base")
|
|
48
44
|
|
|
49
45
|
def test_send_mail_to_multiple_recipients_with_some_not_found(self):
|
|
50
46
|
recipients = [
|
|
51
|
-
UserFactory(email=
|
|
52
|
-
UserFactory(email=
|
|
53
|
-
UserFactory(email=
|
|
47
|
+
UserFactory(email="not-found@udata"),
|
|
48
|
+
UserFactory(email="recipient@udata"),
|
|
49
|
+
UserFactory(email="not-found-either@udata"),
|
|
54
50
|
]
|
|
55
51
|
with assert_emit(mail_sent):
|
|
56
|
-
send(
|
|
52
|
+
send("subject", recipients, "base")
|