update user backend + frontend server function

This commit is contained in:
Oliver Bryan
2025-12-31 19:09:24 +00:00
parent 435540f158
commit c274ea9036
7 changed files with 99 additions and 11 deletions

View File

@@ -1,4 +1,4 @@
import { User } from "@issue/shared"; import { User, type UserRecord } from "@issue/shared";
import { eq } from "drizzle-orm"; import { eq } from "drizzle-orm";
import { db } from "../client"; 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)); const [user] = await db.select().from(User).where(eq(User.username, username));
return user; return user;
} }
export async function updateById(
id: number,
updates: { name?: string; passwordHash?: string; serverURL?: string },
): Promise<UserRecord | undefined> {
const [user] = await db.update(User).set(updates).where(eq(User.id, id)).returning();
return user;
}

View File

@@ -17,15 +17,17 @@ const main = async () => {
"/auth/login": withCors(routes.authLogin), "/auth/login": withCors(routes.authLogin),
"/auth/me": withCors(withAuth(routes.authMe)), "/auth/me": withCors(withAuth(routes.authMe)),
"/user/update": withCors(withAuth(routes.userUpdate)),
"/issue/create": withCors(withAuth(routes.issueCreate)), "/issue/create": withCors(withAuth(routes.issueCreate)),
"/issue/update": withCors(withAuth(routes.issueUpdate)), "/issue/update": withCors(withAuth(routes.issueUpdate)),
"/issue/delete": withCors(withAuth(routes.issueDelete)), "/issue/delete": withCors(withAuth(routes.issueDelete)),
"/issues/by-project": withCors(withAuth(routes.issuesByProject)), "/issues/by-project": withCors(withAuth(routes.issuesByProject)),
"/issues/all": withCors(withAuth(routes.issues)), "/issues/all": withCors(withAuth(routes.issues)),
"/organisation/create": withCors(withAuth(routes.organisationCreate)), "/organisation/create": withCors(withAuth(routes.organisationCreate)),
"/organisation/by-id": withCors(withAuth(routes.organisationById)), "/organisation/by-id": withCors(withAuth(routes.organisationById)),
"/organisations/by-user": withCors(withAuth(routes.organisationByUser)),
"/organisation/update": withCors(withAuth(routes.organisationUpdate)), "/organisation/update": withCors(withAuth(routes.organisationUpdate)),
"/organisation/delete": withCors(withAuth(routes.organisationDelete)), "/organisation/delete": withCors(withAuth(routes.organisationDelete)),
"/organisation/add-member": withCors(withAuth(routes.organisationAddMember)), "/organisation/add-member": withCors(withAuth(routes.organisationAddMember)),
@@ -33,14 +35,17 @@ const main = async () => {
"/organisation/remove-member": withCors(withAuth(routes.organisationRemoveMember)), "/organisation/remove-member": withCors(withAuth(routes.organisationRemoveMember)),
"/organisation/update-member-role": withCors(withAuth(routes.organisationUpdateMemberRole)), "/organisation/update-member-role": withCors(withAuth(routes.organisationUpdateMemberRole)),
"/organisations/by-user": withCors(withAuth(routes.organisationsByUser)),
"/project/create": withCors(withAuth(routes.projectCreate)), "/project/create": withCors(withAuth(routes.projectCreate)),
"/project/update": withCors(withAuth(routes.projectUpdate)), "/project/update": withCors(withAuth(routes.projectUpdate)),
"/project/delete": withCors(withAuth(routes.projectDelete)), "/project/delete": withCors(withAuth(routes.projectDelete)),
"/project/with-creator": withCors(withAuth(routes.projectWithCreator)),
"/projects/by-creator": withCors(withAuth(routes.projectsByCreator)), "/projects/by-creator": withCors(withAuth(routes.projectsByCreator)),
"/projects/by-organisation": withCors(withAuth(routes.projectsByOrganisation)), "/projects/by-organisation": withCors(withAuth(routes.projectsByOrganisation)),
"/projects/all": withCors(withAuth(routes.projectsAll)), "/projects/all": withCors(withAuth(routes.projectsAll)),
"/projects/with-creators": withCors(withAuth(routes.projectsWithCreators)), "/projects/with-creators": withCors(withAuth(routes.projectsWithCreators)),
"/project/with-creator": withCors(withAuth(routes.projectWithCreator)),
}, },
}); });

View File

@@ -8,7 +8,7 @@ import issues from "./issues/all";
import issuesByProject from "./issues/by-project"; import issuesByProject from "./issues/by-project";
import organisationAddMember from "./organisation/add-member"; import organisationAddMember from "./organisation/add-member";
import organisationById from "./organisation/by-id"; import organisationById from "./organisation/by-id";
import organisationByUser from "./organisation/by-user"; import organisationsByUser from "./organisation/by-user";
import organisationCreate from "./organisation/create"; import organisationCreate from "./organisation/create";
import organisationDelete from "./organisation/delete"; import organisationDelete from "./organisation/delete";
import organisationMembers from "./organisation/members"; import organisationMembers from "./organisation/members";
@@ -23,8 +23,15 @@ import projectDelete from "./project/delete";
import projectUpdate from "./project/update"; import projectUpdate from "./project/update";
import projectWithCreator from "./project/with-creator"; import projectWithCreator from "./project/with-creator";
import projectsWithCreators from "./project/with-creators"; import projectsWithCreators from "./project/with-creators";
import userUpdate from "./user/update";
export const routes = { export const routes = {
authRegister,
authLogin,
authMe,
userUpdate,
issueCreate, issueCreate,
issueDelete, issueDelete,
issueUpdate, issueUpdate,
@@ -34,7 +41,6 @@ export const routes = {
organisationCreate, organisationCreate,
organisationById, organisationById,
organisationByUser,
organisationUpdate, organisationUpdate,
organisationDelete, organisationDelete,
organisationAddMember, organisationAddMember,
@@ -42,16 +48,15 @@ export const routes = {
organisationRemoveMember, organisationRemoveMember,
organisationUpdateMemberRole, organisationUpdateMemberRole,
organisationsByUser,
projectCreate, projectCreate,
projectUpdate, projectUpdate,
projectDelete, projectDelete,
projectWithCreator,
projectsByCreator, projectsByCreator,
projectsByOrganisation, projectsByOrganisation,
projectsAll, projectsAll,
projectsWithCreators, projectsWithCreators,
projectWithCreator,
authRegister,
authLogin,
authMe,
}; };

View File

@@ -1,7 +1,7 @@
import type { AuthedRequest } from "../../auth/middleware"; import type { AuthedRequest } from "../../auth/middleware";
import { getOrganisationsByUserId, getUserById } from "../../db/queries"; import { getOrganisationsByUserId, getUserById } from "../../db/queries";
// /organisation/by-user?userId=1 // /organisations/by-user?userId=1
export default async function organisationsByUser(req: AuthedRequest) { export default async function organisationsByUser(req: AuthedRequest) {
const url = new URL(req.url); const url = new URL(req.url);
const userId = url.searchParams.get("userId"); const userId = url.searchParams.get("userId");

View File

@@ -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);
}

View File

@@ -0,0 +1 @@
export { update } from "./update";

View File

@@ -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);
}
}