From 21bfda32e452c05b8906bf318df7415d6cd5acd0 Mon Sep 17 00:00:00 2001 From: Puyodead1 Date: Thu, 22 Dec 2022 10:05:51 -0500 Subject: add connections --- assets/schemas.json | 602 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 602 insertions(+) (limited to 'assets') diff --git a/assets/schemas.json b/assets/schemas.json index 1fdfa361..a4215497 100644 --- a/assets/schemas.json +++ b/assets/schemas.json @@ -2790,6 +2790,608 @@ }, "$schema": "http://json-schema.org/draft-07/schema#" }, + "ConnectionCallbackSchema": { + "type": "object", + "properties": { + "code": { + "type": "string" + }, + "state": { + "type": "string" + }, + "insecure": { + "type": "boolean" + }, + "friend_sync": { + "type": "boolean" + }, + "openid_params": {} + }, + "additionalProperties": false, + "required": [ + "friend_sync", + "insecure", + "state" + ], + "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#" + }, "DmChannelCreateSchema": { "type": "object", "properties": { -- cgit 1.5.1 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 (limited to 'assets') 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.5.1 From 2364096a97ba66949cc3b7fbc5b9fb68977ff3ca Mon Sep 17 00:00:00 2001 From: Madeline <46743919+MaddyUnderStars@users.noreply.github.com> Date: Fri, 23 Dec 2022 12:46:03 +1100 Subject: entities/ConnectionUpdateSchema -> schemas/ConnectionUpdateSchema --- assets/schemas.json | 597 ++++++++++++++++++++- .../connections/#connection_name/authorize.ts | 5 +- src/util/entities/ConnectionUpdateSchema.ts | 3 - src/util/entities/index.ts | 1 - src/util/schemas/ConnectionUpdateSchema.ts | 3 + src/util/schemas/index.ts | 1 + 6 files changed, 593 insertions(+), 17 deletions(-) delete mode 100644 src/util/entities/ConnectionUpdateSchema.ts create mode 100644 src/util/schemas/ConnectionUpdateSchema.ts (limited to 'assets') diff --git a/assets/schemas.json b/assets/schemas.json index 881560dd..fe4fcea3 100644 --- a/assets/schemas.json +++ b/assets/schemas.json @@ -36,16 +36,6 @@ ], "$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": { @@ -4035,6 +4025,593 @@ }, "$schema": "http://json-schema.org/draft-07/schema#" }, + "ConnectionUpdateSchema": { + "type": "object", + "properties": { + "visibility": { + "type": "boolean" + } + }, + "additionalProperties": false, + "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#" + }, "DmChannelCreateSchema": { "type": "object", "properties": { diff --git a/src/api/routes/connections/#connection_name/authorize.ts b/src/api/routes/connections/#connection_name/authorize.ts index 5ce420cf..5c24dc7c 100644 --- a/src/api/routes/connections/#connection_name/authorize.ts +++ b/src/api/routes/connections/#connection_name/authorize.ts @@ -1,7 +1,6 @@ +import { route } from "@fosscord/api"; import { Request, Response, Router } from "express"; -import { FieldErrors } from "../../../../util"; -import { ConnectionStore } from "../../../../util/connections"; -import { route } from "../../../util"; +import { ConnectionStore, FieldErrors } from "../../../../util"; const router = Router(); diff --git a/src/util/entities/ConnectionUpdateSchema.ts b/src/util/entities/ConnectionUpdateSchema.ts deleted file mode 100644 index ac234e7e..00000000 --- a/src/util/entities/ConnectionUpdateSchema.ts +++ /dev/null @@ -1,3 +0,0 @@ -export interface ConnectionUpdateSchema { - visibility?: boolean; -} diff --git a/src/util/entities/index.ts b/src/util/entities/index.ts index b4e3ecd0..ad34f67b 100644 --- a/src/util/entities/index.ts +++ b/src/util/entities/index.ts @@ -28,7 +28,6 @@ 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/schemas/ConnectionUpdateSchema.ts b/src/util/schemas/ConnectionUpdateSchema.ts new file mode 100644 index 00000000..ac234e7e --- /dev/null +++ b/src/util/schemas/ConnectionUpdateSchema.ts @@ -0,0 +1,3 @@ +export interface ConnectionUpdateSchema { + visibility?: boolean; +} diff --git a/src/util/schemas/index.ts b/src/util/schemas/index.ts index 71b4c2ce..e9f4268e 100644 --- a/src/util/schemas/index.ts +++ b/src/util/schemas/index.ts @@ -32,6 +32,7 @@ export * from "./ChannelReorderSchema"; export * from "./CodesVerificationSchema"; export * from "./ConnectedAccountSchema"; export * from "./ConnectionCallbackSchema"; +export * from "./ConnectionUpdateSchema"; export * from "./DmChannelCreateSchema"; export * from "./EmojiCreateSchema"; export * from "./EmojiModifySchema"; -- cgit 1.5.1 From 6d6944cfee4af656c6386c7a44efc6b99bdfd6ed Mon Sep 17 00:00:00 2001 From: Puyodead1 Date: Sat, 24 Dec 2022 16:24:58 -0500 Subject: Add Twitch, error handling, revokation changes, etc --- assets/schemas.json | 1865 +++++++++++++++++++- .../#connection_id/access-token.ts | 16 +- .../#connection_name/#connection_id/index.ts | 13 +- src/connections/BattleNet/index.ts | 25 +- src/connections/Discord/index.ts | 26 +- src/connections/EpicGames/index.ts | 26 +- src/connections/Facebook/index.ts | 25 +- src/connections/GitHub/index.ts | 28 +- src/connections/Reddit/index.ts | 28 +- src/connections/Spotify/index.ts | 51 +- src/connections/Twitch/TwitchSettings.ts | 5 + src/connections/Twitch/index.ts | 196 ++ src/util/connections/RefreshableConnection.ts | 2 +- src/util/dtos/ConnectedAccountDTO.ts | 2 +- src/util/entities/ConnectedAccount.ts | 10 +- src/util/interfaces/ConnectedAccount.ts | 1 + src/util/schemas/ConnectedAccountSchema.ts | 2 +- src/util/schemas/ConnectionUpdateSchema.ts | 1 + src/util/util/Constants.ts | 5 + 19 files changed, 2278 insertions(+), 49 deletions(-) create mode 100644 src/connections/Twitch/TwitchSettings.ts create mode 100644 src/connections/Twitch/index.ts (limited to 'assets') diff --git a/assets/schemas.json b/assets/schemas.json index fe4fcea3..5f897c86 100644 --- a/assets/schemas.json +++ b/assets/schemas.json @@ -36,6 +36,33 @@ ], "$schema": "http://json-schema.org/draft-07/schema#" }, + "ConnectedAccountCommonOAuthTokenResponse": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "scope", + "token_type" + ], + "$schema": "http://json-schema.org/draft-07/schema#" + }, "SMTPConnection.CustomAuthenticationResponse": { "type": "object", "properties": { @@ -419,6 +446,37 @@ ], "type": "number" }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "fetched_at" + ] + }, "ChannelModifySchema": { "type": "object", "properties": { @@ -1021,6 +1079,37 @@ ], "type": "number" }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "fetched_at" + ] + }, "ChannelModifySchema": { "type": "object", "properties": { @@ -1623,6 +1712,37 @@ ], "type": "number" }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "fetched_at" + ] + }, "ChannelModifySchema": { "type": "object", "properties": { @@ -2220,6 +2340,37 @@ ], "type": "number" }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "fetched_at" + ] + }, "ChannelModifySchema": { "type": "object", "properties": { @@ -2799,8 +2950,8 @@ "user_id": { "type": "string" }, - "access_token": { - "type": "string" + "token_data": { + "$ref": "#/definitions/ConnectedAccountTokenData" }, "friend_sync": { "type": "boolean" @@ -2812,7 +2963,7 @@ "type": "boolean" }, "show_activity": { - "type": "boolean" + "type": "integer" }, "type": { "type": "string" @@ -2853,6 +3004,37 @@ ], "type": "number" }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "fetched_at" + ] + }, "ChannelModifySchema": { "type": "object", "properties": { @@ -3455,6 +3637,37 @@ ], "type": "number" }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "fetched_at" + ] + }, "ChannelModifySchema": { "type": "object", "properties": { @@ -4030,6 +4243,9 @@ "properties": { "visibility": { "type": "boolean" + }, + "show_activity": { + "type": "boolean" } }, "additionalProperties": false, @@ -4042,6 +4258,37 @@ ], "type": "number" }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "fetched_at" + ] + }, "ChannelModifySchema": { "type": "object", "properties": { @@ -4638,6 +4885,37 @@ ], "type": "number" }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "fetched_at" + ] + }, "ChannelModifySchema": { "type": "object", "properties": { @@ -5243,6 +5521,37 @@ ], "type": "number" }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "fetched_at" + ] + }, "ChannelModifySchema": { "type": "object", "properties": { @@ -5836,6 +6145,37 @@ ], "type": "number" }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "fetched_at" + ] + }, "ChannelModifySchema": { "type": "object", "properties": { @@ -6429,6 +6769,37 @@ ], "type": "number" }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "fetched_at" + ] + }, "ChannelModifySchema": { "type": "object", "properties": { @@ -7041,6 +7412,37 @@ ], "type": "number" }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "fetched_at" + ] + }, "ChannelModifySchema": { "type": "object", "properties": { @@ -7637,6 +8039,37 @@ ], "type": "number" }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "fetched_at" + ] + }, "ChannelModifySchema": { "type": "object", "properties": { @@ -8293,6 +8726,37 @@ ], "type": "number" }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "fetched_at" + ] + }, "ChannelModifySchema": { "type": "object", "properties": { @@ -8908,6 +9372,37 @@ ], "type": "number" }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "fetched_at" + ] + }, "ChannelModifySchema": { "type": "object", "properties": { @@ -9663,6 +10158,37 @@ ], "type": "number" }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "fetched_at" + ] + }, "ChannelModifySchema": { "type": "object", "properties": { @@ -10274,6 +10800,37 @@ ], "type": "number" }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "fetched_at" + ] + }, "ChannelModifySchema": { "type": "object", "properties": { @@ -10889,6 +11446,37 @@ ], "type": "number" }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "fetched_at" + ] + }, "ChannelModifySchema": { "type": "object", "properties": { @@ -11495,6 +12083,37 @@ ], "type": "number" }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "fetched_at" + ] + }, "ChannelModifySchema": { "type": "object", "properties": { @@ -12107,6 +12726,37 @@ ], "type": "number" }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "fetched_at" + ] + }, "ChannelModifySchema": { "type": "object", "properties": { @@ -12709,6 +13359,37 @@ ], "type": "number" }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "fetched_at" + ] + }, "ChannelModifySchema": { "type": "object", "properties": { @@ -13299,6 +13980,37 @@ ], "type": "number" }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "fetched_at" + ] + }, "ChannelModifySchema": { "type": "object", "properties": { @@ -14000,6 +14712,37 @@ ], "type": "number" }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "fetched_at" + ] + }, "ChannelModifySchema": { "type": "object", "properties": { @@ -14698,6 +15441,37 @@ ], "type": "number" }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "fetched_at" + ] + }, "ChannelModifySchema": { "type": "object", "properties": { @@ -15291,6 +16065,37 @@ ], "type": "number" }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "fetched_at" + ] + }, "ChannelModifySchema": { "type": "object", "properties": { @@ -15892,6 +16697,37 @@ ], "type": "number" }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "fetched_at" + ] + }, "ChannelModifySchema": { "type": "object", "properties": { @@ -16486,6 +17322,37 @@ ], "type": "number" }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "fetched_at" + ] + }, "ChannelModifySchema": { "type": "object", "properties": { @@ -17080,6 +17947,37 @@ ], "type": "number" }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "fetched_at" + ] + }, "ChannelModifySchema": { "type": "object", "properties": { @@ -17703,6 +18601,37 @@ ], "type": "number" }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "fetched_at" + ] + }, "ChannelModifySchema": { "type": "object", "properties": { @@ -18297,6 +19226,37 @@ ], "type": "number" }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "fetched_at" + ] + }, "ChannelModifySchema": { "type": "object", "properties": { @@ -18890,6 +19850,37 @@ ], "type": "number" }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "fetched_at" + ] + }, "ChannelModifySchema": { "type": "object", "properties": { @@ -19498,6 +20489,37 @@ ], "type": "number" }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "fetched_at" + ] + }, "ChannelModifySchema": { "type": "object", "properties": { @@ -20095,6 +21117,37 @@ ], "type": "number" }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "fetched_at" + ] + }, "ChannelModifySchema": { "type": "object", "properties": { @@ -20766,6 +21819,37 @@ ], "type": "number" }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "fetched_at" + ] + }, "ChannelModifySchema": { "type": "object", "properties": { @@ -21359,6 +22443,37 @@ ], "type": "number" }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "fetched_at" + ] + }, "ChannelModifySchema": { "type": "object", "properties": { @@ -21952,6 +23067,37 @@ ], "type": "number" }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "fetched_at" + ] + }, "ChannelModifySchema": { "type": "object", "properties": { @@ -22542,6 +23688,37 @@ ], "type": "number" }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "fetched_at" + ] + }, "ChannelModifySchema": { "type": "object", "properties": { @@ -23138,6 +24315,37 @@ ], "type": "number" }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "fetched_at" + ] + }, "ChannelModifySchema": { "type": "object", "properties": { @@ -23744,6 +24952,37 @@ ], "type": "number" }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "fetched_at" + ] + }, "ChannelModifySchema": { "type": "object", "properties": { @@ -24334,6 +25573,37 @@ ], "type": "number" }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "fetched_at" + ] + }, "ChannelModifySchema": { "type": "object", "properties": { @@ -24973,6 +26243,37 @@ ], "type": "number" }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "fetched_at" + ] + }, "ChannelModifySchema": { "type": "object", "properties": { @@ -25598,6 +26899,37 @@ ], "type": "number" }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "fetched_at" + ] + }, "ChannelModifySchema": { "type": "object", "properties": { @@ -26213,6 +27545,37 @@ ], "type": "number" }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "fetched_at" + ] + }, "ChannelModifySchema": { "type": "object", "properties": { @@ -26917,6 +28280,37 @@ ], "type": "number" }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "fetched_at" + ] + }, "ChannelModifySchema": { "type": "object", "properties": { @@ -27506,6 +28900,37 @@ ], "type": "number" }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "fetched_at" + ] + }, "ChannelModifySchema": { "type": "object", "properties": { @@ -28134,6 +29559,37 @@ ], "type": "number" }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "fetched_at" + ] + }, "ChannelModifySchema": { "type": "object", "properties": { @@ -28747,6 +30203,37 @@ ], "type": "number" }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "fetched_at" + ] + }, "ChannelModifySchema": { "type": "object", "properties": { @@ -29415,6 +30902,37 @@ ], "type": "number" }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "fetched_at" + ] + }, "ChannelModifySchema": { "type": "object", "properties": { @@ -30005,6 +31523,37 @@ ], "type": "number" }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "fetched_at" + ] + }, "ChannelModifySchema": { "type": "object", "properties": { @@ -30603,6 +32152,37 @@ ], "type": "number" }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "fetched_at" + ] + }, "ChannelModifySchema": { "type": "object", "properties": { @@ -31191,6 +32771,37 @@ ], "type": "number" }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "fetched_at" + ] + }, "ChannelModifySchema": { "type": "object", "properties": { @@ -31785,6 +33396,37 @@ ], "type": "number" }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "fetched_at" + ] + }, "ChannelModifySchema": { "type": "object", "properties": { @@ -32379,6 +34021,37 @@ ], "type": "number" }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "fetched_at" + ] + }, "ChannelModifySchema": { "type": "object", "properties": { @@ -32973,6 +34646,37 @@ ], "type": "number" }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "fetched_at" + ] + }, "ChannelModifySchema": { "type": "object", "properties": { @@ -33554,6 +35258,37 @@ ], "type": "number" }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "fetched_at" + ] + }, "ChannelModifySchema": { "type": "object", "properties": { @@ -34147,6 +35882,37 @@ ], "type": "number" }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "fetched_at" + ] + }, "ChannelModifySchema": { "type": "object", "properties": { @@ -34737,6 +36503,37 @@ ], "type": "number" }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "fetched_at" + ] + }, "ChannelModifySchema": { "type": "object", "properties": { @@ -35327,6 +37124,37 @@ ], "type": "number" }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "fetched_at" + ] + }, "ChannelModifySchema": { "type": "object", "properties": { @@ -35923,6 +37751,37 @@ ], "type": "number" }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "fetched_at" + ] + }, "ChannelModifySchema": { "type": "object", "properties": { diff --git a/src/api/routes/users/@me/connections/#connection_name/#connection_id/access-token.ts b/src/api/routes/users/@me/connections/#connection_name/#connection_id/access-token.ts index 760f8135..1ad1c7a7 100644 --- a/src/api/routes/users/@me/connections/#connection_name/#connection_id/access-token.ts +++ b/src/api/routes/users/@me/connections/#connection_name/#connection_id/access-token.ts @@ -19,7 +19,7 @@ const ALLOWED_CONNECTIONS = ["twitch", "youtube"]; router.get("/", route({}), async (req: Request, res: Response) => { const { connection_name, connection_id } = req.params; - const connection = ConnectionStore.connections.get(connection_id); + const connection = ConnectionStore.connections.get(connection_name); if (!ALLOWED_CONNECTIONS.includes(connection_name) || !connection) throw FieldErrors({ @@ -41,7 +41,7 @@ router.get("/", route({}), async (req: Request, res: Response) => { const connectedAccount = await ConnectedAccount.findOne({ where: { type: connection_name, - id: connection_id, + external_id: connection_id, user_id: req.user_id, }, select: [ @@ -64,14 +64,12 @@ router.get("/", route({}), async (req: Request, res: Response) => { throw new ApiError("No token data", 0, 400); let access_token = connectedAccount.token_data.access_token; - const { expires_at, expires_in } = connectedAccount.token_data; + const { expires_at, expires_in, fetched_at } = connectedAccount.token_data; - if (expires_at && expires_at < Date.now()) { - if (!(connection instanceof RefreshableConnection)) - throw new ApiError("Access token expired", 0, 400); - const tokenData = await connection.refresh(connectedAccount); - access_token = tokenData.access_token; - } else if (expires_in && expires_in < Date.now()) { + if ( + (expires_at && expires_at < Date.now()) || + (expires_in && fetched_at + expires_in * 1000 < Date.now()) + ) { if (!(connection instanceof RefreshableConnection)) throw new ApiError("Access token expired", 0, 400); const tokenData = await connection.refresh(connectedAccount); 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 index 9d5f517d..07440eac 100644 --- 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 @@ -1,5 +1,10 @@ import { route } from "@fosscord/api"; -import { ConnectedAccount, DiscordApiErrors, emitEvent, ConnectionUpdateSchema } from "@fosscord/util"; +import { + ConnectedAccount, + ConnectionUpdateSchema, + DiscordApiErrors, + emitEvent +} from "@fosscord/util"; import { Request, Response, Router } from "express"; const router = Router(); @@ -35,6 +40,8 @@ router.patch( //@ts-ignore For some reason the client sends this as a boolean, even tho docs say its a number? if (typeof body.visibility === "boolean") body.visibility = body.visibility ? 1 : 0; + //@ts-ignore For some reason the client sends this as a boolean, even tho docs say its a number? + if (typeof body.show_activity === "boolean") body.show_activity = body.show_activity ? 1 : 0; connection.assign(req.body); @@ -58,7 +65,7 @@ router.delete("/", route({}), async (req: Request, res: Response) => { user_id: req.user_id, external_id: connection_id, type: connection_name, - } + }, }); await Promise.all([ @@ -67,7 +74,7 @@ router.delete("/", route({}), async (req: Request, res: Response) => { event: "USER_CONNECTIONS_UPDATE", data: account, user_id: req.user_id, - }) + }), ]); return res.sendStatus(200); diff --git a/src/connections/BattleNet/index.ts b/src/connections/BattleNet/index.ts index ecba0fa9..8e8eeeed 100644 --- a/src/connections/BattleNet/index.ts +++ b/src/connections/BattleNet/index.ts @@ -1,4 +1,5 @@ import { + ApiError, Config, ConnectedAccount, ConnectedAccountCommonOAuthTokenResponse, @@ -81,7 +82,13 @@ export default class BattleNetConnection extends Connection { }/connections/${this.id}/callback`, }), }) - .then((res) => res.json()) + .then((res) => { + if (!res.ok) { + throw new ApiError("Failed to exchange code", 0, 400); + } + + return res.json(); + }) .then( ( res: ConnectedAccountCommonOAuthTokenResponse & @@ -95,7 +102,7 @@ export default class BattleNetConnection extends Connection { console.error( `Error exchanging token for ${this.id} connection: ${e}`, ); - throw DiscordApiErrors.INVALID_OAUTH_TOKEN; + throw DiscordApiErrors.GENERAL_ERROR; }); } @@ -107,10 +114,22 @@ export default class BattleNetConnection extends Connection { Authorization: `Bearer ${token}`, }, }) - .then((res) => res.json()) + .then((res) => { + if (!res.ok) { + throw new ApiError("Failed to fetch user", 0, 400); + } + + return res.json(); + }) .then((res: BattleNetConnectionUser & BattleNetErrorResponse) => { if (res.error) throw new Error(res.error_description); return res; + }) + .catch((e) => { + console.error( + `Error fetching user for ${this.id} connection: ${e}`, + ); + throw DiscordApiErrors.GENERAL_ERROR; }); } diff --git a/src/connections/Discord/index.ts b/src/connections/Discord/index.ts index 61efcfc5..23f5d978 100644 --- a/src/connections/Discord/index.ts +++ b/src/connections/Discord/index.ts @@ -1,4 +1,5 @@ import { + ApiError, Config, ConnectedAccount, ConnectedAccountCommonOAuthTokenResponse, @@ -81,12 +82,18 @@ export default class DiscordConnection extends Connection { }/connections/${this.id}/callback`, }), }) - .then((res) => res.json()) + .then((res) => { + if (!res.ok) { + throw new ApiError("Failed to exchange token", 0, 400); + } + + return res.json(); + }) .catch((e) => { console.error( `Error exchanging token for ${this.id} connection: ${e}`, ); - throw DiscordApiErrors.INVALID_OAUTH_TOKEN; + throw DiscordApiErrors.GENERAL_ERROR; }); } @@ -97,7 +104,20 @@ export default class DiscordConnection extends Connection { headers: { Authorization: `Bearer ${token}`, }, - }).then((res) => res.json()); + }) + .then((res) => { + if (!res.ok) { + throw new ApiError("Failed to fetch user", 0, 400); + } + + return res.json(); + }) + .catch((e) => { + console.error( + `Error fetching user for ${this.id} connection: ${e}`, + ); + throw DiscordApiErrors.GENERAL_ERROR; + }); } async handleCallback( diff --git a/src/connections/EpicGames/index.ts b/src/connections/EpicGames/index.ts index f1f3f24c..c720dc5d 100644 --- a/src/connections/EpicGames/index.ts +++ b/src/connections/EpicGames/index.ts @@ -1,4 +1,5 @@ import { + ApiError, Config, ConnectedAccount, ConnectedAccountCommonOAuthTokenResponse, @@ -86,12 +87,18 @@ export default class EpicGamesConnection extends Connection { code, }), }) - .then((res) => res.json()) + .then((res) => { + if (!res.ok) { + throw new ApiError("Failed to exchange code", 0, 400); + } + + return res.json(); + }) .catch((e) => { console.error( `Error exchanging token for ${this.id} connection: ${e}`, ); - throw DiscordApiErrors.INVALID_OAUTH_TOKEN; + throw DiscordApiErrors.GENERAL_ERROR; }); } @@ -106,7 +113,20 @@ export default class EpicGamesConnection extends Connection { headers: { Authorization: `Bearer ${token}`, }, - }).then((res) => res.json()); + }) + .then((res) => { + if (!res.ok) { + throw new ApiError("Failed to fetch user", 0, 400); + } + + return res.json(); + }) + .catch((e) => { + console.error( + `Error fetching user for ${this.id} connection: ${e}`, + ); + throw DiscordApiErrors.GENERAL_ERROR; + }); } async handleCallback( diff --git a/src/connections/Facebook/index.ts b/src/connections/Facebook/index.ts index 2d490c63..67f8da79 100644 --- a/src/connections/Facebook/index.ts +++ b/src/connections/Facebook/index.ts @@ -1,4 +1,5 @@ import { + ApiError, Config, ConnectedAccount, ConnectedAccountCommonOAuthTokenResponse, @@ -88,7 +89,13 @@ export default class FacebookConnection extends Connection { Accept: "application/json", }, }) - .then((res) => res.json()) + .then((res) => { + if (!res.ok) { + throw new ApiError("Failed to exchange code", 0, 400); + } + + return res.json(); + }) .then( ( res: ConnectedAccountCommonOAuthTokenResponse & @@ -102,7 +109,7 @@ export default class FacebookConnection extends Connection { console.error( `Error exchanging token for ${this.id} connection: ${e}`, ); - throw DiscordApiErrors.INVALID_OAUTH_TOKEN; + throw DiscordApiErrors.GENERAL_ERROR; }); } @@ -114,10 +121,22 @@ export default class FacebookConnection extends Connection { Authorization: `Bearer ${token}`, }, }) - .then((res) => res.json()) + .then((res) => { + if (!res.ok) { + throw new ApiError("Failed to fetch user", 0, 400); + } + + return res.json(); + }) .then((res: UserResponse & FacebookErrorResponse) => { if (res.error) throw new Error(res.error.message); return res; + }) + .catch((e) => { + console.error( + `Error fetching user for ${this.id} connection: ${e}`, + ); + throw DiscordApiErrors.GENERAL_ERROR; }); } diff --git a/src/connections/GitHub/index.ts b/src/connections/GitHub/index.ts index ab3f8e65..aa686b03 100644 --- a/src/connections/GitHub/index.ts +++ b/src/connections/GitHub/index.ts @@ -1,4 +1,5 @@ import { + ApiError, Config, ConnectedAccount, ConnectedAccountCommonOAuthTokenResponse, @@ -70,12 +71,18 @@ export default class GitHubConnection extends Connection { Accept: "application/json", }, }) - .then((res) => res.json()) + .then((res) => { + if (!res.ok) { + throw new ApiError("Failed to exchange code", 0, 400); + } + + return res.json(); + }) .catch((e) => { console.error( - `Error exchanging token for ${this.id} connection: ${e}`, + `Error exchanging code for ${this.id} connection: ${e}`, ); - throw DiscordApiErrors.INVALID_OAUTH_TOKEN; + throw DiscordApiErrors.GENERAL_ERROR; }); } @@ -86,7 +93,20 @@ export default class GitHubConnection extends Connection { headers: { Authorization: `Bearer ${token}`, }, - }).then((res) => res.json()); + }) + .then((res) => { + if (!res.ok) { + throw new ApiError("Failed to fetch user", 0, 400); + } + + return res.json(); + }) + .catch((e) => { + console.error( + `Error fetching user for ${this.id} connection: ${e}`, + ); + throw DiscordApiErrors.GENERAL_ERROR; + }); } async handleCallback( diff --git a/src/connections/Reddit/index.ts b/src/connections/Reddit/index.ts index 182cd5a5..06fbcbe5 100644 --- a/src/connections/Reddit/index.ts +++ b/src/connections/Reddit/index.ts @@ -1,4 +1,5 @@ import { + ApiError, Config, ConnectedAccount, ConnectedAccountCommonOAuthTokenResponse, @@ -90,12 +91,18 @@ export default class RedditConnection extends Connection { }/connections/${this.id}/callback`, }), }) - .then((res) => res.json()) + .then((res) => { + if (!res.ok) { + throw new ApiError("Failed to code", 0, 400); + } + + return res.json(); + }) .catch((e) => { console.error( - `Error exchanging token for ${this.id} connection: ${e}`, + `Error exchanging code for ${this.id} connection: ${e}`, ); - throw DiscordApiErrors.INVALID_OAUTH_TOKEN; + throw DiscordApiErrors.GENERAL_ERROR; }); } @@ -106,7 +113,20 @@ export default class RedditConnection extends Connection { headers: { Authorization: `Bearer ${token}`, }, - }).then((res) => res.json()); + }) + .then((res) => { + if (!res.ok) { + throw new ApiError("Failed to fetch user", 0, 400); + } + + return res.json(); + }) + .catch((e) => { + console.error( + `Error fetching user for ${this.id} connection: ${e}`, + ); + throw DiscordApiErrors.GENERAL_ERROR; + }); } async handleCallback( diff --git a/src/connections/Spotify/index.ts b/src/connections/Spotify/index.ts index b40d6189..44a4bc28 100644 --- a/src/connections/Spotify/index.ts +++ b/src/connections/Spotify/index.ts @@ -1,4 +1,5 @@ import { + ApiError, Config, ConnectedAccount, ConnectedAccountCommonOAuthTokenResponse, @@ -99,21 +100,28 @@ export default class SpotifyConnection extends RefreshableConnection { }/connections/${this.id}/callback`, }), }) - .then((res) => res.json()) + .then((res) => { + if (!res.ok) { + throw new ApiError("Failed to refresh token", 0, 400); + } + + return res.json(); + }) .then( ( res: ConnectedAccountCommonOAuthTokenResponse & TokenErrorResponse, ) => { - if (res.error) throw new Error(res.error_description); + if (res.error) + throw new ApiError(res.error_description, 0, 400); return res; }, ) .catch((e) => { console.error( - `Error exchanging token for ${this.id} connection: ${e}`, + `Error exchanging code for ${this.id} connection: ${e}`, ); - throw DiscordApiErrors.INVALID_OAUTH_TOKEN; + throw DiscordApiErrors.GENERAL_ERROR; }); } @@ -137,13 +145,26 @@ export default class SpotifyConnection extends RefreshableConnection { refresh_token, }), }) - .then((res) => res.json()) + .then(async (res) => { + if ([400, 401].includes(res.status)) { + // assume the token was revoked + await connectedAccount.revoke(); + return DiscordApiErrors.CONNECTION_REVOKED; + } + // otherwise throw a general error + if (!res.ok) { + throw new ApiError("Failed to refresh token", 0, 400); + } + + return await res.json(); + }) .then( ( res: ConnectedAccountCommonOAuthTokenResponse & TokenErrorResponse, ) => { - if (res.error) throw new Error(res.error_description); + if (res.error) + throw new ApiError(res.error_description, 0, 400); return res; }, ) @@ -151,7 +172,7 @@ export default class SpotifyConnection extends RefreshableConnection { console.error( `Error refreshing token for ${this.id} connection: ${e}`, ); - throw DiscordApiErrors.INVALID_OAUTH_TOKEN; + throw DiscordApiErrors.GENERAL_ERROR; }); } @@ -163,10 +184,22 @@ export default class SpotifyConnection extends RefreshableConnection { Authorization: `Bearer ${token}`, }, }) - .then((res) => res.json()) + .then((res) => { + if (!res.ok) { + throw new ApiError("Failed to fetch user", 0, 400); + } + + return res.json(); + }) .then((res: UserResponse & ErrorResponse) => { if (res.error) throw new Error(res.error.message); return res; + }) + .catch((e) => { + console.error( + `Error fetching user for ${this.id} connection: ${e}`, + ); + throw DiscordApiErrors.GENERAL_ERROR; }); } @@ -182,7 +215,7 @@ export default class SpotifyConnection extends RefreshableConnection { if (exists) return null; return await this.createConnection({ - token_data: tokenData, + token_data: { ...tokenData, fetched_at: Date.now() }, user_id: userId, external_id: userInfo.id, friend_sync: params.friend_sync, diff --git a/src/connections/Twitch/TwitchSettings.ts b/src/connections/Twitch/TwitchSettings.ts new file mode 100644 index 00000000..eb732c82 --- /dev/null +++ b/src/connections/Twitch/TwitchSettings.ts @@ -0,0 +1,5 @@ +export class TwitchSettings { + enabled: boolean = false; + clientId: string | null = null; + clientSecret: string | null = null; +} diff --git a/src/connections/Twitch/index.ts b/src/connections/Twitch/index.ts new file mode 100644 index 00000000..ce04f098 --- /dev/null +++ b/src/connections/Twitch/index.ts @@ -0,0 +1,196 @@ +import { + ApiError, + Config, + ConnectedAccount, + ConnectedAccountCommonOAuthTokenResponse, + ConnectionCallbackSchema, + ConnectionLoader, + DiscordApiErrors, +} from "@fosscord/util"; +import fetch from "node-fetch"; +import RefreshableConnection from "../../util/connections/RefreshableConnection"; +import { TwitchSettings } from "./TwitchSettings"; + +interface TwitchConnectionUserResponse { + data: { + id: string; + login: string; + display_name: string; + type: string; + broadcaster_type: string; + description: string; + profile_image_url: string; + offline_image_url: string; + view_count: number; + created_at: string; + }[]; +} + +export default class TwitchConnection extends RefreshableConnection { + public readonly id = "twitch"; + public readonly authorizeUrl = "https://id.twitch.tv/oauth2/authorize"; + public readonly tokenUrl = "https://id.twitch.tv/oauth2/token"; + public readonly userInfoUrl = "https://api.twitch.tv/helix/users"; + public readonly scopes = [ + "channel_subscriptions", + "channel_check_subscription", + "channel:read:subscriptions", + ]; + settings: TwitchSettings = new TwitchSettings(); + + init(): void { + this.settings = ConnectionLoader.getConnectionConfig( + this.id, + this.settings, + ) as TwitchSettings; + } + + getAuthorizationUrl(userId: string): string { + const state = this.createState(userId); + const url = new URL(this.authorizeUrl); + + url.searchParams.append("client_id", this.settings.clientId!); + // TODO: probably shouldn't rely on cdn as this could be different from what we actually want. we should have an api endpoint setting. + url.searchParams.append( + "redirect_uri", + `${ + Config.get().cdn.endpointPrivate || "http://localhost:3001" + }/connections/${this.id}/callback`, + ); + url.searchParams.append("response_type", "code"); + url.searchParams.append("scope", this.scopes.join(" ")); + url.searchParams.append("state", state); + return url.toString(); + } + + getTokenUrl(): string { + return this.tokenUrl; + } + + async exchangeCode( + state: string, + code: string, + ): Promise { + this.validateState(state); + + const url = this.getTokenUrl(); + + return fetch(url.toString(), { + method: "POST", + headers: { + Accept: "application/json", + "Content-Type": "application/x-www-form-urlencoded", + }, + body: new URLSearchParams({ + grant_type: "authorization_code", + code: code, + client_id: this.settings.clientId!, + client_secret: this.settings.clientSecret!, + redirect_uri: `${ + Config.get().cdn.endpointPrivate || "http://localhost:3001" + }/connections/${this.id}/callback`, + }), + }) + .then((res) => { + if (!res.ok) { + throw new ApiError("Failed to exchange code", 0, 400); + } + + return res.json(); + }) + .catch((e) => { + console.error( + `Error exchanging code for ${this.id} connection: ${e}`, + ); + throw DiscordApiErrors.GENERAL_ERROR; + }); + } + + async refreshToken( + connectedAccount: ConnectedAccount, + ): Promise { + if (!connectedAccount.token_data?.refresh_token) + throw new Error("No refresh token available."); + const refresh_token = connectedAccount.token_data.refresh_token; + + const url = this.getTokenUrl(); + + return fetch(url.toString(), { + method: "POST", + headers: { + Accept: "application/json", + "Content-Type": "application/x-www-form-urlencoded", + }, + body: new URLSearchParams({ + grant_type: "refresh_token", + client_id: this.settings.clientId!, + client_secret: this.settings.clientSecret!, + refresh_token: refresh_token, + }), + }) + .then(async (res) => { + if ([400, 401].includes(res.status)) { + // assume the token was revoked + await connectedAccount.revoke(); + return DiscordApiErrors.CONNECTION_REVOKED; + } + // otherwise throw a general error + if (!res.ok) { + throw new ApiError("Failed to refresh token", 0, 400); + } + + return await res.json(); + }) + .catch((e) => { + console.error( + `Error refreshing token for ${this.id} connection: ${e}`, + ); + throw DiscordApiErrors.GENERAL_ERROR; + }); + } + + async getUser(token: string): Promise { + const url = new URL(this.userInfoUrl); + return fetch(url.toString(), { + method: "GET", + headers: { + Authorization: `Bearer ${token}`, + "Client-Id": this.settings.clientId!, + }, + }) + .then((res) => { + if (!res.ok) { + throw new ApiError("Failed to fetch user", 0, 400); + } + + return res.json(); + }) + .catch((e) => { + console.error( + `Error fetching user for ${this.id} connection: ${e}`, + ); + throw DiscordApiErrors.GENERAL_ERROR; + }); + } + + async handleCallback( + params: ConnectionCallbackSchema, + ): Promise { + const userId = this.getUserId(params.state); + const tokenData = await this.exchangeCode(params.state, params.code!); + const userInfo = await this.getUser(tokenData.access_token); + + const exists = await this.hasConnection(userId, userInfo.data[0].id); + + if (exists) return null; + + return await this.createConnection({ + token_data: { ...tokenData, fetched_at: Date.now() }, + user_id: userId, + external_id: userInfo.data[0].id, + friend_sync: params.friend_sync, + name: userInfo.data[0].display_name, + type: this.id, + }); + } +} diff --git a/src/util/connections/RefreshableConnection.ts b/src/util/connections/RefreshableConnection.ts index 0008cbc0..87f5f6dd 100644 --- a/src/util/connections/RefreshableConnection.ts +++ b/src/util/connections/RefreshableConnection.ts @@ -23,7 +23,7 @@ export default abstract class RefreshableConnection extends Connection { connectedAccount: ConnectedAccount, ): Promise { const tokenData = await this.refreshToken(connectedAccount); - connectedAccount.token_data = tokenData; + connectedAccount.token_data = { ...tokenData, fetched_at: Date.now() }; await connectedAccount.save(); return tokenData; } diff --git a/src/util/dtos/ConnectedAccountDTO.ts b/src/util/dtos/ConnectedAccountDTO.ts index ca15ff41..a3618fd1 100644 --- a/src/util/dtos/ConnectedAccountDTO.ts +++ b/src/util/dtos/ConnectedAccountDTO.ts @@ -7,7 +7,7 @@ export class ConnectedAccountDTO { friend_sync?: boolean; name: string; revoked?: boolean; - show_activity?: boolean; + show_activity?: number; type: string; verified?: boolean; visibility?: number; diff --git a/src/util/entities/ConnectedAccount.ts b/src/util/entities/ConnectedAccount.ts index beb53e41..d8a9de20 100644 --- a/src/util/entities/ConnectedAccount.ts +++ b/src/util/entities/ConnectedAccount.ts @@ -51,7 +51,7 @@ export class ConnectedAccount extends BaseClass { revoked?: boolean = false; @Column({ select: false }) - show_activity?: boolean = true; + show_activity?: number = 0; @Column() type: string; @@ -75,5 +75,11 @@ export class ConnectedAccount extends BaseClass { two_way_link?: boolean = false; @Column({ select: false, nullable: true, type: "simple-json" }) - token_data?: ConnectedAccountTokenData; + token_data?: ConnectedAccountTokenData | null; + + async revoke() { + this.revoked = true; + this.token_data = null; + await this.save(); + } } diff --git a/src/util/interfaces/ConnectedAccount.ts b/src/util/interfaces/ConnectedAccount.ts index c96e5f79..ede02f6d 100644 --- a/src/util/interfaces/ConnectedAccount.ts +++ b/src/util/interfaces/ConnectedAccount.ts @@ -13,4 +13,5 @@ export interface ConnectedAccountTokenData { refresh_token?: string; expires_in?: number; expires_at?: number; + fetched_at: number; } diff --git a/src/util/schemas/ConnectedAccountSchema.ts b/src/util/schemas/ConnectedAccountSchema.ts index e5f838d0..fa834bd6 100644 --- a/src/util/schemas/ConnectedAccountSchema.ts +++ b/src/util/schemas/ConnectedAccountSchema.ts @@ -7,7 +7,7 @@ export interface ConnectedAccountSchema { friend_sync?: boolean; name: string; revoked?: boolean; - show_activity?: boolean; + show_activity?: number; type: string; verified?: boolean; visibility?: number; diff --git a/src/util/schemas/ConnectionUpdateSchema.ts b/src/util/schemas/ConnectionUpdateSchema.ts index ac234e7e..eb6c0916 100644 --- a/src/util/schemas/ConnectionUpdateSchema.ts +++ b/src/util/schemas/ConnectionUpdateSchema.ts @@ -1,3 +1,4 @@ export interface ConnectionUpdateSchema { visibility?: boolean; + show_activity?: boolean; } diff --git a/src/util/util/Constants.ts b/src/util/util/Constants.ts index 3bdfcfa9..47f650f4 100644 --- a/src/util/util/Constants.ts +++ b/src/util/util/Constants.ts @@ -787,6 +787,11 @@ export const DiscordApiErrors = { 40006, ), USER_BANNED: new ApiError("The user is banned from this guild", 40007), + CONNECTION_REVOKED: new ApiError( + "The connection has been revoked", + 40012, + 400, + ), TARGET_USER_IS_NOT_CONNECTED_TO_VOICE: new ApiError( "Target user is not connected to voice", 40032, -- cgit 1.5.1 From 195ea514807d568dfdeb037b411931b365b52479 Mon Sep 17 00:00:00 2001 From: Madeline <46743919+MaddyUnderStars@users.noreply.github.com> Date: Wed, 12 Apr 2023 11:48:00 +1000 Subject: generate:openapi --- assets/openapi.json | 426 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 426 insertions(+) (limited to 'assets') diff --git a/assets/openapi.json b/assets/openapi.json index e0b2e564..4e4d50a8 100644 --- a/assets/openapi.json +++ b/assets/openapi.json @@ -2838,6 +2838,149 @@ "connected_accounts", "user" ] + }, + "ConnectedAccountCommonOAuthTokenResponse": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + } + }, + "required": [ + "access_token", + "scope", + "token_type" + ] + }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "required": [ + "access_token", + "fetched_at" + ] + }, + "ConnectedAccountSchema": { + "type": "object", + "properties": { + "external_id": { + "type": "string" + }, + "user_id": { + "type": "string" + }, + "token_data": { + "$ref": "#/components/schemas/ConnectedAccountTokenData" + }, + "friend_sync": { + "type": "boolean" + }, + "name": { + "type": "string" + }, + "revoked": { + "type": "boolean" + }, + "show_activity": { + "type": "integer" + }, + "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" + } + }, + "required": [ + "external_id", + "name", + "type", + "user_id" + ] + }, + "ConnectionCallbackSchema": { + "type": "object", + "properties": { + "code": { + "type": "string" + }, + "state": { + "type": "string" + }, + "insecure": { + "type": "boolean" + }, + "friend_sync": { + "type": "boolean" + }, + "openid_params": {} + }, + "required": [ + "friend_sync", + "insecure", + "state" + ] + }, + "ConnectionUpdateSchema": { + "type": "object", + "properties": { + "visibility": { + "type": "boolean" + }, + "show_activity": { + "type": "boolean" + } + } } } }, @@ -2934,6 +3077,9 @@ }, { "name": "read-states" + }, + { + "name": "connections" } ], "paths": { @@ -7561,6 +7707,286 @@ "auth" ] } + }, + "/users/@me/connections/{connection_name}/{connection_id}/": { + "patch": { + "security": [ + { + "bearer": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ConnectionUpdateSchema" + } + } + } + }, + "parameters": [ + { + "name": "connection_name", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "connection_name" + }, + { + "name": "connection_id", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "connection_id" + } + ], + "tags": [ + "users" + ] + }, + "delete": { + "security": [ + { + "bearer": [] + } + ], + "parameters": [ + { + "name": "connection_name", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "connection_name" + }, + { + "name": "connection_id", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "connection_id" + } + ], + "tags": [ + "users" + ] + } + }, + "/users/@me/connections/{connection_name}/{connection_id}/access-token/": { + "get": { + "security": [ + { + "bearer": [] + } + ], + "parameters": [ + { + "name": "connection_name", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "connection_name" + }, + { + "name": "connection_id", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "connection_id" + } + ], + "tags": [ + "users" + ] + } + }, + "/guilds/{guild_id}/roles/member-counts/": { + "get": { + "security": [ + { + "bearer": [] + } + ], + "parameters": [ + { + "name": "guild_id", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "guild_id" + } + ], + "tags": [ + "guilds" + ] + } + }, + "/guilds/{guild_id}/roles/{role_id}/members/": { + "patch": { + "x-permission-required": "MANAGE_ROLES", + "security": [ + { + "bearer": [] + } + ], + "parameters": [ + { + "name": "guild_id", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "guild_id" + }, + { + "name": "role_id", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "role_id" + } + ], + "tags": [ + "guilds" + ] + } + }, + "/guilds/{guild_id}/roles/{role_id}/member-ids/": { + "get": { + "security": [ + { + "bearer": [] + } + ], + "parameters": [ + { + "name": "guild_id", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "guild_id" + }, + { + "name": "role_id", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "role_id" + } + ], + "tags": [ + "guilds" + ] + } + }, + "/connections/{connection_name}/callback/": { + "post": { + "security": [ + { + "bearer": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ConnectionCallbackSchema" + } + } + } + }, + "parameters": [ + { + "name": "connection_name", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "connection_name" + } + ], + "tags": [ + "connections" + ] + } + }, + "/connections/{connection_name}/authorize/": { + "get": { + "security": [ + { + "bearer": [] + } + ], + "parameters": [ + { + "name": "connection_name", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "connection_name" + } + ], + "tags": [ + "connections" + ] + } + }, + "/connections/{connection_name}/{connection_id}/refresh/": { + "post": { + "security": [ + { + "bearer": [] + } + ], + "parameters": [ + { + "name": "connection_name", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "connection_name" + }, + { + "name": "connection_id", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "connection_id" + } + ], + "tags": [ + "connections" + ] + } } } } \ No newline at end of file -- cgit 1.5.1