diff --git a/lib/http/converter/individual_header_identifier_converter.dart b/lib/http/converter/individual_header_identifier_converter.dart new file mode 100644 index 0000000..8a4ae4f --- /dev/null +++ b/lib/http/converter/individual_header_identifier_converter.dart @@ -0,0 +1,11 @@ + +import 'package:jmap_dart_client/jmap/mail/email/individual_header_identifier.dart'; + +class IndividualHeaderIdentifierNullableConverter { + + MapEntry parseEntry(String key, String? value) => MapEntry(IndividualHeaderIdentifier(key), value); + + String? toJson(Map? header, IndividualHeaderIdentifier individualHeaderIdentifier) { + return header?[individualHeaderIdentifier]; + } +} \ No newline at end of file diff --git a/lib/jmap/mail/email/email.dart b/lib/jmap/mail/email/email.dart index 886fa03..9e8ea35 100644 --- a/lib/jmap/mail/email/email.dart +++ b/lib/jmap/mail/email/email.dart @@ -4,6 +4,7 @@ import 'package:jmap_dart_client/http/converter/email/email_mailbox_ids_converte import 'package:jmap_dart_client/http/converter/email_id_converter.dart'; import 'package:jmap_dart_client/http/converter/id_nullable_converter.dart'; import 'package:jmap_dart_client/http/converter/email/email_keyword_identifier_converter.dart'; +import 'package:jmap_dart_client/http/converter/individual_header_identifier_converter.dart'; import 'package:jmap_dart_client/http/converter/message_ids_header_value_converter.dart'; import 'package:jmap_dart_client/http/converter/thread_id_nullable_converter.dart'; import 'package:jmap_dart_client/http/converter/unsigned_int_nullable_converter.dart'; @@ -17,6 +18,7 @@ import 'package:jmap_dart_client/jmap/mail/email/email_address.dart'; import 'package:jmap_dart_client/jmap/mail/email/email_body_part.dart'; import 'package:jmap_dart_client/jmap/mail/email/email_body_value.dart'; import 'package:jmap_dart_client/jmap/mail/email/email_header.dart'; +import 'package:jmap_dart_client/jmap/mail/email/individual_header_identifier.dart'; import 'package:jmap_dart_client/jmap/mail/email/keyword_identifier.dart'; import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart'; @@ -52,6 +54,7 @@ class Email with EquatableMixin { final Set? attachments; final EmailBodyPart? bodyStructure; final Map? bodyValues; + final Map? headerUserAgent; Email( this.id, @@ -80,6 +83,7 @@ class Email with EquatableMixin { this.attachments, this.bodyStructure, this.bodyValues, + this.headerUserAgent, }); factory Email.fromJson(Map json) { @@ -118,6 +122,8 @@ class Email with EquatableMixin { ? null : EmailBodyPart.fromJson(json['bodyStructure'] as Map), bodyValues: (json['bodyValues'] as Map?)?.map((key, value) => EmailBodyValueConverter().parseEntry(key, value)), + headerUserAgent: (json[IndividualHeaderIdentifier.headerUserAgent.value] as Map?)?.map((key, value) => + MapEntry(IndividualHeaderIdentifier(key), value as String?)), ); } @@ -157,6 +163,7 @@ class Email with EquatableMixin { writeNotNull('attachments', attachments?.map((attachment) => attachment.toJson()).toList()); writeNotNull('bodyStructure', bodyStructure?.toJson()); writeNotNull('bodyValues', bodyValues?.map((key, value) => EmailBodyValueConverter().toJson(key, value))); + writeNotNull(IndividualHeaderIdentifier.headerUserAgent.value, IndividualHeaderIdentifierNullableConverter().toJson(headerUserAgent, IndividualHeaderIdentifier.headerUserAgent)); return val; } diff --git a/lib/jmap/mail/email/individual_header_identifier.dart b/lib/jmap/mail/email/individual_header_identifier.dart new file mode 100644 index 0000000..059f129 --- /dev/null +++ b/lib/jmap/mail/email/individual_header_identifier.dart @@ -0,0 +1,12 @@ +import 'package:equatable/equatable.dart'; + +class IndividualHeaderIdentifier with EquatableMixin { + static final headerUserAgent = IndividualHeaderIdentifier('header:User-Agent:asText'); + + final String value; + + IndividualHeaderIdentifier(this.value); + + @override + List get props => [value]; +} \ No newline at end of file diff --git a/test/jmap/email/set/set_email_method_test.dart b/test/jmap/email/set/set_email_method_test.dart index 0f0a148..c5fa529 100644 --- a/test/jmap/email/set/set_email_method_test.dart +++ b/test/jmap/email/set/set_email_method_test.dart @@ -11,6 +11,7 @@ import 'package:jmap_dart_client/jmap/mail/email/email.dart'; import 'package:jmap_dart_client/jmap/mail/email/email_address.dart'; import 'package:jmap_dart_client/jmap/mail/email/email_body_part.dart'; import 'package:jmap_dart_client/jmap/mail/email/email_body_value.dart'; +import 'package:jmap_dart_client/jmap/mail/email/individual_header_identifier.dart'; import 'package:jmap_dart_client/jmap/mail/email/keyword_identifier.dart'; import 'package:jmap_dart_client/jmap/mail/email/set/set_email_method.dart'; import 'package:jmap_dart_client/jmap/mail/email/set/set_email_response.dart'; @@ -141,5 +142,124 @@ void main() { expect(setEmailResponse!.created![Id('aa1234')], equals(expectedCreated)); }); + + test('set email method and response parsing with header User-Agent', () async { + final baseOption = BaseOptions(method: 'POST'); + final dio = Dio(baseOption) + ..options.baseUrl = 'http://domain.com'; + final dioAdapter = DioAdapter(dio: dio); + dioAdapter.onPost( + '/jmap', + (server) => server.reply(200, { + "sessionState": "2c9f1b12-b35a-43e6-9af2-0106fb53a943", + "methodResponses": [[ + "Email/set", + { + "accountId":"3ce33c876a726662c627746eb9537a1d13c2338193ef27bd051a3ce5c0fe5b12", + "oldState":"234c9ee0-0596-11ec-b153-2fef1ee78d9e", + "newState":"234c9ee0-0596-11ec-b153-2fef1ee78d9e", + "created": { + "aa1234": { + "id":"29a7f870-0596-11ec-b153-2fef1ee78d9e", + "blobId":"29a7f870-0596-11ec-b153-2fef1ee78d9e", + "threadId":"29a7f870-0596-11ec-b153-2fef1ee78d9e", + "size": 657 + } + } + }, + "c0" + ]] + }), + data: { + 'using': [ + 'urn:ietf:params:jmap:mail', + 'urn:ietf:params:jmap:core' + ], + 'methodCalls': [[ + 'Email/set', + { + 'accountId': '3ce33c876a726662c627746eb9537a1d13c2338193ef27bd051a3ce5c0fe5b12', + 'create': { + 'aa1234': { + 'id': 'ea12345', + 'mailboxIds': { + 'fe00a5c0-0584-11ec-b153-2fef1ee78d9e': true + }, + 'keywords': { + '\$seen': true + }, + 'subject': 'set email 3', + 'sender': [{ + 'name: bob, email: bob@email' + }], + 'from' : [{ + 'name': 'alice', 'email': 'alice@email' + }], + 'to': [{ + 'name': 'dcu', 'email': 'dcu@email' + }], + 'replyTo': [{ + 'name': 'bob', 'email': 'bob@email' + }], + 'htmlBody': [{ + 'partId': 'a49d', 'type': 'text/html' + }], + 'bodyValues': { + 'a49d': { + 'value': 'test html html', + 'isEncodingProblem': false, + 'isTruncated': false + } + }, + 'header:User-Agent:asText': 'Android/1.0.0 TeamMail/1.0' + } + } + }, + 'c0' + ] + ] + }, + headers: { + "accept": "application/json;jmapVersion=rfc-8621", + "content-type": "application/json; charset=utf-8" + } + ); + + final setEmailMethod = SetEmailMethod(AccountId(Id('3ce33c876a726662c627746eb9537a1d13c2338193ef27bd051a3ce5c0fe5b12'))) + ..addCreate(Id('aa1234'), + Email( + EmailId(Id('ea12345')), + mailboxIds: { + MailboxId(Id('fe00a5c0-0584-11ec-b153-2fef1ee78d9e')): true + }, + keywords: { + KeyWordIdentifier.emailSeen: true + }, + replyTo: {EmailAddress('bob', 'bob@email')}, + from: {EmailAddress('alice', 'alice@email')}, + sender: {EmailAddress('bob', 'bob@email')}, + to: {EmailAddress('dcu', 'dcu@email')}, + subject: 'set email 3', + htmlBody: {EmailBodyPart(partId: PartId('a49d'), type: MediaType.parse('text/html'))}, + bodyValues: { + PartId('a49d'): EmailBodyValue('test html html', false, false) + }, + headerUserAgent: {IndividualHeaderIdentifier.headerUserAgent : 'Android/1.0.0 TeamMail/1.0'} + ) + ); + + final httpClient = HttpClient(dio); + final requestBuilder = JmapRequestBuilder(httpClient, ProcessingInvocation()); + final setEmailInvocation = requestBuilder.invocation(setEmailMethod); + final response = await (requestBuilder..usings(setEmailMethod.requiredCapabilities)) + .build() + .execute(); + + final setEmailResponse = response.parse( + setEmailInvocation.methodCallId, + SetEmailResponse.deserialize); + + expect(setEmailResponse!.created![Id('aa1234')], equals(expectedCreated)); + }); }); } \ No newline at end of file diff --git a/test/jmap/email/submission/set_email_submission_method_test.dart b/test/jmap/email/submission/set_email_submission_method_test.dart index 8b21385..2b763b5 100644 --- a/test/jmap/email/submission/set_email_submission_method_test.dart +++ b/test/jmap/email/submission/set_email_submission_method_test.dart @@ -15,6 +15,7 @@ import 'package:jmap_dart_client/jmap/mail/email/email.dart'; import 'package:jmap_dart_client/jmap/mail/email/email_address.dart'; import 'package:jmap_dart_client/jmap/mail/email/email_body_part.dart'; import 'package:jmap_dart_client/jmap/mail/email/email_body_value.dart'; +import 'package:jmap_dart_client/jmap/mail/email/individual_header_identifier.dart'; import 'package:jmap_dart_client/jmap/mail/email/set/set_email_method.dart'; import 'package:jmap_dart_client/jmap/mail/email/set/set_email_response.dart'; import 'package:jmap_dart_client/jmap/mail/email/submission/address.dart'; @@ -27,10 +28,10 @@ import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart'; void main() { group('test to json set email submission method', () { final expectedCreated = Email( - EmailId(Id('dada4400-0c7f-11ec-b57c-2fef1ee78d9e')), - blobId: Id('dada4400-0c7f-11ec-b57c-2fef1ee78d9e'), - threadId: ThreadId(Id('dada4400-0c7f-11ec-b57c-2fef1ee78d9e')), - size: UnsignedInt(662) + EmailId(Id('64469f10-8e15-11ec-984e-e3f8b83572b4')), + blobId: Id('64469f10-8e15-11ec-984e-e3f8b83572b4'), + threadId: ThreadId(Id('64469f10-8e15-11ec-984e-e3f8b83572b4')), + size: UnsignedInt(742) ); test('set email submission method and response parsing', () async { @@ -40,21 +41,209 @@ void main() { dioAdapter.onPost( '/jmap', (server) => server.reply(200, { + "sessionState": "2c9f1b12-b35a-43e6-9af2-0106fb53a943", + "methodResponses": [ + [ + "Email/set", + { + "accountId": "3ce33c876a726662c627746eb9537a1d13c2338193ef27bd051a3ce5c0fe5b12", + "oldState": "3534e880-8e15-11ec-984e-e3f8b83572b4", + "newState": "64b98520-8e15-11ec-984e-e3f8b83572b4", + "created": { + "dab1234": { + "id": "64469f10-8e15-11ec-984e-e3f8b83572b4", + "blobId": "64469f10-8e15-11ec-984e-e3f8b83572b4", + "threadId": "64469f10-8e15-11ec-984e-e3f8b83572b4", + "size": 742 + } + } + }, + "c0" + ], + [ + "EmailSubmission/set", + { + "accountId": "3ce33c876a726662c627746eb9537a1d13c2338193ef27bd051a3ce5c0fe5b12", + "newState": "2c9f1b12-b35a-43e6-9af2-0106fb53a943", + "created": { + "a1234": "6a4cf0b9-956e-41d5-9122-4824e3ea9baf" + } + }, + "c1" + ], + [ + "Email/set", + { + "accountId": "3ce33c876a726662c627746eb9537a1d13c2338193ef27bd051a3ce5c0fe5b12", + "oldState": "64b98520-8e15-11ec-984e-e3f8b83572b4", + "newState": "64b98520-8e15-11ec-984e-e3f8b83572b4", + "updated": { + "64469f10-8e15-11ec-984e-e3f8b83572b4": null + } + }, + "c1" + ] + ] + }), + data: { + "using": [ + "urn:ietf:params:jmap:submission", + "urn:ietf:params:jmap:mail", + "urn:ietf:params:jmap:core" + ], + "methodCalls": [ + [ + "Email/set", + { + "accountId": "3ce33c876a726662c627746eb9537a1d13c2338193ef27bd051a3ce5c0fe5b12", + "create": { + "dab1234": { + "id": "dab1234", + "mailboxIds": { + "5dfb3290-0a14-11ec-b57c-2fef1ee78d9e": true + }, + "subject": "test send email", + "from": [ + { + "name": "userB", + "email": "userb@qa.open-paas.org" + } + ], + "to": [ + { + "name": "userD", + "email": "userd@qa.open-paas.org" + } + ], + "htmlBody": [ + {"partId": "mmm", "blobId": "aaaa", "type": "text/html"} + ], + "bodyValues": { + "mmm": { + "value": "

Hello test send 2



", + "isEncodingProblem": false, + "isTruncated": false + } + } + } + } + }, + "c0" + ], + [ + "EmailSubmission/set", + { + "accountId": "3ce33c876a726662c627746eb9537a1d13c2338193ef27bd051a3ce5c0fe5b12", + "create": { + "a1234": { + "emailId": "#dab1234", + "envelope": { + "mailFrom": {"email": "userb@qa.open-paas.org"}, + "rcptTo": [ + {"email": "userd@qa.open-paas.org"} + ] + } + } + }, + "onSuccessUpdateEmail": { + "#a1234": { + "mailboxIds": { + "5dfb3290-0a14-11ec-b57c-2fef1ee78d9e": true + } + } + } + }, + "c1" + ] + ] + }, + headers: { + "accept": "application/json;jmapVersion=rfc-8621", + "content-type": "application/json; charset=utf-8", + "content-length": 1039 + }); + + final setEmailMethod = SetEmailMethod(AccountId(Id('3ce33c876a726662c627746eb9537a1d13c2338193ef27bd051a3ce5c0fe5b12'))) + ..addCreate(Id('dab1234'), + Email( + EmailId(Id('dab1234')), + mailboxIds: {MailboxId(Id('5dfb3290-0a14-11ec-b57c-2fef1ee78d9e')): true}, + subject: 'test send email', + from: {EmailAddress("userB", 'userb@qa.open-paas.org')}, + to: {EmailAddress("userD", 'userd@qa.open-paas.org')}, + htmlBody: {EmailBodyPart(partId: PartId('mmm'), blobId: Id('aaaa'), type: MediaType.parse('text/html'))}, + bodyValues: { + PartId('mmm'): EmailBodyValue('

