From e081360a842752638851bcf874bd03ab2a59e84e Mon Sep 17 00:00:00 2001 From: "david.delagneau" Date: Tue, 19 May 2026 16:35:24 -0600 Subject: [PATCH] feat: enhance Mattermost mirror with direct-message and group DM labeling for improved clarity --- scripts/mattermost-proxy/README.md | 6 +++ scripts/mattermost-proxy/mattermost_mirror.py | 45 ++++++++++++++++++- 2 files changed, 50 insertions(+), 1 deletion(-) diff --git a/scripts/mattermost-proxy/README.md b/scripts/mattermost-proxy/README.md index fb5c2be..3a7567b 100644 --- a/scripts/mattermost-proxy/README.md +++ b/scripts/mattermost-proxy/README.md @@ -69,6 +69,12 @@ and `threads/...` when a single discussion thread is the relevant evidence. This mirrors Slack's export pattern of one folder per conversation with one file per date, while adding Mattermost-specific thread views. +Direct-message channels are labeled as `dm---` when the mirror +has seen enough user metadata to resolve the Mattermost channel ID. Group DMs +use `group-...`. If a DM was first captured before the relevant user metadata +arrived, the folder can temporarily use raw IDs; later captures use the readable +label and `refs/channels.json` remains the source for resolving channel IDs. + The mirror writes any post payload it sees, including older messages returned when the desktop app loads channel history or a thread. It dedupes by `post_id`, so scrolling back through useful history is a safe way to backfill missing local diff --git a/scripts/mattermost-proxy/mattermost_mirror.py b/scripts/mattermost-proxy/mattermost_mirror.py index f1c23cb..1093969 100644 --- a/scripts/mattermost-proxy/mattermost_mirror.py +++ b/scripts/mattermost-proxy/mattermost_mirror.py @@ -61,6 +61,7 @@ class MattermostMirror: self.seen_by_file: dict[Path, set[str]] = {} self.users: dict[str, str] = {} self.channels: dict[str, str] = {} + self.channel_meta: dict[str, dict[str, Any]] = {} self.state: dict[str, Any] = {"channels": {}, "users": {}, "updated_at": None} self._ensure_dirs() @@ -80,6 +81,7 @@ class MattermostMirror: try: self.state = json.loads(self.state_path.read_text(encoding="utf-8")) self.users = dict(self.state.get("users") or {}) + self.channel_meta = dict(self.state.get("channel_meta") or {}) for channel_id, value in (self.state.get("channels") or {}).items(): if isinstance(value, dict): name = value.get("channel_name") or value.get("name") @@ -205,10 +207,48 @@ class MattermostMirror: channel_id = channel.get("id") if not channel_id: return - name = channel.get("name") or channel.get("display_name") or channel_id + self.channel_meta[channel_id] = channel + name = self._channel_label(channel) self.channels[channel_id] = name self._write_refs() + def _user_label(self, user_id: str | None) -> str | None: + if not user_id: + return None + return self.users.get(user_id) or user_id + + def _channel_label(self, channel: dict[str, Any]) -> str: + channel_id = channel.get("id") or "unknown-channel" + channel_type = channel.get("type") + display_name = (channel.get("display_name") or "").strip() + name = (channel.get("name") or "").strip() + + if channel_type == "D": + user_ids = [item for item in name.split("__") if item] + labels = [self._user_label(user_id) or user_id for user_id in user_ids] + if labels: + return "dm-" + "--".join(labels) + + if channel_type == "G": + if display_name: + return "group-" + display_name + user_ids = [item for item in name.split("__") if item] + labels = [self._user_label(user_id) or user_id for user_id in user_ids] + if labels: + return "group-" + "--".join(labels) + + return display_name or name or channel_id + + def _refresh_channel_labels(self) -> None: + changed = False + for channel_id, meta in self.channel_meta.items(): + label = self._channel_label(meta) + if label and self.channels.get(channel_id) != label: + self.channels[channel_id] = label + changed = True + if changed: + self._write_refs() + def _write_refs(self) -> None: users_path = self.refs_dir / "users.json" channels_path = self.refs_dir / "channels.json" @@ -244,6 +284,8 @@ class MattermostMirror: if isinstance(channel, dict): self._remember_channel(channel) + self._refresh_channel_labels() + def _normalize_post(self, post: dict[str, Any], source: str, raw_event: str | None = None) -> dict[str, Any] | None: post_id = post.get("id") channel_id = post.get("channel_id") @@ -311,6 +353,7 @@ class MattermostMirror: entry["last_seen_create_at"] = max(int(entry.get("last_seen_create_at") or 0), int(msg.get("created_at_ms") or 0)) entry["last_seen_post_id"] = msg.get("post_id") self.state["users"] = self.users + self.state["channel_meta"] = self.channel_meta self.state["updated_at"] = datetime.now(timezone.utc).isoformat() self._atomic_write_text(self.state_path, json.dumps(self.state, ensure_ascii=False, indent=2, sort_keys=True) + "\n") self._write_refs()