From f08003b0e75c345ad2d9f8f63f4d135e7f7377ec Mon Sep 17 00:00:00 2001 From: Dat PHAM HOANG Date: Mon, 28 Jun 2021 11:14:48 +0700 Subject: [PATCH 01/20] Implement Invocation object --- lib/jmap/core/capability.dart | 14 ++++++++++++++ lib/jmap/core/invocation.dart | 36 +++++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+) create mode 100644 lib/jmap/core/capability.dart create mode 100644 lib/jmap/core/invocation.dart diff --git a/lib/jmap/core/capability.dart b/lib/jmap/core/capability.dart new file mode 100644 index 0000000..d761aac --- /dev/null +++ b/lib/jmap/core/capability.dart @@ -0,0 +1,14 @@ +import 'package:equatable/equatable.dart'; + +class CapabilityIdentifier with EquatableMixin { + static final jmapCore = CapabilityIdentifier('urn:ietf:params:jmap:core'); + static final jmapMail = CapabilityIdentifier('urn:ietf:params:jmap:mail'); + + final String value; + + CapabilityIdentifier(this.value); + + @override + List get props => [value]; +} + diff --git a/lib/jmap/core/invocation.dart b/lib/jmap/core/invocation.dart new file mode 100644 index 0000000..b555c9d --- /dev/null +++ b/lib/jmap/core/invocation.dart @@ -0,0 +1,36 @@ +import 'package:equatable/equatable.dart'; + +class Invocation { + final MethodName methodName; + final Arguments arguments; + final MethodCallId methodCallId; + + Invocation(this.methodName, this.arguments, this.methodCallId); +} + +class MethodName with EquatableMixin { + final String value; + + MethodName(this.value); + + @override + List get props => [value]; +} + +class Arguments with EquatableMixin { + final T value; + + Arguments(this.value); + + @override + List get props => [value]; +} + +class MethodCallId with EquatableMixin { + final String value; + + MethodCallId(this.value); + + @override + List get props => [value]; +} \ No newline at end of file From 67fdd7408ceb41997faea5475f08b85b8092b14c Mon Sep 17 00:00:00 2001 From: Dat PHAM HOANG Date: Mon, 28 Jun 2021 11:32:49 +0700 Subject: [PATCH 02/20] Implement RequestObject --- lib/jmap/core/request/ready_to_build.dart | 5 +++ lib/jmap/core/request/request_object.dart | 33 +++++++++++++++++++ .../core/request/require_method_call.dart | 13 ++++++++ lib/jmap/core/request/require_using.dart | 12 +++++++ lib/jmap/entity/mailbox.dart | 0 5 files changed, 63 insertions(+) create mode 100644 lib/jmap/core/request/ready_to_build.dart create mode 100644 lib/jmap/core/request/request_object.dart create mode 100644 lib/jmap/core/request/require_method_call.dart create mode 100644 lib/jmap/core/request/require_using.dart create mode 100644 lib/jmap/entity/mailbox.dart diff --git a/lib/jmap/core/request/ready_to_build.dart b/lib/jmap/core/request/ready_to_build.dart new file mode 100644 index 0000000..967c59b --- /dev/null +++ b/lib/jmap/core/request/ready_to_build.dart @@ -0,0 +1,5 @@ +import 'package:jmap_dart_client/jmap/core/request/request_object.dart'; + +mixin ReadyToBuild { + RequestObject build(); +} \ No newline at end of file diff --git a/lib/jmap/core/request/request_object.dart b/lib/jmap/core/request/request_object.dart new file mode 100644 index 0000000..c02c344 --- /dev/null +++ b/lib/jmap/core/request/request_object.dart @@ -0,0 +1,33 @@ +import 'package:equatable/equatable.dart'; +import 'package:jmap_dart_client/jmap/core/capability.dart'; +import 'package:jmap_dart_client/jmap/core/invocation.dart' as jmapInvocation; +import 'package:jmap_dart_client/jmap/core/request/ready_to_build.dart'; +import 'package:jmap_dart_client/jmap/core/request/require_method_call.dart'; +import 'package:jmap_dart_client/jmap/core/request/require_using.dart'; + +class RequestObject with EquatableMixin { + final Set using; + final List methodCalls; + + RequestObject(this.using, this.methodCalls); + + @override + List get props => [using, methodCalls]; + + static RequiredUsing builder() { + return RequestObjectBuilder(); + } +} + +class RequestObjectBuilder with RequiredUsing, RequireMethodCall, ReadyToBuild { + + @override + ReadyToBuild ready() { + return this; + } + + @override + RequestObject build() { + return RequestObject(capabilities, invocations); + } +} diff --git a/lib/jmap/core/request/require_method_call.dart b/lib/jmap/core/request/require_method_call.dart new file mode 100644 index 0000000..8b90e1c --- /dev/null +++ b/lib/jmap/core/request/require_method_call.dart @@ -0,0 +1,13 @@ +import 'package:jmap_dart_client/jmap/core/invocation.dart' as jmapInvocation; +import 'package:jmap_dart_client/jmap/core/request/ready_to_build.dart'; + +mixin RequireMethodCall { + final List invocations = List.empty(growable: true); + + RequireMethodCall methodCall(jmapInvocation.Invocation invocation) { + invocations.add(invocation); + return this; + } + + ReadyToBuild ready(); +} \ No newline at end of file diff --git a/lib/jmap/core/request/require_using.dart b/lib/jmap/core/request/require_using.dart new file mode 100644 index 0000000..f28b691 --- /dev/null +++ b/lib/jmap/core/request/require_using.dart @@ -0,0 +1,12 @@ +import 'package:jmap_dart_client/jmap/core/request/require_method_call.dart'; + +import '../capability.dart'; + +mixin RequiredUsing implements RequireMethodCall { + final Set capabilities = Set(); + + RequiredUsing using(CapabilityIdentifier capabilityIdentifier) { + capabilities.add(capabilityIdentifier); + return this; + } +} \ No newline at end of file diff --git a/lib/jmap/entity/mailbox.dart b/lib/jmap/entity/mailbox.dart new file mode 100644 index 0000000..e69de29 From 5a7e839d9acbb3c5945db3267b683d09bef942d5 Mon Sep 17 00:00:00 2001 From: Dat PHAM HOANG Date: Fri, 2 Jul 2021 14:17:34 +0700 Subject: [PATCH 03/20] Add Id, UnsignedInt, Capability, Properties in core --- lib/jmap/account_id.dart | 21 +++++++ lib/jmap/core/capability/capability.dart | 25 ++++++++ lib/jmap/core/id.dart | 16 +++++ lib/jmap/core/properties/properties.dart | 22 +++++++ lib/jmap/core/unsigned_int.dart | 13 ++++ test/jmap/core/id_test.dart | 27 ++++++++ .../jmap/core/properties/properties_test.dart | 61 +++++++++++++++++++ 7 files changed, 185 insertions(+) create mode 100644 lib/jmap/account_id.dart create mode 100644 lib/jmap/core/capability/capability.dart create mode 100644 lib/jmap/core/id.dart create mode 100644 lib/jmap/core/properties/properties.dart create mode 100644 lib/jmap/core/unsigned_int.dart create mode 100644 test/jmap/core/id_test.dart create mode 100644 test/jmap/core/properties/properties_test.dart diff --git a/lib/jmap/account_id.dart b/lib/jmap/account_id.dart new file mode 100644 index 0000000..1161cbf --- /dev/null +++ b/lib/jmap/account_id.dart @@ -0,0 +1,21 @@ +import 'package:equatable/equatable.dart'; +import 'package:jmap_dart_client/http/converter/id_converter.dart'; +import 'package:jmap_dart_client/jmap/core/id.dart'; +import 'package:json_annotation/json_annotation.dart'; + +part 'account_id.g.dart'; + +@IdConverter() +@JsonSerializable() +class AccountId with EquatableMixin { + final Id id; + + AccountId(this.id); + + factory AccountId.fromJson(Map json) => _$AccountIdFromJson(json); + + Map toJson() => _$AccountIdToJson(this); + + @override + List get props => [id]; +} \ No newline at end of file diff --git a/lib/jmap/core/capability/capability.dart b/lib/jmap/core/capability/capability.dart new file mode 100644 index 0000000..140ecdf --- /dev/null +++ b/lib/jmap/core/capability/capability.dart @@ -0,0 +1,25 @@ +import 'package:equatable/equatable.dart'; + +class CapabilityIdentifier with EquatableMixin { + static final jmapCore = CapabilityIdentifier('urn:ietf:params:jmap:core'); + static final jmapMail = CapabilityIdentifier('urn:ietf:params:jmap:mail'); + + final String value; + + CapabilityIdentifier(this.value); + + @override + List get props => [value]; +} + +class CapabilityProperties {} + +abstract class Capability { + final CapabilityIdentifier identifier; + final CapabilityProperties properties; + + Capability(this.identifier, this.properties); +} + + + diff --git a/lib/jmap/core/id.dart b/lib/jmap/core/id.dart new file mode 100644 index 0000000..a2720b7 --- /dev/null +++ b/lib/jmap/core/id.dart @@ -0,0 +1,16 @@ +import 'package:equatable/equatable.dart'; +import 'package:quiver/check.dart'; + +class Id with EquatableMixin { + final RegExp _idCharacterConstraint = RegExp(r'^[a-zA-Z0-9]+[a-zA-Z0-9-_]*$'); + final String value; + + Id(this.value) { + checkArgument(value.isNotEmpty, message: 'invalid length'); + checkArgument(value.length < 255, message: 'invalid length'); + checkArgument(_idCharacterConstraint.hasMatch(value)); + } + + @override + List get props => [value]; +} \ No newline at end of file diff --git a/lib/jmap/core/properties/properties.dart b/lib/jmap/core/properties/properties.dart new file mode 100644 index 0000000..1cd16b6 --- /dev/null +++ b/lib/jmap/core/properties/properties.dart @@ -0,0 +1,22 @@ +import 'package:equatable/equatable.dart'; + +class Properties with EquatableMixin { + final Set value; + + Properties(this.value); + + static Properties empty() => Properties(Set()); + + Properties union(Properties other) => Properties(value.union(other.value)); + + Properties removeAll(Properties other) => Properties(value..removeAll(other.value)); + + bool isEmpty() => value.isEmpty; + + Properties operator +(Properties other) => union(other); + + Properties operator -(Properties other) => removeAll(other); + + @override + List get props => [value]; +} \ No newline at end of file diff --git a/lib/jmap/core/unsigned_int.dart b/lib/jmap/core/unsigned_int.dart new file mode 100644 index 0000000..1d8c382 --- /dev/null +++ b/lib/jmap/core/unsigned_int.dart @@ -0,0 +1,13 @@ +import 'package:quiver/check.dart'; + +class UnsignedInt { + static final defaultValue = UnsignedInt(0); + + final num value; + + // UnsignedInt in range [0...2^53-1]. + UnsignedInt(this.value) { + checkArgument(value >= 0); + checkArgument(value < 9007199254740992); + } +} \ No newline at end of file diff --git a/test/jmap/core/id_test.dart b/test/jmap/core/id_test.dart new file mode 100644 index 0000000..007a55e --- /dev/null +++ b/test/jmap/core/id_test.dart @@ -0,0 +1,27 @@ + +import 'package:flutter_test/flutter_test.dart'; +import 'package:jmap_dart_client/jmap/core/id.dart'; + +void main() { + group('invalid id', () { + test('should throw argument error when the id is empty', () { + expect(() => Id(''), throwsArgumentError); + }); + + test('should throw argument error when the id has length more than 255', () { + expect( + () => Id('a123bde34588799922229339933933933993939393939222a123bde34' + '588799922229339933933933993939393939222a123be3458879992222933993393393' + '3993939393939222a123bde34588799922229339933933933993939393939222a123bd' + 'e34588799922229339933933933993939393939222a123bde345887999222293399339' + '33933993939393939222a123bde34588799922229339933933933993939393939222a1' + '23bde34588799922229339933933933993939393939222'), + throwsArgumentError + ); + }); + + test('should throw argument error when the id start with dash', () { + expect(() => Id('_abe23abc'), throwsArgumentError); + }); + }); +} \ No newline at end of file diff --git a/test/jmap/core/properties/properties_test.dart b/test/jmap/core/properties/properties_test.dart new file mode 100644 index 0000000..bf4c2a0 --- /dev/null +++ b/test/jmap/core/properties/properties_test.dart @@ -0,0 +1,61 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:jmap_dart_client/jmap/core/properties/properties.dart'; + +void main() { + group('test union', () { + test('empty properties should union other properties', () { + final emptyProperties = Properties.empty(); + + expect( + emptyProperties.union(Properties({'id', 'name'})), + equals(Properties({'id', 'name'})) + ); + }); + + test('properties should union other properties', () { + final properties = Properties({'role'}); + final unionProperties = properties.union(Properties({'id', 'name'})); + + expect( + unionProperties, + equals(Properties({'role', 'id', 'name'})) + ); + }); + }); + + group('test removeAll', () { + test('empty properties should not remove anything', () { + final emptyProperties = Properties.empty(); + + expect( + emptyProperties.removeAll(Properties({'id', 'name'})), + equals(emptyProperties) + ); + }); + + test('two-item properties should remove all item when remove three-item properties', () { + final twoItem = Properties({ + 'id', + 'name' + }); + + expect( + twoItem.removeAll(Properties({'id', 'name', 'role'})), + equals(Properties.empty()) + ); + }); + + test('properties can remove all contained items', () { + final properties = Properties({ + 'id', + 'name', + 'role' + }); + + expect( + properties.removeAll(Properties({'id', 'name'})), + equals(Properties({'role'})) + ); + }); + }); +} \ No newline at end of file From 199bf1c1e7d45f95a550f513b97674dabfa02a62 Mon Sep 17 00:00:00 2001 From: Dat PHAM HOANG Date: Tue, 6 Jul 2021 16:16:50 +0700 Subject: [PATCH 04/20] Add gitignore --- .gitignore | 56 +++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 51 insertions(+), 5 deletions(-) diff --git a/.gitignore b/.gitignore index a247422..45dcd86 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ # Miscellaneous *.class +*.lock *.log *.pyc *.swp @@ -15,20 +16,46 @@ *.iws .idea/ -# The .vscode folder contains launch configuration and tasks you configure in -# VS Code which you may wish to be included in version control, so this line -# is commented out by default. -#.vscode/ +# Visual Studio Code related +.classpath +.project +.settings/ +.vscode/ + +# Flutter repo-specific +/bin/cache/ +/bin/mingit/ +/dev/benchmarks/mega_gallery/ +/dev/bots/.recipe_deps +/dev/bots/android_tools/ +/dev/devicelab/ABresults*.json +/dev/docs/doc/ +/dev/docs/flutter.docs.zip +/dev/docs/lib/ +/dev/docs/pubspec.yaml +/dev/integration_tests/**/xcuserdata +/dev/integration_tests/**/Pods +/packages/flutter/coverage/ +version +analysis_benchmark.json + +# packages file containing multi-root paths +.packages.generated # Flutter/Dart/Pub related **/doc/api/ .dart_tool/ .flutter-plugins .flutter-plugins-dependencies +**/generated_plugin_registrant.dart .packages .pub-cache/ .pub/ build/ +flutter_*.png +linked_*.ds +unlinked.ds +unlinked_spec.ds # Android related **/android/**/gradle-wrapper.jar @@ -38,6 +65,8 @@ build/ **/android/gradlew.bat **/android/local.properties **/android/**/GeneratedPluginRegistrant.java +**/android/key.properties +*.jks # iOS/XCode related **/ios/**/*.mode1v3 @@ -56,11 +85,11 @@ build/ **/ios/**/profile **/ios/**/xcuserdata **/ios/.generated/ +**/ios/Flutter/.last_build_id **/ios/Flutter/App.framework **/ios/Flutter/Flutter.framework **/ios/Flutter/Flutter.podspec **/ios/Flutter/Generated.xcconfig -**/ios/Flutter/ephemeral **/ios/Flutter/app.flx **/ios/Flutter/app.zip **/ios/Flutter/flutter_assets/ @@ -68,8 +97,25 @@ build/ **/ios/ServiceDefinitions.json **/ios/Runner/GeneratedPluginRegistrant.* +# macOS +**/macos/Flutter/GeneratedPluginRegistrant.swift +**/macos/Flutter/Flutter-Debug.xcconfig +**/macos/Flutter/Flutter-Release.xcconfig +**/macos/Flutter/Flutter-Profile.xcconfig + +# Coverage +coverage/ + +# Symbols +app.*.symbols + # Exceptions to above rules. !**/ios/**/default.mode1v3 !**/ios/**/default.mode2v3 !**/ios/**/default.pbxuser !**/ios/**/default.perspectivev3 +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages +!/dev/ci/**/Gemfile.lock + +#generated file +*.g.dart \ No newline at end of file From 5dd5e8bbf001977cd3b8ca2ac3b54011cbe6de68 Mon Sep 17 00:00:00 2001 From: Dat PHAM HOANG Date: Tue, 6 Jul 2021 16:18:15 +0700 Subject: [PATCH 05/20] Add RequestObject and Builder for it --- .../request_invocation.dart} | 13 +++++---- lib/jmap/core/request/request_object.dart | 27 ++++++++++--------- .../core/request/require_method_call.dart | 15 +++++------ lib/jmap/core/request/require_using.dart | 15 ++++++----- 4 files changed, 36 insertions(+), 34 deletions(-) rename lib/jmap/core/{invocation.dart => request/request_invocation.dart} (64%) diff --git a/lib/jmap/core/invocation.dart b/lib/jmap/core/request/request_invocation.dart similarity index 64% rename from lib/jmap/core/invocation.dart rename to lib/jmap/core/request/request_invocation.dart index b555c9d..cadebc6 100644 --- a/lib/jmap/core/invocation.dart +++ b/lib/jmap/core/request/request_invocation.dart @@ -1,11 +1,13 @@ import 'package:equatable/equatable.dart'; -class Invocation { +import '../method/method.dart'; + +class RequestInvocation { final MethodName methodName; - final Arguments arguments; + final Arguments arguments; final MethodCallId methodCallId; - Invocation(this.methodName, this.arguments, this.methodCallId); + RequestInvocation(this.methodName, this.arguments, this.methodCallId); } class MethodName with EquatableMixin { @@ -17,13 +19,10 @@ class MethodName with EquatableMixin { List get props => [value]; } -class Arguments with EquatableMixin { +class Arguments { final T value; Arguments(this.value); - - @override - List get props => [value]; } class MethodCallId with EquatableMixin { diff --git a/lib/jmap/core/request/request_object.dart b/lib/jmap/core/request/request_object.dart index c02c344..3153567 100644 --- a/lib/jmap/core/request/request_object.dart +++ b/lib/jmap/core/request/request_object.dart @@ -1,32 +1,35 @@ import 'package:equatable/equatable.dart'; -import 'package:jmap_dart_client/jmap/core/capability.dart'; -import 'package:jmap_dart_client/jmap/core/invocation.dart' as jmapInvocation; -import 'package:jmap_dart_client/jmap/core/request/ready_to_build.dart'; +import 'package:jmap_dart_client/http/converter/capability_identifier_onverter.dart'; +import 'package:jmap_dart_client/http/converter/request_invocation_converter.dart'; +import 'package:jmap_dart_client/jmap/core/capability/capability.dart'; +import 'package:jmap_dart_client/jmap/core/request/request_invocation.dart'; import 'package:jmap_dart_client/jmap/core/request/require_method_call.dart'; import 'package:jmap_dart_client/jmap/core/request/require_using.dart'; +import 'package:json_annotation/json_annotation.dart'; +part 'request_object.g.dart'; + +@CapabilityIdentifierConverter() +@RequestInvocationConverter() +@JsonSerializable() class RequestObject with EquatableMixin { final Set using; - final List methodCalls; + final List methodCalls; RequestObject(this.using, this.methodCalls); @override List get props => [using, methodCalls]; - static RequiredUsing builder() { + Map toJson() => _$RequestObjectToJson(this); + + static RequestObjectBuilder builder() { return RequestObjectBuilder(); } } -class RequestObjectBuilder with RequiredUsing, RequireMethodCall, ReadyToBuild { - - @override - ReadyToBuild ready() { - return this; - } +class RequestObjectBuilder with RequiredUsing, RequireMethodCall { - @override RequestObject build() { return RequestObject(capabilities, invocations); } diff --git a/lib/jmap/core/request/require_method_call.dart b/lib/jmap/core/request/require_method_call.dart index 8b90e1c..c47b17a 100644 --- a/lib/jmap/core/request/require_method_call.dart +++ b/lib/jmap/core/request/require_method_call.dart @@ -1,13 +1,10 @@ -import 'package:jmap_dart_client/jmap/core/invocation.dart' as jmapInvocation; -import 'package:jmap_dart_client/jmap/core/request/ready_to_build.dart'; +import 'package:jmap_dart_client/jmap/core/method/method.dart'; +import 'package:jmap_dart_client/jmap/core/request/request_invocation.dart'; -mixin RequireMethodCall { - final List invocations = List.empty(growable: true); +mixin RequireMethodCall { + final List invocations = List.empty(growable: true); - RequireMethodCall methodCall(jmapInvocation.Invocation invocation) { - invocations.add(invocation); - return this; + void methodCalls(List newInvocations) { + invocations.addAll(newInvocations); } - - ReadyToBuild ready(); } \ No newline at end of file diff --git a/lib/jmap/core/request/require_using.dart b/lib/jmap/core/request/require_using.dart index f28b691..fc6f166 100644 --- a/lib/jmap/core/request/require_using.dart +++ b/lib/jmap/core/request/require_using.dart @@ -1,12 +1,15 @@ -import 'package:jmap_dart_client/jmap/core/request/require_method_call.dart'; +import 'dart:collection'; -import '../capability.dart'; +import '../capability/capability.dart'; -mixin RequiredUsing implements RequireMethodCall { - final Set capabilities = Set(); +mixin RequiredUsing { + final Set capabilities = HashSet.identity(); - RequiredUsing using(CapabilityIdentifier capabilityIdentifier) { + void using(CapabilityIdentifier capabilityIdentifier) { capabilities.add(capabilityIdentifier); - return this; + } + + void usings(Set capabilityIdentifiers) { + capabilities.addAll(capabilityIdentifiers); } } \ No newline at end of file From 50af2e2e3047131ef037bf6f9da03164c1e87ae4 Mon Sep 17 00:00:00 2001 From: Dat PHAM HOANG Date: Tue, 6 Jul 2021 16:19:24 +0700 Subject: [PATCH 06/20] Add abstraction for Method and GetMethod --- lib/jmap/core/method/method.dart | 18 +++++++++++++ lib/jmap/core/method/request/get_method.dart | 27 ++++++++++++++++++++ 2 files changed, 45 insertions(+) create mode 100644 lib/jmap/core/method/method.dart create mode 100644 lib/jmap/core/method/request/get_method.dart diff --git a/lib/jmap/core/method/method.dart b/lib/jmap/core/method/method.dart new file mode 100644 index 0000000..9ae89c8 --- /dev/null +++ b/lib/jmap/core/method/method.dart @@ -0,0 +1,18 @@ +import 'package:equatable/equatable.dart'; +import 'package:jmap_dart_client/jmap/account_id.dart'; +import 'package:jmap_dart_client/jmap/core/capability/capability.dart'; +import 'package:jmap_dart_client/jmap/core/request/request_invocation.dart'; + +abstract class Method with EquatableMixin { + MethodName get methodName; + + Set get requiredCapabilities; + + Map toJson(); +} + +abstract class MethodRequiringAccountId extends Method { + final AccountId accountId; + + MethodRequiringAccountId(this.accountId); +} diff --git a/lib/jmap/core/method/request/get_method.dart b/lib/jmap/core/method/request/get_method.dart new file mode 100644 index 0000000..774659f --- /dev/null +++ b/lib/jmap/core/method/request/get_method.dart @@ -0,0 +1,27 @@ +import 'package:jmap_dart_client/jmap/account_id.dart'; +import 'package:jmap_dart_client/jmap/core/id.dart'; +import 'package:jmap_dart_client/jmap/core/method/method.dart'; +import 'package:jmap_dart_client/jmap/core/properties/properties.dart'; + +abstract class GetMethod extends MethodRequiringAccountId with OptionalIds, OptionalProperties { + GetMethod(AccountId accountId) : super(accountId); +} + +mixin OptionalIds { + Set? ids; + + void addIds(Set values) { + if (ids == null) { + ids = Set(); + } + ids?.addAll(values); + } +} + +mixin OptionalProperties { + Properties? properties = Properties.empty(); + + void addProperties(Properties other) { + properties = properties?.union(other); + } +} From 9d561167240cd7d4ae52562a8298911bc1d0b9dd Mon Sep 17 00:00:00 2001 From: Dat PHAM HOANG Date: Tue, 6 Jul 2021 16:20:01 +0700 Subject: [PATCH 07/20] Add abstraction for Response and GetResponse --- lib/jmap/core/method/method_response.dart | 11 +++++++++++ lib/jmap/core/method/response/get_response.dart | 12 ++++++++++++ 2 files changed, 23 insertions(+) create mode 100644 lib/jmap/core/method/method_response.dart create mode 100644 lib/jmap/core/method/response/get_response.dart diff --git a/lib/jmap/core/method/method_response.dart b/lib/jmap/core/method/method_response.dart new file mode 100644 index 0000000..b872786 --- /dev/null +++ b/lib/jmap/core/method/method_response.dart @@ -0,0 +1,11 @@ +import 'package:equatable/equatable.dart'; +import 'package:jmap_dart_client/jmap/account_id.dart'; + +abstract class MethodResponse with EquatableMixin { +} + +abstract class ResponseRequiringAccountId extends MethodResponse { + final AccountId accountId; + + ResponseRequiringAccountId(this.accountId); +} \ No newline at end of file diff --git a/lib/jmap/core/method/response/get_response.dart b/lib/jmap/core/method/response/get_response.dart new file mode 100644 index 0000000..70db854 --- /dev/null +++ b/lib/jmap/core/method/response/get_response.dart @@ -0,0 +1,12 @@ +import 'package:jmap_dart_client/jmap/account_id.dart'; +import 'package:jmap_dart_client/jmap/core/id.dart'; +import 'package:jmap_dart_client/jmap/core/method/method_response.dart'; +import 'package:jmap_dart_client/jmap/core/state.dart'; + +abstract class GetResponse extends ResponseRequiringAccountId { + final State state; + final List list; + final List? notFound; + + GetResponse(AccountId accountId, this.state, this.list, this.notFound) : super(accountId); +} \ No newline at end of file From a7193b8fe1506af768ac0a6497cbf0835b8e732e Mon Sep 17 00:00:00 2001 From: Dat PHAM HOANG Date: Tue, 6 Jul 2021 16:21:36 +0700 Subject: [PATCH 08/20] Add ResponseObject and ResponseInvocation --- .../response_invocation_converter.dart | 25 ++++++++++++ .../core/response/response_invocation.dart | 16 ++++++++ lib/jmap/core/response/response_object.dart | 39 +++++++++++++++++++ lib/jmap/core/state.dart | 10 +++++ 4 files changed, 90 insertions(+) create mode 100644 lib/http/converter/response_invocation_converter.dart create mode 100644 lib/jmap/core/response/response_invocation.dart create mode 100644 lib/jmap/core/response/response_object.dart create mode 100644 lib/jmap/core/state.dart diff --git a/lib/http/converter/response_invocation_converter.dart b/lib/http/converter/response_invocation_converter.dart new file mode 100644 index 0000000..4ef7863 --- /dev/null +++ b/lib/http/converter/response_invocation_converter.dart @@ -0,0 +1,25 @@ + +import 'package:jmap_dart_client/jmap/core/request/request_invocation.dart'; +import 'package:jmap_dart_client/jmap/core/response/response_invocation.dart'; +import 'package:json_annotation/json_annotation.dart'; + +class ResponseInvocationConverter implements JsonConverter> { + const ResponseInvocationConverter(); + + @override + ResponseInvocation fromJson(List json) { + if (json.length == 3) { + return ResponseInvocation( + MethodName(json[0]), + ResponseArguments(json[1]), + MethodCallId(json[2])); + } else { + throw Exception("Wrong response invocation"); + } + } + + @override + List toJson(ResponseInvocation object) { + return List.of({object.methodName, object.arguments, object.methodCallId}); + } +} \ No newline at end of file diff --git a/lib/jmap/core/response/response_invocation.dart b/lib/jmap/core/response/response_invocation.dart new file mode 100644 index 0000000..93b8831 --- /dev/null +++ b/lib/jmap/core/response/response_invocation.dart @@ -0,0 +1,16 @@ +import 'package:jmap_dart_client/jmap/core/request/request_invocation.dart'; + + +class ResponseInvocation { + final MethodName methodName; + final ResponseArguments arguments; + final MethodCallId methodCallId; + + ResponseInvocation(this.methodName, this.arguments, this.methodCallId); +} + +class ResponseArguments { + final dynamic value; + + ResponseArguments(this.value); +} \ No newline at end of file diff --git a/lib/jmap/core/response/response_object.dart b/lib/jmap/core/response/response_object.dart new file mode 100644 index 0000000..7a705ca --- /dev/null +++ b/lib/jmap/core/response/response_object.dart @@ -0,0 +1,39 @@ +import 'dart:developer' as developer; + +import 'package:equatable/equatable.dart'; +import 'package:jmap_dart_client/http/converter/response_invocation_converter.dart'; +import 'package:jmap_dart_client/http/converter/state_converter.dart'; +import 'package:jmap_dart_client/jmap/core/method/method_response.dart'; +import 'package:jmap_dart_client/jmap/core/request/request_invocation.dart'; +import 'package:jmap_dart_client/jmap/core/response/response_invocation.dart'; +import 'package:jmap_dart_client/jmap/core/state.dart'; +import 'package:json_annotation/json_annotation.dart'; + +part 'response_object.g.dart'; + +@StateConverter() +@ResponseInvocationConverter() +@JsonSerializable() +class ResponseObject with EquatableMixin { + final List methodResponses; + final State sessionState; + + ResponseObject(this.methodResponses, this.sessionState); + + factory ResponseObject.fromJson(Map json) => _$ResponseObjectFromJson(json); + + Map toJson() => _$ResponseObjectToJson(this); + + Future parse(MethodCallId methodCallId, T fromJson(Map o)) async { + try { + final matchedResponse = methodResponses.firstWhere((method) => method.methodCallId == methodCallId); + return fromJson(matchedResponse.arguments.value); + } catch(error) { + developer.log('$error'); + return null; + } + } + + @override + List get props => [methodResponses, sessionState]; +} \ No newline at end of file diff --git a/lib/jmap/core/state.dart b/lib/jmap/core/state.dart new file mode 100644 index 0000000..fb26b72 --- /dev/null +++ b/lib/jmap/core/state.dart @@ -0,0 +1,10 @@ +import 'package:equatable/equatable.dart'; + +class State with EquatableMixin { + final String value; + + State(this.value); + + @override + List get props => [value]; +} \ No newline at end of file From c241248820f6948d90726ae72378f7e66be353a6 Mon Sep 17 00:00:00 2001 From: Dat PHAM HOANG Date: Tue, 6 Jul 2021 16:26:23 +0700 Subject: [PATCH 09/20] Add Mailbox and Implement GetMailboxMethod --- lib/jmap/mail/mailbox/get_mailbox_method.dart | 34 +++ .../mail/mailbox/get_mailbox_response.dart | 30 +++ lib/jmap/mail/mailbox/mailbox.dart | 248 ++++++++++++++++++ 3 files changed, 312 insertions(+) create mode 100644 lib/jmap/mail/mailbox/get_mailbox_method.dart create mode 100644 lib/jmap/mail/mailbox/get_mailbox_response.dart create mode 100644 lib/jmap/mail/mailbox/mailbox.dart diff --git a/lib/jmap/mail/mailbox/get_mailbox_method.dart b/lib/jmap/mail/mailbox/get_mailbox_method.dart new file mode 100644 index 0000000..8e6fb0b --- /dev/null +++ b/lib/jmap/mail/mailbox/get_mailbox_method.dart @@ -0,0 +1,34 @@ +import 'package:jmap_dart_client/http/converter/account_id_converter.dart'; +import 'package:jmap_dart_client/http/converter/id_converter.dart'; +import 'package:jmap_dart_client/http/converter/properties_converter.dart'; +import 'package:jmap_dart_client/jmap/account_id.dart'; +import 'package:jmap_dart_client/jmap/core/capability/capability.dart'; +import 'package:jmap_dart_client/jmap/core/method/request/get_method.dart'; +import 'package:jmap_dart_client/jmap/core/request/request_invocation.dart'; +import 'package:json_annotation/json_annotation.dart'; + +part 'get_mailbox_method.g.dart'; + +@IdConverter() +@AccountIdConverter() +@PropertiesConverter() +@JsonSerializable() +class GetMailboxMethod extends GetMethod { + GetMailboxMethod(AccountId accountId) : super(accountId); + + @override + MethodName get methodName => MethodName('Mailbox/get'); + + @override + Set get requiredCapabilities => { + CapabilityIdentifier.jmapCore, + CapabilityIdentifier.jmapMail + }; + + @override + List get props => [methodName, accountId, ids, properties, requiredCapabilities]; + + factory GetMailboxMethod.fromJson(Map json) => _$GetMailboxMethodFromJson(json); + + Map toJson() => _$GetMailboxMethodToJson(this); +} \ No newline at end of file diff --git a/lib/jmap/mail/mailbox/get_mailbox_response.dart b/lib/jmap/mail/mailbox/get_mailbox_response.dart new file mode 100644 index 0000000..1bca718 --- /dev/null +++ b/lib/jmap/mail/mailbox/get_mailbox_response.dart @@ -0,0 +1,30 @@ +import 'package:jmap_dart_client/http/converter/account_id_converter.dart'; +import 'package:jmap_dart_client/http/converter/id_converter.dart'; +import 'package:jmap_dart_client/http/converter/state_converter.dart'; +import 'package:jmap_dart_client/jmap/account_id.dart'; +import 'package:jmap_dart_client/jmap/core/id.dart'; +import 'package:jmap_dart_client/jmap/core/method/response/get_response.dart'; +import 'package:jmap_dart_client/jmap/core/state.dart'; +import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart'; +import 'package:json_annotation/json_annotation.dart'; + +part 'get_mailbox_response.g.dart'; + +@StateConverter() +@AccountIdConverter() +@IdConverter() +@JsonSerializable() +class GetMailboxResponse extends GetResponse { + GetMailboxResponse(AccountId accountId, State state, List list, List? notFound) : super(accountId, state, list, notFound); + + factory GetMailboxResponse.fromJson(Map json) => _$GetMailboxResponseFromJson(json); + + static GetMailboxResponse fromJson1(Map json) { + return GetMailboxResponse.fromJson(json); + } + + Map toJson() => _$GetMailboxResponseToJson(this); + + @override + List get props => [accountId, state, list, notFound]; +} \ No newline at end of file diff --git a/lib/jmap/mail/mailbox/mailbox.dart b/lib/jmap/mail/mailbox/mailbox.dart new file mode 100644 index 0000000..0831829 --- /dev/null +++ b/lib/jmap/mail/mailbox/mailbox.dart @@ -0,0 +1,248 @@ +import 'package:equatable/equatable.dart'; +import 'package:jmap_dart_client/http/converter/mailbox_id_converter.dart'; +import 'package:jmap_dart_client/http/converter/mailbox_id_nullable_converter.dart'; +import 'package:jmap_dart_client/http/converter/mailbox_name_converter.dart'; +import 'package:jmap_dart_client/http/converter/role_converter.dart'; +import 'package:jmap_dart_client/jmap/core/id.dart'; +import 'package:jmap_dart_client/jmap/core/properties/properties.dart'; +import 'package:jmap_dart_client/jmap/core/unsigned_int.dart'; +import 'package:json_annotation/json_annotation.dart'; + +part 'mailbox.g.dart'; + +@RoleConverter() +@MailboxIdNullableConverter() +@MailboxNameConverter() +@MailboxIdConverter() +@JsonSerializable() +class Mailbox with EquatableMixin { + static Properties allProperties = Properties({ + 'id', 'name', 'parentId', 'role', 'sortOrder', 'totalEmails', 'unreadEmails', + 'totalThreads', 'unreadThreads', 'myRights', 'isSubscribed' + }); + + final MailboxId id; + final MailboxName? name; + final MailboxId? parentId; + final Role? role; + final SortOrder? sortOrder; + final TotalEmails? totalEmails; + final UnreadEmails? unreadEmails; + final TotalThreads? totalThreads; + final UnreadThreads? unreadThreads; + final MailboxRights? myRights; + final IsSubscribed? isSubscribed; + + Mailbox( + this.id, + this.name, + this.parentId, + this.role, + this.sortOrder, + this.totalEmails, + this.unreadEmails, + this.totalThreads, + this.unreadThreads, + this.myRights, + this.isSubscribed + ); + + factory Mailbox.fromJson(Map json) => _$MailboxFromJson(json); + + Map toJson() => _$MailboxToJson(this); + + @override + List get props => [id, name, parentId, role]; +} + +class MailboxId with EquatableMixin { + final Id id; + + MailboxId(this.id); + + @override + List get props => [id]; +} + +class MailboxName with EquatableMixin { + final String name; + + MailboxName(this.name); + + @override + List get props => [name]; +} + +class Role with EquatableMixin { + final String value; + + Role(this.value); + + @override + List get props => [value]; +} + +class SortOrder with EquatableMixin { + late final UnsignedInt value; + + SortOrder({int sortValue = 0}) { + this.value = UnsignedInt(sortValue); + } + + @override + List get props => [value]; +} + +class TotalEmails with EquatableMixin { + final UnsignedInt value; + + TotalEmails(this.value); + + @override + List get props => [value]; +} + +class UnreadEmails with EquatableMixin { + final UnsignedInt value; + + UnreadEmails(this.value); + + @override + List get props => [value]; +} + +class TotalThreads with EquatableMixin { + final UnsignedInt value; + + TotalThreads(this.value); + + @override + List get props => [value]; +} + +class UnreadThreads with EquatableMixin { + final UnsignedInt value; + + UnreadThreads(this.value); + + @override + List get props => [value]; +} + +class MailboxRights with EquatableMixin { + final MayReadItems mayReadItems; + final MayAddItems mayAddItems; + final MayRemoveItems mayRemoveItems; + final MaySetSeen maySetSeen; + final MaySetKeywords maySetKeywords; + final MayCreateChild mayCreateChild; + final MayRename mayRename; + final MayDelete mayDelete; + final MaySubmit maySubmit; + + MailboxRights( + this.mayReadItems, + this.mayAddItems, + this.mayRemoveItems, + this.maySetSeen, + this.maySetKeywords, + this.mayCreateChild, + this.mayRename, + this.mayDelete, + this.maySubmit); + + @override + List get props => [mayReadItems, mayAddItems, mayRemoveItems, maySetSeen, + maySetKeywords, mayCreateChild, mayRename, mayDelete, maySubmit]; +} + +class MayReadItems with EquatableMixin { + final bool value; + + MayReadItems(this.value); + + @override + List get props => [value]; +} + +class MayAddItems with EquatableMixin{ + final bool value; + + MayAddItems(this.value); + + @override + List get props => [value]; +} + +class MayRemoveItems with EquatableMixin { + final bool value; + + MayRemoveItems(this.value); + + @override + List get props => [value]; +} + +class MaySetSeen with EquatableMixin { + final bool value; + + MaySetSeen(this.value); + + @override + List get props => [value]; +} + +class MaySetKeywords with EquatableMixin { + final bool value; + + MaySetKeywords(this.value); + + @override + List get props => [value]; +} + +class MayCreateChild with EquatableMixin { + final bool value; + + MayCreateChild(this.value); + + @override + List get props => [value]; +} + +class MayRename with EquatableMixin { + final bool value; + + MayRename(this.value); + + @override + List get props => [value]; +} + +class MayDelete with EquatableMixin { + final bool value; + + MayDelete(this.value); + + @override + List get props => [value]; +} + +class MaySubmit with EquatableMixin { + final bool value; + + MaySubmit(this.value); + + @override + List get props => [value]; +} + +class IsSubscribed with EquatableMixin { + final bool value; + + IsSubscribed(this.value); + + @override + List get props => [value]; +} + From 4a554bdbf720dce1d8fcca0b6630e59ff71abe02 Mon Sep 17 00:00:00 2001 From: Dat PHAM HOANG Date: Tue, 6 Jul 2021 16:27:24 +0700 Subject: [PATCH 10/20] Add some converter for serialize/deserialize Jmap request/response --- lib/http/converter/account_id_converter.dart | 13 +++++++++ .../capability_identifier_onverter.dart | 12 ++++++++ lib/http/converter/id_converter.dart | 18 ++++++++++++ lib/http/converter/mailbox_id_converter.dart | 13 +++++++++ .../mailbox_id_nullable_converter.dart | 13 +++++++++ .../converter/mailbox_name_converter.dart | 12 ++++++++ .../converter/method_response_converter.dart | 17 +++++++++++ lib/http/converter/properties_converter.dart | 28 ++++++++++++++++++ .../request_invocation_converter.dart | 22 ++++++++++++++ lib/http/converter/role_converter.dart | 12 ++++++++ lib/http/converter/state_converter.dart | 12 ++++++++ lib/http/http_client.dart | 29 +++++++++++++++++++ pubspec.yaml | 6 ++++ 13 files changed, 207 insertions(+) create mode 100644 lib/http/converter/account_id_converter.dart create mode 100644 lib/http/converter/capability_identifier_onverter.dart create mode 100644 lib/http/converter/id_converter.dart create mode 100644 lib/http/converter/mailbox_id_converter.dart create mode 100644 lib/http/converter/mailbox_id_nullable_converter.dart create mode 100644 lib/http/converter/mailbox_name_converter.dart create mode 100644 lib/http/converter/method_response_converter.dart create mode 100644 lib/http/converter/properties_converter.dart create mode 100644 lib/http/converter/request_invocation_converter.dart create mode 100644 lib/http/converter/role_converter.dart create mode 100644 lib/http/converter/state_converter.dart create mode 100644 lib/http/http_client.dart diff --git a/lib/http/converter/account_id_converter.dart b/lib/http/converter/account_id_converter.dart new file mode 100644 index 0000000..c03e3e2 --- /dev/null +++ b/lib/http/converter/account_id_converter.dart @@ -0,0 +1,13 @@ +import 'package:jmap_dart_client/jmap/account_id.dart'; +import 'package:jmap_dart_client/jmap/core/id.dart'; +import 'package:json_annotation/json_annotation.dart'; + +class AccountIdConverter implements JsonConverter { + const AccountIdConverter(); + + @override + AccountId fromJson(String json) => AccountId(Id(json)); + + @override + String toJson(AccountId object) => object.id.value; +} \ No newline at end of file diff --git a/lib/http/converter/capability_identifier_onverter.dart b/lib/http/converter/capability_identifier_onverter.dart new file mode 100644 index 0000000..c4a1fdc --- /dev/null +++ b/lib/http/converter/capability_identifier_onverter.dart @@ -0,0 +1,12 @@ +import 'package:jmap_dart_client/jmap/core/capability/capability.dart'; +import 'package:json_annotation/json_annotation.dart'; + +class CapabilityIdentifierConverter implements JsonConverter { + const CapabilityIdentifierConverter(); + + @override + CapabilityIdentifier fromJson(String json) => CapabilityIdentifier(json); + + @override + String toJson(CapabilityIdentifier object) => object.value; +} \ No newline at end of file diff --git a/lib/http/converter/id_converter.dart b/lib/http/converter/id_converter.dart new file mode 100644 index 0000000..e51aad2 --- /dev/null +++ b/lib/http/converter/id_converter.dart @@ -0,0 +1,18 @@ + +import 'package:jmap_dart_client/jmap/core/id.dart'; +import 'package:json_annotation/json_annotation.dart'; + +class IdConverter implements JsonConverter { + const IdConverter(); + + @override + Id fromJson(String json) { + return Id(json); + } + + @override + String toJson(Id object) { + return object.value; + } + +} \ No newline at end of file diff --git a/lib/http/converter/mailbox_id_converter.dart b/lib/http/converter/mailbox_id_converter.dart new file mode 100644 index 0000000..aeaa999 --- /dev/null +++ b/lib/http/converter/mailbox_id_converter.dart @@ -0,0 +1,13 @@ +import 'package:jmap_dart_client/jmap/core/id.dart'; +import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart'; +import 'package:json_annotation/json_annotation.dart'; + +class MailboxIdConverter implements JsonConverter { + const MailboxIdConverter(); + + @override + MailboxId fromJson(String json) => MailboxId(Id(json)); + + @override + String toJson(MailboxId object) => object.id.value; +} \ No newline at end of file diff --git a/lib/http/converter/mailbox_id_nullable_converter.dart b/lib/http/converter/mailbox_id_nullable_converter.dart new file mode 100644 index 0000000..8f01f4e --- /dev/null +++ b/lib/http/converter/mailbox_id_nullable_converter.dart @@ -0,0 +1,13 @@ +import 'package:jmap_dart_client/jmap/core/id.dart'; +import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart'; +import 'package:json_annotation/json_annotation.dart'; + +class MailboxIdNullableConverter implements JsonConverter { + const MailboxIdNullableConverter(); + + @override + MailboxId? fromJson(String? json) => json != null ? MailboxId(Id(json)) : null; + + @override + String? toJson(MailboxId? object) => object?.id.value; +} \ No newline at end of file diff --git a/lib/http/converter/mailbox_name_converter.dart b/lib/http/converter/mailbox_name_converter.dart new file mode 100644 index 0000000..41eb77a --- /dev/null +++ b/lib/http/converter/mailbox_name_converter.dart @@ -0,0 +1,12 @@ +import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart'; +import 'package:json_annotation/json_annotation.dart'; + +class MailboxNameConverter implements JsonConverter { + const MailboxNameConverter(); + + @override + MailboxName? fromJson(String? json) => json != null ? MailboxName(json) : null; + + @override + String? toJson(MailboxName? object) => object?.name; +} \ No newline at end of file diff --git a/lib/http/converter/method_response_converter.dart b/lib/http/converter/method_response_converter.dart new file mode 100644 index 0000000..61db267 --- /dev/null +++ b/lib/http/converter/method_response_converter.dart @@ -0,0 +1,17 @@ + +import 'package:jmap_dart_client/jmap/core/method/method_response.dart'; +import 'package:json_annotation/json_annotation.dart'; + +class MethodResponseConverter implements JsonConverter { + const MethodResponseConverter(); + + @override + MethodResponse fromJson(dynamic json) { + return this.fromJson(json); + } + + @override + dynamic toJson(MethodResponse object) { + return object; + } +} \ No newline at end of file diff --git a/lib/http/converter/properties_converter.dart b/lib/http/converter/properties_converter.dart new file mode 100644 index 0000000..c74f7b8 --- /dev/null +++ b/lib/http/converter/properties_converter.dart @@ -0,0 +1,28 @@ +import 'dart:convert'; + +import 'package:jmap_dart_client/jmap/core/properties/properties.dart'; +import 'package:json_annotation/json_annotation.dart'; + +class PropertiesConverter implements JsonConverter?> { + const PropertiesConverter(); + + @override + Properties? fromJson(List? json) { + + } + + @override + List? toJson(Properties? object) { + if (object == null) { + return null; + } + + if (object.value.isEmpty) { + return null; + } + + return object.value + .map((element) => jsonEncode(element)) + .toList(); + } +} \ No newline at end of file diff --git a/lib/http/converter/request_invocation_converter.dart b/lib/http/converter/request_invocation_converter.dart new file mode 100644 index 0000000..9b4b51e --- /dev/null +++ b/lib/http/converter/request_invocation_converter.dart @@ -0,0 +1,22 @@ +import 'dart:convert'; + +import 'package:jmap_dart_client/jmap/core/request/request_invocation.dart'; +import 'package:json_annotation/json_annotation.dart'; + +class RequestInvocationConverter implements JsonConverter> { + const RequestInvocationConverter(); + + @override + RequestInvocation fromJson(List json) { + return RequestInvocation(MethodName(json[0]), jsonDecode(json[1]), jsonDecode(json[2])); + } + + @override + List toJson(RequestInvocation object) { + List list = List.empty(growable: true); + list.add(object.methodName.value); + list.add(object.arguments.value.toJson()); + list.add(object.methodCallId.value); + return list; + } +} \ No newline at end of file diff --git a/lib/http/converter/role_converter.dart b/lib/http/converter/role_converter.dart new file mode 100644 index 0000000..265516f --- /dev/null +++ b/lib/http/converter/role_converter.dart @@ -0,0 +1,12 @@ +import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart'; +import 'package:json_annotation/json_annotation.dart'; + +class RoleConverter implements JsonConverter { + const RoleConverter(); + + @override + Role? fromJson(String? json) => json != null ? Role(json) : null; + + @override + String? toJson(Role? object) => object?.value; +} \ No newline at end of file diff --git a/lib/http/converter/state_converter.dart b/lib/http/converter/state_converter.dart new file mode 100644 index 0000000..c4fce7c --- /dev/null +++ b/lib/http/converter/state_converter.dart @@ -0,0 +1,12 @@ +import 'package:jmap_dart_client/jmap/core/state.dart'; +import 'package:json_annotation/json_annotation.dart'; + +class StateConverter implements JsonConverter { + const StateConverter(); + + @override + State fromJson(String json) => State(json); + + @override + String toJson(State object) => object.value; +} \ No newline at end of file diff --git a/lib/http/http_client.dart b/lib/http/http_client.dart new file mode 100644 index 0000000..5d4404b --- /dev/null +++ b/lib/http/http_client.dart @@ -0,0 +1,29 @@ +import 'package:dio/dio.dart'; + +class HttpClient { + final Dio _dio; + + HttpClient(this._dio); + + Future> post( + String path, { + data, + Map? queryParameters, + Options? options, + CancelToken? cancelToken, + ProgressCallback? onSendProgress, + ProgressCallback? onReceiveProgress, + } + ) async { + return await _dio.post( + path, + data: data, + queryParameters: queryParameters, + options: options, + cancelToken: cancelToken, + onSendProgress: onSendProgress, + onReceiveProgress: onReceiveProgress) + .then((value) => value.data) + .catchError((error) => throw error); + } +} \ No newline at end of file diff --git a/pubspec.yaml b/pubspec.yaml index 227b4f4..cc92480 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -17,6 +17,12 @@ dependencies: quiver: 3.0.1 + dio: 4.0.0 + + json_annotation: 4.0.1 + build_runner: 2.0.5 + json_serializable: 4.1.3 + dev_dependencies: flutter_test: sdk: flutter From fe70c9757043175753d82caf86e9e27833bb556f Mon Sep 17 00:00:00 2001 From: Dat PHAM HOANG Date: Tue, 6 Jul 2021 16:38:45 +0700 Subject: [PATCH 11/20] Add JmapRequest to execute request and extract response from Jmap server --- lib/jmap/jmap_request.dart | 81 ++++++++++++++++++++++++++++++++++++++ lib/util/util.dart | 4 ++ 2 files changed, 85 insertions(+) create mode 100644 lib/jmap/jmap_request.dart create mode 100644 lib/util/util.dart diff --git a/lib/jmap/jmap_request.dart b/lib/jmap/jmap_request.dart new file mode 100644 index 0000000..e616b5f --- /dev/null +++ b/lib/jmap/jmap_request.dart @@ -0,0 +1,81 @@ +import 'dart:collection'; + +import 'package:jmap_dart_client/http/http_client.dart'; +import 'package:jmap_dart_client/jmap/core/response/response_object.dart'; +import 'package:jmap_dart_client/util/util.dart'; + +import 'core/capability/capability.dart'; +import 'core/method/method.dart'; +import 'core/request/request_invocation.dart'; +import 'core/request/request_object.dart'; + +class JmapRequest { + final HttpClient _httpClient; + final Set _capabilities; + final Map _invocations; + + JmapRequest(this._httpClient, this._capabilities, this._invocations); + + RequestObject? _requestObject; + RequestObject? get requestObject => _requestObject; + + Future execute() async { + _requestObject = (RequestObject.builder() + ..usings(_capabilities) + ..methodCalls(_invocations.values.toList())) + .build(); + + return _httpClient.post('/jmap', data: _requestObject?.toJson()) + .then((value) => extractData(value)) + .catchError((error) => throw error); + } + + ResponseObject extractData(Map body) { + return ResponseObject.fromJson(body); + } +} + +class JmapRequestBuilder { + final HttpClient _httpClient; + final ProcessingInvocation _processingInvocation; + final Set _capabilities = HashSet.identity(); + + JmapRequestBuilder(this._httpClient, this._processingInvocation); + + void call(Method method, {MethodCallId? methodCallId}) { + final callId = methodCallId ?? _processingInvocation.generateMethodCallId(); + final RequestInvocation invocation = RequestInvocation( + method.methodName, + Arguments(method), + callId + ); + _processingInvocation.addMethod(callId, invocation); + } + + void usings(Set capabilityIdentifiers) { + _capabilities.addAll(capabilityIdentifiers); + } + + JmapRequest build() { + return JmapRequest(_httpClient, _capabilities, _processingInvocation._invocations); + } +} + +class ProcessingInvocation { + static const String methodCallIdPrefix = 'c'; + late final Map _invocations; + + ProcessingInvocation() { + _invocations = LinkedHashMap.identity(); + } + + MethodCallId generateMethodCallId() { + return positiveIntegers + .map((item) => MethodCallId(methodCallIdPrefix + item.toString())) + .firstWhere((callId) => !_invocations.keys.contains(callId)); + } + + void addMethod(MethodCallId callId, RequestInvocation requestInvocation) { + _invocations.addAll({callId: requestInvocation}); + } +} diff --git a/lib/util/util.dart b/lib/util/util.dart new file mode 100644 index 0000000..6a35e6c --- /dev/null +++ b/lib/util/util.dart @@ -0,0 +1,4 @@ +Iterable get positiveIntegers sync* { + int i = 0; + while (true) yield i++; +} \ No newline at end of file From 5241a2bd3021efad41472fca4c9d5b2178e4bf0c Mon Sep 17 00:00:00 2001 From: Dat PHAM HOANG Date: Wed, 7 Jul 2021 16:58:48 +0700 Subject: [PATCH 12/20] Using built_collection to use immutable collection in RequestObject --- .../converter/method_call_id_converter.dart | 12 +++++++++ lib/http/converter/method_name_converter.dart | 12 +++++++++ lib/http/converter/properties_converter.dart | 7 ++--- lib/jmap/core/method/request/get_method.dart | 3 +++ lib/jmap/core/request/request_object.dart | 4 ++- .../core/request/require_method_call.dart | 5 ++-- lib/jmap/core/request/require_using.dart | 9 ++++--- lib/jmap/jmap_request.dart | 26 ++++++++++--------- pubspec.yaml | 2 ++ 9 files changed, 56 insertions(+), 24 deletions(-) create mode 100644 lib/http/converter/method_call_id_converter.dart create mode 100644 lib/http/converter/method_name_converter.dart diff --git a/lib/http/converter/method_call_id_converter.dart b/lib/http/converter/method_call_id_converter.dart new file mode 100644 index 0000000..1dc735a --- /dev/null +++ b/lib/http/converter/method_call_id_converter.dart @@ -0,0 +1,12 @@ +import 'package:jmap_dart_client/jmap/core/request/request_invocation.dart'; +import 'package:json_annotation/json_annotation.dart'; + +class MethodCallIdConverter implements JsonConverter { + const MethodCallIdConverter(); + + @override + MethodCallId fromJson(String json) => MethodCallId(json); + + @override + String toJson(MethodCallId object) => object.value; +} \ No newline at end of file diff --git a/lib/http/converter/method_name_converter.dart b/lib/http/converter/method_name_converter.dart new file mode 100644 index 0000000..25fbfea --- /dev/null +++ b/lib/http/converter/method_name_converter.dart @@ -0,0 +1,12 @@ +import 'package:jmap_dart_client/jmap/core/request/request_invocation.dart'; +import 'package:json_annotation/json_annotation.dart'; + +class MethodNameConverter implements JsonConverter { + const MethodNameConverter(); + + @override + MethodName fromJson(String json) => MethodName(json); + + @override + String toJson(MethodName object) => object.value; +} \ No newline at end of file diff --git a/lib/http/converter/properties_converter.dart b/lib/http/converter/properties_converter.dart index c74f7b8..46da977 100644 --- a/lib/http/converter/properties_converter.dart +++ b/lib/http/converter/properties_converter.dart @@ -1,4 +1,3 @@ -import 'dart:convert'; import 'package:jmap_dart_client/jmap/core/properties/properties.dart'; import 'package:json_annotation/json_annotation.dart'; @@ -8,7 +7,7 @@ class PropertiesConverter implements JsonConverter?> { @override Properties? fromJson(List? json) { - + return json != null ? Properties(json.toSet()) : null; } @override @@ -21,8 +20,6 @@ class PropertiesConverter implements JsonConverter?> { return null; } - return object.value - .map((element) => jsonEncode(element)) - .toList(); + return object.value.toList(); } } \ No newline at end of file diff --git a/lib/jmap/core/method/request/get_method.dart b/lib/jmap/core/method/request/get_method.dart index 774659f..28c1d94 100644 --- a/lib/jmap/core/method/request/get_method.dart +++ b/lib/jmap/core/method/request/get_method.dart @@ -2,12 +2,14 @@ import 'package:jmap_dart_client/jmap/account_id.dart'; import 'package:jmap_dart_client/jmap/core/id.dart'; import 'package:jmap_dart_client/jmap/core/method/method.dart'; import 'package:jmap_dart_client/jmap/core/properties/properties.dart'; +import 'package:json_annotation/json_annotation.dart'; abstract class GetMethod extends MethodRequiringAccountId with OptionalIds, OptionalProperties { GetMethod(AccountId accountId) : super(accountId); } mixin OptionalIds { + @JsonKey(includeIfNull: false) Set? ids; void addIds(Set values) { @@ -19,6 +21,7 @@ mixin OptionalIds { } mixin OptionalProperties { + @JsonKey(includeIfNull: false) Properties? properties = Properties.empty(); void addProperties(Properties other) { diff --git a/lib/jmap/core/request/request_object.dart b/lib/jmap/core/request/request_object.dart index 3153567..161ee7e 100644 --- a/lib/jmap/core/request/request_object.dart +++ b/lib/jmap/core/request/request_object.dart @@ -31,6 +31,8 @@ class RequestObject with EquatableMixin { class RequestObjectBuilder with RequiredUsing, RequireMethodCall { RequestObject build() { - return RequestObject(capabilities, invocations); + return RequestObject( + capabilitiesBuilder.build().asSet(), + invocationsBuilder.build().asList()); } } diff --git a/lib/jmap/core/request/require_method_call.dart b/lib/jmap/core/request/require_method_call.dart index c47b17a..6d4674f 100644 --- a/lib/jmap/core/request/require_method_call.dart +++ b/lib/jmap/core/request/require_method_call.dart @@ -1,10 +1,11 @@ +import 'package:built_collection/built_collection.dart'; import 'package:jmap_dart_client/jmap/core/method/method.dart'; import 'package:jmap_dart_client/jmap/core/request/request_invocation.dart'; mixin RequireMethodCall { - final List invocations = List.empty(growable: true); + final ListBuilder invocationsBuilder = ListBuilder(); void methodCalls(List newInvocations) { - invocations.addAll(newInvocations); + invocationsBuilder.addAll(newInvocations); } } \ No newline at end of file diff --git a/lib/jmap/core/request/require_using.dart b/lib/jmap/core/request/require_using.dart index fc6f166..30487ec 100644 --- a/lib/jmap/core/request/require_using.dart +++ b/lib/jmap/core/request/require_using.dart @@ -1,15 +1,16 @@ -import 'dart:collection'; + +import 'package:built_collection/built_collection.dart'; import '../capability/capability.dart'; mixin RequiredUsing { - final Set capabilities = HashSet.identity(); + final SetBuilder capabilitiesBuilder = SetBuilder(); void using(CapabilityIdentifier capabilityIdentifier) { - capabilities.add(capabilityIdentifier); + capabilitiesBuilder.add(capabilityIdentifier); } void usings(Set capabilityIdentifiers) { - capabilities.addAll(capabilityIdentifiers); + capabilitiesBuilder.addAll(capabilityIdentifiers); } } \ No newline at end of file diff --git a/lib/jmap/jmap_request.dart b/lib/jmap/jmap_request.dart index e616b5f..b00e895 100644 --- a/lib/jmap/jmap_request.dart +++ b/lib/jmap/jmap_request.dart @@ -1,5 +1,4 @@ -import 'dart:collection'; - +import 'package:built_collection/built_collection.dart'; import 'package:jmap_dart_client/http/http_client.dart'; import 'package:jmap_dart_client/jmap/core/response/response_object.dart'; import 'package:jmap_dart_client/util/util.dart'; @@ -11,8 +10,8 @@ import 'core/request/request_object.dart'; class JmapRequest { final HttpClient _httpClient; - final Set _capabilities; - final Map _invocations; + final BuiltSet _capabilities; + final BuiltMap _invocations; JmapRequest(this._httpClient, this._capabilities, this._invocations); @@ -21,7 +20,7 @@ class JmapRequest { Future execute() async { _requestObject = (RequestObject.builder() - ..usings(_capabilities) + ..usings(_capabilities.asSet()) ..methodCalls(_invocations.values.toList())) .build(); @@ -38,11 +37,11 @@ class JmapRequest { class JmapRequestBuilder { final HttpClient _httpClient; final ProcessingInvocation _processingInvocation; - final Set _capabilities = HashSet.identity(); + final SetBuilder _capabilitiesBuilder = SetBuilder(); JmapRequestBuilder(this._httpClient, this._processingInvocation); - void call(Method method, {MethodCallId? methodCallId}) { + RequestInvocation invocation(Method method, {MethodCallId? methodCallId}) { final callId = methodCallId ?? _processingInvocation.generateMethodCallId(); final RequestInvocation invocation = RequestInvocation( method.methodName, @@ -50,23 +49,24 @@ class JmapRequestBuilder { callId ); _processingInvocation.addMethod(callId, invocation); + return invocation; } void usings(Set capabilityIdentifiers) { - _capabilities.addAll(capabilityIdentifiers); + _capabilitiesBuilder.addAll(capabilityIdentifiers); } JmapRequest build() { - return JmapRequest(_httpClient, _capabilities, _processingInvocation._invocations); + return JmapRequest(_httpClient, _capabilitiesBuilder.build(), _processingInvocation._invocations); } } class ProcessingInvocation { static const String methodCallIdPrefix = 'c'; - late final Map _invocations; + late BuiltMap _invocations; ProcessingInvocation() { - _invocations = LinkedHashMap.identity(); + _invocations = BuiltMap(); } MethodCallId generateMethodCallId() { @@ -76,6 +76,8 @@ class ProcessingInvocation { } void addMethod(MethodCallId callId, RequestInvocation requestInvocation) { - _invocations.addAll({callId: requestInvocation}); + _invocations = (_invocations.toBuilder() + ..addAll({callId: requestInvocation})) + .build(); } } diff --git a/pubspec.yaml b/pubspec.yaml index cc92480..15be8d5 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -23,6 +23,8 @@ dependencies: build_runner: 2.0.5 json_serializable: 4.1.3 + built_collection: ^5.1.0 + dev_dependencies: flutter_test: sdk: flutter From f43e9d2aef5eafb02da53d7d3f0be9d16344e99b Mon Sep 17 00:00:00 2001 From: Dat PHAM HOANG Date: Thu, 8 Jul 2021 12:06:26 +0700 Subject: [PATCH 13/20] Add some properties to Mailbox --- .../converter/is_subscribed_converter.dart | 16 +++ lib/http/converter/sort_order_converter.dart | 16 +++ lib/http/converter/total_email_converter.dart | 17 +++ .../converter/total_threads_converter.dart | 17 +++ .../converter/unread_emails_converter.dart | 17 +++ .../converter/unread_threads_converter.dart | 17 +++ .../unsigned_int_nullable_converter.dart | 16 +++ lib/jmap/mail/mailbox/mailbox.dart | 122 ++---------------- lib/jmap/mail/mailbox/mailbox_rights.dart | 36 ++++++ 9 files changed, 165 insertions(+), 109 deletions(-) create mode 100644 lib/http/converter/is_subscribed_converter.dart create mode 100644 lib/http/converter/sort_order_converter.dart create mode 100644 lib/http/converter/total_email_converter.dart create mode 100644 lib/http/converter/total_threads_converter.dart create mode 100644 lib/http/converter/unread_emails_converter.dart create mode 100644 lib/http/converter/unread_threads_converter.dart create mode 100644 lib/http/converter/unsigned_int_nullable_converter.dart create mode 100644 lib/jmap/mail/mailbox/mailbox_rights.dart diff --git a/lib/http/converter/is_subscribed_converter.dart b/lib/http/converter/is_subscribed_converter.dart new file mode 100644 index 0000000..d74549b --- /dev/null +++ b/lib/http/converter/is_subscribed_converter.dart @@ -0,0 +1,16 @@ +import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart'; +import 'package:json_annotation/json_annotation.dart'; + +class IsSubscribedConverter implements JsonConverter { + const IsSubscribedConverter(); + + @override + IsSubscribed? fromJson(bool? json) { + return json != null ? IsSubscribed(json) : null; + } + + @override + bool? toJson(IsSubscribed? object) { + return object?.value; + } +} \ No newline at end of file diff --git a/lib/http/converter/sort_order_converter.dart b/lib/http/converter/sort_order_converter.dart new file mode 100644 index 0000000..7787935 --- /dev/null +++ b/lib/http/converter/sort_order_converter.dart @@ -0,0 +1,16 @@ +import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart'; +import 'package:json_annotation/json_annotation.dart'; + +class SortOrderConverter implements JsonConverter { + const SortOrderConverter(); + + @override + SortOrder? fromJson(int? json) { + return json != null ? SortOrder(sortValue: json) : null; + } + + @override + int? toJson(SortOrder? object) { + return object?.value.value.toInt(); + } +} \ No newline at end of file diff --git a/lib/http/converter/total_email_converter.dart b/lib/http/converter/total_email_converter.dart new file mode 100644 index 0000000..bfc35b7 --- /dev/null +++ b/lib/http/converter/total_email_converter.dart @@ -0,0 +1,17 @@ +import 'package:jmap_dart_client/jmap/core/unsigned_int.dart'; +import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart'; +import 'package:json_annotation/json_annotation.dart'; + +class TotalEmailConverter implements JsonConverter { + const TotalEmailConverter(); + + @override + TotalEmails? fromJson(int? json) { + return json != null ? TotalEmails(UnsignedInt(json)) : null; + } + + @override + int? toJson(TotalEmails? object) { + return object?.value.value.toInt(); + } +} \ No newline at end of file diff --git a/lib/http/converter/total_threads_converter.dart b/lib/http/converter/total_threads_converter.dart new file mode 100644 index 0000000..92f9d5e --- /dev/null +++ b/lib/http/converter/total_threads_converter.dart @@ -0,0 +1,17 @@ +import 'package:jmap_dart_client/jmap/core/unsigned_int.dart'; +import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart'; +import 'package:json_annotation/json_annotation.dart'; + +class TotalThreadsConverter implements JsonConverter { + const TotalThreadsConverter(); + + @override + TotalThreads? fromJson(int? json) { + return json != null ? TotalThreads(UnsignedInt(json)) : null; + } + + @override + int? toJson(TotalThreads? object) { + return object?.value.value.toInt(); + } +} \ No newline at end of file diff --git a/lib/http/converter/unread_emails_converter.dart b/lib/http/converter/unread_emails_converter.dart new file mode 100644 index 0000000..389be96 --- /dev/null +++ b/lib/http/converter/unread_emails_converter.dart @@ -0,0 +1,17 @@ +import 'package:jmap_dart_client/jmap/core/unsigned_int.dart'; +import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart'; +import 'package:json_annotation/json_annotation.dart'; + +class UnreadEmailsConverter implements JsonConverter { + const UnreadEmailsConverter(); + + @override + UnreadEmails? fromJson(int? json) { + return json != null ? UnreadEmails(UnsignedInt(json)) : null; + } + + @override + int? toJson(UnreadEmails? object) { + return object?.value.value.toInt(); + } +} \ No newline at end of file diff --git a/lib/http/converter/unread_threads_converter.dart b/lib/http/converter/unread_threads_converter.dart new file mode 100644 index 0000000..57fdfab --- /dev/null +++ b/lib/http/converter/unread_threads_converter.dart @@ -0,0 +1,17 @@ +import 'package:jmap_dart_client/jmap/core/unsigned_int.dart'; +import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart'; +import 'package:json_annotation/json_annotation.dart'; + +class UnreadThreadsConverter implements JsonConverter { + const UnreadThreadsConverter(); + + @override + UnreadThreads? fromJson(int? json) { + return json != null ? UnreadThreads(UnsignedInt(json)) : null; + } + + @override + int? toJson(UnreadThreads? object) { + return object?.value.value.toInt(); + } +} \ No newline at end of file diff --git a/lib/http/converter/unsigned_int_nullable_converter.dart b/lib/http/converter/unsigned_int_nullable_converter.dart new file mode 100644 index 0000000..e5bc233 --- /dev/null +++ b/lib/http/converter/unsigned_int_nullable_converter.dart @@ -0,0 +1,16 @@ +import 'package:jmap_dart_client/jmap/core/unsigned_int.dart'; +import 'package:json_annotation/json_annotation.dart'; + +class UnsignedIntNullableConverter implements JsonConverter { + const UnsignedIntNullableConverter(); + + @override + UnsignedInt? fromJson(int? json) { + return json != null ? UnsignedInt(json) : null; + } + + @override + int? toJson(UnsignedInt? object) { + return object?.value.toInt(); + } +} \ No newline at end of file diff --git a/lib/jmap/mail/mailbox/mailbox.dart b/lib/jmap/mail/mailbox/mailbox.dart index 0831829..1a87e7b 100644 --- a/lib/jmap/mail/mailbox/mailbox.dart +++ b/lib/jmap/mail/mailbox/mailbox.dart @@ -1,15 +1,28 @@ import 'package:equatable/equatable.dart'; +import 'package:jmap_dart_client/http/converter/is_subscribed_converter.dart'; import 'package:jmap_dart_client/http/converter/mailbox_id_converter.dart'; import 'package:jmap_dart_client/http/converter/mailbox_id_nullable_converter.dart'; import 'package:jmap_dart_client/http/converter/mailbox_name_converter.dart'; import 'package:jmap_dart_client/http/converter/role_converter.dart'; +import 'package:jmap_dart_client/http/converter/sort_order_converter.dart'; +import 'package:jmap_dart_client/http/converter/total_email_converter.dart'; +import 'package:jmap_dart_client/http/converter/total_threads_converter.dart'; +import 'package:jmap_dart_client/http/converter/unread_emails_converter.dart'; +import 'package:jmap_dart_client/http/converter/unread_threads_converter.dart'; import 'package:jmap_dart_client/jmap/core/id.dart'; import 'package:jmap_dart_client/jmap/core/properties/properties.dart'; import 'package:jmap_dart_client/jmap/core/unsigned_int.dart'; +import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox_rights.dart'; import 'package:json_annotation/json_annotation.dart'; part 'mailbox.g.dart'; +@IsSubscribedConverter() +@UnreadThreadsConverter() +@UnreadEmailsConverter() +@TotalThreadsConverter() +@TotalEmailConverter() +@SortOrderConverter() @RoleConverter() @MailboxIdNullableConverter() @MailboxNameConverter() @@ -129,114 +142,6 @@ class UnreadThreads with EquatableMixin { List get props => [value]; } -class MailboxRights with EquatableMixin { - final MayReadItems mayReadItems; - final MayAddItems mayAddItems; - final MayRemoveItems mayRemoveItems; - final MaySetSeen maySetSeen; - final MaySetKeywords maySetKeywords; - final MayCreateChild mayCreateChild; - final MayRename mayRename; - final MayDelete mayDelete; - final MaySubmit maySubmit; - - MailboxRights( - this.mayReadItems, - this.mayAddItems, - this.mayRemoveItems, - this.maySetSeen, - this.maySetKeywords, - this.mayCreateChild, - this.mayRename, - this.mayDelete, - this.maySubmit); - - @override - List get props => [mayReadItems, mayAddItems, mayRemoveItems, maySetSeen, - maySetKeywords, mayCreateChild, mayRename, mayDelete, maySubmit]; -} - -class MayReadItems with EquatableMixin { - final bool value; - - MayReadItems(this.value); - - @override - List get props => [value]; -} - -class MayAddItems with EquatableMixin{ - final bool value; - - MayAddItems(this.value); - - @override - List get props => [value]; -} - -class MayRemoveItems with EquatableMixin { - final bool value; - - MayRemoveItems(this.value); - - @override - List get props => [value]; -} - -class MaySetSeen with EquatableMixin { - final bool value; - - MaySetSeen(this.value); - - @override - List get props => [value]; -} - -class MaySetKeywords with EquatableMixin { - final bool value; - - MaySetKeywords(this.value); - - @override - List get props => [value]; -} - -class MayCreateChild with EquatableMixin { - final bool value; - - MayCreateChild(this.value); - - @override - List get props => [value]; -} - -class MayRename with EquatableMixin { - final bool value; - - MayRename(this.value); - - @override - List get props => [value]; -} - -class MayDelete with EquatableMixin { - final bool value; - - MayDelete(this.value); - - @override - List get props => [value]; -} - -class MaySubmit with EquatableMixin { - final bool value; - - MaySubmit(this.value); - - @override - List get props => [value]; -} - class IsSubscribed with EquatableMixin { final bool value; @@ -245,4 +150,3 @@ class IsSubscribed with EquatableMixin { @override List get props => [value]; } - diff --git a/lib/jmap/mail/mailbox/mailbox_rights.dart b/lib/jmap/mail/mailbox/mailbox_rights.dart new file mode 100644 index 0000000..7352583 --- /dev/null +++ b/lib/jmap/mail/mailbox/mailbox_rights.dart @@ -0,0 +1,36 @@ +import 'package:equatable/equatable.dart'; +import 'package:json_annotation/json_annotation.dart'; + +part 'mailbox_rights.g.dart'; + +@JsonSerializable() +class MailboxRights with EquatableMixin { + final bool mayReadItems; + final bool mayAddItems; + final bool mayRemoveItems; + final bool maySetSeen; + final bool maySetKeywords; + final bool mayCreateChild; + final bool mayRename; + final bool mayDelete; + final bool maySubmit; + + MailboxRights( + this.mayReadItems, + this.mayAddItems, + this.mayRemoveItems, + this.maySetSeen, + this.maySetKeywords, + this.mayCreateChild, + this.mayRename, + this.mayDelete, + this.maySubmit); + + factory MailboxRights.fromJson(Map json) { + return _$MailboxRightsFromJson(json); + } + + @override + List get props => [mayReadItems, mayAddItems, mayRemoveItems, maySetSeen, + maySetKeywords, mayCreateChild, mayRename, mayDelete, maySubmit]; +} From be90960644644c444583ade939849e90546c32ab Mon Sep 17 00:00:00 2001 From: Dat PHAM HOANG Date: Thu, 8 Jul 2021 12:08:35 +0700 Subject: [PATCH 14/20] Invocation can create ResultReference --- .../converter/reference_path_converter.dart | 12 ++++++++ lib/jmap/core/method/request/get_method.dart | 22 ++++++++++++++- lib/jmap/core/request/reference_path.dart | 14 ++++++++++ lib/jmap/core/request/request_invocation.dart | 6 ++++ lib/jmap/core/request/result_reference.dart | 28 +++++++++++++++++++ lib/jmap/jmap_request.dart | 9 ++++++ 6 files changed, 90 insertions(+), 1 deletion(-) create mode 100644 lib/http/converter/reference_path_converter.dart create mode 100644 lib/jmap/core/request/reference_path.dart create mode 100644 lib/jmap/core/request/result_reference.dart diff --git a/lib/http/converter/reference_path_converter.dart b/lib/http/converter/reference_path_converter.dart new file mode 100644 index 0000000..1721f2e --- /dev/null +++ b/lib/http/converter/reference_path_converter.dart @@ -0,0 +1,12 @@ +import 'package:jmap_dart_client/jmap/core/request/reference_path.dart'; +import 'package:json_annotation/json_annotation.dart'; + +class ReferencePathConverter implements JsonConverter { + const ReferencePathConverter(); + + @override + ReferencePath fromJson(String json) => ReferencePath(json); + + @override + String toJson(ReferencePath object) => object.value; +} \ No newline at end of file diff --git a/lib/jmap/core/method/request/get_method.dart b/lib/jmap/core/method/request/get_method.dart index 28c1d94..d17991f 100644 --- a/lib/jmap/core/method/request/get_method.dart +++ b/lib/jmap/core/method/request/get_method.dart @@ -2,9 +2,11 @@ import 'package:jmap_dart_client/jmap/account_id.dart'; import 'package:jmap_dart_client/jmap/core/id.dart'; import 'package:jmap_dart_client/jmap/core/method/method.dart'; import 'package:jmap_dart_client/jmap/core/properties/properties.dart'; +import 'package:jmap_dart_client/jmap/core/request/result_reference.dart'; import 'package:json_annotation/json_annotation.dart'; -abstract class GetMethod extends MethodRequiringAccountId with OptionalIds, OptionalProperties { +abstract class GetMethod extends MethodRequiringAccountId + with OptionalIds, OptionalProperties, OptionalReferenceIds, OptionalReferenceProperties { GetMethod(AccountId accountId) : super(accountId); } @@ -20,6 +22,15 @@ mixin OptionalIds { } } +mixin OptionalReferenceIds { + @JsonKey(name: '#ids', includeIfNull: false) + ResultReference? referenceIds; + + void addReferenceIds(ResultReference resultReferenceIds) { + referenceIds = resultReferenceIds; + } +} + mixin OptionalProperties { @JsonKey(includeIfNull: false) Properties? properties = Properties.empty(); @@ -28,3 +39,12 @@ mixin OptionalProperties { properties = properties?.union(other); } } + +mixin OptionalReferenceProperties { + @JsonKey(name: '#properties', includeIfNull: false) + ResultReference? referenceProperties; + + void addReferenceProperties(ResultReference resultReferenceProperties) { + referenceProperties = resultReferenceProperties; + } +} \ No newline at end of file diff --git a/lib/jmap/core/request/reference_path.dart b/lib/jmap/core/request/reference_path.dart new file mode 100644 index 0000000..f05c966 --- /dev/null +++ b/lib/jmap/core/request/reference_path.dart @@ -0,0 +1,14 @@ +import 'package:equatable/equatable.dart'; + +class ReferencePath with EquatableMixin { + static ReferencePath createdPath = ReferencePath('created/*'); + static ReferencePath updatedPath = ReferencePath('updated/*'); + static ReferencePath updatedPropertiesPath = ReferencePath('updatedProperties'); + + final String value; + + ReferencePath(this.value); + + @override + List get props => [value]; +} \ No newline at end of file diff --git a/lib/jmap/core/request/request_invocation.dart b/lib/jmap/core/request/request_invocation.dart index cadebc6..9572948 100644 --- a/lib/jmap/core/request/request_invocation.dart +++ b/lib/jmap/core/request/request_invocation.dart @@ -1,4 +1,6 @@ import 'package:equatable/equatable.dart'; +import 'package:jmap_dart_client/jmap/core/request/reference_path.dart'; +import 'package:jmap_dart_client/jmap/core/request/result_reference.dart'; import '../method/method.dart'; @@ -8,6 +10,10 @@ class RequestInvocation { final MethodCallId methodCallId; RequestInvocation(this.methodName, this.arguments, this.methodCallId); + + ResultReference createResultReference(ReferencePath path) { + return ResultReference(methodCallId, arguments.value.methodName, path); + } } class MethodName with EquatableMixin { diff --git a/lib/jmap/core/request/result_reference.dart b/lib/jmap/core/request/result_reference.dart new file mode 100644 index 0000000..71d6c3f --- /dev/null +++ b/lib/jmap/core/request/result_reference.dart @@ -0,0 +1,28 @@ +import 'package:equatable/equatable.dart'; +import 'package:jmap_dart_client/http/converter/method_call_id_converter.dart'; +import 'package:jmap_dart_client/http/converter/method_name_converter.dart'; +import 'package:jmap_dart_client/http/converter/reference_path_converter.dart'; +import 'package:jmap_dart_client/jmap/core/request/reference_path.dart'; +import 'package:jmap_dart_client/jmap/core/request/request_invocation.dart'; +import 'package:json_annotation/json_annotation.dart'; + +part 'result_reference.g.dart'; + +@ReferencePathConverter() +@MethodNameConverter() +@MethodCallIdConverter() +@JsonSerializable() +class ResultReference with EquatableMixin { + final MethodCallId resultOf; + final MethodName name; + final ReferencePath path; + + ResultReference(this.resultOf, this.name, this.path); + + @override + List get props => [resultOf, name, path]; + + factory ResultReference.fromJson(Map json) => _$ResultReferenceFromJson(json); + + Map toJson() => _$ResultReferenceToJson(this); +} \ No newline at end of file diff --git a/lib/jmap/jmap_request.dart b/lib/jmap/jmap_request.dart index b00e895..f397252 100644 --- a/lib/jmap/jmap_request.dart +++ b/lib/jmap/jmap_request.dart @@ -1,7 +1,11 @@ + import 'package:built_collection/built_collection.dart'; import 'package:jmap_dart_client/http/http_client.dart'; +import 'package:jmap_dart_client/jmap/core/request/reference_path.dart'; +import 'package:jmap_dart_client/jmap/core/request/result_reference.dart'; import 'package:jmap_dart_client/jmap/core/response/response_object.dart'; import 'package:jmap_dart_client/util/util.dart'; +import 'package:quiver/check.dart'; import 'core/capability/capability.dart'; import 'core/method/method.dart'; @@ -80,4 +84,9 @@ class ProcessingInvocation { ..addAll({callId: requestInvocation})) .build(); } + + ResultReference createResultReference(MethodCallId methodCallId, ReferencePath path) { + checkArgument(_invocations.containsKey(methodCallId), message: 'no matched method call id'); + return _invocations[methodCallId]!.createResultReference(path); + } } From 2e8e7b9dbe436754a4fefb7b6306fcdd9198923f Mon Sep 17 00:00:00 2001 From: Dat PHAM HOANG Date: Thu, 8 Jul 2021 12:13:12 +0700 Subject: [PATCH 15/20] change deserialize method name for response --- lib/jmap/core/response/response_object.dart | 2 +- lib/jmap/mail/mailbox/{ => get}/get_mailbox_response.dart | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename lib/jmap/mail/mailbox/{ => get}/get_mailbox_response.dart (94%) diff --git a/lib/jmap/core/response/response_object.dart b/lib/jmap/core/response/response_object.dart index 7a705ca..6c67b27 100644 --- a/lib/jmap/core/response/response_object.dart +++ b/lib/jmap/core/response/response_object.dart @@ -24,7 +24,7 @@ class ResponseObject with EquatableMixin { Map toJson() => _$ResponseObjectToJson(this); - Future parse(MethodCallId methodCallId, T fromJson(Map o)) async { + T? parse(MethodCallId methodCallId, T fromJson(Map o)) { try { final matchedResponse = methodResponses.firstWhere((method) => method.methodCallId == methodCallId); return fromJson(matchedResponse.arguments.value); diff --git a/lib/jmap/mail/mailbox/get_mailbox_response.dart b/lib/jmap/mail/mailbox/get/get_mailbox_response.dart similarity index 94% rename from lib/jmap/mail/mailbox/get_mailbox_response.dart rename to lib/jmap/mail/mailbox/get/get_mailbox_response.dart index 1bca718..d917404 100644 --- a/lib/jmap/mail/mailbox/get_mailbox_response.dart +++ b/lib/jmap/mail/mailbox/get/get_mailbox_response.dart @@ -19,7 +19,7 @@ class GetMailboxResponse extends GetResponse { factory GetMailboxResponse.fromJson(Map json) => _$GetMailboxResponseFromJson(json); - static GetMailboxResponse fromJson1(Map json) { + static GetMailboxResponse deserialize(Map json) { return GetMailboxResponse.fromJson(json); } From a424508f115b98b9b93ce8f4530a6ab414b8f963 Mon Sep 17 00:00:00 2001 From: Dat PHAM HOANG Date: Thu, 8 Jul 2021 12:16:43 +0700 Subject: [PATCH 16/20] Move getMailboxMethod to get directory --- .gitignore | 3 --- lib/jmap/core/capability.dart | 14 -------------- lib/jmap/entity/mailbox.dart | 0 .../mail/mailbox/{ => get}/get_mailbox_method.dart | 1 + 4 files changed, 1 insertion(+), 17 deletions(-) delete mode 100644 lib/jmap/core/capability.dart delete mode 100644 lib/jmap/entity/mailbox.dart rename lib/jmap/mail/mailbox/{ => get}/get_mailbox_method.dart (94%) diff --git a/.gitignore b/.gitignore index 45dcd86..62d9ea0 100644 --- a/.gitignore +++ b/.gitignore @@ -116,6 +116,3 @@ app.*.symbols !**/ios/**/default.perspectivev3 !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages !/dev/ci/**/Gemfile.lock - -#generated file -*.g.dart \ No newline at end of file diff --git a/lib/jmap/core/capability.dart b/lib/jmap/core/capability.dart deleted file mode 100644 index d761aac..0000000 --- a/lib/jmap/core/capability.dart +++ /dev/null @@ -1,14 +0,0 @@ -import 'package:equatable/equatable.dart'; - -class CapabilityIdentifier with EquatableMixin { - static final jmapCore = CapabilityIdentifier('urn:ietf:params:jmap:core'); - static final jmapMail = CapabilityIdentifier('urn:ietf:params:jmap:mail'); - - final String value; - - CapabilityIdentifier(this.value); - - @override - List get props => [value]; -} - diff --git a/lib/jmap/entity/mailbox.dart b/lib/jmap/entity/mailbox.dart deleted file mode 100644 index e69de29..0000000 diff --git a/lib/jmap/mail/mailbox/get_mailbox_method.dart b/lib/jmap/mail/mailbox/get/get_mailbox_method.dart similarity index 94% rename from lib/jmap/mail/mailbox/get_mailbox_method.dart rename to lib/jmap/mail/mailbox/get/get_mailbox_method.dart index 8e6fb0b..b686140 100644 --- a/lib/jmap/mail/mailbox/get_mailbox_method.dart +++ b/lib/jmap/mail/mailbox/get/get_mailbox_method.dart @@ -5,6 +5,7 @@ import 'package:jmap_dart_client/jmap/account_id.dart'; import 'package:jmap_dart_client/jmap/core/capability/capability.dart'; import 'package:jmap_dart_client/jmap/core/method/request/get_method.dart'; import 'package:jmap_dart_client/jmap/core/request/request_invocation.dart'; +import 'package:jmap_dart_client/jmap/core/request/result_reference.dart'; import 'package:json_annotation/json_annotation.dart'; part 'get_mailbox_method.g.dart'; From 4c7e0dbc1a57cb7eabe67b21b34220fcfe431161 Mon Sep 17 00:00:00 2001 From: Dat PHAM HOANG Date: Thu, 8 Jul 2021 12:17:15 +0700 Subject: [PATCH 17/20] Abstraction for Changes method/response --- lib/jmap/core/method/request/changes_method.dart | 14 ++++++++++++++ .../core/method/response/changes_response.dart | 16 ++++++++++++++++ 2 files changed, 30 insertions(+) create mode 100644 lib/jmap/core/method/request/changes_method.dart create mode 100644 lib/jmap/core/method/response/changes_response.dart diff --git a/lib/jmap/core/method/request/changes_method.dart b/lib/jmap/core/method/request/changes_method.dart new file mode 100644 index 0000000..ec30aba --- /dev/null +++ b/lib/jmap/core/method/request/changes_method.dart @@ -0,0 +1,14 @@ +import 'package:jmap_dart_client/jmap/account_id.dart'; +import 'package:jmap_dart_client/jmap/core/method/method.dart'; +import 'package:jmap_dart_client/jmap/core/state.dart'; +import 'package:jmap_dart_client/jmap/core/unsigned_int.dart'; +import 'package:json_annotation/json_annotation.dart'; + +abstract class ChangesMethod extends MethodRequiringAccountId { + final State sinceState; + + @JsonKey(includeIfNull: false) + final UnsignedInt? maxChanges; + + ChangesMethod(AccountId accountId, this.sinceState, {this.maxChanges}) : super(accountId); +} \ No newline at end of file diff --git a/lib/jmap/core/method/response/changes_response.dart b/lib/jmap/core/method/response/changes_response.dart new file mode 100644 index 0000000..b85b0ac --- /dev/null +++ b/lib/jmap/core/method/response/changes_response.dart @@ -0,0 +1,16 @@ +import 'package:jmap_dart_client/jmap/account_id.dart'; +import 'package:jmap_dart_client/jmap/core/id.dart'; +import 'package:jmap_dart_client/jmap/core/method/method_response.dart'; +import 'package:jmap_dart_client/jmap/core/state.dart'; + +abstract class ChangesResponse extends ResponseRequiringAccountId { + final State oldState; + final State newState; + final bool hasMoreChanges; + final Set created; + final Set updated; + final Set destroyed; + + ChangesResponse(AccountId accountId, this.oldState, this.newState, this.hasMoreChanges, + this.created, this.updated, this.destroyed) : super(accountId); +} \ No newline at end of file From 9f958cbc163980912ad812b579020dfa57e7e2a0 Mon Sep 17 00:00:00 2001 From: Dat PHAM HOANG Date: Thu, 8 Jul 2021 12:17:50 +0700 Subject: [PATCH 18/20] Implement ChangesMailboxMethod/Response --- .../changes/changes_mailbox_method.dart | 35 ++++++++++++++++ .../changes/changes_mailbox_response.dart | 41 +++++++++++++++++++ 2 files changed, 76 insertions(+) create mode 100644 lib/jmap/mail/mailbox/changes/changes_mailbox_method.dart create mode 100644 lib/jmap/mail/mailbox/changes/changes_mailbox_response.dart diff --git a/lib/jmap/mail/mailbox/changes/changes_mailbox_method.dart b/lib/jmap/mail/mailbox/changes/changes_mailbox_method.dart new file mode 100644 index 0000000..b7bb372 --- /dev/null +++ b/lib/jmap/mail/mailbox/changes/changes_mailbox_method.dart @@ -0,0 +1,35 @@ +import 'package:jmap_dart_client/http/converter/account_id_converter.dart'; +import 'package:jmap_dart_client/http/converter/state_converter.dart'; +import 'package:jmap_dart_client/http/converter/unsigned_int_nullable_converter.dart'; +import 'package:jmap_dart_client/jmap/account_id.dart'; +import 'package:jmap_dart_client/jmap/core/capability/capability.dart'; +import 'package:jmap_dart_client/jmap/core/method/request/changes_method.dart'; +import 'package:jmap_dart_client/jmap/core/request/request_invocation.dart'; +import 'package:jmap_dart_client/jmap/core/state.dart'; +import 'package:jmap_dart_client/jmap/core/unsigned_int.dart'; +import 'package:json_annotation/json_annotation.dart'; + +part 'changes_mailbox_method.g.dart'; + +@UnsignedIntNullableConverter() +@StateConverter() +@AccountIdConverter() +@JsonSerializable() +class ChangesMailboxMethod extends ChangesMethod { + ChangesMailboxMethod(AccountId accountId, State sinceState, {UnsignedInt? maxChanges}) + : super(accountId, sinceState, maxChanges: maxChanges); + + @override + MethodName get methodName => MethodName('Mailbox/changes'); + + @override + List get props => [accountId, sinceState, maxChanges]; + + @override + Set get requiredCapabilities => {CapabilityIdentifier.jmapMail}; + + factory ChangesMailboxMethod.fromJson(Map json) => _$ChangesMailboxMethodFromJson(json); + + @override + Map toJson() => _$ChangesMailboxMethodToJson(this); +} \ No newline at end of file diff --git a/lib/jmap/mail/mailbox/changes/changes_mailbox_response.dart b/lib/jmap/mail/mailbox/changes/changes_mailbox_response.dart new file mode 100644 index 0000000..6947fd0 --- /dev/null +++ b/lib/jmap/mail/mailbox/changes/changes_mailbox_response.dart @@ -0,0 +1,41 @@ +import 'package:jmap_dart_client/http/converter/account_id_converter.dart'; +import 'package:jmap_dart_client/http/converter/id_converter.dart'; +import 'package:jmap_dart_client/http/converter/properties_converter.dart'; +import 'package:jmap_dart_client/http/converter/state_converter.dart'; +import 'package:jmap_dart_client/jmap/account_id.dart'; +import 'package:jmap_dart_client/jmap/core/id.dart'; +import 'package:jmap_dart_client/jmap/core/method/response/changes_response.dart'; +import 'package:jmap_dart_client/jmap/core/properties/properties.dart'; +import 'package:jmap_dart_client/jmap/core/state.dart'; +import 'package:json_annotation/json_annotation.dart'; + +part 'changes_mailbox_response.g.dart'; + +@PropertiesConverter() +@IdConverter() +@StateConverter() +@AccountIdConverter() +@JsonSerializable() +class ChangesMailboxResponse extends ChangesResponse { + final Properties? updatedProperties; + + ChangesMailboxResponse( + AccountId accountId, + State oldState, + State newState, + bool hasMoreChanges, + Set created, + Set updated, + Set destroyed, + {this.updatedProperties} + ) : super(accountId, oldState, newState, hasMoreChanges, created, updated, destroyed); + + factory ChangesMailboxResponse.fromJson(Map json) => _$ChangesMailboxResponseFromJson(json); + + static ChangesMailboxResponse deserialize(Map json) { + return ChangesMailboxResponse.fromJson(json); + } + + @override + List get props => [accountId, oldState, newState, hasMoreChanges, created, updated, destroyed, updatedProperties]; +} \ No newline at end of file From c4482d1e8911c59fc40f024b9742f030f4143932 Mon Sep 17 00:00:00 2001 From: Dat PHAM HOANG Date: Fri, 9 Jul 2021 14:56:19 +0700 Subject: [PATCH 19/20] Add .g files to support build_run in serialize/deserialize --- lib/jmap/account_id.g.dart | 17 ++++++++ lib/jmap/core/request/request_object.g.dart | 28 ++++++++++++ lib/jmap/core/request/result_reference.g.dart | 22 ++++++++++ lib/jmap/core/response/response_object.g.dart | 24 +++++++++++ .../changes/changes_mailbox_method.g.dart | 34 +++++++++++++++ .../changes/changes_mailbox_response.g.dart | 42 ++++++++++++++++++ .../mailbox/get/get_mailbox_method.g.dart | 43 +++++++++++++++++++ .../mailbox/get/get_mailbox_response.g.dart | 28 ++++++++++++ lib/jmap/mail/mailbox/mailbox.g.dart | 43 +++++++++++++++++++ lib/jmap/mail/mailbox/mailbox_rights.g.dart | 34 +++++++++++++++ 10 files changed, 315 insertions(+) create mode 100644 lib/jmap/account_id.g.dart create mode 100644 lib/jmap/core/request/request_object.g.dart create mode 100644 lib/jmap/core/request/result_reference.g.dart create mode 100644 lib/jmap/core/response/response_object.g.dart create mode 100644 lib/jmap/mail/mailbox/changes/changes_mailbox_method.g.dart create mode 100644 lib/jmap/mail/mailbox/changes/changes_mailbox_response.g.dart create mode 100644 lib/jmap/mail/mailbox/get/get_mailbox_method.g.dart create mode 100644 lib/jmap/mail/mailbox/get/get_mailbox_response.g.dart create mode 100644 lib/jmap/mail/mailbox/mailbox.g.dart create mode 100644 lib/jmap/mail/mailbox/mailbox_rights.g.dart diff --git a/lib/jmap/account_id.g.dart b/lib/jmap/account_id.g.dart new file mode 100644 index 0000000..7084dc0 --- /dev/null +++ b/lib/jmap/account_id.g.dart @@ -0,0 +1,17 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'account_id.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +AccountId _$AccountIdFromJson(Map json) { + return AccountId( + const IdConverter().fromJson(json['id'] as String), + ); +} + +Map _$AccountIdToJson(AccountId instance) => { + 'id': const IdConverter().toJson(instance.id), + }; diff --git a/lib/jmap/core/request/request_object.g.dart b/lib/jmap/core/request/request_object.g.dart new file mode 100644 index 0000000..ea14e7f --- /dev/null +++ b/lib/jmap/core/request/request_object.g.dart @@ -0,0 +1,28 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'request_object.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +RequestObject _$RequestObjectFromJson(Map json) { + return RequestObject( + (json['using'] as List) + .map((e) => const CapabilityIdentifierConverter().fromJson(e as String)) + .toSet(), + (json['methodCalls'] as List) + .map((e) => const RequestInvocationConverter().fromJson(e as List)) + .toList(), + ); +} + +Map _$RequestObjectToJson(RequestObject instance) => + { + 'using': instance.using + .map(const CapabilityIdentifierConverter().toJson) + .toList(), + 'methodCalls': instance.methodCalls + .map(const RequestInvocationConverter().toJson) + .toList(), + }; diff --git a/lib/jmap/core/request/result_reference.g.dart b/lib/jmap/core/request/result_reference.g.dart new file mode 100644 index 0000000..483f540 --- /dev/null +++ b/lib/jmap/core/request/result_reference.g.dart @@ -0,0 +1,22 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'result_reference.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +ResultReference _$ResultReferenceFromJson(Map json) { + return ResultReference( + const MethodCallIdConverter().fromJson(json['resultOf'] as String), + const MethodNameConverter().fromJson(json['name'] as String), + const ReferencePathConverter().fromJson(json['path'] as String), + ); +} + +Map _$ResultReferenceToJson(ResultReference instance) => + { + 'resultOf': const MethodCallIdConverter().toJson(instance.resultOf), + 'name': const MethodNameConverter().toJson(instance.name), + 'path': const ReferencePathConverter().toJson(instance.path), + }; diff --git a/lib/jmap/core/response/response_object.g.dart b/lib/jmap/core/response/response_object.g.dart new file mode 100644 index 0000000..d002c65 --- /dev/null +++ b/lib/jmap/core/response/response_object.g.dart @@ -0,0 +1,24 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'response_object.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +ResponseObject _$ResponseObjectFromJson(Map json) { + return ResponseObject( + (json['methodResponses'] as List) + .map((e) => const ResponseInvocationConverter().fromJson(e as List)) + .toList(), + const StateConverter().fromJson(json['sessionState'] as String), + ); +} + +Map _$ResponseObjectToJson(ResponseObject instance) => + { + 'methodResponses': instance.methodResponses + .map(const ResponseInvocationConverter().toJson) + .toList(), + 'sessionState': const StateConverter().toJson(instance.sessionState), + }; diff --git a/lib/jmap/mail/mailbox/changes/changes_mailbox_method.g.dart b/lib/jmap/mail/mailbox/changes/changes_mailbox_method.g.dart new file mode 100644 index 0000000..74ebcac --- /dev/null +++ b/lib/jmap/mail/mailbox/changes/changes_mailbox_method.g.dart @@ -0,0 +1,34 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'changes_mailbox_method.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +ChangesMailboxMethod _$ChangesMailboxMethodFromJson(Map json) { + return ChangesMailboxMethod( + const AccountIdConverter().fromJson(json['accountId'] as String), + const StateConverter().fromJson(json['sinceState'] as String), + maxChanges: const UnsignedIntNullableConverter() + .fromJson(json['maxChanges'] as int?), + ); +} + +Map _$ChangesMailboxMethodToJson( + ChangesMailboxMethod instance) { + final val = { + 'accountId': const AccountIdConverter().toJson(instance.accountId), + 'sinceState': const StateConverter().toJson(instance.sinceState), + }; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('maxChanges', + const UnsignedIntNullableConverter().toJson(instance.maxChanges)); + return val; +} diff --git a/lib/jmap/mail/mailbox/changes/changes_mailbox_response.g.dart b/lib/jmap/mail/mailbox/changes/changes_mailbox_response.g.dart new file mode 100644 index 0000000..2e2a3df --- /dev/null +++ b/lib/jmap/mail/mailbox/changes/changes_mailbox_response.g.dart @@ -0,0 +1,42 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'changes_mailbox_response.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +ChangesMailboxResponse _$ChangesMailboxResponseFromJson( + Map json) { + return ChangesMailboxResponse( + const AccountIdConverter().fromJson(json['accountId'] as String), + const StateConverter().fromJson(json['oldState'] as String), + const StateConverter().fromJson(json['newState'] as String), + json['hasMoreChanges'] as bool, + (json['created'] as List) + .map((e) => const IdConverter().fromJson(e as String)) + .toSet(), + (json['updated'] as List) + .map((e) => const IdConverter().fromJson(e as String)) + .toSet(), + (json['destroyed'] as List) + .map((e) => const IdConverter().fromJson(e as String)) + .toSet(), + updatedProperties: const PropertiesConverter() + .fromJson(json['updatedProperties'] as List?), + ); +} + +Map _$ChangesMailboxResponseToJson( + ChangesMailboxResponse instance) => + { + 'accountId': const AccountIdConverter().toJson(instance.accountId), + 'oldState': const StateConverter().toJson(instance.oldState), + 'newState': const StateConverter().toJson(instance.newState), + 'hasMoreChanges': instance.hasMoreChanges, + 'created': instance.created.map(const IdConverter().toJson).toList(), + 'updated': instance.updated.map(const IdConverter().toJson).toList(), + 'destroyed': instance.destroyed.map(const IdConverter().toJson).toList(), + 'updatedProperties': + const PropertiesConverter().toJson(instance.updatedProperties), + }; diff --git a/lib/jmap/mail/mailbox/get/get_mailbox_method.g.dart b/lib/jmap/mail/mailbox/get/get_mailbox_method.g.dart new file mode 100644 index 0000000..67c577d --- /dev/null +++ b/lib/jmap/mail/mailbox/get/get_mailbox_method.g.dart @@ -0,0 +1,43 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'get_mailbox_method.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +GetMailboxMethod _$GetMailboxMethodFromJson(Map json) { + return GetMailboxMethod( + const AccountIdConverter().fromJson(json['accountId'] as String), + ) + ..ids = (json['ids'] as List?) + ?.map((e) => const IdConverter().fromJson(e as String)) + .toSet() + ..referenceIds = json['#ids'] == null + ? null + : ResultReference.fromJson(json['#ids'] as Map) + ..properties = const PropertiesConverter() + .fromJson(json['properties'] as List?) + ..referenceProperties = json['#properties'] == null + ? null + : ResultReference.fromJson(json['#properties'] as Map); +} + +Map _$GetMailboxMethodToJson(GetMailboxMethod instance) { + final val = { + 'accountId': const AccountIdConverter().toJson(instance.accountId), + }; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('ids', instance.ids?.map(const IdConverter().toJson).toList()); + writeNotNull('#ids', instance.referenceIds); + writeNotNull( + 'properties', const PropertiesConverter().toJson(instance.properties)); + writeNotNull('#properties', instance.referenceProperties); + return val; +} diff --git a/lib/jmap/mail/mailbox/get/get_mailbox_response.g.dart b/lib/jmap/mail/mailbox/get/get_mailbox_response.g.dart new file mode 100644 index 0000000..ffd1316 --- /dev/null +++ b/lib/jmap/mail/mailbox/get/get_mailbox_response.g.dart @@ -0,0 +1,28 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'get_mailbox_response.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +GetMailboxResponse _$GetMailboxResponseFromJson(Map json) { + return GetMailboxResponse( + const AccountIdConverter().fromJson(json['accountId'] as String), + const StateConverter().fromJson(json['state'] as String), + (json['list'] as List) + .map((e) => Mailbox.fromJson(e as Map)) + .toList(), + (json['notFound'] as List?) + ?.map((e) => const IdConverter().fromJson(e as String)) + .toList(), + ); +} + +Map _$GetMailboxResponseToJson(GetMailboxResponse instance) => + { + 'accountId': const AccountIdConverter().toJson(instance.accountId), + 'state': const StateConverter().toJson(instance.state), + 'list': instance.list, + 'notFound': instance.notFound?.map(const IdConverter().toJson).toList(), + }; diff --git a/lib/jmap/mail/mailbox/mailbox.g.dart b/lib/jmap/mail/mailbox/mailbox.g.dart new file mode 100644 index 0000000..0ab8d54 --- /dev/null +++ b/lib/jmap/mail/mailbox/mailbox.g.dart @@ -0,0 +1,43 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'mailbox.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +Mailbox _$MailboxFromJson(Map json) { + return Mailbox( + const MailboxIdConverter().fromJson(json['id'] as String), + const MailboxNameConverter().fromJson(json['name'] as String?), + const MailboxIdNullableConverter().fromJson(json['parentId'] as String?), + const RoleConverter().fromJson(json['role'] as String?), + const SortOrderConverter().fromJson(json['sortOrder'] as int?), + const TotalEmailConverter().fromJson(json['totalEmails'] as int?), + const UnreadEmailsConverter().fromJson(json['unreadEmails'] as int?), + const TotalThreadsConverter().fromJson(json['totalThreads'] as int?), + const UnreadThreadsConverter().fromJson(json['unreadThreads'] as int?), + json['myRights'] == null + ? null + : MailboxRights.fromJson(json['myRights'] as Map), + const IsSubscribedConverter().fromJson(json['isSubscribed'] as bool?), + ); +} + +Map _$MailboxToJson(Mailbox instance) => { + 'id': const MailboxIdConverter().toJson(instance.id), + 'name': const MailboxNameConverter().toJson(instance.name), + 'parentId': const MailboxIdNullableConverter().toJson(instance.parentId), + 'role': const RoleConverter().toJson(instance.role), + 'sortOrder': const SortOrderConverter().toJson(instance.sortOrder), + 'totalEmails': const TotalEmailConverter().toJson(instance.totalEmails), + 'unreadEmails': + const UnreadEmailsConverter().toJson(instance.unreadEmails), + 'totalThreads': + const TotalThreadsConverter().toJson(instance.totalThreads), + 'unreadThreads': + const UnreadThreadsConverter().toJson(instance.unreadThreads), + 'myRights': instance.myRights, + 'isSubscribed': + const IsSubscribedConverter().toJson(instance.isSubscribed), + }; diff --git a/lib/jmap/mail/mailbox/mailbox_rights.g.dart b/lib/jmap/mail/mailbox/mailbox_rights.g.dart new file mode 100644 index 0000000..2c83ded --- /dev/null +++ b/lib/jmap/mail/mailbox/mailbox_rights.g.dart @@ -0,0 +1,34 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'mailbox_rights.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +MailboxRights _$MailboxRightsFromJson(Map json) { + return MailboxRights( + json['mayReadItems'] as bool, + json['mayAddItems'] as bool, + json['mayRemoveItems'] as bool, + json['maySetSeen'] as bool, + json['maySetKeywords'] as bool, + json['mayCreateChild'] as bool, + json['mayRename'] as bool, + json['mayDelete'] as bool, + json['maySubmit'] as bool, + ); +} + +Map _$MailboxRightsToJson(MailboxRights instance) => + { + 'mayReadItems': instance.mayReadItems, + 'mayAddItems': instance.mayAddItems, + 'mayRemoveItems': instance.mayRemoveItems, + 'maySetSeen': instance.maySetSeen, + 'maySetKeywords': instance.maySetKeywords, + 'mayCreateChild': instance.mayCreateChild, + 'mayRename': instance.mayRename, + 'mayDelete': instance.mayDelete, + 'maySubmit': instance.maySubmit, + }; From 6afbb75fc0576501856fddf1c64bad61776585c7 Mon Sep 17 00:00:00 2001 From: Dat PHAM HOANG Date: Thu, 15 Jul 2021 16:48:35 +0700 Subject: [PATCH 20/20] Add jmapHeader to http client --- lib/http/http_client.dart | 10 +++++++++- lib/util/options_extensions.dart | 12 ++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 lib/util/options_extensions.dart diff --git a/lib/http/http_client.dart b/lib/http/http_client.dart index 5d4404b..a10e95d 100644 --- a/lib/http/http_client.dart +++ b/lib/http/http_client.dart @@ -1,6 +1,11 @@ +import 'dart:io'; + import 'package:dio/dio.dart'; +import 'package:jmap_dart_client/util/options_extensions.dart'; class HttpClient { + static const jmapHeader = 'application/json;jmapVersion=rfc-8621'; + final Dio _dio; HttpClient(this._dio); @@ -15,11 +20,14 @@ class HttpClient { ProgressCallback? onReceiveProgress, } ) async { + final newOptions = options?.appendHeaders({HttpHeaders.acceptHeader : jmapHeader}) + ?? Options(headers: {HttpHeaders.acceptHeader : jmapHeader}) ; + return await _dio.post( path, data: data, queryParameters: queryParameters, - options: options, + options: newOptions, cancelToken: cancelToken, onSendProgress: onSendProgress, onReceiveProgress: onReceiveProgress) diff --git a/lib/util/options_extensions.dart b/lib/util/options_extensions.dart new file mode 100644 index 0000000..f20e898 --- /dev/null +++ b/lib/util/options_extensions.dart @@ -0,0 +1,12 @@ +import 'package:dio/dio.dart'; + +extension OptionsExtension on Options { + Options appendHeaders(Map additionalHeaders) { + if (this.headers != null) { + this.headers?.addAll(additionalHeaders); + } else { + this.headers = additionalHeaders; + } + return this; + } +} \ No newline at end of file