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
|
@@ -2,15 +2,16 @@ from udata.forms import ModelForm, fields, validators
|
|
|
2
2
|
from udata.i18n import lazy_gettext as _
|
|
3
3
|
from udata.models import ContactPoint
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
__all__ = ('ContactPointForm',)
|
|
5
|
+
__all__ = ("ContactPointForm",)
|
|
7
6
|
|
|
8
7
|
|
|
9
8
|
class ContactPointForm(ModelForm):
|
|
10
9
|
model_class = ContactPoint
|
|
11
10
|
|
|
12
|
-
name = fields.StringField(
|
|
13
|
-
|
|
14
|
-
|
|
11
|
+
name = fields.StringField(
|
|
12
|
+
_("Name"),
|
|
13
|
+
[validators.DataRequired(), validators.NoURLs(_("URLs not allowed in this field"))],
|
|
14
|
+
)
|
|
15
|
+
email = fields.StringField(_("Email"), [validators.DataRequired(), validators.Email()])
|
|
15
16
|
owner = fields.CurrentUserField()
|
|
16
|
-
organization = fields.PublishAsField(_(
|
|
17
|
+
organization = fields.PublishAsField(_("Publish as"))
|
|
@@ -1,13 +1,11 @@
|
|
|
1
|
-
from udata.mongo import db
|
|
2
1
|
from udata.core.owned import Owned, OwnedQuerySet
|
|
2
|
+
from udata.mongo import db
|
|
3
3
|
|
|
4
|
-
__all__ = (
|
|
4
|
+
__all__ = ("ContactPoint",)
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
class ContactPoint(db.Document, Owned):
|
|
8
8
|
email = db.StringField(max_length=255, required=True)
|
|
9
9
|
name = db.StringField(max_length=255, required=True)
|
|
10
10
|
|
|
11
|
-
meta = {
|
|
12
|
-
'queryset_class': OwnedQuerySet
|
|
13
|
-
}
|
|
11
|
+
meta = {"queryset_class": OwnedQuerySet}
|
udata/core/dataservices/api.py
CHANGED
|
@@ -1,31 +1,34 @@
|
|
|
1
1
|
from datetime import datetime
|
|
2
|
+
|
|
3
|
+
import mongoengine
|
|
2
4
|
from flask import request
|
|
3
5
|
from flask_login import current_user
|
|
4
|
-
import mongoengine
|
|
5
6
|
|
|
6
|
-
from udata.api import
|
|
7
|
+
from udata.api import API, api
|
|
7
8
|
from udata.api_fields import patch
|
|
8
9
|
from udata.core.dataset.permissions import OwnablePermission
|
|
9
10
|
from udata.core.followers.api import FollowAPI
|
|
11
|
+
|
|
10
12
|
from .models import Dataservice
|
|
11
13
|
|
|
12
|
-
ns = api.namespace(
|
|
14
|
+
ns = api.namespace("dataservices", "Dataservices related operations (beta)")
|
|
13
15
|
|
|
14
16
|
|
|
15
|
-
@ns.route(
|
|
17
|
+
@ns.route("/", endpoint="dataservices")
|
|
16
18
|
class DataservicesAPI(API):
|
|
17
|
-
|
|
18
|
-
|
|
19
|
+
"""Dataservices collection endpoint"""
|
|
20
|
+
|
|
21
|
+
@api.doc("list_dataservices")
|
|
19
22
|
@api.expect(Dataservice.__index_parser__)
|
|
20
23
|
@api.marshal_with(Dataservice.__page_fields__)
|
|
21
24
|
def get(self):
|
|
22
|
-
|
|
25
|
+
"""List or search all dataservices"""
|
|
23
26
|
query = Dataservice.objects.visible()
|
|
24
27
|
|
|
25
28
|
return Dataservice.apply_sort_filters_and_pagination(query)
|
|
26
29
|
|
|
27
30
|
@api.secure
|
|
28
|
-
@api.doc(
|
|
31
|
+
@api.doc("create_dataservice", responses={400: "Validation error"})
|
|
29
32
|
@api.expect(Dataservice.__write_fields__)
|
|
30
33
|
@api.marshal_with(Dataservice.__read_fields__, code=201)
|
|
31
34
|
def post(self):
|
|
@@ -41,22 +44,22 @@ class DataservicesAPI(API):
|
|
|
41
44
|
return dataservice, 201
|
|
42
45
|
|
|
43
46
|
|
|
44
|
-
@ns.route(
|
|
47
|
+
@ns.route("/<dataservice:dataservice>/", endpoint="dataservice")
|
|
45
48
|
class DataserviceAPI(API):
|
|
46
|
-
@api.doc(
|
|
49
|
+
@api.doc("get_dataservice")
|
|
47
50
|
@api.marshal_with(Dataservice.__read_fields__)
|
|
48
51
|
def get(self, dataservice):
|
|
49
52
|
if dataservice.deleted_at and not OwnablePermission(dataservice).can():
|
|
50
|
-
api.abort(410,
|
|
53
|
+
api.abort(410, "Dataservice has been deleted")
|
|
51
54
|
return dataservice
|
|
52
55
|
|
|
53
56
|
@api.secure
|
|
54
|
-
@api.doc(
|
|
57
|
+
@api.doc("update_dataservice", responses={400: "Validation error"})
|
|
55
58
|
@api.expect(Dataservice.__write_fields__)
|
|
56
59
|
@api.marshal_with(Dataservice.__read_fields__)
|
|
57
60
|
def patch(self, dataservice):
|
|
58
61
|
if dataservice.deleted_at:
|
|
59
|
-
api.abort(410,
|
|
62
|
+
api.abort(410, "dataservice has been deleted")
|
|
60
63
|
|
|
61
64
|
OwnablePermission(dataservice).test()
|
|
62
65
|
|
|
@@ -70,23 +73,25 @@ class DataserviceAPI(API):
|
|
|
70
73
|
api.abort(400, e.message)
|
|
71
74
|
|
|
72
75
|
@api.secure
|
|
73
|
-
@api.doc(
|
|
74
|
-
@api.response(204,
|
|
76
|
+
@api.doc("delete_dataservice")
|
|
77
|
+
@api.response(204, "dataservice deleted")
|
|
75
78
|
def delete(self, dataservice):
|
|
76
79
|
if dataservice.deleted_at:
|
|
77
|
-
api.abort(410,
|
|
80
|
+
api.abort(410, "dataservice has been deleted")
|
|
78
81
|
|
|
79
82
|
OwnablePermission(dataservice).test()
|
|
80
83
|
dataservice.deleted_at = datetime.utcnow()
|
|
81
84
|
dataservice.modified_at = datetime.utcnow()
|
|
82
85
|
dataservice.save()
|
|
83
86
|
|
|
84
|
-
return
|
|
87
|
+
return "", 204
|
|
85
88
|
|
|
86
89
|
|
|
87
|
-
@ns.route(
|
|
88
|
-
@ns.doc(
|
|
89
|
-
|
|
90
|
-
|
|
90
|
+
@ns.route("/<id>/followers/", endpoint="dataservice_followers")
|
|
91
|
+
@ns.doc(
|
|
92
|
+
get={"id": "list_dataservice_followers"},
|
|
93
|
+
post={"id": "follow_dataservice"},
|
|
94
|
+
delete={"id": "unfollow_dataservice"},
|
|
95
|
+
)
|
|
91
96
|
class DataserviceFollowersAPI(FollowAPI):
|
|
92
97
|
model = Dataservice
|
|
@@ -4,30 +4,32 @@ from udata.core.dataservices.models import Dataservice, HarvestMetadata
|
|
|
4
4
|
from udata.core.organization.factories import OrganizationFactory
|
|
5
5
|
from udata.factories import ModelFactory
|
|
6
6
|
|
|
7
|
+
|
|
7
8
|
class HarvestMetadataFactory(ModelFactory):
|
|
8
9
|
class Meta:
|
|
9
10
|
model = HarvestMetadata
|
|
10
11
|
|
|
11
|
-
backend =
|
|
12
|
-
domain =
|
|
12
|
+
backend = "csw-dcat"
|
|
13
|
+
domain = "data.gouv.fr"
|
|
14
|
+
|
|
15
|
+
source_id = factory.Faker("unique_string")
|
|
16
|
+
source_url = factory.Faker("url")
|
|
13
17
|
|
|
14
|
-
|
|
15
|
-
|
|
18
|
+
remote_id = factory.Faker("unique_string")
|
|
19
|
+
remote_url = factory.Faker("url")
|
|
16
20
|
|
|
17
|
-
|
|
18
|
-
remote_url = factory.Faker('url')
|
|
21
|
+
uri = factory.Faker("url")
|
|
19
22
|
|
|
20
|
-
uri = factory.Faker('url')
|
|
21
23
|
|
|
22
24
|
class DataserviceFactory(ModelFactory):
|
|
23
25
|
class Meta:
|
|
24
26
|
model = Dataservice
|
|
25
27
|
|
|
26
|
-
title = factory.Faker(
|
|
27
|
-
description = factory.Faker(
|
|
28
|
-
base_api_url = factory.Faker(
|
|
28
|
+
title = factory.Faker("sentence")
|
|
29
|
+
description = factory.Faker("text")
|
|
30
|
+
base_api_url = factory.Faker("url")
|
|
29
31
|
|
|
30
32
|
class Params:
|
|
31
33
|
org = factory.Trait(
|
|
32
34
|
organization=factory.SubFactory(OrganizationFactory),
|
|
33
|
-
)
|
|
35
|
+
)
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
from datetime import datetime
|
|
2
|
+
|
|
3
|
+
import udata.core.contact_point.api_fields as contact_api_fields
|
|
4
|
+
import udata.core.dataset.api_fields as datasets_api_fields
|
|
2
5
|
from udata.api_fields import field, function_field, generate_fields
|
|
3
6
|
from udata.core.dataset.models import Dataset
|
|
4
7
|
from udata.core.metrics.models import WithMetrics
|
|
5
8
|
from udata.core.owned import Owned, OwnedQuerySet
|
|
6
|
-
import udata.core.contact_point.api_fields as contact_api_fields
|
|
7
|
-
import udata.core.dataset.api_fields as datasets_api_fields
|
|
8
9
|
from udata.i18n import lazy_gettext as _
|
|
9
|
-
|
|
10
|
-
from udata.models import db, Discussion, Follow
|
|
10
|
+
from udata.models import Discussion, Follow, db
|
|
11
11
|
from udata.uris import endpoint_for
|
|
12
12
|
|
|
13
13
|
# "frequency"
|
|
@@ -19,7 +19,7 @@ from udata.uris import endpoint_for
|
|
|
19
19
|
# "spatial"
|
|
20
20
|
# "temporal_coverage"
|
|
21
21
|
|
|
22
|
-
DATASERVICE_FORMATS = [
|
|
22
|
+
DATASERVICE_FORMATS = ["REST", "WMS", "WSL"]
|
|
23
23
|
|
|
24
24
|
|
|
25
25
|
class DataserviceQuerySet(OwnedQuerySet):
|
|
@@ -27,9 +27,8 @@ class DataserviceQuerySet(OwnedQuerySet):
|
|
|
27
27
|
return self(archived_at=None, deleted_at=None, private=False)
|
|
28
28
|
|
|
29
29
|
def hidden(self):
|
|
30
|
-
return self(db.Q(private=True) |
|
|
31
|
-
|
|
32
|
-
db.Q(archived_at__ne=None))
|
|
30
|
+
return self(db.Q(private=True) | db.Q(deleted_at__ne=None) | db.Q(archived_at__ne=None))
|
|
31
|
+
|
|
33
32
|
|
|
34
33
|
@generate_fields()
|
|
35
34
|
class HarvestMetadata(db.EmbeddedDocument):
|
|
@@ -43,7 +42,7 @@ class HarvestMetadata(db.EmbeddedDocument):
|
|
|
43
42
|
remote_url = field(db.URLField())
|
|
44
43
|
|
|
45
44
|
# If the node ID is a `URIRef` it means it links to something external, if it's not an `URIRef` it's often a
|
|
46
|
-
# auto-generated ID just to link multiple RDF node togethers. When exporting as RDF to other catalogs, we
|
|
45
|
+
# auto-generated ID just to link multiple RDF node togethers. When exporting as RDF to other catalogs, we
|
|
47
46
|
# want to re-use this node ID (only if it's not auto-generated) to improve compatibility.
|
|
48
47
|
uri = field(
|
|
49
48
|
db.URLField(),
|
|
@@ -51,23 +50,21 @@ class HarvestMetadata(db.EmbeddedDocument):
|
|
|
51
50
|
)
|
|
52
51
|
|
|
53
52
|
created_at = field(
|
|
54
|
-
db.DateTimeField(),
|
|
55
|
-
description="Date of the creation as provided by the harvested catalog"
|
|
56
|
-
)
|
|
57
|
-
last_update = field(
|
|
58
|
-
db.DateTimeField(),
|
|
59
|
-
description="Date of the last harvesting"
|
|
53
|
+
db.DateTimeField(), description="Date of the creation as provided by the harvested catalog"
|
|
60
54
|
)
|
|
55
|
+
last_update = field(db.DateTimeField(), description="Date of the last harvesting")
|
|
61
56
|
archived_at = field(db.DateTimeField())
|
|
62
57
|
|
|
58
|
+
|
|
63
59
|
@generate_fields()
|
|
64
60
|
class Dataservice(WithMetrics, Owned, db.Document):
|
|
65
61
|
meta = {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
]
|
|
69
|
-
|
|
70
|
-
|
|
62
|
+
"indexes": [
|
|
63
|
+
"$title",
|
|
64
|
+
]
|
|
65
|
+
+ Owned.meta["indexes"],
|
|
66
|
+
"queryset_class": DataserviceQuerySet,
|
|
67
|
+
"auto_create_index_on_save": True,
|
|
71
68
|
}
|
|
72
69
|
|
|
73
70
|
title = field(
|
|
@@ -81,30 +78,26 @@ class Dataservice(WithMetrics, Owned, db.Document):
|
|
|
81
78
|
# /!\ do not set directly the slug when creating or updating a dataset
|
|
82
79
|
# this will break the search indexation
|
|
83
80
|
slug = field(
|
|
84
|
-
db.SlugField(
|
|
81
|
+
db.SlugField(
|
|
82
|
+
max_length=255, required=True, populate_from="title", update=True, follow=True
|
|
83
|
+
),
|
|
85
84
|
readonly=True,
|
|
86
85
|
)
|
|
87
|
-
description = field(
|
|
88
|
-
db.StringField(default=''),
|
|
89
|
-
description="In markdown"
|
|
90
|
-
)
|
|
86
|
+
description = field(db.StringField(default=""), description="In markdown")
|
|
91
87
|
base_api_url = field(
|
|
92
88
|
db.URLField(required=True),
|
|
93
89
|
sortable=True,
|
|
94
90
|
)
|
|
95
91
|
endpoint_description_url = field(db.URLField())
|
|
96
92
|
authorization_request_url = field(db.URLField())
|
|
97
|
-
availability= field(
|
|
98
|
-
db.FloatField(min=0, max=100),
|
|
99
|
-
example='99.99'
|
|
100
|
-
)
|
|
93
|
+
availability = field(db.FloatField(min=0, max=100), example="99.99")
|
|
101
94
|
rate_limiting = field(db.StringField())
|
|
102
95
|
is_restricted = field(db.BooleanField())
|
|
103
96
|
has_token = field(db.BooleanField())
|
|
104
97
|
format = field(db.StringField(choices=DATASERVICE_FORMATS))
|
|
105
98
|
|
|
106
99
|
license = field(
|
|
107
|
-
db.ReferenceField(
|
|
100
|
+
db.ReferenceField("License"),
|
|
108
101
|
allow_null=True,
|
|
109
102
|
)
|
|
110
103
|
|
|
@@ -114,23 +107,25 @@ class Dataservice(WithMetrics, Owned, db.Document):
|
|
|
114
107
|
|
|
115
108
|
private = field(
|
|
116
109
|
db.BooleanField(default=False),
|
|
117
|
-
description=
|
|
110
|
+
description="Is the dataservice private to the owner or the organization",
|
|
118
111
|
)
|
|
119
|
-
|
|
112
|
+
|
|
120
113
|
extras = field(db.ExtrasField())
|
|
121
114
|
|
|
122
115
|
contact_point = field(
|
|
123
|
-
db.ReferenceField(
|
|
116
|
+
db.ReferenceField("ContactPoint", reverse_delete_rule=db.NULLIFY),
|
|
124
117
|
nested_fields=contact_api_fields.contact_point_fields,
|
|
125
118
|
allow_null=True,
|
|
126
119
|
)
|
|
127
120
|
|
|
128
121
|
created_at = field(
|
|
129
|
-
db.DateTimeField(verbose_name=_(
|
|
122
|
+
db.DateTimeField(verbose_name=_("Creation date"), default=datetime.utcnow, required=True),
|
|
130
123
|
readonly=True,
|
|
131
124
|
)
|
|
132
125
|
metadata_modified_at = field(
|
|
133
|
-
db.DateTimeField(
|
|
126
|
+
db.DateTimeField(
|
|
127
|
+
verbose_name=_("Last modification date"), default=datetime.utcnow, required=True
|
|
128
|
+
),
|
|
134
129
|
readonly=True,
|
|
135
130
|
)
|
|
136
131
|
deleted_at = field(db.DateTimeField(), readonly=True)
|
|
@@ -144,7 +139,7 @@ class Dataservice(WithMetrics, Owned, db.Document):
|
|
|
144
139
|
)
|
|
145
140
|
),
|
|
146
141
|
filterable={
|
|
147
|
-
|
|
142
|
+
"key": "dataset",
|
|
148
143
|
},
|
|
149
144
|
)
|
|
150
145
|
|
|
@@ -155,11 +150,11 @@ class Dataservice(WithMetrics, Owned, db.Document):
|
|
|
155
150
|
|
|
156
151
|
@function_field(description="Link to the API endpoint for this dataservice")
|
|
157
152
|
def self_api_url(self):
|
|
158
|
-
return endpoint_for(
|
|
153
|
+
return endpoint_for("api.dataservice", dataservice=self, _external=True)
|
|
159
154
|
|
|
160
155
|
@function_field(description="Link to the udata web page for this dataservice")
|
|
161
156
|
def self_web_url(self):
|
|
162
|
-
return endpoint_for(
|
|
157
|
+
return endpoint_for("dataservices.show", dataservice=self, _external=True)
|
|
163
158
|
|
|
164
159
|
# TODO
|
|
165
160
|
# frequency = db.StringField(choices=list(UPDATE_FREQUENCIES.keys()))
|
|
@@ -172,9 +167,9 @@ class Dataservice(WithMetrics, Owned, db.Document):
|
|
|
172
167
|
return self.private or self.deleted_at or self.archived_at
|
|
173
168
|
|
|
174
169
|
def count_discussions(self):
|
|
175
|
-
self.metrics[
|
|
170
|
+
self.metrics["discussions"] = Discussion.objects(subject=self, closed=None).count()
|
|
176
171
|
self.save()
|
|
177
172
|
|
|
178
173
|
def count_followers(self):
|
|
179
|
-
self.metrics[
|
|
174
|
+
self.metrics["followers"] = Follow.objects(until=None).followers(self).count()
|
|
180
175
|
self.save()
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
from udata.core.dataset.permissions import
|
|
2
|
-
|
|
3
|
-
)
|
|
1
|
+
from udata.core.dataset.permissions import OwnablePermission
|
|
2
|
+
|
|
4
3
|
|
|
5
4
|
class DataserviceEditPermission(OwnablePermission):
|
|
6
|
-
|
|
5
|
+
"""Permissions to edit a Dataservice"""
|
|
6
|
+
|
|
7
7
|
pass
|
udata/core/dataservices/rdf.py
CHANGED
|
@@ -1,16 +1,28 @@
|
|
|
1
|
-
|
|
2
1
|
from rdflib import RDF, BNode, Graph, Literal, URIRef
|
|
3
2
|
|
|
4
|
-
from udata.core.dataservices.models import Dataservice
|
|
3
|
+
from udata.core.dataservices.models import Dataservice
|
|
4
|
+
from udata.core.dataservices.models import HarvestMetadata as HarvestDataserviceMetadata
|
|
5
5
|
from udata.core.dataset.models import Dataset, License
|
|
6
6
|
from udata.core.dataset.rdf import dataset_to_graph_id, sanitize_html
|
|
7
|
-
from udata.rdf import
|
|
7
|
+
from udata.rdf import (
|
|
8
|
+
DCAT,
|
|
9
|
+
DCT,
|
|
10
|
+
contact_point_from_rdf,
|
|
11
|
+
namespace_manager,
|
|
12
|
+
rdf_value,
|
|
13
|
+
remote_url_from_rdf,
|
|
14
|
+
themes_from_rdf,
|
|
15
|
+
url_from_rdf,
|
|
16
|
+
)
|
|
8
17
|
from udata.uris import endpoint_for
|
|
9
18
|
|
|
10
|
-
|
|
11
|
-
|
|
19
|
+
|
|
20
|
+
def dataservice_from_rdf(
|
|
21
|
+
graph: Graph, dataservice: Dataservice, node, all_datasets: list[Dataset]
|
|
22
|
+
) -> Dataservice:
|
|
23
|
+
"""
|
|
12
24
|
Create or update a dataset from a RDF/DCAT graph
|
|
13
|
-
|
|
25
|
+
"""
|
|
14
26
|
if node is None: # Assume first match is the only match
|
|
15
27
|
node = graph.value(predicate=RDF.type, object=DCAT.DataService)
|
|
16
28
|
|
|
@@ -27,11 +39,16 @@ def dataservice_from_rdf(graph: Graph, dataservice: Dataservice, node, all_datas
|
|
|
27
39
|
datasets = []
|
|
28
40
|
for dataset_node in d.objects(DCAT.servesDataset):
|
|
29
41
|
id = dataset_node.value(DCT.identifier)
|
|
30
|
-
dataset = next(
|
|
42
|
+
dataset = next(
|
|
43
|
+
(d for d in all_datasets if d is not None and d.harvest.remote_id == id), None
|
|
44
|
+
)
|
|
31
45
|
|
|
32
46
|
if dataset is None:
|
|
33
47
|
# We try with `endswith` because Europe XSLT have problems with IDs. Sometimes they are prefixed with the domain of the catalog, sometimes not.
|
|
34
|
-
dataset = next(
|
|
48
|
+
dataset = next(
|
|
49
|
+
(d for d in all_datasets if d is not None and d.harvest.remote_id.endswith(id)),
|
|
50
|
+
None,
|
|
51
|
+
)
|
|
35
52
|
|
|
36
53
|
if dataset is not None:
|
|
37
54
|
datasets.append(dataset.id)
|
|
@@ -57,16 +74,22 @@ def dataservice_from_rdf(graph: Graph, dataservice: Dataservice, node, all_datas
|
|
|
57
74
|
|
|
58
75
|
|
|
59
76
|
def dataservice_to_rdf(dataservice: Dataservice, graph=None):
|
|
60
|
-
|
|
77
|
+
"""
|
|
61
78
|
Map a dataservice domain model to a DCAT/RDF graph
|
|
62
|
-
|
|
79
|
+
"""
|
|
63
80
|
# Use the unlocalized permalink to the dataset as URI when available
|
|
64
81
|
# unless there is already an upstream URI
|
|
65
82
|
if dataservice.harvest and dataservice.harvest.uri:
|
|
66
83
|
id = URIRef(dataservice.harvest.uri)
|
|
67
84
|
elif dataservice.id:
|
|
68
|
-
id = URIRef(
|
|
69
|
-
|
|
85
|
+
id = URIRef(
|
|
86
|
+
endpoint_for(
|
|
87
|
+
"dataservices.show_redirect",
|
|
88
|
+
"api.dataservice",
|
|
89
|
+
dataservice=dataservice.id,
|
|
90
|
+
_external=True,
|
|
91
|
+
)
|
|
92
|
+
)
|
|
70
93
|
else:
|
|
71
94
|
# Should not happen in production. Some test only
|
|
72
95
|
# `build()` a dataset without saving it to the DB.
|
|
@@ -85,10 +108,10 @@ def dataservice_to_rdf(dataservice: Dataservice, graph=None):
|
|
|
85
108
|
d.set(DCT.title, Literal(dataservice.title))
|
|
86
109
|
d.set(DCT.description, Literal(dataservice.description))
|
|
87
110
|
d.set(DCT.issued, Literal(dataservice.created_at))
|
|
88
|
-
|
|
111
|
+
|
|
89
112
|
if dataservice.base_api_url:
|
|
90
113
|
d.set(DCAT.endpointURL, Literal(dataservice.base_api_url))
|
|
91
|
-
|
|
114
|
+
|
|
92
115
|
if dataservice.endpoint_description_url:
|
|
93
116
|
d.set(DCAT.endpointDescription, Literal(dataservice.endpoint_description_url))
|
|
94
117
|
|
|
@@ -96,11 +119,11 @@ def dataservice_to_rdf(dataservice: Dataservice, graph=None):
|
|
|
96
119
|
d.add(DCAT.keyword, Literal(tag))
|
|
97
120
|
|
|
98
121
|
# `dataset_to_graph_id(dataset)` URIRef may not exist in the current page
|
|
99
|
-
# but should exists in the catalog somewhere. Maybe we should create a Node
|
|
100
|
-
# with some basic information about this dataset (but this will return a page
|
|
122
|
+
# but should exists in the catalog somewhere. Maybe we should create a Node
|
|
123
|
+
# with some basic information about this dataset (but this will return a page
|
|
101
124
|
# with more datasets than the page size… and could be problematic when processing the
|
|
102
125
|
# correct Node with all the information in a future page)
|
|
103
126
|
for dataset in dataservice.datasets:
|
|
104
127
|
d.add(DCAT.servesDataset, dataset_to_graph_id(dataset))
|
|
105
128
|
|
|
106
|
-
return d
|
|
129
|
+
return d
|
udata/core/dataservices/tasks.py
CHANGED
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
from celery.utils.log import get_task_logger
|
|
2
2
|
|
|
3
3
|
from udata.core.dataservices.models import Dataservice
|
|
4
|
+
|
|
4
5
|
# from udata.harvest.models import HarvestJob
|
|
5
|
-
from udata.models import
|
|
6
|
+
from udata.models import Activity, Discussion, Follow, Transfer
|
|
6
7
|
from udata.tasks import job
|
|
7
8
|
|
|
8
9
|
log = get_task_logger(__name__)
|
|
9
10
|
|
|
10
11
|
|
|
11
|
-
@job(
|
|
12
|
+
@job("purge-dataservices")
|
|
12
13
|
def purge_dataservices(self):
|
|
13
14
|
for dataservice in Dataservice.objects(deleted_at__ne=None):
|
|
14
|
-
log.info(f
|
|
15
|
+
log.info(f"Purging dataservice {dataservice}")
|
|
15
16
|
# Remove followers
|
|
16
17
|
Follow.objects(following=dataservice).delete()
|
|
17
18
|
# Remove discussions
|
udata/core/dataset/actions.py
CHANGED
|
@@ -12,24 +12,24 @@ log = logging.getLogger(__name__)
|
|
|
12
12
|
def archive(dataset, comment=False):
|
|
13
13
|
"""Archive a dataset"""
|
|
14
14
|
if dataset.archived:
|
|
15
|
-
log.warning(
|
|
15
|
+
log.warning("Dataset %s already archived, bumping date", dataset)
|
|
16
16
|
dataset.archived = datetime.utcnow()
|
|
17
17
|
dataset.save()
|
|
18
18
|
|
|
19
19
|
if comment:
|
|
20
|
-
log.info(
|
|
21
|
-
lang = current_app.config[
|
|
22
|
-
title = current_app.config[
|
|
23
|
-
user_id = current_app.config[
|
|
20
|
+
log.info("Posting comment for dataset %s...", dataset)
|
|
21
|
+
lang = current_app.config["DEFAULT_LANGUAGE"]
|
|
22
|
+
title = current_app.config["ARCHIVE_COMMENT_TITLE"]
|
|
23
|
+
user_id = current_app.config["ARCHIVE_COMMENT_USER_ID"]
|
|
24
24
|
if user_id:
|
|
25
25
|
with i18n.language(lang):
|
|
26
|
-
msg = render_template(
|
|
26
|
+
msg = render_template("comments/dataset_archived.txt")
|
|
27
27
|
message = Message(content=msg, posted_by=user_id)
|
|
28
28
|
discussion = Discussion(
|
|
29
|
-
user=user_id, discussion=[message], subject=dataset,
|
|
30
|
-
|
|
29
|
+
user=user_id, discussion=[message], subject=dataset, title=str(title)
|
|
30
|
+
)
|
|
31
31
|
discussion.save()
|
|
32
32
|
else:
|
|
33
|
-
log.warning(
|
|
33
|
+
log.warning("ARCHIVE_COMMENT_USER_ID not set, skipping comment")
|
|
34
34
|
|
|
35
|
-
log.info(
|
|
35
|
+
log.info("Archived dataset %s", dataset)
|
udata/core/dataset/activities.py
CHANGED
|
@@ -1,55 +1,53 @@
|
|
|
1
1
|
from udata.auth import current_user
|
|
2
2
|
from udata.i18n import lazy_gettext as _
|
|
3
|
-
from udata.models import
|
|
4
|
-
|
|
3
|
+
from udata.models import Activity, Dataset, db
|
|
5
4
|
|
|
6
5
|
__all__ = (
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
"UserCreatedDataset",
|
|
7
|
+
"UserUpdatedDataset",
|
|
8
|
+
"UserDeletedDataset",
|
|
9
|
+
"DatasetRelatedActivity",
|
|
9
10
|
)
|
|
10
11
|
|
|
11
12
|
|
|
12
13
|
class DatasetRelatedActivity(object):
|
|
13
|
-
template =
|
|
14
|
-
related_to = db.ReferenceField(
|
|
14
|
+
template = "activity/dataset.html"
|
|
15
|
+
related_to = db.ReferenceField("Dataset")
|
|
15
16
|
|
|
16
17
|
|
|
17
18
|
class UserCreatedDataset(DatasetRelatedActivity, Activity):
|
|
18
|
-
key =
|
|
19
|
-
icon =
|
|
20
|
-
badge_type =
|
|
21
|
-
label = _(
|
|
19
|
+
key = "dataset:created"
|
|
20
|
+
icon = "fa fa-plus"
|
|
21
|
+
badge_type = "success"
|
|
22
|
+
label = _("created a dataset")
|
|
22
23
|
|
|
23
24
|
|
|
24
25
|
class UserUpdatedDataset(DatasetRelatedActivity, Activity):
|
|
25
|
-
key =
|
|
26
|
-
icon =
|
|
27
|
-
label = _(
|
|
26
|
+
key = "dataset:updated"
|
|
27
|
+
icon = "fa fa-pencil"
|
|
28
|
+
label = _("updated a dataset")
|
|
28
29
|
|
|
29
30
|
|
|
30
31
|
class UserDeletedDataset(DatasetRelatedActivity, Activity):
|
|
31
|
-
key =
|
|
32
|
-
icon =
|
|
33
|
-
badge_type =
|
|
34
|
-
label = _(
|
|
32
|
+
key = "dataset:deleted"
|
|
33
|
+
icon = "fa fa-remove"
|
|
34
|
+
badge_type = "error"
|
|
35
|
+
label = _("deleted a dataset")
|
|
35
36
|
|
|
36
37
|
|
|
37
38
|
@Dataset.on_create.connect
|
|
38
39
|
def on_user_created_dataset(dataset):
|
|
39
|
-
if
|
|
40
|
-
current_user.is_authenticated):
|
|
40
|
+
if not dataset.private and current_user and current_user.is_authenticated:
|
|
41
41
|
UserCreatedDataset.emit(dataset, dataset.organization)
|
|
42
42
|
|
|
43
43
|
|
|
44
44
|
@Dataset.on_update.connect
|
|
45
45
|
def on_user_updated_dataset(dataset):
|
|
46
|
-
if
|
|
47
|
-
current_user.is_authenticated):
|
|
46
|
+
if not dataset.private and current_user and current_user.is_authenticated:
|
|
48
47
|
UserUpdatedDataset.emit(dataset, dataset.organization)
|
|
49
48
|
|
|
50
49
|
|
|
51
50
|
@Dataset.on_delete.connect
|
|
52
51
|
def on_user_deleted_dataset(dataset):
|
|
53
|
-
if
|
|
54
|
-
current_user.is_authenticated):
|
|
52
|
+
if not dataset.private and current_user and current_user.is_authenticated:
|
|
55
53
|
UserDeletedDataset.emit(dataset, dataset.organization)
|