diff --git a/examples/README.md b/examples/README.md index 95de200..5eaf8cf 100644 --- a/examples/README.md +++ b/examples/README.md @@ -15,6 +15,8 @@ Build something cool with these nodes? Feel free to submit a pull request to sha - [Respond to "image" with an uploaded image](#respond-to-image-with-an-uploaded-image) - [Respond to "file" with an uploaded file](#respond-to-file-with-an-uploaded-file) - [Respond to "react" with a reaction](#respond-to-react-with-a-reaction) +- [Accept room invites from specific user](#accept-room-invites-from-specific-user) +- [Leave room when someone says "bye"](#leave-room-when-someone-says-bye) - [Remove messages containing "delete"](#remove-messages-containing-delete) - [Respond to "users" with full list of server users](#respond-to-users-with-full-list-of-server-users) - [Respond to "newroom" by creating new room and inviting user](#respond-to-newroom-by-creating-new-room-and-inviting-user) @@ -113,6 +115,26 @@ Give a 👍 reaction when someone says "react" +### Accept room invites from specific user + +[View JSON](accept-room-invites.json) + +Accept room invites from specific user. + +![accept-room-invites.png](accept-room-invites.png) + + + +### Leave room when someone says bye + +[View JSON](leave-room-bye.json) + +Leave room when someone says "bye". + +![leave-room-bye.png](leave-room-bye.png) + + + ### Remove messages containing "delete" [View JSON](delete-event.json) diff --git a/examples/accept-room-invites.json b/examples/accept-room-invites.json new file mode 100644 index 0000000..d853c6e --- /dev/null +++ b/examples/accept-room-invites.json @@ -0,0 +1,94 @@ +[ + { + "id": "64f76474ff7a3727", + "type": "matrix-room-invite", + "z": "f025a8b9fbd1b054", + "name": "", + "server": "8da0ef83f77f8e24", + "roomId": null, + "x": 270, + "y": 2380, + "wires": [ + [ + "22f6056fa5bc5bd0" + ] + ] + }, + { + "id": "6d6f304a0a6342b8", + "type": "matrix-join-room", + "z": "f025a8b9fbd1b054", + "name": "", + "server": "8da0ef83f77f8e24", + "x": 770, + "y": 2380, + "wires": [ + [ + "1409ebb4a0e65663" + ], + [ + "1409ebb4a0e65663" + ] + ] + }, + { + "id": "22f6056fa5bc5bd0", + "type": "switch", + "z": "f025a8b9fbd1b054", + "name": "msg.userId == @skylord123:skylar.tech", + "property": "userId", + "propertyType": "msg", + "rules": [ + { + "t": "eq", + "v": "@skylord123:skylar.tech", + "vt": "str" + } + ], + "checkall": "true", + "repair": false, + "outputs": 1, + "x": 520, + "y": 2380, + "wires": [ + [ + "6d6f304a0a6342b8" + ] + ] + }, + { + "id": "043f74e6d76b1eb0", + "type": "comment", + "z": "f025a8b9fbd1b054", + "name": "Only accept room invites from specific user", + "info": "", + "x": 360, + "y": 2340, + "wires": [] + }, + { + "id": "1409ebb4a0e65663", + "type": "debug", + "z": "f025a8b9fbd1b054", + "name": "", + "active": true, + "tosidebar": true, + "console": false, + "tostatus": false, + "complete": "true", + "targetType": "full", + "statusVal": "", + "statusType": "auto", + "x": 910, + "y": 2380, + "wires": [] + }, + { + "id": "8da0ef83f77f8e24", + "type": "matrix-server-config", + "name": null, + "autoAcceptRoomInvites": false, + "enableE2ee": true, + "global": true + } +] \ No newline at end of file diff --git a/examples/accept-room-invites.png b/examples/accept-room-invites.png new file mode 100644 index 0000000..9ba8369 Binary files /dev/null and b/examples/accept-room-invites.png differ diff --git a/examples/leave-room-bye.json b/examples/leave-room-bye.json new file mode 100644 index 0000000..ba054a6 --- /dev/null +++ b/examples/leave-room-bye.json @@ -0,0 +1,103 @@ +[ + { + "id": "997c354038202dba", + "type": "comment", + "z": "f025a8b9fbd1b054", + "name": "Leave room when someone says \"bye\"", + "info": "", + "x": 350, + "y": 2520, + "wires": [] + }, + { + "id": "69c4ea189be94feb", + "type": "matrix-receive", + "z": "f025a8b9fbd1b054", + "name": "", + "server": "8da0ef83f77f8e24", + "roomId": "", + "acceptText": true, + "acceptEmotes": true, + "acceptStickers": true, + "acceptReactions": true, + "acceptFiles": true, + "acceptAudio": true, + "acceptImages": true, + "acceptLocations": true, + "x": 280, + "y": 2560, + "wires": [ + [ + "19e1d64b63ae8a1f" + ] + ] + }, + { + "id": "19e1d64b63ae8a1f", + "type": "switch", + "z": "f025a8b9fbd1b054", + "name": "msg.payload == bye", + "property": "payload", + "propertyType": "msg", + "rules": [ + { + "t": "eq", + "v": "bye", + "vt": "str" + } + ], + "checkall": "true", + "repair": false, + "outputs": 1, + "x": 480, + "y": 2560, + "wires": [ + [ + "db0e51f8e7793f92" + ] + ] + }, + { + "id": "db0e51f8e7793f92", + "type": "matrix-leave-room", + "z": "f025a8b9fbd1b054", + "name": "", + "server": "8da0ef83f77f8e24", + "roomId": null, + "x": 670, + "y": 2560, + "wires": [ + [ + "3791f551bf0e4fc4" + ], + [ + "3791f551bf0e4fc4" + ] + ] + }, + { + "id": "3791f551bf0e4fc4", + "type": "debug", + "z": "f025a8b9fbd1b054", + "name": "", + "active": true, + "tosidebar": true, + "console": false, + "tostatus": false, + "complete": "true", + "targetType": "full", + "statusVal": "", + "statusType": "auto", + "x": 810, + "y": 2560, + "wires": [] + }, + { + "id": "8da0ef83f77f8e24", + "type": "matrix-server-config", + "name": null, + "autoAcceptRoomInvites": false, + "enableE2ee": true, + "global": true + } +] \ No newline at end of file diff --git a/examples/leave-room-bye.png b/examples/leave-room-bye.png new file mode 100644 index 0000000..7ad5cdf Binary files /dev/null and b/examples/leave-room-bye.png differ diff --git a/package.json b/package.json index fe6ba09..789f9a5 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,9 @@ "matrix-react": "src/matrix-react.js", "matrix-create-room": "src/matrix-create-room.js", "matrix-invite-room": "src/matrix-invite-room.js", + "matrix-room-invite": "src/matrix-room-invite.js", "matrix-join-room": "src/matrix-join-room.js", + "matrix-leave-room": "src/matrix-leave-room.js", "matrix-crypt-file": "src/matrix-crypt-file.js", "matrix-room-kick": "src/matrix-room-kick.js", "matrix-room-ban": "src/matrix-room-ban.js", diff --git a/src/matrix-invite-room.html b/src/matrix-invite-room.html index 1294d16..20f49d1 100644 --- a/src/matrix-invite-room.html +++ b/src/matrix-invite-room.html @@ -12,9 +12,9 @@ roomId: { value: null }, }, label: function() { - return this.name || "Room Invite"; + return this.name || "Invite to Room"; }, - paletteLabel: 'Room Invite' + paletteLabel: 'Invite to Room' }); diff --git a/src/matrix-leave-room.html b/src/matrix-leave-room.html new file mode 100644 index 0000000..4795c66 --- /dev/null +++ b/src/matrix-leave-room.html @@ -0,0 +1,63 @@ + + + + + \ No newline at end of file diff --git a/src/matrix-leave-room.js b/src/matrix-leave-room.js new file mode 100644 index 0000000..f69877d --- /dev/null +++ b/src/matrix-leave-room.js @@ -0,0 +1,54 @@ +module.exports = function(RED) { + function MatrixLeaveRoom(n) { + RED.nodes.createNode(this, n); + + let node = this; + + this.name = n.name; + this.server = RED.nodes.getNode(n.server); + this.roomId = n.roomId; + + node.status({ fill: "red", shape: "ring", text: "disconnected" }); + + if (!node.server) { + node.error("No configuration node"); + return; + } + + node.server.on("disconnected", function(){ + node.status({ fill: "red", shape: "ring", text: "disconnected" }); + }); + + node.server.on("connected", function() { + node.status({ fill: "green", shape: "ring", text: "connected" }); + }); + + node.on('input', function(msg) { + if (! node.server || ! node.server.matrixClient) { + node.error("No matrix server selected"); + return; + } + + if(!msg.topic) { + node.error('No room provided in msg.topic'); + return; + } + + if(!node.server.isConnected()) { + node.error("Matrix server connection is currently closed"); + node.send([null, msg]); + } + + try { + node.log("Leaving room " + msg.topic); + node.server.matrixClient.leave(msg.topic); + node.send([msg, null]); + } catch(e) { + node.error("Failed to leave room " + msg.topic + ": " + e); + msg.payload = e; + node.send([null, msg]); + } + }); + } + RED.nodes.registerType("matrix-leave-room", MatrixLeaveRoom); +} \ No newline at end of file diff --git a/src/matrix-receive.js b/src/matrix-receive.js index 27c7ce9..f69225b 100644 --- a/src/matrix-receive.js +++ b/src/matrix-receive.js @@ -32,12 +32,6 @@ module.exports = function(RED) { node.status({ fill: "green", shape: "ring", text: "connected" }); }); - - node.server.on("Room.invite", async function(msg) { - node.send(msg); - }); - - node.server.on("Room.timeline", async function(event, room, toStartOfTimeline, removed, data, msg) { // if node has a room ID set we only listen on that room if(node.roomIds.length && node.roomIds.indexOf(room.roomId) === -1) { diff --git a/src/matrix-room-invite.html b/src/matrix-room-invite.html new file mode 100644 index 0000000..79c9c39 --- /dev/null +++ b/src/matrix-room-invite.html @@ -0,0 +1,80 @@ + + + + + \ No newline at end of file diff --git a/src/matrix-room-invite.js b/src/matrix-room-invite.js new file mode 100644 index 0000000..9c7edf5 --- /dev/null +++ b/src/matrix-room-invite.js @@ -0,0 +1,31 @@ +module.exports = function(RED) { + function MatrixRoomInvite(n) { + RED.nodes.createNode(this, n); + + let node = this; + + this.name = n.name; + this.server = RED.nodes.getNode(n.server); + this.roomId = n.roomId; + + if(!this.server) { + node.error('Server must be configured on the node.'); + return; + } + + node.status({ fill: "red", shape: "ring", text: "disconnected" }); + + node.server.on("disconnected", function(){ + node.status({ fill: "red", shape: "ring", text: "disconnected" }); + }); + + node.server.on("connected", function() { + node.status({ fill: "green", shape: "ring", text: "connected" }); + }); + + node.server.on("Room.invite", async function(msg) { + node.send(msg); + }); + } + RED.nodes.registerType("matrix-room-invite", MatrixRoomInvite); +} \ No newline at end of file diff --git a/src/matrix-server-config.js b/src/matrix-server-config.js index 61ea712..0bf3e30 100644 --- a/src/matrix-server-config.js +++ b/src/matrix-server-config.js @@ -251,23 +251,30 @@ module.exports = function(RED) { // handle auto-joining rooms node.matrixClient.on(RoomMemberEvent.Membership, async function(event, member) { + if(node.initializedAt > event.getDate()) { + return; // skip events that occurred before our client initialized + } + if (member.membership === "invite" && member.userId === node.userId) { + node.log("Got invite to join room " + member.roomId); + console.log(event); if(node.autoAcceptRoomInvites) { node.matrixClient.joinRoom(member.roomId).then(function() { node.log("Automatically accepted invitation to join room " + member.roomId); }).catch(function(e) { node.warn("Cannot join room (could be from being kicked/banned) " + member.roomId + ": " + e); }); - } else { - node.log("Got invite to join room " + member.roomId); - let msg = { - type : 'r.invite', - payload : 'Invitation', - userId : member.userId, - topic : member.roomId - }; - node.emit("Room.invite", msg); } + + let room = node.matrixClient.getRoom(event.getRoomId()); + node.emit("Room.invite", { + type : 'm.room.member', + userId : event.getSender(), + topic : event.getRoomId(), + topicName : (room ? room.name : null) || null, + event : event, + eventId : event.getId(), + }); } });