sharkey/packages/backend/src/server/api/mastodon/MastodonApiServerService.ts
2023-09-23 18:51:57 +02:00

192 lines
8.4 KiB
TypeScript

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();
}
}