chore: update development dependencies and improve test coverage
Some checks failed
CI / lint-and-test (push) Failing after 11s

- Upgraded `pytest-asyncio` to version 1.0 to ensure compatibility with the latest features and improvements.
- Increased the coverage threshold in pytest configuration to 80%, enhancing the quality assurance process.
- Added a new `conftest.py` file to manage shared fixtures and improve test organization.
- Introduced multiple new test files to cover various components, ensuring comprehensive test coverage across the application.
- Updated the `.coverage` file to reflect the latest coverage metrics.
This commit is contained in:
2026-02-20 17:33:04 +03:00
parent ae21883e1e
commit e25eb7be2f
24 changed files with 1267 additions and 18 deletions

View File

@@ -14,7 +14,7 @@ Requires-Dist: pydantic<3.0,>=2.0
Requires-Dist: icalendar<6.0,>=5.0
Provides-Extra: dev
Requires-Dist: pytest<9.0,>=8.0; extra == "dev"
Requires-Dist: pytest-asyncio<1.0,>=0.24; extra == "dev"
Requires-Dist: pytest-asyncio<2.0,>=1.0; extra == "dev"
Requires-Dist: pytest-cov<7.0,>=6.0; extra == "dev"
Requires-Dist: httpx<1.0,>=0.27; extra == "dev"
Provides-Extra: docs
@@ -62,7 +62,7 @@ A minimal Telegram bot boilerplate using [python-telegram-bot](https://github.co
5. **Miniapp access (calendar)**
Set `ALLOWED_USERNAMES` (and optionally `ADMIN_USERNAMES`) to allow access to the calendar miniapp; if both are empty, no one can open it. Users can also be allowed by phone via `ALLOWED_PHONES` / `ADMIN_PHONES` after setting a phone with `/set_phone`.
**Mini App URL:** When configuring the bot's menu button or Web App URL (e.g. in @BotFather or via `setChatMenuButton`), use the URL **with a trailing slash**, e.g. `https://your-domain.com/app/`. A redirect from `/app` to `/app/` can cause the browser to drop the fragment that Telegram sends, which breaks authorization.
**How to open:** Users must open the calendar **via the bot's menu button** (⋮ → «Календарь» or the configured label) or a **Web App inline button**. If they use «Open in browser» or a direct link, Telegram may not send user data (`tgWebAppData`), and access will be denied.
**How to open:** Users must open the calendar **via the bot's menu button** (⋮ → "Calendar" or the configured label) or a **Web App inline button**. If they use "Open in browser" or a direct link, Telegram may not send user data (`tgWebAppData`), and access will be denied.
**BOT_TOKEN:** The server that serves `/api/duties` (e.g. your production host) must have in `.env` the **same** bot token as the bot from which users open the Mini App. If the token differs (e.g. test vs production bot), validation returns "hash_mismatch" and access is denied.
6. **Other options**
@@ -87,7 +87,7 @@ The bot runs in polling mode. Send `/start` or `/help` to your bot in Telegram t
- **`/start`** — Greeting and user registration in the database.
- **`/help`** — Help on available commands.
- **`/set_phone [number]`** — Set or clear phone number (private chat only); used for access via `ALLOWED_PHONES` / `ADMIN_PHONES`.
- **`/import_duty_schedule`** — Import duty schedule (only for `ADMIN_USERNAMES` / `ADMIN_PHONES`); see «Импорт расписания» below for the two-step flow.
- **`/import_duty_schedule`** — Import duty schedule (only for `ADMIN_USERNAMES` / `ADMIN_PHONES`); see **Duty schedule import** below for the two-step flow.
- **`/pin_duty`** — Pin the current duty message in a group (reply to the bots duty message); time/timezone for the pinned message come from `DUTY_DISPLAY_TZ`.
## Run with Docker
@@ -145,16 +145,16 @@ High-level architecture (components, data flow, package relationships) is descri
To add commands, define async handlers in `duty_teller/handlers/commands.py` (or a new module) and register them in `duty_teller/handlers/__init__.py`.
## Импорт расписания дежурств (duty-schedule)
## Duty schedule import (duty-schedule)
Команда **`/import_duty_schedule`** доступна только пользователям из `ADMIN_USERNAMES` или `ADMIN_PHONES`. Импорт выполняется в два шага:
The **`/import_duty_schedule`** command is available only to users in `ADMIN_USERNAMES` or `ADMIN_PHONES`. Import is done in two steps:
1. **Время пересменки** — бот просит указать время и при необходимости часовой пояс (например `09:00 Europe/Moscow` или `06:00 UTC`). Время приводится к UTC и используется для границ смен при создании записей.
2. **Файл JSON** — отправьте файл в формате duty-schedule.
1. **Handover time** — The bot asks for the shift handover time and optional timezone (e.g. `09:00 Europe/Moscow` or `06:00 UTC`). This is converted to UTC and used as the boundary between duty periods when creating records.
2. **JSON file** — Send a file in duty-schedule format.
Формат: в корне JSON — объект **meta** с полем `start_date` (YYYY-MM-DD) и массив **schedule** с объектами `name` (ФИО) и `duty` (строка с разделителем `;`, символы **в/В/б/Б** — дежурство, **Н** — недоступен, **О** — отпуск). Количество дней задаётся длиной строки `duty`. При повторном импорте дежурства в том же диапазоне дат для каждого пользователя заменяются новыми.
Format: at the root of the JSON — a **meta** object with `start_date` (YYYY-MM-DD) and a **schedule** array of objects with `name` (full name) and `duty` (string with separator `;`; characters **в/В/б/Б** = duty, **Н** = unavailable, **О** = vacation). The number of days is given by the length of the `duty` string. On re-import, duties in the same date range for each user are replaced by the new data.
**Полное описание формата и пример JSON:** [docs/import-format.md](docs/import-format.md).
**Full format description and example JSON:** [docs/import-format.md](docs/import-format.md).
## Tests
@@ -168,3 +168,13 @@ pytest
Tests cover `api/telegram_auth` (validate_init_data, auth_date expiry), `config` (is_admin, can_access_miniapp), and the API (date validation, 403/200 with mocked auth, plus an E2E auth test without auth mocks).
**CI (Gitea Actions):** Lint (ruff), tests (pytest), security (bandit). If the workflow uses `PYTHONPATH: src` or `bandit -r src`, update it to match the repo layout (no `src/`).
## Contributing
- **Commits:** Use [Conventional Commits](https://www.conventionalcommits.org/): `feat:`, `fix:`, `docs:`, `refactor:`, `test:`, `chore:`, etc.
- **Branches:** Follow [Gitea Flow](https://docs.gitea.io/en-us/workflow-branching/): main branch `main`, features and fixes in separate branches.
- **Changes:** Via **Pull Request** in Gitea; run linters and tests (`ruff check .`, `pytest`) before merge.
## Logs and rotation
To meet the 7-day log retention policy, configure log rotation at deploy time: e.g. [logrotate](https://manpages.ubuntu.com/logrotate), systemd logging settings, or Docker (size/time retention limits). Keep application logs for no more than 7 days.

View File

@@ -37,13 +37,24 @@ duty_teller/utils/__init__.py
duty_teller/utils/dates.py
duty_teller/utils/handover.py
duty_teller/utils/user.py
tests/test_api_dependencies.py
tests/test_app.py
tests/test_calendar_ics.py
tests/test_calendar_token_repository.py
tests/test_config.py
tests/test_db_session.py
tests/test_duty_schedule_parser.py
tests/test_group_duty_pin_service.py
tests/test_handlers_commands.py
tests/test_handlers_errors.py
tests/test_handlers_group_duty_pin.py
tests/test_handlers_init.py
tests/test_i18n.py
tests/test_import_duty_schedule_integration.py
tests/test_import_service.py
tests/test_package_init.py
tests/test_personal_calendar_ics.py
tests/test_repository_duty_range.py
tests/test_run.py
tests/test_telegram_auth.py
tests/test_utils.py

View File

@@ -9,7 +9,7 @@ icalendar<6.0,>=5.0
[dev]
pytest<9.0,>=8.0
pytest-asyncio<1.0,>=0.24
pytest-asyncio<2.0,>=1.0
pytest-cov<7.0,>=6.0
httpx<1.0,>=0.27