leadguru-jobs 0.414.0__py3-none-any.whl → 0.415.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.
Files changed (43) hide show
  1. {leadguru_jobs-0.414.0.dist-info → leadguru_jobs-0.415.0.dist-info}/METADATA +5 -10
  2. leadguru_jobs-0.415.0.dist-info/RECORD +26 -0
  3. lgt_jobs/__init__.py +4 -4
  4. lgt_jobs/jobs/analytics.py +1 -1
  5. lgt_jobs/jobs/archive_leads.py +2 -2
  6. lgt_jobs/jobs/bot_stats_update.py +9 -9
  7. lgt_jobs/jobs/chat_history.py +52 -57
  8. lgt_jobs/jobs/inbox_leads.py +6 -5
  9. lgt_jobs/jobs/mass_message.py +2 -2
  10. lgt_jobs/jobs/send_code.py +1 -1
  11. lgt_jobs/jobs/send_slack_message.py +24 -5
  12. lgt_jobs/jobs/update_slack_profile.py +14 -12
  13. lgt_jobs/jobs/user_balance_update.py +5 -5
  14. lgt_jobs/jobs/workspace_connect.py +5 -7
  15. lgt_jobs/main.py +11 -9
  16. lgt_jobs/runner.py +9 -6
  17. lgt_jobs/smtp.py +1 -1
  18. leadguru_jobs-0.414.0.dist-info/RECORD +0 -49
  19. lgt_jobs/lgt_common/__init__.py +0 -0
  20. lgt_jobs/lgt_common/discord_client/__init__.py +0 -0
  21. lgt_jobs/lgt_common/discord_client/discord_client.py +0 -62
  22. lgt_jobs/lgt_common/discord_client/methods.py +0 -16
  23. lgt_jobs/lgt_common/enums/__init__.py +0 -0
  24. lgt_jobs/lgt_common/enums/slack_errors.py +0 -6
  25. lgt_jobs/lgt_common/helpers.py +0 -18
  26. lgt_jobs/lgt_common/lgt_logging.py +0 -15
  27. lgt_jobs/lgt_common/pubsub/__init__.py +0 -0
  28. lgt_jobs/lgt_common/pubsub/command.py +0 -14
  29. lgt_jobs/lgt_common/pubsub/messages.py +0 -37
  30. lgt_jobs/lgt_common/pubsub/pubsubfactory.py +0 -51
  31. lgt_jobs/lgt_common/slack_client/__init__.py +0 -0
  32. lgt_jobs/lgt_common/slack_client/methods.py +0 -46
  33. lgt_jobs/lgt_common/slack_client/slack_client.py +0 -392
  34. lgt_jobs/lgt_common/slack_client/web_client.py +0 -167
  35. lgt_jobs/lgt_data/__init__.py +0 -0
  36. lgt_jobs/lgt_data/analytics.py +0 -723
  37. lgt_jobs/lgt_data/engine.py +0 -223
  38. lgt_jobs/lgt_data/enums.py +0 -68
  39. lgt_jobs/lgt_data/helpers.py +0 -2
  40. lgt_jobs/lgt_data/model.py +0 -956
  41. lgt_jobs/lgt_data/mongo_repository.py +0 -1015
  42. {leadguru_jobs-0.414.0.dist-info → leadguru_jobs-0.415.0.dist-info}/WHEEL +0 -0
  43. {leadguru_jobs-0.414.0.dist-info → leadguru_jobs-0.415.0.dist-info}/top_level.txt +0 -0
