diff --git a/bot.py b/bot.py index 1c27a003..7aec6e22 100644 --- a/bot.py +++ b/bot.py @@ -66,4 +66,4 @@ while True: if (end - start).total_seconds() > 20: slow_mode = True else: - sleep(0.2) \ No newline at end of file + sleep(0.01) \ No newline at end of file diff --git a/config/config.cfg.example b/config/config.cfg.example index 568eed70..ee32340e 100644 --- a/config/config.cfg.example +++ b/config/config.cfg.example @@ -1,6 +1,7 @@ [cfg] cache_path = ./cache/ db_path = mysql+pymysql:// +db_cache = False debug_flag = True qq_enable_chat_log = True qq_msg_logging_to_db = False diff --git a/core/bots/aiogram/message.py b/core/bots/aiogram/message.py index f1a216cc..15424c97 100644 --- a/core/bots/aiogram/message.py +++ b/core/bots/aiogram/message.py @@ -10,6 +10,15 @@ from core.elements.others import confirm_command from database import BotDBUtil +def convert2lst(s) -> list: + if isinstance(s, str): + return [Plain(s)] + elif isinstance(s, list): + return s + elif isinstance(s, tuple): + return list(s) + + class MessageSession(MS): class Feature: image = True @@ -22,33 +31,42 @@ class MessageSession(MS): return MessageSession(target=MsgInfo(targetId=0, senderId=0, senderName='', targetFrom='Telegram|Bot', senderFrom='Telegram|Bot'), session=Session(message=send, target=send.chat.id, sender=send.from_user.id)) - if isinstance(msgchain, list): + if isinstance(msgchain, (list, tuple)): count = 0 send_list = [] for x in msgchain: if isinstance(x, Plain): send = await bot.send_message(self.session.target, x.text, - reply_to_message_id=self.session.message.message_id if quote and self.session.message else None) - send_list.append(send) - count += 1 + reply_to_message_id=self.session.message.message_id if quote + and count == 0 and self.session.message else None) if isinstance(x, Image): with open(await x.get(), 'rb') as image: send = await bot.send_photo(self.session.target, image, - reply_to_message_id=self.session.message.message_id if quote and self.session.message else None) - send_list.append(send) - count += 1 + reply_to_message_id=self.session.message.message_id if quote + and count == 0 + and self.session.message else None) if isinstance(x, Voice): with open(x.path, 'rb') as voice: send = await bot.send_audio(self.session.target, voice, - reply_to_message_id=self.session.message.message_id if quote and self.session.message else None) + reply_to_message_id=self.session.message.message_id if quote + and count == 0 and self.session.message else None) + send_list.append(send) + count += 1 return MessageSession(target=MsgInfo(targetId=0, senderId=0, senderName='', targetFrom='Telegram|Bot', senderFrom='Telegram|Bot'), session=Session(message=send_list, target=send.chat.id, sender=send.from_user.id)) - async def waitConfirm(self): + async def waitConfirm(self, msgchain=None, quote=True): + send = None + if msgchain is not None: + msgchain = convert2lst(msgchain) + msgchain.append(Plain('(发送“是”或符合确认条件的词语来确认)')) + send = await self.sendMessage(msgchain, quote) flag = asyncio.Event() MessageTaskManager.add_task(self.session.sender, flag) await flag.wait() + if msgchain is not None: + await send.delete() if FinishedTasks.get()[self.session.sender].text in confirm_command: return True return False diff --git a/core/bots/discord/message.py b/core/bots/discord/message.py index 09ba043d..416fd633 100644 --- a/core/bots/discord/message.py +++ b/core/bots/discord/message.py @@ -10,6 +10,15 @@ from core.elements.others import confirm_command from database import BotDBUtil +def convert2lst(s) -> list: + if isinstance(s, str): + return [Plain(s)] + elif isinstance(s, list): + return s + elif isinstance(s, tuple): + return list(s) + + class MessageSession(MS): class Feature: image = True @@ -24,7 +33,7 @@ class MessageSession(MS): return MessageSession(target=MsgInfo(targetId=0, senderId=0, senderName='', targetFrom='Discord|Bot', senderFrom='Discord|Bot'), session=Session(message=send, target=send.channel, sender=send.author)) - if isinstance(msgchain, list): + if isinstance(msgchain, (list, tuple)): count = 0 send_list = [] for x in msgchain: @@ -41,11 +50,17 @@ class MessageSession(MS): senderFrom='Discord|Bot'), session=Session(message=send_list, target=send.channel, sender=send.author)) - async def waitConfirm(self): + async def waitConfirm(self, msgchain=None, quote=True): def check(m): return m.channel == self.session.message.channel and m.author == self.session.message.author - + send = None + if msgchain is not None: + msgchain = convert2lst(msgchain) + msgchain.append(Plain('(发送“是”或符合确认条件的词语来确认)')) + send = await self.sendMessage(msgchain, quote) msg = await client.wait_for('message', check=check) + if msgchain is not None: + await send.delete() return True if msg.content in confirm_command else False async def checkPermission(self): diff --git a/core/bots/graia/message.py b/core/bots/graia/message.py index d0204b80..ad359244 100644 --- a/core/bots/graia/message.py +++ b/core/bots/graia/message.py @@ -1,5 +1,8 @@ +import asyncio +import random import re import traceback +from typing import List from graia.application import MessageChain, GroupMessage, FriendMessage from graia.application.friend import Friend @@ -7,15 +10,13 @@ from graia.application.group import Group, Member from graia.application.message.elements.internal import Plain, Image, Source, Voice from graia.broadcast.interrupt import InterruptControl from graia.broadcast.interrupt.waiter import Waiter -from typing import List +from config import Config from core.bots.graia.broadcast import app, bcc from core.elements import Plain as BPlain, Image as BImage, Voice as BVoice, MessageSession as MS, MsgInfo, Session, \ FetchTarget as FT from core.elements.others import confirm_command from core.utils import slk_converter - -from config import Config from database import BotDBUtil from database.logging_message import LoggerMSG @@ -57,7 +58,7 @@ class MessageSession(MS): LoggerMSG(userid=self.target.senderId, command=self.trigger_msg, msg=msgchain.asDisplay()) if isinstance(self.session.target, Group) or self.target.targetFrom == 'QQ|Group': send = await app.sendGroupMessage(self.session.target, msgchain, quote=self.session.message[Source][0].id - if quote and self.session.message else None) + if quote and self.session.message else None) return MessageSession( target=MsgInfo(targetId=0, senderId=0, targetFrom='QQ|Bot', senderFrom="QQ|Bot", senderName=''), session=Session(message=send, target=0, sender=0)) @@ -67,7 +68,11 @@ class MessageSession(MS): target=MsgInfo(targetId=0, senderId=0, targetFrom='QQ|Bot', senderFrom="QQ|Bot", senderName=''), session=Session(message=send, target=0, sender=0)) - async def waitConfirm(self): + async def waitConfirm(self, msgchain=None, quote=True): + if msgchain is not None: + msgchain = await msgchain_gen(msgchain) + msgchain = msgchain.plusWith(MessageChain.create([Plain('(发送“是”或符合确认条件的词语来确认)')])) + send = await self.sendMessage(msgchain, quote=quote) inc = InterruptControl(bcc) if isinstance(self.session.target, Group): @Waiter.create_using_function([GroupMessage]) @@ -92,7 +97,10 @@ class MessageSession(MS): else: return False - return await inc.wait(waiter) + wait = await inc.wait(waiter) + if msgchain is not None: + await send.delete() + return wait def asDisplay(self): display = self.session.message.asDisplay() @@ -172,6 +180,7 @@ class FetchTarget(FT): try: send = await fetch.sendMessage(message, quote=False) send_list.append(send) + await asyncio.sleep(random.randint(1, 10)) except Exception: traceback.print_exc() return send_list diff --git a/core/dirty_check.py b/core/dirty_check.py index 7615eac6..d8827f58 100644 --- a/core/dirty_check.py +++ b/core/dirty_check.py @@ -5,7 +5,6 @@ import hmac import json import time -import aiohttp from aiohttp_retry import RetryClient, ExponentialRetry from config import Config diff --git a/core/elements/message/__init__.py b/core/elements/message/__init__.py index d6fb66a5..6d7da5f6 100644 --- a/core/elements/message/__init__.py +++ b/core/elements/message/__init__.py @@ -41,15 +41,16 @@ class MessageSession: """ 用于向消息发送者回复消息。 :param msgchain: 消息链,若传入str则自动创建一条带有Plain元素的消息链 - :param quote: 是否引用传入dict中的消息(仅对Group消息有效)(默认为True) + :param quote: 是否引用传入dict中的消息(默认为True) :return: 被发送的消息链 """ ... - async def waitConfirm(self): + async def waitConfirm(self, msgchain=None, quote=True): """ 一次性模板,用于等待触发对象确认。 - :param display_msg: 函数传入的dict + :param msgchain: 需要发送的确认消息,可不填 + :param quote: 是否引用传入dict中的消息(默认为True) :return: 若对象发送confirm_command中的其一文本时返回True,反之则返回False """ ... diff --git a/core/elements/module/__init__.py b/core/elements/module/__init__.py index 42999d70..6fb0ccfd 100644 --- a/core/elements/module/__init__.py +++ b/core/elements/module/__init__.py @@ -1,18 +1,20 @@ -from typing import Callable +from typing import Callable, Union + from apscheduler.triggers.combining import AndTrigger, OrTrigger -from apscheduler.triggers.interval import IntervalTrigger from apscheduler.triggers.cron import CronTrigger from apscheduler.triggers.date import DateTrigger +from apscheduler.triggers.interval import IntervalTrigger class Command: def __init__(self, function: Callable, bind_prefix: str, - alias: [str, list, tuple] = None, - help_doc: [str, list, tuple] = None, + alias: Union[str, list, tuple, dict] = None, + help_doc: Union[str, list, tuple] = None, + allowed_none: bool = True, desc: str = None, - need_self_process: bool = False, + recommend_modules: Union[str, list, tuple] = None, need_admin: bool = False, is_base_function: bool = False, need_superuser: bool = False, @@ -22,8 +24,9 @@ class Command: self.bind_prefix = bind_prefix self.alias = alias self.help_doc = help_doc + self.allowed_none = allowed_none self.desc = desc - self.need_self_process = need_self_process + self.recommend_modules = recommend_modules self.need_admin = need_admin self.is_base_function = is_base_function self.need_superuser = need_superuser @@ -35,14 +38,17 @@ class Option: def __init__(self, bind_prefix: str, desc: str = None, - help_doc: [str, list, tuple] = None, - alias: [str, list, tuple] = None, + help_doc: Union[str, list, tuple] = None, + alias: Union[str, list, tuple, dict] = None, + recommend_modules: Union[str, list, tuple] = None, need_superuser: bool = False, need_admin: bool = False): self.bind_prefix = bind_prefix self.help_doc = help_doc self.desc = desc self.alias = alias + self.allowed_none = True + self.recommend_modules = recommend_modules self.need_superuser = need_superuser self.is_base_function = False self.is_regex_function = False @@ -55,8 +61,9 @@ class Schedule: trigger: [AndTrigger, OrTrigger, DateTrigger, CronTrigger, IntervalTrigger], bind_prefix: str, desc: str = None, - help_doc: [str, list, tuple] = None, - alias: [str, list, tuple] = None, + help_doc: Union[str, list, tuple] = None, + alias: Union[str, list, tuple, dict] = None, + recommend_modules: Union[str, list, tuple] = None, need_superuser: bool = False, need_admin: bool = False ): @@ -65,7 +72,9 @@ class Schedule: self.bind_prefix = bind_prefix self.desc = desc self.help_doc = help_doc + self.allowed_none = True self.alias = alias + self.recommend_modules = recommend_modules self.need_superuser = need_superuser self.is_base_function = False self.is_regex_function = False diff --git a/core/elements/temp/__init__.py b/core/elements/temp/__init__.py index 630269b9..9f62f24a 100644 --- a/core/elements/temp/__init__.py +++ b/core/elements/temp/__init__.py @@ -21,4 +21,5 @@ class SenderInfoCache: def get_cache(key): return SenderInfoCache._cache.get(key, False) + __all__ = ["EnabledModulesCache", "SenderInfoCache"] diff --git a/core/loader/__init__.py b/core/loader/__init__.py index 99213708..8512074b 100644 --- a/core/loader/__init__.py +++ b/core/loader/__init__.py @@ -45,7 +45,27 @@ class ModulesManager: @staticmethod def return_modules_list_as_dict(): - return {x.bind_prefix: x for x in ModulesManager._modules_list} + d = {} + modules = [] + recommend_modules = [] + for alias in ModulesManager.return_modules_alias_map(): + modules.append(alias) + for x in ModulesManager._modules_list: + prefix = x.bind_prefix + if prefix in d: + raise ValueError(f'Duplicate bind prefix "{prefix}"') + d.update({prefix: x}) + modules.append(prefix) + recommend = x.recommend_modules + if isinstance(recommend, str): + recommend_modules.append(recommend) + if isinstance(recommend, (list, tuple)): + for y in recommend: + recommend_modules.append(y) + for rm in recommend_modules: + if rm not in modules: + raise ValueError(f'Invalid recommend module "{rm}"') + return d @staticmethod def return_modules_alias_map(): diff --git a/core/loader/decorator.py b/core/loader/decorator.py index a9de75bd..4eec485f 100644 --- a/core/loader/decorator.py +++ b/core/loader/decorator.py @@ -1,18 +1,21 @@ +from apscheduler.triggers.combining import AndTrigger, OrTrigger +from apscheduler.triggers.cron import CronTrigger +from apscheduler.triggers.date import DateTrigger +from apscheduler.triggers.interval import IntervalTrigger + from core.elements import Command, Option, Schedule from core.loader import ModulesManager -from apscheduler.triggers.combining import AndTrigger, OrTrigger -from apscheduler.triggers.interval import IntervalTrigger -from apscheduler.triggers.cron import CronTrigger -from apscheduler.triggers.date import DateTrigger +from typing import Union def command( bind_prefix: str, - alias: [str, list, tuple] = None, - help_doc: [str, list, tuple] = None, + alias: Union[str, list, tuple, dict] = None, + help_doc: Union[str, list, tuple] = None, + allowed_none: bool = True, desc: str = None, - need_self_process: bool = False, + recommend_modules: Union[str, list, tuple] = None, need_admin: bool = False, is_base_function: bool = False, need_superuser: bool = False, @@ -24,11 +27,12 @@ def command( alias=alias, bind_prefix=bind_prefix, help_doc=help_doc, + allowed_none=allowed_none, desc=desc, + recommend_modules=recommend_modules, is_base_function=is_base_function, is_regex_function=is_regex_function, need_admin=need_admin, - need_self_process=need_self_process, need_superuser=need_superuser, autorun=autorun) ModulesManager.add_module(module) @@ -40,8 +44,9 @@ def command( def option( bind_prefix: str, desc: str = None, - help_doc: [str, list, tuple] = None, - alias: [str, list, tuple] = None, + help_doc: Union[str, list, tuple] = None, + alias: Union[str, list, tuple, dict] = None, + recommend_modules: Union[str, list, tuple] = None, need_superuser: bool = False, need_admin: bool = False ): @@ -50,6 +55,7 @@ def option( desc=desc, help_doc=help_doc, alias=alias, + recommend_modules=recommend_modules, need_superuser=need_superuser, need_admin=need_admin) ModulesManager.add_module(module) @@ -60,10 +66,11 @@ def option( def schedule( bind_prefix: str, - trigger: [AndTrigger, OrTrigger, DateTrigger, CronTrigger, IntervalTrigger], + trigger: Union[AndTrigger, OrTrigger, DateTrigger, CronTrigger, IntervalTrigger], desc: str = None, - help_doc: [str, list, tuple] = None, - alias: [str, list, tuple] = None, + help_doc: Union[str, list, tuple] = None, + alias: Union[str, list, tuple, dict] = None, + recommend_modules: Union[str, list, tuple] = None, need_superuser: bool = False, need_admin: bool = False ): @@ -74,6 +81,7 @@ def schedule( desc=desc, help_doc=help_doc, alias=alias, + recommend_modules=recommend_modules, need_superuser=need_superuser, need_admin=need_admin) ModulesManager.add_module(module) diff --git a/core/parser/command.py b/core/parser/command.py index 761a116c..1a2901c9 100644 --- a/core/parser/command.py +++ b/core/parser/command.py @@ -1,7 +1,9 @@ import re import shlex +from typing import Union from core.docopt import docopt, DocoptExit +from core.elements import Command, Option, Schedule class InvalidHelpDocTypeError(BaseException): @@ -15,11 +17,18 @@ class InvalidCommandFormatError(BaseException): class CommandParser: - def __init__(self, args: [str, list, tuple]): + def __init__(self, args: Union[str, list, tuple, Command, Option, Schedule]): """ Format: https://github.com/jazzband/docopt-ng#usage-pattern-format * {} - Detail help information """ + self.desc = False + if isinstance(args, (Command, Option, Schedule)): + if args.help_doc is not None: + args = args.help_doc + elif args.desc is not None: + args = args.desc + self.desc = True self.args_raw = args if isinstance(args, str): args = [args] @@ -36,7 +45,8 @@ class CommandParser: def return_formatted_help_doc(self) -> str: args_raw = self.args_raw - + if self.desc: + return args_raw if isinstance(args_raw, str): args_raw = [args_raw] if isinstance(args_raw, (list, tuple)): @@ -52,6 +62,8 @@ class CommandParser: return args def parse(self, command): + if self.desc: + return None command = re.sub('“', '"', re.sub('”', '"', command)) try: split_command = shlex.split(command) diff --git a/core/parser/message.py b/core/parser/message.py index a0ca63af..39f6bdc2 100644 --- a/core/parser/message.py +++ b/core/parser/message.py @@ -63,6 +63,8 @@ async def parser(msg: MessageSession): command_parser = CommandParser(help_doc) try: msg.parsed_msg = command_parser.parse(command) + if msg.parsed_msg is None and not Modules[command_first_word].allowed_none: + return await msg.sendMessage(command_parser.return_formatted_help_doc()) except InvalidCommandFormatError: return await msg.sendMessage('语法错误。\n' + command_parser.return_formatted_help_doc()) except InvalidHelpDocTypeError: diff --git a/core/unit_test/template.py b/core/unit_test/template.py index b9a1d65d..aaf56f00 100644 --- a/core/unit_test/template.py +++ b/core/unit_test/template.py @@ -1,6 +1,7 @@ -from PIL import Image from typing import List +from PIL import Image + from core.elements import MessageSession, Plain, Image as BImage, Session, MsgInfo, FetchTarget as FT from core.elements.others import confirm_command @@ -27,8 +28,12 @@ class Template(MessageSession): return MessageSession(target=self.target, session=Session(message=str(msg_list), target='TEST|Console', sender='TEST|Console')) - async def waitConfirm(self): + async def waitConfirm(self, msgchain=None, quote=True): + if msgchain is not None: + await self.sendMessage(msgchain) + print("(发送“是”或符合确认条件的词语来确认)") c = input('Confirm: ') + print(c) if c in confirm_command: return True return False diff --git a/core/utils/bot.py b/core/utils/bot.py index 360626f3..e11158f0 100644 --- a/core/utils/bot.py +++ b/core/utils/bot.py @@ -1,4 +1,3 @@ -import ujson as json import os import traceback import uuid @@ -6,6 +5,7 @@ from os.path import abspath import aiohttp import filetype as ft +import ujson as json from aiohttp_retry import ExponentialRetry, RetryClient from core.elements import FetchTarget diff --git a/database/__init__.py b/database/__init__.py index e203f9aa..8a1a98c8 100644 --- a/database/__init__.py +++ b/database/__init__.py @@ -4,6 +4,10 @@ from core.elements.message import MessageSession from core.elements.temp import EnabledModulesCache, SenderInfoCache from database.orm import DBSession from database.tables import EnabledModules, SenderInfo, TargetAdmin, CommandTriggerTime +from config import Config + + +cache = Config('db_cache') def convert_list_to_str(lst: list) -> str: @@ -37,7 +41,7 @@ class BotDBUtil: else: self.targetId = msg self.need_insert = False - self.enable_modules_list = EnabledModulesCache.get_cache(self.targetId) + self.enable_modules_list = EnabledModulesCache.get_cache(self.targetId) if cache else False if not self.enable_modules_list: query = self.query_EnabledModules if query is None: @@ -46,7 +50,8 @@ class BotDBUtil: else: query_ = query.enabledModules self.enable_modules_list = convert_str_to_list(query_) - EnabledModulesCache.add_cache(self.targetId, self.enable_modules_list) + if cache: + EnabledModulesCache.add_cache(self.targetId, self.enable_modules_list) @property def query_EnabledModules(self): @@ -76,7 +81,8 @@ class BotDBUtil: self.query_EnabledModules.enabledModules = value session.commit() session.expire_all() - EnabledModulesCache.add_cache(self.targetId, self.enable_modules_list) + if cache: + EnabledModulesCache.add_cache(self.targetId, self.enable_modules_list) return True except Exception: session.rollback() @@ -95,7 +101,8 @@ class BotDBUtil: self.query_EnabledModules.enabledModules = convert_list_to_str(self.enable_modules_list) session.commit() session.expire_all() - EnabledModulesCache.add_cache(self.targetId, self.enable_modules_list) + if cache: + EnabledModulesCache.add_cache(self.targetId, self.enable_modules_list) return True except Exception: session.rollback() @@ -114,7 +121,7 @@ class BotDBUtil: class SenderInfo: def __init__(self, senderId): self.senderId = senderId - query_cache = SenderInfoCache.get_cache(self.senderId) + query_cache = SenderInfoCache.get_cache(self.senderId) if cache else False if query_cache: self.query = Dict2Object(query_cache) else: @@ -124,7 +131,8 @@ class BotDBUtil: session.add_all([SenderInfo(id=senderId)]) session.commit() self.query = session.query(SenderInfo).filter_by(id=senderId).first() - SenderInfoCache.add_cache(self.senderId, self.query.__dict__) + if cache: + SenderInfoCache.add_cache(self.senderId, self.query.__dict__) except Exception: session.rollback() raise @@ -139,7 +147,8 @@ class BotDBUtil: setattr(query, column, value) session.commit() session.expire_all() - SenderInfoCache.add_cache(self.senderId, query.__dict__) + if cache: + SenderInfoCache.add_cache(self.senderId, query.__dict__) return True except Exception: session.rollback() diff --git a/database/logging_message.py b/database/logging_message.py index bac0ae66..a0566f50 100644 --- a/database/logging_message.py +++ b/database/logging_message.py @@ -1,6 +1,6 @@ from sqlalchemy import create_engine, Column, String, Text, Integer -from sqlalchemy.orm import sessionmaker from sqlalchemy.ext.declarative import declarative_base +from sqlalchemy.orm import sessionmaker Base = declarative_base() diff --git a/modules/b30/getb30.py b/modules/b30/getb30.py index 010baf1c..4da0e64d 100644 --- a/modules/b30/getb30.py +++ b/modules/b30/getb30.py @@ -1,8 +1,8 @@ -import ujson as json import os import uuid import aiohttp +import ujson as json from config import Config from .drawb30img import drawb30 diff --git a/modules/bugtracker/__init__.py b/modules/bugtracker/__init__.py index d63631e2..b4d566dd 100644 --- a/modules/bugtracker/__init__.py +++ b/modules/bugtracker/__init__.py @@ -5,7 +5,8 @@ from core.loader.decorator import command from .bugtracker import bugtracker_get -@command('bug', alias='b', help_doc='~bug {查询Mojira上的漏洞编号内容}') +@command('bug', alias='b', help_doc='~bug {查询Mojira上的漏洞编号内容}', + allowed_none=False) async def bugtracker(msg: MessageSession): mojira_id = msg.parsed_msg[''] if mojira_id: diff --git a/modules/core/__init__.py b/modules/core/__init__.py index 9157fa7c..6633411e 100644 --- a/modules/core/__init__.py +++ b/modules/core/__init__.py @@ -1,10 +1,10 @@ import asyncio -import ujson as json import os import sys import time import psutil +import ujson as json from core.elements import MessageSession, Command from core.loader import ModulesManager @@ -19,7 +19,7 @@ from database import BotDBUtil need_admin=True, help_doc=('~module enable (...|all) {开启一个/多个或所有模块}', '~module disable (...|all) {关闭一个/多个或所有模块}'), - alias={'enable': 'module enable', 'disable': 'module disable'} + alias={'enable': 'module enable', 'disable': 'module disable'}, allowed_none=False ) async def config_modules(msg: MessageSession): alias = ModulesManager.return_modules_alias_map() @@ -34,12 +34,13 @@ async def config_modules(msg: MessageSession): wait_config_list.append(module) query = BotDBUtil.Module(msg) msglist = [] + recommend_modules_list = [] if msg.parsed_msg['enable']: + enable_list = [] if wait_config_list == ['all']: for function in modules: if not modules[function].need_superuser and not modules[function].is_base_function: - if query.enable(function): - msglist.append(f'成功:打开模块“{function}”') + enable_list.append(function) else: for module in wait_config_list: if module not in modules: @@ -50,22 +51,47 @@ async def config_modules(msg: MessageSession): elif modules[module].is_base_function: msglist.append(f'失败:“{module}”为基础模块。') else: - if query.enable(wait_config_list): - msglist.append(f'成功:打开模块“{module}”') + enable_list.append(module) + recommend = modules[module].recommend_modules + if isinstance(recommend, str): + recommend_modules_list.append(recommend) + if isinstance(recommend, (list, tuple)): + for r in recommend: + recommend_modules_list.append(r) + if query.enable(enable_list): + for x in enable_list: + msglist.append(f'成功:打开模块“{x}”') elif msg.parsed_msg['disable']: + disable_list = [] if wait_config_list == ['all']: for function in modules: - if query.disable(function): - msglist.append(f'成功:关闭模块“{function}”') + if not modules[function].need_superuser and not modules[function].is_base_function: + disable_list.append(function) else: for module in wait_config_list: if module not in modules: msglist.append(f'失败:“{module}”模块不存在') else: - if query.disable(wait_config_list): - msglist.append(f'成功:关闭模块“{module}”') + disable_list.append(module) + if query.disable(disable_list): + for x in disable_list: + msglist.append(f'成功:关闭模块“{x}”') if msglist is not None: await msg.sendMessage('\n'.join(msglist)) + if recommend_modules_list: + fmt_help_doc_list = [] + for m in recommend_modules_list: + fmt_help_doc_list.append(f'模块{m}的帮助信息:\n' + CommandParser(modules[m]).return_formatted_help_doc()) + confirm = await msg.waitConfirm('建议同时打开以下模块:\n' + + '\n'.join(recommend_modules_list) + '\n' + + '\n'.join(fmt_help_doc_list) + + '\n是否一并打开?') + if confirm: + if query.enable(recommend_modules_list): + msglist = [] + for x in recommend_modules_list: + msglist.append(f'成功:打开模块“{x}”') + await msg.sendMessage('\n'.join(msglist)) @command('help', @@ -82,7 +108,7 @@ async def bot_help(msg: MessageSession): if help_name in alias: help_name = alias[help_name] if help_name in module_list: - help_ = CommandParser(module_list[help_name].help_doc).return_formatted_help_doc() + help_ = CommandParser(module_list[help_name]).return_formatted_help_doc() if help_ is not None: msgs.append(help_) if msgs: @@ -185,7 +211,7 @@ async def ping(msg: MessageSession): @command('admin', is_base_function=True, need_admin=True, - help_doc=('~admin add {设置成员为机器人管理员}', '~admin del {取消成员的机器人管理员}') + help_doc=('~admin add {设置成员为机器人管理员}', '~admin del {取消成员的机器人管理员}'), allowed_none=False ) async def config_gu(msg: MessageSession): if msg.parsed_msg['add']: diff --git a/modules/cytoid/__init__.py b/modules/cytoid/__init__.py index 17d67b1d..475541d8 100644 --- a/modules/cytoid/__init__.py +++ b/modules/cytoid/__init__.py @@ -6,7 +6,8 @@ from .rating import get_rating @command('cytoid', help_doc=('~cytoid (b30|r30) {查询一个用户的b30/r30记录}', - '~cytoid profile {查询一个用户的基本信息}')) + '~cytoid profile {查询一个用户的基本信息}'), + allowed_none=False) async def cytoid(msg: MessageSession): if msg.parsed_msg['profile']: await cytoid_profile(msg) diff --git a/modules/cytoid/rating.py b/modules/cytoid/rating.py index 62f6d0f0..04ebbbf8 100644 --- a/modules/cytoid/rating.py +++ b/modules/cytoid/rating.py @@ -1,4 +1,3 @@ -import ujson as json import os import shutil import time @@ -8,6 +7,7 @@ from datetime import datetime, timedelta from os.path import abspath import aiohttp +import ujson as json from PIL import Image, ImageEnhance, ImageFont, ImageDraw, ImageFilter, ImageOps from gql import Client, gql from gql.transport.aiohttp import AIOHTTPTransport diff --git a/modules/github/__init__.py b/modules/github/__init__.py index 3d3f1e29..d40f498d 100644 --- a/modules/github/__init__.py +++ b/modules/github/__init__.py @@ -7,7 +7,8 @@ from modules.github import repo, user, search '~github repo {获取 GitHub 仓库信息}', '~github user {获取 GitHub 用户或组织信息}', '~github org {~github user 的别名}', - '~github search {搜索 GitHub 上的仓库}')) + '~github search {搜索 GitHub 上的仓库}'), + allowed_none=False) async def github(msg: MessageSession): if msg.parsed_msg['repo']: return await repo.repo(msg) diff --git a/modules/mcv/__init__.py b/modules/mcv/__init__.py index f5205d1d..115988d9 100644 --- a/modules/mcv/__init__.py +++ b/modules/mcv/__init__.py @@ -6,7 +6,8 @@ from .mcv import mcv, mcbv, mcdv @command( bind_prefix='mcv', help_doc='~mcv {查询当前Minecraft Java版启动器内最新版本。}', - alias='m') + alias='m', + recommend_modules='mcbv') async def mcv_loader(msg: MessageSession): await msg.sendMessage(await mcv()) diff --git a/modules/mcv/mcv.py b/modules/mcv/mcv.py index 4b22ad78..591380f9 100644 --- a/modules/mcv/mcv.py +++ b/modules/mcv/mcv.py @@ -1,8 +1,9 @@ -import re import json +import re from core.utils import get_url + async def mcv(): try: data = json.loads(await get_url('http://launchermeta.mojang.com/mc/game/version_manifest.json')) diff --git a/modules/mcv_rss/__init__.py b/modules/mcv_rss/__init__.py index 52b1f5d6..c5d29434 100644 --- a/modules/mcv_rss/__init__.py +++ b/modules/mcv_rss/__init__.py @@ -1,14 +1,12 @@ -import asyncio -import ujson as json import os import traceback -import random + +import ujson as json from core.elements import FetchTarget, IntervalTrigger from core.loader.decorator import schedule from core.logger import Logger from core.utils import get_url, PrivateAssets -from database import BotDBUtil def getfileversions(path): diff --git a/modules/minecraft_news/__init__.py b/modules/minecraft_news/__init__.py index da0c1e6d..c4956a34 100644 --- a/modules/minecraft_news/__init__.py +++ b/modules/minecraft_news/__init__.py @@ -1,16 +1,14 @@ -import asyncio import ujson as json -import traceback import aiohttp -import random +import ujson as json from config import Config -from database import BotDBUtil -from core.utils import get_url, download_to_cache -from core.scheduler import Scheduler +from core.elements import FetchTarget, Image from core.loader.decorator import command -from core.elements import FetchTarget, Plain, Image from core.logger import Logger +from core.scheduler import Scheduler +from core.utils import get_url, download_to_cache +from database import BotDBUtil @command('minecraft_news', autorun=True) diff --git a/modules/nintendo_err/__init__.py b/modules/nintendo_err/__init__.py index 6e6dd6eb..43bb09d9 100644 --- a/modules/nintendo_err/__init__.py +++ b/modules/nintendo_err/__init__.py @@ -295,7 +295,7 @@ invalid for the Wii U.') await ctx.send(kwargs, 'This isn\'t a hexadecimal value!') -@command('err', help_doc='~err {解析任天堂系列主机的报错码并给出原因。}') +@command('err', help_doc='~err {解析任天堂系列主机的报错码并给出原因。}', allowed_none=False) async def result(msg: MessageSession): """ Displays information on game console result codes, with a fancy embed. diff --git a/modules/ptt/__init__.py b/modules/ptt/__init__.py index 4a6989f0..8dcd26a8 100644 --- a/modules/ptt/__init__.py +++ b/modules/ptt/__init__.py @@ -26,7 +26,8 @@ def text_border(draw, x, y, text, shadowcolor, fillcolor, font): draw.text((x, y), text, font=font, fill=fillcolor) -@command('ptt', help_doc='~ptt {生成一张Arcaea Potential图片}') +@command('ptt', help_doc='~ptt {生成一张Arcaea Potential图片}', + allowed_none=False) async def pttimg(msg: MessageSession): ptt = msg.parsed_msg[''] # ptt diff --git a/modules/secret/__init__.py b/modules/secret/__init__.py index 5cb46324..64c89c14 100644 --- a/modules/secret/__init__.py +++ b/modules/secret/__init__.py @@ -1,18 +1,13 @@ -import asyncio import ujson as json -import random -import traceback +from core.dirty_check import check +from core.elements import FetchTarget from core.loader.decorator import command from core.logger import Logger from core.scheduler import Scheduler from core.utils import get_url -from core.elements import FetchTarget -from core.dirty_check import check - from modules.utils.UTC8 import UTC8 -from database import BotDBUtil @command('__check_newbie__', need_superuser=True, autorun=True) async def newbie(bot: FetchTarget): diff --git a/modules/server/__init__.py b/modules/server/__init__.py index 6b906933..49485810 100644 --- a/modules/server/__init__.py +++ b/modules/server/__init__.py @@ -8,7 +8,8 @@ from .server import server @command('server', alias='s', help_doc=('~server : {获取Minecraft Java/基岩版服务器motd。}', '~server : [-r] {获取Minecraft Java/基岩版服务器motd。(原始信息)}', - '~server : [-p] {获取Minecraft Java/基岩版服务器motd。(包括玩家信息)}')) + '~server : [-p] {获取Minecraft Java/基岩版服务器motd。(包括玩家信息)}'), + allowed_none=False) async def main(msg: MessageSession): raw = False showplayer = False diff --git a/modules/server/server.py b/modules/server/server.py index b82653cf..40f02b3e 100644 --- a/modules/server/server.py +++ b/modules/server/server.py @@ -1,8 +1,8 @@ -import ujson as json import re import traceback import aiohttp +import ujson as json async def server(address, raw=False, showplayer=False, mode='j'): diff --git a/modules/user/__init__.py b/modules/user/__init__.py index f111472b..9e187451 100644 --- a/modules/user/__init__.py +++ b/modules/user/__init__.py @@ -8,11 +8,9 @@ from modules.wiki.dbutils import WikiTargetInfo from .userlib import GetUser -@command('user', ['u'], ('~user [-r | -p] {获取一个MediaWiki用户的信息。(-r - 获取详细信息。-p - 生成一张图片。)}')) +@command('user', alias=['u'], help_doc='~user [-r|-p] {获取一个MediaWiki用户的信息。(-r - 获取详细信息。-p - 生成一张图片。)}', + allowed_none=False) async def user(msg: MessageSession): - if msg.parsed_msg is None: - await msg.sendMessage(CommandParser(ModulesManager.return_modules_help()['user']).return_formatted_help_doc()) - return mode = None metaurl = None username = None diff --git a/modules/utils/ab.py b/modules/utils/ab.py index 2ea85922..6c219f33 100644 --- a/modules/utils/ab.py +++ b/modules/utils/ab.py @@ -1,6 +1,5 @@ -import ujson as json - import aiohttp +import ujson as json from core.dirty_check import check from modules.utils.UTC8 import UTC8 diff --git a/modules/utils/newbie.py b/modules/utils/newbie.py index 91151fab..1d2d0f12 100644 --- a/modules/utils/newbie.py +++ b/modules/utils/newbie.py @@ -1,7 +1,7 @@ -import ujson as json import re import aiohttp +import ujson as json from core.dirty_check import check from modules.wiki.wikilib import wikilib diff --git a/modules/utils/rc.py b/modules/utils/rc.py index a535c71b..c6c8a7be 100644 --- a/modules/utils/rc.py +++ b/modules/utils/rc.py @@ -1,6 +1,5 @@ -import ujson as json - import aiohttp +import ujson as json from core.dirty_check import check from modules.utils.UTC8 import UTC8 diff --git a/modules/weekly/__init__.py b/modules/weekly/__init__.py index a8a309b1..97e07657 100644 --- a/modules/weekly/__init__.py +++ b/modules/weekly/__init__.py @@ -1,6 +1,7 @@ -import ujson as json import re +import ujson as json + from core.elements import Plain, Image, MessageSession from core.loader.decorator import command from core.utils import get_url diff --git a/modules/weekly_rss/__init__.py b/modules/weekly_rss/__init__.py index a70c2ccb..5fa182d0 100644 --- a/modules/weekly_rss/__init__.py +++ b/modules/weekly_rss/__init__.py @@ -1,14 +1,6 @@ -import asyncio -import random -import traceback - -from apscheduler.triggers.cron import CronTrigger - -from core.loader.decorator import schedule from core.elements import CronTrigger, FetchTarget +from core.loader.decorator import schedule from core.logger import Logger -from core.scheduler import Scheduler -from database import BotDBUtil from modules.weekly import get_weekly diff --git a/modules/wiki/__init__.py b/modules/wiki/__init__.py index 34bdd6ce..a944131a 100644 --- a/modules/wiki/__init__.py +++ b/modules/wiki/__init__.py @@ -1,10 +1,11 @@ -import ujson as json import re +import ujson as json + from core.elements import MessageSession, Plain, Image, Voice, Option from core.loader import ModulesManager -from core.parser.command import CommandParser from core.loader.decorator import command +from core.parser.command import CommandParser from core.utils import download_to_cache from database import BotDBUtil from modules.wiki.dbutils import WikiTargetInfo @@ -21,11 +22,10 @@ from .getinfobox import get_infobox_pic '~wiki headers (del|delete|remove|rm) {删除一个headers}', '~wiki headers reset {重置headers}', '~wiki headers show {展示当前设置的headers}'), - alias={'wiki_start_site': 'wiki set'}) + alias={'wiki_start_site': 'wiki set'}, + recommend_modules='wiki_inline', + allowed_none=False) async def wiki_wrapper(msg: MessageSession): - if msg.parsed_msg is None: - await msg.sendMessage(CommandParser(ModulesManager.return_modules_help()['wiki']).return_formatted_help_doc()) - return if msg.parsed_msg['set']: await set_start_wiki(msg) elif msg.parsed_msg['iw']: diff --git a/modules/wiki/dbutils.py b/modules/wiki/dbutils.py index ae3cab07..44a8b93a 100644 --- a/modules/wiki/dbutils.py +++ b/modules/wiki/dbutils.py @@ -1,9 +1,8 @@ import ujson as json from core.elements import MessageSession -from .orm import WikiTargetSetInfo, WikiInfo from database.orm import DBSession - +from .orm import WikiTargetSetInfo, WikiInfo session = DBSession().session diff --git a/modules/wiki/getinfobox.py b/modules/wiki/getinfobox.py index 12b8eadc..15d43532 100644 --- a/modules/wiki/getinfobox.py +++ b/modules/wiki/getinfobox.py @@ -1,4 +1,3 @@ -import ujson as json import os import re import traceback @@ -6,6 +5,7 @@ import uuid from urllib.parse import urljoin import aiohttp +import ujson as json from bs4 import BeautifulSoup from config import Config diff --git a/modules/wiki/wikilib.py b/modules/wiki/wikilib.py index d9f3b530..3e3a965b 100644 --- a/modules/wiki/wikilib.py +++ b/modules/wiki/wikilib.py @@ -1,16 +1,15 @@ import asyncio import datetime -import ujson as json import re import traceback import urllib.parse import aiohttp import html2text +import ujson as json from core import dirty_check from core.logger import Logger -from core.utils import get_url from .dbutils import WikiSiteInfo