udata 9.1.2.dev30355__py2.py3-none-any.whl → 9.1.2.dev30454__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 +111 -134
- 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 +58 -55
- 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/cors.py +99 -0
- 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/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 +8 -6
- udata/tests/api/test_auth_api.py +395 -321
- udata/tests/api/test_base_api.py +33 -35
- 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 +79 -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_cors.py +62 -0
- 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.dev30454.dist-info}/METADATA +7 -3
- udata-9.1.2.dev30454.dist-info/RECORD +706 -0
- udata-9.1.2.dev30355.dist-info/RECORD +0 -704
- {udata-9.1.2.dev30355.dist-info → udata-9.1.2.dev30454.dist-info}/LICENSE +0 -0
- {udata-9.1.2.dev30355.dist-info → udata-9.1.2.dev30454.dist-info}/WHEEL +0 -0
- {udata-9.1.2.dev30355.dist-info → udata-9.1.2.dev30454.dist-info}/entry_points.txt +0 -0
- {udata-9.1.2.dev30355.dist-info → udata-9.1.2.dev30454.dist-info}/top_level.txt +0 -0
udata/tests/test_discussions.py
CHANGED
|
@@ -1,28 +1,31 @@
|
|
|
1
1
|
from datetime import datetime
|
|
2
2
|
|
|
3
|
-
from flask import url_for
|
|
4
3
|
import pytest
|
|
4
|
+
from flask import url_for
|
|
5
5
|
|
|
6
|
-
from udata.
|
|
7
|
-
from udata.core.discussions.models import Message, Discussion
|
|
6
|
+
from udata.core.dataset.factories import DatasetFactory
|
|
8
7
|
from udata.core.discussions.metrics import update_discussions_metric # noqa
|
|
8
|
+
from udata.core.discussions.models import Discussion, Message
|
|
9
9
|
from udata.core.discussions.notifications import discussions_notifications
|
|
10
10
|
from udata.core.discussions.signals import (
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
on_discussion_closed,
|
|
12
|
+
on_discussion_deleted,
|
|
13
|
+
on_new_discussion,
|
|
14
|
+
on_new_discussion_comment,
|
|
13
15
|
)
|
|
14
|
-
from udata.core.spam.signals import on_new_potential_spam
|
|
15
16
|
from udata.core.discussions.tasks import (
|
|
16
|
-
|
|
17
|
-
|
|
17
|
+
notify_discussion_closed,
|
|
18
|
+
notify_new_discussion,
|
|
19
|
+
notify_new_discussion_comment,
|
|
18
20
|
)
|
|
19
|
-
from udata.core.dataset.factories import DatasetFactory
|
|
20
21
|
from udata.core.organization.factories import OrganizationFactory
|
|
21
|
-
from udata.core.
|
|
22
|
+
from udata.core.spam.signals import on_new_potential_spam
|
|
23
|
+
from udata.core.user.factories import AdminFactory, UserFactory
|
|
24
|
+
from udata.models import Dataset, Member
|
|
22
25
|
from udata.tests.helpers import capture_mails
|
|
23
26
|
from udata.utils import faker
|
|
24
27
|
|
|
25
|
-
from . import
|
|
28
|
+
from . import DBTestMixin, TestCase
|
|
26
29
|
from .api import APITestCase
|
|
27
30
|
from .helpers import assert_emit, assert_not_emit
|
|
28
31
|
|
|
@@ -30,24 +33,27 @@ from .helpers import assert_emit, assert_not_emit
|
|
|
30
33
|
class DiscussionsTest(APITestCase):
|
|
31
34
|
modules = []
|
|
32
35
|
|
|
33
|
-
@pytest.mark.options(SPAM_WORDS=[
|
|
36
|
+
@pytest.mark.options(SPAM_WORDS=["spam"])
|
|
34
37
|
def test_new_discussion(self):
|
|
35
38
|
user = self.login()
|
|
36
|
-
dataset = Dataset.objects.create(title=
|
|
39
|
+
dataset = Dataset.objects.create(title="Test dataset")
|
|
37
40
|
|
|
38
41
|
with assert_emit(on_new_discussion):
|
|
39
|
-
response = self.post(
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
42
|
+
response = self.post(
|
|
43
|
+
url_for("api.discussions"),
|
|
44
|
+
{
|
|
45
|
+
"title": "test title",
|
|
46
|
+
"comment": "bla bla",
|
|
47
|
+
"subject": {
|
|
48
|
+
"class": "Dataset",
|
|
49
|
+
"id": dataset.id,
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
)
|
|
47
53
|
self.assert201(response)
|
|
48
54
|
|
|
49
55
|
dataset.reload()
|
|
50
|
-
self.assertEqual(dataset.get_metrics()[
|
|
56
|
+
self.assertEqual(dataset.get_metrics()["discussions"], 1)
|
|
51
57
|
|
|
52
58
|
discussions = Discussion.objects(subject=dataset)
|
|
53
59
|
self.assertEqual(len(discussions), 1)
|
|
@@ -58,37 +64,44 @@ class DiscussionsTest(APITestCase):
|
|
|
58
64
|
self.assertIsNotNone(discussion.created)
|
|
59
65
|
self.assertIsNone(discussion.closed)
|
|
60
66
|
self.assertIsNone(discussion.closed_by)
|
|
61
|
-
self.assertEqual(discussion.title,
|
|
67
|
+
self.assertEqual(discussion.title, "test title")
|
|
62
68
|
self.assertFalse(discussion.is_spam())
|
|
63
69
|
|
|
64
70
|
message = discussion.discussion[0]
|
|
65
|
-
self.assertEqual(message.content,
|
|
71
|
+
self.assertEqual(message.content, "bla bla")
|
|
66
72
|
self.assertEqual(message.posted_by, user)
|
|
67
73
|
self.assertIsNotNone(message.posted_on)
|
|
68
74
|
self.assertFalse(message.is_spam())
|
|
69
75
|
|
|
70
|
-
@pytest.mark.options(SPAM_WORDS=[
|
|
76
|
+
@pytest.mark.options(SPAM_WORDS=["spam"])
|
|
71
77
|
def test_spam_in_new_discussion_title(self):
|
|
72
78
|
self.login()
|
|
73
|
-
dataset = Dataset.objects.create(title=
|
|
79
|
+
dataset = Dataset.objects.create(title="Test dataset")
|
|
74
80
|
|
|
75
81
|
with assert_not_emit(on_new_discussion):
|
|
76
82
|
discussion_id = None
|
|
83
|
+
|
|
77
84
|
def check_signal(args):
|
|
78
85
|
self.assertIsNotNone(discussion_id)
|
|
79
|
-
self.assertIn(
|
|
86
|
+
self.assertIn(
|
|
87
|
+
f"http://local.test/api/1/datasets/{dataset.slug}/#discussion-{discussion_id}",
|
|
88
|
+
args[1]["message"],
|
|
89
|
+
)
|
|
80
90
|
|
|
81
91
|
with assert_emit(on_new_potential_spam, assertions_callback=check_signal):
|
|
82
|
-
response = self.post(
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
92
|
+
response = self.post(
|
|
93
|
+
url_for("api.discussions"),
|
|
94
|
+
{
|
|
95
|
+
"title": "spam and blah",
|
|
96
|
+
"comment": "bla bla",
|
|
97
|
+
"subject": {
|
|
98
|
+
"class": "Dataset",
|
|
99
|
+
"id": dataset.id,
|
|
100
|
+
},
|
|
101
|
+
},
|
|
102
|
+
)
|
|
90
103
|
self.assertStatus(response, 201)
|
|
91
|
-
discussion_id = response.json[
|
|
104
|
+
discussion_id = response.json["id"]
|
|
92
105
|
|
|
93
106
|
discussions = Discussion.objects(subject=dataset)
|
|
94
107
|
self.assertEqual(len(discussions), 1)
|
|
@@ -96,70 +109,81 @@ class DiscussionsTest(APITestCase):
|
|
|
96
109
|
discussion = discussions[0]
|
|
97
110
|
self.assertTrue(discussion.is_spam())
|
|
98
111
|
self.assertFalse(discussion.discussion[0].is_spam())
|
|
99
|
-
self.assertTrue(
|
|
112
|
+
self.assertTrue("signal_new" in discussion.spam.callbacks)
|
|
100
113
|
|
|
101
114
|
with assert_not_emit(on_new_discussion):
|
|
102
|
-
response = self.delete(url_for(
|
|
115
|
+
response = self.delete(url_for("api.discussion_spam", id=discussion.id))
|
|
103
116
|
self.assertStatus(response, 403)
|
|
104
117
|
self.assertTrue(discussion.reload().is_spam())
|
|
105
118
|
|
|
106
119
|
self.login(AdminFactory())
|
|
107
|
-
response = self.get(url_for(
|
|
120
|
+
response = self.get(url_for("api.spam"))
|
|
108
121
|
self.assertStatus(response, 200)
|
|
109
|
-
self.assertEqual(
|
|
110
|
-
|
|
111
|
-
|
|
122
|
+
self.assertEqual(
|
|
123
|
+
response.json,
|
|
124
|
+
[
|
|
125
|
+
{
|
|
126
|
+
"message": discussion.spam_report_message([discussion]),
|
|
127
|
+
}
|
|
128
|
+
],
|
|
129
|
+
)
|
|
112
130
|
|
|
113
131
|
with assert_emit(on_new_discussion):
|
|
114
|
-
response = self.delete(url_for(
|
|
132
|
+
response = self.delete(url_for("api.discussion_spam", id=discussion.id))
|
|
115
133
|
self.assertStatus(response, 200)
|
|
116
134
|
self.assertFalse(discussion.reload().is_spam())
|
|
117
135
|
|
|
118
136
|
# Adding a new comment / modifying the not spam discussion
|
|
119
|
-
response = self.post(
|
|
120
|
-
|
|
121
|
-
|
|
137
|
+
response = self.post(
|
|
138
|
+
url_for("api.discussion", id=discussion.id), {"comment": "A new normal comment"}
|
|
139
|
+
)
|
|
122
140
|
self.assertStatus(response, 200)
|
|
123
141
|
self.assertFalse(discussion.reload().is_spam())
|
|
124
142
|
|
|
125
|
-
|
|
126
|
-
@pytest.mark.options(SPAM_WORDS=['spam'])
|
|
143
|
+
@pytest.mark.options(SPAM_WORDS=["spam"])
|
|
127
144
|
def test_spam_by_owner(self):
|
|
128
145
|
user = self.login()
|
|
129
|
-
dataset = Dataset.objects.create(title=
|
|
146
|
+
dataset = Dataset.objects.create(title="Test dataset", owner=user)
|
|
130
147
|
|
|
131
148
|
with assert_not_emit(on_new_potential_spam):
|
|
132
|
-
response = self.post(
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
149
|
+
response = self.post(
|
|
150
|
+
url_for("api.discussions"),
|
|
151
|
+
{
|
|
152
|
+
"title": "spam and blah",
|
|
153
|
+
"comment": "bla bla",
|
|
154
|
+
"subject": {
|
|
155
|
+
"class": "Dataset",
|
|
156
|
+
"id": dataset.id,
|
|
157
|
+
},
|
|
158
|
+
},
|
|
159
|
+
)
|
|
140
160
|
self.assertStatus(response, 201)
|
|
141
|
-
|
|
161
|
+
|
|
142
162
|
with assert_not_emit(on_new_potential_spam):
|
|
143
|
-
response = self.post(
|
|
144
|
-
|
|
145
|
-
|
|
163
|
+
response = self.post(
|
|
164
|
+
url_for("api.discussion", id=response.json["id"]),
|
|
165
|
+
{"comment": "A comment with spam by owner"},
|
|
166
|
+
)
|
|
146
167
|
self.assertStatus(response, 200)
|
|
147
168
|
|
|
148
|
-
@pytest.mark.options(SPAM_WORDS=[
|
|
169
|
+
@pytest.mark.options(SPAM_WORDS=["spam"])
|
|
149
170
|
def test_spam_in_new_discussion_comment(self):
|
|
150
171
|
self.login()
|
|
151
|
-
dataset = Dataset.objects.create(title=
|
|
172
|
+
dataset = Dataset.objects.create(title="Test dataset")
|
|
152
173
|
|
|
153
174
|
with assert_not_emit(on_new_discussion):
|
|
154
175
|
with assert_emit(on_new_potential_spam):
|
|
155
|
-
response = self.post(
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
176
|
+
response = self.post(
|
|
177
|
+
url_for("api.discussions"),
|
|
178
|
+
{
|
|
179
|
+
"title": "title and blah",
|
|
180
|
+
"comment": "bla bla spam",
|
|
181
|
+
"subject": {
|
|
182
|
+
"class": "Dataset",
|
|
183
|
+
"id": dataset.id,
|
|
184
|
+
},
|
|
185
|
+
},
|
|
186
|
+
)
|
|
163
187
|
self.assertStatus(response, 201)
|
|
164
188
|
|
|
165
189
|
discussions = Discussion.objects(subject=dataset)
|
|
@@ -171,53 +195,60 @@ class DiscussionsTest(APITestCase):
|
|
|
171
195
|
|
|
172
196
|
def test_new_discussion_missing_comment(self):
|
|
173
197
|
self.login()
|
|
174
|
-
dataset = Dataset.objects.create(title=
|
|
175
|
-
|
|
176
|
-
response = self.post(
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
198
|
+
dataset = Dataset.objects.create(title="Test dataset")
|
|
199
|
+
|
|
200
|
+
response = self.post(
|
|
201
|
+
url_for("api.discussions"),
|
|
202
|
+
{
|
|
203
|
+
"title": "test title",
|
|
204
|
+
"subject": {
|
|
205
|
+
"class": "Dataset",
|
|
206
|
+
"id": dataset.id,
|
|
207
|
+
},
|
|
208
|
+
},
|
|
209
|
+
)
|
|
183
210
|
self.assertStatus(response, 400)
|
|
184
211
|
|
|
185
212
|
def test_new_discussion_missing_title(self):
|
|
186
213
|
self.login()
|
|
187
|
-
dataset = Dataset.objects.create(title=
|
|
188
|
-
|
|
189
|
-
response = self.post(
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
214
|
+
dataset = Dataset.objects.create(title="Test dataset")
|
|
215
|
+
|
|
216
|
+
response = self.post(
|
|
217
|
+
url_for("api.discussions"),
|
|
218
|
+
{
|
|
219
|
+
"comment": "bla bla",
|
|
220
|
+
"subject": {
|
|
221
|
+
"class": "Dataset",
|
|
222
|
+
"id": dataset.id,
|
|
223
|
+
},
|
|
224
|
+
},
|
|
225
|
+
)
|
|
196
226
|
self.assertStatus(response, 400)
|
|
197
227
|
|
|
198
228
|
def test_new_discussion_missing_subject(self):
|
|
199
229
|
self.login()
|
|
200
|
-
response = self.post(
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
})
|
|
230
|
+
response = self.post(
|
|
231
|
+
url_for("api.discussions"), {"title": "test title", "comment": "bla bla"}
|
|
232
|
+
)
|
|
204
233
|
self.assertStatus(response, 400)
|
|
205
234
|
|
|
206
235
|
def test_new_discussion_with_extras(self):
|
|
207
236
|
user = self.login()
|
|
208
|
-
dataset = Dataset.objects.create(title=
|
|
209
|
-
extras={'key': 'value'})
|
|
237
|
+
dataset = Dataset.objects.create(title="Test dataset", extras={"key": "value"})
|
|
210
238
|
|
|
211
239
|
with assert_emit(on_new_discussion):
|
|
212
|
-
response = self.post(
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
240
|
+
response = self.post(
|
|
241
|
+
url_for("api.discussions"),
|
|
242
|
+
{
|
|
243
|
+
"title": "test title",
|
|
244
|
+
"comment": "bla bla",
|
|
245
|
+
"subject": {
|
|
246
|
+
"class": "Dataset",
|
|
247
|
+
"id": dataset.id,
|
|
248
|
+
},
|
|
249
|
+
"extras": {"key": "value"},
|
|
218
250
|
},
|
|
219
|
-
|
|
220
|
-
})
|
|
251
|
+
)
|
|
221
252
|
self.assert201(response)
|
|
222
253
|
|
|
223
254
|
discussions = Discussion.objects(subject=dataset)
|
|
@@ -226,16 +257,16 @@ class DiscussionsTest(APITestCase):
|
|
|
226
257
|
discussion = discussions[0]
|
|
227
258
|
self.assertEqual(discussion.user, user)
|
|
228
259
|
self.assertEqual(len(discussion.discussion), 1)
|
|
229
|
-
self.assertEqual(discussion.title,
|
|
230
|
-
self.assertEqual(discussion.extras, {
|
|
260
|
+
self.assertEqual(discussion.title, "test title")
|
|
261
|
+
self.assertEqual(discussion.extras, {"key": "value"})
|
|
231
262
|
|
|
232
263
|
message = discussion.discussion[0]
|
|
233
|
-
self.assertEqual(message.content,
|
|
264
|
+
self.assertEqual(message.content, "bla bla")
|
|
234
265
|
self.assertEqual(message.posted_by, user)
|
|
235
266
|
self.assertIsNotNone(message.posted_on)
|
|
236
267
|
|
|
237
268
|
def test_list_discussions(self):
|
|
238
|
-
dataset = Dataset.objects.create(title=
|
|
269
|
+
dataset = Dataset.objects.create(title="Test dataset")
|
|
239
270
|
open_discussions = []
|
|
240
271
|
closed_discussions = []
|
|
241
272
|
for i in range(2):
|
|
@@ -244,8 +275,8 @@ class DiscussionsTest(APITestCase):
|
|
|
244
275
|
discussion = Discussion.objects.create(
|
|
245
276
|
subject=dataset,
|
|
246
277
|
user=user,
|
|
247
|
-
title=
|
|
248
|
-
discussion=[message]
|
|
278
|
+
title="test discussion {}".format(i),
|
|
279
|
+
discussion=[message],
|
|
249
280
|
)
|
|
250
281
|
open_discussions.append(discussion)
|
|
251
282
|
for i in range(3):
|
|
@@ -254,21 +285,20 @@ class DiscussionsTest(APITestCase):
|
|
|
254
285
|
discussion = Discussion.objects.create(
|
|
255
286
|
subject=dataset,
|
|
256
287
|
user=user,
|
|
257
|
-
title=
|
|
288
|
+
title="test discussion {}".format(i),
|
|
258
289
|
discussion=[message],
|
|
259
290
|
closed=datetime.utcnow(),
|
|
260
|
-
closed_by=user
|
|
291
|
+
closed_by=user,
|
|
261
292
|
)
|
|
262
293
|
closed_discussions.append(discussion)
|
|
263
294
|
|
|
264
|
-
response = self.get(url_for(
|
|
295
|
+
response = self.get(url_for("api.discussions"))
|
|
265
296
|
self.assert200(response)
|
|
266
297
|
|
|
267
|
-
self.assertEqual(len(response.json[
|
|
268
|
-
len(open_discussions + closed_discussions))
|
|
298
|
+
self.assertEqual(len(response.json["data"]), len(open_discussions + closed_discussions))
|
|
269
299
|
|
|
270
300
|
def test_list_discussions_closed_filter(self):
|
|
271
|
-
dataset = Dataset.objects.create(title=
|
|
301
|
+
dataset = Dataset.objects.create(title="Test dataset")
|
|
272
302
|
open_discussions = []
|
|
273
303
|
closed_discussions = []
|
|
274
304
|
for i in range(2):
|
|
@@ -277,8 +307,8 @@ class DiscussionsTest(APITestCase):
|
|
|
277
307
|
discussion = Discussion.objects.create(
|
|
278
308
|
subject=dataset,
|
|
279
309
|
user=user,
|
|
280
|
-
title=
|
|
281
|
-
discussion=[message]
|
|
310
|
+
title="test discussion {}".format(i),
|
|
311
|
+
discussion=[message],
|
|
282
312
|
)
|
|
283
313
|
open_discussions.append(discussion)
|
|
284
314
|
for i in range(3):
|
|
@@ -287,18 +317,18 @@ class DiscussionsTest(APITestCase):
|
|
|
287
317
|
discussion = Discussion.objects.create(
|
|
288
318
|
subject=dataset,
|
|
289
319
|
user=user,
|
|
290
|
-
title=
|
|
320
|
+
title="test discussion {}".format(i),
|
|
291
321
|
discussion=[message],
|
|
292
322
|
closed=datetime.utcnow(),
|
|
293
|
-
closed_by=user
|
|
323
|
+
closed_by=user,
|
|
294
324
|
)
|
|
295
325
|
closed_discussions.append(discussion)
|
|
296
326
|
|
|
297
|
-
response = self.get(url_for(
|
|
327
|
+
response = self.get(url_for("api.discussions", closed=True))
|
|
298
328
|
self.assert200(response)
|
|
299
|
-
self.assertEqual(len(response.json[
|
|
300
|
-
for discussion in response.json[
|
|
301
|
-
self.assertIsNotNone(discussion[
|
|
329
|
+
self.assertEqual(len(response.json["data"]), len(closed_discussions))
|
|
330
|
+
for discussion in response.json["data"]:
|
|
331
|
+
self.assertIsNotNone(discussion["closed"])
|
|
302
332
|
|
|
303
333
|
def test_list_discussions_for(self):
|
|
304
334
|
dataset = DatasetFactory()
|
|
@@ -309,8 +339,8 @@ class DiscussionsTest(APITestCase):
|
|
|
309
339
|
discussion = Discussion.objects.create(
|
|
310
340
|
subject=dataset,
|
|
311
341
|
user=user,
|
|
312
|
-
title=
|
|
313
|
-
discussion=[message]
|
|
342
|
+
title="test discussion {}".format(i),
|
|
343
|
+
discussion=[message],
|
|
314
344
|
)
|
|
315
345
|
discussions.append(discussion)
|
|
316
346
|
user = UserFactory()
|
|
@@ -318,15 +348,15 @@ class DiscussionsTest(APITestCase):
|
|
|
318
348
|
Discussion.objects.create(
|
|
319
349
|
subject=DatasetFactory(),
|
|
320
350
|
user=user,
|
|
321
|
-
title=
|
|
322
|
-
discussion=[message]
|
|
351
|
+
title="test discussion {}".format(i),
|
|
352
|
+
discussion=[message],
|
|
323
353
|
)
|
|
324
354
|
|
|
325
|
-
kwargs = {
|
|
326
|
-
response = self.get(url_for(
|
|
355
|
+
kwargs = {"for": str(dataset.id)}
|
|
356
|
+
response = self.get(url_for("api.discussions", **kwargs))
|
|
327
357
|
self.assert200(response)
|
|
328
358
|
|
|
329
|
-
self.assertEqual(len(response.json[
|
|
359
|
+
self.assertEqual(len(response.json["data"]), len(discussions))
|
|
330
360
|
|
|
331
361
|
def test_list_discussions_user(self):
|
|
332
362
|
dataset = DatasetFactory()
|
|
@@ -337,8 +367,8 @@ class DiscussionsTest(APITestCase):
|
|
|
337
367
|
discussion = Discussion.objects.create(
|
|
338
368
|
subject=dataset,
|
|
339
369
|
user=user,
|
|
340
|
-
title=
|
|
341
|
-
discussion=[message]
|
|
370
|
+
title="test discussion {}".format(i),
|
|
371
|
+
discussion=[message],
|
|
342
372
|
)
|
|
343
373
|
discussions.append(discussion)
|
|
344
374
|
user = UserFactory()
|
|
@@ -346,293 +376,262 @@ class DiscussionsTest(APITestCase):
|
|
|
346
376
|
Discussion.objects.create(
|
|
347
377
|
subject=DatasetFactory(),
|
|
348
378
|
user=user,
|
|
349
|
-
title=
|
|
350
|
-
discussion=[message]
|
|
379
|
+
title="test discussion {}".format(i + 1),
|
|
380
|
+
discussion=[message],
|
|
351
381
|
)
|
|
352
382
|
|
|
353
|
-
kwargs = {
|
|
354
|
-
response = self.get(url_for(
|
|
383
|
+
kwargs = {"user": str(user.id)}
|
|
384
|
+
response = self.get(url_for("api.discussions", **kwargs))
|
|
355
385
|
self.assert200(response)
|
|
356
386
|
|
|
357
|
-
self.assertEqual(len(response.json[
|
|
358
|
-
self.assertEqual(response.json[
|
|
387
|
+
self.assertEqual(len(response.json["data"]), 1)
|
|
388
|
+
self.assertEqual(response.json["data"][0]["user"]["id"], str(user.id))
|
|
359
389
|
|
|
360
390
|
def test_get_discussion(self):
|
|
361
|
-
dataset = Dataset.objects.create(title=
|
|
391
|
+
dataset = Dataset.objects.create(title="Test dataset")
|
|
362
392
|
user = UserFactory()
|
|
363
|
-
message = Message(content=
|
|
393
|
+
message = Message(content="bla bla", posted_by=user)
|
|
364
394
|
discussion = Discussion.objects.create(
|
|
365
|
-
subject=dataset,
|
|
366
|
-
user=user,
|
|
367
|
-
title='test discussion',
|
|
368
|
-
discussion=[message]
|
|
395
|
+
subject=dataset, user=user, title="test discussion", discussion=[message]
|
|
369
396
|
)
|
|
370
397
|
|
|
371
|
-
response = self.get(url_for(
|
|
398
|
+
response = self.get(url_for("api.discussion", **{"id": discussion.id}))
|
|
372
399
|
self.assert200(response)
|
|
373
400
|
|
|
374
401
|
data = response.json
|
|
375
402
|
|
|
376
|
-
self.assertEqual(data[
|
|
377
|
-
self.assertEqual(data[
|
|
378
|
-
self.assertEqual(data[
|
|
379
|
-
self.assertEqual(data[
|
|
380
|
-
self.assertIsNotNone(data[
|
|
381
|
-
self.assertEqual(len(data[
|
|
382
|
-
self.assertEqual(data[
|
|
383
|
-
self.assertEqual(
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
@pytest.mark.options(SPAM_WORDS=['spam'])
|
|
403
|
+
self.assertEqual(data["subject"]["class"], "Dataset")
|
|
404
|
+
self.assertEqual(data["subject"]["id"], str(dataset.id))
|
|
405
|
+
self.assertEqual(data["user"]["id"], str(user.id))
|
|
406
|
+
self.assertEqual(data["title"], "test discussion")
|
|
407
|
+
self.assertIsNotNone(data["created"])
|
|
408
|
+
self.assertEqual(len(data["discussion"]), 1)
|
|
409
|
+
self.assertEqual(data["discussion"][0]["content"], "bla bla")
|
|
410
|
+
self.assertEqual(data["discussion"][0]["posted_by"]["id"], str(user.id))
|
|
411
|
+
self.assertIsNotNone(data["discussion"][0]["posted_on"])
|
|
412
|
+
|
|
413
|
+
@pytest.mark.options(SPAM_WORDS=["spam"])
|
|
388
414
|
def test_add_comment_to_discussion(self):
|
|
389
|
-
dataset = Dataset.objects.create(title=
|
|
415
|
+
dataset = Dataset.objects.create(title="Test dataset")
|
|
390
416
|
user = UserFactory()
|
|
391
|
-
message = Message(content=
|
|
417
|
+
message = Message(content="bla bla", posted_by=user)
|
|
392
418
|
discussion = Discussion.objects.create(
|
|
393
|
-
subject=dataset,
|
|
394
|
-
user=user,
|
|
395
|
-
title='test discussion',
|
|
396
|
-
discussion=[message]
|
|
419
|
+
subject=dataset, user=user, title="test discussion", discussion=[message]
|
|
397
420
|
)
|
|
398
421
|
on_new_discussion.send(discussion) # Updating metrics.
|
|
399
422
|
|
|
400
423
|
poster = self.login()
|
|
401
424
|
with assert_emit(on_new_discussion_comment):
|
|
402
|
-
response = self.post(
|
|
403
|
-
|
|
404
|
-
|
|
425
|
+
response = self.post(
|
|
426
|
+
url_for("api.discussion", id=discussion.id), {"comment": "new bla bla"}
|
|
427
|
+
)
|
|
405
428
|
self.assert200(response)
|
|
406
429
|
|
|
407
430
|
dataset.reload()
|
|
408
431
|
discussion.reload()
|
|
409
|
-
self.assertEqual(dataset.get_metrics()[
|
|
432
|
+
self.assertEqual(dataset.get_metrics()["discussions"], 1)
|
|
410
433
|
|
|
411
434
|
data = response.json
|
|
412
435
|
|
|
413
|
-
self.assertEqual(data[
|
|
414
|
-
self.assertEqual(data[
|
|
415
|
-
self.assertEqual(data[
|
|
416
|
-
self.assertEqual(data[
|
|
417
|
-
self.assertIsNotNone(data[
|
|
418
|
-
self.assertIsNone(data[
|
|
419
|
-
self.assertIsNone(data[
|
|
420
|
-
self.assertEqual(len(data[
|
|
421
|
-
self.assertEqual(data[
|
|
422
|
-
self.assertEqual(
|
|
423
|
-
|
|
424
|
-
self.assertIsNotNone(data['discussion'][1]['posted_on'])
|
|
436
|
+
self.assertEqual(data["subject"]["class"], "Dataset")
|
|
437
|
+
self.assertEqual(data["subject"]["id"], str(dataset.id))
|
|
438
|
+
self.assertEqual(data["user"]["id"], str(user.id))
|
|
439
|
+
self.assertEqual(data["title"], "test discussion")
|
|
440
|
+
self.assertIsNotNone(data["created"])
|
|
441
|
+
self.assertIsNone(data["closed"])
|
|
442
|
+
self.assertIsNone(data["closed_by"])
|
|
443
|
+
self.assertEqual(len(data["discussion"]), 2)
|
|
444
|
+
self.assertEqual(data["discussion"][1]["content"], "new bla bla")
|
|
445
|
+
self.assertEqual(data["discussion"][1]["posted_by"]["id"], str(poster.id))
|
|
446
|
+
self.assertIsNotNone(data["discussion"][1]["posted_on"])
|
|
425
447
|
self.assertFalse(discussion.discussion[1].is_spam())
|
|
426
448
|
|
|
427
|
-
@pytest.mark.options(SPAM_WORDS=[
|
|
449
|
+
@pytest.mark.options(SPAM_WORDS=["spam"])
|
|
428
450
|
def test_add_spam_comment_to_discussion(self):
|
|
429
|
-
|
|
430
|
-
dataset = Dataset.objects.create(title='Test dataset')
|
|
451
|
+
dataset = Dataset.objects.create(title="Test dataset")
|
|
431
452
|
user = UserFactory()
|
|
432
|
-
message = Message(content=
|
|
453
|
+
message = Message(content="bla bla", posted_by=user)
|
|
433
454
|
discussion = Discussion.objects.create(
|
|
434
|
-
subject=dataset,
|
|
435
|
-
user=user,
|
|
436
|
-
title='test discussion',
|
|
437
|
-
discussion=[message]
|
|
455
|
+
subject=dataset, user=user, title="test discussion", discussion=[message]
|
|
438
456
|
)
|
|
439
457
|
on_new_discussion.send(discussion) # Updating metrics.
|
|
440
458
|
|
|
441
459
|
self.login()
|
|
442
460
|
with assert_not_emit(on_new_discussion_comment):
|
|
461
|
+
|
|
443
462
|
def check_signal(args):
|
|
444
|
-
self.assertIn(discussion.external_url, args[1][
|
|
463
|
+
self.assertIn(discussion.external_url, args[1]["message"])
|
|
445
464
|
|
|
446
465
|
with assert_emit(on_new_potential_spam, assertions_callback=check_signal):
|
|
447
|
-
response = self.post(
|
|
448
|
-
|
|
449
|
-
|
|
466
|
+
response = self.post(
|
|
467
|
+
url_for("api.discussion", id=discussion.id), {"comment": "spam new bla bla"}
|
|
468
|
+
)
|
|
450
469
|
self.assert200(response)
|
|
451
470
|
|
|
452
471
|
discussion.reload()
|
|
453
472
|
self.assertFalse(discussion.is_spam())
|
|
454
473
|
self.assertTrue(discussion.discussion[1].is_spam())
|
|
455
|
-
self.assertTrue(
|
|
474
|
+
self.assertTrue("signal_comment" in discussion.discussion[1].spam.callbacks)
|
|
456
475
|
|
|
457
476
|
self.login(AdminFactory())
|
|
458
|
-
response = self.get(url_for(
|
|
477
|
+
response = self.get(url_for("api.spam"))
|
|
459
478
|
self.assertStatus(response, 200)
|
|
460
|
-
self.assertEqual(
|
|
461
|
-
|
|
462
|
-
|
|
479
|
+
self.assertEqual(
|
|
480
|
+
response.json,
|
|
481
|
+
[
|
|
482
|
+
{
|
|
483
|
+
"message": discussion.spam_report_message([discussion]),
|
|
484
|
+
}
|
|
485
|
+
],
|
|
486
|
+
)
|
|
463
487
|
|
|
464
488
|
with assert_emit(on_new_discussion_comment):
|
|
465
|
-
response = self.delete(url_for(
|
|
489
|
+
response = self.delete(url_for("api.discussion_comment_spam", id=discussion.id, cidx=1))
|
|
466
490
|
self.assertStatus(response, 200)
|
|
467
491
|
self.assertFalse(discussion.reload().discussion[1].is_spam())
|
|
468
492
|
|
|
469
|
-
response = self.post(
|
|
470
|
-
|
|
471
|
-
|
|
493
|
+
response = self.post(
|
|
494
|
+
url_for("api.discussion", id=discussion.id), {"comment": "New comment"}
|
|
495
|
+
)
|
|
472
496
|
self.assert200(response)
|
|
473
497
|
|
|
474
498
|
# The spam comment marked as no spam is still a no spam
|
|
475
499
|
self.assertFalse(discussion.reload().discussion[1].is_spam())
|
|
476
500
|
|
|
477
|
-
|
|
478
501
|
def test_close_discussion(self):
|
|
479
502
|
owner = self.login()
|
|
480
503
|
user = UserFactory()
|
|
481
|
-
dataset = Dataset.objects.create(title=
|
|
482
|
-
message = Message(content=
|
|
504
|
+
dataset = Dataset.objects.create(title="Test dataset", owner=owner)
|
|
505
|
+
message = Message(content="bla bla", posted_by=user)
|
|
483
506
|
discussion = Discussion.objects.create(
|
|
484
|
-
subject=dataset,
|
|
485
|
-
user=user,
|
|
486
|
-
title='test discussion',
|
|
487
|
-
discussion=[message]
|
|
507
|
+
subject=dataset, user=user, title="test discussion", discussion=[message]
|
|
488
508
|
)
|
|
489
509
|
on_new_discussion.send(discussion) # Updating metrics.
|
|
490
510
|
|
|
491
511
|
with assert_emit(on_discussion_closed):
|
|
492
|
-
response = self.post(
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
512
|
+
response = self.post(
|
|
513
|
+
url_for("api.discussion", id=discussion.id),
|
|
514
|
+
{"comment": "close bla bla", "close": True},
|
|
515
|
+
)
|
|
496
516
|
self.assert200(response)
|
|
497
517
|
|
|
498
518
|
dataset.reload()
|
|
499
|
-
self.assertEqual(dataset.get_metrics()[
|
|
519
|
+
self.assertEqual(dataset.get_metrics()["discussions"], 0)
|
|
500
520
|
|
|
501
521
|
data = response.json
|
|
502
522
|
|
|
503
|
-
self.assertEqual(data[
|
|
504
|
-
self.assertEqual(data[
|
|
505
|
-
self.assertEqual(data[
|
|
506
|
-
self.assertEqual(data[
|
|
507
|
-
self.assertIsNotNone(data[
|
|
508
|
-
self.assertIsNotNone(data[
|
|
509
|
-
self.assertEqual(data[
|
|
510
|
-
self.assertEqual(len(data[
|
|
511
|
-
self.assertEqual(data[
|
|
512
|
-
self.assertEqual(
|
|
513
|
-
|
|
514
|
-
self.assertIsNotNone(data['discussion'][1]['posted_on'])
|
|
523
|
+
self.assertEqual(data["subject"]["class"], "Dataset")
|
|
524
|
+
self.assertEqual(data["subject"]["id"], str(dataset.id))
|
|
525
|
+
self.assertEqual(data["user"]["id"], str(user.id))
|
|
526
|
+
self.assertEqual(data["title"], "test discussion")
|
|
527
|
+
self.assertIsNotNone(data["created"])
|
|
528
|
+
self.assertIsNotNone(data["closed"])
|
|
529
|
+
self.assertEqual(data["closed_by"]["id"], str(owner.id))
|
|
530
|
+
self.assertEqual(len(data["discussion"]), 2)
|
|
531
|
+
self.assertEqual(data["discussion"][1]["content"], "close bla bla")
|
|
532
|
+
self.assertEqual(data["discussion"][1]["posted_by"]["id"], str(owner.id))
|
|
533
|
+
self.assertIsNotNone(data["discussion"][1]["posted_on"])
|
|
515
534
|
|
|
516
535
|
# Can't add anymore comments
|
|
517
|
-
response = self.post(
|
|
518
|
-
|
|
536
|
+
response = self.post(
|
|
537
|
+
url_for("api.discussion", id=discussion.id), {"comment": "can't comment"}
|
|
538
|
+
)
|
|
519
539
|
self.assert403(response)
|
|
520
540
|
|
|
521
541
|
def test_close_discussion_permissions(self):
|
|
522
|
-
dataset = Dataset.objects.create(title=
|
|
542
|
+
dataset = Dataset.objects.create(title="Test dataset")
|
|
523
543
|
user = UserFactory()
|
|
524
|
-
message = Message(content=
|
|
544
|
+
message = Message(content="bla bla", posted_by=user)
|
|
525
545
|
discussion = Discussion.objects.create(
|
|
526
|
-
subject=dataset,
|
|
527
|
-
user=user,
|
|
528
|
-
title='test discussion',
|
|
529
|
-
discussion=[message]
|
|
546
|
+
subject=dataset, user=user, title="test discussion", discussion=[message]
|
|
530
547
|
)
|
|
531
548
|
on_new_discussion.send(discussion) # Updating metrics.
|
|
532
549
|
|
|
533
550
|
self.login()
|
|
534
|
-
response = self.post(
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
})
|
|
551
|
+
response = self.post(
|
|
552
|
+
url_for("api.discussion", id=discussion.id), {"comment": "close bla bla", "close": True}
|
|
553
|
+
)
|
|
538
554
|
self.assert403(response)
|
|
539
555
|
|
|
540
556
|
dataset.reload()
|
|
541
557
|
# Metrics unchanged after attempt to close the discussion.
|
|
542
|
-
self.assertEqual(dataset.get_metrics()[
|
|
558
|
+
self.assertEqual(dataset.get_metrics()["discussions"], 1)
|
|
543
559
|
|
|
544
560
|
def test_delete_discussion(self):
|
|
545
561
|
owner = self.login(AdminFactory())
|
|
546
562
|
user = UserFactory()
|
|
547
|
-
dataset = Dataset.objects.create(title=
|
|
548
|
-
message = Message(content=
|
|
563
|
+
dataset = Dataset.objects.create(title="Test dataset", owner=owner)
|
|
564
|
+
message = Message(content="bla bla", posted_by=user)
|
|
549
565
|
discussion = Discussion.objects.create(
|
|
550
|
-
subject=dataset,
|
|
551
|
-
user=user,
|
|
552
|
-
title='test discussion',
|
|
553
|
-
discussion=[message]
|
|
566
|
+
subject=dataset, user=user, title="test discussion", discussion=[message]
|
|
554
567
|
)
|
|
555
568
|
on_new_discussion.send(discussion) # Updating metrics.
|
|
556
569
|
self.assertEqual(Discussion.objects(subject=dataset).count(), 1)
|
|
557
570
|
|
|
558
571
|
with assert_emit(on_discussion_deleted):
|
|
559
|
-
response = self.delete(url_for(
|
|
572
|
+
response = self.delete(url_for("api.discussion", id=discussion.id))
|
|
560
573
|
self.assertStatus(response, 204)
|
|
561
574
|
|
|
562
575
|
dataset.reload()
|
|
563
|
-
self.assertEqual(dataset.get_metrics()[
|
|
576
|
+
self.assertEqual(dataset.get_metrics()["discussions"], 0)
|
|
564
577
|
self.assertEqual(Discussion.objects(subject=dataset).count(), 0)
|
|
565
578
|
|
|
566
579
|
def test_delete_discussion_comment(self):
|
|
567
580
|
owner = self.login(AdminFactory())
|
|
568
581
|
user = UserFactory()
|
|
569
|
-
dataset = Dataset.objects.create(title=
|
|
570
|
-
message = Message(content=
|
|
571
|
-
message2 = Message(content=
|
|
582
|
+
dataset = Dataset.objects.create(title="Test dataset", owner=owner)
|
|
583
|
+
message = Message(content="bla bla", posted_by=user)
|
|
584
|
+
message2 = Message(content="bla bla bla", posted_by=user)
|
|
572
585
|
discussion = Discussion.objects.create(
|
|
573
|
-
subject=dataset,
|
|
574
|
-
user=user,
|
|
575
|
-
title='test discussion',
|
|
576
|
-
discussion=[message, message2]
|
|
586
|
+
subject=dataset, user=user, title="test discussion", discussion=[message, message2]
|
|
577
587
|
)
|
|
578
588
|
self.assertEqual(len(discussion.discussion), 2)
|
|
579
589
|
|
|
580
590
|
# test first comment deletion
|
|
581
|
-
response = self.delete(url_for(
|
|
582
|
-
id=discussion.id, cidx=0))
|
|
591
|
+
response = self.delete(url_for("api.discussion_comment", id=discussion.id, cidx=0))
|
|
583
592
|
self.assertStatus(response, 400)
|
|
584
593
|
|
|
585
594
|
# test effective deletion
|
|
586
|
-
response = self.delete(url_for(
|
|
587
|
-
id=discussion.id, cidx=1))
|
|
595
|
+
response = self.delete(url_for("api.discussion_comment", id=discussion.id, cidx=1))
|
|
588
596
|
self.assertStatus(response, 204)
|
|
589
597
|
discussion.reload()
|
|
590
598
|
self.assertEqual(len(discussion.discussion), 1)
|
|
591
|
-
self.assertEqual(discussion.discussion[0].content,
|
|
599
|
+
self.assertEqual(discussion.discussion[0].content, "bla bla")
|
|
592
600
|
|
|
593
601
|
# delete again to test list overflow
|
|
594
|
-
response = self.delete(url_for(
|
|
595
|
-
id=discussion.id, cidx=3))
|
|
602
|
+
response = self.delete(url_for("api.discussion_comment", id=discussion.id, cidx=3))
|
|
596
603
|
self.assertStatus(response, 404)
|
|
597
604
|
|
|
598
605
|
# delete again to test last comment deletion
|
|
599
|
-
response = self.delete(url_for(
|
|
600
|
-
id=discussion.id, cidx=0))
|
|
606
|
+
response = self.delete(url_for("api.discussion_comment", id=discussion.id, cidx=0))
|
|
601
607
|
self.assertStatus(response, 400)
|
|
602
608
|
|
|
603
609
|
def test_delete_discussion_permissions(self):
|
|
604
|
-
dataset = Dataset.objects.create(title=
|
|
610
|
+
dataset = Dataset.objects.create(title="Test dataset")
|
|
605
611
|
user = UserFactory()
|
|
606
|
-
message = Message(content=
|
|
612
|
+
message = Message(content="bla bla", posted_by=user)
|
|
607
613
|
discussion = Discussion.objects.create(
|
|
608
|
-
subject=dataset,
|
|
609
|
-
user=user,
|
|
610
|
-
title='test discussion',
|
|
611
|
-
discussion=[message]
|
|
614
|
+
subject=dataset, user=user, title="test discussion", discussion=[message]
|
|
612
615
|
)
|
|
613
616
|
on_new_discussion.send(discussion) # Updating metrics.
|
|
614
617
|
|
|
615
618
|
self.login()
|
|
616
|
-
response = self.delete(url_for(
|
|
619
|
+
response = self.delete(url_for("api.discussion", id=discussion.id))
|
|
617
620
|
self.assert403(response)
|
|
618
621
|
|
|
619
622
|
dataset.reload()
|
|
620
623
|
# Metrics unchanged after attempt to delete the discussion.
|
|
621
|
-
self.assertEqual(dataset.get_metrics()[
|
|
624
|
+
self.assertEqual(dataset.get_metrics()["discussions"], 1)
|
|
622
625
|
|
|
623
626
|
def test_delete_discussion_comment_permissions(self):
|
|
624
|
-
dataset = Dataset.objects.create(title=
|
|
627
|
+
dataset = Dataset.objects.create(title="Test dataset")
|
|
625
628
|
user = UserFactory()
|
|
626
|
-
message = Message(content=
|
|
629
|
+
message = Message(content="bla bla", posted_by=user)
|
|
627
630
|
discussion = Discussion.objects.create(
|
|
628
|
-
subject=dataset,
|
|
629
|
-
user=user,
|
|
630
|
-
title='test discussion',
|
|
631
|
-
discussion=[message]
|
|
631
|
+
subject=dataset, user=user, title="test discussion", discussion=[message]
|
|
632
632
|
)
|
|
633
633
|
self.login()
|
|
634
|
-
response = self.delete(url_for(
|
|
635
|
-
id=discussion.id, cidx=0))
|
|
634
|
+
response = self.delete(url_for("api.discussion_comment", id=discussion.id, cidx=0))
|
|
636
635
|
self.assert403(response)
|
|
637
636
|
|
|
638
637
|
|
|
@@ -646,10 +645,7 @@ class DiscussionsNotificationsTest(TestCase, DBTestMixin):
|
|
|
646
645
|
user = UserFactory()
|
|
647
646
|
message = Message(content=faker.sentence(), posted_by=user)
|
|
648
647
|
discussion = Discussion.objects.create(
|
|
649
|
-
subject=dataset,
|
|
650
|
-
user=user,
|
|
651
|
-
title=faker.sentence(),
|
|
652
|
-
discussion=[message]
|
|
648
|
+
subject=dataset, user=user, title=faker.sentence(), discussion=[message]
|
|
653
649
|
)
|
|
654
650
|
open_discussions[discussion.id] = discussion
|
|
655
651
|
# Creating a closed discussion that shouldn't show up in response.
|
|
@@ -661,7 +657,7 @@ class DiscussionsNotificationsTest(TestCase, DBTestMixin):
|
|
|
661
657
|
title=faker.sentence(),
|
|
662
658
|
discussion=[message],
|
|
663
659
|
closed=datetime.utcnow(),
|
|
664
|
-
closed_by=user
|
|
660
|
+
closed_by=user,
|
|
665
661
|
)
|
|
666
662
|
|
|
667
663
|
notifications = discussions_notifications(owner)
|
|
@@ -669,14 +665,14 @@ class DiscussionsNotificationsTest(TestCase, DBTestMixin):
|
|
|
669
665
|
self.assertEqual(len(notifications), len(open_discussions))
|
|
670
666
|
|
|
671
667
|
for dt, details in notifications:
|
|
672
|
-
discussion = open_discussions[details[
|
|
673
|
-
self.assertEqual(details[
|
|
674
|
-
self.assertEqual(details[
|
|
675
|
-
self.assertEqual(details[
|
|
668
|
+
discussion = open_discussions[details["id"]]
|
|
669
|
+
self.assertEqual(details["title"], discussion.title)
|
|
670
|
+
self.assertEqual(details["subject"]["id"], discussion.subject.id)
|
|
671
|
+
self.assertEqual(details["subject"]["type"], "dataset")
|
|
676
672
|
|
|
677
673
|
def test_notify_org_discussions(self):
|
|
678
674
|
recipient = UserFactory()
|
|
679
|
-
member = Member(user=recipient, role=
|
|
675
|
+
member = Member(user=recipient, role="editor")
|
|
680
676
|
org = OrganizationFactory(members=[member])
|
|
681
677
|
dataset = DatasetFactory(organization=org)
|
|
682
678
|
|
|
@@ -685,10 +681,7 @@ class DiscussionsNotificationsTest(TestCase, DBTestMixin):
|
|
|
685
681
|
user = UserFactory()
|
|
686
682
|
message = Message(content=faker.sentence(), posted_by=user)
|
|
687
683
|
discussion = Discussion.objects.create(
|
|
688
|
-
subject=dataset,
|
|
689
|
-
user=user,
|
|
690
|
-
title=faker.sentence(),
|
|
691
|
-
discussion=[message]
|
|
684
|
+
subject=dataset, user=user, title=faker.sentence(), discussion=[message]
|
|
692
685
|
)
|
|
693
686
|
open_discussions[discussion.id] = discussion
|
|
694
687
|
# Creating a closed discussion that shouldn't show up in response.
|
|
@@ -700,7 +693,7 @@ class DiscussionsNotificationsTest(TestCase, DBTestMixin):
|
|
|
700
693
|
title=faker.sentence(),
|
|
701
694
|
discussion=[message],
|
|
702
695
|
closed=datetime.utcnow(),
|
|
703
|
-
closed_by=user
|
|
696
|
+
closed_by=user,
|
|
704
697
|
)
|
|
705
698
|
|
|
706
699
|
notifications = discussions_notifications(recipient)
|
|
@@ -708,10 +701,10 @@ class DiscussionsNotificationsTest(TestCase, DBTestMixin):
|
|
|
708
701
|
self.assertEqual(len(notifications), len(open_discussions))
|
|
709
702
|
|
|
710
703
|
for dt, details in notifications:
|
|
711
|
-
discussion = open_discussions[details[
|
|
712
|
-
self.assertEqual(details[
|
|
713
|
-
self.assertEqual(details[
|
|
714
|
-
self.assertEqual(details[
|
|
704
|
+
discussion = open_discussions[details["id"]]
|
|
705
|
+
self.assertEqual(details["title"], discussion.title)
|
|
706
|
+
self.assertEqual(details["subject"]["id"], discussion.subject.id)
|
|
707
|
+
self.assertEqual(details["subject"]["type"], "dataset")
|
|
715
708
|
|
|
716
709
|
|
|
717
710
|
class DiscussionsMailsTest(APITestCase):
|
|
@@ -725,7 +718,7 @@ class DiscussionsMailsTest(APITestCase):
|
|
|
725
718
|
subject=DatasetFactory(owner=owner),
|
|
726
719
|
user=user,
|
|
727
720
|
title=faker.sentence(),
|
|
728
|
-
discussion=[message]
|
|
721
|
+
discussion=[message],
|
|
729
722
|
)
|
|
730
723
|
|
|
731
724
|
with capture_mails() as mails:
|
|
@@ -746,7 +739,7 @@ class DiscussionsMailsTest(APITestCase):
|
|
|
746
739
|
subject=DatasetFactory(owner=owner),
|
|
747
740
|
user=poster,
|
|
748
741
|
title=faker.sentence(),
|
|
749
|
-
discussion=[message, second_message, new_message]
|
|
742
|
+
discussion=[message, second_message, new_message],
|
|
750
743
|
)
|
|
751
744
|
|
|
752
745
|
with capture_mails() as mails:
|
|
@@ -772,7 +765,7 @@ class DiscussionsMailsTest(APITestCase):
|
|
|
772
765
|
subject=DatasetFactory(owner=owner),
|
|
773
766
|
user=poster,
|
|
774
767
|
title=faker.sentence(),
|
|
775
|
-
discussion=[message, second_message, closing_message]
|
|
768
|
+
discussion=[message, second_message, closing_message],
|
|
776
769
|
)
|
|
777
770
|
|
|
778
771
|
with capture_mails() as mails:
|