From 1c2a9cd24a478fc08c1a823cd6fa7cd585ab72da Mon Sep 17 00:00:00 2001 From: Max Ronzhin Date: Mon, 10 Aug 2026 16:09:19 +0300 Subject: [PATCH] =?UTF-8?q?style(backend):=20=D1=80=D0=B0=D0=B7=D0=BE?= =?UTF-8?q?=D0=B1=D1=80=D0=B0=D1=82=D1=8C=2013=20=D0=BF=D1=80=D0=B5=D0=B4?= =?UTF-8?q?=D1=83=D0=BF=D1=80=D0=B5=D0=B6=D0=B4=D0=B5=D0=BD=D0=B8=D0=B9=20?= =?UTF-8?q?ruff=20(E501)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Реальный код переформатирован (models/user.py, services/instance_settings.py, tests/test_auth.py). Текст регламента обработки персональных данных вынесен в services/consent_policy_text.py с точечным per-file-ignore E501 (как и email_templates.py) — это прозаический шаблон документа, а не код, оборачивать его строки ради лимита длины бессмысленно. --- backend/models/user.py | 4 ++- backend/pyproject.toml | 3 +++ backend/services/consent_policy_text.py | 35 +++++++++++++++++++++++++ backend/services/instance_settings.py | 33 +++-------------------- backend/tests/test_auth.py | 12 +++++++-- 5 files changed, 55 insertions(+), 32 deletions(-) create mode 100644 backend/services/consent_policy_text.py diff --git a/backend/models/user.py b/backend/models/user.py index e17d6e1..3c03c7a 100644 --- a/backend/models/user.py +++ b/backend/models/user.py @@ -51,7 +51,9 @@ class User(Base): # был выключен либо пользователь зарегистрирован до появления этой # настройки); вход таким пользователям не блокируется. 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( DateTime(timezone=True), nullable=False, server_default=func.now() ) diff --git a/backend/pyproject.toml b/backend/pyproject.toml index a61e18e..423c3ed 100644 --- a/backend/pyproject.toml +++ b/backend/pyproject.toml @@ -61,6 +61,9 @@ ignore = ["B008"] # FastAPI's `Depends(...)` default-argument pattern is idioma # большинство из них игнорирует) — длина строки не показатель качества здесь, # оборачивать вёрстку ради line-length бессмысленно. "services/email_templates.py" = ["E501"] +# Дефолтный текст регламента обработки персональных данных — прозаический +# шаблон документа, не код (см. докстринг модуля). +"services/consent_policy_text.py" = ["E501"] [tool.ruff.lint.isort] # `workers/` — соседний пакет монорепо (см. `pythonpath` в diff --git a/backend/services/consent_policy_text.py b/backend/services/consent_policy_text.py new file mode 100644 index 0000000..5f518a0 --- /dev/null +++ b/backend/services/consent_policy_text.py @@ -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). Шаблон с плейсхолдерами в квадратных +скобках, без указания конкретной организации — администратор обязан +заменить их под свою организацию перед вводом в эксплуатацию.""" diff --git a/backend/services/instance_settings.py b/backend/services/instance_settings.py index cf3df90..718b6e0 100644 --- a/backend/services/instance_settings.py +++ b/backend/services/instance_settings.py @@ -42,6 +42,7 @@ from core.plugins.config import ( from models.instance_setting import InstanceSetting from services.ai_levels import detect_ai_levels from services.ai_tiers import TIERS +from services.consent_policy_text import DEFAULT_CONSENT_POLICY_TEXT _KEY_TRANSCRIBER = "transcriber" _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] = { "enabled": False, "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: 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 = ( patch.consent_policy_text.strip() diff --git a/backend/tests/test_auth.py b/backend/tests/test_auth.py index 67b9638..ba3abe4 100644 --- a/backend/tests/test_auth.py +++ b/backend/tests/test_auth.py @@ -529,7 +529,11 @@ async def test_register_without_consent_when_required_returns_400( response = await client.post( "/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.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`.""" response = await client.post( "/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