Support daily task notice

This commit is contained in:
omg-xtao 2024-03-10 20:10:25 +08:00 committed by GitHub
parent d4d5baf3b2
commit 6b93acb2ab
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 266 additions and 93 deletions

View File

@ -0,0 +1,59 @@
"""tasks_daily
Revision ID: 89dcb9109475
Revises: 27aaa52f9d4a
Create Date: 2024-03-10 10:48:10.227236
"""
from alembic import op
from sqlalchemy.dialects import mysql
# revision identifiers, used by Alembic.
revision = "89dcb9109475"
down_revision = "27aaa52f9d4a"
branch_labels = None
depends_on = None
def upgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.alter_column(
"task",
"type",
existing_type=mysql.ENUM(
"SIGN",
"RESIN",
"REALM",
"EXPEDITION",
"TRANSFORMER",
"CARD",
"DAILY",
collation="utf8mb4_general_ci",
),
nullable=False,
)
op.drop_index("task_1", table_name="task")
op.create_index(op.f("ix_task_user_id"), "task", ["user_id"], unique=False)
# ### end Alembic commands ###
def downgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.drop_index(op.f("ix_task_user_id"), table_name="task")
op.create_index("task_1", "task", ["user_id"], unique=False)
op.alter_column(
"task",
"type",
existing_type=mysql.ENUM(
"SIGN",
"RESIN",
"REALM",
"EXPEDITION",
"TRANSFORMER",
"CARD",
collation="utf8mb4_general_ci",
),
nullable=True,
)
op.alter_column("task", "user_id", existing_type=mysql.BIGINT(), nullable=True)
# ### end Alembic commands ###

View File