Hello test send 2



', false, false) + } + ) + ); + + final setEmailSubmissionMethod = SetEmailSubmissionMethod(AccountId(Id('3ce33c876a726662c627746eb9537a1d13c2338193ef27bd051a3ce5c0fe5b12'))) + ..addCreate( + Id('a1234'), + EmailSubmission( + emailId: EmailId(ReferenceId(ReferencePrefix.defaultPrefix, Id('dab1234'))), + envelope: Envelope( + Address('userb@qa.open-paas.org'), + {Address('userd@qa.open-paas.org')}))) + ..addOnSuccessUpdateEmail({ + EmailSubmissionId(ReferenceId(ReferencePrefix.defaultPrefix, Id('a1234'))): PatchObject({ + PatchObject.mailboxIdsProperty: { + MailboxIdConverter().toJson(MailboxId(Id('5dfb3290-0a14-11ec-b57c-2fef1ee78d9e'))): true + } + }) + }); + + final httpClient = HttpClient(dio); + final requestBuilder = + JmapRequestBuilder(httpClient, ProcessingInvocation()); + + final setEmailInvocation = requestBuilder.invocation(setEmailMethod); + + final setEmailSubmissionInvocation = requestBuilder.invocation(setEmailSubmissionMethod); + + final response = await (requestBuilder + ..usings(setEmailSubmissionMethod.requiredCapabilities)) + .build() + .execute(); + + final setEmailResponse = response.parse( + setEmailInvocation.methodCallId, + SetEmailResponse.deserialize); + + final setEmailUpdateResponse = response.parse( + setEmailSubmissionInvocation.methodCallId, + SetEmailResponse.deserialize, + methodName: setEmailInvocation.methodName); + + expect(setEmailResponse?.created?[Id('dab1234')], + equals(expectedCreated)); + + expect(setEmailUpdateResponse?.updated?[Id('64469f10-8e15-11ec-984e-e3f8b83572b4')], + equals(null)); + }); + + test('set email submission method and response parsing with header User-Agent', () async { + final baseOption = BaseOptions(method: 'POST'); + final dio = Dio(baseOption)..options.baseUrl = 'http://domain.com'; + final dioAdapter = DioAdapter(dio: dio); + dioAdapter.onPost( + '/jmap', + (server) => server.reply(200, { "sessionState": "2c9f1b12-b35a-43e6-9af2-0106fb53a943", "methodResponses": [ [ "Email/set", { - "accountId": - "3ce33c876a726662c627746eb9537a1d13c2338193ef27bd051a3ce5c0fe5b12", - "oldState": "b5e22550-0c70-11ec-b57c-2fef1ee78d9e", - "newState": "b5e22550-0c70-11ec-b57c-2fef1ee78d9e", + "accountId": "3ce33c876a726662c627746eb9537a1d13c2338193ef27bd051a3ce5c0fe5b12", + "oldState": "3534e880-8e15-11ec-984e-e3f8b83572b4", + "newState": "64b98520-8e15-11ec-984e-e3f8b83572b4", "created": { "dab1234": { - "id": "dada4400-0c7f-11ec-b57c-2fef1ee78d9e", - "blobId": "dada4400-0c7f-11ec-b57c-2fef1ee78d9e", - "threadId": "dada4400-0c7f-11ec-b57c-2fef1ee78d9e", - "size": 662 + "id": "64469f10-8e15-11ec-984e-e3f8b83572b4", + "blobId": "64469f10-8e15-11ec-984e-e3f8b83572b4", + "threadId": "64469f10-8e15-11ec-984e-e3f8b83572b4", + "size": 742 } } }, @@ -63,11 +252,10 @@ void main() { [ "EmailSubmission/set", { - "accountId": - "3ce33c876a726662c627746eb9537a1d13c2338193ef27bd051a3ce5c0fe5b12", + "accountId": "3ce33c876a726662c627746eb9537a1d13c2338193ef27bd051a3ce5c0fe5b12", "newState": "2c9f1b12-b35a-43e6-9af2-0106fb53a943", "created": { - "a1234": "3126bf86-1ca0-4307-a789-3c7bf6575e82" + "a1234": "6a4cf0b9-956e-41d5-9122-4824e3ea9baf" } }, "c1" @@ -75,11 +263,12 @@ void main() { [ "Email/set", { - "accountId": - "3ce33c876a726662c627746eb9537a1d13c2338193ef27bd051a3ce5c0fe5b12", - "oldState": "db19be00-0c7f-11ec-b57c-2fef1ee78d9e", - "newState": "db19be00-0c7f-11ec-b57c-2fef1ee78d9e", - "updated": {"dada4400-0c7f-11ec-b57c-2fef1ee78d9e": null} + "accountId": "3ce33c876a726662c627746eb9537a1d13c2338193ef27bd051a3ce5c0fe5b12", + "oldState": "64b98520-8e15-11ec-984e-e3f8b83572b4", + "newState": "64b98520-8e15-11ec-984e-e3f8b83572b4", + "updated": { + "64469f10-8e15-11ec-984e-e3f8b83572b4": null + } }, "c1" ] @@ -124,7 +313,8 @@ void main() { "isEncodingProblem": false, "isTruncated": false } - } + }, + "header:User-Agent:asText": "Android/1.0.0 TeamMail/1.0" } } }, @@ -160,21 +350,22 @@ void main() { headers: { "accept": "application/json;jmapVersion=rfc-8621", "content-type": "application/json; charset=utf-8", - "content-length": 1039 + "content-length": 1095 }); final setEmailMethod = SetEmailMethod(AccountId(Id('3ce33c876a726662c627746eb9537a1d13c2338193ef27bd051a3ce5c0fe5b12'))) ..addCreate(Id('dab1234'), Email( - EmailId(Id('dab1234')), - mailboxIds: {MailboxId(Id('5dfb3290-0a14-11ec-b57c-2fef1ee78d9e')): true}, - subject: 'test send email', - from: {EmailAddress("userB", 'userb@qa.open-paas.org')}, - to: {EmailAddress("userD", 'userd@qa.open-paas.org')}, - htmlBody: {EmailBodyPart(partId: PartId('mmm'), blobId: Id('aaaa'), type: MediaType.parse('text/html'))}, - bodyValues: { - PartId('mmm'): EmailBodyValue('

Hello test send 2



', false, false) - } + EmailId(Id('dab1234')), + mailboxIds: {MailboxId(Id('5dfb3290-0a14-11ec-b57c-2fef1ee78d9e')): true}, + subject: 'test send email', + from: {EmailAddress("userB", 'userb@qa.open-paas.org')}, + to: {EmailAddress("userD", 'userd@qa.open-paas.org')}, + htmlBody: {EmailBodyPart(partId: PartId('mmm'), blobId: Id('aaaa'), type: MediaType.parse('text/html'))}, + bodyValues: { + PartId('mmm'): EmailBodyValue('

Hello test send 2



', false, false) + }, + headerUserAgent: {IndividualHeaderIdentifier.headerUserAgent : 'Android/1.0.0 TeamMail/1.0'} ) ); @@ -196,14 +387,14 @@ void main() { final httpClient = HttpClient(dio); final requestBuilder = - JmapRequestBuilder(httpClient, ProcessingInvocation()); + JmapRequestBuilder(httpClient, ProcessingInvocation()); final setEmailInvocation = requestBuilder.invocation(setEmailMethod); final setEmailSubmissionInvocation = requestBuilder.invocation(setEmailSubmissionMethod); final response = await (requestBuilder - ..usings(setEmailSubmissionMethod.requiredCapabilities)) + ..usings(setEmailSubmissionMethod.requiredCapabilities)) .build() .execute(); @@ -219,7 +410,7 @@ void main() { expect(setEmailResponse?.created?[Id('dab1234')], equals(expectedCreated)); - expect(setEmailUpdateResponse?.updated?[Id('dada4400-0c7f-11ec-b57c-2fef1ee78d9e')], + expect(setEmailUpdateResponse?.updated?[Id('64469f10-8e15-11ec-984e-e3f8b83572b4')], equals(null)); }); });