mirror of
https://git.joinsharkey.org/Sharkey/Sharkey.git
synced 2025-03-13 12:11:06 +02:00
426 lines
16 KiB
TypeScript
426 lines
16 KiB
TypeScript
import querystring from 'querystring';
|
|
import { emojiRegexAtStartToEnd } from '@/misc/emoji-regex.js';
|
|
import { convertId, IdConvertType as IdType, convertAccount, convertAttachment, convertPoll, convertStatusSource, MastoConverters } from '../converters.js';
|
|
import { getClient } from '../MastodonApiServerService.js';
|
|
import { convertTimelinesArgsId, limitToInt } from './timeline.js';
|
|
import type { Entity } from 'megalodon';
|
|
import type { FastifyInstance } from 'fastify';
|
|
import type { Config } from '@/config.js';
|
|
import { NoteEditRepository, NotesRepository, UsersRepository } from '@/models/_.js';
|
|
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
|
|
|
function normalizeQuery(data: any) {
|
|
const str = querystring.stringify(data);
|
|
return querystring.parse(str);
|
|
}
|
|
|
|
export class ApiStatusMastodon {
|
|
private fastify: FastifyInstance;
|
|
private mastoconverter: MastoConverters;
|
|
|
|
constructor(fastify: FastifyInstance, config: Config, usersrepo: UsersRepository, notesrepo: NotesRepository, noteeditrepo: NoteEditRepository, userentity: UserEntityService) {
|
|
this.fastify = fastify;
|
|
this.mastoconverter = new MastoConverters(config, usersrepo, notesrepo, noteeditrepo, userentity);
|
|
}
|
|
|
|
public async getStatus() {
|
|
this.fastify.get<{ Params: { id: string } }>('/v1/statuses/:id', async (_request, reply) => {
|
|
const BASE_URL = `${_request.protocol}://${_request.hostname}`;
|
|
const accessTokens = _request.headers.authorization;
|
|
const client = getClient(BASE_URL, accessTokens);
|
|
try {
|
|
const data = await client.getStatus(convertId(_request.params.id, IdType.SharkeyId));
|
|
reply.send(await this.mastoconverter.convertStatus(data.data));
|
|
} catch (e: any) {
|
|
console.error(e);
|
|
reply.code(_request.is404 ? 404 : 401).send(e.response.data);
|
|
}
|
|
});
|
|
}
|
|
|
|
public async getStatusSource() {
|
|
this.fastify.get<{ Params: { id: string } }>('/v1/statuses/:id/source', async (_request, reply) => {
|
|
const BASE_URL = `${_request.protocol}://${_request.hostname}`;
|
|
const accessTokens = _request.headers.authorization;
|
|
const client = getClient(BASE_URL, accessTokens);
|
|
try {
|
|
const data = await client.getStatusSource(convertId(_request.params.id, IdType.SharkeyId));
|
|
reply.send(convertStatusSource(data.data));
|
|
} catch (e: any) {
|
|
console.error(e);
|
|
reply.code(_request.is404 ? 404 : 401).send(e.response.data);
|
|
}
|
|
});
|
|
}
|
|
|
|
public async getContext() {
|
|
this.fastify.get<{ Params: { id: string } }>('/v1/statuses/:id/context', async (_request, reply) => {
|
|
const BASE_URL = `${_request.protocol}://${_request.hostname}`;
|
|
const accessTokens = _request.headers.authorization;
|
|
const client = getClient(BASE_URL, accessTokens);
|
|
const query: any = _request.query;
|
|
try {
|
|
const data = await client.getStatusContext(
|
|
convertId(_request.params.id, IdType.SharkeyId),
|
|
convertTimelinesArgsId(limitToInt(query)),
|
|
);
|
|
data.data.ancestors = await Promise.all(data.data.ancestors.map(async (status: Entity.Status) => await this.mastoconverter.convertStatus(status)));
|
|
data.data.descendants = await Promise.all(data.data.descendants.map(async (status: Entity.Status) => await this.mastoconverter.convertStatus(status)));
|
|
reply.send(data.data);
|
|
} catch (e: any) {
|
|
console.error(e);
|
|
reply.code(_request.is404 ? 404 : 401).send(e.response.data);
|
|
}
|
|
});
|
|
}
|
|
|
|
public async getHistory() {
|
|
this.fastify.get<{ Params: { id: string } }>('/v1/statuses/:id/history', async (_request, reply) => {
|
|
try {
|
|
reply.send([]);
|
|
} catch (e: any) {
|
|
console.error(e);
|
|
reply.code(401).send(e.response.data);
|
|
}
|
|
});
|
|
}
|
|
|
|
public async getReblogged() {
|
|
this.fastify.get<{ Params: { id: string } }>('/v1/statuses/:id/reblogged_by', async (_request, reply) => {
|
|
const BASE_URL = `${_request.protocol}://${_request.hostname}`;
|
|
const accessTokens = _request.headers.authorization;
|
|
const client = getClient(BASE_URL, accessTokens);
|
|
try {
|
|
const data = await client.getStatusRebloggedBy(convertId(_request.params.id, IdType.SharkeyId));
|
|
reply.send(data.data.map((account: Entity.Account) => convertAccount(account)));
|
|
} catch (e: any) {
|
|
console.error(e);
|
|
reply.code(401).send(e.response.data);
|
|
}
|
|
});
|
|
}
|
|
|
|
public async getFavourites() {
|
|
this.fastify.get<{ Params: { id: string } }>('/v1/statuses/:id/favourited_by', async (_request, reply) => {
|
|
const BASE_URL = `${_request.protocol}://${_request.hostname}`;
|
|
const accessTokens = _request.headers.authorization;
|
|
const client = getClient(BASE_URL, accessTokens);
|
|
try {
|
|
const data = await client.getStatusFavouritedBy(convertId(_request.params.id, IdType.SharkeyId));
|
|
reply.send(data.data.map((account: Entity.Account) => convertAccount(account)));
|
|
} catch (e: any) {
|
|
console.error(e);
|
|
reply.code(401).send(e.response.data);
|
|
}
|
|
});
|
|
}
|
|
|
|
public async getMedia() {
|
|
this.fastify.get<{ Params: { id: string } }>('/v1/media/:id', async (_request, reply) => {
|
|
const BASE_URL = `${_request.protocol}://${_request.hostname}`;
|
|
const accessTokens = _request.headers.authorization;
|
|
const client = getClient(BASE_URL, accessTokens);
|
|
try {
|
|
const data = await client.getMedia(convertId(_request.params.id, IdType.SharkeyId));
|
|
reply.send(convertAttachment(data.data));
|
|
} catch (e: any) {
|
|
console.error(e);
|
|
reply.code(401).send(e.response.data);
|
|
}
|
|
});
|
|
}
|
|
|
|
public async getPoll() {
|
|
this.fastify.get<{ Params: { id: string } }>('/v1/polls/:id', async (_request, reply) => {
|
|
const BASE_URL = `${_request.protocol}://${_request.hostname}`;
|
|
const accessTokens = _request.headers.authorization;
|
|
const client = getClient(BASE_URL, accessTokens);
|
|
try {
|
|
const data = await client.getPoll(convertId(_request.params.id, IdType.SharkeyId));
|
|
reply.send(convertPoll(data.data));
|
|
} catch (e: any) {
|
|
console.error(e);
|
|
reply.code(401).send(e.response.data);
|
|
}
|
|
});
|
|
}
|
|
|
|
public async votePoll() {
|
|
this.fastify.post<{ Params: { id: string } }>('/v1/polls/:id/votes', async (_request, reply) => {
|
|
const BASE_URL = `${_request.protocol}://${_request.hostname}`;
|
|
const accessTokens = _request.headers.authorization;
|
|
const client = getClient(BASE_URL, accessTokens);
|
|
const body: any = _request.body;
|
|
try {
|
|
const data = await client.votePoll(convertId(_request.params.id, IdType.SharkeyId), body.choices);
|
|
reply.send(convertPoll(data.data));
|
|
} catch (e: any) {
|
|
console.error(e);
|
|
reply.code(401).send(e.response.data);
|
|
}
|
|
});
|
|
}
|
|
|
|
public async postStatus() {
|
|
this.fastify.post('/v1/statuses', async (_request, reply) => {
|
|
const BASE_URL = `${_request.protocol}://${_request.hostname}`;
|
|
const accessTokens = _request.headers.authorization;
|
|
const client = getClient(BASE_URL, accessTokens);
|
|
let body: any = _request.body;
|
|
try {
|
|
if (body.in_reply_to_id) body.in_reply_to_id = convertId(body.in_reply_to_id, IdType.SharkeyId);
|
|
if (body.quote_id) body.quote_id = convertId(body.quote_id, IdType.SharkeyId);
|
|
if (
|
|
(!body.poll && body['poll[options][]']) ||
|
|
(!body.media_ids && body['media_ids[]'])
|
|
) {
|
|
body = normalizeQuery(body);
|
|
}
|
|
const text = body.status ? body.status : ' ';
|
|
const removed = text.replace(/@\S+/g, '').replace(/\s|/g, '');
|
|
const isDefaultEmoji = emojiRegexAtStartToEnd.test(removed);
|
|
const isCustomEmoji = /^:[a-zA-Z0-9@_]+:$/.test(removed);
|
|
if ((body.in_reply_to_id && isDefaultEmoji) || (body.in_reply_to_id && isCustomEmoji)) {
|
|
const a = await client.createEmojiReaction(
|
|
body.in_reply_to_id,
|
|
removed,
|
|
);
|
|
reply.send(a.data);
|
|
}
|
|
if (body.in_reply_to_id && removed === '/unreact') {
|
|
try {
|
|
const id = body.in_reply_to_id;
|
|
const post = await client.getStatus(id);
|
|
const react = post.data.emoji_reactions.filter((e: any) => e.me)[0].name;
|
|
const data = await client.deleteEmojiReaction(id, react);
|
|
reply.send(data.data);
|
|
} catch (e: any) {
|
|
console.error(e);
|
|
reply.code(401).send(e.response.data);
|
|
}
|
|
}
|
|
if (!body.media_ids) body.media_ids = undefined;
|
|
if (body.media_ids && !body.media_ids.length) body.media_ids = undefined;
|
|
if (body.media_ids) {
|
|
body.media_ids = (body.media_ids as string[]).map((p) => convertId(p, IdType.SharkeyId));
|
|
}
|
|
|
|
const { sensitive } = body;
|
|
body.sensitive = typeof sensitive === 'string' ? sensitive === 'true' : sensitive;
|
|
|
|
if (body.poll) {
|
|
if (
|
|
body.poll.expires_in != null &&
|
|
typeof body.poll.expires_in === 'string'
|
|
) body.poll.expires_in = parseInt(body.poll.expires_in);
|
|
if (
|
|
body.poll.multiple != null &&
|
|
typeof body.poll.multiple === 'string'
|
|
) body.poll.multiple = body.poll.multiple === 'true';
|
|
if (
|
|
body.poll.hide_totals != null &&
|
|
typeof body.poll.hide_totals === 'string'
|
|
) body.poll.hide_totals = body.poll.hide_totals === 'true';
|
|
}
|
|
|
|
const data = await client.postStatus(text, body);
|
|
reply.send(await this.mastoconverter.convertStatus(data.data as Entity.Status));
|
|
} catch (e: any) {
|
|
console.error(e);
|
|
reply.code(401).send(e.response.data);
|
|
}
|
|
});
|
|
}
|
|
|
|
public async updateStatus() {
|
|
this.fastify.put<{ Params: { id: string } }>('/v1/statuses/:id', async (_request, reply) => {
|
|
const BASE_URL = `${_request.protocol}://${_request.hostname}`;
|
|
const accessTokens = _request.headers.authorization;
|
|
const client = getClient(BASE_URL, accessTokens);
|
|
const body: any = _request.body;
|
|
try {
|
|
if (!body.media_ids) body.media_ids = undefined;
|
|
if (body.media_ids && !body.media_ids.length) body.media_ids = undefined;
|
|
if (body.media_ids) {
|
|
body.media_ids = (body.media_ids as string[]).map((p) => convertId(p, IdType.SharkeyId));
|
|
}
|
|
const data = await client.editStatus(convertId(_request.params.id, IdType.SharkeyId), body);
|
|
reply.send(await this.mastoconverter.convertStatus(data.data));
|
|
} catch (e: any) {
|
|
console.error(e);
|
|
reply.code(_request.is404 ? 404 : 401).send(e.response.data);
|
|
}
|
|
});
|
|
}
|
|
|
|
public async addFavourite() {
|
|
this.fastify.post<{ Params: { id: string } }>('/v1/statuses/:id/favourite', async (_request, reply) => {
|
|
const BASE_URL = `${_request.protocol}://${_request.hostname}`;
|
|
const accessTokens = _request.headers.authorization;
|
|
const client = getClient(BASE_URL, accessTokens);
|
|
try {
|
|
const data = (await client.createEmojiReaction(
|
|
convertId(_request.params.id, IdType.SharkeyId),
|
|
'❤',
|
|
)) as any;
|
|
reply.send(await this.mastoconverter.convertStatus(data.data));
|
|
} catch (e: any) {
|
|
console.error(e);
|
|
reply.code(401).send(e.response.data);
|
|
}
|
|
});
|
|
}
|
|
|
|
public async rmFavourite() {
|
|
this.fastify.post<{ Params: { id: string } }>('/v1/statuses/:id/unfavourite', async (_request, reply) => {
|
|
const BASE_URL = `${_request.protocol}://${_request.hostname}`;
|
|
const accessTokens = _request.headers.authorization;
|
|
const client = getClient(BASE_URL, accessTokens);
|
|
try {
|
|
const data = await client.deleteEmojiReaction(
|
|
convertId(_request.params.id, IdType.SharkeyId),
|
|
'❤',
|
|
);
|
|
reply.send(await this.mastoconverter.convertStatus(data.data));
|
|
} catch (e: any) {
|
|
console.error(e);
|
|
reply.code(401).send(e.response.data);
|
|
}
|
|
});
|
|
}
|
|
|
|
public async reblogStatus() {
|
|
this.fastify.post<{ Params: { id: string } }>('/v1/statuses/:id/reblog', async (_request, reply) => {
|
|
const BASE_URL = `${_request.protocol}://${_request.hostname}`;
|
|
const accessTokens = _request.headers.authorization;
|
|
const client = getClient(BASE_URL, accessTokens);
|
|
try {
|
|
const data = await client.reblogStatus(convertId(_request.params.id, IdType.SharkeyId));
|
|
reply.send(await this.mastoconverter.convertStatus(data.data));
|
|
} catch (e: any) {
|
|
console.error(e);
|
|
reply.code(401).send(e.response.data);
|
|
}
|
|
});
|
|
}
|
|
|
|
public async unreblogStatus() {
|
|
this.fastify.post<{ Params: { id: string } }>('/v1/statuses/:id/unreblog', async (_request, reply) => {
|
|
const BASE_URL = `${_request.protocol}://${_request.hostname}`;
|
|
const accessTokens = _request.headers.authorization;
|
|
const client = getClient(BASE_URL, accessTokens);
|
|
try {
|
|
const data = await client.unreblogStatus(convertId(_request.params.id, IdType.SharkeyId));
|
|
reply.send(await this.mastoconverter.convertStatus(data.data));
|
|
} catch (e: any) {
|
|
console.error(e);
|
|
reply.code(401).send(e.response.data);
|
|
}
|
|
});
|
|
}
|
|
|
|
public async bookmarkStatus() {
|
|
this.fastify.post<{ Params: { id: string } }>('/v1/statuses/:id/bookmark', async (_request, reply) => {
|
|
const BASE_URL = `${_request.protocol}://${_request.hostname}`;
|
|
const accessTokens = _request.headers.authorization;
|
|
const client = getClient(BASE_URL, accessTokens);
|
|
try {
|
|
const data = await client.bookmarkStatus(convertId(_request.params.id, IdType.SharkeyId));
|
|
reply.send(await this.mastoconverter.convertStatus(data.data));
|
|
} catch (e: any) {
|
|
console.error(e);
|
|
reply.code(401).send(e.response.data);
|
|
}
|
|
});
|
|
}
|
|
|
|
public async unbookmarkStatus() {
|
|
this.fastify.post<{ Params: { id: string } }>('/v1/statuses/:id/unbookmark', async (_request, reply) => {
|
|
const BASE_URL = `${_request.protocol}://${_request.hostname}`;
|
|
const accessTokens = _request.headers.authorization;
|
|
const client = getClient(BASE_URL, accessTokens);
|
|
try {
|
|
const data = await client.unbookmarkStatus(convertId(_request.params.id, IdType.SharkeyId));
|
|
reply.send(await this.mastoconverter.convertStatus(data.data));
|
|
} catch (e: any) {
|
|
console.error(e);
|
|
reply.code(401).send(e.response.data);
|
|
}
|
|
});
|
|
}
|
|
|
|
public async pinStatus() {
|
|
this.fastify.post<{ Params: { id: string } }>('/v1/statuses/:id/pin', async (_request, reply) => {
|
|
const BASE_URL = `${_request.protocol}://${_request.hostname}`;
|
|
const accessTokens = _request.headers.authorization;
|
|
const client = getClient(BASE_URL, accessTokens);
|
|
try {
|
|
const data = await client.pinStatus(convertId(_request.params.id, IdType.SharkeyId));
|
|
reply.send(await this.mastoconverter.convertStatus(data.data));
|
|
} catch (e: any) {
|
|
console.error(e);
|
|
reply.code(401).send(e.response.data);
|
|
}
|
|
});
|
|
}
|
|
|
|
public async unpinStatus() {
|
|
this.fastify.post<{ Params: { id: string } }>('/v1/statuses/:id/unpin', async (_request, reply) => {
|
|
const BASE_URL = `${_request.protocol}://${_request.hostname}`;
|
|
const accessTokens = _request.headers.authorization;
|
|
const client = getClient(BASE_URL, accessTokens);
|
|
try {
|
|
const data = await client.unpinStatus(convertId(_request.params.id, IdType.SharkeyId));
|
|
reply.send(await this.mastoconverter.convertStatus(data.data));
|
|
} catch (e: any) {
|
|
console.error(e);
|
|
reply.code(401).send(e.response.data);
|
|
}
|
|
});
|
|
}
|
|
|
|
public async reactStatus() {
|
|
this.fastify.post<{ Params: { id: string, name: string } }>('/v1/statuses/:id/react/:name', async (_request, reply) => {
|
|
const BASE_URL = `${_request.protocol}://${_request.hostname}`;
|
|
const accessTokens = _request.headers.authorization;
|
|
const client = getClient(BASE_URL, accessTokens);
|
|
try {
|
|
const data = await client.createEmojiReaction(convertId(_request.params.id, IdType.SharkeyId), _request.params.name);
|
|
reply.send(await this.mastoconverter.convertStatus(data.data));
|
|
} catch (e: any) {
|
|
console.error(e);
|
|
reply.code(401).send(e.response.data);
|
|
}
|
|
});
|
|
}
|
|
|
|
public async unreactStatus() {
|
|
this.fastify.post<{ Params: { id: string, name: string } }>('/v1/statuses/:id/unreact/:name', async (_request, reply) => {
|
|
const BASE_URL = `${_request.protocol}://${_request.hostname}`;
|
|
const accessTokens = _request.headers.authorization;
|
|
const client = getClient(BASE_URL, accessTokens);
|
|
try {
|
|
const data = await client.deleteEmojiReaction(convertId(_request.params.id, IdType.SharkeyId), _request.params.name);
|
|
reply.send(await this.mastoconverter.convertStatus(data.data));
|
|
} catch (e: any) {
|
|
console.error(e);
|
|
reply.code(401).send(e.response.data);
|
|
}
|
|
});
|
|
}
|
|
|
|
public async deleteStatus() {
|
|
this.fastify.delete<{ Params: { id: string } }>('/v1/statuses/:id', async (_request, reply) => {
|
|
const BASE_URL = `${_request.protocol}://${_request.hostname}`;
|
|
const accessTokens = _request.headers.authorization;
|
|
const client = getClient(BASE_URL, accessTokens);
|
|
try {
|
|
const data = await client.deleteStatus(convertId(_request.params.id, IdType.SharkeyId));
|
|
reply.send(data.data);
|
|
} catch (e: any) {
|
|
console.error(e);
|
|
reply.code(401).send(e.response.data);
|
|
}
|
|
});
|
|
}
|
|
}
|