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.

Files changed (155) hide show
  1. wbcrm/__init__.py +1 -0
  2. wbcrm/admin/__init__.py +4 -0
  3. wbcrm/admin/accounts.py +59 -0
  4. wbcrm/admin/activities.py +101 -0
  5. wbcrm/admin/groups.py +7 -0
  6. wbcrm/admin/products.py +8 -0
  7. wbcrm/apps.py +5 -0
  8. wbcrm/configurations/__init__.py +1 -0
  9. wbcrm/configurations/base.py +16 -0
  10. wbcrm/dynamic_preferences_registry.py +38 -0
  11. wbcrm/factories/__init__.py +14 -0
  12. wbcrm/factories/accounts.py +56 -0
  13. wbcrm/factories/activities.py +125 -0
  14. wbcrm/factories/groups.py +23 -0
  15. wbcrm/factories/products.py +10 -0
  16. wbcrm/filters/__init__.py +10 -0
  17. wbcrm/filters/accounts.py +67 -0
  18. wbcrm/filters/activities.py +181 -0
  19. wbcrm/filters/groups.py +20 -0
  20. wbcrm/filters/products.py +37 -0
  21. wbcrm/filters/signals.py +94 -0
  22. wbcrm/migrations/0001_initial_squashed_squashed_0032_productcompanyrelationship_alter_product_prospects_and_more.py +3948 -0
  23. wbcrm/migrations/0002_alter_activity_repeat_choice.py +32 -0
  24. wbcrm/migrations/0003_remove_activity_external_id_and_more.py +63 -0
  25. wbcrm/migrations/0004_alter_activity_status.py +28 -0
  26. wbcrm/migrations/0005_account_accountrole_accountroletype_and_more.py +182 -0
  27. wbcrm/migrations/0006_alter_activity_location.py +17 -0
  28. wbcrm/migrations/0007_alter_account_status.py +23 -0
  29. wbcrm/migrations/0008_alter_activity_options.py +16 -0
  30. wbcrm/migrations/0009_alter_account_is_public.py +19 -0
  31. wbcrm/migrations/0010_alter_account_reference_id.py +17 -0
  32. wbcrm/migrations/0011_activity_summary.py +22 -0
  33. wbcrm/migrations/0012_alter_activity_summary.py +17 -0
  34. wbcrm/migrations/0013_account_action_plan_account_relationship_status_and_more.py +34 -0
  35. wbcrm/migrations/0014_alter_account_relationship_status.py +24 -0
  36. wbcrm/migrations/0015_alter_activity_type.py +23 -0
  37. wbcrm/migrations/0016_auto_20241205_1015.py +106 -0
  38. wbcrm/migrations/__init__.py +0 -0
  39. wbcrm/models/__init__.py +4 -0
  40. wbcrm/models/accounts.py +637 -0
  41. wbcrm/models/activities.py +1335 -0
  42. wbcrm/models/groups.py +118 -0
  43. wbcrm/models/products.py +83 -0
  44. wbcrm/models/recurrence.py +279 -0
  45. wbcrm/preferences.py +14 -0
  46. wbcrm/serializers/__init__.py +23 -0
  47. wbcrm/serializers/accounts.py +126 -0
  48. wbcrm/serializers/activities.py +526 -0
  49. wbcrm/serializers/groups.py +30 -0
  50. wbcrm/serializers/products.py +57 -0
  51. wbcrm/serializers/recurrence.py +90 -0
  52. wbcrm/serializers/signals.py +70 -0
  53. wbcrm/synchronization/__init__.py +0 -0
  54. wbcrm/synchronization/activity/__init__.py +0 -0
  55. wbcrm/synchronization/activity/admin.py +72 -0
  56. wbcrm/synchronization/activity/backend.py +207 -0
  57. wbcrm/synchronization/activity/backends/__init__.py +0 -0
  58. wbcrm/synchronization/activity/backends/google/__init__.py +2 -0
  59. wbcrm/synchronization/activity/backends/google/google_calendar_backend.py +399 -0
  60. wbcrm/synchronization/activity/backends/google/request_utils/__init__.py +16 -0
  61. wbcrm/synchronization/activity/backends/google/tasks.py +21 -0
  62. wbcrm/synchronization/activity/backends/google/tests/__init__.py +0 -0
  63. wbcrm/synchronization/activity/backends/google/tests/conftest.py +1 -0
  64. wbcrm/synchronization/activity/backends/google/tests/test_data.py +81 -0
  65. wbcrm/synchronization/activity/backends/google/tests/test_google_backend.py +319 -0
  66. wbcrm/synchronization/activity/backends/google/tests/test_utils.py +274 -0
  67. wbcrm/synchronization/activity/backends/google/typing_informations.py +139 -0
  68. wbcrm/synchronization/activity/backends/google/utils.py +216 -0
  69. wbcrm/synchronization/activity/backends/outlook/__init__.py +0 -0
  70. wbcrm/synchronization/activity/backends/outlook/backend.py +576 -0
  71. wbcrm/synchronization/activity/backends/outlook/msgraph.py +438 -0
  72. wbcrm/synchronization/activity/backends/outlook/parser.py +423 -0
  73. wbcrm/synchronization/activity/backends/outlook/tests/__init__.py +0 -0
  74. wbcrm/synchronization/activity/backends/outlook/tests/conftest.py +1 -0
  75. wbcrm/synchronization/activity/backends/outlook/tests/fixtures.py +606 -0
  76. wbcrm/synchronization/activity/backends/outlook/tests/test_admin.py +117 -0
  77. wbcrm/synchronization/activity/backends/outlook/tests/test_backend.py +269 -0
  78. wbcrm/synchronization/activity/backends/outlook/tests/test_controller.py +237 -0
  79. wbcrm/synchronization/activity/backends/outlook/tests/test_parser.py +173 -0
  80. wbcrm/synchronization/activity/controller.py +545 -0
  81. wbcrm/synchronization/activity/dynamic_preferences_registry.py +107 -0
  82. wbcrm/synchronization/activity/preferences.py +21 -0
  83. wbcrm/synchronization/activity/shortcuts.py +9 -0
  84. wbcrm/synchronization/activity/signals.py +28 -0
  85. wbcrm/synchronization/activity/tasks.py +21 -0
  86. wbcrm/synchronization/activity/urls.py +6 -0
  87. wbcrm/synchronization/activity/utils.py +46 -0
  88. wbcrm/synchronization/activity/views.py +37 -0
  89. wbcrm/synchronization/admin.py +1 -0
  90. wbcrm/synchronization/apps.py +15 -0
  91. wbcrm/synchronization/dynamic_preferences_registry.py +1 -0
  92. wbcrm/synchronization/management.py +36 -0
  93. wbcrm/synchronization/tasks.py +1 -0
  94. wbcrm/synchronization/urls.py +5 -0
  95. wbcrm/tasks.py +312 -0
  96. wbcrm/tests/__init__.py +0 -0
  97. wbcrm/tests/accounts/__init__.py +0 -0
  98. wbcrm/tests/accounts/test_models.py +380 -0
  99. wbcrm/tests/accounts/test_viewsets.py +87 -0
  100. wbcrm/tests/conftest.py +76 -0
  101. wbcrm/tests/disable_signals.py +52 -0
  102. wbcrm/tests/e2e/__init__.py +1 -0
  103. wbcrm/tests/e2e/e2e_wbcrm_utility.py +82 -0
  104. wbcrm/tests/e2e/test_e2e.py +369 -0
  105. wbcrm/tests/test_assignee_methods.py +39 -0
  106. wbcrm/tests/test_chartviewsets.py +111 -0
  107. wbcrm/tests/test_dto.py +63 -0
  108. wbcrm/tests/test_filters.py +51 -0
  109. wbcrm/tests/test_models.py +216 -0
  110. wbcrm/tests/test_recurrence.py +291 -0
  111. wbcrm/tests/test_report.py +20 -0
  112. wbcrm/tests/test_serializers.py +170 -0
  113. wbcrm/tests/test_tasks.py +94 -0
  114. wbcrm/tests/test_viewsets.py +967 -0
  115. wbcrm/tests/tests.py +120 -0
  116. wbcrm/typings.py +107 -0
  117. wbcrm/urls.py +67 -0
  118. wbcrm/viewsets/__init__.py +22 -0
  119. wbcrm/viewsets/accounts.py +121 -0
  120. wbcrm/viewsets/activities.py +315 -0
  121. wbcrm/viewsets/buttons/__init__.py +7 -0
  122. wbcrm/viewsets/buttons/accounts.py +27 -0
  123. wbcrm/viewsets/buttons/activities.py +68 -0
  124. wbcrm/viewsets/buttons/signals.py +17 -0
  125. wbcrm/viewsets/display/__init__.py +12 -0
  126. wbcrm/viewsets/display/accounts.py +110 -0
  127. wbcrm/viewsets/display/activities.py +443 -0
  128. wbcrm/viewsets/display/groups.py +22 -0
  129. wbcrm/viewsets/display/products.py +105 -0
  130. wbcrm/viewsets/endpoints/__init__.py +8 -0
  131. wbcrm/viewsets/endpoints/accounts.py +32 -0
  132. wbcrm/viewsets/endpoints/activities.py +30 -0
  133. wbcrm/viewsets/endpoints/groups.py +7 -0
  134. wbcrm/viewsets/endpoints/products.py +9 -0
  135. wbcrm/viewsets/groups.py +37 -0
  136. wbcrm/viewsets/menu/__init__.py +8 -0
  137. wbcrm/viewsets/menu/accounts.py +18 -0
  138. wbcrm/viewsets/menu/activities.py +61 -0
  139. wbcrm/viewsets/menu/groups.py +16 -0
  140. wbcrm/viewsets/menu/products.py +20 -0
  141. wbcrm/viewsets/mixins.py +34 -0
  142. wbcrm/viewsets/previews/__init__.py +1 -0
  143. wbcrm/viewsets/previews/activities.py +10 -0
  144. wbcrm/viewsets/products.py +56 -0
  145. wbcrm/viewsets/recurrence.py +26 -0
  146. wbcrm/viewsets/titles/__init__.py +13 -0
  147. wbcrm/viewsets/titles/accounts.py +22 -0
  148. wbcrm/viewsets/titles/activities.py +61 -0
  149. wbcrm/viewsets/titles/products.py +13 -0
  150. wbcrm/viewsets/titles/utils.py +46 -0
  151. wbcrm/workflows/__init__.py +1 -0
  152. wbcrm/workflows/assignee_methods.py +25 -0
  153. wbcrm-2.2.1.dist-info/METADATA +11 -0
  154. wbcrm-2.2.1.dist-info/RECORD +155 -0
  155. wbcrm-2.2.1.dist-info/WHEEL +5 -0
@@ -0,0 +1,319 @@
1
+ # import datetime
2
+ # import json
3
+ # from unittest.mock import patch
4
+
5
+ # import pytest
6
+ # from django.utils import timezone
7
+ # from dynamic_preferences.registries import global_preferences_registry
8
+ # from rest_framework.test import APIRequestFactory
9
+ # from wbcore.test.utils import get_or_create_superuser
10
+ # from wbcrm.models import ActivityParticipant
11
+
12
+ # from ..google_calendar_backend import GoogleCalendarBackend
13
+ # from .test_data import credentials, event_data, execute_service, service_data
14
+
15
+
16
+ # class TestInitialisationGoogleCalendarBackend:
17
+ # @pytest.fixture()
18
+ # def activity_with_user(self, activity_factory):
19
+ # user = get_or_create_superuser()
20
+ # user.metadata = {"google_backend": {"watch": {"id": "fake_id"}}}
21
+ # user.save()
22
+ # return activity_factory(creator=user.profile)
23
+
24
+ # @pytest.fixture()
25
+ # def activity_with_user2(self, activity_factory):
26
+ # user = get_or_create_superuser()
27
+ # user.metadata = {"google_backend": {"watch": {"id": "fake_id2"}}}
28
+ # user.save()
29
+ # return activity_factory(creator=user.profile)
30
+
31
+ # @pytest.mark.parametrize("credentials", ["", credentials])
32
+ # def test_get_service_account_file(self, credentials):
33
+ # from ..google_calendar_backend import GoogleCalendarBackend
34
+
35
+ # global_preferences_registry.manager()["wbactivity_sync__google_sync_credentials"] = credentials
36
+
37
+ # backend = GoogleCalendarBackend()
38
+
39
+ # if not credentials:
40
+ # with pytest.raises(ValueError) as excinfo:
41
+ # file = backend._get_service_account_file()
42
+ # assert (
43
+ # "The Google credentials are not set. You cannot use the Google Calendar Backend without the Google credentials."
44
+ # in str(excinfo.value)
45
+ # )
46
+ # else:
47
+ # file = backend._get_service_account_file()
48
+ # assert file == json.loads(credentials)
49
+
50
+ # @pytest.mark.parametrize("credentials", [credentials])
51
+ # def test_get_service_account_url(self, credentials):
52
+ # from ..google_calendar_backend import GoogleCalendarBackend
53
+
54
+ # global_preferences_registry.manager()["wbactivity_sync__google_sync_credentials"] = credentials
55
+ # assert GoogleCalendarBackend()._get_service_account_url()
56
+
57
+ # def test_get_service_user_email(self, activity_with_user, activity_with_user2, activity_factory):
58
+ # global_preferences_registry.manager()["wbcrm__main_company"] = employee.employers.first().id
59
+
60
+ # activity = activity_factory()
61
+ # activity1 = activity_factory()
62
+ # activity2 = activity_with_user2
63
+ # activity3 = activity_with_user
64
+ # activity4 = activity_factory(participants=(employee,))
65
+ # tomorrow = (timezone.now() + datetime.timedelta(days=1)).replace(tzinfo=None)
66
+ # activity3.creator.user_account.metadata["google_backend"]["watch"]["expiration"] = (
67
+ # datetime.datetime.timestamp(tomorrow) * 1000
68
+ # )
69
+ # activity3.creator.user_account.save()
70
+ # employee.user_account.metadata = activity3.creator.user_account.metadata
71
+ # employee.user_account.save()
72
+ # backend = GoogleCalendarBackend()
73
+ # assert backend._get_service_user_email(activity) == ""
74
+ # assert backend._get_service_user_email(activity1) == ""
75
+ # assert backend._get_service_user_email(activity2) == ""
76
+ # assert backend._get_service_user_email(activity3) == activity3.creator.user_account.email
77
+ # assert backend._get_service_user_email(activity4)
78
+
79
+ # @patch("wbcrm.synchronization.activity.backends.google.google_calendar_backend.Credentials")
80
+ # @patch("wbcrm.synchronization.activity.backends.google.google_calendar_backend.build")
81
+ # @pytest.mark.parametrize("credentials", ["", credentials])
82
+ # def test_build_service(self, mock_build, mock_credentials, credentials):
83
+ # global_preferences_registry.manager()["wbactivity_sync__google_sync_credentials"] = credentials
84
+ # user = get_or_create_superuser()
85
+ # backend = GoogleCalendarBackend()
86
+ # if not credentials:
87
+ # with pytest.raises(ValueError) as excinfo:
88
+ # resource = backend._build_service(user.email)
89
+ # assert backend.error_messages["service_build_error"] in str(excinfo.value)
90
+ # else:
91
+ # resource = backend._build_service(user.email)
92
+ # assert resource
93
+
94
+
95
+ # @patch("wbcrm.synchronization.activity.backends.google.google_calendar_backend.GoogleCalendarBackend._build_service")
96
+ # @patch(
97
+ # "wbcrm.synchronization.activity.backends.google.google_calendar_backend.GoogleCalendarBackend._get_service_user_email"
98
+ # )
99
+ # @pytest.mark.parametrize(
100
+ # "sync_past_activity, event", [(False, ""), (True, ""), (False, event_data), (True, event_data)]
101
+ # )
102
+ # @pytest.mark.django_db
103
+ # class TestGoogleCalendarBackend:
104
+ # @pytest.fixture()
105
+ # def activity_fixture(self, activity_factory, event):
106
+ # user = get_or_create_superuser()
107
+ # user.metadata = {"google_backend": {"watch": {"id": "fake_id"}}}
108
+ # user.save()
109
+ # if event:
110
+ # metadata = {"google_backend": {"event": event}}
111
+ # return activity_factory(creator=user.profile, metadata=metadata, external_id=event["id"])
112
+ # else:
113
+ # metadata = {}
114
+ # return activity_factory(creator=user.profile, metadata=metadata, external_id=None)
115
+
116
+ # def test_create_external_activity(
117
+ # self, mock_user_email, mock_service, sync_past_activity, event, activity_factory
118
+ # ):
119
+ # global_preferences_registry.manager()["wbactivity_sync__sync_past_activity"] = sync_past_activity
120
+ # now = timezone.now()
121
+ # yesterday = now - datetime.timedelta(days=1)
122
+ # tomorrow = now + datetime.timedelta(days=1)
123
+
124
+ # activity_passed = activity_factory(start=yesterday, end=yesterday + datetime.timedelta(hours=1))
125
+ # activity = activity_factory(start=tomorrow, end=tomorrow + datetime.timedelta(hours=1))
126
+ # activity_with_parent = activity_factory(
127
+ # start=tomorrow, end=tomorrow + datetime.timedelta(hours=1), parent_occurrence=activity_passed
128
+ # )
129
+
130
+ # mock_service.return_value = service_data()
131
+ # with patch.object(execute_service, "execute", return_value=event):
132
+
133
+ # backend = GoogleCalendarBackend()
134
+ # if event:
135
+ # backend.create_external_activity(activity_passed)
136
+ # backend.create_external_activity(activity)
137
+ # backend.create_external_activity(activity_with_parent)
138
+ # assert (
139
+ # mock_service.call_count == 2
140
+ # ) # 2 instead of 3 because an activity with a parent cannot be synchronized
141
+
142
+ # else:
143
+ # with pytest.raises(ValueError) as excinfo:
144
+ # backend.create_external_activity(activity_passed)
145
+ # backend.create_external_activity(activity)
146
+ # backend.create_external_activity(activity_with_parent)
147
+ # assert "Could not create the external google event. Exception" in str(excinfo.value)
148
+
149
+ # if sync_past_activity:
150
+ # assert mock_service.call_count == 1
151
+ # else:
152
+ # assert mock_service.call_count == 1
153
+ # activity_passed.refresh_from_db()
154
+ # activity.refresh_from_db()
155
+ # activity_with_parent.refresh_from_db()
156
+
157
+ # assert activity_with_parent.metadata == {}
158
+ # assert activity_with_parent.external_id is None
159
+
160
+ # if event:
161
+ # assert activity.metadata
162
+ # assert activity.external_id == event["id"]
163
+ # else:
164
+ # assert activity.metadata == {}
165
+ # assert activity.external_id is None
166
+
167
+ # if sync_past_activity and event:
168
+ # assert activity_passed.metadata
169
+ # assert activity_passed.external_id == event["id"]
170
+ # else:
171
+ # assert activity_passed.metadata == {}
172
+ # assert activity_passed.external_id is None
173
+
174
+ # def test_delete_external_activity(
175
+ # self, mock_user_email, mock_service, sync_past_activity, event, activity_factory
176
+ # ):
177
+ # global_preferences_registry.manager()["wbactivity_sync__sync_past_activity"] = sync_past_activity
178
+ # now = timezone.now()
179
+ # yesterday = now - datetime.timedelta(days=1)
180
+ # tomorrow = now + datetime.timedelta(days=1)
181
+
182
+ # activity_passed = activity_factory(start=yesterday, end=yesterday + datetime.timedelta(hours=1))
183
+ # activity = activity_factory(start=tomorrow, end=tomorrow + datetime.timedelta(hours=1))
184
+ # activity_with_parent = activity_factory(
185
+ # start=tomorrow, end=tomorrow + datetime.timedelta(hours=1), parent_occurrence=activity_passed
186
+ # )
187
+
188
+ # mock_service.return_value = service_data()
189
+ # with patch.object(execute_service, "execute", return_value=None):
190
+
191
+ # backend = GoogleCalendarBackend()
192
+ # backend.delete_external_activity(activity_passed)
193
+ # backend.delete_external_activity(activity)
194
+ # backend.delete_external_activity(activity_with_parent)
195
+ # assert mock_service.call_count == 3
196
+
197
+ # def test_update_external_activity(
198
+ # self, mock_user_email, mock_service, sync_past_activity, event, activity_factory
199
+ # ):
200
+ # global_preferences_registry.manager()["wbactivity_sync__sync_past_activity"] = sync_past_activity
201
+ # now = timezone.now()
202
+ # yesterday = now - datetime.timedelta(days=1)
203
+ # tomorrow = now + datetime.timedelta(days=1)
204
+
205
+ # metadata = {"google_backend": {"instance": event if event else {}}}
206
+ # external_id = event["id"] if event else None
207
+ # activity_no_metadata = activity_factory(start=tomorrow, end=tomorrow + datetime.timedelta(hours=1))
208
+ # activity_passed = activity_factory(
209
+ # start=yesterday, end=yesterday + datetime.timedelta(hours=1), external_id=external_id, metadata=metadata
210
+ # )
211
+ # activity = activity_factory(
212
+ # start=tomorrow, end=tomorrow + datetime.timedelta(hours=1), external_id=external_id, metadata=metadata
213
+ # )
214
+ # activity_with_parent = activity_factory(
215
+ # start=tomorrow,
216
+ # end=tomorrow + datetime.timedelta(hours=1),
217
+ # parent_occurrence=activity_passed,
218
+ # external_id=external_id,
219
+ # metadata=metadata,
220
+ # )
221
+
222
+ # mock_service.return_value = service_data()
223
+ # with patch.object(execute_service, "execute", return_value=event if event else {"id": None}):
224
+ # backend = GoogleCalendarBackend()
225
+ # backend.update_external_activity(activity_no_metadata)
226
+ # backend.update_external_activity(activity_passed)
227
+ # backend.update_external_activity(activity)
228
+ # backend.update_external_activity(activity_with_parent)
229
+
230
+ # assert (
231
+ # mock_service.call_count == 5
232
+ # ) # rather than 4 because we call create_external_activity if no metadata
233
+ # assert activity_no_metadata.external_id == external_id
234
+ # assert activity_no_metadata.metadata == {"google_backend": {"event": event if event else {"id": None}}}
235
+
236
+ # @pytest.mark.parametrize("response_status", [*list(ActivityParticipant.ParticipationStatus)])
237
+ # def test_send_participant_response_external_activity(
238
+ # self,
239
+ # mock_user_email,
240
+ # mock_service,
241
+ # response_status,
242
+ # sync_past_activity,
243
+ # event,
244
+ # person_factory,
245
+ # activity_fixture,
246
+ # ):
247
+ # global_preferences_registry.manager()["wbactivity_sync__sync_past_activity"] = sync_past_activity
248
+ # activity = activity_fixture
249
+ # person = person_factory()
250
+ # activity.participants.add(person, activity.creator)
251
+ # activity.save()
252
+ # creator_participant = ActivityParticipant.objects.filter(
253
+ # activity=activity, participant=activity.creator
254
+ # ).first()
255
+ # mock_service.return_value = service_data()
256
+ # with patch.object(execute_service, "execute", return_value=event if event else {"id": None}) as mock_execute:
257
+ # backend = GoogleCalendarBackend()
258
+ # activityparticipant = activity.activity_participants.filter(participant=person).first()
259
+ # backend.send_participant_response_external_activity(activityparticipant, response_status)
260
+ # backend.send_participant_response_external_activity(creator_participant, response_status)
261
+ # if event:
262
+ # assert mock_execute.call_count
263
+ # else:
264
+ # assert mock_execute.call_count == 0
265
+
266
+ # @patch(
267
+ # "wbcrm.synchronization.activity.backends.google.google_calendar_backend.GoogleCalendarBackend.sync_with_external_calendar"
268
+ # )
269
+ # def test_sync_with_external_calendar(
270
+ # self, mock_handle_changes, mock_user_email, mock_service, sync_past_activity, event
271
+ # ):
272
+ # user = get_or_create_superuser()
273
+ # request = APIRequestFactory().get("", **{"HTTP_X-Goog-Channel-Id": user.id})
274
+ # backend = GoogleCalendarBackend()
275
+ # backend.sync_with_external_calendar(request)
276
+ # assert mock_handle_changes.call_count == 1
277
+
278
+ # def test_get_sync_token(self, mock_user_email, mock_service, sync_past_activity, event):
279
+ # user = get_or_create_superuser()
280
+ # user.metadata = {"google_backend": {"sync_token": "fake_token"}}
281
+ # user.save()
282
+ # backend = GoogleCalendarBackend()
283
+ # assert backend.get_sync_token(user) == "fake_token"
284
+
285
+ # def test_get_external_activity(self, mock_user_email, mock_service, sync_past_activity, event):
286
+ # pass
287
+
288
+ # def test_forward_external_activity(self, mock_user_email, mock_service, sync_past_activity, event):
289
+ # pass
290
+
291
+ # @patch(
292
+ # "wbcrm.synchronization.activity.backends.google.google_calendar_backend.GoogleCalendarBackend._get_service_account_url"
293
+ # )
294
+ # def test_set_web_hook(self, mock_url, mock_user_email, mock_service, sync_past_activity, event):
295
+ # user = get_or_create_superuser()
296
+ # watch = {"id": "fake_id"}
297
+ # mock_service.return_value = service_data()
298
+ # with patch.object(execute_service, "execute", return_value=watch):
299
+ # GoogleCalendarBackend().set_web_hook(user)
300
+ # assert user.metadata["google_backend"]["watch"] == watch
301
+
302
+ # def test_stop_web_hook(self, mock_user_email, mock_service, sync_past_activity, event):
303
+ # user = get_or_create_superuser()
304
+ # user.metadata = {"google_backend": {"watch": {"id": "fake_id", "resourceId": "fake_resource_id"}}}
305
+ # user.save()
306
+ # watch = {"id": "fake_id"}
307
+ # mock_service.return_value = service_data()
308
+ # with patch.object(execute_service, "execute", return_value=watch):
309
+ # GoogleCalendarBackend().stop_web_hook(user)
310
+ # assert user.metadata["google_backend"] == {}
311
+
312
+ # def test_check_web_hook(self, mock_user_email, mock_service, sync_past_activity, event):
313
+ # tomorrow = (timezone.now() + datetime.timedelta(days=1)).replace(tzinfo=None)
314
+ # user = get_or_create_superuser()
315
+ # user.metadata = {"google_backend": {"watch": {"expiration": datetime.datetime.timestamp(tomorrow) * 1000}}}
316
+ # user.save()
317
+ # with pytest.warns() as record:
318
+ # GoogleCalendarBackend().check_web_hook(user)
319
+ # assert len(record) == 1
@@ -0,0 +1,274 @@
1
+ # import datetime
2
+ # from zoneinfo import ZoneInfo
3
+
4
+ # import pytest
5
+ # from django.conf import settings
6
+ # from dynamic_preferences.registries import global_preferences_registry
7
+ # from wbcrm.models import (
8
+ # Activity,
9
+ # ActivityParticipant,
10
+ # CalendarItem,
11
+ # EmailContact,
12
+ # Person,
13
+ # )
14
+
15
+ # from ..utils import GoogleSyncUtils
16
+ # from .test_data import event, event_list
17
+
18
+
19
+ # @pytest.mark.django_db
20
+ # class TestUtils:
21
+ # def test_add_instance_metadata(self, activity_factory):
22
+ # new_metadata = {"google_backend": {"instance": {"uID": "UID"}, "event": {"id": "event id"}}}
23
+ # parent_occurrence: Activity = activity_factory(
24
+ # metadata={"google_backend": {"instance": {"originalStartTime": {"dateTime": "Fake Date Time"}}}}
25
+ # )
26
+ # child_activity_a: Activity = activity_factory(
27
+ # parent_occurrence=parent_occurrence,
28
+ # metadata={"google_backend": {"instance": {"originalStartTime": {"dateTime": "Fake Date Time A"}}}},
29
+ # )
30
+ # child_activity_b: Activity = activity_factory(
31
+ # parent_occurrence=parent_occurrence,
32
+ # metadata={"google_backend": {"instance": {"originalStartTime": {"dateTime": "Fake Date Time B"}}}},
33
+ # )
34
+ # child_activity_c: Activity = activity_factory(
35
+ # parent_occurrence=parent_occurrence,
36
+ # metadata={"google_backend": {"instance": {"originalStartTime": {"dateTime": "Fake Date Time C"}}}},
37
+ # )
38
+ # GoogleSyncUtils.add_instance_metadata(parent_occurrence, event_list, new_metadata)
39
+ # parent_occurrence = Activity.objects.get(id=parent_occurrence.id)
40
+ # child_activity_a = Activity.objects.get(id=child_activity_a.id)
41
+ # child_activity_b = Activity.objects.get(id=child_activity_b.id)
42
+ # child_activity_c = Activity.objects.get(id=child_activity_c.id)
43
+ # assert parent_occurrence.metadata["google_backend"]["instance"]["metaTest"] == "Parent"
44
+ # assert child_activity_a.external_id == "2"
45
+ # assert child_activity_a.metadata["google_backend"]["instance"]["metaTest"] == "Child A"
46
+ # assert child_activity_b.external_id == "3"
47
+ # assert child_activity_b.metadata["google_backend"]["instance"]["metaTest"] == "Child B"
48
+ # assert child_activity_c.external_id == "4"
49
+ # assert child_activity_c.metadata["google_backend"]["instance"]["metaTest"] == "Child C"
50
+
51
+ # def test_convert_activity_visibility_to_event_visibility(self):
52
+ # assert (
53
+ # GoogleSyncUtils.convert_activity_visibility_to_event_visibility(CalendarItem.Visibility.PUBLIC) == "public"
54
+ # )
55
+ # assert (
56
+ # GoogleSyncUtils.convert_activity_visibility_to_event_visibility(CalendarItem.Visibility.PRIVATE)
57
+ # == "private"
58
+ # )
59
+ # assert (
60
+ # GoogleSyncUtils.convert_activity_visibility_to_event_visibility(CalendarItem.Visibility.CONFIDENTIAL)
61
+ # == "private"
62
+ # )
63
+
64
+ # def test_convert_event_visibility_to_activity_visibility(self):
65
+ # assert (
66
+ # GoogleSyncUtils.convert_event_visibility_to_activity_visibility("private")
67
+ # == CalendarItem.Visibility.PRIVATE
68
+ # ) or (
69
+ # GoogleSyncUtils.convert_event_visibility_to_activity_visibility("private")
70
+ # == CalendarItem.Visibility.CONFIDENTIAL
71
+ # )
72
+ # assert (
73
+ # GoogleSyncUtils.convert_event_visibility_to_activity_visibility("public") == CalendarItem.Visibility.PUBLIC
74
+ # )
75
+
76
+ # def test_convert_attendee_status_to_participant_status(self):
77
+ # assert (
78
+ # GoogleSyncUtils.convert_attendee_status_to_participant_status("accepted")
79
+ # == ActivityParticipant.ParticipationStatus.ATTENDS
80
+ # )
81
+ # assert (
82
+ # GoogleSyncUtils.convert_attendee_status_to_participant_status("declined")
83
+ # == ActivityParticipant.ParticipationStatus.CANCELLED
84
+ # )
85
+ # assert (
86
+ # GoogleSyncUtils.convert_attendee_status_to_participant_status("tentative")
87
+ # == ActivityParticipant.ParticipationStatus.MAYBE
88
+ # )
89
+ # assert (
90
+ # GoogleSyncUtils.convert_attendee_status_to_participant_status("Something different")
91
+ # == ActivityParticipant.ParticipationStatus.NOTRESPONDED
92
+ # )
93
+
94
+ # def test_convert_participant_status_to_attendee_status(self):
95
+ # assert (
96
+ # GoogleSyncUtils.convert_participant_status_to_attendee_status(
97
+ # ActivityParticipant.ParticipationStatus.ATTENDS
98
+ # )
99
+ # == "accepted"
100
+ # )
101
+ # assert (
102
+ # GoogleSyncUtils.convert_participant_status_to_attendee_status(
103
+ # ActivityParticipant.ParticipationStatus.ATTENDS_DIGITALLY
104
+ # )
105
+ # == "accepted"
106
+ # )
107
+ # assert (
108
+ # GoogleSyncUtils.convert_participant_status_to_attendee_status(
109
+ # ActivityParticipant.ParticipationStatus.CANCELLED
110
+ # )
111
+ # == "declined"
112
+ # )
113
+ # assert (
114
+ # GoogleSyncUtils.convert_participant_status_to_attendee_status(
115
+ # ActivityParticipant.ParticipationStatus.MAYBE
116
+ # )
117
+ # == "tentative"
118
+ # )
119
+ # assert GoogleSyncUtils.convert_participant_status_to_attendee_status("Something different") == "notResponded"
120
+
121
+ # @pytest.mark.parametrize("google_event", [{}, event])
122
+ # def test_get_participants(self, google_event, person_factory, email_contact_factory):
123
+ # person_a = person_factory()
124
+ # person_b = person_factory()
125
+ # person_c = person_factory()
126
+ # email_contact_factory(primary=True, entry=person_a, address="Foo@Foo.com")
127
+ # email_contact_factory(primary=True, entry=person_b, address="Bar@Bar.com")
128
+ # part_list = GoogleSyncUtils.get_or_create_participants(google_event, person_c)
129
+ # if not google_event:
130
+ # assert part_list == [{"person_id": person_c.id, "status": ActivityParticipant.ParticipationStatus.ATTENDS}]
131
+ # else:
132
+ # person_d = Person.objects.get(last_name="Foo Bar")
133
+ # person_e = Person.objects.get(last_name="Bar@Foo.com")
134
+ # assert len(part_list) == 5
135
+ # assert {"person_id": person_a.id, "status": ActivityParticipant.ParticipationStatus.ATTENDS} in part_list
136
+ # assert {"person_id": person_b.id, "status": ActivityParticipant.ParticipationStatus.CANCELLED} in part_list
137
+ # assert {"person_id": person_c.id, "status": ActivityParticipant.ParticipationStatus.ATTENDS} in part_list
138
+ # assert {"person_id": person_d.id, "status": ActivityParticipant.ParticipationStatus.MAYBE} in part_list
139
+ # assert {"person_id": person_e.id, "status": ActivityParticipant.ParticipationStatus.MAYBE} in part_list
140
+
141
+ # @pytest.mark.parametrize("can_sync", [False, True])
142
+ # @pytest.mark.parametrize("google_event", [{}, event])
143
+ # def test_convert_activity_participants_to_attendees_list(
144
+ # self, can_sync, google_event, activity_factory, person_factory, internal_user_factory, email_contact_factory
145
+ # ):
146
+ # global_preferences_registry.manager()["wbactivity_sync__sync_external_participants"] = can_sync
147
+ # person_a: Person = internal_user_factory()
148
+ # person_b: Person = person_factory()
149
+ # person_c: Person = person_factory()
150
+ # email_contact_factory(primary=True, entry=person_a, address="A@A.com")
151
+ # email_contact_factory(primary=True, entry=person_b, address="B@B.com")
152
+ # email_contact_factory(primary=True, entry=person_c, address="Foo@Bar.com")
153
+ # activity: Activity = activity_factory(creator=person_a, participants=[person_a.id, person_b.id, person_c])
154
+ # # attendees: list[dict] = convert_activity_participants_to_attendees_list(activity, google_event)
155
+ # attendees: list[dict] = GoogleSyncUtils.convert_activity_participants_to_attendees(activity, google_event)
156
+
157
+ # person_a_dict: dict = {
158
+ # "displayName": person_a.computed_str,
159
+ # "email": str(person_a.primary_email_contact()),
160
+ # "responseStatus": "accepted",
161
+ # }
162
+ # person_b_dict: dict = {
163
+ # "displayName": person_b.computed_str,
164
+ # "email": str(person_b.primary_email_contact()),
165
+ # "responseStatus": "needsAction",
166
+ # }
167
+ # person_c_dict: dict = {
168
+ # "displayName": person_c.computed_str,
169
+ # "email": str(person_c.primary_email_contact()),
170
+ # "responseStatus": "needsAction",
171
+ # }
172
+ # if not google_event and not can_sync:
173
+ # assert len(attendees) == 1
174
+ # assert person_a_dict in attendees
175
+ # elif not google_event and can_sync:
176
+ # assert len(attendees) == 3
177
+ # assert person_a_dict in attendees
178
+ # assert person_b_dict in attendees
179
+ # elif google_event and not can_sync:
180
+ # assert len(attendees) == 2
181
+ # assert person_a_dict in attendees
182
+ # assert person_c_dict in attendees
183
+ # assert person_b_dict not in attendees
184
+ # else:
185
+ # assert len(attendees) == 3
186
+ # assert person_a_dict in attendees
187
+ # assert person_b_dict in attendees
188
+ # assert person_c_dict in attendees
189
+
190
+ # @pytest.mark.parametrize("created", [False])
191
+ # @pytest.mark.parametrize(
192
+ # "metadata",
193
+ # [{}, {"recurrence": ["Recurrence A"], "google_backend": {"event": {"recurrence": ["Recurrence B"]}}}],
194
+ # )
195
+ # def test_convert_activity_to_event(
196
+ # self, internal_user_factory, activity_factory, email_contact_factory, created, metadata
197
+ # ):
198
+ # timezone = ZoneInfo(settings.TIME_ZONE)
199
+ # person_a: Person = internal_user_factory()
200
+ # person_b: Person = internal_user_factory()
201
+ # email_contact_factory(primary=True, entry=person_a, address="Foo@Foo.com")
202
+ # email_contact_factory(primary=True, entry=person_b, address="Bar@Bar.com")
203
+ # activity: Activity = activity_factory(
204
+ # creator=person_a,
205
+ # participants=[person_b.id],
206
+ # visibility=CalendarItem.Visibility.PUBLIC,
207
+ # metadata=metadata,
208
+ # )
209
+ # event = GoogleSyncUtils.convert_activity_to_event(activity, created)
210
+ # assert event["summary"] == activity.title
211
+ # assert event["creator"] == str(activity.creator.primary_email_contact())
212
+ # assert event["organizer"] == str(activity.assigned_to.primary_email_contact())
213
+ # assert event["location"] == activity.location
214
+ # assert event["visibility"] == "public"
215
+ # assert event["attendees"] == [
216
+ # {
217
+ # "displayName": person_b.computed_str,
218
+ # "email": str(person_b.primary_email_contact()),
219
+ # "responseStatus": "needsAction",
220
+ # }
221
+ # ]
222
+ # assert event["start"] == {
223
+ # "dateTime": activity.period.lower.astimezone(timezone).isoformat(),
224
+ # "timeZone": settings.TIME_ZONE,
225
+ # }
226
+ # assert event["end"] == {
227
+ # "dateTime": activity.period.upper.astimezone(timezone).isoformat(),
228
+ # "timeZone": settings.TIME_ZONE,
229
+ # }
230
+ # if metadata and not created:
231
+ # assert event["recurrence"] == ["Recurrence B"]
232
+ # elif metadata and created:
233
+ # assert event["recurrence"] == ["Recurrence A"]
234
+ # else:
235
+ # assert event["recurrence"] == []
236
+
237
+ # def test_get_start_and_end(self):
238
+ # meta = {
239
+ # "start": {"dateTime": "2022-12-20T11:30:00+01:00", "timeZone": "Europe/Berlin"},
240
+ # "end": {"dateTime": "2022-12-20T12:30:00+01:00", "timeZone": "Europe/Berlin"},
241
+ # }
242
+ # meta_date = {
243
+ # "start": {"date": "2022-12-24"},
244
+ # "end": {"date": "2022-12-25"},
245
+ # }
246
+ # start, end = GoogleSyncUtils.get_start_and_end(meta)
247
+ # assert start == datetime.datetime(
248
+ # 2022, 12, 20, 11, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=3600))
249
+ # )
250
+ # assert end == datetime.datetime(
251
+ # 2022, 12, 20, 12, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=3600))
252
+ # )
253
+ # start, end = GoogleSyncUtils.get_start_and_end(meta_date)
254
+ # assert start == datetime.datetime(2022, 12, 24)
255
+ # assert end == datetime.datetime(2022, 12, 24, 23, 59, 59)
256
+
257
+ # @pytest.mark.parametrize(
258
+ # "organizer",
259
+ # ["", "Foo@Foo.com", "Bar@Bar.com"],
260
+ # )
261
+ # def test_get_person(self, person_factory, email_contact_factory, organizer):
262
+ # person_a: Person = person_factory()
263
+ # email_contact_factory(primary=True, entry=person_a, address="foo@foo.com")
264
+
265
+ # if organizer == "Foo@Foo.com":
266
+ # assert GoogleSyncUtils.get_or_create_person(organizer) == person_a
267
+ # elif organizer and (mail := organizer) == "Bar@Bar.com":
268
+ # creator = GoogleSyncUtils.get_or_create_person(mail)
269
+ # person_b = Person.objects.get(last_name=mail)
270
+ # assert EmailContact.objects.filter(entry=creator, address=mail.lower(), primary=True).exists()
271
+ # assert creator.id == person_b.id
272
+ # assert creator.last_name == mail
273
+ # else:
274
+ # assert GoogleSyncUtils.get_or_create_person(organizer) is None