[admin] Add moderation/admin management endpoints
This commit is contained in:
parent
b755e87868
commit
013f5b8bb5
|
@ -139,6 +139,10 @@ Enum AuditLogAction {
|
|||
CANVAS_FREEZE
|
||||
CANVAS_UNFREEZE
|
||||
CANVAS_AREA_UNDO
|
||||
USER_MOD
|
||||
USER_UNMOD
|
||||
USER_ADMIN
|
||||
USER_UNADMIN
|
||||
}
|
||||
|
||||
Ref: Pixel.userId > User.sub
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
-- AlterEnum
|
||||
-- This migration adds more than one value to an enum.
|
||||
-- With PostgreSQL versions 11 and earlier, this is not possible
|
||||
-- in a single migration. This can be worked around by creating
|
||||
-- multiple migrations, each migration adding only one value to
|
||||
-- the enum.
|
||||
|
||||
|
||||
ALTER TYPE "AuditLogAction" ADD VALUE 'USER_MOD';
|
||||
ALTER TYPE "AuditLogAction" ADD VALUE 'USER_UNMOD';
|
||||
ALTER TYPE "AuditLogAction" ADD VALUE 'USER_ADMIN';
|
||||
ALTER TYPE "AuditLogAction" ADD VALUE 'USER_UNADMIN';
|
|
@ -26,8 +26,8 @@ model User {
|
|||
profile_url String?
|
||||
|
||||
lastTimeGainStarted DateTime @default(now()) // the time base used to determine the amount of stack the user should gain
|
||||
pixelStack Int @default(0) // amount of pixels stacked for this user
|
||||
undoExpires DateTime? // when the undo for the most recent pixel expires at
|
||||
pixelStack Int @default(0) // amount of pixels stacked for this user
|
||||
undoExpires DateTime? // when the undo for the most recent pixel expires at
|
||||
|
||||
isAdmin Boolean @default(false)
|
||||
isModerator Boolean @default(false)
|
||||
|
@ -157,6 +157,10 @@ enum AuditLogAction {
|
|||
CANVAS_FREEZE
|
||||
CANVAS_UNFREEZE
|
||||
CANVAS_AREA_UNDO
|
||||
USER_MOD
|
||||
USER_UNMOD
|
||||
USER_ADMIN
|
||||
USER_UNADMIN
|
||||
}
|
||||
|
||||
model AuditLog {
|
||||
|
|
|
@ -679,6 +679,158 @@ app.post("/user/:sub/notice", async (req, res) => {
|
|||
res.json({ success: true });
|
||||
});
|
||||
|
||||
/**
|
||||
* Mark a user as a moderator
|
||||
*
|
||||
* @param :sub User ID
|
||||
*/
|
||||
app.put("/user/:sub/moderator", async (req, res) => {
|
||||
let user: User;
|
||||
|
||||
try {
|
||||
user = await User.fromSub(req.params.sub);
|
||||
} catch (e) {
|
||||
if (e instanceof UserNotFound) {
|
||||
res.status(404).json({ success: false, error: "User not found" });
|
||||
} else {
|
||||
res.status(500).json({ success: false, error: "Internal error" });
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
await prisma.user.update({
|
||||
where: { sub: user.sub },
|
||||
data: {
|
||||
isModerator: true,
|
||||
},
|
||||
});
|
||||
|
||||
await user.update(true);
|
||||
|
||||
const adminUser = (await User.fromAuthSession(req.session.user!))!;
|
||||
const auditLog = await AuditLog.Factory(adminUser.sub)
|
||||
.doing("USER_MOD")
|
||||
.reason(req.header("X-Audit") || null)
|
||||
.withComment(`Made ${user.sub} a moderator`)
|
||||
.create();
|
||||
|
||||
res.json({ success: true, auditLog });
|
||||
});
|
||||
|
||||
/**
|
||||
* Unmark a user as a moderator
|
||||
*
|
||||
* @param :sub User ID
|
||||
*/
|
||||
app.delete("/user/:sub/moderator", async (req, res) => {
|
||||
let user: User;
|
||||
|
||||
try {
|
||||
user = await User.fromSub(req.params.sub);
|
||||
} catch (e) {
|
||||
if (e instanceof UserNotFound) {
|
||||
res.status(404).json({ success: false, error: "User not found" });
|
||||
} else {
|
||||
res.status(500).json({ success: false, error: "Internal error" });
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
await prisma.user.update({
|
||||
where: { sub: user.sub },
|
||||
data: {
|
||||
isModerator: false,
|
||||
},
|
||||
});
|
||||
|
||||
await user.update(true);
|
||||
|
||||
const adminUser = (await User.fromAuthSession(req.session.user!))!;
|
||||
const auditLog = await AuditLog.Factory(adminUser.sub)
|
||||
.doing("USER_UNMOD")
|
||||
.reason(req.header("X-Audit") || null)
|
||||
.withComment(`Removed ${user.sub} as moderator`)
|
||||
.create();
|
||||
|
||||
res.json({ success: true, auditLog });
|
||||
});
|
||||
|
||||
/**
|
||||
* Mark a user as an admin
|
||||
*
|
||||
* @param :sub User ID
|
||||
*/
|
||||
app.put("/user/:sub/admin", async (req, res) => {
|
||||
let user: User;
|
||||
|
||||
try {
|
||||
user = await User.fromSub(req.params.sub);
|
||||
} catch (e) {
|
||||
if (e instanceof UserNotFound) {
|
||||
res.status(404).json({ success: false, error: "User not found" });
|
||||
} else {
|
||||
res.status(500).json({ success: false, error: "Internal error" });
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
await prisma.user.update({
|
||||
where: { sub: user.sub },
|
||||
data: {
|
||||
isAdmin: true,
|
||||
},
|
||||
});
|
||||
|
||||
await user.update(true);
|
||||
|
||||
const adminUser = (await User.fromAuthSession(req.session.user!))!;
|
||||
const auditLog = await AuditLog.Factory(adminUser.sub)
|
||||
.doing("USER_ADMIN")
|
||||
.reason(req.header("X-Audit") || null)
|
||||
.withComment(`Added ${user.sub} as admin`)
|
||||
.create();
|
||||
|
||||
res.json({ success: true, auditLog });
|
||||
});
|
||||
|
||||
/**
|
||||
* Unmark a user as an admin
|
||||
*
|
||||
* @param :sub User ID
|
||||
*/
|
||||
app.delete("/user/:sub/admin", async (req, res) => {
|
||||
let user: User;
|
||||
|
||||
try {
|
||||
user = await User.fromSub(req.params.sub);
|
||||
} catch (e) {
|
||||
if (e instanceof UserNotFound) {
|
||||
res.status(404).json({ success: false, error: "User not found" });
|
||||
} else {
|
||||
res.status(500).json({ success: false, error: "Internal error" });
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
await prisma.user.update({
|
||||
where: { sub: user.sub },
|
||||
data: {
|
||||
isAdmin: false,
|
||||
},
|
||||
});
|
||||
|
||||
await user.update(true);
|
||||
|
||||
const adminUser = (await User.fromAuthSession(req.session.user!))!;
|
||||
const auditLog = await AuditLog.Factory(adminUser.sub)
|
||||
.doing("USER_UNADMIN")
|
||||
.reason(req.header("X-Audit") || null)
|
||||
.withComment(`Removed ${user.sub} as admin`)
|
||||
.create();
|
||||
|
||||
res.json({ success: true, auditLog });
|
||||
});
|
||||
|
||||
app.get("/instance/:domain/ban", async (req, res) => {
|
||||
// get ban information
|
||||
|
||||
|
|
Loading…
Reference in New Issue