diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 9240335..f9cb756 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -56,6 +56,7 @@ model users { id Int @id(map: "pk_users") @default(autoincrement()) login String @unique @db.VarChar(25) pass String @db.VarChar(100) + fullName String? @db.VarChar(100) is_admin Boolean @default(false) timetable timetable[] user_session user_session[] diff --git a/src/db.ts b/src/db.ts index 5887396..723060f 100644 --- a/src/db.ts +++ b/src/db.ts @@ -68,6 +68,27 @@ export async function createUser(login: string, password: string) { return user; } +export async function updateUserPassword(login: string, newPassword: string) { + const user = await client.users.update({ + where: { + login: login, + }, + data: { + pass: toHex(blake3(newPassword)), + }, + }); + return user; +} + +export async function deleteUser(login: string) { + const user = await client.users.delete({ + where: { + login: login, + }, + }); + return user; +} + export async function createSession(user: users) { const session = await client.user_session.create({ data: { @@ -144,3 +165,19 @@ export async function getArticle(articleId: number) { return article; } + +export async function searchUsers(params: { login?: string; isAdmin?: boolean; fullName?: string }) { + const users = await client.users.findMany({ + where: { + login: { + contains: params.login, + }, + is_admin: params.isAdmin, + fullName: params.fullName, + }, + orderBy: { + id: "asc", + }, + }); + return users; +} diff --git a/src/pages/userapi/deleteUser.ts b/src/pages/userapi/deleteUser.ts new file mode 100644 index 0000000..37b1fd0 --- /dev/null +++ b/src/pages/userapi/deleteUser.ts @@ -0,0 +1,46 @@ +import type { APIContext } from "astro"; +import { deleteUser, getSessionUser } from "../../db"; +import { Prisma } from "@prisma/client"; + +export async function post({ request, cookies }: APIContext) { + const response: { ok: boolean; reason?: string } = { + ok: true, + }; + try { + const sessId = cookies.get("session").value!; + const user = (await getSessionUser(sessId))!; + if (!user.is_admin) { + throw new Error("Доступно только администраторам"); + } + + const formData = await request.formData(); + const login = formData.get("login"); + if (login === null) { + throw new Error("Не предоставлены данные для удаления пользователя"); + } + + if (login.toString() === user.login) { + throw new Error("Невозможно удалить самого себя"); + } + + const deletedUser = await deleteUser(login.toString()); + if (deletedUser === null) { + throw new Error("Не удалось удалить пользователя"); + } + + response.ok = true; + } catch (e: any) { + response.ok = false; + if (e instanceof Prisma.PrismaClientKnownRequestError) { + response.reason = `Неизвестная ошибка базы данных. Код ${e.code}`; + } else if (e instanceof Error) { + response.reason = e.message.trim(); + } else { + response.reason = e.toString().trim(); + } + } + + return { + body: JSON.stringify(response), + }; +} diff --git a/src/pages/userapi/updatePassword.ts b/src/pages/userapi/updatePassword.ts new file mode 100644 index 0000000..c7800b3 --- /dev/null +++ b/src/pages/userapi/updatePassword.ts @@ -0,0 +1,43 @@ +import type { APIContext } from "astro"; +import { updateUserPassword, getSessionUser } from "../../db"; +import { Prisma } from "@prisma/client"; + +export async function post({ request, cookies }: APIContext) { + const response: { ok: boolean; reason?: string } = { + ok: true, + }; + try { + const sessId = cookies.get("session").value!; + const user = (await getSessionUser(sessId))!; + if (!user.is_admin) { + throw new Error("Доступно только администраторам"); + } + + const formData = await request.formData(); + const login = formData.get("login"); + const password = formData.get("password"); + if (login === null || password === null) { + throw new Error("Не предоставлены данные для обновления пароля"); + } + + const updatedUser = await updateUserPassword(login.toString(), password.toString()); + if (updatedUser === null) { + throw new Error("Не удалось обновить пароль"); + } + + response.ok = true; + } catch (e: any) { + response.ok = false; + if (e instanceof Prisma.PrismaClientKnownRequestError) { + response.reason = `Неизвестная ошибка базы данных. Код ${e.code}`; + } else if (e instanceof Error) { + response.reason = e.message.trim(); + } else { + response.reason = e.toString().trim(); + } + } + + return { + body: JSON.stringify(response), + }; +} diff --git a/src/pages/users.astro b/src/pages/users.astro new file mode 100644 index 0000000..8384331 --- /dev/null +++ b/src/pages/users.astro @@ -0,0 +1,112 @@ +--- +import Layout from "../layouts/Layout.astro"; + +import { getUserSession, searchUsers, getSessionUser } from "../db"; +import Navbar from "../components/Navbar.astro"; + +if (Astro.cookies.has("session")) { + const sessId = Astro.cookies.get("session").value!; + const dbSess = await getUserSession(sessId); + if (dbSess === null) { + Astro.cookies.delete("session"); + return Astro.redirect("/login"); + } +} else { + return Astro.redirect("/login"); +} + +const sessId = Astro.cookies.get("session").value!; +const user = (await getSessionUser(sessId))!; +if (!user.is_admin) { + return Astro.redirect("/"); +} + +const users = await searchUsers({}); +--- + + +
+ +
+ { + users.map((e) => ( +
+
+
{e.fullName}
+
{e.login}
+ + + Открыть профиль + + + Редактировать расписание + + +
+
+ )) + } +
+
+
+ +