wbintegrator_office365 2.2.1__tar.gz

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. wbintegrator_office365-2.2.1/.gitignore +181 -0
  2. wbintegrator_office365-2.2.1/PKG-INFO +10 -0
  3. wbintegrator_office365-2.2.1/pyproject.toml +36 -0
  4. wbintegrator_office365-2.2.1/wbintegrator_office365/__init__.py +1 -0
  5. wbintegrator_office365-2.2.1/wbintegrator_office365/admin.py +209 -0
  6. wbintegrator_office365-2.2.1/wbintegrator_office365/apps.py +5 -0
  7. wbintegrator_office365-2.2.1/wbintegrator_office365/configurations/__init__.py +0 -0
  8. wbintegrator_office365-2.2.1/wbintegrator_office365/configurations/configurations/__init__.py +23 -0
  9. wbintegrator_office365-2.2.1/wbintegrator_office365/dynamic_preferences_registry.py +15 -0
  10. wbintegrator_office365-2.2.1/wbintegrator_office365/factories.py +102 -0
  11. wbintegrator_office365-2.2.1/wbintegrator_office365/filters.py +237 -0
  12. wbintegrator_office365-2.2.1/wbintegrator_office365/importer/__init__.py +3 -0
  13. wbintegrator_office365-2.2.1/wbintegrator_office365/importer/api.py +403 -0
  14. wbintegrator_office365-2.2.1/wbintegrator_office365/importer/disable_signals.py +43 -0
  15. wbintegrator_office365-2.2.1/wbintegrator_office365/importer/parser.py +135 -0
  16. wbintegrator_office365-2.2.1/wbintegrator_office365/kpi_handlers/__init__.py +1 -0
  17. wbintegrator_office365-2.2.1/wbintegrator_office365/kpi_handlers/calls.py +114 -0
  18. wbintegrator_office365-2.2.1/wbintegrator_office365/migrations/0001_initial_squashed_squashed_0003_alter_calendar_owner_alter_calendarevent_organizer_and_more.py +677 -0
  19. wbintegrator_office365-2.2.1/wbintegrator_office365/migrations/0002_remove_calendar_owner_remove_calendarevent_activity_and_more.py +85 -0
  20. wbintegrator_office365-2.2.1/wbintegrator_office365/migrations/0003_alter_event_options.py +20 -0
  21. wbintegrator_office365-2.2.1/wbintegrator_office365/migrations/__init__.py +0 -0
  22. wbintegrator_office365-2.2.1/wbintegrator_office365/models/__init__.py +3 -0
  23. wbintegrator_office365-2.2.1/wbintegrator_office365/models/event.py +623 -0
  24. wbintegrator_office365-2.2.1/wbintegrator_office365/models/subscription.py +144 -0
  25. wbintegrator_office365-2.2.1/wbintegrator_office365/models/tenant.py +62 -0
  26. wbintegrator_office365-2.2.1/wbintegrator_office365/serializers.py +266 -0
  27. wbintegrator_office365-2.2.1/wbintegrator_office365/tasks.py +108 -0
  28. wbintegrator_office365-2.2.1/wbintegrator_office365/templates/admin/tenant_change_list.html +12 -0
  29. wbintegrator_office365-2.2.1/wbintegrator_office365/tests/__init__.py +0 -0
  30. wbintegrator_office365-2.2.1/wbintegrator_office365/tests/conftest.py +28 -0
  31. wbintegrator_office365-2.2.1/wbintegrator_office365/tests/test_admin.py +86 -0
  32. wbintegrator_office365-2.2.1/wbintegrator_office365/tests/test_models.py +65 -0
  33. wbintegrator_office365-2.2.1/wbintegrator_office365/tests/test_tasks.py +318 -0
  34. wbintegrator_office365-2.2.1/wbintegrator_office365/tests/test_views.py +128 -0
  35. wbintegrator_office365-2.2.1/wbintegrator_office365/tests/tests.py +12 -0
  36. wbintegrator_office365-2.2.1/wbintegrator_office365/urls.py +46 -0
  37. wbintegrator_office365-2.2.1/wbintegrator_office365/viewsets/__init__.py +31 -0
  38. wbintegrator_office365-2.2.1/wbintegrator_office365/viewsets/display.py +306 -0
  39. wbintegrator_office365-2.2.1/wbintegrator_office365/viewsets/endpoints.py +52 -0
  40. wbintegrator_office365-2.2.1/wbintegrator_office365/viewsets/menu.py +65 -0
  41. wbintegrator_office365-2.2.1/wbintegrator_office365/viewsets/titles.py +49 -0
  42. wbintegrator_office365-2.2.1/wbintegrator_office365/viewsets/viewsets.py +745 -0
