webex-message-handler 0.6.5__tar.gz → 0.6.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 (27) hide show
  1. {webex_message_handler-0.6.5 → webex_message_handler-0.6.7}/PKG-INFO +67 -2
  2. {webex_message_handler-0.6.5 → webex_message_handler-0.6.7}/README.md +66 -1
  3. {webex_message_handler-0.6.5 → webex_message_handler-0.6.7}/pyproject.toml +1 -1
  4. {webex_message_handler-0.6.5 → webex_message_handler-0.6.7}/src/webex_message_handler/__init__.py +8 -0
  5. {webex_message_handler-0.6.5 → webex_message_handler-0.6.7}/src/webex_message_handler/handler.py +48 -3
  6. webex_message_handler-0.6.7/src/webex_message_handler/mention_parser.py +59 -0
  7. {webex_message_handler-0.6.5 → webex_message_handler-0.6.7}/src/webex_message_handler/mercury_socket.py +2 -0
  8. {webex_message_handler-0.6.5 → webex_message_handler-0.6.7}/src/webex_message_handler/types.py +66 -0
  9. {webex_message_handler-0.6.5 → webex_message_handler-0.6.7}/tests/test_handler.py +5 -2
  10. {webex_message_handler-0.6.5 → webex_message_handler-0.6.7}/.gitignore +0 -0
  11. {webex_message_handler-0.6.5 → webex_message_handler-0.6.7}/API.md +0 -0
  12. {webex_message_handler-0.6.5 → webex_message_handler-0.6.7}/LICENSE +0 -0
  13. {webex_message_handler-0.6.5 → webex_message_handler-0.6.7}/examples/basic_bot.py +0 -0
  14. {webex_message_handler-0.6.5 → webex_message_handler-0.6.7}/src/webex_message_handler/device_manager.py +0 -0
  15. {webex_message_handler-0.6.5 → webex_message_handler-0.6.7}/src/webex_message_handler/errors.py +0 -0
  16. {webex_message_handler-0.6.5 → webex_message_handler-0.6.7}/src/webex_message_handler/id_utils.py +0 -0
  17. {webex_message_handler-0.6.5 → webex_message_handler-0.6.7}/src/webex_message_handler/kms_client.py +0 -0
  18. {webex_message_handler-0.6.5 → webex_message_handler-0.6.7}/src/webex_message_handler/logger.py +0 -0
  19. {webex_message_handler-0.6.5 → webex_message_handler-0.6.7}/src/webex_message_handler/message_decryptor.py +0 -0
  20. {webex_message_handler-0.6.5 → webex_message_handler-0.6.7}/src/webex_message_handler/url_validation.py +0 -0
  21. {webex_message_handler-0.6.5 → webex_message_handler-0.6.7}/test-proxy.py +0 -0
  22. {webex_message_handler-0.6.5 → webex_message_handler-0.6.7}/tests/__init__.py +0 -0
  23. {webex_message_handler-0.6.5 → webex_message_handler-0.6.7}/tests/conftest.py +0 -0
  24. {webex_message_handler-0.6.5 → webex_message_handler-0.6.7}/tests/test_device_manager.py +0 -0
  25. {webex_message_handler-0.6.5 → webex_message_handler-0.6.7}/tests/test_id_utils.py +0 -0
  26. {webex_message_handler-0.6.5 → webex_message_handler-0.6.7}/tests/test_integration.py +0 -0
  27. {webex_message_handler-0.6.5 → webex_message_handler-0.6.7}/tests/test_message_decryptor.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: webex-message-handler
3
- Version: 0.6.5
3
+ Version: 0.6.7
4
4
  Summary: Lightweight Webex Mercury WebSocket + KMS decryption for receiving bot messages without the full Webex SDK
5
5
  Project-URL: Homepage, https://github.com/3rg0n/webex-message-handler
6
6
  Project-URL: Repository, https://github.com/3rg0n/webex-message-handler
@@ -71,6 +71,18 @@ async def on_message(msg):
71
71
  def on_deleted(data):
72
72
  print(f"Message {data.message_id} deleted by {data.person_id}")
73
73
 
