From 82c10de2651107cb19c788d756cdeeb84122c0b0 Mon Sep 17 00:00:00 2001 From: Mar0xy Date: Sun, 29 Oct 2023 00:50:00 +0200 Subject: upd: change deps, fix a few bugs, update converter Fixes User and Notes count bug (transfem-org/Sharkey#113) Fixes build issues due to types (transfem-org/Sharkey#111) Return accounts and notes like Iceshrimp Use MFM class from Iceshrimp to fix HTML output for mastodon --- .../api/mastodon/MastodonApiServerService.ts | 44 ++--- .../backend/src/server/api/mastodon/converters.ts | 181 ++++++++++----------- .../src/server/api/mastodon/endpoints/account.ts | 73 +++++---- .../src/server/api/mastodon/endpoints/filter.ts | 8 +- .../server/api/mastodon/endpoints/notifications.ts | 9 +- .../src/server/api/mastodon/endpoints/search.ts | 6 +- .../src/server/api/mastodon/endpoints/status.ts | 67 +++----- .../src/server/api/mastodon/endpoints/timeline.ts | 44 ++--- 8 files changed, 200 insertions(+), 232 deletions(-) (limited to 'packages/backend/src/server/api') diff --git a/packages/backend/src/server/api/mastodon/MastodonApiServerService.ts b/packages/backend/src/server/api/mastodon/MastodonApiServerService.ts index a8c45b98f7..9a2890f507 100644 --- a/packages/backend/src/server/api/mastodon/MastodonApiServerService.ts +++ b/packages/backend/src/server/api/mastodon/MastodonApiServerService.ts @@ -8,7 +8,7 @@ import { DI } from '@/di-symbols.js'; import { bindThis } from '@/decorators.js'; import type { Config } from '@/config.js'; import { MetaService } from '@/core/MetaService.js'; -import { convertId, IdConvertType as IdType, convertAccount, convertAnnouncement, convertFilter, convertAttachment, convertFeaturedTag, convertList } from './converters.js'; +import { convertAccount, convertAnnouncement, convertFilter, convertAttachment, convertFeaturedTag, convertList } from './converters.js'; import { getInstance } from './endpoints/meta.js'; import { ApiAuthMastodon, ApiAccountMastodon, ApiFilterMastodon, ApiNotifyMastodon, ApiSearchMastodon, ApiTimelineMastodon, ApiStatusMastodon } from './endpoints.js'; import type { FastifyInstance, FastifyPluginOptions } from 'fastify'; @@ -128,7 +128,7 @@ export class MastodonApiServerService { const client = getClient(BASE_URL, accessTokens); try { const data = await client.dismissInstanceAnnouncement( - convertId(_request.body['id'], IdType.SharkeyId), + _request.body['id'], ); reply.send(data.data); } catch (e: any) { @@ -236,7 +236,7 @@ export class MastodonApiServerService { const client = getClient(BASE_URL, accessTokens); // we are using this here, because in private mode some info isnt // displayed without being logged in try { - const account = new ApiAccountMastodon(_request, client, BASE_URL); + const account = new ApiAccountMastodon(_request, client, BASE_URL, this.config, this.usersRepository, this.notesRepository, this.noteEditRepository, this.userEntityService); reply.send(await account.verifyCredentials()); } catch (e: any) { /* console.error(e); */ @@ -286,7 +286,7 @@ export class MastodonApiServerService { ids = [ids]; } users = ids; - const account = new ApiAccountMastodon(_request, client, BASE_URL); + const account = new ApiAccountMastodon(_request, client, BASE_URL, this.config, this.usersRepository, this.notesRepository, this.noteEditRepository, this.userEntityService); reply.send(await account.getRelationships(users)); } catch (e: any) { /* console.error(e); */ @@ -302,7 +302,7 @@ export class MastodonApiServerService { const accessTokens = _request.headers.authorization; const client = getClient(BASE_URL, accessTokens); try { - const sharkId = convertId(_request.params.id, IdType.SharkeyId); + const sharkId = _request.params.id; const data = await client.getAccount(sharkId); const profile = await this.userProfilesRepository.findOneBy({ userId: sharkId }); data.data.fields = profile?.fields.map(f => ({ ...f, verified_at: null })) || []; @@ -319,7 +319,7 @@ export class MastodonApiServerService { const accessTokens = _request.headers.authorization; const client = getClient(BASE_URL, accessTokens); try { - const account = new ApiAccountMastodon(_request, client, BASE_URL); + const account = new ApiAccountMastodon(_request, client, BASE_URL, this.config, this.usersRepository, this.notesRepository, this.noteEditRepository, this.userEntityService); reply.send(await account.getStatuses()); } catch (e: any) { /* console.error(e); @@ -347,7 +347,7 @@ export class MastodonApiServerService { const accessTokens = _request.headers.authorization; const client = getClient(BASE_URL, accessTokens); try { - const account = new ApiAccountMastodon(_request, client, BASE_URL); + const account = new ApiAccountMastodon(_request, client, BASE_URL, this.config, this.usersRepository, this.notesRepository, this.noteEditRepository, this.userEntityService); reply.send(await account.getFollowers()); } catch (e: any) { /* console.error(e); @@ -361,7 +361,7 @@ export class MastodonApiServerService { const accessTokens = _request.headers.authorization; const client = getClient(BASE_URL, accessTokens); try { - const account = new ApiAccountMastodon(_request, client, BASE_URL); + const account = new ApiAccountMastodon(_request, client, BASE_URL, this.config, this.usersRepository, this.notesRepository, this.noteEditRepository, this.userEntityService); reply.send(await account.getFollowing()); } catch (e: any) { /* console.error(e); @@ -375,7 +375,7 @@ export class MastodonApiServerService { const accessTokens = _request.headers.authorization; const client = getClient(BASE_URL, accessTokens); try { - const data = await client.getAccountLists(convertId(_request.params.id, IdType.SharkeyId)); + const data = await client.getAccountLists(_request.params.id); reply.send(data.data.map((list) => convertList(list))); } catch (e: any) { /* console.error(e); @@ -389,7 +389,7 @@ export class MastodonApiServerService { const accessTokens = _request.headers.authorization; const client = getClient(BASE_URL, accessTokens); try { - const account = new ApiAccountMastodon(_request, client, BASE_URL); + const account = new ApiAccountMastodon(_request, client, BASE_URL, this.config, this.usersRepository, this.notesRepository, this.noteEditRepository, this.userEntityService); reply.send(await account.addFollow()); } catch (e: any) { /* console.error(e); @@ -403,7 +403,7 @@ export class MastodonApiServerService { const accessTokens = _request.headers.authorization; const client = getClient(BASE_URL, accessTokens); try { - const account = new ApiAccountMastodon(_request, client, BASE_URL); + const account = new ApiAccountMastodon(_request, client, BASE_URL, this.config, this.usersRepository, this.notesRepository, this.noteEditRepository, this.userEntityService); reply.send(await account.rmFollow()); } catch (e: any) { /* console.error(e); @@ -417,7 +417,7 @@ export class MastodonApiServerService { const accessTokens = _request.headers.authorization; const client = getClient(BASE_URL, accessTokens); try { - const account = new ApiAccountMastodon(_request, client, BASE_URL); + const account = new ApiAccountMastodon(_request, client, BASE_URL, this.config, this.usersRepository, this.notesRepository, this.noteEditRepository, this.userEntityService); reply.send(await account.addBlock()); } catch (e: any) { /* console.error(e); @@ -431,7 +431,7 @@ export class MastodonApiServerService { const accessTokens = _request.headers.authorization; const client = getClient(BASE_URL, accessTokens); try { - const account = new ApiAccountMastodon(_request, client, BASE_URL); + const account = new ApiAccountMastodon(_request, client, BASE_URL, this.config, this.usersRepository, this.notesRepository, this.noteEditRepository, this.userEntityService); reply.send(await account.rmBlock()); } catch (e: any) { /* console.error(e); @@ -445,7 +445,7 @@ export class MastodonApiServerService { const accessTokens = _request.headers.authorization; const client = getClient(BASE_URL, accessTokens); try { - const account = new ApiAccountMastodon(_request, client, BASE_URL); + const account = new ApiAccountMastodon(_request, client, BASE_URL, this.config, this.usersRepository, this.notesRepository, this.noteEditRepository, this.userEntityService); reply.send(await account.addMute()); } catch (e: any) { /* console.error(e); @@ -459,7 +459,7 @@ export class MastodonApiServerService { const accessTokens = _request.headers.authorization; const client = getClient(BASE_URL, accessTokens); try { - const account = new ApiAccountMastodon(_request, client, BASE_URL); + const account = new ApiAccountMastodon(_request, client, BASE_URL, this.config, this.usersRepository, this.notesRepository, this.noteEditRepository, this.userEntityService); reply.send(await account.rmMute()); } catch (e: any) { /* console.error(e); @@ -487,7 +487,7 @@ export class MastodonApiServerService { const accessTokens = _request.headers.authorization; const client = getClient(BASE_URL, accessTokens); try { - const account = new ApiAccountMastodon(_request, client, BASE_URL); + const account = new ApiAccountMastodon(_request, client, BASE_URL, this.config, this.usersRepository, this.notesRepository, this.noteEditRepository, this.userEntityService); reply.send(await account.getBookmarks()); } catch (e: any) { /* console.error(e); @@ -501,7 +501,7 @@ export class MastodonApiServerService { const accessTokens = _request.headers.authorization; const client = getClient(BASE_URL, accessTokens); try { - const account = new ApiAccountMastodon(_request, client, BASE_URL); + const account = new ApiAccountMastodon(_request, client, BASE_URL, this.config, this.usersRepository, this.notesRepository, this.noteEditRepository, this.userEntityService); reply.send(await account.getFavourites()); } catch (e: any) { /* console.error(e); @@ -515,7 +515,7 @@ export class MastodonApiServerService { const accessTokens = _request.headers.authorization; const client = getClient(BASE_URL, accessTokens); try { - const account = new ApiAccountMastodon(_request, client, BASE_URL); + const account = new ApiAccountMastodon(_request, client, BASE_URL, this.config, this.usersRepository, this.notesRepository, this.noteEditRepository, this.userEntityService); reply.send(await account.getMutes()); } catch (e: any) { /* console.error(e); @@ -529,7 +529,7 @@ export class MastodonApiServerService { const accessTokens = _request.headers.authorization; const client = getClient(BASE_URL, accessTokens); try { - const account = new ApiAccountMastodon(_request, client, BASE_URL); + const account = new ApiAccountMastodon(_request, client, BASE_URL, this.config, this.usersRepository, this.notesRepository, this.noteEditRepository, this.userEntityService); reply.send(await account.getBlocks()); } catch (e: any) { /* console.error(e); @@ -557,7 +557,7 @@ export class MastodonApiServerService { const accessTokens = _request.headers.authorization; const client = getClient(BASE_URL, accessTokens); try { - const account = new ApiAccountMastodon(_request, client, BASE_URL); + const account = new ApiAccountMastodon(_request, client, BASE_URL, this.config, this.usersRepository, this.notesRepository, this.noteEditRepository, this.userEntityService); reply.send(await account.acceptFollow()); } catch (e: any) { /* console.error(e); @@ -571,7 +571,7 @@ export class MastodonApiServerService { const accessTokens = _request.headers.authorization; const client = getClient(BASE_URL, accessTokens); try { - const account = new ApiAccountMastodon(_request, client, BASE_URL); + const account = new ApiAccountMastodon(_request, client, BASE_URL, this.config, this.usersRepository, this.notesRepository, this.noteEditRepository, this.userEntityService); reply.send(await account.rejectFollow()); } catch (e: any) { /* console.error(e); @@ -813,7 +813,7 @@ export class MastodonApiServerService { const accessTokens = _request.headers.authorization; const client = getClient(BASE_URL, accessTokens); try { - const data = await client.updateMedia(convertId(_request.params.id, IdType.SharkeyId), _request.body!); + const data = await client.updateMedia(_request.params.id, _request.body!); reply.send(convertAttachment(data.data)); } catch (e: any) { /* console.error(e); */ diff --git a/packages/backend/src/server/api/mastodon/converters.ts b/packages/backend/src/server/api/mastodon/converters.ts index cbd2550f92..a839145609 100644 --- a/packages/backend/src/server/api/mastodon/converters.ts +++ b/packages/backend/src/server/api/mastodon/converters.ts @@ -3,14 +3,13 @@ import { MfmService } from '@/core/MfmService.js'; import { DI } from '@/di-symbols.js'; import { Inject } from '@nestjs/common'; import { Entity } from 'megalodon'; -import { parse } from 'mfm-js'; +import mfm from 'mfm-js'; import { GetterService } from '../GetterService.js'; import type { IMentionedRemoteUsers } from '@/models/Note.js'; import type { MiUser } from '@/models/User.js'; import type { NoteEditRepository, NotesRepository, UsersRepository } from '@/models/_.js'; import { UserEntityService } from '@/core/entities/UserEntityService.js'; - -const CHAR_COLLECTION = '0123456789abcdefghijklmnopqrstuvwxyz'; +import { awaitAll } from '@/misc/prelude/await-all.js'; export enum IdConvertType { MastodonId, @@ -18,13 +17,13 @@ export enum IdConvertType { } export const escapeMFM = (text: string): string => text - .replace(/&/g, "&") - .replace(//g, ">") - .replace(/"/g, """) - .replace(/'/g, "'") - .replace(/`/g, "`") - .replace(/\r?\n/g, "
"); + .replace(/&/g, "&") + .replace(//g, ">") + .replace(/"/g, """) + .replace(/'/g, "'") + .replace(/`/g, "`") + .replace(/\r?\n/g, "
"); export class MastoConverters { private MfmService: MfmService; @@ -49,7 +48,7 @@ export class MastoConverters { this.GetterService = new GetterService(this.usersRepository, this.notesRepository, this.noteEditRepository, this.userEntityService); } - private encode(u: MiUser, m: IMentionedRemoteUsers): MastodonEntity.Mention { + private encode(u: MiUser, m: IMentionedRemoteUsers): Entity.Mention { let acct = u.username; let acctUrl = `https://${u.host || this.config.host}/@${u.username}`; let url: string | null = null; @@ -73,89 +72,97 @@ export class MastoConverters { }); } + public async convertAccount(account: Entity.Account) { + return awaitAll({ + id: account.id, + username: account.username, + acct: account.acct, + fqn: account.fqn, + display_name: account.display_name || account.username, + locked: account.locked, + created_at: account.created_at, + followers_count: account.followers_count, + following_count: account.following_count, + statuses_count: account.statuses_count, + note: account.note, + url: account.url, + avatar: account.avatar, + avatar_static: account.avatar, + header: account.header, + header_static: account.header, + emojis: account.emojis, + moved: null, //FIXME + fields: [], + bot: false, + discoverable: true, + }); + } + public async convertStatus(status: Entity.Status) { - status.account = convertAccount(status.account); + const convertedAccount = this.convertAccount(status.account); const note = await this.GetterService.getNote(status.id); - status.id = convertId(status.id, IdConvertType.MastodonId); - if (status.in_reply_to_account_id) status.in_reply_to_account_id = convertId( - status.in_reply_to_account_id, - IdConvertType.MastodonId, - ); - if (status.in_reply_to_id) status.in_reply_to_id = convertId(status.in_reply_to_id, IdConvertType.MastodonId); - status.media_attachments = status.media_attachments.map((attachment) => - convertAttachment(attachment), - ); - // This will eventually be improved with a rewrite of this file + const mentions = Promise.all(note.mentions.map(p => this.getUser(p) .then(u => this.encode(u, JSON.parse(note.mentionedRemoteUsers))) .catch(() => null))) - .then(p => p.filter(m => m)) as Promise; - status.mentions = await mentions; - status.mentions = status.mentions.map((mention) => ({ - ...mention, - id: convertId(mention.id, IdConvertType.MastodonId), - })); - const convertedMFM = this.MfmService.toHtml(parse(status.content), JSON.parse(note.mentionedRemoteUsers)); - status.content = status.content ? convertedMFM?.replace(/&/g, "&").replaceAll(`&`, "\'") as string : status.content; - if (status.poll) status.poll = convertPoll(status.poll); - if (status.reblog) status.reblog = convertStatus(status.reblog); - - return status; - } -} - -export function convertId(in_id: string, id_convert_type: IdConvertType): string { - switch (id_convert_type) { - case IdConvertType.MastodonId: { - let out = BigInt(0); - const lowerCaseId = in_id.toLowerCase(); - for (let i = 0; i < lowerCaseId.length; i++) { - const charValue = numFromChar(lowerCaseId.charAt(i)); - out += BigInt(charValue) * BigInt(36) ** BigInt(i); - } - return out.toString(); - } - - case IdConvertType.SharkeyId: { - let input = BigInt(in_id); - let outStr = ''; - while (input > BigInt(0)) { - const remainder = Number(input % BigInt(36)); - outStr = charFromNum(remainder) + outStr; - input /= BigInt(36); - } - const ReversedoutStr = outStr.split('').reduce((acc, char) => char + acc, ''); - return ReversedoutStr; - } - - default: - throw new Error('Invalid ID conversion type'); - } -} - -function numFromChar(character: string): number { - for (let i = 0; i < CHAR_COLLECTION.length; i++) { - if (CHAR_COLLECTION.charAt(i) === character) { - return i; - } - } - - throw new Error('Invalid character in parsed base36 id'); -} + .then(p => p.filter(m => m)) as Promise; + + const content = note.text !== null + ? this.MfmService.toMastoHtml(mfm.parse(note.text!), JSON.parse(note.mentionedRemoteUsers), false, null) + .then(p => p ?? escapeMFM(note.text!)) + : ''; + + const tags = note.tags.map(tag => { + return { + name: tag, + url: `${this.config.url}/tags/${tag}`, + } as Entity.Tag; + }); -function charFromNum(number: number): string { - if (number >= 0 && number < CHAR_COLLECTION.length) { - return CHAR_COLLECTION.charAt(number); - } else { - throw new Error('Invalid number for base-36 encoding'); + // noinspection ES6MissingAwait + return await awaitAll({ + id: note.id, + uri: note.uri ?? `https://${this.config.host}/notes/${note.id}`, + url: note.url ?? note.uri ?? `https://${this.config.host}/notes/${note.id}`, + account: convertedAccount, + in_reply_to_id: note.replyId, + in_reply_to_account_id: note.replyUserId, + reblog: status.reblog, + content: content, + content_type: 'text/x.misskeymarkdown', + text: note.text, + created_at: status.created_at, + emojis: status.emojis, + replies_count: note.repliesCount, + reblogs_count: note.renoteCount, + favourites_count: status.favourites_count, + reblogged: false, + favourited: status.favourited, + muted: status.muted, + sensitive: status.sensitive, + spoiler_text: note.cw ? note.cw : '', + visibility: status.visibility, + media_attachments: status.media_attachments, + mentions: mentions, + tags: tags, + card: null, //FIXME + poll: status.poll ?? null, + application: null, //FIXME + language: null, //FIXME + pinned: null, + reactions: status.emoji_reactions, + emoji_reactions: status.emoji_reactions, + bookmarked: false, + quote: false, + edited_at: note.updatedAt?.toISOString(), + }); } } function simpleConvert(data: any) { // copy the object to bypass weird pass by reference bugs const result = Object.assign({}, data); - result.id = convertId(data.id, IdConvertType.MastodonId); return result; } @@ -180,7 +187,6 @@ export function convertFeaturedTag(tag: Entity.FeaturedTag) { export function convertNotification(notification: Entity.Notification) { notification.account = convertAccount(notification.account); - notification.id = convertId(notification.id, IdConvertType.MastodonId); if (notification.status) notification.status = convertStatus(notification.status); return notification; } @@ -200,19 +206,9 @@ export function convertRelationship(relationship: Entity.Relationship) { export function convertStatus(status: Entity.Status) { status.account = convertAccount(status.account); - status.id = convertId(status.id, IdConvertType.MastodonId); - if (status.in_reply_to_account_id) status.in_reply_to_account_id = convertId( - status.in_reply_to_account_id, - IdConvertType.MastodonId, - ); - if (status.in_reply_to_id) status.in_reply_to_id = convertId(status.in_reply_to_id, IdConvertType.MastodonId); status.media_attachments = status.media_attachments.map((attachment) => convertAttachment(attachment), ); - status.mentions = status.mentions.map((mention) => ({ - ...mention, - id: convertId(mention.id, IdConvertType.MastodonId), - })); if (status.poll) status.poll = convertPoll(status.poll); if (status.reblog) status.reblog = convertStatus(status.reblog); @@ -224,7 +220,6 @@ export function convertStatusSource(status: Entity.StatusSource) { } export function convertConversation(conversation: Entity.Conversation) { - conversation.id = convertId(conversation.id, IdConvertType.MastodonId); conversation.accounts = conversation.accounts.map(convertAccount); if (conversation.last_status) { conversation.last_status = convertStatus(conversation.last_status); diff --git a/packages/backend/src/server/api/mastodon/endpoints/account.ts b/packages/backend/src/server/api/mastodon/endpoints/account.ts index 24ebe0c48b..802f1f5a67 100644 --- a/packages/backend/src/server/api/mastodon/endpoints/account.ts +++ b/packages/backend/src/server/api/mastodon/endpoints/account.ts @@ -1,7 +1,10 @@ -import { convertId, IdConvertType as IdType, convertAccount, convertRelationship, convertStatus } from '../converters.js'; -import { argsToBools, convertTimelinesArgsId, limitToInt } from './timeline.js'; +import { MastoConverters, convertRelationship } from '../converters.js'; +import { argsToBools, limitToInt } from './timeline.js'; import type { MegalodonInterface } from 'megalodon'; import type { FastifyRequest } from 'fastify'; +import { NoteEditRepository, NotesRepository, UsersRepository } from '@/models/_.js'; +import { UserEntityService } from '@/core/entities/UserEntityService.js'; +import type { Config } from '@/config.js'; const relationshipModel = { id: '', @@ -24,18 +27,25 @@ export class ApiAccountMastodon { private request: FastifyRequest; private client: MegalodonInterface; private BASE_URL: string; + private mastoconverter: MastoConverters; - constructor(request: FastifyRequest, client: MegalodonInterface, BASE_URL: string) { + constructor(request: FastifyRequest, client: MegalodonInterface, BASE_URL: string, + config: Config, + usersrepo: UsersRepository, + notesrepo: NotesRepository, + noteeditrepo: NoteEditRepository, + userentity: UserEntityService, + ) { this.request = request; this.client = client; this.BASE_URL = BASE_URL; + this.mastoconverter = new MastoConverters(config, usersrepo, notesrepo, noteeditrepo, userentity); } public async verifyCredentials() { try { const data = await this.client.verifyAccountCredentials(); const acct = data.data; - acct.id = convertId(acct.id, IdType.MastodonId); acct.display_name = acct.display_name || acct.username; acct.url = `${this.BASE_URL}/@${acct.url}`; acct.note = acct.note || ''; @@ -61,7 +71,7 @@ export class ApiAccountMastodon { public async lookup() { try { const data = await this.client.search((this.request.query as any).acct, { type: 'accounts' }); - return convertAccount(data.data.accounts[0]); + return this.mastoconverter.convertAccount(data.data.accounts[0]); } catch (e: any) { /* console.error(e) console.error(e.response.data); */ @@ -79,7 +89,7 @@ export class ApiAccountMastodon { const reqIds = []; for (let i = 0; i < users.length; i++) { - reqIds.push(convertId(users[i], IdType.SharkeyId)); + reqIds.push(users[i]); } const data = await this.client.getRelationships(reqIds); @@ -93,11 +103,8 @@ export class ApiAccountMastodon { public async getStatuses() { try { - const data = await this.client.getAccountStatuses( - convertId((this.request.params as any).id, IdType.SharkeyId), - convertTimelinesArgsId(argsToBools(limitToInt(this.request.query as any))) - ); - return data.data.map((status) => convertStatus(status)); + const data = await this.client.getAccountStatuses((this.request.params as any).id, argsToBools(limitToInt(this.request.query as any))); + return data.data.map((status) => this.mastoconverter.convertStatus(status)); } catch (e: any) { console.error(e); console.error(e.response.data); @@ -108,10 +115,10 @@ export class ApiAccountMastodon { public async getFollowers() { try { const data = await this.client.getAccountFollowers( - convertId((this.request.params as any).id, IdType.SharkeyId), - convertTimelinesArgsId(limitToInt(this.request.query as any)), + (this.request.params as any).id, + limitToInt(this.request.query as any), ); - return data.data.map((account) => convertAccount(account)); + return data.data.map((account) => this.mastoconverter.convertAccount(account)); } catch (e: any) { console.error(e); console.error(e.response.data); @@ -122,10 +129,10 @@ export class ApiAccountMastodon { public async getFollowing() { try { const data = await this.client.getAccountFollowing( - convertId((this.request.params as any).id, IdType.SharkeyId), - convertTimelinesArgsId(limitToInt(this.request.query as any)), + (this.request.params as any).id, + limitToInt(this.request.query as any), ); - return data.data.map((account) => convertAccount(account)); + return data.data.map((account) => this.mastoconverter.convertAccount(account)); } catch (e: any) { console.error(e); console.error(e.response.data); @@ -135,7 +142,7 @@ export class ApiAccountMastodon { public async addFollow() { try { - const data = await this.client.followAccount( convertId((this.request.params as any).id, IdType.SharkeyId) ); + const data = await this.client.followAccount( (this.request.params as any).id ); const acct = convertRelationship(data.data); acct.following = true; return acct; @@ -148,7 +155,7 @@ export class ApiAccountMastodon { public async rmFollow() { try { - const data = await this.client.unfollowAccount( convertId((this.request.params as any).id, IdType.SharkeyId) ); + const data = await this.client.unfollowAccount( (this.request.params as any).id ); const acct = convertRelationship(data.data); acct.following = false; return acct; @@ -161,7 +168,7 @@ export class ApiAccountMastodon { public async addBlock() { try { - const data = await this.client.blockAccount( convertId((this.request.params as any).id, IdType.SharkeyId) ); + const data = await this.client.blockAccount( (this.request.params as any).id ); return convertRelationship(data.data); } catch (e: any) { console.error(e); @@ -172,7 +179,7 @@ export class ApiAccountMastodon { public async rmBlock() { try { - const data = await this.client.unblockAccount( convertId((this.request.params as any).id, IdType.SharkeyId) ); + const data = await this.client.unblockAccount( (this.request.params as any).id ); return convertRelationship(data.data); } catch (e: any) { console.error(e); @@ -184,7 +191,7 @@ export class ApiAccountMastodon { public async addMute() { try { const data = await this.client.muteAccount( - convertId((this.request.params as any).id, IdType.SharkeyId), + (this.request.params as any).id, this.request.body as any, ); return convertRelationship(data.data); @@ -197,7 +204,7 @@ export class ApiAccountMastodon { public async rmMute() { try { - const data = await this.client.unmuteAccount( convertId((this.request.params as any).id, IdType.SharkeyId) ); + const data = await this.client.unmuteAccount( (this.request.params as any).id ); return convertRelationship(data.data); } catch (e: any) { console.error(e); @@ -208,8 +215,8 @@ export class ApiAccountMastodon { public async getBookmarks() { try { - const data = await this.client.getBookmarks( convertTimelinesArgsId(limitToInt(this.request.query as any)) ); - return data.data.map((status) => convertStatus(status)); + const data = await this.client.getBookmarks( limitToInt(this.request.query as any) ); + return data.data.map((status) => this.mastoconverter.convertStatus(status)); } catch (e: any) { console.error(e); console.error(e.response.data); @@ -219,8 +226,8 @@ export class ApiAccountMastodon { public async getFavourites() { try { - const data = await this.client.getFavourites( convertTimelinesArgsId(limitToInt(this.request.query as any)) ); - return data.data.map((status) => convertStatus(status)); + const data = await this.client.getFavourites( limitToInt(this.request.query as any) ); + return data.data.map((status) => this.mastoconverter.convertStatus(status)); } catch (e: any) { console.error(e); console.error(e.response.data); @@ -230,8 +237,8 @@ export class ApiAccountMastodon { public async getMutes() { try { - const data = await this.client.getMutes( convertTimelinesArgsId(limitToInt(this.request.query as any)) ); - return data.data.map((account) => convertAccount(account)); + const data = await this.client.getMutes( limitToInt(this.request.query as any) ); + return data.data.map((account) => this.mastoconverter.convertAccount(account)); } catch (e: any) { console.error(e); console.error(e.response.data); @@ -241,8 +248,8 @@ export class ApiAccountMastodon { public async getBlocks() { try { - const data = await this.client.getBlocks( convertTimelinesArgsId(limitToInt(this.request.query as any)) ); - return data.data.map((account) => convertAccount(account)); + const data = await this.client.getBlocks( limitToInt(this.request.query as any) ); + return data.data.map((account) => this.mastoconverter.convertAccount(account)); } catch (e: any) { console.error(e); console.error(e.response.data); @@ -252,7 +259,7 @@ export class ApiAccountMastodon { public async acceptFollow() { try { - const data = await this.client.acceptFollowRequest( convertId((this.request.params as any).id, IdType.SharkeyId) ); + const data = await this.client.acceptFollowRequest( (this.request.params as any).id ); return convertRelationship(data.data); } catch (e: any) { console.error(e); @@ -263,7 +270,7 @@ export class ApiAccountMastodon { public async rejectFollow() { try { - const data = await this.client.rejectFollowRequest( convertId((this.request.params as any).id, IdType.SharkeyId) ); + const data = await this.client.rejectFollowRequest( (this.request.params as any).id ); return convertRelationship(data.data); } catch (e: any) { console.error(e); diff --git a/packages/backend/src/server/api/mastodon/endpoints/filter.ts b/packages/backend/src/server/api/mastodon/endpoints/filter.ts index e27bc956fa..212c79b251 100644 --- a/packages/backend/src/server/api/mastodon/endpoints/filter.ts +++ b/packages/backend/src/server/api/mastodon/endpoints/filter.ts @@ -1,4 +1,4 @@ -import { IdConvertType as IdType, convertId, convertFilter } from '../converters.js'; +import { convertFilter } from '../converters.js'; import type { MegalodonInterface } from 'megalodon'; import type { FastifyRequest } from 'fastify'; @@ -23,7 +23,7 @@ export class ApiFilterMastodon { public async getFilter() { try { - const data = await this.client.getFilter( convertId((this.request.params as any).id, IdType.SharkeyId) ); + const data = await this.client.getFilter( (this.request.params as any).id ); return convertFilter(data.data); } catch (e: any) { console.error(e); @@ -45,7 +45,7 @@ export class ApiFilterMastodon { public async updateFilter() { try { const body: any = this.request.body; - const data = await this.client.updateFilter(convertId((this.request.params as any).id, IdType.SharkeyId), body.pharse, body.context); + const data = await this.client.updateFilter((this.request.params as any).id, body.pharse, body.context); return convertFilter(data.data); } catch (e: any) { console.error(e); @@ -55,7 +55,7 @@ export class ApiFilterMastodon { public async rmFilter() { try { - const data = await this.client.deleteFilter( convertId((this.request.params as any).id, IdType.SharkeyId) ); + const data = await this.client.deleteFilter( (this.request.params as any).id ); return data.data; } catch (e: any) { console.error(e); diff --git a/packages/backend/src/server/api/mastodon/endpoints/notifications.ts b/packages/backend/src/server/api/mastodon/endpoints/notifications.ts index dc801dd053..c4628b58c4 100644 --- a/packages/backend/src/server/api/mastodon/endpoints/notifications.ts +++ b/packages/backend/src/server/api/mastodon/endpoints/notifications.ts @@ -1,5 +1,4 @@ -import { IdConvertType as IdType, convertId, convertNotification } from '../converters.js'; -import { convertTimelinesArgsId } from './timeline.js'; +import { convertNotification } from '../converters.js'; import type { MegalodonInterface, Entity } from 'megalodon'; import type { FastifyRequest } from 'fastify'; @@ -19,7 +18,7 @@ export class ApiNotifyMastodon { public async getNotifications() { try { - const data = await this.client.getNotifications( convertTimelinesArgsId(toLimitToInt(this.request.query)) ); + const data = await this.client.getNotifications( toLimitToInt(this.request.query) ); const notifs = data.data; const processed = notifs.map((n: Entity.Notification) => { const convertedn = convertNotification(n); @@ -39,7 +38,7 @@ export class ApiNotifyMastodon { public async getNotification() { try { - const data = await this.client.getNotification( convertId((this.request.params as any).id, IdType.SharkeyId) ); + const data = await this.client.getNotification( (this.request.params as any).id ); const notif = convertNotification(data.data); if (notif.type !== 'follow' && notif.type !== 'follow_request' && notif.type === 'reaction') notif.type = 'favourite'; return notif; @@ -51,7 +50,7 @@ export class ApiNotifyMastodon { public async rmNotification() { try { - const data = await this.client.dismissNotification( convertId((this.request.params as any).id, IdType.SharkeyId) ); + const data = await this.client.dismissNotification( (this.request.params as any).id ); return data.data; } catch (e: any) { console.error(e); diff --git a/packages/backend/src/server/api/mastodon/endpoints/search.ts b/packages/backend/src/server/api/mastodon/endpoints/search.ts index 5c68402ed8..d5839ff1c8 100644 --- a/packages/backend/src/server/api/mastodon/endpoints/search.ts +++ b/packages/backend/src/server/api/mastodon/endpoints/search.ts @@ -1,6 +1,6 @@ import { Converter } from 'megalodon'; import { convertAccount, convertStatus } from '../converters.js'; -import { convertTimelinesArgsId, limitToInt } from './timeline.js'; +import { limitToInt } from './timeline.js'; import type { MegalodonInterface } from 'megalodon'; import type { FastifyRequest } from 'fastify'; @@ -71,7 +71,7 @@ export class ApiSearchMastodon { public async SearchV1() { try { - const query: any = convertTimelinesArgsId(limitToInt(this.request.query as any)); + const query: any = limitToInt(this.request.query as any); const type = query.type || ''; const data = await this.client.search(query.q, { type: type, ...query }); return data.data; @@ -83,7 +83,7 @@ export class ApiSearchMastodon { public async SearchV2() { try { - const query: any = convertTimelinesArgsId(limitToInt(this.request.query as any)); + const query: any = limitToInt(this.request.query as any); const type = query.type; const acct = !type || type === 'accounts' ? await this.client.search(query.q, { type: 'accounts', ...query }) : null; const stat = !type || type === 'statuses' ? await this.client.search(query.q, { type: 'statuses', ...query }) : null; diff --git a/packages/backend/src/server/api/mastodon/endpoints/status.ts b/packages/backend/src/server/api/mastodon/endpoints/status.ts index 2690a1036f..a15e9761b4 100644 --- a/packages/backend/src/server/api/mastodon/endpoints/status.ts +++ b/packages/backend/src/server/api/mastodon/endpoints/status.ts @@ -1,8 +1,8 @@ import querystring from 'querystring'; import { emojiRegexAtStartToEnd } from '@/misc/emoji-regex.js'; -import { convertId, IdConvertType as IdType, convertAccount, convertAttachment, convertPoll, convertStatusSource, MastoConverters } from '../converters.js'; +import { convertAttachment, convertPoll, convertStatusSource, MastoConverters } from '../converters.js'; import { getClient } from '../MastodonApiServerService.js'; -import { convertTimelinesArgsId, limitToInt } from './timeline.js'; +import { limitToInt } from './timeline.js'; import type { Entity } from 'megalodon'; import type { FastifyInstance } from 'fastify'; import type { Config } from '@/config.js'; @@ -29,7 +29,7 @@ export class ApiStatusMastodon { const accessTokens = _request.headers.authorization; const client = getClient(BASE_URL, accessTokens); try { - const data = await client.getStatus(convertId(_request.params.id, IdType.SharkeyId)); + const data = await client.getStatus(_request.params.id); reply.send(await this.mastoconverter.convertStatus(data.data)); } catch (e: any) { console.error(e); @@ -44,8 +44,8 @@ export class ApiStatusMastodon { const accessTokens = _request.headers.authorization; const client = getClient(BASE_URL, accessTokens); try { - const data = await client.getStatusSource(convertId(_request.params.id, IdType.SharkeyId)); - reply.send(convertStatusSource(data.data)); + const data = await client.getStatusSource(_request.params.id); + reply.send(data.data); } catch (e: any) { console.error(e); reply.code(_request.is404 ? 404 : 401).send(e.response.data); @@ -60,10 +60,7 @@ export class ApiStatusMastodon { const client = getClient(BASE_URL, accessTokens); const query: any = _request.query; try { - const data = await client.getStatusContext( - convertId(_request.params.id, IdType.SharkeyId), - convertTimelinesArgsId(limitToInt(query)), - ); + const data = await client.getStatusContext(_request.params.id, limitToInt(query)); data.data.ancestors = await Promise.all(data.data.ancestors.map(async (status: Entity.Status) => await this.mastoconverter.convertStatus(status))); data.data.descendants = await Promise.all(data.data.descendants.map(async (status: Entity.Status) => await this.mastoconverter.convertStatus(status))); reply.send(data.data); @@ -91,8 +88,8 @@ export class ApiStatusMastodon { const accessTokens = _request.headers.authorization; const client = getClient(BASE_URL, accessTokens); try { - const data = await client.getStatusRebloggedBy(convertId(_request.params.id, IdType.SharkeyId)); - reply.send(data.data.map((account: Entity.Account) => convertAccount(account))); + const data = await client.getStatusRebloggedBy(_request.params.id); + reply.send(data.data.map((account: Entity.Account) => this.mastoconverter.convertAccount(account))); } catch (e: any) { console.error(e); reply.code(401).send(e.response.data); @@ -106,8 +103,8 @@ export class ApiStatusMastodon { const accessTokens = _request.headers.authorization; const client = getClient(BASE_URL, accessTokens); try { - const data = await client.getStatusFavouritedBy(convertId(_request.params.id, IdType.SharkeyId)); - reply.send(data.data.map((account: Entity.Account) => convertAccount(account))); + const data = await client.getStatusFavouritedBy(_request.params.id); + reply.send(data.data.map((account: Entity.Account) => this.mastoconverter.convertAccount(account))); } catch (e: any) { console.error(e); reply.code(401).send(e.response.data); @@ -121,7 +118,7 @@ export class ApiStatusMastodon { const accessTokens = _request.headers.authorization; const client = getClient(BASE_URL, accessTokens); try { - const data = await client.getMedia(convertId(_request.params.id, IdType.SharkeyId)); + const data = await client.getMedia(_request.params.id); reply.send(convertAttachment(data.data)); } catch (e: any) { console.error(e); @@ -136,7 +133,7 @@ export class ApiStatusMastodon { const accessTokens = _request.headers.authorization; const client = getClient(BASE_URL, accessTokens); try { - const data = await client.getPoll(convertId(_request.params.id, IdType.SharkeyId)); + const data = await client.getPoll(_request.params.id); reply.send(convertPoll(data.data)); } catch (e: any) { console.error(e); @@ -152,7 +149,7 @@ export class ApiStatusMastodon { const client = getClient(BASE_URL, accessTokens); const body: any = _request.body; try { - const data = await client.votePoll(convertId(_request.params.id, IdType.SharkeyId), body.choices); + const data = await client.votePoll(_request.params.id, body.choices); reply.send(convertPoll(data.data)); } catch (e: any) { console.error(e); @@ -168,8 +165,6 @@ export class ApiStatusMastodon { const client = getClient(BASE_URL, accessTokens); let body: any = _request.body; try { - if (body.in_reply_to_id) body.in_reply_to_id = convertId(body.in_reply_to_id, IdType.SharkeyId); - if (body.quote_id) body.quote_id = convertId(body.quote_id, IdType.SharkeyId); if ( (!body.poll && body['poll[options][]']) || (!body.media_ids && body['media_ids[]']) @@ -201,9 +196,6 @@ export class ApiStatusMastodon { } if (!body.media_ids) body.media_ids = undefined; if (body.media_ids && !body.media_ids.length) body.media_ids = undefined; - if (body.media_ids) { - body.media_ids = (body.media_ids as string[]).map((p) => convertId(p, IdType.SharkeyId)); - } const { sensitive } = body; body.sensitive = typeof sensitive === 'string' ? sensitive === 'true' : sensitive; @@ -241,10 +233,7 @@ export class ApiStatusMastodon { try { if (!body.media_ids) body.media_ids = undefined; if (body.media_ids && !body.media_ids.length) body.media_ids = undefined; - if (body.media_ids) { - body.media_ids = (body.media_ids as string[]).map((p) => convertId(p, IdType.SharkeyId)); - } - const data = await client.editStatus(convertId(_request.params.id, IdType.SharkeyId), body); + const data = await client.editStatus(_request.params.id, body); reply.send(await this.mastoconverter.convertStatus(data.data)); } catch (e: any) { console.error(e); @@ -259,10 +248,7 @@ export class ApiStatusMastodon { const accessTokens = _request.headers.authorization; const client = getClient(BASE_URL, accessTokens); try { - const data = (await client.createEmojiReaction( - convertId(_request.params.id, IdType.SharkeyId), - '❤', - )) as any; + const data = (await client.createEmojiReaction(_request.params.id, '❤')) as any; reply.send(await this.mastoconverter.convertStatus(data.data)); } catch (e: any) { console.error(e); @@ -277,10 +263,7 @@ export class ApiStatusMastodon { const accessTokens = _request.headers.authorization; const client = getClient(BASE_URL, accessTokens); try { - const data = await client.deleteEmojiReaction( - convertId(_request.params.id, IdType.SharkeyId), - '❤', - ); + const data = await client.deleteEmojiReaction(_request.params.id, '❤'); reply.send(await this.mastoconverter.convertStatus(data.data)); } catch (e: any) { console.error(e); @@ -295,7 +278,7 @@ export class ApiStatusMastodon { const accessTokens = _request.headers.authorization; const client = getClient(BASE_URL, accessTokens); try { - const data = await client.reblogStatus(convertId(_request.params.id, IdType.SharkeyId)); + const data = await client.reblogStatus(_request.params.id); reply.send(await this.mastoconverter.convertStatus(data.data)); } catch (e: any) { console.error(e); @@ -310,7 +293,7 @@ export class ApiStatusMastodon { const accessTokens = _request.headers.authorization; const client = getClient(BASE_URL, accessTokens); try { - const data = await client.unreblogStatus(convertId(_request.params.id, IdType.SharkeyId)); + const data = await client.unreblogStatus(_request.params.id); reply.send(await this.mastoconverter.convertStatus(data.data)); } catch (e: any) { console.error(e); @@ -325,7 +308,7 @@ export class ApiStatusMastodon { const accessTokens = _request.headers.authorization; const client = getClient(BASE_URL, accessTokens); try { - const data = await client.bookmarkStatus(convertId(_request.params.id, IdType.SharkeyId)); + const data = await client.bookmarkStatus(_request.params.id); reply.send(await this.mastoconverter.convertStatus(data.data)); } catch (e: any) { console.error(e); @@ -340,7 +323,7 @@ export class ApiStatusMastodon { const accessTokens = _request.headers.authorization; const client = getClient(BASE_URL, accessTokens); try { - const data = await client.unbookmarkStatus(convertId(_request.params.id, IdType.SharkeyId)); + const data = await client.unbookmarkStatus(_request.params.id); reply.send(await this.mastoconverter.convertStatus(data.data)); } catch (e: any) { console.error(e); @@ -355,7 +338,7 @@ export class ApiStatusMastodon { const accessTokens = _request.headers.authorization; const client = getClient(BASE_URL, accessTokens); try { - const data = await client.pinStatus(convertId(_request.params.id, IdType.SharkeyId)); + const data = await client.pinStatus(_request.params.id); reply.send(await this.mastoconverter.convertStatus(data.data)); } catch (e: any) { console.error(e); @@ -370,7 +353,7 @@ export class ApiStatusMastodon { const accessTokens = _request.headers.authorization; const client = getClient(BASE_URL, accessTokens); try { - const data = await client.unpinStatus(convertId(_request.params.id, IdType.SharkeyId)); + const data = await client.unpinStatus(_request.params.id); reply.send(await this.mastoconverter.convertStatus(data.data)); } catch (e: any) { console.error(e); @@ -385,7 +368,7 @@ export class ApiStatusMastodon { const accessTokens = _request.headers.authorization; const client = getClient(BASE_URL, accessTokens); try { - const data = await client.createEmojiReaction(convertId(_request.params.id, IdType.SharkeyId), _request.params.name); + const data = await client.createEmojiReaction(_request.params.id, _request.params.name); reply.send(await this.mastoconverter.convertStatus(data.data)); } catch (e: any) { console.error(e); @@ -400,7 +383,7 @@ export class ApiStatusMastodon { const accessTokens = _request.headers.authorization; const client = getClient(BASE_URL, accessTokens); try { - const data = await client.deleteEmojiReaction(convertId(_request.params.id, IdType.SharkeyId), _request.params.name); + const data = await client.deleteEmojiReaction(_request.params.id, _request.params.name); reply.send(await this.mastoconverter.convertStatus(data.data)); } catch (e: any) { console.error(e); @@ -415,7 +398,7 @@ export class ApiStatusMastodon { const accessTokens = _request.headers.authorization; const client = getClient(BASE_URL, accessTokens); try { - const data = await client.deleteStatus(convertId(_request.params.id, IdType.SharkeyId)); + const data = await client.deleteStatus(_request.params.id); reply.send(data.data); } catch (e: any) { console.error(e); diff --git a/packages/backend/src/server/api/mastodon/endpoints/timeline.ts b/packages/backend/src/server/api/mastodon/endpoints/timeline.ts index e4f510ea2b..b1b487f394 100644 --- a/packages/backend/src/server/api/mastodon/endpoints/timeline.ts +++ b/packages/backend/src/server/api/mastodon/endpoints/timeline.ts @@ -1,5 +1,5 @@ import { ParsedUrlQuery } from 'querystring'; -import { convertId, IdConvertType as IdType, convertAccount, convertConversation, convertList, MastoConverters } from '../converters.js'; +import { convertConversation, convertList, MastoConverters } from '../converters.js'; import { getClient } from '../MastodonApiServerService.js'; import type { Entity } from 'megalodon'; import type { FastifyInstance } from 'fastify'; @@ -32,13 +32,6 @@ export function argsToBools(q: ParsedUrlQuery) { return q; } -export function convertTimelinesArgsId(q: ParsedUrlQuery) { - if (typeof q.min_id === 'string') q.min_id = convertId(q.min_id, IdType.SharkeyId); - if (typeof q.max_id === 'string') q.max_id = convertId(q.max_id, IdType.SharkeyId); - if (typeof q.since_id === 'string') q.since_id = convertId(q.since_id, IdType.SharkeyId); - return q; -} - export class ApiTimelineMastodon { private fastify: FastifyInstance; private mastoconverter: MastoConverters; @@ -56,8 +49,8 @@ export class ApiTimelineMastodon { try { const query: any = _request.query; const data = query.local === 'true' - ? await client.getLocalTimeline(convertTimelinesArgsId(argsToBools(limitToInt(query)))) - : await client.getPublicTimeline(convertTimelinesArgsId(argsToBools(limitToInt(query)))); + ? await client.getLocalTimeline(argsToBools(limitToInt(query))) + : await client.getPublicTimeline(argsToBools(limitToInt(query))); reply.send(await Promise.all(data.data.map(async (status: Entity.Status) => await this.mastoconverter.convertStatus(status)))); } catch (e: any) { console.error(e); @@ -74,7 +67,7 @@ export class ApiTimelineMastodon { const client = getClient(BASE_URL, accessTokens); try { const query: any = _request.query; - const data = await client.getHomeTimeline(convertTimelinesArgsId(limitToInt(query))); + const data = await client.getHomeTimeline(limitToInt(query)); reply.send(await Promise.all(data.data.map(async (status: Entity.Status) => await this.mastoconverter.convertStatus(status)))); } catch (e: any) { console.error(e); @@ -92,7 +85,7 @@ export class ApiTimelineMastodon { try { const query: any = _request.query; const params: any = _request.params; - const data = await client.getTagTimeline(params.hashtag, convertTimelinesArgsId(limitToInt(query))); + const data = await client.getTagTimeline(params.hashtag, limitToInt(query)); reply.send(await Promise.all(data.data.map(async (status: Entity.Status) => await this.mastoconverter.convertStatus(status)))); } catch (e: any) { console.error(e); @@ -110,7 +103,7 @@ export class ApiTimelineMastodon { try { const query: any = _request.query; const params: any = _request.params; - const data = await client.getListTimeline(convertId(params.id, IdType.SharkeyId), convertTimelinesArgsId(limitToInt(query))); + const data = await client.getListTimeline(params.id, limitToInt(query)); reply.send(await Promise.all(data.data.map(async (status: Entity.Status) => await this.mastoconverter.convertStatus(status)))); } catch (e: any) { console.error(e); @@ -127,7 +120,7 @@ export class ApiTimelineMastodon { const client = getClient(BASE_URL, accessTokens); try { const query: any = _request.query; - const data = await client.getConversationTimeline(convertTimelinesArgsId(limitToInt(query))); + const data = await client.getConversationTimeline(limitToInt(query)); reply.send(data.data.map((conversation: Entity.Conversation) => convertConversation(conversation))); } catch (e: any) { console.error(e); @@ -144,7 +137,7 @@ export class ApiTimelineMastodon { const accessTokens = _request.headers.authorization; const client = getClient(BASE_URL, accessTokens); const params: any = _request.params; - const data = await client.getList(convertId(params.id, IdType.SharkeyId)); + const data = await client.getList(params.id); reply.send(convertList(data.data)); } catch (e: any) { console.error(e); @@ -178,11 +171,8 @@ export class ApiTimelineMastodon { const client = getClient(BASE_URL, accessTokens); const params: any = _request.params; const query: any = _request.query; - const data = await client.getAccountsInList( - convertId(params.id, IdType.SharkeyId), - convertTimelinesArgsId(query), - ); - reply.send(data.data.map((account: Entity.Account) => convertAccount(account))); + const data = await client.getAccountsInList(params.id, query); + reply.send(data.data.map((account: Entity.Account) => this.mastoconverter.convertAccount(account))); } catch (e: any) { console.error(e); console.error(e.response.data); @@ -199,10 +189,7 @@ export class ApiTimelineMastodon { const client = getClient(BASE_URL, accessTokens); const params: any = _request.params; const query: any = _request.query; - const data = await client.addAccountsToList( - convertId(params.id, IdType.SharkeyId), - (query.accounts_id as string[]).map((id) => convertId(id, IdType.SharkeyId)), - ); + const data = await client.addAccountsToList(params.id, query.accounts_id); reply.send(data.data); } catch (e: any) { console.error(e); @@ -220,10 +207,7 @@ export class ApiTimelineMastodon { const client = getClient(BASE_URL, accessTokens); const params: any = _request.params; const query: any = _request.query; - const data = await client.deleteAccountsFromList( - convertId(params.id, IdType.SharkeyId), - (query.accounts_id as string[]).map((id) => convertId(id, IdType.SharkeyId)), - ); + const data = await client.deleteAccountsFromList(params.id, query.accounts_id); reply.send(data.data); } catch (e: any) { console.error(e); @@ -258,7 +242,7 @@ export class ApiTimelineMastodon { const client = getClient(BASE_URL, accessTokens); const body: any = _request.body; const params: any = _request.params; - const data = await client.updateList(convertId(params.id, IdType.SharkeyId), body.title); + const data = await client.updateList(params.id, body.title); reply.send(convertList(data.data)); } catch (e: any) { console.error(e); @@ -275,7 +259,7 @@ export class ApiTimelineMastodon { const accessTokens = _request.headers.authorization; const client = getClient(BASE_URL, accessTokens); const params: any = _request.params; - const data = await client.deleteList(convertId(params.id, IdType.SharkeyId)); + const data = await client.deleteList(params.id); reply.send(data.data); } catch (e: any) { console.error(e); -- cgit v1.2.3-freya From 43f27a639fb75c9e4ccc8bea02eaf83382b93ea1 Mon Sep 17 00:00:00 2001 From: Mar0xy Date: Sun, 29 Oct 2023 02:06:19 +0200 Subject: upd: simplify importing of mastoconverter, fix bug Lets you import stuff into mastoconverter without needing to also import them everywhere else Fixes not being able to get statuses on accounts --- packages/backend/src/server/ServerModule.ts | 2 ++ .../api/mastodon/MastodonApiServerService.ts | 41 +++++++++++----------- .../backend/src/server/api/mastodon/converters.ts | 26 ++++---------- .../src/server/api/mastodon/endpoints/account.ts | 16 ++++----- .../src/server/api/mastodon/endpoints/status.ts | 4 +-- .../src/server/api/mastodon/endpoints/timeline.ts | 4 +-- 6 files changed, 39 insertions(+), 54 deletions(-) (limited to 'packages/backend/src/server/api') diff --git a/packages/backend/src/server/ServerModule.ts b/packages/backend/src/server/ServerModule.ts index fc6f019602..fc5eece01f 100644 --- a/packages/backend/src/server/ServerModule.ts +++ b/packages/backend/src/server/ServerModule.ts @@ -23,6 +23,7 @@ import { SigninService } from './api/SigninService.js'; import { SignupApiService } from './api/SignupApiService.js'; import { StreamingApiServerService } from './api/StreamingApiServerService.js'; import { ClientServerService } from './web/ClientServerService.js'; +import { MastoConverters } from './api/mastodon/converters.js'; import { FeedService } from './web/FeedService.js'; import { UrlPreviewService } from './web/UrlPreviewService.js'; import { MainChannelService } from './api/stream/channels/main.js'; @@ -87,6 +88,7 @@ import { OAuth2ProviderService } from './oauth/OAuth2ProviderService.js'; OpenApiServerService, MastodonApiServerService, OAuth2ProviderService, + MastoConverters, ], exports: [ ServerService, diff --git a/packages/backend/src/server/api/mastodon/MastodonApiServerService.ts b/packages/backend/src/server/api/mastodon/MastodonApiServerService.ts index 9a2890f507..13cf45368d 100644 --- a/packages/backend/src/server/api/mastodon/MastodonApiServerService.ts +++ b/packages/backend/src/server/api/mastodon/MastodonApiServerService.ts @@ -8,7 +8,7 @@ import { DI } from '@/di-symbols.js'; import { bindThis } from '@/decorators.js'; import type { Config } from '@/config.js'; import { MetaService } from '@/core/MetaService.js'; -import { convertAccount, convertAnnouncement, convertFilter, convertAttachment, convertFeaturedTag, convertList } from './converters.js'; +import { convertAccount, convertAnnouncement, convertFilter, convertAttachment, convertFeaturedTag, convertList, MastoConverters } from './converters.js'; import { getInstance } from './endpoints/meta.js'; import { ApiAuthMastodon, ApiAccountMastodon, ApiFilterMastodon, ApiNotifyMastodon, ApiSearchMastodon, ApiTimelineMastodon, ApiStatusMastodon } from './endpoints.js'; import type { FastifyInstance, FastifyPluginOptions } from 'fastify'; @@ -37,6 +37,7 @@ export class MastodonApiServerService { private config: Config, private metaService: MetaService, private userEntityService: UserEntityService, + private mastoConverter: MastoConverters, ) { } @bindThis @@ -236,7 +237,7 @@ export class MastodonApiServerService { const client = getClient(BASE_URL, accessTokens); // we are using this here, because in private mode some info isnt // displayed without being logged in try { - const account = new ApiAccountMastodon(_request, client, BASE_URL, this.config, this.usersRepository, this.notesRepository, this.noteEditRepository, this.userEntityService); + const account = new ApiAccountMastodon(_request, client, BASE_URL, this.mastoConverter); reply.send(await account.verifyCredentials()); } catch (e: any) { /* console.error(e); */ @@ -286,7 +287,7 @@ export class MastodonApiServerService { ids = [ids]; } users = ids; - const account = new ApiAccountMastodon(_request, client, BASE_URL, this.config, this.usersRepository, this.notesRepository, this.noteEditRepository, this.userEntityService); + const account = new ApiAccountMastodon(_request, client, BASE_URL, this.mastoConverter); reply.send(await account.getRelationships(users)); } catch (e: any) { /* console.error(e); */ @@ -319,7 +320,7 @@ export class MastodonApiServerService { const accessTokens = _request.headers.authorization; const client = getClient(BASE_URL, accessTokens); try { - const account = new ApiAccountMastodon(_request, client, BASE_URL, this.config, this.usersRepository, this.notesRepository, this.noteEditRepository, this.userEntityService); + const account = new ApiAccountMastodon(_request, client, BASE_URL, this.mastoConverter); reply.send(await account.getStatuses()); } catch (e: any) { /* console.error(e); @@ -347,7 +348,7 @@ export class MastodonApiServerService { const accessTokens = _request.headers.authorization; const client = getClient(BASE_URL, accessTokens); try { - const account = new ApiAccountMastodon(_request, client, BASE_URL, this.config, this.usersRepository, this.notesRepository, this.noteEditRepository, this.userEntityService); + const account = new ApiAccountMastodon(_request, client, BASE_URL, this.mastoConverter); reply.send(await account.getFollowers()); } catch (e: any) { /* console.error(e); @@ -361,7 +362,7 @@ export class MastodonApiServerService { const accessTokens = _request.headers.authorization; const client = getClient(BASE_URL, accessTokens); try { - const account = new ApiAccountMastodon(_request, client, BASE_URL, this.config, this.usersRepository, this.notesRepository, this.noteEditRepository, this.userEntityService); + const account = new ApiAccountMastodon(_request, client, BASE_URL, this.mastoConverter); reply.send(await account.getFollowing()); } catch (e: any) { /* console.error(e); @@ -389,7 +390,7 @@ export class MastodonApiServerService { const accessTokens = _request.headers.authorization; const client = getClient(BASE_URL, accessTokens); try { - const account = new ApiAccountMastodon(_request, client, BASE_URL, this.config, this.usersRepository, this.notesRepository, this.noteEditRepository, this.userEntityService); + const account = new ApiAccountMastodon(_request, client, BASE_URL, this.mastoConverter); reply.send(await account.addFollow()); } catch (e: any) { /* console.error(e); @@ -403,7 +404,7 @@ export class MastodonApiServerService { const accessTokens = _request.headers.authorization; const client = getClient(BASE_URL, accessTokens); try { - const account = new ApiAccountMastodon(_request, client, BASE_URL, this.config, this.usersRepository, this.notesRepository, this.noteEditRepository, this.userEntityService); + const account = new ApiAccountMastodon(_request, client, BASE_URL, this.mastoConverter); reply.send(await account.rmFollow()); } catch (e: any) { /* console.error(e); @@ -417,7 +418,7 @@ export class MastodonApiServerService { const accessTokens = _request.headers.authorization; const client = getClient(BASE_URL, accessTokens); try { - const account = new ApiAccountMastodon(_request, client, BASE_URL, this.config, this.usersRepository, this.notesRepository, this.noteEditRepository, this.userEntityService); + const account = new ApiAccountMastodon(_request, client, BASE_URL, this.mastoConverter); reply.send(await account.addBlock()); } catch (e: any) { /* console.error(e); @@ -431,7 +432,7 @@ export class MastodonApiServerService { const accessTokens = _request.headers.authorization; const client = getClient(BASE_URL, accessTokens); try { - const account = new ApiAccountMastodon(_request, client, BASE_URL, this.config, this.usersRepository, this.notesRepository, this.noteEditRepository, this.userEntityService); + const account = new ApiAccountMastodon(_request, client, BASE_URL, this.mastoConverter); reply.send(await account.rmBlock()); } catch (e: any) { /* console.error(e); @@ -445,7 +446,7 @@ export class MastodonApiServerService { const accessTokens = _request.headers.authorization; const client = getClient(BASE_URL, accessTokens); try { - const account = new ApiAccountMastodon(_request, client, BASE_URL, this.config, this.usersRepository, this.notesRepository, this.noteEditRepository, this.userEntityService); + const account = new ApiAccountMastodon(_request, client, BASE_URL, this.mastoConverter); reply.send(await account.addMute()); } catch (e: any) { /* console.error(e); @@ -459,7 +460,7 @@ export class MastodonApiServerService { const accessTokens = _request.headers.authorization; const client = getClient(BASE_URL, accessTokens); try { - const account = new ApiAccountMastodon(_request, client, BASE_URL, this.config, this.usersRepository, this.notesRepository, this.noteEditRepository, this.userEntityService); + const account = new ApiAccountMastodon(_request, client, BASE_URL, this.mastoConverter); reply.send(await account.rmMute()); } catch (e: any) { /* console.error(e); @@ -487,7 +488,7 @@ export class MastodonApiServerService { const accessTokens = _request.headers.authorization; const client = getClient(BASE_URL, accessTokens); try { - const account = new ApiAccountMastodon(_request, client, BASE_URL, this.config, this.usersRepository, this.notesRepository, this.noteEditRepository, this.userEntityService); + const account = new ApiAccountMastodon(_request, client, BASE_URL, this.mastoConverter); reply.send(await account.getBookmarks()); } catch (e: any) { /* console.error(e); @@ -501,7 +502,7 @@ export class MastodonApiServerService { const accessTokens = _request.headers.authorization; const client = getClient(BASE_URL, accessTokens); try { - const account = new ApiAccountMastodon(_request, client, BASE_URL, this.config, this.usersRepository, this.notesRepository, this.noteEditRepository, this.userEntityService); + const account = new ApiAccountMastodon(_request, client, BASE_URL, this.mastoConverter); reply.send(await account.getFavourites()); } catch (e: any) { /* console.error(e); @@ -515,7 +516,7 @@ export class MastodonApiServerService { const accessTokens = _request.headers.authorization; const client = getClient(BASE_URL, accessTokens); try { - const account = new ApiAccountMastodon(_request, client, BASE_URL, this.config, this.usersRepository, this.notesRepository, this.noteEditRepository, this.userEntityService); + const account = new ApiAccountMastodon(_request, client, BASE_URL, this.mastoConverter); reply.send(await account.getMutes()); } catch (e: any) { /* console.error(e); @@ -529,7 +530,7 @@ export class MastodonApiServerService { const accessTokens = _request.headers.authorization; const client = getClient(BASE_URL, accessTokens); try { - const account = new ApiAccountMastodon(_request, client, BASE_URL, this.config, this.usersRepository, this.notesRepository, this.noteEditRepository, this.userEntityService); + const account = new ApiAccountMastodon(_request, client, BASE_URL, this.mastoConverter); reply.send(await account.getBlocks()); } catch (e: any) { /* console.error(e); @@ -557,7 +558,7 @@ export class MastodonApiServerService { const accessTokens = _request.headers.authorization; const client = getClient(BASE_URL, accessTokens); try { - const account = new ApiAccountMastodon(_request, client, BASE_URL, this.config, this.usersRepository, this.notesRepository, this.noteEditRepository, this.userEntityService); + const account = new ApiAccountMastodon(_request, client, BASE_URL, this.mastoConverter); reply.send(await account.acceptFollow()); } catch (e: any) { /* console.error(e); @@ -571,7 +572,7 @@ export class MastodonApiServerService { const accessTokens = _request.headers.authorization; const client = getClient(BASE_URL, accessTokens); try { - const account = new ApiAccountMastodon(_request, client, BASE_URL, this.config, this.usersRepository, this.notesRepository, this.noteEditRepository, this.userEntityService); + const account = new ApiAccountMastodon(_request, client, BASE_URL, this.mastoConverter); reply.send(await account.rejectFollow()); } catch (e: any) { /* console.error(e); @@ -756,7 +757,7 @@ export class MastodonApiServerService { //#endregion //#region Timelines - const TLEndpoint = new ApiTimelineMastodon(fastify, this.config, this.usersRepository, this.notesRepository, this.noteEditRepository, this.userEntityService); + const TLEndpoint = new ApiTimelineMastodon(fastify, this.config, this.mastoConverter); // GET Endpoints TLEndpoint.getTL(); @@ -781,7 +782,7 @@ export class MastodonApiServerService { //#endregion //#region Status - const NoteEndpoint = new ApiStatusMastodon(fastify, this.config, this.usersRepository, this.notesRepository, this.noteEditRepository, this.userEntityService); + const NoteEndpoint = new ApiStatusMastodon(fastify, this.mastoConverter); // GET Endpoints NoteEndpoint.getStatus(); diff --git a/packages/backend/src/server/api/mastodon/converters.ts b/packages/backend/src/server/api/mastodon/converters.ts index a839145609..6019b825e6 100644 --- a/packages/backend/src/server/api/mastodon/converters.ts +++ b/packages/backend/src/server/api/mastodon/converters.ts @@ -1,7 +1,7 @@ import type { Config } from '@/config.js'; import { MfmService } from '@/core/MfmService.js'; import { DI } from '@/di-symbols.js'; -import { Inject } from '@nestjs/common'; +import { Inject, Injectable } from '@nestjs/common'; import { Entity } from 'megalodon'; import mfm from 'mfm-js'; import { GetterService } from '../GetterService.js'; @@ -25,27 +25,15 @@ export const escapeMFM = (text: string): string => text .replace(/`/g, "`") .replace(/\r?\n/g, "
"); +@Injectable() export class MastoConverters { - private MfmService: MfmService; - private GetterService: GetterService; - constructor( @Inject(DI.config) private config: Config, - @Inject(DI.usersRepository) - private usersRepository: UsersRepository, - - @Inject(DI.notesRepository) - private notesRepository: NotesRepository, - - @Inject(DI.noteEditRepository) - private noteEditRepository: NoteEditRepository, - - private userEntityService: UserEntityService + private mfmService: MfmService, + private getterService: GetterService, ) { - this.MfmService = new MfmService(this.config); - this.GetterService = new GetterService(this.usersRepository, this.notesRepository, this.noteEditRepository, this.userEntityService); } private encode(u: MiUser, m: IMentionedRemoteUsers): Entity.Mention { @@ -67,7 +55,7 @@ export class MastoConverters { } public async getUser(id: string): Promise { - return this.GetterService.getUser(id).then(p => { + return this.getterService.getUser(id).then(p => { return p; }); } @@ -100,7 +88,7 @@ export class MastoConverters { public async convertStatus(status: Entity.Status) { const convertedAccount = this.convertAccount(status.account); - const note = await this.GetterService.getNote(status.id); + const note = await this.getterService.getNote(status.id); const mentions = Promise.all(note.mentions.map(p => this.getUser(p) @@ -109,7 +97,7 @@ export class MastoConverters { .then(p => p.filter(m => m)) as Promise; const content = note.text !== null - ? this.MfmService.toMastoHtml(mfm.parse(note.text!), JSON.parse(note.mentionedRemoteUsers), false, null) + ? this.mfmService.toMastoHtml(mfm.parse(note.text!), JSON.parse(note.mentionedRemoteUsers), false, null) .then(p => p ?? escapeMFM(note.text!)) : ''; diff --git a/packages/backend/src/server/api/mastodon/endpoints/account.ts b/packages/backend/src/server/api/mastodon/endpoints/account.ts index 802f1f5a67..f2525c723f 100644 --- a/packages/backend/src/server/api/mastodon/endpoints/account.ts +++ b/packages/backend/src/server/api/mastodon/endpoints/account.ts @@ -5,6 +5,7 @@ import type { FastifyRequest } from 'fastify'; import { NoteEditRepository, NotesRepository, UsersRepository } from '@/models/_.js'; import { UserEntityService } from '@/core/entities/UserEntityService.js'; import type { Config } from '@/config.js'; +import { Injectable } from '@nestjs/common'; const relationshipModel = { id: '', @@ -23,23 +24,16 @@ const relationshipModel = { note: '', }; +@Injectable() export class ApiAccountMastodon { private request: FastifyRequest; private client: MegalodonInterface; private BASE_URL: string; - private mastoconverter: MastoConverters; - constructor(request: FastifyRequest, client: MegalodonInterface, BASE_URL: string, - config: Config, - usersrepo: UsersRepository, - notesrepo: NotesRepository, - noteeditrepo: NoteEditRepository, - userentity: UserEntityService, - ) { + constructor(request: FastifyRequest, client: MegalodonInterface, BASE_URL: string, private mastoconverter: MastoConverters) { this.request = request; this.client = client; this.BASE_URL = BASE_URL; - this.mastoconverter = new MastoConverters(config, usersrepo, notesrepo, noteeditrepo, userentity); } public async verifyCredentials() { @@ -104,7 +98,9 @@ export class ApiAccountMastodon { public async getStatuses() { try { const data = await this.client.getAccountStatuses((this.request.params as any).id, argsToBools(limitToInt(this.request.query as any))); - return data.data.map((status) => this.mastoconverter.convertStatus(status)); + const a = await Promise.all(data.data.map(async (status) => await this.mastoconverter.convertStatus(status))); + console.error(a); + return a; } catch (e: any) { console.error(e); console.error(e.response.data); diff --git a/packages/backend/src/server/api/mastodon/endpoints/status.ts b/packages/backend/src/server/api/mastodon/endpoints/status.ts index a15e9761b4..294d38f200 100644 --- a/packages/backend/src/server/api/mastodon/endpoints/status.ts +++ b/packages/backend/src/server/api/mastodon/endpoints/status.ts @@ -18,9 +18,9 @@ export class ApiStatusMastodon { private fastify: FastifyInstance; private mastoconverter: MastoConverters; - constructor(fastify: FastifyInstance, config: Config, usersrepo: UsersRepository, notesrepo: NotesRepository, noteeditrepo: NoteEditRepository, userentity: UserEntityService) { + constructor(fastify: FastifyInstance, mastoconverter: MastoConverters) { this.fastify = fastify; - this.mastoconverter = new MastoConverters(config, usersrepo, notesrepo, noteeditrepo, userentity); + this.mastoconverter = mastoconverter; } public async getStatus() { diff --git a/packages/backend/src/server/api/mastodon/endpoints/timeline.ts b/packages/backend/src/server/api/mastodon/endpoints/timeline.ts index b1b487f394..152d4a7729 100644 --- a/packages/backend/src/server/api/mastodon/endpoints/timeline.ts +++ b/packages/backend/src/server/api/mastodon/endpoints/timeline.ts @@ -34,11 +34,9 @@ export function argsToBools(q: ParsedUrlQuery) { export class ApiTimelineMastodon { private fastify: FastifyInstance; - private mastoconverter: MastoConverters; - constructor(fastify: FastifyInstance, config: Config, usersRepository: UsersRepository, notesRepository: NotesRepository, noteEditRepository: NoteEditRepository, userEntityService: UserEntityService) { + constructor(fastify: FastifyInstance, config: Config, private mastoconverter: MastoConverters) { this.fastify = fastify; - this.mastoconverter = new MastoConverters(config, usersRepository, notesRepository, noteEditRepository, userEntityService); } public async getTL() { -- cgit v1.2.3-freya From 90b666e626371ad91db9a07cb59176f95e35e2ac Mon Sep 17 00:00:00 2001 From: Mar0xy Date: Sun, 29 Oct 2023 02:20:05 +0200 Subject: fix: await all results on favourites and reblogged --- packages/backend/src/server/api/mastodon/endpoints/account.ts | 4 +--- packages/backend/src/server/api/mastodon/endpoints/status.ts | 4 ++-- 2 files changed, 3 insertions(+), 5 deletions(-) (limited to 'packages/backend/src/server/api') diff --git a/packages/backend/src/server/api/mastodon/endpoints/account.ts b/packages/backend/src/server/api/mastodon/endpoints/account.ts index f2525c723f..a1f3773fd4 100644 --- a/packages/backend/src/server/api/mastodon/endpoints/account.ts +++ b/packages/backend/src/server/api/mastodon/endpoints/account.ts @@ -98,9 +98,7 @@ export class ApiAccountMastodon { public async getStatuses() { try { const data = await this.client.getAccountStatuses((this.request.params as any).id, argsToBools(limitToInt(this.request.query as any))); - const a = await Promise.all(data.data.map(async (status) => await this.mastoconverter.convertStatus(status))); - console.error(a); - return a; + return await Promise.all(data.data.map(async (status) => await this.mastoconverter.convertStatus(status))); } catch (e: any) { console.error(e); console.error(e.response.data); diff --git a/packages/backend/src/server/api/mastodon/endpoints/status.ts b/packages/backend/src/server/api/mastodon/endpoints/status.ts index 294d38f200..e5202244ea 100644 --- a/packages/backend/src/server/api/mastodon/endpoints/status.ts +++ b/packages/backend/src/server/api/mastodon/endpoints/status.ts @@ -89,7 +89,7 @@ export class ApiStatusMastodon { const client = getClient(BASE_URL, accessTokens); try { const data = await client.getStatusRebloggedBy(_request.params.id); - reply.send(data.data.map((account: Entity.Account) => this.mastoconverter.convertAccount(account))); + reply.send(await Promise.all(data.data.map(async (account: Entity.Account) => await this.mastoconverter.convertAccount(account)))); } catch (e: any) { console.error(e); reply.code(401).send(e.response.data); @@ -104,7 +104,7 @@ export class ApiStatusMastodon { const client = getClient(BASE_URL, accessTokens); try { const data = await client.getStatusFavouritedBy(_request.params.id); - reply.send(data.data.map((account: Entity.Account) => this.mastoconverter.convertAccount(account))); + reply.send(await Promise.all(data.data.map(async (account: Entity.Account) => await this.mastoconverter.convertAccount(account)))); } catch (e: any) { console.error(e); reply.code(401).send(e.response.data); -- cgit v1.2.3-freya From 95bcfd8ef3274f06e7a0f9e5e5062769c93d079b Mon Sep 17 00:00:00 2001 From: Mar0xy Date: Sun, 29 Oct 2023 02:23:43 +0200 Subject: fix: followers and following not being able to load --- packages/backend/src/server/api/mastodon/endpoints/account.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'packages/backend/src/server/api') diff --git a/packages/backend/src/server/api/mastodon/endpoints/account.ts b/packages/backend/src/server/api/mastodon/endpoints/account.ts index a1f3773fd4..39da0e4a53 100644 --- a/packages/backend/src/server/api/mastodon/endpoints/account.ts +++ b/packages/backend/src/server/api/mastodon/endpoints/account.ts @@ -112,7 +112,7 @@ export class ApiAccountMastodon { (this.request.params as any).id, limitToInt(this.request.query as any), ); - return data.data.map((account) => this.mastoconverter.convertAccount(account)); + return await Promise.all(data.data.map(async (account) => await this.mastoconverter.convertAccount(account))); } catch (e: any) { console.error(e); console.error(e.response.data); @@ -126,7 +126,7 @@ export class ApiAccountMastodon { (this.request.params as any).id, limitToInt(this.request.query as any), ); - return data.data.map((account) => this.mastoconverter.convertAccount(account)); + return await Promise.all(data.data.map(async (account) => await this.mastoconverter.convertAccount(account))); } catch (e: any) { console.error(e); console.error(e.response.data); -- cgit v1.2.3-freya From 549bcf70db6575390f4a89f2d880332a76949c7b Mon Sep 17 00:00:00 2001 From: Mar0xy Date: Sun, 29 Oct 2023 02:59:36 +0100 Subject: upd: convertAccount now fetches info from the DB --- .../api/mastodon/MastodonApiServerService.ts | 5 +- .../backend/src/server/api/mastodon/converters.ts | 80 +++++++++++++++------- packages/megalodon/src/entities/field.ts | 2 +- packages/megalodon/src/misskey/entities/field.ts | 1 + 4 files changed, 59 insertions(+), 29 deletions(-) (limited to 'packages/backend/src/server/api') diff --git a/packages/backend/src/server/api/mastodon/MastodonApiServerService.ts b/packages/backend/src/server/api/mastodon/MastodonApiServerService.ts index 13cf45368d..49274f7074 100644 --- a/packages/backend/src/server/api/mastodon/MastodonApiServerService.ts +++ b/packages/backend/src/server/api/mastodon/MastodonApiServerService.ts @@ -305,9 +305,8 @@ export class MastodonApiServerService { try { const sharkId = _request.params.id; const data = await client.getAccount(sharkId); - const profile = await this.userProfilesRepository.findOneBy({ userId: sharkId }); - data.data.fields = profile?.fields.map(f => ({ ...f, verified_at: null })) || []; - reply.send(convertAccount(data.data)); + const account = await this.mastoConverter.convertAccount(data.data); + reply.send(account); } catch (e: any) { /* console.error(e); console.error(e.response.data); */ diff --git a/packages/backend/src/server/api/mastodon/converters.ts b/packages/backend/src/server/api/mastodon/converters.ts index 6019b825e6..55cf60c66a 100644 --- a/packages/backend/src/server/api/mastodon/converters.ts +++ b/packages/backend/src/server/api/mastodon/converters.ts @@ -1,15 +1,16 @@ -import type { Config } from '@/config.js'; -import { MfmService } from '@/core/MfmService.js'; -import { DI } from '@/di-symbols.js'; import { Inject, Injectable } from '@nestjs/common'; import { Entity } from 'megalodon'; import mfm from 'mfm-js'; -import { GetterService } from '../GetterService.js'; +import { DI } from '@/di-symbols.js'; +import { MfmService } from '@/core/MfmService.js'; +import type { Config } from '@/config.js'; import type { IMentionedRemoteUsers } from '@/models/Note.js'; import type { MiUser } from '@/models/User.js'; -import type { NoteEditRepository, NotesRepository, UsersRepository } from '@/models/_.js'; +import type { NoteEditRepository, NotesRepository, UserProfilesRepository, UsersRepository } from '@/models/_.js'; import { UserEntityService } from '@/core/entities/UserEntityService.js'; import { awaitAll } from '@/misc/prelude/await-all.js'; +import { GetterService } from '../GetterService.js'; +import { CustomEmojiService } from '@/core/CustomEmojiService.js'; export enum IdConvertType { MastodonId, @@ -17,13 +18,13 @@ export enum IdConvertType { } export const escapeMFM = (text: string): string => text - .replace(/&/g, "&") - .replace(//g, ">") - .replace(/"/g, """) - .replace(/'/g, "'") - .replace(/`/g, "`") - .replace(/\r?\n/g, "
"); + .replace(/&/g, '&') + .replace(//g, '>') + .replace(/"/g, '"') + .replace(/'/g, ''') + .replace(/`/g, '`') + .replace(/\r?\n/g, '
'); @Injectable() export class MastoConverters { @@ -31,8 +32,15 @@ export class MastoConverters { @Inject(DI.config) private config: Config, + @Inject(DI.usersRepository) + private usersRepository: UsersRepository, + + @Inject(DI.userProfilesRepository) + private userProfilesRepository: UserProfilesRepository, + private mfmService: MfmService, private getterService: GetterService, + private customEmojiService: CustomEmojiService, ) { } @@ -60,29 +68,51 @@ export class MastoConverters { }); } + private async encodeField(f: Entity.Field): Promise { + return { + name: f.name, + value: await this.mfmService.toMastoHtml(mfm.parse(f.value), [], true) ?? escapeMFM(f.value), + verified_at: null, + }; + } + public async convertAccount(account: Entity.Account) { + const user = await this.getUser(account.id); + const profile = await this.userProfilesRepository.findOneBy({ userId: user.id }); + const emojis = await this.customEmojiService.populateEmojis(user.emojis, user.host ? user.host : this.config.host); + const emoji: Entity.Emoji[] = []; + Object.entries(emojis).forEach(entry => { + const [key, value] = entry; + emoji.push({ + shortcode: key, + static_url: value, + url: value, + visible_in_picker: true, + category: undefined, + }); + }); return awaitAll({ id: account.id, username: account.username, acct: account.acct, fqn: account.fqn, display_name: account.display_name || account.username, - locked: account.locked, + locked: user.isLocked, created_at: account.created_at, - followers_count: account.followers_count, - following_count: account.following_count, - statuses_count: account.statuses_count, - note: account.note, + followers_count: user.followersCount, + following_count: user.followingCount, + statuses_count: user.notesCount, + note: profile?.description ?? account.note, url: account.url, - avatar: account.avatar, - avatar_static: account.avatar, - header: account.header, - header_static: account.header, - emojis: account.emojis, + avatar: user.avatarUrl ? user.avatarUrl : 'https://dev.joinsharkey.org/static-assets/avatar.png', + avatar_static: user.avatarUrl ? user.avatarUrl : 'https://dev.joinsharkey.org/static-assets/avatar.png', + header: user.bannerUrl ? user.bannerUrl : 'https://dev.joinsharkey.org/static-assets/transparent.png', + header_static: user.bannerUrl ? user.bannerUrl : 'https://dev.joinsharkey.org/static-assets/transparent.png', + emojis: emoji, moved: null, //FIXME - fields: [], - bot: false, - discoverable: true, + fields: Promise.all(profile?.fields.map(async p => this.encodeField(p)) ?? []), + bot: user.isBot, + discoverable: user.isExplorable, }); } diff --git a/packages/megalodon/src/entities/field.ts b/packages/megalodon/src/entities/field.ts index 03e4604b02..71ce3c0cfa 100644 --- a/packages/megalodon/src/entities/field.ts +++ b/packages/megalodon/src/entities/field.ts @@ -2,6 +2,6 @@ namespace Entity { export type Field = { name: string value: string - verified_at: string | null + verified_at?: string | null } } diff --git a/packages/megalodon/src/misskey/entities/field.ts b/packages/megalodon/src/misskey/entities/field.ts index 8bbb2d7c42..1e61178e56 100644 --- a/packages/megalodon/src/misskey/entities/field.ts +++ b/packages/megalodon/src/misskey/entities/field.ts @@ -3,5 +3,6 @@ namespace MisskeyEntity { name: string; value: string; verified?: string; + verified_at?: string; }; } -- cgit v1.2.3-freya From d8b0078ffa3bd952b9cf237b1177a40a90d5ebda Mon Sep 17 00:00:00 2001 From: Mar0xy Date: Sun, 29 Oct 2023 03:23:09 +0100 Subject: fix: emojis not loading on local statuses --- .../backend/src/server/api/mastodon/converters.ts | 24 ++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) (limited to 'packages/backend/src/server/api') diff --git a/packages/backend/src/server/api/mastodon/converters.ts b/packages/backend/src/server/api/mastodon/converters.ts index 55cf60c66a..e2c9a2d34c 100644 --- a/packages/backend/src/server/api/mastodon/converters.ts +++ b/packages/backend/src/server/api/mastodon/converters.ts @@ -9,8 +9,9 @@ import type { MiUser } from '@/models/User.js'; import type { NoteEditRepository, NotesRepository, UserProfilesRepository, UsersRepository } from '@/models/_.js'; import { UserEntityService } from '@/core/entities/UserEntityService.js'; import { awaitAll } from '@/misc/prelude/await-all.js'; -import { GetterService } from '../GetterService.js'; import { CustomEmojiService } from '@/core/CustomEmojiService.js'; +import { GetterService } from '../GetterService.js'; +import { ReactionService } from '@/core/ReactionService.js'; export enum IdConvertType { MastodonId, @@ -41,6 +42,7 @@ export class MastoConverters { private mfmService: MfmService, private getterService: GetterService, private customEmojiService: CustomEmojiService, + private reactionService: ReactionService, ) { } @@ -119,6 +121,24 @@ export class MastoConverters { public async convertStatus(status: Entity.Status) { const convertedAccount = this.convertAccount(status.account); const note = await this.getterService.getNote(status.id); + const noteUser = await this.getUser(status.account.id); + + const reactionEmojiNames = Object.keys(note.reactions) + .filter(x => x.startsWith(':') && x.includes('@') && !x.includes('@.')) + .map(x => this.reactionService.decodeReaction(x).reaction.replaceAll(':', '')); + + const emojis = await this.customEmojiService.populateEmojis(reactionEmojiNames, noteUser.host ? noteUser.host : this.config.host); + const emoji: Entity.Emoji[] = []; + Object.entries(emojis).forEach(entry => { + const [key, value] = entry; + emoji.push({ + shortcode: key, + static_url: value, + url: value, + visible_in_picker: true, + category: undefined, + }); + }); const mentions = Promise.all(note.mentions.map(p => this.getUser(p) @@ -151,7 +171,7 @@ export class MastoConverters { content_type: 'text/x.misskeymarkdown', text: note.text, created_at: status.created_at, - emojis: status.emojis, + emojis: emoji, replies_count: note.repliesCount, reblogs_count: note.renoteCount, favourites_count: status.favourites_count, -- cgit v1.2.3-freya From 8fd669ff7ddd793442597adff6386661e944d089 Mon Sep 17 00:00:00 2001 From: Mar0xy Date: Sun, 29 Oct 2023 03:30:35 +0100 Subject: fix: statuses using wrong emojis --- packages/backend/src/server/api/mastodon/converters.ts | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'packages/backend/src/server/api') diff --git a/packages/backend/src/server/api/mastodon/converters.ts b/packages/backend/src/server/api/mastodon/converters.ts index e2c9a2d34c..22bc3cf6fe 100644 --- a/packages/backend/src/server/api/mastodon/converters.ts +++ b/packages/backend/src/server/api/mastodon/converters.ts @@ -123,11 +123,7 @@ export class MastoConverters { const note = await this.getterService.getNote(status.id); const noteUser = await this.getUser(status.account.id); - const reactionEmojiNames = Object.keys(note.reactions) - .filter(x => x.startsWith(':') && x.includes('@') && !x.includes('@.')) - .map(x => this.reactionService.decodeReaction(x).reaction.replaceAll(':', '')); - - const emojis = await this.customEmojiService.populateEmojis(reactionEmojiNames, noteUser.host ? noteUser.host : this.config.host); + const emojis = await this.customEmojiService.populateEmojis(note.emojis, noteUser.host ? noteUser.host : this.config.host); const emoji: Entity.Emoji[] = []; Object.entries(emojis).forEach(entry => { const [key, value] = entry; -- cgit v1.2.3-freya From c53323d23748161a0f5cd9d46b4b711c7260383b Mon Sep 17 00:00:00 2001 From: Mar0xy Date: Sun, 29 Oct 2023 12:18:18 +0100 Subject: upd: add history endpoint, make sure all areas use new convertAccount --- .../api/mastodon/MastodonApiServerService.ts | 20 ++--- .../backend/src/server/api/mastodon/converters.ts | 96 +++++++++++++++++++--- .../src/server/api/mastodon/endpoints/search.ts | 8 +- .../src/server/api/mastodon/endpoints/status.ts | 3 +- packages/megalodon/src/entities/list.ts | 3 +- packages/megalodon/src/misskey/api_client.ts | 2 +- 6 files changed, 104 insertions(+), 28 deletions(-) (limited to 'packages/backend/src/server/api') diff --git a/packages/backend/src/server/api/mastodon/MastodonApiServerService.ts b/packages/backend/src/server/api/mastodon/MastodonApiServerService.ts index 49274f7074..32534d9ef2 100644 --- a/packages/backend/src/server/api/mastodon/MastodonApiServerService.ts +++ b/packages/backend/src/server/api/mastodon/MastodonApiServerService.ts @@ -8,7 +8,7 @@ import { DI } from '@/di-symbols.js'; import { bindThis } from '@/decorators.js'; import type { Config } from '@/config.js'; import { MetaService } from '@/core/MetaService.js'; -import { convertAccount, convertAnnouncement, convertFilter, convertAttachment, convertFeaturedTag, convertList, MastoConverters } from './converters.js'; +import { convertAnnouncement, convertFilter, convertAttachment, convertFeaturedTag, convertList, MastoConverters } from './converters.js'; import { getInstance } from './endpoints/meta.js'; import { ApiAuthMastodon, ApiAccountMastodon, ApiFilterMastodon, ApiNotifyMastodon, ApiSearchMastodon, ApiTimelineMastodon, ApiStatusMastodon } from './endpoints.js'; import type { FastifyInstance, FastifyPluginOptions } from 'fastify'; @@ -102,8 +102,8 @@ export class MastodonApiServerService { }, order: { id: 'ASC' }, }); - const contact = admin == null ? null : convertAccount((await client.getAccount(admin.id)).data); - reply.send(await getInstance(data.data, contact, this.config, await this.metaService.fetch())); + const contact = admin == null ? null : await this.mastoConverter.convertAccount((await client.getAccount(admin.id)).data); + reply.send(await getInstance(data.data, contact as Entity.Account, this.config, await this.metaService.fetch())); } catch (e: any) { /* console.error(e); */ reply.code(401).send(e.response.data); @@ -252,7 +252,7 @@ export class MastodonApiServerService { // displayed without being logged in try { const data = await client.updateCredentials(_request.body!); - reply.send(convertAccount(data.data)); + reply.send(await this.mastoConverter.convertAccount(data.data)); } catch (e: any) { /* console.error(e); */ reply.code(401).send(e.response.data); @@ -268,7 +268,7 @@ export class MastodonApiServerService { const data = await client.search((_request.query as any).acct, { type: 'accounts' }); const profile = await this.userProfilesRepository.findOneBy({ userId: data.data.accounts[0].id }); data.data.accounts[0].fields = profile?.fields.map(f => ({ ...f, verified_at: null })) || []; - reply.send(convertAccount(data.data.accounts[0])); + reply.send(await this.mastoConverter.convertAccount(data.data.accounts[0])); } catch (e: any) { /* console.error(e); */ reply.code(401).send(e.response.data); @@ -544,7 +544,7 @@ export class MastodonApiServerService { const client = getClient(BASE_URL, accessTokens); try { const data = await client.getFollowRequests( ((_request.query as any) || { limit: 20 }).limit ); - reply.send(data.data.map((account) => convertAccount(account as Entity.Account))); + reply.send(await Promise.all(data.data.map(async (account) => await this.mastoConverter.convertAccount(account as Entity.Account)))); } catch (e: any) { /* console.error(e); console.error(e.response.data); */ @@ -587,7 +587,7 @@ export class MastodonApiServerService { const accessTokens = _request.headers.authorization; const client = getClient(BASE_URL, accessTokens); try { - const search = new ApiSearchMastodon(_request, client, BASE_URL); + const search = new ApiSearchMastodon(_request, client, BASE_URL, this.mastoConverter); reply.send(await search.SearchV1()); } catch (e: any) { /* console.error(e); @@ -601,7 +601,7 @@ export class MastodonApiServerService { const accessTokens = _request.headers.authorization; const client = getClient(BASE_URL, accessTokens); try { - const search = new ApiSearchMastodon(_request, client, BASE_URL); + const search = new ApiSearchMastodon(_request, client, BASE_URL, this.mastoConverter); reply.send(await search.SearchV2()); } catch (e: any) { /* console.error(e); @@ -615,7 +615,7 @@ export class MastodonApiServerService { const accessTokens = _request.headers.authorization; const client = getClient(BASE_URL, accessTokens); try { - const search = new ApiSearchMastodon(_request, client, BASE_URL); + const search = new ApiSearchMastodon(_request, client, BASE_URL, this.mastoConverter); reply.send(await search.getStatusTrends()); } catch (e: any) { /* console.error(e); @@ -629,7 +629,7 @@ export class MastodonApiServerService { const accessTokens = _request.headers.authorization; const client = getClient(BASE_URL, accessTokens); try { - const search = new ApiSearchMastodon(_request, client, BASE_URL); + const search = new ApiSearchMastodon(_request, client, BASE_URL, this.mastoConverter); reply.send(await search.getSuggestions()); } catch (e: any) { /* console.error(e); diff --git a/packages/backend/src/server/api/mastodon/converters.ts b/packages/backend/src/server/api/mastodon/converters.ts index 22bc3cf6fe..51556adf22 100644 --- a/packages/backend/src/server/api/mastodon/converters.ts +++ b/packages/backend/src/server/api/mastodon/converters.ts @@ -7,11 +7,11 @@ import type { Config } from '@/config.js'; import type { IMentionedRemoteUsers } from '@/models/Note.js'; import type { MiUser } from '@/models/User.js'; import type { NoteEditRepository, NotesRepository, UserProfilesRepository, UsersRepository } from '@/models/_.js'; -import { UserEntityService } from '@/core/entities/UserEntityService.js'; import { awaitAll } from '@/misc/prelude/await-all.js'; import { CustomEmojiService } from '@/core/CustomEmojiService.js'; import { GetterService } from '../GetterService.js'; -import { ReactionService } from '@/core/ReactionService.js'; +import { DriveFileEntityService } from '@/core/entities/DriveFileEntityService.js'; +import { IdService } from '@/core/IdService.js'; export enum IdConvertType { MastodonId, @@ -39,10 +39,14 @@ export class MastoConverters { @Inject(DI.userProfilesRepository) private userProfilesRepository: UserProfilesRepository, + @Inject(DI.noteEditRepository) + private noteEditRepository: NoteEditRepository, + private mfmService: MfmService, private getterService: GetterService, private customEmojiService: CustomEmojiService, - private reactionService: ReactionService, + private idService: IdService, + private driveFileEntityService: DriveFileEntityService, ) { } @@ -64,6 +68,39 @@ export class MastoConverters { }; } + public fileType(s: string): 'unknown' | 'image' | 'gifv' | 'video' | 'audio' { + if (s === 'image/gif') { + return 'gifv'; + } + if (s.includes('image')) { + return 'image'; + } + if (s.includes('video')) { + return 'video'; + } + if (s.includes('audio')) { + return 'audio'; + } + return 'unknown'; + } + + public encodeFile(f: any): Entity.Attachment { + return { + id: f.id, + type: this.fileType(f.type), + url: f.url, + remote_url: f.url, + preview_url: f.thumbnailUrl, + text_url: f.url, + meta: { + width: f.properties.width, + height: f.properties.height + }, + description: f.comment ? f.comment : null, + blurhash: f.blurhash ? f.blurhash : null + }; + } + public async getUser(id: string): Promise { return this.getterService.getUser(id).then(p => { return p; @@ -78,7 +115,7 @@ export class MastoConverters { }; } - public async convertAccount(account: Entity.Account) { + public async convertAccount(account: Entity.Account | MiUser) { const user = await this.getUser(account.id); const profile = await this.userProfilesRepository.findOneBy({ userId: user.id }); const emojis = await this.customEmojiService.populateEmojis(user.emojis, user.host ? user.host : this.config.host); @@ -93,19 +130,26 @@ export class MastoConverters { category: undefined, }); }); + const fqn = `${user.username}@${user.host ?? this.config.hostname}`; + let acct = user.username; + let acctUrl = `https://${user.host || this.config.host}/@${user.username}`; + if (user.host) { + acct = `${user.username}@${user.host}`; + acctUrl = `https://${user.host}/@${user.username}`; + } return awaitAll({ id: account.id, - username: account.username, - acct: account.acct, - fqn: account.fqn, - display_name: account.display_name || account.username, + username: user.username, + acct: acct, + fqn: fqn, + display_name: user.name ?? user.username, locked: user.isLocked, - created_at: account.created_at, + created_at: this.idService.parse(user.id).date.toISOString(), followers_count: user.followersCount, following_count: user.followingCount, statuses_count: user.notesCount, - note: profile?.description ?? account.note, - url: account.url, + note: profile?.description ?? '', + url: user.uri ?? acctUrl, avatar: user.avatarUrl ? user.avatarUrl : 'https://dev.joinsharkey.org/static-assets/avatar.png', avatar_static: user.avatarUrl ? user.avatarUrl : 'https://dev.joinsharkey.org/static-assets/avatar.png', header: user.bannerUrl ? user.bannerUrl : 'https://dev.joinsharkey.org/static-assets/transparent.png', @@ -118,6 +162,36 @@ export class MastoConverters { }); } + public async getEdits(id: string) { + const note = await this.getterService.getNote(id); + if (!note) { + return {}; + } + + const noteUser = await this.getUser(note.userId).then(async (p) => await this.convertAccount(p)); + const edits = await this.noteEditRepository.find({ where: { noteId: note.id }, order: { id: 'ASC' } }); + const history: Promise[] = []; + + let lastDate = this.idService.parse(note.id).date; + for (const edit of edits) { + const files = this.driveFileEntityService.packManyByIds(edit.fileIds); + const item = { + account: noteUser, + content: this.mfmService.toMastoHtml(mfm.parse(edit.newText ?? ''), JSON.parse(note.mentionedRemoteUsers)).then(p => p ?? ''), + created_at: lastDate.toISOString(), + emojis: [], + sensitive: files.then(files => files.length > 0 ? files.some((f) => f.isSensitive) : false), + spoiler_text: edit.cw ?? '', + poll: null, + media_attachments: files.then(files => files.length > 0 ? files.map((f) => this.encodeFile(f)) : []) + }; + lastDate = edit.updatedAt; + history.push(awaitAll(item)); + } + + return await Promise.all(history); + } + public async convertStatus(status: Entity.Status) { const convertedAccount = this.convertAccount(status.account); const note = await this.getterService.getNote(status.id); diff --git a/packages/backend/src/server/api/mastodon/endpoints/search.ts b/packages/backend/src/server/api/mastodon/endpoints/search.ts index d5839ff1c8..772ef33076 100644 --- a/packages/backend/src/server/api/mastodon/endpoints/search.ts +++ b/packages/backend/src/server/api/mastodon/endpoints/search.ts @@ -1,5 +1,5 @@ import { Converter } from 'megalodon'; -import { convertAccount, convertStatus } from '../converters.js'; +import { MastoConverters, convertAccount, convertStatus } from '../converters.js'; import { limitToInt } from './timeline.js'; import type { MegalodonInterface } from 'megalodon'; import type { FastifyRequest } from 'fastify'; @@ -63,7 +63,7 @@ export class ApiSearchMastodon { private client: MegalodonInterface; private BASE_URL: string; - constructor(request: FastifyRequest, client: MegalodonInterface, BASE_URL: string) { + constructor(request: FastifyRequest, client: MegalodonInterface, BASE_URL: string, private mastoConverter: MastoConverters) { this.request = request; this.client = client; this.BASE_URL = BASE_URL; @@ -89,8 +89,8 @@ export class ApiSearchMastodon { const stat = !type || type === 'statuses' ? await this.client.search(query.q, { type: 'statuses', ...query }) : null; const tags = !type || type === 'hashtags' ? await this.client.search(query.q, { type: 'hashtags', ...query }) : null; const data = { - accounts: acct?.data.accounts.map((account) => convertAccount(account)) ?? [], - statuses: stat?.data.statuses.map((status) => convertStatus(status)) ?? [], + accounts: await Promise.all(acct?.data.accounts.map(async (account) => await this.mastoConverter.convertAccount(account)) ?? []), + statuses: await Promise.all(stat?.data.statuses.map(async (status) => await this.mastoConverter.convertStatus(status)) ?? []), hashtags: tags?.data.hashtags ?? [], }; return data; diff --git a/packages/backend/src/server/api/mastodon/endpoints/status.ts b/packages/backend/src/server/api/mastodon/endpoints/status.ts index e5202244ea..fe77646af4 100644 --- a/packages/backend/src/server/api/mastodon/endpoints/status.ts +++ b/packages/backend/src/server/api/mastodon/endpoints/status.ts @@ -74,7 +74,8 @@ export class ApiStatusMastodon { public async getHistory() { this.fastify.get<{ Params: { id: string } }>('/v1/statuses/:id/history', async (_request, reply) => { try { - reply.send([]); + const edits = await this.mastoconverter.getEdits(_request.params.id); + reply.send(edits); } catch (e: any) { console.error(e); reply.code(401).send(e.response.data); diff --git a/packages/megalodon/src/entities/list.ts b/packages/megalodon/src/entities/list.ts index 58c264abab..281f02b110 100644 --- a/packages/megalodon/src/entities/list.ts +++ b/packages/megalodon/src/entities/list.ts @@ -2,7 +2,8 @@ namespace Entity { export type List = { id: string title: string - replies_policy: RepliesPolicy | null + replies_policy?: RepliesPolicy | null + exclusive?: RepliesPolicy | null } export type RepliesPolicy = 'followed' | 'list' | 'none' diff --git a/packages/megalodon/src/misskey/api_client.ts b/packages/megalodon/src/misskey/api_client.ts index 66347fc469..520928c9fe 100644 --- a/packages/megalodon/src/misskey/api_client.ts +++ b/packages/megalodon/src/misskey/api_client.ts @@ -391,7 +391,7 @@ namespace MisskeyAPI { export const list = (l: Entity.List): MegalodonEntity.List => ({ id: l.id, title: l.name, - replies_policy: null + exclusive: null }) export const encodeNotificationType = ( -- cgit v1.2.3-freya From b596a4978f51e72e4cfe789ac56a7f9b7d95b1ba Mon Sep 17 00:00:00 2001 From: Mar0xy Date: Sun, 29 Oct 2023 12:49:41 +0100 Subject: upd: add quoteUri resolving and correct reblog/quote handling --- .../backend/src/server/api/mastodon/converters.ts | 28 ++++++++++++++++------ 1 file changed, 21 insertions(+), 7 deletions(-) (limited to 'packages/backend/src/server/api') diff --git a/packages/backend/src/server/api/mastodon/converters.ts b/packages/backend/src/server/api/mastodon/converters.ts index 51556adf22..0383191399 100644 --- a/packages/backend/src/server/api/mastodon/converters.ts +++ b/packages/backend/src/server/api/mastodon/converters.ts @@ -192,6 +192,11 @@ export class MastoConverters { return await Promise.all(history); } + private async convertReblog(status: Entity.Status | null): Promise { + if (!status) return null; + return await this.convertStatus(status); + } + public async convertStatus(status: Entity.Status) { const convertedAccount = this.convertAccount(status.account); const note = await this.getterService.getNote(status.id); @@ -216,11 +221,6 @@ export class MastoConverters { .catch(() => null))) .then(p => p.filter(m => m)) as Promise; - const content = note.text !== null - ? this.mfmService.toMastoHtml(mfm.parse(note.text!), JSON.parse(note.mentionedRemoteUsers), false, null) - .then(p => p ?? escapeMFM(note.text!)) - : ''; - const tags = note.tags.map(tag => { return { name: tag, @@ -228,6 +228,20 @@ export class MastoConverters { } as Entity.Tag; }); + const isQuote = note.renoteId && note.text ? true : false; + + const renote = note.renoteId ? this.getterService.getNote(note.renoteId) : null; + + const quoteUri = Promise.resolve(renote).then(renote => { + if (!renote || !isQuote) return null; + return renote.url ?? renote.uri ?? `${this.config.url}/notes/${renote.id}`; + }); + + const content = note.text !== null + ? quoteUri.then(quoteUri => this.mfmService.toMastoHtml(mfm.parse(note.text!), JSON.parse(note.mentionedRemoteUsers), false, quoteUri)) + .then(p => p ?? escapeMFM(note.text!)) + : ''; + // noinspection ES6MissingAwait return await awaitAll({ id: note.id, @@ -236,7 +250,7 @@ export class MastoConverters { account: convertedAccount, in_reply_to_id: note.replyId, in_reply_to_account_id: note.replyUserId, - reblog: status.reblog, + reblog: !isQuote ? await this.convertReblog(status.reblog) : null, content: content, content_type: 'text/x.misskeymarkdown', text: note.text, @@ -262,7 +276,7 @@ export class MastoConverters { reactions: status.emoji_reactions, emoji_reactions: status.emoji_reactions, bookmarked: false, - quote: false, + quote: isQuote ? await this.convertReblog(status.reblog) : null, edited_at: note.updatedAt?.toISOString(), }); } -- cgit v1.2.3-freya From cd1083cc3074f570e57877e125e305193b1a108f Mon Sep 17 00:00:00 2001 From: Mar0xy Date: Sun, 29 Oct 2023 14:31:26 +0100 Subject: fix: relationships not working on some clients --- packages/backend/src/server/api/mastodon/MastodonApiServerService.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'packages/backend/src/server/api') diff --git a/packages/backend/src/server/api/mastodon/MastodonApiServerService.ts b/packages/backend/src/server/api/mastodon/MastodonApiServerService.ts index 32534d9ef2..efc2302f3f 100644 --- a/packages/backend/src/server/api/mastodon/MastodonApiServerService.ts +++ b/packages/backend/src/server/api/mastodon/MastodonApiServerService.ts @@ -282,7 +282,7 @@ export class MastodonApiServerService { // displayed without being logged in let users; try { - let ids = _request.query ? (_request.query as any)['id[]'] : null; + let ids = _request.query ? (_request.query as any)['id[]'] ?? (_request.query as any)['id'] : null; if (typeof ids === 'string') { ids = [ids]; } -- cgit v1.2.3-freya From b57ec5e2eb5e7ad30d9c989105cb2ac34de9d2ba Mon Sep 17 00:00:00 2001 From: Mar0xy Date: Mon, 30 Oct 2023 00:27:04 +0100 Subject: test: avatar and header uploading --- packages/backend/src/misc/prelude/array.ts | 4 ++ .../api/mastodon/MastodonApiServerService.ts | 43 ++++++++++++++++++++-- packages/megalodon/src/misskey.ts | 10 +++++ 3 files changed, 53 insertions(+), 4 deletions(-) (limited to 'packages/backend/src/server/api') diff --git a/packages/backend/src/misc/prelude/array.ts b/packages/backend/src/misc/prelude/array.ts index b2f29bcecf..8438b64805 100644 --- a/packages/backend/src/misc/prelude/array.ts +++ b/packages/backend/src/misc/prelude/array.ts @@ -142,3 +142,7 @@ export function toArray(x: T | T[] | undefined): T[] { export function toSingle(x: T | T[] | undefined): T | undefined { return Array.isArray(x) ? x[0] : x; } + +export function toSingleLast(x: T | T[] | undefined): T | undefined { + return Array.isArray(x) ? x.at(-1) : x; +} diff --git a/packages/backend/src/server/api/mastodon/MastodonApiServerService.ts b/packages/backend/src/server/api/mastodon/MastodonApiServerService.ts index efc2302f3f..0bfa1a39fa 100644 --- a/packages/backend/src/server/api/mastodon/MastodonApiServerService.ts +++ b/packages/backend/src/server/api/mastodon/MastodonApiServerService.ts @@ -3,16 +3,18 @@ import megalodon, { Entity, MegalodonInterface } from 'megalodon'; import querystring from 'querystring'; import { IsNull } from 'typeorm'; import multer from 'fastify-multer'; -import type { NoteEditRepository, NotesRepository, UserProfilesRepository, UsersRepository } from '@/models/_.js'; +import type { AccessTokensRepository, NoteEditRepository, NotesRepository, UserProfilesRepository, UsersRepository } from '@/models/_.js'; import { DI } from '@/di-symbols.js'; import { bindThis } from '@/decorators.js'; import type { Config } from '@/config.js'; import { MetaService } from '@/core/MetaService.js'; -import { convertAnnouncement, convertFilter, convertAttachment, convertFeaturedTag, convertList, MastoConverters } from './converters.js'; +import { convertAnnouncement, convertFilter, convertAttachment, convertFeaturedTag, convertList, MastoConverters } from './converters.js'; import { getInstance } from './endpoints/meta.js'; import { ApiAuthMastodon, ApiAccountMastodon, ApiFilterMastodon, ApiNotifyMastodon, ApiSearchMastodon, ApiTimelineMastodon, ApiStatusMastodon } from './endpoints.js'; import type { FastifyInstance, FastifyPluginOptions } from 'fastify'; import { UserEntityService } from '@/core/entities/UserEntityService.js'; +import { DriveService } from '@/core/DriveService.js'; +import { toSingleLast } from '@/misc/prelude/array.js'; export function getClient(BASE_URL: string, authorization: string | undefined): MegalodonInterface { const accessTokenArr = authorization?.split(' ') ?? [null]; @@ -33,10 +35,13 @@ export class MastodonApiServerService { private userProfilesRepository: UserProfilesRepository, @Inject(DI.noteEditRepository) private noteEditRepository: NoteEditRepository, + @Inject(DI.accessTokensRepository) + private accessTokensRepository: AccessTokensRepository, @Inject(DI.config) private config: Config, private metaService: MetaService, private userEntityService: UserEntityService, + private driveService: DriveService, private mastoConverter: MastoConverters, ) { } @@ -245,16 +250,46 @@ export class MastodonApiServerService { } }); - fastify.patch('/v1/accounts/update_credentials', { preHandler: upload.none() }, async (_request, reply) => { + fastify.patch('/v1/accounts/update_credentials', { preHandler: upload.any() }, async (_request, reply) => { const BASE_URL = `${_request.protocol}://${_request.hostname}`; const accessTokens = _request.headers.authorization; const client = getClient(BASE_URL, accessTokens); // we are using this here, because in private mode some info isnt // displayed without being logged in try { + if (_request.files.length > 0) { + const tokeninfo = await this.accessTokensRepository.findOneBy({ token: accessTokens }); + console.error(tokeninfo); + if (tokeninfo && (_request.files as any)['avatar']) { + const file = toSingleLast((_request.files as any)['avatar']); + const user = await this.usersRepository.findOneBy({ id: tokeninfo.userId }); + const upload = await this.driveService.addFile({ + user: { id: tokeninfo.userId, host: user ? user.host : null }, + path: file.path, + name: file.originalname !== null && file.originalname !== 'file' ? file.originalname : undefined, + sensitive: false, + }); + if (upload.type.startsWith('image/')) { + (_request.body as any).avatar = upload.id; + } + } + if (tokeninfo && (_request.files as any)['header']) { + const file = toSingleLast((_request.files as any)['header']); + const user = await this.usersRepository.findOneBy({ id: tokeninfo.userId }); + const upload = await this.driveService.addFile({ + user: { id: tokeninfo.userId, host: user ? user.host : null }, + path: file.path, + name: file.originalname !== null && file.originalname !== 'file' ? file.originalname : undefined, + sensitive: false, + }); + if (upload.type.startsWith('image/')) { + (_request.body as any).header = upload.id; + } + } + } const data = await client.updateCredentials(_request.body!); reply.send(await this.mastoConverter.convertAccount(data.data)); } catch (e: any) { - /* console.error(e); */ + //console.error(e); reply.code(401).send(e.response.data); } }); diff --git a/packages/megalodon/src/misskey.ts b/packages/megalodon/src/misskey.ts index 69a8972d61..b81fb77a6b 100644 --- a/packages/megalodon/src/misskey.ts +++ b/packages/megalodon/src/misskey.ts @@ -238,6 +238,16 @@ export default class Misskey implements MegalodonInterface { description: options.note }) } + if (options.avatar) { + params = Object.assign(params, { + avatarId: options.avatar + }) + } + if (options.header) { + params = Object.assign(params, { + bannerId: options.header + }) + } if (options.locked !== undefined) { params = Object.assign(params, { isLocked: options.locked.toString() === 'true' ? true : false -- cgit v1.2.3-freya From 2aa7c1ae34d2942a5a338510777a5a7e082b2a24 Mon Sep 17 00:00:00 2001 From: Mar0xy Date: Mon, 30 Oct 2023 00:29:58 +0100 Subject: upd: remove Bearer from auth when looking up token --- packages/backend/src/server/api/mastodon/MastodonApiServerService.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'packages/backend/src/server/api') diff --git a/packages/backend/src/server/api/mastodon/MastodonApiServerService.ts b/packages/backend/src/server/api/mastodon/MastodonApiServerService.ts index 0bfa1a39fa..a956cf9036 100644 --- a/packages/backend/src/server/api/mastodon/MastodonApiServerService.ts +++ b/packages/backend/src/server/api/mastodon/MastodonApiServerService.ts @@ -256,8 +256,8 @@ export class MastodonApiServerService { const client = getClient(BASE_URL, accessTokens); // we are using this here, because in private mode some info isnt // displayed without being logged in try { - if (_request.files.length > 0) { - const tokeninfo = await this.accessTokensRepository.findOneBy({ token: accessTokens }); + if (_request.files.length > 0 && accessTokens) { + const tokeninfo = await this.accessTokensRepository.findOneBy({ token: accessTokens.replace('Bearer ', '') }); console.error(tokeninfo); if (tokeninfo && (_request.files as any)['avatar']) { const file = toSingleLast((_request.files as any)['avatar']); -- cgit v1.2.3-freya From e8e4bafa6410fce77ec70efceec842926c666cfa Mon Sep 17 00:00:00 2001 From: Mar0xy Date: Mon, 30 Oct 2023 00:34:19 +0100 Subject: upd: remove host lookup on file updating --- .../backend/src/server/api/mastodon/MastodonApiServerService.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'packages/backend/src/server/api') diff --git a/packages/backend/src/server/api/mastodon/MastodonApiServerService.ts b/packages/backend/src/server/api/mastodon/MastodonApiServerService.ts index a956cf9036..06aaebf032 100644 --- a/packages/backend/src/server/api/mastodon/MastodonApiServerService.ts +++ b/packages/backend/src/server/api/mastodon/MastodonApiServerService.ts @@ -261,9 +261,8 @@ export class MastodonApiServerService { console.error(tokeninfo); if (tokeninfo && (_request.files as any)['avatar']) { const file = toSingleLast((_request.files as any)['avatar']); - const user = await this.usersRepository.findOneBy({ id: tokeninfo.userId }); const upload = await this.driveService.addFile({ - user: { id: tokeninfo.userId, host: user ? user.host : null }, + user: { id: tokeninfo.userId, host: null }, path: file.path, name: file.originalname !== null && file.originalname !== 'file' ? file.originalname : undefined, sensitive: false, @@ -274,9 +273,8 @@ export class MastodonApiServerService { } if (tokeninfo && (_request.files as any)['header']) { const file = toSingleLast((_request.files as any)['header']); - const user = await this.usersRepository.findOneBy({ id: tokeninfo.userId }); const upload = await this.driveService.addFile({ - user: { id: tokeninfo.userId, host: user ? user.host : null }, + user: { id: tokeninfo.userId, host: null }, path: file.path, name: file.originalname !== null && file.originalname !== 'file' ? file.originalname : undefined, sensitive: false, -- cgit v1.2.3-freya From be7d3859c3629dffb8e3d4a421978f67ddc3c02b Mon Sep 17 00:00:00 2001 From: Mar0xy Date: Mon, 30 Oct 2023 00:45:38 +0100 Subject: test: update debug lines --- packages/backend/src/server/api/mastodon/MastodonApiServerService.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'packages/backend/src/server/api') diff --git a/packages/backend/src/server/api/mastodon/MastodonApiServerService.ts b/packages/backend/src/server/api/mastodon/MastodonApiServerService.ts index 06aaebf032..ac66d8d49b 100644 --- a/packages/backend/src/server/api/mastodon/MastodonApiServerService.ts +++ b/packages/backend/src/server/api/mastodon/MastodonApiServerService.ts @@ -258,8 +258,9 @@ export class MastodonApiServerService { try { if (_request.files.length > 0 && accessTokens) { const tokeninfo = await this.accessTokensRepository.findOneBy({ token: accessTokens.replace('Bearer ', '') }); - console.error(tokeninfo); + console.error(_request.files); if (tokeninfo && (_request.files as any)['avatar']) { + console.error('avatar'); const file = toSingleLast((_request.files as any)['avatar']); const upload = await this.driveService.addFile({ user: { id: tokeninfo.userId, host: null }, @@ -267,6 +268,7 @@ export class MastodonApiServerService { name: file.originalname !== null && file.originalname !== 'file' ? file.originalname : undefined, sensitive: false, }); + console.error(upload); if (upload.type.startsWith('image/')) { (_request.body as any).avatar = upload.id; } -- cgit v1.2.3-freya From d942d4d0d01505b1a532b502181704f6310226fb Mon Sep 17 00:00:00 2001 From: Mar0xy Date: Mon, 30 Oct 2023 00:57:12 +0100 Subject: upd: change resolving of _request.files --- .../api/mastodon/MastodonApiServerService.ts | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) (limited to 'packages/backend/src/server/api') diff --git a/packages/backend/src/server/api/mastodon/MastodonApiServerService.ts b/packages/backend/src/server/api/mastodon/MastodonApiServerService.ts index ac66d8d49b..cc61a234d7 100644 --- a/packages/backend/src/server/api/mastodon/MastodonApiServerService.ts +++ b/packages/backend/src/server/api/mastodon/MastodonApiServerService.ts @@ -258,14 +258,19 @@ export class MastodonApiServerService { try { if (_request.files.length > 0 && accessTokens) { const tokeninfo = await this.accessTokensRepository.findOneBy({ token: accessTokens.replace('Bearer ', '') }); - console.error(_request.files); - if (tokeninfo && (_request.files as any)['avatar']) { + const avatar = (_request.files as any).find((obj: any) => { + return obj.fieldname === 'avatar'; + }); + const header = (_request.files as any).find((obj: any) => { + return obj.fieldname === 'header'; + }); + + if (tokeninfo && avatar) { console.error('avatar'); - const file = toSingleLast((_request.files as any)['avatar']); const upload = await this.driveService.addFile({ user: { id: tokeninfo.userId, host: null }, - path: file.path, - name: file.originalname !== null && file.originalname !== 'file' ? file.originalname : undefined, + path: avatar.path, + name: avatar.originalname !== null && avatar.originalname !== 'file' ? avatar.originalname : undefined, sensitive: false, }); console.error(upload); @@ -273,12 +278,11 @@ export class MastodonApiServerService { (_request.body as any).avatar = upload.id; } } - if (tokeninfo && (_request.files as any)['header']) { - const file = toSingleLast((_request.files as any)['header']); + if (tokeninfo && (_request.files as any)['header']) { const upload = await this.driveService.addFile({ user: { id: tokeninfo.userId, host: null }, - path: file.path, - name: file.originalname !== null && file.originalname !== 'file' ? file.originalname : undefined, + path: header.path, + name: header.originalname !== null && header.originalname !== 'file' ? header.originalname : undefined, sensitive: false, }); if (upload.type.startsWith('image/')) { -- cgit v1.2.3-freya From c88fbe843a10c56dbe74311a8eeb4b6b1e025d7b Mon Sep 17 00:00:00 2001 From: Mar0xy Date: Mon, 30 Oct 2023 01:04:55 +0100 Subject: upd: remove debug lines, fix header not being detected --- .../backend/src/server/api/mastodon/MastodonApiServerService.ts | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'packages/backend/src/server/api') diff --git a/packages/backend/src/server/api/mastodon/MastodonApiServerService.ts b/packages/backend/src/server/api/mastodon/MastodonApiServerService.ts index cc61a234d7..bdf3af0588 100644 --- a/packages/backend/src/server/api/mastodon/MastodonApiServerService.ts +++ b/packages/backend/src/server/api/mastodon/MastodonApiServerService.ts @@ -258,27 +258,27 @@ export class MastodonApiServerService { try { if (_request.files.length > 0 && accessTokens) { const tokeninfo = await this.accessTokensRepository.findOneBy({ token: accessTokens.replace('Bearer ', '') }); + // eslint-disable-next-line @typescript-eslint/no-explicit-any const avatar = (_request.files as any).find((obj: any) => { return obj.fieldname === 'avatar'; }); + // eslint-disable-next-line @typescript-eslint/no-explicit-any const header = (_request.files as any).find((obj: any) => { return obj.fieldname === 'header'; }); if (tokeninfo && avatar) { - console.error('avatar'); const upload = await this.driveService.addFile({ user: { id: tokeninfo.userId, host: null }, path: avatar.path, name: avatar.originalname !== null && avatar.originalname !== 'file' ? avatar.originalname : undefined, sensitive: false, }); - console.error(upload); if (upload.type.startsWith('image/')) { + // eslint-disable-next-line @typescript-eslint/no-explicit-any (_request.body as any).avatar = upload.id; } - } - if (tokeninfo && (_request.files as any)['header']) { + } else if (tokeninfo && header) { const upload = await this.driveService.addFile({ user: { id: tokeninfo.userId, host: null }, path: header.path, @@ -286,6 +286,7 @@ export class MastodonApiServerService { sensitive: false, }); if (upload.type.startsWith('image/')) { + // eslint-disable-next-line @typescript-eslint/no-explicit-any (_request.body as any).header = upload.id; } } -- cgit v1.2.3-freya From 81def9457bdf15a566d808dec63e344ee0ebc7d5 Mon Sep 17 00:00:00 2001 From: Mar0xy Date: Mon, 30 Oct 2023 01:32:48 +0100 Subject: upd: allow updating of fields --- .../api/mastodon/MastodonApiServerService.ts | 16 ++++++++++++- .../src/server/api/mastodon/endpoints/account.ts | 28 ++++++++++------------ packages/megalodon/src/misskey.ts | 5 ++++ 3 files changed, 32 insertions(+), 17 deletions(-) (limited to 'packages/backend/src/server/api') diff --git a/packages/backend/src/server/api/mastodon/MastodonApiServerService.ts b/packages/backend/src/server/api/mastodon/MastodonApiServerService.ts index bdf3af0588..55e4615b91 100644 --- a/packages/backend/src/server/api/mastodon/MastodonApiServerService.ts +++ b/packages/backend/src/server/api/mastodon/MastodonApiServerService.ts @@ -14,7 +14,6 @@ import { ApiAuthMastodon, ApiAccountMastodon, ApiFilterMastodon, ApiNotifyMastod import type { FastifyInstance, FastifyPluginOptions } from 'fastify'; import { UserEntityService } from '@/core/entities/UserEntityService.js'; import { DriveService } from '@/core/DriveService.js'; -import { toSingleLast } from '@/misc/prelude/array.js'; export function getClient(BASE_URL: string, authorization: string | undefined): MegalodonInterface { const accessTokenArr = authorization?.split(' ') ?? [null]; @@ -256,6 +255,7 @@ export class MastodonApiServerService { const client = getClient(BASE_URL, accessTokens); // we are using this here, because in private mode some info isnt // displayed without being logged in try { + // Check if there is an Header or Avatar being uploaded, if there is proceed to upload it to the drive of the user and then set it. if (_request.files.length > 0 && accessTokens) { const tokeninfo = await this.accessTokensRepository.findOneBy({ token: accessTokens.replace('Bearer ', '') }); // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -291,6 +291,20 @@ export class MastodonApiServerService { } } } + + if ((_request.body as any).fields_attributes) { + const fields = (_request.body as any).fields_attributes.map((field: any) => { + if (!(field.name.trim() === '' && field.value.trim() === '')) { + if (field.name.trim() === '') return reply.code(400).send('Field name can not be empty'); + if (field.value.trim() === '') return reply.code(400).send('Field value can not be empty'); + } + return { + ...field, + }; + }); + (_request.body as any).fields_attributes = fields.filter((field: any) => field.name.trim().length > 0 && field.value.length > 0); + } + const data = await client.updateCredentials(_request.body!); reply.send(await this.mastoConverter.convertAccount(data.data)); } catch (e: any) { diff --git a/packages/backend/src/server/api/mastodon/endpoints/account.ts b/packages/backend/src/server/api/mastodon/endpoints/account.ts index 39da0e4a53..694879764b 100644 --- a/packages/backend/src/server/api/mastodon/endpoints/account.ts +++ b/packages/backend/src/server/api/mastodon/endpoints/account.ts @@ -39,22 +39,18 @@ export class ApiAccountMastodon { public async verifyCredentials() { try { const data = await this.client.verifyAccountCredentials(); - const acct = data.data; - acct.display_name = acct.display_name || acct.username; - acct.url = `${this.BASE_URL}/@${acct.url}`; - acct.note = acct.note || ''; - acct.avatar_static = acct.avatar; - acct.header = acct.header || '/static-assets/transparent.png'; - acct.header_static = acct.header || '/static-assets/transparent.png'; - acct.source = { - note: acct.note, - fields: acct.fields, - privacy: '', - sensitive: false, - language: '', - }; - console.log(acct); - return acct; + const acct = await this.mastoconverter.convertAccount(data.data); + const newAcct = Object.assign({}, acct, { + source: { + note: acct.note, + fields: acct.fields, + privacy: '', + sensitive: false, + language: '', + }, + }); + console.log(newAcct); + return newAcct; } catch (e: any) { /* console.error(e); console.error(e.response.data); */ diff --git a/packages/megalodon/src/misskey.ts b/packages/megalodon/src/misskey.ts index b81fb77a6b..a0b222c230 100644 --- a/packages/megalodon/src/misskey.ts +++ b/packages/megalodon/src/misskey.ts @@ -248,6 +248,11 @@ export default class Misskey implements MegalodonInterface { bannerId: options.header }) } + if (options.fields_attributes) { + params = Object.assign(params, { + fields: options.fields_attributes + }) + } if (options.locked !== undefined) { params = Object.assign(params, { isLocked: options.locked.toString() === 'true' ? true : false -- cgit v1.2.3-freya From e24a57402b0769fac49174f5f47a8d7a46828812 Mon Sep 17 00:00:00 2001 From: Mar0xy Date: Mon, 30 Oct 2023 01:47:24 +0100 Subject: chore: lint --- packages/backend/src/server/api/mastodon/MastodonApiServerService.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'packages/backend/src/server/api') diff --git a/packages/backend/src/server/api/mastodon/MastodonApiServerService.ts b/packages/backend/src/server/api/mastodon/MastodonApiServerService.ts index 55e4615b91..4a81320de5 100644 --- a/packages/backend/src/server/api/mastodon/MastodonApiServerService.ts +++ b/packages/backend/src/server/api/mastodon/MastodonApiServerService.ts @@ -292,7 +292,9 @@ export class MastodonApiServerService { } } + // eslint-disable-next-line @typescript-eslint/no-explicit-any if ((_request.body as any).fields_attributes) { + // eslint-disable-next-line @typescript-eslint/no-explicit-any const fields = (_request.body as any).fields_attributes.map((field: any) => { if (!(field.name.trim() === '' && field.value.trim() === '')) { if (field.name.trim() === '') return reply.code(400).send('Field name can not be empty'); @@ -302,9 +304,10 @@ export class MastodonApiServerService { ...field, }; }); + // eslint-disable-next-line @typescript-eslint/no-explicit-any (_request.body as any).fields_attributes = fields.filter((field: any) => field.name.trim().length > 0 && field.value.length > 0); } - + const data = await client.updateCredentials(_request.body!); reply.send(await this.mastoConverter.convertAccount(data.data)); } catch (e: any) { -- cgit v1.2.3-freya From 46bb5f2dac16a54bcaedafaed397c8cdc02d7008 Mon Sep 17 00:00:00 2001 From: Mar0xy Date: Mon, 30 Oct 2023 12:53:28 +0100 Subject: fix: lists not being received properly --- packages/backend/src/server/api/mastodon/endpoints/timeline.ts | 3 +-- packages/megalodon/src/misskey.ts | 10 ++++++++-- 2 files changed, 9 insertions(+), 4 deletions(-) (limited to 'packages/backend/src/server/api') diff --git a/packages/backend/src/server/api/mastodon/endpoints/timeline.ts b/packages/backend/src/server/api/mastodon/endpoints/timeline.ts index 152d4a7729..0f2b208153 100644 --- a/packages/backend/src/server/api/mastodon/endpoints/timeline.ts +++ b/packages/backend/src/server/api/mastodon/endpoints/timeline.ts @@ -151,8 +151,7 @@ export class ApiTimelineMastodon { const BASE_URL = `${_request.protocol}://${_request.hostname}`; const accessTokens = _request.headers.authorization; const client = getClient(BASE_URL, accessTokens); - const account = await client.verifyAccountCredentials(); - const data = await client.getLists(account.data.id); + const data = await client.getLists(); reply.send(data.data.map((list: Entity.List) => convertList(list))); } catch (e: any) { console.error(e); diff --git a/packages/megalodon/src/misskey.ts b/packages/megalodon/src/misskey.ts index a0b222c230..7d68d4eddf 100644 --- a/packages/megalodon/src/misskey.ts +++ b/packages/megalodon/src/misskey.ts @@ -1892,9 +1892,15 @@ export default class Misskey implements MegalodonInterface { /** * POST /api/users/lists/list */ - public async getLists(id: string): Promise>> { + public async getLists(id?: string): Promise>> { + if (id) { + return this.client + .post>('/api/users/lists/list', { userId: id }) + .then(res => ({ ...res, data: res.data.map(l => MisskeyAPI.Converter.list(l)) })) + } + return this.client - .post>('/api/users/lists/list', { userId: id }) + .post>('/api/users/lists/list', {}) .then(res => ({ ...res, data: res.data.map(l => MisskeyAPI.Converter.list(l)) })) } -- cgit v1.2.3-freya From 4fa15f27c717f2aba27a8c38cb1ca18629cdd20d Mon Sep 17 00:00:00 2001 From: Mar0xy Date: Mon, 30 Oct 2023 13:00:58 +0100 Subject: fix: deleting a list returning an error as success --- packages/backend/src/server/api/mastodon/endpoints/timeline.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'packages/backend/src/server/api') diff --git a/packages/backend/src/server/api/mastodon/endpoints/timeline.ts b/packages/backend/src/server/api/mastodon/endpoints/timeline.ts index 0f2b208153..f81b63b9ac 100644 --- a/packages/backend/src/server/api/mastodon/endpoints/timeline.ts +++ b/packages/backend/src/server/api/mastodon/endpoints/timeline.ts @@ -257,7 +257,7 @@ export class ApiTimelineMastodon { const client = getClient(BASE_URL, accessTokens); const params: any = _request.params; const data = await client.deleteList(params.id); - reply.send(data.data); + reply.send({}); } catch (e: any) { console.error(e); console.error(e.response.data); -- cgit v1.2.3-freya From d15c588080a56811d19b03d054080d5be64f64f1 Mon Sep 17 00:00:00 2001 From: Mar0xy Date: Tue, 31 Oct 2023 11:31:31 +0100 Subject: upd: change handling of suggestions and status trends --- .../src/server/api/mastodon/endpoints/search.ts | 101 ++++++--------------- packages/megalodon/src/megalodon.ts | 2 +- 2 files changed, 30 insertions(+), 73 deletions(-) (limited to 'packages/backend/src/server/api') diff --git a/packages/backend/src/server/api/mastodon/endpoints/search.ts b/packages/backend/src/server/api/mastodon/endpoints/search.ts index 772ef33076..633a3d05e4 100644 --- a/packages/backend/src/server/api/mastodon/endpoints/search.ts +++ b/packages/backend/src/server/api/mastodon/endpoints/search.ts @@ -1,63 +1,8 @@ -import { Converter } from 'megalodon'; -import { MastoConverters, convertAccount, convertStatus } from '../converters.js'; +import { MastoConverters } from '../converters.js'; import { limitToInt } from './timeline.js'; import type { MegalodonInterface } from 'megalodon'; import type { FastifyRequest } from 'fastify'; -async function getHighlight( - BASE_URL: string, - domain: string, - accessTokens: string | undefined, -) { - const accessTokenArr = accessTokens?.split(' ') ?? [null]; - const accessToken = accessTokenArr[accessTokenArr.length - 1]; - try { - const apicall = await fetch(`${BASE_URL}/api/notes/featured`, - { - method: 'POST', - headers: { - 'Accept': 'application/json, text/plain, */*', - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ i: accessToken }), - }); - const api = await apicall.json(); - const data: MisskeyEntity.Note[] = api; - return data.map((note) => Converter.note(note, domain)); - } catch (e: any) { - console.log(e); - console.log(e.response.data); - return []; - } -} - -async function getFeaturedUser( BASE_URL: string, host: string, accessTokens: string | undefined, limit: number ) { - const accessTokenArr = accessTokens?.split(' ') ?? [null]; - const accessToken = accessTokenArr[accessTokenArr.length - 1]; - try { - const apicall = await fetch(`${BASE_URL}/api/users`, - { - method: 'POST', - headers: { - 'Accept': 'application/json, text/plain, */*', - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ i: accessToken, limit, origin: 'local', sort: '+follower', state: 'alive' }), - }); - const api = await apicall.json(); - const data: MisskeyEntity.UserDetail[] = api; - return data.map((u) => { - return { - source: 'past_interactions', - account: Converter.userDetail(u, host), - }; - }); - } catch (e: any) { - console.log(e); - console.log(e.response.data); - return []; - } -} export class ApiSearchMastodon { private request: FastifyRequest; private client: MegalodonInterface; @@ -89,8 +34,8 @@ export class ApiSearchMastodon { const stat = !type || type === 'statuses' ? await this.client.search(query.q, { type: 'statuses', ...query }) : null; const tags = !type || type === 'hashtags' ? await this.client.search(query.q, { type: 'hashtags', ...query }) : null; const data = { - accounts: await Promise.all(acct?.data.accounts.map(async (account) => await this.mastoConverter.convertAccount(account)) ?? []), - statuses: await Promise.all(stat?.data.statuses.map(async (status) => await this.mastoConverter.convertStatus(status)) ?? []), + accounts: await Promise.all(acct?.data.accounts.map(async (account: any) => await this.mastoConverter.convertAccount(account)) ?? []), + statuses: await Promise.all(stat?.data.statuses.map(async (status: any) => await this.mastoConverter.convertStatus(status)) ?? []), hashtags: tags?.data.hashtags ?? [], }; return data; @@ -102,27 +47,39 @@ export class ApiSearchMastodon { public async getStatusTrends() { try { - const data = await getHighlight( - this.BASE_URL, - this.request.hostname, - this.request.headers.authorization, - ); - return data.map((status) => convertStatus(status)); + let map; + await fetch(`${this.BASE_URL}/api/notes/featured`, + { + method: 'POST', + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json', + }, + body: JSON.stringify({}), + }) + .then(res => res.json()) + .then((data) => { + map = data.map((status: any) => this.mastoConverter.convertStatus(status)); + }); + return map; } catch (e: any) { console.error(e); - return e.response.data; + return []; } } public async getSuggestions() { try { - const data = await getFeaturedUser( - this.BASE_URL, - this.request.hostname, - this.request.headers.authorization, - (this.request.query as any).limit || 20, - ); - return data.map((suggestion) => { suggestion.account = convertAccount(suggestion.account); return suggestion; }); + const data = await fetch(`${this.BASE_URL}/api/users`, + { + method: 'POST', + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ i: this.request.headers.authorization?.replace('Bearer ', ''), limit: (this.request.query as any).limit || 20, origin: 'local', sort: '+follower', state: 'alive' }), + }).then((res) => res.json()).then((data) => data.map(((entry: any) => { return { source: 'global', account: entry }; }))); + return Promise.all(data.map(async (suggestion: any) => { suggestion.account = await this.mastoConverter.convertAccount(suggestion.account); return suggestion; })); } catch (e: any) { console.error(e); return e.response.data; diff --git a/packages/megalodon/src/megalodon.ts b/packages/megalodon/src/megalodon.ts index 19cd5c5551..e2245f7c21 100644 --- a/packages/megalodon/src/megalodon.ts +++ b/packages/megalodon/src/megalodon.ts @@ -1041,7 +1041,7 @@ export interface MegalodonInterface { * * @return Array of lists. */ - getLists(id: string): Promise>> + getLists(id?: string): Promise>> /** * Show a single list. * -- cgit v1.2.3-freya From 0a9ca195e27321c8f959bfb69a7272a70bfaaa89 Mon Sep 17 00:00:00 2001 From: Mar0xy Date: Tue, 31 Oct 2023 11:34:25 +0100 Subject: fix: create trends/tags endpoint --- .../src/server/api/mastodon/MastodonApiServerService.ts | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'packages/backend/src/server/api') diff --git a/packages/backend/src/server/api/mastodon/MastodonApiServerService.ts b/packages/backend/src/server/api/mastodon/MastodonApiServerService.ts index 4a81320de5..8a93392599 100644 --- a/packages/backend/src/server/api/mastodon/MastodonApiServerService.ts +++ b/packages/backend/src/server/api/mastodon/MastodonApiServerService.ts @@ -207,6 +207,20 @@ export class MastodonApiServerService { } }); + fastify.get('/v1/trends/tags', async (_request, reply) => { + const BASE_URL = `${_request.protocol}://${_request.hostname}`; + const accessTokens = _request.headers.authorization; + const client = getClient(BASE_URL, accessTokens); // we are using this here, because in private mode some info isnt + // displayed without being logged in + try { + const data = await client.getInstanceTrends(); + reply.send(data.data); + } catch (e: any) { + /* console.error(e); */ + reply.code(401).send(e.response.data); + } + }); + fastify.post('/v1/apps', async (_request, reply) => { const BASE_URL = `${_request.protocol}://${_request.hostname}`; const client = getClient(BASE_URL, ''); // we are using this here, because in private mode some info isnt -- cgit v1.2.3-freya From 171ba6f4f579d7bec3b662e1b19651056a50f62b Mon Sep 17 00:00:00 2001 From: Mar0xy Date: Tue, 31 Oct 2023 11:38:23 +0100 Subject: chore: change style of getStatusTrends --- packages/backend/src/server/api/mastodon/endpoints/search.ts | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) (limited to 'packages/backend/src/server/api') diff --git a/packages/backend/src/server/api/mastodon/endpoints/search.ts b/packages/backend/src/server/api/mastodon/endpoints/search.ts index 633a3d05e4..2087d13ad0 100644 --- a/packages/backend/src/server/api/mastodon/endpoints/search.ts +++ b/packages/backend/src/server/api/mastodon/endpoints/search.ts @@ -47,8 +47,7 @@ export class ApiSearchMastodon { public async getStatusTrends() { try { - let map; - await fetch(`${this.BASE_URL}/api/notes/featured`, + const data = await fetch(`${this.BASE_URL}/api/notes/featured`, { method: 'POST', headers: { @@ -58,10 +57,8 @@ export class ApiSearchMastodon { body: JSON.stringify({}), }) .then(res => res.json()) - .then((data) => { - map = data.map((status: any) => this.mastoConverter.convertStatus(status)); - }); - return map; + .then(data => data.map((status: any) => this.mastoConverter.convertStatus(status))); + return data; } catch (e: any) { console.error(e); return []; @@ -82,7 +79,7 @@ export class ApiSearchMastodon { return Promise.all(data.map(async (suggestion: any) => { suggestion.account = await this.mastoConverter.convertAccount(suggestion.account); return suggestion; })); } catch (e: any) { console.error(e); - return e.response.data; + return []; } } } -- cgit v1.2.3-freya From 98389114a8cba8c41f861bf7f8036827069042bf Mon Sep 17 00:00:00 2001 From: Mar0xy Date: Tue, 31 Oct 2023 11:46:08 +0100 Subject: fix: suggestions --- packages/backend/src/server/api/mastodon/endpoints/search.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'packages/backend/src/server/api') diff --git a/packages/backend/src/server/api/mastodon/endpoints/search.ts b/packages/backend/src/server/api/mastodon/endpoints/search.ts index 2087d13ad0..432a1f144d 100644 --- a/packages/backend/src/server/api/mastodon/endpoints/search.ts +++ b/packages/backend/src/server/api/mastodon/endpoints/search.ts @@ -74,8 +74,8 @@ export class ApiSearchMastodon { 'Accept': 'application/json', 'Content-Type': 'application/json', }, - body: JSON.stringify({ i: this.request.headers.authorization?.replace('Bearer ', ''), limit: (this.request.query as any).limit || 20, origin: 'local', sort: '+follower', state: 'alive' }), - }).then((res) => res.json()).then((data) => data.map(((entry: any) => { return { source: 'global', account: entry }; }))); + body: JSON.stringify({ limit: (this.request.query as any).limit || 20, origin: 'local', sort: '+follower', state: 'alive' }), + }).then((res) => res.json()).then(data => data.map(((entry: any) => { return { source: 'global', account: entry }; }))); return Promise.all(data.map(async (suggestion: any) => { suggestion.account = await this.mastoConverter.convertAccount(suggestion.account); return suggestion; })); } catch (e: any) { console.error(e); -- cgit v1.2.3-freya From c18efe0042a8f87a7fc204e6f7bc29ff4f505e7e Mon Sep 17 00:00:00 2001 From: Mar0xy Date: Tue, 31 Oct 2023 11:49:34 +0100 Subject: upd: add empty return on trends/links --- packages/backend/src/server/api/mastodon/MastodonApiServerService.ts | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'packages/backend/src/server/api') diff --git a/packages/backend/src/server/api/mastodon/MastodonApiServerService.ts b/packages/backend/src/server/api/mastodon/MastodonApiServerService.ts index 8a93392599..c0e4ea80dc 100644 --- a/packages/backend/src/server/api/mastodon/MastodonApiServerService.ts +++ b/packages/backend/src/server/api/mastodon/MastodonApiServerService.ts @@ -221,6 +221,11 @@ export class MastodonApiServerService { } }); + fastify.get('/v1/trends/links', async (_request, reply) => { + // As we do not have any system for news/links this will just return empty + reply.send([]); + }); + fastify.post('/v1/apps', async (_request, reply) => { const BASE_URL = `${_request.protocol}://${_request.hostname}`; const client = getClient(BASE_URL, ''); // we are using this here, because in private mode some info isnt -- cgit v1.2.3-freya From 6673c7fc13e45141ce9ec10cf4b8d9eb25f6a1fc Mon Sep 17 00:00:00 2001 From: Mar0xy Date: Tue, 31 Oct 2023 12:06:47 +0100 Subject: fix: limit query being returned as string instead of int --- packages/backend/src/server/api/mastodon/endpoints/search.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'packages/backend/src/server/api') diff --git a/packages/backend/src/server/api/mastodon/endpoints/search.ts b/packages/backend/src/server/api/mastodon/endpoints/search.ts index 432a1f144d..500129c901 100644 --- a/packages/backend/src/server/api/mastodon/endpoints/search.ts +++ b/packages/backend/src/server/api/mastodon/endpoints/search.ts @@ -74,7 +74,7 @@ export class ApiSearchMastodon { 'Accept': 'application/json', 'Content-Type': 'application/json', }, - body: JSON.stringify({ limit: (this.request.query as any).limit || 20, origin: 'local', sort: '+follower', state: 'alive' }), + body: JSON.stringify({ i: this.request.headers.authorization?.replace('Bearer ', ''), limit: parseInt((this.request.query as any).limit) || 20, origin: 'local', sort: '+follower', state: 'alive' }), }).then((res) => res.json()).then(data => data.map(((entry: any) => { return { source: 'global', account: entry }; }))); return Promise.all(data.map(async (suggestion: any) => { suggestion.account = await this.mastoConverter.convertAccount(suggestion.account); return suggestion; })); } catch (e: any) { -- cgit v1.2.3-freya From b57b644ec6ba51c5d561fc499e21dc9632858746 Mon Sep 17 00:00:00 2001 From: Mar0xy Date: Tue, 31 Oct 2023 12:13:37 +0100 Subject: chore: remove console log on verify_credentials --- packages/backend/src/server/api/mastodon/endpoints/account.ts | 1 - 1 file changed, 1 deletion(-) (limited to 'packages/backend/src/server/api') diff --git a/packages/backend/src/server/api/mastodon/endpoints/account.ts b/packages/backend/src/server/api/mastodon/endpoints/account.ts index 694879764b..07d9efb8c1 100644 --- a/packages/backend/src/server/api/mastodon/endpoints/account.ts +++ b/packages/backend/src/server/api/mastodon/endpoints/account.ts @@ -49,7 +49,6 @@ export class ApiAccountMastodon { language: '', }, }); - console.log(newAcct); return newAcct; } catch (e: any) { /* console.error(e); -- cgit v1.2.3-freya