diff --git a/packages/backend/src/server/api/mastodon/MastodonApiServerService.ts b/packages/backend/src/server/api/mastodon/MastodonApiServerService.ts index 3af93fda66..9d1ee61053 100644 --- a/packages/backend/src/server/api/mastodon/MastodonApiServerService.ts +++ b/packages/backend/src/server/api/mastodon/MastodonApiServerService.ts @@ -5,12 +5,14 @@ import { DI } from '@/di-symbols.js'; import { bindThis } from '@/decorators.js'; import megalodon, { MegalodonInterface } from "megalodon"; import type { FastifyInstance, FastifyPluginOptions } from 'fastify'; -import { convertId, IdConvertType as IdType, convertAccount, convertAnnouncement, convertFilter, convertAttachment } from './converters.js'; +import { convertId, IdConvertType as IdType, convertAccount, convertAnnouncement, convertFilter, convertAttachment, convertFeaturedTag } from './converters.js'; import { IsNull } from 'typeorm'; import type { Config } from '@/config.js'; import { getInstance } from './endpoints/meta.js'; import { MetaService } from '@/core/MetaService.js'; import multer from 'fastify-multer'; +import { apiAuthMastodon } from './endpoints/auth.js'; +import { apiAccountMastodon } from './endpoints/account.js'; const staticAssets = fileURLToPath(new URL('../../../../assets/', import.meta.url)); @@ -173,6 +175,19 @@ export class MastodonApiServerService { 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 + // displayed without being logged in + try { + const data = await apiAuthMastodon(_request, client); + reply.send(data); + } catch (e: any) { + console.error(e); + reply.code(401).send(e.response.data); + } + }); fastify.get("/v1/preferences", async (_request, reply) => { const BASE_URL = `${_request.protocol}://${_request.hostname}`; @@ -186,7 +201,145 @@ export class MastodonApiServerService { console.error(e); reply.code(401).send(e.response.data); } - }); + }); + + //#region Accounts + fastify.get("/v1/accounts/verify_credentials", 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 account = new apiAccountMastodon(_request, client, BASE_URL); + reply.send(await account.verifyCredentials()); + } catch (e: any) { + console.error(e); + reply.code(401).send(e.response.data); + } + }); + + fastify.patch("/v1/accounts/update_credentials", 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 account = new apiAccountMastodon(_request, client, BASE_URL); + reply.send(await account.updateCredentials()); + } catch (e: any) { + console.error(e); + reply.code(401).send(e.response.data); + } + }); + + fastify.get("/v1/accounts/lookup", 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 account = new apiAccountMastodon(_request, client, BASE_URL); + reply.send(await account.lookup()); + } catch (e: any) { + console.error(e); + reply.code(401).send(e.response.data); + } + }); + + fastify.get("/v1/accounts/relationships", 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 + let users; + try { + let ids = _request.query ? (_request.query as any)["id[]"] : null; + if (typeof ids === "string") { + ids = [ids]; + } + users = ids; + const account = new apiAccountMastodon(_request, client, BASE_URL); + reply.send(await account.getRelationships(users)); + } catch (e: any) { + console.error(e); + let data = e.response.data; + data.users = users; + console.error(data); + reply.code(401).send(data); + } + }); + + fastify.get<{ Params: { id: string } }>("/v1/accounts/:id", async (_request, reply) => { + const BASE_URL = `${_request.protocol}://${_request.hostname}`; + const accessTokens = _request.headers.authorization; + const client = getClient(BASE_URL, accessTokens); + try { + const sharkId = convertId(_request.params.id, IdType.SharkeyId); + const data = await client.getAccount(sharkId); + reply.send(convertAccount(data.data)); + } catch (e: any) { + console.error(e); + console.error(e.response.data); + reply.code(401).send(e.response.data); + } + }); + + fastify.get<{ Params: { id: string } }>("/v1/accounts/:id/statuses", async (_request, reply) => { + const BASE_URL = `${_request.protocol}://${_request.hostname}`; + const accessTokens = _request.headers.authorization; + const client = getClient(BASE_URL, accessTokens); + try { + const account = new apiAccountMastodon(_request, client, BASE_URL); + reply.send(await account.getStatuses()); + } catch (e: any) { + console.error(e); + console.error(e.response.data); + reply.code(401).send(e.response.data); + } + }); + + fastify.get<{ Params: { id: string } }>("/v1/accounts/:id/featured_tags", async (_request, reply) => { + const BASE_URL = `${_request.protocol}://${_request.hostname}`; + const accessTokens = _request.headers.authorization; + const client = getClient(BASE_URL, accessTokens); + try { + const data = await client.getAccountFeaturedTags(convertId(_request.params.id, IdType.SharkeyId)); + reply.send(data.data.map((tag) => convertFeaturedTag(tag))); + } catch (e: any) { + console.error(e); + console.error(e.response.data); + reply.code(401).send(e.response.data); + } + }); + + fastify.get<{ Params: { id: string } }>("/v1/accounts/:id/followers", async (_request, reply) => { + const BASE_URL = `${_request.protocol}://${_request.hostname}`; + const accessTokens = _request.headers.authorization; + const client = getClient(BASE_URL, accessTokens); + try { + const account = new apiAccountMastodon(_request, client, BASE_URL); + reply.send(await account.getFollowers()); + } catch (e: any) { + console.error(e); + console.error(e.response.data); + reply.code(401).send(e.response.data); + } + }); + + fastify.get<{ Params: { id: string } }>("/v1/accounts/:id/following", async (_request, reply) => { + const BASE_URL = `${_request.protocol}://${_request.hostname}`; + const accessTokens = _request.headers.authorization; + const client = getClient(BASE_URL, accessTokens); + try { + const account = new apiAccountMastodon(_request, client, BASE_URL); + reply.send(await account.getFollowing()); + } catch (e: any) { + console.error(e); + console.error(e.response.data); + reply.code(401).send(e.response.data); + } + }); + //#endregion done(); } } \ No newline at end of file