diff --git a/packages/backend/src/server/api/endpoints/ap/show.ts b/packages/backend/src/server/api/endpoints/ap/show.ts index 3dd168d718..c25f0a8018 100644 --- a/packages/backend/src/server/api/endpoints/ap/show.ts +++ b/packages/backend/src/server/api/endpoints/ap/show.ts @@ -10,7 +10,7 @@ import type { Note } from "@/models/entities/note.js"; import type { CacheableLocalUser, User } from "@/models/entities/user.js"; import { isActor, isPost, getApId } from "@/remote/activitypub/type.js"; import type { SchemaType } from "@/misc/schema.js"; -import { HOUR } from "@/const.js"; +import { MINUTE } from "@/const.js"; import { shouldBlockInstance } from "@/misc/should-block-instance.js"; import { updateQuestion } from "@/remote/activitypub/models/question.js"; import { populatePoll } from "@/models/repositories/note.js"; @@ -22,8 +22,8 @@ export const meta = { requireCredential: true, limit: { - duration: HOUR, - max: 30, + duration: MINUTE, + max: 10, }, errors: { diff --git a/packages/backend/src/server/api/mastodon/endpoints/search.ts b/packages/backend/src/server/api/mastodon/endpoints/search.ts index c2f828ad74..8a48175579 100644 --- a/packages/backend/src/server/api/mastodon/endpoints/search.ts +++ b/packages/backend/src/server/api/mastodon/endpoints/search.ts @@ -42,6 +42,7 @@ export function apiSearchMastodon(router: Router): void { !type || type === "hashtags" ? await client.search(query.q, "hashtags", query) : null; + ctx.body = { accounts: acct?.data?.accounts.map((account) => convertAccount(account)) ?? [], diff --git a/packages/megalodon/src/entities/poll.ts b/packages/megalodon/src/entities/poll.ts index 69706e8ae1..c4f8f4f6df 100644 --- a/packages/megalodon/src/entities/poll.ts +++ b/packages/megalodon/src/entities/poll.ts @@ -9,5 +9,6 @@ namespace Entity { votes_count: number options: Array voted: boolean + own_votes: Array } } diff --git a/packages/megalodon/src/megalodon.ts b/packages/megalodon/src/megalodon.ts index 74966ccf4b..1cd0a7db3a 100644 --- a/packages/megalodon/src/megalodon.ts +++ b/packages/megalodon/src/megalodon.ts @@ -841,7 +841,7 @@ export interface MegalodonInterface { * @param choices Array of own votes containing index for each option (starting from 0). * @return Poll */ - votePoll(id: string, choices: Array, status_id?: string | null): Promise> + votePoll(id: string, choices: Array): Promise> // ====================================== // statuses/scheduled_statuses // ====================================== diff --git a/packages/megalodon/src/misskey.ts b/packages/megalodon/src/misskey.ts index 48950f943f..f2befd31e3 100644 --- a/packages/megalodon/src/misskey.ts +++ b/packages/megalodon/src/misskey.ts @@ -1281,6 +1281,8 @@ export default class Misskey implements MegalodonInterface { status.mentions = (await this.getMentions(status.plain_content!, cache)).filter(p => p != null); for (const m of status.mentions.filter((value, index, array) => array.indexOf(value) === index)) { + if (m.acct == m.username) + status.content = status.content.replace(`@${m.acct}@${this.baseUrlToHost(this.baseUrl)}`, `@${m.acct}`); status.content = status.content.replace(`@${m.acct}`, `@${m.acct}`); } return status; @@ -1686,31 +1688,35 @@ export default class Misskey implements MegalodonInterface { // ====================================== // statuses/polls // ====================================== - public async getPoll(_id: string): Promise> { - return new Promise((_, reject) => { - const err = new NoImplementedError('misskey does not support') - reject(err) - }) + public async getPoll(id: string): Promise> { + const res = await this.getStatus(id); + if (res.data.poll == null) + throw new Error('poll not found'); + return { ...res, data: res.data.poll } } /** * POST /api/notes/polls/vote */ - public async votePoll(_id: string, choices: Array, status_id?: string | null): Promise> { - if (!status_id) { + public async votePoll(id: string, choices: Array): Promise> { + if (!id) { return new Promise((_, reject) => { - const err = new ArgumentError('status_id is required') + const err = new ArgumentError('id is required') reject(err) }) } - const params = { - noteId: status_id, - choice: choices[0] - } - await this.client.post<{}>('/api/notes/polls/vote', params) + + for (const c of choices) { + const params = { + noteId: id, + choice: +c + } + await this.client.post<{}>('/api/notes/polls/vote', params) + } + const res = await this.client .post('/api/notes/show', { - noteId: status_id + noteId: id }) .then(async res => { const note = await this.noteWithDetails(res.data, this.baseUrlToHost(this.baseUrl), this.getFreshAccountCache()) @@ -2389,6 +2395,32 @@ export default class Misskey implements MegalodonInterface { switch (type) { case 'accounts': { + if (q.startsWith("http://") || q.startsWith("https://")) { + return this.client.post('/api/ap/show', {uri: q}).then(async res => { + if (res.status != 200 || res.data.type != 'User') { + res.status = 200; + res.statusText = "OK"; + res.data = { + accounts: [], + statuses: [], + hashtags: [] + }; + + return res; + } + + const account = await this.converter.userDetail(res.data.object as MisskeyAPI.Entity.UserDetail, this.baseUrlToHost(this.baseUrl)); + + return { + ...res, + data: { + accounts: options?.max_id && options?.max_id >= account.id ? [] : [account], + statuses: [], + hashtags: [] + } + }; + }) + } let params = { query: q } @@ -2462,6 +2494,32 @@ export default class Misskey implements MegalodonInterface { })) } case 'statuses': { + if (q.startsWith("http://") || q.startsWith("https://")) { + return this.client.post('/api/ap/show', {uri: q}).then(async res => { + if (res.status != 200 || res.data.type != 'Note') { + res.status = 200; + res.statusText = "OK"; + res.data = { + accounts: [], + statuses: [], + hashtags: [] + }; + + return res; + } + + const post = await this.noteWithDetails(res.data.object as MisskeyAPI.Entity.Note, this.baseUrlToHost(this.baseUrl), accountCache); + + return { + ...res, + data: { + accounts: [], + statuses: options?.max_id && options.max_id >= post.id ? [] : [post], + hashtags: [] + } + } + }) + } let params = { query: q } diff --git a/packages/megalodon/src/misskey/api_client.ts b/packages/megalodon/src/misskey/api_client.ts index 1833f9956b..7f1409c706 100644 --- a/packages/megalodon/src/misskey/api_client.ts +++ b/packages/megalodon/src/misskey/api_client.ts @@ -161,7 +161,7 @@ namespace MisskeyAPI { followers_count: u.followersCount, following_count: u.followingCount, statuses_count: u.notesCount, - note: u.description, + note: u.description?.replace(/\n|\\n/g, '
') ?? '', url: acctUrl, avatar: u.avatarUrl, avatar_static: u.avatarUrl, @@ -275,18 +275,19 @@ namespace MisskeyAPI { } } - poll = (p: Entity.Poll): MegalodonEntity.Poll => { + poll = (p: Entity.Poll, id: string): MegalodonEntity.Poll => { const now = dayjs() const expire = dayjs(p.expiresAt) const count = p.choices.reduce((sum, choice) => sum + choice.votes, 0) return { - id: '', + id: id, expires_at: p.expiresAt, expired: now.isAfter(expire), multiple: p.multiple, votes_count: count, options: p.choices.map(c => this.choice(c)), - voted: p.choices.some(c => c.isVoted) + voted: p.choices.some(c => c.isVoted), + own_votes: p.choices.filter(c => c.isVoted).map(c => p.choices.indexOf(c)) } } @@ -318,7 +319,7 @@ namespace MisskeyAPI { mentions: [], tags: [], card: null, - poll: n.poll ? this.poll(n.poll) : null, + poll: n.poll ? this.poll(n.poll, n.id) : null, application: null, language: null, pinned: null,