commit 070a1722d28b3bf5a53384a004be698383aa28d2 Author: IluaAir Date: Mon Sep 29 12:48:09 2025 +0300 init diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7a3a3f1 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/.venv/ +/.idea/ diff --git a/add_tenant_with_prefix.py b/add_tenant_with_prefix.py new file mode 100644 index 0000000..7108224 --- /dev/null +++ b/add_tenant_with_prefix.py @@ -0,0 +1,151 @@ +import re + +from tenancy.models import Tenant, TenantGroup +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='ФИО') + contacts_phone = StringVar(label='Номер тел.') + contacts_email = StringVar(label='E-mail') + + 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}") + 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}") + + 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() + 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("Изменения отменены из-за ошибки")