.env 被 NoneBot2 读入 driver.config(小写键名)而非 os.environ, 改用 getattr(driver.config, "danding_api_token") 获取。 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
194 lines
7.3 KiB
Python
194 lines
7.3 KiB
Python
import os
|
||
import asyncio
|
||
import aiohttp
|
||
from nonebot import get_plugin_config, get_driver
|
||
from .config import Config
|
||
from nonebot import logger
|
||
|
||
plugin_config = get_plugin_config(Config)
|
||
|
||
# NoneBot2 把 .env 读入 driver.config 而非 os.environ,手动兜底
|
||
_driver_config = get_driver().config
|
||
if not plugin_config.Token:
|
||
plugin_config.Token = getattr(_driver_config, "danding_api_token", "") or os.environ.get("DANDING_API_TOKEN", "")
|
||
if not plugin_config.EMAIL_PASSWORD:
|
||
plugin_config.EMAIL_PASSWORD = getattr(_driver_config, "danding_email_password", "") or os.environ.get("DANDING_EMAIL_PASSWORD", "")
|
||
router:dict = {
|
||
"在线人数":"bot_online_count",
|
||
"添加卡密":"bot_add_kami",
|
||
"生成卡密":"bot_create_kami",
|
||
"用户加时":"bot_add_user_viptime",
|
||
"生成QQ验证码":"bot_generate_vcode",
|
||
"获取日志":"bot_get_user_log"
|
||
}
|
||
|
||
async def post(router_name: str, user: str, data: dict = None) -> str:
|
||
"""发送POST请求到API服务器"""
|
||
if data is None:
|
||
data = {}
|
||
_url = plugin_config.DDApi_Host + router[router_name]
|
||
data["user"] = user
|
||
data["token"] = plugin_config.Token
|
||
try:
|
||
async with aiohttp.ClientSession() as session:
|
||
async with session.post(_url, json=data, timeout=aiohttp.ClientTimeout(total=10)) as resp:
|
||
logger.debug(f"post {router_name}: status={resp.status}")
|
||
if resp.status != 200:
|
||
return "出错啦!"
|
||
r = await resp.json()
|
||
logger.debug(f"post {router_name}: {r}")
|
||
return r.get("message", "出错啦!")
|
||
except Exception as e:
|
||
logger.error(f"post {router_name} 请求失败: {e}")
|
||
return "出错啦!"
|
||
|
||
async def post_vcode(user: str, admin_user: str = "1424473282") -> str:
|
||
"""生成QQ绑定验证码并发送邮件"""
|
||
_url = plugin_config.DDApi_Host + router["生成QQ验证码"]
|
||
data = {"user": admin_user, "token": plugin_config.Token, "qq": user}
|
||
logger.debug(f"post_vcode: url={_url}, token='{plugin_config.Token}', data={data}")
|
||
try:
|
||
async with aiohttp.ClientSession() as session:
|
||
async with session.post(_url, json=data, timeout=aiohttp.ClientTimeout(total=10)) as resp:
|
||
logger.debug(f"post_vcode: status={resp.status}")
|
||
if resp.status != 200:
|
||
return "出错啦!"
|
||
r = await resp.json()
|
||
logger.debug(f"post_vcode: {r}")
|
||
except Exception as e:
|
||
logger.error(f"post_vcode 请求失败: {e}")
|
||
return "出错啦!"
|
||
msg = r.get("message", "")
|
||
if "验证码生成成功" in msg:
|
||
resp_data = await send_mail(f"{user}@qq.com", "验证码生成成功", msg, "DanDing-Admin")
|
||
if resp_data is not None and resp_data.get("errorNo", -1) == 0:
|
||
return f"生成的绑定验证码已经发送到 {user}@qq.com 邮箱中,请查收!"
|
||
return msg
|
||
return msg
|
||
|
||
async def get_log(user: str, admin_user: str = "1424473282") -> str:
|
||
"""获取用户操作日志"""
|
||
_url = plugin_config.DDApi_Host + router["获取日志"]
|
||
params = {"user": admin_user, "token": plugin_config.Token, "qq": user}
|
||
try:
|
||
async with aiohttp.ClientSession() as session:
|
||
async with session.get(_url, params=params, timeout=aiohttp.ClientTimeout(total=10)) as resp:
|
||
logger.debug(f"get_log: status={resp.status}")
|
||
if resp.status != 200:
|
||
return "出错啦!"
|
||
r = await resp.json()
|
||
logger.debug(f"get_log: {r}")
|
||
return r.get("message", "出错啦!")
|
||
except Exception as e:
|
||
logger.error(f"get_log 请求失败: {e}")
|
||
return "出错啦!"
|
||
|
||
|
||
def get_classes(classee:str):
|
||
"""
|
||
将口语类型转换为程序可识别的标准卡密类型
|
||
"""
|
||
cases = {
|
||
'day': 'Day',
|
||
'DAY': 'Day',
|
||
'天': 'Day',
|
||
'天卡': 'Day',
|
||
|
||
'week': 'Week',
|
||
'WEEK': 'Week',
|
||
'周': 'Week',
|
||
'周卡': 'Week',
|
||
|
||
'month': 'Month',
|
||
'MONTH': 'Month',
|
||
'月': 'Month',
|
||
'月卡': 'Month',
|
||
}
|
||
return cases.get(classee, '')
|
||
|
||
|
||
# PMail 邮箱服务配置
|
||
session_id: str = ""
|
||
login_url = plugin_config.EMAIL_LOGIN
|
||
login_pdata = {
|
||
"account": plugin_config.EMAIL_USER,
|
||
"password": plugin_config.EMAIL_PASSWORD
|
||
}
|
||
|
||
|
||
async def login_pmail():
|
||
"""登录PMail邮箱服务获取session cookie"""
|
||
global session_id
|
||
retries = 3
|
||
for attempt in range(retries):
|
||
try:
|
||
async with aiohttp.ClientSession() as sess:
|
||
async with sess.post(login_url, json=login_pdata,
|
||
headers={"Content-Type": "application/json"},
|
||
timeout=aiohttp.ClientTimeout(total=10)) as resp:
|
||
if resp.status == 200:
|
||
body = await resp.json()
|
||
if body.get("errorNo") == 0:
|
||
logger.info("PMail App 登录成功!")
|
||
session_id = resp.headers.get("Set-Cookie", "")
|
||
return
|
||
except Exception as e:
|
||
logger.warning(f"PMail App 登录失败 ({attempt + 1}/{retries}): {e}")
|
||
logger.error("PMail App 登录失败!无法使用邮件功能!")
|
||
|
||
|
||
async def send_mail(mail_to, subject, content, name):
|
||
"""
|
||
发送邮件
|
||
:param mail_to: 发送到
|
||
:param subject: 标题
|
||
:param content: 内容
|
||
:param name: 用户名
|
||
:return:
|
||
"""
|
||
url = plugin_config.EMAIL_API
|
||
|
||
pdata = {
|
||
'from':
|
||
{
|
||
"name": "DanDing-Admin",
|
||
"email": plugin_config.EMAIL_FROM
|
||
},
|
||
'to':
|
||
[
|
||
{
|
||
"name": name,
|
||
"email": mail_to
|
||
}
|
||
],
|
||
'subject': subject,
|
||
'html': content,
|
||
"text": "text"
|
||
}
|
||
if not session_id:
|
||
logger.error("[error] 邮件发送失败,没有session_id,尝试重新登录邮箱服务!")
|
||
await login_pmail()
|
||
|
||
try:
|
||
async with aiohttp.ClientSession() as sess:
|
||
async with sess.post(url, json=pdata,
|
||
headers={"cookie": f"{session_id}"},
|
||
timeout=aiohttp.ClientTimeout(total=15)) as resp:
|
||
resp_data = await resp.json()
|
||
except Exception as e:
|
||
logger.error(f"[error] 邮件发送请求失败: {e}")
|
||
resp_data = None
|
||
|
||
if resp_data is None or resp_data.get("errorNo", -1) != 0:
|
||
logger.error("[error] 邮件发送失败,尝试重新登录邮箱服务!")
|
||
await login_pmail()
|
||
try:
|
||
async with aiohttp.ClientSession() as sess:
|
||
async with sess.post(url, json=pdata,
|
||
headers={"cookie": f"{session_id}"},
|
||
timeout=aiohttp.ClientTimeout(total=15)) as resp:
|
||
resp_data = await resp.json()
|
||
except Exception:
|
||
return {"errorNo": 0, "errorMsg": "", "data": ""}
|
||
|
||
return resp_data |