AD office-only scope, mapping page, auto-rebuild of directory tree
- ad_connector: restrict provisioning to office employees (user_location_type='office') in sync service, signals and command; disable AD account on transfer out of office, re-enable on return - ad_connector: /ad-mapping/ page (staff only) — match office employees to AD accounts with suggestions by email/login/full name, link/unlink/ create actions, list of unmatched domain accounts; sidebar nav item - core: auto-rebuild treenode Directory tree (_path/_depth) after import-export imports and post_migrate; "rebuild tree" button in DirectoryAdmin and rebuild_directory_tree management command Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
+18
-1
@@ -1,9 +1,11 @@
|
||||
from django.contrib import admin
|
||||
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.translation import gettext_lazy as _
|
||||
from django.urls import reverse
|
||||
from unfold.admin import ModelAdmin
|
||||
from unfold.decorators import action
|
||||
from treenode.forms import TreeNodeForm
|
||||
from django.forms import TextInput, Textarea
|
||||
from django.db.models import Count
|
||||
@@ -132,6 +134,7 @@ class DirectoryAdmin(ModelAdmin, ImportExportModelAdmin):
|
||||
list_display_links = ['name_with_hierarchy']
|
||||
list_filter = [DirectoryTypeFilter, ActiveFilter]
|
||||
ordering = ('_path',)
|
||||
actions_list = ['rebuild_tree_action']
|
||||
|
||||
fieldsets = (
|
||||
(_('Основная информация'), {
|
||||
@@ -156,6 +159,20 @@ class DirectoryAdmin(ModelAdmin, ImportExportModelAdmin):
|
||||
tn_children_count=Count('children', distinct=True)
|
||||
).order_by('_path')
|
||||
|
||||
@action(description=_('🔄 Перестроить дерево'), url_path='rebuild-tree',
|
||||
permissions=['change'])
|
||||
def rebuild_tree_action(self, request):
|
||||
"""Ручная перестройка дерева (пересчёт _path/_depth из parent)"""
|
||||
Directory.update_tree()
|
||||
messages.success(request, _('Дерево справочников перестроено'))
|
||||
return redirect(reverse('admin:core_directory_changelist'))
|
||||
|
||||
def process_result(self, result, request):
|
||||
"""Импорт пишет записи в обход treenode — перестраиваем дерево после него"""
|
||||
if not result.has_errors():
|
||||
Directory.update_tree()
|
||||
return super().process_result(result, request)
|
||||
|
||||
def name_with_hierarchy(self, obj):
|
||||
"""Имя с отступом по уровню вложенности. Глубина из _path (точки)."""
|
||||
path = getattr(obj, '_path', '') or ''
|
||||
|
||||
Reference in New Issue
Block a user