diff --git a/app/api/auth/me/route.ts b/app/api/auth/me/route.ts deleted file mode 100644 index f187b283..00000000 --- a/app/api/auth/me/route.ts +++ /dev/null @@ -1,65 +0,0 @@ -// app/api/auth/me/route.ts -import { NextRequest, NextResponse } from "next/server"; - -const DIRECTUS_URL = process.env.DIRECTUS_URL!; -const ACCESS_COOKIE = "ma_at"; - -export const runtime = "nodejs"; - -/** - * GET /api/auth/me - * Returns the current Directus user using the access token in "ma_at". - * Mirrors the shape you’re already expecting on the client: - * { id, username, display_name, first_name, last_name, email, ... } - */ -export async function GET(_req: NextRequest) { - try { - if (!DIRECTUS_URL) { - return NextResponse.json({ error: "Missing DIRECTUS_URL" }, { status: 500 }); - } - - // Prefer cookie; allow Authorization header for flexibility - const cookie = _req.cookies.get(ACCESS_COOKIE)?.value; - const authHeader = _req.headers.get("authorization") || ""; - const bearer = - authHeader?.toLowerCase().startsWith("bearer ") - ? authHeader.slice(7).trim() - : cookie; - - if (!bearer) { - // No token: treat as not signed in (same semantics as your client) - return NextResponse.json({ error: "not-signed-in" }, { status: 401 }); - } - - const url = `${DIRECTUS_URL}/users/me?fields=id,username,display_name,first_name,last_name,email`; - - const res = await fetch(url, { - headers: { - Accept: "application/json", - Authorization: `Bearer ${bearer}`, - }, - cache: "no-store", - }); - - const text = await res.text(); - let json: any = null; - try { - json = text ? JSON.parse(text) : null; - } catch { - // non-JSON from Directus; keep raw text for error messages - } - - if (!res.ok) { - const msg = json?.errors?.[0]?.message || json?.error || text || "Directus error"; - const status = res.status === 401 || res.status === 403 ? res.status : 500; - return NextResponse.json({ error: msg }, { status }); - } - - // Directus often wraps in { data: {...} } - const data = json?.data ?? json ?? null; - return NextResponse.json(data ?? {}, { status: 200 }); - } catch (err: any) { - const msg = err?.message || "Failed to fetch current user"; - return NextResponse.json({ error: msg }, { status: 500 }); - } -} diff --git a/app/api/bgremove/methods/route.ts b/app/api/bgremove/methods/route.ts deleted file mode 100644 index 2b8e9ddf..00000000 --- a/app/api/bgremove/methods/route.ts +++ /dev/null @@ -1,25 +0,0 @@ -export const runtime = "nodejs"; -export const dynamic = "force-dynamic"; - -const BGBYE_URL = - process.env.BGBYE_URL || - process.env.BG_BYE_URL || - process.env.BGREMOVER_BASE_URL || - "http://bgbye:7001"; - -export async function GET() { - try { - const r = await fetch(`${BGBYE_URL}/methods`, { cache: "no-store" }); - const body = await r.text(); - return new Response(body, { - status: r.status, - headers: { "content-type": r.headers.get("content-type") || "application/json" }, - }); - } catch { - return new Response(JSON.stringify({ methods: [] }), { - status: 200, - headers: { "content-type": "application/json" }, - }); - } -} - diff --git a/app/api/files/download-file/route.ts b/app/api/files/download-file/route.ts deleted file mode 100644 index 0a7fab9f..00000000 --- a/app/api/files/download-file/route.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { NextResponse } from 'next/server'; -import path from 'node:path'; -import fs from 'node:fs/promises'; - -const BASE_DIR = '/app/files'; - -export async function GET(req: Request) { - try { - const url = new URL(req.url); - const raw = url.searchParams.get('path'); - if (!raw) { - return NextResponse.json({ error: 'Missing path' }, { status: 400 }); - } - const safe = path.normalize('/' + raw).replace(/^\/+/, '/'); - const target = path.resolve(BASE_DIR, '.' + safe); - - if (!target.startsWith(BASE_DIR)) { - return NextResponse.json({ error: 'Invalid path' }, { status: 400 }); - } - - const st = await fs.stat(target).catch(() => null); - if (!st || !st.isFile()) { - return NextResponse.json({ error: 'Not a file' }, { status: 400 }); - } - - const data = await fs.readFile(target); - // naive content-type guess - const ext = path.extname(target).toLowerCase(); - const ctype = - ext === '.pdf' ? 'application/pdf' : - ext === '.png' ? 'image/png' : - ext === '.jpg' || ext === '.jpeg' ? 'image/jpeg' : - ext === '.webp' ? 'image/webp' : - ext === '.txt' ? 'text/plain; charset=utf-8' : - 'application/octet-stream'; - - return new Response(data, { - headers: { - 'Content-Type': ctype, - 'Content-Length': String(data.byteLength), - 'Content-Disposition': `inline; filename="${path.basename(target)}"`, - 'Cache-Control': 'no-store', - } - }); - } catch (e: any) { - return NextResponse.json({ error: e?.message ?? 'Unknown error' }, { status: 500 }); - } -} diff --git a/app/api/files/get/route.ts b/app/api/files/get/route.ts deleted file mode 100644 index 9e149f9c..00000000 --- a/app/api/files/get/route.ts +++ /dev/null @@ -1,50 +0,0 @@ -import { NextResponse } from "next/server"; -import fs from "node:fs/promises"; -import path from "node:path"; - -export const runtime = "nodejs"; -export const dynamic = "force-dynamic"; - -const BASE = "/app/files"; - -function safeJoin(base: string, reqPath: string) { - const rel = reqPath.startsWith("/") ? reqPath : `/${reqPath}`; - const full = path.resolve(base, "." + rel); - if (!full.startsWith(base)) throw new Error("Outside base"); - return full; -} - -const CONTENT_MAP: Record = { - ".png": "image/png", - ".jpg": "image/jpeg", - ".jpeg": "image/jpeg", - ".gif": "image/gif", - ".webp": "image/webp", - ".svg": "image/svg+xml", - ".txt": "text/plain; charset=utf-8", - ".json": "application/json; charset=utf-8", - ".pdf": "application/pdf", -}; - -export async function GET(req: Request) { - try { - const url = new URL(req.url); - const reqPath = url.searchParams.get("path"); - if (!reqPath) return NextResponse.json({ error: "Missing path" }, { status: 400 }); - - const full = safeJoin(BASE, reqPath); - const stat = await fs.stat(full); - if (!stat.isFile()) return NextResponse.json({ error: "Not a file" }, { status: 400 }); - - const data = await fs.readFile(full); - const ext = path.extname(full).toLowerCase(); - const type = CONTENT_MAP[ext] ?? "application/octet-stream"; - - return new NextResponse(data, { - status: 200, - headers: { "Content-Type": type, "Cache-Control": "public, max-age=300" }, - }); - } catch (e: any) { - return NextResponse.json({ error: e?.message ?? "Unknown" }, { status: 400 }); - } -} diff --git a/app/api/files/list-files/route.ts b/app/api/files/list-files/route.ts deleted file mode 100644 index dc959e80..00000000 --- a/app/api/files/list-files/route.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { NextResponse } from 'next/server'; -import path from 'node:path'; -import fs from 'node:fs/promises'; - -const BASE_DIR = '/app/files'; - -export async function GET(req: Request) { - try { - const url = new URL(req.url); - const raw = url.searchParams.get('path') ?? '/'; - const safe = path.normalize('/' + raw).replace(/^\/+/, '/'); // normalize & ensure leading slash - const target = path.resolve(BASE_DIR, '.' + safe); - - if (!target.startsWith(BASE_DIR)) { - return NextResponse.json({ error: 'Invalid path' }, { status: 400 }); - } - - const st = await fs.stat(target).catch(() => null); - if (!st || !st.isDirectory()) { - return NextResponse.json({ error: 'Not a directory' }, { status: 400 }); - } - - const entries = await fs.readdir(target, { withFileTypes: true }); - const items = await Promise.all(entries.map(async (d) => { - const full = path.join(target, d.name); - const rel = path.posix.join(safe, d.name).replaceAll('\\', '/'); - const s = await fs.stat(full); - return { - name: d.name, - path: rel, - type: d.isDirectory() ? 'dir' : 'file', - size: s.size, - mtime: s.mtimeMs, - }; - })); - - return NextResponse.json({ path: safe, items }); - } catch (e: any) { - return NextResponse.json({ error: e?.message ?? 'Unknown error' }, { status: 500 }); - } -} diff --git a/app/api/files/route.ts b/app/api/files/route.ts deleted file mode 100644 index 4ff1ea0c..00000000 --- a/app/api/files/route.ts +++ /dev/null @@ -1,50 +0,0 @@ -import { NextResponse } from "next/server"; -import fs from "node:fs/promises"; -import fssync from "node:fs"; -import path from "node:path"; - -const BASE = "/app/files"; // this is /var/www/makearmy.io/app/files on the host - -function safeJoin(base: string, reqPath: string) { - const decoded = decodeURIComponent(reqPath || "/"); - // normalize, strip traversal, and join under BASE - const normalized = path.posix.normalize("/" + decoded).replace(/^(\.\.(\/|\\|$))+/g, ""); - const full = path.join(base, normalized); - if (!full.startsWith(base)) throw new Error("Invalid path"); - return full; -} - -export async function GET(req: Request) { - try { - const { searchParams } = new URL(req.url); - const p = searchParams.get("path") || "/"; - const abs = safeJoin(BASE, p); - - const entries = await fs.readdir(abs, { withFileTypes: true }); - const rows = await Promise.all(entries.map(async (ent) => { - const full = path.join(abs, ent.name); - const stat = await fs.stat(full); - const isDir = ent.isDirectory(); - return { - name: ent.name, - type: isDir ? "dir" : "file", - size: isDir ? null : stat.size, - mtime: stat.mtime.toISOString(), - path: path.posix.join(p.endsWith("/") ? p : p + "/", ent.name), - // raw download/view URL (served by /api/files/raw) - url: isDir ? null : `/api/files/raw?path=${encodeURIComponent(path.posix.join(p, ent.name))}`, - }; - })); - - // Sort: directories first, then files alphabetically - rows.sort((a, b) => { - if (a.type !== b.type) return a.type === "dir" ? -1 : 1; - return a.name.localeCompare(b.name, undefined, { sensitivity: "base" }); - }); - - return NextResponse.json({ ok: true, path: p, items: rows }); - } catch (err: any) { - return NextResponse.json({ ok: false, error: err?.message || "Error" }, { status: 400 }); - } -} - diff --git a/app/api/health/directus/route.ts b/app/api/health/directus/route.ts deleted file mode 100644 index 24aeb8c2..00000000 --- a/app/api/health/directus/route.ts +++ /dev/null @@ -1,38 +0,0 @@ -// app/api/health/directus/route.ts -import { NextResponse } from "next/server"; -import { directusFetch } from "@/lib/directus"; - -export const runtime = "nodejs"; - -export async function GET() { - const out: any = { ok: true, checks: {} }; - try { - // who am I? - try { - const who = await directusFetch<{ data: any }>(`/users/me?fields=id,email,role.name`); - out.checks.user = { ok: true, role: who?.data?.role?.name ?? null }; - } catch (e: any) { - out.checks.user = { ok: false, error: e?.message || String(e) }; - } - - // can read folders? - try { - const folders = await directusFetch<{ data: any[] }>(`/folders?limit=1&fields=id,name`); - out.checks.folders = { ok: true, sample: folders?.data?.[0] ?? null }; - } catch (e: any) { - out.checks.folders = { ok: false, error: e?.message || String(e) }; - } - - // can read files (not create; safe) - try { - const files = await directusFetch<{ data: any[] }>(`/files?limit=0`); - out.checks.files_read = { ok: true, totalKnown: files?.data?.length ?? 0 }; - } catch (e: any) { - out.checks.files_read = { ok: false, error: e?.message || String(e) }; - } - - return NextResponse.json(out); - } catch (e: any) { - return NextResponse.json({ ok: false, error: e?.message || "health error", ...out }, { status: 500 }); - } -} diff --git a/app/api/health/options/route.ts b/app/api/health/options/route.ts deleted file mode 100644 index 1efc79ba..00000000 --- a/app/api/health/options/route.ts +++ /dev/null @@ -1,28 +0,0 @@ -// app/api/health/options/route.ts -import { NextResponse } from "next/server"; -import { directusFetch } from "@/lib/directus"; - -const TESTS = [ - { name: "material", path: "/items/material?limit=1" }, -{ name: "material_coating", path: "/items/material_coating?limit=1" }, -{ name: "material_color", path: "/items/material_color?limit=1" }, -{ name: "material_opacity", path: "/items/material_opacity?limit=1" }, -{ name: "laser_software", path: "/items/laser_software?limit=1" }, -{ name: "laser_source", path: "/items/laser_source?limit=1" }, -{ name: "laser_scan_lens", path: "/items/laser_scan_lens?limit=1" }, -{ name: "laser_focusing_lens",path: "/items/laser_focusing_lens?limit=1" }, -]; - -export async function GET() { - const results: any[] = []; - for (const t of TESTS) { - try { - const { data } = await directusFetch<{ data: any[] }>(t.path); - const first = data?.[0] ?? null; - results.push({ name: t.name, ok: true, sample_id: first?.submission_id ?? first?.id ?? null }); - } catch (e: any) { - results.push({ name: t.name, ok: false, error: e?.message || String(e) }); - } - } - return NextResponse.json({ ok: true, results }); -} diff --git a/app/components/toolkit/ToolShell.tsx b/app/components/toolkit/ToolShell.tsx deleted file mode 100644 index d950fbae..00000000 --- a/app/components/toolkit/ToolShell.tsx +++ /dev/null @@ -1,35 +0,0 @@ -// /var/www/makearmy.io/app/components/toolkit/ToolShell.tsx -"use client"; - -import Link from "next/link"; - -export default function ToolShell({ - title, - subtitle, - children, -}: { - title: string; - subtitle?: string; - children: React.ReactNode; -}) { - return ( -
-
-
-

{title}

- {subtitle && ( -

{subtitle}

- )} -
- - Back to Main Menu - -
- {children} -
- ); -} - diff --git a/app/submit/settings/page.tsx b/app/submit/settings/page.tsx index 126cec4d..f4124034 100644 --- a/app/submit/settings/page.tsx +++ b/app/submit/settings/page.tsx @@ -1,5 +1,5 @@ import { Suspense } from "react"; -import SettingsSubmit from "@/app/components/forms/SettingsSubmit"; +import SettingsSubmit from "@/components/forms/SettingsSubmit"; export const dynamic = "force-dynamic"; // keeps this page from being statically prerendered diff --git a/app/components/forms/SettingsSubmit.tsx b/components/forms/SettingsSubmit.tsx similarity index 100% rename from app/components/forms/SettingsSubmit.tsx rename to components/forms/SettingsSubmit.tsx