Merge remote-tracking branch 'spacebar/master' into webrtc-test

merge
This commit is contained in:
pixtaded 2025-06-03 14:50:21 +03:00
commit d8e1045d59
6 changed files with 79 additions and 88 deletions

View File

@ -5171,7 +5171,10 @@
"type": "boolean"
},
"parent_id": {
"type": "string"
"type": [
"null",
"string"
]
}
},
"additionalProperties": false,

View File

@ -60170,7 +60170,10 @@
"type": "boolean"
},
"parent_id": {
"type": "string"
"type": [
"null",
"string"
]
}
},
"additionalProperties": false,

View File

@ -108,70 +108,93 @@ router.patch(
async (req: Request, res: Response) => {
// changes guild channel position
const { guild_id } = req.params;
const body = req.body as ChannelReorderSchema;
let body = req.body as ChannelReorderSchema;
const guild = await Guild.findOneOrFail({
where: { id: guild_id },
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
const notMentioned = guild.channel_ordering.filter(
(x) => !body.find((c) => c.id == x),
);
const withParents = body.filter((x) => x.parent_id != undefined);
const withPositions = body.filter((x) => x.position != undefined);
const withParents = body.filter((x) => x.parent_id !== 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(
withPositions.map(async (opt) => {
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);
}),
);
notMentioned.splice(opt.position as number, 0, channel.id);
channel.position = notMentioned.findIndex((_) => _ === channel.id);
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
await Promise.all(
withParents.map(async (opt) => {
const [channel, parent] = await Promise.all([
Channel.findOneOrFail({
where: { id: opt.id },
}),
Channel.findOneOrFail({
where: { id: opt.parent_id as string },
select: { permission_overwrites: true },
}),
]);
if (opt.lock_permissions)
await Channel.update(
{ id: channel.id },
{ permission_overwrites: parent.permission_overwrites },
);
for await (const opt of withParents) {
const [channel, parent] = await Promise.all([
Channel.findOneOrFail({
where: { id: opt.id },
}),
opt.parent_id
? Channel.findOneOrFail({
where: { id: opt.parent_id },
select: {
permission_overwrites: true,
id: true,
},
})
: null,
]);
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);
notMentioned.splice(parentPos + 1, 0, channel.id);
channel.position = (parentPos + 1) as number;
}
channel.parent = parent || undefined;
channel.parent_id = parent?.id || null;
await channel.save();
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);
}
await Guild.update(
{ id: guild_id },

View File

@ -28,7 +28,6 @@ import {
ajv,
getPermission,
getRights,
normalizeBody,
} from "@spacebar/util";
import { AnyValidateFunction } from "ajv/dist/core";
import { NextFunction, Request, Response } from "express";
@ -121,7 +120,7 @@ export function route(opts: RouteOptions) {
}
if (validate) {
const valid = validate(normalizeBody(req.body));
const valid = validate(req.body);
if (!valid) {
const fields: Record<
string,

View File

@ -20,5 +20,5 @@ export type ChannelReorderSchema = {
id: string;
position?: number;
lock_permissions?: boolean;
parent_id?: string;
parent_id?: null | string;
}[];

View File

@ -46,44 +46,7 @@ export const ajv = new Ajv({
addFormats(ajv);
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;
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;
};