Compare commits
No commits in common. "b466bfb941e72af4ca07773bffbf48b5c39cf686" and "69b5ba0198f1c3aa26d99b64c58bc3dc5745c009" have entirely different histories.
b466bfb941
...
69b5ba0198
6 changed files with 2 additions and 145 deletions
|
|
@ -1,66 +1,6 @@
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
|
|
||||||
from apps.chat.models import (
|
from apps.chat.models import ConversationReport
|
||||||
Conversation,
|
|
||||||
ConversationParticipant,
|
|
||||||
ConversationReadState,
|
|
||||||
ConversationReport,
|
|
||||||
MattermostAccountMapping,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class ConversationParticipantInline(admin.TabularInline):
|
|
||||||
model = ConversationParticipant
|
|
||||||
extra = 0
|
|
||||||
fields = ("user_uuid", "joined_at")
|
|
||||||
readonly_fields = ("joined_at",)
|
|
||||||
|
|
||||||
|
|
||||||
@admin.register(Conversation)
|
|
||||||
class ConversationAdmin(admin.ModelAdmin):
|
|
||||||
list_display = (
|
|
||||||
"uuid",
|
|
||||||
"type",
|
|
||||||
"status",
|
|
||||||
"mattermost_channel_id",
|
|
||||||
"closed_by_uuid",
|
|
||||||
"created_at",
|
|
||||||
)
|
|
||||||
list_filter = ("type", "status", "created_at")
|
|
||||||
search_fields = ("uuid", "mattermost_channel_id")
|
|
||||||
readonly_fields = ("uuid", "created_at", "updated_at")
|
|
||||||
ordering = ("-created_at",)
|
|
||||||
inlines = [ConversationParticipantInline]
|
|
||||||
|
|
||||||
|
|
||||||
@admin.register(ConversationParticipant)
|
|
||||||
class ConversationParticipantAdmin(admin.ModelAdmin):
|
|
||||||
list_display = ("uuid", "conversation", "user_uuid", "joined_at")
|
|
||||||
search_fields = ("uuid", "conversation__uuid", "user_uuid")
|
|
||||||
readonly_fields = ("uuid", "joined_at")
|
|
||||||
ordering = ("-joined_at",)
|
|
||||||
|
|
||||||
|
|
||||||
@admin.register(ConversationReadState)
|
|
||||||
class ConversationReadStateAdmin(admin.ModelAdmin):
|
|
||||||
list_display = (
|
|
||||||
"uuid",
|
|
||||||
"conversation",
|
|
||||||
"user_uuid",
|
|
||||||
"last_read_mattermost_post_id",
|
|
||||||
"updated_at",
|
|
||||||
)
|
|
||||||
search_fields = ("uuid", "conversation__uuid", "user_uuid")
|
|
||||||
readonly_fields = ("uuid", "updated_at")
|
|
||||||
ordering = ("-updated_at",)
|
|
||||||
|
|
||||||
|
|
||||||
@admin.register(MattermostAccountMapping)
|
|
||||||
class MattermostAccountMappingAdmin(admin.ModelAdmin):
|
|
||||||
list_display = ("uuid", "user_uuid", "mattermost_user_id", "created_at")
|
|
||||||
search_fields = ("uuid", "user_uuid", "mattermost_user_id")
|
|
||||||
readonly_fields = ("uuid", "created_at")
|
|
||||||
ordering = ("-created_at",)
|
|
||||||
|
|
||||||
|
|
||||||
@admin.register(ConversationReport)
|
@admin.register(ConversationReport)
|
||||||
|
|
|
||||||
|
|
@ -181,8 +181,6 @@ class MattermostClient:
|
||||||
) -> list[dict]:
|
) -> list[dict]:
|
||||||
"""
|
"""
|
||||||
Fetch posts from a channel and return them in chronological order.
|
Fetch posts from a channel and return them in chronological order.
|
||||||
Includes Mattermost system posts (channel membership changes, etc.)
|
|
||||||
as-is, with their raw `type` intact — callers filter if they need to.
|
|
||||||
|
|
||||||
`since` is a Unix timestamp in **milliseconds**. When provided,
|
`since` is a Unix timestamp in **milliseconds**. When provided,
|
||||||
`page` is ignored and all posts after that timestamp are returned.
|
`page` is ignored and all posts after that timestamp are returned.
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,6 @@ class MessageSerializer(serializers.Serializer):
|
||||||
post_id = serializers.CharField()
|
post_id = serializers.CharField()
|
||||||
sender_uuid = serializers.UUIDField(allow_null=True)
|
sender_uuid = serializers.UUIDField(allow_null=True)
|
||||||
message_type = serializers.CharField(default="text")
|
message_type = serializers.CharField(default="text")
|
||||||
mattermost_message_type = serializers.CharField(default="", allow_blank=True)
|
|
||||||
text = serializers.CharField(allow_null=True, required=False)
|
text = serializers.CharField(allow_null=True, required=False)
|
||||||
url = serializers.CharField(allow_null=True, required=False)
|
url = serializers.CharField(allow_null=True, required=False)
|
||||||
created_at = serializers.DateTimeField(allow_null=True, required=False)
|
created_at = serializers.DateTimeField(allow_null=True, required=False)
|
||||||
|
|
|
||||||
|
|
@ -78,7 +78,6 @@ class MessageService:
|
||||||
"post_id": post_id,
|
"post_id": post_id,
|
||||||
"sender_uuid": sender_uuid,
|
"sender_uuid": sender_uuid,
|
||||||
"message_type": message_type,
|
"message_type": message_type,
|
||||||
"mattermost_message_type": "",
|
|
||||||
"text": text,
|
"text": text,
|
||||||
"url": download_url,
|
"url": download_url,
|
||||||
"created_at": None,
|
"created_at": None,
|
||||||
|
|
@ -126,7 +125,6 @@ class MessageService:
|
||||||
"post_id": post.get("id"),
|
"post_id": post.get("id"),
|
||||||
"sender_uuid": sender_uuid,
|
"sender_uuid": sender_uuid,
|
||||||
"message_type": message_type,
|
"message_type": message_type,
|
||||||
"mattermost_message_type": post.get("type", ""),
|
|
||||||
"text": None,
|
"text": None,
|
||||||
"url": self._storage.get_download_url(object_key),
|
"url": self._storage.get_download_url(object_key),
|
||||||
"created_at": created_at,
|
"created_at": created_at,
|
||||||
|
|
@ -136,7 +134,6 @@ class MessageService:
|
||||||
"post_id": post.get("id"),
|
"post_id": post.get("id"),
|
||||||
"sender_uuid": sender_uuid,
|
"sender_uuid": sender_uuid,
|
||||||
"message_type": "text",
|
"message_type": "text",
|
||||||
"mattermost_message_type": post.get("type", ""),
|
|
||||||
"text": msg,
|
"text": msg,
|
||||||
"url": None,
|
"url": None,
|
||||||
"created_at": created_at,
|
"created_at": created_at,
|
||||||
|
|
|
||||||
|
|
@ -1,63 +0,0 @@
|
||||||
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_keeps_chronological_order():
|
|
||||||
# Mattermost order is newest-first.
|
|
||||||
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_posts_includes_system_posts_with_raw_type():
|
|
||||||
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", "sys1"]
|
|
||||||
assert result[1]["type"] == "system_add_to_channel"
|
|
||||||
|
|
||||||
|
|
||||||
def test_get_latest_post_id_returns_newest_post_id():
|
|
||||||
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"
|
|
||||||
|
|
||||||
|
|
||||||
def test_get_latest_post_id_returns_none_when_empty():
|
|
||||||
client = _make_client({"order": [], "posts": {}})
|
|
||||||
|
|
||||||
assert client.get_latest_post_id("chan-1") is None
|
|
||||||
|
|
@ -91,13 +91,6 @@ def test_list_messages_normalized():
|
||||||
"message": f"voice:{object_key}",
|
"message": f"voice:{object_key}",
|
||||||
"create_at": 1700000001000,
|
"create_at": 1700000001000,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"id": "sys1",
|
|
||||||
"type": "system_add_to_channel",
|
|
||||||
"user_id": mm_user_id,
|
|
||||||
"message": "user-x added to the channel",
|
|
||||||
"create_at": 1700000002000,
|
|
||||||
},
|
|
||||||
]
|
]
|
||||||
|
|
||||||
download_url = "http://minio.local/chat/voice/def456/clip.ogg?X-Amz-Signature=..."
|
download_url = "http://minio.local/chat/voice/def456/clip.ogg?X-Amz-Signature=..."
|
||||||
|
|
@ -108,13 +101,12 @@ def test_list_messages_normalized():
|
||||||
|
|
||||||
messages = svc.list_messages(conv.uuid, page=0, per_page=20)
|
messages = svc.list_messages(conv.uuid, page=0, per_page=20)
|
||||||
|
|
||||||
assert len(messages) == 3
|
assert len(messages) == 2
|
||||||
|
|
||||||
text_msg = messages[0]
|
text_msg = messages[0]
|
||||||
assert text_msg["post_id"] == "p1"
|
assert text_msg["post_id"] == "p1"
|
||||||
assert text_msg["sender_uuid"] == sender_uuid
|
assert text_msg["sender_uuid"] == sender_uuid
|
||||||
assert text_msg["message_type"] == "text"
|
assert text_msg["message_type"] == "text"
|
||||||
assert text_msg["mattermost_message_type"] == ""
|
|
||||||
assert text_msg["text"] == "First message"
|
assert text_msg["text"] == "First message"
|
||||||
assert text_msg["url"] is None
|
assert text_msg["url"] is None
|
||||||
|
|
||||||
|
|
@ -122,17 +114,11 @@ def test_list_messages_normalized():
|
||||||
assert voice_msg["post_id"] == "p2"
|
assert voice_msg["post_id"] == "p2"
|
||||||
assert voice_msg["sender_uuid"] == sender_uuid
|
assert voice_msg["sender_uuid"] == sender_uuid
|
||||||
assert voice_msg["message_type"] == "voice"
|
assert voice_msg["message_type"] == "voice"
|
||||||
assert voice_msg["mattermost_message_type"] == ""
|
|
||||||
assert voice_msg["url"] == download_url
|
assert voice_msg["url"] == download_url
|
||||||
assert voice_msg["text"] is None
|
assert voice_msg["text"] is None
|
||||||
|
|
||||||
storage.get_download_url.assert_called_once_with(object_key)
|
storage.get_download_url.assert_called_once_with(object_key)
|
||||||
|
|
||||||
system_msg = messages[2]
|
|
||||||
assert system_msg["post_id"] == "sys1"
|
|
||||||
assert system_msg["sender_uuid"] == sender_uuid
|
|
||||||
assert system_msg["mattermost_message_type"] == "system_add_to_channel"
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
def test_list_messages_treats_colon_in_plain_text_as_text():
|
def test_list_messages_treats_colon_in_plain_text_as_text():
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue