From 12c92a29500d8a48ba7373f17eeaa2c1fceee3be Mon Sep 17 00:00:00 2001 From: AlTech98 Date: Mon, 13 Sep 2021 17:31:07 +0200 Subject: [PATCH 1/8] Fix attachments not being saved to db --- util/src/entities/Message.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util/src/entities/Message.ts b/util/src/entities/Message.ts index f4c7fdc7..506db71a 100644 --- a/util/src/entities/Message.ts +++ b/util/src/entities/Message.ts @@ -128,7 +128,7 @@ export class Message extends BaseClass { sticker_items?: Sticker[]; @JoinColumn({ name: "attachment_ids" }) - @OneToMany(() => Attachment, (attachment: Attachment) => attachment.message) + @OneToMany(() => Attachment, (attachment: Attachment) => attachment.message, { cascade: true }) attachments?: Attachment[]; @Column({ type: "simple-json" }) From aa1f1a22a4cce0c51d84c10d5a741699f7bbfff2 Mon Sep 17 00:00:00 2001 From: AlTech98 Date: Mon, 13 Sep 2021 17:32:31 +0200 Subject: [PATCH 2/8] Delete attachments of deleted messages, fix #273 --- api/assets/schemas.json | 6 +++++- .../#channel_id/messages/#message_id/index.ts | 7 ++++--- .../routes/channels/#channel_id/messages/index.ts | 1 + api/src/util/Attachments.ts | 12 ++++++++++++ api/src/util/cdn.ts | 13 +++++++++++++ cdn/src/util/FileStorage.ts | 1 + 6 files changed, 36 insertions(+), 4 deletions(-) create mode 100644 api/src/util/Attachments.ts diff --git a/api/assets/schemas.json b/api/assets/schemas.json index ac7df859..94aa0660 100644 --- a/api/assets/schemas.json +++ b/api/assets/schemas.json @@ -462,7 +462,11 @@ "payload_json": { "type": "string" }, - "file": {} + "file": {}, + "attachments": { + "type": "array", + "items": {} + } }, "additionalProperties": false, "definitions": { diff --git a/api/src/routes/channels/#channel_id/messages/#message_id/index.ts b/api/src/routes/channels/#channel_id/messages/#message_id/index.ts index d0f780db..b5220fab 100644 --- a/api/src/routes/channels/#channel_id/messages/#message_id/index.ts +++ b/api/src/routes/channels/#channel_id/messages/#message_id/index.ts @@ -3,6 +3,7 @@ import { Router, Response, Request } from "express"; import { route } from "@fosscord/api"; import { handleMessage, postHandleMessage } from "@fosscord/api"; import { MessageCreateSchema } from "../index"; +import { deleteMessageAttachments } from "@fosscord/api/util/Attachments"; const router = Router(); // TODO: message content/embed string length limit @@ -11,7 +12,7 @@ router.patch("/", route({ body: "MessageCreateSchema", permission: "SEND_MESSAGE const { message_id, channel_id } = req.params; var body = req.body as MessageCreateSchema; - const message = await Message.findOneOrFail({ id: message_id, channel_id }); + const message = await Message.findOneOrFail({ where: { id: message_id, channel_id }, relations: ["attachments"] }); const permissions = await getPermission(req.user_id, undefined, channel_id); @@ -33,6 +34,7 @@ router.patch("/", route({ body: "MessageCreateSchema", permission: "SEND_MESSAGE }); await Promise.all([ + await deleteMessageAttachments(message_id, new_message.attachments), //This delete all the attachments not in the array new_message!.save(), await emitEvent({ event: "MESSAGE_UPDATE", @@ -46,8 +48,6 @@ router.patch("/", route({ body: "MessageCreateSchema", permission: "SEND_MESSAGE return res.json(message); }); -// TODO: delete attachments in message - // permission check only if deletes messagr from other user router.delete("/", route({}), async (req: Request, res: Response) => { const { message_id, channel_id } = req.params; @@ -60,6 +60,7 @@ router.delete("/", route({}), async (req: Request, res: Response) => { permission.hasThrow("MANAGE_MESSAGES"); } + await deleteMessageAttachments(message_id); await Message.delete({ id: message_id }); await emitEvent({ diff --git a/api/src/routes/channels/#channel_id/messages/index.ts b/api/src/routes/channels/#channel_id/messages/index.ts index 11334367..25ecc1c7 100644 --- a/api/src/routes/channels/#channel_id/messages/index.ts +++ b/api/src/routes/channels/#channel_id/messages/index.ts @@ -51,6 +51,7 @@ export interface MessageCreateSchema { }; payload_json?: string; file?: any; + attachments?: any[]; //TODO we should create an interface for attachments } // https://discord.com/developers/docs/resources/channel#create-message diff --git a/api/src/util/Attachments.ts b/api/src/util/Attachments.ts new file mode 100644 index 00000000..addda97f --- /dev/null +++ b/api/src/util/Attachments.ts @@ -0,0 +1,12 @@ +import { Attachment } from "@fosscord/util"; +import { deleteFile } from "@fosscord/api"; +import { URL } from "url"; + +export async function deleteMessageAttachments(messageId: string, keep?: Attachment[]) { + let attachments = await Attachment.find({ message_id: messageId }); + if (keep) + attachments = attachments.filter(x => !keep.map(k => k.id).includes(x.id)); + await Promise.all(attachments.map(a => a.remove())); + + attachments.forEach(a => deleteFile((new URL(a.url)).pathname)); //We don't need to await since this is done on the cdn +} diff --git a/api/src/util/cdn.ts b/api/src/util/cdn.ts index 3c71d980..88b0ea0d 100644 --- a/api/src/util/cdn.ts +++ b/api/src/util/cdn.ts @@ -38,3 +38,16 @@ export async function handleFile(path: string, body?: string): Promise Date: Mon, 13 Sep 2021 19:09:01 +0200 Subject: [PATCH 3/8] Emit USER_UPDATE, fix #214 --- api/src/routes/users/@me/index.ts | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/api/src/routes/users/@me/index.ts b/api/src/routes/users/@me/index.ts index 68723374..a8c0edc4 100644 --- a/api/src/routes/users/@me/index.ts +++ b/api/src/routes/users/@me/index.ts @@ -1,6 +1,6 @@ import { Router, Request, Response } from "express"; -import { User, PrivateUserProjection } from "@fosscord/util"; -import { check, route } from "@fosscord/api"; +import { User, PrivateUserProjection, emitEvent, UserUpdateEvent } from "@fosscord/util"; +import { route } from "@fosscord/api"; import { handleFile } from "@fosscord/api"; const router: Router = Router(); @@ -33,8 +33,16 @@ router.patch("/", route({ body: "UserModifySchema" }), async (req: Request, res: if (body.avatar) body.avatar = await handleFile(`/avatars/${req.user_id}`, body.avatar as string); if (body.banner) body.banner = await handleFile(`/banners/${req.user_id}`, body.banner as string); - const user = await new User({ ...body, id: req.user_id }).save(); - // TODO: dispatch user update event + await new User({ ...body, id: req.user_id }).save(); + + //Need to reload user from db due to https://github.com/typeorm/typeorm/issues/3490 + const user = await User.findOneOrFail({ where: { id: req.user_id }, select: PrivateUserProjection }); + + await emitEvent({ + event: "USER_UPDATE", + user_id: req.user_id, + data: user + } as UserUpdateEvent); res.json(user); }); From 68eae50a63df0a84d75c05abce5142a33f4c5bd3 Mon Sep 17 00:00:00 2001 From: Flam3rboy <34555296+Flam3rboy@users.noreply.github.com> Date: Mon, 13 Sep 2021 19:12:19 +0200 Subject: [PATCH 4/8] Update index.ts --- api/src/routes/users/@me/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/src/routes/users/@me/index.ts b/api/src/routes/users/@me/index.ts index a8c0edc4..c0002d79 100644 --- a/api/src/routes/users/@me/index.ts +++ b/api/src/routes/users/@me/index.ts @@ -37,7 +37,7 @@ router.patch("/", route({ body: "UserModifySchema" }), async (req: Request, res: //Need to reload user from db due to https://github.com/typeorm/typeorm/issues/3490 const user = await User.findOneOrFail({ where: { id: req.user_id }, select: PrivateUserProjection }); - + // TODO: send update member list event in gateway await emitEvent({ event: "USER_UPDATE", user_id: req.user_id, From 7cdcb82ecdf51b2dab5808a89ed50b96af0a60cc Mon Sep 17 00:00:00 2001 From: AlTech98 Date: Mon, 13 Sep 2021 19:25:44 +0200 Subject: [PATCH 5/8] Fix #356 --- api/assets/schemas.json | 35 +++++++++++++++++++----- api/src/routes/guilds/#guild_id/index.ts | 10 +++---- api/src/routes/guilds/index.ts | 2 +- 3 files changed, 34 insertions(+), 13 deletions(-) diff --git a/api/assets/schemas.json b/api/assets/schemas.json index 94aa0660..3f760c35 100644 --- a/api/assets/schemas.json +++ b/api/assets/schemas.json @@ -2548,7 +2548,10 @@ "type": "string" }, "system_channel_id": { - "type": "string" + "type": [ + "null", + "string" + ] }, "rules_channel_id": { "type": "string" @@ -2802,13 +2805,22 @@ "type": "object", "properties": { "banner": { - "type": "string" + "type": [ + "null", + "string" + ] }, "splash": { - "type": "string" + "type": [ + "null", + "string" + ] }, "description": { - "type": "string" + "type": [ + "null", + "string" + ] }, "features": { "type": "array", @@ -2829,13 +2841,19 @@ "type": "integer" }, "public_updates_channel_id": { - "type": "string" + "type": [ + "null", + "string" + ] }, "afk_timeout": { "type": "integer" }, "afk_channel_id": { - "type": "string" + "type": [ + "null", + "string" + ] }, "preferred_locale": { "type": "string" @@ -2854,7 +2872,10 @@ "type": "string" }, "system_channel_id": { - "type": "string" + "type": [ + "null", + "string" + ] }, "rules_channel_id": { "type": "string" diff --git a/api/src/routes/guilds/#guild_id/index.ts b/api/src/routes/guilds/#guild_id/index.ts index 690d4103..9c67798d 100644 --- a/api/src/routes/guilds/#guild_id/index.ts +++ b/api/src/routes/guilds/#guild_id/index.ts @@ -9,17 +9,17 @@ import { GuildCreateSchema } from "../index"; const router = Router(); export interface GuildUpdateSchema extends Omit { - banner?: string; - splash?: string; - description?: string; + banner?: string | null; + splash?: string | null; + description?: string | null; features?: string[]; verification_level?: number; default_message_notifications?: number; system_channel_flags?: number; explicit_content_filter?: number; - public_updates_channel_id?: string; + public_updates_channel_id?: string | null; afk_timeout?: number; - afk_channel_id?: string; + afk_channel_id?: string | null; preferred_locale?: string; } diff --git a/api/src/routes/guilds/index.ts b/api/src/routes/guilds/index.ts index ba951f96..674dc16b 100644 --- a/api/src/routes/guilds/index.ts +++ b/api/src/routes/guilds/index.ts @@ -16,7 +16,7 @@ export interface GuildCreateSchema { icon?: string; channels?: ChannelModifySchema[]; guild_template_code?: string; - system_channel_id?: string; + system_channel_id?: string | null; rules_channel_id?: string; } From 9b10ab2d0b7a7a1c3c9a8b65a02518dffdbf04ba Mon Sep 17 00:00:00 2001 From: uurgothat Date: Mon, 13 Sep 2021 21:22:14 +0300 Subject: [PATCH 6/8] add store endpoints --- api/src/routes/store/applications.ts | 11 +++++++++++ api/src/routes/store/skus.ts | 11 +++++++++++ 2 files changed, 22 insertions(+) create mode 100644 api/src/routes/store/applications.ts create mode 100644 api/src/routes/store/skus.ts diff --git a/api/src/routes/store/applications.ts b/api/src/routes/store/applications.ts new file mode 100644 index 00000000..69cd716d --- /dev/null +++ b/api/src/routes/store/applications.ts @@ -0,0 +1,11 @@ +import { Request, Response, Router } from "express"; + +const router: Router = Router(); + +router.get("/applications/:id", async (req: Request, res: Response) => { + //TODO + const { id } = req.params; + res.json([]).status(200); +}); + +export default router; \ No newline at end of file diff --git a/api/src/routes/store/skus.ts b/api/src/routes/store/skus.ts new file mode 100644 index 00000000..5c37850d --- /dev/null +++ b/api/src/routes/store/skus.ts @@ -0,0 +1,11 @@ +import { Request, Response, Router } from "express"; + +const router: Router = Router(); + +router.get("/skus/:id", async (req: Request, res: Response) => { + //TODO + const { id } = req.params; + res.json([]).status(200); +}); + +export default router; \ No newline at end of file From 8f68c4abcf8cb1e15a694795a3a13538bc4f1dcc Mon Sep 17 00:00:00 2001 From: AlTech98 Date: Tue, 14 Sep 2021 09:38:21 +0200 Subject: [PATCH 7/8] Fix invites creation --- api/assets/schemas.json | 5 ++++- api/src/routes/channels/#channel_id/invites.ts | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/api/assets/schemas.json b/api/assets/schemas.json index 3f760c35..9c34f968 100644 --- a/api/assets/schemas.json +++ b/api/assets/schemas.json @@ -713,7 +713,10 @@ "type": "object", "properties": { "target_user_id": { - "type": "string" + "type": [ + "null", + "string" + ] }, "target_type": { "type": [ diff --git a/api/src/routes/channels/#channel_id/invites.ts b/api/src/routes/channels/#channel_id/invites.ts index 2edb4fc2..71612e31 100644 --- a/api/src/routes/channels/#channel_id/invites.ts +++ b/api/src/routes/channels/#channel_id/invites.ts @@ -8,7 +8,7 @@ import { isTextChannel } from "./messages"; const router: Router = Router(); export interface InviteCreateSchema { - target_user_id?: string; + target_user_id?: string | null; target_type?: string | null; validate?: string | null; // ? what is this max_age?: number; From b17f3c053d0449823892aa08172fd6fe4d465e78 Mon Sep 17 00:00:00 2001 From: AlTech98 Date: Tue, 14 Sep 2021 09:38:52 +0200 Subject: [PATCH 8/8] Emit INVITE_DELETE --- api/src/routes/invites/index.ts | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/api/src/routes/invites/index.ts b/api/src/routes/invites/index.ts index 6e77a853..ae8a5944 100644 --- a/api/src/routes/invites/index.ts +++ b/api/src/routes/invites/index.ts @@ -1,7 +1,8 @@ import { Router, Request, Response } from "express"; -import { getPermission, Guild, Invite, Member, PublicInviteRelation } from "@fosscord/util"; +import { emitEvent, getPermission, Guild, Invite, InviteDeleteEvent, Member, PublicInviteRelation } from "@fosscord/util"; import { route } from "@fosscord/api"; import { HTTPError } from "lambert-server"; + const router: Router = Router(); router.get("/:code", route({}), async (req: Request, res: Response) => { @@ -35,7 +36,19 @@ router.delete("/:code", route({}), async (req: Request, res: Response) => { if (!permission.has("MANAGE_GUILD") && !permission.has("MANAGE_CHANNELS")) throw new HTTPError("You missing the MANAGE_GUILD or MANAGE_CHANNELS permission", 401); - await Promise.all([Invite.delete({ code }), Guild.update({ vanity_url_code: code }, { vanity_url_code: undefined })]); + await Promise.all([ + Invite.delete({ code }), + Guild.update({ vanity_url_code: code }, { vanity_url_code: undefined }), + emitEvent({ + event: "INVITE_DELETE", + guild_id: guild_id, + data: { + channel_id: channel_id, + guild_id: guild_id, + code: code + } + } as InviteDeleteEvent) + ]); res.json({ invite: invite }); });