Mod: UserReactionBlockingServiceとUserBlockingServiceを統合
This commit is contained in:
parent
0301e86aff
commit
da94dbee00
|
@ -58,7 +58,6 @@ import { S3Service } from './S3Service.js';
|
||||||
import { SignupService } from './SignupService.js';
|
import { SignupService } from './SignupService.js';
|
||||||
import { WebAuthnService } from './WebAuthnService.js';
|
import { WebAuthnService } from './WebAuthnService.js';
|
||||||
import { UserBlockingService } from './UserBlockingService.js';
|
import { UserBlockingService } from './UserBlockingService.js';
|
||||||
import { UserReactionBlockingService } from './UserReactionBlockingService.js';
|
|
||||||
import { CacheService } from './CacheService.js';
|
import { CacheService } from './CacheService.js';
|
||||||
import { UserService } from './UserService.js';
|
import { UserService } from './UserService.js';
|
||||||
import { UserFollowingService } from './UserFollowingService.js';
|
import { UserFollowingService } from './UserFollowingService.js';
|
||||||
|
@ -203,7 +202,6 @@ const $S3Service: Provider = { provide: 'S3Service', useExisting: S3Service };
|
||||||
const $SignupService: Provider = { provide: 'SignupService', useExisting: SignupService };
|
const $SignupService: Provider = { provide: 'SignupService', useExisting: SignupService };
|
||||||
const $WebAuthnService: Provider = { provide: 'WebAuthnService', useExisting: WebAuthnService };
|
const $WebAuthnService: Provider = { provide: 'WebAuthnService', useExisting: WebAuthnService };
|
||||||
const $UserBlockingService: Provider = { provide: 'UserBlockingService', useExisting: UserBlockingService };
|
const $UserBlockingService: Provider = { provide: 'UserBlockingService', useExisting: UserBlockingService };
|
||||||
const $UserReactionBlockingService: Provider = { provide: 'UserReactionBlockingService', useExisting: UserReactionBlockingService };
|
|
||||||
const $CacheService: Provider = { provide: 'CacheService', useExisting: CacheService };
|
const $CacheService: Provider = { provide: 'CacheService', useExisting: CacheService };
|
||||||
const $UserService: Provider = { provide: 'UserService', useExisting: UserService };
|
const $UserService: Provider = { provide: 'UserService', useExisting: UserService };
|
||||||
const $UserFollowingService: Provider = { provide: 'UserFollowingService', useExisting: UserFollowingService };
|
const $UserFollowingService: Provider = { provide: 'UserFollowingService', useExisting: UserFollowingService };
|
||||||
|
@ -355,7 +353,6 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
|
||||||
SignupService,
|
SignupService,
|
||||||
WebAuthnService,
|
WebAuthnService,
|
||||||
UserBlockingService,
|
UserBlockingService,
|
||||||
UserReactionBlockingService,
|
|
||||||
CacheService,
|
CacheService,
|
||||||
UserService,
|
UserService,
|
||||||
UserFollowingService,
|
UserFollowingService,
|
||||||
|
@ -503,7 +500,6 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
|
||||||
$SignupService,
|
$SignupService,
|
||||||
$WebAuthnService,
|
$WebAuthnService,
|
||||||
$UserBlockingService,
|
$UserBlockingService,
|
||||||
$UserReactionBlockingService,
|
|
||||||
$CacheService,
|
$CacheService,
|
||||||
$UserService,
|
$UserService,
|
||||||
$UserFollowingService,
|
$UserFollowingService,
|
||||||
|
@ -652,7 +648,6 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
|
||||||
SignupService,
|
SignupService,
|
||||||
WebAuthnService,
|
WebAuthnService,
|
||||||
UserBlockingService,
|
UserBlockingService,
|
||||||
UserReactionBlockingService,
|
|
||||||
CacheService,
|
CacheService,
|
||||||
UserService,
|
UserService,
|
||||||
UserFollowingService,
|
UserFollowingService,
|
||||||
|
@ -799,7 +794,6 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
|
||||||
$SignupService,
|
$SignupService,
|
||||||
$WebAuthnService,
|
$WebAuthnService,
|
||||||
$UserBlockingService,
|
$UserBlockingService,
|
||||||
$UserReactionBlockingService,
|
|
||||||
$CacheService,
|
$CacheService,
|
||||||
$UserService,
|
$UserService,
|
||||||
$UserFollowingService,
|
$UserFollowingService,
|
||||||
|
|
|
@ -30,7 +30,6 @@ import { trackPromise } from '@/misc/promise-tracker.js';
|
||||||
import { isQuote, isRenote } from '@/misc/is-renote.js';
|
import { isQuote, isRenote } from '@/misc/is-renote.js';
|
||||||
import { ReactionsBufferingService } from '@/core/ReactionsBufferingService.js';
|
import { ReactionsBufferingService } from '@/core/ReactionsBufferingService.js';
|
||||||
import { PER_NOTE_REACTION_USER_PAIR_CACHE_MAX } from '@/const.js';
|
import { PER_NOTE_REACTION_USER_PAIR_CACHE_MAX } from '@/const.js';
|
||||||
import { BlockingReactionUserService } from '@/core/BlockingReactionUserService.js';
|
|
||||||
|
|
||||||
const FALLBACK = '\u2764';
|
const FALLBACK = '\u2764';
|
||||||
|
|
||||||
|
@ -92,7 +91,7 @@ export class ReactionService {
|
||||||
private userEntityService: UserEntityService,
|
private userEntityService: UserEntityService,
|
||||||
private noteEntityService: NoteEntityService,
|
private noteEntityService: NoteEntityService,
|
||||||
private userBlockingService: UserBlockingService,
|
private userBlockingService: UserBlockingService,
|
||||||
private blockingReactionUserService: BlockingReactionUserService,
|
private userReactionBlockingService: UserBlockingService,
|
||||||
private reactionsBufferingService: ReactionsBufferingService,
|
private reactionsBufferingService: ReactionsBufferingService,
|
||||||
private idService: IdService,
|
private idService: IdService,
|
||||||
private featuredService: FeaturedService,
|
private featuredService: FeaturedService,
|
||||||
|
@ -109,7 +108,7 @@ export class ReactionService {
|
||||||
// Check blocking
|
// Check blocking
|
||||||
if (note.userId !== user.id) {
|
if (note.userId !== user.id) {
|
||||||
const blocked = await this.userBlockingService.checkBlocked(note.userId, user.id);
|
const blocked = await this.userBlockingService.checkBlocked(note.userId, user.id);
|
||||||
const reactionBlocked = await this.blockingReactionUserService.checkBlocked(note.userId, user.id);
|
const reactionBlocked = await this.userReactionBlockingService.checkBlocked(note.userId, user.id);
|
||||||
if (blocked || reactionBlocked) {
|
if (blocked || reactionBlocked) {
|
||||||
throw new IdentifiableError('e70412a4-7197-4726-8e74-f3e0deb92aa7');
|
throw new IdentifiableError('e70412a4-7197-4726-8e74-f3e0deb92aa7');
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,6 @@ import { UserWebhookService } from '@/core/UserWebhookService.js';
|
||||||
import { bindThis } from '@/decorators.js';
|
import { bindThis } from '@/decorators.js';
|
||||||
import { CacheService } from '@/core/CacheService.js';
|
import { CacheService } from '@/core/CacheService.js';
|
||||||
import { UserFollowingService } from '@/core/UserFollowingService.js';
|
import { UserFollowingService } from '@/core/UserFollowingService.js';
|
||||||
import { UserReactionBlockingService } from '@/core/UserReactionBlockingService.js';
|
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class UserBlockingService implements OnModuleInit {
|
export class UserBlockingService implements OnModuleInit {
|
||||||
|
@ -50,7 +49,6 @@ export class UserBlockingService implements OnModuleInit {
|
||||||
|
|
||||||
private cacheService: CacheService,
|
private cacheService: CacheService,
|
||||||
private userEntityService: UserEntityService,
|
private userEntityService: UserEntityService,
|
||||||
private userReactionBlockingService: UserReactionBlockingService,
|
|
||||||
private idService: IdService,
|
private idService: IdService,
|
||||||
private queueService: QueueService,
|
private queueService: QueueService,
|
||||||
private globalEventService: GlobalEventService,
|
private globalEventService: GlobalEventService,
|
||||||
|
@ -93,7 +91,7 @@ export class UserBlockingService implements OnModuleInit {
|
||||||
});
|
});
|
||||||
|
|
||||||
if (blocking.blockType === MiBlockingType.Reaction) {
|
if (blocking.blockType === MiBlockingType.Reaction) {
|
||||||
await this.userReactionBlockingService.unblock(blocker, blockee);
|
await this.reactionUnblock(blocker, blockee);
|
||||||
}
|
}
|
||||||
blocking.blockType = MiBlockingType.User;
|
blocking.blockType = MiBlockingType.User;
|
||||||
await this.blockingsRepository.insert(blocking);
|
await this.blockingsRepository.insert(blocking);
|
||||||
|
@ -216,4 +214,74 @@ export class UserBlockingService implements OnModuleInit {
|
||||||
public async checkBlocked(blockerId: MiUser['id'], blockeeId: MiUser['id']): Promise<boolean> {
|
public async checkBlocked(blockerId: MiUser['id'], blockeeId: MiUser['id']): Promise<boolean> {
|
||||||
return (await this.cacheService.userBlockingCache.fetch(blockerId)).has(blockeeId);
|
return (await this.cacheService.userBlockingCache.fetch(blockerId)).has(blockeeId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@bindThis
|
||||||
|
public async reactionBlock(blocker: MiUser, blockee: MiUser, silent = false) {
|
||||||
|
const blocking = await this.blockingsRepository.findOneBy({
|
||||||
|
blockerId: blocker.id,
|
||||||
|
blockeeId: blockee.id,
|
||||||
|
}).then(blocking => {
|
||||||
|
if (blocking) {
|
||||||
|
return blocking;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
id: this.idService.gen(),
|
||||||
|
blocker,
|
||||||
|
blockerId: blocker.id,
|
||||||
|
blockee,
|
||||||
|
blockeeId: blockee.id,
|
||||||
|
blockType: MiBlockingType.Reaction,
|
||||||
|
} as MiBlocking;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (blocking.blockType === MiBlockingType.User) {
|
||||||
|
await this.unblock(blocker, blockee);
|
||||||
|
}
|
||||||
|
blocking.blockType = MiBlockingType.Reaction;
|
||||||
|
await this.blockingsRepository.insert(blocking);
|
||||||
|
|
||||||
|
this.cacheService.userReactionBlockingCache.refresh(blocker.id);
|
||||||
|
this.cacheService.userReactionBlockedCache.refresh(blockee.id);
|
||||||
|
|
||||||
|
this.globalEventService.publishInternalEvent('blockingReactionCreated', {
|
||||||
|
blockerId: blocker.id,
|
||||||
|
blockeeId: blockee.id,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
|
public async reactionUnblock(blocker: MiUser, blockee: MiUser) {
|
||||||
|
const blocking = await this.blockingsRepository.findOneBy({
|
||||||
|
blockerId: blocker.id,
|
||||||
|
blockeeId: blockee.id,
|
||||||
|
blockType: MiBlockingType.Reaction,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (blocking == null) {
|
||||||
|
this.logger.warn('Unblock requested, but the target was not blocked.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Since we already have the blocker and blockee, we do not need to fetch
|
||||||
|
// them in the query above and can just manually insert them here.
|
||||||
|
blocking.blocker = blocker;
|
||||||
|
blocking.blockee = blockee;
|
||||||
|
|
||||||
|
await this.blockingsRepository.delete(blocking.id);
|
||||||
|
|
||||||
|
this.cacheService.userReactionBlockingCache.refresh(blocker.id);
|
||||||
|
this.cacheService.userReactionBlockedCache.refresh(blockee.id);
|
||||||
|
|
||||||
|
this.globalEventService.publishInternalEvent('blockingReactionDeleted', {
|
||||||
|
blockerId: blocker.id,
|
||||||
|
blockeeId: blockee.id,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
|
public async checkReactionBlocked(blockerId: MiUser['id'], blockeeId: MiUser['id']): Promise<boolean> {
|
||||||
|
return (await this.cacheService.userReactionBlockingCache.fetch(blockerId)).has(blockeeId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,120 +0,0 @@
|
||||||
/*
|
|
||||||
* SPDX-FileCopyrightText: syuilo and misskey-project
|
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { Inject, Injectable } from '@nestjs/common';
|
|
||||||
import { ModuleRef } from '@nestjs/core';
|
|
||||||
import { IdService } from '@/core/IdService.js';
|
|
||||||
import type { MiUser } from '@/models/User.js';
|
|
||||||
import type { MiBlocking } from '@/models/Blocking.js';
|
|
||||||
import { QueueService } from '@/core/QueueService.js';
|
|
||||||
import { GlobalEventService } from '@/core/GlobalEventService.js';
|
|
||||||
import { DI } from '@/di-symbols.js';
|
|
||||||
import type { BlockingsRepository, UserListsRepository } from '@/models/_.js';
|
|
||||||
import Logger from '@/logger.js';
|
|
||||||
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
|
||||||
import { ApRendererService } from '@/core/activitypub/ApRendererService.js';
|
|
||||||
import { LoggerService } from '@/core/LoggerService.js';
|
|
||||||
import { UserWebhookService } from '@/core/UserWebhookService.js';
|
|
||||||
import { bindThis } from '@/decorators.js';
|
|
||||||
import { CacheService } from '@/core/CacheService.js';
|
|
||||||
import { UserFollowingService } from '@/core/UserFollowingService.js';
|
|
||||||
import { MiBlockingType } from '@/models/Blocking.js';
|
|
||||||
import { UserBlockingService } from '@/core/UserBlockingService.js';
|
|
||||||
|
|
||||||
@Injectable()
|
|
||||||
export class UserReactionBlockingService {
|
|
||||||
private logger: Logger;
|
|
||||||
private userFollowingService: UserFollowingService;
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
private moduleRef: ModuleRef,
|
|
||||||
|
|
||||||
@Inject(DI.blockingsRepository)
|
|
||||||
private blockingsRepository: BlockingsRepository,
|
|
||||||
|
|
||||||
@Inject(DI.userListsRepository)
|
|
||||||
private userListsRepository: UserListsRepository,
|
|
||||||
|
|
||||||
private cacheService: CacheService,
|
|
||||||
private userEntityService: UserEntityService,
|
|
||||||
private userBlockingService: UserBlockingService,
|
|
||||||
private idService: IdService,
|
|
||||||
private queueService: QueueService,
|
|
||||||
private globalEventService: GlobalEventService,
|
|
||||||
private webhookService: UserWebhookService,
|
|
||||||
private apRendererService: ApRendererService,
|
|
||||||
private loggerService: LoggerService,
|
|
||||||
) {
|
|
||||||
this.logger = this.loggerService.getLogger('user-block');
|
|
||||||
}
|
|
||||||
|
|
||||||
@bindThis
|
|
||||||
public async block(blocker: MiUser, blockee: MiUser, silent = false) {
|
|
||||||
const blocking = await this.blockingsRepository.findOneBy({
|
|
||||||
blockerId: blocker.id,
|
|
||||||
blockeeId: blockee.id,
|
|
||||||
}).then(blocking => {
|
|
||||||
if (blocking) {
|
|
||||||
return blocking;
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
id: this.idService.gen(),
|
|
||||||
blocker,
|
|
||||||
blockerId: blocker.id,
|
|
||||||
blockee,
|
|
||||||
blockeeId: blockee.id,
|
|
||||||
blockType: MiBlockingType.Reaction,
|
|
||||||
} as MiBlocking;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (blocking.blockType === MiBlockingType.User) {
|
|
||||||
await this.userBlockingService.unblock(blocker, blockee);
|
|
||||||
}
|
|
||||||
blocking.blockType = MiBlockingType.Reaction;
|
|
||||||
await this.blockingsRepository.insert(blocking);
|
|
||||||
|
|
||||||
this.cacheService.userReactionBlockingCache.refresh(blocker.id);
|
|
||||||
this.cacheService.userReactionBlockedCache.refresh(blockee.id);
|
|
||||||
|
|
||||||
this.globalEventService.publishInternalEvent('blockingReactionCreated', {
|
|
||||||
blockerId: blocker.id,
|
|
||||||
blockeeId: blockee.id,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@bindThis
|
|
||||||
public async unblock(blocker: MiUser, blockee: MiUser) {
|
|
||||||
const blocking = await this.blockingsRepository.findOneBy({
|
|
||||||
blockerId: blocker.id,
|
|
||||||
blockeeId: blockee.id,
|
|
||||||
blockType: MiBlockingType.Reaction,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (blocking == null) {
|
|
||||||
this.logger.warn('Unblock requested, but the target was not blocked.');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Since we already have the blocker and blockee, we do not need to fetch
|
|
||||||
// them in the query above and can just manually insert them here.
|
|
||||||
blocking.blocker = blocker;
|
|
||||||
blocking.blockee = blockee;
|
|
||||||
|
|
||||||
await this.blockingsRepository.delete(blocking.id);
|
|
||||||
|
|
||||||
this.cacheService.userReactionBlockingCache.refresh(blocker.id);
|
|
||||||
this.cacheService.userReactionBlockedCache.refresh(blockee.id);
|
|
||||||
|
|
||||||
this.globalEventService.publishInternalEvent('blockingReactionDeleted', {
|
|
||||||
blockerId: blocker.id,
|
|
||||||
blockeeId: blockee.id,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@bindThis
|
|
||||||
public async checkBlocked(blockerId: MiUser['id'], blockeeId: MiUser['id']): Promise<boolean> {
|
|
||||||
return (await this.cacheService.userReactionBlockingCache.fetch(blockerId)).has(blockeeId);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -11,7 +11,7 @@ import { MiBlockingType } from '@/models/_.js';
|
||||||
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import { GetterService } from '@/server/api/GetterService.js';
|
import { GetterService } from '@/server/api/GetterService.js';
|
||||||
import { UserReactionBlockingService } from '@/core/UserReactionBlockingService.js';
|
import { UserBlockingService } from '@/core/UserBlockingService.js';
|
||||||
import { ApiError } from '../../error.js';
|
import { ApiError } from '../../error.js';
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
|
@ -72,7 +72,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
|
|
||||||
private userEntityService: UserEntityService,
|
private userEntityService: UserEntityService,
|
||||||
private getterService: GetterService,
|
private getterService: GetterService,
|
||||||
private userReactionBlockingService: UserReactionBlockingService,
|
private userBlockingService: UserBlockingService,
|
||||||
) {
|
) {
|
||||||
super(meta, paramDef, async (ps, me) => {
|
super(meta, paramDef, async (ps, me) => {
|
||||||
const blocker = await this.usersRepository.findOneByOrFail({ id: me.id });
|
const blocker = await this.usersRepository.findOneByOrFail({ id: me.id });
|
||||||
|
@ -101,7 +101,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
throw new ApiError(meta.errors.alreadyBlocking);
|
throw new ApiError(meta.errors.alreadyBlocking);
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.userReactionBlockingService.block(blocker, blockee);
|
await this.userBlockingService.reactionBlock(blocker, blockee);
|
||||||
|
|
||||||
return await this.userEntityService.pack(blockee.id, blocker, {
|
return await this.userEntityService.pack(blockee.id, blocker, {
|
||||||
schema: 'UserDetailedNotMe',
|
schema: 'UserDetailedNotMe',
|
||||||
|
|
|
@ -8,9 +8,9 @@ import { Inject, Injectable } from '@nestjs/common';
|
||||||
import { Endpoint } from '@/server/api/endpoint-base.js';
|
import { Endpoint } from '@/server/api/endpoint-base.js';
|
||||||
import type { UsersRepository, BlockingsRepository, MiBlockingType } from '@/models/_.js';
|
import type { UsersRepository, BlockingsRepository, MiBlockingType } from '@/models/_.js';
|
||||||
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
||||||
import { UserReactionBlockingService } from '@/core/UserReactionBlockingService.js';
|
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import { GetterService } from '@/server/api/GetterService.js';
|
import { GetterService } from '@/server/api/GetterService.js';
|
||||||
|
import { UserBlockingService } from '@/core/UserBlockingService.js';
|
||||||
import { ApiError } from '../../error.js';
|
import { ApiError } from '../../error.js';
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
|
@ -71,7 +71,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
|
|
||||||
private userEntityService: UserEntityService,
|
private userEntityService: UserEntityService,
|
||||||
private getterService: GetterService,
|
private getterService: GetterService,
|
||||||
private userReactionBlockingService: UserReactionBlockingService,
|
private userBlockingService: UserBlockingService,
|
||||||
) {
|
) {
|
||||||
super(meta, paramDef, async (ps, me) => {
|
super(meta, paramDef, async (ps, me) => {
|
||||||
const blocker = await this.usersRepository.findOneByOrFail({ id: me.id });
|
const blocker = await this.usersRepository.findOneByOrFail({ id: me.id });
|
||||||
|
@ -101,7 +101,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete blocking
|
// Delete blocking
|
||||||
await this.userReactionBlockingService.unblock(blocker, blockee);
|
await this.userBlockingService.reactionUnblock(blocker, blockee);
|
||||||
|
|
||||||
return await this.userEntityService.pack(blockee.id, blocker, {
|
return await this.userEntityService.pack(blockee.id, blocker, {
|
||||||
schema: 'UserDetailedNotMe',
|
schema: 'UserDetailedNotMe',
|
||||||
|
|
|
@ -4515,7 +4515,8 @@ export type components = {
|
||||||
/** Format: id */
|
/** Format: id */
|
||||||
blockeeId: string;
|
blockeeId: string;
|
||||||
blockee: components['schemas']['UserDetailedNotMe'];
|
blockee: components['schemas']['UserDetailedNotMe'];
|
||||||
isReactionBlock: boolean;
|
/** @enum {string} */
|
||||||
|
blockType: 'user' | 'reaction';
|
||||||
};
|
};
|
||||||
Hashtag: {
|
Hashtag: {
|
||||||
/** @example misskey */
|
/** @example misskey */
|
||||||
|
|
Loading…
Reference in New Issue