mirror of
https://codeberg.org/yeentown/barkey.git
synced 2025-04-29 10:06:57 +00:00
improve mastodon note conversion and use access checks in more places (resolves #509)
This commit is contained in:
parent
3550ce27d5
commit
1e43162ba7
8 changed files with 222 additions and 236 deletions
|
@ -19,12 +19,13 @@ import { ApiSearchMastodonRoute } from '@/server/api/mastodon/endpoints/search.j
|
||||||
import { ApiFilterMastodonRoute } from '@/server/api/mastodon/endpoints/filter.js';
|
import { ApiFilterMastodonRoute } from '@/server/api/mastodon/endpoints/filter.js';
|
||||||
import { ApiNotifyMastodonRoute } from '@/server/api/mastodon/endpoints/notifications.js';
|
import { ApiNotifyMastodonRoute } from '@/server/api/mastodon/endpoints/notifications.js';
|
||||||
import { AuthenticateService } from '@/server/api/AuthenticateService.js';
|
import { AuthenticateService } from '@/server/api/AuthenticateService.js';
|
||||||
|
import { MiLocalUser } from '@/models/User.js';
|
||||||
import { AuthMastodonRoute } from './endpoints/auth.js';
|
import { AuthMastodonRoute } from './endpoints/auth.js';
|
||||||
import { toBoolean } from './timelineArgs.js';
|
import { toBoolean } from './timelineArgs.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 { getInstance } from './endpoints/meta.js';
|
||||||
import { ApiAuthMastodon, ApiAccountMastodon, ApiFilterMastodon, ApiNotifyMastodon, ApiSearchMastodon, ApiTimelineMastodon, ApiStatusMastodon } from './endpoints.js';
|
import { ApiAuthMastodon, ApiAccountMastodon, ApiFilterMastodon, ApiNotifyMastodon, ApiSearchMastodon, ApiTimelineMastodon, ApiStatusMastodon } from './endpoints.js';
|
||||||
import type { FastifyInstance, FastifyPluginOptions } from 'fastify';
|
import type { FastifyInstance, FastifyPluginOptions, FastifyRequest } from 'fastify';
|
||||||
|
|
||||||
export function getAccessToken(authorization: string | undefined): string | null {
|
export function getAccessToken(authorization: string | undefined): string | null {
|
||||||
const accessTokenArr = authorization?.split(' ') ?? [null];
|
const accessTokenArr = authorization?.split(' ') ?? [null];
|
||||||
|
@ -50,11 +51,29 @@ export class MastodonApiServerService {
|
||||||
@Inject(DI.config)
|
@Inject(DI.config)
|
||||||
private readonly config: Config,
|
private readonly config: Config,
|
||||||
private readonly driveService: DriveService,
|
private readonly driveService: DriveService,
|
||||||
private readonly mastoConverter: MastoConverters,
|
private readonly mastoConverters: MastoConverters,
|
||||||
private readonly logger: MastodonLogger,
|
private readonly logger: MastodonLogger,
|
||||||
private readonly authenticateService: AuthenticateService,
|
private readonly authenticateService: AuthenticateService,
|
||||||
) { }
|
) { }
|
||||||
|
|
||||||
|
@bindThis
|
||||||
|
public async getAuthClient(request: FastifyRequest): Promise<{ client: MegalodonInterface, me: MiLocalUser | null }> {
|
||||||
|
const accessToken = getAccessToken(request.headers.authorization);
|
||||||
|
const [me] = await this.authenticateService.authenticate(accessToken);
|
||||||
|
|
||||||
|
const baseUrl = `${request.protocol}://${request.host}`;
|
||||||
|
const client = megalodon('misskey', baseUrl, accessToken);
|
||||||
|
|
||||||
|
return { client, me };
|
||||||
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
|
public async getAuthOnly(request: FastifyRequest): Promise<MiLocalUser | null> {
|
||||||
|
const accessToken = getAccessToken(request.headers.authorization);
|
||||||
|
const [me] = await this.authenticateService.authenticate(accessToken);
|
||||||
|
return me;
|
||||||
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
public createServer(fastify: FastifyInstance, _options: FastifyPluginOptions, done: (err?: Error) => void) {
|
public createServer(fastify: FastifyInstance, _options: FastifyPluginOptions, done: (err?: Error) => void) {
|
||||||
const upload = multer({
|
const upload = multer({
|
||||||
|
@ -118,7 +137,7 @@ export class MastodonApiServerService {
|
||||||
},
|
},
|
||||||
order: { id: 'ASC' },
|
order: { id: 'ASC' },
|
||||||
});
|
});
|
||||||
const contact = admin == null ? null : await this.mastoConverter.convertAccount((await client.getAccount(admin.id)).data);
|
const contact = admin == null ? null : await this.mastoConverters.convertAccount((await client.getAccount(admin.id)).data);
|
||||||
reply.send(await getInstance(data.data, contact as Entity.Account, this.config, this.serverSettings));
|
reply.send(await getInstance(data.data, contact as Entity.Account, this.config, this.serverSettings));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
const data = getErrorData(e);
|
const data = getErrorData(e);
|
||||||
|
@ -275,12 +294,9 @@ export class MastodonApiServerService {
|
||||||
|
|
||||||
//#region Accounts
|
//#region Accounts
|
||||||
fastify.get<ApiAccountMastodonRoute>('/v1/accounts/verify_credentials', async (_request, reply) => {
|
fastify.get<ApiAccountMastodonRoute>('/v1/accounts/verify_credentials', async (_request, reply) => {
|
||||||
const BASE_URL = `${_request.protocol}://${_request.host}`;
|
|
||||||
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 {
|
try {
|
||||||
const account = new ApiAccountMastodon(_request, client, this.mastoConverter);
|
const { client, me } = await this.getAuthClient(_request);
|
||||||
|
const account = new ApiAccountMastodon(_request, client, me, this.mastoConverters);
|
||||||
reply.send(await account.verifyCredentials());
|
reply.send(await account.verifyCredentials());
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
const data = getErrorData(e);
|
const data = getErrorData(e);
|
||||||
|
@ -378,7 +394,7 @@ export class MastodonApiServerService {
|
||||||
} : undefined,
|
} : undefined,
|
||||||
};
|
};
|
||||||
const data = await client.updateCredentials(options);
|
const data = await client.updateCredentials(options);
|
||||||
reply.send(await this.mastoConverter.convertAccount(data.data));
|
reply.send(await this.mastoConverters.convertAccount(data.data));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
const data = getErrorData(e);
|
const data = getErrorData(e);
|
||||||
this.logger.error('PATCH /v1/accounts/update_credentials', data);
|
this.logger.error('PATCH /v1/accounts/update_credentials', data);
|
||||||
|
@ -395,7 +411,7 @@ export class MastodonApiServerService {
|
||||||
const data = await client.search(_request.query.acct, { type: 'accounts' });
|
const data = await client.search(_request.query.acct, { type: 'accounts' });
|
||||||
const profile = await this.userProfilesRepository.findOneBy({ userId: data.data.accounts[0].id });
|
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 })) ?? [];
|
data.data.accounts[0].fields = profile?.fields.map(f => ({ ...f, verified_at: null })) ?? [];
|
||||||
reply.send(await this.mastoConverter.convertAccount(data.data.accounts[0]));
|
reply.send(await this.mastoConverters.convertAccount(data.data.accounts[0]));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
const data = getErrorData(e);
|
const data = getErrorData(e);
|
||||||
this.logger.error('GET /v1/accounts/lookup', data);
|
this.logger.error('GET /v1/accounts/lookup', data);
|
||||||
|
@ -404,15 +420,13 @@ export class MastodonApiServerService {
|
||||||
});
|
});
|
||||||
|
|
||||||
fastify.get<ApiAccountMastodonRoute & { Querystring: { id?: string | string[], 'id[]'?: string | string[] }}>('/v1/accounts/relationships', async (_request, reply) => {
|
fastify.get<ApiAccountMastodonRoute & { Querystring: { id?: string | string[], 'id[]'?: string | string[] }}>('/v1/accounts/relationships', async (_request, reply) => {
|
||||||
const BASE_URL = `${_request.protocol}://${_request.host}`;
|
|
||||||
const accessTokens = _request.headers.authorization;
|
|
||||||
const client = getClient(BASE_URL, accessTokens); // we are using this here, because in private mode some info isn't displayed without being logged in
|
|
||||||
try {
|
try {
|
||||||
|
const { client, me } = await this.getAuthClient(_request);
|
||||||
let ids = _request.query['id[]'] ?? _request.query['id'] ?? [];
|
let ids = _request.query['id[]'] ?? _request.query['id'] ?? [];
|
||||||
if (typeof ids === 'string') {
|
if (typeof ids === 'string') {
|
||||||
ids = [ids];
|
ids = [ids];
|
||||||
}
|
}
|
||||||
const account = new ApiAccountMastodon(_request, client, this.mastoConverter);
|
const account = new ApiAccountMastodon(_request, client, me, this.mastoConverters);
|
||||||
reply.send(await account.getRelationships(ids));
|
reply.send(await account.getRelationships(ids));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
const data = getErrorData(e);
|
const data = getErrorData(e);
|
||||||
|
@ -428,7 +442,7 @@ export class MastodonApiServerService {
|
||||||
try {
|
try {
|
||||||
if (!_request.params.id) return reply.code(400).send({ error: 'Missing required parameter "id"' });
|
if (!_request.params.id) return reply.code(400).send({ error: 'Missing required parameter "id"' });
|
||||||
const data = await client.getAccount(_request.params.id);
|
const data = await client.getAccount(_request.params.id);
|
||||||
const account = await this.mastoConverter.convertAccount(data.data);
|
const account = await this.mastoConverters.convertAccount(data.data);
|
||||||
reply.send(account);
|
reply.send(account);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
const data = getErrorData(e);
|
const data = getErrorData(e);
|
||||||
|
@ -438,12 +452,10 @@ export class MastodonApiServerService {
|
||||||
});
|
});
|
||||||
|
|
||||||
fastify.get<ApiAccountMastodonRoute & { Params: { id?: string } }>('/v1/accounts/:id/statuses', async (_request, reply) => {
|
fastify.get<ApiAccountMastodonRoute & { Params: { id?: string } }>('/v1/accounts/:id/statuses', async (_request, reply) => {
|
||||||
const BASE_URL = `${_request.protocol}://${_request.host}`;
|
|
||||||
const accessTokens = _request.headers.authorization;
|
|
||||||
const client = getClient(BASE_URL, accessTokens);
|
|
||||||
try {
|
try {
|
||||||
if (!_request.params.id) return reply.code(400).send({ error: 'Missing required parameter "id"' });
|
if (!_request.params.id) return reply.code(400).send({ error: 'Missing required parameter "id"' });
|
||||||
const account = new ApiAccountMastodon(_request, client, this.mastoConverter);
|
const { client, me } = await this.getAuthClient(_request);
|
||||||
|
const account = new ApiAccountMastodon(_request, client, me, this.mastoConverters);
|
||||||
reply.send(await account.getStatuses());
|
reply.send(await account.getStatuses());
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
const data = getErrorData(e);
|
const data = getErrorData(e);
|
||||||
|
@ -468,12 +480,10 @@ export class MastodonApiServerService {
|
||||||
});
|
});
|
||||||
|
|
||||||
fastify.get<ApiAccountMastodonRoute & { Params: { id?: string } }>('/v1/accounts/:id/followers', async (_request, reply) => {
|
fastify.get<ApiAccountMastodonRoute & { Params: { id?: string } }>('/v1/accounts/:id/followers', async (_request, reply) => {
|
||||||
const BASE_URL = `${_request.protocol}://${_request.host}`;
|
|
||||||
const accessTokens = _request.headers.authorization;
|
|
||||||
const client = getClient(BASE_URL, accessTokens);
|
|
||||||
try {
|
try {
|
||||||
if (!_request.params.id) return reply.code(400).send({ error: 'Missing required parameter "id"' });
|
if (!_request.params.id) return reply.code(400).send({ error: 'Missing required parameter "id"' });
|
||||||
const account = new ApiAccountMastodon(_request, client, this.mastoConverter);
|
const { client, me } = await this.getAuthClient(_request);
|
||||||
|
const account = new ApiAccountMastodon(_request, client, me, this.mastoConverters);
|
||||||
reply.send(await account.getFollowers());
|
reply.send(await account.getFollowers());
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
const data = getErrorData(e);
|
const data = getErrorData(e);
|
||||||
|
@ -483,12 +493,10 @@ export class MastodonApiServerService {
|
||||||
});
|
});
|
||||||
|
|
||||||
fastify.get<ApiAccountMastodonRoute & { Params: { id?: string } }>('/v1/accounts/:id/following', async (_request, reply) => {
|
fastify.get<ApiAccountMastodonRoute & { Params: { id?: string } }>('/v1/accounts/:id/following', async (_request, reply) => {
|
||||||
const BASE_URL = `${_request.protocol}://${_request.host}`;
|
|
||||||
const accessTokens = _request.headers.authorization;
|
|
||||||
const client = getClient(BASE_URL, accessTokens);
|
|
||||||
try {
|
try {
|
||||||
if (!_request.params.id) return reply.code(400).send({ error: 'Missing required parameter "id"' });
|
if (!_request.params.id) return reply.code(400).send({ error: 'Missing required parameter "id"' });
|
||||||
const account = new ApiAccountMastodon(_request, client, this.mastoConverter);
|
const { client, me } = await this.getAuthClient(_request);
|
||||||
|
const account = new ApiAccountMastodon(_request, client, me, this.mastoConverters);
|
||||||
reply.send(await account.getFollowing());
|
reply.send(await account.getFollowing());
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
const data = getErrorData(e);
|
const data = getErrorData(e);
|
||||||
|
@ -513,12 +521,10 @@ export class MastodonApiServerService {
|
||||||
});
|
});
|
||||||
|
|
||||||
fastify.post<ApiAccountMastodonRoute & { Params: { id?: string } }>('/v1/accounts/:id/follow', { preHandler: upload.single('none') }, async (_request, reply) => {
|
fastify.post<ApiAccountMastodonRoute & { Params: { id?: string } }>('/v1/accounts/:id/follow', { preHandler: upload.single('none') }, async (_request, reply) => {
|
||||||
const BASE_URL = `${_request.protocol}://${_request.host}`;
|
|
||||||
const accessTokens = _request.headers.authorization;
|
|
||||||
const client = getClient(BASE_URL, accessTokens);
|
|
||||||
try {
|
try {
|
||||||
if (!_request.params.id) return reply.code(400).send({ error: 'Missing required parameter "id"' });
|
if (!_request.params.id) return reply.code(400).send({ error: 'Missing required parameter "id"' });
|
||||||
const account = new ApiAccountMastodon(_request, client, this.mastoConverter);
|
const { client, me } = await this.getAuthClient(_request);
|
||||||
|
const account = new ApiAccountMastodon(_request, client, me, this.mastoConverters);
|
||||||
reply.send(await account.addFollow());
|
reply.send(await account.addFollow());
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
const data = getErrorData(e);
|
const data = getErrorData(e);
|
||||||
|
@ -528,12 +534,10 @@ export class MastodonApiServerService {
|
||||||
});
|
});
|
||||||
|
|
||||||
fastify.post<ApiAccountMastodonRoute & { Params: { id?: string } }>('/v1/accounts/:id/unfollow', { preHandler: upload.single('none') }, async (_request, reply) => {
|
fastify.post<ApiAccountMastodonRoute & { Params: { id?: string } }>('/v1/accounts/:id/unfollow', { preHandler: upload.single('none') }, async (_request, reply) => {
|
||||||
const BASE_URL = `${_request.protocol}://${_request.host}`;
|
|
||||||
const accessTokens = _request.headers.authorization;
|
|
||||||
const client = getClient(BASE_URL, accessTokens);
|
|
||||||
try {
|
try {
|
||||||
if (!_request.params.id) return reply.code(400).send({ error: 'Missing required parameter "id"' });
|
if (!_request.params.id) return reply.code(400).send({ error: 'Missing required parameter "id"' });
|
||||||
const account = new ApiAccountMastodon(_request, client, this.mastoConverter);
|
const { client, me } = await this.getAuthClient(_request);
|
||||||
|
const account = new ApiAccountMastodon(_request, client, me, this.mastoConverters);
|
||||||
reply.send(await account.rmFollow());
|
reply.send(await account.rmFollow());
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
const data = getErrorData(e);
|
const data = getErrorData(e);
|
||||||
|
@ -543,12 +547,10 @@ export class MastodonApiServerService {
|
||||||
});
|
});
|
||||||
|
|
||||||
fastify.post<ApiAccountMastodonRoute & { Params: { id?: string } }>('/v1/accounts/:id/block', { preHandler: upload.single('none') }, async (_request, reply) => {
|
fastify.post<ApiAccountMastodonRoute & { Params: { id?: string } }>('/v1/accounts/:id/block', { preHandler: upload.single('none') }, async (_request, reply) => {
|
||||||
const BASE_URL = `${_request.protocol}://${_request.host}`;
|
|
||||||
const accessTokens = _request.headers.authorization;
|
|
||||||
const client = getClient(BASE_URL, accessTokens);
|
|
||||||
try {
|
try {
|
||||||
if (!_request.params.id) return reply.code(400).send({ error: 'Missing required parameter "id"' });
|
if (!_request.params.id) return reply.code(400).send({ error: 'Missing required parameter "id"' });
|
||||||
const account = new ApiAccountMastodon(_request, client, this.mastoConverter);
|
const { client, me } = await this.getAuthClient(_request);
|
||||||
|
const account = new ApiAccountMastodon(_request, client, me, this.mastoConverters);
|
||||||
reply.send(await account.addBlock());
|
reply.send(await account.addBlock());
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
const data = getErrorData(e);
|
const data = getErrorData(e);
|
||||||
|
@ -558,12 +560,10 @@ export class MastodonApiServerService {
|
||||||
});
|
});
|
||||||
|
|
||||||
fastify.post<ApiAccountMastodonRoute & { Params: { id?: string } }>('/v1/accounts/:id/unblock', { preHandler: upload.single('none') }, async (_request, reply) => {
|
fastify.post<ApiAccountMastodonRoute & { Params: { id?: string } }>('/v1/accounts/:id/unblock', { preHandler: upload.single('none') }, async (_request, reply) => {
|
||||||
const BASE_URL = `${_request.protocol}://${_request.host}`;
|
|
||||||
const accessTokens = _request.headers.authorization;
|
|
||||||
const client = getClient(BASE_URL, accessTokens);
|
|
||||||
try {
|
try {
|
||||||
if (!_request.params.id) return reply.code(400).send({ error: 'Missing required parameter "id"' });
|
if (!_request.params.id) return reply.code(400).send({ error: 'Missing required parameter "id"' });
|
||||||
const account = new ApiAccountMastodon(_request, client, this.mastoConverter);
|
const { client, me } = await this.getAuthClient(_request);
|
||||||
|
const account = new ApiAccountMastodon(_request, client, me, this.mastoConverters);
|
||||||
reply.send(await account.rmBlock());
|
reply.send(await account.rmBlock());
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
const data = getErrorData(e);
|
const data = getErrorData(e);
|
||||||
|
@ -573,12 +573,10 @@ export class MastodonApiServerService {
|
||||||
});
|
});
|
||||||
|
|
||||||
fastify.post<ApiAccountMastodonRoute & { Params: { id?: string } }>('/v1/accounts/:id/mute', { preHandler: upload.single('none') }, async (_request, reply) => {
|
fastify.post<ApiAccountMastodonRoute & { Params: { id?: string } }>('/v1/accounts/:id/mute', { preHandler: upload.single('none') }, async (_request, reply) => {
|
||||||
const BASE_URL = `${_request.protocol}://${_request.host}`;
|
|
||||||
const accessTokens = _request.headers.authorization;
|
|
||||||
const client = getClient(BASE_URL, accessTokens);
|
|
||||||
try {
|
try {
|
||||||
if (!_request.params.id) return reply.code(400).send({ error: 'Missing required parameter "id"' });
|
if (!_request.params.id) return reply.code(400).send({ error: 'Missing required parameter "id"' });
|
||||||
const account = new ApiAccountMastodon(_request, client, this.mastoConverter);
|
const { client, me } = await this.getAuthClient(_request);
|
||||||
|
const account = new ApiAccountMastodon(_request, client, me, this.mastoConverters);
|
||||||
reply.send(await account.addMute());
|
reply.send(await account.addMute());
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
const data = getErrorData(e);
|
const data = getErrorData(e);
|
||||||
|
@ -588,12 +586,10 @@ export class MastodonApiServerService {
|
||||||
});
|
});
|
||||||
|
|
||||||
fastify.post<ApiAccountMastodonRoute & { Params: { id?: string } }>('/v1/accounts/:id/unmute', { preHandler: upload.single('none') }, async (_request, reply) => {
|
fastify.post<ApiAccountMastodonRoute & { Params: { id?: string } }>('/v1/accounts/:id/unmute', { preHandler: upload.single('none') }, async (_request, reply) => {
|
||||||
const BASE_URL = `${_request.protocol}://${_request.host}`;
|
|
||||||
const accessTokens = _request.headers.authorization;
|
|
||||||
const client = getClient(BASE_URL, accessTokens);
|
|
||||||
try {
|
try {
|
||||||
if (!_request.params.id) return reply.code(400).send({ error: 'Missing required parameter "id"' });
|
if (!_request.params.id) return reply.code(400).send({ error: 'Missing required parameter "id"' });
|
||||||
const account = new ApiAccountMastodon(_request, client, this.mastoConverter);
|
const { client, me } = await this.getAuthClient(_request);
|
||||||
|
const account = new ApiAccountMastodon(_request, client, me, this.mastoConverters);
|
||||||
reply.send(await account.rmMute());
|
reply.send(await account.rmMute());
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
const data = getErrorData(e);
|
const data = getErrorData(e);
|
||||||
|
@ -617,11 +613,9 @@ export class MastodonApiServerService {
|
||||||
});
|
});
|
||||||
|
|
||||||
fastify.get<ApiAccountMastodonRoute>('/v1/bookmarks', async (_request, reply) => {
|
fastify.get<ApiAccountMastodonRoute>('/v1/bookmarks', async (_request, reply) => {
|
||||||
const BASE_URL = `${_request.protocol}://${_request.host}`;
|
|
||||||
const accessTokens = _request.headers.authorization;
|
|
||||||
const client = getClient(BASE_URL, accessTokens);
|
|
||||||
try {
|
try {
|
||||||
const account = new ApiAccountMastodon(_request, client, this.mastoConverter);
|
const { client, me } = await this.getAuthClient(_request);
|
||||||
|
const account = new ApiAccountMastodon(_request, client, me, this.mastoConverters);
|
||||||
reply.send(await account.getBookmarks());
|
reply.send(await account.getBookmarks());
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
const data = getErrorData(e);
|
const data = getErrorData(e);
|
||||||
|
@ -631,11 +625,9 @@ export class MastodonApiServerService {
|
||||||
});
|
});
|
||||||
|
|
||||||
fastify.get<ApiAccountMastodonRoute>('/v1/favourites', async (_request, reply) => {
|
fastify.get<ApiAccountMastodonRoute>('/v1/favourites', async (_request, reply) => {
|
||||||
const BASE_URL = `${_request.protocol}://${_request.host}`;
|
|
||||||
const accessTokens = _request.headers.authorization;
|
|
||||||
const client = getClient(BASE_URL, accessTokens);
|
|
||||||
try {
|
try {
|
||||||
const account = new ApiAccountMastodon(_request, client, this.mastoConverter);
|
const { client, me } = await this.getAuthClient(_request);
|
||||||
|
const account = new ApiAccountMastodon(_request, client, me, this.mastoConverters);
|
||||||
reply.send(await account.getFavourites());
|
reply.send(await account.getFavourites());
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
const data = getErrorData(e);
|
const data = getErrorData(e);
|
||||||
|
@ -645,11 +637,9 @@ export class MastodonApiServerService {
|
||||||
});
|
});
|
||||||
|
|
||||||
fastify.get<ApiAccountMastodonRoute>('/v1/mutes', async (_request, reply) => {
|
fastify.get<ApiAccountMastodonRoute>('/v1/mutes', async (_request, reply) => {
|
||||||
const BASE_URL = `${_request.protocol}://${_request.host}`;
|
|
||||||
const accessTokens = _request.headers.authorization;
|
|
||||||
const client = getClient(BASE_URL, accessTokens);
|
|
||||||
try {
|
try {
|
||||||
const account = new ApiAccountMastodon(_request, client, this.mastoConverter);
|
const { client, me } = await this.getAuthClient(_request);
|
||||||
|
const account = new ApiAccountMastodon(_request, client, me, this.mastoConverters);
|
||||||
reply.send(await account.getMutes());
|
reply.send(await account.getMutes());
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
const data = getErrorData(e);
|
const data = getErrorData(e);
|
||||||
|
@ -659,11 +649,9 @@ export class MastodonApiServerService {
|
||||||
});
|
});
|
||||||
|
|
||||||
fastify.get<ApiAccountMastodonRoute>('/v1/blocks', async (_request, reply) => {
|
fastify.get<ApiAccountMastodonRoute>('/v1/blocks', async (_request, reply) => {
|
||||||
const BASE_URL = `${_request.protocol}://${_request.host}`;
|
|
||||||
const accessTokens = _request.headers.authorization;
|
|
||||||
const client = getClient(BASE_URL, accessTokens);
|
|
||||||
try {
|
try {
|
||||||
const account = new ApiAccountMastodon(_request, client, this.mastoConverter);
|
const { client, me } = await this.getAuthClient(_request);
|
||||||
|
const account = new ApiAccountMastodon(_request, client, me, this.mastoConverters);
|
||||||
reply.send(await account.getBlocks());
|
reply.send(await account.getBlocks());
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
const data = getErrorData(e);
|
const data = getErrorData(e);
|
||||||
|
@ -679,7 +667,7 @@ export class MastodonApiServerService {
|
||||||
try {
|
try {
|
||||||
const limit = _request.query.limit ? parseInt(_request.query.limit) : 20;
|
const limit = _request.query.limit ? parseInt(_request.query.limit) : 20;
|
||||||
const data = await client.getFollowRequests(limit);
|
const data = await client.getFollowRequests(limit);
|
||||||
reply.send(await Promise.all(data.data.map(async (account) => await this.mastoConverter.convertAccount(account as Entity.Account))));
|
reply.send(await Promise.all(data.data.map(async (account) => await this.mastoConverters.convertAccount(account as Entity.Account))));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
const data = getErrorData(e);
|
const data = getErrorData(e);
|
||||||
this.logger.error('GET /v1/follow_requests', data);
|
this.logger.error('GET /v1/follow_requests', data);
|
||||||
|
@ -688,12 +676,10 @@ export class MastodonApiServerService {
|
||||||
});
|
});
|
||||||
|
|
||||||
fastify.post<ApiAccountMastodonRoute & { Params: { id?: string } }>('/v1/follow_requests/:id/authorize', { preHandler: upload.single('none') }, async (_request, reply) => {
|
fastify.post<ApiAccountMastodonRoute & { Params: { id?: string } }>('/v1/follow_requests/:id/authorize', { preHandler: upload.single('none') }, async (_request, reply) => {
|
||||||
const BASE_URL = `${_request.protocol}://${_request.host}`;
|
|
||||||
const accessTokens = _request.headers.authorization;
|
|
||||||
const client = getClient(BASE_URL, accessTokens);
|
|
||||||
try {
|
try {
|
||||||
if (!_request.params.id) return reply.code(400).send({ error: 'Missing required parameter "id"' });
|
if (!_request.params.id) return reply.code(400).send({ error: 'Missing required parameter "id"' });
|
||||||
const account = new ApiAccountMastodon(_request, client, this.mastoConverter);
|
const { client, me } = await this.getAuthClient(_request);
|
||||||
|
const account = new ApiAccountMastodon(_request, client, me, this.mastoConverters);
|
||||||
reply.send(await account.acceptFollow());
|
reply.send(await account.acceptFollow());
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
const data = getErrorData(e);
|
const data = getErrorData(e);
|
||||||
|
@ -703,12 +689,10 @@ export class MastodonApiServerService {
|
||||||
});
|
});
|
||||||
|
|
||||||
fastify.post<ApiAccountMastodonRoute & { Params: { id?: string } }>('/v1/follow_requests/:id/reject', { preHandler: upload.single('none') }, async (_request, reply) => {
|
fastify.post<ApiAccountMastodonRoute & { Params: { id?: string } }>('/v1/follow_requests/:id/reject', { preHandler: upload.single('none') }, async (_request, reply) => {
|
||||||
const BASE_URL = `${_request.protocol}://${_request.host}`;
|
|
||||||
const accessTokens = _request.headers.authorization;
|
|
||||||
const client = getClient(BASE_URL, accessTokens);
|
|
||||||
try {
|
try {
|
||||||
if (!_request.params.id) return reply.code(400).send({ error: 'Missing required parameter "id"' });
|
if (!_request.params.id) return reply.code(400).send({ error: 'Missing required parameter "id"' });
|
||||||
const account = new ApiAccountMastodon(_request, client, this.mastoConverter);
|
const { client, me } = await this.getAuthClient(_request);
|
||||||
|
const account = new ApiAccountMastodon(_request, client, me, this.mastoConverters);
|
||||||
reply.send(await account.rejectFollow());
|
reply.send(await account.rejectFollow());
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
const data = getErrorData(e);
|
const data = getErrorData(e);
|
||||||
|
@ -721,10 +705,9 @@ export class MastodonApiServerService {
|
||||||
//#region Search
|
//#region Search
|
||||||
fastify.get<ApiSearchMastodonRoute>('/v1/search', async (_request, reply) => {
|
fastify.get<ApiSearchMastodonRoute>('/v1/search', async (_request, reply) => {
|
||||||
const BASE_URL = `${_request.protocol}://${_request.host}`;
|
const BASE_URL = `${_request.protocol}://${_request.host}`;
|
||||||
const accessTokens = _request.headers.authorization;
|
|
||||||
const client = getClient(BASE_URL, accessTokens);
|
|
||||||
try {
|
try {
|
||||||
const search = new ApiSearchMastodon(_request, client, BASE_URL, this.mastoConverter);
|
const { client, me } = await this.getAuthClient(_request);
|
||||||
|
const search = new ApiSearchMastodon(_request, client, me, BASE_URL, this.mastoConverters);
|
||||||
reply.send(await search.SearchV1());
|
reply.send(await search.SearchV1());
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
const data = getErrorData(e);
|
const data = getErrorData(e);
|
||||||
|
@ -735,10 +718,9 @@ export class MastodonApiServerService {
|
||||||
|
|
||||||
fastify.get<ApiSearchMastodonRoute>('/v2/search', async (_request, reply) => {
|
fastify.get<ApiSearchMastodonRoute>('/v2/search', async (_request, reply) => {
|
||||||
const BASE_URL = `${_request.protocol}://${_request.host}`;
|
const BASE_URL = `${_request.protocol}://${_request.host}`;
|
||||||
const accessTokens = _request.headers.authorization;
|
|
||||||
const client = getClient(BASE_URL, accessTokens);
|
|
||||||
try {
|
try {
|
||||||
const search = new ApiSearchMastodon(_request, client, BASE_URL, this.mastoConverter);
|
const { client, me } = await this.getAuthClient(_request);
|
||||||
|
const search = new ApiSearchMastodon(_request, client, me, BASE_URL, this.mastoConverters);
|
||||||
reply.send(await search.SearchV2());
|
reply.send(await search.SearchV2());
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
const data = getErrorData(e);
|
const data = getErrorData(e);
|
||||||
|
@ -749,10 +731,9 @@ export class MastodonApiServerService {
|
||||||
|
|
||||||
fastify.get<ApiSearchMastodonRoute>('/v1/trends/statuses', async (_request, reply) => {
|
fastify.get<ApiSearchMastodonRoute>('/v1/trends/statuses', async (_request, reply) => {
|
||||||
const BASE_URL = `${_request.protocol}://${_request.host}`;
|
const BASE_URL = `${_request.protocol}://${_request.host}`;
|
||||||
const accessTokens = _request.headers.authorization;
|
|
||||||
const client = getClient(BASE_URL, accessTokens);
|
|
||||||
try {
|
try {
|
||||||
const search = new ApiSearchMastodon(_request, client, BASE_URL, this.mastoConverter);
|
const { client, me } = await this.getAuthClient(_request);
|
||||||
|
const search = new ApiSearchMastodon(_request, client, me, BASE_URL, this.mastoConverters);
|
||||||
reply.send(await search.getStatusTrends());
|
reply.send(await search.getStatusTrends());
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
const data = getErrorData(e);
|
const data = getErrorData(e);
|
||||||
|
@ -763,10 +744,9 @@ export class MastodonApiServerService {
|
||||||
|
|
||||||
fastify.get<ApiSearchMastodonRoute>('/v2/suggestions', async (_request, reply) => {
|
fastify.get<ApiSearchMastodonRoute>('/v2/suggestions', async (_request, reply) => {
|
||||||
const BASE_URL = `${_request.protocol}://${_request.host}`;
|
const BASE_URL = `${_request.protocol}://${_request.host}`;
|
||||||
const accessTokens = _request.headers.authorization;
|
|
||||||
const client = getClient(BASE_URL, accessTokens);
|
|
||||||
try {
|
try {
|
||||||
const search = new ApiSearchMastodon(_request, client, BASE_URL, this.mastoConverter);
|
const { client, me } = await this.getAuthClient(_request);
|
||||||
|
const search = new ApiSearchMastodon(_request, client, me, BASE_URL, this.mastoConverters);
|
||||||
reply.send(await search.getSuggestions());
|
reply.send(await search.getSuggestions());
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
const data = getErrorData(e);
|
const data = getErrorData(e);
|
||||||
|
@ -778,11 +758,9 @@ export class MastodonApiServerService {
|
||||||
|
|
||||||
//#region Notifications
|
//#region Notifications
|
||||||
fastify.get<ApiNotifyMastodonRoute>('/v1/notifications', async (_request, reply) => {
|
fastify.get<ApiNotifyMastodonRoute>('/v1/notifications', async (_request, reply) => {
|
||||||
const BASE_URL = `${_request.protocol}://${_request.host}`;
|
|
||||||
const accessTokens = _request.headers.authorization;
|
|
||||||
const client = getClient(BASE_URL, accessTokens);
|
|
||||||
try {
|
try {
|
||||||
const notify = new ApiNotifyMastodon(_request, client);
|
const { client, me } = await this.getAuthClient(_request);
|
||||||
|
const notify = new ApiNotifyMastodon(_request, client, me, this.mastoConverters);
|
||||||
reply.send(await notify.getNotifications());
|
reply.send(await notify.getNotifications());
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
const data = getErrorData(e);
|
const data = getErrorData(e);
|
||||||
|
@ -792,12 +770,10 @@ export class MastodonApiServerService {
|
||||||
});
|
});
|
||||||
|
|
||||||
fastify.get<ApiNotifyMastodonRoute & { Params: { id?: string } }>('/v1/notification/:id', async (_request, reply) => {
|
fastify.get<ApiNotifyMastodonRoute & { Params: { id?: string } }>('/v1/notification/:id', async (_request, reply) => {
|
||||||
const BASE_URL = `${_request.protocol}://${_request.host}`;
|
|
||||||
const accessTokens = _request.headers.authorization;
|
|
||||||
const client = getClient(BASE_URL, accessTokens);
|
|
||||||
try {
|
try {
|
||||||
if (!_request.params.id) return reply.code(400).send({ error: 'Missing required parameter "id"' });
|
if (!_request.params.id) return reply.code(400).send({ error: 'Missing required parameter "id"' });
|
||||||
const notify = new ApiNotifyMastodon(_request, client);
|
const { client, me } = await this.getAuthClient(_request);
|
||||||
|
const notify = new ApiNotifyMastodon(_request, client, me, this.mastoConverters);
|
||||||
reply.send(await notify.getNotification());
|
reply.send(await notify.getNotification());
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
const data = getErrorData(e);
|
const data = getErrorData(e);
|
||||||
|
@ -807,12 +783,10 @@ export class MastodonApiServerService {
|
||||||
});
|
});
|
||||||
|
|
||||||
fastify.post<ApiNotifyMastodonRoute & { Params: { id?: string } }>('/v1/notification/:id/dismiss', { preHandler: upload.single('none') }, async (_request, reply) => {
|
fastify.post<ApiNotifyMastodonRoute & { Params: { id?: string } }>('/v1/notification/:id/dismiss', { preHandler: upload.single('none') }, async (_request, reply) => {
|
||||||
const BASE_URL = `${_request.protocol}://${_request.host}`;
|
|
||||||
const accessTokens = _request.headers.authorization;
|
|
||||||
const client = getClient(BASE_URL, accessTokens);
|
|
||||||
try {
|
try {
|
||||||
if (!_request.params.id) return reply.code(400).send({ error: 'Missing required parameter "id"' });
|
if (!_request.params.id) return reply.code(400).send({ error: 'Missing required parameter "id"' });
|
||||||
const notify = new ApiNotifyMastodon(_request, client);
|
const { client, me } = await this.getAuthClient(_request);
|
||||||
|
const notify = new ApiNotifyMastodon(_request, client, me, this.mastoConverters);
|
||||||
reply.send(await notify.rmNotification());
|
reply.send(await notify.rmNotification());
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
const data = getErrorData(e);
|
const data = getErrorData(e);
|
||||||
|
@ -822,11 +796,9 @@ export class MastodonApiServerService {
|
||||||
});
|
});
|
||||||
|
|
||||||
fastify.post<ApiNotifyMastodonRoute>('/v1/notifications/clear', { preHandler: upload.single('none') }, async (_request, reply) => {
|
fastify.post<ApiNotifyMastodonRoute>('/v1/notifications/clear', { preHandler: upload.single('none') }, async (_request, reply) => {
|
||||||
const BASE_URL = `${_request.protocol}://${_request.host}`;
|
|
||||||
const accessTokens = _request.headers.authorization;
|
|
||||||
const client = getClient(BASE_URL, accessTokens);
|
|
||||||
try {
|
try {
|
||||||
const notify = new ApiNotifyMastodon(_request, client);
|
const { client, me } = await this.getAuthClient(_request);
|
||||||
|
const notify = new ApiNotifyMastodon(_request, client, me, this.mastoConverters);
|
||||||
reply.send(await notify.rmNotifications());
|
reply.send(await notify.rmNotifications());
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
const data = getErrorData(e);
|
const data = getErrorData(e);
|
||||||
|
@ -899,7 +871,7 @@ export class MastodonApiServerService {
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
//#region Timelines
|
//#region Timelines
|
||||||
const TLEndpoint = new ApiTimelineMastodon(fastify, this.mastoConverter, this.logger);
|
const TLEndpoint = new ApiTimelineMastodon(fastify, this.mastoConverters, this.logger, this);
|
||||||
|
|
||||||
// GET Endpoints
|
// GET Endpoints
|
||||||
TLEndpoint.getTL();
|
TLEndpoint.getTL();
|
||||||
|
@ -924,7 +896,7 @@ export class MastodonApiServerService {
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
//#region Status
|
//#region Status
|
||||||
const NoteEndpoint = new ApiStatusMastodon(fastify, this.mastoConverter, this.logger, this.authenticateService);
|
const NoteEndpoint = new ApiStatusMastodon(fastify, this.mastoConverters, this.logger, this.authenticateService, this);
|
||||||
|
|
||||||
// GET Endpoints
|
// GET Endpoints
|
||||||
NoteEndpoint.getStatus();
|
NoteEndpoint.getStatus();
|
||||||
|
|
|
@ -4,10 +4,12 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Inject, Injectable } from '@nestjs/common';
|
import { Inject, Injectable } from '@nestjs/common';
|
||||||
|
import { IsNull } from 'typeorm';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import { QueryService } from '@/core/QueryService.js';
|
import { QueryService } from '@/core/QueryService.js';
|
||||||
import type { MiNote, NotesRepository } from '@/models/_.js';
|
import type { MiNote, NotesRepository } from '@/models/_.js';
|
||||||
import type { MiLocalUser } from '@/models/User.js';
|
import type { MiLocalUser } from '@/models/User.js';
|
||||||
|
import { ApiError } from '../error.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Utility service for accessing data with Mastodon semantics
|
* Utility service for accessing data with Mastodon semantics
|
||||||
|
@ -22,6 +24,28 @@ export class MastodonDataService {
|
||||||
private readonly queryService: QueryService,
|
private readonly queryService: QueryService,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetches a note in the context of the current user, and throws an exception if not found.
|
||||||
|
*/
|
||||||
|
public async requireNote(noteId: string, me?: MiLocalUser | null): Promise<MiNote> {
|
||||||
|
const note = await this.getNote(noteId, me);
|
||||||
|
|
||||||
|
if (!note) {
|
||||||
|
throw new ApiError({
|
||||||
|
message: 'No such note.',
|
||||||
|
code: 'NO_SUCH_NOTE',
|
||||||
|
id: '24fcbfc6-2e37-42b6-8388-c29b3861a08d',
|
||||||
|
kind: 'client',
|
||||||
|
httpStatusCode: 404,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return note;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetches a note in the context of the current user.
|
||||||
|
*/
|
||||||
public async getNote(noteId: string, me?: MiLocalUser | null): Promise<MiNote | null> {
|
public async getNote(noteId: string, me?: MiLocalUser | null): Promise<MiNote | null> {
|
||||||
// Root query: note + required dependencies
|
// Root query: note + required dependencies
|
||||||
const query = this.notesRepository
|
const query = this.notesRepository
|
||||||
|
@ -37,4 +61,24 @@ export class MastodonDataService {
|
||||||
|
|
||||||
return await query.getOne();
|
return await query.getOne();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks where the current user has made a reblog / boost / pure renote of a given target note.
|
||||||
|
*/
|
||||||
|
public async hasReblog(noteId: string, me: MiLocalUser | null | undefined): Promise<boolean> {
|
||||||
|
if (!me) return false;
|
||||||
|
|
||||||
|
return await this.notesRepository.existsBy({
|
||||||
|
// Reblog of the target note by me
|
||||||
|
userId: me.id,
|
||||||
|
renoteId: noteId,
|
||||||
|
|
||||||
|
// That is pure (not a quote)
|
||||||
|
text: IsNull(),
|
||||||
|
cw: IsNull(),
|
||||||
|
replyId: IsNull(),
|
||||||
|
hasPoll: false,
|
||||||
|
fileIds: '{}',
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -215,15 +215,16 @@ export class MastoConverters {
|
||||||
return await Promise.all(history);
|
return await Promise.all(history);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async convertReblog(status: Entity.Status | null): Promise<MastodonEntity.Status | null> {
|
private async convertReblog(status: Entity.Status | null, me?: MiLocalUser | null): Promise<MastodonEntity.Status | null> {
|
||||||
if (!status) return null;
|
if (!status) return null;
|
||||||
return await this.convertStatus(status);
|
return await this.convertStatus(status, me);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async convertStatus(status: Entity.Status): Promise<MastodonEntity.Status> {
|
public async convertStatus(status: Entity.Status, me?: MiLocalUser | null): Promise<MastodonEntity.Status> {
|
||||||
const convertedAccount = this.convertAccount(status.account);
|
const convertedAccount = this.convertAccount(status.account);
|
||||||
const note = await this.getterService.getNote(status.id);
|
const note = await this.mastodonDataService.requireNote(status.id, me);
|
||||||
const noteUser = await this.getUser(status.account.id);
|
const noteUser = await this.getUser(status.account.id);
|
||||||
|
const mentionedRemoteUsers = JSON.parse(note.mentionedRemoteUsers);
|
||||||
|
|
||||||
const emojis = await this.customEmojiService.populateEmojis(note.emojis, 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[] = [];
|
const emoji: Entity.Emoji[] = [];
|
||||||
|
@ -240,7 +241,7 @@ export class MastoConverters {
|
||||||
|
|
||||||
const mentions = Promise.all(note.mentions.map(p =>
|
const mentions = Promise.all(note.mentions.map(p =>
|
||||||
this.getUser(p)
|
this.getUser(p)
|
||||||
.then(u => this.encode(u, JSON.parse(note.mentionedRemoteUsers)))
|
.then(u => this.encode(u, mentionedRemoteUsers))
|
||||||
.catch(() => null)))
|
.catch(() => null)))
|
||||||
.then(p => p.filter(m => m)) as Promise<Entity.Mention[]>;
|
.then(p => p.filter(m => m)) as Promise<Entity.Mention[]>;
|
||||||
|
|
||||||
|
@ -255,7 +256,7 @@ export class MastoConverters {
|
||||||
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
|
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
|
||||||
const isQuote = note.renoteId && (note.text || note.cw || note.fileIds.length > 0 || note.hasPoll || note.replyId);
|
const isQuote = note.renoteId && (note.text || note.cw || note.fileIds.length > 0 || note.hasPoll || note.replyId);
|
||||||
|
|
||||||
const renote: Promise<MiNote> | null = note.renoteId ? this.getterService.getNote(note.renoteId) : null;
|
const renote: Promise<MiNote> | null = note.renoteId ? this.mastodonDataService.requireNote(note.renoteId, me) : null;
|
||||||
|
|
||||||
const quoteUri = Promise.resolve(renote).then(renote => {
|
const quoteUri = Promise.resolve(renote).then(renote => {
|
||||||
if (!renote || !isQuote) return null;
|
if (!renote || !isQuote) return null;
|
||||||
|
@ -265,10 +266,12 @@ export class MastoConverters {
|
||||||
const text = note.text;
|
const text = note.text;
|
||||||
const content = text !== null
|
const content = text !== null
|
||||||
? quoteUri
|
? quoteUri
|
||||||
.then(quoteUri => this.mfmService.toMastoApiHtml(mfm.parse(text), JSON.parse(note.mentionedRemoteUsers), false, quoteUri))
|
.then(quoteUri => this.mfmService.toMastoApiHtml(mfm.parse(text), mentionedRemoteUsers, false, quoteUri))
|
||||||
.then(p => p ?? escapeMFM(text))
|
.then(p => p ?? escapeMFM(text))
|
||||||
: '';
|
: '';
|
||||||
|
|
||||||
|
const reblogged = await this.mastodonDataService.hasReblog(note.id, me);
|
||||||
|
|
||||||
// noinspection ES6MissingAwait
|
// noinspection ES6MissingAwait
|
||||||
return await awaitAll({
|
return await awaitAll({
|
||||||
id: note.id,
|
id: note.id,
|
||||||
|
@ -277,7 +280,7 @@ export class MastoConverters {
|
||||||
account: convertedAccount,
|
account: convertedAccount,
|
||||||
in_reply_to_id: note.replyId,
|
in_reply_to_id: note.replyId,
|
||||||
in_reply_to_account_id: note.replyUserId,
|
in_reply_to_account_id: note.replyUserId,
|
||||||
reblog: !isQuote ? await this.convertReblog(status.reblog) : null,
|
reblog: !isQuote ? await this.convertReblog(status.reblog, me) : null,
|
||||||
content: content,
|
content: content,
|
||||||
content_type: 'text/x.misskeymarkdown',
|
content_type: 'text/x.misskeymarkdown',
|
||||||
text: note.text,
|
text: note.text,
|
||||||
|
@ -286,7 +289,7 @@ export class MastoConverters {
|
||||||
replies_count: note.repliesCount,
|
replies_count: note.repliesCount,
|
||||||
reblogs_count: note.renoteCount,
|
reblogs_count: note.renoteCount,
|
||||||
favourites_count: status.favourites_count,
|
favourites_count: status.favourites_count,
|
||||||
reblogged: false,
|
reblogged,
|
||||||
favourited: status.favourited,
|
favourited: status.favourited,
|
||||||
muted: status.muted,
|
muted: status.muted,
|
||||||
sensitive: status.sensitive,
|
sensitive: status.sensitive,
|
||||||
|
@ -303,10 +306,29 @@ export class MastoConverters {
|
||||||
reactions: status.emoji_reactions,
|
reactions: status.emoji_reactions,
|
||||||
emoji_reactions: status.emoji_reactions,
|
emoji_reactions: status.emoji_reactions,
|
||||||
bookmarked: false, //FIXME
|
bookmarked: false, //FIXME
|
||||||
quote: isQuote ? await this.convertReblog(status.reblog) : null,
|
quote: isQuote ? await this.convertReblog(status.reblog, me) : null,
|
||||||
edited_at: note.updatedAt?.toISOString() ?? null,
|
edited_at: note.updatedAt?.toISOString() ?? null,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async convertConversation(conversation: Entity.Conversation, me?: MiLocalUser | null): Promise<MastodonEntity.Conversation> {
|
||||||
|
return {
|
||||||
|
id: conversation.id,
|
||||||
|
accounts: await Promise.all(conversation.accounts.map(a => this.convertAccount(a))),
|
||||||
|
last_status: conversation.last_status ? await this.convertStatus(conversation.last_status, me) : null,
|
||||||
|
unread: conversation.unread,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public async convertNotification(notification: Entity.Notification, me?: MiLocalUser | null): Promise<MastodonEntity.Notification> {
|
||||||
|
return {
|
||||||
|
account: await this.convertAccount(notification.account),
|
||||||
|
created_at: notification.created_at,
|
||||||
|
id: notification.id,
|
||||||
|
status: notification.status ? await this.convertStatus(notification.status, me) : undefined,
|
||||||
|
type: notification.type,
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function simpleConvert<T>(data: T): T {
|
function simpleConvert<T>(data: T): T {
|
||||||
|
@ -333,12 +355,6 @@ export function convertFeaturedTag(tag: Entity.FeaturedTag) {
|
||||||
return simpleConvert(tag);
|
return simpleConvert(tag);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function convertNotification(notification: Entity.Notification) {
|
|
||||||
notification.account = convertAccount(notification.account);
|
|
||||||
if (notification.status) notification.status = convertStatus(notification.status);
|
|
||||||
return notification;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function convertPoll(poll: Entity.Poll) {
|
export function convertPoll(poll: Entity.Poll) {
|
||||||
return simpleConvert(poll);
|
return simpleConvert(poll);
|
||||||
}
|
}
|
||||||
|
@ -372,27 +388,7 @@ export function convertRelationship(relationship: Partial<Entity.Relationship> &
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function convertStatus(status: Entity.Status) {
|
|
||||||
status.account = convertAccount(status.account);
|
|
||||||
status.media_attachments = status.media_attachments.map((attachment) =>
|
|
||||||
convertAttachment(attachment),
|
|
||||||
);
|
|
||||||
if (status.poll) status.poll = convertPoll(status.poll);
|
|
||||||
if (status.reblog) status.reblog = convertStatus(status.reblog);
|
|
||||||
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
// noinspection JSUnusedGlobalSymbols
|
// noinspection JSUnusedGlobalSymbols
|
||||||
export function convertStatusSource(status: Entity.StatusSource) {
|
export function convertStatusSource(status: Entity.StatusSource) {
|
||||||
return simpleConvert(status);
|
return simpleConvert(status);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function convertConversation(conversation: Entity.Conversation) {
|
|
||||||
conversation.accounts = conversation.accounts.map(convertAccount);
|
|
||||||
if (conversation.last_status) {
|
|
||||||
conversation.last_status = convertStatus(conversation.last_status);
|
|
||||||
}
|
|
||||||
|
|
||||||
return conversation;
|
|
||||||
}
|
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
|
|
||||||
import { Injectable } from '@nestjs/common';
|
import { Injectable } from '@nestjs/common';
|
||||||
import { parseTimelineArgs, TimelineArgs } from '@/server/api/mastodon/timelineArgs.js';
|
import { parseTimelineArgs, TimelineArgs } from '@/server/api/mastodon/timelineArgs.js';
|
||||||
|
import { MiLocalUser } from '@/models/User.js';
|
||||||
import { MastoConverters, convertRelationship } from '../converters.js';
|
import { MastoConverters, convertRelationship } from '../converters.js';
|
||||||
import type { MegalodonInterface } from 'megalodon';
|
import type { MegalodonInterface } from 'megalodon';
|
||||||
import type { FastifyRequest } from 'fastify';
|
import type { FastifyRequest } from 'fastify';
|
||||||
|
@ -20,6 +21,7 @@ export class ApiAccountMastodon {
|
||||||
constructor(
|
constructor(
|
||||||
private readonly request: FastifyRequest<ApiAccountMastodonRoute>,
|
private readonly request: FastifyRequest<ApiAccountMastodonRoute>,
|
||||||
private readonly client: MegalodonInterface,
|
private readonly client: MegalodonInterface,
|
||||||
|
private readonly me: MiLocalUser | null,
|
||||||
private readonly mastoConverters: MastoConverters,
|
private readonly mastoConverters: MastoConverters,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
|
@ -51,7 +53,7 @@ export class ApiAccountMastodon {
|
||||||
public async getStatuses() {
|
public async getStatuses() {
|
||||||
if (!this.request.params.id) throw new Error('Missing required parameter "id"');
|
if (!this.request.params.id) throw new Error('Missing required parameter "id"');
|
||||||
const data = await this.client.getAccountStatuses(this.request.params.id, parseTimelineArgs(this.request.query));
|
const data = await this.client.getAccountStatuses(this.request.params.id, parseTimelineArgs(this.request.query));
|
||||||
return await Promise.all(data.data.map(async (status) => await this.mastoConverters.convertStatus(status)));
|
return await Promise.all(data.data.map(async (status) => await this.mastoConverters.convertStatus(status, this.me)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public async getFollowers() {
|
public async getFollowers() {
|
||||||
|
@ -117,12 +119,12 @@ export class ApiAccountMastodon {
|
||||||
|
|
||||||
public async getBookmarks() {
|
public async getBookmarks() {
|
||||||
const data = await this.client.getBookmarks(parseTimelineArgs(this.request.query));
|
const data = await this.client.getBookmarks(parseTimelineArgs(this.request.query));
|
||||||
return Promise.all(data.data.map((status) => this.mastoConverters.convertStatus(status)));
|
return Promise.all(data.data.map((status) => this.mastoConverters.convertStatus(status, this.me)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public async getFavourites() {
|
public async getFavourites() {
|
||||||
const data = await this.client.getFavourites(parseTimelineArgs(this.request.query));
|
const data = await this.client.getFavourites(parseTimelineArgs(this.request.query));
|
||||||
return Promise.all(data.data.map((status) => this.mastoConverters.convertStatus(status)));
|
return Promise.all(data.data.map((status) => this.mastoConverters.convertStatus(status, this.me)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public async getMutes() {
|
public async getMutes() {
|
||||||
|
|
|
@ -4,7 +4,8 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { parseTimelineArgs, TimelineArgs } from '@/server/api/mastodon/timelineArgs.js';
|
import { parseTimelineArgs, TimelineArgs } from '@/server/api/mastodon/timelineArgs.js';
|
||||||
import { convertNotification } from '../converters.js';
|
import { MiLocalUser } from '@/models/User.js';
|
||||||
|
import { MastoConverters } from '@/server/api/mastodon/converters.js';
|
||||||
import type { MegalodonInterface } from 'megalodon';
|
import type { MegalodonInterface } from 'megalodon';
|
||||||
import type { FastifyRequest } from 'fastify';
|
import type { FastifyRequest } from 'fastify';
|
||||||
|
|
||||||
|
@ -19,23 +20,25 @@ export class ApiNotifyMastodon {
|
||||||
constructor(
|
constructor(
|
||||||
private readonly request: FastifyRequest<ApiNotifyMastodonRoute>,
|
private readonly request: FastifyRequest<ApiNotifyMastodonRoute>,
|
||||||
private readonly client: MegalodonInterface,
|
private readonly client: MegalodonInterface,
|
||||||
|
private readonly me: MiLocalUser | null,
|
||||||
|
private readonly mastoConverters: MastoConverters,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
public async getNotifications() {
|
public async getNotifications() {
|
||||||
const data = await this.client.getNotifications(parseTimelineArgs(this.request.query));
|
const data = await this.client.getNotifications(parseTimelineArgs(this.request.query));
|
||||||
return data.data.map(n => {
|
return Promise.all(data.data.map(async n => {
|
||||||
const converted = convertNotification(n);
|
const converted = await this.mastoConverters.convertNotification(n, this.me);
|
||||||
if (converted.type === 'reaction') {
|
if (converted.type === 'reaction') {
|
||||||
converted.type = 'favourite';
|
converted.type = 'favourite';
|
||||||
}
|
}
|
||||||
return converted;
|
return converted;
|
||||||
});
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
public async getNotification() {
|
public async getNotification() {
|
||||||
if (!this.request.params.id) throw new Error('Missing required parameter "id"');
|
if (!this.request.params.id) throw new Error('Missing required parameter "id"');
|
||||||
const data = await this.client.getNotification(this.request.params.id);
|
const data = await this.client.getNotification(this.request.params.id);
|
||||||
const converted = convertNotification(data.data);
|
const converted = await this.mastoConverters.convertNotification(data.data, this.me);
|
||||||
if (converted.type === 'reaction') {
|
if (converted.type === 'reaction') {
|
||||||
converted.type = 'favourite';
|
converted.type = 'favourite';
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { MiLocalUser } from '@/models/User.js';
|
||||||
import { MastoConverters } from '../converters.js';
|
import { MastoConverters } from '../converters.js';
|
||||||
import { parseTimelineArgs, TimelineArgs } from '../timelineArgs.js';
|
import { parseTimelineArgs, TimelineArgs } from '../timelineArgs.js';
|
||||||
import Account = Entity.Account;
|
import Account = Entity.Account;
|
||||||
|
@ -21,8 +22,9 @@ export class ApiSearchMastodon {
|
||||||
constructor(
|
constructor(
|
||||||
private readonly request: FastifyRequest<ApiSearchMastodonRoute>,
|
private readonly request: FastifyRequest<ApiSearchMastodonRoute>,
|
||||||
private readonly client: MegalodonInterface,
|
private readonly client: MegalodonInterface,
|
||||||
|
private readonly me: MiLocalUser | null,
|
||||||
private readonly BASE_URL: string,
|
private readonly BASE_URL: string,
|
||||||
private readonly mastoConverter: MastoConverters,
|
private readonly mastoConverters: MastoConverters,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
public async SearchV1() {
|
public async SearchV1() {
|
||||||
|
@ -40,8 +42,8 @@ export class ApiSearchMastodon {
|
||||||
const stat = !type || type === 'statuses' ? await this.client.search(this.request.query.q, { type: 'statuses', ...query }) : null;
|
const stat = !type || type === 'statuses' ? await this.client.search(this.request.query.q, { type: 'statuses', ...query }) : null;
|
||||||
const tags = !type || type === 'hashtags' ? await this.client.search(this.request.query.q, { type: 'hashtags', ...query }) : null;
|
const tags = !type || type === 'hashtags' ? await this.client.search(this.request.query.q, { type: 'hashtags', ...query }) : null;
|
||||||
return {
|
return {
|
||||||
accounts: await Promise.all(acct?.data.accounts.map(async (account: Account) => await this.mastoConverter.convertAccount(account)) ?? []),
|
accounts: await Promise.all(acct?.data.accounts.map(async (account: Account) => await this.mastoConverters.convertAccount(account)) ?? []),
|
||||||
statuses: await Promise.all(stat?.data.statuses.map(async (status: Status) => await this.mastoConverter.convertStatus(status)) ?? []),
|
statuses: await Promise.all(stat?.data.statuses.map(async (status: Status) => await this.mastoConverters.convertStatus(status, this.me)) ?? []),
|
||||||
hashtags: tags?.data.hashtags ?? [],
|
hashtags: tags?.data.hashtags ?? [],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -54,10 +56,12 @@ export class ApiSearchMastodon {
|
||||||
'Accept': 'application/json',
|
'Accept': 'application/json',
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
},
|
},
|
||||||
body: '{}',
|
body: JSON.stringify({
|
||||||
|
i: this.request.headers.authorization?.replace('Bearer ', ''),
|
||||||
|
}),
|
||||||
})
|
})
|
||||||
.then(res => res.json() as Promise<Status[]>)
|
.then(res => res.json() as Promise<Status[]>)
|
||||||
.then(data => data.map(status => this.mastoConverter.convertStatus(status)));
|
.then(data => data.map(status => this.mastoConverters.convertStatus(status, this.me)));
|
||||||
return Promise.all(data);
|
return Promise.all(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,7 +87,7 @@ export class ApiSearchMastodon {
|
||||||
account: entry,
|
account: entry,
|
||||||
}))));
|
}))));
|
||||||
return Promise.all(data.map(async suggestion => {
|
return Promise.all(data.map(async suggestion => {
|
||||||
suggestion.account = await this.mastoConverter.convertAccount(suggestion.account);
|
suggestion.account = await this.mastoConverters.convertAccount(suggestion.account);
|
||||||
return suggestion;
|
return suggestion;
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@ import { getErrorData, MastodonLogger } from '@/server/api/mastodon/MastodonLogg
|
||||||
import { parseTimelineArgs, TimelineArgs, toBoolean, toInt } from '@/server/api/mastodon/timelineArgs.js';
|
import { parseTimelineArgs, TimelineArgs, toBoolean, toInt } from '@/server/api/mastodon/timelineArgs.js';
|
||||||
import { AuthenticateService } from '@/server/api/AuthenticateService.js';
|
import { AuthenticateService } from '@/server/api/AuthenticateService.js';
|
||||||
import { convertAttachment, convertPoll, MastoConverters } from '../converters.js';
|
import { convertAttachment, convertPoll, MastoConverters } from '../converters.js';
|
||||||
import { getAccessToken, getClient } from '../MastodonApiServerService.js';
|
import { getAccessToken, getClient, MastodonApiServerService } from '../MastodonApiServerService.js';
|
||||||
import type { Entity } from 'megalodon';
|
import type { Entity } from 'megalodon';
|
||||||
import type { FastifyInstance } from 'fastify';
|
import type { FastifyInstance } from 'fastify';
|
||||||
|
|
||||||
|
@ -24,17 +24,16 @@ export class ApiStatusMastodon {
|
||||||
private readonly mastoConverters: MastoConverters,
|
private readonly mastoConverters: MastoConverters,
|
||||||
private readonly logger: MastodonLogger,
|
private readonly logger: MastodonLogger,
|
||||||
private readonly authenticateService: AuthenticateService,
|
private readonly authenticateService: AuthenticateService,
|
||||||
|
private readonly mastodon: MastodonApiServerService,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
public getStatus() {
|
public getStatus() {
|
||||||
this.fastify.get<{ Params: { id?: string } }>('/v1/statuses/:id', async (_request, reply) => {
|
this.fastify.get<{ Params: { id?: string } }>('/v1/statuses/:id', async (_request, reply) => {
|
||||||
const BASE_URL = `${_request.protocol}://${_request.host}`;
|
|
||||||
const accessTokens = _request.headers.authorization;
|
|
||||||
const client = getClient(BASE_URL, accessTokens);
|
|
||||||
try {
|
try {
|
||||||
|
const { client, me } = await this.mastodon.getAuthClient(_request);
|
||||||
if (!_request.params.id) return reply.code(400).send({ error: 'Missing required parameter "id"' });
|
if (!_request.params.id) return reply.code(400).send({ error: 'Missing required parameter "id"' });
|
||||||
const data = await client.getStatus(_request.params.id);
|
const data = await client.getStatus(_request.params.id);
|
||||||
reply.send(await this.mastoConverters.convertStatus(data.data));
|
reply.send(await this.mastoConverters.convertStatus(data.data, me));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
const data = getErrorData(e);
|
const data = getErrorData(e);
|
||||||
this.logger.error(`GET /v1/statuses/${_request.params.id}`, data);
|
this.logger.error(`GET /v1/statuses/${_request.params.id}`, data);
|
||||||
|
@ -62,14 +61,12 @@ export class ApiStatusMastodon {
|
||||||
|
|
||||||
public getContext() {
|
public getContext() {
|
||||||
this.fastify.get<{ Params: { id?: string }, Querystring: TimelineArgs }>('/v1/statuses/:id/context', async (_request, reply) => {
|
this.fastify.get<{ Params: { id?: string }, Querystring: TimelineArgs }>('/v1/statuses/:id/context', async (_request, reply) => {
|
||||||
const BASE_URL = `${_request.protocol}://${_request.host}`;
|
|
||||||
const accessTokens = _request.headers.authorization;
|
|
||||||
const client = getClient(BASE_URL, accessTokens);
|
|
||||||
try {
|
try {
|
||||||
if (!_request.params.id) return reply.code(400).send({ error: 'Missing required parameter "id"' });
|
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.getStatusContext(_request.params.id, parseTimelineArgs(_request.query));
|
const { data } = await client.getStatusContext(_request.params.id, parseTimelineArgs(_request.query));
|
||||||
const ancestors = await Promise.all(data.ancestors.map(async status => await this.mastoConverters.convertStatus(status)));
|
const ancestors = await Promise.all(data.ancestors.map(async status => await this.mastoConverters.convertStatus(status, me)));
|
||||||
const descendants = await Promise.all(data.descendants.map(async status => await this.mastoConverters.convertStatus(status)));
|
const descendants = await Promise.all(data.descendants.map(async status => await this.mastoConverters.convertStatus(status, me)));
|
||||||
reply.send({ ancestors, descendants });
|
reply.send({ ancestors, descendants });
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
const data = getErrorData(e);
|
const data = getErrorData(e);
|
||||||
|
@ -204,11 +201,9 @@ export class ApiStatusMastodon {
|
||||||
'media_ids[]'?: string[],
|
'media_ids[]'?: string[],
|
||||||
}
|
}
|
||||||
}>('/v1/statuses', async (_request, reply) => {
|
}>('/v1/statuses', async (_request, reply) => {
|
||||||
const BASE_URL = `${_request.protocol}://${_request.host}`;
|
|
||||||
const accessTokens = _request.headers.authorization;
|
|
||||||
const client = getClient(BASE_URL, accessTokens);
|
|
||||||
let body = _request.body;
|
let body = _request.body;
|
||||||
try {
|
try {
|
||||||
|
const { client, me } = await this.mastodon.getAuthClient(_request);
|
||||||
if ((!body.poll && body['poll[options][]']) || (!body.media_ids && body['media_ids[]'])
|
if ((!body.poll && body['poll[options][]']) || (!body.media_ids && body['media_ids[]'])
|
||||||
) {
|
) {
|
||||||
body = normalizeQuery(body);
|
body = normalizeQuery(body);
|
||||||
|
@ -253,7 +248,7 @@ export class ApiStatusMastodon {
|
||||||
};
|
};
|
||||||
|
|
||||||
const data = await client.postStatus(text, options);
|
const data = await client.postStatus(text, options);
|
||||||
reply.send(await this.mastoConverters.convertStatus(data.data as Entity.Status));
|
reply.send(await this.mastoConverters.convertStatus(data.data as Entity.Status, me));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
const data = getErrorData(e);
|
const data = getErrorData(e);
|
||||||
this.logger.error('POST /v1/statuses', data);
|
this.logger.error('POST /v1/statuses', data);
|
||||||
|
@ -278,10 +273,8 @@ export class ApiStatusMastodon {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}>('/v1/statuses/:id', async (_request, reply) => {
|
}>('/v1/statuses/:id', async (_request, reply) => {
|
||||||
const BASE_URL = `${_request.protocol}://${_request.host}`;
|
|
||||||
const accessTokens = _request.headers.authorization;
|
|
||||||
const client = getClient(BASE_URL, accessTokens);
|
|
||||||
try {
|
try {
|
||||||
|
const { client, me } = await this.mastodon.getAuthClient(_request);
|
||||||
const body = _request.body;
|
const body = _request.body;
|
||||||
|
|
||||||
if (!body.media_ids || !body.media_ids.length) {
|
if (!body.media_ids || !body.media_ids.length) {
|
||||||
|
@ -300,7 +293,7 @@ export class ApiStatusMastodon {
|
||||||
};
|
};
|
||||||
|
|
||||||
const data = await client.editStatus(_request.params.id, options);
|
const data = await client.editStatus(_request.params.id, options);
|
||||||
reply.send(await this.mastoConverters.convertStatus(data.data));
|
reply.send(await this.mastoConverters.convertStatus(data.data, me));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
const data = getErrorData(e);
|
const data = getErrorData(e);
|
||||||
this.logger.error(`POST /v1/statuses/${_request.params.id}`, data);
|
this.logger.error(`POST /v1/statuses/${_request.params.id}`, data);
|
||||||
|
@ -311,13 +304,11 @@ export class ApiStatusMastodon {
|
||||||
|
|
||||||
public addFavourite() {
|
public addFavourite() {
|
||||||
this.fastify.post<{ Params: { id?: string } }>('/v1/statuses/:id/favourite', async (_request, reply) => {
|
this.fastify.post<{ Params: { id?: string } }>('/v1/statuses/:id/favourite', async (_request, reply) => {
|
||||||
const BASE_URL = `${_request.protocol}://${_request.host}`;
|
|
||||||
const accessTokens = _request.headers.authorization;
|
|
||||||
const client = getClient(BASE_URL, accessTokens);
|
|
||||||
try {
|
try {
|
||||||
if (!_request.params.id) return reply.code(400).send({ error: 'Missing required parameter "id"' });
|
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.createEmojiReaction(_request.params.id, '❤');
|
const data = await client.createEmojiReaction(_request.params.id, '❤');
|
||||||
reply.send(await this.mastoConverters.convertStatus(data.data));
|
reply.send(await this.mastoConverters.convertStatus(data.data, me));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
const data = getErrorData(e);
|
const data = getErrorData(e);
|
||||||
this.logger.error(`POST /v1/statuses/${_request.params.id}/favorite`, data);
|
this.logger.error(`POST /v1/statuses/${_request.params.id}/favorite`, data);
|
||||||
|
@ -328,13 +319,11 @@ export class ApiStatusMastodon {
|
||||||
|
|
||||||
public rmFavourite() {
|
public rmFavourite() {
|
||||||
this.fastify.post<{ Params: { id?: string } }>('/v1/statuses/:id/unfavourite', async (_request, reply) => {
|
this.fastify.post<{ Params: { id?: string } }>('/v1/statuses/:id/unfavourite', async (_request, reply) => {
|
||||||
const BASE_URL = `${_request.protocol}://${_request.host}`;
|
|
||||||
const accessTokens = _request.headers.authorization;
|
|
||||||
const client = getClient(BASE_URL, accessTokens);
|
|
||||||
try {
|
try {
|
||||||
|
const { client, me } = await this.mastodon.getAuthClient(_request);
|
||||||
if (!_request.params.id) return reply.code(400).send({ error: 'Missing required parameter "id"' });
|
if (!_request.params.id) return reply.code(400).send({ error: 'Missing required parameter "id"' });
|
||||||
const data = await client.deleteEmojiReaction(_request.params.id, '❤');
|
const data = await client.deleteEmojiReaction(_request.params.id, '❤');
|
||||||
reply.send(await this.mastoConverters.convertStatus(data.data));
|
reply.send(await this.mastoConverters.convertStatus(data.data, me));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
const data = getErrorData(e);
|
const data = getErrorData(e);
|
||||||
this.logger.error(`GET /v1/statuses/${_request.params.id}/unfavorite`, data);
|
this.logger.error(`GET /v1/statuses/${_request.params.id}/unfavorite`, data);
|
||||||
|
@ -345,13 +334,11 @@ export class ApiStatusMastodon {
|
||||||
|
|
||||||
public reblogStatus() {
|
public reblogStatus() {
|
||||||
this.fastify.post<{ Params: { id?: string } }>('/v1/statuses/:id/reblog', async (_request, reply) => {
|
this.fastify.post<{ Params: { id?: string } }>('/v1/statuses/:id/reblog', async (_request, reply) => {
|
||||||
const BASE_URL = `${_request.protocol}://${_request.host}`;
|
|
||||||
const accessTokens = _request.headers.authorization;
|
|
||||||
const client = getClient(BASE_URL, accessTokens);
|
|
||||||
try {
|
try {
|
||||||
if (!_request.params.id) return reply.code(400).send({ error: 'Missing required parameter "id"' });
|
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.reblogStatus(_request.params.id);
|
const data = await client.reblogStatus(_request.params.id);
|
||||||
reply.send(await this.mastoConverters.convertStatus(data.data));
|
reply.send(await this.mastoConverters.convertStatus(data.data, me));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
const data = getErrorData(e);
|
const data = getErrorData(e);
|
||||||
this.logger.error(`POST /v1/statuses/${_request.params.id}/reblog`, data);
|
this.logger.error(`POST /v1/statuses/${_request.params.id}/reblog`, data);
|
||||||
|
@ -362,13 +349,11 @@ export class ApiStatusMastodon {
|
||||||
|
|
||||||
public unreblogStatus() {
|
public unreblogStatus() {
|
||||||
this.fastify.post<{ Params: { id?: string } }>('/v1/statuses/:id/unreblog', async (_request, reply) => {
|
this.fastify.post<{ Params: { id?: string } }>('/v1/statuses/:id/unreblog', async (_request, reply) => {
|
||||||
const BASE_URL = `${_request.protocol}://${_request.host}`;
|
|
||||||
const accessTokens = _request.headers.authorization;
|
|
||||||
const client = getClient(BASE_URL, accessTokens);
|
|
||||||
try {
|
try {
|
||||||
if (!_request.params.id) return reply.code(400).send({ error: 'Missing required parameter "id"' });
|
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.unreblogStatus(_request.params.id);
|
const data = await client.unreblogStatus(_request.params.id);
|
||||||
reply.send(await this.mastoConverters.convertStatus(data.data));
|
reply.send(await this.mastoConverters.convertStatus(data.data, me));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
const data = getErrorData(e);
|
const data = getErrorData(e);
|
||||||
this.logger.error(`POST /v1/statuses/${_request.params.id}/unreblog`, data);
|
this.logger.error(`POST /v1/statuses/${_request.params.id}/unreblog`, data);
|
||||||
|
@ -379,13 +364,11 @@ export class ApiStatusMastodon {
|
||||||
|
|
||||||
public bookmarkStatus() {
|
public bookmarkStatus() {
|
||||||
this.fastify.post<{ Params: { id?: string } }>('/v1/statuses/:id/bookmark', async (_request, reply) => {
|
this.fastify.post<{ Params: { id?: string } }>('/v1/statuses/:id/bookmark', async (_request, reply) => {
|
||||||
const BASE_URL = `${_request.protocol}://${_request.host}`;
|
|
||||||
const accessTokens = _request.headers.authorization;
|
|
||||||
const client = getClient(BASE_URL, accessTokens);
|
|
||||||
try {
|
try {
|
||||||
if (!_request.params.id) return reply.code(400).send({ error: 'Missing required parameter "id"' });
|
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.bookmarkStatus(_request.params.id);
|
const data = await client.bookmarkStatus(_request.params.id);
|
||||||
reply.send(await this.mastoConverters.convertStatus(data.data));
|
reply.send(await this.mastoConverters.convertStatus(data.data, me));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
const data = getErrorData(e);
|
const data = getErrorData(e);
|
||||||
this.logger.error(`POST /v1/statuses/${_request.params.id}/bookmark`, data);
|
this.logger.error(`POST /v1/statuses/${_request.params.id}/bookmark`, data);
|
||||||
|
@ -396,13 +379,11 @@ export class ApiStatusMastodon {
|
||||||
|
|
||||||
public unbookmarkStatus() {
|
public unbookmarkStatus() {
|
||||||
this.fastify.post<{ Params: { id?: string } }>('/v1/statuses/:id/unbookmark', async (_request, reply) => {
|
this.fastify.post<{ Params: { id?: string } }>('/v1/statuses/:id/unbookmark', async (_request, reply) => {
|
||||||
const BASE_URL = `${_request.protocol}://${_request.host}`;
|
|
||||||
const accessTokens = _request.headers.authorization;
|
|
||||||
const client = getClient(BASE_URL, accessTokens);
|
|
||||||
try {
|
try {
|
||||||
if (!_request.params.id) return reply.code(400).send({ error: 'Missing required parameter "id"' });
|
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.unbookmarkStatus(_request.params.id);
|
const data = await client.unbookmarkStatus(_request.params.id);
|
||||||
reply.send(await this.mastoConverters.convertStatus(data.data));
|
reply.send(await this.mastoConverters.convertStatus(data.data, me));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
const data = getErrorData(e);
|
const data = getErrorData(e);
|
||||||
this.logger.error(`POST /v1/statuses/${_request.params.id}/unbookmark`, data);
|
this.logger.error(`POST /v1/statuses/${_request.params.id}/unbookmark`, data);
|
||||||
|
@ -413,13 +394,11 @@ export class ApiStatusMastodon {
|
||||||
|
|
||||||
public pinStatus() {
|
public pinStatus() {
|
||||||
this.fastify.post<{ Params: { id?: string } }>('/v1/statuses/:id/pin', async (_request, reply) => {
|
this.fastify.post<{ Params: { id?: string } }>('/v1/statuses/:id/pin', async (_request, reply) => {
|
||||||
const BASE_URL = `${_request.protocol}://${_request.host}`;
|
|
||||||
const accessTokens = _request.headers.authorization;
|
|
||||||
const client = getClient(BASE_URL, accessTokens);
|
|
||||||
try {
|
try {
|
||||||
if (!_request.params.id) return reply.code(400).send({ error: 'Missing required parameter "id"' });
|
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.pinStatus(_request.params.id);
|
const data = await client.pinStatus(_request.params.id);
|
||||||
reply.send(await this.mastoConverters.convertStatus(data.data));
|
reply.send(await this.mastoConverters.convertStatus(data.data, me));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
const data = getErrorData(e);
|
const data = getErrorData(e);
|
||||||
this.logger.error(`POST /v1/statuses/${_request.params.id}/pin`, data);
|
this.logger.error(`POST /v1/statuses/${_request.params.id}/pin`, data);
|
||||||
|
@ -430,13 +409,11 @@ export class ApiStatusMastodon {
|
||||||
|
|
||||||
public unpinStatus() {
|
public unpinStatus() {
|
||||||
this.fastify.post<{ Params: { id?: string } }>('/v1/statuses/:id/unpin', async (_request, reply) => {
|
this.fastify.post<{ Params: { id?: string } }>('/v1/statuses/:id/unpin', async (_request, reply) => {
|
||||||
const BASE_URL = `${_request.protocol}://${_request.host}`;
|
|
||||||
const accessTokens = _request.headers.authorization;
|
|
||||||
const client = getClient(BASE_URL, accessTokens);
|
|
||||||
try {
|
try {
|
||||||
if (!_request.params.id) return reply.code(400).send({ error: 'Missing required parameter "id"' });
|
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.unpinStatus(_request.params.id);
|
const data = await client.unpinStatus(_request.params.id);
|
||||||
reply.send(await this.mastoConverters.convertStatus(data.data));
|
reply.send(await this.mastoConverters.convertStatus(data.data, me));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
const data = getErrorData(e);
|
const data = getErrorData(e);
|
||||||
this.logger.error(`POST /v1/statuses/${_request.params.id}/unpin`, data);
|
this.logger.error(`POST /v1/statuses/${_request.params.id}/unpin`, data);
|
||||||
|
@ -447,14 +424,12 @@ export class ApiStatusMastodon {
|
||||||
|
|
||||||
public reactStatus() {
|
public reactStatus() {
|
||||||
this.fastify.post<{ Params: { id?: string, name?: string } }>('/v1/statuses/:id/react/:name', async (_request, reply) => {
|
this.fastify.post<{ Params: { id?: string, name?: string } }>('/v1/statuses/:id/react/:name', async (_request, reply) => {
|
||||||
const BASE_URL = `${_request.protocol}://${_request.host}`;
|
|
||||||
const accessTokens = _request.headers.authorization;
|
|
||||||
const client = getClient(BASE_URL, accessTokens);
|
|
||||||
try {
|
try {
|
||||||
if (!_request.params.id) return reply.code(400).send({ error: 'Missing required parameter "id"' });
|
if (!_request.params.id) return reply.code(400).send({ error: 'Missing required parameter "id"' });
|
||||||
if (!_request.params.name) return reply.code(400).send({ error: 'Missing required parameter "name"' });
|
if (!_request.params.name) return reply.code(400).send({ error: 'Missing required parameter "name"' });
|
||||||
|
const { client, me } = await this.mastodon.getAuthClient(_request);
|
||||||
const data = await client.createEmojiReaction(_request.params.id, _request.params.name);
|
const data = await client.createEmojiReaction(_request.params.id, _request.params.name);
|
||||||
reply.send(await this.mastoConverters.convertStatus(data.data));
|
reply.send(await this.mastoConverters.convertStatus(data.data, me));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
const data = getErrorData(e);
|
const data = getErrorData(e);
|
||||||
this.logger.error(`POST /v1/statuses/${_request.params.id}/react/${_request.params.name}`, data);
|
this.logger.error(`POST /v1/statuses/${_request.params.id}/react/${_request.params.name}`, data);
|
||||||
|
@ -465,14 +440,12 @@ export class ApiStatusMastodon {
|
||||||
|
|
||||||
public unreactStatus() {
|
public unreactStatus() {
|
||||||
this.fastify.post<{ Params: { id?: string, name?: string } }>('/v1/statuses/:id/unreact/:name', async (_request, reply) => {
|
this.fastify.post<{ Params: { id?: string, name?: string } }>('/v1/statuses/:id/unreact/:name', async (_request, reply) => {
|
||||||
const BASE_URL = `${_request.protocol}://${_request.host}`;
|
|
||||||
const accessTokens = _request.headers.authorization;
|
|
||||||
const client = getClient(BASE_URL, accessTokens);
|
|
||||||
try {
|
try {
|
||||||
if (!_request.params.id) return reply.code(400).send({ error: 'Missing required parameter "id"' });
|
if (!_request.params.id) return reply.code(400).send({ error: 'Missing required parameter "id"' });
|
||||||
if (!_request.params.name) return reply.code(400).send({ error: 'Missing required parameter "name"' });
|
if (!_request.params.name) return reply.code(400).send({ error: 'Missing required parameter "name"' });
|
||||||
|
const { client, me } = await this.mastodon.getAuthClient(_request);
|
||||||
const data = await client.deleteEmojiReaction(_request.params.id, _request.params.name);
|
const data = await client.deleteEmojiReaction(_request.params.id, _request.params.name);
|
||||||
reply.send(await this.mastoConverters.convertStatus(data.data));
|
reply.send(await this.mastoConverters.convertStatus(data.data, me));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
const data = getErrorData(e);
|
const data = getErrorData(e);
|
||||||
this.logger.error(`POST /v1/statuses/${_request.params.id}/unreact/${_request.params.name}`, data);
|
this.logger.error(`POST /v1/statuses/${_request.params.id}/unreact/${_request.params.name}`, data);
|
||||||
|
|
|
@ -4,8 +4,8 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { getErrorData, MastodonLogger } from '@/server/api/mastodon/MastodonLogger.js';
|
import { getErrorData, MastodonLogger } from '@/server/api/mastodon/MastodonLogger.js';
|
||||||
import { convertConversation, convertList, MastoConverters } from '../converters.js';
|
import { convertList, MastoConverters } from '../converters.js';
|
||||||
import { getClient } from '../MastodonApiServerService.js';
|
import { getClient, MastodonApiServerService } from '../MastodonApiServerService.js';
|
||||||
import { parseTimelineArgs, TimelineArgs, toBoolean } from '../timelineArgs.js';
|
import { parseTimelineArgs, TimelineArgs, toBoolean } from '../timelineArgs.js';
|
||||||
import type { Entity } from 'megalodon';
|
import type { Entity } from 'megalodon';
|
||||||
import type { FastifyInstance } from 'fastify';
|
import type { FastifyInstance } from 'fastify';
|
||||||
|
@ -15,18 +15,17 @@ export class ApiTimelineMastodon {
|
||||||
private readonly fastify: FastifyInstance,
|
private readonly fastify: FastifyInstance,
|
||||||
private readonly mastoConverters: MastoConverters,
|
private readonly mastoConverters: MastoConverters,
|
||||||
private readonly logger: MastodonLogger,
|
private readonly logger: MastodonLogger,
|
||||||
|
private readonly mastodon: MastodonApiServerService,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
public getTL() {
|
public getTL() {
|
||||||
this.fastify.get<{ Querystring: TimelineArgs }>('/v1/timelines/public', async (_request, reply) => {
|
this.fastify.get<{ Querystring: TimelineArgs }>('/v1/timelines/public', async (_request, reply) => {
|
||||||
const BASE_URL = `${_request.protocol}://${_request.host}`;
|
|
||||||
const accessTokens = _request.headers.authorization;
|
|
||||||
const client = getClient(BASE_URL, accessTokens);
|
|
||||||
try {
|
try {
|
||||||
|
const { client, me } = await this.mastodon.getAuthClient(_request);
|
||||||
const data = toBoolean(_request.query.local)
|
const data = toBoolean(_request.query.local)
|
||||||
? await client.getLocalTimeline(parseTimelineArgs(_request.query))
|
? await client.getLocalTimeline(parseTimelineArgs(_request.query))
|
||||||
: await client.getPublicTimeline(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))));
|
reply.send(await Promise.all(data.data.map(async (status: Entity.Status) => await this.mastoConverters.convertStatus(status, me))));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
const data = getErrorData(e);
|
const data = getErrorData(e);
|
||||||
this.logger.error('GET /v1/timelines/public', data);
|
this.logger.error('GET /v1/timelines/public', data);
|
||||||
|
@ -37,12 +36,10 @@ export class ApiTimelineMastodon {
|
||||||
|
|
||||||
public getHomeTl() {
|
public getHomeTl() {
|
||||||
this.fastify.get<{ Querystring: TimelineArgs }>('/v1/timelines/home', async (_request, reply) => {
|
this.fastify.get<{ Querystring: TimelineArgs }>('/v1/timelines/home', async (_request, reply) => {
|
||||||
const BASE_URL = `${_request.protocol}://${_request.host}`;
|
|
||||||
const accessTokens = _request.headers.authorization;
|
|
||||||
const client = getClient(BASE_URL, accessTokens);
|
|
||||||
try {
|
try {
|
||||||
|
const { client, me } = await this.mastodon.getAuthClient(_request);
|
||||||
const data = await client.getHomeTimeline(parseTimelineArgs(_request.query));
|
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))));
|
reply.send(await Promise.all(data.data.map(async (status: Entity.Status) => await this.mastoConverters.convertStatus(status, me))));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
const data = getErrorData(e);
|
const data = getErrorData(e);
|
||||||
this.logger.error('GET /v1/timelines/home', data);
|
this.logger.error('GET /v1/timelines/home', data);
|
||||||
|
@ -53,13 +50,11 @@ export class ApiTimelineMastodon {
|
||||||
|
|
||||||
public getTagTl() {
|
public getTagTl() {
|
||||||
this.fastify.get<{ Params: { hashtag?: string }, Querystring: TimelineArgs }>('/v1/timelines/tag/:hashtag', async (_request, reply) => {
|
this.fastify.get<{ Params: { hashtag?: string }, Querystring: TimelineArgs }>('/v1/timelines/tag/:hashtag', async (_request, reply) => {
|
||||||
const BASE_URL = `${_request.protocol}://${_request.host}`;
|
|
||||||
const accessTokens = _request.headers.authorization;
|
|
||||||
const client = getClient(BASE_URL, accessTokens);
|
|
||||||
try {
|
try {
|
||||||
if (!_request.params.hashtag) return reply.code(400).send({ error: 'Missing required parameter "hashtag"' });
|
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));
|
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))));
|
reply.send(await Promise.all(data.data.map(async (status: Entity.Status) => await this.mastoConverters.convertStatus(status, me))));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
const data = getErrorData(e);
|
const data = getErrorData(e);
|
||||||
this.logger.error(`GET /v1/timelines/tag/${_request.params.hashtag}`, data);
|
this.logger.error(`GET /v1/timelines/tag/${_request.params.hashtag}`, data);
|
||||||
|
@ -70,13 +65,11 @@ export class ApiTimelineMastodon {
|
||||||
|
|
||||||
public getListTL() {
|
public getListTL() {
|
||||||
this.fastify.get<{ Params: { id?: string }, Querystring: TimelineArgs }>('/v1/timelines/list/:id', async (_request, reply) => {
|
this.fastify.get<{ Params: { id?: string }, Querystring: TimelineArgs }>('/v1/timelines/list/:id', async (_request, reply) => {
|
||||||
const BASE_URL = `${_request.protocol}://${_request.host}`;
|
|
||||||
const accessTokens = _request.headers.authorization;
|
|
||||||
const client = getClient(BASE_URL, accessTokens);
|
|
||||||
try {
|
try {
|
||||||
if (!_request.params.id) return reply.code(400).send({ error: 'Missing required parameter "id"' });
|
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));
|
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))));
|
reply.send(await Promise.all(data.data.map(async (status: Entity.Status) => await this.mastoConverters.convertStatus(status, me))));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
const data = getErrorData(e);
|
const data = getErrorData(e);
|
||||||
this.logger.error(`GET /v1/timelines/list/${_request.params.id}`, data);
|
this.logger.error(`GET /v1/timelines/list/${_request.params.id}`, data);
|
||||||
|
@ -87,12 +80,11 @@ export class ApiTimelineMastodon {
|
||||||
|
|
||||||
public getConversations() {
|
public getConversations() {
|
||||||
this.fastify.get<{ Querystring: TimelineArgs }>('/v1/conversations', async (_request, reply) => {
|
this.fastify.get<{ Querystring: TimelineArgs }>('/v1/conversations', async (_request, reply) => {
|
||||||
const BASE_URL = `${_request.protocol}://${_request.host}`;
|
|
||||||
const accessTokens = _request.headers.authorization;
|
|
||||||
const client = getClient(BASE_URL, accessTokens);
|
|
||||||
try {
|
try {
|
||||||
|
const { client, me } = await this.mastodon.getAuthClient(_request);
|
||||||
const data = await client.getConversationTimeline(parseTimelineArgs(_request.query));
|
const data = await client.getConversationTimeline(parseTimelineArgs(_request.query));
|
||||||
reply.send(data.data.map((conversation: Entity.Conversation) => convertConversation(conversation)));
|
const conversations = await Promise.all(data.data.map(async (conversation: Entity.Conversation) => await this.mastoConverters.convertConversation(conversation, me)));
|
||||||
|
reply.send(conversations);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
const data = getErrorData(e);
|
const data = getErrorData(e);
|
||||||
this.logger.error('GET /v1/conversations', data);
|
this.logger.error('GET /v1/conversations', data);
|
||||||
|
|
Loading…
Add table
Reference in a new issue