wbintegrator_office365 2.2.1__py2.py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- 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/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-2.2.1.dist-info/METADATA +10 -0
- wbintegrator_office365-2.2.1.dist-info/RECORD +41 -0
- wbintegrator_office365-2.2.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
|
+
]
|