Skip to content

Conversation

@shubham1g5
Copy link
Contributor

@shubham1g5 shubham1g5 commented Dec 8, 2025

Product Description

https://dimagi.atlassian.net/browse/CCCT-1940

Technical Summary

Refactors the code to separate out DB operations from parser to be able to uniformly test parser without mocking a lot of DB calls.

API Response → Parser (Focuses on pure json parsing) → PushNotificationApiHelper (Stores data into DB, UI state change and Acknowledment to server)

  • Eliminated redundant filtering and processing of notifications code
  • Better Separation between Parser and API Handler

Safety Assurance

Safety story

This should not cause any changes in the existing functionality, I have verified it with tests but given the code has changed a bunch, I think we will need to have a QA cycle on notifications before releasing this (already part of QA plan)

QA Plan

Should be QA'ed as part of mobile release

Labels and Review

  • Do we need to enhance the manual QA test coverage ? If yes, the "QA Note" label is set correctly
  • Does the PR introduce any major changes worth communicating ? If yes, the "Release Note" label is set and a "Release Note" is specified in PR description.
  • Risk label is set correctly
  • The set of people pinged as reviewers is appropriate for the level of risk of the change

Parser → Service → API Handler flow
Parser -> purely focused on parsing JSON data
NotificationService -> Takes the parsed models and store into DB and supply modified result to the Api handler
PushNotificationApiHelper -> Post hooks for UI logic + acknowledgment to server
@coderabbitai
Copy link

coderabbitai bot commented Dec 8, 2025

📝 Walkthrough

Walkthrough

This PR refactors the notification parsing and processing workflow into a multi-stage pipeline. It introduces a new factory method on ConnectMessagingMessageRecord for JSON decryption, changes PushNotificationRecord's parsing from batch to single-object, and restructures RetrieveNotificationsResponseParser from a generic parser to a concrete parser that returns NotificationParseResult. A new NotificationService processes parsed data into the database, separating messaging and push notifications into distinct paths. PersonalIdApiHandler, PushNotificationApiHelper, and related components are updated to use the new ProcessedNotificationResult container, replacing direct list handling with structured result objects.

Sequence Diagram

sequenceDiagram
    participant API as PersonalIdApiHandler
    participant Parser as RetrieveNotificationsResponseParser
    participant Service as NotificationService
    participant DB as Database
    participant Result as ProcessedNotificationResult

    API->>Parser: parse(responseStream)
    Parser->>Parser: parseChannels()
    Parser->>Parser: parseAndSeparateNotifications()
    Note over Parser: Classify notifications into<br/>Push and Messaging types
    Parser-->>API: NotificationParseResult
    API->>Service: processNotificationData(context, parseResult)
    Service->>Service: Filter notifications by type
    Service->>DB: Save messaging channels
    Service->>DB: Save messaging messages
    Service->>DB: Save push notifications
    Service-->>Result: ProcessedNotificationResult<br/>(savedNotifications,<br/>messagingIds,<br/>savedIds)
    API->>API: Handle processed results<br/>and broadcast
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

  • Decryption logic: Review the fromJson() method in ConnectMessagingMessageRecord to ensure proper error handling and null-safety when channels are missing or decryption fails
  • Database transaction handling: Verify that NotificationService properly handles atomicity and error scenarios when persisting multiple entity types (channels, messages, notifications)
  • Type contract changes: Audit PersonalIdApiHandler and PushNotificationApiHelper for correct usage of ProcessedNotificationResult fields and ensure compatibility with existing downstream consumers
  • Parser refactoring: Validate that RetrieveNotificationsResponseParser correctly classifies and separates messaging vs. push notifications, and that the isNotificationMessageType detection logic is comprehensive
  • Test coverage: Ensure RetrieveNotificationsResponseParserTest covers edge cases such as malformed decryption tags, missing required fields, and partial channel availability

Possibly related PRs

Suggested reviewers

  • conroy-ricketts
  • Jignesh-dimagi

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 22.58% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Notifications Parser refactor and tests' clearly and concisely summarizes the main objective of the PR, which is refactoring the notification parser and adding corresponding tests.
Description check ✅ Passed The pull request description provides a product link, technical rationale, safety story, and QA plan with appropriate labels checked.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch notificationsRefactorAndTests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
app/src/org/commcare/android/database/connect/models/ConnectMessagingMessageRecord.java (1)

90-91: Potential NPE if DateUtils.parseDateTime returns null.

Similar to PushNotificationRecord, DateUtils.parseDateTime can return null on parse failure, which would set timeStamp to null. Consider adding a null check or default:

 String dateString = json.getString(META_MESSAGE_TIMESTAMP);
-connectMessagingMessageRecord.timeStamp = DateUtils.parseDateTime(dateString);
+Date parsedDate = DateUtils.parseDateTime(dateString);
+if (parsedDate == null) {
+    return null;
+}
+connectMessagingMessageRecord.timeStamp = parsedDate;
🧹 Nitpick comments (3)
app/unit-tests/src/org/commcare/connect/network/connectId/parser/RetrieveNotificationsResponseParserTest.kt (1)

212-242: Consider adding a test for successful message decryption.

The current test at lines 223-226 mocks getMessagingChannels to return an empty list, so messaging notifications are never decrypted (as noted in the comment at line 233). Consider adding a test that provides a channel with a valid encryption key to verify the message decryption path works correctly.

app/src/org/commcare/connect/network/connectId/parser/NotificationParseResult.kt (1)

7-10: Clarify "exclusive" in the documentation.

The term "exclusive" suggests the three entity types are mutually exclusive (only one can be present at a time), but the parser can populate all three lists simultaneously from a single response. Consider rewording to "separate" or "distinct" to avoid confusion.

Apply this diff to clarify the documentation:

 /**
  * Data class to hold the result of parsing notification response
- * Contains three separate, exclusive entities: notifications, channels, and messages
+ * Contains three separate entities: notifications, channels, and messages
  */
app/src/org/commcare/connect/network/connectId/parser/RetrieveNotificationsResponseParser.kt (1)

45-56: Consider more idiomatic Kotlin.

The channel parsing logic is correct but could be simplified using Kotlin's collection operations for better readability.

Apply this diff for a more idiomatic approach:

-    private fun parseChannels(responseJsonObject: JSONObject): MutableList<ConnectMessagingChannelRecord> {
-        val channels: MutableList<ConnectMessagingChannelRecord> = ArrayList()
+    private fun parseChannels(responseJsonObject: JSONObject): List<ConnectMessagingChannelRecord> {
         if (responseJsonObject.has("channels")) {
             val channelsJson: JSONArray = responseJsonObject.getJSONArray("channels")
-            for (i in 0 until channelsJson.length()) {
-                val obj = channelsJson.get(i) as JSONObject
-                val channel = ConnectMessagingChannelRecord.fromJson(obj)
-                channels.add(channel)
-            }
+            return (0 until channelsJson.length())
+                .map { channelsJson.getJSONObject(it) }
+                .map { ConnectMessagingChannelRecord.fromJson(it) }
         }
-        return channels
+        return emptyList()
     }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 484df28 and cb09195.

📒 Files selected for processing (9)
  • app/src/org/commcare/android/database/connect/models/ConnectMessagingMessageRecord.java (2 hunks)
  • app/src/org/commcare/android/database/connect/models/PushNotificationRecord.kt (2 hunks)
  • app/src/org/commcare/connect/network/connectId/PersonalIdApiHandler.java (2 hunks)
  • app/src/org/commcare/connect/network/connectId/parser/NotificationParseResult.kt (1 hunks)
  • app/src/org/commcare/connect/network/connectId/parser/RetrieveNotificationsResponseParser.kt (1 hunks)
  • app/src/org/commcare/connect/services/NotificationService.kt (1 hunks)
  • app/src/org/commcare/connect/services/ProcessedNotificationResult.kt (1 hunks)
  • app/src/org/commcare/utils/PushNotificationApiHelper.kt (2 hunks)
  • app/unit-tests/src/org/commcare/connect/network/connectId/parser/RetrieveNotificationsResponseParserTest.kt (1 hunks)
🧰 Additional context used
🧠 Learnings (15)
📓 Common learnings
Learnt from: shubham1g5
Repo: dimagi/commcare-android PR: 0
File: :0-0
Timestamp: 2025-05-08T11:08:18.530Z
Learning: PR #3048 "Phase 4 Connect PR" introduces a substantial feature called "Connect" to the CommCare Android app, which includes messaging, job management, delivery tracking, payment processing, authentication flows, and learning modules. It follows a modern architecture using Navigation Components with three navigation graphs, segregated business logic in Manager classes, and proper database persistence.
Learnt from: OrangeAndGreen
Repo: dimagi/commcare-android PR: 3248
File: app/src/org/commcare/connect/MessageManager.java:0-0
Timestamp: 2025-07-29T14:54:47.940Z
Learning: User OrangeAndGreen organizes messaging-related changes into separate PRs rather than mixing them with other Connect work, which aligns with their preference for handling code issues in separate PRs when they are not directly related to the main changes.
Learnt from: Jignesh-dimagi
Repo: dimagi/commcare-android PR: 0
File: :0-0
Timestamp: 2025-05-08T13:40:19.645Z
Learning: PR #3048 introduces a comprehensive messaging system in the Connect feature, implementing secure encryption using AES-GCM for message content, proper channel management with consent flows, and a well-designed UI separation between sent and received messages with real-time notification integration.
📚 Learning: 2025-01-21T18:20:43.883Z
Learnt from: OrangeAndGreen
Repo: dimagi/commcare-android PR: 2912
File: app/src/org/commcare/fragments/connectId/ConnectIdPasswordVerificationFragment.java:206-213
Timestamp: 2025-01-21T18:20:43.883Z
Learning: In the Connect ID feature, server responses containing user data should be parsed using ConnectUserResponseParser to ensure consistent handling of payment information (owner_name and phone_number) and secondary phone verification across all authentication flows.

Applied to files:

  • app/src/org/commcare/connect/network/connectId/parser/RetrieveNotificationsResponseParser.kt
  • app/src/org/commcare/connect/network/connectId/parser/NotificationParseResult.kt
  • app/src/org/commcare/connect/network/connectId/PersonalIdApiHandler.java
📚 Learning: 2025-02-04T21:22:56.537Z
Learnt from: pm-dimagi
Repo: dimagi/commcare-android PR: 2949
File: app/src/org/commcare/fragments/connectId/ConnectIdPinFragment.java:244-275
Timestamp: 2025-02-04T21:22:56.537Z
Learning: Direct JSONObject parsing is acceptable for handling user data responses in ConnectIdPinFragment, as decided by the team. No need to enforce ConnectUserResponseParser usage in this context.

Applied to files:

  • app/src/org/commcare/connect/network/connectId/parser/RetrieveNotificationsResponseParser.kt
  • app/src/org/commcare/connect/network/connectId/PersonalIdApiHandler.java
📚 Learning: 2025-11-06T11:44:23.934Z
Learnt from: Jignesh-dimagi
Repo: dimagi/commcare-android PR: 3407
File: app/src/org/commcare/android/database/connect/models/PushNotificationRecord.kt:92-107
Timestamp: 2025-11-06T11:44:23.934Z
Learning: In PushNotificationRecord, the `acknowledged` field (META_ACKNOWLEDGED) is a client-side field that is not included in the server's JSON response, so it should not be read in the fromJsonArray method.

Applied to files:

  • app/src/org/commcare/android/database/connect/models/PushNotificationRecord.kt
📚 Learning: 2025-04-18T20:13:29.655Z
Learnt from: OrangeAndGreen
Repo: dimagi/commcare-android PR: 3040
File: app/src/org/commcare/android/database/connect/models/ConnectJobDeliveryFlagRecord.java:39-55
Timestamp: 2025-04-18T20:13:29.655Z
Learning: In the CommCare Android Connect feature, the JSON object passed to `ConnectJobDeliveryFlagRecord.fromJson()` method should never be null based on the implementation design.

Applied to files:

  • app/src/org/commcare/android/database/connect/models/PushNotificationRecord.kt
  • app/src/org/commcare/android/database/connect/models/ConnectMessagingMessageRecord.java
📚 Learning: 2025-04-22T17:04:26.780Z
Learnt from: OrangeAndGreen
Repo: dimagi/commcare-android PR: 3043
File: app/src/org/commcare/android/database/connect/models/ConnectMessagingChannelRecord.java:0-0
Timestamp: 2025-04-22T17:04:26.780Z
Learning: In the Connect API contract, the server doesn't include the fields `created`, `answered_consent`, and `key` in JSON responses for messaging channels, which is why the `fromJson` method in `ConnectMessagingChannelRecord` explicitly initializes these values rather than parsing them.

Applied to files:

  • app/src/org/commcare/android/database/connect/models/ConnectMessagingMessageRecord.java
📚 Learning: 2025-04-22T17:04:26.780Z
Learnt from: OrangeAndGreen
Repo: dimagi/commcare-android PR: 3043
File: app/src/org/commcare/android/database/connect/models/ConnectMessagingChannelRecord.java:0-0
Timestamp: 2025-04-22T17:04:26.780Z
Learning: In the Connect API contract, the server doesn't include the fields `created`, `answered_consent`, and `key` in JSON responses for messaging channels, which is why the `fromJson` method in `ConnectMessagingChannelRecord` explicitly initializes these values rather than parsing them from JSON.

Applied to files:

  • app/src/org/commcare/android/database/connect/models/ConnectMessagingMessageRecord.java
📚 Learning: 2025-05-08T13:40:19.645Z
Learnt from: Jignesh-dimagi
Repo: dimagi/commcare-android PR: 0
File: :0-0
Timestamp: 2025-05-08T13:40:19.645Z
Learning: PR #3048 introduces a comprehensive messaging system in the Connect feature, implementing secure encryption using AES-GCM for message content, proper channel management with consent flows, and a well-designed UI separation between sent and received messages with real-time notification integration.

Applied to files:

  • app/src/org/commcare/android/database/connect/models/ConnectMessagingMessageRecord.java
📚 Learning: 2025-04-22T17:05:39.842Z
Learnt from: OrangeAndGreen
Repo: dimagi/commcare-android PR: 3043
File: app/src/org/commcare/android/database/connect/models/ConnectMessagingMessageRecord.java:0-0
Timestamp: 2025-04-22T17:05:39.842Z
Learning: In ConnectMessagingMessageRecord, decryption failures are expected in some scenarios and are handled by logging the exception with Logger.exception() but continuing execution by returning null, allowing the application to gracefully handle the failure.

Applied to files:

  • app/src/org/commcare/android/database/connect/models/ConnectMessagingMessageRecord.java
📚 Learning: 2025-07-29T14:14:07.954Z
Learnt from: OrangeAndGreen
Repo: dimagi/commcare-android PR: 3248
File: app/src/org/commcare/adapters/ConnectMessageAdapter.java:0-0
Timestamp: 2025-07-29T14:14:07.954Z
Learning: In the CommCare Android Connect messaging system (ConnectMessageAdapter.java), the team prefers to let getMessage() potentially return null and crash rather than adding defensive null checks. This follows the fail-fast philosophy used throughout the Connect feature to catch programming errors immediately during development.

Applied to files:

  • app/src/org/commcare/android/database/connect/models/ConnectMessagingMessageRecord.java
📚 Learning: 2025-05-08T11:08:18.530Z
Learnt from: shubham1g5
Repo: dimagi/commcare-android PR: 0
File: :0-0
Timestamp: 2025-05-08T11:08:18.530Z
Learning: PR #3048 "Phase 4 Connect PR" introduces a substantial feature called "Connect" to the CommCare Android app, which includes messaging, job management, delivery tracking, payment processing, authentication flows, and learning modules. It follows a modern architecture using Navigation Components with three navigation graphs, segregated business logic in Manager classes, and proper database persistence.

Applied to files:

  • app/src/org/commcare/android/database/connect/models/ConnectMessagingMessageRecord.java
  • app/src/org/commcare/connect/network/connectId/PersonalIdApiHandler.java
  • app/src/org/commcare/utils/PushNotificationApiHelper.kt
📚 Learning: 2025-07-29T14:45:13.470Z
Learnt from: OrangeAndGreen
Repo: dimagi/commcare-android PR: 3248
File: app/src/org/commcare/connect/MessageManager.java:0-0
Timestamp: 2025-07-29T14:45:13.470Z
Learning: In the CommCare Android Connect messaging system (MessageManager.java), the error handling logic in updateChannelConsent's processFailure callback intentionally attempts to retrieve the channel encryption key even after consent update failure. This behavior was recommended by the server team and the worst case scenario is silently failing to retrieve the encryption key, which is considered acceptable.

Applied to files:

  • app/src/org/commcare/android/database/connect/models/ConnectMessagingMessageRecord.java
📚 Learning: 2025-04-22T16:44:26.867Z
Learnt from: OrangeAndGreen
Repo: dimagi/commcare-android PR: 3043
File: app/src/org/commcare/android/database/connect/models/ConnectMessagingChannelRecord.java:86-99
Timestamp: 2025-04-22T16:44:26.867Z
Learning: In ConnectMessagingChannelRecord, fields like META_CHANNEL_ID, META_CONSENT, META_CHANNEL_NAME, and META_KEY_URL are required fields, and the code is intentionally designed to crash if they're missing to raise awareness of data integrity issues rather than handling them silently.

Applied to files:

  • app/src/org/commcare/android/database/connect/models/ConnectMessagingMessageRecord.java
📚 Learning: 2025-01-27T09:08:32.722Z
Learnt from: pm-dimagi
Repo: dimagi/commcare-android PR: 2847
File: app/src/org/commcare/android/database/connect/models/ConnectJobDeliveryRecord.java:86-93
Timestamp: 2025-01-27T09:08:32.722Z
Learning: The JSON fields (status, unitName, slug, entityId, entityName, reason) in ConnectJobDeliveryRecord's fromJson method are guaranteed to be non-null through the application's data contract, except for the 'id' field which is explicitly checked.

Applied to files:

  • app/src/org/commcare/android/database/connect/models/ConnectMessagingMessageRecord.java
📚 Learning: 2025-02-19T15:15:01.935Z
Learnt from: pm-dimagi
Repo: dimagi/commcare-android PR: 2956
File: app/src/org/commcare/fragments/connectMessaging/ConnectMessageChannelListFragment.java:58-60
Timestamp: 2025-02-19T15:15:01.935Z
Learning: Error handling for message retrieval in ConnectMessageChannelListFragment's retrieveMessages callback is not required as per user preference.

Applied to files:

  • app/src/org/commcare/connect/network/connectId/PersonalIdApiHandler.java
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Lint Code Base
🔇 Additional comments (6)
app/src/org/commcare/connect/services/ProcessedNotificationResult.kt (1)

8-12: LGTM!

Clean immutable data class with clear separation between saved notifications and their IDs. Good documentation.

app/unit-tests/src/org/commcare/connect/network/connectId/parser/RetrieveNotificationsResponseParserTest.kt (1)

31-42: LGTM!

Comprehensive test suite with good coverage of parsing scenarios including empty arrays, push notifications, channels, complete responses with all types, optional fields, and error conditions.

app/src/org/commcare/utils/PushNotificationApiHelper.kt (1)

68-106: LGTM!

Clean refactor to use ProcessedNotificationResult. The logic correctly:

  • Sets notification as unread only when there are saved notification IDs
  • Broadcasts when there are either saved notifications or messaging notifications
  • Acknowledges both saved and messaging notification IDs
  • Returns only non-messaging notifications for backward compatibility
app/src/org/commcare/connect/network/connectId/PersonalIdApiHandler.java (1)

313-330: The review comment is incorrect. The stopLoadingAndInformError method in BaseApiHandler.kt (line 156) calls onStop() internally before invoking onFailure(), so the error path properly terminates the loading state. No issue exists here.

Likely an incorrect or invalid review comment.

app/src/org/commcare/connect/network/connectId/parser/RetrieveNotificationsResponseParser.kt (2)

17-43: LGTM! Clean refactoring of the parser flow.

The new structure clearly separates channel parsing, notification parsing, and result construction. The concrete return type (NotificationParseResult) improves type safety and aligns well with the refactor objectives.


98-101: LGTM!

The notification type detection logic is clear and correct.

Comment on lines +96 to +97
val dateString: String = obj.getString(META_TIME_STAMP)
createdDate = DateUtils.parseDateTime(dateString)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Potential NPE if DateUtils.parseDateTime returns null.

DateUtils.parseDateTime(dateString) can return null if the date string cannot be parsed. Assigning null to createdDate (which is non-null Date) will cause issues. Consider adding null-safety:

 val dateString: String = obj.getString(META_TIME_STAMP)
-createdDate = DateUtils.parseDateTime(dateString)
+createdDate = DateUtils.parseDateTime(dateString) ?: Date()
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
val dateString: String = obj.getString(META_TIME_STAMP)
createdDate = DateUtils.parseDateTime(dateString)
val dateString: String = obj.getString(META_TIME_STAMP)
createdDate = DateUtils.parseDateTime(dateString) ?: Date()
🤖 Prompt for AI Agents
In
app/src/org/commcare/android/database/connect/models/PushNotificationRecord.kt
around lines 96-97, createdDate is assigned directly from
DateUtils.parseDateTime(dateString) which can return null; update the code to
safely handle a null return by calling parseDateTime into a nullable variable,
then either (a) provide a non-null fallback (e.g., Date() or Date(0)) and log a
warning, or (b) throw/propagate a descriptive exception if a missing date should
be considered fatal; ensure createdDate remains non-null after this check and
that any logging uses the original dateString for context.

@shubham1g5 shubham1g5 requested review from OrangeAndGreen and removed request for orangejenny December 8, 2025 12:59
conroy-ricketts
conroy-ricketts previously approved these changes Dec 8, 2025
Copy link
Contributor

@conroy-ricketts conroy-ricketts left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great to me! I'd like another set of eyes on this before we merge though

val nonMessagingNotifications: List<PushNotificationRecord>,
val channels: List<ConnectMessagingChannelRecord>,
val messages: List<ConnectMessagingMessageRecord>,
val messagingNotificationIds: List<String>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@shubham1g5 We can follow the same procedure to get the list of messagingNotificationIds as done for nonMessagingNotifications. We don't have to pass the messagingNotificationIds here but in fact this and this should return the list of message Ids which are store successfully. So this way its consistent with both non message and message local DB storing

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Jignesh-dimagi messagingNotificationIds are not the message ids here but the ids of the notifications associated with the notifications which is what we need to acknowledge to the server.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Jignesh-dimagi messagingNotificationIds are not the message ids here but the ids of the notifications associated with the notifications which is what we need to acknowledge to the server.

Yeah agree. I was trying to see if we can only acknowledge message notifications which are stored successfully. I also see your point that we don't have right now a way to do that.


// ========== Test Data Builders ==========

private fun createPushNotificationJson(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@shubham1g5 Just a thought. We can create a util NotificationsTestUtil and add all create methods in it to be used by other tests also in future.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment on lines 313 to 330
private IApiCallback createNotificationCallback(Context context) {
onStart();
return new BaseApiCallback<T>(this) {
@Override
public void processSuccess(int responseCode, InputStream responseData) {
try {
RetrieveNotificationsResponseParser parser = new RetrieveNotificationsResponseParser(context);
NotificationParseResult parseResult = parser.parse(responseCode, responseData, null);
ProcessedNotificationResult processedResult =
NotificationService.INSTANCE.processNotificationData(context, parseResult);
onSuccess((T) processedResult);
onStop();
} catch (Exception e) {
Logger.exception("Error processing notification data", e);
stopLoadingAndInformError(PersonalIdOrConnectApiErrorCodes.JSON_PARSING_ERROR, e);
}
}
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@shubham1g5 This class doesn't have implementation for BaseApiCallback for particular API. I am seeing that you can directly return ProcessedNotificationResult from here and let PushNotificationApiHelper handle the NotificationService part. This will maintain the uniformity of this class for all API calls.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

user.getPassword(),
createCallback(new RetrieveNotificationsResponseParser<>(context), null)
);
createCallback((BaseApiResponseParser<T>) new RetrieveNotificationsResponseParser(context), null));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@shubham1g5 Why data type casting is required here?

Copy link
Contributor Author

@shubham1g5 shubham1g5 Dec 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's required due to the change in RetrieveNotificationsResponseParser definition to extend from BaseApiResponseParser<NotificationParseResult> instead of BaseApiResponseParser<T>

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can still keep BaseApiResponseParser<T> and return NotificationParseResult as T?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No strong thoughts on my end, Do you have a sense of why one is better than other ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like we need to cast over here or as done in this PR.

Jignesh-dimagi
Jignesh-dimagi previously approved these changes Dec 10, 2025
@shubham1g5 shubham1g5 merged commit 9601032 into master Dec 10, 2025
7 of 9 checks passed
@shubham1g5 shubham1g5 deleted the notificationsRefactorAndTests branch December 10, 2025 12:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants