Commit
This commit is contained in:
128
old/bot/utils.py
Normal file
128
old/bot/utils.py
Normal file
@@ -0,0 +1,128 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Utility functions and decorators for the bot.
|
||||
"""
|
||||
import os
|
||||
import functools
|
||||
import logging
|
||||
from telegram import Update
|
||||
from telegram.ext import ContextTypes
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def create_progress_bar(current: int, maximum: int, length: int = 10, filled_char: str = "█", empty_char: str = "░") -> str:
|
||||
"""
|
||||
Create a visual progress bar.
|
||||
|
||||
Args:
|
||||
current: Current value
|
||||
maximum: Maximum value
|
||||
length: Length of the bar in characters (default 10)
|
||||
filled_char: Character for filled portion (default █)
|
||||
empty_char: Character for empty portion (default ░)
|
||||
|
||||
Returns:
|
||||
String representation of progress bar
|
||||
|
||||
Examples:
|
||||
>>> create_progress_bar(75, 100)
|
||||
"███████░░░"
|
||||
>>> create_progress_bar(0, 100)
|
||||
"░░░░░░░░░░"
|
||||
>>> create_progress_bar(100, 100)
|
||||
"██████████"
|
||||
"""
|
||||
if maximum <= 0:
|
||||
return empty_char * length
|
||||
|
||||
percentage = min(1.0, max(0.0, current / maximum))
|
||||
filled_length = int(length * percentage)
|
||||
empty_length = length - filled_length
|
||||
|
||||
return filled_char * filled_length + empty_char * empty_length
|
||||
|
||||
|
||||
def format_stat_bar(label: str, emoji: str, current: int, maximum: int, bar_length: int = 10, label_width: int = 7) -> str:
|
||||
"""
|
||||
Format a stat (HP, Stamina, etc.) with visual progress bar.
|
||||
Uses right-aligned label format to avoid alignment issues with Telegram's proportional font.
|
||||
|
||||
Args:
|
||||
label: Stat label (e.g., "HP", "Stamina", "Your HP")
|
||||
emoji: Emoji to display (e.g., "❤️", "⚡", "🐕")
|
||||
current: Current value
|
||||
maximum: Maximum value
|
||||
bar_length: Length of the progress bar
|
||||
label_width: Not used, kept for backwards compatibility
|
||||
|
||||
Returns:
|
||||
Formatted string with bar on left, label on right
|
||||
|
||||
Examples:
|
||||
>>> format_stat_bar("HP", "❤️", 75, 100)
|
||||
"███████░░░ 75% (75/100) ❤️ HP"
|
||||
>>> format_stat_bar("Stamina", "⚡", 50, 100)
|
||||
"█████░░░░░ 50% (50/100) ⚡ Stamina"
|
||||
"""
|
||||
bar = create_progress_bar(current, maximum, bar_length)
|
||||
percentage = int((current / maximum * 100)) if maximum > 0 else 0
|
||||
|
||||
# Right-aligned format: bar first, then stats, then emoji + label
|
||||
# This way bars are always left-aligned regardless of label length
|
||||
if emoji:
|
||||
return f"{bar} {percentage}% ({current}/{maximum}) {emoji} {label}"
|
||||
else:
|
||||
# If no emoji provided, just use label
|
||||
return f"{bar} {percentage}% ({current}/{maximum}) {label}"
|
||||
|
||||
|
||||
|
||||
def get_admin_ids():
|
||||
"""Get the list of admin user IDs from environment variable."""
|
||||
admin_ids_str = os.getenv("ADMIN_IDS", "")
|
||||
if not admin_ids_str:
|
||||
logger.warning("ADMIN_IDS not set in .env file. No admins configured.")
|
||||
return set()
|
||||
|
||||
try:
|
||||
# Parse comma-separated list of IDs
|
||||
admin_ids = set(int(id.strip()) for id in admin_ids_str.split(",") if id.strip())
|
||||
return admin_ids
|
||||
except ValueError as e:
|
||||
logger.error(f"Error parsing ADMIN_IDS: {e}")
|
||||
return set()
|
||||
|
||||
|
||||
def admin_only(func):
|
||||
"""
|
||||
Decorator that restricts command to admin users only.
|
||||
|
||||
Usage:
|
||||
@admin_only
|
||||
async def my_admin_command(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||
...
|
||||
"""
|
||||
@functools.wraps(func)
|
||||
async def wrapper(update: Update, context: ContextTypes.DEFAULT_TYPE, *args, **kwargs):
|
||||
user_id = update.effective_user.id
|
||||
admin_ids = get_admin_ids()
|
||||
|
||||
if user_id not in admin_ids:
|
||||
await update.message.reply_html(
|
||||
"🚫 <b>Access Denied</b>\n\n"
|
||||
"This command is restricted to administrators only."
|
||||
)
|
||||
logger.warning(f"User {user_id} attempted to use admin command: {func.__name__}")
|
||||
return
|
||||
|
||||
# User is admin, execute the command
|
||||
return await func(update, context, *args, **kwargs)
|
||||
|
||||
return wrapper
|
||||
|
||||
|
||||
def is_admin(user_id: int) -> bool:
|
||||
"""Check if a user ID is an admin."""
|
||||
admin_ids = get_admin_ids()
|
||||
return user_id in admin_ids
|
||||
Reference in New Issue
Block a user