{"id":51521326,"url":"https://github.com/nimos95/otskvm-vk-teams-bot","last_synced_at":"2026-07-08T16:01:16.877Z","repository":{"id":365432308,"uuid":"1270120546","full_name":"Nimos95/otskvm-vk-teams-bot","owner":"Nimos95","description":"Бот для инженеров технического сопровождения конгрессно-выставочных мероприятий СПбПУ. Бот позволяет быстро отмечать состояние аудиторий, отслеживать проблемы, координировать работу и интегрироваться с Google Calendar.","archived":false,"fork":false,"pushed_at":"2026-06-24T11:39:25.000Z","size":108,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-24T12:21:43.350Z","etag":null,"topics":["bot","google-calendar-api","postgresql","python","vk-teams"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Nimos95.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-06-15T12:05:37.000Z","updated_at":"2026-06-24T11:39:29.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/Nimos95/otskvm-vk-teams-bot","commit_stats":null,"previous_names":["nimos95/otskvm-vk-teams-bot"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/Nimos95/otskvm-vk-teams-bot","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Nimos95%2Fotskvm-vk-teams-bot","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Nimos95%2Fotskvm-vk-teams-bot/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Nimos95%2Fotskvm-vk-teams-bot/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Nimos95%2Fotskvm-vk-teams-bot/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Nimos95","download_url":"https://codeload.github.com/Nimos95/otskvm-vk-teams-bot/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Nimos95%2Fotskvm-vk-teams-bot/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35270196,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-08T02:00:06.796Z","response_time":61,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bot","google-calendar-api","postgresql","python","vk-teams"],"created_at":"2026-07-08T16:01:15.688Z","updated_at":"2026-07-08T16:01:16.857Z","avatar_url":"https://github.com/Nimos95.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# 🤖 OTSKVM VK Teams Bot\n\nБот для учёта состояния аудиторий и интеграции с Google Calendar в VK Workspace.\n\n[![Python](https://img.shields.io/badge/Python-3.6-3776AB?style=for-the-badge\u0026logo=python\u0026logoColor=white)](https://python.org)\n[![VK Teams](https://img.shields.io/badge/VK%20Teams-Bot%20API-0077FF?style=for-the-badge\u0026logo=vk\u0026logoColor=white)](https://teams.vk.com/botapi/)\n[![PostgreSQL](https://img.shields.io/badge/PostgreSQL-18-4169E1?style=for-the-badge\u0026logo=postgresql\u0026logoColor=white)](https://postgresql.org)\n[![Google Calendar](https://img.shields.io/badge/Google%20Calendar-API-4285F4?style=for-the-badge\u0026logo=google\u0026logoColor=white)](https://developers.google.com/calendar)\n\n---\n\n## 📋 О проекте\n\n**OTSKVM VK Teams Bot** — бот для инженеров технического сопровождения конгрессно-выставочных мероприятий СПбПУ. Бот позволяет быстро отмечать состояние аудиторий, отслеживать проблемы, координировать работу и интегрироваться с Google Calendar.\n\nПроект разработан для автоматизации процессов отдела и перехода от реактивного обслуживания к проактивному управлению инфраструктурой.\n\n---\n\n## 🎯 Возможности\n\n### ✅ Реализовано\n\n#### 📅 **Интеграция с Google Calendar**\n- ✅ Команда `/today` — мероприятия на сегодня\n- ✅ Команда `/tomorrow` — мероприятия на завтра\n- ✅ Команда `/week` — мероприятия на неделю с группировкой по дням\n- ✅ Команда `/sync` — принудительная синхронизация с Google Calendar\n- ✅ Автоматическое кэширование событий в PostgreSQL\n- ✅ Поддержка событий на целый день и с конкретным временем\n- ✅ Русские названия дней недели\n- ✅ MarkdownV2-форматирование (жирный шрифт)\n- ✅ Модальные окна с результатами синхронизации\n\n#### 🏛️ **Привязка событий к аудиториям**\n- ✅ Автоматическое извлечение названия аудитории из `location` события\n- ✅ Нормализация названий через словарь синонимов\n- ✅ Отображение аудитории и здания в сообщениях\n- ✅ Логирование ненайденных аудиторий для пополнения словаря\n\n#### 🟢 **Учёт статусов аудиторий** \n- ✅ Команда `/status` — просмотр текущих статусов всех аудиторий\n- ✅ Команда `/set_status` — интерактивная отметка статуса с выбором аудитории\n- ✅ Инлайн-кнопки для быстрого выбора статуса (🟢 Всё работает, 🟡 Есть проблемы, 🔴 Не работает)\n- ✅ Карточка аудитории с информацией о текущем статусе\n- ✅ Изменение статуса с обязательным комментарием\n- ✅ Кнопка «⏭️ Сохранить без комментария»\n- ✅ Подтверждение сохранения статуса\n- ✅ Уведомления в общий чат при отметке 🟡/🔴\n- ✅ Статистика по статусам в админ-панели\n- ✅ История статусов с указанием времени и автора\n- ✅ Права доступа: только Engineer+ могут менять статусы\n- ✅ Автоматическое обновление списка аудиторий после сохранения статуса\n\n\n#### 🎛️ **Навигация и интерфейс**\n- ✅ Главное меню с инлайн-кнопками (команда `/start`)\n- ✅ Динамическое меню в зависимости от роли пользователя\n- ✅ Админ-панель с разграничением по ролям\n- ✅ Модальные окна для результатов действий\n- ✅ Редактирование сообщений вместо отправки новых\n- ✅ Вертикальное расположение кнопок для удобства на мобильных устройствах\n\n#### 👥 **Управление пользователями и ролями**\n- ✅ Автоматическая регистрация новых пользователей\n- ✅ Команда `/my_role` — просмотр своей роли\n- ✅ Команда `/set_role` — назначение роли (только Superadmin)\n- ✅ Команда `/list_users` — список всех пользователей\n- ✅ Ролевая модель:\n  - **Viewer** — только просмотр календаря\n  - **Engineer** — календарь + статусы + мои мероприятия\n  - **Admin** — все технические операции + админ-панель\n  - **Manager** — календарь + отчётность\n  - **Superadmin** — полный доступ\n\n#### 🏗️ **Архитектура**\n- ✅ Модульная структура (легко добавлять новые функции)\n- ✅ Единый диспетчер callback-событий\n- ✅ Синхронный драйвер БД (psycopg2)\n- ✅ Фильтрация чатов (личные vs групповые)\n- ✅ База данных PostgreSQL с пулом соединений\n- ✅ Безопасная обработка сигналов (корректный Ctrl+C)\n\n---\n\n## 🛠 Технологический стек\n\n| Компонент | Технология | Версия |\n|-----------|------------|--------|\n| **Язык программирования** | Python | 3.6 |\n| **VK Teams Bot API** | mailru-im-bot | latest |\n| **База данных** | PostgreSQL | 18.x |\n| **Синхронный драйвер БД** | psycopg2-binary | 2.9.3 |\n| **Асинхронный драйвер БД** | asyncpg | 0.30.0 |\n| **Google Calendar API** | google-api-python-client | 1.12.8 |\n| **Парсинг дат** | python-dateutil | 2.8.2 |\n| **Транслитерация** | cyrtranslit | 0.9.2 |\n| **Конфигурация** | python-dotenv | 1.0.0 |\n\n---\n\n## 🔐 Матрица доступа\n\n### 📊 Сводная таблица\n\n| Функция / Роль | Viewer | Engineer | Admin | Manager | Superadmin |\n|----------------|:------:|:--------:|:-----:|:-------:|:----------:|\n| **Календарь** | | | | | |\n| Просмотр событий (`/today`, `/tomorrow`, `/week`) | ✅ | ✅ | ✅ | ✅ | ✅ |\n| Синхронизация (`/sync`) | ❌ | ❌ | ✅ | ❌ | ✅ |\n| **Аудитории** | | | | | |\n| Просмотр статусов аудиторий | ✅ | ✅ | ✅ | ✅ | ✅ |\n| Отметка статуса аудитории (`/set_status`) | ❌ | ✅ | ✅ | ❌ | ✅ |\n| История статусов аудитории | ✅ | ✅ | ✅ | ✅ | ✅ |\n| **Назначения** | | | | | |\n| Просмотр своих мероприятий | ❌ | ✅ | ✅ | ❌ | ✅ |\n| Назначение инженера на мероприятие (`/assign`) | ❌ | ❌ | ✅ | ❌ | ✅ |\n| Подтверждение/отказ от назначения | ❌ | ✅ | ✅ | ❌ | ✅ |\n| Просмотр всех назначений | ❌ | ❌ | ✅ | ✅ | ✅ |\n| **Пользователи** | | | | | |\n| Просмотр своего профиля (`/my_role`) | ✅ | ✅ | ✅ | ✅ | ✅ |\n| Список всех пользователей (`/list_users`) | ❌ | ❌ | ✅ | ✅ | ✅ |\n| Назначение роли (`/set_role`) | ❌ | ❌ | ❌ | ❌ | ✅ |\n| **Отчётность** | | | | | |\n| Статистика (`/stats`) | ❌ | ❌ | ✅ | ✅ | ✅ |\n| **Администрирование** | | | | | |\n| Доступ к админ-панели | ❌ | ❌ | ✅ | ❌ | ✅ |\n\n---\n\n### 📋 Описание ролей\n\n| Роль | Должность | Описание | Ключевые права |\n|------|-----------|----------|----------------|\n| **Superadmin** | Разработчик, главный администратор | Полный контроль над системой | ✅ Всё, включая управление пользователями и ролями |\n| **Admin** | Начальник отдела | Оперативное управление, участие в работе | 🔧 Все технические операции, админ-панель |\n| **Manager** | Начальник управления | Стратегическое управление, контроль работы отдела | 📊 Статистика, список пользователей, просмотр назначений |\n| **Engineer** | Инженер | Исполнение задач, работа с аудиториями | 🛠️ Статусы, свои мероприятия |\n| **Viewer** | Внешний наблюдатель | Только просмотр | 👁️ Календарь, статусы аудиторий |\n\n---\n\n### 📝 Команды и их доступность\n\n| Команда | Viewer | Engineer | Admin | Manager | Superadmin |\n|---------|:------:|:--------:|:-----:|:-------:|:----------:|\n| `/start` | ✅ | ✅ | ✅ | ✅ | ✅ |\n| `/help` | ✅ | ✅ | ✅ | ✅ | ✅ |\n| `/today` | ✅ | ✅ | ✅ | ✅ | ✅ |\n| `/tomorrow` | ✅ | ✅ | ✅ | ✅ | ✅ |\n| `/week` | ✅ | ✅ | ✅ | ✅ | ✅ |\n| `/sync` | ❌ | ❌ | ✅ | ❌ | ✅ |\n| `/my_role` | ✅ | ✅ | ✅ | ✅ | ✅ |\n| `/list_users` | ❌ | ❌ | ✅ | ✅ | ✅ |\n| `/set_role` | ❌ | ❌ | ❌ | ❌ | ✅ |\n| `/status` | ✅ | ✅ | ✅ | ✅ | ✅ |\n| `/set_status` | ❌ | ✅ | ✅ | ❌ | ✅ |\n| `/assign` | ❌ | ❌ | ✅ | ❌ | ✅ |\n| `/my_assignments` | ❌ | ✅ | ✅ | ❌ | ✅ |\n| `/stats` | ❌ | ❌ | ✅ | ✅ | ✅ |\n| `/history` | ✅ | ✅ | ✅ | ✅ | ✅ |\n\n---\n\n### ✅ Итоговая логика ролей\n\n| Роль | Календарь | Статусы | Назначения | Пользователи | Отчётность | Админ-панель |\n|------|:---------:|:-------:|:----------:|:------------:|:----------:|:------------:|\n| **Viewer** | ✅ (просмотр) | ✅ (просмотр) | ❌ | ❌ | ❌ | ❌ |\n| **Engineer** | ✅ (просмотр) | ✅ (изменение) | ✅ (свои) | ❌ | ❌ | ❌ |\n| **Admin** | ✅ (всё) | ✅ (всё) | ✅ (все) | ✅ (просмотр) | ✅ | ✅ (ограниченная) |\n| **Manager** | ✅ (просмотр) | ✅ (просмотр) | ✅ (просмотр) | ✅ (просмотр) | ✅ | ❌ |\n| **Superadmin** | ✅ (всё) | ✅ (всё) | ✅ (все) | ✅ (полный) | ✅ | ✅ (полная) |\n\n---\n\n### 🔒 Принципы назначения ролей\n\n1. **Viewer** — автоматически при первом обращении к боту.\n2. **Engineer** — назначается администратором или суперадминистратором.\n3. **Manager** — назначается администратором или суперадминистратором.\n4. **Admin** — назначается только суперадминистратором.\n5. **Superadmin** — назначается только вручную через БД (или другим суперадминистратором).\n\n---\n\n### 📊 Сравнение ролей: ключевые различий\n\n| Характеристика | Viewer | Engineer | Admin | Manager | Superadmin |\n|----------------|:------:|:--------:|:-----:|:-------:|:----------:|\n| Может отмечать статусы | ❌ | ✅ | ✅ | ❌ | ✅ |\n| Может назначать инженеров | ❌ | ❌ | ✅ | ❌ | ✅ |\n| Может назначать роли | ❌ | ❌ | ❌ | ❌ | ✅ |\n| Видит всех пользователей | ❌ | ❌ | ✅ | ✅ | ✅ |\n| Имеет доступ к админ-панели | ❌ | ❌ | ✅ | ❌ | ✅ |\n| Может синхронизировать календарь | ❌ | ❌ | ✅ | ❌ | ✅ |\n\n---\n\n### 💡 Примеры использования\n\n| Сценарий | Кто может |\n|----------|-----------|\n| Инженер отмечает проблему в аудитории 501 | Engineer, Admin, Superadmin |\n| Менеджер смотрит статистику по мероприятиям | Admin, Manager, Superadmin |\n| Администратор назначает инженера на мероприятие | Admin, Superadmin |\n| Суперадминистратор назначает нового администратора | Superadmin |\n| Наблюдатель смотрит расписание на сегодня | Все |\n\n---\n\n## 🗄️ Структура базы данных\n\n### Таблица `users` — пользователи системы\n\n| Поле | Тип | Ограничение | Описание |\n|------|-----|-------------|----------|\n| `user_id` | VARCHAR(255) | PRIMARY KEY | ID пользователя (email из VK Workspace) |\n| `full_name` | VARCHAR(100) | | Имя для отображения |\n| `role` | VARCHAR(20) | DEFAULT 'viewer' | Роль: superadmin / admin / manager / engineer / viewer |\n| `created_at` | TIMESTAMP | DEFAULT CURRENT_TIMESTAMP | Дата регистрации |\n| `last_active` | TIMESTAMP | DEFAULT CURRENT_TIMESTAMP | Последняя активность |\n| `is_active` | BOOLEAN | DEFAULT TRUE | Активен ли пользователь |\n\n### Таблица `status_log` — история статусов аудиторий (Новое в День 6)\n\n| Поле | Тип | Ограничение | Описание |\n|------|-----|-------------|----------|\n| `id` | SERIAL | PRIMARY KEY | Внутренний ID |\n| `auditory_id` | INTEGER | FOREIGN KEY (auditories.id) NOT NULL | ID аудитории |\n| `status` | VARCHAR(10) | NOT NULL | green / yellow / red |\n| `comment` | TEXT | | Комментарий к проблеме |\n| `reported_by` | VARCHAR(255) | FOREIGN KEY (users.user_id) NOT NULL | Кто отметил |\n| `created_at` | TIMESTAMP | DEFAULT CURRENT_TIMESTAMP | Когда отметили |\n| `resolved_at` | TIMESTAMP | | Когда починили |\n| `resolution_comment` | TEXT | | Как починили |\n\n**Индексы:**\n- `idx_status_log_auditory` — для быстрого поиска по аудитории\n- `idx_status_log_created` — для поиска по дате\n\n### Таблица `calendar_events` — мероприятия из Google Calendar\n\n| Поле | Тип | Ограничение | Описание |\n|------|-----|-------------|----------|\n| `id` | SERIAL | PRIMARY KEY | Внутренний ID |\n| `google_event_id` | VARCHAR(255) | UNIQUE NOT NULL | ID из Google Calendar |\n| `auditory_id` | INTEGER | FOREIGN KEY (auditories.id) | ID аудитории |\n| `title` | VARCHAR(500) | NOT NULL | Название мероприятия |\n| `description` | TEXT | | Описание мероприятия |\n| `location` | TEXT | | Место проведения (из Google Calendar) |\n| `start_time` | TIMESTAMP WITH TIME ZONE | NOT NULL | Начало мероприятия |\n| `end_time` | TIMESTAMP WITH TIME ZONE | NOT NULL | Конец мероприятия |\n| `is_all_day` | BOOLEAN | DEFAULT FALSE | Целодневное событие |\n| `status` | VARCHAR(20) | DEFAULT 'confirmed' | confirmed / cancelled / tentative |\n| `organizer` | VARCHAR(255) | | Организатор (email) |\n| `last_sync` | TIMESTAMP WITH TIME ZONE | DEFAULT CURRENT_TIMESTAMP | Время последней синхронизации |\n| `created_at` | TIMESTAMP WITH TIME ZONE | DEFAULT CURRENT_TIMESTAMP | Дата создания записи |\n| `updated_at` | TIMESTAMP WITH TIME ZONE | DEFAULT CURRENT_TIMESTAMP | Дата обновления записи |\n\n### Таблица `auditories` — аудитории\n\n| Поле | Тип | Ограничение | Описание |\n|------|-----|-------------|----------|\n| `id` | SERIAL | PRIMARY KEY | Внутренний ID |\n| `name` | VARCHAR(50) | NOT NULL | Номер аудитории ('501', '315') |\n| `building` | VARCHAR(50) | | Корпус |\n| `floor` | INTEGER | | Этаж |\n| `equipment` | TEXT | | Описание оборудования |\n| `notes` | TEXT | | Заметки |\n| `is_active` | BOOLEAN | DEFAULT TRUE | Не списана ли |\n\n### Таблица `sync_log` — лог синхронизации\n\n| Поле | Тип | Ограничение | Описание |\n|------|-----|-------------|----------|\n| `id` | SERIAL | PRIMARY KEY | Внутренний ID |\n| `sync_type` | VARCHAR(20) | NOT NULL | Тип: full / incremental |\n| `events_processed` | INTEGER | DEFAULT 0 | Всего обработано событий |\n| `events_inserted` | INTEGER | DEFAULT 0 | Добавлено событий |\n| `events_updated` | INTEGER | DEFAULT 0 | Обновлено событий |\n| `events_cancelled` | INTEGER | DEFAULT 0 | Отменено событий |\n| `status` | VARCHAR(20) | DEFAULT 'success' | success / partial / failed |\n| `error_message` | TEXT | | Текст ошибки (если была) |\n| `started_at` | TIMESTAMP WITH TIME ZONE | DEFAULT CURRENT_TIMESTAMP | Начало синхронизации |\n| `finished_at` | TIMESTAMP WITH TIME ZONE | | Окончание синхронизации |\n\n---\n\n### Связи между таблицами\n\n```mermaid\nerDiagram\n    users ||--o{ calendar_events : \"организует\"\n    users ||--o{ status_log : \"отмечает\"\n    auditories ||--o{ calendar_events : \"расположена в\"\n    auditories ||--o{ status_log : \"имеет статус\"\n    users {\n        varchar user_id PK\n        varchar full_name\n        varchar role\n        timestamp created_at\n        timestamp last_active\n        boolean is_active\n    }\n    status_log {\n        serial id PK\n        integer auditory_id FK\n        varchar status\n        text comment\n        varchar reported_by FK\n        timestamp created_at\n        timestamp resolved_at\n        text resolution_comment\n    }\n    calendar_events {\n        serial id PK\n        varchar google_event_id UK\n        integer auditory_id FK\n        varchar title\n        text description\n        text location\n        timestamp start_time\n        timestamp end_time\n        boolean is_all_day\n        varchar status\n        varchar organizer\n        timestamp last_sync\n    }\n    auditories {\n        serial id PK\n        varchar name\n        varchar building\n        integer floor\n        text equipment\n        text notes\n        boolean is_active\n    }\n    sync_log {\n        serial id PK\n        varchar sync_type\n        integer events_processed\n        integer events_inserted\n        integer events_updated\n        integer events_cancelled\n        varchar status\n        text error_message\n        timestamp started_at\n        timestamp finished_at\n    }\n```\n\n---   \n\n## 📋 Примеры работы модулей\n\n---\n\n### 📅 Модуль календаря\n\n#### Команда `/today` — просмотр событий на сегодня\n```bash\n📅 События на сегодня\n\n🕐 10:00 — Встреча с командой\n📍 Аудитория: 501 (Главный корпус)\n👤 Иванов И.И.\n\n🕐 14:00 — Техническое совещание\n📍 Аудитория: Лекционный зал 1 (Корпус Б)\n\n━━━━━━━━━━━━━━━━━━━━━\nℹ️ Итого: 2 мероприятия\n\n[📅 Сегодня]\n[➡️ Завтра]\n[📆 Неделя]\n[🔄 Синхронизация]\n[◀️ В главное меню]\n```\n\n#### Команда `/week` — просмотр событий на неделю\n```bash\n📊 События на неделю\n\n22.06 (Понедельник)\n🕐 10:00 — Планёрка по УМСиИ\n🏛️ 118 (ГУК)\n\n23.06 (Вторник)\n🕐 09:00 — Совещание первого корпуса\n🏛️ 315 (Главный корпус)\n🕐 16:00 — Конференция\n🏛️ Лекционный зал 1\n\n━━━━━━━━━━━━━━━━━━━━━\nℹ️ Итого: 3 мероприятия\n```\n\n#### Синхронизация с Google Calendar\n\nПри нажатии кнопки **🔄 Синхронизация** появляется модальное окно с результатом:\n```bash\n✅ Синхронизация завершена!\n\n📊 Получено: 43 событий\n💾 Сохранено: 43 событий\n```\n\n---\n\n### 🟢 Модуль аудиторий\n\n#### Команда `/status` — просмотр статусов всех аудиторий\n```bash\n🏛️ Статусы аудиторий\n\n🟢 501 — Всё работает (Главный корпус)\n👤 Иванов Иван (10:15)\n\n🟡 Лекционный зал 1 — Есть проблемы\n📝 Проектор не включается\n👤 Петров Пётр (08:30)\n\n🔴 118 — Не работает\n📝 Нет звука в колонках\n👤 Сидоров Сидор (08:00)\n\n━━━━━━━━━━━━━━━━━━━━━\nℹ️ Всего: 7 аудиторий\n```\n\n#### Команда `/set_status` — интерактивная отметка статуса\n\n**Шаг 1: Выбор аудитории**\n```bash\n🏛️ Выберите аудиторию:\n\n[501 (Главный корпус)]\n[315 (Главный корпус)]\n[Лекционный зал 1 (Главный корпус)]\n[Семенов]\n[Капица]\n[118 (ГУК)]\n[130]\n[◀️ Отмена]\n```\n\n**Шаг 2: Карточка аудитории**\n```bash\n🏛️ 501\n\n📍 Главный корпус, 5 этаж\n🔧 Проектор, звук, HDMI\n\nТекущий статус: 🟢 Всё работает\n👤 Иванов Иван (10:15)\n\n[🟢 Всё работает] [🟡 Есть проблемы]\n[🔴 Не работает] [📋 История]\n[◀️ Назад к списку]\n```\n\n**Шаг 3: Выбор статуса**\n```bash\n📝 Введите комментарий\n\n🏛️ Аудитория: 501\n🔄 Статус: 🟡 Есть проблемы\n\n📝 Напишите комментарий в следующем сообщении.\n💡 Нажмите «⏭️ Сохранить без комментария», чтобы пропустить.\n\n[⏭️ Сохранить без комментария] [❌ Отмена]\n```\n\n**Шаг 4: Подтверждение сохранения статуса**\n```bash\n✅ Статус обновлён!\n\n🏛️ Аудитория: 501\n🔄 Статус: 🟡 Есть проблемы\n📝 Комментарий: Проектор не включается\n👤 Отметил: Иванов Иван\n🕐 10:20\n```\n#### Команда `/history` - история статусов конкретной аудитории\n```bash\n📋 История статусов: 501\n\n🟢 Всё работает — 10:15 22.06\n👤 Иванов Иван\n\n🟡 Есть проблемы — 10:20 22.06\n📝 Проектор не включается\n👤 Петров Пётр\n\n🔴 Не работает — 08:00 22.06\n📝 Нет звука в колонках\n👤 Сидоров Сидор\n✅ Исправлено: заменили кабель\n\n━━━━━━━━━━━━━━━━━━━━━\nℹ️ Последние 3 изменения\n```\n---\n\n#### 🔔 Уведомление в общий чат (при отметке статуса 🟡/🔴)\n```bash\n⚠️ Изменение статуса аудитории\n\n🏛️ Аудитория: 501 (Главный корпус)\n🔄 Статус: 🟡 Есть проблемы\n📝 Комментарий: Проектор не включается\n👤 Отметил: Иванов Иван\n🕐 10:20\n```\n\n---\n\n## 🚀 Установка и запуск\n\n### Требования\n- Python 2.7, 3.4, 3.5, 3.6\n- PostgreSQL 18+\n- VK Workspace аккаунт с правами на создание бота\n- Google Cloud проект с включённым Calendar API\n\n### Установка\n\n1. Клонируйте репозиторий:\n```bash\ngit clone https://github.com/YOUR_USERNAME/otskvm-vk-teams-bot.git\ncd otskvm-vk-teams-bot\n```\n\n2. Создайте виртуальное окружение:\n```bash\npython -m venv venv\n# source venv/bin/activate  # Linux/Mac\nvenv\\Scripts\\activate   # Windows\n```\n\n3. Установите зависимости:\n```bash\npip install -r requirements.txt\n```\n\n4. Создайте файл .env и добавьте токен бота:\n```bash\n# VK Workspace\nBOT_TOKEN=ваш_токен_от_metabot\n\n# База данных PostgreSQL\nDATABASE_URL=postgresql://user:password@localhost:5432/database_name\n\n# Google Calendar\nGOOGLE_CALENDAR_ID=primary  # или ID вашего календаря\n```\n\n5. Настройте Google Calendar API:\n```bash\nСкачайте credentials.json из Google Cloud Console\nПоложите в корень проекта\n```\n\n6. Запустите бота:\n```bash\npython run.py\n```\n\n## 🐛 Известные проблемы и решения\n\n### Ошибки при запуске и работе бота\n\n| Проблема | Причина | Решение |\n|----------|---------|---------|\n| `ModuleNotFoundError: No module named 'bot.bot'` | Конфликт имён: ваш файл `bot.py` перекрывает библиотеку `mailru-im-bot` | Переименуйте файл `bot.py` в `run.py` (или `main.py`) и обновите точку входа |\n| `SyntaxError: future feature annotations is not defined` | Использование `from __future__ import annotations` в Python 3.6 | Удалите эту строку из файла (поддерживается только с Python 3.7+) |\n| `TypeError: _signal_handler() takes 2 positional arguments but 3 were given` | Конфликт обработчиков сигналов в библиотеке `mailru-im-bot` на Windows | Используйте `bot_wrapper.py` с переопределённым методом `idle()` (реализовано в проекте) |\n| `RuntimeError: Event loop is closed` | Проблемы с event loop при асинхронных операциях | Используйте `run_async()` для изоляции асинхронных вызовов (реализовано в проекте) |\n| `ImportError: cannot import name 'Final'` | `typing.Final` не поддерживается в Python 3.6 | Удалите аннотации `Final` из `constants.py` (исправлено) |\n| `type object 'datetime.datetime' has no attribute 'fromisoformat'` | `datetime.fromisoformat()` работает некорректно с некоторыми форматами в Python 3.6 | Используйте `python-dateutil` для парсинга дат (реализовано) |\n\n### Проблемы с Google Calendar API\n\n| Проблема | Причина | Решение |\n|----------|---------|---------|\n| Бот не видит события в календаре | Неправильный `GOOGLE_CALENDAR_ID` в `.env` | Проверьте ID календаря. Используйте `primary` для основного календаря или скопируйте ID из настроек Google Calendar |\n| `FileNotFoundError: credentials.json not found` | Файл с учётными данными Google OAuth отсутствует | Скачайте `credentials.json` из Google Cloud Console (Desktop app) и положите в корень проекта |\n| Ошибка авторизации при первом запуске | Требуется подтверждение доступа к календарю | При первом запуске откроется браузер для авторизации. Войдите в аккаунт и разрешите доступ |\n| `HttpError 403: Rate Limit Exceeded` | Превышен лимит запросов к Google API | Увеличьте интервал синхронизации или уменьшите количество дней в `fetch_events()` |\n\n### Проблемы с базой данных\n\n| Проблема | Причина | Решение |\n|----------|---------|---------|\n| `Connection refused` при подключении к БД | PostgreSQL не запущен или неправильные параметры подключения | Проверьте, что контейнер Docker запущен (`docker ps`). Проверьте `DATABASE_URL` в `.env` |\n| `relation \"calendar_events\" does not exist` | Таблица не создана | Таблицы создаются автоматически при первом запуске через `database.py`. Убедитесь, что у пользователя есть права на создание таблиц |\n| `column \"location\" does not exist` | В проекте используется `auditory_id` вместо `location` | В текущей версии проекта поле `location` не используется. Проверьте структуру таблицы `calendar_events` |\n\n### Проблемы с нормализацией аудиторий\n\n| Проблема | Причина | Решение |\n|----------|---------|---------|\n| `⚠️ Аудитория не найдена: '...'` в логах | Название аудитории из календаря отсутствует в словаре синонимов | Добавьте новый вариант в `ALIASES` в файле `src/utils/auditory_normalizer.py` |\n| Название аудитории не отображается в сообщениях | `auditory_id` не найден или `LEFT JOIN` не сработал | Проверьте, что в таблице `auditories` есть запись с соответствующим названием. Проверьте SQL-запрос в `get_events_from_db()` |\n\n### Проблемы с VK Workspace\n\n| Проблема | Причина | Решение |\n|----------|---------|---------|\n| Бот не отвечает в общих чатах | Не настроена фильтрация чатов | Проверьте функцию `is_private_chat()` — для корпоративной версии личные чаты определяются по email |\n| Бот не видит сообщения в личке | Бот не добавлен в чат или нет прав | Убедитесь, что бот добавлен в чат. Проверьте токен и права доступа через `@metabot` |\n| Кнопки не работают | Не зарегистрирован `BotButtonCommandHandler` | Убедитесь, что в `setup()` модуля зарегистрирован обработчик кнопок |\n| `parse_mode=\"HTML\"` не работает | VK Teams не поддерживает HTML в сообщениях | Используйте MarkdownV2 или проверьте документацию VK Teams Bot API |\n\n### Прочие проблемы\n\n| Проблема | Причина | Решение |\n|----------|---------|---------|\n| `pip install` не находит нужную версию пакета | Старая версия `pip` | Обновите pip: `python -m pip install --upgrade pip` |\n| `protobuf` требует Python \u003e=3.7 | Новая версия `protobuf` не совместима с Python 3.6 | Установите `protobuf==3.19.6` (указано в `requirements.txt`) |\n| Названия дней недели на английском в `/week` | Удалён словарь `WEEKDAYS_RU` или используется `%A` без перевода | Добавьте словарь `WEEKDAYS_RU` и используйте его в `week_handler` |\n\n### Как сообщить о новой проблеме\n\n1. Проверьте логи в консоли — там может быть подробная информация об ошибке.\n2. Проверьте, не описана ли проблема выше.\n3. Если проблема новая, создайте issue в репозитории с описанием:\n   - Что вы делали\n   - Что ожидали увидеть\n   - Что увидели на самом деле\n   - Полный вывод ошибки (traceback)\n\n---\n\n### Быстрая диагностика\n\n1. **Проверить подключение к БД:**\n   ```bash\n   python -c \"from src.core.database import Database; import asyncio; asyncio.run(Database.get_pool()); print('✅ БД подключена')\"\n   ```\n\n2. **Проверить Google Calendar:**\n   ```bash\n   python -c \"from src.core.google_client import calendar_client; events = calendar_client.fetch_events(1); print(f'✅ Получено {len(events)} событий')\"\n   ```\n\n3. **Проверить нормализацию:**\n   ```bash\n   python -c \"from src.utils.auditory_normalizer import AuditoryNormalizer; print(AuditoryNormalizer.normalize('лекц. 1'))\"\n   # Ожидаемый вывод: Лекционный зал 1\n   ```\n\n4. **Проверить импорты модулей:**\n   ```bash\n   python -c \"import src.modules.calendar.handlers; print('✅ Модуль календаря загружен')\"\n   ```\n\n## 📝 Планы развития\n\n- Назначения инженеров на мероприятия из календаря\n- Модуль задач и финальная полировка\n\n## 👨‍💻 Разработка\n\n### Добавление нового модуля\n\n1. Создайте папку в src/modules/\n2. Создайте handlers.py с функцией setup()\n3. Зарегистрируйте команды через module_manager.register_command()\n4. Зарегистрируйте callback'и через module_manager.register_callback()\n5. Модуль автоматически загрузится при запуске\n\n### Пример модуля:\n```python\n# src/modules/example/handlers.py\n\ndef setup(bot, module_manager):\n    module_manager.register_command('/example', example_handler, 'example')\n    module_manager.register_callback('example_callback', example_callback, 'example')\n\ndef example_handler(bot, event):\n    # обработка команды\n    pass\n\ndef example_callback(bot, event):\n    # обработка кнопки\n    pass\n```\n\n\n## 🔗 Ссылки\n\n### 📚 Документация\n| Ресурс | Ссылка | Описание |\n|--------|--------|----------|\n| **Репозиторий проекта** | [otskvm-vk-teams-bot](https://github.com/Nimos95/otskvm-vk-teams-bot) | Исходный код бота |\n| **VK Teams Bot API** | [teams.vk.com/botapi/](https://teams.vk.com/botapi/) | Официальная документация по ботам VK Teams |\n| **Google Calendar API** | [developers.google.com/calendar](https://developers.google.com/calendar/api/guides/overview) | Документация по Google Calendar API |\n| **PostgreSQL** | [postgresql.org/docs](https://www.postgresql.org/docs/) | Документация по PostgreSQL |\n\n### 🛠 Инструменты\n| Ресурс | Ссылка | Описание |\n|--------|--------|----------|\n| **Google Cloud Console** | [console.cloud.google.com](https://console.cloud.google.com/) | Настройка API и получение `credentials.json` |\n| **DBeaver** | [dbeaver.io](https://dbeaver.io/) | Клиент для работы с PostgreSQL |\n| **PostgreSQL Docker** | [hub.docker.com/_/postgres](https://hub.docker.com/_/postgres) | Образ PostgreSQL для Docker |\n\n### 🔗 Связанные проекты\n| Ресурс | Ссылка | Описание |\n|--------|--------|----------|\n| **OTSKVMBot (Telegram)** | [github.com/Nimos95/otskvm-bot](https://github.com/Nimos95/otskvm-bot) | Исходная версия бота для Telegram |\n\n---\n\n### 👨‍💻 Контакты\n\n- **Автор:** Москвин Никита Романович — [@Nimos95](https://github.com/Nimos95)\n- **Организация:** СПбПУ Петра Великого, отдел технического сопровождения КВМ\n- 📧 moskvin_nr@spbstu.ru\n- 📞 +7 (993) 486-4670\n\n---\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnimos95%2Fotskvm-vk-teams-bot","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnimos95%2Fotskvm-vk-teams-bot","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnimos95%2Fotskvm-vk-teams-bot/lists"}