Merge remote-tracking branch 'spacebar/master' into webrtc-test
merge
This commit is contained in:
commit
d8e1045d59
@ -5171,7 +5171,10 @@
|
|||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
},
|
},
|
||||||
"parent_id": {
|
"parent_id": {
|
||||||
"type": "string"
|
"type": [
|
||||||
|
"null",
|
||||||
|
"string"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"additionalProperties": false,
|
"additionalProperties": false,
|
||||||
|
@ -60170,7 +60170,10 @@
|
|||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
},
|
},
|
||||||
"parent_id": {
|
"parent_id": {
|
||||||
"type": "string"
|
"type": [
|
||||||
|
"null",
|
||||||
|
"string"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"additionalProperties": false,
|
"additionalProperties": false,
|
||||||
|
@ -108,70 +108,93 @@ router.patch(
|
|||||||
async (req: Request, res: Response) => {
|
async (req: Request, res: Response) => {
|
||||||
// changes guild channel position
|
// changes guild channel position
|
||||||
const { guild_id } = req.params;
|
const { guild_id } = req.params;
|
||||||
const body = req.body as ChannelReorderSchema;
|
let body = req.body as ChannelReorderSchema;
|
||||||
|
|
||||||
const guild = await Guild.findOneOrFail({
|
const guild = await Guild.findOneOrFail({
|
||||||
where: { id: guild_id },
|
where: { id: guild_id },
|
||||||
select: { channel_ordering: true },
|
select: { channel_ordering: true },
|
||||||
});
|
});
|
||||||
|
|
||||||
|
body = body.sort((a, b) => {
|
||||||
|
const apos =
|
||||||
|
a.position ||
|
||||||
|
(a.parent_id
|
||||||
|
? guild.channel_ordering.findIndex(
|
||||||
|
(_) => _ === a.parent_id,
|
||||||
|
) + 1
|
||||||
|
: 0);
|
||||||
|
const bpos =
|
||||||
|
b.position ||
|
||||||
|
(b.parent_id
|
||||||
|
? guild.channel_ordering.findIndex(
|
||||||
|
(_) => _ === b.parent_id,
|
||||||
|
) + 1
|
||||||
|
: 0);
|
||||||
|
return apos - bpos;
|
||||||
|
});
|
||||||
|
|
||||||
// The channels not listed for this query
|
// The channels not listed for this query
|
||||||
const notMentioned = guild.channel_ordering.filter(
|
const notMentioned = guild.channel_ordering.filter(
|
||||||
(x) => !body.find((c) => c.id == x),
|
(x) => !body.find((c) => c.id == x),
|
||||||
);
|
);
|
||||||
|
|
||||||
const withParents = body.filter((x) => x.parent_id != undefined);
|
const withParents = body.filter((x) => x.parent_id !== undefined);
|
||||||
const withPositions = body.filter((x) => x.position != undefined);
|
const withPositions = body.filter((x) => x.position !== undefined);
|
||||||
|
// You can't do it with Promise.all or the way this is being done is super incorrect
|
||||||
|
for await (const opt of withPositions) {
|
||||||
|
const channel = await Channel.findOneOrFail({
|
||||||
|
where: { id: opt.id },
|
||||||
|
});
|
||||||
|
|
||||||
await Promise.all(
|
notMentioned.splice(opt.position as number, 0, channel.id);
|
||||||
withPositions.map(async (opt) => {
|
channel.position = notMentioned.findIndex((_) => _ === channel.id);
|
||||||
const channel = await Channel.findOneOrFail({
|
|
||||||
where: { id: opt.id },
|
|
||||||
});
|
|
||||||
|
|
||||||
channel.position = opt.position as number;
|
|
||||||
notMentioned.splice(opt.position as number, 0, channel.id);
|
|
||||||
|
|
||||||
await emitEvent({
|
|
||||||
event: "CHANNEL_UPDATE",
|
|
||||||
data: channel,
|
|
||||||
channel_id: channel.id,
|
|
||||||
guild_id,
|
|
||||||
} as ChannelUpdateEvent);
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
|
await emitEvent({
|
||||||
|
event: "CHANNEL_UPDATE",
|
||||||
|
data: channel,
|
||||||
|
channel_id: channel.id,
|
||||||
|
guild_id,
|
||||||
|
} as ChannelUpdateEvent);
|
||||||
|
}
|
||||||
|
// Due to this also being able to change the order, this needs to be done in order
|
||||||
// have to do the parents after the positions
|
// have to do the parents after the positions
|
||||||
await Promise.all(
|
for await (const opt of withParents) {
|
||||||
withParents.map(async (opt) => {
|
const [channel, parent] = await Promise.all([
|
||||||
const [channel, parent] = await Promise.all([
|
Channel.findOneOrFail({
|
||||||
Channel.findOneOrFail({
|
where: { id: opt.id },
|
||||||
where: { id: opt.id },
|
}),
|
||||||
}),
|
opt.parent_id
|
||||||
Channel.findOneOrFail({
|
? Channel.findOneOrFail({
|
||||||
where: { id: opt.parent_id as string },
|
where: { id: opt.parent_id },
|
||||||
select: { permission_overwrites: true },
|
select: {
|
||||||
}),
|
permission_overwrites: true,
|
||||||
]);
|
id: true,
|
||||||
|
},
|
||||||
if (opt.lock_permissions)
|
})
|
||||||
await Channel.update(
|
: null,
|
||||||
{ id: channel.id },
|
]);
|
||||||
{ permission_overwrites: parent.permission_overwrites },
|
|
||||||
);
|
|
||||||
|
|
||||||
|
if (opt.lock_permissions && parent)
|
||||||
|
await Channel.update(
|
||||||
|
{ id: channel.id },
|
||||||
|
{ permission_overwrites: parent.permission_overwrites },
|
||||||
|
);
|
||||||
|
if (parent && opt.position === undefined) {
|
||||||
const parentPos = notMentioned.indexOf(parent.id);
|
const parentPos = notMentioned.indexOf(parent.id);
|
||||||
notMentioned.splice(parentPos + 1, 0, channel.id);
|
notMentioned.splice(parentPos + 1, 0, channel.id);
|
||||||
channel.position = (parentPos + 1) as number;
|
channel.position = (parentPos + 1) as number;
|
||||||
|
}
|
||||||
|
channel.parent = parent || undefined;
|
||||||
|
channel.parent_id = parent?.id || null;
|
||||||
|
await channel.save();
|
||||||
|
|
||||||
await emitEvent({
|
await emitEvent({
|
||||||
event: "CHANNEL_UPDATE",
|
event: "CHANNEL_UPDATE",
|
||||||
data: channel,
|
data: channel,
|
||||||
channel_id: channel.id,
|
channel_id: channel.id,
|
||||||
guild_id,
|
guild_id,
|
||||||
} as ChannelUpdateEvent);
|
} as ChannelUpdateEvent);
|
||||||
}),
|
}
|
||||||
);
|
|
||||||
|
|
||||||
await Guild.update(
|
await Guild.update(
|
||||||
{ id: guild_id },
|
{ id: guild_id },
|
||||||
|
@ -28,7 +28,6 @@ import {
|
|||||||
ajv,
|
ajv,
|
||||||
getPermission,
|
getPermission,
|
||||||
getRights,
|
getRights,
|
||||||
normalizeBody,
|
|
||||||
} from "@spacebar/util";
|
} from "@spacebar/util";
|
||||||
import { AnyValidateFunction } from "ajv/dist/core";
|
import { AnyValidateFunction } from "ajv/dist/core";
|
||||||
import { NextFunction, Request, Response } from "express";
|
import { NextFunction, Request, Response } from "express";
|
||||||
@ -121,7 +120,7 @@ export function route(opts: RouteOptions) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (validate) {
|
if (validate) {
|
||||||
const valid = validate(normalizeBody(req.body));
|
const valid = validate(req.body);
|
||||||
if (!valid) {
|
if (!valid) {
|
||||||
const fields: Record<
|
const fields: Record<
|
||||||
string,
|
string,
|
||||||
|
@ -20,5 +20,5 @@ export type ChannelReorderSchema = {
|
|||||||
id: string;
|
id: string;
|
||||||
position?: number;
|
position?: number;
|
||||||
lock_permissions?: boolean;
|
lock_permissions?: boolean;
|
||||||
parent_id?: string;
|
parent_id?: null | string;
|
||||||
}[];
|
}[];
|
||||||
|
@ -46,44 +46,7 @@ export const ajv = new Ajv({
|
|||||||
addFormats(ajv);
|
addFormats(ajv);
|
||||||
|
|
||||||
export function validateSchema<G extends object>(schema: string, data: G): G {
|
export function validateSchema<G extends object>(schema: string, data: G): G {
|
||||||
const valid = ajv.validate(schema, normalizeBody(data));
|
const valid = ajv.validate(schema, data);
|
||||||
if (!valid) throw ajv.errors;
|
if (!valid) throw ajv.errors;
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Normalizer is introduced to workaround https://github.com/ajv-validator/ajv/issues/1287
|
|
||||||
// this removes null values as ajv doesn't treat them as undefined
|
|
||||||
// normalizeBody allows to handle circular structures without issues
|
|
||||||
// taken from https://github.com/serverless/serverless/blob/master/lib/classes/ConfigSchemaHandler/index.js#L30 (MIT license)
|
|
||||||
export const normalizeBody = (body: object = {}) => {
|
|
||||||
const normalizedObjectsSet = new WeakSet();
|
|
||||||
const normalizeObject = (object: object) => {
|
|
||||||
if (normalizedObjectsSet.has(object)) return;
|
|
||||||
normalizedObjectsSet.add(object);
|
|
||||||
if (Array.isArray(object)) {
|
|
||||||
for (const [, value] of object.entries()) {
|
|
||||||
if (typeof value === "object") normalizeObject(value);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for (const [key, value] of Object.entries(object)) {
|
|
||||||
if (value == null) {
|
|
||||||
if (
|
|
||||||
key === "icon" ||
|
|
||||||
key === "avatar" ||
|
|
||||||
key === "banner" ||
|
|
||||||
key === "splash" ||
|
|
||||||
key === "discovery_splash"
|
|
||||||
)
|
|
||||||
continue;
|
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
||||||
//@ts-ignore
|
|
||||||
delete object[key];
|
|
||||||
} else if (typeof value === "object") {
|
|
||||||
normalizeObject(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
normalizeObject(body);
|
|
||||||
return body;
|
|
||||||
};
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user