filter system message on starting the chat
This commit is contained in:
parent
ba236c2b3e
commit
5dcfec3e80
2 changed files with 103 additions and 4 deletions
|
|
@ -156,6 +156,15 @@ class MattermostClient:
|
|||
|
||||
return channel_id
|
||||
|
||||
@staticmethod
|
||||
def _is_system_post(post: dict) -> bool:
|
||||
"""
|
||||
Mattermost auto-generates posts like "user-x added to the channel"
|
||||
(type e.g. "system_add_to_channel") whenever channel membership
|
||||
changes. Real user-sent posts have an empty type.
|
||||
"""
|
||||
return post.get("type", "").startswith("system_")
|
||||
|
||||
def post_message(self, channel_id: str, message: str) -> str:
|
||||
"""
|
||||
Post a message to the given channel using the admin token.
|
||||
|
|
@ -181,6 +190,8 @@ class MattermostClient:
|
|||
) -> list[dict]:
|
||||
"""
|
||||
Fetch posts from a channel and return them in chronological order.
|
||||
System posts (channel membership changes, etc.) are excluded — only
|
||||
real user-sent posts are returned.
|
||||
|
||||
`since` is a Unix timestamp in **milliseconds**. When provided,
|
||||
`page` is ignored and all posts after that timestamp are returned.
|
||||
|
|
@ -200,19 +211,30 @@ class MattermostClient:
|
|||
posts_map: dict = data.get("posts", {})
|
||||
|
||||
# Mattermost returns newest-first; reverse to get chronological order.
|
||||
return [posts_map[pid] for pid in reversed(order) if pid in posts_map]
|
||||
return [
|
||||
posts_map[pid]
|
||||
for pid in reversed(order)
|
||||
if pid in posts_map and not self._is_system_post(posts_map[pid])
|
||||
]
|
||||
|
||||
def get_latest_post_id(self, channel_id: str) -> str | None:
|
||||
"""
|
||||
Return the ID of the most recent post in the channel, or None if empty.
|
||||
Return the ID of the most recent real (non-system) post in the
|
||||
channel, or None if there are none yet.
|
||||
Used to derive `has_unread` against a stored last_read_mattermost_post_id.
|
||||
"""
|
||||
try:
|
||||
data = self._driver.posts.get_posts_for_channel(
|
||||
channel_id, params={"page": 0, "per_page": 1}
|
||||
channel_id, params={"page": 0, "per_page": 20}
|
||||
)
|
||||
except Exception as exc:
|
||||
raise MattermostError(f"Fetching latest post failed: {exc}") from exc
|
||||
|
||||
order: list[str] = data.get("order", [])
|
||||
return order[0] if order else None
|
||||
posts_map: dict = data.get("posts", {})
|
||||
|
||||
for pid in order: # newest-first
|
||||
post = posts_map.get(pid)
|
||||
if post and not self._is_system_post(post):
|
||||
return pid
|
||||
return None
|
||||
|
|
|
|||
77
apps/chat/tests/test_mattermost_client.py
Normal file
77
apps/chat/tests/test_mattermost_client.py
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
from unittest.mock import Mock
|
||||
|
||||
from apps.chat.integrations.mattermost.client import MattermostClient
|
||||
|
||||
|
||||
def _make_client(driver_response: dict) -> MattermostClient:
|
||||
"""Build a MattermostClient without hitting the network (no __init__)."""
|
||||
client = MattermostClient.__new__(MattermostClient)
|
||||
client._driver = Mock()
|
||||
client._driver.posts.get_posts_for_channel.return_value = driver_response
|
||||
return client
|
||||
|
||||
|
||||
def _post(post_id, msg="hi", post_type="", user_id="u1"):
|
||||
return {
|
||||
"id": post_id,
|
||||
"type": post_type,
|
||||
"message": msg,
|
||||
"user_id": user_id,
|
||||
"create_at": 1700000000000,
|
||||
}
|
||||
|
||||
|
||||
def test_get_posts_excludes_system_posts():
|
||||
# Mattermost order is newest-first.
|
||||
posts_map = {
|
||||
"p1": _post("p1", "real message"),
|
||||
"sys1": _post("sys1", "user-x added to the channel", post_type="system_add_to_channel"),
|
||||
}
|
||||
client = _make_client({"order": ["sys1", "p1"], "posts": posts_map})
|
||||
|
||||
result = client.get_posts("chan-1")
|
||||
|
||||
assert [p["id"] for p in result] == ["p1"]
|
||||
|
||||
|
||||
def test_get_posts_keeps_chronological_order_with_no_system_posts():
|
||||
posts_map = {
|
||||
"p1": _post("p1", "first"),
|
||||
"p2": _post("p2", "second"),
|
||||
}
|
||||
client = _make_client({"order": ["p2", "p1"], "posts": posts_map})
|
||||
|
||||
result = client.get_posts("chan-1")
|
||||
|
||||
assert [p["id"] for p in result] == ["p1", "p2"]
|
||||
|
||||
|
||||
def test_get_latest_post_id_skips_leading_system_post():
|
||||
# sys1 is newest (e.g. someone was just added), p1 is the latest real message.
|
||||
posts_map = {
|
||||
"sys1": _post("sys1", "user-y added to the channel", post_type="system_add_to_channel"),
|
||||
"p1": _post("p1", "real message"),
|
||||
}
|
||||
client = _make_client({"order": ["sys1", "p1"], "posts": posts_map})
|
||||
|
||||
assert client.get_latest_post_id("chan-1") == "p1"
|
||||
|
||||
|
||||
def test_get_latest_post_id_returns_none_when_only_system_posts_exist():
|
||||
posts_map = {
|
||||
"sys1": _post("sys1", "user-x added to the channel", post_type="system_add_to_channel"),
|
||||
"sys2": _post("sys2", "user-y added to the channel", post_type="system_add_to_channel"),
|
||||
}
|
||||
client = _make_client({"order": ["sys2", "sys1"], "posts": posts_map})
|
||||
|
||||
assert client.get_latest_post_id("chan-1") is None
|
||||
|
||||
|
||||
def test_get_latest_post_id_returns_newest_real_post_when_no_system_posts():
|
||||
posts_map = {
|
||||
"p1": _post("p1", "first"),
|
||||
"p2": _post("p2", "second"),
|
||||
}
|
||||
client = _make_client({"order": ["p2", "p1"], "posts": posts_map})
|
||||
|
||||
assert client.get_latest_post_id("chan-1") == "p2"
|
||||
Loading…
Add table
Reference in a new issue