🐛 修复迁移旧版数据库失败的BUG
This commit is contained in:
parent
cca3dc5d4d
commit
c131692b19
@ -37,7 +37,7 @@ __plugin_meta__ = PluginMetadata(
|
|||||||
""".strip(),
|
""".strip(),
|
||||||
extra=PluginExtraData(
|
extra=PluginExtraData(
|
||||||
author="Art_Sakura",
|
author="Art_Sakura",
|
||||||
version="1.3",
|
version="1.4",
|
||||||
commands=[Command(command="我的农场")],
|
commands=[Command(command="我的农场")],
|
||||||
menu_type="群内小游戏",
|
menu_type="群内小游戏",
|
||||||
configs=[
|
configs=[
|
||||||
@ -82,6 +82,8 @@ async def start():
|
|||||||
|
|
||||||
await g_pDBService.init()
|
await g_pDBService.init()
|
||||||
|
|
||||||
|
# await g_pRequestManager.initSignInFile()
|
||||||
|
|
||||||
# 析构函数
|
# 析构函数
|
||||||
@driver.on_shutdown
|
@driver.on_shutdown
|
||||||
async def shutdown():
|
async def shutdown():
|
||||||
|
|||||||
38
command.py
38
command.py
@ -1,3 +1,5 @@
|
|||||||
|
from datetime import date, datetime, timedelta
|
||||||
|
|
||||||
from nonebot.adapters import Event, MessageTemplate
|
from nonebot.adapters import Event, MessageTemplate
|
||||||
from nonebot.rule import to_me
|
from nonebot.rule import to_me
|
||||||
from nonebot_plugin_alconna import (Alconna, AlconnaMatch, AlconnaQuery, Args,
|
from nonebot_plugin_alconna import (Alconna, AlconnaMatch, AlconnaQuery, Args,
|
||||||
@ -133,7 +135,8 @@ diuse_farm = on_alconna(
|
|||||||
Subcommand("stealing", Args["target?", At], help_text="偷菜"),
|
Subcommand("stealing", Args["target?", At], help_text="偷菜"),
|
||||||
Subcommand("buy-point", Args["num?", int], help_text="购买农场币"),
|
Subcommand("buy-point", Args["num?", int], help_text="购买农场币"),
|
||||||
#Subcommand("sell-point", Args["num?", int], help_text="转换金币")
|
#Subcommand("sell-point", Args["num?", int], help_text="转换金币")
|
||||||
Subcommand("change-name", Args["name?", str], help_text="更改农场名")
|
Subcommand("change-name", Args["name?", str], help_text="更改农场名"),
|
||||||
|
Subcommand("sing-in", help_text="农场签到"),
|
||||||
),
|
),
|
||||||
priority=5,
|
priority=5,
|
||||||
block=True,
|
block=True,
|
||||||
@ -165,10 +168,7 @@ async def _(session: Uninfo):
|
|||||||
|
|
||||||
info = await g_pFarmManager.drawDetailFarmByUid(uid)
|
info = await g_pFarmManager.drawDetailFarmByUid(uid)
|
||||||
|
|
||||||
a = await MessageUtils.alc_forward_msg(info, session.self_id, BotConfig.self_nickname).send(reply_to=True)
|
await MessageUtils.alc_forward_msg([info], session.self_id, BotConfig.self_nickname).send(reply_to=True)
|
||||||
|
|
||||||
logger.info(f"{a}")
|
|
||||||
|
|
||||||
|
|
||||||
diuse_farm.shortcut(
|
diuse_farm.shortcut(
|
||||||
"我的农场币",
|
"我的农场币",
|
||||||
@ -445,3 +445,31 @@ async def _(session: Uninfo, name: Match[str]):
|
|||||||
await MessageUtils.build_message("更新用户名成功!").send(reply_to=True)
|
await MessageUtils.build_message("更新用户名成功!").send(reply_to=True)
|
||||||
else:
|
else:
|
||||||
await MessageUtils.build_message("更新用户名失败!").send(reply_to=True)
|
await MessageUtils.build_message("更新用户名失败!").send(reply_to=True)
|
||||||
|
|
||||||
|
reclamation = on_alconna(
|
||||||
|
Alconna("农场签到"),
|
||||||
|
priority=5,
|
||||||
|
block=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
@reclamation.handle()
|
||||||
|
async def _(session: Uninfo):
|
||||||
|
uid = str(session.user.id)
|
||||||
|
|
||||||
|
if await isRegisteredByUid(uid) == False:
|
||||||
|
return
|
||||||
|
|
||||||
|
toDay = date.today()
|
||||||
|
|
||||||
|
message = ""
|
||||||
|
status = await g_pDBService.userSign.sign(uid, toDay.strftime("%Y-%m-%d"))
|
||||||
|
|
||||||
|
if status == True:
|
||||||
|
message = "签到成功"
|
||||||
|
|
||||||
|
|
||||||
|
img = await g_pDBService.userSign.drawSignCalendarImage(uid, toDay.year, toDay.month)
|
||||||
|
|
||||||
|
await MessageUtils.build_message(img).send()
|
||||||
|
|
||||||
|
# await MessageUtils.alc_forward_msg([info], session.self_id, BotConfig.self_nickname).send(reply_to=True)
|
||||||
|
|||||||
@ -7,3 +7,6 @@ g_sDBFilePath = DATA_PATH / "farm_db/farm.db"
|
|||||||
|
|
||||||
g_sResourcePath = Path(__file__).resolve().parent / "resource"
|
g_sResourcePath = Path(__file__).resolve().parent / "resource"
|
||||||
g_sPlantPath = g_sResourcePath / "db/plant.db"
|
g_sPlantPath = g_sResourcePath / "db/plant.db"
|
||||||
|
|
||||||
|
g_sConfigPath = Path(__file__).resolve().parent / "config"
|
||||||
|
g_sSignInPath = g_sConfigPath / "sign_in.json"
|
||||||
|
|||||||
@ -1,31 +0,0 @@
|
|||||||
{
|
|
||||||
"date": "202505",
|
|
||||||
"point_max": 5000,
|
|
||||||
"point_min": 200,
|
|
||||||
"continuou":
|
|
||||||
{
|
|
||||||
"1":
|
|
||||||
{
|
|
||||||
"point": 5000,
|
|
||||||
"exp": 20
|
|
||||||
},
|
|
||||||
"3":
|
|
||||||
{
|
|
||||||
"point": 7000,
|
|
||||||
"exp": 25,
|
|
||||||
"plant":
|
|
||||||
{
|
|
||||||
"胡萝卜": 3
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"5":
|
|
||||||
{
|
|
||||||
"point": 9000,
|
|
||||||
"exp": 50,
|
|
||||||
"plant":
|
|
||||||
{
|
|
||||||
"胡萝卜": 3
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -11,21 +11,14 @@ class CUserDB(CSqlManager):
|
|||||||
@classmethod
|
@classmethod
|
||||||
async def initDB(cls):
|
async def initDB(cls):
|
||||||
"""初始化用户表结构,确保user表存在且字段完整"""
|
"""初始化用户表结构,确保user表存在且字段完整"""
|
||||||
#uid: 用户Uid
|
|
||||||
#name: 农场名称
|
|
||||||
#exp: 经验值
|
|
||||||
#point: 金币
|
|
||||||
#soil: 解锁土地数量
|
|
||||||
#stealTime: 偷菜时间字符串
|
|
||||||
#stealCount: 剩余偷菜次数
|
|
||||||
userInfo = {
|
userInfo = {
|
||||||
"uid": "INTEGER PRIMARY KEY AUTOINCREMENT",
|
"uid": "TEXT PRIMARY KEY", #用户Uid
|
||||||
"name": "TEXT NOT NULL",
|
"name": "TEXT NOT NULL", #农场名称
|
||||||
"exp": "INTEGER DEFAULT 0",
|
"exp": "INTEGER DEFAULT 0", #经验值
|
||||||
"point": "INTEGER DEFAULT 0",
|
"point": "INTEGER DEFAULT 0", #金币
|
||||||
"soil": "INTEGER DEFAULT 3",
|
"soil": "INTEGER DEFAULT 3", #解锁土地数量
|
||||||
"stealTime": "TEXT DEFAULT NULL",
|
"stealTime": "TEXT DEFAULT NULL", #偷菜时间字符串
|
||||||
"stealCount": "INTEGER DEFAULT 0"
|
"stealCount": "INTEGER DEFAULT 0" #剩余偷菜次数
|
||||||
}
|
}
|
||||||
await cls.ensureTableSchema("user", userInfo)
|
await cls.ensureTableSchema("user", userInfo)
|
||||||
|
|
||||||
|
|||||||
@ -8,13 +8,10 @@ from .database import CSqlManager
|
|||||||
class CUserItemDB(CSqlManager):
|
class CUserItemDB(CSqlManager):
|
||||||
@classmethod
|
@classmethod
|
||||||
async def initDB(cls):
|
async def initDB(cls):
|
||||||
#用户Uid
|
|
||||||
#物品名称
|
|
||||||
#数量
|
|
||||||
userItem = {
|
userItem = {
|
||||||
"uid": "INTEGER NOT NULL",
|
"uid": "TEXT NOT NULL", #用户Uid
|
||||||
"item": "TEXT NOT NULL",
|
"item": "TEXT NOT NULL", #物品名称
|
||||||
"count": "INTEGER NOT NULL DEFAULT 0",
|
"count": "INTEGER NOT NULL DEFAULT 0", #数量
|
||||||
"PRIMARY KEY": "(uid, item)"
|
"PRIMARY KEY": "(uid, item)"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -8,13 +8,10 @@ from .database import CSqlManager
|
|||||||
class CUserPlantDB(CSqlManager):
|
class CUserPlantDB(CSqlManager):
|
||||||
@classmethod
|
@classmethod
|
||||||
async def initDB(cls):
|
async def initDB(cls):
|
||||||
#用户UiD
|
|
||||||
#作物名称
|
|
||||||
#数量
|
|
||||||
userPlant = {
|
userPlant = {
|
||||||
"uid": "INTEGER NOT NULL",
|
"uid": "TEXT NOT NULL", #用户Uid
|
||||||
"plant": "TEXT NOT NULL",
|
"plant": "TEXT NOT NULL", #作物名称
|
||||||
"count": "INTEGER NOT NULL DEFAULT 0",
|
"count": "INTEGER NOT NULL DEFAULT 0", #数量
|
||||||
"PRIMARY KEY": "(uid, plant)"
|
"PRIMARY KEY": "(uid, plant)"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -8,13 +8,10 @@ from .database import CSqlManager
|
|||||||
class CUserSeedDB(CSqlManager):
|
class CUserSeedDB(CSqlManager):
|
||||||
@classmethod
|
@classmethod
|
||||||
async def initDB(cls):
|
async def initDB(cls):
|
||||||
#用户Uid
|
|
||||||
#种子名称
|
|
||||||
#数量
|
|
||||||
userSeed = {
|
userSeed = {
|
||||||
"uid": "INTEGER NOT NULL",
|
"uid": "TEXT NOT NULL", #用户Uid
|
||||||
"seed": "TEXT NOT NULL",
|
"seed": "TEXT NOT NULL", #种子名称
|
||||||
"count": "INTEGER NOT NULL DEFAULT 0",
|
"count": "INTEGER NOT NULL DEFAULT 0", #数量
|
||||||
"PRIMARY KEY": "(uid, seed)"
|
"PRIMARY KEY": "(uid, seed)"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
174
database/userSign.py
Normal file
174
database/userSign.py
Normal file
@ -0,0 +1,174 @@
|
|||||||
|
import calendar
|
||||||
|
from datetime import date, datetime, timedelta
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
from zhenxun.services.log import logger
|
||||||
|
from zhenxun.utils._build_image import BuildImage
|
||||||
|
|
||||||
|
from ..dbService import g_pDBService
|
||||||
|
from ..json import g_pJsonManager
|
||||||
|
from .database import CSqlManager
|
||||||
|
|
||||||
|
|
||||||
|
class CUserSignDB(CSqlManager):
|
||||||
|
@classmethod
|
||||||
|
async def initDB(cls):
|
||||||
|
#userSignLog 表结构,每条为一次签到事件
|
||||||
|
userSignLog = {
|
||||||
|
"uid": "TEXT NOT NULL", #用户ID
|
||||||
|
"signDate": "DATE NOT NULL", #签到日期
|
||||||
|
"isSupplement": "TINYINT NOT NULL DEFAULT 0", #是否补签
|
||||||
|
"rewardType": "VARCHAR(20) DEFAULT ''", #奖励类型
|
||||||
|
"createdAt": "DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP", #创建时间
|
||||||
|
"PRIMARY KEY": "(uid, signDate)"
|
||||||
|
}
|
||||||
|
|
||||||
|
#userSignSummary 表结构,每用户一行用于缓存签到状态
|
||||||
|
userSignSummary = {
|
||||||
|
"uid": "TEXT PRIMARY KEY NOT NULL", #用户ID
|
||||||
|
"totalSignDays": "INT NOT NULL DEFAULT 0", #累计签到天数
|
||||||
|
"currentMonth": "CHAR(7) NOT NULL DEFAULT ''", #当前月份(如2025-05)
|
||||||
|
"monthSignDays": "INT NOT NULL DEFAULT 0", #本月签到次数
|
||||||
|
"lastSignDate": "DATE DEFAULT NULL", #上次签到日期
|
||||||
|
"continuousDays": "INT NOT NULL DEFAULT 0", #连续签到天数
|
||||||
|
"supplementCount": "INT NOT NULL DEFAULT 0", #补签次数
|
||||||
|
"updatedAt": "DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP", #更新时间
|
||||||
|
}
|
||||||
|
|
||||||
|
await cls.ensureTableSchema("userSignLog", userSignLog)
|
||||||
|
await cls.ensureTableSchema("userSignSummary", userSignSummary)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
async def getUserSignCountByDate(cls, uid: str, monthStr: str) -> int:
|
||||||
|
"""
|
||||||
|
|
||||||
|
Args:
|
||||||
|
uid (str): 用户Uid
|
||||||
|
monthStr (str): 需要查询的日期 示例: 2025-05
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
int: _description_
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
sql = "SELECT COUNT(*) FROM userSignLog WHERE uid=? AND signDate LIKE ?"
|
||||||
|
param = f"{monthStr}-%"
|
||||||
|
async with cls.m_pDB.execute(sql, (uid, param)) as cursor:
|
||||||
|
row = await cursor.fetchone()
|
||||||
|
return row[0] if row else 0
|
||||||
|
except Exception as e:
|
||||||
|
logger.warning("统计用户月签到次数失败", e=e)
|
||||||
|
return 0
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
async def hasSigned(cls, uid: str, signDate: str) -> bool:
|
||||||
|
"""判断指定日期是否已签到
|
||||||
|
|
||||||
|
Args:
|
||||||
|
uid (int): 用户ID
|
||||||
|
signDate (str): 日期字符串 'YYYY-MM-DD'
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: True=已签到,False=未签到
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
sql = "SELECT 1 FROM userSignLog WHERE uid=? AND signDate=? LIMIT 1"
|
||||||
|
async with cls.m_pDB.execute(sql, (uid, signDate)) as cursor:
|
||||||
|
row = await cursor.fetchone()
|
||||||
|
return row is not None
|
||||||
|
except Exception as e:
|
||||||
|
logger.warning("查询是否已签到失败", e=e)
|
||||||
|
return False
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
async def sign(cls, uid: str, signDate: str = '') -> bool:
|
||||||
|
try:
|
||||||
|
if not signDate:
|
||||||
|
signDate = date.today().strftime("%Y-%m-%d")
|
||||||
|
|
||||||
|
if await cls.hasSigned(uid, signDate):
|
||||||
|
return False
|
||||||
|
|
||||||
|
todayStr = date.today().strftime("%Y-%m-%d")
|
||||||
|
isSupplement = 0 if signDate == todayStr else 1
|
||||||
|
|
||||||
|
async with cls._transaction():
|
||||||
|
await cls.m_pDB.execute(
|
||||||
|
"INSERT INTO userSignLog (uid, signDate, isSupplement, rewardType) VALUES (?, ?, ?, '')",
|
||||||
|
(uid, signDate, isSupplement)
|
||||||
|
)
|
||||||
|
|
||||||
|
cursor = await cls.m_pDB.execute("SELECT * FROM userSignSummary WHERE uid=?", (uid,))
|
||||||
|
row = await cursor.fetchone()
|
||||||
|
|
||||||
|
currentMonth = signDate[:7]
|
||||||
|
if row:
|
||||||
|
monthSignDays = row['monthSignDays'] + 1 if row['currentMonth'] == currentMonth else 1
|
||||||
|
lastDate = row['lastSignDate']
|
||||||
|
prevDate = (datetime.strptime(signDate, "%Y-%m-%d") - timedelta(days=1)).strftime("%Y-%m-%d")
|
||||||
|
continuousDays = row['continuousDays'] + 1 if lastDate == prevDate else 1
|
||||||
|
supplementCount = row['supplementCount'] + 1 if isSupplement else row['supplementCount']
|
||||||
|
await cls.m_pDB.execute(
|
||||||
|
"""
|
||||||
|
UPDATE userSignSummary
|
||||||
|
SET totalSignDays=totalSignDays+1,
|
||||||
|
currentMonth=?,
|
||||||
|
monthSignDays=?,
|
||||||
|
lastSignDate=?,
|
||||||
|
continuousDays=?,
|
||||||
|
supplementCount=?
|
||||||
|
WHERE uid=?
|
||||||
|
""",
|
||||||
|
(currentMonth, monthSignDays, signDate, continuousDays, supplementCount, uid)
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
await cls.m_pDB.execute(
|
||||||
|
"""
|
||||||
|
INSERT INTO userSignSummary
|
||||||
|
(uid, totalSignDays, currentMonth, monthSignDays, lastSignDate, continuousDays, supplementCount)
|
||||||
|
VALUES (?, ?, ?, ?, ?, ?, ?)
|
||||||
|
""",
|
||||||
|
(uid, 1, currentMonth, 1, signDate, 1, 1 if isSupplement else 0)
|
||||||
|
)
|
||||||
|
return True
|
||||||
|
except Exception as e:
|
||||||
|
logger.warning("执行签到失败", e=e)
|
||||||
|
return False
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
async def drawSignCalendarImage(cls, uid: str, year: int, month: int):
|
||||||
|
#绘制签到图,自动提取数据库中该用户该月的签到天数
|
||||||
|
cellSize = 80
|
||||||
|
padding = 40
|
||||||
|
titleHeight = 80
|
||||||
|
cols = 7
|
||||||
|
rows = 6
|
||||||
|
width = cellSize * cols + padding * 2
|
||||||
|
height = cellSize * rows + padding * 2 + titleHeight
|
||||||
|
|
||||||
|
img = BuildImage(width, height, color=(255, 255, 255))
|
||||||
|
await img.text((padding, 20), f"{year}年{month}月签到表", font_size=36)
|
||||||
|
|
||||||
|
firstWeekday, totalDays = calendar.monthrange(year, month)
|
||||||
|
monthStr = f"{year:04d}-{month:02d}"
|
||||||
|
try:
|
||||||
|
sql = "SELECT signDate FROM userSignLog WHERE uid=? AND signDate LIKE ?"
|
||||||
|
async with cls.m_pDB.execute(sql, (uid, f"{monthStr}-%")) as cursor:
|
||||||
|
rows = await cursor.fetchall()
|
||||||
|
signedDays = set(int(r[0][-2:]) for r in rows if r[0][-2:].isdigit())
|
||||||
|
except Exception as e:
|
||||||
|
logger.warning("绘制签到图时数据库查询失败", e=e)
|
||||||
|
signedDays = set()
|
||||||
|
|
||||||
|
for day in range(1, totalDays + 1):
|
||||||
|
index = day + firstWeekday - 1
|
||||||
|
row = index // cols
|
||||||
|
col = index % cols
|
||||||
|
x1 = padding + col * cellSize
|
||||||
|
y1 = padding + titleHeight + row * cellSize
|
||||||
|
x2 = x1 + cellSize - 10
|
||||||
|
y2 = y1 + cellSize - 10
|
||||||
|
color = (112, 196, 112) if day in signedDays else (220, 220, 220)
|
||||||
|
await img.rectangle((x1, y1, x2, y2), fill=color, outline="black", width=2)
|
||||||
|
await img.text((x1 + 10, y1 + 10), str(day), font_size=24)
|
||||||
|
|
||||||
|
return img
|
||||||
@ -11,31 +11,19 @@ from .database import CSqlManager
|
|||||||
class CUserSoilDB(CSqlManager):
|
class CUserSoilDB(CSqlManager):
|
||||||
@classmethod
|
@classmethod
|
||||||
async def initDB(cls):
|
async def initDB(cls):
|
||||||
#uid: 用户Uid
|
|
||||||
#soilIndex: 地块索引从1开始
|
|
||||||
#plantName: 作物名称
|
|
||||||
#plantTime: 播种时间
|
|
||||||
#matureTime: 成熟时间
|
|
||||||
#soilLevel: 土地等级 0=普通地,1=红土地,2=黑土地,3=金土地
|
|
||||||
#wiltStatus: 枯萎状态 0=未枯萎,1=枯萎
|
|
||||||
#fertilizerStatus: 施肥状态 0=未施肥,1=施肥 2=增肥
|
|
||||||
#bugStatus: 虫害状态 0=无虫害,1=有虫害
|
|
||||||
#weedStatus: 杂草状态 0=无杂草,1=有杂草
|
|
||||||
#waterStatus: 缺水状态 0=不缺水,1=缺水
|
|
||||||
#harvestCount: 收获次数
|
|
||||||
userSoil = {
|
userSoil = {
|
||||||
"uid": "TEXT NOT NULL",
|
"uid": "TEXT NOT NULL",
|
||||||
"soilIndex": "INTEGER NOT NULL",
|
"soilIndex": "INTEGER NOT NULL", #地块索引从1开始
|
||||||
"plantName": "TEXT DEFAULT ''",
|
"plantName": "TEXT DEFAULT ''", #作物名称
|
||||||
"plantTime": "INTEGER DEFAULT 0",
|
"plantTime": "INTEGER DEFAULT 0", #播种时间
|
||||||
"matureTime": "INTEGER DEFAULT 0",
|
"matureTime": "INTEGER DEFAULT 0", #成熟时间
|
||||||
"soilLevel": "INTEGER DEFAULT 0",
|
"soilLevel": "INTEGER DEFAULT 0", #土地等级 0=普通地,1=红土地,2=黑土地,3=金土地
|
||||||
"wiltStatus": "INTEGER DEFAULT 0",
|
"wiltStatus": "INTEGER DEFAULT 0", #枯萎状态 0=未枯萎,1=枯萎
|
||||||
"fertilizerStatus": "INTEGER DEFAULT 0",
|
"fertilizerStatus": "INTEGER DEFAULT 0",#施肥状态 0=未施肥,1=施肥 2=增肥
|
||||||
"bugStatus": "INTEGER DEFAULT 0",
|
"bugStatus": "INTEGER DEFAULT 0", #虫害状态 0=无虫害,1=有虫害
|
||||||
"weedStatus": "INTEGER DEFAULT 0",
|
"weedStatus": "INTEGER DEFAULT 0", #杂草状态 0=无杂草,1=有杂草
|
||||||
"waterStatus": "INTEGER DEFAULT 0",
|
"waterStatus": "INTEGER DEFAULT 0", #缺水状态 0=不缺水,1=缺水
|
||||||
"harvestCount": "INTEGER DEFAULT 0",
|
"harvestCount": "INTEGER DEFAULT 0", #收获次数
|
||||||
"PRIMARY KEY": "(uid, soilIndex)",
|
"PRIMARY KEY": "(uid, soilIndex)",
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -93,13 +81,15 @@ class CUserSoilDB(CSqlManager):
|
|||||||
await cls.m_pDB.execute(
|
await cls.m_pDB.execute(
|
||||||
"""
|
"""
|
||||||
INSERT INTO userSoil
|
INSERT INTO userSoil
|
||||||
(uid,soilIndex,plantName,plantTime,matureTime,harvestCount,)
|
(uid,soilIndex,plantName,plantTime,matureTime,harvestCount)
|
||||||
VALUES (?,?,?,?,?,?)
|
VALUES (?,?,?,?,?,?)
|
||||||
""",
|
""",
|
||||||
(uid, i, name, pt, mt, 0),
|
(uid, i, name, pt, mt, 0),
|
||||||
)
|
)
|
||||||
|
|
||||||
await cls.m_pDB.execute("DROP TABLE soil")
|
await cls.m_pDB.execute("DROP TABLE soil")
|
||||||
|
|
||||||
|
logger.info("数据库迁移完毕!")
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
|||||||
@ -6,17 +6,12 @@ from .database import CSqlManager
|
|||||||
class CUserStealDB(CSqlManager):
|
class CUserStealDB(CSqlManager):
|
||||||
@classmethod
|
@classmethod
|
||||||
async def initDB(cls):
|
async def initDB(cls):
|
||||||
#uid: 被偷用户Uid
|
|
||||||
#soilIndex: 被偷的地块索引 从1开始
|
|
||||||
#stealerUid: 偷菜用户Uid
|
|
||||||
#stealCount: 被偷数量
|
|
||||||
#stealTime: 被偷时间
|
|
||||||
userSteal = {
|
userSteal = {
|
||||||
"uid": "TEXT NOT NULL",
|
"uid": "TEXT NOT NULL", #被偷用户Uid
|
||||||
"soilIndex": "INTEGER NOT NULL",
|
"soilIndex": "INTEGER NOT NULL", #被偷的地块索引 从1开始
|
||||||
"stealerUid": "TEXT NOT NULL",
|
"stealerUid": "TEXT NOT NULL", #偷菜用户Uid
|
||||||
"stealCount": "INTEGER NOT NULL",
|
"stealCount": "INTEGER NOT NULL", #被偷数量
|
||||||
"stealTime": "INTEGER NOT NULL",
|
"stealTime": "INTEGER NOT NULL", #被偷时间
|
||||||
"PRIMARY KEY": "(uid, soilIndex, stealerUid)"
|
"PRIMARY KEY": "(uid, soilIndex, stealerUid)"
|
||||||
}
|
}
|
||||||
await cls.ensureTableSchema("userSteal", userSteal)
|
await cls.ensureTableSchema("userSteal", userSteal)
|
||||||
|
|||||||
@ -9,6 +9,7 @@ class CDBService:
|
|||||||
from .database.userItem import CUserItemDB
|
from .database.userItem import CUserItemDB
|
||||||
from .database.userPlant import CUserPlantDB
|
from .database.userPlant import CUserPlantDB
|
||||||
from .database.userSeed import CUserSeedDB
|
from .database.userSeed import CUserSeedDB
|
||||||
|
from .database.userSign import CUserSignDB
|
||||||
from .database.userSoil import CUserSoilDB
|
from .database.userSoil import CUserSoilDB
|
||||||
from .database.userSteal import CUserStealDB
|
from .database.userSteal import CUserStealDB
|
||||||
|
|
||||||
@ -33,6 +34,9 @@ class CDBService:
|
|||||||
cls.userSteal = CUserStealDB()
|
cls.userSteal = CUserStealDB()
|
||||||
await cls.userSteal.initDB()
|
await cls.userSteal.initDB()
|
||||||
|
|
||||||
|
cls.userSign = CUserSignDB()
|
||||||
|
await cls.userSign.initDB()
|
||||||
|
|
||||||
#迁移旧数据库
|
#迁移旧数据库
|
||||||
await cls.userSoil.migrateOldFarmData()
|
await cls.userSoil.migrateOldFarmData()
|
||||||
|
|
||||||
|
|||||||
@ -2,7 +2,6 @@ import asyncio
|
|||||||
import math
|
import math
|
||||||
import random
|
import random
|
||||||
from datetime import date, datetime
|
from datetime import date, datetime
|
||||||
from io import StringIO
|
|
||||||
from typing import Dict, List, Tuple
|
from typing import Dict, List, Tuple
|
||||||
|
|
||||||
from zhenxun.configs.config import Config
|
from zhenxun.configs.config import Config
|
||||||
|
|||||||
76
request.py
76
request.py
@ -1,28 +1,50 @@
|
|||||||
|
import json
|
||||||
import os
|
import os
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
import httpx
|
import httpx
|
||||||
|
|
||||||
from zhenxun.configs.config import Config
|
from zhenxun.configs.config import Config
|
||||||
from zhenxun.services.log import logger
|
from zhenxun.services.log import logger
|
||||||
|
|
||||||
|
from .config import g_sSignInPath
|
||||||
|
from .tool import g_pToolManager
|
||||||
|
|
||||||
|
|
||||||
class CRequestManager:
|
class CRequestManager:
|
||||||
|
m_sTokens = "xZ%?z5LtWV7H:0-Xnwp+bNRNQ-jbfrxG"
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def download(cls, url: str, savePath: str, fileName: str) -> bool:
|
async def download(cls,
|
||||||
|
url: str,
|
||||||
|
savePath: str,
|
||||||
|
fileName: str,
|
||||||
|
params: dict | None = None,
|
||||||
|
jsonData: dict | None = None) -> bool:
|
||||||
"""下载文件到指定路径并覆盖已存在的文件
|
"""下载文件到指定路径并覆盖已存在的文件
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
url (str): 文件的下载链接
|
url (str): 文件的下载链接
|
||||||
savePath (str): 保存文件夹路径
|
savePath (str): 保存文件夹路径
|
||||||
fileName (str): 保存后的文件名
|
fileName (str): 保存后的文件名
|
||||||
|
params (dict | None): 可选的 URL 查询参数
|
||||||
|
jsonData (dict | None): 可选的 JSON 请求体
|
||||||
Returns:
|
Returns:
|
||||||
bool: 是否下载成功
|
bool: 是否下载成功
|
||||||
"""
|
"""
|
||||||
|
headers = {"token": cls.m_sTokens}
|
||||||
|
|
||||||
try:
|
try:
|
||||||
async with httpx.AsyncClient(timeout=10.0) as client:
|
async with httpx.AsyncClient(timeout=10.0) as client:
|
||||||
response = await client.get(url)
|
# 动态组装请求参数
|
||||||
|
requestArgs: dict = {"headers": headers}
|
||||||
|
if params:
|
||||||
|
requestArgs["params"] = params
|
||||||
|
if jsonData:
|
||||||
|
requestArgs["json"] = jsonData
|
||||||
|
|
||||||
|
response = await client.request("GET", url, **requestArgs)
|
||||||
|
|
||||||
if response.status_code == 200:
|
if response.status_code == 200:
|
||||||
fullPath = os.path.join(savePath, fileName)
|
fullPath = os.path.join(savePath, fileName)
|
||||||
os.makedirs(os.path.dirname(fullPath), exist_ok=True)
|
os.makedirs(os.path.dirname(fullPath), exist_ok=True)
|
||||||
@ -32,6 +54,7 @@ class CRequestManager:
|
|||||||
else:
|
else:
|
||||||
logger.warning(f"文件下载失败: HTTP {response.status_code} {response.text}")
|
logger.warning(f"文件下载失败: HTTP {response.status_code} {response.text}")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warning(f"下载文件异常: {e}")
|
logger.warning(f"下载文件异常: {e}")
|
||||||
return False
|
return False
|
||||||
@ -56,7 +79,7 @@ class CRequestManager:
|
|||||||
|
|
||||||
baseUrl = Config.get_config("zhenxun_plugin_farm", "服务地址")
|
baseUrl = Config.get_config("zhenxun_plugin_farm", "服务地址")
|
||||||
url = f"{baseUrl.rstrip('/')}/{endpoint.lstrip('/')}"
|
url = f"{baseUrl.rstrip('/')}/{endpoint.lstrip('/')}"
|
||||||
headers = {"token": "xZ%?z5LtWV7H:0-Xnwp+bNRNQ-jbfrxG"}
|
headers = {"token": cls.m_sTokens}
|
||||||
|
|
||||||
try:
|
try:
|
||||||
async with httpx.AsyncClient(timeout=5.0) as client:
|
async with httpx.AsyncClient(timeout=5.0) as client:
|
||||||
@ -87,7 +110,7 @@ class CRequestManager:
|
|||||||
"""
|
"""
|
||||||
baseUrl = Config.get_config("zhenxun_plugin_farm", "服务地址")
|
baseUrl = Config.get_config("zhenxun_plugin_farm", "服务地址")
|
||||||
url = f"{baseUrl.rstrip('/')}/{endpoint.lstrip('/')}"
|
url = f"{baseUrl.rstrip('/')}/{endpoint.lstrip('/')}"
|
||||||
headers = {"token": "xZ%?z5LtWV7H:0-Xnwp+bNRNQ-jbfrxG"}
|
headers = {"token": cls.m_sTokens}
|
||||||
|
|
||||||
try:
|
try:
|
||||||
async with httpx.AsyncClient(timeout=5.0) as client:
|
async with httpx.AsyncClient(timeout=5.0) as client:
|
||||||
@ -106,20 +129,43 @@ class CRequestManager:
|
|||||||
return {}
|
return {}
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def sign(cls, uid: str) -> str:
|
async def initSignInFile(cls):
|
||||||
a = await cls.post("http://diuse.work:9099/testPost", jsonData={"level":3})
|
if os.path.exists(g_sSignInPath):
|
||||||
|
|
||||||
result = ""
|
try:
|
||||||
|
with open(g_sSignInPath, "r", encoding="utf-8") as f:
|
||||||
|
content = f.read()
|
||||||
|
sign = json.loads(content)
|
||||||
|
|
||||||
type = int(a["type"])
|
date = sign.get("date", "")
|
||||||
if type == 1:
|
yearMonth = datetime.now().strftime("%Y%m")
|
||||||
result = f"签到成功 type = 1"
|
|
||||||
elif type == 2:
|
if date == yearMonth:
|
||||||
result = f"签到成功 type = 2"
|
logger.debug("真寻农场签到文件检查完毕")
|
||||||
|
else:
|
||||||
|
logger.warning("真寻农场签到文件检查失败, 即将下载")
|
||||||
|
await cls.downloadSignInFile()
|
||||||
|
except json.JSONDecodeError as e:
|
||||||
|
logger.warning(f"真寻农场签到文件格式错误, 即将下载")
|
||||||
|
await cls.downloadSignInFile()
|
||||||
else:
|
else:
|
||||||
result = f"签到成功 type = {type}"
|
await cls.downloadSignInFile()
|
||||||
|
|
||||||
return result
|
@classmethod
|
||||||
|
async def downloadSignInFile(cls):
|
||||||
|
baseUrl = Config.get_config("zhenxun_plugin_farm", "服务地址")
|
||||||
|
|
||||||
|
url = f"{baseUrl.rstrip('/')}/sign_in"
|
||||||
|
url = f"http://127.0.0.1:8998/sign_in"
|
||||||
|
|
||||||
|
path = str(g_sSignInPath.parent.resolve(strict=False))
|
||||||
|
yearMonth = datetime.now().strftime("%Y%m")
|
||||||
|
|
||||||
|
logger.info(f"{yearMonth}")
|
||||||
|
yearMonth = "202506"
|
||||||
|
|
||||||
|
await cls.download(url, path, "signTemp.json", jsonData={'date':yearMonth})
|
||||||
|
g_pToolManager.renameFile(f"{path}/signTemp.json", "sign_in.json")
|
||||||
|
|
||||||
|
|
||||||
g_pRequestManager = CRequestManager()
|
g_pRequestManager = CRequestManager()
|
||||||
|
|||||||
32
tool.py
Normal file
32
tool.py
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
import os
|
||||||
|
|
||||||
|
from zhenxun.services.log import logger
|
||||||
|
|
||||||
|
|
||||||
|
class CToolManager:
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def renameFile(cls, currentFilePath: str, newFileName: str) -> bool:
|
||||||
|
"""重命名文件,如果目标文件名已存在则先删除再重命名
|
||||||
|
|
||||||
|
Args:
|
||||||
|
currentFilePath (str): 当前文件的完整路径
|
||||||
|
newFileName (str): 重命名后的文件名
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: 重命名成功返回 True,否则返回 False
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
dirPath = os.path.dirname(currentFilePath)
|
||||||
|
newFilePath = os.path.join(dirPath, newFileName)
|
||||||
|
|
||||||
|
if os.path.exists(newFilePath):
|
||||||
|
os.remove(newFilePath)
|
||||||
|
|
||||||
|
os.rename(currentFilePath, newFilePath)
|
||||||
|
return True
|
||||||
|
except Exception as e:
|
||||||
|
logger.warning(f"文件重命名失败: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
g_pToolManager = CToolManager()
|
||||||
Loading…
Reference in New Issue
Block a user