leadguru-jobs 0.405.0__tar.gz → 0.407.0__tar.gz

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 (61) hide show
  1. {leadguru_jobs-0.405.0 → leadguru_jobs-0.407.0}/PKG-INFO +10 -5
  2. {leadguru_jobs-0.405.0 → leadguru_jobs-0.407.0}/leadguru_jobs.egg-info/PKG-INFO +10 -5
  3. leadguru_jobs-0.407.0/leadguru_jobs.egg-info/SOURCES.txt +55 -0
  4. leadguru_jobs-0.407.0/leadguru_jobs.egg-info/requires.txt +19 -0
  5. {leadguru_jobs-0.405.0 → leadguru_jobs-0.407.0}/lgt_jobs/__init__.py +4 -4
  6. {leadguru_jobs-0.405.0 → leadguru_jobs-0.407.0}/lgt_jobs/jobs/analytics.py +1 -1
  7. {leadguru_jobs-0.405.0 → leadguru_jobs-0.407.0}/lgt_jobs/jobs/archive_leads.py +2 -2
  8. {leadguru_jobs-0.405.0 → leadguru_jobs-0.407.0}/lgt_jobs/jobs/bot_stats_update.py +10 -11
  9. leadguru_jobs-0.407.0/lgt_jobs/jobs/chat_history.py +116 -0
  10. {leadguru_jobs-0.405.0 → leadguru_jobs-0.407.0}/lgt_jobs/jobs/inbox_leads.py +5 -6
  11. {leadguru_jobs-0.405.0 → leadguru_jobs-0.407.0}/lgt_jobs/jobs/mass_message.py +2 -2
  12. {leadguru_jobs-0.405.0 → leadguru_jobs-0.407.0}/lgt_jobs/jobs/send_code.py +1 -1
  13. leadguru_jobs-0.407.0/lgt_jobs/jobs/send_slack_message.py +46 -0
  14. {leadguru_jobs-0.405.0 → leadguru_jobs-0.407.0}/lgt_jobs/jobs/update_slack_profile.py +12 -14
  15. {leadguru_jobs-0.405.0 → leadguru_jobs-0.407.0}/lgt_jobs/jobs/user_balance_update.py +5 -5
  16. {leadguru_jobs-0.405.0 → leadguru_jobs-0.407.0}/lgt_jobs/jobs/workspace_connect.py +7 -5
  17. leadguru_jobs-0.407.0/lgt_jobs/lgt_common/discord_client/discord_client.py +62 -0
  18. leadguru_jobs-0.407.0/lgt_jobs/lgt_common/discord_client/methods.py +16 -0
  19. leadguru_jobs-0.407.0/lgt_jobs/lgt_common/enums/__init__.py +0 -0
  20. leadguru_jobs-0.407.0/lgt_jobs/lgt_common/enums/slack_errors.py +6 -0
  21. leadguru_jobs-0.407.0/lgt_jobs/lgt_common/helpers.py +18 -0
  22. leadguru_jobs-0.407.0/lgt_jobs/lgt_common/lgt_logging.py +15 -0
  23. leadguru_jobs-0.407.0/lgt_jobs/lgt_common/pubsub/__init__.py +0 -0
  24. leadguru_jobs-0.407.0/lgt_jobs/lgt_common/pubsub/command.py +14 -0
  25. leadguru_jobs-0.407.0/lgt_jobs/lgt_common/pubsub/messages.py +37 -0
  26. leadguru_jobs-0.407.0/lgt_jobs/lgt_common/pubsub/pubsubfactory.py +51 -0
  27. leadguru_jobs-0.407.0/lgt_jobs/lgt_common/slack_client/__init__.py +0 -0
  28. leadguru_jobs-0.407.0/lgt_jobs/lgt_common/slack_client/methods.py +46 -0
  29. leadguru_jobs-0.407.0/lgt_jobs/lgt_common/slack_client/slack_client.py +392 -0
  30. leadguru_jobs-0.407.0/lgt_jobs/lgt_common/slack_client/web_client.py +166 -0
  31. leadguru_jobs-0.407.0/lgt_jobs/lgt_data/__init__.py +0 -0
  32. leadguru_jobs-0.407.0/lgt_jobs/lgt_data/analytics.py +723 -0
  33. leadguru_jobs-0.407.0/lgt_jobs/lgt_data/engine.py +223 -0
  34. leadguru_jobs-0.407.0/lgt_jobs/lgt_data/enums.py +68 -0
  35. leadguru_jobs-0.407.0/lgt_jobs/lgt_data/helpers.py +2 -0
  36. leadguru_jobs-0.407.0/lgt_jobs/lgt_data/model.py +955 -0
  37. leadguru_jobs-0.407.0/lgt_jobs/lgt_data/mongo_repository.py +998 -0
  38. {leadguru_jobs-0.405.0 → leadguru_jobs-0.407.0}/lgt_jobs/main.py +9 -11
  39. {leadguru_jobs-0.405.0 → leadguru_jobs-0.407.0}/lgt_jobs/runner.py +6 -9
  40. leadguru_jobs-0.407.0/lgt_jobs/services/__init__.py +0 -0
  41. {leadguru_jobs-0.405.0 → leadguru_jobs-0.407.0}/lgt_jobs/smtp.py +1 -1
  42. {leadguru_jobs-0.405.0 → leadguru_jobs-0.407.0}/setup.py +10 -5
  43. leadguru_jobs-0.405.0/leadguru_jobs.egg-info/SOURCES.txt +0 -34
  44. leadguru_jobs-0.405.0/leadguru_jobs.egg-info/requires.txt +0 -14
  45. leadguru_jobs-0.405.0/lgt_jobs/jobs/chat_history.py +0 -109
  46. leadguru_jobs-0.405.0/lgt_jobs/jobs/send_slack_message.py +0 -65
  47. leadguru_jobs-0.405.0/tests/job_data_test.py +0 -42
  48. {leadguru_jobs-0.405.0 → leadguru_jobs-0.407.0}/MANIFEST.in +0 -0
  49. {leadguru_jobs-0.405.0 → leadguru_jobs-0.407.0}/README.md +0 -0
  50. {leadguru_jobs-0.405.0 → leadguru_jobs-0.407.0}/leadguru_jobs.egg-info/dependency_links.txt +0 -0
  51. {leadguru_jobs-0.405.0 → leadguru_jobs-0.407.0}/leadguru_jobs.egg-info/not-zip-safe +0 -0
  52. {leadguru_jobs-0.405.0 → leadguru_jobs-0.407.0}/leadguru_jobs.egg-info/top_level.txt +0 -0
  53. {leadguru_jobs-0.405.0 → leadguru_jobs-0.407.0}/lgt_jobs/basejobs.py +0 -0
  54. {leadguru_jobs-0.405.0 → leadguru_jobs-0.407.0}/lgt_jobs/env.py +0 -0
  55. {leadguru_jobs-0.405.0 → leadguru_jobs-0.407.0}/lgt_jobs/jobs/__init__.py +0 -0
  56. {leadguru_jobs-0.405.0/lgt_jobs/services → leadguru_jobs-0.407.0/lgt_jobs/lgt_common}/__init__.py +0 -0
  57. {leadguru_jobs-0.405.0/tests → leadguru_jobs-0.407.0/lgt_jobs/lgt_common/discord_client}/__init__.py +0 -0
  58. {leadguru_jobs-0.405.0 → leadguru_jobs-0.407.0}/lgt_jobs/services/web_client.py +0 -0
  59. {leadguru_jobs-0.405.0 → leadguru_jobs-0.407.0}/lgt_jobs/simple_job.py +0 -0
  60. {leadguru_jobs-0.405.0 → leadguru_jobs-0.407.0}/lgt_jobs/templates/new_message_mail_template.html +0 -0
  61. {leadguru_jobs-0.405.0 → leadguru_jobs-0.407.0}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: leadguru_jobs
