webex-bot 0.4.1__tar.gz → 0.4.7__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 (35) hide show
  1. {webex_bot-0.4.1 → webex_bot-0.4.7}/PKG-INFO +14 -2
  2. {webex_bot-0.4.1 → webex_bot-0.4.7}/README.md +12 -0
  3. {webex_bot-0.4.1 → webex_bot-0.4.7}/setup.cfg +1 -1
  4. {webex_bot-0.4.1 → webex_bot-0.4.7}/setup.py +3 -3
  5. {webex_bot-0.4.1 → webex_bot-0.4.7}/webex_bot/__init__.py +1 -1
  6. {webex_bot-0.4.1 → webex_bot-0.4.7}/webex_bot/commands/help.py +3 -2
  7. {webex_bot-0.4.1 → webex_bot-0.4.7}/webex_bot/webex_bot.py +40 -21
  8. {webex_bot-0.4.1 → webex_bot-0.4.7}/webex_bot/websockets/webex_websocket_client.py +45 -6
  9. {webex_bot-0.4.1 → webex_bot-0.4.7}/webex_bot.egg-info/PKG-INFO +14 -2
  10. {webex_bot-0.4.1 → webex_bot-0.4.7}/webex_bot.egg-info/requires.txt +1 -1
  11. {webex_bot-0.4.1 → webex_bot-0.4.7}/CONTRIBUTING.rst +0 -0
  12. {webex_bot-0.4.1 → webex_bot-0.4.7}/LICENSE +0 -0
  13. {webex_bot-0.4.1 → webex_bot-0.4.7}/MANIFEST.in +0 -0
  14. {webex_bot-0.4.1 → webex_bot-0.4.7}/docs/Makefile +0 -0
  15. {webex_bot-0.4.1 → webex_bot-0.4.7}/docs/conf.py +0 -0
  16. {webex_bot-0.4.1 → webex_bot-0.4.7}/docs/contributing.rst +0 -0
  17. {webex_bot-0.4.1 → webex_bot-0.4.7}/docs/index.rst +0 -0
  18. {webex_bot-0.4.1 → webex_bot-0.4.7}/docs/installation.rst +0 -0
  19. {webex_bot-0.4.1 → webex_bot-0.4.7}/docs/make.bat +0 -0
  20. {webex_bot-0.4.1 → webex_bot-0.4.7}/docs/usage.rst +0 -0
  21. {webex_bot-0.4.1 → webex_bot-0.4.7}/tests/__init__.py +0 -0
  22. {webex_bot-0.4.1 → webex_bot-0.4.7}/tests/test_webex_bot.py +0 -0
  23. {webex_bot-0.4.1 → webex_bot-0.4.7}/webex_bot/cards/__init__.py +0 -0
  24. {webex_bot-0.4.1 → webex_bot-0.4.7}/webex_bot/commands/__init__.py +0 -0
  25. {webex_bot-0.4.1 → webex_bot-0.4.7}/webex_bot/commands/echo.py +0 -0
  26. {webex_bot-0.4.1 → webex_bot-0.4.7}/webex_bot/exceptions.py +0 -0
  27. {webex_bot-0.4.1 → webex_bot-0.4.7}/webex_bot/formatting.py +0 -0
  28. {webex_bot-0.4.1 → webex_bot-0.4.7}/webex_bot/models/__init__.py +0 -0
  29. {webex_bot-0.4.1 → webex_bot-0.4.7}/webex_bot/models/command.py +0 -0
  30. {webex_bot-0.4.1 → webex_bot-0.4.7}/webex_bot/models/response.py +0 -0
  31. {webex_bot-0.4.1 → webex_bot-0.4.7}/webex_bot/websockets/__init__.py +0 -0
  32. {webex_bot-0.4.1 → webex_bot-0.4.7}/webex_bot.egg-info/SOURCES.txt +0 -0
  33. {webex_bot-0.4.1 → webex_bot-0.4.7}/webex_bot.egg-info/dependency_links.txt +0 -0
  34. {webex_bot-0.4.1 → webex_bot-0.4.7}/webex_bot.egg-info/not-zip-safe +0 -0
  35. {webex_bot-0.4.1 → webex_bot-0.4.7}/webex_bot.egg-info/top_level.txt +0 -0
@@ -1,10 +1,10 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: webex_bot
3
- Version: 0.4.1
3
+ Version: 0.4.7
4
4
  Summary: Python package for a Webex Bot based on websockets.
5
5
  Home-page: https://github.com/fbradyirl/webex_bot
6
6
  Author: Finbarr Brady
7
- Author-email: finbarr.brady@gmail.com
7
+ Author-email: finbarr@somemail.com
8
8
  License: MIT license
9
9
  Keywords: webex_bot
10
10
  Platform: UNKNOWN
@@ -347,6 +347,18 @@ and off you go!
347
347
 
348
348
  * Always ensure there is a thread ID in the Activity before accessing it
349
349
 
350
+ ### 0.4.6 (2024-Apr-24)
351
+
352
+ * Add max backoff time (#55)
353
+ * Attached files. Help, threading and log level overrides. (#54)
354
+ * add stop() call to gracefully exit the bot (#42)
355
+ * feat(20231212): add help image size parameter (#46)
356
+ * update websockets to 11.0.3 (#43)
357
+
358
+ ### 0.4.7 (2024-Apr-24)
359
+
360
+ * Fix for help_command syntax issue
361
+
350
362
  [1]: https://github.com/aaugustin/websockets
351
363
 
352
364
  [2]: https://github.com/CiscoDevNet/webexteamssdk
@@ -327,6 +327,18 @@ and off you go!
327
327
 
328
328
  * Always ensure there is a thread ID in the Activity before accessing it
329
329
 
330
+ ### 0.4.6 (2024-Apr-24)
331
+
332
+ * Add max backoff time (#55)
333
+ * Attached files. Help, threading and log level overrides. (#54)
334
+ * add stop() call to gracefully exit the bot (#42)
335
+ * feat(20231212): add help image size parameter (#46)
336
+ * update websockets to 11.0.3 (#43)
337
+
338
+ ### 0.4.7 (2024-Apr-24)
339
+
340
+ * Fix for help_command syntax issue
341
+
330
342
  [1]: https://github.com/aaugustin/websockets
331
343
 
332
344
  [2]: https://github.com/CiscoDevNet/webexteamssdk
@@ -1,5 +1,5 @@
1
1
  [bumpversion]
2
- current_version = 0.4.1
2
+ current_version = 0.4.7
3
3
  commit = True
4
4
  tag = True
5
5
 
@@ -7,7 +7,7 @@ from setuptools import setup, find_packages
7
7
  with open('README.md') as readme_file:
8
8
  readme = readme_file.read()
9
9
 
10
- requirements = ['webexteamssdk==1.6.1', 'coloredlogs', 'websockets==10.2', 'backoff']
10
+ requirements = ['webexteamssdk==1.6.1', 'coloredlogs', 'websockets==11.0.3', 'backoff']
11
11
 
12
12
  setup_requirements = ['pytest-runner', ]
13
13
 
@@ -15,7 +15,7 @@ test_requirements = ['pytest>=3', ]
15
15
 
16
16
  setup(
17
17
  author="Finbarr Brady",
18
- author_email='finbarr.brady@gmail.com',
18
+ author_email='finbarr@somemail.com',
19
19
  python_requires='>=3.8',
20
20
  classifiers=[
21
21
  'Development Status :: 2 - Pre-Alpha',
@@ -38,6 +38,6 @@ setup(
38
38
  test_suite='tests',
39
39
  tests_require=test_requirements,
40
40
  url='https://github.com/fbradyirl/webex_bot',
41
- version='0.4.1',
41
+ version='0.4.7',
42
42
  zip_safe=False,
43
43
  )
@@ -1,4 +1,4 @@
1
1
  """Top-level package for Webex Bot."""
2
2
 
3
3
  __author__ = """Finbarr Brady"""
4
- __version__ = '0.4.1'
4
+ __version__ = '0.4.7'
@@ -14,7 +14,7 @@ HELP_COMMAND_KEYWORD = "help"
14
14
 
15
15
  class HelpCommand(Command):
16
16
 
17
- def __init__(self, bot_name, bot_help_subtitle, bot_help_image):
17
+ def __init__(self, bot_name, bot_help_subtitle, bot_help_image, bot_help_image_size=ImageSize.SMALL):
18
18
  self.commands = None
19
19
  super().__init__(
20
20
  command_keyword=HELP_COMMAND_KEYWORD,
@@ -25,6 +25,7 @@ class HelpCommand(Command):
25
25
  self.bot_name = bot_name
26
26
  self.bot_help_subtitle = bot_help_subtitle
27
27
  self.bot_help_image = bot_help_image
28
+ self.bot_help_image_size = bot_help_image_size
28
29
 
29
30
  def execute(self, message, attachment_actions, activity):
30
31
  pass
@@ -42,7 +43,7 @@ class HelpCommand(Command):
42
43
 
43
44
  image = Image(
44
45
  url=self.bot_help_image,
45
- size=ImageSize.SMALL)
46
+ size=self.bot_help_image_size)
46
47
 
47
48
  header_column = Column(items=[heading, subtitle], width=2)
48
49
  header_image_column = Column(
@@ -16,10 +16,6 @@ from webex_bot.models.response import Response
16
16
  from webex_bot.websockets.webex_websocket_client import WebexWebsocketClient, DEFAULT_DEVICE_URL
17
17
 
18
18
  log = logging.getLogger(__name__)
19
- coloredlogs.install(level=os.getenv("LOG_LEVEL", "INFO"),
20
- fmt='%(asctime)s [%(levelname)s] '
21
- '[%(module)s.%(name)s.%(funcName)'
22
- 's]:%(lineno)s %(message)s')
23
19
 
24
20
 
25
21
  class WebexBot(WebexWebsocketClient):
@@ -32,7 +28,10 @@ class WebexBot(WebexWebsocketClient):
32
28
  device_url=DEFAULT_DEVICE_URL,
33
29
  include_demo_commands=False,
34
30
  bot_name="Webex Bot",
35
- bot_help_subtitle="Here are my available commands. Click one to begin."):
31
+ bot_help_subtitle="Here are my available commands. Click one to begin.",
32
+ threads=True,
33
+ help_command=None,
34
+ log_level="INFO"):
36
35
  """
37
36
  Initialise WebexBot.
38
37
 
@@ -44,8 +43,16 @@ class WebexBot(WebexWebsocketClient):
44
43
  @param include_demo_commands: If True, any demo commands will be included.
45
44
  @param bot_name: Your custom name for the bot.
46
45
  @param bot_help_subtitle: Text to show in the help card.
46
+ @param threads: If True, respond to msg by creating a thread.
47
+ @param help_command: If None, use internal HelpCommand, otherwise override.
48
+ @param log_level: Set loggin level.
49
+
47
50
  """
48
51
 
52
+ coloredlogs.install(level=os.getenv("LOG_LEVEL", log_level),
53
+ fmt='%(asctime)s [%(levelname)s] '
54
+ '[%(module)s.%(name)s.%(funcName)'
55
+ 's]:%(lineno)s %(message)s')
49
56
  log.info("Registering bot with Webex cloud")
50
57
  WebexWebsocketClient.__init__(self,
51
58
  teams_bot_token,
@@ -53,32 +60,33 @@ class WebexBot(WebexWebsocketClient):
53
60
  on_card_action=self.process_incoming_card_action,
54
61
  device_url=device_url)
55
62
 
63
+ if help_command is None:
64
+ self.help_command = HelpCommand(
65
+ bot_name=bot_name,
66
+ bot_help_subtitle=bot_help_subtitle,
67
+ bot_help_image=self.teams.people.me().avatar)
68
+ else:
69
+ self.help_command = help_command
70
+
56
71
  # A dictionary of commands this bot listens to
57
72
  # Each key in the dictionary is a command, with associated help
58
73
  # text and callback function
59
74
  # By default supports 2 command, echo and help
60
-
61
- self.help_command = HelpCommand(
62
- bot_name=bot_name,
63
- bot_help_subtitle=bot_help_subtitle,
64
- bot_help_image=self.teams.people.me().avatar)
65
75
  self.commands = {
66
76
  self.help_command
67
77
  }
78
+
68
79
  if include_demo_commands:
69
80
  self.add_command(EchoCommand())
70
81
 
71
- self.help_command.commands = self.commands
72
-
73
82
  self.card_callback_commands = {}
74
83
  self.approved_users = approved_users
75
84
  self.approved_domains = approved_domains
76
85
  self.approved_rooms = approved_rooms
77
- # Set default help message
78
- self.help_message = "Hello! I understand the following commands: \n"
79
86
  self.approval_parameters_check()
80
87
  self.bot_display_name = ""
81
88
  self.get_me_info()
89
+ self.threads = threads
82
90
 
83
91
  @backoff.on_exception(backoff.expo, requests.exceptions.ConnectionError)
84
92
  def get_me_info(self):
@@ -307,7 +315,7 @@ class WebexBot(WebexWebsocketClient):
307
315
  # If the Response lacks a roomId, set it to the incoming room
308
316
  if not reply.roomId:
309
317
  reply.roomId = room_id
310
- if not reply.parentId and conv_target_id:
318
+ if not reply.parentId and conv_target_id and self.threads:
311
319
  reply.parentId = conv_target_id
312
320
  reply = reply.as_dict()
313
321
  self.teams.messages.create(**reply)
@@ -351,14 +359,25 @@ class WebexBot(WebexWebsocketClient):
351
359
  quote_info(f"{user_email} I've messaged you 1-1. Please reply to me there.")
352
360
  if reply_one_to_one:
353
361
  if not is_one_on_one_space:
354
- self.teams.messages.create(roomId=room_id,
355
- markdown=default_move_to_one_to_one_heads_up,
362
+ if self.threads:
363
+ self.teams.messages.create(roomId=room_id,
364
+ markdown=default_move_to_one_to_one_heads_up,
365
+ parentId=conv_target_id)
366
+ else:
367
+ self.teams.messages.create(roomId=room_id,
368
+ markdown=default_move_to_one_to_one_heads_up)
369
+ if self.threads:
370
+ self.teams.messages.create(toPersonEmail=user_email,
371
+ markdown=reply,
356
372
  parentId=conv_target_id)
357
- self.teams.messages.create(toPersonEmail=user_email,
358
- markdown=reply,
359
- parentId=conv_target_id)
373
+ else:
374
+ self.teams.messages.create(toPersonEmail=user_email,
375
+ markdown=reply)
360
376
  else:
361
- self.teams.messages.create(roomId=room_id, markdown=reply, parentId=conv_target_id)
377
+ if self.threads:
378
+ self.teams.messages.create(roomId=room_id, markdown=reply, parentId=conv_target_id)
379
+ else:
380
+ self.teams.messages.create(roomId=room_id, markdown=reply)
362
381
 
363
382
  def run_pre_card_load_reply(self, command, message, teams_message, activity):
364
383
  """
@@ -28,6 +28,8 @@ DEVICE_DATA = {
28
28
  ssl_context = ssl.create_default_context()
29
29
  ssl_context.load_verify_locations(certifi.where())
30
30
 
31
+ MAX_BACKOFF_TIME = 240
32
+
31
33
 
32
34
  class WebexWebsocketClient(object):
33
35
  def __init__(self,
@@ -42,12 +44,14 @@ class WebexWebsocketClient(object):
42
44
  self.on_message = on_message
43
45
  self.on_card_action = on_card_action
44
46
  self.websocket = None
47
+ self.share_id = None
45
48
 
46
49
  def _process_incoming_websocket_message(self, msg):
47
50
  """
48
51
  Handle websocket data.
49
52
  :param msg: The raw websocket message
50
53
  """
54
+ logger.info(f"msg['data'] = {msg['data']}")
51
55
  if msg['data']['eventType'] == 'conversation.activity':
52
56
  activity = msg['data']['activity']
53
57
  if activity['verb'] == 'post':
@@ -61,6 +65,31 @@ class WebexWebsocketClient(object):
61
65
  self._ack_message(message_base_64_id)
62
66
  # Now process it with the handler
63
67
  self.on_message(teams_message=webex_message, activity=activity)
68
+ elif activity['verb'] == 'share':
69
+ logger.debug(f"activity={activity}")
70
+ self.share_id = activity['id']
71
+ return
72
+ elif activity['verb'] == 'update':
73
+ logger.debug(f"activity={activity}")
74
+
75
+ object = activity['object']
76
+ if object['objectType'] == 'content' and object['contentCategory'] == 'documents':
77
+ if 'files' in object.keys():
78
+ for item in object['files']['items']:
79
+ if not item['malwareQuarantineState'] == 'safe':
80
+ return
81
+ else:
82
+ return
83
+ else:
84
+ return
85
+ message_base_64_id = self._get_base64_message_id(activity)
86
+ webex_message = self.teams.messages.get(message_base_64_id)
87
+ logger.debug(f"webex_message from message_base_64_id: {webex_message}")
88
+ if self.on_message:
89
+ # ack message first
90
+ self._ack_message(message_base_64_id)
91
+ # Now process it with the handler
92
+ self.on_message(teams_message=webex_message, activity=activity)
64
93
  elif activity['verb'] == 'cardAction':
65
94
  logger.debug(f"activity={activity}")
66
95
 
@@ -83,10 +112,14 @@ class WebexWebsocketClient(object):
83
112
  @return: base 64 message id
84
113
  """
85
114
  activity_id = activity['id']
86
- logger.debug(f"activity verb=post. message id={activity_id}")
115
+ logger.debug(f"activity verb={activity['verb']}. message id={activity_id}")
87
116
  conversation_url = activity['target']['url']
88
117
  conv_target_id = activity['target']['id']
89
- verb = "messages" if activity['verb'] == "post" else "attachment/actions"
118
+ verb = "messages" if activity['verb'] in ["post", "update"] else "attachment/actions"
119
+ if activity['verb'] == "update" and self.share_id is not None:
120
+ activity_id = self.share_id
121
+ self.share_id = None
122
+ logger.debug(f"activity_id={activity_id}")
90
123
  conversation_message_url = conversation_url.replace(f"conversations/{conv_target_id}",
91
124
  f"{verb}/{activity_id}")
92
125
  headers = {"Authorization": f"Bearer {self.access_token}"}
@@ -134,6 +167,12 @@ class WebexWebsocketClient(object):
134
167
  logger.debug(f"self.device_info: {self.device_info}")
135
168
  return resp
136
169
 
170
+ def stop(self):
171
+ def terminate():
172
+ raise SystemExit()
173
+
174
+ asyncio.get_event_loop().create_task(terminate())
175
+
137
176
  def run(self):
138
177
  if self.device_info is None:
139
178
  if self._get_device_info() is None:
@@ -151,10 +190,10 @@ class WebexWebsocketClient(object):
151
190
  logger.warning(
152
191
  f"An exception occurred while processing message. Ignoring. {messageProcessingException}")
153
192
 
154
- @backoff.on_exception(backoff.expo, websockets.ConnectionClosedError)
155
- @backoff.on_exception(backoff.expo, websockets.ConnectionClosedOK)
156
- @backoff.on_exception(backoff.expo, websockets.ConnectionClosed)
157
- @backoff.on_exception(backoff.expo, socket.gaierror)
193
+ @backoff.on_exception(backoff.expo, websockets.ConnectionClosedError, max_time=MAX_BACKOFF_TIME)
194
+ @backoff.on_exception(backoff.expo, websockets.ConnectionClosedOK, max_time=MAX_BACKOFF_TIME)
195
+ @backoff.on_exception(backoff.expo, websockets.ConnectionClosed, max_time=MAX_BACKOFF_TIME)
196
+ @backoff.on_exception(backoff.expo, socket.gaierror, max_time=MAX_BACKOFF_TIME)
158
197
  async def _connect_and_listen():
159
198
  ws_url = self.device_info['webSocketUrl']
160
199
  logger.info(f"Opening websocket connection to {ws_url}")
@@ -1,10 +1,10 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: webex-bot
3
- Version: 0.4.1
3
+ Version: 0.4.7
4
4
  Summary: Python package for a Webex Bot based on websockets.
5
5
  Home-page: https://github.com/fbradyirl/webex_bot
6
6
  Author: Finbarr Brady
7
- Author-email: finbarr.brady@gmail.com
7
+ Author-email: finbarr@somemail.com
8
8
  License: MIT license
9
9
  Keywords: webex_bot
10
10
  Platform: UNKNOWN
@@ -347,6 +347,18 @@ and off you go!
347
347
 
348
348
  * Always ensure there is a thread ID in the Activity before accessing it
349
349
 
350
+ ### 0.4.6 (2024-Apr-24)
351
+
352
+ * Add max backoff time (#55)
353
+ * Attached files. Help, threading and log level overrides. (#54)
354
+ * add stop() call to gracefully exit the bot (#42)
355
+ * feat(20231212): add help image size parameter (#46)
356
+ * update websockets to 11.0.3 (#43)
357
+
358
+ ### 0.4.7 (2024-Apr-24)
359
+
360
+ * Fix for help_command syntax issue
361
+
350
362
  [1]: https://github.com/aaugustin/websockets
351
363
 
352
364
  [2]: https://github.com/CiscoDevNet/webexteamssdk
@@ -1,4 +1,4 @@
1
1
  webexteamssdk==1.6.1
2
2
  coloredlogs
3
- websockets==10.2
3
+ websockets==11.0.3
4
4
  backoff
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes