mirror of
https://github.com/nonebot/nonebot2.git
synced 2025-01-19 17:58:26 +08:00
Lots of updates
This commit is contained in:
parent
1835a4c33d
commit
a13128f356
@ -74,7 +74,7 @@ def load_builtin_plugins():
|
||||
load_plugins(plugin_dir, 'none.plugins')
|
||||
|
||||
|
||||
from .command import on_command, CommandSession
|
||||
from .command import on_command, CommandSession, CommandGroup
|
||||
from .notice_request import (
|
||||
on_notice, NoticeSession,
|
||||
on_request, RequestSession,
|
||||
|
@ -5,13 +5,13 @@ from typing import (
|
||||
Tuple, Union, Callable, Iterable, Dict, Any, Optional, Sequence
|
||||
)
|
||||
|
||||
from aiocqhttp import CQHttp, Error as CQHttpError
|
||||
from aiocqhttp import CQHttp
|
||||
from aiocqhttp.message import Message
|
||||
|
||||
from . import permissions as perm
|
||||
from ..helpers import context_source
|
||||
from ..expression import render
|
||||
from ..session import BaseSession
|
||||
from . import permission as perm
|
||||
from .helpers import context_source
|
||||
from .expression import render
|
||||
from .session import BaseSession
|
||||
|
||||
# Key: str (one segment of command name)
|
||||
# Value: subtree or a leaf Command object
|
||||
@ -37,17 +37,20 @@ class Command:
|
||||
self.only_to_me = only_to_me
|
||||
self.args_parser_func = None
|
||||
|
||||
async def run(self, session, *, permission: Optional[int] = None) -> bool:
|
||||
async def run(self, session, check_perm: bool = True) -> bool:
|
||||
"""
|
||||
Run the command in a given session.
|
||||
|
||||
:param session: CommandSession object
|
||||
:param permission: the permission the caller owns
|
||||
:param check_perm: should check permission before running
|
||||
:return: the command is finished
|
||||
"""
|
||||
if permission is None:
|
||||
permission = await _calculate_permission(session.bot, session.ctx)
|
||||
if self.func and permission & self.permission:
|
||||
if check_perm:
|
||||
has_perm = await perm.check_permission(
|
||||
session.bot, session.ctx, self.permission)
|
||||
else:
|
||||
has_perm = True
|
||||
if self.func and has_perm:
|
||||
if self.args_parser_func:
|
||||
await self.args_parser_func(session)
|
||||
await self.func(session)
|
||||
@ -55,48 +58,6 @@ class Command:
|
||||
return False
|
||||
|
||||
|
||||
async def _calculate_permission(bot: CQHttp, ctx: Dict[str, Any]) -> int:
|
||||
"""
|
||||
Calculate the permission OWNED by the current context.
|
||||
|
||||
This is different from the permission REQUIRED by a command.
|
||||
The result of this function should be made a bit-and with
|
||||
the permission required by some command to check whether
|
||||
the context is allowed to call the command.
|
||||
|
||||
:param bot: CQHttp instance
|
||||
:param ctx: message context
|
||||
:return: the calculated permission value
|
||||
"""
|
||||
permission = 0
|
||||
if ctx['user_id'] in bot.config.SUPERUSERS:
|
||||
permission |= perm.IS_SUPERUSER
|
||||
if ctx['message_type'] == 'private':
|
||||
if ctx['sub_type'] == 'friend':
|
||||
permission |= perm.IS_PRIVATE_FRIEND
|
||||
elif ctx['sub_type'] == 'group':
|
||||
permission |= perm.IS_PRIVATE_GROUP
|
||||
elif ctx['sub_type'] == 'discuss':
|
||||
permission |= perm.IS_PRIVATE_DISCUSS
|
||||
elif ctx['sub_type'] == 'other':
|
||||
permission |= perm.IS_PRIVATE_OTHER
|
||||
elif ctx['message_type'] == 'group':
|
||||
permission |= perm.IS_GROUP_MEMBER
|
||||
if not ctx['anonymous']:
|
||||
try:
|
||||
member_info = await bot.get_group_member_info(**ctx)
|
||||
if member_info:
|
||||
if member_info['role'] == 'owner':
|
||||
permission |= perm.IS_GROUP_OWNER
|
||||
elif member_info['role'] == 'admin':
|
||||
permission |= perm.IS_GROUP_ADMIN
|
||||
except CQHttpError:
|
||||
pass
|
||||
elif ctx['message_type'] == 'discuss':
|
||||
permission |= perm.IS_DISCUSS
|
||||
return permission
|
||||
|
||||
|
||||
def on_command(name: Union[str, Tuple[str]], *,
|
||||
aliases: Iterable = (),
|
||||
permission: int = perm.EVERYBODY,
|
||||
@ -325,10 +286,13 @@ async def handle_command(bot: CQHttp, ctx: Dict[str, Any]) -> bool:
|
||||
"""
|
||||
src = context_source(ctx)
|
||||
session = None
|
||||
check_perm = True
|
||||
if _sessions.get(src):
|
||||
session = _sessions[src]
|
||||
if session and session.is_valid:
|
||||
session.refresh(ctx, current_arg=str(ctx['message']))
|
||||
# there is no need to check permission for existing session
|
||||
check_perm = False
|
||||
else:
|
||||
# the session is expired, remove it
|
||||
del _sessions[src]
|
||||
@ -340,7 +304,7 @@ async def handle_command(bot: CQHttp, ctx: Dict[str, Any]) -> bool:
|
||||
_sessions[src] = session
|
||||
|
||||
try:
|
||||
res = await session.cmd.run(session)
|
||||
res = await session.cmd.run(session, check_perm=check_perm)
|
||||
# the command is finished, remove the session
|
||||
del _sessions[src]
|
||||
return res
|
@ -1,25 +0,0 @@
|
||||
PRIVATE_FRIEND = 0x0001
|
||||
PRIVATE_GROUP = 0x0002
|
||||
PRIVATE_DISCUSS = 0x0004
|
||||
PRIVATE_OTHER = 0x0008
|
||||
PRIVATE = 0x000F
|
||||
DISCUSS = 0x00F0
|
||||
GROUP_MEMBER = 0x0100
|
||||
GROUP_ADMIN = 0x0200
|
||||
GROUP_OWNER = 0x0400
|
||||
GROUP = 0x0F00
|
||||
SUPERUSER = 0xF000
|
||||
EVERYBODY = 0xFFFF
|
||||
|
||||
IS_NOBODY = 0x0000
|
||||
IS_PRIVATE_FRIEND = PRIVATE_FRIEND
|
||||
IS_PRIVATE_GROUP = PRIVATE_GROUP
|
||||
IS_PRIVATE_DISCUSS = PRIVATE_DISCUSS
|
||||
IS_PRIVATE_OTHER = PRIVATE_OTHER
|
||||
IS_PRIVATE = PRIVATE
|
||||
IS_DISCUSS = DISCUSS
|
||||
IS_GROUP_MEMBER = GROUP_MEMBER
|
||||
IS_GROUP_ADMIN = GROUP_MEMBER | GROUP_ADMIN
|
||||
IS_GROUP_OWNER = GROUP_ADMIN | GROUP_OWNER
|
||||
IS_GROUP = GROUP
|
||||
IS_SUPERUSER = 0xFFFF
|
@ -4,8 +4,8 @@ from aiocqhttp import CQHttp
|
||||
from aiocqhttp.message import MessageSegment
|
||||
|
||||
from .command import handle_command
|
||||
from .natural_language import handle_natural_language
|
||||
from .log import logger
|
||||
from .helpers import send
|
||||
|
||||
|
||||
async def handle_message(bot: CQHttp, ctx: Dict[str, Any]) -> None:
|
||||
@ -23,9 +23,10 @@ async def handle_message(bot: CQHttp, ctx: Dict[str, Any]) -> None:
|
||||
|
||||
handled = await handle_command(bot, ctx)
|
||||
if handled:
|
||||
logger.debug('Message is handled as a command')
|
||||
logger.debug('Message is handled as command')
|
||||
return
|
||||
elif ctx['to_me']:
|
||||
await send(bot, ctx, '你在说什么我看不懂诶')
|
||||
|
||||
# TODO: NLP
|
||||
handled = await handle_natural_language(bot, ctx)
|
||||
if handled:
|
||||
logger.debug('Message is handled as natural language')
|
||||
return
|
||||
|
22
none/natural_language.py
Normal file
22
none/natural_language.py
Normal file
@ -0,0 +1,22 @@
|
||||
from collections import namedtuple
|
||||
from typing import Dict, Any
|
||||
|
||||
from aiocqhttp import CQHttp
|
||||
|
||||
_nl_processors = set()
|
||||
|
||||
|
||||
class NLProcessor:
|
||||
__slots__ = ('func', 'permission', 'only_to_me', 'keywords',
|
||||
'precondition_func')
|
||||
|
||||
|
||||
NLPResult = namedtuple('NLPResult', (
|
||||
'confidence',
|
||||
'cmd_name',
|
||||
'cmd_args',
|
||||
))
|
||||
|
||||
|
||||
async def handle_natural_language(bot: CQHttp, ctx: Dict[str, Any]) -> None:
|
||||
pass
|
91
none/permission.py
Normal file
91
none/permission.py
Normal file
@ -0,0 +1,91 @@
|
||||
from collections import namedtuple
|
||||
from typing import Dict, Any
|
||||
|
||||
from aiocache import cached
|
||||
from aiocqhttp import CQHttp, Error as CQHttpError
|
||||
|
||||
PRIVATE_FRIEND = 0x0001
|
||||
PRIVATE_GROUP = 0x0002
|
||||
PRIVATE_DISCUSS = 0x0004
|
||||
PRIVATE_OTHER = 0x0008
|
||||
PRIVATE = 0x000F
|
||||
DISCUSS = 0x00F0
|
||||
GROUP_MEMBER = 0x0100
|
||||
GROUP_ADMIN = 0x0200
|
||||
GROUP_OWNER = 0x0400
|
||||
GROUP = 0x0F00
|
||||
SUPERUSER = 0xF000
|
||||
EVERYBODY = 0xFFFF
|
||||
|
||||
IS_NOBODY = 0x0000
|
||||
IS_PRIVATE_FRIEND = PRIVATE_FRIEND
|
||||
IS_PRIVATE_GROUP = PRIVATE_GROUP
|
||||
IS_PRIVATE_DISCUSS = PRIVATE_DISCUSS
|
||||
IS_PRIVATE_OTHER = PRIVATE_OTHER
|
||||
IS_PRIVATE = PRIVATE
|
||||
IS_DISCUSS = DISCUSS
|
||||
IS_GROUP_MEMBER = GROUP_MEMBER
|
||||
IS_GROUP_ADMIN = GROUP_MEMBER | GROUP_ADMIN
|
||||
IS_GROUP_OWNER = GROUP_ADMIN | GROUP_OWNER
|
||||
IS_GROUP = GROUP
|
||||
IS_SUPERUSER = 0xFFFF
|
||||
|
||||
_min_context_fields = (
|
||||
'message_type',
|
||||
'sub_type',
|
||||
'user_id',
|
||||
'discuss_id',
|
||||
'group_id',
|
||||
'anonymous',
|
||||
)
|
||||
|
||||
_MinContext = namedtuple('MinContext', _min_context_fields)
|
||||
|
||||
|
||||
async def check_permission(bot: CQHttp, ctx: Dict[str, Any],
|
||||
permission_required: int) -> bool:
|
||||
min_ctx_kwargs = {}
|
||||
for field in _min_context_fields:
|
||||
if field in ctx:
|
||||
min_ctx_kwargs[field] = ctx[field]
|
||||
else:
|
||||
min_ctx_kwargs[field] = None
|
||||
min_ctx = _MinContext(**min_ctx_kwargs)
|
||||
return await _check(bot, min_ctx, permission_required)
|
||||
|
||||
|
||||
@cached(ttl=2 * 60) # cache the result for 1 minute
|
||||
async def _check(bot: CQHttp, min_ctx: _MinContext,
|
||||
permission_required: int) -> bool:
|
||||
permission = 0
|
||||
if min_ctx.user_id in bot.config.SUPERUSERS:
|
||||
permission |= IS_SUPERUSER
|
||||
if min_ctx.message_type == 'private':
|
||||
if min_ctx.sub_type == 'friend':
|
||||
permission |= IS_PRIVATE_FRIEND
|
||||
elif min_ctx.sub_type == 'group':
|
||||
permission |= IS_PRIVATE_GROUP
|
||||
elif min_ctx.sub_type == 'discuss':
|
||||
permission |= IS_PRIVATE_DISCUSS
|
||||
elif min_ctx.sub_type == 'other':
|
||||
permission |= IS_PRIVATE_OTHER
|
||||
elif min_ctx.message_type == 'group':
|
||||
permission |= IS_GROUP_MEMBER
|
||||
if not min_ctx.anonymous:
|
||||
try:
|
||||
member_info = await bot.get_group_member_info(
|
||||
group_id=min_ctx.group_id,
|
||||
user_id=min_ctx.user_id,
|
||||
no_cache=True
|
||||
)
|
||||
if member_info:
|
||||
if member_info['role'] == 'owner':
|
||||
permission |= IS_GROUP_OWNER
|
||||
elif member_info['role'] == 'admin':
|
||||
permission |= IS_GROUP_ADMIN
|
||||
except CQHttpError:
|
||||
pass
|
||||
elif min_ctx.message_type == 'discuss':
|
||||
permission |= IS_DISCUSS
|
||||
|
||||
return bool(permission & permission_required)
|
@ -1,15 +1,14 @@
|
||||
from aiocqhttp.message import unescape
|
||||
|
||||
from none import on_command, CommandSession
|
||||
from none.command import permissions as perm
|
||||
from none import on_command, CommandSession, permission as perm
|
||||
|
||||
|
||||
@on_command('echo', only_to_me=False)
|
||||
async def echo(session: CommandSession):
|
||||
await session.send(session.args.get('text') or session.current_arg)
|
||||
await session.send(session.args.get('message') or session.current_arg)
|
||||
|
||||
|
||||
@on_command('say', permission=perm.SUPERUSER, only_to_me=False)
|
||||
async def _(session: CommandSession):
|
||||
await session.send(
|
||||
unescape(session.args.get('text') or session.current_arg))
|
||||
unescape(session.args.get('message') or session.current_arg))
|
||||
|
@ -1,4 +1,4 @@
|
||||
from none.command import CommandSession, CommandGroup
|
||||
from none import CommandSession, CommandGroup
|
||||
|
||||
from . import expressions as expr
|
||||
|
||||
@ -17,6 +17,26 @@ async def _(session: CommandSession):
|
||||
session.args[session.current_key] = session.current_arg_text.strip()
|
||||
|
||||
|
||||
# @on_natural_language(keywords={'天气', '雨', '雪', '晴', '阴', '多云', '冰雹'},
|
||||
# only_to_me=False)
|
||||
# async def weather_nlp(session: NaturalLanguageSession):
|
||||
# return NLPResult(89.5, ('weather', 'weather'), {'city': '南京'})
|
||||
#
|
||||
#
|
||||
# @weather_nlp.condition
|
||||
# async def _(session: NaturalLanguageSession):
|
||||
# keywords = {'天气', '雨', '雪', '晴', '阴', '多云', '冰雹'}
|
||||
# for kw in keywords:
|
||||
# if kw in session.text:
|
||||
# keyword_hit = True
|
||||
# break
|
||||
# else:
|
||||
# keyword_hit = False
|
||||
# if session.ctx['to_me'] and keyword_hit:
|
||||
# return True
|
||||
# return False
|
||||
|
||||
|
||||
@w.command('suggestion', aliases=('生活指数', '生活建议', '生活提示'))
|
||||
async def suggestion(session: CommandSession):
|
||||
await session.send('suggestion')
|
||||
|
2
setup.py
2
setup.py
@ -14,7 +14,7 @@ setup(
|
||||
description='A QQ bot framework',
|
||||
long_description=long_description,
|
||||
long_description_content_type="text/markdown",
|
||||
install_requires=['aiocqhttp>=0.3'],
|
||||
install_requires=['aiocqhttp>=0.3', 'aiocache'],
|
||||
python_requires='>=3.6',
|
||||
platforms='any',
|
||||
classifiers=(
|
||||
|
Loading…
Reference in New Issue
Block a user