2023-10-21 18:38:07 +09:00
|
|
|
/*
|
2024-02-12 11:37:45 +09:00
|
|
|
* SPDX-FileCopyrightText: syuilo and misskey-project
|
2023-10-21 18:38:07 +09:00
|
|
|
* SPDX-License-Identifier: AGPL-3.0-only
|
|
|
|
*/
|
|
|
|
|
|
|
|
import { Inject, Injectable, OnApplicationShutdown } from '@nestjs/common';
|
|
|
|
import * as Redis from 'ioredis';
|
|
|
|
import type { AvatarDecorationsRepository, 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';
|
|
|
|
|
|
|
|
@Injectable()
|
|
|
|
export class AvatarDecorationService implements OnApplicationShutdown {
|
|
|
|
public cache: MemorySingleCache<MiAvatarDecoration[]>;
|
|
|
|
|
|
|
|
constructor(
|
|
|
|
@Inject(DI.redisForSub)
|
|
|
|
private redisForSub: Redis.Redis,
|
|
|
|
|
|
|
|
@Inject(DI.avatarDecorationsRepository)
|
|
|
|
private avatarDecorationsRepository: AvatarDecorationsRepository,
|
|
|
|
|
|
|
|
private idService: IdService,
|
|
|
|
private moderationLogService: ModerationLogService,
|
|
|
|
private globalEventService: GlobalEventService,
|
|
|
|
) {
|
|
|
|
this.cache = new MemorySingleCache<MiAvatarDecoration[]>(1000 * 60 * 30);
|
|
|
|
|
|
|
|
this.redisForSub.on('message', this.onMessage);
|
|
|
|
}
|
|
|
|
|
|
|
|
@bindThis
|
|
|
|
private async onMessage(_: string, data: string): Promise<void> {
|
|
|
|
const obj = JSON.parse(data);
|
|
|
|
|
|
|
|
if (obj.channel === 'internal') {
|
|
|
|
const { type, body } = obj.message as GlobalEvents['internal']['payload'];
|
|
|
|
switch (type) {
|
|
|
|
case 'avatarDecorationCreated':
|
|
|
|
case 'avatarDecorationUpdated':
|
|
|
|
case 'avatarDecorationDeleted': {
|
|
|
|
this.cache.delete();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@bindThis
|
|
|
|
public async create(options: Partial<MiAvatarDecoration>, moderator?: MiUser): Promise<MiAvatarDecoration> {
|
|
|
|
const created = await this.avatarDecorationsRepository.insert({
|
|
|
|
id: this.idService.gen(),
|
|
|
|
...options,
|
|
|
|
}).then(x => this.avatarDecorationsRepository.findOneByOrFail(x.identifiers[0]));
|
|
|
|
|
|
|
|
this.globalEventService.publishInternalEvent('avatarDecorationCreated', created);
|
|
|
|
|
|
|
|
if (moderator) {
|
|
|
|
this.moderationLogService.log(moderator, 'createAvatarDecoration', {
|
|
|
|
avatarDecorationId: created.id,
|
|
|
|
avatarDecoration: created,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
return created;
|
|
|
|
}
|
|
|
|
|
|
|
|
@bindThis
|
|
|
|
public async update(id: MiAvatarDecoration['id'], params: Partial<MiAvatarDecoration>, moderator?: MiUser): Promise<void> {
|
|
|
|
const avatarDecoration = await this.avatarDecorationsRepository.findOneByOrFail({ id });
|
|
|
|
|
|
|
|
const date = new Date();
|
|
|
|
await this.avatarDecorationsRepository.update(avatarDecoration.id, {
|
|
|
|
updatedAt: date,
|
|
|
|
...params,
|
|
|
|
});
|
|
|
|
|
|
|
|
const updated = await this.avatarDecorationsRepository.findOneByOrFail({ id: avatarDecoration.id });
|
|
|
|
this.globalEventService.publishInternalEvent('avatarDecorationUpdated', updated);
|
|
|
|
|
|
|
|
if (moderator) {
|
|
|
|
this.moderationLogService.log(moderator, 'updateAvatarDecoration', {
|
|
|
|
avatarDecorationId: avatarDecoration.id,
|
|
|
|
before: avatarDecoration,
|
|
|
|
after: updated,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@bindThis
|
|
|
|
public async delete(id: MiAvatarDecoration['id'], moderator?: MiUser): Promise<void> {
|
|
|
|
const avatarDecoration = await this.avatarDecorationsRepository.findOneByOrFail({ id });
|
|
|
|
|
|
|
|
await this.avatarDecorationsRepository.delete({ id: avatarDecoration.id });
|
|
|
|
this.globalEventService.publishInternalEvent('avatarDecorationDeleted', avatarDecoration);
|
|
|
|
|
|
|
|
if (moderator) {
|
|
|
|
this.moderationLogService.log(moderator, 'deleteAvatarDecoration', {
|
|
|
|
avatarDecorationId: avatarDecoration.id,
|
|
|
|
avatarDecoration: avatarDecoration,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@bindThis
|
|
|
|
public async getAll(noCache = false): Promise<MiAvatarDecoration[]> {
|
|
|
|
if (noCache) {
|
|
|
|
this.cache.delete();
|
|
|
|
}
|
|
|
|
return this.cache.fetch(() => this.avatarDecorationsRepository.find());
|
|
|
|
}
|
|
|
|
|
|
|
|
@bindThis
|
|
|
|
public dispose(): void {
|
|
|
|
this.redisForSub.off('message', this.onMessage);
|
|
|
|
}
|
|
|
|
|
|
|
|
@bindThis
|
|
|
|
public onApplicationShutdown(signal?: string | undefined): void {
|
|
|
|
this.dispose();
|
|
|
|
}
|
|
|
|
}
|