Extract backend tenant routes
This commit is contained in:
99
backend/routes/tenantsRoutes.js
Normal file
99
backend/routes/tenantsRoutes.js
Normal file
@@ -0,0 +1,99 @@
|
||||
const express = require('express');
|
||||
const crypto = require('crypto');
|
||||
const { requireRole } = require('../middleware/auth');
|
||||
|
||||
const createTenantsRouter = ({ pool, transporter, getBaseUrl }) => {
|
||||
const router = express.Router();
|
||||
|
||||
router.get('/tenants', requireRole(['super_admin']), async (req, res) => {
|
||||
try {
|
||||
const q = 'SELECT t.*, (SELECT COUNT(*) FROM users u WHERE u.tenant_id = t.id) as user_count, (SELECT COUNT(*) FROM attendances a WHERE a.tenant_id = t.id) as attendance_count FROM tenants t';
|
||||
const [rows] = await pool.query(q);
|
||||
res.json(rows);
|
||||
} catch (error) {
|
||||
res.status(500).json({ error: error.message });
|
||||
}
|
||||
});
|
||||
|
||||
router.post('/tenants', requireRole(['super_admin']), async (req, res) => {
|
||||
const { name, slug, admin_email, status } = req.body;
|
||||
const connection = await pool.getConnection();
|
||||
try {
|
||||
await connection.beginTransaction();
|
||||
const tid = `tenant_${crypto.randomUUID().split('-')[0]}`;
|
||||
await connection.query('INSERT INTO tenants (id, name, slug, admin_email, status) VALUES (?, ?, ?, ?, ?)', [tid, name, slug, admin_email, status || 'active']);
|
||||
|
||||
const [existingUser] = await connection.query('SELECT id FROM users WHERE email = ?', [admin_email]);
|
||||
if (existingUser.length === 0) {
|
||||
const uid = `u_${crypto.randomUUID().split('-')[0]}`;
|
||||
const userSlug = `admin-${crypto.randomBytes(4).toString('hex')}`;
|
||||
const placeholderHash = 'pending_setup';
|
||||
await connection.query('INSERT INTO users (id, tenant_id, name, email, password_hash, slug, role) VALUES (?, ?, ?, ?, ?, ?, ?)', [uid, tid, 'Admin', admin_email, placeholderHash, userSlug, 'admin']);
|
||||
|
||||
const token = crypto.randomBytes(32).toString('hex');
|
||||
await connection.query('INSERT INTO password_resets (email, token, expires_at) VALUES (?, ?, DATE_ADD(NOW(), INTERVAL 15 MINUTE))', [admin_email, token]);
|
||||
|
||||
const setupLink = `${getBaseUrl(req)}/#/setup-account?token=${token}`;
|
||||
|
||||
const [superAdmins] = await connection.query("SELECT id FROM users WHERE role = 'super_admin'");
|
||||
for (const sa of superAdmins) {
|
||||
await connection.query(
|
||||
'INSERT INTO notifications (id, user_id, type, title, message, link) VALUES (?, ?, ?, ?, ?, ?)',
|
||||
[crypto.randomUUID(), sa.id, 'success', 'Nova Organização', `A organização ${name} foi criada.`, '/super-admin']
|
||||
);
|
||||
}
|
||||
|
||||
await transporter.sendMail({
|
||||
from: `"Fasto" <${process.env.MAIL_FROM || 'nao-responda@blyzer.com.br'}>`,
|
||||
to: admin_email,
|
||||
subject: 'Bem-vindo ao Fasto - Conclua seu cadastro de Admin',
|
||||
html: `
|
||||
<div style="font-family: sans-serif; max-width: 600px; margin: 0 auto; padding: 20px; border: 1px solid #e2e8f0; border-radius: 12px; background: #ffffff; color: #0f172a;">
|
||||
<h2 style="color: #0f172a;">Sua organização foi criada</h2>
|
||||
<p style="color: #475569;">Você foi definido como administrador da organização <strong>${name}</strong>.</p>
|
||||
<p style="color: #475569;">Por favor, clique no botão abaixo para definir sua senha e concluir seu cadastro.</p>
|
||||
<div style="text-align: center; margin: 30px 0;">
|
||||
<a href="${setupLink}" style="background-color: #0f172a; color: white; padding: 12px 24px; text-decoration: none; border-radius: 8px; font-weight: bold; display: inline-block;">Finalizar Cadastro</a>
|
||||
</div>
|
||||
<p style="font-size: 12px; color: #94a3b8;">Este link expira em 15 minutos.</p>
|
||||
</div>
|
||||
`
|
||||
}).catch(err => console.error("Email failed:", err));
|
||||
}
|
||||
|
||||
await connection.commit();
|
||||
res.status(201).json({ id: tid, message: 'Organização criada e convite enviado por e-mail.' });
|
||||
} catch (error) {
|
||||
await connection.rollback();
|
||||
res.status(500).json({ error: error.message });
|
||||
} finally {
|
||||
connection.release();
|
||||
}
|
||||
});
|
||||
|
||||
router.put('/tenants/:id', requireRole(['super_admin']), async (req, res) => {
|
||||
const { name, slug, admin_email, status } = req.body;
|
||||
try {
|
||||
await pool.query(
|
||||
'UPDATE tenants SET name = ?, slug = ?, admin_email = ?, status = ? WHERE id = ?',
|
||||
[name, slug || null, admin_email, status, req.params.id]
|
||||
);
|
||||
res.json({ message: 'Tenant updated successfully.' });
|
||||
} catch (error) {
|
||||
res.status(500).json({ error: error.message });
|
||||
}
|
||||
});
|
||||
|
||||
router.delete('/tenants/:id', requireRole(['super_admin']), async (req, res) => {
|
||||
try {
|
||||
await pool.query('DELETE FROM tenants WHERE id = ?', [req.params.id]);
|
||||
res.json({ message: 'Tenant deleted successfully.' });
|
||||
} catch (error) {
|
||||
res.status(500).json({ error: error.message });
|
||||
}
|
||||
});
|
||||
|
||||
return router;
|
||||
};
|
||||
|
||||
module.exports = { createTenantsRouter };
|
||||
Reference in New Issue
Block a user