Skip to content

Conversation

@sean-brydon
Copy link
Member

@sean-brydon sean-brydon commented Jan 18, 2026

What does this PR do?

When a user is auto-locked (or has their locked field set to true), this PR dispatches a job via tasker to send the user an email explaining:

  • That their account has been locked
  • Why they were locked (rate limit exceeded or spam detected in workflow)
  • How to reach out to support if it's a false alarm

Implements both async (via trigger.dev) and sync variants for sending the locked user email, using the same DI (Dependency Injection) pattern as MonthlyProrationTasker.

Changes

  • Added new tasker task type sendUserLockedEmail
  • Created email template class and React component for the locked user notification
  • Modified lockUser function to automatically dispatch the email task when a user is locked
  • Added sendUserLockedEmailAsync and sendUserLockedEmailSync exported functions for flexibility
  • Added all necessary translations for email content
  • Updated lockUser to fetch user's name and locale for personalized emails

Updates since last revision

  • Refactored to use DI pattern following MonthlyProrationTasker:
    • Created IUserLockedEmailTasker interface with sendEmail method
    • Created UserLockedEmailTasker extending Tasker base class (provides automatic async→sync fallback)
    • Created UserLockedEmailSyncTasker for synchronous email sending
    • Created UserLockedEmailTriggerDevTasker for async execution via trigger.dev
    • Added DI tokens and modules in packages/features/ee/api-keys/di/tasker/
    • Added trigger.dev task configuration with retry logic and queue settings
  • Updated tests to mock the new DI container (getUserLockedEmailTasker)
  • Fixed CI test failures: Added ENABLE_ASYNC_TASKER to constants mocks:
    • @calcom/lib/__mocks__/constants.ts (global mock)
    • apps/web/test/lib/getSchedule/futureLimit.timezone.test.ts (test-specific mock)

Mandatory Tasks (DO NOT REMOVE)

  • I have self-reviewed the code (A decent size PR without self-review might be rejected).
  • I have updated the developer docs in /docs if this PR makes changes that would require a documentation change. N/A - no docs changes needed
  • I confirm automated tests are in place that prove my fix is effective or that my feature works.

How should this be tested?

  1. Trigger a user lock by either:

    • Exceeding the rate limit threshold multiple times (requires UPSTASH env vars)
    • Having spam detected in a workflow body (requires IFFY_API_KEY)
    • Manually calling lockUser("userId", "123", LockReason.RATE_LIMIT)
  2. Verify the DI-based tasker dispatches the email task

  3. When the task is processed, verify the email is sent with:

    • Correct subject line
    • User's name in greeting
    • Appropriate lock reason explanation
    • Support contact button/link

For sync variant testing:

import { sendUserLockedEmailSync, LockReason } from "@calcom/features/ee/api-keys/lib/autoLock";

await sendUserLockedEmailSync({
  userId: 123,
  email: "[email protected]",
  name: "Test User",
  lockReason: LockReason.RATE_LIMIT,
  locale: "en"
});

Checklist

  • My code follows the style guidelines of this project
  • I have checked if my changes generate no new warnings

Human Review Checklist

  • Verify email template renders correctly (no visual demo provided)
  • Check LockReason enum values map correctly to translation keys
  • Verify DI modules are wired correctly (tokens, modules, container)
  • Confirm trigger.dev task config (queue, retry settings) is appropriate
  • Note: sendUserLockedEmailAsync logs errors but doesn't throw - confirm this is desired behavior
  • Verify no conflicts between old tasker task (tasks/sendUserLockedEmail.ts) and new DI-based implementation

Link to Devin run: https://app.devin.ai/sessions/fc8c8aeabef641b7bbf8e331f5750588
Requested by: @sean-brydon

…ontact

- Add new tasker task type sendUserLockedEmail
- Create task handler for sending locked user emails
- Create email template class and React component
- Add translations for email content
- Modify lockUser function to dispatch async task
- Add sync variant function for direct email sending

Co-Authored-By: [email protected] <[email protected]>
@devin-ai-integration
Copy link
Contributor

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR that start with 'DevinAI' or '@devin'.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment and CI monitoring

devin-ai-integration bot and others added 2 commits January 18, 2026 16:07
- Create IUserLockedEmailTasker interface with sendEmail method
- Create UserLockedEmailTasker extending Tasker base class
- Create UserLockedEmailSyncTasker for synchronous email sending
- Create UserLockedEmailTriggerDevTasker for async via trigger.dev
- Add DI tokens and modules for dependency injection wiring
- Add trigger task with config, schema, and sendUserLockedEmail
- Update autoLock.ts to use new DI-based tasker
- Update tests to mock new DI container

This follows the same DI pattern used by MonthlyProrationTasker,
providing automatic fallback from async to sync and better testability.

Co-Authored-By: [email protected] <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants