501 lines
8.8 KiB
Python
501 lines
8.8 KiB
Python
import aiosqlite
|
|
from datetime import datetime
|
|
import json
|
|
|
|
|
|
DB_NAME = "database/database.db"
|
|
|
|
|
|
async def init_db():
|
|
|
|
async with aiosqlite.connect(DB_NAME) as db:
|
|
|
|
# Пользователи
|
|
await db.execute("""
|
|
CREATE TABLE IF NOT EXISTS users(
|
|
|
|
user_id INTEGER PRIMARY KEY,
|
|
|
|
username TEXT,
|
|
|
|
first_name TEXT,
|
|
|
|
last_name TEXT,
|
|
|
|
phone TEXT,
|
|
|
|
email TEXT,
|
|
|
|
group_id INTEGER,
|
|
|
|
group_name TEXT,
|
|
|
|
subgroup TEXT,
|
|
|
|
created_at TEXT,
|
|
|
|
last_seen TEXT
|
|
|
|
)
|
|
""")
|
|
|
|
# Кэш расписания
|
|
await db.execute("""
|
|
CREATE TABLE IF NOT EXISTS schedule_cache(
|
|
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
|
|
group_id INTEGER NOT NULL,
|
|
|
|
date TEXT NOT NULL,
|
|
|
|
data TEXT NOT NULL,
|
|
|
|
created_at TEXT NOT NULL,
|
|
|
|
UNIQUE(group_id, date)
|
|
|
|
)
|
|
""")
|
|
|
|
# Индекс
|
|
await db.execute("""
|
|
CREATE INDEX IF NOT EXISTS idx_schedule_cache
|
|
ON schedule_cache(group_id, date)
|
|
""")
|
|
|
|
# Поддержка
|
|
await db.execute("""
|
|
CREATE TABLE IF NOT EXISTS support(
|
|
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
|
|
user_id INTEGER NOT NULL,
|
|
|
|
message TEXT NOT NULL,
|
|
|
|
answer TEXT,
|
|
|
|
status TEXT DEFAULT 'open',
|
|
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
|
|
)
|
|
""")
|
|
|
|
await db.commit()
|
|
|
|
async def save_group(
|
|
user_id: int,
|
|
group_id: int,
|
|
group_name: str,
|
|
subgroup: str | None = None
|
|
):
|
|
|
|
async with aiosqlite.connect(DB_NAME) as db:
|
|
|
|
await db.execute(
|
|
"""
|
|
INSERT INTO users(
|
|
user_id,
|
|
group_id,
|
|
group_name,
|
|
subgroup
|
|
)
|
|
|
|
VALUES(?,?,?,?)
|
|
|
|
ON CONFLICT(user_id)
|
|
|
|
DO UPDATE SET
|
|
|
|
group_id = excluded.group_id,
|
|
|
|
group_name = excluded.group_name,
|
|
|
|
subgroup = excluded.subgroup
|
|
|
|
""",
|
|
(
|
|
user_id,
|
|
group_id,
|
|
group_name,
|
|
subgroup
|
|
)
|
|
)
|
|
|
|
await db.commit()
|
|
|
|
|
|
|
|
async def get_group(
|
|
user_id: int
|
|
):
|
|
|
|
async with aiosqlite.connect(DB_NAME) as db:
|
|
|
|
cursor = await db.execute(
|
|
"""
|
|
SELECT
|
|
|
|
group_id,
|
|
|
|
group_name,
|
|
|
|
subgroup
|
|
|
|
FROM users
|
|
|
|
WHERE user_id=?
|
|
|
|
""",
|
|
(
|
|
user_id,
|
|
)
|
|
)
|
|
|
|
|
|
row = await cursor.fetchone()
|
|
|
|
|
|
if row is None:
|
|
return None
|
|
|
|
|
|
return {
|
|
|
|
"group_id": row[0],
|
|
|
|
"group_name": row[1],
|
|
|
|
"subgroup": row[2]
|
|
|
|
}
|
|
|
|
|
|
|
|
async def delete_group(
|
|
user_id: int
|
|
):
|
|
|
|
async with aiosqlite.connect(DB_NAME) as db:
|
|
|
|
await db.execute(
|
|
"""
|
|
DELETE FROM users
|
|
|
|
WHERE user_id=?
|
|
|
|
""",
|
|
(
|
|
user_id,
|
|
)
|
|
)
|
|
|
|
await db.commit()
|
|
|
|
|
|
|
|
async def update_subgroup(
|
|
user_id: int,
|
|
subgroup: str
|
|
):
|
|
|
|
async with aiosqlite.connect(DB_NAME) as db:
|
|
|
|
await db.execute(
|
|
"""
|
|
UPDATE users
|
|
|
|
SET subgroup=?
|
|
|
|
WHERE user_id=?
|
|
|
|
""",
|
|
(
|
|
subgroup,
|
|
user_id
|
|
)
|
|
)
|
|
|
|
await db.commit()
|
|
|
|
async def create_ticket(
|
|
user_id: int,
|
|
message: str
|
|
):
|
|
|
|
async with aiosqlite.connect(DB_NAME) as db:
|
|
|
|
cursor = await db.execute(
|
|
"""
|
|
INSERT INTO support(
|
|
user_id,
|
|
message
|
|
)
|
|
VALUES(?,?)
|
|
""",
|
|
(
|
|
user_id,
|
|
message
|
|
)
|
|
)
|
|
|
|
await db.commit()
|
|
|
|
return cursor.lastrowid
|
|
|
|
#tickets
|
|
async def get_ticket(ticket_id: int):
|
|
|
|
async with aiosqlite.connect(DB_NAME) as db:
|
|
|
|
cursor = await db.execute(
|
|
"""
|
|
SELECT
|
|
id,
|
|
user_id,
|
|
message,
|
|
status
|
|
FROM support
|
|
WHERE id=?
|
|
""",
|
|
(ticket_id,)
|
|
)
|
|
|
|
row = await cursor.fetchone()
|
|
|
|
return row
|
|
|
|
async def get_tickets():
|
|
|
|
async with aiosqlite.connect(DB_NAME) as db:
|
|
|
|
cursor = await db.execute(
|
|
"""
|
|
SELECT
|
|
id,
|
|
user_id,
|
|
message,
|
|
status
|
|
FROM support
|
|
WHERE status='open'
|
|
ORDER BY id DESC
|
|
"""
|
|
)
|
|
|
|
rows = await cursor.fetchall()
|
|
|
|
return rows
|
|
|
|
async def close_ticket(ticket_id: int):
|
|
|
|
async with aiosqlite.connect(DB_NAME) as db:
|
|
|
|
await db.execute(
|
|
"""
|
|
UPDATE support
|
|
SET status='closed'
|
|
WHERE id=?
|
|
""",
|
|
(ticket_id,)
|
|
)
|
|
|
|
await db.commit()
|
|
|
|
|
|
async def update_user(
|
|
user_id: int,
|
|
username: str | None = None,
|
|
first_name: str | None = None,
|
|
last_name: str | None = None
|
|
):
|
|
|
|
now = datetime.now().isoformat()
|
|
|
|
|
|
async with aiosqlite.connect(DB_NAME) as db:
|
|
|
|
await db.execute(
|
|
"""
|
|
INSERT INTO users(
|
|
user_id,
|
|
username,
|
|
first_name,
|
|
last_name,
|
|
created_at,
|
|
last_seen
|
|
)
|
|
|
|
VALUES(?,?,?,?,?,?)
|
|
|
|
ON CONFLICT(user_id)
|
|
|
|
DO UPDATE SET
|
|
|
|
username=excluded.username,
|
|
first_name=excluded.first_name,
|
|
last_name=excluded.last_name,
|
|
last_seen=excluded.last_seen
|
|
|
|
""",
|
|
|
|
(
|
|
user_id,
|
|
username,
|
|
first_name,
|
|
last_name,
|
|
now,
|
|
now
|
|
)
|
|
)
|
|
|
|
|
|
await db.commit()
|
|
|
|
async def save_phone(
|
|
user_id: int,
|
|
phone: str
|
|
):
|
|
|
|
async with aiosqlite.connect(DB_NAME) as db:
|
|
|
|
await db.execute(
|
|
"""
|
|
UPDATE users
|
|
SET phone=?
|
|
WHERE user_id=?
|
|
""",
|
|
(
|
|
phone,
|
|
user_id
|
|
)
|
|
)
|
|
|
|
await db.commit()
|
|
|
|
async def get_cached_schedule(
|
|
group_id: int,
|
|
schedule_date: str,
|
|
ttl_minutes: int
|
|
):
|
|
|
|
async with aiosqlite.connect(DB_NAME) as db:
|
|
|
|
cursor = await db.execute(
|
|
"""
|
|
SELECT
|
|
data,
|
|
created_at
|
|
|
|
FROM schedule_cache
|
|
|
|
WHERE group_id=?
|
|
AND date=?
|
|
|
|
""",
|
|
(
|
|
group_id,
|
|
schedule_date
|
|
)
|
|
)
|
|
|
|
row = await cursor.fetchone()
|
|
|
|
|
|
if row is None:
|
|
return None
|
|
|
|
|
|
created = datetime.fromisoformat(
|
|
row[1]
|
|
)
|
|
|
|
|
|
age = (
|
|
datetime.now() - created
|
|
).total_seconds() / 60
|
|
|
|
|
|
# кэш устарел
|
|
|
|
if age > ttl_minutes:
|
|
|
|
return None
|
|
|
|
|
|
return json.loads(row[0])
|
|
|
|
async def save_schedule_cache(
|
|
group_id: int,
|
|
schedule_date: str,
|
|
data: dict
|
|
):
|
|
|
|
async with aiosqlite.connect(DB_NAME) as db:
|
|
|
|
await db.execute(
|
|
"""
|
|
INSERT INTO schedule_cache(
|
|
group_id,
|
|
date,
|
|
data,
|
|
created_at
|
|
)
|
|
|
|
VALUES(?,?,?,?)
|
|
|
|
ON CONFLICT(group_id, date)
|
|
|
|
DO UPDATE SET
|
|
|
|
data = excluded.data,
|
|
created_at = excluded.created_at
|
|
""",
|
|
(
|
|
group_id,
|
|
schedule_date,
|
|
json.dumps(
|
|
data,
|
|
ensure_ascii=False
|
|
),
|
|
datetime.now().isoformat()
|
|
)
|
|
)
|
|
|
|
await db.commit()
|
|
|
|
|
|
async def clear_old_cache(days: int = 30):
|
|
|
|
async with aiosqlite.connect(DB_NAME) as db:
|
|
|
|
cursor = await db.execute(
|
|
"""
|
|
DELETE FROM schedule_cache
|
|
WHERE datetime(created_at)
|
|
< datetime('now', ?)
|
|
""",
|
|
(f"-{days} days",)
|
|
)
|
|
|
|
await db.commit()
|
|
|
|
return cursor.rowcount
|
|
|
|
|
|
async def get_active_groups():
|
|
|
|
async with aiosqlite.connect(DB_NAME) as db:
|
|
|
|
cursor = await db.execute(
|
|
"""
|
|
SELECT DISTINCT group_id
|
|
FROM users
|
|
WHERE group_id IS NOT NULL
|
|
"""
|
|
)
|
|
|
|
rows = await cursor.fetchall()
|
|
|
|
return [row[0] for row in rows] |