From a39c4fa26d6e0dc5ae9466e484e6e93e012172e2 Mon Sep 17 00:00:00 2001 From: Leo dev Date: Tue, 23 Dec 2025 15:24:59 +0100 Subject: [PATCH] Working supabase structure --- src/actions/get-profile.ts | 43 +++++++++- src/actions/get-session.ts | 2 +- src/actions/login-server.ts | 2 +- src/app/api/auth/route.ts | 83 ------------------- src/app/api/profile/route.ts | 115 --------------------------- src/app/api/user/route.ts | 22 ----- src/components/settings/Settings.tsx | 3 +- src/hooks/use-app.ts | 13 ++- src/lib/auth.ts | 5 +- src/lib/supa.ts | 24 ------ 10 files changed, 52 insertions(+), 260 deletions(-) delete mode 100644 src/app/api/profile/route.ts delete mode 100644 src/lib/supa.ts diff --git a/src/actions/get-profile.ts b/src/actions/get-profile.ts index 168878d..be1577c 100644 --- a/src/actions/get-profile.ts +++ b/src/actions/get-profile.ts @@ -1,8 +1,11 @@ "use server"; -import createClient from "@/lib/supa"; +import createClient from "@/actions/supa"; +import { ProfileSettings } from "@/types/settings"; +import getSession from "./get-session"; +import { UserProfile } from "@/hooks/get-user"; -export async function getProfileById(id: string) { +export async function getProfileById(id: string): Promise { const supabase = await createClient(); const { error, data } = await supabase @@ -17,3 +20,39 @@ export async function getProfileById(id: string) { return data; } + +export async function getProfileByUsername( + username: string +): Promise { + const supabase = await createClient(); + + const { error, data } = await supabase + .from("profiles") + .select("id, username, display_name, avatar_url, node_address") + .eq("username", username) + .maybeSingle(); + + if (error) { + throw error; + } + + return data; +} + +export async function updateProfile(profile: ProfileSettings) { + const supabase = await createClient(); + const user_id = await getSession(); + + if (!user_id) { + throw new Error("User id invalid"); + } + + const { error } = await supabase + .from("profiles") + .update(profile) + .eq("id", user_id); + + if (error) { + throw error; + } +} diff --git a/src/actions/get-session.ts b/src/actions/get-session.ts index 6b2bc78..1b48ff3 100644 --- a/src/actions/get-session.ts +++ b/src/actions/get-session.ts @@ -1,6 +1,6 @@ "use server"; -import createClient from "@/lib/supa"; +import createClient from "@/actions/supa"; export default async function getSession() { const supabase = await createClient(); diff --git a/src/actions/login-server.ts b/src/actions/login-server.ts index c0d2063..ea358c6 100644 --- a/src/actions/login-server.ts +++ b/src/actions/login-server.ts @@ -1,6 +1,6 @@ "use server"; -import createClient from "@/lib/supa"; +import createClient from "@/actions/supa"; export default async function loginServer(email: string, password: string) { const supabase = await createClient(); diff --git a/src/app/api/auth/route.ts b/src/app/api/auth/route.ts index 55b1387..5be2a90 100644 --- a/src/app/api/auth/route.ts +++ b/src/app/api/auth/route.ts @@ -49,86 +49,3 @@ export async function GET(req: NextRequest) { return NextResponse.json({ message: "ok", ...auth }); } - -/** - * POST /api/auth - * Called by the client to request a temporary relay token for a DM server. - * - * Body: { server_id: string } - * Header: Authorization: Bearer - */ -export async function POST(req: NextRequest) { - const { server_id } = await req.json(); - const authHeader = req.cookies.get("token"); - - if (!server_id) - return NextResponse.json( - { message: "Missing server_id in the json body" }, - { status: StatusCodes.BAD_REQUEST } - ); - - if (!authHeader) - return NextResponse.json( - { message: "Missing Supabase Authorization header" }, - { status: StatusCodes.BAD_REQUEST } - ); - - const { - data: { user }, - error, - } = await supabase.auth.getUser(authHeader.value); - - if (error || !user) { - return NextResponse.json( - { message: "Invalid Supabase token" }, - { status: StatusCodes.UNAUTHORIZED } - ); - } - - const { data: relayToken, error: errorRelay } = await supabase - .from("server_auth") - .insert({ - user_id: user.id, - server_id, - }) - .select() - .maybeSingle(); - - if (!relayToken || errorRelay) - return NextResponse.json( - { message: "Failed to create relay token" }, - { status: StatusCodes.INTERNAL_SERVER_ERROR } - ); - - return NextResponse.json({ message: "ok", token: relayToken.key }); -} - -/** - * PUT /api/auth - * Called by the client to refresh the access token. - */ -export async function PUT(req: NextRequest) { - const refresh_token = req.cookies.get("refresh_token")?.value; - - if (!refresh_token) - return NextResponse.json( - { message: "Missing refresh_token cookie" }, - { status: StatusCodes.BAD_REQUEST } - ); - - const session = await supabase.auth.refreshSession({ refresh_token }); - - if (session.error) - return NextResponse.json( - { - message: session.error.message, - }, - { status: StatusCodes.INTERNAL_SERVER_ERROR } - ); - - return NextResponse.json({ - message: "ok", - access_token: session.data.session?.access_token, - refresh_token: session.data.session?.refresh_token, - }); -} diff --git a/src/app/api/profile/route.ts b/src/app/api/profile/route.ts deleted file mode 100644 index dcf9960..0000000 --- a/src/app/api/profile/route.ts +++ /dev/null @@ -1,115 +0,0 @@ -import { StatusCodes } from "http-status-codes"; -import { NextRequest, NextResponse } from "next/server"; -import { supabase } from "../supa"; -import { ProfileSettings } from "@/types/settings"; - -/** - * POST /api/profile - * body { username, display_name, avatar_url } - */ -export async function POST(req: NextRequest) { - const url = new URL(req.url); - const token = req.cookies.get("token")?.value; - const { username, display_name, avatar_url, node_address } = - (await req.json()) as ProfileSettings; - - if (!token) - return NextResponse.json( - { message: "Token cookie not found" }, - { status: StatusCodes.BAD_REQUEST } - ); - - if ( - !username || - !display_name || - avatar_url === undefined || - avatar_url === null || - node_address === undefined || - node_address === null - ) - return NextResponse.json( - { - message: - "Invalid body, requires username, display_name, avatar_url, node_address", - }, - { status: StatusCodes.BAD_REQUEST } - ); - - const { - data: { user }, - } = await supabase.auth.getUser(token); - - if (!user) - return NextResponse.json( - { message: "Invalid token" }, - { status: StatusCodes.NOT_FOUND } - ); - - const { error } = await supabase - .from("profiles") - .update({ - username, - display_name, - avatar_url, - node_address, - }) - .eq("id", user.id); - - if (error) { - return NextResponse.json( - { message: error.message }, - { status: StatusCodes.INTERNAL_SERVER_ERROR } - ); - } - - return NextResponse.json({ message: "ok" }); -} - -/** - * GET /api/profile?id= - * or cookie-based lookup - */ -export async function GET(req: NextRequest) { - const url = new URL(req.url); - const id = url.searchParams.get("id"); - const username = url.searchParams.get("username"); - const token = req.cookies.get("token")?.value; - - if (!token && !id && !username) - return NextResponse.json( - { message: "Query arg should be token or id or username" }, - { status: StatusCodes.BAD_REQUEST } - ); - - const { data: profile, error } = id - ? await supabase - .from("profiles") - .select("id, username, display_name, avatar_url, node_address") - .eq("id", id) - .maybeSingle() - : username - ? await supabase - .from("profiles") - .select("id, username, display_name, avatar_url, node_address") - .eq("username", username) - .maybeSingle() - : await supabase - .from("profiles") - .select("id, username, display_name, avatar_url, node_address") - .eq("id", (await supabase.auth.getUser(token)).data.user?.id) - .maybeSingle(); - - if (error) - return NextResponse.json( - { message: error.message }, - { status: StatusCodes.INTERNAL_SERVER_ERROR } - ); - - if (!profile) - return NextResponse.json( - { message: "Profile not found" }, - { status: StatusCodes.NOT_FOUND } - ); - - return NextResponse.json({ message: "ok", ...profile }); -} diff --git a/src/app/api/user/route.ts b/src/app/api/user/route.ts index 11e57fd..e6b81b2 100644 --- a/src/app/api/user/route.ts +++ b/src/app/api/user/route.ts @@ -98,25 +98,3 @@ export async function GET(req: NextRequest) { return res; } - -/** - * DELETE /api/auth - * Body: { username } - */ -export async function DELETE(req: NextRequest) { - const { username } = await req.json(); - - // Delete both profile + auth user - const { data: profile } = await supabase - .from("profiles") - .select("id") - .eq("username", username) - .maybeSingle(); - - if (profile) { - await supabase.auth.admin.deleteUser(profile.id); - await supabase.from("profiles").delete().eq("id", profile.id); - } - - return NextResponse.json({ message: "ok" }); -} diff --git a/src/components/settings/Settings.tsx b/src/components/settings/Settings.tsx index 78b02f2..1547981 100644 --- a/src/components/settings/Settings.tsx +++ b/src/components/settings/Settings.tsx @@ -14,6 +14,7 @@ import { useRouter } from "next/navigation"; import axios from "axios"; import { useClientSettings } from "@/hooks/use-settings"; import { useState } from "react"; +import { updateProfile } from "@/actions/get-profile"; export default function Settings({ tab, @@ -55,7 +56,7 @@ export default function Settings({ setSettings={setProfileSettings} schema={PROFILE_SCHEMA} onSave={async () => { - await axios.post("/api/profile", profileSettings); + await updateProfile(profileSettings); }} /> diff --git a/src/hooks/use-app.ts b/src/hooks/use-app.ts index 141ada0..6ca9fe3 100644 --- a/src/hooks/use-app.ts +++ b/src/hooks/use-app.ts @@ -8,6 +8,7 @@ import { get, Response } from "@/lib/request"; import { Channel, Server } from "@/types/types"; import Cookies from "js-cookie"; import { toast } from "sonner"; +import { getProfileById } from "@/actions/get-profile"; export default function useApp(): App { const node = useRef(null); @@ -58,17 +59,13 @@ export default function useApp(): App { getUserById: async (id: string) => { if (profiles[id] !== undefined) return profiles[id]; - const onResponse = (res: Response) => { + try { + const user = await getProfileById(id); setProfiles((prev) => { - prev[id] = res.data as UserProfile; + prev[id] = user; return prev; }); - }; - - try { - const user = await get(`/api/profile/?id=${id}`, onResponse); - onResponse(user); - return user.data; + return user; } catch { return null; } diff --git a/src/lib/auth.ts b/src/lib/auth.ts index 4f95497..aa703b6 100644 --- a/src/lib/auth.ts +++ b/src/lib/auth.ts @@ -5,6 +5,7 @@ import { get } from "./request"; import { toast } from "sonner"; import { MessageStore } from "@/hooks/use-messages"; import { IndicatorContext, ServerMessage } from "@/types/protocol"; +import { authRelay } from "@/actions/auth"; type AuthParams = { id: string; @@ -30,9 +31,7 @@ export default async function auth({ const ip = ((await get(`/api/server/${id}`)).data as any).address as string; console.log("Authenticating with server at:", ip); - const server_auth = ( - (await axios.post("/api/auth", { server_id: id })).data as any - ).token; + const server_auth = await authRelay(id); var name = id; diff --git a/src/lib/supa.ts b/src/lib/supa.ts deleted file mode 100644 index 5c7f41e..0000000 --- a/src/lib/supa.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { cookies } from "next/headers"; -import { createServerClient } from "@supabase/ssr"; - -export default async function createClient() { - const cookieStore = await cookies(); - - return createServerClient( - process.env.NEXT_PUBLIC_SUPABASE_URL!, - process.env.SUPABASE_SERVICE_ROLE_KEY!, - { - cookies: { - get(name) { - return cookieStore.get(name)?.value; - }, - set(name, value) { - cookieStore.set(name, value); - }, - remove(name) { - cookieStore.delete(name); - }, - }, - } - ); -}