From 0cc58cffa6ed750124963f65b8c1cfaf82da752f Mon Sep 17 00:00:00 2001 From: Shigma <1700011071@pku.edu.cn> Date: Wed, 15 Jan 2020 03:20:08 +0800 Subject: [PATCH] feat(plugin-common): optimize admin command --- packages/koishi-core/src/database.ts | 2 + packages/plugin-common/src/admin.ts | 63 ++++++---- .../tests/__snapshots__/admin.spec.ts.snap | 9 ++ packages/plugin-common/tests/admin.spec.ts | 113 ++++++++++++++++++ 4 files changed, 166 insertions(+), 21 deletions(-) create mode 100644 packages/plugin-common/tests/__snapshots__/admin.spec.ts.snap create mode 100644 packages/plugin-common/tests/admin.spec.ts diff --git a/packages/koishi-core/src/database.ts b/packages/koishi-core/src/database.ts index 9b17ba8e4c..7fc04ac9aa 100644 --- a/packages/koishi-core/src/database.ts +++ b/packages/koishi-core/src/database.ts @@ -60,6 +60,8 @@ export enum GroupFlag { noEmit = 4, } +export const groupFlags: (keyof typeof GroupFlag)[] = ['noCommand', 'noResponse', 'noEmit'] + export type Group = Observed> export type GroupField = keyof GroupData export const groupFields: GroupField[] = [] diff --git a/packages/plugin-common/src/admin.ts b/packages/plugin-common/src/admin.ts index 5de6db7dab..f808468782 100644 --- a/packages/plugin-common/src/admin.ts +++ b/packages/plugin-common/src/admin.ts @@ -1,4 +1,4 @@ -import { Context, User, userFlags, UserFlag, Meta, UserField, getTargetId, CommandConfig, GroupField, UserData, GroupData } from 'koishi-core' +import { Context, User, userFlags, UserFlag, Meta, UserField, getTargetId, CommandConfig, GroupField, UserData, GroupData, GroupFlag, groupFlags, Group, userFields, groupFields } from 'koishi-core' import { isInteger, difference, Observed, paramCase } from 'koishi-utils' type ActionCallback = @@ -17,11 +17,11 @@ export interface GroupAction { const userActionMap: Record = {} const groupActionMap: Record = {} -export function registerUserAction (name: string, callback: ActionCallback, fields: K[] = []) { +export function registerUserAction (name: string, callback: ActionCallback, fields?: K[]) { userActionMap[paramCase(name)] = { callback, fields } } -export function registerGroupAction (name: string, callback: ActionCallback, fields: K[] = []) { +export function registerGroupAction (name: string, callback: ActionCallback, fields?: K[]) { groupActionMap[paramCase(name)] = { callback, fields } } @@ -36,7 +36,7 @@ registerUserAction('setAuth', async (meta, user, value) => { await user._update() return meta.$send('用户权限已修改。') } -}) +}, ['authority']) registerUserAction('setFlag', async (meta, user, ...flags) => { if (!flags.length) return meta.$send(`可用的标记有 ${userFlags.join(', ')}。`) @@ -47,10 +47,10 @@ registerUserAction('setFlag', async (meta, user, ...flags) => { } await user._update() return meta.$send('用户信息已修改。') -}) +}, ['flag']) registerUserAction('unsetFlag', async (meta, user, ...flags) => { - if (!flags.length) return meta.$send(`可用的 flag 有:${userFlags.join(', ')}。`) + if (!flags.length) return meta.$send(`可用的标记有 ${userFlags.join(', ')}。`) const notFound = difference(flags, userFlags) if (notFound.length) return meta.$send(`未找到标记 ${notFound.join(', ')}。`) for (const name of flags) { @@ -58,7 +58,7 @@ registerUserAction('unsetFlag', async (meta, user, ...flags) => { } await user._update() return meta.$send('用户信息已修改。') -}) +}, ['flag']) registerUserAction('clearUsage', async (meta, user, ...commands) => { if (commands.length) { @@ -70,7 +70,7 @@ registerUserAction('clearUsage', async (meta, user, ...commands) => { } await user._update() return meta.$send('用户信息已修改。') -}) +}, ['usage']) registerUserAction('showUsage', async (meta, user, ...commands) => { const { usage } = user @@ -80,7 +80,29 @@ registerUserAction('showUsage', async (meta, user, ...commands) => { '用户今日各指令的调用次数为:', ...commands.sort().map(name => `${name}:${usage[name] ? usage[name].count : 0} 次`), ].join('\n')) -}) +}, ['usage']) + +registerGroupAction('setFlag', async (meta, group, ...flags) => { + if (!flags.length) return meta.$send(`可用的标记有 ${groupFlags.join(', ')}。`) + const notFound = difference(flags, groupFlags) + if (notFound.length) return meta.$send(`未找到标记 ${notFound.join(', ')}。`) + for (const name of flags) { + group.flag |= GroupFlag[name] + } + await group._update() + return meta.$send('群信息已修改。') +}, ['flag']) + +registerGroupAction('unsetFlag', async (meta, group, ...flags) => { + if (!flags.length) return meta.$send(`可用的标记有 ${groupFlags.join(', ')}。`) + const notFound = difference(flags, groupFlags) + if (notFound.length) return meta.$send(`未找到标记 ${notFound.join(', ')}。`) + for (const name of flags) { + group.flag &= ~GroupFlag[name] + } + await group._update() + return meta.$send('群信息已修改。') +}, ['flag']) export default function apply (ctx: Context, options: CommandConfig) { const userActions = Object.keys(userActionMap).map(paramCase).join(', ') @@ -92,35 +114,34 @@ export default function apply (ctx: Context, options: CommandConfig) { .option('-G, --this-group', '指定目标群为本群') .action(async ({ meta, options }, name: string, ...args: string[]) => { const isGroup = 'g' in options || 'G' in options - if ('user' in options && isGroup) { - return meta.$send('不能同时目标为指定用户和群。') - } + if ('user' in options && isGroup) return meta.$send('不能同时目标为指定用户和群。') + const actionList = isGroup ? groupActions : userActions const actionMap = isGroup ? groupActionMap : userActionMap - if (!name) { - return meta.$send(`当前的可用指令有:${actionList}。`) - } + if (!name) return meta.$send(`当前的可用指令有:${actionList}。`) + const action = actionMap[paramCase(name)] if (!action) return meta.$send(`指令未找到。当前的可用指令有:${actionList}。`) if (isGroup) { - let group: Observed + const fields = action.fields ? action.fields.slice() as GroupField[] : groupFields + let group: Group if (options.thisGroup) { - group = await ctx.database.observeGroup(meta.$group) - } else if (typeof options.group === 'number') { - group = await ctx.database.observeGroup(options.group) + group = await ctx.database.observeGroup(meta.$group, fields) + } else if (isInteger(options.group) && options.group > 0) { + group = await ctx.database.observeGroup(options.group, fields) } if (!group) return meta.$send('未找到指定的群。') return action.callback.call(ctx, meta, group, ...args) } else { - const fields = action.fields.slice() as UserField[] + const fields = action.fields ? action.fields.slice() as UserField[] : userFields if (!fields.includes('authority')) fields.push('authority') let user: User if (options.user) { const qq = getTargetId(options.user) if (!qq) return meta.$send('未指定目标。') user = await ctx.database.observeUser(qq, -1, fields) - if (!user) return meta.$send('未找到用户。') + if (!user) return meta.$send('未找到指定的用户。') if (qq !== meta.$user.id && meta.$user.authority <= user.authority) return meta.$send('权限不足。') } else { user = await ctx.database.observeUser(meta.$user, 0, fields) diff --git a/packages/plugin-common/tests/__snapshots__/admin.spec.ts.snap b/packages/plugin-common/tests/__snapshots__/admin.spec.ts.snap new file mode 100644 index 0000000000..df5f3f4613 --- /dev/null +++ b/packages/plugin-common/tests/__snapshots__/admin.spec.ts.snap @@ -0,0 +1,9 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`group operations list actions: admin -G 1`] = `"当前的可用指令有:set-flag, unset-flag。"`; + +exports[`group operations list actions: admin -G foo 1`] = `"指令未找到。当前的可用指令有:set-flag, unset-flag。"`; + +exports[`user operations list actions: admin 1`] = `"当前的可用指令有:set-auth, set-flag, unset-flag, clear-usage, show-usage。"`; + +exports[`user operations list actions: admin foo 1`] = `"指令未找到。当前的可用指令有:set-auth, set-flag, unset-flag, clear-usage, show-usage。"`; diff --git a/packages/plugin-common/tests/admin.spec.ts b/packages/plugin-common/tests/admin.spec.ts new file mode 100644 index 0000000000..93608cf55a --- /dev/null +++ b/packages/plugin-common/tests/admin.spec.ts @@ -0,0 +1,113 @@ +import { MockedApp, MemoryDatabase } from 'koishi-test-utils' +import { registerDatabase, userFlags, groupFlags, UserFlag, GroupFlag } from 'koishi-core' +import admin, { registerUserAction, registerGroupAction } from '../src/admin' + +registerDatabase('memory', MemoryDatabase) + +const app = new MockedApp({ database: { memory: {} } }) +const session = app.createSession('group', 123, 321) + +app.plugin(admin) +app.command('foo', { maxUsage: 10 }).action(({ meta }) => meta.$send('bar')) +app.command('bar', { maxUsage: 10 }).action(({ meta }) => meta.$send('foo')) + +beforeAll(async () => { + await app.start() + await app.database.getUser(123, 4) + await app.database.getUser(456, 3) + await app.database.getUser(789, 4) + await app.database.getGroup(321, app.selfId) + await app.database.getGroup(654, app.selfId) +}) + +describe('basic features', () => { + test('check', async () => { + await session.shouldHaveReply('admin -u 456 -g 321', '不能同时目标为指定用户和群。') + }) +}) + +describe('user operations', () => { + test('list actions', async () => { + await session.shouldMatchSnapshot('admin') + await session.shouldMatchSnapshot('admin foo') + }) + + test('check target', async () => { + await session.shouldHaveReply('admin -u bar set-flag', '未指定目标。') + await session.shouldHaveReply('admin -u 233 set-flag', '未找到指定的用户。') + await session.shouldHaveReply('admin -u 789 show-usage', '权限不足。') + }) + + test('setAuth', async () => { + await session.shouldHaveReply('admin -u 456 set-auth -1', '参数错误。') + await session.shouldHaveReply('admin -u 456 set-auth 3', '用户权限未改动。') + await session.shouldHaveReply('admin -u 456 set-auth 2', '用户权限已修改。') + await session.shouldHaveReply('admin -u 456 set-auth 4', '权限不足。') + }) + + test('setFlag', async () => { + await session.shouldHaveReply('admin -u 456 set-flag', `可用的标记有 ${userFlags.join(', ')}。`) + await session.shouldHaveReply('admin -u 456 set-flag foo', '未找到标记 foo。') + await session.shouldHaveReply('admin -u 456 set-flag ignore', '用户信息已修改。') + await expect(app.database.getUser(456)).resolves.toHaveProperty('flag', UserFlag.ignore) + }) + + test('unsetFlag', async () => { + await session.shouldHaveReply('admin -u 456 unset-flag', `可用的标记有 ${userFlags.join(', ')}。`) + await session.shouldHaveReply('admin -u 456 unset-flag foo', '未找到标记 foo。') + await session.shouldHaveReply('admin -u 456 unset-flag ignore', '用户信息已修改。') + await expect(app.database.getUser(456)).resolves.toHaveProperty('flag', 0) + }) + + test('showUsage', async () => { + await session.shouldHaveReply('admin show-usage', '用户今日没有调用过指令。') + await session.shouldHaveReply('foo', 'bar') + await session.shouldHaveReply('admin show-usage', '用户今日各指令的调用次数为:\nfoo:1 次') + await session.shouldHaveReply('admin show-usage foo bar', '用户今日各指令的调用次数为:\nbar:0 次\nfoo:1 次') + }) + + test('clearUsage', async () => { + await session.shouldHaveReply('bar', 'foo') + await session.shouldHaveReply('admin clear-usage foo', '用户信息已修改。') + await session.shouldHaveReply('admin show-usage', '用户今日各指令的调用次数为:\nbar:1 次') + await session.shouldHaveReply('admin clear-usage', '用户信息已修改。') + await session.shouldHaveReply('admin show-usage', '用户今日没有调用过指令。') + }) +}) + +describe('group operations', () => { + test('list actions', async () => { + await session.shouldMatchSnapshot('admin -G') + await session.shouldMatchSnapshot('admin -G foo') + }) + + test('check target', async () => { + await session.shouldHaveReply('admin -g bar set-flag', '未找到指定的群。') + }) + + test('setFlag', async () => { + await session.shouldHaveReply('admin -G set-flag', `可用的标记有 ${groupFlags.join(', ')}。`) + await session.shouldHaveReply('admin -g 654 set-flag foo', '未找到标记 foo。') + await session.shouldHaveReply('admin -g 654 set-flag noCommand noEmit', '群信息已修改。') + await expect(app.database.getGroup(654)).resolves.toHaveProperty('flag', GroupFlag.noCommand | GroupFlag.noEmit) + }) + + test('unsetFlag', async () => { + await session.shouldHaveReply('admin -G unset-flag', `可用的标记有 ${groupFlags.join(', ')}。`) + await session.shouldHaveReply('admin -g 654 unset-flag foo', '未找到标记 foo。') + await session.shouldHaveReply('admin -g 654 unset-flag noEmit noResponse', '群信息已修改。') + await expect(app.database.getGroup(654)).resolves.toHaveProperty('flag', GroupFlag.noCommand) + }) +}) + +describe('custom actions', () => { + test('user action', async () => { + registerUserAction('test', meta => meta.$send('foo')) + await session.shouldHaveReply('admin test', 'foo') + }) + + test('group action', async () => { + registerGroupAction('test', meta => meta.$send('bar')) + await session.shouldHaveReply('admin -G test', 'bar') + }) +})