- Modelo Usuario + seed desde lista de vendedores (18 usuarios, bcrypt cost 12) - POST /api/auth/login + /api/auth/me; middleware Bearer en todo /api excepto health, login y webhook Monday; flag AUTH_ENABLED - Username = nombre completo normalizado (case/acentos insensible), password inicial Frasa2026, admin vía ADMIN_PASSWORD - Apps: LoginScreen + AuthGate (StudioBlank), token en localStorage, header Authorization en todas las llamadas, logout en 401 - Tests: api 136, cotizador 71, alta 65, cobranza 71, agente-ia 13, landing 4
124 lines
3.8 KiB
TypeScript
124 lines
3.8 KiB
TypeScript
/**
|
|
* Siembra los usuarios del ecosistema FRASA.
|
|
*
|
|
* - Lee reference/vendedores.json (gitignored). Si no existe, solo crea el
|
|
* usuario admin y avisa.
|
|
* - Username = nombre completo normalizado (minúsculas, sin acentos, espacios
|
|
* simples). Password inicial de todos: 'Frasa2026' (bcrypt cost 12).
|
|
* - Upsert por username: NO resetea el password de usuarios existentes.
|
|
* Con `--reset-passwords` sí lo restablece al inicial.
|
|
* - Admin: username 'admin', password de env ADMIN_PASSWORD (default
|
|
* 'Frasa2026'), rol 'admin'.
|
|
*
|
|
* Uso: npm run seed:usuarios [-- --reset-passwords]
|
|
*/
|
|
import fs from 'node:fs'
|
|
import path from 'node:path'
|
|
import bcrypt from 'bcryptjs'
|
|
import { prisma } from '../src/services/prisma.js'
|
|
import { normalizarUsername } from '../src/services/auth.service.js'
|
|
import { config } from '../src/config/index.js'
|
|
|
|
const PASSWORD_INICIAL = 'Frasa2026'
|
|
const BCRYPT_COST = 12
|
|
|
|
export interface DatosUsuarioSeed {
|
|
username: string
|
|
nombre: string
|
|
rol: string
|
|
asignacion: string | null
|
|
empleadoId: number | null
|
|
passwordHash: string
|
|
}
|
|
|
|
/**
|
|
* Upsert por username. NO toca el password de un usuario existente salvo que
|
|
* resetPasswords sea true (flag --reset-passwords).
|
|
*/
|
|
export async function upsertUsuario(
|
|
datos: DatosUsuarioSeed,
|
|
resetPasswords: boolean,
|
|
): Promise<'creado' | 'actualizado'> {
|
|
const existente = await prisma.usuario.findUnique({ where: { username: datos.username } })
|
|
if (!existente) {
|
|
await prisma.usuario.create({ data: datos })
|
|
return 'creado'
|
|
}
|
|
await prisma.usuario.update({
|
|
where: { username: datos.username },
|
|
data: {
|
|
nombre: datos.nombre,
|
|
rol: datos.rol,
|
|
asignacion: datos.asignacion,
|
|
empleadoId: datos.empleadoId,
|
|
...(resetPasswords ? { passwordHash: datos.passwordHash } : {}),
|
|
},
|
|
})
|
|
return 'actualizado'
|
|
}
|
|
|
|
interface VendedorJson {
|
|
empleadoId: number | null
|
|
nombre: string
|
|
asignacion: string | null
|
|
rol: string
|
|
}
|
|
|
|
async function main(): Promise<void> {
|
|
const resetPasswords = process.argv.includes('--reset-passwords')
|
|
const rutaVendedores = path.resolve(process.cwd(), '..', 'reference', 'vendedores.json')
|
|
const hashVendedores = bcrypt.hashSync(PASSWORD_INICIAL, BCRYPT_COST)
|
|
const hashAdmin = bcrypt.hashSync(config.auth.adminPassword, BCRYPT_COST)
|
|
|
|
let creados = 0
|
|
let actualizados = 0
|
|
|
|
if (fs.existsSync(rutaVendedores)) {
|
|
const json = JSON.parse(fs.readFileSync(rutaVendedores, 'utf8')) as { vendedores: VendedorJson[] }
|
|
for (const v of json.vendedores) {
|
|
const resultado = await upsertUsuario(
|
|
{
|
|
username: normalizarUsername(v.nombre),
|
|
nombre: v.nombre,
|
|
rol: v.rol,
|
|
asignacion: v.asignacion,
|
|
empleadoId: v.empleadoId,
|
|
passwordHash: hashVendedores,
|
|
},
|
|
resetPasswords,
|
|
)
|
|
if (resultado === 'creado') creados++
|
|
else actualizados++
|
|
}
|
|
console.log(`[seed-usuarios] vendedores: ${creados} creados, ${actualizados} actualizados`)
|
|
} else {
|
|
console.warn(`[seed-usuarios] AVISO: no existe ${rutaVendedores}; se crea solo el admin`)
|
|
}
|
|
|
|
const admin = await upsertUsuario(
|
|
{
|
|
username: 'admin',
|
|
nombre: 'Administrador FRASA',
|
|
rol: 'admin',
|
|
asignacion: null,
|
|
empleadoId: null,
|
|
passwordHash: hashAdmin,
|
|
},
|
|
resetPasswords,
|
|
)
|
|
console.log(`[seed-usuarios] admin ${admin}${resetPasswords ? ' (password restablecido)' : ''}`)
|
|
|
|
const total = await prisma.usuario.count()
|
|
console.log(`[seed-usuarios] total de usuarios en BD: ${total}`)
|
|
}
|
|
|
|
// Solo se ejecuta como script (npm run seed:usuarios); al importarlo en tests no corre
|
|
if (process.argv[1]?.endsWith('seed-usuarios.ts')) {
|
|
main()
|
|
.catch((err) => {
|
|
console.error('[seed-usuarios] falló:', err)
|
|
process.exitCode = 1
|
|
})
|
|
.finally(() => prisma.$disconnect())
|
|
}
|