mirror of
https://github.com/paricafe/misskey.git
synced 2024-11-24 10:36:43 -06:00
enhance: 新しいコンディショナルロール条件の実装 (#13732)
* enhance: 新しいコンディショナルロールの実装 * fix: CHANGELOG.md
This commit is contained in:
parent
ea9aa6fdb4
commit
cd7f7271ca
12 changed files with 624 additions and 74 deletions
|
@ -8,6 +8,12 @@
|
||||||
- Enhance: アンテナでBotによるノートを除外できるように
|
- Enhance: アンテナでBotによるノートを除外できるように
|
||||||
(Cherry-picked from https://github.com/MisskeyIO/misskey/pull/545)
|
(Cherry-picked from https://github.com/MisskeyIO/misskey/pull/545)
|
||||||
- Enhance: クリップのノート数を表示するように
|
- Enhance: クリップのノート数を表示するように
|
||||||
|
- Enhance: コンディショナルロールの条件として以下を新たに追加 (#13667)
|
||||||
|
- 猫ユーザーか
|
||||||
|
- botユーザーか
|
||||||
|
- サスペンド済みユーザーか
|
||||||
|
- 鍵アカウントユーザーか
|
||||||
|
- 「アカウントを見つけやすくする」が有効なユーザーか
|
||||||
- Fix: Play作成時に設定した公開範囲が機能していない問題を修正
|
- Fix: Play作成時に設定した公開範囲が機能していない問題を修正
|
||||||
|
|
||||||
### Client
|
### Client
|
||||||
|
|
20
locales/index.d.ts
vendored
20
locales/index.d.ts
vendored
|
@ -6592,6 +6592,26 @@ export interface Locale extends ILocale {
|
||||||
* リモートユーザー
|
* リモートユーザー
|
||||||
*/
|
*/
|
||||||
"isRemote": string;
|
"isRemote": string;
|
||||||
|
/**
|
||||||
|
* 猫ユーザー
|
||||||
|
*/
|
||||||
|
"isCat": string;
|
||||||
|
/**
|
||||||
|
* botユーザー
|
||||||
|
*/
|
||||||
|
"isBot": string;
|
||||||
|
/**
|
||||||
|
* サスペンド済みユーザー
|
||||||
|
*/
|
||||||
|
"isSuspended": string;
|
||||||
|
/**
|
||||||
|
* 鍵アカウントユーザー
|
||||||
|
*/
|
||||||
|
"isLocked": string;
|
||||||
|
/**
|
||||||
|
* 「アカウントを見つけやすくする」が有効なユーザー
|
||||||
|
*/
|
||||||
|
"isExplorable": string;
|
||||||
/**
|
/**
|
||||||
* アカウント作成から~以内
|
* アカウント作成から~以内
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -1703,6 +1703,11 @@ _role:
|
||||||
roleAssignedTo: "マニュアルロールにアサイン済み"
|
roleAssignedTo: "マニュアルロールにアサイン済み"
|
||||||
isLocal: "ローカルユーザー"
|
isLocal: "ローカルユーザー"
|
||||||
isRemote: "リモートユーザー"
|
isRemote: "リモートユーザー"
|
||||||
|
isCat: "猫ユーザー"
|
||||||
|
isBot: "botユーザー"
|
||||||
|
isSuspended: "サスペンド済みユーザー"
|
||||||
|
isLocked: "鍵アカウントユーザー"
|
||||||
|
isExplorable: "「アカウントを見つけやすくする」が有効なユーザー"
|
||||||
createdLessThan: "アカウント作成から~以内"
|
createdLessThan: "アカウント作成から~以内"
|
||||||
createdMoreThan: "アカウント作成から~経過"
|
createdMoreThan: "アカウント作成から~経過"
|
||||||
followersLessThanOrEq: "フォロワー数が~以下"
|
followersLessThanOrEq: "フォロワー数が~以下"
|
||||||
|
|
|
@ -205,45 +205,79 @@ export class RoleService implements OnApplicationShutdown, OnModuleInit {
|
||||||
private evalCond(user: MiUser, roles: MiRole[], value: RoleCondFormulaValue): boolean {
|
private evalCond(user: MiUser, roles: MiRole[], value: RoleCondFormulaValue): boolean {
|
||||||
try {
|
try {
|
||||||
switch (value.type) {
|
switch (value.type) {
|
||||||
|
// ~かつ~
|
||||||
case 'and': {
|
case 'and': {
|
||||||
return value.values.every(v => this.evalCond(user, roles, v));
|
return value.values.every(v => this.evalCond(user, roles, v));
|
||||||
}
|
}
|
||||||
|
// ~または~
|
||||||
case 'or': {
|
case 'or': {
|
||||||
return value.values.some(v => this.evalCond(user, roles, v));
|
return value.values.some(v => this.evalCond(user, roles, v));
|
||||||
}
|
}
|
||||||
|
// ~ではない
|
||||||
case 'not': {
|
case 'not': {
|
||||||
return !this.evalCond(user, roles, value.value);
|
return !this.evalCond(user, roles, value.value);
|
||||||
}
|
}
|
||||||
|
// マニュアルロールがアサインされている
|
||||||
case 'roleAssignedTo': {
|
case 'roleAssignedTo': {
|
||||||
return roles.some(r => r.id === value.roleId);
|
return roles.some(r => r.id === value.roleId);
|
||||||
}
|
}
|
||||||
|
// ローカルユーザのみ
|
||||||
case 'isLocal': {
|
case 'isLocal': {
|
||||||
return this.userEntityService.isLocalUser(user);
|
return this.userEntityService.isLocalUser(user);
|
||||||
}
|
}
|
||||||
|
// リモートユーザのみ
|
||||||
case 'isRemote': {
|
case 'isRemote': {
|
||||||
return this.userEntityService.isRemoteUser(user);
|
return this.userEntityService.isRemoteUser(user);
|
||||||
}
|
}
|
||||||
|
// サスペンド済みユーザである
|
||||||
|
case 'isSuspended': {
|
||||||
|
return user.isSuspended;
|
||||||
|
}
|
||||||
|
// 鍵アカウントユーザである
|
||||||
|
case 'isLocked': {
|
||||||
|
return user.isLocked;
|
||||||
|
}
|
||||||
|
// botユーザである
|
||||||
|
case 'isBot': {
|
||||||
|
return user.isBot;
|
||||||
|
}
|
||||||
|
// 猫である
|
||||||
|
case 'isCat': {
|
||||||
|
return user.isCat;
|
||||||
|
}
|
||||||
|
// 「ユーザを見つけやすくする」が有効なアカウント
|
||||||
|
case 'isExplorable': {
|
||||||
|
return user.isExplorable;
|
||||||
|
}
|
||||||
|
// ユーザが作成されてから指定期間経過した
|
||||||
case 'createdLessThan': {
|
case 'createdLessThan': {
|
||||||
return this.idService.parse(user.id).date.getTime() > (Date.now() - (value.sec * 1000));
|
return this.idService.parse(user.id).date.getTime() > (Date.now() - (value.sec * 1000));
|
||||||
}
|
}
|
||||||
|
// ユーザが作成されてから指定期間経っていない
|
||||||
case 'createdMoreThan': {
|
case 'createdMoreThan': {
|
||||||
return this.idService.parse(user.id).date.getTime() < (Date.now() - (value.sec * 1000));
|
return this.idService.parse(user.id).date.getTime() < (Date.now() - (value.sec * 1000));
|
||||||
}
|
}
|
||||||
|
// フォロワー数が指定値以下
|
||||||
case 'followersLessThanOrEq': {
|
case 'followersLessThanOrEq': {
|
||||||
return user.followersCount <= value.value;
|
return user.followersCount <= value.value;
|
||||||
}
|
}
|
||||||
|
// フォロワー数が指定値以上
|
||||||
case 'followersMoreThanOrEq': {
|
case 'followersMoreThanOrEq': {
|
||||||
return user.followersCount >= value.value;
|
return user.followersCount >= value.value;
|
||||||
}
|
}
|
||||||
|
// フォロー数が指定値以下
|
||||||
case 'followingLessThanOrEq': {
|
case 'followingLessThanOrEq': {
|
||||||
return user.followingCount <= value.value;
|
return user.followingCount <= value.value;
|
||||||
}
|
}
|
||||||
|
// フォロー数が指定値以上
|
||||||
case 'followingMoreThanOrEq': {
|
case 'followingMoreThanOrEq': {
|
||||||
return user.followingCount >= value.value;
|
return user.followingCount >= value.value;
|
||||||
}
|
}
|
||||||
|
// ノート数が指定値以下
|
||||||
case 'notesLessThanOrEq': {
|
case 'notesLessThanOrEq': {
|
||||||
return user.notesCount <= value.value;
|
return user.notesCount <= value.value;
|
||||||
}
|
}
|
||||||
|
// ノート数が指定値以上
|
||||||
case 'notesMoreThanOrEq': {
|
case 'notesMoreThanOrEq': {
|
||||||
return user.notesCount >= value.value;
|
return user.notesCount >= value.value;
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,6 +48,7 @@ import {
|
||||||
packedRoleCondFormulaValueCreatedSchema,
|
packedRoleCondFormulaValueCreatedSchema,
|
||||||
packedRoleCondFormulaFollowersOrFollowingOrNotesSchema,
|
packedRoleCondFormulaFollowersOrFollowingOrNotesSchema,
|
||||||
packedRoleCondFormulaValueSchema,
|
packedRoleCondFormulaValueSchema,
|
||||||
|
packedRoleCondFormulaValueUserSettingBooleanSchema,
|
||||||
} from '@/models/json-schema/role.js';
|
} from '@/models/json-schema/role.js';
|
||||||
import { packedAdSchema } from '@/models/json-schema/ad.js';
|
import { packedAdSchema } from '@/models/json-schema/ad.js';
|
||||||
import { packedReversiGameLiteSchema, packedReversiGameDetailedSchema } from '@/models/json-schema/reversi-game.js';
|
import { packedReversiGameLiteSchema, packedReversiGameDetailedSchema } from '@/models/json-schema/reversi-game.js';
|
||||||
|
@ -97,6 +98,7 @@ export const refs = {
|
||||||
RoleCondFormulaLogics: packedRoleCondFormulaLogicsSchema,
|
RoleCondFormulaLogics: packedRoleCondFormulaLogicsSchema,
|
||||||
RoleCondFormulaValueNot: packedRoleCondFormulaValueNot,
|
RoleCondFormulaValueNot: packedRoleCondFormulaValueNot,
|
||||||
RoleCondFormulaValueIsLocalOrRemote: packedRoleCondFormulaValueIsLocalOrRemoteSchema,
|
RoleCondFormulaValueIsLocalOrRemote: packedRoleCondFormulaValueIsLocalOrRemoteSchema,
|
||||||
|
RoleCondFormulaValueUserSettingBooleanSchema: packedRoleCondFormulaValueUserSettingBooleanSchema,
|
||||||
RoleCondFormulaValueAssignedRole: packedRoleCondFormulaValueAssignedRoleSchema,
|
RoleCondFormulaValueAssignedRole: packedRoleCondFormulaValueAssignedRoleSchema,
|
||||||
RoleCondFormulaValueCreated: packedRoleCondFormulaValueCreatedSchema,
|
RoleCondFormulaValueCreated: packedRoleCondFormulaValueCreatedSchema,
|
||||||
RoleCondFormulaFollowersOrFollowingOrNotes: packedRoleCondFormulaFollowersOrFollowingOrNotesSchema,
|
RoleCondFormulaFollowersOrFollowingOrNotes: packedRoleCondFormulaFollowersOrFollowingOrNotesSchema,
|
||||||
|
|
|
@ -6,69 +6,149 @@
|
||||||
import { Entity, Column, PrimaryColumn } from 'typeorm';
|
import { Entity, Column, PrimaryColumn } from 'typeorm';
|
||||||
import { id } from './util/id.js';
|
import { id } from './util/id.js';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ~かつ~
|
||||||
|
* 複数の条件を同時に満たす場合のみ成立とする
|
||||||
|
*/
|
||||||
type CondFormulaValueAnd = {
|
type CondFormulaValueAnd = {
|
||||||
type: 'and';
|
type: 'and';
|
||||||
values: RoleCondFormulaValue[];
|
values: RoleCondFormulaValue[];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ~または~
|
||||||
|
* 複数の条件のうち、いずれかを満たす場合のみ成立とする
|
||||||
|
*/
|
||||||
type CondFormulaValueOr = {
|
type CondFormulaValueOr = {
|
||||||
type: 'or';
|
type: 'or';
|
||||||
values: RoleCondFormulaValue[];
|
values: RoleCondFormulaValue[];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ~ではない
|
||||||
|
* 条件を満たさない場合のみ成立とする
|
||||||
|
*/
|
||||||
type CondFormulaValueNot = {
|
type CondFormulaValueNot = {
|
||||||
type: 'not';
|
type: 'not';
|
||||||
value: RoleCondFormulaValue;
|
value: RoleCondFormulaValue;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ローカルユーザーのみ成立とする
|
||||||
|
*/
|
||||||
type CondFormulaValueIsLocal = {
|
type CondFormulaValueIsLocal = {
|
||||||
type: 'isLocal';
|
type: 'isLocal';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* リモートユーザーのみ成立とする
|
||||||
|
*/
|
||||||
type CondFormulaValueIsRemote = {
|
type CondFormulaValueIsRemote = {
|
||||||
type: 'isRemote';
|
type: 'isRemote';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 既に指定のマニュアルロールにアサインされている場合のみ成立とする
|
||||||
|
*/
|
||||||
type CondFormulaValueRoleAssignedTo = {
|
type CondFormulaValueRoleAssignedTo = {
|
||||||
type: 'roleAssignedTo';
|
type: 'roleAssignedTo';
|
||||||
roleId: string;
|
roleId: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* サスペンド済みアカウントの場合のみ成立とする
|
||||||
|
*/
|
||||||
|
type CondFormulaValueIsSuspended = {
|
||||||
|
type: 'isSuspended';
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 鍵アカウントの場合のみ成立とする
|
||||||
|
*/
|
||||||
|
type CondFormulaValueIsLocked = {
|
||||||
|
type: 'isLocked';
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* botアカウントの場合のみ成立とする
|
||||||
|
*/
|
||||||
|
type CondFormulaValueIsBot = {
|
||||||
|
type: 'isBot';
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 猫アカウントの場合のみ成立とする
|
||||||
|
*/
|
||||||
|
type CondFormulaValueIsCat = {
|
||||||
|
type: 'isCat';
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 「ユーザを見つけやすくする」が有効なアカウントの場合のみ成立とする
|
||||||
|
*/
|
||||||
|
type CondFormulaValueIsExplorable = {
|
||||||
|
type: 'isExplorable';
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ユーザが作成されてから指定期間経過した場合のみ成立とする
|
||||||
|
*/
|
||||||
type CondFormulaValueCreatedLessThan = {
|
type CondFormulaValueCreatedLessThan = {
|
||||||
type: 'createdLessThan';
|
type: 'createdLessThan';
|
||||||
sec: number;
|
sec: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ユーザが作成されてから指定期間経っていない場合のみ成立とする
|
||||||
|
*/
|
||||||
type CondFormulaValueCreatedMoreThan = {
|
type CondFormulaValueCreatedMoreThan = {
|
||||||
type: 'createdMoreThan';
|
type: 'createdMoreThan';
|
||||||
sec: number;
|
sec: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* フォロワー数が指定値以下の場合のみ成立とする
|
||||||
|
*/
|
||||||
type CondFormulaValueFollowersLessThanOrEq = {
|
type CondFormulaValueFollowersLessThanOrEq = {
|
||||||
type: 'followersLessThanOrEq';
|
type: 'followersLessThanOrEq';
|
||||||
value: number;
|
value: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* フォロワー数が指定値以上の場合のみ成立とする
|
||||||
|
*/
|
||||||
type CondFormulaValueFollowersMoreThanOrEq = {
|
type CondFormulaValueFollowersMoreThanOrEq = {
|
||||||
type: 'followersMoreThanOrEq';
|
type: 'followersMoreThanOrEq';
|
||||||
value: number;
|
value: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* フォロー数が指定値以下の場合のみ成立とする
|
||||||
|
*/
|
||||||
type CondFormulaValueFollowingLessThanOrEq = {
|
type CondFormulaValueFollowingLessThanOrEq = {
|
||||||
type: 'followingLessThanOrEq';
|
type: 'followingLessThanOrEq';
|
||||||
value: number;
|
value: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* フォロー数が指定値以上の場合のみ成立とする
|
||||||
|
*/
|
||||||
type CondFormulaValueFollowingMoreThanOrEq = {
|
type CondFormulaValueFollowingMoreThanOrEq = {
|
||||||
type: 'followingMoreThanOrEq';
|
type: 'followingMoreThanOrEq';
|
||||||
value: number;
|
value: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 投稿数が指定値以下の場合のみ成立とする
|
||||||
|
*/
|
||||||
type CondFormulaValueNotesLessThanOrEq = {
|
type CondFormulaValueNotesLessThanOrEq = {
|
||||||
type: 'notesLessThanOrEq';
|
type: 'notesLessThanOrEq';
|
||||||
value: number;
|
value: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 投稿数が指定値以上の場合のみ成立とする
|
||||||
|
*/
|
||||||
type CondFormulaValueNotesMoreThanOrEq = {
|
type CondFormulaValueNotesMoreThanOrEq = {
|
||||||
type: 'notesMoreThanOrEq';
|
type: 'notesMoreThanOrEq';
|
||||||
value: number;
|
value: number;
|
||||||
|
@ -80,6 +160,11 @@ export type RoleCondFormulaValue = { id: string } & (
|
||||||
CondFormulaValueNot |
|
CondFormulaValueNot |
|
||||||
CondFormulaValueIsLocal |
|
CondFormulaValueIsLocal |
|
||||||
CondFormulaValueIsRemote |
|
CondFormulaValueIsRemote |
|
||||||
|
CondFormulaValueIsSuspended |
|
||||||
|
CondFormulaValueIsLocked |
|
||||||
|
CondFormulaValueIsBot |
|
||||||
|
CondFormulaValueIsCat |
|
||||||
|
CondFormulaValueIsExplorable |
|
||||||
CondFormulaValueRoleAssignedTo |
|
CondFormulaValueRoleAssignedTo |
|
||||||
CondFormulaValueCreatedLessThan |
|
CondFormulaValueCreatedLessThan |
|
||||||
CondFormulaValueCreatedMoreThan |
|
CondFormulaValueCreatedMoreThan |
|
||||||
|
|
|
@ -57,6 +57,20 @@ export const packedRoleCondFormulaValueIsLocalOrRemoteSchema = {
|
||||||
},
|
},
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
|
export const packedRoleCondFormulaValueUserSettingBooleanSchema = {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
id: {
|
||||||
|
type: 'string', optional: false,
|
||||||
|
},
|
||||||
|
type: {
|
||||||
|
type: 'string',
|
||||||
|
nullable: false, optional: false,
|
||||||
|
enum: ['isSuspended', 'isLocked', 'isBot', 'isCat', 'isExplorable'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} as const;
|
||||||
|
|
||||||
export const packedRoleCondFormulaValueAssignedRoleSchema = {
|
export const packedRoleCondFormulaValueAssignedRoleSchema = {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
properties: {
|
properties: {
|
||||||
|
@ -135,6 +149,9 @@ export const packedRoleCondFormulaValueSchema = {
|
||||||
{
|
{
|
||||||
ref: 'RoleCondFormulaValueIsLocalOrRemote',
|
ref: 'RoleCondFormulaValueIsLocalOrRemote',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
ref: 'RoleCondFormulaValueUserSettingBooleanSchema',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
ref: 'RoleCondFormulaValueAssignedRole',
|
ref: 'RoleCondFormulaValueAssignedRole',
|
||||||
},
|
},
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
||||||
|
|
||||||
process.env.NODE_ENV = 'test';
|
process.env.NODE_ENV = 'test';
|
||||||
|
|
||||||
import { jest } from '@jest/globals';
|
import { jest } from '@jest/globals';
|
||||||
|
@ -20,6 +22,7 @@ import { IdService } from '@/core/IdService.js';
|
||||||
import { GlobalEventService } from '@/core/GlobalEventService.js';
|
import { GlobalEventService } from '@/core/GlobalEventService.js';
|
||||||
import { secureRndstr } from '@/misc/secure-rndstr.js';
|
import { secureRndstr } from '@/misc/secure-rndstr.js';
|
||||||
import { NotificationService } from '@/core/NotificationService.js';
|
import { NotificationService } from '@/core/NotificationService.js';
|
||||||
|
import { RoleCondFormulaValue } from '@/models/Role.js';
|
||||||
import { sleep } from '../utils.js';
|
import { sleep } from '../utils.js';
|
||||||
import type { TestingModule } from '@nestjs/testing';
|
import type { TestingModule } from '@nestjs/testing';
|
||||||
import type { MockFunctionMetadata } from 'jest-mock';
|
import type { MockFunctionMetadata } from 'jest-mock';
|
||||||
|
@ -52,12 +55,26 @@ describe('RoleService', () => {
|
||||||
id: genAidx(Date.now()),
|
id: genAidx(Date.now()),
|
||||||
updatedAt: new Date(),
|
updatedAt: new Date(),
|
||||||
lastUsedAt: new Date(),
|
lastUsedAt: new Date(),
|
||||||
|
name: '',
|
||||||
description: '',
|
description: '',
|
||||||
...data,
|
...data,
|
||||||
})
|
})
|
||||||
.then(x => rolesRepository.findOneByOrFail(x.identifiers[0]));
|
.then(x => rolesRepository.findOneByOrFail(x.identifiers[0]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function createConditionalRole(condFormula: RoleCondFormulaValue, data: Partial<MiRole> = {}) {
|
||||||
|
return createRole({
|
||||||
|
name: `[conditional] ${condFormula.type}`,
|
||||||
|
target: 'conditional',
|
||||||
|
condFormula: condFormula,
|
||||||
|
...data,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function aidx() {
|
||||||
|
return genAidx(Date.now());
|
||||||
|
}
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
clock = lolex.install({
|
clock = lolex.install({
|
||||||
now: new Date(),
|
now: new Date(),
|
||||||
|
@ -73,6 +90,7 @@ describe('RoleService', () => {
|
||||||
CacheService,
|
CacheService,
|
||||||
IdService,
|
IdService,
|
||||||
GlobalEventService,
|
GlobalEventService,
|
||||||
|
UserEntityService,
|
||||||
{
|
{
|
||||||
provide: NotificationService,
|
provide: NotificationService,
|
||||||
useFactory: () => ({
|
useFactory: () => ({
|
||||||
|
@ -209,79 +227,6 @@ describe('RoleService', () => {
|
||||||
expect(result.driveCapacityMb).toBe(100);
|
expect(result.driveCapacityMb).toBe(100);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('conditional role', async () => {
|
|
||||||
const user1 = await createUser({
|
|
||||||
id: genAidx(Date.now() - (1000 * 60 * 60 * 24 * 365)),
|
|
||||||
});
|
|
||||||
const user2 = await createUser({
|
|
||||||
id: genAidx(Date.now() - (1000 * 60 * 60 * 24 * 365)),
|
|
||||||
followersCount: 10,
|
|
||||||
});
|
|
||||||
await createRole({
|
|
||||||
name: 'a',
|
|
||||||
policies: {
|
|
||||||
canManageCustomEmojis: {
|
|
||||||
useDefault: false,
|
|
||||||
priority: 0,
|
|
||||||
value: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
target: 'conditional',
|
|
||||||
condFormula: {
|
|
||||||
id: '232a4221-9816-49a6-a967-ae0fac52ec5e',
|
|
||||||
type: 'and',
|
|
||||||
values: [{
|
|
||||||
id: '2a37ef43-2d93-4c4d-87f6-f2fdb7d9b530',
|
|
||||||
type: 'followersMoreThanOrEq',
|
|
||||||
value: 10,
|
|
||||||
}, {
|
|
||||||
id: '1bd67839-b126-4f92-bad0-4e285dab453b',
|
|
||||||
type: 'createdMoreThan',
|
|
||||||
sec: 60 * 60 * 24 * 7,
|
|
||||||
}],
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
metaService.fetch.mockResolvedValue({
|
|
||||||
policies: {
|
|
||||||
canManageCustomEmojis: false,
|
|
||||||
},
|
|
||||||
} as any);
|
|
||||||
|
|
||||||
const user1Policies = await roleService.getUserPolicies(user1.id);
|
|
||||||
const user2Policies = await roleService.getUserPolicies(user2.id);
|
|
||||||
expect(user1Policies.canManageCustomEmojis).toBe(false);
|
|
||||||
expect(user2Policies.canManageCustomEmojis).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('コンディショナルロール: マニュアルロールにアサイン済み', async () => {
|
|
||||||
const [user1, user2, role1] = await Promise.all([
|
|
||||||
createUser(),
|
|
||||||
createUser(),
|
|
||||||
createRole({
|
|
||||||
name: 'manual role',
|
|
||||||
}),
|
|
||||||
]);
|
|
||||||
const role2 = await createRole({
|
|
||||||
name: 'conditional role',
|
|
||||||
target: 'conditional',
|
|
||||||
condFormula: {
|
|
||||||
// idはバックエンドのロジックに必要ない?
|
|
||||||
id: 'bdc612bd-9d54-4675-ae83-0499c82ea670',
|
|
||||||
type: 'roleAssignedTo',
|
|
||||||
roleId: role1.id,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
await roleService.assign(user2.id, role1.id);
|
|
||||||
|
|
||||||
const [u1role, u2role] = await Promise.all([
|
|
||||||
roleService.getUserRoles(user1.id),
|
|
||||||
roleService.getUserRoles(user2.id),
|
|
||||||
]);
|
|
||||||
expect(u1role.some(r => r.id === role2.id)).toBe(false);
|
|
||||||
expect(u2role.some(r => r.id === role2.id)).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('expired role', async () => {
|
test('expired role', async () => {
|
||||||
const user = await createUser();
|
const user = await createUser();
|
||||||
const role = await createRole({
|
const role = await createRole({
|
||||||
|
@ -320,6 +265,427 @@ describe('RoleService', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('conditional role', () => {
|
||||||
|
test('~かつ~', async () => {
|
||||||
|
const [user1, user2, user3, user4] = await Promise.all([
|
||||||
|
createUser({ isBot: true, isCat: false, isSuspended: false }),
|
||||||
|
createUser({ isBot: false, isCat: true, isSuspended: false }),
|
||||||
|
createUser({ isBot: true, isCat: true, isSuspended: false }),
|
||||||
|
createUser({ isBot: false, isCat: false, isSuspended: true }),
|
||||||
|
]);
|
||||||
|
const role1 = await createConditionalRole({
|
||||||
|
id: aidx(),
|
||||||
|
type: 'isBot',
|
||||||
|
});
|
||||||
|
const role2 = await createConditionalRole({
|
||||||
|
id: aidx(),
|
||||||
|
type: 'isCat',
|
||||||
|
});
|
||||||
|
const role3 = await createConditionalRole({
|
||||||
|
id: aidx(),
|
||||||
|
type: 'isSuspended',
|
||||||
|
});
|
||||||
|
const role4 = await createConditionalRole({
|
||||||
|
id: aidx(),
|
||||||
|
type: 'and',
|
||||||
|
values: [role1.condFormula, role2.condFormula],
|
||||||
|
});
|
||||||
|
|
||||||
|
const actual1 = await roleService.getUserRoles(user1.id);
|
||||||
|
const actual2 = await roleService.getUserRoles(user2.id);
|
||||||
|
const actual3 = await roleService.getUserRoles(user3.id);
|
||||||
|
const actual4 = await roleService.getUserRoles(user4.id);
|
||||||
|
expect(actual1.some(r => r.id === role4.id)).toBe(false);
|
||||||
|
expect(actual2.some(r => r.id === role4.id)).toBe(false);
|
||||||
|
expect(actual3.some(r => r.id === role4.id)).toBe(true);
|
||||||
|
expect(actual4.some(r => r.id === role4.id)).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('~または~', async () => {
|
||||||
|
const [user1, user2, user3, user4] = await Promise.all([
|
||||||
|
createUser({ isBot: true, isCat: false, isSuspended: false }),
|
||||||
|
createUser({ isBot: false, isCat: true, isSuspended: false }),
|
||||||
|
createUser({ isBot: true, isCat: true, isSuspended: false }),
|
||||||
|
createUser({ isBot: false, isCat: false, isSuspended: true }),
|
||||||
|
]);
|
||||||
|
const role1 = await createConditionalRole({
|
||||||
|
id: aidx(),
|
||||||
|
type: 'isBot',
|
||||||
|
});
|
||||||
|
const role2 = await createConditionalRole({
|
||||||
|
id: aidx(),
|
||||||
|
type: 'isCat',
|
||||||
|
});
|
||||||
|
const role3 = await createConditionalRole({
|
||||||
|
id: aidx(),
|
||||||
|
type: 'isSuspended',
|
||||||
|
});
|
||||||
|
const role4 = await createConditionalRole({
|
||||||
|
id: aidx(),
|
||||||
|
type: 'or',
|
||||||
|
values: [role1.condFormula, role2.condFormula],
|
||||||
|
});
|
||||||
|
|
||||||
|
const actual1 = await roleService.getUserRoles(user1.id);
|
||||||
|
const actual2 = await roleService.getUserRoles(user2.id);
|
||||||
|
const actual3 = await roleService.getUserRoles(user3.id);
|
||||||
|
const actual4 = await roleService.getUserRoles(user4.id);
|
||||||
|
expect(actual1.some(r => r.id === role4.id)).toBe(true);
|
||||||
|
expect(actual2.some(r => r.id === role4.id)).toBe(true);
|
||||||
|
expect(actual3.some(r => r.id === role4.id)).toBe(true);
|
||||||
|
expect(actual4.some(r => r.id === role4.id)).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('~ではない', async () => {
|
||||||
|
const [user1, user2, user3] = await Promise.all([
|
||||||
|
createUser({ isBot: true, isCat: false, isSuspended: false }),
|
||||||
|
createUser({ isBot: false, isCat: true, isSuspended: false }),
|
||||||
|
createUser({ isBot: true, isCat: true, isSuspended: false }),
|
||||||
|
]);
|
||||||
|
const role1 = await createConditionalRole({
|
||||||
|
id: aidx(),
|
||||||
|
type: 'isBot',
|
||||||
|
});
|
||||||
|
const role2 = await createConditionalRole({
|
||||||
|
id: aidx(),
|
||||||
|
type: 'isCat',
|
||||||
|
});
|
||||||
|
const role4 = await createConditionalRole({
|
||||||
|
id: aidx(),
|
||||||
|
type: 'not',
|
||||||
|
value: role1.condFormula,
|
||||||
|
});
|
||||||
|
|
||||||
|
const actual1 = await roleService.getUserRoles(user1.id);
|
||||||
|
const actual2 = await roleService.getUserRoles(user2.id);
|
||||||
|
const actual3 = await roleService.getUserRoles(user3.id);
|
||||||
|
expect(actual1.some(r => r.id === role4.id)).toBe(false);
|
||||||
|
expect(actual2.some(r => r.id === role4.id)).toBe(true);
|
||||||
|
expect(actual3.some(r => r.id === role4.id)).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('マニュアルロールにアサイン済み', async () => {
|
||||||
|
const [user1, user2, role1] = await Promise.all([
|
||||||
|
createUser(),
|
||||||
|
createUser(),
|
||||||
|
createRole({
|
||||||
|
name: 'manual role',
|
||||||
|
}),
|
||||||
|
]);
|
||||||
|
const role2 = await createConditionalRole({
|
||||||
|
id: aidx(),
|
||||||
|
type: 'roleAssignedTo',
|
||||||
|
roleId: role1.id,
|
||||||
|
});
|
||||||
|
await roleService.assign(user2.id, role1.id);
|
||||||
|
|
||||||
|
const [u1role, u2role] = await Promise.all([
|
||||||
|
roleService.getUserRoles(user1.id),
|
||||||
|
roleService.getUserRoles(user2.id),
|
||||||
|
]);
|
||||||
|
expect(u1role.some(r => r.id === role2.id)).toBe(false);
|
||||||
|
expect(u2role.some(r => r.id === role2.id)).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('ローカルユーザのみ', async () => {
|
||||||
|
const [user1, user2] = await Promise.all([
|
||||||
|
createUser({ host: null }),
|
||||||
|
createUser({ host: 'example.com' }),
|
||||||
|
]);
|
||||||
|
const role = await createConditionalRole({
|
||||||
|
id: aidx(),
|
||||||
|
type: 'isLocal',
|
||||||
|
});
|
||||||
|
|
||||||
|
const actual1 = await roleService.getUserRoles(user1.id);
|
||||||
|
const actual2 = await roleService.getUserRoles(user2.id);
|
||||||
|
expect(actual1.some(r => r.id === role.id)).toBe(true);
|
||||||
|
expect(actual2.some(r => r.id === role.id)).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('リモートユーザのみ', async () => {
|
||||||
|
const [user1, user2] = await Promise.all([
|
||||||
|
createUser({ host: null }),
|
||||||
|
createUser({ host: 'example.com' }),
|
||||||
|
]);
|
||||||
|
const role = await createConditionalRole({
|
||||||
|
id: aidx(),
|
||||||
|
type: 'isRemote',
|
||||||
|
});
|
||||||
|
|
||||||
|
const actual1 = await roleService.getUserRoles(user1.id);
|
||||||
|
const actual2 = await roleService.getUserRoles(user2.id);
|
||||||
|
expect(actual1.some(r => r.id === role.id)).toBe(false);
|
||||||
|
expect(actual2.some(r => r.id === role.id)).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('サスペンド済みユーザである', async () => {
|
||||||
|
const [user1, user2] = await Promise.all([
|
||||||
|
createUser({ isSuspended: false }),
|
||||||
|
createUser({ isSuspended: true }),
|
||||||
|
]);
|
||||||
|
const role = await createConditionalRole({
|
||||||
|
id: aidx(),
|
||||||
|
type: 'isSuspended',
|
||||||
|
});
|
||||||
|
|
||||||
|
const actual1 = await roleService.getUserRoles(user1.id);
|
||||||
|
const actual2 = await roleService.getUserRoles(user2.id);
|
||||||
|
expect(actual1.some(r => r.id === role.id)).toBe(false);
|
||||||
|
expect(actual2.some(r => r.id === role.id)).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('鍵アカウントユーザである', async () => {
|
||||||
|
const [user1, user2] = await Promise.all([
|
||||||
|
createUser({ isLocked: false }),
|
||||||
|
createUser({ isLocked: true }),
|
||||||
|
]);
|
||||||
|
const role = await createConditionalRole({
|
||||||
|
id: aidx(),
|
||||||
|
type: 'isLocked',
|
||||||
|
});
|
||||||
|
|
||||||
|
const actual1 = await roleService.getUserRoles(user1.id);
|
||||||
|
const actual2 = await roleService.getUserRoles(user2.id);
|
||||||
|
expect(actual1.some(r => r.id === role.id)).toBe(false);
|
||||||
|
expect(actual2.some(r => r.id === role.id)).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('botユーザである', async () => {
|
||||||
|
const [user1, user2] = await Promise.all([
|
||||||
|
createUser({ isBot: false }),
|
||||||
|
createUser({ isBot: true }),
|
||||||
|
]);
|
||||||
|
const role = await createConditionalRole({
|
||||||
|
id: aidx(),
|
||||||
|
type: 'isBot',
|
||||||
|
});
|
||||||
|
|
||||||
|
const actual1 = await roleService.getUserRoles(user1.id);
|
||||||
|
const actual2 = await roleService.getUserRoles(user2.id);
|
||||||
|
expect(actual1.some(r => r.id === role.id)).toBe(false);
|
||||||
|
expect(actual2.some(r => r.id === role.id)).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('猫である', async () => {
|
||||||
|
const [user1, user2] = await Promise.all([
|
||||||
|
createUser({ isCat: false }),
|
||||||
|
createUser({ isCat: true }),
|
||||||
|
]);
|
||||||
|
const role = await createConditionalRole({
|
||||||
|
id: aidx(),
|
||||||
|
type: 'isCat',
|
||||||
|
});
|
||||||
|
|
||||||
|
const actual1 = await roleService.getUserRoles(user1.id);
|
||||||
|
const actual2 = await roleService.getUserRoles(user2.id);
|
||||||
|
expect(actual1.some(r => r.id === role.id)).toBe(false);
|
||||||
|
expect(actual2.some(r => r.id === role.id)).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('「ユーザを見つけやすくする」が有効なアカウント', async () => {
|
||||||
|
const [user1, user2] = await Promise.all([
|
||||||
|
createUser({ isExplorable: false }),
|
||||||
|
createUser({ isExplorable: true }),
|
||||||
|
]);
|
||||||
|
const role = await createConditionalRole({
|
||||||
|
id: aidx(),
|
||||||
|
type: 'isExplorable',
|
||||||
|
});
|
||||||
|
|
||||||
|
const actual1 = await roleService.getUserRoles(user1.id);
|
||||||
|
const actual2 = await roleService.getUserRoles(user2.id);
|
||||||
|
expect(actual1.some(r => r.id === role.id)).toBe(false);
|
||||||
|
expect(actual2.some(r => r.id === role.id)).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('ユーザが作成されてから指定期間経過した', async () => {
|
||||||
|
const base = new Date();
|
||||||
|
base.setMinutes(base.getMinutes() - 5);
|
||||||
|
|
||||||
|
const d1 = new Date(base);
|
||||||
|
const d2 = new Date(base);
|
||||||
|
const d3 = new Date(base);
|
||||||
|
d1.setSeconds(d1.getSeconds() - 1);
|
||||||
|
d3.setSeconds(d3.getSeconds() + 1);
|
||||||
|
|
||||||
|
const [user1, user2, user3] = await Promise.all([
|
||||||
|
// 4:59
|
||||||
|
createUser({ id: genAidx(d1.getTime()) }),
|
||||||
|
// 5:00
|
||||||
|
createUser({ id: genAidx(d2.getTime()) }),
|
||||||
|
// 5:01
|
||||||
|
createUser({ id: genAidx(d3.getTime()) }),
|
||||||
|
]);
|
||||||
|
const role = await createConditionalRole({
|
||||||
|
id: aidx(),
|
||||||
|
type: 'createdLessThan',
|
||||||
|
// 5 minutes
|
||||||
|
sec: 300,
|
||||||
|
});
|
||||||
|
|
||||||
|
const actual1 = await roleService.getUserRoles(user1.id);
|
||||||
|
const actual2 = await roleService.getUserRoles(user2.id);
|
||||||
|
const actual3 = await roleService.getUserRoles(user3.id);
|
||||||
|
expect(actual1.some(r => r.id === role.id)).toBe(false);
|
||||||
|
expect(actual2.some(r => r.id === role.id)).toBe(false);
|
||||||
|
expect(actual3.some(r => r.id === role.id)).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('ユーザが作成されてから指定期間経っていない', async () => {
|
||||||
|
const base = new Date();
|
||||||
|
base.setMinutes(base.getMinutes() - 5);
|
||||||
|
|
||||||
|
const d1 = new Date(base);
|
||||||
|
const d2 = new Date(base);
|
||||||
|
const d3 = new Date(base);
|
||||||
|
d1.setSeconds(d1.getSeconds() - 1);
|
||||||
|
d3.setSeconds(d3.getSeconds() + 1);
|
||||||
|
|
||||||
|
const [user1, user2, user3] = await Promise.all([
|
||||||
|
// 4:59
|
||||||
|
createUser({ id: genAidx(d1.getTime()) }),
|
||||||
|
// 5:00
|
||||||
|
createUser({ id: genAidx(d2.getTime()) }),
|
||||||
|
// 5:01
|
||||||
|
createUser({ id: genAidx(d3.getTime()) }),
|
||||||
|
]);
|
||||||
|
const role = await createConditionalRole({
|
||||||
|
id: aidx(),
|
||||||
|
type: 'createdMoreThan',
|
||||||
|
// 5 minutes
|
||||||
|
sec: 300,
|
||||||
|
});
|
||||||
|
|
||||||
|
const actual1 = await roleService.getUserRoles(user1.id);
|
||||||
|
const actual2 = await roleService.getUserRoles(user2.id);
|
||||||
|
const actual3 = await roleService.getUserRoles(user3.id);
|
||||||
|
expect(actual1.some(r => r.id === role.id)).toBe(true);
|
||||||
|
expect(actual2.some(r => r.id === role.id)).toBe(false);
|
||||||
|
expect(actual3.some(r => r.id === role.id)).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('フォロワー数が指定値以下', async () => {
|
||||||
|
const [user1, user2, user3] = await Promise.all([
|
||||||
|
createUser({ followersCount: 99 }),
|
||||||
|
createUser({ followersCount: 100 }),
|
||||||
|
createUser({ followersCount: 101 }),
|
||||||
|
]);
|
||||||
|
const role = await createConditionalRole({
|
||||||
|
id: aidx(),
|
||||||
|
type: 'followersLessThanOrEq',
|
||||||
|
value: 100,
|
||||||
|
});
|
||||||
|
|
||||||
|
const actual1 = await roleService.getUserRoles(user1.id);
|
||||||
|
const actual2 = await roleService.getUserRoles(user2.id);
|
||||||
|
const actual3 = await roleService.getUserRoles(user3.id);
|
||||||
|
expect(actual1.some(r => r.id === role.id)).toBe(true);
|
||||||
|
expect(actual2.some(r => r.id === role.id)).toBe(true);
|
||||||
|
expect(actual3.some(r => r.id === role.id)).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('フォロワー数が指定値以下', async () => {
|
||||||
|
const [user1, user2, user3] = await Promise.all([
|
||||||
|
createUser({ followersCount: 99 }),
|
||||||
|
createUser({ followersCount: 100 }),
|
||||||
|
createUser({ followersCount: 101 }),
|
||||||
|
]);
|
||||||
|
const role = await createConditionalRole({
|
||||||
|
id: aidx(),
|
||||||
|
type: 'followersMoreThanOrEq',
|
||||||
|
value: 100,
|
||||||
|
});
|
||||||
|
|
||||||
|
const actual1 = await roleService.getUserRoles(user1.id);
|
||||||
|
const actual2 = await roleService.getUserRoles(user2.id);
|
||||||
|
const actual3 = await roleService.getUserRoles(user3.id);
|
||||||
|
expect(actual1.some(r => r.id === role.id)).toBe(false);
|
||||||
|
expect(actual2.some(r => r.id === role.id)).toBe(true);
|
||||||
|
expect(actual3.some(r => r.id === role.id)).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('フォロー数が指定値以下', async () => {
|
||||||
|
const [user1, user2, user3] = await Promise.all([
|
||||||
|
createUser({ followingCount: 99 }),
|
||||||
|
createUser({ followingCount: 100 }),
|
||||||
|
createUser({ followingCount: 101 }),
|
||||||
|
]);
|
||||||
|
const role = await createConditionalRole({
|
||||||
|
id: aidx(),
|
||||||
|
type: 'followingLessThanOrEq',
|
||||||
|
value: 100,
|
||||||
|
});
|
||||||
|
|
||||||
|
const actual1 = await roleService.getUserRoles(user1.id);
|
||||||
|
const actual2 = await roleService.getUserRoles(user2.id);
|
||||||
|
const actual3 = await roleService.getUserRoles(user3.id);
|
||||||
|
expect(actual1.some(r => r.id === role.id)).toBe(true);
|
||||||
|
expect(actual2.some(r => r.id === role.id)).toBe(true);
|
||||||
|
expect(actual3.some(r => r.id === role.id)).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('フォロー数が指定値以上', async () => {
|
||||||
|
const [user1, user2, user3] = await Promise.all([
|
||||||
|
createUser({ followingCount: 99 }),
|
||||||
|
createUser({ followingCount: 100 }),
|
||||||
|
createUser({ followingCount: 101 }),
|
||||||
|
]);
|
||||||
|
const role = await createConditionalRole({
|
||||||
|
id: aidx(),
|
||||||
|
type: 'followingMoreThanOrEq',
|
||||||
|
value: 100,
|
||||||
|
});
|
||||||
|
|
||||||
|
const actual1 = await roleService.getUserRoles(user1.id);
|
||||||
|
const actual2 = await roleService.getUserRoles(user2.id);
|
||||||
|
const actual3 = await roleService.getUserRoles(user3.id);
|
||||||
|
expect(actual1.some(r => r.id === role.id)).toBe(false);
|
||||||
|
expect(actual2.some(r => r.id === role.id)).toBe(true);
|
||||||
|
expect(actual3.some(r => r.id === role.id)).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('ノート数が指定値以下', async () => {
|
||||||
|
const [user1, user2, user3] = await Promise.all([
|
||||||
|
createUser({ notesCount: 9 }),
|
||||||
|
createUser({ notesCount: 10 }),
|
||||||
|
createUser({ notesCount: 11 }),
|
||||||
|
]);
|
||||||
|
const role = await createConditionalRole({
|
||||||
|
id: aidx(),
|
||||||
|
type: 'notesLessThanOrEq',
|
||||||
|
value: 10,
|
||||||
|
});
|
||||||
|
|
||||||
|
const actual1 = await roleService.getUserRoles(user1.id);
|
||||||
|
const actual2 = await roleService.getUserRoles(user2.id);
|
||||||
|
const actual3 = await roleService.getUserRoles(user3.id);
|
||||||
|
expect(actual1.some(r => r.id === role.id)).toBe(true);
|
||||||
|
expect(actual2.some(r => r.id === role.id)).toBe(true);
|
||||||
|
expect(actual3.some(r => r.id === role.id)).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('ノート数が指定値以上', async () => {
|
||||||
|
const [user1, user2, user3] = await Promise.all([
|
||||||
|
createUser({ notesCount: 9 }),
|
||||||
|
createUser({ notesCount: 10 }),
|
||||||
|
createUser({ notesCount: 11 }),
|
||||||
|
]);
|
||||||
|
const role = await createConditionalRole({
|
||||||
|
id: aidx(),
|
||||||
|
type: 'notesMoreThanOrEq',
|
||||||
|
value: 10,
|
||||||
|
});
|
||||||
|
|
||||||
|
const actual1 = await roleService.getUserRoles(user1.id);
|
||||||
|
const actual2 = await roleService.getUserRoles(user2.id);
|
||||||
|
const actual3 = await roleService.getUserRoles(user3.id);
|
||||||
|
expect(actual1.some(r => r.id === role.id)).toBe(false);
|
||||||
|
expect(actual2.some(r => r.id === role.id)).toBe(true);
|
||||||
|
expect(actual3.some(r => r.id === role.id)).toBe(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('assign', () => {
|
describe('assign', () => {
|
||||||
test('公開ロールの場合は通知される', async () => {
|
test('公開ロールの場合は通知される', async () => {
|
||||||
const user = await createUser();
|
const user = await createUser();
|
||||||
|
|
|
@ -9,6 +9,11 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<MkSelect v-model="type" :class="$style.typeSelect">
|
<MkSelect v-model="type" :class="$style.typeSelect">
|
||||||
<option value="isLocal">{{ i18n.ts._role._condition.isLocal }}</option>
|
<option value="isLocal">{{ i18n.ts._role._condition.isLocal }}</option>
|
||||||
<option value="isRemote">{{ i18n.ts._role._condition.isRemote }}</option>
|
<option value="isRemote">{{ i18n.ts._role._condition.isRemote }}</option>
|
||||||
|
<option value="isSuspended">{{ i18n.ts._role._condition.isSuspended }}</option>
|
||||||
|
<option value="isLocked">{{ i18n.ts._role._condition.isLocked }}</option>
|
||||||
|
<option value="isBot">{{ i18n.ts._role._condition.isBot }}</option>
|
||||||
|
<option value="isCat">{{ i18n.ts._role._condition.isCat }}</option>
|
||||||
|
<option value="isExplorable">{{ i18n.ts._role._condition.isExplorable }}</option>
|
||||||
<option value="roleAssignedTo">{{ i18n.ts._role._condition.roleAssignedTo }}</option>
|
<option value="roleAssignedTo">{{ i18n.ts._role._condition.roleAssignedTo }}</option>
|
||||||
<option value="createdLessThan">{{ i18n.ts._role._condition.createdLessThan }}</option>
|
<option value="createdLessThan">{{ i18n.ts._role._condition.createdLessThan }}</option>
|
||||||
<option value="createdMoreThan">{{ i18n.ts._role._condition.createdMoreThan }}</option>
|
<option value="createdMoreThan">{{ i18n.ts._role._condition.createdMoreThan }}</option>
|
||||||
|
|
|
@ -1713,6 +1713,7 @@ declare namespace entities {
|
||||||
RoleCondFormulaLogics,
|
RoleCondFormulaLogics,
|
||||||
RoleCondFormulaValueNot,
|
RoleCondFormulaValueNot,
|
||||||
RoleCondFormulaValueIsLocalOrRemote,
|
RoleCondFormulaValueIsLocalOrRemote,
|
||||||
|
RoleCondFormulaValueUserSettingBooleanSchema,
|
||||||
RoleCondFormulaValueAssignedRole,
|
RoleCondFormulaValueAssignedRole,
|
||||||
RoleCondFormulaValueCreated,
|
RoleCondFormulaValueCreated,
|
||||||
RoleCondFormulaFollowersOrFollowingOrNotes,
|
RoleCondFormulaFollowersOrFollowingOrNotes,
|
||||||
|
@ -2745,6 +2746,9 @@ type RoleCondFormulaValueIsLocalOrRemote = components['schemas']['RoleCondFormul
|
||||||
// @public (undocumented)
|
// @public (undocumented)
|
||||||
type RoleCondFormulaValueNot = components['schemas']['RoleCondFormulaValueNot'];
|
type RoleCondFormulaValueNot = components['schemas']['RoleCondFormulaValueNot'];
|
||||||
|
|
||||||
|
// @public (undocumented)
|
||||||
|
type RoleCondFormulaValueUserSettingBooleanSchema = components['schemas']['RoleCondFormulaValueUserSettingBooleanSchema'];
|
||||||
|
|
||||||
// @public (undocumented)
|
// @public (undocumented)
|
||||||
type RoleLite = components['schemas']['RoleLite'];
|
type RoleLite = components['schemas']['RoleLite'];
|
||||||
|
|
||||||
|
|
|
@ -38,6 +38,7 @@ export type Signin = components['schemas']['Signin'];
|
||||||
export type RoleCondFormulaLogics = components['schemas']['RoleCondFormulaLogics'];
|
export type RoleCondFormulaLogics = components['schemas']['RoleCondFormulaLogics'];
|
||||||
export type RoleCondFormulaValueNot = components['schemas']['RoleCondFormulaValueNot'];
|
export type RoleCondFormulaValueNot = components['schemas']['RoleCondFormulaValueNot'];
|
||||||
export type RoleCondFormulaValueIsLocalOrRemote = components['schemas']['RoleCondFormulaValueIsLocalOrRemote'];
|
export type RoleCondFormulaValueIsLocalOrRemote = components['schemas']['RoleCondFormulaValueIsLocalOrRemote'];
|
||||||
|
export type RoleCondFormulaValueUserSettingBooleanSchema = components['schemas']['RoleCondFormulaValueUserSettingBooleanSchema'];
|
||||||
export type RoleCondFormulaValueAssignedRole = components['schemas']['RoleCondFormulaValueAssignedRole'];
|
export type RoleCondFormulaValueAssignedRole = components['schemas']['RoleCondFormulaValueAssignedRole'];
|
||||||
export type RoleCondFormulaValueCreated = components['schemas']['RoleCondFormulaValueCreated'];
|
export type RoleCondFormulaValueCreated = components['schemas']['RoleCondFormulaValueCreated'];
|
||||||
export type RoleCondFormulaFollowersOrFollowingOrNotes = components['schemas']['RoleCondFormulaFollowersOrFollowingOrNotes'];
|
export type RoleCondFormulaFollowersOrFollowingOrNotes = components['schemas']['RoleCondFormulaFollowersOrFollowingOrNotes'];
|
||||||
|
|
|
@ -4586,6 +4586,11 @@ export type components = {
|
||||||
/** @enum {string} */
|
/** @enum {string} */
|
||||||
type: 'isLocal' | 'isRemote';
|
type: 'isLocal' | 'isRemote';
|
||||||
};
|
};
|
||||||
|
RoleCondFormulaValueUserSettingBooleanSchema: {
|
||||||
|
id: string;
|
||||||
|
/** @enum {string} */
|
||||||
|
type: 'isSuspended' | 'isLocked' | 'isBot' | 'isCat' | 'isExplorable';
|
||||||
|
};
|
||||||
RoleCondFormulaValueAssignedRole: {
|
RoleCondFormulaValueAssignedRole: {
|
||||||
id: string;
|
id: string;
|
||||||
/** @enum {string} */
|
/** @enum {string} */
|
||||||
|
@ -4608,7 +4613,7 @@ export type components = {
|
||||||
type: 'followersLessThanOrEq' | 'followersMoreThanOrEq' | 'followingLessThanOrEq' | 'followingMoreThanOrEq' | 'notesLessThanOrEq' | 'notesMoreThanOrEq';
|
type: 'followersLessThanOrEq' | 'followersMoreThanOrEq' | 'followingLessThanOrEq' | 'followingMoreThanOrEq' | 'notesLessThanOrEq' | 'notesMoreThanOrEq';
|
||||||
value: number;
|
value: number;
|
||||||
};
|
};
|
||||||
RoleCondFormulaValue: components['schemas']['RoleCondFormulaLogics'] | components['schemas']['RoleCondFormulaValueNot'] | components['schemas']['RoleCondFormulaValueIsLocalOrRemote'] | components['schemas']['RoleCondFormulaValueAssignedRole'] | components['schemas']['RoleCondFormulaValueCreated'] | components['schemas']['RoleCondFormulaFollowersOrFollowingOrNotes'];
|
RoleCondFormulaValue: components['schemas']['RoleCondFormulaLogics'] | components['schemas']['RoleCondFormulaValueNot'] | components['schemas']['RoleCondFormulaValueIsLocalOrRemote'] | components['schemas']['RoleCondFormulaValueUserSettingBooleanSchema'] | components['schemas']['RoleCondFormulaValueAssignedRole'] | components['schemas']['RoleCondFormulaValueCreated'] | components['schemas']['RoleCondFormulaFollowersOrFollowingOrNotes'];
|
||||||
RoleLite: {
|
RoleLite: {
|
||||||
/**
|
/**
|
||||||
* Format: id
|
* Format: id
|
||||||
|
|
Loading…
Reference in a new issue