mirror of
https://github.com/misskey-dev/misskey.git
synced 2024-12-23 17:10:39 +01:00
enhance: ユーザーリストおよびユーザーリスト内のユーザーの作成可能数を設定可能に
This commit is contained in:
parent
c41879c542
commit
76c049522e
9 changed files with 88 additions and 4 deletions
|
@ -77,6 +77,7 @@ You should also include the user name that made the change.
|
||||||
- 非モデレーターでも、権限を持つロールをアサインされたユーザーはインスタンスの招待コードを発行できるように @syuilo
|
- 非モデレーターでも、権限を持つロールをアサインされたユーザーはインスタンスの招待コードを発行できるように @syuilo
|
||||||
- 非モデレーターでも、権限を持つロールをアサインされたユーザーはカスタム絵文字の追加、編集、削除を行えるように @syuilo
|
- 非モデレーターでも、権限を持つロールをアサインされたユーザーはカスタム絵文字の追加、編集、削除を行えるように @syuilo
|
||||||
- クリップおよびクリップ内のノートの作成可能数を設定可能に @syuilo
|
- クリップおよびクリップ内のノートの作成可能数を設定可能に @syuilo
|
||||||
|
- ユーザーリストおよびユーザーリスト内のユーザーの作成可能数を設定可能に @syuilo
|
||||||
- ハードワードミュートの最大文字数を設定可能に @syuilo
|
- ハードワードミュートの最大文字数を設定可能に @syuilo
|
||||||
- Webhookの作成可能数を設定可能に @syuilo
|
- Webhookの作成可能数を設定可能に @syuilo
|
||||||
- Server: signToActivityPubGet is set to true by default @syuilo
|
- Server: signToActivityPubGet is set to true by default @syuilo
|
||||||
|
|
|
@ -966,6 +966,8 @@ _role:
|
||||||
webhookMax: "Webhookの作成可能数"
|
webhookMax: "Webhookの作成可能数"
|
||||||
clipMax: "クリップの作成可能数"
|
clipMax: "クリップの作成可能数"
|
||||||
noteEachClipsMax: "クリップ内のノートの最大数"
|
noteEachClipsMax: "クリップ内のノートの最大数"
|
||||||
|
userListMax: "ユーザーリストの作成可能数"
|
||||||
|
userEachUserListsMax: "ユーザーリスト内のユーザーの最大数"
|
||||||
_condition:
|
_condition:
|
||||||
isLocal: "ローカルユーザー"
|
isLocal: "ローカルユーザー"
|
||||||
isRemote: "リモートユーザー"
|
isRemote: "リモートユーザー"
|
||||||
|
|
|
@ -25,6 +25,8 @@ export type RoleOptions = {
|
||||||
webhookLimit: number;
|
webhookLimit: number;
|
||||||
clipLimit: number;
|
clipLimit: number;
|
||||||
noteEachClipsLimit: number;
|
noteEachClipsLimit: number;
|
||||||
|
userListLimit: number;
|
||||||
|
userEachUserListsLimit: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const DEFAULT_ROLE: RoleOptions = {
|
export const DEFAULT_ROLE: RoleOptions = {
|
||||||
|
@ -39,6 +41,8 @@ export const DEFAULT_ROLE: RoleOptions = {
|
||||||
webhookLimit: 3,
|
webhookLimit: 3,
|
||||||
clipLimit: 10,
|
clipLimit: 10,
|
||||||
noteEachClipsLimit: 200,
|
noteEachClipsLimit: 200,
|
||||||
|
userListLimit: 10,
|
||||||
|
userEachUserListsLimit: 50,
|
||||||
};
|
};
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
|
@ -212,6 +216,8 @@ export class RoleService implements OnApplicationShutdown {
|
||||||
webhookLimit: Math.max(...getOptionValues('webhookLimit')),
|
webhookLimit: Math.max(...getOptionValues('webhookLimit')),
|
||||||
clipLimit: Math.max(...getOptionValues('clipLimit')),
|
clipLimit: Math.max(...getOptionValues('clipLimit')),
|
||||||
noteEachClipsLimit: Math.max(...getOptionValues('noteEachClipsLimit')),
|
noteEachClipsLimit: Math.max(...getOptionValues('noteEachClipsLimit')),
|
||||||
|
userListLimit: Math.max(...getOptionValues('userListLimit')),
|
||||||
|
userEachUserListsLimit: Math.max(...getOptionValues('userEachUserListsLimit')),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@ import { DI } from '@/di-symbols.js';
|
||||||
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
||||||
import { ProxyAccountService } from '@/core/ProxyAccountService.js';
|
import { ProxyAccountService } from '@/core/ProxyAccountService.js';
|
||||||
import { bindThis } from '@/decorators.js';
|
import { bindThis } from '@/decorators.js';
|
||||||
|
import { RoleService } from '@/core/RoleService.js';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class UserListService {
|
export class UserListService {
|
||||||
|
@ -23,13 +24,21 @@ export class UserListService {
|
||||||
private userEntityService: UserEntityService,
|
private userEntityService: UserEntityService,
|
||||||
private idService: IdService,
|
private idService: IdService,
|
||||||
private userFollowingService: UserFollowingService,
|
private userFollowingService: UserFollowingService,
|
||||||
|
private roleService: RoleService,
|
||||||
private globalEventServie: GlobalEventService,
|
private globalEventServie: GlobalEventService,
|
||||||
private proxyAccountService: ProxyAccountService,
|
private proxyAccountService: ProxyAccountService,
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
public async push(target: User, list: UserList) {
|
public async push(target: User, list: UserList, me: User) {
|
||||||
|
const currentCount = await this.userListJoiningsRepository.countBy({
|
||||||
|
userListId: list.id,
|
||||||
|
});
|
||||||
|
if (currentCount > (await this.roleService.getUserRoleOptions(me.id)).userEachUserListsLimit) {
|
||||||
|
throw new Error('Too many users');
|
||||||
|
}
|
||||||
|
|
||||||
await this.userListJoiningsRepository.insert({
|
await this.userListJoiningsRepository.insert({
|
||||||
id: this.idService.genId(),
|
id: this.idService.genId(),
|
||||||
createdAt: new Date(),
|
createdAt: new Date(),
|
||||||
|
|
|
@ -10,10 +10,10 @@ import { DownloadService } from '@/core/DownloadService.js';
|
||||||
import { UserListService } from '@/core/UserListService.js';
|
import { UserListService } from '@/core/UserListService.js';
|
||||||
import { IdService } from '@/core/IdService.js';
|
import { IdService } from '@/core/IdService.js';
|
||||||
import { UtilityService } from '@/core/UtilityService.js';
|
import { UtilityService } from '@/core/UtilityService.js';
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
import { QueueLoggerService } from '../QueueLoggerService.js';
|
import { QueueLoggerService } from '../QueueLoggerService.js';
|
||||||
import type Bull from 'bull';
|
import type Bull from 'bull';
|
||||||
import type { DbUserImportJobData } from '../types.js';
|
import type { DbUserImportJobData } from '../types.js';
|
||||||
import { bindThis } from '@/decorators.js';
|
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class ImportUserListsProcessorService {
|
export class ImportUserListsProcessorService {
|
||||||
|
@ -102,7 +102,7 @@ export class ImportUserListsProcessorService {
|
||||||
|
|
||||||
if (await this.userListJoiningsRepository.findOneBy({ userListId: list!.id, userId: target.id }) != null) continue;
|
if (await this.userListJoiningsRepository.findOneBy({ userListId: list!.id, userId: target.id }) != null) continue;
|
||||||
|
|
||||||
this.userListService.push(target, list!);
|
this.userListService.push(target, list!, user);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.logger.warn(`Error in line:${linenum} ${e}`);
|
this.logger.warn(`Error in line:${linenum} ${e}`);
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,8 @@ import type { UserList } from '@/models/entities/UserList.js';
|
||||||
import { Endpoint } from '@/server/api/endpoint-base.js';
|
import { Endpoint } from '@/server/api/endpoint-base.js';
|
||||||
import { UserListEntityService } from '@/core/entities/UserListEntityService.js';
|
import { UserListEntityService } from '@/core/entities/UserListEntityService.js';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
|
import { ApiError } from '@/server/api/error';
|
||||||
|
import { RoleService } from '@/core/RoleService.js';
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
tags: ['lists'],
|
tags: ['lists'],
|
||||||
|
@ -20,6 +22,14 @@ export const meta = {
|
||||||
optional: false, nullable: false,
|
optional: false, nullable: false,
|
||||||
ref: 'UserList',
|
ref: 'UserList',
|
||||||
},
|
},
|
||||||
|
|
||||||
|
errors: {
|
||||||
|
tooManyUserLists: {
|
||||||
|
message: 'You cannot create user list any more.',
|
||||||
|
code: 'TOO_MANY_USERLISTS',
|
||||||
|
id: '0cf21a28-7715-4f39-a20d-777bfdb8d138',
|
||||||
|
},
|
||||||
|
},
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
export const paramDef = {
|
export const paramDef = {
|
||||||
|
@ -39,8 +49,16 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
|
||||||
|
|
||||||
private userListEntityService: UserListEntityService,
|
private userListEntityService: UserListEntityService,
|
||||||
private idService: IdService,
|
private idService: IdService,
|
||||||
|
private roleService: RoleService,
|
||||||
) {
|
) {
|
||||||
super(meta, paramDef, async (ps, me) => {
|
super(meta, paramDef, async (ps, me) => {
|
||||||
|
const currentCount = await this.userListsRepository.countBy({
|
||||||
|
userId: me.id,
|
||||||
|
});
|
||||||
|
if (currentCount > (await this.roleService.getUserRoleOptions(me.id)).userListLimit) {
|
||||||
|
throw new ApiError(meta.errors.tooManyUserLists);
|
||||||
|
}
|
||||||
|
|
||||||
const userList = await this.userListsRepository.insert({
|
const userList = await this.userListsRepository.insert({
|
||||||
id: this.idService.genId(),
|
id: this.idService.genId(),
|
||||||
createdAt: new Date(),
|
createdAt: new Date(),
|
||||||
|
|
|
@ -111,7 +111,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Push the user
|
// Push the user
|
||||||
await this.userListService.push(user, userList);
|
await this.userListService.push(user, userList, me);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -176,6 +176,30 @@
|
||||||
</MkInput>
|
</MkInput>
|
||||||
</div>
|
</div>
|
||||||
</MkFolder>
|
</MkFolder>
|
||||||
|
|
||||||
|
<MkFolder>
|
||||||
|
<template #label>{{ i18n.ts._role._options.userListMax }}</template>
|
||||||
|
<template #suffix>{{ options_userList_useDefault ? i18n.ts._role.useBaseValue : (options_userList_value) }}</template>
|
||||||
|
<div class="_gaps">
|
||||||
|
<MkSwitch v-model="options_userList_useDefault" :readonly="readonly">
|
||||||
|
<template #label>{{ i18n.ts._role.useBaseValue }}</template>
|
||||||
|
</MkSwitch>
|
||||||
|
<MkInput v-model="options_userList_value" :disabled="options_userList_useDefault" type="number" :readonly="readonly">
|
||||||
|
</MkInput>
|
||||||
|
</div>
|
||||||
|
</MkFolder>
|
||||||
|
|
||||||
|
<MkFolder>
|
||||||
|
<template #label>{{ i18n.ts._role._options.userEachUserListsMax }}</template>
|
||||||
|
<template #suffix>{{ options_userEachUserListsLimit_useDefault ? i18n.ts._role.useBaseValue : (options_userEachUserListsLimit_value) }}</template>
|
||||||
|
<div class="_gaps">
|
||||||
|
<MkSwitch v-model="options_userEachUserListsLimit_useDefault" :readonly="readonly">
|
||||||
|
<template #label>{{ i18n.ts._role.useBaseValue }}</template>
|
||||||
|
</MkSwitch>
|
||||||
|
<MkInput v-model="options_userEachUserListsLimit_value" :disabled="options_userEachUserListsLimit_useDefault" type="number" :readonly="readonly">
|
||||||
|
</MkInput>
|
||||||
|
</div>
|
||||||
|
</MkFolder>
|
||||||
</div>
|
</div>
|
||||||
</FormSlot>
|
</FormSlot>
|
||||||
|
|
||||||
|
@ -251,6 +275,10 @@ let options_clipLimit_useDefault = $ref(role?.options?.clipLimit?.useDefault ??
|
||||||
let options_clipLimit_value = $ref(role?.options?.clipLimit?.value ?? 0);
|
let options_clipLimit_value = $ref(role?.options?.clipLimit?.value ?? 0);
|
||||||
let options_noteEachClipsLimit_useDefault = $ref(role?.options?.noteEachClipsLimit?.useDefault ?? true);
|
let options_noteEachClipsLimit_useDefault = $ref(role?.options?.noteEachClipsLimit?.useDefault ?? true);
|
||||||
let options_noteEachClipsLimit_value = $ref(role?.options?.noteEachClipsLimit?.value ?? 0);
|
let options_noteEachClipsLimit_value = $ref(role?.options?.noteEachClipsLimit?.value ?? 0);
|
||||||
|
let options_userListLimit_useDefault = $ref(role?.options?.userListLimit?.useDefault ?? true);
|
||||||
|
let options_userListLimit_value = $ref(role?.options?.userListLimit?.value ?? 0);
|
||||||
|
let options_userEachUserListsLimit_useDefault = $ref(role?.options?.userEachUserListsLimit?.useDefault ?? true);
|
||||||
|
let options_userEachUserListsLimit_value = $ref(role?.options?.userEachUserListsLimit?.value ?? 0);
|
||||||
|
|
||||||
if (_DEV_) {
|
if (_DEV_) {
|
||||||
watch($$(condFormula), () => {
|
watch($$(condFormula), () => {
|
||||||
|
@ -271,6 +299,8 @@ function getOptions() {
|
||||||
webhookLimit: { useDefault: options_webhookLimit_useDefault, value: options_webhookLimit_value },
|
webhookLimit: { useDefault: options_webhookLimit_useDefault, value: options_webhookLimit_value },
|
||||||
clipLimit: { useDefault: options_clipLimit_useDefault, value: options_clipLimit_value },
|
clipLimit: { useDefault: options_clipLimit_useDefault, value: options_clipLimit_value },
|
||||||
noteEachClipsLimit: { useDefault: options_noteEachClipsLimit_useDefault, value: options_noteEachClipsLimit_value },
|
noteEachClipsLimit: { useDefault: options_noteEachClipsLimit_useDefault, value: options_noteEachClipsLimit_value },
|
||||||
|
userListLimit: { useDefault: options_userListLimit_useDefault, value: options_userListLimit_value },
|
||||||
|
userEachUserListsLimit: { useDefault: options_userEachUserListsLimit_useDefault, value: options_userEachUserListsLimit_value },
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -92,6 +92,20 @@
|
||||||
</MkInput>
|
</MkInput>
|
||||||
</MkFolder>
|
</MkFolder>
|
||||||
|
|
||||||
|
<MkFolder>
|
||||||
|
<template #label>{{ i18n.ts._role._options.userListMax }}</template>
|
||||||
|
<template #suffix>{{ options_userListLimit }}</template>
|
||||||
|
<MkInput v-model="options_userListLimit" type="number">
|
||||||
|
</MkInput>
|
||||||
|
</MkFolder>
|
||||||
|
|
||||||
|
<MkFolder>
|
||||||
|
<template #label>{{ i18n.ts._role._options.userEachUserListsMax }}</template>
|
||||||
|
<template #suffix>{{ options_userEachUserListsLimit }}</template>
|
||||||
|
<MkInput v-model="options_userEachUserListsLimit" type="number">
|
||||||
|
</MkInput>
|
||||||
|
</MkFolder>
|
||||||
|
|
||||||
<MkButton primary rounded @click="updateBaseRole">{{ i18n.ts.save }}</MkButton>
|
<MkButton primary rounded @click="updateBaseRole">{{ i18n.ts.save }}</MkButton>
|
||||||
</div>
|
</div>
|
||||||
</MkFolder>
|
</MkFolder>
|
||||||
|
@ -135,6 +149,8 @@ let options_wordMuteLimit = $ref(instance.baseRole.wordMuteLimit);
|
||||||
let options_webhookLimit = $ref(instance.baseRole.webhookLimit);
|
let options_webhookLimit = $ref(instance.baseRole.webhookLimit);
|
||||||
let options_clipLimit = $ref(instance.baseRole.clipLimit);
|
let options_clipLimit = $ref(instance.baseRole.clipLimit);
|
||||||
let options_noteEachClipsLimit = $ref(instance.baseRole.noteEachClipsLimit);
|
let options_noteEachClipsLimit = $ref(instance.baseRole.noteEachClipsLimit);
|
||||||
|
let options_userListLimit = $ref(instance.baseRole.userListLimit);
|
||||||
|
let options_userEachUserListsLimit = $ref(instance.baseRole.userEachUserListsLimit);
|
||||||
|
|
||||||
async function updateBaseRole() {
|
async function updateBaseRole() {
|
||||||
await os.apiWithDialog('admin/roles/update-default-role-override', {
|
await os.apiWithDialog('admin/roles/update-default-role-override', {
|
||||||
|
@ -150,6 +166,8 @@ async function updateBaseRole() {
|
||||||
webhookLimit: options_webhookLimit,
|
webhookLimit: options_webhookLimit,
|
||||||
clipLimit: options_clipLimit,
|
clipLimit: options_clipLimit,
|
||||||
noteEachClipsLimit: options_noteEachClipsLimit,
|
noteEachClipsLimit: options_noteEachClipsLimit,
|
||||||
|
userListLimit: options_userListLimit,
|
||||||
|
userEachUserListsLimit: options_userEachUserListsLimit,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue