archetecture security fix
This commit is contained in:
@@ -0,0 +1,69 @@
|
||||
export declare function listBillingAccounts(query: {
|
||||
q?: string;
|
||||
status?: string;
|
||||
plan?: string;
|
||||
page: number;
|
||||
pageSize: number;
|
||||
}): Promise<{
|
||||
data: any[];
|
||||
total: any;
|
||||
stats: {
|
||||
billingAccountCount: any;
|
||||
openInvoiceCount: any;
|
||||
pastDueInvoiceCount: any;
|
||||
paidInvoiceCount: any;
|
||||
accountsReceivableTotal: any;
|
||||
recognizedRevenueTotal: any;
|
||||
};
|
||||
}>;
|
||||
export declare function getBillingAccountDetail(companyId: string): Promise<any>;
|
||||
export declare function updateBillingAccount(billingAccountId: string, data: {
|
||||
legalName?: string;
|
||||
billingEmail?: string;
|
||||
billingAddress?: any;
|
||||
taxId?: string | null;
|
||||
taxExempt?: boolean;
|
||||
invoiceTerms?: string;
|
||||
netTermsDays?: number;
|
||||
}, adminId: string, ip?: string): Promise<any>;
|
||||
export declare function setDunningPaused(billingAccountId: string, paused: boolean, adminId: string, ip?: string): Promise<any>;
|
||||
export declare function createDraftInvoice(billingAccountId: string, data: {
|
||||
subscriptionId?: string | null;
|
||||
invoiceType: string;
|
||||
currency?: string;
|
||||
dueAt?: string | null;
|
||||
isSubscriptionBlocking?: boolean;
|
||||
adminReason?: string | null;
|
||||
lineItems: Array<{
|
||||
type: string;
|
||||
description: string;
|
||||
quantity: number;
|
||||
unitAmount: number;
|
||||
periodStart?: string | null;
|
||||
periodEnd?: string | null;
|
||||
}>;
|
||||
}, adminId: string, ip?: string): Promise<any>;
|
||||
export declare function finalizeInvoice(invoiceId: string, adminId: string, ip?: string): Promise<any>;
|
||||
export declare function payInvoice(invoiceId: string, data: {
|
||||
amount?: number;
|
||||
paymentMethodId?: string | null;
|
||||
providerPaymentId?: string | null;
|
||||
}, adminId: string, ip?: string): Promise<any>;
|
||||
export declare function retryInvoicePayment(invoiceId: string, data: {
|
||||
paymentMethodId?: string | null;
|
||||
}, adminId: string, ip?: string): Promise<any>;
|
||||
export declare function voidInvoice(invoiceId: string, reason: string, adminId: string, ip?: string): Promise<any>;
|
||||
export declare function markInvoiceUncollectible(invoiceId: string, reason: string, adminId: string, ip?: string): Promise<any>;
|
||||
export declare function issueCreditNote(invoiceId: string, data: {
|
||||
amount: number;
|
||||
reason: string;
|
||||
}, adminId: string, ip?: string): Promise<any>;
|
||||
export declare function issueRefund(invoiceId: string, data: {
|
||||
amount: number;
|
||||
reason: string;
|
||||
}, adminId: string, ip?: string): Promise<any>;
|
||||
export declare function getInvoicePdf(invoiceId: string): Promise<{
|
||||
pdfBuffer: Buffer<ArrayBufferLike>;
|
||||
invoiceNumber: any;
|
||||
}>;
|
||||
//# sourceMappingURL=admin.billing.service.d.ts.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"admin.billing.service.d.ts","sourceRoot":"","sources":["../../../src/modules/admin/admin.billing.service.ts"],"names":[],"mappings":"AA8VA,wBAAsB,mBAAmB,CAAC,KAAK,EAAE;IAAE,CAAC,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE;;;;;;;;;;;GA2H9H;AAED,wBAAsB,uBAAuB,CAAC,SAAS,EAAE,MAAM,gBAyC9D;AAED,wBAAsB,oBAAoB,CACxC,gBAAgB,EAAE,MAAM,EACxB,IAAI,EAAE;IACJ,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,cAAc,CAAC,EAAE,GAAG,CAAA;IACpB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACrB,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB,EACD,OAAO,EAAE,MAAM,EACf,EAAE,CAAC,EAAE,MAAM,gBAuCZ;AAED,wBAAsB,gBAAgB,CACpC,gBAAgB,EAAE,MAAM,EACxB,MAAM,EAAE,OAAO,EACf,OAAO,EAAE,MAAM,EACf,EAAE,CAAC,EAAE,MAAM,gBAkCZ;AAED,wBAAsB,kBAAkB,CACtC,gBAAgB,EAAE,MAAM,EACxB,IAAI,EAAE;IACJ,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC9B,WAAW,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACrB,sBAAsB,CAAC,EAAE,OAAO,CAAA;IAChC,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC3B,SAAS,EAAE,KAAK,CAAC;QACf,IAAI,EAAE,MAAM,CAAA;QACZ,WAAW,EAAE,MAAM,CAAA;QACnB,QAAQ,EAAE,MAAM,CAAA;QAChB,UAAU,EAAE,MAAM,CAAA;QAClB,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;QAC3B,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;KAC1B,CAAC,CAAA;CACH,EACD,OAAO,EAAE,MAAM,EACf,EAAE,CAAC,EAAE,MAAM,gBAmEZ;AAED,wBAAsB,eAAe,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,MAAM,gBAwLpF;AAED,wBAAsB,UAAU,CAC9B,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE;IACJ,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC/B,iBAAiB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAClC,EACD,OAAO,EAAE,MAAM,EACf,EAAE,CAAC,EAAE,MAAM,gBAiGZ;AAED,wBAAsB,mBAAmB,CACvC,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE;IAAE,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,EACzC,OAAO,EAAE,MAAM,EACf,EAAE,CAAC,EAAE,MAAM,gBA0EZ;AAED,wBAAsB,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,MAAM,gBAmDhG;AAED,wBAAsB,wBAAwB,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,MAAM,gBAgD7G;AAED,wBAAsB,eAAe,CACnC,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,EACxC,OAAO,EAAE,MAAM,EACf,EAAE,CAAC,EAAE,MAAM,gBA4EZ;AAED,wBAAsB,WAAW,CAC/B,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,EACxC,OAAO,EAAE,MAAM,EACf,EAAE,CAAC,EAAE,MAAM,gBA6EZ;AAED,wBAAsB,aAAa,CAAC,SAAS,EAAE,MAAM;;;GAiEpD"}
|
||||
+1227
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
@@ -0,0 +1,13 @@
|
||||
export declare function presentAdminUser<T extends Record<string, any>>(admin: T): Omit<T, "passwordHash" | "totpSecret">;
|
||||
export declare function presentAdminSession<T extends Record<string, any>>(admin: T, token: string): {
|
||||
token: string;
|
||||
admin: Omit<T, "passwordHash" | "totpSecret">;
|
||||
};
|
||||
export declare function presentPaginated<T>(data: T[], total: number, page: number, pageSize: number, extra?: Record<string, unknown>): {
|
||||
data: T[];
|
||||
total: number;
|
||||
page: number;
|
||||
pageSize: number;
|
||||
totalPages: number;
|
||||
};
|
||||
//# sourceMappingURL=admin.presenter.d.ts.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"admin.presenter.d.ts","sourceRoot":"","sources":["../../../src/modules/admin/admin.presenter.ts"],"names":[],"mappings":"AAAA,wBAAgB,gBAAgB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,KAAK,EAAE,CAAC,0CAGvE;AAED,wBAAgB,mBAAmB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM;;;EAKzF;AAED,wBAAgB,gBAAgB,CAAC,CAAC,EAChC,IAAI,EAAE,CAAC,EAAE,EACT,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,EAChB,KAAK,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM;;;;;;EAUpC"}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.presentAdminUser = presentAdminUser;
|
||||
exports.presentAdminSession = presentAdminSession;
|
||||
exports.presentPaginated = presentPaginated;
|
||||
function presentAdminUser(admin) {
|
||||
const { passwordHash, totpSecret, ...safe } = admin;
|
||||
return safe;
|
||||
}
|
||||
function presentAdminSession(admin, token) {
|
||||
return {
|
||||
token,
|
||||
admin: presentAdminUser(admin),
|
||||
};
|
||||
}
|
||||
function presentPaginated(data, total, page, pageSize, extra = {}) {
|
||||
return {
|
||||
data,
|
||||
total,
|
||||
page,
|
||||
pageSize,
|
||||
totalPages: Math.ceil(total / pageSize),
|
||||
...extra,
|
||||
};
|
||||
}
|
||||
//# sourceMappingURL=admin.presenter.js.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"admin.presenter.js","sourceRoot":"","sources":["../../../src/modules/admin/admin.presenter.ts"],"names":[],"mappings":";;AAAA,4CAGC;AAED,kDAKC;AAED,4CAeC;AA3BD,SAAgB,gBAAgB,CAAgC,KAAQ;IACtE,MAAM,EAAE,YAAY,EAAE,UAAU,EAAE,GAAG,IAAI,EAAE,GAAG,KAAK,CAAA;IACnD,OAAO,IAAI,CAAA;AACb,CAAC;AAED,SAAgB,mBAAmB,CAAgC,KAAQ,EAAE,KAAa;IACxF,OAAO;QACL,KAAK;QACL,KAAK,EAAE,gBAAgB,CAAC,KAAK,CAAC;KAC/B,CAAA;AACH,CAAC;AAED,SAAgB,gBAAgB,CAC9B,IAAS,EACT,KAAa,EACb,IAAY,EACZ,QAAgB,EAChB,QAAiC,EAAE;IAEnC,OAAO;QACL,IAAI;QACJ,KAAK;QACL,IAAI;QACJ,QAAQ;QACR,UAAU,EAAE,IAAI,CAAC,IAAI,CAAC,KAAK,GAAG,QAAQ,CAAC;QACvC,GAAG,KAAK;KACT,CAAA;AACH,CAAC"}
|
||||
+161
@@ -0,0 +1,161 @@
|
||||
export declare function findAdminByEmail(email: string): any;
|
||||
export declare function findAdminByIdOrThrow(id: string): any;
|
||||
export declare function updateAdminLastLogin(id: string): any;
|
||||
export declare function updateAdminTotpSecret(id: string, secret: string): any;
|
||||
export declare function enableAdminTotp(id: string): any;
|
||||
export declare function replaceAdminRecoveryCodes(adminUserId: string, codeHashes: string[]): Promise<any>;
|
||||
export declare function listUnusedAdminRecoveryCodes(adminUserId: string): any;
|
||||
export declare function markAdminRecoveryCodeUsed(id: string): any;
|
||||
export declare function setAdminPasswordReset(id: string, token: string, expiresAt: Date): any;
|
||||
export declare function findAdminByResetToken(token: string): any;
|
||||
export declare function updateAdminPassword(id: string, passwordHash: string): any;
|
||||
export declare function createAuditLog(data: Record<string, unknown>): any;
|
||||
export declare function listCompaniesPage(query: {
|
||||
q?: string;
|
||||
status?: string;
|
||||
plan?: string;
|
||||
page: number;
|
||||
pageSize: number;
|
||||
}): Promise<{
|
||||
data: any;
|
||||
total: any;
|
||||
}>;
|
||||
export declare function getCompanyDetail(id: string): any;
|
||||
export declare function getCompanyUpdateSnapshot(id: string): any;
|
||||
export declare function applyCompanyUpdate(id: string, body: any, current: {
|
||||
name: string;
|
||||
slug: string;
|
||||
address?: unknown;
|
||||
brand?: {
|
||||
paymentMethodsEnabled?: any[] | null;
|
||||
} | null;
|
||||
}): Promise<any>;
|
||||
export declare function updateCompanyStatus(id: string, status: string): any;
|
||||
export declare function deleteCompany(id: string): any;
|
||||
export declare function getCompanyForImpersonation(id: string): any;
|
||||
export declare function listRentersPage(query: {
|
||||
q?: string;
|
||||
blocked?: string;
|
||||
page: number;
|
||||
pageSize: number;
|
||||
}): Promise<{
|
||||
data: any;
|
||||
total: any;
|
||||
}>;
|
||||
export declare function updateRenterActive(id: string, isActive: boolean): any;
|
||||
export declare function getPlatformMetricCounts(): Promise<{
|
||||
totalCompanies: any;
|
||||
activeCompanies: any;
|
||||
trialingCompanies: any;
|
||||
suspendedCompanies: any;
|
||||
totalRenters: any;
|
||||
totalReservations: any;
|
||||
}>;
|
||||
export declare function listAuditLogsPage(query: {
|
||||
adminId?: string;
|
||||
action?: string;
|
||||
companyId?: string;
|
||||
entityId?: string;
|
||||
page: number;
|
||||
pageSize: number;
|
||||
}): Promise<{
|
||||
data: any;
|
||||
total: any;
|
||||
}>;
|
||||
export declare function listAdmins(): any;
|
||||
export declare function createAdmin(data: {
|
||||
email: string;
|
||||
firstName: string;
|
||||
lastName: string;
|
||||
role: string;
|
||||
passwordHash: string;
|
||||
permissions?: any[];
|
||||
}): any;
|
||||
export declare function updateAdminRole(id: string, role: string): any;
|
||||
export declare function updateAdmin(id: string, data: {
|
||||
email?: string;
|
||||
firstName?: string;
|
||||
lastName?: string;
|
||||
role?: string;
|
||||
passwordHash?: string;
|
||||
isActive?: boolean;
|
||||
}): any;
|
||||
export declare function replaceAdminPermissions(id: string, permissions: any[]): Promise<any>;
|
||||
export declare function listBillingPage(query: {
|
||||
status?: string;
|
||||
plan?: string;
|
||||
page: number;
|
||||
pageSize: number;
|
||||
}): Promise<{
|
||||
data: any;
|
||||
total: any;
|
||||
}>;
|
||||
export declare function listActiveSubscriptionsForMrr(): any;
|
||||
export declare function getBillingStatusCounts(): Promise<{
|
||||
activeCount: any;
|
||||
trialingCount: any;
|
||||
pastDueCount: any;
|
||||
cancelledCount: any;
|
||||
}>;
|
||||
export declare function listCompanyInvoicesPage(companyId: string, query: {
|
||||
page: number;
|
||||
pageSize: number;
|
||||
}): Promise<{
|
||||
data: any;
|
||||
total: any;
|
||||
}>;
|
||||
export declare function getInvoicePdfRecord(invoiceId: string): any;
|
||||
export declare function listPricingConfigs(): any;
|
||||
export declare function upsertPricingConfig(plan: string, billingPeriod: string, amount: number, updatedBy?: string): any;
|
||||
export declare function listPlanFeatures(): any;
|
||||
export declare function createPlanFeature(data: {
|
||||
plan: 'STARTER' | 'GROWTH' | 'PRO';
|
||||
label: string;
|
||||
sortOrder?: number;
|
||||
}): any;
|
||||
export declare function updatePlanFeature(id: string, data: Partial<{
|
||||
plan: 'STARTER' | 'GROWTH' | 'PRO';
|
||||
label: string;
|
||||
sortOrder: number;
|
||||
}>): any;
|
||||
export declare function deletePlanFeature(id: string): any;
|
||||
export declare function listPromotions(): any;
|
||||
export declare function createPromotion(data: {
|
||||
code: string;
|
||||
name: string;
|
||||
description?: string | null;
|
||||
discountType: string;
|
||||
discountValue: number;
|
||||
plans: string[];
|
||||
periods: string[];
|
||||
maxUses?: number | null;
|
||||
validFrom: string;
|
||||
validUntil?: string | null;
|
||||
isActive: boolean;
|
||||
createdBy?: string | null;
|
||||
}): any;
|
||||
export declare function updatePromotion(id: string, data: Partial<{
|
||||
code: string;
|
||||
name: string;
|
||||
description: string | null;
|
||||
discountType: string;
|
||||
discountValue: number;
|
||||
plans: string[];
|
||||
periods: string[];
|
||||
maxUses: number | null;
|
||||
validFrom: string;
|
||||
validUntil: string | null;
|
||||
isActive: boolean;
|
||||
}>): any;
|
||||
export declare function deletePromotion(id: string): any;
|
||||
export declare function listNotificationsPage(query: {
|
||||
channel?: string;
|
||||
status?: string;
|
||||
companyId?: string;
|
||||
page: number;
|
||||
pageSize: number;
|
||||
}): Promise<{
|
||||
data: any;
|
||||
total: any;
|
||||
}>;
|
||||
//# sourceMappingURL=admin.repo.d.ts.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"admin.repo.d.ts","sourceRoot":"","sources":["../../../src/modules/admin/admin.repo.ts"],"names":[],"mappings":"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"}
|
||||
+523
@@ -0,0 +1,523 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.findAdminByEmail = findAdminByEmail;
|
||||
exports.findAdminByIdOrThrow = findAdminByIdOrThrow;
|
||||
exports.updateAdminLastLogin = updateAdminLastLogin;
|
||||
exports.updateAdminTotpSecret = updateAdminTotpSecret;
|
||||
exports.enableAdminTotp = enableAdminTotp;
|
||||
exports.replaceAdminRecoveryCodes = replaceAdminRecoveryCodes;
|
||||
exports.listUnusedAdminRecoveryCodes = listUnusedAdminRecoveryCodes;
|
||||
exports.markAdminRecoveryCodeUsed = markAdminRecoveryCodeUsed;
|
||||
exports.setAdminPasswordReset = setAdminPasswordReset;
|
||||
exports.findAdminByResetToken = findAdminByResetToken;
|
||||
exports.updateAdminPassword = updateAdminPassword;
|
||||
exports.createAuditLog = createAuditLog;
|
||||
exports.listCompaniesPage = listCompaniesPage;
|
||||
exports.getCompanyDetail = getCompanyDetail;
|
||||
exports.getCompanyUpdateSnapshot = getCompanyUpdateSnapshot;
|
||||
exports.applyCompanyUpdate = applyCompanyUpdate;
|
||||
exports.updateCompanyStatus = updateCompanyStatus;
|
||||
exports.deleteCompany = deleteCompany;
|
||||
exports.getCompanyForImpersonation = getCompanyForImpersonation;
|
||||
exports.listRentersPage = listRentersPage;
|
||||
exports.updateRenterActive = updateRenterActive;
|
||||
exports.getPlatformMetricCounts = getPlatformMetricCounts;
|
||||
exports.listAuditLogsPage = listAuditLogsPage;
|
||||
exports.listAdmins = listAdmins;
|
||||
exports.createAdmin = createAdmin;
|
||||
exports.updateAdminRole = updateAdminRole;
|
||||
exports.updateAdmin = updateAdmin;
|
||||
exports.replaceAdminPermissions = replaceAdminPermissions;
|
||||
exports.listBillingPage = listBillingPage;
|
||||
exports.listActiveSubscriptionsForMrr = listActiveSubscriptionsForMrr;
|
||||
exports.getBillingStatusCounts = getBillingStatusCounts;
|
||||
exports.listCompanyInvoicesPage = listCompanyInvoicesPage;
|
||||
exports.getInvoicePdfRecord = getInvoicePdfRecord;
|
||||
exports.listPricingConfigs = listPricingConfigs;
|
||||
exports.upsertPricingConfig = upsertPricingConfig;
|
||||
exports.listPlanFeatures = listPlanFeatures;
|
||||
exports.createPlanFeature = createPlanFeature;
|
||||
exports.updatePlanFeature = updatePlanFeature;
|
||||
exports.deletePlanFeature = deletePlanFeature;
|
||||
exports.listPromotions = listPromotions;
|
||||
exports.createPromotion = createPromotion;
|
||||
exports.updatePromotion = updatePromotion;
|
||||
exports.deletePromotion = deletePromotion;
|
||||
exports.listNotificationsPage = listNotificationsPage;
|
||||
const prisma_1 = require("../../lib/prisma");
|
||||
const companyListInclude = {
|
||||
brand: { select: { displayName: true, logoUrl: true, subdomain: true } },
|
||||
contractSettings: { select: { legalName: true } },
|
||||
subscription: { select: { plan: true, status: true } },
|
||||
_count: { select: { employees: true, vehicles: true } },
|
||||
};
|
||||
const companyDetailInclude = {
|
||||
brand: true,
|
||||
contractSettings: true,
|
||||
accountingSettings: true,
|
||||
subscription: { include: { invoices: { orderBy: { createdAt: 'desc' }, take: 10 } } },
|
||||
employees: true,
|
||||
_count: { select: { employees: true, vehicles: true, customers: true, reservations: true } },
|
||||
};
|
||||
const billingInclude = {
|
||||
company: { select: { id: true, name: true, email: true, slug: true, status: true } },
|
||||
invoices: {
|
||||
select: { id: true, amount: true, currency: true, status: true, paidAt: true, createdAt: true },
|
||||
orderBy: { createdAt: 'desc' },
|
||||
take: 5,
|
||||
},
|
||||
_count: { select: { invoices: true } },
|
||||
};
|
||||
function parseOptionalDate(value) {
|
||||
if (!value)
|
||||
return null;
|
||||
return new Date(value);
|
||||
}
|
||||
function findAdminByEmail(email) {
|
||||
return prisma_1.prisma.adminUser.findFirst({
|
||||
where: {
|
||||
email: {
|
||||
equals: email,
|
||||
mode: 'insensitive',
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
function findAdminByIdOrThrow(id) {
|
||||
return prisma_1.prisma.adminUser.findUniqueOrThrow({ where: { id } });
|
||||
}
|
||||
function updateAdminLastLogin(id) {
|
||||
return prisma_1.prisma.adminUser.update({ where: { id }, data: { lastLoginAt: new Date() } });
|
||||
}
|
||||
function updateAdminTotpSecret(id, secret) {
|
||||
return prisma_1.prisma.adminUser.update({ where: { id }, data: { totpSecret: secret } });
|
||||
}
|
||||
function enableAdminTotp(id) {
|
||||
return prisma_1.prisma.adminUser.update({ where: { id }, data: { totpEnabled: true } });
|
||||
}
|
||||
async function replaceAdminRecoveryCodes(adminUserId, codeHashes) {
|
||||
return prisma_1.prisma.$transaction(async (tx) => {
|
||||
await tx.adminRecoveryCode.deleteMany({ where: { adminUserId } });
|
||||
await tx.adminRecoveryCode.createMany({
|
||||
data: codeHashes.map((codeHash) => ({ adminUserId, codeHash })),
|
||||
});
|
||||
});
|
||||
}
|
||||
function listUnusedAdminRecoveryCodes(adminUserId) {
|
||||
return prisma_1.prisma.adminRecoveryCode.findMany({
|
||||
where: { adminUserId, usedAt: null },
|
||||
select: { id: true, codeHash: true },
|
||||
orderBy: { createdAt: 'asc' },
|
||||
});
|
||||
}
|
||||
function markAdminRecoveryCodeUsed(id) {
|
||||
return prisma_1.prisma.adminRecoveryCode.update({ where: { id }, data: { usedAt: new Date() } });
|
||||
}
|
||||
function setAdminPasswordReset(id, token, expiresAt) {
|
||||
return prisma_1.prisma.adminUser.update({
|
||||
where: { id },
|
||||
data: { passwordResetToken: token, passwordResetExpiresAt: expiresAt },
|
||||
});
|
||||
}
|
||||
function findAdminByResetToken(token) {
|
||||
return prisma_1.prisma.adminUser.findFirst({
|
||||
where: {
|
||||
passwordResetToken: token,
|
||||
passwordResetExpiresAt: { gt: new Date() },
|
||||
},
|
||||
});
|
||||
}
|
||||
function updateAdminPassword(id, passwordHash) {
|
||||
return prisma_1.prisma.adminUser.update({
|
||||
where: { id },
|
||||
data: {
|
||||
passwordHash,
|
||||
passwordResetToken: null,
|
||||
passwordResetExpiresAt: null,
|
||||
},
|
||||
});
|
||||
}
|
||||
function createAuditLog(data) {
|
||||
return prisma_1.prisma.auditLog.create({ data: data });
|
||||
}
|
||||
async function listCompaniesPage(query) {
|
||||
const where = {};
|
||||
if (query.status)
|
||||
where.status = query.status;
|
||||
if (query.q) {
|
||||
where.OR = [
|
||||
{ name: { contains: query.q, mode: 'insensitive' } },
|
||||
{ email: { contains: query.q, mode: 'insensitive' } },
|
||||
{ slug: { contains: query.q, mode: 'insensitive' } },
|
||||
];
|
||||
}
|
||||
if (query.plan)
|
||||
where.subscription = { plan: query.plan };
|
||||
const [data, total] = await Promise.all([
|
||||
prisma_1.prisma.company.findMany({
|
||||
where,
|
||||
include: companyListInclude,
|
||||
skip: (query.page - 1) * query.pageSize,
|
||||
take: query.pageSize,
|
||||
orderBy: { createdAt: 'desc' },
|
||||
}),
|
||||
prisma_1.prisma.company.count({ where }),
|
||||
]);
|
||||
return { data, total };
|
||||
}
|
||||
function getCompanyDetail(id) {
|
||||
return prisma_1.prisma.company.findUniqueOrThrow({ where: { id }, include: companyDetailInclude });
|
||||
}
|
||||
function getCompanyUpdateSnapshot(id) {
|
||||
return prisma_1.prisma.company.findUniqueOrThrow({
|
||||
where: { id },
|
||||
include: { brand: true, contractSettings: true, accountingSettings: true, subscription: true },
|
||||
});
|
||||
}
|
||||
async function applyCompanyUpdate(id, body, current) {
|
||||
return prisma_1.prisma.$transaction(async (tx) => {
|
||||
if (body.company) {
|
||||
const companyData = { ...body.company };
|
||||
if (companyData.address && typeof companyData.address === 'object' && !Array.isArray(companyData.address)) {
|
||||
const baseAddress = current.address && typeof current.address === 'object' && !Array.isArray(current.address)
|
||||
? current.address
|
||||
: {};
|
||||
companyData.address = { ...baseAddress, ...companyData.address };
|
||||
}
|
||||
await tx.company.update({ where: { id }, data: companyData });
|
||||
}
|
||||
if (body.subscription) {
|
||||
const sub = body.subscription;
|
||||
await tx.subscription.upsert({
|
||||
where: { companyId: id },
|
||||
update: {
|
||||
...sub,
|
||||
trialStartAt: parseOptionalDate(sub.trialStartAt),
|
||||
trialEndAt: parseOptionalDate(sub.trialEndAt),
|
||||
currentPeriodStart: parseOptionalDate(sub.currentPeriodStart),
|
||||
currentPeriodEnd: parseOptionalDate(sub.currentPeriodEnd),
|
||||
cancelledAt: parseOptionalDate(sub.cancelledAt),
|
||||
},
|
||||
create: {
|
||||
companyId: id,
|
||||
plan: sub.plan ?? 'STARTER',
|
||||
billingPeriod: sub.billingPeriod ?? 'MONTHLY',
|
||||
status: sub.status ?? 'TRIALING',
|
||||
currency: sub.currency ?? 'MAD',
|
||||
trialStartAt: parseOptionalDate(sub.trialStartAt),
|
||||
trialEndAt: parseOptionalDate(sub.trialEndAt),
|
||||
currentPeriodStart: parseOptionalDate(sub.currentPeriodStart),
|
||||
currentPeriodEnd: parseOptionalDate(sub.currentPeriodEnd),
|
||||
cancelledAt: parseOptionalDate(sub.cancelledAt),
|
||||
cancelAtPeriodEnd: sub.cancelAtPeriodEnd ?? false,
|
||||
},
|
||||
});
|
||||
}
|
||||
if (body.brand) {
|
||||
await tx.brandSettings.upsert({
|
||||
where: { companyId: id },
|
||||
update: body.brand,
|
||||
create: {
|
||||
companyId: id,
|
||||
displayName: body.brand.displayName ?? current.name,
|
||||
subdomain: body.brand.subdomain ?? current.slug,
|
||||
paymentMethodsEnabled: current.brand?.paymentMethodsEnabled ?? [],
|
||||
...body.brand,
|
||||
},
|
||||
});
|
||||
}
|
||||
if (body.contractSettings) {
|
||||
await tx.contractSettings.upsert({
|
||||
where: { companyId: id },
|
||||
update: body.contractSettings,
|
||||
create: { companyId: id, ...body.contractSettings },
|
||||
});
|
||||
}
|
||||
if (body.accountingSettings) {
|
||||
await tx.accountingSettings.upsert({
|
||||
where: { companyId: id },
|
||||
update: body.accountingSettings,
|
||||
create: { companyId: id, ...body.accountingSettings },
|
||||
});
|
||||
}
|
||||
return tx.company.findUniqueOrThrow({ where: { id }, include: companyDetailInclude });
|
||||
});
|
||||
}
|
||||
function updateCompanyStatus(id, status) {
|
||||
return prisma_1.prisma.company.update({ where: { id }, data: { status: status } });
|
||||
}
|
||||
function deleteCompany(id) {
|
||||
return prisma_1.prisma.company.delete({ where: { id } });
|
||||
}
|
||||
function getCompanyForImpersonation(id) {
|
||||
return prisma_1.prisma.company.findUniqueOrThrow({
|
||||
where: { id },
|
||||
include: { employees: { where: { role: 'OWNER' } } },
|
||||
});
|
||||
}
|
||||
async function listRentersPage(query) {
|
||||
const where = {};
|
||||
if (query.blocked !== undefined)
|
||||
where.isActive = query.blocked === 'false';
|
||||
if (query.q) {
|
||||
where.OR = [
|
||||
{ firstName: { contains: query.q, mode: 'insensitive' } },
|
||||
{ email: { contains: query.q, mode: 'insensitive' } },
|
||||
];
|
||||
}
|
||||
const [data, total] = await Promise.all([
|
||||
prisma_1.prisma.renter.findMany({
|
||||
where,
|
||||
select: {
|
||||
id: true,
|
||||
firstName: true,
|
||||
lastName: true,
|
||||
email: true,
|
||||
phone: true,
|
||||
isActive: true,
|
||||
createdAt: true,
|
||||
_count: { select: { reservations: true } },
|
||||
},
|
||||
skip: (query.page - 1) * query.pageSize,
|
||||
take: query.pageSize,
|
||||
orderBy: { createdAt: 'desc' },
|
||||
}),
|
||||
prisma_1.prisma.renter.count({ where }),
|
||||
]);
|
||||
return { data, total };
|
||||
}
|
||||
function updateRenterActive(id, isActive) {
|
||||
return prisma_1.prisma.renter.update({ where: { id }, data: { isActive } });
|
||||
}
|
||||
async function getPlatformMetricCounts() {
|
||||
const [totalCompanies, activeCompanies, trialingCompanies, suspendedCompanies, totalRenters, totalReservations,] = await Promise.all([
|
||||
prisma_1.prisma.company.count(),
|
||||
prisma_1.prisma.company.count({ where: { status: 'ACTIVE' } }),
|
||||
prisma_1.prisma.company.count({ where: { status: 'TRIALING' } }),
|
||||
prisma_1.prisma.company.count({ where: { status: 'SUSPENDED' } }),
|
||||
prisma_1.prisma.renter.count(),
|
||||
prisma_1.prisma.reservation.count(),
|
||||
]);
|
||||
return {
|
||||
totalCompanies,
|
||||
activeCompanies,
|
||||
trialingCompanies,
|
||||
suspendedCompanies,
|
||||
totalRenters,
|
||||
totalReservations,
|
||||
};
|
||||
}
|
||||
async function listAuditLogsPage(query) {
|
||||
const where = {};
|
||||
if (query.adminId)
|
||||
where.adminUserId = query.adminId;
|
||||
if (query.action)
|
||||
where.action = { contains: query.action };
|
||||
if (query.companyId)
|
||||
where.companyId = query.companyId;
|
||||
if (query.entityId)
|
||||
where.resourceId = query.entityId;
|
||||
const [data, total] = await Promise.all([
|
||||
prisma_1.prisma.auditLog.findMany({
|
||||
where,
|
||||
include: { adminUser: { select: { firstName: true, lastName: true, email: true } } },
|
||||
skip: (query.page - 1) * query.pageSize,
|
||||
take: query.pageSize,
|
||||
orderBy: { createdAt: 'desc' },
|
||||
}),
|
||||
prisma_1.prisma.auditLog.count({ where }),
|
||||
]);
|
||||
return { data, total };
|
||||
}
|
||||
function listAdmins() {
|
||||
return prisma_1.prisma.adminUser.findMany({
|
||||
include: { permissions: true },
|
||||
});
|
||||
}
|
||||
function createAdmin(data) {
|
||||
return prisma_1.prisma.adminUser.create({
|
||||
data: {
|
||||
email: data.email,
|
||||
firstName: data.firstName,
|
||||
lastName: data.lastName,
|
||||
role: data.role,
|
||||
passwordHash: data.passwordHash,
|
||||
permissions: data.permissions ? { create: data.permissions } : undefined,
|
||||
},
|
||||
include: { permissions: true },
|
||||
});
|
||||
}
|
||||
function updateAdminRole(id, role) {
|
||||
return prisma_1.prisma.adminUser.update({ where: { id }, data: { role: role } });
|
||||
}
|
||||
function updateAdmin(id, data) {
|
||||
return prisma_1.prisma.adminUser.update({
|
||||
where: { id },
|
||||
data: {
|
||||
...(data.email !== undefined ? { email: data.email } : {}),
|
||||
...(data.firstName !== undefined ? { firstName: data.firstName } : {}),
|
||||
...(data.lastName !== undefined ? { lastName: data.lastName } : {}),
|
||||
...(data.role !== undefined ? { role: data.role } : {}),
|
||||
...(data.passwordHash !== undefined ? { passwordHash: data.passwordHash } : {}),
|
||||
...(data.isActive !== undefined ? { isActive: data.isActive } : {}),
|
||||
},
|
||||
include: { permissions: true },
|
||||
});
|
||||
}
|
||||
async function replaceAdminPermissions(id, permissions) {
|
||||
await prisma_1.prisma.adminUser.findUniqueOrThrow({ where: { id } });
|
||||
await prisma_1.prisma.$transaction([
|
||||
prisma_1.prisma.adminPermission.deleteMany({ where: { adminUserId: id } }),
|
||||
prisma_1.prisma.adminPermission.createMany({
|
||||
data: permissions.map((permission) => ({
|
||||
adminUserId: id,
|
||||
resource: permission.resource,
|
||||
actions: permission.actions,
|
||||
})),
|
||||
}),
|
||||
]);
|
||||
return prisma_1.prisma.adminUser.findUniqueOrThrow({ where: { id }, include: { permissions: true } });
|
||||
}
|
||||
async function listBillingPage(query) {
|
||||
const where = {};
|
||||
if (query.status)
|
||||
where.status = query.status;
|
||||
if (query.plan)
|
||||
where.plan = query.plan;
|
||||
const [data, total] = await Promise.all([
|
||||
prisma_1.prisma.subscription.findMany({
|
||||
where,
|
||||
include: billingInclude,
|
||||
skip: (query.page - 1) * query.pageSize,
|
||||
take: query.pageSize,
|
||||
orderBy: { createdAt: 'desc' },
|
||||
}),
|
||||
prisma_1.prisma.subscription.count({ where }),
|
||||
]);
|
||||
return { data, total };
|
||||
}
|
||||
function listActiveSubscriptionsForMrr() {
|
||||
return prisma_1.prisma.subscription.findMany({
|
||||
where: { status: { in: ['ACTIVE', 'TRIALING'] } },
|
||||
select: { plan: true, billingPeriod: true },
|
||||
});
|
||||
}
|
||||
async function getBillingStatusCounts() {
|
||||
const [activeCount, trialingCount, pastDueCount, cancelledCount] = await Promise.all([
|
||||
prisma_1.prisma.subscription.count({ where: { status: 'ACTIVE' } }),
|
||||
prisma_1.prisma.subscription.count({ where: { status: 'TRIALING' } }),
|
||||
prisma_1.prisma.subscription.count({ where: { status: 'PAST_DUE' } }),
|
||||
prisma_1.prisma.subscription.count({ where: { status: 'CANCELLED' } }),
|
||||
]);
|
||||
return { activeCount, trialingCount, pastDueCount, cancelledCount };
|
||||
}
|
||||
async function listCompanyInvoicesPage(companyId, query) {
|
||||
const [data, total] = await Promise.all([
|
||||
prisma_1.prisma.subscriptionInvoice.findMany({
|
||||
where: { companyId },
|
||||
orderBy: { createdAt: 'desc' },
|
||||
skip: (query.page - 1) * query.pageSize,
|
||||
take: query.pageSize,
|
||||
}),
|
||||
prisma_1.prisma.subscriptionInvoice.count({ where: { companyId } }),
|
||||
]);
|
||||
return { data, total };
|
||||
}
|
||||
function getInvoicePdfRecord(invoiceId) {
|
||||
return prisma_1.prisma.subscriptionInvoice.findUniqueOrThrow({
|
||||
where: { id: invoiceId },
|
||||
include: {
|
||||
company: { select: { name: true, email: true, phone: true, address: true } },
|
||||
subscription: {
|
||||
select: {
|
||||
plan: true,
|
||||
billingPeriod: true,
|
||||
currency: true,
|
||||
currentPeriodStart: true,
|
||||
currentPeriodEnd: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
function listPricingConfigs() {
|
||||
return prisma_1.prisma.pricingConfig.findMany({ orderBy: [{ plan: 'asc' }, { billingPeriod: 'asc' }] });
|
||||
}
|
||||
function upsertPricingConfig(plan, billingPeriod, amount, updatedBy) {
|
||||
return prisma_1.prisma.pricingConfig.upsert({
|
||||
where: { plan_billingPeriod: { plan, billingPeriod } },
|
||||
update: { amount, updatedBy },
|
||||
create: { id: `prc_${plan.toLowerCase()}_${billingPeriod.toLowerCase()}`, plan, billingPeriod, amount, updatedBy },
|
||||
});
|
||||
}
|
||||
function listPlanFeatures() {
|
||||
return prisma_1.prisma.planFeature.findMany({
|
||||
orderBy: [{ plan: 'asc' }, { sortOrder: 'asc' }, { createdAt: 'asc' }],
|
||||
});
|
||||
}
|
||||
function createPlanFeature(data) {
|
||||
return prisma_1.prisma.planFeature.create({
|
||||
data: {
|
||||
plan: data.plan,
|
||||
label: data.label,
|
||||
sortOrder: data.sortOrder ?? 0,
|
||||
},
|
||||
});
|
||||
}
|
||||
function updatePlanFeature(id, data) {
|
||||
return prisma_1.prisma.planFeature.update({
|
||||
where: { id },
|
||||
data,
|
||||
});
|
||||
}
|
||||
function deletePlanFeature(id) {
|
||||
return prisma_1.prisma.planFeature.delete({ where: { id } });
|
||||
}
|
||||
// ─── Pricing promotions ────────────────────────────────────────────────────
|
||||
function listPromotions() {
|
||||
return prisma_1.prisma.pricingPromotion.findMany({ orderBy: { createdAt: 'desc' } });
|
||||
}
|
||||
function createPromotion(data) {
|
||||
return prisma_1.prisma.pricingPromotion.create({
|
||||
data: {
|
||||
...data,
|
||||
validFrom: new Date(data.validFrom),
|
||||
validUntil: data.validUntil ? new Date(data.validUntil) : null,
|
||||
},
|
||||
});
|
||||
}
|
||||
function updatePromotion(id, data) {
|
||||
const { validFrom, validUntil, ...rest } = data;
|
||||
return prisma_1.prisma.pricingPromotion.update({
|
||||
where: { id },
|
||||
data: {
|
||||
...rest,
|
||||
...(validFrom ? { validFrom: new Date(validFrom) } : {}),
|
||||
...(validUntil !== undefined ? { validUntil: validUntil ? new Date(validUntil) : null } : {}),
|
||||
},
|
||||
});
|
||||
}
|
||||
function deletePromotion(id) {
|
||||
return prisma_1.prisma.pricingPromotion.delete({ where: { id } });
|
||||
}
|
||||
async function listNotificationsPage(query) {
|
||||
const where = {};
|
||||
if (query.channel)
|
||||
where.channel = query.channel;
|
||||
if (query.status)
|
||||
where.status = query.status;
|
||||
if (query.companyId)
|
||||
where.companyId = query.companyId;
|
||||
const [data, total] = await Promise.all([
|
||||
prisma_1.prisma.notification.findMany({
|
||||
where,
|
||||
orderBy: { createdAt: 'desc' },
|
||||
skip: (query.page - 1) * query.pageSize,
|
||||
take: query.pageSize,
|
||||
include: { company: { select: { name: true } } },
|
||||
}),
|
||||
prisma_1.prisma.notification.count({ where }),
|
||||
]);
|
||||
return { data, total };
|
||||
}
|
||||
//# sourceMappingURL=admin.repo.js.map
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,3 @@
|
||||
declare const router: import("express-serve-static-core").Router;
|
||||
export default router;
|
||||
//# sourceMappingURL=admin.routes.d.ts.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"admin.routes.d.ts","sourceRoot":"","sources":["../../../src/modules/admin/admin.routes.ts"],"names":[],"mappings":"AAsCA,QAAA,MAAM,MAAM,4CAAW,CAAA;AAwhBvB,eAAe,MAAM,CAAA"}
|
||||
+720
@@ -0,0 +1,720 @@
|
||||
"use strict";
|
||||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
var desc = Object.getOwnPropertyDescriptor(m, k);
|
||||
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
||||
desc = { enumerable: true, get: function() { return m[k]; } };
|
||||
}
|
||||
Object.defineProperty(o, k2, desc);
|
||||
}) : (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
o[k2] = m[k];
|
||||
}));
|
||||
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
||||
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
||||
}) : function(o, v) {
|
||||
o["default"] = v;
|
||||
});
|
||||
var __importStar = (this && this.__importStar) || (function () {
|
||||
var ownKeys = function(o) {
|
||||
ownKeys = Object.getOwnPropertyNames || function (o) {
|
||||
var ar = [];
|
||||
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
||||
return ar;
|
||||
};
|
||||
return ownKeys(o);
|
||||
};
|
||||
return function (mod) {
|
||||
if (mod && mod.__esModule) return mod;
|
||||
var result = {};
|
||||
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
||||
__setModuleDefault(result, mod);
|
||||
return result;
|
||||
};
|
||||
})();
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const express_1 = require("express");
|
||||
const requireAdminAuth_1 = require("../../middleware/requireAdminAuth");
|
||||
const validate_1 = require("../../http/validate");
|
||||
const respond_1 = require("../../http/respond");
|
||||
const sessionCookies_1 = require("../../security/sessionCookies");
|
||||
const service = __importStar(require("./admin.service"));
|
||||
const subService = __importStar(require("../subscriptions/subscription.service"));
|
||||
const menuService = __importStar(require("../menu/menu.service"));
|
||||
const admin_presenter_1 = require("./admin.presenter");
|
||||
const admin_schemas_1 = require("./admin.schemas");
|
||||
const zod_1 = require("zod");
|
||||
const adminSubOverrideSchema = zod_1.z.object({
|
||||
reason: zod_1.z.string().min(1).max(500),
|
||||
});
|
||||
const adminExtendTrialSchema = zod_1.z.object({
|
||||
extraDays: zod_1.z.number().int().positive(),
|
||||
reason: zod_1.z.string().min(1).max(500),
|
||||
});
|
||||
const adminImpersonationSchema = zod_1.z.object({
|
||||
reason: zod_1.z.string().min(5).max(500),
|
||||
durationMinutes: zod_1.z.number().int().min(1).max(30).default(15),
|
||||
});
|
||||
const subIdParamSchema = zod_1.z.object({ subscriptionId: zod_1.z.string() });
|
||||
const router = (0, express_1.Router)();
|
||||
// ─── Auth (public) ─────────────────────────────────────────────
|
||||
router.post('/auth/login', async (req, res, next) => {
|
||||
try {
|
||||
const { email, password, totpCode, recoveryCode } = (0, validate_1.parseBody)(admin_schemas_1.loginSchema, req);
|
||||
const result = await service.login(email, password, totpCode, recoveryCode);
|
||||
if (!result)
|
||||
return res.status(401).json({ error: 'invalid_credentials', message: 'Invalid email or password', statusCode: 401 });
|
||||
if ('totpRequired' in result)
|
||||
return res.status(401).json({ error: 'totp_required', message: '2FA code required', statusCode: 401 });
|
||||
if ('invalidTotp' in result)
|
||||
return res.status(401).json({ error: 'invalid_totp', message: 'Invalid 2FA code', statusCode: 401 });
|
||||
(0, sessionCookies_1.setSessionCookie)(res, 'admin', result.token, 8 * 60 * 60 * 1000);
|
||||
(0, respond_1.ok)(res, result);
|
||||
}
|
||||
catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
router.post('/auth/logout', (_req, res) => {
|
||||
(0, sessionCookies_1.clearSessionCookie)(res, 'admin');
|
||||
(0, respond_1.ok)(res, { success: true });
|
||||
});
|
||||
router.post('/auth/forgot-password', async (req, res, next) => {
|
||||
try {
|
||||
const { email } = (0, validate_1.parseBody)(admin_schemas_1.forgotPasswordSchema, req);
|
||||
await service.forgotPassword(email);
|
||||
(0, respond_1.ok)(res, { message: 'If that email is registered, a reset link has been sent.' });
|
||||
}
|
||||
catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
router.post('/auth/reset-password', async (req, res, next) => {
|
||||
try {
|
||||
const { token, password } = (0, validate_1.parseBody)(admin_schemas_1.resetPasswordSchema, req);
|
||||
const ok2 = await service.resetPassword(token, password);
|
||||
if (!ok2)
|
||||
return res.status(400).json({ error: 'invalid_token', message: 'Reset link is invalid or has expired.', statusCode: 400 });
|
||||
(0, respond_1.ok)(res, { message: 'Password updated successfully. You can now sign in.' });
|
||||
}
|
||||
catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
// ─── Auth (protected) ──────────────────────────────────────────
|
||||
router.get('/auth/me', requireAdminAuth_1.requireAdminAuth, (req, res) => {
|
||||
(0, respond_1.ok)(res, (0, admin_presenter_1.presentAdminUser)(req.admin));
|
||||
});
|
||||
router.post('/auth/2fa/setup', requireAdminAuth_1.requireAdminAuth, async (req, res, next) => {
|
||||
try {
|
||||
(0, respond_1.ok)(res, await service.setupTotp(req.admin.id, req.admin.email));
|
||||
}
|
||||
catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
router.post('/auth/2fa/verify', requireAdminAuth_1.requireAdminAuth, async (req, res, next) => {
|
||||
try {
|
||||
const { code } = (0, validate_1.parseBody)(admin_schemas_1.totpVerifySchema, req);
|
||||
const result = await service.verifyTotp(req.admin.id, code);
|
||||
if (!result)
|
||||
return res.status(400).json({ error: 'invalid_code', message: 'Invalid 2FA code', statusCode: 400 });
|
||||
(0, sessionCookies_1.setSessionCookie)(res, 'admin', result.token, 8 * 60 * 60 * 1000);
|
||||
(0, respond_1.ok)(res, { success: true, admin: result.admin, recoveryCodes: result.recoveryCodes });
|
||||
}
|
||||
catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
router.post('/auth/2fa/recovery-codes/regenerate', requireAdminAuth_1.requireAdminAuth, requireAdminAuth_1.requireFreshAdmin2FA, async (req, res, next) => {
|
||||
try {
|
||||
(0, respond_1.ok)(res, await service.regenerateRecoveryCodes(req.admin.id));
|
||||
}
|
||||
catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
// ─── Companies ─────────────────────────────────────────────────
|
||||
router.get('/companies', requireAdminAuth_1.requireAdminAuth, async (req, res, next) => {
|
||||
try {
|
||||
(0, respond_1.ok)(res, await service.listCompanies((0, validate_1.parseQuery)(admin_schemas_1.companiesQuerySchema, req)));
|
||||
}
|
||||
catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
router.get('/companies/:id', requireAdminAuth_1.requireAdminAuth, async (req, res, next) => {
|
||||
try {
|
||||
const { id } = (0, validate_1.parseParams)(admin_schemas_1.idParamSchema, req);
|
||||
(0, respond_1.ok)(res, await service.getCompany(id));
|
||||
}
|
||||
catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
router.patch('/companies/:id', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('SUPPORT'), async (req, res, next) => {
|
||||
try {
|
||||
const { id } = (0, validate_1.parseParams)(admin_schemas_1.idParamSchema, req);
|
||||
const body = (0, validate_1.parseBody)(admin_schemas_1.adminCompanyUpdateSchema, req);
|
||||
(0, respond_1.ok)(res, await service.updateCompany(id, body, req.admin.id, req.ip));
|
||||
}
|
||||
catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
router.patch('/companies/:id/status', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('SUPPORT'), async (req, res, next) => {
|
||||
try {
|
||||
const { id } = (0, validate_1.parseParams)(admin_schemas_1.idParamSchema, req);
|
||||
const { status, reason } = (0, validate_1.parseBody)(admin_schemas_1.companyStatusSchema, req);
|
||||
(0, respond_1.ok)(res, await service.setCompanyStatus(id, status, reason, req.admin.id, req.ip));
|
||||
}
|
||||
catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
router.delete('/companies/:id', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('ADMIN'), requireAdminAuth_1.requireFreshAdmin2FA, async (req, res, next) => {
|
||||
try {
|
||||
const { id } = (0, validate_1.parseParams)(admin_schemas_1.idParamSchema, req);
|
||||
await service.deleteCompany(id, req.admin.id, req.ip);
|
||||
(0, respond_1.ok)(res, { success: true });
|
||||
}
|
||||
catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
router.post('/companies/:id/impersonate', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('SUPER_ADMIN'), requireAdminAuth_1.requireFreshAdmin2FA, async (req, res, next) => {
|
||||
try {
|
||||
const { id } = (0, validate_1.parseParams)(admin_schemas_1.idParamSchema, req);
|
||||
const { reason, durationMinutes } = (0, validate_1.parseBody)(adminImpersonationSchema, req);
|
||||
(0, respond_1.ok)(res, await service.impersonateCompany(id, req.admin.id, req.ip, reason, durationMinutes));
|
||||
}
|
||||
catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
// ─── Menu management ──────────────────────────────────────────
|
||||
router.get('/menu-items', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('SUPPORT'), async (_req, res, next) => {
|
||||
try {
|
||||
(0, respond_1.ok)(res, await menuService.listMenuItems());
|
||||
}
|
||||
catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
router.post('/menu-items', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('ADMIN'), async (req, res, next) => {
|
||||
try {
|
||||
(0, respond_1.created)(res, { data: await menuService.createMenuItem((0, validate_1.parseBody)(admin_schemas_1.menuItemSchema, req), req.admin) });
|
||||
}
|
||||
catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
router.get('/menu-items/:id', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('SUPPORT'), async (req, res, next) => {
|
||||
try {
|
||||
const { id } = (0, validate_1.parseParams)(admin_schemas_1.idParamSchema, req);
|
||||
(0, respond_1.ok)(res, await menuService.getMenuItem(id));
|
||||
}
|
||||
catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
router.put('/menu-items/:id', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('ADMIN'), async (req, res, next) => {
|
||||
try {
|
||||
const { id } = (0, validate_1.parseParams)(admin_schemas_1.idParamSchema, req);
|
||||
(0, respond_1.ok)(res, await menuService.updateMenuItem(id, (0, validate_1.parseBody)(admin_schemas_1.menuItemSchema, req), req.admin));
|
||||
}
|
||||
catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
router.patch('/menu-items/:id/status', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('ADMIN'), async (req, res, next) => {
|
||||
try {
|
||||
const { id } = (0, validate_1.parseParams)(admin_schemas_1.idParamSchema, req);
|
||||
const { isActive } = (0, validate_1.parseBody)(admin_schemas_1.menuItemStatusSchema, req);
|
||||
(0, respond_1.ok)(res, await menuService.setMenuItemStatus(id, isActive, req.admin));
|
||||
}
|
||||
catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
router.delete('/menu-items/:id', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('ADMIN'), async (req, res, next) => {
|
||||
try {
|
||||
const { id } = (0, validate_1.parseParams)(admin_schemas_1.idParamSchema, req);
|
||||
await menuService.deleteMenuItem(id, req.admin);
|
||||
(0, respond_1.ok)(res, { success: true });
|
||||
}
|
||||
catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
router.post('/menu-items/:id/subscriptions', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('ADMIN'), async (req, res, next) => {
|
||||
try {
|
||||
const { id } = (0, validate_1.parseParams)(admin_schemas_1.idParamSchema, req);
|
||||
const { assignments } = (0, validate_1.parseBody)(admin_schemas_1.menuPlanAssignmentsSchema, req);
|
||||
(0, respond_1.ok)(res, await menuService.assignMenuItemToPlans(id, assignments, req.admin));
|
||||
}
|
||||
catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
router.delete('/menu-items/:id/subscriptions/:plan', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('ADMIN'), async (req, res, next) => {
|
||||
try {
|
||||
const { id, plan } = (0, validate_1.parseParams)(admin_schemas_1.menuPlanParamSchema, req);
|
||||
(0, respond_1.ok)(res, await menuService.removeMenuItemFromPlan(id, plan, req.admin));
|
||||
}
|
||||
catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
router.post('/menu-items/:id/companies', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('ADMIN'), async (req, res, next) => {
|
||||
try {
|
||||
const { id } = (0, validate_1.parseParams)(admin_schemas_1.idParamSchema, req);
|
||||
const { assignments } = (0, validate_1.parseBody)(admin_schemas_1.menuCompanyAssignmentsSchema, req);
|
||||
(0, respond_1.ok)(res, await menuService.assignMenuItemToCompanies(id, assignments, req.admin));
|
||||
}
|
||||
catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
router.delete('/menu-items/:id/companies/:companyId', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('ADMIN'), async (req, res, next) => {
|
||||
try {
|
||||
const { id, companyId } = (0, validate_1.parseParams)(admin_schemas_1.menuCompanyParamSchema, req);
|
||||
(0, respond_1.ok)(res, await menuService.removeMenuItemFromCompany(id, companyId, req.admin));
|
||||
}
|
||||
catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
router.post('/menu-preview', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('SUPPORT'), async (req, res, next) => {
|
||||
try {
|
||||
(0, respond_1.ok)(res, await menuService.previewCompanyMenu((0, validate_1.parseBody)(admin_schemas_1.menuPreviewSchema, req)));
|
||||
}
|
||||
catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
router.get('/menu-audit-logs', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('SUPPORT'), async (req, res, next) => {
|
||||
try {
|
||||
(0, respond_1.ok)(res, await menuService.listMenuAuditLogs((0, validate_1.parseQuery)(admin_schemas_1.menuAuditLogQuerySchema, req)));
|
||||
}
|
||||
catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
// ─── Renters ───────────────────────────────────────────────────
|
||||
router.get('/renters', requireAdminAuth_1.requireAdminAuth, async (req, res, next) => {
|
||||
try {
|
||||
(0, respond_1.ok)(res, await service.listRenters((0, validate_1.parseQuery)(admin_schemas_1.rentersQuerySchema, req)));
|
||||
}
|
||||
catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
router.post('/renters/:id/block', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('SUPPORT'), async (req, res, next) => {
|
||||
try {
|
||||
const { id } = (0, validate_1.parseParams)(admin_schemas_1.idParamSchema, req);
|
||||
await service.setRenterActive(id, false);
|
||||
(0, respond_1.ok)(res, { success: true });
|
||||
}
|
||||
catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
router.post('/renters/:id/unblock', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('SUPPORT'), async (req, res, next) => {
|
||||
try {
|
||||
const { id } = (0, validate_1.parseParams)(admin_schemas_1.idParamSchema, req);
|
||||
await service.setRenterActive(id, true);
|
||||
(0, respond_1.ok)(res, { success: true });
|
||||
}
|
||||
catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
// ─── Metrics ───────────────────────────────────────────────────
|
||||
router.get('/metrics', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('FINANCE'), async (req, res, next) => {
|
||||
try {
|
||||
(0, respond_1.ok)(res, await service.getPlatformMetrics());
|
||||
}
|
||||
catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
// ─── Notifications ─────────────────────────────────────────────
|
||||
router.get('/notifications', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('SUPPORT'), async (req, res, next) => {
|
||||
try {
|
||||
(0, respond_1.ok)(res, await service.listNotifications((0, validate_1.parseQuery)(admin_schemas_1.notificationsQuerySchema, req)));
|
||||
}
|
||||
catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
// ─── Audit logs ────────────────────────────────────────────────
|
||||
router.get('/audit-logs', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('ADMIN'), async (req, res, next) => {
|
||||
try {
|
||||
(0, respond_1.ok)(res, await service.getAuditLogs((0, validate_1.parseQuery)(admin_schemas_1.auditLogQuerySchema, req)));
|
||||
}
|
||||
catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
// ─── Admin users ───────────────────────────────────────────────
|
||||
router.get('/admins', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('SUPER_ADMIN'), async (req, res, next) => {
|
||||
try {
|
||||
(0, respond_1.ok)(res, await service.listAdmins());
|
||||
}
|
||||
catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
router.post('/admins', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('SUPER_ADMIN'), requireAdminAuth_1.requireFreshAdmin2FA, async (req, res, next) => {
|
||||
try {
|
||||
(0, respond_1.created)(res, { data: await service.createAdmin((0, validate_1.parseBody)(admin_schemas_1.createAdminSchema, req)) });
|
||||
}
|
||||
catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
router.patch('/admins/:id', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('SUPER_ADMIN'), requireAdminAuth_1.requireFreshAdmin2FA, async (req, res, next) => {
|
||||
try {
|
||||
const { id } = (0, validate_1.parseParams)(admin_schemas_1.idParamSchema, req);
|
||||
(0, respond_1.ok)(res, await service.updateAdmin(id, (0, validate_1.parseBody)(admin_schemas_1.updateAdminSchema, req)));
|
||||
}
|
||||
catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
router.patch('/admins/:id/role', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('SUPER_ADMIN'), requireAdminAuth_1.requireFreshAdmin2FA, async (req, res, next) => {
|
||||
try {
|
||||
const { id } = (0, validate_1.parseParams)(admin_schemas_1.idParamSchema, req);
|
||||
const { role } = (0, validate_1.parseBody)(admin_schemas_1.adminRoleSchema, req);
|
||||
await service.updateAdminRole(id, role);
|
||||
(0, respond_1.ok)(res, { success: true });
|
||||
}
|
||||
catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
router.patch('/admins/:id/permissions', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('SUPER_ADMIN'), requireAdminAuth_1.requireFreshAdmin2FA, async (req, res, next) => {
|
||||
try {
|
||||
const { id } = (0, validate_1.parseParams)(admin_schemas_1.idParamSchema, req);
|
||||
const { permissions } = (0, validate_1.parseBody)(admin_schemas_1.adminPermissionsSchema, req);
|
||||
(0, respond_1.ok)(res, await service.updateAdminPermissions(id, permissions));
|
||||
}
|
||||
catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
// ─── Billing ───────────────────────────────────────────────────
|
||||
router.get('/billing', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('FINANCE'), async (req, res, next) => {
|
||||
try {
|
||||
(0, respond_1.ok)(res, await service.getBilling((0, validate_1.parseQuery)(admin_schemas_1.billingQuerySchema, req)));
|
||||
}
|
||||
catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
router.get('/billing/invoices/:invoiceId/pdf', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('FINANCE'), async (req, res, next) => {
|
||||
try {
|
||||
const { invoiceId } = (0, validate_1.parseParams)(admin_schemas_1.invoiceIdParamSchema, req);
|
||||
const { pdfBuffer, invoiceNumber } = await service.getInvoicePdf(invoiceId);
|
||||
res.setHeader('Content-Type', 'application/pdf');
|
||||
res.setHeader('Content-Disposition', `attachment; filename="${invoiceNumber}.pdf"`);
|
||||
res.setHeader('Content-Length', pdfBuffer.length);
|
||||
res.end(pdfBuffer);
|
||||
}
|
||||
catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
router.get('/billing/:companyId', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('FINANCE'), async (req, res, next) => {
|
||||
try {
|
||||
const { companyId } = (0, validate_1.parseParams)(admin_schemas_1.companyIdParamSchema, req);
|
||||
(0, respond_1.ok)(res, await service.getBillingAccountDetail(companyId));
|
||||
}
|
||||
catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
router.get('/billing/:companyId/invoices', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('FINANCE'), async (req, res, next) => {
|
||||
try {
|
||||
const { companyId } = (0, validate_1.parseParams)(admin_schemas_1.companyIdParamSchema, req);
|
||||
(0, respond_1.ok)(res, await service.getCompanyInvoices(companyId, (0, validate_1.parseQuery)(admin_schemas_1.invoicesQuerySchema, req)));
|
||||
}
|
||||
catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
router.patch('/billing/accounts/:billingAccountId', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('FINANCE'), async (req, res, next) => {
|
||||
try {
|
||||
const { billingAccountId } = (0, validate_1.parseParams)(admin_schemas_1.billingAccountIdParamSchema, req);
|
||||
(0, respond_1.ok)(res, await service.updateBillingAccount(billingAccountId, (0, validate_1.parseBody)(admin_schemas_1.billingAccountUpdateSchema, req), req.admin.id, req.ip));
|
||||
}
|
||||
catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
router.post('/billing/accounts/:billingAccountId/pause-dunning', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('FINANCE'), async (req, res, next) => {
|
||||
try {
|
||||
const { billingAccountId } = (0, validate_1.parseParams)(admin_schemas_1.billingAccountIdParamSchema, req);
|
||||
(0, respond_1.ok)(res, await service.setDunningPaused(billingAccountId, true, req.admin.id, req.ip));
|
||||
}
|
||||
catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
router.post('/billing/accounts/:billingAccountId/resume-dunning', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('FINANCE'), async (req, res, next) => {
|
||||
try {
|
||||
const { billingAccountId } = (0, validate_1.parseParams)(admin_schemas_1.billingAccountIdParamSchema, req);
|
||||
(0, respond_1.ok)(res, await service.setDunningPaused(billingAccountId, false, req.admin.id, req.ip));
|
||||
}
|
||||
catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
router.post('/billing/accounts/:billingAccountId/invoices', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('FINANCE'), async (req, res, next) => {
|
||||
try {
|
||||
const { billingAccountId } = (0, validate_1.parseParams)(admin_schemas_1.billingAccountIdParamSchema, req);
|
||||
(0, respond_1.created)(res, await service.createBillingInvoice(billingAccountId, (0, validate_1.parseBody)(admin_schemas_1.createBillingInvoiceSchema, req), req.admin.id, req.ip));
|
||||
}
|
||||
catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
router.post('/billing/invoices/:invoiceId/finalize', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('FINANCE'), async (req, res, next) => {
|
||||
try {
|
||||
const { invoiceId } = (0, validate_1.parseParams)(admin_schemas_1.invoiceIdParamSchema, req);
|
||||
(0, respond_1.ok)(res, await service.finalizeBillingInvoice(invoiceId, req.admin.id, req.ip));
|
||||
}
|
||||
catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
router.post('/billing/invoices/:invoiceId/pay', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('FINANCE'), requireAdminAuth_1.requireFreshAdmin2FA, async (req, res, next) => {
|
||||
try {
|
||||
const { invoiceId } = (0, validate_1.parseParams)(admin_schemas_1.invoiceIdParamSchema, req);
|
||||
(0, respond_1.ok)(res, await service.payBillingInvoice(invoiceId, (0, validate_1.parseBody)(admin_schemas_1.payBillingInvoiceSchema, req), req.admin.id, req.ip));
|
||||
}
|
||||
catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
router.post('/billing/invoices/:invoiceId/retry-payment', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('FINANCE'), async (req, res, next) => {
|
||||
try {
|
||||
const { invoiceId } = (0, validate_1.parseParams)(admin_schemas_1.invoiceIdParamSchema, req);
|
||||
(0, respond_1.ok)(res, await service.retryBillingInvoicePayment(invoiceId, (0, validate_1.parseBody)(admin_schemas_1.retryBillingInvoiceSchema, req), req.admin.id, req.ip));
|
||||
}
|
||||
catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
router.post('/billing/invoices/:invoiceId/void', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('FINANCE'), async (req, res, next) => {
|
||||
try {
|
||||
const { invoiceId } = (0, validate_1.parseParams)(admin_schemas_1.invoiceIdParamSchema, req);
|
||||
const { reason } = (0, validate_1.parseBody)(admin_schemas_1.billingReasonSchema, req);
|
||||
(0, respond_1.ok)(res, await service.voidBillingInvoice(invoiceId, reason, req.admin.id, req.ip));
|
||||
}
|
||||
catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
router.post('/billing/invoices/:invoiceId/uncollectible', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('FINANCE'), async (req, res, next) => {
|
||||
try {
|
||||
const { invoiceId } = (0, validate_1.parseParams)(admin_schemas_1.invoiceIdParamSchema, req);
|
||||
const { reason } = (0, validate_1.parseBody)(admin_schemas_1.billingReasonSchema, req);
|
||||
(0, respond_1.ok)(res, await service.markBillingInvoiceUncollectible(invoiceId, reason, req.admin.id, req.ip));
|
||||
}
|
||||
catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
router.post('/billing/invoices/:invoiceId/credit-notes', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('FINANCE'), async (req, res, next) => {
|
||||
try {
|
||||
const { invoiceId } = (0, validate_1.parseParams)(admin_schemas_1.invoiceIdParamSchema, req);
|
||||
(0, respond_1.ok)(res, await service.issueBillingCreditNote(invoiceId, (0, validate_1.parseBody)(admin_schemas_1.billingCreditNoteSchema, req), req.admin.id, req.ip));
|
||||
}
|
||||
catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
router.post('/billing/invoices/:invoiceId/refunds', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('FINANCE'), requireAdminAuth_1.requireFreshAdmin2FA, async (req, res, next) => {
|
||||
try {
|
||||
const { invoiceId } = (0, validate_1.parseParams)(admin_schemas_1.invoiceIdParamSchema, req);
|
||||
(0, respond_1.ok)(res, await service.issueBillingRefund(invoiceId, (0, validate_1.parseBody)(admin_schemas_1.billingRefundSchema, req), req.admin.id, req.ip));
|
||||
}
|
||||
catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
// ─── Pricing config ────────────────────────────────────────────
|
||||
router.get('/pricing', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('FINANCE'), async (req, res, next) => {
|
||||
try {
|
||||
(0, respond_1.ok)(res, await service.getPricingConfigs());
|
||||
}
|
||||
catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
router.patch('/pricing', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('FINANCE'), requireAdminAuth_1.requireFreshAdmin2FA, async (req, res, next) => {
|
||||
try {
|
||||
const { entries } = (0, validate_1.parseBody)(admin_schemas_1.pricingUpdateSchema, req);
|
||||
(0, respond_1.ok)(res, await service.updatePricingConfigs(entries, req.admin.id, req.ip));
|
||||
}
|
||||
catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
router.get('/pricing/features', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('FINANCE'), async (_req, res, next) => {
|
||||
try {
|
||||
(0, respond_1.ok)(res, await service.listPlanFeatures());
|
||||
}
|
||||
catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
router.post('/pricing/features', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('FINANCE'), requireAdminAuth_1.requireFreshAdmin2FA, async (req, res, next) => {
|
||||
try {
|
||||
const data = (0, validate_1.parseBody)(admin_schemas_1.planFeatureCreateSchema, req);
|
||||
(0, respond_1.created)(res, await service.createPlanFeature(data, req.admin.id, req.ip));
|
||||
}
|
||||
catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
router.patch('/pricing/features/:featureId', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('FINANCE'), requireAdminAuth_1.requireFreshAdmin2FA, async (req, res, next) => {
|
||||
try {
|
||||
const { featureId } = (0, validate_1.parseParams)(admin_schemas_1.planFeatureIdParamSchema, req);
|
||||
const data = (0, validate_1.parseBody)(admin_schemas_1.planFeatureUpdateSchema, req);
|
||||
(0, respond_1.ok)(res, await service.updatePlanFeature(featureId, data, req.admin.id, req.ip));
|
||||
}
|
||||
catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
router.delete('/pricing/features/:featureId', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('FINANCE'), requireAdminAuth_1.requireFreshAdmin2FA, async (req, res, next) => {
|
||||
try {
|
||||
const { featureId } = (0, validate_1.parseParams)(admin_schemas_1.planFeatureIdParamSchema, req);
|
||||
await service.deletePlanFeature(featureId, req.admin.id, req.ip);
|
||||
(0, respond_1.ok)(res, { success: true });
|
||||
}
|
||||
catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
// ─── Promotions ────────────────────────────────────────────────────────────
|
||||
router.get('/pricing/promotions', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('FINANCE'), async (req, res, next) => {
|
||||
try {
|
||||
(0, respond_1.ok)(res, await service.listPromotions());
|
||||
}
|
||||
catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
router.post('/pricing/promotions', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('FINANCE'), requireAdminAuth_1.requireFreshAdmin2FA, async (req, res, next) => {
|
||||
try {
|
||||
const data = (0, validate_1.parseBody)(admin_schemas_1.promotionCreateSchema, req);
|
||||
(0, respond_1.created)(res, await service.createPromotion(data, req.admin.id, req.ip));
|
||||
}
|
||||
catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
router.patch('/pricing/promotions/:promotionId', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('FINANCE'), requireAdminAuth_1.requireFreshAdmin2FA, async (req, res, next) => {
|
||||
try {
|
||||
const { promotionId } = (0, validate_1.parseParams)(admin_schemas_1.promotionIdParamSchema, req);
|
||||
const data = (0, validate_1.parseBody)(admin_schemas_1.promotionUpdateSchema, req);
|
||||
(0, respond_1.ok)(res, await service.updatePromotion(promotionId, data, req.admin.id, req.ip));
|
||||
}
|
||||
catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
router.delete('/pricing/promotions/:promotionId', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('FINANCE'), requireAdminAuth_1.requireFreshAdmin2FA, async (req, res, next) => {
|
||||
try {
|
||||
const { promotionId } = (0, validate_1.parseParams)(admin_schemas_1.promotionIdParamSchema, req);
|
||||
await service.deletePromotion(promotionId, req.admin.id, req.ip);
|
||||
(0, respond_1.ok)(res, { success: true });
|
||||
}
|
||||
catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
// ─── Subscription admin overrides ─────────────────────────────
|
||||
router.get('/subscriptions/:subscriptionId/events', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('SUPPORT'), async (req, res, next) => {
|
||||
try {
|
||||
const { subscriptionId } = (0, validate_1.parseParams)(subIdParamSchema, req);
|
||||
(0, respond_1.ok)(res, await subService.getEventsBySubscriptionId(subscriptionId));
|
||||
}
|
||||
catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
router.post('/subscriptions/:subscriptionId/extend-trial', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('SUPPORT'), requireAdminAuth_1.requireFreshAdmin2FA, async (req, res, next) => {
|
||||
try {
|
||||
const { subscriptionId } = (0, validate_1.parseParams)(subIdParamSchema, req);
|
||||
const { extraDays, reason } = (0, validate_1.parseBody)(adminExtendTrialSchema, req);
|
||||
(0, respond_1.ok)(res, await subService.adminExtendTrial(subscriptionId, extraDays, req.admin.id, reason));
|
||||
}
|
||||
catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
router.post('/subscriptions/:subscriptionId/extend-grace-period', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('SUPPORT'), requireAdminAuth_1.requireFreshAdmin2FA, async (req, res, next) => {
|
||||
try {
|
||||
const { subscriptionId } = (0, validate_1.parseParams)(subIdParamSchema, req);
|
||||
const { reason } = (0, validate_1.parseBody)(adminSubOverrideSchema, req);
|
||||
(0, respond_1.ok)(res, await subService.adminExtendGracePeriod(subscriptionId, 7, req.admin.id, reason));
|
||||
}
|
||||
catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
router.post('/subscriptions/:subscriptionId/suspend', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('SUPPORT'), requireAdminAuth_1.requireFreshAdmin2FA, async (req, res, next) => {
|
||||
try {
|
||||
const { subscriptionId } = (0, validate_1.parseParams)(subIdParamSchema, req);
|
||||
const { reason } = (0, validate_1.parseBody)(adminSubOverrideSchema, req);
|
||||
(0, respond_1.ok)(res, await subService.adminSuspendSubscription(subscriptionId, req.admin.id, reason));
|
||||
}
|
||||
catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
router.post('/subscriptions/:subscriptionId/reactivate', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('SUPPORT'), requireAdminAuth_1.requireFreshAdmin2FA, async (req, res, next) => {
|
||||
try {
|
||||
const { subscriptionId } = (0, validate_1.parseParams)(subIdParamSchema, req);
|
||||
const { reason } = (0, validate_1.parseBody)(adminSubOverrideSchema, req);
|
||||
(0, respond_1.ok)(res, await subService.adminReactivateSubscription(subscriptionId, req.admin.id, reason));
|
||||
}
|
||||
catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
router.post('/subscriptions/:subscriptionId/cancel', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('SUPPORT'), requireAdminAuth_1.requireFreshAdmin2FA, async (req, res, next) => {
|
||||
try {
|
||||
const { subscriptionId } = (0, validate_1.parseParams)(subIdParamSchema, req);
|
||||
const { reason } = (0, validate_1.parseBody)(adminSubOverrideSchema, req);
|
||||
(0, respond_1.ok)(res, await subService.adminCancelSubscription(subscriptionId, req.admin.id, reason));
|
||||
}
|
||||
catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
// ─── Site config ───────────────────────────────────────────────
|
||||
router.get('/site-config/marketplace-homepage', requireAdminAuth_1.requireAdminAuth, async (req, res, next) => {
|
||||
try {
|
||||
(0, respond_1.ok)(res, await service.getMarketplaceHomepage());
|
||||
}
|
||||
catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
router.patch('/site-config/marketplace-homepage', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('SUPPORT'), async (req, res, next) => {
|
||||
try {
|
||||
const { homepage } = (0, validate_1.parseBody)(admin_schemas_1.homepageUpdateSchema, req);
|
||||
(0, respond_1.ok)(res, await service.updateMarketplaceHomepage(homepage, req.admin.id, req.ip));
|
||||
}
|
||||
catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
exports.default = router;
|
||||
//# sourceMappingURL=admin.routes.js.map
|
||||
File diff suppressed because one or more lines are too long
+1260
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"admin.schemas.d.ts","sourceRoot":"","sources":["../../../src/modules/admin/admin.schemas.ts"],"names":[],"mappings":"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"}
|
||||
+361
@@ -0,0 +1,361 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.menuCompanyParamSchema = exports.menuPlanParamSchema = exports.menuItemIdParamSchema = exports.menuAuditLogQuerySchema = exports.menuPreviewSchema = exports.menuCompanyAssignmentsSchema = exports.menuPlanAssignmentsSchema = exports.menuItemStatusSchema = exports.menuItemSchema = exports.promotionIdParamSchema = exports.planFeatureIdParamSchema = exports.promotionUpdateSchema = exports.promotionCreateSchema = exports.planFeatureUpdateSchema = exports.planFeatureCreateSchema = exports.pricingUpdateSchema = exports.homepageUpdateSchema = exports.billingRefundSchema = exports.billingCreditNoteSchema = exports.billingReasonSchema = exports.retryBillingInvoiceSchema = exports.payBillingInvoiceSchema = exports.createBillingInvoiceSchema = exports.billingLineItemInputSchema = exports.billingAccountUpdateSchema = exports.invoiceIdParamSchema = exports.billingAccountIdParamSchema = exports.companyIdParamSchema = exports.idParamSchema = exports.marketplaceHomepageConfigSchema = exports.adminCompanyUpdateSchema = exports.companyStatusSchema = exports.adminPermissionsSchema = exports.adminRoleSchema = exports.updateAdminSchema = exports.createAdminSchema = exports.permissionSchema = exports.invoicesQuerySchema = exports.billingQuerySchema = exports.notificationsQuerySchema = exports.auditLogQuerySchema = exports.rentersQuerySchema = exports.companiesQuerySchema = exports.totpVerifySchema = exports.resetPasswordSchema = exports.forgotPasswordSchema = exports.loginSchema = void 0;
|
||||
const zod_1 = require("zod");
|
||||
exports.loginSchema = zod_1.z.object({
|
||||
email: zod_1.z.string().email().max(255).trim().toLowerCase(),
|
||||
password: zod_1.z.string().max(128),
|
||||
totpCode: zod_1.z.string().length(6).optional(),
|
||||
recoveryCode: zod_1.z.string().min(8).max(32).optional(),
|
||||
});
|
||||
exports.forgotPasswordSchema = zod_1.z.object({
|
||||
email: zod_1.z.string().email().max(255).trim().toLowerCase(),
|
||||
});
|
||||
exports.resetPasswordSchema = zod_1.z.object({
|
||||
token: zod_1.z.string().min(1),
|
||||
password: zod_1.z.string().min(8).max(128),
|
||||
});
|
||||
exports.totpVerifySchema = zod_1.z.object({
|
||||
code: zod_1.z.string().length(6),
|
||||
});
|
||||
exports.companiesQuerySchema = zod_1.z.object({
|
||||
q: zod_1.z.string().optional(),
|
||||
status: zod_1.z.string().optional(),
|
||||
plan: zod_1.z.string().optional(),
|
||||
page: zod_1.z.coerce.number().int().min(1).default(1),
|
||||
pageSize: zod_1.z.coerce.number().int().min(1).max(100).default(20),
|
||||
});
|
||||
exports.rentersQuerySchema = zod_1.z.object({
|
||||
q: zod_1.z.string().optional(),
|
||||
blocked: zod_1.z.string().optional(),
|
||||
page: zod_1.z.coerce.number().int().min(1).default(1),
|
||||
pageSize: zod_1.z.coerce.number().int().min(1).max(100).default(20),
|
||||
});
|
||||
exports.auditLogQuerySchema = zod_1.z.object({
|
||||
adminId: zod_1.z.string().optional(),
|
||||
action: zod_1.z.string().optional(),
|
||||
companyId: zod_1.z.string().optional(),
|
||||
entityId: zod_1.z.string().optional(),
|
||||
page: zod_1.z.coerce.number().int().min(1).default(1),
|
||||
pageSize: zod_1.z.coerce.number().int().min(1).max(100).default(50),
|
||||
});
|
||||
exports.notificationsQuerySchema = zod_1.z.object({
|
||||
channel: zod_1.z.string().optional(),
|
||||
status: zod_1.z.string().optional(),
|
||||
companyId: zod_1.z.string().optional(),
|
||||
page: zod_1.z.coerce.number().int().min(1).default(1),
|
||||
pageSize: zod_1.z.coerce.number().int().min(1).max(200).default(50),
|
||||
});
|
||||
exports.billingQuerySchema = zod_1.z.object({
|
||||
q: zod_1.z.string().optional(),
|
||||
status: zod_1.z.string().optional(),
|
||||
plan: zod_1.z.string().optional(),
|
||||
page: zod_1.z.coerce.number().int().min(1).default(1),
|
||||
pageSize: zod_1.z.coerce.number().int().min(1).max(100).default(20),
|
||||
});
|
||||
exports.invoicesQuerySchema = zod_1.z.object({
|
||||
page: zod_1.z.coerce.number().int().min(1).default(1),
|
||||
pageSize: zod_1.z.coerce.number().int().min(1).max(100).default(20),
|
||||
});
|
||||
exports.permissionSchema = zod_1.z.object({
|
||||
resource: zod_1.z.enum(['COMPANIES', 'COMPANY_EMPLOYEES', 'SUBSCRIPTIONS', 'PAYMENTS', 'OFFERS', 'RENTERS', 'ADMIN_USERS', 'AUDIT_LOGS', 'PLATFORM_METRICS']),
|
||||
actions: zod_1.z.array(zod_1.z.enum(['READ', 'CREATE', 'UPDATE', 'DELETE', 'SUSPEND', 'IMPERSONATE'])).min(1),
|
||||
});
|
||||
exports.createAdminSchema = zod_1.z.object({
|
||||
email: zod_1.z.string().email().trim().toLowerCase(),
|
||||
firstName: zod_1.z.string().min(1).max(100).trim(),
|
||||
lastName: zod_1.z.string().min(1).max(100).trim(),
|
||||
role: zod_1.z.enum(['SUPER_ADMIN', 'ADMIN', 'SUPPORT', 'FINANCE', 'VIEWER']),
|
||||
password: zod_1.z.string().min(8),
|
||||
permissions: zod_1.z.array(exports.permissionSchema).optional(),
|
||||
});
|
||||
exports.updateAdminSchema = zod_1.z.object({
|
||||
email: zod_1.z.string().email().trim().toLowerCase().optional(),
|
||||
firstName: zod_1.z.string().min(1).max(100).trim().optional(),
|
||||
lastName: zod_1.z.string().min(1).max(100).trim().optional(),
|
||||
role: zod_1.z.enum(['SUPER_ADMIN', 'ADMIN', 'SUPPORT', 'FINANCE', 'VIEWER']).optional(),
|
||||
password: zod_1.z.string().min(8).optional(),
|
||||
isActive: zod_1.z.boolean().optional(),
|
||||
});
|
||||
exports.adminRoleSchema = zod_1.z.object({
|
||||
role: zod_1.z.enum(['SUPER_ADMIN', 'ADMIN', 'SUPPORT', 'FINANCE', 'VIEWER']),
|
||||
});
|
||||
exports.adminPermissionsSchema = zod_1.z.object({
|
||||
permissions: zod_1.z.array(exports.permissionSchema),
|
||||
});
|
||||
exports.companyStatusSchema = zod_1.z.object({
|
||||
status: zod_1.z.enum(['ACTIVE', 'SUSPENDED', 'CANCELLED']),
|
||||
reason: zod_1.z.string().optional(),
|
||||
});
|
||||
const nullableString = zod_1.z.union([zod_1.z.string(), zod_1.z.null()]).optional();
|
||||
const nullableEmail = zod_1.z.union([zod_1.z.string().email(), zod_1.z.null()]).optional();
|
||||
const nullableUrl = zod_1.z.union([zod_1.z.string().url(), zod_1.z.null()]).optional();
|
||||
const nullableDate = zod_1.z.union([zod_1.z.string().datetime(), zod_1.z.string().regex(/^\d{4}-\d{2}-\d{2}$/), zod_1.z.null()]).optional();
|
||||
exports.adminCompanyUpdateSchema = zod_1.z.object({
|
||||
company: zod_1.z.object({
|
||||
name: zod_1.z.string().min(1).optional(), slug: zod_1.z.string().min(1).optional(),
|
||||
email: zod_1.z.string().email().optional(), phone: nullableString,
|
||||
status: zod_1.z.enum(['PENDING', 'TRIALING', 'ACTIVE', 'PAST_DUE', 'SUSPENDED', 'CANCELLED']).optional(),
|
||||
subscriptionPaymentRef: nullableString,
|
||||
address: zod_1.z.object({
|
||||
streetAddress: nullableString,
|
||||
city: nullableString,
|
||||
country: nullableString,
|
||||
zipCode: nullableString,
|
||||
legalName: nullableString,
|
||||
legalForm: nullableString,
|
||||
companyEmail: nullableEmail,
|
||||
managerName: nullableString,
|
||||
iceNumber: nullableString,
|
||||
operatingLicenseNumber: nullableString,
|
||||
operatingLicenseIssuedAt: nullableString,
|
||||
operatingLicenseIssuedBy: nullableString,
|
||||
fax: nullableString,
|
||||
yearsActive: nullableString,
|
||||
representativeName: nullableString,
|
||||
representativeTitle: nullableString,
|
||||
responsibleName: nullableString,
|
||||
responsibleRole: nullableString,
|
||||
responsibleIdentityNumber: nullableString,
|
||||
responsibleQualification: nullableString,
|
||||
responsiblePhone: nullableString,
|
||||
responsibleEmail: nullableEmail,
|
||||
}).optional(),
|
||||
}).optional(),
|
||||
subscription: zod_1.z.object({
|
||||
plan: zod_1.z.enum(['STARTER', 'GROWTH', 'PRO']).optional(),
|
||||
billingPeriod: zod_1.z.enum(['MONTHLY', 'ANNUAL']).optional(),
|
||||
status: zod_1.z.enum(['TRIALING', 'ACTIVE', 'PAST_DUE', 'CANCELLED', 'UNPAID']).optional(),
|
||||
currency: zod_1.z.literal('MAD').optional(),
|
||||
trialStartAt: nullableDate, trialEndAt: nullableDate,
|
||||
currentPeriodStart: nullableDate, currentPeriodEnd: nullableDate,
|
||||
cancelledAt: nullableDate, cancelAtPeriodEnd: zod_1.z.boolean().optional(),
|
||||
}).optional(),
|
||||
brand: zod_1.z.object({
|
||||
displayName: zod_1.z.string().min(1).optional(), tagline: nullableString,
|
||||
subdomain: zod_1.z.string().min(1).optional(), customDomain: nullableString,
|
||||
publicEmail: nullableEmail, publicPhone: nullableString, publicAddress: nullableString,
|
||||
publicCity: nullableString, publicCountry: nullableString, websiteUrl: nullableUrl,
|
||||
whatsappNumber: nullableString, defaultLocale: zod_1.z.string().min(2).optional(),
|
||||
defaultCurrency: zod_1.z.literal('MAD').optional(),
|
||||
isListedOnMarketplace: zod_1.z.boolean().optional(),
|
||||
homePageConfig: zod_1.z.any().optional(),
|
||||
menuConfig: zod_1.z.any().optional(),
|
||||
}).optional(),
|
||||
contractSettings: zod_1.z.object({
|
||||
legalName: nullableString, registrationNumber: nullableString, taxId: nullableString,
|
||||
terms: zod_1.z.string().optional(),
|
||||
fuelPolicyType: zod_1.z.enum(['FULL_TO_FULL', 'FULL_TO_EMPTY', 'SAME_TO_SAME', 'PREPAID', 'FREE']).optional(),
|
||||
lateFeePerHour: zod_1.z.number().int().nullable().optional(), taxRate: zod_1.z.number().nullable().optional(),
|
||||
signatureRequired: zod_1.z.boolean().optional(), showTax: zod_1.z.boolean().optional(),
|
||||
}).optional(),
|
||||
accountingSettings: zod_1.z.object({
|
||||
reportingPeriod: zod_1.z.enum(['WEEKLY', 'MONTHLY', 'QUARTERLY', 'ANNUAL']).optional(),
|
||||
fiscalYearStart: zod_1.z.number().int().min(1).max(12).optional(),
|
||||
currency: zod_1.z.literal('MAD').optional(),
|
||||
accountantEmail: nullableEmail, accountantName: nullableString,
|
||||
autoSendReport: zod_1.z.boolean().optional(),
|
||||
reportFormat: zod_1.z.enum(['PDF', 'CSV', 'BOTH']).optional(),
|
||||
}).optional(),
|
||||
});
|
||||
const marketplaceMetricSchema = zod_1.z.object({ value: zod_1.z.string().min(1), label: zod_1.z.string().min(1) });
|
||||
const marketplacePillarSchema = zod_1.z.object({ title: zod_1.z.string().min(1), body: zod_1.z.string().min(1) });
|
||||
const marketplaceStepSchema = zod_1.z.object({ step: zod_1.z.string().min(1), title: zod_1.z.string().min(1), body: zod_1.z.string().min(1) });
|
||||
const marketplaceSectionSchema = zod_1.z.enum(['hero', 'surface', 'pillars', 'audiences', 'features', 'steps', 'closing']);
|
||||
const marketplaceHomepageContentSchema = zod_1.z.object({
|
||||
sections: zod_1.z.array(marketplaceSectionSchema).min(1),
|
||||
heroKicker: zod_1.z.string().min(1), heroTitle: zod_1.z.string().min(1), heroBody: zod_1.z.string().min(1),
|
||||
startTrial: zod_1.z.string().min(1), exploreVehicles: zod_1.z.string().min(1),
|
||||
surfaceLabel: zod_1.z.string().min(1), surfaceTitle: zod_1.z.string().min(1), surfaceBody: zod_1.z.string().min(1),
|
||||
liveLabel: zod_1.z.string().min(1), trustedFleets: zod_1.z.string().min(1), brandedFlows: zod_1.z.string().min(1), multiTenant: zod_1.z.string().min(1),
|
||||
companyKicker: zod_1.z.string().min(1), companyTitle: zod_1.z.string().min(1), companyBody: zod_1.z.string().min(1),
|
||||
renterKicker: zod_1.z.string().min(1), renterTitle: zod_1.z.string().min(1), renterBody: zod_1.z.string().min(1),
|
||||
pillars: zod_1.z.array(marketplacePillarSchema).length(3),
|
||||
metrics: zod_1.z.array(marketplaceMetricSchema).length(3),
|
||||
featureLabel: zod_1.z.string().min(1), features: zod_1.z.array(zod_1.z.string().min(1)).min(1),
|
||||
stepsTitle: zod_1.z.string().min(1), steps: zod_1.z.array(marketplaceStepSchema).length(3), stepLabel: zod_1.z.string().min(1),
|
||||
readyKicker: zod_1.z.string().min(1), readyTitle: zod_1.z.string().min(1), readyBody: zod_1.z.string().min(1),
|
||||
viewPricing: zod_1.z.string().min(1), createWorkspace: zod_1.z.string().min(1),
|
||||
});
|
||||
exports.marketplaceHomepageConfigSchema = zod_1.z.object({
|
||||
en: marketplaceHomepageContentSchema,
|
||||
fr: marketplaceHomepageContentSchema,
|
||||
ar: marketplaceHomepageContentSchema,
|
||||
});
|
||||
exports.idParamSchema = zod_1.z.object({
|
||||
id: zod_1.z.string().min(1),
|
||||
});
|
||||
exports.companyIdParamSchema = zod_1.z.object({
|
||||
companyId: zod_1.z.string().min(1),
|
||||
});
|
||||
exports.billingAccountIdParamSchema = zod_1.z.object({
|
||||
billingAccountId: zod_1.z.string().min(1),
|
||||
});
|
||||
exports.invoiceIdParamSchema = zod_1.z.object({
|
||||
invoiceId: zod_1.z.string().min(1),
|
||||
});
|
||||
exports.billingAccountUpdateSchema = zod_1.z.object({
|
||||
legalName: zod_1.z.string().min(1).max(255).optional(),
|
||||
billingEmail: zod_1.z.string().email().optional(),
|
||||
billingAddress: zod_1.z.any().optional(),
|
||||
taxId: zod_1.z.union([zod_1.z.string().max(120), zod_1.z.null()]).optional(),
|
||||
taxExempt: zod_1.z.boolean().optional(),
|
||||
invoiceTerms: zod_1.z.enum(['DUE_ON_RECEIPT', 'NET_7', 'NET_15', 'NET_30', 'NET_45', 'NET_60']).optional(),
|
||||
netTermsDays: zod_1.z.number().int().min(0).max(365).optional(),
|
||||
});
|
||||
exports.billingLineItemInputSchema = zod_1.z.object({
|
||||
type: zod_1.z.enum([
|
||||
'SUBSCRIPTION_FEE',
|
||||
'SEAT_FEE',
|
||||
'USAGE_FEE',
|
||||
'SETUP_FEE',
|
||||
'DISCOUNT',
|
||||
'TAX',
|
||||
'CREDIT',
|
||||
'PRORATION',
|
||||
'REFUND_ADJUSTMENT',
|
||||
'MANUAL_ADJUSTMENT',
|
||||
'PROFESSIONAL_SERVICES',
|
||||
'CANCELLATION_FEE',
|
||||
]),
|
||||
description: zod_1.z.string().min(1).max(255),
|
||||
quantity: zod_1.z.number().int().positive().max(100000),
|
||||
unitAmount: zod_1.z.number().int(),
|
||||
periodStart: nullableDate,
|
||||
periodEnd: nullableDate,
|
||||
});
|
||||
exports.createBillingInvoiceSchema = zod_1.z.object({
|
||||
subscriptionId: zod_1.z.union([zod_1.z.string(), zod_1.z.null()]).optional(),
|
||||
invoiceType: zod_1.z.enum([
|
||||
'SUBSCRIPTION_INITIAL',
|
||||
'SUBSCRIPTION_RENEWAL',
|
||||
'TRIAL_CONVERSION',
|
||||
'SUBSCRIPTION_UPGRADE',
|
||||
'SUBSCRIPTION_DOWNGRADE_CREDIT',
|
||||
'USAGE_BASED',
|
||||
'ONE_TIME',
|
||||
'MANUAL',
|
||||
'CORRECTION',
|
||||
'CANCELLATION_FEE',
|
||||
]),
|
||||
currency: zod_1.z.string().min(3).max(8).optional(),
|
||||
dueAt: nullableDate,
|
||||
isSubscriptionBlocking: zod_1.z.boolean().optional(),
|
||||
adminReason: zod_1.z.union([zod_1.z.string().max(500), zod_1.z.null()]).optional(),
|
||||
lineItems: zod_1.z.array(exports.billingLineItemInputSchema).min(1),
|
||||
});
|
||||
exports.payBillingInvoiceSchema = zod_1.z.object({
|
||||
amount: zod_1.z.number().int().positive().optional(),
|
||||
paymentMethodId: zod_1.z.union([zod_1.z.string(), zod_1.z.null()]).optional(),
|
||||
providerPaymentId: zod_1.z.union([zod_1.z.string(), zod_1.z.null()]).optional(),
|
||||
});
|
||||
exports.retryBillingInvoiceSchema = zod_1.z.object({
|
||||
paymentMethodId: zod_1.z.union([zod_1.z.string(), zod_1.z.null()]).optional(),
|
||||
});
|
||||
exports.billingReasonSchema = zod_1.z.object({
|
||||
reason: zod_1.z.string().min(1).max(500),
|
||||
});
|
||||
exports.billingCreditNoteSchema = zod_1.z.object({
|
||||
amount: zod_1.z.number().int().positive(),
|
||||
reason: zod_1.z.string().min(1).max(500),
|
||||
});
|
||||
exports.billingRefundSchema = zod_1.z.object({
|
||||
amount: zod_1.z.number().int().positive(),
|
||||
reason: zod_1.z.string().min(1).max(500),
|
||||
});
|
||||
exports.homepageUpdateSchema = zod_1.z.object({
|
||||
homepage: exports.marketplaceHomepageConfigSchema,
|
||||
});
|
||||
exports.pricingUpdateSchema = zod_1.z.object({
|
||||
entries: zod_1.z.array(zod_1.z.object({
|
||||
plan: zod_1.z.enum(['STARTER', 'GROWTH', 'PRO']),
|
||||
billingPeriod: zod_1.z.enum(['MONTHLY', 'ANNUAL']),
|
||||
amount: zod_1.z.number().int().positive(),
|
||||
})).min(1),
|
||||
});
|
||||
const planFeatureSchema = zod_1.z.object({
|
||||
plan: zod_1.z.enum(['STARTER', 'GROWTH', 'PRO']),
|
||||
label: zod_1.z.string().min(1).max(120),
|
||||
sortOrder: zod_1.z.number().int().min(0).default(0),
|
||||
});
|
||||
exports.planFeatureCreateSchema = planFeatureSchema;
|
||||
exports.planFeatureUpdateSchema = planFeatureSchema.partial();
|
||||
exports.promotionCreateSchema = zod_1.z.object({
|
||||
code: zod_1.z.string().min(2).max(30).regex(/^[A-Z0-9_-]+$/, 'Code must be uppercase A-Z, 0-9, _ or -'),
|
||||
name: zod_1.z.string().min(1).max(100),
|
||||
description: zod_1.z.string().max(500).optional(),
|
||||
discountType: zod_1.z.enum(['PERCENTAGE', 'FIXED']),
|
||||
discountValue: zod_1.z.number().int().positive(),
|
||||
plans: zod_1.z.array(zod_1.z.enum(['STARTER', 'GROWTH', 'PRO'])),
|
||||
periods: zod_1.z.array(zod_1.z.enum(['MONTHLY', 'ANNUAL'])),
|
||||
maxUses: zod_1.z.number().int().positive().nullable().optional(),
|
||||
validFrom: zod_1.z.string().datetime(),
|
||||
validUntil: zod_1.z.string().datetime().nullable().optional(),
|
||||
isActive: zod_1.z.boolean().default(true),
|
||||
});
|
||||
exports.promotionUpdateSchema = exports.promotionCreateSchema.partial();
|
||||
exports.planFeatureIdParamSchema = zod_1.z.object({ featureId: zod_1.z.string().min(1) });
|
||||
exports.promotionIdParamSchema = zod_1.z.object({ promotionId: zod_1.z.string().min(1) });
|
||||
const employeeRoleSchema = zod_1.z.enum(['OWNER', 'MANAGER', 'AGENT']);
|
||||
const planSchema = zod_1.z.enum(['STARTER', 'GROWTH', 'PRO']);
|
||||
const menuItemTypeSchema = zod_1.z.enum(['INTERNAL_PAGE', 'EXTERNAL_LINK', 'PARENT_MENU', 'SECTION_LABEL', 'DIVIDER']);
|
||||
exports.menuItemSchema = zod_1.z.object({
|
||||
systemKey: zod_1.z.string().trim().min(1).max(120).optional().nullable(),
|
||||
label: zod_1.z.string().trim().min(1).max(120),
|
||||
itemType: menuItemTypeSchema,
|
||||
routeOrUrl: zod_1.z.string().trim().max(400).optional().nullable(),
|
||||
icon: zod_1.z.string().trim().max(120).optional().nullable(),
|
||||
parentId: zod_1.z.string().trim().min(1).optional().nullable(),
|
||||
displayOrder: zod_1.z.number().int().min(0).default(0),
|
||||
openInNewTab: zod_1.z.boolean().default(false),
|
||||
isRequired: zod_1.z.boolean().default(false),
|
||||
isActive: zod_1.z.boolean().default(true),
|
||||
roles: zod_1.z.array(employeeRoleSchema).default([]),
|
||||
subscriptionPlans: zod_1.z.array(zod_1.z.object({
|
||||
plan: planSchema,
|
||||
displayOrder: zod_1.z.number().int().min(0).optional(),
|
||||
isActive: zod_1.z.boolean().optional(),
|
||||
})).default([]),
|
||||
companyAssignments: zod_1.z.array(zod_1.z.object({
|
||||
companyId: zod_1.z.string().trim().min(1),
|
||||
displayOrder: zod_1.z.number().int().min(0).optional(),
|
||||
isActive: zod_1.z.boolean().optional(),
|
||||
})).default([]),
|
||||
});
|
||||
exports.menuItemStatusSchema = zod_1.z.object({
|
||||
isActive: zod_1.z.boolean(),
|
||||
});
|
||||
exports.menuPlanAssignmentsSchema = zod_1.z.object({
|
||||
assignments: zod_1.z.array(zod_1.z.object({
|
||||
plan: planSchema,
|
||||
displayOrder: zod_1.z.number().int().min(0).optional(),
|
||||
isActive: zod_1.z.boolean().optional(),
|
||||
})).min(1),
|
||||
});
|
||||
exports.menuCompanyAssignmentsSchema = zod_1.z.object({
|
||||
assignments: zod_1.z.array(zod_1.z.object({
|
||||
companyId: zod_1.z.string().trim().min(1),
|
||||
displayOrder: zod_1.z.number().int().min(0).optional(),
|
||||
isActive: zod_1.z.boolean().optional(),
|
||||
})).min(1),
|
||||
});
|
||||
exports.menuPreviewSchema = zod_1.z.object({
|
||||
companyId: zod_1.z.string().trim().min(1),
|
||||
role: employeeRoleSchema,
|
||||
});
|
||||
exports.menuAuditLogQuerySchema = zod_1.z.object({
|
||||
page: zod_1.z.coerce.number().int().min(1).default(1),
|
||||
pageSize: zod_1.z.coerce.number().int().min(1).max(100).default(20),
|
||||
});
|
||||
exports.menuItemIdParamSchema = zod_1.z.object({
|
||||
id: zod_1.z.string().min(1),
|
||||
});
|
||||
exports.menuPlanParamSchema = zod_1.z.object({
|
||||
id: zod_1.z.string().min(1),
|
||||
plan: planSchema,
|
||||
});
|
||||
exports.menuCompanyParamSchema = zod_1.z.object({
|
||||
id: zod_1.z.string().min(1),
|
||||
companyId: zod_1.z.string().min(1),
|
||||
});
|
||||
//# sourceMappingURL=admin.schemas.js.map
|
||||
File diff suppressed because one or more lines are too long
+174
@@ -0,0 +1,174 @@
|
||||
import * as repo from './admin.repo';
|
||||
import * as billingService from './admin.billing.service';
|
||||
export declare function login(email: string, password: string, totpCode?: string, recoveryCode?: string): Promise<{
|
||||
token: string;
|
||||
admin: Omit<any, "passwordHash" | "totpSecret">;
|
||||
} | {
|
||||
readonly totpRequired: true;
|
||||
readonly invalidTotp?: undefined;
|
||||
} | {
|
||||
readonly invalidTotp: true;
|
||||
readonly totpRequired?: undefined;
|
||||
} | null>;
|
||||
export declare function setupTotp(adminId: string, email: string): Promise<{
|
||||
secret: string;
|
||||
qrCode: string;
|
||||
}>;
|
||||
export declare function verifyTotp(adminId: string, code: string): Promise<false | {
|
||||
recoveryCodes: string[];
|
||||
token: string;
|
||||
admin: Omit<any, "passwordHash" | "totpSecret">;
|
||||
}>;
|
||||
export declare function regenerateRecoveryCodes(adminId: string): Promise<{
|
||||
recoveryCodes: string[];
|
||||
}>;
|
||||
export declare function forgotPassword(email: string): Promise<void>;
|
||||
export declare function resetPassword(token: string, password: string): Promise<boolean>;
|
||||
export declare function listCompanies(query: {
|
||||
q?: string;
|
||||
status?: string;
|
||||
plan?: string;
|
||||
page: number;
|
||||
pageSize: number;
|
||||
}): Promise<{
|
||||
data: unknown[];
|
||||
total: number;
|
||||
page: number;
|
||||
pageSize: number;
|
||||
totalPages: number;
|
||||
}>;
|
||||
export declare function getCompany(id: string): any;
|
||||
export declare function updateCompany(id: string, body: any, adminId: string, ip?: string): Promise<any>;
|
||||
export declare function setCompanyStatus(id: string, status: string, reason: string | undefined, adminId: string, ip?: string): Promise<any>;
|
||||
export declare function deleteCompany(id: string, adminId: string, ip?: string): Promise<void>;
|
||||
export declare function impersonateCompany(id: string, adminId: string, ip?: string, reason?: string, durationMinutes?: number): Promise<{
|
||||
token: string;
|
||||
expiresIn: number;
|
||||
impersonation: {
|
||||
companyId: string;
|
||||
reason: string | undefined;
|
||||
durationMinutes: number;
|
||||
};
|
||||
}>;
|
||||
export declare function listRenters(query: {
|
||||
q?: string;
|
||||
blocked?: string;
|
||||
page: number;
|
||||
pageSize: number;
|
||||
}): Promise<{
|
||||
data: unknown[];
|
||||
total: number;
|
||||
page: number;
|
||||
pageSize: number;
|
||||
totalPages: number;
|
||||
}>;
|
||||
export declare function setRenterActive(id: string, isActive: boolean): any;
|
||||
export declare function getPlatformMetrics(): Promise<{
|
||||
totalCompanies: any;
|
||||
activeCompanies: any;
|
||||
trialingCompanies: any;
|
||||
suspendedCompanies: any;
|
||||
totalRenters: any;
|
||||
totalReservations: any;
|
||||
}>;
|
||||
export declare function listNotifications(query: {
|
||||
channel?: string;
|
||||
status?: string;
|
||||
companyId?: string;
|
||||
page: number;
|
||||
pageSize: number;
|
||||
}): Promise<{
|
||||
data: unknown[];
|
||||
total: number;
|
||||
page: number;
|
||||
pageSize: number;
|
||||
totalPages: number;
|
||||
}>;
|
||||
export declare function getAuditLogs(query: {
|
||||
adminId?: string;
|
||||
action?: string;
|
||||
companyId?: string;
|
||||
entityId?: string;
|
||||
page: number;
|
||||
pageSize: number;
|
||||
}): Promise<{
|
||||
data: unknown[];
|
||||
total: number;
|
||||
page: number;
|
||||
pageSize: number;
|
||||
totalPages: number;
|
||||
}>;
|
||||
export declare function listAdmins(): Promise<any>;
|
||||
export declare function createAdmin(body: {
|
||||
email: string;
|
||||
firstName: string;
|
||||
lastName: string;
|
||||
role: string;
|
||||
password: string;
|
||||
permissions?: any[];
|
||||
}): Promise<Omit<any, "passwordHash" | "totpSecret">>;
|
||||
export declare function updateAdmin(id: string, body: {
|
||||
email?: string;
|
||||
firstName?: string;
|
||||
lastName?: string;
|
||||
role?: string;
|
||||
password?: string;
|
||||
isActive?: boolean;
|
||||
}): Promise<Omit<any, "passwordHash" | "totpSecret">>;
|
||||
export declare function updateAdminRole(id: string, role: string): any;
|
||||
export declare function updateAdminPermissions(id: string, permissions: any[]): Promise<Omit<any, "passwordHash" | "totpSecret">>;
|
||||
export declare function getBilling(query: {
|
||||
q?: string;
|
||||
status?: string;
|
||||
plan?: string;
|
||||
page: number;
|
||||
pageSize: number;
|
||||
}): Promise<{
|
||||
data: any[];
|
||||
total: number;
|
||||
page: number;
|
||||
pageSize: number;
|
||||
totalPages: number;
|
||||
}>;
|
||||
export declare function getCompanyInvoices(companyId: string, query: {
|
||||
page: number;
|
||||
pageSize: number;
|
||||
}): Promise<{
|
||||
data: unknown[];
|
||||
total: number;
|
||||
page: number;
|
||||
pageSize: number;
|
||||
totalPages: number;
|
||||
}>;
|
||||
export declare function getInvoicePdf(invoiceId: string): Promise<{
|
||||
pdfBuffer: Buffer<ArrayBufferLike>;
|
||||
invoiceNumber: any;
|
||||
}>;
|
||||
export declare function getBillingAccountDetail(companyId: string): Promise<any>;
|
||||
export declare function updateBillingAccount(billingAccountId: string, data: Parameters<typeof billingService.updateBillingAccount>[1], adminId: string, ip?: string): Promise<any>;
|
||||
export declare function setDunningPaused(billingAccountId: string, paused: boolean, adminId: string, ip?: string): Promise<any>;
|
||||
export declare function createBillingInvoice(billingAccountId: string, data: Parameters<typeof billingService.createDraftInvoice>[1], adminId: string, ip?: string): Promise<any>;
|
||||
export declare function finalizeBillingInvoice(invoiceId: string, adminId: string, ip?: string): Promise<any>;
|
||||
export declare function payBillingInvoice(invoiceId: string, data: Parameters<typeof billingService.payInvoice>[1], adminId: string, ip?: string): Promise<any>;
|
||||
export declare function retryBillingInvoicePayment(invoiceId: string, data: Parameters<typeof billingService.retryInvoicePayment>[1], adminId: string, ip?: string): Promise<any>;
|
||||
export declare function voidBillingInvoice(invoiceId: string, reason: string, adminId: string, ip?: string): Promise<any>;
|
||||
export declare function markBillingInvoiceUncollectible(invoiceId: string, reason: string, adminId: string, ip?: string): Promise<any>;
|
||||
export declare function issueBillingCreditNote(invoiceId: string, data: Parameters<typeof billingService.issueCreditNote>[1], adminId: string, ip?: string): Promise<any>;
|
||||
export declare function issueBillingRefund(invoiceId: string, data: Parameters<typeof billingService.issueRefund>[1], adminId: string, ip?: string): Promise<any>;
|
||||
export declare function getMarketplaceHomepage(): Promise<import("@rentaldrivego/types").MarketplaceHomepageConfig>;
|
||||
export declare function updateMarketplaceHomepage(homepage: any, adminId: string, ip?: string): Promise<import("@rentaldrivego/types").MarketplaceHomepageConfig>;
|
||||
export declare function getPricingConfigs(): any;
|
||||
export declare function updatePricingConfigs(entries: {
|
||||
plan: string;
|
||||
billingPeriod: string;
|
||||
amount: number;
|
||||
}[], adminId: string, ip?: string): Promise<any>;
|
||||
export declare function listPlanFeatures(): any;
|
||||
export declare function createPlanFeature(data: Parameters<typeof repo.createPlanFeature>[0], adminId: string, ip?: string): Promise<any>;
|
||||
export declare function updatePlanFeature(id: string, data: Parameters<typeof repo.updatePlanFeature>[1], adminId: string, ip?: string): Promise<any>;
|
||||
export declare function deletePlanFeature(id: string, adminId: string, ip?: string): Promise<void>;
|
||||
export declare function listPromotions(): any;
|
||||
export declare function createPromotion(data: Parameters<typeof repo.createPromotion>[0], adminId: string, ip?: string): Promise<any>;
|
||||
export declare function updatePromotion(id: string, data: Parameters<typeof repo.updatePromotion>[1], adminId: string, ip?: string): Promise<any>;
|
||||
export declare function deletePromotion(id: string, adminId: string, ip?: string): Promise<void>;
|
||||
//# sourceMappingURL=admin.service.d.ts.map
|
||||
File diff suppressed because one or more lines are too long
+494
@@ -0,0 +1,494 @@
|
||||
"use strict";
|
||||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
var desc = Object.getOwnPropertyDescriptor(m, k);
|
||||
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
||||
desc = { enumerable: true, get: function() { return m[k]; } };
|
||||
}
|
||||
Object.defineProperty(o, k2, desc);
|
||||
}) : (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
o[k2] = m[k];
|
||||
}));
|
||||
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
||||
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
||||
}) : function(o, v) {
|
||||
o["default"] = v;
|
||||
});
|
||||
var __importStar = (this && this.__importStar) || (function () {
|
||||
var ownKeys = function(o) {
|
||||
ownKeys = Object.getOwnPropertyNames || function (o) {
|
||||
var ar = [];
|
||||
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
||||
return ar;
|
||||
};
|
||||
return ownKeys(o);
|
||||
};
|
||||
return function (mod) {
|
||||
if (mod && mod.__esModule) return mod;
|
||||
var result = {};
|
||||
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
||||
__setModuleDefault(result, mod);
|
||||
return result;
|
||||
};
|
||||
})();
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.login = login;
|
||||
exports.setupTotp = setupTotp;
|
||||
exports.verifyTotp = verifyTotp;
|
||||
exports.regenerateRecoveryCodes = regenerateRecoveryCodes;
|
||||
exports.forgotPassword = forgotPassword;
|
||||
exports.resetPassword = resetPassword;
|
||||
exports.listCompanies = listCompanies;
|
||||
exports.getCompany = getCompany;
|
||||
exports.updateCompany = updateCompany;
|
||||
exports.setCompanyStatus = setCompanyStatus;
|
||||
exports.deleteCompany = deleteCompany;
|
||||
exports.impersonateCompany = impersonateCompany;
|
||||
exports.listRenters = listRenters;
|
||||
exports.setRenterActive = setRenterActive;
|
||||
exports.getPlatformMetrics = getPlatformMetrics;
|
||||
exports.listNotifications = listNotifications;
|
||||
exports.getAuditLogs = getAuditLogs;
|
||||
exports.listAdmins = listAdmins;
|
||||
exports.createAdmin = createAdmin;
|
||||
exports.updateAdmin = updateAdmin;
|
||||
exports.updateAdminRole = updateAdminRole;
|
||||
exports.updateAdminPermissions = updateAdminPermissions;
|
||||
exports.getBilling = getBilling;
|
||||
exports.getCompanyInvoices = getCompanyInvoices;
|
||||
exports.getInvoicePdf = getInvoicePdf;
|
||||
exports.getBillingAccountDetail = getBillingAccountDetail;
|
||||
exports.updateBillingAccount = updateBillingAccount;
|
||||
exports.setDunningPaused = setDunningPaused;
|
||||
exports.createBillingInvoice = createBillingInvoice;
|
||||
exports.finalizeBillingInvoice = finalizeBillingInvoice;
|
||||
exports.payBillingInvoice = payBillingInvoice;
|
||||
exports.retryBillingInvoicePayment = retryBillingInvoicePayment;
|
||||
exports.voidBillingInvoice = voidBillingInvoice;
|
||||
exports.markBillingInvoiceUncollectible = markBillingInvoiceUncollectible;
|
||||
exports.issueBillingCreditNote = issueBillingCreditNote;
|
||||
exports.issueBillingRefund = issueBillingRefund;
|
||||
exports.getMarketplaceHomepage = getMarketplaceHomepage;
|
||||
exports.updateMarketplaceHomepage = updateMarketplaceHomepage;
|
||||
exports.getPricingConfigs = getPricingConfigs;
|
||||
exports.updatePricingConfigs = updatePricingConfigs;
|
||||
exports.listPlanFeatures = listPlanFeatures;
|
||||
exports.createPlanFeature = createPlanFeature;
|
||||
exports.updatePlanFeature = updatePlanFeature;
|
||||
exports.deletePlanFeature = deletePlanFeature;
|
||||
exports.listPromotions = listPromotions;
|
||||
exports.createPromotion = createPromotion;
|
||||
exports.updatePromotion = updatePromotion;
|
||||
exports.deletePromotion = deletePromotion;
|
||||
const bcryptjs_1 = __importDefault(require("bcryptjs"));
|
||||
const crypto_1 = __importDefault(require("crypto"));
|
||||
const otplib_1 = require("otplib");
|
||||
const tokens_1 = require("../../security/tokens");
|
||||
const qrcode_1 = __importDefault(require("qrcode"));
|
||||
const platformContentService_1 = require("../../services/platformContentService");
|
||||
const notificationService_1 = require("../../services/notificationService");
|
||||
const presenter = __importStar(require("./admin.presenter"));
|
||||
const repo = __importStar(require("./admin.repo"));
|
||||
const billingService = __importStar(require("./admin.billing.service"));
|
||||
const ADMIN_RESET_TTL_MINUTES = 60;
|
||||
const ADMIN_RECOVERY_CODE_COUNT = 10;
|
||||
function generateRecoveryCode() {
|
||||
const raw = crypto_1.default.randomBytes(9).toString('base64url').replace(/[^a-zA-Z0-9]/g, '').toUpperCase().slice(0, 12);
|
||||
return `${raw.slice(0, 4)}-${raw.slice(4, 8)}-${raw.slice(8, 12)}`;
|
||||
}
|
||||
async function issueAdminRecoveryCodes(adminId) {
|
||||
const codes = Array.from({ length: ADMIN_RECOVERY_CODE_COUNT }, generateRecoveryCode);
|
||||
const hashes = await Promise.all(codes.map((code) => bcryptjs_1.default.hash(code, 12)));
|
||||
await repo.replaceAdminRecoveryCodes(adminId, hashes);
|
||||
await repo.createAuditLog({
|
||||
adminUserId: adminId,
|
||||
action: 'ADMIN_2FA_RECOVERY_CODES_ISSUED',
|
||||
resource: 'AdminUser',
|
||||
resourceId: adminId,
|
||||
});
|
||||
return codes;
|
||||
}
|
||||
async function consumeAdminRecoveryCode(adminId, code) {
|
||||
const normalized = code.trim().toUpperCase();
|
||||
if (!normalized)
|
||||
return false;
|
||||
const codes = await repo.listUnusedAdminRecoveryCodes(adminId);
|
||||
for (const candidate of codes) {
|
||||
if (await bcryptjs_1.default.compare(normalized, candidate.codeHash)) {
|
||||
await repo.markAdminRecoveryCodeUsed(candidate.id);
|
||||
await repo.createAuditLog({
|
||||
adminUserId: adminId,
|
||||
action: 'ADMIN_2FA_RECOVERY_CODE_USED',
|
||||
resource: 'AdminUser',
|
||||
resourceId: adminId,
|
||||
});
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
function signAdminToken(adminId, last2faAt) {
|
||||
return (0, tokens_1.signActorToken)(adminId, 'admin', { expiresIn: '8h', last2faAt });
|
||||
}
|
||||
function toAuditJson(value) {
|
||||
return JSON.parse(JSON.stringify(value));
|
||||
}
|
||||
function ensureAdminBasePath(baseUrl) {
|
||||
try {
|
||||
const url = new URL(baseUrl);
|
||||
const pathname = url.pathname.replace(/\/$/, '');
|
||||
if (!pathname.endsWith('/admin'))
|
||||
url.pathname = `${pathname}/admin`;
|
||||
return url.toString().replace(/\/$/, '');
|
||||
}
|
||||
catch {
|
||||
const trimmed = baseUrl.replace(/\/$/, '');
|
||||
return trimmed.endsWith('/admin') ? trimmed : `${trimmed}/admin`;
|
||||
}
|
||||
}
|
||||
async function login(email, password, totpCode, recoveryCode) {
|
||||
const admin = await repo.findAdminByEmail(email);
|
||||
if (!admin || !admin.isActive)
|
||||
return null;
|
||||
const valid = await bcryptjs_1.default.compare(password, admin.passwordHash);
|
||||
if (!valid)
|
||||
return null;
|
||||
if (admin.totpEnabled) {
|
||||
if (!totpCode && !recoveryCode)
|
||||
return { totpRequired: true };
|
||||
const validTotp = totpCode
|
||||
? otplib_1.authenticator.verify({ token: totpCode, secret: admin.totpSecret })
|
||||
: false;
|
||||
const validRecoveryCode = !validTotp && recoveryCode
|
||||
? await consumeAdminRecoveryCode(admin.id, recoveryCode)
|
||||
: false;
|
||||
if (!validTotp && !validRecoveryCode) {
|
||||
return { invalidTotp: true };
|
||||
}
|
||||
}
|
||||
await repo.updateAdminLastLogin(admin.id);
|
||||
await repo.createAuditLog({
|
||||
adminUserId: admin.id,
|
||||
action: 'ADMIN_LOGIN',
|
||||
resource: 'AdminUser',
|
||||
resourceId: admin.id,
|
||||
});
|
||||
return presenter.presentAdminSession(admin, signAdminToken(admin.id, admin.totpEnabled ? Date.now() : undefined));
|
||||
}
|
||||
async function setupTotp(adminId, email) {
|
||||
const secret = otplib_1.authenticator.generateSecret();
|
||||
await repo.updateAdminTotpSecret(adminId, secret);
|
||||
const otpauth = otplib_1.authenticator.keyuri(email, 'RentalDriveGo Admin', secret);
|
||||
const qrCode = await qrcode_1.default.toDataURL(otpauth);
|
||||
return { secret, qrCode };
|
||||
}
|
||||
async function verifyTotp(adminId, code) {
|
||||
const admin = await repo.findAdminByIdOrThrow(adminId);
|
||||
if (!admin.totpSecret)
|
||||
return false;
|
||||
const valid = otplib_1.authenticator.verify({ token: code, secret: admin.totpSecret });
|
||||
if (!valid)
|
||||
return false;
|
||||
await repo.enableAdminTotp(adminId);
|
||||
await repo.createAuditLog({
|
||||
adminUserId: adminId,
|
||||
action: 'ADMIN_2FA_VERIFIED',
|
||||
resource: 'AdminUser',
|
||||
resourceId: adminId,
|
||||
});
|
||||
const recoveryCodes = await issueAdminRecoveryCodes(adminId);
|
||||
return {
|
||||
...presenter.presentAdminSession({ ...admin, totpEnabled: true }, signAdminToken(adminId, Date.now())),
|
||||
recoveryCodes,
|
||||
};
|
||||
}
|
||||
async function regenerateRecoveryCodes(adminId) {
|
||||
return { recoveryCodes: await issueAdminRecoveryCodes(adminId) };
|
||||
}
|
||||
async function forgotPassword(email) {
|
||||
const admin = await repo.findAdminByEmail(email);
|
||||
if (!admin || !admin.isActive)
|
||||
return;
|
||||
const rawToken = crypto_1.default.randomBytes(32).toString('hex');
|
||||
const expiresAt = new Date(Date.now() + ADMIN_RESET_TTL_MINUTES * 60 * 1000);
|
||||
await repo.setAdminPasswordReset(admin.id, rawToken, expiresAt);
|
||||
const adminUrl = ensureAdminBasePath(process.env.ADMIN_URL ?? process.env.NEXT_PUBLIC_ADMIN_URL ?? 'http://localhost:3000/admin');
|
||||
const resetUrl = `${adminUrl}/reset-password?token=${rawToken}`;
|
||||
await (0, notificationService_1.sendTransactionalEmail)({
|
||||
to: admin.email,
|
||||
subject: 'Reset your RentalDriveGo admin password',
|
||||
html: `<p>Hi ${admin.firstName},</p><p><a href="${resetUrl}">Reset password</a></p><p>Expires in ${ADMIN_RESET_TTL_MINUTES} minutes.</p>`,
|
||||
text: `Hi ${admin.firstName},\n\nReset here: ${resetUrl}\n\nExpires in ${ADMIN_RESET_TTL_MINUTES} minutes.`,
|
||||
}).catch((err) => console.error('[AdminForgotPassword]', err?.message));
|
||||
}
|
||||
async function resetPassword(token, password) {
|
||||
const admin = await repo.findAdminByResetToken(token);
|
||||
if (!admin)
|
||||
return false;
|
||||
await repo.updateAdminPassword(admin.id, await bcryptjs_1.default.hash(password, 12));
|
||||
return true;
|
||||
}
|
||||
async function listCompanies(query) {
|
||||
const { data, total } = await repo.listCompaniesPage(query);
|
||||
return presenter.presentPaginated(data, total, query.page, query.pageSize);
|
||||
}
|
||||
function getCompany(id) {
|
||||
return repo.getCompanyDetail(id);
|
||||
}
|
||||
async function updateCompany(id, body, adminId, ip) {
|
||||
const before = await repo.getCompanyUpdateSnapshot(id);
|
||||
const updated = await repo.applyCompanyUpdate(id, body, before);
|
||||
await repo.createAuditLog({
|
||||
adminUserId: adminId,
|
||||
action: 'UPDATE_COMPANY',
|
||||
resource: 'Company',
|
||||
resourceId: id,
|
||||
companyId: id,
|
||||
before: toAuditJson(before),
|
||||
after: toAuditJson(body),
|
||||
ipAddress: ip,
|
||||
});
|
||||
return updated;
|
||||
}
|
||||
async function setCompanyStatus(id, status, reason, adminId, ip) {
|
||||
const before = await repo.getCompanyUpdateSnapshot(id);
|
||||
const updated = await repo.updateCompanyStatus(id, status);
|
||||
await repo.createAuditLog({
|
||||
adminUserId: adminId,
|
||||
action: `SET_COMPANY_STATUS_${status}`,
|
||||
resource: 'Company',
|
||||
resourceId: id,
|
||||
companyId: id,
|
||||
before: { status: before.status },
|
||||
after: { status },
|
||||
note: reason,
|
||||
ipAddress: ip,
|
||||
});
|
||||
return updated;
|
||||
}
|
||||
async function deleteCompany(id, adminId, ip) {
|
||||
await repo.deleteCompany(id);
|
||||
await repo.createAuditLog({
|
||||
adminUserId: adminId,
|
||||
action: 'DELETE_COMPANY',
|
||||
resource: 'Company',
|
||||
resourceId: id,
|
||||
ipAddress: ip,
|
||||
});
|
||||
}
|
||||
async function impersonateCompany(id, adminId, ip, reason, durationMinutes = 15) {
|
||||
const company = await repo.getCompanyForImpersonation(id);
|
||||
const ttlMinutes = Math.min(Math.max(durationMinutes, 1), 30);
|
||||
const employeeId = company.employees[0]?.id;
|
||||
if (!employeeId)
|
||||
throw new Error('Company has no employee account to impersonate');
|
||||
const token = (0, tokens_1.signActorToken)(employeeId, 'employee', { expiresIn: `${ttlMinutes}m` });
|
||||
await repo.createAuditLog({
|
||||
adminUserId: adminId,
|
||||
action: 'IMPERSONATE_COMPANY',
|
||||
resource: 'Company',
|
||||
resourceId: id,
|
||||
companyId: id,
|
||||
note: reason,
|
||||
before: { originalAdminId: adminId },
|
||||
after: { targetCompanyId: id, durationMinutes: ttlMinutes },
|
||||
ipAddress: ip,
|
||||
});
|
||||
return { token, expiresIn: ttlMinutes * 60, impersonation: { companyId: id, reason, durationMinutes: ttlMinutes } };
|
||||
}
|
||||
async function listRenters(query) {
|
||||
const { data, total } = await repo.listRentersPage(query);
|
||||
return presenter.presentPaginated(data, total, query.page, query.pageSize);
|
||||
}
|
||||
function setRenterActive(id, isActive) {
|
||||
return repo.updateRenterActive(id, isActive);
|
||||
}
|
||||
function getPlatformMetrics() {
|
||||
return repo.getPlatformMetricCounts();
|
||||
}
|
||||
async function listNotifications(query) {
|
||||
const { data, total } = await repo.listNotificationsPage(query);
|
||||
return presenter.presentPaginated(data, total, query.page, query.pageSize);
|
||||
}
|
||||
async function getAuditLogs(query) {
|
||||
const { data, total } = await repo.listAuditLogsPage(query);
|
||||
return presenter.presentPaginated(data, total, query.page, query.pageSize);
|
||||
}
|
||||
async function listAdmins() {
|
||||
const admins = await repo.listAdmins();
|
||||
return admins.map((admin) => presenter.presentAdminUser(admin));
|
||||
}
|
||||
async function createAdmin(body) {
|
||||
const admin = await repo.createAdmin({
|
||||
...body,
|
||||
passwordHash: await bcryptjs_1.default.hash(body.password, 12),
|
||||
});
|
||||
return presenter.presentAdminUser(admin);
|
||||
}
|
||||
async function updateAdmin(id, body) {
|
||||
const admin = await repo.updateAdmin(id, {
|
||||
...(body.email !== undefined ? { email: body.email } : {}),
|
||||
...(body.firstName !== undefined ? { firstName: body.firstName } : {}),
|
||||
...(body.lastName !== undefined ? { lastName: body.lastName } : {}),
|
||||
...(body.role !== undefined ? { role: body.role } : {}),
|
||||
...(body.isActive !== undefined ? { isActive: body.isActive } : {}),
|
||||
...(body.password ? { passwordHash: await bcryptjs_1.default.hash(body.password, 12) } : {}),
|
||||
});
|
||||
return presenter.presentAdminUser(admin);
|
||||
}
|
||||
function updateAdminRole(id, role) {
|
||||
return repo.updateAdminRole(id, role);
|
||||
}
|
||||
async function updateAdminPermissions(id, permissions) {
|
||||
const admin = await repo.replaceAdminPermissions(id, permissions);
|
||||
return presenter.presentAdminUser(admin);
|
||||
}
|
||||
async function getBilling(query) {
|
||||
const { data, total, stats } = await billingService.listBillingAccounts(query);
|
||||
return presenter.presentPaginated(data, total, query.page, query.pageSize, { stats });
|
||||
}
|
||||
async function getCompanyInvoices(companyId, query) {
|
||||
const detail = await billingService.getBillingAccountDetail(companyId);
|
||||
const start = (query.page - 1) * query.pageSize;
|
||||
const end = start + query.pageSize;
|
||||
const data = detail.invoices.slice(start, end);
|
||||
const total = detail.invoices.length;
|
||||
return presenter.presentPaginated(data, total, query.page, query.pageSize);
|
||||
}
|
||||
async function getInvoicePdf(invoiceId) {
|
||||
return billingService.getInvoicePdf(invoiceId);
|
||||
}
|
||||
function getBillingAccountDetail(companyId) {
|
||||
return billingService.getBillingAccountDetail(companyId);
|
||||
}
|
||||
function updateBillingAccount(billingAccountId, data, adminId, ip) {
|
||||
return billingService.updateBillingAccount(billingAccountId, data, adminId, ip);
|
||||
}
|
||||
function setDunningPaused(billingAccountId, paused, adminId, ip) {
|
||||
return billingService.setDunningPaused(billingAccountId, paused, adminId, ip);
|
||||
}
|
||||
function createBillingInvoice(billingAccountId, data, adminId, ip) {
|
||||
return billingService.createDraftInvoice(billingAccountId, data, adminId, ip);
|
||||
}
|
||||
function finalizeBillingInvoice(invoiceId, adminId, ip) {
|
||||
return billingService.finalizeInvoice(invoiceId, adminId, ip);
|
||||
}
|
||||
function payBillingInvoice(invoiceId, data, adminId, ip) {
|
||||
return billingService.payInvoice(invoiceId, data, adminId, ip);
|
||||
}
|
||||
function retryBillingInvoicePayment(invoiceId, data, adminId, ip) {
|
||||
return billingService.retryInvoicePayment(invoiceId, data, adminId, ip);
|
||||
}
|
||||
function voidBillingInvoice(invoiceId, reason, adminId, ip) {
|
||||
return billingService.voidInvoice(invoiceId, reason, adminId, ip);
|
||||
}
|
||||
function markBillingInvoiceUncollectible(invoiceId, reason, adminId, ip) {
|
||||
return billingService.markInvoiceUncollectible(invoiceId, reason, adminId, ip);
|
||||
}
|
||||
function issueBillingCreditNote(invoiceId, data, adminId, ip) {
|
||||
return billingService.issueCreditNote(invoiceId, data, adminId, ip);
|
||||
}
|
||||
function issueBillingRefund(invoiceId, data, adminId, ip) {
|
||||
return billingService.issueRefund(invoiceId, data, adminId, ip);
|
||||
}
|
||||
function getMarketplaceHomepage() {
|
||||
return (0, platformContentService_1.getMarketplaceHomepageContent)();
|
||||
}
|
||||
async function updateMarketplaceHomepage(homepage, adminId, ip) {
|
||||
const saved = await (0, platformContentService_1.saveMarketplaceHomepageContent)(homepage);
|
||||
await repo.createAuditLog({
|
||||
adminUserId: adminId,
|
||||
action: 'UPDATE',
|
||||
resource: 'MarketplaceHomepage',
|
||||
after: toAuditJson(saved),
|
||||
ipAddress: ip,
|
||||
userAgent: undefined,
|
||||
});
|
||||
return saved;
|
||||
}
|
||||
function getPricingConfigs() {
|
||||
return repo.listPricingConfigs();
|
||||
}
|
||||
async function updatePricingConfigs(entries, adminId, ip) {
|
||||
const results = await Promise.all(entries.map((e) => repo.upsertPricingConfig(e.plan, e.billingPeriod, e.amount, adminId)));
|
||||
await repo.createAuditLog({
|
||||
adminUserId: adminId,
|
||||
action: 'UPDATE',
|
||||
resource: 'PricingConfig',
|
||||
after: toAuditJson(results),
|
||||
ipAddress: ip,
|
||||
userAgent: undefined,
|
||||
});
|
||||
return results;
|
||||
}
|
||||
function listPlanFeatures() {
|
||||
return repo.listPlanFeatures();
|
||||
}
|
||||
async function createPlanFeature(data, adminId, ip) {
|
||||
const feature = await repo.createPlanFeature(data);
|
||||
await repo.createAuditLog({
|
||||
adminUserId: adminId,
|
||||
action: 'CREATE',
|
||||
resource: 'PlanFeature',
|
||||
after: toAuditJson(feature),
|
||||
ipAddress: ip,
|
||||
userAgent: undefined,
|
||||
});
|
||||
return feature;
|
||||
}
|
||||
async function updatePlanFeature(id, data, adminId, ip) {
|
||||
const feature = await repo.updatePlanFeature(id, data);
|
||||
await repo.createAuditLog({
|
||||
adminUserId: adminId,
|
||||
action: 'UPDATE',
|
||||
resource: 'PlanFeature',
|
||||
resourceId: id,
|
||||
after: toAuditJson(feature),
|
||||
ipAddress: ip,
|
||||
userAgent: undefined,
|
||||
});
|
||||
return feature;
|
||||
}
|
||||
async function deletePlanFeature(id, adminId, ip) {
|
||||
await repo.deletePlanFeature(id);
|
||||
await repo.createAuditLog({
|
||||
adminUserId: adminId,
|
||||
action: 'DELETE',
|
||||
resource: 'PlanFeature',
|
||||
resourceId: id,
|
||||
ipAddress: ip,
|
||||
userAgent: undefined,
|
||||
});
|
||||
}
|
||||
// ─── Promotions ────────────────────────────────────────────────────────────
|
||||
function listPromotions() {
|
||||
return repo.listPromotions();
|
||||
}
|
||||
async function createPromotion(data, adminId, ip) {
|
||||
const promo = await repo.createPromotion({ ...data, createdBy: adminId });
|
||||
await repo.createAuditLog({
|
||||
adminUserId: adminId, action: 'CREATE', resource: 'PricingPromotion',
|
||||
after: toAuditJson(promo), ipAddress: ip, userAgent: undefined,
|
||||
});
|
||||
return promo;
|
||||
}
|
||||
async function updatePromotion(id, data, adminId, ip) {
|
||||
const promo = await repo.updatePromotion(id, data);
|
||||
await repo.createAuditLog({
|
||||
adminUserId: adminId, action: 'UPDATE', resource: 'PricingPromotion',
|
||||
after: toAuditJson(promo), ipAddress: ip, userAgent: undefined,
|
||||
});
|
||||
return promo;
|
||||
}
|
||||
async function deletePromotion(id, adminId, ip) {
|
||||
await repo.deletePromotion(id);
|
||||
await repo.createAuditLog({
|
||||
adminUserId: adminId, action: 'DELETE', resource: 'PricingPromotion',
|
||||
entityId: id, ipAddress: ip, userAgent: undefined,
|
||||
});
|
||||
}
|
||||
//# sourceMappingURL=admin.service.js.map
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,3 @@
|
||||
declare const router: import("express-serve-static-core").Router;
|
||||
export default router;
|
||||
//# sourceMappingURL=analytics.routes.d.ts.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"analytics.routes.d.ts","sourceRoot":"","sources":["../../../src/modules/analytics/analytics.routes.ts"],"names":[],"mappings":"AAUA,QAAA,MAAM,MAAM,4CAAW,CAAA;AAsCvB,eAAe,MAAM,CAAA"}
|
||||
@@ -0,0 +1,90 @@
|
||||
"use strict";
|
||||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
var desc = Object.getOwnPropertyDescriptor(m, k);
|
||||
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
||||
desc = { enumerable: true, get: function() { return m[k]; } };
|
||||
}
|
||||
Object.defineProperty(o, k2, desc);
|
||||
}) : (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
o[k2] = m[k];
|
||||
}));
|
||||
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
||||
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
||||
}) : function(o, v) {
|
||||
o["default"] = v;
|
||||
});
|
||||
var __importStar = (this && this.__importStar) || (function () {
|
||||
var ownKeys = function(o) {
|
||||
ownKeys = Object.getOwnPropertyNames || function (o) {
|
||||
var ar = [];
|
||||
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
||||
return ar;
|
||||
};
|
||||
return ownKeys(o);
|
||||
};
|
||||
return function (mod) {
|
||||
if (mod && mod.__esModule) return mod;
|
||||
var result = {};
|
||||
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
||||
__setModuleDefault(result, mod);
|
||||
return result;
|
||||
};
|
||||
})();
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const express_1 = require("express");
|
||||
const requireCompanyAuth_1 = require("../../middleware/requireCompanyAuth");
|
||||
const requireTenant_1 = require("../../middleware/requireTenant");
|
||||
const requireSubscription_1 = require("../../middleware/requireSubscription");
|
||||
const requireRole_1 = require("../../middleware/requireRole");
|
||||
const validate_1 = require("../../http/validate");
|
||||
const respond_1 = require("../../http/respond");
|
||||
const service = __importStar(require("./analytics.service"));
|
||||
const analytics_schemas_1 = require("./analytics.schemas");
|
||||
const router = (0, express_1.Router)();
|
||||
router.use(requireCompanyAuth_1.requireCompanyAuth, requireTenant_1.requireTenant, requireSubscription_1.requireSubscription);
|
||||
router.get('/summary', async (req, res, next) => {
|
||||
try {
|
||||
const { period } = (0, validate_1.parseQuery)(analytics_schemas_1.summaryQuerySchema, req);
|
||||
(0, respond_1.ok)(res, await service.getSummary(req.companyId, period));
|
||||
}
|
||||
catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
router.get('/dashboard', async (req, res, next) => {
|
||||
try {
|
||||
(0, respond_1.ok)(res, await service.getDashboard(req.companyId));
|
||||
}
|
||||
catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
router.get('/sources', async (req, res, next) => {
|
||||
try {
|
||||
(0, respond_1.ok)(res, await service.getSources(req.companyId));
|
||||
}
|
||||
catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
router.get('/report', (0, requireRole_1.requireRole)('MANAGER'), async (req, res, next) => {
|
||||
try {
|
||||
const query = (0, validate_1.parseQuery)(analytics_schemas_1.reportQuerySchema, req);
|
||||
const result = await service.getReport(req.companyId, query);
|
||||
if (result.format === 'CSV') {
|
||||
const start = result.startDate.toISOString().slice(0, 10);
|
||||
const end = result.endDate.toISOString().slice(0, 10);
|
||||
res.setHeader('Content-Type', 'text/csv');
|
||||
res.setHeader('Content-Disposition', `attachment; filename="report-${start}-${end}.csv"`);
|
||||
return res.send(result.csv);
|
||||
}
|
||||
(0, respond_1.ok)(res, result.report);
|
||||
}
|
||||
catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
exports.default = router;
|
||||
//# sourceMappingURL=analytics.routes.js.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"analytics.routes.js","sourceRoot":"","sources":["../../../src/modules/analytics/analytics.routes.ts"],"names":[],"mappings":"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"}
|
||||
@@ -0,0 +1,25 @@
|
||||
import { z } from 'zod';
|
||||
export declare const summaryQuerySchema: z.ZodObject<{
|
||||
period: z.ZodDefault<z.ZodString>;
|
||||
}, "strip", z.ZodTypeAny, {
|
||||
period: string;
|
||||
}, {
|
||||
period?: string | undefined;
|
||||
}>;
|
||||
export declare const reportQuerySchema: z.ZodObject<{
|
||||
from: z.ZodOptional<z.ZodString>;
|
||||
to: z.ZodOptional<z.ZodString>;
|
||||
format: z.ZodDefault<z.ZodString>;
|
||||
period: z.ZodOptional<z.ZodString>;
|
||||
}, "strip", z.ZodTypeAny, {
|
||||
format: string;
|
||||
from?: string | undefined;
|
||||
to?: string | undefined;
|
||||
period?: string | undefined;
|
||||
}, {
|
||||
format?: string | undefined;
|
||||
from?: string | undefined;
|
||||
to?: string | undefined;
|
||||
period?: string | undefined;
|
||||
}>;
|
||||
//# sourceMappingURL=analytics.schemas.d.ts.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"analytics.schemas.d.ts","sourceRoot":"","sources":["../../../src/modules/analytics/analytics.schemas.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAEvB,eAAO,MAAM,kBAAkB;;;;;;EAE7B,CAAA;AAEF,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;EAK5B,CAAA"}
|
||||
@@ -0,0 +1,14 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.reportQuerySchema = exports.summaryQuerySchema = void 0;
|
||||
const zod_1 = require("zod");
|
||||
exports.summaryQuerySchema = zod_1.z.object({
|
||||
period: zod_1.z.string().default('30d'),
|
||||
});
|
||||
exports.reportQuerySchema = zod_1.z.object({
|
||||
from: zod_1.z.string().optional(),
|
||||
to: zod_1.z.string().optional(),
|
||||
format: zod_1.z.string().default('JSON'),
|
||||
period: zod_1.z.string().optional(),
|
||||
});
|
||||
//# sourceMappingURL=analytics.schemas.js.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"analytics.schemas.js","sourceRoot":"","sources":["../../../src/modules/analytics/analytics.schemas.ts"],"names":[],"mappings":";;;AAAA,6BAAuB;AAEV,QAAA,kBAAkB,GAAG,OAAC,CAAC,MAAM,CAAC;IACzC,MAAM,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC;CAClC,CAAC,CAAA;AAEW,QAAA,iBAAiB,GAAG,OAAC,CAAC,MAAM,CAAC;IACxC,IAAI,EAAI,OAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC7B,EAAE,EAAM,OAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC7B,MAAM,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC;IAClC,MAAM,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CAC9B,CAAC,CAAA"}
|
||||
@@ -0,0 +1,70 @@
|
||||
export declare function getSummary(companyId: string, period: string): Promise<{
|
||||
totalReservations: any;
|
||||
activeVehicles: any;
|
||||
totalRevenue: any;
|
||||
totalCustomers: any;
|
||||
period: string;
|
||||
}>;
|
||||
export declare function getDashboard(companyId: string): Promise<{
|
||||
kpis: {
|
||||
totalBookings: any;
|
||||
activeVehicles: any;
|
||||
monthlyRevenue: any;
|
||||
totalCustomers: any;
|
||||
bookingsChange: number;
|
||||
vehiclesChange: number;
|
||||
revenueChange: number;
|
||||
customersChange: number;
|
||||
};
|
||||
recentReservations: {
|
||||
id: any;
|
||||
bookingRef: any;
|
||||
customerName: string;
|
||||
vehicleName: string;
|
||||
startDate: any;
|
||||
endDate: any;
|
||||
status: any;
|
||||
totalAmount: any;
|
||||
}[];
|
||||
sourceBreakdown: {
|
||||
source: any;
|
||||
count: any;
|
||||
revenue: any;
|
||||
}[];
|
||||
subscription: {
|
||||
status: any;
|
||||
planName: any;
|
||||
trialEndsAt: any;
|
||||
} | null;
|
||||
}>;
|
||||
export declare function getSources(companyId: string): Promise<any>;
|
||||
export declare function getReport(companyId: string, query: {
|
||||
from?: string;
|
||||
to?: string;
|
||||
format: string;
|
||||
period?: string;
|
||||
}): Promise<{
|
||||
report: {
|
||||
summary: {
|
||||
totalReservations: any;
|
||||
totalRentalRevenue: any;
|
||||
totalDiscounts: any;
|
||||
totalInsurance: any;
|
||||
totalAdditionalDrivers: any;
|
||||
totalPricingRulesAdj: any;
|
||||
totalDeposits: any;
|
||||
totalCollected: any;
|
||||
averageRentalDays: number;
|
||||
};
|
||||
rows: any;
|
||||
period: {
|
||||
startDate: Date;
|
||||
endDate: Date;
|
||||
};
|
||||
};
|
||||
startDate: Date;
|
||||
endDate: Date;
|
||||
format: string;
|
||||
csv: string | null;
|
||||
}>;
|
||||
//# sourceMappingURL=analytics.service.d.ts.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"analytics.service.d.ts","sourceRoot":"","sources":["../../../src/modules/analytics/analytics.service.ts"],"names":[],"mappings":"AAkBA,wBAAsB,UAAU,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;;;;;;GAUjE;AAED,wBAAsB,YAAY,CAAC,SAAS,EAAE,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwDnD;AAED,wBAAsB,UAAU,CAAC,SAAS,EAAE,MAAM,gBAEjD;AAED,wBAAsB,SAAS,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,EAAE,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE;;;;;;;;;;;;;;;;;;;;;;;GAOxH"}
|
||||
@@ -0,0 +1,96 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.getSummary = getSummary;
|
||||
exports.getDashboard = getDashboard;
|
||||
exports.getSources = getSources;
|
||||
exports.getReport = getReport;
|
||||
const prisma_1 = require("../../lib/prisma");
|
||||
const financialReportService_1 = require("../../services/financialReportService");
|
||||
function getRangeFromPeriod(period) {
|
||||
const now = new Date();
|
||||
switch (period) {
|
||||
case 'WEEKLY': return { from: new Date(now.getTime() - 7 * 24 * 60 * 60 * 1000), to: now };
|
||||
case 'QUARTERLY': return { from: new Date(now.getFullYear(), now.getMonth() - 2, 1), to: now };
|
||||
case 'ANNUAL': return { from: new Date(now.getFullYear(), 0, 1), to: now };
|
||||
default: return { from: new Date(now.getFullYear(), now.getMonth(), 1), to: now };
|
||||
}
|
||||
}
|
||||
function pct(current, previous) {
|
||||
if (previous === 0)
|
||||
return current > 0 ? 100 : 0;
|
||||
return Math.round(((current - previous) / previous) * 100);
|
||||
}
|
||||
async function getSummary(companyId, period) {
|
||||
const days = parseInt(period.replace('d', '')) || 30;
|
||||
const since = new Date(Date.now() - days * 24 * 60 * 60 * 1000);
|
||||
const [totalReservations, activeVehicles, totalRevenue, totalCustomers] = await Promise.all([
|
||||
prisma_1.prisma.reservation.count({ where: { companyId, createdAt: { gte: since } } }),
|
||||
prisma_1.prisma.vehicle.count({ where: { companyId, status: 'AVAILABLE' } }),
|
||||
prisma_1.prisma.reservation.aggregate({ where: { companyId, status: { in: ['COMPLETED'] }, createdAt: { gte: since } }, _sum: { totalAmount: true } }),
|
||||
prisma_1.prisma.customer.count({ where: { companyId } }),
|
||||
]);
|
||||
return { totalReservations, activeVehicles, totalRevenue: totalRevenue._sum.totalAmount ?? 0, totalCustomers, period };
|
||||
}
|
||||
async function getDashboard(companyId) {
|
||||
const now = new Date();
|
||||
const monthStart = new Date(now.getFullYear(), now.getMonth(), 1);
|
||||
const prevMonthStart = new Date(now.getFullYear(), now.getMonth() - 1, 1);
|
||||
const prevMonthEnd = new Date(monthStart.getTime() - 1);
|
||||
const [totalBookings, previousBookings, activeVehicles, previousActiveVehicles, totalCustomers, previousCustomers, monthlyRevenueAgg, previousRevenueAgg, recentReservations, sourceGroups, subscription,] = await Promise.all([
|
||||
prisma_1.prisma.reservation.count({ where: { companyId, createdAt: { gte: monthStart } } }),
|
||||
prisma_1.prisma.reservation.count({ where: { companyId, createdAt: { gte: prevMonthStart, lte: prevMonthEnd } } }),
|
||||
prisma_1.prisma.vehicle.count({ where: { companyId, status: { in: ['AVAILABLE', 'RENTED'] } } }),
|
||||
prisma_1.prisma.vehicle.count({ where: { companyId, createdAt: { lte: prevMonthEnd }, status: { in: ['AVAILABLE', 'RENTED'] } } }),
|
||||
prisma_1.prisma.customer.count({ where: { companyId } }),
|
||||
prisma_1.prisma.customer.count({ where: { companyId, createdAt: { lte: prevMonthEnd } } }),
|
||||
prisma_1.prisma.reservation.aggregate({ where: { companyId, status: { in: ['CONFIRMED', 'ACTIVE', 'COMPLETED'] }, createdAt: { gte: monthStart } }, _sum: { totalAmount: true } }),
|
||||
prisma_1.prisma.reservation.aggregate({ where: { companyId, status: { in: ['CONFIRMED', 'ACTIVE', 'COMPLETED'] }, createdAt: { gte: prevMonthStart, lte: prevMonthEnd } }, _sum: { totalAmount: true } }),
|
||||
prisma_1.prisma.reservation.findMany({ where: { companyId }, include: { customer: true, vehicle: true }, orderBy: { createdAt: 'desc' }, take: 8 }),
|
||||
prisma_1.prisma.reservation.groupBy({ by: ['source'], where: { companyId }, _count: { id: true }, _sum: { totalAmount: true } }),
|
||||
prisma_1.prisma.subscription.findUnique({ where: { companyId } }),
|
||||
]);
|
||||
return {
|
||||
kpis: {
|
||||
totalBookings,
|
||||
activeVehicles,
|
||||
monthlyRevenue: monthlyRevenueAgg._sum.totalAmount ?? 0,
|
||||
totalCustomers,
|
||||
bookingsChange: pct(totalBookings, previousBookings),
|
||||
vehiclesChange: pct(activeVehicles, previousActiveVehicles),
|
||||
revenueChange: pct(monthlyRevenueAgg._sum.totalAmount ?? 0, previousRevenueAgg._sum.totalAmount ?? 0),
|
||||
customersChange: pct(totalCustomers, previousCustomers),
|
||||
},
|
||||
recentReservations: recentReservations.map((r) => ({
|
||||
id: r.id,
|
||||
bookingRef: r.contractNumber ?? r.id.slice(-8).toUpperCase(),
|
||||
customerName: `${r.customer.firstName} ${r.customer.lastName}`,
|
||||
vehicleName: `${r.vehicle.make} ${r.vehicle.model}`,
|
||||
startDate: r.startDate,
|
||||
endDate: r.endDate,
|
||||
status: r.status,
|
||||
totalAmount: r.totalAmount,
|
||||
})),
|
||||
sourceBreakdown: sourceGroups.map((g) => ({
|
||||
source: g.source,
|
||||
count: g._count.id,
|
||||
revenue: g._sum.totalAmount ?? 0,
|
||||
})),
|
||||
subscription: subscription ? {
|
||||
status: subscription.status,
|
||||
planName: subscription.plan,
|
||||
trialEndsAt: subscription.trialEndAt,
|
||||
} : null,
|
||||
};
|
||||
}
|
||||
async function getSources(companyId) {
|
||||
return prisma_1.prisma.reservation.groupBy({ by: ['source'], where: { companyId }, _count: { id: true } });
|
||||
}
|
||||
async function getReport(companyId, query) {
|
||||
const accountingSettings = await prisma_1.prisma.accountingSettings.findUnique({ where: { companyId } });
|
||||
const derivedRange = getRangeFromPeriod(query.period || accountingSettings?.reportingPeriod || 'MONTHLY');
|
||||
const startDate = query.from ? new Date(query.from) : derivedRange.from;
|
||||
const endDate = query.to ? new Date(query.to) : derivedRange.to;
|
||||
const report = await (0, financialReportService_1.generateFinancialReport)(companyId, startDate, endDate);
|
||||
return { report, startDate, endDate, format: query.format, csv: query.format === 'CSV' ? (0, financialReportService_1.toCsv)(report.rows) : null };
|
||||
}
|
||||
//# sourceMappingURL=analytics.service.js.map
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,50 @@
|
||||
import { prisma } from '../../lib/prisma';
|
||||
type DbClient = Pick<typeof prisma, 'company' | 'brandSettings' | 'contractSettings' | 'subscription' | 'employee'>;
|
||||
type CompanySignupInput = {
|
||||
companyName: string;
|
||||
legalName: string;
|
||||
slug: string;
|
||||
ownerEmail: string;
|
||||
companyEmail: string;
|
||||
companyPhone: string;
|
||||
streetAddress: string;
|
||||
city: string;
|
||||
country: string;
|
||||
zipCode: string;
|
||||
legalForm: string;
|
||||
managerName: string;
|
||||
iceNumber: string;
|
||||
taxId: string;
|
||||
operatingLicenseNumber: string;
|
||||
operatingLicenseIssuedAt: string;
|
||||
operatingLicenseIssuedBy: string;
|
||||
fax?: string;
|
||||
yearsActive: string;
|
||||
representativeName?: string;
|
||||
representativeTitle?: string;
|
||||
responsibleName: string;
|
||||
responsibleRole: string;
|
||||
responsibleIdentityNumber: string;
|
||||
responsibleQualification?: string;
|
||||
responsiblePhone: string;
|
||||
responsibleEmail: string;
|
||||
currency: 'MAD';
|
||||
registrationNumber: string;
|
||||
plan: 'STARTER' | 'GROWTH' | 'PRO';
|
||||
billingPeriod: 'MONTHLY' | 'ANNUAL';
|
||||
preferredLanguage: 'en' | 'fr' | 'ar';
|
||||
firstName: string;
|
||||
lastName: string;
|
||||
passwordHash: string;
|
||||
now: Date;
|
||||
trialEndAt: Date;
|
||||
};
|
||||
export declare function findCompanyBySlug(slug: string): any;
|
||||
export declare function findCompanyByEmail(email: string): any;
|
||||
export declare function findEmployeeByEmail(email: string): any;
|
||||
export declare function createCompanySignup(db: DbClient, input: CompanySignupInput): Promise<{
|
||||
company: any;
|
||||
employee: any;
|
||||
}>;
|
||||
export {};
|
||||
//# sourceMappingURL=auth.company.repo.d.ts.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"auth.company.repo.d.ts","sourceRoot":"","sources":["../../../src/modules/auth/auth.company.repo.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAA;AAEzC,KAAK,QAAQ,GAAG,IAAI,CAAC,OAAO,MAAM,EAAE,SAAS,GAAG,eAAe,GAAG,kBAAkB,GAAG,cAAc,GAAG,UAAU,CAAC,CAAA;AAEnH,KAAK,kBAAkB,GAAG;IACxB,WAAW,EAAE,MAAM,CAAA;IACnB,SAAS,EAAE,MAAM,CAAA;IACjB,IAAI,EAAE,MAAM,CAAA;IACZ,UAAU,EAAE,MAAM,CAAA;IAClB,YAAY,EAAE,MAAM,CAAA;IACpB,YAAY,EAAE,MAAM,CAAA;IACpB,aAAa,EAAE,MAAM,CAAA;IACrB,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,CAAA;IACf,OAAO,EAAE,MAAM,CAAA;IACf,SAAS,EAAE,MAAM,CAAA;IACjB,WAAW,EAAE,MAAM,CAAA;IACnB,SAAS,EAAE,MAAM,CAAA;IACjB,KAAK,EAAE,MAAM,CAAA;IACb,sBAAsB,EAAE,MAAM,CAAA;IAC9B,wBAAwB,EAAE,MAAM,CAAA;IAChC,wBAAwB,EAAE,MAAM,CAAA;IAChC,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,WAAW,EAAE,MAAM,CAAA;IACnB,kBAAkB,CAAC,EAAE,MAAM,CAAA;IAC3B,mBAAmB,CAAC,EAAE,MAAM,CAAA;IAC5B,eAAe,EAAE,MAAM,CAAA;IACvB,eAAe,EAAE,MAAM,CAAA;IACvB,yBAAyB,EAAE,MAAM,CAAA;IACjC,wBAAwB,CAAC,EAAE,MAAM,CAAA;IACjC,gBAAgB,EAAE,MAAM,CAAA;IACxB,gBAAgB,EAAE,MAAM,CAAA;IACxB,QAAQ,EAAE,KAAK,CAAA;IACf,kBAAkB,EAAE,MAAM,CAAA;IAC1B,IAAI,EAAE,SAAS,GAAG,QAAQ,GAAG,KAAK,CAAA;IAClC,aAAa,EAAE,SAAS,GAAG,QAAQ,CAAA;IACnC,iBAAiB,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAAA;IACrC,SAAS,EAAE,MAAM,CAAA;IACjB,QAAQ,EAAE,MAAM,CAAA;IAChB,YAAY,EAAE,MAAM,CAAA;IACpB,GAAG,EAAE,IAAI,CAAA;IACT,UAAU,EAAE,IAAI,CAAA;CACjB,CAAA;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,OAE7C;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,OAE/C;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,OAEhD;AAED,wBAAsB,mBAAmB,CAAC,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,kBAAkB;;;GAyFhF"}
|
||||
+102
@@ -0,0 +1,102 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.findCompanyBySlug = findCompanyBySlug;
|
||||
exports.findCompanyByEmail = findCompanyByEmail;
|
||||
exports.findEmployeeByEmail = findEmployeeByEmail;
|
||||
exports.createCompanySignup = createCompanySignup;
|
||||
const prisma_1 = require("../../lib/prisma");
|
||||
function findCompanyBySlug(slug) {
|
||||
return prisma_1.prisma.company.findUnique({ where: { slug } });
|
||||
}
|
||||
function findCompanyByEmail(email) {
|
||||
return prisma_1.prisma.company.findUnique({ where: { email } });
|
||||
}
|
||||
function findEmployeeByEmail(email) {
|
||||
return prisma_1.prisma.employee.findFirst({ where: { email } });
|
||||
}
|
||||
async function createCompanySignup(db, input) {
|
||||
const company = await db.company.create({
|
||||
data: {
|
||||
name: input.companyName,
|
||||
slug: input.slug,
|
||||
email: input.companyEmail,
|
||||
phone: input.companyPhone,
|
||||
address: {
|
||||
streetAddress: input.streetAddress,
|
||||
city: input.city,
|
||||
country: input.country,
|
||||
zipCode: input.zipCode,
|
||||
legalName: input.legalName,
|
||||
legalForm: input.legalForm,
|
||||
companyEmail: input.companyEmail,
|
||||
managerName: input.managerName,
|
||||
iceNumber: input.iceNumber,
|
||||
operatingLicenseNumber: input.operatingLicenseNumber,
|
||||
operatingLicenseIssuedAt: input.operatingLicenseIssuedAt,
|
||||
operatingLicenseIssuedBy: input.operatingLicenseIssuedBy,
|
||||
fax: input.fax || null,
|
||||
yearsActive: input.yearsActive,
|
||||
representativeName: input.representativeName || null,
|
||||
representativeTitle: input.representativeTitle || null,
|
||||
responsibleName: input.responsibleName,
|
||||
responsibleRole: input.responsibleRole,
|
||||
responsibleIdentityNumber: input.responsibleIdentityNumber,
|
||||
responsibleQualification: input.responsibleQualification || null,
|
||||
responsiblePhone: input.responsiblePhone,
|
||||
responsibleEmail: input.responsibleEmail,
|
||||
},
|
||||
status: 'TRIALING',
|
||||
},
|
||||
});
|
||||
await db.brandSettings.create({
|
||||
data: {
|
||||
companyId: company.id,
|
||||
displayName: input.companyName,
|
||||
subdomain: input.slug,
|
||||
publicEmail: input.companyEmail,
|
||||
publicPhone: input.companyPhone,
|
||||
publicAddress: input.streetAddress,
|
||||
publicCity: input.city,
|
||||
publicCountry: input.country,
|
||||
defaultLocale: input.preferredLanguage,
|
||||
defaultCurrency: input.currency,
|
||||
},
|
||||
});
|
||||
await db.contractSettings.create({
|
||||
data: {
|
||||
companyId: company.id,
|
||||
legalName: input.legalName,
|
||||
registrationNumber: input.registrationNumber,
|
||||
taxId: input.taxId,
|
||||
},
|
||||
});
|
||||
await db.subscription.create({
|
||||
data: {
|
||||
companyId: company.id,
|
||||
plan: input.plan,
|
||||
billingPeriod: input.billingPeriod,
|
||||
currency: input.currency,
|
||||
status: 'TRIALING',
|
||||
trialStartAt: input.now,
|
||||
trialEndAt: input.trialEndAt,
|
||||
currentPeriodStart: input.now,
|
||||
currentPeriodEnd: input.trialEndAt,
|
||||
},
|
||||
});
|
||||
const employee = await db.employee.create({
|
||||
data: {
|
||||
companyId: company.id,
|
||||
clerkUserId: `local_owner_${company.id}`,
|
||||
firstName: input.firstName,
|
||||
lastName: input.lastName,
|
||||
email: input.ownerEmail,
|
||||
phone: input.companyPhone,
|
||||
passwordHash: input.passwordHash,
|
||||
role: 'OWNER',
|
||||
preferredLanguage: input.preferredLanguage,
|
||||
isActive: true,
|
||||
},
|
||||
});
|
||||
return { company, employee };
|
||||
}
|
||||
//# sourceMappingURL=auth.company.repo.js.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"auth.company.repo.js","sourceRoot":"","sources":["../../../src/modules/auth/auth.company.repo.ts"],"names":[],"mappings":"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"}
|
||||
@@ -0,0 +1,3 @@
|
||||
declare const router: import("express-serve-static-core").Router;
|
||||
export default router;
|
||||
//# sourceMappingURL=auth.company.routes.d.ts.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"auth.company.routes.d.ts","sourceRoot":"","sources":["../../../src/modules/auth/auth.company.routes.ts"],"names":[],"mappings":"AAMA,QAAA,MAAM,MAAM,4CAAW,CAAA;AAmBvB,eAAe,MAAM,CAAA"}
|
||||
@@ -0,0 +1,60 @@
|
||||
"use strict";
|
||||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
var desc = Object.getOwnPropertyDescriptor(m, k);
|
||||
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
||||
desc = { enumerable: true, get: function() { return m[k]; } };
|
||||
}
|
||||
Object.defineProperty(o, k2, desc);
|
||||
}) : (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
o[k2] = m[k];
|
||||
}));
|
||||
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
||||
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
||||
}) : function(o, v) {
|
||||
o["default"] = v;
|
||||
});
|
||||
var __importStar = (this && this.__importStar) || (function () {
|
||||
var ownKeys = function(o) {
|
||||
ownKeys = Object.getOwnPropertyNames || function (o) {
|
||||
var ar = [];
|
||||
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
||||
return ar;
|
||||
};
|
||||
return ownKeys(o);
|
||||
};
|
||||
return function (mod) {
|
||||
if (mod && mod.__esModule) return mod;
|
||||
var result = {};
|
||||
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
||||
__setModuleDefault(result, mod);
|
||||
return result;
|
||||
};
|
||||
})();
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const express_1 = require("express");
|
||||
const validate_1 = require("../../http/validate");
|
||||
const respond_1 = require("../../http/respond");
|
||||
const auth_company_schemas_1 = require("./auth.company.schemas");
|
||||
const service = __importStar(require("./auth.company.service"));
|
||||
const router = (0, express_1.Router)();
|
||||
router.post('/signup', async (req, res, next) => {
|
||||
try {
|
||||
const body = (0, validate_1.parseBody)(auth_company_schemas_1.companySignupSchema, req);
|
||||
(0, respond_1.created)(res, await service.signup(body));
|
||||
}
|
||||
catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
router.post('/complete-signup', (_req, res) => {
|
||||
service.completeSignupDisabled();
|
||||
res.end();
|
||||
});
|
||||
router.post('/verify-email', (_req, res) => {
|
||||
service.verifyEmailDisabled();
|
||||
res.end();
|
||||
});
|
||||
exports.default = router;
|
||||
//# sourceMappingURL=auth.company.routes.js.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"auth.company.routes.js","sourceRoot":"","sources":["../../../src/modules/auth/auth.company.routes.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,qCAAgC;AAChC,kDAA+C;AAC/C,gDAA4C;AAC5C,iEAA4D;AAC5D,gEAAiD;AAEjD,MAAM,MAAM,GAAG,IAAA,gBAAM,GAAE,CAAA;AAEvB,MAAM,CAAC,IAAI,CAAC,SAAS,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE;IAC9C,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,IAAA,oBAAS,EAAC,0CAAmB,EAAE,GAAG,CAAC,CAAA;QAChD,IAAA,iBAAO,EAAC,GAAG,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAA;IAC1C,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QAAC,IAAI,CAAC,GAAG,CAAC,CAAA;IAAC,CAAC;AAC7B,CAAC,CAAC,CAAA;AAEF,MAAM,CAAC,IAAI,CAAC,kBAAkB,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE;IAC5C,OAAO,CAAC,sBAAsB,EAAE,CAAA;IAChC,GAAG,CAAC,GAAG,EAAE,CAAA;AACX,CAAC,CAAC,CAAA;AAEF,MAAM,CAAC,IAAI,CAAC,eAAe,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE;IACzC,OAAO,CAAC,mBAAmB,EAAE,CAAA;IAC7B,GAAG,CAAC,GAAG,EAAE,CAAA;AACX,CAAC,CAAC,CAAA;AAEF,kBAAe,MAAM,CAAA"}
|
||||
@@ -0,0 +1,108 @@
|
||||
import { z } from 'zod';
|
||||
export declare const companySignupSchema: z.ZodObject<{
|
||||
firstName: z.ZodString;
|
||||
lastName: z.ZodString;
|
||||
email: z.ZodString;
|
||||
password: z.ZodString;
|
||||
companyName: z.ZodString;
|
||||
legalName: z.ZodString;
|
||||
legalForm: z.ZodString;
|
||||
registrationNumber: z.ZodString;
|
||||
iceNumber: z.ZodString;
|
||||
taxId: z.ZodString;
|
||||
operatingLicenseNumber: z.ZodString;
|
||||
operatingLicenseIssuedAt: z.ZodString;
|
||||
operatingLicenseIssuedBy: z.ZodString;
|
||||
streetAddress: z.ZodString;
|
||||
city: z.ZodString;
|
||||
country: z.ZodString;
|
||||
zipCode: z.ZodString;
|
||||
companyPhone: z.ZodString;
|
||||
companyEmail: z.ZodString;
|
||||
fax: z.ZodOptional<z.ZodString>;
|
||||
yearsActive: z.ZodString;
|
||||
representativeName: z.ZodOptional<z.ZodString>;
|
||||
representativeTitle: z.ZodOptional<z.ZodString>;
|
||||
responsibleName: z.ZodString;
|
||||
responsibleRole: z.ZodString;
|
||||
responsibleIdentityNumber: z.ZodString;
|
||||
responsibleQualification: z.ZodOptional<z.ZodString>;
|
||||
responsiblePhone: z.ZodString;
|
||||
responsibleEmail: z.ZodString;
|
||||
preferredLanguage: z.ZodDefault<z.ZodEnum<["en", "fr", "ar"]>>;
|
||||
plan: z.ZodEnum<["STARTER", "GROWTH", "PRO"]>;
|
||||
billingPeriod: z.ZodEnum<["MONTHLY", "ANNUAL"]>;
|
||||
currency: z.ZodLiteral<"MAD">;
|
||||
paymentProvider: z.ZodEnum<["AMANPAY", "PAYPAL"]>;
|
||||
}, "strip", z.ZodTypeAny, {
|
||||
firstName: string;
|
||||
lastName: string;
|
||||
email: string;
|
||||
currency: "MAD";
|
||||
password: string;
|
||||
companyName: string;
|
||||
legalName: string;
|
||||
legalForm: string;
|
||||
registrationNumber: string;
|
||||
iceNumber: string;
|
||||
taxId: string;
|
||||
operatingLicenseNumber: string;
|
||||
operatingLicenseIssuedAt: string;
|
||||
operatingLicenseIssuedBy: string;
|
||||
streetAddress: string;
|
||||
city: string;
|
||||
country: string;
|
||||
zipCode: string;
|
||||
companyPhone: string;
|
||||
companyEmail: string;
|
||||
yearsActive: string;
|
||||
responsibleName: string;
|
||||
responsibleRole: string;
|
||||
responsibleIdentityNumber: string;
|
||||
responsiblePhone: string;
|
||||
responsibleEmail: string;
|
||||
preferredLanguage: "en" | "fr" | "ar";
|
||||
plan: "STARTER" | "GROWTH" | "PRO";
|
||||
billingPeriod: "MONTHLY" | "ANNUAL";
|
||||
paymentProvider: "AMANPAY" | "PAYPAL";
|
||||
fax?: string | undefined;
|
||||
representativeName?: string | undefined;
|
||||
representativeTitle?: string | undefined;
|
||||
responsibleQualification?: string | undefined;
|
||||
}, {
|
||||
firstName: string;
|
||||
lastName: string;
|
||||
email: string;
|
||||
currency: "MAD";
|
||||
password: string;
|
||||
companyName: string;
|
||||
legalName: string;
|
||||
legalForm: string;
|
||||
registrationNumber: string;
|
||||
iceNumber: string;
|
||||
taxId: string;
|
||||
operatingLicenseNumber: string;
|
||||
operatingLicenseIssuedAt: string;
|
||||
operatingLicenseIssuedBy: string;
|
||||
streetAddress: string;
|
||||
city: string;
|
||||
country: string;
|
||||
zipCode: string;
|
||||
companyPhone: string;
|
||||
companyEmail: string;
|
||||
yearsActive: string;
|
||||
responsibleName: string;
|
||||
responsibleRole: string;
|
||||
responsibleIdentityNumber: string;
|
||||
responsiblePhone: string;
|
||||
responsibleEmail: string;
|
||||
plan: "STARTER" | "GROWTH" | "PRO";
|
||||
billingPeriod: "MONTHLY" | "ANNUAL";
|
||||
paymentProvider: "AMANPAY" | "PAYPAL";
|
||||
fax?: string | undefined;
|
||||
representativeName?: string | undefined;
|
||||
representativeTitle?: string | undefined;
|
||||
responsibleQualification?: string | undefined;
|
||||
preferredLanguage?: "en" | "fr" | "ar" | undefined;
|
||||
}>;
|
||||
//# sourceMappingURL=auth.company.schemas.d.ts.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"auth.company.schemas.d.ts","sourceRoot":"","sources":["../../../src/modules/auth/auth.company.schemas.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAEvB,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAmC9B,CAAA"}
|
||||
@@ -0,0 +1,41 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.companySignupSchema = void 0;
|
||||
const zod_1 = require("zod");
|
||||
exports.companySignupSchema = zod_1.z.object({
|
||||
firstName: zod_1.z.string().min(1).max(80),
|
||||
lastName: zod_1.z.string().min(1).max(80),
|
||||
email: zod_1.z.string().email(),
|
||||
password: zod_1.z.string().min(8).max(128),
|
||||
companyName: zod_1.z.string().min(2).max(120),
|
||||
legalName: zod_1.z.string().min(2).max(160),
|
||||
legalForm: zod_1.z.string().min(1).max(80),
|
||||
registrationNumber: zod_1.z.string().min(1).max(120),
|
||||
iceNumber: zod_1.z.string().min(1).max(120),
|
||||
taxId: zod_1.z.string().min(1).max(120),
|
||||
operatingLicenseNumber: zod_1.z.string().min(1).max(120),
|
||||
operatingLicenseIssuedAt: zod_1.z.string().min(1).max(40),
|
||||
operatingLicenseIssuedBy: zod_1.z.string().min(1).max(160),
|
||||
streetAddress: zod_1.z.string().min(1).max(200),
|
||||
city: zod_1.z.string().min(1).max(120),
|
||||
country: zod_1.z.string().min(1).max(120),
|
||||
zipCode: zod_1.z.string().min(1).max(40),
|
||||
companyPhone: zod_1.z.string().min(1).max(80),
|
||||
companyEmail: zod_1.z.string().email(),
|
||||
fax: zod_1.z.string().max(80).optional(),
|
||||
yearsActive: zod_1.z.string().min(1).max(80),
|
||||
representativeName: zod_1.z.string().max(160).optional(),
|
||||
representativeTitle: zod_1.z.string().max(120).optional(),
|
||||
responsibleName: zod_1.z.string().min(1).max(160),
|
||||
responsibleRole: zod_1.z.string().min(1).max(120),
|
||||
responsibleIdentityNumber: zod_1.z.string().min(1).max(120),
|
||||
responsibleQualification: zod_1.z.string().max(200).optional(),
|
||||
responsiblePhone: zod_1.z.string().min(1).max(80),
|
||||
responsibleEmail: zod_1.z.string().email(),
|
||||
preferredLanguage: zod_1.z.enum(['en', 'fr', 'ar']).default('en'),
|
||||
plan: zod_1.z.enum(['STARTER', 'GROWTH', 'PRO']),
|
||||
billingPeriod: zod_1.z.enum(['MONTHLY', 'ANNUAL']),
|
||||
currency: zod_1.z.literal('MAD'),
|
||||
paymentProvider: zod_1.z.enum(['AMANPAY', 'PAYPAL']),
|
||||
});
|
||||
//# sourceMappingURL=auth.company.schemas.js.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"auth.company.schemas.js","sourceRoot":"","sources":["../../../src/modules/auth/auth.company.schemas.ts"],"names":[],"mappings":"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"}
|
||||
@@ -0,0 +1,16 @@
|
||||
import { companySignupSchema } from './auth.company.schemas';
|
||||
import type { output } from 'zod';
|
||||
type CompanySignupInput = output<typeof companySignupSchema>;
|
||||
export declare function signup(body: CompanySignupInput): Promise<{
|
||||
companyId: string;
|
||||
companyName: string;
|
||||
slug: string;
|
||||
invitationId: null;
|
||||
trialEndsAt: string;
|
||||
nextStep: string;
|
||||
emailDelivery: {};
|
||||
}>;
|
||||
export declare function completeSignupDisabled(): void;
|
||||
export declare function verifyEmailDisabled(): void;
|
||||
export {};
|
||||
//# sourceMappingURL=auth.company.service.d.ts.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"auth.company.service.d.ts","sourceRoot":"","sources":["../../../src/modules/auth/auth.company.service.ts"],"names":[],"mappings":"AAWA,OAAO,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAA;AAC5D,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,KAAK,CAAA;AAEjC,KAAK,kBAAkB,GAAG,MAAM,CAAC,OAAO,mBAAmB,CAAC,CAAA;AAmB5D,wBAAsB,MAAM,CAAC,IAAI,EAAE,kBAAkB;;;;;;;;GAiFpD;AAED,wBAAgB,sBAAsB,SAErC;AAED,wBAAgB,mBAAmB,SAElC"}
|
||||
+145
@@ -0,0 +1,145 @@
|
||||
"use strict";
|
||||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
var desc = Object.getOwnPropertyDescriptor(m, k);
|
||||
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
||||
desc = { enumerable: true, get: function() { return m[k]; } };
|
||||
}
|
||||
Object.defineProperty(o, k2, desc);
|
||||
}) : (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
o[k2] = m[k];
|
||||
}));
|
||||
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
||||
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
||||
}) : function(o, v) {
|
||||
o["default"] = v;
|
||||
});
|
||||
var __importStar = (this && this.__importStar) || (function () {
|
||||
var ownKeys = function(o) {
|
||||
ownKeys = Object.getOwnPropertyNames || function (o) {
|
||||
var ar = [];
|
||||
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
||||
return ar;
|
||||
};
|
||||
return ownKeys(o);
|
||||
};
|
||||
return function (mod) {
|
||||
if (mod && mod.__esModule) return mod;
|
||||
var result = {};
|
||||
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
||||
__setModuleDefault(result, mod);
|
||||
return result;
|
||||
};
|
||||
})();
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.signup = signup;
|
||||
exports.completeSignupDisabled = completeSignupDisabled;
|
||||
exports.verifyEmailDisabled = verifyEmailDisabled;
|
||||
const bcryptjs_1 = __importDefault(require("bcryptjs"));
|
||||
const errors_1 = require("../../http/errors");
|
||||
const prisma_1 = require("../../lib/prisma");
|
||||
const notificationService_1 = require("../../services/notificationService");
|
||||
const notificationLocalizationService_1 = require("../../services/notificationLocalizationService");
|
||||
const auth_presenter_1 = require("./auth.presenter");
|
||||
const repo = __importStar(require("./auth.company.repo"));
|
||||
const TRIAL_PERIOD_DAYS = 90;
|
||||
function slugify(value) {
|
||||
return value.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '').slice(0, 50) || 'company';
|
||||
}
|
||||
async function generateUniqueSlug(baseName) {
|
||||
const base = slugify(baseName);
|
||||
for (let attempt = 0; attempt < 25; attempt++) {
|
||||
const slug = attempt === 0 ? base : `${base}-${attempt + 1}`;
|
||||
const existing = await repo.findCompanyBySlug(slug);
|
||||
if (!existing)
|
||||
return slug;
|
||||
}
|
||||
return `${base}-${Date.now().toString(36)}`;
|
||||
}
|
||||
async function signup(body) {
|
||||
if (await repo.findCompanyByEmail(body.companyEmail)) {
|
||||
throw new errors_1.AppError('A company account with this contact email already exists', 409, 'company_email_taken');
|
||||
}
|
||||
if (await repo.findEmployeeByEmail(body.email)) {
|
||||
throw new errors_1.AppError('An employee account with this owner email already exists', 409, 'owner_email_taken');
|
||||
}
|
||||
const slug = await generateUniqueSlug(body.companyName);
|
||||
const now = new Date();
|
||||
const trialEndAt = new Date(now.getTime() + TRIAL_PERIOD_DAYS * 24 * 60 * 60 * 1000);
|
||||
const passwordHash = await bcryptjs_1.default.hash(body.password, 12);
|
||||
const result = await prisma_1.prisma.$transaction((tx) => repo.createCompanySignup(tx, {
|
||||
companyName: body.companyName,
|
||||
legalName: body.legalName,
|
||||
slug,
|
||||
ownerEmail: body.email,
|
||||
companyEmail: body.companyEmail,
|
||||
companyPhone: body.companyPhone,
|
||||
streetAddress: body.streetAddress,
|
||||
city: body.city,
|
||||
country: body.country,
|
||||
zipCode: body.zipCode,
|
||||
legalForm: body.legalForm,
|
||||
managerName: `${body.firstName} ${body.lastName}`.trim(),
|
||||
iceNumber: body.iceNumber,
|
||||
taxId: body.taxId,
|
||||
operatingLicenseNumber: body.operatingLicenseNumber,
|
||||
operatingLicenseIssuedAt: body.operatingLicenseIssuedAt,
|
||||
operatingLicenseIssuedBy: body.operatingLicenseIssuedBy,
|
||||
fax: body.fax,
|
||||
yearsActive: body.yearsActive,
|
||||
representativeName: body.representativeName,
|
||||
representativeTitle: body.representativeTitle,
|
||||
responsibleName: body.responsibleName,
|
||||
responsibleRole: body.responsibleRole,
|
||||
responsibleIdentityNumber: body.responsibleIdentityNumber,
|
||||
responsibleQualification: body.responsibleQualification,
|
||||
responsiblePhone: body.responsiblePhone,
|
||||
responsibleEmail: body.responsibleEmail,
|
||||
currency: body.currency,
|
||||
registrationNumber: body.registrationNumber,
|
||||
plan: body.plan,
|
||||
billingPeriod: body.billingPeriod,
|
||||
preferredLanguage: body.preferredLanguage,
|
||||
firstName: body.firstName,
|
||||
lastName: body.lastName,
|
||||
passwordHash,
|
||||
now,
|
||||
trialEndAt,
|
||||
}));
|
||||
const lang = (0, notificationLocalizationService_1.coerceNotificationLocale)(body.preferredLanguage);
|
||||
const emailResult = await (0, notificationService_1.sendNotification)({
|
||||
type: 'ACCOUNT_CREATED',
|
||||
companyId: result.company.id,
|
||||
employeeId: result.employee.id,
|
||||
email: body.email,
|
||||
channels: ['EMAIL', 'IN_APP'],
|
||||
locale: lang,
|
||||
templateKey: 'account.created',
|
||||
templateVariables: {
|
||||
firstName: body.firstName,
|
||||
companyName: body.companyName,
|
||||
planName: (0, notificationLocalizationService_1.localizePlanName)(body.plan, lang),
|
||||
billingPeriodLabel: (0, notificationLocalizationService_1.localizeBillingPeriod)(body.billingPeriod, lang),
|
||||
currency: body.currency,
|
||||
paymentProvider: body.paymentProvider,
|
||||
trialEndDate: trialEndAt,
|
||||
},
|
||||
}).catch(() => []);
|
||||
const emailDelivery = emailResult.find((entry) => entry.channel === 'EMAIL');
|
||||
return (0, auth_presenter_1.presentCompanySignup)({
|
||||
company: result.company,
|
||||
trialEndAt,
|
||||
emailDelivery,
|
||||
});
|
||||
}
|
||||
function completeSignupDisabled() {
|
||||
throw new errors_1.AppError('Clerk-based signup has been removed. Use /auth/company/signup instead.', 410, 'disabled');
|
||||
}
|
||||
function verifyEmailDisabled() {
|
||||
throw new errors_1.AppError('Email verification resend via Clerk has been removed from this project.', 410, 'disabled');
|
||||
}
|
||||
//# sourceMappingURL=auth.company.service.js.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"auth.company.service.js","sourceRoot":"","sources":["../../../src/modules/auth/auth.company.service.ts"],"names":[],"mappings":"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"}
|
||||
@@ -0,0 +1,9 @@
|
||||
export declare function findEmployeeWithCompanyById(id: string): any;
|
||||
export declare function findEmployeeById(id: string): any;
|
||||
export declare function findEmployeeWithCompanyByEmail(email: string): any;
|
||||
export declare function findActiveEmployeeByEmail(email: string): any;
|
||||
export declare function setPasswordResetToken(id: string, passwordResetToken: string, passwordResetExpiresAt: Date): any;
|
||||
export declare function updatePreferredLanguage(id: string, preferredLanguage: 'en' | 'fr' | 'ar'): any;
|
||||
export declare function findEmployeeByResetToken(token: string): any;
|
||||
export declare function resetPassword(id: string, passwordHash: string): any;
|
||||
//# sourceMappingURL=auth.employee.repo.d.ts.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"auth.employee.repo.d.ts","sourceRoot":"","sources":["../../../src/modules/auth/auth.employee.repo.ts"],"names":[],"mappings":"AAEA,wBAAgB,2BAA2B,CAAC,EAAE,EAAE,MAAM,OAKrD;AAED,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,MAAM,OAI1C;AAED,wBAAgB,8BAA8B,CAAC,KAAK,EAAE,MAAM,OAU3D;AAED,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,MAAM,OAUtD;AAED,wBAAgB,qBAAqB,CAAC,EAAE,EAAE,MAAM,EAAE,kBAAkB,EAAE,MAAM,EAAE,sBAAsB,EAAE,IAAI,OAKzG;AAED,wBAAgB,uBAAuB,CAAC,EAAE,EAAE,MAAM,EAAE,iBAAiB,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,OAKxF;AAED,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,MAAM,OAOrD;AAED,wBAAgB,aAAa,CAAC,EAAE,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,OAS7D"}
|
||||
@@ -0,0 +1,75 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.findEmployeeWithCompanyById = findEmployeeWithCompanyById;
|
||||
exports.findEmployeeById = findEmployeeById;
|
||||
exports.findEmployeeWithCompanyByEmail = findEmployeeWithCompanyByEmail;
|
||||
exports.findActiveEmployeeByEmail = findActiveEmployeeByEmail;
|
||||
exports.setPasswordResetToken = setPasswordResetToken;
|
||||
exports.updatePreferredLanguage = updatePreferredLanguage;
|
||||
exports.findEmployeeByResetToken = findEmployeeByResetToken;
|
||||
exports.resetPassword = resetPassword;
|
||||
const prisma_1 = require("../../lib/prisma");
|
||||
function findEmployeeWithCompanyById(id) {
|
||||
return prisma_1.prisma.employee.findUnique({
|
||||
where: { id },
|
||||
include: { company: true },
|
||||
});
|
||||
}
|
||||
function findEmployeeById(id) {
|
||||
return prisma_1.prisma.employee.findUnique({
|
||||
where: { id },
|
||||
});
|
||||
}
|
||||
function findEmployeeWithCompanyByEmail(email) {
|
||||
return prisma_1.prisma.employee.findFirst({
|
||||
where: {
|
||||
email: {
|
||||
equals: email,
|
||||
mode: 'insensitive',
|
||||
},
|
||||
},
|
||||
include: { company: true },
|
||||
});
|
||||
}
|
||||
function findActiveEmployeeByEmail(email) {
|
||||
return prisma_1.prisma.employee.findFirst({
|
||||
where: {
|
||||
email: {
|
||||
equals: email,
|
||||
mode: 'insensitive',
|
||||
},
|
||||
isActive: true,
|
||||
},
|
||||
});
|
||||
}
|
||||
function setPasswordResetToken(id, passwordResetToken, passwordResetExpiresAt) {
|
||||
return prisma_1.prisma.employee.update({
|
||||
where: { id },
|
||||
data: { passwordResetToken, passwordResetExpiresAt },
|
||||
});
|
||||
}
|
||||
function updatePreferredLanguage(id, preferredLanguage) {
|
||||
return prisma_1.prisma.employee.update({
|
||||
where: { id },
|
||||
data: { preferredLanguage },
|
||||
});
|
||||
}
|
||||
function findEmployeeByResetToken(token) {
|
||||
return prisma_1.prisma.employee.findFirst({
|
||||
where: {
|
||||
passwordResetToken: token,
|
||||
passwordResetExpiresAt: { gt: new Date() },
|
||||
},
|
||||
});
|
||||
}
|
||||
function resetPassword(id, passwordHash) {
|
||||
return prisma_1.prisma.employee.update({
|
||||
where: { id },
|
||||
data: {
|
||||
passwordHash,
|
||||
passwordResetToken: null,
|
||||
passwordResetExpiresAt: null,
|
||||
},
|
||||
});
|
||||
}
|
||||
//# sourceMappingURL=auth.employee.repo.js.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"auth.employee.repo.js","sourceRoot":"","sources":["../../../src/modules/auth/auth.employee.repo.ts"],"names":[],"mappings":";;AAEA,kEAKC;AAED,4CAIC;AAED,wEAUC;AAED,8DAUC;AAED,sDAKC;AAED,0DAKC;AAED,4DAOC;AAED,sCASC;AAvED,6CAAyC;AAEzC,SAAgB,2BAA2B,CAAC,EAAU;IACpD,OAAO,eAAM,CAAC,QAAQ,CAAC,UAAU,CAAC;QAChC,KAAK,EAAE,EAAE,EAAE,EAAE;QACb,OAAO,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE;KAC3B,CAAC,CAAA;AACJ,CAAC;AAED,SAAgB,gBAAgB,CAAC,EAAU;IACzC,OAAO,eAAM,CAAC,QAAQ,CAAC,UAAU,CAAC;QAChC,KAAK,EAAE,EAAE,EAAE,EAAE;KACd,CAAC,CAAA;AACJ,CAAC;AAED,SAAgB,8BAA8B,CAAC,KAAa;IAC1D,OAAO,eAAM,CAAC,QAAQ,CAAC,SAAS,CAAC;QAC/B,KAAK,EAAE;YACL,KAAK,EAAE;gBACL,MAAM,EAAE,KAAK;gBACb,IAAI,EAAE,aAAa;aACpB;SACF;QACD,OAAO,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE;KAC3B,CAAC,CAAA;AACJ,CAAC;AAED,SAAgB,yBAAyB,CAAC,KAAa;IACrD,OAAO,eAAM,CAAC,QAAQ,CAAC,SAAS,CAAC;QAC/B,KAAK,EAAE;YACL,KAAK,EAAE;gBACL,MAAM,EAAE,KAAK;gBACb,IAAI,EAAE,aAAa;aACpB;YACD,QAAQ,EAAE,IAAI;SACf;KACF,CAAC,CAAA;AACJ,CAAC;AAED,SAAgB,qBAAqB,CAAC,EAAU,EAAE,kBAA0B,EAAE,sBAA4B;IACxG,OAAO,eAAM,CAAC,QAAQ,CAAC,MAAM,CAAC;QAC5B,KAAK,EAAE,EAAE,EAAE,EAAE;QACb,IAAI,EAAE,EAAE,kBAAkB,EAAE,sBAAsB,EAAE;KACrD,CAAC,CAAA;AACJ,CAAC;AAED,SAAgB,uBAAuB,CAAC,EAAU,EAAE,iBAAqC;IACvF,OAAO,eAAM,CAAC,QAAQ,CAAC,MAAM,CAAC;QAC5B,KAAK,EAAE,EAAE,EAAE,EAAE;QACb,IAAI,EAAE,EAAE,iBAAiB,EAAE;KAC5B,CAAC,CAAA;AACJ,CAAC;AAED,SAAgB,wBAAwB,CAAC,KAAa;IACpD,OAAO,eAAM,CAAC,QAAQ,CAAC,SAAS,CAAC;QAC/B,KAAK,EAAE;YACL,kBAAkB,EAAE,KAAK;YACzB,sBAAsB,EAAE,EAAE,EAAE,EAAE,IAAI,IAAI,EAAE,EAAE;SAC3C;KACF,CAAC,CAAA;AACJ,CAAC;AAED,SAAgB,aAAa,CAAC,EAAU,EAAE,YAAoB;IAC5D,OAAO,eAAM,CAAC,QAAQ,CAAC,MAAM,CAAC;QAC5B,KAAK,EAAE,EAAE,EAAE,EAAE;QACb,IAAI,EAAE;YACJ,YAAY;YACZ,kBAAkB,EAAE,IAAI;YACxB,sBAAsB,EAAE,IAAI;SAC7B;KACF,CAAC,CAAA;AACJ,CAAC"}
|
||||
@@ -0,0 +1,3 @@
|
||||
declare const router: import("express-serve-static-core").Router;
|
||||
export default router;
|
||||
//# sourceMappingURL=auth.employee.routes.d.ts.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"auth.employee.routes.d.ts","sourceRoot":"","sources":["../../../src/modules/auth/auth.employee.routes.ts"],"names":[],"mappings":"AAcA,QAAA,MAAM,MAAM,4CAAW,CAAA;AAiDvB,eAAe,MAAM,CAAA"}
|
||||
+105
@@ -0,0 +1,105 @@
|
||||
"use strict";
|
||||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
var desc = Object.getOwnPropertyDescriptor(m, k);
|
||||
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
||||
desc = { enumerable: true, get: function() { return m[k]; } };
|
||||
}
|
||||
Object.defineProperty(o, k2, desc);
|
||||
}) : (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
o[k2] = m[k];
|
||||
}));
|
||||
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
||||
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
||||
}) : function(o, v) {
|
||||
o["default"] = v;
|
||||
});
|
||||
var __importStar = (this && this.__importStar) || (function () {
|
||||
var ownKeys = function(o) {
|
||||
ownKeys = Object.getOwnPropertyNames || function (o) {
|
||||
var ar = [];
|
||||
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
||||
return ar;
|
||||
};
|
||||
return ownKeys(o);
|
||||
};
|
||||
return function (mod) {
|
||||
if (mod && mod.__esModule) return mod;
|
||||
var result = {};
|
||||
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
||||
__setModuleDefault(result, mod);
|
||||
return result;
|
||||
};
|
||||
})();
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const express_1 = require("express");
|
||||
const requireCompanyAuth_1 = require("../../middleware/requireCompanyAuth");
|
||||
const validate_1 = require("../../http/validate");
|
||||
const respond_1 = require("../../http/respond");
|
||||
const sessionCookies_1 = require("../../security/sessionCookies");
|
||||
const menu_service_1 = require("../menu/menu.service");
|
||||
const auth_employee_schemas_1 = require("./auth.employee.schemas");
|
||||
const service = __importStar(require("./auth.employee.service"));
|
||||
const router = (0, express_1.Router)();
|
||||
router.get('/me', requireCompanyAuth_1.requireCompanyAuth, async (req, res, next) => {
|
||||
try {
|
||||
(0, respond_1.ok)(res, await service.getMe(req.employee.id));
|
||||
}
|
||||
catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
router.get('/menu', requireCompanyAuth_1.requireCompanyAuth, async (req, res, next) => {
|
||||
try {
|
||||
(0, respond_1.ok)(res, await (0, menu_service_1.getEmployeeMenu)(req.employee.id));
|
||||
}
|
||||
catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
router.post('/login', async (req, res, next) => {
|
||||
try {
|
||||
const body = (0, validate_1.parseBody)(auth_employee_schemas_1.employeeLoginSchema, req);
|
||||
const result = await service.login(body);
|
||||
if ('token' in result)
|
||||
(0, sessionCookies_1.setSessionCookie)(res, 'employee', result.token, 8 * 60 * 60 * 1000);
|
||||
(0, respond_1.ok)(res, result);
|
||||
}
|
||||
catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
router.post('/logout', (_req, res) => {
|
||||
(0, sessionCookies_1.clearSessionCookie)(res, 'employee');
|
||||
(0, respond_1.ok)(res, { success: true });
|
||||
});
|
||||
router.post('/forgot-password', async (req, res, next) => {
|
||||
try {
|
||||
const { email } = (0, validate_1.parseBody)(auth_employee_schemas_1.employeeForgotPasswordSchema, req);
|
||||
(0, respond_1.ok)(res, await service.forgotPassword(email));
|
||||
}
|
||||
catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
router.patch('/me/language', requireCompanyAuth_1.requireCompanyAuth, async (req, res, next) => {
|
||||
try {
|
||||
const { language } = (0, validate_1.parseBody)(auth_employee_schemas_1.employeeLanguageSchema, req);
|
||||
(0, respond_1.ok)(res, await service.updateLanguage(req.employee.id, language));
|
||||
}
|
||||
catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
router.post('/reset-password', async (req, res, next) => {
|
||||
try {
|
||||
const { token, password } = (0, validate_1.parseBody)(auth_employee_schemas_1.employeeResetPasswordSchema, req);
|
||||
(0, respond_1.ok)(res, await service.resetPassword(token, password));
|
||||
}
|
||||
catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
exports.default = router;
|
||||
//# sourceMappingURL=auth.employee.routes.js.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"auth.employee.routes.js","sourceRoot":"","sources":["../../../src/modules/auth/auth.employee.routes.ts"],"names":[],"mappings":"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"}
|
||||
@@ -0,0 +1,36 @@
|
||||
import { z } from 'zod';
|
||||
export declare const employeeLoginSchema: z.ZodObject<{
|
||||
email: z.ZodString;
|
||||
password: z.ZodString;
|
||||
}, "strip", z.ZodTypeAny, {
|
||||
email: string;
|
||||
password: string;
|
||||
}, {
|
||||
email: string;
|
||||
password: string;
|
||||
}>;
|
||||
export declare const employeeForgotPasswordSchema: z.ZodObject<{
|
||||
email: z.ZodString;
|
||||
}, "strip", z.ZodTypeAny, {
|
||||
email: string;
|
||||
}, {
|
||||
email: string;
|
||||
}>;
|
||||
export declare const employeeLanguageSchema: z.ZodObject<{
|
||||
language: z.ZodEnum<["en", "fr", "ar"]>;
|
||||
}, "strip", z.ZodTypeAny, {
|
||||
language: "en" | "fr" | "ar";
|
||||
}, {
|
||||
language: "en" | "fr" | "ar";
|
||||
}>;
|
||||
export declare const employeeResetPasswordSchema: z.ZodObject<{
|
||||
token: z.ZodString;
|
||||
password: z.ZodString;
|
||||
}, "strip", z.ZodTypeAny, {
|
||||
password: string;
|
||||
token: string;
|
||||
}, {
|
||||
password: string;
|
||||
token: string;
|
||||
}>;
|
||||
//# sourceMappingURL=auth.employee.schemas.d.ts.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"auth.employee.schemas.d.ts","sourceRoot":"","sources":["../../../src/modules/auth/auth.employee.schemas.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAEvB,eAAO,MAAM,mBAAmB;;;;;;;;;EAG9B,CAAA;AAEF,eAAO,MAAM,4BAA4B;;;;;;EAEvC,CAAA;AAEF,eAAO,MAAM,sBAAsB;;;;;;EAEjC,CAAA;AAEF,eAAO,MAAM,2BAA2B;;;;;;;;;EAGtC,CAAA"}
|
||||
@@ -0,0 +1,19 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.employeeResetPasswordSchema = exports.employeeLanguageSchema = exports.employeeForgotPasswordSchema = exports.employeeLoginSchema = void 0;
|
||||
const zod_1 = require("zod");
|
||||
exports.employeeLoginSchema = zod_1.z.object({
|
||||
email: zod_1.z.string().email().max(255).trim().toLowerCase(),
|
||||
password: zod_1.z.string().max(128),
|
||||
});
|
||||
exports.employeeForgotPasswordSchema = zod_1.z.object({
|
||||
email: zod_1.z.string().email().max(255).trim().toLowerCase(),
|
||||
});
|
||||
exports.employeeLanguageSchema = zod_1.z.object({
|
||||
language: zod_1.z.enum(['en', 'fr', 'ar']),
|
||||
});
|
||||
exports.employeeResetPasswordSchema = zod_1.z.object({
|
||||
token: zod_1.z.string().min(1),
|
||||
password: zod_1.z.string().min(8).max(128),
|
||||
});
|
||||
//# sourceMappingURL=auth.employee.schemas.js.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"auth.employee.schemas.js","sourceRoot":"","sources":["../../../src/modules/auth/auth.employee.schemas.ts"],"names":[],"mappings":";;;AAAA,6BAAuB;AAEV,QAAA,mBAAmB,GAAG,OAAC,CAAC,MAAM,CAAC;IAC1C,KAAK,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE;IACvD,QAAQ,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC;CAC9B,CAAC,CAAA;AAEW,QAAA,4BAA4B,GAAG,OAAC,CAAC,MAAM,CAAC;IACnD,KAAK,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE;CACxD,CAAC,CAAA;AAEW,QAAA,sBAAsB,GAAG,OAAC,CAAC,MAAM,CAAC;IAC7C,QAAQ,EAAE,OAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;CACrC,CAAC,CAAA;AAEW,QAAA,2BAA2B,GAAG,OAAC,CAAC,MAAM,CAAC;IAClD,KAAK,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IACxB,QAAQ,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC;CACrC,CAAC,CAAA"}
|
||||
@@ -0,0 +1,67 @@
|
||||
import { employeeLanguageSchema, employeeLoginSchema } from './auth.employee.schemas';
|
||||
import type { output } from 'zod';
|
||||
type EmployeeLoginInput = output<typeof employeeLoginSchema>;
|
||||
type EmployeeLanguageInput = output<typeof employeeLanguageSchema>;
|
||||
export declare function getMe(employeeId: string): Promise<{
|
||||
employee: {
|
||||
id: string;
|
||||
email: string;
|
||||
firstName: string;
|
||||
lastName: string;
|
||||
role: string;
|
||||
preferredLanguage: string | null | undefined;
|
||||
companyId: string;
|
||||
companyName: string;
|
||||
companySlug: string;
|
||||
};
|
||||
} | {
|
||||
employee: {
|
||||
id: string;
|
||||
email: string;
|
||||
firstName: string;
|
||||
lastName: string;
|
||||
role: string;
|
||||
preferredLanguage: string | null | undefined;
|
||||
companyId: string;
|
||||
companyName: string;
|
||||
companySlug: string;
|
||||
};
|
||||
token: string;
|
||||
}>;
|
||||
export declare function login(body: EmployeeLoginInput): Promise<{
|
||||
employee: {
|
||||
id: string;
|
||||
email: string;
|
||||
firstName: string;
|
||||
lastName: string;
|
||||
role: string;
|
||||
preferredLanguage: string | null | undefined;
|
||||
companyId: string;
|
||||
companyName: string;
|
||||
companySlug: string;
|
||||
};
|
||||
} | {
|
||||
employee: {
|
||||
id: string;
|
||||
email: string;
|
||||
firstName: string;
|
||||
lastName: string;
|
||||
role: string;
|
||||
preferredLanguage: string | null | undefined;
|
||||
companyId: string;
|
||||
companyName: string;
|
||||
companySlug: string;
|
||||
};
|
||||
token: string;
|
||||
}>;
|
||||
export declare function forgotPassword(email: string): Promise<{
|
||||
message: string;
|
||||
}>;
|
||||
export declare function updateLanguage(employeeId: string, language: EmployeeLanguageInput['language']): Promise<{
|
||||
language: "en" | "fr" | "ar";
|
||||
}>;
|
||||
export declare function resetPassword(token: string, password: string): Promise<{
|
||||
message: string;
|
||||
}>;
|
||||
export {};
|
||||
//# sourceMappingURL=auth.employee.service.d.ts.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"auth.employee.service.d.ts","sourceRoot":"","sources":["../../../src/modules/auth/auth.employee.service.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,sBAAsB,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAA;AACrF,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,KAAK,CAAA;AAIjC,KAAK,kBAAkB,GAAG,MAAM,CAAC,OAAO,mBAAmB,CAAC,CAAA;AAC5D,KAAK,qBAAqB,GAAG,MAAM,CAAC,OAAO,sBAAsB,CAAC,CAAA;AAuElE,wBAAsB,KAAK,CAAC,UAAU,EAAE,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;GAQ7C;AAED,wBAAsB,KAAK,CAAC,IAAI,EAAE,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;GAiBnD;AAED,wBAAsB,cAAc,CAAC,KAAK,EAAE,MAAM;;GAwBjD;AAED,wBAAsB,cAAc,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,qBAAqB,CAAC,UAAU,CAAC;;GAGnG;AAuBD,wBAAsB,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM;;GASlE"}
|
||||
+180
@@ -0,0 +1,180 @@
|
||||
"use strict";
|
||||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
var desc = Object.getOwnPropertyDescriptor(m, k);
|
||||
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
||||
desc = { enumerable: true, get: function() { return m[k]; } };
|
||||
}
|
||||
Object.defineProperty(o, k2, desc);
|
||||
}) : (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
o[k2] = m[k];
|
||||
}));
|
||||
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
||||
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
||||
}) : function(o, v) {
|
||||
o["default"] = v;
|
||||
});
|
||||
var __importStar = (this && this.__importStar) || (function () {
|
||||
var ownKeys = function(o) {
|
||||
ownKeys = Object.getOwnPropertyNames || function (o) {
|
||||
var ar = [];
|
||||
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
||||
return ar;
|
||||
};
|
||||
return ownKeys(o);
|
||||
};
|
||||
return function (mod) {
|
||||
if (mod && mod.__esModule) return mod;
|
||||
var result = {};
|
||||
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
||||
__setModuleDefault(result, mod);
|
||||
return result;
|
||||
};
|
||||
})();
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.getMe = getMe;
|
||||
exports.login = login;
|
||||
exports.forgotPassword = forgotPassword;
|
||||
exports.updateLanguage = updateLanguage;
|
||||
exports.resetPassword = resetPassword;
|
||||
const bcryptjs_1 = __importDefault(require("bcryptjs"));
|
||||
const crypto_1 = __importDefault(require("crypto"));
|
||||
const jsonwebtoken_1 = __importDefault(require("jsonwebtoken"));
|
||||
const tokens_1 = require("../../security/tokens");
|
||||
const errors_1 = require("../../http/errors");
|
||||
const notificationService_1 = require("../../services/notificationService");
|
||||
const emailTranslations_1 = require("../../lib/emailTranslations");
|
||||
const auth_presenter_1 = require("./auth.presenter");
|
||||
const repo = __importStar(require("./auth.employee.repo"));
|
||||
const RESET_TOKEN_TTL_MINUTES = 60;
|
||||
function signEmployeeToken(employeeId) {
|
||||
return (0, tokens_1.signActorToken)(employeeId, 'employee', {
|
||||
expiresIn: (process.env.JWT_EXPIRY ?? '8h'),
|
||||
});
|
||||
}
|
||||
function getEmployeePasswordResetVersion(passwordHash) {
|
||||
return crypto_1.default
|
||||
.createHash('sha256')
|
||||
.update(`${process.env.JWT_SECRET}:${passwordHash ?? 'no-password-set'}`)
|
||||
.digest('hex');
|
||||
}
|
||||
function signEmployeePasswordResetToken(employeeId, passwordHash) {
|
||||
return jsonwebtoken_1.default.sign({
|
||||
sub: employeeId,
|
||||
type: 'employee_password_reset',
|
||||
pwdv: getEmployeePasswordResetVersion(passwordHash),
|
||||
}, process.env.JWT_SECRET, {
|
||||
algorithm: 'HS256',
|
||||
issuer: 'rentaldrivego-api',
|
||||
audience: 'employee_password_reset',
|
||||
expiresIn: `${RESET_TOKEN_TTL_MINUTES}m`,
|
||||
});
|
||||
}
|
||||
function verifyEmployeePasswordResetToken(token) {
|
||||
try {
|
||||
const payload = jsonwebtoken_1.default.verify(token, process.env.JWT_SECRET, {
|
||||
algorithms: ['HS256'],
|
||||
issuer: 'rentaldrivego-api',
|
||||
audience: 'employee_password_reset',
|
||||
});
|
||||
if (typeof payload.sub !== 'string' ||
|
||||
payload.type !== 'employee_password_reset' ||
|
||||
typeof payload.pwdv !== 'string') {
|
||||
return null;
|
||||
}
|
||||
return payload;
|
||||
}
|
||||
catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
function ensureDashboardBasePath(baseUrl) {
|
||||
try {
|
||||
const url = new URL(baseUrl);
|
||||
const pathname = url.pathname.replace(/\/$/, '');
|
||||
if (!pathname.endsWith('/dashboard'))
|
||||
url.pathname = `${pathname}/dashboard`;
|
||||
return url.toString().replace(/\/$/, '');
|
||||
}
|
||||
catch {
|
||||
const trimmed = baseUrl.replace(/\/$/, '');
|
||||
return trimmed.endsWith('/dashboard') ? trimmed : `${trimmed}/dashboard`;
|
||||
}
|
||||
}
|
||||
async function getMe(employeeId) {
|
||||
const employee = await repo.findEmployeeWithCompanyById(employeeId);
|
||||
if (!employee || !employee.isActive) {
|
||||
throw new errors_1.AppError('Employee account not found or inactive', 401, 'unauthenticated');
|
||||
}
|
||||
return (0, auth_presenter_1.presentEmployeeSession)(employee);
|
||||
}
|
||||
async function login(body) {
|
||||
const employee = await repo.findEmployeeWithCompanyByEmail(body.email);
|
||||
if (!employee || !employee.isActive) {
|
||||
throw new errors_1.AppError('Invalid email or password', 401, 'invalid_credentials');
|
||||
}
|
||||
if (!employee.passwordHash) {
|
||||
throw new errors_1.AppError('This account does not have a password yet. Use the invitation or reset email to set one first.', 401, 'password_not_set');
|
||||
}
|
||||
const validPassword = await bcryptjs_1.default.compare(body.password, employee.passwordHash);
|
||||
if (!validPassword) {
|
||||
throw new errors_1.AppError('Invalid email or password', 401, 'invalid_credentials');
|
||||
}
|
||||
return (0, auth_presenter_1.presentEmployeeSession)(employee, signEmployeeToken(employee.id));
|
||||
}
|
||||
async function forgotPassword(email) {
|
||||
const employee = await repo.findActiveEmployeeByEmail(email);
|
||||
if (employee) {
|
||||
const resetToken = signEmployeePasswordResetToken(employee.id, employee.passwordHash);
|
||||
const dashboardUrl = ensureDashboardBasePath(process.env.DASHBOARD_URL ?? process.env.NEXT_PUBLIC_DASHBOARD_URL ?? 'http://localhost:3000/dashboard');
|
||||
const resetUrl = `${dashboardUrl}/reset-password?token=${encodeURIComponent(resetToken)}`;
|
||||
const lang = employee.preferredLanguage ?? 'fr';
|
||||
await (0, notificationService_1.sendTransactionalEmail)({
|
||||
to: employee.email,
|
||||
subject: emailTranslations_1.resetPasswordEmail.subject(lang),
|
||||
html: emailTranslations_1.resetPasswordEmail.html(resetUrl, employee.firstName, RESET_TOKEN_TTL_MINUTES, lang),
|
||||
text: emailTranslations_1.resetPasswordEmail.text(resetUrl, employee.firstName, RESET_TOKEN_TTL_MINUTES, lang),
|
||||
}).catch((err) => {
|
||||
console.error('[ForgotPassword] Email delivery failed:', err?.message);
|
||||
console.error('[ForgotPassword] Provider config — resendKey present:', !!process.env.RESEND_API_KEY, '| smtpHost:', process.env.MAIL_HOST ?? 'not set');
|
||||
});
|
||||
}
|
||||
return { message: 'If that email is registered, a reset link has been sent.' };
|
||||
}
|
||||
async function updateLanguage(employeeId, language) {
|
||||
await repo.updatePreferredLanguage(employeeId, language);
|
||||
return { language };
|
||||
}
|
||||
async function findEmployeeFromResetToken(token) {
|
||||
try {
|
||||
const employee = await repo.findEmployeeByResetToken(token);
|
||||
if (employee)
|
||||
return employee;
|
||||
}
|
||||
catch (err) {
|
||||
console.error('[EmployeeResetPassword] Stored token lookup failed:', err?.message ?? String(err));
|
||||
}
|
||||
const payload = verifyEmployeePasswordResetToken(token);
|
||||
if (!payload)
|
||||
return null;
|
||||
const employee = await repo.findEmployeeById(payload.sub);
|
||||
if (!employee || !employee.isActive)
|
||||
return null;
|
||||
if (payload.pwdv !== getEmployeePasswordResetVersion(employee.passwordHash)) {
|
||||
return null;
|
||||
}
|
||||
return employee;
|
||||
}
|
||||
async function resetPassword(token, password) {
|
||||
const employee = await findEmployeeFromResetToken(token);
|
||||
if (!employee) {
|
||||
throw new errors_1.AppError('Reset link is invalid or has expired.', 400, 'invalid_token');
|
||||
}
|
||||
await repo.resetPassword(employee.id, await bcryptjs_1.default.hash(password, 12));
|
||||
return { message: 'Password updated successfully. You can now sign in.' };
|
||||
}
|
||||
//# sourceMappingURL=auth.employee.service.js.map
|
||||
File diff suppressed because one or more lines are too long
+98
@@ -0,0 +1,98 @@
|
||||
type EmployeeWithCompany = {
|
||||
id: string;
|
||||
email: string;
|
||||
firstName: string;
|
||||
lastName: string;
|
||||
role: string;
|
||||
preferredLanguage?: string | null;
|
||||
companyId: string;
|
||||
company: {
|
||||
name: string;
|
||||
slug: string;
|
||||
};
|
||||
};
|
||||
type CompanySignupResult = {
|
||||
company: {
|
||||
id: string;
|
||||
name: string;
|
||||
slug: string;
|
||||
};
|
||||
trialEndAt: Date;
|
||||
emailDelivery?: unknown;
|
||||
};
|
||||
type RenterProfile = {
|
||||
id: string;
|
||||
firstName: string;
|
||||
lastName: string;
|
||||
email: string;
|
||||
phone: string | null;
|
||||
preferredLocale: string | null;
|
||||
preferredCurrency: string | null;
|
||||
emailVerified: boolean;
|
||||
savedCompanies: Array<{
|
||||
companyId: string;
|
||||
}>;
|
||||
};
|
||||
type SavedCompany = {
|
||||
id: string;
|
||||
brand: {
|
||||
displayName: string | null;
|
||||
subdomain: string | null;
|
||||
logoUrl: string | null;
|
||||
} | null;
|
||||
};
|
||||
export declare function presentEmployeeSession(employee: EmployeeWithCompany, token?: string): {
|
||||
employee: {
|
||||
id: string;
|
||||
email: string;
|
||||
firstName: string;
|
||||
lastName: string;
|
||||
role: string;
|
||||
preferredLanguage: string | null | undefined;
|
||||
companyId: string;
|
||||
companyName: string;
|
||||
companySlug: string;
|
||||
};
|
||||
} | {
|
||||
employee: {
|
||||
id: string;
|
||||
email: string;
|
||||
firstName: string;
|
||||
lastName: string;
|
||||
role: string;
|
||||
preferredLanguage: string | null | undefined;
|
||||
companyId: string;
|
||||
companyName: string;
|
||||
companySlug: string;
|
||||
};
|
||||
token: string;
|
||||
};
|
||||
export declare function presentCompanySignup(result: CompanySignupResult): {
|
||||
companyId: string;
|
||||
companyName: string;
|
||||
slug: string;
|
||||
invitationId: null;
|
||||
trialEndsAt: string;
|
||||
nextStep: string;
|
||||
emailDelivery: {};
|
||||
};
|
||||
export declare function presentRenterProfile(renter: RenterProfile, companies: SavedCompany[]): {
|
||||
savedCompanies: {
|
||||
id: string;
|
||||
brand: {
|
||||
displayName: string | null;
|
||||
subdomain: string | null;
|
||||
logoUrl: string | null;
|
||||
} | null;
|
||||
}[];
|
||||
id: string;
|
||||
firstName: string;
|
||||
lastName: string;
|
||||
email: string;
|
||||
phone: string | null;
|
||||
preferredLocale: string | null;
|
||||
preferredCurrency: string | null;
|
||||
emailVerified: boolean;
|
||||
};
|
||||
export {};
|
||||
//# sourceMappingURL=auth.presenter.d.ts.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"auth.presenter.d.ts","sourceRoot":"","sources":["../../../src/modules/auth/auth.presenter.ts"],"names":[],"mappings":"AAAA,KAAK,mBAAmB,GAAG;IACzB,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,MAAM,CAAA;IACb,SAAS,EAAE,MAAM,CAAA;IACjB,QAAQ,EAAE,MAAM,CAAA;IAChB,IAAI,EAAE,MAAM,CAAA;IACZ,iBAAiB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACjC,SAAS,EAAE,MAAM,CAAA;IACjB,OAAO,EAAE;QACP,IAAI,EAAE,MAAM,CAAA;QACZ,IAAI,EAAE,MAAM,CAAA;KACb,CAAA;CACF,CAAA;AAED,KAAK,mBAAmB,GAAG;IACzB,OAAO,EAAE;QACP,EAAE,EAAE,MAAM,CAAA;QACV,IAAI,EAAE,MAAM,CAAA;QACZ,IAAI,EAAE,MAAM,CAAA;KACb,CAAA;IACD,UAAU,EAAE,IAAI,CAAA;IAChB,aAAa,CAAC,EAAE,OAAO,CAAA;CACxB,CAAA;AAED,KAAK,aAAa,GAAG;IACnB,EAAE,EAAE,MAAM,CAAA;IACV,SAAS,EAAE,MAAM,CAAA;IACjB,QAAQ,EAAE,MAAM,CAAA;IAChB,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,eAAe,EAAE,MAAM,GAAG,IAAI,CAAA;IAC9B,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAA;IAChC,aAAa,EAAE,OAAO,CAAA;IACtB,cAAc,EAAE,KAAK,CAAC;QAAE,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CAC7C,CAAA;AAED,KAAK,YAAY,GAAG;IAClB,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE;QACL,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;QAC1B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;QACxB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;KACvB,GAAG,IAAI,CAAA;CACT,CAAA;AAED,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,mBAAmB,EAAE,KAAK,CAAC,EAAE,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;EAgBnF;AAED,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,mBAAmB;;;;;;;;EAU/D;AAED,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,aAAa,EAAE,SAAS,EAAE,YAAY,EAAE;;;;yBApCpE,MAAM,GAAG,IAAI;uBACf,MAAM,GAAG,IAAI;qBACf,MAAM,GAAG,IAAI;;;QAhBpB,MAAM;eACC,MAAM;cACP,MAAM;WACT,MAAM;WACN,MAAM,GAAG,IAAI;qBACH,MAAM,GAAG,IAAI;uBACX,MAAM,GAAG,IAAI;mBACjB,OAAO;EAqDvB"}
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.presentEmployeeSession = presentEmployeeSession;
|
||||
exports.presentCompanySignup = presentCompanySignup;
|
||||
exports.presentRenterProfile = presentRenterProfile;
|
||||
function presentEmployeeSession(employee, token) {
|
||||
const data = {
|
||||
employee: {
|
||||
id: employee.id,
|
||||
email: employee.email,
|
||||
firstName: employee.firstName,
|
||||
lastName: employee.lastName,
|
||||
role: employee.role,
|
||||
preferredLanguage: employee.preferredLanguage,
|
||||
companyId: employee.companyId,
|
||||
companyName: employee.company.name,
|
||||
companySlug: employee.company.slug,
|
||||
},
|
||||
};
|
||||
return token ? { token, ...data } : data;
|
||||
}
|
||||
function presentCompanySignup(result) {
|
||||
return {
|
||||
companyId: result.company.id,
|
||||
companyName: result.company.name,
|
||||
slug: result.company.slug,
|
||||
invitationId: null,
|
||||
trialEndsAt: result.trialEndAt.toISOString(),
|
||||
nextStep: 'workspace_created',
|
||||
emailDelivery: result.emailDelivery ?? { attempted: false, success: false, error: null },
|
||||
};
|
||||
}
|
||||
function presentRenterProfile(renter, companies) {
|
||||
const companyMap = new Map(companies.map((company) => [company.id, company]));
|
||||
return {
|
||||
...renter,
|
||||
savedCompanies: renter.savedCompanies.map((savedCompany) => ({
|
||||
id: savedCompany.companyId,
|
||||
brand: companyMap.get(savedCompany.companyId)?.brand ?? null,
|
||||
})),
|
||||
};
|
||||
}
|
||||
//# sourceMappingURL=auth.presenter.js.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"auth.presenter.js","sourceRoot":"","sources":["../../../src/modules/auth/auth.presenter.ts"],"names":[],"mappings":";;AA6CA,wDAgBC;AAED,oDAUC;AAED,oDAUC;AAxCD,SAAgB,sBAAsB,CAAC,QAA6B,EAAE,KAAc;IAClF,MAAM,IAAI,GAAG;QACX,QAAQ,EAAE;YACR,EAAE,EAAE,QAAQ,CAAC,EAAE;YACf,KAAK,EAAE,QAAQ,CAAC,KAAK;YACrB,SAAS,EAAE,QAAQ,CAAC,SAAS;YAC7B,QAAQ,EAAE,QAAQ,CAAC,QAAQ;YAC3B,IAAI,EAAE,QAAQ,CAAC,IAAI;YACnB,iBAAiB,EAAE,QAAQ,CAAC,iBAAiB;YAC7C,SAAS,EAAE,QAAQ,CAAC,SAAS;YAC7B,WAAW,EAAE,QAAQ,CAAC,OAAO,CAAC,IAAI;YAClC,WAAW,EAAE,QAAQ,CAAC,OAAO,CAAC,IAAI;SACnC;KACF,CAAA;IAED,OAAO,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,GAAG,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAA;AAC1C,CAAC;AAED,SAAgB,oBAAoB,CAAC,MAA2B;IAC9D,OAAO;QACL,SAAS,EAAE,MAAM,CAAC,OAAO,CAAC,EAAE;QAC5B,WAAW,EAAE,MAAM,CAAC,OAAO,CAAC,IAAI;QAChC,IAAI,EAAE,MAAM,CAAC,OAAO,CAAC,IAAI;QACzB,YAAY,EAAE,IAAI;QAClB,WAAW,EAAE,MAAM,CAAC,UAAU,CAAC,WAAW,EAAE;QAC5C,QAAQ,EAAE,mBAAmB;QAC7B,aAAa,EAAE,MAAM,CAAC,aAAa,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE;KACzF,CAAA;AACH,CAAC;AAED,SAAgB,oBAAoB,CAAC,MAAqB,EAAE,SAAyB;IACnF,MAAM,UAAU,GAAG,IAAI,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC,CAAC,CAAA;IAE7E,OAAO;QACL,GAAG,MAAM;QACT,cAAc,EAAE,MAAM,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC;YAC3D,EAAE,EAAE,YAAY,CAAC,SAAS;YAC1B,KAAK,EAAE,UAAU,CAAC,GAAG,CAAC,YAAY,CAAC,SAAS,CAAC,EAAE,KAAK,IAAI,IAAI;SAC7D,CAAC,CAAC;KACJ,CAAA;AACH,CAAC"}
|
||||
@@ -0,0 +1,9 @@
|
||||
import type { output } from 'zod';
|
||||
import { renterUpdateSchema } from './auth.renter.schemas';
|
||||
type RenterUpdateInput = output<typeof renterUpdateSchema>;
|
||||
export declare function findRenterProfile(id: string): any;
|
||||
export declare function findSavedCompanies(companyIds: string[]): any;
|
||||
export declare function updateRenterProfile(id: string, data: RenterUpdateInput): any;
|
||||
export declare function updateRenterFcmToken(id: string, fcmToken: string): any;
|
||||
export {};
|
||||
//# sourceMappingURL=auth.renter.repo.d.ts.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"auth.renter.repo.d.ts","sourceRoot":"","sources":["../../../src/modules/auth/auth.renter.repo.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,KAAK,CAAA;AACjC,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAA;AAE1D,KAAK,iBAAiB,GAAG,MAAM,CAAC,OAAO,kBAAkB,CAAC,CAAA;AAE1D,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,MAAM,OAe3C;AAED,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,MAAM,EAAE,OAYtD;AAED,wBAAgB,mBAAmB,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,iBAAiB,OAKtE;AAED,wBAAgB,oBAAoB,CAAC,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,OAKhE"}
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.findRenterProfile = findRenterProfile;
|
||||
exports.findSavedCompanies = findSavedCompanies;
|
||||
exports.updateRenterProfile = updateRenterProfile;
|
||||
exports.updateRenterFcmToken = updateRenterFcmToken;
|
||||
const prisma_1 = require("../../lib/prisma");
|
||||
function findRenterProfile(id) {
|
||||
return prisma_1.prisma.renter.findUniqueOrThrow({
|
||||
where: { id },
|
||||
select: {
|
||||
id: true,
|
||||
firstName: true,
|
||||
lastName: true,
|
||||
email: true,
|
||||
phone: true,
|
||||
preferredLocale: true,
|
||||
preferredCurrency: true,
|
||||
emailVerified: true,
|
||||
savedCompanies: { select: { companyId: true } },
|
||||
},
|
||||
});
|
||||
}
|
||||
function findSavedCompanies(companyIds) {
|
||||
return companyIds.length === 0
|
||||
? Promise.resolve([])
|
||||
: prisma_1.prisma.company.findMany({
|
||||
where: { id: { in: companyIds } },
|
||||
select: {
|
||||
id: true,
|
||||
brand: {
|
||||
select: { displayName: true, subdomain: true, logoUrl: true },
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
function updateRenterProfile(id, data) {
|
||||
return prisma_1.prisma.renter.update({
|
||||
where: { id },
|
||||
data,
|
||||
});
|
||||
}
|
||||
function updateRenterFcmToken(id, fcmToken) {
|
||||
return prisma_1.prisma.renter.update({
|
||||
where: { id },
|
||||
data: { fcmToken },
|
||||
});
|
||||
}
|
||||
//# sourceMappingURL=auth.renter.repo.js.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"auth.renter.repo.js","sourceRoot":"","sources":["../../../src/modules/auth/auth.renter.repo.ts"],"names":[],"mappings":";;AAMA,8CAeC;AAED,gDAYC;AAED,kDAKC;AAED,oDAKC;AAjDD,6CAAyC;AAMzC,SAAgB,iBAAiB,CAAC,EAAU;IAC1C,OAAO,eAAM,CAAC,MAAM,CAAC,iBAAiB,CAAC;QACrC,KAAK,EAAE,EAAE,EAAE,EAAE;QACb,MAAM,EAAE;YACN,EAAE,EAAE,IAAI;YACR,SAAS,EAAE,IAAI;YACf,QAAQ,EAAE,IAAI;YACd,KAAK,EAAE,IAAI;YACX,KAAK,EAAE,IAAI;YACX,eAAe,EAAE,IAAI;YACrB,iBAAiB,EAAE,IAAI;YACvB,aAAa,EAAE,IAAI;YACnB,cAAc,EAAE,EAAE,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,EAAE;SAChD;KACF,CAAC,CAAA;AACJ,CAAC;AAED,SAAgB,kBAAkB,CAAC,UAAoB;IACrD,OAAO,UAAU,CAAC,MAAM,KAAK,CAAC;QAC5B,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;QACrB,CAAC,CAAC,eAAM,CAAC,OAAO,CAAC,QAAQ,CAAC;YACtB,KAAK,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,UAAU,EAAE,EAAE;YACjC,MAAM,EAAE;gBACN,EAAE,EAAE,IAAI;gBACR,KAAK,EAAE;oBACL,MAAM,EAAE,EAAE,WAAW,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE;iBAC9D;aACF;SACF,CAAC,CAAA;AACR,CAAC;AAED,SAAgB,mBAAmB,CAAC,EAAU,EAAE,IAAuB;IACrE,OAAO,eAAM,CAAC,MAAM,CAAC,MAAM,CAAC;QAC1B,KAAK,EAAE,EAAE,EAAE,EAAE;QACb,IAAI;KACL,CAAC,CAAA;AACJ,CAAC;AAED,SAAgB,oBAAoB,CAAC,EAAU,EAAE,QAAgB;IAC/D,OAAO,eAAM,CAAC,MAAM,CAAC,MAAM,CAAC;QAC1B,KAAK,EAAE,EAAE,EAAE,EAAE;QACb,IAAI,EAAE,EAAE,QAAQ,EAAE;KACnB,CAAC,CAAA;AACJ,CAAC"}
|
||||
@@ -0,0 +1,3 @@
|
||||
declare const router: import("express-serve-static-core").Router;
|
||||
export default router;
|
||||
//# sourceMappingURL=auth.renter.routes.d.ts.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"auth.renter.routes.d.ts","sourceRoot":"","sources":["../../../src/modules/auth/auth.renter.routes.ts"],"names":[],"mappings":"AAOA,QAAA,MAAM,MAAM,4CAAW,CAAA;AAgCvB,eAAe,MAAM,CAAA"}
|
||||
@@ -0,0 +1,78 @@
|
||||
"use strict";
|
||||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
var desc = Object.getOwnPropertyDescriptor(m, k);
|
||||
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
||||
desc = { enumerable: true, get: function() { return m[k]; } };
|
||||
}
|
||||
Object.defineProperty(o, k2, desc);
|
||||
}) : (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
o[k2] = m[k];
|
||||
}));
|
||||
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
||||
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
||||
}) : function(o, v) {
|
||||
o["default"] = v;
|
||||
});
|
||||
var __importStar = (this && this.__importStar) || (function () {
|
||||
var ownKeys = function(o) {
|
||||
ownKeys = Object.getOwnPropertyNames || function (o) {
|
||||
var ar = [];
|
||||
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
||||
return ar;
|
||||
};
|
||||
return ownKeys(o);
|
||||
};
|
||||
return function (mod) {
|
||||
if (mod && mod.__esModule) return mod;
|
||||
var result = {};
|
||||
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
||||
__setModuleDefault(result, mod);
|
||||
return result;
|
||||
};
|
||||
})();
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const express_1 = require("express");
|
||||
const requireRenterAuth_1 = require("../../middleware/requireRenterAuth");
|
||||
const validate_1 = require("../../http/validate");
|
||||
const respond_1 = require("../../http/respond");
|
||||
const auth_renter_schemas_1 = require("./auth.renter.schemas");
|
||||
const service = __importStar(require("./auth.renter.service"));
|
||||
const router = (0, express_1.Router)();
|
||||
router.post('/signup', (_req, res) => {
|
||||
service.signupDisabled();
|
||||
res.end();
|
||||
});
|
||||
router.post('/login', (_req, res) => {
|
||||
service.loginDisabled();
|
||||
res.end();
|
||||
});
|
||||
router.get('/me', requireRenterAuth_1.requireRenterAuth, async (req, res, next) => {
|
||||
try {
|
||||
(0, respond_1.ok)(res, await service.getMe(req.renterId));
|
||||
}
|
||||
catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
router.patch('/me', requireRenterAuth_1.requireRenterAuth, async (req, res, next) => {
|
||||
try {
|
||||
const body = (0, validate_1.parseBody)(auth_renter_schemas_1.renterUpdateSchema, req);
|
||||
(0, respond_1.ok)(res, await service.updateMe(req.renterId, body));
|
||||
}
|
||||
catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
router.post('/me/fcm-token', requireRenterAuth_1.requireRenterAuth, async (req, res, next) => {
|
||||
try {
|
||||
const { fcmToken } = (0, validate_1.parseBody)(auth_renter_schemas_1.renterFcmTokenSchema, req);
|
||||
(0, respond_1.ok)(res, await service.updateFcmToken(req.renterId, fcmToken));
|
||||
}
|
||||
catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
exports.default = router;
|
||||
//# sourceMappingURL=auth.renter.routes.js.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"auth.renter.routes.js","sourceRoot":"","sources":["../../../src/modules/auth/auth.renter.routes.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,qCAAgC;AAChC,0EAAsE;AACtE,kDAA+C;AAC/C,gDAAuC;AACvC,+DAAgF;AAChF,+DAAgD;AAEhD,MAAM,MAAM,GAAG,IAAA,gBAAM,GAAE,CAAA;AAEvB,MAAM,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE;IACnC,OAAO,CAAC,cAAc,EAAE,CAAA;IACxB,GAAG,CAAC,GAAG,EAAE,CAAA;AACX,CAAC,CAAC,CAAA;AAEF,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE;IAClC,OAAO,CAAC,aAAa,EAAE,CAAA;IACvB,GAAG,CAAC,GAAG,EAAE,CAAA;AACX,CAAC,CAAC,CAAA;AAEF,MAAM,CAAC,GAAG,CAAC,KAAK,EAAE,qCAAiB,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE;IAC5D,IAAI,CAAC;QACH,IAAA,YAAE,EAAC,GAAG,EAAE,MAAM,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAA;IAC5C,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QAAC,IAAI,CAAC,GAAG,CAAC,CAAA;IAAC,CAAC;AAC7B,CAAC,CAAC,CAAA;AAEF,MAAM,CAAC,KAAK,CAAC,KAAK,EAAE,qCAAiB,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE;IAC9D,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,IAAA,oBAAS,EAAC,wCAAkB,EAAE,GAAG,CAAC,CAAA;QAC/C,IAAA,YAAE,EAAC,GAAG,EAAE,MAAM,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC,CAAA;IACrD,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QAAC,IAAI,CAAC,GAAG,CAAC,CAAA;IAAC,CAAC;AAC7B,CAAC,CAAC,CAAA;AAEF,MAAM,CAAC,IAAI,CAAC,eAAe,EAAE,qCAAiB,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE;IACvE,IAAI,CAAC;QACH,MAAM,EAAE,QAAQ,EAAE,GAAG,IAAA,oBAAS,EAAC,0CAAoB,EAAE,GAAG,CAAC,CAAA;QACzD,IAAA,YAAE,EAAC,GAAG,EAAE,MAAM,OAAO,CAAC,cAAc,CAAC,GAAG,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAA;IAC/D,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QAAC,IAAI,CAAC,GAAG,CAAC,CAAA;IAAC,CAAC;AAC7B,CAAC,CAAC,CAAA;AAEF,kBAAe,MAAM,CAAA"}
|
||||
@@ -0,0 +1,28 @@
|
||||
import { z } from 'zod';
|
||||
export declare const renterUpdateSchema: z.ZodObject<{
|
||||
firstName: z.ZodOptional<z.ZodString>;
|
||||
lastName: z.ZodOptional<z.ZodString>;
|
||||
phone: z.ZodOptional<z.ZodString>;
|
||||
preferredLocale: z.ZodOptional<z.ZodEnum<["en", "fr", "ar"]>>;
|
||||
preferredCurrency: z.ZodOptional<z.ZodLiteral<"MAD">>;
|
||||
}, "strip", z.ZodTypeAny, {
|
||||
firstName?: string | undefined;
|
||||
lastName?: string | undefined;
|
||||
phone?: string | undefined;
|
||||
preferredLocale?: "en" | "fr" | "ar" | undefined;
|
||||
preferredCurrency?: "MAD" | undefined;
|
||||
}, {
|
||||
firstName?: string | undefined;
|
||||
lastName?: string | undefined;
|
||||
phone?: string | undefined;
|
||||
preferredLocale?: "en" | "fr" | "ar" | undefined;
|
||||
preferredCurrency?: "MAD" | undefined;
|
||||
}>;
|
||||
export declare const renterFcmTokenSchema: z.ZodObject<{
|
||||
fcmToken: z.ZodString;
|
||||
}, "strip", z.ZodTypeAny, {
|
||||
fcmToken: string;
|
||||
}, {
|
||||
fcmToken: string;
|
||||
}>;
|
||||
//# sourceMappingURL=auth.renter.schemas.d.ts.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"auth.renter.schemas.d.ts","sourceRoot":"","sources":["../../../src/modules/auth/auth.renter.schemas.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAEvB,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;EAM7B,CAAA;AAEF,eAAO,MAAM,oBAAoB;;;;;;EAE/B,CAAA"}
|
||||
@@ -0,0 +1,15 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.renterFcmTokenSchema = exports.renterUpdateSchema = void 0;
|
||||
const zod_1 = require("zod");
|
||||
exports.renterUpdateSchema = zod_1.z.object({
|
||||
firstName: zod_1.z.string().min(1).max(100).trim().optional(),
|
||||
lastName: zod_1.z.string().min(1).max(100).trim().optional(),
|
||||
phone: zod_1.z.string().max(30).trim().optional(),
|
||||
preferredLocale: zod_1.z.enum(['en', 'fr', 'ar']).optional(),
|
||||
preferredCurrency: zod_1.z.literal('MAD').optional(),
|
||||
});
|
||||
exports.renterFcmTokenSchema = zod_1.z.object({
|
||||
fcmToken: zod_1.z.string(),
|
||||
});
|
||||
//# sourceMappingURL=auth.renter.schemas.js.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"auth.renter.schemas.js","sourceRoot":"","sources":["../../../src/modules/auth/auth.renter.schemas.ts"],"names":[],"mappings":";;;AAAA,6BAAuB;AAEV,QAAA,kBAAkB,GAAG,OAAC,CAAC,MAAM,CAAC;IACzC,SAAS,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,QAAQ,EAAE;IACvD,QAAQ,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,QAAQ,EAAE;IACtD,KAAK,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,QAAQ,EAAE;IAC3C,eAAe,EAAE,OAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,QAAQ,EAAE;IACtD,iBAAiB,EAAE,OAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,QAAQ,EAAE;CAC/C,CAAC,CAAA;AAEW,QAAA,oBAAoB,GAAG,OAAC,CAAC,MAAM,CAAC;IAC3C,QAAQ,EAAE,OAAC,CAAC,MAAM,EAAE;CACrB,CAAC,CAAA"}
|
||||
@@ -0,0 +1,29 @@
|
||||
import type { output } from 'zod';
|
||||
import { renterUpdateSchema } from './auth.renter.schemas';
|
||||
type RenterUpdateInput = output<typeof renterUpdateSchema>;
|
||||
export declare function signupDisabled(): void;
|
||||
export declare function loginDisabled(): void;
|
||||
export declare function getMe(renterId: string): Promise<{
|
||||
savedCompanies: {
|
||||
id: string;
|
||||
brand: {
|
||||
displayName: string | null;
|
||||
subdomain: string | null;
|
||||
logoUrl: string | null;
|
||||
} | null;
|
||||
}[];
|
||||
id: string;
|
||||
firstName: string;
|
||||
lastName: string;
|
||||
email: string;
|
||||
phone: string | null;
|
||||
preferredLocale: string | null;
|
||||
preferredCurrency: string | null;
|
||||
emailVerified: boolean;
|
||||
}>;
|
||||
export declare function updateMe(renterId: string, body: RenterUpdateInput): any;
|
||||
export declare function updateFcmToken(renterId: string, fcmToken: string): Promise<{
|
||||
success: boolean;
|
||||
}>;
|
||||
export {};
|
||||
//# sourceMappingURL=auth.renter.service.d.ts.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"auth.renter.service.d.ts","sourceRoot":"","sources":["../../../src/modules/auth/auth.renter.service.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,KAAK,CAAA;AACjC,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAA;AAE1D,KAAK,iBAAiB,GAAG,MAAM,CAAC,OAAO,kBAAkB,CAAC,CAAA;AAE1D,wBAAgB,cAAc,SAE7B;AAED,wBAAgB,aAAa,SAE5B;AAED,wBAAsB,KAAK,CAAC,QAAQ,EAAE,MAAM;;;;;;;;;;;;;;;;;GAI3C;AAED,wBAAgB,QAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,iBAAiB,OAEjE;AAED,wBAAsB,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM;;GAGtE"}
|
||||
@@ -0,0 +1,62 @@
|
||||
"use strict";
|
||||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
var desc = Object.getOwnPropertyDescriptor(m, k);
|
||||
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
||||
desc = { enumerable: true, get: function() { return m[k]; } };
|
||||
}
|
||||
Object.defineProperty(o, k2, desc);
|
||||
}) : (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
o[k2] = m[k];
|
||||
}));
|
||||
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
||||
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
||||
}) : function(o, v) {
|
||||
o["default"] = v;
|
||||
});
|
||||
var __importStar = (this && this.__importStar) || (function () {
|
||||
var ownKeys = function(o) {
|
||||
ownKeys = Object.getOwnPropertyNames || function (o) {
|
||||
var ar = [];
|
||||
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
||||
return ar;
|
||||
};
|
||||
return ownKeys(o);
|
||||
};
|
||||
return function (mod) {
|
||||
if (mod && mod.__esModule) return mod;
|
||||
var result = {};
|
||||
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
||||
__setModuleDefault(result, mod);
|
||||
return result;
|
||||
};
|
||||
})();
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.signupDisabled = signupDisabled;
|
||||
exports.loginDisabled = loginDisabled;
|
||||
exports.getMe = getMe;
|
||||
exports.updateMe = updateMe;
|
||||
exports.updateFcmToken = updateFcmToken;
|
||||
const errors_1 = require("../../http/errors");
|
||||
const auth_presenter_1 = require("./auth.presenter");
|
||||
const repo = __importStar(require("./auth.renter.repo"));
|
||||
function signupDisabled() {
|
||||
throw new errors_1.AppError('Renter account creation is disabled. Only company owners can sign in to the platform.', 403, 'renter_signup_disabled');
|
||||
}
|
||||
function loginDisabled() {
|
||||
throw new errors_1.AppError('Renter sign-in is disabled. Only company owners can sign in to the platform.', 403, 'renter_login_disabled');
|
||||
}
|
||||
async function getMe(renterId) {
|
||||
const renter = await repo.findRenterProfile(renterId);
|
||||
const savedCompanies = await repo.findSavedCompanies(renter.savedCompanies.map((savedCompany) => savedCompany.companyId));
|
||||
return (0, auth_presenter_1.presentRenterProfile)(renter, savedCompanies);
|
||||
}
|
||||
function updateMe(renterId, body) {
|
||||
return repo.updateRenterProfile(renterId, body);
|
||||
}
|
||||
async function updateFcmToken(renterId, fcmToken) {
|
||||
await repo.updateRenterFcmToken(renterId, fcmToken);
|
||||
return { success: true };
|
||||
}
|
||||
//# sourceMappingURL=auth.renter.service.js.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"auth.renter.service.js","sourceRoot":"","sources":["../../../src/modules/auth/auth.renter.service.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAQA,wCAEC;AAED,sCAEC;AAED,sBAIC;AAED,4BAEC;AAED,wCAGC;AA7BD,8CAA4C;AAC5C,qDAAuD;AACvD,yDAA0C;AAM1C,SAAgB,cAAc;IAC5B,MAAM,IAAI,iBAAQ,CAAC,uFAAuF,EAAE,GAAG,EAAE,wBAAwB,CAAC,CAAA;AAC5I,CAAC;AAED,SAAgB,aAAa;IAC3B,MAAM,IAAI,iBAAQ,CAAC,8EAA8E,EAAE,GAAG,EAAE,uBAAuB,CAAC,CAAA;AAClI,CAAC;AAEM,KAAK,UAAU,KAAK,CAAC,QAAgB;IAC1C,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,iBAAiB,CAAC,QAAQ,CAAC,CAAA;IACrD,MAAM,cAAc,GAAG,MAAM,IAAI,CAAC,kBAAkB,CAAC,MAAM,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,YAAiB,EAAE,EAAE,CAAC,YAAY,CAAC,SAAS,CAAC,CAAC,CAAA;IAC9H,OAAO,IAAA,qCAAoB,EAAC,MAAM,EAAE,cAAc,CAAC,CAAA;AACrD,CAAC;AAED,SAAgB,QAAQ,CAAC,QAAgB,EAAE,IAAuB;IAChE,OAAO,IAAI,CAAC,mBAAmB,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAA;AACjD,CAAC;AAEM,KAAK,UAAU,cAAc,CAAC,QAAgB,EAAE,QAAgB;IACrE,MAAM,IAAI,CAAC,oBAAoB,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAA;IACnD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAA;AAC1B,CAAC"}
|
||||
@@ -0,0 +1,3 @@
|
||||
export declare function presentCompany(company: any): any;
|
||||
export declare function presentBrand(brand: any): any;
|
||||
//# sourceMappingURL=company.presenter.d.ts.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"company.presenter.d.ts","sourceRoot":"","sources":["../../../src/modules/companies/company.presenter.ts"],"names":[],"mappings":"AAAA,wBAAgB,cAAc,CAAC,OAAO,EAAE,GAAG,OAE1C;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,GAAG,OAQtC"}
|
||||
@@ -0,0 +1,18 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.presentCompany = presentCompany;
|
||||
exports.presentBrand = presentBrand;
|
||||
function presentCompany(company) {
|
||||
return company;
|
||||
}
|
||||
function presentBrand(brand) {
|
||||
if (!brand)
|
||||
return brand;
|
||||
const { amanpaySecretKey, amanpayMerchantId, paypalEmail, paypalMerchantId, ...safe } = brand;
|
||||
return {
|
||||
...safe,
|
||||
amanpayConfigured: !!(amanpayMerchantId && amanpaySecretKey),
|
||||
paypalConfigured: !!(paypalEmail || paypalMerchantId),
|
||||
};
|
||||
}
|
||||
//# sourceMappingURL=company.presenter.js.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"company.presenter.js","sourceRoot":"","sources":["../../../src/modules/companies/company.presenter.ts"],"names":[],"mappings":";;AAAA,wCAEC;AAED,oCAQC;AAZD,SAAgB,cAAc,CAAC,OAAY;IACzC,OAAO,OAAO,CAAA;AAChB,CAAC;AAED,SAAgB,YAAY,CAAC,KAAU;IACrC,IAAI,CAAC,KAAK;QAAE,OAAO,KAAK,CAAA;IACxB,MAAM,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,WAAW,EAAE,gBAAgB,EAAE,GAAG,IAAI,EAAE,GAAG,KAAK,CAAA;IAC7F,OAAO;QACL,GAAG,IAAI;QACP,iBAAiB,EAAE,CAAC,CAAC,CAAC,iBAAiB,IAAI,gBAAgB,CAAC;QAC5D,gBAAgB,EAAG,CAAC,CAAC,CAAC,WAAW,IAAI,gBAAgB,CAAC;KACvD,CAAA;AACH,CAAC"}
|
||||
@@ -0,0 +1,30 @@
|
||||
export declare function findCompany(companyId: string): Promise<any>;
|
||||
export declare function updateCompany(companyId: string, data: any): Promise<any>;
|
||||
export declare function findBrand(companyId: string): Promise<any>;
|
||||
export declare function upsertBrand(companyId: string, updateData: any, createData: any): Promise<any>;
|
||||
export declare function findContractSettings(companyId: string): Promise<any>;
|
||||
export declare function upsertContractSettings(companyId: string, data: any): Promise<any>;
|
||||
export declare function findInsurancePolicies(companyId: string): Promise<any>;
|
||||
export declare function createInsurancePolicy(companyId: string, data: any): Promise<any>;
|
||||
export declare function updateInsurancePolicy(id: string, companyId: string, data: any): Promise<any>;
|
||||
export declare function findInsurancePolicyOrThrow(id: string): Promise<any>;
|
||||
export declare function deleteInsurancePolicy(id: string, companyId: string): Promise<any>;
|
||||
export declare function findPricingRules(companyId: string): Promise<any>;
|
||||
export declare function createPricingRule(companyId: string, data: any): Promise<any>;
|
||||
export declare function updatePricingRule(id: string, companyId: string, data: any): Promise<any>;
|
||||
export declare function findPricingRuleOrThrow(id: string): Promise<any>;
|
||||
export declare function deletePricingRule(id: string, companyId: string): Promise<any>;
|
||||
export declare function findAccountingSettings(companyId: string): Promise<any>;
|
||||
export declare function upsertAccountingSettings(companyId: string, data: any): Promise<any>;
|
||||
export declare function findApiKey(companyId: string): Promise<{
|
||||
apiKeys: any;
|
||||
}>;
|
||||
export declare function regenerateApiKey(companyId: string): Promise<{
|
||||
apiKey: string;
|
||||
prefix: string;
|
||||
warning: string;
|
||||
}>;
|
||||
export declare function findBrandBySubdomain(subdomain: string, excludeCompanyId: string): Promise<any>;
|
||||
export declare function findBrandByCustomDomain(customDomain: string, excludeCompanyId: string): Promise<any>;
|
||||
export declare function clearCustomDomain(companyId: string): Promise<any>;
|
||||
//# sourceMappingURL=company.repo.d.ts.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"company.repo.d.ts","sourceRoot":"","sources":["../../../src/modules/companies/company.repo.ts"],"names":[],"mappings":"AAGA,wBAAsB,WAAW,CAAC,SAAS,EAAE,MAAM,gBASlD;AAED,wBAAsB,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,gBAE/D;AAED,wBAAsB,SAAS,CAAC,SAAS,EAAE,MAAM,gBAEhD;AAED,wBAAsB,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,GAAG,EAAE,UAAU,EAAE,GAAG,gBAMpF;AAED,wBAAsB,oBAAoB,CAAC,SAAS,EAAE,MAAM,gBAE3D;AAED,wBAAsB,sBAAsB,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,gBAMxE;AAED,wBAAsB,qBAAqB,CAAC,SAAS,EAAE,MAAM,gBAK5D;AAED,wBAAsB,qBAAqB,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,gBAEvE;AAED,wBAAsB,qBAAqB,CAAC,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,gBAEnF;AAED,wBAAsB,0BAA0B,CAAC,EAAE,EAAE,MAAM,gBAE1D;AAED,wBAAsB,qBAAqB,CAAC,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,gBAExE;AAED,wBAAsB,gBAAgB,CAAC,SAAS,EAAE,MAAM,gBAKvD;AAED,wBAAsB,iBAAiB,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,gBAEnE;AAED,wBAAsB,iBAAiB,CAAC,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,gBAE/E;AAED,wBAAsB,sBAAsB,CAAC,EAAE,EAAE,MAAM,gBAEtD;AAED,wBAAsB,iBAAiB,CAAC,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,gBAEpE;AAED,wBAAsB,sBAAsB,CAAC,SAAS,EAAE,MAAM,gBAE7D;AAED,wBAAsB,wBAAwB,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,gBAM1E;AAED,wBAAsB,UAAU,CAAC,SAAS,EAAE,MAAM;;GAQjD;AAED,wBAAsB,gBAAgB,CAAC,SAAS,EAAE,MAAM;;;;GAmBvD;AAED,wBAAsB,oBAAoB,CAAC,SAAS,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,gBAErF;AAED,wBAAsB,uBAAuB,CAAC,YAAY,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,gBAE3F;AAED,wBAAsB,iBAAiB,CAAC,SAAS,EAAE,MAAM,gBAKxD"}
|
||||
+145
@@ -0,0 +1,145 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.findCompany = findCompany;
|
||||
exports.updateCompany = updateCompany;
|
||||
exports.findBrand = findBrand;
|
||||
exports.upsertBrand = upsertBrand;
|
||||
exports.findContractSettings = findContractSettings;
|
||||
exports.upsertContractSettings = upsertContractSettings;
|
||||
exports.findInsurancePolicies = findInsurancePolicies;
|
||||
exports.createInsurancePolicy = createInsurancePolicy;
|
||||
exports.updateInsurancePolicy = updateInsurancePolicy;
|
||||
exports.findInsurancePolicyOrThrow = findInsurancePolicyOrThrow;
|
||||
exports.deleteInsurancePolicy = deleteInsurancePolicy;
|
||||
exports.findPricingRules = findPricingRules;
|
||||
exports.createPricingRule = createPricingRule;
|
||||
exports.updatePricingRule = updatePricingRule;
|
||||
exports.findPricingRuleOrThrow = findPricingRuleOrThrow;
|
||||
exports.deletePricingRule = deletePricingRule;
|
||||
exports.findAccountingSettings = findAccountingSettings;
|
||||
exports.upsertAccountingSettings = upsertAccountingSettings;
|
||||
exports.findApiKey = findApiKey;
|
||||
exports.regenerateApiKey = regenerateApiKey;
|
||||
exports.findBrandBySubdomain = findBrandBySubdomain;
|
||||
exports.findBrandByCustomDomain = findBrandByCustomDomain;
|
||||
exports.clearCustomDomain = clearCustomDomain;
|
||||
const prisma_1 = require("../../lib/prisma");
|
||||
const apiKeys_1 = require("../../security/apiKeys");
|
||||
async function findCompany(companyId) {
|
||||
return prisma_1.prisma.company.findUniqueOrThrow({
|
||||
where: { id: companyId },
|
||||
include: {
|
||||
brand: true,
|
||||
subscription: true,
|
||||
_count: { select: { vehicles: true, customers: true, reservations: true } },
|
||||
},
|
||||
});
|
||||
}
|
||||
async function updateCompany(companyId, data) {
|
||||
return prisma_1.prisma.company.update({ where: { id: companyId }, data });
|
||||
}
|
||||
async function findBrand(companyId) {
|
||||
return prisma_1.prisma.brandSettings.findUnique({ where: { companyId } });
|
||||
}
|
||||
async function upsertBrand(companyId, updateData, createData) {
|
||||
return prisma_1.prisma.brandSettings.upsert({
|
||||
where: { companyId },
|
||||
update: updateData,
|
||||
create: { companyId, ...createData },
|
||||
});
|
||||
}
|
||||
async function findContractSettings(companyId) {
|
||||
return prisma_1.prisma.contractSettings.findUnique({ where: { companyId } });
|
||||
}
|
||||
async function upsertContractSettings(companyId, data) {
|
||||
return prisma_1.prisma.contractSettings.upsert({
|
||||
where: { companyId },
|
||||
update: data,
|
||||
create: { companyId, ...data },
|
||||
});
|
||||
}
|
||||
async function findInsurancePolicies(companyId) {
|
||||
return prisma_1.prisma.insurancePolicy.findMany({
|
||||
where: { companyId },
|
||||
orderBy: [{ isRequired: 'desc' }, { sortOrder: 'asc' }, { name: 'asc' }],
|
||||
});
|
||||
}
|
||||
async function createInsurancePolicy(companyId, data) {
|
||||
return prisma_1.prisma.insurancePolicy.create({ data: { companyId, ...data } });
|
||||
}
|
||||
async function updateInsurancePolicy(id, companyId, data) {
|
||||
return prisma_1.prisma.insurancePolicy.updateMany({ where: { id, companyId }, data });
|
||||
}
|
||||
async function findInsurancePolicyOrThrow(id) {
|
||||
return prisma_1.prisma.insurancePolicy.findUniqueOrThrow({ where: { id } });
|
||||
}
|
||||
async function deleteInsurancePolicy(id, companyId) {
|
||||
return prisma_1.prisma.insurancePolicy.deleteMany({ where: { id, companyId } });
|
||||
}
|
||||
async function findPricingRules(companyId) {
|
||||
return prisma_1.prisma.pricingRule.findMany({
|
||||
where: { companyId },
|
||||
orderBy: [{ isActive: 'desc' }, { createdAt: 'asc' }],
|
||||
});
|
||||
}
|
||||
async function createPricingRule(companyId, data) {
|
||||
return prisma_1.prisma.pricingRule.create({ data: { companyId, ...data } });
|
||||
}
|
||||
async function updatePricingRule(id, companyId, data) {
|
||||
return prisma_1.prisma.pricingRule.updateMany({ where: { id, companyId }, data });
|
||||
}
|
||||
async function findPricingRuleOrThrow(id) {
|
||||
return prisma_1.prisma.pricingRule.findUniqueOrThrow({ where: { id } });
|
||||
}
|
||||
async function deletePricingRule(id, companyId) {
|
||||
return prisma_1.prisma.pricingRule.deleteMany({ where: { id, companyId } });
|
||||
}
|
||||
async function findAccountingSettings(companyId) {
|
||||
return prisma_1.prisma.accountingSettings.findUnique({ where: { companyId } });
|
||||
}
|
||||
async function upsertAccountingSettings(companyId, data) {
|
||||
return prisma_1.prisma.accountingSettings.upsert({
|
||||
where: { companyId },
|
||||
update: data,
|
||||
create: { companyId, ...data },
|
||||
});
|
||||
}
|
||||
async function findApiKey(companyId) {
|
||||
const apiKeys = await prisma_1.prisma.companyApiKey.findMany({
|
||||
where: { companyId, revokedAt: null },
|
||||
orderBy: { createdAt: 'desc' },
|
||||
select: { id: true, name: true, prefix: true, lastUsedAt: true, createdAt: true, revokedAt: true },
|
||||
});
|
||||
return { apiKeys };
|
||||
}
|
||||
async function regenerateApiKey(companyId) {
|
||||
const nextKey = (0, apiKeys_1.generateCompanyApiKey)();
|
||||
await prisma_1.prisma.$transaction(async (tx) => {
|
||||
await tx.companyApiKey.updateMany({
|
||||
where: { companyId, revokedAt: null },
|
||||
data: { revokedAt: new Date() },
|
||||
});
|
||||
await tx.companyApiKey.create({
|
||||
data: {
|
||||
companyId,
|
||||
name: 'Default API key',
|
||||
prefix: nextKey.prefix,
|
||||
keyHash: nextKey.keyHash,
|
||||
},
|
||||
});
|
||||
});
|
||||
return { apiKey: nextKey.rawKey, prefix: nextKey.prefix, warning: 'This raw API key is shown once. Store it securely.' };
|
||||
}
|
||||
async function findBrandBySubdomain(subdomain, excludeCompanyId) {
|
||||
return prisma_1.prisma.brandSettings.findFirst({ where: { subdomain, companyId: { not: excludeCompanyId } } });
|
||||
}
|
||||
async function findBrandByCustomDomain(customDomain, excludeCompanyId) {
|
||||
return prisma_1.prisma.brandSettings.findFirst({ where: { customDomain, companyId: { not: excludeCompanyId } } });
|
||||
}
|
||||
async function clearCustomDomain(companyId) {
|
||||
return prisma_1.prisma.brandSettings.updateMany({
|
||||
where: { companyId },
|
||||
data: { customDomain: null, customDomainVerified: false, customDomainAddedAt: null },
|
||||
});
|
||||
}
|
||||
//# sourceMappingURL=company.repo.js.map
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,3 @@
|
||||
declare const router: import("express-serve-static-core").Router;
|
||||
export default router;
|
||||
//# sourceMappingURL=company.routes.d.ts.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"company.routes.d.ts","sourceRoot":"","sources":["../../../src/modules/companies/company.routes.ts"],"names":[],"mappings":"AAgBA,QAAA,MAAM,MAAM,4CAAW,CAAA;AA4LvB,eAAe,MAAM,CAAA"}
|
||||
+282
@@ -0,0 +1,282 @@
|
||||
"use strict";
|
||||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
var desc = Object.getOwnPropertyDescriptor(m, k);
|
||||
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
||||
desc = { enumerable: true, get: function() { return m[k]; } };
|
||||
}
|
||||
Object.defineProperty(o, k2, desc);
|
||||
}) : (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
o[k2] = m[k];
|
||||
}));
|
||||
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
||||
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
||||
}) : function(o, v) {
|
||||
o["default"] = v;
|
||||
});
|
||||
var __importStar = (this && this.__importStar) || (function () {
|
||||
var ownKeys = function(o) {
|
||||
ownKeys = Object.getOwnPropertyNames || function (o) {
|
||||
var ar = [];
|
||||
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
||||
return ar;
|
||||
};
|
||||
return ownKeys(o);
|
||||
};
|
||||
return function (mod) {
|
||||
if (mod && mod.__esModule) return mod;
|
||||
var result = {};
|
||||
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
||||
__setModuleDefault(result, mod);
|
||||
return result;
|
||||
};
|
||||
})();
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const express_1 = require("express");
|
||||
const requireCompanyAuth_1 = require("../../middleware/requireCompanyAuth");
|
||||
const requireTenant_1 = require("../../middleware/requireTenant");
|
||||
const requireSubscription_1 = require("../../middleware/requireSubscription");
|
||||
const requireRole_1 = require("../../middleware/requireRole");
|
||||
const requireCompanyPolicy_1 = require("../../middleware/requireCompanyPolicy");
|
||||
const validate_1 = require("../../http/validate");
|
||||
const respond_1 = require("../../http/respond");
|
||||
const upload_1 = require("../../http/upload");
|
||||
const service = __importStar(require("./company.service"));
|
||||
const company_schemas_1 = require("./company.schemas");
|
||||
const router = (0, express_1.Router)();
|
||||
router.use(requireCompanyAuth_1.requireCompanyAuth, requireTenant_1.requireTenant, requireSubscription_1.requireSubscription);
|
||||
router.get('/me', async (req, res, next) => {
|
||||
try {
|
||||
const company = await service.getCompany(req.companyId);
|
||||
(0, respond_1.ok)(res, company);
|
||||
}
|
||||
catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
router.patch('/me', (0, requireRole_1.requireRole)('OWNER'), async (req, res, next) => {
|
||||
try {
|
||||
const body = (0, validate_1.parseBody)(company_schemas_1.companySchema, req);
|
||||
const company = await service.updateCompany(req.companyId, body);
|
||||
(0, respond_1.ok)(res, company);
|
||||
}
|
||||
catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
router.get('/me/brand', async (req, res, next) => {
|
||||
try {
|
||||
const brand = await service.getBrand(req.companyId);
|
||||
(0, respond_1.ok)(res, brand);
|
||||
}
|
||||
catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
router.patch('/me/brand', (0, requireRole_1.requireRole)('OWNER'), async (req, res, next) => {
|
||||
try {
|
||||
const body = (0, validate_1.parseBody)(company_schemas_1.brandSchema, req);
|
||||
const brand = await service.updateBrand(req.companyId, body, req.company.name, req.company.slug);
|
||||
(0, respond_1.ok)(res, brand);
|
||||
}
|
||||
catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
router.post('/me/brand/logo', (0, requireRole_1.requireRole)('OWNER'), upload_1.imageUpload.single('file'), async (req, res, next) => {
|
||||
try {
|
||||
(0, upload_1.assertImageFile)(req.file, 'logo');
|
||||
const brand = await service.uploadLogo(req.companyId, req.company.name, req.company.slug, req.file.buffer);
|
||||
(0, respond_1.ok)(res, brand);
|
||||
}
|
||||
catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
router.post('/me/brand/hero', (0, requireRole_1.requireRole)('OWNER'), upload_1.imageUpload.single('file'), async (req, res, next) => {
|
||||
try {
|
||||
(0, upload_1.assertImageFile)(req.file, 'hero image');
|
||||
const brand = await service.uploadHeroImage(req.companyId, req.company.name, req.company.slug, req.file.buffer);
|
||||
(0, respond_1.ok)(res, brand);
|
||||
}
|
||||
catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
router.post('/me/brand/subdomain/check', (0, requireRole_1.requireRole)('OWNER'), async (req, res, next) => {
|
||||
try {
|
||||
const { subdomain } = (0, validate_1.parseBody)(company_schemas_1.subdomainSchema, req);
|
||||
const result = await service.checkSubdomainAvailability(subdomain, req.companyId);
|
||||
(0, respond_1.ok)(res, result);
|
||||
}
|
||||
catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
router.post('/me/brand/custom-domain', (0, requireRole_1.requireRole)('OWNER'), async (req, res, next) => {
|
||||
try {
|
||||
const { customDomain } = (0, validate_1.parseBody)(company_schemas_1.customDomainSchema, req);
|
||||
const brand = await service.setCustomDomain(req.companyId, req.company.name, req.company.slug, customDomain);
|
||||
(0, respond_1.ok)(res, brand);
|
||||
}
|
||||
catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
router.get('/me/brand/custom-domain/status', async (req, res, next) => {
|
||||
try {
|
||||
const status = await service.getCustomDomainStatus(req.companyId);
|
||||
(0, respond_1.ok)(res, status);
|
||||
}
|
||||
catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
router.delete('/me/brand/custom-domain', (0, requireRole_1.requireRole)('OWNER'), async (req, res, next) => {
|
||||
try {
|
||||
const result = await service.removeCustomDomain(req.companyId);
|
||||
(0, respond_1.ok)(res, result);
|
||||
}
|
||||
catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
router.get('/me/contract-settings', async (req, res, next) => {
|
||||
try {
|
||||
const settings = await service.getContractSettings(req.companyId);
|
||||
(0, respond_1.ok)(res, settings);
|
||||
}
|
||||
catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
router.patch('/me/contract-settings', (0, requireRole_1.requireRole)('MANAGER'), async (req, res, next) => {
|
||||
try {
|
||||
const body = (0, validate_1.parseBody)(company_schemas_1.contractSettingsSchema, req);
|
||||
const settings = await service.updateContractSettings(req.companyId, body);
|
||||
(0, respond_1.ok)(res, settings);
|
||||
}
|
||||
catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
router.get('/me/insurance-policies', async (req, res, next) => {
|
||||
try {
|
||||
const policies = await service.getInsurancePolicies(req.companyId);
|
||||
(0, respond_1.ok)(res, policies);
|
||||
}
|
||||
catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
router.post('/me/insurance-policies', (0, requireRole_1.requireRole)('MANAGER'), async (req, res, next) => {
|
||||
try {
|
||||
const body = (0, validate_1.parseBody)(company_schemas_1.insurancePolicySchema, req);
|
||||
const policy = await service.createInsurancePolicy(req.companyId, body);
|
||||
(0, respond_1.created)(res, policy);
|
||||
}
|
||||
catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
router.patch('/me/insurance-policies/:id', (0, requireRole_1.requireRole)('MANAGER'), async (req, res, next) => {
|
||||
try {
|
||||
const { id } = (0, validate_1.parseParams)(company_schemas_1.idParamSchema, req);
|
||||
const body = (0, validate_1.parseBody)(company_schemas_1.insurancePolicySchema.partial(), req);
|
||||
const policy = await service.updateInsurancePolicy(id, req.companyId, body);
|
||||
(0, respond_1.ok)(res, policy);
|
||||
}
|
||||
catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
router.delete('/me/insurance-policies/:id', (0, requireRole_1.requireRole)('MANAGER'), async (req, res, next) => {
|
||||
try {
|
||||
const { id } = (0, validate_1.parseParams)(company_schemas_1.idParamSchema, req);
|
||||
await service.deleteInsurancePolicy(id, req.companyId);
|
||||
(0, respond_1.ok)(res, { success: true });
|
||||
}
|
||||
catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
router.get('/me/pricing-rules', async (req, res, next) => {
|
||||
try {
|
||||
const rules = await service.getPricingRules(req.companyId);
|
||||
(0, respond_1.ok)(res, rules);
|
||||
}
|
||||
catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
router.post('/me/pricing-rules', (0, requireRole_1.requireRole)('MANAGER'), async (req, res, next) => {
|
||||
try {
|
||||
const body = (0, validate_1.parseBody)(company_schemas_1.pricingRuleSchema, req);
|
||||
const rule = await service.createPricingRule(req.companyId, body);
|
||||
(0, respond_1.created)(res, rule);
|
||||
}
|
||||
catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
router.patch('/me/pricing-rules/:id', (0, requireRole_1.requireRole)('MANAGER'), async (req, res, next) => {
|
||||
try {
|
||||
const { id } = (0, validate_1.parseParams)(company_schemas_1.idParamSchema, req);
|
||||
const body = (0, validate_1.parseBody)(company_schemas_1.pricingRuleSchema.partial(), req);
|
||||
const rule = await service.updatePricingRule(id, req.companyId, body);
|
||||
(0, respond_1.ok)(res, rule);
|
||||
}
|
||||
catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
router.delete('/me/pricing-rules/:id', (0, requireCompanyPolicy_1.requireCompanyPolicy)('deletePricingRule'), async (req, res, next) => {
|
||||
try {
|
||||
const { id } = (0, validate_1.parseParams)(company_schemas_1.idParamSchema, req);
|
||||
await service.deletePricingRule(id, req.companyId);
|
||||
(0, respond_1.ok)(res, { success: true });
|
||||
}
|
||||
catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
router.get('/me/accounting-settings', async (req, res, next) => {
|
||||
try {
|
||||
const settings = await service.getAccountingSettings(req.companyId);
|
||||
(0, respond_1.ok)(res, settings);
|
||||
}
|
||||
catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
router.patch('/me/accounting-settings', (0, requireCompanyPolicy_1.requireCompanyPolicy)('updateAccountingSettings'), async (req, res, next) => {
|
||||
try {
|
||||
const body = (0, validate_1.parseBody)(company_schemas_1.accountingSettingsSchema, req);
|
||||
const settings = await service.updateAccountingSettings(req.companyId, body);
|
||||
(0, respond_1.ok)(res, settings);
|
||||
}
|
||||
catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
router.get('/me/api-key', (0, requireCompanyPolicy_1.requireCompanyPolicy)('viewApiKey'), async (req, res, next) => {
|
||||
try {
|
||||
const company = await service.getApiKey(req.companyId);
|
||||
(0, respond_1.ok)(res, company);
|
||||
}
|
||||
catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
router.post('/me/api-key/regenerate', (0, requireCompanyPolicy_1.requireCompanyPolicy)('regenerateApiKey'), async (req, res, next) => {
|
||||
try {
|
||||
const company = await service.regenerateApiKey(req.companyId);
|
||||
(0, respond_1.ok)(res, company);
|
||||
}
|
||||
catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
exports.default = router;
|
||||
//# sourceMappingURL=company.routes.js.map
|
||||
File diff suppressed because one or more lines are too long
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user