mirror of
https://github.com/FerraSoft/bottohelp.git
synced 2026-08-06 21:55:03 +00:00
374 lines
12 KiB
Python
374 lines
12 KiB
Python
"""
|
|
Модели данных для телеграм-бота.
|
|
Определяют структуру данных и их взаимосвязи.
|
|
"""
|
|
|
|
from dataclasses import dataclass
|
|
from datetime import datetime
|
|
from typing import Optional, List, Any, Dict
|
|
|
|
|
|
@dataclass
|
|
class Role:
|
|
"""Модель роли пользователя"""
|
|
id: int
|
|
name: str
|
|
display_name: str
|
|
description: Optional[str] = None
|
|
permissions: Optional[str] = None # JSON строка с разрешениями
|
|
is_active: bool = True
|
|
|
|
|
|
@dataclass
|
|
class User:
|
|
"""Модель пользователя"""
|
|
id: int
|
|
telegram_id: int
|
|
username: Optional[str] = None
|
|
first_name: Optional[str] = None
|
|
last_name: Optional[str] = None
|
|
joined_date: datetime = None
|
|
last_activity: datetime = None
|
|
reputation: int = 0
|
|
rank: str = "Новичок"
|
|
warnings: int = 0
|
|
is_active: bool = True
|
|
role_id: int = 1 # Ссылка на таблицу roles, по умолчанию user
|
|
|
|
def __post_init__(self):
|
|
if self.joined_date is None:
|
|
self.joined_date = datetime.now()
|
|
if self.last_activity is None:
|
|
self.last_activity = datetime.now()
|
|
|
|
|
|
@dataclass
|
|
class Score:
|
|
"""Модель очков и статистики пользователя"""
|
|
id: int
|
|
user_id: int
|
|
total_score: int = 0
|
|
message_count: int = 0
|
|
game_wins: int = 0
|
|
donations_total: float = 0.0
|
|
last_updated: datetime = None
|
|
|
|
def __post_init__(self):
|
|
if self.last_updated is None:
|
|
self.last_updated = datetime.now()
|
|
|
|
|
|
@dataclass
|
|
class Error:
|
|
"""Модель ошибки/отчета об ошибке"""
|
|
id: int
|
|
admin_id: int
|
|
error_type: str
|
|
title: str
|
|
description: str
|
|
status: str = "new"
|
|
priority: str = "medium"
|
|
created_at: datetime = None
|
|
updated_at: datetime = None
|
|
ai_analysis: Optional[str] = None
|
|
todo_added: bool = False
|
|
resolved_at: Optional[datetime] = None
|
|
|
|
def __post_init__(self):
|
|
if self.created_at is None:
|
|
self.created_at = datetime.now()
|
|
if self.updated_at is None:
|
|
self.updated_at = datetime.now()
|
|
|
|
|
|
@dataclass
|
|
class ScheduledPost:
|
|
"""Модель запланированного поста"""
|
|
id: int
|
|
chat_id: int
|
|
text: str
|
|
image_path: Optional[str] = None
|
|
schedule_time: datetime = None
|
|
created_by: int = 0
|
|
status: str = "pending"
|
|
published_at: Optional[datetime] = None
|
|
created_at: datetime = None
|
|
|
|
def __post_init__(self):
|
|
if self.schedule_time is None:
|
|
self.schedule_time = datetime.now()
|
|
if self.created_at is None:
|
|
self.created_at = datetime.now()
|
|
|
|
|
|
@dataclass
|
|
class Achievement:
|
|
"""Модель достижения"""
|
|
id: int
|
|
name: str
|
|
description: str
|
|
condition_type: str
|
|
condition_value: Any
|
|
badge: str
|
|
is_active: bool = True
|
|
|
|
|
|
@dataclass
|
|
class UserAchievement:
|
|
"""Модель разблокированного достижения пользователя"""
|
|
id: int
|
|
user_id: int
|
|
achievement_id: int
|
|
unlocked_at: datetime = None
|
|
|
|
def __post_init__(self):
|
|
if self.unlocked_at is None:
|
|
self.unlocked_at = datetime.now()
|
|
|
|
|
|
@dataclass
|
|
class Trigger:
|
|
"""Модель триггера"""
|
|
id: int
|
|
name: str
|
|
pattern: str # Регулярное выражение для сопоставления текста
|
|
description: Optional[str] = None
|
|
response_text: Optional[str] = None
|
|
response_sticker: Optional[str] = None
|
|
response_gif: Optional[str] = None
|
|
reaction_type: Optional[str] = None # "emoji" для реакции эмодзи
|
|
action_data: Optional[str] = None # Данные действия, например emoji
|
|
is_active: bool = True
|
|
created_by: int = 0
|
|
created_at: datetime = None
|
|
trigger_count: int = 0 # Количество срабатываний
|
|
last_triggered: Optional[datetime] = None
|
|
chat_type: str = "group" # "group" или "private"
|
|
|
|
def __post_init__(self):
|
|
if self.created_at is None:
|
|
self.created_at = datetime.now()
|
|
|
|
@dataclass
|
|
class Warning:
|
|
"""Модель предупреждения пользователя"""
|
|
id: int
|
|
user_id: int
|
|
reason: str
|
|
admin_id: int
|
|
created_at: datetime = None
|
|
|
|
def __post_init__(self):
|
|
if self.created_at is None:
|
|
self.created_at = datetime.now()
|
|
|
|
|
|
@dataclass
|
|
class Donation:
|
|
"""Модель доната пользователя"""
|
|
id: int
|
|
user_id: int
|
|
amount: float
|
|
year: int = None
|
|
created_at: datetime = None
|
|
|
|
def __post_init__(self):
|
|
if self.year is None:
|
|
self.year = datetime.now().year
|
|
if self.created_at is None:
|
|
self.created_at = datetime.now()
|
|
|
|
|
|
class DatabaseSchema:
|
|
"""Схема базы данных"""
|
|
|
|
TABLES = {
|
|
'roles': '''
|
|
CREATE TABLE IF NOT EXISTS roles (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
name TEXT UNIQUE NOT NULL,
|
|
display_name TEXT NOT NULL,
|
|
description TEXT,
|
|
permissions TEXT,
|
|
is_active BOOLEAN DEFAULT 1,
|
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
)
|
|
''',
|
|
|
|
'users': '''
|
|
CREATE TABLE IF NOT EXISTS users (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
telegram_id INTEGER UNIQUE NOT NULL,
|
|
username TEXT,
|
|
first_name TEXT,
|
|
last_name TEXT,
|
|
joined_date DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
last_activity DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
reputation INTEGER DEFAULT 0,
|
|
rank TEXT DEFAULT 'Новичок',
|
|
warnings INTEGER DEFAULT 0,
|
|
is_active BOOLEAN DEFAULT 1,
|
|
role_id INTEGER DEFAULT 1,
|
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
FOREIGN KEY (role_id) REFERENCES roles(id)
|
|
)
|
|
''',
|
|
|
|
'scores': '''
|
|
CREATE TABLE IF NOT EXISTS scores (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
user_id INTEGER UNIQUE NOT NULL,
|
|
total_score INTEGER DEFAULT 0,
|
|
message_count INTEGER DEFAULT 0,
|
|
game_wins INTEGER DEFAULT 0,
|
|
donations_total REAL DEFAULT 0.0,
|
|
last_updated DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
FOREIGN KEY (user_id) REFERENCES users(id)
|
|
)
|
|
''',
|
|
|
|
'errors': '''
|
|
CREATE TABLE IF NOT EXISTS errors (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
admin_id INTEGER NOT NULL,
|
|
error_type TEXT NOT NULL,
|
|
title TEXT NOT NULL,
|
|
description TEXT,
|
|
status TEXT DEFAULT 'new',
|
|
priority TEXT DEFAULT 'medium',
|
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
ai_analysis TEXT,
|
|
todo_added BOOLEAN DEFAULT 0,
|
|
resolved_at DATETIME,
|
|
FOREIGN KEY (admin_id) REFERENCES users(id)
|
|
)
|
|
''',
|
|
|
|
'scheduled_posts': '''
|
|
CREATE TABLE IF NOT EXISTS scheduled_posts (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
chat_id INTEGER NOT NULL,
|
|
text TEXT NOT NULL,
|
|
image_path TEXT,
|
|
schedule_time DATETIME NOT NULL,
|
|
created_by INTEGER DEFAULT 0,
|
|
status TEXT DEFAULT 'pending',
|
|
published_at DATETIME,
|
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
)
|
|
''',
|
|
|
|
'achievements': '''
|
|
CREATE TABLE IF NOT EXISTS achievements (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
name TEXT UNIQUE NOT NULL,
|
|
description TEXT NOT NULL,
|
|
condition_type TEXT NOT NULL,
|
|
condition_value TEXT NOT NULL,
|
|
badge TEXT NOT NULL,
|
|
is_active BOOLEAN DEFAULT 1,
|
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
)
|
|
''',
|
|
|
|
'user_achievements': '''
|
|
CREATE TABLE IF NOT EXISTS user_achievements (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
user_id INTEGER NOT NULL,
|
|
achievement_id INTEGER NOT NULL,
|
|
unlocked_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
FOREIGN KEY (user_id) REFERENCES users(id),
|
|
FOREIGN KEY (achievement_id) REFERENCES achievements(id),
|
|
UNIQUE(user_id, achievement_id)
|
|
)
|
|
''',
|
|
|
|
'warnings': '''
|
|
CREATE TABLE IF NOT EXISTS warnings (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
user_id INTEGER NOT NULL,
|
|
reason TEXT NOT NULL,
|
|
admin_id INTEGER NOT NULL,
|
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
FOREIGN KEY (user_id) REFERENCES users(id),
|
|
FOREIGN KEY (admin_id) REFERENCES users(id)
|
|
)
|
|
''',
|
|
|
|
'donations': '''
|
|
CREATE TABLE IF NOT EXISTS donations (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
user_id INTEGER NOT NULL,
|
|
amount REAL NOT NULL,
|
|
year INTEGER NOT NULL DEFAULT (strftime('%Y', 'now')),
|
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
FOREIGN KEY (user_id) REFERENCES users(id)
|
|
)
|
|
''',
|
|
|
|
'payments': '''
|
|
CREATE TABLE IF NOT EXISTS payments (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
user_id INTEGER NOT NULL,
|
|
amount REAL NOT NULL,
|
|
currency TEXT DEFAULT 'RUB',
|
|
provider TEXT NOT NULL, -- 'stripe' или 'yookassa'
|
|
external_id TEXT UNIQUE NOT NULL,
|
|
status TEXT DEFAULT 'pending',
|
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
processed_at DATETIME,
|
|
metadata TEXT, -- JSON
|
|
error_message TEXT,
|
|
FOREIGN KEY (user_id) REFERENCES users(id)
|
|
)
|
|
''',
|
|
|
|
'transactions': '''
|
|
CREATE TABLE IF NOT EXISTS transactions (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
payment_id INTEGER NOT NULL,
|
|
type TEXT NOT NULL, -- 'payment', 'refund'
|
|
amount REAL NOT NULL,
|
|
status TEXT NOT NULL,
|
|
external_transaction_id TEXT,
|
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
details TEXT, -- JSON
|
|
FOREIGN KEY (payment_id) REFERENCES payments(id)
|
|
)
|
|
''',
|
|
|
|
'triggers': '''
|
|
CREATE TABLE IF NOT EXISTS triggers (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
name TEXT NOT NULL,
|
|
description TEXT,
|
|
pattern TEXT NOT NULL,
|
|
response_text TEXT,
|
|
response_sticker TEXT,
|
|
response_gif TEXT,
|
|
reaction_type TEXT,
|
|
action_data TEXT,
|
|
is_active BOOLEAN DEFAULT 1,
|
|
created_by INTEGER DEFAULT 0,
|
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
trigger_count INTEGER DEFAULT 0,
|
|
last_triggered DATETIME,
|
|
chat_type TEXT DEFAULT 'group'
|
|
)
|
|
''',
|
|
|
|
}
|
|
|
|
@classmethod
|
|
def get_create_tables_sql(cls) -> List[str]:
|
|
"""Получение SQL для создания всех таблиц"""
|
|
return list(cls.TABLES.values())
|
|
|
|
@classmethod
|
|
def get_table_names(cls) -> List[str]:
|
|
"""Получение списка имен таблиц"""
|
|
return list(cls.TABLES.keys()) |