Skip to content

Commit

Permalink
2024.8.0+monster1 (#10)
Browse files Browse the repository at this point in the history
* ํฐํŠธ ๋ณ€๊ฒฝ(suite, zen maru gothic)

* Relay GTL patch

* ๋ฒ„์ „๋ช…๋ช…(2024.8.0+monster)

* Support Remote Avatar Decoration view

+ fix 7891331

+ fix !avatarDecorations

* Remote Avatar ๋ฐ์ฝ”๋ ˆ์ด์…˜์šฉ ์บ์‹œ

* Avatar decoration ์—ฐํ•ฉ์— offsetX, offsetY ์ถ”๊ฐ€

* ๋ฆฌ๋ชจํŠธ ์œ ์ €์˜ ์—ฌ๋Ÿฌ ์•„๋ฐ”ํƒ€ ์žฅ์‹ ์—ฐํ•ฉ ์ง€์›

* ๋ฒ„์ „๋ช…๋ช…(2024.8.0+monster1)

---------

Co-authored-by: Yunochi <[email protected]>
Co-authored-by: caipira113 <[email protected]>
  • Loading branch information
3 people authored Aug 31, 2024
1 parent d316fc8 commit 93eccf0
Show file tree
Hide file tree
Showing 6 changed files with 149 additions and 5 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "misskey",
"version": "2024.8.0+monster",
"version": "2024.8.0+monster1",
"codename": "nasubi",
"repository": {
"type": "git",
Expand Down
13 changes: 13 additions & 0 deletions packages/backend/migration/1699432324194-remoteAvaterDecoration.js
Original file line number Diff line number Diff line change
@@ -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"`);
}
}
120 changes: 117 additions & 3 deletions packages/backend/src/core/AvatarDecorationService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,31 +5,47 @@

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';
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[]>;
public cacheWithRemote: 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); // 30s
this.cacheWithRemote = new MemorySingleCache<MiAvatarDecoration[]>(1000 * 60 * 30);

this.redisForSub.on('message', this.onMessage);
}
Expand Down Expand Up @@ -94,6 +110,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<MiUser>;
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<MiUser>;
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<void> {
const avatarDecoration = await this.avatarDecorationsRepository.findOneByOrFail({ id });
Expand All @@ -110,11 +219,16 @@ 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();
this.cacheWithRemote.delete();
}
if (!withRemote) {
return this.cache.fetch(() => this.avatarDecorationsRepository.find({ where: { host: IsNull() } }));
} else {
return this.cacheWithRemote.fetch(() => this.avatarDecorationsRepository.find());
}
return this.cache.fetch(() => this.avatarDecorationsRepository.find());
}

@bindThis
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,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, ICollection, IObject, IOrderedCollection } from '../type.js';
import { AvatarDecorationService } from '@/core/AvatarDecorationService.js';

const nameLength = 128;
const summaryLength = 2048;
Expand Down Expand Up @@ -103,6 +104,8 @@ export class ApPersonService implements OnModuleInit {
private followingsRepository: FollowingsRepository,

private roleService: RoleService,

private avatarDecorationService: AvatarDecorationService,
) {
}

Expand Down Expand Up @@ -420,6 +423,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);
Expand Down Expand Up @@ -545,6 +550,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) {
Expand Down
2 changes: 1 addition & 1 deletion packages/backend/src/core/entities/UserEntityService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -480,7 +480,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,
Expand Down
10 changes: 10 additions & 0 deletions packages/backend/src/models/AvatarDecoration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

0 comments on commit 93eccf0

Please sign in to comment.