Switch from "Users" to "Clans"
This commit is contained in:
parent
b955477231
commit
28c27fb172
28 changed files with 581 additions and 500 deletions
|
@ -1,4 +1,5 @@
|
|||
# TrollCallAPIs
|
||||
|
||||
A set of TrollCallNotAgain-equivalent API hooks, made to let developers create third-party apps for the TrollCall service.
|
||||
|
||||
---
|
||||
|
@ -6,11 +7,13 @@ A set of TrollCallNotAgain-equivalent API hooks, made to let developers create t
|
|||
TrollCall is great, but the merge of the client and server TrollCallNotAgain has with Next.js is problematic. (ahem, Client/Server Hydration and Server Components (those are messy grr))
|
||||
|
||||
There are a few issues with the existing APIs as well:
|
||||
|
||||
1. Objects get duplicated if their name/first-name is changed.
|
||||
|
||||
Doing this:
|
||||
|
||||
```
|
||||
PUSH /api/user/.../troll/name1
|
||||
PUSH /api/clan/.../troll/name1
|
||||
|
||||
{
|
||||
...
|
||||
|
@ -18,12 +21,15 @@ PUSH /api/user/.../troll/name1
|
|||
...
|
||||
}
|
||||
```
|
||||
|
||||
results in this on the database:
|
||||
|
||||
```
|
||||
trolls/
|
||||
|- Document {"name": ["name1", ...], ...}
|
||||
|- Document {"name": ["name2", ...], ...}
|
||||
```
|
||||
|
||||
which is not good.
|
||||
|
||||
2. More issues that I forgot
|
||||
|
|
12
package-lock.json
generated
12
package-lock.json
generated
|
@ -10,10 +10,12 @@
|
|||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@types/cookie-parser": "^1.4.3",
|
||||
"@types/crypto-js": "^4.1.1",
|
||||
"@types/react": "^18.2.14",
|
||||
"body-parser": "^1.20.2",
|
||||
"cookie": "^0.5.0",
|
||||
"cookie-parser": "^1.4.6",
|
||||
"crypto-js": "^4.1.1",
|
||||
"dotenv": "^16.3.0",
|
||||
"express": "^4.18.2",
|
||||
"lodash": "^4.17.21",
|
||||
|
@ -262,6 +264,11 @@
|
|||
"@types/express": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/crypto-js": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/crypto-js/-/crypto-js-4.1.1.tgz",
|
||||
"integrity": "sha512-BG7fQKZ689HIoc5h+6D2Dgq1fABRa0RbBWKBd9SP/MVRVXROflpm5fhwyATX5duFmbStzyzyycPB8qUYKDH3NA=="
|
||||
},
|
||||
"node_modules/@types/express": {
|
||||
"version": "4.17.17",
|
||||
"resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.17.tgz",
|
||||
|
@ -748,6 +755,11 @@
|
|||
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
|
||||
"integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ=="
|
||||
},
|
||||
"node_modules/crypto-js": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.1.1.tgz",
|
||||
"integrity": "sha512-o2JlM7ydqd3Qk9CA0L4NL6mTzU2sdx96a+oOfPu8Mkl/PK51vSyoi8/rQ8NknZtk44vq15lmhAj9CIAGwgeWKw=="
|
||||
},
|
||||
"node_modules/csstype": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz",
|
||||
|
|
|
@ -24,10 +24,12 @@
|
|||
"description": "",
|
||||
"dependencies": {
|
||||
"@types/cookie-parser": "^1.4.3",
|
||||
"@types/crypto-js": "^4.1.1",
|
||||
"@types/react": "^18.2.14",
|
||||
"body-parser": "^1.20.2",
|
||||
"cookie": "^0.5.0",
|
||||
"cookie-parser": "^1.4.6",
|
||||
"crypto-js": "^4.1.1",
|
||||
"dotenv": "^16.3.0",
|
||||
"express": "^4.18.2",
|
||||
"lodash": "^4.17.21",
|
||||
|
|
|
@ -1,6 +1,21 @@
|
|||
import { MongoClient } from "mongodb";
|
||||
|
||||
if (process.env.MONGODB_DATABASE == null) process.exit();
|
||||
if (process.env.ENCRYPT_CODE == null) {
|
||||
console.log(
|
||||
"You need to write an encryption code to run a TrollCall server!"
|
||||
);
|
||||
process.exit();
|
||||
}
|
||||
if (process.env.MONGODB_DATABASE == null) {
|
||||
console.log("You need a MongoDB Database URI to run a TrollCall server!");
|
||||
process.exit();
|
||||
}
|
||||
if (process.env.MONGODB_DATABASE_NAME == null) {
|
||||
console.log(
|
||||
'You need to specify a MongoDB Database Store to run a TrollCall server! Default can be "trollcall"'
|
||||
);
|
||||
process.exit();
|
||||
}
|
||||
|
||||
export const client = new MongoClient(process.env.MONGODB_DATABASE, {});
|
||||
|
||||
|
|
28
src/lib/trollcall/api/clan.ts
Normal file
28
src/lib/trollcall/api/clan.ts
Normal file
|
@ -0,0 +1,28 @@
|
|||
import { ClientClan, ServerClan } from "@/types/clan";
|
||||
import { getSingleClan } from "../clan";
|
||||
import { ServerClanToClientClan } from "../convert/clan";
|
||||
import { ServerFlairToClientFlair } from "../convert/flair";
|
||||
import { getManyFlairs } from "../flair";
|
||||
import { cutArray } from "../utility/merge";
|
||||
|
||||
export async function ClanGET(
|
||||
query?: Partial<{
|
||||
[key: string]: string | string[];
|
||||
}> | null,
|
||||
existingClan?: ServerClan
|
||||
): Promise<ClientClan | null> {
|
||||
const clan =
|
||||
existingClan ??
|
||||
(await getSingleClan({
|
||||
name: query?.clan
|
||||
}));
|
||||
if (clan == null) return null;
|
||||
const serverClan = await ServerClanToClientClan(clan);
|
||||
serverClan.flairs = cutArray(
|
||||
await getManyFlairs(
|
||||
{ _id: { $in: clan.flairs } },
|
||||
ServerFlairToClientFlair
|
||||
)
|
||||
);
|
||||
return serverClan as ClientClan;
|
||||
}
|
87
src/lib/trollcall/clan.ts
Normal file
87
src/lib/trollcall/clan.ts
Normal file
|
@ -0,0 +1,87 @@
|
|||
import { ServerClan } from "@/types/clan";
|
||||
import { Sort } from "mongodb";
|
||||
import {
|
||||
Filter,
|
||||
createOne,
|
||||
cursorToArray,
|
||||
readMany,
|
||||
readOne,
|
||||
replaceOne
|
||||
} from "../db/crud";
|
||||
|
||||
const ClanSort: Sort = { updatedDate: -1, _id: -1 };
|
||||
|
||||
/**
|
||||
* A function that returns one ServerClan from the database.
|
||||
* @param query A partial Find query. Can contain an ID.
|
||||
* @returns A ServerClan.
|
||||
*/
|
||||
|
||||
export async function getSingleClan(
|
||||
query: Filter<ServerClan>
|
||||
): Promise<ServerClan | null> {
|
||||
const clan = (await readOne("clans", query)) as ServerClan | null;
|
||||
return clan;
|
||||
}
|
||||
|
||||
/**
|
||||
* A function that returns many ServerClans from the database using a FindCursor.
|
||||
* @param query A partial Find query. Can contain an ID.
|
||||
* @param func A function to run on every ServerClan returned. Helps reduce loops.
|
||||
* @returns An array of ServerClans.
|
||||
*/
|
||||
|
||||
export async function getManyClans<T>(
|
||||
query: Filter<ServerClan>,
|
||||
func?: (input: any) => T
|
||||
): Promise<(Awaited<T> | null)[]> {
|
||||
const clan = (await cursorToArray(
|
||||
readMany("clans", query, ClanSort),
|
||||
func
|
||||
)) as (Awaited<T> | null)[];
|
||||
return clan;
|
||||
}
|
||||
|
||||
/**
|
||||
* A function that returns many ServerClans from the database using a FindCursor, limited by count.
|
||||
* @param query A partial Find query. Can contain an ID.
|
||||
* @param func A function to run on every ServerClan returned. Helps reduce loops.
|
||||
* @returns An array of ServerClans.
|
||||
*/
|
||||
|
||||
export async function getManyPagedClans<T>(
|
||||
query: Filter<ServerClan>,
|
||||
func?: (input: any) => T,
|
||||
count: number = 5,
|
||||
page: number = 0
|
||||
): Promise<(Awaited<T> | null)[]> {
|
||||
const find = readMany("clans", query, ClanSort)
|
||||
.limit(count)
|
||||
.skip(page * count);
|
||||
const clan = (await cursorToArray(find, func)) as (Awaited<T> | null)[];
|
||||
return clan;
|
||||
}
|
||||
|
||||
/**
|
||||
* A function that puts one ServerClan into the database.
|
||||
* @param clan A ServerClan.
|
||||
* @returns A ServerClan, or null, depending on if the operation succeeded.
|
||||
*/
|
||||
|
||||
export async function createClan(
|
||||
clan: Omit<ServerClan, "_id">
|
||||
): Promise<Omit<ServerClan, "_id"> | null> {
|
||||
const newClan = await createOne("clans", clan);
|
||||
return newClan.acknowledged ? clan : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* A function that changes one database clan with the given params.
|
||||
* @param clan A ServerClan.
|
||||
* @returns A ServerClan, or null, depending on if the operation succeeded.
|
||||
*/
|
||||
|
||||
export async function changeClan(clan: ServerClan): Promise<ServerClan | null> {
|
||||
const newClan = await replaceOne("clans", { _id: clan._id }, clan);
|
||||
return newClan.acknowledged ? clan : null;
|
||||
}
|
39
src/lib/trollcall/convert/clan.ts
Normal file
39
src/lib/trollcall/convert/clan.ts
Normal file
|
@ -0,0 +1,39 @@
|
|||
import { ClientClan, ServerClan } from "@/types/clan";
|
||||
import { SubmitClan } from "@/types/client/clan";
|
||||
import { cutObject, removeCode, sanitize } from "../utility/merge";
|
||||
|
||||
export async function ServerClanToClientClan(
|
||||
serverClan: ServerClan
|
||||
): Promise<Partial<ClientClan>> {
|
||||
const sanitizedClan = removeCode(sanitize(serverClan));
|
||||
let clientClan: Partial<ClientClan> = {
|
||||
...sanitizedClan,
|
||||
flairs: undefined,
|
||||
updatedDate: serverClan.updatedDate?.getTime()
|
||||
};
|
||||
return clientClan;
|
||||
}
|
||||
|
||||
export function SubmitClanToServerClan(
|
||||
submitClan: Partial<SubmitClan>
|
||||
): Omit<Partial<ServerClan>, "_id"> {
|
||||
let serverClan: Omit<Partial<ServerClan>, "_id"> = {
|
||||
...submitClan,
|
||||
flairs: undefined,
|
||||
code: submitClan.code || undefined,
|
||||
updatedDate: new Date()
|
||||
};
|
||||
return serverClan;
|
||||
}
|
||||
|
||||
export function MergeServerClans(
|
||||
submitClan: ServerClan,
|
||||
merge: Partial<Omit<ServerClan, "_id">>
|
||||
): ServerClan {
|
||||
let serverClan: ServerClan = {
|
||||
...submitClan,
|
||||
...cutObject(merge),
|
||||
updatedDate: new Date()
|
||||
};
|
||||
return serverClan;
|
||||
}
|
|
@ -1,19 +1,14 @@
|
|||
import { Class, TrueSign } from "@/types/assist/extended_zodiac";
|
||||
import { SubmitTroll } from "@/types/client/troll";
|
||||
import { ClientTroll, ServerTroll } from "@/types/troll";
|
||||
import { getManyFlairs } from "../flair";
|
||||
import { cutArray, cutObject, sanitize } from "../utility/merge";
|
||||
import { ServerFlairToClientFlair } from "./flair";
|
||||
import { cutObject, sanitize } from "../utility/merge";
|
||||
|
||||
export async function ServerTrollToClientTroll(
|
||||
serverTroll: ServerTroll
|
||||
): Promise<ClientTroll> {
|
||||
): Promise<Partial<ClientTroll>> {
|
||||
const sanitizedTroll = sanitize(serverTroll);
|
||||
const flairs = await getManyFlairs(
|
||||
{ _id: { $in: serverTroll.flairs } },
|
||||
ServerFlairToClientFlair
|
||||
);
|
||||
let clientTroll: ClientTroll = {
|
||||
|
||||
let clientTroll: Partial<ClientTroll> = {
|
||||
...sanitizedTroll,
|
||||
trueSign: TrueSign[serverTroll.trueSign],
|
||||
falseSign:
|
||||
|
@ -21,8 +16,8 @@ export async function ServerTrollToClientTroll(
|
|||
? TrueSign[serverTroll.falseSign]
|
||||
: null,
|
||||
class: serverTroll.class ? Class[serverTroll.class] : null,
|
||||
owners: [],
|
||||
flairs: cutArray(flairs)
|
||||
owner: undefined,
|
||||
flairs: undefined
|
||||
};
|
||||
|
||||
return clientTroll;
|
||||
|
@ -36,7 +31,7 @@ export function SubmitTrollToServerTroll(
|
|||
quirks: submitTroll.quirks
|
||||
? Object.fromEntries(submitTroll.quirks)
|
||||
: undefined,
|
||||
owners: undefined,
|
||||
owner: undefined,
|
||||
flairs: undefined,
|
||||
updatedDate: new Date()
|
||||
};
|
||||
|
|
|
@ -1,47 +0,0 @@
|
|||
import { TrueSign } from "@/types/assist/extended_zodiac";
|
||||
import { SubmitUser } from "@/types/client/user";
|
||||
import { ClientUser, ServerUser } from "@/types/user";
|
||||
import { getManyFlairs } from "../flair";
|
||||
import { cutArray, cutObject, removeCode, sanitize } from "../utility/merge";
|
||||
import { ServerFlairToClientFlair } from "./flair";
|
||||
|
||||
export async function ServerUserToClientUser(
|
||||
serverUser: ServerUser
|
||||
): Promise<ClientUser> {
|
||||
const sanitizedUser = removeCode(sanitize(serverUser));
|
||||
const flairs = await getManyFlairs(
|
||||
{ _id: { $in: serverUser.flairs } },
|
||||
ServerFlairToClientFlair
|
||||
);
|
||||
let clientUser: ClientUser = {
|
||||
...sanitizedUser,
|
||||
trueSign: serverUser.trueSign ? TrueSign[serverUser.trueSign] : null,
|
||||
flairs: cutArray(flairs),
|
||||
updatedDate: serverUser.updatedDate?.getTime()
|
||||
};
|
||||
return clientUser;
|
||||
}
|
||||
|
||||
export function SubmitUserToServerUser(
|
||||
submitUser: Partial<SubmitUser>
|
||||
): Omit<Partial<ServerUser>, "_id"> {
|
||||
let serverUser: Omit<Partial<ServerUser>, "_id"> = {
|
||||
...submitUser,
|
||||
flairs: undefined,
|
||||
code: submitUser.code || "",
|
||||
updatedDate: new Date()
|
||||
};
|
||||
return serverUser;
|
||||
}
|
||||
|
||||
export function MergeServerUsers(
|
||||
submitUser: ServerUser,
|
||||
merge: Partial<Omit<ServerUser, "_id">>
|
||||
): ServerUser {
|
||||
let serverUser: ServerUser = {
|
||||
...submitUser,
|
||||
...cutObject(merge),
|
||||
updatedDate: new Date()
|
||||
};
|
||||
return serverUser;
|
||||
}
|
|
@ -1,11 +1,13 @@
|
|||
import { Levels, Permissions } from "@/permissions";
|
||||
import { ServerUser } from "@/types/user";
|
||||
import { ServerClan } from "@/types/clan";
|
||||
import CryptoJS from "crypto-js";
|
||||
import AES from "crypto-js/aes";
|
||||
import { ObjectId } from "mongodb";
|
||||
|
||||
export function getLevel(user: Partial<ServerUser> & { flairs: ObjectId[] }) {
|
||||
let highestLevel = "USER";
|
||||
export function getLevel(clan: Partial<ServerClan> & { flairs: ObjectId[] }) {
|
||||
let highestLevel = "CLAN";
|
||||
for (let level of Permissions) {
|
||||
if (user.flairs.some(oid => level.values.includes(oid.toString())))
|
||||
if (clan.flairs.some(oid => level.values.includes(oid.toString())))
|
||||
highestLevel = level.name;
|
||||
}
|
||||
return highestLevel;
|
||||
|
@ -16,13 +18,17 @@ export function compareLevels(level: string, compareLevel: string) {
|
|||
}
|
||||
|
||||
export function compareCredentials(
|
||||
user: ServerUser,
|
||||
clan: ServerClan,
|
||||
cookies: Partial<{
|
||||
[key: string]: string;
|
||||
}>
|
||||
) {
|
||||
const decryptCode = AES.decrypt(
|
||||
clan.code,
|
||||
process.env.ENCRYPT_CODE ?? "HACKTHIS"
|
||||
).toString(CryptoJS.enc.Utf8);
|
||||
return (
|
||||
user.code === cookies.TROLLCALL_CODE &&
|
||||
user.name === cookies.TROLLCALL_NAME
|
||||
decryptCode === cookies.TROLLCALL_CODE &&
|
||||
clan.name === cookies.TROLLCALL_NAME
|
||||
);
|
||||
}
|
||||
|
|
|
@ -58,8 +58,8 @@ export async function getManyPagedTrolls<T>(
|
|||
const find = readMany("trolls", query, TrollSort)
|
||||
.limit(count)
|
||||
.skip(page * count);
|
||||
const user = (await cursorToArray(find, func)) as (Awaited<T> | null)[];
|
||||
return user;
|
||||
const clan = (await cursorToArray(find, func)) as (Awaited<T> | null)[];
|
||||
return clan;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,87 +0,0 @@
|
|||
import { ServerUser } from "@/types/user";
|
||||
import { Sort } from "mongodb";
|
||||
import {
|
||||
Filter,
|
||||
createOne,
|
||||
cursorToArray,
|
||||
readMany,
|
||||
readOne,
|
||||
replaceOne
|
||||
} from "../db/crud";
|
||||
|
||||
const UserSort: Sort = { updatedDate: -1, _id: -1 };
|
||||
|
||||
/**
|
||||
* A function that returns one ServerUser from the database.
|
||||
* @param query A partial Find query. Can contain an ID.
|
||||
* @returns A ServerUser.
|
||||
*/
|
||||
|
||||
export async function getSingleUser(
|
||||
query: Filter<ServerUser>
|
||||
): Promise<ServerUser | null> {
|
||||
const user = (await readOne("users", query)) as ServerUser | null;
|
||||
return user;
|
||||
}
|
||||
|
||||
/**
|
||||
* A function that returns many ServerUsers from the database using a FindCursor.
|
||||
* @param query A partial Find query. Can contain an ID.
|
||||
* @param func A function to run on every ServerUser returned. Helps reduce loops.
|
||||
* @returns An array of ServerUsers.
|
||||
*/
|
||||
|
||||
export async function getManyUsers<T>(
|
||||
query: Filter<ServerUser>,
|
||||
func?: (input: any) => T
|
||||
): Promise<(Awaited<T> | null)[]> {
|
||||
const user = (await cursorToArray(
|
||||
readMany("users", query, UserSort),
|
||||
func
|
||||
)) as (Awaited<T> | null)[];
|
||||
return user;
|
||||
}
|
||||
|
||||
/**
|
||||
* A function that returns many ServerUsers from the database using a FindCursor, limited by count.
|
||||
* @param query A partial Find query. Can contain an ID.
|
||||
* @param func A function to run on every ServerUser returned. Helps reduce loops.
|
||||
* @returns An array of ServerUsers.
|
||||
*/
|
||||
|
||||
export async function getManyPagedUsers<T>(
|
||||
query: Filter<ServerUser>,
|
||||
func?: (input: any) => T,
|
||||
count: number = 5,
|
||||
page: number = 0
|
||||
): Promise<(Awaited<T> | null)[]> {
|
||||
const find = readMany("users", query, UserSort)
|
||||
.limit(count)
|
||||
.skip(page * count);
|
||||
const user = (await cursorToArray(find, func)) as (Awaited<T> | null)[];
|
||||
return user;
|
||||
}
|
||||
|
||||
/**
|
||||
* A function that puts one ServerUser into the database.
|
||||
* @param user A ServerUser.
|
||||
* @returns A ServerUser, or null, depending on if the operation succeeded.
|
||||
*/
|
||||
|
||||
export async function createUser(
|
||||
user: Omit<ServerUser, "_id">
|
||||
): Promise<Omit<ServerUser, "_id"> | null> {
|
||||
const newUser = await createOne("users", user);
|
||||
return newUser.acknowledged ? user : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* A function that changes one database user with the given params.
|
||||
* @param user A ServerUser.
|
||||
* @returns A ServerUser, or null, depending on if the operation succeeded.
|
||||
*/
|
||||
|
||||
export async function changeUser(user: ServerUser): Promise<ServerUser | null> {
|
||||
const newUser = await replaceOne("users", { _id: user._id }, user);
|
||||
return newUser.acknowledged ? user : null;
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
import { ServerUserToClientUser } from "@/lib/trollcall/convert/user";
|
||||
import { getManyPagedUsers } from "@/lib/trollcall/user";
|
||||
import { getManyPagedClans } from "@/lib/trollcall/clan";
|
||||
import { ServerClanToClientClan } from "@/lib/trollcall/convert/clan";
|
||||
import { NextApiRequest, NextApiResponse } from "next";
|
||||
|
||||
export default async function handler(
|
||||
|
@ -9,13 +9,13 @@ export default async function handler(
|
|||
const { method, query } = req;
|
||||
const page = query.page ? query.page[0] : 0;
|
||||
if (method === "GET") {
|
||||
const users = await getManyPagedUsers(
|
||||
const clans = await getManyPagedClans(
|
||||
{},
|
||||
ServerUserToClientUser,
|
||||
ServerClanToClientClan,
|
||||
5,
|
||||
page
|
||||
);
|
||||
if (users == null) return res.status(404).end();
|
||||
res.json(users);
|
||||
if (clans == null) return res.status(404).end();
|
||||
res.json(clans);
|
||||
} else return res.status(405).end();
|
||||
}
|
85
src/pages/api/clan/[clan]/index.ts
Normal file
85
src/pages/api/clan/[clan]/index.ts
Normal file
|
@ -0,0 +1,85 @@
|
|||
import { ClanGET } from "@/lib/trollcall/api/clan";
|
||||
import { changeClan, getSingleClan } from "@/lib/trollcall/clan";
|
||||
import {
|
||||
MergeServerClans,
|
||||
SubmitClanToServerClan
|
||||
} from "@/lib/trollcall/convert/clan";
|
||||
import {
|
||||
compareCredentials,
|
||||
compareLevels,
|
||||
getLevel
|
||||
} from "@/lib/trollcall/perms";
|
||||
import { PartialClanSchema, SubmitClan } from "@/types/client/clan";
|
||||
import { serialize } from "cookie";
|
||||
import AES from "crypto-js/aes";
|
||||
import { nanoid } from "nanoid";
|
||||
import { NextApiRequest, NextApiResponse } from "next";
|
||||
|
||||
export default async function handler(
|
||||
req: NextApiRequest,
|
||||
res: NextApiResponse
|
||||
) {
|
||||
const { body, cookies, query, method } = req;
|
||||
if (method === "GET") {
|
||||
res.json(await ClanGET(query));
|
||||
} else if (method === "PUT") {
|
||||
let validatedClan: Partial<SubmitClan>;
|
||||
try {
|
||||
validatedClan = (await PartialClanSchema.validate(body, {
|
||||
stripUnknown: true
|
||||
})) as Partial<SubmitClan>;
|
||||
} catch (err) {
|
||||
return res.status(400).send(err);
|
||||
}
|
||||
const checkExistingClan = await getSingleClan({
|
||||
name: query.clan
|
||||
});
|
||||
if (checkExistingClan == null) return res.status(404).end();
|
||||
let isModerator = false;
|
||||
if (!compareCredentials(checkExistingClan, cookies)) {
|
||||
const thisClan = await getSingleClan({
|
||||
name: cookies.TROLLCALL_NAME
|
||||
});
|
||||
if (thisClan == null || !compareCredentials(thisClan, cookies))
|
||||
return res.status(403).end();
|
||||
if (!compareLevels(getLevel(thisClan), "MODERATOR"))
|
||||
return res.status(403).end();
|
||||
isModerator = true;
|
||||
}
|
||||
const serverClan = SubmitClanToServerClan(validatedClan);
|
||||
if (serverClan.code == null)
|
||||
serverClan.code = checkExistingClan.code || nanoid(16);
|
||||
|
||||
// Encrypt code lole
|
||||
serverClan.code = AES.encrypt(
|
||||
serverClan.code,
|
||||
process.env.ENCRYPT_CODE ?? "HACKTHIS"
|
||||
).toString();
|
||||
|
||||
if (!compareLevels(getLevel(checkExistingClan), "SUPPORTER")) {
|
||||
serverClan.bgimage = null;
|
||||
serverClan.css = null;
|
||||
}
|
||||
const bothClans = MergeServerClans(checkExistingClan, serverClan);
|
||||
const newClan = await changeClan(bothClans);
|
||||
if (newClan == null) return res.status(503).end();
|
||||
// Give cookies, redundant style
|
||||
if (!isModerator)
|
||||
// don't set cookies if moderator is changing credentials
|
||||
res.setHeader("Set-Cookie", [
|
||||
serialize("TROLLCALL_NAME", newClan.name, {
|
||||
path: "/",
|
||||
maxAge: 31540000
|
||||
}),
|
||||
serialize("TROLLCALL_CODE", newClan.code, {
|
||||
path: "/",
|
||||
maxAge: 31540000
|
||||
}),
|
||||
serialize("TROLLCALL_PFP", newClan.pfp ?? "", {
|
||||
path: "/",
|
||||
maxAge: 31540000
|
||||
})
|
||||
]).json(newClan);
|
||||
else res.json(newClan);
|
||||
} else return res.status(405).end();
|
||||
}
|
63
src/pages/api/clan/index.ts
Normal file
63
src/pages/api/clan/index.ts
Normal file
|
@ -0,0 +1,63 @@
|
|||
import { createClan, getSingleClan } from "@/lib/trollcall/clan";
|
||||
import { SubmitClanToServerClan } from "@/lib/trollcall/convert/clan";
|
||||
import { compareLevels, getLevel } from "@/lib/trollcall/perms";
|
||||
import { ServerClan } from "@/types/clan";
|
||||
import { SubmitClanSchema } from "@/types/client/clan";
|
||||
import { serialize } from "cookie";
|
||||
import AES from "crypto-js/aes";
|
||||
import { nanoid } from "nanoid";
|
||||
import { NextApiRequest, NextApiResponse } from "next";
|
||||
|
||||
export default async function handler(
|
||||
req: NextApiRequest,
|
||||
res: NextApiResponse
|
||||
) {
|
||||
const { body, method } = req;
|
||||
if (method === "POST") {
|
||||
let validatedClan;
|
||||
try {
|
||||
validatedClan = await SubmitClanSchema.validate(body, {
|
||||
stripUnknown: true
|
||||
});
|
||||
} catch (err) {
|
||||
return res.status(400).send(err);
|
||||
}
|
||||
const checkExistingClan = await getSingleClan({
|
||||
name: validatedClan.name
|
||||
});
|
||||
if (checkExistingClan != null) return res.status(409).end();
|
||||
// we are sure this object is full, so cast partial
|
||||
const serverClan = SubmitClanToServerClan(validatedClan) as Omit<
|
||||
ServerClan,
|
||||
"_id"
|
||||
>;
|
||||
if (serverClan.code == null) serverClan.code = nanoid(16);
|
||||
|
||||
// Encrypt code lole
|
||||
serverClan.code = AES.encrypt(
|
||||
serverClan.code,
|
||||
process.env.ENCRYPT_CODE ?? "HACKTHIS"
|
||||
).toString();
|
||||
|
||||
if (!compareLevels(getLevel(serverClan), "SUPPORTER"))
|
||||
serverClan.bgimage = null;
|
||||
const newClan = await createClan(serverClan);
|
||||
if (newClan == null) return res.status(503).end();
|
||||
// Give cookies
|
||||
res.setHeader("Set-Cookie", [
|
||||
serialize("TROLLCALL_NAME", newClan.name, {
|
||||
path: "/",
|
||||
maxAge: 31540000
|
||||
}),
|
||||
serialize("TROLLCALL_CODE", newClan.code, {
|
||||
path: "/",
|
||||
maxAge: 31540000
|
||||
}),
|
||||
serialize("TROLLCALL_PFP", newClan.pfp ?? "", {
|
||||
path: "/",
|
||||
maxAge: 31540000
|
||||
})
|
||||
]);
|
||||
res.json(newClan);
|
||||
} else return res.status(405).end();
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
import { getSingleClan } from "@/lib/trollcall/clan";
|
||||
import { ServerTrollToClientTroll } from "@/lib/trollcall/convert/troll";
|
||||
import { getManyPagedTrolls } from "@/lib/trollcall/troll";
|
||||
import { getSingleUser } from "@/lib/trollcall/user";
|
||||
import { NextApiRequest, NextApiResponse } from "next";
|
||||
|
||||
export default async function handler(
|
||||
|
@ -10,13 +10,13 @@ export default async function handler(
|
|||
const { method, query } = req;
|
||||
const page = query.page ? query.page[0] : 0;
|
||||
if (method === "GET") {
|
||||
const user = await getSingleUser({
|
||||
name: query.user
|
||||
const clan = await getSingleClan({
|
||||
name: query.clan
|
||||
});
|
||||
if (user == null) return res.status(404).end();
|
||||
if (clan == null) return res.status(404).end();
|
||||
const trolls = await getManyPagedTrolls(
|
||||
{
|
||||
"owners.0": user._id
|
||||
"owner": clan._id
|
||||
},
|
||||
ServerTrollToClientTroll,
|
||||
5,
|
|
@ -1,15 +1,20 @@
|
|||
import { ClanGET } from "@/lib/trollcall/api/clan";
|
||||
import { getSingleClan } from "@/lib/trollcall/clan";
|
||||
import { ServerFlairToClientFlair } from "@/lib/trollcall/convert/flair";
|
||||
import {
|
||||
MergeServerTrolls,
|
||||
ServerTrollToClientTroll,
|
||||
SubmitTrollToServerTroll
|
||||
} from "@/lib/trollcall/convert/troll";
|
||||
import { getManyFlairs } from "@/lib/trollcall/flair";
|
||||
import {
|
||||
compareCredentials,
|
||||
compareLevels,
|
||||
getLevel
|
||||
} from "@/lib/trollcall/perms";
|
||||
import { changeTroll, getSingleTroll } from "@/lib/trollcall/troll";
|
||||
import { getSingleUser } from "@/lib/trollcall/user";
|
||||
import { cutArray } from "@/lib/trollcall/utility/merge";
|
||||
import { ClientClan } from "@/types/clan";
|
||||
import { PartialTrollSchema, SubmitTroll } from "@/types/client/troll";
|
||||
import { NextApiRequest, NextApiResponse } from "next";
|
||||
|
||||
|
@ -19,16 +24,24 @@ export default async function handler(
|
|||
) {
|
||||
const { query, cookies, method, body } = req;
|
||||
if (method === "GET") {
|
||||
const user = await getSingleUser({
|
||||
name: query.user
|
||||
const clan = await getSingleClan({
|
||||
name: query.clan
|
||||
});
|
||||
if (user == null) return res.status(404).end();
|
||||
if (clan == null) return res.status(404).end();
|
||||
const troll = await getSingleTroll({
|
||||
"name.0": query.troll,
|
||||
"owners.0": user._id
|
||||
"owner": clan._id
|
||||
});
|
||||
if (troll == null) return res.status(404).end();
|
||||
const serverTroll = await ServerTrollToClientTroll(troll);
|
||||
serverTroll.flairs = cutArray(
|
||||
await getManyFlairs(
|
||||
{ _id: { $in: troll.flairs } },
|
||||
ServerFlairToClientFlair
|
||||
)
|
||||
);
|
||||
// we know this is not null, as we passed in our own clan
|
||||
serverTroll.owner = (await ClanGET(null, clan)) as ClientClan;
|
||||
res.json(serverTroll);
|
||||
} else if (method === "PUT") {
|
||||
let validatedTroll: Partial<SubmitTroll>;
|
||||
|
@ -39,23 +52,23 @@ export default async function handler(
|
|||
} catch (err) {
|
||||
return res.status(400).send(err);
|
||||
}
|
||||
const checkUser = await getSingleUser({
|
||||
name: query.user
|
||||
const checkClan = await getSingleClan({
|
||||
name: query.clan
|
||||
});
|
||||
if (checkUser == null) return res.status(404).end();
|
||||
if (!compareCredentials(checkUser, cookies)) {
|
||||
const thisUser = await getSingleUser({
|
||||
if (checkClan == null) return res.status(404).end();
|
||||
if (!compareCredentials(checkClan, cookies)) {
|
||||
const thisClan = await getSingleClan({
|
||||
name: cookies.TROLLCALL_NAME
|
||||
});
|
||||
if (thisUser == null || !compareCredentials(thisUser, cookies))
|
||||
if (thisClan == null || !compareCredentials(thisClan, cookies))
|
||||
return res.status(403).end();
|
||||
console.log(getLevel(thisUser));
|
||||
if (!compareLevels(getLevel(thisUser), "MODERATOR"))
|
||||
console.log(getLevel(thisClan));
|
||||
if (!compareLevels(getLevel(thisClan), "MODERATOR"))
|
||||
return res.status(403).end();
|
||||
}
|
||||
const editingTroll = await getSingleTroll({
|
||||
"name.0": query.troll,
|
||||
"owners.0": checkUser._id
|
||||
"owner": checkClan._id
|
||||
});
|
||||
if (editingTroll == null) return res.status(404).end();
|
||||
const serverTroll = SubmitTrollToServerTroll(validatedTroll);
|
|
@ -1,10 +1,10 @@
|
|||
import { getSingleClan } from "@/lib/trollcall/clan";
|
||||
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(
|
||||
|
@ -13,22 +13,22 @@ export default async function handler(
|
|||
) {
|
||||
const { query, cookies, method, body } = req;
|
||||
if (method === "GET") {
|
||||
const user = await getSingleUser({
|
||||
name: query.user
|
||||
const clan = await getSingleClan({
|
||||
name: query.clan
|
||||
});
|
||||
if (user == null) return res.status(404).end();
|
||||
if (!compareCredentials(user, cookies)) {
|
||||
const thisUser = await getSingleUser({
|
||||
if (clan == null) return res.status(404).end();
|
||||
if (!compareCredentials(clan, cookies)) {
|
||||
const thisClan = await getSingleClan({
|
||||
name: cookies.TROLLCALL_NAME
|
||||
});
|
||||
if (thisUser == null || !compareCredentials(thisUser, cookies))
|
||||
if (thisClan == null || !compareCredentials(thisClan, cookies))
|
||||
return res.status(403).end();
|
||||
if (!compareLevels(getLevel(thisUser), "MODERATOR"))
|
||||
if (!compareLevels(getLevel(thisClan), "MODERATOR"))
|
||||
return res.status(403).end();
|
||||
}
|
||||
const troll = await getSingleTroll({
|
||||
"name.0": query.troll,
|
||||
"owners.0": user._id
|
||||
"owner": clan._id
|
||||
});
|
||||
if (troll == null) return res.status(404).end();
|
||||
res.json(troll);
|
|
@ -1,7 +1,7 @@
|
|||
import { getSingleClan } from "@/lib/trollcall/clan";
|
||||
import { SubmitTrollToServerTroll } from "@/lib/trollcall/convert/troll";
|
||||
import { compareCredentials } from "@/lib/trollcall/perms";
|
||||
import { createTroll, getSingleTroll } from "@/lib/trollcall/troll";
|
||||
import { getSingleUser } from "@/lib/trollcall/user";
|
||||
import { SubmitTrollSchema } from "@/types/client/troll";
|
||||
import { ServerTroll } from "@/types/troll";
|
||||
import { NextApiRequest, NextApiResponse } from "next";
|
||||
|
@ -20,15 +20,15 @@ export default async function handler(
|
|||
} catch (err) {
|
||||
return res.status(400).send(err);
|
||||
}
|
||||
const checkUser = await getSingleUser({
|
||||
const checkClan = await getSingleClan({
|
||||
name: cookies.TROLLCALL_NAME
|
||||
});
|
||||
if (checkUser == null) return res.status(404).end();
|
||||
if (!compareCredentials(checkUser, cookies))
|
||||
if (checkClan == null) return res.status(404).end();
|
||||
if (!compareCredentials(checkClan, cookies))
|
||||
return res.status(403).end();
|
||||
const checkExistingTroll = await getSingleTroll({
|
||||
"name.0": validatedTroll.name[0],
|
||||
"owners": checkUser._id
|
||||
"owner": checkClan._id
|
||||
});
|
||||
if (checkExistingTroll != null) return res.status(409).end();
|
||||
// we are sure this object is full, so cast partial
|
||||
|
@ -36,7 +36,7 @@ export default async function handler(
|
|||
ServerTroll,
|
||||
"_id"
|
||||
>;
|
||||
serverTroll.owners[0] = checkUser._id;
|
||||
serverTroll.owner = checkClan._id;
|
||||
const newTroll = await createTroll(serverTroll);
|
||||
if (newTroll == null) return res.status(503).end();
|
||||
res.json(newTroll);
|
||||
|
|
|
@ -1,82 +0,0 @@
|
|||
import {
|
||||
MergeServerUsers,
|
||||
ServerUserToClientUser,
|
||||
SubmitUserToServerUser
|
||||
} from "@/lib/trollcall/convert/user";
|
||||
import {
|
||||
compareCredentials,
|
||||
compareLevels,
|
||||
getLevel
|
||||
} from "@/lib/trollcall/perms";
|
||||
import { changeUser, getSingleUser } from "@/lib/trollcall/user";
|
||||
import { PartialUserSchema, SubmitUser } from "@/types/client/user";
|
||||
import { serialize } from "cookie";
|
||||
import { nanoid } from "nanoid";
|
||||
import { NextApiRequest, NextApiResponse } from "next";
|
||||
|
||||
export default async function handler(
|
||||
req: NextApiRequest,
|
||||
res: NextApiResponse
|
||||
) {
|
||||
const { body, cookies, query, method } = req;
|
||||
if (method === "GET") {
|
||||
const user = await getSingleUser({
|
||||
name: query.user
|
||||
});
|
||||
if (user == null) return res.status(404).end();
|
||||
const serverUser = await ServerUserToClientUser(user);
|
||||
res.json(serverUser);
|
||||
} else if (method === "PUT") {
|
||||
let validatedUser: Partial<SubmitUser>;
|
||||
try {
|
||||
validatedUser = (await PartialUserSchema.validate(body, {
|
||||
stripUnknown: true
|
||||
})) as Partial<SubmitUser>;
|
||||
} catch (err) {
|
||||
return res.status(400).send(err);
|
||||
}
|
||||
const checkExistingUser = await getSingleUser({
|
||||
name: query.user
|
||||
});
|
||||
if (checkExistingUser == null) return res.status(404).end();
|
||||
let isModerator = false;
|
||||
if (!compareCredentials(checkExistingUser, 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();
|
||||
isModerator = true;
|
||||
}
|
||||
const serverUser = SubmitUserToServerUser(validatedUser);
|
||||
if (serverUser.code === "")
|
||||
serverUser.code = checkExistingUser.code || nanoid(16);
|
||||
if (!compareLevels(getLevel(checkExistingUser), "SUPPORTER")) {
|
||||
serverUser.bgimage = null;
|
||||
serverUser.css = null;
|
||||
}
|
||||
const bothUsers = MergeServerUsers(checkExistingUser, serverUser);
|
||||
const newUser = await changeUser(bothUsers);
|
||||
if (newUser == null) return res.status(503).end();
|
||||
// Give cookies, redundant style
|
||||
if (!isModerator)
|
||||
// don't set cookies if moderator is changing credentials
|
||||
res.setHeader("Set-Cookie", [
|
||||
serialize("TROLLCALL_NAME", newUser.name, {
|
||||
path: "/",
|
||||
maxAge: 31540000
|
||||
}),
|
||||
serialize("TROLLCALL_CODE", newUser.code, {
|
||||
path: "/",
|
||||
maxAge: 31540000
|
||||
}),
|
||||
serialize("TROLLCALL_PFP", newUser.pfp ?? "", {
|
||||
path: "/",
|
||||
maxAge: 31540000
|
||||
})
|
||||
]).json(newUser);
|
||||
else res.json(newUser);
|
||||
} else return res.status(405).end();
|
||||
}
|
|
@ -1,55 +0,0 @@
|
|||
import { SubmitUserToServerUser } from "@/lib/trollcall/convert/user";
|
||||
import { compareLevels, getLevel } from "@/lib/trollcall/perms";
|
||||
import { createUser, getSingleUser } from "@/lib/trollcall/user";
|
||||
import { SubmitUserSchema } from "@/types/client/user";
|
||||
import { ServerUser } from "@/types/user";
|
||||
import { serialize } from "cookie";
|
||||
import { nanoid } from "nanoid";
|
||||
import { NextApiRequest, NextApiResponse } from "next";
|
||||
|
||||
export default async function handler(
|
||||
req: NextApiRequest,
|
||||
res: NextApiResponse
|
||||
) {
|
||||
const { body, method } = req;
|
||||
if (method === "POST") {
|
||||
let validatedUser;
|
||||
try {
|
||||
validatedUser = await SubmitUserSchema.validate(body, {
|
||||
stripUnknown: true
|
||||
});
|
||||
} catch (err) {
|
||||
return res.status(400).send(err);
|
||||
}
|
||||
const checkExistingUser = await getSingleUser({
|
||||
name: validatedUser.name
|
||||
});
|
||||
if (checkExistingUser != null) return res.status(409).end();
|
||||
// we are sure this object is full, so cast partial
|
||||
const serverUser = SubmitUserToServerUser(validatedUser) as Omit<
|
||||
ServerUser,
|
||||
"_id"
|
||||
>;
|
||||
if (serverUser.code === "") serverUser.code = nanoid(16);
|
||||
if (!compareLevels(getLevel(serverUser), "SUPPORTER"))
|
||||
serverUser.bgimage = null;
|
||||
const newUser = await createUser(serverUser);
|
||||
if (newUser == null) return res.status(503).end();
|
||||
// Give cookies
|
||||
res.setHeader("Set-Cookie", [
|
||||
serialize("TROLLCALL_NAME", newUser.name, {
|
||||
path: "/",
|
||||
maxAge: 31540000
|
||||
}),
|
||||
serialize("TROLLCALL_CODE", newUser.code, {
|
||||
path: "/",
|
||||
maxAge: 31540000
|
||||
}),
|
||||
serialize("TROLLCALL_PFP", newUser.pfp ?? "", {
|
||||
path: "/",
|
||||
maxAge: 31540000
|
||||
})
|
||||
]);
|
||||
res.json(newUser);
|
||||
} else return res.status(405).end();
|
||||
}
|
20
src/types/clan.ts
Normal file
20
src/types/clan.ts
Normal file
|
@ -0,0 +1,20 @@
|
|||
import { WithId } from "@/lib/db/crud";
|
||||
import * as yup from "yup";
|
||||
import { ObjectIdSchema } from "./assist/mongo";
|
||||
import { SubmitClanSchema } from "./client/clan";
|
||||
import { ClientFlairSchema } from "./flair";
|
||||
|
||||
export const ServerClanSchema = SubmitClanSchema.shape({
|
||||
flairs: yup.array().of(ObjectIdSchema.required()).required(),
|
||||
code: yup.string().required().max(10000),
|
||||
updatedDate: yup.date().notRequired()
|
||||
});
|
||||
|
||||
export type ServerClan = WithId<yup.InferType<typeof ServerClanSchema>>;
|
||||
|
||||
export const ClientClanSchema = SubmitClanSchema.shape({
|
||||
flairs: yup.array().of(ClientFlairSchema.required()).required(),
|
||||
updatedDate: yup.number().notRequired()
|
||||
});
|
||||
|
||||
export type ClientClan = yup.InferType<typeof ClientClanSchema>;
|
139
src/types/client/clan.ts
Normal file
139
src/types/client/clan.ts
Normal file
|
@ -0,0 +1,139 @@
|
|||
import * as yup from "yup";
|
||||
import { PolicySchema } from "../assist/generics";
|
||||
|
||||
export const SubmitClanSchema = yup
|
||||
.object({
|
||||
name: yup
|
||||
.string()
|
||||
.required()
|
||||
.matches(/^[\w-]+$/, "No special characters or spaces")
|
||||
.min(3)
|
||||
.max(50)
|
||||
.lowercase(),
|
||||
members: yup
|
||||
.array()
|
||||
.of(
|
||||
yup
|
||||
.object({
|
||||
name: yup.string().required().min(3).max(50),
|
||||
pronouns: yup
|
||||
.array()
|
||||
.of(
|
||||
yup.tuple([
|
||||
yup
|
||||
.string()
|
||||
.required()
|
||||
.matches(/^[A-z]+$/, "Letters only")
|
||||
.max(10)
|
||||
.lowercase(), // she, he, they
|
||||
yup
|
||||
.string()
|
||||
.required()
|
||||
.matches(/^[A-z]+$/, "Letters only")
|
||||
.max(10)
|
||||
.lowercase(), // her, him, them
|
||||
yup
|
||||
.string()
|
||||
.required()
|
||||
.matches(/^[A-z]+$/, "Letters only")
|
||||
.max(10)
|
||||
.lowercase() // hers, his, theirs
|
||||
])
|
||||
)
|
||||
.required()
|
||||
.min(1)
|
||||
})
|
||||
.required()
|
||||
)
|
||||
.required()
|
||||
.min(1)
|
||||
.max(20),
|
||||
description: yup.string().max(10000).ensure(),
|
||||
url: yup.string().notRequired().url(),
|
||||
color: yup
|
||||
.tuple([
|
||||
yup.number().min(0).max(255),
|
||||
yup.number().min(0).max(255),
|
||||
yup.number().min(0).max(255)
|
||||
])
|
||||
.notRequired(),
|
||||
policies: yup
|
||||
.object({
|
||||
fanart: PolicySchema.required(),
|
||||
fanartOthers: PolicySchema.required(),
|
||||
kinning: PolicySchema.required(),
|
||||
shipping: PolicySchema.required(),
|
||||
fanfiction: PolicySchema.required()
|
||||
})
|
||||
.required(),
|
||||
pfp: yup.string().notRequired().url(),
|
||||
bgimage: yup.string().notRequired().url(),
|
||||
css: yup.string().notRequired(),
|
||||
code: yup.string().notRequired().max(256, "Too secure!!")
|
||||
// flairs: yup.array().of(ClientFlairSchema).required(),
|
||||
})
|
||||
.required();
|
||||
|
||||
export type SubmitClan = yup.InferType<typeof SubmitClanSchema>;
|
||||
|
||||
export const PartialClanSchema = yup
|
||||
.object({
|
||||
name: yup
|
||||
.string()
|
||||
.matches(/^[\w-]+$/, "No special characters or spaces")
|
||||
.min(3)
|
||||
.max(50)
|
||||
.lowercase(),
|
||||
members: yup
|
||||
.array()
|
||||
.of(
|
||||
yup.object({
|
||||
name: yup.string().min(3).max(50),
|
||||
pronouns: yup
|
||||
.array()
|
||||
.of(
|
||||
yup.tuple([
|
||||
yup
|
||||
.string()
|
||||
.matches(/^[A-z]+$/, "Letters only")
|
||||
.max(10)
|
||||
.lowercase(), // she, he, they
|
||||
yup
|
||||
.string()
|
||||
.matches(/^[A-z]+$/, "Letters only")
|
||||
.max(10)
|
||||
.lowercase(), // her, him, them
|
||||
yup
|
||||
.string()
|
||||
.matches(/^[A-z]+$/, "Letters only")
|
||||
.max(10)
|
||||
.lowercase() // hers, his, theirs
|
||||
])
|
||||
)
|
||||
.min(1)
|
||||
})
|
||||
)
|
||||
.min(1),
|
||||
description: yup.string().max(10000),
|
||||
url: yup.string().url(),
|
||||
color: yup.tuple([
|
||||
yup.number().min(0).max(255),
|
||||
yup.number().min(0).max(255),
|
||||
yup.number().min(0).max(255)
|
||||
]),
|
||||
policies: yup.object({
|
||||
fanart: PolicySchema,
|
||||
fanartOthers: PolicySchema,
|
||||
kinning: PolicySchema,
|
||||
shipping: PolicySchema,
|
||||
fanfiction: PolicySchema
|
||||
}),
|
||||
pfp: yup.string().url(),
|
||||
bgimage: yup.string().url(),
|
||||
css: yup.string(),
|
||||
code: yup.string().max(256, "Too secure!!")
|
||||
// flairs: yup.array().of(ClientFlairSchema).required(),
|
||||
})
|
||||
.required();
|
||||
|
||||
export type PartialClan = yup.InferType<typeof PartialClanSchema>;
|
|
@ -31,12 +31,14 @@ export const SubmitTrollSchema = yup
|
|||
.string()
|
||||
.required()
|
||||
.matches(/^[A-z-]+$/, "Letters only")
|
||||
.lowercase(),
|
||||
.lowercase()
|
||||
.max(50),
|
||||
yup
|
||||
.string()
|
||||
.required()
|
||||
.matches(/^[A-z-]+$/, "Letters only")
|
||||
.lowercase()
|
||||
.max(50)
|
||||
])
|
||||
.required(),
|
||||
pronouns: yup
|
||||
|
@ -137,8 +139,6 @@ export const SubmitTrollSchema = yup
|
|||
shipping: PolicySchema.required(),
|
||||
fanfiction: PolicySchema.required()
|
||||
})
|
||||
// owners: yup.array().of(yup.string().required()).required().min(1),
|
||||
// flairs: yup.array().of(yup.mixed()).required().ensure(),
|
||||
})
|
||||
.required();
|
||||
|
||||
|
|
|
@ -1,136 +0,0 @@
|
|||
import * as yup from "yup";
|
||||
import { TrueSignKeys } from "../assist/extended_zodiac";
|
||||
import { PolicySchema } from "../assist/generics";
|
||||
|
||||
export const SubmitUserSchema = yup
|
||||
.object({
|
||||
name: yup
|
||||
.string()
|
||||
.required()
|
||||
.matches(/^[\w-]+$/, "No special characters or spaces")
|
||||
.min(3)
|
||||
.max(50)
|
||||
.lowercase(),
|
||||
description: yup.string().max(10000).ensure(),
|
||||
url: yup.string().notRequired().url(),
|
||||
trueSign: yup.string().notRequired().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: yup
|
||||
.tuple([
|
||||
yup.number().min(0).max(255),
|
||||
yup.number().min(0).max(255),
|
||||
yup.number().min(0).max(255)
|
||||
])
|
||||
.notRequired(),
|
||||
policies: yup
|
||||
.object({
|
||||
fanart: PolicySchema.required(),
|
||||
fanartOthers: PolicySchema.required(),
|
||||
kinning: PolicySchema.required(),
|
||||
shipping: PolicySchema.required(),
|
||||
fanfiction: PolicySchema.required()
|
||||
})
|
||||
.required(),
|
||||
pfp: yup.string().notRequired().url(),
|
||||
bgimage: yup.string().notRequired().url(),
|
||||
css: yup.string().notRequired(),
|
||||
code: yup.string().notRequired().max(256, "Too secure!!")
|
||||
// flairs: yup.array().of(ClientFlairSchema).required(),
|
||||
})
|
||||
.required();
|
||||
|
||||
export type SubmitUser = yup.InferType<typeof SubmitUserSchema>;
|
||||
|
||||
export const PartialUserSchema = yup
|
||||
.object({
|
||||
name: yup
|
||||
.string()
|
||||
.matches(/^[\w-]+$/, "No special characters or spaces")
|
||||
.min(3)
|
||||
.max(50)
|
||||
.lowercase(),
|
||||
description: yup.string().max(10000),
|
||||
url: yup.string().url(),
|
||||
trueSign: yup
|
||||
.string()
|
||||
.nullable()
|
||||
.transform(v => {
|
||||
return v === "" ? null : v;
|
||||
})
|
||||
.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([
|
||||
yup.number().min(0).max(255),
|
||||
yup.number().min(0).max(255),
|
||||
yup.number().min(0).max(255)
|
||||
]),
|
||||
policies: yup.object({
|
||||
fanart: PolicySchema,
|
||||
fanartOthers: PolicySchema,
|
||||
kinning: PolicySchema,
|
||||
shipping: PolicySchema,
|
||||
fanfiction: PolicySchema
|
||||
}),
|
||||
pfp: yup.string().url(),
|
||||
bgimage: yup.string().url(),
|
||||
css: yup.string(),
|
||||
code: yup.string().max(256, "Too secure!!")
|
||||
// flairs: yup.array().of(ClientFlairSchema).required(),
|
||||
})
|
||||
.required();
|
||||
|
||||
export type PartialUser = yup.InferType<typeof PartialUserSchema>;
|
|
@ -1,9 +1,9 @@
|
|||
import { WithId } from "@/lib/db/crud";
|
||||
import * as yup from "yup";
|
||||
import { ObjectIdSchema } from "./assist/mongo";
|
||||
import { ClientClanSchema } from "./clan";
|
||||
import { SubmitDialogSchema } from "./client/dialoglog";
|
||||
import { ClientTroll, ClientTrollSchema } from "./troll";
|
||||
import { ClientUserSchema } from "./user";
|
||||
|
||||
export const ServerDialogSchema = SubmitDialogSchema.shape({
|
||||
owners: yup.array().of(ObjectIdSchema.required()).required().min(1),
|
||||
|
@ -23,7 +23,7 @@ export const ServerDialogSchema = SubmitDialogSchema.shape({
|
|||
export type ServerDialog = WithId<yup.InferType<typeof ServerDialogSchema>>;
|
||||
|
||||
export const ClientDialogSchema = SubmitDialogSchema.shape({
|
||||
owners: yup.array().of(ClientUserSchema.required()).required().min(1),
|
||||
owners: yup.array().of(ClientClanSchema.required()).required().min(1),
|
||||
characters: yup
|
||||
.array()
|
||||
.of(
|
||||
|
|
|
@ -2,13 +2,13 @@ import { WithId } from "@/lib/db/crud";
|
|||
import * as yup from "yup";
|
||||
import { ClassSchema, TrueSignSchema } from "./assist/extended_zodiac";
|
||||
import { ObjectIdSchema } from "./assist/mongo";
|
||||
import { ClientClanSchema } from "./clan";
|
||||
import { SubmitTrollSchema } from "./client/troll";
|
||||
import { ClientFlairSchema } from "./flair";
|
||||
import { ServerQuirkHolder, ServerQuirkHolderSchema } from "./quirks";
|
||||
import { ClientUserSchema } from "./user";
|
||||
|
||||
export const ServerTrollSchema = SubmitTrollSchema.shape({
|
||||
owners: yup.array().of(ObjectIdSchema.required()).required().min(1),
|
||||
owner: ObjectIdSchema.required(),
|
||||
flairs: yup.array().of(ObjectIdSchema.required()).required(),
|
||||
quirks: ServerQuirkHolderSchema.required(),
|
||||
updatedDate: yup.date().notRequired()
|
||||
|
@ -17,7 +17,7 @@ export const ServerTrollSchema = SubmitTrollSchema.shape({
|
|||
export type ServerTroll = WithId<yup.InferType<typeof ServerTrollSchema>>;
|
||||
|
||||
export const ClientTrollSchema = SubmitTrollSchema.shape({
|
||||
owners: yup.array().of(ClientUserSchema.required()).required().min(1),
|
||||
owner: ClientClanSchema.required(),
|
||||
flairs: yup.array().of(ClientFlairSchema.required()).required(),
|
||||
quirks: ServerQuirkHolderSchema.required(),
|
||||
trueSign: TrueSignSchema.notRequired(),
|
||||
|
|
|
@ -1,22 +0,0 @@
|
|||
import { WithId } from "@/lib/db/crud";
|
||||
import * as yup from "yup";
|
||||
import { TrueSignSchema } from "./assist/extended_zodiac";
|
||||
import { ObjectIdSchema } from "./assist/mongo";
|
||||
import { SubmitUserSchema } from "./client/user";
|
||||
import { ClientFlairSchema } from "./flair";
|
||||
|
||||
export const ServerUserSchema = SubmitUserSchema.shape({
|
||||
flairs: yup.array().of(ObjectIdSchema.required()).required(),
|
||||
code: yup.string().required(),
|
||||
updatedDate: yup.date().notRequired()
|
||||
});
|
||||
|
||||
export type ServerUser = WithId<yup.InferType<typeof ServerUserSchema>>;
|
||||
|
||||
export const ClientUserSchema = SubmitUserSchema.shape({
|
||||
flairs: yup.array().of(ClientFlairSchema.required()).required(),
|
||||
trueSign: TrueSignSchema.notRequired(),
|
||||
updatedDate: yup.number().notRequired()
|
||||
});
|
||||
|
||||
export type ClientUser = yup.InferType<typeof ClientUserSchema>;
|
Loading…
Reference in a new issue