first commit
This commit is contained in:
147
api/src/controllers/admin.controller.ts
Normal file
147
api/src/controllers/admin.controller.ts
Normal file
@@ -0,0 +1,147 @@
|
||||
import type { Response } from 'express';
|
||||
import { createRequire } from 'node:module';
|
||||
import { z } from 'zod';
|
||||
import { AppDataSource } from '../config/data-source.js';
|
||||
import { AppSetting } from '../entities/AppSetting.js';
|
||||
import { User } from '../entities/User.js';
|
||||
import { sanitizeUser } from '../services/auth.service.js';
|
||||
import type { AuthenticatedRequest } from '../types/express.js';
|
||||
|
||||
const settingsSchema = z.object({
|
||||
appName: z.string().min(2).max(120),
|
||||
defaultCurrency: z.string().min(3).max(8),
|
||||
registrationEnabled: z.boolean(),
|
||||
allowedProofTypes: z.array(z.string().min(2).max(30)).min(1),
|
||||
uiPreferences: z.record(z.string(), z.union([z.string(), z.number(), z.boolean()])),
|
||||
smtpEnabled: z.boolean(),
|
||||
smtpHost: z.string().max(120).nullable().optional(),
|
||||
smtpPort: z.number().int().min(1).max(65535),
|
||||
smtpSecure: z.boolean(),
|
||||
smtpUser: z.string().max(160).nullable().optional(),
|
||||
smtpPassword: z.string().max(255).nullable().optional(),
|
||||
smtpFromName: z.string().max(120).nullable().optional(),
|
||||
smtpFromEmail: z.string().max(160).nullable().optional()
|
||||
});
|
||||
|
||||
const userUpdateSchema = z.object({
|
||||
role: z.enum(['ADMIN', 'USER']).optional(),
|
||||
isActive: z.boolean().optional(),
|
||||
defaultCurrency: z.string().min(3).max(8).optional()
|
||||
});
|
||||
|
||||
const require = createRequire(import.meta.url);
|
||||
const settingsRepo = () => AppDataSource.getRepository(AppSetting);
|
||||
const userRepo = () => AppDataSource.getRepository(User);
|
||||
|
||||
const sanitizeSettings = (item: AppSetting) => ({
|
||||
id: item.id,
|
||||
appName: item.appName,
|
||||
defaultCurrency: item.defaultCurrency,
|
||||
registrationEnabled: item.registrationEnabled,
|
||||
allowedProofTypes: item.allowedProofTypes,
|
||||
uiPreferences: item.uiPreferences,
|
||||
smtpEnabled: item.smtpEnabled,
|
||||
smtpHost: item.smtpHost,
|
||||
smtpPort: item.smtpPort,
|
||||
smtpSecure: item.smtpSecure,
|
||||
smtpUser: item.smtpUser,
|
||||
smtpPassword: item.smtpPassword,
|
||||
smtpFromName: item.smtpFromName,
|
||||
smtpFromEmail: item.smtpFromEmail,
|
||||
createdAt: item.createdAt,
|
||||
updatedAt: item.updatedAt
|
||||
});
|
||||
|
||||
const getSettingsEntity = async () => {
|
||||
const [item] = await settingsRepo().find({ take: 1, order: { createdAt: 'ASC' } });
|
||||
return item ?? null;
|
||||
};
|
||||
|
||||
export const getSettings = async (_req: AuthenticatedRequest, res: Response) => {
|
||||
const item = await getSettingsEntity();
|
||||
if (!item) return res.status(404).json({ message: 'Settings were not initialized' });
|
||||
return res.json({ item: sanitizeSettings(item) });
|
||||
};
|
||||
|
||||
export const updateSettings = async (req: AuthenticatedRequest, res: Response) => {
|
||||
const parsed = settingsSchema.safeParse(req.body);
|
||||
if (!parsed.success) {
|
||||
return res.status(400).json({ message: 'Invalid settings payload', issues: parsed.error.issues });
|
||||
}
|
||||
|
||||
const item = await getSettingsEntity();
|
||||
if (!item) return res.status(404).json({ message: 'Settings were not initialized' });
|
||||
|
||||
Object.assign(item, {
|
||||
appName: parsed.data.appName,
|
||||
defaultCurrency: parsed.data.defaultCurrency,
|
||||
registrationEnabled: parsed.data.registrationEnabled,
|
||||
allowedProofTypes: parsed.data.allowedProofTypes,
|
||||
uiPreferences: parsed.data.uiPreferences,
|
||||
smtpEnabled: parsed.data.smtpEnabled,
|
||||
smtpHost: parsed.data.smtpHost ?? null,
|
||||
smtpPort: parsed.data.smtpPort,
|
||||
smtpSecure: parsed.data.smtpSecure,
|
||||
smtpUser: parsed.data.smtpUser ?? null,
|
||||
smtpPassword: parsed.data.smtpPassword ?? null,
|
||||
smtpFromName: parsed.data.smtpFromName ?? null,
|
||||
smtpFromEmail: parsed.data.smtpFromEmail ?? null
|
||||
});
|
||||
|
||||
await settingsRepo().save(item);
|
||||
return res.json({ item: sanitizeSettings(item) });
|
||||
};
|
||||
|
||||
export const listUsers = async (_req: AuthenticatedRequest, res: Response) => {
|
||||
const items = await userRepo().find({ order: { createdAt: 'DESC' } });
|
||||
return res.json({ items: items.map(sanitizeUser) });
|
||||
};
|
||||
|
||||
export const updateUser = async (req: AuthenticatedRequest, res: Response) => {
|
||||
const parsed = userUpdateSchema.safeParse(req.body);
|
||||
if (!parsed.success) {
|
||||
return res.status(400).json({ message: 'Invalid user update payload', issues: parsed.error.issues });
|
||||
}
|
||||
|
||||
const itemId = String(req.params.id);
|
||||
const item = await userRepo().findOne({ where: { id: itemId } });
|
||||
if (!item) return res.status(404).json({ message: 'User not found' });
|
||||
|
||||
if (parsed.data.role) item.role = parsed.data.role;
|
||||
if (typeof parsed.data.isActive === 'boolean') item.isActive = parsed.data.isActive;
|
||||
if (parsed.data.defaultCurrency) item.defaultCurrency = parsed.data.defaultCurrency;
|
||||
|
||||
await userRepo().save(item);
|
||||
return res.json({ item: sanitizeUser(item) });
|
||||
};
|
||||
|
||||
export const testSmtp = async (req: AuthenticatedRequest, res: Response) => {
|
||||
const parsed = z.object({ to: z.email() }).safeParse(req.body);
|
||||
if (!parsed.success) {
|
||||
return res.status(400).json({ message: 'Invalid test email payload', issues: parsed.error.issues });
|
||||
}
|
||||
|
||||
const settings = await getSettingsEntity();
|
||||
if (!settings || !settings.smtpEnabled || !settings.smtpHost || !settings.smtpFromEmail) {
|
||||
return res.status(400).json({ message: 'SMTP is not configured' });
|
||||
}
|
||||
|
||||
const nodemailer = require('nodemailer') as { createTransport: (options: unknown) => { sendMail: (message: unknown) => Promise<unknown> } };
|
||||
const transport = nodemailer.createTransport({
|
||||
host: settings.smtpHost,
|
||||
port: settings.smtpPort,
|
||||
secure: settings.smtpSecure,
|
||||
auth: settings.smtpUser ? { user: settings.smtpUser, pass: settings.smtpPassword ?? '' } : undefined
|
||||
});
|
||||
|
||||
await transport.sendMail({
|
||||
from: settings.smtpFromName
|
||||
? `"${settings.smtpFromName}" <${settings.smtpFromEmail}>`
|
||||
: settings.smtpFromEmail,
|
||||
to: parsed.data.to,
|
||||
subject: `${settings.appName} - SMTP test`,
|
||||
html: `<div style="font-family:Arial,sans-serif"><h2>SMTP connection works</h2><p>This message was sent from the admin panel test action.</p></div>`
|
||||
});
|
||||
|
||||
return res.json({ message: 'SMTP test message was sent' });
|
||||
};
|
||||
Reference in New Issue
Block a user