From c274ea9036ec5a426439c292a9ce2a4e63397f75 Mon Sep 17 00:00:00 2001 From: Oliver Bryan <04oliverbryan@gmail.com> Date: Wed, 31 Dec 2025 19:09:24 +0000 Subject: [PATCH] update user backend + frontend server function --- packages/backend/src/db/queries/users.ts | 10 ++++- packages/backend/src/index.ts | 9 ++++- packages/backend/src/routes/index.ts | 19 +++++---- .../src/routes/organisation/by-user.ts | 2 +- packages/backend/src/routes/user/update.ts | 30 ++++++++++++++ .../frontend/src/lib/server/user/index.ts | 1 + .../frontend/src/lib/server/user/update.ts | 39 +++++++++++++++++++ 7 files changed, 99 insertions(+), 11 deletions(-) create mode 100644 packages/backend/src/routes/user/update.ts create mode 100644 packages/frontend/src/lib/server/user/index.ts create mode 100644 packages/frontend/src/lib/server/user/update.ts diff --git a/packages/backend/src/db/queries/users.ts b/packages/backend/src/db/queries/users.ts index 737b4a1..3c8b975 100644 --- a/packages/backend/src/db/queries/users.ts +++ b/packages/backend/src/db/queries/users.ts @@ -1,4 +1,4 @@ -import { User } from "@issue/shared"; +import { User, type UserRecord } from "@issue/shared"; import { eq } from "drizzle-orm"; import { db } from "../client"; @@ -16,3 +16,11 @@ export async function getUserByUsername(username: string) { const [user] = await db.select().from(User).where(eq(User.username, username)); return user; } + +export async function updateById( + id: number, + updates: { name?: string; passwordHash?: string; serverURL?: string }, +): Promise { + const [user] = await db.update(User).set(updates).where(eq(User.id, id)).returning(); + return user; +} diff --git a/packages/backend/src/index.ts b/packages/backend/src/index.ts index d4a8a4a..8f7ca9f 100644 --- a/packages/backend/src/index.ts +++ b/packages/backend/src/index.ts @@ -17,15 +17,17 @@ const main = async () => { "/auth/login": withCors(routes.authLogin), "/auth/me": withCors(withAuth(routes.authMe)), + "/user/update": withCors(withAuth(routes.userUpdate)), + "/issue/create": withCors(withAuth(routes.issueCreate)), "/issue/update": withCors(withAuth(routes.issueUpdate)), "/issue/delete": withCors(withAuth(routes.issueDelete)), + "/issues/by-project": withCors(withAuth(routes.issuesByProject)), "/issues/all": withCors(withAuth(routes.issues)), "/organisation/create": withCors(withAuth(routes.organisationCreate)), "/organisation/by-id": withCors(withAuth(routes.organisationById)), - "/organisations/by-user": withCors(withAuth(routes.organisationByUser)), "/organisation/update": withCors(withAuth(routes.organisationUpdate)), "/organisation/delete": withCors(withAuth(routes.organisationDelete)), "/organisation/add-member": withCors(withAuth(routes.organisationAddMember)), @@ -33,14 +35,17 @@ const main = async () => { "/organisation/remove-member": withCors(withAuth(routes.organisationRemoveMember)), "/organisation/update-member-role": withCors(withAuth(routes.organisationUpdateMemberRole)), + "/organisations/by-user": withCors(withAuth(routes.organisationsByUser)), + "/project/create": withCors(withAuth(routes.projectCreate)), "/project/update": withCors(withAuth(routes.projectUpdate)), "/project/delete": withCors(withAuth(routes.projectDelete)), + "/project/with-creator": withCors(withAuth(routes.projectWithCreator)), + "/projects/by-creator": withCors(withAuth(routes.projectsByCreator)), "/projects/by-organisation": withCors(withAuth(routes.projectsByOrganisation)), "/projects/all": withCors(withAuth(routes.projectsAll)), "/projects/with-creators": withCors(withAuth(routes.projectsWithCreators)), - "/project/with-creator": withCors(withAuth(routes.projectWithCreator)), }, }); diff --git a/packages/backend/src/routes/index.ts b/packages/backend/src/routes/index.ts index ae57508..4daf7df 100644 --- a/packages/backend/src/routes/index.ts +++ b/packages/backend/src/routes/index.ts @@ -8,7 +8,7 @@ import issues from "./issues/all"; import issuesByProject from "./issues/by-project"; import organisationAddMember from "./organisation/add-member"; import organisationById from "./organisation/by-id"; -import organisationByUser from "./organisation/by-user"; +import organisationsByUser from "./organisation/by-user"; import organisationCreate from "./organisation/create"; import organisationDelete from "./organisation/delete"; import organisationMembers from "./organisation/members"; @@ -23,8 +23,15 @@ import projectDelete from "./project/delete"; import projectUpdate from "./project/update"; import projectWithCreator from "./project/with-creator"; import projectsWithCreators from "./project/with-creators"; +import userUpdate from "./user/update"; export const routes = { + authRegister, + authLogin, + authMe, + + userUpdate, + issueCreate, issueDelete, issueUpdate, @@ -34,7 +41,6 @@ export const routes = { organisationCreate, organisationById, - organisationByUser, organisationUpdate, organisationDelete, organisationAddMember, @@ -42,16 +48,15 @@ export const routes = { organisationRemoveMember, organisationUpdateMemberRole, + organisationsByUser, + projectCreate, projectUpdate, projectDelete, + projectWithCreator, + projectsByCreator, projectsByOrganisation, projectsAll, projectsWithCreators, - projectWithCreator, - - authRegister, - authLogin, - authMe, }; diff --git a/packages/backend/src/routes/organisation/by-user.ts b/packages/backend/src/routes/organisation/by-user.ts index 0bf8dce..04e0194 100644 --- a/packages/backend/src/routes/organisation/by-user.ts +++ b/packages/backend/src/routes/organisation/by-user.ts @@ -1,7 +1,7 @@ import type { AuthedRequest } from "../../auth/middleware"; import { getOrganisationsByUserId, getUserById } from "../../db/queries"; -// /organisation/by-user?userId=1 +// /organisations/by-user?userId=1 export default async function organisationsByUser(req: AuthedRequest) { const url = new URL(req.url); const userId = url.searchParams.get("userId"); diff --git a/packages/backend/src/routes/user/update.ts b/packages/backend/src/routes/user/update.ts new file mode 100644 index 0000000..dabe7d7 --- /dev/null +++ b/packages/backend/src/routes/user/update.ts @@ -0,0 +1,30 @@ +import type { UserRecord } from "@issue/shared"; +import type { AuthedRequest } from "../../auth/middleware"; +import { getUserById } from "../../db/queries"; + +// /user/update?id=1&name=NewName&passwordHash=NewHash&serverURL=NewURL +export default async function update(req: AuthedRequest) { + const url = new URL(req.url); + const id = url.searchParams.get("id"); + if (!id) { + return new Response("id is required", { status: 400 }); + } + + const user = await getUserById(Number(id)); + if (!user) { + return new Response("user not found", { status: 404 }); + } + + const name = url.searchParams.get("name") || undefined; + const passwordHash = url.searchParams.get("passwordHash") || undefined; + const serverURL = url.searchParams.get("serverURL") || undefined; + + const { updateById } = await import("../../db/queries/users"); + const updatedUser = await updateById(user.id, { name, passwordHash, serverURL }); + + if (!updatedUser) { + return new Response("failed to update user", { status: 500 }); + } + + return Response.json(updatedUser as UserRecord); +} diff --git a/packages/frontend/src/lib/server/user/index.ts b/packages/frontend/src/lib/server/user/index.ts new file mode 100644 index 0000000..f4df357 --- /dev/null +++ b/packages/frontend/src/lib/server/user/index.ts @@ -0,0 +1 @@ +export { update } from "./update"; diff --git a/packages/frontend/src/lib/server/user/update.ts b/packages/frontend/src/lib/server/user/update.ts new file mode 100644 index 0000000..3078d7c --- /dev/null +++ b/packages/frontend/src/lib/server/user/update.ts @@ -0,0 +1,39 @@ +import { getAuthHeaders, getServerURL } from "@/lib/utils"; +import type { ServerQueryInput } from ".."; + +export async function update({ + id, + name, + password, + serverURL, + onSuccess, + onError, +}: { + id: number; + name: string; + password: string; + serverURL: string; +} & ServerQueryInput) { + const url = new URL(`${getServerURL()}/user/update`); + url.searchParams.set("id", `${id}`); + url.searchParams.set("name", name.trim()); + url.searchParams.set("password", password.trim()); + url.searchParams.set("serverURL", serverURL.trim()); + + const res = await fetch(url.toString(), { + headers: getAuthHeaders(), + }); + + if (!res.ok) { + const error = await res.text(); + onError?.(error || `failed to update user (${res.status})`); + } else { + const data = await res.json(); + if (!data.id) { + onError?.(`failed to update user (${res.status})`); + return; + } + + onSuccess?.(data, res); + } +}