Implement token expiration warnings (P3.9)
Add email warnings for Garmin token expiration at 14-day and 7-day thresholds. When the garmin-sync cron job runs, it now checks each user's token expiry and sends a warning email at exactly 14 days and 7 days before expiration. Changes: - Add sendTokenExpirationWarning() to email.ts with differentiated subject lines and urgency levels for 14-day vs 7-day warnings - Integrate warning logic into garmin-sync cron route using daysUntilExpiry() - Track warnings sent in sync response with new warningsSent counter - Add 20 new tests (10 for email function, 10 for sync integration) Test count: 517 → 537 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -4,8 +4,10 @@ import { NextResponse } from "next/server";
|
||||
|
||||
import { getCycleDay, getPhase, getPhaseLimit } from "@/lib/cycle";
|
||||
import { getDecisionWithOverrides } from "@/lib/decision-engine";
|
||||
import { sendTokenExpirationWarning } from "@/lib/email";
|
||||
import { decrypt } from "@/lib/encryption";
|
||||
import {
|
||||
daysUntilExpiry,
|
||||
fetchBodyBattery,
|
||||
fetchHrvStatus,
|
||||
fetchIntensityMinutes,
|
||||
@@ -19,6 +21,7 @@ interface SyncResult {
|
||||
usersProcessed: number;
|
||||
errors: number;
|
||||
skippedExpired: number;
|
||||
warningsSent: number;
|
||||
timestamp: string;
|
||||
}
|
||||
|
||||
@@ -36,6 +39,7 @@ export async function POST(request: Request) {
|
||||
usersProcessed: 0,
|
||||
errors: 0,
|
||||
skippedExpired: 0,
|
||||
warningsSent: 0,
|
||||
timestamp: new Date().toISOString(),
|
||||
};
|
||||
|
||||
@@ -61,6 +65,17 @@ export async function POST(request: Request) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check for token expiration warnings (exactly 14 or 7 days)
|
||||
const daysRemaining = daysUntilExpiry(tokens);
|
||||
if (daysRemaining === 14 || daysRemaining === 7) {
|
||||
try {
|
||||
await sendTokenExpirationWarning(user.email, daysRemaining);
|
||||
result.warningsSent++;
|
||||
} catch {
|
||||
// Continue processing even if warning email fails
|
||||
}
|
||||
}
|
||||
|
||||
// Decrypt OAuth2 token
|
||||
const oauth2Json = decrypt(user.garminOauth2Token);
|
||||
const oauth2Data = JSON.parse(oauth2Json);
|
||||
|
||||
Reference in New Issue
Block a user