74
+ @handler.on("message:updated")
75
+ async def on_updated(msg):
76
+ print(f"[EDIT] [{msg.person_email}] {msg.text}")
77
+
78
+ @handler.on("attachmentAction:created")
79
+ def on_card(action):
80
+ print(f"Card submitted by {action.person_email}: {action.inputs}")
81
+
82
+ @handler.on("room:updated")
83
+ def on_room_updated(room):
84
+ print(f"Room {room.room_id} updated by {room.actor_id}")
85
+
74
86
  @handler.on("connected")
75
87
  def on_connected():
76
88
  print("Connected to Webex")
@@ -214,6 +226,11 @@ WebexMessageHandler(config: WebexMessageHandlerConfig)
214
226
  |-------|---------|-------------|
215
227
  | `message:created` | `DecryptedMessage` | New message received and decrypted |
216
228
  | `message:deleted` | `DeletedMessage` | Message was deleted |
229
+ | `message:updated` | `DecryptedMessage` | Message was edited and re-decrypted |
230
+ | `attachmentAction:created` | `AttachmentAction` | Adaptive Card submitted |
231
+ | `room:created` | `RoomActivity` | New room/space created |
232
+ | `room:updated` | `RoomActivity` | Room/space updated |
233
+ | `membership:created` | `MembershipActivity` | Member added/removed or moderator changed |
217
234
  | `connected` | — | Connected/reconnected to Mercury |
218
235
  | `disconnected` | `reason: str` | Disconnected from Mercury |
219
236
  | `reconnecting` | `attempt: int` | Attempting to reconnect |
@@ -225,16 +242,64 @@ WebexMessageHandler(config: WebexMessageHandlerConfig)
225
242
  @dataclass
226
243
  class DecryptedMessage:
227
244
  id: str
245
+ parent_id: str | None # Parent activity UUID (threaded replies)
228
246
  room_id: str
229
247
  person_id: str
230
248
  person_email: str
231
249
  text: str
232
250
  created: str
233
251
  html: str | None
234
- room_type: str | None # "direct" | "group"
252
+ room_type: str | None # "direct" | "group"
253
+ mentioned_people: list[str] # Person UUIDs from <spark-mention> tags
254
+ mentioned_groups: list[str] # e.g. ["all"] from group mentions
255
+ files: list[str] # File attachment URLs
235
256
  raw: MercuryActivity | None
236
257
  ```
237
258
 
259
+ ### `AttachmentAction`
260
+
261
+ Emitted when a user submits an Adaptive Card.
262
+
263
+ ```python
264
+ @dataclass
265
+ class AttachmentAction:
266
+ id: str # Activity UUID
267
+ message_id: str # Parent message containing the card
268
+ person_id: str # Person who submitted
269
+ person_email: str
270
+ room_id: str
271
+ inputs: dict[str, Any] # Card form data
272
+ created: str
273
+ raw: MercuryActivity
274
+ ```
275
+
276
+ ### `RoomActivity`
277
+
278
+ Emitted for room lifecycle events.
279
+
280
+ ```python
281
+ @dataclass
282
+ class RoomActivity:
283
+ id: str # Activity UUID
284
+ room_id: str
285
+ actor_id: str # Person who triggered the event
286
+ action: str # "create" or "update"
287
+ created: str
288
+ raw: MercuryActivity
289
+ ```
290
+
291
+ ### `parse_mentions(html)`
292
+
293
+ Extracts mentions from decrypted HTML. Called automatically during decryption — the results populate `DecryptedMessage.mentioned_people` and `DecryptedMessage.mentioned_groups`. Exported for standalone use.
294
+
295
+ ```python
296
+ from webex_message_handler import parse_mentions
297
+
298
+ result = parse_mentions(msg.html)
299
+ # result.mentioned_people: ["uuid-1", "uuid-2"]
300
+ # result.mentioned_groups: ["all"]
301
+ ```
302
+
238
303
  ## Architecture
239
304
 
240
305
  ```
@@ -39,6 +39,18 @@ async def on_message(msg):
39
39
  def on_deleted(data):
40
40
  print(f"Message {data.message_id} deleted by {data.person_id}")
41
41
 
42
+ @handler.on("message:updated")
43
+ async def on_updated(msg):
44
+ print(f"[EDIT] [{msg.person_email}] {msg.text}")
45
+
46
+ @handler.on("attachmentAction:created")
47
+ def on_card(action):
48
+ print(f"Card submitted by {action.person_email}: {action.inputs}")
49
+
50
+ @handler.on("room:updated")
51
+ def on_room_updated(room):
52
+ print(f"Room {room.room_id} updated by {room.actor_id}")
53
+
42
54
  @handler.on("connected")
43
55
  def on_connected():
44
56
  print("Connected to Webex")
@@ -182,6 +194,11 @@ WebexMessageHandler(config: WebexMessageHandlerConfig)
182
194
  |-------|---------|-------------|
183
195
  | `message:created` | `DecryptedMessage` | New message received and decrypted |
184
196
  | `message:deleted` | `DeletedMessage` | Message was deleted |
197
+ | `message:updated` | `DecryptedMessage` | Message was edited and re-decrypted |
198
+ | `attachmentAction:created` | `AttachmentAction` | Adaptive Card submitted |
199
+ | `room:created` | `RoomActivity` | New room/space created |
200
+ | `room:updated` | `RoomActivity` | Room/space updated |
201
+ | `membership:created` | `MembershipActivity` | Member added/removed or moderator changed |
185
202
  | `connected` | — | Connected/reconnected to Mercury |
186
203
  | `disconnected` | `reason: str` | Disconnected from Mercury |
187
204
  | `reconnecting` | `attempt: int` | Attempting to reconnect |
@@ -193,16 +210,64 @@ WebexMessageHandler(config: WebexMessageHandlerConfig)
193
210
  @dataclass
194
211
  class DecryptedMessage:
195
212
  id: str
213
+ parent_id: str | None # Parent activity UUID (threaded replies)
196
214
  room_id: str
197
215
  person_id: str
198
216
  person_email: str
199
217
  text: str
200
218
  created: str
201
219
  html: str | None
202
- room_type: str | None # "direct" | "group"
220
+ room_type: str | None # "direct" | "group"
221
+ mentioned_people: list[str] # Person UUIDs from <spark-mention> tags
222
+ mentioned_groups: list[str] # e.g. ["all"] from group mentions
223
+ files: list[str] # File attachment URLs
203
224
  raw: MercuryActivity | None
204
225
  ```
205
226
 
227
+ ### `AttachmentAction`
228
+
229
+ Emitted when a user submits an Adaptive Card.
230
+
231
+ ```python
232
+ @dataclass
233
+ class AttachmentAction:
234
+ id: str # Activity UUID
235
+ message_id: str # Parent message containing the card
236
+ person_id: str # Person who submitted
237
+ person_email: str
238
+ room_id: str
239
+ inputs: dict[str, Any] # Card form data
240
+ created: str
241
+ raw: MercuryActivity
242
+ ```
243
+
244
+ ### `RoomActivity`
245
+
246
+ Emitted for room lifecycle events.
247
+
248
+ ```python
249
+ @dataclass
250
+ class RoomActivity:
251
+ id: str # Activity UUID
252
+ room_id: str
253
+ actor_id: str # Person who triggered the event
254
+ action: str # "create" or "update"
255
+ created: str
256
+ raw: MercuryActivity
257
+ ```
258
+
259
+ ### `parse_mentions(html)`
260
+
261
+ Extracts mentions from decrypted HTML. Called automatically during decryption — the results populate `DecryptedMessage.mentioned_people` and `DecryptedMessage.mentioned_groups`. Exported for standalone use.
262
+
263
+ ```python
264
+ from webex_message_handler import parse_mentions
265
+
266
+ result = parse_mentions(msg.html)
267
+ # result.mentioned_people: ["uuid-1", "uuid-2"]
268
+ # result.mentioned_groups: ["all"]
269
+ ```
270
+
206
271
  ## Architecture
207
272
 
208
273
  ```
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "webex-message-handler"
7
- version = "0.6.5"
7
+ version = "0.6.7"
8
8
  description = "Lightweight Webex Mercury WebSocket + KMS decryption for receiving bot messages without the full Webex SDK"
9
9
  readme = "README.md"
10
10
  license = "MIT"
@@ -13,9 +13,11 @@ from .handler import WebexMessageHandler
13
13
  from .id_utils import from_rest_id, to_rest_id
14
14
  from .kms_client import KmsClient
15
15
  from .logger import Logger, console_logger, noop_logger
16
+ from .mention_parser import ParsedMentions, parse_mentions
16
17
  from .mercury_socket import MercurySocket
