commit
3b19154426
@ -0,0 +1,12 @@
|
||||
ENVIRONMENT=dev
|
||||
|
||||
SUPERUSERS=[""]
|
||||
COMMAND_START=[""]
|
||||
COMMAND_SEP=["."]
|
||||
SESSION_EXPIRE_TIMEOUT=90
|
||||
API_TIMEOUT=300
|
||||
|
||||
MYSQL_DB = ""
|
||||
MYSQL_USER = ""
|
||||
MYSQL_HOST = ""
|
||||
MYSQL_PASSWORD = ""
|
@ -0,0 +1,146 @@
|
||||
|
||||
# Created by https://www.toptal.com/developers/gitignore/api/python
|
||||
# Edit at https://www.toptal.com/developers/gitignore?templates=python
|
||||
|
||||
### Python ###
|
||||
# Byte-compiled / optimized / DLL files
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
|
||||
# Data
|
||||
data/class_system/*
|
||||
data/chatword/*
|
||||
tests
|
||||
|
||||
# C extensions
|
||||
*.so
|
||||
|
||||
# Distribution / packaging
|
||||
.Python
|
||||
build/
|
||||
develop-eggs/
|
||||
dist/
|
||||
downloads/
|
||||
eggs/
|
||||
.eggs/
|
||||
lib/
|
||||
lib64/
|
||||
parts/
|
||||
sdist/
|
||||
var/
|
||||
wheels/
|
||||
pip-wheel-metadata/
|
||||
share/python-wheels/
|
||||
*.egg-info/
|
||||
.installed.cfg
|
||||
*.egg
|
||||
MANIFEST
|
||||
|
||||
# PyInstaller
|
||||
# Usually these files are written by a python script from a template
|
||||
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||
*.manifest
|
||||
*.spec
|
||||
|
||||
# Installer logs
|
||||
pip-log.txt
|
||||
pip-delete-this-directory.txt
|
||||
|
||||
# Unit test / coverage reports
|
||||
htmlcov/
|
||||
.tox/
|
||||
.nox/
|
||||
.coverage
|
||||
.coverage.*
|
||||
.cache
|
||||
nosetests.xml
|
||||
coverage.xml
|
||||
*.cover
|
||||
*.py,cover
|
||||
.hypothesis/
|
||||
.pytest_cache/
|
||||
pytestdebug.log
|
||||
|
||||
# Translations
|
||||
*.mo
|
||||
*.pot
|
||||
|
||||
# Django stuff:
|
||||
*.log
|
||||
local_settings.py
|
||||
db.sqlite3
|
||||
db.sqlite3-journal
|
||||
|
||||
# Flask stuff:
|
||||
instance/
|
||||
.webassets-cache
|
||||
|
||||
# Scrapy stuff:
|
||||
.scrapy
|
||||
|
||||
# Sphinx documentation
|
||||
docs/_build/
|
||||
doc/_build/
|
||||
|
||||
# PyBuilder
|
||||
target/
|
||||
|
||||
# Jupyter Notebook
|
||||
.ipynb_checkpoints
|
||||
|
||||
# IPython
|
||||
profile_default/
|
||||
ipython_config.py
|
||||
|
||||
# pyenv
|
||||
.python-version
|
||||
|
||||
# pipenv
|
||||
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
||||
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
||||
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
||||
# install all needed dependencies.
|
||||
#Pipfile.lock
|
||||
|
||||
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
|
||||
__pypackages__/
|
||||
|
||||
# Celery stuff
|
||||
celerybeat-schedule
|
||||
celerybeat.pid
|
||||
|
||||
# SageMath parsed files
|
||||
*.sage.py
|
||||
|
||||
# Environments
|
||||
.env.dev
|
||||
.venv
|
||||
env/
|
||||
venv/
|
||||
ENV/
|
||||
env.bak/
|
||||
venv.bak/
|
||||
|
||||
# Spyder project settings
|
||||
.spyderproject
|
||||
.spyproject
|
||||
|
||||
# Rope project settings
|
||||
.ropeproject
|
||||
|
||||
# mkdocs documentation
|
||||
/site
|
||||
|
||||
# mypy
|
||||
.mypy_cache/
|
||||
.dmypy.json
|
||||
dmypy.json
|
||||
|
||||
# Pyre type checker
|
||||
.pyre/
|
||||
|
||||
# pytype static type analyzer
|
||||
.pytype/
|
||||
|
||||
# End of https://www.toptal.com/developers/gitignore/api/python
|
@ -0,0 +1,9 @@
|
||||
FROM tiangolo/uvicorn-gunicorn-fastapi:python3.8
|
||||
|
||||
RUN python3 -m pip config set global.index-url https://mirrors.aliyun.com/pypi/simple
|
||||
|
||||
RUN python3 -m pip install poetry && poetry config virtualenvs.create false
|
||||
|
||||
COPY ./pyproject.toml ./poetry.lock* /app/
|
||||
|
||||
RUN poetry install --no-root --no-dev
|
@ -0,0 +1,37 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
import nonebot
|
||||
from os import getcwd
|
||||
from nonebot.adapters.cqhttp import Bot
|
||||
|
||||
|
||||
# Custom your logger
|
||||
#
|
||||
# from nonebot.log import logger, default_format
|
||||
# logger.add("error.log",
|
||||
# rotation="00:00",
|
||||
# diagnose=False,
|
||||
# level="ERROR",
|
||||
# format=default_format)
|
||||
|
||||
# You can pass some keyword args config to init function
|
||||
nonebot.init()
|
||||
app = nonebot.get_asgi()
|
||||
|
||||
driver = nonebot.get_driver()
|
||||
driver.register_adapter("cqhttp", Bot)
|
||||
|
||||
|
||||
nonebot.load_plugins("src/utils")
|
||||
nonebot.load_from_toml("pyproject.toml")
|
||||
nonebot.load_plugins("src/class_management_system")
|
||||
|
||||
# Modify some config / config depends on loaded configs
|
||||
#
|
||||
# config = driver.config
|
||||
# do something...
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
nonebot.logger.warning("Always use `nb run` to start the bot instead of manually running!")
|
||||
nonebot.run(app="__mp_main__:app")
|
@ -0,0 +1,100 @@
|
||||
CREATE TABLE IF NOT EXISTS faculty_table (
|
||||
faculty VARCHAR(30) PRIMARY KEY COMMENT '院系',
|
||||
invitee VARCHAR(99) NOT NULL COMMENT '添加人'
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS teacher (
|
||||
name VARCHAR(20) NOT NULL COMMENT '教师姓名',
|
||||
qq BIGINT PRIMARY KEY COMMENT '教师qq号',
|
||||
invitee VARCHAR(99) NOT NULL COMMENT '添加人',
|
||||
telephone BIGINT NOT NULL UNIQUE COMMENT '教师电话'
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS expertise_table (
|
||||
faculty VARCHAR(30) NOT NULL COMMENT '院系',
|
||||
expertise VARCHAR(60) PRIMARY KEY COMMENT '专业',
|
||||
FOREIGN KEY (faculty) REFERENCES faculty_table(faculty)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS class_table (
|
||||
class_id BIGINT NOT NULL COMMENT '班级号',
|
||||
expertise VARCHAR(60) NOT NULL COMMENT '专业',
|
||||
class_group BIGINT NOT NULL UNIQUE COMMENT '班级QQ群',
|
||||
class_name VARCHAR(255) PRIMARY KEY COMMENT '班级群名',
|
||||
class_teacher BIGINT NOT NULL COMMENT '班主任QQ',
|
||||
FOREIGN KEY (class_teacher) REFERENCES teacher(qq),
|
||||
FOREIGN KEY (expertise) REFERENCES expertise_table(expertise)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS score_log (
|
||||
class_name VARCHAR(255) NOT NULL COMMENT '班级群名',
|
||||
score_type VARCHAR(50) COMMENT '分数类型',
|
||||
explain_reason TEXT COMMENT '解释原因原因',
|
||||
name VARCHAR(20) NOT NULL COMMENT '学生姓名',
|
||||
student_id BIGINT NOT NULL COMMENT '学生学号',
|
||||
score INT COMMENT '加减的分数',
|
||||
qq BIGINT NOT NULL COMMENT '学生qq',
|
||||
log_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '日志时间',
|
||||
prove VARCHAR(255) DEFAULT "" COMMENT "证明文件"
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS user_info (
|
||||
姓名 VARCHAR(20) NOT NULL COMMENT '学生姓名',
|
||||
班级 VARCHAR(255) NOT NULL COMMENT '班级名称',
|
||||
序号 INT NOT NULL COMMENT '个人在班级中的序号',
|
||||
学号 BIGINT NOT NULL COMMENT '学号',
|
||||
性别 VARCHAR(10) NOT NULL COMMENT '性别',
|
||||
联系方式 BIGINT NOT NULL COMMENT "学生联系方式",
|
||||
身份证号 VARCHAR(20) COMMENT '学生身份证',
|
||||
出生日期 TIMESTAMP COMMENT '出生日期',
|
||||
寝室 VARCHAR(10) COMMENT '寝室号',
|
||||
寝室长 VARCHAR(5) COMMENT '是否为寝室长',
|
||||
微信 VARCHAR(100) COMMENT '微信号',
|
||||
QQ BIGINT PRIMARY KEY COMMENT 'QQ',
|
||||
邮箱 VARCHAR(100) COMMENT '邮箱号',
|
||||
民族 VARCHAR(200) COMMENT '民族',
|
||||
籍贯 VARCHAR(200) COMMENT '籍贯',
|
||||
职位 VARCHAR(50) NOT NULL DEFAULT '学生' COMMENT '学生',
|
||||
团员 VARCHAR(10) COMMENT '是否为团员',
|
||||
入党积极分子 VARCHAR(10) COMMENT '是否为入党积极分子',
|
||||
团学 VARCHAR(100) COMMENT '团学干部',
|
||||
社团 VARCHAR(200) COMMENT '加入的社团',
|
||||
分数 INT NOT NULL DEFAULT 0 COMMENT '分数',
|
||||
FOREIGN KEY (班级) REFERENCES class_table(class_name)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS shop (
|
||||
teacher BIGINT NOT NULL COMMENT '教师QQ',
|
||||
shop_name VARCHAR(255) NOT NULL COMMENT '商品',
|
||||
shop_price INT NOT NULL DEFAULT 0 COMMENT '商品价格',
|
||||
FOREIGN KEY (teacher) REFERENCES teacher(qq)
|
||||
);
|
||||
|
||||
|
||||
CREATE TABLE IF NOT EXISTS receiving (
|
||||
title VARCHAR(255) NOT NULL COMMENT '收取标题',
|
||||
type VARCHAR(255) NOT NULL COMMENT '收取类型',
|
||||
class_name VARCHAR(255) NOT NULL COMMENT '班级名称',
|
||||
initiate BIGINT NOT NULL COMMENT '发起人',
|
||||
completed boolean NOT NULL DEFAULT FALSE COMMENT '是否已经完成',
|
||||
create_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间'
|
||||
);
|
||||
|
||||
|
||||
CREATE TABLE IF NOT EXISTS receiving_pictures (
|
||||
title VARCHAR(255) NOT NULL COMMENT '收取标题',
|
||||
user_id BIGINT NOT NULL COMMENT '提交人QQ',
|
||||
user_name VARCHAR(20) NOT NULL COMMENT '提交人姓名',
|
||||
class_name VARCHAR(255) NOT NULL COMMENT '班级名称',
|
||||
file_name VARCHAR(255) NOT NULL COMMENT '文件名称md5',
|
||||
create_time TIMESTAMP NOT NULL COMMENT '创建时间',
|
||||
push_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '上传时间'
|
||||
);
|
||||
|
||||
|
||||
CREATE TABLE IF NOT EXISTS cost (
|
||||
thing TEXT NOT NULL COMMENT '费用所花费在某件事情',
|
||||
money DOUBLE NOT NULL COMMENT '花费金额',
|
||||
|
||||
)
|
||||
|
Binary file not shown.
@ -0,0 +1,22 @@
|
||||
[tool.poetry]
|
||||
name = "classRobot"
|
||||
version = "0.1.0"
|
||||
description = "classRobot"
|
||||
authors = []
|
||||
readme = "README.md"
|
||||
|
||||
[tool.poetry.dependencies]
|
||||
python = "^3.7"
|
||||
nonebot2 = "^2.0.0.a1"
|
||||
nb-cli = "^0.1.0"
|
||||
|
||||
[tool.poetry.dev-dependencies]
|
||||
nonebot-test = "^0.1.0"
|
||||
|
||||
[nonebot.plugins]
|
||||
plugins = []
|
||||
plugin_dirs = ["src/plugins"]
|
||||
|
||||
[build-system]
|
||||
requires = ["poetry>=0.12"]
|
||||
build-backend = "poetry.masonry.api"
|
Binary file not shown.
@ -0,0 +1,13 @@
|
||||
from nonebot import on_request, require
|
||||
from nonebot.adapters.cqhttp import Bot, FriendRequestEvent
|
||||
|
||||
|
||||
friends = on_request()
|
||||
IS_USER = require("rule").IS_USER
|
||||
|
||||
|
||||
@friends.handle()
|
||||
async def friends_handle(bot: Bot, event: FriendRequestEvent, state: dict):
|
||||
if await IS_USER(bot, event, state):
|
||||
text = f"{state['user_info']['班级']}-{state['user_info']['姓名']}"
|
||||
await bot.set_friend_add_request(flag=event.flag, approve=True, remark=text)
|
@ -0,0 +1,3 @@
|
||||
# 生日插件
|
||||
|
||||
每天检查是否有用户生日,会在用户所在班级群内发送生日消息
|
@ -0,0 +1,21 @@
|
||||
from pprint import pprint
|
||||
|
||||
from nonebot import require, get_driver, get_bot
|
||||
from asyncio import sleep
|
||||
from nonebot.adapters.cqhttp import Bot, Message
|
||||
from .data_source import config, SelectBirthdayUser
|
||||
|
||||
driver = get_driver()
|
||||
scheduler = require("nonebot_plugin_apscheduler").scheduler
|
||||
|
||||
|
||||
async def birthday(bot: Bot):
|
||||
async with SelectBirthdayUser() as res:
|
||||
for txt, group_id in res.text():
|
||||
await sleep(5)
|
||||
await bot.send_group_msg(group_id=group_id, message=txt)
|
||||
|
||||
|
||||
@driver.on_bot_connect
|
||||
async def _(bot: Bot):
|
||||
scheduler.add_job(birthday, 'cron', hour=0, minute=0, id='birthday', args=[bot])
|
@ -0,0 +1,7 @@
|
||||
from pydantic import BaseSettings
|
||||
|
||||
|
||||
class Config(BaseSettings):
|
||||
user_table = "user_info"
|
||||
class_table = "class_table"
|
||||
notification_time = 0
|
@ -0,0 +1,101 @@
|
||||
from nonebot import on_command, require
|
||||
from nonebot.rule import T_State
|
||||
from nonebot.adapters.cqhttp import Bot, MessageEvent, Message, GroupMessageEvent, PrivateMessageEvent
|
||||
from .data_source import SetSignIn, SignIn, QuerySignIn
|
||||
|
||||
rule = require("rule")
|
||||
CLASS_CADRE = rule.CLASS_CADRE
|
||||
IS_USER = rule.IS_USER
|
||||
|
||||
query_sign_in = on_command("签到情况", aliases={"签到状态"})
|
||||
set_login_in = on_command("添加签到", aliases={"设置签到"})
|
||||
set_group_login = on_command("添加群签到")
|
||||
set_private_login = on_command("添加个人签到", aliases={"添加单独签到"})
|
||||
login_in = on_command("签到")
|
||||
|
||||
|
||||
# ---------- 发起签到 ----------
|
||||
async def set_login_in_handle(bot: Bot, event: MessageEvent, state: T_State):
|
||||
if await CLASS_CADRE(bot, event, state):
|
||||
state["param"] = state["class_cadre"]
|
||||
key = event.message
|
||||
if key:
|
||||
state["key"] = key
|
||||
else:
|
||||
await set_login_in.finish()
|
||||
|
||||
|
||||
def set_login_in_got(typeof: str):
|
||||
"""添加签到"""
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
state["key"] = Message(state["key"])
|
||||
async with SetSignIn(state["param"]["班级"],
|
||||
state["key"], typeof) as res:
|
||||
if not res.existence:
|
||||
await set_login_in.finish(res.text())
|
||||
else:
|
||||
await set_login_in.send(res.text())
|
||||
return _
|
||||
|
||||
|
||||
def set_login_in_reset(typeof: str):
|
||||
"""判断是否重置签到"""
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
if "是" in state["existence"]:
|
||||
async with SetSignIn(state["param"]["班级"], state["key"], typeof) as res:
|
||||
res.reset_sign_in()
|
||||
await set_login_in.finish(res.text())
|
||||
return _
|
||||
|
||||
|
||||
set_login_in.handle()(set_login_in_handle)
|
||||
set_private_login.handle()(set_login_in_handle)
|
||||
set_group_login.handle()(set_login_in_handle)
|
||||
|
||||
set_login_in.got("key", prompt="请输入签到关键字")(set_login_in_got("any"))
|
||||
set_private_login.got("key", prompt="请输入签到关键字")(set_login_in_got("private"))
|
||||
set_group_login.got("key", prompt="请输入签到关键字")(set_login_in_got("group"))
|
||||
|
||||
set_login_in.got("existence")(set_login_in_reset("any"))
|
||||
set_private_login.got("existence")(set_login_in_reset("private"))
|
||||
set_group_login.got("existence")(set_login_in_reset("group"))
|
||||
|
||||
|
||||
# ---------- 签到 ----------
|
||||
@login_in.handle()
|
||||
async def login_in_handle(bot: Bot, event: MessageEvent, state: T_State):
|
||||
if await IS_USER(bot, event, state):
|
||||
if event.message:
|
||||
state["key"] = event.message
|
||||
else:
|
||||
await login_in.finish()
|
||||
|
||||
|
||||
@login_in.got("key", prompt="请输入签到关键字")
|
||||
async def login_in_got(bot: Bot, event: MessageEvent, state: T_State):
|
||||
state["key"] = Message(state["key"])
|
||||
with SignIn(
|
||||
event.user_id,
|
||||
state["user_info"]["姓名"],
|
||||
state["user_info"]["班级"],
|
||||
state["key"],
|
||||
event.message_type) as res:
|
||||
await login_in.finish(res.text())
|
||||
|
||||
|
||||
# ---------- 查询签到 ----------
|
||||
@query_sign_in.handle()
|
||||
async def query_sign_in_handle(bot: Bot, event: MessageEvent, state: T_State):
|
||||
if await CLASS_CADRE(bot, event, state):
|
||||
state["param"] = state["class_cadre"]
|
||||
else:
|
||||
await query_sign_in.finish()
|
||||
|
||||
|
||||
@query_sign_in.got("param")
|
||||
async def query_sign_in_got(bot: Bot, event: MessageEvent, state: T_State):
|
||||
with QuerySignIn(state["param"]["班级"]) as res:
|
||||
for msg in res.text():
|
||||
await query_sign_in.send(msg)
|
||||
|
||||
|
@ -0,0 +1,5 @@
|
||||
from pydantic import BaseSettings
|
||||
|
||||
|
||||
class Config(BaseSettings):
|
||||
user_table = "user_info"
|
@ -0,0 +1,160 @@
|
||||
from nonebot import on_command, require
|
||||
from nonebot.adapters.cqhttp import Bot, GroupMessageEvent, MessageEvent
|
||||
from .data_source import SelectTasks, AddTask, PushTaskFile, Image, ExportTask, DeleteTask
|
||||
|
||||
rule = require("rule")
|
||||
IS_USER = rule.IS_USER
|
||||
CLASS_CADRE = rule.CLASS_CADRE
|
||||
query_task = on_command("查询任务")
|
||||
add_task = on_command("添加任务")
|
||||
push_task_file = on_command("提交任务")
|
||||
export_task = on_command("导出任务")
|
||||
delete_task = on_command("删除任务")
|
||||
|
||||
|
||||
# 查询任务
|
||||
@query_task.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: dict):
|
||||
if await IS_USER(bot, event, state):
|
||||
text = event.get_plaintext()
|
||||
task: SelectTasks = await SelectTasks(
|
||||
state["user_info"]["班级"],
|
||||
int(text) - 1 if text.isdigit() else None)
|
||||
async for msg in task.text():
|
||||
await query_task.send(msg)
|
||||
|
||||
|
||||
# 添加任务
|
||||
@add_task.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: dict):
|
||||
if await CLASS_CADRE(bot, event, state):
|
||||
text = event.get_plaintext()
|
||||
if text:
|
||||
state["title"] = text
|
||||
|
||||
|
||||
@add_task.got("title", prompt="这个任务的标题叫什么呢?")
|
||||
async def _(bot: Bot, event: MessageEvent, state: dict):
|
||||
text = event.get_plaintext()
|
||||
if text:
|
||||
async with AddTask(text, event.user_id, state["class_cadre"]["班级"], state["class_cadre"]["职位"]) as text:
|
||||
await add_task.finish(text)
|
||||
else:
|
||||
await add_task.finish("不告诉我就不给你添加了,哼~")
|
||||
|
||||
|
||||
# 提交任务
|
||||
@push_task_file.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: dict):
|
||||
if await IS_USER(bot, event, state):
|
||||
text = event.get_plaintext()
|
||||
task: PushTaskFile = await PushTaskFile(state["user_info"]["班级"], int(text) - 1 if text.isdigit() else None)
|
||||
state["task"] = task
|
||||
if not task:
|
||||
await push_task_file.finish(await task.text_one())
|
||||
elif task.index is None:
|
||||
await push_task_file.send(await task.text_one())
|
||||
else:
|
||||
state['index'] = task.index
|
||||
|
||||
|
||||
@push_task_file.got("index", prompt="你想交第几个任务呀!")
|
||||
async def _(bot: Bot, event: MessageEvent, state: dict):
|
||||
index = state["index"]
|
||||
task: PushTaskFile = state["task"]
|
||||
if not isinstance(index, int):
|
||||
text = event.get_plaintext()
|
||||
index = int(text) - 1 if text.isdigit() else None
|
||||
if index is None:
|
||||
await push_task_file.finish(f"不提交就算了,哼~")
|
||||
elif index not in task:
|
||||
await push_task_file.finish(f"你有看到我给你列出{index+1}号吗?哼~")
|
||||
|
||||
task(state["user_info"]["姓名"], event.user_id, index)
|
||||
|
||||
|
||||
@push_task_file.got('file', prompt="文件给我吧。")
|
||||
async def _(bot: Bot, event: MessageEvent, state: dict):
|
||||
task: PushTaskFile = state["task"]
|
||||
image = [Image(msg.data) for msg in event.message if msg.type == "image"]
|
||||
if image:
|
||||
image = image[0]
|
||||
if await task.file_exists(image):
|
||||
await push_task_file.finish("你这是拿别人的文件吧,不要瞎搞哦!")
|
||||
else:
|
||||
await push_task_file.finish(await task.save(image))
|
||||
else:
|
||||
await push_task_file.finish("文件呢?")
|
||||
|
||||
|
||||
# 导出任务
|
||||
@export_task.handle()
|
||||
async def _(bot: Bot, event: GroupMessageEvent, state: dict):
|
||||
if await CLASS_CADRE(bot, event, state):
|
||||
text = event.get_plaintext()
|
||||
task: ExportTask = await ExportTask(state["class_cadre"]["班级"], int(text) - 1 if text.isdigit() else None)
|
||||
state["task"] = task
|
||||
if not task:
|
||||
await export_task.finish(await task.text_one())
|
||||
elif task.index is None:
|
||||
await export_task.send(await task.text_one())
|
||||
else:
|
||||
state['index'] = task.index
|
||||
|
||||
|
||||
@export_task.got("index", prompt="你想导出第几个任务呀!")
|
||||
async def _(bot: Bot, event: GroupMessageEvent, state: dict):
|
||||
index = state["index"]
|
||||
task: ExportTask = state["task"]
|
||||
if not isinstance(index, int):
|
||||
text = event.get_plaintext()
|
||||
index = int(text) - 1 if text.isdigit() else None
|
||||
if index is None:
|
||||
await export_task.finish(f"不提交就算了,哼~")
|
||||
elif index not in task:
|
||||
await export_task.finish(f"你有看到我给你列出{index+1}号吗?哼~")
|
||||
|
||||
if task(index).task_user.shape[0]:
|
||||
await export_task.send("开始进行打包咯...")
|
||||
file, name = task.zip()
|
||||
await export_task.send("打包完成,开始发送文件...")
|
||||
await bot.call_api("upload_group_file", group_id=event.group_id, file=file, name=name)
|
||||
else:
|
||||
await export_task.finish("都没人提交,你这叫我怎么导出嘛!")
|
||||
|
||||
|
||||
# 删除任务
|
||||
@delete_task.handle()
|
||||
async def _(bot: Bot, event: GroupMessageEvent, state: dict):
|
||||
if await CLASS_CADRE(bot, event, state):
|
||||
text = event.get_plaintext()
|
||||
task: DeleteTask = await DeleteTask(state["class_cadre"]["班级"], int(text) - 1 if text.isdigit() else None)
|
||||
state["task"] = task
|
||||
if not task:
|
||||
await delete_task.finish(await task.text_one())
|
||||
elif task.index is None:
|
||||
await delete_task.send(await task.text_one())
|
||||
else:
|
||||
state['index'] = task.index
|
||||
|
||||
|
||||
@delete_task.got("index", prompt="你想删除第几个任务呀!")
|
||||
async def _(bot: Bot, event: MessageEvent, state: dict):
|
||||
index = state["index"]
|
||||
task: ExportTask = state["task"]
|
||||
if not isinstance(index, int):
|
||||
text = event.get_plaintext()
|
||||
index = int(text) - 1 if text.isdigit() else None
|
||||
if index is None:
|
||||
await delete_task.finish(f"取消删除")
|
||||
elif index not in task:
|
||||
await delete_task.finish(f"你有看到我给你列出{index + 1}号吗?哼~")
|
||||
state["index"] = index
|
||||
await delete_task.send(f"如果真的要删除”{task[index]['title']}“请发送”确认“。")
|
||||
|
||||
|
||||
@delete_task.got("delete")
|
||||
async def _(bot: Bot, event: MessageEvent, state: dict):
|
||||
if "确认" in event.get_plaintext():
|
||||
task: DeleteTask = state["task"](state["index"])
|
||||
await delete_task.finish(await task.delete())
|
@ -0,0 +1,24 @@
|
||||
from nonebot import require, on_command
|
||||
from nonebot.adapters.cqhttp import Bot, MessageEvent
|
||||
from .data_source import SetWatermark
|
||||
|
||||
|
||||
watermark = on_command("水印", aliases={"打水印", "添加水印"})
|
||||
IS_USER = require("rule").IS_USER
|
||||
|
||||
|
||||
@watermark.handle()
|
||||
async def watermark_handler(bot: Bot, event: MessageEvent, state: dict):
|
||||
if await IS_USER(bot, event, state):
|
||||
for msg in event.message:
|
||||
if msg.type == "image":
|
||||
state['params'] = True
|
||||
break
|
||||
|
||||
|
||||
@watermark.got("params", prompt="请发送图片")
|
||||
async def watermark_got(bot: Bot, event: MessageEvent, state: dict):
|
||||
for msg in event.message:
|
||||
if msg.type == "image":
|
||||
async with SetWatermark(msg.data["url"], state["user_info"]) as res:
|
||||
await watermark.send(res.image())
|
@ -0,0 +1,35 @@
|
||||
from nonebot import require
|
||||
from io import BytesIO
|
||||
from nonebot.adapters.cqhttp import MessageSegment
|
||||
from PIL.PngImagePlugin import PngImageFile
|
||||
from pandas import DataFrame
|
||||
|
||||
Watermark = require("tools").Watermark
|
||||
|
||||
|
||||
class SetWatermark:
|
||||
def __init__(self, file, user_info: DataFrame):
|
||||
self.file = file
|
||||
self.user_info = user_info
|
||||
|
||||
def image(self):
|
||||
"""发送图片"""
|
||||
img_bytes = BytesIO()
|
||||
self.img.save(img_bytes, format="JPEG")
|
||||
return MessageSegment.image(img_bytes)
|
||||
|
||||
async def draw(self) -> PngImageFile:
|
||||
"""绘制"""
|
||||
async with Watermark(
|
||||
url=self.file,
|
||||
text=f'{self.user_info["姓名"]}\n{self.user_info["班级"]}',
|
||||
size=100,
|
||||
xy=(50, 50)) as res:
|
||||
return res.img
|
||||
|
||||
async def __aenter__(self):
|
||||
self.img = await self.draw()
|
||||
return self
|
||||
|
||||
async def __aexit__(self, *args):
|
||||
...
|
@ -0,0 +1 @@
|
||||
# 德育分,表现分记录
|
@ -0,0 +1,6 @@
|
||||
from pydantic import BaseSettings
|
||||
|
||||
|
||||
class Config(BaseSettings):
|
||||
score_log = "score_log"
|
||||
user_table = "user_info"
|
@ -0,0 +1,203 @@
|
||||
from nonebot import require
|
||||
from typing import List, Union
|
||||
from .config import Config
|
||||
from aiohttp import ClientSession
|
||||
from zipfile import ZipFile, ZIP_DEFLATED
|
||||
from pandas import DataFrame, Series
|
||||
from json import loads, dumps
|
||||
from os import path
|
||||
from datetime import datetime
|
||||
from nonebot.adapters.cqhttp import Message, MessageSegment
|
||||
|
||||
config = Config()
|
||||
mysql = require("botdb").MySQLdbMethods()
|
||||
readfile = require("readfile").ReadFile("data", "class_system")
|
||||
|
||||
|
||||
def select_names(names, typeof="name"):
|
||||
"""查看是否有需要查找的用户的名字"""
|
||||
return f" and {typeof} in({','.join(['%s'] * len(names))})" if names else ""
|
||||
|
||||
|
||||
class Image:
|
||||
def __init__(self, data):
|
||||
self.name = data.get("file").split(".")[0]
|
||||
self.url = data.get("url")
|
||||
|
||||
|
||||
class GetMessage:
|
||||
def __init__(self, message: Message):
|
||||
self.text = ""
|
||||
self.images: List[Image] = []
|
||||
for msg in message:
|
||||
if msg.type == "text":
|
||||
txt = msg.data.get("text").strip()
|
||||
if txt:
|
||||
self.text = txt
|
||||
elif msg.type == "image":
|
||||
self.images.append(Image(msg.data))
|
||||
|
||||
|
||||
class AddScoreLog:
|
||||
def __init__(self, class_name: str,
|
||||
name: Union[str, list],
|
||||
user_id: Union[int, list],
|
||||
student_id: Union[str, list],
|
||||
images: List[Image],
|
||||
explain_reason: str):
|
||||
self.class_name = class_name
|
||||
self.name = name
|
||||
self.image = images[0]
|
||||
self.user_id = user_id
|
||||
self.student_id = int(student_id)
|
||||
self.explain_reason = explain_reason
|
||||
self.reply = ""
|
||||
self.image_path = path.join(self.class_name, "images")
|
||||
self.prove_file = path.join(self.class_name, "prove.json")
|
||||
|
||||
async def read_prove(self):
|
||||
"""读取证明"""
|
||||
try:
|
||||
return loads(await readfile.read(self.prove_file))
|
||||
except FileNotFoundError:
|
||||
"""读取失败时候创建新证明"""
|
||||
prove = {"all_file": [], "user_file": {}}
|
||||
readfile.mkdir(self.class_name)
|
||||
await readfile.write(self.prove_file, dumps(prove))
|
||||
return prove
|
||||
|
||||
async def save_prove(self):
|
||||
"""保存证明"""
|
||||
await readfile.write(self.prove_file, dumps(self.prove))
|
||||
|
||||
async def query_user(self) -> DataFrame:
|
||||
"""按照班级查找用户"""
|
||||
await mysql.execute(f"select 姓名, qq, 学号 from {config.user_table} where 班级=%s{select_names(self.name, '姓名')}",
|
||||
[self.class_name, *self.name])
|
||||
return mysql.form()
|
||||
|
||||
async def add_logger(self, name, user_id, student_id):
|
||||
await mysql.execute_commit(f"insert into {config.score_log} "
|
||||
"(class_name, name, qq, student_id, explain_reason, prove) value (%s,%s,%s,%s,%s,%s)",
|
||||
[self.class_name, name, user_id, student_id, self.explain_reason, self.image.name])
|
||||
|
||||
async def save_image(self):
|
||||
"""将图片保存到本地"""
|
||||
readfile.mkdir(self.image_path)
|
||||
if self.image.name not in self.prove["all_file"]:
|
||||
self.prove["all_file"].append(self.image.name)
|
||||
async with ClientSession() as session:
|
||||
async with session.get(self.image.url) as res:
|
||||
data = await res.read()
|
||||
await readfile.write(path.join(self.image_path, f"{self.image.name}.jpg"), data, mode="wb")
|
||||
|
||||
async def __aenter__(self):
|
||||
self.prove = await self.read_prove()
|
||||
if isinstance(self.name, list):
|
||||
self.user_info = await self.query_user()
|
||||
for i, user in self.user_info.iterrows():
|
||||
self.reply += user["姓名"] + ","
|
||||
await self.add_logger(user["姓名"], user["qq"], user["学号"])
|
||||
else:
|
||||
await self.add_logger(self.name, self.user_id, self.student_id)
|
||||
self.reply += "德育日志添加成功!!"
|
||||
return self
|
||||
|
||||
def text(self):
|
||||
return Message(self.reply)
|
||||
|
||||
async def __aexit__(self, *args):
|
||||
await self.save_image()
|
||||
await self.save_prove()
|
||||
|
||||
|
||||
class SaveDialog:
|
||||
def __init__(self, class_name: str, names: list):
|
||||
self.date = datetime.now()
|
||||
self.class_name = class_name
|
||||
self.names = names
|
||||
self.class_file = path.join(readfile.path, class_name) # 班级文件路径
|
||||
self.not_value = True # 是否为空数据
|
||||
self.file_path = ""
|
||||
self.reply = ""
|
||||
|
||||
def save(self):
|
||||
"""保存到本地文件"""
|
||||
try:
|
||||
self.data.to_excel(self.file_path, index=False)
|
||||
except FileNotFoundError:
|
||||
readfile.mkdir(self.class_name)
|
||||
self.save()
|
||||
|
||||
def file_name(self, suffix: str):
|
||||
"""根据班级名+时间保存为文件名"""
|
||||
if self.names:
|
||||
file_name = '_'.join(set(self.data["姓名"]))
|
||||
else:
|
||||
file_name = self.class_name
|
||||
date = str(self.date).split(".")[0].replace(" ", "-").replace(":", "-")
|
||||
return file_name + date + "." + suffix
|
||||
|
||||
@staticmethod
|
||||
def set_data(data: DataFrame) -> DataFrame:
|
||||
"""设置数据,将说明与时间相结合,并且添加附加分名称与分数"""
|
||||
data["说明"] = [str(data.loc[i]["log_time"].date()) + data.loc[i]["说明"] for i in range(data.shape[0])]
|
||||
data["附加分名称"], data["分数"] = "", ""
|
||||
data.drop(columns="log_time", axis=0, inplace=True)
|
||||
data.sort_values(by="姓名", ascending=False, inplace=True) # 按照姓名排序
|
||||
return data[["学号", "姓名", "附加分名称", "分数", "说明"]]
|
||||
|
||||
async def get_data(self) -> DataFrame:
|
||||
"""查找用户,并且按照当月筛选出用户"""
|
||||
await mysql.execute(
|
||||
f"select student_id 学号, name 姓名, explain_reason 说明, log_time, prove from {config.score_log} "
|
||||
f"where year(log_time)=%s and month(log_time)=%s and class_name=%s{select_names(self.names)}",
|
||||
[self.date.year, self.date.month, self.class_name, *self.names])
|
||||
return mysql.form()
|
||||
|
||||
async def __aenter__(self):
|
||||
data: DataFrame = await self.get_data()
|
||||
if data.shape[0]:
|
||||
self.not_value = False
|
||||
self.data: DataFrame = self.set_data(data)
|
||||
self.name = self.file_name("xlsx") # 文件名
|
||||
self.file_path = path.join(self.class_file, self.name)
|
||||
self.save()
|
||||
else:
|
||||
self.reply = "未发现日志!!!"
|
||||
return self
|
||||
|
||||
def text(self):
|
||||
return Message(self.reply)
|
||||
|
||||
async def __aexit__(self, *args):
|
||||
...
|
||||
|
||||
|
||||
class ExportProve(SaveDialog):
|
||||
def __init__(self, class_name: str, names: list):
|
||||
super().__init__(class_name, names)
|
||||
|
||||
async def __aenter__(self):
|
||||
self.data: DataFrame = await self.get_data()
|
||||
if self.data.shape[0]:
|
||||
self.not_value = False
|
||||
self.name = self.file_name("zip") # 文件名
|
||||
self.file_path = path.join(self.class_file, self.name)
|
||||
self.zip()
|
||||
else:
|
||||
self.reply = "未发现日志!!!"
|
||||
return self
|
||||
|
||||
def zip(self):
|
||||
prove = set(self.data["prove"])
|
||||
length = len(prove)
|
||||
yield "开始进行打包..."
|
||||
with ZipFile(self.file_path, "w", ZIP_DEFLATED) as zip_file:
|
||||
for img in prove:
|
||||
try:
|
||||
zip_file.write(path.join(self.class_file, "images", f"{img}.jpg"), f"{img}.jpg")
|
||||
except FileNotFoundError as err:
|
||||
length -= 1
|
||||
print(err)
|
||||
yield f"打包完成\n文件数量:{length}\n开始发送请耐心等待..."
|
@ -0,0 +1,58 @@
|
||||
from nonebot import on_command, require
|
||||
from .data_source import InsertUser
|
||||
from nonebot.adapters.cqhttp import Bot, GroupMessageEvent, Message
|
||||
from nonebot.rule import T_State
|
||||
from typing import Union
|
||||
import re
|
||||
|
||||
rule = require("rule")
|
||||
permission = require("permission")
|
||||
TEACHER = permission.TEACHER
|
||||
MASTER = rule.MASTER
|
||||
push_user = on_command("导入班级信息", aliases={"导入班级"})
|
||||
|
||||
|
||||
def re_docs(text: str) -> str:
|
||||
return re.search(r"https://docs.qq.com/sheet/\S[^\"']+", str(text).replace("\\", ""), re.I).group()
|
||||
|
||||
|
||||
def get_url(message: Union[Message, str]) -> str:
|
||||
url = None
|
||||
if isinstance(message, Message):
|
||||
for msg in message:
|
||||
if msg.type == "json" or msg.type == "xml":
|
||||
url = re_docs(msg.data["data"])
|
||||
elif msg.type == "text":
|
||||
url = re_docs(msg.data["text"])
|
||||
if url:
|
||||
return url
|
||||
else:
|
||||
return re_docs(message)
|
||||
|
||||
|
||||
def get_text(message: Message):
|
||||
"""获取文本"""
|
||||
for msg in message:
|
||||
if msg.type == "text":
|
||||
return msg.data.get("text").strip()
|
||||
|
||||
|
||||
@push_user.handle()
|
||||
async def push_user_handler(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||
if await MASTER(bot, event, state):
|
||||
url = get_url(event.message)
|
||||
if url:
|
||||
state["param"] = url
|
||||
else:
|
||||
await push_user.finish()
|
||||
|
||||
|
||||
@push_user.got("param", "请转发腾讯在线文档,或者在线文档的链接!!!")
|
||||
async def push_user_got(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||
url = get_url(state["param"])
|
||||
if url:
|
||||
# 获取班级名称
|
||||
class_name = state["all_group"]["class_name"][state["all_group"]["class_group"].index(event.group_id)]
|
||||
async with InsertUser(url, class_name) as res:
|
||||
await push_user.finish(res.text())
|
||||
|
@ -0,0 +1,35 @@
|
||||
from pydantic import BaseSettings
|
||||
|
||||
|
||||
class Config(BaseSettings):
|
||||
user_table = "user_info"
|
||||
user_table_param_not_null = {
|
||||
"姓名": str,
|
||||
"序号": int,
|
||||
"学号": int,
|
||||
"性别": str,
|
||||
"联系方式": int
|
||||
}
|
||||
user_table_param_type = {
|
||||
"序号": int,
|
||||
"姓名": str,
|
||||
"班级": str,
|
||||
"学号": int,
|
||||
"性别": str,
|
||||
"联系方式": int,
|
||||
"身份证号": str,
|
||||
"出生日期": str,
|
||||
"寝室": str,
|
||||
"寝室长": str,
|
||||
"微信": str,
|
||||
"QQ": int,
|
||||
"邮箱": str,
|
||||
"民族": str,
|
||||
"籍贯": str,
|
||||
"职位": str,
|
||||
"团员": str,
|
||||
"入党积极分子": str,
|
||||
"团学": str,
|
||||
"社团": str,
|
||||
"分数": int
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
# 查询用户
|
||||
|
||||
编写功能
|
||||
- 查询
|
||||
- 查询 姓名 qq 序号 学号
|
||||
- at
|
||||
- at 姓名 qq 序号 学号
|
@ -0,0 +1,55 @@
|
||||
from nonebot import on_command, require
|
||||
from nonebot.adapters.cqhttp import Bot, Message, GroupMessageEvent
|
||||
from nonebot.rule import T_State
|
||||
from .data_source import QueryUser, AtUser
|
||||
|
||||
|
||||
CLASS_GROUP = require("permission").CLASS_GROUP
|
||||
query_user = on_command("查询", aliases={"查找", "搜索"})
|
||||
at_user = on_command("at", aliases={"艾特", "@"})
|
||||
|
||||
|
||||
def get_text(message: Message) -> str:
|
||||
"""获取文本"""
|
||||
for msg in message:
|
||||
if msg.type == "text":
|
||||
return msg.data.get("text").strip()
|
||||
if msg.type == "at":
|
||||
return " " + str(msg.data.get("qq"))
|
||||
|
||||
|
||||
@query_user.handle()
|
||||
async def query_user_handle(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||
"""获取查询的用户,如果没有填写查询对象则默认查询自己"""
|
||||
if await CLASS_GROUP(bot, event):
|
||||
features = get_text(event.message)
|
||||
state["param"] = features.split() if features else [event.get_user_id()]
|
||||
else:
|
||||
await query_user.finish()
|
||||
|
||||
|
||||
@query_user.got("param")
|
||||
async def query_user_got(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||
async with QueryUser(state["param"], event.group_id) as res:
|
||||
await query_user.finish(res.text())
|
||||
|
||||
|
||||
@at_user.handle()
|
||||
async def at_user_handle(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||
if await CLASS_GROUP(bot, event):
|
||||
features = get_text(event.message)
|
||||
if features:
|
||||
state["param"] = features.split()
|
||||
else:
|
||||
await query_user.finish()
|
||||
|
||||
|
||||
@at_user.got("param", prompt="请输入您需要at的成员名称/序号/qq/学号。")
|
||||
async def at_user_got(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||
if isinstance(state["param"], str):
|
||||
state["param"] = state["param"].split()
|
||||
if state["param"]:
|
||||
async with AtUser(state["param"], event.group_id) as res:
|
||||
if not res.is_err:
|
||||
await at_user.finish(res.text())
|
||||
|
@ -0,0 +1,7 @@
|
||||
from pydantic import BaseSettings
|
||||
|
||||
|
||||
class Config(BaseSettings):
|
||||
user_table = "user_info"
|
||||
teacher_table = "teacher"
|
||||
class_table = "class_table"
|
@ -0,0 +1 @@
|
||||
# 群友重命名插件
|
@ -0,0 +1,23 @@
|
||||
from pprint import pprint
|
||||
|
||||
from nonebot import on_command, require
|
||||
from nonebot.adapters.cqhttp import Bot, GroupMessageEvent
|
||||
from .data_source import UserName
|
||||
|
||||
|
||||
reset_name = on_command("重命名", aliases={"班级重命名", "学生重命名", "自动改备注"})
|
||||
IS_USER = require("rule").IS_USER
|
||||
|
||||
|
||||
def get_group_user_id(users: list):
|
||||
return [int(user["user_id"]) for user in users]
|
||||
|
||||
|
||||
@reset_name.handle()
|
||||
async def reset_name_handle(bot: Bot, event: GroupMessageEvent, state: dict):
|
||||
if await IS_USER(bot, event, state):
|
||||
group_user = get_group_user_id(await bot.get_group_member_list(group_id=event.group_id))
|
||||
async with UserName(group_user) as res:
|
||||
await reset_name.send(res.load_text())
|
||||
await res.reset_name(event.group_id, bot.set_group_card)
|
||||
await reset_name.finish(res.text())
|
@ -0,0 +1,6 @@
|
||||
from pydantic import BaseSettings
|
||||
|
||||
|
||||
class Config(BaseSettings):
|
||||
user_table = "user_info"
|
||||
|
@ -0,0 +1,41 @@
|
||||
from nonebot import require
|
||||
from nonebot.adapters.cqhttp import Message
|
||||
from asyncio import sleep
|
||||
from pandas import DataFrame
|
||||
|
||||
from .config import Config
|
||||
|
||||
mysql = require("botdb").MySQLdbMethods()
|
||||
config = Config()
|
||||
|
||||
|
||||
class UserName:
|
||||
def __init__(self, users: list):
|
||||
self.users = users
|
||||
self.reply = ""
|
||||
self.sleep = 5
|
||||
|
||||
async def select_user(self):
|
||||
await mysql.execute(f"select * from {config.user_table} where qq in({','.join(['%s'] * len(self.users))})",
|
||||
self.users)
|
||||
return mysql.form()
|
||||
|
||||
async def __aenter__(self):
|
||||
self.all_user: DataFrame = await self.select_user()
|
||||
return self
|
||||
|
||||
def load_text(self):
|
||||
return Message(f"请稍等,预计需要{self.all_user.shape[0] * self.sleep}秒完成!")
|
||||
|
||||
async def reset_name(self, group_id: int, func):
|
||||
for index, user in self.all_user.iterrows():
|
||||
await sleep(self.sleep)
|
||||
# print(f"{user['姓名']} {user['寝室']} {user['联系方式']}")
|
||||
await func(group_id=group_id, user_id=user["QQ"], card=f"{user['姓名']} {user['寝室']} {user['联系方式']}")
|
||||
self.reply = "重命名成功"
|
||||
|
||||
def text(self):
|
||||
return Message(self.reply)
|
||||
|
||||
async def __aexit__(self, *args):
|
||||
...
|
@ -0,0 +1,11 @@
|
||||
# 增加或减少数据
|
||||
|
||||
- 增加
|
||||
- 院系
|
||||
- 教师
|
||||
- 专业
|
||||
- 班级
|
||||
|
||||
## 教师权限
|
||||
可以
|
||||
|
@ -0,0 +1,8 @@
|
||||
from pydantic import BaseSettings
|
||||
|
||||
|
||||
class Config(BaseSettings):
|
||||
faculty = "faculty_table"
|
||||
expertise = "expertise_table"
|
||||
teacher = "teacher"
|
||||
class_table = "class_table"
|
@ -0,0 +1,209 @@
|
||||
from nonebot import require
|
||||
from .config import Config
|
||||
from nonebot.adapters.cqhttp import Message
|
||||
from aiomysql import IntegrityError
|
||||
|
||||
ADD = "add"
|
||||
DEL = "del"
|
||||
MySQLdbMethods = require("botdb").MySQLdbMethods
|
||||
mysql = MySQLdbMethods()
|
||||
config = Config()
|
||||
|
||||
|
||||
# 学院院系
|
||||
class Faculty:
|
||||
def __init__(self,
|
||||
typeof: str,
|
||||
faculty: str,
|
||||
invitee: int
|
||||
):
|
||||
"""
|
||||
:param faculty: 需要添加的院系
|
||||
:param invitee: 添加人的QQ
|
||||
"""
|
||||
self.typeof = typeof
|
||||
self.faculty = faculty # 院系
|
||||
self.invitee = invitee # 添加人
|
||||
self.is_err = False
|
||||
self.reply_text = None
|
||||
self.table_name = config.faculty
|
||||
|
||||
async def __aenter__(self):
|
||||
try:
|
||||
if self.typeof == ADD:
|
||||
# ----- 添加数据 -----
|
||||
await mysql.execute_commit(
|
||||
f"insert into {self.table_name} value (%s,%s)", param=[
|
||||
self.faculty, self.invitee
|
||||
])
|
||||
# ----- 添加数据回复 -----
|
||||
self.reply_text = f"”{self.faculty}“添加成功。"
|
||||
elif self.typeof == DEL:
|
||||
# ----- 删除数据回复 -----
|
||||
await mysql.execute_commit(f"delete from {self.table_name} where faculty=%s", param=[
|
||||
self.faculty])
|
||||
# ----- 删除成功回复 -----
|
||||
self.reply_text = f"“{self.faculty}”已删除。"
|
||||
except IntegrityError:
|
||||
if self.typeof == DEL:
|
||||
# ----- 删除失败回复 -----
|
||||
self.reply_text = f"“{self.faculty}”删除失败,可能”{self.faculty}“下还所在专业未删除!!!"
|
||||
elif self.typeof == ADD:
|
||||
# ----- 添加失败回复 -----
|
||||
self.reply_text = f"”{self.faculty}“已经添加,无需重复执行!!!"
|
||||
self.is_err = True
|
||||
return self
|
||||
|
||||
def text(self) -> Message:
|
||||
return Message(self.reply_text)
|
||||
|
||||
async def __aexit__(self, *args):
|
||||
...
|
||||
|
||||
|
||||
# 院系的专业
|
||||
class Expertise:
|
||||
def __init__(self,
|
||||
typeof,
|
||||
expertise: str,
|
||||
faculty: str = None
|
||||
):
|
||||
self.typeof = typeof
|
||||
self.faculty = faculty # 院系
|
||||
self.expertise = expertise # 专业
|
||||
self.is_err = False
|
||||
self.reply_text = None
|
||||
self.table_name = config.expertise
|
||||
|
||||
async def __aenter__(self):
|
||||
try:
|
||||
if self.typeof == ADD:
|
||||
# ----- 添加数据 -----
|
||||
await mysql.execute_commit(
|
||||
f"insert into {self.table_name} value (%s,%s)", param=[
|
||||
self.faculty, self.expertise
|
||||
])
|
||||
# ----- 添加成功回复 -----
|
||||
self.reply_text = f"“{self.expertise}”添加成功,所在院系”{self.faculty}“。"
|
||||
elif self.typeof == DEL:
|
||||
# ----- 删除数据 -----
|
||||
await mysql.execute_commit(f"delete from {self.table_name} where expertise=%s", param=[
|
||||
self.expertise])
|
||||
# ----- 删除成功回复 -----
|
||||
self.reply_text = f"“{self.expertise}”已删除。"
|
||||
except IntegrityError:
|
||||
if self.typeof == ADD:
|
||||
# ----- 添加失败回复 -----
|
||||
self.reply_text = f"”{self.expertise}“添加失败,可能是”{self.faculty}“不存在,或者是”{self.expertise}“已经添加过!!!"
|
||||
self.is_err = True
|
||||
return self
|
||||
|
||||
def text(self) -> Message:
|
||||
return Message(self.reply_text)
|
||||
|
||||
async def __aexit__(self, *args):
|
||||
...
|
||||
|
||||
|
||||
class Teacher:
|
||||
def __init__(self,
|
||||
typeof: str,
|
||||
name: str = None,
|
||||
qq: int = None,
|
||||
tel: int = None,
|
||||
invitee: int = None
|
||||
):
|
||||
self.qq = qq # 教师QQ
|
||||
self.tel = tel # 教师电话
|
||||
self.name = name # 教师姓名
|
||||
self.invitee = str(invitee) # 添加人
|
||||
self.typeof = typeof
|
||||
self.is_err = False
|
||||
self.reply_text = None
|
||||
self.table_name = config.teacher
|
||||
|
||||
async def __aenter__(self):
|
||||
try:
|
||||
if self.typeof == ADD:
|
||||
# ----- 添加教师信息 -----
|
||||
await mysql.execute_commit(f"insert into {self.table_name} values (%s,%s,%s,%s)", param=[
|
||||
self.name, self.qq, self.invitee, self.tel
|
||||
])
|
||||
# ----- 添加成功回复 -----
|
||||
self.reply_text = f"”{self.name}“添加成功。"
|
||||
elif self.typeof == DEL:
|
||||
# # ----- 删除教师信息 -----
|
||||
if self.name:
|
||||
sql = f"delete from {self.table_name} where name=%s"
|
||||
else:
|
||||
sql = f"delete from {self.table_name} where qq=%s"
|
||||
await mysql.execute_commit(sql, param=[self.name or self.qq])
|
||||
# # ----- 删除成功回复 -----
|
||||
self.reply_text = f"”{self.name or self.qq}“已删除。"
|
||||
except IntegrityError:
|
||||
if self.typeof == ADD:
|
||||
# ----- 添加失败回复 -----
|
||||
self.reply_text = f"“{self.name}”添加失败,可能重复添加某条数据,或者缺少某些数据!!!"
|
||||
elif self.typeof == DEL:
|
||||
# ----- 删除失败回复 -----
|
||||
self.reply_text = f"“{self.name}”删除失败,可能“{self.name}”下还有班级未删除!!!"
|
||||
return self
|
||||
|
||||
def text(self):
|
||||
return Message(self.reply_text)
|
||||
|
||||
async def __aexit__(self, *args):
|
||||
...
|
||||
|
||||
|
||||
class Class:
|
||||
def __init__(self,
|
||||
typeof: str,
|
||||
class_name: str = None,
|
||||
class_id: int = None,
|
||||
class_group: int = None,
|
||||
class_teacher: int = None,
|
||||
expertise: str = None
|
||||
):
|
||||
self.typeof = typeof
|
||||
self.class_name = class_name # 班级全称
|
||||
self.class_id = class_id # 班级id
|
||||
self.class_group = class_group # 班级群
|
||||
self.class_teacher = class_teacher # 班主任
|
||||
self.expertise = expertise # 专业
|
||||
self.is_err = False
|
||||
self.reply_text = None
|
||||
self.table_name = config.class_table
|
||||
|
||||
async def __aenter__(self):
|
||||
try:
|
||||
if self.typeof == ADD:
|
||||
# ----- 添加班级 -----
|
||||
await mysql.execute_commit(f"insert into {self.table_name} values (%s,%s,%s,%s,%s)", param=[
|
||||
self.class_id, self.expertise, self.class_group, self.class_name, self.class_teacher
|
||||
])
|
||||
# ----- 添加成功回复 -----
|
||||
self.reply_text = f"”{self.class_name}“添加完成,您已成为”{self.class_name}“班主任,可以在此群导入班级表格。"
|
||||
elif self.typeof == DEL:
|
||||
# ----- 删除班级 -----
|
||||
if self.class_name:
|
||||
sql = f"delete from {self.table_name} where class_name=%s"
|
||||
else:
|
||||
sql = f"delete from {self.table_name} where class_group=%s"
|
||||
await mysql.execute_commit(sql, param=[self.class_name or self.class_group])
|
||||
# ----- 删除成功回复 -----
|
||||
self.reply_text = f"“{self.class_name or self.class_group}“已删除"
|
||||
except IntegrityError:
|
||||
if self.typeof == ADD:
|
||||
# ----- 添加失败回复 -----
|
||||
self.reply_text = f"“{self.class_name}”添加失败,错误原因可能如下:\n1.教师不在数据库中。\n2.此专业存在。\n3.此班级已创建!!!"
|
||||
elif self.typeof == DEL:
|
||||
# ----- 删除失败回复 -----
|
||||
self.reply_text = f"“{self.class_name}”删除失败,请先清空该班级下的学生信息!!!"
|
||||
return self
|
||||
|
||||
def text(self):
|
||||
return Message(self.reply_text)
|
||||
|
||||
async def __aexit__(self, *args):
|
||||
...
|
@ -0,0 +1,45 @@
|
||||
from nonebot import on_command, require
|
||||
from nonebot.adapters.cqhttp import Bot, MessageEvent
|
||||
from .data_source import SetScore, config, GiftScore
|
||||
|
||||
rule = require("rule")
|
||||
IS_USER = rule.IS_USER
|
||||
CLASS_CADRE = rule.CLASS_CADRE
|
||||
|
||||
add_score = on_command("加分", aliases={"添加分数", "减分", "扣分", "设置分数"})
|
||||
gift_score = on_command("转让", aliases={"赠与"})
|
||||
|
||||
|
||||
@add_score.handle()
|
||||
async def add_score_handler(bot: Bot, event: MessageEvent, state: dict):
|
||||
if (await CLASS_CADRE(bot, event, state)) and state["class_cadre"]["职位"] in config.score:
|
||||
text = event.get_plaintext()
|
||||
if text:
|
||||
state["param"] = text.split()
|
||||
else:
|
||||
await add_score.finish()
|
||||
|
||||
|
||||
@add_score.got("param", prompt="请输入成员名称与分数")
|
||||
async def add_score_got(bot: Bot, event: MessageEvent, state: dict):
|
||||
text = event.get_plaintext()
|
||||
if text:
|
||||
async with SetScore(state["class_cadre"]["班级"], text) as res:
|
||||
await add_score.finish(res.text())
|
||||
|
||||
|
||||
@gift_score.handle()
|
||||
async def gift_score_handle(bot: Bot, event: MessageEvent, state: dict):
|
||||
if await IS_USER(bot, event, state):
|
||||
text = event.get_plaintext()
|
||||
if text:
|
||||
state["param"] = text
|
||||
|
||||
|
||||
@gift_score.got("param", prompt="请输入需要转让的那一位同学姓名与数量")
|
||||
async def gift_score_got(bot: Bot, event: MessageEvent, state: dict):
|
||||
text = event.get_plaintext()
|
||||
if text:
|
||||
async with GiftScore(state["user_info"]["班级"], event.user_id, state["user_info"]["分数"], text) as res:
|
||||
await gift_score.finish(res.text())
|
||||
|
@ -0,0 +1,6 @@
|
||||
from pydantic import BaseSettings
|
||||
|
||||
|
||||
class Config(BaseSettings):
|
||||
user_table = "user_info"
|
||||
score = ["学习委员"]
|
@ -0,0 +1 @@
|
||||
# 商店插件
|
@ -0,0 +1,52 @@
|
||||
from nonebot import on_command, require
|
||||
from nonebot.adapters.cqhttp import Bot, MessageEvent
|
||||
from .data_source import get_url, AddGoods, SelectGoods
|
||||
|
||||
add_goods = on_command("更新商品", aliases={"添加商品", "更新列表"})
|
||||
select_goods = on_command("查看商品", aliases={"商品列表", "兑换列表"})
|
||||
# purchase = on_command("购买", aliases={"兑换"})
|
||||
TEACHER = require("permission").TEACHER
|
||||
IS_USER = require("rule").IS_USER
|
||||
|
||||
|
||||
@add_goods.handle()
|
||||
async def add_goods_handle(bot: Bot, event: MessageEvent, state: dict):
|
||||
if await TEACHER(bot, event):
|
||||
url = get_url(event.message)
|
||||
if url:
|
||||
state["url"] = url
|
||||
else:
|
||||
await add_goods.finish()
|
||||
|
||||
|
||||
@add_goods.got("url", prompt="请发送在线文档或者链接")
|
||||
async def add_goods_got(bot: Bot, event: MessageEvent, state: dict):
|
||||
url = get_url(state["url"])
|
||||
if url:
|
||||
async with AddGoods(event.user_id, url) as res:
|
||||
await add_goods.finish(res.text())
|
||||
|
||||
|
||||
@select_goods.handle()
|
||||
async def select_goods_handle(bot: Bot, event: MessageEvent, state: dict):
|
||||
if await IS_USER(bot, event, state):
|
||||
async with SelectGoods(event.user_id) as res:
|
||||
await select_goods.finish(res.text())
|
||||
|
||||
|
||||
# @purchase.handle()
|
||||
# async def purchase_handle(bot: Bot, event: MessageEvent, state: dict):
|
||||
# if await IS_USER(bot, event, state):
|
||||
# text = event.get_plaintext()
|
||||
# if text:
|
||||
# state["param"] = text
|
||||
|
||||
|
||||
# @purchase.got("param", prompt="请输入序号或名称")
|
||||
# async def purchase_got(bot: Bot, event: MessageEvent, state: dict):
|
||||
# if not isinstance(state["param"], list):
|
||||
# state["param"] = state["param"].split()
|
||||
# if state["param"]:
|
||||
# ...
|
||||
|
||||
|
@ -0,0 +1,5 @@
|
||||
from pydantic import BaseSettings
|
||||
|
||||
|
||||
class Config(BaseSettings):
|
||||
shop_table = "shop"
|
@ -0,0 +1 @@
|
||||
# 表格处理插件
|
@ -0,0 +1,77 @@
|
||||
from nonebot import on_command, require
|
||||
from nonebot.rule import T_State
|
||||
from .data_source import get_url, GetExcelNotUser, CheckUser
|
||||
from nonebot.adapters.cqhttp import Bot, GroupMessageEvent
|
||||
|
||||
push_user_info = on_command("未填写", aliases={"查表格", "查表", "为填表"})
|
||||
check_user = on_command("核对信息", aliases={"核验", "检查", "检查信息"})
|
||||
deep_check_user = on_command("深度检查", aliases={"严格检查", "深度核对"})
|
||||
super_check_user = on_command("超级核对", aliases={"超级检查"})
|
||||
IS_USER = require("rule").IS_USER
|
||||
|
||||
|
||||
# 添加班级成员需要按群添加,因为群内唯一群号绑定一个班级名
|
||||
@push_user_info.handle()
|
||||
async def _push_user_info_handle(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||
if await IS_USER(bot, event, state):
|
||||
url = get_url(event.message)
|
||||
if url:
|
||||
state["url"] = url
|
||||
else:
|
||||
await push_user_info.finish()
|
||||
|
||||
|
||||
# 未接受到班级表格时
|
||||
@push_user_info.got("url", prompt="请发送班级表格")
|
||||
async def _push_user_info_got(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||
url = get_url(state["url"])
|
||||
if url:
|
||||
async with GetExcelNotUser(state["user_info"]["班级"], url) as res:
|
||||
await push_user_info.finish(res.text())
|
||||
|
||||
|
||||
def set_url(matcher):
|
||||
@matcher.handle()
|
||||
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||
if await IS_USER(bot, event, state):
|
||||
url = get_url(event.message)
|
||||
if url:
|
||||
state["url"] = url
|
||||
else:
|
||||
await matcher.finish()
|
||||
|
||||
|
||||
# 检查班级信息
|
||||
set_url(check_user)
|
||||
set_url(deep_check_user)
|
||||
set_url(super_check_user)
|
||||
|
||||
|
||||
# 未接受到班级表格时
|
||||
@check_user.got("url", prompt="请发送班级表格")
|
||||
async def _push_user_info_got(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||
url = get_url(state["url"])
|
||||
if url:
|
||||
async with CheckUser(state["user_info"]["班级"], url) as res:
|
||||
res.select_info()
|
||||
await check_user.finish(res.text())
|
||||
|
||||
|
||||
# 未接受到班级表格时
|
||||
@deep_check_user.got("url", prompt="请发送班级表格")
|
||||
async def _push_user_info_got(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||
url = get_url(state["url"])
|
||||
if url:
|
||||
async with CheckUser(state["user_info"]["班级"], url) as res:
|
||||
res.deep_select_info()
|
||||
await deep_check_user.finish(res.text())
|
||||
|
||||
|
||||
# 未接受到班级表格时
|
||||
@super_check_user.got("url", prompt="请发送班级表格")
|
||||
async def _push_user_info_got(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||
url = get_url(state["url"])
|
||||
if url:
|
||||
async with CheckUser(state["user_info"]["班级"], url) as res:
|
||||
res.super_select_info()
|
||||
await super_check_user.finish(res.text())
|
@ -0,0 +1,5 @@
|
||||
from pydantic import BaseSettings
|
||||
|
||||
|
||||
class Config(BaseSettings):
|
||||
user_table = "user_info"
|
@ -0,0 +1,42 @@
|
||||
from nonebot.rule import T_State
|
||||
from nonebot import on_command
|
||||
from nonebot.adapters.cqhttp import Bot, MessageEvent, Message
|
||||
from .data_source import GetDMHY
|
||||
|
||||
|
||||
anime_res = on_command("资源", aliases={"动漫资源"})
|
||||
|
||||
|
||||
@anime_res.handle()
|
||||
async def anime_res_handle(bot: Bot, event: MessageEvent, state: T_State):
|
||||
msg = event.get_plaintext()
|
||||
if msg:
|
||||
state["msg"] = msg
|
||||
|
||||
|
||||
@anime_res.got("msg", prompt="动漫名字叫什么呀!")
|
||||
async def anime_res_got(bot: Bot, event: MessageEvent, state: T_State):
|
||||
msg = event.get_plaintext()
|
||||
if not msg:
|
||||
await anime_res.finish("...")
|
||||
async with GetDMHY(msg) as res:
|
||||
if not res:
|
||||
await anime_res.finish("没有找到你想要的,看看是不是输错了吧!")
|
||||
state["res"] = res
|
||||
types = '\n'.join([f'{i+1}:{v}' for i, v in enumerate(res)])
|
||||
await anime_res.send(f"你需要什么类型的资源:{types}")
|
||||
|
||||
|
||||
@anime_res.got("index")
|
||||
async def anime_res_index(bot: Bot, event: MessageEvent, state: T_State):
|
||||
index = state["index"]
|
||||
if index.isdigit():
|
||||
res: GetDMHY = state["res"]
|
||||
index = int(index)
|
||||
if 0 < index <= res.length:
|
||||
anime = res[res.tags[index-1]][0]
|
||||
await anime_res.finish(f"资源名称:{anime.title}\n{anime.href}")
|
||||
else:
|
||||
await anime_res.finish("有这个序号吗?")
|
||||
else:
|
||||
await anime_res.finish("您输入的是什么呀,让你输入数字呢!")
|
@ -0,0 +1,60 @@
|
||||
from typing import Any, List, Tuple
|
||||
from aiohttp import ClientSession, ClientTimeout
|
||||
from feedparser import parse
|
||||
from pydantic import BaseSettings
|
||||
|
||||
|
||||
class AnimeRes(BaseSettings):
|
||||
def __init__(self, value: dict, **values: Any):
|
||||
super().__init__(**values)
|
||||
self.title = value['title']
|
||||
try:
|
||||
self.href = value["links"][1]['href'].split("&")[0]
|
||||
except KeyError:
|
||||
self.href = None
|
||||
self.tags = [i["term"] for i in value["tags"]]
|
||||
self.tag = value["tags"][0]['term']
|
||||
|
||||
class Config:
|
||||
extra = "allow"
|
||||
|
||||
|
||||
class GetDMHY:
|
||||
main_url = "https://dmhy.anoneko.com/topics/rss/rss.xml"
|
||||
|
||||
def __init__(self, keyword: str):
|
||||
self.params = {"keyword": keyword}
|
||||
|
||||
def classification(self) -> Tuple[dict, list]:
|
||||
values, tags = {}, []
|
||||
for i in self.resources:
|
||||
if i.href:
|
||||
if values.get(i.tag):
|
||||
values[i.tag].append(i)
|
||||
else:
|
||||
values[i.tag] = [i]
|
||||
tags.append(i.tag)
|
||||
return values, tags
|
||||
|
||||
def __getitem__(self, item: str) -> List[AnimeRes]:
|
||||
return self.values.get(item)
|
||||
|
||||
def __iter__(self):
|
||||
return iter(self.tags)
|
||||
|
||||
async def get(self) -> List[AnimeRes]:
|
||||
async with self.session.get(self.main_url, params=self.params) as res:
|
||||
return [AnimeRes(i) for i in parse(await res.text()).get("entries")]
|
||||
|
||||
def __bool__(self):
|
||||
return bool(self.tags)
|
||||
|
||||
async def __aenter__(self):
|
||||
self.session = ClientSession(timeout=ClientTimeout(600))
|
||||
self.resources = await self.get()
|
||||
self.values, self.tags = self.classification()
|
||||
self.length = len(self.tags)
|
||||
return self
|
||||
|
||||
async def __aexit__(self, *args):
|
||||
await self.session.close()
|
@ -0,0 +1,52 @@
|
||||
from nonebot import on_command, on_message
|
||||
from nonebot.permission import SUPERUSER
|
||||
from nonebot.rule import T_State
|
||||
from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent
|
||||
from .config import Config
|
||||
from .data_source import AddChatWord, get_url, BotChat
|
||||
|
||||
|
||||
# export_chat = on_command("导入词库", aliases={"添加词库", "更新词库"})
|
||||
on_chat = on_message(priority=100)
|
||||
chat_ends = ["再见", "不聊了", "结束对话", "拜拜", "bye"]
|
||||
|
||||
|
||||
# @export_chat.handle()
|
||||
# async def export_chat_handle(bot: Bot, event: MessageEvent, state: T_State):
|
||||
# if await SUPERUSER(bot, event):
|
||||
# url = get_url(event.message)
|
||||
# if url:
|
||||
# state["url"] = url
|
||||
# else:
|
||||
# await export_chat.finish()
|
||||
#
|
||||
#
|
||||
# @export_chat.got("url", prompt="请发送在线文档链接或卡片")
|
||||
# async def export_chat_got(bot: Bot, event: MessageEvent, state: T_State):
|
||||
# url = get_url(state["url"])
|
||||
# if url:
|
||||
# async with AddChatWord(url) as res:
|
||||
# await export_chat.finish(res.text())
|
||||
# else:
|
||||
# await export_chat.finish("添加失败!!!")
|
||||
|
||||
|
||||
@on_chat.handle()
|
||||
async def on_chat_handle(bot: Bot, event: MessageEvent, state: T_State):
|
||||
if event.to_me:
|
||||
state["start"] = "开始聊天"
|
||||
else:
|
||||
await on_chat.finish()
|
||||
|
||||
|
||||
@on_chat.got("start")
|
||||
async def on_chat_got(bot: Bot, event: MessageEvent, state: T_State):
|
||||
text = event.get_plaintext()
|
||||
for txt in chat_ends:
|
||||
if txt in text:
|
||||
await on_chat.finish("拜拜!")
|
||||
async with BotChat(text) as res:
|
||||
if isinstance(event, GroupMessageEvent):
|
||||
await on_chat.reject(await res.text())
|
||||
await on_chat.finish(await res.text())
|
||||
|
@ -0,0 +1,8 @@
|
||||
from pydantic import BaseSettings
|
||||
|
||||
|
||||
class Config(BaseSettings):
|
||||
# Your Config Here
|
||||
|
||||
class Config:
|
||||
extra = "ignore"
|
@ -0,0 +1,132 @@
|
||||
from aiohttp import ClientSession
|
||||
from nonebot import require
|
||||
from pandas import DataFrame
|
||||
from nonebot.adapters.cqhttp import Message
|
||||
from json import dumps, loads
|
||||
from random import choice
|
||||
from typing import List
|
||||
|
||||
tools = require("tools")
|
||||
readfile = require("readfile").ReadFile("data", "chatword")
|
||||
base_url = "http://i.itpk.cn/api.php"
|
||||
|
||||
|
||||
def get_params(msg: str):
|
||||
return {
|
||||
"question": msg,
|
||||
"limit": 8,
|
||||
"api_key": "1447d08d8e018247e2ce829e9d0380e8",
|
||||
"api_secret": "p782g4wij4b0"
|
||||
}
|
||||
|
||||
|
||||
GetDocsSheet = tools.GetDocsSheet
|
||||
get_url = tools.get_url
|
||||
bot_chat: dict = {
|
||||
"words": []
|
||||
}
|
||||
|
||||
|
||||
def chat_sorted(words: dict) -> List:
|
||||
return [list(i) for i in sorted(words.items(), key=lambda x: -len(x[0]))]
|
||||
|
||||
|
||||
class AddChatWord:
|
||||
def __init__(self, url: str):
|
||||
self.url = url
|
||||
self.reply = ""
|
||||
|
||||
async def get_sheet(self):
|
||||
"""获取腾讯文档"""
|
||||
async with GetDocsSheet(self.url) as res:
|
||||
return res
|
||||
|
||||
async def __aenter__(self):
|
||||
"""
|
||||
从腾讯文档中获取数据
|
||||
取出转为dafaframe的数据
|
||||
提取词库
|
||||
保存到本地
|
||||
"""
|
||||
self.sheet = await self.get_sheet()
|
||||
self.data: dict = self.sheet.data
|
||||
self.df: DataFrame = self.sheet.data
|
||||
self.words = self.chat_word()
|
||||
await self.save()
|
||||
self.reply = "词库更新成功。"
|
||||
return self
|
||||
|
||||
def chat_word(self):
|
||||
"""
|
||||
提取词库整理成字典
|
||||
再将字典排序转为列表
|
||||
"""
|
||||
words = {word["关键字"]: [txt for txt in word['随机回复词1': "随机回复词20"] if txt] for i, word in self.df.iterrows()}
|
||||
return [list(i) for i in sorted(words.items(), key=lambda x: -len(x[0]))]
|
||||
|
||||
def text(self):
|
||||
return Message(self.reply)
|
||||
|
||||
async def save(self):
|
||||
"""
|
||||
将数据保存到本地
|
||||
"""
|
||||
bot_chat["words"] = self.words
|
||||
await readfile.write("chat_word.json", dumps(self.words))
|
||||
|
||||
async def __aexit__(self, *args):
|
||||
...
|
||||
|
||||
|
||||
class BotChat:
|
||||
def __init__(self, word: str):
|
||||
self.word = word
|
||||
|
||||
@staticmethod
|
||||
async def data_in_msg(msg: str):
|
||||
data = await readfile.read("data.json")
|
||||
for i in data:
|
||||
if i in msg:
|
||||
return choice(data[i])
|
||||
|
||||
@staticmethod
|
||||
async def get_message_reply(msg: str):
|
||||
async with ClientSession() as session:
|
||||
async with session.get(url=base_url, params=get_params(msg)) as resp:
|
||||
try:
|
||||
text = loads((await resp.text()).encode("utf-8"))
|
||||
try:
|
||||
return text["content"]
|
||||
except KeyError:
|
||||
return "抱歉,为对数据进行整理目前无法使用"
|
||||
except ValueError:
|
||||
return await resp.text()
|
||||
|
||||
@staticmethod
|
||||
async def get_words():
|
||||
"""
|
||||
从全局变量中查看是否存在词库
|
||||
如果不存在则从本地取出
|
||||
:return:
|
||||
"""
|
||||
words = bot_chat["words"]
|
||||
if not words:
|
||||
words = loads(await readfile.read("data.json"))
|
||||
bot_chat["words"] = words
|
||||
return words
|
||||
|
||||
async def text(self):
|
||||
for i in [
|
||||
self.data_in_msg,
|
||||
self.get_message_reply
|
||||
]:
|
||||
msg = await i(self.word)
|
||||
if msg:
|
||||
return msg
|
||||
|
||||
async def __aenter__(self):
|
||||
# self.words = await self.get_words()
|
||||
return self
|
||||
|
||||
async def __aexit__(self, *args):
|
||||
...
|
@ -0,0 +1,41 @@
|
||||
from nonebot import get_driver, on_command
|
||||
from aiohttp import ClientSession
|
||||
from nonebot.adapters.cqhttp import Bot, MessageEvent, Message
|
||||
from nonebot.rule import T_State
|
||||
from .config import Config
|
||||
|
||||
covid = on_command("疫情", aliases={"疫情查询"})
|
||||
get_covid = []
|
||||
|
||||
|
||||
@covid.handle()
|
||||
async def covid_handler(bot: Bot, event: MessageEvent, state: T_State):
|
||||
text = event.get_plaintext()
|
||||
if text and event.user_id not in get_covid:
|
||||
state["region"] = text
|
||||
get_covid.append(event.user_id)
|
||||
else:
|
||||
await covid.finish("请勿频繁获取!!!")
|
||||
|
||||
|
||||
@covid.got("region", prompt="请发送地区")
|
||||
async def covid_got(bot: Bot, event: MessageEvent, state: T_State):
|
||||
text = state["region"]
|
||||
await covid.send(Message("正在获取中..."))
|
||||
try:
|
||||
async with ClientSession() as session:
|
||||
async with session.get("https://api.iyk0.com/yq/", params={"msg": text}) as res:
|
||||
data = await res.json()
|
||||
if data["code"] == 200:
|
||||
await covid.send(Message(f'{data["msg"]}\n'
|
||||
f'查询地区:{data["查询地区"]}\n'
|
||||
f'目前确诊:{data["目前确诊"]}\n'
|
||||
f'死亡人数:{data["死亡人数"]}\n'
|
||||
f'治愈人数:{data["治愈人数"]}\n'
|
||||
f'新增确诊:{data["新增确诊"]}\n'
|
||||
f'现存无症状:{data["现存无症状"]}\n'
|
||||
f'更新时间:{data["time"]}'))
|
||||
elif data["code"] == 202:
|
||||
await covid.send(Message(data["msg"]))
|
||||
finally:
|
||||
get_covid.remove(event.user_id)
|
@ -0,0 +1,8 @@
|
||||
from pydantic import BaseSettings
|
||||
|
||||
|
||||
class Config(BaseSettings):
|
||||
# Your Config Here
|
||||
|
||||
class Config:
|
||||
extra = "ignore"
|
@ -0,0 +1,51 @@
|
||||
from nonebot import get_driver, on_command, on_notice
|
||||
from aiohttp import ClientSession
|
||||
from nonebot.adapters.cqhttp import Bot, MessageEvent, Message, PokeNotifyEvent, MessageSegment
|
||||
from nonebot.rule import T_State
|
||||
from .config import Config
|
||||
|
||||
encyclopedia = on_command("百科", aliases={"百科搜索"})
|
||||
echo = on_command("echo")
|
||||
get_covid = []
|
||||
poke = on_notice()
|
||||
|
||||
|
||||
@echo.handle()
|
||||
async def echo_handler(bot: Bot, event: MessageEvent):
|
||||
await echo.finish(event.message)
|
||||
|
||||
|
||||
@poke.handle()
|
||||
async def poke_handle(bot: Bot, event: PokeNotifyEvent, state: T_State):
|
||||
if event.is_tome():
|
||||
await poke.finish("不,不要戳我>_<!!")
|
||||
else:
|
||||
...
|
||||
|
||||
|
||||
@encyclopedia.handle()
|
||||
async def covid_handler(bot: Bot, event: MessageEvent, state: T_State):
|
||||
text = event.get_plaintext()
|
||||
if text and event.user_id not in get_covid:
|
||||
state["region"] = text
|
||||
get_covid.append(event.user_id)
|
||||
else:
|
||||
await encyclopedia.finish("请勿频繁获取!!!")
|
||||
|
||||
|
||||
@encyclopedia.got("region", prompt="请发送搜索内容")
|
||||
async def covid_got(bot: Bot, event: MessageEvent, state: T_State):
|
||||
text = state["region"]
|
||||
await encyclopedia.send(Message("正在获取中..."))
|
||||
try:
|
||||
async with ClientSession() as session:
|
||||
async with session.get("https://api.iyk0.com/sgbk/", params={"msg": text}) as res:
|
||||
data = await res.json()
|
||||
if data["code"] == 200:
|
||||
await encyclopedia.send(Message(f"内容:{data['data']}\n---\n"
|
||||
f"类型:{data['type']}\n---\n"
|
||||
f"更多:{data['more']}"))
|
||||
elif data["code"] == 202:
|
||||
await encyclopedia.send(Message(data["msg"]))
|
||||
finally:
|
||||
get_covid.remove(event.user_id)
|
@ -0,0 +1,8 @@
|
||||
from pydantic import BaseSettings
|
||||
|
||||
|
||||
class Config(BaseSettings):
|
||||
# Your Config Here
|
||||
|
||||
class Config:
|
||||
extra = "ignore"
|
@ -0,0 +1,16 @@
|
||||
# 获取BiliBili用户信息与视频信息插件
|
||||
|
||||
#### 回复消息发送一下几类消息
|
||||
- b站xml卡片
|
||||
- 视频卡片
|
||||
- up主卡片
|
||||
- 聊天消息中包含的关键字
|
||||
- av号
|
||||
- bv号
|
||||
- 视频链接
|
||||
- up主链接
|
||||
- up主名字需要使用命令
|
||||
- up
|
||||
- UP
|
||||
- mid
|
||||
|
@ -0,0 +1,16 @@
|
||||
from pydantic import BaseSettings
|
||||
|
||||
|
||||
class Config(BaseSettings):
|
||||
# 视频信息地址
|
||||
video_info_url = "https://api.bilibili.com/x/web-interface/view"
|
||||
# 用户信息地址
|
||||
user_info_url = "http://api.bilibili.com/x/space/acc/info"
|
||||
# 视频链接
|
||||
video_url = "https://www.bilibili.com/video/"
|
||||
# 用户链接
|
||||
user_url = "https://space.bilibili.com/"
|
||||
# 用户名搜索
|
||||
user_name_search_url = "https://api.bilibili.com/x/web-interface/search/type"
|
||||
# bili直播地址
|
||||
bili_live_url = "https://live.bilibili.com/"
|
@ -0,0 +1,14 @@
|
||||
from nonebot import on_command
|
||||
from nonebot.adapters.cqhttp import Bot, GroupMessageEvent, MessageSegment
|
||||
from nonebot.permission import SUPERUSER
|
||||
from .data_source import Peeping
|
||||
from json import dumps
|
||||
|
||||
peeping = on_command("窥屏", permission=SUPERUSER, block=False, priority=1)
|
||||
|
||||
|
||||
@peeping.handle()
|
||||
async def peeping_handle(bot: Bot, event: GroupMessageEvent):
|
||||
async with Peeping() as res:
|
||||
await peeping.send(MessageSegment.xml(res.get_xml()))
|
||||
await peeping.finish(await res.get_send_msg())
|
@ -0,0 +1,35 @@
|
||||
{
|
||||
"app": "com.tencent.structmsg",
|
||||
"config": {
|
||||
"autosize": true,
|
||||
"ctime": 1636171890,
|
||||
"forward": true,
|
||||
"token": "7264596b2c6ae2063f045293b78db1dc",
|
||||
"type": "normal"
|
||||
},
|
||||
"desc": "新闻",
|
||||
"extra": {
|
||||
"app_type": 1,
|
||||
"appid": 100951776,
|
||||
"msg_seq": 7027304746066715522,
|
||||
"uin": 2711402357
|
||||
},
|
||||
"meta": {
|
||||
"news": {
|
||||
"action": "",
|
||||
"android_pkg_name": "",
|
||||
"app_type": 1,
|
||||
"appid": 100951776,
|
||||
"desc": "你感兴趣的视频都在B站",
|
||||
"jumpUrl": "https://b23.tv/mGMAnD?share_medium=android&share_source=qq&bbid=XX5AE4A57C36D652CA32EB08BA6E8735D8FDF&ts=1636171884331",
|
||||
"preview":"https://open.gtimg.cn/open/app_icon/00/95/17/76/100951776_100_m.png?t=1635933215?date=20211106",
|
||||
"source_icon":"",
|
||||
"source_url":"",
|
||||
"tag":"哔哩哔哩",
|
||||
"title":"MelodyKnit的个人空间"
|
||||
}
|
||||
},
|
||||
"prompt":"[分享]MelodyKnit的个人空间",
|
||||
"ver":"0.0.0.1",
|
||||
"view":"news"
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
from nonebot import on_command
|
||||
from random import choice
|
||||
from nonebot.adapters.cqhttp import Bot, MessageEvent, Message
|
||||
|
||||
on_random = on_command("随机")
|
||||
|
||||
|
||||
@on_random.handle()
|
||||
async def random_handle(bot: Bot, event: MessageEvent, state: dict):
|
||||
params = event.get_plaintext().split()
|
||||
if len(params) > 1:
|
||||
await on_random.finish(Message(choice(params)))
|
||||
|
@ -0,0 +1,3 @@
|
||||
# 天气插件
|
||||
|
||||
命令: 天气
|
@ -0,0 +1,31 @@
|
||||
from nonebot import require, on_command, get_bot, get_driver
|
||||
from .data_source import GetCurrentWeather, config, ToDayWeather
|
||||
from asyncio import sleep
|
||||
from nonebot.adapters.cqhttp import Bot, MessageEvent
|
||||
|
||||
weather = on_command("天气")
|
||||
scheduler = require("nonebot_plugin_apscheduler").scheduler
|
||||
|
||||
|
||||
@weather.handle()
|
||||
async def _(bot: Bot, event: MessageEvent):
|
||||
if not config.loading_weather:
|
||||
await weather.send("正在获取当前天气,请稍后...")
|
||||
async with GetCurrentWeather() as res:
|
||||
await weather.finish(res.text())
|
||||
else:
|
||||
await weather.finish("请勿重复请求天气!")
|
||||
|
||||
|
||||
async def today_weather(bot=None):
|
||||
bot: Bot = get_bot()
|
||||
async with ToDayWeather() as res:
|
||||
text = list(res.text())
|
||||
# for group_id in await res.get_class():
|
||||
# for msg in text:
|
||||
# await sleep(1)
|
||||
# await bot.send_group_msg(group_id=, message=msg)
|
||||
|
||||
# get_driver().on_bot_connect(today_weather)
|
||||
|
||||
scheduler.add_job(today_weather, 'cron', hour=6, minute=0, id='today_weather')
|
@ -0,0 +1,23 @@
|
||||
from pydantic import BaseSettings
|
||||
|
||||
|
||||
class Config(BaseSettings):
|
||||
loading_weather = False
|
||||
|
||||
# 中国天气气象局
|
||||
class CmaWeatherApi:
|
||||
url = "https://weather.cma.cn/api/now/57679"
|
||||
params = {}
|
||||
|
||||
# oppo color 天气
|
||||
class OppoWeatherApi:
|
||||
url = "https://weather.oppomobile.com/dailyForecastAd/v1/00282430113087"
|
||||
params = {
|
||||
"language": "zh-cn",
|
||||
"unit": "c",
|
||||
"appVerCode": "8002026",
|
||||
"appVerName": "8.2.26",
|
||||
"caller": "WEATHER_APP",
|
||||
"frontCode": "2.0",
|
||||
"fromWeatherApp": "true"
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
# 功能插件
|
||||
|
||||
提高代码混淆度
|
||||
|
||||
功能
|
||||
- 数据库操作
|
||||
- permission
|
||||
- rule
|
||||
- 文件读取
|
||||
- 读取和写入数据,方便直接获取文件路径保存文件
|
||||
- 工具箱
|
||||
- 常用爬虫或功能集成
|
@ -0,0 +1,6 @@
|
||||
from nonebot import export
|
||||
from .data_source import MySQLdbMethods
|
||||
|
||||
export = export()
|
||||
|
||||
export.MySQLdbMethods = MySQLdbMethods
|
@ -0,0 +1,40 @@
|
||||
from nonebot import require, export
|
||||
from nonebot.permission import Permission, SUPERUSER
|
||||
from nonebot.adapters.cqhttp import Bot, Event, MessageEvent
|
||||
|
||||
MySQLdbMethods = require("botdb").MySQLdbMethods
|
||||
mysql = MySQLdbMethods()
|
||||
export = export()
|
||||
|
||||
|
||||
async def _teacher(bot: Bot, event: Event):
|
||||
"""分析是否为教师或超级用户,如果是则满足条件"""
|
||||
if event.get_type() == "message":
|
||||
event: MessageEvent
|
||||
user_id = event.get_user_id()
|
||||
# 是否为超级用户
|
||||
if user_id in bot.config.superusers:
|
||||
return True
|
||||
else:
|
||||
# 是否为教师
|
||||
await mysql.execute("select qq from teacher where qq=%s" % event.user_id)
|
||||
return event.user_id in set(mysql.form()["qq"])
|
||||
return False
|
||||
|
||||
|
||||
async def _class_group(bot: Bot, event: Event):
|
||||
if event.get_type() == "message":
|
||||
event: MessageEvent
|
||||
user_id = event.get_user_id()
|
||||
# 是否为超级用户
|
||||
if user_id in bot.config.superusers:
|
||||
return True
|
||||
else:
|
||||
await mysql.execute("select qq from user_info union select qq from teacher")
|
||||
return event.user_id in set(mysql.form()["qq"])
|
||||
return False
|
||||
|
||||
CLASS_GROUP = Permission(_class_group)
|
||||
TEACHER = Permission(_teacher)
|
||||
export.CLASS_GROUP = CLASS_GROUP
|
||||
export.TEACHER = TEACHER
|
@ -0,0 +1,63 @@
|
||||
from aiofile import async_open
|
||||
from nonebot import export
|
||||
from os.path import join, dirname
|
||||
import os
|
||||
|
||||
export = export()
|
||||
|
||||
global_default_path: str = os.getcwd()
|
||||
|
||||
|
||||
def set_path(path):
|
||||
"""设置读取的文件路径"""
|
||||
global global_default_path
|
||||
global_default_path = path
|
||||
|
||||
|
||||
class ReadFile:
|
||||
# 默认路径
|
||||
default_path: str = global_default_path
|
||||
|
||||
def __init__(self, *args: str):
|
||||
"""
|
||||
:param args: 默认路径下的其它文件
|
||||
"""
|
||||
self.path = join(self.default_path, *args)
|
||||
|
||||
async def read(self, file_name, *, mode="r"):
|
||||
async with async_open(join(self.path, file_name), mode=mode) as file:
|
||||
return await file.read()
|
||||
|
||||
async def write(self, file_name, data, *, mode="w", end=True):
|
||||
try:
|
||||
async with async_open(join(self.path, file_name), mode=mode) as file:
|
||||
return await file.write(data)
|
||||
except FileNotFoundError as err:
|
||||
if end:
|
||||
self.mkdir(dirname(file_name))
|
||||
await self.write(file_name, data, mode=mode, end=False)
|
||||
else:
|
||||
raise err
|
||||
|
||||
def listdir(self, *args: str) -> list:
|
||||
return os.listdir(join(self.path, *args))
|
||||
|
||||
def remove(self, *args: str) -> bool:
|
||||
try:
|
||||
os.remove(join(self.path, *args))
|
||||
return True
|
||||
except FileNotFoundError:
|
||||
return False
|
||||
|
||||
def mkdir(self, *args: str) -> bool:
|
||||
try:
|
||||
os.makedirs(join(self.path, *args))
|
||||
return True
|
||||
except FileExistsError:
|
||||
return False
|
||||
|
||||
|
||||
# 设置读取的文件路径
|
||||
export.set_path = set_path
|
||||
export.ReadFile = ReadFile
|
||||
|
@ -0,0 +1,11 @@
|
||||
from pydantic import BaseSettings
|
||||
|
||||
|
||||
class Config(BaseSettings):
|
||||
# Your Config Here
|
||||
dir_name = "src"
|
||||
data_dir_name = "data"
|
||||
config_dir_name = "config"
|
||||
|
||||
class Config:
|
||||
extra = "ignore"
|
@ -0,0 +1,7 @@
|
||||
from pydantic import BaseSettings
|
||||
|
||||
|
||||
class Config(BaseSettings):
|
||||
class_cadre = ["组织委员", "心理委员", "宣传委员", "体育委员", "男生委员",
|
||||
"女生委员", "治保委员", "副班长", "学习委员", "生卫委员",
|
||||
"权益委员", "班长", "团支书"]
|
@ -0,0 +1,32 @@
|
||||
import re
|
||||
from nonebot import export
|
||||
from nonebot.adapters.cqhttp import Message
|
||||
from .data_source import GetDocsSheet
|
||||
from .config import Config
|
||||
from .watermark import Watermark
|
||||
from typing import Union
|
||||
|
||||
|
||||
def re_docs(text: str) -> str:
|
||||
return re.search(r"https://docs.qq.com/sheet/\S[^\"']+", str(text).replace("\\", ""), re.I).group()
|
||||
|
||||
|
||||
def get_url(message: Union[Message, str]) -> str:
|
||||
url = None
|
||||
if isinstance(message, Message):
|
||||
for msg in message:
|
||||
if msg.type == "json" or msg.type == "xml":
|
||||
url = re_docs(msg.data["data"])
|
||||
elif msg.type == "text":
|
||||
url = re_docs(msg.data["text"])
|
||||
if url:
|
||||
return url
|
||||
else:
|
||||
return re_docs(message)
|
||||
|
||||
|
||||
export = export()
|
||||
export.GetDocsSheet = GetDocsSheet
|
||||
export.Watermark = Watermark
|
||||
export.get_url = get_url
|
||||
export.re_docs = re_docs
|
@ -0,0 +1,8 @@
|
||||
from pydantic import BaseSettings
|
||||
|
||||
|
||||
class Config(BaseSettings):
|
||||
# Your Config Here
|
||||
|
||||
class Config:
|
||||
extra = "ignore"
|
@ -0,0 +1,62 @@
|
||||
from typing import Tuple, Union
|
||||
|
||||
from PIL import Image, ImageDraw, ImageFont
|
||||
from PIL.PngImagePlugin import PngImageFile
|
||||
from aiohttp import ClientSession
|
||||
from io import BytesIO
|
||||
|
||||
|
||||
class Watermark:
|
||||
def __init__(self,
|
||||
file: Union[str, bytes] = None,
|
||||
url: str = None,
|
||||
text: str = None,
|
||||
size: int = 50,
|
||||
font: str = "simhei.ttf",
|
||||
xy: Tuple[int, int] = None,
|
||||
fill: Tuple[int, int, int] = None):
|
||||
self.url = url
|
||||
self.file = file
|
||||
self.text = text
|
||||
self.size = size
|
||||
self.font = font
|
||||
self.xy = xy or (0, 0)
|
||||
self.fill = fill or (255, 0, 0)
|
||||
|
||||
async def url_img(self) -> PngImageFile:
|
||||
"""下载图片"""
|
||||
async with ClientSession() as session:
|
||||
async with session.get(self.url) as res:
|
||||
return Image.open(BytesIO(await res.read()))
|
||||
|
||||
def byte_img(self) -> PngImageFile:
|
||||
"""数据流"""
|
||||
return Image.open(BytesIO(self.file))
|
||||
|
||||
def local_img(self):
|
||||
"""本地图片"""
|
||||
return Image.open(self.file)
|
||||
|
||||
def draw(self, img: PngImageFile = None) -> PngImageFile:
|
||||
"""绘制"""
|
||||
img = self.img
|
||||
draw = ImageDraw.Draw(img)
|
||||
draw.text(xy=self.xy, text=self.text, fill=self.fill,
|
||||
font=ImageFont.truetype(font=self.font, size=self.size))
|
||||
return img
|
||||
|
||||
async def __aenter__(self):
|
||||
if self.file:
|
||||
if isinstance(self.file, bytes):
|
||||
self.img = self.byte_img()
|
||||
else:
|
||||
self.img = self.local_img()
|
||||
elif self.url:
|
||||
self.img = await self.url_img()
|
||||
else:
|
||||
raise TypeError("String or Bytes")
|
||||
self.draw()
|
||||
return self
|
||||
|
||||
async def __aexit__(self, *args):
|
||||
...
|
Loading…
Reference in new issue