Напоминалки: выбор часового пояса кнопками городов + ручной ввод
При гейте часового пояса теперь показывается клавиатура с частыми российскими городами-поясами (Калининград..Камчатка). Клик по кнопке шлёт 'Город, UTC+N' — _parse_tz_offset распознаёт и это, и обычный ручной ввод вида '+3'/'-5', если своего города в списке нет. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -488,12 +488,16 @@ class VKBotApplication:
|
|||||||
return f"{name} (vk.com/id{uid})" if name else f"vk.com/id{uid}"
|
return f"{name} (vk.com/id{uid})" if name else f"vk.com/id{uid}"
|
||||||
|
|
||||||
def _parse_tz_offset(self, raw: str) -> Optional[int]:
|
def _parse_tz_offset(self, raw: str) -> Optional[int]:
|
||||||
"""Парсит смещение от UTC вида '+3', '-5', '0'. None, если не число
|
"""Парсит смещение от UTC: либо чистое число '+3'/'-5'/'0' (ручной ввод),
|
||||||
или вне диапазона реальных часовых поясов (-12..+14)."""
|
либо 'Город, UTC+N' (клик по кнопке get_timezone_keyboard). None, если
|
||||||
|
не удалось распознать или число вне диапазона реальных поясов (-12..+14)."""
|
||||||
raw = raw.strip()
|
raw = raw.strip()
|
||||||
if not re.match(r"^[+-]?\d{1,2}$", raw):
|
m = re.search(r"UTC\s*([+-]?\d{1,2})\s*$", raw, re.I)
|
||||||
|
if not m:
|
||||||
|
m = re.match(r"^([+-]?\d{1,2})$", raw)
|
||||||
|
if not m:
|
||||||
return None
|
return None
|
||||||
val = int(raw)
|
val = int(m.group(1))
|
||||||
return val if -12 <= val <= 14 else None
|
return val if -12 <= val <= 14 else None
|
||||||
|
|
||||||
def _require_reminder_tz(self, user_id: int) -> bool:
|
def _require_reminder_tz(self, user_id: int) -> bool:
|
||||||
@@ -505,9 +509,10 @@ class VKBotApplication:
|
|||||||
db.update_user_state(user_id, "ADMIN_REMINDER_TZ_SETUP")
|
db.update_user_state(user_id, "ADMIN_REMINDER_TZ_SETUP")
|
||||||
self.send_message(
|
self.send_message(
|
||||||
user_id,
|
user_id,
|
||||||
"🌐 Прежде чем пользоваться напоминалками, укажите свой часовой пояс "
|
"🌐 Прежде чем пользоваться напоминалками, укажите свой часовой пояс.\n"
|
||||||
"относительно UTC.\nНапример: +3 (Москва), +5 (Екатеринбург), 0 (UTC).",
|
"Выберите город кнопкой ниже, либо введите смещение от UTC вручную "
|
||||||
keyboard=get_cancel_admin_keyboard()
|
"(например, +3), если своего города в списке нет.",
|
||||||
|
keyboard=get_timezone_keyboard()
|
||||||
)
|
)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@@ -1784,8 +1789,9 @@ class VKBotApplication:
|
|||||||
if state == "ADMIN_REMINDER_TZ_SETUP":
|
if state == "ADMIN_REMINDER_TZ_SETUP":
|
||||||
offset = self._parse_tz_offset(text)
|
offset = self._parse_tz_offset(text)
|
||||||
if offset is None:
|
if offset is None:
|
||||||
self.send_message(user_id, "⚠️ Формат: число от -12 до +14, например +3 или -5.",
|
self.send_message(user_id, "⚠️ Выберите город кнопкой ниже, либо введите число "
|
||||||
keyboard=get_cancel_admin_keyboard())
|
"от -12 до +14 вручную, например +3 или -5.",
|
||||||
|
keyboard=get_timezone_keyboard())
|
||||||
return
|
return
|
||||||
db.set_admin_tz_offset(user_id, offset)
|
db.set_admin_tz_offset(user_id, offset)
|
||||||
db.update_user_state(user_id, "FREE_CHAT")
|
db.update_user_state(user_id, "FREE_CHAT")
|
||||||
|
|||||||
@@ -213,6 +213,27 @@ def get_reminders_admin_keyboard() -> str:
|
|||||||
return keyboard.get_keyboard()
|
return keyboard.get_keyboard()
|
||||||
|
|
||||||
|
|
||||||
|
def get_timezone_keyboard() -> str:
|
||||||
|
"""Клавиатура выбора часового пояса: частые российские города-пояса
|
||||||
|
кнопками (кнопка шлёт 'Город, UTC±N' — _parse_tz_offset вытаскивает
|
||||||
|
смещение из этого текста), плюс можно просто ввести своё смещение
|
||||||
|
вручную, если города в списке нет."""
|
||||||
|
cities = [
|
||||||
|
("Калининград", 2), ("Москва", 3), ("Самара", 4),
|
||||||
|
("Екатеринбург", 5), ("Омск", 6), ("Красноярск", 7),
|
||||||
|
("Иркутск", 8), ("Якутск", 9), ("Владивосток", 10),
|
||||||
|
("Магадан", 11), ("Камчатка", 12),
|
||||||
|
]
|
||||||
|
keyboard = VkKeyboard(one_time=False)
|
||||||
|
for i, (city, offset) in enumerate(cities):
|
||||||
|
if i and i % 2 == 0:
|
||||||
|
keyboard.add_line()
|
||||||
|
keyboard.add_button(f"{city}, UTC+{offset}", color=VkKeyboardColor.SECONDARY)
|
||||||
|
keyboard.add_line()
|
||||||
|
keyboard.add_button("Отмена ❌", color=VkKeyboardColor.NEGATIVE)
|
||||||
|
return keyboard.get_keyboard()
|
||||||
|
|
||||||
|
|
||||||
def get_pick_keyboard(items: list) -> str:
|
def get_pick_keyboard(items: list) -> str:
|
||||||
"""Клавиатура выбора из списка пар (id, label). Кнопка отправляет '<id>. <label>'."""
|
"""Клавиатура выбора из списка пар (id, label). Кнопка отправляет '<id>. <label>'."""
|
||||||
keyboard = VkKeyboard(one_time=False)
|
keyboard = VkKeyboard(one_time=False)
|
||||||
|
|||||||
@@ -459,6 +459,19 @@ def test_reminder_tz_gate_before_list(app, monkeypatch):
|
|||||||
assert _state(admin) == "FREE_CHAT"
|
assert _state(admin) == "FREE_CHAT"
|
||||||
|
|
||||||
|
|
||||||
|
def test_reminder_tz_setup_via_city_button(app, monkeypatch):
|
||||||
|
"""Часовой пояс можно выбрать кнопкой города, а не только вводом числа."""
|
||||||
|
admin = 80010
|
||||||
|
monkeypatch.setattr(bot.config, "ADMIN_IDS", [admin])
|
||||||
|
|
||||||
|
app.handle_message(admin, "⏰ Напоминалки")
|
||||||
|
assert _state(admin) == "ADMIN_REMINDER_TZ_SETUP"
|
||||||
|
|
||||||
|
app.handle_message(admin, "Екатеринбург, UTC+5") # клик по кнопке клавиатуры
|
||||||
|
assert _state(admin) == "FREE_CHAT"
|
||||||
|
assert bot.db.get_admin_tz_offset(admin) == 5
|
||||||
|
|
||||||
|
|
||||||
def test_reminder_creation_converts_author_local_time_to_server(app, monkeypatch):
|
def test_reminder_creation_converts_author_local_time_to_server(app, monkeypatch):
|
||||||
admin = 80007
|
admin = 80007
|
||||||
monkeypatch.setattr(bot.config, "ADMIN_IDS", [admin])
|
monkeypatch.setattr(bot.config, "ADMIN_IDS", [admin])
|
||||||
|
|||||||
Reference in New Issue
Block a user