leadguru-jobs 0.637.0__py3-none-any.whl → 0.639.0__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.
- {leadguru_jobs-0.637.0.dist-info → leadguru_jobs-0.639.0.dist-info}/METADATA +1 -1
- {leadguru_jobs-0.637.0.dist-info → leadguru_jobs-0.639.0.dist-info}/RECORD +17 -18
- lgt_jobs/jobs/bot_stats_update.py +2 -10
- lgt_jobs/jobs/chat_history.py +3 -6
- lgt_jobs/jobs/connect_sources.py +4 -1
- lgt_jobs/jobs/inbox_leads.py +6 -2
- lgt_jobs/jobs/load_slack_people.py +2 -1
- lgt_jobs/jobs/send_slack_message.py +1 -1
- lgt_jobs/jobs/update_slack_profile.py +2 -1
- lgt_jobs/jobs/workspace_connect.py +3 -1
- lgt_jobs/lgt_data/model.py +0 -1136
- lgt_jobs/lgt_data/models/base.py +29 -0
- lgt_jobs/lgt_data/mongo_repository.py +225 -45
- lgt_jobs/runner.py +2 -2
- lgt_jobs/simple_job.py +1 -1
- lgt_jobs/lgt_common/lgt_logging.py +0 -15
- lgt_jobs/lgt_data/models/message_request.py +0 -14
- {leadguru_jobs-0.637.0.dist-info → leadguru_jobs-0.639.0.dist-info}/WHEEL +0 -0
- {leadguru_jobs-0.637.0.dist-info → leadguru_jobs-0.639.0.dist-info}/top_level.txt +0 -0
lgt_jobs/lgt_data/model.py
CHANGED
@@ -1,1136 +0,0 @@
|
|
1
|
-
from __future__ import annotations
|
2
|
-
import copy
|
3
|
-
import json
|
4
|
-
from abc import ABC
|
5
|
-
from datetime import datetime, UTC, timedelta
|
6
|
-
from typing import Optional, List
|
7
|
-
from lgt_jobs.lgt_data.enums import UserRole, SourceType, FeaturesEnum, FeatureOptions, NotificationType
|
8
|
-
from bson import ObjectId
|
9
|
-
|
10
|
-
|
11
|
-
class DictionaryModel(ABC):
|
12
|
-
@classmethod
|
13
|
-
def from_dic(cls, dic: dict):
|
14
|
-
if not dic:
|
15
|
-
return None
|
16
|
-
|
17
|
-
model = cls()
|
18
|
-
for k, v in dic.items():
|
19
|
-
setattr(model, k, v)
|
20
|
-
|
21
|
-
if '_id' in dic:
|
22
|
-
setattr(model, 'id', dic['_id'])
|
23
|
-
|
24
|
-
return model
|
25
|
-
|
26
|
-
def to_dic(self):
|
27
|
-
result = copy.deepcopy(self.__dict__)
|
28
|
-
return result
|
29
|
-
|
30
|
-
|
31
|
-
class BaseModel(DictionaryModel):
|
32
|
-
def __init__(self):
|
33
|
-
self.id = None
|
34
|
-
self.created_at = datetime.now(UTC)
|
35
|
-
|
36
|
-
|
37
|
-
class Credentials(BaseModel):
|
38
|
-
def __init__(self):
|
39
|
-
super().__init__()
|
40
|
-
self.token = None
|
41
|
-
self.cookies = None
|
42
|
-
self.invalid_creds = False
|
43
|
-
|
44
|
-
|
45
|
-
class Source:
|
46
|
-
def __init__(self):
|
47
|
-
self.source_type: SourceType | None = None
|
48
|
-
self.source_name = None
|
49
|
-
self.source_id = None
|
50
|
-
|
51
|
-
@classmethod
|
52
|
-
def from_dic(cls, dic: dict):
|
53
|
-
if not dic:
|
54
|
-
return None
|
55
|
-
|
56
|
-
model = cls()
|
57
|
-
for k, v in dic.items():
|
58
|
-
setattr(model, k, v)
|
59
|
-
|
60
|
-
return model
|
61
|
-
|
62
|
-
def to_dic(self):
|
63
|
-
result = copy.deepcopy(self.__dict__)
|
64
|
-
return result
|
65
|
-
|
66
|
-
|
67
|
-
class BaseConfig:
|
68
|
-
def __init__(self):
|
69
|
-
self.owner = None
|
70
|
-
self.id = None
|
71
|
-
|
72
|
-
@classmethod
|
73
|
-
def from_dic(cls, dic: dict):
|
74
|
-
if not dic:
|
75
|
-
return None
|
76
|
-
|
77
|
-
model = cls()
|
78
|
-
for k, v in dic.items():
|
79
|
-
setattr(model, k, v)
|
80
|
-
|
81
|
-
return model
|
82
|
-
|
83
|
-
def to_dic(self):
|
84
|
-
result = copy.deepcopy(self.__dict__)
|
85
|
-
return result
|
86
|
-
|
87
|
-
|
88
|
-
class Config(BaseConfig):
|
89
|
-
def __init__(self):
|
90
|
-
super().__init__()
|
91
|
-
self.name = None
|
92
|
-
|
93
|
-
|
94
|
-
class BaseBotModel(Credentials):
|
95
|
-
def __init__(self):
|
96
|
-
super().__init__()
|
97
|
-
self.created_by = None
|
98
|
-
self.user_name = None
|
99
|
-
self.slack_url = None
|
100
|
-
self.registration_link = None
|
101
|
-
self.channels = None
|
102
|
-
self.connected_channels = None
|
103
|
-
self.channels_users = None
|
104
|
-
self.users_count = None
|
105
|
-
self.recent_messages: List[str] = []
|
106
|
-
self.icon = None
|
107
|
-
self.active_channels = {}
|
108
|
-
self.paused_channels = []
|
109
|
-
self.source: Source | None = None
|
110
|
-
self.two_factor_required: bool = False
|
111
|
-
self.banned: bool = False
|
112
|
-
self.associated_user = None
|
113
|
-
self.type: SourceType | None = None
|
114
|
-
self.deleted = False
|
115
|
-
|
116
|
-
|
117
|
-
class DedicatedBotModel(BaseBotModel):
|
118
|
-
def __init__(self):
|
119
|
-
super().__init__()
|
120
|
-
self.user_id: Optional[str] = None
|
121
|
-
self.updated_at: Optional[datetime] = datetime.now(UTC)
|
122
|
-
self.servers: List[Server] = []
|
123
|
-
self.state = 0
|
124
|
-
self.source: Source | None = None
|
125
|
-
|
126
|
-
def to_dic(self):
|
127
|
-
result = copy.deepcopy(self.__dict__)
|
128
|
-
|
129
|
-
if result.get('source'):
|
130
|
-
result['source'] = Source.to_dic(result.get('source'))
|
131
|
-
|
132
|
-
result['servers'] = [Server.to_dic(server) for server in self.servers]
|
133
|
-
return result
|
134
|
-
|
135
|
-
@classmethod
|
136
|
-
def from_dic(cls, dic: dict):
|
137
|
-
if not dic:
|
138
|
-
return None
|
139
|
-
|
140
|
-
model: DedicatedBotModel = cls()
|
141
|
-
for k, v in dic.items():
|
142
|
-
setattr(model, k, v)
|
143
|
-
|
144
|
-
if '_id' in dic:
|
145
|
-
setattr(model, 'id', dic['_id'])
|
146
|
-
|
147
|
-
model.source = Source.from_dic(dic.get("source"))
|
148
|
-
model.servers = [Server.from_dic(server) for server in dic.get("servers", [])]
|
149
|
-
return model
|
150
|
-
|
151
|
-
|
152
|
-
class Server:
|
153
|
-
pass
|
154
|
-
|
155
|
-
def __init__(self):
|
156
|
-
self.id = None
|
157
|
-
self.name = None
|
158
|
-
self.channels: List[Channel] = []
|
159
|
-
self.icon = None
|
160
|
-
self.active = False
|
161
|
-
self.deleted = False
|
162
|
-
self.subscribers = 0
|
163
|
-
self.approximate_member_count = 0
|
164
|
-
self.messages_received: int = 0
|
165
|
-
self.messages_filtered: int = 0
|
166
|
-
|
167
|
-
@classmethod
|
168
|
-
def from_dic(cls, dic: dict):
|
169
|
-
if not dic:
|
170
|
-
return None
|
171
|
-
|
172
|
-
model = cls()
|
173
|
-
for k, v in dic.items():
|
174
|
-
if hasattr(model, k):
|
175
|
-
setattr(model, k, v)
|
176
|
-
|
177
|
-
model.channels = [Channel.from_dic(channel) for channel in dic.get("channels", [])]
|
178
|
-
model.subscribers = dic.get('approximate_member_count')
|
179
|
-
return model
|
180
|
-
|
181
|
-
def to_dic(self):
|
182
|
-
result = copy.deepcopy(self.__dict__)
|
183
|
-
result['channels'] = [Channel.to_dic(channel) for channel in self.channels]
|
184
|
-
return result
|
185
|
-
|
186
|
-
|
187
|
-
class Channel:
|
188
|
-
pass
|
189
|
-
|
190
|
-
def __init__(self):
|
191
|
-
self.id = None
|
192
|
-
self.name = None
|
193
|
-
self.type = None
|
194
|
-
self.is_member = True
|
195
|
-
self.active = True
|
196
|
-
self.subscribers = 0
|
197
|
-
|
198
|
-
@classmethod
|
199
|
-
def from_dic(cls, dic: dict):
|
200
|
-
if not dic:
|
201
|
-
return None
|
202
|
-
|
203
|
-
model = cls()
|
204
|
-
for k, v in dic.items():
|
205
|
-
if hasattr(model, k):
|
206
|
-
setattr(model, k, v)
|
207
|
-
|
208
|
-
return model
|
209
|
-
|
210
|
-
def to_dic(self):
|
211
|
-
result = copy.deepcopy(self.__dict__)
|
212
|
-
return result
|
213
|
-
|
214
|
-
|
215
|
-
class MessageModel:
|
216
|
-
pass
|
217
|
-
|
218
|
-
def __init__(self):
|
219
|
-
self.message_id = None
|
220
|
-
self.channel_id = None
|
221
|
-
self.channel_name = None
|
222
|
-
self.message = None
|
223
|
-
self.name = None
|
224
|
-
self.sender_id = None
|
225
|
-
self.source: Source | None = None
|
226
|
-
self.companies: List[str] = list()
|
227
|
-
self.technologies: List[str] = list()
|
228
|
-
self.locations: List[str] = list()
|
229
|
-
self.configs: List[BaseConfig] = list()
|
230
|
-
self.attachments: List[dict] = []
|
231
|
-
self.timestamp = None
|
232
|
-
self.tags: List[str] = []
|
233
|
-
|
234
|
-
@classmethod
|
235
|
-
def from_dic(cls, dic: dict):
|
236
|
-
if not dic:
|
237
|
-
return None
|
238
|
-
if isinstance(dic.get('attachments'), str):
|
239
|
-
dic['attachments'] = json.loads(dic['attachments'])
|
240
|
-
|
241
|
-
model: MessageModel = cls()
|
242
|
-
for k, v in dic.items():
|
243
|
-
setattr(model, k, v)
|
244
|
-
|
245
|
-
model.source = Source.from_dic(dic.get("source"))
|
246
|
-
model.configs = [BaseConfig.from_dic(doc) for doc in dic.get("configs", [])]
|
247
|
-
return model
|
248
|
-
|
249
|
-
def to_dic(self):
|
250
|
-
result = copy.deepcopy(self.__dict__)
|
251
|
-
|
252
|
-
if result.get('source'):
|
253
|
-
result['source'] = Source.to_dic(result.get('source'))
|
254
|
-
if result.get('configs'):
|
255
|
-
result['configs'] = [BaseConfig.to_dic(config) for config in result.get('configs')]
|
256
|
-
return result
|
257
|
-
|
258
|
-
|
259
|
-
class Notification(DictionaryModel):
|
260
|
-
def __init__(self):
|
261
|
-
self.enabled: bool = True
|
262
|
-
self.type: NotificationType = NotificationType.INSTANTLY
|
263
|
-
self.day: int | None = None
|
264
|
-
self.hour: int | None = None
|
265
|
-
self.minute: int | None = None
|
266
|
-
self.last_notification: datetime | None = None
|
267
|
-
self.need_to_notify: bool = False
|
268
|
-
self.attributes: list[str] = []
|
269
|
-
|
270
|
-
@property
|
271
|
-
def need_to_notify_now(self) -> bool:
|
272
|
-
if not self.enabled or not self.need_to_notify:
|
273
|
-
return False
|
274
|
-
|
275
|
-
now = datetime.now(UTC)
|
276
|
-
current_week_day = datetime.isoweekday(now)
|
277
|
-
if self.last_notification:
|
278
|
-
self.last_notification = self.last_notification.replace(tzinfo=UTC)
|
279
|
-
|
280
|
-
if (self.type == NotificationType.UNREAD_FOR_FEW_MINUTES
|
281
|
-
and self.last_notification and (now.minute - self.minute <= self.last_notification.minute)):
|
282
|
-
return False
|
283
|
-
|
284
|
-
if self.type == NotificationType.ONCE_A_WEEK and current_week_day != self.day:
|
285
|
-
return False
|
286
|
-
|
287
|
-
if ((self.type == NotificationType.ONCE_A_DAY or self.type == NotificationType.ONCE_A_WEEK)
|
288
|
-
and now.hour != self.hour and now.minute < self.minute):
|
289
|
-
return False
|
290
|
-
|
291
|
-
if ((self.type == NotificationType.ONCE_A_DAY or self.type == NotificationType.ONCE_A_WEEK)
|
292
|
-
and self.last_notification and self.last_notification > now - timedelta(hours=1)):
|
293
|
-
return False
|
294
|
-
|
295
|
-
return True
|
296
|
-
|
297
|
-
@staticmethod
|
298
|
-
def need_to_notify_week_before(date: datetime) -> bool:
|
299
|
-
return datetime.now(UTC) < (date + timedelta(7))
|
300
|
-
|
301
|
-
|
302
|
-
class NotificationSettings(DictionaryModel):
|
303
|
-
def __init__(self):
|
304
|
-
self.incoming_messages: Notification | None = None
|
305
|
-
self.inbox: Notification | None = None
|
306
|
-
self.source_deactivation: Notification | None = None
|
307
|
-
self.billing: Notification | None = None
|
308
|
-
self.bulk_replies: Notification | None = None
|
309
|
-
self.bulk_reactions: Notification | None = None
|
310
|
-
self.follow_ups: Notification | None = None
|
311
|
-
|
312
|
-
@classmethod
|
313
|
-
def from_dic(cls, dic: dict):
|
314
|
-
if not dic:
|
315
|
-
return None
|
316
|
-
|
317
|
-
model: NotificationSettings = cls()
|
318
|
-
model.incoming_messages = Notification.from_dic(dic.get('incoming_messages'))
|
319
|
-
model.inbox = Notification.from_dic(dic.get('inbox'))
|
320
|
-
model.source_deactivation = Notification.from_dic(dic.get('source_deactivation'))
|
321
|
-
model.billing = Notification.from_dic(dic.get('billing'))
|
322
|
-
model.bulk_replies = Notification.from_dic(dic.get('bulk_replies'))
|
323
|
-
model.bulk_reactions = Notification.from_dic(dic.get('bulk_reactions'))
|
324
|
-
model.follow_ups = Notification.from_dic(dic.get('follow_ups'))
|
325
|
-
return model
|
326
|
-
|
327
|
-
def to_dic(self):
|
328
|
-
result = copy.deepcopy(self.__dict__)
|
329
|
-
|
330
|
-
if result.get('incoming_messages'):
|
331
|
-
result['incoming_messages'] = Notification.to_dic(result.get('incoming_messages'))
|
332
|
-
if result.get('inbox'):
|
333
|
-
result['inbox'] = Notification.to_dic(result.get('inbox'))
|
334
|
-
if result.get('source_deactivation'):
|
335
|
-
result['source_deactivation'] = Notification.to_dic(result.get('source_deactivation'))
|
336
|
-
if result.get('billing'):
|
337
|
-
result['billing'] = Notification.to_dic(result.get('billing'))
|
338
|
-
if result.get('bulk_replies'):
|
339
|
-
result['bulk_replies'] = Notification.to_dic(result.get('bulk_replies'))
|
340
|
-
if result.get('bulk_reactions'):
|
341
|
-
result['bulk_reactions'] = Notification.to_dic(result.get('bulk_reactions'))
|
342
|
-
if result.get('follow_ups'):
|
343
|
-
result['follow_ups'] = Notification.to_dic(result.get('follow_ups'))
|
344
|
-
|
345
|
-
return result
|
346
|
-
|
347
|
-
|
348
|
-
class GeneralSettings(DictionaryModel):
|
349
|
-
def __init__(self):
|
350
|
-
self.theme: str | None = None
|
351
|
-
self.ask_pipeline_and_status: bool = False
|
352
|
-
self.ask_follow_up: bool = False
|
353
|
-
self.dashboard_is_starting_page: bool = False
|
354
|
-
|
355
|
-
|
356
|
-
class UserModel(BaseModel):
|
357
|
-
def __init__(self):
|
358
|
-
super().__init__()
|
359
|
-
self.email: Optional[str] = None
|
360
|
-
self.password: Optional[str] = None
|
361
|
-
self.roles: List[str] = []
|
362
|
-
self.user_name: str = ''
|
363
|
-
self.company: str = ''
|
364
|
-
self.company_size: Optional[int] = None
|
365
|
-
self.company_industries: Optional[List[str]] = None
|
366
|
-
self.company_technologies: Optional[List[str]] = None
|
367
|
-
self.company_locations: Optional[List[str]] = None
|
368
|
-
self.company_web_site: str = ''
|
369
|
-
self.company_description: str = ''
|
370
|
-
self.position: str = ''
|
371
|
-
self.leads_limit: Optional[int] = None
|
372
|
-
self.leads_proceeded: Optional[int] = None
|
373
|
-
self.leads_filtered: Optional[int] = None
|
374
|
-
self.leads_limit_updated_at: Optional[int] = None
|
375
|
-
self.paid_lead_price: int = 1
|
376
|
-
self.state: int = 0
|
377
|
-
self.credits_exceeded_at: Optional[datetime] = None
|
378
|
-
self.unanswered_leads_period = None
|
379
|
-
self.inactive = None
|
380
|
-
self.slack_users: List[SlackUser] = []
|
381
|
-
self.discord_users: List[DiscordUser] = []
|
382
|
-
self.verified: bool = False
|
383
|
-
self.subscription_id: ObjectId | None = None
|
384
|
-
self.subscription_expired_at: datetime | None = None
|
385
|
-
self.balance: str | None = None
|
386
|
-
self.subscription_name: str | None = None
|
387
|
-
self.subscription_expiration_notified = False
|
388
|
-
self.subscription_expiration_warning_notified = False
|
389
|
-
self.notification_settings: NotificationSettings | None = None
|
390
|
-
self.general_settings: GeneralSettings | None = None
|
391
|
-
|
392
|
-
@classmethod
|
393
|
-
def from_dic(cls, dic: dict):
|
394
|
-
if not dic:
|
395
|
-
return None
|
396
|
-
|
397
|
-
model: UserModel = cls()
|
398
|
-
for k, v in dic.items():
|
399
|
-
setattr(model, k, v)
|
400
|
-
|
401
|
-
if '_id' in dic:
|
402
|
-
setattr(model, 'id', dic['_id'])
|
403
|
-
|
404
|
-
model.slack_profile = Profile.from_dic(dic.get('slack_profile'))
|
405
|
-
model.slack_users = [SlackUser.from_dic(user) for user in dic.get('slack_users', [])]
|
406
|
-
model.discord_users = [DiscordUser.from_dic(user) for user in dic.get('discord_users', [])]
|
407
|
-
model.notification_settings = NotificationSettings.from_dic(dic.get('notification_settings'))
|
408
|
-
model.general_settings = GeneralSettings.from_dic(dic.get('general_settings'))
|
409
|
-
return model
|
410
|
-
|
411
|
-
def to_dic(self):
|
412
|
-
result = copy.deepcopy(self.__dict__)
|
413
|
-
|
414
|
-
if result.get('slack_profile'):
|
415
|
-
result['slack_profile'] = result.get('slack_profile').__dict__
|
416
|
-
if result.get('notification_settings'):
|
417
|
-
result['notification_settings'] = NotificationSettings.to_dic(result.get('notification_settings'))
|
418
|
-
if result.get('general_settings'):
|
419
|
-
result['general_settings'] = GeneralSettings.to_dic(result.get('general_settings'))
|
420
|
-
|
421
|
-
return result
|
422
|
-
|
423
|
-
@property
|
424
|
-
def is_admin(self):
|
425
|
-
return UserRole.ADMIN in self.roles
|
426
|
-
|
427
|
-
@property
|
428
|
-
def subscription_expired(self):
|
429
|
-
return self.subscription_expired_at.replace(tzinfo=UTC) < datetime.now(UTC)
|
430
|
-
|
431
|
-
def get_slack_user(self, slack_email: str) -> SlackUser:
|
432
|
-
return next(filter(lambda x: slack_email == x.email, self.slack_users), None)
|
433
|
-
|
434
|
-
def get_discord_user(self, login: str) -> DiscordUser:
|
435
|
-
return next(filter(lambda x: login == x.login, self.discord_users), None)
|
436
|
-
|
437
|
-
|
438
|
-
class DiscordUser(DictionaryModel):
|
439
|
-
pass
|
440
|
-
|
441
|
-
def __init__(self):
|
442
|
-
super().__init__()
|
443
|
-
self.created_at = datetime.now(UTC)
|
444
|
-
self.login = ''
|
445
|
-
self.captcha_key = ''
|
446
|
-
self.status = None
|
447
|
-
self.workspaces: List[UserWorkspace] = []
|
448
|
-
self.deleted = False
|
449
|
-
self.profile: Profile | None = None
|
450
|
-
|
451
|
-
def to_dic(self):
|
452
|
-
result = copy.deepcopy(self.__dict__)
|
453
|
-
|
454
|
-
if result.get('workspaces'):
|
455
|
-
result['workspaces'] = [ws.__dict__ for ws in result.get('workspaces')]
|
456
|
-
|
457
|
-
if result.get('profile'):
|
458
|
-
result['profile'] = result.get('profile').__dict__
|
459
|
-
|
460
|
-
return result
|
461
|
-
|
462
|
-
@classmethod
|
463
|
-
def from_dic(cls, dic: dict):
|
464
|
-
if not dic:
|
465
|
-
return None
|
466
|
-
|
467
|
-
model = cls()
|
468
|
-
for k, v in dic.items():
|
469
|
-
setattr(model, k, v)
|
470
|
-
|
471
|
-
model.workspaces = [UserWorkspace.from_dic(ws) for ws in dic.get('workspaces', [])]
|
472
|
-
model.profile = Profile.from_dic(dic.get('profile'))
|
473
|
-
return model
|
474
|
-
|
475
|
-
|
476
|
-
class SlackUser:
|
477
|
-
pass
|
478
|
-
|
479
|
-
def __init__(self):
|
480
|
-
self.created_at = datetime.now(UTC)
|
481
|
-
self.cookies = {}
|
482
|
-
self.email = ''
|
483
|
-
self.status = None
|
484
|
-
self.workspaces: List[UserWorkspace] = []
|
485
|
-
self.deleted = False
|
486
|
-
self.profile: Profile | None = None
|
487
|
-
|
488
|
-
def to_dic(self):
|
489
|
-
result = copy.deepcopy(self.__dict__)
|
490
|
-
|
491
|
-
if result.get('workspaces', None):
|
492
|
-
result['workspaces'] = [ws.__dict__ for ws in result.get('workspaces')]
|
493
|
-
|
494
|
-
if result.get('profile'):
|
495
|
-
result['profile'] = result.get('profile').__dict__
|
496
|
-
|
497
|
-
return result
|
498
|
-
|
499
|
-
@classmethod
|
500
|
-
def from_dic(cls, dic: dict):
|
501
|
-
if not dic:
|
502
|
-
return None
|
503
|
-
|
504
|
-
model = cls()
|
505
|
-
for k, v in dic.items():
|
506
|
-
setattr(model, k, v)
|
507
|
-
|
508
|
-
model.workspaces = [UserWorkspace.from_dic(ws) for ws in dic.get('workspaces', [])]
|
509
|
-
model.profile = Profile.from_dic(dic.get('profile'))
|
510
|
-
return model
|
511
|
-
|
512
|
-
|
513
|
-
class UserWorkspace:
|
514
|
-
pass
|
515
|
-
|
516
|
-
def __init__(self):
|
517
|
-
super().__init__()
|
518
|
-
self.id = ''
|
519
|
-
self.name = ''
|
520
|
-
self.url = ''
|
521
|
-
self.domain = ''
|
522
|
-
self.active_users = ''
|
523
|
-
self.profile_photos = []
|
524
|
-
self.associated_user = ''
|
525
|
-
self.magic_login_url = ''
|
526
|
-
self.magic_login_code = ''
|
527
|
-
self.user_email = ''
|
528
|
-
self.user_type = ''
|
529
|
-
self.variant = ''
|
530
|
-
self.token = ''
|
531
|
-
self.icon = ''
|
532
|
-
self.two_factor_required = False
|
533
|
-
|
534
|
-
@classmethod
|
535
|
-
def from_dic(cls, dic: dict):
|
536
|
-
if not dic:
|
537
|
-
return None
|
538
|
-
|
539
|
-
model: UserWorkspace = cls()
|
540
|
-
for k, v in dic.items():
|
541
|
-
setattr(model, k, v)
|
542
|
-
|
543
|
-
model.icon = dic.get('icon_88', "")
|
544
|
-
return model
|
545
|
-
|
546
|
-
|
547
|
-
class UserResetPasswordModel(BaseModel):
|
548
|
-
pass
|
549
|
-
|
550
|
-
def __init__(self):
|
551
|
-
super().__init__()
|
552
|
-
self.email = None
|
553
|
-
|
554
|
-
|
555
|
-
class LeadModel(BaseModel):
|
556
|
-
def __init__(self):
|
557
|
-
super().__init__()
|
558
|
-
self.status = ''
|
559
|
-
self.notes = ''
|
560
|
-
self.archived = False
|
561
|
-
self.message: Optional[MessageModel] = None
|
562
|
-
self.hidden = False
|
563
|
-
self.followup_date = None
|
564
|
-
self.score = 0
|
565
|
-
self.board_id = None
|
566
|
-
self.linkedin_urls = []
|
567
|
-
self.likes = 0
|
568
|
-
self.reactions = 0
|
569
|
-
self.replies = []
|
570
|
-
self.last_action_at: Optional[datetime] = None
|
571
|
-
self.slack_channel = None
|
572
|
-
|
573
|
-
@classmethod
|
574
|
-
def from_dic(cls, dic: dict):
|
575
|
-
if not dic:
|
576
|
-
return None
|
577
|
-
|
578
|
-
model: LeadModel = cls()
|
579
|
-
for k, v in dic.items():
|
580
|
-
setattr(model, k, v)
|
581
|
-
|
582
|
-
model.message = MessageModel.from_dic(dic['message'])
|
583
|
-
if not model.last_action_at:
|
584
|
-
model.last_action_at = model.created_at
|
585
|
-
|
586
|
-
return model
|
587
|
-
|
588
|
-
def to_dic(self):
|
589
|
-
result = copy.deepcopy(self.__dict__)
|
590
|
-
result["message"] = self.message.to_dic()
|
591
|
-
result['archived'] = self.archived
|
592
|
-
return result
|
593
|
-
|
594
|
-
|
595
|
-
class ExtendedLeadModel(LeadModel):
|
596
|
-
def __init__(self):
|
597
|
-
super().__init__()
|
598
|
-
self.previous_publications = []
|
599
|
-
self.last_conversation: List[ChatMessage] = []
|
600
|
-
self.contact: SlackMemberInformation | None = None
|
601
|
-
self.deleted = False
|
602
|
-
self.user_lead: UserLeadModel | None = None
|
603
|
-
self.dedicated: bool = False
|
604
|
-
self.bots: List[BotInfo] = []
|
605
|
-
self.user_contact: UserContact | None = None
|
606
|
-
self.paid: bool = False
|
607
|
-
self.hidden_by_user: bool = False
|
608
|
-
|
609
|
-
@classmethod
|
610
|
-
def from_dic(cls, dic: dict):
|
611
|
-
if not dic:
|
612
|
-
return None
|
613
|
-
|
614
|
-
result: ExtendedLeadModel | None = LeadModel.from_dic(dic)
|
615
|
-
if not result:
|
616
|
-
return None
|
617
|
-
|
618
|
-
result.contact = SlackMemberInformation.from_dic(dic.get('contact'))
|
619
|
-
result.user_contact = UserContact.from_dic(dic.get('user_contact'))
|
620
|
-
result.previous_publications = [LeadModel.from_dic(lead) for lead in dic.get('previous_publications', [])]
|
621
|
-
result.user_lead = UserLeadModel.from_dic(dic.get('user_lead'))
|
622
|
-
result.last_conversation = [ChatMessage.from_dic(message) for message in dic.get('last_conversation', [])]
|
623
|
-
result.bots = [BotInfo.from_dic(bot) for bot in dic.get('bots', [])]
|
624
|
-
return result
|
625
|
-
|
626
|
-
def to_csv(self, board_name: str) -> List[str]:
|
627
|
-
return [self.message.source, self.contact.real_name, self.contact.title, self.contact.email,
|
628
|
-
self.notes, board_name, self.status,
|
629
|
-
self.followup_date.strftime("%d.%m.%Y %H:%M") if self.followup_date else "",
|
630
|
-
self.message.message.replace('\n', ' ').strip()]
|
631
|
-
|
632
|
-
|
633
|
-
class BotInfo:
|
634
|
-
def __init__(self):
|
635
|
-
self.id = None
|
636
|
-
self.invalid_creds: bool | None = False
|
637
|
-
self.source = None
|
638
|
-
self.banned: bool | None = False
|
639
|
-
self.user_name: str = ''
|
640
|
-
self.associated_user: str | None = ''
|
641
|
-
self.deleted: bool = False
|
642
|
-
self.two_factor_required = False
|
643
|
-
|
644
|
-
@classmethod
|
645
|
-
def from_dic(cls, dic: dict):
|
646
|
-
if not dic:
|
647
|
-
return None
|
648
|
-
|
649
|
-
model = BotInfo()
|
650
|
-
for k, v in dic.items():
|
651
|
-
if hasattr(model, k):
|
652
|
-
setattr(model, k, v)
|
653
|
-
|
654
|
-
if '_id' in dic:
|
655
|
-
setattr(model, 'id', dic['_id'])
|
656
|
-
|
657
|
-
return model
|
658
|
-
|
659
|
-
def to_dic(self):
|
660
|
-
result = copy.deepcopy(self.__dict__)
|
661
|
-
return result
|
662
|
-
|
663
|
-
|
664
|
-
class ChatMessage:
|
665
|
-
bot_id: ObjectId
|
666
|
-
user_id: ObjectId
|
667
|
-
sender_id: str
|
668
|
-
text: str
|
669
|
-
user: str
|
670
|
-
id: str
|
671
|
-
viewed: bool
|
672
|
-
files: list
|
673
|
-
attachments: list[dict] | None
|
674
|
-
created_at: datetime | None
|
675
|
-
source_id: str | None
|
676
|
-
|
677
|
-
class SlackFileModel:
|
678
|
-
def __init__(self):
|
679
|
-
self.id = None
|
680
|
-
self.name = None
|
681
|
-
self.title = None
|
682
|
-
self.filetype = None
|
683
|
-
self.size = 0
|
684
|
-
self.mimetype = None
|
685
|
-
self.download_url = None
|
686
|
-
|
687
|
-
def to_dic(self):
|
688
|
-
result = copy.deepcopy(self.__dict__)
|
689
|
-
return result
|
690
|
-
|
691
|
-
def __init__(self):
|
692
|
-
self.viewed = False
|
693
|
-
self.text: str = ''
|
694
|
-
self.created_at: datetime
|
695
|
-
self.user = ''
|
696
|
-
self.id = ''
|
697
|
-
self.files = []
|
698
|
-
self.attachments = []
|
699
|
-
|
700
|
-
def to_dic(self):
|
701
|
-
result = copy.deepcopy(self.__dict__)
|
702
|
-
result['files'] = [x.to_dic() for x in result.get('files', [])]
|
703
|
-
return result
|
704
|
-
|
705
|
-
@classmethod
|
706
|
-
def from_dic(cls, dic: dict):
|
707
|
-
if not dic:
|
708
|
-
return None
|
709
|
-
model = cls()
|
710
|
-
for k, v in dic.items():
|
711
|
-
setattr(model, k, v)
|
712
|
-
return model
|
713
|
-
|
714
|
-
@classmethod
|
715
|
-
def from_slack_response(cls, bot: DedicatedBotModel, message_data: dict, sender_id: str):
|
716
|
-
model = cls()
|
717
|
-
model.sender_id = sender_id
|
718
|
-
model.bot_id = bot.id
|
719
|
-
model.text = message_data.get('text', '')
|
720
|
-
model.user = message_data.get('user', '')
|
721
|
-
model.id = message_data.get('ts', '')
|
722
|
-
model.attachments = message_data.get('attachments', [])
|
723
|
-
model.files = []
|
724
|
-
model.user_id = bot.user_id
|
725
|
-
model.source_id = bot.source.source_id
|
726
|
-
if 'files' in message_data:
|
727
|
-
for file in message_data.get('files'):
|
728
|
-
if file.get('mode') != "tombstone" and file.get('url_private_download'):
|
729
|
-
leadguru_file = LeadGuruFile()
|
730
|
-
leadguru_file.id = file['id']
|
731
|
-
leadguru_file.content_type = file['mimetype']
|
732
|
-
leadguru_file.file_name = file['name']
|
733
|
-
leadguru_file.blob_path = f'slack_files/{bot.user_name}/slack_files/{file["id"]}'
|
734
|
-
model.files.append(leadguru_file)
|
735
|
-
|
736
|
-
js_ticks = int(model.id.split('.')[0] + model.id.split('.')[1][3:])
|
737
|
-
model.created_at = datetime.fromtimestamp(js_ticks / 1000.0)
|
738
|
-
return model
|
739
|
-
|
740
|
-
|
741
|
-
class ScheduledChatMessage(ChatMessage):
|
742
|
-
post_at: Optional[datetime]
|
743
|
-
jib: Optional[str]
|
744
|
-
|
745
|
-
def __init__(self):
|
746
|
-
super(ScheduledChatMessage, self).__init__()
|
747
|
-
|
748
|
-
self.post_at = None
|
749
|
-
self.jib = None
|
750
|
-
|
751
|
-
|
752
|
-
class UserLeadModel(LeadModel):
|
753
|
-
pass
|
754
|
-
|
755
|
-
def __init__(self):
|
756
|
-
super().__init__()
|
757
|
-
self.order: int = 0
|
758
|
-
self.followup_date = None
|
759
|
-
self.user_id = None
|
760
|
-
self.chat_viewed_at = None
|
761
|
-
self.board_id = None
|
762
|
-
|
763
|
-
@classmethod
|
764
|
-
def from_dic(cls, dic: dict):
|
765
|
-
if not dic:
|
766
|
-
return None
|
767
|
-
|
768
|
-
result: UserLeadModel | None = super().from_dic(dic)
|
769
|
-
if not result:
|
770
|
-
return None
|
771
|
-
|
772
|
-
result.chat_viewed_at = dic.get('chat_viewed_at')
|
773
|
-
return result
|
774
|
-
|
775
|
-
|
776
|
-
class ExtendedUserLeadModel(UserLeadModel):
|
777
|
-
pass
|
778
|
-
|
779
|
-
def __init__(self):
|
780
|
-
super().__init__()
|
781
|
-
self.contact: SlackMemberInformation | None = None
|
782
|
-
self.previous_publications = []
|
783
|
-
self.bots: List[BotInfo] = []
|
784
|
-
|
785
|
-
@classmethod
|
786
|
-
def from_dic(cls, dic: dict):
|
787
|
-
if not dic:
|
788
|
-
return None
|
789
|
-
|
790
|
-
result: ExtendedUserLeadModel | None = super().from_dic(dic)
|
791
|
-
if not result:
|
792
|
-
return None
|
793
|
-
|
794
|
-
result.contact = SlackMemberInformation.from_dic(dic.get('contact'))
|
795
|
-
result.previous_publications = [LeadModel.from_dic(lead) for lead in dic.get('previous_publications', [])]
|
796
|
-
return result
|
797
|
-
|
798
|
-
def to_dic(self):
|
799
|
-
result = super().to_dic()
|
800
|
-
result["contact"] = self.contact.to_dic()
|
801
|
-
return result
|
802
|
-
|
803
|
-
def to_csv(self, board_name: str) -> List[str]:
|
804
|
-
return [self.message.source, self.contact.real_name, self.contact.title, self.contact.email,
|
805
|
-
self.notes, board_name, self.status,
|
806
|
-
self.followup_date.strftime("%d.%m.%Y %H:%M") if self.followup_date else "",
|
807
|
-
self.message.message.replace('\n', ' ').strip()]
|
808
|
-
|
809
|
-
|
810
|
-
class BoardModel(BaseModel):
|
811
|
-
pass
|
812
|
-
|
813
|
-
def __init__(self):
|
814
|
-
super().__init__()
|
815
|
-
self.name = None
|
816
|
-
self.user_id = None
|
817
|
-
self.statuses: List[BoardedStatus] = []
|
818
|
-
self.is_primary = None
|
819
|
-
self.default = False
|
820
|
-
|
821
|
-
@classmethod
|
822
|
-
def from_dic(cls, dic: dict):
|
823
|
-
if not dic:
|
824
|
-
return None
|
825
|
-
|
826
|
-
model = BoardModel()
|
827
|
-
for k, v in dic.items():
|
828
|
-
setattr(model, k, v)
|
829
|
-
|
830
|
-
model.id = dic.get('_id')
|
831
|
-
model.statuses = [BoardedStatus.from_dic(status) for status in dic.get('statuses', [])]
|
832
|
-
return model
|
833
|
-
|
834
|
-
def to_dic(self):
|
835
|
-
result = copy.deepcopy(self.__dict__)
|
836
|
-
result["statuses"] = [BoardedStatus.to_dic(status) for status in self.statuses]
|
837
|
-
|
838
|
-
for status in result['statuses']:
|
839
|
-
status['board_id'] = result['id']
|
840
|
-
|
841
|
-
return result
|
842
|
-
|
843
|
-
|
844
|
-
class BoardedStatus:
|
845
|
-
pass
|
846
|
-
|
847
|
-
def __init__(self):
|
848
|
-
self.id = None
|
849
|
-
self.name = None
|
850
|
-
self.order = 0
|
851
|
-
self.is_primary = False
|
852
|
-
self.default = False
|
853
|
-
self.user_leads = 0
|
854
|
-
self.collapsed = False
|
855
|
-
|
856
|
-
def to_dic(self):
|
857
|
-
self.id = self.name
|
858
|
-
return copy.deepcopy(self.__dict__)
|
859
|
-
|
860
|
-
@classmethod
|
861
|
-
def from_dic(cls, dic: dict):
|
862
|
-
if not dic:
|
863
|
-
return None
|
864
|
-
model = cls()
|
865
|
-
for k, v in dic.items():
|
866
|
-
setattr(model, k, v)
|
867
|
-
return model
|
868
|
-
|
869
|
-
|
870
|
-
class Profile:
|
871
|
-
pass
|
872
|
-
|
873
|
-
def __init__(self):
|
874
|
-
self.title = ''
|
875
|
-
self.phone = ''
|
876
|
-
self.skype = ''
|
877
|
-
self.display_name = ''
|
878
|
-
self.real_name = ''
|
879
|
-
self.email = ''
|
880
|
-
self.photo_url = ''
|
881
|
-
self.main = False
|
882
|
-
|
883
|
-
def to_dic(self):
|
884
|
-
return copy.deepcopy(self.__dict__)
|
885
|
-
|
886
|
-
@classmethod
|
887
|
-
def from_dic(cls, dic: dict):
|
888
|
-
if not dic:
|
889
|
-
return None
|
890
|
-
model = cls()
|
891
|
-
for k, v in dic.items():
|
892
|
-
setattr(model, k, v)
|
893
|
-
return model
|
894
|
-
|
895
|
-
|
896
|
-
class SlackMemberInformation(BaseModel, Profile):
|
897
|
-
workspace: str
|
898
|
-
sender_id: str
|
899
|
-
images: dict
|
900
|
-
full_text: str
|
901
|
-
deleted: bool = False
|
902
|
-
is_bot: bool = False
|
903
|
-
is_app_user: bool = False
|
904
|
-
is_admin: bool = False
|
905
|
-
is_owner: bool = False
|
906
|
-
is_email_confirmed: bool = False
|
907
|
-
online: Optional[str] = None
|
908
|
-
online_updated_at: datetime = None
|
909
|
-
timezone: SlackTimeZone = None
|
910
|
-
source: Source = None
|
911
|
-
|
912
|
-
@classmethod
|
913
|
-
def from_dic(cls, dic: dict):
|
914
|
-
model: SlackMemberInformation = cls()
|
915
|
-
if not dic:
|
916
|
-
return None
|
917
|
-
|
918
|
-
for k, v in dic.items():
|
919
|
-
setattr(model, k, v)
|
920
|
-
|
921
|
-
model.online = dic.get('online', '') == "active"
|
922
|
-
model: SlackMemberInformation | None = super().from_dic(dic)
|
923
|
-
model.source = Source.from_dic(dic.get('source'))
|
924
|
-
return model
|
925
|
-
|
926
|
-
def to_dic(self):
|
927
|
-
result = copy.deepcopy(self.__dict__)
|
928
|
-
if result.get('source'):
|
929
|
-
result['source'] = Source.to_dic(result.get('source'))
|
930
|
-
return result
|
931
|
-
|
932
|
-
@staticmethod
|
933
|
-
def from_slack_response(slack_profile: dict, source: Source = None):
|
934
|
-
member_info: SlackMemberInformation = SlackMemberInformation()
|
935
|
-
member_info.source = source
|
936
|
-
member_info.sender_id = slack_profile.get("id")
|
937
|
-
member_info.display_name = slack_profile["profile"].get("display_name")
|
938
|
-
member_info.real_name = slack_profile["profile"].get("real_name")
|
939
|
-
member_info.title = slack_profile["profile"].get("title")
|
940
|
-
member_info.phone = slack_profile["profile"].get("phone")
|
941
|
-
member_info.skype = slack_profile["profile"].get("skype")
|
942
|
-
member_info.email = slack_profile["profile"].get("email")
|
943
|
-
member_info.images = {
|
944
|
-
'image_24': slack_profile.get("profile", {}).get("image_24",
|
945
|
-
'https://a.slack-edge.com/80588/img/slackbot_24.png'),
|
946
|
-
'image_32': slack_profile.get("profile", {}).get("image_32",
|
947
|
-
'https://a.slack-edge.com/80588/img/slackbot_32.png'),
|
948
|
-
'image_48': slack_profile.get("profile", {}).get("image_48",
|
949
|
-
'https://a.slack-edge.com/80588/img/slackbot_48.png'),
|
950
|
-
'image_72': slack_profile.get("profile", {}).get("image_72",
|
951
|
-
'https://a.slack-edge.com/80588/img/slackbot_72.png'),
|
952
|
-
'image_192': slack_profile.get("profile", {}).get("image_192",
|
953
|
-
'https://a.slack-edge.com/80588/img/slackbot_192.png'),
|
954
|
-
'image_512': slack_profile.get("profile", {}).get("image_512",
|
955
|
-
'https://a.slack-edge.com/80588/img/slackbot_512.png'),
|
956
|
-
|
957
|
-
}
|
958
|
-
member_info.timezone = {"tz": slack_profile.get("tz"), "tz_label": slack_profile.get("tz_label"),
|
959
|
-
"tz_offset": slack_profile.get("tz_offset")}
|
960
|
-
return member_info
|
961
|
-
|
962
|
-
|
963
|
-
class UserContact(SlackMemberInformation):
|
964
|
-
chat_id: str
|
965
|
-
user_id: ObjectId
|
966
|
-
source_id: str
|
967
|
-
scheduled_messages: List[ScheduledChatMessage] = []
|
968
|
-
last_message_at: Optional[datetime]
|
969
|
-
|
970
|
-
@classmethod
|
971
|
-
def from_dic(cls, dic: dict):
|
972
|
-
if not dic:
|
973
|
-
return None
|
974
|
-
model: UserContact | None = super().from_dic(dic)
|
975
|
-
model.chat_history = [ChatMessage.from_dic(message) for message in dic.get('chat_history', [])]
|
976
|
-
model.scheduled_messages = [ScheduledChatMessage.from_dic(item) for item in dic.get("scheduled_messages", [])]
|
977
|
-
return model
|
978
|
-
|
979
|
-
|
980
|
-
class SlackTimeZone:
|
981
|
-
tz: Optional[str]
|
982
|
-
tz_label: Optional[str]
|
983
|
-
tz_offset: Optional[int]
|
984
|
-
|
985
|
-
|
986
|
-
class ExtendedSlackMemberInformation(SlackMemberInformation):
|
987
|
-
previous_publications = []
|
988
|
-
name: str = None
|
989
|
-
bots: List[BotInfo] = []
|
990
|
-
|
991
|
-
@classmethod
|
992
|
-
def from_dic(cls, dic: dict):
|
993
|
-
model: ExtendedSlackMemberInformation | None = super().from_dic(dic)
|
994
|
-
if not model:
|
995
|
-
return None
|
996
|
-
|
997
|
-
model.previous_publications = [LeadModel.from_dic(lead) for lead in dic.get('previous_publications', [])]
|
998
|
-
model.bots = [BotInfo.from_dic(bot) for bot in dic.get('bots', [])]
|
999
|
-
return model
|
1000
|
-
|
1001
|
-
@staticmethod
|
1002
|
-
def to_lead(contact: ExtendedSlackMemberInformation) -> ExtendedUserLeadModel:
|
1003
|
-
lead = ExtendedUserLeadModel()
|
1004
|
-
lead.id = str(contact.id)
|
1005
|
-
lead.created_at = contact.created_at
|
1006
|
-
lead.notes = ""
|
1007
|
-
lead.slack_channel = None
|
1008
|
-
lead.hidden = True
|
1009
|
-
lead.replies = []
|
1010
|
-
lead.reactions = 0
|
1011
|
-
lead.last_action_at = datetime.now(UTC)
|
1012
|
-
lead.created_at = datetime.now(UTC)
|
1013
|
-
if not hasattr(contact, "real_name"):
|
1014
|
-
contact.real_name = contact.name
|
1015
|
-
if not hasattr(contact, "display_name"):
|
1016
|
-
contact.display_name = contact.name
|
1017
|
-
|
1018
|
-
lead.linkedin_urls = [
|
1019
|
-
f"https://www.linkedin.com/search/results/all/?keywords={contact.real_name}&origin=GLOBAL_SEARCH_HEADER&sid=u%40F"]
|
1020
|
-
lead.message = MessageModel()
|
1021
|
-
lead.message.message = contact.real_name
|
1022
|
-
if contact.title:
|
1023
|
-
lead.message.message += contact.title
|
1024
|
-
lead.message.message_id = str(contact.id)
|
1025
|
-
lead.message.name = contact.source.source_name
|
1026
|
-
lead.message.source = contact.source
|
1027
|
-
lead.message.sender_id = contact.sender_id
|
1028
|
-
lead.message.companies = []
|
1029
|
-
lead.message.technologies = []
|
1030
|
-
lead.message.locations = []
|
1031
|
-
lead.message.chat_history = []
|
1032
|
-
lead.chat_viewed_at = datetime.now(UTC)
|
1033
|
-
lead.chat_history = []
|
1034
|
-
lead.previous_publications = contact.previous_publications if hasattr(contact, "previous_publications") else []
|
1035
|
-
lead.bots = contact.bots if hasattr(contact, "bots") else []
|
1036
|
-
lead.contact = contact
|
1037
|
-
return lead
|
1038
|
-
|
1039
|
-
|
1040
|
-
class UserTemplateModel(BaseModel):
|
1041
|
-
text: str
|
1042
|
-
subject: Optional[str]
|
1043
|
-
user_id: Optional[ObjectId]
|
1044
|
-
|
1045
|
-
|
1046
|
-
class CloudFileModel(BaseModel):
|
1047
|
-
blob_path: str
|
1048
|
-
public_url: str
|
1049
|
-
file_name: str
|
1050
|
-
|
1051
|
-
def __init__(self, blob_path: str, public_url: str, file_name: str):
|
1052
|
-
super().__init__()
|
1053
|
-
if not self.id:
|
1054
|
-
self.id = str(ObjectId())
|
1055
|
-
self.blob_path = blob_path
|
1056
|
-
self.public_url = public_url
|
1057
|
-
self.file_name = file_name
|
1058
|
-
|
1059
|
-
|
1060
|
-
class GroupedMessagesModel:
|
1061
|
-
messages: List[ChatMessage] = []
|
1062
|
-
|
1063
|
-
@classmethod
|
1064
|
-
def from_dic(cls, dic: dict):
|
1065
|
-
if not dic:
|
1066
|
-
return None
|
1067
|
-
|
1068
|
-
model = cls()
|
1069
|
-
model.messages = [ChatMessage.from_dic(message) for message in dic.get('messages', [])]
|
1070
|
-
return model
|
1071
|
-
|
1072
|
-
|
1073
|
-
class UserVerificationModel(DictionaryModel):
|
1074
|
-
pass
|
1075
|
-
|
1076
|
-
def __init__(self):
|
1077
|
-
super().__init__()
|
1078
|
-
self.email = None
|
1079
|
-
self.created_at = datetime.now(UTC)
|
1080
|
-
|
1081
|
-
|
1082
|
-
class UsersPage:
|
1083
|
-
users: List[UserModel]
|
1084
|
-
count: int = 0
|
1085
|
-
|
1086
|
-
def __init__(self, users: List[UserModel], count: int):
|
1087
|
-
self.users = users
|
1088
|
-
self.count = count
|
1089
|
-
|
1090
|
-
@staticmethod
|
1091
|
-
def from_dic(dic: dict):
|
1092
|
-
users = [UserModel.from_dic(doc) for doc in dic.get('page', [])]
|
1093
|
-
count = dic.get('count', 0)
|
1094
|
-
return UsersPage(users=users, count=count)
|
1095
|
-
|
1096
|
-
|
1097
|
-
class Feature(DictionaryModel):
|
1098
|
-
display_name: str
|
1099
|
-
name: FeaturesEnum
|
1100
|
-
description: str | None = None
|
1101
|
-
limit: int | None = None
|
1102
|
-
options: FeatureOptions | None = None
|
1103
|
-
|
1104
|
-
|
1105
|
-
class Subscription(BaseModel):
|
1106
|
-
features: list[Feature]
|
1107
|
-
duration_days: int
|
1108
|
-
name: str
|
1109
|
-
price: int
|
1110
|
-
limits: int
|
1111
|
-
trial: bool
|
1112
|
-
updated_at: datetime = None
|
1113
|
-
|
1114
|
-
@classmethod
|
1115
|
-
def from_dic(cls, dic: dict):
|
1116
|
-
if not dic:
|
1117
|
-
return None
|
1118
|
-
model: Subscription | None = super().from_dic(dic)
|
1119
|
-
model.features = [Feature.from_dic(feature) for feature in dic.get('features', [])]
|
1120
|
-
return model
|
1121
|
-
|
1122
|
-
|
1123
|
-
class LeadGuruFile(DictionaryModel):
|
1124
|
-
id: str = None
|
1125
|
-
blob_path: str
|
1126
|
-
content_type: str
|
1127
|
-
file_name: str = None
|
1128
|
-
|
1129
|
-
|
1130
|
-
class ScheduledMessage(BaseModel):
|
1131
|
-
post_at: datetime
|
1132
|
-
bot_id: ObjectId
|
1133
|
-
user_id: ObjectId
|
1134
|
-
sender_id: str
|
1135
|
-
text: str | None
|
1136
|
-
files: list
|