AI Implementation feature(891): Admin Area General Settings and Categories 1.09 (#31)

This commit was merged in pull request #31.
This commit is contained in:
2026-07-22 15:47:04 +00:00
parent 2a6182b938
commit 4656a5b082
11 changed files with 432 additions and 42 deletions
+48 -1
View File
@@ -1,6 +1,53 @@
import { isIP } from 'net';
import { z } from 'zod';
import { THEME_IDS } from '../../../common/types/theme-ids';
const HOSTNAME_LABEL = /^(?!-)[A-Za-z0-9-]{1,63}(?<!-)$/;
const ALL_NUMERIC_LABEL = /^[0-9]+$/;
function isValidHostname(value: string): boolean {
if (value.length === 0 || value.length > 253) return false;
if (value.startsWith('.') || value.endsWith('.')) return false;
const labels = value.split('.');
if (labels.length < 2) return false;
if (labels.some((label) => ALL_NUMERIC_LABEL.test(label))) return false;
return labels.every((label) => HOSTNAME_LABEL.test(label));
}
export function isValidDefaultChallengeAddress(value: string): boolean {
if (isIP(value) === 4) return true;
return isValidHostname(value);
}
const defaultChallengeIpSchema = z
.string({ required_error: 'defaultChallengeIp is required', invalid_type_error: 'defaultChallengeIp must be a string' })
.transform((v) => v.trim())
.superRefine((value, ctx) => {
if (value.length === 0) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
path: [],
message: 'defaultChallengeIp is required and cannot contain only whitespace',
});
return;
}
if (value.length > 255) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
path: [],
message: 'defaultChallengeIp must be 255 characters or fewer',
});
return;
}
if (!isValidDefaultChallengeAddress(value)) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
path: [],
message: 'defaultChallengeIp must be a valid IPv4 address or hostname',
});
}
});
export const GeneralSettingsSchema = z
.object({
pageTitle: z.string().trim().min(1).max(120),
@@ -9,7 +56,7 @@ export const GeneralSettingsSchema = z
themeKey: z.enum(THEME_IDS as unknown as [string, ...string[]]),
eventStartUtc: z.string().datetime({ message: 'eventStartUtc must be a valid ISO-8601 datetime' }),
eventEndUtc: z.string().datetime({ message: 'eventEndUtc must be a valid ISO-8601 datetime' }),
defaultChallengeIp: z.string().min(1).max(255),
defaultChallengeIp: defaultChallengeIpSchema,
registrationsEnabled: z.boolean(),
})
.superRefine((val, ctx) => {