Merge branch 'pushrules' into 'master'

Add GET Pushrules Endpoint

See merge request famedly/famedlysdk!10
This commit is contained in:
Christian 2019-06-21 07:41:09 +00:00
commit 116a644a0e
8 changed files with 708 additions and 1 deletions

View file

@ -64,3 +64,13 @@ final resp = await matrix.connection.jsonRequest(
}
);
```
## Development
### Regenerating JSON Classes
To regenerate the part files of JSON Classes you need to run this command:
```bash
flutter pub run build_runner build
```

View file

@ -27,6 +27,7 @@ import 'responses/ErrorResponse.dart';
import 'Connection.dart';
import 'Store.dart';
import 'User.dart';
import 'responses/PushrulesResponse.dart';
/// Represents a Matrix client to communicate with a
/// [Matrix](https://matrix.org) homeserver and is the entry point for this
@ -206,4 +207,20 @@ class Client {
return resp["room_id"];
}
/// Fetches the pushrules for the logged in user.
/// These are needed for notifications on Android
Future<PushrulesResponse> getPushrules() async {
final dynamic resp = await connection.jsonRequest(
type: "GET",
action: "/client/r0/pushrules",
);
if (resp is ErrorResponse) {
connection.onError.add(resp);
return null;
}
return PushrulesResponse.fromJson(resp);
}
}

View file

@ -0,0 +1,111 @@
/*
* Copyright (c) 2019 Zender & Kurtz GbR.
*
* Authors:
* Christian Pauly <krille@famedly.com>
* Marcel Radzio <mtrnord@famedly.com>
*
* This file is part of famedlysdk.
*
* famedlysdk is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* famedlysdk is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with famedly. If not, see <http://www.gnu.org/licenses/>.
*/
import 'package:json_annotation/json_annotation.dart';
part 'PushrulesResponse.g.dart';
@JsonSerializable(explicitToJson: true, nullable: false)
class PushrulesResponse {
@JsonKey(nullable: false)
Global global;
PushrulesResponse(
this.global,
);
factory PushrulesResponse.fromJson(Map<String, dynamic> json) =>
_$PushrulesResponseFromJson(json);
Map<String, dynamic> toJson() => _$PushrulesResponseToJson(this);
}
@JsonSerializable(explicitToJson: true)
class Global {
List<PushRule> content;
List<PushRule> room;
List<PushRule> sender;
List<PushRule> override;
List<PushRule> underride;
Global(
this.content,
this.room,
this.sender,
this.override,
this.underride,
);
factory Global.fromJson(Map<String, dynamic> json) => _$GlobalFromJson(json);
Map<String, dynamic> toJson() => _$GlobalToJson(this);
}
@JsonSerializable(explicitToJson: true)
class PushRule {
@JsonKey(nullable: false)
List<dynamic> actions;
List<Condition> conditions;
@JsonKey(nullable: false, name: "default")
bool contentDefault;
@JsonKey(nullable: false)
bool enabled;
@JsonKey(nullable: false)
String ruleId;
String pattern;
PushRule(
this.actions,
this.conditions,
this.contentDefault,
this.enabled,
this.ruleId,
this.pattern,
);
factory PushRule.fromJson(Map<String, dynamic> json) =>
_$PushRuleFromJson(json);
Map<String, dynamic> toJson() => _$PushRuleToJson(this);
}
@JsonSerializable(explicitToJson: true)
class Condition {
String key;
@JsonKey(name: "is")
String conditionIs;
@JsonKey(nullable: false)
String kind;
String pattern;
Condition(
this.key,
this.conditionIs,
this.kind,
this.pattern,
);
factory Condition.fromJson(Map<String, dynamic> json) =>
_$ConditionFromJson(json);
Map<String, dynamic> toJson() => _$ConditionToJson(this);
}

View file

@ -0,0 +1,81 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'PushrulesResponse.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
PushrulesResponse _$PushrulesResponseFromJson(Map<String, dynamic> json) {
return PushrulesResponse(
Global.fromJson(json['global'] as Map<String, dynamic>));
}
Map<String, dynamic> _$PushrulesResponseToJson(PushrulesResponse instance) =>
<String, dynamic>{'global': instance.global.toJson()};
Global _$GlobalFromJson(Map<String, dynamic> json) {
return Global(
(json['content'] as List)
?.map((e) =>
e == null ? null : PushRule.fromJson(e as Map<String, dynamic>))
?.toList(),
(json['room'] as List)
?.map((e) =>
e == null ? null : PushRule.fromJson(e as Map<String, dynamic>))
?.toList(),
(json['sender'] as List)
?.map((e) =>
e == null ? null : PushRule.fromJson(e as Map<String, dynamic>))
?.toList(),
(json['override'] as List)
?.map((e) =>
e == null ? null : PushRule.fromJson(e as Map<String, dynamic>))
?.toList(),
(json['underride'] as List)
?.map((e) =>
e == null ? null : PushRule.fromJson(e as Map<String, dynamic>))
?.toList());
}
Map<String, dynamic> _$GlobalToJson(Global instance) => <String, dynamic>{
'content': instance.content?.map((e) => e?.toJson())?.toList(),
'room': instance.room?.map((e) => e?.toJson())?.toList(),
'sender': instance.sender?.map((e) => e?.toJson())?.toList(),
'override': instance.override?.map((e) => e?.toJson())?.toList(),
'underride': instance.underride?.map((e) => e?.toJson())?.toList()
};
PushRule _$PushRuleFromJson(Map<String, dynamic> json) {
return PushRule(
json['actions'] as List,
(json['conditions'] as List)
?.map((e) =>
e == null ? null : Condition.fromJson(e as Map<String, dynamic>))
?.toList(),
json['default'] as bool,
json['enabled'] as bool,
json['ruleId'] as String,
json['pattern'] as String);
}
Map<String, dynamic> _$PushRuleToJson(PushRule instance) => <String, dynamic>{
'actions': instance.actions,
'conditions': instance.conditions?.map((e) => e?.toJson())?.toList(),
'default': instance.contentDefault,
'enabled': instance.enabled,
'ruleId': instance.ruleId,
'pattern': instance.pattern
};
Condition _$ConditionFromJson(Map<String, dynamic> json) {
return Condition(json['key'] as String, json['is'] as String,
json['kind'] as String, json['pattern'] as String);
}
Map<String, dynamic> _$ConditionToJson(Condition instance) => <String, dynamic>{
'key': instance.key,
'is': instance.conditionIs,
'kind': instance.kind,
'pattern': instance.pattern
};

View file

@ -1,6 +1,20 @@
# Generated by pub
# See https://www.dartlang.org/tools/pub/glossary#lockfile
packages:
analyzer:
dependency: transitive
description:
name: analyzer
url: "https://pub.dartlang.org"
source: hosted
version: "0.36.3"
args:
dependency: transitive
description:
name: args
url: "https://pub.dartlang.org"
source: hosted
version: "1.5.2"
async:
dependency: transitive
description:
@ -15,6 +29,62 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.4"
build:
dependency: transitive
description:
name: build
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.4"
build_config:
dependency: transitive
description:
name: build_config
url: "https://pub.dartlang.org"
source: hosted
version: "0.4.0"
build_daemon:
dependency: transitive
description:
name: build_daemon
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.0"
build_resolvers:
dependency: transitive
description:
name: build_resolvers
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.5"
build_runner:
dependency: "direct dev"
description:
name: build_runner
url: "https://pub.dartlang.org"
source: hosted
version: "1.5.2"
build_runner_core:
dependency: transitive
description:
name: build_runner_core
url: "https://pub.dartlang.org"
source: hosted
version: "3.0.6"
built_collection:
dependency: transitive
description:
name: built_collection
url: "https://pub.dartlang.org"
source: hosted
version: "4.2.2"
built_value:
dependency: transitive
description:
name: built_value
url: "https://pub.dartlang.org"
source: hosted
version: "6.6.0"
charcode:
dependency: transitive
description:
@ -22,6 +92,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.2"
code_builder:
dependency: transitive
description:
name: code_builder
url: "https://pub.dartlang.org"
source: hosted
version: "3.2.0"
collection:
dependency: transitive
description:
@ -29,6 +106,41 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "1.14.11"
convert:
dependency: transitive
description:
name: convert
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.1"
crypto:
dependency: transitive
description:
name: crypto
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.6"
csslib:
dependency: transitive
description:
name: csslib
url: "https://pub.dartlang.org"
source: hosted
version: "0.16.0"
dart_style:
dependency: transitive
description:
name: dart_style
url: "https://pub.dartlang.org"
source: hosted
version: "1.2.7"
fixnum:
dependency: transitive
description:
name: fixnum
url: "https://pub.dartlang.org"
source: hosted
version: "0.10.9"
flutter:
dependency: "direct main"
description: flutter
@ -39,6 +151,34 @@ packages:
description: flutter
source: sdk
version: "0.0.0"
front_end:
dependency: transitive
description:
name: front_end
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.18"
glob:
dependency: transitive
description:
name: glob
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.7"
graphs:
dependency: transitive
description:
name: graphs
url: "https://pub.dartlang.org"
source: hosted
version: "0.2.0"
html:
dependency: transitive
description:
name: html
url: "https://pub.dartlang.org"
source: hosted
version: "0.14.0+2"
http:
dependency: "direct main"
description:
@ -46,6 +186,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "0.12.0+2"
http_multi_server:
dependency: transitive
description:
name: http_multi_server
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.0"
http_parser:
dependency: transitive
description:
@ -60,6 +207,48 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "0.15.8"
io:
dependency: transitive
description:
name: io
url: "https://pub.dartlang.org"
source: hosted
version: "0.3.3"
js:
dependency: transitive
description:
name: js
url: "https://pub.dartlang.org"
source: hosted
version: "0.6.1+1"
json_annotation:
dependency: "direct main"
description:
name: json_annotation
url: "https://pub.dartlang.org"
source: hosted
version: "2.4.0"
json_serializable:
dependency: "direct dev"
description:
name: json_serializable
url: "https://pub.dartlang.org"
source: hosted
version: "3.0.0"
kernel:
dependency: transitive
description:
name: kernel
url: "https://pub.dartlang.org"
source: hosted
version: "0.3.18"
logging:
dependency: transitive
description:
name: logging
url: "https://pub.dartlang.org"
source: hosted
version: "0.11.3+2"
matcher:
dependency: transitive
description:
@ -74,6 +263,27 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.6"
mime:
dependency: transitive
description:
name: mime
url: "https://pub.dartlang.org"
source: hosted
version: "0.9.6+3"
package_config:
dependency: transitive
description:
name: package_config
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.5"
package_resolver:
dependency: transitive
description:
name: package_resolver
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.10"
path:
dependency: "direct main"
description:
@ -88,6 +298,27 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "1.5.0"
pool:
dependency: transitive
description:
name: pool
url: "https://pub.dartlang.org"
source: hosted
version: "1.4.0"
pub_semver:
dependency: transitive
description:
name: pub_semver
url: "https://pub.dartlang.org"
source: hosted
version: "1.4.2"
pubspec_parse:
dependency: transitive
description:
name: pubspec_parse
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.4"
quiver:
dependency: transitive
description:
@ -95,11 +326,32 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.2"
shelf:
dependency: transitive
description:
name: shelf
url: "https://pub.dartlang.org"
source: hosted
version: "0.7.5"
shelf_web_socket:
dependency: transitive
description:
name: shelf_web_socket
url: "https://pub.dartlang.org"
source: hosted
version: "0.2.3"
sky_engine:
dependency: transitive
description: flutter
source: sdk
version: "0.0.99"
source_gen:
dependency: transitive
description:
name: source_gen
url: "https://pub.dartlang.org"
source: hosted
version: "0.9.4+2"
source_span:
dependency: transitive
description:
@ -128,6 +380,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.0"
stream_transform:
dependency: transitive
description:
name: stream_transform
url: "https://pub.dartlang.org"
source: hosted
version: "0.0.19"
string_scanner:
dependency: transitive
description:
@ -156,6 +415,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "0.2.4"
timing:
dependency: transitive
description:
name: timing
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.1+1"
typed_data:
dependency: transitive
description:
@ -170,6 +436,27 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.8"
watcher:
dependency: transitive
description:
name: watcher
url: "https://pub.dartlang.org"
source: hosted
version: "0.9.7+10"
web_socket_channel:
dependency: transitive
description:
name: web_socket_channel
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.13"
yaml:
dependency: transitive
description:
name: yaml
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.16"
sdks:
dart: ">=2.2.0 <3.0.0"
dart: ">=2.3.0-dev.0.1 <3.0.0"
flutter: ">=1.2.1 <2.0.0"

View file

@ -21,10 +21,15 @@ dependencies:
# Time formatting
intl: ^0.15.8
json_annotation: ^2.4.0
dev_dependencies:
flutter_test:
sdk: flutter
build_runner: ^1.5.2
json_serializable: ^3.0.0
# For information on the generic Dart part of this file, see the
# following page: https://www.dartlang.org/tools/pub/pubspec

View file

@ -21,6 +21,7 @@
* along with Foobar. If not, see <http://www.gnu.org/licenses/>.
*/
import 'package:famedlysdk/src/responses/PushrulesResponse.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:famedlysdk/src/Client.dart';
import 'package:famedlysdk/src/Connection.dart';
@ -238,6 +239,13 @@ void main() {
expect(newID, "!1234:fakeServer.notExisting");
});
test('getPushrules', () async {
final PushrulesResponse pushrules = await matrix.getPushrules();
final PushrulesResponse awaited_resp = PushrulesResponse.fromJson(
FakeMatrixApi.api["GET"]["/client/r0/pushrules"](""));
expect(pushrules.toJson(), awaited_resp.toJson());
});
test('Logout when token is unknown', () async {
Future<LoginState> loginStateFuture =
matrix.connection.onLoginStateChanged.stream.first;

View file

@ -89,6 +89,194 @@ class FakeMatrixApi extends MockClient {
}
]
},
"/client/r0/pushrules": (var req) => {
"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": [],
"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"
}
],
"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"
}
]
}
},
"/client/r0/sync": (var req) => {
"next_batch": Random().nextDouble().toString(),
"presence": {