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