refactor mastodon API and preserve remote user agent for requests
This commit is contained in:
parent
92382b2ed4
commit
f61d71ac8c
17 changed files with 1319 additions and 1447 deletions
|
|
@ -3,87 +3,97 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { getErrorData, MastodonLogger } from '@/server/api/mastodon/MastodonLogger.js';
|
||||
import { MastodonClientService } from '@/server/api/mastodon/MastodonClientService.js';
|
||||
import { convertList, MastoConverters } from '../converters.js';
|
||||
import { getClient, MastodonApiServerService } from '../MastodonApiServerService.js';
|
||||
import { parseTimelineArgs, TimelineArgs, toBoolean } from '../timelineArgs.js';
|
||||
import { parseTimelineArgs, TimelineArgs, toBoolean } from '../argsUtils.js';
|
||||
import type { Entity } from 'megalodon';
|
||||
import type { FastifyInstance } from 'fastify';
|
||||
|
||||
@Injectable()
|
||||
export class ApiTimelineMastodon {
|
||||
constructor(
|
||||
private readonly fastify: FastifyInstance,
|
||||
private readonly clientService: MastodonClientService,
|
||||
private readonly mastoConverters: MastoConverters,
|
||||
private readonly logger: MastodonLogger,
|
||||
private readonly mastodon: MastodonApiServerService,
|
||||
) {}
|
||||
|
||||
public getTL() {
|
||||
this.fastify.get<{ Querystring: TimelineArgs }>('/v1/timelines/public', async (_request, reply) => {
|
||||
public register(fastify: FastifyInstance): void {
|
||||
fastify.get<{ Querystring: TimelineArgs }>('/v1/timelines/public', async (_request, reply) => {
|
||||
try {
|
||||
const { client, me } = await this.mastodon.getAuthClient(_request);
|
||||
const { client, me } = await this.clientService.getAuthClient(_request);
|
||||
|
||||
const query = parseTimelineArgs(_request.query);
|
||||
const data = toBoolean(_request.query.local)
|
||||
? await client.getLocalTimeline(parseTimelineArgs(_request.query))
|
||||
: await client.getPublicTimeline(parseTimelineArgs(_request.query));
|
||||
reply.send(await Promise.all(data.data.map(async (status: Entity.Status) => await this.mastoConverters.convertStatus(status, me))));
|
||||
? await client.getLocalTimeline(query)
|
||||
: await client.getPublicTimeline(query);
|
||||
const response = await Promise.all(data.data.map((status: Entity.Status) => this.mastoConverters.convertStatus(status, me)));
|
||||
|
||||
reply.send(response);
|
||||
} catch (e) {
|
||||
const data = getErrorData(e);
|
||||
this.logger.error('GET /v1/timelines/public', data);
|
||||
reply.code(401).send(data);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public getHomeTl() {
|
||||
this.fastify.get<{ Querystring: TimelineArgs }>('/v1/timelines/home', async (_request, reply) => {
|
||||
fastify.get<{ Querystring: TimelineArgs }>('/v1/timelines/home', async (_request, reply) => {
|
||||
try {
|
||||
const { client, me } = await this.mastodon.getAuthClient(_request);
|
||||
const data = await client.getHomeTimeline(parseTimelineArgs(_request.query));
|
||||
reply.send(await Promise.all(data.data.map(async (status: Entity.Status) => await this.mastoConverters.convertStatus(status, me))));
|
||||
const { client, me } = await this.clientService.getAuthClient(_request);
|
||||
const query = parseTimelineArgs(_request.query);
|
||||
const data = await client.getHomeTimeline(query);
|
||||
const response = await Promise.all(data.data.map((status: Entity.Status) => this.mastoConverters.convertStatus(status, me)));
|
||||
|
||||
reply.send(response);
|
||||
} catch (e) {
|
||||
const data = getErrorData(e);
|
||||
this.logger.error('GET /v1/timelines/home', data);
|
||||
reply.code(401).send(data);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public getTagTl() {
|
||||
this.fastify.get<{ Params: { hashtag?: string }, Querystring: TimelineArgs }>('/v1/timelines/tag/:hashtag', async (_request, reply) => {
|
||||
fastify.get<{ Params: { hashtag?: string }, Querystring: TimelineArgs }>('/v1/timelines/tag/:hashtag', async (_request, reply) => {
|
||||
try {
|
||||
if (!_request.params.hashtag) return reply.code(400).send({ error: 'Missing required parameter "hashtag"' });
|
||||
const { client, me } = await this.mastodon.getAuthClient(_request);
|
||||
const data = await client.getTagTimeline(_request.params.hashtag, parseTimelineArgs(_request.query));
|
||||
reply.send(await Promise.all(data.data.map(async (status: Entity.Status) => await this.mastoConverters.convertStatus(status, me))));
|
||||
|
||||
const { client, me } = await this.clientService.getAuthClient(_request);
|
||||
const query = parseTimelineArgs(_request.query);
|
||||
const data = await client.getTagTimeline(_request.params.hashtag, query);
|
||||
const response = await Promise.all(data.data.map((status: Entity.Status) => this.mastoConverters.convertStatus(status, me)));
|
||||
|
||||
reply.send(response);
|
||||
} catch (e) {
|
||||
const data = getErrorData(e);
|
||||
this.logger.error(`GET /v1/timelines/tag/${_request.params.hashtag}`, data);
|
||||
reply.code(401).send(data);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public getListTL() {
|
||||
this.fastify.get<{ Params: { id?: string }, Querystring: TimelineArgs }>('/v1/timelines/list/:id', async (_request, reply) => {
|
||||
fastify.get<{ Params: { id?: string }, Querystring: TimelineArgs }>('/v1/timelines/list/:id', async (_request, reply) => {
|
||||
try {
|
||||
if (!_request.params.id) return reply.code(400).send({ error: 'Missing required parameter "id"' });
|
||||
const { client, me } = await this.mastodon.getAuthClient(_request);
|
||||
const data = await client.getListTimeline(_request.params.id, parseTimelineArgs(_request.query));
|
||||
reply.send(await Promise.all(data.data.map(async (status: Entity.Status) => await this.mastoConverters.convertStatus(status, me))));
|
||||
|
||||
const { client, me } = await this.clientService.getAuthClient(_request);
|
||||
const query = parseTimelineArgs(_request.query);
|
||||
const data = await client.getListTimeline(_request.params.id, query);
|
||||
const response = await Promise.all(data.data.map(async (status: Entity.Status) => await this.mastoConverters.convertStatus(status, me)));
|
||||
|
||||
reply.send(response);
|
||||
} catch (e) {
|
||||
const data = getErrorData(e);
|
||||
this.logger.error(`GET /v1/timelines/list/${_request.params.id}`, data);
|
||||
reply.code(401).send(data);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public getConversations() {
|
||||
this.fastify.get<{ Querystring: TimelineArgs }>('/v1/conversations', async (_request, reply) => {
|
||||
fastify.get<{ Querystring: TimelineArgs }>('/v1/conversations', async (_request, reply) => {
|
||||
try {
|
||||
const { client, me } = await this.mastodon.getAuthClient(_request);
|
||||
const data = await client.getConversationTimeline(parseTimelineArgs(_request.query));
|
||||
const conversations = await Promise.all(data.data.map(async (conversation: Entity.Conversation) => await this.mastoConverters.convertConversation(conversation, me)));
|
||||
const { client, me } = await this.clientService.getAuthClient(_request);
|
||||
const query = parseTimelineArgs(_request.query);
|
||||
const data = await client.getConversationTimeline(query);
|
||||
const conversations = await Promise.all(data.data.map((conversation: Entity.Conversation) => this.mastoConverters.convertConversation(conversation, me)));
|
||||
|
||||
reply.send(conversations);
|
||||
} catch (e) {
|
||||
const data = getErrorData(e);
|
||||
|
|
@ -91,50 +101,45 @@ export class ApiTimelineMastodon {
|
|||
reply.code(401).send(data);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public getList() {
|
||||
this.fastify.get<{ Params: { id?: string } }>('/v1/lists/:id', async (_request, reply) => {
|
||||
fastify.get<{ Params: { id?: string } }>('/v1/lists/:id', async (_request, reply) => {
|
||||
try {
|
||||
if (!_request.params.id) return reply.code(400).send({ error: 'Missing required parameter "id"' });
|
||||
const BASE_URL = `${_request.protocol}://${_request.host}`;
|
||||
const accessTokens = _request.headers.authorization;
|
||||
const client = getClient(BASE_URL, accessTokens);
|
||||
|
||||
const client = this.clientService.getClient(_request);
|
||||
const data = await client.getList(_request.params.id);
|
||||
reply.send(convertList(data.data));
|
||||
const response = convertList(data.data);
|
||||
|
||||
reply.send(response);
|
||||
} catch (e) {
|
||||
const data = getErrorData(e);
|
||||
this.logger.error(`GET /v1/lists/${_request.params.id}`, data);
|
||||
reply.code(401).send(data);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public getLists() {
|
||||
this.fastify.get('/v1/lists', async (_request, reply) => {
|
||||
fastify.get('/v1/lists', async (_request, reply) => {
|
||||
try {
|
||||
const BASE_URL = `${_request.protocol}://${_request.host}`;
|
||||
const accessTokens = _request.headers.authorization;
|
||||
const client = getClient(BASE_URL, accessTokens);
|
||||
const client = this.clientService.getClient(_request);
|
||||
const data = await client.getLists();
|
||||
reply.send(data.data.map((list: Entity.List) => convertList(list)));
|
||||
const response = data.data.map((list: Entity.List) => convertList(list));
|
||||
|
||||
reply.send(response);
|
||||
} catch (e) {
|
||||
const data = getErrorData(e);
|
||||
this.logger.error('GET /v1/lists', data);
|
||||
reply.code(401).send(data);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public getListAccounts() {
|
||||
this.fastify.get<{ Params: { id?: string }, Querystring: { limit?: number, max_id?: string, since_id?: string } }>('/v1/lists/:id/accounts', async (_request, reply) => {
|
||||
fastify.get<{ Params: { id?: string }, Querystring: { limit?: number, max_id?: string, since_id?: string } }>('/v1/lists/:id/accounts', async (_request, reply) => {
|
||||
try {
|
||||
if (!_request.params.id) return reply.code(400).send({ error: 'Missing required parameter "id"' });
|
||||
const BASE_URL = `${_request.protocol}://${_request.host}`;
|
||||
const accessTokens = _request.headers.authorization;
|
||||
const client = getClient(BASE_URL, accessTokens);
|
||||
|
||||
const client = this.clientService.getClient(_request);
|
||||
const data = await client.getAccountsInList(_request.params.id, _request.query);
|
||||
const accounts = await Promise.all(data.data.map((account: Entity.Account) => this.mastoConverters.convertAccount(account)));
|
||||
|
||||
reply.send(accounts);
|
||||
} catch (e) {
|
||||
const data = getErrorData(e);
|
||||
|
|
@ -142,17 +147,15 @@ export class ApiTimelineMastodon {
|
|||
reply.code(401).send(data);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public addListAccount() {
|
||||
this.fastify.post<{ Params: { id?: string }, Querystring: { accounts_id?: string[] } }>('/v1/lists/:id/accounts', async (_request, reply) => {
|
||||
fastify.post<{ Params: { id?: string }, Querystring: { accounts_id?: string[] } }>('/v1/lists/:id/accounts', async (_request, reply) => {
|
||||
try {
|
||||
if (!_request.params.id) return reply.code(400).send({ error: 'Missing required parameter "id"' });
|
||||
if (!_request.query.accounts_id) return reply.code(400).send({ error: 'Missing required property "accounts_id"' });
|
||||
const BASE_URL = `${_request.protocol}://${_request.host}`;
|
||||
const accessTokens = _request.headers.authorization;
|
||||
const client = getClient(BASE_URL, accessTokens);
|
||||
|
||||
const client = this.clientService.getClient(_request);
|
||||
const data = await client.addAccountsToList(_request.params.id, _request.query.accounts_id);
|
||||
|
||||
reply.send(data.data);
|
||||
} catch (e) {
|
||||
const data = getErrorData(e);
|
||||
|
|
@ -160,17 +163,15 @@ export class ApiTimelineMastodon {
|
|||
reply.code(401).send(data);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public rmListAccount() {
|
||||
this.fastify.delete<{ Params: { id?: string }, Querystring: { accounts_id?: string[] } }>('/v1/lists/:id/accounts', async (_request, reply) => {
|
||||
fastify.delete<{ Params: { id?: string }, Querystring: { accounts_id?: string[] } }>('/v1/lists/:id/accounts', async (_request, reply) => {
|
||||
try {
|
||||
if (!_request.params.id) return reply.code(400).send({ error: 'Missing required parameter "id"' });
|
||||
if (!_request.query.accounts_id) return reply.code(400).send({ error: 'Missing required property "accounts_id"' });
|
||||
const BASE_URL = `${_request.protocol}://${_request.host}`;
|
||||
const accessTokens = _request.headers.authorization;
|
||||
const client = getClient(BASE_URL, accessTokens);
|
||||
|
||||
const client = this.clientService.getClient(_request);
|
||||
const data = await client.deleteAccountsFromList(_request.params.id, _request.query.accounts_id);
|
||||
|
||||
reply.send(data.data);
|
||||
} catch (e) {
|
||||
const data = getErrorData(e);
|
||||
|
|
@ -178,51 +179,47 @@ export class ApiTimelineMastodon {
|
|||
reply.code(401).send(data);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public createList() {
|
||||
this.fastify.post<{ Body: { title?: string } }>('/v1/lists', async (_request, reply) => {
|
||||
fastify.post<{ Body: { title?: string } }>('/v1/lists', async (_request, reply) => {
|
||||
try {
|
||||
if (!_request.body.title) return reply.code(400).send({ error: 'Missing required payload "title"' });
|
||||
const BASE_URL = `${_request.protocol}://${_request.host}`;
|
||||
const accessTokens = _request.headers.authorization;
|
||||
const client = getClient(BASE_URL, accessTokens);
|
||||
|
||||
const client = this.clientService.getClient(_request);
|
||||
const data = await client.createList(_request.body.title);
|
||||
reply.send(convertList(data.data));
|
||||
const response = convertList(data.data);
|
||||
|
||||
reply.send(response);
|
||||
} catch (e) {
|
||||
const data = getErrorData(e);
|
||||
this.logger.error('POST /v1/lists', data);
|
||||
reply.code(401).send(data);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public updateList() {
|
||||
this.fastify.put<{ Params: { id?: string }, Body: { title?: string } }>('/v1/lists/:id', async (_request, reply) => {
|
||||
fastify.put<{ Params: { id?: string }, Body: { title?: string } }>('/v1/lists/:id', async (_request, reply) => {
|
||||
try {
|
||||
if (!_request.params.id) return reply.code(400).send({ error: 'Missing required parameter "id"' });
|
||||
if (!_request.body.title) return reply.code(400).send({ error: 'Missing required payload "title"' });
|
||||
const BASE_URL = `${_request.protocol}://${_request.host}`;
|
||||
const accessTokens = _request.headers.authorization;
|
||||
const client = getClient(BASE_URL, accessTokens);
|
||||
|
||||
const client = this.clientService.getClient(_request);
|
||||
const data = await client.updateList(_request.params.id, _request.body.title);
|
||||
reply.send(convertList(data.data));
|
||||
const response = convertList(data.data);
|
||||
|
||||
reply.send(response);
|
||||
} catch (e) {
|
||||
const data = getErrorData(e);
|
||||
this.logger.error(`PUT /v1/lists/${_request.params.id}`, data);
|
||||
reply.code(401).send(data);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public deleteList() {
|
||||
this.fastify.delete<{ Params: { id?: string } }>('/v1/lists/:id', async (_request, reply) => {
|
||||
fastify.delete<{ Params: { id?: string } }>('/v1/lists/:id', async (_request, reply) => {
|
||||
try {
|
||||
if (!_request.params.id) return reply.code(400).send({ error: 'Missing required parameter "id"' });
|
||||
const BASE_URL = `${_request.protocol}://${_request.host}`;
|
||||
const accessTokens = _request.headers.authorization;
|
||||
const client = getClient(BASE_URL, accessTokens);
|
||||
|
||||
const client = this.clientService.getClient(_request);
|
||||
await client.deleteList(_request.params.id);
|
||||
|
||||
reply.send({});
|
||||
} catch (e) {
|
||||
const data = getErrorData(e);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue