feat : Init Project
This commit is contained in:
115
nest-backend/src/routes/auth.ts
Normal file
115
nest-backend/src/routes/auth.ts
Normal file
@@ -0,0 +1,115 @@
|
||||
import { Router, Request, Response } from 'express';
|
||||
import bcrypt from 'bcryptjs';
|
||||
import jwt from 'jsonwebtoken';
|
||||
import { z } from 'zod';
|
||||
import prisma from '../lib/prisma.js';
|
||||
import { authenticate } from '../middleware/auth.js';
|
||||
|
||||
const router = Router();
|
||||
|
||||
const loginSchema = z.object({
|
||||
email: z.string().email(),
|
||||
password: z.string().min(1),
|
||||
});
|
||||
|
||||
const registerSchema = z.object({
|
||||
username: z.string().min(2).max(32),
|
||||
email: z.string().email(),
|
||||
password: z.string().min(6),
|
||||
});
|
||||
|
||||
function signToken(userId: string, role: string, isAdmin: boolean): string {
|
||||
return jwt.sign({ userId, role, isAdmin }, process.env.JWT_SECRET!, { expiresIn: '7d' });
|
||||
}
|
||||
|
||||
function safeUser(user: { id: string; username: string; email: string; role: string; isAdmin: boolean; isBanned: boolean; avatarUrl: string | null; createdAt: Date }) {
|
||||
return {
|
||||
id: user.id,
|
||||
username: user.username,
|
||||
email: user.email,
|
||||
role: user.role,
|
||||
isAdmin: user.isAdmin,
|
||||
isBanned: user.isBanned,
|
||||
avatarUrl: user.avatarUrl,
|
||||
createdAt: user.createdAt.toISOString(),
|
||||
};
|
||||
}
|
||||
|
||||
// POST /api/auth/login
|
||||
router.post('/login', async (req: Request, res: Response): Promise<void> => {
|
||||
const parsed = loginSchema.safeParse(req.body);
|
||||
if (!parsed.success) {
|
||||
res.status(400).json({ error: parsed.error.flatten() });
|
||||
return;
|
||||
}
|
||||
|
||||
const { email, password } = parsed.data;
|
||||
|
||||
const user = await prisma.user.findUnique({ where: { email: email.toLowerCase() } });
|
||||
if (!user) {
|
||||
res.status(401).json({ error: 'No account found with that email address.' });
|
||||
return;
|
||||
}
|
||||
|
||||
const valid = await bcrypt.compare(password, user.password);
|
||||
if (!valid) {
|
||||
res.status(401).json({ error: 'Incorrect password.' });
|
||||
return;
|
||||
}
|
||||
|
||||
if (user.isBanned) {
|
||||
res.status(403).json({ error: 'This account has been suspended.' });
|
||||
return;
|
||||
}
|
||||
|
||||
const token = signToken(user.id, user.role, user.isAdmin);
|
||||
res.json({ token, user: safeUser(user) });
|
||||
});
|
||||
|
||||
// POST /api/auth/register (public site only — creates role=user)
|
||||
router.post('/register', async (req: Request, res: Response): Promise<void> => {
|
||||
const parsed = registerSchema.safeParse(req.body);
|
||||
if (!parsed.success) {
|
||||
res.status(400).json({ error: parsed.error.flatten() });
|
||||
return;
|
||||
}
|
||||
|
||||
const { username, email, password } = parsed.data;
|
||||
|
||||
const emailTaken = await prisma.user.findUnique({ where: { email: email.toLowerCase() } });
|
||||
if (emailTaken) {
|
||||
res.status(409).json({ error: 'An account with this email already exists.' });
|
||||
return;
|
||||
}
|
||||
|
||||
const usernameTaken = await prisma.user.findUnique({ where: { username } });
|
||||
if (usernameTaken) {
|
||||
res.status(409).json({ error: 'This username is already taken.' });
|
||||
return;
|
||||
}
|
||||
|
||||
const hashed = await bcrypt.hash(password, 10);
|
||||
const user = await prisma.user.create({
|
||||
data: {
|
||||
username,
|
||||
email: email.toLowerCase(),
|
||||
password: hashed,
|
||||
role: 'user',
|
||||
},
|
||||
});
|
||||
|
||||
const token = signToken(user.id, user.role, user.isAdmin);
|
||||
res.status(201).json({ token, user: safeUser(user) });
|
||||
});
|
||||
|
||||
// GET /api/auth/me
|
||||
router.get('/me', authenticate, async (req: Request, res: Response): Promise<void> => {
|
||||
const user = await prisma.user.findUnique({ where: { id: req.user!.userId } });
|
||||
if (!user) {
|
||||
res.status(404).json({ error: 'User not found' });
|
||||
return;
|
||||
}
|
||||
res.json(safeUser(user));
|
||||
});
|
||||
|
||||
export default router;
|
||||
Reference in New Issue
Block a user