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
|
# TrollCallAPIs
|
||||||
|
|
||||||
A set of TrollCallNotAgain-equivalent API hooks, made to let developers create third-party apps for the TrollCall service.
|
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))
|
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:
|
There are a few issues with the existing APIs as well:
|
||||||
|
|
||||||
1. Objects get duplicated if their name/first-name is changed.
|
1. Objects get duplicated if their name/first-name is changed.
|
||||||
|
|
||||||
Doing this:
|
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:
|
results in this on the database:
|
||||||
|
|
||||||
```
|
```
|
||||||
trolls/
|
trolls/
|
||||||
|- Document {"name": ["name1", ...], ...}
|
|- Document {"name": ["name1", ...], ...}
|
||||||
|- Document {"name": ["name2", ...], ...}
|
|- Document {"name": ["name2", ...], ...}
|
||||||
```
|
```
|
||||||
|
|
||||||
which is not good.
|
which is not good.
|
||||||
|
|
||||||
2. More issues that I forgot
|
2. More issues that I forgot
|
||||||
|
|
12
package-lock.json
generated
12
package-lock.json
generated
|
@ -10,10 +10,12 @@
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/cookie-parser": "^1.4.3",
|
"@types/cookie-parser": "^1.4.3",
|
||||||
|
"@types/crypto-js": "^4.1.1",
|
||||||
"@types/react": "^18.2.14",
|
"@types/react": "^18.2.14",
|
||||||
"body-parser": "^1.20.2",
|
"body-parser": "^1.20.2",
|
||||||
"cookie": "^0.5.0",
|
"cookie": "^0.5.0",
|
||||||
"cookie-parser": "^1.4.6",
|
"cookie-parser": "^1.4.6",
|
||||||
|
"crypto-js": "^4.1.1",
|
||||||
"dotenv": "^16.3.0",
|
"dotenv": "^16.3.0",
|
||||||
"express": "^4.18.2",
|
"express": "^4.18.2",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
|
@ -262,6 +264,11 @@
|
||||||
"@types/express": "*"
|
"@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": {
|
"node_modules/@types/express": {
|
||||||
"version": "4.17.17",
|
"version": "4.17.17",
|
||||||
"resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.17.tgz",
|
"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",
|
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
|
||||||
"integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ=="
|
"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": {
|
"node_modules/csstype": {
|
||||||
"version": "3.1.2",
|
"version": "3.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz",
|
||||||
|
|
|
@ -24,10 +24,12 @@
|
||||||
"description": "",
|
"description": "",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/cookie-parser": "^1.4.3",
|
"@types/cookie-parser": "^1.4.3",
|
||||||
|
"@types/crypto-js": "^4.1.1",
|
||||||
"@types/react": "^18.2.14",
|
"@types/react": "^18.2.14",
|
||||||
"body-parser": "^1.20.2",
|
"body-parser": "^1.20.2",
|
||||||
"cookie": "^0.5.0",
|
"cookie": "^0.5.0",
|
||||||
"cookie-parser": "^1.4.6",
|
"cookie-parser": "^1.4.6",
|
||||||
|
"crypto-js": "^4.1.1",
|
||||||
"dotenv": "^16.3.0",
|
"dotenv": "^16.3.0",
|
||||||
"express": "^4.18.2",
|
"express": "^4.18.2",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
|
|
|
@ -1,6 +1,21 @@
|
||||||
import { MongoClient } from "mongodb";
|
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, {});
|
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 { Class, TrueSign } from "@/types/assist/extended_zodiac";
|
||||||
import { SubmitTroll } from "@/types/client/troll";
|
import { SubmitTroll } from "@/types/client/troll";
|
||||||
import { ClientTroll, ServerTroll } from "@/types/troll";
|
import { ClientTroll, ServerTroll } from "@/types/troll";
|
||||||
import { getManyFlairs } from "../flair";
|
import { cutObject, sanitize } from "../utility/merge";
|
||||||
import { cutArray, cutObject, sanitize } from "../utility/merge";
|
|
||||||
import { ServerFlairToClientFlair } from "./flair";
|
|
||||||
|
|
||||||
export async function ServerTrollToClientTroll(
|
export async function ServerTrollToClientTroll(
|
||||||
serverTroll: ServerTroll
|
serverTroll: ServerTroll
|
||||||
): Promise<ClientTroll> {
|
): Promise<Partial<ClientTroll>> {
|
||||||
const sanitizedTroll = sanitize(serverTroll);
|
const sanitizedTroll = sanitize(serverTroll);
|
||||||
const flairs = await getManyFlairs(
|
|
||||||
{ _id: { $in: serverTroll.flairs } },
|
let clientTroll: Partial<ClientTroll> = {
|
||||||
ServerFlairToClientFlair
|
|
||||||
);
|
|
||||||
let clientTroll: ClientTroll = {
|
|
||||||
...sanitizedTroll,
|
...sanitizedTroll,
|
||||||
trueSign: TrueSign[serverTroll.trueSign],
|
trueSign: TrueSign[serverTroll.trueSign],
|
||||||
falseSign:
|
falseSign:
|
||||||
|
@ -21,8 +16,8 @@ export async function ServerTrollToClientTroll(
|
||||||
? TrueSign[serverTroll.falseSign]
|
? TrueSign[serverTroll.falseSign]
|
||||||
: null,
|
: null,
|
||||||
class: serverTroll.class ? Class[serverTroll.class] : null,
|
class: serverTroll.class ? Class[serverTroll.class] : null,
|
||||||
owners: [],
|
owner: undefined,
|
||||||
flairs: cutArray(flairs)
|
flairs: undefined
|
||||||
};
|
};
|
||||||
|
|
||||||
return clientTroll;
|
return clientTroll;
|
||||||
|
@ -36,7 +31,7 @@ export function SubmitTrollToServerTroll(
|
||||||
quirks: submitTroll.quirks
|
quirks: submitTroll.quirks
|
||||||
? Object.fromEntries(submitTroll.quirks)
|
? Object.fromEntries(submitTroll.quirks)
|
||||||
: undefined,
|
: undefined,
|
||||||
owners: undefined,
|
owner: undefined,
|
||||||
flairs: undefined,
|
flairs: undefined,
|
||||||
updatedDate: new Date()
|
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 { 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";
|
import { ObjectId } from "mongodb";
|
||||||
|
|
||||||
export function getLevel(user: Partial<ServerUser> & { flairs: ObjectId[] }) {
|
export function getLevel(clan: Partial<ServerClan> & { flairs: ObjectId[] }) {
|
||||||
let highestLevel = "USER";
|
let highestLevel = "CLAN";
|
||||||
for (let level of Permissions) {
|
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;
|
highestLevel = level.name;
|
||||||
}
|
}
|
||||||
return highestLevel;
|
return highestLevel;
|
||||||
|
@ -16,13 +18,17 @@ export function compareLevels(level: string, compareLevel: string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function compareCredentials(
|
export function compareCredentials(
|
||||||
user: ServerUser,
|
clan: ServerClan,
|
||||||
cookies: Partial<{
|
cookies: Partial<{
|
||||||
[key: string]: string;
|
[key: string]: string;
|
||||||
}>
|
}>
|
||||||
) {
|
) {
|
||||||
|
const decryptCode = AES.decrypt(
|
||||||
|
clan.code,
|
||||||
|
process.env.ENCRYPT_CODE ?? "HACKTHIS"
|
||||||
|
).toString(CryptoJS.enc.Utf8);
|
||||||
return (
|
return (
|
||||||
user.code === cookies.TROLLCALL_CODE &&
|
decryptCode === cookies.TROLLCALL_CODE &&
|
||||||
user.name === cookies.TROLLCALL_NAME
|
clan.name === cookies.TROLLCALL_NAME
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,8 +58,8 @@ export async function getManyPagedTrolls<T>(
|
||||||
const find = readMany("trolls", query, TrollSort)
|
const find = readMany("trolls", query, TrollSort)
|
||||||
.limit(count)
|
.limit(count)
|
||||||
.skip(page * count);
|
.skip(page * count);
|
||||||
const user = (await cursorToArray(find, func)) as (Awaited<T> | null)[];
|
const clan = (await cursorToArray(find, func)) as (Awaited<T> | null)[];
|
||||||
return user;
|
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 { getManyPagedClans } from "@/lib/trollcall/clan";
|
||||||
import { getManyPagedUsers } from "@/lib/trollcall/user";
|
import { ServerClanToClientClan } from "@/lib/trollcall/convert/clan";
|
||||||
import { NextApiRequest, NextApiResponse } from "next";
|
import { NextApiRequest, NextApiResponse } from "next";
|
||||||
|
|
||||||
export default async function handler(
|
export default async function handler(
|
||||||
|
@ -9,13 +9,13 @@ export default async function handler(
|
||||||
const { method, query } = req;
|
const { method, query } = req;
|
||||||
const page = query.page ? query.page[0] : 0;
|
const page = query.page ? query.page[0] : 0;
|
||||||
if (method === "GET") {
|
if (method === "GET") {
|
||||||
const users = await getManyPagedUsers(
|
const clans = await getManyPagedClans(
|
||||||
{},
|
{},
|
||||||
ServerUserToClientUser,
|
ServerClanToClientClan,
|
||||||
5,
|
5,
|
||||||
page
|
page
|
||||||
);
|
);
|
||||||
if (users == null) return res.status(404).end();
|
if (clans == null) return res.status(404).end();
|
||||||
res.json(users);
|
res.json(clans);
|
||||||
} else return res.status(405).end();
|
} 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 { ServerTrollToClientTroll } from "@/lib/trollcall/convert/troll";
|
||||||
import { getManyPagedTrolls } from "@/lib/trollcall/troll";
|
import { getManyPagedTrolls } from "@/lib/trollcall/troll";
|
||||||
import { getSingleUser } from "@/lib/trollcall/user";
|
|
||||||
import { NextApiRequest, NextApiResponse } from "next";
|
import { NextApiRequest, NextApiResponse } from "next";
|
||||||
|
|
||||||
export default async function handler(
|
export default async function handler(
|
||||||
|
@ -10,13 +10,13 @@ export default async function handler(
|
||||||
const { method, query } = req;
|
const { method, query } = req;
|
||||||
const page = query.page ? query.page[0] : 0;
|
const page = query.page ? query.page[0] : 0;
|
||||||
if (method === "GET") {
|
if (method === "GET") {
|
||||||
const user = await getSingleUser({
|
const clan = await getSingleClan({
|
||||||
name: query.user
|
name: query.clan
|
||||||
});
|
});
|
||||||
if (user == null) return res.status(404).end();
|
if (clan == null) return res.status(404).end();
|
||||||
const trolls = await getManyPagedTrolls(
|
const trolls = await getManyPagedTrolls(
|
||||||
{
|
{
|
||||||
"owners.0": user._id
|
"owner": clan._id
|
||||||
},
|
},
|
||||||
ServerTrollToClientTroll,
|
ServerTrollToClientTroll,
|
||||||
5,
|
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 {
|
import {
|
||||||
MergeServerTrolls,
|
MergeServerTrolls,
|
||||||
ServerTrollToClientTroll,
|
ServerTrollToClientTroll,
|
||||||
SubmitTrollToServerTroll
|
SubmitTrollToServerTroll
|
||||||
} from "@/lib/trollcall/convert/troll";
|
} from "@/lib/trollcall/convert/troll";
|
||||||
|
import { getManyFlairs } from "@/lib/trollcall/flair";
|
||||||
import {
|
import {
|
||||||
compareCredentials,
|
compareCredentials,
|
||||||
compareLevels,
|
compareLevels,
|
||||||
getLevel
|
getLevel
|
||||||
} from "@/lib/trollcall/perms";
|
} from "@/lib/trollcall/perms";
|
||||||
import { changeTroll, getSingleTroll } from "@/lib/trollcall/troll";
|
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 { PartialTrollSchema, SubmitTroll } from "@/types/client/troll";
|
||||||
import { NextApiRequest, NextApiResponse } from "next";
|
import { NextApiRequest, NextApiResponse } from "next";
|
||||||
|
|
||||||
|
@ -19,16 +24,24 @@ export default async function handler(
|
||||||
) {
|
) {
|
||||||
const { query, cookies, method, body } = req;
|
const { query, cookies, method, body } = req;
|
||||||
if (method === "GET") {
|
if (method === "GET") {
|
||||||
const user = await getSingleUser({
|
const clan = await getSingleClan({
|
||||||
name: query.user
|
name: query.clan
|
||||||
});
|
});
|
||||||
if (user == null) return res.status(404).end();
|
if (clan == null) return res.status(404).end();
|
||||||
const troll = await getSingleTroll({
|
const troll = await getSingleTroll({
|
||||||
"name.0": query.troll,
|
"name.0": query.troll,
|
||||||
"owners.0": user._id
|
"owner": clan._id
|
||||||
});
|
});
|
||||||
if (troll == null) return res.status(404).end();
|
if (troll == null) return res.status(404).end();
|
||||||
const serverTroll = await ServerTrollToClientTroll(troll);
|
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);
|
res.json(serverTroll);
|
||||||
} else if (method === "PUT") {
|
} else if (method === "PUT") {
|
||||||
let validatedTroll: Partial<SubmitTroll>;
|
let validatedTroll: Partial<SubmitTroll>;
|
||||||
|
@ -39,23 +52,23 @@ export default async function handler(
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
return res.status(400).send(err);
|
return res.status(400).send(err);
|
||||||
}
|
}
|
||||||
const checkUser = await getSingleUser({
|
const checkClan = await getSingleClan({
|
||||||
name: query.user
|
name: query.clan
|
||||||
});
|
});
|
||||||
if (checkUser == null) return res.status(404).end();
|
if (checkClan == null) return res.status(404).end();
|
||||||
if (!compareCredentials(checkUser, cookies)) {
|
if (!compareCredentials(checkClan, cookies)) {
|
||||||
const thisUser = await getSingleUser({
|
const thisClan = await getSingleClan({
|
||||||
name: cookies.TROLLCALL_NAME
|
name: cookies.TROLLCALL_NAME
|
||||||
});
|
});
|
||||||
if (thisUser == null || !compareCredentials(thisUser, cookies))
|
if (thisClan == null || !compareCredentials(thisClan, cookies))
|
||||||
return res.status(403).end();
|
return res.status(403).end();
|
||||||
console.log(getLevel(thisUser));
|
console.log(getLevel(thisClan));
|
||||||
if (!compareLevels(getLevel(thisUser), "MODERATOR"))
|
if (!compareLevels(getLevel(thisClan), "MODERATOR"))
|
||||||
return res.status(403).end();
|
return res.status(403).end();
|
||||||
}
|
}
|
||||||
const editingTroll = await getSingleTroll({
|
const editingTroll = await getSingleTroll({
|
||||||
"name.0": query.troll,
|
"name.0": query.troll,
|
||||||
"owners.0": checkUser._id
|
"owner": checkClan._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);
|
|
@ -1,10 +1,10 @@
|
||||||
|
import { getSingleClan } from "@/lib/trollcall/clan";
|
||||||
import {
|
import {
|
||||||
compareCredentials,
|
compareCredentials,
|
||||||
compareLevels,
|
compareLevels,
|
||||||
getLevel
|
getLevel
|
||||||
} from "@/lib/trollcall/perms";
|
} from "@/lib/trollcall/perms";
|
||||||
import { getSingleTroll } from "@/lib/trollcall/troll";
|
import { getSingleTroll } from "@/lib/trollcall/troll";
|
||||||
import { getSingleUser } from "@/lib/trollcall/user";
|
|
||||||
import { NextApiRequest, NextApiResponse } from "next";
|
import { NextApiRequest, NextApiResponse } from "next";
|
||||||
|
|
||||||
export default async function handler(
|
export default async function handler(
|
||||||
|
@ -13,22 +13,22 @@ export default async function handler(
|
||||||
) {
|
) {
|
||||||
const { query, cookies, method, body } = req;
|
const { query, cookies, method, body } = req;
|
||||||
if (method === "GET") {
|
if (method === "GET") {
|
||||||
const user = await getSingleUser({
|
const clan = await getSingleClan({
|
||||||
name: query.user
|
name: query.clan
|
||||||
});
|
});
|
||||||
if (user == null) return res.status(404).end();
|
if (clan == null) return res.status(404).end();
|
||||||
if (!compareCredentials(user, cookies)) {
|
if (!compareCredentials(clan, cookies)) {
|
||||||
const thisUser = await getSingleUser({
|
const thisClan = await getSingleClan({
|
||||||
name: cookies.TROLLCALL_NAME
|
name: cookies.TROLLCALL_NAME
|
||||||
});
|
});
|
||||||
if (thisUser == null || !compareCredentials(thisUser, cookies))
|
if (thisClan == null || !compareCredentials(thisClan, cookies))
|
||||||
return res.status(403).end();
|
return res.status(403).end();
|
||||||
if (!compareLevels(getLevel(thisUser), "MODERATOR"))
|
if (!compareLevels(getLevel(thisClan), "MODERATOR"))
|
||||||
return res.status(403).end();
|
return res.status(403).end();
|
||||||
}
|
}
|
||||||
const troll = await getSingleTroll({
|
const troll = await getSingleTroll({
|
||||||
"name.0": query.troll,
|
"name.0": query.troll,
|
||||||
"owners.0": user._id
|
"owner": clan._id
|
||||||
});
|
});
|
||||||
if (troll == null) return res.status(404).end();
|
if (troll == null) return res.status(404).end();
|
||||||
res.json(troll);
|
res.json(troll);
|
|
@ -1,7 +1,7 @@
|
||||||
|
import { getSingleClan } from "@/lib/trollcall/clan";
|
||||||
import { SubmitTrollToServerTroll } from "@/lib/trollcall/convert/troll";
|
import { SubmitTrollToServerTroll } from "@/lib/trollcall/convert/troll";
|
||||||
import { compareCredentials } from "@/lib/trollcall/perms";
|
import { compareCredentials } from "@/lib/trollcall/perms";
|
||||||
import { createTroll, getSingleTroll } from "@/lib/trollcall/troll";
|
import { createTroll, getSingleTroll } from "@/lib/trollcall/troll";
|
||||||
import { getSingleUser } from "@/lib/trollcall/user";
|
|
||||||
import { SubmitTrollSchema } from "@/types/client/troll";
|
import { SubmitTrollSchema } from "@/types/client/troll";
|
||||||
import { ServerTroll } from "@/types/troll";
|
import { ServerTroll } from "@/types/troll";
|
||||||
import { NextApiRequest, NextApiResponse } from "next";
|
import { NextApiRequest, NextApiResponse } from "next";
|
||||||
|
@ -20,15 +20,15 @@ export default async function handler(
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
return res.status(400).send(err);
|
return res.status(400).send(err);
|
||||||
}
|
}
|
||||||
const checkUser = await getSingleUser({
|
const checkClan = await getSingleClan({
|
||||||
name: cookies.TROLLCALL_NAME
|
name: cookies.TROLLCALL_NAME
|
||||||
});
|
});
|
||||||
if (checkUser == null) return res.status(404).end();
|
if (checkClan == null) return res.status(404).end();
|
||||||
if (!compareCredentials(checkUser, cookies))
|
if (!compareCredentials(checkClan, cookies))
|
||||||
return res.status(403).end();
|
return res.status(403).end();
|
||||||
const checkExistingTroll = await getSingleTroll({
|
const checkExistingTroll = await getSingleTroll({
|
||||||
"name.0": validatedTroll.name[0],
|
"name.0": validatedTroll.name[0],
|
||||||
"owners": checkUser._id
|
"owner": checkClan._id
|
||||||
});
|
});
|
||||||
if (checkExistingTroll != null) return res.status(409).end();
|
if (checkExistingTroll != null) return res.status(409).end();
|
||||||
// we are sure this object is full, so cast partial
|
// we are sure this object is full, so cast partial
|
||||||
|
@ -36,7 +36,7 @@ export default async function handler(
|
||||||
ServerTroll,
|
ServerTroll,
|
||||||
"_id"
|
"_id"
|
||||||
>;
|
>;
|
||||||
serverTroll.owners[0] = checkUser._id;
|
serverTroll.owner = checkClan._id;
|
||||||
const newTroll = await createTroll(serverTroll);
|
const newTroll = await createTroll(serverTroll);
|
||||||
if (newTroll == null) return res.status(503).end();
|
if (newTroll == null) return res.status(503).end();
|
||||||
res.json(newTroll);
|
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()
|
.string()
|
||||||
.required()
|
.required()
|
||||||
.matches(/^[A-z-]+$/, "Letters only")
|
.matches(/^[A-z-]+$/, "Letters only")
|
||||||
.lowercase(),
|
.lowercase()
|
||||||
|
.max(50),
|
||||||
yup
|
yup
|
||||||
.string()
|
.string()
|
||||||
.required()
|
.required()
|
||||||
.matches(/^[A-z-]+$/, "Letters only")
|
.matches(/^[A-z-]+$/, "Letters only")
|
||||||
.lowercase()
|
.lowercase()
|
||||||
|
.max(50)
|
||||||
])
|
])
|
||||||
.required(),
|
.required(),
|
||||||
pronouns: yup
|
pronouns: yup
|
||||||
|
@ -137,8 +139,6 @@ export const SubmitTrollSchema = yup
|
||||||
shipping: PolicySchema.required(),
|
shipping: PolicySchema.required(),
|
||||||
fanfiction: PolicySchema.required()
|
fanfiction: PolicySchema.required()
|
||||||
})
|
})
|
||||||
// owners: yup.array().of(yup.string().required()).required().min(1),
|
|
||||||
// flairs: yup.array().of(yup.mixed()).required().ensure(),
|
|
||||||
})
|
})
|
||||||
.required();
|
.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 { WithId } from "@/lib/db/crud";
|
||||||
import * as yup from "yup";
|
import * as yup from "yup";
|
||||||
import { ObjectIdSchema } from "./assist/mongo";
|
import { ObjectIdSchema } from "./assist/mongo";
|
||||||
|
import { ClientClanSchema } from "./clan";
|
||||||
import { SubmitDialogSchema } from "./client/dialoglog";
|
import { SubmitDialogSchema } from "./client/dialoglog";
|
||||||
import { ClientTroll, ClientTrollSchema } from "./troll";
|
import { ClientTroll, ClientTrollSchema } from "./troll";
|
||||||
import { ClientUserSchema } from "./user";
|
|
||||||
|
|
||||||
export const ServerDialogSchema = SubmitDialogSchema.shape({
|
export const ServerDialogSchema = SubmitDialogSchema.shape({
|
||||||
owners: yup.array().of(ObjectIdSchema.required()).required().min(1),
|
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 type ServerDialog = WithId<yup.InferType<typeof ServerDialogSchema>>;
|
||||||
|
|
||||||
export const ClientDialogSchema = SubmitDialogSchema.shape({
|
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
|
characters: yup
|
||||||
.array()
|
.array()
|
||||||
.of(
|
.of(
|
||||||
|
|
|
@ -2,13 +2,13 @@ import { WithId } from "@/lib/db/crud";
|
||||||
import * as yup from "yup";
|
import * as yup from "yup";
|
||||||
import { ClassSchema, TrueSignSchema } from "./assist/extended_zodiac";
|
import { ClassSchema, TrueSignSchema } from "./assist/extended_zodiac";
|
||||||
import { ObjectIdSchema } from "./assist/mongo";
|
import { ObjectIdSchema } from "./assist/mongo";
|
||||||
|
import { ClientClanSchema } from "./clan";
|
||||||
import { SubmitTrollSchema } from "./client/troll";
|
import { SubmitTrollSchema } from "./client/troll";
|
||||||
import { ClientFlairSchema } from "./flair";
|
import { ClientFlairSchema } from "./flair";
|
||||||
import { ServerQuirkHolder, ServerQuirkHolderSchema } from "./quirks";
|
import { ServerQuirkHolder, ServerQuirkHolderSchema } from "./quirks";
|
||||||
import { ClientUserSchema } from "./user";
|
|
||||||
|
|
||||||
export const ServerTrollSchema = SubmitTrollSchema.shape({
|
export const ServerTrollSchema = SubmitTrollSchema.shape({
|
||||||
owners: yup.array().of(ObjectIdSchema.required()).required().min(1),
|
owner: ObjectIdSchema.required(),
|
||||||
flairs: yup.array().of(ObjectIdSchema.required()).required(),
|
flairs: yup.array().of(ObjectIdSchema.required()).required(),
|
||||||
quirks: ServerQuirkHolderSchema.required(),
|
quirks: ServerQuirkHolderSchema.required(),
|
||||||
updatedDate: yup.date().notRequired()
|
updatedDate: yup.date().notRequired()
|
||||||
|
@ -17,7 +17,7 @@ export const ServerTrollSchema = SubmitTrollSchema.shape({
|
||||||
export type ServerTroll = WithId<yup.InferType<typeof ServerTrollSchema>>;
|
export type ServerTroll = WithId<yup.InferType<typeof ServerTrollSchema>>;
|
||||||
|
|
||||||
export const ClientTrollSchema = SubmitTrollSchema.shape({
|
export const ClientTrollSchema = SubmitTrollSchema.shape({
|
||||||
owners: yup.array().of(ClientUserSchema.required()).required().min(1),
|
owner: ClientClanSchema.required(),
|
||||||
flairs: yup.array().of(ClientFlairSchema.required()).required(),
|
flairs: yup.array().of(ClientFlairSchema.required()).required(),
|
||||||
quirks: ServerQuirkHolderSchema.required(),
|
quirks: ServerQuirkHolderSchema.required(),
|
||||||
trueSign: TrueSignSchema.notRequired(),
|
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