import re from tenancy.models import Tenant, TenantGroup, Contact, ContactRole from ipam.models import Prefix, VRF, Role from extras.scripts import Script, StringVar, IPNetworkVar, ChoiceVar, ObjectVar from django.core.exceptions import ValidationError from extras.models import CustomField def slugify(text: str): CYRILLIC_TO_LATIN = { "а": "a", "б": "b", "в": "v", "г": "g", "д": "d", "е": "e", "ё": "e", "ж": "zh", "з": "z", "и": "i", "й": "i", "к": "k", "л": "l", "м": "m", "н": "n", "о": "o", "п": "p", "р": "r", "с": "s", "т": "t", "у": "u", "ф": "f", "х": "h", "ц": "c", "ч": "ch", "ш": "sh", "щ": "shch", "ъ": "", "ы": "y", "ь": "", "э": "e", "ю": "yu", "я": "ya", "А": "A", "Б": "B", "В": "V", "Г": "G", "Д": "D", "Е": "E", "Ё": "E", "Ж": "ZH", "З": "Z", "И": "I", "Й": "I", "К": "K", "Л": "L", "М": "M", "Н": "N", "О": "O", "П": "P", "Р": "R", "С": "S", "Т": "T", "У": "U", "Ф": "F", "Х": "H", "Ц": "C", "Ч": "CH", "Ш": "SH", "Щ": "SHCH", "Ъ": "", "Ы": "Y", "Ь": "", "Э": "E", "Ю": "YU", "Я": "YA", } text = text.replace("ООО", "").lstrip() text = "".join(CYRILLIC_TO_LATIN.get(c, c) for c in text) text = text.lower() text = re.sub(r"\s+", "_", text) text = re.sub(r"[^a-z0-9_-]", "", text) text = re.sub(r"[-_]{2,}", "_", text).strip("_-") return text class CreateTenant(Script): class Meta: name = "Создание Оператора" description = "Создание оператора и связанного префикса" fieldsets = ( ( "Оператор", ( "tenant_name", "tenant_group", "tenant_connection_type", "tenant_description", ), ), ( "Префикс", ("prefix_cidr", "prefix_vrf", "prefix_role", "prefix_description"), ), ("Документы", ("tenant_contract", "tenant_prefix_task", "tenant_tr")), ("Контакты", ("contacts_fio", "contacts_phone", "contacts_email")), ) connection_types = CustomField.objects.get(name="connection_type") tenant_name = StringVar(label="Имя оператора") tenant_group = ObjectVar( label="Группа оператора", model=TenantGroup, required=False ) tenant_connection_type = ChoiceVar( label="Тип подключения", choices=connection_types.choices, required=True ) tenant_description = StringVar(label="Описание оператора", required=False) tenant_contract = StringVar( label="Договор", description="Номер договора на разработку комплекса", required=False, ) tenant_tr = StringVar( label="Проект/ТР", description="Пример: DOCXXXXX", required=False ) tenant_prefix_task = StringVar( label="Задача", description="URL или номер задачи из redmine, jira, CRM", required=False, ) prefix_cidr = IPNetworkVar(label="Префикс (CIDR)") prefix_vrf = ObjectVar(label="VRF проекта", model=VRF, required=True) prefix_role = ObjectVar(label="Роль", model=Role, required=True) prefix_description = StringVar(label="Описание префикса", required=False) contacts_fio = StringVar(label="ФИО", required=False) contacts_phone = StringVar(label="Номер тел.", required=False) contacts_email = StringVar(label="E-mail", required=False) contacts_role = ObjectVar(label="Роль контакта", model=ContactRole, required=False) def run(self, data, commit): try: tenant_slug = slugify(data["tenant_name"]) if Tenant.objects.filter(name=data["tenant_name"]).exists(): self.log_failure( f"Оператор с именем '{data['tenant_name']}' уже существует" ) return if Tenant.objects.filter(slug=tenant_slug).exists(): self.log_failure( f"Оператор со slug '{data['tenant_slug']}' уже существует" ) return tenant_data = { "name": data["tenant_name"], "slug": tenant_slug, "group": data["tenant_group"], } if data.get("tenant_description"): tenant_data["description"] = data["tenant_description"] tenant = Tenant(**tenant_data) tenant.custom_field_data["dogovor"] = data["tenant_contract"] tenant.custom_field_data["connection_type"] = data["tenant_connection_type"] tenant.custom_field_data["link_on_docs"] = data["tenant_tr"] tenant.full_clean() if commit: tenant.save() self.log_success( f"Создан новый оператор: {tenant.name} - {tenant.slug}" ) if Prefix.objects.filter(prefix=data["prefix_cidr"]).exists(): self.log_warning(f"Префикс {data['prefix_cidr']} уже существует") return prefix = Prefix( prefix=data["prefix_cidr"], tenant=tenant, description=data.get("prefix_description") or "", vrf=data["prefix_vrf"], role=data["prefix_role"], ) prefix.custom_field_data["Project"] = data["tenant_tr"] prefix.custom_field_data["zadacha"] = data["tenant_prefix_task"] prefix.full_clean() prefix.save() self.log_success( f"Создан префикс {prefix.prefix} для оператора: {tenant.name}" ) if data.get("contacts_fio"): try: role = data.get("contacts_role", ContactRole.objects.first()) except Exception as e: self.log_failure(f"Ошибка при получении роли контакта: {e}") contact = Contact( name=data["contacts_fio"], phone=data["contacts_phone"], email=data["contacts_email"], role=role, tenant=tenant, ) try: contact.full_clean() contact.save() self.log_success(f"Создан контакт: {contact.name}") except Exception as e: self.log_failure(f"Ошибка при создании контакта: {e}") else: self.log_info( f"Тестовый режим: Будет создан оператор: {tenant.name} (slug: {tenant.slug})" ) self.log_info( f"Тестовый режим: Будет создан префикс: {data['prefix_cidr']}" ) try: tenant.full_clean() prefix = Prefix( prefix=data["prefix_cidr"], tenant=tenant, description=data.get("prefix_description") or "", ) prefix.full_clean() contact = Contact( name=data["contacts_fio"], phone=data["contacts_phone"], email=data["contacts_email"], role=data.get("contacts_role", ContactRole.objects.first()), tenant=tenant, ) contact.full_clean() self.log_success("Все данные валидны") except ValidationError as e: self.log_failure(f"Ошибка валидации: {e}") except Exception as e: self.log_failure(f"Ошибка при выполнении скрипта: {e}") if commit: self.log_failure("Изменения отменены из-за ошибки")