3
- Version: 0.405.0
3
+ Version: 0.407.0
4
4
  Summary: LGT jobs builds
5
5
  Author-email: developer@leadguru.co
6
6
  Classifier: Development Status :: 5 - Production/Stable
@@ -17,11 +17,8 @@ Classifier: Intended Audience :: System Administrators
17
17
  Classifier: Environment :: Console
18
18
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
19
19
  Classifier: Topic :: Internet
20
- Requires-Dist: loguru
20
+ Requires-Dist: cachetools==3.1.0
21
21
  Requires-Dist: pydantic
22
- Requires-Dist: cachetools>=3.1.0
23
- Requires-Dist: leadguru-common==0.383.0
24
- Requires-Dist: leadguru-data==0.390.0
25
22
  Requires-Dist: wheel
26
23
  Requires-Dist: setuptools
27
24
  Requires-Dist: twine
@@ -31,3 +28,11 @@ Requires-Dist: pyyaml
31
28
  Requires-Dist: pymongo
32
29
  Requires-Dist: pytz
33
30
  Requires-Dist: requests
31
+ Requires-Dist: mongoengine
32
+ Requires-Dist: google
33
+ Requires-Dist: google-cloud-pubsub
34
+ Requires-Dist: google-cloud-storage
35
+ Requires-Dist: websockets
36
+ Requires-Dist: aiohttp
37
+ Requires-Dist: nameparser
38
+ Requires-Dist: loguru
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: leadguru_jobs
3
- Version: 0.405.0
3
+ Version: 0.407.0
4
4
  Summary: LGT jobs builds
5
5
  Author-email: developer@leadguru.co
6
6
  Classifier: Development Status :: 5 - Production/Stable
@@ -17,11 +17,8 @@ Classifier: Intended Audience :: System Administrators
17
17
  Classifier: Environment :: Console
18
18
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
19
19
  Classifier: Topic :: Internet
20
- Requires-Dist: loguru
20
+ Requires-Dist: cachetools==3.1.0
21
21
  Requires-Dist: pydantic
22
- Requires-Dist: cachetools>=3.1.0
23
- Requires-Dist: leadguru-common==0.383.0
24
- Requires-Dist: leadguru-data==0.390.0
25
22
  Requires-Dist: wheel
26
23
  Requires-Dist: setuptools
27
24
  Requires-Dist: twine
@@ -31,3 +28,11 @@ Requires-Dist: pyyaml
31
28
  Requires-Dist: pymongo
