feat(invitations): multi-language CSV parsing, locale templates, and external ID conflict resolution#8427
Open
LWS49 wants to merge 2 commits into
Open
feat(invitations): multi-language CSV parsing, locale templates, and external ID conflict resolution#8427LWS49 wants to merge 2 commits into
LWS49 wants to merge 2 commits into
Conversation
37a5204 to
211f960
Compare
211f960 to
67de552
Compare
1314602 to
121b8a7
Compare
23c59ca to
559264e
Compare
546aed9 to
b379882
Compare
121b8a7 to
b8b6ea2
Compare
b761414 to
db5b8c8
Compare
b8b6ea2 to
41090fe
Compare
d2db7b1 to
fd1f9ca
Compare
6a0574f to
e89d94b
Compare
e89d94b to
9cfbad4
Compare
d56c8f3 to
03143e6
Compare
… resolution - validate CSV column headers explicitly instead of checking column count - detect external ID changes on existing users/invitations before applying; surface a confirmation prompt (Keep Existing / Replace) with a side-by-side Current / New External ID table capped at 320px for large uploads - conflict resolution wired into both file upload and individual invite form; file ref preserved on Go Back so admin need not re-select - add ExternalIdResolution and PendingExternalIdConflict types; update invite API and operations layer to detect and return conflict payload - controller rescues PendingExternalIdUpdates, renders jbuilder partial; concern branches on @resolution to populate pending vs updated arrays - i18n: add EN/KO/ZH translations for conflict prompt and new table columns
180a6af to
49f1663
Compare
77c57cc to
cca3bcd
Compare
…anonical column order, and locale-specific CSV templates
cca3bcd to
d38fa7f
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
Rewrites the course invitation CSV pipeline across four areas. Header parsing is now order-independent and language-aware: English, Chinese, and Korean header rows are all accepted via a union alias map, removing the previous positional and English-only assumptions. Six locale-specific downloadable templates (en/zh/ko × timeline/no-timeline) replace the two English-only ones, with UTF-8 BOM so Excel opens zh/ko files without garbling the characters. Header validation is strict — the uploaded file must contain exactly the expected columns for the course's timeline setting, and duplicate columns (including cross-language duplicates like
Name+姓名) are now detected and rejected. External ID uploads to courses with existing members or pending invitations now go through a conflict resolution flow: the first pass defaults to keep-existing, and any file values that differ from stored are surfaced as an optional Apply action in the results dialog, with Undo. Finally, external ID is included in the user search across Manage Users and Student Statistics.Design decisions
Design Considerations
One combined diff section with sub-labels vs. two independent sections
Decision: Merge pending-update rows for invitations and enrolled members into a single "External ID updates" section with one atomic Apply covering both; distinguish them with sub-table headings rather than per-row badges or two independent Apply controls.
Why considered: Two visible tables naturally invite the expectation of two independent controls.
For:
Against:
Alternatives:
Rationale: I chose one combined section because the control granularity was already settled as atomic upstream. Matching the single action avoids implying a selectivity that the backend doesn't support, and sub-labels reuse the dialog's existing structural convention.
Accept all 3 locales regardless of UI locale
Decision: The parser accepts English, Chinese, and Korean header rows via one global union alias map, independent of
I18n.locale.Why considered: The obvious alternative is to accept only headers matching the user's current UI language.
For:
Against:
Alternatives:
I18n.locale- rejected; produces brittle, surprising rejections with no upside and is more code.Rationale: I chose the union map because tying parse acceptance to UI locale solves no real problem and creates failure modes; the disjoint character sets mean there is no collision risk to mitigate.
Static per-language templates + guard test, not a generated endpoint
Decision: Ship 6 static CSV templates and add an RSpec guard asserting each template's header row is accepted by the parser.
Why considered: A backend-generated template would have a single source of truth between the template and the parser.
For:
Against:
Alternatives:
csv.yml).Rationale: I chose static + guard test because the DRY benefit of generation was largely illusory; the client i18n and backend csv.yml would still need to stay in sync regardless. Static files with a CI guard give the safety of generation with none of the moving parts.
Regression prevention
Covers: multi-language header parsing (en/zh/ko accepted, mixed-language headers accepted), order-independent column resolution, exact-column validation (timeline vs. no-timeline mismatch rejected), duplicate column detection (same-language and cross-language), external ID conflict detection and keep-existing default, conflict resolution (apply and undo), external ID dedup across new invitations and existing records, re-invitation with external ID update, search by external ID in Manage Users and Student Statistics.
Manual testing: all scenarios above confirmed - zh/ko templates open without garbled characters in Excel, multi-language uploads parse correctly, duplicate-column uploads error with the offending column named, external ID conflict prompt appears and apply/undo work correctly for both invited and enrolled members, external ID search returns results.