@@ -0,0 +1,181 @@
1
+ ~
2
+
3
+ # Docker volumes
4
+ volumes/
5
+ # Poetry auth file
6
+ auth.toml
7
+
8
+ media/*
9
+ media/
10
+ mediafiles/
11
+ mediafiles/*
12
+ test/*
13
+ staticfiles/*
14
+ staticfiles/
15
+ #
16
+ # Byte-compiled / optimized / DLL files
17
+ __pycache__/
18
+ *.py[cod]
19
+ *$py.class
20
+
21
+ # C extensions
22
+ *.so
23
+
24
+ # Distribution / packaging
25
+ .Python
26
+ build/
27
+ develop-eggs/
28
+ dist/
29
+ info/
30
+ downloads/
31
+ eggs/
32
+ .eggs/
33
+ lib/
34
+ lib64/
35
+ parts/
36
+ sdist/
37
+ var/
38
+ wheels/
39
+ share/python-wheels/
40
+ *.egg-info/
41
+ .installed.cfg
42
+ *.egg
43
+ MANIFEST
44
+
45
+ # PyInstaller
46
+ # Usually these files are written by a python script from a template
47
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
48
+ *.manifest
49
+ *.spec
50
+
51
+ # Installer logs
52
+ pip-log.txt
53
+ pip-delete-this-directory.txt
54
+
55
+ # Unit test / coverage reports
56
+ htmlcov/
57
+ .tox/
58
+ .nox/
59
+ .coverage
60
+ .coverage.*
61
+ .cache
62
+ .dccache
63
+ nosetests.xml
64
+ coverage.xml
65
+ *.cover
66
+ *.py,cover
67
+ .hypothesis/
68
+ .pytest_cache/
69
+ cover/
70
+ report.xml
71
+ */report.xml
72
+
73
+ # Translations
74
+ *.mo
75
+ *.pot
76
+
77
+ # Django stuff:
78
+ *.log
79
+ local_settings.py
80
+ *.sqlite3
81
+ db.sqlite3-journal
82
+
83
+ # Flask stuff:
84
+ instance/
85
+ .webassets-cache
86
+
87
+ # Scrapy stuff:
88
+ .scrapy
89
+
90
+ # Sphinx documentation
91
+ docs/_build/
92
+
93
+ # PyBuilder
94
+ .pybuilder/
95
+ target/
96
+
97
+ # Jupyter Notebook
98
+ .ipynb_checkpoints
99
+ *.ipynb
100
+ # IPython
101
+ profile_default/
102
+ ipython_config.py
103
+
104
+ # pyenv
105
+ # For a library or package, you might want to ignore these files since the code is
106
+ # intended to run in multiple environments; otherwise, check them in:
107
+ # .python-version
108
+
109
+ # pipenv
110
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
111
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
112
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
113
+ # install all needed dependencies.
114
+ #Pipfile.lock
115
+
116
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow
117
+ __pypackages__/
118
+
119
+ # Celery stuff
120
+ celerybeat-schedule
121
+ celerybeat.pid
122
+
123
+ # SageMath parsed files
124
+ *.sage.py
125
+
126
+ # Environments
127
+ .env
128
+ .envrc
129
+ .venv
130
+ env/
131
+ venv/
132
+ ENV/
133
+ env.bak/
134
+ venv.bak/
135
+ .vscode/
136
+ .idea/
137
+ .idea.bkp/
138
+
139
+ # Spyder project settings
140
+ .spyderproject
141
+ .spyproject
142
+
143
+ # Rope project settings
144
+ .ropeproject
145
+
146
+ # mkdocs documentation
147
+ /site
148
+
149
+ # mypy
150
+ .mypy_cache/
151
+ .dmypy.json
152
+ dmypy.json
153
+
154
+ # Pyre type checker
155
+ .pyre/
156
+
157
+ # pytype static type analyzer
158
+ .pytype/
159
+ crm/
160
+ # Cython debug symbols
161
+ cython_debug/
162
+
163
+ # Gitlab Runner
164
+ builds
165
+ builds/
166
+
167
+ # Integrator Office 365 : reverse proxy tunnel for outlook365
168
+ ngrok
169
+ */ngrok
170
+ /modules/**/system/
171
+
172
+ /modules/wbmailing/files/*
173
+ /modules/wbmailing/mailing/*
174
+
175
+ /projects/*/requirements.txt
176
+ public
177
+
178
+ # Ignore archive localization generated folder
179
+ backend/modules/**/archive/*
180
+ **/**/requirements.txt
181
+ CHANGELOG-*
@@ -0,0 +1,10 @@
1
+ Metadata-Version: 2.3
2
+ Name: wbintegrator_office365
3
+ Version: 2.2.1
4
+ Author-email: Christopher Wittlinger <c.wittlinger@stainly.com>
5
+ Requires-Dist: bs4==0.0.*
6
+ Requires-Dist: oauthlib==3.1.*
7
+ Requires-Dist: requests-oauthlib==1.3.*
8
+ Requires-Dist: wbcore
9
+ Requires-Dist: wbcrm
10
+ Requires-Dist: wbhuman-resources
@@ -0,0 +1,36 @@
1
+ [project]
2
+ name = "wbintegrator_office365"
3
+ description = ""
4
+ authors = [{ name = "Christopher Wittlinger", email = "c.wittlinger@stainly.com"}]
5
+ dynamic = ["version"]
6
+
7
+ dependencies = [
8
+ "wbcore",
9
+ "wbcrm",
10
+ "wbhuman_resources",
11
+ "oauthlib == 3.1.*",
12
+ "requests-oauthlib == 1.3.*",
13
+ "bs4 == 0.0.*",
14
+ ]
15
+
16
+ [tool.uv.sources]
17
+ wbcore = { workspace = true }
18
+ wbcrm = { workspace = true }
19
+ wbhuman_resources = { workspace = true }
20
+
21
+ [tool.uv]
22
+ package = true
23
+
24
+ [tool.hatch.version]
25
+ path = "../../pyproject.toml"
26
+
27
+ [tool.hatch.build.targets.sdist]
28
+ include = ["wbintegrator_office365/*"]
29
+
30
+ [tool.hatch.build.targets.wheel]
31
+ packages = ["wbintegrator_office365"]
32
+ only-packages = true
33
+
34
+ [build-system]
35
+ requires = ["hatchling"]
36
+ build-backend = "hatchling.build"
@@ -0,0 +1 @@
1
+ __version__ = "1.0.0"
@@ -0,0 +1,209 @@
1
+ from django.contrib import admin
2
+ from django.shortcuts import redirect
3
+ from django.urls import path
4
+ from wbcore.admin import ExportCsvMixin, ImportCsvMixin
5
+ from wbintegrator_office365.models.event import fetch_tenantusers
6
+ from wbintegrator_office365.models.subscription import (
7
+ resubscribe_as_task,
8
+ verification_subscriptions,
9
+ )
10
+
11
+ from .models import CallEvent, CallUser, Event, EventLog, Subscription, TenantUser
12
+
13
+
14
+ @admin.register(TenantUser)
15
+ class TenantUserAdmin(admin.ModelAdmin, ImportCsvMixin, ExportCsvMixin):
16
+ search_fields = ("tenant_id", "display_name", "mail", "phone", "profile__computed_str", "tenant_organization_id")
17
+ list_display = (
18
+ "tenant_id",
19
+ "display_name",
20
+ "mail",
21
+ "phone",
22
+ "profile",
23
+ "tenant_organization_id",
24
+ )
25
+ change_list_template = "admin/tenant_change_list.html"
26
+ list_filter = ("is_internal_organization",)
27
+ readonly_fields = ("is_internal_organization",)
28
+
29
+ def get_urls(self):
30
+ urls = super().get_urls()
31
+ my_urls = [path("fetch_tenantusers/", self._fetch_tenantusers)]
32
+ return my_urls + urls
33
+
34
+ def _fetch_tenantusers(self, request):
35
+ datum, count_added = fetch_tenantusers()
36
+ self.message_user(
37
+ request, str(len(datum)) + " tenants users found " + str(count_added) + " new tenants users added"
38
+ )
39
+ return redirect("..")
40
+
41
+
42
+ @admin.register(EventLog)
43
+ class EventLogAdmin(admin.ModelAdmin):
44
+ search_fields = ("id", "change_type", "last_event__resource", "last_event__subscription_id", "id_event")
45
+ list_display = (
46
+ "id",
47
+ "order_received",
48
+ "change_type",
49
+ "is_handled",
50
+ "resource",
51
+ "created",
52
+ "changed",
53
+ "last_event",
54
+ "id_event",
55
+ )
56
+ ordering = ["-id", "-order_received"]
57
+ list_filter = ("change_type", "created", "changed")
58
+
59
+
60
+ class EventLogTabularInline(admin.TabularInline):
61
+ model = EventLog
62
+ fields = ["id", "order_received", "change_type", "is_handled", "resource", "created", "changed"]
63
+ readonly_fields = ("id", "order_received", "change_type", "resource", "created", "changed")
64
+ extra = 0
65
+ autocomplete_fields = ["last_event"]
66
+ ordering = ["-id", "-order_received"]
67
+
68
+
69
+ @admin.register(Event)
70
+ class EventAdmin(admin.ModelAdmin):
71
+ search_fields = (
72
+ "id",
73
+ "id_event",
74
+ "resource",
75
+ "subscription_id",
76
+ "tenant_user__display_name",
77
+ "tenant_user__mail",
78
+ "tenant_user__phone",
79
+ "tenant_user__profile__computed_str",
80
+ "tenant_user__tenant_organization_id",
81
+ )
82
+ list_display = (
83
+ "id",
84
+ "auto_inc_id",
85
+ "nb_received",
86
+ "type",
87
+ "change_type",
88
+ "tenant_user",
89
+ "is_handled",
90
+ "created",
91
+ "changed",
92
+ "uuid_event",
93
+ "id_event",
94
+ "subscription_id",
95
+ )
96
+ raw_id_fields = ["tenant_user"]
97
+ ordering = ["-auto_inc_id"]
98
+ inlines = [EventLogTabularInline]
99
+ list_filter = ("type", "change_type", "created", "changed")
100
+
101
+
102
+ @admin.register(CallEvent)
103
+ class CallEventAdmin(admin.ModelAdmin):
104
+ search_fields = (
105
+ "id",
106
+ "event__id",
107
+ "organizer__tenant_user__display_name",
108
+ "organizer__tenant_user__mail",
109
+ "organizer__tenant_user__phone",
110
+ "organizer__tenant_user__profile__computed_str",
111
+ "organizer__tenant_user__tenant_organization_id",
112
+ )
113
+ list_display = (
114
+ "id",
115
+ "event",
116
+ "organizer",
117
+ "version",
118
+ "start",
119
+ "end",
120
+ "created",
121
+ "last_modified",
122
+ "is_internal_call",
123
+ )
124
+ list_filter = ("is_internal_call", "created", "last_modified", "start", "end")
125
+
126
+
127
+ @admin.register(CallUser)
128
+ class CallUserAdmin(admin.ModelAdmin):
129
+ search_fields = (
130
+ "tenant_user__display_name",
131
+ "tenant_user__mail",
132
+ "tenant_user__phone",
133
+ "tenant_user__profile__computed_str",
134
+ "tenant_user__tenant_organization_id",
135
+ )
136
+ list_display = ("id", "tenant_user", "is_guest", "is_phone")
137
+ list_filter = ("is_guest", "is_phone")
138
+
139
+
140
+ @admin.register(Subscription)
141
+ class SubscriptionAdmin(admin.ModelAdmin):
142
+ search_fields = (
143
+ "id",
144
+ "subscription_id",
145
+ "resource",
146
+ "tenant_user__display_name",
147
+ "tenant_user__mail",
148
+ "tenant_user__phone",
149
+ "tenant_user__profile__computed_str",
150
+ "tenant_user__tenant_organization_id",
151
+ )
152
+ list_display = (
153
+ "id",
154
+ "subscription_id",
155
+ "expiration_date",
156
+ "type_resource",
157
+ "tenant_user",
158
+ "is_enable",
159
+ "created",
160
+ "change_type",
161
+ "resource",
162
+ "notification_url",
163
+ )
164
+ list_filter = ("is_enable", "type_resource", "expiration_date", "created")
165
+
166
+ def disable_selected_subscriptions(self, request, queryset):
167
+ for subscription in queryset:
168
+ subscription.is_enable = False
169
+ subscription.save()
170
+
171
+ self.message_user(
172
+ request,
173
+ "Operation completed, we unsubscribe the subscriptions selected",
174
+ )
175
+
176
+ def verification_selected_subscriptions(self, request, queryset):
177
+ for subscription in queryset:
178
+ verification_subscriptions.delay(subscription.id)
179
+ self.message_user(
180
+ request,
181
+ "Verification completed for the subscriptions selected",
182
+ )
183
+
184
+ def renew_selected_subscriptions(self, request, queryset):
185
+ for subscription in queryset:
186
+ resubscribe_as_task.delay(subscription.id)
187
+ self.message_user(request, "Active subscriptions are renewed on microsoft")
188
+ return redirect("..")
189
+
190
+ actions = [disable_selected_subscriptions, verification_selected_subscriptions, renew_selected_subscriptions]
191
+
192
+ readonly_fields = [
193
+ "subscription_id",
194
+ "change_type",
195
+ "expiration_date",
196
+ "notification_url",
197
+ "resource",
198
+ "application_id",
199
+ "creator_id",
200
+ "client_state",
201
+ "latest_supported_tls_version",
202
+ "notification_content_type",
203
+ "odata_context",
204
+ "encryption_certificate_id",
205
+ "encryption_certificate",
206
+ "include_resource_data",
207
+ "notification_query_options",
208
+ "is_enable",
209
+ ]
@@ -0,0 +1,5 @@
1
+ from django.apps import AppConfig
2
+
3
+
4
+ class WbintegratorOffice365Config(AppConfig):
5
+ name = "wbintegrator_office365"
@@ -0,0 +1,23 @@
1
+ from os import environ
2
+
3
+ from configurations import values
4
+
5
+
6
+ class Office365:
7
+ WBINTEGRATOR_OFFICE365_TENANT_ID = values.Value("", environ_prefix=None)
8
+ WBINTEGRATOR_OFFICE365_CLIENT_ID = values.Value("", environ_prefix=None)
9
+ WBINTEGRATOR_OFFICE365_CLIENT_SECRET = values.Value("", environ_prefix=None)
10
+ WBINTEGRATOR_OFFICE365_REDIRECT_URI = values.Value("", environ_prefix=None)
11
+ WBINTEGRATOR_OFFICE365_TOKEN_ENDPOINT = values.Value("", environ_prefix=None)
12
+ WBINTEGRATOR_OFFICE365_NOTIFICATION_URL = values.Value("", environ_prefix=None)
13
+ WBINTEGRATOR_OFFICE365_GRAPH_API_VERSION = values.Value("", environ_prefix=None)
14
+ WBINTEGRATOR_OFFICE365_AUTHORITY_PREFIX = values.Value("", environ_prefix=None)
15
+ WBINTEGRATOR_OFFICE365_GRAPH_URL_PREFIX = values.Value("", environ_prefix=None)
16
+
17
+ @property
18
+ def WBINTEGRATOR_OFFICE365_AUTHORITY(self):
19
+ return self.WBINTEGRATOR_OFFICE365_AUTHORITY_PREFIX + self.WBINTEGRATOR_OFFICE365_TENANT_ID
20
+
21
+ @property
22
+ def WBINTEGRATOR_OFFICE365_GRAPH_URL(self):
23
+ return self.WBINTEGRATOR_OFFICE365_GRAPH_URL_PREFIX + self.WBINTEGRATOR_OFFICE365_GRAPH_API_VERSION
@@ -0,0 +1,15 @@
1
+ from dynamic_preferences.preferences import Section
2
+ from dynamic_preferences.registries import global_preferences_registry
3
+ from dynamic_preferences.types import StringPreference
4
+
5
+ general = Section("wbintegrator_office365")
6
+
7
+
8
+ @global_preferences_registry.register
9
+ class AccesTokenPreference(StringPreference):
10
+ section = general
11
+ name = "access_token"
12
+ default = "0"
13
+
14
+ verbose_name = "Access Token"
15
+ help_text = "The access token obtained from subscriptions Microsoft for authentication"
@@ -0,0 +1,102 @@
1
+ import random
2
+
3
+ import factory
4
+ import pytz
5
+
6
+
7
+ class TenantUserFactory(factory.django.DjangoModelFactory):
8
+ class Meta:
9
+ model = "wbintegrator_office365.TenantUser"
10
+
11
+ tenant_id = factory.Sequence(lambda n: "user_tenant_%d" % n)
12
+ display_name = factory.Faker("name")
13
+ mail = factory.Faker("email")
14
+ phone = factory.Faker("phone_number")
15
+ profile = factory.SubFactory("wbcore.contrib.directory.factories.PersonFactory")
16
+ tenant_organization_id = factory.Faker("pystr")
17
+
18
+
19
+ class SubscriptionFactory(factory.django.DjangoModelFactory):
20
+ class Meta:
21
+ model = "wbintegrator_office365.Subscription"
22
+
23
+ subscription_id = factory.Sequence(lambda n: "subscription%d" % n)
24
+ expiration_date = factory.Faker("date_time_between", start_date="+2d", end_date="+3d", tzinfo=pytz.utc)
25
+ change_type = factory.Faker("pystr")
26
+ notification_url = factory.Faker("url")
27
+ resource = factory.Faker("uri")
28
+ application_id = factory.Faker("pystr")
29
+ creator_id = factory.Faker("pystr")
30
+ client_state = factory.Faker("pystr")
31
+ latest_supported_tls_version = factory.Faker("pystr")
32
+ notification_content_type = factory.Faker("pystr")
33
+ odata_context = factory.Faker("pystr")
34
+ encryption_certificate_id = factory.Faker("pystr")
35
+ encryption_certificate = factory.Faker("pystr")
36
+ include_resource_data = factory.Faker("pystr")
37
+ notification_query_options = factory.Faker("pystr")
38
+ tenant_user = factory.SubFactory(TenantUserFactory)
39
+
40
+
41
+ class EventFactory(factory.django.DjangoModelFactory):
42
+ class Meta:
43
+ model = "wbintegrator_office365.Event"
44
+
45
+ uuid_event = factory.Sequence(lambda n: "UID%d" % n)
46
+ id_event = factory.Sequence(lambda n: "ID%d" % n)
47
+ # type = "CALLRECORD"
48
+ subscription_id = factory.Sequence(lambda n: "subscription%d" % n)
49
+ # change_type = "CREATED" #"UPDATED"
50
+ resource = factory.Faker("uri")
51
+ tenant_user = factory.SubFactory(TenantUserFactory)
52
+
53
+
54
+ class EventLogFactory(factory.django.DjangoModelFactory):
55
+ class Meta:
56
+ model = "wbintegrator_office365.EventLog"
57
+
58
+ last_event = factory.SubFactory(EventFactory)
59
+ id_event = factory.Sequence(lambda n: "event%d" % n)
60
+
61
+
62
+ class CallUserFactory(factory.django.DjangoModelFactory):
63
+ class Meta:
64
+ model = "wbintegrator_office365.CallUser"
65
+
66
+ acs_user = factory.Faker("pystr")
67
+ splool_user = factory.Faker("pystr")
68
+ encrypted = factory.Faker("pystr")
69
+ on_premises = factory.Faker("pystr")
70
+ acs_application_instance = factory.Faker("pystr")
71
+ spool_application_instance = factory.Faker("pystr")
72
+ application_instance = factory.Faker("pystr")
73
+ application = factory.Faker("pystr")
74
+ device = factory.Faker("pystr")
75
+ tenant_user = factory.SubFactory(TenantUserFactory)
76
+ is_guest = factory.Faker("pybool")
77
+ is_phone = factory.Faker("pybool")
78
+
79
+
80
+ class CallEventFactory(factory.django.DjangoModelFactory):
81
+ class Meta:
82
+ model = "wbintegrator_office365.CallEvent"
83
+ django_get_or_create = ["activity"]
84
+
85
+ event = factory.SubFactory(EventFactory)
86
+ version = random.randint(1, 4)
87
+ type = factory.Faker("pystr")
88
+ start = factory.Faker("date_time_between", start_date="+2d", end_date="+3d", tzinfo=pytz.utc)
89
+ end = factory.Faker("date_time_between", start_date="+2d", end_date="+3d", tzinfo=pytz.utc)
90
+ last_modified = factory.Faker("date_time_between", start_date="+4d", end_date="+5d", tzinfo=pytz.utc)
91
+ join_web_url = factory.Faker("url")
92
+ organizer = factory.SubFactory(CallUserFactory)
93
+ activity = factory.SubFactory("wbcrm.factories.ActivityFactory")
94
+ is_internal_call = factory.Faker("pybool")
95
+
96
+ @factory.post_generation
97
+ def participants(self, create, extracted, **kwargs):
98
+ if not create:
99
+ return
100
+ if extracted:
101
+ for participant in extracted:
102
+ self.participants.add(participant)