leadguru-jobs 0.552.0__tar.gz → 0.555.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 (60) hide show
  1. {leadguru_jobs-0.552.0 → leadguru_jobs-0.555.0}/PKG-INFO +1 -1
  2. {leadguru_jobs-0.552.0 → leadguru_jobs-0.555.0}/leadguru_jobs.egg-info/PKG-INFO +1 -1
  3. {leadguru_jobs-0.552.0 → leadguru_jobs-0.555.0}/leadguru_jobs.egg-info/SOURCES.txt +1 -0
  4. {leadguru_jobs-0.552.0 → leadguru_jobs-0.555.0}/lgt_jobs/__init__.py +4 -0
  5. {leadguru_jobs-0.552.0 → leadguru_jobs-0.555.0}/lgt_jobs/jobs/chat_history.py +2 -3
  6. leadguru_jobs-0.555.0/lgt_jobs/jobs/connect_sources.py +81 -0
  7. {leadguru_jobs-0.552.0 → leadguru_jobs-0.555.0}/lgt_jobs/jobs/send_slack_message.py +2 -4
  8. {leadguru_jobs-0.552.0 → leadguru_jobs-0.555.0}/lgt_jobs/lgt_common/slack_client/web_client.py +16 -51
  9. {leadguru_jobs-0.552.0 → leadguru_jobs-0.555.0}/lgt_jobs/lgt_data/model.py +8 -3
  10. {leadguru_jobs-0.552.0 → leadguru_jobs-0.555.0}/MANIFEST.in +0 -0
  11. {leadguru_jobs-0.552.0 → leadguru_jobs-0.555.0}/README.md +0 -0
  12. {leadguru_jobs-0.552.0 → leadguru_jobs-0.555.0}/leadguru_jobs.egg-info/dependency_links.txt +0 -0
  13. {leadguru_jobs-0.552.0 → leadguru_jobs-0.555.0}/leadguru_jobs.egg-info/not-zip-safe +0 -0
  14. {leadguru_jobs-0.552.0 → leadguru_jobs-0.555.0}/leadguru_jobs.egg-info/requires.txt +0 -0
  15. {leadguru_jobs-0.552.0 → leadguru_jobs-0.555.0}/leadguru_jobs.egg-info/top_level.txt +0 -0
  16. {leadguru_jobs-0.552.0 → leadguru_jobs-0.555.0}/lgt_jobs/assets/images/arrow.png +0 -0
  17. {leadguru_jobs-0.552.0 → leadguru_jobs-0.555.0}/lgt_jobs/assets/images/firework.png +0 -0
  18. {leadguru_jobs-0.552.0 → leadguru_jobs-0.555.0}/lgt_jobs/assets/images/lock.png +0 -0
  19. {leadguru_jobs-0.552.0 → leadguru_jobs-0.555.0}/lgt_jobs/assets/images/logo.png +0 -0
  20. {leadguru_jobs-0.552.0 → leadguru_jobs-0.555.0}/lgt_jobs/assets/images/mail.png +0 -0
  21. {leadguru_jobs-0.552.0 → leadguru_jobs-0.555.0}/lgt_jobs/basejobs.py +0 -0
  22. {leadguru_jobs-0.552.0 → leadguru_jobs-0.555.0}/lgt_jobs/env.py +0 -0
  23. {leadguru_jobs-0.552.0 → leadguru_jobs-0.555.0}/lgt_jobs/jobs/__init__.py +0 -0
  24. {leadguru_jobs-0.552.0 → leadguru_jobs-0.555.0}/lgt_jobs/jobs/analytics.py +0 -0
  25. {leadguru_jobs-0.552.0 → leadguru_jobs-0.555.0}/lgt_jobs/jobs/bot_stats_update.py +0 -0
  26. {leadguru_jobs-0.552.0 → leadguru_jobs-0.555.0}/lgt_jobs/jobs/inbox_leads.py +0 -0
  27. {leadguru_jobs-0.552.0 → leadguru_jobs-0.555.0}/lgt_jobs/jobs/mass_message.py +0 -0
  28. {leadguru_jobs-0.552.0 → leadguru_jobs-0.555.0}/lgt_jobs/jobs/send_code.py +0 -0
  29. {leadguru_jobs-0.552.0 → leadguru_jobs-0.555.0}/lgt_jobs/jobs/update_slack_profile.py +0 -0
  30. {leadguru_jobs-0.552.0 → leadguru_jobs-0.555.0}/lgt_jobs/jobs/user_balance_update.py +0 -0
  31. {leadguru_jobs-0.552.0 → leadguru_jobs-0.555.0}/lgt_jobs/jobs/workspace_connect.py +0 -0
  32. {leadguru_jobs-0.552.0 → leadguru_jobs-0.555.0}/lgt_jobs/lgt_common/__init__.py +0 -0
  33. {leadguru_jobs-0.552.0 → leadguru_jobs-0.555.0}/lgt_jobs/lgt_common/discord_client/__init__.py +0 -0
  34. {leadguru_jobs-0.552.0 → leadguru_jobs-0.555.0}/lgt_jobs/lgt_common/discord_client/discord_client.py +0 -0
  35. {leadguru_jobs-0.552.0 → leadguru_jobs-0.555.0}/lgt_jobs/lgt_common/discord_client/methods.py +0 -0
  36. {leadguru_jobs-0.552.0 → leadguru_jobs-0.555.0}/lgt_jobs/lgt_common/enums/__init__.py +0 -0
  37. {leadguru_jobs-0.552.0 → leadguru_jobs-0.555.0}/lgt_jobs/lgt_common/enums/slack_errors.py +0 -0
  38. {leadguru_jobs-0.552.0 → leadguru_jobs-0.555.0}/lgt_jobs/lgt_common/helpers.py +0 -0
  39. {leadguru_jobs-0.552.0 → leadguru_jobs-0.555.0}/lgt_jobs/lgt_common/lgt_logging.py +0 -0
  40. {leadguru_jobs-0.552.0 → leadguru_jobs-0.555.0}/lgt_jobs/lgt_common/pubsub/__init__.py +0 -0
  41. {leadguru_jobs-0.552.0 → leadguru_jobs-0.555.0}/lgt_jobs/lgt_common/pubsub/messages.py +0 -0
  42. {leadguru_jobs-0.552.0 → leadguru_jobs-0.555.0}/lgt_jobs/lgt_common/pubsub/pubsubfactory.py +0 -0
  43. {leadguru_jobs-0.552.0 → leadguru_jobs-0.555.0}/lgt_jobs/lgt_common/slack_client/__init__.py +0 -0
  44. {leadguru_jobs-0.552.0 → leadguru_jobs-0.555.0}/lgt_jobs/lgt_common/slack_client/methods.py +0 -0
  45. {leadguru_jobs-0.552.0 → leadguru_jobs-0.555.0}/lgt_jobs/lgt_common/slack_client/slack_client.py +0 -0
  46. {leadguru_jobs-0.552.0 → leadguru_jobs-0.555.0}/lgt_jobs/lgt_data/__init__.py +0 -0
  47. {leadguru_jobs-0.552.0 → leadguru_jobs-0.555.0}/lgt_jobs/lgt_data/analytics.py +0 -0
  48. {leadguru_jobs-0.552.0 → leadguru_jobs-0.555.0}/lgt_jobs/lgt_data/engine.py +0 -0
  49. {leadguru_jobs-0.552.0 → leadguru_jobs-0.555.0}/lgt_jobs/lgt_data/enums.py +0 -0
  50. {leadguru_jobs-0.552.0 → leadguru_jobs-0.555.0}/lgt_jobs/lgt_data/helpers.py +0 -0
  51. {leadguru_jobs-0.552.0 → leadguru_jobs-0.555.0}/lgt_jobs/lgt_data/mongo_repository.py +0 -0
  52. {leadguru_jobs-0.552.0 → leadguru_jobs-0.555.0}/lgt_jobs/main.py +0 -0
  53. {leadguru_jobs-0.552.0 → leadguru_jobs-0.555.0}/lgt_jobs/runner.py +0 -0
  54. {leadguru_jobs-0.552.0 → leadguru_jobs-0.555.0}/lgt_jobs/services/__init__.py +0 -0
  55. {leadguru_jobs-0.552.0 → leadguru_jobs-0.555.0}/lgt_jobs/services/web_client.py +0 -0
  56. {leadguru_jobs-0.552.0 → leadguru_jobs-0.555.0}/lgt_jobs/simple_job.py +0 -0
  57. {leadguru_jobs-0.552.0 → leadguru_jobs-0.555.0}/lgt_jobs/smtp.py +0 -0
  58. {leadguru_jobs-0.552.0 → leadguru_jobs-0.555.0}/lgt_jobs/templates/new_message.html +0 -0
  59. {leadguru_jobs-0.552.0 → leadguru_jobs-0.555.0}/setup.cfg +0 -0
  60. {leadguru_jobs-0.552.0 → leadguru_jobs-0.555.0}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: leadguru_jobs
3
- Version: 0.552.0
3
+ Version: 0.555.0
4
4
  Summary: LGT jobs builds
5
5
  Author-email: developer@leadguru.co
6
6
  Classifier: Development Status :: 5 - Production/Stable
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: leadguru_jobs
3
- Version: 0.552.0
3
+ Version: 0.555.0
4
4
  Summary: LGT jobs builds
5
5
  Author-email: developer@leadguru.co
6
6
  Classifier: Development Status :: 5 - Production/Stable
@@ -24,6 +24,7 @@ lgt_jobs/jobs/__init__.py
24
24
  lgt_jobs/jobs/analytics.py
25
25
  lgt_jobs/jobs/bot_stats_update.py
26
26
  lgt_jobs/jobs/chat_history.py
27
+ lgt_jobs/jobs/connect_sources.py
27
28
  lgt_jobs/jobs/inbox_leads.py
28
29
  lgt_jobs/jobs/mass_message.py
29
30
  lgt_jobs/jobs/send_code.py
@@ -3,6 +3,7 @@ name = "lgt_jobs"
3
3
  from .jobs.user_balance_update import UpdateUserBalanceJob, UpdateUserBalanceJobData
4
4
  from .jobs.send_slack_message import SendSlackMessageJob, SendSlackMessageJobData