32
29
  Requires-Dist: pytz
33
30
  Requires-Dist: requests
31
+ Requires-Dist: mongoengine
32
+ Requires-Dist: google
33
+ Requires-Dist: google-cloud-pubsub
34
+ Requires-Dist: google-cloud-storage
35
+ Requires-Dist: websockets
36
+ Requires-Dist: aiohttp
37
+ Requires-Dist: nameparser
38
+ Requires-Dist: loguru
@@ -0,0 +1,55 @@
1
+ MANIFEST.in
2
+ README.md
3
+ setup.cfg
4
+ setup.py
5
+ leadguru_jobs.egg-info/PKG-INFO
6
+ leadguru_jobs.egg-info/SOURCES.txt
7
+ leadguru_jobs.egg-info/dependency_links.txt
8
+ leadguru_jobs.egg-info/not-zip-safe
9
+ leadguru_jobs.egg-info/requires.txt
10
+ leadguru_jobs.egg-info/top_level.txt
11
+ lgt_jobs/__init__.py
12
+ lgt_jobs/basejobs.py
13
+ lgt_jobs/env.py
14
+ lgt_jobs/main.py
15
+ lgt_jobs/runner.py
16
+ lgt_jobs/simple_job.py
17
+ lgt_jobs/smtp.py
18
+ lgt_jobs/jobs/__init__.py
19
+ lgt_jobs/jobs/analytics.py
20
+ lgt_jobs/jobs/archive_leads.py
21
+ lgt_jobs/jobs/bot_stats_update.py
22
+ lgt_jobs/jobs/chat_history.py
23
+ lgt_jobs/jobs/inbox_leads.py
24
+ lgt_jobs/jobs/mass_message.py
25
+ lgt_jobs/jobs/send_code.py
26
+ lgt_jobs/jobs/send_slack_message.py
27
+ lgt_jobs/jobs/update_slack_profile.py
28
+ lgt_jobs/jobs/user_balance_update.py
29
+ lgt_jobs/jobs/workspace_connect.py
30
+ lgt_jobs/lgt_common/__init__.py
31
+ lgt_jobs/lgt_common/helpers.py
32
+ lgt_jobs/lgt_common/lgt_logging.py
33
+ lgt_jobs/lgt_common/discord_client/__init__.py
34
+ lgt_jobs/lgt_common/discord_client/discord_client.py
35
+ lgt_jobs/lgt_common/discord_client/methods.py
36
+ lgt_jobs/lgt_common/enums/__init__.py
37
+ lgt_jobs/lgt_common/enums/slack_errors.py
38
+ lgt_jobs/lgt_common/pubsub/__init__.py
39
+ lgt_jobs/lgt_common/pubsub/command.py
40
+ lgt_jobs/lgt_common/pubsub/messages.py
41
+ lgt_jobs/lgt_common/pubsub/pubsubfactory.py
42
+ lgt_jobs/lgt_common/slack_client/__init__.py
43
+ lgt_jobs/lgt_common/slack_client/methods.py
44
+ lgt_jobs/lgt_common/slack_client/slack_client.py
45
+ lgt_jobs/lgt_common/slack_client/web_client.py
46
+ lgt_jobs/lgt_data/__init__.py
47
+ lgt_jobs/lgt_data/analytics.py
48
+ lgt_jobs/lgt_data/engine.py
49
+ lgt_jobs/lgt_data/enums.py
50
+ lgt_jobs/lgt_data/helpers.py
51
+ lgt_jobs/lgt_data/model.py
52
+ lgt_jobs/lgt_data/mongo_repository.py
53
+ lgt_jobs/services/__init__.py
54
+ lgt_jobs/services/web_client.py
55
+ lgt_jobs/templates/new_message_mail_template.html
@@ -0,0 +1,19 @@
1
+ cachetools==3.1.0
2
+ pydantic
3
+ wheel
4
+ setuptools
5
+ twine
6
+ build
7
+ kubernetes
8
+ pyyaml
9
+ pymongo
10
+ pytz
11
+ requests
12
+ mongoengine
13
+ google
14
+ google-cloud-pubsub
15
+ google-cloud-storage
16
+ websockets
17
+ aiohttp
18
+ nameparser
19
+ loguru
@@ -6,7 +6,7 @@ from .jobs.analytics import (TrackAnalyticsJob, TrackAnalyticsJobData)
6
6
  from .jobs.archive_leads import (ArchiveLeadsJob, ArchiveLeadsJobData)
7
7
  from .jobs.bot_stats_update import (BotStatsUpdateJob, BotStatsUpdateJobData)
8
8
  from .jobs.chat_history import (LoadChatHistoryJob, LoadChatHistoryJobData)
9
- from .jobs.update_slack_profile import (UpdateUserSlackProfileJob, UpdateUserSlackProfileJobData)
9
+ from .jobs.update_slack_profile import (UpdateExternalUserProfileJob, UpdateExternalUserProfileJobData)
10
10
  from .jobs.mass_message import SendMassMessageSlackChannelJob, SendMassMessageSlackChannelJobData
11
11
  from .basejobs import (BaseBackgroundJobData, BaseBackgroundJob, InvalidJobTypeException)
