leadguru-jobs 0.639.0__py3-none-any.whl → 0.641.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 (60) hide show
  1. {leadguru_jobs-0.639.0.dist-info → leadguru_jobs-0.641.0.dist-info}/METADATA +1 -1
  2. leadguru_jobs-0.641.0.dist-info/RECORD +109 -0
  3. lgt_jobs/lgt_data/models/boards/__init__.py +0 -0
  4. lgt_jobs/lgt_data/models/boards/board.py +39 -0
  5. lgt_jobs/lgt_data/models/boards/status.py +14 -0
  6. lgt_jobs/lgt_data/models/bots/__init__.py +0 -0
  7. lgt_jobs/lgt_data/models/bots/base_bot.py +44 -0
  8. lgt_jobs/lgt_data/models/bots/bot_info.py +33 -0
  9. lgt_jobs/lgt_data/models/bots/dedicated_bot.py +90 -0
  10. lgt_jobs/lgt_data/models/chat/__init__.py +0 -0
  11. lgt_jobs/lgt_data/models/chat/file.py +8 -0
  12. lgt_jobs/lgt_data/models/chat/grouped_messages.py +17 -0
  13. lgt_jobs/lgt_data/models/chat/message.py +85 -0
  14. lgt_jobs/lgt_data/models/chat/request.py +15 -0
  15. lgt_jobs/lgt_data/models/chat/scheduled_message.py +14 -0
  16. lgt_jobs/lgt_data/models/contacts/__init__.py +0 -0
  17. lgt_jobs/lgt_data/models/contacts/contact.py +22 -0
  18. lgt_jobs/lgt_data/models/external/__init__.py +0 -0
  19. lgt_jobs/lgt_data/models/external/cloud/__init__.py +0 -0
  20. lgt_jobs/lgt_data/models/external/cloud/file.py +18 -0
  21. lgt_jobs/lgt_data/models/external/discord/__init__.py +0 -0
  22. lgt_jobs/lgt_data/models/external/discord/user.py +45 -0
  23. lgt_jobs/lgt_data/models/external/slack/__init__.py +0 -0
  24. lgt_jobs/lgt_data/models/external/slack/timezone.py +8 -0
  25. lgt_jobs/lgt_data/models/external/slack/user.py +43 -0
  26. lgt_jobs/lgt_data/models/external/user_workspace.py +32 -0
  27. lgt_jobs/lgt_data/models/leads/__init__.py +0 -0
  28. lgt_jobs/lgt_data/models/leads/config.py +13 -0
  29. lgt_jobs/lgt_data/models/leads/extended_lead.py +46 -0
  30. lgt_jobs/lgt_data/models/leads/lead.py +48 -0
  31. lgt_jobs/lgt_data/models/leads/message.py +51 -0
  32. lgt_jobs/lgt_data/models/notifications/__init__.py +0 -0
  33. lgt_jobs/lgt_data/models/notifications/notification.py +248 -0
  34. lgt_jobs/lgt_data/models/notifications/notification_settings.py +52 -0
  35. lgt_jobs/lgt_data/models/people/__init__.py +0 -0
  36. lgt_jobs/lgt_data/models/people/people.py +75 -0
  37. lgt_jobs/lgt_data/models/people/profile.py +13 -0
  38. lgt_jobs/lgt_data/models/post/__init__.py +0 -0
  39. lgt_jobs/lgt_data/models/post/message.py +18 -0
  40. lgt_jobs/lgt_data/models/post/post.py +15 -0
  41. lgt_jobs/lgt_data/models/templates/__init__.py +0 -0
  42. lgt_jobs/lgt_data/models/templates/template.py +12 -0
  43. lgt_jobs/lgt_data/models/user/__init__.py +0 -0
  44. lgt_jobs/lgt_data/models/user/feature.py +10 -0
  45. lgt_jobs/lgt_data/models/user/general_settings.py +9 -0
  46. lgt_jobs/lgt_data/models/user/reset_password.py +7 -0
  47. lgt_jobs/lgt_data/models/user/subscription.py +22 -0
  48. lgt_jobs/lgt_data/models/user/user.py +95 -0
  49. lgt_jobs/lgt_data/models/user/user_follow_ups.py +20 -0
  50. lgt_jobs/lgt_data/models/user/user_page.py +19 -0
  51. lgt_jobs/lgt_data/models/user/verification.py +12 -0
  52. lgt_jobs/lgt_data/models/user_leads/__init__.py +0 -0
  53. lgt_jobs/lgt_data/models/user_leads/extended_user_lead.py +41 -0
  54. lgt_jobs/lgt_data/models/user_leads/user_lead.py +33 -0
  55. lgt_jobs/lgt_data/repositories/__init__.py +0 -0
  56. lgt_jobs/lgt_data/repositories/post/__init__.py +0 -0
  57. lgt_jobs/lgt_data/repositories/post/posts.py +28 -0
  58. leadguru_jobs-0.639.0.dist-info/RECORD +0 -54
  59. {leadguru_jobs-0.639.0.dist-info → leadguru_jobs-0.641.0.dist-info}/WHEEL +0 -0
  60. {leadguru_jobs-0.639.0.dist-info → leadguru_jobs-0.641.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,32 @@
1
+ class UserWorkspace:
2
+ pass
3
+
4
+ def __init__(self):
5
+ super().__init__()
6
+ self.id = ''
7
+ self.name = ''
8
+ self.url = ''
9
+ self.domain = ''
10
+ self.active_users = ''
11
+ self.profile_photos = []
12
+ self.associated_user = ''
13
+ self.magic_login_url = ''
14
+ self.magic_login_code = ''
15
+ self.user_email = ''
16
+ self.user_type = ''
17
+ self.variant = ''
18
+ self.token = ''
19
+ self.icon = ''
20
+ self.two_factor_required = False
21
+
22
+ @classmethod
23
+ def from_dic(cls, dic: dict):
24
+ if not dic:
25
+ return None
26
+
27
+ model: UserWorkspace = cls()
28
+ for k, v in dic.items():
29
+ setattr(model, k, v)
30
+
31
+ model.icon = dic.get('icon_88', "")
32
+ return model
File without changes
@@ -0,0 +1,13 @@
1
+ from lgt_jobs.lgt_data.models.base import DictionaryModel
2
+
3
+
4
+ class BaseConfig(DictionaryModel):
5
+ def __init__(self):
6
+ self.owner = None
7
+ self.id = None
8
+
9
+
10
+ class Config(BaseConfig):
11
+ def __init__(self):
12
+ super().__init__()
13
+ self.name = None
@@ -0,0 +1,46 @@
1
+ from typing import List
2
+
3
+ from lgt_jobs.lgt_data.models.bots.bot_info import BotInfo
4
+ from lgt_jobs.lgt_data.models.chat.message import ChatMessage
5
+ from lgt_jobs.lgt_data.models.contacts.contact import UserContact
6
+ from lgt_jobs.lgt_data.models.leads.lead import LeadModel
7
+ from lgt_jobs.lgt_data.models.people.people import SlackMemberInformation
8
+ from lgt_jobs.lgt_data.models.user_leads.user_lead import UserLeadModel
9
+
10
+
11
+ class ExtendedLeadModel(LeadModel):
12
+ def __init__(self):
13
+ super().__init__()
14
+ self.previous_publications = []
15
+ self.last_conversation: List[ChatMessage] = []
16
+ self.contact: SlackMemberInformation | None = None
17
+ self.deleted = False
18
+ self.user_lead: UserLeadModel | None = None
19
+ self.dedicated: bool = False
20
+ self.bots: List[BotInfo] = []
21
+ self.user_contact: UserContact | None = None
22
+ self.paid: bool = False
23
+ self.hidden_by_user: bool = False
24
+
25
+ @classmethod
26
+ def from_dic(cls, dic: dict):
27
+ if not dic:
28
+ return None
29
+
30
+ result: ExtendedLeadModel | None = LeadModel.from_dic(dic)
31
+ if not result:
32
+ return None
33
+
34
+ result.contact = SlackMemberInformation.from_dic(dic.get('contact'))
35
+ result.user_contact = UserContact.from_dic(dic.get('user_contact'))
36
+ result.previous_publications = [LeadModel.from_dic(lead) for lead in dic.get('previous_publications', [])]
37
+ result.user_lead = UserLeadModel.from_dic(dic.get('user_lead'))
38
+ result.last_conversation = [ChatMessage.from_dic(message) for message in dic.get('last_conversation', [])]
39
+ result.bots = [BotInfo.from_dic(bot) for bot in dic.get('bots', [])]
40
+ return result
41
+
42
+ def to_csv(self, board_name: str) -> List[str]:
43
+ return [self.message.source, self.contact.real_name, self.contact.title, self.contact.email,
44
+ self.notes, board_name, self.status,
45
+ self.followup_date.strftime("%d.%m.%Y %H:%M") if self.followup_date else "",
46
+ self.message.message.replace('\n', ' ').strip()]
@@ -0,0 +1,48 @@
1
+ import copy
2
+ from datetime import datetime
3
+ from typing import Optional
4
+
5
+ from lgt_jobs.lgt_data.models.base import BaseModel
6
+ from lgt_jobs.lgt_data.models.leads.message import MessageModel
7
+
8
+
9
+ class LeadModel(BaseModel):
10
+ def __init__(self):
11
+ super().__init__()
12
+ self.status = ''
13
+ self.notes = ''
14
+ self.archived = False
15
+ self.message: Optional[MessageModel] = None
16
+ self.hidden = False
17
+ self.followup_date = None
18
+ self.score = 0
19
+ self.board_id = None
20
+ self.linkedin_urls = []
21
+ self.likes = 0
22
+ self.reactions = 0
23
+ self.replies = []
24
+ self.last_action_at: Optional[datetime] = None
25
+ self.slack_channel = None
26
+
27
+ @classmethod
28
+ def from_dic(cls, dic: dict):
29
+ if not dic:
30
+ return None
31
+
32
+ model: LeadModel = cls()
33
+ for k, v in dic.items():
34
+ setattr(model, k, v)
35
+
36
+ if dic.get('message'):
37
+ model.message = MessageModel.from_dic(dic['message'])
38
+
39
+ if not model.last_action_at:
40
+ model.last_action_at = model.created_at
41
+
42
+ return model
43
+
44
+ def to_dic(self):
45
+ result = copy.deepcopy(self.__dict__)
46
+ result["message"] = self.message.to_dic()
47
+ result['archived'] = self.archived
48
+ return result
@@ -0,0 +1,51 @@
1
+ import copy
2
+ import json
3
+ from typing import List
4
+
5
+ from lgt_jobs.lgt_data.models.bots.base_bot import Source
6
+ from lgt_jobs.lgt_data.models.leads.config import BaseConfig
7
+
8
+
9
+ class MessageModel:
10
+ pass
11
+
12
+ def __init__(self):
13
+ self.message_id = None
14
+ self.channel_id = None
15
+ self.channel_name = None
16
+ self.message = None
17
+ self.name = None
18
+ self.sender_id = None
19
+ self.source: Source | None = None
20
+ self.companies: List[str] = list()
21
+ self.technologies: List[str] = list()
22
+ self.locations: List[str] = list()
23
+ self.configs: List[BaseConfig] = list()
24
+ self.attachments: List[dict] = []
25
+ self.timestamp = None
26
+ self.tags: List[str] = []
27
+
28
+ @classmethod
29
+ def from_dic(cls, dic: dict):
30
+ if not dic:
31
+ return None
32
+ if isinstance(dic.get('attachments'), str):
33
+ dic['attachments'] = json.loads(dic['attachments'])
34
+
35
+ model: MessageModel = cls()
36
+ for k, v in dic.items():
37
+ setattr(model, k, v)
38
+
39
+ model.source = Source.from_dic(dic.get("source"))
40
+ model.configs = [BaseConfig.from_dic(doc) for doc in dic.get("configs", [])]
41
+ return model
42
+
43
+ def to_dic(self):
44
+ result = copy.deepcopy(self.__dict__)
45
+
46
+ if result.get('source'):
47
+ result['source'] = Source.to_dic(result.get('source'))
48
+ if result.get('configs'):
49
+ result['configs'] = [BaseConfig.to_dic(config) for config in result.get('configs')]
50
+ return result
51
+
File without changes
@@ -0,0 +1,248 @@
1
+ from datetime import datetime, UTC, timedelta
2
+ from lgt_jobs.env import portal_url
3
+ from lgt_jobs.lgt_data.enums import NotificationType
4
+ from lgt_jobs.lgt_data.models.base import DictionaryModel
5
+ from lgt_jobs.lgt_data.models.bots.dedicated_bot import DedicatedBotModel
6
+ from lgt_jobs.lgt_data.models.post.post import Post
7
+ from lgt_jobs.lgt_data.models.user_leads.extended_user_lead import ExtendedUserLeadModel
8
+ from lgt_jobs.lgt_data.models.user_leads.user_lead import UserLeadModel
9
+
10
+
11
+ class Notification(DictionaryModel):
12
+ def __init__(self):
13
+ self.enabled: bool = True
14
+ self.type: NotificationType = NotificationType.INSTANTLY
15
+ self.day: int | None = None
16
+ self.hour: int | None = None
17
+ self.minute: int | None = None
18
+ self.last_notification: datetime | None = None
19
+ self.need_to_notify: bool = False
20
+ self.attributes: list = []
21
+
22
+ @property
23
+ def need_to_notify_now(self) -> bool:
24
+ if not self.enabled or not self.need_to_notify:
25
+ return False
26
+
27
+ now = datetime.now(UTC)
28
+ current_week_day = datetime.isoweekday(now)
29
+ if self.last_notification:
30
+ self.last_notification = self.last_notification.replace(tzinfo=UTC)
31
+
32
+ if (self.type == NotificationType.UNREAD_FOR_FEW_MINUTES
33
+ and self.last_notification and (now.minute - self.minute <= self.last_notification.minute)):
34
+ return False
35
+
36
+ if self.type == NotificationType.ONCE_A_WEEK and current_week_day != self.day:
37
+ return False
38
+
39
+ if ((self.type == NotificationType.ONCE_A_DAY or self.type == NotificationType.ONCE_A_WEEK)
40
+ and now.hour != self.hour and now.minute < self.minute):
41
+ return False
42
+
43
+ if ((self.type == NotificationType.ONCE_A_DAY or self.type == NotificationType.ONCE_A_WEEK)
44
+ and self.last_notification and self.last_notification > now - timedelta(hours=1)):
45
+ return False
46
+
47
+ return True
48
+
49
+ @staticmethod
50
+ def need_to_notify_week_before(date: datetime) -> bool:
51
+ return datetime.now(UTC) < (date + timedelta(7))
52
+
53
+
54
+ class IncomingMessageNotification(Notification):
55
+ @staticmethod
56
+ def get_button_name() -> str:
57
+ return 'View message'
58
+
59
+ @staticmethod
60
+ def get_button_url(sender_id: str, source_id: str) -> str:
61
+ return f'{portal_url}/feed?senderId={sender_id}&sourceId={source_id}'
62
+
63
+ def get_subject_text(self, users: list) -> str:
64
+ if self.type == NotificationType.INSTANTLY or self.type == NotificationType.UNREAD_FOR_FEW_MINUTES:
65
+ return 'New message from your lead'
66
+ elif len(users) > 1:
67
+ return 'Unread messages from your lead'
68
+ return 'Unread message from your lead'
69
+
70
+ def get_notification_text(self, users: list):
71
+ if self.type == NotificationType.INSTANTLY:
72
+ return f'{users[-1]} has just sent you a message.'
73
+ elif self.type == NotificationType.UNREAD_FOR_FEW_MINUTES:
74
+ return f'{users[-1]} sent you a message {self.minute} minutes ago.'
75
+ elif (self.type == NotificationType.ONCE_A_DAY or self.type == NotificationType.ONCE_A_WEEK) and users:
76
+ match len(users):
77
+ case 1:
78
+ return f'You have unread message(s) from {users[0]}.'
79
+ case 2 | 3:
80
+ return f'You have unread messages from {", ".join(users)}.'
81
+ case _:
82
+ return f'You have unread messages from {", ".join(users[:3])} and other leads.'
83
+
84
+
85
+ class InboxNotification(Notification):
86
+
87
+ @staticmethod
88
+ def get_button_name():
89
+ return 'View message request'
90
+
91
+ @staticmethod
92
+ def get_button_url():
93
+ return f'{portal_url}/feed?requests=true'
94
+
95
+ def get_subject_text(self, users: list) -> str:
96
+ if self.type == NotificationType.INSTANTLY:
97
+ return 'New message request on Leadguru'
98
+ elif len(users) > 1:
99
+ return 'Message requests on Leadguru'
100
+ return 'Message request on Leadguru'
101
+
102
+ def get_notification_text(self, users: list):
103
+ if self.type == NotificationType.INSTANTLY:
104
+ return f'{users[0]} has just sent you message request.'
105
+ elif (self.type == NotificationType.ONCE_A_DAY or self.type == NotificationType.ONCE_A_WEEK) and users:
106
+ match len(users):
107
+ case 1:
108
+ return f'You have unread message request from {users[0]}.'
109
+ case 2 | 3:
110
+ return f'You have unread message request from {", ".join(users)}.'
111
+ case _:
112
+ return f'You have unread message requests from {", ".join(users[:3])} and other leads.'
113
+
114
+
115
+ class SourceDeactivationNotification(Notification):
116
+ @staticmethod
117
+ def get_button_name() -> str:
118
+ return 'Show community'
119
+
120
+ @staticmethod
121
+ def get_button_url() -> str:
122
+ return f'{portal_url}/communities?inactive=true'
123
+
124
+ @staticmethod
125
+ def get_subject_text() -> str:
126
+ return 'Inactivation of Community on Leadguru'
127
+
128
+ def get_notification_text(self, bots: list[DedicatedBotModel]):
129
+ names = [bot.source.source_name.capitalize() for bot in bots]
130
+ if self.type == NotificationType.INSTANTLY:
131
+ return f'{bots[-1].source.source_name.capitalize()} became inactive on Leadguru.'
132
+ elif (self.type == NotificationType.ONCE_A_DAY or self.type == NotificationType.ONCE_A_WEEK) and bots:
133
+ match len(bots):
134
+ case 1:
135
+ return f'{names[-1]} became inactive on Leadguru.'
136
+ case 2 | 3:
137
+ return f'{", ".join(names)} became inactive on Leadguru.'
138
+ case _:
139
+ return f'{", ".join(names)} and other became inactive on Leadguru.'
140
+
141
+
142
+ class BulkRepliesNotification(Notification):
143
+
144
+ @staticmethod
145
+ def get_button_name() -> str:
146
+ return 'View post'
147
+
148
+ @staticmethod
149
+ def get_button_url(post: Post) -> str:
150
+ return f'{portal_url}/bulk-post/form/{post.id}'
151
+
152
+ def get_subject_text(self, post: Post) -> str:
153
+ replied_messages = [message.id for message in post.messages if message.id in self.attributes]
154
+ if len(replied_messages) > 1:
155
+ return 'New replies to your bulk post'
156
+ return 'New reply to your bulk post'
157
+
158
+ @staticmethod
159
+ def get_notification_text(post: Post):
160
+ if len(post.messages) <= 1:
161
+ source_name = post.messages[0].server_name
162
+ channel_name = post.messages[0].channel_name
163
+ return f'You have new reply in #{channel_name} from {source_name.capitalize()} to your {post.title} post.'
164
+
165
+ channels = set([message.channel_id for message in post.messages])
166
+ sources = set([message.server_id for message in post.messages])
167
+ return (f'You have new replies in {len(channels)} from {len(sources)} communities '
168
+ f'to your {post.title} post.')
169
+
170
+
171
+ class BulkReactionsNotification(Notification):
172
+
173
+ @staticmethod
174
+ def get_button_name() -> str:
175
+ return 'View post'
176
+
177
+ @staticmethod
178
+ def get_button_url(post: Post) -> str:
179
+ return f'{portal_url}/bulk-post/form/{post.id}'
180
+
181
+ @staticmethod
182
+ def get_subject_text() -> str:
183
+ return 'People are reacting to your post'
184
+
185
+ @staticmethod
186
+ def get_notification_text(post: Post):
187
+ if len(post.messages) <= 1:
188
+ source_name = post.messages[0].server_name
189
+ channel_name = post.messages[0].channel_name
190
+ return (f'You have new reaction in #{channel_name} from {source_name.capitalize()} '
191
+ f'to your {post.title} post.')
192
+
193
+ channels = set([message.channel_id for message in post.messages])
194
+ sources = set([message.server_id for message in post.messages])
195
+ return (f'You have new reactions in {len(channels)} from {len(sources)} communities '
196
+ f'to your {post.title} post.')
197
+
198
+
199
+ class FollowUpNotification(Notification):
200
+
201
+ @staticmethod
202
+ def get_button_name(actual: list[UserLeadModel]) -> str:
203
+ if len(actual) > 1:
204
+ return 'View calendar'
205
+ return 'Send message'
206
+
207
+ def get_button_url(self, actual: list[UserLeadModel]) -> str:
208
+ if len(actual) > 1:
209
+ if self.type == NotificationType.ONCE_A_DAY:
210
+ return f'{portal_url}/dashboard/calendar?view=day'
211
+ return f'{portal_url}/dashboard/calendar?view=week'
212
+ return f'{portal_url}/feed?senderId={actual[0].message.sender_id}&sourceId={actual[0].message.source.source_id}'
213
+
214
+ def get_subject_text(self, actual: list[UserLeadModel]) -> str:
215
+ subject_text = 'You have planned follow-ups' if len(actual) > 1 else 'You have planned follow-up'
216
+
217
+ if self.type == NotificationType.ONCE_A_DAY:
218
+ return f'{subject_text} for today'
219
+ elif self.type == NotificationType.ONCE_A_WEEK:
220
+ return f'{subject_text} for this week'
221
+
222
+ def get_notification_text(self, actual: list[ExtendedUserLeadModel], overdue: list[ExtendedUserLeadModel]) -> str:
223
+ notification_text = ''
224
+ names = [lead.contact.real_name for lead in actual]
225
+ if self.type == NotificationType.ONCE_A_DAY:
226
+ match len(actual):
227
+ case 1:
228
+ notification_text = f'You have planned to send follow-up today to {names[0]}.'
229
+ case 2 | 3:
230
+ notification_text = f'You have planned to send follow-up today to {", ".join(names)}.'
231
+ case _:
232
+ notification_text = (f'You have planned to send follow-up today to {", ".join(names[:3])} '
233
+ f'and {len(names) - 3} other leads.')
234
+ elif self.type == NotificationType.ONCE_A_WEEK:
235
+ match len(actual):
236
+ case 1:
237
+ notification_text = f'You have planned to send follow-up to {names[0]} this week.'
238
+ case 2 | 3:
239
+ notification_text = f'You have planned to send follow-up to {", ".join(names)} this week.'
240
+ case _:
241
+ notification_text = (f'You have planned to send follow-up to {", ".join(names[:3])} '
242
+ f'and {len(names) - 3} other leads this week.')
243
+
244
+ return f'{notification_text} Plus you have {len(overdue)} overdue follow-ups.' if overdue else notification_text
245
+
246
+
247
+ class BillingNotifications(Notification):
248
+ pass
@@ -0,0 +1,52 @@
1
+ import copy
2
+ from lgt_jobs.lgt_data.models.base import DictionaryModel
3
+ from lgt_jobs.lgt_data.models.notifications.notification import (Notification, IncomingMessageNotification,
4
+ InboxNotification, SourceDeactivationNotification,
5
+ BillingNotifications, BulkRepliesNotification,
6
+ BulkReactionsNotification, FollowUpNotification)
7
+
8
+
9
+ class NotificationSettings(DictionaryModel):
10
+ def __init__(self):
11
+ self.incoming_messages: IncomingMessageNotification | None = None
12
+ self.inbox: InboxNotification | None = None
13
+ self.source_deactivation: SourceDeactivationNotification | None = None
14
+ self.billing: BillingNotifications | None = None
15
+ self.bulk_replies: BulkRepliesNotification | None = None
16
+ self.bulk_reactions: BulkReactionsNotification | None = None
17
+ self.follow_ups: FollowUpNotification | None = None
18
+
19
+ @classmethod
20
+ def from_dic(cls, dic: dict):
21
+ if not dic:
22
+ return None
23
+
24
+ model: NotificationSettings = cls()
25
+ model.incoming_messages = IncomingMessageNotification.from_dic(dic.get('incoming_messages'))
26
+ model.inbox = InboxNotification.from_dic(dic.get('inbox'))
27
+ model.source_deactivation = SourceDeactivationNotification.from_dic(dic.get('source_deactivation'))
28
+ model.billing = BillingNotifications.from_dic(dic.get('billing'))
29
+ model.bulk_replies = BulkRepliesNotification.from_dic(dic.get('bulk_replies'))
30
+ model.bulk_reactions = BulkReactionsNotification.from_dic(dic.get('bulk_reactions'))
31
+ model.follow_ups = FollowUpNotification.from_dic(dic.get('follow_ups'))
32
+ return model
33
+
34
+ def to_dic(self):
35
+ result = copy.deepcopy(self.__dict__)
36
+
37
+ if result.get('incoming_messages'):
38
+ result['incoming_messages'] = Notification.to_dic(result.get('incoming_messages'))
39
+ if result.get('inbox'):
40
+ result['inbox'] = Notification.to_dic(result.get('inbox'))
41
+ if result.get('source_deactivation'):
42
+ result['source_deactivation'] = Notification.to_dic(result.get('source_deactivation'))
43
+ if result.get('billing'):
44
+ result['billing'] = Notification.to_dic(result.get('billing'))
45
+ if result.get('bulk_replies'):
46
+ result['bulk_replies'] = Notification.to_dic(result.get('bulk_replies'))
47
+ if result.get('bulk_reactions'):
48
+ result['bulk_reactions'] = Notification.to_dic(result.get('bulk_reactions'))
49
+ if result.get('follow_ups'):
50
+ result['follow_ups'] = Notification.to_dic(result.get('follow_ups'))
51
+
52
+ return result
File without changes
@@ -0,0 +1,75 @@
1
+ import copy
2
+ from datetime import datetime
3
+ from typing import Optional
4
+
5
+ from lgt_jobs.lgt_data.models.base import BaseModel
6
+ from lgt_jobs.lgt_data.models.bots.base_bot import Source
7
+ from lgt_jobs.lgt_data.models.external.slack.timezone import SlackTimeZone
8
+ from lgt_jobs.lgt_data.models.people.profile import Profile
9
+
10
+
11
+ class SlackMemberInformation(BaseModel, Profile):
12
+ workspace: str
13
+ sender_id: str
14
+ images: dict
15
+ full_text: str
16
+ deleted: bool = False
17
+ is_bot: bool = False
18
+ is_app_user: bool = False
19
+ is_admin: bool = False
20
+ is_owner: bool = False
21
+ is_email_confirmed: bool = False
22
+ online: Optional[str] = None
23
+ online_updated_at: datetime = None
24
+ timezone: SlackTimeZone = None
25
+ source: Source = None
26
+
27
+ @classmethod
28
+ def from_dic(cls, dic: dict):
29
+ model: SlackMemberInformation = cls()
30
+ if not dic:
31
+ return None
32
+
33
+ for k, v in dic.items():
34
+ setattr(model, k, v)
35
+
36
+ model.online = dic.get('online', '') == "active"
37
+ model: SlackMemberInformation | None = super().from_dic(dic)
38
+ model.source = Source.from_dic(dic.get('source'))
39
+ return model
40
+
41
+ def to_dic(self):
42
+ result = copy.deepcopy(self.__dict__)
43
+ if result.get('source'):
44
+ result['source'] = Source.to_dic(result.get('source'))
45
+ return result
46
+
47
+ @staticmethod
48
+ def from_slack_response(slack_profile: dict, source: Source = None):
49
+ member_info: SlackMemberInformation = SlackMemberInformation()
50
+ member_info.source = source
51
+ member_info.sender_id = slack_profile.get("id")
52
+ member_info.display_name = slack_profile["profile"].get("display_name")
53
+ member_info.real_name = slack_profile["profile"].get("real_name")
54
+ member_info.title = slack_profile["profile"].get("title")
55
+ member_info.phone = slack_profile["profile"].get("phone")
56
+ member_info.skype = slack_profile["profile"].get("skype")
57
+ member_info.email = slack_profile["profile"].get("email")
58
+ member_info.images = {
59
+ 'image_24': slack_profile.get("profile", {}).get("image_24",
60
+ 'https://a.slack-edge.com/80588/img/slackbot_24.png'),
61
+ 'image_32': slack_profile.get("profile", {}).get("image_32",
62
+ 'https://a.slack-edge.com/80588/img/slackbot_32.png'),
63
+ 'image_48': slack_profile.get("profile", {}).get("image_48",
64
+ 'https://a.slack-edge.com/80588/img/slackbot_48.png'),
65
+ 'image_72': slack_profile.get("profile", {}).get("image_72",
66
+ 'https://a.slack-edge.com/80588/img/slackbot_72.png'),
67
+ 'image_192': slack_profile.get("profile", {}).get("image_192",
68
+ 'https://a.slack-edge.com/80588/img/slackbot_192.png'),
69
+ 'image_512': slack_profile.get("profile", {}).get("image_512",
70
+ 'https://a.slack-edge.com/80588/img/slackbot_512.png'),
71
+
72
+ }
73
+ member_info.timezone = {"tz": slack_profile.get("tz"), "tz_label": slack_profile.get("tz_label"),
74
+ "tz_offset": slack_profile.get("tz_offset")}
75
+ return member_info
@@ -0,0 +1,13 @@
1
+ from lgt_jobs.lgt_data.models.base import DictionaryModel
2
+
3
+
4
+ class Profile(DictionaryModel):
5
+ def __init__(self):
6
+ self.title = ''
7
+ self.phone = ''
8
+ self.skype = ''
9
+ self.display_name = ''
10
+ self.real_name = ''
11
+ self.email = ''
12
+ self.photo_url = ''
13
+ self.main = False
File without changes
@@ -0,0 +1,18 @@
1
+ from lgt_jobs.lgt_data.models.base import DictionaryModel
2
+
3
+
4
+ class PostMessage(DictionaryModel):
5
+ id: str
6
+ server_id: str
7
+ server_name: str
8
+ channel_id: str
9
+ channel_name: str
10
+
11
+ @classmethod
12
+ def from_dic(cls, dic: dict):
13
+ if not dic:
14
+ return None
15
+ model = cls()
16
+ for k, v in dic.items():
17
+ setattr(model, k, v)
18
+ return model
@@ -0,0 +1,15 @@
1
+ from lgt_jobs.lgt_data.models.base import BaseModel
2
+ from lgt_jobs.lgt_data.models.post.message import PostMessage
3
+
4
+
5
+ class Post(BaseModel):
6
+ messages: list[PostMessage]
7
+ title: str
8
+
9
+ @classmethod
10
+ def from_dic(cls, dic: dict):
11
+ if not dic:
12
+ return None
13
+ model: Post | None = super().from_dic(dic)
14
+ model.messages = [PostMessage.from_dic(message) for message in dic.get('messages', [])]
15
+ return model
File without changes
@@ -0,0 +1,12 @@
1
+ from typing import Optional
2
+
3
+ from bson import ObjectId
4
+
5
+ from lgt_jobs.lgt_data.models.base import BaseModel
6
+
7
+
8
+ class UserTemplateModel(BaseModel):
9
+ text: str
10
+ subject: Optional[str]
11
+ user_id: Optional[ObjectId]
12
+
File without changes
@@ -0,0 +1,10 @@
1
+ from lgt_jobs.lgt_data.enums import FeaturesEnum, FeatureOptions
2
+ from lgt_jobs.lgt_data.models.base import DictionaryModel
3
+
4
+
5
+ class Feature(DictionaryModel):
6
+ display_name: str
7
+ name: FeaturesEnum
8
+ description: str | None = None
9
+ limit: int | None = None
10
+ options: FeatureOptions | None = None
@@ -0,0 +1,9 @@
1
+ from lgt_jobs.lgt_data.models.base import DictionaryModel
2
+
3
+
4
+ class GeneralSettings(DictionaryModel):
5
+ def __init__(self):
6
+ self.theme: str | None = None
7
+ self.ask_pipeline_and_status: bool = False
8
+ self.ask_follow_up: bool = False
9
+ self.dashboard_is_starting_page: bool = False