mirror of
https://github.com/misskey-dev/misskey.git
synced 2024-12-29 07:49:53 +01:00
Add: BlockingテーブルにisReactionBlockカラムを追加し、blocking-reaction-userエンドポイントを追加
ユーザー単位でリアクションをブロックするため、blocking-reaction-userエンドポイントを追加。 ロジックは別途実装する。
This commit is contained in:
parent
eed45c7915
commit
3dd5af3003
22 changed files with 868 additions and 15 deletions
|
@ -0,0 +1,20 @@
|
||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: syuilo and misskey-project
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
export class AddBlockingReactionUser1731898598469 {
|
||||||
|
name = 'AddBlockingReactionUser1731898598469'
|
||||||
|
|
||||||
|
async up(queryRunner) {
|
||||||
|
await queryRunner.query(`ALTER TABLE "blocking" ADD "isReactionBlock" boolean NOT NULL DEFAULT false`);
|
||||||
|
await queryRunner.query(`COMMENT ON COLUMN "blocking"."isReactionBlock" IS 'Whether the blockee is a reaction block.'`);
|
||||||
|
await queryRunner.query(`CREATE INDEX "IDX_7b0698c38d27a5554bed4858bd" ON "blocking" ("isReactionBlock") `);
|
||||||
|
}
|
||||||
|
|
||||||
|
async down(queryRunner) {
|
||||||
|
await queryRunner.query(`DELETE FROM blocking WHERE "isReactionBlock" = 'true'`); // blockingテーブルのisReactionBlockカラムがtrueの行を削除する
|
||||||
|
await queryRunner.query(`DROP INDEX "IDX_7b0698c38d27a5554bed4858bd"`);
|
||||||
|
await queryRunner.query(`ALTER TABLE "blocking" DROP COLUMN "isReactionBlock"`);
|
||||||
|
}
|
||||||
|
}
|
|
@ -24,6 +24,8 @@ export class CacheService implements OnApplicationShutdown {
|
||||||
public userMutingsCache: RedisKVCache<Set<string>>;
|
public userMutingsCache: RedisKVCache<Set<string>>;
|
||||||
public userBlockingCache: RedisKVCache<Set<string>>;
|
public userBlockingCache: RedisKVCache<Set<string>>;
|
||||||
public userBlockedCache: RedisKVCache<Set<string>>; // NOTE: 「被」Blockキャッシュ
|
public userBlockedCache: RedisKVCache<Set<string>>; // NOTE: 「被」Blockキャッシュ
|
||||||
|
public userReactionBlockingCache: RedisKVCache<Set<string>>; // NOTE: リアクションBlockキャッシュ
|
||||||
|
public userReactionBlockedCache: RedisKVCache<Set<string>>; // NOTE: 「被」リアクションBlockキャッシュ
|
||||||
public renoteMutingsCache: RedisKVCache<Set<string>>;
|
public renoteMutingsCache: RedisKVCache<Set<string>>;
|
||||||
public userFollowingsCache: RedisKVCache<Record<string, Pick<MiFollowing, 'withReplies'> | undefined>>;
|
public userFollowingsCache: RedisKVCache<Record<string, Pick<MiFollowing, 'withReplies'> | undefined>>;
|
||||||
|
|
||||||
|
@ -80,7 +82,7 @@ export class CacheService implements OnApplicationShutdown {
|
||||||
this.userBlockingCache = new RedisKVCache<Set<string>>(this.redisClient, 'userBlocking', {
|
this.userBlockingCache = new RedisKVCache<Set<string>>(this.redisClient, 'userBlocking', {
|
||||||
lifetime: 1000 * 60 * 30, // 30m
|
lifetime: 1000 * 60 * 30, // 30m
|
||||||
memoryCacheLifetime: 1000 * 60, // 1m
|
memoryCacheLifetime: 1000 * 60, // 1m
|
||||||
fetcher: (key) => this.blockingsRepository.find({ where: { blockerId: key }, select: ['blockeeId'] }).then(xs => new Set(xs.map(x => x.blockeeId))),
|
fetcher: (key) => this.blockingsRepository.find({ where: { blockerId: key, isReactionBlock: false }, select: ['blockeeId'] }).then(xs => new Set(xs.map(x => x.blockeeId))),
|
||||||
toRedisConverter: (value) => JSON.stringify(Array.from(value)),
|
toRedisConverter: (value) => JSON.stringify(Array.from(value)),
|
||||||
fromRedisConverter: (value) => new Set(JSON.parse(value)),
|
fromRedisConverter: (value) => new Set(JSON.parse(value)),
|
||||||
});
|
});
|
||||||
|
@ -88,7 +90,23 @@ export class CacheService implements OnApplicationShutdown {
|
||||||
this.userBlockedCache = new RedisKVCache<Set<string>>(this.redisClient, 'userBlocked', {
|
this.userBlockedCache = new RedisKVCache<Set<string>>(this.redisClient, 'userBlocked', {
|
||||||
lifetime: 1000 * 60 * 30, // 30m
|
lifetime: 1000 * 60 * 30, // 30m
|
||||||
memoryCacheLifetime: 1000 * 60, // 1m
|
memoryCacheLifetime: 1000 * 60, // 1m
|
||||||
fetcher: (key) => this.blockingsRepository.find({ where: { blockeeId: key }, select: ['blockerId'] }).then(xs => new Set(xs.map(x => x.blockerId))),
|
fetcher: (key) => this.blockingsRepository.find({ where: { blockeeId: key, isReactionBlock: false }, select: ['blockerId'] }).then(xs => new Set(xs.map(x => x.blockerId))),
|
||||||
|
toRedisConverter: (value) => JSON.stringify(Array.from(value)),
|
||||||
|
fromRedisConverter: (value) => new Set(JSON.parse(value)),
|
||||||
|
});
|
||||||
|
|
||||||
|
this.userReactionBlockingCache = new RedisKVCache<Set<string>>(this.redisClient, 'userReactionBlocking', {
|
||||||
|
lifetime: 1000 * 60 * 30, // 30m
|
||||||
|
memoryCacheLifetime: 1000 * 60, // 1m
|
||||||
|
fetcher: (key) => this.blockingsRepository.find({ where: { blockerId: key, isReactionBlock: true }, select: ['blockeeId'] }).then(xs => new Set(xs.map(x => x.blockeeId))),
|
||||||
|
toRedisConverter: (value) => JSON.stringify(Array.from(value)),
|
||||||
|
fromRedisConverter: (value) => new Set(JSON.parse(value)),
|
||||||
|
});
|
||||||
|
|
||||||
|
this.userReactionBlockedCache = new RedisKVCache<Set<string>>(this.redisClient, 'userReactionBlocked', {
|
||||||
|
lifetime: 1000 * 60 * 30, // 30m
|
||||||
|
memoryCacheLifetime: 1000 * 60, // 1m
|
||||||
|
fetcher: (key) => this.blockingsRepository.find({ where: { blockeeId: key, isReactionBlock: true }, select: ['blockerId'] }).then(xs => new Set(xs.map(x => x.blockerId))),
|
||||||
toRedisConverter: (value) => JSON.stringify(Array.from(value)),
|
toRedisConverter: (value) => JSON.stringify(Array.from(value)),
|
||||||
fromRedisConverter: (value) => new Set(JSON.parse(value)),
|
fromRedisConverter: (value) => new Set(JSON.parse(value)),
|
||||||
});
|
});
|
||||||
|
|
|
@ -58,6 +58,7 @@ 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';
|
||||||
|
@ -202,6 +203,7 @@ 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 };
|
||||||
|
@ -353,6 +355,7 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
|
||||||
SignupService,
|
SignupService,
|
||||||
WebAuthnService,
|
WebAuthnService,
|
||||||
UserBlockingService,
|
UserBlockingService,
|
||||||
|
UserReactionBlockingService,
|
||||||
CacheService,
|
CacheService,
|
||||||
UserService,
|
UserService,
|
||||||
UserFollowingService,
|
UserFollowingService,
|
||||||
|
@ -500,6 +503,7 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
|
||||||
$SignupService,
|
$SignupService,
|
||||||
$WebAuthnService,
|
$WebAuthnService,
|
||||||
$UserBlockingService,
|
$UserBlockingService,
|
||||||
|
$UserReactionBlockingService,
|
||||||
$CacheService,
|
$CacheService,
|
||||||
$UserService,
|
$UserService,
|
||||||
$UserFollowingService,
|
$UserFollowingService,
|
||||||
|
@ -648,6 +652,7 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
|
||||||
SignupService,
|
SignupService,
|
||||||
WebAuthnService,
|
WebAuthnService,
|
||||||
UserBlockingService,
|
UserBlockingService,
|
||||||
|
UserReactionBlockingService,
|
||||||
CacheService,
|
CacheService,
|
||||||
UserService,
|
UserService,
|
||||||
UserFollowingService,
|
UserFollowingService,
|
||||||
|
@ -794,6 +799,7 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
|
||||||
$SignupService,
|
$SignupService,
|
||||||
$WebAuthnService,
|
$WebAuthnService,
|
||||||
$UserBlockingService,
|
$UserBlockingService,
|
||||||
|
$UserReactionBlockingService,
|
||||||
$CacheService,
|
$CacheService,
|
||||||
$UserService,
|
$UserService,
|
||||||
$UserFollowingService,
|
$UserFollowingService,
|
||||||
|
|
|
@ -223,6 +223,8 @@ export interface InternalEventTypes {
|
||||||
unfollow: { followerId: MiUser['id']; followeeId: MiUser['id']; };
|
unfollow: { followerId: MiUser['id']; followeeId: MiUser['id']; };
|
||||||
blockingCreated: { blockerId: MiUser['id']; blockeeId: MiUser['id']; };
|
blockingCreated: { blockerId: MiUser['id']; blockeeId: MiUser['id']; };
|
||||||
blockingDeleted: { blockerId: MiUser['id']; blockeeId: MiUser['id']; };
|
blockingDeleted: { blockerId: MiUser['id']; blockeeId: MiUser['id']; };
|
||||||
|
blockingReactionCreated: { blockerId: MiUser['id']; blockeeId: MiUser['id']; };
|
||||||
|
blockingReactionDeleted: { blockerId: MiUser['id']; blockeeId: MiUser['id']; };
|
||||||
policiesUpdated: MiRole['policies'];
|
policiesUpdated: MiRole['policies'];
|
||||||
roleCreated: MiRole;
|
roleCreated: MiRole;
|
||||||
roleDeleted: MiRole;
|
roleDeleted: MiRole;
|
||||||
|
|
|
@ -73,6 +73,7 @@ export class UserBlockingService implements OnModuleInit {
|
||||||
blockerId: blocker.id,
|
blockerId: blocker.id,
|
||||||
blockee,
|
blockee,
|
||||||
blockeeId: blockee.id,
|
blockeeId: blockee.id,
|
||||||
|
isReactionBlock: false,
|
||||||
} as MiBlocking;
|
} as MiBlocking;
|
||||||
|
|
||||||
await this.blockingsRepository.insert(blocking);
|
await this.blockingsRepository.insert(blocking);
|
||||||
|
@ -160,6 +161,7 @@ export class UserBlockingService implements OnModuleInit {
|
||||||
const blocking = await this.blockingsRepository.findOneBy({
|
const blocking = await this.blockingsRepository.findOneBy({
|
||||||
blockerId: blocker.id,
|
blockerId: blocker.id,
|
||||||
blockeeId: blockee.id,
|
blockeeId: blockee.id,
|
||||||
|
isReactionBlock: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (blocking == null) {
|
if (blocking == null) {
|
||||||
|
@ -169,28 +171,23 @@ export class UserBlockingService implements OnModuleInit {
|
||||||
|
|
||||||
// Since we already have the blocker and blockee, we do not need to fetch
|
// 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.
|
// them in the query above and can just manually insert them here.
|
||||||
blocking.blocker = blocker;
|
// But we don't need to do this because we are not using them in this function.
|
||||||
blocking.blockee = blockee;
|
// blocking.blocker = blocker;
|
||||||
|
// blocking.blockee = blockee;
|
||||||
|
|
||||||
await this.blockingsRepository.delete(blocking.id);
|
await this.blockingsRepository.delete(blocking.id);
|
||||||
|
|
||||||
this.cacheService.userBlockingCache.refresh(blocker.id);
|
this.cacheService.userReactionBlockedCache.refresh(blocker.id);
|
||||||
this.cacheService.userBlockedCache.refresh(blockee.id);
|
this.cacheService.userReactionBlockedCache.refresh(blockee.id);
|
||||||
|
|
||||||
this.globalEventService.publishInternalEvent('blockingDeleted', {
|
this.globalEventService.publishInternalEvent('blockingReactionDeleted', {
|
||||||
blockerId: blocker.id,
|
blockerId: blocker.id,
|
||||||
blockeeId: blockee.id,
|
blockeeId: blockee.id,
|
||||||
});
|
});
|
||||||
|
|
||||||
// deliver if remote bloking
|
|
||||||
if (this.userEntityService.isLocalUser(blocker) && this.userEntityService.isRemoteUser(blockee)) {
|
|
||||||
const content = this.apRendererService.addContext(this.apRendererService.renderUndo(this.apRendererService.renderBlock(blocking), blocker));
|
|
||||||
this.queueService.deliver(blocker, content, blockee.inbox, false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
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.userReactionBlockingCache.fetch(blockerId)).has(blockeeId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
111
packages/backend/src/core/UserReactionBlockingService.ts
Normal file
111
packages/backend/src/core/UserReactionBlockingService.ts
Normal file
|
@ -0,0 +1,111 @@
|
||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: syuilo and misskey-project
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { Inject, Injectable, OnModuleInit } 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';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class UserReactionBlockingService implements OnModuleInit {
|
||||||
|
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 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 = {
|
||||||
|
id: this.idService.gen(),
|
||||||
|
blocker,
|
||||||
|
blockerId: blocker.id,
|
||||||
|
blockee,
|
||||||
|
blockeeId: blockee.id,
|
||||||
|
isReactionBlock: true,
|
||||||
|
} as MiBlocking;
|
||||||
|
|
||||||
|
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,
|
||||||
|
isReactionBlock: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (blocking == null) {
|
||||||
|
this.logger.warn('ブロック解除がリクエストされましたがブロックしていませんでした');
|
||||||
|
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.userBlockingCache.refresh(blocker.id);
|
||||||
|
this.cacheService.userBlockedCache.refresh(blockee.id);
|
||||||
|
|
||||||
|
this.globalEventService.publishInternalEvent('blockingDeleted', {
|
||||||
|
blockerId: blocker.id,
|
||||||
|
blockeeId: blockee.id,
|
||||||
|
});
|
||||||
|
|
||||||
|
// deliver if remote bloking
|
||||||
|
if (this.userEntityService.isLocalUser(blocker) && this.userEntityService.isRemoteUser(blockee)) {
|
||||||
|
const content = this.apRendererService.addContext(this.apRendererService.renderUndo(this.apRendererService.renderBlock(blocking), blocker));
|
||||||
|
this.queueService.deliver(blocker, content, blockee.inbox, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
|
public async checkBlocked(blockerId: MiUser['id'], blockeeId: MiUser['id']): Promise<boolean> {
|
||||||
|
return (await this.cacheService.userBlockingCache.fetch(blockerId)).has(blockeeId);
|
||||||
|
}
|
||||||
|
}
|
|
@ -76,6 +76,8 @@ export type UserRelation = {
|
||||||
hasPendingFollowRequestToYou: boolean
|
hasPendingFollowRequestToYou: boolean
|
||||||
isBlocking: boolean
|
isBlocking: boolean
|
||||||
isBlocked: boolean
|
isBlocked: boolean
|
||||||
|
isReactionBlocking: boolean
|
||||||
|
isReactionBlocked: boolean
|
||||||
isMuted: boolean
|
isMuted: boolean
|
||||||
isRenoteMuted: boolean
|
isRenoteMuted: boolean
|
||||||
}
|
}
|
||||||
|
@ -169,6 +171,8 @@ export class UserEntityService implements OnModuleInit {
|
||||||
hasPendingFollowRequestToYou,
|
hasPendingFollowRequestToYou,
|
||||||
isBlocking,
|
isBlocking,
|
||||||
isBlocked,
|
isBlocked,
|
||||||
|
isReactionBlocking,
|
||||||
|
isReactionBlocked,
|
||||||
isMuted,
|
isMuted,
|
||||||
isRenoteMuted,
|
isRenoteMuted,
|
||||||
] = await Promise.all([
|
] = await Promise.all([
|
||||||
|
@ -198,12 +202,28 @@ export class UserEntityService implements OnModuleInit {
|
||||||
where: {
|
where: {
|
||||||
blockerId: me,
|
blockerId: me,
|
||||||
blockeeId: target,
|
blockeeId: target,
|
||||||
|
isReactionBlock: false,
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
this.blockingsRepository.exists({
|
this.blockingsRepository.exists({
|
||||||
where: {
|
where: {
|
||||||
blockerId: target,
|
blockerId: target,
|
||||||
blockeeId: me,
|
blockeeId: me,
|
||||||
|
isReactionBlock: false,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
this.blockingsRepository.exists({
|
||||||
|
where: {
|
||||||
|
blockerId: me,
|
||||||
|
blockeeId: target,
|
||||||
|
isReactionBlock: true,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
this.blockingsRepository.exists({
|
||||||
|
where: {
|
||||||
|
blockerId: target,
|
||||||
|
blockeeId: me,
|
||||||
|
isReactionBlock: true,
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
this.mutingsRepository.exists({
|
this.mutingsRepository.exists({
|
||||||
|
@ -229,6 +249,8 @@ export class UserEntityService implements OnModuleInit {
|
||||||
hasPendingFollowRequestToYou,
|
hasPendingFollowRequestToYou,
|
||||||
isBlocking,
|
isBlocking,
|
||||||
isBlocked,
|
isBlocked,
|
||||||
|
isReactionBlocking,
|
||||||
|
isReactionBlocked,
|
||||||
isMuted,
|
isMuted,
|
||||||
isRenoteMuted,
|
isRenoteMuted,
|
||||||
};
|
};
|
||||||
|
@ -243,6 +265,8 @@ export class UserEntityService implements OnModuleInit {
|
||||||
followeesRequests,
|
followeesRequests,
|
||||||
blockers,
|
blockers,
|
||||||
blockees,
|
blockees,
|
||||||
|
reactionBlockers,
|
||||||
|
reactionBlockees,
|
||||||
muters,
|
muters,
|
||||||
renoteMuters,
|
renoteMuters,
|
||||||
] = await Promise.all([
|
] = await Promise.all([
|
||||||
|
@ -266,11 +290,25 @@ export class UserEntityService implements OnModuleInit {
|
||||||
this.blockingsRepository.createQueryBuilder('b')
|
this.blockingsRepository.createQueryBuilder('b')
|
||||||
.select('b.blockeeId')
|
.select('b.blockeeId')
|
||||||
.where('b.blockerId = :me', { me })
|
.where('b.blockerId = :me', { me })
|
||||||
|
.andWhere('b.isReactionBlock = false')
|
||||||
.getRawMany<{ b_blockeeId: string }>()
|
.getRawMany<{ b_blockeeId: string }>()
|
||||||
.then(it => it.map(it => it.b_blockeeId)),
|
.then(it => it.map(it => it.b_blockeeId)),
|
||||||
this.blockingsRepository.createQueryBuilder('b')
|
this.blockingsRepository.createQueryBuilder('b')
|
||||||
.select('b.blockerId')
|
.select('b.blockerId')
|
||||||
.where('b.blockeeId = :me', { me })
|
.where('b.blockeeId = :me', { me })
|
||||||
|
.andWhere('b.isReactionBlock = false')
|
||||||
|
.getRawMany<{ b_blockerId: string }>()
|
||||||
|
.then(it => it.map(it => it.b_blockerId)),
|
||||||
|
this.blockingsRepository.createQueryBuilder('b')
|
||||||
|
.select('b.blockeeId')
|
||||||
|
.where('b.blockerId = :me', { me })
|
||||||
|
.andWhere('b.isReactionBlock = true')
|
||||||
|
.getRawMany<{ b_blockeeId: string }>()
|
||||||
|
.then(it => it.map(it => it.b_blockeeId)),
|
||||||
|
this.blockingsRepository.createQueryBuilder('b')
|
||||||
|
.select('b.blockerId')
|
||||||
|
.where('b.blockeeId = :me', { me })
|
||||||
|
.andWhere('b.isReactionBlock = true')
|
||||||
.getRawMany<{ b_blockerId: string }>()
|
.getRawMany<{ b_blockerId: string }>()
|
||||||
.then(it => it.map(it => it.b_blockerId)),
|
.then(it => it.map(it => it.b_blockerId)),
|
||||||
this.mutingsRepository.createQueryBuilder('m')
|
this.mutingsRepository.createQueryBuilder('m')
|
||||||
|
@ -300,6 +338,8 @@ export class UserEntityService implements OnModuleInit {
|
||||||
hasPendingFollowRequestToYou: followeesRequests.includes(target),
|
hasPendingFollowRequestToYou: followeesRequests.includes(target),
|
||||||
isBlocking: blockers.includes(target),
|
isBlocking: blockers.includes(target),
|
||||||
isBlocked: blockees.includes(target),
|
isBlocked: blockees.includes(target),
|
||||||
|
isReactionBlocking: reactionBlockers.includes(target),
|
||||||
|
isReactionBlocked: reactionBlockees.includes(target),
|
||||||
isMuted: muters.includes(target),
|
isMuted: muters.includes(target),
|
||||||
isRenoteMuted: renoteMuters.includes(target),
|
isRenoteMuted: renoteMuters.includes(target),
|
||||||
},
|
},
|
||||||
|
@ -638,6 +678,8 @@ export class UserEntityService implements OnModuleInit {
|
||||||
hasPendingFollowRequestToYou: relation.hasPendingFollowRequestToYou,
|
hasPendingFollowRequestToYou: relation.hasPendingFollowRequestToYou,
|
||||||
isBlocking: relation.isBlocking,
|
isBlocking: relation.isBlocking,
|
||||||
isBlocked: relation.isBlocked,
|
isBlocked: relation.isBlocked,
|
||||||
|
isReactionBlocking: relation.isReactionBlocking,
|
||||||
|
isReactionBlocked: relation.isReactionBlocked,
|
||||||
isMuted: relation.isMuted,
|
isMuted: relation.isMuted,
|
||||||
isRenoteMuted: relation.isRenoteMuted,
|
isRenoteMuted: relation.isRenoteMuted,
|
||||||
notify: relation.following?.notify ?? 'none',
|
notify: relation.following?.notify ?? 'none',
|
||||||
|
|
|
@ -38,4 +38,11 @@ export class MiBlocking {
|
||||||
})
|
})
|
||||||
@JoinColumn()
|
@JoinColumn()
|
||||||
public blocker: MiUser | null;
|
public blocker: MiUser | null;
|
||||||
|
|
||||||
|
@Index()
|
||||||
|
@Column({
|
||||||
|
comment: 'Whether the blockee is a reaction block.',
|
||||||
|
default: false,
|
||||||
|
})
|
||||||
|
public isReactionBlock: boolean;
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,5 +27,9 @@ export const packedBlockingSchema = {
|
||||||
optional: false, nullable: false,
|
optional: false, nullable: false,
|
||||||
ref: 'UserDetailedNotMe',
|
ref: 'UserDetailedNotMe',
|
||||||
},
|
},
|
||||||
|
isReactionBlock: {
|
||||||
|
type: 'boolean',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
} as const;
|
} as const;
|
||||||
|
|
|
@ -416,6 +416,14 @@ export const packedUserDetailedNotMeOnlySchema = {
|
||||||
type: 'boolean',
|
type: 'boolean',
|
||||||
nullable: false, optional: true,
|
nullable: false, optional: true,
|
||||||
},
|
},
|
||||||
|
isReactionBlocking: {
|
||||||
|
type: 'boolean',
|
||||||
|
nullable: false, optional: true,
|
||||||
|
},
|
||||||
|
isReactionBlocked: {
|
||||||
|
type: 'boolean',
|
||||||
|
nullable: false, optional: true,
|
||||||
|
},
|
||||||
isMuted: {
|
isMuted: {
|
||||||
type: 'boolean',
|
type: 'boolean',
|
||||||
nullable: false, optional: true,
|
nullable: false, optional: true,
|
||||||
|
|
|
@ -231,6 +231,9 @@ import * as ep___i_favorites from './endpoints/i/favorites.js';
|
||||||
import * as ep___i_gallery_likes from './endpoints/i/gallery/likes.js';
|
import * as ep___i_gallery_likes from './endpoints/i/gallery/likes.js';
|
||||||
import * as ep___i_gallery_posts from './endpoints/i/gallery/posts.js';
|
import * as ep___i_gallery_posts from './endpoints/i/gallery/posts.js';
|
||||||
import * as ep___i_importBlocking from './endpoints/i/import-blocking.js';
|
import * as ep___i_importBlocking from './endpoints/i/import-blocking.js';
|
||||||
|
import * as ep___blocking_reaction_user_create from './endpoints/blocking-reaction-user/create.js';
|
||||||
|
import * as ep___blocking_reaction_user_delete from './endpoints/blocking-reaction-user/delete.js';
|
||||||
|
import * as ep___blocking_reaction_user_list from './endpoints/blocking-reaction-user/list.js';
|
||||||
import * as ep___i_importFollowing from './endpoints/i/import-following.js';
|
import * as ep___i_importFollowing from './endpoints/i/import-following.js';
|
||||||
import * as ep___i_importMuting from './endpoints/i/import-muting.js';
|
import * as ep___i_importMuting from './endpoints/i/import-muting.js';
|
||||||
import * as ep___i_importUserLists from './endpoints/i/import-user-lists.js';
|
import * as ep___i_importUserLists from './endpoints/i/import-user-lists.js';
|
||||||
|
@ -502,6 +505,9 @@ const $auth_session_userkey: Provider = { provide: 'ep:auth/session/userkey', us
|
||||||
const $blocking_create: Provider = { provide: 'ep:blocking/create', useClass: ep___blocking_create.default };
|
const $blocking_create: Provider = { provide: 'ep:blocking/create', useClass: ep___blocking_create.default };
|
||||||
const $blocking_delete: Provider = { provide: 'ep:blocking/delete', useClass: ep___blocking_delete.default };
|
const $blocking_delete: Provider = { provide: 'ep:blocking/delete', useClass: ep___blocking_delete.default };
|
||||||
const $blocking_list: Provider = { provide: 'ep:blocking/list', useClass: ep___blocking_list.default };
|
const $blocking_list: Provider = { provide: 'ep:blocking/list', useClass: ep___blocking_list.default };
|
||||||
|
const $blocking_reaction_user_create: Provider = { provide: 'ep:blocking-reaction-user/create', useClass: ep___blocking_reaction_user_create.default };
|
||||||
|
const $blocking_reaction_user_delete: Provider = { provide: 'ep:blocking-reaction-user/delete', useClass: ep___blocking_reaction_user_delete.default };
|
||||||
|
const $blocking_reaction_user_list: Provider = { provide: 'ep:blocking-reaction-user/list', useClass: ep___blocking_reaction_user_list.default };
|
||||||
const $channels_create: Provider = { provide: 'ep:channels/create', useClass: ep___channels_create.default };
|
const $channels_create: Provider = { provide: 'ep:channels/create', useClass: ep___channels_create.default };
|
||||||
const $channels_featured: Provider = { provide: 'ep:channels/featured', useClass: ep___channels_featured.default };
|
const $channels_featured: Provider = { provide: 'ep:channels/featured', useClass: ep___channels_featured.default };
|
||||||
const $channels_follow: Provider = { provide: 'ep:channels/follow', useClass: ep___channels_follow.default };
|
const $channels_follow: Provider = { provide: 'ep:channels/follow', useClass: ep___channels_follow.default };
|
||||||
|
@ -894,6 +900,9 @@ const $reversi_verify: Provider = { provide: 'ep:reversi/verify', useClass: ep__
|
||||||
$blocking_create,
|
$blocking_create,
|
||||||
$blocking_delete,
|
$blocking_delete,
|
||||||
$blocking_list,
|
$blocking_list,
|
||||||
|
$blocking_reaction_user_create,
|
||||||
|
$blocking_reaction_user_delete,
|
||||||
|
$blocking_reaction_user_list,
|
||||||
$channels_create,
|
$channels_create,
|
||||||
$channels_featured,
|
$channels_featured,
|
||||||
$channels_follow,
|
$channels_follow,
|
||||||
|
|
|
@ -120,6 +120,9 @@ import * as ep___auth_session_userkey from './endpoints/auth/session/userkey.js'
|
||||||
import * as ep___blocking_create from './endpoints/blocking/create.js';
|
import * as ep___blocking_create from './endpoints/blocking/create.js';
|
||||||
import * as ep___blocking_delete from './endpoints/blocking/delete.js';
|
import * as ep___blocking_delete from './endpoints/blocking/delete.js';
|
||||||
import * as ep___blocking_list from './endpoints/blocking/list.js';
|
import * as ep___blocking_list from './endpoints/blocking/list.js';
|
||||||
|
import * as ep___blocking_reaction_user_create from './endpoints/blocking-reaction-user/create.js';
|
||||||
|
import * as ep___blocking_reaction_user_delete from './endpoints/blocking-reaction-user/delete.js';
|
||||||
|
import * as ep___blocking_reaction_user_list from './endpoints/blocking-reaction-user/list.js';
|
||||||
import * as ep___channels_create from './endpoints/channels/create.js';
|
import * as ep___channels_create from './endpoints/channels/create.js';
|
||||||
import * as ep___channels_featured from './endpoints/channels/featured.js';
|
import * as ep___channels_featured from './endpoints/channels/featured.js';
|
||||||
import * as ep___channels_follow from './endpoints/channels/follow.js';
|
import * as ep___channels_follow from './endpoints/channels/follow.js';
|
||||||
|
@ -506,6 +509,9 @@ const eps = [
|
||||||
['blocking/create', ep___blocking_create],
|
['blocking/create', ep___blocking_create],
|
||||||
['blocking/delete', ep___blocking_delete],
|
['blocking/delete', ep___blocking_delete],
|
||||||
['blocking/list', ep___blocking_list],
|
['blocking/list', ep___blocking_list],
|
||||||
|
['blocking-reaction-user/create', ep___blocking_reaction_user_create],
|
||||||
|
['blocking-reaction-user/delete', ep___blocking_reaction_user_delete],
|
||||||
|
['blocking-reaction-user/list', ep___blocking_reaction_user_list],
|
||||||
['channels/create', ep___channels_create],
|
['channels/create', ep___channels_create],
|
||||||
['channels/featured', ep___channels_featured],
|
['channels/featured', ep___channels_featured],
|
||||||
['channels/follow', ep___channels_follow],
|
['channels/follow', ep___channels_follow],
|
||||||
|
|
|
@ -0,0 +1,110 @@
|
||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: syuilo and misskey-project
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
import ms from 'ms';
|
||||||
|
import { Inject, Injectable } from '@nestjs/common';
|
||||||
|
import { Endpoint } from '@/server/api/endpoint-base.js';
|
||||||
|
import type { UsersRepository, BlockingsRepository } from '@/models/_.js';
|
||||||
|
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
||||||
|
import { DI } from '@/di-symbols.js';
|
||||||
|
import { GetterService } from '@/server/api/GetterService.js';
|
||||||
|
import { ApiError } from '../../error.js';
|
||||||
|
import { UserReactionBlockingService } from '@/core/UserReactionBlockingService.js';
|
||||||
|
|
||||||
|
export const meta = {
|
||||||
|
tags: ['account'],
|
||||||
|
|
||||||
|
limit: {
|
||||||
|
duration: ms('1hour'),
|
||||||
|
max: 20,
|
||||||
|
},
|
||||||
|
|
||||||
|
requireCredential: true,
|
||||||
|
|
||||||
|
kind: 'write:blocks',
|
||||||
|
|
||||||
|
errors: {
|
||||||
|
noSuchUser: {
|
||||||
|
message: 'No such user.',
|
||||||
|
code: 'NO_SUCH_USER',
|
||||||
|
id: '7cc4f851-e2f1-4621-9633-ec9e1d00c01e',
|
||||||
|
},
|
||||||
|
|
||||||
|
blockeeIsYourself: {
|
||||||
|
message: 'Blockee is yourself.',
|
||||||
|
code: 'BLOCKEE_IS_YOURSELF',
|
||||||
|
id: '88b19138-f28d-42c0-8499-6a31bbd0fdc6',
|
||||||
|
},
|
||||||
|
|
||||||
|
alreadyBlocking: {
|
||||||
|
message: 'You are already blocking that user.',
|
||||||
|
code: 'ALREADY_BLOCKING',
|
||||||
|
id: '787fed64-acb9-464a-82eb-afbd745b9614',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
res: {
|
||||||
|
type: 'object',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
ref: 'UserDetailedNotMe',
|
||||||
|
},
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
export const paramDef = {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
userId: { type: 'string', format: 'misskey:id' },
|
||||||
|
},
|
||||||
|
required: ['userId'],
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export
|
||||||
|
constructor(
|
||||||
|
@Inject(DI.usersRepository)
|
||||||
|
private usersRepository: UsersRepository,
|
||||||
|
|
||||||
|
@Inject(DI.blockingsRepository)
|
||||||
|
private blockingsRepository: BlockingsRepository,
|
||||||
|
|
||||||
|
private userEntityService: UserEntityService,
|
||||||
|
private getterService: GetterService,
|
||||||
|
private userReactionBlockingService: UserReactionBlockingService,
|
||||||
|
) {
|
||||||
|
super(meta, paramDef, async (ps, me) => {
|
||||||
|
const blocker = await this.usersRepository.findOneByOrFail({ id: me.id });
|
||||||
|
|
||||||
|
// 自分自身
|
||||||
|
if (me.id === ps.userId) {
|
||||||
|
throw new ApiError(meta.errors.blockeeIsYourself);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get blockee
|
||||||
|
const blockee = await this.getterService.getUser(ps.userId).catch(err => {
|
||||||
|
if (err.id === '15348ddd-432d-49c2-8a5a-8069753becff') throw new ApiError(meta.errors.noSuchUser);
|
||||||
|
throw err;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Check if already blocking
|
||||||
|
const exist = await this.blockingsRepository.exists({
|
||||||
|
where: {
|
||||||
|
blockerId: blocker.id,
|
||||||
|
blockeeId: blockee.id,
|
||||||
|
isReactionBlock: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (exist) {
|
||||||
|
throw new ApiError(meta.errors.alreadyBlocking);
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.userReactionBlockingService.block(blocker, blockee);
|
||||||
|
|
||||||
|
return await this.userEntityService.pack(blockee.id, blocker, {
|
||||||
|
schema: 'UserDetailedNotMe',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,111 @@
|
||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: syuilo and misskey-project
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
import ms from 'ms';
|
||||||
|
import { Inject, Injectable } from '@nestjs/common';
|
||||||
|
import { Endpoint } from '@/server/api/endpoint-base.js';
|
||||||
|
import type { UsersRepository, BlockingsRepository } from '@/models/_.js';
|
||||||
|
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
||||||
|
import { UserReactionBlockingService } from '@/core/UserReactionBlockingService.js';
|
||||||
|
import { DI } from '@/di-symbols.js';
|
||||||
|
import { GetterService } from '@/server/api/GetterService.js';
|
||||||
|
import { ApiError } from '../../error.js';
|
||||||
|
|
||||||
|
export const meta = {
|
||||||
|
tags: ['account'],
|
||||||
|
|
||||||
|
limit: {
|
||||||
|
duration: ms('1hour'),
|
||||||
|
max: 100,
|
||||||
|
},
|
||||||
|
|
||||||
|
requireCredential: true,
|
||||||
|
|
||||||
|
kind: 'write:blocks',
|
||||||
|
|
||||||
|
errors: {
|
||||||
|
noSuchUser: {
|
||||||
|
message: 'No such user.',
|
||||||
|
code: 'NO_SUCH_USER',
|
||||||
|
id: '8621d8bf-c358-4303-a066-5ea78610eb3f',
|
||||||
|
},
|
||||||
|
|
||||||
|
blockeeIsYourself: {
|
||||||
|
message: 'Blockee is yourself.',
|
||||||
|
code: 'BLOCKEE_IS_YOURSELF',
|
||||||
|
id: '06f6fac6-524b-473c-a354-e97a40ae6eac',
|
||||||
|
},
|
||||||
|
|
||||||
|
notBlocking: {
|
||||||
|
message: 'You are not blocking that user.',
|
||||||
|
code: 'NOT_BLOCKING',
|
||||||
|
id: '291b2efa-60c6-45c0-9f6a-045c8f9b02cd',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
res: {
|
||||||
|
type: 'object',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
ref: 'UserDetailedNotMe',
|
||||||
|
},
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
export const paramDef = {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
userId: { type: 'string', format: 'misskey:id' },
|
||||||
|
},
|
||||||
|
required: ['userId'],
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export
|
||||||
|
constructor(
|
||||||
|
@Inject(DI.usersRepository)
|
||||||
|
private usersRepository: UsersRepository,
|
||||||
|
|
||||||
|
@Inject(DI.blockingsRepository)
|
||||||
|
private blockingsRepository: BlockingsRepository,
|
||||||
|
|
||||||
|
private userEntityService: UserEntityService,
|
||||||
|
private getterService: GetterService,
|
||||||
|
private userReactionBlockingService: UserReactionBlockingService,
|
||||||
|
) {
|
||||||
|
super(meta, paramDef, async (ps, me) => {
|
||||||
|
const blocker = await this.usersRepository.findOneByOrFail({ id: me.id });
|
||||||
|
|
||||||
|
// Check if the blockee is yourself
|
||||||
|
if (me.id === ps.userId) {
|
||||||
|
throw new ApiError(meta.errors.blockeeIsYourself);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get blockee
|
||||||
|
const blockee = await this.getterService.getUser(ps.userId).catch(err => {
|
||||||
|
if (err.id === '15348ddd-432d-49c2-8a5a-8069753becff') throw new ApiError(meta.errors.noSuchUser);
|
||||||
|
throw err;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Check not blocking
|
||||||
|
const exist = await this.blockingsRepository.exists({
|
||||||
|
where: {
|
||||||
|
blockerId: blocker.id,
|
||||||
|
blockeeId: blockee.id,
|
||||||
|
isReactionBlock: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!exist) {
|
||||||
|
throw new ApiError(meta.errors.notBlocking);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete blocking
|
||||||
|
await this.userReactionBlockingService.unblock(blocker, blockee);
|
||||||
|
|
||||||
|
return await this.userEntityService.pack(blockee.id, blocker, {
|
||||||
|
schema: 'UserDetailedNotMe',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,62 @@
|
||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: syuilo and misskey-project
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { Inject, Injectable } from '@nestjs/common';
|
||||||
|
import { Endpoint } from '@/server/api/endpoint-base.js';
|
||||||
|
import type { BlockingsRepository } from '@/models/_.js';
|
||||||
|
import { QueryService } from '@/core/QueryService.js';
|
||||||
|
import { BlockingEntityService } from '@/core/entities/BlockingEntityService.js';
|
||||||
|
import { DI } from '@/di-symbols.js';
|
||||||
|
|
||||||
|
export const meta = {
|
||||||
|
tags: ['account'],
|
||||||
|
|
||||||
|
requireCredential: true,
|
||||||
|
|
||||||
|
kind: 'read:blocks',
|
||||||
|
|
||||||
|
res: {
|
||||||
|
type: 'array',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
items: {
|
||||||
|
type: 'object',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
ref: 'Blocking',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
export const paramDef = {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
limit: { type: 'integer', minimum: 1, maximum: 100, default: 30 },
|
||||||
|
sinceId: { type: 'string', format: 'misskey:id' },
|
||||||
|
untilId: { type: 'string', format: 'misskey:id' },
|
||||||
|
},
|
||||||
|
required: [],
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export
|
||||||
|
constructor(
|
||||||
|
@Inject(DI.blockingsRepository)
|
||||||
|
private blockingsRepository: BlockingsRepository,
|
||||||
|
|
||||||
|
private blockingEntityService: BlockingEntityService,
|
||||||
|
private queryService: QueryService,
|
||||||
|
) {
|
||||||
|
super(meta, paramDef, async (ps, me) => {
|
||||||
|
const query = this.queryService.makePaginationQuery(this.blockingsRepository.createQueryBuilder('blocking'), ps.sinceId, ps.untilId)
|
||||||
|
.andWhere('blocking.blockerId = :meId', { meId: me.id })
|
||||||
|
.andWhere('blocking.isReactionBlock = true');
|
||||||
|
|
||||||
|
const blockings = await query
|
||||||
|
.limit(ps.limit)
|
||||||
|
.getMany();
|
||||||
|
|
||||||
|
return await this.blockingEntityService.packMany(blockings, me);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -49,7 +49,8 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
) {
|
) {
|
||||||
super(meta, paramDef, async (ps, me) => {
|
super(meta, paramDef, async (ps, me) => {
|
||||||
const query = this.queryService.makePaginationQuery(this.blockingsRepository.createQueryBuilder('blocking'), ps.sinceId, ps.untilId)
|
const query = this.queryService.makePaginationQuery(this.blockingsRepository.createQueryBuilder('blocking'), ps.sinceId, ps.untilId)
|
||||||
.andWhere('blocking.blockerId = :meId', { meId: me.id });
|
.andWhere('blocking.blockerId = :meId', { meId: me.id })
|
||||||
|
.andWhere('blocking.isReactionBlock = false');
|
||||||
|
|
||||||
const blockings = await query
|
const blockings = await query
|
||||||
.limit(ps.limit)
|
.limit(ps.limit)
|
||||||
|
|
|
@ -115,6 +115,16 @@ describe('UserEntityService', () => {
|
||||||
id: genAidx(Date.now()),
|
id: genAidx(Date.now()),
|
||||||
blockerId: blocker.id,
|
blockerId: blocker.id,
|
||||||
blockeeId: blockee.id,
|
blockeeId: blockee.id,
|
||||||
|
isReactionBlock: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function blockReaction(blocker: MiUser, blockee: MiUser) {
|
||||||
|
await blockingRepository.insert({
|
||||||
|
id: genAidx(Date.now()),
|
||||||
|
blockerId: blocker.id,
|
||||||
|
blockeeId: blockee.id,
|
||||||
|
isReactionBlock: true,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -260,6 +270,8 @@ describe('UserEntityService', () => {
|
||||||
expect(actual.hasPendingFollowRequestToYou).toBe(false);
|
expect(actual.hasPendingFollowRequestToYou).toBe(false);
|
||||||
expect(actual.isBlocking).toBe(false);
|
expect(actual.isBlocking).toBe(false);
|
||||||
expect(actual.isBlocked).toBe(false);
|
expect(actual.isBlocked).toBe(false);
|
||||||
|
expect(actual.isReactionBlocking).toBe(false);
|
||||||
|
expect(actual.isReactionBlocked).toBe(false);
|
||||||
expect(actual.isMuted).toBe(false);
|
expect(actual.isMuted).toBe(false);
|
||||||
expect(actual.isRenoteMuted).toBe(false);
|
expect(actual.isRenoteMuted).toBe(false);
|
||||||
}
|
}
|
||||||
|
@ -275,6 +287,8 @@ describe('UserEntityService', () => {
|
||||||
expect(actual.hasPendingFollowRequestToYou).toBe(false);
|
expect(actual.hasPendingFollowRequestToYou).toBe(false);
|
||||||
expect(actual.isBlocking).toBe(false);
|
expect(actual.isBlocking).toBe(false);
|
||||||
expect(actual.isBlocked).toBe(false);
|
expect(actual.isBlocked).toBe(false);
|
||||||
|
expect(actual.isReactionBlocking).toBe(false);
|
||||||
|
expect(actual.isReactionBlocked).toBe(false);
|
||||||
expect(actual.isMuted).toBe(false);
|
expect(actual.isMuted).toBe(false);
|
||||||
expect(actual.isRenoteMuted).toBe(false);
|
expect(actual.isRenoteMuted).toBe(false);
|
||||||
}
|
}
|
||||||
|
@ -290,6 +304,8 @@ describe('UserEntityService', () => {
|
||||||
expect(actual.hasPendingFollowRequestToYou).toBe(false);
|
expect(actual.hasPendingFollowRequestToYou).toBe(false);
|
||||||
expect(actual.isBlocking).toBe(false);
|
expect(actual.isBlocking).toBe(false);
|
||||||
expect(actual.isBlocked).toBe(false);
|
expect(actual.isBlocked).toBe(false);
|
||||||
|
expect(actual.isReactionBlocking).toBe(false);
|
||||||
|
expect(actual.isReactionBlocked).toBe(false);
|
||||||
expect(actual.isMuted).toBe(false);
|
expect(actual.isMuted).toBe(false);
|
||||||
expect(actual.isRenoteMuted).toBe(false);
|
expect(actual.isRenoteMuted).toBe(false);
|
||||||
}
|
}
|
||||||
|
@ -305,6 +321,8 @@ describe('UserEntityService', () => {
|
||||||
expect(actual.hasPendingFollowRequestToYou).toBe(true);
|
expect(actual.hasPendingFollowRequestToYou).toBe(true);
|
||||||
expect(actual.isBlocking).toBe(false);
|
expect(actual.isBlocking).toBe(false);
|
||||||
expect(actual.isBlocked).toBe(false);
|
expect(actual.isBlocked).toBe(false);
|
||||||
|
expect(actual.isReactionBlocking).toBe(false);
|
||||||
|
expect(actual.isReactionBlocked).toBe(false);
|
||||||
expect(actual.isMuted).toBe(false);
|
expect(actual.isMuted).toBe(false);
|
||||||
expect(actual.isRenoteMuted).toBe(false);
|
expect(actual.isRenoteMuted).toBe(false);
|
||||||
}
|
}
|
||||||
|
@ -320,6 +338,8 @@ describe('UserEntityService', () => {
|
||||||
expect(actual.hasPendingFollowRequestToYou).toBe(false);
|
expect(actual.hasPendingFollowRequestToYou).toBe(false);
|
||||||
expect(actual.isBlocking).toBe(true);
|
expect(actual.isBlocking).toBe(true);
|
||||||
expect(actual.isBlocked).toBe(false);
|
expect(actual.isBlocked).toBe(false);
|
||||||
|
expect(actual.isReactionBlocking).toBe(false);
|
||||||
|
expect(actual.isReactionBlocked).toBe(false);
|
||||||
expect(actual.isMuted).toBe(false);
|
expect(actual.isMuted).toBe(false);
|
||||||
expect(actual.isRenoteMuted).toBe(false);
|
expect(actual.isRenoteMuted).toBe(false);
|
||||||
}
|
}
|
||||||
|
@ -339,6 +359,41 @@ describe('UserEntityService', () => {
|
||||||
expect(actual.isRenoteMuted).toBe(false);
|
expect(actual.isRenoteMuted).toBe(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// meがリアクションをブロックしてる人たち
|
||||||
|
const reactionBlockingYou = await Promise.all(randomIntRange().map(() => createUser()));
|
||||||
|
for (const who of reactionBlockingYou) {
|
||||||
|
await blockReaction(me, who);
|
||||||
|
const actual = await service.pack(who, me, { schema: 'UserDetailed' }) as any;
|
||||||
|
expect(actual.isFollowing).toBe(false);
|
||||||
|
expect(actual.isFollowed).toBe(false);
|
||||||
|
expect(actual.hasPendingFollowRequestFromYou).toBe(false);
|
||||||
|
expect(actual.hasPendingFollowRequestToYou).toBe(false);
|
||||||
|
expect(actual.isBlocking).toBe(false);
|
||||||
|
expect(actual.isBlocked).toBe(false);
|
||||||
|
expect(actual.isReactionBlocking).toBe(true);
|
||||||
|
expect(actual.isReactionBlocked).toBe(false);
|
||||||
|
expect(actual.isMuted).toBe(false);
|
||||||
|
expect(actual.isRenoteMuted).toBe(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// meのリアクションをブロックしてる人たち
|
||||||
|
const reactionBlockingMe = await Promise.all(randomIntRange().map(() => createUser()));
|
||||||
|
for (const who of reactionBlockingMe) {
|
||||||
|
await blockReaction(who, me);
|
||||||
|
const actual = await service.pack(who, me, { schema: 'UserDetailed' }) as any;
|
||||||
|
expect(actual.isFollowing).toBe(false);
|
||||||
|
expect(actual.isFollowed).toBe(false);
|
||||||
|
expect(actual.hasPendingFollowRequestFromYou).toBe(false);
|
||||||
|
expect(actual.hasPendingFollowRequestToYou).toBe(false);
|
||||||
|
expect(actual.isBlocking).toBe(false);
|
||||||
|
expect(actual.isBlocked).toBe(false);
|
||||||
|
expect(actual.isReactionBlocking).toBe(false);
|
||||||
|
expect(actual.isReactionBlocked).toBe(true);
|
||||||
|
expect(actual.isMuted).toBe(false);
|
||||||
|
expect(actual.isRenoteMuted).toBe(false);
|
||||||
|
}
|
||||||
|
|
||||||
// meがミュートしてる人たち
|
// meがミュートしてる人たち
|
||||||
const muters = await Promise.all(randomIntRange().map(() => createUser()));
|
const muters = await Promise.all(randomIntRange().map(() => createUser()));
|
||||||
for (const who of muters) {
|
for (const who of muters) {
|
||||||
|
@ -350,6 +405,8 @@ describe('UserEntityService', () => {
|
||||||
expect(actual.hasPendingFollowRequestToYou).toBe(false);
|
expect(actual.hasPendingFollowRequestToYou).toBe(false);
|
||||||
expect(actual.isBlocking).toBe(false);
|
expect(actual.isBlocking).toBe(false);
|
||||||
expect(actual.isBlocked).toBe(false);
|
expect(actual.isBlocked).toBe(false);
|
||||||
|
expect(actual.isReactionBlocking).toBe(false);
|
||||||
|
expect(actual.isReactionBlocked).toBe(false);
|
||||||
expect(actual.isMuted).toBe(true);
|
expect(actual.isMuted).toBe(true);
|
||||||
expect(actual.isRenoteMuted).toBe(false);
|
expect(actual.isRenoteMuted).toBe(false);
|
||||||
}
|
}
|
||||||
|
@ -365,6 +422,8 @@ describe('UserEntityService', () => {
|
||||||
expect(actual.hasPendingFollowRequestToYou).toBe(false);
|
expect(actual.hasPendingFollowRequestToYou).toBe(false);
|
||||||
expect(actual.isBlocking).toBe(false);
|
expect(actual.isBlocking).toBe(false);
|
||||||
expect(actual.isBlocked).toBe(false);
|
expect(actual.isBlocked).toBe(false);
|
||||||
|
expect(actual.isReactionBlocking).toBe(false);
|
||||||
|
expect(actual.isReactionBlocked).toBe(false);
|
||||||
expect(actual.isMuted).toBe(false);
|
expect(actual.isMuted).toBe(false);
|
||||||
expect(actual.isRenoteMuted).toBe(true);
|
expect(actual.isRenoteMuted).toBe(true);
|
||||||
}
|
}
|
||||||
|
|
|
@ -551,6 +551,24 @@ type BlockingListRequest = operations['blocking___list']['requestBody']['content
|
||||||
// @public (undocumented)
|
// @public (undocumented)
|
||||||
type BlockingListResponse = operations['blocking___list']['responses']['200']['content']['application/json'];
|
type BlockingListResponse = operations['blocking___list']['responses']['200']['content']['application/json'];
|
||||||
|
|
||||||
|
// @public (undocumented)
|
||||||
|
type BlockingReactionUserCreateRequest = operations['blocking-reaction-user___create']['requestBody']['content']['application/json'];
|
||||||
|
|
||||||
|
// @public (undocumented)
|
||||||
|
type BlockingReactionUserCreateResponse = operations['blocking-reaction-user___create']['responses']['200']['content']['application/json'];
|
||||||
|
|
||||||
|
// @public (undocumented)
|
||||||
|
type BlockingReactionUserDeleteRequest = operations['blocking-reaction-user___delete']['requestBody']['content']['application/json'];
|
||||||
|
|
||||||
|
// @public (undocumented)
|
||||||
|
type BlockingReactionUserDeleteResponse = operations['blocking-reaction-user___delete']['responses']['200']['content']['application/json'];
|
||||||
|
|
||||||
|
// @public (undocumented)
|
||||||
|
type BlockingReactionUserListRequest = operations['blocking-reaction-user___list']['requestBody']['content']['application/json'];
|
||||||
|
|
||||||
|
// @public (undocumented)
|
||||||
|
type BlockingReactionUserListResponse = operations['blocking-reaction-user___list']['responses']['200']['content']['application/json'];
|
||||||
|
|
||||||
// @public (undocumented)
|
// @public (undocumented)
|
||||||
type BubbleGameRankingRequest = operations['bubble-game___ranking']['requestBody']['content']['application/json'];
|
type BubbleGameRankingRequest = operations['bubble-game___ranking']['requestBody']['content']['application/json'];
|
||||||
|
|
||||||
|
@ -1381,6 +1399,12 @@ declare namespace entities {
|
||||||
BlockingDeleteResponse,
|
BlockingDeleteResponse,
|
||||||
BlockingListRequest,
|
BlockingListRequest,
|
||||||
BlockingListResponse,
|
BlockingListResponse,
|
||||||
|
BlockingReactionUserCreateRequest,
|
||||||
|
BlockingReactionUserCreateResponse,
|
||||||
|
BlockingReactionUserDeleteRequest,
|
||||||
|
BlockingReactionUserDeleteResponse,
|
||||||
|
BlockingReactionUserListRequest,
|
||||||
|
BlockingReactionUserListResponse,
|
||||||
ChannelsCreateRequest,
|
ChannelsCreateRequest,
|
||||||
ChannelsCreateResponse,
|
ChannelsCreateResponse,
|
||||||
ChannelsFeaturedResponse,
|
ChannelsFeaturedResponse,
|
||||||
|
|
|
@ -1204,6 +1204,39 @@ declare module '../api.js' {
|
||||||
credential?: string | null,
|
credential?: string | null,
|
||||||
): Promise<SwitchCaseResponseType<E, P>>;
|
): Promise<SwitchCaseResponseType<E, P>>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* No description provided.
|
||||||
|
*
|
||||||
|
* **Credential required**: *Yes* / **Permission**: *write:blocks*
|
||||||
|
*/
|
||||||
|
request<E extends 'blocking-reaction-user/create', P extends Endpoints[E]['req']>(
|
||||||
|
endpoint: E,
|
||||||
|
params: P,
|
||||||
|
credential?: string | null,
|
||||||
|
): Promise<SwitchCaseResponseType<E, P>>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* No description provided.
|
||||||
|
*
|
||||||
|
* **Credential required**: *Yes* / **Permission**: *write:blocks*
|
||||||
|
*/
|
||||||
|
request<E extends 'blocking-reaction-user/delete', P extends Endpoints[E]['req']>(
|
||||||
|
endpoint: E,
|
||||||
|
params: P,
|
||||||
|
credential?: string | null,
|
||||||
|
): Promise<SwitchCaseResponseType<E, P>>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* No description provided.
|
||||||
|
*
|
||||||
|
* **Credential required**: *Yes* / **Permission**: *read:blocks*
|
||||||
|
*/
|
||||||
|
request<E extends 'blocking-reaction-user/list', P extends Endpoints[E]['req']>(
|
||||||
|
endpoint: E,
|
||||||
|
params: P,
|
||||||
|
credential?: string | null,
|
||||||
|
): Promise<SwitchCaseResponseType<E, P>>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* No description provided.
|
* No description provided.
|
||||||
*
|
*
|
||||||
|
|
|
@ -156,6 +156,12 @@ import type {
|
||||||
BlockingDeleteResponse,
|
BlockingDeleteResponse,
|
||||||
BlockingListRequest,
|
BlockingListRequest,
|
||||||
BlockingListResponse,
|
BlockingListResponse,
|
||||||
|
BlockingReactionUserCreateRequest,
|
||||||
|
BlockingReactionUserCreateResponse,
|
||||||
|
BlockingReactionUserDeleteRequest,
|
||||||
|
BlockingReactionUserDeleteResponse,
|
||||||
|
BlockingReactionUserListRequest,
|
||||||
|
BlockingReactionUserListResponse,
|
||||||
ChannelsCreateRequest,
|
ChannelsCreateRequest,
|
||||||
ChannelsCreateResponse,
|
ChannelsCreateResponse,
|
||||||
ChannelsFeaturedResponse,
|
ChannelsFeaturedResponse,
|
||||||
|
@ -690,6 +696,9 @@ export type Endpoints = {
|
||||||
'blocking/create': { req: BlockingCreateRequest; res: BlockingCreateResponse };
|
'blocking/create': { req: BlockingCreateRequest; res: BlockingCreateResponse };
|
||||||
'blocking/delete': { req: BlockingDeleteRequest; res: BlockingDeleteResponse };
|
'blocking/delete': { req: BlockingDeleteRequest; res: BlockingDeleteResponse };
|
||||||
'blocking/list': { req: BlockingListRequest; res: BlockingListResponse };
|
'blocking/list': { req: BlockingListRequest; res: BlockingListResponse };
|
||||||
|
'blocking-reaction-user/create': { req: BlockingReactionUserCreateRequest; res: BlockingReactionUserCreateResponse };
|
||||||
|
'blocking-reaction-user/delete': { req: BlockingReactionUserDeleteRequest; res: BlockingReactionUserDeleteResponse };
|
||||||
|
'blocking-reaction-user/list': { req: BlockingReactionUserListRequest; res: BlockingReactionUserListResponse };
|
||||||
'channels/create': { req: ChannelsCreateRequest; res: ChannelsCreateResponse };
|
'channels/create': { req: ChannelsCreateRequest; res: ChannelsCreateResponse };
|
||||||
'channels/featured': { req: EmptyRequest; res: ChannelsFeaturedResponse };
|
'channels/featured': { req: EmptyRequest; res: ChannelsFeaturedResponse };
|
||||||
'channels/follow': { req: ChannelsFollowRequest; res: EmptyResponse };
|
'channels/follow': { req: ChannelsFollowRequest; res: EmptyResponse };
|
||||||
|
|
|
@ -159,6 +159,12 @@ export type BlockingDeleteRequest = operations['blocking___delete']['requestBody
|
||||||
export type BlockingDeleteResponse = operations['blocking___delete']['responses']['200']['content']['application/json'];
|
export type BlockingDeleteResponse = operations['blocking___delete']['responses']['200']['content']['application/json'];
|
||||||
export type BlockingListRequest = operations['blocking___list']['requestBody']['content']['application/json'];
|
export type BlockingListRequest = operations['blocking___list']['requestBody']['content']['application/json'];
|
||||||
export type BlockingListResponse = operations['blocking___list']['responses']['200']['content']['application/json'];
|
export type BlockingListResponse = operations['blocking___list']['responses']['200']['content']['application/json'];
|
||||||
|
export type BlockingReactionUserCreateRequest = operations['blocking-reaction-user___create']['requestBody']['content']['application/json'];
|
||||||
|
export type BlockingReactionUserCreateResponse = operations['blocking-reaction-user___create']['responses']['200']['content']['application/json'];
|
||||||
|
export type BlockingReactionUserDeleteRequest = operations['blocking-reaction-user___delete']['requestBody']['content']['application/json'];
|
||||||
|
export type BlockingReactionUserDeleteResponse = operations['blocking-reaction-user___delete']['responses']['200']['content']['application/json'];
|
||||||
|
export type BlockingReactionUserListRequest = operations['blocking-reaction-user___list']['requestBody']['content']['application/json'];
|
||||||
|
export type BlockingReactionUserListResponse = operations['blocking-reaction-user___list']['responses']['200']['content']['application/json'];
|
||||||
export type ChannelsCreateRequest = operations['channels___create']['requestBody']['content']['application/json'];
|
export type ChannelsCreateRequest = operations['channels___create']['requestBody']['content']['application/json'];
|
||||||
export type ChannelsCreateResponse = operations['channels___create']['responses']['200']['content']['application/json'];
|
export type ChannelsCreateResponse = operations['channels___create']['responses']['200']['content']['application/json'];
|
||||||
export type ChannelsFeaturedResponse = operations['channels___featured']['responses']['200']['content']['application/json'];
|
export type ChannelsFeaturedResponse = operations['channels___featured']['responses']['200']['content']['application/json'];
|
||||||
|
|
|
@ -997,6 +997,33 @@ export type paths = {
|
||||||
*/
|
*/
|
||||||
post: operations['blocking___list'];
|
post: operations['blocking___list'];
|
||||||
};
|
};
|
||||||
|
'/blocking-reaction-user/create': {
|
||||||
|
/**
|
||||||
|
* blocking-reaction-user/create
|
||||||
|
* @description No description provided.
|
||||||
|
*
|
||||||
|
* **Credential required**: *Yes* / **Permission**: *write:blocks*
|
||||||
|
*/
|
||||||
|
post: operations['blocking-reaction-user___create'];
|
||||||
|
};
|
||||||
|
'/blocking-reaction-user/delete': {
|
||||||
|
/**
|
||||||
|
* blocking-reaction-user/delete
|
||||||
|
* @description No description provided.
|
||||||
|
*
|
||||||
|
* **Credential required**: *Yes* / **Permission**: *write:blocks*
|
||||||
|
*/
|
||||||
|
post: operations['blocking-reaction-user___delete'];
|
||||||
|
};
|
||||||
|
'/blocking-reaction-user/list': {
|
||||||
|
/**
|
||||||
|
* blocking-reaction-user/list
|
||||||
|
* @description No description provided.
|
||||||
|
*
|
||||||
|
* **Credential required**: *Yes* / **Permission**: *read:blocks*
|
||||||
|
*/
|
||||||
|
post: operations['blocking-reaction-user___list'];
|
||||||
|
};
|
||||||
'/channels/create': {
|
'/channels/create': {
|
||||||
/**
|
/**
|
||||||
* channels/create
|
* channels/create
|
||||||
|
@ -3825,6 +3852,8 @@ export type components = {
|
||||||
hasPendingFollowRequestToYou?: boolean;
|
hasPendingFollowRequestToYou?: boolean;
|
||||||
isBlocking?: boolean;
|
isBlocking?: boolean;
|
||||||
isBlocked?: boolean;
|
isBlocked?: boolean;
|
||||||
|
isReactionBlocking?: boolean;
|
||||||
|
isReactionBlocked?: boolean;
|
||||||
isMuted?: boolean;
|
isMuted?: boolean;
|
||||||
isRenoteMuted?: boolean;
|
isRenoteMuted?: boolean;
|
||||||
/** @enum {string} */
|
/** @enum {string} */
|
||||||
|
@ -4486,6 +4515,7 @@ export type components = {
|
||||||
/** Format: id */
|
/** Format: id */
|
||||||
blockeeId: string;
|
blockeeId: string;
|
||||||
blockee: components['schemas']['UserDetailedNotMe'];
|
blockee: components['schemas']['UserDetailedNotMe'];
|
||||||
|
isReactionBlock: boolean;
|
||||||
};
|
};
|
||||||
Hashtag: {
|
Hashtag: {
|
||||||
/** @example misskey */
|
/** @example misskey */
|
||||||
|
@ -11705,6 +11735,184 @@ export type operations = {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
/**
|
||||||
|
* blocking-reaction-user/create
|
||||||
|
* @description No description provided.
|
||||||
|
*
|
||||||
|
* **Credential required**: *Yes* / **Permission**: *write:blocks*
|
||||||
|
*/
|
||||||
|
'blocking-reaction-user___create': {
|
||||||
|
requestBody: {
|
||||||
|
content: {
|
||||||
|
'application/json': {
|
||||||
|
/** Format: misskey:id */
|
||||||
|
userId: string;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
responses: {
|
||||||
|
/** @description OK (with results) */
|
||||||
|
200: {
|
||||||
|
content: {
|
||||||
|
'application/json': components['schemas']['UserDetailedNotMe'];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
/** @description Client error */
|
||||||
|
400: {
|
||||||
|
content: {
|
||||||
|
'application/json': components['schemas']['Error'];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
/** @description Authentication error */
|
||||||
|
401: {
|
||||||
|
content: {
|
||||||
|
'application/json': components['schemas']['Error'];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
/** @description Forbidden error */
|
||||||
|
403: {
|
||||||
|
content: {
|
||||||
|
'application/json': components['schemas']['Error'];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
/** @description I'm Ai */
|
||||||
|
418: {
|
||||||
|
content: {
|
||||||
|
'application/json': components['schemas']['Error'];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
/** @description To many requests */
|
||||||
|
429: {
|
||||||
|
content: {
|
||||||
|
'application/json': components['schemas']['Error'];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
/** @description Internal server error */
|
||||||
|
500: {
|
||||||
|
content: {
|
||||||
|
'application/json': components['schemas']['Error'];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* blocking-reaction-user/delete
|
||||||
|
* @description No description provided.
|
||||||
|
*
|
||||||
|
* **Credential required**: *Yes* / **Permission**: *write:blocks*
|
||||||
|
*/
|
||||||
|
'blocking-reaction-user___delete': {
|
||||||
|
requestBody: {
|
||||||
|
content: {
|
||||||
|
'application/json': {
|
||||||
|
/** Format: misskey:id */
|
||||||
|
userId: string;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
responses: {
|
||||||
|
/** @description OK (with results) */
|
||||||
|
200: {
|
||||||
|
content: {
|
||||||
|
'application/json': components['schemas']['UserDetailedNotMe'];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
/** @description Client error */
|
||||||
|
400: {
|
||||||
|
content: {
|
||||||
|
'application/json': components['schemas']['Error'];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
/** @description Authentication error */
|
||||||
|
401: {
|
||||||
|
content: {
|
||||||
|
'application/json': components['schemas']['Error'];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
/** @description Forbidden error */
|
||||||
|
403: {
|
||||||
|
content: {
|
||||||
|
'application/json': components['schemas']['Error'];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
/** @description I'm Ai */
|
||||||
|
418: {
|
||||||
|
content: {
|
||||||
|
'application/json': components['schemas']['Error'];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
/** @description To many requests */
|
||||||
|
429: {
|
||||||
|
content: {
|
||||||
|
'application/json': components['schemas']['Error'];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
/** @description Internal server error */
|
||||||
|
500: {
|
||||||
|
content: {
|
||||||
|
'application/json': components['schemas']['Error'];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* blocking-reaction-user/list
|
||||||
|
* @description No description provided.
|
||||||
|
*
|
||||||
|
* **Credential required**: *Yes* / **Permission**: *read:blocks*
|
||||||
|
*/
|
||||||
|
'blocking-reaction-user___list': {
|
||||||
|
requestBody: {
|
||||||
|
content: {
|
||||||
|
'application/json': {
|
||||||
|
/** @default 30 */
|
||||||
|
limit?: number;
|
||||||
|
/** Format: misskey:id */
|
||||||
|
sinceId?: string;
|
||||||
|
/** Format: misskey:id */
|
||||||
|
untilId?: string;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
responses: {
|
||||||
|
/** @description OK (with results) */
|
||||||
|
200: {
|
||||||
|
content: {
|
||||||
|
'application/json': components['schemas']['Blocking'][];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
/** @description Client error */
|
||||||
|
400: {
|
||||||
|
content: {
|
||||||
|
'application/json': components['schemas']['Error'];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
/** @description Authentication error */
|
||||||
|
401: {
|
||||||
|
content: {
|
||||||
|
'application/json': components['schemas']['Error'];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
/** @description Forbidden error */
|
||||||
|
403: {
|
||||||
|
content: {
|
||||||
|
'application/json': components['schemas']['Error'];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
/** @description I'm Ai */
|
||||||
|
418: {
|
||||||
|
content: {
|
||||||
|
'application/json': components['schemas']['Error'];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
/** @description Internal server error */
|
||||||
|
500: {
|
||||||
|
content: {
|
||||||
|
'application/json': components['schemas']['Error'];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
/**
|
/**
|
||||||
* channels/create
|
* channels/create
|
||||||
* @description No description provided.
|
* @description No description provided.
|
||||||
|
|
Loading…
Reference in a new issue