wbintegrator_office365 1.43.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.
- wbintegrator_office365/__init__.py +1 -0
- wbintegrator_office365/admin.py +209 -0
- wbintegrator_office365/apps.py +5 -0
- wbintegrator_office365/configurations/__init__.py +0 -0
- wbintegrator_office365/configurations/configurations/__init__.py +23 -0
- wbintegrator_office365/dynamic_preferences_registry.py +15 -0
- wbintegrator_office365/factories.py +102 -0
- wbintegrator_office365/filters.py +237 -0
- wbintegrator_office365/importer/__init__.py +3 -0
- wbintegrator_office365/importer/api.py +403 -0
- wbintegrator_office365/importer/disable_signals.py +43 -0
- wbintegrator_office365/importer/parser.py +135 -0
- wbintegrator_office365/kpi_handlers/__init__.py +1 -0
- wbintegrator_office365/kpi_handlers/calls.py +114 -0
- wbintegrator_office365/migrations/0001_initial_squashed_squashed_0003_alter_calendar_owner_alter_calendarevent_organizer_and_more.py +677 -0
- wbintegrator_office365/migrations/0002_remove_calendar_owner_remove_calendarevent_activity_and_more.py +85 -0
- wbintegrator_office365/migrations/0003_alter_event_options.py +20 -0
- wbintegrator_office365/migrations/__init__.py +0 -0
- wbintegrator_office365/models/__init__.py +3 -0
- wbintegrator_office365/models/event.py +623 -0
- wbintegrator_office365/models/subscription.py +144 -0
- wbintegrator_office365/models/tenant.py +62 -0
- wbintegrator_office365/serializers.py +266 -0
- wbintegrator_office365/tasks.py +108 -0
- wbintegrator_office365/templates/admin/tenant_change_list.html +12 -0
- wbintegrator_office365/tests/__init__.py +0 -0
- wbintegrator_office365/tests/conftest.py +28 -0
- wbintegrator_office365/tests/test_admin.py +86 -0
- wbintegrator_office365/tests/test_models.py +65 -0
- wbintegrator_office365/tests/test_tasks.py +318 -0
- wbintegrator_office365/tests/test_views.py +128 -0
- wbintegrator_office365/tests/tests.py +12 -0
- wbintegrator_office365/urls.py +46 -0
- wbintegrator_office365/viewsets/__init__.py +31 -0
- wbintegrator_office365/viewsets/display.py +306 -0
- wbintegrator_office365/viewsets/endpoints.py +52 -0
- wbintegrator_office365/viewsets/menu.py +65 -0
- wbintegrator_office365/viewsets/titles.py +49 -0
- wbintegrator_office365/viewsets/viewsets.py +745 -0
- wbintegrator_office365-1.43.1.dist-info/METADATA +10 -0
- wbintegrator_office365-1.43.1.dist-info/RECORD +42 -0
- wbintegrator_office365-1.43.1.dist-info/WHEEL +5 -0
@@ -0,0 +1,86 @@
|
|
1
|
+
from unittest.mock import patch
|
2
|
+
|
3
|
+
import pytest
|
4
|
+
from django.contrib.admin import AdminSite
|
5
|
+
from django.contrib.messages import get_messages, storage
|
6
|
+
from rest_framework import status
|
7
|
+
from rest_framework.test import APIRequestFactory
|
8
|
+
from wbcore.test.utils import get_or_create_superuser
|
9
|
+
from wbintegrator_office365.admin import SubscriptionAdmin, TenantUserAdmin
|
10
|
+
from wbintegrator_office365.factories import TenantUserFactory
|
11
|
+
from wbintegrator_office365.models import Subscription, TenantUser
|
12
|
+
|
13
|
+
|
14
|
+
@pytest.mark.django_db
|
15
|
+
class TestAdmin:
|
16
|
+
@pytest.fixture()
|
17
|
+
def fixture_request(self):
|
18
|
+
request = APIRequestFactory().get("")
|
19
|
+
request.session = {} # for sessions middleware
|
20
|
+
request._messages = storage.default_storage(request) # for messages middleware
|
21
|
+
request.user = get_or_create_superuser()
|
22
|
+
return request
|
23
|
+
|
24
|
+
@patch("wbintegrator_office365.importer.MicrosoftGraphAPI._get_access_token")
|
25
|
+
@patch("wbintegrator_office365.importer.MicrosoftGraphAPI.users")
|
26
|
+
def test_admin_fetch_tenantusers(self, mock_users, mock_access_token, fixture_request):
|
27
|
+
data = [
|
28
|
+
{
|
29
|
+
"id": "87d349ed-44d7-43e1-9a83-5f2406dee5bd",
|
30
|
+
"display_name": "contoso1",
|
31
|
+
"email": "contoso1_gmail.com#EXT#@microsoft.onmicrosoft.com",
|
32
|
+
}
|
33
|
+
]
|
34
|
+
mock_users.return_value.status_code = status.HTTP_200_OK
|
35
|
+
mock_users.return_value = data
|
36
|
+
|
37
|
+
mock_access_token.return_value.status_code = status.HTTP_200_OK
|
38
|
+
mock_access_token.return_value = "FAKE_TOKEN"
|
39
|
+
|
40
|
+
TenantUserFactory()
|
41
|
+
mma = TenantUserAdmin(TenantUser, AdminSite())
|
42
|
+
|
43
|
+
storages = get_messages(fixture_request)
|
44
|
+
assert len(storages) == 0
|
45
|
+
|
46
|
+
response = mma._fetch_tenantusers(fixture_request)
|
47
|
+
|
48
|
+
storages = get_messages(fixture_request)
|
49
|
+
assert len(storages) == 1
|
50
|
+
assert mock_users.call_count == 1
|
51
|
+
assert response.status_code == status.HTTP_302_FOUND
|
52
|
+
|
53
|
+
def test_disable_selected_subscriptions(self, subscription_factory, fixture_request):
|
54
|
+
obj = subscription_factory()
|
55
|
+
mma = SubscriptionAdmin(TenantUser, AdminSite())
|
56
|
+
storages = get_messages(fixture_request)
|
57
|
+
assert len(storages) == 0
|
58
|
+
assert obj.is_enable is True
|
59
|
+
mma.disable_selected_subscriptions(fixture_request, Subscription.objects.all())
|
60
|
+
obj.refresh_from_db()
|
61
|
+
assert obj.is_enable is False
|
62
|
+
|
63
|
+
storages = get_messages(fixture_request)
|
64
|
+
assert len(storages) == 1
|
65
|
+
|
66
|
+
def test_verification_selected_subscriptions(self, subscription_factory, fixture_request):
|
67
|
+
obj = subscription_factory()
|
68
|
+
mma = SubscriptionAdmin(TenantUser, AdminSite())
|
69
|
+
storages = get_messages(fixture_request)
|
70
|
+
assert len(storages) == 0
|
71
|
+
assert obj.is_enable is True
|
72
|
+
mma.verification_selected_subscriptions(fixture_request, Subscription.objects.all())
|
73
|
+
|
74
|
+
storages = get_messages(fixture_request)
|
75
|
+
assert len(storages) == 1
|
76
|
+
|
77
|
+
def test_renew_selected_subscriptions(self, subscription_factory, fixture_request):
|
78
|
+
obj = subscription_factory()
|
79
|
+
mma = SubscriptionAdmin(TenantUser, AdminSite())
|
80
|
+
storages = get_messages(fixture_request)
|
81
|
+
assert len(storages) == 0
|
82
|
+
assert obj.is_enable is True
|
83
|
+
mma.renew_selected_subscriptions(fixture_request, Subscription.objects.all())
|
84
|
+
|
85
|
+
storages = get_messages(fixture_request)
|
86
|
+
assert len(storages) == 1
|
@@ -0,0 +1,65 @@
|
|
1
|
+
from unittest.mock import patch
|
2
|
+
|
3
|
+
import pytest
|
4
|
+
from wbintegrator_office365.factories import EventFactory, SubscriptionFactory
|
5
|
+
from wbintegrator_office365.importer import DisableSignals
|
6
|
+
from wbintegrator_office365.models import (
|
7
|
+
CallEvent,
|
8
|
+
CallUser,
|
9
|
+
Event,
|
10
|
+
Subscription,
|
11
|
+
TenantUser,
|
12
|
+
)
|
13
|
+
|
14
|
+
|
15
|
+
@pytest.mark.django_db
|
16
|
+
class TestModels:
|
17
|
+
def test_tenantuser(self, tenant_user_factory):
|
18
|
+
assert TenantUser.objects.count() == 0
|
19
|
+
tenant_user_factory()
|
20
|
+
assert TenantUser.objects.count() == 1
|
21
|
+
|
22
|
+
def test_event(self, event_factory):
|
23
|
+
assert Event.objects.count() == 0
|
24
|
+
# obj = event_factory() # there is a confusion with another model event from another app
|
25
|
+
EventFactory()
|
26
|
+
assert Event.objects.count() == 1
|
27
|
+
|
28
|
+
@patch("wbintegrator_office365.models.subscription.unsubscribe.delay")
|
29
|
+
@patch("wbintegrator_office365.models.subscription.chain")
|
30
|
+
@patch("requests.post")
|
31
|
+
def test_subscription(self, mock_post, mock_chain, mock_unsubscribe):
|
32
|
+
with patch("wbintegrator_office365.models.event.transaction.on_commit", new=lambda fn: fn()):
|
33
|
+
assert Subscription.objects.count() == 0
|
34
|
+
assert mock_chain.call_count == 0
|
35
|
+
SubscriptionFactory()
|
36
|
+
assert Subscription.objects.count() == 1
|
37
|
+
assert mock_chain.call_count == 0
|
38
|
+
|
39
|
+
assert mock_unsubscribe.call_count == 0
|
40
|
+
SubscriptionFactory(is_enable=False)
|
41
|
+
assert mock_chain.call_count == 1
|
42
|
+
|
43
|
+
def test_call_event_disconnect_signal(self, call_event_factory):
|
44
|
+
assert CallEvent.objects.count() == 0
|
45
|
+
with DisableSignals():
|
46
|
+
call_event_factory()
|
47
|
+
assert CallEvent.objects.count() == 1
|
48
|
+
|
49
|
+
def test_call_event(self, call_event_factory):
|
50
|
+
assert CallEvent.objects.count() == 0
|
51
|
+
call_event_factory()
|
52
|
+
assert CallEvent.objects.count() == 1
|
53
|
+
|
54
|
+
def test_call_user(self, call_user_factory):
|
55
|
+
assert CallUser.objects.count() == 0
|
56
|
+
call_user_factory()
|
57
|
+
assert CallUser.objects.count() == 1
|
58
|
+
|
59
|
+
def test_post_save_participant_event(self, call_event_factory, call_user_factory):
|
60
|
+
obj = call_event_factory()
|
61
|
+
call_user = call_user_factory()
|
62
|
+
obj.participants.add(call_user)
|
63
|
+
assert obj.is_internal_call is False
|
64
|
+
obj.participants.remove(call_user)
|
65
|
+
assert obj.is_internal_call is True
|
@@ -0,0 +1,318 @@
|
|
1
|
+
from datetime import timedelta
|
2
|
+
from unittest.mock import patch
|
3
|
+
|
4
|
+
import pandas as pd
|
5
|
+
import phonenumbers
|
6
|
+
import pytest
|
7
|
+
from rest_framework import status
|
8
|
+
from wbcore.contrib.directory.factories import TelephoneContactFactory
|
9
|
+
from wbintegrator_office365.factories import SubscriptionFactory, TenantUserFactory
|
10
|
+
from wbintegrator_office365.importer import parse
|
11
|
+
from wbintegrator_office365.models import CallEvent, Subscription
|
12
|
+
from wbintegrator_office365.models.event import fetch_tenantusers
|
13
|
+
from wbintegrator_office365.models.subscription import (
|
14
|
+
subscribe,
|
15
|
+
unsubscribe,
|
16
|
+
verification_subscriptions,
|
17
|
+
)
|
18
|
+
|
19
|
+
|
20
|
+
# This method will be used by the mock to replace requests.get
|
21
|
+
class MockResponse:
|
22
|
+
def __init__(self, json_data, status_code):
|
23
|
+
self.json_data = json_data
|
24
|
+
self.status_code = status_code
|
25
|
+
|
26
|
+
def json(self):
|
27
|
+
return self.json_data
|
28
|
+
|
29
|
+
|
30
|
+
@pytest.mark.django_db
|
31
|
+
class TestTaskSubscription:
|
32
|
+
@patch("wbintegrator_office365.importer.MicrosoftGraphAPI._get_access_token")
|
33
|
+
@patch("wbintegrator_office365.importer.api.requests.post")
|
34
|
+
def test_subscribe(self, mock_post, mock_access_token):
|
35
|
+
obj = SubscriptionFactory(type_resource=Subscription.TypeResource.CALLRECORD)
|
36
|
+
data = {
|
37
|
+
"@odata.context": "https://graph.microsoft.com/v1.0/$metadata#subscriptions/$entity",
|
38
|
+
"value": [
|
39
|
+
{
|
40
|
+
"id": "7f105c7d-2dc5-4530-97cd-4e7ae6534c07",
|
41
|
+
"resource": "me/mailFolders('Inbox')/messages",
|
42
|
+
"applicationId": "24d3b144-21ae-4080-943f-7067b395b913",
|
43
|
+
"changeType": "created",
|
44
|
+
"clientState": "secretClientValue",
|
45
|
+
"notificationUrl": "https://webhook.azurewebsites.net/api/send/myNotifyClient",
|
46
|
+
"expirationDateTime": "2016-11-20T18:23:45.9356913Z",
|
47
|
+
"creatorId": "8ee44408-0679-472c-bc2a-692812af3437",
|
48
|
+
"latestSupportedTlsVersion": "v1_2",
|
49
|
+
}
|
50
|
+
],
|
51
|
+
}
|
52
|
+
data = parse(pd.json_normalize(data.get("value")))[0]
|
53
|
+
mock_access_token.return_value.status_code = status.HTTP_200_OK
|
54
|
+
mock_access_token.return_value = "FAKE_TOKEN"
|
55
|
+
|
56
|
+
mock_post.return_value = MockResponse(data, 201)
|
57
|
+
assert obj.subscription_id != data.get("id")
|
58
|
+
subscribe(obj.id, "/communications/callRecords")
|
59
|
+
assert mock_post.call_count == 1
|
60
|
+
obj = Subscription.objects.get(id=obj.id)
|
61
|
+
assert obj.subscription_id == data.get("id")
|
62
|
+
|
63
|
+
@patch("wbintegrator_office365.importer.MicrosoftGraphAPI.users")
|
64
|
+
@patch("wbintegrator_office365.models.subscription.chain")
|
65
|
+
def test_post_save_subscription(self, mock_chain, mock_users):
|
66
|
+
with patch("wbintegrator_office365.models.event.transaction.on_commit", new=lambda fn: fn()):
|
67
|
+
mock_chain.return_value.status_code = 200
|
68
|
+
mock_users.return_value.status_code = 200
|
69
|
+
|
70
|
+
tenant = TenantUserFactory()
|
71
|
+
mock_users.return_value = [{"id": tenant.tenant_id}]
|
72
|
+
|
73
|
+
assert mock_chain.call_count == 0
|
74
|
+
SubscriptionFactory(
|
75
|
+
is_enable=True, type_resource=Subscription.TypeResource.CALLRECORD, expiration_date=None
|
76
|
+
)
|
77
|
+
assert mock_chain.call_count == 1
|
78
|
+
SubscriptionFactory(
|
79
|
+
subscription_id=None,
|
80
|
+
is_enable=True,
|
81
|
+
tenant_user=tenant,
|
82
|
+
type_resource=Subscription.TypeResource.CALENDAR,
|
83
|
+
)
|
84
|
+
assert mock_chain.call_count == 1
|
85
|
+
|
86
|
+
@pytest.mark.parametrize("type_resource", ["CALLRECORD", "CALENDAR"])
|
87
|
+
@patch("wbintegrator_office365.models.subscription.chain")
|
88
|
+
@patch("wbintegrator_office365.importer.MicrosoftGraphAPI.users")
|
89
|
+
@patch("requests.patch")
|
90
|
+
def test_resubscribe(self, mock_patch, mock_users, mock_chain, type_resource):
|
91
|
+
if type_resource == Subscription.TypeResource.CALLRECORD:
|
92
|
+
obj = SubscriptionFactory(is_enable=True, type_resource=Subscription.TypeResource.CALLRECORD)
|
93
|
+
else:
|
94
|
+
mock_users.return_value.status_code = 200
|
95
|
+
tenant = TenantUserFactory()
|
96
|
+
mock_users.return_value = [{"id": tenant.tenant_id}]
|
97
|
+
obj = SubscriptionFactory(
|
98
|
+
is_enable=True, tenant_user=tenant, type_resource=Subscription.TypeResource.CALENDAR
|
99
|
+
)
|
100
|
+
data = {"expiration": obj.expiration_date + timedelta(days=2), "notification_url": "fake_url"}
|
101
|
+
mock_patch.return_value.status_code = 200
|
102
|
+
mock_patch.return_value.json.return_value = data
|
103
|
+
|
104
|
+
assert mock_patch.call_count == 0
|
105
|
+
obj.resubscribe()
|
106
|
+
assert mock_patch.call_count == 1
|
107
|
+
|
108
|
+
obj = Subscription.objects.get(id=obj.id)
|
109
|
+
assert obj.expiration_date == data.get("expiration")
|
110
|
+
|
111
|
+
@patch("wbintegrator_office365.models.subscription.chain")
|
112
|
+
@patch("requests.get")
|
113
|
+
def test_verification_subscriptions(self, mock_get, mock_chain):
|
114
|
+
with patch("wbintegrator_office365.models.event.transaction.on_commit", new=lambda fn: fn()):
|
115
|
+
data = {"value": [{"id": "fake_id"}]}
|
116
|
+
mock_get.return_value.status_code = 200
|
117
|
+
mock_get.return_value.json.return_value = data
|
118
|
+
|
119
|
+
obj = SubscriptionFactory(
|
120
|
+
expiration_date=None, type_resource="CALLRECORD", is_enable=True, subscription_id="fake_id"
|
121
|
+
)
|
122
|
+
obj2 = SubscriptionFactory(
|
123
|
+
subscription_id=None, type_resource="CALENDAR", is_enable=True, tenant_user=TenantUserFactory()
|
124
|
+
)
|
125
|
+
obj2.subscription_id = "other_fake_id"
|
126
|
+
obj2.save()
|
127
|
+
|
128
|
+
assert mock_chain.call_count == 1
|
129
|
+
assert mock_get.call_count == 0
|
130
|
+
verification_subscriptions(obj.id)
|
131
|
+
assert mock_get.call_count == 1
|
132
|
+
verification_subscriptions(obj2.id)
|
133
|
+
assert mock_get.call_count == 2
|
134
|
+
|
135
|
+
assert Subscription.objects.get(id=obj.id).is_enable is True
|
136
|
+
assert Subscription.objects.get(id=obj2.id).is_enable is False
|
137
|
+
|
138
|
+
@patch("requests.delete")
|
139
|
+
def test_unsubscribe(self, mock_delete):
|
140
|
+
mock_delete.return_value.status_code = 204
|
141
|
+
obj = SubscriptionFactory(is_enable=True)
|
142
|
+
assert mock_delete.call_count == 0
|
143
|
+
unsubscribe(obj.id)
|
144
|
+
assert mock_delete.call_count == 1
|
145
|
+
|
146
|
+
|
147
|
+
data = {
|
148
|
+
"@odata.context": "https://graph.microsoft.com/v1.0/$metadata#communications/callRecords/$entity",
|
149
|
+
"version": 1,
|
150
|
+
"type": "peerToPeer",
|
151
|
+
"modalities": ["audio"],
|
152
|
+
"lastModifiedDateTime": "2020-02-25T19:00:24.582757Z",
|
153
|
+
"startDateTime": "2020-02-25T18:52:21.2169889Z",
|
154
|
+
"endDateTime": "2020-02-25T18:52:46.7640013Z",
|
155
|
+
"id": "e523d2ed-2966-4b6b-925b-754a88034cc5",
|
156
|
+
"organizer": {
|
157
|
+
"user": {
|
158
|
+
"id": "821809f5-0000-0000-0000-3b5136c0e777",
|
159
|
+
"displayName": "Abbie Wilkins",
|
160
|
+
"tenantId": "dc368399-474c-4d40-900c-6265431fd81f",
|
161
|
+
}
|
162
|
+
},
|
163
|
+
"participants": [
|
164
|
+
{
|
165
|
+
"user": {
|
166
|
+
"id": "821809f5-0000-0000-0000-3b5136c0e777",
|
167
|
+
"displayName": "Abbie Wilkins",
|
168
|
+
"tenantId": "dc368399-474c-4d40-900c-6265431fd81f",
|
169
|
+
}
|
170
|
+
},
|
171
|
+
{
|
172
|
+
"user": {
|
173
|
+
"id": "f69e2c00-0000-0000-0000-185e5f5f5d8a",
|
174
|
+
"displayName": "Owen Franklin",
|
175
|
+
"tenantId": "dc368399-474c-4d40-900c-6265431fd81f",
|
176
|
+
}
|
177
|
+
},
|
178
|
+
],
|
179
|
+
}
|
180
|
+
|
181
|
+
data_with_guest_user = {
|
182
|
+
"@odata.context": "https://graph.microsoft.com/v1.0/$metadata#communications/callRecords/$entity",
|
183
|
+
"version": 1,
|
184
|
+
"type": "peerToPeer",
|
185
|
+
"modalities": ["audio"],
|
186
|
+
"lastModifiedDateTime": "2020-02-25T19:00:24.582757Z",
|
187
|
+
"startDateTime": "2020-02-25T18:52:21.2169889Z",
|
188
|
+
"endDateTime": "2020-02-25T18:52:46.7640013Z",
|
189
|
+
"id": "e523d2ed-2966-4b6b-925b-754a88034cc5",
|
190
|
+
"organizer": {
|
191
|
+
"user": {
|
192
|
+
"id": "821809f5-0000-0000-0000-3b5136c0e777",
|
193
|
+
"displayName": "Abbie Wilkins",
|
194
|
+
"tenantId": "dc368399-474c-4d40-900c-6265431fd81f",
|
195
|
+
}
|
196
|
+
},
|
197
|
+
"participants": [
|
198
|
+
{
|
199
|
+
"user": None,
|
200
|
+
"acsUser": None,
|
201
|
+
"spoolUser": None,
|
202
|
+
"phone": None,
|
203
|
+
"guest": {"id": "c6f4f18f1e99401a9193fbf954f6e903", "displayName": "Guest user", "tenantId": None},
|
204
|
+
"encrypted": None,
|
205
|
+
"onPremises": None,
|
206
|
+
"acsApplicationInstance": None,
|
207
|
+
"spoolApplicationInstance": None,
|
208
|
+
"applicationInstance": None,
|
209
|
+
"application": None,
|
210
|
+
"device": None,
|
211
|
+
},
|
212
|
+
{
|
213
|
+
"acsUser": None,
|
214
|
+
"spoolUser": None,
|
215
|
+
"phone": None,
|
216
|
+
"guest": None,
|
217
|
+
"encrypted": None,
|
218
|
+
"onPremises": None,
|
219
|
+
"acsApplicationInstance": None,
|
220
|
+
"spoolApplicationInstance": None,
|
221
|
+
"applicationInstance": None,
|
222
|
+
"application": None,
|
223
|
+
"device": None,
|
224
|
+
"user": {
|
225
|
+
"id": "303eecac-5bf1-44df-96c2-2aae187d46d1",
|
226
|
+
"displayName": "External user",
|
227
|
+
"tenantId": "9692a3d3-2a08-4ec8-a0bd-1db355eb4230",
|
228
|
+
},
|
229
|
+
},
|
230
|
+
],
|
231
|
+
}
|
232
|
+
|
233
|
+
data_with_guest_organiser = {
|
234
|
+
"@odata.context": "https://graph.microsoft.com/v1.0/$metadata#communications/callRecords/$entity",
|
235
|
+
"version": 1,
|
236
|
+
"type": "peerToPeer",
|
237
|
+
"modalities": ["audio"],
|
238
|
+
"lastModifiedDateTime": "2020-02-25T19:00:24.582757Z",
|
239
|
+
"startDateTime": "2020-02-25T18:52:21.2169889Z",
|
240
|
+
"endDateTime": "2020-02-25T18:52:46.7640013Z",
|
241
|
+
"id": "e523d2ed-2966-4b6b-925b-754a88034cc5",
|
242
|
+
"organizer": {
|
243
|
+
"user": None,
|
244
|
+
"guest": {
|
245
|
+
"id": "821809f5-0000-0000-0000-3b5136c0e777",
|
246
|
+
"displayName": "Abbie Wilkins",
|
247
|
+
"tenantId": "dc368399-474c-4d40-900c-6265431fd81f",
|
248
|
+
},
|
249
|
+
},
|
250
|
+
"participants": [],
|
251
|
+
}
|
252
|
+
|
253
|
+
data_with_phone_organiser = {
|
254
|
+
"@odata.context": "https://graph.microsoft.com/v1.0/$metadata#communications/callRecords/$entity",
|
255
|
+
"version": 1,
|
256
|
+
"type": "peerToPeer",
|
257
|
+
"modalities": ["audio"],
|
258
|
+
"lastModifiedDateTime": "2020-02-25T19:00:24.582757Z",
|
259
|
+
"startDateTime": "2020-02-25T18:52:21.2169889Z",
|
260
|
+
"endDateTime": "2020-02-25T18:52:46.7640013Z",
|
261
|
+
"id": "e523d2ed-2966-4b6b-925b-754a88034cc5",
|
262
|
+
"organizer": {
|
263
|
+
"user": None,
|
264
|
+
"guest": None,
|
265
|
+
"phone": {"id": "+41223178146", "displayName": "None", "tenantId": "None"},
|
266
|
+
},
|
267
|
+
"participants": [],
|
268
|
+
}
|
269
|
+
|
270
|
+
|
271
|
+
@pytest.mark.django_db
|
272
|
+
class TestTasksCall:
|
273
|
+
@patch("wbintegrator_office365.importer.MicrosoftGraphAPI.users")
|
274
|
+
def test_fetch_tenantusers(self, mock_users):
|
275
|
+
data = [
|
276
|
+
{
|
277
|
+
"id": "87d349ed-44d7-43e1-9a83-5f2406dee5bd",
|
278
|
+
"display_name": "contoso1",
|
279
|
+
"email": "contoso1_gmail.com#EXT#@microsoft.onmicrosoft.com",
|
280
|
+
}
|
281
|
+
]
|
282
|
+
mock_users.return_value.status_code = 200
|
283
|
+
mock_users.return_value = data
|
284
|
+
datum, count_added = fetch_tenantusers()
|
285
|
+
assert mock_users.call_count == 1
|
286
|
+
assert datum == data
|
287
|
+
assert count_added == 1
|
288
|
+
|
289
|
+
@patch("requests.get")
|
290
|
+
@pytest.mark.parametrize(
|
291
|
+
"data", [data, data_with_guest_user, data_with_guest_organiser, data_with_phone_organiser]
|
292
|
+
)
|
293
|
+
def test_fetch_call(self, mock_get, data, event_factory):
|
294
|
+
event = event_factory(uuid_event="87d349ed-44d7-43e1-9a83-5f2406dee5bd")
|
295
|
+
mock_get.return_value.status_code = 200
|
296
|
+
mock_get.return_value.json.return_value = parse(pd.json_normalize(data))
|
297
|
+
|
298
|
+
assert CallEvent.objects.count() == 0
|
299
|
+
event.fetch_call()
|
300
|
+
assert mock_get.call_count == 1
|
301
|
+
assert CallEvent.objects.count() == 1
|
302
|
+
|
303
|
+
@patch("requests.get")
|
304
|
+
@pytest.mark.parametrize("data", [data_with_phone_organiser])
|
305
|
+
def test_fetch_call_phone(self, mock_get, data, event_factory):
|
306
|
+
event = event_factory(uuid_event="87d349ed-44d7-43e1-9a83-5f2406dee5bd")
|
307
|
+
mock_get.return_value.status_code = 200
|
308
|
+
mock_get.return_value.json.return_value = parse(pd.json_normalize(data))
|
309
|
+
|
310
|
+
my_number = "+41 22 317 81 46"
|
311
|
+
parser_number = phonenumbers.parse(my_number, "CH")
|
312
|
+
phone_numbers = phonenumbers.format_number(parser_number, phonenumbers.PhoneNumberFormat.E164)
|
313
|
+
TelephoneContactFactory(number=phone_numbers)
|
314
|
+
|
315
|
+
assert CallEvent.objects.count() == 0
|
316
|
+
event.fetch_call()
|
317
|
+
assert mock_get.call_count == 1
|
318
|
+
assert CallEvent.objects.count() == 1
|
@@ -0,0 +1,128 @@
|
|
1
|
+
from datetime import timedelta
|
2
|
+
from unittest.mock import patch
|
3
|
+
|
4
|
+
import pytest
|
5
|
+
from rest_framework import status
|
6
|
+
from rest_framework.test import APIRequestFactory
|
7
|
+
from wbcore.contrib.authentication.factories import InternalUserFactory
|
8
|
+
from wbcore.test.utils import get_or_create_superuser
|
9
|
+
from wbhuman_resources.factories import EmployeeHumanResourceFactory
|
10
|
+
from wbintegrator_office365.factories import CallEventFactory, CallUserFactory
|
11
|
+
from wbintegrator_office365.viewsets.viewsets import (
|
12
|
+
CallEventReceptionTime,
|
13
|
+
CallEventSummaryGraph,
|
14
|
+
callback_consent_permission,
|
15
|
+
listen,
|
16
|
+
)
|
17
|
+
|
18
|
+
|
19
|
+
@pytest.mark.django_db
|
20
|
+
class TestView:
|
21
|
+
@pytest.mark.parametrize(
|
22
|
+
"mvs, factory",
|
23
|
+
[
|
24
|
+
(CallEventReceptionTime, CallEventFactory),
|
25
|
+
(CallEventSummaryGraph, CallEventFactory),
|
26
|
+
],
|
27
|
+
)
|
28
|
+
@patch("wbintegrator_office365.importer.MicrosoftGraphAPI._get_access_token")
|
29
|
+
@patch("wbintegrator_office365.importer.MicrosoftGraphAPI.users")
|
30
|
+
@patch("wbintegrator_office365.importer.MicrosoftGraphAPI.get_calendar_event")
|
31
|
+
def test_option_request(self, mock_calendar_event, mock_users, mock_acess, mvs, factory):
|
32
|
+
request = APIRequestFactory().options("")
|
33
|
+
request.user = get_or_create_superuser()
|
34
|
+
factory()
|
35
|
+
kwargs = {"user_id": request.user.id}
|
36
|
+
vs = mvs.as_view({"options": "options"})
|
37
|
+
response = vs(request, **kwargs)
|
38
|
+
assert response.status_code == status.HTTP_200_OK
|
39
|
+
assert response.data
|
40
|
+
|
41
|
+
@pytest.mark.parametrize(
|
42
|
+
"mvs, factory",
|
43
|
+
[
|
44
|
+
(CallEventReceptionTime, CallEventFactory),
|
45
|
+
(CallEventSummaryGraph, CallEventFactory),
|
46
|
+
],
|
47
|
+
)
|
48
|
+
def test_get_plotly(self, mvs, factory):
|
49
|
+
request = APIRequestFactory().get("")
|
50
|
+
request.user = get_or_create_superuser()
|
51
|
+
_mvs = mvs(request=request)
|
52
|
+
fig = _mvs.get_plotly(_mvs.queryset)
|
53
|
+
assert fig
|
54
|
+
|
55
|
+
factory()
|
56
|
+
_mvs = mvs(request=request)
|
57
|
+
fig = _mvs.get_plotly(_mvs.queryset)
|
58
|
+
assert fig
|
59
|
+
|
60
|
+
@pytest.mark.parametrize(
|
61
|
+
"mvs, factory, empty_compare_employee",
|
62
|
+
[(CallEventSummaryGraph, CallEventFactory, True), (CallEventSummaryGraph, CallEventFactory, False)],
|
63
|
+
)
|
64
|
+
@patch("wbintegrator_office365.importer.MicrosoftGraphAPI._get_access_token")
|
65
|
+
@patch("wbintegrator_office365.importer.MicrosoftGraphAPI.users")
|
66
|
+
def test_get_plotly_CallEventSummaryGraph(self, mock_users, mock_acess, mvs, factory, empty_compare_employee):
|
67
|
+
request = APIRequestFactory().get("")
|
68
|
+
request.user = get_or_create_superuser()
|
69
|
+
|
70
|
+
obj = factory(is_internal_call=True)
|
71
|
+
obj.end = obj.start + timedelta(seconds=60)
|
72
|
+
person = InternalUserFactory().profile
|
73
|
+
employee = EmployeeHumanResourceFactory(profile=person)
|
74
|
+
|
75
|
+
if not empty_compare_employee:
|
76
|
+
call_user = CallUserFactory(tenant_user__profile=person)
|
77
|
+
factory(start=obj.start, end=obj.end, type=obj.type, is_internal_call=True, participants=(call_user,))
|
78
|
+
|
79
|
+
request.GET = request.GET.copy()
|
80
|
+
request.GET["compare_employee"] = employee.id
|
81
|
+
request.GET["start"] = str(obj.start.date())
|
82
|
+
request.GET["end"] = str(obj.end.date() + timedelta(days=30))
|
83
|
+
request.GET["call_duration"] = (obj.end - obj.start).total_seconds()
|
84
|
+
request.GET["call_type"] = obj.type
|
85
|
+
request.GET["call_area"] = obj.is_internal_call
|
86
|
+
request.GET["business_day_without_call"] = "true"
|
87
|
+
_mvs = mvs(request=request)
|
88
|
+
fig = _mvs.get_plotly(_mvs.get_queryset())
|
89
|
+
assert fig
|
90
|
+
|
91
|
+
@pytest.mark.parametrize("view", [callback_consent_permission])
|
92
|
+
def test_callback_consent_permission(self, view):
|
93
|
+
factory = APIRequestFactory()
|
94
|
+
request = factory.get("")
|
95
|
+
response = view(request)
|
96
|
+
assert response.status_code == status.HTTP_200_OK
|
97
|
+
|
98
|
+
data = {
|
99
|
+
"value": [
|
100
|
+
{
|
101
|
+
"change_type": "created",
|
102
|
+
"subscription_id": "82507f73-75c5-4295-8ac4-5bf55f38541f",
|
103
|
+
"resource": "communications/callRecords/af419444-a189-499c-967b-1aae574b2cc1",
|
104
|
+
"resource_data": {"id": "af419444-a189-499c-967b-1aae574b2cc1"},
|
105
|
+
}
|
106
|
+
]
|
107
|
+
}
|
108
|
+
|
109
|
+
@patch("wbintegrator_office365.models.event.handle_event_from_webhook.delay")
|
110
|
+
@pytest.mark.parametrize(
|
111
|
+
"view, validation_token, request_body",
|
112
|
+
[(listen, None, None), (listen, "validationToken", None), (listen, None, data)],
|
113
|
+
)
|
114
|
+
def test_listen(self, handle_event, view, validation_token, request_body, event_factory):
|
115
|
+
with patch("wbintegrator_office365.viewsets.viewsets.transaction.on_commit", new=lambda fn: fn()):
|
116
|
+
factory = APIRequestFactory()
|
117
|
+
request = factory.post("", request_body, format="json")
|
118
|
+
if validation_token:
|
119
|
+
request.GET = request.GET.copy()
|
120
|
+
request.GET["validationToken"] = "fake_validation_token"
|
121
|
+
assert handle_event.call_count == 0
|
122
|
+
for i in range(1, 3):
|
123
|
+
response = view(request)
|
124
|
+
if request_body:
|
125
|
+
assert handle_event.call_count == i
|
126
|
+
else:
|
127
|
+
assert handle_event.call_count == 0
|
128
|
+
assert response.status_code == status.HTTP_200_OK
|
@@ -0,0 +1,12 @@
|
|
1
|
+
import pytest
|
2
|
+
from wbcore.test import GenerateTest, default_config
|
3
|
+
|
4
|
+
config = {}
|
5
|
+
for key, value in default_config.items():
|
6
|
+
config[key] = list(filter(lambda x: x.__module__.startswith("wbintegrator_office365"), value))
|
7
|
+
|
8
|
+
|
9
|
+
@pytest.mark.django_db
|
10
|
+
@GenerateTest(config)
|
11
|
+
class TestProject:
|
12
|
+
pass
|
@@ -0,0 +1,46 @@
|
|
1
|
+
from django.urls import include, path
|
2
|
+
from wbcore.routers import WBCoreRouter
|
3
|
+
from wbintegrator_office365.viewsets import viewsets
|
4
|
+
|
5
|
+
router = WBCoreRouter()
|
6
|
+
router.register(
|
7
|
+
r"tenantuserrepresentation", viewsets.TenantUserRepresentationViewSet, basename="tenantuserrepresentation"
|
8
|
+
)
|
9
|
+
router.register(r"tenantuser", viewsets.TenantUserViewSet)
|
10
|
+
|
11
|
+
router.register(
|
12
|
+
r"subscriptionrepresentation", viewsets.SubscriptionRepresentationViewSet, basename="subscriptionrepresentation"
|
13
|
+
)
|
14
|
+
router.register(r"subscription", viewsets.SubscriptionViewSet, basename="subscription")
|
15
|
+
|
16
|
+
router.register(r"eventrepresentation", viewsets.EventRepresentationViewSet, basename="eventrepresentation")
|
17
|
+
router.register(r"event", viewsets.EventViewSet, basename="event")
|
18
|
+
|
19
|
+
router.register(r"calluserrepresentation", viewsets.CallUserRepresentationViewSet, basename="calluserrepresentation")
|
20
|
+
router.register(r"calluser", viewsets.CallUserViewSet, basename="calluser")
|
21
|
+
|
22
|
+
router.register(
|
23
|
+
r"calleventrepresentation", viewsets.CallEventRepresentationViewSet, basename="calleventrepresentation"
|
24
|
+
)
|
25
|
+
router.register(r"callevent", viewsets.CallEventViewSet, basename="callevent")
|
26
|
+
|
27
|
+
router.register(r"calleventchart", viewsets.CallEventReceptionTime, basename="calleventchart")
|
28
|
+
router.register(r"calleventsummarygraph", viewsets.CallEventSummaryGraph, basename="calleventsummarygraph")
|
29
|
+
|
30
|
+
router.register(r"eventlog", viewsets.EventLogViewSet, basename="eventlog")
|
31
|
+
router.register(r"eventlog", viewsets.EventLogRepresentationViewSet, basename="eventlogrepresentation")
|
32
|
+
|
33
|
+
event_router = WBCoreRouter()
|
34
|
+
event_router.register(
|
35
|
+
r"eventlog",
|
36
|
+
viewsets.EventLogEventViewSet,
|
37
|
+
basename="event-eventlog",
|
38
|
+
)
|
39
|
+
|
40
|
+
|
41
|
+
urlpatterns = [
|
42
|
+
path("", include(router.urls)),
|
43
|
+
path("event/<str:last_event_id>/", include(event_router.urls)),
|
44
|
+
path("listen", viewsets.listen, name="listen"),
|
45
|
+
path("callback/permissions", viewsets.callback_consent_permission),
|
46
|
+
]
|