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/commands/static.py
CHANGED
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
import logging
|
|
2
2
|
import os
|
|
3
3
|
import shutil
|
|
4
|
-
|
|
5
|
-
import click
|
|
6
|
-
|
|
7
4
|
from glob import iglob
|
|
8
5
|
from os import makedirs
|
|
9
|
-
from os.path import exists,
|
|
6
|
+
from os.path import exists, isdir, join
|
|
10
7
|
|
|
8
|
+
import click
|
|
11
9
|
from flask import current_app
|
|
12
10
|
|
|
13
11
|
from udata.commands import cli
|
|
@@ -16,21 +14,21 @@ log = logging.getLogger(__name__)
|
|
|
16
14
|
|
|
17
15
|
|
|
18
16
|
@cli.command()
|
|
19
|
-
@click.argument(
|
|
20
|
-
@click.option(
|
|
17
|
+
@click.argument("path", default="public")
|
|
18
|
+
@click.option("-ni", "--no-input", is_flag=True, help="Disable input prompts")
|
|
21
19
|
def collect(path, no_input):
|
|
22
|
-
|
|
20
|
+
"""Collect static files"""
|
|
23
21
|
if exists(path):
|
|
24
22
|
msg = '"%s" directory already exists and will be erased'
|
|
25
23
|
log.warning(msg, path)
|
|
26
24
|
if not no_input:
|
|
27
|
-
click.confirm(
|
|
25
|
+
click.confirm("Are you sure?", abort=True)
|
|
28
26
|
|
|
29
27
|
log.info('Deleting static directory "%s"', path)
|
|
30
28
|
shutil.rmtree(path)
|
|
31
29
|
|
|
32
30
|
prefix = current_app.static_url_path or current_app.static_folder
|
|
33
|
-
if prefix.startswith(
|
|
31
|
+
if prefix.startswith("/"):
|
|
34
32
|
prefix = prefix[1:]
|
|
35
33
|
destination = join(path, prefix)
|
|
36
34
|
log.info('Copying application assets into "%s"', destination)
|
|
@@ -39,29 +37,29 @@ def collect(path, no_input):
|
|
|
39
37
|
for blueprint in current_app.blueprints.values():
|
|
40
38
|
if blueprint.has_static_folder:
|
|
41
39
|
prefix = current_app.static_prefixes.get(blueprint.name)
|
|
42
|
-
prefix = prefix or blueprint.url_prefix or
|
|
43
|
-
prefix += blueprint.static_url_path or
|
|
44
|
-
if prefix.startswith(
|
|
40
|
+
prefix = prefix or blueprint.url_prefix or ""
|
|
41
|
+
prefix += blueprint.static_url_path or ""
|
|
42
|
+
if prefix.startswith("/"):
|
|
45
43
|
prefix = prefix[1:]
|
|
46
44
|
|
|
47
|
-
log.info(
|
|
45
|
+
log.info("Copying %s assets to %s", blueprint.name, prefix)
|
|
48
46
|
destination = join(path, prefix)
|
|
49
47
|
copy_recursive(blueprint.static_folder, destination)
|
|
50
48
|
|
|
51
|
-
for prefix, source in current_app.config[
|
|
52
|
-
log.info(
|
|
49
|
+
for prefix, source in current_app.config["STATIC_DIRS"]:
|
|
50
|
+
log.info("Copying %s to %s", source, prefix)
|
|
53
51
|
destination = join(path, prefix)
|
|
54
52
|
copy_recursive(source, destination)
|
|
55
53
|
|
|
56
|
-
log.info(
|
|
54
|
+
log.info("Done")
|
|
57
55
|
|
|
58
56
|
|
|
59
57
|
def copy_recursive(source, destination):
|
|
60
58
|
if not exists(destination):
|
|
61
59
|
makedirs(destination)
|
|
62
|
-
for filename in iglob(join(source,
|
|
60
|
+
for filename in iglob(join(source, "*")):
|
|
63
61
|
if isdir(filename):
|
|
64
|
-
suffix = filename.replace(source,
|
|
62
|
+
suffix = filename.replace(source, "")
|
|
65
63
|
if suffix.startswith(os.sep):
|
|
66
64
|
suffix = suffix[1:]
|
|
67
65
|
copy_recursive(filename, join(destination, suffix))
|
udata/commands/test.py
CHANGED
|
@@ -1,33 +1,33 @@
|
|
|
1
1
|
import logging
|
|
2
2
|
|
|
3
|
-
from . import cli,
|
|
3
|
+
from . import cli, error, header, success
|
|
4
4
|
|
|
5
5
|
logger = logging.getLogger(__name__)
|
|
6
6
|
|
|
7
7
|
|
|
8
|
-
@cli.group(
|
|
8
|
+
@cli.group("test")
|
|
9
9
|
def test():
|
|
10
|
-
|
|
10
|
+
"""Some commands for testing purpose"""
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
@test.command()
|
|
14
14
|
def log():
|
|
15
|
-
|
|
16
|
-
header(
|
|
17
|
-
success(
|
|
18
|
-
error(
|
|
19
|
-
error(
|
|
20
|
-
error(
|
|
21
|
-
logger.debug(
|
|
22
|
-
logger.info(
|
|
23
|
-
logger.info(
|
|
24
|
-
logger.info(
|
|
25
|
-
logger.info(
|
|
26
|
-
logger.info(
|
|
27
|
-
logger.warning(
|
|
28
|
-
logger.error(
|
|
29
|
-
logger.critical(
|
|
15
|
+
"""Test logging"""
|
|
16
|
+
header("header é")
|
|
17
|
+
success("success é")
|
|
18
|
+
error("error é")
|
|
19
|
+
error("error with string details é", "ééé")
|
|
20
|
+
error("error with object details é", Exception("ééé"))
|
|
21
|
+
logger.debug("debug é")
|
|
22
|
+
logger.info("info é")
|
|
23
|
+
logger.info("info é with unicode interpolation %s", "ééé")
|
|
24
|
+
logger.info("info é with interpolations %s %d %f", "ééé", 10, 0.1)
|
|
25
|
+
logger.info("success é")
|
|
26
|
+
logger.info("info\nmulti\nlines é")
|
|
27
|
+
logger.warning("warning é")
|
|
28
|
+
logger.error("error é")
|
|
29
|
+
logger.critical("critical é")
|
|
30
30
|
try:
|
|
31
|
-
raise Exception(
|
|
31
|
+
raise Exception("An exception é")
|
|
32
32
|
except Exception:
|
|
33
|
-
logger.exception(
|
|
33
|
+
logger.exception("exception é")
|
udata/commands/tests/fixtures.py
CHANGED
|
@@ -3,37 +3,39 @@ from tempfile import NamedTemporaryFile
|
|
|
3
3
|
|
|
4
4
|
from udata import models
|
|
5
5
|
from udata.commands.fixtures import generate_fixtures
|
|
6
|
-
from udata.tests import
|
|
6
|
+
from udata.tests import DBTestMixin, TestCase
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
class FixturesTest(DBTestMixin, TestCase):
|
|
10
|
-
|
|
11
10
|
def test_generate_fixtures(self):
|
|
12
11
|
with NamedTemporaryFile(delete=True) as fixtures_fd:
|
|
13
|
-
json_fixtures = [
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
12
|
+
json_fixtures = [
|
|
13
|
+
{
|
|
14
|
+
"resources": [
|
|
15
|
+
{
|
|
16
|
+
"description": "test description",
|
|
17
|
+
"filetype": "remote",
|
|
18
|
+
"title": "test",
|
|
19
|
+
"url": "https://dev.local",
|
|
20
|
+
}
|
|
21
|
+
],
|
|
22
|
+
"dataset": {
|
|
23
|
+
"description": "### Le Test",
|
|
24
|
+
"frequency": "punctual",
|
|
25
|
+
"tags": ["action-publique"],
|
|
17
26
|
"title": "test",
|
|
18
|
-
"url": "https://dev.local"
|
|
19
|
-
}],
|
|
20
|
-
"dataset": {
|
|
21
|
-
"description": "### Le Test",
|
|
22
|
-
"frequency": "punctual",
|
|
23
|
-
"tags": ["action-publique"],
|
|
24
|
-
"title": "test"
|
|
25
27
|
},
|
|
26
|
-
|
|
27
|
-
"
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
with open(fixtures_fd,
|
|
28
|
+
"organization": {"description": "test description", "name": "Test"},
|
|
29
|
+
"reuses": [
|
|
30
|
+
{
|
|
31
|
+
"description": "test description",
|
|
32
|
+
"title": "test",
|
|
33
|
+
"url": "https://dev.local",
|
|
34
|
+
}
|
|
35
|
+
],
|
|
36
|
+
}
|
|
37
|
+
]
|
|
38
|
+
with open(fixtures_fd, "w") as f:
|
|
37
39
|
json.dump(json_fixtures, f)
|
|
38
40
|
generate_fixtures(fixtures_fd)
|
|
39
41
|
self.assertEqual(models.Organization.objects.count(), 1)
|
udata/commands/worker.py
CHANGED
|
@@ -5,7 +5,6 @@ from urllib.parse import urlparse
|
|
|
5
5
|
|
|
6
6
|
import click
|
|
7
7
|
import redis
|
|
8
|
-
|
|
9
8
|
from flask import current_app
|
|
10
9
|
|
|
11
10
|
from udata.commands import cli, exit_with_error
|
|
@@ -14,15 +13,15 @@ from udata.tasks import celery, router
|
|
|
14
13
|
log = logging.getLogger(__name__)
|
|
15
14
|
|
|
16
15
|
|
|
17
|
-
@cli.group(
|
|
16
|
+
@cli.group("worker")
|
|
18
17
|
def grp():
|
|
19
|
-
|
|
18
|
+
"""Worker related operations"""
|
|
20
19
|
pass
|
|
21
20
|
|
|
22
21
|
|
|
23
22
|
@grp.command()
|
|
24
23
|
def start():
|
|
25
|
-
|
|
24
|
+
"""Start a worker"""
|
|
26
25
|
worker = celery.Worker()
|
|
27
26
|
worker.start()
|
|
28
27
|
return worker.exitcode
|
|
@@ -31,27 +30,27 @@ def start():
|
|
|
31
30
|
def status_print_task(count, biggest_task_name, munin=False):
|
|
32
31
|
if munin:
|
|
33
32
|
# Munin expect all values, including zeros
|
|
34
|
-
print(
|
|
33
|
+
print("%s.value %s" % (format_field_for_munin(count[0]), count[1]))
|
|
35
34
|
elif count[1] > 0:
|
|
36
35
|
# We only display tasks with items in queue for readability
|
|
37
|
-
print(
|
|
36
|
+
print("* %s : %s" % (count[0].ljust(biggest_task_name), count[1]))
|
|
38
37
|
|
|
39
38
|
|
|
40
39
|
def status_print_config(queue):
|
|
41
40
|
if not queue:
|
|
42
|
-
exit_with_error(
|
|
41
|
+
exit_with_error("--munin-config called without a --queue parameter")
|
|
43
42
|
tasks = [n for n, q in get_tasks().items() if q == queue]
|
|
44
|
-
print(
|
|
45
|
-
print(
|
|
46
|
-
print(
|
|
43
|
+
print("graph_title Waiting tasks for queue %s" % queue)
|
|
44
|
+
print("graph_vlabel Nb of tasks")
|
|
45
|
+
print("graph_category celery")
|
|
47
46
|
for task in tasks:
|
|
48
|
-
print(
|
|
47
|
+
print("%s.label %s" % (format_field_for_munin(task), short_name(task)))
|
|
49
48
|
|
|
50
49
|
|
|
51
50
|
def status_print_queue(queue, munin=False):
|
|
52
51
|
r = get_redis_connection()
|
|
53
52
|
if not munin:
|
|
54
|
-
print(
|
|
53
|
+
print("-" * 40)
|
|
55
54
|
queue_length = r.llen(queue)
|
|
56
55
|
if not munin:
|
|
57
56
|
print('Queue "%s": %s task(s)' % (queue, queue_length))
|
|
@@ -59,7 +58,7 @@ def status_print_queue(queue, munin=False):
|
|
|
59
58
|
biggest_task_name = 0
|
|
60
59
|
for task in r.lrange(queue, 0, -1):
|
|
61
60
|
task = json.loads(task)
|
|
62
|
-
task_name = task[
|
|
61
|
+
task_name = task["headers"]["task"]
|
|
63
62
|
if len(task_name) > biggest_task_name:
|
|
64
63
|
biggest_task_name = len(task_name)
|
|
65
64
|
counter[task_name] += 1
|
|
@@ -68,63 +67,62 @@ def status_print_queue(queue, munin=False):
|
|
|
68
67
|
|
|
69
68
|
|
|
70
69
|
def format_field_for_munin(field):
|
|
71
|
-
return field.replace(
|
|
70
|
+
return field.replace(".", "__").replace("-", "_")
|
|
72
71
|
|
|
73
72
|
|
|
74
73
|
def get_queues(queue):
|
|
75
|
-
queues = [q.name for q in current_app.config[
|
|
74
|
+
queues = [q.name for q in current_app.config["CELERY_TASK_QUEUES"]]
|
|
76
75
|
if queue:
|
|
77
76
|
queues = [q for q in queues if q == queue]
|
|
78
77
|
if not len(queues):
|
|
79
|
-
exit_with_error(
|
|
78
|
+
exit_with_error("Error: no queue found")
|
|
80
79
|
return queues
|
|
81
80
|
|
|
82
81
|
|
|
83
82
|
def get_redis_connection():
|
|
84
|
-
parsed_url = urlparse(current_app.config[
|
|
83
|
+
parsed_url = urlparse(current_app.config["CELERY_BROKER_URL"])
|
|
85
84
|
db = parsed_url.path[1:] if parsed_url.path else 0
|
|
86
|
-
return redis.StrictRedis(host=parsed_url.hostname, port=parsed_url.port,
|
|
87
|
-
db=db)
|
|
85
|
+
return redis.StrictRedis(host=parsed_url.hostname, port=parsed_url.port, db=db)
|
|
88
86
|
|
|
89
87
|
|
|
90
88
|
def get_task_queue(name, cls):
|
|
91
|
-
return (router(name, [], {}, None, task=cls) or {}).get(
|
|
89
|
+
return (router(name, [], {}, None, task=cls) or {}).get("queue", "default")
|
|
92
90
|
|
|
93
91
|
|
|
94
92
|
def short_name(name):
|
|
95
|
-
if
|
|
93
|
+
if "." not in name:
|
|
96
94
|
return name
|
|
97
|
-
return name.rsplit(
|
|
95
|
+
return name.rsplit(".", 1)[1]
|
|
98
96
|
|
|
99
97
|
|
|
100
98
|
def get_tasks():
|
|
101
|
-
|
|
99
|
+
"""Get a list of known tasks with their routing queue"""
|
|
102
100
|
return {
|
|
103
101
|
name: get_task_queue(name, cls)
|
|
104
102
|
for name, cls in celery.tasks.items()
|
|
105
103
|
# Exclude celery internal tasks
|
|
106
|
-
if not name.startswith(
|
|
104
|
+
if not name.startswith("celery.")
|
|
107
105
|
# Exclude udata test tasks
|
|
108
|
-
and not name.startswith(
|
|
106
|
+
and not name.startswith("test-")
|
|
109
107
|
}
|
|
110
108
|
|
|
111
109
|
|
|
112
110
|
@grp.command()
|
|
113
111
|
def tasks():
|
|
114
|
-
|
|
112
|
+
"""Display registered tasks with their queue"""
|
|
115
113
|
tasks = get_tasks()
|
|
116
114
|
longest = max(tasks.keys(), key=len)
|
|
117
115
|
size = len(longest)
|
|
118
116
|
for name, queue in sorted(tasks.items()):
|
|
119
|
-
print(
|
|
117
|
+
print("* {0}: {1}".format(name.ljust(size), queue))
|
|
120
118
|
|
|
121
119
|
|
|
122
120
|
@grp.command()
|
|
123
|
-
@click.option(
|
|
124
|
-
@click.option(
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
121
|
+
@click.option("-q", "--queue", help="Queue to be analyzed", default=None)
|
|
122
|
+
@click.option("-m", "--munin", is_flag=True, help="Output in a munin plugin compatible format")
|
|
123
|
+
@click.option(
|
|
124
|
+
"-c", "--munin-config", is_flag=True, help="Output in a munin plugin config compatible format"
|
|
125
|
+
)
|
|
128
126
|
def status(queue, munin, munin_config):
|
|
129
127
|
"""List queued tasks aggregated by name"""
|
|
130
128
|
if munin_config:
|
|
@@ -133,4 +131,4 @@ def status(queue, munin, munin_config):
|
|
|
133
131
|
for queue in queues:
|
|
134
132
|
status_print_queue(queue, munin=munin)
|
|
135
133
|
if not munin:
|
|
136
|
-
print(
|
|
134
|
+
print("-" * 40)
|
udata/core/__init__.py
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
from importlib import import_module
|
|
2
2
|
|
|
3
3
|
MODULES = (
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
4
|
+
"metrics",
|
|
5
|
+
"storages",
|
|
6
|
+
"user",
|
|
7
|
+
"dataset",
|
|
8
|
+
"reuse",
|
|
9
|
+
"organization",
|
|
10
|
+
"activity",
|
|
11
|
+
"followers",
|
|
12
|
+
"topic",
|
|
13
|
+
"post",
|
|
14
14
|
)
|
|
15
15
|
|
|
16
16
|
|
|
17
17
|
def init_app(app):
|
|
18
18
|
for module in MODULES:
|
|
19
|
-
module = import_module(
|
|
20
|
-
if hasattr(module,
|
|
19
|
+
module = import_module("udata.core.{0}".format(module))
|
|
20
|
+
if hasattr(module, "init_app"):
|
|
21
21
|
module.init_app(app)
|
udata/core/activity/__init__.py
CHANGED
udata/core/activity/api.py
CHANGED
|
@@ -2,75 +2,85 @@ import logging
|
|
|
2
2
|
|
|
3
3
|
from mongoengine.errors import DoesNotExist
|
|
4
4
|
|
|
5
|
-
from udata.api import
|
|
6
|
-
from udata.models import db, Activity
|
|
7
|
-
|
|
8
|
-
from udata.core.user.api_fields import user_ref_fields
|
|
5
|
+
from udata.api import API, api, fields
|
|
9
6
|
from udata.core.organization.api_fields import org_ref_fields
|
|
7
|
+
from udata.core.user.api_fields import user_ref_fields
|
|
8
|
+
from udata.models import Activity, db
|
|
10
9
|
|
|
11
10
|
log = logging.getLogger(__name__)
|
|
12
11
|
|
|
13
|
-
activity_fields = api.model(
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
12
|
+
activity_fields = api.model(
|
|
13
|
+
"Activity",
|
|
14
|
+
{
|
|
15
|
+
"actor": fields.Nested(
|
|
16
|
+
user_ref_fields, description="The user who performed the action", readonly=True
|
|
17
|
+
),
|
|
18
|
+
"organization": fields.Nested(
|
|
19
|
+
org_ref_fields,
|
|
20
|
+
allow_null=True,
|
|
21
|
+
readonly=True,
|
|
22
|
+
description="The organization who performed the action",
|
|
23
|
+
),
|
|
24
|
+
"related_to": fields.String(
|
|
25
|
+
attribute="related_to", description="The activity target name", required=True
|
|
26
|
+
),
|
|
27
|
+
"related_to_id": fields.String(
|
|
28
|
+
attribute="related_to.id",
|
|
29
|
+
description="The activity target object identifier",
|
|
30
|
+
required=True,
|
|
31
|
+
),
|
|
32
|
+
"related_to_kind": fields.String(
|
|
33
|
+
attribute="related_to.__class__.__name__",
|
|
34
|
+
description="The activity target object class name",
|
|
35
|
+
required=True,
|
|
36
|
+
),
|
|
37
|
+
"related_to_url": fields.String(
|
|
38
|
+
attribute="related_to.display_url",
|
|
39
|
+
description="The activity target model",
|
|
40
|
+
required=True,
|
|
41
|
+
),
|
|
42
|
+
"created_at": fields.ISODateTime(
|
|
43
|
+
description="When the action has been performed", readonly=True
|
|
44
|
+
),
|
|
45
|
+
"label": fields.String(description="The label of the activity", required=True),
|
|
46
|
+
"key": fields.String(description="The key of the activity", required=True),
|
|
47
|
+
"icon": fields.String(description="The icon of the activity", required=True),
|
|
48
|
+
"extras": fields.Raw(description="Extras attributes as key-value pairs"),
|
|
49
|
+
},
|
|
50
|
+
)
|
|
42
51
|
|
|
43
|
-
activity_page_fields = api.model(
|
|
52
|
+
activity_page_fields = api.model("ActivityPage", fields.pager(activity_fields))
|
|
44
53
|
|
|
45
54
|
activity_parser = api.page_parser()
|
|
46
55
|
activity_parser.add_argument(
|
|
47
|
-
|
|
48
|
-
|
|
56
|
+
"user", type=str, help="Filter activities for that particular user", location="args"
|
|
57
|
+
)
|
|
49
58
|
activity_parser.add_argument(
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
59
|
+
"organization",
|
|
60
|
+
type=str,
|
|
61
|
+
help="Filter activities for that particular organization",
|
|
62
|
+
location="args",
|
|
63
|
+
)
|
|
53
64
|
|
|
54
65
|
|
|
55
|
-
@api.route(
|
|
66
|
+
@api.route("/activity", endpoint="activity")
|
|
56
67
|
class SiteActivityAPI(API):
|
|
57
|
-
@api.doc(
|
|
68
|
+
@api.doc("activity")
|
|
58
69
|
@api.expect(activity_parser)
|
|
59
70
|
@api.marshal_list_with(activity_page_fields)
|
|
60
71
|
def get(self):
|
|
61
|
-
|
|
72
|
+
"""Fetch site activity, optionally filtered by user of org."""
|
|
62
73
|
args = activity_parser.parse_args()
|
|
63
74
|
qs = Activity.objects
|
|
64
75
|
|
|
65
|
-
if args[
|
|
66
|
-
qs = qs(db.Q(organization=args[
|
|
67
|
-
db.Q(related_to=args['organization']))
|
|
76
|
+
if args["organization"]:
|
|
77
|
+
qs = qs(db.Q(organization=args["organization"]) | db.Q(related_to=args["organization"]))
|
|
68
78
|
|
|
69
|
-
if args[
|
|
70
|
-
qs = qs(actor=args[
|
|
79
|
+
if args["user"]:
|
|
80
|
+
qs = qs(actor=args["user"])
|
|
71
81
|
|
|
72
|
-
qs = qs.order_by(
|
|
73
|
-
qs = qs.paginate(args[
|
|
82
|
+
qs = qs.order_by("-created_at")
|
|
83
|
+
qs = qs.paginate(args["page"], args["page_size"])
|
|
74
84
|
|
|
75
85
|
# Filter out DBRefs
|
|
76
86
|
# Always return a result even not complete
|
udata/core/activity/models.py
CHANGED
|
@@ -3,23 +3,22 @@ from datetime import datetime
|
|
|
3
3
|
from blinker import Signal
|
|
4
4
|
from mongoengine.signals import post_save
|
|
5
5
|
|
|
6
|
-
from udata.mongo import db
|
|
7
6
|
from udata.auth import current_user
|
|
7
|
+
from udata.mongo import db
|
|
8
8
|
|
|
9
9
|
from .signals import new_activity
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
__all__ = ('Activity', )
|
|
11
|
+
__all__ = ("Activity",)
|
|
13
12
|
|
|
14
13
|
|
|
15
14
|
_registered_activities = {}
|
|
16
15
|
|
|
17
16
|
|
|
18
17
|
class EmitNewActivityMetaClass(db.BaseDocumentMetaclass):
|
|
19
|
-
|
|
18
|
+
"""Ensure any child class dispatches the on_new signal"""
|
|
19
|
+
|
|
20
20
|
def __new__(cls, name, bases, attrs):
|
|
21
|
-
new_class = super(EmitNewActivityMetaClass, cls).__new__(
|
|
22
|
-
cls, name, bases, attrs)
|
|
21
|
+
new_class = super(EmitNewActivityMetaClass, cls).__new__(cls, name, bases, attrs)
|
|
23
22
|
if new_class.key:
|
|
24
23
|
post_save.connect(cls.post_save, sender=new_class)
|
|
25
24
|
_registered_activities[new_class.key] = new_class
|
|
@@ -31,9 +30,10 @@ class EmitNewActivityMetaClass(db.BaseDocumentMetaclass):
|
|
|
31
30
|
|
|
32
31
|
|
|
33
32
|
class Activity(db.Document, metaclass=EmitNewActivityMetaClass):
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
33
|
+
"""Store the activity entries for a single related object"""
|
|
34
|
+
|
|
35
|
+
actor = db.ReferenceField("User", required=True)
|
|
36
|
+
organization = db.ReferenceField("Organization")
|
|
37
37
|
related_to = db.ReferenceField(db.DomainModel, required=True)
|
|
38
38
|
created_at = db.DateTimeField(default=datetime.utcnow, required=True)
|
|
39
39
|
|
|
@@ -42,23 +42,23 @@ class Activity(db.Document, metaclass=EmitNewActivityMetaClass):
|
|
|
42
42
|
on_new = Signal()
|
|
43
43
|
|
|
44
44
|
meta = {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
(
|
|
51
|
-
(
|
|
52
|
-
(
|
|
45
|
+
"indexes": [
|
|
46
|
+
"actor",
|
|
47
|
+
"organization",
|
|
48
|
+
"related_to",
|
|
49
|
+
"-created_at",
|
|
50
|
+
("actor", "-created_at"),
|
|
51
|
+
("organization", "-created_at"),
|
|
52
|
+
("related_to", "-created_at"),
|
|
53
53
|
],
|
|
54
|
-
|
|
54
|
+
"allow_inheritance": True,
|
|
55
55
|
}
|
|
56
56
|
|
|
57
57
|
key = None
|
|
58
58
|
label = None
|
|
59
|
-
badge_type =
|
|
60
|
-
icon =
|
|
61
|
-
template =
|
|
59
|
+
badge_type = "primary"
|
|
60
|
+
icon = "fa fa-info-circle"
|
|
61
|
+
template = "activity/base.html"
|
|
62
62
|
|
|
63
63
|
@classmethod
|
|
64
64
|
def connect(cls, func):
|
|
@@ -66,8 +66,10 @@ class Activity(db.Document, metaclass=EmitNewActivityMetaClass):
|
|
|
66
66
|
|
|
67
67
|
@classmethod
|
|
68
68
|
def emit(cls, related_to, organization=None, extras=None):
|
|
69
|
-
new_activity.send(
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
69
|
+
new_activity.send(
|
|
70
|
+
cls,
|
|
71
|
+
related_to=related_to,
|
|
72
|
+
actor=current_user._get_current_object(),
|
|
73
|
+
organization=organization,
|
|
74
|
+
extras=extras,
|
|
75
|
+
)
|
udata/core/activity/signals.py
CHANGED