feat: delete users - not tested

This commit is contained in:
Eric Gullickson
2025-12-22 18:20:25 -06:00
parent 91b4534e76
commit 4897f0a52c
73 changed files with 4923 additions and 62 deletions

View File

@@ -0,0 +1,122 @@
/**
* @ai-summary Fastify route handlers for auth API
* @ai-context HTTP request/response handling with Fastify reply methods
*/
import { FastifyRequest, FastifyReply } from 'fastify';
import { AuthService } from '../domain/auth.service';
import { UserProfileRepository } from '../../user-profile/data/user-profile.repository';
import { pool } from '../../../core/config/database';
import { logger } from '../../../core/logging/logger';
import { signupSchema } from './auth.validation';
export class AuthController {
private authService: AuthService;
constructor() {
const userProfileRepository = new UserProfileRepository(pool);
this.authService = new AuthService(userProfileRepository);
}
/**
* POST /api/auth/signup
* Create new user account
* Public endpoint - no JWT required
*/
async signup(request: FastifyRequest, reply: FastifyReply) {
try {
const validation = signupSchema.safeParse(request.body);
if (!validation.success) {
return reply.code(400).send({
error: 'Validation error',
message: validation.error.errors[0]?.message || 'Invalid input',
details: validation.error.errors,
});
}
const { email, password } = validation.data;
const result = await this.authService.signup({ email, password });
logger.info('User signup successful', { email, userId: result.userId });
return reply.code(201).send(result);
} catch (error: any) {
logger.error('Signup failed', { error, email: (request.body as any)?.email });
if (error.message === 'Email already exists') {
return reply.code(409).send({
error: 'Conflict',
message: 'An account with this email already exists',
});
}
// Auth0 API errors
if (error.message?.includes('Auth0')) {
return reply.code(500).send({
error: 'Internal server error',
message: 'Failed to create account. Please try again later.',
});
}
return reply.code(500).send({
error: 'Internal server error',
message: 'Failed to create account',
});
}
}
/**
* GET /api/auth/verify-status
* Check email verification status
* Protected endpoint - requires JWT
*/
async getVerifyStatus(request: FastifyRequest, reply: FastifyReply) {
try {
const userId = (request as any).user.sub;
const result = await this.authService.getVerifyStatus(userId);
logger.info('Verification status checked', { userId, emailVerified: result.emailVerified });
return reply.code(200).send(result);
} catch (error: any) {
logger.error('Failed to get verification status', {
error,
userId: (request as any).user?.sub,
});
return reply.code(500).send({
error: 'Internal server error',
message: 'Failed to check verification status',
});
}
}
/**
* POST /api/auth/resend-verification
* Resend verification email
* Protected endpoint - requires JWT
*/
async resendVerification(request: FastifyRequest, reply: FastifyReply) {
try {
const userId = (request as any).user.sub;
const result = await this.authService.resendVerification(userId);
logger.info('Verification email resent', { userId });
return reply.code(200).send(result);
} catch (error: any) {
logger.error('Failed to resend verification email', {
error,
userId: (request as any).user?.sub,
});
return reply.code(500).send({
error: 'Internal server error',
message: 'Failed to resend verification email',
});
}
}
}

View File

@@ -0,0 +1,30 @@
/**
* @ai-summary Fastify routes for auth API
* @ai-context Route definitions with Zod validation and authentication
*/
import { FastifyInstance, FastifyPluginOptions } from 'fastify';
import { FastifyPluginAsync } from 'fastify';
import { AuthController } from './auth.controller';
export const authRoutes: FastifyPluginAsync = async (
fastify: FastifyInstance,
_opts: FastifyPluginOptions
) => {
const authController = new AuthController();
// POST /api/auth/signup - Create new user (public, no JWT required)
fastify.post('/auth/signup', authController.signup.bind(authController));
// GET /api/auth/verify-status - Check verification status (requires JWT)
fastify.get('/auth/verify-status', {
preHandler: [fastify.authenticate],
handler: authController.getVerifyStatus.bind(authController),
});
// POST /api/auth/resend-verification - Resend verification email (requires JWT)
fastify.post('/auth/resend-verification', {
preHandler: [fastify.authenticate],
handler: authController.resendVerification.bind(authController),
});
};

View File

@@ -0,0 +1,23 @@
/**
* @ai-summary Request validation schemas for auth API
* @ai-context Uses Zod for runtime validation and type safety
*/
import { z } from 'zod';
// Password requirements:
// - Minimum 8 characters
// - At least one uppercase letter
// - At least one number
const passwordSchema = z
.string()
.min(8, 'Password must be at least 8 characters long')
.regex(/[A-Z]/, 'Password must contain at least one uppercase letter')
.regex(/[0-9]/, 'Password must contain at least one number');
export const signupSchema = z.object({
email: z.string().email('Invalid email format'),
password: passwordSchema,
});
export type SignupInput = z.infer<typeof signupSchema>;