Skip to content

Conversation

@kristofnemere
Copy link
Contributor

@kristofnemere kristofnemere commented Nov 26, 2025

Summary

Fixed issue where cross-shard user submissions were throwing page errors. When a course is on a different shard than the user's home shard, the user ID now gets converted to a global user ID for API calls.

Changes:

  • Parse and store shard IDs from course tab URLs
  • Added APIHelper methods to extract shard IDs from access tokens and create global user IDs
  • Updated SubmissionDetailsEffectHandler to use global user IDs for cross-shard courses
  • Fixed DiscussionSubmissionViewFragment to handle override domains for routing and authentication
  • Added comprehensive unit tests for all new functionality

Test plan

  1. Sign in to a user account that has courses on different Canvas shards (cross-shard courses)
  2. Navigate to an assignment in a cross-shard course
  3. Open submission details
  4. Verify that the submission loads correctly without page errors
  5. Test discussion submission routing for cross-shard courses
  6. Verify that authentication works correctly for override domains

refs: MBL-19515
affects: Student
release note: Fixed errors when viewing submissions in courses across different Canvas shards

Fixed issue where cross-shard users would get page errors when viewing
their submission details and comments.

Changes:
- Added shard ID parsing from course tab URLs in EnabledTabs
- Created APIHelper methods for shard ID extraction and global user ID conversion
- Updated SubmissionDetailsEffectHandler to use global user IDs for cross-shard courses
- Updated DiscussionSubmissionViewFragment to handle override domains
- Injected ApiPrefs into SubmissionDetailsEffectHandler for better testability
- Added comprehensive unit tests for shard ID handling

Technical details:
- Parse shard IDs from tab.externalUrl (format: "https://domain.com/courses/7053~2848/...")
- Store shard IDs per course in ApiPrefs.shardIds map
- Extract shard ID from access token if present (format: "shardId~token")
- Convert user IDs to global format (shardId * 10^13 + userId) for cross-shard API calls
- Handle routing and authentication for override domains in discussion submissions

Test plan:
- Cross-shard user can view submission details without page error
- Same-shard user continues to work as before
- Discussion submissions route correctly for both main and override domains
- Unit tests verify shard ID parsing and conversion logic

Affects: Student

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
@kristofnemere kristofnemere changed the title [MBL-19515] Fix cross-shard user submissions [MBL-19515][Student] Fix cross-shard user submissions Nov 26, 2025
Copy link

@claude claude bot left a comment

Choose a reason for hiding this comment

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

Summary

This PR implements cross-shard course support for Canvas Android by handling cases where a user's courses exist on different shards than their account. The implementation adds shard ID tracking, global user ID conversion, and domain override handling for multi-shard scenarios.

Strengths

  • Comprehensive test coverage: Two new unit tests verify both cross-shard and same-shard scenarios in SubmissionDetailsEffectHandlerTest
  • Solid utility functions: APIHelper additions are well-structured with clear responsibilities
  • Good separation of concerns: Effect handler properly injects ApiPrefs dependency rather than using singleton directly
  • Consistent pattern: The domain override logic in DiscussionSubmissionViewFragment follows good encapsulation practices

Issues Found

  • Null safety concern in SubmissionDetailsEffectHandler.kt:75 - Using !! operator without null check (see inline comment)
  • Error handling needed in APIHelper.createGlobalUserId() - toLong() conversion can throw (see inline comment)
  • Empty string validation in DiscussionSubmissionViewFragment.kt:58 - Should check isNullOrEmpty() instead of just null (see inline comment)
  • Defensive programming in EnabledTabs.kt:79 - Consider using getOrNull() for safer array access (see inline comment)

Performance Considerations

  • The shard ID parsing from URL happens on each tab initialization, but this should be acceptable given it's a one-time setup operation
  • The getUserIdForCourse() function is efficient with simple map lookups and string comparisons

Architecture Notes

  • Follows MVVM pattern correctly with dependency injection via Hilt
  • Properly extends the existing ApiPrefs object with new shardIds map
  • Maintains backward compatibility by falling back to original behavior when shard IDs aren't present

Test Coverage

The new tests cover the critical scenarios:

  • ✅ Cross-shard course access with global user ID conversion
  • ✅ Same-shard course access without conversion
  • ✅ Shard ID extraction from tokens
  • ✅ Global user ID creation logic

Overall, this is a well-designed implementation with good test coverage. The inline comments highlight some defensive programming improvements that would make the code more robust against edge cases.

@github-actions
Copy link

github-actions bot commented Nov 26, 2025

📊 Code Coverage Report

✅ Student

  • PR Coverage: 42.80%
  • Master Coverage: 42.80%
  • Delta: +0.00%

✅ Teacher

  • PR Coverage: 25.45%
  • Master Coverage: 25.44%
  • Delta: +0.00%

✅ Pandautils

  • PR Coverage: 22.61%
  • Master Coverage: 22.61%
  • Delta: +0.00%

📈 Overall Average

  • PR Coverage: 30.29%
  • Master Coverage: 30.29%
  • Delta: +0.00%

Changes based on PR review comments:
- EnabledTabs.kt: Use getOrNull() for safer array access when parsing shard IDs
- APIHelper.kt: Add error handling for toLong() conversion in createGlobalUserId()
- DiscussionSubmissionViewFragment.kt: Check isNullOrEmpty() instead of just null for override domains

These changes improve null safety and error handling throughout the cross-shard submission code.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
@github-actions
Copy link

Student Install Page

Copy link
Contributor

@kdeakinstructure kdeakinstructure left a comment

Choose a reason for hiding this comment

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

QA 👍

@kristofnemere kristofnemere merged commit 9f41e62 into master Nov 27, 2025
67 of 69 checks passed
@kristofnemere kristofnemere deleted the MBL-19515-fix-cross-shard-submissions branch November 27, 2025 12:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants