diff --git a/packages/backend/src/server/api/endpoints/i/known-as.ts b/packages/backend/src/server/api/endpoints/i/known-as.ts index 5e86e8b955..d4d9061b30 100644 --- a/packages/backend/src/server/api/endpoints/i/known-as.ts +++ b/packages/backend/src/server/api/endpoints/i/known-as.ts @@ -1,4 +1,4 @@ -import type { User, UserDetailedNotMeOnly } from "@/models/entities/user.js"; +import type { User } from "@/models/entities/user.js"; import { Users } from "@/models/index.js"; import { resolveUser } from "@/remote/resolve-user.js"; import acceptAllFollowRequests from "@/services/following/requests/accept-all.js"; @@ -6,10 +6,9 @@ import { publishToFollowers } from "@/services/i/update.js"; import { publishMainStream } from "@/services/stream.js"; import { DAY } from "@/const.js"; import { apiLogger } from "../../logger.js"; -import { UserProfiles } from "@/models/index.js"; -import config from "@/config/index.js"; import define from "../../define.js"; import { ApiError } from "../../error.js"; +import { parse } from "@/misc/acct.js"; export const meta = { tags: ["users"], @@ -38,49 +37,57 @@ export const meta = { code: "URI_NULL", id: "bf326f31-d430-4f97-9933-5d61e4d48a23", }, + alreadyMoved: { + message: 'You have already moved your account.', + code: 'ALREADY_MOVED', + id: '56f20ec9-fd06-4fa5-841b-edd6d7d4fa31', + }, + yourself: { + message: 'You can\'t set yourself as your own alias.', + code: 'FORBIDDEN_TO_SET_YOURSELF', + id: '25c90186-4ab0-49c8-9bba-a1fa6c202ba4', + }, }, } as const; export const paramDef = { type: "object", properties: { - alsoKnownAs: { type: "string" }, + alsoKnownAs: { + type: 'array', + maxItems: 10, + uniqueItems: true, + items: { type: 'string' }, + }, }, required: ["alsoKnownAs"], } as const; export default define(meta, paramDef, async (ps, user) => { if (!ps.alsoKnownAs) throw new ApiError(meta.errors.noSuchUser); + if (user.movedToUri) throw new ApiError(meta.errors.alreadyMoved); - let unfiltered: string = ps.alsoKnownAs; - const updates = {} as Partial; + const newAka = new Set(); - if (!unfiltered) { - updates.alsoKnownAs = null; - } else { - if (unfiltered.startsWith("acct:")) unfiltered = unfiltered.substring(5); - if (unfiltered.startsWith("@")) unfiltered = unfiltered.substring(1); - if (!unfiltered.includes("@")) throw new ApiError(meta.errors.notRemote); + for (const line of ps.alsoKnownAs) { + if (!line) throw new ApiError(meta.errors.noSuchUser); + const { username, host } = parse(line); - const userAddress: string[] = unfiltered.split("@"); - const knownAs = await resolveUser(userAddress[0], userAddress[1]).catch( - (e) => { - apiLogger.warn(`failed to resolve remote user: ${e}`); - throw new ApiError(meta.errors.noSuchUser); - }, - ); + const aka = await resolveUser(username, host).catch((e) => { + apiLogger.warn(`failed to resolve remote user: ${e}`); + throw new ApiError(meta.errors.noSuchUser); + }); - const toUrl: string | null = knownAs.uri; - if (!toUrl) { - throw new ApiError(meta.errors.uriNull); - } - if (updates.alsoKnownAs == null || updates.alsoKnownAs.length === 0) { - updates.alsoKnownAs = [toUrl]; - } else { - updates.alsoKnownAs.push(toUrl); - } + if (aka.id === user.id) throw new ApiError(meta.errors.yourself); + if (!aka.uri) throw new ApiError(meta.errors.uriNull); + + newAka.add(aka.uri); } + const updates = { + alsoKnownAs: newAka.size > 0 ? Array.from(newAka) : null, + } as Partial; + await Users.update(user.id, updates); const iObj = await Users.pack(user.id, user, { diff --git a/packages/backend/src/server/api/endpoints/users/show.ts b/packages/backend/src/server/api/endpoints/users/show.ts index 49cac81fdb..bead8df0a4 100644 --- a/packages/backend/src/server/api/endpoints/users/show.ts +++ b/packages/backend/src/server/api/endpoints/users/show.ts @@ -54,7 +54,7 @@ export const paramDef = { anyOf: [ { properties: { - userId: { type: "string", format: "misskey:id" }, + userId: { type: "string" }, }, required: ["userId"], }, @@ -65,7 +65,6 @@ export const paramDef = { uniqueItems: true, items: { type: "string", - format: "misskey:id", }, }, }, @@ -95,21 +94,27 @@ export default define(meta, paramDef, async (ps, me) => { return []; } - const users = await Users.findBy( - isAdminOrModerator - ? { - id: In(ps.userIds), - } - : { - id: In(ps.userIds), - isSuspended: false, - }, - ); + const isUrl = ps.userIds[0].startsWith("http"); + let users: User[]; + if (isUrl) { + users = await Users.findBy( + isAdminOrModerator + ? { uri: In(ps.userIds) } + : { uri: In(ps.userIds), isSuspended: false }, + ); + } else { + users = await Users.findBy( + isAdminOrModerator + ? { id: In(ps.userIds) } + : { id: In(ps.userIds), isSuspended: false }, + ); + } // リクエストされた通りに並べ替え const _users: User[] = []; for (const id of ps.userIds) { - _users.push(users.find((x) => x.id === id)!); + const res = users.find((x) => (isUrl ? x.uri === id : x.id === id)); + if (res) _users.push(res); } return await Promise.all( @@ -129,7 +134,9 @@ export default define(meta, paramDef, async (ps, me) => { } else { const q: FindOptionsWhere = ps.userId != null - ? { id: ps.userId } + ? ps.userId.startsWith("http") + ? { uri: ps.userId } + : { id: ps.userId } : { usernameLower: ps.username!.toLowerCase(), host: IsNull() }; user = await Users.findOneBy(q); diff --git a/packages/client/src/pages/settings/migration.vue b/packages/client/src/pages/settings/migration.vue index 6d5b435e3b..610d1ce1fe 100644 --- a/packages/client/src/pages/settings/migration.vue +++ b/packages/client/src/pages/settings/migration.vue @@ -2,14 +2,10 @@
+ {{ i18n.ts.moveAccountDescription }} - + - {{ i18n.ts.moveAccount }} @@ -18,19 +14,15 @@ - - - - + {{ i18n.ts.moveFromDescription }} + + + - + + {{ i18n.ts.add }} + {{ i18n.ts.save }} @@ -42,17 +34,35 @@ import FormSection from "@/components/form/section.vue"; import FormInput from "@/components/form/input.vue"; import FormButton from "@/components/MkButton.vue"; +import FormInfo from "@/components/MkInfo.vue"; import * as os from "@/os"; import { i18n } from "@/i18n"; import { definePageMetadata } from "@/scripts/page-metadata"; +import { $i } from "@/account"; +import { toString } from 'calckey-js/built/acct'; let moveToAccount = $ref(""); -let accountAlias = $ref(""); +let accountAlias = $ref([""]); -async function save(account): Promise { - os.apiWithDialog("i/known-as", { - alsoKnownAs: account, +await init(); + +async function init() { + if ($i?.alsoKnownAs && $i.alsoKnownAs.length > 0) { + const aka = await os.api('users/show', { userIds: $i.alsoKnownAs }); + accountAlias = (aka && aka.length > 0) ? aka.map(user => `@${toString(user)}`) : ['']; + } +} + +async function save(): Promise { + const i = os.apiWithDialog("i/known-as", { + alsoKnownAs: accountAlias.map(e => e.trim()).filter(e => e !== ""), }); + $i.alsoKnownAs = i.alsoKnownAs; + await init(); +} + +function add(): void { + accountAlias.push(''); } async function move(account): Promise {