| import datetime |
|
|
| from peewee import * |
|
|
| import resources.Environment as Env |
| from src.model.BaseModel import BaseModel |
| from src.model.GroupChat import GroupChat |
| from src.model.User import User |
| from src.model.enums.daily_reward.DailyRewardBonus import DailyRewardBonus, DailyRewardBonusType |
| from src.model.enums.daily_reward.DailyRewardLimitation import DailyRewardLimitation |
| from src.model.enums.daily_reward.DailyRewardPrizeSource import DailyRewardPrizeSource |
| from src.model.enums.daily_reward.DailyRewardPrizeType import DailyRewardPrizeType |
| from src.service.date_service import get_day_in_past, is_same_day |
| from src.utils.math_utils import get_value_from_percentage |
|
|
|
|
| class DailyReward(BaseModel): |
| """ |
| DailyReward class |
| """ |
|
|
| user: User | ForeignKeyField = ForeignKeyField(User, backref="daily_bonuses") |
| base_amount: int | BigIntegerField = BigIntegerField() |
| bonus_list: str | TextField = TextField() |
| total_amount: int | BigIntegerField = BigIntegerField() |
| streak_count: int | IntegerField = IntegerField() |
| limitation: str | DailyRewardLimitation = CharField(max_length=20) |
| prize_type: DailyRewardPrizeType | CharField = CharField(max_length=20, null=True) |
| prize_value: str | CharField = CharField(max_length=50, null=True) |
| prize_source: DailyRewardPrizeSource | CharField = CharField(max_length=20, null=True) |
| group_chat: GroupChat | ForeignKeyField = ForeignKeyField( |
| GroupChat, backref="daily_rewards", null=True |
| ) |
| message_id: int | IntegerField = IntegerField(null=True) |
| message_id_prize: int | IntegerField = IntegerField(null=True) |
|
|
| class Meta: |
| db_table = "daily_reward" |
|
|
| @staticmethod |
| def reset(): |
| """ |
| Reset the daily rewards |
| """ |
|
|
| User.reset_daily_reward() |
|
|
| @staticmethod |
| def get_daily_reward_reset_times(): |
| """ |
| Get how many times daily reward is reset during the day |
| """ |
| cron_expression = Env.CRON_DAILY_REWARD.get() |
| cron_parts = cron_expression.split() |
|
|
| |
| if cron_parts[1] == "*": |
| return 24 |
|
|
| |
| if "*/" in cron_parts[1]: |
| return 24 // int(cron_parts[1].split("/")[1]) |
|
|
| |
| return 1 |
|
|
| @staticmethod |
| def get_next_reward_time() -> datetime.datetime: |
| from src.service.date_service import get_next_run |
|
|
| return get_next_run(Env.CRON_DAILY_REWARD.get()) |
|
|
| @staticmethod |
| def get_remaining_time_to_next_reward() -> str: |
| from src.service.date_service import get_remaining_duration |
|
|
| return get_remaining_duration(DailyReward.get_next_reward_time()) |
|
|
| @staticmethod |
| def get_last_streak_reward(user: User) -> "DailyReward": |
| """ |
| Get the last streak reward for the user |
| :param user: The user |
| :return: The last streak reward |
| """ |
|
|
| return ( |
| DailyReward.select() |
| .where((DailyReward.user == user) & (DailyReward.date >= get_day_in_past(1))) |
| .order_by(DailyReward.date.desc()) |
| .first() |
| ) |
|
|
| @staticmethod |
| def get_user_streak_count(user: User) -> int: |
| """ |
| Get the user's streak count |
| :param user: The user |
| :return: The streak count |
| """ |
|
|
| |
| last_streak_reward = DailyReward.get_last_streak_reward(user) |
|
|
| if last_streak_reward is None: |
| return 1 |
|
|
| streak_count = last_streak_reward.streak_count |
|
|
| |
| if is_same_day(last_streak_reward.date, get_day_in_past(1)): |
| return streak_count + 1 |
|
|
| return last_streak_reward.streak_count |
|
|
| @staticmethod |
| def get_bonuses_for_user(user: User, base_amount: int) -> list[DailyRewardBonus]: |
| """ |
| Get the bonus_list for the user |
| :param user: The user |
| :param base_amount: The base amount |
| :return: The bonus_list |
| """ |
|
|
| bonus_list: list[DailyRewardBonus] = [] |
| total_amount = base_amount |
|
|
| for bonus_type in list(DailyRewardBonusType): |
| multiplier = None |
| match bonus_type: |
| |
| case DailyRewardBonusType.STREAK: |
| value = Env.DAILY_REWARD_BONUS_BASE_STREAK.get_int() |
| streak_count = min( |
| DailyReward.get_user_streak_count(user), |
| Env.DAILY_REWARD_BONUS_MAX_STREAK.get_int(), |
| ) |
| multiplier = streak_count |
| value *= multiplier |
|
|
| |
| case DailyRewardBonusType.LOCATION: |
| multiplier = user.location_level |
| value = Env.DAILY_REWARD_BONUS_BASE_LOCATION.get_int() * multiplier |
|
|
| |
| case DailyRewardBonusType.CREW_LEVEL: |
| if not user.is_crew_member(): |
| continue |
| multiplier = user.crew.level |
| value = Env.DAILY_REWARD_BONUS_BASE_CREW_LEVEL.get_int() * multiplier |
|
|
| |
| case DailyRewardBonusType.CREW_MVP: |
| if not user.has_crew_mvp_bonus(): |
| continue |
| value = Env.DAILY_REWARD_BONUS_CREW_MVP.get_int() |
|
|
| case _: |
| raise ValueError(f"Invalid bonus type: {bonus_type}") |
|
|
| amount = int(get_value_from_percentage(total_amount, value)) |
| total_amount += amount |
| bonus_list.append(DailyRewardBonus(bonus_type, value, amount, multiplier)) |
|
|
| return bonus_list |
|
|
| def get_days_to_next_prize(self) -> int: |
| """ |
| Get the days to next prize |
| :return: The days to next prize |
| """ |
|
|
| prize_days = Env.DAILY_REWARD_STREAK_DAYS.get_int() |
| last_streak_reward = self.get_last_streak_reward(self.user) |
|
|
| |
| |
| if last_streak_reward.streak_count < prize_days: |
| return prize_days - last_streak_reward.streak_count |
|
|
| |
| return prize_days - (last_streak_reward.streak_count % prize_days) |
|
|
| def get_base_belly_prize_offer(self) -> int: |
| """ |
| Get the base belly prize |
| :return: The base belly prize offer |
| """ |
|
|
| return self.total_amount |
|
|
| @staticmethod |
| def get_minimum_belly_prize() -> int: |
| """ |
| Get the minimum belly prize |
| :return: The minimum belly prize |
| """ |
|
|
| return 1 |
|
|
| def get_maximum_belly_prize(self) -> int: |
| """ |
| Get the maximum belly prize |
| :return: The maximum belly prize |
| """ |
|
|
| return self.total_amount * 2 |
|
|
| @staticmethod |
| def get_reward_count_for_user(user: User) -> int: |
| """ |
| Get the reward count for the user |
| :param user: The user |
| :return: The reward count for the user |
| """ |
|
|
| return DailyReward.select().where(DailyReward.user == user).count() |
|
|
| def should_award_prize(self) -> bool: |
| """ |
| Should award prize |
| :return: Should award prize |
| """ |
| |
| if DailyReward.get_reward_count_for_user(self.user) == 1: |
| return True |
|
|
| |
| if self.get_days_to_next_prize() != Env.DAILY_REWARD_STREAK_DAYS.get_int(): |
| return False |
|
|
| |
| rewards_today = ( |
| DailyReward.select() |
| .where((DailyReward.user == self.user) & (DailyReward.date >= get_day_in_past())) |
| .count() |
| ) |
|
|
| return rewards_today == 1 |
|
|
|
|
| DailyReward.create_table() |
|
|