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:
@@ -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()
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -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` в
|
||||||
|
|||||||
35
backend/services/consent_policy_text.py
Normal file
35
backend/services/consent_policy_text.py
Normal 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). Шаблон с плейсхолдерами в квадратных
|
||||||
|
скобках, без указания конкретной организации — администратор обязан
|
||||||
|
заменить их под свою организацию перед вводом в эксплуатацию."""
|
||||||
@@ -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()
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user