You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
163 lines
3.7 KiB
JavaScript
163 lines
3.7 KiB
JavaScript
"use strict";
|
|
|
|
const matchValue = require("match-value");
|
|
const defaultValue = require("default-value");
|
|
const syncpipe = require("syncpipe");
|
|
const splitFilter = require("split-filter");
|
|
const flatten = require("flatten");
|
|
const unreachable = require("@joepie91/unreachable")("@modular-matrix/client"); // FIXME
|
|
|
|
function parsePredicate(predicate) {
|
|
let match = /^(>|>=|<|<=|==)?([0-9]+)$/.exec(predicate);
|
|
|
|
if (match != null) {
|
|
return {
|
|
operator: defaultValue(match[1], "=="),
|
|
value: match[2]
|
|
};
|
|
} else {
|
|
unreachable("Failed to parse predicate");
|
|
}
|
|
}
|
|
|
|
function mapCondition(condition) {
|
|
if (condition.kind === "event_match") {
|
|
return {
|
|
type: "matchEventField",
|
|
field: condition.key,
|
|
pattern: condition.pattern
|
|
};
|
|
} else if (condition.kind === "contains_display_name") {
|
|
return {
|
|
type: "matchDisplayName"
|
|
};
|
|
} else if (condition.kind === "room_member_count") {
|
|
let { operator, value } = parsePredicate(condition.is);
|
|
|
|
return {
|
|
type: "matchRoomMemberCount",
|
|
operator: operator,
|
|
value: value
|
|
};
|
|
} else if (condition.kind === "sender_notification_permission") {
|
|
return {
|
|
type: "requireEventPowerLevel",
|
|
notificationType: condition.key
|
|
};
|
|
} else {
|
|
// Spec: "Unrecognised conditions MUST NOT match any events, effectively making the push rule disabled."
|
|
// FIXME: Log warning?
|
|
return {
|
|
type: "neverMatch"
|
|
};
|
|
}
|
|
}
|
|
|
|
function mapAction(action) {
|
|
if (action === "notify") {
|
|
return {
|
|
type: "notification"
|
|
};
|
|
} else if (action === "dont_notify") {
|
|
return {
|
|
type: "preventNotification"
|
|
};
|
|
} else if (action === "coalesce") {
|
|
return {
|
|
type: "digestNotification"
|
|
};
|
|
} else if (action.set_tweak != null) {
|
|
let key = action.set_tweak;
|
|
|
|
return {
|
|
type: "setTweak",
|
|
key: key,
|
|
value: matchValue(key, {
|
|
sound: () => (action.value === "default") ? true : action.value,
|
|
highlight: () => defaultValue(action.value, true),
|
|
_: () => action.value
|
|
})
|
|
};
|
|
} else {
|
|
unreachable(`Unrecognized action type`);
|
|
}
|
|
}
|
|
|
|
function mapRule(rule) {
|
|
let mappedActions = rule.actions.map(mapAction);
|
|
let [ tweaks, actualActions ] = splitFilter(mappedActions, (action) => action.type === "setTweak");
|
|
|
|
return {
|
|
id: rule.rule_id,
|
|
isDefault: rule.default,
|
|
isEnabled: rule.enabled,
|
|
actions: actualActions,
|
|
// FIXME: Clearly document that these 'options' are called 'tweaks' on the push gateway side!
|
|
notificationOptions: Object.fromEntries(tweaks.map(({ key, value }) => [ key, value ]))
|
|
};
|
|
}
|
|
|
|
function mapRuleset(rules, key) {
|
|
if (rules == null) {
|
|
return [];
|
|
} else if (key === "content") {
|
|
return rules.map((rule) => {
|
|
return {
|
|
... mapRule(rule),
|
|
conditions: [{
|
|
type: "matchContent",
|
|
pattern: rule.pattern
|
|
}]
|
|
};
|
|
});
|
|
} else if (key === "room") {
|
|
return rules.map((rule) => {
|
|
return {
|
|
... mapRule(rule),
|
|
conditions: [{
|
|
type: "matchRoom",
|
|
roomID: rule.rule_id
|
|
}]
|
|
};
|
|
});
|
|
} else if (key === "sender") {
|
|
return rules.map((rule) => {
|
|
return {
|
|
... mapRule(rule),
|
|
conditions: [{
|
|
type: "matchSender",
|
|
userID: rule.rule_id
|
|
}]
|
|
};
|
|
});
|
|
} else if (key === "override" || key === "underride") {
|
|
return rules.map((rule) => {
|
|
return {
|
|
... mapRule(rule),
|
|
conditions: rule.conditions.map(mapCondition)
|
|
};
|
|
});
|
|
} else {
|
|
throw unreachable("Unrecognized ruleset key");
|
|
}
|
|
}
|
|
|
|
function mapRulesets(rulesets) {
|
|
if (rulesets != null) {
|
|
return syncpipe([ "override", "content", "room", "sender", "underride" ], [
|
|
(_) => _.map((key) => mapRuleset(rulesets[key], key)),
|
|
(_) => _.filter((ruleset) => ruleset.length > 0),
|
|
(_) => flatten(_)
|
|
]);
|
|
} else {
|
|
return [];
|
|
}
|
|
}
|
|
|
|
module.exports = function mapPushRulesEvent(event, _context) {
|
|
return {
|
|
type: "pushRulesChanged",
|
|
rulesets: mapRulesets(event.content.global)
|
|
};
|
|
};
|