@ -5,6 +5,7 @@ from gram_core.services.task.services import (
TaskResinServices,
TaskRealmServices,
TaskExpeditionServices,
TaskDailyServices,
)
__all__ = [
@ -14,4 +15,5 @@ __all__ = [
"TaskResinServices",
"TaskRealmServices",
"TaskExpeditionServices",
"TaskDailyServices",
]

@ -1 +1 @@
Subproject commit 909c81b14035f97dae6fa0b7ea474576ecc25fd7
Subproject commit b8260c296496b2352ed71c489ea19b1fc57125af

View File

@ -1,3 +1,5 @@
from typing import TYPE_CHECKING
from pydantic import ValidationError
from simnet import Region
from simnet.errors import DataNotPublic, BadRequest as SimnetBadRequest
@ -14,8 +16,10 @@ from plugins.tools.daily_note import DailyNoteSystem, WebAppData
from plugins.tools.genshin import GenshinHelper, CookiesNotFoundError, PlayerNotFoundError
from utils.log import logger
__all__ = ("DailyNoteTasksPlugin",)
if TYPE_CHECKING:
from simnet import GenshinClient
__all__ = ("DailyNoteTasksPlugin",)
SET_BY_WEB = 10100
@ -106,7 +110,7 @@ class DailyNoteTasksPlugin(Plugin.Conversation):
validate = WebAppData(**result.data)
except ValidationError:
await message.reply_text(
"数据错误\n" "树脂提醒数值必须在 100 ~ 160 之间\n" "洞天宝钱提醒数值必须在 100 ~ 2400 之间",
"数据错误\n树脂提醒数值必须在 100 ~ 160 之间\n洞天宝钱提醒数值必须在 100 ~ 2400 之间\n每日任务提醒时间必须在 0 ~ 23 之间",
reply_markup=ReplyKeyboardRemove(),
)
return ConversationHandler.END

View File

@ -1,5 +1,6 @@
import base64
from typing import TYPE_CHECKING, List, Optional
from datetime import datetime
from typing import TYPE_CHECKING, List, Optional, Union
from pydantic import BaseModel, validator
from simnet import Region
@ -10,13 +11,14 @@ from telegram.error import BadRequest, Forbidden
from core.plugin import Plugin
from core.services.task.models import Task as TaskUser, TaskStatusEnum
from core.services.task.services import TaskResinServices, TaskRealmServices, TaskExpeditionServices
from core.services.task.services import TaskResinServices, TaskRealmServices, TaskExpeditionServices, TaskDailyServices
from gram_core.plugin.methods.migrate_data import IMigrateData, MigrateDataException
from plugins.tools.genshin import GenshinHelper, PlayerNotFoundError, CookiesNotFoundError
from utils.log import logger
if TYPE_CHECKING:
from simnet import GenshinClient
from simnet.models.genshin.chronicle.notes import Notes, NotesWidget
from telegram.ext import ContextTypes
from gram_core.services.task.services import TaskServices
@ -49,10 +51,21 @@ class ExpeditionData(TaskDataBase):
pass
class DailyData(TaskDataBase):
notice_hour: Optional[int] = 22
@validator("notice_hour")
def notice_hour_validator(cls, v):
if v < 0 or v > 23:
raise ValueError("每日任务提醒时间必须在 0 ~ 23 之间")
return v
class WebAppData(BaseModel):
resin: Optional[ResinData]
realm: Optional[RealmData]
expedition: Optional[ExpeditionData]
daily: Optional[DailyData]
class DailyNoteTaskUser:
@ -62,14 +75,17 @@ class DailyNoteTaskUser:
resin_db: Optional[TaskUser] = None,
realm_db: Optional[TaskUser] = None,
expedition_db: Optional[TaskUser] = None,
daily_db: Optional[TaskUser] = None,
):
self.user_id = user_id
self.resin_db = resin_db
self.realm_db = realm_db
self.expedition_db = expedition_db
self.daily_db = daily_db
self.resin = ResinData(**self.resin_db.data) if self.resin_db else None
self.realm = RealmData(**self.realm_db.data) if self.realm_db else None
self.expedition = ExpeditionData(**self.expedition_db.data) if self.expedition_db else None
self.daily = DailyData(**self.daily_db.data) if self.daily_db else None
@property
def status(self) -> TaskStatusEnum:
@ -78,6 +94,7 @@ class DailyNoteTaskUser:
self.resin_db.status if self.resin_db else TaskStatusEnum.STATUS_SUCCESS,
self.realm_db.status if self.realm_db else TaskStatusEnum.STATUS_SUCCESS,
self.expedition_db.status if self.expedition_db else TaskStatusEnum.STATUS_SUCCESS,
self.daily_db.status if self.daily_db else TaskStatusEnum.STATUS_SUCCESS,
]
)
@ -89,6 +106,8 @@ class DailyNoteTaskUser:
self.realm_db.status = value
if self.expedition_db:
self.expedition_db.status = value
if self.daily:
self.daily_db.status = value
@staticmethod
def js_bool(value: bool) -> str:
@ -108,6 +127,7 @@ class DailyNoteTaskUser:
resin=self.set_model_noticed(self.resin) if self.resin else None,
realm=self.set_model_noticed(self.realm) if self.realm else None,
expedition=self.set_model_noticed(self.expedition) if self.expedition else None,
daily=self.set_model_noticed(self.daily) if self.daily else None,
).json()
).encode()
).decode()
@ -119,6 +139,8 @@ class DailyNoteTaskUser:
self.realm_db.data = self.realm.dict()
if self.expedition_db:
self.expedition_db.data = self.expedition.dict()
if self.daily_db:
self.daily_db.data = self.daily.dict()
class DailyNoteSystem(Plugin):
@ -128,23 +150,89 @@ class DailyNoteSystem(Plugin):
resin_service: TaskResinServices,
realm_service: TaskRealmServices,
expedition_service: TaskExpeditionServices,
daily_service: TaskDailyServices,
):
self.genshin_helper = genshin_helper
self.resin_service = resin_service
self.realm_service = realm_service
self.expedition_service = expedition_service
self.daily_service = daily_service
async def get_single_task_user(self, user_id: int) -> DailyNoteTaskUser:
resin_db = await self.resin_service.get_by_user_id(user_id)
realm_db = await self.realm_service.get_by_user_id(user_id)
expedition_db = await self.expedition_service.get_by_user_id(user_id)
daily_db = await self.daily_service.get_by_user_id(user_id)
return DailyNoteTaskUser(
user_id=user_id,
resin_db=resin_db,
realm_db=realm_db,
expedition_db=expedition_db,
daily_db=daily_db,
)
@staticmethod
def get_resin_notice(user: DailyNoteTaskUser, notes: Union["Notes", "NotesWidget"]) -> str:
notice = None
if user.resin_db and notes.max_resin > 0:
if notes.current_resin >= user.resin.notice_num:
if not user.resin.noticed:
notice = (
f"### 树脂提示 ####\n\n当前树脂为 {notes.current_resin} / {notes.max_resin} ,记得使用哦~\n"
f"预计全部恢复完成:{notes.resin_recovery_time.strftime('%Y-%m-%d %H:%M')}"
)
user.resin.noticed = True
else:
user.resin.noticed = False
return notice
@staticmethod
def get_realm_notice(user: DailyNoteTaskUser, notes: Union["Notes", "NotesWidget"]) -> str:
notice = None
if user.realm_db and notes.max_realm_currency > 0:
if notes.current_realm_currency >= user.realm.notice_num:
if not user.realm.noticed:
notice = (
f"### 洞天宝钱提示 ####\n\n"
f"当前存储为 {notes.current_realm_currency} / {notes.max_realm_currency} ,记得领取哦~"
)
user.realm.noticed = True
else:
user.realm.noticed = False
return notice
@staticmethod
def get_expedition_notice(user: DailyNoteTaskUser, notes: Union["Notes", "NotesWidget"]) -> str:
notice = None
if user.expedition_db and len(notes.expeditions) > 0:
all_finished = all(i.status == "Finished" for i in notes.expeditions)
if all_finished:
if not user.expedition.noticed:
notice = "### 探索派遣提示 ####\n\n所有探索派遣已完成,记得重新派遣哦~"
user.expedition.noticed = True
else:
user.expedition.noticed = False
return notice
@staticmethod
def get_daily_notice(user: DailyNoteTaskUser, notes: Union["Notes", "NotesWidget"]) -> str:
notice = None
now_hour = datetime.now().hour
if user.daily_db:
if now_hour == user.daily.notice_hour:
if (notes.completed_commissions != notes.max_commissions or (not notes.claimed_commission_reward)) and (
not user.daily.noticed
):
notice_ = "已领取奖励" if notes.claimed_commission_reward else "未领取奖励"
notice = (
f"### 每日任务提示 ####\n\n"
f"当前进度为 {notes.completed_commissions} / {notes.max_commissions} ({notice_}) ,记得完成哦~"
)
user.daily.noticed = True
else:
user.daily.noticed = False
return notice
@staticmethod
async def start_get_notes(
client: "GenshinClient",
@ -156,41 +244,12 @@ class DailyNoteSystem(Plugin):
notes = await client.get_genshin_notes_by_stoken()
if not user:
return []
notices = []
notice = None
if user.resin_db and notes.max_resin > 0:
if notes.current_resin >= user.resin.notice_num:
if not user.resin.noticed:
notice = (
f"### 树脂提示 ####\n\n当前树脂为 {notes.current_resin} / {notes.max_resin} ,记得使用哦~\n"
f"预计全部恢复完成:{notes.resin_recovery_time.strftime('%Y-%m-%d %H:%M')}"
)
user.resin.noticed = True
else:
user.resin.noticed = False
notices.append(notice)
notice = None
if user.realm_db and notes.max_realm_currency > 0:
if notes.current_realm_currency >= user.realm.notice_num:
if not user.realm.noticed:
notice = (
f"### 洞天宝钱提示 ####\n\n"
f"当前存储为 {notes.current_realm_currency} / {notes.max_realm_currency} ,记得领取哦~"
)
user.realm.noticed = True
else:
user.realm.noticed = False
notices.append(notice)
notice = None
if user.expedition_db and len(notes.expeditions) > 0:
all_finished = all(i.status == "Finished" for i in notes.expeditions)
if all_finished:
if not user.expedition.noticed:
notice = "### 探索派遣提示 ####\n\n所有探索派遣已完成,记得重新派遣哦~"
user.expedition.noticed = True
else:
user.expedition.noticed = False
notices.append(notice)
notices = [
DailyNoteSystem.get_resin_notice(user, notes),
DailyNoteSystem.get_realm_notice(user, notes),
DailyNoteSystem.get_expedition_notice(user, notes),
DailyNoteSystem.get_daily_notice(user, notes),
]
user.save()
return notices
@ -198,6 +257,7 @@ class DailyNoteSystem(Plugin):
resin_list = await self.resin_service.get_all()
realm_list = await self.realm_service.get_all()
expedition_list = await self.expedition_service.get_all()
daily_list = await self.daily_service.get_all()
user_list = set()
for i in resin_list:
user_list.add(i.user_id)
@ -205,12 +265,15 @@ class DailyNoteSystem(Plugin):
user_list.add(i.user_id)
for i in expedition_list:
user_list.add(i.user_id)
for i in daily_list:
user_list.add(i.user_id)
return [
DailyNoteTaskUser(
user_id=i,
resin_db=next((x for x in resin_list if x.user_id == i), None),
realm_db=next((x for x in realm_list if x.user_id == i), None),
expedition_db=next((x for x in expedition_list if x.user_id == i), None),
daily_db=next((x for x in daily_list if x.user_id == i), None),
)
for i in user_list
]
@ -222,6 +285,8 @@ class DailyNoteSystem(Plugin):
await self.realm_service.remove(user.realm_db)
if user.expedition_db:
await self.expedition_service.remove(user.expedition_db)
if user.daily_db:
await self.daily_service.remove(user.daily_db)
async def update_task_user(self, user: DailyNoteTaskUser):
if user.resin_db:
@ -239,6 +304,11 @@ class DailyNoteSystem(Plugin):
await self.expedition_service.update(user.expedition_db)
except StaleDataError:
logger.warning("用户 user_id[%s] 自动便签提醒 - 探索派遣数据过期,跳过更新数据", user.user_id)
if user.daily_db:
try:
await self.daily_service.update(user.daily_db)
except StaleDataError:
logger.warning("用户 user_id[%s] 自动便签提醒 - 每日任务数据过期,跳过更新数据", user.user_id)
@staticmethod
async def check_need_note(web_config: WebAppData) -> bool:
@ -249,65 +319,101 @@ class DailyNoteSystem(Plugin):
need_verify = True
if web_config.expedition and web_config.expedition.noticed:
need_verify = True
if web_config.daily and web_config.daily.noticed:
need_verify = True
return need_verify
async def import_web_config_resin(self, user: DailyNoteTaskUser, web_config: WebAppData):
user_id = user.user_id
if web_config.resin.noticed:
if not user.resin_db:
resin = self.resin_service.create(
user_id,
user_id,
status=TaskStatusEnum.STATUS_SUCCESS,
data=ResinData(notice_num=web_config.resin.notice_num).dict(),
)
await self.resin_service.add(resin)
else:
user.resin.notice_num = web_config.resin.notice_num
user.resin.noticed = False
user.resin_db.status = TaskStatusEnum.STATUS_SUCCESS
else:
if user.resin_db:
await self.resin_service.remove(user.resin_db)
user.resin_db = None
user.resin = None
async def import_web_config_realm(self, user: DailyNoteTaskUser, web_config: WebAppData):
user_id = user.user_id
if web_config.realm.noticed:
if not user.realm_db:
realm = self.realm_service.create(
user_id,
user_id,
status=TaskStatusEnum.STATUS_SUCCESS,
data=RealmData(notice_num=web_config.realm.notice_num).dict(),
)
await self.realm_service.add(realm)
else:
user.realm.notice_num = web_config.realm.notice_num
user.realm.noticed = False
else:
if user.realm_db:
await self.realm_service.remove(user.realm_db)
user.realm_db = None
user.realm = None
async def import_web_config_expedition(self, user: DailyNoteTaskUser, web_config: WebAppData):
user_id = user.user_id
if web_config.expedition.noticed:
if not user.expedition_db:
expedition = self.expedition_service.create(
user_id,
user_id,
status=TaskStatusEnum.STATUS_SUCCESS,
data=ExpeditionData().dict(),
)
await self.expedition_service.add(expedition)
else:
user.expedition.noticed = False
user.expedition_db.status = TaskStatusEnum.STATUS_SUCCESS
else:
if user.expedition_db:
await self.expedition_service.remove(user.expedition_db)
user.expedition_db = None
user.expedition = None
async def import_web_config_daily(self, user: DailyNoteTaskUser, web_config: WebAppData):
user_id = user.user_id
if web_config.daily.noticed:
if not user.daily_db:
daily = self.daily_service.create(
user_id,
user_id,
status=TaskStatusEnum.STATUS_SUCCESS,
data=DailyData(notice_hour=web_config.daily.notice_hour).dict(),
)
await self.daily_service.add(daily)
else:
user.daily.noticed = False
user.daily_db.status = TaskStatusEnum.STATUS_SUCCESS
else:
if user.daily_db:
await self.daily_service.remove(user.daily_db)
user.daily_db = None
user.daily = None
async def import_web_config(self, user_id: int, web_config: WebAppData):
user = await self.get_single_task_user(user_id)
if web_config.resin:
if web_config.resin.noticed:
if not user.resin_db:
resin = self.resin_service.create(
user_id,
user_id,
status=TaskStatusEnum.STATUS_SUCCESS,
data=ResinData(notice_num=web_config.resin.notice_num).dict(),
)
await self.resin_service.add(resin)
else:
user.resin.notice_num = web_config.resin.notice_num
user.resin.noticed = False
user.resin_db.status = TaskStatusEnum.STATUS_SUCCESS
else:
if user.resin_db:
await self.resin_service.remove(user.resin_db)
user.resin_db = None
user.resin = None
await self.import_web_config_resin(user, web_config)
if web_config.realm:
if web_config.realm.noticed:
if not user.realm_db:
realm = self.realm_service.create(
user_id,
user_id,
status=TaskStatusEnum.STATUS_SUCCESS,
data=RealmData(notice_num=web_config.realm.notice_num).dict(),
)
await self.realm_service.add(realm)
else:
user.realm.notice_num = web_config.realm.notice_num
user.realm.noticed = False
else:
if user.realm_db:
await self.realm_service.remove(user.realm_db)
user.realm_db = None
user.realm = None
await self.import_web_config_realm(user, web_config)
if web_config.expedition:
if web_config.expedition.noticed:
if not user.expedition_db:
expedition = self.expedition_service.create(
user_id,
user_id,
status=TaskStatusEnum.STATUS_SUCCESS,
data=ExpeditionData().dict(),
)
await self.expedition_service.add(expedition)
else:
user.expedition.noticed = False
user.expedition_db.status = TaskStatusEnum.STATUS_SUCCESS
else:
if user.expedition_db:
await self.expedition_service.remove(user.expedition_db)
user.expedition_db = None
user.expedition = None
await self.import_web_config_expedition(user, web_config)
if web_config.daily:
await self.import_web_config_daily(user, web_config)
user.save()
await self.update_task_user(user)
@ -347,7 +453,9 @@ class DailyNoteSystem(Plugin):
text = "获取便签失败了呜呜呜 ~ 执行自动便签提醒时发生错误"
else:
task_db.status = TaskStatusEnum.STATUS_SUCCESS
for idx, task_user_db in enumerate([task_db.resin_db, task_db.realm_db, task_db.expedition_db]):
for idx, task_user_db in enumerate(
[task_db.resin_db, task_db.realm_db, task_db.expedition_db, task_db.daily_db]
):
if task_user_db is None:
continue
notice_text = text[idx] if isinstance(text, list) else text