Compare commits

...

6 Commits

Author SHA1 Message Date
fd605005d1 Closes #99
- matrix-server-config now auto populates with first option
2023-10-21 19:47:12 -06:00
85de450a1a
Merge pull request #98 from Skylar-Tech/97-room-settings
97 room settings
2023-10-21 19:43:29 -06:00
e7e0f2967b Issue #97 Room Settings
- Remove unused returnValues config option for Room State Events node
2023-10-21 19:39:32 -06:00
611e23b845 Issue #97 Room Settings
- Room Settings node renamed to Room State Events
- Room State Events node allows configuring inputs/outputs from config
- Fix bug with various nodes allowing execution even though matrix server isn't connected
- Replace deprecated matrixClient.setGlobalErrorOnUnknownDevices method
- Update docs for new Room State Events node
2023-10-21 19:33:44 -06:00
9d050a0d44 Issue #97 Room Settings
- fix join_allow_rules for Room Setting node not getting correctly
- update Room Setting docs
2023-10-15 14:45:16 -06:00
c833a40a84 Issue #97 Room Settings
- Can set room name, topic, and avatar
- Can get name, topic, avatar, encrypted, power_levels, aliases, guest_access, join_rule, and join_allow_rules
2023-10-15 04:17:12 -06:00
38 changed files with 652 additions and 22 deletions

View File

@ -32,13 +32,14 @@
"matrix-crypt-file": "src/matrix-crypt-file.js", "matrix-crypt-file": "src/matrix-crypt-file.js",
"matrix-room-kick": "src/matrix-room-kick.js", "matrix-room-kick": "src/matrix-room-kick.js",
"matrix-room-ban": "src/matrix-room-ban.js", "matrix-room-ban": "src/matrix-room-ban.js",
"matrix-room-users": "src/matrix-room-users.js",
"matrix-room-state-events": "src/matrix-room-state-events.js",
"matrix-synapse-users": "src/matrix-synapse-users.js", "matrix-synapse-users": "src/matrix-synapse-users.js",
"matrix-synapse-register": "src/matrix-synapse-register.js", "matrix-synapse-register": "src/matrix-synapse-register.js",
"matrix-synapse-create-edit-user": "src/matrix-synapse-create-edit-user.js", "matrix-synapse-create-edit-user": "src/matrix-synapse-create-edit-user.js",
"matrix-synapse-deactivate-user": "src/matrix-synapse-deactivate-user.js", "matrix-synapse-deactivate-user": "src/matrix-synapse-deactivate-user.js",
"matrix-synapse-join-room": "src/matrix-synapse-join-room.js", "matrix-synapse-join-room": "src/matrix-synapse-join-room.js",
"matrix-whois-user": "src/matrix-whois-user.js", "matrix-whois-user": "src/matrix-whois-user.js"
"matrix-room-users": "src/matrix-room-users.js"
} }
}, },
"engines": { "engines": {

View File

@ -8,7 +8,7 @@
outputs: 2, outputs: 2,
defaults: { defaults: {
name: { value: null }, name: { value: null },
server: { value: "", type: "matrix-server-config" } server: { type: "matrix-server-config" }
}, },
label: function() { label: function() {
return this.name || "Create Room"; return this.name || "Create Room";

View File

@ -44,6 +44,7 @@ module.exports = function(RED) {
if(!node.server.isConnected()) { if(!node.server.isConnected()) {
node.error("Matrix server connection is currently closed", msg); node.error("Matrix server connection is currently closed", msg);
node.send([null, msg]); node.send([null, msg]);
return;
} }
if(!msg.payload) { if(!msg.payload) {

View File

@ -8,7 +8,7 @@
outputs:2, outputs:2,
defaults: { defaults: {
name: { value: null }, name: { value: null },
server: { value: "", type: "matrix-server-config" }, server: { type: "matrix-server-config" },
roomId: { value: null }, roomId: { value: null },
reason: { value: "" }, reason: { value: "" },
}, },

View File

@ -8,7 +8,7 @@
outputs: 2, outputs: 2,
defaults: { defaults: {
name: { value: null }, name: { value: null },
server: { value: "", type: "matrix-server-config" }, server: { type: "matrix-server-config" },
roomId: { value: null }, roomId: { value: null },
}, },
label: function() { label: function() {

View File

@ -45,6 +45,7 @@ module.exports = function(RED) {
if(!node.server.isConnected()) { if(!node.server.isConnected()) {
node.error("Matrix server connection is currently closed", msg); node.error("Matrix server connection is currently closed", msg);
node.send([null, msg]); node.send([null, msg]);
return;
} }
msg.topic = node.roomId || msg.topic; msg.topic = node.roomId || msg.topic;

View File

@ -8,7 +8,7 @@
outputs:2, outputs:2,
defaults: { defaults: {
name: { value: null }, name: { value: null },
server: { value: "", type: "matrix-server-config" } server: { type: "matrix-server-config" }
}, },
label: function() { label: function() {
return this.name || "Join Room"; return this.name || "Join Room";

View File

@ -32,6 +32,7 @@ module.exports = function(RED) {
if(!node.server.isConnected()) { if(!node.server.isConnected()) {
node.error("Matrix server connection is currently closed", msg); node.error("Matrix server connection is currently closed", msg);
node.send([null, msg]); node.send([null, msg]);
return;
} }
if(!msg.topic) { if(!msg.topic) {

View File

@ -8,7 +8,7 @@
outputs: 2, outputs: 2,
defaults: { defaults: {
name: { value: null }, name: { value: null },
server: { value: "", type: "matrix-server-config" }, server: { type: "matrix-server-config" },
roomId: { value: null }, roomId: { value: null },
}, },
label: function() { label: function() {

View File

@ -38,6 +38,7 @@ module.exports = function(RED) {
if(!node.server.isConnected()) { if(!node.server.isConnected()) {
node.error("Matrix server connection is currently closed", msg); node.error("Matrix server connection is currently closed", msg);
node.send([null, msg]); node.send([null, msg]);
return;
} }
try { try {

View File

@ -8,7 +8,7 @@
outputs:2, outputs:2,
defaults: { defaults: {
name: { value: null }, name: { value: null },
server: { value: "", type: "matrix-server-config" }, server: { type: "matrix-server-config" },
roomId: { value: null }, roomId: { value: null },
reaction: { value: null } reaction: { value: null }
}, },

View File

@ -34,6 +34,7 @@ module.exports = function(RED) {
if(!node.server.isConnected()) { if(!node.server.isConnected()) {
node.error("Matrix server connection is currently closed", msg); node.error("Matrix server connection is currently closed", msg);
node.send([null, msg]); node.send([null, msg]);
return;
} }
msg.topic = node.roomId || msg.topic; msg.topic = node.roomId || msg.topic;

View File

@ -8,7 +8,7 @@
outputs:1, outputs:1,
defaults: { defaults: {
name: { value: null }, name: { value: null },
server: { value: "", type: "matrix-server-config" }, server: { type: "matrix-server-config" },
roomId: {"value": null}, roomId: {"value": null},
acceptText: {"value": true}, acceptText: {"value": true},
acceptEmotes: {"value": true}, acceptEmotes: {"value": true},

View File

@ -8,7 +8,7 @@
outputs:2, outputs:2,
defaults: { defaults: {
name: { value: null }, name: { value: null },
server: { value: "", type: "matrix-server-config" }, server: { type: "matrix-server-config" },
roomId: { value: null }, roomId: { value: null },
reason: { value: null } reason: { value: null }
}, },

View File

@ -34,6 +34,7 @@ module.exports = function(RED) {
if(!node.server.isConnected()) { if(!node.server.isConnected()) {
node.error("Matrix server connection is currently closed", msg); node.error("Matrix server connection is currently closed", msg);
node.send([null, msg]); node.send([null, msg]);
return;
} }
msg.topic = node.roomId || msg.topic; msg.topic = node.roomId || msg.topic;

View File

@ -8,7 +8,7 @@
outputs: 1, outputs: 1,
defaults: { defaults: {
name: { value: null }, name: { value: null },
server: { value: "", type: "matrix-server-config" }, server: { type: "matrix-server-config" },
roomId: { value: null }, roomId: { value: null },
}, },
label: function() { label: function() {

View File

@ -8,7 +8,7 @@
outputs:2, outputs:2,
defaults: { defaults: {
name: { value: null }, name: { value: null },
server: { value: "", type: "matrix-server-config" }, server: { type: "matrix-server-config" },
roomId: { value: null }, roomId: { value: null },
reason: { value: null } reason: { value: null }
}, },

View File

@ -34,6 +34,7 @@ module.exports = function(RED) {
if(!node.server.isConnected()) { if(!node.server.isConnected()) {
node.error("Matrix server connection is currently closed", msg); node.error("Matrix server connection is currently closed", msg);
node.send([null, msg]); node.send([null, msg]);
return;
} }
msg.topic = node.roomId || msg.topic; msg.topic = node.roomId || msg.topic;

View File

@ -0,0 +1,342 @@
<script type="text/html" data-template-name="matrix-room-state-events">
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
<input type="text" id="node-input-name" placeholder="Name">
</div>
<div class="form-row">
<label for="node-input-server"><i class="fa fa-user"></i> Matrix Server Config</label>
<input type="text" id="node-input-server">
</div>
<div class="form-row">
<label for="node-input-roomId"><i class="fa fa-comments"></i> Room ID</label>
<input type="text" id="node-input-roomId" placeholder="msg.topic">
<pre class="form-tips" id="node-input-roomId-error" style="color: #721c24;background-color: #f8d7da;border-color: #f5c6cb;margin-bottom: 12px;margin-top: 12px;display:none;"></pre>
</div>
<div class="form-row" style="margin-bottom:0;">
<label><i class="fa fa-list"></i> <span data-i18n="change.label.rules"></span></label>
</div>
<div class="form-row node-input-rule-container-row">
<ol id="node-input-rule-container"></ol>
</div>
<script type="text/javascript">
$(function(){
$("#node-input-roomId").on("keyup", function() {
if($(this).val() && !$(this).val().startsWith("!")) {
$("#node-input-roomId-error").html(`Room IDs start with exclamation point "!"<br />Example: !OGEhHVWSdvArJzumhm:matrix.org`).show();
} else {
$("#node-input-roomId-error").hide();
}
}).trigger('keyup');
});
</script>
</script>
<script type="text/html" data-help-name="matrix-room-state-events">
<h3>Details</h3>
<p>
Set and Get a list of room state events for a given room. Allows you to set/get room name, topic, avatar, etc.
</p>
<h3>Inputs</h3>
<dl class="message-properties">
<dt class="optional">msg.topic
<span class="property-type">string | null</span>
</dt>
<dd> The room to set/get settings for.</dd>
<dt class="optional">dynamic
<span class="property-type">string|object</span>
</dt>
<dd> You configure what room state events in the node configuration. <code style="white-space: normal;">m.room.name</code>, <code style="white-space: normal;">m.room.avatar</code>, and <code style="white-space: normal;">m.room.guest_access</code> allow you to pass a string to set their value but all other room state events will require the full content object (find this by referencing the <a href="https://spec.matrix.org/latest/client-server-api" target="_blank">Matrix Client-Server docs</a>)</dd>
</dl>
<h3>Outputs</h3>
<ol class="node-ports">
<li>Success
<dl class="message-properties">
<dt>msg <span class="property-type">object</span></dt>
<dd>Original message object with modifications based on config.</dd>
</dl>
<dl class="message-properties">
<dt>msg.setter_errors <span class="property-type">undefined|object</span></dt>
<dd>Returned if setting a room state event failed. The key of the object is the room state event type and the value is the error that occurred.</dd>
</dl>
<dl class="message-properties">
<dt>msg.getter_errors <span class="property-type">undefined|object</span></dt>
<dd>Returned if getting a room state event failed. The key of the object is the room state event type and the value is the error that occurred. Note that you will get an error if you try getting a room state event that doesn't exist (such as fetching avatar on a room that doesn't have one).</dd>
</dl>
<dt class="optional">dynamic
<span class="property-type">string|object</span>
</dt>
<dd> You configure what room state events to output in the node configuration. <code style="white-space: normal;">m.room.name</code>, <code style="white-space: normal;">m.room.avatar</code>, and <code style="white-space: normal;">m.room.guest_access</code> will come back as strings otherwise you will get the full content object of the event (find this by referencing the <a href="https://spec.matrix.org/latest/client-server-api" target="_blank">Matrix Client-Server docs</a>)</dd>
</li>
</ol>
</script>
<script type="text/javascript">
(function(){
var roomEventTypeOptions = [
{ value: "m.room.name", label: "m.room.name"},
{ value: "m.room.topic", label: "m.room.topic"},
{ value: "m.room.avatar", label: "m.room.avatar"},
{ value: "m.room.power_levels", label: "m.room.power_levels"},
{ value: "m.room.guest_access", label: "m.room.guest_access"},
{ value: "m.room.join_rules", label: "m.room.join_rules"},
{ value: "m.room.canonical_alias", label: "m.room.canonical_alias"}
];
var defaultRules = [{
t: "set",
p: roomEventTypeOptions[0].value,
to: "payload",
tot: "msg"
}];
function isInvalidProperty(v,vt) {
if (/msg|flow|global/.test(vt)) {
if (!RED.utils.validatePropertyExpression(v)) {
return "Invalid property: " + v;
}
} else if (vt === "jsonata") {
try{ jsonata(v); } catch(e) {
return "Invalid expression: " + e.message;
}
} else if (vt === "json") {
try{ JSON.parse(v); } catch(e) {
return "Invalid JSON data: " + e.message;
}
}
return false;
}
RED.nodes.registerType('matrix-room-state-events',{
category: 'matrix',
color: '#00b7ca',
icon: "matrix.png",
outputLabels: ["success", "error"],
inputs:1,
outputs:2,
defaults: {
name: { value: null },
server: { type: "matrix-server-config" },
roomId: { value: null },
reason: { value: null },
rules: {
value: defaultRules,
validate: function(rules, opt) {
let msg;
const errors = []
if (!rules || rules.length === 0) { return true }
for (let i=0;i<rules.length;i++) {
const opt = { label: "Rule"+' '+(i+1) }
const r = rules[i];
if (r.t === 'set' || r.t === 'get') {
if ((msg = isInvalidProperty(r.p,r.pt)) !== false) {
return msg;
}
if ((msg = isInvalidProperty(r.to,r.tot)) !== false) {
return msg;
}
}
}
return errors.length ? errors : true;
}
},
},
oneditprepare: function() {
var set = "Set";
var to = "to the value";
var toValueLabel = "to the property";
var search = this._("change.action.search");
var replace = this._("change.action.replace");
var regex = this._("change.label.regex");
function createPropertyValue(row2_1, row2_2, type, defaultType) {
var propValInput = $('<input/>',{class:"node-input-rule-property-value",type:"text"})
.appendTo(row2_1)
.typedInput({
default: defaultType || (type === 'set' ? 'str' : 'msg'),
types: (type === 'set' ? ['msg','flow','global','str','num','bool','json','bin','date','jsonata'] : ['msg', 'flow', 'global'])
});
var dcLabel = $('<label style="padding-left: 130px;"></label>').appendTo(row2_2);
propValInput.on("change", function(evt,type,val) {
row2_2.toggle(type === "msg" || type === "flow" || type === "global" || type === "env");
})
return [propValInput];
}
$('#node-input-rule-container').css('min-height','150px').css('min-width','450px').editableList({
addItem: function(container,i,opt) {
var rule = opt;
if (!rule.hasOwnProperty('t')) {
rule = {t:"set",p:roomEventTypeOptions[0].value,to:"payload",tot:"msg"};
}
if (rule.t === "set" && !rule.tot) {
if (rule.to.indexOf("msg.") === 0 && !rule.tot) {
rule.to = rule.to.substring(4);
rule.tot = "msg";
} else {
rule.tot = "str";
}
}
container.css({
overflow: 'hidden',
whiteSpace: 'nowrap'
});
let fragment = document.createDocumentFragment();
var row1 = $('<div/>',{style:"display:flex; align-items: center"}).appendTo(fragment);
var row2 = $('<div/>',{style:"margin-top:8px;"}).appendTo(fragment);
var row3 = $('<div/>',{style:"margin-top:8px;"}).appendTo(fragment);
var row4 = $('<div/>',{style:"display:flex;margin-top:8px;align-items: baseline"}).appendTo(fragment);
var selectField = $('<select/>',{class:"node-input-rule-type",style:"width:110px; margin-right:10px;"}).appendTo(row1);
var selectOptions = [
{v:"set",l:"Set"},
{v:"get",l:"Get"}
];
for (var x=0; x<selectOptions.length; x++) {
selectField.append($("<option></option>").val(selectOptions[x].v).text(selectOptions[x].l));
}
var propertyName = $('<input/>',{class:"node-input-rule-property-name",type:"text"})
.appendTo(row1)
.autoComplete({
minLength:0,
search: function(val) {
if(!val) {
return roomEventTypeOptions.sort(function(A,B){return A.i-B.i});
}
var matches = [];
roomEventTypeOptions.map((x) => x.value).forEach(v => {
var i = v.toLowerCase().indexOf(val.toLowerCase());
if (i > -1) {
matches.push({
value: v,
label: v,
i: i
})
}
});
matches.sort(function(A,B){return A.i-B.i})
return matches
}
})
.on('focus', function(evt){
// following is a fix so autocomplete will show list on focus
if(!evt.isTrigger) {
evt.stopPropagation();
$(this).trigger("keyup.red-ui-autoComplete");
}
}).on("keyup", function(evt) {
// following allows autocomplete to display even when backspace/delete is used
if (evt.keyCode === 8 || evt.keyCode === 46) {
evt.stopPropagation();
$(this).trigger("keyup.red-ui-autoComplete");
}
});
var row2_1 = $('<div/>', {style:"display:flex;align-items: baseline"}).appendTo(row2);
$('<div/>',{style:"display:inline-block;text-align:right; width:120px; padding-right:10px; box-sizing:border-box;"})
.text(toValueLabel)
.appendTo(row2_1);
var row2_2 = $('<div/>', {style:"margin-top: 4px;"}).appendTo(row2);
var row3_1 = $('<div/>', {style:"display:flex;align-items: baseline"}).appendTo(row3);
$('<div/>',{style:"display:inline-block;text-align:right; width:120px; padding-right:10px; box-sizing:border-box;"})
.text(search)
.appendTo(row3_1);
var row3_2 = $('<div/>',{style:"display:flex;margin-top:8px;align-items: baseline"}).appendTo(row3);
$('<div/>',{style:"display:inline-block;text-align:right; width:120px; padding-right:10px; box-sizing:border-box;"})
.text(replace)
.appendTo(row3_2);
$('<div/>',{style:"display:inline-block;text-align:right; width:120px; padding-right:10px; box-sizing:border-box;"})
.text(to)
.appendTo(row4);
let propertyValue = null;
let fromValue = null;
let toValue = null;
selectField.on("change", function() {
var type = $(this).val();
if (propertyValue) {
propertyValue.typedInput('hide');
}
if (fromValue) {
fromValue.typedInput('hide');
}
if (toValue) {
toValue.typedInput('hide');
}
if (!propertyValue) {
var parts = createPropertyValue(row2_1, row2_2, type);
propertyValue = parts[0];
} else {
propertyValue.typedInput('types', (type === 'set' ? ['msg','flow','global','str','num','bool','json','bin','date','jsonata','env'] : ['msg', 'flow', 'global']));
}
propertyValue.typedInput('show');
row2.show();
row3.hide();
row4.hide();
});
selectField.val(rule.t);
propertyName.val(rule.p);
if (rule.t === "set" || rule.t === "get") {
var parts = createPropertyValue(row2_1, row2_2, rule.t, rule.tot);
propertyValue = parts[0];
propertyValue.typedInput('value',rule.to);
}
selectField.change();
container[0].appendChild(fragment);
},
removable: true,
sortable: true
});
for (var i=0; i<this.rules.length; i++) {
var rule = this.rules[i];
$("#node-input-rule-container").editableList('addItem',rule);
}
},
oneditsave: function() {
var rules = $("#node-input-rule-container").editableList('items');
var node = this;
node.rules= [];
rules.each(function(i) {
var rule = $(this);
var type = rule.find(".node-input-rule-type").val();
var r = {
t:type,
p:rule.find(".node-input-rule-property-name").val(),
to:rule.find(".node-input-rule-property-value").typedInput('value'),
tot:rule.find(".node-input-rule-property-value").typedInput('type')
};
node.rules.push(r);
});
},
oneditresize: function(size) {
var rows = $("#dialog-form>div:not(.node-input-rule-container-row)");
var height = size.height;
for (var i=0; i<rows.length; i++) {
height -= $(rows[i]).outerHeight(true);
}
var editorRow = $("#dialog-form>div.node-input-rule-container-row");
height -= (parseInt(editorRow.css("marginTop"))+parseInt(editorRow.css("marginBottom")));
height += 16;
$("#node-input-rule-container").editableList('height',height);
},
label: function() {
return this.name || "Room State Events";
},
paletteLabel: 'Room State Events'
});
})();
</script>

View File

@ -0,0 +1,272 @@
module.exports = function(RED) {
function MatrixRoomSettings(n) {
RED.nodes.createNode(this, n);
var node = this;
this.name = n.name;
this.server = RED.nodes.getNode(n.server);
this.roomId = n.roomId;
this.rules = n.rules;
if (!node.server) {
node.warn("No configuration node");
return;
}
node.server.register(node);
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.on("input", async function (msg) {
if (! node.server || ! node.server.matrixClient) {
msg.error = "No matrix server selected";
node.error(msg.error, msg);
node.send([null, msg]);
return;
}
if(!node.server.isConnected()) {
msg.error = "Matrix server connection is currently closed";
node.error(msg.error, msg);
node.send([null, msg]);
return;
}
msg.topic = node.roomId || msg.topic;
if(!msg.topic) {
msg.error = "Room must be specified in msg.topic or in configuration";
node.error(msg.error, msg);
node.send([null, msg]);
return;
}
let getterErrors = {},
setterErrors = {};
if(!Array.isArray(node.rules) || !node.rules.length) {
node.warn("No rules configured, skipping", msg);
return msg;
}
function getToValue(msg, rule) {
var value = rule.to;
if (rule.tot === 'json') {
try {
value = JSON.parse(rule.to);
} catch(e) {
throw new Error("Invalid JSON");
}
} else if (rule.tot === 'bin') {
try {
value = Buffer.from(JSON.parse(rule.to))
} catch(e) {
throw new Error("Invalid Binary");
}
}
if (rule.tot === "msg") {
value = RED.util.getMessageProperty(msg,rule.to);
} else if ((rule.tot === 'flow') || (rule.tot === 'global')) {
RED.util.evaluateNodeProperty(rule.to, rule.tot, node, msg, (err,value) => {
if (err) {
throw new Error("Invalid value evaluation");
} else {
return value;
}
});
return
} else if (rule.tot === 'date') {
value = Date.now();
} else if (rule.tot === 'jsonata') {
RED.util.evaluateJSONataExpression(rule.to,msg, (err, value) => {
if (err) {
throw new Error("Invalid expression");
} else {
return value;
}
});
return;
}
return value;
}
function setToValue(value, rule) {
if(rule.tot === 'global' || rule.tot === 'flow') {
var contextKey = RED.util.parseContextStore(rule.to);
if (/\[msg/.test(contextKey.key)) {
// The key has a nest msg. reference to evaluate first
contextKey.key = RED.util.normalisePropertyExpression(contextKey.key, msg, true)
}
var target = node.context()[rule.tot];
var callback = err => {
if (err) {
node.error(err, msg);
getterErrors[rule.p] = err.message;
}
}
target.set(contextKey.key, value, contextKey.store, callback);
} else if(rule.tot === 'msg') {
if (!RED.util.setMessageProperty(msg, rule.to, value)) {
node.warn(RED._("change.errors.no-override",{property:rule.to}));
}
}
}
for(let rule of node.rules) {
// [
// {
// "t": "set",
// "p": "m.room.topic",
// "to": "asdf",
// "tot": "str"
// }, ...
// ]
let cachedGetters = {};
if(rule.t === 'set') {
let value;
try {
value = getToValue(msg, rule);
switch(rule.p) {
case "m.room.name":
await node.server.matrixClient.sendStateEvent(
msg.topic,
"m.room.name",
typeof value === "string"
? { name: value }
: value);
break;
case "m.room.topic":
if(typeof value === "string") {
await node.server.matrixClient.setRoomTopic(msg.topic, value);
} else {
await node.server.matrixClient.sendStateEvent(
msg.topic,
"m.room.topic",
value
);
}
break;
case "m.room.avatar":
await node.server.matrixClient.sendStateEvent(
msg.topic,
"m.room.avatar",
typeof value === "string"
? { "url": value }
: value,
"");
break;
case "m.room.power_levels":
if(typeof value !== 'object') {
setterErrors[rule.p] = "m.room.power_levels content must be object";
} else {
await node.server.matrixClient.sendStateEvent(
msg.topic,
"m.room.power_levels",
value,
"");
}
break;
case "m.room.guest_access":
await node.server.matrixClient.sendStateEvent(
msg.topic,
"m.room.guest_access",
typeof value === "string"
? { "guest_access": value }
: value,
"");
break;
case "m.room.join_rules":
if(typeof value !== 'object') {
setterErrors[rule.p] = "m.room.join_rules content must be object";
} else {
await node.server.matrixClient.sendStateEvent(
msg.topic,
"m.room.join_rules",
value,
"");
}
break;
case "m.room.canonical_alias":
if(typeof value !== 'object') {
setterErrors[rule.p] = "m.room.canonical_alias content must be object";
} else {
await node.server.matrixClient.sendStateEvent(
msg.topic,
"m.room.canonical_alias",
value,
"");
}
break;
default:
if(typeof value !== 'object') {
setterErrors[rule.p] = "Custom event content must be object";
} else {
await node.server.matrixClient.sendStateEvent(
msg.topic,
rule.p,
value,
"");
}
break;
}
} catch(e) {
setterErrors[rule.p] = e.message;
}
} else if(rule.t === 'get') {
let value;
if(cachedGetters.hasOwnProperty(rule.p)) {
value = cachedGetters[rule.p];
} else {
try {
// we may want to fetch from local storage in the future, this is how to do that
// const room = this.getRoom(roomId);
// const ev = room.currentState.getStateEvents(EventType.RoomEncryption, "");
value = await node.server.matrixClient.getStateEvent(msg.topic, rule.p, "");
switch(rule.p) {
case "m.room.name":
value = value?.name
break;
case "m.room.topic":
value = value?.topic
break;
case "m.room.avatar":
value = value?.url
break;
case "m.room.guest_access":
value = value?.guest_access;
break;
}
setToValue(value, rule);
} catch(e) {
getterErrors[rule.p] = e;
}
}
}
}
if(Object.keys(setterErrors).length) {
msg.setter_errors = setterErrors;
}
if(Object.keys(getterErrors).length) {
msg.getter_errors = getterErrors;
}
node.send([msg, null]);
});
node.on("close", function() {
node.server.deregister(node);
});
}
RED.nodes.registerType("matrix-room-state-events", MatrixRoomSettings);
}

View File

@ -8,7 +8,7 @@
outputs:2, outputs:2,
defaults: { defaults: {
name: { value: null }, name: { value: null },
server: { value: "", type: "matrix-server-config" }, server: { type: "matrix-server-config" },
roomId: { value: "" } roomId: { value: "" }
}, },
label: function() { label: function() {

View File

@ -34,6 +34,7 @@ module.exports = function(RED) {
if(!node.server.isConnected()) { if(!node.server.isConnected()) {
node.error("Matrix server connection is currently closed", msg); node.error("Matrix server connection is currently closed", msg);
node.send([null, msg]); node.send([null, msg]);
return;
} }
let roomId = node.roomId || msg.topic; let roomId = node.roomId || msg.topic;

View File

@ -8,7 +8,7 @@
outputs:2, outputs:2,
defaults: { defaults: {
name: { value: null }, name: { value: null },
server: { value: "", type: "matrix-server-config" }, server: { type: "matrix-server-config" },
roomId: { value: null }, roomId: { value: null },
contentType: { value: null } contentType: { value: null }
}, },

View File

@ -34,6 +34,7 @@ module.exports = function(RED) {
if(!node.server.isConnected()) { if(!node.server.isConnected()) {
node.error("Matrix server connection is currently closed", msg); node.error("Matrix server connection is currently closed", msg);
node.send([null, msg]); node.send([null, msg]);
return;
} }
msg.topic = node.roomId || msg.topic; msg.topic = node.roomId || msg.topic;

View File

@ -8,7 +8,7 @@
outputs:2, outputs:2,
defaults: { defaults: {
name: { value: null }, name: { value: null },
server: { value: "", type: "matrix-server-config" }, server: { type: "matrix-server-config" },
roomId: { value: null }, roomId: { value: null },
contentType: { value: null } contentType: { value: null }
}, },

View File

@ -34,6 +34,7 @@ module.exports = function(RED) {
if(!node.server.isConnected()) { if(!node.server.isConnected()) {
node.error("Matrix server connection is currently closed", msg); node.error("Matrix server connection is currently closed", msg);
node.send([null, msg]); node.send([null, msg]);
return;
} }
msg.topic = node.roomId || msg.topic; msg.topic = node.roomId || msg.topic;

View File

@ -8,7 +8,7 @@
outputs:2, outputs:2,
defaults: { defaults: {
name: { value: null }, name: { value: null },
server: { value: "", type: "matrix-server-config" }, server: { type: "matrix-server-config" },
roomId: { value: null }, roomId: { value: null },
message: { value: null }, message: { value: null },
messageType: { value: 'm.text' }, messageType: { value: 'm.text' },

View File

@ -379,7 +379,7 @@ module.exports = function(RED) {
if(node.e2ee){ if(node.e2ee){
node.log("Initializing crypto..."); node.log("Initializing crypto...");
await node.matrixClient.initCrypto(); await node.matrixClient.initCrypto();
node.matrixClient.setGlobalErrorOnUnknownDevices(false); node.matrixClient.getCrypto().globalBlacklistUnverifiedDevices = false; // prevent errors from unverified devices
} }
node.log("Connecting to Matrix server..."); node.log("Connecting to Matrix server...");
await node.matrixClient.startClient({ await node.matrixClient.startClient({

View File

@ -8,7 +8,7 @@
outputs:2, outputs:2,
defaults: { defaults: {
name: { value: null }, name: { value: null },
server: { value: "", type: "matrix-server-config" }, server: { type: "matrix-server-config" },
}, },
label: function() { label: function() {
return this.name || "Synapse Add/Edit User"; return this.name || "Synapse Add/Edit User";

View File

@ -44,6 +44,7 @@ module.exports = function(RED) {
if(!node.server.isConnected()) { if(!node.server.isConnected()) {
node.error("Matrix server connection is currently closed", msg); node.error("Matrix server connection is currently closed", msg);
node.send([null, msg]); node.send([null, msg]);
return;
} }
if(!msg.userId) { if(!msg.userId) {

View File

@ -8,7 +8,7 @@
outputs:2, outputs:2,
defaults: { defaults: {
name: { value: null }, name: { value: null },
server: { value: "", type: "matrix-server-config" }, server: { type: "matrix-server-config" },
}, },
label: function() { label: function() {
return this.name || "Synapse Deactivate User"; return this.name || "Synapse Deactivate User";

View File

@ -44,6 +44,7 @@ module.exports = function(RED) {
if(!node.server.isConnected()) { if(!node.server.isConnected()) {
node.error("Matrix server connection is currently closed", msg); node.error("Matrix server connection is currently closed", msg);
node.send([null, msg]); node.send([null, msg]);
return;
} }
if(!msg.userId) { if(!msg.userId) {

View File

@ -8,7 +8,7 @@
outputs: 2, outputs: 2,
defaults: { defaults: {
name: { value: null }, name: { value: null },
server: { value: "", type: "matrix-server-config" }, server: { type: "matrix-server-config" },
roomId: { value: null }, roomId: { value: null },
}, },
label: function() { label: function() {

View File

@ -43,6 +43,7 @@ module.exports = function(RED) {
if(!node.server.isConnected()) { if(!node.server.isConnected()) {
node.error("Matrix server connection is currently closed", msg); node.error("Matrix server connection is currently closed", msg);
node.send([null, msg]); node.send([null, msg]);
return;
} }
msg.topic = node.roomId || msg.topic; msg.topic = node.roomId || msg.topic;

View File

@ -8,7 +8,7 @@
outputs:2, outputs:2,
defaults: { defaults: {
name: { value: null }, name: { value: null },
server: { value: "", type: "matrix-server-config" } server: { type: "matrix-server-config" }
}, },
label: function() { label: function() {
return this.name || "Synapse User List"; return this.name || "Synapse User List";

View File

@ -33,6 +33,7 @@ module.exports = function(RED) {
if(!node.server.isConnected()) { if(!node.server.isConnected()) {
node.error("Matrix server connection is currently closed", msg); node.error("Matrix server connection is currently closed", msg);
node.send([null, msg]); node.send([null, msg]);
return;
} }
let queryParams = { let queryParams = {

View File

@ -8,7 +8,7 @@
outputs:2, outputs:2,
defaults: { defaults: {
name: { value: null }, name: { value: null },
server: { value: "", type: "matrix-server-config" }, server: { type: "matrix-server-config" },
}, },
label: function() { label: function() {
return this.name || "WhoIs User"; return this.name || "WhoIs User";

View File

@ -45,6 +45,7 @@ module.exports = function(RED) {
if(!node.server.isConnected()) { if(!node.server.isConnected()) {
node.error("Matrix server connection is currently closed", msg); node.error("Matrix server connection is currently closed", msg);
node.send([null, msg]); node.send([null, msg]);
return;
} }
if(!msg.userId) { if(!msg.userId) {