Merge branch 'room-enhance-push-rules' into 'master'

[Room] New push rule methods

Closes #13

See merge request famedly/famedlysdk!132
This commit is contained in:
Christian Pauly 2019-12-04 09:58:47 +00:00
commit a9a1a5ddd5
5 changed files with 351 additions and 7 deletions

View file

@ -852,4 +852,107 @@ class Room {
return ownPowerLevel >= return ownPowerLevel >=
getState("m.room.power_levels").content["events"][eventType]; getState("m.room.power_levels").content["events"][eventType];
} }
/// Returns the [PushRuleState] for this room, based on the m.push_rules stored in
/// the account_data.
PushRuleState get pushRuleState {
if (!client.accountData.containsKey("m.push_rules") ||
!(client.accountData["m.push_rules"].content["global"] is Map))
return PushRuleState.notify;
final Map<String, dynamic> globalPushRules =
client.accountData["m.push_rules"].content["global"];
if (globalPushRules == null) return PushRuleState.notify;
if (globalPushRules["override"] is List) {
for (var i = 0; i < globalPushRules["override"].length; i++) {
if (globalPushRules["override"][i]["rule_id"] == id) {
if (globalPushRules["override"][i]["actions"]
.indexOf("dont_notify") !=
-1) {
return PushRuleState.dont_notify;
}
break;
}
}
}
if (globalPushRules["room"] is List) {
for (var i = 0; i < globalPushRules["room"].length; i++) {
if (globalPushRules["room"][i]["rule_id"] == id) {
if (globalPushRules["room"][i]["actions"].indexOf("dont_notify") !=
-1) {
return PushRuleState.mentions_only;
}
break;
}
}
}
return PushRuleState.notify;
}
/// Sends a request to the homeserver to set the [PushRuleState] for this room.
/// Returns ErrorResponse if something goes wrong.
Future<dynamic> setPushRuleState(PushRuleState newState) async {
if (newState == pushRuleState) return null;
dynamic resp;
switch (newState) {
// All push notifications should be sent to the user
case PushRuleState.notify:
if (pushRuleState == PushRuleState.dont_notify)
resp = await client.connection.jsonRequest(
type: HTTPType.DELETE,
action: "/client/r0/pushrules/global/override/$id",
data: {});
else if (pushRuleState == PushRuleState.mentions_only)
resp = await client.connection.jsonRequest(
type: HTTPType.DELETE,
action: "/client/r0/pushrules/global/room/$id",
data: {});
break;
// Only when someone mentions the user, a push notification should be sent
case PushRuleState.mentions_only:
if (pushRuleState == PushRuleState.dont_notify) {
resp = await client.connection.jsonRequest(
type: HTTPType.DELETE,
action: "/client/r0/pushrules/global/override/$id",
data: {});
if (resp == ErrorResponse) return resp;
resp = await client.connection.jsonRequest(
type: HTTPType.PUT,
action: "/client/r0/pushrules/global/room/$id",
data: {
"actions": ["dont_notify"]
});
} else if (pushRuleState == PushRuleState.notify)
resp = await client.connection.jsonRequest(
type: HTTPType.PUT,
action: "/client/r0/pushrules/global/room/$id",
data: {
"actions": ["dont_notify"]
});
break;
// No push notification should be ever sent for this room.
case PushRuleState.dont_notify:
if (pushRuleState == PushRuleState.mentions_only) {
resp = await client.connection.jsonRequest(
type: HTTPType.DELETE,
action: "/client/r0/pushrules/global/room/$id",
data: {});
if (resp == ErrorResponse) return resp;
}
resp = await client.connection.jsonRequest(
type: HTTPType.PUT,
action: "/client/r0/pushrules/global/override/$id",
data: {
"actions": ["dont_notify"],
"conditions": [
{"key": "room_id", "kind": "event_match", "pattern": id}
]
});
}
return resp;
}
} }
enum PushRuleState { notify, mentions_only, dont_notify }

View file

