From 12cca1b5469f76d7b54be1cf09fe3e242e8c7271 Mon Sep 17 00:00:00 2001 From: TomatoCake <60300461+DEVTomatoCake@users.noreply.github.com> Date: Sun, 30 Jun 2024 21:53:21 +0200 Subject: [PATCH 01/30] Add migration for new user setting props --- .../mariadb/1719776735000-newUserSettings.ts | 23 +++++++++++++++++++ .../mysql/1719776735000-newUserSettings.ts | 23 +++++++++++++++++++ .../postgres/1719776735000-newUserSettings.ts | 23 +++++++++++++++++++ 3 files changed, 69 insertions(+) create mode 100644 src/util/migration/mariadb/1719776735000-newUserSettings.ts create mode 100644 src/util/migration/mysql/1719776735000-newUserSettings.ts create mode 100644 src/util/migration/postgres/1719776735000-newUserSettings.ts diff --git a/src/util/migration/mariadb/1719776735000-newUserSettings.ts b/src/util/migration/mariadb/1719776735000-newUserSettings.ts new file mode 100644 index 00000000..f7c37ca9 --- /dev/null +++ b/src/util/migration/mariadb/1719776735000-newUserSettings.ts @@ -0,0 +1,23 @@ +import { MigrationInterface, QueryRunner } from "typeorm"; + +export class NewUserSettings1719776735000 implements MigrationInterface { + name = "NewUserSettings1719776735000"; + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + "ALTER TABLE `user_settings` ADD friend_discovery_flags integer NULL DEFAULT 0;", + ); + await queryRunner.query( + "ALTER TABLE `user_settings` ADD view_nsfw_guilds tinyint NULL DEFAULT 1;", + ); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query( + "ALTER TABLE `user_settings` DROP COLUMN friend_discovery_flags;", + ); + await queryRunner.query( + "ALTER TABLE `user_settings` DROP COLUMN view_nsfw_guilds;", + ); + } +} diff --git a/src/util/migration/mysql/1719776735000-newUserSettings.ts b/src/util/migration/mysql/1719776735000-newUserSettings.ts new file mode 100644 index 00000000..f7c37ca9 --- /dev/null +++ b/src/util/migration/mysql/1719776735000-newUserSettings.ts @@ -0,0 +1,23 @@ +import { MigrationInterface, QueryRunner } from "typeorm"; + +export class NewUserSettings1719776735000 implements MigrationInterface { + name = "NewUserSettings1719776735000"; + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + "ALTER TABLE `user_settings` ADD friend_discovery_flags integer NULL DEFAULT 0;", + ); + await queryRunner.query( + "ALTER TABLE `user_settings` ADD view_nsfw_guilds tinyint NULL DEFAULT 1;", + ); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query( + "ALTER TABLE `user_settings` DROP COLUMN friend_discovery_flags;", + ); + await queryRunner.query( + "ALTER TABLE `user_settings` DROP COLUMN view_nsfw_guilds;", + ); + } +} diff --git a/src/util/migration/postgres/1719776735000-newUserSettings.ts b/src/util/migration/postgres/1719776735000-newUserSettings.ts new file mode 100644 index 00000000..4d0224f0 --- /dev/null +++ b/src/util/migration/postgres/1719776735000-newUserSettings.ts @@ -0,0 +1,23 @@ +import { MigrationInterface, QueryRunner } from "typeorm"; + +export class NewUserSettings1719776735000 implements MigrationInterface { + name = "NewUserSettings1719776735000"; + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + "ALTER TABLE user_settings ADD COLUMN friend_discovery_flags integer DEFAULT 0;", + ); + await queryRunner.query( + "ALTER TABLE user_settings ADD COLUMN view_nsfw_guilds tinyint DEFAULT 1;", + ); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query( + "ALTER TABLE user_settings DROP COLUMN friend_discovery_flags;", + ); + await queryRunner.query( + "ALTER TABLE user_settings DROP COLUMN view_nsfw_guilds;", + ); + } +} From 9d27a5138fa0fa7ef44c9a357e243e773bf7d3e2 Mon Sep 17 00:00:00 2001 From: TomatoCake <60300461+DEVTomatoCake@users.noreply.github.com> Date: Sun, 30 Jun 2024 21:54:03 +0200 Subject: [PATCH 02/30] Prettier -.- --- src/util/entities/UserSettings.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/util/entities/UserSettings.ts b/src/util/entities/UserSettings.ts index 0d4b6a7b..d3efe79b 100644 --- a/src/util/entities/UserSettings.ts +++ b/src/util/entities/UserSettings.ts @@ -122,7 +122,6 @@ export class UserSettings extends BaseClassWithoutId { @Column({ nullable: true }) view_nsfw_guilds: boolean = true; - } interface CustomStatus { From b7bf2a11ea7b1183c45d3def833310fa39fe74d6 Mon Sep 17 00:00:00 2001 From: TomatoCake <60300461+DEVTomatoCake@users.noreply.github.com> Date: Mon, 1 Jul 2024 18:25:29 +0200 Subject: [PATCH 03/30] Fix Postgres column type (hopefully) --- src/util/migration/postgres/1719776735000-newUserSettings.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util/migration/postgres/1719776735000-newUserSettings.ts b/src/util/migration/postgres/1719776735000-newUserSettings.ts index 4d0224f0..dbee0b0d 100644 --- a/src/util/migration/postgres/1719776735000-newUserSettings.ts +++ b/src/util/migration/postgres/1719776735000-newUserSettings.ts @@ -8,7 +8,7 @@ export class NewUserSettings1719776735000 implements MigrationInterface { "ALTER TABLE user_settings ADD COLUMN friend_discovery_flags integer DEFAULT 0;", ); await queryRunner.query( - "ALTER TABLE user_settings ADD COLUMN view_nsfw_guilds tinyint DEFAULT 1;", + "ALTER TABLE user_settings ADD COLUMN view_nsfw_guilds boolean DEFAULT true;", ); } From ef13c8c814df0a1e0636cc0d39d46f16422b0e38 Mon Sep 17 00:00:00 2001 From: TomatoCake <60300461+DEVTomatoCake@users.noreply.github.com> Date: Sun, 30 Jun 2024 20:13:13 +0200 Subject: [PATCH 04/30] Add "email.senderAddress" config --- src/util/config/types/EmailConfiguration.ts | 1 + src/util/util/email/index.ts | 4 +++- src/util/util/email/transports/SMTP.ts | 7 +++++-- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/util/config/types/EmailConfiguration.ts b/src/util/config/types/EmailConfiguration.ts index ae9d53ba..62305d10 100644 --- a/src/util/config/types/EmailConfiguration.ts +++ b/src/util/config/types/EmailConfiguration.ts @@ -25,6 +25,7 @@ import { SendGridConfiguration } from "./subconfigurations/email/SendGrid"; export class EmailConfiguration { provider: string | null = null; + senderAddress: string | null = null; smtp: SMTPConfiguration = new SMTPConfiguration(); mailgun: MailGunConfiguration = new MailGunConfiguration(); mailjet: MailJetConfiguration = new MailJetConfiguration(); diff --git a/src/util/util/email/index.ts b/src/util/util/email/index.ts index 619cc5c3..d765f5ff 100644 --- a/src/util/util/email/index.ts +++ b/src/util/util/email/index.ts @@ -187,7 +187,9 @@ export const Email: { const message = { from: - Config.get().general.correspondenceEmail || "noreply@localhost", + Config.get().email.senderAddress || + Config.get().general.correspondenceEmail || + "noreply@localhost", to: email, subject, html, diff --git a/src/util/util/email/transports/SMTP.ts b/src/util/util/email/transports/SMTP.ts index 5b43a870..e3031943 100644 --- a/src/util/util/email/transports/SMTP.ts +++ b/src/util/util/email/transports/SMTP.ts @@ -27,9 +27,12 @@ export default async function () { if (!host || !port || secure === null || !username || !password) return console.error("[Email] SMTP has not been configured correctly."); - if (!Config.get().general.correspondenceEmail) + if ( + !Config.get().email.senderAddress && + !Config.get().general.correspondenceEmail + ) return console.error( - "[Email] Correspondence email has not been configured! This is used as the sender email address.", + '[Email] You have to configure either "email_senderAddress" or "general_correspondenceEmail" for emails to work. The configured value is used as the sender address.', ); // construct the transporter From e116e936936025a27ec75d915b680f981ce564e9 Mon Sep 17 00:00:00 2001 From: TomatoCake <60300461+DEVTomatoCake@users.noreply.github.com> Date: Sat, 29 Jun 2024 14:22:19 +0200 Subject: [PATCH 05/30] Add .position to public endpoints --- src/api/routes/channels/#channel_id/index.ts | 6 ++++++ .../channels/#channel_id/permissions.ts | 11 ++++++++--- src/api/routes/guilds/#guild_id/channels.ts | 19 ++++++++++++++++--- 3 files changed, 30 insertions(+), 6 deletions(-) diff --git a/src/api/routes/channels/#channel_id/index.ts b/src/api/routes/channels/#channel_id/index.ts index 99f9a647..291b6472 100644 --- a/src/api/routes/channels/#channel_id/index.ts +++ b/src/api/routes/channels/#channel_id/index.ts @@ -50,7 +50,13 @@ router.get( const channel = await Channel.findOneOrFail({ where: { id: channel_id }, }); + if (!channel.guild_id) return res.send(channel); + channel.position = await Channel.calculatePosition( + channel_id, + channel.guild_id, + channel.guild, + ); return res.send(channel); }, ); diff --git a/src/api/routes/channels/#channel_id/permissions.ts b/src/api/routes/channels/#channel_id/permissions.ts index d3edb0fa..fe289f23 100644 --- a/src/api/routes/channels/#channel_id/permissions.ts +++ b/src/api/routes/channels/#channel_id/permissions.ts @@ -1,17 +1,17 @@ /* Spacebar: A FOSS re-implementation and extension of the Discord.com backend. Copyright (C) 2023 Spacebar and Spacebar Contributors - + 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 by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. - + You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ @@ -53,6 +53,11 @@ router.put( where: { id: channel_id }, }); if (!channel.guild_id) throw new HTTPError("Channel not found", 404); + channel.position = await Channel.calculatePosition( + channel_id, + channel.guild_id, + channel.guild, + ); if (body.type === 0) { if (!(await Role.count({ where: { id: overwrite_id } }))) diff --git a/src/api/routes/guilds/#guild_id/channels.ts b/src/api/routes/guilds/#guild_id/channels.ts index 68208fee..51c38a75 100644 --- a/src/api/routes/guilds/#guild_id/channels.ts +++ b/src/api/routes/guilds/#guild_id/channels.ts @@ -1,17 +1,17 @@ /* Spacebar: A FOSS re-implementation and extension of the Discord.com backend. Copyright (C) 2023 Spacebar and Spacebar Contributors - + 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 by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. - + You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ @@ -41,6 +41,14 @@ router.get( const { guild_id } = req.params; const channels = await Channel.find({ where: { guild_id } }); + for await (const channel of channels) { + channel.position = await Channel.calculatePosition( + channel.id, + guild_id, + channel.guild, + ); + } + res.json(channels); }, ); @@ -71,6 +79,11 @@ router.post( { ...body, guild_id }, req.user_id, ); + channel.position = await Channel.calculatePosition( + channel.id, + guild_id, + channel.guild, + ); res.status(201).json(channel); }, From 6ca12cb7fb93498f1243f4a9ac5dd63782131568 Mon Sep 17 00:00:00 2001 From: TomatoCake <60300461+DEVTomatoCake@users.noreply.github.com> Date: Sat, 29 Jun 2024 14:47:20 +0200 Subject: [PATCH 06/30] Sort /channels for gateway consistency --- src/api/routes/guilds/#guild_id/channels.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/api/routes/guilds/#guild_id/channels.ts b/src/api/routes/guilds/#guild_id/channels.ts index 51c38a75..3488b64d 100644 --- a/src/api/routes/guilds/#guild_id/channels.ts +++ b/src/api/routes/guilds/#guild_id/channels.ts @@ -48,6 +48,7 @@ router.get( channel.guild, ); } + channels.sort((a, b) => a.position - b.position); res.json(channels); }, From 5f9c6b01a79ffff7ee9410d3a8649796db1e4875 Mon Sep 17 00:00:00 2001 From: TomatoCake <60300461+DEVTomatoCake@users.noreply.github.com> Date: Sat, 29 Jun 2024 19:40:08 +0200 Subject: [PATCH 07/30] Send position property on guild join --- src/util/entities/Member.ts | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/util/entities/Member.ts b/src/util/entities/Member.ts index 65942816..3ef778ac 100644 --- a/src/util/entities/Member.ts +++ b/src/util/entities/Member.ts @@ -1,17 +1,17 @@ /* Spacebar: A FOSS re-implementation and extension of the Discord.com backend. Copyright (C) 2023 Spacebar and Spacebar Contributors - + 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 by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. - + You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ @@ -31,7 +31,7 @@ import { PrimaryGeneratedColumn, RelationId, } from "typeorm"; -import { Ban, PublicGuildRelations } from "."; +import { Ban, Channel, PublicGuildRelations } from "."; import { ReadyGuildDTO } from "../dtos"; import { GuildCreateEvent, @@ -330,6 +330,13 @@ export class Member extends BaseClassWithoutId { relationLoadStrategy: "query", }); + for await (const channel of guild.channels) { + channel.position = await Channel.calculatePosition( + channel.id, + guild_id, + ); + } + const memberCount = await Member.count({ where: { guild_id } }); const memberPreview = ( From 0ac8888d410a3d8cd172ffe4eb44ebeff1e416e2 Mon Sep 17 00:00:00 2001 From: TomatoCake <60300461+DEVTomatoCake@users.noreply.github.com> Date: Tue, 25 Jun 2024 22:01:35 +0200 Subject: [PATCH 08/30] Don't embed links in <> --- src/api/util/handlers/Message.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/api/util/handlers/Message.ts b/src/api/util/handlers/Message.ts index 6172a3d0..85db26b2 100644 --- a/src/api/util/handlers/Message.ts +++ b/src/api/util/handlers/Message.ts @@ -51,7 +51,7 @@ const allow_empty = false; // TODO: embed gifs/videos/images const LINK_REGEX = - /https?:\/\/(www\.)?[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_+.~#?&//=]*)/g; + /?/g; export async function handleMessage(opts: MessageOptions): Promise { const channel = await Channel.findOneOrFail({ @@ -213,6 +213,9 @@ export async function postHandleMessage(message: Message) { const cachePromises = []; for (const link of links) { + // Don't embed links in <> + if (link.startsWith("<") && link.endsWith(">")) continue; + const url = new URL(link); const cached = await EmbedCache.findOne({ where: { url: link } }); From c52d6c49a3dac5123f5ca8d157e4a951f8b4e972 Mon Sep 17 00:00:00 2001 From: TomatoCake <60300461+DEVTomatoCake@users.noreply.github.com> Date: Fri, 5 Jul 2024 07:43:50 +0200 Subject: [PATCH 09/30] Add new message flags once again --- .../messages/#message_id/crosspost.ts | 7 ++-- .../guilds/#guild_id/messages/search.ts | 7 ++-- src/util/entities/Message.ts | 40 +++++++++++++++++-- .../1720157926878-messagePollObject.ts | 13 ++++++ .../mysql/1720157926878-messagePollObject.ts | 13 ++++++ .../1720157926878-messagePollObject.ts | 13 ++++++ src/util/schemas/MessageCreateSchema.ts | 27 ++++++++++--- .../responses/GuildMessagesSearchResponse.ts | 11 +++-- 8 files changed, 112 insertions(+), 19 deletions(-) create mode 100644 src/util/migration/mariadb/1720157926878-messagePollObject.ts create mode 100644 src/util/migration/mysql/1720157926878-messagePollObject.ts create mode 100644 src/util/migration/postgres/1720157926878-messagePollObject.ts diff --git a/src/api/routes/channels/#channel_id/messages/#message_id/crosspost.ts b/src/api/routes/channels/#channel_id/messages/#message_id/crosspost.ts index 5ca645c0..6362941c 100644 --- a/src/api/routes/channels/#channel_id/messages/#message_id/crosspost.ts +++ b/src/api/routes/channels/#channel_id/messages/#message_id/crosspost.ts @@ -1,17 +1,17 @@ /* Spacebar: A FOSS re-implementation and extension of the Discord.com backend. Copyright (C) 2023 Spacebar and Spacebar Contributors - + 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 by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. - + You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ @@ -56,6 +56,7 @@ router.post( edited_timestamp: null, flags: 1, components: [], + poll: {}, }).status(200); }, ); diff --git a/src/api/routes/guilds/#guild_id/messages/search.ts b/src/api/routes/guilds/#guild_id/messages/search.ts index 637d1e43..94adf9c6 100644 --- a/src/api/routes/guilds/#guild_id/messages/search.ts +++ b/src/api/routes/guilds/#guild_id/messages/search.ts @@ -1,17 +1,17 @@ /* Spacebar: A FOSS re-implementation and extension of the Discord.com backend. Copyright (C) 2023 Spacebar and Spacebar Contributors - + 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 by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. - + You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ @@ -162,6 +162,7 @@ router.get( edited_timestamp: x.edited_timestamp, flags: x.flags, components: x.components, + poll: x.poll, hit: true, }, ]); diff --git a/src/util/entities/Message.ts b/src/util/entities/Message.ts index 4a9cff4a..a76ebb1f 100644 --- a/src/util/entities/Message.ts +++ b/src/util/entities/Message.ts @@ -1,17 +1,17 @@ /* Spacebar: A FOSS re-implementation and extension of the Discord.com backend. Copyright (C) 2023 Spacebar and Spacebar Contributors - + 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 by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. - + You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ @@ -218,6 +218,9 @@ export class Message extends BaseClass { @Column({ type: "simple-json", nullable: true }) components?: MessageComponent[]; + @Column({ type: "simple-json", nullable: true }) + poll?: Poll[]; + toJSON(): Message { return { ...this, @@ -238,6 +241,7 @@ export class Message extends BaseClass { activity: this.activity ?? undefined, application: this.application ?? undefined, components: this.components ?? undefined, + poll: this.poll ?? undefined, content: this.content ?? "", }; } @@ -249,6 +253,7 @@ export interface MessageComponent { label?: string; emoji?: PartialEmoji; custom_id?: string; + sku_id?: string; url?: string; disabled?: boolean; components: MessageComponent[]; @@ -327,3 +332,32 @@ export interface AllowedMentions { users?: string[]; replied_user?: boolean; } + +export interface Poll { + question: PollMedia; + answers: PollAnswer[]; + expiry: Date; + allow_multiselect: boolean; + results?: PollResult; +} + +export interface PollMedia { + text?: string; + emoji?: PartialEmoji; +} + +export interface PollAnswer { + answer_id?: string; + poll_media: PollMedia; +} + +export interface PollResult { + is_finalized: boolean; + answer_counts: PollAnswerCount[]; +} + +export interface PollAnswerCount { + id: string; + count: number; + me_voted: boolean; +} diff --git a/src/util/migration/mariadb/1720157926878-messagePollObject.ts b/src/util/migration/mariadb/1720157926878-messagePollObject.ts new file mode 100644 index 00000000..c0866426 --- /dev/null +++ b/src/util/migration/mariadb/1720157926878-messagePollObject.ts @@ -0,0 +1,13 @@ +import { MigrationInterface, QueryRunner } from "typeorm"; + +export class MessagePollObject1720157926878 implements MigrationInterface { + name = "MessagePollObject1720157926878"; + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query("ALTER TABLE `messages` ADD `poll` text NULL"); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query("ALTER TABLE `messages` DROP COLUMN `poll`"); + } +} diff --git a/src/util/migration/mysql/1720157926878-messagePollObject.ts b/src/util/migration/mysql/1720157926878-messagePollObject.ts new file mode 100644 index 00000000..c0866426 --- /dev/null +++ b/src/util/migration/mysql/1720157926878-messagePollObject.ts @@ -0,0 +1,13 @@ +import { MigrationInterface, QueryRunner } from "typeorm"; + +export class MessagePollObject1720157926878 implements MigrationInterface { + name = "MessagePollObject1720157926878"; + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query("ALTER TABLE `messages` ADD `poll` text NULL"); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query("ALTER TABLE `messages` DROP COLUMN `poll`"); + } +} diff --git a/src/util/migration/postgres/1720157926878-messagePollObject.ts b/src/util/migration/postgres/1720157926878-messagePollObject.ts new file mode 100644 index 00000000..7c3c95a0 --- /dev/null +++ b/src/util/migration/postgres/1720157926878-messagePollObject.ts @@ -0,0 +1,13 @@ +import { MigrationInterface, QueryRunner } from "typeorm"; + +export class MessagePollObject1720157926878 implements MigrationInterface { + name = "MessagePollObject1720157926878"; + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query("ALTER TABLE messages ADD poll text NULL"); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query("ALTER TABLE messages DROP COLUMN poll"); + } +} diff --git a/src/util/schemas/MessageCreateSchema.ts b/src/util/schemas/MessageCreateSchema.ts index 57abf62f..be1c31be 100644 --- a/src/util/schemas/MessageCreateSchema.ts +++ b/src/util/schemas/MessageCreateSchema.ts @@ -1,22 +1,22 @@ /* Spacebar: A FOSS re-implementation and extension of the Discord.com backend. Copyright (C) 2023 Spacebar and Spacebar Contributors - + 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 by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. - + You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ -import { Embed } from "@spacebar/util"; +import { Embed, MessageComponent, PollAnswer, PollMedia } from "@spacebar/util"; type Attachment = { id: string; @@ -54,6 +54,21 @@ export interface MessageCreateSchema { **/ attachments?: Attachment[]; sticker_ids?: string[]; - // eslint-disable-next-line @typescript-eslint/no-explicit-any - components?: any[]; + components?: MessageComponent[]; + // TODO: Fix TypeScript errors in src\api\util\handlers\Message.ts once this is enabled + //poll?: PollCreationSchema; + enforce_nonce?: boolean; // For Discord compatibility, it's the default behavior here + applied_tags?: string[]; // Not implemented yet, for webhooks in forums + thread_name?: string; // Not implemented yet, for webhooks + avatar_url?: string; // Not implemented yet, for webhooks +} + +// TypeScript complains once this is used above +// eslint-disable-next-line @typescript-eslint/no-unused-vars +interface PollCreationSchema { + question: PollMedia; + answers: PollAnswer[]; + duration?: number; + allow_multiselect?: boolean; + layout_type?: number; } diff --git a/src/util/schemas/responses/GuildMessagesSearchResponse.ts b/src/util/schemas/responses/GuildMessagesSearchResponse.ts index b42aafd3..6121983e 100644 --- a/src/util/schemas/responses/GuildMessagesSearchResponse.ts +++ b/src/util/schemas/responses/GuildMessagesSearchResponse.ts @@ -1,17 +1,17 @@ /* Spacebar: A FOSS re-implementation and extension of the Discord.com backend. Copyright (C) 2023 Spacebar and Spacebar Contributors - + 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 by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. - + You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ @@ -19,7 +19,9 @@ import { Attachment, Embed, + MessageComponent, MessageType, + Poll, PublicUser, Role, } from "../../entities"; @@ -40,7 +42,8 @@ export interface GuildMessagesSearchMessage { timestamp: string; edited_timestamp: string | null; flags: number; - components: unknown[]; + components: MessageComponent[]; + poll: Poll; hit: true; } From cd7641c2aebd245a59a189233fc5700a924639e0 Mon Sep 17 00:00:00 2001 From: TomatoCake <60300461+DEVTomatoCake@users.noreply.github.com> Date: Sat, 6 Jul 2024 06:47:14 +0200 Subject: [PATCH 10/30] Fix loading connection settings --- src/connections/BattleNet/index.ts | 20 +++++++++++--------- src/connections/Discord/index.ts | 13 ++++++++----- src/connections/EpicGames/index.ts | 20 +++++++++++--------- src/connections/Facebook/index.ts | 13 ++++++++----- src/connections/GitHub/index.ts | 13 ++++++++----- src/connections/Reddit/index.ts | 13 ++++++++----- src/connections/Spotify/index.ts | 14 +++++++++----- src/connections/Twitch/index.ts | 13 ++++++++----- src/connections/Twitter/index.ts | 13 ++++++++----- src/connections/Xbox/index.ts | 13 ++++++++----- src/connections/Youtube/index.ts | 13 ++++++++----- 11 files changed, 95 insertions(+), 63 deletions(-) diff --git a/src/connections/BattleNet/index.ts b/src/connections/BattleNet/index.ts index 4fdfccb1..8f44944c 100644 --- a/src/connections/BattleNet/index.ts +++ b/src/connections/BattleNet/index.ts @@ -1,17 +1,17 @@ /* Spacebar: A FOSS re-implementation and extension of the Discord.com backend. Copyright (C) 2023 Spacebar and Spacebar Contributors - + 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 by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. - + You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ @@ -47,13 +47,15 @@ export default class BattleNetConnection extends Connection { settings: BattleNetSettings = new BattleNetSettings(); init(): void { - const settings = - ConnectionLoader.getConnectionConfig( - this.id, - this.settings, - ); + this.settings = ConnectionLoader.getConnectionConfig( + this.id, + this.settings, + ); - if (settings.enabled && (!settings.clientId || !settings.clientSecret)) + if ( + this.settings.enabled && + (!this.settings.clientId || !this.settings.clientSecret) + ) throw new Error(`Invalid settings for connection ${this.id}`); } diff --git a/src/connections/Discord/index.ts b/src/connections/Discord/index.ts index 731086f1..e5508f48 100644 --- a/src/connections/Discord/index.ts +++ b/src/connections/Discord/index.ts @@ -1,17 +1,17 @@ /* Spacebar: A FOSS re-implementation and extension of the Discord.com backend. Copyright (C) 2023 Spacebar and Spacebar Contributors - + 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 by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. - + You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ @@ -43,12 +43,15 @@ export default class DiscordConnection extends Connection { settings: DiscordSettings = new DiscordSettings(); init(): void { - const settings = ConnectionLoader.getConnectionConfig( + this.settings = ConnectionLoader.getConnectionConfig( this.id, this.settings, ); - if (settings.enabled && (!settings.clientId || !settings.clientSecret)) + if ( + this.settings.enabled && + (!this.settings.clientId || !this.settings.clientSecret) + ) throw new Error(`Invalid settings for connection ${this.id}`); } diff --git a/src/connections/EpicGames/index.ts b/src/connections/EpicGames/index.ts index e5b2d336..cedfcd0a 100644 --- a/src/connections/EpicGames/index.ts +++ b/src/connections/EpicGames/index.ts @@ -1,17 +1,17 @@ /* Spacebar: A FOSS re-implementation and extension of the Discord.com backend. Copyright (C) 2023 Spacebar and Spacebar Contributors - + 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 by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. - + You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ @@ -53,13 +53,15 @@ export default class EpicGamesConnection extends Connection { settings: EpicGamesSettings = new EpicGamesSettings(); init(): void { - const settings = - ConnectionLoader.getConnectionConfig( - this.id, - this.settings, - ); + this.settings = ConnectionLoader.getConnectionConfig( + this.id, + this.settings, + ); - if (settings.enabled && (!settings.clientId || !settings.clientSecret)) + if ( + this.settings.enabled && + (!this.settings.clientId || !this.settings.clientSecret) + ) throw new Error(`Invalid settings for connection ${this.id}`); } diff --git a/src/connections/Facebook/index.ts b/src/connections/Facebook/index.ts index 2bf26f34..bcb90b4c 100644 --- a/src/connections/Facebook/index.ts +++ b/src/connections/Facebook/index.ts @@ -1,17 +1,17 @@ /* Spacebar: A FOSS re-implementation and extension of the Discord.com backend. Copyright (C) 2023 Spacebar and Spacebar Contributors - + 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 by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. - + You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ @@ -52,12 +52,15 @@ export default class FacebookConnection extends Connection { settings: FacebookSettings = new FacebookSettings(); init(): void { - const settings = ConnectionLoader.getConnectionConfig( + this.settings = ConnectionLoader.getConnectionConfig( this.id, this.settings, ); - if (settings.enabled && (!settings.clientId || !settings.clientSecret)) + if ( + this.settings.enabled && + (!this.settings.clientId || !this.settings.clientSecret) + ) throw new Error(`Invalid settings for connection ${this.id}`); } diff --git a/src/connections/GitHub/index.ts b/src/connections/GitHub/index.ts index 25e5f89f..78bf510e 100644 --- a/src/connections/GitHub/index.ts +++ b/src/connections/GitHub/index.ts @@ -1,17 +1,17 @@ /* Spacebar: A FOSS re-implementation and extension of the Discord.com backend. Copyright (C) 2023 Spacebar and Spacebar Contributors - + 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 by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. - + You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ @@ -42,12 +42,15 @@ export default class GitHubConnection extends Connection { settings: GitHubSettings = new GitHubSettings(); init(): void { - const settings = ConnectionLoader.getConnectionConfig( + this.settings = ConnectionLoader.getConnectionConfig( this.id, this.settings, ); - if (settings.enabled && (!settings.clientId || !settings.clientSecret)) + if ( + this.settings.enabled && + (!this.settings.clientId || !this.settings.clientSecret) + ) throw new Error(`Invalid settings for connection ${this.id}`); } diff --git a/src/connections/Reddit/index.ts b/src/connections/Reddit/index.ts index 149cce02..0db23731 100644 --- a/src/connections/Reddit/index.ts +++ b/src/connections/Reddit/index.ts @@ -1,17 +1,17 @@ /* Spacebar: A FOSS re-implementation and extension of the Discord.com backend. Copyright (C) 2023 Spacebar and Spacebar Contributors - + 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 by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. - + You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ @@ -54,12 +54,15 @@ export default class RedditConnection extends Connection { settings: RedditSettings = new RedditSettings(); init(): void { - const settings = ConnectionLoader.getConnectionConfig( + this.settings = ConnectionLoader.getConnectionConfig( this.id, this.settings, ); - if (settings.enabled && (!settings.clientId || !settings.clientSecret)) + if ( + this.settings.enabled && + (!this.settings.clientId || !this.settings.clientSecret) + ) throw new Error(`Invalid settings for connection ${this.id}`); } diff --git a/src/connections/Spotify/index.ts b/src/connections/Spotify/index.ts index ece404d8..4eb12602 100644 --- a/src/connections/Spotify/index.ts +++ b/src/connections/Spotify/index.ts @@ -1,17 +1,17 @@ /* Spacebar: A FOSS re-implementation and extension of the Discord.com backend. Copyright (C) 2023 Spacebar and Spacebar Contributors - + 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 by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. - + You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ @@ -63,12 +63,16 @@ export default class SpotifyConnection extends RefreshableConnection { * So to prevent spamming the spotify api we disable the ability to refresh. */ this.refreshEnabled = false; - const settings = ConnectionLoader.getConnectionConfig( + + this.settings = ConnectionLoader.getConnectionConfig( this.id, this.settings, ); - if (settings.enabled && (!settings.clientId || !settings.clientSecret)) + if ( + this.settings.enabled && + (!this.settings.clientId || !this.settings.clientSecret) + ) throw new Error(`Invalid settings for connection ${this.id}`); } diff --git a/src/connections/Twitch/index.ts b/src/connections/Twitch/index.ts index 9a6cea35..953669a1 100644 --- a/src/connections/Twitch/index.ts +++ b/src/connections/Twitch/index.ts @@ -1,17 +1,17 @@ /* Spacebar: A FOSS re-implementation and extension of the Discord.com backend. Copyright (C) 2023 Spacebar and Spacebar Contributors - + 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 by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. - + You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ @@ -55,12 +55,15 @@ export default class TwitchConnection extends RefreshableConnection { settings: TwitchSettings = new TwitchSettings(); init(): void { - const settings = ConnectionLoader.getConnectionConfig( + this.settings = ConnectionLoader.getConnectionConfig( this.id, this.settings, ); - if (settings.enabled && (!settings.clientId || !settings.clientSecret)) + if ( + this.settings.enabled && + (!this.settings.clientId || !this.settings.clientSecret) + ) throw new Error(`Invalid settings for connection ${this.id}`); } diff --git a/src/connections/Twitter/index.ts b/src/connections/Twitter/index.ts index 62fd7da1..eba8ceb5 100644 --- a/src/connections/Twitter/index.ts +++ b/src/connections/Twitter/index.ts @@ -1,17 +1,17 @@ /* Spacebar: A FOSS re-implementation and extension of the Discord.com backend. Copyright (C) 2023 Spacebar and Spacebar Contributors - + 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 by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. - + You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ @@ -55,12 +55,15 @@ export default class TwitterConnection extends RefreshableConnection { settings: TwitterSettings = new TwitterSettings(); init(): void { - const settings = ConnectionLoader.getConnectionConfig( + this.settings = ConnectionLoader.getConnectionConfig( this.id, this.settings, ); - if (settings.enabled && (!settings.clientId || !settings.clientSecret)) + if ( + this.settings.enabled && + (!this.settings.clientId || !this.settings.clientSecret) + ) throw new Error(`Invalid settings for connection ${this.id}`); } diff --git a/src/connections/Xbox/index.ts b/src/connections/Xbox/index.ts index 935ff7ab..84066def 100644 --- a/src/connections/Xbox/index.ts +++ b/src/connections/Xbox/index.ts @@ -1,17 +1,17 @@ /* Spacebar: A FOSS re-implementation and extension of the Discord.com backend. Copyright (C) 2023 Spacebar and Spacebar Contributors - + 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 by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. - + You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ @@ -62,12 +62,15 @@ export default class XboxConnection extends Connection { settings: XboxSettings = new XboxSettings(); init(): void { - const settings = ConnectionLoader.getConnectionConfig( + this.settings = ConnectionLoader.getConnectionConfig( this.id, this.settings, ); - if (settings.enabled && (!settings.clientId || !settings.clientSecret)) + if ( + this.settings.enabled && + (!this.settings.clientId || !this.settings.clientSecret) + ) throw new Error(`Invalid settings for connection ${this.id}`); } diff --git a/src/connections/Youtube/index.ts b/src/connections/Youtube/index.ts index 844803cf..38edbb0d 100644 --- a/src/connections/Youtube/index.ts +++ b/src/connections/Youtube/index.ts @@ -1,17 +1,17 @@ /* Spacebar: A FOSS re-implementation and extension of the Discord.com backend. Copyright (C) 2023 Spacebar and Spacebar Contributors - + 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 by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. - + You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ @@ -62,12 +62,15 @@ export default class YoutubeConnection extends Connection { settings: YoutubeSettings = new YoutubeSettings(); init(): void { - const settings = ConnectionLoader.getConnectionConfig( + this.settings = ConnectionLoader.getConnectionConfig( this.id, this.settings, ); - if (settings.enabled && (!settings.clientId || !settings.clientSecret)) + if ( + this.settings.enabled && + (!this.settings.clientId || !this.settings.clientSecret) + ) throw new Error(`Invalid settings for connection ${this.id}`); } From ba1ec9cab4221c62e87b1f7555958747320e7a98 Mon Sep 17 00:00:00 2001 From: TomatoCake <60300461+DEVTomatoCake@users.noreply.github.com> Date: Sat, 6 Jul 2024 15:57:56 +0200 Subject: [PATCH 11/30] Fix msg attachment proxy_url when using paths --- .../channels/#channel_id/messages/index.ts | 20 +++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/src/api/routes/channels/#channel_id/messages/index.ts b/src/api/routes/channels/#channel_id/messages/index.ts index a5bfcfd7..4d7e388f 100644 --- a/src/api/routes/channels/#channel_id/messages/index.ts +++ b/src/api/routes/channels/#channel_id/messages/index.ts @@ -1,17 +1,17 @@ /* Spacebar: A FOSS re-implementation and extension of the Discord.com backend. Copyright (C) 2023 Spacebar and Spacebar Contributors - + 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 by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. - + You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ @@ -183,9 +183,17 @@ router.get( const uri = y.proxy_url.startsWith("http") ? y.proxy_url : `https://example.org${y.proxy_url}`; - y.proxy_url = `${endpoint == null ? "" : endpoint}${ - new URL(uri).pathname - }`; + + let pathname = new URL(uri).pathname; + while ( + pathname.split("/")[0] != "attachments" && + pathname.length > 10 + ) { + pathname = pathname.split("/").slice(1).join("/"); + } + if (!endpoint?.endsWith("/")) pathname = "/" + pathname; + + y.proxy_url = `${endpoint == null ? "" : endpoint}${pathname}`; }); /** From 8358755eeb8aea4bc4d151b778f818c5d6e9527f Mon Sep 17 00:00:00 2001 From: TomatoCake <60300461+DEVTomatoCake@users.noreply.github.com> Date: Sat, 6 Jul 2024 16:02:21 +0200 Subject: [PATCH 12/30] Increase minimum char count --- src/api/routes/channels/#channel_id/messages/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/routes/channels/#channel_id/messages/index.ts b/src/api/routes/channels/#channel_id/messages/index.ts index 4d7e388f..645c6db2 100644 --- a/src/api/routes/channels/#channel_id/messages/index.ts +++ b/src/api/routes/channels/#channel_id/messages/index.ts @@ -187,7 +187,7 @@ router.get( let pathname = new URL(uri).pathname; while ( pathname.split("/")[0] != "attachments" && - pathname.length > 10 + pathname.length > 30 ) { pathname = pathname.split("/").slice(1).join("/"); } From bd66ee0349ec9133706f793dbfcd6e82489dae38 Mon Sep 17 00:00:00 2001 From: TomatoCake <60300461+DEVTomatoCake@users.noreply.github.com> Date: Sat, 6 Jul 2024 17:51:52 +0200 Subject: [PATCH 13/30] Use front end URI instead of API --- src/util/connections/Connection.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/util/connections/Connection.ts b/src/util/connections/Connection.ts index 5bdebd47..638dde2c 100644 --- a/src/util/connections/Connection.ts +++ b/src/util/connections/Connection.ts @@ -1,17 +1,17 @@ /* Spacebar: A FOSS re-implementation and extension of the Discord.com backend. Copyright (C) 2023 Spacebar and Spacebar Contributors - + 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 by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. - + You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ @@ -43,7 +43,7 @@ export abstract class Connection { */ getRedirectUri() { const endpointPublic = - Config.get().api.endpointPublic ?? "http://localhost:3001"; + Config.get().general.frontPage ?? "http://localhost:3001"; return `${endpointPublic}/connections/${this.id}/callback`; } From 4e825cc4d33b5d0f56b1907a6ac901eb9af14f15 Mon Sep 17 00:00:00 2001 From: Puyodead1 Date: Mon, 8 Jul 2024 21:23:41 -0400 Subject: [PATCH 14/30] fix `verify_email` template --- assets/email_templates/verify_email.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/assets/email_templates/verify_email.html b/assets/email_templates/verify_email.html index 109fc4aa..cbd94280 100644 --- a/assets/email_templates/verify_email.html +++ b/assets/email_templates/verify_email.html @@ -69,7 +69,7 @@ > {emailVerificationUrl}{actionUrl} From 629451bbfd9698975bdb95dce4f3152bbdb3893c Mon Sep 17 00:00:00 2001 From: Puyodead1 Date: Mon, 8 Jul 2024 22:10:50 -0400 Subject: [PATCH 15/30] fix incorrect error field --- src/api/routes/auth/verify/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/routes/auth/verify/index.ts b/src/api/routes/auth/verify/index.ts index 49f74277..32c3f305 100644 --- a/src/api/routes/auth/verify/index.ts +++ b/src/api/routes/auth/verify/index.ts @@ -85,7 +85,7 @@ router.post( user = userTokenData.user; } catch { throw FieldErrors({ - password: { + token: { message: req.t("auth:password_reset.INVALID_TOKEN"), code: "INVALID_TOKEN", }, From bc432a4325644eb1e5040b47ed05eda699bd404f Mon Sep 17 00:00:00 2001 From: Puyodead1 Date: Mon, 8 Jul 2024 22:30:41 -0400 Subject: [PATCH 16/30] add email verification page --- .../email_templates/new_login_location.html | 145 +++++++++-------- assets/email_templates/password_changed.html | 4 +- .../password_reset_request.html | 125 ++++++++------- assets/email_templates/phone_removed.html | 4 +- assets/email_templates/verify_email.html | 9 +- assets/public/verify.html | 147 ++++++++++++++++++ flake.lock | Bin 1497 -> 1305 bytes src/api/Server.ts | 18 ++- src/util/util/email/index.ts | 3 +- 9 files changed, 323 insertions(+), 132 deletions(-) create mode 100644 assets/public/verify.html diff --git a/assets/email_templates/new_login_location.html b/assets/email_templates/new_login_location.html index f1c5f8c5..b8c4a4fb 100644 --- a/assets/email_templates/new_login_location.html +++ b/assets/email_templates/new_login_location.html @@ -1,76 +1,87 @@ - + + + + + + + Verify {instanceName} Login from New Location - - - - - - Verify {instanceName} Login from New Location + + - .ExternalClass { - width: 100%; - } - - - - -
- Branding + Branding -
+
-

+

- Hey {userUsername}, -

-

- It looks like someone tried to log into your {instanceName} - account from a new location. If this is you, follow the link - below to authorize logging in from this location on your - account. If this isn't you, we suggest changing your - password as soon as possible. -

-

- IP Address: {ipAddress} -
- Location: {locationCity}, {locationRegion}, - {locationCountryName} -

-
-
+ Hey {userUsername}, +

+

+ It looks like someone tried to log into your {instanceName} + account from a new location. If this is you, follow the link + below to authorize logging in from this location on your + account. If this isn't you, we suggest changing your + password as soon as possible. +

+

+ IP Address: {ipAddress} +
+ Location: {locationCity}, {locationRegion}, + {locationCountryName} +

+
+ -
-
Verify Login +
+
+
-

- Alternatively, you can directly paste this link into - your browser: -

- {actionUrl} + " + > +

+ Alternatively, you can directly paste this link into + your browser: +

+ {actionUrl} +
-
- - + diff --git a/assets/email_templates/password_changed.html b/assets/email_templates/password_changed.html index d0426279..7d368a0a 100644 --- a/assets/email_templates/password_changed.html +++ b/assets/email_templates/password_changed.html @@ -1,4 +1,4 @@ - + @@ -22,7 +22,7 @@ -
+
Branding + + + + + + + Password Reset Request for {instanceName} - - - - - - Password Reset Request for {instanceName} + + - .ExternalClass { - width: 100%; - } - - - - -
- Branding + Branding -
+
-

+

- Hey {userUsername}, -

-

- Your {instanceName} password can be reset by clicking the - button below. If you did not request a new password, please - ignore this email. -

-
-
+ Hey {userUsername}, +

+

+ Your {instanceName} password can be reset by clicking the + button below. If you did not request a new password, please + ignore this email. +

+
+ -
-
-

- Alternatively, you can directly paste this link into - your browser: -

- {actionUrl} + " + >Reset Password +
+
+
+

+ Alternatively, you can directly paste this link into + your browser: +

+ {actionUrl} +
-
- - + diff --git a/assets/email_templates/phone_removed.html b/assets/email_templates/phone_removed.html index 7cc552e9..bcbc8f18 100644 --- a/assets/email_templates/phone_removed.html +++ b/assets/email_templates/phone_removed.html @@ -1,4 +1,4 @@ - + @@ -22,7 +22,7 @@ -
+
Branding + @@ -22,7 +22,7 @@ -
+ diff --git a/assets/public/verify.html b/assets/public/verify.html new file mode 100644 index 00000000..c70d7709 --- /dev/null +++ b/assets/public/verify.html @@ -0,0 +1,147 @@ + + + + + + + Spacebar Server + + + + + + + + + +
+ Spacebar Logo + +
+

Verifying your email

+

Please wait...

+
+
+ + + + diff --git a/flake.lock b/flake.lock index ae5e8b23070de1f0618864a223c9a3c17f752ca5..844f26fa6bf673dc335b2aabc1e75e6c0d046c8c 100644 GIT binary patch literal 1305 zcmbVL+j5&Q5Pi14qNC?}tP2RKGkvgKx1QEZaj)~F!UY8fyO60p1Z6~lvC*{VrH}<#aYqhW!Q&u5+ zKM(dl=j$6tjLO(=tYw;gSCLoEK7un!@)+x^!HCPK@Rjc3nNE`?eA(AICDRYh4bm>w z)IyRtP$FKl;}lD1DMtyy2*FBf$HlZmEUHvDd7fYFN(WqYo@Bn~$0Dq68!hYJ|AW;K zd=1u$3u6C}23~K)6!UwUT<(F!ePLIjqZnKT< z7B|syIiR(FNb*jXPU(*0OO;JViNqE$pd$>WnahZ_G?5S!hnt*BA{`AL_^Flb`tFicl>`>KS{47a|&e~TyaXDYZ`wsl-@>pcv3G+$Vh4VpXYDD_^R zmPu(>lwr|%bzUSTs0BF{wV{q{Qo)fzltY9$(I#?)=@?vKtM_0?>}xE(lGPA=qxHDm XC2)50^sdW-2c6}964wq}$I-BL+kcBkbn$d%Ezv_v;VyTWjBt}+UX6D z6LQX*^FGPTU^q0=Ovu9cIDAn9HS}X1$x&5?@q18(!*pAfdPK#Fx+rDR1m8Z}9K+%3 zhtr1=5Tl%&{%!~3a6QLirGtdSW1`J`dTh*xI`GOalHur`ji;Sw30p=1rcoO3F}3eJ+>VteMg`tu4*v zQ!@*tk0i07hh5-7rqnWmJYWk~a7-~q!jrC#h@QEux3XCqgyp7kjf=iyc^HH#kJUfN z#-T)WlS4&80t4#Ks`49)k%&;ET6gj6b72Uy>(SQz~!cp)Tdb55_IE5Fkp?pD}r?VZO5_+^Lp_`@L7v^kDuZ&v8(%9s96ctD7KV z$#iBD+Kb7kQ`niNE{qNqA$?xOrSA9%7Qu-P7~u*H*S82~P(Z=}L<~y{y4-S2#*uyI pU5`Os-5X%}N3A^tkN&75oW0Z#U8v4egi7jeBA&5 diff --git a/src/api/Server.ts b/src/api/Server.ts index 472ab1d6..40d2b6dc 100644 --- a/src/api/Server.ts +++ b/src/api/Server.ts @@ -18,15 +18,15 @@ import { Config, - Email, - initDatabase, - initEvent, - JSONReplacer, - registerRoutes, - Sentry, - WebAuthn, ConnectionConfig, ConnectionLoader, + Email, + JSONReplacer, + Sentry, + WebAuthn, + initDatabase, + initEvent, + registerRoutes, } from "@spacebar/util"; import { Request, Response, Router } from "express"; import { Server, ServerOptions } from "lambert-server"; @@ -141,6 +141,10 @@ export class SpacebarServer extends Server { res.sendFile(path.join(PUBLIC_ASSETS_FOLDER, "index.html")), ); + app.get("/verify", (req, res) => + res.sendFile(path.join(PUBLIC_ASSETS_FOLDER, "verify.html")), + ); + this.app.use(ErrorHandler); Sentry.errorHandler(this.app); diff --git a/src/util/util/email/index.ts b/src/util/util/email/index.ts index d765f5ff..e3382794 100644 --- a/src/util/util/email/index.ts +++ b/src/util/util/email/index.ts @@ -141,8 +141,9 @@ export const Email: { */ generateLink: async function (type, id, email) { const token = (await generateToken(id, email)) as string; + // puyodead1: this is set to api endpoint because the verification page is on the server since no clients have one, and not all 3rd party clients will have one const instanceUrl = - Config.get().general.frontPage || "http://localhost:3001"; + Config.get().api.endpointPublic || "http://localhost:3001"; const link = `${instanceUrl}/${type}#token=${token}`; return link; }, From 35c9a09ea52099d8ee7eb79a4683f9301dedecd4 Mon Sep 17 00:00:00 2001 From: Madeline <46743919+MaddyUnderStars@users.noreply.github.com> Date: Tue, 9 Jul 2024 15:27:24 +1000 Subject: [PATCH 17/30] fix poll in msg create schema --- assets/openapi.json | Bin 573995 -> 581490 bytes assets/schemas.json | Bin 18446882 -> 19250985 bytes src/api/util/handlers/Message.ts | 37 ++++++++++++------------ src/util/schemas/MessageCreateSchema.ts | 2 +- 4 files changed, 20 insertions(+), 19 deletions(-) diff --git a/assets/openapi.json b/assets/openapi.json index f649c9b22c817a2f33ae5c7afdb99e5b8398c25f..0a211d3c30e6fecaff7eedb22937a8e90e8364c4 100644 GIT binary patch delta 1432 zcmc&!T})eL7|#2h)1LkSc0gzm+VNA}V6HzS5Faiw{2LBOlkz)270!B5bzN!sXggAH@MaS?H6dGH@5lys>cjKwK1(p;#1!BV>pjNr?$Gv_eysV=bKg+am@;H2;h7 zjLyUg(Zm>fv&^hUNpvZ1w|Bx}n%@_|pUN4vE|Ll-LkTe~2GF$%1M0AFGL}l>>c?ac zHN0!Vh8xgZLJ?R}S1Pt+jnrWJ9k8erP!GC{Ol|fzXre1`JxA{zZKU41SJ0jTHJ#XR zR=UEQ??aOURf&!fV&3j$G7f`9bb4)uXHUpzH2=5t$wAN`XLr-ZNTWs$;3K8+s)`*@ z`v=_8hk|QA`ZdIdU)=#Kb=a(QC2w0w=T^L$U?>rYjf(NC2*;@5Ya2dO%@k8Tg`=k%ytKs$H~UN+jMGIuApA*2vgtx-f%|bD)tNc6j4>NejtY zIK?pXGUbe#txf(nVkdMe{9F&avKQd#46EW|A{9pAGHFoutd&=KMER1$+Z|-EC<@J% zD5$gZSyfX}Lkjy;0gqQh?GrNK6dA}M*#9$YQrbtuD)YQH!4HR`LO3)|{}?*1S5U+_ zABd%7-CicUmBo}RiHa!2_<>jouPwkh_b`rnzPIQ?+Ypn%efr0u(cVIeno~+m;zTP^ zQ{(Als))#s#^~y@6TOvCQ?ihwg|KMKfDsKnP{$S{(!n-qJ`3mCa85^F#^1{|YV5N? z|3lh#DyxAaYbM!7lJ7c%2{{qNxnD^wz5kL;u yUA;Yg@0*9*2kCsc3fE4vRg&XNRRp;1RQPSBoXo^|^bT;F)3@q5=~lhQ^T|KZo%~Dy delta 373 zcmZ8cJxD@P80EY7`L0o~s3fz@M3=A>L2;|6I5Y$m&P6rY6e$Qn(eR+aG2s?pL())0 zU_|t)O9=6t^NHZ^`9D=mMkq5(W z(!;~^aqed_`drYCnLA*3@(4jbY45;HADD5`3w3;J$A-@;m_$K^(=mNz`VBB~OqkF% zV2ReKSJx544e=Tb!b; z0y6}=!{8EyC&<12DtOyZJJFvaU4KQ{YqHw%PZ47;WMas8dciYEuW2vML!ciLxq}zpy&YwnaE6*+6(=Ofg~dkVP?5kw?-+m5HKi-rxKI1NV)} diff --git a/assets/schemas.json b/assets/schemas.json index 7a57dfcf5dac412b69d459413e85bcc0240fe948..a77f86b6771c9397acc37934a29a2205f1064d2d 100644 GIT binary patch delta 109953 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 d8?WU$M8$^*$Qd15+vc&t1Xx{CixQtr{{r57x�K diff --git a/src/api/util/handlers/Message.ts b/src/api/util/handlers/Message.ts index 85db26b2..64bcdd56 100644 --- a/src/api/util/handlers/Message.ts +++ b/src/api/util/handlers/Message.ts @@ -16,36 +16,36 @@ along with this program. If not, see . */ +import * as Sentry from "@sentry/node"; +import { EmbedHandlers } from "@spacebar/api"; import { + Application, + Attachment, Channel, + Config, Embed, + EmbedCache, emitEvent, - Guild, - Message, - MessageCreateEvent, - MessageUpdateEvent, + EVERYONE_MENTION, getPermission, getRights, + Guild, + HERE_MENTION, + Message, + MessageCreateEvent, + MessageCreateSchema, + MessageType, + MessageUpdateEvent, + Role, + ROLE_MENTION, + Sticker, + User, //CHANNEL_MENTION, USER_MENTION, - ROLE_MENTION, - Role, - EVERYONE_MENTION, - HERE_MENTION, - MessageType, - User, - Application, Webhook, - Attachment, - Config, - Sticker, - MessageCreateSchema, - EmbedCache, } from "@spacebar/util"; import { HTTPError } from "lambert-server"; import { In } from "typeorm"; -import { EmbedHandlers } from "@spacebar/api"; -import * as Sentry from "@sentry/node"; const allow_empty = false; // TODO: check webhook, application, system author, stickers // TODO: embed gifs/videos/images @@ -66,6 +66,7 @@ export async function handleMessage(opts: MessageOptions): Promise { : undefined; const message = Message.create({ ...opts, + poll: opts.poll ? [opts.poll] : undefined, sticker_items: stickers, guild_id: channel.guild_id, channel_id: opts.channel_id, diff --git a/src/util/schemas/MessageCreateSchema.ts b/src/util/schemas/MessageCreateSchema.ts index be1c31be..495e2ebd 100644 --- a/src/util/schemas/MessageCreateSchema.ts +++ b/src/util/schemas/MessageCreateSchema.ts @@ -56,7 +56,7 @@ export interface MessageCreateSchema { sticker_ids?: string[]; components?: MessageComponent[]; // TODO: Fix TypeScript errors in src\api\util\handlers\Message.ts once this is enabled - //poll?: PollCreationSchema; + poll?: PollCreationSchema; enforce_nonce?: boolean; // For Discord compatibility, it's the default behavior here applied_tags?: string[]; // Not implemented yet, for webhooks in forums thread_name?: string; // Not implemented yet, for webhooks From 9b02e82614403d11b463217b2867b127ff3305f2 Mon Sep 17 00:00:00 2001 From: TomatoCake <60300461+DEVTomatoCake@users.noreply.github.com> Date: Tue, 9 Jul 2024 14:55:01 +0200 Subject: [PATCH 18/30] Make poll a single object instead of an array --- src/api/util/handlers/Message.ts | 8 ++++---- src/util/entities/Message.ts | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/api/util/handlers/Message.ts b/src/api/util/handlers/Message.ts index 64bcdd56..325a7e1a 100644 --- a/src/api/util/handlers/Message.ts +++ b/src/api/util/handlers/Message.ts @@ -1,17 +1,17 @@ /* Spacebar: A FOSS re-implementation and extension of the Discord.com backend. Copyright (C) 2023 Spacebar and Spacebar Contributors - + 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 by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. - + You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ @@ -66,7 +66,7 @@ export async function handleMessage(opts: MessageOptions): Promise { : undefined; const message = Message.create({ ...opts, - poll: opts.poll ? [opts.poll] : undefined, + poll: opts.poll, sticker_items: stickers, guild_id: channel.guild_id, channel_id: opts.channel_id, diff --git a/src/util/entities/Message.ts b/src/util/entities/Message.ts index a76ebb1f..d28c8c29 100644 --- a/src/util/entities/Message.ts +++ b/src/util/entities/Message.ts @@ -219,7 +219,7 @@ export class Message extends BaseClass { components?: MessageComponent[]; @Column({ type: "simple-json", nullable: true }) - poll?: Poll[]; + poll?: Poll; toJSON(): Message { return { From 21579b11cd3ca2205cd7b2dce8c3734c101855b6 Mon Sep 17 00:00:00 2001 From: Cyber Date: Tue, 9 Jul 2024 16:02:11 +0200 Subject: [PATCH 19/30] fix: poll message is not an empty message --- src/api/util/handlers/Message.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/api/util/handlers/Message.ts b/src/api/util/handlers/Message.ts index 325a7e1a..ea673e50 100644 --- a/src/api/util/handlers/Message.ts +++ b/src/api/util/handlers/Message.ts @@ -139,7 +139,8 @@ export async function handleMessage(opts: MessageOptions): Promise { !opts.content && !opts.embeds?.length && !opts.attachments?.length && - !opts.sticker_ids?.length + !opts.sticker_ids?.length && + !opts.poll ) { throw new HTTPError("Empty messages are not allowed", 50006); } From 7698a15f030732f4c855ec11a9c08538be037d78 Mon Sep 17 00:00:00 2001 From: Cyber Date: Tue, 9 Jul 2024 17:19:28 +0200 Subject: [PATCH 20/30] fix: check for message components --- src/api/util/handlers/Message.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/api/util/handlers/Message.ts b/src/api/util/handlers/Message.ts index ea673e50..14efa95b 100644 --- a/src/api/util/handlers/Message.ts +++ b/src/api/util/handlers/Message.ts @@ -140,7 +140,8 @@ export async function handleMessage(opts: MessageOptions): Promise { !opts.embeds?.length && !opts.attachments?.length && !opts.sticker_ids?.length && - !opts.poll + !opts.poll && + !opts.components?.length ) { throw new HTTPError("Empty messages are not allowed", 50006); } From 9f049cb9683e1854abe804a0afeae5e5dde677f4 Mon Sep 17 00:00:00 2001 From: Puyodead1 Date: Wed, 10 Jul 2024 01:53:16 -0400 Subject: [PATCH 21/30] update default avatars --- .../public/0c8138dcc0dfe2689cdd73f7952c2475.png | Bin 4657 -> 0 bytes .../public/22341bdb500c7b63a93bbce957d1601e.png | Bin 0 -> 4550 bytes .../public/4a8562cf00887030c416d3ec2d46385a.png | Bin 0 -> 4361 bytes .../public/5ac2728593bb455250d11b848a0c36c6.png | Bin 4494 -> 0 bytes .../public/7213ab6677377974697dfdfbaf5f6a6f.png | Bin 0 -> 4199 bytes .../public/823a3de61c4dc2415cc4dbc38fca4299.png | Bin 4380 -> 0 bytes .../public/9b0bb198936784c45c72833cc426cc55.png | Bin 0 -> 4209 bytes .../public/9d6ddb4e4d899a533a8cc617011351c9.png | Bin 0 -> 4471 bytes .../public/addd2f3268df46459e1d6012ad8e75bd.png | Bin 4511 -> 0 bytes .../public/c4e0c8300fa491d94acfd2a1fb26cea8.png | Bin 4251 -> 0 bytes .../public/d9977836b82058bf2f74eebd50edc095.png | Bin 0 -> 4503 bytes .../public/e56a89224be0b2b1f7c04eca975be468.png | Bin 4158 -> 0 bytes src/cdn/routes/embed.ts | 12 ++++++------ 13 files changed, 6 insertions(+), 6 deletions(-) delete mode 100644 assets/public/0c8138dcc0dfe2689cdd73f7952c2475.png create mode 100644 assets/public/22341bdb500c7b63a93bbce957d1601e.png create mode 100644 assets/public/4a8562cf00887030c416d3ec2d46385a.png delete mode 100644 assets/public/5ac2728593bb455250d11b848a0c36c6.png create mode 100644 assets/public/7213ab6677377974697dfdfbaf5f6a6f.png delete mode 100644 assets/public/823a3de61c4dc2415cc4dbc38fca4299.png create mode 100644 assets/public/9b0bb198936784c45c72833cc426cc55.png create mode 100644 assets/public/9d6ddb4e4d899a533a8cc617011351c9.png delete mode 100644 assets/public/addd2f3268df46459e1d6012ad8e75bd.png delete mode 100644 assets/public/c4e0c8300fa491d94acfd2a1fb26cea8.png create mode 100644 assets/public/d9977836b82058bf2f74eebd50edc095.png delete mode 100644 assets/public/e56a89224be0b2b1f7c04eca975be468.png diff --git a/assets/public/0c8138dcc0dfe2689cdd73f7952c2475.png b/assets/public/0c8138dcc0dfe2689cdd73f7952c2475.png deleted file mode 100644 index 3e8eeae966239718d268a633fad988660477fbad..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4657 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 R7Q6!jObpER%k|I?{|^icQZfJl diff --git a/assets/public/22341bdb500c7b63a93bbce957d1601e.png b/assets/public/22341bdb500c7b63a93bbce957d1601e.png new file mode 100644 index 0000000000000000000000000000000000000000..c8bf93d0113089e65b822bb4e3117e3a2a4061f1 GIT binary patch literal 4550 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 AegFUf literal 0 HcmV?d00001 diff --git a/assets/public/4a8562cf00887030c416d3ec2d46385a.png b/assets/public/4a8562cf00887030c416d3ec2d46385a.png new file mode 100644 index 0000000000000000000000000000000000000000..73426bcdeccfba19c366e3fbf848cae6e18b8560 GIT binary patch literal 4361 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 F_#fdIp#}f| literal 0 HcmV?d00001 diff --git a/assets/public/5ac2728593bb455250d11b848a0c36c6.png b/assets/public/5ac2728593bb455250d11b848a0c36c6.png deleted file mode 100644 index 9f137906bb118658aa801f164c17ba36018e8653..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4494 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 Ay8r+H diff --git a/assets/public/7213ab6677377974697dfdfbaf5f6a6f.png b/assets/public/7213ab6677377974697dfdfbaf5f6a6f.png new file mode 100644 index 0000000000000000000000000000000000000000..f1fa9f0bc6d78174ae6ec26f72f635133ec5f05d GIT binary patch literal 4199 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 SLCl{6z)0Urui}o|i~j>)J;D?K literal 0 HcmV?d00001 diff --git a/assets/public/823a3de61c4dc2415cc4dbc38fca4299.png b/assets/public/823a3de61c4dc2415cc4dbc38fca4299.png deleted file mode 100644 index 9b92bd2f36e3a6b9bc6dd2fd2e454480f8dbb180..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4380 zcmeHL_gmA+xBi4E!4L@|C95Uiw!+!DXmG0N@=o*1vu`IDc(wKS~UPV?j zNppmJDH&Viekrc(lyOm*iK>y{XI-_7f5NEWcKhKu8VJxS)0KB&gu?M_qEWO2+1YQ+ z1@A*wWL)R{TA}(98Sla%&y2)4u|`V&FGkhn>mpovdJwVUR&IWdJT=CzX&l=71X?wo zDm&H8i{Qj!U?g%Yr2RhdteX}w6~-(4@6gc5{|-%q#rcvi0T412d_Nj*KJ@E}+`;~im!WE2Au=X>{oLZVf#w{r1-(f*mKJa9eI zzi{&*(8@}r6GSot<4iQXD6_N*r;)_%q_gnebB8tAMQuViA26SnSb!H#6jp_X+DrTf zc2~IyCd@TvDb!_}($%Z8d8Y(8(cl>flff-yn0C#G zJ9KB;QJaR1emD}-XzA7XGpPy0r3Ba^IC&ERnLpZV{5MP+241^5FC-nEnlY1ID6O^n zb{dUU2h}OVh(F1!RFkvP3Mnotqlu_n0YPEQ8#w{H5Cj1I6yj%6;V6(t%ZmcYK3!cz zaWIoqunMDx+b1nr%WedA= z+-@;1z2xlMR&~jcXaWvYWS)27<8XJwFRsGf1OXi%%jNGZPDc)N=}s5oL4fiREg>Y@bBGZ=?Fdg1`pLrrvC$;5ucSEt z%0OIf*WQm^k{MP1j64LhRe+Y~)ZTZ4skom|7dL$?kShEDKmfx}c6zyP3PFO_HV)B- z3CY=i)FiL~Fgh16N!zyCkJe_0Wtqv1j?q`)O2C_m_y7xe`&UBCr4296z~2r*!?%_M z*&r)#QD1ugdf5K@Sj4cntjl04N06z%n>;FgEb@t(#_}xfg?|wRrp2~W5&(t5mbDlj(kE}Wcn$)?l-YKjTCg?WwI$*TD{*=(yWBL90&NTJrkpr??&m z;uXhl`>edg{XPAOgLO0(6Czp9tWlz!LX}QVirl_KUyag&p;OuS@G0r;plrNR;#-}M z-z7&elAw}!4B5#){?~}9SGeg!aA;~|8TL=fym4kwH0bk%st@GJl^?Mp#`&7_ z4<`~D{Y+YDK__47+#3o&rH8CLh4u0rJv3Bv0es_@Wb#pk-4seD#%pAYRA}k;!(*tY z`jK^X_8J&p%i2FsMWXs^SyRq{FLqv9SSK4lj?%7J`k`*>+_$KGv@M0Rt4FP@SPRwF z)qj6_oFW8HUpP3_39r#g1VeVr0z(2_Me98k^&JbQ)rHTW8_@_!@{8OM1gCf9=6Z&2 z`|t@VhT6fIQsXyh!^yZ{TD!9oU4%M(8B$lrGsK)H0&W*5cgo+J&6cJq_y@>UQYi`! zE-sXBx+aC9V@-qiH7m`nT#MT*h6aW_y8t)*pqWtN`mK_hUW2EF)6M^IFXDrb$8`J0 zXpt=2fF*_7ceYkhjxcmK+hUuVRGG9yTyoUrUxZ1`wfkTK(^~lQ<@Si7jlj?_otHTj z%*GE_0^J3uK|lSN(A&$ODjcAzTWAIF4!BGyh1Ch6K~$}0CxH3U1Qp1d z{qJzF;N>IlnEx@%rcJr&a}R~G-?9P)qMl0s zz{cPxL%#8Z;HfB-GH?#Tsq1H|^M3g{I8SYHc3;8ABksf9ge_kgiZT#`msE->NX&7RCN>2eWN);I zQ0`znP3C8qug8zi;y}Ezg5ch4gKDqG!pVZTCHEQW8A#hvZ}$fCvc9^pFE3c!T%OZ2 zL=lc+QFOI8jWnV-Dl2)I^ObMvf9EOVTAD$czLGKEbc|9EqmFl3*p`O~q){3s@%vTR ztyG>Kn5uH3(=V4vP6xO0CJS}(CdN_SXUdt8@Wb8977l0I@Glylfp}f0S6sdy*)N`P z`Yw7s^_=Lg53N>$MA+@wZUMy1*Zzr_glIb?w^VL;mbz&** zk?-v)SHSl>H)@Dfn>Y6gsgqp`Z$e>HoG5iz2K8E>i z{$V=vbZV)&1-@e==uf>m&KQ1nTnw47LlhkOfZY3^#V;NoQ+yn7NlE-j=9Ofz&Cxi} z=QGrTB$tuyaCuwak=?uN^lC3$?|c5h@XlB#DNgY|g?o=&NC)9;`X@dAZGt}j@GjKa zTBe23)^(rYK0!||-gu?e)2VWPvwDsmu6=+}<>wBVPH`JH3^9OeAx&JJ(;Y{%Yj z*W)ahdX-R9gIF9&D=re(;t2;DkUvXHF5-fw>l$8p7%2gFT~^?*qhK%o4>n!q_QIq$ z#51Gb%)|SCE$Yk<3FPp`buo+!J;>Bx=fu<5z%Q)LWu_4aO>Tjsxpv~74yuTUE0e(SYPO9YV@1Fd|Mg>t23Qk@ri5rRzV z_%E5YkIPZL^#ZxMUM+`DuKLet7O{E&%v=*TVBUA{qa>(SOvS>IuPax|#kN{paOGX| zjK}ttJK=Ci;s#$6Bc4rE;Llu4hLE%U) zhu#Z?VI}{#xn*vjpD^5|Y=X~-7-zVKI4+*`2-}rt#Cizc2UMTkI9+k~Y@30`M%KKv zsybzF2%dpyAySV$I{=Kc`%*;fy_*tjy0r~{+}vdoQp*cQGb%pxbrrN4hlgV2_T1z+ zvE2iV=iYs3YH_h`JG_ zJ=A02c7V)SS=;em4Tdf(@U%TykU`}r0si;uE6szDDVv+BgZTlCc29X+fMurReXp@qIpJpu?W9UR+8taCn{4 z`v|foqD{N(3dA80H1hOpN!xVyS63cX_jLe)&0h?`t3-OdO`fz;3*4v+Nx3z{=4SCe zO9bLGZ0E7rND5)hZ(q#P6EfTQXmt9F9-Hsv5=Ql5%U#tZ>4?^SkGTYmz7 z?VxCPPbXh%=|{4=SR1^mO^+c0F2X;M@egQRZkQ{n9MB7EPWWi24THI_uTs?D;kgz8JR^6MOI+H3gPsTup> zm)S+axAo$>F~f`aYh=S4*y8(Lv9JGf0iLu62*57+p~FOrZZDz(ruqpYh7l_C?izkR zV=rQ6ZYR~@<%PI?C Y85`u-fIly=zdHb912g?9UFVqp0N>i?kpKVy diff --git a/assets/public/9b0bb198936784c45c72833cc426cc55.png b/assets/public/9b0bb198936784c45c72833cc426cc55.png new file mode 100644 index 0000000000000000000000000000000000000000..367051ceb7bbfe748bf49f434ccee0b4832c52f7 GIT binary patch literal 4209 zcmeHLXIE3(7Cj+AsDcy;Eg&F8iu7Kkd!?v=pcDZwqF^XeLLd<2N)>}NQL1!8RTM-@ zr~)eWf}){=bObJ7C;{H~jrZ}rfABu+arW6~<&3@8nsd#W6K8E{%F4vY1VIq1xtY;b z2!eqr3}T=M7f1h64{%}hHFJ0XL2{zM2MklB7X(4q$Sd);D5Z?yJp5ETbjv4%rXXme9s&?0}zpAOhfBWX(jYbnuO2rv{9$aV6wEyrw ztD_@mZf*`ixdSmpMdxH>WLoF8Zbd}6Y!wc54SxH^YprAS#_aNCBQG!M*R{0+)ZlQE z5J5=qLr+hvNlI58l^Qnk^=pSmZT9|#s;cVX=;))aF5^V;gm4!9q)F_m?3=o}c5hY0 zky3eiIZ{BNb9~&9RwBWvtgNiGveMYu+1X4_OfVwG#+NgQ)Km`|}fF2FK0KhVtf z^zw@8z0I_|$icy3ZDT{5(Dm@`Ta~r-bz{%=F*kXnwSz+(x!$K^#`iDkc0)tM*!Xzo z%E~?3;sjZ3diKBS>Qs>|(GO0-LP9j+6B4$j+u)B0gc!fqV<{;qQPI)#ViFQAo>~?b z7MmFD$3OWuWm@?`QbcrhkK4%#nSGx3?p+KG)q4HGE zQE<>dwO&1jVWNmcVh#F&k`iYw?iVkyyxeb@gM^3a`}rwoYHB9s<_djTPft%5k&~0F zAU{?KL*%r1)Si`2)h`dIW#iz*UrvP?0P|79>mGX zd72#l#vSTUN=e}yT9*(LoBmRHGb1PG!}PRple3QzrG&@N&#$zstZlUXx@b%F+L|~0 zGz&{B?_@xWo+A@8^A&sh*yH2y$4{Po*l|k_o(w^#p~v+vUVJEisO2bcBmv%itDdYf z;o{^Z`0>-Hp^1sa{rwONir`&<3(vcEhp5m}<{38gZYaxO6%zQl-Jh+M@!~~$Ypedq z1u2l?-*t3waOhc;Y;T+KZAI6+ySp21<4oc7(_E^V>y8Q5?M0=f438c?T3TL?`%ZFo zlH=jy=TAG1pv6~I$bcx8R;f1!hbJ=PDU5x6eUj4BhCV(Q?Ck7p2wYsC=pR0qaB*>! zqUc)Nyfjo)im)tBZjj}Se}fHSQ;(OI_gyGOE;>3|UQ;tZJ6mv6G@IDeBmfHJ>Y&Xn z_f$8Nvk!^Cwj>3`fJ#|AJ3q;dIObJSQX+Qm^OXD@m#O9>qM~BED|sTJp~0(~DZ4@_ zF`|L{(lkz>>VA~YoZ;b#0Vs114@co}xQ|~?0qy|E&wWgjzO;zpjOl2DvhXnV$dxF& zHb6Q9Q&R*zJ^gf0W18d6RY%9iFJAE3SK9Sa1kdN3(&mNxKJ4r?8Wp9jEH0-1@#DwR z%1V2CJE%o~x&TPFfrm%2_#t!5=g*%@buu~3Sy~zMmlIh9Xv-@rS;3x{Ha21g7882H zADf7x$KOQ)aK?J;C1Zp)Z-dYs3?z@FqoeEj^r_nZB_V-GOiaAe_(m0+ zFD@=_?ECktI`LKVP`8-4xX8J4#=FQx55?z$!^01Qr*J$vIy&|@ZoD7-RbeOnA~Vyl zMfMr0!BMUXp&m_vtBc==I28Jg(#gpu2M1Vtne+$u3y4G}7u>Gx<*+>%PUhz@e>jM< zqwy`Rs9^CS9jRhNL!(+Y^n-#_b@!&DVkejl(md503smT*Gdz#@DKd8D-1X>*_Ssnx z5c#UEE@+mNkdR<#Xb6vwk5|sI=GW%lJ3->z-S#b#)6yOd=$#0Nii%>WdkWO>lau3{ z#>RB#rKJmIvyMYF1WutCw4-6_A_@vu>ZPHMviy9S{r&yD<&xZ*+S;gv1&`Auy)5)_ z(95>SKBO{~u^JLDDkdoAuP*Q#M>LVGkI*5g`$&AmoC99eZ5_HLFNWKLJ+Iz!0D*f8 zu{hAWuDl)58b;#3=Hp=ObcB~D2>2%76qmoRPOBbRb=#uqWj~Ifp+>-m^Bv`iXjuj4iirFZYe&;Fj))Ne*3JXcMD2NN`h*?RbW}J3V%Uk{86*;q@0{8 zEbZ055H!3{3nT5E*8sF>A&lgqWn_bRpr<=7P(EDvs7u0`S5gxib_ttJi~P?5t@uH4 z9v~CZ6oS@%{+tEfgy*}7Fgw2Y_QkNUFr(}5*4NfrHz+Pk&JQE?p=WYVniS52b}3m| zR!~1JEiIzym5bg`g3P;jaJHl+N&N7r-ogXJ?bp(9oXMNeYFsbwrt(qfA8* z1_MsUCMLT6-D@wPC!2V;jszw4y_3eG@aLU(fS&g0Qe(gwd{2&#k|L_g%l}AWJGpZ0 z+BG0`BLTViH97+kc%B<p$zOhkdV)1P50M9VO%heTzB1k;s%tm{9GDu5Hzu36m zE;?f=q6nRL_O2%8vFdA*SjYIK# zzK*T_8oDyq@pg6>t1?yMY{}?laT~IcIkw&>pIFNiy6lc-5T_Q#CniP%a$Le-z%wvrt%6wCv`Z{H2qw_1@d~W*Yg7(a_j{uNk_ zy^NW;`4t`d<2$m$zGii(PVJ}{Nf=vz=b=GV!ReRZSqtX{Y9`0VU#>Q5JG5t_W1 z?f2Ms3{n|?-+cc3`N!&KHQ&5Hk`(ATKiLa|cdO@z9vuW09a>pgv8{NNderi!rKRy* z4tW3R*#+qdy*z@C_YL;bkWN#EWeI0dQPIa=Q{TVy?T{*~s_g1ey1rzWQb1qEMB zrZ<(9F>-TrpFMFzqvgJn$tqeXAn;pVJT6NM>Gx+av{+^9lL>qH4ZYj5GW1cf-0%ab z9G%eUSFc{hY9j`2E4~D3eeT@3o{t|jDM5-#N?Sjkxwv_IvjA8d=-7+d0AC;}E87J+ zL}1{&(*=^Uh=ma(vh|_4G&z|gH8u6tpMTPQ`t->)ggv_L*6$)Z%3U8jj<&jV>EiwS zvXc=fxF*aNjhB~~>%K1#)8CK_iu(n!V@t?mJPq6244hI!_r#BGPKUl=C7QV{Ad<30B(TcCDB=%IX7Wm z{`)Be0e4l7ip=i>N-Kw2tfEtZCH<53M6Q2ss}yCR5FA- z1=~?jPUqfqs;jRz#x)lVdi(e!92^R< zpMf9@VCl+fvl0^%6B|OFh94{=H@ACaBy~l>>`s`jP;^X;E#W0thVU_LLPS(#KyhQ^ z&0U5|u`I3q{ihBN4r~YpnloFNnwpwCEXz3~@E2?xt>)q30oLR9!*r>@g%Z21O}rr} zucXBEv#m>jVy{rRJ_ZU33i92U)B%DbqDS2{H2T@YWnqMX)Zg74JUXP<5)AlOS64gM z)+$yMQaOd7>FJf~jg~`8H9}W@&k8UWV;Ur$d5lb+ s^AU`{r_E|6hJ@??fBcUej77jKQ%N*OncGD04FNJYwlu1`cW0$gKNQ-?)NyAW)WF1S{ zDqEt$Si&$E+t|&#)9>&5AG|+&Kj;48y1)0iuXC>JT=$)D$pS0LcZd%FAb8#sV+{a= za|r=FFwWrUSA3H*@cNkA`vY)F{%=8oU!sEm5Iue#V`vkcvoI1GY{SfLTkig7e$y}e zyc{oYYO2A-)F=p7kmnN;;hJYX`6@Y>Ed1}_fA6bD5qIC>s;**8RLUGo>p#B;YF4IJM*QCHsMjHn76GcPZ z#l>pZixCw;za5--^FIc}+Bwt{>|hCKLa8zh#zv<#bVI z)!Y&F`#9_5n2#_t<#U zbw=1&-;GQH#Pkv4+T}DfrH0@&Q)`zUD0~w`)=MnnT#2=m2BRg{$m*K z+%_>q+a=uU)3AB!3Ld$9w>wf92FVv*czk{^k!>_H*)8|B_S1OByT@fme8vy9?=9~$ zKGzz3je!kbz{BG@Ed&h25}h6S$g1d-zD29$ zXYq~0uzXp&{@6-{v#f+sQ|@5F*f+Y14Z)1=fO|eQgJgW}5)E59l`+{?6nL^^xxEsB z?pFhQKJ-tMx~$u=cBB04tyho-D}8cBFq#BE$%leua1aI ze*Q|b<==mO0-dyI2VU}=Tk%%P(1LF-Avb==SWWzL$c*Pe6D0{aTud|E%aFBj#aOnN z{p~|?zGr*3Kd(`VM3WwgE%SKRC0Y3%?i-bByBVw*qGVuhYdr4snVc{cBg;K89cp&L zod-7d=>*JeCTg4*sC=6E@+Ob@y}HuRZAx%?O`MksnX z6oY;IW!Uj@ugiyejlX>9s;|G)c*xc8kU<4fqu zTf(@`u3*08XPV!Dyg+-_8PS3#8%Uq!Opo6tTB$kxDOlR<7j3K8&jc^)$0(|S`ko8J zJ2_`@c{|`1MeP@kEl-tbP0GRIM4Y&BjRee2-asdGk^aaa+RJ`M=ZgVtLLTr6zmu zkR4)k7>Jq8x8$M+izn-5!n7twcPUNc(F&hPZA;Rye0co}?LyR--Y|(3?^?bBb{%}W z^?PJ`Z<4W+;~HvYaF$@r&Wuo2*PNei1#77%QDSb69Cds%9u<6M$bUd!Rx0}EE%~*z z2}5dncS-dT8eJ+1QCA6R=Veti-s|Z!S;}2{_@c4xPAS%Bi|Y?=8G8F8>$JtpDb&2# z+Mzt|`6em*B0P87tjT?)jL4H5zlef1ZXTGphF)OOg`8dyS985T>J{k1YRJ_X&a1`U z8CAP!K{BRw)TV9pCp8B7T8zc?i*A3NC=FkQj_l|LBbU6@KwR&IL{}TUKRiEucZT?2 zEb+c-8{t0gtN=&GF~cROmEAzt@qW!bI4wGoOZsz`%FHL%WJL7XH*U(K_9G~6u8}z_;|!F`@1@wWJ}1;*#sHPFj3P_ zBSZn<%pJ3w4q%k@ZgBLj)TDBOF#l_W@$p_rPn={^G1*!lcKqlHLL^R92KcL^_@7v8 z=f;@84Yq}ea;!pwUdY&is6Va!>FSv@@}=omUlJC8q5l@%w2bc;z78#d)V~3$g12CF zlk47xMIIKdhZ+2S@O1K?g!C`*q?{W+Y>iRM^DMSP>JXrPI+DTEoP)jjFW}s=3bMQL z!DdyrYg{3?1B}Dnenz<(puWUuhKu=G?42o{O_x5X+3=rkjU8Kvb8@tJjq>YCTyXui zXs_87gTrxA-tS!o@KyNgA?eghRSjm>p)SgG`+|cPF3`dPG$)9W16}NY zh4&~4QevSFq7jP+Vu_*q8V>fS-t8ykOTy#A+Sj*)3q6^PoLuoJnG`uzhfqMoJE&84 zT@Fn^Qu%py##wvZq0RZAVv6i#3a zC8WeXigYv4YD{Y9FMsL#ydm(E{llRh+1iFOtK+K{O-QJVjophNiBO&zyYhP@HGgj# z+-m=KXy?(j#=SBHkG!JDTw(Svrsme+D7mbdJ!+a@wxjc^r$!wM4UI4l`yJGZ-c{La zS<`B1`|af1FNOZW)T}qS0aW(g1yvg|KH*>U#A>g>cC&_lSUP3Ah)ftc`R4cV9>d){ zn>L5X9Z?6<0sGMNrr-B8LlZy2Sy>q5p1%Mk1>;1`aN}$W{@2uuKWBU)JxP26!(78t z{zCO;)8{F;5QjH0Y{#dRq!zuE{vg7;F0}pHk=o?S)dk%L;QVB-ie&FqjaU&5uG5*G)nrryJlj5^D{j_YcWRQyLp!91M^ zmCEL@0k>)+3|M<^l!0AR8+&}zT)aZo00X`}a9}Ee%e6^W8uLfXm>=p@m7-#Q>6HF+ zP?yVuo3hm0$ih|28mJE*4IO(R2lBU6Uef7P3TA_MlafL37@xscVj-UUc1Sd&@z|5N zcx@AukP+(gj#bW6Vo5;whj^YS+;dh+`9Dn40eQ;BiO-Kh%i8ZP;9rs~kJUbJ+QVR-U#;b_9~kC3O7hFmRFLA=gO$=*51ly1^PgF;3Ln zjI<)pri+9H>>(j%%Wx(_d5N z*IC#URKb?Yro}l4R=;Ibh|OLq!OcRCtKik5@g@gQ=VfdyEOAh!{`r1Zq&6>$LCpF7 zYQNXp7SRFuzbniZ#e&@*i(;wf3Npw|`vWtaI-&@aL57XS+ z>*tLA;B@%Yv_}8gE$jyHQE3M+@Q;&bX%P%w6p%MET7c)i(#}Ik$t7WF>GsahigVDi za~gu1DVbc-8Yax6Wp8xPa*l95(HT&;RHxgil2FbG=}iaJx!z2bld$;$;=fm-=R_Tk zAVI=(ef;VNa45E&IBKOIa{|K+Kr_eg^ts&QY1xb>uaR=Rz?FDjgZYKVVnnn$=Fb+I z(@N8iYiZF=4sk^v<{nj?AF0CG#a;}|=Fev~1VhBLO}}Twt0vdE0FV(Tb9#k1?u2)7 zW~6KdF+I&NStD=Qa$rw5UlJUXd5vhXea?aA3YXh(pf-cz-6TX)-~^Y*NcFz)z{7t# zrf*)C2oU-LWzi_;=1YyXV1~ILiH{Qu56eI5GAy+2o@eNyfb83%8 z4gx@PcrTRptXlU{O{-+>8}{c~TS7td5C8@{b#bXfKTGif)}|}jvLcA6*3mQbJLBdY zRhz7{S9dFi(~hUd3xS^S5BXImyzKO0A4|iV#4xy@#dv|KRyd$FY?myMh@sPOuRg{t z@IQO*Ipxm@L)@^jd>Y-mAn?cgHya;H5cm6NlwlJZ-j6(|rgsmbeUY=KJ@`dwj8v#Fro$%sX(M$>_82vSG**$^r_jFr=kx+uyw#IsHNteDB>^WiP`aSu9PL&wP6)0lM z6orkS2D=p~QR=!5CxMxS?O3#q?uaBfsUs%Rgu-4HQ5FT{SLSXGxQPfJM8l4XB}3%? gzy1#n<|84W57-Y4?tUHP{7C`lO)M~FMlLb`1Jsx1bpQYW literal 0 HcmV?d00001 diff --git a/assets/public/addd2f3268df46459e1d6012ad8e75bd.png b/assets/public/addd2f3268df46459e1d6012ad8e75bd.png deleted file mode 100644 index 62c599a7ac74890f7852146fbd8c1abbd008a277..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4511 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 asA!v19e0>|Nh$r03t)WNOut;$A?jZfA^@ZS diff --git a/assets/public/c4e0c8300fa491d94acfd2a1fb26cea8.png b/assets/public/c4e0c8300fa491d94acfd2a1fb26cea8.png deleted file mode 100644 index bd7afef2a8bc23feb6427fc452987c27cc73b64c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4251 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 diff --git a/assets/public/d9977836b82058bf2f74eebd50edc095.png b/assets/public/d9977836b82058bf2f74eebd50edc095.png new file mode 100644 index 0000000000000000000000000000000000000000..bb73cd99d47ec27d6a9f32b57a104ae711bf8b37 GIT binary patch literal 4503 zcmeHK`8(9_*T2UISzA6ua;*_R>9VC+%ZL$Xg%A|lIYh!Gkg zlYB)X6j>&+#MtL~_x$`k|H1c%`?}xfzV7$yI@h_+Ij`4Au`t7Ou?w>U0Jw~eFjfG- zpidZJV}Ulupl9yTb~M1qE*JoLslN*r_7oio0K(W9qkA>1aCtHkm$O+!S)&F&9=MhD z==}pAc{DG9eBxiBk5cwed}ty4&lBCskoHrsIGJfW3Fpbw<^-9}|6Tug44PJ8>zT@PqUxKg~E(RL(r2^H!oFhrSUqOu)|;n|4~% zos&0~Be!gOsj<%RD);W<;OrM8F^z;-*2rMRiPg7L;FCqf=rzGk3&ZgMVv#4~OVQo- zbzE+RaB*RhA#>h0wioqkKYYdB_{kG5f@ls!Fm<1LYk!87bjOwdyu*Xls$^&L{DQ>y zNdgT|j`!SXuv?-Oj4w&N}8pF%HrcVb4$wT7PYoWuP%Z>PL z7)XL)*ZjqH5?~AQ)@W-wo1&+c_s|IyHQn^fLEAE~G5oPO@x7BtkJ{ZjYydtAcE3ft+zwL>EjMWlG zb2xp5)og|B{w&o$v`P_Z<9vziCQc7?>BoSnILv|J8&hHHHCl(JU3gtZx0S7|2L*60VkmlZU~l=PJfcprrEiwgQUI=dl@i z?-=M~VN4{heke@e+ML4r%-4R3NOMAob@ogRd}-vtt-ZBOx!wi-IG@#qTO4UFdKsXq{UNwBdaM&2*nU~J~`TyKDdF5k*OCBUn9dJ%c$=tNLDz#sOC0u1!oZA--SgMfPdbdHMta579;)Q*< zi$P9soc2DLHl2MGTbaGN#7(~E0jxsph?HP7`L-Y-d%);Ob>>ba;CV{r5Qto3XPK5p zo;sbZk+8>g%$AdE>|QMX(_~RuN(z@gEd<$k>)x6B)P2#EnK+pG*(ozvMOj1DQqE+4 zH%$-#_ZHEu{D{e$8G4r_o{7LgyO8vEvnfAL5cb70rBL&m9J4dT-Gd3wNmz-VfqGeT zC@#IMXd4JN)$V=JDHlA{Ln0uSH*7H-cWX4RoeAyCF5?j=;7RjHH-S6M7XY4@?cHcG zY+8sAXJ-?lsP9Iid^Ev9ellB9 z18R)t%Ltd^y~`wq6H^KoK}dEal9NCy-$Z|Jk7A8QpK-{z=vP%rWBJOaA!i>ok3o%otYYW9?HjWn)-E1737__CVX7O? z{boMpXd;HbG=1|p>o-e9V}=!lyUW+#l2oC5JNMIOo8B$(%lOMqG~VL4(x&%Tjw$DU z{#99eFemv+cZQdBq;s0nBp}L^y9^x@gL2>a5fa@S(*VX3p5>i(q5LVY0&TFw$)NLK#bA&9HNk3^F zQJr~HD=?|tq@2l_xvS3b!KfBX_(QjQ;|Lj9U^a;(zs9BOB2W8bORK@^g^w!Ww!l$- zesEhso~sygOIhU)?aZu*5)8`SO;Laer-(|<59lbt>SVoP`UB{^3lfVo9i;R_634oekb+y4aRlOT9IT!BJx>*-9@={-?i<*T+8SU$ z+v=N_szHU&mCC@G%aQw6$)S9v!>EQ^30voQg$@Z25CQ=dehqOs;u1e^E*BWr4YvqZ zS@P&i$0?l4f98M0!>KwX3J{14lp6mnW-?r%!p4S`5uSJ3p~G{>_cpp|HS5I%Qi=0v zh`U#*H_F|XhlTV8h4~Sn)-g??WtQdqozkQ7_D8)jA-m>^SNNR5y;oS4f}J=FY!9+` zLn5;kF8V43lyxORRkx4{%6xZ?_yyu(9K4jduUsKG@Lr!U7VxGLEaN-O&u;ELJ+~ z)c{&Fse|WQ2)r=qot){TC_j(Z6+})3g3!f^OaFML)&2PY${a{Nb)npjDY~Vt80Q2K z#Yk8Sy>4xwF!4KW{W7Gu{@RA%a61=DDXLL8^)8#v5=J>||2%<3aw~Z>B)v4@E&w{X z`FkX6=_SO}-sy>^A0&!}o+&uK7rKayUB~!PHXsy3GqBZh{^#_uKGS_C4YXW0GkMty z`{&_#5=A2YvY3XnS4?I;gha{R3rW{OjvjVvL4TQC1y*MY5HWWuSCo2*(3AnS?6?)B zoa6ieEKIBuRuH{J()BP?I$K`~hYp_V&l7cE2hkVhNdb5H#=qE*^s>U1zo-?he^H0G zde4)vAEB;bRf8RBcd3C;rCj~}4Di1nLqr6fgHqblD|ZimUxwWJ04biK-E0vE(n{iOroFLOSRCH1o$7th|7bmB0f0$c4zHa~cIc|> zvdGHcnFxY6!vn%fLx+8I*aHv0dj|iGv@iPM-n_P?3l@_>Az#d%jVNQqszt1Zge?>G za%dKIau}r{yOae9!_wRM2np(R%H2aIEESz&Q21;PQWu* z7;QaJiZi`vGoj1mu%Hn7qZ^FamjbAhBS9Ftdht8(q`w}qJ#m4rFiNSq&wg^)Lcxln ztq0K#PMiKLzdynw6(-0OIU%%K(hAyd2fOeY;L@cWWK+go`a-i1r)$ULu@?MAZWee3 zj3@y-zCVI0s7qK2xwUW<>WXkVEZws!=iV&kw-m&-S>kQ+voqWo+rz&zG`C)@bgt*# zb%>u!6*|B1mE112r)o=l*uRzYeF7#o;jUg|l={SOxS B-10NTG;XnUJA|4_QejRJ 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 Date: Wed, 10 Jul 2024 05:08:11 +0200 Subject: [PATCH 22/30] Add /policies/instance/connections --- .../routes/policies/instance/connections.ts | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 src/api/routes/policies/instance/connections.ts diff --git a/src/api/routes/policies/instance/connections.ts b/src/api/routes/policies/instance/connections.ts new file mode 100644 index 00000000..dc557853 --- /dev/null +++ b/src/api/routes/policies/instance/connections.ts @@ -0,0 +1,45 @@ +/* + Spacebar: A FOSS re-implementation and extension of the Discord.com backend. + Copyright (C) 2023 Spacebar and Spacebar Contributors + + 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 + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + +import { route } from "@spacebar/api"; +import { ConnectionConfig } from "@spacebar/util"; +import { Request, Response, Router } from "express"; +const router = Router(); + +router.get( + "/", + route({ + responses: { + 200: { + body: "APILimitsConfiguration", + }, + }, + }), + async (req: Request, res: Response) => { + const config = ConnectionConfig.get(); + + Object.keys(config).forEach((key) => { + delete config[key].clientId; + delete config[key].clientSecret; + }); + + res.json(config); + }, +); + +export default router; From d56ba868519c673c59bb7074af0c595f4fe5cb47 Mon Sep 17 00:00:00 2001 From: TomatoCake <60300461+DEVTomatoCake@users.noreply.github.com> Date: Sat, 13 Jul 2024 06:09:07 +0200 Subject: [PATCH 23/30] Update schema & add response type --- assets/openapi.json | Bin 581490 -> 582010 bytes assets/schemas.json | Bin 19250985 -> 19384340 bytes .../routes/policies/instance/connections.ts | 2 +- src/util/schemas/responses/TypedResponses.ts | 10 +++++++--- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/assets/openapi.json b/assets/openapi.json index 0a211d3c30e6fecaff7eedb22937a8e90e8364c4..a6f5d962c8e2509102bdfbe40c2127cc106286ad 100644 GIT binary patch delta 168 zcmeygPx;p&<%TVcH*BXXoMcj*?rFy;HhsZ&M#YS~8?duY*HdDYm_FeeBm4Ai z_ZUqkC&)-mpP<9YF}+5Yk#q9mWs=h$*fX-WAFyWxVkRJF24a@&2kco51*ZGCuyRcA z_hsdr?tF{Ie48h$9HX#veqLT`a!F=>UNMlFmYH5!H2uO>j{OAeY(C9 zqxiI)Osvzr?lGE84`^hRnQm~Ck*!_do)L(dfS4JGS+?ujvqlKC{|saWVm2UV-~Ka@ Hqp=?VtNSNr diff --git a/assets/schemas.json b/assets/schemas.json index a77f86b6771c9397acc37934a29a2205f1064d2d..c5a5bedd07b2152b4e838a52b78d7044697bf592 100644 GIT binary patch delta 4680 zcmai%dpOm19LJxp`{9s^ZjPjm+mUqB1yR|e&J#kY#U^T;q!JamRq7kZ&dDXeEh{r3 zD|Snt9OZYmwa3(HE{mRQmPeaRIkTQxql5kM?63OR-{*DS@6YG^d4Dgz%8^1|!I@%S z##M62o5?WU?!(OU9O@{X=c`Y<%;rFsnT1HeIG5|_Gsf0rI^DcW3pVf4wpoC&lw-lU zTsImgf*$KZ&}03}^Dzyke~*zqW0|#@M^$z_P}vzq*3q!3~ese;b<@_wVonmJohm?sI#LU^qgL&be*{bFR;ew|O%r63~sW ztYPD;`2j0YBGg|9q5d{$ZzyykJTyPg7V`7#s&JR#HhUOub0|R9mHN(f1mBqp196w| zZB7urZIKJE;eXB<{Ld{GB8$$&oFnwpiz*$zz3JKDHLh-wFfsKO%b(3TUYz6*&{-^;^y*{z@mxD~XM;4a4tBH?&J)CGK( zb++$<&i38=oY6XX!f4LW;2og2kn-1r}Z8~^+yghqS;G~(iixXbyRPvCq`NdZbQ9KoX+)u*6QmA=A@spVgU zT7LQac+1^eE1-Mpr4`7Oxf`_k{$&H&Sy&03g`eRV%Fu+{ zcOl{Sk6AdO;5CDS*K!&sMtxdg)aR!Lw3z&Ko)MMh-UC@~n?I^EPL(&eLwWQ4fXON4 zln0=k(yAKtYX(k;?>+?a-LB&}kYzjpqi?czQda z&T?5LA*`%Yiv*)*x4fiJo3JH)I-~(TG~_mpdW5xc)F(ZQu_Z6QP-jStpL3*nv7TQiXaJk1;y(aE&=(!!zbb(Yb`(KWasW@fJm%)`S&#&L`NTOC*qYr7a+ASDKLI MB8CeDT863r0tASE>i_@% delta 6520 zcmb7IYgAO%6<&w;46i%#mT`CuqX=CC1mzV78W*ohI-(#J6-2NyCIW2?k%FKohk@dN zLpU*M7&<{HDq?Bk#=>&YA_Sr|5<_)i0|{!8wusbdQN&)Dpt1SOx5_hOiP;HEt+x5{Dp2V?W5bze3l)!8^|>YOERw87{gG#C{Gh-rVO5%gyo zzu|>Kr=Bu_)KjK=acIZ;X5e_={ER2YHj948o}*Hk0HiWurVK-&BiWWPl5G`+lEZkk zkbTo0?|H&qq)9hf!HyT0y0Pk`wG!5SX}gGWXRLucV{_93ofJ5v>_<5`mqlB?VSGu&dpi2u5L%E{zwh)lFg(4?nXetbb zrosbo1x%JlK(ahC6O|`wo%04*=R~F8&>iR2LC3lEQrrrZ&%6opnGN|U+l)tBQ?tNm zFbj-{Ls6(MFBWupaW`>^>2HsR{`Q{_;cQRMY=o(qgd#sw@1zxOvY@@M{{nhnS486+ z@DxZZOneK4F6-KSp=--Lsv+yTHk;6-=Sh(CJXwvhzQ_m! zdme{!ttF&`(9!7$7|`v`a`g>zF3NCX4dqz zrIbyZKrqX>TVlbc?QEPE&qDr7z;eB}xc>CTu`%y0_WYMb!-Hry8Mn>eR3B$!0vojBW^Sh7G}g^hY%_ z?aOb0zWmdXICM(K8A$0ktMa1j0n{d?J(Zo%Q`uF8Yl%Il zLY5o$?j>P&2;&l!9Md*&V)oVdN+)e@u{T++u@!A)m)^EG$Dw`agG}ezVZ3rU|HOdVo}tac>eb z?)~c!PRVQ1|G;a~DP#uCc0UBO-P4azyOr{@3JFa!H^MNZMDynV3wiU83vs%mBA!50 z#8YHW918yj4u!KvQMMO{nq8O`IkU*|?_xAuiz!X%dpTj#~GO z4@F36_{&ZjPH=TlyIeFTdY6kPBpG$ys;|tN68)7~Gt!6Jvg(Bgq5e*&fZX@T)K2YC zE+l$~a!cZZ3R!))--_rD_gj-Fg#MpiMryIpmgvPoj%-3i5h+$*j}sC7^|)n3iNFVl z)fFl`qOVZdlebW1R{MV8K=i&}IFeSJeP0V_9&h17wxaNCSm)?$IIHW0Hiie$)GAkJ zHs&Vq()!1H5echqb92y)MM(7W3Nc9~OFpcF#Oj4tr@p&<1(`+Eg3prGfQ0C+2HZ#x xE{cU4mii?BFI0b0;7MNKQu`p*i|8N3O35q^zoy)q=+~6XNDV^NYO#^9=>OhMP*4B> diff --git a/src/api/routes/policies/instance/connections.ts b/src/api/routes/policies/instance/connections.ts index dc557853..37c20a37 100644 --- a/src/api/routes/policies/instance/connections.ts +++ b/src/api/routes/policies/instance/connections.ts @@ -26,7 +26,7 @@ router.get( route({ responses: { 200: { - body: "APILimitsConfiguration", + body: "APIConnectionsConfiguration", }, }, }), diff --git a/src/util/schemas/responses/TypedResponses.ts b/src/util/schemas/responses/TypedResponses.ts index fa169c25..14067844 100644 --- a/src/util/schemas/responses/TypedResponses.ts +++ b/src/util/schemas/responses/TypedResponses.ts @@ -1,17 +1,17 @@ /* Spacebar: A FOSS re-implementation and extension of the Discord.com backend. Copyright (C) 2023 Spacebar and Spacebar Contributors - + 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 by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. - + You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ @@ -104,3 +104,7 @@ export type APIGuildVoiceRegion = GuildVoiceRegion[]; export type APILimitsConfiguration = LimitsConfiguration; export type APIStickerPackArray = StickerPack[]; + +export type APIConnectionsConfiguration = Record; From bbaef373f95854ebde96296e764c5d7af9aa8e0a Mon Sep 17 00:00:00 2001 From: TomatoCake <60300461+DEVTomatoCake@users.noreply.github.com> Date: Sat, 13 Jul 2024 06:09:56 +0200 Subject: [PATCH 24/30] Run prettier .-. --- src/util/schemas/responses/TypedResponses.ts | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/util/schemas/responses/TypedResponses.ts b/src/util/schemas/responses/TypedResponses.ts index 14067844..8214ff7b 100644 --- a/src/util/schemas/responses/TypedResponses.ts +++ b/src/util/schemas/responses/TypedResponses.ts @@ -105,6 +105,9 @@ export type APILimitsConfiguration = LimitsConfiguration; export type APIStickerPackArray = StickerPack[]; -export type APIConnectionsConfiguration = Record; +export type APIConnectionsConfiguration = Record< + string, + { + enabled: boolean; + } +>; From c4469a53e75c9e8d95fed46437646b8df4c71ae7 Mon Sep 17 00:00:00 2001 From: TomatoCake <60300461+DEVTomatoCake@users.noreply.github.com> Date: Sat, 13 Jul 2024 06:45:06 +0200 Subject: [PATCH 25/30] Move route to api/connections --- assets/openapi.json | Bin 582010 -> 582218 bytes .../connections.ts => connections/index.ts} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename src/api/routes/{policies/instance/connections.ts => connections/index.ts} (100%) diff --git a/assets/openapi.json b/assets/openapi.json index a6f5d962c8e2509102bdfbe40c2127cc106286ad..2788cdb08bb2d9d7ee2a458cbee2a0f133cee203 100644 GIT binary patch delta 86 zcmV-c0IC1_!XwJWBY=bfgaU*Ev;_Pam+DXj9G9No10j52y{22td{22v{HHZ08 s1&8@j2DkZ92a`3I<=F(#mk_lC`FEi8W|+ask|wns{_cAHM$;K3?5J-e0Ne7nIL7CFZ0PVMYx hrWbgyIEL)52>_8x9vA=s diff --git a/src/api/routes/policies/instance/connections.ts b/src/api/routes/connections/index.ts similarity index 100% rename from src/api/routes/policies/instance/connections.ts rename to src/api/routes/connections/index.ts From 0096938d363fdb9c9b5dd929f6f07a7dc9a5c87b Mon Sep 17 00:00:00 2001 From: TomatoCake <60300461+DEVTomatoCake@users.noreply.github.com> Date: Sat, 13 Jul 2024 13:58:04 +0200 Subject: [PATCH 26/30] Support proper "animated" property for emojis --- src/api/routes/guilds/#guild_id/emojis.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/api/routes/guilds/#guild_id/emojis.ts b/src/api/routes/guilds/#guild_id/emojis.ts index ef28f989..649a748e 100644 --- a/src/api/routes/guilds/#guild_id/emojis.ts +++ b/src/api/routes/guilds/#guild_id/emojis.ts @@ -1,17 +1,17 @@ /* Spacebar: A FOSS re-implementation and extension of the Discord.com backend. Copyright (C) 2023 Spacebar and Spacebar Contributors - + 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 by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. - + You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ @@ -132,7 +132,7 @@ router.post( require_colons: body.require_colons ?? undefined, // schema allows nulls, db does not user: user, managed: false, - animated: false, // TODO: Add support animated emojis + animated: body.image.split(":")[1].split(";")[0] == "image/gif", available: true, roles: [], }).save(); From 2f679fda5dd66999fb4f0246a73bf662aa13fd2e Mon Sep 17 00:00:00 2001 From: TomatoCake <60300461+DEVTomatoCake@users.noreply.github.com> Date: Tue, 16 Jul 2024 17:44:39 +0200 Subject: [PATCH 27/30] Support apng & webm --- src/api/routes/guilds/#guild_id/emojis.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/api/routes/guilds/#guild_id/emojis.ts b/src/api/routes/guilds/#guild_id/emojis.ts index 649a748e..f3f0fd8b 100644 --- a/src/api/routes/guilds/#guild_id/emojis.ts +++ b/src/api/routes/guilds/#guild_id/emojis.ts @@ -125,6 +125,7 @@ router.post( const user = await User.findOneOrFail({ where: { id: req.user_id } }); body.image = (await handleFile(`/emojis/${id}`, body.image)) as string; + const mimeType = body.image.split(":")[1].split(";")[0]; const emoji = await Emoji.create({ id: id, guild_id: guild_id, @@ -132,7 +133,10 @@ router.post( require_colons: body.require_colons ?? undefined, // schema allows nulls, db does not user: user, managed: false, - animated: body.image.split(":")[1].split(";")[0] == "image/gif", + animated: + mimeType == "image/gif" || + mimeType == "image/apng" || + mimeType == "video/webm", available: true, roles: [], }).save(); From 01ca7b77360c1ead0961815b2c73bbe091c3e06e Mon Sep 17 00:00:00 2001 From: Cyber Date: Wed, 10 Jul 2024 20:03:30 +0200 Subject: [PATCH 28/30] feat: badges --- src/api/routes/users/#id/profile.ts | 5 +++ src/util/dtos/UserDTO.ts | 2 ++ src/util/entities/Badge.ts | 35 +++++++++++++++++++ src/util/entities/User.ts | 4 +++ src/util/entities/index.ts | 1 + .../migration/mariadb/1720628601997-badges.ts | 21 +++++++++++ .../migration/mysql/1720628601997-badges.ts | 21 +++++++++++ .../postgres/1720628601997-badges.ts | 16 +++++++++ .../schemas/responses/UserProfileResponse.ts | 2 ++ 9 files changed, 107 insertions(+) create mode 100644 src/util/entities/Badge.ts create mode 100644 src/util/migration/mariadb/1720628601997-badges.ts create mode 100644 src/util/migration/mysql/1720628601997-badges.ts create mode 100644 src/util/migration/postgres/1720628601997-badges.ts diff --git a/src/api/routes/users/#id/profile.ts b/src/api/routes/users/#id/profile.ts index eecec0f3..db0922d6 100644 --- a/src/api/routes/users/#id/profile.ts +++ b/src/api/routes/users/#id/profile.ts @@ -18,6 +18,7 @@ import { route } from "@spacebar/api"; import { + Badge, Member, PrivateUserProjection, User, @@ -98,6 +99,9 @@ router.get( bio: guild_member?.bio || "", guild_id, }; + + const badges = await Badge.find(); + res.json({ connected_accounts: user.connected_accounts.filter( (x) => x.visibility != 0, @@ -111,6 +115,7 @@ router.get( user_profile: userProfile, guild_member: guild_member?.toPublicMember(), guild_member_profile: guild_id && guildMemberProfile, + badges: badges.filter((x) => user.badge_ids?.includes(x.id)), }); }, ); diff --git a/src/util/dtos/UserDTO.ts b/src/util/dtos/UserDTO.ts index a24c8d96..17e4435f 100644 --- a/src/util/dtos/UserDTO.ts +++ b/src/util/dtos/UserDTO.ts @@ -24,6 +24,7 @@ export class MinimalPublicUserDTO { id: string; public_flags: number; username: string; + badge_ids?: string[] | null; constructor(user: User) { this.avatar = user.avatar; @@ -31,5 +32,6 @@ export class MinimalPublicUserDTO { this.id = user.id; this.public_flags = user.public_flags; this.username = user.username; + this.badge_ids = user.badge_ids; } } diff --git a/src/util/entities/Badge.ts b/src/util/entities/Badge.ts new file mode 100644 index 00000000..9535e207 --- /dev/null +++ b/src/util/entities/Badge.ts @@ -0,0 +1,35 @@ +/* + Spacebar: A FOSS re-implementation and extension of the Discord.com backend. + Copyright (C) 2023 Spacebar and Spacebar Contributors + + 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 + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + +import { Column, Entity } from "typeorm"; +import { BaseClassWithoutId } from "./BaseClass"; + +@Entity("badges") +export class Badge extends BaseClassWithoutId { + @Column({ primary: true }) + id: string; + + @Column() + description: string; + + @Column() + icon: string; + + @Column({ nullable: true }) + link?: string; +} diff --git a/src/util/entities/User.ts b/src/util/entities/User.ts index c6582b00..c929039e 100644 --- a/src/util/entities/User.ts +++ b/src/util/entities/User.ts @@ -49,6 +49,7 @@ export enum PublicUserEnum { premium_type, theme_colors, pronouns, + badge_ids, } export type PublicUserKeys = keyof typeof PublicUserEnum; @@ -231,6 +232,9 @@ export class User extends BaseClass { @OneToMany(() => SecurityKey, (key: SecurityKey) => key.user) security_keys: SecurityKey[]; + @Column({ type: "simple-array", nullable: true }) + badge_ids?: string[]; + // TODO: I don't like this method? validate() { if (this.discriminator) { diff --git a/src/util/entities/index.ts b/src/util/entities/index.ts index aa943dca..b2356aa7 100644 --- a/src/util/entities/index.ts +++ b/src/util/entities/index.ts @@ -20,6 +20,7 @@ export * from "./Application"; export * from "./Attachment"; export * from "./AuditLog"; export * from "./BackupCodes"; +export * from "./Badge"; export * from "./Ban"; export * from "./BaseClass"; export * from "./Categories"; diff --git a/src/util/migration/mariadb/1720628601997-badges.ts b/src/util/migration/mariadb/1720628601997-badges.ts new file mode 100644 index 00000000..af298e42 --- /dev/null +++ b/src/util/migration/mariadb/1720628601997-badges.ts @@ -0,0 +1,21 @@ +import { MigrationInterface, QueryRunner } from "typeorm"; + +export class Badges1720628601997 implements MigrationInterface { + name = "Badges1720628601997"; + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `CREATE TABLE \`badges\` (\`id\` varchar(255) NOT NULL, \`description\` varchar(255) NOT NULL, \`icon\` varchar(255) NOT NULL, \`link\` varchar(255) NULL, PRIMARY KEY (\`id\`)) ENGINE=InnoDB`, + ); + await queryRunner.query( + `ALTER TABLE \`users\` ADD \`badge_ids\` text NULL`, + ); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `ALTER TABLE \`users\` DROP COLUMN \`badge_ids\``, + ); + await queryRunner.query(`DROP TABLE \`badges\``); + } +} diff --git a/src/util/migration/mysql/1720628601997-badges.ts b/src/util/migration/mysql/1720628601997-badges.ts new file mode 100644 index 00000000..af298e42 --- /dev/null +++ b/src/util/migration/mysql/1720628601997-badges.ts @@ -0,0 +1,21 @@ +import { MigrationInterface, QueryRunner } from "typeorm"; + +export class Badges1720628601997 implements MigrationInterface { + name = "Badges1720628601997"; + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `CREATE TABLE \`badges\` (\`id\` varchar(255) NOT NULL, \`description\` varchar(255) NOT NULL, \`icon\` varchar(255) NOT NULL, \`link\` varchar(255) NULL, PRIMARY KEY (\`id\`)) ENGINE=InnoDB`, + ); + await queryRunner.query( + `ALTER TABLE \`users\` ADD \`badge_ids\` text NULL`, + ); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `ALTER TABLE \`users\` DROP COLUMN \`badge_ids\``, + ); + await queryRunner.query(`DROP TABLE \`badges\``); + } +} diff --git a/src/util/migration/postgres/1720628601997-badges.ts b/src/util/migration/postgres/1720628601997-badges.ts new file mode 100644 index 00000000..f7b9958b --- /dev/null +++ b/src/util/migration/postgres/1720628601997-badges.ts @@ -0,0 +1,16 @@ +import { MigrationInterface, QueryRunner } from "typeorm"; + +export class Badges1720628601997 implements MigrationInterface { + name = "Badges1720628601997"; + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `CREATE TABLE "badges" ("id" character varying NOT NULL, "description" character varying NOT NULL, "icon" character varying NOT NULL, "link" character varying, CONSTRAINT "PK_8a651318b8de577e8e217676466" PRIMARY KEY ("id"))`, + ); + await queryRunner.query(`ALTER TABLE "users" ADD "badge_ids" text`); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE "users" DROP COLUMN "badge_ids"`); + } +} diff --git a/src/util/schemas/responses/UserProfileResponse.ts b/src/util/schemas/responses/UserProfileResponse.ts index 26e7e3bc..7b63542e 100644 --- a/src/util/schemas/responses/UserProfileResponse.ts +++ b/src/util/schemas/responses/UserProfileResponse.ts @@ -17,6 +17,7 @@ */ import { + Badge, Member, PublicConnectedAccount, PublicMember, @@ -52,4 +53,5 @@ export interface UserProfileResponse { user_profile: UserProfile; guild_member?: PublicMember; guild_member_profile?: PublicMemberProfile; + badges: Badge[]; } From df9153f5ba31af005607cd62db67dd4438a9ca7d Mon Sep 17 00:00:00 2001 From: Cyber Date: Wed, 10 Jul 2024 21:14:59 +0200 Subject: [PATCH 29/30] feat: badge-icons cdn route --- src/cdn/routes/badge-icons.ts | 40 +++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 src/cdn/routes/badge-icons.ts diff --git a/src/cdn/routes/badge-icons.ts b/src/cdn/routes/badge-icons.ts new file mode 100644 index 00000000..04e96f2f --- /dev/null +++ b/src/cdn/routes/badge-icons.ts @@ -0,0 +1,40 @@ +/* + Spacebar: A FOSS re-implementation and extension of the Discord.com backend. + Copyright (C) 2023 Spacebar and Spacebar Contributors + + 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 + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + +import { Router, Response, Request } from "express"; +import { storage } from "../util/Storage"; +import FileType from "file-type"; +import { HTTPError } from "lambert-server"; + +const router = Router(); + +router.get("/:badge_id", async (req: Request, res: Response) => { + const { badge_id } = req.params; + const path = `badge-icons/${badge_id}`; + + const file = await storage.get(path); + if (!file) throw new HTTPError("not found", 404); + const type = await FileType.fromBuffer(file); + + res.set("Content-Type", type?.mime); + res.set("Cache-Control", "public, max-age=31536000, must-revalidate"); + + return res.send(file); +}); + +export default router; From d3ece937e6e6e476610fc1d7eae085727d01ec95 Mon Sep 17 00:00:00 2001 From: TomatoCake <60300461+DEVTomatoCake@users.noreply.github.com> Date: Wed, 17 Jul 2024 12:31:09 +0200 Subject: [PATCH 30/30] Make channel ID optional when replying --- assets/schemas.json | Bin 19384340 -> 19589397 bytes .../#channel_id/messages/#message_id/index.ts | 9 ++++----- src/api/util/handlers/Message.ts | 8 ++++++++ src/util/schemas/MessageCreateSchema.ts | 2 +- 4 files changed, 13 insertions(+), 6 deletions(-) diff --git a/assets/schemas.json b/assets/schemas.json index c5a5bedd07b2152b4e838a52b78d7044697bf592..00f86b3604f19db3f1eb55db5e1432de30d7d2a5 100644 GIT binary patch delta 23218 zcmds<`A<|=6vy*`fq645GpvK)Fvu=Yz$l=A0yY*&TT#KKVgVHwssgoYRjA_@u~r>B z=!r395Lt>FNLp@HWY8jIKn2kdQ!8K*V@U+mKtxe`hex;n;GX_C%MYJ?-}jw!?)TpJ z@-;gCSld~?(yLpvB5l>0bU6B5+5mL5dl>fjcVv_Pj?Z6Nd zsPV6Wel-bNmhPAjs!Y#R$Z9b2Jl6G21kqM&E^F%+ZXv3W!&4@k#-^=;QzI)bgKC+3 zI%qlr{a_%>ZW@g42^2wlj>zk{wWHSfqa~zDZJdn%5P|GO$OK(il$eu)y7HnMDJ--y z@T6&#$+KD{tjQ&2j(QBNO*~ONF<*j0*A^Z=+F;KUPjBAtItFpuc+#^@+KEEkm%m_8 zw2>!ay*5cG6s4@elWjdvlz~PbD65E!WY}9_5%>HV$I+`uOqKn6XT9w^ z8%Yx*SvLMASn4cgwbY&F-MM%Oy6}7%sQUd>pe~EHhPr)KGM&1~k~0I1T<)M%ivr<@ z+jb8au<>69I+=ecQC~}bR)fUs1xJJKB5Bk>SuKd`oe)1BvL1CvL9-)QuI-9aLRd!V z$E5$)kQ6LUrgW;z4VISmxR3z%sm(~dBIsX~5;|S-U;PQyKk;WIh7YO;M>CnW_08x) zGU$;-K~Z*CSgkT=S+LJKP#klznfbelQa17MCS;D3M825qj6zl#tWjW76s$B{J)Ir5 zoBbh=8o?L@SH-K@*Hsvv`(At)(8&A^HpU7mIrGJ&A#&azl3|Td;I~Lvt7{gXM}m61 zW}z8LdXqF0$vrm48xgU@m;L%B)C7y1PpXi3fh@n0EJHGO|0qw1!IG&A#imsvv4HNk z>0(Ywl6J3*MUt$Li28IT`%|q@4BpDt{)EH{WNAW%If{)}ny{MYuit>hulDU5cOe-P z$#hlr4HSMg@UXw$Wb*M0X}C6XuhJNzl7!Svttj9ddEM1KS58cB>Na1*MeNtP)eOnx zsH>YR=d4JFa=R1>F*)>Ujtl#&(aw8XdFa#UIKY4z2_uCCU+qNEIB3x*yDOy|EtDEE zAFIVMU}vou+kl~;=$?RAqRU^OWYFc6Xiq;WwKDl4;opVciMC|pWAzaGc{{yESxC z8Bd}!3uoY?4yY(PgUZZ1`-&Yg)ig99TfuaTByQ^2JcQ-r5O{%+Ig@ zS%*1K&ILzZWk0480+n@=x(XzhgVfBup2vQBR;lY79x~saX-L`3lS7>igX}w1VD(cP zd`08B(r2WdK{YSN9qQ(VyFo&at@}R*{Grw|R|T5A`ASgv@iLQMe$6;#ec-S4eM+7#}Vx7N@t3jJb9S< z#FG7I>x7v?Q~DH#2dJ*AdwTuY_kf^lsOK{@HH%-_U&wwAC(P?frO&@?N3z)a;@wLu zYYR|Ej9QTRs39LLH<%*lRWSRkW2S}bVYvckc0c++D=Qa~C0AazVHp$e43CJ}U&;$5 zms%LhNULAIo#Pbj+jneztarX-%88Kdd+4tZi?}W9hn9k}#s^YvS!;tcZA|H#3t?Ap zpyFRCn=$k@zIITXz1&_%+kyjZ7mLTS@cjW?0x{s|2Py>tKo delta 7258 zcmbW5eNdED7{%vxb{8(lvcQ6Zd@N$fr`k%W2!^6CmLZv81lnc^WuuWI)EFZoX$^rS z$gL?_s3eR~$mEisOQV_^g=QtbQNL^0cQzaL4Vj^&1?o>SSm|~}XGCG+3+c4F^4&<*m*er5Kg$Zq zZY8v!My8;4DN~);{q+;Nj)6GixQhXW){QC>P$jzNLt6zMTH;RF#|wy46ROGa!N<`g zOnKJM8zE~vS_m6bt6oH*+C)bmBukS}aiXJ~T`g1Fp<=9Nz-9a>kYbI;8NxOPySg@_ z(DE%)!m;w+IRj~Q5q88%qYEw!V)T{1!3lSBShWyO#%wbGI!7FaQ`Tv z6EuUNZRA_sjzFL~Gs84(!Iy!h;gFHAQx3D*fzA=oORKd0gboK(2hda(Yjt5?geR-l zX{%0Hz6v56->MKfrcTuV*QH!HmOk)z(9q!sr9JEWC$tBcC)`gfVd*jR9$;l~Xm;NG zOF-Phu(31335LpCBduU4`ISYTXs^->e@5Fe+5W|@upB4lF!W`}(jCCo5D{M5`s{XC z$+PLXpwkw2XYIARHo|NiKWuU%Ow^*6v7SK`k4 zsxsXGjaiO2+6k+_z0HU$a7gxgV1- zX99a&Kt1}r3cwR@)n5o((!YBm=82!p)q#7mu<|&xDy^s-D35#MP~%U<&Oq0hA)2^B zp=9OOpXI^EMq)olUM!-;D2Z1=<`>OlofhZ71T=5-^qmG2x*6W)C#Sn#>zc?K7q#62 zT2P2?%IydSG7*r@c=jn6ig!MTtg|?4E_=Ca%j4OL(|30^Tb?F=oKL4ehR#cXF#*+T zFWiOKEj8oUP(VrKp3-nB2!>WlmuJ9GRP^sSq|LoLA6A-S9JB+zqVOQ@0m~|KyP+Ej zfD7y1cM}i$`1M<*z(g12O$+%uv)l4k70}u}BYvnS{qT?^S+Ny8qtj88g}IN-f}y}y z@8caYy?opnonr=*GjKz75W}EWCQSld@uAd8497AQk_>qJnn#%-=a{v$33!tTs!nDr zwJ513W}fpN#X{;CzRX+Stgw~rX>XE`k}i*K^U}u>Tgl6ya<-L5fH`FTeSK`1y+r6h zuimpTPN_1CC)i1OurXg4vm2CF6Hiya@-{9KrETIObG*z6)* z24dpp@fKo8s+%k&0c8p*{ehdL04VdfS;PFr9uo5X+?=Mtba$@+R!&s7@0_=E1=s)& lkD!KSlc!0@cOW5HyV_SmZj^#@|JqNA1cKyL6PaL>`7ao|)baoT diff --git a/src/api/routes/channels/#channel_id/messages/#message_id/index.ts b/src/api/routes/channels/#channel_id/messages/#message_id/index.ts index c4d2e1e8..211cf997 100644 --- a/src/api/routes/channels/#channel_id/messages/#message_id/index.ts +++ b/src/api/routes/channels/#channel_id/messages/#message_id/index.ts @@ -1,17 +1,17 @@ /* Spacebar: A FOSS re-implementation and extension of the Discord.com backend. Copyright (C) 2023 Spacebar and Spacebar Contributors - + 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 by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. - + You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ @@ -91,11 +91,10 @@ router.patch( } } else rights.hasThrow("SELF_EDIT_MESSAGES"); + // @ts-expect-error Something is wrong with message_reference here, TS complains since "channel_id" is optional in MessageCreateSchema const new_message = await handleMessage({ ...message, // TODO: should message_reference be overridable? - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore message_reference: message.message_reference, ...body, author_id: message.author_id, diff --git a/src/api/util/handlers/Message.ts b/src/api/util/handlers/Message.ts index 14efa95b..c3658668 100644 --- a/src/api/util/handlers/Message.ts +++ b/src/api/util/handlers/Message.ts @@ -117,6 +117,12 @@ export async function handleMessage(opts: MessageOptions): Promise { const guild = await Guild.findOneOrFail({ where: { id: channel.guild_id }, }); + + if (!opts.message_reference.guild_id) + opts.message_reference.guild_id = channel.guild_id; + if (!opts.message_reference.channel_id) + opts.message_reference.channel_id = opts.channel_id; + if (!guild.features.includes("CROSS_CHANNEL_REPLIES")) { if (opts.message_reference.guild_id !== channel.guild_id) throw new HTTPError( @@ -127,6 +133,8 @@ export async function handleMessage(opts: MessageOptions): Promise { "You can only reference messages from this channel", ); } + + message.message_reference = opts.message_reference; } /** Q: should be checked if the referenced message exists? ANSWER: NO otherwise backfilling won't work **/ diff --git a/src/util/schemas/MessageCreateSchema.ts b/src/util/schemas/MessageCreateSchema.ts index 495e2ebd..014f6c87 100644 --- a/src/util/schemas/MessageCreateSchema.ts +++ b/src/util/schemas/MessageCreateSchema.ts @@ -42,7 +42,7 @@ export interface MessageCreateSchema { }; message_reference?: { message_id: string; - channel_id: string; + channel_id?: string; guild_id?: string; fail_if_not_exists?: boolean; };