Adds Task Persistance Layer#3785
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (14)
💤 Files with no reviewable changes (1)
👮 Files not reviewed due to content moderation or server errors (13)
📝 Walkthrough
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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. Comment |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #3785 +/- ##
============================================
+ Coverage 25.95% 26.14% +0.19%
- Complexity 4406 4462 +56
============================================
Files 953 954 +1
Lines 57334 57383 +49
Branches 6823 6830 +7
============================================
+ Hits 14879 15002 +123
+ Misses 40623 40545 -78
- Partials 1832 1836 +4 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
cfc92b7 to
7741e3c
Compare
256106e to
7d599a9
Compare
- ConnectTaskRecord: DB model with all fields; fromJson uses correct JSON key names (assigned_task_id, task_name, etc.) and parses date_created via ConnectDateUtils.parseServerTimestamp - ConnectDatabaseSchemaManager: bumps to v27, adds connect_tasks table - ConnectDatabaseUpgrader: adds v27 migration path - ConnectDateUtils: adds parseServerTimestamp for ISO-8601 timestamps Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Legacy relearn-task prefs (isRelearnTaskPending, setRelearnTaskPending, getRelearnTasksCompletedTimeMs, setRelearnTasksCompletedTime) are deprecated now that task state is persisted in ConnectTaskRecord. Adds getTaskModifiedTime / updateTaskModifiedTime backed by KEY_TASK_LAST_MODIFIED_TIME for ConnectTaskUtils to record when task state last changed. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
ConnectTaskUtils provides storeTasks (insert/update/delete to match incoming payload), hasPendingTask, getPendingTaskOfType, hasPendingTaskOfType, and shouldShowTasksCompletedMessage — replacing the equivalent logic that was inlined in ConnectJobRecord. DeliveryAppProgressResponseParser now builds ConnectTaskRecord directly via ConnectTaskRecord.fromJson (removing the ParsedConnectTask shim). DeliveryAppProgressResponseModel.applyToJob calls ConnectTaskUtils.storeTasks instead of syncRelearnTasksPrefs. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
ConnectTaskUtilsTest covers storeTasks (insert, update, no-op, delete), query helpers, and shouldShowTasksCompletedMessage. Uses the real in-memory Robolectric DB via CommCareTestApplication — no static mocks. DeliveryAppProgressResponseParserTest covers JSON → ConnectTaskRecord parsing end-to-end. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
7d599a9 to
106bec4
Compare
| } | ||
| } | ||
|
|
||
| fun formatNotificationTime( |
There was a problem hiding this comment.
changes in the method are formatting only and can be skipped while review
| val task = ConnectTaskRecord() | ||
| task.jobUUID = job.jobUUID | ||
| task.taskId = json.getString("assigned_task_id") | ||
| task.name = json.getString("task_name") | ||
| task.description = json.optString("task_description", "") | ||
| task.status = json.getString("status") | ||
| task.connectChannelId = json.optString("connect_channel_id", "") | ||
| task.type = json.optString("task_type", "") | ||
| if (json.hasNonNull("due_date")) { | ||
| task.dueDate = DateUtils.parseDate(json.getString("due_date")) | ||
| } | ||
| if (json.hasNonNull("date_created")) { | ||
| task.dateCreated = ConnectDateUtils.parseServerTimestamp( | ||
| json.getString("date_created"), | ||
| ) ?: Date() | ||
| } | ||
| return task |
There was a problem hiding this comment.
Should these keys be the same constants used on the Record's fields?
There was a problem hiding this comment.
not really, DB level fields and related constants are different from API payload and should not be used inter-changeably.
conroy-ricketts
left a comment
There was a problem hiding this comment.
All looks great to me, would love a second set of eyes before merge
| setRelearnTaskPending(incoming.any { it.status == "assigned" }) | ||
| resetRelearnTasksCompletedTime() |
There was a problem hiding this comment.
Since we are migrating from SharedPreferences to a local database, do we still need to store these specific values in preferences?
There was a problem hiding this comment.
These preferences are still in use to provide backward compatibility for some edge cases as currently we can't make sure whether someone has re-synced tasks after taking an update or not, once we release 2.64 these can be removed.
| for (orphan in existing.filter { it.taskId !in incomingIds }) { | ||
| storage.remove(orphan) | ||
| changed = true | ||
| } |
There was a problem hiding this comment.
Now that orphan tasks are removed from the DB during sync, if the payload stops sending the completed task the banner disappears immediately. In the previous implementation it was kept for up to 6 hours after completion.
There was a problem hiding this comment.
Can confirm here that the server payload does retain completed tasks.
| fun shouldShowTasksCompletedMessage( | ||
| context: Context, | ||
| job: ConnectJobRecord, | ||
| ): Boolean { | ||
| if (hasPendingTask(context, job.jobUUID)) return false | ||
| val mostRecent = getMostRecentlyCompletedTask(context, job.jobUUID) ?: return false | ||
| val timeElapsed = Date().time - mostRecent.dateModified.time | ||
| return timeElapsed < TASKS_COMPLETED_MESSAGE_WINDOW_MS && job.status == ConnectJobRecord.STATUS_DELIVERING | ||
| } |
There was a problem hiding this comment.
ConnectTaskRecord.fromJson parses date_created but not date_modified. The deleted ParsedConnectTask.fromJson did parse it.
This function measures the 6h window from now (dateModified) and not when the worker actually completed it.
There was a problem hiding this comment.
I am checking with server team if it's possible to get date_modified in the payload (we do not currently) . If they confirm, I will update the parsing to account for date_modified.
There was a problem hiding this comment.
Although even without date, the dateModified is written to the db row based on whether a task model has changed in storeTasks so this implementation should still be correct as dateModified is derived locally by comparing the model fields for task and detecting a change. As such the net effect here would be that the completed message banner would appear to the user until 6 hour since they synced a completed task which I think is acceptable behaviour. Thoughts ?
There was a problem hiding this comment.
I am now parsing date_modified from server payload - 7fe8ea9
| task.dueDate = DateUtils.parseDate(json.getString("due_date")) | ||
| } | ||
| if (json.hasNonNull("date_created")) { | ||
| task.dateCreated = ConnectDateUtils.parseServerTimestamp( |
There was a problem hiding this comment.
Can we use DateUtils.parseDateTime as its achieving same thing?
Product Description
https://dimagi.atlassian.net/browse/CCCT-2539
No visible UI changes
Technical Summary
Implements first part of OCS task spec
Stores tasks in DB and migrate current preferences methods to use DB instead.
Safety Assurance
Safety story
Verified locally that all current tasks behavious works as today and the PR doesn't cause any changes in current functionality around tasks
Automated test coverage
Tests are added for new functionality on DB and parse layers.
Labels and Review