From bcf3bba44e61280a9743bf0a6394a8caded7548f Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Tue, 7 Mar 2023 11:36:06 -0500 Subject: [PATCH] Implement MSC3966: a push rule condition to check if an array contains a value (#3180) * Support MSC3966 to match values in an array in push rule conditions. * Update to stable identifiers. * Appease the linter. --- spec/unit/pushprocessor.spec.ts | 69 +++++++++++++++++++++++++++++++++ src/@types/PushRules.ts | 7 ++++ src/pushprocessor.ts | 21 ++++++++++ 3 files changed, 97 insertions(+) diff --git a/spec/unit/pushprocessor.spec.ts b/spec/unit/pushprocessor.spec.ts index c78569efcee..2f219b3070f 100644 --- a/spec/unit/pushprocessor.spec.ts +++ b/spec/unit/pushprocessor.spec.ts @@ -576,6 +576,75 @@ describe("NotificationService", function () { }); }); + describe("Test event property contains", () => { + it.each([ + // Simple string matching. + { value: "bar", eventValue: ["bar"], expected: true }, + // Matches are case-sensitive. + { value: "bar", eventValue: ["BAR"], expected: false }, + // Values should not be type-coerced. + { value: "bar", eventValue: [true], expected: false }, + { value: "bar", eventValue: [1], expected: false }, + { value: "bar", eventValue: [false], expected: false }, + // Boolean matching. + { value: true, eventValue: [true], expected: true }, + { value: false, eventValue: [false], expected: true }, + // Types should not be coerced. + { value: true, eventValue: ["true"], expected: false }, + { value: true, eventValue: [1], expected: false }, + { value: false, eventValue: [null], expected: false }, + // Null matching. + { value: null, eventValue: [null], expected: true }, + // Types should not be coerced + { value: null, eventValue: [false], expected: false }, + { value: null, eventValue: [0], expected: false }, + { value: null, eventValue: [""], expected: false }, + { value: null, eventValue: [undefined], expected: false }, + // Non-array or empty values should never be matched. + { value: "bar", eventValue: "bar", expected: false }, + { value: "bar", eventValue: { bar: true }, expected: false }, + { value: true, eventValue: { true: true }, expected: false }, + { value: true, eventValue: true, expected: false }, + { value: null, eventValue: [], expected: false }, + { value: null, eventValue: {}, expected: false }, + { value: null, eventValue: null, expected: false }, + { value: null, eventValue: undefined, expected: false }, + ])("test $value against $eventValue", ({ value, eventValue, expected }) => { + matrixClient.pushRules! = { + global: { + override: [ + { + actions: [PushRuleActionName.Notify], + conditions: [ + { + kind: ConditionKind.EventPropertyContains, + key: "content.foo", + value: value, + }, + ], + default: true, + enabled: true, + rule_id: ".m.rule.test", + }, + ], + }, + }; + + testEvent = utils.mkEvent({ + type: "m.room.message", + room: testRoomId, + user: "@alfred:localhost", + event: true, + content: { + foo: eventValue, + }, + }); + + const actions = pushProcessor.actionsForEvent(testEvent); + expect(actions?.notify).toBe(expected ? true : undefined); + }); + }); + it.each([ // The properly escaped key works. { key: "content.m\\.test.foo", pattern: "bar", expected: true }, diff --git a/src/@types/PushRules.ts b/src/@types/PushRules.ts index 8f6d24a5b8c..2234a62c21b 100644 --- a/src/@types/PushRules.ts +++ b/src/@types/PushRules.ts @@ -63,6 +63,7 @@ export function isDmMemberCountCondition(condition: AnyMemberCountCondition): bo export enum ConditionKind { EventMatch = "event_match", EventPropertyIs = "event_property_is", + EventPropertyContains = "event_property_contains", ContainsDisplayName = "contains_display_name", RoomMemberCount = "room_member_count", SenderNotificationPermission = "sender_notification_permission", @@ -88,6 +89,11 @@ export interface IEventPropertyIsCondition extends IPushRuleCondition { + key: string; + value: string | boolean | null | number; +} + export interface IContainsDisplayNameCondition extends IPushRuleCondition { // no additional fields } @@ -114,6 +120,7 @@ export interface ICallStartedPrefixCondition extends IPushRuleCondition