summaryrefslogtreecommitdiff
path: root/packages/backend/src/server/api/mastodon/MastodonApiServerService.ts
diff options
context:
space:
mode:
Diffstat (limited to 'packages/backend/src/server/api/mastodon/MastodonApiServerService.ts')
-rw-r--r--packages/backend/src/server/api/mastodon/MastodonApiServerService.ts192
1 files changed, 192 insertions, 0 deletions
diff --git a/packages/backend/src/server/api/mastodon/MastodonApiServerService.ts b/packages/backend/src/server/api/mastodon/MastodonApiServerService.ts
new file mode 100644
index 0000000000..b79489d18d
--- /dev/null
+++ b/packages/backend/src/server/api/mastodon/MastodonApiServerService.ts
@@ -0,0 +1,192 @@
+import { fileURLToPath } from 'node:url';
+import { Inject, Injectable } from '@nestjs/common';
+import type { UsersRepository } from '@/models/_.js';
+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 { 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';
+
+const staticAssets = fileURLToPath(new URL('../../../../assets/', import.meta.url));
+
+export function getClient(BASE_URL: string, authorization: string | undefined): MegalodonInterface {
+ const accessTokenArr = authorization?.split(" ") ?? [null];
+ const accessToken = accessTokenArr[accessTokenArr.length - 1];
+ const generator = (megalodon as any).default;
+ const client = generator(BASE_URL, accessToken) as MegalodonInterface;
+ return client;
+}
+
+@Injectable()
+export class MastodonApiServerService {
+ constructor(
+ @Inject(DI.usersRepository)
+ private usersRepository: UsersRepository,
+ @Inject(DI.config)
+ private config: Config,
+ private metaService: MetaService,
+ ) { }
+
+ @bindThis
+ public createServer(fastify: FastifyInstance, _options: FastifyPluginOptions, done: (err?: Error) => void) {
+ const upload = multer({
+ storage: multer.diskStorage({}),
+ limits: {
+ fileSize: this.config.maxFileSize || 262144000,
+ files: 1,
+ },
+ });
+
+ fastify.register(multer.contentParser);
+
+ fastify.get("/v1/custom_emojis", 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.getInstanceCustomEmojis();
+ reply.send(data.data);
+ } catch (e: any) {
+ console.error(e);
+ reply.code(401).send(e.response.data);
+ }
+ });
+
+ fastify.get("/v1/instance", 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.getInstance();
+ const admin = await this.usersRepository.findOne({
+ where: {
+ host: IsNull(),
+ isRoot: true,
+ isDeleted: false,
+ isSuspended: false,
+ },
+ 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()));
+ } catch (e: any) {
+ console.error(e);
+ reply.code(401).send(e.response.data);
+ }
+ });
+
+ fastify.get("/v1/announcements", 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.getInstanceAnnouncements();
+ reply.send(data.data.map((announcement) => convertAnnouncement(announcement)));
+ } catch (e: any) {
+ console.error(e);
+ reply.code(401).send(e.response.data);
+ }
+ });
+
+ fastify.post<{ Body: { id: string } }>("/v1/announcements/:id/dismiss", 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.dismissInstanceAnnouncement(
+ convertId(_request.body['id'], IdType.SharkeyId)
+ );
+ reply.send(data.data);
+ } catch (e: any) {
+ console.error(e);
+ reply.code(401).send(e.response.data);
+ }
+ },
+ );
+
+ fastify.post("/v1/media", { preHandler: upload.single('file') }, async (_request, reply) => {
+ const BASE_URL = `${_request.protocol}://${_request.hostname}`;
+ const accessTokens = _request.headers.authorization;
+ const client = getClient(BASE_URL, accessTokens);
+ try {
+ const multipartData = await _request.file;
+ if (!multipartData) {
+ reply.code(401).send({ error: "No image" });
+ return;
+ }
+ const data = await client.uploadMedia(multipartData);
+ reply.send(convertAttachment(data.data as Entity.Attachment));
+ } catch (e: any) {
+ console.error(e);
+ reply.code(401).send(e.response.data);
+ }
+ });
+
+ fastify.post("/v2/media", { preHandler: upload.single('file') }, async (_request, reply) => {
+ const BASE_URL = `${_request.protocol}://${_request.hostname}`;
+ const accessTokens = _request.headers.authorization;
+ const client = getClient(BASE_URL, accessTokens);
+ try {
+ const multipartData = await _request.file;
+ if (!multipartData) {
+ reply.code(401).send({ error: "No image" });
+ return;
+ }
+ const data = await client.uploadMedia(multipartData, _request.body!);
+ reply.send(convertAttachment(data.data as Entity.Attachment));
+ } catch (e: any) {
+ console.error(e);
+ reply.code(401).send(e.response.data);
+ }
+ });
+
+ fastify.get("/v1/filters", 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.getFilters();
+ reply.send(data.data.map((filter) => convertFilter(filter)));
+ } catch (e: any) {
+ console.error(e);
+ reply.code(401).send(e.response.data);
+ }
+ });
+
+ fastify.get("/v1/trends", 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.get("/v1/preferences", 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.getPreferences();
+ reply.send(data.data);
+ } catch (e: any) {
+ console.error(e);
+ reply.code(401).send(e.response.data);
+ }
+ });
+ done();
+ }
+} \ No newline at end of file