diff --git a/locales/en-US.yml b/locales/en-US.yml
index ec1bae34c..09f1494ac 100644
--- a/locales/en-US.yml
+++ b/locales/en-US.yml
@@ -1202,7 +1202,7 @@ _mfm:
inlineMath: "Math (Inline)"
inlineMathDescription: "Display math formulas (KaTeX) in-line"
blockMath: "Math (Block)"
- blockMathDescription: "Display multi-line math formulas (KaTeX) in a block"
+ blockMathDescription: "Display math formulas (KaTeX) in a block"
quote: "Quote"
quoteDescription: "Displays content as a quote."
emoji: "Custom Emoji"
diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml
index 641aca938..8ae43cdb9 100644
--- a/locales/ja-JP.yml
+++ b/locales/ja-JP.yml
@@ -1083,7 +1083,7 @@ _mfm:
inlineMath: "数式(インライン)"
inlineMathDescription: "数式(KaTeX)をインラインで表示します。"
blockMath: "数式(ブロック)"
- blockMathDescription: "複数行の数式(KaTeX)をブロックで表示します。"
+ blockMathDescription: "数式(KaTeX)をブロックで表示します。"
quote: "引用"
quoteDescription: "内容が引用であることを示せます。"
emoji: "カスタム絵文字"
@@ -1124,6 +1124,7 @@ _mfm:
rotateDescription: "指定した角度で回転させます。"
plain: "プレーン"
plainDescription: "内側の構文を全て無効にします。"
+ position: 位置
_instanceTicker:
none: "表示しない"
remote: "リモートユーザーに表示"
@@ -1132,7 +1133,7 @@ _serverDisconnectedBehavior:
reload: "自動でリロード"
dialog: "ダイアログで警告"
quiet: "控えめに警告"
- nothing: "何も起こらない"
+ nothing: "何もしない"
_channel:
create: "チャンネルを作成"
edit: "チャンネルを編集"
diff --git a/locales/zh-CN.yml b/locales/zh-CN.yml
index c652b52b7..645f11f56 100644
--- a/locales/zh-CN.yml
+++ b/locales/zh-CN.yml
@@ -1009,9 +1009,9 @@ _mfm:
blockCode: "代码(块)"
blockCodeDescription: "语法高亮显示整块程序代码。"
inlineMath: "数学公式(内嵌)"
- inlineMathDescription: "显示内嵌的KaTex公式。"
+ inlineMathDescription: "显示内嵌的KaTeX公式。"
blockMath: "数学公式(块)"
- blockMathDescription: "显示整块的多行KaTex数学公式。"
+ blockMathDescription: "显示整块的KaTeX数学公式。"
quote: "引用"
quoteDescription: "可以用来表示引用的内容。"
emoji: "自定义表情符号"
diff --git a/locales/zh-TW.yml b/locales/zh-TW.yml
index eb640b7dd..c2dfd1ce0 100644
--- a/locales/zh-TW.yml
+++ b/locales/zh-TW.yml
@@ -1012,9 +1012,9 @@ _mfm:
blockCode: "程式碼(區塊)"
blockCodeDescription: "在區塊中用高亮度顯示,例如複數行的程式碼語法。"
inlineMath: "數學公式(內嵌)"
- inlineMathDescription: "顯示內嵌的KaTex數學公式。"
+ inlineMathDescription: "顯示內嵌的KaTeX數學公式。"
blockMath: "數學公式(方塊)"
- blockMathDescription: "以區塊顯示複數行的KaTex數學式。"
+ blockMathDescription: "以區塊顯示KaTeX數學式。"
quote: "引用"
quoteDescription: "可以用來表示引用的内容。"
emoji: "自訂表情符號"
diff --git a/package.json b/package.json
index 61c247ab2..78e39e69f 100644
--- a/package.json
+++ b/package.json
@@ -40,6 +40,8 @@
"@bull-board/ui": "^4.10.2",
"@napi-rs/cli": "^2.15.0",
"@tensorflow/tfjs": "^3.21.0",
+ "focus-trap": "^7.2.0",
+ "focus-trap-vue": "^4.0.1",
"js-yaml": "4.1.0",
"seedrandom": "^3.0.5"
},
diff --git a/packages/backend/src/server/activitypub.ts b/packages/backend/src/server/activitypub.ts
index 29ac726ef..d47e6f300 100644
--- a/packages/backend/src/server/activitypub.ts
+++ b/packages/backend/src/server/activitypub.ts
@@ -10,7 +10,7 @@ import { renderPerson } from "@/remote/activitypub/renderer/person.js";
import renderEmoji from "@/remote/activitypub/renderer/emoji.js";
import { inbox as processInbox } from "@/queue/index.js";
import { isSelfHost, toPuny } from "@/misc/convert-host.js";
-import { Notes, Users, Emojis, NoteReactions } from "@/models/index.js";
+import { Notes, Users, Emojis, NoteReactions, FollowRequests } from "@/models/index.js";
import type { ILocalUser, User } from "@/models/entities/user.js";
import { renderLike } from "@/remote/activitypub/renderer/like.js";
import { getUserKeypair } from "@/misc/keypair-store.js";
@@ -330,7 +330,7 @@ router.get("/likes/:like", async (ctx) => {
});
// follow
-router.get("/follows/:follower/:followee", async (ctx) => {
+router.get("/follows/:follower/:followee", async (ctx: Router.RouterContext) => {
const verify = await checkFetch(ctx.req);
if (verify !== 200) {
ctx.status = verify;
@@ -365,4 +365,47 @@ router.get("/follows/:follower/:followee", async (ctx) => {
setResponseType(ctx);
});
+// follow request
+router.get("/follows/:followRequestId", async (ctx: Router.RouterContext) => {
+ const verify = await checkFetch(ctx.req);
+ if (verify !== 200) {
+ ctx.status = verify;
+ return;
+ }
+
+ const followRequest = await FollowRequests.findOneBy({
+ id: ctx.params.followRequestId,
+ });
+
+ if (followRequest == null) {
+ ctx.status = 404;
+ return;
+ }
+
+ const [follower, followee] = await Promise.all([
+ Users.findOneBy({
+ id: followRequest.followerId,
+ host: IsNull(),
+ }),
+ Users.findOneBy({
+ id: followRequest.followeeId,
+ host: Not(IsNull()),
+ }),
+ ]);
+
+ if (follower == null || followee == null) {
+ ctx.status = 404;
+ return;
+ }
+
+ const meta = await fetchMeta();
+ if (meta.secureMode || meta.privateMode) {
+ ctx.set("Cache-Control", "private, max-age=0, must-revalidate");
+ } else {
+ ctx.set("Cache-Control", "public, max-age=180");
+ }
+ ctx.body = renderActivity(renderFollow(follower, followee));
+ setResponseType(ctx);
+});
+
export default router;
diff --git a/packages/backend/src/server/api/index.ts b/packages/backend/src/server/api/index.ts
index 06b3ea4ef..3568a27b2 100644
--- a/packages/backend/src/server/api/index.ts
+++ b/packages/backend/src/server/api/index.ts
@@ -29,6 +29,7 @@ import {
convertId,
IdConvertType as IdType,
} from "../../../native-utils/built/index.js";
+import { convertAttachment } from "./mastodon/converters.js";
// re-export native rust id conversion (function and enum)
export { IdType, convertId };
@@ -93,7 +94,7 @@ mastoFileRouter.post("/v1/media", upload.single("file"), async (ctx) => {
return;
}
const data = await client.uploadMedia(multipartData);
- ctx.body = data.data;
+ ctx.body = convertAttachment(data.data as Entity.Attachment);
} catch (e: any) {
console.error(e);
ctx.status = 401;
@@ -112,7 +113,7 @@ mastoFileRouter.post("/v2/media", upload.single("file"), async (ctx) => {
return;
}
const data = await client.uploadMedia(multipartData);
- ctx.body = data.data;
+ ctx.body = convertAttachment(data.data as Entity.Attachment);
} catch (e: any) {
console.error(e);
ctx.status = 401;
diff --git a/packages/backend/src/server/api/mastodon/ApiMastodonCompatibleService.ts b/packages/backend/src/server/api/mastodon/ApiMastodonCompatibleService.ts
index e8dfe5281..0c59b38f4 100644
--- a/packages/backend/src/server/api/mastodon/ApiMastodonCompatibleService.ts
+++ b/packages/backend/src/server/api/mastodon/ApiMastodonCompatibleService.ts
@@ -8,6 +8,8 @@ import { apiTimelineMastodon } from "./endpoints/timeline.js";
import { apiNotificationsMastodon } from "./endpoints/notifications.js";
import { apiSearchMastodon } from "./endpoints/search.js";
import { getInstance } from "./endpoints/meta.js";
+import { convertAnnouncement, convertFilter } from "./converters.js";
+import { convertId, IdType } from "../index.js";
export function getClient(
BASE_URL: string,
@@ -68,7 +70,7 @@ export function apiMastodonCompatible(router: Router): void {
const client = getClient(BASE_URL, accessTokens);
try {
const data = await client.getInstanceAnnouncements();
- ctx.body = data.data;
+ ctx.body = data.data.map(announcement => convertAnnouncement(announcement));
} catch (e: any) {
console.error(e);
ctx.status = 401;
@@ -83,7 +85,9 @@ export function apiMastodonCompatible(router: Router): void {
const accessTokens = ctx.request.headers.authorization;
const client = getClient(BASE_URL, accessTokens);
try {
- const data = await client.dismissInstanceAnnouncement(ctx.params.id);
+ const data = await client.dismissInstanceAnnouncement(
+ convertId(ctx.params.id, IdType.CalckeyId),
+ );
ctx.body = data.data;
} catch (e: any) {
console.error(e);
@@ -100,7 +104,7 @@ export function apiMastodonCompatible(router: Router): void {
// displayed without being logged in
try {
const data = await client.getFilters();
- ctx.body = data.data;
+ ctx.body = data.data.map(filter => convertFilter(filter));
} catch (e: any) {
console.error(e);
ctx.status = 401;
diff --git a/packages/backend/src/server/api/mastodon/converters.ts b/packages/backend/src/server/api/mastodon/converters.ts
new file mode 100644
index 000000000..d9a4f90ef
--- /dev/null
+++ b/packages/backend/src/server/api/mastodon/converters.ts
@@ -0,0 +1,44 @@
+import { Entity } from "@calckey/megalodon";
+import { convertId, IdType } from "../index.js";
+
+function simpleConvert(data: any) {
+ data.id = convertId(data.id, IdType.MastodonId);
+ return data;
+}
+
+export function convertAccount(account: Entity.Account) { return simpleConvert(account); }
+export function convertAnnouncement(announcement: Entity.Announcement) { return simpleConvert(announcement); }
+export function convertAttachment(attachment: Entity.Attachment) { return simpleConvert(attachment); }
+export function convertFilter(filter: Entity.Filter) { return simpleConvert(filter); }
+export function convertList(list: Entity.List) { return simpleConvert(list); }
+
+export function convertNotification(notification: Entity.Notification) {
+ notification.account = convertAccount(notification.account);
+ notification.id = convertId(notification.id, IdType.MastodonId);
+ if (notification.status)
+ notification.status = convertStatus(notification.status);
+ return notification;
+}
+
+export function convertPoll(poll: Entity.Poll) { return simpleConvert(poll); }
+export function convertRelationship(relationship: Entity.Relationship) { return simpleConvert(relationship); }
+
+export function convertStatus(status: Entity.Status) {
+ status.account = convertAccount(status.account);
+ status.id = convertId(status.id, IdType.MastodonId);
+ if (status.in_reply_to_account_id)
+ status.in_reply_to_account_id = convertId(status.in_reply_to_account_id, IdType.MastodonId);
+ if (status.in_reply_to_id)
+ status.in_reply_to_id = convertId(status.in_reply_to_id, IdType.MastodonId);
+ status.media_attachments = status.media_attachments.map(attachment => convertAttachment(attachment));
+ status.mentions = status.mentions.map(mention => ({
+ ...mention,
+ id: convertId(mention.id, IdType.MastodonId),
+ }));
+ if (status.poll)
+ status.poll = convertPoll(status.poll);
+ if (status.reblog)
+ status.reblog = convertStatus(status.reblog);
+
+ return status;
+}
diff --git a/packages/backend/src/server/api/mastodon/endpoints/account.ts b/packages/backend/src/server/api/mastodon/endpoints/account.ts
index 749058193..2984c20e3 100644
--- a/packages/backend/src/server/api/mastodon/endpoints/account.ts
+++ b/packages/backend/src/server/api/mastodon/endpoints/account.ts
@@ -3,8 +3,9 @@ import { resolveUser } from "@/remote/resolve-user.js";
import Router from "@koa/router";
import { FindOptionsWhere, IsNull } from "typeorm";
import { getClient } from "../ApiMastodonCompatibleService.js";
-import { argsToBools, limitToInt } from "./timeline.js";
+import { argsToBools, convertTimelinesArgsId, limitToInt } from "./timeline.js";
import { convertId, IdType } from "../../index.js";
+import { convertAccount, convertList, convertRelationship, convertStatus } from "../converters.js";
const relationshipModel = {
id: "",
@@ -62,9 +63,7 @@ export function apiAccountMastodon(router: Router): void {
const data = await client.updateCredentials(
(ctx.request as any).body as any,
);
- let resp = data.data;
- resp.id = convertId(resp.id, IdType.MastodonId);
- ctx.body = resp;
+ ctx.body = convertAccount(data.data);
} catch (e: any) {
console.error(e);
console.error(e.response.data);
@@ -81,9 +80,7 @@ export function apiAccountMastodon(router: Router): void {
(ctx.request.query as any).acct,
"accounts",
);
- let resp = data.data.accounts[0];
- resp.id = convertId(resp.id, IdType.MastodonId);
- ctx.body = resp;
+ ctx.body = convertAccount(data.data.accounts[0]);
} catch (e: any) {
console.error(e);
console.error(e.response.data);
@@ -115,11 +112,7 @@ export function apiAccountMastodon(router: Router): void {
}
const data = await client.getRelationships(reqIds);
- let resp = data.data;
- for (let acctIdx = 0; acctIdx < resp.length; acctIdx++) {
- resp[acctIdx].id = convertId(resp[acctIdx].id, IdType.MastodonId);
- }
- ctx.body = resp;
+ ctx.body = data.data.map(relationship => convertRelationship(relationship));
} catch (e: any) {
console.error(e);
let data = e.response.data;
@@ -136,9 +129,7 @@ export function apiAccountMastodon(router: Router): void {
try {
const calcId = convertId(ctx.params.id, IdType.CalckeyId);
const data = await client.getAccount(calcId);
- let resp = data.data;
- resp.id = convertId(resp.id, IdType.MastodonId);
- ctx.body = resp;
+ ctx.body = convertAccount(data.data);
} catch (e: any) {
console.error(e);
console.error(e.response.data);
@@ -155,27 +146,9 @@ export function apiAccountMastodon(router: Router): void {
try {
const data = await client.getAccountStatuses(
convertId(ctx.params.id, IdType.CalckeyId),
- argsToBools(limitToInt(ctx.query as any)),
+ convertTimelinesArgsId(argsToBools(limitToInt(ctx.query as any))),
);
- let resp = data.data;
- for (let statIdx = 0; statIdx < resp.length; statIdx++) {
- resp[statIdx].id = convertId(resp[statIdx].id, IdType.MastodonId);
- resp[statIdx].in_reply_to_account_id = resp[statIdx]
- .in_reply_to_account_id
- ? convertId(resp[statIdx].in_reply_to_account_id, IdType.MastodonId)
- : null;
- resp[statIdx].in_reply_to_id = resp[statIdx].in_reply_to_id
- ? convertId(resp[statIdx].in_reply_to_id, IdType.MastodonId)
- : null;
- let mentions = resp[statIdx].mentions;
- for (let mtnIdx = 0; mtnIdx < mentions.length; mtnIdx++) {
- resp[statIdx].mentions[mtnIdx].id = convertId(
- mentions[mtnIdx].id,
- IdType.MastodonId,
- );
- }
- }
- ctx.body = resp;
+ ctx.body = data.data.map(status => convertStatus(status));
} catch (e: any) {
console.error(e);
console.error(e.response.data);
@@ -193,13 +166,9 @@ export function apiAccountMastodon(router: Router): void {
try {
const data = await client.getAccountFollowers(
convertId(ctx.params.id, IdType.CalckeyId),
- limitToInt(ctx.query as any),
+ convertTimelinesArgsId(limitToInt(ctx.query as any)),
);
- let resp = data.data;
- for (let acctIdx = 0; acctIdx < resp.length; acctIdx++) {
- resp[acctIdx].id = convertId(resp[acctIdx].id, IdType.MastodonId);
- }
- ctx.body = resp;
+ ctx.body = data.data.map(account => convertAccount(account));
} catch (e: any) {
console.error(e);
console.error(e.response.data);
@@ -217,13 +186,9 @@ export function apiAccountMastodon(router: Router): void {
try {
const data = await client.getAccountFollowing(
convertId(ctx.params.id, IdType.CalckeyId),
- limitToInt(ctx.query as any),
+ convertTimelinesArgsId(limitToInt(ctx.query as any)),
);
- let resp = data.data;
- for (let acctIdx = 0; acctIdx < resp.length; acctIdx++) {
- resp[acctIdx].id = convertId(resp[acctIdx].id, IdType.MastodonId);
- }
- ctx.body = resp;
+ ctx.body = data.data.map(account => convertAccount(account));
} catch (e: any) {
console.error(e);
console.error(e.response.data);
@@ -239,8 +204,10 @@ export function apiAccountMastodon(router: Router): void {
const accessTokens = ctx.headers.authorization;
const client = getClient(BASE_URL, accessTokens);
try {
- const data = await client.getAccountLists(ctx.params.id);
- ctx.body = data.data;
+ const data = await client.getAccountLists(
+ convertId(ctx.params.id, IdType.CalckeyId)
+ );
+ ctx.body = data.data.map(list => convertList(list));
} catch (e: any) {
console.error(e);
console.error(e.response.data);
@@ -259,9 +226,8 @@ export function apiAccountMastodon(router: Router): void {
const data = await client.followAccount(
convertId(ctx.params.id, IdType.CalckeyId),
);
- let acct = data.data;
+ let acct = convertRelationship(data.data);
acct.following = true;
- acct.id = convertId(acct.id, IdType.MastodonId);
ctx.body = acct;
} catch (e: any) {
console.error(e);
@@ -281,8 +247,7 @@ export function apiAccountMastodon(router: Router): void {
const data = await client.unfollowAccount(
convertId(ctx.params.id, IdType.CalckeyId),
);
- let acct = data.data;
- acct.id = convertId(acct.id, IdType.MastodonId);
+ let acct = convertRelationship(data.data);
acct.following = false;
ctx.body = acct;
} catch (e: any) {
@@ -303,9 +268,7 @@ export function apiAccountMastodon(router: Router): void {
const data = await client.blockAccount(
convertId(ctx.params.id, IdType.CalckeyId),
);
- let resp = data.data;
- resp.id = convertId(resp.id, IdType.MastodonId);
- ctx.body = resp;
+ ctx.body = convertRelationship(data.data);
} catch (e: any) {
console.error(e);
console.error(e.response.data);
@@ -324,9 +287,7 @@ export function apiAccountMastodon(router: Router): void {
const data = await client.unblockAccount(
convertId(ctx.params.id, IdType.MastodonId),
);
- let resp = data.data;
- resp.id = convertId(resp.id, IdType.MastodonId);
- ctx.body = resp;
+ ctx.body = convertRelationship(data.data);
} catch (e: any) {
console.error(e);
console.error(e.response.data);
@@ -346,9 +307,7 @@ export function apiAccountMastodon(router: Router): void {
convertId(ctx.params.id, IdType.CalckeyId),
(ctx.request as any).body as any,
);
- let resp = data.data;
- resp.id = convertId(resp.id, IdType.MastodonId);
- ctx.body = resp;
+ ctx.body = convertRelationship(data.data);
} catch (e: any) {
console.error(e);
console.error(e.response.data);
@@ -367,9 +326,7 @@ export function apiAccountMastodon(router: Router): void {
const data = await client.unmuteAccount(
convertId(ctx.params.id, IdType.CalckeyId),
);
- let resp = data.data;
- resp.id = convertId(resp.id, IdType.MastodonId);
- ctx.body = resp;
+ ctx.body = convertRelationship(data.data);
} catch (e: any) {
console.error(e);
console.error(e.response.data);
@@ -384,27 +341,9 @@ export function apiAccountMastodon(router: Router): void {
const client = getClient(BASE_URL, accessTokens);
try {
const data = (await client.getBookmarks(
- limitToInt(ctx.query as any),
- )) as any;
- let resp = data.data;
- for (let statIdx = 0; statIdx < resp.length; statIdx++) {
- resp[statIdx].id = convertId(resp[statIdx].id, IdType.MastodonId);
- resp[statIdx].in_reply_to_account_id = resp[statIdx]
- .in_reply_to_account_id
- ? convertId(resp[statIdx].in_reply_to_account_id, IdType.MastodonId)
- : null;
- resp[statIdx].in_reply_to_id = resp[statIdx].in_reply_to_id
- ? convertId(resp[statIdx].in_reply_to_id, IdType.MastodonId)
- : null;
- let mentions = resp[statIdx].mentions;
- for (let mtnIdx = 0; mtnIdx < mentions.length; mtnIdx++) {
- resp[statIdx].mentions[mtnIdx].id = convertId(
- mentions[mtnIdx].id,
- IdType.MastodonId,
- );
- }
- }
- ctx.body = resp;
+ convertTimelinesArgsId(limitToInt(ctx.query as any)),
+ ));
+ ctx.body = data.data.map(status => convertStatus(status));
} catch (e: any) {
console.error(e);
console.error(e.response.data);
@@ -417,26 +356,8 @@ export function apiAccountMastodon(router: Router): void {
const accessTokens = ctx.headers.authorization;
const client = getClient(BASE_URL, accessTokens);
try {
- const data = await client.getFavourites(limitToInt(ctx.query as any));
- let resp = data.data;
- for (let statIdx = 0; statIdx < resp.length; statIdx++) {
- resp[statIdx].id = convertId(resp[statIdx].id, IdType.MastodonId);
- resp[statIdx].in_reply_to_account_id = resp[statIdx]
- .in_reply_to_account_id
- ? convertId(resp[statIdx].in_reply_to_account_id, IdType.MastodonId)
- : null;
- resp[statIdx].in_reply_to_id = resp[statIdx].in_reply_to_id
- ? convertId(resp[statIdx].in_reply_to_id, IdType.MastodonId)
- : null;
- let mentions = resp[statIdx].mentions;
- for (let mtnIdx = 0; mtnIdx < mentions.length; mtnIdx++) {
- resp[statIdx].mentions[mtnIdx].id = convertId(
- mentions[mtnIdx].id,
- IdType.MastodonId,
- );
- }
- }
- ctx.body = resp;
+ const data = await client.getFavourites(convertTimelinesArgsId(limitToInt(ctx.query as any)));
+ ctx.body = data.data.map(status => convertStatus(status));
} catch (e: any) {
console.error(e);
console.error(e.response.data);
@@ -449,12 +370,8 @@ export function apiAccountMastodon(router: Router): void {
const accessTokens = ctx.headers.authorization;
const client = getClient(BASE_URL, accessTokens);
try {
- const data = await client.getMutes(limitToInt(ctx.query as any));
- let resp = data.data;
- for (let acctIdx = 0; acctIdx < resp.length; acctIdx++) {
- resp[acctIdx].id = convertId(resp[acctIdx].id, IdType.MastodonId);
- }
- ctx.body = resp;
+ const data = await client.getMutes(convertTimelinesArgsId(limitToInt(ctx.query as any)));
+ ctx.body = data.data.map(account => convertAccount(account));
} catch (e: any) {
console.error(e);
console.error(e.response.data);
@@ -467,12 +384,8 @@ export function apiAccountMastodon(router: Router): void {
const accessTokens = ctx.headers.authorization;
const client = getClient(BASE_URL, accessTokens);
try {
- const data = await client.getBlocks(limitToInt(ctx.query as any));
- let resp = data.data;
- for (let acctIdx = 0; acctIdx < resp.length; acctIdx++) {
- resp[acctIdx].id = convertId(resp[acctIdx].id, IdType.MastodonId);
- }
- ctx.body = resp;
+ const data = await client.getBlocks(convertTimelinesArgsId(limitToInt(ctx.query as any)));
+ ctx.body = data.data.map(account => convertAccount(account));
} catch (e: any) {
console.error(e);
console.error(e.response.data);
@@ -488,11 +401,7 @@ export function apiAccountMastodon(router: Router): void {
const data = await client.getFollowRequests(
((ctx.query as any) || { limit: 20 }).limit,
);
- let resp = data.data;
- for (let acctIdx = 0; acctIdx < resp.length; acctIdx++) {
- resp[acctIdx].id = convertId(resp[acctIdx].id, IdType.MastodonId);
- }
- ctx.body = resp;
+ ctx.body = data.data.map(account => convertAccount(account));
} catch (e: any) {
console.error(e);
console.error(e.response.data);
@@ -510,9 +419,7 @@ export function apiAccountMastodon(router: Router): void {
const data = await client.acceptFollowRequest(
convertId(ctx.params.id, IdType.CalckeyId),
);
- let resp = data.data;
- resp.id = convertId(resp.id, IdType.MastodonId);
- ctx.body = resp;
+ ctx.body = convertRelationship(data.data);
} catch (e: any) {
console.error(e);
console.error(e.response.data);
@@ -531,9 +438,7 @@ export function apiAccountMastodon(router: Router): void {
const data = await client.rejectFollowRequest(
convertId(ctx.params.id, IdType.CalckeyId),
);
- let resp = data.data;
- resp.id = convertId(resp.id, IdType.MastodonId);
- ctx.body = resp;
+ ctx.body = convertRelationship(data.data);
} catch (e: any) {
console.error(e);
console.error(e.response.data);
diff --git a/packages/backend/src/server/api/mastodon/endpoints/filter.ts b/packages/backend/src/server/api/mastodon/endpoints/filter.ts
index d21bc1d33..7343fc337 100644
--- a/packages/backend/src/server/api/mastodon/endpoints/filter.ts
+++ b/packages/backend/src/server/api/mastodon/endpoints/filter.ts
@@ -1,6 +1,8 @@
import megalodon, { MegalodonInterface } from "@calckey/megalodon";
import Router from "@koa/router";
import { getClient } from "../ApiMastodonCompatibleService.js";
+import { IdType, convertId } from "../../index.js";
+import { convertFilter } from "../converters.js";
export function apiFilterMastodon(router: Router): void {
router.get("/v1/filters", async (ctx) => {
@@ -10,7 +12,7 @@ export function apiFilterMastodon(router: Router): void {
const body: any = ctx.request.body;
try {
const data = await client.getFilters();
- ctx.body = data.data;
+ ctx.body = data.data.map(filter => convertFilter(filter));
} catch (e: any) {
console.error(e);
ctx.status = 401;
@@ -24,8 +26,10 @@ export function apiFilterMastodon(router: Router): void {
const client = getClient(BASE_URL, accessTokens);
const body: any = ctx.request.body;
try {
- const data = await client.getFilter(ctx.params.id);
- ctx.body = data.data;
+ const data = await client.getFilter(
+ convertId(ctx.params.id, IdType.CalckeyId)
+ );
+ ctx.body = convertFilter(data.data);
} catch (e: any) {
console.error(e);
ctx.status = 401;
@@ -40,7 +44,7 @@ export function apiFilterMastodon(router: Router): void {
const body: any = ctx.request.body;
try {
const data = await client.createFilter(body.phrase, body.context, body);
- ctx.body = data.data;
+ ctx.body = convertFilter(data.data);
} catch (e: any) {
console.error(e);
ctx.status = 401;
@@ -55,11 +59,11 @@ export function apiFilterMastodon(router: Router): void {
const body: any = ctx.request.body;
try {
const data = await client.updateFilter(
- ctx.params.id,
+ convertId(ctx.params.id, IdType.CalckeyId),
body.phrase,
body.context,
);
- ctx.body = data.data;
+ ctx.body = convertFilter(data.data);
} catch (e: any) {
console.error(e);
ctx.status = 401;
@@ -73,7 +77,9 @@ export function apiFilterMastodon(router: Router): void {
const client = getClient(BASE_URL, accessTokens);
const body: any = ctx.request.body;
try {
- const data = await client.deleteFilter(ctx.params.id);
+ const data = await client.deleteFilter(
+ convertId(ctx.params.id, IdType.CalckeyId)
+ );
ctx.body = data.data;
} catch (e: any) {
console.error(e);
diff --git a/packages/backend/src/server/api/mastodon/endpoints/notifications.ts b/packages/backend/src/server/api/mastodon/endpoints/notifications.ts
index 8508f1d48..868377b78 100644
--- a/packages/backend/src/server/api/mastodon/endpoints/notifications.ts
+++ b/packages/backend/src/server/api/mastodon/endpoints/notifications.ts
@@ -1,8 +1,10 @@
import megalodon, { MegalodonInterface } from "@calckey/megalodon";
import Router from "@koa/router";
import { koaBody } from "koa-body";
+import { convertId, IdType } from "../../index.js";
import { getClient } from "../ApiMastodonCompatibleService.js";
-import { toTextWithReaction } from "./timeline.js";
+import { convertTimelinesArgsId, toTextWithReaction } from "./timeline.js";
+import { convertNotification } from "../converters.js";
function toLimitToInt(q: any) {
if (q.limit) if (typeof q.limit === "string") q.limit = parseInt(q.limit, 10);
return q;
@@ -15,9 +17,10 @@ export function apiNotificationsMastodon(router: Router): void {
const client = getClient(BASE_URL, accessTokens);
const body: any = ctx.request.body;
try {
- const data = await client.getNotifications(toLimitToInt(ctx.query));
+ const data = await client.getNotifications(convertTimelinesArgsId(toLimitToInt(ctx.query)));
const notfs = data.data;
const ret = notfs.map((n) => {
+ n = convertNotification(n);
if (n.type !== "follow" && n.type !== "follow_request") {
if (n.type === "reaction") n.type = "favourite";
n.status = toTextWithReaction(
@@ -43,8 +46,10 @@ export function apiNotificationsMastodon(router: Router): void {
const client = getClient(BASE_URL, accessTokens);
const body: any = ctx.request.body;
try {
- const dataRaw = await client.getNotification(ctx.params.id);
- const data = dataRaw.data;
+ const dataRaw = await client.getNotification(
+ convertId(ctx.params.id, IdType.CalckeyId)
+ );
+ const data = convertNotification(dataRaw.data);
if (data.type !== "follow" && data.type !== "follow_request") {
if (data.type === "reaction") data.type = "favourite";
ctx.body = toTextWithReaction([data as any], ctx.request.hostname)[0];
@@ -79,7 +84,9 @@ export function apiNotificationsMastodon(router: Router): void {
const client = getClient(BASE_URL, accessTokens);
const body: any = ctx.request.body;
try {
- const data = await client.dismissNotification(ctx.params.id);
+ const data = await client.dismissNotification(
+ convertId(ctx.params.id, IdType.CalckeyId)
+ );
ctx.body = data.data;
} catch (e: any) {
console.error(e);
diff --git a/packages/backend/src/server/api/mastodon/endpoints/search.ts b/packages/backend/src/server/api/mastodon/endpoints/search.ts
index e4990811a..98349cfd2 100644
--- a/packages/backend/src/server/api/mastodon/endpoints/search.ts
+++ b/packages/backend/src/server/api/mastodon/endpoints/search.ts
@@ -3,7 +3,8 @@ import Router from "@koa/router";
import { getClient } from "../ApiMastodonCompatibleService.js";
import axios from "axios";
import { Converter } from "@calckey/megalodon";
-import { limitToInt } from "./timeline.js";
+import { convertTimelinesArgsId, limitToInt } from "./timeline.js";
+import { convertAccount, convertStatus } from "../converters.js";
export function apiSearchMastodon(router: Router): void {
router.get("/v1/search", async (ctx) => {
@@ -12,7 +13,7 @@ export function apiSearchMastodon(router: Router): void {
const client = getClient(BASE_URL, accessTokens);
const body: any = ctx.request.body;
try {
- const query: any = limitToInt(ctx.query);
+ const query: any = convertTimelinesArgsId(limitToInt(ctx.query));
const type = query.type || "";
const data = await client.search(query.q, type, query);
ctx.body = data.data;
@@ -27,18 +28,18 @@ export function apiSearchMastodon(router: Router): void {
const accessTokens = ctx.headers.authorization;
const client = getClient(BASE_URL, accessTokens);
try {
- const query: any = limitToInt(ctx.query);
+ const query: any = convertTimelinesArgsId(limitToInt(ctx.query));
const type = query.type;
if (type) {
const data = await client.search(query.q, type, query);
- ctx.body = data.data;
+ ctx.body = data.data.accounts.map(account => convertAccount(account));
} else {
const acct = await client.search(query.q, "accounts", query);
const stat = await client.search(query.q, "statuses", query);
const tags = await client.search(query.q, "hashtags", query);
ctx.body = {
- accounts: acct.data.accounts,
- statuses: stat.data.statuses,
+ accounts: acct.data.accounts.map(account => convertAccount(account)),
+ statuses: stat.data.statuses.map(status => convertStatus(status)),
hashtags: tags.data.hashtags,
};
}
@@ -57,7 +58,7 @@ export function apiSearchMastodon(router: Router): void {
ctx.request.hostname,
accessTokens,
);
- ctx.body = data;
+ ctx.body = data.map(status => convertStatus(status));
} catch (e: any) {
console.error(e);
ctx.status = 401;
@@ -69,12 +70,16 @@ export function apiSearchMastodon(router: Router): void {
const accessTokens = ctx.headers.authorization;
try {
const query: any = ctx.query;
- const data = await getFeaturedUser(
+ let data = await getFeaturedUser(
BASE_URL,
ctx.request.hostname,
accessTokens,
query.limit || 20,
);
+ data = data.map(suggestion => {
+ suggestion.account = convertAccount(suggestion.account);
+ return suggestion;
+ });
console.log(data);
ctx.body = data;
} catch (e: any) {
diff --git a/packages/backend/src/server/api/mastodon/endpoints/status.ts b/packages/backend/src/server/api/mastodon/endpoints/status.ts
index f7589569c..27b30d113 100644
--- a/packages/backend/src/server/api/mastodon/endpoints/status.ts
+++ b/packages/backend/src/server/api/mastodon/endpoints/status.ts
@@ -4,7 +4,9 @@ import { emojiRegexAtStartToEnd } from "@/misc/emoji-regex.js";
import axios from "axios";
import querystring from "node:querystring";
import qs from "qs";
-import { limitToInt } from "./timeline.js";
+import { convertTimelinesArgsId, limitToInt } from "./timeline.js";
+import { convertId, IdType } from "../../index.js";
+import { convertAccount, convertAttachment, convertPoll, convertStatus } from "../converters.js";
function normalizeQuery(data: any) {
const str = querystring.stringify(data);
@@ -18,6 +20,8 @@ export function apiStatusMastodon(router: Router): void {
const client = getClient(BASE_URL, accessTokens);
try {
let body: any = ctx.request.body;
+ if (body.in_reply_to_id)
+ body.in_reply_to_id = convertId(body.in_reply_to_id, IdType.CalckeyId);
if (
(!body.poll && body["poll[options][]"]) ||
(!body.media_ids && body["media_ids[]"])
@@ -54,7 +58,7 @@ export function apiStatusMastodon(router: Router): void {
body.sensitive =
typeof sensitive === "string" ? sensitive === "true" : sensitive;
const data = await client.postStatus(text, body);
- ctx.body = data.data;
+ ctx.body = convertStatus(data.data);
} catch (e: any) {
console.error(e);
ctx.status = 401;
@@ -66,8 +70,10 @@ export function apiStatusMastodon(router: Router): void {
const accessTokens = ctx.headers.authorization;
const client = getClient(BASE_URL, accessTokens);
try {
- const data = await client.getStatus(ctx.params.id);
- ctx.body = data.data;
+ const data = await client.getStatus(
+ convertId(ctx.params.id, IdType.CalckeyId),
+ );
+ ctx.body = convertStatus(data.data);
} catch (e: any) {
console.error(e);
ctx.status = 401;
@@ -79,7 +85,9 @@ export function apiStatusMastodon(router: Router): void {
const accessTokens = ctx.headers.authorization;
const client = getClient(BASE_URL, accessTokens);
try {
- const data = await client.deleteStatus(ctx.params.id);
+ const data = await client.deleteStatus(
+ convertId(ctx.params.id, IdType.CalckeyId)
+ );
ctx.body = data.data;
} catch (e: any) {
console.error(e.response.data, request.params.id);
@@ -100,10 +108,10 @@ export function apiStatusMastodon(router: Router): void {
const accessTokens = ctx.headers.authorization;
const client = getClient(BASE_URL, accessTokens);
try {
- const id = ctx.params.id;
+ const id = convertId(ctx.params.id, IdType.CalckeyId);
const data = await client.getStatusContext(
id,
- limitToInt(ctx.query as any),
+ convertTimelinesArgsId(limitToInt(ctx.query as any)),
);
const status = await client.getStatus(id);
let reqInstance = axios.create({
@@ -126,6 +134,8 @@ export function apiStatusMastodon(router: Router): void {
text,
),
);
+ data.data.ancestors = data.data.ancestors.map(status => convertStatus(status));
+ data.data.descendants = data.data.descendants.map(status => convertStatus(status));
ctx.body = data.data;
} catch (e: any) {
console.error(e);
@@ -141,8 +151,10 @@ export function apiStatusMastodon(router: Router): void {
const accessTokens = ctx.headers.authorization;
const client = getClient(BASE_URL, accessTokens);
try {
- const data = await client.getStatusRebloggedBy(ctx.params.id);
- ctx.body = data.data;
+ const data = await client.getStatusRebloggedBy(
+ convertId(ctx.params.id, IdType.CalckeyId)
+ );
+ ctx.body = data.data.map(account => convertAccount(account));
} catch (e: any) {
console.error(e);
ctx.status = 401;
@@ -165,11 +177,11 @@ export function apiStatusMastodon(router: Router): void {
const react = await getFirstReaction(BASE_URL, accessTokens);
try {
const a = (await client.createEmojiReaction(
- ctx.params.id,
+ convertId(ctx.params.id, IdType.CalckeyId),
react,
)) as any;
//const data = await client.favouriteStatus(ctx.params.id) as any;
- ctx.body = a.data;
+ ctx.body = convertStatus(a.data);
} catch (e: any) {
console.error(e);
console.error(e.response.data);
@@ -186,8 +198,11 @@ export function apiStatusMastodon(router: Router): void {
const client = getClient(BASE_URL, accessTokens);
const react = await getFirstReaction(BASE_URL, accessTokens);
try {
- const data = await client.deleteEmojiReaction(ctx.params.id, react);
- ctx.body = data.data;
+ const data = await client.deleteEmojiReaction(
+ convertId(ctx.params.id, IdType.CalckeyId),
+ react
+ );
+ ctx.body = convertStatus(data.data);
} catch (e: any) {
console.error(e);
ctx.status = 401;
@@ -203,8 +218,10 @@ export function apiStatusMastodon(router: Router): void {
const accessTokens = ctx.headers.authorization;
const client = getClient(BASE_URL, accessTokens);
try {
- const data = await client.reblogStatus(ctx.params.id);
- ctx.body = data.data;
+ const data = await client.reblogStatus(
+ convertId(ctx.params.id, IdType.CalckeyId)
+ );
+ ctx.body = convertStatus(data.data);
} catch (e: any) {
console.error(e);
ctx.status = 401;
@@ -220,8 +237,10 @@ export function apiStatusMastodon(router: Router): void {
const accessTokens = ctx.headers.authorization;
const client = getClient(BASE_URL, accessTokens);
try {
- const data = await client.unreblogStatus(ctx.params.id);
- ctx.body = data.data;
+ const data = await client.unreblogStatus(
+ convertId(ctx.params.id, IdType.CalckeyId)
+ );
+ ctx.body = convertStatus(data.data);
} catch (e: any) {
console.error(e);
ctx.status = 401;
@@ -237,8 +256,10 @@ export function apiStatusMastodon(router: Router): void {
const accessTokens = ctx.headers.authorization;
const client = getClient(BASE_URL, accessTokens);
try {
- const data = await client.bookmarkStatus(ctx.params.id);
- ctx.body = data.data;
+ const data = await client.bookmarkStatus(
+ convertId(ctx.params.id, IdType.CalckeyId)
+ );
+ ctx.body = convertStatus(data.data);
} catch (e: any) {
console.error(e);
ctx.status = 401;
@@ -254,8 +275,10 @@ export function apiStatusMastodon(router: Router): void {
const accessTokens = ctx.headers.authorization;
const client = getClient(BASE_URL, accessTokens);
try {
- const data = (await client.unbookmarkStatus(ctx.params.id)) as any;
- ctx.body = data.data;
+ const data = await client.unbookmarkStatus(
+ convertId(ctx.params.id, IdType.CalckeyId)
+ );
+ ctx.body = convertStatus(data.data);
} catch (e: any) {
console.error(e);
ctx.status = 401;
@@ -271,8 +294,10 @@ export function apiStatusMastodon(router: Router): void {
const accessTokens = ctx.headers.authorization;
const client = getClient(BASE_URL, accessTokens);
try {
- const data = await client.pinStatus(ctx.params.id);
- ctx.body = data.data;
+ const data = await client.pinStatus(
+ convertId(ctx.params.id, IdType.CalckeyId)
+ );
+ ctx.body = convertStatus(data.data);
} catch (e: any) {
console.error(e);
ctx.status = 401;
@@ -288,8 +313,10 @@ export function apiStatusMastodon(router: Router): void {
const accessTokens = ctx.headers.authorization;
const client = getClient(BASE_URL, accessTokens);
try {
- const data = await client.unpinStatus(ctx.params.id);
- ctx.body = data.data;
+ const data = await client.unpinStatus(
+ convertId(ctx.params.id, IdType.CalckeyId)
+ );
+ ctx.body = convertStatus(data.data);
} catch (e: any) {
console.error(e);
ctx.status = 401;
@@ -302,8 +329,10 @@ export function apiStatusMastodon(router: Router): void {
const accessTokens = ctx.headers.authorization;
const client = getClient(BASE_URL, accessTokens);
try {
- const data = await client.getMedia(ctx.params.id);
- ctx.body = data.data;
+ const data = await client.getMedia(
+ convertId(ctx.params.id, IdType.CalckeyId)
+ );
+ ctx.body = convertAttachment(data.data);
} catch (e: any) {
console.error(e);
ctx.status = 401;
@@ -316,10 +345,10 @@ export function apiStatusMastodon(router: Router): void {
const client = getClient(BASE_URL, accessTokens);
try {
const data = await client.updateMedia(
- ctx.params.id,
+ convertId(ctx.params.id, IdType.CalckeyId),
ctx.request.body as any,
);
- ctx.body = data.data;
+ ctx.body = convertAttachment(data.data);
} catch (e: any) {
console.error(e);
ctx.status = 401;
@@ -331,8 +360,10 @@ export function apiStatusMastodon(router: Router): void {
const accessTokens = ctx.headers.authorization;
const client = getClient(BASE_URL, accessTokens);
try {
- const data = await client.getPoll(ctx.params.id);
- ctx.body = data.data;
+ const data = await client.getPoll(
+ convertId(ctx.params.id, IdType.CalckeyId)
+ );
+ ctx.body = convertPoll(data.data);
} catch (e: any) {
console.error(e);
ctx.status = 401;
@@ -347,10 +378,10 @@ export function apiStatusMastodon(router: Router): void {
const client = getClient(BASE_URL, accessTokens);
try {
const data = await client.votePoll(
- ctx.params.id,
+ convertId(ctx.params.id, IdType.CalckeyId),
(ctx.request.body as any).choices,
);
- ctx.body = data.data;
+ ctx.body = convertPoll(data.data);
} catch (e: any) {
console.error(e);
ctx.status = 401;
diff --git a/packages/backend/src/server/api/mastodon/endpoints/timeline.ts b/packages/backend/src/server/api/mastodon/endpoints/timeline.ts
index 57e5d9bb0..268c6a161 100644
--- a/packages/backend/src/server/api/mastodon/endpoints/timeline.ts
+++ b/packages/backend/src/server/api/mastodon/endpoints/timeline.ts
@@ -4,6 +4,8 @@ import { getClient } from "../ApiMastodonCompatibleService.js";
import { statusModel } from "./status.js";
import Autolinker from "autolinker";
import { ParsedUrlQuery } from "querystring";
+import { convertAccount, convertList, convertStatus } from "../converters.js";
+import { convertId, IdType } from "../../index.js";
export function limitToInt(q: ParsedUrlQuery) {
let object: any = q;
@@ -29,6 +31,16 @@ export function argsToBools(q: ParsedUrlQuery) {
return q;
}
+export function convertTimelinesArgsId(q: ParsedUrlQuery) {
+ if (typeof q.min_id === "string")
+ q.min_id = convertId(q.min_id, IdType.CalckeyId);
+ if (typeof q.max_id === "string")
+ q.max_id = convertId(q.max_id, IdType.CalckeyId);
+ if (typeof q.since_id === "string")
+ q.since_id = convertId(q.since_id, IdType.CalckeyId);
+ return q;
+}
+
export function toTextWithReaction(status: Entity.Status[], host: string) {
return status.map((t) => {
if (!t) return statusModel(null, null, [], "no content");
@@ -97,9 +109,10 @@ export function apiTimelineMastodon(router: Router): void {
try {
const query: any = ctx.query;
const data = query.local
- ? await client.getLocalTimeline(argsToBools(limitToInt(query)))
- : await client.getPublicTimeline(argsToBools(limitToInt(query)));
- ctx.body = toTextWithReaction(data.data, ctx.hostname);
+ ? await client.getLocalTimeline(convertTimelinesArgsId(argsToBools(limitToInt(query))))
+ : await client.getPublicTimeline(convertTimelinesArgsId(argsToBools(limitToInt(query))));
+ let resp = data.data.map(status => convertStatus(status));
+ ctx.body = toTextWithReaction(resp, ctx.hostname);
} catch (e: any) {
console.error(e);
console.error(e.response.data);
@@ -116,9 +129,10 @@ export function apiTimelineMastodon(router: Router): void {
try {
const data = await client.getTagTimeline(
ctx.params.hashtag,
- argsToBools(limitToInt(ctx.query)),
+ convertTimelinesArgsId(argsToBools(limitToInt(ctx.query))),
);
- ctx.body = toTextWithReaction(data.data, ctx.hostname);
+ let resp = data.data.map(status => convertStatus(status));
+ ctx.body = toTextWithReaction(resp, ctx.hostname);
} catch (e: any) {
console.error(e);
console.error(e.response.data);
@@ -132,8 +146,9 @@ export function apiTimelineMastodon(router: Router): void {
const accessTokens = ctx.headers.authorization;
const client = getClient(BASE_URL, accessTokens);
try {
- const data = await client.getHomeTimeline(limitToInt(ctx.query));
- ctx.body = toTextWithReaction(data.data, ctx.hostname);
+ const data = await client.getHomeTimeline(convertTimelinesArgsId(limitToInt(ctx.query)));
+ let resp = data.data.map(status => convertStatus(status));
+ ctx.body = toTextWithReaction(resp, ctx.hostname);
} catch (e: any) {
console.error(e);
console.error(e.response.data);
@@ -149,10 +164,11 @@ export function apiTimelineMastodon(router: Router): void {
const client = getClient(BASE_URL, accessTokens);
try {
const data = await client.getListTimeline(
- ctx.params.listId,
- limitToInt(ctx.query),
+ convertId(ctx.params.listId, IdType.CalckeyId),
+ convertTimelinesArgsId(limitToInt(ctx.query)),
);
- ctx.body = toTextWithReaction(data.data, ctx.hostname);
+ let resp = data.data.map(status => convertStatus(status));
+ ctx.body = toTextWithReaction(resp, ctx.hostname);
} catch (e: any) {
console.error(e);
console.error(e.response.data);
@@ -166,7 +182,7 @@ export function apiTimelineMastodon(router: Router): void {
const accessTokens = ctx.headers.authorization;
const client = getClient(BASE_URL, accessTokens);
try {
- const data = await client.getConversationTimeline(limitToInt(ctx.query));
+ const data = await client.getConversationTimeline(convertTimelinesArgsId(limitToInt(ctx.query)));
ctx.body = data.data;
} catch (e: any) {
console.error(e);
@@ -181,7 +197,7 @@ export function apiTimelineMastodon(router: Router): void {
const client = getClient(BASE_URL, accessTokens);
try {
const data = await client.getLists();
- ctx.body = data.data;
+ ctx.body = data.data.map(list => convertList(list));
} catch (e: any) {
console.error(e);
console.error(e.response.data);
@@ -196,8 +212,10 @@ export function apiTimelineMastodon(router: Router): void {
const accessTokens = ctx.headers.authorization;
const client = getClient(BASE_URL, accessTokens);
try {
- const data = await client.getList(ctx.params.id);
- ctx.body = data.data;
+ const data = await client.getList(
+ convertId(ctx.params.id, IdType.CalckeyId),
+ );
+ ctx.body = convertList(data.data);
} catch (e: any) {
console.error(e);
console.error(e.response.data);
@@ -212,7 +230,7 @@ export function apiTimelineMastodon(router: Router): void {
const client = getClient(BASE_URL, accessTokens);
try {
const data = await client.createList((ctx.request.body as any).title);
- ctx.body = data.data;
+ ctx.body = convertList(data.data);
} catch (e: any) {
console.error(e);
console.error(e.response.data);
@@ -227,8 +245,11 @@ export function apiTimelineMastodon(router: Router): void {
const accessTokens = ctx.headers.authorization;
const client = getClient(BASE_URL, accessTokens);
try {
- const data = await client.updateList(ctx.params.id, (ctx.request.body as any).title);
- ctx.body = data.data;
+ const data = await client.updateList(
+ convertId(ctx.params.id, IdType.CalckeyId),
+ (ctx.request.body as any).title
+ );
+ ctx.body = convertList(data.data);
} catch (e: any) {
console.error(e);
console.error(e.response.data);
@@ -244,7 +265,9 @@ export function apiTimelineMastodon(router: Router): void {
const accessTokens = ctx.headers.authorization;
const client = getClient(BASE_URL, accessTokens);
try {
- const data = await client.deleteList(ctx.params.id);
+ const data = await client.deleteList(
+ convertId(ctx.params.id, IdType.CalckeyId),
+ );
ctx.body = data.data;
} catch (e: any) {
console.error(e);
@@ -262,10 +285,10 @@ export function apiTimelineMastodon(router: Router): void {
const client = getClient(BASE_URL, accessTokens);
try {
const data = await client.getAccountsInList(
- ctx.params.id,
- ctx.query as any,
+ convertId(ctx.params.id, IdType.CalckeyId),
+ convertTimelinesArgsId(ctx.query as any),
);
- ctx.body = data.data;
+ ctx.body = data.data.map(account => convertAccount(account));
} catch (e: any) {
console.error(e);
console.error(e.response.data);
@@ -282,8 +305,8 @@ export function apiTimelineMastodon(router: Router): void {
const client = getClient(BASE_URL, accessTokens);
try {
const data = await client.addAccountsToList(
- ctx.params.id,
- (ctx.query as any).account_ids,
+ convertId(ctx.params.id, IdType.CalckeyId),
+ (ctx.query.account_ids as string[]).map(id => convertId(id, IdType.CalckeyId)),
);
ctx.body = data.data;
} catch (e: any) {
@@ -302,8 +325,8 @@ export function apiTimelineMastodon(router: Router): void {
const client = getClient(BASE_URL, accessTokens);
try {
const data = await client.deleteAccountsFromList(
- ctx.params.id,
- (ctx.query as any).account_ids,
+ convertId(ctx.params.id, IdType.CalckeyId),
+ (ctx.query.account_ids as string[]).map(id => convertId(id, IdType.CalckeyId)),
);
ctx.body = data.data;
} catch (e: any) {
diff --git a/packages/backend/src/services/following/requests/create.ts b/packages/backend/src/services/following/requests/create.ts
index 8b2e86ab5..27f9144d0 100644
--- a/packages/backend/src/services/following/requests/create.ts
+++ b/packages/backend/src/services/following/requests/create.ts
@@ -6,6 +6,7 @@ import type { User } from "@/models/entities/user.js";
import { Blockings, FollowRequests, Users } from "@/models/index.js";
import { genId } from "@/misc/gen-id.js";
import { createNotification } from "../../create-notification.js";
+import config from "@/config/index.js";
export default async function (
follower: {
@@ -79,7 +80,7 @@ export default async function (
}
if (Users.isLocalUser(follower) && Users.isRemoteUser(followee)) {
- const content = renderActivity(renderFollow(follower, followee));
+ const content = renderActivity(renderFollow(follower, followee, requestId ?? `${config.url}/follows/${followRequest.id}`));
deliver(follower, content, followee.inbox);
}
}
diff --git a/packages/client/package.json b/packages/client/package.json
index 49c175b15..173585503 100644
--- a/packages/client/package.json
+++ b/packages/client/package.json
@@ -32,7 +32,7 @@
"autosize": "5.0.2",
"blurhash": "1.1.5",
"broadcast-channel": "4.19.1",
- "browser-image-resizer": "https://github.com/misskey-dev/browser-image-resizer.git",
+ "browser-image-resizer": "github:misskey-dev/browser-image-resizer",
"calckey-js": "workspace:*",
"chart.js": "4.1.1",
"chartjs-adapter-date-fns": "2.0.1",
diff --git a/packages/client/src/components/MkButton.vue b/packages/client/src/components/MkButton.vue
index 5f1a5bdb7..feac281d9 100644
--- a/packages/client/src/components/MkButton.vue
+++ b/packages/client/src/components/MkButton.vue
@@ -195,8 +195,7 @@ function onMousedown(evt: MouseEvent): void {
}
&:focus-visible {
- outline: solid 2px var(--focus);
- outline-offset: 2px;
+ outline: auto;
}
&.inline {
diff --git a/packages/client/src/components/MkCwButton.vue b/packages/client/src/components/MkCwButton.vue
index 35af48874..5e59853b6 100644
--- a/packages/client/src/components/MkCwButton.vue
+++ b/packages/client/src/components/MkCwButton.vue
@@ -1,5 +1,6 @@
diff --git a/packages/client/src/ui/classic.header.vue b/packages/client/src/ui/classic.header.vue
index 5c3e6b702..99a0ab098 100644
--- a/packages/client/src/ui/classic.header.vue
+++ b/packages/client/src/ui/classic.header.vue
@@ -83,6 +83,7 @@