5
5
  from .jobs.analytics import (TrackAnalyticsJob, TrackAnalyticsJobData)
6
+ from .jobs.connect_sources import (ConnectSourceJobData, ConnectSourceJob)
6
7
  from .jobs.bot_stats_update import (BotStatsUpdateJob, BotStatsUpdateJobData)
7
8
  from .jobs.chat_history import (LoadChatHistoryJob, LoadChatHistoryJobData)
8
9
  from .jobs.update_slack_profile import (UpdateExternalUserProfileJob, UpdateExternalUserProfileJobData)
@@ -22,6 +23,7 @@ jobs_map = {
22
23
  "SendSlackMessageJob": SendSlackMessageJob,
23
24
  "UpdateUserBalanceJob": UpdateUserBalanceJob,
24
25
  "SendMassMessageSlackChannelJob": SendMassMessageSlackChannelJob,
26
+ "ConnectSourceJob": ConnectSourceJob
25
27
  }
26
28
  __all__ = [
27
29
  # Jobs
@@ -35,6 +37,7 @@ __all__ = [
35
37
  SendSlackMessageJob,
36
38
  UpdateUserBalanceJob,
37
39
  SendMassMessageSlackChannelJob,
40
+ ConnectSourceJob,
38
41
 
39
42
  # module classes
40
43
  BackgroundJobRunner,
@@ -50,6 +53,7 @@ __all__ = [
50
53
  SendSlackMessageJobData,
51
54
  UpdateUserBalanceJobData,
52
55
  SendMassMessageSlackChannelJobData,
56
+ ConnectSourceJobData,
53
57
  # mapping
54
58
  jobs_map
55
59
  ]
@@ -100,9 +100,8 @@ class LoadChatHistoryJob(BaseBackgroundJob, ABC):
100
100
  if not messages:
101
101
  return None
102
102
 
103
- messages = [SlackMessageConvertService.from_slack_response(user.email, "slack_files",
104
- bot.token, m, contact.sender_id, bot.id,
105
- user.id, bot.cookies) for m in messages]
103
+ messages = [SlackMessageConvertService.from_slack_response(bot.user_name, m, contact.sender_id,
104
+ bot.id, user.id) for m in messages]
106
105
  new_messages = self._get_new_messages(contact, bot, messages)
107
106
  chat_history = [message.to_dic() for message in new_messages]
108
107
  self.chat_repo.upsert_messages(chat_history)
@@ -0,0 +1,81 @@
1
+ from abc import ABC
2
+ from typing import List
3
+ import logging as log
4
+ from lgt_jobs import BaseBackgroundJob, BaseBackgroundJobData, BackgroundJobRunner, BotStatsUpdateJob, \
5
+ BotStatsUpdateJobData
6
+ from lgt_jobs.lgt_data.engine import UserTrackAction
7
+ from lgt_jobs.lgt_data.enums import SourceType, UserAction, StatusConnection
8
+ from lgt_jobs.lgt_data.model import BaseModel, DedicatedBotModel, Server, Source, SlackUser
9
+ from lgt_jobs.lgt_data.mongo_repository import DedicatedBotRepository, UserMongoRepository
10
+
11
+
12
+ class ConnectSourceJobData(BaseBackgroundJobData, BaseModel):
13
+ slack_email: str
14
+ sources_ids: List[str]
15
+ action_user_email: str
16
+ user_email: str
17
+
18
+
19
+ class ConnectSourceJob(BaseBackgroundJob, ABC):
20
+ @property
21
+ def job_data_type(self) -> type:
22
+ return ConnectSourceJobData
23
+
24
+ def exec(self, data: ConnectSourceJobData):
25
+ users_repository = UserMongoRepository()
26
+ bots_repository = DedicatedBotRepository()
27
+ action_user = users_repository.get_by_email(data.action_user_email)
28
+ user = users_repository.get_by_email(data.user_email)
29
+ if not action_user:
30
+ log.info(f'Unable to find user with email: {data.action_user_email}')
31
+ return
32
+
33
+ slack_user: SlackUser = action_user.get_slack_user(data.slack_email)
34
+ if not slack_user:
35
+ log.info(f"You have no credentials for {data.slack_email}. Try to login to Slack.")
36
+ bots = []
37
+ for ws in slack_user.workspaces:
38
+ if ws.id in data.sources_ids:
39
+ active_bot = bots_repository.get_one(user_id=action_user.id, active_server_id=ws.id)
40
+ bot = bots_repository.get_one(user_id=action_user.id, server_id=ws.id, include_deleted=True,
41
+ user_name=data.slack_email)
42
+ if active_bot:
43
+ continue
44
+ if not bot:
45
+ bot = DedicatedBotModel()
46
+ bot.servers = [Server()]
47
+
48
+ bot.user_name = slack_user.email
49
+ bot.slack_url = ws.url
50
+ bot.user_id = action_user.id
51
+ bot.created_by = user.email
52
+ bot.registration_link = ws.url
53
+ bot.token = ws.token
54
+ bot.cookies = slack_user.cookies
55
+ bot.deleted = False
56
+ bot.paused = False
57
+ bot.invalid_creds = False
58
+ bot.banned = False
59
+ bot.two_factor_required = ws.two_factor_required
60
+ source = Source()
61
+
62
+ for server in bot.servers:
63
+ server.id = ws.id
64
+ server.name = ws.domain
65
+ server.deleted = False
66
+ server.active = True
67
+ server.icon = ws.icon
68
+
69
+ source.source_id = ws.id
70
+ source.source_name = ws.domain
71
+ bot.type = source.source_type = SourceType.SLACK
72
+ bot.icon = ws.icon
73
+ bot.source = source
74
+ bots_repository.add_or_update(bot)
75
+ UserTrackAction.track(action_user.id, UserAction.START_SOURCE, ws.id)
76
+ bot = bots_repository.get_one(user_id=action_user.id, server_id=ws.id, user_name=slack_user.email)
77
+ bots.append(bot)
78
+ BackgroundJobRunner.submit(BotStatsUpdateJob, BotStatsUpdateJobData(bot_id=str(bot.id)))
79
+ slack_user.status = StatusConnection.COMPLETE
80
+ users_repository.set(action_user.id, slack_users=[user.to_dic() for user in action_user.slack_users])
81
+ return bots
@@ -54,9 +54,7 @@ class SendSlackMessageJob(BaseBackgroundJob, ABC):
54
54
  message = resp.get('message') if 'message' in resp \
55
55
  else slack_client.conversation_replies(channel_id, resp['file_msg_ts'])['messages'][0]
56
56
 
57
- message_model: ChatMessage = SlackMessageConvertService.from_slack_response(user.email, "slack_files",
58
- bot.token, message, data.sender_id,
59
- bot.id, user.id,
60
- slack_client.client.cookies)
57
+ message_model: ChatMessage = SlackMessageConvertService.from_slack_response(bot.user_name, message,
58
+ data.sender_id, bot.id, user.id)
61
59
  message_model.viewed = True
62
60
  ChatRepository().upsert_messages([message_model.to_dic()])
@@ -1,28 +1,13 @@
1
- import requests
2
1
  from google.cloud import storage
3
2
  from datetime import datetime, timedelta
4
- from lgt_jobs.lgt_data.model import ChatMessage
5
- from .slack_client import SlackClient
6
- from ...lgt_data.mongo_repository import to_object_id
7
-
8
-
9
- def get_file_url(blob_path):
10
- storage_client = storage.Client()
11
- bucket = storage_client.get_bucket(SlackFilesClient.bucket_name)
12
- blob = bucket.get_blob(blob_path)
13
- if not blob:
14
- return None
15
- # valid for 3 days
16
- return blob.generate_signed_url(timedelta(3))
3
+ from lgt_jobs.lgt_data.model import ChatMessage, LeadGuruFile
4
+ from lgt_jobs.lgt_common.slack_client.slack_client import SlackClient
5
+ from lgt_jobs.lgt_data.mongo_repository import to_object_id
17
6
 
18
7
 
19
8
  class SlackMessageConvertService:
20
9
  @staticmethod
21
- def from_slack_response(user_email, bot_name, bot_token, dic, sender_id, bot_id, user_id, cookies=None):
22
-
23
- """
24
- :rtype: SlackHistoryMessageModel
25
- """
10
+ def from_slack_response(bot_name, dic, sender_id, bot_id, user_id) -> ChatMessage:
26
11
  result = ChatMessage()
27
12
  result.sender_id = sender_id
28
13
  result.bot_id = bot_id
@@ -32,24 +17,15 @@ class SlackMessageConvertService:
32
17
  result.attachments = dic.get('attachments', [])
33
18
  result.files = []
34
19
  result.user_id = to_object_id(user_id)
35
-
36
20
  if 'files' in dic:
37
21
  for file in dic.get('files'):
38
- if file.get('mode', '') == "tombstone" or not file.get('url_private_download'):
39
- continue
40
- new_file = ChatMessage.SlackFileModel()
41
- new_file.id = file.get('id')
42
- new_file.name = file.get('name')
43
- new_file.title = file.get('title')
44
- new_file.filetype = file.get('filetype')
45
- new_file.size = file.get('size')
46
- new_file.mimetype = file.get('mimetype')
47
-
48
- url_private_download = file.get('url_private_download')
49
- new_file.download_url = SlackFilesClient.get_file_url(user_email, bot_name, bot_token,
50
- new_file.id, url_private_download,
51
- new_file.mimetype, cookies)
52
- result.files.append(new_file)
22
+ if file.get('mode') != "tombstone" and file.get('url_private_download'):
23
+ leadguru_file = LeadGuruFile()
24
+ leadguru_file.id = file['id']
25
+ leadguru_file.content_type = file['mimetype']
26
+ leadguru_file.file_name = file['name']
27
+ leadguru_file.blob_path = f'slack_files/{bot_name}/slack_files/{file["id"]}'
28
+ result.files.append(leadguru_file)
53
29
 
54
30
  js_ticks = int(result.id.split('.')[0] + result.id.split('.')[1][3:])
55
31
  result.created_at = datetime.fromtimestamp(js_ticks / 1000.0)
@@ -59,23 +35,12 @@ class SlackMessageConvertService:
59
35
  class SlackFilesClient:
60
36
  bucket_name = 'lgt_service_file'
61
37
 
62
- # Consider to cache these file somewhere in the super-fast cache solution
63
- @staticmethod
64
- def get_file_url(user_email, bot_name, bot_token, file_id, url_private_download, mimetype, cookies=None):
38
+ def get_file_url(self, blob_path):
65
39
  storage_client = storage.Client()
66
- bucket = storage_client.get_bucket(SlackFilesClient.bucket_name)
67
- blob_path = f'slack_files/{user_email}/{bot_name}/{file_id}'
40
+ bucket = storage_client.get_bucket(self.bucket_name)
68
41
  blob = bucket.get_blob(blob_path)
69
-
70
42
  if not blob:
71
- res = requests.get(url_private_download, headers={'Authorization': f'Bearer {bot_token}'}, cookies=cookies)
72
- if res.status_code != 200:
73
- raise Exception(
74
- f'Failed to download file: {url_private_download} from slack due to response: '
75
- f'Code: {res.status_code} Error: {res.content}')
76
- blob = bucket.blob(blob_path)
77
- blob.upload_from_string(res.content, content_type=mimetype)
78
-
43
+ return None
79
44
  # valid for 3 days
80
45
  return blob.generate_signed_url(timedelta(3))
81
46
 
@@ -138,10 +103,10 @@ class SlackWebClient:
138
103
  def confirm_email(self, email: str, user_agent: str, locale: str = 'en-US') -> bool:
139
104
  return self.client.confirm_email(email, user_agent, locale)
140
105
 
141
- def confirm_code(self, email: str, code: str, user_agent: str, ) -> requests.Response:
106
+ def confirm_code(self, email: str, code: str, user_agent: str):
142
107
  return self.client.confirm_code(email, code, user_agent)
143
108
 
144
- def find_workspaces(self, user_agent: str, ) -> requests.Response:
109
+ def find_workspaces(self, user_agent: str):
145
110
  return self.client.find_workspaces(user_agent)
146
111
 
147
112
  def conversation_replies(self, channel: str, id: str) -> dict:
@@ -579,9 +579,7 @@ class ChatMessage:
579
579
 
580
580
  def to_dic(self):
581
581
  result = copy.deepcopy(self.__dict__)
582
- if self.files and 'files' in result:
583
- result['files'] = [x.to_dic() if isinstance(x, ChatMessage.SlackFileModel) else x for x in self.files]
584
-
582
+ result['files'] = [x.to_dic() for x in result.get('files', [])]
585
583
  return result
586
584
 
587
585
  @classmethod
@@ -971,3 +969,10 @@ class Subscription(BaseModel):
971
969
  model: Subscription | None = super().from_dic(dic)
972
970
  model.features = [Feature.from_dic(feature) for feature in dic.get('features', [])]
973
971
  return model
972
+
973
+
974
+ class LeadGuruFile(DictionaryModel):
975
+ id: str = None
976
+ blob_path: str
977
+ content_type: str
978
+ file_name: str = None