| author | Stephen Paul Weber
<singpolyma@singpolyma.net> 2026-06-22 18:44:37 UTC |
| committer | Stephen Paul Weber
<singpolyma@singpolyma.net> 2026-06-22 18:44:37 UTC |
| parent | 0e879bc727d56705747201113af5cfa33391d0fe |
| 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);