feat: add optional external_id field#8390
Draft
LWS49 wants to merge 1 commit into
Draft
Conversation
0417ba7 to
c646bec
Compare
…itations
Allows institutions to link Coursemology enrolments to their own student
records or LMS identifiers. The field is stored on CourseUser and
Course::UserInvitation and validated unique per course across both tables
via a cross-table concern and partial DB index - a pending invitation holds
its ext_id until confirmed, preventing collisions with direct enrolments.
Surfaces:
- Individual invite form: ext_id input field
- Bulk CSV invite: ext_id column in both template variants (with and without
Timeline column); set on new records only - existing pending invitations
and enrolled users are read-only in this flow
- Manage users table: inline editable ext_id column (always visible)
- Score summary export: ext_id column included when any student has one
- Statistics > Students table: ext_id column, sortable and searchable,
shown only when at least one student has a non-null ext_id
View-only tables suppress the ext_id column when no course members have
one set, consistent with how group manager, gamification, and video columns
are conditionally shown. Edit tables always show it.
Also changes error responses from the invitations controller from a single
concatenated string to an array of per-record strings, enabling the frontend
to render overflow counts without truncating meaningful error detail.
c646bec to
d6e1808
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds an optional
external_idfield to course members and pending invitations, allowing institutions to link Coursemology enrolments to their own student records or LMS identifiers. The field is stored on bothCourseUserandCourse::UserInvitationand validated unique per course across both tables (a pending invitation "holds" an ext_id until confirmed).The field is exposed in five places: the individual invite form, the bulk CSV invite (two templates - with and without Timeline column, depending on whether personal timelines are enabled), the manage users table (inline editable), the score summary export, and the Statistics > Students table. View-only tables (score summary export, statistics table) show the ext_id column only when at least one enrolled student has a non-null ext_id; the manage users edit table always shows it. Error responses from the invitations controller are changed from a single concatenated sentence to an array of per-record strings; the individual invite form shows the first error with a count of remaining errors (e.g. "Email taken (and 2 more)") rather than a generic failure message.
Scope note: two things are intentionally deferred to follow-up PRs: (1) updating ext_ids on existing pending invitations or enrolled users via bulk invite - a follow-up PR will expose those updates in a dedicated result-dialog section with proper UX; (2) additional display surfaces (gradebook table, leaderboard, submission listings) - these are separate in scope.
Design decisions
It does not land in Existing Course USers because with current implementation, the unique identifier is strictly email. as External ID is nullable, while we maintain its uniqueness within the course, for now we want to keep things simple and keep email as the only unique identifier. Thus, we do not intrepret duplicate ext_id without duplicate email as the course user with said ext_id attempting to be re-enrolled.
User::Email- when a user adds an email that matches an existing invitation, the invitation is confirmed before theCourseUseris built. Without this,UniqueExternalIdConcernwould reject the newCourseUserfor sharing an ext_id with what is still a live invitation in the DB.Regression prevention
external_idis optional and blank-normalised to nil. All existing flows behave identically when no ext_id is provided.Complete feature intended behaviour
The following is what the bulk invite flow should do once the follow-up PR is implemented.
Intended decision tree (complete feature)
Key differences from the current PR