UNPKG

skailan-core

Version:

Servicio de autenticación y multitenancy para Skailan.

176 lines (175 loc) 6.88 kB
const JWT_SECRET = process.env.JWT_SECRET || "skailan-secret"; export class OrganizationService { static async createOrganization(prisma, userId, name, slug, domain, subdomain) { // Inicializar trial de 14 días const now = new Date(); const trialEnd = new Date(now.getTime() + 14 * 24 * 60 * 60 * 1000); const org = await prisma.organization.create({ data: { name, slug, domain, subdomain, trialStart: now, trialEnd: trialEnd, isBlocked: false, }, }); await prisma.membership.create({ data: { userId, organizationId: org.id, role: "OWNER", status: "ACTIVE" }, }); // Función auxiliar para provisionar el esquema del tenant await this.provisionTenantSchema(prisma, org.slug); return org; } // Función para provisionar el esquema del tenant static async provisionTenantSchema(prisma, organizationSlug) { const schemaName = `org_${organizationSlug}`; const productTableSql = ` CREATE TABLE "${schemaName}"."products" ( "id" TEXT NOT NULL, "name" TEXT NOT NULL, "description" TEXT, "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, "updatedAt" TIMESTAMP(3) NOT NULL, CONSTRAINT "products_pkey" PRIMARY KEY ("id") ); `; try { await prisma.$executeRawUnsafe(`CREATE SCHEMA IF NOT EXISTS "${schemaName}";`); await prisma.$executeRawUnsafe(productTableSql); console.log(`Esquema y tablas provisionadas para el tenant: ${schemaName}`); } catch (error) { console.error(`Error provisionando el esquema para ${schemaName}:`, error); throw error; // Re-lanzar el error para que la transacción de creación de la organización falle } } static async listOrganizations(prisma, userId, page, limit) { const skip = (page - 1) * limit; const [memberships, total] = await Promise.all([ prisma.membership.findMany({ where: { userId }, include: { organization: true }, skip, take: limit, }), prisma.membership.count({ where: { userId } }), ]); const organizations = memberships .map((m) => m.organization) .filter(Boolean); return { data: organizations, meta: { total, page, limit, totalPages: Math.ceil(total / limit), }, }; } static async getOrganization(prisma, userId, organizationId) { const membership = await prisma.membership.findUnique({ where: { userId_organizationId: { userId, organizationId } }, include: { organization: true }, }); if (!membership) { throw new Error("No tienes acceso a esta organización."); } return membership.organization; } static async updateOrganization(prisma, userId, organizationId, name, domain, subdomain) { const membership = await prisma.membership.findUnique({ where: { userId_organizationId: { userId, organizationId } }, }); if (!membership || membership.role !== "OWNER") { throw new Error("Solo el propietario puede editar."); } const org = await prisma.organization.update({ where: { id: organizationId }, data: { name, domain, subdomain }, }); return org; } static async deleteOrganization(prisma, userId, organizationId) { const membership = await prisma.membership.findUnique({ where: { userId_organizationId: { userId, organizationId } }, }); if (!membership || membership.role !== "OWNER") { throw new Error("Solo el propietario puede eliminar."); } const members = await prisma.membership.count({ where: { organizationId }, }); if (members > 1) { throw new Error("No se puede eliminar una organización con más de un miembro."); } await prisma.organization.update({ where: { id: organizationId }, data: { deletedAt: new Date() }, }); } static async getOrganizationSettings(prisma, userId, organizationId) { const membership = await prisma.membership.findUnique({ where: { userId_organizationId: { userId, organizationId } }, }); if (!membership) { throw new Error("No tienes acceso a esta organización."); } const org = await prisma.organization.findUnique({ where: { id: organizationId }, }); if (!org) { throw new Error("Organización no encontrada."); } return { settings: org.settings || {} }; } static async updateOrganizationSettings(prisma, userId, organizationId, settings) { const membership = await prisma.membership.findUnique({ where: { userId_organizationId: { userId, organizationId } }, }); if (!membership || membership.role !== "OWNER") { throw new Error("Solo el propietario puede modificar los settings."); } const org = await prisma.organization.update({ where: { id: organizationId }, data: { settings }, }); return { settings: org.settings }; } static async getOrganizationStatus(prisma, userId, organizationId) { const membership = await prisma.membership.findUnique({ where: { userId_organizationId: { userId, organizationId } }, }); if (!membership) { throw new Error("No tienes acceso a esta organización."); } const org = await prisma.organization.findUnique({ where: { id: organizationId }, include: { Subscription: { where: { status: "ACTIVE" }, include: { plan: true } }, }, }); if (!org) { throw new Error("Organización no encontrada."); } let trialDaysLeft = null; if (org.trialEnd) { const now = new Date(); const diff = org.trialEnd.getTime() - now.getTime(); trialDaysLeft = Math.max(0, Math.ceil(diff / (1000 * 60 * 60 * 24))); } const activePlan = org.Subscription && org.Subscription.length > 0 ? org.Subscription[0]?.plan || null : null; return { trialStart: org.trialStart, trialEnd: org.trialEnd, trialDaysLeft, isBlocked: org.isBlocked, activePlan, }; } } //# sourceMappingURL=OrganizationService.js.map