-
Notifications
You must be signed in to change notification settings - Fork 0
feat(auth-service): email linking from auth service [LFXV2-502] #130
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?
feat(auth-service): email linking from auth service [LFXV2-502] #130
Conversation
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.
Conventional Commits FTW!
|
Note Other AI code review bot(s) detectedCodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review. WalkthroughAdds a complete email verification feature: frontend modal and profile UI updates, new client methods, server endpoints and EmailService using NATS request/reply, plus shared NATS subject enum additions and new user-email types. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant UI as Client UI / Modal
participant API as Backend API
participant NATS as NATS Service
User->>UI: Request verification for email
UI->>API: POST /api/profile/emails/send-verification { email }
API->>NATS: EMAIL_LINKING_SEND_VERIFICATION
NATS-->>API: ack / success
API-->>UI: { success: true }
UI-->>User: Open verification modal (timer starts)
User->>UI: Submit 6‑digit code
UI->>API: POST /api/profile/emails/verify { email, otp }
API->>NATS: EMAIL_LINKING_VERIFY
NATS-->>API: { otp verified, id_token }
API->>NATS: USER_IDENTITY_LINK (with id_token)
NATS-->>API: identity linked
API-->>UI: { success: true }
UI-->>User: Modal closes — email linked
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes
Possibly related PRs
Suggested labels
Pre-merge checks and finishing touches❌ Failed checks (1 inconclusive)
✅ Passed checks (4 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: CHILL Plan: Pro Disabled knowledge base sources:
📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
Comment |
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
This PR implements email linking functionality that integrates with Auth0 authentication, enabling users to verify and link alternate email addresses through a secure OTP verification workflow.
Key Changes:
- Added backend email verification service with NATS integration for Auth0 communication
- Created new API endpoints for sending verification codes and verifying/linking emails
- Implemented frontend verification modal component with 6-digit OTP input and timer functionality
Reviewed Changes
Copilot reviewed 11 out of 11 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/shared/src/interfaces/user-profile.interface.ts | Added TypeScript interfaces for alternate emails and user email data structures |
| packages/shared/src/enums/nats.enum.ts | Defined new NATS subjects for email linking and identity management operations |
| apps/lfx-one/src/server/services/email.service.ts | Implemented core email verification service with OTP handling and identity linking |
| apps/lfx-one/src/server/services/user.service.ts | Added getUserEmails method to fetch user email data via NATS |
| apps/lfx-one/src/server/routes/profile.route.ts | Registered new email verification and linking API endpoints |
| apps/lfx-one/src/server/controllers/profile.controller.ts | Implemented controller methods for email verification flow and updated getUserEmails to use NATS |
| apps/lfx-one/src/app/shared/services/user.service.ts | Added frontend service methods for email verification API calls |
| apps/lfx-one/src/app/modules/profile/email/profile-email.component.ts | Updated email management component to trigger verification modal and handle responses |
| apps/lfx-one/src/app/modules/profile/email/profile-email.component.html | Modified UI to display email field errors and simplified email management text |
| apps/lfx-one/src/app/modules/profile/email/email-verification-modal/email-verification-modal.component.ts | Created modal component with OTP input handling, timer, and paste functionality |
| apps/lfx-one/src/app/modules/profile/email/email-verification-modal/email-verification-modal.component.html | Implemented modal UI with 6-digit code input, countdown timer, and error messaging |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
2b2abcc to
86b1dee
Compare
86b1dee to
d89b6e4
Compare
…d users - Add auto-join functionality that opens Zoom meetings automatically for signed-in users - Implement timeout-based execution to prevent infinite loops and toast spam - Add proper state management with hasAutoJoined signal to prevent multiple attempts - Include fallback manual join option if auto-join fails - Add component cleanup with ngOnDestroy to prevent memory leaks - Update UI to show auto-join status with success message and manual fallback - Respect existing timing constraints (early join time window) 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> Signed-off-by: Jordan Evans <jevans@linuxfoundation.org> Signed-off-by: Mauricio Zanetti Salomao <msalomao@contractor.linuxfoundation.org>
- Replace any timeout type with proper ReturnType<typeof setTimeout> - Extract ternary logic from template into computed signals for better maintainability - Add data-testid attributes for reliable e2e testing (join-status-message, join-meeting-button-*) - Implement secure popup handling with opener clearing and popup blocker detection - Add fallback messaging for blocked popups with auto-join flag reset - Apply code formatting and resolve linting issues 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> Signed-off-by: Jordan Evans <jevans@linuxfoundation.org> Signed-off-by: Mauricio Zanetti Salomao <msalomao@contractor.linuxfoundation.org>
… opening - Remove isJoining() dependency from auto-join effect to prevent re-triggering - Eliminate hasAutoJoined flag resets that caused infinite loops - Remove popup blocker detection and toast notifications - Ensure all join buttons use click handler for consistent new tab behavior - Simplify openMeetingSecurely method for reliable URL opening 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> Signed-off-by: Jordan Evans <jevans@linuxfoundation.org> Signed-off-by: Mauricio Zanetti Salomao <msalomao@contractor.linuxfoundation.org>
Update the meeting join page login button to use LFX brand blue colors instead of gray for better visibility and prominence when users are not authenticated. Changes include: - Apply bg-brand-500 (primary LFX blue) background - Add hover:bg-brand-600 for darker blue on hover - Use white text for high contrast - Increase padding from px-2 py-1 to px-3 py-2 - Add font-medium weight and shadow-sm for visual emphasis 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> Signed-off-by: Jordan Evans <jevans@linuxfoundation.org> Signed-off-by: Mauricio Zanetti Salomao <msalomao@contractor.linuxfoundation.org>
…ion (#119) * wip(dashboard): initial core persona developer dashboard implementation Work in progress implementation for LFXV2-644. Adding foundational components and structure for the Core Developer Persona dashboard. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> Signed-off-by: Jordan Evans <jevans@linuxfoundation.org> * feat(dashboard): improve core developer persona dashboard UI Reduce section header sizes from text-xl to text-lg for better visual hierarchy. Enhance meetings section with modern card design, calendar icons, participant badges, and Join buttons. Fix ESLint member ordering issues for LFXV2-644. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> Signed-off-by: Jordan Evans <jevans@linuxfoundation.org> * fix(layout): prevent sidebar from floating during horizontal scroll Change sidebar from fixed to sticky positioning within a flex container. This ensures the sidebar stays in its designated column and doesn't cover content during horizontal scrolling. Updates for LFXV2-644. - Wrap sidebar in flex-shrink-0 container with fixed width - Change sidebar positioning from fixed to sticky - Remove margin-left from main content, use min-w-0 for proper scrolling - Maintain sticky behavior for vertical scrolling within column 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> Signed-off-by: Jordan Evans <jevans@linuxfoundation.org> * style(dashboard): further reduce section header sizes Change section headers from text-lg to text-base for a more compact and modern dashboard appearance. Reduces visual hierarchy emphasis on section titles in favor of content focus for LFXV2-644. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> Signed-off-by: Jordan Evans <jevans@linuxfoundation.org> * feat(dashboard): integrate meetings API with occurrence-based filtering Replace hardcoded meeting data with live API integration that properly handles: - Meeting occurrences for recurring meetings - Time-based filtering with 40-minute buffer after meeting end - Sorting by earliest time first - Frontend limit to 5 meetings maximum - Smart time formatting (Today/Tomorrow/Date) - Total attendee count from registrants and committee members 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * feat(dashboard): implement persona-based dashboard architecture - Replace home-new component with modular dashboard architecture - Add persona-specific dashboard components (my-meetings, my-projects, pending-actions, recent-progress) - Implement persona service with reactive persona selection - Update sidebar with footer navigation support and improved styling - Match sidebar border/shadow styling with PrimeNG card components - Add persona selector component with dropdown interface - Update header to integrate persona selector - Add persona constants to shared package - Update main layout to support dynamic persona-based routing - Update profile layout to handle persona changes - Server-side: Fix user profile persona field mapping Technical improvements: - Sidebar: Remove border, update border-radius to 12px, match card shadow - Sidebar: Add footer items support with separate navigation section - Sidebar: Improve accessibility with consistent text sizing (text-sm) - Remove icon hover animations for visual consistency LFXV2-644 Signed-off-by: Asitha de Silva <asithade@gmail.com> * refactor(sidebar): replace function calls with computed signals - Remove getTestId() function calls from template - Add testId property to SidebarMenuItem interface - Create computed signals (itemsWithTestIds, footerItemsWithTestIds) for test ID generation - Use Angular signals pattern for better performance and change detection Performance improvements: - Computed signals only recalculate when input changes - Eliminates repeated function calls during template rendering - Leverages Angular 19 zoneless change detection optimization LFXV2-644 Signed-off-by: Asitha de Silva <asithade@gmail.com> * fix(dashboard): resolve pr comments Signed-off-by: Asitha de Silva <asithade@gmail.com> * fix(yarn): yarn.lock update Signed-off-by: Asitha de Silva <asithade@gmail.com> * feat(dashboard): implement dashboard meeting card component - Create reusable DashboardMeetingCardComponent for displaying meeting information - Update MyMeetingsComponent to use new card component with Today/Upcoming sections - Add conditional section rendering (hide sections when empty) - Match React component styling with white card background, gray icons, rounded-xl borders - Implement smart date filtering for today's meetings vs upcoming meetings - Add meeting feature icons (YouTube, Recording, Transcripts, AI, Public/Private) - Add DashboardMeetingCardProps and DashboardMeetingFeatures interfaces to shared package - Update RecentProgressComponent styling to match React design - Remove PrimeNG Card dependency in favor of semantic HTML with Tailwind LFXV2-644 Signed-off-by: Asitha de Silva <asithade@gmail.com> * refactor(dashboard): update pending actions and meeting card layout - Remove LFX card wrapper from pending actions component - Add consistent header with "View All" button to pending actions - Simplify pending action button styling to white background with slate-100 hover - Update dashboard meeting card to use project_name from meeting data - Add project_name enrichment in meeting service - Remove projectName input from dashboard meeting card component - Add project_name field to Meeting interface Generated with [Claude Code](https://claude.ai/code) Signed-off-by: Asitha de Silva <asithade@gmail.com> * refactor(dashboard): update my-projects with table layout - Replace card-based layout with lfx-table component - Implement 4-column table structure (Project, Affiliations, Code Activities, Non-Code Activities) - Apply React-style formatting: - Equal column widths (w-1/4 for each column) - Fixed chart container width (12.5rem) - Grey borders (border-gray-200) on table cells - Rounded table container with overflow handling - Blue project name links (#009aff) - Help icons for activity columns - Update chart colors: - Code Activities: #009AFF (blue) - Non-Code Activities: #10b981 (green) - Add generateLabels() helper method for dynamic chart labels - Remove unused CardComponent import - Maintain all existing test IDs for E2E compatibility Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> Signed-off-by: Asitha de Silva <asithade@gmail.com> * ci(gha): disable automatic quality check workflow Disabled automatic PR quality checks as project is moving away from old UI. Changed trigger from pull_request to workflow_dispatch for manual runs only. LFXV2-644 Generated with [Claude Code](https://claude.ai/code) Signed-off-by: Asitha de Silva <asithade@gmail.com> --------- Signed-off-by: Jordan Evans <jevans@linuxfoundation.org> Signed-off-by: Asitha de Silva <asithade@gmail.com> Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: Asitha de Silva <asithade@gmail.com> Signed-off-by: Mauricio Zanetti Salomao <msalomao@contractor.linuxfoundation.org>
…126) * fix(meeting-join): refactor auto-join logic to prevent infinite loop - Remove OnDestroy lifecycle and timeout cleanup - Simplify auto-join using RxJS filter and take(1) operators - Create fetchedJoinUrl signal for preemptive URL fetching - Convert join buttons to use href instead of click handlers - Add security attributes to button component links - Fix project logo centering and sizing LFXV2-669 Generated with [Claude Code](https://claude.ai/code) Signed-off-by: Asitha de Silva <asithade@gmail.com> * fix(ui): pass in link target and rel for buttons Signed-off-by: Asitha de Silva <asithade@gmail.com> * fix(ui): pass in link target and rel for buttons Signed-off-by: Asitha de Silva <asithade@gmail.com> * fix(meeting-join): add loading and error handling for join URL LFXV2-669 - Add loading spinner while fetching join URL - Display error messages when join URL fetch fails - Separate authenticated and unauthenticated user flows - Add debouncing (300ms) to form status changes to prevent rapid re-fetches - Improve user feedback with loading states in both authenticated and form sections - Reset error state on each fetch attempt Signed-off-by: Asitha de Silva <asithade@gmail.com> * refactor(meeting-join): simplify bindings and eliminate duplication Simplified button href and disabled bindings by removing redundant canJoinMeeting() checks since fetchedJoinUrl() already returns undefined when the meeting cannot be joined. Refactored initializeFetchedJoinUrl() to eliminate code duplication: - Extracted common join URL fetching logic into fetchJoinUrl() method - Removed duplicate API call handling for authenticated/unauthenticated flows - Removed signal mutation anti-pattern (meeting.join_url assignment) - Improved maintainability with single source of truth for fetch logic Generated with [Claude Code](https://claude.ai/code) Signed-off-by: Asitha de Silva <asithade@gmail.com> --------- Signed-off-by: Asitha de Silva <asithade@gmail.com> Signed-off-by: Mauricio Zanetti Salomao <msalomao@contractor.linuxfoundation.org>
…#127) - Add Maintainer as new persona option - Migrate dashboard to new dashboards module structure - Rename existing dashboard to Core Developer dashboard - Create Maintainer dashboard with persona-specific metrics - Implement persona-aware pending actions with computed signals - Implement persona-aware progress metrics with line and bar charts - Move shared dashboard components to centralized location - Update routing to use new dashboard component structure LFXV2-649 Signed-off-by: Asitha de Silva <asithade@gmail.com> Signed-off-by: Mauricio Zanetti Salomao <msalomao@contractor.linuxfoundation.org>
…l and API integration - Add EmailVerificationModalComponent for user to input verification code - Implement sendEmailVerification and verifyAndLinkEmail methods in UserService - Update ProfileEmailComponent to handle email verification process - Remove old resend verification button and logic - Integrate NATS communication for sending verification codes and verifying OTP - Enhance server-side profile controller to manage email verification requests Jira Ticket: https://linuxfoundation.atlassian.net/browse/LFXV2-501 Generated with [Cursor](https://cursor.com/) Signed-off-by: Mauricio Zanetti Salomao <mauriciozanetti86@gmail.com> Signed-off-by: Mauricio Zanetti Salomao <msalomao@contractor.linuxfoundation.org>
#128) Multiple enhancements across the application: - LFXV2-670: Relocate footer to main layout for consistency - LFXV2-671: Replace "old-ui" with "home" persona and simplify routing - LFXV2-672: Add scrollable containers and refactor dashboard charts - LFXV2-673: Add meeting attachments display with file type icons - LFXV2-674: Enhance meeting join with password support and new tab - LFXV2-675: Improve error handling and null safety across services Generated with [Claude Code](https://claude.ai/code) Signed-off-by: Asitha de Silva <asithade@gmail.com> Signed-off-by: Mauricio Zanetti Salomao <msalomao@contractor.linuxfoundation.org>
* feat(backend): add snowflake data warehouse integration (LFXV2-671) - Add SnowflakeService with connection pooling, query execution, and caching - Implement LockManager for distributed operations and resource coordination - Add Snowflake-related interfaces, enums, and constants to shared package - Add comprehensive architecture documentation for Snowflake integration - Configure environment variables for Snowflake connection - Add @snowflake-sdk/client dependency This integration enables server-side data warehouse queries with proper connection management, query optimization, and distributed locking. Signed-off-by: Asitha de Silva <asithade@gmail.com> * feat(analytics): implement snowflake integration with error handling - Add AnalyticsController with three endpoints: * GET /api/analytics/active-weeks-streak (52 weeks of activity data) * GET /api/analytics/pull-requests-merged (last 30 days) * GET /api/analytics/code-commits (last 30 days) - Implement proper error handling: * AuthenticationError (401) for missing user email * ResourceNotFoundError (404) for no analytics data * Consistent error propagation via next(error) - Use SQL window functions for accurate aggregations: * SUM(DAILY_COUNT) OVER () for totals across filtered results * DATEADD(DAY, -30, CURRENT_DATE()) for 30-day filtering - Add analytics data interfaces to shared package: * ActiveWeeksStreakRow/Response * UserPullRequestsRow/Response * UserCodeCommitsRow/Response - Update frontend dashboard with Chart.js visualizations: * Interactive tooltips with formatted dates and counts * Real-time data from Snowflake via analytics service - Update Snowflake integration documentation: * Focus on service architecture and best practices * Add examples for parameterized queries and lazy initialization * Document error handling patterns for callers - Update .env.example with analytics endpoint usage comments LFXV2-671 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> Signed-off-by: Asitha de Silva <asithade@gmail.com> * feat(auth): add authelia support and refactor profile to use nats - Add Authelia OIDC claims middleware for Auth0 compatibility - Transform standard OIDC claims to Auth0 format - Only activates for non-Auth0 users (issuer check) - Maps preferred_username, splits name into given/family - Modifies user object in-place (not replaceable) - Refactor profile controller to use NATS exclusively - Remove Supabase dependency for user profile data - Construct UserProfile from OIDC token claims - Use NATS as sole authoritative source for metadata - Email management methods still use Supabase - Change user metadata field from 'title' to 'job_title' - Update UserMetadata interface - Update frontend components (profile edit, layout, header) - Update backend validation logic - Ensure consistent field naming across all layers - Clean up debug logging - Remove console.log statement from server.ts - Simplify authelia userinfo fetch logic - Minor improvements - Remove unused 'open' dependency from angular.json - Fix header component formatting - Optimize auth-helper to use OIDC data directly Generated with [Claude Code](https://claude.ai/code) Signed-off-by: Asitha de Silva <asithade@gmail.com> * build: configure snowflake sdk logging and add to gitignore - Set Snowflake SDK log level to ERROR by default - Add SNOWFLAKE_LOG_LEVEL environment variable support - Prevent snowflake.log from being committed to repository Signed-off-by: Asitha de Silva <asithade@gmail.com> * fix(server): remove middleware Signed-off-by: Asitha de Silva <asithade@gmail.com> --------- Signed-off-by: Asitha de Silva <asithade@gmail.com> Co-authored-by: Claude <noreply@anthropic.com> Signed-off-by: Mauricio Zanetti Salomao <msalomao@contractor.linuxfoundation.org>
- Update ProfileEmailComponent to manage email input errors and provide user feedback for already linked emails. - Modify email verification modal to display error messages for invalid verification codes and handle pasting of digits. - Integrate NATS for fetching user emails and transform response for frontend compatibility. - Temporarily disable email deletion and primary email management features, with informative messages for users. Jira Ticket: https://linuxfoundation.atlassian.net/browse/LFXV2-502 Generated with [Cursor](https://cursor.com/) Signed-off-by: Mauricio Zanetti Salomao <mauriciozanetti86@gmail.com> Signed-off-by: Mauricio Zanetti Salomao <msalomao@contractor.linuxfoundation.org>
d89b6e4 to
7afef47
Compare
…cation methods - Refactor sendEmailVerification and verifyAndLinkEmail methods for better readability and consistency. - Enhance error handling for invalid email and OTP inputs with detailed logging. - Update documentation comments to clarify the email verification and linking flow steps. Jira Ticket: https://linuxfoundation.atlassian.net/browse/LFXV2-252 Generated with [Cursor](https://cursor.com/) Signed-off-by: Mauricio Zanetti Salomao <msalomao@contractor.linuxfoundation.org>
c7a5197 to
b74a40d
Compare
… and input events - Clear previous error messages when submitting the verification code, typing, or pasting input. - Improve user experience by ensuring error messages are reset appropriately during interactions. Jira Ticket: https://linuxfoundation.atlassian.net/browse/LFXV2-502 Generated with [Cursor](https://cursor.com/) Signed-off-by: Mauricio Zanetti Salomao <msalomao@contractor.linuxfoundation.org>
b74a40d to
eb05bab
Compare
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.
Actionable comments posted: 3
🧹 Nitpick comments (5)
apps/lfx-one/src/app/modules/profile/email/email-verification-modal/email-verification-modal.component.html (1)
51-102: Bring data-testid names in line with our conventionThe new modal test ids (
digit-*-input,resend-link,resend-code-button, etc.) don’t follow the required[section]-[component]-[element]format. Please rename them accordingly (e.g.,profile-emailVerificationModal-digit-1-input,profile-emailVerificationModal-resend-link,profile-emailVerificationModal-resend-code-button), and update all new ids in this template so automated tests remain consistent. As per coding guidelines.Also applies to: 128-149
apps/lfx-one/src/app/modules/profile/email/profile-email.component.ts (1)
69-71: Guard the valueChanges subscription lifecycle
valueChanges.subscribein the constructor never tears down, so the component holds a live subscription for its entire lifetime. Pipe it throughtakeUntilDestroyed()(from@angular/core/rxjs-interop) so Angular disposes it when the component is destroyed.-import { toSignal } from '@angular/core/rxjs-interop'; +import { takeUntilDestroyed, toSignal } from '@angular/core/rxjs-interop'; @@ - this.addEmailForm.get('email')?.valueChanges.subscribe(() => { + this.addEmailForm + .get('email') + ?.valueChanges.pipe(takeUntilDestroyed()) + .subscribe(() => { this.emailFieldError.set(null); });apps/lfx-one/src/server/services/email.service.ts (2)
85-149: Consider error codes instead of string matching.Lines 115 and 201 use string matching (
includes('already linked')) to detect specific error cases. This is fragile and could break if error messages change.Consider having the auth service return structured error responses with error codes:
- if (result.error?.includes('already linked')) { + if (result.errorCode === 'EMAIL_ALREADY_LINKED') { throw ServiceValidationError.forField('email', 'This email address is already linked to an account', {This would require coordinating with the auth service to return
errorCodefields in error responses.
255-317: Consider basic token format validation.The method only checks token presence but doesn't validate format. While the auth service will validate tokens, a basic JWT format check (three base64 segments separated by dots) could provide faster feedback for malformed tokens.
// Validate tokens if (!userToken || !linkWithToken) { throw ServiceValidationError.forField('token', 'User token and link token are required', { operation: 'link_identity', service: 'email_service', path: '/nats/user-identity/link', }); } + + // Basic JWT format validation (three segments separated by dots) + const jwtRegex = /^[A-Za-z0-9-_]+\.[A-Za-z0-9-_]+\.[A-Za-z0-9-_]+$/; + if (!jwtRegex.test(userToken) || !jwtRegex.test(linkWithToken)) { + throw ServiceValidationError.forField('token', 'Invalid token format', { + operation: 'link_identity', + service: 'email_service', + path: '/nats/user-identity/link', + }); + }apps/lfx-one/src/app/modules/profile/email/email-verification-modal/email-verification-modal.component.ts (1)
78-136: Consider simplifying code concatenation.Line 87 manually concatenates all six digit values. This could be more maintainable using Object.values or an array approach.
- const code = `${this.verificationForm.value.digit1}${this.verificationForm.value.digit2}${this.verificationForm.value.digit3}${this.verificationForm.value.digit4}${this.verificationForm.value.digit5}${this.verificationForm.value.digit6}`; + const code = Object.values(this.verificationForm.value).join('');This is more concise and would work even if the number of digits changes in the future.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
Disabled knowledge base sources:
- Jira integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (11)
apps/lfx-one/src/app/modules/profile/email/email-verification-modal/email-verification-modal.component.html(1 hunks)apps/lfx-one/src/app/modules/profile/email/email-verification-modal/email-verification-modal.component.ts(1 hunks)apps/lfx-one/src/app/modules/profile/email/profile-email.component.html(4 hunks)apps/lfx-one/src/app/modules/profile/email/profile-email.component.ts(7 hunks)apps/lfx-one/src/app/shared/services/user.service.ts(1 hunks)apps/lfx-one/src/server/controllers/profile.controller.ts(6 hunks)apps/lfx-one/src/server/routes/profile.route.ts(1 hunks)apps/lfx-one/src/server/services/email.service.ts(1 hunks)apps/lfx-one/src/server/services/user.service.ts(2 hunks)packages/shared/src/enums/nats.enum.ts(1 hunks)packages/shared/src/interfaces/user-profile.interface.ts(1 hunks)
🧰 Additional context used
📓 Path-based instructions (6)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{ts,tsx}: Use TypeScript interfaces instead of union types for better maintainability
When defining PrimeNG-related types, reference the official PrimeNG component interfaces
Files:
apps/lfx-one/src/app/shared/services/user.service.tspackages/shared/src/interfaces/user-profile.interface.tsapps/lfx-one/src/app/modules/profile/email/email-verification-modal/email-verification-modal.component.tsapps/lfx-one/src/app/modules/profile/email/profile-email.component.tsapps/lfx-one/src/server/services/email.service.tsapps/lfx-one/src/server/services/user.service.tsapps/lfx-one/src/server/controllers/profile.controller.tspackages/shared/src/enums/nats.enum.tsapps/lfx-one/src/server/routes/profile.route.ts
**/*.{ts,tsx,js,jsx,mjs,cjs,html,css,scss}
📄 CodeRabbit inference engine (CLAUDE.md)
Include required license headers on all source files
Files:
apps/lfx-one/src/app/shared/services/user.service.tsapps/lfx-one/src/app/modules/profile/email/email-verification-modal/email-verification-modal.component.htmlpackages/shared/src/interfaces/user-profile.interface.tsapps/lfx-one/src/app/modules/profile/email/email-verification-modal/email-verification-modal.component.tsapps/lfx-one/src/app/modules/profile/email/profile-email.component.tsapps/lfx-one/src/server/services/email.service.tsapps/lfx-one/src/server/services/user.service.tsapps/lfx-one/src/server/controllers/profile.controller.tsapps/lfx-one/src/app/modules/profile/email/profile-email.component.htmlpackages/shared/src/enums/nats.enum.tsapps/lfx-one/src/server/routes/profile.route.ts
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Do not nest ternary expressions
Files:
apps/lfx-one/src/app/shared/services/user.service.tspackages/shared/src/interfaces/user-profile.interface.tsapps/lfx-one/src/app/modules/profile/email/email-verification-modal/email-verification-modal.component.tsapps/lfx-one/src/app/modules/profile/email/profile-email.component.tsapps/lfx-one/src/server/services/email.service.tsapps/lfx-one/src/server/services/user.service.tsapps/lfx-one/src/server/controllers/profile.controller.tspackages/shared/src/enums/nats.enum.tsapps/lfx-one/src/server/routes/profile.route.ts
apps/lfx-one/src/**/*.html
📄 CodeRabbit inference engine (CLAUDE.md)
apps/lfx-one/src/**/*.html: Always add data-testid attributes when creating new Angular components for reliable test targeting
Use data-testid naming convention [section]-[component]-[element]
Files:
apps/lfx-one/src/app/modules/profile/email/email-verification-modal/email-verification-modal.component.htmlapps/lfx-one/src/app/modules/profile/email/profile-email.component.html
packages/shared/src/interfaces/**/*.ts
📄 CodeRabbit inference engine (CLAUDE.md)
Place all TypeScript interfaces in the shared package at packages/shared/src/interfaces
Files:
packages/shared/src/interfaces/user-profile.interface.ts
packages/shared/src/enums/**/*.ts
📄 CodeRabbit inference engine (CLAUDE.md)
Place all enums in the shared package at packages/shared/src/enums
Files:
packages/shared/src/enums/nats.enum.ts
🧠 Learnings (2)
📚 Learning: 2025-09-16T03:32:46.518Z
Learnt from: CR
PR: linuxfoundation/lfx-v2-ui#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-16T03:32:46.518Z
Learning: Applies to packages/shared/src/interfaces/**/*.ts : Place all TypeScript interfaces in the shared package at packages/shared/src/interfaces
Applied to files:
packages/shared/src/interfaces/user-profile.interface.ts
📚 Learning: 2025-09-16T03:32:46.518Z
Learnt from: CR
PR: linuxfoundation/lfx-v2-ui#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-16T03:32:46.518Z
Learning: Applies to packages/shared/src/enums/**/*.ts : Place all enums in the shared package at packages/shared/src/enums
Applied to files:
packages/shared/src/enums/nats.enum.ts
🧬 Code graph analysis (6)
apps/lfx-one/src/app/shared/services/user.service.ts (1)
packages/shared/src/interfaces/user-profile.interface.ts (1)
AddEmailRequest(53-55)
apps/lfx-one/src/app/modules/profile/email/email-verification-modal/email-verification-modal.component.ts (1)
apps/lfx-one/src/app/modules/profile/email/profile-email.component.ts (1)
Component(30-345)
apps/lfx-one/src/app/modules/profile/email/profile-email.component.ts (1)
packages/shared/src/interfaces/user-profile.interface.ts (1)
UserEmail(25-35)
apps/lfx-one/src/server/services/email.service.ts (2)
apps/lfx-one/src/server/services/nats.service.ts (1)
NatsService(13-133)packages/shared/src/constants/api.constants.ts (1)
NATS_CONFIG(28-43)
apps/lfx-one/src/server/services/user.service.ts (2)
packages/shared/src/interfaces/user-profile.interface.ts (1)
UserEmailsResponse(183-187)packages/shared/src/constants/api.constants.ts (1)
NATS_CONFIG(28-43)
apps/lfx-one/src/server/controllers/profile.controller.ts (2)
apps/lfx-one/src/server/services/email.service.ts (1)
EmailService(68-348)packages/shared/src/interfaces/user-profile.interface.ts (3)
UserEmail(25-35)EmailManagementData(69-72)AddEmailRequest(53-55)
🔇 Additional comments (10)
apps/lfx-one/src/server/controllers/profile.controller.ts (3)
7-7: LGTM - Imports and service initialization.The imports and EmailService field initialization follow the same pattern as existing services in the controller.
Also applies to: 10-10, 19-19, 30-30
465-509: LGTM - Email verification endpoint.The endpoint has appropriate validation, logging, and error handling. The EmailService performs additional validation including email format checking.
511-573: Verify authorization checks in the auth-service microservice repository.The SSR server correctly delegates identity linking authorization to a separate NATS-based auth service. The endpoint passes both the user's bearer token and the identity token from OTP verification. However, the auth service implementation is in a separate microservice repository (not in this codebase), so I cannot verify that it performs the required authorization checks.
To complete this verification, manually confirm in the auth-service repository that the
user-identity/linkNATS handler validates:
- Bearer token validity and user identity
- User authorization to link the email to their account
- Email is not already linked to another user
The current SSR code correctly delegates the responsibility; verification requires inspecting the auth-service implementation directly.
apps/lfx-one/src/server/services/email.service.ts (3)
14-73: LGTM - Interface definitions and constructor.The internal interfaces are well-structured for the three-step verification flow. The NatsService is properly instantiated and manages connection pooling internally.
162-243: LGTM - OTP verification logic.The method properly validates the 6-digit OTP format and handles error cases appropriately. The string matching concern is addressed in a previous comment.
329-347: LGTM - Orchestration logic is sound.The method properly chains the OTP verification and identity linking steps, with appropriate validation between steps.
packages/shared/src/enums/nats.enum.ts (1)
13-19: LGTM - NATS subject additions.The new enum members follow consistent naming conventions and are appropriately categorized with inline comments. They align with the email verification and linking flow implemented in the EmailService.
Based on learnings
apps/lfx-one/src/app/modules/profile/email/email-verification-modal/email-verification-modal.component.ts (3)
29-49: LGTM - Timer and form initialization.The 5-minute timer and 6-digit form setup with per-digit validation are appropriate for the OTP verification flow.
51-70: LGTM - Lifecycle hooks.Proper initialization with auto-focus and cleanup with the destroy$ subject for subscription management.
211-309: LGTM - Keyboard navigation and paste handling.The keyboard event handlers provide excellent UX with backspace, arrow key navigation, and comprehensive paste support. The duplicate paste logic concern is addressed in the previous comment.
...src/app/modules/profile/email/email-verification-modal/email-verification-modal.component.ts
Outdated
Show resolved
Hide resolved
...src/app/modules/profile/email/email-verification-modal/email-verification-modal.component.ts
Show resolved
Hide resolved
…error handling - Replace individual digit inputs with a single input for the 6-digit verification code to simplify user interaction. - Update error messages for clarity and consistency, particularly for already linked emails. - Enhance the timer functionality and cleanup logic to improve component lifecycle management. Jira Ticket: https://linuxfoundation.atlassian.net/browse/LFXV2-502 Generated with [Cursor](https://cursor.com/) Signed-off-by: Mauricio Zanetti Salomao <msalomao@contractor.linuxfoundation.org>
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.
Actionable comments posted: 2
🧹 Nitpick comments (1)
apps/lfx-one/src/app/modules/profile/email/email-verification-modal/email-verification-modal.component.ts (1)
132-132: Remove debug console.log.Debug logging should be removed before merging to production.
Apply this diff:
// Set error message AFTER reset to prevent it from being cleared this.errorMessage.set(errorMsg); - console.log('Error message signal value:', this.errorMessage()); }, });
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
Disabled knowledge base sources:
- Jira integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (3)
apps/lfx-one/src/app/modules/profile/email/email-verification-modal/email-verification-modal.component.html(1 hunks)apps/lfx-one/src/app/modules/profile/email/email-verification-modal/email-verification-modal.component.ts(1 hunks)apps/lfx-one/src/app/modules/profile/email/profile-email.component.ts(7 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- apps/lfx-one/src/app/modules/profile/email/email-verification-modal/email-verification-modal.component.html
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{ts,tsx}: Use TypeScript interfaces instead of union types for better maintainability
When defining PrimeNG-related types, reference the official PrimeNG component interfaces
Files:
apps/lfx-one/src/app/modules/profile/email/email-verification-modal/email-verification-modal.component.tsapps/lfx-one/src/app/modules/profile/email/profile-email.component.ts
**/*.{ts,tsx,js,jsx,mjs,cjs,html,css,scss}
📄 CodeRabbit inference engine (CLAUDE.md)
Include required license headers on all source files
Files:
apps/lfx-one/src/app/modules/profile/email/email-verification-modal/email-verification-modal.component.tsapps/lfx-one/src/app/modules/profile/email/profile-email.component.ts
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Do not nest ternary expressions
Files:
apps/lfx-one/src/app/modules/profile/email/email-verification-modal/email-verification-modal.component.tsapps/lfx-one/src/app/modules/profile/email/profile-email.component.ts
🧬 Code graph analysis (2)
apps/lfx-one/src/app/modules/profile/email/email-verification-modal/email-verification-modal.component.ts (1)
apps/lfx-one/src/app/modules/profile/email/profile-email.component.ts (1)
Component(30-345)
apps/lfx-one/src/app/modules/profile/email/profile-email.component.ts (1)
packages/shared/src/interfaces/user-profile.interface.ts (1)
UserEmail(25-35)
🔇 Additional comments (4)
apps/lfx-one/src/app/modules/profile/email/profile-email.component.ts (2)
100-102: Feature flags properly documented.The temporarily disabled features are clearly marked with inline comments and hard-coded flags. This approach provides transparency about the current implementation status.
152-186: Modal result handling is well-structured.The three distinct outcomes (success, alreadyLinked, cancelled) are handled appropriately with different UI responses—inline errors for field-level issues and toasts for system-level feedback.
apps/lfx-one/src/app/modules/profile/email/email-verification-modal/email-verification-modal.component.ts (2)
56-73: Lifecycle management is correct.The use of
takeUntilDestroyed()viadestroyRefproperly handles cleanup for the form subscription and timer intervals when the component is destroyed.
75-135: Error handling covers multiple scenarios well.The method distinguishes between "already linked," OTP verification failures, and generic errors, providing appropriate feedback for each case. The sequence of resetting the form before setting the error message prevents the error from being immediately cleared.
...src/app/modules/profile/email/email-verification-modal/email-verification-modal.component.ts
Show resolved
Hide resolved
…anagement - Integrate takeUntilDestroyed for better subscription management in email input value changes. - Improve component lifecycle handling by ensuring subscriptions are properly cleaned up. Jira Ticket: https://linuxfoundation.atlassian.net/browse/LFXV2-502 Reviewed with [GitHub Copilot](https://github.com/features/copilot) Signed-off-by: Mauricio Zanetti Salomao <msalomao@contractor.linuxfoundation.org>
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.
Actionable comments posted: 1
🧹 Nitpick comments (4)
apps/lfx-one/src/app/modules/profile/email/profile-email.component.ts (3)
130-152: Consider extracting error message detection logic.The error message extraction and "already linked" detection logic (lines 134-143) is somewhat complex and similar patterns appear in the modal's error handling. Consider extracting this to a helper method to improve maintainability.
Example refactor:
private isAlreadyLinkedError(error: any): boolean { const specificMessage = error.error?.errors?.[0]?.message || ''; const genericMessage = error.error?.message || error.message || ''; const errorText = (specificMessage + ' ' + genericMessage).toLowerCase(); return errorText.includes('already linked'); }Then use it in both places:
if (this.isAlreadyLinkedError(error)) { this.emailFieldError.set('This email address is already in use.'); } else { // ... generic error handling }
156-190: Extract duplicate error message string to a constant.The error message "This email address is already in use." appears on both line 143 and line 181. Extract this to a private constant to maintain consistency.
Apply this diff:
export class ProfileEmailComponent { private readonly userService = inject(UserService); private readonly confirmationService = inject(ConfirmationService); private readonly messageService = inject(MessageService); private readonly dialogService = inject(DialogService); private readonly destroyRef = takeUntilDestroyed(); + + private readonly EMAIL_ALREADY_LINKED_ERROR = 'This email address is already in use.'; // Dialog reference private dialogRef: DynamicDialogRef | undefined;Then use it:
- this.emailFieldError.set('This email address is already in use.'); + this.emailFieldError.set(this.EMAIL_ALREADY_LINKED_ERROR);- this.emailFieldError.set('This email address is already in use.'); + this.emailFieldError.set(this.EMAIL_ALREADY_LINKED_ERROR);
207-234: Consider removing commented-out code blocks.The setPrimary method contains a large commented-out implementation (lines 215-233). Since this feature is temporarily disabled and tracked in the TODO comment, consider removing the commented code to reduce clutter. The implementation can be retrieved from git history when needed.
This same suggestion applies to the deleteEmail method (lines 245-274).
apps/lfx-one/src/app/modules/profile/email/email-verification-modal/email-verification-modal.component.ts (1)
99-126: Consider extracting error handling logic to a shared utility.The error extraction and classification logic (lines 99-126) has similarities with the parent component's error handling. Consider creating a shared error utility to handle email verification errors consistently across components.
Example utility:
// shared/utils/email-error.util.ts export interface EmailVerificationError { isAlreadyLinked: boolean; isInvalidOtp: boolean; message: string; } export function parseEmailVerificationError(error: any): EmailVerificationError { const specificMessage = error.error?.errors?.[0]?.message || ''; const genericMessage = error.error?.message || error.message || ''; const errorCode = error.error?.error_code || ''; const errorType = error.error?.error_type || ''; const errorText = (specificMessage + ' ' + genericMessage + ' ' + errorCode).toLowerCase(); return { isAlreadyLinked: errorText.includes('already linked'), isInvalidOtp: errorCode === 'OTP_VERIFICATION_FAILED' || errorType === '_MicroserviceError', message: errorText, }; }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
Disabled knowledge base sources:
- Jira integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (2)
apps/lfx-one/src/app/modules/profile/email/email-verification-modal/email-verification-modal.component.ts(1 hunks)apps/lfx-one/src/app/modules/profile/email/profile-email.component.ts(8 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{ts,tsx}: Use TypeScript interfaces instead of union types for better maintainability
When defining PrimeNG-related types, reference the official PrimeNG component interfaces
Files:
apps/lfx-one/src/app/modules/profile/email/profile-email.component.tsapps/lfx-one/src/app/modules/profile/email/email-verification-modal/email-verification-modal.component.ts
**/*.{ts,tsx,js,jsx,mjs,cjs,html,css,scss}
📄 CodeRabbit inference engine (CLAUDE.md)
Include required license headers on all source files
Files:
apps/lfx-one/src/app/modules/profile/email/profile-email.component.tsapps/lfx-one/src/app/modules/profile/email/email-verification-modal/email-verification-modal.component.ts
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Do not nest ternary expressions
Files:
apps/lfx-one/src/app/modules/profile/email/profile-email.component.tsapps/lfx-one/src/app/modules/profile/email/email-verification-modal/email-verification-modal.component.ts
🧠 Learnings (2)
📓 Common learnings
Learnt from: mauriciozanettisalomao
Repo: linuxfoundation/lfx-v2-ui PR: 130
File: apps/lfx-one/src/server/controllers/profile.controller.ts:303-370
Timestamp: 2025-10-31T14:39:34.327Z
Learning: The synthetic timestamps (created_at, updated_at, verified_at) in the getUserEmails transformation for apps/lfx-one/src/server/controllers/profile.controller.ts are temporary placeholders. Real timestamps will be included in the NATS response once the Auth0 backend implementation is complete.
📚 Learning: 2025-10-31T14:39:34.327Z
Learnt from: mauriciozanettisalomao
Repo: linuxfoundation/lfx-v2-ui PR: 130
File: apps/lfx-one/src/server/controllers/profile.controller.ts:303-370
Timestamp: 2025-10-31T14:39:34.327Z
Learning: The synthetic timestamps (created_at, updated_at, verified_at) in the getUserEmails transformation for apps/lfx-one/src/server/controllers/profile.controller.ts are temporary placeholders. Real timestamps will be included in the NATS response once the Auth0 backend implementation is complete.
Applied to files:
apps/lfx-one/src/app/modules/profile/email/profile-email.component.tsapps/lfx-one/src/app/modules/profile/email/email-verification-modal/email-verification-modal.component.ts
🧬 Code graph analysis (2)
apps/lfx-one/src/app/modules/profile/email/profile-email.component.ts (1)
packages/shared/src/interfaces/user-profile.interface.ts (1)
UserEmail(25-35)
apps/lfx-one/src/app/modules/profile/email/email-verification-modal/email-verification-modal.component.ts (1)
apps/lfx-one/src/app/modules/profile/email/profile-email.component.ts (1)
Component(30-349)
🔇 Additional comments (6)
apps/lfx-one/src/app/modules/profile/email/profile-email.component.ts (2)
68-76: LGTM! Subscription cleanup properly implemented.The form subscription now uses
takeUntilDestroyed()which properly cleans up the subscription when the component is destroyed, addressing the memory leak concern from the previous review.
18-18: LGTM! DynamicDialog integration properly configured.The DynamicDialog imports, module registration, and service injection are correctly set up to support the new email verification modal flow.
Also applies to: 23-23, 43-43, 47-47, 54-55
apps/lfx-one/src/app/modules/profile/email/email-verification-modal/email-verification-modal.component.ts (4)
1-3: LGTM! Required license header present.The file includes the required Linux Foundation license header as per coding guidelines.
142-162: LGTM! Timer cleanup properly implemented.The timer implementation now correctly prevents multiple concurrent intervals by tracking and unsubscribing the previous subscription (lines 144-146) before starting a new one. Combined with
takeUntilDestroyed(), this ensures proper cleanup both on resend and component destroy.
57-74: LGTM! Thoughtful form subscription implementation.The ngOnInit logic properly:
- Retrieves email from dialog config
- Starts the countdown timer
- Subscribes to form changes with proper cleanup via
takeUntilDestroyed()- Conditionally clears errors only when user is actively typing (line 70), preventing unwanted error clearing during programmatic form resets
164-201: LGTM! Resend flow properly implemented.The resendCode method correctly:
- Manages loading state with the
resendingsignal- Resets all timer and form state on success
- Restarts the timer (which properly handles cleanup)
- Provides appropriate user feedback via toasts
...src/app/modules/profile/email/email-verification-modal/email-verification-modal.component.ts
Outdated
Show resolved
Hide resolved
- Removed console log statement that outputs the error message signal value to clean up the code and reduce unnecessary logging during error handling. Jira Ticket: https://linuxfoundation.atlassian.net/browse/LFXV2-502 Reviewed with [GitHub Copilot](https://github.com/features/copilot) Signed-off-by: Mauricio Zanetti Salomao <msalomao@contractor.linuxfoundation.org>
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.
Actionable comments posted: 0
🧹 Nitpick comments (1)
apps/lfx-one/src/app/modules/profile/email/email-verification-modal/email-verification-modal.component.ts (1)
96-135: Consider extracting error parsing logic.The error handling correctly manages multiple backend formats (ServiceValidationError vs. microservice errors), and the special handling for "already linked" is appropriate. However, the parsing logic (lines 101-126) could be extracted to a helper method to improve testability and maintainability.
For example:
private parseVerificationError(error: any): { isAlreadyLinked: boolean; message: string } { const specificMessage = error.error?.errors?.[0]?.message || ''; const genericMessage = error.error?.message || error.message || ''; const errorCode = error.error?.error_code || ''; const errorType = error.error?.error_type || ''; const errorText = (specificMessage + ' ' + genericMessage + ' ' + errorCode).toLowerCase(); if (errorText.includes('already linked')) { return { isAlreadyLinked: true, message: '' }; } if (errorCode === 'OTP_VERIFICATION_FAILED' || errorType === '_MicroserviceError') { return { isAlreadyLinked: false, message: 'Invalid or expired verification code. Please try again.' }; } return { isAlreadyLinked: false, message: 'Invalid verification code. Please try again.' }; }Then simplify the error handler:
error: (error) => { console.error('Failed to verify code:', error); const parsed = this.parseVerificationError(error); if (parsed.isAlreadyLinked) { this.dialogRef.close({ alreadyLinked: true, email: this.email }); return; } this.verificationForm.reset(); this.errorMessage.set(parsed.message); }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
Disabled knowledge base sources:
- Jira integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (1)
apps/lfx-one/src/app/modules/profile/email/email-verification-modal/email-verification-modal.component.ts(1 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{ts,tsx}: Use TypeScript interfaces instead of union types for better maintainability
When defining PrimeNG-related types, reference the official PrimeNG component interfaces
Files:
apps/lfx-one/src/app/modules/profile/email/email-verification-modal/email-verification-modal.component.ts
**/*.{ts,tsx,js,jsx,mjs,cjs,html,css,scss}
📄 CodeRabbit inference engine (CLAUDE.md)
Include required license headers on all source files
Files:
apps/lfx-one/src/app/modules/profile/email/email-verification-modal/email-verification-modal.component.ts
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Do not nest ternary expressions
Files:
apps/lfx-one/src/app/modules/profile/email/email-verification-modal/email-verification-modal.component.ts
🧠 Learnings (2)
📓 Common learnings
Learnt from: mauriciozanettisalomao
Repo: linuxfoundation/lfx-v2-ui PR: 130
File: apps/lfx-one/src/server/controllers/profile.controller.ts:303-370
Timestamp: 2025-10-31T14:39:34.327Z
Learning: The synthetic timestamps (created_at, updated_at, verified_at) in the getUserEmails transformation for apps/lfx-one/src/server/controllers/profile.controller.ts are temporary placeholders. Real timestamps will be included in the NATS response once the Auth0 backend implementation is complete.
📚 Learning: 2025-10-31T14:39:34.327Z
Learnt from: mauriciozanettisalomao
Repo: linuxfoundation/lfx-v2-ui PR: 130
File: apps/lfx-one/src/server/controllers/profile.controller.ts:303-370
Timestamp: 2025-10-31T14:39:34.327Z
Learning: The synthetic timestamps (created_at, updated_at, verified_at) in the getUserEmails transformation for apps/lfx-one/src/server/controllers/profile.controller.ts are temporary placeholders. Real timestamps will be included in the NATS response once the Auth0 backend implementation is complete.
Applied to files:
apps/lfx-one/src/app/modules/profile/email/email-verification-modal/email-verification-modal.component.ts
🧬 Code graph analysis (1)
apps/lfx-one/src/app/modules/profile/email/email-verification-modal/email-verification-modal.component.ts (1)
apps/lfx-one/src/app/modules/profile/email/profile-email.component.ts (1)
Component(30-349)
🔇 Additional comments (5)
apps/lfx-one/src/app/modules/profile/email/email-verification-modal/email-verification-modal.component.ts (5)
1-24: LGTM! Clean component setup.The license header, imports, and component configuration follow Angular best practices. Using a standalone component with localized MessageService provider is appropriate for this modal.
25-56: Well-structured state management.The use of signals for reactive state and a simple FormGroup with pattern validation is clean. Timer subscription tracking ensures proper cleanup.
57-74: LGTM! Thoughtful initialization logic.The conditional error clearing (only when value is truthy) prevents the message from disappearing on reset, which is good UX. Timer starts appropriately on init.
141-161: Excellent timer implementation.The timer correctly prevents multiple concurrent intervals (lines 143-145) and uses
takeUntilDestroyed()for automatic cleanup, which resolves the issues from previous reviews. The form disabling on expiry is appropriate.
163-200: LGTM! Clean resend flow.The resend logic properly resets all state (timer, form, flags) and restarts the timer. The toast notifications provide clear user feedback.
…rvice Jira Ticket: https://linuxfoundation.atlassian.net/browse/LFXV2-502 Signed-off-by: Mauricio Zanetti Salomao <msalomao@contractor.linuxfoundation.org>
Overview
Jira ticket https://linuxfoundation.atlassian.net/browse/LFXV2-502
Implements email linking functionality that integrates with the Auth0 authentication service, allowing users to verify and link alternate email addresses to their accounts through a secure OTP verification flow.
Notes:
For now, to focus on removing non-auth-service integrations from the profile, we’ve disabled the delete email action until we implement it. The set primary email action is also on hold, as we need to check if it’s supported on the Auth0 side.
Changes
verifyAndLinkEmail(),linkIdentity(), and related methods to handle the complete email verification and linking workflowPOST /api/profile/emails/send-verification- Sends OTP verification codePOST /api/profile/emails/verify- Verifies OTP and links email to accountEMAIL_LINKING_SEND_VERIFICATION- Request verification codeEMAIL_LINKING_VERIFY- Verify OTP codeUSER_IDENTITY_LINK- Link identity to user accountupdate:current_user_metadatafor identity linking operationsTechnical Details
The implementation follows a three-step process:
Screenshots:
Modal to provide the OTP
Incorrect code behavior
Expired code behavior
Successful verification behavior