Add side loading for single user sync of data that does not fall within single user scope
See original GitHub issueThis issue shall serve as the tech spec for https://github.com/learningequality/kolibri/issues/8038
The partitions for Lessons, Quizzes, and their respective Assignments do not fall within the scope of an individual user syncing certificate, and hence need to be synced across to a SoUD through a parallel (non-Morango) mechanism. However, this can still happen within the context of a Morango sync session, and use the open sync session as a means of authentication.
The proposal is to add a new public API endpoint in Kolibri, /api/public/assignment_sync/<user_id>
, that can handle HEAD
requests (to check the server’s current ETag value before sending a bunch of data), GET
requests (to retrieve the current set of assigned resources), and POST
requests (to send the current set of assigned resources).
When the SoUD is the client, initiating a sync with a full-facility server:
- After the “pull” phase of the sync, the client calculates its own ETag, then sends an ETag-conditional
GET
request to/api/public/assignment_sync/<user_id>
. - The server calculates its own ETag, and if it matches the client-provided value, returns a
304 Not Modified
. - Otherwise, it returns the serialized data for the assigned resources. If this happens, the client removes all Lesson/Quiz assignments it has stored for the user, and creates the records that it received.
When the full-facility device is the client, initiating a sync with the SoUD:
- After the “push” phase of the sync, the client (full-facility device) calculates its own ETag, then sends a
HEAD
request to the SoUD’s/api/public/assignment_sync/<user_id>
to check its ETag. - If they match, it continues merrily.
- If they don’t match, it makes a
GET
request to the endpoint, then removes and replaces its local resources with the response.
All of these requests will include a header with the Sync Session ID. The server should validate that:
- The corresponding Sync Session exists and is still active. Otherwise, return a
401 Unauthorized
. - The user_id is for a user that is within scope of the Sync Sessions certificates. Otherwise, return a
403 Forbidden
. - When it is validating records received, ensure the partition is correct, and the ID matches the computed ID. Otherwise, return a
400 Bad Request
.
The proposed structure of the serialized payload is:
{
"lessons": [{<lesson_1_serialization>}, {<lesson_2_serialization>}, ...],
"quizzes": [{<quiz_1_serialization>}, {<quiz_2_serialization>}, ...]
}
There should be no need to sync the *Assignment objects themselves, as they are implicit in the lists of resources (these are all-inclusive lists of the resources currently assigned, so assignments can be deleted or created based on presence of a resource in here).
Note: when quiz/lesson resource and assignment model instances are created on a SoUD, they should be marked as “not dirty” to prevent unnecessary serialization (that could also cause issues if the device later synced the full facility). Similarly, the signal that tracks model deletion should be bypassed when they are removed.
Issue Analytics
- State:
- Created 2 years ago
- Reactions:1
- Comments:7 (7 by maintainers)
Top GitHub Comments
Yes, exactly – @rtibbles and I chatted about this, and agree for the S2S use case it’s not a concern. And we can easily add the “create IA’s on full-facility-sync for users that have done single-user-syncs previously” in future versions if it starts to look like a practical issue.
The main thing that makes this messy is that many ways that a user can come to be assigned something:
So one thing @rtibbles and I talked about was that if we did essentially go with the “IA’s should always represent current assignment state”, we still need the current type of collection-level assignment structures so that we can re-compute the IA’s when stuff changes (on local activity as well as stuff syncing in). And that’s compatible with the direction this is heading in – but for now we’re only generating the IA’s at the time a single-user sync happens.
Fixed in #8219