Partypack/Server/Source/Routes/Admin.ts

135 lines
5.6 KiB
TypeScript
Raw Permalink Normal View History

2024-01-28 11:07:10 +01:00
/* eslint-disable no-case-declarations */
2024-02-04 22:28:42 +01:00
import j from "joi";
2024-01-28 11:07:10 +01:00
import { Router } from "express";
import { UserPermissions } from "../Schemas/User";
2024-02-04 22:28:42 +01:00
import { Song } from "../Schemas/Song";
2024-01-28 11:07:10 +01:00
import { RequireAuthentication, ValidateBody } from "../Modules/Middleware";
import { ForcedCategory } from "../Schemas/ForcedCategory";
2024-02-04 22:28:42 +01:00
import { DiscordRole } from "../Schemas/DiscordRole";
import { Bot } from "../Handlers/DiscordBot";
import { DISCORD_SERVER_ID } from "../Modules/Constants";
2024-02-07 20:02:39 +01:00
import { MisconfiguredDiscordBot, MissingDatabaseRole, MissingServerRole, MissingPermissions } from "../Modules/Errors";
2024-01-28 11:07:10 +01:00
const App = Router();
// ! ANY ENDPOINTS DEFINED IN THIS FILE WILL REQUIRE ADMIN AUTHORIZATION !
// ! ANY ENDPOINTS DEFINED IN THIS FILE WILL REQUIRE ADMIN AUTHORIZATION !
// ! ANY ENDPOINTS DEFINED IN THIS FILE WILL REQUIRE ADMIN AUTHORIZATION !
App.use(RequireAuthentication());
App.use((req, res, next) => {
if (req.user!.PermissionLevel! < UserPermissions.Administrator)
2024-02-07 20:02:39 +01:00
//return res.status(403).send("You don't have permission to access this endpoint.");
return res.status(403).json(new MissingPermissions().errorJSON()).set('X-PartyPacker-ErrorString', new MissingPermissions().errorString());
2024-01-28 11:07:10 +01:00
next();
});
2024-02-04 22:28:42 +01:00
App.post("/create/role",
ValidateBody(j.object({
ID: j.string().min(10).max(32).required(),
Comment: j.string().max(128).optional(),
PermissionLevel: j.number().valid(...(Object.values(UserPermissions).filter(x => !isNaN(Number(x))))).required()
})),
async (req, res) => {
if (!Bot.isReady())
2024-02-07 20:02:39 +01:00
//return res.status(503).send("This Partypack instance has a misconfigured Discord bot.");
return res.status(503).json(new MisconfiguredDiscordBot().errorJSON()).set('X-PartyPacker-ErrorString', new MisconfiguredDiscordBot().errorString());
2024-02-04 22:28:42 +01:00
if (!Bot.guilds.cache.get(DISCORD_SERVER_ID as string)?.roles.cache.has(req.body.ID))
2024-02-07 20:02:39 +01:00
//return res.status(400).send("This role does not exist in the Discord server.");
return res.status(400).json(new MissingServerRole().errorJSON()).set('X-PartyPacker-ErrorString', new MissingServerRole().errorString());
2024-02-04 22:28:42 +01:00
const Existing = await DiscordRole.findOne({ where: { ID: req.body.ID } });
if (Existing) {
Existing.GrantedPermissions = req.body.PermissionLevel as UserPermissions;
Existing.Comment = req.body.Comment ?? Existing.Comment;
await Existing.save();
return res.json(Existing.Package(true));
}
const RoleEntry = await DiscordRole.create({
ID: req.body.ID,
Comment: req.body.Comment ?? "No comment",
GrantedPermissions: req.body.PermissionLevel as UserPermissions
}).save();
res.json(RoleEntry.Package(true));
});
App.post("/delete/role",
ValidateBody(j.object({
ID: j.string().min(10).max(32).required()
})),
async (req, res) => {
const RoleData = await DiscordRole.findOne({ where: { ID: req.body.ID } });
if (!RoleData)
2024-02-07 20:02:39 +01:00
//return res.status(404).json(new MissingDatabaseRole());
return res.status(404).json(new MissingDatabaseRole().errorJSON()).set('X-PartyPacker-ErrorString', new MissingDatabaseRole().errorString());
2024-02-04 22:28:42 +01:00
await RoleData.remove();
2024-02-07 20:02:39 +01:00
res.send.status(204);
2024-02-04 22:28:42 +01:00
})
App.get("/roles", async (_, res) => res.json((await DiscordRole.find()).map(x => x.Package(true))));
App.get("/tracks", async (_, res) => res.json((await Song.find()).map(x => x.Package(true))));
2024-01-28 11:07:10 +01:00
App.post("/update/discovery",
ValidateBody(j.array().items(j.object({
ID: j.string().uuid().required(),
Songs: j.array().items(j.string().uuid()).unique().min(1).max(20).required(),
Priority: j.number().min(-50000).max(50000).required(),
Header: j.string().min(3).max(125).required(),
ShouldDelete: j.boolean().required()
})).max(15)),
async (req, res) => {
const b = req.body as { ID: string, Songs: string[], Priority: number, Header: string, ShouldDelete: boolean }[];
const Failures: { Regarding: string, Message: string }[] = [];
const Successes: { Regarding: string, Message: string }[] = [];
for (const Entry of b) {
let Category = await ForcedCategory.findOne({ where: { ID: Entry.ID } });
if (Entry.ShouldDelete) { // DELETION
if (!Category) {
Failures.push({ Regarding: Entry.ID, Message: "Cannot delete non-existent category." });
continue;
}
await Category.remove();
Successes.push({ Regarding: Entry.ID, Message: "Successfully deleted category." });
continue;
}
if (!Category) // CREATION
Category = await ForcedCategory.create({
Header: Entry.Header,
Activated: true,
Priority: Entry.Priority,
Songs: []
});
// MODIFICATION
const Songs = await Promise.all(Entry.Songs.map(x => Song.findOne({ where: { ID: x } })));
if (Songs.includes(null)) {
Failures.push({ Regarding: Entry.ID, Message: `Cannot modify "${Entry.ID}" songs as it includes a non-existent song` });
continue;
}
Category.Header = Entry.Header;
Category.Priority = Entry.Priority;
Category.Songs = Songs as Song[];
Category.save();
Successes.push({ Regarding: Entry.ID, Message: `Successfully created/modified category "${Category.ID}".` });
}
res.status(Failures.length > Successes.length ? 400 : 200).json({
Failures,
Successes
})
});
export default {
App,
DefaultAPI: "/api/admin"
2024-01-20 23:34:31 +01:00
}