Интеграции AD/Mattermost: OU-управление, импорт, шифрование токенов

- ad_connector: страницы управления OU и импорта из AD, поле ad_ou_dn
  в Directory, ADSyncLog; расширение sync-сервиса и клиента
- mattermost_connector: personal access token шифруется (Fernet,
  token_service), бот-сервис, команды создания бота и синхронизации;
  публикация постов в каналы. Тесты (19)
- core: ConnectorConfig, Directory (ad_ou_dn), обновления админки

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-22 17:32:26 +03:00
parent 38747a93fc
commit 81dee5cba2
23 changed files with 1245 additions and 35 deletions
+6 -5
View File
@@ -2,6 +2,7 @@ from django.contrib import admin, messages
from django.contrib.admin import SimpleListFilter
from django.shortcuts import redirect
from django.utils.html import format_html
from django.utils.safestring import mark_safe
from django.utils.translation import gettext_lazy as _
from django.urls import reverse
from unfold.admin import ModelAdmin
@@ -141,8 +142,9 @@ class DirectoryAdmin(ModelAdmin, ImportExportModelAdmin):
'fields': ('directory_type', 'parent', 'code', 'name', 'description', 'is_active')
}),
(_('Должности и локации'), {
'fields': ('location_types', 'ad_group_dn'),
'description': 'location_types — для должностей: в каких локациях доступна. ad_group_dn — для отделов.',
'fields': ('location_types', 'ad_group_dn', 'ad_ou_dn'),
'description': 'location_types — для должностей: в каких локациях доступна. '
'ad_group_dn, ad_ou_dn — для отделов.',
'classes': ('collapse',)
}),
(_('Дополнительные данные'), {
@@ -197,13 +199,13 @@ class DirectoryAdmin(ModelAdmin, ImportExportModelAdmin):
location_types = obj.location_types.all()
if not location_types.exists():
return format_html('<span style="color: #999;">Все типы</span>')
return mark_safe('<span style="color: #999;">Все типы</span>')
types_html = ', '.join([
f'<span style="background-color: #e3f2fd; padding: 2px 6px; border-radius: 3px; font-size: 11px;">{lt.name}</span>'
for lt in location_types
])
return format_html(types_html)
return mark_safe(types_html)
location_types_display.short_description = _('Типы локаций')
def children_count_display(self, obj):
@@ -236,7 +238,6 @@ class ConnectorConfigAdmin(ModelAdmin):
}),
(_('Дополнительные параметры'), {
'fields': ('extra_config',),
'classes': ('collapse',),
}),
)