refactor: mark dead exports with TODO, deduplicate field sanitization, fix import placement
Local Build and Deploy / deploy (push) Successful in 1m36s
Local Build and Deploy / deploy (push) Successful in 1m36s
This commit is contained in:
1 parent
2beba07ba5
commit
d5e3bc7875
13 files changed
+49
-64
No files matched your search
+15
-58
@@ -5,6 +5,7 @@ import { redirect } from "next/navigation";
|
||||
import { requirePermission } from "@/lib/admin/guard";
|
||||
import { PERMS } from "@/lib/permissions";
|
||||
import { formPositiveBigInt } from "@/lib/form-data";
|
||||
import { canonicalize, sanitizeField } from "@/lib/foundation/security";
|
||||
import { prisma } from "@/lib/prisma";
|
||||
import { logStaffActivity } from "@/lib/services/staff-activity";
|
||||
|
||||
@@ -18,37 +19,15 @@ function parsePosition(value: FormDataEntryValue | null): number {
|
||||
|
||||
export async function createHelpQuestion(formData: FormData): Promise<void> {
|
||||
const staff = await requirePermission(PERMS.PAGES_EDIT);
|
||||
const name = String(formData.get("name") ?? "")
|
||||
.normalize("NFC")
|
||||
.trim()
|
||||
.slice(0, 255);
|
||||
const content = String(formData.get("content") ?? "")
|
||||
.normalize("NFC")
|
||||
.trim();
|
||||
const name = sanitizeField(formData.get("name"));
|
||||
const content = canonicalize(String(formData.get("content") ?? ""));
|
||||
if (!name || !content) return;
|
||||
|
||||
const imageUrl = String(formData.get("imageUrl") ?? "")
|
||||
.normalize("NFC")
|
||||
.trim()
|
||||
.slice(0, 255);
|
||||
const buttonText = String(formData.get("buttonText") ?? "")
|
||||
.normalize("NFC")
|
||||
.trim()
|
||||
.slice(0, 255);
|
||||
const buttonUrl = String(formData.get("buttonUrl") ?? "")
|
||||
.normalize("NFC")
|
||||
.trim()
|
||||
.slice(0, 255);
|
||||
const buttonColor =
|
||||
String(formData.get("buttonColor") ?? "")
|
||||
.normalize("NFC")
|
||||
.trim()
|
||||
.slice(0, 16) || "#eeb425";
|
||||
const buttonBorderColor =
|
||||
String(formData.get("buttonBorderColor") ?? "")
|
||||
.normalize("NFC")
|
||||
.trim()
|
||||
.slice(0, 16) || "#facc15";
|
||||
const imageUrl = sanitizeField(formData.get("imageUrl"));
|
||||
const buttonText = sanitizeField(formData.get("buttonText"));
|
||||
const buttonUrl = sanitizeField(formData.get("buttonUrl"));
|
||||
const buttonColor = sanitizeField(formData.get("buttonColor"), 16) || "#eeb425";
|
||||
const buttonBorderColor = sanitizeField(formData.get("buttonBorderColor"), 16) || "#facc15";
|
||||
|
||||
try {
|
||||
const entry = await prisma.websiteHelpCenterCategories.create({
|
||||
@@ -87,37 +66,15 @@ export async function updateHelpQuestion(formData: FormData): Promise<void> {
|
||||
const id = formPositiveBigInt(formData, "id");
|
||||
if (!id) return;
|
||||
|
||||
const name = String(formData.get("name") ?? "")
|
||||
.normalize("NFC")
|
||||
.trim()
|
||||
.slice(0, 255);
|
||||
const content = String(formData.get("content") ?? "")
|
||||
.normalize("NFC")
|
||||
.trim();
|
||||
const name = sanitizeField(formData.get("name"));
|
||||
const content = canonicalize(String(formData.get("content") ?? ""));
|
||||
if (!name || !content) return;
|
||||
|
||||
const imageUrl = String(formData.get("imageUrl") ?? "")
|
||||
.normalize("NFC")
|
||||
.trim()
|
||||
.slice(0, 255);
|
||||
const buttonText = String(formData.get("buttonText") ?? "")
|
||||
.normalize("NFC")
|
||||
.trim()
|
||||
.slice(0, 255);
|
||||
const buttonUrl = String(formData.get("buttonUrl") ?? "")
|
||||
.normalize("NFC")
|
||||
.trim()
|
||||
.slice(0, 255);
|
||||
const buttonColor =
|
||||
String(formData.get("buttonColor") ?? "")
|
||||
.normalize("NFC")
|
||||
.trim()
|
||||
.slice(0, 16) || "#eeb425";
|
||||
const buttonBorderColor =
|
||||
String(formData.get("buttonBorderColor") ?? "")
|
||||
.normalize("NFC")
|
||||
.trim()
|
||||
.slice(0, 16) || "#facc15";
|
||||
const imageUrl = sanitizeField(formData.get("imageUrl"));
|
||||
const buttonText = sanitizeField(formData.get("buttonText"));
|
||||
const buttonUrl = sanitizeField(formData.get("buttonUrl"));
|
||||
const buttonColor = sanitizeField(formData.get("buttonColor"), 16) || "#eeb425";
|
||||
const buttonBorderColor = sanitizeField(formData.get("buttonBorderColor"), 16) || "#facc15";
|
||||
|
||||
try {
|
||||
await prisma.websiteHelpCenterCategories.update({
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
import { motion } from "framer-motion";
|
||||
import { useCallback, useEffect, useRef, useState } from "react";
|
||||
import { useEventSource } from "@/lib/use-event-source";
|
||||
|
||||
/**
|
||||
* Fixed bottom-right radio player widget — the Next.js port of AtomCMS's
|
||||
@@ -135,8 +136,6 @@ function parseListeners(data: unknown): number | null {
|
||||
return null;
|
||||
}
|
||||
|
||||
import { useEventSource } from "@/lib/use-event-source";
|
||||
|
||||
export default function RadioPlayer() {
|
||||
const audioRef = useRef<HTMLAudioElement | null>(null);
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// TODO: Check of dit bestand weg kan — uitsluitend gebruikt door eigen test
|
||||
export interface AdminMutationNotice {
|
||||
tone: "ok" | "danger";
|
||||
label: "Saved" | "Error";
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// TODO: Check of dit bestand weg kan — uitsluitend gebruikt door eigen test
|
||||
import type { AuthorizationActor } from "@/lib/admin/authorization-policy";
|
||||
|
||||
export interface RankAuthorityDb {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// TODO: Check of dit bestand weg kan — uitsluitend gebruikt door eigen test
|
||||
import { isStaff } from "@/lib/admin/is-staff";
|
||||
|
||||
export interface StaffUserRecord {
|
||||
|
||||
@@ -30,7 +30,7 @@ export function apiValidationError(zodError: z.ZodError) {
|
||||
);
|
||||
}
|
||||
|
||||
/** Centralized error handler for API routes */
|
||||
// TODO: Check of dit weg kan — niet geïmporteerd in de codebase
|
||||
export function handleApiError(error: unknown): Response {
|
||||
if (error instanceof ApiError) {
|
||||
return apiError(error.message, error.status);
|
||||
|
||||
@@ -16,6 +16,7 @@ export function cached<T>(
|
||||
});
|
||||
}
|
||||
|
||||
// TODO: Check of dit weg kan — niet geïmporteerd in de codebase
|
||||
export function bustCache(key: string): void {
|
||||
store.delete(key);
|
||||
}
|
||||
@@ -49,6 +49,7 @@ export class RateLimitError extends DomainError {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Check of dit weg kan — niet geïmporteerd in de codebase
|
||||
export class ConflictError extends DomainError {
|
||||
constructor(message: string) {
|
||||
super(message, 409);
|
||||
|
||||
@@ -30,6 +30,7 @@ export function runWithStore<T>(store: RequestStore, fn: () => T): T {
|
||||
return als.run(store, fn);
|
||||
}
|
||||
|
||||
// TODO: Check of dit weg kan — niet geïmporteerd in de codebase
|
||||
export function getRequestStore(): RequestStore | null {
|
||||
return als.getStore() ?? null;
|
||||
}
|
||||
@@ -38,6 +39,7 @@ export function getRequestId(): RequestId {
|
||||
return als.getStore()?.requestId ?? generateRequestId();
|
||||
}
|
||||
|
||||
// TODO: Check of dit weg kan — niet geïmporteerd in de codebase
|
||||
export function getClientIp(): IpAddress {
|
||||
return als.getStore()?.ip ?? ("0.0.0.0" as IpAddress);
|
||||
}
|
||||
@@ -47,6 +49,7 @@ export function setContextUserId(userId: UserId): void {
|
||||
if (store) store.userId = userId;
|
||||
}
|
||||
|
||||
// TODO: Check of dit weg kan — niet geïmporteerd in de codebase
|
||||
export function elapsed(): number {
|
||||
const store = als.getStore();
|
||||
return store ? Date.now() - store.startedAt : 0;
|
||||
|
||||
@@ -182,6 +182,15 @@ export function canonicalize(input: string): string {
|
||||
return input.normalize("NFC").trim();
|
||||
}
|
||||
|
||||
/** Normalize, trim and truncate a form field value to maxLen (default 255). */
|
||||
export function sanitizeField(
|
||||
value: FormDataEntryValue | null,
|
||||
maxLen = 255,
|
||||
): string {
|
||||
const s = canonicalize(String(value ?? ""));
|
||||
return s.slice(0, maxLen);
|
||||
}
|
||||
|
||||
const INVALID_FILENAME_CHARS = /[<>:"/\\|?*]/;
|
||||
|
||||
function removeControlChars(s: string): string {
|
||||
@@ -193,6 +202,7 @@ function removeControlChars(s: string): string {
|
||||
return result;
|
||||
}
|
||||
|
||||
// TODO: Check of dit weg kan — niet geïmporteerd in de codebase
|
||||
export function sanitizeFilename(name: string): string {
|
||||
return removeControlChars(
|
||||
name
|
||||
@@ -212,6 +222,7 @@ export function canonicalizeFormValue(
|
||||
return maxLen ? s.slice(0, maxLen) : s;
|
||||
}
|
||||
|
||||
// TODO: Check of dit weg kan — niet geïmporteerd in de codebase
|
||||
export function canonicalizeFormData(
|
||||
formData: FormData,
|
||||
fields: Record<string, number | undefined>,
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// TODO: Check of dit bestand weg kan — uitsluitend gebruikt door eigen test
|
||||
import { access, readdir, readFile } from "node:fs/promises";
|
||||
import { dirname, extname, join, relative, resolve, sep } from "node:path";
|
||||
|
||||
|
||||
@@ -1,35 +1,42 @@
|
||||
import type { Variants } from "framer-motion";
|
||||
|
||||
// TODO: Check of dit weg kan — niet geïmporteerd in de codebase
|
||||
export const fadeIn: Variants = {
|
||||
hidden: { opacity: 0 },
|
||||
visible: { opacity: 1, transition: { duration: 0.4 } },
|
||||
};
|
||||
|
||||
// TODO: Check of dit weg kan — niet geïmporteerd in de codebase
|
||||
export const fadeInUp: Variants = {
|
||||
hidden: { opacity: 0, y: 20 },
|
||||
visible: { opacity: 1, y: 0, transition: { duration: 0.4 } },
|
||||
};
|
||||
|
||||
// TODO: Check of dit weg kan — niet geïmporteerd in de codebase
|
||||
export const fadeInDown: Variants = {
|
||||
hidden: { opacity: 0, y: -12 },
|
||||
visible: { opacity: 1, y: 0, transition: { duration: 0.3 } },
|
||||
};
|
||||
|
||||
// TODO: Check of dit weg kan — niet geïmporteerd in de codebase
|
||||
export const fadeInLeft: Variants = {
|
||||
hidden: { opacity: 0, x: -20 },
|
||||
visible: { opacity: 1, x: 0, transition: { duration: 0.35 } },
|
||||
};
|
||||
|
||||
// TODO: Check of dit weg kan — niet geïmporteerd in de codebase
|
||||
export const fadeInRight: Variants = {
|
||||
hidden: { opacity: 0, x: 20 },
|
||||
visible: { opacity: 1, x: 0, transition: { duration: 0.35 } },
|
||||
};
|
||||
|
||||
// TODO: Check of dit weg kan — niet geïmporteerd in de codebase
|
||||
export const scaleIn: Variants = {
|
||||
hidden: { opacity: 0, scale: 0.95 },
|
||||
visible: { opacity: 1, scale: 1, transition: { duration: 0.25 } },
|
||||
};
|
||||
|
||||
// TODO: Check of dit weg kan — niet geïmporteerd in de codebase
|
||||
export const slideUp: Variants = {
|
||||
hidden: { opacity: 0, y: 30 },
|
||||
visible: {
|
||||
@@ -39,6 +46,7 @@ export const slideUp: Variants = {
|
||||
},
|
||||
};
|
||||
|
||||
// TODO: Check of dit weg kan — niet geïmporteerd in de codebase
|
||||
export const staggerContainer: Variants = {
|
||||
hidden: {},
|
||||
visible: {
|
||||
@@ -49,6 +57,7 @@ export const staggerContainer: Variants = {
|
||||
},
|
||||
};
|
||||
|
||||
// TODO: Check of dit weg kan — niet geïmporteerd in de codebase
|
||||
export const staggerItem: Variants = {
|
||||
hidden: { opacity: 0, y: 16 },
|
||||
visible: { opacity: 1, y: 0, transition: { duration: 0.35 } },
|
||||
@@ -103,12 +112,14 @@ export const modalContentVariants: Variants = {
|
||||
exit: { opacity: 0, scale: 0.95, y: 10, transition: { duration: 0.15 } },
|
||||
};
|
||||
|
||||
// TODO: Check of dit weg kan — niet geïmporteerd in de codebase
|
||||
export const hoverScale = {
|
||||
whileHover: { scale: 1.03 },
|
||||
whileTap: { scale: 0.97 },
|
||||
transition: { type: "spring" as const, stiffness: 400, damping: 17 },
|
||||
};
|
||||
|
||||
// TODO: Check of dit weg kan — niet geïmporteerd in de codebase
|
||||
export const hoverLift = {
|
||||
whileHover: { y: -3, transition: { duration: 0.2 } },
|
||||
whileTap: { y: 0 },
|
||||
|
||||
@@ -33,9 +33,7 @@ export async function redisCache<T>(
|
||||
return fresh;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidate a cached key. No-op if Redis is unavailable.
|
||||
*/
|
||||
// TODO: Check of dit weg kan — niet geïmporteerd in de codebase
|
||||
export async function invalidateCache(key: string): Promise<void> {
|
||||
if (!redis) return;
|
||||
try {
|
||||
|
||||
Reference in new issue
Block a user