Skip to content

Commit 43c748f

Browse files
committed
refactor(push): implement conditional push notification client initialization
- Add null safety to firebaseAuthenticator and push notification clients - Initialize FirebasePushNotificationClient only if credentials are present - Initialize OneSignalPushNotificationClient only if credentials are present - Move push notification client initialization before repository initialization - Log appropriate messages for initialized and disabled push notification clients
1 parent 6c30ed5 commit 43c748f

File tree

1 file changed

+77
-62
lines changed

1 file changed

+77
-62
lines changed

lib/src/config/app_dependencies.dart

Lines changed: 77 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -67,11 +67,11 @@ class AppDependencies {
6767
late final DataRepository<User> userRepository;
6868
late final DataRepository<UserAppSettings> userAppSettingsRepository;
6969
late final DataRepository<UserContentPreferences>
70-
userContentPreferencesRepository;
70+
userContentPreferencesRepository;
7171
late final DataRepository<PushNotificationDevice>
72-
pushNotificationDeviceRepository;
72+
pushNotificationDeviceRepository;
7373
late final DataRepository<PushNotificationSubscription>
74-
pushNotificationSubscriptionRepository;
74+
pushNotificationSubscriptionRepository;
7575
late final DataRepository<RemoteConfig> remoteConfigRepository;
7676
late final EmailRepository emailRepository;
7777

@@ -87,9 +87,9 @@ class AppDependencies {
8787
late final RateLimitService rateLimitService;
8888
late final CountryQueryService countryQueryService;
8989
late final IPushNotificationService pushNotificationService;
90-
late final IFirebaseAuthenticator firebaseAuthenticator;
91-
late final IPushNotificationClient firebasePushNotificationClient;
92-
late final IPushNotificationClient oneSignalPushNotificationClient;
90+
late final IFirebaseAuthenticator? firebaseAuthenticator;
91+
late final IPushNotificationClient? firebasePushNotificationClient;
92+
late final IPushNotificationClient? oneSignalPushNotificationClient;
9393

9494
/// Initializes all application dependencies.
9595
///
@@ -222,51 +222,78 @@ class AppDependencies {
222222
);
223223
final pushNotificationSubscriptionClient =
224224
DataMongodb<PushNotificationSubscription>(
225-
connectionManager: _mongoDbConnectionManager,
226-
modelName: 'push_notification_subscriptions',
227-
fromJson: PushNotificationSubscription.fromJson,
228-
toJson: (item) => item.toJson(),
229-
logger: Logger('DataMongodb<PushNotificationSubscription>'),
230-
);
231-
232-
// --- Initialize Firebase Authenticator ---
233-
// This dedicated service encapsulates the logic for obtaining a Firebase
234-
// access token, keeping the dependency setup clean.
235-
firebaseAuthenticator = FirebaseAuthenticator(
236-
log: Logger('FirebaseAuthenticator'),
237-
);
238-
239-
// --- Initialize HTTP clients for push notification providers ---
240-
241-
// The Firebase client requires a short-lived OAuth2 access token. This
242-
// tokenProvider implements the required two-legged OAuth flow:
243-
// 1. Create a JWT signed with the service account's private key.
244-
// 2. Exchange this JWT for an access token from Google's token endpoint.
245-
final firebaseHttpClient = HttpClient(
246-
baseUrl:
247-
'https://fcm.googleapis.com/v1/projects/${EnvironmentConfig.firebaseProjectId}/',
248-
tokenProvider: firebaseAuthenticator.getAccessToken,
249-
logger: Logger('FirebasePushNotificationClient'),
250-
);
225+
connectionManager: _mongoDbConnectionManager,
226+
modelName: 'push_notification_subscriptions',
227+
fromJson: PushNotificationSubscription.fromJson,
228+
toJson: (item) => item.toJson(),
229+
logger: Logger('DataMongodb<PushNotificationSubscription>'),
230+
);
231+
232+
// --- Conditionally Initialize Push Notification Clients ---
233+
234+
// Firebase
235+
final fcmProjectId = EnvironmentConfig.firebaseProjectId;
236+
final fcmClientEmail = EnvironmentConfig.firebaseClientEmail;
237+
final fcmPrivateKey = EnvironmentConfig.firebasePrivateKey;
238+
239+
if (fcmProjectId != null &&
240+
fcmClientEmail != null &&
241+
fcmPrivateKey != null) {
242+
_log.info('Firebase credentials found. Initializing Firebase client.');
243+
firebaseAuthenticator =
244+
FirebaseAuthenticator(log: Logger('FirebaseAuthenticator'));
245+
246+
final firebaseHttpClient = HttpClient(
247+
baseUrl: 'https://fcm.googleapis.com/v1/projects/$fcmProjectId/',
248+
tokenProvider: firebaseAuthenticator!.getAccessToken,
249+
logger: Logger('FirebasePushNotificationClient'),
250+
);
251+
252+
firebasePushNotificationClient = FirebasePushNotificationClient(
253+
httpClient: firebaseHttpClient,
254+
projectId: fcmProjectId,
255+
log: Logger('FirebasePushNotificationClient'),
256+
);
257+
} else {
258+
_log.warning(
259+
'One or more Firebase credentials not found. Firebase push notifications will be disabled.',
260+
);
261+
firebaseAuthenticator = null;
262+
firebasePushNotificationClient = null;
263+
}
264+
265+
// OneSignal
266+
final osAppId = EnvironmentConfig.oneSignalAppId;
267+
final osApiKey = EnvironmentConfig.oneSignalRestApiKey;
268+
269+
if (osAppId != null && osApiKey != null) {
270+
_log.info('OneSignal credentials found. Initializing OneSignal client.');
271+
final oneSignalHttpClient = HttpClient(
272+
baseUrl: 'https://onesignal.com/api/v1/',
273+
tokenProvider: () async => null,
274+
interceptors: [
275+
InterceptorsWrapper(
276+
onRequest: (options, handler) {
277+
options.headers['Authorization'] = 'Basic $osApiKey';
278+
return handler.next(options);
279+
},
280+
),
281+
],
282+
logger: Logger('OneSignalPushNotificationClient'),
283+
);
284+
285+
oneSignalPushNotificationClient = OneSignalPushNotificationClient(
286+
httpClient: oneSignalHttpClient,
287+
appId: osAppId,
288+
log: Logger('OneSignalPushNotificationClient'),
289+
);
290+
} else {
291+
_log.warning(
292+
'One or more OneSignal credentials not found. OneSignal push notifications will be disabled.',
293+
);
294+
oneSignalPushNotificationClient = null;
295+
}
251296

252-
// The OneSignal client requires the REST API key for authentication.
253-
// We use a custom interceptor to add the 'Authorization: Basic <API_KEY>'
254-
// header, as the default AuthInterceptor is hardcoded for 'Bearer' tokens.
255-
final oneSignalHttpClient = HttpClient(
256-
baseUrl: 'https://onesignal.com/api/v1/',
257-
// The tokenProvider is not used here; auth is handled by the interceptor.
258-
tokenProvider: () async => null,
259-
interceptors: [
260-
InterceptorsWrapper(
261-
onRequest: (options, handler) {
262-
options.headers['Authorization'] =
263-
'Basic ${EnvironmentConfig.oneSignalRestApiKey}';
264-
return handler.next(options);
265-
},
266-
),
267-
],
268-
logger: Logger('OneSignalPushNotificationClient'),
269-
);
270297
// 4. Initialize Repositories
271298
headlineRepository = DataRepository(dataClient: headlineClient);
272299
topicRepository = DataRepository(dataClient: topicClient);
@@ -306,18 +333,6 @@ class AppDependencies {
306333

307334
emailRepository = EmailRepository(emailClient: emailClient);
308335

309-
// Initialize Push Notification Clients
310-
firebasePushNotificationClient = FirebasePushNotificationClient(
311-
httpClient: firebaseHttpClient,
312-
projectId: EnvironmentConfig.firebaseProjectId,
313-
log: Logger('FirebasePushNotificationClient'),
314-
);
315-
oneSignalPushNotificationClient = OneSignalPushNotificationClient(
316-
httpClient: oneSignalHttpClient,
317-
appId: EnvironmentConfig.oneSignalAppId,
318-
log: Logger('OneSignalPushNotificationClient'),
319-
);
320-
321336
// 5. Initialize Services
322337
tokenBlacklistService = MongoDbTokenBlacklistService(
323338
connectionManager: _mongoDbConnectionManager,

0 commit comments

Comments
 (0)