@@ -1,956 +0,0 @@
1
- from __future__ import annotations
2
- import copy
3
- import json
4
- from abc import ABC
5
- from datetime import datetime, UTC
6
- from typing import Optional, List, Dict
7
- from .enums import UserRole, SourceType
8
- from .helpers import get_linkedin_search_contact
9
- from bson import ObjectId
10
-
11
-
12
- class BaseModel(ABC):
13
- def __init__(self):
14
- self.id = None
15
- self.created_at = datetime.now(UTC)
16
-
17
- @classmethod
18
- def from_dic(cls, dic: dict):
19
- if not dic:
20
- return None
21
-
22
- model = cls()
23
- for k, v in dic.items():
24
- setattr(model, k, v)
25
-
26
- if '_id' in dic:
27
- setattr(model, 'id', dic['_id'])
28
-
29
- return model
30
-
31
- def to_dic(self):
32
- result = copy.deepcopy(self.__dict__)
33
- return result
34
-
35
-
36
- class Credentials(BaseModel):
37
- def __init__(self):
38
- super().__init__()
39
- self.token = None
40
- self.cookies = None
41
- self.invalid_creds = False
42
-
43
-
44
- class Source:
45
- def __init__(self):
46
- self.source_type: SourceType | None = None
47
- self.source_name = None
48
- self.source_id = None
49
-
50
- @classmethod
51
- def from_dic(cls, dic: dict):
52
- if not dic:
53
- return None
54
-
55
- model = cls()
56
- for k, v in dic.items():
57
- setattr(model, k, v)
58
-
59
- return model
60
-
61
- def to_dic(self):
62
- result = copy.deepcopy(self.__dict__)
63
- return result
64
-
65
-
66
- class BaseConfig:
67
- def __init__(self):
68
- self.owner = None
69
- self.id = None
70
-
71
- @classmethod
72
- def from_dic(cls, dic: dict):
73
- if not dic:
74
- return None
75
-
76
- model = cls()
77
- for k, v in dic.items():
78
- setattr(model, k, v)
79
-
80
- return model
81
-
82
- def to_dic(self):
83
- result = copy.deepcopy(self.__dict__)
84
- return result
85
-
86
-
87
- class Config(BaseConfig):
88
- def __init__(self):
89
- super().__init__()
90
- self.name = None
91
-
92
-
93
- class BaseBotModel(Credentials):
94
- def __init__(self):
95
- super().__init__()
96
- self.created_by = None
97
- self.user_name = None
98
- self.slack_url = None
99
- self.registration_link = None
100
- self.channels = None
101
- self.connected_channels = None
102
- self.channels_users = None
103
- self.users_count = None
104
- self.messages_received: int = 0
105
- self.messages_filtered: int = 0
106
- self.recent_messages: List[str] = []
107
- self.icon = None
108
- self.active_channels = {}
109
- self.paused_channels = []
110
- self.source: Source | None = None
111
- self.two_factor_required: bool = False
112
- self.banned: bool = False
113
- self.associated_user = None
114
- self.type: SourceType | None = None
115
- self.deleted = False
116
-
117
-
118
- class DedicatedBotModel(BaseBotModel):
119
- def __init__(self):
120
- super().__init__()
121
- self.user_id: Optional[str] = None
122
- self.updated_at: Optional[datetime] = datetime.now(UTC)
123
- self.servers: List[Server] = []
124
- self.state = 0
125
- self.source: Source | None = None
126
-
127
- def to_dic(self):
128
- result = copy.deepcopy(self.__dict__)
129
-
130
- if result.get('source'):
131
- result['source'] = Source.to_dic(result.get('source'))
132
-
133
- result['servers'] = [Server.to_dic(server) for server in self.servers]
134
- return result
135
-
136
- @classmethod
137
- def from_dic(cls, dic: dict):
138
- if not dic:
139
- return None
140
-
141
- model: DedicatedBotModel = cls()
142
- for k, v in dic.items():
143
- setattr(model, k, v)
144
-
145
- if '_id' in dic:
146
- setattr(model, 'id', dic['_id'])
147
-
148
- model.source = Source.from_dic(dic.get("source"))
149
- model.servers = [Server.from_dic(server) for server in dic.get("servers", [])]
150
- return model
151
-
152
-
153
- class Server:
154
- pass
155
-
156
- def __init__(self):
157
- self.id = None
158
- self.name = None
159
- self.channels: List[Channel] = []
160
- self.icon = None
161
- self.active = False
162
- self.deleted = False
163
- self.subscribers = 0
164
-
165
- @classmethod
166
- def from_dic(cls, dic: dict):
167
- if not dic:
168
- return None
169
-
170
- model = cls()
171
- for k, v in dic.items():
172
- if hasattr(model, k):
173
- setattr(model, k, v)
174
-
175
- model.channels = [Channel.from_dic(channel) for channel in dic.get("channels", [])]
176
- return model
177
-
178
- def to_dic(self):
179
- result = copy.deepcopy(self.__dict__)
180
- result['channels'] = [Channel.to_dic(channel) for channel in self.channels]
181
- return result
182
-
183
-
184
- class Channel:
185
- pass
186
-
187
- def __init__(self):
188
- self.id = None
189
- self.name = None
190
- self.type = None
191
- self.is_member = True
192
- self.active = False
193
- self.subscribers = 0
194
-
195
- @classmethod
196
- def from_dic(cls, dic: dict):
197
- if not dic:
198
- return None
199
-
200
- model = cls()
201
- for k, v in dic.items():
202
- if hasattr(model, k):
203
- setattr(model, k, v)
204
-
205
- return model
206
-
207
- def to_dic(self):
208
- result = copy.deepcopy(self.__dict__)
209
- return result
210
-
211
-
212
- class MessageModel:
213
- pass
214
-
215
- def __init__(self):
216
- self.message_id = None
217
- self.channel_id = None
218
- self.channel_name = None
219
- self.message = None
220
- self.name = None
221
- self.sender_id = None
222
- self.source: Source | None = None
223
- self.companies: List[str] = list()
224
- self.technologies: List[str] = list()
225
- self.locations: List[str] = list()
226
- self.configs: List[BaseConfig] = list()
227
- self.attachments: List[dict] = []
228
- self.timestamp = None
229
- self.tags: List[str] = []
230
-
231
- @classmethod
232
- def from_dic(cls, dic: dict):
233
- if not dic:
234
- return None
235
- if isinstance(dic.get('attachments'), str):
236
- dic['attachments'] = json.loads(dic['attachments'])
237
-
238
- model: MessageModel = cls()
239
- for k, v in dic.items():
240
- setattr(model, k, v)
241
-
242
- model.source = Source.from_dic(dic.get("source"))
243
- model.configs = [BaseConfig.from_dic(doc) for doc in dic.get("configs", [])]
244
- return model
245
-
246
- def to_dic(self):
247
- result = copy.deepcopy(self.__dict__)
248
-
249
- if result.get('source'):
250
- result['source'] = Source.to_dic(result.get('source'))
251
- if result.get('configs'):
252
- result['configs'] = [BaseConfig.to_dic(config) for config in result.get('configs')]
253
- return result
254
-
255
-
256
- class UserModel(BaseModel):
257
- def __init__(self):
258
- super().__init__()
259
- self.email: Optional[str] = None
260
- self.password: Optional[str] = None
261
- self.roles: List[str] = []
262
- self.user_name: str = ''
263
- self.company: str = ''
264
- self.company_size: Optional[int] = None
265
- self.company_industries: Optional[List[str]] = None
266
- self.company_technologies: Optional[List[str]] = None
267
- self.company_locations: Optional[List[str]] = None
268
- self.company_web_site: str = ''
269
- self.company_description: str = ''
270
- self.position: str = ''
271
- self.new_message_notified_at: Optional[datetime] = None
272
- self.photo_url: str = ''
273
- self.slack_profile = SlackProfile()
274
- self.leads_limit: Optional[int] = None
275
- self.leads_proceeded: Optional[int] = None
276
- self.leads_filtered: Optional[int] = None
277
- self.leads_limit_updated_at: Optional[int] = None
278
- self.excluded_channels: Optional[Dict[str, List[str]]] = None
279
- self.excluded_workspaces: Optional[List[str]] = []
280
- self.keywords: Optional[List[str]] = None
281
- self.block_words: Optional[List[str]] = None
282
- self.paid_lead_price: int = 1
283
- self.state: int = 0
284
- self.credits_exceeded_at: Optional[datetime] = None
285
- self.unanswered_leads_period = None
286
- self.inactive = None
287
- self.slack_users: List[SlackUser] = []
288
- self.discord_users: List[DiscordUser] = []
289
-
290
- @classmethod
291
- def from_dic(cls, dic: dict):
292
- if not dic:
293
- return None
294
-
295
- model: UserModel = cls()
296
- for k, v in dic.items():
297
- setattr(model, k, v)
298
-
299
- if '_id' in dic:
300
- setattr(model, 'id', dic['_id'])
301
-
302
- model.slack_profile = SlackProfile.from_dic(dic.get('slack_profile'))
303
- model.slack_users = [SlackUser.from_dic(user) for user in dic.get('slack_users', [])]
304
- model.discord_users = [DiscordUser.from_dic(user) for user in dic.get('discord_users', [])]
305
- return model
306
-
307
- def to_dic(self):
308
- result = copy.deepcopy(self.__dict__)
309
-
310
- if result.get('slack_profile', None):
311
- result['slack_profile'] = result.get('slack_profile').__dict__
312
-
313
- return result
314
-
315
- @property
316
- def is_admin(self):
317
- return UserRole.ADMIN in self.roles
318
-
319
- def get_slack_user(self, slack_email: str):
320
- return next(filter(lambda x: slack_email == x.email, self.slack_users), None)
321
-
322
- def get_discord_user(self, login: str):
323
- return next(filter(lambda x: login == x.login, self.discord_users), None)
324
-
325
-
326
- class DiscordUser(BaseModel):
327
- pass
328
-
329
- def __init__(self):
330
- super().__init__()
331
- self.created_at = datetime.now(UTC)
332
- self.login = ''
333
- self.captcha_key = ''
334
- self.status = None
335
- self.workspaces: List[UserWorkspace] = []
336
-
337
- def to_dic(self):
338
- result = copy.deepcopy(self.__dict__)
339
-
340
- if result.get('workspaces', None):
341
- result['workspaces'] = [ws.__dict__ for ws in result.get('workspaces')]
342
-
343
- return result
344
-
345
- @classmethod
346
- def from_dic(cls, dic: dict):
347
- if not dic:
348
- return None
349
-
350
- model = cls()
351
- for k, v in dic.items():
352
- setattr(model, k, v)
353
-
354
- model.workspaces = [UserWorkspace.from_dic(ws) for ws in dic.get('workspaces', [])]
355
- return model
356
-
357
-
358
- class SlackUser:
359
- pass
360
-
361
- def __init__(self):
362
- self.created_at = datetime.now(UTC)
363
- self.cookies = {}
364
- self.email = ''
365
- self.status = None
366
- self.workspaces: List[UserWorkspace] = []
367
-
368
- def to_dic(self):
369
- result = copy.deepcopy(self.__dict__)
370
-
371
- if result.get('workspaces', None):
372
- result['workspaces'] = [ws.__dict__ for ws in result.get('workspaces')]
373
-
374
- return result
375
-
376
- @classmethod
377
- def from_dic(cls, dic: dict):
378
- if not dic:
379
- return None
380
-
381
- model = cls()
382
- for k, v in dic.items():
383
- setattr(model, k, v)
384
-
385
- model.workspaces = [UserWorkspace.from_dic(ws) for ws in dic.get('workspaces', [])]
386
- return model
387
-
388
-
389
- class UserWorkspace:
390
- pass
391
-
392
- def __init__(self):
393
- super().__init__()
394
- self.id = ''
395
- self.name = ''
396
- self.url = ''
397
- self.domain = ''
398
- self.active_users = ''
399
- self.profile_photos = []
400
- self.associated_user = ''
401
- self.magic_login_url = ''
402
- self.magic_login_code = ''
403
- self.user_email = ''
404
- self.user_type = ''
405
- self.variant = ''
406
- self.token = ''
407
- self.icon = ''
408
- self.two_factor_required = False
409
-
410
- @classmethod
411
- def from_dic(cls, dic: dict):
412
- if not dic:
413
- return None
414
-
415
- model: UserWorkspace = cls()
416
- for k, v in dic.items():
417
- setattr(model, k, v)
418
-
419
- model.icon = dic.get('icon_88', "")
420
- return model
421
-
422
-
423
- class UserResetPasswordModel(BaseModel):
424
- pass
425
-
426
- def __init__(self):
427
- super().__init__()
428
- self.email = None
429
-
430
-
431
- class LeadModel(BaseModel):
432
- def __init__(self):
433
- super().__init__()
434
- self.status = ''
435
- self.notes = ''
436
- self.archived = False
437
- self.message: Optional[MessageModel] = None
438
- self.hidden = False
439
- self.followup_date = None
440
- self.score = 0
441
- self.board_id = None
442
- self.linkedin_urls = []
443
- self.likes = 0
444
- self.reactions = 0
445
- self.replies = []
446
- self.last_action_at: Optional[datetime] = None
447
- self.scheduled_messages: List[ScheduledChatMessage] = []
448
- self.slack_channel = None
449
-
450
- def is_dedicated_lead(self) -> bool:
451
- return self.message and \
452
- hasattr(self.message, "dedicated_slack_options") and \
453
- self.message.dedicated_slack_options
454
-
455
- @classmethod
456
- def from_dic(cls, dic: dict):
457
- if not dic:
458
- return None
459
-
460
- model: LeadModel = cls()
461
- for k, v in dic.items():
462
- setattr(model, k, v)
463
-
464
- model.message = MessageModel.from_dic(dic['message'])
465
- model.scheduled_messages = [ScheduledChatMessage.from_dic(item) for item in dic.get("scheduled_messages", [])]
466
-
467
- if not model.last_action_at:
468
- model.last_action_at = model.created_at
469
-
470
- return model
471
-
472
- def to_dic(self):
473
- result = copy.deepcopy(self.__dict__)
474
- result["message"] = self.message.to_dic()
475
- result['archived'] = self.archived
476
- return result
477
-
478
-
479
- class ExtendedLeadModel(LeadModel):
480
- def __init__(self):
481
- super().__init__()
482
- self.previous_publications = []
483
- self.last_conversation: List[ChatMessage] = []
484
- self.contact: SlackMemberInformation | None = None
485
- self.deleted = False
486
- self.user_lead: UserLeadModel | None = None
487
- self.dedicated: bool = False
488
- self.bots: List[BotInfo] = []
489
-
490
- @classmethod
491
- def from_dic(cls, dic: dict):
492
- if not dic:
493
- return None
494
-
495
- result: ExtendedLeadModel | None = LeadModel.from_dic(dic)
496
- if not result:
497
- return None
498
-
499
- result.contact = SlackMemberInformation.from_dic(dic.get('contact'))
500
- result.previous_publications = [LeadModel.from_dic(lead) for lead in dic.get('previous_publications', [])]
501
- result.user_lead = UserLeadModel.from_dic(dic.get('user_lead'))
502
- result.last_conversation = [ChatMessage.from_dic(message) for message in dic.get('last_conversation', [])]
503
- result.bots = [BotInfo.from_dic(bot) for bot in dic.get('bots', [])]
504
- return result
505
-
506
- def to_csv(self, board_name: str) -> List[str]:
507
- return [self.message.source, self.contact.real_name, self.contact.title, self.contact.email,
508
- self.notes, board_name, self.status,
509
- self.followup_date.strftime("%d.%m.%Y %H:%M") if self.followup_date else "",
510
- self.message.message.replace('\n', ' ').strip()]
511
-
512
-
513
- class BotInfo:
514
- def __init__(self):
515
- self.id = None
516
- self.invalid_creds: bool | None = False
517
- self.source = None
518
- self.banned: bool | None = False
519
- self.user_name: str = ''
520
- self.associated_user: str | None = ''
521
-
522
- @classmethod
523
- def from_dic(cls, dic: dict):
524
- if not dic:
525
- return None
526
-
527
- model = BotInfo()
528
- for k, v in dic.items():
529
- if hasattr(model, k):
530
- setattr(model, k, v)
531
-
532
- if '_id' in dic:
533
- setattr(model, 'id', dic['_id'])
534
-
535
- return model
536
-
537
- def to_dic(self):
538
- result = copy.deepcopy(self.__dict__)
539
- return result
540
-
541
-
542
- class SlackReplyModel(BaseModel):
543
- def __init__(self):
544
- super().__init__()
545
- self.type = None
546
- self.user = None
547
- self.username = None
548
- self.text = None
549
- self.thread_ts = None
550
- self.parent_user_id = None
551
- self.ts = None
552
- self.files = []
553
- self.attachments = []
554
-
555
- @classmethod
556
- def from_slack_response(cls, dic: dict):
557
- if not dic:
558
- return None
559
-
560
- model = cls()
561
- for k, v in dic.items():
562
- setattr(model, k, v)
563
-
564
- js_ticks = int(model.ts.split('.')[0] + model.ts.split('.')[1][3:])
565
- model.created_at = datetime.fromtimestamp(js_ticks / 1000.0)
566
-
567
- if model.files:
568
- model.files = [{"url_private_download": file.get("url_private_download")} for file in model.files]
569
-
570
- return model
571
-
572
-
573
- class ChatMessage:
574
- bot_id: ObjectId
575
- user_id: ObjectId
576
- sender_id: str
577
- text: str
578
- user: str
579
- ts: str
580
- viewed: bool
581
- files: list
582
- attachments: list[dict] | None
583
- created_at: datetime | None
584
-
585
- class SlackFileModel:
586
- def __init__(self):
587
- self.id = None
588
- self.name = None
589
- self.title = None
590
- self.filetype = None
591
- self.size = 0
592
- self.mimetype = None
593
- self.download_url = None
594
-
595
- def to_dic(self):
596
- result = copy.deepcopy(self.__dict__)
597
- return result
598
-
599
- def __init__(self):
600
- self.viewed = False
601
- self.text: str = ''
602
- self.created_at: datetime
603
- self.user = ''
604
- self.ts = ''
605
- self.files = []
606
- self.attachments = []
607
-
608
- def to_dic(self):
609
- result = copy.deepcopy(self.__dict__)
610
- if self.files and 'files' in result:
611
- result['files'] = [x.to_dic() if isinstance(x, ChatMessage.SlackFileModel) else x for x in self.files]
612
-
613
- return result
614
-
615
- @classmethod
616
- def from_dic(cls, dic: dict):
617
- if not dic:
618
- return None
619
- model = cls()
620
- for k, v in dic.items():
621
- setattr(model, k, v)
622
- return model
623
-
624
-
625
- class ScheduledChatMessage(ChatMessage):
626
- post_at: Optional[datetime]
627
- jib: Optional[str]
628
-
629
- def __init__(self):
630
- super(ScheduledChatMessage, self).__init__()
631
-
632
- self.post_at = None
633
- self.jib = None
634
-
635
-
636
- class UserLeadModel(LeadModel):
637
- pass
638
-
639
- def __init__(self):
640
- super().__init__()
641
- self.order: int = 0
642
- self.followup_date = None
643
- self.user_id = None
644
- self.chat_viewed_at = None
645
- self.chat_history: List[ChatMessage] = []
646
- self.board_id = None
647
-
648
- @classmethod
649
- def from_dic(cls, dic: dict):
650
- if not dic:
651
- return None
652
-
653
- result: UserLeadModel | None = super().from_dic(dic)
654
- if not result:
655
- return None
656
-
657
- result.chat_history = [ChatMessage.from_dic(message) for message in dic.get('chat_history', [])]
658
- result.chat_viewed_at = dic.get('chat_viewed_at')
659
- result.chat_history = sorted(result.chat_history, key=lambda x: x.created_at)
660
- return result
661
-
662
- @staticmethod
663
- def from_route(lead: LeadModel):
664
- model_dict = lead.to_dic()
665
- result = UserLeadModel.from_dic(model_dict)
666
- result.order = 0
667
-
668
- result.message = MessageModel.from_dic(model_dict['message'])
669
- result.chat_history = []
670
- result.chat_viewed_at = None
671
- return result
672
-
673
-
674
- class ExtendedUserLeadModel(UserLeadModel):
675
- pass
676
-
677
- def __init__(self):
678
- super().__init__()
679
- self.contact: SlackMemberInformation | None = None
680
- self.previous_publications = []
681
- self.bots: List[BotInfo] = []
682
-
683
- @classmethod
684
- def from_dic(cls, dic: dict):
685
- if not dic:
686
- return None
687
-
688
- result: ExtendedUserLeadModel | None = super().from_dic(dic)
689
- if not result:
690
- return None
691
-
692
- result.contact = SlackMemberInformation.from_dic(dic.get('contact'))
693
- result.previous_publications = [LeadModel.from_dic(lead) for lead in dic.get('previous_publications', [])]
694
- return result
695
-
696
- def to_dic(self):
697
- result = super().to_dic()
698
- result["contact"] = self.contact.to_dic()
699
- return result
700
-
701
- def to_csv(self, board_name: str) -> List[str]:
702
- return [self.message.source, self.contact.real_name, self.contact.title, self.contact.email,
703
- self.notes, board_name, self.status,
704
- self.followup_date.strftime("%d.%m.%Y %H:%M") if self.followup_date else "",
705
- self.message.message.replace('\n', ' ').strip()]
706
-
707
-
708
- class BoardModel(BaseModel):
709
- pass
710
-
711
- def __init__(self):
712
- super().__init__()
713
- self.name = None
714
- self.user_id = None
715
- self.statuses = list()
716
- self.is_primary = None
717
- self.default = False
718
-
719
- @classmethod
720
- def from_dic(cls, dic: dict):
721
- if not dic:
722
- return None
723
-
724
- model = BoardModel()
725
- for k, v in dic.items():
726
- setattr(model, k, v)
727
-
728
- model.id = dic.get('_id')
729
- model.statuses = [BoardedStatus.from_dic(status) for status in dic.get('statuses', [])]
730
- return model
731
-
732
- def to_dic(self):
733
- result = copy.deepcopy(self.__dict__)
734
- result["statuses"] = [BoardedStatus.to_dic(status) for status in self.statuses]
735
-
736
- for status in result['statuses']:
737
- status['board_id'] = result['id']
738
-
739
- return result
740
-
741
-
742
- class BoardedStatus:
743
- pass
744
-
745
- def __init__(self):
746
- self.id = None
747
- self.name = None
748
- self.order = 0
749
- self.is_primary = False
750
- self.default = False
751
-
752
- def to_dic(self):
753
- self.id = self.name
754
- return copy.deepcopy(self.__dict__)
755
-
756
- @classmethod
757
- def from_dic(cls, dic: dict):
758
- if not dic:
759
- return None
760
- model = cls()
761
- for k, v in dic.items():
762
- setattr(model, k, v)
763
- return model
764
-
765
-
766
- class SlackProfile:
767
- pass
768
-
769
- def __init__(self):
770
- self.title = ''
771
- self.phone = ''
772
- self.skype = ''
773
- self.display_name = ''
774
- self.real_name = ''
775
- self.email = ''
776
-
777
- def to_dic(self):
778
- return copy.deepcopy(self.__dict__)
779
-
780
- @classmethod
781
- def from_dic(cls, dic: dict):
782
- if not dic:
783
- return None
784
- model = cls()
785
- for k, v in dic.items():
786
- setattr(model, k, v)
787
- return model
788
-
789
-
790
- class SlackMemberInformation(BaseModel, SlackProfile):
791
- workspace: str
792
- sender_id: str
793
- images: dict
794
- full_text: str
795
- deleted: bool = False
796
- is_bot: bool = False
797
- is_app_user: bool = False
798
- is_admin: bool = False
799
- is_owner: bool = False
800
- is_email_confirmed: bool = False
801
- online: Optional[str] = None
802
- online_updated_at: datetime = None
803
- timezone: SlackTimeZone = None
804
- source: Source = None
805
-
806
- @classmethod
807
- def from_dic(cls, dic: dict):
808
- model: SlackMemberInformation = cls()
809
- if not dic:
810
- return None
811
-
812
- for k, v in dic.items():
813
- setattr(model, k, v)
814
-
815
- model.online = dic.get('online', '') == "active"
816
- model: SlackMemberInformation | None = super().from_dic(dic)
817
- model.source = Source.from_dic(dic.get('source'))
818
- return model
819
-
820
- def to_dic(self):
821
- result = copy.deepcopy(self.__dict__)
822
- if result.get('source'):
823
- result['source'] = Source.to_dic(result.get('source'))
824
- return result
825
-
826
- @staticmethod
827
- def from_slack_response(slack_profile: dict, source: Source = None):
828
- member_info: SlackMemberInformation = SlackMemberInformation()
829
- member_info.source = source
830
- member_info.sender_id = slack_profile.get("id")
831
- member_info.display_name = slack_profile["profile"].get("display_name")
832
- member_info.real_name = slack_profile["profile"].get("real_name")
833
- member_info.title = slack_profile["profile"].get("title")
834
- member_info.phone = slack_profile["profile"].get("phone")
835
- member_info.skype = slack_profile["profile"].get("skype")
836
- member_info.email = slack_profile["profile"].get("email")
837
- member_info.images = {
838
- 'image_24': slack_profile.get("profile", {}).get("image_24",
839
- 'https://a.slack-edge.com/80588/img/slackbot_24.png'),
840
- 'image_32': slack_profile.get("profile", {}).get("image_32",
841
- 'https://a.slack-edge.com/80588/img/slackbot_32.png'),
842
- 'image_48': slack_profile.get("profile", {}).get("image_48",
843
- 'https://a.slack-edge.com/80588/img/slackbot_48.png'),
844
- 'image_72': slack_profile.get("profile", {}).get("image_72",
845
- 'https://a.slack-edge.com/80588/img/slackbot_72.png'),
846
- 'image_192': slack_profile.get("profile", {}).get("image_192",
847
- 'https://a.slack-edge.com/80588/img/slackbot_192.png'),
848
- 'image_512': slack_profile.get("profile", {}).get("image_512",
849
- 'https://a.slack-edge.com/80588/img/slackbot_512.png'),
850
-
851
- }
852
- member_info.timezone = {"tz": slack_profile.get("tz"), "tz_label": slack_profile.get("tz_label"),
853
- "tz_offset": slack_profile.get("tz_offset")}
854
- return member_info
855
-
856
-
857
- class UserContact(SlackMemberInformation):
858
- chat_id: str
859
- source_id: str
860
- scheduled_messages: List[ScheduledChatMessage] = []
861
-
862
- @classmethod
863
- def from_dic(cls, dic: dict):
864
- model: UserContact | None = super().from_dic(dic)
865
- model.chat_history = [ChatMessage.from_dic(message) for message in dic.get('chat_history', [])]
866
- model.scheduled_messages = [ScheduledChatMessage.from_dic(item) for item in dic.get("scheduled_messages", [])]
867
- return model
868
-
869
-
870
- class SlackTimeZone:
871
- tz: Optional[str]
872
- tz_label: Optional[str]
873
- tz_offset: Optional[int]
874
-
875
-
876
- class ExtendedSlackMemberInformation(SlackMemberInformation):
877
- previous_publications = []
878
- name: str = None
879
- bots: List[BotInfo] = []
880
-
881
- @classmethod
882
- def from_dic(cls, dic: dict):
883
- model: ExtendedSlackMemberInformation | None = super().from_dic(dic)
884
- if not model:
885
- return None
886
-
887
- model.previous_publications = [LeadModel.from_dic(lead) for lead in dic.get('previous_publications', [])]
888
- model.bots = [BotInfo.from_dic(bot) for bot in dic.get('bots', [])]
889
- return model
890
-
891
- @staticmethod
892
- def to_lead(contact: ExtendedSlackMemberInformation, linkedin_contacts: Dict[str, LinkedinContact] = None) \
893
- -> ExtendedUserLeadModel:
894
- lead = ExtendedUserLeadModel()
895
- lead.id = str(contact.id)
896
- lead.created_at = contact.created_at
897
- lead.notes = ""
898
- lead.slack_channel = None
899
- lead.hidden = True
900
- lead.replies = []
901
- lead.reactions = 0
902
- lead.last_action_at = datetime.now(UTC)
903
- lead.created_at = datetime.now(UTC)
904
- if not hasattr(contact, "real_name"):
905
- contact.real_name = contact.name
906
- if not hasattr(contact, "display_name"):
907
- contact.display_name = contact.name
908
-
909
- lead.linkedin_urls = [linkedin_contacts[contact.sender_id].urls[0].get("url")] \
910
- if linkedin_contacts and contact.sender_id in linkedin_contacts \
911
- else [get_linkedin_search_contact(contact.real_name)]
912
- lead.message = MessageModel()
913
- lead.message.message = contact.real_name
914
- if contact.title:
915
- lead.message.message += contact.title
916
- lead.message.message_id = str(contact.id)
917
- lead.message.name = contact.source.source_name
918
- lead.message.source = contact.source
919
- lead.message.sender_id = contact.sender_id
920
- lead.message.companies = []
921
- lead.message.technologies = []
922
- lead.message.locations = []
923
- lead.message.chat_history = []
924
- lead.chat_viewed_at = datetime.now(UTC)
925
- lead.chat_history = []
926
- lead.previous_publications = contact.previous_publications if hasattr(contact, "previous_publications") else []
927
- lead.bots = contact.bots if hasattr(contact, "bots") else []
928
- lead.contact = contact
929
- return lead
930
-
931
-
932
- class UserTemplateModel(BaseModel):
933
- text: str
934
- subject: Optional[str]
935
- user_id: Optional[ObjectId]
936
-
937
-
938
- class LinkedinContact(BaseModel):
939
- full_name: str
940
- slack_user: str
941
- title: str
942
- urls: List[dict]
943
-
944
-
945
- class CloudFileModel(BaseModel):
946
- blob_path: str
947
- public_url: str
948
- file_name: str
949
-
950
- def __init__(self, blob_path: str, public_url: str, file_name: str):
951
- super().__init__()
952
- if not self.id:
953
- self.id = str(ObjectId())
954
- self.blob_path = blob_path
955
- self.public_url = public_url
956
- self.file_name = file_name