TF-2298 Update expires time when old token has expired

Signed-off-by: dab246 <tdvu@linagora.com>
(cherry picked from commit fb26afe8f52df6e16476aea8a68f9f92c5c4b001)
This commit is contained in:
dab246
2023-12-04 10:53:26 +07:00
committed by Dat H. Pham
parent e3dea129b6
commit f5d878012d
72 changed files with 964 additions and 736 deletions
@@ -0,0 +1,12 @@
import 'package:fcm/model/fcm_token.dart';
import 'package:json_annotation/json_annotation.dart';
class FcmTokenNullableConverter implements JsonConverter<FcmToken?, String?> {
const FcmTokenNullableConverter();
@override
FcmToken? fromJson(String? json) => json != null ? FcmToken(json) : null;
@override
String? toJson(FcmToken? object) => object?.value;
}
@@ -1,20 +0,0 @@
import 'package:fcm/model/firebase_expired_time.dart';
import 'package:jmap_dart_client/http/converter/utc_date_converter.dart';
import 'package:jmap_dart_client/http/converter/utc_date_nullable_converter.dart';
import 'package:json_annotation/json_annotation.dart';
class FirebaseExpiredTimeNullableConverter implements JsonConverter<FirebaseExpiredTime?, String?> {
const FirebaseExpiredTimeNullableConverter();
@override
FirebaseExpiredTime? fromJson(String? json) {
if (json != null) {
return FirebaseExpiredTime(const UTCDateConverter().fromJson(json));
} else {
return null;
}
}
@override
String? toJson(FirebaseExpiredTime? object) => const UTCDateNullableConverter().toJson(object?.value);
}
@@ -0,0 +1,20 @@
import 'package:fcm/model/firebase_registration_expired_time.dart';
import 'package:jmap_dart_client/http/converter/utc_date_converter.dart';
import 'package:jmap_dart_client/http/converter/utc_date_nullable_converter.dart';
import 'package:json_annotation/json_annotation.dart';
class FirebaseRegistrationExpiredTimeNullableConverter implements JsonConverter<FirebaseRegistrationExpiredTime?, String?> {
const FirebaseRegistrationExpiredTimeNullableConverter();
@override
FirebaseRegistrationExpiredTime? fromJson(String? json) {
if (json != null) {
return FirebaseRegistrationExpiredTime(const UTCDateConverter().fromJson(json));
} else {
return null;
}
}
@override
String? toJson(FirebaseRegistrationExpiredTime? object) => const UTCDateNullableConverter().toJson(object?.value);
}
@@ -0,0 +1,13 @@
import 'package:fcm/model/firebase_registration_id.dart';
import 'package:jmap_dart_client/jmap/core/id.dart';
import 'package:json_annotation/json_annotation.dart';
class FirebaseRegistrationIdNullableConverter implements JsonConverter<FirebaseRegistrationId?, String?> {
const FirebaseRegistrationIdNullableConverter();
@override
FirebaseRegistrationId? fromJson(String? json) => json != null ? FirebaseRegistrationId(Id(json)) : null;
@override
String? toJson(FirebaseRegistrationId? object) => object?.id.value;
}
@@ -1,13 +0,0 @@
import 'package:fcm/model/firebase_subscription_id.dart';
import 'package:jmap_dart_client/jmap/core/id.dart';
import 'package:json_annotation/json_annotation.dart';
class FirebaseSubscriptionIdNullableConverter implements JsonConverter<FirebaseSubscriptionId?, String?> {
const FirebaseSubscriptionIdNullableConverter();
@override
FirebaseSubscriptionId? fromJson(String? json) => json != null ? FirebaseSubscriptionId(Id(json)) : null;
@override
String? toJson(FirebaseSubscriptionId? object) => object?.id.value;
}
@@ -1,12 +0,0 @@
import 'package:fcm/model/firebase_token.dart';
import 'package:json_annotation/json_annotation.dart';
class FirebaseTokenNullableConverter implements JsonConverter<FirebaseToken?, String?> {
const FirebaseTokenNullableConverter();
@override
FirebaseToken? fromJson(String? json) => json != null ? FirebaseToken(json) : null;
@override
String? toJson(FirebaseToken? object) => object?.value;
}
@@ -7,14 +7,14 @@ import 'package:jmap_dart_client/jmap/core/request/request_invocation.dart';
import 'package:jmap_dart_client/jmap/core/request/result_reference.dart'; import 'package:jmap_dart_client/jmap/core/request/result_reference.dart';
import 'package:json_annotation/json_annotation.dart'; import 'package:json_annotation/json_annotation.dart';
part 'firebase_subscription_get_method.g.dart'; part 'firebase_registration_get_method.g.dart';
@IdConverter() @IdConverter()
@PropertiesConverter() @PropertiesConverter()
@JsonSerializable(explicitToJson: true) @JsonSerializable(explicitToJson: true)
class FirebaseSubscriptionGetMethod extends GetMethodNoNeedAccountId { class FirebaseRegistrationGetMethod extends GetMethodNoNeedAccountId {
FirebaseSubscriptionGetMethod() : super(); FirebaseRegistrationGetMethod() : super();
@override @override
MethodName get methodName => MethodName('FirebaseRegistration/get'); MethodName get methodName => MethodName('FirebaseRegistration/get');
@@ -28,8 +28,8 @@ class FirebaseSubscriptionGetMethod extends GetMethodNoNeedAccountId {
@override @override
List<Object?> get props => [methodName, ids, requiredCapabilities]; List<Object?> get props => [methodName, ids, requiredCapabilities];
factory FirebaseSubscriptionGetMethod.fromJson(Map<String, dynamic> json) => _$FirebaseSubscriptionGetMethodFromJson(json); factory FirebaseRegistrationGetMethod.fromJson(Map<String, dynamic> json) => _$FirebaseRegistrationGetMethodFromJson(json);
@override @override
Map<String, dynamic> toJson() => _$FirebaseSubscriptionGetMethodToJson(this); Map<String, dynamic> toJson() => _$FirebaseRegistrationGetMethodToJson(this);
} }
@@ -0,0 +1,29 @@
import 'package:fcm/model/firebase_registration.dart';
import 'package:jmap_dart_client/http/converter/id_converter.dart';
import 'package:jmap_dart_client/jmap/core/id.dart';
import 'package:jmap_dart_client/jmap/core/method/response/get_response.dart';
import 'package:json_annotation/json_annotation.dart';
part 'firebase_registration_get_response.g.dart';
@IdConverter()
@JsonSerializable(explicitToJson: true)
class FirebaseRegistrationGetResponse extends GetResponseNoAccountId<FirebaseRegistration> {
FirebaseRegistrationGetResponse(
List<FirebaseRegistration> list,
List<Id>? notFound
) : super(list, notFound);
factory FirebaseRegistrationGetResponse.fromJson(Map<String, dynamic> json) =>
_$FirebaseRegistrationGetResponseFromJson(json);
static FirebaseRegistrationGetResponse deserialize(Map<String, dynamic> json) {
return FirebaseRegistrationGetResponse.fromJson(json);
}
Map<String, dynamic> toJson() => _$FirebaseRegistrationGetResponseToJson(this);
@override
List<Object?> get props => [list, notFound];
}
@@ -1,29 +0,0 @@
import 'package:fcm/model/firebase_subscription.dart';
import 'package:jmap_dart_client/http/converter/id_converter.dart';
import 'package:jmap_dart_client/jmap/core/id.dart';
import 'package:jmap_dart_client/jmap/core/method/response/get_response.dart';
import 'package:json_annotation/json_annotation.dart';
part 'firebase_subscription_get_response.g.dart';
@IdConverter()
@JsonSerializable(explicitToJson: true)
class FirebaseSubscriptionGetResponse extends GetResponseNoAccountId<FirebaseSubscription> {
FirebaseSubscriptionGetResponse(
List<FirebaseSubscription> list,
List<Id>? notFound
) : super(list, notFound);
factory FirebaseSubscriptionGetResponse.fromJson(Map<String, dynamic> json) =>
_$FirebaseSubscriptionGetResponseFromJson(json);
static FirebaseSubscriptionGetResponse deserialize(Map<String, dynamic> json) {
return FirebaseSubscriptionGetResponse.fromJson(json);
}
Map<String, dynamic> toJson() => _$FirebaseSubscriptionGetResponseToJson(this);
@override
List<Object?> get props => [list, notFound];
}
@@ -1,4 +1,4 @@
import 'package:fcm/model/firebase_subscription.dart'; import 'package:fcm/model/firebase_registration.dart';
import 'package:fcm/model/firebase_capability.dart'; import 'package:fcm/model/firebase_capability.dart';
import 'package:jmap_dart_client/http/converter/id_converter.dart'; import 'package:jmap_dart_client/http/converter/id_converter.dart';
import 'package:jmap_dart_client/http/converter/set/set_method_properties_converter.dart'; import 'package:jmap_dart_client/http/converter/set/set_method_properties_converter.dart';
@@ -6,9 +6,9 @@ import 'package:jmap_dart_client/jmap/core/capability/capability_identifier.dart
import 'package:jmap_dart_client/jmap/core/method/request/set_method.dart'; import 'package:jmap_dart_client/jmap/core/method/request/set_method.dart';
import 'package:jmap_dart_client/jmap/core/request/request_invocation.dart'; import 'package:jmap_dart_client/jmap/core/request/request_invocation.dart';
class FirebaseSubscriptionSetMethod extends SetMethodNoNeedAccountId<FirebaseSubscription> { class FirebaseRegistrationSetMethod extends SetMethodNoNeedAccountId<FirebaseRegistration> {
FirebaseSubscriptionSetMethod() : super(); FirebaseRegistrationSetMethod() : super();
@override @override
MethodName get methodName => MethodName('FirebaseRegistration/set'); MethodName get methodName => MethodName('FirebaseRegistration/set');
@@ -1,13 +1,13 @@
import 'package:fcm/model/firebase_subscription.dart'; import 'package:fcm/model/firebase_registration.dart';
import 'package:jmap_dart_client/http/converter/id_converter.dart'; import 'package:jmap_dart_client/http/converter/id_converter.dart';
import 'package:jmap_dart_client/jmap/core/error/set_error.dart'; import 'package:jmap_dart_client/jmap/core/error/set_error.dart';
import 'package:jmap_dart_client/jmap/core/id.dart'; import 'package:jmap_dart_client/jmap/core/id.dart';
import 'package:jmap_dart_client/jmap/core/method/response/set_response.dart'; import 'package:jmap_dart_client/jmap/core/method/response/set_response.dart';
class FirebaseSubscriptionSetResponse extends SetResponseNoAccount<FirebaseSubscription> { class FirebaseRegistrationSetResponse extends SetResponseNoAccount<FirebaseRegistration> {
FirebaseSubscriptionSetResponse({ FirebaseRegistrationSetResponse({
Map<Id, FirebaseSubscription>? created, Map<Id, FirebaseRegistration>? created,
Map<Id, FirebaseSubscription?>? updated, Map<Id, FirebaseRegistration?>? updated,
Set<Id>? destroyed, Set<Id>? destroyed,
Map<Id, SetError>? notCreated, Map<Id, SetError>? notCreated,
Map<Id, SetError>? notUpdated, Map<Id, SetError>? notUpdated,
@@ -21,15 +21,15 @@ class FirebaseSubscriptionSetResponse extends SetResponseNoAccount<FirebaseSubsc
notDestroyed: notDestroyed notDestroyed: notDestroyed
); );
static FirebaseSubscriptionSetResponse deserialize(Map<String, dynamic> json) { static FirebaseRegistrationSetResponse deserialize(Map<String, dynamic> json) {
return FirebaseSubscriptionSetResponse( return FirebaseRegistrationSetResponse(
created: (json['created'] as Map<String, dynamic>?)?.map((key, value) => MapEntry( created: (json['created'] as Map<String, dynamic>?)?.map((key, value) => MapEntry(
const IdConverter().fromJson(key), const IdConverter().fromJson(key),
FirebaseSubscription.fromJson(value as Map<String, dynamic>) FirebaseRegistration.fromJson(value as Map<String, dynamic>)
)), )),
updated: (json['updated'] as Map<String, dynamic>?)?.map((key, value) => MapEntry( updated: (json['updated'] as Map<String, dynamic>?)?.map((key, value) => MapEntry(
const IdConverter().fromJson(key), const IdConverter().fromJson(key),
value != null ? FirebaseSubscription.fromJson(value as Map<String, dynamic>) : null value != null ? FirebaseRegistration.fromJson(value as Map<String, dynamic>) : null
)), )),
destroyed: (json['destroyed'] as List<dynamic>?)?.map((id) => const IdConverter().fromJson(id)).toSet(), destroyed: (json['destroyed'] as List<dynamic>?)?.map((id) => const IdConverter().fromJson(id)).toSet(),
notCreated: (json['notCreated'] as Map<String, dynamic>?)?.map((key, value) => MapEntry( notCreated: (json['notCreated'] as Map<String, dynamic>?)?.map((key, value) => MapEntry(
@@ -1,11 +1,11 @@
import 'package:equatable/equatable.dart'; import 'package:equatable/equatable.dart';
class FirebaseToken with EquatableMixin { class FcmToken with EquatableMixin {
final String value; final String value;
FirebaseToken(this.value); FcmToken(this.value);
@override @override
List<Object?> get props => [value]; List<Object?> get props => [value];
+45
View File
@@ -0,0 +1,45 @@
import 'package:equatable/equatable.dart';
import 'package:fcm/converter/device_client_id_nullable_converter.dart';
import 'package:fcm/converter/firebase_registration_expired_time_nullable_converter.dart';
import 'package:fcm/converter/firebase_registration_id_nullable_converter.dart';
import 'package:fcm/converter/fcm_token_nullable_converter.dart';
import 'package:fcm/converter/type_name_converter.dart';
import 'package:fcm/model/device_client_id.dart';
import 'package:fcm/model/firebase_registration_expired_time.dart';
import 'package:fcm/model/firebase_registration_id.dart';
import 'package:fcm/model/fcm_token.dart';
import 'package:fcm/model/type_name.dart';
import 'package:json_annotation/json_annotation.dart';
part 'firebase_registration.g.dart';
@DeviceClientIdNullableConverter()
@FirebaseRegistrationIdNullableConverter()
@FcmTokenNullableConverter()
@FirebaseRegistrationExpiredTimeNullableConverter()
@TypeNameConverter()
@JsonSerializable(explicitToJson: true, includeIfNull: false)
class FirebaseRegistration with EquatableMixin {
final FirebaseRegistrationId? id;
final FcmToken? token;
final DeviceClientId? deviceClientId;
final FirebaseRegistrationExpiredTime? expires;
final List<TypeName>? types;
FirebaseRegistration({
this.id,
this.token,
this.deviceClientId,
this.expires,
this.types
});
factory FirebaseRegistration.fromJson(Map<String, dynamic> json) => _$FirebaseRegistrationFromJson(json);
Map<String, dynamic> toJson() => _$FirebaseRegistrationToJson(this);
@override
List<Object?> get props => [id, token, deviceClientId, expires, types];
}
@@ -2,11 +2,11 @@
import 'package:equatable/equatable.dart'; import 'package:equatable/equatable.dart';
import 'package:jmap_dart_client/jmap/core/utc_date.dart'; import 'package:jmap_dart_client/jmap/core/utc_date.dart';
class FirebaseExpiredTime with EquatableMixin { class FirebaseRegistrationExpiredTime with EquatableMixin {
final UTCDate value; final UTCDate value;
FirebaseExpiredTime(this.value); FirebaseRegistrationExpiredTime(this.value);
@override @override
List<Object?> get props => [value]; List<Object?> get props => [value];
@@ -2,11 +2,11 @@
import 'package:equatable/equatable.dart'; import 'package:equatable/equatable.dart';
import 'package:jmap_dart_client/jmap/core/id.dart'; import 'package:jmap_dart_client/jmap/core/id.dart';
class FirebaseSubscriptionId with EquatableMixin { class FirebaseRegistrationId with EquatableMixin {
final Id id; final Id id;
FirebaseSubscriptionId(this.id); FirebaseRegistrationId(this.id);
@override @override
List<Object?> get props => [id]; List<Object?> get props => [id];
-45
View File
@@ -1,45 +0,0 @@
import 'package:equatable/equatable.dart';
import 'package:fcm/converter/device_client_id_nullable_converter.dart';
import 'package:fcm/converter/firebase_expired_time_nullable_converter.dart';
import 'package:fcm/converter/firebase_subscription_id_nullable_converter.dart';
import 'package:fcm/converter/firebase_token_nullable_converter.dart';
import 'package:fcm/converter/type_name_converter.dart';
import 'package:fcm/model/device_client_id.dart';
import 'package:fcm/model/firebase_expired_time.dart';
import 'package:fcm/model/firebase_subscription_id.dart';
import 'package:fcm/model/firebase_token.dart';
import 'package:fcm/model/type_name.dart';
import 'package:json_annotation/json_annotation.dart';
part 'firebase_subscription.g.dart';
@DeviceClientIdNullableConverter()
@FirebaseSubscriptionIdNullableConverter()
@FirebaseTokenNullableConverter()
@FirebaseExpiredTimeNullableConverter()
@TypeNameConverter()
@JsonSerializable(explicitToJson: true, includeIfNull: false)
class FirebaseSubscription with EquatableMixin {
final FirebaseSubscriptionId? id;
final FirebaseToken? token;
final DeviceClientId? deviceClientId;
final FirebaseExpiredTime? expires;
final List<TypeName>? types;
FirebaseSubscription({
this.id,
this.token,
this.deviceClientId,
this.expires,
this.types
});
factory FirebaseSubscription.fromJson(Map<String, dynamic> json) => _$FirebaseSubscriptionFromJson(json);
Map<String, dynamic> toJson() => _$FirebaseSubscriptionToJson(this);
@override
List<Object?> get props => [id, token, deviceClientId, expires, types];
}
@@ -1,10 +1,10 @@
import 'package:dio/dio.dart'; import 'package:dio/dio.dart';
import 'package:fcm/method/get/firebase_subscription_get_method.dart'; import 'package:fcm/method/get/firebase_registration_get_method.dart';
import 'package:fcm/method/get/firebase_subscription_get_response.dart'; import 'package:fcm/method/get/firebase_registration_get_response.dart';
import 'package:fcm/model/device_client_id.dart'; import 'package:fcm/model/device_client_id.dart';
import 'package:fcm/model/firebase_expired_time.dart'; import 'package:fcm/model/firebase_registration_expired_time.dart';
import 'package:fcm/model/firebase_subscription.dart'; import 'package:fcm/model/firebase_registration.dart';
import 'package:fcm/model/firebase_subscription_id.dart'; import 'package:fcm/model/firebase_registration_id.dart';
import 'package:fcm/model/type_name.dart'; import 'package:fcm/model/type_name.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:http_mock_adapter/http_mock_adapter.dart'; import 'package:http_mock_adapter/http_mock_adapter.dart';
@@ -14,22 +14,22 @@ import 'package:jmap_dart_client/jmap/core/utc_date.dart';
import 'package:jmap_dart_client/jmap/jmap_request.dart'; import 'package:jmap_dart_client/jmap/jmap_request.dart';
void main() { void main() {
group('test to json firebase subscription get method', () { group('test to json firebase registration get method', () {
final expectFirebaseSubscription1 = FirebaseSubscription( final expectFirebaseRegistration1 = FirebaseRegistration(
id: FirebaseSubscriptionId(Id('e50b2c1d-9553-41a3-b0a7-a7d26b599ee1')), id: FirebaseRegistrationId(Id('e50b2c1d-9553-41a3-b0a7-a7d26b599ee1')),
deviceClientId: DeviceClientId('b37ff8001ca0'), deviceClientId: DeviceClientId('b37ff8001ca0'),
expires: FirebaseExpiredTime(UTCDate(DateTime.parse('2018-07-31T00:13:21Z'))), expires: FirebaseRegistrationExpiredTime(UTCDate(DateTime.parse('2018-07-31T00:13:21Z'))),
types: [TypeName.mailboxType], types: [TypeName.mailboxType],
); );
final expectFirebaseSubscription2 = FirebaseSubscription( final expectFirebaseRegistration2 = FirebaseRegistration(
id: FirebaseSubscriptionId(Id('f2d0aab5-e976-4e8b-ad4b-b380a5b987e4')), id: FirebaseRegistrationId(Id('f2d0aab5-e976-4e8b-ad4b-b380a5b987e4')),
deviceClientId: DeviceClientId('X8980fc'), deviceClientId: DeviceClientId('X8980fc'),
expires: FirebaseExpiredTime(UTCDate(DateTime.parse('2018-07-12T05:55:00Z'))), expires: FirebaseRegistrationExpiredTime(UTCDate(DateTime.parse('2018-07-12T05:55:00Z'))),
types: [TypeName.mailboxType, TypeName.emailType, TypeName.emailDelivery], types: [TypeName.mailboxType, TypeName.emailType, TypeName.emailDelivery],
); );
test('firebase subscription get method and response parsing', () async { test('firebase registration get method and response parsing', () async {
final baseOption = BaseOptions(method: 'POST'); final baseOption = BaseOptions(method: 'POST');
final dio = Dio(baseOption)..options.baseUrl = 'http://domain.com/jmap'; final dio = Dio(baseOption)..options.baseUrl = 'http://domain.com/jmap';
final dioAdapter = DioAdapter(dio: dio); final dioAdapter = DioAdapter(dio: dio);
@@ -84,20 +84,20 @@ void main() {
final processingInvocation = ProcessingInvocation(); final processingInvocation = ProcessingInvocation();
final requestBuilder = JmapRequestBuilder(httpClient, processingInvocation); final requestBuilder = JmapRequestBuilder(httpClient, processingInvocation);
final firebaseSubscriptionGetMethod = FirebaseSubscriptionGetMethod(); final firebaseRegistrationGetMethod = FirebaseRegistrationGetMethod();
final firebaseSubscriptionGetInvocation = requestBuilder.invocation(firebaseSubscriptionGetMethod); final firebaseRegistrationGetInvocation = requestBuilder.invocation(firebaseRegistrationGetMethod);
final response = await (requestBuilder final response = await (requestBuilder
..usings(firebaseSubscriptionGetMethod.requiredCapabilities)) ..usings(firebaseRegistrationGetMethod.requiredCapabilities))
.build() .build()
.execute(); .execute();
final resultList = response.parse<FirebaseSubscriptionGetResponse>( final resultList = response.parse<FirebaseRegistrationGetResponse>(
firebaseSubscriptionGetInvocation.methodCallId, firebaseRegistrationGetInvocation.methodCallId,
FirebaseSubscriptionGetResponse.deserialize FirebaseRegistrationGetResponse.deserialize
); );
expect(resultList?.list.length, equals(2)); expect(resultList?.list.length, equals(2));
expect(resultList?.list, containsAll([expectFirebaseSubscription1, expectFirebaseSubscription2])); expect(resultList?.list, containsAll([expectFirebaseRegistration1, expectFirebaseRegistration2]));
}); });
}); });
} }
@@ -1,11 +1,11 @@
import 'package:dio/dio.dart'; import 'package:dio/dio.dart';
import 'package:fcm/method/set/firebase_subscription_set_method.dart'; import 'package:fcm/method/set/firebase_registration_set_method.dart';
import 'package:fcm/method/set/firebase_subscription_set_response.dart'; import 'package:fcm/method/set/firebase_registration_set_response.dart';
import 'package:fcm/model/device_client_id.dart'; import 'package:fcm/model/device_client_id.dart';
import 'package:fcm/model/firebase_expired_time.dart'; import 'package:fcm/model/firebase_registration_expired_time.dart';
import 'package:fcm/model/firebase_subscription.dart'; import 'package:fcm/model/firebase_registration.dart';
import 'package:fcm/model/firebase_subscription_id.dart'; import 'package:fcm/model/firebase_registration_id.dart';
import 'package:fcm/model/firebase_token.dart'; import 'package:fcm/model/fcm_token.dart';
import 'package:fcm/model/type_name.dart'; import 'package:fcm/model/type_name.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:http_mock_adapter/http_mock_adapter.dart'; import 'package:http_mock_adapter/http_mock_adapter.dart';
@@ -15,13 +15,13 @@ import 'package:jmap_dart_client/jmap/core/utc_date.dart';
import 'package:jmap_dart_client/jmap/jmap_request.dart'; import 'package:jmap_dart_client/jmap/jmap_request.dart';
void main() { void main() {
group('test to json firebase subscription set method', () { group('test to json firebase registration set method', () {
final expectedFirebaseSubscriptionCreated = FirebaseSubscription( final expectedFirebaseRegistrationCreated = FirebaseRegistration(
id: FirebaseSubscriptionId(Id('175dbd70-93d1-11ec-984e-e3f8b83572b4')), id: FirebaseRegistrationId(Id('175dbd70-93d1-11ec-984e-e3f8b83572b4')),
expires: FirebaseExpiredTime(UTCDate(DateTime.parse('2022-03-31T02:14:29Z'))), expires: FirebaseRegistrationExpiredTime(UTCDate(DateTime.parse('2022-03-31T02:14:29Z'))),
); );
test('firebase subscription set method and response parsing', () async { test('firebase registration set method and response parsing', () async {
final baseOption = BaseOptions(method: 'POST'); final baseOption = BaseOptions(method: 'POST');
final dio = Dio(baseOption) final dio = Dio(baseOption)
..options.baseUrl = 'http://domain.com/jmap'; ..options.baseUrl = 'http://domain.com/jmap';
@@ -75,31 +75,31 @@ void main() {
final createRequestId = Id('dab246'); final createRequestId = Id('dab246');
final firebaseSubscriptionSetMethod = FirebaseSubscriptionSetMethod() final firebaseRegistrationSetMethod = FirebaseRegistrationSetMethod()
..addCreate( ..addCreate(
createRequestId, createRequestId,
FirebaseSubscription( FirebaseRegistration(
deviceClientId: DeviceClientId('a123-b123-c123'), deviceClientId: DeviceClientId('a123-b123-c123'),
token: FirebaseToken('token1'), token: FcmToken('token1'),
types: [TypeName.mailboxType] types: [TypeName.mailboxType]
) )
); );
final httpClient = HttpClient(dio); final httpClient = HttpClient(dio);
final requestBuilder = JmapRequestBuilder(httpClient, ProcessingInvocation()); final requestBuilder = JmapRequestBuilder(httpClient, ProcessingInvocation());
final firebaseSubscriptionSetInvocation = requestBuilder.invocation(firebaseSubscriptionSetMethod); final firebaseRegistrationSetInvocation = requestBuilder.invocation(firebaseRegistrationSetMethod);
final response = await (requestBuilder final response = await (requestBuilder
..usings(firebaseSubscriptionSetMethod.requiredCapabilities)) ..usings(firebaseRegistrationSetMethod.requiredCapabilities))
.build() .build()
.execute(); .execute();
final firebaseSubscriptionSetResponse = response.parse<FirebaseSubscriptionSetResponse>( final firebaseRegistrationSetResponse = response.parse<FirebaseRegistrationSetResponse>(
firebaseSubscriptionSetInvocation.methodCallId, firebaseRegistrationSetInvocation.methodCallId,
FirebaseSubscriptionSetResponse.deserialize); FirebaseRegistrationSetResponse.deserialize);
expect( expect(
firebaseSubscriptionSetResponse!.created![createRequestId]!.id, firebaseRegistrationSetResponse!.created![createRequestId]!.id,
equals(expectedFirebaseSubscriptionCreated.id) equals(expectedFirebaseRegistrationCreated.id)
); );
}); });
}); });
+24 -23
View File
@@ -12,6 +12,7 @@ import 'package:core/utils/fps_manager.dart';
import 'package:core/utils/platform_info.dart'; import 'package:core/utils/platform_info.dart';
import 'package:dartz/dartz.dart'; import 'package:dartz/dartz.dart';
import 'package:fcm/model/firebase_capability.dart'; import 'package:fcm/model/firebase_capability.dart';
import 'package:fcm/model/firebase_registration_id.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart'; import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:forward/forward/capability_forward.dart'; import 'package:forward/forward/capability_forward.dart';
@@ -38,10 +39,10 @@ import 'package:tmail_ui_user/features/manage_account/domain/usecases/log_out_oi
import 'package:tmail_ui_user/features/manage_account/presentation/email_rules/bindings/email_rules_interactor_bindings.dart'; import 'package:tmail_ui_user/features/manage_account/presentation/email_rules/bindings/email_rules_interactor_bindings.dart';
import 'package:tmail_ui_user/features/manage_account/presentation/forward/bindings/forwarding_interactors_bindings.dart'; import 'package:tmail_ui_user/features/manage_account/presentation/forward/bindings/forwarding_interactors_bindings.dart';
import 'package:tmail_ui_user/features/push_notification/domain/exceptions/fcm_exception.dart'; import 'package:tmail_ui_user/features/push_notification/domain/exceptions/fcm_exception.dart';
import 'package:tmail_ui_user/features/push_notification/domain/state/destroy_subscription_state.dart'; import 'package:tmail_ui_user/features/push_notification/domain/state/destroy_firebase_registration_state.dart';
import 'package:tmail_ui_user/features/push_notification/domain/state/get_fcm_subscription_local.dart'; import 'package:tmail_ui_user/features/push_notification/domain/state/get_stored_firebase_registration_state.dart';
import 'package:tmail_ui_user/features/push_notification/domain/usecases/destroy_subscription_interactor.dart'; import 'package:tmail_ui_user/features/push_notification/domain/usecases/destroy_firebase_registration_interactor.dart';
import 'package:tmail_ui_user/features/push_notification/domain/usecases/get_fcm_subscription_local_interactor.dart'; import 'package:tmail_ui_user/features/push_notification/domain/usecases/get_stored_firebase_registration_interactor.dart';
import 'package:tmail_ui_user/features/push_notification/presentation/bindings/fcm_interactor_bindings.dart'; import 'package:tmail_ui_user/features/push_notification/presentation/bindings/fcm_interactor_bindings.dart';
import 'package:tmail_ui_user/features/push_notification/presentation/config/fcm_configuration.dart'; import 'package:tmail_ui_user/features/push_notification/presentation/config/fcm_configuration.dart';
import 'package:tmail_ui_user/features/push_notification/presentation/controller/fcm_message_controller.dart'; import 'package:tmail_ui_user/features/push_notification/presentation/controller/fcm_message_controller.dart';
@@ -76,8 +77,8 @@ abstract class BaseController extends GetxController
final _fcmReceiver = FcmReceiver.instance; final _fcmReceiver = FcmReceiver.instance;
bool _isFcmEnabled = false; bool _isFcmEnabled = false;
GetFCMSubscriptionLocalInteractor? _getSubscriptionLocalInteractor; GetStoredFirebaseRegistrationInteractor? _getStoredFirebaseRegistrationInteractor;
DestroySubscriptionInteractor? _destroySubscriptionInteractor; DestroyFirebaseRegistrationInteractor? _destroyFirebaseRegistrationInteractor;
final viewState = Rx<Either<Failure, Success>>(Right(UIState.idle)); final viewState = Rx<Either<Failure, Success>>(Right(UIState.idle));
FpsCallback? fpsCallback; FpsCallback? fpsCallback;
@@ -180,12 +181,12 @@ abstract class BaseController extends GetxController
logError('BaseController::handleFailureViewState(): ${failure.runtimeType}'); logError('BaseController::handleFailureViewState(): ${failure.runtimeType}');
if (failure is LogoutOidcFailure) { if (failure is LogoutOidcFailure) {
if (_isFcmEnabled) { if (_isFcmEnabled) {
_getSubscriptionLocalAction(); _getStoredFirebaseRegistrationFromCache();
} else { } else {
await clearDataAndGoToLoginPage(); await clearDataAndGoToLoginPage();
} }
} else if (failure is GetFCMSubscriptionLocalFailure || } else if (failure is GetStoredFirebaseRegistrationFailure ||
failure is DestroySubscriptionFailure) { failure is DestroyFirebaseRegistrationFailure) {
await clearDataAndGoToLoginPage(); await clearDataAndGoToLoginPage();
} }
} }
@@ -194,13 +195,13 @@ abstract class BaseController extends GetxController
log('BaseController::handleSuccessViewState(): ${success.runtimeType}'); log('BaseController::handleSuccessViewState(): ${success.runtimeType}');
if (success is LogoutOidcSuccess) { if (success is LogoutOidcSuccess) {
if (_isFcmEnabled) { if (_isFcmEnabled) {
_getSubscriptionLocalAction(); _getStoredFirebaseRegistrationFromCache();
} else { } else {
await clearDataAndGoToLoginPage(); await clearDataAndGoToLoginPage();
} }
} else if (success is GetFCMSubscriptionLocalSuccess) { } else if (success is GetStoredFirebaseRegistrationSuccess) {
_destroySubscriptionAction(success.fcmSubscription.subscriptionId); _destroyFirebaseRegistration(success.firebaseRegistration.id!);
} else if (success is DestroySubscriptionSuccess) { } else if (success is DestroyFirebaseRegistrationSuccess) {
await clearDataAndGoToLoginPage(); await clearDataAndGoToLoginPage();
} }
} }
@@ -265,7 +266,7 @@ abstract class BaseController extends GetxController
if (AppConfig.fcmAvailable) { if (AppConfig.fcmAvailable) {
final mapEnvData = Map<String, String>.from(dotenv.env); final mapEnvData = Map<String, String>.from(dotenv.env);
await AppUtils.loadFcmConfigFileToEnv(currentMapEnvData: mapEnvData); await AppUtils.loadFcmConfigFileToEnv(currentMapEnvData: mapEnvData);
FcmConfiguration.initialize(); await FcmConfiguration.initialize();
FcmInteractorBindings().dependencies(); FcmInteractorBindings().dependencies();
FcmMessageController.instance.initializeFromAccountId(accountId, session); FcmMessageController.instance.initializeFromAccountId(accountId, session);
} else { } else {
@@ -299,26 +300,26 @@ abstract class BaseController extends GetxController
consumeState(logoutOidcInteractor.execute()); consumeState(logoutOidcInteractor.execute());
} else { } else {
if (_isFcmEnabled) { if (_isFcmEnabled) {
_getSubscriptionLocalAction(); _getStoredFirebaseRegistrationFromCache();
} else { } else {
await clearDataAndGoToLoginPage(); await clearDataAndGoToLoginPage();
} }
} }
} }
void _destroySubscriptionAction(String subscriptionId) async { void _destroyFirebaseRegistration(FirebaseRegistrationId firebaseRegistrationId) async {
_destroySubscriptionInteractor = getBinding<DestroySubscriptionInteractor>(); _destroyFirebaseRegistrationInteractor = getBinding<DestroyFirebaseRegistrationInteractor>();
if (_destroySubscriptionInteractor != null) { if (_destroyFirebaseRegistrationInteractor != null) {
consumeState(_destroySubscriptionInteractor!.execute(subscriptionId)); consumeState(_destroyFirebaseRegistrationInteractor!.execute(firebaseRegistrationId));
} else { } else {
await clearDataAndGoToLoginPage(); await clearDataAndGoToLoginPage();
} }
} }
void _getSubscriptionLocalAction() async { void _getStoredFirebaseRegistrationFromCache() async {
_getSubscriptionLocalInteractor = getBinding<GetFCMSubscriptionLocalInteractor>(); _getStoredFirebaseRegistrationInteractor = getBinding<GetStoredFirebaseRegistrationInteractor>();
if (_getSubscriptionLocalInteractor != null) { if (_getStoredFirebaseRegistrationInteractor != null) {
consumeState(_getSubscriptionLocalInteractor!.execute()); consumeState(_getStoredFirebaseRegistrationInteractor!.execute());
} else { } else {
await clearDataAndGoToLoginPage(); await clearDataAndGoToLoginPage();
} }
+5 -5
View File
@@ -14,7 +14,7 @@ import 'package:tmail_ui_user/features/caching/clients/hive_cache_version_client
import 'package:tmail_ui_user/features/caching/clients/mailbox_cache_client.dart'; import 'package:tmail_ui_user/features/caching/clients/mailbox_cache_client.dart';
import 'package:tmail_ui_user/features/caching/clients/recent_search_cache_client.dart'; import 'package:tmail_ui_user/features/caching/clients/recent_search_cache_client.dart';
import 'package:tmail_ui_user/features/caching/clients/state_cache_client.dart'; import 'package:tmail_ui_user/features/caching/clients/state_cache_client.dart';
import 'package:tmail_ui_user/features/caching/clients/subscription_cache_client.dart'; import 'package:tmail_ui_user/features/caching/clients/firebase_registration_cache_client.dart';
import 'package:tmail_ui_user/features/caching/utils/caching_constants.dart'; import 'package:tmail_ui_user/features/caching/utils/caching_constants.dart';
import 'package:tmail_ui_user/features/mailbox/data/model/state_type.dart'; import 'package:tmail_ui_user/features/mailbox/data/model/state_type.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/data/local/local_spam_report_manager.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/data/local/local_spam_report_manager.dart';
@@ -28,7 +28,7 @@ class CachingManager {
final RecentSearchCacheClient _recentSearchCacheClient; final RecentSearchCacheClient _recentSearchCacheClient;
final AccountCacheClient _accountCacheClient; final AccountCacheClient _accountCacheClient;
final FcmCacheClient _fcmCacheClient; final FcmCacheClient _fcmCacheClient;
final FCMSubscriptionCacheClient _fcmSubscriptionCacheClient; final FirebaseRegistrationCacheClient _firebaseRegistrationCacheClient;
final HiveCacheVersionClient _hiveCacheVersionClient; final HiveCacheVersionClient _hiveCacheVersionClient;
final NewEmailHiveCacheClient _newEmailHiveCacheClient; final NewEmailHiveCacheClient _newEmailHiveCacheClient;
final OpenedEmailHiveCacheClient _openedEmailHiveCacheClient; final OpenedEmailHiveCacheClient _openedEmailHiveCacheClient;
@@ -44,7 +44,7 @@ class CachingManager {
this._recentSearchCacheClient, this._recentSearchCacheClient,
this._accountCacheClient, this._accountCacheClient,
this._fcmCacheClient, this._fcmCacheClient,
this._fcmSubscriptionCacheClient, this._firebaseRegistrationCacheClient,
this._hiveCacheVersionClient, this._hiveCacheVersionClient,
this._newEmailHiveCacheClient, this._newEmailHiveCacheClient,
this._openedEmailHiveCacheClient, this._openedEmailHiveCacheClient,
@@ -60,7 +60,7 @@ class CachingManager {
_mailboxCacheClient.clearAllData(), _mailboxCacheClient.clearAllData(),
_emailCacheClient.clearAllData(), _emailCacheClient.clearAllData(),
_fcmCacheClient.clearAllData(), _fcmCacheClient.clearAllData(),
_fcmSubscriptionCacheClient.clearAllData(), _firebaseRegistrationCacheClient.clearAllData(),
_recentSearchCacheClient.clearAllData(), _recentSearchCacheClient.clearAllData(),
_accountCacheClient.clearAllData(), _accountCacheClient.clearAllData(),
_localSpamReportManager.clear(), _localSpamReportManager.clear(),
@@ -80,7 +80,7 @@ class CachingManager {
_mailboxCacheClient.clearAllData(), _mailboxCacheClient.clearAllData(),
_emailCacheClient.clearAllData(), _emailCacheClient.clearAllData(),
_fcmCacheClient.clearAllData(), _fcmCacheClient.clearAllData(),
_fcmSubscriptionCacheClient.clearAllData(), _firebaseRegistrationCacheClient.clearAllData(),
_recentSearchCacheClient.clearAllData(), _recentSearchCacheClient.clearAllData(),
_localSpamReportManager.clear(), _localSpamReportManager.clear(),
if (PlatformInfo.isMobile) if (PlatformInfo.isMobile)
@@ -0,0 +1,10 @@
import 'package:tmail_ui_user/features/caching/config/hive_cache_client.dart';
import 'package:tmail_ui_user/features/caching/utils/caching_constants.dart';
import 'package:tmail_ui_user/features/push_notification/data/model/firebase_registration_cache.dart';
class FirebaseRegistrationCacheClient extends HiveCacheClient<FirebaseRegistrationCache> {
@override
String get tableName => CachingConstants.firebaseRegistrationCacheBoxName;
}
@@ -1,9 +0,0 @@
import 'package:tmail_ui_user/features/caching/config/hive_cache_client.dart';
import 'package:tmail_ui_user/features/push_notification/data/model/fcm_subscription.dart';
class FCMSubscriptionCacheClient extends HiveCacheClient<FCMSubscriptionCache> {
@override
String get tableName => 'FCMSubscriptionCache';
}
@@ -26,7 +26,7 @@ import 'package:tmail_ui_user/features/offline_mode/model/attachment_hive_cache.
import 'package:tmail_ui_user/features/offline_mode/model/detailed_email_hive_cache.dart'; import 'package:tmail_ui_user/features/offline_mode/model/detailed_email_hive_cache.dart';
import 'package:tmail_ui_user/features/offline_mode/model/email_header_hive_cache.dart'; import 'package:tmail_ui_user/features/offline_mode/model/email_header_hive_cache.dart';
import 'package:tmail_ui_user/features/offline_mode/model/sending_email_hive_cache.dart'; import 'package:tmail_ui_user/features/offline_mode/model/sending_email_hive_cache.dart';
import 'package:tmail_ui_user/features/push_notification/data/model/fcm_subscription.dart'; import 'package:tmail_ui_user/features/push_notification/data/model/firebase_registration_cache.dart';
import 'package:tmail_ui_user/features/thread/data/model/email_address_hive_cache.dart'; import 'package:tmail_ui_user/features/thread/data/model/email_address_hive_cache.dart';
import 'package:tmail_ui_user/features/thread/data/model/email_cache.dart'; import 'package:tmail_ui_user/features/thread/data/model/email_cache.dart';
import 'package:tmail_ui_user/main/bindings/network/binding_tag.dart'; import 'package:tmail_ui_user/main/bindings/network/binding_tag.dart';
@@ -145,9 +145,9 @@ class HiveCacheConfig {
RecentLoginUsernameCacheAdapter(), RecentLoginUsernameCacheAdapter(),
CachingConstants.RECENT_LOGIN_USERNAME_HIVE_CACHE_IDENTITY CachingConstants.RECENT_LOGIN_USERNAME_HIVE_CACHE_IDENTITY
); );
registerCacheAdapter<FCMSubscriptionCache>( registerCacheAdapter<FirebaseRegistrationCache>(
FCMSubscriptionCacheAdapter(), FirebaseRegistrationCacheAdapter(),
CachingConstants.FCM_SUBSCRIPTION_HIVE_CACHE_IDENTITY CachingConstants.FIREBASE_REGISTRATION_HIVE_CACHE_IDENTITY
); );
registerCacheAdapter<AttachmentHiveCache>( registerCacheAdapter<AttachmentHiveCache>(
AttachmentHiveCacheAdapter(), AttachmentHiveCacheAdapter(),
@@ -13,7 +13,7 @@ class CachingConstants {
static const int AUTHENTICATION_INFO_HIVE_CACHE_IDENTIFY = 11; static const int AUTHENTICATION_INFO_HIVE_CACHE_IDENTIFY = 11;
static const int RECENT_LOGIN_URL_HIVE_CACHE_IDENTITY = 12; static const int RECENT_LOGIN_URL_HIVE_CACHE_IDENTITY = 12;
static const int RECENT_LOGIN_USERNAME_HIVE_CACHE_IDENTITY = 13; static const int RECENT_LOGIN_USERNAME_HIVE_CACHE_IDENTITY = 13;
static const int FCM_SUBSCRIPTION_HIVE_CACHE_IDENTITY = 14; static const int FIREBASE_REGISTRATION_HIVE_CACHE_IDENTITY = 14;
static const int ATTACHMENT_HIVE_CACHE_ID = 15; static const int ATTACHMENT_HIVE_CACHE_ID = 15;
static const int EMAIL_HEADER_HIVE_CACHE_ID = 16; static const int EMAIL_HEADER_HIVE_CACHE_ID = 16;
static const int DETAILED_EMAIL_HIVE_CACHE_ID = 17; static const int DETAILED_EMAIL_HIVE_CACHE_ID = 17;
@@ -25,6 +25,7 @@ class CachingConstants {
static const String openedEmailCacheBoxName = 'opened_email_cache_box'; static const String openedEmailCacheBoxName = 'opened_email_cache_box';
static const String sendingEmailCacheBoxName = 'sending_email_cache_box'; static const String sendingEmailCacheBoxName = 'sending_email_cache_box';
static const String sessionCacheBoxName = 'session_cache_box'; static const String sessionCacheBoxName = 'session_cache_box';
static const String firebaseRegistrationCacheBoxName = 'firebase_registration_cache_box';
static const String newEmailsContentFolderName = 'new_emails'; static const String newEmailsContentFolderName = 'new_emails';
static const String openedEmailContentFolderName = 'opened_email'; static const String openedEmailContentFolderName = 'opened_email';
@@ -1,11 +1,13 @@
import 'package:fcm/model/firebase_subscription.dart'; import 'package:fcm/model/device_client_id.dart';
import 'package:fcm/model/firebase_registration.dart';
import 'package:fcm/model/firebase_registration_id.dart';
import 'package:fcm/model/type_name.dart'; import 'package:fcm/model/type_name.dart';
import 'package:jmap_dart_client/jmap/account_id.dart'; import 'package:jmap_dart_client/jmap/account_id.dart';
import 'package:jmap_dart_client/jmap/core/state.dart' as jmap; import 'package:jmap_dart_client/jmap/core/state.dart' as jmap;
import 'package:jmap_dart_client/jmap/core/user_name.dart'; import 'package:jmap_dart_client/jmap/core/user_name.dart';
import 'package:tmail_ui_user/features/push_notification/data/model/fcm_subscription.dart';
import 'package:tmail_ui_user/features/push_notification/domain/model/register_new_token_request.dart'; import 'package:tmail_ui_user/features/push_notification/domain/model/register_new_token_request.dart';
import 'package:tmail_ui_user/features/push_notification/domain/model/update_token_expired_time_request.dart';
abstract class FCMDatasource { abstract class FCMDatasource {
Future<void> storeStateToRefresh(AccountId accountId, UserName userName, TypeName typeName, jmap.State newState); Future<void> storeStateToRefresh(AccountId accountId, UserName userName, TypeName typeName, jmap.State newState);
@@ -14,13 +16,17 @@ abstract class FCMDatasource {
Future<void> deleteStateToRefresh(AccountId accountId, UserName userName, TypeName typeName); Future<void> deleteStateToRefresh(AccountId accountId, UserName userName, TypeName typeName);
Future<void> storeSubscription(FCMSubscriptionCache fcmSubscriptionCache); Future<void> storeFirebaseRegistration(FirebaseRegistration firebaseRegistration);
Future<FirebaseSubscription> getFirebaseSubscriptionByDeviceId(String deviceId); Future<FirebaseRegistration> getFirebaseRegistrationByDeviceId(DeviceClientId deviceId);
Future<FirebaseSubscription> registerNewToken(RegisterNewTokenRequest newTokenRequest); Future<FirebaseRegistration> registerNewFirebaseRegistrationToken(RegisterNewTokenRequest newTokenRequest);
Future<FCMSubscriptionCache> geSubscription(); Future<FirebaseRegistration> getStoredFirebaseRegistration();
Future<bool> destroySubscription(String subscriptionId); Future<void> deleteFirebaseRegistrationCache();
Future<void> destroyFirebaseRegistration(FirebaseRegistrationId registrationId);
Future<void> updateFirebaseRegistrationToken(UpdateTokenExpiredTimeRequest expiredTimeRequest);
} }
@@ -1,12 +1,16 @@
import 'package:fcm/model/firebase_subscription.dart'; import 'package:fcm/model/device_client_id.dart';
import 'package:fcm/model/firebase_registration.dart';
import 'package:fcm/model/firebase_registration_id.dart';
import 'package:fcm/model/type_name.dart'; import 'package:fcm/model/type_name.dart';
import 'package:jmap_dart_client/jmap/account_id.dart'; import 'package:jmap_dart_client/jmap/account_id.dart';
import 'package:jmap_dart_client/jmap/core/state.dart' as jmap; import 'package:jmap_dart_client/jmap/core/state.dart' as jmap;
import 'package:jmap_dart_client/jmap/core/user_name.dart'; import 'package:jmap_dart_client/jmap/core/user_name.dart';
import 'package:tmail_ui_user/features/push_notification/data/datasource/fcm_datasource.dart'; import 'package:tmail_ui_user/features/push_notification/data/datasource/fcm_datasource.dart';
import 'package:tmail_ui_user/features/push_notification/data/extensions/firebase_registration_cache_extension.dart';
import 'package:tmail_ui_user/features/push_notification/data/extensions/firebase_registration_extension.dart';
import 'package:tmail_ui_user/features/push_notification/data/local/fcm_cache_manager.dart'; import 'package:tmail_ui_user/features/push_notification/data/local/fcm_cache_manager.dart';
import 'package:tmail_ui_user/features/push_notification/data/model/fcm_subscription.dart';
import 'package:tmail_ui_user/features/push_notification/domain/model/register_new_token_request.dart'; import 'package:tmail_ui_user/features/push_notification/domain/model/register_new_token_request.dart';
import 'package:tmail_ui_user/features/push_notification/domain/model/update_token_expired_time_request.dart';
import 'package:tmail_ui_user/main/exceptions/exception_thrower.dart'; import 'package:tmail_ui_user/main/exceptions/exception_thrower.dart';
class CacheFCMDatasourceImpl extends FCMDatasource { class CacheFCMDatasourceImpl extends FCMDatasource {
@@ -38,31 +42,44 @@ class CacheFCMDatasourceImpl extends FCMDatasource {
} }
@override @override
Future<FirebaseSubscription> getFirebaseSubscriptionByDeviceId(String deviceId) { Future<FirebaseRegistration> getFirebaseRegistrationByDeviceId(DeviceClientId deviceId) {
throw UnimplementedError(); throw UnimplementedError();
} }
@override @override
Future<FirebaseSubscription> registerNewToken(RegisterNewTokenRequest newTokenRequest) { Future<FirebaseRegistration> registerNewFirebaseRegistrationToken(RegisterNewTokenRequest newTokenRequest) {
throw UnimplementedError(); throw UnimplementedError();
} }
@override @override
Future<void> storeSubscription(FCMSubscriptionCache fcmSubscriptionCache) { Future<void> storeFirebaseRegistration(FirebaseRegistration firebaseRegistration) {
return Future.sync(() async { return Future.sync(() async {
return await _firebaseCacheManager.storeSubscription(fcmSubscriptionCache); return await _firebaseCacheManager.storeFirebaseRegistration(firebaseRegistration.toFirebaseRegistrationCache());
}).catchError(_exceptionThrower.throwException); }).catchError(_exceptionThrower.throwException);
} }
@override @override
Future<FCMSubscriptionCache> geSubscription() { Future<FirebaseRegistration> getStoredFirebaseRegistration() {
return Future.sync(() async { return Future.sync(() async {
return await _firebaseCacheManager.getSubscription(); final firebaseRegistrationCache = await _firebaseCacheManager.getStoredFirebaseRegistration();
return firebaseRegistrationCache.toFirebaseRegistration();
}).catchError(_exceptionThrower.throwException); }).catchError(_exceptionThrower.throwException);
} }
@override @override
Future<bool> destroySubscription(String subscriptionId) { Future<void> destroyFirebaseRegistration(FirebaseRegistrationId registrationId) {
throw UnimplementedError(); throw UnimplementedError();
} }
@override
Future<void> updateFirebaseRegistrationToken(UpdateTokenExpiredTimeRequest expiredTimeRequest) {
throw UnimplementedError();
}
@override
Future<void> deleteFirebaseRegistrationCache() {
return Future.sync(() async {
return await _firebaseCacheManager.deleteFirebaseRegistration();
}).catchError(_exceptionThrower.throwException);
}
} }
@@ -1,13 +1,15 @@
import 'package:fcm/model/firebase_subscription.dart'; import 'package:fcm/model/device_client_id.dart';
import 'package:fcm/model/firebase_registration.dart';
import 'package:fcm/model/firebase_registration_id.dart';
import 'package:fcm/model/type_name.dart'; import 'package:fcm/model/type_name.dart';
import 'package:jmap_dart_client/jmap/account_id.dart'; import 'package:jmap_dart_client/jmap/account_id.dart';
import 'package:jmap_dart_client/jmap/core/state.dart' as jmap; import 'package:jmap_dart_client/jmap/core/state.dart' as jmap;
import 'package:jmap_dart_client/jmap/core/user_name.dart'; import 'package:jmap_dart_client/jmap/core/user_name.dart';
import 'package:tmail_ui_user/features/push_notification/data/datasource/fcm_datasource.dart'; import 'package:tmail_ui_user/features/push_notification/data/datasource/fcm_datasource.dart';
import 'package:tmail_ui_user/features/push_notification/data/model/fcm_subscription.dart';
import 'package:tmail_ui_user/features/push_notification/data/network/fcm_api.dart'; import 'package:tmail_ui_user/features/push_notification/data/network/fcm_api.dart';
import 'package:tmail_ui_user/features/push_notification/domain/extensions/firebase_subscription_extension.dart'; import 'package:tmail_ui_user/features/push_notification/domain/extensions/firebase_registration_extension.dart';
import 'package:tmail_ui_user/features/push_notification/domain/model/register_new_token_request.dart'; import 'package:tmail_ui_user/features/push_notification/domain/model/register_new_token_request.dart';
import 'package:tmail_ui_user/features/push_notification/domain/model/update_token_expired_time_request.dart';
import 'package:tmail_ui_user/main/exceptions/exception_thrower.dart'; import 'package:tmail_ui_user/main/exceptions/exception_thrower.dart';
class FcmDatasourceImpl extends FCMDatasource { class FcmDatasourceImpl extends FCMDatasource {
@@ -18,9 +20,9 @@ class FcmDatasourceImpl extends FCMDatasource {
FcmDatasourceImpl(this._fcmApi, this._exceptionThrower); FcmDatasourceImpl(this._fcmApi, this._exceptionThrower);
@override @override
Future<FirebaseSubscription> getFirebaseSubscriptionByDeviceId(String deviceId) { Future<FirebaseRegistration> getFirebaseRegistrationByDeviceId(DeviceClientId deviceId) {
return Future.sync(() async { return Future.sync(() async {
return await _fcmApi.getFirebaseSubscriptionByDeviceId(deviceId); return await _fcmApi.getFirebaseRegistrationByDeviceId(deviceId);
}).catchError(_exceptionThrower.throwException); }).catchError(_exceptionThrower.throwException);
} }
@@ -40,27 +42,43 @@ class FcmDatasourceImpl extends FCMDatasource {
} }
@override @override
Future<FirebaseSubscription> registerNewToken(RegisterNewTokenRequest newTokenRequest) { Future<FirebaseRegistration> registerNewFirebaseRegistrationToken(RegisterNewTokenRequest newTokenRequest) {
return Future.sync(() async { return Future.sync(() async {
final firebaseSubscription = await _fcmApi.registerNewToken(newTokenRequest); final registrationCreated = await _fcmApi.registerNewFirebaseRegistrationToken(newTokenRequest);
return firebaseSubscription.fromDeviceId(newDeviceId: newTokenRequest.firebaseSubscription.deviceClientId); return registrationCreated.syncProperties(
newDeviceId: newTokenRequest.firebaseRegistration.deviceClientId,
newFcmToken: newTokenRequest.firebaseRegistration.token,
newTypes: newTokenRequest.firebaseRegistration.types,
);
}).catchError(_exceptionThrower.throwException); }).catchError(_exceptionThrower.throwException);
} }
@override @override
Future<bool> storeSubscription(FCMSubscriptionCache fcmSubscriptionCache) { Future<bool> storeFirebaseRegistration(FirebaseRegistration firebaseRegistration) {
throw UnimplementedError(); throw UnimplementedError();
} }
@override @override
Future<FCMSubscriptionCache> geSubscription() { Future<FirebaseRegistration> getStoredFirebaseRegistration() {
throw UnimplementedError(); throw UnimplementedError();
} }
@override @override
Future<bool> destroySubscription(String subscriptionId) { Future<void> destroyFirebaseRegistration(FirebaseRegistrationId registrationId) {
return Future.sync(() async { return Future.sync(() async {
return await _fcmApi.destroySubscription(subscriptionId); return await _fcmApi.destroyFirebaseRegistration(registrationId);
}).catchError(_exceptionThrower.throwException); }).catchError(_exceptionThrower.throwException);
} }
@override
Future<void> updateFirebaseRegistrationToken(UpdateTokenExpiredTimeRequest expiredTimeRequest) {
return Future.sync(() async {
return await _fcmApi.updateFirebaseRegistrationToken(expiredTimeRequest);
}).catchError(_exceptionThrower.throwException);
}
@override
Future<void> deleteFirebaseRegistrationCache() {
throw UnimplementedError();
}
} }
@@ -1,10 +0,0 @@
import 'package:tmail_ui_user/features/push_notification/data/model/fcm_subscription.dart';
import 'package:tmail_ui_user/features/push_notification/domain/model/fcm_subscription.dart';
extension FCMSubscriptionExtension on FCMSubscription {
FCMSubscriptionCache toFCMSubscriptionCache() {
return FCMSubscriptionCache(deviceId, subscriptionId);
}
}
@@ -0,0 +1,20 @@
import 'package:fcm/converter/device_client_id_nullable_converter.dart';
import 'package:fcm/converter/fcm_token_nullable_converter.dart';
import 'package:fcm/converter/firebase_registration_id_nullable_converter.dart';
import 'package:fcm/converter/type_name_converter.dart';
import 'package:fcm/model/firebase_registration.dart';
import 'package:fcm/model/firebase_registration_expired_time.dart';
import 'package:jmap_dart_client/jmap/core/utc_date.dart';
import 'package:tmail_ui_user/features/push_notification/data/model/firebase_registration_cache.dart';
extension FirebaseRegistrationCacheExtension on FirebaseRegistrationCache {
FirebaseRegistration toFirebaseRegistration() {
return FirebaseRegistration(
id: const FirebaseRegistrationIdNullableConverter().fromJson(id),
token: const FcmTokenNullableConverter().fromJson(token),
deviceClientId: const DeviceClientIdNullableConverter().fromJson(deviceClientId),
expires: expires != null ? FirebaseRegistrationExpiredTime(UTCDate(expires!)) : null,
types: types?.map((type) => const TypeNameConverter().fromJson(type)).toList()
);
}
}
@@ -0,0 +1,14 @@
import 'package:fcm/model/firebase_registration.dart';
import 'package:tmail_ui_user/features/push_notification/data/model/firebase_registration_cache.dart';
extension FirebaseRegistrationExtension on FirebaseRegistration {
FirebaseRegistrationCache toFirebaseRegistrationCache() {
return FirebaseRegistrationCache(
deviceClientId: deviceClientId!.value,
id: id?.id.value,
token: token?.value,
expires: expires?.value.value,
types: types?.map((type) => type.value).toList(),
);
}
}
@@ -3,17 +3,17 @@ import 'package:jmap_dart_client/jmap/account_id.dart';
import 'package:jmap_dart_client/jmap/core/user_name.dart'; import 'package:jmap_dart_client/jmap/core/user_name.dart';
import 'package:model/extensions/account_id_extensions.dart'; import 'package:model/extensions/account_id_extensions.dart';
import 'package:tmail_ui_user/features/caching/clients/fcm_cache_client.dart'; import 'package:tmail_ui_user/features/caching/clients/fcm_cache_client.dart';
import 'package:tmail_ui_user/features/caching/clients/subscription_cache_client.dart'; import 'package:tmail_ui_user/features/caching/clients/firebase_registration_cache_client.dart';
import 'package:tmail_ui_user/features/caching/utils/cache_utils.dart'; import 'package:tmail_ui_user/features/caching/utils/cache_utils.dart';
import 'package:tmail_ui_user/features/push_notification/data/model/fcm_subscription.dart'; import 'package:tmail_ui_user/features/push_notification/data/model/firebase_registration_cache.dart';
import 'package:tmail_ui_user/features/push_notification/domain/exceptions/fcm_exception.dart'; import 'package:tmail_ui_user/features/push_notification/domain/exceptions/fcm_exception.dart';
import 'package:jmap_dart_client/jmap/core/state.dart' as jmap; import 'package:jmap_dart_client/jmap/core/state.dart' as jmap;
class FCMCacheManager { class FCMCacheManager {
final FcmCacheClient _fcmCacheClient; final FcmCacheClient _fcmCacheClient;
final FCMSubscriptionCacheClient _fcmSubscriptionCacheClient; final FirebaseRegistrationCacheClient _firebaseRegistrationCacheClient;
FCMCacheManager(this._fcmCacheClient,this._fcmSubscriptionCacheClient); FCMCacheManager(this._fcmCacheClient,this._firebaseRegistrationCacheClient);
Future<void> storeStateToRefresh(AccountId accountId, UserName userName, TypeName typeName, jmap.State newState) { Future<void> storeStateToRefresh(AccountId accountId, UserName userName, TypeName typeName, jmap.State newState) {
final stateKeyCache = TupleKey(typeName.value, accountId.asString, userName.value).encodeKey; final stateKeyCache = TupleKey(typeName.value, accountId.asString, userName.value).encodeKey;
@@ -43,17 +43,23 @@ class FCMCacheManager {
return _fcmCacheClient.clearAllData(); return _fcmCacheClient.clearAllData();
} }
Future<void> storeSubscription(FCMSubscriptionCache fcmSubscriptionCache) { Future<void> storeFirebaseRegistration(FirebaseRegistrationCache firebaseRegistrationCache) {
return _fcmSubscriptionCacheClient.insertItem( return _firebaseRegistrationCacheClient.insertItem(
FCMSubscriptionCache.keyCacheValue, fcmSubscriptionCache); FirebaseRegistrationCache.keyCacheValue,
firebaseRegistrationCache
);
} }
Future<FCMSubscriptionCache> getSubscription() async { Future<FirebaseRegistrationCache> getStoredFirebaseRegistration() async {
final fcmSubscription = await _fcmSubscriptionCacheClient.getItem(FCMSubscriptionCache.keyCacheValue); final firebaseRegistration = await _firebaseRegistrationCacheClient.getItem(FirebaseRegistrationCache.keyCacheValue);
if (fcmSubscription == null) { if (firebaseRegistration == null) {
throw NotFoundSubscriptionException(); throw NotFoundFirebaseRegistrationCacheException();
} else { } else {
return fcmSubscription; return firebaseRegistration;
} }
} }
Future<void> deleteFirebaseRegistration() async {
await _firebaseRegistrationCacheClient.deleteItem(FirebaseRegistrationCache.keyCacheValue);
}
} }
@@ -1,23 +0,0 @@
import 'package:equatable/equatable.dart';
import 'package:hive/hive.dart';
import 'package:tmail_ui_user/features/caching/utils/caching_constants.dart';
part 'fcm_subscription.g.dart';
@HiveType(typeId: CachingConstants.FCM_SUBSCRIPTION_HIVE_CACHE_IDENTITY)
class FCMSubscriptionCache extends HiveObject with EquatableMixin {
static const String keyCacheValue = 'fcmSubscriptionCache';
@HiveField(0)
final String deviceId;
@HiveField(1)
final String subscriptionId;
FCMSubscriptionCache(this.deviceId, this.subscriptionId);
@override
List<Object?> get props => [deviceId, subscriptionId];
}
@@ -0,0 +1,44 @@
import 'package:equatable/equatable.dart';
import 'package:hive/hive.dart';
import 'package:tmail_ui_user/features/caching/utils/caching_constants.dart';
part 'firebase_registration_cache.g.dart';
@HiveType(typeId: CachingConstants.FIREBASE_REGISTRATION_HIVE_CACHE_IDENTITY)
class FirebaseRegistrationCache extends HiveObject with EquatableMixin {
static const String keyCacheValue = 'firebaseRegistrationCache';
@HiveField(0)
final String deviceClientId;
@HiveField(1)
final String? id;
@HiveField(2)
final String? token;
@HiveField(3)
final DateTime? expires;
@HiveField(4)
final List<String>? types;
FirebaseRegistrationCache({
required this.deviceClientId,
this.id,
this.token,
this.expires,
this.types
});
@override
List<Object?> get props => [
deviceClientId,
id,
token,
expires,
types
];
}
@@ -1,16 +1,19 @@
import 'package:fcm/method/set/firebase_subscription_set_method.dart'; import 'package:fcm/converter/firebase_registration_expired_time_nullable_converter.dart';
import 'package:fcm/method/set/firebase_subscription_set_response.dart'; import 'package:fcm/method/set/firebase_registration_set_method.dart';
import 'package:fcm/method/get/firebase_subscription_get_method.dart'; import 'package:fcm/method/set/firebase_registration_set_response.dart';
import 'package:fcm/method/get/firebase_subscription_get_response.dart'; import 'package:fcm/method/get/firebase_registration_get_method.dart';
import 'package:fcm/model/firebase_capability.dart'; import 'package:fcm/method/get/firebase_registration_get_response.dart';
import 'package:fcm/model/firebase_subscription.dart'; import 'package:fcm/model/device_client_id.dart';
import 'package:fcm/model/firebase_registration.dart';
import 'package:fcm/model/firebase_registration_id.dart';
import 'package:jmap_dart_client/http/http_client.dart'; import 'package:jmap_dart_client/http/http_client.dart';
import 'package:jmap_dart_client/jmap/core/capability/capability_identifier.dart'; import 'package:jmap_dart_client/jmap/core/patch_object.dart';
import 'package:jmap_dart_client/jmap/core/id.dart';
import 'package:jmap_dart_client/jmap/jmap_request.dart'; import 'package:jmap_dart_client/jmap/jmap_request.dart';
import 'package:tmail_ui_user/features/push_notification/domain/exceptions/fcm_exception.dart'; import 'package:tmail_ui_user/features/push_notification/domain/exceptions/fcm_exception.dart';
import 'package:tmail_ui_user/features/push_notification/domain/model/register_new_token_request.dart'; import 'package:tmail_ui_user/features/push_notification/domain/model/register_new_token_request.dart';
import 'package:tmail_ui_user/features/push_notification/domain/model/update_token_expired_time_request.dart';
import 'package:tmail_ui_user/features/push_notification/domain/utils/fcm_constants.dart';
class FcmApi { class FcmApi {
@@ -18,76 +21,105 @@ class FcmApi {
FcmApi(this._httpClient); FcmApi(this._httpClient);
Future<FirebaseSubscription> getFirebaseSubscriptionByDeviceId(String deviceId) async { Future<FirebaseRegistration> getFirebaseRegistrationByDeviceId(DeviceClientId deviceId) async {
final processingInvocation = ProcessingInvocation(); final processingInvocation = ProcessingInvocation();
final requestBuilder = JmapRequestBuilder(_httpClient, processingInvocation); final requestBuilder = JmapRequestBuilder(_httpClient, processingInvocation);
final firebaseSubscriptionGetMethod = FirebaseSubscriptionGetMethod(); final firebaseRegistrationGetMethod = FirebaseRegistrationGetMethod();
final firebaseSubscriptionGetInvocation = requestBuilder.invocation(firebaseSubscriptionGetMethod); final firebaseRegistrationGetInvocation = requestBuilder.invocation(firebaseRegistrationGetMethod);
final response = await (requestBuilder final response = await (requestBuilder
..usings(firebaseSubscriptionGetMethod.requiredCapabilities)) ..usings(firebaseRegistrationGetMethod.requiredCapabilities))
.build() .build()
.execute(); .execute();
final getResponse = response.parse<FirebaseSubscriptionGetResponse>( final getResponse = response.parse<FirebaseRegistrationGetResponse>(
firebaseSubscriptionGetInvocation.methodCallId, firebaseRegistrationGetInvocation.methodCallId,
FirebaseSubscriptionGetResponse.deserialize); FirebaseRegistrationGetResponse.deserialize);
final matchedFirebaseSubscription = getResponse?.list final matchedFirebaseRegistration = getResponse?.list
.where((fcmSub) => fcmSub.deviceClientId?.value == deviceId) .where((fcmSub) => fcmSub.deviceClientId == deviceId)
.toList(); .toList();
if (matchedFirebaseSubscription?.isNotEmpty == true) { if (matchedFirebaseRegistration?.isNotEmpty == true) {
return matchedFirebaseSubscription!.first; return matchedFirebaseRegistration!.first;
} else { } else {
throw NotFoundFirebaseSubscriptionException(); throw NotFoundFirebaseRegistrationForDeviceException();
} }
} }
Future<FirebaseSubscription> registerNewToken(RegisterNewTokenRequest newTokenRequest) async { Future<FirebaseRegistration> registerNewFirebaseRegistrationToken(RegisterNewTokenRequest newTokenRequest) async {
final processingInvocation = ProcessingInvocation(); final processingInvocation = ProcessingInvocation();
final requestBuilder = JmapRequestBuilder(_httpClient, processingInvocation); final requestBuilder = JmapRequestBuilder(_httpClient, processingInvocation);
final firebaseSubscriptionSetMethod = FirebaseSubscriptionSetMethod() final firebaseRegistrationSetMethod = FirebaseRegistrationSetMethod()
..addCreate( ..addCreate(
newTokenRequest.createRequestId, newTokenRequest.createRequestId,
newTokenRequest.firebaseSubscription newTokenRequest.firebaseRegistration
); );
final firebaseSubscriptionSetInvocation = requestBuilder.invocation(firebaseSubscriptionSetMethod); final firebaseRegistrationSetInvocation = requestBuilder.invocation(firebaseRegistrationSetMethod);
final response = await (requestBuilder final response = await (requestBuilder
..usings(firebaseSubscriptionSetMethod.requiredCapabilities)) ..usings(firebaseRegistrationSetMethod.requiredCapabilities))
.build() .build()
.execute(); .execute();
final firebaseSubscriptionSetResponse = response.parse<FirebaseSubscriptionSetResponse>( final firebaseRegistrationSetResponse = response.parse<FirebaseRegistrationSetResponse>(
firebaseSubscriptionSetInvocation.methodCallId, firebaseRegistrationSetInvocation.methodCallId,
FirebaseSubscriptionSetResponse.deserialize); FirebaseRegistrationSetResponse.deserialize);
return firebaseSubscriptionSetResponse!.created![newTokenRequest.createRequestId]!; final firebaseRegistration = firebaseRegistrationSetResponse?.created?[newTokenRequest.createRequestId];
if (firebaseRegistration != null) {
return firebaseRegistration;
} else {
throw NotFoundFirebaseRegistrationCreatedException();
}
} }
Future<bool> destroySubscription(String subscriptionId) async { Future<void> destroyFirebaseRegistration(FirebaseRegistrationId registrationId) async {
final processingInvocation = ProcessingInvocation(); final processingInvocation = ProcessingInvocation();
final requestBuilder = JmapRequestBuilder(_httpClient, processingInvocation); final requestBuilder = JmapRequestBuilder(_httpClient, processingInvocation);
final firebaseSubscriptionSetMethod = FirebaseSubscriptionSetMethod()..addDestroy({Id(subscriptionId)}); final firebaseRegistrationSetMethod = FirebaseRegistrationSetMethod()..addDestroy({registrationId.id});
final firebaseSubscriptionSetInvocation = requestBuilder.invocation(firebaseSubscriptionSetMethod); final firebaseRegistrationSetInvocation = requestBuilder.invocation(firebaseRegistrationSetMethod);
final response = await (requestBuilder final response = await (requestBuilder
..usings({ ..usings(firebaseRegistrationSetMethod.requiredCapabilities))
CapabilityIdentifier.jmapCore,
FirebaseCapability.fcmIdentifier,
}))
.build() .build()
.execute(); .execute();
final firebaseSubscriptionSetResponse = response.parse<FirebaseSubscriptionSetResponse>( final firebaseRegistrationSetResponse = response.parse<FirebaseRegistrationSetResponse>(
firebaseSubscriptionSetInvocation.methodCallId, firebaseRegistrationSetInvocation.methodCallId,
FirebaseSubscriptionSetResponse.deserialize); FirebaseRegistrationSetResponse.deserialize);
return Future.sync(() async { if (firebaseRegistrationSetResponse?.destroyed?.contains(registrationId.id) == true) {
return firebaseSubscriptionSetResponse?.destroyed?.contains(Id(subscriptionId)) == true; return;
}).catchError((error) { } else {
throw error; throw NotFoundFirebaseRegistrationDestroyedException();
}); }
}
Future<void> updateFirebaseRegistrationToken(UpdateTokenExpiredTimeRequest expiredTimeRequest) async {
final processingInvocation = ProcessingInvocation();
final requestBuilder = JmapRequestBuilder(_httpClient, processingInvocation);
final firebaseRegistrationSetMethod = FirebaseRegistrationSetMethod()
..addUpdates({
expiredTimeRequest.firebaseRegistrationId.id: PatchObject({
FcmConstants.firebaseRegistrationExpiredTimeProperty: const FirebaseRegistrationExpiredTimeNullableConverter().toJson(expiredTimeRequest.firebaseRegistrationExpiredTime)
})
});
final firebaseRegistrationSetInvocation = requestBuilder.invocation(firebaseRegistrationSetMethod);
final response = await (requestBuilder
..usings(firebaseRegistrationSetMethod.requiredCapabilities))
.build()
.execute();
final firebaseRegistrationSetResponse = response.parse<FirebaseRegistrationSetResponse>(
firebaseRegistrationSetInvocation.methodCallId,
FirebaseRegistrationSetResponse.deserialize);
if (firebaseRegistrationSetResponse?.updated?.containsKey(expiredTimeRequest.firebaseRegistrationId.id) == true) {
return;
} else {
throw NotFoundFirebaseRegistrationUpdatedException();
}
} }
} }
@@ -1,6 +1,8 @@
import 'package:core/data/model/source_type/data_source_type.dart'; import 'package:core/data/model/source_type/data_source_type.dart';
import 'package:core/utils/app_logger.dart'; import 'package:core/utils/app_logger.dart';
import 'package:fcm/model/firebase_subscription.dart'; import 'package:fcm/model/device_client_id.dart';
import 'package:fcm/model/firebase_registration.dart';
import 'package:fcm/model/firebase_registration_id.dart';
import 'package:fcm/model/type_name.dart'; import 'package:fcm/model/type_name.dart';
import 'package:jmap_dart_client/jmap/account_id.dart'; import 'package:jmap_dart_client/jmap/account_id.dart';
import 'package:jmap_dart_client/jmap/core/properties/properties.dart'; import 'package:jmap_dart_client/jmap/core/properties/properties.dart';
@@ -15,10 +17,9 @@ import 'package:model/extensions/presentation_mailbox_extension.dart';
import 'package:model/mailbox/presentation_mailbox.dart'; import 'package:model/mailbox/presentation_mailbox.dart';
import 'package:tmail_ui_user/features/mailbox/data/datasource/mailbox_datasource.dart'; import 'package:tmail_ui_user/features/mailbox/data/datasource/mailbox_datasource.dart';
import 'package:tmail_ui_user/features/push_notification/data/datasource/fcm_datasource.dart'; import 'package:tmail_ui_user/features/push_notification/data/datasource/fcm_datasource.dart';
import 'package:tmail_ui_user/features/push_notification/data/extensions/fcm_subscription_extensions.dart';
import 'package:tmail_ui_user/features/push_notification/domain/exceptions/fcm_exception.dart'; import 'package:tmail_ui_user/features/push_notification/domain/exceptions/fcm_exception.dart';
import 'package:tmail_ui_user/features/push_notification/domain/model/fcm_subscription.dart';
import 'package:tmail_ui_user/features/push_notification/domain/model/register_new_token_request.dart'; import 'package:tmail_ui_user/features/push_notification/domain/model/register_new_token_request.dart';
import 'package:tmail_ui_user/features/push_notification/domain/model/update_token_expired_time_request.dart';
import 'package:tmail_ui_user/features/push_notification/domain/repository/fcm_repository.dart'; import 'package:tmail_ui_user/features/push_notification/domain/repository/fcm_repository.dart';
import 'package:tmail_ui_user/features/push_notification/domain/utils/fcm_constants.dart'; import 'package:tmail_ui_user/features/push_notification/domain/utils/fcm_constants.dart';
import 'package:tmail_ui_user/features/thread/data/datasource/thread_datasource.dart'; import 'package:tmail_ui_user/features/thread/data/datasource/thread_datasource.dart';
@@ -94,29 +95,28 @@ class FCMRepositoryImpl extends FCMRepository {
} }
@override @override
Future<FirebaseSubscription> getFirebaseSubscriptionByDeviceId(String deviceId) { Future<FirebaseRegistration> getFirebaseRegistrationByDeviceId(DeviceClientId deviceId) {
return _fcmDatasource[DataSourceType.network]!.getFirebaseSubscriptionByDeviceId(deviceId); return _fcmDatasource[DataSourceType.network]!.getFirebaseRegistrationByDeviceId(deviceId);
} }
@override @override
Future<FirebaseSubscription> registerNewToken(RegisterNewTokenRequest newTokenRequest) { Future<FirebaseRegistration> registerNewFirebaseRegistrationToken(RegisterNewTokenRequest newTokenRequest) {
return _fcmDatasource[DataSourceType.network]!.registerNewToken(newTokenRequest); return _fcmDatasource[DataSourceType.network]!.registerNewFirebaseRegistrationToken(newTokenRequest);
} }
@override @override
Future<FCMSubscription> getSubscription() async { Future<FirebaseRegistration> getStoredFirebaseRegistration() {
final fcmSubScription = await _fcmDatasource[DataSourceType.local]!.geSubscription(); return _fcmDatasource[DataSourceType.local]!.getStoredFirebaseRegistration();
return FCMSubscription(fcmSubScription.deviceId, fcmSubScription.subscriptionId);
} }
@override @override
Future<void> storeSubscription(FCMSubscription fcmSubscription) { Future<void> storeFirebaseRegistration(FirebaseRegistration firebaseRegistration) {
return _fcmDatasource[DataSourceType.local]!.storeSubscription(fcmSubscription.toFCMSubscriptionCache()); return _fcmDatasource[DataSourceType.local]!.storeFirebaseRegistration(firebaseRegistration);
} }
@override @override
Future<bool> destroySubscription(String subscriptionId) { Future<void> destroyFirebaseRegistration(FirebaseRegistrationId registrationId) {
return _fcmDatasource[DataSourceType.network]!.destroySubscription(subscriptionId); return _fcmDatasource[DataSourceType.network]!.destroyFirebaseRegistration(registrationId);
} }
@override @override
@@ -127,7 +127,7 @@ class FCMRepositoryImpl extends FCMRepository {
.where((presentationMailbox) => presentationMailbox.pushNotificationDeactivated) .where((presentationMailbox) => presentationMailbox.pushNotificationDeactivated)
.toList(); .toList();
log('FCMRepositoryImpl::getMailboxesNotPutNotifications():mailboxesCacheNotPutNotifications: $mailboxesCacheNotPutNotifications'); log('FCMRepositoryImpl::getMailboxesNotPutNotifications():mailboxesCacheNotPutNotifications: $mailboxesCacheNotPutNotifications');
if (mailboxesCacheNotPutNotifications.isNotEmpty && mailboxesCacheNotPutNotifications.length == FcmConstants.mailboxRuleAllowPushNotifications.length) { if (mailboxesCacheNotPutNotifications.isNotEmpty && mailboxesCacheNotPutNotifications.length == FcmConstants.mailboxRuleDoNotAllowPushNotifications.length) {
return mailboxesCacheNotPutNotifications; return mailboxesCacheNotPutNotifications;
} else { } else {
final mailboxResponse = await _mapMailboxDataSource[DataSourceType.network]!.getAllMailbox(session, accountId); final mailboxResponse = await _mapMailboxDataSource[DataSourceType.network]!.getAllMailbox(session, accountId);
@@ -217,4 +217,14 @@ class FCMRepositoryImpl extends FCMRepository {
throw NotFoundNewReceiveEmailException(); throw NotFoundNewReceiveEmailException();
} }
} }
@override
Future<void> updateFirebaseRegistrationToken(UpdateTokenExpiredTimeRequest expiredTimeRequest) {
return _fcmDatasource[DataSourceType.network]!.updateFirebaseRegistrationToken(expiredTimeRequest);
}
@override
Future<void> deleteFirebaseRegistrationCache() {
return _fcmDatasource[DataSourceType.local]!.deleteFirebaseRegistrationCache();
}
} }
@@ -6,12 +6,18 @@ class NotFoundStateToRefreshException implements Exception {}
class NotFoundEmailDeliveryStateException implements Exception {} class NotFoundEmailDeliveryStateException implements Exception {}
class NotFoundFirebaseSubscriptionException implements Exception {} class NotFoundFirebaseRegistrationForDeviceException implements Exception {}
class NotFoundSubscriptionException implements Exception {} class NotFoundFirebaseRegistrationCacheException implements Exception {}
class NotFoundEmailStateException implements Exception {} class NotFoundEmailStateException implements Exception {}
class NotFoundNewReceiveEmailException implements Exception {} class NotFoundNewReceiveEmailException implements Exception {}
class EmailStateNoChangeException implements Exception {} class EmailStateNoChangeException implements Exception {}
class NotFoundFirebaseRegistrationCreatedException implements Exception {}
class NotFoundFirebaseRegistrationUpdatedException implements Exception {}
class NotFoundFirebaseRegistrationDestroyedException implements Exception {}
@@ -0,0 +1,22 @@
import 'package:fcm/model/device_client_id.dart';
import 'package:fcm/model/fcm_token.dart';
import 'package:fcm/model/firebase_registration.dart';
import 'package:fcm/model/type_name.dart';
extension FirebaseRegistrationExtension on FirebaseRegistration {
FirebaseRegistration syncProperties({
DeviceClientId? newDeviceId,
FcmToken? newFcmToken,
List<TypeName>? newTypes,
}) {
return FirebaseRegistration(
id: id,
token: newFcmToken ?? token,
deviceClientId: newDeviceId ?? deviceClientId,
expires: expires,
types: newTypes ?? types
);
}
}
@@ -1,16 +0,0 @@
import 'package:fcm/model/device_client_id.dart';
import 'package:fcm/model/firebase_subscription.dart';
extension FirebaseSubscriptionExtension on FirebaseSubscription {
FirebaseSubscription fromDeviceId({DeviceClientId? newDeviceId}) {
return FirebaseSubscription(
id: id,
token: token,
deviceClientId: newDeviceId ?? deviceClientId,
expires: expires,
types: types
);
}
}
@@ -1,16 +0,0 @@
import 'package:equatable/equatable.dart';
class FCMSubscription with EquatableMixin {
final String deviceId;
final String subscriptionId;
FCMSubscription(this.deviceId, this.subscriptionId);
@override
List<Object?> get props => [
deviceId,
subscriptionId
];
}
@@ -1,18 +1,18 @@
import 'package:equatable/equatable.dart'; import 'package:equatable/equatable.dart';
import 'package:fcm/model/firebase_subscription.dart'; import 'package:fcm/model/firebase_registration.dart';
import 'package:jmap_dart_client/jmap/core/id.dart'; import 'package:jmap_dart_client/jmap/core/id.dart';
class RegisterNewTokenRequest with EquatableMixin { class RegisterNewTokenRequest with EquatableMixin {
final Id createRequestId; final Id createRequestId;
final FirebaseSubscription firebaseSubscription; final FirebaseRegistration firebaseRegistration;
RegisterNewTokenRequest(this.createRequestId, this.firebaseSubscription); RegisterNewTokenRequest(this.createRequestId, this.firebaseRegistration);
@override @override
List<Object?> get props => [ List<Object?> get props => [
createRequestId, createRequestId,
firebaseSubscription firebaseRegistration
]; ];
} }
@@ -0,0 +1,21 @@
import 'package:equatable/equatable.dart';
import 'package:fcm/model/firebase_registration_expired_time.dart';
import 'package:fcm/model/firebase_registration_id.dart';
class UpdateTokenExpiredTimeRequest with EquatableMixin {
final FirebaseRegistrationId firebaseRegistrationId;
final FirebaseRegistrationExpiredTime firebaseRegistrationExpiredTime;
UpdateTokenExpiredTimeRequest(
this.firebaseRegistrationId,
this.firebaseRegistrationExpiredTime
);
@override
List<Object?> get props => [
firebaseRegistrationId,
firebaseRegistrationExpiredTime
];
}
@@ -1,4 +1,6 @@
import 'package:fcm/model/firebase_subscription.dart'; import 'package:fcm/model/device_client_id.dart';
import 'package:fcm/model/firebase_registration.dart';
import 'package:fcm/model/firebase_registration_id.dart';
import 'package:fcm/model/type_name.dart'; import 'package:fcm/model/type_name.dart';
import 'package:jmap_dart_client/jmap/account_id.dart'; import 'package:jmap_dart_client/jmap/account_id.dart';
import 'package:jmap_dart_client/jmap/core/properties/properties.dart'; import 'package:jmap_dart_client/jmap/core/properties/properties.dart';
@@ -6,8 +8,8 @@ import 'package:jmap_dart_client/jmap/core/session/session.dart';
import 'package:jmap_dart_client/jmap/core/user_name.dart'; import 'package:jmap_dart_client/jmap/core/user_name.dart';
import 'package:jmap_dart_client/jmap/mail/email/email.dart'; import 'package:jmap_dart_client/jmap/mail/email/email.dart';
import 'package:model/mailbox/presentation_mailbox.dart'; import 'package:model/mailbox/presentation_mailbox.dart';
import 'package:tmail_ui_user/features/push_notification/domain/model/fcm_subscription.dart';
import 'package:tmail_ui_user/features/push_notification/domain/model/register_new_token_request.dart'; import 'package:tmail_ui_user/features/push_notification/domain/model/register_new_token_request.dart';
import 'package:tmail_ui_user/features/push_notification/domain/model/update_token_expired_time_request.dart';
import 'package:tmail_ui_user/features/thread/domain/model/email_response.dart'; import 'package:tmail_ui_user/features/thread/domain/model/email_response.dart';
import 'package:jmap_dart_client/jmap/core/state.dart' as jmap; import 'package:jmap_dart_client/jmap/core/state.dart' as jmap;
@@ -28,15 +30,19 @@ abstract class FCMRepository {
Future<void> deleteStateToRefresh(AccountId accountId, UserName userName, TypeName typeName); Future<void> deleteStateToRefresh(AccountId accountId, UserName userName, TypeName typeName);
Future<void> storeSubscription(FCMSubscription fcmSubscription); Future<void> storeFirebaseRegistration(FirebaseRegistration firebaseRegistration);
Future<FirebaseSubscription> getFirebaseSubscriptionByDeviceId(String deviceId); Future<FirebaseRegistration> getFirebaseRegistrationByDeviceId(DeviceClientId deviceId);
Future<FirebaseSubscription> registerNewToken(RegisterNewTokenRequest newTokenRequest); Future<FirebaseRegistration> registerNewFirebaseRegistrationToken(RegisterNewTokenRequest newTokenRequest);
Future<FCMSubscription> getSubscription(); Future<FirebaseRegistration> getStoredFirebaseRegistration();
Future<bool> destroySubscription(String subscriptionId); Future<void> deleteFirebaseRegistrationCache();
Future<void> destroyFirebaseRegistration(FirebaseRegistrationId registrationId);
Future<void> updateFirebaseRegistrationToken(UpdateTokenExpiredTimeRequest expiredTimeRequest);
Future<List<PresentationMailbox>> getMailboxesNotPutNotifications(Session session, AccountId accountId); Future<List<PresentationMailbox>> getMailboxesNotPutNotifications(Session session, AccountId accountId);
@@ -0,0 +1,12 @@
import 'package:core/presentation/state/failure.dart';
import 'package:core/presentation/state/success.dart';
class DeleteFirebaseRegistrationCacheLoading extends LoadingState {}
class DeleteFirebaseRegistrationCacheSuccess extends UIState {}
class DeleteFirebaseRegistrationCacheFailure extends FeatureFailure {
DeleteFirebaseRegistrationCacheFailure(dynamic exception) : super(exception: exception);
}
@@ -0,0 +1,11 @@
import 'package:core/presentation/state/failure.dart';
import 'package:core/presentation/state/success.dart';
class DestroyFirebaseRegistrationLoading extends LoadingState {}
class DestroyFirebaseRegistrationSuccess extends UIState {}
class DestroyFirebaseRegistrationFailure extends FeatureFailure {
DestroyFirebaseRegistrationFailure(dynamic exception) : super(exception: exception);
}
@@ -1,19 +0,0 @@
import 'package:core/presentation/state/failure.dart';
import 'package:core/presentation/state/success.dart';
class DestroySubscriptionLoading extends UIState {}
class DestroySubscriptionSuccess extends UIState {
final bool destroyedSubscription;
DestroySubscriptionSuccess(this.destroyedSubscription);
@override
List<Object> get props => [destroyedSubscription];
}
class DestroySubscriptionFailure extends FeatureFailure {
DestroySubscriptionFailure(dynamic exception) : super(exception: exception);
}
@@ -1,21 +0,0 @@
import 'package:core/presentation/state/failure.dart';
import 'package:core/presentation/state/success.dart';
import 'package:tmail_ui_user/features/push_notification/domain/model/fcm_subscription.dart';
class GetFCMSubscriptionLocalLoading extends UIState {}
class GetFCMSubscriptionLocalSuccess extends UIState {
final FCMSubscription fcmSubscription;
GetFCMSubscriptionLocalSuccess(this.fcmSubscription);
@override
List<Object> get props => [fcmSubscription];
}
class GetFCMSubscriptionLocalFailure extends FeatureFailure {
GetFCMSubscriptionLocalFailure(dynamic exception) : super(exception: exception);
}
@@ -0,0 +1,27 @@
import 'package:core/presentation/state/failure.dart';
import 'package:core/presentation/state/success.dart';
import 'package:fcm/model/fcm_token.dart';
import 'package:fcm/model/firebase_registration.dart';
class GetFirebaseRegistrationByDeviceIdLoading extends LoadingState {}
class GetFirebaseRegistrationByDeviceIdSuccess extends UIState {
final FirebaseRegistration firebaseRegistration;
final FcmToken? newFcmToken;
GetFirebaseRegistrationByDeviceIdSuccess(this.firebaseRegistration, this.newFcmToken);
@override
List<Object?> get props => [firebaseRegistration, newFcmToken];
}
class GetFirebaseRegistrationByDeviceIdFailure extends FeatureFailure {
final FcmToken? newFcmToken;
GetFirebaseRegistrationByDeviceIdFailure(dynamic exception, this.newFcmToken) : super(exception: exception);
@override
List<Object?> get props => [newFcmToken, ...super.props];
}
@@ -1,21 +0,0 @@
import 'package:core/presentation/state/failure.dart';
import 'package:core/presentation/state/success.dart';
import 'package:fcm/model/firebase_subscription.dart';
class GetFirebaseSubscriptionLoading extends UIState {}
class GetFirebaseSubscriptionSuccess extends UIState {
final FirebaseSubscription firebaseSubscription;
GetFirebaseSubscriptionSuccess(this.firebaseSubscription);
@override
List<Object> get props => [firebaseSubscription];
}
class GetFirebaseSubscriptionFailure extends FeatureFailure {
GetFirebaseSubscriptionFailure(dynamic exception) : super(exception: exception);
}
@@ -0,0 +1,21 @@
import 'package:core/presentation/state/failure.dart';
import 'package:core/presentation/state/success.dart';
import 'package:fcm/model/firebase_registration.dart';
class GetStoredFirebaseRegistrationLoading extends LoadingState {}
class GetStoredFirebaseRegistrationSuccess extends UIState {
final FirebaseRegistration firebaseRegistration;
GetStoredFirebaseRegistrationSuccess(this.firebaseRegistration);
@override
List<Object> get props => [firebaseRegistration];
}
class GetStoredFirebaseRegistrationFailure extends FeatureFailure {
GetStoredFirebaseRegistrationFailure(dynamic exception) : super(exception: exception);
}
@@ -0,0 +1,21 @@
import 'package:core/presentation/state/failure.dart';
import 'package:core/presentation/state/success.dart';
import 'package:fcm/model/firebase_registration.dart';
class RegisterNewFirebaseRegistrationTokenLoading extends LoadingState {}
class RegisterNewFirebaseRegistrationTokenSuccess extends UIState {
final FirebaseRegistration firebaseRegistration;
RegisterNewFirebaseRegistrationTokenSuccess(this.firebaseRegistration);
@override
List<Object> get props => [firebaseRegistration];
}
class RegisterNewFirebaseRegistrationTokenFailure extends FeatureFailure {
RegisterNewFirebaseRegistrationTokenFailure(dynamic exception) : super(exception: exception);
}
@@ -1,21 +0,0 @@
import 'package:core/presentation/state/failure.dart';
import 'package:core/presentation/state/success.dart';
import 'package:fcm/model/firebase_subscription.dart';
class RegisterNewTokenLoading extends UIState {}
class RegisterNewTokenSuccess extends UIState {
final FirebaseSubscription firebaseSubscription;
RegisterNewTokenSuccess(this.firebaseSubscription);
@override
List<Object> get props => [firebaseSubscription];
}
class RegisterNewTokenFailure extends FeatureFailure {
RegisterNewTokenFailure(dynamic exception) : super(exception: exception);
}
@@ -0,0 +1,12 @@
import 'package:core/presentation/state/failure.dart';
import 'package:core/presentation/state/success.dart';
class StoreFirebaseRegistrationLoading extends LoadingState {}
class StoreFirebaseRegistrationSuccess extends UIState {}
class StoreFirebaseRegistrationFailure extends FeatureFailure {
StoreFirebaseRegistrationFailure(dynamic exception) : super(exception: exception);
}
@@ -1,12 +0,0 @@
import 'package:core/presentation/state/failure.dart';
import 'package:core/presentation/state/success.dart';
class StoreSubscriptionLoading extends UIState {}
class StoreSubscriptionSuccess extends UIState {}
class StoreSubscriptionFailure extends FeatureFailure {
StoreSubscriptionFailure(dynamic exception) : super(exception: exception);
}
@@ -0,0 +1,12 @@
import 'package:core/presentation/state/failure.dart';
import 'package:core/presentation/state/success.dart';
class UpdateFirebaseRegistrationTokenLoading extends LoadingState {}
class UpdateFirebaseRegistrationTokenSuccess extends UIState {}
class UpdateFirebaseRegistrationTokenFailure extends FeatureFailure {
UpdateFirebaseRegistrationTokenFailure(dynamic exception) : super(exception: exception);
}
@@ -0,0 +1,21 @@
import 'package:core/presentation/state/failure.dart';
import 'package:core/presentation/state/success.dart';
import 'package:dartz/dartz.dart';
import 'package:tmail_ui_user/features/push_notification/domain/repository/fcm_repository.dart';
import 'package:tmail_ui_user/features/push_notification/domain/state/delete_firebase_registration_cache_state.dart';
class DeleteFirebaseRegistrationCacheInteractor {
final FCMRepository _fcmRepository;
DeleteFirebaseRegistrationCacheInteractor(this._fcmRepository);
Stream<Either<Failure, Success>> execute() async* {
try {
yield Right<Failure, Success>(DeleteFirebaseRegistrationCacheLoading());
await _fcmRepository.getStoredFirebaseRegistration();
yield Right<Failure, Success>(DeleteFirebaseRegistrationCacheSuccess());
} catch (e) {
yield Left<Failure, Success>(DeleteFirebaseRegistrationCacheFailure(e));
}
}
}
@@ -0,0 +1,23 @@
import 'package:core/presentation/state/failure.dart';
import 'package:core/presentation/state/success.dart';
import 'package:dartz/dartz.dart';
import 'package:fcm/model/firebase_registration_id.dart';
import 'package:tmail_ui_user/features/push_notification/domain/repository/fcm_repository.dart';
import 'package:tmail_ui_user/features/push_notification/domain/state/destroy_firebase_registration_state.dart';
class DestroyFirebaseRegistrationInteractor {
final FCMRepository _fcmRepository;
DestroyFirebaseRegistrationInteractor(this._fcmRepository);
Stream<Either<Failure, Success>> execute(FirebaseRegistrationId registrationId) async* {
try {
yield Right<Failure, Success>(DestroyFirebaseRegistrationLoading());
await _fcmRepository.destroyFirebaseRegistration(registrationId);
yield Right<Failure, Success>(DestroyFirebaseRegistrationSuccess());
} catch (e) {
yield Left<Failure, Success>(DestroyFirebaseRegistrationFailure(e));
}
}
}
@@ -1,22 +0,0 @@
import 'package:core/presentation/state/failure.dart';
import 'package:core/presentation/state/success.dart';
import 'package:dartz/dartz.dart';
import 'package:tmail_ui_user/features/push_notification/domain/repository/fcm_repository.dart';
import 'package:tmail_ui_user/features/push_notification/domain/state/destroy_subscription_state.dart';
class DestroySubscriptionInteractor {
final FCMRepository _fcmRepository;
DestroySubscriptionInteractor(this._fcmRepository);
Stream<Either<Failure, Success>> execute(String subscriptionId) async* {
try {
yield Right<Failure, Success>(DestroySubscriptionLoading());
final destroyedSubscription = await _fcmRepository.destroySubscription(subscriptionId);
yield Right<Failure, Success>(DestroySubscriptionSuccess(destroyedSubscription));
} catch (e) {
yield Left<Failure, Success>(DestroySubscriptionFailure(e));
}
}
}
@@ -1,21 +0,0 @@
import 'package:core/presentation/state/failure.dart';
import 'package:core/presentation/state/success.dart';
import 'package:dartz/dartz.dart';
import 'package:tmail_ui_user/features/push_notification/domain/repository/fcm_repository.dart';
import 'package:tmail_ui_user/features/push_notification/domain/state/get_fcm_subscription_local.dart';
class GetFCMSubscriptionLocalInteractor {
final FCMRepository _fcmRepository;
GetFCMSubscriptionLocalInteractor(this._fcmRepository);
Stream<Either<Failure, Success>> execute() async* {
try {
yield Right<Failure, Success>(GetFCMSubscriptionLocalLoading());
final subscription = await _fcmRepository.getSubscription();
yield Right<Failure, Success>(GetFCMSubscriptionLocalSuccess(subscription));
} catch (e) {
yield Left<Failure, Success>(GetFCMSubscriptionLocalFailure(e));
}
}
}
@@ -0,0 +1,25 @@
import 'package:core/presentation/state/failure.dart';
import 'package:core/presentation/state/success.dart';
import 'package:dartz/dartz.dart';
import 'package:fcm/model/device_client_id.dart';
import 'package:fcm/model/fcm_token.dart';
import 'package:tmail_ui_user/features/push_notification/domain/repository/fcm_repository.dart';
import 'package:tmail_ui_user/features/push_notification/domain/state/get_firebase_registration_by_device_id_state.dart';
class GetFirebaseRegistrationByDeviceIdInteractor {
final FCMRepository _fcmRepository;
GetFirebaseRegistrationByDeviceIdInteractor(this._fcmRepository);
Stream<Either<Failure, Success>> execute({required DeviceClientId deviceClientId, FcmToken? newFcmToken}) async* {
try {
yield Right<Failure, Success>(GetFirebaseRegistrationByDeviceIdLoading());
final firebaseRegistration = await _fcmRepository.getFirebaseRegistrationByDeviceId(deviceClientId);
yield Right<Failure, Success>(GetFirebaseRegistrationByDeviceIdSuccess(firebaseRegistration, newFcmToken));
} catch (e) {
yield Left<Failure, Success>(GetFirebaseRegistrationByDeviceIdFailure(e, newFcmToken));
}
}
}
@@ -1,23 +0,0 @@
import 'package:core/presentation/state/failure.dart';
import 'package:core/presentation/state/success.dart';
import 'package:dartz/dartz.dart';
import 'package:tmail_ui_user/features/push_notification/domain/repository/fcm_repository.dart';
import 'package:tmail_ui_user/features/push_notification/domain/state/get_firebase_subscription_state.dart';
class GetFirebaseSubscriptionInteractor {
final FCMRepository _fcmRepository;
GetFirebaseSubscriptionInteractor(this._fcmRepository);
Stream<Either<Failure, Success>> execute(String deviceId) async* {
try {
yield Right<Failure, Success>(GetFirebaseSubscriptionLoading());
final firebaseSubscription = await _fcmRepository.getFirebaseSubscriptionByDeviceId(deviceId);
yield Right<Failure, Success>(GetFirebaseSubscriptionSuccess(firebaseSubscription));
} catch (e) {
yield Left<Failure, Success>(GetFirebaseSubscriptionFailure(e));
}
}
}
@@ -0,0 +1,21 @@
import 'package:core/presentation/state/failure.dart';
import 'package:core/presentation/state/success.dart';
import 'package:dartz/dartz.dart';
import 'package:tmail_ui_user/features/push_notification/domain/repository/fcm_repository.dart';
import 'package:tmail_ui_user/features/push_notification/domain/state/get_stored_firebase_registration_state.dart';
class GetStoredFirebaseRegistrationInteractor {
final FCMRepository _fcmRepository;
GetStoredFirebaseRegistrationInteractor(this._fcmRepository);
Stream<Either<Failure, Success>> execute() async* {
try {
yield Right<Failure, Success>(GetStoredFirebaseRegistrationLoading());
final registration = await _fcmRepository.getStoredFirebaseRegistration();
yield Right<Failure, Success>(GetStoredFirebaseRegistrationSuccess(registration));
} catch (e) {
yield Left<Failure, Success>(GetStoredFirebaseRegistrationFailure(e));
}
}
}
@@ -4,21 +4,21 @@ import 'package:core/presentation/state/success.dart';
import 'package:dartz/dartz.dart'; import 'package:dartz/dartz.dart';
import 'package:tmail_ui_user/features/push_notification/domain/model/register_new_token_request.dart'; import 'package:tmail_ui_user/features/push_notification/domain/model/register_new_token_request.dart';
import 'package:tmail_ui_user/features/push_notification/domain/repository/fcm_repository.dart'; import 'package:tmail_ui_user/features/push_notification/domain/repository/fcm_repository.dart';
import 'package:tmail_ui_user/features/push_notification/domain/state/register_new_token_state.dart'; import 'package:tmail_ui_user/features/push_notification/domain/state/register_new_firebase_registration_token_state.dart';
class RegisterNewTokenInteractor { class RegisterNewFirebaseRegistrationTokenInteractor {
final FCMRepository _fcmRepository; final FCMRepository _fcmRepository;
RegisterNewTokenInteractor(this._fcmRepository); RegisterNewFirebaseRegistrationTokenInteractor(this._fcmRepository);
Stream<Either<Failure, Success>> execute(RegisterNewTokenRequest newTokenRequest) async* { Stream<Either<Failure, Success>> execute(RegisterNewTokenRequest newTokenRequest) async* {
try { try {
yield Right<Failure, Success>(RegisterNewTokenLoading()); yield Right<Failure, Success>(RegisterNewFirebaseRegistrationTokenLoading());
final firebaseSubscription = await _fcmRepository.registerNewToken(newTokenRequest); final firebaseRegistration = await _fcmRepository.registerNewFirebaseRegistrationToken(newTokenRequest);
yield Right<Failure, Success>(RegisterNewTokenSuccess(firebaseSubscription)); yield Right<Failure, Success>(RegisterNewFirebaseRegistrationTokenSuccess(firebaseRegistration));
} catch (e) { } catch (e) {
yield Left<Failure, Success>(RegisterNewTokenFailure(e)); yield Left<Failure, Success>(RegisterNewFirebaseRegistrationTokenFailure(e));
} }
} }
} }
@@ -0,0 +1,22 @@
import 'package:core/presentation/state/failure.dart';
import 'package:core/presentation/state/success.dart';
import 'package:dartz/dartz.dart';
import 'package:fcm/model/firebase_registration.dart';
import 'package:tmail_ui_user/features/push_notification/domain/repository/fcm_repository.dart';
import 'package:tmail_ui_user/features/push_notification/domain/state/store_firebase_registration_state.dart';
class StoreFirebaseRegistrationInteractor {
final FCMRepository _fcmRepository;
StoreFirebaseRegistrationInteractor(this._fcmRepository);
Stream<Either<Failure, Success>> execute(FirebaseRegistration firebaseRegistration) async* {
try {
yield Right<Failure, Success>(StoreFirebaseRegistrationLoading());
await _fcmRepository.storeFirebaseRegistration(firebaseRegistration);
yield Right<Failure, Success>(StoreFirebaseRegistrationSuccess());
} catch (e) {
yield Left<Failure, Success>(StoreFirebaseRegistrationFailure(e));
}
}
}
@@ -1,22 +0,0 @@
import 'package:core/presentation/state/failure.dart';
import 'package:core/presentation/state/success.dart';
import 'package:dartz/dartz.dart';
import 'package:tmail_ui_user/features/push_notification/domain/model/fcm_subscription.dart';
import 'package:tmail_ui_user/features/push_notification/domain/repository/fcm_repository.dart';
import 'package:tmail_ui_user/features/push_notification/domain/state/store_subscription_state.dart';
class StoreSubscriptionInteractor {
final FCMRepository _fcmRepository;
StoreSubscriptionInteractor(this._fcmRepository);
Stream<Either<Failure, Success>> execute(FCMSubscription fcmSubscription) async* {
try {
yield Right<Failure, Success>(StoreSubscriptionLoading());
await _fcmRepository.storeSubscription(fcmSubscription);
yield Right<Failure, Success>(StoreSubscriptionSuccess());
} catch (e) {
yield Left<Failure, Success>(StoreSubscriptionFailure(e));
}
}
}
@@ -0,0 +1,24 @@
import 'package:core/presentation/state/failure.dart';
import 'package:core/presentation/state/success.dart';
import 'package:dartz/dartz.dart';
import 'package:tmail_ui_user/features/push_notification/domain/model/update_token_expired_time_request.dart';
import 'package:tmail_ui_user/features/push_notification/domain/repository/fcm_repository.dart';
import 'package:tmail_ui_user/features/push_notification/domain/state/update_firebase_registration_token_state.dart';
class UpdateFirebaseRegistrationTokenInteractor {
final FCMRepository _fcmRepository;
UpdateFirebaseRegistrationTokenInteractor(this._fcmRepository);
Stream<Either<Failure, Success>> execute(UpdateTokenExpiredTimeRequest updateTokenExpiredTimeRequest) async* {
try {
yield Right<Failure, Success>(UpdateFirebaseRegistrationTokenLoading());
await _fcmRepository.updateFirebaseRegistrationToken(updateTokenExpiredTimeRequest);
yield Right<Failure, Success>(UpdateFirebaseRegistrationTokenSuccess());
} catch (e) {
yield Left<Failure, Success>(UpdateFirebaseRegistrationTokenFailure(e));
}
}
}
@@ -3,12 +3,13 @@ import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart';
import 'package:model/mailbox/presentation_mailbox.dart'; import 'package:model/mailbox/presentation_mailbox.dart';
class FcmConstants { class FcmConstants {
static final List<Role> mailboxRuleDoNotAllowPushNotifications = [
static final List<Role> mailboxRuleAllowPushNotifications = [
PresentationMailbox.roleDrafts, PresentationMailbox.roleDrafts,
PresentationMailbox.roleSent, PresentationMailbox.roleSent,
PresentationMailbox.roleOutbox, PresentationMailbox.roleOutbox,
PresentationMailbox.roleSpam, PresentationMailbox.roleSpam,
PresentationMailbox.roleTrash PresentationMailbox.roleTrash
]; ];
static const String firebaseRegistrationExpiredTimeProperty = 'expires';
} }
@@ -35,21 +35,23 @@ import 'package:tmail_ui_user/features/push_notification/data/network/fcm_api.da
import 'package:tmail_ui_user/features/push_notification/data/repository/fcm_repository_impl.dart'; import 'package:tmail_ui_user/features/push_notification/data/repository/fcm_repository_impl.dart';
import 'package:tmail_ui_user/features/push_notification/domain/repository/fcm_repository.dart'; import 'package:tmail_ui_user/features/push_notification/domain/repository/fcm_repository.dart';
import 'package:tmail_ui_user/features/push_notification/domain/usecases/delete_email_state_to_refresh_interactor.dart'; import 'package:tmail_ui_user/features/push_notification/domain/usecases/delete_email_state_to_refresh_interactor.dart';
import 'package:tmail_ui_user/features/push_notification/domain/usecases/destroy_subscription_interactor.dart'; import 'package:tmail_ui_user/features/push_notification/domain/usecases/delete_firebase_registration_cache_interactor.dart';
import 'package:tmail_ui_user/features/push_notification/domain/usecases/destroy_firebase_registration_interactor.dart';
import 'package:tmail_ui_user/features/push_notification/domain/usecases/get_email_changes_to_push_notification_interactor.dart'; import 'package:tmail_ui_user/features/push_notification/domain/usecases/get_email_changes_to_push_notification_interactor.dart';
import 'package:tmail_ui_user/features/push_notification/domain/usecases/get_email_changes_to_remove_notification_interactor.dart'; import 'package:tmail_ui_user/features/push_notification/domain/usecases/get_email_changes_to_remove_notification_interactor.dart';
import 'package:tmail_ui_user/features/push_notification/domain/usecases/get_email_state_to_refresh_interactor.dart'; import 'package:tmail_ui_user/features/push_notification/domain/usecases/get_email_state_to_refresh_interactor.dart';
import 'package:tmail_ui_user/features/push_notification/domain/usecases/get_fcm_subscription_local_interactor.dart'; import 'package:tmail_ui_user/features/push_notification/domain/usecases/get_firebase_registration_by_device_id_interactor.dart';
import 'package:tmail_ui_user/features/push_notification/domain/usecases/get_firebase_subscription_interactor.dart';
import 'package:tmail_ui_user/features/push_notification/domain/usecases/get_mailbox_state_to_refresh_interactor.dart'; import 'package:tmail_ui_user/features/push_notification/domain/usecases/get_mailbox_state_to_refresh_interactor.dart';
import 'package:tmail_ui_user/features/push_notification/domain/usecases/get_mailboxes_not_put_notifications_interactor.dart'; import 'package:tmail_ui_user/features/push_notification/domain/usecases/get_mailboxes_not_put_notifications_interactor.dart';
import 'package:tmail_ui_user/features/push_notification/domain/usecases/get_new_receive_email_from_notification_interactor.dart'; import 'package:tmail_ui_user/features/push_notification/domain/usecases/get_new_receive_email_from_notification_interactor.dart';
import 'package:tmail_ui_user/features/push_notification/domain/usecases/get_stored_email_delivery_state_interactor.dart'; import 'package:tmail_ui_user/features/push_notification/domain/usecases/get_stored_email_delivery_state_interactor.dart';
import 'package:tmail_ui_user/features/push_notification/domain/usecases/register_new_token_interactor.dart'; import 'package:tmail_ui_user/features/push_notification/domain/usecases/get_stored_firebase_registration_interactor.dart';
import 'package:tmail_ui_user/features/push_notification/domain/usecases/register_new_firebase_registration_token_interactor.dart';
import 'package:tmail_ui_user/features/push_notification/domain/usecases/store_email_delivery_state_interactor.dart'; import 'package:tmail_ui_user/features/push_notification/domain/usecases/store_email_delivery_state_interactor.dart';
import 'package:tmail_ui_user/features/push_notification/domain/usecases/store_email_state_to_refresh_interactor.dart'; import 'package:tmail_ui_user/features/push_notification/domain/usecases/store_email_state_to_refresh_interactor.dart';
import 'package:tmail_ui_user/features/push_notification/domain/usecases/store_firebase_registration_interator.dart';
import 'package:tmail_ui_user/features/push_notification/domain/usecases/store_mailbox_state_to_refresh_interactor.dart'; import 'package:tmail_ui_user/features/push_notification/domain/usecases/store_mailbox_state_to_refresh_interactor.dart';
import 'package:tmail_ui_user/features/push_notification/domain/usecases/store_subscription_interator.dart'; import 'package:tmail_ui_user/features/push_notification/domain/usecases/update_firebase_registration_token_interactor.dart';
import 'package:tmail_ui_user/features/thread/data/datasource/thread_datasource.dart'; import 'package:tmail_ui_user/features/thread/data/datasource/thread_datasource.dart';
import 'package:tmail_ui_user/features/thread/data/datasource_impl/thread_datasource_impl.dart'; import 'package:tmail_ui_user/features/thread/data/datasource_impl/thread_datasource_impl.dart';
import 'package:tmail_ui_user/features/thread/data/local/email_cache_manager.dart'; import 'package:tmail_ui_user/features/thread/data/local/email_cache_manager.dart';
@@ -123,13 +125,16 @@ class FcmInteractorBindings extends InteractorsBindings {
Get.lazyPut(() => StoreEmailStateToRefreshInteractor(Get.find<FCMRepositoryImpl>())); Get.lazyPut(() => StoreEmailStateToRefreshInteractor(Get.find<FCMRepositoryImpl>()));
Get.lazyPut(() => GetEmailStateToRefreshInteractor(Get.find<FCMRepositoryImpl>())); Get.lazyPut(() => GetEmailStateToRefreshInteractor(Get.find<FCMRepositoryImpl>()));
Get.lazyPut(() => DeleteEmailStateToRefreshInteractor(Get.find<FCMRepositoryImpl>())); Get.lazyPut(() => DeleteEmailStateToRefreshInteractor(Get.find<FCMRepositoryImpl>()));
Get.lazyPut(() => GetFirebaseSubscriptionInteractor(Get.find<FCMRepositoryImpl>())); Get.lazyPut(() => GetFirebaseRegistrationByDeviceIdInteractor(Get.find<FCMRepositoryImpl>()));
Get.lazyPut(() => RegisterNewTokenInteractor(Get.find<FCMRepositoryImpl>())); Get.lazyPut(() => RegisterNewFirebaseRegistrationTokenInteractor(Get.find<FCMRepositoryImpl>()));
Get.lazyPut(() => StoreMailboxStateToRefreshInteractor(Get.find<FCMRepositoryImpl>())); Get.lazyPut(() => StoreMailboxStateToRefreshInteractor(Get.find<FCMRepositoryImpl>()));
Get.lazyPut(() => GetMailboxStateToRefreshInteractor(Get.find<FCMRepositoryImpl>())); Get.lazyPut(() => GetMailboxStateToRefreshInteractor(Get.find<FCMRepositoryImpl>()));
Get.lazyPut(() => StoreSubscriptionInteractor(Get.find<FCMRepositoryImpl>())); Get.lazyPut(() => StoreFirebaseRegistrationInteractor(Get.find<FCMRepositoryImpl>()));
Get.lazyPut(() => GetFCMSubscriptionLocalInteractor(Get.find<FCMRepositoryImpl>())); Get.lazyPut(() => GetStoredFirebaseRegistrationInteractor(Get.find<FCMRepositoryImpl>()));
Get.lazyPut(() => DestroySubscriptionInteractor(Get.find<FCMRepositoryImpl>())); Get.lazyPut(() => DestroyFirebaseRegistrationInteractor(Get.find<FCMRepositoryImpl>()));
Get.lazyPut(() => UpdateFirebaseRegistrationTokenInteractor(Get.find<FCMRepositoryImpl>()));
Get.lazyPut(() => DeleteFirebaseRegistrationCacheInteractor(Get.find<FCMRepositoryImpl>()));
Get.lazyPut(() => DestroyFirebaseRegistrationInteractor(Get.find<FCMRepositoryImpl>()));
Get.lazyPut(() => GetMailboxesNotPutNotificationsInteractor(Get.find<FCMRepositoryImpl>())); Get.lazyPut(() => GetMailboxesNotPutNotificationsInteractor(Get.find<FCMRepositoryImpl>()));
Get.lazyPut(() => GetNewReceiveEmailFromNotificationInteractor( Get.lazyPut(() => GetNewReceiveEmailFromNotificationInteractor(
Get.find<FCMRepositoryImpl>(), Get.find<FCMRepositoryImpl>(),
@@ -6,7 +6,7 @@ import 'package:tmail_ui_user/features/push_notification/presentation/services/f
class FcmConfiguration { class FcmConfiguration {
static void initialize() async { static Future<void> initialize() async {
await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform); await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);
await FcmService.instance.recreateStreamController(); await FcmService.instance.recreateStreamController();
_initMessageListener(); _initMessageListener();
@@ -95,7 +95,7 @@ class FcmMessageController extends FcmBaseController {
Future<void> listenTokenStream() { Future<void> listenTokenStream() {
FcmService.instance.fcmTokenStream FcmService.instance.fcmTokenStream
.debounceTime(const Duration(milliseconds: FcmService.durationRefreshToken)) .debounceTime(const Duration(milliseconds: FcmService.durationRefreshToken))
.listen(FcmTokenController.instance.handleTokenAction); .listen(FcmTokenController.instance.onFcmTokenChanged);
return Future.value(); return Future.value();
} }
@@ -199,23 +199,18 @@ class FcmMessageController extends FcmBaseController {
FcmInteractorBindings().dependencies(); FcmInteractorBindings().dependencies();
}); });
await _getInteractorBindings(); _getInteractorBindings();
await _newEmailCacheManager?.closeNewEmailHiveCacheBox(); await _newEmailCacheManager?.closeNewEmailHiveCacheBox();
} }
Future<void> _getInteractorBindings() { void _getInteractorBindings() {
try { _getAuthenticatedAccountInteractor = getBinding<GetAuthenticatedAccountInteractor>();
_getAuthenticatedAccountInteractor = getBinding<GetAuthenticatedAccountInteractor>(); _dynamicUrlInterceptors = getBinding<DynamicUrlInterceptors>();
_dynamicUrlInterceptors = getBinding<DynamicUrlInterceptors>(); _authorizationInterceptors = getBinding<AuthorizationInterceptors>();
_authorizationInterceptors = getBinding<AuthorizationInterceptors>(); _getSessionInteractor = getBinding<GetSessionInteractor>();
_getSessionInteractor = getBinding<GetSessionInteractor>(); _newEmailCacheManager = getBinding<NewEmailCacheManager>();
_newEmailCacheManager = getBinding<NewEmailCacheManager>(); FcmTokenController.instance.initialize();
FcmTokenController.instance.initialize();
} catch (e) {
logError('FcmMessageController::_getBindings(): ${e.toString()}');
}
return Future.value(null);
} }
void _getAuthenticatedAccount() { void _getAuthenticatedAccount() {
@@ -4,21 +4,22 @@ import 'package:core/presentation/state/failure.dart';
import 'package:core/presentation/state/success.dart'; import 'package:core/presentation/state/success.dart';
import 'package:core/utils/app_logger.dart'; import 'package:core/utils/app_logger.dart';
import 'package:fcm/model/device_client_id.dart'; import 'package:fcm/model/device_client_id.dart';
import 'package:fcm/model/firebase_expired_time.dart'; import 'package:fcm/model/firebase_registration_expired_time.dart';
import 'package:fcm/model/firebase_subscription.dart'; import 'package:fcm/model/firebase_registration.dart';
import 'package:fcm/model/firebase_token.dart'; import 'package:fcm/model/fcm_token.dart';
import 'package:fcm/model/type_name.dart';
import 'package:jmap_dart_client/jmap/core/id.dart'; import 'package:jmap_dart_client/jmap/core/id.dart';
import 'package:tmail_ui_user/features/manage_account/presentation/extensions/datetime_extension.dart'; import 'package:jmap_dart_client/jmap/core/utc_date.dart';
import 'package:tmail_ui_user/features/push_notification/domain/model/fcm_subscription.dart';
import 'package:tmail_ui_user/features/push_notification/domain/model/register_new_token_request.dart'; import 'package:tmail_ui_user/features/push_notification/domain/model/register_new_token_request.dart';
import 'package:tmail_ui_user/features/push_notification/domain/state/get_fcm_subscription_local.dart'; import 'package:tmail_ui_user/features/push_notification/domain/model/update_token_expired_time_request.dart';
import 'package:tmail_ui_user/features/push_notification/domain/state/get_firebase_subscription_state.dart'; import 'package:tmail_ui_user/features/push_notification/domain/state/get_firebase_registration_by_device_id_state.dart';
import 'package:tmail_ui_user/features/push_notification/domain/state/register_new_token_state.dart'; import 'package:tmail_ui_user/features/push_notification/domain/state/get_stored_firebase_registration_state.dart';
import 'package:tmail_ui_user/features/push_notification/domain/usecases/get_fcm_subscription_local_interactor.dart'; import 'package:tmail_ui_user/features/push_notification/domain/state/register_new_firebase_registration_token_state.dart';
import 'package:tmail_ui_user/features/push_notification/domain/usecases/get_firebase_subscription_interactor.dart'; import 'package:tmail_ui_user/features/push_notification/domain/usecases/delete_firebase_registration_cache_interactor.dart';
import 'package:tmail_ui_user/features/push_notification/domain/usecases/register_new_token_interactor.dart'; import 'package:tmail_ui_user/features/push_notification/domain/usecases/get_firebase_registration_by_device_id_interactor.dart';
import 'package:tmail_ui_user/features/push_notification/domain/usecases/store_subscription_interator.dart'; import 'package:tmail_ui_user/features/push_notification/domain/usecases/get_stored_firebase_registration_interactor.dart';
import 'package:tmail_ui_user/features/push_notification/domain/usecases/register_new_firebase_registration_token_interactor.dart';
import 'package:tmail_ui_user/features/push_notification/domain/usecases/store_firebase_registration_interator.dart';
import 'package:tmail_ui_user/features/push_notification/domain/usecases/update_firebase_registration_token_interactor.dart';
import 'package:tmail_ui_user/features/push_notification/presentation/controller/fcm_base_controller.dart'; import 'package:tmail_ui_user/features/push_notification/presentation/controller/fcm_base_controller.dart';
import 'package:tmail_ui_user/features/push_notification/presentation/utils/fcm_utils.dart'; import 'package:tmail_ui_user/features/push_notification/presentation/utils/fcm_utils.dart';
import 'package:tmail_ui_user/main/routes/route_navigation.dart'; import 'package:tmail_ui_user/main/routes/route_navigation.dart';
@@ -35,146 +36,137 @@ class FcmTokenController extends FcmBaseController {
static const int limitedTimeToExpire = 3; static const int limitedTimeToExpire = 3;
static const int extensionTimeExpire = 7; static const int extensionTimeExpire = 7;
StoreSubscriptionInteractor? _storeSubscriptionInteractor; StoreFirebaseRegistrationInteractor? _storeFirebaseRegistrationInteractor;
GetFirebaseSubscriptionInteractor? _getFirebaseSubscriptionInteractor; GetFirebaseRegistrationByDeviceIdInteractor? _getFirebaseRegistrationByDeviceIdInteractor;
RegisterNewTokenInteractor? _registerNewTokenInteractor; RegisterNewFirebaseRegistrationTokenInteractor? _registerNewFirebaseRegistrationTokenInteractor;
GetFCMSubscriptionLocalInteractor? _getFCMSubscriptionLocalInteractor; GetStoredFirebaseRegistrationInteractor? _getStoredFirebaseRegistrationInteractor;
UpdateFirebaseRegistrationTokenInteractor? _updateFirebaseRegistrationTokenInteractor;
FirebaseToken? _fcmToken; DeleteFirebaseRegistrationCacheInteractor? _deleteFirebaseRegistrationCacheInteractor;
DeviceClientId? _deviceClientId;
void initialize() { void initialize() {
try { _storeFirebaseRegistrationInteractor = getBinding<StoreFirebaseRegistrationInteractor>();
_storeSubscriptionInteractor = getBinding<StoreSubscriptionInteractor>(); _getFirebaseRegistrationByDeviceIdInteractor = getBinding<GetFirebaseRegistrationByDeviceIdInteractor>();
_getFirebaseSubscriptionInteractor = getBinding<GetFirebaseSubscriptionInteractor>(); _registerNewFirebaseRegistrationTokenInteractor = getBinding<RegisterNewFirebaseRegistrationTokenInteractor>();
_registerNewTokenInteractor = getBinding<RegisterNewTokenInteractor>(); _getStoredFirebaseRegistrationInteractor = getBinding<GetStoredFirebaseRegistrationInteractor>();
_getFCMSubscriptionLocalInteractor = getBinding<GetFCMSubscriptionLocalInteractor>(); _updateFirebaseRegistrationTokenInteractor = getBinding<UpdateFirebaseRegistrationTokenInteractor>();
} catch (e) { _deleteFirebaseRegistrationCacheInteractor = getBinding<DeleteFirebaseRegistrationCacheInteractor>();
logError('FcmTokenController::initialize(): ${e.toString()}');
}
} }
void handleTokenAction(String? token) { void onFcmTokenChanged(String? newToken) {
log('FcmTokenController::handleTokenAction():token: $token'); log('FcmTokenController::onFcmTokenChanged():newToken: $newToken');
if (token != null) { if (newToken != null) {
_fcmToken = FirebaseToken(token); _getFirebaseRegistrationFromServer(
final deviceId = FcmUtils.instance.hashTokenToDeviceId(token); newFcmToken: FcmToken(newToken),
_deviceClientId = DeviceClientId(deviceId); deviceClientId: DeviceClientId(FcmUtils.instance.hashTokenToDeviceId(newToken))
log('FcmTokenController::handleTokenAction(): fcmToken: $_fcmToken'); );
log('FcmTokenController::handleTokenAction(): deviceId: $deviceId');
_getFcmTokenFromBackend(deviceId);
} else { } else {
_getFCMSubscriptionLocalAction(); _getStoredFirebaseRegistrationFromCache();
} }
} }
void _getFcmTokenFromBackend(String deviceId) { void _getFirebaseRegistrationFromServer({
if (_getFirebaseSubscriptionInteractor != null) { required DeviceClientId deviceClientId,
consumeState(_getFirebaseSubscriptionInteractor!.execute(deviceId)); FcmToken? newFcmToken
}) {
if (_getFirebaseRegistrationByDeviceIdInteractor != null) {
consumeState(
_getFirebaseRegistrationByDeviceIdInteractor!.execute(
deviceClientId: deviceClientId,
newFcmToken: newFcmToken
)
);
} else if (newFcmToken != null) {
_registerNewFirebaseRegistrationToken(newFcmToken);
} }
} }
void _storeSubscriptionAction(FCMSubscription fcmSubscription){ void _getStoredFirebaseRegistrationFromCache() {
if (_storeSubscriptionInteractor != null) { if (_getStoredFirebaseRegistrationInteractor != null) {
consumeState(_storeSubscriptionInteractor!.execute(fcmSubscription)); consumeState(_getStoredFirebaseRegistrationInteractor!.execute());
} }
} }
bool _isTokenExpired(FirebaseExpiredTime? expireTime) { void _storeFirebaseRegistrationToCache(FirebaseRegistration firebaseRegistration){
log('FcmTokenController::_isTokenExpired():expireTime: $expireTime'); if (_storeFirebaseRegistrationInteractor != null) {
if (expireTime != null) { consumeState(_storeFirebaseRegistrationInteractor!.execute(firebaseRegistration));
final expireTimeLocal = expireTime.value.value.toLocal(); }
}
bool _validateFirebaseRegistrationTokenExpired(FirebaseRegistration firebaseRegistration) {
log('FcmTokenController::_validateFirebaseRegistrationTokenExpired():firebaseRegistration: $firebaseRegistration');
if (firebaseRegistration.expires != null) {
final expireTimeLocal = firebaseRegistration.expires!.value.value.toLocal();
final currentTime = DateTime.now(); final currentTime = DateTime.now();
log('FcmTokenController::_validateFirebaseRegistrationTokenExpired():expireTimeLocal: $expireTimeLocal | currentTime: $currentTime');
log('FcmTokenController::_isTokenExpired():expireTimeLocal: $expireTimeLocal'); final offsetTime = expireTimeLocal.minutesBetween(currentTime);
log('FcmTokenController::_isTokenExpired():currentTime: $currentTime'); log('FcmTokenController::_validateFirebaseRegistrationTokenExpired():offsetTime: $offsetTime');
return currentTime.isBefore(expireTimeLocal) && offsetTime <= limitedTimeToExpire;
return currentTime.isBefore(expireTimeLocal) &&
expireTimeLocal.daysBetween(currentTime) <= limitedTimeToExpire;
} else { } else {
return true; return true;
} }
} }
void _handleWhenTokenExpired() { void _updateNewExpiredTimeForFirebaseRegistration(FirebaseRegistration firebaseRegistration) {
if (_fcmToken == null || _deviceClientId == null) { log('FcmTokenController::_updateNewExpiredTimeForFirebaseRegistration():firebaseRegistration: $firebaseRegistration');
log('FcmTokenController::_handleSuccessViewState():_fcmToken or _deviceClientId is null'); if (_updateFirebaseRegistrationTokenInteractor != null && firebaseRegistration.id != null) {
return; final newExpiredTime = DateTime.now().add(const Duration(days: extensionTimeExpire));
consumeState(
_updateFirebaseRegistrationTokenInteractor!.execute(
UpdateTokenExpiredTimeRequest(
firebaseRegistration.id!,
FirebaseRegistrationExpiredTime(UTCDate(newExpiredTime)),
)
)
);
} }
final generateCreationId = Id(const Uuid().v4());
final newExpireTime = DateTime.now().add(const Duration(days: extensionTimeExpire));
log('FcmTokenController::_handleSuccessViewState():newExpireTime: $newExpireTime');
final firebaseSubscription = FirebaseSubscription(
token: _fcmToken!,
expires: FirebaseExpiredTime(newExpireTime.toUTCDate()!),
deviceClientId: _deviceClientId!,
types: [TypeName.emailType, TypeName.mailboxType, TypeName.emailDelivery]
);
log('FcmTokenController::_handleSuccessViewState():firebaseSubscription: $firebaseSubscription');
_invokeRegisterNewTokenAction(RegisterNewTokenRequest(
generateCreationId,
firebaseSubscription
));
} }
void _handleRegisterNewToken(FirebaseToken fcmToken, DeviceClientId deviceClientId) { void _registerNewFirebaseRegistrationToken(FcmToken fcmToken) {
final generateCreationId = Id(const Uuid().v4()); final generateCreationId = Id(const Uuid().v4());
final firebaseSubscription = FirebaseSubscription( final firebaseRegistration = FirebaseRegistration(
token: fcmToken, token: fcmToken,
deviceClientId: deviceClientId, deviceClientId: DeviceClientId(FcmUtils.instance.hashTokenToDeviceId(fcmToken.value)),
types: [TypeName.emailType, TypeName.mailboxType, TypeName.emailDelivery] types: FcmUtils.defaultFirebaseRegistrationTypes
); );
log('FcmTokenController::_handleRegisterNewToken():firebaseSubscription: $firebaseSubscription'); log('FcmTokenController::_registerNewFirebaseRegistrationToken():generateCreationId: $generateCreationId | firebaseRegistration: $firebaseRegistration');
_invokeRegisterNewTokenAction(RegisterNewTokenRequest( if (_registerNewFirebaseRegistrationTokenInteractor != null) {
generateCreationId, consumeState(
firebaseSubscription _registerNewFirebaseRegistrationTokenInteractor!.execute(
)); RegisterNewTokenRequest(
} generateCreationId,
firebaseRegistration
void _invokeRegisterNewTokenAction(RegisterNewTokenRequest newTokenRequest) { )
if (_registerNewTokenInteractor != null) { )
consumeState(_registerNewTokenInteractor!.execute(newTokenRequest)); );
} }
} }
void _getFCMSubscriptionLocalAction() { void _deleteFirebaseRegistrationInCache() {
if (_getFCMSubscriptionLocalInteractor != null) { if (_deleteFirebaseRegistrationCacheInteractor != null) {
consumeState(_getFCMSubscriptionLocalInteractor!.execute()); consumeState(_deleteFirebaseRegistrationCacheInteractor!.execute());
} }
} }
@override @override
void handleFailureViewState(Failure failure) { void handleFailureViewState(Failure failure) {
log('FcmTokenController::_handleFailureViewState(): $failure'); log('FcmTokenController::_handleFailureViewState(): $failure');
if (failure is GetFirebaseSubscriptionFailure) { if (failure is GetFirebaseRegistrationByDeviceIdFailure && failure.newFcmToken != null) {
if (_fcmToken != null && _deviceClientId != null) { _registerNewFirebaseRegistrationToken(failure.newFcmToken!);
_handleRegisterNewToken(_fcmToken!, _deviceClientId!); } else if (failure is RegisterNewFirebaseRegistrationTokenFailure) {
} _deleteFirebaseRegistrationInCache();
} }
} }
@override @override
void handleSuccessViewState(Success success) { void handleSuccessViewState(Success success) {
log('FcmTokenController::_handleSuccessViewState(): $success'); log('FcmTokenController::_handleSuccessViewState(): $success');
if (success is GetFirebaseSubscriptionSuccess) { if (success is GetFirebaseRegistrationByDeviceIdSuccess &&
_deviceClientId = success.firebaseSubscription.deviceClientId; _validateFirebaseRegistrationTokenExpired(success.firebaseRegistration)) {
final expireTime = success.firebaseSubscription.expires; _updateNewExpiredTimeForFirebaseRegistration(success.firebaseRegistration);
log('FcmTokenController::_handleSuccessViewState():_fcmToken: $_fcmToken'); } else if (success is GetStoredFirebaseRegistrationSuccess) {
if (_isTokenExpired(expireTime)) { _getFirebaseRegistrationFromServer(deviceClientId: success.firebaseRegistration.deviceClientId!);
log('FcmTokenController::_handleSuccessViewState(): _isTokenExpired true'); } else if (success is RegisterNewFirebaseRegistrationTokenSuccess) {
_handleWhenTokenExpired(); _storeFirebaseRegistrationToCache(success.firebaseRegistration);
}
} else if (success is RegisterNewTokenSuccess) {
final deviceId = success.firebaseSubscription.deviceClientId?.value;
final subscriptionId = success.firebaseSubscription.id?.id.value;
if (deviceId != null && subscriptionId != null) {
_storeSubscriptionAction(FCMSubscription(deviceId, subscriptionId));
}
} else if (success is GetFCMSubscriptionLocalSuccess) {
_getFcmTokenFromBackend(success.fcmSubscription.deviceId);
} }
} }
} }
@@ -18,6 +18,11 @@ class FcmUtils {
static FcmUtils get instance => _instance; static FcmUtils get instance => _instance;
static const String hashCodeKey = 'TeamMail'; static const String hashCodeKey = 'TeamMail';
static final List<TypeName> defaultFirebaseRegistrationTypes = [
TypeName.emailType,
TypeName.mailboxType,
TypeName.emailDelivery
];
StateChange? convertFirebaseDataMessageToStateChange(Map<String, dynamic> dataMessage) { StateChange? convertFirebaseDataMessageToStateChange(Map<String, dynamic> dataMessage) {
log('FcmUtils::convertFirebaseDataMessageToStateChange():dataMessage: $dataMessage'); log('FcmUtils::convertFirebaseDataMessageToStateChange():dataMessage: $dataMessage');
+4 -4
View File
@@ -18,7 +18,7 @@ import 'package:tmail_ui_user/features/caching/clients/recent_search_cache_clien
import 'package:tmail_ui_user/features/caching/clients/sending_email_hive_cache_client.dart'; import 'package:tmail_ui_user/features/caching/clients/sending_email_hive_cache_client.dart';
import 'package:tmail_ui_user/features/caching/clients/session_hive_cache_client.dart'; import 'package:tmail_ui_user/features/caching/clients/session_hive_cache_client.dart';
import 'package:tmail_ui_user/features/caching/clients/state_cache_client.dart'; import 'package:tmail_ui_user/features/caching/clients/state_cache_client.dart';
import 'package:tmail_ui_user/features/caching/clients/subscription_cache_client.dart'; import 'package:tmail_ui_user/features/caching/clients/firebase_registration_cache_client.dart';
import 'package:tmail_ui_user/features/caching/clients/token_oidc_cache_client.dart'; import 'package:tmail_ui_user/features/caching/clients/token_oidc_cache_client.dart';
import 'package:tmail_ui_user/features/cleanup/data/local/recent_login_url_cache_manager.dart'; import 'package:tmail_ui_user/features/cleanup/data/local/recent_login_url_cache_manager.dart';
import 'package:tmail_ui_user/features/cleanup/data/local/recent_login_username_cache_manager.dart'; import 'package:tmail_ui_user/features/cleanup/data/local/recent_login_username_cache_manager.dart';
@@ -71,9 +71,9 @@ class LocalBindings extends Bindings {
Get.put(RecentLoginUrlCacheManager((Get.find<RecentLoginUrlCacheClient>()))); Get.put(RecentLoginUrlCacheManager((Get.find<RecentLoginUrlCacheClient>())));
Get.put(RecentLoginUsernameCacheClient()); Get.put(RecentLoginUsernameCacheClient());
Get.put(RecentLoginUsernameCacheManager(Get.find<RecentLoginUsernameCacheClient>())); Get.put(RecentLoginUsernameCacheManager(Get.find<RecentLoginUsernameCacheClient>()));
Get.put(FCMSubscriptionCacheClient()); Get.put(FirebaseRegistrationCacheClient());
Get.put(FcmCacheClient()); Get.put(FcmCacheClient());
Get.put(FCMCacheManager(Get.find<FcmCacheClient>(),Get.find<FCMSubscriptionCacheClient>())); Get.put(FCMCacheManager(Get.find<FcmCacheClient>(),Get.find<FirebaseRegistrationCacheClient>()));
Get.put(HiveCacheVersionClient(Get.find<SharedPreferences>(), Get.find<CacheExceptionThrower>())); Get.put(HiveCacheVersionClient(Get.find<SharedPreferences>(), Get.find<CacheExceptionThrower>()));
Get.put(NewEmailHiveCacheClient()); Get.put(NewEmailHiveCacheClient());
Get.put(NewEmailCacheManager(Get.find<NewEmailHiveCacheClient>(), Get.find<FileUtils>())); Get.put(NewEmailCacheManager(Get.find<NewEmailHiveCacheClient>(), Get.find<FileUtils>()));
@@ -90,7 +90,7 @@ class LocalBindings extends Bindings {
Get.find<RecentSearchCacheClient>(), Get.find<RecentSearchCacheClient>(),
Get.find<AccountCacheClient>(), Get.find<AccountCacheClient>(),
Get.find<FcmCacheClient>(), Get.find<FcmCacheClient>(),
Get.find<FCMSubscriptionCacheClient>(), Get.find<FirebaseRegistrationCacheClient>(),
Get.find<HiveCacheVersionClient>(), Get.find<HiveCacheVersionClient>(),
Get.find<NewEmailHiveCacheClient>(), Get.find<NewEmailHiveCacheClient>(),
Get.find<OpenedEmailHiveCacheClient>(), Get.find<OpenedEmailHiveCacheClient>(),