Merge pull request #1982 from famedly/karthi/push-rules
feat: support push rule conditions event_property_is & event_property_contains
This commit is contained in:
commit
992c8e42f2
|
|
@ -2188,7 +2188,11 @@ class Room {
|
||||||
id,
|
id,
|
||||||
[],
|
[],
|
||||||
conditions: [
|
conditions: [
|
||||||
PushCondition(kind: 'event_match', key: 'room_id', pattern: id),
|
PushCondition(
|
||||||
|
kind: PushRuleConditions.eventMatch.name,
|
||||||
|
key: 'room_id',
|
||||||
|
pattern: id,
|
||||||
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,8 +18,26 @@
|
||||||
|
|
||||||
// Helper for fast evaluation of push conditions on a bunch of events
|
// Helper for fast evaluation of push conditions on a bunch of events
|
||||||
|
|
||||||
|
import 'package:collection/collection.dart';
|
||||||
|
|
||||||
import 'package:matrix/matrix.dart';
|
import 'package:matrix/matrix.dart';
|
||||||
|
|
||||||
|
enum PushRuleConditions {
|
||||||
|
eventMatch('event_match'),
|
||||||
|
eventPropertyIs('event_property_is'),
|
||||||
|
eventPropertyContains('event_property_contains'),
|
||||||
|
containsDisplayName('contains_display_name'),
|
||||||
|
roomMemberCount('room_member_count'),
|
||||||
|
senderNotificationPermission('sender_notification_permission');
|
||||||
|
|
||||||
|
final String name;
|
||||||
|
const PushRuleConditions(this.name);
|
||||||
|
|
||||||
|
static PushRuleConditions? fromString(String name) {
|
||||||
|
return values.firstWhereOrNull((e) => e.name == name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class EvaluatedPushRuleAction {
|
class EvaluatedPushRuleAction {
|
||||||
// if this message should be highlighted.
|
// if this message should be highlighted.
|
||||||
bool highlight = false;
|
bool highlight = false;
|
||||||
|
|
@ -56,23 +74,19 @@ class _PatternCondition {
|
||||||
String field = '';
|
String field = '';
|
||||||
|
|
||||||
_PatternCondition.fromEventMatch(PushCondition condition) {
|
_PatternCondition.fromEventMatch(PushCondition condition) {
|
||||||
if (condition.kind != 'event_match') {
|
if (condition.kind != PushRuleConditions.eventMatch.name) {
|
||||||
throw 'Logic error: invalid push rule passed to constructor ${condition.kind}';
|
throw 'Logic error: invalid push rule passed to constructor ${condition.kind}';
|
||||||
}
|
}
|
||||||
|
|
||||||
final tempField = condition.key;
|
final tempField = condition.key;
|
||||||
if (tempField == null) {
|
if (tempField == null) {
|
||||||
{
|
throw 'No field to match pattern on!';
|
||||||
throw 'No field to match pattern on!';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
field = tempField;
|
field = tempField;
|
||||||
|
|
||||||
var tempPat = condition.pattern;
|
var tempPat = condition.pattern;
|
||||||
if (tempPat == null) {
|
if (tempPat == null) {
|
||||||
{
|
throw 'PushCondition is missing pattern';
|
||||||
throw 'PushCondition is missing pattern';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
tempPat =
|
tempPat =
|
||||||
RegExp.escape(tempPat).replaceAll('\\*', '.*').replaceAll('\\?', '.');
|
RegExp.escape(tempPat).replaceAll('\\*', '.*').replaceAll('\\?', '.');
|
||||||
|
|
@ -84,15 +98,60 @@ class _PatternCondition {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool match(Map<String, String> content) {
|
bool match(Map<String, Object?> flattenedEventJson) {
|
||||||
final fieldContent = content[field];
|
final fieldContent = flattenedEventJson[field];
|
||||||
if (fieldContent == null) {
|
if (fieldContent == null || fieldContent is! String) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return pattern.hasMatch(fieldContent);
|
return pattern.hasMatch(fieldContent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class _EventPropertyCondition {
|
||||||
|
PushRuleConditions? kind;
|
||||||
|
// what field to match on, i.e. content.body
|
||||||
|
String field = '';
|
||||||
|
Object? value;
|
||||||
|
|
||||||
|
_EventPropertyCondition.fromEventMatch(PushCondition condition) {
|
||||||
|
if (![
|
||||||
|
PushRuleConditions.eventPropertyIs.name,
|
||||||
|
PushRuleConditions.eventPropertyContains.name,
|
||||||
|
].contains(condition.kind)) {
|
||||||
|
throw 'Logic error: invalid push rule passed to constructor ${condition.kind}';
|
||||||
|
}
|
||||||
|
kind = PushRuleConditions.fromString(condition.kind);
|
||||||
|
|
||||||
|
final tempField = condition.key;
|
||||||
|
if (tempField == null) {
|
||||||
|
throw 'No field to check event property on!';
|
||||||
|
}
|
||||||
|
field = tempField;
|
||||||
|
|
||||||
|
final tempValue = condition.value;
|
||||||
|
if (![String, int, bool, Null].contains(tempValue.runtimeType)) {
|
||||||
|
throw 'PushCondition value is not a string, int, bool or null';
|
||||||
|
}
|
||||||
|
value = tempValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool match(Map<String, Object?> flattenedEventJson) {
|
||||||
|
final fieldContent = flattenedEventJson[field];
|
||||||
|
switch (kind) {
|
||||||
|
case PushRuleConditions.eventPropertyIs:
|
||||||
|
// We check if the property exists because null is a valid property value.
|
||||||
|
if (!flattenedEventJson.keys.contains(field)) return false;
|
||||||
|
return fieldContent == value;
|
||||||
|
case PushRuleConditions.eventPropertyContains:
|
||||||
|
if (fieldContent is! Iterable) return false;
|
||||||
|
return fieldContent.contains(value);
|
||||||
|
default:
|
||||||
|
// This should never happen
|
||||||
|
throw 'Logic error: invalid push rule passed in _EventPropertyCondition ${kind?.name}';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
enum _CountComparisonOp {
|
enum _CountComparisonOp {
|
||||||
eq,
|
eq,
|
||||||
lt,
|
lt,
|
||||||
|
|
@ -106,7 +165,7 @@ class _MemberCountCondition {
|
||||||
int count = 0;
|
int count = 0;
|
||||||
|
|
||||||
_MemberCountCondition.fromEventMatch(PushCondition condition) {
|
_MemberCountCondition.fromEventMatch(PushCondition condition) {
|
||||||
if (condition.kind != 'room_member_count') {
|
if (condition.kind != PushRuleConditions.roomMemberCount.name) {
|
||||||
throw 'Logic error: invalid push rule passed to constructor ${condition.kind}';
|
throw 'Logic error: invalid push rule passed to constructor ${condition.kind}';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -160,6 +219,7 @@ class _MemberCountCondition {
|
||||||
|
|
||||||
class _OptimizedRules {
|
class _OptimizedRules {
|
||||||
List<_PatternCondition> patterns = [];
|
List<_PatternCondition> patterns = [];
|
||||||
|
List<_EventPropertyCondition> eventProperties = [];
|
||||||
List<_MemberCountCondition> memberCounts = [];
|
List<_MemberCountCondition> memberCounts = [];
|
||||||
List<String> notificationPermissions = [];
|
List<String> notificationPermissions = [];
|
||||||
bool matchDisplayname = false;
|
bool matchDisplayname = false;
|
||||||
|
|
@ -168,18 +228,24 @@ class _OptimizedRules {
|
||||||
_OptimizedRules.fromRule(PushRule rule) {
|
_OptimizedRules.fromRule(PushRule rule) {
|
||||||
if (!rule.enabled) return;
|
if (!rule.enabled) return;
|
||||||
|
|
||||||
for (final condition in rule.conditions ?? []) {
|
for (final condition in rule.conditions ?? <PushCondition>[]) {
|
||||||
switch (condition.kind) {
|
final kind = PushRuleConditions.fromString(condition.kind);
|
||||||
case 'event_match':
|
switch (kind) {
|
||||||
|
case PushRuleConditions.eventMatch:
|
||||||
patterns.add(_PatternCondition.fromEventMatch(condition));
|
patterns.add(_PatternCondition.fromEventMatch(condition));
|
||||||
break;
|
break;
|
||||||
case 'contains_display_name':
|
case PushRuleConditions.eventPropertyIs:
|
||||||
|
case PushRuleConditions.eventPropertyContains:
|
||||||
|
eventProperties
|
||||||
|
.add(_EventPropertyCondition.fromEventMatch(condition));
|
||||||
|
break;
|
||||||
|
case PushRuleConditions.containsDisplayName:
|
||||||
matchDisplayname = true;
|
matchDisplayname = true;
|
||||||
break;
|
break;
|
||||||
case 'room_member_count':
|
case PushRuleConditions.roomMemberCount:
|
||||||
memberCounts.add(_MemberCountCondition.fromEventMatch(condition));
|
memberCounts.add(_MemberCountCondition.fromEventMatch(condition));
|
||||||
break;
|
break;
|
||||||
case 'sender_notification_permission':
|
case PushRuleConditions.senderNotificationPermission:
|
||||||
final key = condition.key;
|
final key = condition.key;
|
||||||
if (key != null) {
|
if (key != null) {
|
||||||
notificationPermissions.add(key);
|
notificationPermissions.add(key);
|
||||||
|
|
@ -193,19 +259,22 @@ class _OptimizedRules {
|
||||||
}
|
}
|
||||||
|
|
||||||
EvaluatedPushRuleAction? match(
|
EvaluatedPushRuleAction? match(
|
||||||
Map<String, String> event,
|
Map<String, Object?> flattenedEventJson,
|
||||||
String? displayName,
|
String? displayName,
|
||||||
int memberCount,
|
int memberCount,
|
||||||
Room room,
|
Room room,
|
||||||
) {
|
) {
|
||||||
if (patterns.any((pat) => !pat.match(event))) {
|
if (patterns.any((pat) => !pat.match(flattenedEventJson))) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (eventProperties.any((pat) => !pat.match(flattenedEventJson))) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if (memberCounts.any((pat) => !pat.match(memberCount))) {
|
if (memberCounts.any((pat) => !pat.match(memberCount))) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if (matchDisplayname) {
|
if (matchDisplayname) {
|
||||||
final body = event.tryGet<String>('content.body');
|
final body = flattenedEventJson.tryGet<String>('content.body');
|
||||||
if (displayName == null || body == null) {
|
if (displayName == null || body == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
@ -220,7 +289,7 @@ class _OptimizedRules {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (notificationPermissions.isNotEmpty) {
|
if (notificationPermissions.isNotEmpty) {
|
||||||
final sender = event.tryGet<String>('sender');
|
final sender = flattenedEventJson.tryGet<String>('sender');
|
||||||
if (sender == null ||
|
if (sender == null ||
|
||||||
notificationPermissions.any(
|
notificationPermissions.any(
|
||||||
(notificationType) => !room.canSendNotification(
|
(notificationType) => !room.canSendNotification(
|
||||||
|
|
@ -244,7 +313,7 @@ class PushruleEvaluator {
|
||||||
final List<_OptimizedRules> _underride = [];
|
final List<_OptimizedRules> _underride = [];
|
||||||
|
|
||||||
PushruleEvaluator.fromRuleset(PushRuleSet ruleset) {
|
PushruleEvaluator.fromRuleset(PushRuleSet ruleset) {
|
||||||
for (final o in ruleset.override ?? []) {
|
for (final o in ruleset.override ?? <PushRule>[]) {
|
||||||
if (!o.enabled) continue;
|
if (!o.enabled) continue;
|
||||||
try {
|
try {
|
||||||
_override.add(_OptimizedRules.fromRule(o));
|
_override.add(_OptimizedRules.fromRule(o));
|
||||||
|
|
@ -252,7 +321,7 @@ class PushruleEvaluator {
|
||||||
Logs().d('Error parsing push rule $o', e);
|
Logs().d('Error parsing push rule $o', e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (final u in ruleset.underride ?? []) {
|
for (final u in ruleset.underride ?? <PushRule>[]) {
|
||||||
if (!u.enabled) continue;
|
if (!u.enabled) continue;
|
||||||
try {
|
try {
|
||||||
_underride.add(_OptimizedRules.fromRule(u));
|
_underride.add(_OptimizedRules.fromRule(u));
|
||||||
|
|
@ -260,13 +329,13 @@ class PushruleEvaluator {
|
||||||
Logs().d('Error parsing push rule $u', e);
|
Logs().d('Error parsing push rule $u', e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (final c in ruleset.content ?? []) {
|
for (final c in ruleset.content ?? <PushRule>[]) {
|
||||||
if (!c.enabled) continue;
|
if (!c.enabled) continue;
|
||||||
final rule = PushRule(
|
final rule = PushRule(
|
||||||
actions: c.actions,
|
actions: c.actions,
|
||||||
conditions: [
|
conditions: [
|
||||||
PushCondition(
|
PushCondition(
|
||||||
kind: 'event_match',
|
kind: PushRuleConditions.eventMatch.name,
|
||||||
key: 'content.body',
|
key: 'content.body',
|
||||||
pattern: c.pattern,
|
pattern: c.pattern,
|
||||||
),
|
),
|
||||||
|
|
@ -281,12 +350,12 @@ class PushruleEvaluator {
|
||||||
Logs().d('Error parsing push rule $rule', e);
|
Logs().d('Error parsing push rule $rule', e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (final r in ruleset.room ?? []) {
|
for (final r in ruleset.room ?? <PushRule>[]) {
|
||||||
if (r.enabled) {
|
if (r.enabled) {
|
||||||
_room_rules[r.ruleId] = EvaluatedPushRuleAction.fromActions(r.actions);
|
_room_rules[r.ruleId] = EvaluatedPushRuleAction.fromActions(r.actions);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (final r in ruleset.sender ?? []) {
|
for (final r in ruleset.sender ?? <PushRule>[]) {
|
||||||
if (r.enabled) {
|
if (r.enabled) {
|
||||||
_sender_rules[r.ruleId] =
|
_sender_rules[r.ruleId] =
|
||||||
EvaluatedPushRuleAction.fromActions(r.actions);
|
EvaluatedPushRuleAction.fromActions(r.actions);
|
||||||
|
|
@ -294,18 +363,18 @@ class PushruleEvaluator {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<String, String> _flattenJson(
|
Map<String, Object?> _flattenJson(
|
||||||
Map<String, dynamic> obj,
|
Map<String, dynamic> obj,
|
||||||
Map<String, String> flattened,
|
Map<String, Object?> flattened,
|
||||||
String prefix,
|
String prefix,
|
||||||
) {
|
) {
|
||||||
for (final entry in obj.entries) {
|
for (final entry in obj.entries) {
|
||||||
final key = prefix == '' ? entry.key : '$prefix.${entry.key}';
|
final key = prefix == '' ? entry.key : '$prefix.${entry.key}';
|
||||||
final value = entry.value;
|
final value = entry.value;
|
||||||
if (value is String) {
|
if (value is Map<String, dynamic>) {
|
||||||
flattened[key] = value;
|
|
||||||
} else if (value is Map<String, dynamic>) {
|
|
||||||
flattened = _flattenJson(value, flattened, key);
|
flattened = _flattenJson(value, flattened, key);
|
||||||
|
} else {
|
||||||
|
flattened[key] = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -317,12 +386,13 @@ class PushruleEvaluator {
|
||||||
final displayName = event.room
|
final displayName = event.room
|
||||||
.unsafeGetUserFromMemoryOrFallback(event.room.client.userID!)
|
.unsafeGetUserFromMemoryOrFallback(event.room.client.userID!)
|
||||||
.displayName;
|
.displayName;
|
||||||
final content = _flattenJson(event.toJson(), {}, '');
|
final flattenedEventJson = _flattenJson(event.toJson(), {}, '');
|
||||||
// ensure roomid is present
|
// ensure roomid is present
|
||||||
content['room_id'] = event.room.id;
|
flattenedEventJson['room_id'] = event.room.id;
|
||||||
|
|
||||||
for (final o in _override) {
|
for (final o in _override) {
|
||||||
final actions = o.match(content, displayName, memberCount, event.room);
|
final actions =
|
||||||
|
o.match(flattenedEventJson, displayName, memberCount, event.room);
|
||||||
if (actions != null) {
|
if (actions != null) {
|
||||||
return actions;
|
return actions;
|
||||||
}
|
}
|
||||||
|
|
@ -339,14 +409,16 @@ class PushruleEvaluator {
|
||||||
}
|
}
|
||||||
|
|
||||||
for (final o in _content_rules) {
|
for (final o in _content_rules) {
|
||||||
final actions = o.match(content, displayName, memberCount, event.room);
|
final actions =
|
||||||
|
o.match(flattenedEventJson, displayName, memberCount, event.room);
|
||||||
if (actions != null) {
|
if (actions != null) {
|
||||||
return actions;
|
return actions;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (final o in _underride) {
|
for (final o in _underride) {
|
||||||
final actions = o.match(content, displayName, memberCount, event.room);
|
final actions =
|
||||||
|
o.match(flattenedEventJson, displayName, memberCount, event.room);
|
||||||
if (actions != null) {
|
if (actions != null) {
|
||||||
return actions;
|
return actions;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,22 @@ import 'package:test/test.dart';
|
||||||
import 'package:matrix/matrix.dart';
|
import 'package:matrix/matrix.dart';
|
||||||
import 'fake_client.dart';
|
import 'fake_client.dart';
|
||||||
|
|
||||||
|
void _testMatch(PushRuleSet ruleset, Event event) {
|
||||||
|
final evaluator = PushruleEvaluator.fromRuleset(ruleset);
|
||||||
|
final actions = evaluator.match(event);
|
||||||
|
expect(actions.notify, true);
|
||||||
|
expect(actions.highlight, true);
|
||||||
|
expect(actions.sound, 'goose.wav');
|
||||||
|
}
|
||||||
|
|
||||||
|
void _testNotMatch(PushRuleSet ruleset, Event event) {
|
||||||
|
final evaluator = PushruleEvaluator.fromRuleset(ruleset);
|
||||||
|
final actions = evaluator.match(event);
|
||||||
|
expect(actions.notify, false);
|
||||||
|
expect(actions.highlight, false);
|
||||||
|
expect(actions.sound, null);
|
||||||
|
}
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
/// All Tests related to the Event
|
/// All Tests related to the Event
|
||||||
group('Event', () {
|
group('Event', () {
|
||||||
|
|
@ -145,62 +161,46 @@ void main() {
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
void testMatch(PushRuleSet ruleset, Event event) {
|
_testMatch(override_ruleset, event);
|
||||||
final evaluator = PushruleEvaluator.fromRuleset(ruleset);
|
_testMatch(underride_ruleset, event);
|
||||||
final actions = evaluator.match(event);
|
_testMatch(content_ruleset, event);
|
||||||
expect(actions.notify, true);
|
_testMatch(room_ruleset, event);
|
||||||
expect(actions.highlight, true);
|
_testMatch(sender_ruleset, event);
|
||||||
expect(actions.sound, 'goose.wav');
|
|
||||||
}
|
|
||||||
|
|
||||||
void testNotMatch(PushRuleSet ruleset, Event event) {
|
|
||||||
final evaluator = PushruleEvaluator.fromRuleset(ruleset);
|
|
||||||
final actions = evaluator.match(event);
|
|
||||||
expect(actions.notify, false);
|
|
||||||
expect(actions.highlight, false);
|
|
||||||
expect(actions.sound, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
testMatch(override_ruleset, event);
|
|
||||||
testMatch(underride_ruleset, event);
|
|
||||||
testMatch(content_ruleset, event);
|
|
||||||
testMatch(room_ruleset, event);
|
|
||||||
testMatch(sender_ruleset, event);
|
|
||||||
|
|
||||||
event.content['body'] = 'FoX';
|
event.content['body'] = 'FoX';
|
||||||
testMatch(override_ruleset, event);
|
_testMatch(override_ruleset, event);
|
||||||
testMatch(underride_ruleset, event);
|
_testMatch(underride_ruleset, event);
|
||||||
testMatch(content_ruleset, event);
|
_testMatch(content_ruleset, event);
|
||||||
testMatch(room_ruleset, event);
|
_testMatch(room_ruleset, event);
|
||||||
testMatch(sender_ruleset, event);
|
_testMatch(sender_ruleset, event);
|
||||||
|
|
||||||
event.content['body'] = '@FoX:';
|
event.content['body'] = '@FoX:';
|
||||||
testMatch(override_ruleset, event);
|
_testMatch(override_ruleset, event);
|
||||||
testMatch(underride_ruleset, event);
|
_testMatch(underride_ruleset, event);
|
||||||
testMatch(content_ruleset, event);
|
_testMatch(content_ruleset, event);
|
||||||
testMatch(room_ruleset, event);
|
_testMatch(room_ruleset, event);
|
||||||
testMatch(sender_ruleset, event);
|
_testMatch(sender_ruleset, event);
|
||||||
|
|
||||||
event.content['body'] = 'äFoXü';
|
event.content['body'] = 'äFoXü';
|
||||||
testMatch(override_ruleset, event);
|
_testMatch(override_ruleset, event);
|
||||||
testMatch(underride_ruleset, event);
|
_testMatch(underride_ruleset, event);
|
||||||
testMatch(content_ruleset, event);
|
_testMatch(content_ruleset, event);
|
||||||
testMatch(room_ruleset, event);
|
_testMatch(room_ruleset, event);
|
||||||
testMatch(sender_ruleset, event);
|
_testMatch(sender_ruleset, event);
|
||||||
|
|
||||||
event.content['body'] = 'äFoXu';
|
event.content['body'] = 'äFoXu';
|
||||||
testNotMatch(override_ruleset, event);
|
_testNotMatch(override_ruleset, event);
|
||||||
testNotMatch(underride_ruleset, event);
|
_testNotMatch(underride_ruleset, event);
|
||||||
testNotMatch(content_ruleset, event);
|
_testNotMatch(content_ruleset, event);
|
||||||
testMatch(room_ruleset, event);
|
_testMatch(room_ruleset, event);
|
||||||
testMatch(sender_ruleset, event);
|
_testMatch(sender_ruleset, event);
|
||||||
|
|
||||||
event.content['body'] = 'aFoXü';
|
event.content['body'] = 'aFoXü';
|
||||||
testNotMatch(override_ruleset, event);
|
_testNotMatch(override_ruleset, event);
|
||||||
testNotMatch(underride_ruleset, event);
|
_testNotMatch(underride_ruleset, event);
|
||||||
testNotMatch(content_ruleset, event);
|
_testNotMatch(content_ruleset, event);
|
||||||
testMatch(room_ruleset, event);
|
_testMatch(room_ruleset, event);
|
||||||
testMatch(sender_ruleset, event);
|
_testMatch(sender_ruleset, event);
|
||||||
|
|
||||||
final override_ruleset2 = PushRuleSet(
|
final override_ruleset2 = PushRuleSet(
|
||||||
override: [
|
override: [
|
||||||
|
|
@ -224,22 +224,25 @@ void main() {
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
testMatch(override_ruleset2, event);
|
_testMatch(override_ruleset2, event);
|
||||||
event.senderId = '@nope:server.tld';
|
event.senderId = '@nope:server.tld';
|
||||||
testNotMatch(override_ruleset2, event);
|
_testNotMatch(override_ruleset2, event);
|
||||||
event.senderId = '${senderID}a';
|
event.senderId = '${senderID}a';
|
||||||
testNotMatch(override_ruleset2, event);
|
_testNotMatch(override_ruleset2, event);
|
||||||
event.senderId = 'a$senderID';
|
event.senderId = 'a$senderID';
|
||||||
testNotMatch(override_ruleset2, event);
|
_testNotMatch(override_ruleset2, event);
|
||||||
|
|
||||||
event.senderId = senderID;
|
event.senderId = senderID;
|
||||||
testMatch(override_ruleset2, event);
|
_testMatch(override_ruleset2, event);
|
||||||
override_ruleset2.override?[0].enabled = false;
|
override_ruleset2.override?[0].enabled = false;
|
||||||
testNotMatch(override_ruleset2, event);
|
_testNotMatch(override_ruleset2, event);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('invalid push condition', () async {
|
test('event_property_is rule', () async {
|
||||||
final invalid_ruleset = PushRuleSet(
|
final event = Event.fromJson(jsonObj, room);
|
||||||
|
event.content['body'] = 'Hello fox';
|
||||||
|
|
||||||
|
final ruleset = PushRuleSet(
|
||||||
override: [
|
override: [
|
||||||
PushRule(
|
PushRule(
|
||||||
ruleId: 'my.rule',
|
ruleId: 'my.rule',
|
||||||
|
|
@ -252,26 +255,81 @@ void main() {
|
||||||
],
|
],
|
||||||
conditions: [
|
conditions: [
|
||||||
PushCondition(
|
PushCondition(
|
||||||
kind: 'invalidcondition',
|
kind: 'event_property_is',
|
||||||
pattern: 'fox',
|
|
||||||
key: 'content.body',
|
key: 'content.body',
|
||||||
|
value: 'Hello fox',
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(
|
_testMatch(ruleset, event);
|
||||||
() => PushruleEvaluator.fromRuleset(invalid_ruleset),
|
|
||||||
returnsNormally,
|
event.content['body'] = 'Hello Fox';
|
||||||
|
_testNotMatch(ruleset, event);
|
||||||
|
|
||||||
|
event.content['body'] = null;
|
||||||
|
ruleset.override?[0].conditions?[0].value = null;
|
||||||
|
_testMatch(ruleset, event);
|
||||||
|
|
||||||
|
event.content['body'] = true;
|
||||||
|
_testNotMatch(ruleset, event);
|
||||||
|
|
||||||
|
ruleset.override?[0].conditions?[0].value = true;
|
||||||
|
_testMatch(ruleset, event);
|
||||||
|
|
||||||
|
event.content['body'] = 12345;
|
||||||
|
_testNotMatch(ruleset, event);
|
||||||
|
|
||||||
|
ruleset.override?[0].conditions?[0].value = 12345;
|
||||||
|
_testMatch(ruleset, event);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('event_property_contains rule', () async {
|
||||||
|
final event = Event.fromJson(jsonObj, room);
|
||||||
|
|
||||||
|
final ruleset = PushRuleSet(
|
||||||
|
override: [
|
||||||
|
PushRule(
|
||||||
|
ruleId: 'my.rule',
|
||||||
|
default$: false,
|
||||||
|
enabled: true,
|
||||||
|
actions: [
|
||||||
|
'notify',
|
||||||
|
{'set_tweak': 'highlight', 'value': true},
|
||||||
|
{'set_tweak': 'sound', 'value': 'goose.wav'},
|
||||||
|
],
|
||||||
|
conditions: [
|
||||||
|
PushCondition(
|
||||||
|
kind: 'event_property_contains',
|
||||||
|
key: 'content.body',
|
||||||
|
value: 'Fox',
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
final evaluator = PushruleEvaluator.fromRuleset(invalid_ruleset);
|
_testNotMatch(ruleset, event);
|
||||||
final event = Event.fromJson(jsonObj, room);
|
|
||||||
final actions = evaluator.match(event);
|
event.content['body'] = [];
|
||||||
expect(actions.highlight, false);
|
_testNotMatch(ruleset, event);
|
||||||
expect(actions.sound, null);
|
|
||||||
expect(actions.notify, false);
|
event.content['body'] = null;
|
||||||
|
_testNotMatch(ruleset, event);
|
||||||
|
|
||||||
|
event.content['body'] = ['Fox'];
|
||||||
|
_testMatch(ruleset, event);
|
||||||
|
|
||||||
|
ruleset.override?[0].conditions?[0].value = true;
|
||||||
|
_testNotMatch(ruleset, event);
|
||||||
|
|
||||||
|
event.content['body'] = [12345, true];
|
||||||
|
_testMatch(ruleset, event);
|
||||||
|
|
||||||
|
ruleset.override?[0].conditions?[0].value = 12345;
|
||||||
|
_testMatch(ruleset, event);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('match_display_name rule', () async {
|
test('match_display_name rule', () async {
|
||||||
|
|
@ -306,17 +364,12 @@ void main() {
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
event.content['body'] = 'äNicoü';
|
|
||||||
|
|
||||||
final evaluator = PushruleEvaluator.fromRuleset(ruleset);
|
event.content['body'] = 'äNicoü';
|
||||||
var actions = evaluator.match(event);
|
_testMatch(ruleset, event);
|
||||||
expect(actions.notify, true);
|
|
||||||
expect(actions.highlight, true);
|
|
||||||
expect(actions.sound, 'goose.wav');
|
|
||||||
|
|
||||||
event.content['body'] = 'äNicou';
|
event.content['body'] = 'äNicou';
|
||||||
actions = evaluator.match(event);
|
_testNotMatch(ruleset, event);
|
||||||
expect(actions.notify, false);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test('member_count rule', () async {
|
test('member_count rule', () async {
|
||||||
|
|
@ -352,33 +405,25 @@ void main() {
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
event.content['body'] = 'äNicoü';
|
event.content['body'] = 'äNicoü';
|
||||||
|
_testMatch(ruleset, event);
|
||||||
var evaluator = PushruleEvaluator.fromRuleset(ruleset);
|
|
||||||
expect(evaluator.match(event).notify, true);
|
|
||||||
|
|
||||||
ruleset.override?[0].conditions?[0].is$ = '<=0';
|
ruleset.override?[0].conditions?[0].is$ = '<=0';
|
||||||
evaluator = PushruleEvaluator.fromRuleset(ruleset);
|
_testNotMatch(ruleset, event);
|
||||||
expect(evaluator.match(event).notify, false);
|
|
||||||
|
|
||||||
ruleset.override?[0].conditions?[0].is$ = '<=1';
|
ruleset.override?[0].conditions?[0].is$ = '<=1';
|
||||||
evaluator = PushruleEvaluator.fromRuleset(ruleset);
|
_testMatch(ruleset, event);
|
||||||
expect(evaluator.match(event).notify, true);
|
|
||||||
|
|
||||||
ruleset.override?[0].conditions?[0].is$ = '>=1';
|
ruleset.override?[0].conditions?[0].is$ = '>=1';
|
||||||
evaluator = PushruleEvaluator.fromRuleset(ruleset);
|
_testMatch(ruleset, event);
|
||||||
expect(evaluator.match(event).notify, true);
|
|
||||||
|
|
||||||
ruleset.override?[0].conditions?[0].is$ = '>1';
|
ruleset.override?[0].conditions?[0].is$ = '>1';
|
||||||
evaluator = PushruleEvaluator.fromRuleset(ruleset);
|
_testNotMatch(ruleset, event);
|
||||||
expect(evaluator.match(event).notify, false);
|
|
||||||
|
|
||||||
ruleset.override?[0].conditions?[0].is$ = '==1';
|
ruleset.override?[0].conditions?[0].is$ = '==1';
|
||||||
evaluator = PushruleEvaluator.fromRuleset(ruleset);
|
_testMatch(ruleset, event);
|
||||||
expect(evaluator.match(event).notify, true);
|
|
||||||
|
|
||||||
ruleset.override?[0].conditions?[0].is$ = '1';
|
ruleset.override?[0].conditions?[0].is$ = '1';
|
||||||
evaluator = PushruleEvaluator.fromRuleset(ruleset);
|
_testMatch(ruleset, event);
|
||||||
expect(evaluator.match(event).notify, true);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test('notification permissions rule', () async {
|
test('notification permissions rule', () async {
|
||||||
|
|
@ -420,11 +465,42 @@ void main() {
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
final evaluator = PushruleEvaluator.fromRuleset(ruleset);
|
_testMatch(ruleset, event);
|
||||||
expect(evaluator.match(event).notify, true);
|
|
||||||
|
|
||||||
event.senderId = '@a:b.c';
|
event.senderId = '@a:b.c';
|
||||||
expect(evaluator.match(event).notify, false);
|
_testNotMatch(ruleset, event);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('invalid push condition', () async {
|
||||||
|
final invalid_ruleset = PushRuleSet(
|
||||||
|
override: [
|
||||||
|
PushRule(
|
||||||
|
ruleId: 'my.rule',
|
||||||
|
default$: false,
|
||||||
|
enabled: true,
|
||||||
|
actions: [
|
||||||
|
'notify',
|
||||||
|
{'set_tweak': 'highlight', 'value': true},
|
||||||
|
{'set_tweak': 'sound', 'value': 'goose.wav'},
|
||||||
|
],
|
||||||
|
conditions: [
|
||||||
|
PushCondition(
|
||||||
|
kind: 'invalidcondition',
|
||||||
|
pattern: 'fox',
|
||||||
|
key: 'content.body',
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
() => PushruleEvaluator.fromRuleset(invalid_ruleset),
|
||||||
|
returnsNormally,
|
||||||
|
);
|
||||||
|
|
||||||
|
final event = Event.fromJson(jsonObj, room);
|
||||||
|
_testNotMatch(invalid_ruleset, event);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('invalid content rule', () async {
|
test('invalid content rule', () async {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue