Files
clube67.com/backend/src/controllers/auth.controller.ts
T
2026-05-18 18:32:55 +02:00

156 lines
5.8 KiB
TypeScript

import { Request, Response } from 'express';
import bcrypt from 'bcryptjs';
import { db } from '../config/database';
import { generateTokens } from '../middleware/auth';
import { auditLog } from '../utils/audit';
export async function register(req: Request, res: Response) {
const { name, email, password, type, whatsapp, address, pj_data } = req.body;
// Validations (before transaction)
if (!name || !email || !password) {
return res.status(400).json({ error: 'Campos obrigatórios faltando (nome, email, senha)' });
}
const trx = await db.transaction();
try {
const existingUser = await trx('users').where({ email }).first();
if (existingUser) {
await trx.rollback();
return res.status(400).json({ error: 'E-mail já cadastrado' });
}
const password_hash = await bcrypt.hash(password, 10);
// Create User
const [userId] = await trx('users').insert({
name,
email,
password_hash,
whatsapp,
role: type === 'partner' ? 'partner_admin' : 'user',
state: address?.state || null,
// city: address?.city, // Column doesn't exist yet, ignoring to avoid crash
// neighborhood: address?.neighborhood, // Column doesn't exist yet
status: 'active', // Users are active by default (partners rely on partner status)
created_at: new Date(),
updated_at: new Date()
});
// Create Partner (PJ)
if (type === 'partner' && pj_data) {
// Check existing CNPJ
if (pj_data.cnpj) {
const existingPartner = await trx('partners').where({ cnpj: pj_data.cnpj }).first();
if (existingPartner) {
await trx.rollback();
return res.status(400).json({ error: 'CNPJ já cadastrado' });
}
}
const [partnerId] = await trx('partners').insert({
company_name: pj_data.fantasy_name,
slug: null, // Removed automatic random slug. User will choose via modal.
cnpj: pj_data.cnpj || null,
email, // Contact email
phone: whatsapp,
address_street: address?.street,
address_number: address?.number,
address_neighborhood: address?.neighborhood,
address_city: address?.city,
address_state: address?.state,
type: String(pj_data.category_id || 'Serviços'),
status: 'inactive', // 'pending' doesn't exist in enum ('active','inactive'), so using 'inactive' as pending approval
owner_user_id: userId,
created_at: new Date(),
updated_at: new Date(),
data_consent: 1 // Implicit consent
});
// Link user to partner
await trx('users').where({ id: userId }).update({ partner_id: partnerId });
}
await trx.commit();
// Auto-login response
const user = await db('users').where({ id: userId }).first();
const tokens = generateTokens(user);
const redirectPath = getRedirectPath(user);
// Log action (outside transaction)
await auditLog(user.id, 'REGISTER', 'user', user.id, `Novo cadastro: ${type}`, req.ip);
res.status(201).json({ user, redirectPath, ...tokens });
} catch (err: any) {
await trx.rollback();
console.error('Register Error:', err);
res.status(500).json({ error: 'Erro ao criar conta: ' + (err.message || 'Erro interno') });
}
}
export async function login(req: Request, res: Response) {
try {
const { email, password } = req.body;
const user = await db('users').where({ email }).first();
if (!user || user.deleted_at || user.status === 'banned') {
return res.status(401).json({ error: 'Credenciais inválidas ou conta desativada' });
}
if (!(await bcrypt.compare(password, user.password_hash))) {
return res.status(401).json({ error: 'Credenciais inválidas' });
}
const tokens = generateTokens(user);
await auditLog(user.id, 'LOGIN', 'user', user.id, 'Usuário logou no sistema', req.ip);
const redirectPath = getRedirectPath(user);
res.json({ user, redirectPath, ...tokens });
} catch (err: any) {
res.status(500).json({ error: 'Erro no servidor' });
}
}
function getRedirectPath(user: any) {
if (user.role === 'super_admin') return '/admin/dashboard';
if (user.role === 'partner' || user.role === 'partner_admin') {
return '/partner/dashboard';
}
return '/user/dashboard';
}
export async function profile(req: Request, res: Response) {
try {
const user = await db('users')
.select('users.*', 'partners.slug as partner_slug')
.leftJoin('partners', 'users.partner_id', 'partners.id')
.where('users.id', req.user!.id)
.first();
res.json(user);
} catch (err) {
res.status(500).json({ error: 'Erro ao buscar perfil' });
}
}
export async function completeProfile(req: Request, res: Response) {
try {
const userId = req.user!.id;
const { whatsapp, state, city, neighborhood } = req.body || {};
if (!whatsapp || !state || !city || !neighborhood) {
return res.status(400).json({ error: 'Campos obrigatórios faltando' });
}
await db('users').where({ id: userId }).update({
whatsapp,
state,
city,
neighborhood,
updated_at: new Date(),
});
const user = await db('users').where({ id: userId }).first();
res.json(user);
} catch (err: any) {
res.status(500).json({ error: 'Erro ao completar cadastro' });
}
}