fix: populate slugs for old users and include slug/team_id in jwt token
All checks were successful
Build and Deploy / build-and-push (push) Successful in 1m53s

This commit is contained in:
Cauê Faleiros
2026-03-06 16:15:16 -03:00
parent feb98d830b
commit 0d3ce93e32

View File

@@ -210,8 +210,8 @@ apiRouter.post('/auth/login', async (req, res) => {
const valid = await bcrypt.compare(password, user.password_hash); const valid = await bcrypt.compare(password, user.password_hash);
if (!valid) return res.status(401).json({ error: 'Credenciais inválidas.' }); if (!valid) return res.status(401).json({ error: 'Credenciais inválidas.' });
const token = jwt.sign({ id: user.id, tenant_id: user.tenant_id, role: user.role }, JWT_SECRET, { expiresIn: '24h' }); const token = jwt.sign({ id: user.id, tenant_id: user.tenant_id, role: user.role, team_id: user.team_id, slug: user.slug }, JWT_SECRET, { expiresIn: '24h' });
res.json({ token, user: { id: user.id, name: user.name, email: user.email, role: user.role, tenant_id: user.tenant_id } }); res.json({ token, user: { id: user.id, name: user.name, email: user.email, role: user.role, tenant_id: user.tenant_id, team_id: user.team_id, slug: user.slug } });
} catch (error) { } catch (error) {
res.status(500).json({ error: error.message }); res.status(500).json({ error: error.message });
} }
@@ -328,12 +328,13 @@ apiRouter.post('/users', requireRole(['admin', 'owner', 'super_admin']), async (
if (existing.length > 0) return res.status(400).json({ error: 'E-mail já cadastrado.' }); if (existing.length > 0) return res.status(400).json({ error: 'E-mail já cadastrado.' });
const uid = `u_${crypto.randomUUID().split('-')[0]}`; const uid = `u_${crypto.randomUUID().split('-')[0]}`;
const slug = `${name.toLowerCase().replace(/[^a-z0-9]+/g, '-')}-${crypto.randomBytes(4).toString('hex')}`;
const placeholderHash = 'pending_setup'; // Usuário não pode logar com isso const placeholderHash = 'pending_setup'; // Usuário não pode logar com isso
// 2. Criar Usuário // 2. Criar Usuário
await pool.query( await pool.query(
'INSERT INTO users (id, tenant_id, team_id, name, email, password_hash, role, status) VALUES (?, ?, ?, ?, ?, ?, ?, ?)', 'INSERT INTO users (id, tenant_id, team_id, name, email, password_hash, slug, role, status) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)',
[uid, effectiveTenantId, team_id || null, name, email, placeholderHash, role || 'agent', 'active'] [uid, effectiveTenantId, team_id || null, name, email, placeholderHash, slug, role || 'agent', 'active']
); );
// 3. Gerar Token de Setup de Senha (reusando lógica de reset) // 3. Gerar Token de Setup de Senha (reusando lógica de reset)
@@ -607,8 +608,9 @@ apiRouter.post('/tenants', requireRole(['super_admin']), async (req, res) => {
const [existingUser] = await connection.query('SELECT id FROM users WHERE email = ?', [admin_email]); const [existingUser] = await connection.query('SELECT id FROM users WHERE email = ?', [admin_email]);
if (existingUser.length === 0) { if (existingUser.length === 0) {
const uid = `u_${crypto.randomUUID().split('-')[0]}`; const uid = `u_${crypto.randomUUID().split('-')[0]}`;
const userSlug = `admin-${crypto.randomBytes(4).toString('hex')}`;
const placeholderHash = 'pending_setup'; const placeholderHash = 'pending_setup';
await connection.query('INSERT INTO users (id, tenant_id, name, email, password_hash, role) VALUES (?, ?, ?, ?, ?, ?)', [uid, tid, 'Admin', admin_email, placeholderHash, 'admin']); 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'); const token = crypto.randomBytes(32).toString('hex');
// Adicionar aos pending_registrations em vez de criar um usuário direto se quisermos que eles completem o cadastro. // Adicionar aos pending_registrations em vez de criar um usuário direto se quisermos que eles completem o cadastro.
@@ -713,6 +715,13 @@ const provisionSuperAdmin = async (retries = 10, delay = 10000) => {
if (err.code !== 'ER_DUP_FIELDNAME') console.log('Schema update note (slug):', err.message); if (err.code !== 'ER_DUP_FIELDNAME') console.log('Schema update note (slug):', err.message);
} }
// Populate empty slugs
try {
await connection.query(`UPDATE users SET slug = CONCAT(LOWER(REPLACE(name, ' ', '-')), '-', SUBSTRING(MD5(RAND()), 1, 8)) WHERE slug IS NULL`);
} catch (err) {
console.log('Schema update note (populate slugs):', err.message);
}
// Update origin enum // Update origin enum
try { try {
await connection.query("ALTER TABLE attendances MODIFY COLUMN origin ENUM('WhatsApp','Instagram','Website','LinkedIn','Indicação') NOT NULL"); await connection.query("ALTER TABLE attendances MODIFY COLUMN origin ENUM('WhatsApp','Instagram','Website','LinkedIn','Indicação') NOT NULL");
@@ -732,10 +741,11 @@ const provisionSuperAdmin = async (retries = 10, delay = 10000) => {
if (existing.length === 0) { if (existing.length === 0) {
const uid = `u_${crypto.randomUUID().split('-')[0]}`; const uid = `u_${crypto.randomUUID().split('-')[0]}`;
const placeholderHash = 'pending_setup'; const placeholderHash = 'pending_setup';
const superAdminSlug = 'suporte-blyzer';
await pool.query( await pool.query(
'INSERT INTO users (id, tenant_id, name, email, password_hash, role, status) VALUES (?, ?, ?, ?, ?, ?, ?)', 'INSERT INTO users (id, tenant_id, name, email, password_hash, slug, role, status) VALUES (?, ?, ?, ?, ?, ?, ?, ?)',
[uid, 'system', 'Blyzer Suporte', email, placeholderHash, 'super_admin', 'active'] [uid, 'system', 'Blyzer Suporte', email, placeholderHash, superAdminSlug, 'super_admin', 'active']
); );
} }