170 lines
5.6 KiB
TypeScript
170 lines
5.6 KiB
TypeScript
|
|
import { zValidator } from '@hono/zod-validator';
|
||
|
|
import { Hono } from 'hono';
|
||
|
|
import config from '../config';
|
||
|
|
import { ADMIN_SETTINGS_FIELDS, PUBLIC_SETTINGS_FIELDS } from '../lib/constants';
|
||
|
|
import prisma from '../lib/db';
|
||
|
|
import settingsCache, { setCachedInstanceSettings } from '../lib/settings';
|
||
|
|
import { handleNotFound, isPublicUrl } from '../lib/utils';
|
||
|
|
import { authMiddleware, checkAdmin } from '../middlewares/auth';
|
||
|
|
import { instanceSettingsSchema } from '../validations/instance';
|
||
|
|
|
||
|
|
const app = new Hono();
|
||
|
|
|
||
|
|
// GET /api/instance/managed - check if instance is in managed mode
|
||
|
|
app.get('/managed', async (c) => {
|
||
|
|
return c.json({ managed: config.isManaged() });
|
||
|
|
});
|
||
|
|
|
||
|
|
// GET /api/instance/settings/public - public settings for all users
|
||
|
|
app.get('/settings/public', async (c) => {
|
||
|
|
try {
|
||
|
|
// In managed mode, return settings from environment variables
|
||
|
|
if (config.isManaged()) {
|
||
|
|
const managedSettings = config.getManagedSettings();
|
||
|
|
const publicSettings = Object.fromEntries(
|
||
|
|
Object.entries(managedSettings || {}).filter(
|
||
|
|
([key]) => key in PUBLIC_SETTINGS_FIELDS
|
||
|
|
)
|
||
|
|
);
|
||
|
|
return c.json(publicSettings);
|
||
|
|
}
|
||
|
|
|
||
|
|
let dbSettings = await prisma.instanceSettings.findFirst({
|
||
|
|
select: PUBLIC_SETTINGS_FIELDS,
|
||
|
|
});
|
||
|
|
|
||
|
|
if (!dbSettings) {
|
||
|
|
const initialData = {
|
||
|
|
...Object.fromEntries(
|
||
|
|
Object.entries(config.get('general')).filter(([, v]) => v !== undefined)
|
||
|
|
),
|
||
|
|
...Object.fromEntries(
|
||
|
|
Object.entries(config.get('security')).filter(([, v]) => v !== undefined)
|
||
|
|
),
|
||
|
|
};
|
||
|
|
|
||
|
|
dbSettings = await prisma.instanceSettings.create({
|
||
|
|
data: initialData,
|
||
|
|
select: PUBLIC_SETTINGS_FIELDS,
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
const configSettings = {
|
||
|
|
...config.get('general'),
|
||
|
|
...config.get('security'),
|
||
|
|
};
|
||
|
|
const filteredConfigSettings = Object.fromEntries(
|
||
|
|
Object.entries(configSettings).filter(
|
||
|
|
([key, value]) => value !== undefined && key in PUBLIC_SETTINGS_FIELDS
|
||
|
|
)
|
||
|
|
);
|
||
|
|
|
||
|
|
const finalSettings = {
|
||
|
|
...dbSettings,
|
||
|
|
...filteredConfigSettings,
|
||
|
|
};
|
||
|
|
|
||
|
|
return c.json(finalSettings);
|
||
|
|
} catch (error) {
|
||
|
|
console.error('Failed to fetch public instance settings:', error);
|
||
|
|
return c.json({ error: 'Failed to fetch instance settings' }, 500);
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
// GET /api/instance/settings - admin only
|
||
|
|
app.get('/settings', authMiddleware, checkAdmin, async (c) => {
|
||
|
|
try {
|
||
|
|
// In managed mode, return settings from environment variables
|
||
|
|
if (config.isManaged()) {
|
||
|
|
const managedSettings = config.getManagedSettings();
|
||
|
|
return c.json(managedSettings);
|
||
|
|
}
|
||
|
|
|
||
|
|
let dbSettings = await prisma.instanceSettings.findFirst({ select: ADMIN_SETTINGS_FIELDS });
|
||
|
|
|
||
|
|
if (!dbSettings) {
|
||
|
|
const initialData = {
|
||
|
|
...Object.fromEntries(
|
||
|
|
Object.entries(config.get('general')).filter(([, v]) => v !== undefined)
|
||
|
|
),
|
||
|
|
...Object.fromEntries(
|
||
|
|
Object.entries(config.get('security')).filter(([, v]) => v !== undefined)
|
||
|
|
),
|
||
|
|
};
|
||
|
|
|
||
|
|
dbSettings = await prisma.instanceSettings.create({
|
||
|
|
data: initialData,
|
||
|
|
select: ADMIN_SETTINGS_FIELDS,
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
const configSettings = {
|
||
|
|
...config.get('general'),
|
||
|
|
...config.get('security'),
|
||
|
|
};
|
||
|
|
const filteredConfigSettings = Object.fromEntries(
|
||
|
|
Object.entries(configSettings).filter(([, value]) => value !== undefined)
|
||
|
|
);
|
||
|
|
|
||
|
|
const finalSettings = {
|
||
|
|
...dbSettings,
|
||
|
|
...filteredConfigSettings,
|
||
|
|
};
|
||
|
|
|
||
|
|
return c.json(finalSettings);
|
||
|
|
} catch (error) {
|
||
|
|
console.error('Failed to fetch instance settings:', error);
|
||
|
|
return c.json({ error: 'Failed to fetch instance settings' }, 500);
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
// PUT /api/instance/settings
|
||
|
|
app.put(
|
||
|
|
'/settings',
|
||
|
|
authMiddleware,
|
||
|
|
checkAdmin,
|
||
|
|
zValidator('json', instanceSettingsSchema),
|
||
|
|
async (c) => {
|
||
|
|
// Block updates in managed mode
|
||
|
|
if (config.isManaged()) {
|
||
|
|
return c.json(
|
||
|
|
{ error: 'Instance is in managed mode. Settings cannot be modified.' },
|
||
|
|
403
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
const body = c.req.valid('json');
|
||
|
|
|
||
|
|
if (body.webhookUrl && body.webhookUrl !== '' && !(await isPublicUrl(body.webhookUrl))) {
|
||
|
|
return c.json({ error: 'Webhook URL cannot point to private/internal addresses' }, 400);
|
||
|
|
}
|
||
|
|
|
||
|
|
try {
|
||
|
|
const settings = await prisma.instanceSettings.findFirst();
|
||
|
|
|
||
|
|
if (!settings) {
|
||
|
|
return c.json({ error: 'Instance settings not found' }, 404);
|
||
|
|
}
|
||
|
|
|
||
|
|
const updatedSettings = await prisma.instanceSettings.update({
|
||
|
|
where: { id: settings.id },
|
||
|
|
data: body,
|
||
|
|
select: ADMIN_SETTINGS_FIELDS,
|
||
|
|
});
|
||
|
|
|
||
|
|
const currentSettings = settingsCache.get('instanceSettings');
|
||
|
|
setCachedInstanceSettings({
|
||
|
|
...currentSettings,
|
||
|
|
...updatedSettings,
|
||
|
|
});
|
||
|
|
|
||
|
|
return c.json(updatedSettings);
|
||
|
|
} catch (error) {
|
||
|
|
console.error('Failed to update instance settings:', error);
|
||
|
|
return handleNotFound(error as Error & { code?: string }, c);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
);
|
||
|
|
|
||
|
|
export default app;
|