wbcrm 2.2.1__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 wbcrm might be problematic. Click here for more details.
- wbcrm/__init__.py +1 -0
- wbcrm/admin/__init__.py +4 -0
- wbcrm/admin/accounts.py +59 -0
- wbcrm/admin/activities.py +101 -0
- wbcrm/admin/groups.py +7 -0
- wbcrm/admin/products.py +8 -0
- wbcrm/apps.py +5 -0
- wbcrm/configurations/__init__.py +1 -0
- wbcrm/configurations/base.py +16 -0
- wbcrm/dynamic_preferences_registry.py +38 -0
- wbcrm/factories/__init__.py +14 -0
- wbcrm/factories/accounts.py +56 -0
- wbcrm/factories/activities.py +125 -0
- wbcrm/factories/groups.py +23 -0
- wbcrm/factories/products.py +10 -0
- wbcrm/filters/__init__.py +10 -0
- wbcrm/filters/accounts.py +67 -0
- wbcrm/filters/activities.py +181 -0
- wbcrm/filters/groups.py +20 -0
- wbcrm/filters/products.py +37 -0
- wbcrm/filters/signals.py +94 -0
- wbcrm/migrations/0001_initial_squashed_squashed_0032_productcompanyrelationship_alter_product_prospects_and_more.py +3948 -0
- wbcrm/migrations/0002_alter_activity_repeat_choice.py +32 -0
- wbcrm/migrations/0003_remove_activity_external_id_and_more.py +63 -0
- wbcrm/migrations/0004_alter_activity_status.py +28 -0
- wbcrm/migrations/0005_account_accountrole_accountroletype_and_more.py +182 -0
- wbcrm/migrations/0006_alter_activity_location.py +17 -0
- wbcrm/migrations/0007_alter_account_status.py +23 -0
- wbcrm/migrations/0008_alter_activity_options.py +16 -0
- wbcrm/migrations/0009_alter_account_is_public.py +19 -0
- wbcrm/migrations/0010_alter_account_reference_id.py +17 -0
- wbcrm/migrations/0011_activity_summary.py +22 -0
- wbcrm/migrations/0012_alter_activity_summary.py +17 -0
- wbcrm/migrations/0013_account_action_plan_account_relationship_status_and_more.py +34 -0
- wbcrm/migrations/0014_alter_account_relationship_status.py +24 -0
- wbcrm/migrations/0015_alter_activity_type.py +23 -0
- wbcrm/migrations/0016_auto_20241205_1015.py +106 -0
- wbcrm/migrations/__init__.py +0 -0
- wbcrm/models/__init__.py +4 -0
- wbcrm/models/accounts.py +637 -0
- wbcrm/models/activities.py +1335 -0
- wbcrm/models/groups.py +118 -0
- wbcrm/models/products.py +83 -0
- wbcrm/models/recurrence.py +279 -0
- wbcrm/preferences.py +14 -0
- wbcrm/serializers/__init__.py +23 -0
- wbcrm/serializers/accounts.py +126 -0
- wbcrm/serializers/activities.py +526 -0
- wbcrm/serializers/groups.py +30 -0
- wbcrm/serializers/products.py +57 -0
- wbcrm/serializers/recurrence.py +90 -0
- wbcrm/serializers/signals.py +70 -0
- wbcrm/synchronization/__init__.py +0 -0
- wbcrm/synchronization/activity/__init__.py +0 -0
- wbcrm/synchronization/activity/admin.py +72 -0
- wbcrm/synchronization/activity/backend.py +207 -0
- wbcrm/synchronization/activity/backends/__init__.py +0 -0
- wbcrm/synchronization/activity/backends/google/__init__.py +2 -0
- wbcrm/synchronization/activity/backends/google/google_calendar_backend.py +399 -0
- wbcrm/synchronization/activity/backends/google/request_utils/__init__.py +16 -0
- wbcrm/synchronization/activity/backends/google/tasks.py +21 -0
- wbcrm/synchronization/activity/backends/google/tests/__init__.py +0 -0
- wbcrm/synchronization/activity/backends/google/tests/conftest.py +1 -0
- wbcrm/synchronization/activity/backends/google/tests/test_data.py +81 -0
- wbcrm/synchronization/activity/backends/google/tests/test_google_backend.py +319 -0
- wbcrm/synchronization/activity/backends/google/tests/test_utils.py +274 -0
- wbcrm/synchronization/activity/backends/google/typing_informations.py +139 -0
- wbcrm/synchronization/activity/backends/google/utils.py +216 -0
- wbcrm/synchronization/activity/backends/outlook/__init__.py +0 -0
- wbcrm/synchronization/activity/backends/outlook/backend.py +576 -0
- wbcrm/synchronization/activity/backends/outlook/msgraph.py +438 -0
- wbcrm/synchronization/activity/backends/outlook/parser.py +423 -0
- wbcrm/synchronization/activity/backends/outlook/tests/__init__.py +0 -0
- wbcrm/synchronization/activity/backends/outlook/tests/conftest.py +1 -0
- wbcrm/synchronization/activity/backends/outlook/tests/fixtures.py +606 -0
- wbcrm/synchronization/activity/backends/outlook/tests/test_admin.py +117 -0
- wbcrm/synchronization/activity/backends/outlook/tests/test_backend.py +269 -0
- wbcrm/synchronization/activity/backends/outlook/tests/test_controller.py +237 -0
- wbcrm/synchronization/activity/backends/outlook/tests/test_parser.py +173 -0
- wbcrm/synchronization/activity/controller.py +545 -0
- wbcrm/synchronization/activity/dynamic_preferences_registry.py +107 -0
- wbcrm/synchronization/activity/preferences.py +21 -0
- wbcrm/synchronization/activity/shortcuts.py +9 -0
- wbcrm/synchronization/activity/signals.py +28 -0
- wbcrm/synchronization/activity/tasks.py +21 -0
- wbcrm/synchronization/activity/urls.py +6 -0
- wbcrm/synchronization/activity/utils.py +46 -0
- wbcrm/synchronization/activity/views.py +37 -0
- wbcrm/synchronization/admin.py +1 -0
- wbcrm/synchronization/apps.py +15 -0
- wbcrm/synchronization/dynamic_preferences_registry.py +1 -0
- wbcrm/synchronization/management.py +36 -0
- wbcrm/synchronization/tasks.py +1 -0
- wbcrm/synchronization/urls.py +5 -0
- wbcrm/tasks.py +312 -0
- wbcrm/tests/__init__.py +0 -0
- wbcrm/tests/accounts/__init__.py +0 -0
- wbcrm/tests/accounts/test_models.py +380 -0
- wbcrm/tests/accounts/test_viewsets.py +87 -0
- wbcrm/tests/conftest.py +76 -0
- wbcrm/tests/disable_signals.py +52 -0
- wbcrm/tests/e2e/__init__.py +1 -0
- wbcrm/tests/e2e/e2e_wbcrm_utility.py +82 -0
- wbcrm/tests/e2e/test_e2e.py +369 -0
- wbcrm/tests/test_assignee_methods.py +39 -0
- wbcrm/tests/test_chartviewsets.py +111 -0
- wbcrm/tests/test_dto.py +63 -0
- wbcrm/tests/test_filters.py +51 -0
- wbcrm/tests/test_models.py +216 -0
- wbcrm/tests/test_recurrence.py +291 -0
- wbcrm/tests/test_report.py +20 -0
- wbcrm/tests/test_serializers.py +170 -0
- wbcrm/tests/test_tasks.py +94 -0
- wbcrm/tests/test_viewsets.py +967 -0
- wbcrm/tests/tests.py +120 -0
- wbcrm/typings.py +107 -0
- wbcrm/urls.py +67 -0
- wbcrm/viewsets/__init__.py +22 -0
- wbcrm/viewsets/accounts.py +121 -0
- wbcrm/viewsets/activities.py +315 -0
- wbcrm/viewsets/buttons/__init__.py +7 -0
- wbcrm/viewsets/buttons/accounts.py +27 -0
- wbcrm/viewsets/buttons/activities.py +68 -0
- wbcrm/viewsets/buttons/signals.py +17 -0
- wbcrm/viewsets/display/__init__.py +12 -0
- wbcrm/viewsets/display/accounts.py +110 -0
- wbcrm/viewsets/display/activities.py +443 -0
- wbcrm/viewsets/display/groups.py +22 -0
- wbcrm/viewsets/display/products.py +105 -0
- wbcrm/viewsets/endpoints/__init__.py +8 -0
- wbcrm/viewsets/endpoints/accounts.py +32 -0
- wbcrm/viewsets/endpoints/activities.py +30 -0
- wbcrm/viewsets/endpoints/groups.py +7 -0
- wbcrm/viewsets/endpoints/products.py +9 -0
- wbcrm/viewsets/groups.py +37 -0
- wbcrm/viewsets/menu/__init__.py +8 -0
- wbcrm/viewsets/menu/accounts.py +18 -0
- wbcrm/viewsets/menu/activities.py +61 -0
- wbcrm/viewsets/menu/groups.py +16 -0
- wbcrm/viewsets/menu/products.py +20 -0
- wbcrm/viewsets/mixins.py +34 -0
- wbcrm/viewsets/previews/__init__.py +1 -0
- wbcrm/viewsets/previews/activities.py +10 -0
- wbcrm/viewsets/products.py +56 -0
- wbcrm/viewsets/recurrence.py +26 -0
- wbcrm/viewsets/titles/__init__.py +13 -0
- wbcrm/viewsets/titles/accounts.py +22 -0
- wbcrm/viewsets/titles/activities.py +61 -0
- wbcrm/viewsets/titles/products.py +13 -0
- wbcrm/viewsets/titles/utils.py +46 -0
- wbcrm/workflows/__init__.py +1 -0
- wbcrm/workflows/assignee_methods.py +25 -0
- wbcrm-2.2.1.dist-info/METADATA +11 -0
- wbcrm-2.2.1.dist-info/RECORD +155 -0
- wbcrm-2.2.1.dist-info/WHEEL +5 -0
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
from unittest.mock import patch
|
|
2
|
+
|
|
3
|
+
import pytest
|
|
4
|
+
from django.contrib.admin import AdminSite
|
|
5
|
+
from django.contrib.auth import get_user_model
|
|
6
|
+
from django.contrib.messages import get_messages
|
|
7
|
+
from dynamic_preferences.registries import global_preferences_registry
|
|
8
|
+
from rest_framework import status
|
|
9
|
+
from wbcore.contrib.authentication.factories import UserFactory
|
|
10
|
+
from wbcrm.synchronization.activity.admin import UserSyncAdmin
|
|
11
|
+
|
|
12
|
+
from .fixtures import TestOutlookSyncFixture, msgraph_fixture
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@pytest.mark.parametrize(
|
|
16
|
+
"backend, credentials, subscription, tenant_id",
|
|
17
|
+
[
|
|
18
|
+
(False, True, {"id": "fake_id"}, "fake_tenant_id"),
|
|
19
|
+
(True, False, None, None),
|
|
20
|
+
(True, True, None, None),
|
|
21
|
+
(True, True, {"id": "fake_id"}, None),
|
|
22
|
+
(True, True, {"id": "fake_id"}, "fake_tenant_id"),
|
|
23
|
+
],
|
|
24
|
+
)
|
|
25
|
+
@patch("wbcrm.synchronization.activity.backends.outlook.backend.MicrosoftGraphAPI")
|
|
26
|
+
@pytest.mark.django_db
|
|
27
|
+
class TestAdminUserWebhook(TestOutlookSyncFixture):
|
|
28
|
+
def _initialiation(self, mock_msgraph, backend, credentials, subscription, tenant_id, credentials_fixture):
|
|
29
|
+
preferences = global_preferences_registry.manager()
|
|
30
|
+
preferences["wbactivity_sync__sync_backend_calendar"] = preferences[
|
|
31
|
+
"wbactivity_sync__outlook_sync_credentials"
|
|
32
|
+
] = ""
|
|
33
|
+
if backend:
|
|
34
|
+
preferences[
|
|
35
|
+
"wbactivity_sync__sync_backend_calendar"
|
|
36
|
+
] = "wbcrm.synchronization.activity.backends.outlook.backend.OutlookSyncBackend"
|
|
37
|
+
mock_msgraph.return_value.status_code = status.HTTP_200_OK
|
|
38
|
+
mock_msgraph.return_value = msgraph_fixture()
|
|
39
|
+
if credentials:
|
|
40
|
+
preferences["wbactivity_sync__outlook_sync_credentials"] = credentials_fixture
|
|
41
|
+
msgraph_fixture._subscription = subscription
|
|
42
|
+
msgraph_fixture.tenant_id = tenant_id
|
|
43
|
+
else:
|
|
44
|
+
mock_msgraph.side_effect = AssertionError("Invalid URL")
|
|
45
|
+
user = UserFactory(is_superuser=True)
|
|
46
|
+
if subscription:
|
|
47
|
+
user.metadata = {"outlook": {"subscription": subscription}}
|
|
48
|
+
user.save()
|
|
49
|
+
return user
|
|
50
|
+
|
|
51
|
+
def test_set_web_hook(
|
|
52
|
+
self, mock_msgraph, backend, credentials, subscription, tenant_id, fixture_request, credentials_fixture
|
|
53
|
+
):
|
|
54
|
+
user = self._initialiation(mock_msgraph, backend, credentials, subscription, tenant_id, credentials_fixture)
|
|
55
|
+
fixture_request.user = user
|
|
56
|
+
assert len([m.message for m in get_messages(fixture_request)]) == 0
|
|
57
|
+
user_admin = UserSyncAdmin(UserFactory, AdminSite())
|
|
58
|
+
user_admin.set_web_hook(fixture_request, get_user_model().objects.filter(id=user.id))
|
|
59
|
+
messages = [m.message for m in get_messages(fixture_request)]
|
|
60
|
+
assert len(messages) == 1
|
|
61
|
+
if backend:
|
|
62
|
+
if credentials:
|
|
63
|
+
if subscription or tenant_id:
|
|
64
|
+
assert "Operation completed" in messages[0]
|
|
65
|
+
else:
|
|
66
|
+
assert messages[0] == f"Operation Failed, Outlook TenantId not found for: {user}"
|
|
67
|
+
else:
|
|
68
|
+
assert "Operation Failed, Invalid URL" in messages[0]
|
|
69
|
+
else:
|
|
70
|
+
assert messages[0] == "Operation Failed, No backend set in preferences"
|
|
71
|
+
|
|
72
|
+
def test_stop_web_hook(
|
|
73
|
+
self, mock_msgraph, backend, credentials, subscription, tenant_id, fixture_request, credentials_fixture
|
|
74
|
+
):
|
|
75
|
+
user = self._initialiation(mock_msgraph, backend, credentials, subscription, tenant_id, credentials_fixture)
|
|
76
|
+
fixture_request.user = user
|
|
77
|
+
assert len([m.message for m in get_messages(fixture_request)]) == 0
|
|
78
|
+
user_admin = UserSyncAdmin(UserFactory, AdminSite())
|
|
79
|
+
user_admin.stop_web_hook(fixture_request, get_user_model().objects.filter(id=user.id))
|
|
80
|
+
messages = [m.message for m in get_messages(fixture_request)]
|
|
81
|
+
assert len(messages) == 1
|
|
82
|
+
if backend:
|
|
83
|
+
if subscription:
|
|
84
|
+
if credentials:
|
|
85
|
+
assert "Operation completed" in messages[0]
|
|
86
|
+
else:
|
|
87
|
+
assert "Operation Failed, Invalid URL" in messages[0]
|
|
88
|
+
else:
|
|
89
|
+
assert f"Operation Failed, {user} has no active webhook"
|
|
90
|
+
else:
|
|
91
|
+
assert messages[0] == "Operation Failed, No backend set in preferences"
|
|
92
|
+
|
|
93
|
+
def test_check_web_hook(
|
|
94
|
+
self, mock_msgraph, backend, credentials, subscription, tenant_id, fixture_request, credentials_fixture
|
|
95
|
+
):
|
|
96
|
+
user = self._initialiation(mock_msgraph, backend, credentials, subscription, tenant_id, credentials_fixture)
|
|
97
|
+
fixture_request.user = user
|
|
98
|
+
assert len([m.message for m in get_messages(fixture_request)]) == 0
|
|
99
|
+
user_admin = UserSyncAdmin(UserFactory, AdminSite())
|
|
100
|
+
user_admin.check_web_hook(fixture_request, get_user_model().objects.filter(id=user.id))
|
|
101
|
+
messages = [m.message for m in get_messages(fixture_request)]
|
|
102
|
+
assert len(messages) == 1
|
|
103
|
+
if backend:
|
|
104
|
+
if credentials:
|
|
105
|
+
if subscription:
|
|
106
|
+
assert "Operation completed" in messages[0]
|
|
107
|
+
elif tenant_id:
|
|
108
|
+
assert (
|
|
109
|
+
"Operation Failed, Webhook not found. Number of subscriptions found in outlook for"
|
|
110
|
+
in messages[0]
|
|
111
|
+
)
|
|
112
|
+
else:
|
|
113
|
+
assert messages[0] == f"Operation Failed, Webhook not found. TenantId not found for {user}"
|
|
114
|
+
else:
|
|
115
|
+
assert "Operation Failed, Invalid URL" in messages[0]
|
|
116
|
+
else:
|
|
117
|
+
assert messages[0] == "Operation Failed, No backend set in preferences"
|
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
import json
|
|
2
|
+
from unittest.mock import patch
|
|
3
|
+
|
|
4
|
+
import pytest
|
|
5
|
+
from dynamic_preferences.registries import global_preferences_registry
|
|
6
|
+
from rest_framework.test import APIRequestFactory
|
|
7
|
+
from wbcore.contrib.authentication.factories import UserFactory
|
|
8
|
+
from wbcrm.models.activities import Activity
|
|
9
|
+
from wbcrm.synchronization.activity.backends.outlook.backend import OutlookSyncBackend
|
|
10
|
+
|
|
11
|
+
from .fixtures import TestOutlookSyncFixture, msgraph_fixture
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@pytest.mark.django_db
|
|
15
|
+
class TestOutlookSyncBackend(TestOutlookSyncFixture):
|
|
16
|
+
backend = OutlookSyncBackend()
|
|
17
|
+
|
|
18
|
+
def test_attribute(self):
|
|
19
|
+
assert OutlookSyncBackend.METADATA_KEY == "outlook"
|
|
20
|
+
|
|
21
|
+
def test_open(self):
|
|
22
|
+
preferences = global_preferences_registry.manager()
|
|
23
|
+
preferences["wbactivity_sync__outlook_sync_credentials"] = ""
|
|
24
|
+
assert hasattr(self.backend, "msgraph") is False
|
|
25
|
+
self.backend.open()
|
|
26
|
+
assert self.backend.msgraph
|
|
27
|
+
|
|
28
|
+
@pytest.mark.parametrize("type_request", [None, "validationToken", "admin_consent"])
|
|
29
|
+
def test_validation_response(self, type_request):
|
|
30
|
+
request1 = APIRequestFactory().get("")
|
|
31
|
+
if type_request:
|
|
32
|
+
request1.GET = request1.GET.copy()
|
|
33
|
+
request1.GET[type_request] = "fake_info"
|
|
34
|
+
assert self.backend._validation_response(request1).content.decode("UTF-8") == "fake_info"
|
|
35
|
+
else:
|
|
36
|
+
assert self.backend._validation_response(request1) is None
|
|
37
|
+
|
|
38
|
+
@pytest.mark.parametrize("client_state", [False, True])
|
|
39
|
+
def test_is_inbound_request_valid(
|
|
40
|
+
self, client_state, notification_created_fixture, notification_call_record_fixture
|
|
41
|
+
):
|
|
42
|
+
api_factory = APIRequestFactory()
|
|
43
|
+
request1 = api_factory.post("", data={})
|
|
44
|
+
request2 = api_factory.post(
|
|
45
|
+
"", data=json.dumps({"value": [notification_call_record_fixture]}), content_type="application/json"
|
|
46
|
+
)
|
|
47
|
+
request3 = api_factory.post(
|
|
48
|
+
"", data=json.dumps({"value": [notification_created_fixture]}), content_type="application/json"
|
|
49
|
+
)
|
|
50
|
+
preferences = global_preferences_registry.manager()
|
|
51
|
+
preferences["wbactivity_sync__outlook_sync_client_state"] = ""
|
|
52
|
+
if client_state:
|
|
53
|
+
preferences["wbactivity_sync__outlook_sync_client_state"] = notification_created_fixture["client_state"]
|
|
54
|
+
|
|
55
|
+
assert self.backend._is_inbound_request_valid(request1) is False
|
|
56
|
+
assert self.backend._is_inbound_request_valid(request2) is False
|
|
57
|
+
assert self.backend._is_inbound_request_valid(request3) == client_state
|
|
58
|
+
|
|
59
|
+
@pytest.mark.parametrize("event_found, is_organizer", [(False, True), (True, True), (True, False)])
|
|
60
|
+
@patch("wbcrm.synchronization.activity.backends.outlook.backend.MicrosoftGraphAPI")
|
|
61
|
+
def test_get_events_from_request(
|
|
62
|
+
self,
|
|
63
|
+
mock_msgraph,
|
|
64
|
+
event_found,
|
|
65
|
+
is_organizer,
|
|
66
|
+
notification_created_fixture,
|
|
67
|
+
organizer_event_fixture_parsed,
|
|
68
|
+
invitation_event_fixture_parsed,
|
|
69
|
+
):
|
|
70
|
+
api_factory = APIRequestFactory()
|
|
71
|
+
request1 = api_factory.post(
|
|
72
|
+
"", data=json.dumps({"value": [notification_created_fixture]}), content_type="application/json"
|
|
73
|
+
)
|
|
74
|
+
self.backend.open()
|
|
75
|
+
self.backend.msgraph = msgraph_fixture()
|
|
76
|
+
if event_found:
|
|
77
|
+
if is_organizer:
|
|
78
|
+
msgraph_fixture.event = organizer_event_fixture_parsed
|
|
79
|
+
msgraph_fixture.tenant_id = "fake_tenant_id"
|
|
80
|
+
else:
|
|
81
|
+
msgraph_fixture.event = invitation_event_fixture_parsed
|
|
82
|
+
msgraph_fixture.event_by_uid = organizer_event_fixture_parsed
|
|
83
|
+
events = self.backend._get_events_from_request(request1)
|
|
84
|
+
assert len(events) == 1
|
|
85
|
+
if event_found:
|
|
86
|
+
assert {"change_type", "resource", "subscription_id"}.issubset(set(events[0].keys()))
|
|
87
|
+
assert events[0].get("id")
|
|
88
|
+
else:
|
|
89
|
+
assert {"change_type", "resource", "subscription_id"} == set(events[0].keys())
|
|
90
|
+
|
|
91
|
+
def test_deserialize(self, organizer_event_fixture_parsed, organizer_master_event_fixture_parsed):
|
|
92
|
+
activity_dto0, is_deleted0, user_dto0 = self.backend._deserialize(
|
|
93
|
+
organizer_event_fixture_parsed, include_metadata=False
|
|
94
|
+
)
|
|
95
|
+
activity_dto, is_deleted, user_dto = self.backend._deserialize(organizer_event_fixture_parsed)
|
|
96
|
+
activity_dto2, is_deleted2, user_dto2 = self.backend._deserialize(organizer_master_event_fixture_parsed)
|
|
97
|
+
|
|
98
|
+
assert is_deleted0 == is_deleted == is_deleted2 is False
|
|
99
|
+
assert user_dto0 == user_dto == user_dto2 is None
|
|
100
|
+
assert activity_dto0.metadata == {}
|
|
101
|
+
assert activity_dto.metadata == {
|
|
102
|
+
self.backend.METADATA_KEY: {
|
|
103
|
+
"event_uid": organizer_event_fixture_parsed["uid"],
|
|
104
|
+
"event_id": organizer_event_fixture_parsed["id"],
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
assert activity_dto2.metadata == {
|
|
108
|
+
self.backend.METADATA_KEY: {
|
|
109
|
+
"event_uid": organizer_master_event_fixture_parsed["uid"],
|
|
110
|
+
"event_id": organizer_master_event_fixture_parsed["id"],
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
assert activity_dto.period
|
|
114
|
+
assert activity_dto.repeat_choice == "NEVER"
|
|
115
|
+
assert activity_dto2.repeat_choice != "NEVER"
|
|
116
|
+
|
|
117
|
+
def test_serialize(self, activity_factory):
|
|
118
|
+
activity_dto = activity_factory(preceded_by=None)._build_dto()
|
|
119
|
+
act_dto = activity_factory(
|
|
120
|
+
repeat_choice=Activity.ReoccuranceChoice.DAILY, recurrence_count=3, preceded_by=None
|
|
121
|
+
)._build_dto()
|
|
122
|
+
activity_dict = self.backend._serialize(activity_dto)
|
|
123
|
+
activity_dict1 = self.backend._serialize(activity_dto, created=True)
|
|
124
|
+
act_dict = self.backend._serialize(act_dto)
|
|
125
|
+
act_dict1 = self.backend._serialize(act_dto, created=True)
|
|
126
|
+
keys = {
|
|
127
|
+
"subject",
|
|
128
|
+
"start",
|
|
129
|
+
"end",
|
|
130
|
+
"body",
|
|
131
|
+
"attendees",
|
|
132
|
+
"sensitivity",
|
|
133
|
+
"isReminderOn",
|
|
134
|
+
"reminderMinutesBeforeStart",
|
|
135
|
+
"isAllDay",
|
|
136
|
+
"responseRequested",
|
|
137
|
+
"location",
|
|
138
|
+
"locations",
|
|
139
|
+
}
|
|
140
|
+
assert set(activity_dict.keys()) == set(act_dict.keys()) == set(activity_dict1.keys()) == keys
|
|
141
|
+
assert set(act_dict1.keys()) == keys.union({"recurrence"})
|
|
142
|
+
|
|
143
|
+
@pytest.mark.parametrize(
|
|
144
|
+
"metadata, master_event",
|
|
145
|
+
[
|
|
146
|
+
({}, False),
|
|
147
|
+
({}, True),
|
|
148
|
+
({"organizer_resource": "fake_resource"}, False),
|
|
149
|
+
({"organizer_resource": "fake_resource"}, True),
|
|
150
|
+
({"event_id": "fake_event_id"}, False),
|
|
151
|
+
({"event_id": "fake_event_id"}, True),
|
|
152
|
+
({"event_uid": "fake_event_uid"}, False),
|
|
153
|
+
({"event_uid": "fake_event_uid"}, True),
|
|
154
|
+
({"occurrence_resource": "fake_resource"}, False),
|
|
155
|
+
({"occurrence_resource": "fake_resource"}, True),
|
|
156
|
+
({"occurrence_id": "fake_occurrence_id"}, False),
|
|
157
|
+
({"occurrence_id": "fake_occurrence_id"}, True),
|
|
158
|
+
],
|
|
159
|
+
)
|
|
160
|
+
def test_get_external_event(self, metadata, master_event, activity_factory):
|
|
161
|
+
activity_dto = activity_factory(preceded_by=None)._build_dto()
|
|
162
|
+
activity_dto2 = activity_factory(preceded_by=None, metadata={self.backend.METADATA_KEY: metadata})._build_dto()
|
|
163
|
+
self.backend.open()
|
|
164
|
+
self.backend.msgraph = msgraph_fixture()
|
|
165
|
+
msgraph_fixture.tenant_id = "fake_tenant_id"
|
|
166
|
+
msgraph_fixture.event_by_uid = msgraph_fixture.event = {"id": "event_id"}
|
|
167
|
+
assert (
|
|
168
|
+
self.backend.get_external_event(activity_dto, master_event)
|
|
169
|
+
== self.backend.get_external_event(activity_dto, master_event)
|
|
170
|
+
is None
|
|
171
|
+
)
|
|
172
|
+
if metadata:
|
|
173
|
+
event_result = self.backend.get_external_event(activity_dto2, master_event)
|
|
174
|
+
if master_event or not activity_dto2.is_recurrent:
|
|
175
|
+
if metadata.get("event_uid") or metadata.get("event_id") or metadata.get("organizer_resource"):
|
|
176
|
+
assert event_result == {"id": "event_id"}
|
|
177
|
+
else:
|
|
178
|
+
assert event_result is None
|
|
179
|
+
else:
|
|
180
|
+
if metadata.get("occurrence_resource") or metadata.get("occurrence_id"):
|
|
181
|
+
assert event_result == {"id": "event_id"}
|
|
182
|
+
else:
|
|
183
|
+
assert event_result is None
|
|
184
|
+
else:
|
|
185
|
+
assert self.backend.get_external_event(activity_dto2, master_event) is None
|
|
186
|
+
|
|
187
|
+
def test_get_external_participants(self, activity_factory, person_factory):
|
|
188
|
+
person = person_factory()
|
|
189
|
+
activity_dto = activity_factory(preceded_by=None, participants=(person,))._build_dto()
|
|
190
|
+
activity_dto2 = activity_factory(
|
|
191
|
+
preceded_by=None,
|
|
192
|
+
participants=(person,),
|
|
193
|
+
metadata={self.backend.METADATA_KEY: {"organizer_resource": "fake_resource"}},
|
|
194
|
+
)._build_dto()
|
|
195
|
+
self.backend.open()
|
|
196
|
+
self.backend.msgraph = msgraph_fixture()
|
|
197
|
+
msgraph_fixture.tenant_id = "fake_tenant_id"
|
|
198
|
+
msgraph_fixture.event_by_uid = msgraph_fixture.event = {
|
|
199
|
+
"id": "event_id",
|
|
200
|
+
"attendees": [{"emailAddress": {"address": person._build_dto().email}}],
|
|
201
|
+
}
|
|
202
|
+
assert len(self.backend.get_external_participants(activity_dto, [])) == 0
|
|
203
|
+
assert len(self.backend.get_external_participants(activity_dto2, [])) == 1
|
|
204
|
+
assert len(self.backend.get_external_participants(activity_dto2, activity_dto2.participants)) == 0
|
|
205
|
+
|
|
206
|
+
@patch("wbcrm.synchronization.activity.backends.outlook.backend.MicrosoftGraphAPI")
|
|
207
|
+
def test_is_participant_valid(self, mock_msgraph):
|
|
208
|
+
user = UserFactory(is_superuser=True)
|
|
209
|
+
user2 = UserFactory(is_superuser=True)
|
|
210
|
+
user2.metadata = {self.backend.METADATA_KEY: {"subscription": {"id": "fake_subscription_id"}}}
|
|
211
|
+
user2.save()
|
|
212
|
+
msgraph_fixture._subscription = {"id": "fake_subscription_id"}
|
|
213
|
+
mock_msgraph.return_value = msgraph_fixture()
|
|
214
|
+
assert self.backend._is_participant_valid(user2) is True
|
|
215
|
+
assert self.backend._is_participant_valid(user) is False
|
|
216
|
+
|
|
217
|
+
def test_generate_event_metadata(self):
|
|
218
|
+
event = {"id": "fake_id", "uid": "fake_uid"}
|
|
219
|
+
occurrence_event = {"id": "fake_id", "uid": "fake_uid"}
|
|
220
|
+
resource = f"Users/fake_tenant_id/Events/{event['id']}"
|
|
221
|
+
result = {
|
|
222
|
+
"resources": [resource],
|
|
223
|
+
"organizer_resource": resource,
|
|
224
|
+
"event_uid": event["uid"],
|
|
225
|
+
"event_id": event["id"],
|
|
226
|
+
}
|
|
227
|
+
metadata = self.backend._generate_event_metadata("fake_tenant_id", event)
|
|
228
|
+
metadata2 = self.backend._generate_event_metadata("fake_tenant_id", event, occurrence_event)
|
|
229
|
+
assert metadata == {self.backend.METADATA_KEY: result}
|
|
230
|
+
assert metadata2 == {
|
|
231
|
+
self.backend.METADATA_KEY: {**result, **{"occurrence_id": event["id"], "occurrence_resource": resource}}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
def test_get_metadata_from_event(
|
|
235
|
+
self, activity_factory, organizer_event_fixture_parsed, organizer_master_event_fixture_parsed
|
|
236
|
+
):
|
|
237
|
+
self.backend.open()
|
|
238
|
+
self.backend.msgraph = msgraph_fixture()
|
|
239
|
+
msgraph_fixture.tenant_id = "fake_tenant_id"
|
|
240
|
+
activity_dto = activity_factory(preceded_by=None)._build_dto()
|
|
241
|
+
metadata_list = self.backend._get_metadata_from_event(activity_dto, organizer_event_fixture_parsed)
|
|
242
|
+
# self.backend._get_metadata_from_event()
|
|
243
|
+
resource = f"Users/fake_tenant_id/Events/{organizer_event_fixture_parsed['id']}"
|
|
244
|
+
assert len(metadata_list) == 1
|
|
245
|
+
assert metadata_list[0][0] == activity_dto
|
|
246
|
+
assert metadata_list[0][1] == {
|
|
247
|
+
self.backend.METADATA_KEY: {
|
|
248
|
+
"resources": [resource],
|
|
249
|
+
"organizer_resource": resource,
|
|
250
|
+
"event_uid": organizer_event_fixture_parsed["uid"],
|
|
251
|
+
"event_id": organizer_event_fixture_parsed["id"],
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
@patch("wbcrm.synchronization.activity.backends.outlook.backend.MicrosoftGraphAPI")
|
|
256
|
+
def test_renew_web_hooks(self, mock_msgraph):
|
|
257
|
+
msgraph_fixture._subscription = {"id": "fake_id_new"}
|
|
258
|
+
mock_msgraph.return_value = msgraph_fixture()
|
|
259
|
+
|
|
260
|
+
user1 = UserFactory(is_superuser=True)
|
|
261
|
+
user2 = UserFactory(is_superuser=True)
|
|
262
|
+
user2.metadata = {self.backend.METADATA_KEY: {"subscription": {"id": "fake_id"}}}
|
|
263
|
+
user2.save()
|
|
264
|
+
|
|
265
|
+
self.backend.renew_web_hooks()
|
|
266
|
+
user1.refresh_from_db()
|
|
267
|
+
user2.refresh_from_db()
|
|
268
|
+
assert user1.metadata == {}
|
|
269
|
+
assert user2.metadata == {self.backend.METADATA_KEY: {"subscription": {"id": "fake_id_new"}}}
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
import itertools
|
|
2
|
+
import json
|
|
3
|
+
from unittest.mock import patch
|
|
4
|
+
|
|
5
|
+
import pytest
|
|
6
|
+
from django.contrib.auth import get_user_model
|
|
7
|
+
from django.contrib.auth.models import Permission
|
|
8
|
+
from django.contrib.contenttypes.models import ContentType
|
|
9
|
+
from dynamic_preferences.registries import global_preferences_registry
|
|
10
|
+
from rest_framework.test import APIRequestFactory
|
|
11
|
+
from wbcore.permissions.registry import user_registry
|
|
12
|
+
from wbcrm.factories import ActivityFactory
|
|
13
|
+
from wbcrm.models import Activity, ActivityParticipant
|
|
14
|
+
from wbcrm.synchronization.activity.controller import ActivityController
|
|
15
|
+
from wbcrm.typings import User as UserDTO
|
|
16
|
+
|
|
17
|
+
from .fixtures import TestOutlookSyncFixture, msgraph_fixture
|
|
18
|
+
|
|
19
|
+
User = get_user_model()
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
@pytest.mark.django_db
|
|
23
|
+
class TestInitController:
|
|
24
|
+
def test_init(self):
|
|
25
|
+
global_preferences_registry.manager()["wbactivity_sync__sync_backend_calendar"] = ""
|
|
26
|
+
controller = ActivityController()
|
|
27
|
+
assert controller.backend is None
|
|
28
|
+
|
|
29
|
+
global_preferences_registry.manager()[
|
|
30
|
+
"wbactivity_sync__sync_backend_calendar"
|
|
31
|
+
] = "wbcrm.synchronization.activity.backends.outlook.backend.OutlookSyncBackend"
|
|
32
|
+
controller2 = ActivityController()
|
|
33
|
+
assert controller2.backend
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
@pytest.mark.django_db
|
|
37
|
+
class TestController(TestOutlookSyncFixture):
|
|
38
|
+
def setup_method(self):
|
|
39
|
+
global_preferences_registry.manager()[
|
|
40
|
+
"wbactivity_sync__sync_backend_calendar"
|
|
41
|
+
] = "wbcrm.synchronization.activity.backends.outlook.backend.OutlookSyncBackend"
|
|
42
|
+
|
|
43
|
+
@pytest.fixture()
|
|
44
|
+
@patch("wbcrm.synchronization.activity.backends.outlook.backend.MicrosoftGraphAPI")
|
|
45
|
+
def controller(self, mock_msgraph):
|
|
46
|
+
controller = ActivityController()
|
|
47
|
+
controller.backend.open()
|
|
48
|
+
controller.backend.msgraph = msgraph_fixture()
|
|
49
|
+
return controller
|
|
50
|
+
|
|
51
|
+
def test_init(self):
|
|
52
|
+
controller = ActivityController()
|
|
53
|
+
assert controller.backend
|
|
54
|
+
|
|
55
|
+
@pytest.mark.parametrize("type_request", [None, "validationToken", "admin_consent"])
|
|
56
|
+
def test_handle_inbound_validation_response(self, controller, type_request):
|
|
57
|
+
request1 = APIRequestFactory().get("")
|
|
58
|
+
if type_request:
|
|
59
|
+
request1.GET = request1.GET.copy()
|
|
60
|
+
request1.GET[type_request] = "fake_info"
|
|
61
|
+
assert controller.handle_inbound_validation_response(request1).content.decode("UTF-8") == "fake_info"
|
|
62
|
+
else:
|
|
63
|
+
assert controller.handle_inbound_validation_response(request1) is None
|
|
64
|
+
|
|
65
|
+
@pytest.mark.parametrize("client_state", ["secret1", "secret2"])
|
|
66
|
+
@patch("wbcrm.synchronization.activity.backends.outlook.backend.MicrosoftGraphAPI")
|
|
67
|
+
def test_get_events_from_inbound_request(
|
|
68
|
+
self, mock_msgraph, controller, client_state, notification_fixture, teams_event_fixture
|
|
69
|
+
):
|
|
70
|
+
notification_fixture["client_state"] = client_state
|
|
71
|
+
global_preferences_registry.manager()["wbactivity_sync__outlook_sync_client_state"] = "secret2"
|
|
72
|
+
api_factory = APIRequestFactory()
|
|
73
|
+
request1 = api_factory.post("", data={})
|
|
74
|
+
request2 = api_factory.post(
|
|
75
|
+
"", data=json.dumps({"value": [notification_fixture]}), content_type="application/json"
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
mock_msgraph.return_value = controller.backend.msgraph
|
|
79
|
+
controller.backend.msgraph.event = teams_event_fixture
|
|
80
|
+
controller.backend.msgraph.event_by_uid = teams_event_fixture
|
|
81
|
+
events1 = controller.get_events_from_inbound_request(request1)
|
|
82
|
+
events2 = controller.get_events_from_inbound_request(request2)
|
|
83
|
+
assert events1 == []
|
|
84
|
+
if client_state != global_preferences_registry.manager()["wbactivity_sync__outlook_sync_client_state"]:
|
|
85
|
+
assert events1 == events2 == []
|
|
86
|
+
else:
|
|
87
|
+
assert events1 == []
|
|
88
|
+
assert len(events2) == 1
|
|
89
|
+
expected_result = {
|
|
90
|
+
"change_type": notification_fixture["change_type"],
|
|
91
|
+
"resource": notification_fixture["resource"],
|
|
92
|
+
"subscription_id": notification_fixture["subscription_id"],
|
|
93
|
+
"organizer_resource": notification_fixture["resource"],
|
|
94
|
+
**teams_event_fixture,
|
|
95
|
+
}
|
|
96
|
+
assert set(events2[0].keys()) == set(expected_result.keys())
|
|
97
|
+
|
|
98
|
+
@patch("wbcrm.synchronization.activity.backends.outlook.backend.MicrosoftGraphAPI")
|
|
99
|
+
def test_user_for_handle_inbound(
|
|
100
|
+
self, mock_msgraph, controller, notification_fixture, teams_event_fixture, user_factory
|
|
101
|
+
):
|
|
102
|
+
event = {
|
|
103
|
+
"change_type": notification_fixture["change_type"],
|
|
104
|
+
"resource": notification_fixture["resource"],
|
|
105
|
+
"subscription_id": notification_fixture["subscription_id"],
|
|
106
|
+
**teams_event_fixture,
|
|
107
|
+
}
|
|
108
|
+
metadata = {"outlook": {"subscription": {"id": notification_fixture["subscription_id"]}}}
|
|
109
|
+
_, _, user_dto = controller.backend._deserialize(event)
|
|
110
|
+
user_result = UserDTO(metadata=metadata, id=None)
|
|
111
|
+
assert user_dto.id is None
|
|
112
|
+
assert user_dto.metadata == user_result.metadata
|
|
113
|
+
|
|
114
|
+
assert controller.get_activity_participant(user_dto) is None
|
|
115
|
+
user = user_factory(is_active=True, is_superuser=True, metadata=metadata)
|
|
116
|
+
assert controller.get_activity_participant(user_dto) == user.profile
|
|
117
|
+
|
|
118
|
+
def _get_user_and_activities(self, notification_fixture, user_factory, teams_event_fixture):
|
|
119
|
+
user1 = user_factory(is_active=True)
|
|
120
|
+
user2 = user_factory(
|
|
121
|
+
is_active=True, metadata={"outlook": {"subscription": {"id": notification_fixture["subscription_id"]}}}
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
other1_activity = ActivityFactory(creator=user1.profile, participants=(user2.profile,))
|
|
125
|
+
other2_activity = ActivityFactory(
|
|
126
|
+
creator=user1.profile,
|
|
127
|
+
participants=(user2.profile,),
|
|
128
|
+
metadata={"outlook": {"event_id": 1, "event_uid": 2, "resources": ["Users/1/events/1"]}},
|
|
129
|
+
)
|
|
130
|
+
metadata = {
|
|
131
|
+
"outlook": {
|
|
132
|
+
"resources": [notification_fixture["resource"]],
|
|
133
|
+
"organizer_resource": notification_fixture["resource"],
|
|
134
|
+
"event_uid": teams_event_fixture["uid"],
|
|
135
|
+
"event_id": teams_event_fixture["id"],
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
activity = ActivityFactory(creator=user1.profile, participants=(user2.profile,))
|
|
139
|
+
Activity.objects.filter(id=activity.id).update(metadata=metadata)
|
|
140
|
+
return {"activities": (other1_activity, other2_activity, activity), "users": (user1, user2)}
|
|
141
|
+
|
|
142
|
+
@pytest.mark.parametrize("is_internal_creator, cancel_activity", list(itertools.product([True, False], repeat=2)))
|
|
143
|
+
def test_delete_activity(
|
|
144
|
+
self, cancel_activity, is_internal_creator, controller, notification_fixture, user_factory, teams_event_fixture
|
|
145
|
+
):
|
|
146
|
+
global_preferences_registry.manager()["wbactivity_sync__sync_cancelled_activity"] = cancel_activity
|
|
147
|
+
|
|
148
|
+
data = self._get_user_and_activities(notification_fixture, user_factory, teams_event_fixture)
|
|
149
|
+
other1_activity, other2_activity, activity = data["activities"]
|
|
150
|
+
user1, user2 = data["users"]
|
|
151
|
+
if is_internal_creator:
|
|
152
|
+
permission = Permission.objects.get_or_create(
|
|
153
|
+
content_type=ContentType.objects.get_for_model(User), codename="is_internal_user"
|
|
154
|
+
)[0]
|
|
155
|
+
user1.user_permissions.add(permission)
|
|
156
|
+
user_registry.reset_cache()
|
|
157
|
+
activity.refresh_from_db()
|
|
158
|
+
activity_dto = activity._build_dto()
|
|
159
|
+
|
|
160
|
+
user1_dto = UserDTO(metadata=user1.metadata, id=None)
|
|
161
|
+
user2_dto = UserDTO(metadata=user2.metadata, id=None)
|
|
162
|
+
|
|
163
|
+
assert set(Activity.objects.all()) == {other1_activity, other2_activity, activity}
|
|
164
|
+
|
|
165
|
+
controller.delete_activity(activity_dto, user1_dto)
|
|
166
|
+
assert set(Activity.objects.all()) == {other1_activity, other2_activity, activity}
|
|
167
|
+
|
|
168
|
+
controller.delete_activity(
|
|
169
|
+
activity_dto, user2_dto
|
|
170
|
+
) # user 2 is not the creator of the activity. it's a participant
|
|
171
|
+
assert set(Activity.objects.all()) == {other1_activity, other2_activity, activity}
|
|
172
|
+
if is_internal_creator:
|
|
173
|
+
assert (
|
|
174
|
+
activity.activity_participants.get(participant=user2.profile).participation_status
|
|
175
|
+
== ActivityParticipant.ParticipationStatus.CANCELLED
|
|
176
|
+
)
|
|
177
|
+
|
|
178
|
+
controller.delete_activity(
|
|
179
|
+
activity_dto, user1_dto
|
|
180
|
+
) # user 1 is the creator of the activity but doesn't have an active subscription
|
|
181
|
+
assert set(Activity.objects.all()) == {other1_activity, other2_activity, activity}
|
|
182
|
+
user1.metadata = user2.metadata
|
|
183
|
+
user1.save()
|
|
184
|
+
user2.metadata = {}
|
|
185
|
+
user2.metadata = {"outlook": {"subscription": {"id": "new_subscription1"}}}
|
|
186
|
+
user2.save()
|
|
187
|
+
user1.refresh_from_db()
|
|
188
|
+
user1_dto = UserDTO(metadata=user1.metadata, id=None)
|
|
189
|
+
|
|
190
|
+
controller.delete_activity(
|
|
191
|
+
activity_dto, user1_dto
|
|
192
|
+
) # user 1 is the creator of the activity with an active subscription
|
|
193
|
+
if is_internal_creator and not cancel_activity:
|
|
194
|
+
assert set(Activity.objects.all()) == {other1_activity, other2_activity}
|
|
195
|
+
else:
|
|
196
|
+
assert set(Activity.objects.all()) == {other1_activity, other2_activity, activity}
|
|
197
|
+
assert set(Activity.all_objects.all()) == {other1_activity, other2_activity, activity}
|
|
198
|
+
|
|
199
|
+
@pytest.mark.parametrize(
|
|
200
|
+
"cancel_external_creator_activity, cancel_activity", list(itertools.product([True, False], repeat=2))
|
|
201
|
+
)
|
|
202
|
+
def test_cancel_no_participant_external_creator_activity(
|
|
203
|
+
self,
|
|
204
|
+
cancel_external_creator_activity,
|
|
205
|
+
cancel_activity,
|
|
206
|
+
controller,
|
|
207
|
+
notification_fixture,
|
|
208
|
+
user_factory,
|
|
209
|
+
teams_event_fixture,
|
|
210
|
+
):
|
|
211
|
+
global_preferences_registry.manager()["wbactivity_sync__sync_cancelled_activity"] = cancel_activity
|
|
212
|
+
global_preferences_registry.manager()[
|
|
213
|
+
"wbactivity_sync__sync_cancelled_external_activity"
|
|
214
|
+
] = cancel_external_creator_activity
|
|
215
|
+
|
|
216
|
+
data = self._get_user_and_activities(notification_fixture, user_factory, teams_event_fixture)
|
|
217
|
+
other1_activity, other2_activity, activity = data["activities"]
|
|
218
|
+
user1, user2 = data["users"]
|
|
219
|
+
permission = Permission.objects.get_or_create(
|
|
220
|
+
content_type=ContentType.objects.get_for_model(User), codename="is_internal_user"
|
|
221
|
+
)[0]
|
|
222
|
+
user2.user_permissions.add(permission)
|
|
223
|
+
user_registry.reset_cache()
|
|
224
|
+
user2_dto = UserDTO(metadata=user2.metadata, id=None)
|
|
225
|
+
Activity.objects.filter(id=activity.id).update(creator=user1.profile)
|
|
226
|
+
activity.refresh_from_db()
|
|
227
|
+
activity_dto = activity._build_dto()
|
|
228
|
+
|
|
229
|
+
assert set(Activity.objects.all()) == {other1_activity, other2_activity, activity}
|
|
230
|
+
|
|
231
|
+
# user 1 is an external user and it's the creator of the activity without an active subscription
|
|
232
|
+
# user 2 is a internal participant
|
|
233
|
+
controller.delete_activity(activity_dto, user2_dto)
|
|
234
|
+
if cancel_external_creator_activity and not cancel_activity:
|
|
235
|
+
assert set(Activity.objects.all()) == {other1_activity, other2_activity}
|
|
236
|
+
else:
|
|
237
|
+
assert set(Activity.objects.all()) == {other1_activity, other2_activity, activity}
|