From 32210f636d4b916826b083898c2f38255ed2e3c1 Mon Sep 17 00:00:00 2001 From: Laura Hausmann Date: Sat, 8 Jul 2023 18:48:59 +0200 Subject: [PATCH 1/8] [mastodon-client] remove reactions reply --- .../server/api/mastodon/endpoints/status.ts | 84 +------------------ 1 file changed, 1 insertion(+), 83 deletions(-) diff --git a/packages/backend/src/server/api/mastodon/endpoints/status.ts b/packages/backend/src/server/api/mastodon/endpoints/status.ts index 3c58cf3a4..76057ef0a 100644 --- a/packages/backend/src/server/api/mastodon/endpoints/status.ts +++ b/packages/backend/src/server/api/mastodon/endpoints/status.ts @@ -123,27 +123,7 @@ export function apiStatusMastodon(router: Router): void { id, convertTimelinesArgsId(limitToInt(ctx.query as any)), ); - const status = await client.getStatus(id); - let reqInstance = axios.create({ - headers: { - Authorization: ctx.headers.authorization, - }, - }); - const reactionsAxios = await reqInstance.get( - `${BASE_URL}/api/notes/reactions?noteId=${id}`, - ); - const reactions: IReaction[] = reactionsAxios.data; - const text = reactions - .map((r) => `${r.type.replace("@.", "")} ${r.user.username}`) - .join("
"); - data.data.descendants.unshift( - statusModel( - status.data.id, - status.data.account.id, - status.data.emojis, - text, - ), - ); + data.data.ancestors = data.data.ancestors.map((status) => convertStatus(status), ); @@ -456,65 +436,3 @@ async function getFirstReaction( return react; } } - -export function statusModel( - id: string | null, - acctId: string | null, - emojis: MastodonEntity.Emoji[], - content: string, -) { - const now = new Date().toISOString(); - return { - id: "9atm5frjhb", - uri: "/static-assets/transparent.png", // "" - url: "/static-assets/transparent.png", // "", - account: { - id: "9arzuvv0sw", - username: "Reactions", - acct: "Reactions", - display_name: "Reactions to this post", - locked: false, - created_at: now, - followers_count: 0, - following_count: 0, - statuses_count: 0, - note: "", - url: "/static-assets/transparent.png", - avatar: "/static-assets/badges/info.png", - avatar_static: "/static-assets/badges/info.png", - header: "/static-assets/transparent.png", // "" - header_static: "/static-assets/transparent.png", // "" - emojis: [], - fields: [], - moved: null, - bot: false, - }, - in_reply_to_id: id, - in_reply_to_account_id: acctId, - reblog: null, - content: `

${content}

`, - plain_content: null, - created_at: now, - emojis: emojis, - replies_count: 0, - reblogs_count: 0, - favourites_count: 0, - favourited: false, - reblogged: false, - muted: false, - sensitive: false, - spoiler_text: "", - visibility: "public" as const, - media_attachments: [], - mentions: [], - tags: [], - card: null, - poll: null, - application: null, - language: null, - pinned: false, - emoji_reactions: [], - bookmarked: false, - quote: null, - }; -} From 8f7f078f08ebb883bd3fcae7841b209eabcbeed3 Mon Sep 17 00:00:00 2001 From: Laura Hausmann Date: Sat, 8 Jul 2023 21:31:45 +0200 Subject: [PATCH 2/8] [mastodon-client] send actual default post privacy instead of fallback value --- .../api/endpoints/i/registry/get-unsecure.ts | 2 +- .../server/api/mastodon/endpoints/account.ts | 2 +- packages/megalodon/src/misskey.ts | 17 +++++++++++++++++ 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/packages/backend/src/server/api/endpoints/i/registry/get-unsecure.ts b/packages/backend/src/server/api/endpoints/i/registry/get-unsecure.ts index f98c6c929..a9bcf6935 100644 --- a/packages/backend/src/server/api/endpoints/i/registry/get-unsecure.ts +++ b/packages/backend/src/server/api/endpoints/i/registry/get-unsecure.ts @@ -33,7 +33,7 @@ export const paramDef = { } as const; export default define(meta, paramDef, async (ps, user) => { - if (ps.key !== "reactions") return; + if (ps.key !== "reactions" && ps.key !== "defaultNoteVisibility") return; const query = RegistryItems.createQueryBuilder("item") .where("item.domain IS NULL") .andWhere("item.userId = :userId", { userId: user.id }) diff --git a/packages/backend/src/server/api/mastodon/endpoints/account.ts b/packages/backend/src/server/api/mastodon/endpoints/account.ts index 3fb1c9cbe..5d0abdedd 100644 --- a/packages/backend/src/server/api/mastodon/endpoints/account.ts +++ b/packages/backend/src/server/api/mastodon/endpoints/account.ts @@ -48,7 +48,7 @@ export function apiAccountMastodon(router: Router): void { acct.source = { note: acct.note, fields: acct.fields, - privacy: "public", + privacy: await client.getDefaultPostPrivacy(), sensitive: false, language: "", }; diff --git a/packages/megalodon/src/misskey.ts b/packages/megalodon/src/misskey.ts index f2befd31e..2c0b140bf 100644 --- a/packages/megalodon/src/misskey.ts +++ b/packages/megalodon/src/misskey.ts @@ -1529,6 +1529,23 @@ export default class Misskey implements MegalodonInterface { .then(res => res.data[0] ?? '⭐'); } + private async getDefaultPostPrivacy(): Promise { + // NOTE: get-unsecure is calckey's extension. + // Misskey doesn't have this endpoint and regular `/i/registry/get` won't work + // unless you have a 'nativeToken', which is reserved for the frontend webapp. + + return this.client + .post('/api/i/registry/get-unsecure', { + key: 'defaultNoteVisibility', + scope: ['client', 'base'], + }) + .then(res => { + if (!res.data || (res.data != 'public' && res.data != 'home' && res.data != 'followers' && res.data != 'specified')) + return 'public'; + return this.converter.visibility(res.data); + }); + } + public async unfavouriteStatus(id: string): Promise> { // NOTE: Misskey allows only one reaction per status, so we don't need to care what that emoji was. return this.deleteEmojiReaction(id, ''); From c7d031e7ec862e3bffccd6c876cdefa45c3cd665 Mon Sep 17 00:00:00 2001 From: Laura Hausmann Date: Sat, 8 Jul 2023 21:52:55 +0200 Subject: [PATCH 3/8] [mastodon-client] send proper user preferences --- packages/megalodon/src/misskey.ts | 24 +++++--------------- packages/megalodon/src/misskey/api_client.ts | 4 ++-- 2 files changed, 8 insertions(+), 20 deletions(-) diff --git a/packages/megalodon/src/misskey.ts b/packages/megalodon/src/misskey.ts index 2c0b140bf..c3bbfb746 100644 --- a/packages/megalodon/src/misskey.ts +++ b/packages/megalodon/src/misskey.ts @@ -1079,23 +1079,11 @@ export default class Misskey implements MegalodonInterface { // accounts/preferences // ====================================== public async getPreferences(): Promise> { - return this.client.post('/api/i').then(res => { - /* - return this.client.post('/api/i/registry/get-all', { - scope: ['client', 'base'], - }).then(ga => { - return Object.assign(res, { - data: this.converter.userPreferences(res.data, ga.data) - }) - }) - */ - - // TODO: - // FIXME: get this from api - return Object.assign(res, { - data: this.converter.userPreferences(res.data, {defaultNoteVisibility: "followers", tutorial: -1}) - }) - }) + return this.client.post('/api/i').then(async res => { + return Object.assign(res, { + data: this.converter.userPreferences(res.data, await this.getDefaultPostPrivacy()) + }) + }) } // ====================================== @@ -1529,7 +1517,7 @@ export default class Misskey implements MegalodonInterface { .then(res => res.data[0] ?? '⭐'); } - private async getDefaultPostPrivacy(): Promise { + private async getDefaultPostPrivacy(): Promise<'public' | 'unlisted' | 'private' | 'direct'> { // NOTE: get-unsecure is calckey's extension. // Misskey doesn't have this endpoint and regular `/i/registry/get` won't work // unless you have a 'nativeToken', which is reserved for the frontend webapp. diff --git a/packages/megalodon/src/misskey/api_client.ts b/packages/megalodon/src/misskey/api_client.ts index 7f1409c70..dec98fc22 100644 --- a/packages/megalodon/src/misskey/api_client.ts +++ b/packages/megalodon/src/misskey/api_client.ts @@ -174,13 +174,13 @@ namespace MisskeyAPI { } } - userPreferences = (u: MisskeyAPI.Entity.UserDetailMe, g: MisskeyAPI.Entity.GetAll): MegalodonEntity.Preferences => { + userPreferences = (u: MisskeyAPI.Entity.UserDetailMe, v: 'public' | 'unlisted' | 'private' | 'direct'): MegalodonEntity.Preferences => { return { "reading:expand:media": "default", "reading:expand:spoilers": false, "posting:default:language": u.lang, "posting:default:sensitive": u.alwaysMarkNsfw, - "posting:default:visibility": this.visibility(g.defaultNoteVisibility) + "posting:default:visibility": v } } From 994f08d735414258874a2d1a073bfb40bfd17924 Mon Sep 17 00:00:00 2001 From: Laura Hausmann Date: Sat, 8 Jul 2023 23:35:27 +0200 Subject: [PATCH 4/8] [mastodon-client] media caption support --- packages/backend/src/server/api/index.ts | 2 +- packages/megalodon/src/misskey.ts | 29 ++++++++++++++++++------ 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/packages/backend/src/server/api/index.ts b/packages/backend/src/server/api/index.ts index 29cfbf93c..9e8c45886 100644 --- a/packages/backend/src/server/api/index.ts +++ b/packages/backend/src/server/api/index.ts @@ -112,7 +112,7 @@ mastoFileRouter.post("/v2/media", upload.single("file"), async (ctx) => { ctx.status = 401; return; } - const data = await client.uploadMedia(multipartData); + const data = await client.uploadMedia(multipartData, ctx.request.body); ctx.body = convertAttachment(data.data as Entity.Attachment); } catch (e: any) { console.error(e); diff --git a/packages/megalodon/src/misskey.ts b/packages/megalodon/src/misskey.ts index c3bbfb746..97b17a0d6 100644 --- a/packages/megalodon/src/misskey.ts +++ b/packages/megalodon/src/misskey.ts @@ -1643,20 +1643,29 @@ export default class Misskey implements MegalodonInterface { /** * POST /api/drive/files/create */ - public async uploadMedia(file: any, _options?: { description?: string; focus?: string }): Promise> { + public async uploadMedia(file: any, options?: { description?: string; focus?: string }): Promise> { const formData = new FormData() - formData.append('file', fs.createReadStream(file.path), { - contentType: file.mimetype, - filename: file.originalname, - }) + formData.append('file', fs.createReadStream(file.path), { + contentType: file.mimetype, + filename: file.originalname + }) + + if (file.originalname != null) { + formData.append('name', file.originalname); + } + + if (options?.description != null) { + formData.append('comment', options.description); + } + let headers: { [key: string]: string } = {} if (typeof formData.getHeaders === 'function') { headers = formData.getHeaders() } return this.client .post('/api/drive/files/create', formData, headers) - .then(res => ({ ...res, data: this.converter.file(res.data) })) - } + .then(res => ({ ...res, data: this.converter.file(res.data) })) + } public async getMedia(id: string): Promise> { const res = await this.client.post('/api/drive/files/show', { fileId: id }) @@ -1684,6 +1693,12 @@ export default class Misskey implements MegalodonInterface { isSensitive: options.is_sensitive }) } + + if (options.description !== undefined) { + params = Object.assign(params, { + comment: options.description + }) + } } return this.client .post('/api/drive/files/update', params) From 8180f4d494ff27674d3df3fafd96616be7036929 Mon Sep 17 00:00:00 2001 From: Laura Hausmann Date: Sat, 8 Jul 2023 23:50:25 +0200 Subject: [PATCH 5/8] [mastodon-client] drive file name fixup --- packages/megalodon/src/misskey.ts | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/packages/megalodon/src/misskey.ts b/packages/megalodon/src/misskey.ts index 97b17a0d6..39665572c 100644 --- a/packages/megalodon/src/misskey.ts +++ b/packages/megalodon/src/misskey.ts @@ -1646,17 +1646,14 @@ export default class Misskey implements MegalodonInterface { public async uploadMedia(file: any, options?: { description?: string; focus?: string }): Promise> { const formData = new FormData() formData.append('file', fs.createReadStream(file.path), { - contentType: file.mimetype, - filename: file.originalname + contentType: file.mimetype }) - if (file.originalname != null) { + if (file.originalname != null && file.originalname !== 'file') formData.append('name', file.originalname); - } - if (options?.description != null) { + if (options?.description != null) formData.append('comment', options.description); - } let headers: { [key: string]: string } = {} if (typeof formData.getHeaders === 'function') { From d0fb97649ed58701381d8cf0b2dc82bcba015609 Mon Sep 17 00:00:00 2001 From: Laura Hausmann Date: Sun, 9 Jul 2023 00:14:03 +0200 Subject: [PATCH 6/8] [mastodon-client] TODO/FIXME cleanup --- packages/megalodon/src/misskey/api_client.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/megalodon/src/misskey/api_client.ts b/packages/megalodon/src/misskey/api_client.ts index dec98fc22..34e11784e 100644 --- a/packages/megalodon/src/misskey/api_client.ts +++ b/packages/megalodon/src/misskey/api_client.ts @@ -134,8 +134,8 @@ namespace MisskeyAPI { url: acctUrl, avatar: u.avatarUrl, avatar_static: u.avatarUrl, - header: this.plcUrl, // FIXME - header_static: this.plcUrl, // FIXME + header: this.plcUrl, + header_static: this.plcUrl, emojis: u.emojis.map(e => this.emoji(e)), moved: null, fields: [], @@ -308,7 +308,7 @@ namespace MisskeyAPI { emojis: n.emojis.map(e => this.emoji(e)), replies_count: n.repliesCount, reblogs_count: n.renoteCount, - favourites_count: this.getTotalReactions(n.reactions), // FIXME: instead get # of default reaction emoji reactions + favourites_count: this.getTotalReactions(n.reactions), reblogged: false, favourited: !!n.myReaction, muted: false, From d7e63edbd753417340ded69cd186da9f04490376 Mon Sep 17 00:00:00 2001 From: Laura Hausmann Date: Sun, 9 Jul 2023 00:20:14 +0200 Subject: [PATCH 7/8] [mastodon-client] enforce limits for /following and /followers --- packages/megalodon/src/misskey.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/megalodon/src/misskey.ts b/packages/megalodon/src/misskey.ts index 39665572c..7e9bc6c8a 100644 --- a/packages/megalodon/src/misskey.ts +++ b/packages/megalodon/src/misskey.ts @@ -460,7 +460,7 @@ export default class Misskey implements MegalodonInterface { if (options) { if (options.limit) { params = Object.assign(params, { - limit: options.limit + limit: options.limit <= 100 ? options.limit : 100 }) } else { @@ -498,7 +498,7 @@ export default class Misskey implements MegalodonInterface { if (options) { if (options.limit) { params = Object.assign(params, { - limit: options.limit + limit: options.limit <= 100 ? options.limit : 100 }) } } From 57f35be999667975dc275e3ebee95d2c8841f9d2 Mon Sep 17 00:00:00 2001 From: Laura Hausmann Date: Sun, 9 Jul 2023 00:31:24 +0200 Subject: [PATCH 8/8] [mastodon-client] populate user details for account following/followers --- packages/megalodon/src/misskey.ts | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/packages/megalodon/src/misskey.ts b/packages/megalodon/src/misskey.ts index 7e9bc6c8a..e05a12eaa 100644 --- a/packages/megalodon/src/misskey.ts +++ b/packages/megalodon/src/misskey.ts @@ -474,11 +474,11 @@ export default class Misskey implements MegalodonInterface { limit: 40 }) } - return this.client.post>('/api/users/followers', params).then(res => { - return Object.assign(res, { - data: res.data.map(f => this.converter.follower(f)) - }) - }) + return this.client.post>('/api/users/followers', params).then(async res => { + return Object.assign(res, { + data: (await Promise.all(res.data.map(async f => (this.getAccount(f.followerId)).then(p => p.data)))) + }) + }) } /** @@ -502,11 +502,11 @@ export default class Misskey implements MegalodonInterface { }) } } - return this.client.post>('/api/users/following', params).then(res => { - return Object.assign(res, { - data: res.data.map(f => this.converter.following(f)) - }) - }) + return this.client.post>('/api/users/following', params).then(async res => { + return Object.assign(res, { + data: (await Promise.all(res.data.map(async f => (this.getAccount(f.followeeId)).then(p => p.data)))) + }) + }) } public async getAccountLists(_id: string): Promise>> {