From 1dfb013278ed14ff625757361364533f4857986b Mon Sep 17 00:00:00 2001 From: YUNOCHI Date: Mon, 25 Dec 2023 21:18:15 +0900 Subject: [PATCH] =?UTF-8?q?=EB=A6=AC=EB=AA=A8=ED=8A=B8=20=EC=9C=A0?= =?UTF-8?q?=EC=A0=80=EC=9D=98=20=EC=97=AC=EB=9F=AC=20=EC=95=84=EB=B0=94?= =?UTF-8?q?=ED=83=80=20=EC=9E=A5=EC=8B=9D=20=EC=97=B0=ED=95=A9=20=EC=A7=80?= =?UTF-8?q?=EC=9B=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/core/AvatarDecorationService.ts | 93 +++++++++++++++++++ 1 file changed, 93 insertions(+) diff --git a/packages/backend/src/core/AvatarDecorationService.ts b/packages/backend/src/core/AvatarDecorationService.ts index 21e31d79a429..aa87100c70fa 100644 --- a/packages/backend/src/core/AvatarDecorationService.ts +++ b/packages/backend/src/core/AvatarDecorationService.ts @@ -94,6 +94,99 @@ export class AvatarDecorationService implements OnApplicationShutdown { } } + @bindThis + private getProxiedUrl(url: string, mode?: 'static' | 'avatar'): string { + return appendQuery( + `${this.config.mediaProxy}/${mode ?? 'image'}.webp`, + query({ + url, + ...(mode ? { [mode]: '1' } : {}), + }), + ); + } + + @bindThis + public async remoteUserUpdate(user: MiUser) { + const userHost = user.host ?? ''; + const instance = await this.instancesRepository.findOneBy({ host: userHost }); + const userHostUrl = `https://${user.host}`; + const showUserApiUrl = `${userHostUrl}/api/users/show`; + + if (instance?.softwareName !== 'misskey' && instance?.softwareName !== 'cherrypick') { + return; + } + + const res = await this.httpRequestService.send(showUserApiUrl, { + method: 'POST', + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ "username": user.username }), + }); + + const userData: any = await res.json(); + const userAvatarDecorations = userData.avatarDecorations ?? undefined; + + if (!userAvatarDecorations || userAvatarDecorations.length === 0) { + const updates = {} as Partial; + updates.avatarDecorations = []; + await this.usersRepository.update({id: user.id}, updates); + return; + } + + const instanceHost = instance?.host; + const decorationApiUrl = `https://${instanceHost}/api/get-avatar-decorations`; + const allRes = await this.httpRequestService.send(decorationApiUrl, { + method: 'POST', + headers: {"Content-Type": "application/json"}, + body: JSON.stringify({}), + }); + const allDecorations: any = await allRes.json(); + const updates = {} as Partial; + updates.avatarDecorations = []; + for (const avatarDecoration of userAvatarDecorations) { + let name; + let description; + const avatarDecorationId = avatarDecoration.id + for (const decoration of allDecorations) { + if (decoration.id == avatarDecorationId) { + name = decoration.name; + description = decoration.description; + break; + } + } + const existingDecoration = await this.avatarDecorationsRepository.findOneBy({ + host: userHost, + remoteId: avatarDecorationId + }); + const decorationData = { + name: name, + description: description, + url: this.getProxiedUrl(avatarDecoration.url, 'static'), + remoteId: avatarDecorationId, + host: userHost, + }; + if (existingDecoration == null) { + await this.create(decorationData); + this.cacheWithRemote.delete(); + } else { + await this.update(existingDecoration.id, decorationData); + this.cacheWithRemote.delete(); + } + const findDecoration = await this.avatarDecorationsRepository.findOneBy({ + host: userHost, + remoteId: avatarDecorationId + }); + + updates.avatarDecorations.push({ + id: findDecoration?.id ?? '', + angle: avatarDecoration.angle ?? 0, + flipH: avatarDecoration.flipH ?? false, + offsetX: avatarDecoration.offsetX ?? 0, + offsetY: avatarDecoration.offsetY ?? 0, + }); + } + await this.usersRepository.update({id: user.id}, updates); + } + @bindThis public async delete(id: MiAvatarDecoration['id'], moderator?: MiUser): Promise { const avatarDecoration = await this.avatarDecorationsRepository.findOneByOrFail({ id });