Fix/backround clear magic tokens#17
Merged
Merged
Conversation
…d fix date fields by adding the timezone=True property to store time zone information. Fix and add missing relationships
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
…d also fix the issue of multiple bans for one user simultaneously, while preserving the ban history.
…e for consistency
Contributor
Руководство для ревьюераРефакторинг и расширение модели данных SQLAlchemy (users, magic tokens, bans, services, appointments), исправление обработки и очистки magic‑токенов, корректировка стартового сценария Telegram‑бота и добавление модульных тестов для JWT/паролей и мелких исправлений в тестах. Диаграмма последовательностей для Telegram /start с magic‑token ссылкойsequenceDiagram
actor TgUser
participant Bot as TelegramBot
participant TgLinkService
participant DB
TgUser->>Bot: /start
Bot->>Bot: start_handler(message)
Bot->>TgLinkService: is_telegram_linked(user_id)
TgLinkService->>DB: SELECT User by telegram_id
DB-->>TgLinkService: User or None
TgLinkService-->>Bot: connected flag
alt not connected
Bot->>TgLinkService: generate_magic_token(user_id)
TgLinkService->>DB: INSERT MagicToken
DB-->>TgLinkService: MagicToken
TgLinkService-->>Bot: token
Bot-->>TgUser: message with URL /auth/login-link?token=...
else already connected
Bot-->>TgUser: message about existing link
end
Диаграмма связей сущностей для обновлённых моделей user, magic token, appointment, service и banerDiagram
User {
int id
int telegram_id
string username
string phone
string email
string role
}
MagicToken {
int id
string token
datetime expires_at
bool used
datetime created_at
int user_id
}
Service {
int id
string name
int price
string duration
int entrepreneur_id
}
Appointment {
int id
datetime date
int service_id
int entrepreneur_id
int user_id
}
Ban {
int id
string reason
int user_id
int banned_by
int revoked_by
datetime banned_at
datetime expires_at
datetime revoked_at
}
User ||--o{ MagicToken : has
User ||--o{ Service : offers
User ||--o{ Appointment : books
Service ||--o{ Appointment : includes
User ||--o{ Ban : receives
Изменения по файлам
Подсказки и командыВзаимодействие с Sourcery
Настройка вашего опытаЗайдите в вашу панель управления, чтобы:
Получение помощи
Original review guide in EnglishReviewer's GuideRefactors and extends the SQLAlchemy data model (users, magic tokens, bans, services, appointments), fixes magic-token handling and cleanup, adjusts the Telegram bot start flow, and adds JWT/password unit tests and minor test fixes. Sequence diagram for Telegram /start flow with magic token linksequenceDiagram
actor TgUser
participant Bot as TelegramBot
participant TgLinkService
participant DB
TgUser->>Bot: /start
Bot->>Bot: start_handler(message)
Bot->>TgLinkService: is_telegram_linked(user_id)
TgLinkService->>DB: SELECT User by telegram_id
DB-->>TgLinkService: User or None
TgLinkService-->>Bot: connected flag
alt not connected
Bot->>TgLinkService: generate_magic_token(user_id)
TgLinkService->>DB: INSERT MagicToken
DB-->>TgLinkService: MagicToken
TgLinkService-->>Bot: token
Bot-->>TgUser: message with URL /auth/login-link?token=...
else already connected
Bot-->>TgUser: message about existing link
end
Entity relationship diagram for updated user, magic token, appointment, service, and ban modelserDiagram
User {
int id
int telegram_id
string username
string phone
string email
string role
}
MagicToken {
int id
string token
datetime expires_at
bool used
datetime created_at
int user_id
}
Service {
int id
string name
int price
string duration
int entrepreneur_id
}
Appointment {
int id
datetime date
int service_id
int entrepreneur_id
int user_id
}
Ban {
int id
string reason
int user_id
int banned_by
int revoked_by
datetime banned_at
datetime expires_at
datetime revoked_at
}
User ||--o{ MagicToken : has
User ||--o{ Service : offers
User ||--o{ Appointment : books
Service ||--o{ Appointment : includes
User ||--o{ Ban : receives
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
Contributor
There was a problem hiding this comment.
Привет — я нашёл 5 проблем и оставил немного высокоуровневого фидбэка:
- В
TgLinkService.check_magic_tokenи нескольких тестах всё ещё используетсяdatetime.now()без таймзоны, в то время какexpires_atопределён какDateTime(timezone=True)в других местах; имеет смысл везде последовательно использоватьdatetime.now(timezone.utc), чтобы избежать тонких багов, связанных с таймзонами, и несоответствий с БД. - В новой модели
Banопределено несколько связей сUser(moderator,user,revoker), но толькоuserсвязан черезback_populates; имеет смысл добавить соответствующие связи или подсказкиoverlapsнаUser, чтобы избежать неоднозначности/варнингов SQLAlchemy при нескольких FK на одну и ту же таблицу.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- In `TgLinkService.check_magic_token` and some tests you still use `datetime.now()` without timezone while `expires_at` is defined as `DateTime(timezone=True)` elsewhere; consider consistently using `datetime.now(timezone.utc)` to avoid subtle timezone bugs and mismatches with the DB.
- The new `Ban` model defines several relationships to `User` (`moderator`, `user`, `revoker`) but only `user` is connected via `back_populates`; you may want to add corresponding relationships or `overlaps` hints on `User` to avoid SQLAlchemy relationship ambiguity/warning with multiple FKs to the same table.
## Individual Comments
### Comment 1
<location path="src/domain/services/tg_link_service.py" line_range="60" />
<code_context>
- MagicTokens.used == False # noqa: E712
+ result = await db.execute(select(MagicToken).where(
+ MagicToken.token == token,
+ MagicToken.expires_at > datetime.now(),
+ MagicToken.used == False # noqa: E712
))
</code_context>
<issue_to_address>
**suggestion (bug_risk):** Use timezone‑aware `datetime` when comparing with a timezone‑aware DB column.
`expires_at` is `DateTime(timezone=True)`, but this comparison uses a naive `datetime.now()`. To match the column type and avoid timezone issues, use a timezone‑aware value here (e.g. `datetime.now(timezone.utc)`) as done elsewhere in the codebase.
Suggested implementation:
```python
result = await db.execute(select(MagicToken).where(
MagicToken.token == token,
MagicToken.expires_at > datetime.now(timezone.utc),
MagicToken.used == False # noqa: E712
))
```
1. At the top of `src/domain/services/tg_link_service.py`, ensure you have:
`from datetime import datetime, timezone`
If `datetime` is already imported (e.g. `from datetime import datetime`), extend that import to include `timezone` instead of adding a separate conflicting import.
</issue_to_address>
### Comment 2
<location path="src/domain/services/tg_link_service.py" line_range="37-40" />
<code_context>
-> Null
"""
- link_token = MagicTokens(
+ link_token = MagicToken(
telegram_id=telegram_id,
token=token,
expires_at=expires_at
</code_context>
<issue_to_address>
**issue (bug_risk):** `MagicToken` is instantiated with `telegram_id`, but the model no longer appears to define that column.
In the updated `MagicToken` model, only `id`, `token`, `expires_at`, `used`, `created_at`, and `user_id` are mapped, so `telegram_id` will either be an unmapped attribute or cause an error at runtime. If `telegram_id` is still required, it should be reintroduced as a mapped column; otherwise, drop this argument and adjust the flow to use `user_id` or another appropriate field instead.
</issue_to_address>
### Comment 3
<location path="tests/unit/test_auth/test_jwt.py" line_range="7-20" />
<code_context>
+ create_access_token
+)
+
+def test_hash_password():
+ """Тестирование хэширования паролей"""
+ password = "password_123"
+ wrong_password = "password"
+
+ wrong_hash = hash_password(wrong_password)
+ hash1 = hash_password(password)
+ hash2 = hash_password(password)
+
+ assert verify_password(password, hash1) is True, "Пароли не совпадают"
+ assert verify_password(password, hash2) is True, "Пароли не совпадают"
+
+ assert verify_password(wrong_hash, hash1) is False, "Верный и не верный пароли совпадают"
+ assert verify_password(wrong_hash, hash2) is False, "Верный и не верный пароли совпадают"
+
+def test_create_access_token():
</code_context>
<issue_to_address>
**suggestion (testing):** Усилить тест хэширования пароля: проверить рандомизацию хэша и дополнительные негативные кейсы
Сейчас тест проверяет только успешную и неуспешную верификацию. Предлагаю дополнить его:
1) Явно зафиксировать рандомизацию хэша (при наличии соли):
```python
hash1 = hash_password(password)
hash2 = hash_password(password)
assert hash1 != hash2
```
2) Проверять негативный кейс именно с неверным *plain*-паролем, а не только с `wrong_hash`, чтобы очевидно проверялся контракт `verify_password(plain, hashed)`:
```python
assert verify_password(wrong_password, hash1) is False
```
3) Опционально добавить кейсы для пустого и очень длинного пароля, чтобы убедиться, что реализация не падает на граничных значениях.
```suggestion
def test_hash_password():
"""Тестирование хэширования паролей"""
password = "password_123"
wrong_password = "password"
wrong_hash = hash_password(wrong_password)
hash1 = hash_password(password)
hash2 = hash_password(password)
# 1) Рандомизация хэша (наличие соли)
assert hash1 != hash2, "Хэши одинаковы, возможно отсутствует соль"
# 2) Позитивная проверка: верный пароль проходит верификацию
assert verify_password(password, hash1) is True, "Пароли не совпадают"
assert verify_password(password, hash2) is True, "Пароли не совпадают"
# 2) Негативный кейс: неверный plain-пароль не проходит верификацию
assert verify_password(wrong_password, hash1) is False, "Неверный пароль проходит верификацию"
assert verify_password(wrong_password, hash2) is False, "Неверный пароль проходит верификацию"
# Дополнительный негативный кейс: неверный хэш не проходит верификацию
assert verify_password(wrong_hash, hash1) is False, "Верный и неверный пароли дают совпадающий результат"
assert verify_password(wrong_hash, hash2) is False, "Верный и неверный пароли дают совпадающий результат"
# 3) Граничные значения: пустой и очень длинный пароль
empty_password = ""
long_password = "x" * 1024
empty_hash = hash_password(empty_password)
long_hash = hash_password(long_password)
# Пустой пароль хэшируется и корректно верифицируется
assert verify_password(empty_password, empty_hash) is True, "Пустой пароль не проходит верификацию"
assert verify_password(wrong_password, empty_hash) is False, "Неверный пароль проходит верификацию для пустого пароля"
# Очень длинный пароль хэшируется и корректно верифицируется
assert verify_password(long_password, long_hash) is True, "Длинный пароль не проходит верификацию"
assert verify_password(wrong_password, long_hash) is False, "Неверный пароль проходит верификацию для длинного пароля"
```
</issue_to_address>
### Comment 4
<location path="tests/unit/test_auth/test_jwt.py" line_range="22-29" />
<code_context>
+ assert verify_password(wrong_hash, hash1) is False, "Верный и не верный пароли совпадают"
+ assert verify_password(wrong_hash, hash2) is False, "Верный и не верный пароли совпадают"
+
+def test_create_access_token():
+ """Тестирование создания JWT токена"""
+
+ data = {"sub": 1234}
+ token = create_access_token(data)
+
+ assert isinstance(token, str)
+ assert len(token) > 100, "Токен слишком длинный"
+
+def test_decode_token():
</code_context>
<issue_to_address>
**suggestion (testing):** Уточнить проверки для JWT: не только длина, но и содержимое/распаковка токена
Сейчас тест лишь проверяет, что `create_access_token` возвращает достаточно длинную строку, и при этом сообщение об ошибке противоречит условию (`len(token) > 100`, но текст: "Токен слишком длинный"). Лучше либо поправить текст на "Токен слишком короткий", либо отказаться от проверки длины и вместо этого декодировать токен тем же механизмом, что и в приложении, и проверить, что:
- `sub` присутствует и совпадает с переданным значением;
- есть ожидаемые клеймы (например, `exp`).
Так тест будет действительно проверять корректность и структуру JWT, а не только форму.
Suggested implementation:
```python
def test_create_access_token():
"""Тестирование создания JWT токена"""
data = {"sub": 1234}
token = create_access_token(data)
assert isinstance(token, str)
assert len(token) > 100, "Токен слишком короткий"
# Проверяем, что токен корректно декодируется тем же механизмом, что и в приложении
payload = decode_access_token(token)
assert "sub" in payload, "В токене отсутствует claim 'sub'"
assert payload["sub"] == data["sub"], "Claim 'sub' в токене не совпадает с исходными данными"
assert "exp" in payload, "В токене отсутствует claim 'exp' (время истечения)"
def test_decode_token():
"""Тестирование расшифровки токена"""
data = {"sub": 5678}
token = create_access_token(data)
payload = decode_access_token(token)
assert payload["sub"] == data["sub"], "Claim 'sub' в расшифрованном токене не совпадает с исходными данными"
assert "exp" in payload, "В расшифрованном токене отсутствует claim 'exp'"
```
1. В начале файла необходимо импортировать функцию `decode_access_token` из того же модуля, где она используется в приложении (например, `from app.auth.jwt import decode_access_token` или аналогично принятой структуре проекта).
2. Если в кодовой базе вместо `decode_access_token` используется другая функция/утилита для разбора JWT, замените вызовы `decode_access_token(...)` в тестах на фактическую функцию декодирования и скорректируйте импорт.
3. Если `create_access_token` возвращает токен, в котором `sub` хранится как строка, возможно, потребуется привести типы в ассертах (`str(data["sub"])`) в обоих тестах.
</issue_to_address>
### Comment 5
<location path="tests/unit/test_auth/test_jwt.py" line_range="31-32" />
<code_context>
+ assert isinstance(token, str)
+ assert len(token) > 100, "Токен слишком длинный"
+
+def test_decode_token():
+ """Тестирование расшифровки токена"""
+
+
</code_context>
<issue_to_address>
**issue (testing):** Пустой `test_decode_token` создает ложное ощущение покрытия и не проверяет декодирование JWT
Сейчас `test_decode_token` не содержит ни одной проверки и всегда проходит.
Предлагаю либо:
- реализовать тест: сгенерировать токен, декодировать его и проверить ключевые поля (`sub`, срок действия и т.п.), а также реакцию на невалидный/просроченный токен;
- либо временно удалить тест, пока он не будет полноценно реализован.
Минимальный набор: один happy-path (валидный токен декодируется корректно) и один негативный сценарий (например, подделанный токен приводит к ожидаемому исключению/результату).
</issue_to_address>Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Original comment in English
Hey - I've found 5 issues, and left some high level feedback:
- In
TgLinkService.check_magic_tokenand some tests you still usedatetime.now()without timezone whileexpires_atis defined asDateTime(timezone=True)elsewhere; consider consistently usingdatetime.now(timezone.utc)to avoid subtle timezone bugs and mismatches with the DB. - The new
Banmodel defines several relationships toUser(moderator,user,revoker) but onlyuseris connected viaback_populates; you may want to add corresponding relationships oroverlapshints onUserto avoid SQLAlchemy relationship ambiguity/warning with multiple FKs to the same table.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- In `TgLinkService.check_magic_token` and some tests you still use `datetime.now()` without timezone while `expires_at` is defined as `DateTime(timezone=True)` elsewhere; consider consistently using `datetime.now(timezone.utc)` to avoid subtle timezone bugs and mismatches with the DB.
- The new `Ban` model defines several relationships to `User` (`moderator`, `user`, `revoker`) but only `user` is connected via `back_populates`; you may want to add corresponding relationships or `overlaps` hints on `User` to avoid SQLAlchemy relationship ambiguity/warning with multiple FKs to the same table.
## Individual Comments
### Comment 1
<location path="src/domain/services/tg_link_service.py" line_range="60" />
<code_context>
- MagicTokens.used == False # noqa: E712
+ result = await db.execute(select(MagicToken).where(
+ MagicToken.token == token,
+ MagicToken.expires_at > datetime.now(),
+ MagicToken.used == False # noqa: E712
))
</code_context>
<issue_to_address>
**suggestion (bug_risk):** Use timezone‑aware `datetime` when comparing with a timezone‑aware DB column.
`expires_at` is `DateTime(timezone=True)`, but this comparison uses a naive `datetime.now()`. To match the column type and avoid timezone issues, use a timezone‑aware value here (e.g. `datetime.now(timezone.utc)`) as done elsewhere in the codebase.
Suggested implementation:
```python
result = await db.execute(select(MagicToken).where(
MagicToken.token == token,
MagicToken.expires_at > datetime.now(timezone.utc),
MagicToken.used == False # noqa: E712
))
```
1. At the top of `src/domain/services/tg_link_service.py`, ensure you have:
`from datetime import datetime, timezone`
If `datetime` is already imported (e.g. `from datetime import datetime`), extend that import to include `timezone` instead of adding a separate conflicting import.
</issue_to_address>
### Comment 2
<location path="src/domain/services/tg_link_service.py" line_range="37-40" />
<code_context>
-> Null
"""
- link_token = MagicTokens(
+ link_token = MagicToken(
telegram_id=telegram_id,
token=token,
expires_at=expires_at
</code_context>
<issue_to_address>
**issue (bug_risk):** `MagicToken` is instantiated with `telegram_id`, but the model no longer appears to define that column.
In the updated `MagicToken` model, only `id`, `token`, `expires_at`, `used`, `created_at`, and `user_id` are mapped, so `telegram_id` will either be an unmapped attribute or cause an error at runtime. If `telegram_id` is still required, it should be reintroduced as a mapped column; otherwise, drop this argument and adjust the flow to use `user_id` or another appropriate field instead.
</issue_to_address>
### Comment 3
<location path="tests/unit/test_auth/test_jwt.py" line_range="7-20" />
<code_context>
+ create_access_token
+)
+
+def test_hash_password():
+ """Тестирование хэширования паролей"""
+ password = "password_123"
+ wrong_password = "password"
+
+ wrong_hash = hash_password(wrong_password)
+ hash1 = hash_password(password)
+ hash2 = hash_password(password)
+
+ assert verify_password(password, hash1) is True, "Пароли не совпадают"
+ assert verify_password(password, hash2) is True, "Пароли не совпадают"
+
+ assert verify_password(wrong_hash, hash1) is False, "Верный и не верный пароли совпадают"
+ assert verify_password(wrong_hash, hash2) is False, "Верный и не верный пароли совпадают"
+
+def test_create_access_token():
</code_context>
<issue_to_address>
**suggestion (testing):** Усилить тест хэширования пароля: проверить рандомизацию хэша и дополнительные негативные кейсы
Сейчас тест проверяет только успешную и неуспешную верификацию. Предлагаю дополнить его:
1) Явно зафиксировать рандомизацию хэша (при наличии соли):
```python
hash1 = hash_password(password)
hash2 = hash_password(password)
assert hash1 != hash2
```
2) Проверять негативный кейс именно с неверным *plain*-паролем, а не только с `wrong_hash`, чтобы очевидно проверялся контракт `verify_password(plain, hashed)`:
```python
assert verify_password(wrong_password, hash1) is False
```
3) Опционально добавить кейсы для пустого и очень длинного пароля, чтобы убедиться, что реализация не падает на граничных значениях.
```suggestion
def test_hash_password():
"""Тестирование хэширования паролей"""
password = "password_123"
wrong_password = "password"
wrong_hash = hash_password(wrong_password)
hash1 = hash_password(password)
hash2 = hash_password(password)
# 1) Рандомизация хэша (наличие соли)
assert hash1 != hash2, "Хэши одинаковы, возможно отсутствует соль"
# 2) Позитивная проверка: верный пароль проходит верификацию
assert verify_password(password, hash1) is True, "Пароли не совпадают"
assert verify_password(password, hash2) is True, "Пароли не совпадают"
# 2) Негативный кейс: неверный plain-пароль не проходит верификацию
assert verify_password(wrong_password, hash1) is False, "Неверный пароль проходит верификацию"
assert verify_password(wrong_password, hash2) is False, "Неверный пароль проходит верификацию"
# Дополнительный негативный кейс: неверный хэш не проходит верификацию
assert verify_password(wrong_hash, hash1) is False, "Верный и неверный пароли дают совпадающий результат"
assert verify_password(wrong_hash, hash2) is False, "Верный и неверный пароли дают совпадающий результат"
# 3) Граничные значения: пустой и очень длинный пароль
empty_password = ""
long_password = "x" * 1024
empty_hash = hash_password(empty_password)
long_hash = hash_password(long_password)
# Пустой пароль хэшируется и корректно верифицируется
assert verify_password(empty_password, empty_hash) is True, "Пустой пароль не проходит верификацию"
assert verify_password(wrong_password, empty_hash) is False, "Неверный пароль проходит верификацию для пустого пароля"
# Очень длинный пароль хэшируется и корректно верифицируется
assert verify_password(long_password, long_hash) is True, "Длинный пароль не проходит верификацию"
assert verify_password(wrong_password, long_hash) is False, "Неверный пароль проходит верификацию для длинного пароля"
```
</issue_to_address>
### Comment 4
<location path="tests/unit/test_auth/test_jwt.py" line_range="22-29" />
<code_context>
+ assert verify_password(wrong_hash, hash1) is False, "Верный и не верный пароли совпадают"
+ assert verify_password(wrong_hash, hash2) is False, "Верный и не верный пароли совпадают"
+
+def test_create_access_token():
+ """Тестирование создания JWT токена"""
+
+ data = {"sub": 1234}
+ token = create_access_token(data)
+
+ assert isinstance(token, str)
+ assert len(token) > 100, "Токен слишком длинный"
+
+def test_decode_token():
</code_context>
<issue_to_address>
**suggestion (testing):** Уточнить проверки для JWT: не только длина, но и содержимое/распаковка токена
Сейчас тест лишь проверяет, что `create_access_token` возвращает достаточно длинную строку, и при этом сообщение об ошибке противоречит условию (`len(token) > 100`, но текст: "Токен слишком длинный"). Лучше либо поправить текст на "Токен слишком короткий", либо отказаться от проверки длины и вместо этого декодировать токен тем же механизмом, что и в приложении, и проверить, что:
- `sub` присутствует и совпадает с переданным значением;
- есть ожидаемые клеймы (например, `exp`).
Так тест будет действительно проверять корректность и структуру JWT, а не только форму.
Suggested implementation:
```python
def test_create_access_token():
"""Тестирование создания JWT токена"""
data = {"sub": 1234}
token = create_access_token(data)
assert isinstance(token, str)
assert len(token) > 100, "Токен слишком короткий"
# Проверяем, что токен корректно декодируется тем же механизмом, что и в приложении
payload = decode_access_token(token)
assert "sub" in payload, "В токене отсутствует claim 'sub'"
assert payload["sub"] == data["sub"], "Claim 'sub' в токене не совпадает с исходными данными"
assert "exp" in payload, "В токене отсутствует claim 'exp' (время истечения)"
def test_decode_token():
"""Тестирование расшифровки токена"""
data = {"sub": 5678}
token = create_access_token(data)
payload = decode_access_token(token)
assert payload["sub"] == data["sub"], "Claim 'sub' в расшифрованном токене не совпадает с исходными данными"
assert "exp" in payload, "В расшифрованном токене отсутствует claim 'exp'"
```
1. В начале файла необходимо импортировать функцию `decode_access_token` из того же модуля, где она используется в приложении (например, `from app.auth.jwt import decode_access_token` или аналогично принятой структуре проекта).
2. Если в кодовой базе вместо `decode_access_token` используется другая функция/утилита для разбора JWT, замените вызовы `decode_access_token(...)` в тестах на фактическую функцию декодирования и скорректируйте импорт.
3. Если `create_access_token` возвращает токен, в котором `sub` хранится как строка, возможно, потребуется привести типы в ассертах (`str(data["sub"])`) в обоих тестах.
</issue_to_address>
### Comment 5
<location path="tests/unit/test_auth/test_jwt.py" line_range="31-32" />
<code_context>
+ assert isinstance(token, str)
+ assert len(token) > 100, "Токен слишком длинный"
+
+def test_decode_token():
+ """Тестирование расшифровки токена"""
+
+
</code_context>
<issue_to_address>
**issue (testing):** Пустой `test_decode_token` создает ложное ощущение покрытия и не проверяет декодирование JWT
Сейчас `test_decode_token` не содержит ни одной проверки и всегда проходит.
Предлагаю либо:
- реализовать тест: сгенерировать токен, декодировать его и проверить ключевые поля (`sub`, срок действия и т.п.), а также реакцию на невалидный/просроченный токен;
- либо временно удалить тест, пока он не будет полноценно реализован.
Минимальный набор: один happy-path (валидный токен декодируется корректно) и один негативный сценарий (например, подделанный токен приводит к ожидаемому исключению/результату).
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary by Sourcery
Добавлены пользовательские роли и поддержка блокировок, уточнена работа с Telegram magic token, а также изменены URL-адреса в потоке запуска бота и соответствующие тесты.
New Features:
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
Introduce user roles and banning support, refine Telegram magic token handling, and adjust bot start flow URLs and tests.
New Features:
Bug Fixes:
Enhancements:
Tests: