first commit

This commit is contained in:
Michaël
2026-01-29 14:13:11 -03:00
commit 2302748c87
105 changed files with 93301 additions and 0 deletions

View File

@@ -0,0 +1,278 @@
import { Hono } from 'hono';
import { zValidator } from '@hono/zod-validator';
import { z } from 'zod';
import { db, paymentOptions, eventPaymentOverrides, events } from '../db/index.js';
import { eq } from 'drizzle-orm';
import { requireAuth } from '../lib/auth.js';
import { generateId, getNow } from '../lib/utils.js';
const paymentOptionsRouter = new Hono();
// Schema for updating global payment options
const updatePaymentOptionsSchema = z.object({
tpagoEnabled: z.boolean().optional(),
tpagoLink: z.string().optional().nullable(),
tpagoInstructions: z.string().optional().nullable(),
tpagoInstructionsEs: z.string().optional().nullable(),
bankTransferEnabled: z.boolean().optional(),
bankName: z.string().optional().nullable(),
bankAccountHolder: z.string().optional().nullable(),
bankAccountNumber: z.string().optional().nullable(),
bankAlias: z.string().optional().nullable(),
bankPhone: z.string().optional().nullable(),
bankNotes: z.string().optional().nullable(),
bankNotesEs: z.string().optional().nullable(),
lightningEnabled: z.boolean().optional(),
cashEnabled: z.boolean().optional(),
cashInstructions: z.string().optional().nullable(),
cashInstructionsEs: z.string().optional().nullable(),
});
// Schema for event-level overrides
const updateEventOverridesSchema = z.object({
tpagoEnabled: z.boolean().optional().nullable(),
tpagoLink: z.string().optional().nullable(),
tpagoInstructions: z.string().optional().nullable(),
tpagoInstructionsEs: z.string().optional().nullable(),
bankTransferEnabled: z.boolean().optional().nullable(),
bankName: z.string().optional().nullable(),
bankAccountHolder: z.string().optional().nullable(),
bankAccountNumber: z.string().optional().nullable(),
bankAlias: z.string().optional().nullable(),
bankPhone: z.string().optional().nullable(),
bankNotes: z.string().optional().nullable(),
bankNotesEs: z.string().optional().nullable(),
lightningEnabled: z.boolean().optional().nullable(),
cashEnabled: z.boolean().optional().nullable(),
cashInstructions: z.string().optional().nullable(),
cashInstructionsEs: z.string().optional().nullable(),
});
// Get global payment options
paymentOptionsRouter.get('/', requireAuth(['admin']), async (c) => {
const options = await (db as any)
.select()
.from(paymentOptions)
.get();
// If no options exist yet, return defaults
if (!options) {
return c.json({
paymentOptions: {
tpagoEnabled: false,
tpagoLink: null,
tpagoInstructions: null,
tpagoInstructionsEs: null,
bankTransferEnabled: false,
bankName: null,
bankAccountHolder: null,
bankAccountNumber: null,
bankAlias: null,
bankPhone: null,
bankNotes: null,
bankNotesEs: null,
lightningEnabled: true,
cashEnabled: true,
cashInstructions: null,
cashInstructionsEs: null,
},
});
}
return c.json({ paymentOptions: options });
});
// Update global payment options
paymentOptionsRouter.put('/', requireAuth(['admin']), zValidator('json', updatePaymentOptionsSchema), async (c) => {
const data = c.req.valid('json');
const user = (c as any).get('user');
const now = getNow();
// Check if options exist
const existing = await (db as any)
.select()
.from(paymentOptions)
.get();
if (existing) {
// Update existing
await (db as any)
.update(paymentOptions)
.set({
...data,
updatedAt: now,
updatedBy: user.id,
})
.where(eq((paymentOptions as any).id, existing.id));
} else {
// Create new
const id = generateId();
await (db as any).insert(paymentOptions).values({
id,
...data,
updatedAt: now,
updatedBy: user.id,
});
}
const updated = await (db as any)
.select()
.from(paymentOptions)
.get();
return c.json({ paymentOptions: updated, message: 'Payment options updated successfully' });
});
// Get payment options for a specific event (merged with global)
paymentOptionsRouter.get('/event/:eventId', async (c) => {
const eventId = c.req.param('eventId');
// Get the event first to verify it exists
const event = await (db as any)
.select()
.from(events)
.where(eq((events as any).id, eventId))
.get();
if (!event) {
return c.json({ error: 'Event not found' }, 404);
}
// Get global options
const globalOptions = await (db as any)
.select()
.from(paymentOptions)
.get();
// Get event overrides
const overrides = await (db as any)
.select()
.from(eventPaymentOverrides)
.where(eq((eventPaymentOverrides as any).eventId, eventId))
.get();
// Merge global with overrides (override takes precedence if not null)
const defaults = {
tpagoEnabled: false,
tpagoLink: null,
tpagoInstructions: null,
tpagoInstructionsEs: null,
bankTransferEnabled: false,
bankName: null,
bankAccountHolder: null,
bankAccountNumber: null,
bankAlias: null,
bankPhone: null,
bankNotes: null,
bankNotesEs: null,
lightningEnabled: true,
cashEnabled: true,
cashInstructions: null,
cashInstructionsEs: null,
};
const global = globalOptions || defaults;
// Merge: override values take precedence if they're not null/undefined
const merged = {
tpagoEnabled: overrides?.tpagoEnabled ?? global.tpagoEnabled,
tpagoLink: overrides?.tpagoLink ?? global.tpagoLink,
tpagoInstructions: overrides?.tpagoInstructions ?? global.tpagoInstructions,
tpagoInstructionsEs: overrides?.tpagoInstructionsEs ?? global.tpagoInstructionsEs,
bankTransferEnabled: overrides?.bankTransferEnabled ?? global.bankTransferEnabled,
bankName: overrides?.bankName ?? global.bankName,
bankAccountHolder: overrides?.bankAccountHolder ?? global.bankAccountHolder,
bankAccountNumber: overrides?.bankAccountNumber ?? global.bankAccountNumber,
bankAlias: overrides?.bankAlias ?? global.bankAlias,
bankPhone: overrides?.bankPhone ?? global.bankPhone,
bankNotes: overrides?.bankNotes ?? global.bankNotes,
bankNotesEs: overrides?.bankNotesEs ?? global.bankNotesEs,
lightningEnabled: overrides?.lightningEnabled ?? global.lightningEnabled,
cashEnabled: overrides?.cashEnabled ?? global.cashEnabled,
cashInstructions: overrides?.cashInstructions ?? global.cashInstructions,
cashInstructionsEs: overrides?.cashInstructionsEs ?? global.cashInstructionsEs,
};
return c.json({
paymentOptions: merged,
hasOverrides: !!overrides,
});
});
// Get event payment overrides (admin only)
paymentOptionsRouter.get('/event/:eventId/overrides', requireAuth(['admin', 'organizer']), async (c) => {
const eventId = c.req.param('eventId');
const overrides = await (db as any)
.select()
.from(eventPaymentOverrides)
.where(eq((eventPaymentOverrides as any).eventId, eventId))
.get();
return c.json({ overrides: overrides || null });
});
// Update event payment overrides
paymentOptionsRouter.put('/event/:eventId/overrides', requireAuth(['admin', 'organizer']), zValidator('json', updateEventOverridesSchema), async (c) => {
const eventId = c.req.param('eventId');
const data = c.req.valid('json');
const now = getNow();
// Verify event exists
const event = await (db as any)
.select()
.from(events)
.where(eq((events as any).id, eventId))
.get();
if (!event) {
return c.json({ error: 'Event not found' }, 404);
}
// Check if overrides exist
const existing = await (db as any)
.select()
.from(eventPaymentOverrides)
.where(eq((eventPaymentOverrides as any).eventId, eventId))
.get();
if (existing) {
await (db as any)
.update(eventPaymentOverrides)
.set({
...data,
updatedAt: now,
})
.where(eq((eventPaymentOverrides as any).id, existing.id));
} else {
const id = generateId();
await (db as any).insert(eventPaymentOverrides).values({
id,
eventId,
...data,
createdAt: now,
updatedAt: now,
});
}
const updated = await (db as any)
.select()
.from(eventPaymentOverrides)
.where(eq((eventPaymentOverrides as any).eventId, eventId))
.get();
return c.json({ overrides: updated, message: 'Event payment overrides updated successfully' });
});
// Delete event payment overrides (revert to global)
paymentOptionsRouter.delete('/event/:eventId/overrides', requireAuth(['admin', 'organizer']), async (c) => {
const eventId = c.req.param('eventId');
await (db as any)
.delete(eventPaymentOverrides)
.where(eq((eventPaymentOverrides as any).eventId, eventId));
return c.json({ message: 'Event payment overrides removed' });
});
export default paymentOptionsRouter;