12
12
  from .smtp import (SendMailJob, SendMailJobData)
@@ -20,7 +20,7 @@ jobs_map = {
20
20
  "SendMailJob": SendMailJob,
21
21
  "TrackAnalyticsJob": TrackAnalyticsJob,
22
22
  "LoadChatHistoryJob": LoadChatHistoryJob,
23
- "UpdateUserSlackProfileJob": UpdateUserSlackProfileJob,
23
+ "UpdateExternalUserProfileJob": UpdateExternalUserProfileJob,
24
24
  "SendSlackMessageJob": SendSlackMessageJob,
25
25
  "UpdateUserBalanceJob": UpdateUserBalanceJob,
26
26
  "SendMassMessageSlackChannelJob": SendMassMessageSlackChannelJob,
@@ -33,7 +33,7 @@ __all__ = [
33
33
  SendMailJob,
34
34
  SimpleTestJob,
35
35
  LoadChatHistoryJob,
36
- UpdateUserSlackProfileJob,
36
+ UpdateExternalUserProfileJob,
37
37
  TrackAnalyticsJob,
38
38
  SendSlackMessageJob,
39
39
  UpdateUserBalanceJob,
@@ -49,7 +49,7 @@ __all__ = [
49
49
  SendMailJobData,
50
50
  SimpleTestJobData,
51
51
  LoadChatHistoryJobData,
52
- UpdateUserSlackProfileJobData,
52
+ UpdateExternalUserProfileJobData,
53
53
  TrackAnalyticsJobData,
54
54
  SendSlackMessageJobData,
55
55
  UpdateUserBalanceJobData,
@@ -3,7 +3,7 @@ import datetime
3
3
  from typing import Optional, List
4
4
  from pydantic import BaseModel, conlist
5
5
  from pymongo import MongoClient
6
- from lgt.common.python.lgt_logging import log
6
+ from lgt_jobs.lgt_common.lgt_logging import log
7
7
  from ..basejobs import BaseBackgroundJob, BaseBackgroundJobData
8
8
  from ..env import mongo_connection_string
9
9
 
@@ -1,6 +1,6 @@
1
1
  from abc import ABC
2
2
  import datetime
3
- from lgt_data.mongo_repository import UserLeadMongoRepository
3
+ from lgt_jobs.lgt_data.mongo_repository import UserLeadMongoRepository
4
4
  from pydantic import BaseModel
5
5
  from ..basejobs import BaseBackgroundJob, BaseBackgroundJobData
6
6
 
@@ -21,7 +21,7 @@ class ArchiveLeadsJob(BaseBackgroundJob, ABC):
21
21
  def exec(self, data: ArchiveLeadsJobData):
22
22
  lead_repository = UserLeadMongoRepository()
23
23
  leads = lead_repository.get_leads(data.user_id, 0, 1000, archived=False,
24
- to_date=datetime.datetime.utcnow() - datetime.timedelta(days=90))
24
+ to_date=datetime.datetime.now(datetime.UTC) - datetime.timedelta(days=90))
25
25
 
26
26
  for lead in leads:
27
27
  lead_repository.update_lead(data.user_id, lead.id, archived=True)
@@ -2,16 +2,16 @@ import random
2
2
  import time
3
3
  from abc import ABC
4
4
  from typing import Optional
5
- from lgt.common.python.discord_client.discord_client import DiscordClient
6
- from lgt.common.python.helpers import get_formatted_bot_name
7
- from lgt.common.python.slack_client.web_client import SlackWebClient
8
- from lgt_data.enums import SourceType
9
- from lgt_data.model import DedicatedBotModel, Server, Channel, DiscordUser
10
- from lgt_data.mongo_repository import DedicatedBotRepository, UserMongoRepository
5
+ from lgt_jobs.lgt_common.discord_client.discord_client import DiscordClient
6
+ from lgt_jobs.lgt_common.helpers import get_formatted_bot_name
7
+ from lgt_jobs.lgt_common.slack_client.web_client import SlackWebClient
8
+ from lgt_jobs.lgt_data.enums import SourceType
9
+ from lgt_jobs.lgt_data.model import DedicatedBotModel, Server, Channel, DiscordUser
10
+ from lgt_jobs.lgt_data.mongo_repository import DedicatedBotRepository, UserMongoRepository
11
11
  from pydantic import BaseModel
12
- from lgt_data.analytics import get_bots_aggregated_analytics
13
- from lgt.common.python.lgt_logging import log
14
- from lgt.common.python.enums.slack_errors import SlackErrors
12
+ from lgt_jobs.lgt_data.analytics import get_bots_aggregated_analytics
13
+ from lgt_jobs.lgt_common.lgt_logging import log
14
+ from lgt_jobs.lgt_common.enums.slack_errors import SlackErrors
15
15
  from ..basejobs import BaseBackgroundJob, BaseBackgroundJobData
16
16
 
17
17
  """
@@ -56,8 +56,7 @@ class BotStatsUpdateJob(BaseBackgroundJob, ABC):
56
56
  discord_server.deleted = server.deleted
57
57
  else:
58
58
  discord_server.deleted = True
59
- discord_channels = [Channel.from_dic(channel) for channel in client.get_channels(discord_server.id)
60
- if channel.get('type', 0) == 0]
59
+ discord_channels = [Channel.from_dic(channel) for channel in client.get_channels(discord_server.id)]
61
60
  for discord_channel in discord_channels:
62
61
  if server:
63
62
  channel = next(filter(lambda x: x.id == discord_channel.id, server.channels), None)
@@ -0,0 +1,116 @@
1
+ import datetime
2
+ from abc import ABC
3
+ from typing import Optional, List
4
+ from lgt_jobs.lgt_common.lgt_logging import log
5
+ from lgt_jobs.lgt_common.slack_client.web_client import SlackWebClient, SlackMessageConvertService
6
+ from lgt_jobs.lgt_data.model import ChatMessage, UserModel, UserContact, DedicatedBotModel
7
+ from lgt_jobs.lgt_data.mongo_repository import UserMongoRepository, DedicatedBotRepository, UserContactsRepository, \
8
+ ChatRepository
9
+ from pydantic import BaseModel
10
+ from lgt_jobs.lgt_data.enums import SourceType
11
+ from lgt_jobs.runner import BaseBackgroundJob, BaseBackgroundJobData, BackgroundJobRunner
12
+ from ..env import portal_url
13
+ from ..smtp import SendMailJobData, SendMailJob
14
+
15
+ """
16
+ Load slack chat history
17
+ """
18
+
19
+
20
+ class LoadChatHistoryJobData(BaseBackgroundJobData, BaseModel):
21
+ user_id: str
22
+ template_path: str = 'lgt_jobs/templates/new_message_mail_template.html'
23
+
24
+
25
+ class LoadChatHistoryJob(BaseBackgroundJob, ABC):
26
+ @property
27
+ def job_data_type(self) -> type:
28
+ return LoadChatHistoryJobData
29
+
30
+ def exec(self, data: LoadChatHistoryJobData):
31
+ user = UserMongoRepository().get(data.user_id)
32
+ bots = DedicatedBotRepository().get_all(only_valid=True, user_id=user.id, source_type=SourceType.SLACK)
33
+ if not bots:
34
+ return
35
+ last_message = None
36
+ last_message_contact = None
37
+ for bot in bots:
38
+ contacts = UserContactsRepository().find(user.id, spam=False, source_id=bot.source.source_id)
39
+ if not contacts:
40
+ continue
41
+
42
+ log.info(f"[LoadChatHistoryJob]: processing {len(contacts)} contacts for user: {user.email}")
43
+ for contact in contacts:
44
+ message = LoadChatHistoryJob._update_history(user=user, contact=contact, bot=bot)
45
+
46
+ if not message:
47
+ continue
48
+
49
+ if not last_message:
50
+ last_message = message
51
+ last_message_contact = contact
52
+
53
+ if message.created_at > last_message.created_at and message.user == contact.sender_id:
54
+ last_message = message
55
+ last_message_contact = contact
56
+
57
+ has_to_be_notified = (not user.new_message_notified_at or
58
+ (last_message and last_message.created_at > user.new_message_notified_at))
59
+
60
+ if last_message and has_to_be_notified and last_message.user == last_message_contact.sender_id:
61
+ LoadChatHistoryJob._notify_about_new_messages(user, last_message_contact, data.template_path)
62
+ UserMongoRepository().set(data.user_id, new_message_notified_at=datetime.datetime.now(datetime.UTC))
63
+
64
+ @staticmethod
65
+ def _get_new_messages(contact: UserContact, bot: DedicatedBotModel, slack_chat: List[ChatMessage]):
66
+ chat_repo = ChatRepository()
67
+ messages = chat_repo.get_list(sender_id=contact.sender_id, bot_id=bot.id)
68
+ new_messages = []
69
+ for message in slack_chat:
70
+ same_messages = [msg for msg in messages if msg.ts == message.ts]
71
+ if not same_messages:
72
+ new_messages.append(message)
73
+ return new_messages
74
+
75
+ @staticmethod
76
+ def _update_history(user: UserModel, contact: UserContact, bot: DedicatedBotModel) -> Optional[ChatMessage]:
77
+ if bot.type == SourceType.SLACK:
78
+ slack_client = SlackWebClient(bot.token, bot.cookies)
79
+ try:
80
+ chat_id = slack_client.im_open(contact.sender_id).get('channel', {}).get('id')
81
+ history = slack_client.chat_history(chat_id)
82
+ except Exception as ex:
83
+ log.error(f'[LoadChatHistoryJob]: Failed to load chat for the contact: {contact.id}. ERROR: {str(ex)}')
84
+ return
85
+
86
+ if not history['ok']:
87
+ log.error(f'Failed to load chat for the contact: {contact.id}. ERROR: {history.get("error", "")}')
88
+ return
89
+
90
+ messages = history.get('messages', [])
91
+ if not messages:
92
+ return None
93
+
94
+ messages = [SlackMessageConvertService.from_slack_response(user.email, "slack_files",
95
+ bot.token, m, contact.sender_id, bot.id,
96
+ user.id, bot.cookies) for m in messages]
97
+ new_messages = LoadChatHistoryJob._get_new_messages(contact, bot, messages)
98
+ chat_history = [message.to_dic() for message in new_messages]
99
+ ChatRepository().upsert_messages(chat_history)
100
+ return new_messages[-1] if bot.associated_user != contact.sender_id else None
101
+
102
+ @staticmethod
103
+ def _notify_about_new_messages(user: UserModel, contact: UserContact, template_path: str):
104
+ with open(template_path, mode='r') as template_file:
105
+ html = template_file.read()
106
+ html = html.replace("{sender}", contact.name if hasattr(contact, 'name') else contact.real_name)
107
+ html = html.replace("{view_message_link}", f'{portal_url}/')
108
+
109
+ message_data = {
110
+ "html": html,
111
+ "subject": 'New message(s) on LEADGURU',
112
+ "recipient": user.email,
113
+ "sender": None
114
+ }
115
+
116
+ BackgroundJobRunner.submit(SendMailJob, SendMailJobData(**message_data))
@@ -1,9 +1,9 @@
1
1
  from abc import ABC
2
- from lgt.common.python.lgt_logging import log
3
- from lgt.common.python.slack_client.web_client import SlackWebClient
4
- from lgt_data.enums import DefaultBoards
5
- from lgt_data.model import UserModel, DedicatedBotModel, SlackMemberInformation, UserLeadModel
6
- from lgt_data.mongo_repository import UserMongoRepository, DedicatedBotRepository, \
2
+ from lgt_jobs.lgt_common.lgt_logging import log
3
+ from lgt_jobs.lgt_common.slack_client.web_client import SlackWebClient
4
+ from lgt_jobs.lgt_data.enums import DefaultBoards
5
+ from lgt_jobs.lgt_data.model import UserModel, DedicatedBotModel, SlackMemberInformation, UserLeadModel
6
+ from lgt_jobs.lgt_data.mongo_repository import UserMongoRepository, DedicatedBotRepository, \
7
7
  SlackContactUserRepository, BoardsMongoRepository, UserContactsRepository
8
8
  from pydantic import BaseModel
9
9
  from ..basejobs import BaseBackgroundJob, BaseBackgroundJobData
@@ -80,7 +80,6 @@ class InboxLeadsJob(BaseBackgroundJob, ABC):
80
80
  @staticmethod
81
81
  def create_people(slack_profile: dict, dedicated_bot: DedicatedBotModel):
82
82
  member_info: SlackMemberInformation = SlackMemberInformation.from_slack_response(slack_profile,
83
- dedicated_bot.source.source_name,
84
83
  dedicated_bot.source)
85
84
  SlackContactUserRepository().collection().update_one({"sender_id": member_info.sender_id,
86
85
  "source.source_id": dedicated_bot.source.source_id},
@@ -2,8 +2,8 @@ import time
2
2
  from abc import ABC
3
3
  from random import randint
4
4
  from typing import Optional, Any
5
- from lgt.common.python.slack_client.web_client import SlackWebClient
6
- from lgt_data.mongo_repository import DedicatedBotRepository
5
+ from lgt_jobs.lgt_common.slack_client.web_client import SlackWebClient
6
+ from lgt_jobs.lgt_data.mongo_repository import DedicatedBotRepository
7
7
  from loguru import logger as log
8
8
  from pydantic import BaseModel
9
9
  from ..basejobs import BaseBackgroundJobData, BaseBackgroundJob
@@ -1,7 +1,7 @@
1
1
  from abc import ABC
2
2
  from typing import Optional
3
3
  from loguru import logger as log
4
- from lgt.common.python.slack_client.web_client import SlackWebClient
4
+ from lgt_jobs.lgt_common.slack_client.web_client import SlackWebClient
5
5
  from pydantic import BaseModel
6
6
  from ..basejobs import BaseBackgroundJobData, BaseBackgroundJob
7
7
 
@@ -0,0 +1,46 @@
1
+ from abc import ABC
2
+ from typing import Optional
3
+ from lgt_jobs.lgt_common.lgt_logging import log
4
+ from lgt_jobs.lgt_common.slack_client.web_client import SlackWebClient
5
+ from lgt_jobs.lgt_data.mongo_repository import UserLeadMongoRepository, DedicatedBotRepository
6
+ from pydantic import BaseModel
7
+ from ..basejobs import BaseBackgroundJobData, BaseBackgroundJob
8
+
9
+ """
10
+ Send Slack Message
11
+ """
12
+
13
+
14
+ class SendSlackMessageJobData(BaseBackgroundJobData, BaseModel):
15
+ lead_id: str
16
+ user_id: str
17
+ text: Optional[str]
18
+ files_ids: Optional[list]
19
+
20
+
21
+ class SendSlackMessageJob(BaseBackgroundJob, ABC):
22
+ @property
23
+ def job_data_type(self) -> type:
24
+ return SendSlackMessageJobData
25
+
26
+ def exec(self, data: SendSlackMessageJobData):
27
+ user_leads_repository = UserLeadMongoRepository()
28
+ lead = user_leads_repository.get_lead(user_id=data.user_id, lead_id=data.lead_id)
29
+ if not lead:
30
+ return
31
+
32
+ bot = DedicatedBotRepository().get_one(user_id=data.user_id, source_id=data.source_id, only_valid=True)
33
+ if not bot:
34
+ return
35
+
36
+ slack_client = SlackWebClient(bot.token, bot.cookies)
37
+ resp = slack_client.im_open(lead.message.sender_id)
38
+ if not resp['ok']:
39
+ log.warning(f"Unable to open im with user: {resp}")
40
+ return
41
+
42
+ channel_id = resp['channel']['id']
43
+ if data.files_ids:
44
+ slack_client.share_files(data.files_ids, channel_id, data.text)
45
+ else:
46
+ slack_client.post_message(channel_id, data.text)
@@ -1,34 +1,32 @@
1
1
  from abc import ABC
2
- from lgt.common.python.slack_client.slack_client import SlackClient
3
- from lgt_data.model import UserModel
4
- from lgt_data.mongo_repository import UserMongoRepository, DedicatedBotRepository
2
+ from lgt_jobs.lgt_common.slack_client.slack_client import SlackClient
3
+ from lgt_jobs.lgt_data.enums import SourceType
4
+ from lgt_jobs.lgt_data.model import UserModel
5
+ from lgt_jobs.lgt_data.mongo_repository import UserMongoRepository, DedicatedBotRepository
5
6
  from pydantic import BaseModel
6
7
  from ..basejobs import BaseBackgroundJobData, BaseBackgroundJob
7
8
 
8
- """
9
- Update Slack User profile
10
- """
11
9
 
12
-
13
- class UpdateUserSlackProfileJobData(BaseBackgroundJobData, BaseModel):
10
+ class UpdateExternalUserProfileJobData(BaseBackgroundJobData, BaseModel):
14
11
  user_id: str
15
12
 
16
13
 
17
- class UpdateUserSlackProfileJob(BaseBackgroundJob, ABC):
14
+ class UpdateExternalUserProfileJob(BaseBackgroundJob, ABC):
18
15
 
19
16
  @property
20
17
  def job_data_type(self) -> type:
21
- return UpdateUserSlackProfileJobData
18
+ return UpdateExternalUserProfileJobData
22
19
 
23
- def exec(self, data: UpdateUserSlackProfileJobData):
20
+ def exec(self, data: UpdateExternalUserProfileJobData):
24
21
  user = UserMongoRepository().get(data.user_id)
25
22
  bots = DedicatedBotRepository().get_all(user_id=data.user_id, only_valid=True, include_deleted=False)
26
23
  for bot in bots:
27
- slack = SlackClient(bot.token, bot.cookies)
28
- UpdateUserSlackProfileJob.__update_profile(user, slack)
24
+ if bot.type == SourceType.SLACK:
25
+ slack = SlackClient(bot.token, bot.cookies)
26
+ UpdateExternalUserProfileJob.__update_slack_profile(user, slack)
29
27
 
30
28
  @staticmethod
31
- def __update_profile(user: UserModel, slack: SlackClient):
29
+ def __update_slack_profile(user: UserModel, slack: SlackClient):
32
30
  profile = slack.get_team_profile()
33
31
  title_section_id = None
34
32
  title_field_id = None
@@ -1,10 +1,10 @@
1
1
  import datetime
2
2
  from abc import ABC
3
3
  from typing import Optional
4
- from lgt_data.engine import UserCreditStatementDocument
5
- from lgt_data.enums import UserAccountState, UserAction
6
- from lgt_data.model import UserModel
7
- from lgt_data.mongo_repository import UserMongoRepository, to_object_id
4
+ from lgt_jobs.lgt_data.engine import UserCreditStatementDocument
5
+ from lgt_jobs.lgt_data.enums import UserAccountState, UserAction
6
+ from lgt_jobs.lgt_data.model import UserModel
7
+ from lgt_jobs.lgt_data.mongo_repository import UserMongoRepository, to_object_id
8
8
  from pydantic import BaseModel
9
9
  from ..basejobs import BaseBackgroundJobData, BaseBackgroundJob
10
10
 
@@ -49,7 +49,7 @@ class UpdateUserBalanceJob(BaseBackgroundJob, ABC):
49
49
  # suspend account
50
50
  if user.state != UserAccountState.Suspended.value:
51
51
  UserMongoRepository().set(user.id, leads_proceeded=count,
52
- credits_exceeded_at=datetime.datetime.utcnow(),
52
+ credits_exceeded_at=datetime.datetime.now(datetime.UTC),
53
53
  state=UserAccountState.Suspended.value)
54
54
  return
55
55
 
@@ -1,11 +1,11 @@
1
1
  from abc import ABC
2
2
  from typing import Dict
3
3
  import requests
4
- from lgt.common.python.helpers import update_credentials, get_formatted_bot_name
5
- from lgt.common.python.slack_client.web_client import SlackWebClient
6
- from lgt_data.enums import StatusConnection, SourceType
7
- from lgt_data.model import UserWorkspace, SlackUser, DedicatedBotModel
8
- from lgt_data.mongo_repository import UserMongoRepository, DedicatedBotRepository
4
+ from lgt_jobs.lgt_common.helpers import update_credentials, get_formatted_bot_name
5
+ from lgt_jobs.lgt_common.slack_client.web_client import SlackWebClient
6
+ from lgt_jobs.lgt_data.enums import StatusConnection, SourceType
7
+ from lgt_jobs.lgt_data.model import UserWorkspace, SlackUser, DedicatedBotModel
8
+ from lgt_jobs.lgt_data.mongo_repository import UserMongoRepository, DedicatedBotRepository
9
9
  from ..basejobs import BaseBackgroundJobData, BaseBackgroundJob
10
10
  from .bot_stats_update import BotStatsUpdateJob, BotStatsUpdateJobData
11
11
  from ..runner import BackgroundJobRunner
@@ -129,4 +129,6 @@ class ConnectSlackAccountJob(BaseBackgroundJob, ABC):
129
129
  if auth.status_code == 200 and dedicated_bot.source.source_id not in user_workspaces_map.keys():
130
130
  dedicated_bot.banned = True
131
131
  dedicated_bot.invalid_creds = True
132
+ for server in dedicated_bot.servers:
133
+ server.deleted = True
132
134
  dedicated_bots_repository.add_or_update(dedicated_bot)
@@ -0,0 +1,62 @@
1
+ import loguru
2
+ import requests
3
+ from requests import Response
4
+ from lgt_jobs.lgt_common.discord_client.methods import DiscordMethods
5
+
6
+
7
+ class DiscordClient:
8
+ base_url = 'https://discord.com/api/'
9
+ discord_api_version = 'v9/'
10
+ token: str
11
+ headers: dict
12
+
13
+ def __init__(self, token: str = None):
14
+ self.token = token
15
+ self.headers = {"Authorization": self.token}
16
+
17
+ def login(self, login: str, password: str, captcha_key: str = None) -> dict:
18
+ payload = {
19
+ 'login': login,
20
+ 'password': password,
21
+ 'captcha_key': captcha_key,
22
+ "undelete": False,
23
+ "login_source": "",
24
+ "gift_code_sku_id": None
25
+ }
26
+ response = requests.post(f"{self.base_url}{self.discord_api_version}{DiscordMethods.LOGIN.value}", json=payload)
27
+ if response.status_code == 400 or response.status_code == 200:
28
+ return response.json()
29
+ return {}
30
+
31
+ def get_servers(self) -> list | dict:
32
+ response = requests.get(f"{self.base_url}{DiscordMethods.USER_GUILDS.value}", headers=self.headers)
33
+ return self.__response(response).json()
34
+
35
+ def get_dms(self) -> list | dict:
36
+ response = requests.get(f"{self.base_url}{DiscordMethods.USER_DMS.value}", headers=self.headers)
37
+ return self.__response(response).json()
38
+
39
+ def get_current_user(self) -> dict:
40
+ response = requests.get(f"{self.base_url}{DiscordMethods.USER.value}", headers=self.headers)
41
+ if response.status_code != 200:
42
+ self.__log_error(response)
43
+ return response.json()
44
+
45
+ def get_channels(self, guild_id: str) -> list | dict:
46
+ response = requests.get(f"{self.base_url}{DiscordMethods.guild_channels(guild_id)}", headers=self.headers)
47
+ return self.__response(response).json()
48
+
49
+ def get_invite_link(self, channel_id: str) -> Response:
50
+ response = requests.post(f'{self.base_url}{self.discord_api_version}'
51
+ f'{DiscordMethods.channels_invites(channel_id)}', headers=self.headers)
52
+ return self.__response(response)
53
+
54
+ @staticmethod
55
+ def __log_error(response: Response):
56
+ loguru.logger.warning(f"[DiscordClient WARNING]: {response.url}, {response.status_code}, {response.content}")
57
+
58
+ @staticmethod
59
+ def __response(response: Response):
60
+ if response.status_code != 200:
61
+ DiscordClient.__log_error(response)
62
+ return response
@@ -0,0 +1,16 @@
1
+ from enum import Enum
2
+
3
+
4
+ class DiscordMethods(str, Enum):
5
+ USER_GUILDS = 'users/@me/guilds'
6
+ USER_DMS = 'users/@me/channels'
7
+ USER = 'users/@me'
8
+ LOGIN = 'auth/login'
9
+
10
+ @staticmethod
11
+ def guild_channels(guild_id: str):
12
+ return f'guilds/{guild_id}/channels'
13
+
14
+ @staticmethod
15
+ def channels_invites(channel_id: str):
16
+ return f'channels/{channel_id}/invites'
@@ -0,0 +1,6 @@
1
+ from enum import Enum
2
+
3
+
4
+ class SlackErrors(str, Enum):
5
+ INVALID_AUTH = 'invalid_auth'
6
+ TWO_FACTOR_REQUIRED = 'two_factor_setup_required'
@@ -0,0 +1,18 @@
1
+ import re
2
+
3
+
4
+ def update_credentials(credentials, token, cookies):
5
+ credentials.token = token
6
+ credentials.cookies = cookies
7
+ credentials.invalid_creds = False
8
+ return credentials
9
+
10
+
11
+ def get_formatted_bot_name(name):
12
+ bot_name = name
13
+ bot_name.replace(" ", "_") \
14
+ .replace(".", "dot_") \
15
+ .replace("#", "") \
16
+ .replace("+", "_plus")
17
+
18
+ return re.sub(r'[^A-Za-z0-9]', "", bot_name).lower()