Enhance: コンディショナルロールの条件に「マニュアルロールへのアサイン」を追加 (#13463)
* コンディショナルロールの条件に「マニュアルロールへのアサイン」を追加 * コメント修正
This commit is contained in:
parent
0fb7b98f96
commit
f906ad6ca7
|
@ -15,6 +15,7 @@
|
||||||
|
|
||||||
### General
|
### General
|
||||||
- Enhance: サーバーごとにモデレーションノートを残せるように
|
- Enhance: サーバーごとにモデレーションノートを残せるように
|
||||||
|
- Enhance: コンディショナルロールの条件に「マニュアルロールへのアサイン」を追加
|
||||||
|
|
||||||
### Client
|
### Client
|
||||||
- Enhance: ノート作成画面のファイル添付メニューの区切り線の位置を調整
|
- Enhance: ノート作成画面のファイル添付メニューの区切り線の位置を調整
|
||||||
|
|
|
@ -6528,6 +6528,10 @@ export interface Locale extends ILocale {
|
||||||
"avatarDecorationLimit": string;
|
"avatarDecorationLimit": string;
|
||||||
};
|
};
|
||||||
"_condition": {
|
"_condition": {
|
||||||
|
/**
|
||||||
|
* マニュアルロールにアサイン済み
|
||||||
|
*/
|
||||||
|
"roleAssignedTo": string;
|
||||||
/**
|
/**
|
||||||
* ローカルユーザー
|
* ローカルユーザー
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -1687,6 +1687,7 @@ _role:
|
||||||
canUseTranslator: "翻訳機能の利用"
|
canUseTranslator: "翻訳機能の利用"
|
||||||
avatarDecorationLimit: "アイコンデコレーションの最大取付個数"
|
avatarDecorationLimit: "アイコンデコレーションの最大取付個数"
|
||||||
_condition:
|
_condition:
|
||||||
|
roleAssignedTo: "マニュアルロールにアサイン済み"
|
||||||
isLocal: "ローカルユーザー"
|
isLocal: "ローカルユーザー"
|
||||||
isRemote: "リモートユーザー"
|
isRemote: "リモートユーザー"
|
||||||
createdLessThan: "アカウント作成から~以内"
|
createdLessThan: "アカウント作成から~以内"
|
||||||
|
|
|
@ -200,17 +200,20 @@ export class RoleService implements OnApplicationShutdown, OnModuleInit {
|
||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
private evalCond(user: MiUser, 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, v));
|
return value.values.every(v => this.evalCond(user, roles, v));
|
||||||
}
|
}
|
||||||
case 'or': {
|
case 'or': {
|
||||||
return value.values.some(v => this.evalCond(user, v));
|
return value.values.some(v => this.evalCond(user, roles, v));
|
||||||
}
|
}
|
||||||
case 'not': {
|
case 'not': {
|
||||||
return !this.evalCond(user, value.value);
|
return !this.evalCond(user, roles, value.value);
|
||||||
|
}
|
||||||
|
case 'roleAssignedTo': {
|
||||||
|
return roles.some(r => r.id === value.roleId);
|
||||||
}
|
}
|
||||||
case 'isLocal': {
|
case 'isLocal': {
|
||||||
return this.userEntityService.isLocalUser(user);
|
return this.userEntityService.isLocalUser(user);
|
||||||
|
@ -272,7 +275,7 @@ export class RoleService implements OnApplicationShutdown, OnModuleInit {
|
||||||
const assigns = await this.getUserAssigns(userId);
|
const assigns = await this.getUserAssigns(userId);
|
||||||
const assignedRoles = roles.filter(r => assigns.map(x => x.roleId).includes(r.id));
|
const assignedRoles = roles.filter(r => assigns.map(x => x.roleId).includes(r.id));
|
||||||
const user = roles.some(r => r.target === 'conditional') ? await this.cacheService.findUserById(userId) : null;
|
const user = roles.some(r => r.target === 'conditional') ? await this.cacheService.findUserById(userId) : null;
|
||||||
const matchedCondRoles = roles.filter(r => r.target === 'conditional' && this.evalCond(user!, r.condFormula));
|
const matchedCondRoles = roles.filter(r => r.target === 'conditional' && this.evalCond(user!, assignedRoles, r.condFormula));
|
||||||
return [...assignedRoles, ...matchedCondRoles];
|
return [...assignedRoles, ...matchedCondRoles];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -285,13 +288,13 @@ export class RoleService implements OnApplicationShutdown, OnModuleInit {
|
||||||
let assigns = await this.roleAssignmentByUserIdCache.fetch(userId, () => this.roleAssignmentsRepository.findBy({ userId }));
|
let assigns = await this.roleAssignmentByUserIdCache.fetch(userId, () => this.roleAssignmentsRepository.findBy({ userId }));
|
||||||
// 期限切れのロールを除外
|
// 期限切れのロールを除外
|
||||||
assigns = assigns.filter(a => a.expiresAt == null || (a.expiresAt.getTime() > now));
|
assigns = assigns.filter(a => a.expiresAt == null || (a.expiresAt.getTime() > now));
|
||||||
const assignedRoleIds = assigns.map(x => x.roleId);
|
|
||||||
const roles = await this.rolesCache.fetch(() => this.rolesRepository.findBy({}));
|
const roles = await this.rolesCache.fetch(() => this.rolesRepository.findBy({}));
|
||||||
const assignedBadgeRoles = roles.filter(r => r.asBadge && assignedRoleIds.includes(r.id));
|
const assignedRoles = roles.filter(r => assigns.map(x => x.roleId).includes(r.id));
|
||||||
|
const assignedBadgeRoles = assignedRoles.filter(r => r.asBadge);
|
||||||
const badgeCondRoles = roles.filter(r => r.asBadge && (r.target === 'conditional'));
|
const badgeCondRoles = roles.filter(r => r.asBadge && (r.target === 'conditional'));
|
||||||
if (badgeCondRoles.length > 0) {
|
if (badgeCondRoles.length > 0) {
|
||||||
const user = roles.some(r => r.target === 'conditional') ? await this.cacheService.findUserById(userId) : null;
|
const user = roles.some(r => r.target === 'conditional') ? await this.cacheService.findUserById(userId) : null;
|
||||||
const matchedBadgeCondRoles = badgeCondRoles.filter(r => this.evalCond(user!, r.condFormula));
|
const matchedBadgeCondRoles = badgeCondRoles.filter(r => this.evalCond(user!, assignedRoles, r.condFormula));
|
||||||
return [...assignedBadgeRoles, ...matchedBadgeCondRoles];
|
return [...assignedBadgeRoles, ...matchedBadgeCondRoles];
|
||||||
} else {
|
} else {
|
||||||
return assignedBadgeRoles;
|
return assignedBadgeRoles;
|
||||||
|
|
|
@ -44,6 +44,7 @@ import {
|
||||||
packedRoleCondFormulaLogicsSchema,
|
packedRoleCondFormulaLogicsSchema,
|
||||||
packedRoleCondFormulaValueNot,
|
packedRoleCondFormulaValueNot,
|
||||||
packedRoleCondFormulaValueIsLocalOrRemoteSchema,
|
packedRoleCondFormulaValueIsLocalOrRemoteSchema,
|
||||||
|
packedRoleCondFormulaValueAssignedRoleSchema,
|
||||||
packedRoleCondFormulaValueCreatedSchema,
|
packedRoleCondFormulaValueCreatedSchema,
|
||||||
packedRoleCondFormulaFollowersOrFollowingOrNotesSchema,
|
packedRoleCondFormulaFollowersOrFollowingOrNotesSchema,
|
||||||
packedRoleCondFormulaValueSchema,
|
packedRoleCondFormulaValueSchema,
|
||||||
|
@ -96,6 +97,7 @@ export const refs = {
|
||||||
RoleCondFormulaLogics: packedRoleCondFormulaLogicsSchema,
|
RoleCondFormulaLogics: packedRoleCondFormulaLogicsSchema,
|
||||||
RoleCondFormulaValueNot: packedRoleCondFormulaValueNot,
|
RoleCondFormulaValueNot: packedRoleCondFormulaValueNot,
|
||||||
RoleCondFormulaValueIsLocalOrRemote: packedRoleCondFormulaValueIsLocalOrRemoteSchema,
|
RoleCondFormulaValueIsLocalOrRemote: packedRoleCondFormulaValueIsLocalOrRemoteSchema,
|
||||||
|
RoleCondFormulaValueAssignedRole: packedRoleCondFormulaValueAssignedRoleSchema,
|
||||||
RoleCondFormulaValueCreated: packedRoleCondFormulaValueCreatedSchema,
|
RoleCondFormulaValueCreated: packedRoleCondFormulaValueCreatedSchema,
|
||||||
RoleCondFormulaFollowersOrFollowingOrNotes: packedRoleCondFormulaFollowersOrFollowingOrNotesSchema,
|
RoleCondFormulaFollowersOrFollowingOrNotes: packedRoleCondFormulaFollowersOrFollowingOrNotesSchema,
|
||||||
RoleCondFormulaValue: packedRoleCondFormulaValueSchema,
|
RoleCondFormulaValue: packedRoleCondFormulaValueSchema,
|
||||||
|
|
|
@ -29,6 +29,11 @@ type CondFormulaValueIsRemote = {
|
||||||
type: 'isRemote';
|
type: 'isRemote';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type CondFormulaValueRoleAssignedTo = {
|
||||||
|
type: 'roleAssignedTo';
|
||||||
|
roleId: string;
|
||||||
|
};
|
||||||
|
|
||||||
type CondFormulaValueCreatedLessThan = {
|
type CondFormulaValueCreatedLessThan = {
|
||||||
type: 'createdLessThan';
|
type: 'createdLessThan';
|
||||||
sec: number;
|
sec: number;
|
||||||
|
@ -75,6 +80,7 @@ export type RoleCondFormulaValue = { id: string } & (
|
||||||
CondFormulaValueNot |
|
CondFormulaValueNot |
|
||||||
CondFormulaValueIsLocal |
|
CondFormulaValueIsLocal |
|
||||||
CondFormulaValueIsRemote |
|
CondFormulaValueIsRemote |
|
||||||
|
CondFormulaValueRoleAssignedTo |
|
||||||
CondFormulaValueCreatedLessThan |
|
CondFormulaValueCreatedLessThan |
|
||||||
CondFormulaValueCreatedMoreThan |
|
CondFormulaValueCreatedMoreThan |
|
||||||
CondFormulaValueFollowersLessThanOrEq |
|
CondFormulaValueFollowersLessThanOrEq |
|
||||||
|
|
|
@ -57,6 +57,23 @@ export const packedRoleCondFormulaValueIsLocalOrRemoteSchema = {
|
||||||
},
|
},
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
|
export const packedRoleCondFormulaValueAssignedRoleSchema = {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
type: {
|
||||||
|
type: 'string',
|
||||||
|
nullable: false, optional: false,
|
||||||
|
enum: ['roleAssignedTo'],
|
||||||
|
},
|
||||||
|
roleId: {
|
||||||
|
type: 'string',
|
||||||
|
nullable: false, optional: false,
|
||||||
|
format: 'id',
|
||||||
|
example: 'xxxxxxxxxx',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} as const;
|
||||||
|
|
||||||
export const packedRoleCondFormulaValueCreatedSchema = {
|
export const packedRoleCondFormulaValueCreatedSchema = {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
properties: {
|
properties: {
|
||||||
|
@ -115,6 +132,9 @@ export const packedRoleCondFormulaValueSchema = {
|
||||||
{
|
{
|
||||||
ref: 'RoleCondFormulaValueIsLocalOrRemote',
|
ref: 'RoleCondFormulaValueIsLocalOrRemote',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
ref: 'RoleCondFormulaValueAssignedRole',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
ref: 'RoleCondFormulaValueCreated',
|
ref: 'RoleCondFormulaValueCreated',
|
||||||
},
|
},
|
||||||
|
|
|
@ -251,6 +251,34 @@ describe('RoleService', () => {
|
||||||
expect(user2Policies.canManageCustomEmojis).toBe(true);
|
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({
|
||||||
|
|
|
@ -9,6 +9,7 @@ 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="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>
|
||||||
<option value="followersLessThanOrEq">{{ i18n.ts._role._condition.followersLessThanOrEq }}</option>
|
<option value="followersLessThanOrEq">{{ i18n.ts._role._condition.followersLessThanOrEq }}</option>
|
||||||
|
@ -51,6 +52,10 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
<MkInput v-else-if="['followersLessThanOrEq', 'followersMoreThanOrEq', 'followingLessThanOrEq', 'followingMoreThanOrEq', 'notesLessThanOrEq', 'notesMoreThanOrEq'].includes(type)" v-model="v.value" type="number">
|
<MkInput v-else-if="['followersLessThanOrEq', 'followersMoreThanOrEq', 'followingLessThanOrEq', 'followingMoreThanOrEq', 'notesLessThanOrEq', 'notesMoreThanOrEq'].includes(type)" v-model="v.value" type="number">
|
||||||
</MkInput>
|
</MkInput>
|
||||||
|
|
||||||
|
<MkSelect v-else-if="type === 'roleAssignedTo'" v-model="v.roleId">
|
||||||
|
<option v-for="role in roles.filter(r => r.target === 'manual')" :key="role.id" :value="role.id">{{ role.name }}</option>
|
||||||
|
</MkSelect>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -62,6 +67,7 @@ import MkSelect from '@/components/MkSelect.vue';
|
||||||
import MkButton from '@/components/MkButton.vue';
|
import MkButton from '@/components/MkButton.vue';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { deepClone } from '@/scripts/clone.js';
|
import { deepClone } from '@/scripts/clone.js';
|
||||||
|
import { rolesCache } from '@/cache.js';
|
||||||
|
|
||||||
const Sortable = defineAsyncComponent(() => import('vuedraggable').then(x => x.default));
|
const Sortable = defineAsyncComponent(() => import('vuedraggable').then(x => x.default));
|
||||||
|
|
||||||
|
@ -77,6 +83,8 @@ const props = defineProps<{
|
||||||
|
|
||||||
const v = ref(deepClone(props.modelValue));
|
const v = ref(deepClone(props.modelValue));
|
||||||
|
|
||||||
|
const roles = await rolesCache.fetch();
|
||||||
|
|
||||||
watch(() => props.modelValue, () => {
|
watch(() => props.modelValue, () => {
|
||||||
if (JSON.stringify(props.modelValue) === JSON.stringify(v.value)) return;
|
if (JSON.stringify(props.modelValue) === JSON.stringify(v.value)) return;
|
||||||
v.value = deepClone(props.modelValue);
|
v.value = deepClone(props.modelValue);
|
||||||
|
@ -92,6 +100,7 @@ const type = computed({
|
||||||
if (t === 'and') v.value.values = [];
|
if (t === 'and') v.value.values = [];
|
||||||
if (t === 'or') v.value.values = [];
|
if (t === 'or') v.value.values = [];
|
||||||
if (t === 'not') v.value.value = { id: uuid(), type: 'isRemote' };
|
if (t === 'not') v.value.value = { id: uuid(), type: 'isRemote' };
|
||||||
|
if (t === 'roleAssignedTo') v.value.roleId = '';
|
||||||
if (t === 'createdLessThan') v.value.sec = 86400;
|
if (t === 'createdLessThan') v.value.sec = 86400;
|
||||||
if (t === 'createdMoreThan') v.value.sec = 86400;
|
if (t === 'createdMoreThan') v.value.sec = 86400;
|
||||||
if (t === 'followersLessThanOrEq') v.value.value = 10;
|
if (t === 'followersLessThanOrEq') v.value.value = 10;
|
||||||
|
|
|
@ -1712,6 +1712,7 @@ declare namespace entities {
|
||||||
RoleCondFormulaLogics,
|
RoleCondFormulaLogics,
|
||||||
RoleCondFormulaValueNot,
|
RoleCondFormulaValueNot,
|
||||||
RoleCondFormulaValueIsLocalOrRemote,
|
RoleCondFormulaValueIsLocalOrRemote,
|
||||||
|
RoleCondFormulaValueAssignedRole,
|
||||||
RoleCondFormulaValueCreated,
|
RoleCondFormulaValueCreated,
|
||||||
RoleCondFormulaFollowersOrFollowingOrNotes,
|
RoleCondFormulaFollowersOrFollowingOrNotes,
|
||||||
RoleCondFormulaValue,
|
RoleCondFormulaValue,
|
||||||
|
@ -2731,6 +2732,9 @@ type RoleCondFormulaLogics = components['schemas']['RoleCondFormulaLogics'];
|
||||||
// @public (undocumented)
|
// @public (undocumented)
|
||||||
type RoleCondFormulaValue = components['schemas']['RoleCondFormulaValue'];
|
type RoleCondFormulaValue = components['schemas']['RoleCondFormulaValue'];
|
||||||
|
|
||||||
|
// @public (undocumented)
|
||||||
|
type RoleCondFormulaValueAssignedRole = components['schemas']['RoleCondFormulaValueAssignedRole'];
|
||||||
|
|
||||||
// @public (undocumented)
|
// @public (undocumented)
|
||||||
type RoleCondFormulaValueCreated = components['schemas']['RoleCondFormulaValueCreated'];
|
type RoleCondFormulaValueCreated = components['schemas']['RoleCondFormulaValueCreated'];
|
||||||
|
|
||||||
|
|
|
@ -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 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'];
|
||||||
export type RoleCondFormulaValue = components['schemas']['RoleCondFormulaValue'];
|
export type RoleCondFormulaValue = components['schemas']['RoleCondFormulaValue'];
|
||||||
|
|
|
@ -4573,6 +4573,15 @@ export type components = {
|
||||||
/** @enum {string} */
|
/** @enum {string} */
|
||||||
type: 'isLocal' | 'isRemote';
|
type: 'isLocal' | 'isRemote';
|
||||||
};
|
};
|
||||||
|
RoleCondFormulaValueAssignedRole: {
|
||||||
|
/** @enum {string} */
|
||||||
|
type: 'roleAssignedTo';
|
||||||
|
/**
|
||||||
|
* Format: id
|
||||||
|
* @example xxxxxxxxxx
|
||||||
|
*/
|
||||||
|
roleId: string;
|
||||||
|
};
|
||||||
RoleCondFormulaValueCreated: {
|
RoleCondFormulaValueCreated: {
|
||||||
id: string;
|
id: string;
|
||||||
/** @enum {string} */
|
/** @enum {string} */
|
||||||
|
@ -4585,7 +4594,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']['RoleCondFormulaValueCreated'] | components['schemas']['RoleCondFormulaFollowersOrFollowingOrNotes'];
|
RoleCondFormulaValue: components['schemas']['RoleCondFormulaLogics'] | components['schemas']['RoleCondFormulaValueNot'] | components['schemas']['RoleCondFormulaValueIsLocalOrRemote'] | components['schemas']['RoleCondFormulaValueAssignedRole'] | components['schemas']['RoleCondFormulaValueCreated'] | components['schemas']['RoleCondFormulaFollowersOrFollowingOrNotes'];
|
||||||
RoleLite: {
|
RoleLite: {
|
||||||
/**
|
/**
|
||||||
* Format: id
|
* Format: id
|
||||||
|
|
Loading…
Reference in New Issue