chore: Реорганизация проекта - очистка и структурирование файлов
- Добавлена папка ДОКУМЕНТАЦИЯ с централизованным хранением всех руководств - Перенесены утилитарные скрипты в myproject/scripts/ - Удалены временные файлы (current_settings.txt, old_settings.txt, nul) - Добавлены celerybeat-schedule файлы в .gitignore - Обновлен .env.example (удалены устаревшие настройки PLATFORM_SUPPORT) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -5,7 +5,6 @@
|
||||
Единственный источник истины для создания тенанта и всех связанных сущностей.
|
||||
"""
|
||||
import logging
|
||||
import secrets
|
||||
from django.db import connection, transaction
|
||||
from django.utils import timezone
|
||||
from django.conf import settings
|
||||
@@ -229,8 +228,11 @@ class TenantOnboardingService:
|
||||
else:
|
||||
logger.warning(f"Пользователь {registration.owner_email} уже существует")
|
||||
|
||||
# 2. Техподдержка платформы (скрытый аккаунт)
|
||||
cls._create_platform_support_user(registration)
|
||||
# 2. Техподдержка платформы
|
||||
# SECURITY: НЕ создаём отдельную учетку CustomUser для саппорта
|
||||
# PlatformAdmin с is_superuser=True уже имеет полный доступ к tenant
|
||||
# через PlatformAdminBackend и TenantAdminAccessMiddleware
|
||||
logger.info("Техподдержка: используется PlatformAdmin (отдельный CustomUser НЕ создаётся)")
|
||||
|
||||
@classmethod
|
||||
def _assign_owner_role(cls, owner):
|
||||
@@ -245,83 +247,6 @@ class TenantOnboardingService:
|
||||
except Exception as e:
|
||||
logger.error(f"Ошибка при назначении роли: {e}", exc_info=True)
|
||||
|
||||
@classmethod
|
||||
def _create_platform_support_user(cls, registration: TenantRegistration):
|
||||
"""
|
||||
Создание скрытого аккаунта техподдержки платформы.
|
||||
|
||||
- Email берётся из настроек PLATFORM_SUPPORT_EMAIL
|
||||
- Пароль генерируется уникальный для каждого тенанта
|
||||
- Пароль выводится в лог (для владельца платформы)
|
||||
- Пользователь не виден владельцу тенанта
|
||||
"""
|
||||
from accounts.models import CustomUser
|
||||
from user_roles.services import RoleService
|
||||
from user_roles.models import Role
|
||||
|
||||
support_email = getattr(settings, 'PLATFORM_SUPPORT_EMAIL', None)
|
||||
if not support_email:
|
||||
logger.info("PLATFORM_SUPPORT_EMAIL не задан - пропускаем создание техподдержки")
|
||||
return
|
||||
|
||||
if CustomUser.objects.filter(email=support_email).exists():
|
||||
logger.info(f"Техподдержка {support_email} уже существует в этом тенанте")
|
||||
return
|
||||
|
||||
# Генерируем уникальный пароль для этого тенанта
|
||||
password = secrets.token_urlsafe(16)
|
||||
|
||||
support_user = CustomUser.objects.create_user(
|
||||
email=support_email,
|
||||
name='Техподдержка',
|
||||
password=password,
|
||||
)
|
||||
support_user.is_email_confirmed = True
|
||||
support_user.email_confirmed_at = timezone.now()
|
||||
support_user.is_active = True
|
||||
support_user.is_superuser = True
|
||||
support_user.save()
|
||||
|
||||
# Назначаем роль platform_support
|
||||
RoleService.assign_role_to_user(support_user, Role.PLATFORM_SUPPORT, created_by=None)
|
||||
|
||||
# Выводим пароль в лог (безопасно, т.к. логи доступны только владельцу платформы)
|
||||
logger.info(
|
||||
f"[PLATFORM_SUPPORT] Тенант: {registration.schema_name} | "
|
||||
f"Email: {support_email} | Пароль: {password}"
|
||||
)
|
||||
|
||||
# Сохраняем credentials в файл
|
||||
cls._save_support_credentials(registration, support_email, password)
|
||||
|
||||
@classmethod
|
||||
def _save_support_credentials(cls, registration: TenantRegistration, email: str, password: str):
|
||||
"""
|
||||
Сохраняет credentials техподдержки в файл.
|
||||
|
||||
Формат: домен:логин:пароль
|
||||
Файл: support_credentials.txt в корне проекта
|
||||
"""
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
# Корень проекта (где manage.py)
|
||||
project_root = Path(settings.BASE_DIR)
|
||||
credentials_file = project_root / 'support_credentials.txt'
|
||||
|
||||
# Формируем домен тенанта
|
||||
domain_base = settings.TENANT_DOMAIN_BASE
|
||||
if ':' in domain_base:
|
||||
domain_base = domain_base.split(':')[0]
|
||||
tenant_domain = f"{registration.schema_name}.{domain_base}"
|
||||
|
||||
# Добавляем строку в файл
|
||||
try:
|
||||
with open(credentials_file, 'a', encoding='utf-8') as f:
|
||||
f.write(f"{tenant_domain}:{email}:{password}\n")
|
||||
logger.info(f"Credentials сохранены в {credentials_file}")
|
||||
except Exception as e:
|
||||
logger.error(f"Ошибка сохранения credentials: {e}")
|
||||
|
||||
@classmethod
|
||||
def _init_tenant_data(cls):
|
||||
|
||||
Reference in New Issue
Block a user