style(backend): разобрать 13 предупреждений ruff (E501)

Реальный код переформатирован (models/user.py, services/instance_settings.py,
tests/test_auth.py). Текст регламента обработки персональных данных вынесен
в services/consent_policy_text.py с точечным per-file-ignore E501 (как и
email_templates.py) — это прозаический шаблон документа, а не код, оборачивать
его строки ради лимита длины бессмысленно.
This commit is contained in:
2026-08-10 16:09:19 +03:00
parent c4485d43b1
commit 1c2a9cd24a
5 changed files with 55 additions and 32 deletions

View File

@@ -51,7 +51,9 @@ class User(Base):
# был выключен либо пользователь зарегистрирован до появления этой # был выключен либо пользователь зарегистрирован до появления этой
# настройки); вход таким пользователям не блокируется. # настройки); вход таким пользователям не блокируется.
consent_version: Mapped[int | None] = mapped_column(Integer, nullable=True) consent_version: Mapped[int | None] = mapped_column(Integer, nullable=True)
consent_given_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True) consent_given_at: Mapped[datetime | None] = mapped_column(
DateTime(timezone=True), nullable=True
)
created_at: Mapped[datetime] = mapped_column( created_at: Mapped[datetime] = mapped_column(
DateTime(timezone=True), nullable=False, server_default=func.now() DateTime(timezone=True), nullable=False, server_default=func.now()
) )

View File

@@ -61,6 +61,9 @@ ignore = ["B008"] # FastAPI's `Depends(...)` default-argument pattern is idioma
# большинство из них игнорирует) — длина строки не показатель качества здесь, # большинство из них игнорирует) — длина строки не показатель качества здесь,
# оборачивать вёрстку ради line-length бессмысленно. # оборачивать вёрстку ради line-length бессмысленно.
"services/email_templates.py" = ["E501"] "services/email_templates.py" = ["E501"]
# Дефолтный текст регламента обработки персональных данных — прозаический
# шаблон документа, не код (см. докстринг модуля).
"services/consent_policy_text.py" = ["E501"]
[tool.ruff.lint.isort] [tool.ruff.lint.isort]
# `workers/` — соседний пакет монорепо (см. `pythonpath` в # `workers/` — соседний пакет монорепо (см. `pythonpath` в

View File

@@ -0,0 +1,35 @@
"""Дефолтный текст регламента обработки персональных данных (ключ `instance_settings.consent_policy`).
Вынесен из `services/instance_settings.py` в отдельный модуль ради `E501`:
это прозаический шаблон документа, а не код, оборачивать его строки ради
лимита длины строки бессмысленно — так же, как `email_templates.py`
(см. `[tool.ruff.lint.per-file-ignores]` в `pyproject.toml`).
"""
DEFAULT_CONSENT_POLICY_TEXT = """Это типовой шаблон для предварительной демонстрации. Текст не проходил проверку юриста и не может использоваться как окончательная редакция без такой проверки. Администратор обязан заменить плейсхолдеры в квадратных скобках и, при необходимости, весь текст — под свою организацию и юрисдикцию.
1. Оператор персональных данных
Оператором персональных данных, обрабатываемых при использовании сервиса [название сервиса], является: [полное наименование организации], [ОГРН/ИНН], адрес места нахождения: [адрес]. Контакты по вопросам обработки персональных данных: [email], [телефон].
2. Правовое основание обработки
Обработка персональных данных осуществляется в соответствии с Конституцией Российской Федерации, Федеральным законом от 27.07.2006 № 152-ФЗ «О персональных данных» и принятыми в соответствии с ним нормативными правовыми актами, на основании согласия субъекта персональных данных (статья 9 Федерального закона № 152-ФЗ).
3. Состав и цели обработки
При регистрации в сервисе обрабатываются следующие персональные данные: адрес электронной почты, имя и фамилия (или иное указанное пользователем имя), пароль (в виде хеша) [дополнить при необходимости].
Цели обработки: [указать цели — например: создание учётной записи, идентификация пользователя, обеспечение доступа к видеоконференциям, направление служебных уведомлений].
4. Срок обработки и хранения
Персональные данные хранятся в течение [указать срок — например: срока действия учётной записи и установленного законом срока после её удаления] либо до отзыва согласия, если это не противоречит требованиям законодательства.
5. Действия с персональными данными
В отношении персональных данных совершаются следующие действия: сбор, запись, систематизация, накопление, хранение, уточнение, извлечение, использование, передача (в объёме, необходимом для функционирования сервиса), обезличивание, блокирование, удаление, уничтожение.
6. Права субъекта персональных данных
Субъект персональных данных вправе получать информацию о том, как обрабатываются его персональные данные, требовать их уточнения, блокирования или уничтожения, а также отозвать согласие на обработку, обратившись по контактам, указанным в разделе 1.
7. Согласие
Регистрируясь в сервисе, пользователь подтверждает, что ознакомлен с настоящим регламентом и даёт согласие на обработку своих персональных данных на условиях, изложенных выше."""
"""Дефолтный текст регламента (ключ `consent_policy`) — согласован с оператором
до встраивания в код (сессия 30). Шаблон с плейсхолдерами в квадратных
скобках, без указания конкретной организации — администратор обязан
заменить их под свою организацию перед вводом в эксплуатацию."""

View File

