1
0
mirror of https://github.com/spacebarchat/server.git synced 2024-11-05 02:12:28 +01:00

Merge branch 'master' of https://github.com/DEVTomatoCake/spacebar-server into feat/local-image-proxy

This commit is contained in:
TomatoCake 2024-08-18 19:00:43 +02:00
commit e24297b67c
18 changed files with 292 additions and 68 deletions

4
.gitattributes vendored Normal file
View File

@ -0,0 +1,4 @@
* text=auto
*.sh -crlf
*.nix -crlf
.husky/pre-commit -crlf

4
.gitignore vendored
View File

@ -1,4 +1,4 @@
.DS_STORE **/.DS_STORE
db/ db/
dist/ dist/
node_modules node_modules
@ -19,4 +19,4 @@ build
*.tmp *.tmp
tmp/ tmp/
dump/ dump/
result result

View File

@ -6262,7 +6262,21 @@
"type": "object", "type": "object",
"properties": { "properties": {
"guild_id": { "guild_id": {
"type": "string" "anyOf": [
{
"type": "array",
"items": [
{
"type": "string"
}
],
"minItems": 1,
"maxItems": 1
},
{
"type": "string"
}
]
}, },
"query": { "query": {
"type": "string" "type": "string"
@ -16619,6 +16633,86 @@
] ]
} }
}, },
"/channels/{channel_id}/messages/{message_id}/reactions/{emoji}/{burst}/{user_id}": {
"delete": {
"security": [
{
"bearer": []
}
],
"responses": {
"204": {
"description": "No description available"
},
"400": {
"description": "",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIErrorResponse"
}
}
}
},
"403": {
"description": "No description available"
},
"404": {
"description": "No description available"
}
},
"parameters": [
{
"name": "channel_id",
"in": "path",
"required": true,
"schema": {
"type": "string"
},
"description": "channel_id"
},
{
"name": "message_id",
"in": "path",
"required": true,
"schema": {
"type": "string"
},
"description": "message_id"
},
{
"name": "emoji",
"in": "path",
"required": true,
"schema": {
"type": "string"
},
"description": "emoji"
},
{
"name": "burst",
"in": "path",
"required": true,
"schema": {
"type": "string"
},
"description": "burst"
},
{
"name": "user_id",
"in": "path",
"required": true,
"schema": {
"type": "string"
},
"description": "user_id"
}
],
"tags": [
"channels"
]
}
},
"/channels/{channel_id}/messages/{message_id}/": { "/channels/{channel_id}/messages/{message_id}/": {
"patch": { "patch": {
"x-right-required": "SEND_MESSAGES", "x-right-required": "SEND_MESSAGES",

View File

@ -211519,7 +211519,21 @@
"type": "object", "type": "object",
"properties": { "properties": {
"guild_id": { "guild_id": {
"type": "string" "anyOf": [
{
"type": "array",
"items": [
{
"type": "string"
}
],
"minItems": 1,
"maxItems": 1
},
{
"type": "string"
}
]
}, },
"query": { "query": {
"type": "string" "type": "string"

View File

@ -1,3 +1,3 @@
{ {
"npmDepsHash": "sha256-q1Q7rpSzfiRvrkoDPER9wjBOzZ5Bn5B+d41MFssM7nU=" "npmDepsHash": "sha256-q1Q7rpSzfiRvrkoDPER9wjBOzZ5Bn5B+d41MFssM7nU="
} }

View File

@ -1,17 +1,17 @@
/* /*
Spacebar: A FOSS re-implementation and extension of the Discord.com backend. Spacebar: A FOSS re-implementation and extension of the Discord.com backend.
Copyright (C) 2023 Spacebar and Spacebar Contributors Copyright (C) 2023 Spacebar and Spacebar Contributors
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published it under the terms of the GNU Affero General Public License as published
by the Free Software Foundation, either version 3 of the License, or by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details. GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
@ -287,6 +287,16 @@ router.post(
}); });
} }
const { maxUsername } = Config.get().limits.user;
if (body.username.length > maxUsername) {
throw FieldErrors({
username: {
code: "BASE_TYPE_BAD_LENGTH",
message: `Must be between 2 and ${maxUsername} in length.`,
},
});
}
const user = await User.register({ ...body, req }); const user = await User.register({ ...body, req });
if (body.invite) { if (body.invite) {

View File

@ -1,30 +1,31 @@
/* /*
Spacebar: A FOSS re-implementation and extension of the Discord.com backend. Spacebar: A FOSS re-implementation and extension of the Discord.com backend.
Copyright (C) 2023 Spacebar and Spacebar Contributors Copyright (C) 2023 Spacebar and Spacebar Contributors
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published it under the terms of the GNU Affero General Public License as published
by the Free Software Foundation, either version 3 of the License, or by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details. GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
import { route } from "@spacebar/api"; import { route } from "@spacebar/api";
import { import {
Channel,
ChannelPinsUpdateEvent, ChannelPinsUpdateEvent,
Config, Config,
DiscordApiErrors, DiscordApiErrors,
emitEvent, emitEvent,
Message, Message,
MessageCreateEvent,
MessageUpdateEvent, MessageUpdateEvent,
User,
} from "@spacebar/util"; } from "@spacebar/util";
import { Request, Response, Router } from "express"; import { Request, Response, Router } from "express";
@ -60,8 +61,34 @@ router.put(
if (pinned_count >= maxPins) if (pinned_count >= maxPins)
throw DiscordApiErrors.MAXIMUM_PINS.withParams(maxPins); throw DiscordApiErrors.MAXIMUM_PINS.withParams(maxPins);
message.pinned = true;
const author = await User.getPublicUser(req.user_id);
const systemPinMessage = Message.create({
timestamp: new Date(),
type: 6,
guild_id: message.guild_id,
channel_id: message.channel_id,
author,
message_reference: {
message_id: message.id,
channel_id: message.channel_id,
guild_id: message.guild_id,
},
reactions: [],
attachments: [],
embeds: [],
sticker_items: [],
edited_timestamp: undefined,
mentions: [],
mention_channels: [],
mention_roles: [],
mention_everyone: false,
});
await Promise.all([ await Promise.all([
Message.update({ id: message_id }, { pinned: true }), message.save(),
emitEvent({ emitEvent({
event: "MESSAGE_UPDATE", event: "MESSAGE_UPDATE",
channel_id, channel_id,
@ -76,6 +103,12 @@ router.put(
last_pin_timestamp: undefined, last_pin_timestamp: undefined,
}, },
} as ChannelPinsUpdateEvent), } as ChannelPinsUpdateEvent),
systemPinMessage.save(),
emitEvent({
event: "MESSAGE_CREATE",
channel_id: message.channel_id,
data: systemPinMessage,
} as MessageCreateEvent),
]); ]);
res.sendStatus(204); res.sendStatus(204);
@ -98,31 +131,27 @@ router.delete(
async (req: Request, res: Response) => { async (req: Request, res: Response) => {
const { channel_id, message_id } = req.params; const { channel_id, message_id } = req.params;
const channel = await Channel.findOneOrFail({
where: { id: channel_id },
});
if (channel.guild_id) req.permission?.hasThrow("MANAGE_MESSAGES");
const message = await Message.findOneOrFail({ const message = await Message.findOneOrFail({
where: { id: message_id }, where: { id: message_id },
}); });
if (message.guild_id) req.permission?.hasThrow("MANAGE_MESSAGES");
message.pinned = false; message.pinned = false;
await Promise.all([ await Promise.all([
message.save(), message.save(),
emitEvent({ emitEvent({
event: "MESSAGE_UPDATE", event: "MESSAGE_UPDATE",
channel_id, channel_id,
data: message, data: message,
} as MessageUpdateEvent), } as MessageUpdateEvent),
emitEvent({ emitEvent({
event: "CHANNEL_PINS_UPDATE", event: "CHANNEL_PINS_UPDATE",
channel_id, channel_id,
data: { data: {
channel_id, channel_id,
guild_id: channel.guild_id, guild_id: message.guild_id,
last_pin_timestamp: undefined, last_pin_timestamp: undefined,
}, },
} as ChannelPinsUpdateEvent), } as ChannelPinsUpdateEvent),

View File

@ -1,25 +1,31 @@
/* /*
Spacebar: A FOSS re-implementation and extension of the Discord.com backend. Spacebar: A FOSS re-implementation and extension of the Discord.com backend.
Copyright (C) 2023 Spacebar and Spacebar Contributors Copyright (C) 2023 Spacebar and Spacebar Contributors
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published it under the terms of the GNU Affero General Public License as published
by the Free Software Foundation, either version 3 of the License, or by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details. GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
import { random, route } from "@spacebar/api"; import { random, route } from "@spacebar/api";
import { Channel, Guild, Invite, Member, Permissions } from "@spacebar/util"; import {
Channel,
DiscordApiErrors,
Guild,
Invite,
Member,
Permissions,
} from "@spacebar/util";
import { Request, Response, Router } from "express"; import { Request, Response, Router } from "express";
import { HTTPError } from "lambert-server";
const router: Router = Router(); const router: Router = Router();
@ -48,7 +54,7 @@ router.get(
const { guild_id } = req.params; const { guild_id } = req.params;
const guild = await Guild.findOneOrFail({ where: { id: guild_id } }); const guild = await Guild.findOneOrFail({ where: { id: guild_id } });
if (!guild.widget_enabled) throw new HTTPError("Widget Disabled", 404); if (!guild.widget_enabled) throw DiscordApiErrors.EMBED_DISABLED;
// Fetch existing widget invite for widget channel // Fetch existing widget invite for widget channel
let invite = await Invite.findOne({ let invite = await Invite.findOne({

View File

@ -1,17 +1,17 @@
/* /*
Spacebar: A FOSS re-implementation and extension of the Discord.com backend. Spacebar: A FOSS re-implementation and extension of the Discord.com backend.
Copyright (C) 2023 Spacebar and Spacebar Contributors Copyright (C) 2023 Spacebar and Spacebar Contributors
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published it under the terms of the GNU Affero General Public License as published
by the Free Software Foundation, either version 3 of the License, or by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details. GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
@ -19,11 +19,12 @@
/* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/no-explicit-any */
import { route } from "@spacebar/api"; import { route } from "@spacebar/api";
import { Guild } from "@spacebar/util"; import { DiscordApiErrors, Guild } from "@spacebar/util";
import { Request, Response, Router } from "express"; import { Request, Response, Router } from "express";
import fs from "fs"; import fs from "fs";
import { HTTPError } from "lambert-server"; import { HTTPError } from "lambert-server";
import path from "path"; import path from "path";
import { storage } from "../../../../cdn/util/Storage";
const router: Router = Router(); const router: Router = Router();
@ -48,10 +49,10 @@ router.get(
const { guild_id } = req.params; const { guild_id } = req.params;
const guild = await Guild.findOneOrFail({ where: { id: guild_id } }); const guild = await Guild.findOneOrFail({ where: { id: guild_id } });
if (!guild.widget_enabled) throw new HTTPError("Unknown Guild", 404); if (!guild.widget_enabled) throw DiscordApiErrors.EMBED_DISABLED;
// Fetch guild information // Fetch guild information
const icon = guild.icon; const icon = "avatars/" + guild_id + "/" + guild.icon;
const name = guild.name; const name = guild.name;
const presence = guild.presence_count + " ONLINE"; const presence = guild.presence_count + " ONLINE";
@ -69,8 +70,7 @@ router.get(
} }
// Setup canvas // Setup canvas
const { createCanvas } = require("canvas"); const { createCanvas, loadImage } = require("canvas");
const { loadImage } = require("canvas");
const sizeOf = require("image-size"); const sizeOf = require("image-size");
// TODO: Widget style templates need Spacebar branding // TODO: Widget style templates need Spacebar branding
@ -211,8 +211,8 @@ async function drawIcon(
scale: number, scale: number,
icon: string, icon: string,
) { ) {
const img = new (require("canvas").Image)(); const { loadImage } = require("canvas");
img.src = icon; const img = await loadImage(await storage.get(icon));
// Do some canvas clipping magic! // Do some canvas clipping magic!
canvas.save(); canvas.save();

View File

@ -155,8 +155,8 @@ router.patch(
if (check_username.length > maxUsername) { if (check_username.length > maxUsername) {
throw FieldErrors({ throw FieldErrors({
username: { username: {
code: "USERNAME_INVALID", code: "BASE_TYPE_BAD_LENGTH",
message: `Username must be less than ${maxUsername} in length`, message: `Must be between 2 and ${maxUsername} in length.`,
}, },
}); });
} }

View File

@ -82,6 +82,7 @@ export async function onIdentify(this: WebSocket, data: Payload) {
const identify: IdentifySchema = data.d; const identify: IdentifySchema = data.d;
this.capabilities = new Capabilities(identify.capabilities || 0); this.capabilities = new Capabilities(identify.capabilities || 0);
this.large_threshold = identify.large_threshold || 250;
const user = await tryGetUserFromToken(identify.token, { const user = await tryGetUserFromToken(identify.token, {
relations: ["relationships", "relationships.to", "settings"], relations: ["relationships", "relationships.to", "settings"],
@ -126,6 +127,7 @@ export async function onIdentify(this: WebSocket, data: Payload) {
os: identify.properties?.os || identify.properties?.$os, os: identify.properties?.os || identify.properties?.$os,
version: 0, version: 0,
}, },
client_status: {},
activities: identify.presence?.activities, // TODO: validation activities: identify.presence?.activities, // TODO: validation
}); });

View File

@ -17,6 +17,7 @@
*/ */
import { import {
getDatabase,
getPermission, getPermission,
GuildMembersChunkEvent, GuildMembersChunkEvent,
Member, Member,
@ -29,19 +30,24 @@ import { check } from "./instanceOf";
import { FindManyOptions, In, Like } from "typeorm"; import { FindManyOptions, In, Like } from "typeorm";
export async function onRequestGuildMembers(this: WebSocket, { d }: Payload) { export async function onRequestGuildMembers(this: WebSocket, { d }: Payload) {
// TODO: check data // Schema validation can only accept either string or array, so transforming it here to support both
if (!d.guild_id) throw new Error('"guild_id" is required');
d.guild_id = Array.isArray(d.guild_id) ? d.guild_id[0] : d.guild_id;
if (d.user_ids && !Array.isArray(d.user_ids)) d.user_ids = [d.user_ids];
check.call(this, RequestGuildMembersSchema, d); check.call(this, RequestGuildMembersSchema, d);
const { guild_id, query, presences, nonce } = const { query, presences, nonce } = d as RequestGuildMembersSchema;
d as RequestGuildMembersSchema; let { limit, user_ids, guild_id } = d as RequestGuildMembersSchema;
let { limit, user_ids } = d as RequestGuildMembersSchema;
guild_id = guild_id as string;
user_ids = user_ids as string[] | undefined;
if ("query" in d && (!limit || Number.isNaN(limit))) if ("query" in d && (!limit || Number.isNaN(limit)))
throw new Error('"query" requires "limit" to be set'); throw new Error('"query" requires "limit" to be set');
if ("query" in d && user_ids) if ("query" in d && user_ids)
throw new Error('"query" and "user_ids" are mutually exclusive'); throw new Error('"query" and "user_ids" are mutually exclusive');
if (user_ids && !Array.isArray(user_ids)) user_ids = [user_ids];
user_ids = user_ids as string[] | undefined;
// TODO: Configurable limit? // TODO: Configurable limit?
if ((query || (user_ids && user_ids.length > 0)) && (!limit || limit > 100)) if ((query || (user_ids && user_ids.length > 0)) && (!limit || limit > 100))
@ -50,24 +56,74 @@ export async function onRequestGuildMembers(this: WebSocket, { d }: Payload) {
const permissions = await getPermission(this.user_id, guild_id); const permissions = await getPermission(this.user_id, guild_id);
permissions.hasThrow("VIEW_CHANNEL"); permissions.hasThrow("VIEW_CHANNEL");
const whereQuery: FindManyOptions["where"] = {}; const memberCount = await Member.count({
if (query) { where: {
whereQuery.user = { guild_id,
username: Like(query + "%"), },
}; });
} else if (user_ids && user_ids.length > 0) {
whereQuery.id = In(user_ids);
}
const memberFind: FindManyOptions = { const memberFind: FindManyOptions = {
where: { where: {
...whereQuery,
guild_id, guild_id,
}, },
relations: ["user", "roles"], relations: ["user", "roles"],
}; };
if (limit) memberFind.take = Math.abs(Number(limit || 100)); if (limit) memberFind.take = Math.abs(Number(limit || 100));
const members = await Member.find(memberFind);
let members: Member[] = [];
if (memberCount > 75000) {
// since we dont have voice channels yet, just return the connecting users member object
members = await Member.find({
...memberFind,
where: {
...memberFind.where,
user: {
id: this.user_id,
},
},
});
} else if (memberCount > this.large_threshold) {
// find all members who are online, have a role, have a nickname, or are in a voice channel, as well as respecting the query and user_ids
const db = getDatabase();
if (!db) throw new Error("Database not initialized");
const repo = db.getRepository(Member);
const q = repo
.createQueryBuilder("member")
.where("member.guild_id = :guild_id", { guild_id })
.leftJoinAndSelect("member.roles", "role")
.leftJoinAndSelect("member.user", "user")
.leftJoinAndSelect("user.sessions", "session")
.andWhere(
"',' || member.roles || ',' NOT LIKE :everyoneRoleIdList",
{ everyoneRoleIdList: "%," + guild_id + ",%" },
)
.andWhere("session.status != 'offline'")
.addOrderBy("user.username", "ASC")
.limit(memberFind.take);
if (query && query != "") {
q.andWhere(`user.username ILIKE :query`, {
query: `${query}%`,
});
} else if (user_ids) {
q.andWhere(`user.id IN (:...user_ids)`, { user_ids });
}
members = await q.getMany();
} else {
if (query) {
// @ts-expect-error memberFind.where is very much defined
memberFind.where.user = {
username: Like(query + "%"),
};
} else if (user_ids && user_ids.length > 0) {
// @ts-expect-error memberFind.where is still very much defined
memberFind.where.id = In(user_ids);
}
members = await Member.find(memberFind);
}
const baseData = { const baseData = {
guild_id, guild_id,
@ -111,7 +167,17 @@ export async function onRequestGuildMembers(this: WebSocket, { d }: Payload) {
}); });
} }
if (notFound.length > 0) chunks[0].not_found = notFound; if (notFound.length > 0) {
if (chunks.length == 0)
chunks.push({
...baseData,
members: [],
presences: presences ? [] : undefined,
chunk_index: 0,
chunk_count: 1,
});
chunks[0].not_found = notFound;
}
chunks.forEach((chunk) => { chunks.forEach((chunk) => {
Send(this, { Send(this, {

View File

@ -1,17 +1,17 @@
/* /*
Spacebar: A FOSS re-implementation and extension of the Discord.com backend. Spacebar: A FOSS re-implementation and extension of the Discord.com backend.
Copyright (C) 2023 Spacebar and Spacebar Contributors Copyright (C) 2023 Spacebar and Spacebar Contributors
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published it under the terms of the GNU Affero General Public License as published
by the Free Software Foundation, either version 3 of the License, or by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details. GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
@ -43,4 +43,5 @@ export interface WebSocket extends WS {
listen_options: ListenEventOpts; listen_options: ListenEventOpts;
capabilities?: Capabilities; capabilities?: Capabilities;
// client?: Client; // client?: Client;
large_threshold: number;
} }

View File

@ -1,17 +1,17 @@
/* /*
Spacebar: A FOSS re-implementation and extension of the Discord.com backend. Spacebar: A FOSS re-implementation and extension of the Discord.com backend.
Copyright (C) 2023 Spacebar and Spacebar Contributors Copyright (C) 2023 Spacebar and Spacebar Contributors
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published it under the terms of the GNU Affero General Public License as published
by the Free Software Foundation, either version 3 of the License, or by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details. GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
@ -19,7 +19,6 @@
export interface RegisterSchema { export interface RegisterSchema {
/** /**
* @minLength 2 * @minLength 2
* @maxLength 32
*/ */
username: string; username: string;
/** /**

View File

@ -17,7 +17,7 @@
*/ */
export interface RequestGuildMembersSchema { export interface RequestGuildMembersSchema {
guild_id: string; guild_id: string | [string];
query?: string; query?: string;
limit?: number; limit?: number;
presences?: boolean; presences?: boolean;
@ -26,7 +26,7 @@ export interface RequestGuildMembersSchema {
} }
export const RequestGuildMembersSchema = { export const RequestGuildMembersSchema = {
guild_id: String, guild_id: "" as string | string[],
$query: String, $query: String,
$limit: Number, $limit: Number,
$presences: Boolean, $presences: Boolean,

View File

@ -18,8 +18,7 @@
export interface UserModifySchema { export interface UserModifySchema {
/** /**
* @minLength 1 * @minLength 2
* @maxLength 100
*/ */
username?: string; username?: string;
avatar?: string | null; avatar?: string | null;

View File

@ -812,7 +812,7 @@ export const DiscordApiErrors = {
"Cannot execute action on a DM channel", "Cannot execute action on a DM channel",
50003, 50003,
), ),
EMBED_DISABLED: new ApiError("Guild widget disabled", 50004), EMBED_DISABLED: new ApiError("Widget Disabled", 50004),
CANNOT_EDIT_MESSAGE_BY_OTHER: new ApiError( CANNOT_EDIT_MESSAGE_BY_OTHER: new ApiError(
"Cannot edit a message authored by another user", "Cannot edit a message authored by another user",
50005, 50005,

BIN
src/webrtc/.DS_Store vendored

Binary file not shown.