git » sdk » commit af3c0c0

Helper to get moderation reason

author Stephen Paul Weber
2026-04-21 02:24:59 UTC
committer Stephen Paul Weber
2026-04-21 02:24:59 UTC
parent 78aaef98cd175d38886b430369392229bc9c74e4

Helper to get moderation reason

borogove/ChatMessage.hx +8 -0
test/TestClient.hx +74 -0

diff --git a/borogove/ChatMessage.hx b/borogove/ChatMessage.hx
index 5b6454e..8564975 100644
--- a/borogove/ChatMessage.hx
+++ b/borogove/ChatMessage.hx
@@ -453,6 +453,14 @@ class ChatMessage {
 		return threadId == null ? null : Identicon.svg(threadId);
 	}
 
+	/**
+		If message is moderated, the reason
+	**/
+	public function moderationReason(): Null<String> {
+		final retracted = payloads.find((el) -> el.attr.get("xmlns") == "urn:xmpp:message-retract:1");
+		return retracted == null ? null : retracted.getChildText("reason") ?? "moderated";
+	}
+
 	/**
 		The last status of the call if this message is related to a call
 	**/
diff --git a/test/TestClient.hx b/test/TestClient.hx
index ba6fae8..0b48b24 100644
--- a/test/TestClient.hx
+++ b/test/TestClient.hx
@@ -10,6 +10,7 @@ import borogove.ChatMessageBuilder;
 import borogove.Client;
 import borogove.JID;
 import borogove.Message;
+import borogove.ModerationAction;
 import borogove.Stanza;
 import borogove.persistence.Dummy;
 
@@ -23,6 +24,58 @@ class TestClient extends utest.Test {
 		Assert.equals("test@example.com", client.accountId());
 	}
 
+	public function testModerateMessage(async: Async) {
+		final persistence = new MessageMockPersistence();
+		final client = new Client("test@example.com", persistence);
+		final chatId = "chat@example.com";
+		final serverId = "msg123";
+
+		// Pre-populate persistence with a message
+		final builder = new ChatMessageBuilder();
+		builder.serverId = serverId;
+		builder.from = JID.parse("other@example.com");
+		builder.to = JID.parse("test@example.com");
+		builder.senderId = "other@example.com";
+		builder.text = "to be moderated";
+		final originalMessage = builder.build();
+
+		persistence.storeMessages(client.accountId(), [originalMessage]).then((_) -> {
+			final action = new ModerationAction(chatId, serverId, "2023-01-01T00:00:00Z", "mod@example.com", "Spam");
+
+			client.moderateMessage(action).then((moderatedMessage) -> {
+				Assert.notNull(moderatedMessage);
+				Assert.equals("Spam", moderatedMessage.moderationReason());
+				async.done();
+			});
+		});
+	}
+
+	public function testModerateMessageNoReason(async: Async) {
+		final persistence = new MessageMockPersistence();
+		final client = new Client("test@example.com", persistence);
+		final chatId = "chat@example.com";
+		final serverId = "msg124";
+
+		// Pre-populate persistence with a message
+		final builder = new ChatMessageBuilder();
+		builder.serverId = serverId;
+		builder.from = JID.parse("other@example.com");
+		builder.to = JID.parse("test@example.com");
+		builder.senderId = "other@example.com";
+		builder.text = "to be moderated";
+		final originalMessage = builder.build();
+
+		persistence.storeMessages(client.accountId(), [originalMessage]).then((_) -> {
+			final action = new ModerationAction(chatId, serverId, "2023-01-01T00:00:00Z", "mod@example.com", null);
+
+			client.moderateMessage(action).then((moderatedMessage) -> {
+				Assert.notNull(moderatedMessage);
+				Assert.equals("moderated", moderatedMessage.moderationReason());
+				async.done();
+			});
+		});
+	}
+
 	public function testDefaultDisplayName() {
 		final persistence = new Dummy();
 		final client = new Client("test@example.com", persistence);
@@ -413,3 +466,24 @@ class MockPersistence extends Dummy {
 		return Promise.resolve(builder.build());
 	}
 }
+
+@:access(borogove)
+class MessageMockPersistence extends Dummy {
+	public var messages: Map<String, ChatMessage> = [];
+	public function new() { super(); }
+
+	override public function storeMessages(accountId: String, messages: Array<ChatMessage>): Promise<Array<ChatMessage>> {
+		for (m in messages) {
+			if (m.serverId != null) this.messages.set(m.serverId, m);
+		}
+		return Promise.resolve(messages);
+	}
+
+	override public function getMessage(accountId: String, chatId: String, serverId: Null<String>, localId: Null<String>): Promise<Null<ChatMessage>> {
+		return Promise.resolve(serverId != null ? messages.get(serverId) : null);
+	}
+
+	override public function updateMessage(accountId: String, message: ChatMessage) {
+		if (message.serverId != null) this.messages.set(message.serverId, message);
+	}
+}