git » sdk » commit decea9e

setSubject

author Stephen Paul Weber
2026-06-22 18:44:37 UTC
committer Stephen Paul Weber
2026-06-22 18:44:37 UTC
parent 0e879bc727d56705747201113af5cfa33391d0fe

setSubject

borogove/Chat.hx +27 -0
test/TestChat.hx +76 -0

diff --git a/borogove/Chat.hx b/borogove/Chat.hx
index 120b553..b4a8210 100644
--- a/borogove/Chat.hx
+++ b/borogove/Chat.hx
@@ -1576,6 +1576,33 @@ class Channel extends Chat {
 		return threads.get(null) ?? "";
 	}
 
+	/**
+		Can the user set the Channel subject?
+	**/
+	public function canSetSubject() {
+		if (self == null || disco == null) return false;
+
+		final it = self.presence.iterator();
+		if (!it.hasNext()) return false;
+
+		final subjectmod = (info()?.field("muc#roominfo_subjectmod")?.value ?? ["0"]).join("");
+		if (Stanza.parseXmlBool(subjectmod)) {
+			return true;
+		}
+
+		return it.next().mucUser.role == "moderator";
+	}
+
+	/**
+		Set the Channel subject, or subject of a thread
+	**/
+	public function setSubject(subject: String, threadId: Null<String> = null) {
+		final outboxItem = outbox.newItem();
+		final stanza = new Stanza("message", { to: chatId }).textTag("subject", subject);
+		if (threadId != null) stanza.textTag("thread", threadId);
+		sendMessageStanza(stanza, outboxItem);
+	}
+
 	/**
 		Description of this Channel
 	**/
diff --git a/test/TestChat.hx b/test/TestChat.hx
index 79be54d..8ea724f 100644
--- a/test/TestChat.hx
+++ b/test/TestChat.hx
@@ -307,6 +307,82 @@ class TestChat extends utest.Test {
 		Assert.isTrue(chat.canModerate());
 	}
 
+	public function testCanSetSubjectChannel() {
+		final persistence = new Dummy();
+		final client = new Client("test@example.com", persistence);
+		final chat = new borogove.Chat.Channel(client, client.stream, persistence, "channel@example.com");
+
+		// Default
+		Assert.isFalse(chat.canSetSubject());
+
+		// Self set but no disco
+		chat.self = new Member(
+			"me", "myself", null, true, [], JID.parse("test@example.com"),
+			["myself" => new borogove.Presence(null, new Stanza("x", { xmlns: "http://jabber.org/protocol/muc#user" }).tag("item", { role: "participant" }).up(), null)],
+			null
+		);
+		Assert.isFalse(chat.canSetSubject());
+
+		chat.disco = new borogove.Caps("", [], [], []);
+
+		// Is participant, subjectmod not set
+		Assert.isFalse(chat.canSetSubject());
+
+		// Is moderator, subjectmod not set
+		chat.self = new Member(
+			"me", "myself", null, true, [], JID.parse("test@example.com"),
+			["myself" => new borogove.Presence(null, new Stanza("x", { xmlns: "http://jabber.org/protocol/muc#user" }).tag("item", { role: "moderator" }).up(), null)],
+			null
+		);
+		Assert.isTrue(chat.canSetSubject());
+
+		// Is participant, subjectmod set
+		chat.self = new Member(
+			"me", "myself", null, true, [], JID.parse("test@example.com"),
+			["myself" => new borogove.Presence(null, new Stanza("x", { xmlns: "http://jabber.org/protocol/muc#user" }).tag("item", { role: "participant" }).up(), null)],
+			null
+		);
+		chat.disco = new borogove.Caps("", [], [], [new Stanza("x", { xmlns: "jabber:x:data", type: "result" }).tag("field", { "var": "FORM_TYPE", type: "hidden" }).textTag("value", "http://jabber.org/protocol/muc#roominfo").up().tag("field", { "var": "muc#roominfo_subjectmod" }).textTag("value", "1").up()]);
+		Assert.isTrue(chat.canSetSubject());
+	}
+
+	public function testSetSubject(async: Async) {
+		final persistence = new Dummy();
+		final client = new Client("test@example.com", persistence);
+		final chat = new borogove.Chat.Channel(client, client.stream, persistence, "channel@example.com");
+
+		client.stream.on("sendStanza", (stanza: Stanza) -> {
+			if (stanza.name == "message" && stanza.attr.get("to") == "channel@example.com") {
+				Assert.equals("New Subject", stanza.getChild("subject").getText());
+				async.done();
+				return EventHandled;
+			}
+			return EventUnhandled;
+		});
+
+		chat.outbox.start();
+		chat.setSubject("New Subject");
+	}
+
+	public function testSetSubjectThread(async: Async) {
+		final persistence = new Dummy();
+		final client = new Client("test@example.com", persistence);
+		final chat = new borogove.Chat.Channel(client, client.stream, persistence, "channel@example.com");
+
+		client.stream.on("sendStanza", (stanza: Stanza) -> {
+			if (stanza.name == "message" && stanza.attr.get("to") == "channel@example.com") {
+				Assert.equals("New Thread Subject", stanza.getChild("subject").getText());
+				Assert.equals("thread123", stanza.getChild("thread").getText());
+				async.done();
+				return EventHandled;
+			}
+			return EventUnhandled;
+		});
+
+		chat.outbox.start();
+		chat.setSubject("New Thread Subject", "thread123");
+	}
+
 	public function testJoinFailure() {
 		final persistence = new Dummy();
 		final client = new Client("test@example.com", persistence);