wow
Co-authored-by: Copilot <copilot@github.com>
This commit is contained in:
parent
4c3d96778d
commit
3253e91d95
4 changed files with 89 additions and 27 deletions
|
|
@ -263,6 +263,57 @@ export default new Elysia({ prefix: "/auth" })
|
||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
|
|
||||||
|
.delete("/user/:id", async ({ params, jwt, cookie: { mizuki }, status }) => {
|
||||||
|
const rawToken = mizuki.value;
|
||||||
|
if (typeof rawToken !== "string" || rawToken.length === 0) {
|
||||||
|
return status(401, "Unauthorized");
|
||||||
|
}
|
||||||
|
|
||||||
|
const payload = await jwt.verify(rawToken);
|
||||||
|
if (!payload || typeof payload !== "object" || !("id" in payload) || typeof payload.id !== "string") {
|
||||||
|
return status(401, "Unauthorized");
|
||||||
|
}
|
||||||
|
|
||||||
|
const requester = await User.findOne({ userId: payload.id });
|
||||||
|
if (!requester || requester.role !== "admin") {
|
||||||
|
return status(403, "Forbidden");
|
||||||
|
}
|
||||||
|
|
||||||
|
const target = await User.findOne({ userId: params.id });
|
||||||
|
if (!target) {
|
||||||
|
return status(404, "User not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hardcodedOwners.has(target.discordId)) {
|
||||||
|
return status(400, "Hardcoded owners cannot be deleted");
|
||||||
|
}
|
||||||
|
|
||||||
|
await User.deleteOne({ userId: params.id });
|
||||||
|
|
||||||
|
await createAuditLog({
|
||||||
|
actor: {
|
||||||
|
userId: requester.userId,
|
||||||
|
discordId: requester.discordId,
|
||||||
|
username: requester.username,
|
||||||
|
role: requester.role,
|
||||||
|
},
|
||||||
|
action: "auth.user.delete",
|
||||||
|
targetType: "user",
|
||||||
|
targetId: params.id,
|
||||||
|
summary: `${requester.username} deleted user ${target.username}`,
|
||||||
|
detail: {
|
||||||
|
userId: target.userId,
|
||||||
|
discordId: target.discordId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return { ok: true };
|
||||||
|
}, {
|
||||||
|
params: t.Object({
|
||||||
|
id: t.String(),
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
.get("/users", async ({ jwt, cookie: { mizuki }, status }) => {
|
.get("/users", async ({ jwt, cookie: { mizuki }, status }) => {
|
||||||
const rawToken = mizuki.value;
|
const rawToken = mizuki.value;
|
||||||
if (typeof rawToken !== "string" || rawToken.length === 0) {
|
if (typeof rawToken !== "string" || rawToken.length === 0) {
|
||||||
|
|
|
||||||
|
|
@ -217,7 +217,17 @@ export default new Elysia({ prefix: "/post" })
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
.get("/list", async ({ query }) => {
|
.get("/list", async ({ query, jwt, cookie: { mizuki }, status }) => {
|
||||||
|
const rawToken = mizuki.value;
|
||||||
|
if (typeof rawToken !== "string" || rawToken.length === 0) {
|
||||||
|
return status(401, "Unauthorized");
|
||||||
|
}
|
||||||
|
|
||||||
|
const payload = await jwt.verify(rawToken);
|
||||||
|
if (!payload || typeof payload !== "object" || !("id" in payload) || typeof payload.id !== "string") {
|
||||||
|
return status(401, "Unauthorized");
|
||||||
|
}
|
||||||
|
|
||||||
const page = query.page;
|
const page = query.page;
|
||||||
const pageSize = query.size || 10;
|
const pageSize = query.size || 10;
|
||||||
const filterTags = normalizeQueryTags(query.tags);
|
const filterTags = normalizeQueryTags(query.tags);
|
||||||
|
|
@ -260,22 +270,7 @@ export default new Elysia({ prefix: "/post" })
|
||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
|
|
||||||
.get("/detail/:id", async ({ params, status, jwt, cookie: { mizuki } }) => {
|
.get("/detail/:id", async ({ params, status }) => {
|
||||||
const rawToken = mizuki.value;
|
|
||||||
if (typeof rawToken !== "string" || rawToken.length === 0) {
|
|
||||||
return status(401, "Unauthorized");
|
|
||||||
}
|
|
||||||
|
|
||||||
const payload = await jwt.verify(rawToken);
|
|
||||||
if (!payload || typeof payload !== "object" || !("id" in payload) || typeof payload.id !== "string") {
|
|
||||||
return status(401, "Unauthorized");
|
|
||||||
}
|
|
||||||
|
|
||||||
const user = await User.findOne({ userId: payload.id });
|
|
||||||
if (!user) {
|
|
||||||
return status(401, "Unauthorized");
|
|
||||||
}
|
|
||||||
|
|
||||||
const post = await MediaUpload.findById(params.id);
|
const post = await MediaUpload.findById(params.id);
|
||||||
if (!post) {
|
if (!post) {
|
||||||
return status(404, "포스트를 찾을 수 없습니다.");
|
return status(404, "포스트를 찾을 수 없습니다.");
|
||||||
|
|
|
||||||
|
|
@ -416,16 +416,28 @@ export default function DashboardPage() {
|
||||||
</select>
|
</select>
|
||||||
</td>
|
</td>
|
||||||
<td className="px-3 py-2">
|
<td className="px-3 py-2">
|
||||||
<button
|
<div className="flex items-center gap-2">
|
||||||
type="button"
|
<button
|
||||||
onClick={() => {
|
type="button"
|
||||||
void updateRole(user);
|
onClick={() => {
|
||||||
}}
|
void updateRole(user);
|
||||||
disabled={savingUserId === user.id || (pendingRole[user.id] ?? user.role) === user.role}
|
}}
|
||||||
className="border border-border px-3 py-1 disabled:opacity-50"
|
disabled={savingUserId === user.id || (pendingRole[user.id] ?? user.role) === user.role}
|
||||||
>
|
className="border border-border px-3 py-1 disabled:opacity-50"
|
||||||
{savingUserId === user.id ? "저장 중..." : "저장"}
|
>
|
||||||
</button>
|
{savingUserId === user.id ? "저장 중..." : "저장"}
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() => {
|
||||||
|
void deleteUser(user);
|
||||||
|
}}
|
||||||
|
disabled={savingUserId === user.id}
|
||||||
|
className="border border-red-300 bg-red-50 px-3 py-1 text-xs text-red-700 disabled:opacity-50"
|
||||||
|
>
|
||||||
|
삭제
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
))}
|
))}
|
||||||
|
|
|
||||||
|
|
@ -102,6 +102,10 @@
|
||||||
transition-timing-function: var(--ease-out-expo);
|
transition-timing-function: var(--ease-out-expo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
html, body {
|
||||||
|
overscroll-behavior-y: none;
|
||||||
|
}
|
||||||
|
|
||||||
@media (hover: hover) {
|
@media (hover: hover) {
|
||||||
.image-scale:hover {
|
.image-scale:hover {
|
||||||
--tw-scale-x: 105%;
|
--tw-scale-x: 105%;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue