Супер-админ, выбор даты/времени звонка, инлайн-документы, маска телефона

- Супер-админ (config.SUPER_ADMIN_IDS, только через код): добавляет/удаляет
  обычных админов из бота (раздел «Администраторы 👑»), таблица admins.
  _is_admin теперь учитывает супер-админов, .env и добавленных из бота.
- «Когда удобно созвониться» → выбор конкретного дня (кнопки на ближайшие даты)
  и времени (слоты), сохраняется как «День, ЧЧ:ММ».
- Шаг согласия: инлайн-кнопки со ссылками на оферту и политику ПД (PDF), затем
  подтверждение. Старое вложение .docx убрано.
- Маска отображения телефона: +7 (999) 123-45-67 в карточке и уведомлениях.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Kenik
2026-06-24 18:39:19 +03:00
parent ab7df0644e
commit 29097a18c3
3 changed files with 236 additions and 53 deletions
+32
View File
@@ -123,6 +123,14 @@ class DatabaseManager:
except sqlite3.OperationalError:
pass
# Table for runtime-added admins (добавляются супер-админом из бота)
cursor.execute("""
CREATE TABLE IF NOT EXISTS admins (
user_id INTEGER PRIMARY KEY,
added_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
""")
# Table for editable quick FAQ answers (быстрые ответы по ключевым словам)
cursor.execute("""
CREATE TABLE IF NOT EXISTS custom_faq (
@@ -426,6 +434,30 @@ class DatabaseManager:
)
conn.commit()
# --- Администраторы (добавленные в рантайме супер-админом) ---
def add_admin(self, user_id: int) -> bool:
with self._get_connection() as conn:
cursor = conn.cursor()
try:
cursor.execute("INSERT INTO admins (user_id) VALUES (?)", (user_id,))
conn.commit()
return True
except sqlite3.IntegrityError:
return False # уже админ
def remove_admin(self, user_id: int) -> bool:
with self._get_connection() as conn:
cursor = conn.cursor()
cursor.execute("DELETE FROM admins WHERE user_id = ?", (user_id,))
conn.commit()
return cursor.rowcount > 0
def get_admins(self) -> list:
with self._get_connection() as conn:
cursor = conn.cursor()
cursor.execute("SELECT user_id FROM admins ORDER BY user_id")
return [r[0] for r in cursor.fetchall()]
# --- Быстрые ответы (custom FAQ) ---
def add_custom_faq(self, keyword: str, answer: str) -> int:
with self._get_connection() as conn: