leadguru-jobs 0.553.0__py3-none-any.whl → 0.555.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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: leadguru_jobs
3
- Version: 0.553.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,4 +1,4 @@
1
- lgt_jobs/__init__.py,sha256=lrhMUJ7a5YSkYswQkQe981b_w8h8NHyncwfEduXEq6Q,1992
1
+ lgt_jobs/__init__.py,sha256=kmM5J3qBJd-fOZa2I4gkh36IytrgN6_18gWwwpR3n6Y,2156
2
2
  lgt_jobs/basejobs.py,sha256=LPEclvY6fIG17YMGy9pRK0Q58n62gkI5W1BTK6R2p-c,1234
3
3
  lgt_jobs/env.py,sha256=cRO03GGvstUjBsv3uYO-iakrOvAk_ZWUP_fnmf21iZQ,789
4
4
  lgt_jobs/main.py,sha256=cK_nkBtJHnUNDbba1WZotqPtI_6OWxiYQkAgco9OAmE,1539
@@ -13,11 +13,12 @@ lgt_jobs/assets/images/mail.png,sha256=eORzQcAMkFr7DjgtABVhJ_zFuXgO7OXv78lLF4b39
13
13
  lgt_jobs/jobs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
14
14
  lgt_jobs/jobs/analytics.py,sha256=IIsWt4A1qUw3w-S-8W16uKY1FRVWfXXA41_mu4uCNiM,979
15
15
  lgt_jobs/jobs/bot_stats_update.py,sha256=R6mf5FxhWbyx92AYXlj0FZVjz2Tgz86mBvLHrsQ9AFE,7502
16
- lgt_jobs/jobs/chat_history.py,sha256=QZdSWlk_DrDJt5yrNApYHiUEWQMYcKyuXaP_PlzkjYw,6303
16
+ lgt_jobs/jobs/chat_history.py,sha256=tZ4XyOGdy1k6r4uotxSSKbXjTR_oRK6Ym0YthFYBtl8,6200
17
+ lgt_jobs/jobs/connect_sources.py,sha256=2tl1MGdm6l0yFwCXlD0J2tFSQpj7i1eT9sYd1nMOwWA,3596
17
18
  lgt_jobs/jobs/inbox_leads.py,sha256=EYxdQPseNBY5ON7BK3LpnXDCgQpzHTPLRJCZmZiAAHA,5582
18
19
  lgt_jobs/jobs/mass_message.py,sha256=1mFcBlL2MhzLbj5yrd_NyJc7TXDWCcROAzGDnr0miMU,2035
19
20
  lgt_jobs/jobs/send_code.py,sha256=dIlLPkG3GgGKIEqGiElyzrtdrnJNTL1Ak2V0xnE-WIQ,824
20
- lgt_jobs/jobs/send_slack_message.py,sha256=WdXXh7QpjJKSvDU93YT9QKzoGRNBpPCJgiIxPs5gp1s,2782
21
+ lgt_jobs/jobs/send_slack_message.py,sha256=IuRqDGcDrz2EAZzF6nrLXO0aSA4mETB_tGOEbcMhjHE,2562
21
22
  lgt_jobs/jobs/update_slack_profile.py,sha256=0fUHBd2gEBne52sTfxwji2Wu-oYDM5dLGsL-rHq5kwM,2765
22
23
  lgt_jobs/jobs/user_balance_update.py,sha256=HxeEmDdloK9EcoEj1ybYTgxIkB0IQNLnss_kk3rLI1Q,2404
23
24
  lgt_jobs/jobs/workspace_connect.py,sha256=qgjIRzAQRbJBx--eYsTtYgOUh2-p3N_-LIltfbJrYYo,7102
@@ -35,18 +36,18 @@ lgt_jobs/lgt_common/pubsub/pubsubfactory.py,sha256=rfUDooYuhBQ2pE9FdDxZOpXjbrvlp
35
36
  lgt_jobs/lgt_common/slack_client/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
36
37
  lgt_jobs/lgt_common/slack_client/methods.py,sha256=ctKF_1UHEmSWaRsoGEgMZicVabV7eEufZ7pjxdMAx8g,1455
37
38
  lgt_jobs/lgt_common/slack_client/slack_client.py,sha256=fxSTaU696yfe5tFWnuW6LuH4EUkgB2kdqDxQ96GYMJY,13799
38
- lgt_jobs/lgt_common/slack_client/web_client.py,sha256=hiexBYtCnwz0oZvU6GnlQkD3aDqt9v5CvfPWMbz3Z50,6311
39
+ lgt_jobs/lgt_common/slack_client/web_client.py,sha256=JrkEepL6EhEtX3Psv_sd25bcRB2P23LoGnFHcczQpnc,4778
39
40
  lgt_jobs/lgt_data/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
40
41
  lgt_jobs/lgt_data/analytics.py,sha256=TFUffL8Dn-vIJ3ZaCVN-cj1Qnjb8F9GJyuk6Fo7mR1s,21645
41
42
  lgt_jobs/lgt_data/engine.py,sha256=Rsbz-CApAo_TVDssdjBkv8v_fVOZm_Uh1S6W4fnaEWo,7728
42
43
  lgt_jobs/lgt_data/enums.py,sha256=GZn6wm-kOd3veEOo1qlOR8QYje4vKaGV0na9jGt9388,2160
43
44
  lgt_jobs/lgt_data/helpers.py,sha256=NDa-V5EYaJfkGoWsmQSwSe6N_jxNxs8tHRQzW1iST6k,480
44
- lgt_jobs/lgt_data/model.py,sha256=DDfoWeH6rLWKoZsFJ2tI5Yagj1WlOa0PIJp-GqBIVSA,28112
45
+ lgt_jobs/lgt_data/model.py,sha256=KLfryiir_OfvACBFaJtbCssc5B5Xxw7XGlrnsypX1hA,28148
45
46
  lgt_jobs/lgt_data/mongo_repository.py,sha256=qqbt-oJ-RHmICLARgWvHuyPwVeKFkUqJZ2MA1bfIlXs,44762
46
47
  lgt_jobs/services/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
47
48
  lgt_jobs/services/web_client.py,sha256=GLWsJkIC8rv6xLFaLwcMm4EwBlVDu0njORwkZqBJaE4,2086
48
49
  lgt_jobs/templates/new_message.html,sha256=BD_E90akmQ1Wf07wtZAjeK_7DUKRmja5HFHVo_AKI24,6994
49
- leadguru_jobs-0.553.0.dist-info/METADATA,sha256=aW7QHrxDxKqTKUytouVMGYCf2UD7ZYHULpKOthzi_p0,1319
50
- leadguru_jobs-0.553.0.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
51
- leadguru_jobs-0.553.0.dist-info/top_level.txt,sha256=rIuw1DqwbnZyeoarBSC-bYeGOhv9mZBs7_afl9q4_JI,9
52
- leadguru_jobs-0.553.0.dist-info/RECORD,,
50
+ leadguru_jobs-0.555.0.dist-info/METADATA,sha256=uiUeMuopoV1T2SIcBVBCwuWZQgS4K3S8wnztsysxJ1k,1319
51
+ leadguru_jobs-0.555.0.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
52
+ leadguru_jobs-0.555.0.dist-info/top_level.txt,sha256=rIuw1DqwbnZyeoarBSC-bYeGOhv9mZBs7_afl9q4_JI,9
53
+ leadguru_jobs-0.555.0.dist-info/RECORD,,
lgt_jobs/__init__.py CHANGED
@@ -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