feat: delete users - not tested
This commit is contained in:
122
backend/src/features/auth/api/auth.controller.ts
Normal file
122
backend/src/features/auth/api/auth.controller.ts
Normal 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',
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
30
backend/src/features/auth/api/auth.routes.ts
Normal file
30
backend/src/features/auth/api/auth.routes.ts
Normal 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),
|
||||
});
|
||||
};
|
||||
23
backend/src/features/auth/api/auth.validation.ts
Normal file
23
backend/src/features/auth/api/auth.validation.ts
Normal 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>;
|
||||
Reference in New Issue
Block a user