@ -0,0 +1,64 @@
class PushRule {
final String ruleId;
final bool isDefault;
final bool enabled;
final List<Conditions> conditions;
final List<dynamic> actions;
PushRule(
{this.ruleId,
this.isDefault,
this.enabled,
this.conditions,
this.actions});
PushRule.fromJson(Map<String, dynamic> json)
: ruleId = json['rule_id'],
isDefault = json['is_default'],
enabled = json['enabled'],
conditions = _getConditionsFromJson(json['conditions']),
actions = json['actions'];
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['rule_id'] = this.ruleId;
data['is_default'] = this.isDefault;
data['enabled'] = this.enabled;
if (this.conditions != null) {
data['conditions'] = this.conditions.map((v) => v.toJson()).toList();
}
data['actions'] = this.actions;
return data;
}
static List<Conditions> _getConditionsFromJson(List<dynamic> json) {
List<Conditions> conditions = [];
if (json == null) return conditions;
for (int i = 0; i < json.length; i++) {
conditions.add(Conditions.fromJson(json[i]));
}
return conditions;
}
}
class Conditions {
String key;
String kind;
String pattern;
Conditions({this.key, this.kind, this.pattern});
Conditions.fromJson(Map<String, dynamic> json) {
key = json['key'];
kind = json['kind'];
pattern = json['pattern'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['key'] = this.key;
data['kind'] = this.kind;
data['pattern'] = this.pattern;
return data;
}
}

View file

@ -120,7 +120,7 @@ void main() {
expect(firstSync, true); expect(firstSync, true);
expect(sync["next_batch"] == matrix.prevBatch, true); expect(sync["next_batch"] == matrix.prevBatch, true);
expect(matrix.accountData.length, 2); expect(matrix.accountData.length, 3);
expect(matrix.getDirectChatFromUserId("@bob:example.com"), expect(matrix.getDirectChatFromUserId("@bob:example.com"),
"!726s6s6q:example.com"); "!726s6s6q:example.com");
expect(matrix.roomList.rooms[1].directChatMatrixID, "@bob:example.com"); expect(matrix.roomList.rooms[1].directChatMatrixID, "@bob:example.com");
@ -147,7 +147,7 @@ void main() {
expect( expect(
matrix.presences["@alice:example.com"].presence, PresenceType.online); matrix.presences["@alice:example.com"].presence, PresenceType.online);
expect(presenceCounter, 1); expect(presenceCounter, 1);
expect(accountDataCounter, 2); expect(accountDataCounter, 3);
matrix.connection.onEvent.add( matrix.connection.onEvent.add(
EventUpdate( EventUpdate(
@ -283,13 +283,16 @@ void main() {
List<UserUpdate> eventUpdateList = await userUpdateListFuture; List<UserUpdate> eventUpdateList = await userUpdateListFuture;
expect(eventUpdateList.length, 4); expect(eventUpdateList.length, 5);
expect(eventUpdateList[0].eventType == "m.presence", true); expect(eventUpdateList[0].eventType, "m.presence");
expect(eventUpdateList[0].type == "presence", true); expect(eventUpdateList[0].type, "presence");
expect(eventUpdateList[1].eventType == "org.example.custom.config", true); expect(eventUpdateList[1].eventType, "m.push_rules");
expect(eventUpdateList[1].type == "account_data", true); expect(eventUpdateList[1].type, "account_data");
expect(eventUpdateList[2].eventType, "org.example.custom.config");
expect(eventUpdateList[2].type, "account_data");
}); });
test('Login', () async { test('Login', () async {

View file

@ -75,6 +75,173 @@ class FakeMatrixApi extends MockClient {
}, },
"account_data": { "account_data": {
"events": [ "events": [
{
"content": {
"global": {
"content": [
{
"actions": [
"notify",
{"set_tweak": "sound", "value": "default"},
{"set_tweak": "highlight"}
],
"default": true,
"enabled": true,
"pattern": "alice",
"rule_id": ".m.rule.contains_user_name"
}
],
"override": [
{
"actions": ["dont_notify"],
"conditions": [],
"default": true,
"enabled": false,
"rule_id": ".m.rule.master"
},
{
"actions": ["dont_notify"],
"conditions": [
{
"key": "content.msgtype",
"kind": "event_match",
"pattern": "m.notice"
}
],
"default": true,
"enabled": true,
"rule_id": ".m.rule.suppress_notices"
}
],
"room": [
{
"actions": ["dont_notify"],
"conditions": [
{
"key": "room_id",
"kind": "event_match",
"pattern": "!localpart:server.abc",
}
],
"default": true,
"enabled": true,
"rule_id": "!localpart:server.abc"
}
],
"sender": [],
"underride": [
{
"actions": [
"notify",
{"set_tweak": "sound", "value": "ring"},
{"set_tweak": "highlight", "value": false}
],
"conditions": [
{
"key": "type",
"kind": "event_match",
"pattern": "m.call.invite"
}
],
"default": true,
"enabled": true,
"rule_id": ".m.rule.call"
},
{
"actions": [
"notify",
{"set_tweak": "sound", "value": "default"},
{"set_tweak": "highlight"}
],
"conditions": [
{"kind": "contains_display_name"}
],
"default": true,
"enabled": true,
"rule_id": ".m.rule.contains_display_name"
},
{
"actions": [
"notify",
{"set_tweak": "sound", "value": "default"},
{"set_tweak": "highlight", "value": false}
],
"conditions": [
{"is": "2", "kind": "room_member_count"},
{
"key": "type",
"kind": "event_match",
"pattern": "m.room.message"
}
],
"default": true,
"enabled": true,
"rule_id": ".m.rule.room_one_to_one"
},
{
"actions": [
"notify",
{"set_tweak": "sound", "value": "default"},
{"set_tweak": "highlight", "value": false}
],
"conditions": [
{
"key": "type",
"kind": "event_match",
"pattern": "m.room.member"
},
{
"key": "content.membership",
"kind": "event_match",
"pattern": "invite"
},
{
"key": "state_key",
"kind": "event_match",
"pattern": "@alice:example.com"
}
],
"default": true,
"enabled": true,
"rule_id": ".m.rule.invite_for_me"
},
{
"actions": [
"notify",
{"set_tweak": "highlight", "value": false}
],
"conditions": [
{
"key": "type",
"kind": "event_match",
"pattern": "m.room.member"
}
],
"default": true,
"enabled": true,
"rule_id": ".m.rule.member_event"
},
{
"actions": [
"notify",
{"set_tweak": "highlight", "value": false}
],
"conditions": [
{
"key": "type",
"kind": "event_match",
"pattern": "m.room.message"
}
],
"default": true,
"enabled": true,
"rule_id": ".m.rule.message"
}
]
}
},
"type": "m.push_rules"
},
{ {
"type": "org.example.custom.config", "type": "org.example.custom.config",
"content": {"custom_config_key": "custom_config_value"} "content": {"custom_config_key": "custom_config_value"}

View file

@ -335,5 +335,12 @@ void main() {
await room.sendFileEvent(testFile, "m.file", txid: "testtxid"); await room.sendFileEvent(testFile, "m.file", txid: "testtxid");
expect(resp, "42"); expect(resp, "42");
}); });
test('pushRuleState', () async {
expect(room.pushRuleState, PushRuleState.mentions_only);
matrix.accountData["m.push_rules"].content["global"]["override"]
.add(matrix.accountData["m.push_rules"].content["global"]["room"][0]);
expect(room.pushRuleState, PushRuleState.dont_notify);
});
}); });
} }