diff --git a/packages/backend/src/core/CustomEmojiService.ts b/packages/backend/src/core/CustomEmojiService.ts index 18b4067f6..1f0b21415 100644 --- a/packages/backend/src/core/CustomEmojiService.ts +++ b/packages/backend/src/core/CustomEmojiService.ts @@ -2,6 +2,8 @@ import { Inject, Injectable } from '@nestjs/common'; import { DataSource, In, IsNull } from 'typeorm'; import { DI } from '@/di-symbols.js'; import { IdService } from '@/core/IdService.js'; +import { EmojiEntityService } from '@/core/entities/EmojiEntityService.js'; +import { GlobalEventService } from '@/core/GlobalEventService.js'; import type { DriveFile } from '@/models/entities/DriveFile.js'; import type { Emoji } from '@/models/entities/Emoji.js'; import type { EmojisRepository } from '@/models/index.js'; @@ -17,6 +19,8 @@ export class CustomEmojiService { private emojisRepository: EmojisRepository, private idService: IdService, + private emojiEntityService: EmojiEntityService, + private globalEventService: GlobalEventService, ) { } @@ -42,6 +46,10 @@ export class CustomEmojiService { await this.db.queryResultCache!.remove(['meta_emojis']); + this.globalEventService.publishBroadcastStream('emojiAdded', { + emoji: await this.emojiEntityService.pack(emoji.id), + }); + return emoji; } } diff --git a/packages/backend/src/server/api/endpoints/admin/emoji/add-aliases-bulk.ts b/packages/backend/src/server/api/endpoints/admin/emoji/add-aliases-bulk.ts index 9b6c774f0..c683cd24c 100644 --- a/packages/backend/src/server/api/endpoints/admin/emoji/add-aliases-bulk.ts +++ b/packages/backend/src/server/api/endpoints/admin/emoji/add-aliases-bulk.ts @@ -3,6 +3,8 @@ import { DataSource, In } from 'typeorm'; import { Endpoint } from '@/server/api/endpoint-base.js'; import type { EmojisRepository } from '@/models/index.js'; import { DI } from '@/di-symbols.js'; +import { EmojiEntityService } from '@/core/entities/EmojiEntityService.js'; +import { GlobalEventService } from '@/core/GlobalEventService.js'; export const meta = { tags: ['admin'], @@ -35,6 +37,9 @@ export default class extends Endpoint { @Inject(DI.emojisRepository) private emojisRepository: EmojisRepository, + + private emojiEntityService: EmojiEntityService, + private globalEventService: GlobalEventService, ) { super(meta, paramDef, async (ps, me) => { const emojis = await this.emojisRepository.findBy({ @@ -49,6 +54,10 @@ export default class extends Endpoint { } await this.db.queryResultCache!.remove(['meta_emojis']); + + this.globalEventService.publishBroadcastStream('emojiUpdated', { + emojis: await this.emojiEntityService.packMany(ps.ids), + }); }); } } diff --git a/packages/backend/src/server/api/endpoints/admin/emoji/add.ts b/packages/backend/src/server/api/endpoints/admin/emoji/add.ts index abca1d169..1bb05c15c 100644 --- a/packages/backend/src/server/api/endpoints/admin/emoji/add.ts +++ b/packages/backend/src/server/api/endpoints/admin/emoji/add.ts @@ -2,12 +2,10 @@ import { Inject, Injectable } from '@nestjs/common'; import rndstr from 'rndstr'; import { DataSource } from 'typeorm'; import { Endpoint } from '@/server/api/endpoint-base.js'; -import type { DriveFilesRepository, EmojisRepository } from '@/models/index.js'; -import { IdService } from '@/core/IdService.js'; +import type { DriveFilesRepository } from '@/models/index.js'; import { DI } from '@/di-symbols.js'; -import { GlobalEventService } from '@/core/GlobalEventService.js'; +import { CustomEmojiService } from '@/core/CustomEmojiService.js'; import { ModerationLogService } from '@/core/ModerationLogService.js'; -import { EmojiEntityService } from '@/core/entities/EmojiEntityService.js'; import { ApiError } from '../../../error.js'; export const meta = { @@ -39,43 +37,26 @@ export const paramDef = { @Injectable() export default class extends Endpoint { constructor( - @Inject(DI.db) - private db: DataSource, - @Inject(DI.driveFilesRepository) private driveFilesRepository: DriveFilesRepository, - @Inject(DI.emojisRepository) - private emojisRepository: EmojisRepository, + private customEmojiService: CustomEmojiService, - private emojiEntityService: EmojiEntityService, - private idService: IdService, - private globalEventService: GlobalEventService, private moderationLogService: ModerationLogService, ) { super(meta, paramDef, async (ps, me) => { - const file = await this.driveFilesRepository.findOneBy({ id: ps.fileId }); + const driveFile = await this.driveFilesRepository.findOneBy({ id: ps.fileId }); - if (file == null) throw new ApiError(meta.errors.noSuchFile); + if (driveFile == null) throw new ApiError(meta.errors.noSuchFile); - const name = file.name.split('.')[0].match(/^[a-z0-9_]+$/) ? file.name.split('.')[0] : `_${rndstr('a-z0-9', 8)}_`; + const name = driveFile.name.split('.')[0].match(/^[a-z0-9_]+$/) ? driveFile.name.split('.')[0] : `_${rndstr('a-z0-9', 8)}_`; - const emoji = await this.emojisRepository.insert({ - id: this.idService.genId(), - updatedAt: new Date(), - name: name, + const emoji = await this.customEmojiService.add({ + driveFile, + name, category: null, - host: null, aliases: [], - originalUrl: file.url, - publicUrl: file.webpublicUrl ?? file.url, - type: file.webpublicType ?? file.type, - }).then(x => this.emojisRepository.findOneByOrFail(x.identifiers[0])); - - await this.db.queryResultCache!.remove(['meta_emojis']); - - this.globalEventService.publishBroadcastStream('emojiAdded', { - emoji: await this.emojiEntityService.pack(emoji.id), + host: null, }); this.moderationLogService.insertModerationLog(me, 'addEmoji', { diff --git a/packages/backend/src/server/api/endpoints/admin/emoji/delete-bulk.ts b/packages/backend/src/server/api/endpoints/admin/emoji/delete-bulk.ts index ae45105b2..0c337237d 100644 --- a/packages/backend/src/server/api/endpoints/admin/emoji/delete-bulk.ts +++ b/packages/backend/src/server/api/endpoints/admin/emoji/delete-bulk.ts @@ -4,6 +4,8 @@ import { Endpoint } from '@/server/api/endpoint-base.js'; import type { EmojisRepository } from '@/models/index.js'; import { DI } from '@/di-symbols.js'; import { ModerationLogService } from '@/core/ModerationLogService.js'; +import { EmojiEntityService } from '@/core/entities/EmojiEntityService.js'; +import { GlobalEventService } from '@/core/GlobalEventService.js'; export const meta = { tags: ['admin'], @@ -35,6 +37,8 @@ export default class extends Endpoint { private emojisRepository: EmojisRepository, private moderationLogService: ModerationLogService, + private emojiEntityService: EmojiEntityService, + private globalEventService: GlobalEventService, ) { super(meta, paramDef, async (ps, me) => { const emojis = await this.emojisRepository.findBy({ @@ -43,13 +47,15 @@ export default class extends Endpoint { for (const emoji of emojis) { await this.emojisRepository.delete(emoji.id); - await this.db.queryResultCache!.remove(['meta_emojis']); - this.moderationLogService.insertModerationLog(me, 'deleteEmoji', { emoji: emoji, }); } + + this.globalEventService.publishBroadcastStream('emojiDeleted', { + emojis: await this.emojiEntityService.packMany(emojis), + }); }); } } diff --git a/packages/backend/src/server/api/endpoints/admin/emoji/delete.ts b/packages/backend/src/server/api/endpoints/admin/emoji/delete.ts index e237d87d3..c1a60a277 100644 --- a/packages/backend/src/server/api/endpoints/admin/emoji/delete.ts +++ b/packages/backend/src/server/api/endpoints/admin/emoji/delete.ts @@ -5,6 +5,8 @@ import type { EmojisRepository } from '@/models/index.js'; import { DI } from '@/di-symbols.js'; import { ModerationLogService } from '@/core/ModerationLogService.js'; import { ApiError } from '../../../error.js'; +import { EmojiEntityService } from '@/core/entities/EmojiEntityService.js'; +import { GlobalEventService } from '@/core/GlobalEventService.js'; export const meta = { tags: ['admin'], @@ -42,6 +44,8 @@ export default class extends Endpoint { private emojisRepository: EmojisRepository, private moderationLogService: ModerationLogService, + private emojiEntityService: EmojiEntityService, + private globalEventService: GlobalEventService, ) { super(meta, paramDef, async (ps, me) => { const emoji = await this.emojisRepository.findOneBy({ id: ps.id }); @@ -52,6 +56,10 @@ export default class extends Endpoint { await this.db.queryResultCache!.remove(['meta_emojis']); + this.globalEventService.publishBroadcastStream('emojiDeleted', { + emojis: [ await this.emojiEntityService.pack(emoji) ], + }); + this.moderationLogService.insertModerationLog(me, 'deleteEmoji', { emoji: emoji, }); diff --git a/packages/backend/src/server/api/endpoints/admin/emoji/remove-aliases-bulk.ts b/packages/backend/src/server/api/endpoints/admin/emoji/remove-aliases-bulk.ts index 5fc9e024b..065965f64 100644 --- a/packages/backend/src/server/api/endpoints/admin/emoji/remove-aliases-bulk.ts +++ b/packages/backend/src/server/api/endpoints/admin/emoji/remove-aliases-bulk.ts @@ -3,6 +3,8 @@ import { DataSource, In } from 'typeorm'; import { Endpoint } from '@/server/api/endpoint-base.js'; import type { EmojisRepository } from '@/models/index.js'; import { DI } from '@/di-symbols.js'; +import { EmojiEntityService } from '@/core/entities/EmojiEntityService.js'; +import { GlobalEventService } from '@/core/GlobalEventService.js'; export const meta = { tags: ['admin'], @@ -35,6 +37,9 @@ export default class extends Endpoint { @Inject(DI.emojisRepository) private emojisRepository: EmojisRepository, + + private emojiEntityService: EmojiEntityService, + private globalEventService: GlobalEventService, ) { super(meta, paramDef, async (ps, me) => { const emojis = await this.emojisRepository.findBy({ @@ -49,6 +54,10 @@ export default class extends Endpoint { } await this.db.queryResultCache!.remove(['meta_emojis']); + + this.globalEventService.publishBroadcastStream('emojiUpdated', { + emojis: await this.emojiEntityService.packMany(ps.ids), + }); }); } } diff --git a/packages/backend/src/server/api/endpoints/admin/emoji/set-aliases-bulk.ts b/packages/backend/src/server/api/endpoints/admin/emoji/set-aliases-bulk.ts index 8b5ba8fbf..51c0f329a 100644 --- a/packages/backend/src/server/api/endpoints/admin/emoji/set-aliases-bulk.ts +++ b/packages/backend/src/server/api/endpoints/admin/emoji/set-aliases-bulk.ts @@ -3,6 +3,8 @@ import { DataSource, In } from 'typeorm'; import { Endpoint } from '@/server/api/endpoint-base.js'; import type { EmojisRepository } from '@/models/index.js'; import { DI } from '@/di-symbols.js'; +import { EmojiEntityService } from '@/core/entities/EmojiEntityService.js'; +import { GlobalEventService } from '@/core/GlobalEventService.js'; export const meta = { tags: ['admin'], @@ -35,6 +37,9 @@ export default class extends Endpoint { @Inject(DI.emojisRepository) private emojisRepository: EmojisRepository, + + private emojiEntityService: EmojiEntityService, + private globalEventService: GlobalEventService, ) { super(meta, paramDef, async (ps, me) => { await this.emojisRepository.update({ @@ -45,6 +50,10 @@ export default class extends Endpoint { }); await this.db.queryResultCache!.remove(['meta_emojis']); + + this.globalEventService.publishBroadcastStream('emojiUpdated', { + emojis: await this.emojiEntityService.packMany(ps.ids), + }); }); } } diff --git a/packages/backend/src/server/api/endpoints/admin/emoji/set-category-bulk.ts b/packages/backend/src/server/api/endpoints/admin/emoji/set-category-bulk.ts index 827b5ace7..3329cab7b 100644 --- a/packages/backend/src/server/api/endpoints/admin/emoji/set-category-bulk.ts +++ b/packages/backend/src/server/api/endpoints/admin/emoji/set-category-bulk.ts @@ -3,6 +3,8 @@ import { DataSource, In } from 'typeorm'; import { Endpoint } from '@/server/api/endpoint-base.js'; import type { EmojisRepository } from '@/models/index.js'; import { DI } from '@/di-symbols.js'; +import { EmojiEntityService } from '@/core/entities/EmojiEntityService.js'; +import { GlobalEventService } from '@/core/GlobalEventService.js'; export const meta = { tags: ['admin'], @@ -37,6 +39,9 @@ export default class extends Endpoint { @Inject(DI.emojisRepository) private emojisRepository: EmojisRepository, + + private emojiEntityService: EmojiEntityService, + private globalEventService: GlobalEventService, ) { super(meta, paramDef, async (ps, me) => { await this.emojisRepository.update({ @@ -47,6 +52,10 @@ export default class extends Endpoint { }); await this.db.queryResultCache!.remove(['meta_emojis']); + + this.globalEventService.publishBroadcastStream('emojiUpdated', { + emojis: await this.emojiEntityService.packMany(ps.ids), + }); }); } } diff --git a/packages/backend/src/server/api/endpoints/admin/emoji/update.ts b/packages/backend/src/server/api/endpoints/admin/emoji/update.ts index fb0ef1287..6c4c8d0e6 100644 --- a/packages/backend/src/server/api/endpoints/admin/emoji/update.ts +++ b/packages/backend/src/server/api/endpoints/admin/emoji/update.ts @@ -4,6 +4,8 @@ import { Endpoint } from '@/server/api/endpoint-base.js'; import type { EmojisRepository } from '@/models/index.js'; import { DI } from '@/di-symbols.js'; import { ApiError } from '../../../error.js'; +import { EmojiEntityService } from '@/core/entities/EmojiEntityService.js'; +import { GlobalEventService } from '@/core/GlobalEventService.js'; export const meta = { tags: ['admin'], @@ -48,6 +50,9 @@ export default class extends Endpoint { @Inject(DI.emojisRepository) private emojisRepository: EmojisRepository, + + private emojiEntityService: EmojiEntityService, + private globalEventService: GlobalEventService, ) { super(meta, paramDef, async (ps, me) => { const emoji = await this.emojisRepository.findOneBy({ id: ps.id }); @@ -62,6 +67,22 @@ export default class extends Endpoint { }); await this.db.queryResultCache!.remove(['meta_emojis']); + + const updated = await this.emojiEntityService.pack(emoji.id); + + if (emoji.name === ps.name) { + this.globalEventService.publishBroadcastStream('emojiUpdated', { + emojis: [ updated ], + }); + } else { + this.globalEventService.publishBroadcastStream('emojiDeleted', { + emojis: [ emoji ], + }); + + this.globalEventService.publishBroadcastStream('emojiAdded', { + emoji: updated, + }); + } }); } } diff --git a/packages/backend/src/server/api/stream/types.ts b/packages/backend/src/server/api/stream/types.ts index a442529bb..9daaa4acf 100644 --- a/packages/backend/src/server/api/stream/types.ts +++ b/packages/backend/src/server/api/stream/types.ts @@ -49,6 +49,16 @@ export interface BroadcastTypes { emojiAdded: { emoji: Packed<'Emoji'>; }; + emojiUpdated: { + emojis: Packed<'Emoji'>[]; + }; + emojiDeleted: { + emojis: { + id?: string; + name: string; + [other: string]: any; + }[]; + }; } export interface UserStreamTypes { diff --git a/packages/frontend/src/custom-emojis.ts b/packages/frontend/src/custom-emojis.ts index 57842459b..5b13176cd 100644 --- a/packages/frontend/src/custom-emojis.ts +++ b/packages/frontend/src/custom-emojis.ts @@ -2,6 +2,7 @@ import { apiGet } from './os'; import { miLocalStorage } from './local-storage'; import { shallowRef, computed, markRaw } from 'vue'; import * as Misskey from 'misskey-js'; +import { stream } from '@/stream'; const storageCache = miLocalStorage.getItem('emojis'); export const customEmojis = shallowRef(storageCache ? JSON.parse(storageCache) : []); @@ -14,7 +15,18 @@ export const customEmojiCategories = computed(() => { }); fetchCustomEmojis(); -window.setInterval(fetchCustomEmojis, 1000 * 60 * 10); + +stream.on('emojiAdded', emojiData => { + customEmojis.value = [ emojiData.emoji, ...customEmojis.value ] +}); + +stream.on('emojiUpdated', emojiData => { + customEmojis.value = customEmojis.value.map(item => emojiData.emojis.find(search => search.name === item.name) as Misskey.entities.CustomEmoji ?? item); +}); + +stream.on('emojiDeleted', emojiData => { + customEmojis.value = customEmojis.value.filter(item => !emojiData.emojis.some(search => search.name === item.name)) +}); export async function fetchCustomEmojis() { const now = Date.now(); diff --git a/packages/frontend/src/init.ts b/packages/frontend/src/init.ts index 36897545e..2432b5f6f 100644 --- a/packages/frontend/src/init.ts +++ b/packages/frontend/src/init.ts @@ -338,11 +338,6 @@ import { fetchCustomEmojis } from './custom-emojis'; } }); - stream.on('emojiAdded', emojiData => { - // TODO - //store.commit('instance/set', ); - }); - for (const plugin of ColdDeviceStorage.get('plugins').filter(p => p.active)) { import('./plugin').then(({ install }) => { install(plugin);