@@ -42,6 +42,7 @@ from core.plugins.config import (
from models.instance_setting import InstanceSetting from models.instance_setting import InstanceSetting
from services.ai_levels import detect_ai_levels from services.ai_levels import detect_ai_levels
from services.ai_tiers import TIERS from services.ai_tiers import TIERS
from services.consent_policy_text import DEFAULT_CONSENT_POLICY_TEXT
_KEY_TRANSCRIBER = "transcriber" _KEY_TRANSCRIBER = "transcriber"
_KEY_SUMMARIZER = "summarizer" _KEY_SUMMARIZER = "summarizer"
@@ -107,34 +108,6 @@ _DEFAULT_VIRTUAL_BACKGROUND_VALUE = {"enabled": False}
нейросеть сегментации на клиенте, и включать её самим фактом обновления у тех, нейросеть сегментации на клиенте, и включать её самим фактом обновления у тех,
кто ничего не просил, нельзя (то же правило, что и у остальных модулей).""" кто ничего не просил, нельзя (то же правило, что и у остальных модулей)."""
DEFAULT_CONSENT_POLICY_TEXT = """Это типовой шаблон для предварительной демонстрации. Текст не проходил проверку юриста и не может использоваться как окончательная редакция без такой проверки. Администратор обязан заменить плейсхолдеры в квадратных скобках и, при необходимости, весь текст — под свою организацию и юрисдикцию.
1. Оператор персональных данных
Оператором персональных данных, обрабатываемых при использовании сервиса [название сервиса], является: [полное наименование организации], [ОГРН/ИНН], адрес места нахождения: [адрес]. Контакты по вопросам обработки персональных данных: [email], [телефон].
2. Правовое основание обработки
Обработка персональных данных осуществляется в соответствии с Конституцией Российской Федерации, Федеральным законом от 27.07.2006 № 152-ФЗ «О персональных данных» и принятыми в соответствии с ним нормативными правовыми актами, на основании согласия субъекта персональных данных (статья 9 Федерального закона № 152-ФЗ).
3. Состав и цели обработки
При регистрации в сервисе обрабатываются следующие персональные данные: адрес электронной почты, имя и фамилия (или иное указанное пользователем имя), пароль (в виде хеша) [дополнить при необходимости].
Цели обработки: [указать цели — например: создание учётной записи, идентификация пользователя, обеспечение доступа к видеоконференциям, направление служебных уведомлений].
4. Срок обработки и хранения
Персональные данные хранятся в течение [указать срок — например: срока действия учётной записи и установленного законом срока после её удаления] либо до отзыва согласия, если это не противоречит требованиям законодательства.
5. Действия с персональными данными
В отношении персональных данных совершаются следующие действия: сбор, запись, систематизация, накопление, хранение, уточнение, извлечение, использование, передача (в объёме, необходимом для функционирования сервиса), обезличивание, блокирование, удаление, уничтожение.
6. Права субъекта персональных данных
Субъект персональных данных вправе получать информацию о том, как обрабатываются его персональные данные, требовать их уточнения, блокирования или уничтожения, а также отозвать согласие на обработку, обратившись по контактам, указанным в разделе 1.
7. Согласие
Регистрируясь в сервисе, пользователь подтверждает, что ознакомлен с настоящим регламентом и даёт согласие на обработку своих персональных данных на условиях, изложенных выше."""
"""Дефолтный текст регламента (ключ `consent_policy`) — согласован с оператором
до встраивания в код (сессия 30). Шаблон с плейсхолдерами в квадратных
скобках, без указания конкретной организации — администратор обязан
заменить их под свою организацию перед вводом в эксплуатацию."""
_DEFAULT_CONSENT_POLICY_VALUE: dict[str, Any] = { _DEFAULT_CONSENT_POLICY_VALUE: dict[str, Any] = {
"enabled": False, "enabled": False,
"text": DEFAULT_CONSENT_POLICY_TEXT, "text": DEFAULT_CONSENT_POLICY_TEXT,
@@ -455,7 +428,9 @@ class InstanceSettingsService:
if patch.consent_required is not None or patch.consent_policy_text is not None: if patch.consent_required is not None or patch.consent_policy_text is not None:
consent_required = ( consent_required = (
patch.consent_required if patch.consent_required is not None else cfg.consent_required patch.consent_required
if patch.consent_required is not None
else cfg.consent_required
) )
consent_text = ( consent_text = (
patch.consent_policy_text.strip() patch.consent_policy_text.strip()

View File

@@ -529,7 +529,11 @@ async def test_register_without_consent_when_required_returns_400(
response = await client.post( response = await client.post(
"/api/v1/auth/register", "/api/v1/auth/register",
json={"email": "no-consent@example.com", "name_user": "No Consent", "password": "supersecret1"}, json={
"email": "no-consent@example.com",
"name_user": "No Consent",
"password": "supersecret1",
},
) )
assert response.status_code == 400 assert response.status_code == 400
assert response.json()["detail"] == "consent_required" assert response.json()["detail"] == "consent_required"
@@ -571,7 +575,11 @@ async def test_register_without_consent_when_module_disabled_succeeds_and_leaves
галочки, `consent_version`/`consent_given_at` остаются `NULL`.""" галочки, `consent_version`/`consent_given_at` остаются `NULL`."""
response = await client.post( response = await client.post(
"/api/v1/auth/register", "/api/v1/auth/register",
json={"email": "consent-disabled@example.com", "name_user": "Consent Disabled", "password": "supersecret1"}, json={
"email": "consent-disabled@example.com",
"name_user": "Consent Disabled",
"password": "supersecret1",
},
) )
assert response.status_code == 201, response.text assert response.status_code == 201, response.text