17
18
  from .message_decryptor import MessageDecryptor
18
19
  from .types import (
20
+ AttachmentAction,
19
21
  ConnectionStatus,
20
22
  DecryptedMessage,
21
23
  DeletedMessage,
@@ -33,6 +35,7 @@ from .types import (
33
35
  MercuryParent,
34
36
  MercuryTarget,
35
37
  NetworkMode,
38
+ RoomActivity,
36
39
  WebexMessageHandlerConfig,
37
40
  WebSocketFactory,
38
41
  )
@@ -45,6 +48,9 @@ __all__ = [
45
48
  "MercurySocket",
46
49
  "KmsClient",
47
50
  "MessageDecryptor",
51
+ # Mention parsing
52
+ "ParsedMentions",
53
+ "parse_mentions",
48
54
  # Errors
49
55
  "WebexError",
50
56
  "AuthError",
@@ -71,6 +77,8 @@ __all__ = [
71
77
  "DecryptedMessage",
72
78
  "DeletedMessage",
73
79
  "MembershipActivity",
80
+ "AttachmentAction",
81
+ "RoomActivity",
74
82
  "HandlerStatus",
75
83
  "ConnectionStatus",
76
84
  # Networking types
@@ -12,9 +12,11 @@ import aiohttp
12
12
  from .device_manager import DeviceManager
13
13
  from .kms_client import KmsClient
14
14
  from .logger import Logger, noop_logger
15
+ from .mention_parser import parse_mentions
15
16
  from .mercury_socket import MercurySocket
16
17
  from .message_decryptor import MessageDecryptor
17
18
  from .types import (
19
+ AttachmentAction,
18
20
  ConnectionStatus,
19
21
  DecryptedMessage,
20
22
  DeletedMessage,
@@ -26,6 +28,7 @@ from .types import (
26
28
  InjectedWebSocket,
27
29
  MembershipActivity,
28
30
  MercuryActivity,
31
+ RoomActivity,
29
32
  WebexMessageHandlerConfig,
30
33
  WebSocketFactory,
31
34
  )
@@ -135,8 +138,12 @@ class WebexMessageHandler:
135
138
  # Event listeners
136
139
  self._listeners: dict[str, list[EventCallback]] = {
137
140
  "message:created": [],
141
+ "message:updated": [],
138
142
  "message:deleted": [],
139
143
  "membership:created": [],
144
+ "attachmentAction:created": [],
145
+ "room:created": [],
146
+ "room:updated": [],
140
147
  "connected": [],
141
148
  "disconnected": [],
142
149
  "reconnecting": [],
@@ -455,13 +462,14 @@ class WebexMessageHandler:
455
462
  if len(self._recent_activity_ids) % 100 == 0:
456
463
  self._sweep_old_activity_ids()
457
464
 
458
- # message:created — verb=post + objectType=comment
459
- if activity.verb == "post" and activity.object.object_type == "comment":
465
+ # message:created or message:updated — verb=post/update + objectType=comment
466
+ if activity.verb in ("post", "update") and activity.object.object_type == "comment":
460
467
  if not self._message_decryptor:
461
468
  self._logger.warning("Received activity but decryptor not initialized")
462
469
  return
463
470
 
464
471
  decrypted = await self._message_decryptor.decrypt_activity(activity)
472
+ mentions = parse_mentions(decrypted.object.content)
465
473
  message = DecryptedMessage(
466
474
  id=decrypted.id,
467
475
  room_id=decrypted.target.id,
@@ -470,6 +478,9 @@ class WebexMessageHandler:
470
478
  text=decrypted.object.display_name or "",
471
479
  created=decrypted.published,
472
480
  parent_id=decrypted.parent.id if decrypted.parent else None,
481
+ mentioned_people=mentions.mentioned_people,
482
+ mentioned_groups=mentions.mentioned_groups,
483
+ files=decrypted.object.files or [],
473
484
  html=decrypted.object.content,
474
485
  room_type=self._infer_room_type(decrypted),
475
486
  raw=decrypted,
@@ -483,7 +494,8 @@ class WebexMessageHandler:
483
494
  self._logger.debug(f"Ignoring self-message from bot ({self._bot_person_id})")
484
495
  return
485
496
 
486
- self._emit("message:created", message)
497
+ event_name = "message:updated" if activity.verb == "update" else "message:created"
498
+ self._emit(event_name, message)
487
499
  return
488
500
 
489
501
  # message:deleted — verb=delete + objectType=activity
@@ -515,6 +527,39 @@ class WebexMessageHandler:
515
527
  raw=activity,
516
528
  ),
517
529
  )
530
+ return
531
+
532
+ # attachmentAction:created — verb=cardAction + objectType=submit
533
+ if activity.verb == "cardAction" and activity.object.object_type == "submit":
534
+ self._emit(
535
+ "attachmentAction:created",
536
+ AttachmentAction(
537
+ id=activity.id,
538
+ message_id=activity.parent.id if activity.parent else "",
539
+ person_id=activity.actor.id,
540
+ person_email=activity.actor.email_address or "",
541
+ room_id=activity.target.id,
542
+ inputs=activity.object.inputs or {},
543
+ created=activity.published,
544
+ raw=activity,
545
+ ),
546
+ )
547
+ return
548
+
549
+ # room:created or room:updated — verb=create/update + object.objectType=conversation
550
+ if activity.verb in ("create", "update") and activity.object.object_type == "conversation":
551
+ event_name = "room:created" if activity.verb == "create" else "room:updated"
552
+ self._emit(
553
+ event_name,
554
+ RoomActivity(
555
+ id=activity.id,
556
+ room_id=activity.target.id,
557
+ actor_id=activity.actor.id,
558
+ action="created" if activity.verb == "create" else "updated",
559
+ created=activity.published,
560
+ raw=activity,
561
+ ),
562
+ )
518
563
 
519
564
  @staticmethod
520
565
  def _infer_room_type(activity: MercuryActivity) -> str | None:
@@ -0,0 +1,59 @@
1
+ """Parse Webex ``<spark-mention>`` tags from decrypted HTML."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import re
6
+ from dataclasses import dataclass, field
7
+
8
+
9
+ @dataclass
10
+ class ParsedMentions:
11
+ """Mentions extracted from message HTML."""
12
+
13
+ mentioned_people: list[str] = field(default_factory=list)
14
+ mentioned_groups: list[str] = field(default_factory=list)
15
+
16
+
17
+ _MENTION_RE = re.compile(
18
+ r'<spark-mention[^>]*data-object-type="([^"]*)"[^>]*>', re.IGNORECASE
19
+ )
20
+ _PERSON_ID_RE = re.compile(r'data-object-id="([^"]*)"', re.IGNORECASE)
21
+ _GROUP_TYPE_RE = re.compile(r'data-group-type="([^"]*)"', re.IGNORECASE)
22
+
23
+
24
+ def parse_mentions(html: str | None) -> ParsedMentions:
25
+ """Extract mentioned people and groups from decrypted HTML.
26
+
27
+ Parses ``<spark-mention>`` tags to find person UUIDs and group
28
+ mention types (e.g. ``"all"``). Duplicates are removed.
29
+
30
+ Args:
31
+ html: Decrypted HTML content from a Webex message.
32
+
33
+ Returns:
34
+ ParsedMentions with ``mentioned_people`` and ``mentioned_groups``.
35
+ """
36
+ result = ParsedMentions()
37
+ if not html:
38
+ return result
39
+
40
+ seen: set[str] = set()
41
+
42
+ for match in _MENTION_RE.finditer(html):
43
+ tag = match.group(0)
44
+ object_type = match.group(1)
45
+
46
+ if object_type == "person":
47
+ id_match = _PERSON_ID_RE.search(tag)
48
+ if id_match and id_match.group(1) and id_match.group(1) not in seen:
49
+ seen.add(id_match.group(1))
50
+ result.mentioned_people.append(id_match.group(1))
51
+ elif object_type == "groupMention":
52
+ group_match = _GROUP_TYPE_RE.search(tag)
53
+ if group_match and group_match.group(1):
54
+ key = f"group:{group_match.group(1)}"
55
+ if key not in seen:
56
+ seen.add(key)
57
+ result.mentioned_groups.append(group_match.group(1))
58
+
59
+ return result
@@ -411,6 +411,8 @@ def _parse_activity(raw: dict[str, Any]) -> MercuryActivity:
411
411
  display_name=object_raw.get("displayName"),
412
412
  content=object_raw.get("content"),
413
413
  encryption_key_url=object_raw.get("encryptionKeyUrl"),
414
+ inputs=object_raw.get("inputs"),
415
+ files=object_raw.get("files"),
414
416
  ),
415
417
  target=MercuryTarget(
416
418
  id=target_raw.get("id", ""),
@@ -158,6 +158,11 @@ class MercuryObject:
158
158
  display_name: str | None = None
159
159
  content: str | None = None
160
160
  encryption_key_url: str | None = None
161
+ inputs: dict[str, Any] | None = None
162
+ """Card form input values (present on cardAction/submit activities)."""
163
+
164
+ files: list[str] | None = None
165
+ """File URLs attached to the message (present on file-share messages)."""
161
166
 
162
167
 
163
168
  @dataclass
@@ -222,6 +227,15 @@ class DecryptedMessage:
222
227
  parent_id: str | None = None
223
228
  """Parent activity UUID for threaded replies. None if not a thread reply."""
224
229
 
230
+ mentioned_people: list[str] = field(default_factory=list)
231
+ """Person UUIDs mentioned via @mention in the message."""
232
+
233
+ mentioned_groups: list[str] = field(default_factory=list)
234
+ """Group mention types (e.g. 'all') in the message."""
235
+
236
+ files: list[str] = field(default_factory=list)
237
+ """File URLs attached to the message."""
238
+
225
239
  html: str | None = None
226
240
  """Decrypted HTML content (rich text messages)."""
227
241
 
@@ -270,6 +284,58 @@ class MembershipActivity:
270
284
  """Full raw activity for advanced use."""
271
285
 
272
286
 
287
+ @dataclass
288
+ class AttachmentAction:
289
+ """An adaptive card submission from Mercury."""
290
+
291
+ id: str
292
+ """Activity ID."""
293
+
294
+ message_id: str
295
+ """ID of the message the card was attached to."""
296
+
297
+ person_id: str
298
+ """ID of the person who submitted the card."""
299
+
300
+ person_email: str
301
+ """Email of the person who submitted the card."""
302
+
303
+ room_id: str
304
+ """Conversation/space ID."""
305
+
306
+ inputs: dict[str, Any]
307
+ """Card form input values."""
308
+
309
+ created: str
310
+ """ISO 8601 timestamp."""
311
+
312
+ raw: MercuryActivity | None = None
313
+ """Full raw activity for advanced use."""
314
+
315
+
316
+ @dataclass
317
+ class RoomActivity:
318
+ """A room event from Mercury."""
319
+
320
+ id: str
321
+ """Activity ID."""
322
+
323
+ room_id: str
324
+ """Conversation/space ID."""
325
+
326
+ actor_id: str
327
+ """ID of the person who performed the action."""
328
+
329
+ action: str
330
+ """Room action: 'created' or 'updated'."""
331
+
332
+ created: str
333
+ """ISO 8601 timestamp."""
334
+
335
+ raw: MercuryActivity | None = None
336
+ """Full raw activity for advanced use."""
337
+
338
+
273
339
  # --- Status ---
274
340
 
275
341
  ConnectionStatus = Literal["connected", "connecting", "reconnecting", "disconnected"]
@@ -276,16 +276,19 @@ class TestMessageHandling:
276
276
  async def test_ignores_non_message_activities(self):
277
277
  handler = _make_handler()
278
278
  handler._message_decryptor = MagicMock()
279
- handler._message_decryptor.decrypt_activity = AsyncMock(return_value=_make_activity(verb="update"))
279
+ handler._message_decryptor.decrypt_activity = AsyncMock(return_value=_make_activity(verb="acknowledge"))
280
280
 
281
281
  messages = []
282
+ updated = []
282
283
  deleted = []
283
284
  handler.on("message:created", lambda msg: messages.append(msg))
285
+ handler.on("message:updated", lambda msg: updated.append(msg))
284
286
  handler.on("message:deleted", lambda d: deleted.append(d))
285
287
 
286
- await handler._handle_activity(_make_activity(verb="update"))
288
+ await handler._handle_activity(_make_activity(verb="acknowledge"))
287
289
 
288
290
  assert len(messages) == 0
291
+ assert len(updated) == 0
289
292
  assert len(deleted) == 0
290
293
 
291
294
  async def test_ignores_post_non_comment(self):