From 5c682137b2ab6ecef2a52fc3974a2cc01931dbf2 Mon Sep 17 00:00:00 2001 From: Puyodead1 Date: Thu, 22 Dec 2022 11:08:03 -0500 Subject: implement PATCH connection --- assets/schemas.json | 643 +++++++++++++++++++++ src/api/routes/users/@me/connections.ts | 47 -- .../#connection_name/#connection_id/index.ts | 51 ++ src/api/routes/users/@me/connections/index.ts | 47 ++ src/util/dtos/ConnectedAccountDTO.ts | 6 +- src/util/entities/ConnectedAccount.ts | 4 +- src/util/entities/ConnectionUpdateSchema.ts | 3 + src/util/entities/index.ts | 1 + src/util/util/Constants.ts | 1 + 9 files changed, 752 insertions(+), 51 deletions(-) delete mode 100644 src/api/routes/users/@me/connections.ts create mode 100644 src/api/routes/users/@me/connections/#connection_name/#connection_id/index.ts create mode 100644 src/api/routes/users/@me/connections/index.ts create mode 100644 src/util/entities/ConnectionUpdateSchema.ts diff --git a/assets/schemas.json b/assets/schemas.json index a4215497..881560dd 100644 --- a/assets/schemas.json +++ b/assets/schemas.json @@ -36,6 +36,16 @@ ], "$schema": "http://json-schema.org/draft-07/schema#" }, + "ConnectionUpdateSchema": { + "type": "object", + "properties": { + "visibility": { + "type": "boolean" + } + }, + "additionalProperties": false, + "$schema": "http://json-schema.org/draft-07/schema#" + }, "SMTPConnection.CustomAuthenticationResponse": { "type": "object", "properties": { @@ -2790,6 +2800,639 @@ }, "$schema": "http://json-schema.org/draft-07/schema#" }, + "ConnectedAccountSchema": { + "type": "object", + "properties": { + "external_id": { + "type": "string" + }, + "user_id": { + "type": "string" + }, + "access_token": { + "type": "string" + }, + "friend_sync": { + "type": "boolean" + }, + "name": { + "type": "string" + }, + "revoked": { + "type": "boolean" + }, + "show_activity": { + "type": "boolean" + }, + "type": { + "type": "string" + }, + "verified": { + "type": "boolean" + }, + "visibility": { + "type": "integer" + }, + "integrations": { + "type": "array", + "items": { + "type": "string" + } + }, + "metadata_": {}, + "metadata_visibility": { + "type": "integer" + }, + "two_way_link": { + "type": "boolean" + } + }, + "additionalProperties": false, + "required": [ + "external_id", + "name", + "type", + "user_id" + ], + "definitions": { + "ChannelPermissionOverwriteType": { + "enum": [ + 0, + 1, + 2 + ], + "type": "number" + }, + "ChannelModifySchema": { + "type": "object", + "properties": { + "name": { + "maxLength": 100, + "type": "string" + }, + "type": { + "enum": [ + 0, + 1, + 10, + 11, + 12, + 13, + 14, + 15, + 2, + 255, + 3, + 33, + 34, + 35, + 4, + 5, + 6, + 64, + 7, + 8, + 9 + ], + "type": "number" + }, + "topic": { + "type": "string" + }, + "icon": { + "type": [ + "null", + "string" + ] + }, + "bitrate": { + "type": "integer" + }, + "user_limit": { + "type": "integer" + }, + "rate_limit_per_user": { + "type": "integer" + }, + "position": { + "type": "integer" + }, + "permission_overwrites": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "type": { + "$ref": "#/definitions/ChannelPermissionOverwriteType" + }, + "allow": { + "type": "string" + }, + "deny": { + "type": "string" + } + }, + "additionalProperties": false, + "required": [ + "allow", + "deny", + "id", + "type" + ] + } + }, + "parent_id": { + "type": "string" + }, + "id": { + "type": "string" + }, + "nsfw": { + "type": "boolean" + }, + "rtc_region": { + "type": "string" + }, + "default_auto_archive_duration": { + "type": "integer" + }, + "default_reaction_emoji": { + "type": [ + "null", + "string" + ] + }, + "flags": { + "type": "integer" + }, + "default_thread_rate_limit_per_user": { + "type": "integer" + }, + "video_quality_mode": { + "type": "integer" + } + }, + "additionalProperties": false + }, + "ActivitySchema": { + "type": "object", + "properties": { + "afk": { + "type": "boolean" + }, + "status": { + "$ref": "#/definitions/Status" + }, + "activities": { + "type": "array", + "items": { + "$ref": "#/definitions/Activity" + } + }, + "since": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "status" + ] + }, + "Status": { + "enum": [ + "dnd", + "idle", + "invisible", + "offline", + "online" + ], + "type": "string" + }, + "Activity": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "type": { + "$ref": "#/definitions/ActivityType" + }, + "url": { + "type": "string" + }, + "created_at": { + "type": "integer" + }, + "timestamps": { + "type": "object", + "properties": { + "start": { + "type": "integer" + }, + "end": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "end", + "start" + ] + }, + "application_id": { + "type": "string" + }, + "details": { + "type": "string" + }, + "state": { + "type": "string" + }, + "emoji": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "id": { + "type": "string" + }, + "animated": { + "type": "boolean" + } + }, + "additionalProperties": false, + "required": [ + "animated", + "name" + ] + }, + "party": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "size": { + "type": "array", + "items": [ + { + "type": "integer" + } + ], + "minItems": 1, + "maxItems": 1 + } + }, + "additionalProperties": false + }, + "assets": { + "type": "object", + "properties": { + "large_image": { + "type": "string" + }, + "large_text": { + "type": "string" + }, + "small_image": { + "type": "string" + }, + "small_text": { + "type": "string" + } + }, + "additionalProperties": false + }, + "secrets": { + "type": "object", + "properties": { + "join": { + "type": "string" + }, + "spectate": { + "type": "string" + }, + "match": { + "type": "string" + } + }, + "additionalProperties": false + }, + "instance": { + "type": "boolean" + }, + "flags": { + "type": "string" + }, + "id": { + "type": "string" + }, + "sync_id": { + "type": "string" + }, + "metadata": { + "type": "object", + "properties": { + "context_uri": { + "type": "string" + }, + "album_id": { + "type": "string" + }, + "artist_ids": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "additionalProperties": false, + "required": [ + "album_id", + "artist_ids" + ] + }, + "session_id": { + "type": "string" + } + }, + "additionalProperties": false, + "required": [ + "flags", + "name", + "session_id", + "type" + ] + }, + "ActivityType": { + "enum": [ + 0, + 1, + 2, + 4, + 5 + ], + "type": "number" + }, + "Record": { + "type": "object", + "additionalProperties": false + }, + "Embed": { + "type": "object", + "properties": { + "title": { + "type": "string" + }, + "type": { + "enum": [ + "article", + "gifv", + "image", + "link", + "rich", + "video" + ], + "type": "string" + }, + "description": { + "type": "string" + }, + "url": { + "type": "string" + }, + "timestamp": { + "type": "string", + "format": "date-time" + }, + "color": { + "type": "integer" + }, + "footer": { + "type": "object", + "properties": { + "text": { + "type": "string" + }, + "icon_url": { + "type": "string" + }, + "proxy_icon_url": { + "type": "string" + } + }, + "additionalProperties": false, + "required": [ + "text" + ] + }, + "image": { + "$ref": "#/definitions/EmbedImage" + }, + "thumbnail": { + "$ref": "#/definitions/EmbedImage" + }, + "video": { + "$ref": "#/definitions/EmbedImage" + }, + "provider": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "url": { + "type": "string" + } + }, + "additionalProperties": false + }, + "author": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "url": { + "type": "string" + }, + "icon_url": { + "type": "string" + }, + "proxy_icon_url": { + "type": "string" + } + }, + "additionalProperties": false + }, + "fields": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + }, + "inline": { + "type": "boolean" + } + }, + "additionalProperties": false, + "required": [ + "name", + "value" + ] + } + } + }, + "additionalProperties": false + }, + "EmbedImage": { + "type": "object", + "properties": { + "url": { + "type": "string" + }, + "proxy_url": { + "type": "string" + }, + "height": { + "type": "integer" + }, + "width": { + "type": "integer" + } + }, + "additionalProperties": false + }, + "Partial": { + "type": "object", + "properties": { + "message_notifications": { + "type": "integer" + }, + "mute_config": { + "$ref": "#/definitions/MuteConfig" + }, + "muted": { + "type": "boolean" + }, + "channel_id": { + "type": [ + "null", + "string" + ] + } + }, + "additionalProperties": false + }, + "MuteConfig": { + "type": "object", + "properties": { + "end_time": { + "type": "integer" + }, + "selected_time_window": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "end_time", + "selected_time_window" + ] + }, + "CustomStatus": { + "type": "object", + "properties": { + "emoji_id": { + "type": "string" + }, + "emoji_name": { + "type": "string" + }, + "expires_at": { + "type": "integer" + }, + "text": { + "type": "string" + } + }, + "additionalProperties": false + }, + "FriendSourceFlags": { + "type": "object", + "properties": { + "all": { + "type": "boolean" + } + }, + "additionalProperties": false, + "required": [ + "all" + ] + }, + "GuildFolder": { + "type": "object", + "properties": { + "color": { + "type": "integer" + }, + "guild_ids": { + "type": "array", + "items": { + "type": "string" + } + }, + "id": { + "type": "integer" + }, + "name": { + "type": "string" + } + }, + "additionalProperties": false, + "required": [ + "color", + "guild_ids", + "id", + "name" + ] + }, + "Partial": { + "type": "object", + "properties": { + "password": { + "type": "string" + } + }, + "additionalProperties": false + }, + "Partial": { + "type": "object", + "properties": { + "credential": { + "type": "string" + }, + "name": { + "type": "string" + }, + "ticket": { + "type": "string" + } + }, + "additionalProperties": false + } + }, + "$schema": "http://json-schema.org/draft-07/schema#" + }, "ConnectionCallbackSchema": { "type": "object", "properties": { diff --git a/src/api/routes/users/@me/connections.ts b/src/api/routes/users/@me/connections.ts deleted file mode 100644 index a5041be1..00000000 --- a/src/api/routes/users/@me/connections.ts +++ /dev/null @@ -1,47 +0,0 @@ -/* - Fosscord: A FOSS re-implementation and extension of the Discord.com backend. - Copyright (C) 2023 Fosscord and Fosscord 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 "@fosscord/api"; -import { ConnectedAccount, ConnectedAccountDTO } from "@fosscord/util"; -import { Request, Response, Router } from "express"; - -const router: Router = Router(); - -router.get("/", route({}), async (req: Request, res: Response) => { - const connections = await ConnectedAccount.find({ - where: { - user_id: req.user_id, - }, - select: [ - "external_id", - "type", - "name", - "verified", - "visibility", - "show_activity", - "revoked", - "access_token", - "friend_sync", - "integrations", - ], - }); - - res.json(connections.map((x) => new ConnectedAccountDTO(x, true))); -}); - -export default router; diff --git a/src/api/routes/users/@me/connections/#connection_name/#connection_id/index.ts b/src/api/routes/users/@me/connections/#connection_name/#connection_id/index.ts new file mode 100644 index 00000000..76eb9936 --- /dev/null +++ b/src/api/routes/users/@me/connections/#connection_name/#connection_id/index.ts @@ -0,0 +1,51 @@ +import { route } from "@fosscord/api"; +import { Request, Response, Router } from "express"; +import { + ConnectedAccount, + DiscordApiErrors, + OrmUtils, +} from "../../../../../../../util"; +const router = Router(); + +// TODO: connection update schema +router.patch( + "/", + route({ body: "ConnectionUpdateSchema" }), + async (req: Request, res: Response) => { + const { connection_name, connection_id } = req.params; + + const connection = await ConnectedAccount.findOne({ + where: { + user_id: req.user_id, + external_id: connection_id, + type: connection_name, + }, + select: [ + "external_id", + "type", + "name", + "verified", + "visibility", + "show_activity", + "revoked", + "friend_sync", + "integrations", + ], + }); + + if (!connection) return DiscordApiErrors.UNKNOWN_CONNECTION; + // TODO: do we need to do anything if the connection is revoked? + OrmUtils.mergeDeep(connection, req.body); + await ConnectedAccount.update( + { + user_id: req.user_id, + external_id: connection_id, + type: connection_name, + }, + connection, + ); + res.json(connection.toJSON()); + }, +); + +export default router; diff --git a/src/api/routes/users/@me/connections/index.ts b/src/api/routes/users/@me/connections/index.ts new file mode 100644 index 00000000..a5041be1 --- /dev/null +++ b/src/api/routes/users/@me/connections/index.ts @@ -0,0 +1,47 @@ +/* + Fosscord: A FOSS re-implementation and extension of the Discord.com backend. + Copyright (C) 2023 Fosscord and Fosscord 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 "@fosscord/api"; +import { ConnectedAccount, ConnectedAccountDTO } from "@fosscord/util"; +import { Request, Response, Router } from "express"; + +const router: Router = Router(); + +router.get("/", route({}), async (req: Request, res: Response) => { + const connections = await ConnectedAccount.find({ + where: { + user_id: req.user_id, + }, + select: [ + "external_id", + "type", + "name", + "verified", + "visibility", + "show_activity", + "revoked", + "access_token", + "friend_sync", + "integrations", + ], + }); + + res.json(connections.map((x) => new ConnectedAccountDTO(x, true))); +}); + +export default router; diff --git a/src/util/dtos/ConnectedAccountDTO.ts b/src/util/dtos/ConnectedAccountDTO.ts index 36a4e6b3..debc5535 100644 --- a/src/util/dtos/ConnectedAccountDTO.ts +++ b/src/util/dtos/ConnectedAccountDTO.ts @@ -32,10 +32,12 @@ export class ConnectedAccountDTO { this.show_activity = connectedAccount.show_activity; this.type = connectedAccount.type; this.verified = connectedAccount.verified; - this.visibility = connectedAccount.visibility; + this.visibility = +(connectedAccount.visibility || false); this.integrations = connectedAccount.integrations; this.metadata_ = connectedAccount.metadata_; - this.metadata_visibility = connectedAccount.metadata_visibility; + this.metadata_visibility = +( + connectedAccount.metadata_visibility || false + ); this.two_way_link = connectedAccount.two_way_link; } } diff --git a/src/util/entities/ConnectedAccount.ts b/src/util/entities/ConnectedAccount.ts index 25d5a0c7..714faf0c 100644 --- a/src/util/entities/ConnectedAccount.ts +++ b/src/util/entities/ConnectedAccount.ts @@ -62,7 +62,7 @@ export class ConnectedAccount extends BaseClass { verified?: boolean = true; @Column({ select: false }) - visibility?: number = 0; + visibility?: boolean = false; @Column({ type: "simple-array" }) integrations?: string[] = []; @@ -71,7 +71,7 @@ export class ConnectedAccount extends BaseClass { metadata_?: any; @Column() - metadata_visibility?: number = 0; + metadata_visibility?: boolean = false; @Column() two_way_link?: boolean = false; diff --git a/src/util/entities/ConnectionUpdateSchema.ts b/src/util/entities/ConnectionUpdateSchema.ts new file mode 100644 index 00000000..ac234e7e --- /dev/null +++ b/src/util/entities/ConnectionUpdateSchema.ts @@ -0,0 +1,3 @@ +export interface ConnectionUpdateSchema { + visibility?: boolean; +} diff --git a/src/util/entities/index.ts b/src/util/entities/index.ts index ad34f67b..b4e3ecd0 100644 --- a/src/util/entities/index.ts +++ b/src/util/entities/index.ts @@ -28,6 +28,7 @@ export * from "./ClientRelease"; export * from "./Config"; export * from "./ConnectedAccount"; export * from "./ConnectionConfigEntity"; +export * from "./ConnectionUpdateSchema"; export * from "./EmbedCache"; export * from "./Emoji"; export * from "./Encryption"; diff --git a/src/util/util/Constants.ts b/src/util/util/Constants.ts index 1afdce49..3bdfcfa9 100644 --- a/src/util/util/Constants.ts +++ b/src/util/util/Constants.ts @@ -578,6 +578,7 @@ export const DiscordApiErrors = { UNKNOWN_EMOJI: new ApiError("Unknown emoji", 10014), UNKNOWN_WEBHOOK: new ApiError("Unknown webhook", 10015), UNKNOWN_WEBHOOK_SERVICE: new ApiError("Unknown webhook service", 10016), + UNKNOWN_CONNECTION: new ApiError("Unknown connection", 10017, 400), UNKNOWN_SESSION: new ApiError("Unknown session", 10020), UNKNOWN_BAN: new ApiError("Unknown ban", 10026), UNKNOWN_SKU: new ApiError("Unknown SKU", 10027), -- cgit 1.4.1