I think the API is done.

This commit is contained in:
MeowcaTheoRange 2023-07-13 14:33:16 -05:00
parent 588868a26b
commit 2864193fd9
7 changed files with 122 additions and 21 deletions

View file

@ -27,7 +27,7 @@ export function SubmitUserToServerUser(
): Omit<Partial<ServerUser>, "_id"> { ): Omit<Partial<ServerUser>, "_id"> {
let serverUser: Omit<Partial<ServerUser>, "_id"> = { let serverUser: Omit<Partial<ServerUser>, "_id"> = {
...submitUser, ...submitUser,
flairs: [], flairs: undefined,
code: submitUser.code || "", code: submitUser.code || "",
updatedDate: new Date() updatedDate: new Date()
}; };

View file

@ -1,7 +1,8 @@
import { Levels, Permissions } from "@/permissions"; import { Levels, Permissions } from "@/permissions";
import { ServerUser } from "@/types/user"; import { ServerUser } from "@/types/user";
import { ObjectId } from "mongodb";
export function getLevel(user: ServerUser) { export function getLevel(user: Partial<ServerUser> & { flairs: ObjectId[] }) {
let highestLevel = "USER"; let highestLevel = "USER";
for (let level of Permissions) { for (let level of Permissions) {
if (user.flairs.some(oid => level.values.includes(oid.toString()))) if (user.flairs.some(oid => level.values.includes(oid.toString())))

View file

@ -11,11 +11,8 @@ import {
import { changeTroll, getSingleTroll } from "@/lib/trollcall/troll"; import { changeTroll, getSingleTroll } from "@/lib/trollcall/troll";
import { getSingleUser } from "@/lib/trollcall/user"; import { getSingleUser } from "@/lib/trollcall/user";
import { PartialTrollSchema, SubmitTroll } from "@/types/client/troll"; import { PartialTrollSchema, SubmitTroll } from "@/types/client/troll";
import { Router } from "express";
import { NextApiRequest, NextApiResponse } from "next"; import { NextApiRequest, NextApiResponse } from "next";
export const trollRouter = Router();
export default async function handler( export default async function handler(
req: NextApiRequest, req: NextApiRequest,
res: NextApiResponse res: NextApiResponse
@ -46,7 +43,6 @@ export default async function handler(
name: query.user name: query.user
}); });
if (checkUser == null) return res.status(404).end(); if (checkUser == null) return res.status(404).end();
// Make sure to reverse methods so that way other owners can edit this troll
if (!compareCredentials(checkUser, cookies)) { if (!compareCredentials(checkUser, cookies)) {
const thisUser = await getSingleUser({ const thisUser = await getSingleUser({
name: cookies.TROLLCALL_NAME name: cookies.TROLLCALL_NAME
@ -59,7 +55,7 @@ export default async function handler(
} }
const editingTroll = await getSingleTroll({ const editingTroll = await getSingleTroll({
"name.0": query.troll, "name.0": query.troll,
"owners": checkUser._id "owners.0": checkUser._id
}); });
if (editingTroll == null) return res.status(404).end(); if (editingTroll == null) return res.status(404).end();
const serverTroll = SubmitTrollToServerTroll(validatedTroll); const serverTroll = SubmitTrollToServerTroll(validatedTroll);

View file

@ -0,0 +1,36 @@
import {
compareCredentials,
compareLevels,
getLevel
} from "@/lib/trollcall/perms";
import { getSingleTroll } from "@/lib/trollcall/troll";
import { getSingleUser } from "@/lib/trollcall/user";
import { NextApiRequest, NextApiResponse } from "next";
export default async function handler(
req: NextApiRequest,
res: NextApiResponse
) {
const { query, cookies, method, body } = req;
if (method === "GET") {
const user = await getSingleUser({
name: query.user
});
if (user == null) return res.status(404).end();
if (!compareCredentials(user, cookies)) {
const thisUser = await getSingleUser({
name: cookies.TROLLCALL_NAME
});
if (thisUser == null || !compareCredentials(thisUser, cookies))
return res.status(403).end();
if (!compareLevels(getLevel(thisUser), "MODERATOR"))
return res.status(403).end();
}
const troll = await getSingleTroll({
"name.0": query.troll,
"owners.0": user._id
});
if (troll == null) return res.status(404).end();
res.json(troll);
}
}

View file

@ -39,6 +39,7 @@ export default async function handler(
name: query.user name: query.user
}); });
if (checkExistingUser == null) return res.status(404).end(); if (checkExistingUser == null) return res.status(404).end();
let isModerator = false;
if (!compareCredentials(checkExistingUser, cookies)) { if (!compareCredentials(checkExistingUser, cookies)) {
const thisUser = await getSingleUser({ const thisUser = await getSingleUser({
name: cookies.TROLLCALL_NAME name: cookies.TROLLCALL_NAME
@ -47,27 +48,33 @@ export default async function handler(
return res.status(403).end(); return res.status(403).end();
if (!compareLevels(getLevel(thisUser), "MODERATOR")) if (!compareLevels(getLevel(thisUser), "MODERATOR"))
return res.status(403).end(); return res.status(403).end();
isModerator = true;
} }
const serverUser = SubmitUserToServerUser(validatedUser); const serverUser = SubmitUserToServerUser(validatedUser);
if (serverUser.code === "") if (serverUser.code === "")
serverUser.code = checkExistingUser.code || nanoid(16); serverUser.code = checkExistingUser.code || nanoid(16);
if (!compareLevels(getLevel(checkExistingUser), "SUPPORTER"))
serverUser.bgimage = null;
const bothUsers = MergeServerUsers(checkExistingUser, serverUser); const bothUsers = MergeServerUsers(checkExistingUser, serverUser);
const newUser = await changeUser(bothUsers); const newUser = await changeUser(bothUsers);
if (newUser == null) return res.status(503).end(); if (newUser == null) return res.status(503).end();
// Give cookies, redundant style // Give cookies, redundant style
res.setHeader("Set-Cookie", [ if (!isModerator)
serialize("TROLLCALL_NAME", newUser.name, { // don't set cookies if moderator is changing credentials
path: "/", res.setHeader("Set-Cookie", [
maxAge: 31540000 serialize("TROLLCALL_NAME", newUser.name, {
}), path: "/",
serialize("TROLLCALL_CODE", newUser.code, { maxAge: 31540000
path: "/", }),
maxAge: 31540000 serialize("TROLLCALL_CODE", newUser.code, {
}), path: "/",
serialize("TROLLCALL_PFP", newUser.pfp ?? "", { maxAge: 31540000
path: "/", }),
maxAge: 31540000 serialize("TROLLCALL_PFP", newUser.pfp ?? "", {
}) path: "/",
]).json(newUser); maxAge: 31540000
})
]).json(newUser);
else res.json(newUser);
} else return res.status(405).end(); } else return res.status(405).end();
} }

View file

@ -1,4 +1,5 @@
import { SubmitUserToServerUser } from "@/lib/trollcall/convert/user"; import { SubmitUserToServerUser } from "@/lib/trollcall/convert/user";
import { compareLevels, getLevel } from "@/lib/trollcall/perms";
import { createUser, getSingleUser } from "@/lib/trollcall/user"; import { createUser, getSingleUser } from "@/lib/trollcall/user";
import { SubmitUserSchema } from "@/types/client/user"; import { SubmitUserSchema } from "@/types/client/user";
import { ServerUser } from "@/types/user"; import { ServerUser } from "@/types/user";
@ -30,6 +31,8 @@ export default async function handler(
"_id" "_id"
>; >;
if (serverUser.code === "") serverUser.code = nanoid(16); if (serverUser.code === "") serverUser.code = nanoid(16);
if (!compareLevels(getLevel(serverUser), "SUPPORTER"))
serverUser.bgimage = null;
const newUser = await createUser(serverUser); const newUser = await createUser(serverUser);
if (newUser == null) return res.status(503).end(); if (newUser == null) return res.status(503).end();
// Give cookies // Give cookies

View file

@ -14,8 +14,40 @@ export const SubmitUserSchema = yup
description: yup.string().max(10000).ensure(), description: yup.string().max(10000).ensure(),
url: yup.string().notRequired().url(), url: yup.string().notRequired().url(),
trueSign: yup.string().required().oneOf(TrueSignKeys), trueSign: yup.string().required().oneOf(TrueSignKeys),
pronouns: yup
.array()
.of(
yup
.tuple([
yup
.string()
.required()
.matches(/^[A-z]+$/, "Letters only")
.min(1)
.max(10)
.lowercase(), // she, he, they
yup
.string()
.required()
.matches(/^[A-z]+$/, "Letters only")
.min(1)
.max(10)
.lowercase(), // her, him, them
yup
.string()
.required()
.matches(/^[A-z]+$/, "Letters only")
.min(1)
.max(10)
.lowercase() // hers, his, theirs
])
.required()
)
.required()
.min(1),
color: ColorSchema.required(), color: ColorSchema.required(),
pfp: yup.string().notRequired().url(), pfp: yup.string().notRequired().url(),
bgimage: yup.string().notRequired().url(),
code: yup.string().notRequired().max(256, "Too secure!!") code: yup.string().notRequired().max(256, "Too secure!!")
// flairs: yup.array().of(ClientFlairSchema).required(), // flairs: yup.array().of(ClientFlairSchema).required(),
}) })
@ -40,12 +72,38 @@ export const PartialUserSchema = yup
return v === "" ? null : v; return v === "" ? null : v;
}) })
.oneOf(TrueSignKeys), .oneOf(TrueSignKeys),
pronouns: yup
.array()
.of(
yup.tuple([
yup
.string()
.matches(/^[A-z]+$/, "Letters only")
.min(1)
.max(10)
.lowercase(), // she, he, they
yup
.string()
.matches(/^[A-z]+$/, "Letters only")
.min(1)
.max(10)
.lowercase(), // her, him, them
yup
.string()
.matches(/^[A-z]+$/, "Letters only")
.min(1)
.max(10)
.lowercase() // hers, his, theirs
])
)
.min(1),
color: yup.tuple([ color: yup.tuple([
yup.number().min(0).max(255), yup.number().min(0).max(255),
yup.number().min(0).max(255), yup.number().min(0).max(255),
yup.number().min(0).max(255) yup.number().min(0).max(255)
]), ]),
pfp: yup.string().url(), pfp: yup.string().url(),
bgimage: yup.string().url(),
code: yup.string().max(256, "Too secure!!") code: yup.string().max(256, "Too secure!!")
// flairs: yup.array().of(ClientFlairSchema).required(), // flairs: yup.array().of(ClientFlairSchema).required(),
}) })