mirror of
https://github.com/kokonect-link/cherrypick
synced 2024-11-27 14:28:53 +09:00
Support Remote Avatar Decoration view
This commit is contained in:
parent
d96dc193fe
commit
4b991190cf
@ -0,0 +1,13 @@
|
||||
export class RemoteAvaterDecoration1699432324194 {
|
||||
name = 'RemoteAvaterDecoration1699432324194'
|
||||
|
||||
async up(queryRunner) {
|
||||
queryRunner.query(`ALTER TABLE "avatar_decoration" ADD "remoteId" varchar(32)`);
|
||||
queryRunner.query(`ALTER TABLE "avatar_decoration" ADD "host" varchar(128)`);
|
||||
}
|
||||
|
||||
async down(queryRunner) {
|
||||
queryRunner.query(`ALTER TABLE "avatar_decoration" DROP COLUMN "host"`);
|
||||
queryRunner.query(`ALTER TABLE "avatar_decoration" DROP COLUMN "remoteId"`);
|
||||
}
|
||||
}
|
@ -5,7 +5,7 @@
|
||||
|
||||
import { Inject, Injectable, OnApplicationShutdown } from '@nestjs/common';
|
||||
import * as Redis from 'ioredis';
|
||||
import type { AvatarDecorationsRepository, MiAvatarDecoration, MiUser } from '@/models/_.js';
|
||||
import type { AvatarDecorationsRepository, InstancesRepository, UsersRepository, MiAvatarDecoration, MiUser } from '@/models/_.js';
|
||||
import { IdService } from '@/core/IdService.js';
|
||||
import { GlobalEventService } from '@/core/GlobalEventService.js';
|
||||
import { DI } from '@/di-symbols.js';
|
||||
@ -13,21 +13,35 @@ import { bindThis } from '@/decorators.js';
|
||||
import { MemorySingleCache } from '@/misc/cache.js';
|
||||
import type { GlobalEvents } from '@/core/GlobalEventService.js';
|
||||
import { ModerationLogService } from '@/core/ModerationLogService.js';
|
||||
import { HttpRequestService } from "@/core/HttpRequestService.js";
|
||||
import { appendQuery, query } from '@/misc/prelude/url.js';
|
||||
import type { Config } from '@/config.js';
|
||||
import {IsNull} from "typeorm";
|
||||
|
||||
@Injectable()
|
||||
export class AvatarDecorationService implements OnApplicationShutdown {
|
||||
public cache: MemorySingleCache<MiAvatarDecoration[]>;
|
||||
|
||||
constructor(
|
||||
@Inject(DI.config)
|
||||
private config: Config,
|
||||
|
||||
@Inject(DI.redisForSub)
|
||||
private redisForSub: Redis.Redis,
|
||||
|
||||
@Inject(DI.avatarDecorationsRepository)
|
||||
private avatarDecorationsRepository: AvatarDecorationsRepository,
|
||||
|
||||
@Inject(DI.instancesRepository)
|
||||
private instancesRepository: InstancesRepository,
|
||||
|
||||
@Inject(DI.usersRepository)
|
||||
private usersRepository: UsersRepository,
|
||||
|
||||
private idService: IdService,
|
||||
private moderationLogService: ModerationLogService,
|
||||
private globalEventService: GlobalEventService,
|
||||
private httpRequestService: HttpRequestService,
|
||||
) {
|
||||
this.cache = new MemorySingleCache<MiAvatarDecoration[]>(1000 * 60 * 30);
|
||||
|
||||
@ -94,6 +108,87 @@ 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 avatarDecorations = userData.avatarDecorations[0];
|
||||
|
||||
if (avatarDecorations != null) {
|
||||
const avatarDecorationId = avatarDecorations.id;
|
||||
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();
|
||||
let name;
|
||||
let description;
|
||||
|
||||
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(avatarDecorations.url, 'static'),
|
||||
remoteId: avatarDecorationId,
|
||||
host: userHost,
|
||||
};
|
||||
|
||||
if (existingDecoration == null) {
|
||||
await this.create(decorationData);
|
||||
} else {
|
||||
await this.update(existingDecoration.id, decorationData);
|
||||
}
|
||||
|
||||
const findDecoration = await this.avatarDecorationsRepository.findOneBy({ host: userHost, remoteId: avatarDecorationId });
|
||||
const updates = {} as Partial<MiUser>;
|
||||
updates.avatarDecorations = [{
|
||||
id: findDecoration?.id ?? '',
|
||||
angle: avatarDecorations.angle ?? 0,
|
||||
flipH: avatarDecorations.flipH ?? false,
|
||||
}];
|
||||
|
||||
await this.usersRepository.update({ id: user.id }, updates);
|
||||
}
|
||||
}
|
||||
|
||||
@bindThis
|
||||
public async delete(id: MiAvatarDecoration['id'], moderator?: MiUser): Promise<void> {
|
||||
const avatarDecoration = await this.avatarDecorationsRepository.findOneByOrFail({ id });
|
||||
@ -110,11 +205,15 @@ export class AvatarDecorationService implements OnApplicationShutdown {
|
||||
}
|
||||
|
||||
@bindThis
|
||||
public async getAll(noCache = false): Promise<MiAvatarDecoration[]> {
|
||||
public async getAll(noCache = false, withRemote = false): Promise<MiAvatarDecoration[]> {
|
||||
if (noCache) {
|
||||
this.cache.delete();
|
||||
}
|
||||
return this.cache.fetch(() => this.avatarDecorationsRepository.find());
|
||||
if (!withRemote) {
|
||||
return this.cache.fetch(() => this.avatarDecorationsRepository.find({ where: { host: IsNull() } }));
|
||||
} else {
|
||||
return this.cache.fetch(() => this.avatarDecorationsRepository.find());
|
||||
}
|
||||
}
|
||||
|
||||
@bindThis
|
||||
|
@ -48,6 +48,7 @@ import type { ApLoggerService } from '../ApLoggerService.js';
|
||||
// eslint-disable-next-line @typescript-eslint/consistent-type-imports
|
||||
import type { ApImageService } from './ApImageService.js';
|
||||
import type { IActor, IObject } from '../type.js';
|
||||
import { AvatarDecorationService } from '@/core/AvatarDecorationService.js';
|
||||
|
||||
const nameLength = 128;
|
||||
const summaryLength = 2048;
|
||||
@ -100,6 +101,8 @@ export class ApPersonService implements OnModuleInit {
|
||||
|
||||
@Inject(DI.followingsRepository)
|
||||
private followingsRepository: FollowingsRepository,
|
||||
|
||||
private avatarDecorationService: AvatarDecorationService,
|
||||
) {
|
||||
}
|
||||
|
||||
@ -462,6 +465,8 @@ export class ApPersonService implements OnModuleInit {
|
||||
// ハッシュタグ更新
|
||||
this.hashtagService.updateUsertags(user, tags);
|
||||
|
||||
this.avatarDecorationService.remoteUserUpdate(user);
|
||||
|
||||
//#region アバターとヘッダー画像をフェッチ
|
||||
try {
|
||||
const updates = await this.resolveAvatarAndBanner(user, person.icon, person.image);
|
||||
@ -639,6 +644,8 @@ export class ApPersonService implements OnModuleInit {
|
||||
if (moving) updates.movedAt = new Date();
|
||||
|
||||
// Update user
|
||||
const user = await this.usersRepository.findOneByOrFail({ id: exist.id });
|
||||
await this.avatarDecorationService.remoteUserUpdate(user);
|
||||
await this.usersRepository.update(exist.id, updates);
|
||||
|
||||
if (person.publicKey) {
|
||||
|
@ -394,7 +394,7 @@ export class UserEntityService implements OnModuleInit {
|
||||
host: user.host,
|
||||
avatarUrl: user.avatarUrl ?? this.getIdenticonUrl(user),
|
||||
avatarBlurhash: user.avatarBlurhash,
|
||||
avatarDecorations: user.avatarDecorations.length > 0 ? this.avatarDecorationService.getAll().then(decorations => user.avatarDecorations.filter(ud => decorations.some(d => d.id === ud.id)).map(ud => ({
|
||||
avatarDecorations: user.avatarDecorations.length > 0 ? this.avatarDecorationService.getAll(false, true).then(decorations => user.avatarDecorations.filter(ud => decorations.some(d => d.id === ud.id)).map(ud => ({
|
||||
id: ud.id,
|
||||
angle: ud.angle || undefined,
|
||||
flipH: ud.flipH || undefined,
|
||||
|
@ -36,4 +36,14 @@ export class MiAvatarDecoration {
|
||||
array: true, length: 128, default: '{}',
|
||||
})
|
||||
public roleIdsThatCanBeUsedThisDecoration: string[];
|
||||
|
||||
@Column('varchar', {
|
||||
length: 32,
|
||||
})
|
||||
public remoteId: string;
|
||||
|
||||
@Column('varchar', {
|
||||
length: 128, nullable: true
|
||||
})
|
||||
public host: string | null;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user