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/harvest/tests/test_api.py
CHANGED
|
@@ -1,349 +1,343 @@
|
|
|
1
1
|
import logging
|
|
2
|
-
import pytest
|
|
3
|
-
|
|
4
2
|
from datetime import datetime
|
|
5
3
|
|
|
4
|
+
import pytest
|
|
6
5
|
from flask import url_for
|
|
7
6
|
from pytest_mock import MockerFixture
|
|
8
7
|
|
|
9
|
-
from udata.tests.plugin import ApiClient
|
|
10
|
-
|
|
11
|
-
from .. import actions
|
|
12
|
-
|
|
13
|
-
from udata.models import Member, PeriodicTask
|
|
14
8
|
from udata.core.organization.factories import OrganizationFactory
|
|
15
9
|
from udata.core.user.factories import AdminFactory, UserFactory
|
|
10
|
+
from udata.models import Member, PeriodicTask
|
|
11
|
+
from udata.tests.helpers import assert200, assert201, assert204, assert400, assert403
|
|
12
|
+
from udata.tests.plugin import ApiClient
|
|
16
13
|
from udata.utils import faker
|
|
17
|
-
from udata.tests.helpers import (
|
|
18
|
-
assert200, assert201, assert204, assert400, assert403
|
|
19
|
-
)
|
|
20
14
|
|
|
15
|
+
from .. import actions
|
|
21
16
|
from ..models import (
|
|
22
|
-
|
|
23
|
-
|
|
17
|
+
VALIDATION_ACCEPTED,
|
|
18
|
+
VALIDATION_PENDING,
|
|
19
|
+
VALIDATION_REFUSED,
|
|
20
|
+
HarvestSource,
|
|
21
|
+
HarvestSourceValidation,
|
|
24
22
|
)
|
|
25
23
|
from .factories import HarvestSourceFactory, MockBackendsMixin
|
|
26
24
|
|
|
27
|
-
|
|
28
25
|
log = logging.getLogger(__name__)
|
|
29
26
|
|
|
30
27
|
|
|
31
|
-
|
|
32
|
-
@pytest.mark.usefixtures('clean_db')
|
|
28
|
+
@pytest.mark.usefixtures("clean_db")
|
|
33
29
|
class HarvestAPITest(MockBackendsMixin):
|
|
34
30
|
modules = []
|
|
35
31
|
|
|
36
32
|
def test_list_backends(self, api):
|
|
37
|
-
|
|
38
|
-
response = api.get(url_for(
|
|
33
|
+
"""It should fetch the harvest backends list from the API"""
|
|
34
|
+
response = api.get(url_for("api.harvest_backends"))
|
|
39
35
|
assert200(response)
|
|
40
36
|
assert len(response.json) == len(actions.list_backends())
|
|
41
37
|
for data in response.json:
|
|
42
|
-
assert
|
|
43
|
-
assert
|
|
44
|
-
assert
|
|
45
|
-
assert isinstance(data[
|
|
38
|
+
assert "id" in data
|
|
39
|
+
assert "label" in data
|
|
40
|
+
assert "filters" in data
|
|
41
|
+
assert isinstance(data["filters"], (list, tuple))
|
|
46
42
|
|
|
47
43
|
def test_list_sources(self, api):
|
|
48
44
|
sources = HarvestSourceFactory.create_batch(3)
|
|
49
45
|
|
|
50
|
-
response = api.get(url_for(
|
|
46
|
+
response = api.get(url_for("api.harvest_sources"))
|
|
51
47
|
assert200(response)
|
|
52
|
-
assert len(response.json[
|
|
48
|
+
assert len(response.json["data"]) == len(sources)
|
|
53
49
|
|
|
54
50
|
def test_list_sources_exclude_deleted(self, api):
|
|
55
51
|
sources = HarvestSourceFactory.create_batch(3)
|
|
56
52
|
HarvestSourceFactory.create_batch(2, deleted=datetime.utcnow())
|
|
57
53
|
|
|
58
|
-
response = api.get(url_for(
|
|
54
|
+
response = api.get(url_for("api.harvest_sources"))
|
|
59
55
|
assert200(response)
|
|
60
|
-
assert len(response.json[
|
|
56
|
+
assert len(response.json["data"]) == len(sources)
|
|
61
57
|
|
|
62
58
|
def test_list_sources_include_deleted(self, api):
|
|
63
59
|
sources = HarvestSourceFactory.create_batch(3)
|
|
64
60
|
sources.extend(HarvestSourceFactory.create_batch(2, deleted=datetime.utcnow()))
|
|
65
61
|
|
|
66
|
-
response = api.get(url_for(
|
|
62
|
+
response = api.get(url_for("api.harvest_sources", deleted=True))
|
|
67
63
|
assert200(response)
|
|
68
|
-
assert len(response.json[
|
|
64
|
+
assert len(response.json["data"]) == len(sources)
|
|
69
65
|
|
|
70
66
|
def test_list_sources_for_owner(self, api):
|
|
71
67
|
owner = UserFactory()
|
|
72
68
|
sources = HarvestSourceFactory.create_batch(3, owner=owner)
|
|
73
69
|
HarvestSourceFactory()
|
|
74
70
|
|
|
75
|
-
url = url_for(
|
|
71
|
+
url = url_for("api.harvest_sources", owner=str(owner.id))
|
|
76
72
|
response = api.get(url)
|
|
77
73
|
assert200(response)
|
|
78
74
|
|
|
79
|
-
assert len(response.json[
|
|
75
|
+
assert len(response.json["data"]) == len(sources)
|
|
80
76
|
|
|
81
77
|
def test_list_sources_for_org(self, api):
|
|
82
78
|
org = OrganizationFactory()
|
|
83
79
|
sources = HarvestSourceFactory.create_batch(3, organization=org)
|
|
84
80
|
HarvestSourceFactory()
|
|
85
81
|
|
|
86
|
-
response = api.get(url_for(
|
|
82
|
+
response = api.get(url_for("api.harvest_sources", owner=str(org.id)))
|
|
87
83
|
assert200(response)
|
|
88
84
|
|
|
89
|
-
assert len(response.json[
|
|
85
|
+
assert len(response.json["data"]) == len(sources)
|
|
90
86
|
|
|
91
87
|
def test_create_source_with_owner(self, api):
|
|
92
|
-
|
|
88
|
+
"""It should create and attach a new source to an owner"""
|
|
93
89
|
user = api.login()
|
|
94
|
-
data = {
|
|
95
|
-
|
|
96
|
-
'url': faker.url(),
|
|
97
|
-
'backend': 'factory'
|
|
98
|
-
}
|
|
99
|
-
response = api.post(url_for('api.harvest_sources'), data)
|
|
90
|
+
data = {"name": faker.word(), "url": faker.url(), "backend": "factory"}
|
|
91
|
+
response = api.post(url_for("api.harvest_sources"), data)
|
|
100
92
|
|
|
101
93
|
assert201(response)
|
|
102
94
|
|
|
103
95
|
source = response.json
|
|
104
|
-
assert source[
|
|
105
|
-
assert source[
|
|
106
|
-
assert source[
|
|
96
|
+
assert source["validation"]["state"] == VALIDATION_PENDING
|
|
97
|
+
assert source["owner"]["id"] == str(user.id)
|
|
98
|
+
assert source["organization"] is None
|
|
107
99
|
|
|
108
100
|
def test_create_source_with_org(self, api):
|
|
109
|
-
|
|
101
|
+
"""It should create and attach a new source to an organization"""
|
|
110
102
|
user = api.login()
|
|
111
|
-
member = Member(user=user, role=
|
|
103
|
+
member = Member(user=user, role="admin")
|
|
112
104
|
org = OrganizationFactory(members=[member])
|
|
113
105
|
data = {
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
106
|
+
"name": faker.word(),
|
|
107
|
+
"url": faker.url(),
|
|
108
|
+
"backend": "factory",
|
|
109
|
+
"organization": str(org.id),
|
|
118
110
|
}
|
|
119
|
-
response = api.post(url_for(
|
|
111
|
+
response = api.post(url_for("api.harvest_sources"), data)
|
|
120
112
|
|
|
121
113
|
assert201(response)
|
|
122
114
|
|
|
123
115
|
source = response.json
|
|
124
|
-
assert source[
|
|
125
|
-
assert source[
|
|
126
|
-
assert source[
|
|
116
|
+
assert source["validation"]["state"] == VALIDATION_PENDING
|
|
117
|
+
assert source["owner"] is None
|
|
118
|
+
assert source["organization"]["id"] == str(org.id)
|
|
127
119
|
|
|
128
120
|
def test_create_source_with_org_not_member(self, api):
|
|
129
|
-
|
|
121
|
+
"""It should create and attach a new source to an organization"""
|
|
130
122
|
user = api.login()
|
|
131
|
-
member = Member(user=user, role=
|
|
123
|
+
member = Member(user=user, role="editor")
|
|
132
124
|
org = OrganizationFactory(members=[member])
|
|
133
125
|
data = {
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
126
|
+
"name": faker.word(),
|
|
127
|
+
"url": faker.url(),
|
|
128
|
+
"backend": "factory",
|
|
129
|
+
"organization": str(org.id),
|
|
138
130
|
}
|
|
139
|
-
response = api.post(url_for(
|
|
131
|
+
response = api.post(url_for("api.harvest_sources"), data)
|
|
140
132
|
|
|
141
133
|
assert403(response)
|
|
142
134
|
|
|
143
135
|
def test_create_source_with_config(self, api):
|
|
144
|
-
|
|
136
|
+
"""It should create a new source with configuration"""
|
|
145
137
|
api.login()
|
|
146
138
|
data = {
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
{
|
|
153
|
-
{
|
|
154
|
-
{
|
|
139
|
+
"name": faker.word(),
|
|
140
|
+
"url": faker.url(),
|
|
141
|
+
"backend": "factory",
|
|
142
|
+
"config": {
|
|
143
|
+
"filters": [
|
|
144
|
+
{"key": "test", "value": 1},
|
|
145
|
+
{"key": "test", "value": 42},
|
|
146
|
+
{"key": "tag", "value": "my-tag"},
|
|
155
147
|
],
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
}
|
|
160
|
-
}
|
|
148
|
+
"features": {
|
|
149
|
+
"test": True,
|
|
150
|
+
"toggled": True,
|
|
151
|
+
},
|
|
152
|
+
},
|
|
161
153
|
}
|
|
162
|
-
response = api.post(url_for(
|
|
154
|
+
response = api.post(url_for("api.harvest_sources"), data)
|
|
163
155
|
|
|
164
156
|
assert201(response)
|
|
165
157
|
|
|
166
158
|
source = response.json
|
|
167
|
-
assert source[
|
|
168
|
-
|
|
169
|
-
{
|
|
170
|
-
{
|
|
171
|
-
{
|
|
159
|
+
assert source["config"] == {
|
|
160
|
+
"filters": [
|
|
161
|
+
{"key": "test", "value": 1},
|
|
162
|
+
{"key": "test", "value": 42},
|
|
163
|
+
{"key": "tag", "value": "my-tag"},
|
|
172
164
|
],
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
}
|
|
165
|
+
"features": {
|
|
166
|
+
"test": True,
|
|
167
|
+
"toggled": True,
|
|
168
|
+
},
|
|
177
169
|
}
|
|
178
170
|
|
|
179
171
|
def test_create_source_with_unknown_filter(self, api):
|
|
180
|
-
|
|
172
|
+
"""Can only use known filters in config"""
|
|
181
173
|
api.login()
|
|
182
174
|
data = {
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
{
|
|
175
|
+
"name": faker.word(),
|
|
176
|
+
"url": faker.url(),
|
|
177
|
+
"backend": "factory",
|
|
178
|
+
"config": {
|
|
179
|
+
"filters": [
|
|
180
|
+
{"key": "unknown", "value": "any"},
|
|
189
181
|
]
|
|
190
|
-
}
|
|
182
|
+
},
|
|
191
183
|
}
|
|
192
|
-
response = api.post(url_for(
|
|
184
|
+
response = api.post(url_for("api.harvest_sources"), data)
|
|
193
185
|
|
|
194
186
|
assert400(response)
|
|
195
187
|
|
|
196
188
|
def test_create_source_with_bad_filter_type(self, api):
|
|
197
|
-
|
|
189
|
+
"""Can only use the xpected filter type"""
|
|
198
190
|
api.login()
|
|
199
191
|
data = {
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
{
|
|
192
|
+
"name": faker.word(),
|
|
193
|
+
"url": faker.url(),
|
|
194
|
+
"backend": "factory",
|
|
195
|
+
"config": {
|
|
196
|
+
"filters": [
|
|
197
|
+
{"key": "test", "value": "not-an-integer"},
|
|
206
198
|
]
|
|
207
|
-
}
|
|
199
|
+
},
|
|
208
200
|
}
|
|
209
|
-
response = api.post(url_for(
|
|
201
|
+
response = api.post(url_for("api.harvest_sources"), data)
|
|
210
202
|
|
|
211
203
|
assert400(response)
|
|
212
204
|
|
|
213
205
|
def test_create_source_with_bad_filter_format(self, api):
|
|
214
|
-
|
|
206
|
+
"""Filters should have the right format"""
|
|
215
207
|
api.login()
|
|
216
208
|
data = {
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
{
|
|
209
|
+
"name": faker.word(),
|
|
210
|
+
"url": faker.url(),
|
|
211
|
+
"backend": "factory",
|
|
212
|
+
"config": {
|
|
213
|
+
"filters": [
|
|
214
|
+
{"key": "unknown", "notvalue": "any"},
|
|
223
215
|
]
|
|
224
|
-
}
|
|
216
|
+
},
|
|
225
217
|
}
|
|
226
|
-
response = api.post(url_for(
|
|
218
|
+
response = api.post(url_for("api.harvest_sources"), data)
|
|
227
219
|
|
|
228
220
|
assert400(response)
|
|
229
221
|
|
|
230
222
|
def test_create_source_with_unknown_feature(self, api):
|
|
231
|
-
|
|
223
|
+
"""Can only use known features in config"""
|
|
232
224
|
api.login()
|
|
233
225
|
data = {
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
}
|
|
226
|
+
"name": faker.word(),
|
|
227
|
+
"url": faker.url(),
|
|
228
|
+
"backend": "factory",
|
|
229
|
+
"config": {
|
|
230
|
+
"features": {"unknown": True},
|
|
231
|
+
},
|
|
240
232
|
}
|
|
241
|
-
response = api.post(url_for(
|
|
233
|
+
response = api.post(url_for("api.harvest_sources"), data)
|
|
242
234
|
|
|
243
235
|
assert400(response)
|
|
244
236
|
|
|
245
237
|
def test_create_source_with_false_feature(self, api):
|
|
246
|
-
|
|
238
|
+
"""It should handled negative values"""
|
|
247
239
|
api.login()
|
|
248
240
|
data = {
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
241
|
+
"name": faker.word(),
|
|
242
|
+
"url": faker.url(),
|
|
243
|
+
"backend": "factory",
|
|
244
|
+
"config": {
|
|
245
|
+
"features": {
|
|
246
|
+
"test": False,
|
|
247
|
+
"toggled": False,
|
|
256
248
|
}
|
|
257
|
-
}
|
|
249
|
+
},
|
|
258
250
|
}
|
|
259
|
-
response = api.post(url_for(
|
|
251
|
+
response = api.post(url_for("api.harvest_sources"), data)
|
|
260
252
|
|
|
261
253
|
assert201(response)
|
|
262
254
|
|
|
263
255
|
source = response.json
|
|
264
|
-
assert source[
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
256
|
+
assert source["config"] == {
|
|
257
|
+
"features": {
|
|
258
|
+
"test": False,
|
|
259
|
+
"toggled": False,
|
|
260
|
+
}
|
|
261
|
+
}
|
|
268
262
|
|
|
269
263
|
def test_create_source_with_not_boolean_feature(self, api):
|
|
270
|
-
|
|
264
|
+
"""It should handled negative values"""
|
|
271
265
|
api.login()
|
|
272
266
|
data = {
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
267
|
+
"name": faker.word(),
|
|
268
|
+
"url": faker.url(),
|
|
269
|
+
"backend": "factory",
|
|
270
|
+
"config": {
|
|
271
|
+
"features": {
|
|
272
|
+
"test": "not a boolean",
|
|
279
273
|
}
|
|
280
|
-
}
|
|
274
|
+
},
|
|
281
275
|
}
|
|
282
|
-
response = api.post(url_for(
|
|
276
|
+
response = api.post(url_for("api.harvest_sources"), data)
|
|
283
277
|
|
|
284
278
|
assert400(response)
|
|
285
279
|
|
|
286
280
|
def test_create_source_with_config_with_custom_key(self, api):
|
|
287
281
|
api.login()
|
|
288
282
|
data = {
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
283
|
+
"name": faker.word(),
|
|
284
|
+
"url": faker.url(),
|
|
285
|
+
"backend": "factory",
|
|
286
|
+
"config": {"custom": "value"},
|
|
293
287
|
}
|
|
294
|
-
response = api.post(url_for(
|
|
288
|
+
response = api.post(url_for("api.harvest_sources"), data)
|
|
295
289
|
|
|
296
290
|
assert201(response)
|
|
297
291
|
|
|
298
292
|
source = response.json
|
|
299
|
-
assert source[
|
|
293
|
+
assert source["config"] == {"custom": "value"}
|
|
300
294
|
|
|
301
295
|
def test_update_source(self, api):
|
|
302
|
-
|
|
296
|
+
"""It should update a source if owner or orga member"""
|
|
303
297
|
user = api.login()
|
|
304
298
|
source = HarvestSourceFactory(owner=user)
|
|
305
299
|
new_url = faker.url()
|
|
306
300
|
data = {
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
301
|
+
"name": source.name,
|
|
302
|
+
"description": source.description,
|
|
303
|
+
"url": new_url,
|
|
304
|
+
"backend": "factory",
|
|
311
305
|
}
|
|
312
|
-
api_url = url_for(
|
|
306
|
+
api_url = url_for("api.harvest_source", ident=str(source.id))
|
|
313
307
|
response = api.put(api_url, data)
|
|
314
308
|
assert200(response)
|
|
315
|
-
assert response.json[
|
|
309
|
+
assert response.json["url"] == new_url
|
|
316
310
|
|
|
317
311
|
# Source is now owned by orga, with user as member
|
|
318
312
|
source.organization = OrganizationFactory(members=[Member(user=user)])
|
|
319
313
|
source.save()
|
|
320
|
-
api_url = url_for(
|
|
314
|
+
api_url = url_for("api.harvest_source", ident=str(source.id))
|
|
321
315
|
response = api.put(api_url, data)
|
|
322
316
|
assert200(response)
|
|
323
317
|
|
|
324
318
|
def test_update_source_require_permission(self, api):
|
|
325
|
-
|
|
319
|
+
"""It should not update a source if not the owner"""
|
|
326
320
|
api.login()
|
|
327
321
|
source = HarvestSourceFactory()
|
|
328
322
|
new_url: str = faker.url()
|
|
329
323
|
data = {
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
324
|
+
"name": source.name,
|
|
325
|
+
"description": source.description,
|
|
326
|
+
"url": new_url,
|
|
327
|
+
"backend": "factory",
|
|
334
328
|
}
|
|
335
|
-
api_url: str = url_for(
|
|
329
|
+
api_url: str = url_for("api.harvest_source", ident=str(source.id))
|
|
336
330
|
response = api.put(api_url, data)
|
|
337
331
|
|
|
338
332
|
assert403(response)
|
|
339
333
|
|
|
340
334
|
def test_validate_source(self, api):
|
|
341
|
-
|
|
335
|
+
"""It should allow to validate a source if admin"""
|
|
342
336
|
user = api.login(AdminFactory())
|
|
343
337
|
source = HarvestSourceFactory()
|
|
344
338
|
|
|
345
|
-
data = {
|
|
346
|
-
url = url_for(
|
|
339
|
+
data = {"state": VALIDATION_ACCEPTED}
|
|
340
|
+
url = url_for("api.validate_harvest_source", ident=str(source.id))
|
|
347
341
|
response = api.post(url, data)
|
|
348
342
|
assert200(response)
|
|
349
343
|
|
|
@@ -352,53 +346,57 @@ class HarvestAPITest(MockBackendsMixin):
|
|
|
352
346
|
assert source.validation.by == user
|
|
353
347
|
|
|
354
348
|
def test_reject_source(self, api):
|
|
355
|
-
|
|
349
|
+
"""It should allow to reject a source if admin"""
|
|
356
350
|
user = api.login(AdminFactory())
|
|
357
351
|
source = HarvestSourceFactory()
|
|
358
352
|
|
|
359
|
-
data = {
|
|
360
|
-
url = url_for(
|
|
353
|
+
data = {"state": VALIDATION_REFUSED, "comment": "Not valid"}
|
|
354
|
+
url = url_for("api.validate_harvest_source", ident=str(source.id))
|
|
361
355
|
response = api.post(url, data)
|
|
362
356
|
assert200(response)
|
|
363
357
|
|
|
364
358
|
source.reload()
|
|
365
359
|
assert source.validation.state == VALIDATION_REFUSED
|
|
366
|
-
assert source.validation.comment ==
|
|
360
|
+
assert source.validation.comment == "Not valid"
|
|
367
361
|
assert source.validation.by == user
|
|
368
362
|
|
|
369
363
|
def test_validate_source_is_admin_only(self, api):
|
|
370
|
-
|
|
364
|
+
"""It should allow to validate a source if admin"""
|
|
371
365
|
api.login()
|
|
372
366
|
source = HarvestSourceFactory()
|
|
373
367
|
|
|
374
|
-
data = {
|
|
375
|
-
url = url_for(
|
|
368
|
+
data = {"validate": True}
|
|
369
|
+
url = url_for("api.validate_harvest_source", ident=str(source.id))
|
|
376
370
|
response = api.post(url, data)
|
|
377
371
|
assert403(response)
|
|
378
372
|
|
|
379
373
|
def test_get_source(self, api):
|
|
380
374
|
source = HarvestSourceFactory()
|
|
381
375
|
|
|
382
|
-
url = url_for(
|
|
376
|
+
url = url_for("api.harvest_source", ident=str(source.id))
|
|
383
377
|
response = api.get(url)
|
|
384
378
|
assert200(response)
|
|
385
379
|
|
|
386
380
|
def test_source_preview(self, api):
|
|
387
381
|
api.login()
|
|
388
|
-
source = HarvestSourceFactory(backend=
|
|
382
|
+
source = HarvestSourceFactory(backend="factory")
|
|
389
383
|
|
|
390
|
-
url = url_for(
|
|
384
|
+
url = url_for("api.preview_harvest_source", ident=str(source.id))
|
|
391
385
|
response = api.get(url)
|
|
392
386
|
assert200(response)
|
|
393
387
|
|
|
394
388
|
@pytest.mark.options(HARVEST_ENABLE_MANUAL_RUN=True)
|
|
395
389
|
def test_run_source(self, mocker: MockerFixture, api: ApiClient):
|
|
396
|
-
launch = mocker.patch.object(actions.harvest,
|
|
390
|
+
launch = mocker.patch.object(actions.harvest, "delay")
|
|
397
391
|
user = api.login()
|
|
398
392
|
|
|
399
|
-
source = HarvestSourceFactory(
|
|
393
|
+
source = HarvestSourceFactory(
|
|
394
|
+
backend="factory",
|
|
395
|
+
owner=user,
|
|
396
|
+
validation=HarvestSourceValidation(state=VALIDATION_ACCEPTED),
|
|
397
|
+
)
|
|
400
398
|
|
|
401
|
-
url = url_for(
|
|
399
|
+
url = url_for("api.run_harvest_source", ident=str(source.id))
|
|
402
400
|
response = api.post(url)
|
|
403
401
|
assert200(response)
|
|
404
402
|
|
|
@@ -406,12 +404,16 @@ class HarvestAPITest(MockBackendsMixin):
|
|
|
406
404
|
|
|
407
405
|
@pytest.mark.options(HARVEST_ENABLE_MANUAL_RUN=False)
|
|
408
406
|
def test_cannot_run_source_if_disabled(self, mocker: MockerFixture, api: ApiClient):
|
|
409
|
-
launch = mocker.patch.object(actions.harvest,
|
|
407
|
+
launch = mocker.patch.object(actions.harvest, "delay")
|
|
410
408
|
user = api.login()
|
|
411
409
|
|
|
412
|
-
source = HarvestSourceFactory(
|
|
410
|
+
source = HarvestSourceFactory(
|
|
411
|
+
backend="factory",
|
|
412
|
+
owner=user,
|
|
413
|
+
validation=HarvestSourceValidation(state=VALIDATION_ACCEPTED),
|
|
414
|
+
)
|
|
413
415
|
|
|
414
|
-
url = url_for(
|
|
416
|
+
url = url_for("api.run_harvest_source", ident=str(source.id))
|
|
415
417
|
response = api.post(url)
|
|
416
418
|
assert400(response)
|
|
417
419
|
|
|
@@ -419,13 +421,17 @@ class HarvestAPITest(MockBackendsMixin):
|
|
|
419
421
|
|
|
420
422
|
@pytest.mark.options(HARVEST_ENABLE_MANUAL_RUN=True)
|
|
421
423
|
def test_cannot_run_source_if_not_owned(self, mocker: MockerFixture, api: ApiClient):
|
|
422
|
-
launch = mocker.patch.object(actions.harvest,
|
|
424
|
+
launch = mocker.patch.object(actions.harvest, "delay")
|
|
423
425
|
other_user = UserFactory()
|
|
424
426
|
api.login()
|
|
425
427
|
|
|
426
|
-
source = HarvestSourceFactory(
|
|
428
|
+
source = HarvestSourceFactory(
|
|
429
|
+
backend="factory",
|
|
430
|
+
owner=other_user,
|
|
431
|
+
validation=HarvestSourceValidation(state=VALIDATION_ACCEPTED),
|
|
432
|
+
)
|
|
427
433
|
|
|
428
|
-
url = url_for(
|
|
434
|
+
url = url_for("api.run_harvest_source", ident=str(source.id))
|
|
429
435
|
response = api.post(url)
|
|
430
436
|
assert403(response)
|
|
431
437
|
|
|
@@ -433,12 +439,16 @@ class HarvestAPITest(MockBackendsMixin):
|
|
|
433
439
|
|
|
434
440
|
@pytest.mark.options(HARVEST_ENABLE_MANUAL_RUN=True)
|
|
435
441
|
def test_cannot_run_source_if_not_validated(self, mocker: MockerFixture, api: ApiClient):
|
|
436
|
-
launch = mocker.patch.object(actions.harvest,
|
|
442
|
+
launch = mocker.patch.object(actions.harvest, "delay")
|
|
437
443
|
user = api.login()
|
|
438
444
|
|
|
439
|
-
source = HarvestSourceFactory(
|
|
445
|
+
source = HarvestSourceFactory(
|
|
446
|
+
backend="factory",
|
|
447
|
+
owner=user,
|
|
448
|
+
validation=HarvestSourceValidation(state=VALIDATION_PENDING),
|
|
449
|
+
)
|
|
440
450
|
|
|
441
|
-
url = url_for(
|
|
451
|
+
url = url_for("api.run_harvest_source", ident=str(source.id))
|
|
442
452
|
response = api.post(url)
|
|
443
453
|
assert400(response)
|
|
444
454
|
|
|
@@ -446,19 +456,15 @@ class HarvestAPITest(MockBackendsMixin):
|
|
|
446
456
|
|
|
447
457
|
def test_source_from_config(self, api):
|
|
448
458
|
api.login()
|
|
449
|
-
data = {
|
|
450
|
-
|
|
451
|
-
'url': faker.url(),
|
|
452
|
-
'backend': 'factory'
|
|
453
|
-
}
|
|
454
|
-
response = api.post(url_for('api.preview_harvest_source_config'), data)
|
|
459
|
+
data = {"name": faker.word(), "url": faker.url(), "backend": "factory"}
|
|
460
|
+
response = api.post(url_for("api.preview_harvest_source_config"), data)
|
|
455
461
|
assert200(response)
|
|
456
462
|
|
|
457
463
|
def test_delete_source(self, api):
|
|
458
464
|
user = api.login()
|
|
459
465
|
source = HarvestSourceFactory(owner=user)
|
|
460
466
|
|
|
461
|
-
url = url_for(
|
|
467
|
+
url = url_for("api.harvest_source", ident=str(source.id))
|
|
462
468
|
response = api.delete(url)
|
|
463
469
|
assert204(response)
|
|
464
470
|
|
|
@@ -466,44 +472,44 @@ class HarvestAPITest(MockBackendsMixin):
|
|
|
466
472
|
assert len(deleted_sources) == 1
|
|
467
473
|
|
|
468
474
|
def test_delete_source_require_permission(self, api):
|
|
469
|
-
|
|
475
|
+
"""It should not delete a source if not the owner"""
|
|
470
476
|
api.login()
|
|
471
477
|
source = HarvestSourceFactory()
|
|
472
478
|
|
|
473
|
-
url = url_for(
|
|
479
|
+
url = url_for("api.harvest_source", ident=str(source.id))
|
|
474
480
|
response = api.delete(url)
|
|
475
481
|
|
|
476
482
|
assert403(response)
|
|
477
483
|
|
|
478
484
|
def test_schedule_source(self, api):
|
|
479
|
-
|
|
485
|
+
"""It should allow to schedule a source if admin"""
|
|
480
486
|
api.login(AdminFactory())
|
|
481
487
|
source = HarvestSourceFactory()
|
|
482
488
|
|
|
483
|
-
data =
|
|
484
|
-
url = url_for(
|
|
489
|
+
data = "0 0 * * *"
|
|
490
|
+
url = url_for("api.schedule_harvest_source", ident=str(source.id))
|
|
485
491
|
response = api.post(url, data)
|
|
486
492
|
assert200(response)
|
|
487
493
|
|
|
488
|
-
assert response.json[
|
|
494
|
+
assert response.json["schedule"] == "0 0 * * *"
|
|
489
495
|
|
|
490
496
|
source.reload()
|
|
491
497
|
assert source.periodic_task is not None
|
|
492
498
|
periodic_task = source.periodic_task
|
|
493
|
-
assert periodic_task.crontab.hour ==
|
|
494
|
-
assert periodic_task.crontab.minute ==
|
|
495
|
-
assert periodic_task.crontab.day_of_week ==
|
|
496
|
-
assert periodic_task.crontab.day_of_month ==
|
|
497
|
-
assert periodic_task.crontab.month_of_year ==
|
|
499
|
+
assert periodic_task.crontab.hour == "0"
|
|
500
|
+
assert periodic_task.crontab.minute == "0"
|
|
501
|
+
assert periodic_task.crontab.day_of_week == "*"
|
|
502
|
+
assert periodic_task.crontab.day_of_month == "*"
|
|
503
|
+
assert periodic_task.crontab.month_of_year == "*"
|
|
498
504
|
assert periodic_task.enabled
|
|
499
505
|
|
|
500
506
|
def test_schedule_source_is_admin_only(self, api):
|
|
501
|
-
|
|
507
|
+
"""It should only allow admins to schedule a source"""
|
|
502
508
|
api.login()
|
|
503
509
|
source = HarvestSourceFactory()
|
|
504
510
|
|
|
505
|
-
data =
|
|
506
|
-
url = url_for(
|
|
511
|
+
data = "0 0 * * *"
|
|
512
|
+
url = url_for("api.schedule_harvest_source", ident=str(source.id))
|
|
507
513
|
response = api.post(url, data)
|
|
508
514
|
assert403(response)
|
|
509
515
|
|
|
@@ -511,18 +517,18 @@ class HarvestAPITest(MockBackendsMixin):
|
|
|
511
517
|
assert source.periodic_task is None
|
|
512
518
|
|
|
513
519
|
def test_unschedule_source(self, api):
|
|
514
|
-
|
|
520
|
+
"""It should allow to unschedule a source if admin"""
|
|
515
521
|
api.login(AdminFactory())
|
|
516
522
|
periodic_task = PeriodicTask.objects.create(
|
|
517
|
-
task=
|
|
523
|
+
task="harvest",
|
|
518
524
|
name=faker.name(),
|
|
519
525
|
description=faker.sentence(),
|
|
520
526
|
enabled=True,
|
|
521
|
-
crontab=PeriodicTask.Crontab()
|
|
527
|
+
crontab=PeriodicTask.Crontab(),
|
|
522
528
|
)
|
|
523
529
|
source = HarvestSourceFactory(periodic_task=periodic_task)
|
|
524
530
|
|
|
525
|
-
url = url_for(
|
|
531
|
+
url = url_for("api.schedule_harvest_source", ident=str(source.id))
|
|
526
532
|
response = api.delete(url)
|
|
527
533
|
assert204(response)
|
|
528
534
|
|
|
@@ -530,18 +536,18 @@ class HarvestAPITest(MockBackendsMixin):
|
|
|
530
536
|
assert source.periodic_task is None
|
|
531
537
|
|
|
532
538
|
def test_unschedule_source_is_admin_only(self, api):
|
|
533
|
-
|
|
539
|
+
"""It should only allow admins to unschedule a source"""
|
|
534
540
|
api.login()
|
|
535
541
|
periodic_task = PeriodicTask.objects.create(
|
|
536
|
-
task=
|
|
542
|
+
task="harvest",
|
|
537
543
|
name=faker.name(),
|
|
538
544
|
description=faker.sentence(),
|
|
539
545
|
enabled=True,
|
|
540
|
-
crontab=PeriodicTask.Crontab()
|
|
546
|
+
crontab=PeriodicTask.Crontab(),
|
|
541
547
|
)
|
|
542
548
|
source = HarvestSourceFactory(periodic_task=periodic_task)
|
|
543
549
|
|
|
544
|
-
url = url_for(
|
|
550
|
+
url = url_for("api.schedule_harvest_source", ident=str(source.id))
|
|
545
551
|
response = api.delete(url)
|
|
546
552
|
assert403(response)
|
|
547
553
|
|