-
Notifications
You must be signed in to change notification settings - Fork 0
feat(effort): VPR-46 - Effort verification #101
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
rlorenzo
commented
Jan 24, 2026
- Add My Effort page for instructors to self-verify effort data
- Implement verification reminder emails (individual and bulk)
- Add VerificationController/Service with Razor email templates
- Show verification status on instructor list with email buttons
- Add My Effort page for instructors to self-verify effort data - Implement verification reminder emails (individual and bulk) - Add VerificationController/Service with Razor email templates - Show verification status on instructor list with email buttons
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
Adds instructor self-service effort verification and verification reminder emailing, including Razor-based email template rendering and UI updates to support verification workflows.
Changes:
- Introduces Effort verification API (controller/service), settings, DTOs, and Razor email template(s) for verification reminders.
- Adds shared Razor email templating infrastructure (layout + renderer) and migrates ClinicalScheduler “Primary Evaluator Removed” email to Razor templates.
- Updates Vue Effort UI to add a “My Effort” page, show verification status, and provide single/bulk verification email actions.
Reviewed changes
Copilot reviewed 56 out of 56 changed files in this pull request and generated 10 comments.
Show a summary per file
| File | Description |
|---|---|
| web/appsettings.json | Adds default Effort verification email settings. |
| web/appsettings.Test.json | Adds EffortSettings BaseUrl for test environment links. |
| web/appsettings.Production.json | Adds EffortSettings BaseUrl for production environment links. |
| web/Viper.csproj | Adds Razor.Templating.Core dependency. |
| web/Program.cs | Registers VerificationService, EffortSettings options, and Razor templating services. |
| web/EmailTemplates/Views/_ViewImports.cshtml | Adds shared imports for email templates. |
| web/EmailTemplates/Views/Shared/_EmailLayout.cshtml | Adds shared HTML email layout for UC Davis branding. |
| web/EmailTemplates/Services/IEmailTemplateRenderer.cs | Defines abstraction for rendering Razor templates to HTML. |
| web/EmailTemplates/Services/EmailTemplateRenderer.cs | Implements Razor template rendering via Razor.Templating.Core. |
| web/EmailTemplates/Models/EmailViewModelBase.cs | Adds common email view-model base utilities (BaseUrl, absolute links). |
| web/Areas/Effort/Services/VerificationService.cs | Implements “My Effort” retrieval, verification, and reminder email logic. |
| web/Areas/Effort/Services/IVerificationService.cs | Defines verification service contract. |
| web/Areas/Effort/Services/IEffortPermissionService.cs | Adds HasAnyViewAccessAsync API for permission checks. |
| web/Areas/Effort/Services/EffortRecordService.cs | Auto-creates instructor record when creating an effort record (legacy parity). |
| web/Areas/Effort/Services/EffortPermissionService.cs | Updates current person lookup via VIPER People and adds HasAnyViewAccessAsync. |
| web/Areas/Effort/Models/DTOs/Responses/VerificationDtos.cs | Adds response DTOs for verification, emails, and “My Effort”. |
| web/Areas/Effort/Models/DTOs/Requests/VerificationRequests.cs | Adds request DTOs for single/bulk verification email sends. |
| web/Areas/Effort/Models/AutoMapperProfileEffort.cs | Adds mapping from EffortRecord → InstructorEffortRecordDto for display. |
| web/Areas/Effort/EmailTemplates/Views/VerificationReminder.cshtml | Adds Razor template for verification reminder email body. |
| web/Areas/Effort/EmailTemplates/Models/VerificationReminderViewModel.cs | Adds view model types for verification reminder email template. |
| web/Areas/Effort/EffortSettings.cs | Adds configurable Effort verification settings. |
| web/Areas/Effort/Controllers/VerificationController.cs | Adds verification API endpoints (self-service + admin email endpoints). |
| web/Areas/Effort/Controllers/TermsController.cs | Expands terms endpoint access to VerifyEffort users for self-service. |
| web/Areas/Effort/Constants/EffortPermissions.cs | Adds AnyViewAccess composed permission constant. |
| web/Areas/ClinicalScheduler/Services/ScheduleEditService.cs | Switches primary-evaluator-removed email construction to Razor template rendering. |
| web/Areas/ClinicalScheduler/EmailTemplates/Views/PrimaryEvaluatorRemoved.cshtml | Adds Razor template for primary evaluator removed notification email. |
| web/Areas/ClinicalScheduler/EmailTemplates/Models/PrimaryEvaluatorRemovedViewModel.cs | Adds view model for primary evaluator removed email template. |
| test/EmailTemplates/EmailTemplateRendererIntegrationTests.cs | Adds integration tests for Razor email rendering (currently has a compile issue). |
| test/Effort/VerificationServiceTests.cs | Adds unit tests for verification service behavior (renderer mock setup needs adjustment). |
| test/Effort/VerificationControllerTests.cs | Adds unit tests for verification controller endpoints. |
| test/Effort/Integration/EffortPermissionIntegrationTests.cs | Updates integration tests for new EffortPermissionService constructor. |
| test/Effort/EffortRecordServiceTests.cs | Updates tests for EffortRecordService constructor and new behavior. |
| test/Effort/EffortIntegrationTestBase.cs | Adds VIPERContext to Effort integration test base and seeds needed person data. |
| test/ClinicalScheduler/TestableScheduleEditService.cs | Updates testable service wrapper for new constructor dependency. |
| test/ClinicalScheduler/ScheduleEditServiceTest.cs | Updates ScheduleEditService tests for new dependency (needs renderer mock setup). |
| test/ClinicalScheduler/Integration/ControllerServiceIntegrationTest.cs | Updates integration wiring for new ScheduleEditService constructor dependency. |
| test/ClinicalScheduler/EmailNotificationTest.cs | Updates notification tests for Razor rendering (generic mock setup needs adjustment). |
| scripts/verify-build.js | Improves captured build error output when error.output is empty. |
| scripts/lib/build-cache.js | Improves cached error messaging and expands error filtering patterns. |
| VueApp/src/Effort/types/verification-types.ts | Adds TypeScript types for verification feature APIs. |
| VueApp/src/Effort/types/index.ts | Re-exports verification types for consumers. |
| VueApp/src/Effort/services/verification-service.ts | Adds Vue API client for verification endpoints. |
| VueApp/src/Effort/router/routes.ts | Adds “My Effort” route and applies view-level permission meta to base routes. |
| VueApp/src/Effort/pages/MyEffort.vue | Adds instructor “My Effort” verification page UI. |
| VueApp/src/Effort/pages/InstructorList.vue | Shows verification status and adds single/bulk verification email actions. |
| VueApp/src/Effort/pages/InstructorDetail.vue | Improves edit/add flows and warns about verification implications on record changes. |
| VueApp/src/Effort/pages/CourseList.vue | Adds async load race-condition protection and improves accessibility labels. |
| VueApp/src/Effort/pages/CourseDetail.vue | Adds accessibility labels for key actions. |
| VueApp/src/Effort/components/InstructorEditDialog.vue | Adds accessibility label for close action. |
| VueApp/src/Effort/components/InstructorAddDialog.vue | Adds accessibility label for close action. |
| VueApp/src/Effort/components/EffortRecordEditDialog.vue | Adds verification warning banner and accessibility improvements. |
| VueApp/src/Effort/components/EffortRecordAddDialog.vue | Adds verification warning banner, course preselect support, and accessibility improvements. |
| VueApp/src/Effort/components/EffortLeftNav.vue | Adds “My Effort” nav entry and accessibility label for close action. |
| VueApp/src/Effort/components/CourseImportDialog.vue | Emits imported courseId to enable follow-up “Add Effort” flow. |
| VueApp/src/Effort/components/CourseEditDialog.vue | Adds accessibility label for close action. |
| VueApp/src/Effort/components/CourseAddDialog.vue | Adds accessibility label for close action. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
…ords - Skip sending emails to instructors with no effort data; show N/A status - Add CanSendVerificationEmail property for email eligibility checks - Sanitize department code in bulk email logging (log injection fix) - Add keyboard accessibility to email action icons
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
Copilot reviewed 62 out of 62 changed files in this pull request and generated 3 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Filter bulk verification emails to only instructors with effort records - Convert ChildCourseInfo to private sealed record for better encapsulation - Fix test mock setup for instructor-not-found error path
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
Copilot reviewed 62 out of 62 changed files in this pull request and generated 3 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Add audit entry for invalid email addresses in verification emails - Use toLocaleString for date+time display on verification timestamps
|
@bsedwards Example of the new email template |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
Copilot reviewed 62 out of 62 changed files in this pull request and generated 5 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Cache personId lookup in EffortPermissionService to avoid repeated DB queries - Validate BaseUrl configuration before sending email to fail fast on misconfiguration - Add proper URL format validation for BaseUrl setting - Switch keyboard handlers from keyup to keydown.prevent to avoid double-firing
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
Copilot reviewed 62 out of 62 changed files in this pull request and generated 1 comment.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
@bsedwards Improved the email templates: No effort template. Added term dates under the term:
Also, made the templates mobile responsive:
|
- Enable verification for instructors without effort records - Add term dates and "no effort" messaging to verification emails - Show "No Effort" badge and distinct verification icons in UI - Make email layout responsive for mobile devices - Fix Vite HMR config for secure WebSocket connections
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
Copilot reviewed 63 out of 63 changed files in this pull request and generated 7 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
…matting - Replace VIPERContext MothraId lookup with direct AaudUserId from user context - Remove VIPERContext dependency from EffortPermissionService and tests - Trim SubjCode and SeqNumb in course code formatting (4 locations) - Update RecordCount comment to reflect "no effort" verification support
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
Copilot reviewed 80 out of 82 changed files in this pull request and generated 3 comments.
Files not reviewed (1)
- VueApp/package-lock.json: Language not supported
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Pass credentials via curl stdin config instead of CLI args - Validate tokens contain only safe alphanumeric characters - Require HTTPS URLs and validate format before use - Use set -a/source instead of brittle export/xargs parsing - Use --ssl-revoke-best-effort for internal server CRL issues
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
Copilot reviewed 80 out of 82 changed files in this pull request and generated no new comments.
Files not reviewed (1)
- VueApp/package-lock.json: Language not supported
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
Copilot reviewed 80 out of 82 changed files in this pull request and generated 2 comments.
Files not reviewed (1)
- VueApp/package-lock.json: Language not supported
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
…ading - Add LastEmailed/LastEmailedBy columns to Persons table with FK to avoid audit table scans; includes post-deployment migration with backfill - Add read-only cross-schema entity for single-query sender name resolution - Consolidate email and edit/delete into single Actions column in UI
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
Copilot reviewed 87 out of 89 changed files in this pull request and generated 2 comments.
Files not reviewed (1)
- VueApp/package-lock.json: Language not supported
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Automates merge workflow with safety checks: clean working dir, commits pushed, no divergence; auto-retries with rebase on conflict - Fix hardcoded "7 days" in InstructorList to use config value - Remove redundant HasColumnName mappings for ViperPerson entity
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
Copilot reviewed 89 out of 91 changed files in this pull request and generated 3 comments.
Files not reviewed (1)
- VueApp/package-lock.json: Language not supported
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Enable sending multiple verification emails simultaneously by using Sets instead of single-value state for tracking in-progress sends - Block emails to already-verified instructors with 409 Conflict response - Add Range validation to PersonId and TermCode request parameters - Extend navigation guards to warn on any in-progress email operation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
Copilot reviewed 89 out of 91 changed files in this pull request and generated 2 comments.
Files not reviewed (1)
- VueApp/package-lock.json: Language not supported
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Invert to fail-safe: require "0 Error(s)" or "Build succeeded." to pass - Rename hasActualErrors() to isConfirmedWarningsOnly() - Expand filterBuildErrors() to catch more error types
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
Copilot reviewed 89 out of 91 changed files in this pull request and generated 2 comments.
Files not reviewed (1)
- VueApp/package-lock.json: Language not supported
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
@bsedwards Ready for review again. Highlights of recent changes:
|
|
@rlorenzo Was trying to get to the effort entry for an instructor. On the instructor list, clicking their name should take you to their effort. Currently it opens the edit dialog like the edit button. |
|
@bsedwards, I fixed it in the other branch: #102, since it was related to making the modal for Instructor editing a link. But that brings up a UX issue. Right now, in the instructor listing, if you click on the Instructor's name, you go to a separate page to see the Instructor's effort. Then, if you click the edit icon, you'll see a modal where you can edit the instructor's details and the assignment percentage. It isn't good UX to have both a separate page and a modal for similar actions to access a CRUD screen. We can do the following options:
Might be simpler to do 2, but option 3 is interesting. Thoughts? |
|
If I had to guess, I would say 90% of department staff work is looking at the effort for an instructor. The instructor edit page has info that is a) auto imported, like job code and department, and only updated if it's incorrect by Academic Programs or b) the percent assignment, again edited by Academic Programs and mostly via the other page. So, I think the instructor effort page is where department staff and faculty (when verifying or now entering their own effort) interact the most. Having instructor effort be a full page makes the most sense, though I understand the UX reason for a modal so the user doesn't lose their place. I thinking both of people's resistance to change, and also how it looks if their list is long. Option three seems like it could work, but we should double check if department staff can use the edit button currently. If it's just AP that can edit the instructor then assess if it's worth it. Thanks for the thoughtful approach.
|
|
@bsedwards, For now, I will keep them both open on separate pages, for someone like BANNASCH, DANIKA, who has a long history of percent assignments dating back to 2002, using it in a modal is cumbersome. |


