193 lines
8.2 KiB
Python
193 lines
8.2 KiB
Python
"""
|
|
Exporte les configurations utilisateur (UserConfig + toutes les relations)
|
|
dans un fichier JSON portable entre environnements.
|
|
|
|
Usage :
|
|
# Exporter tous les utilisateurs
|
|
python manage.py export_user_configs --output exports/user_configs.json
|
|
|
|
# Exporter un ou plusieurs utilisateurs précis
|
|
python manage.py export_user_configs --user alice@example.com --user bob@example.com --output users.json
|
|
|
|
# Afficher dans la console (stdout)
|
|
python manage.py export_user_configs
|
|
"""
|
|
|
|
import json
|
|
import sys
|
|
from django.core.management.base import BaseCommand
|
|
from django.contrib.auth import get_user_model
|
|
|
|
from common.models import UserConfig, UserThematics, UserContractAccess, UserWarehouseAccess, UserWarehouseLocationAccess
|
|
from common.models import UserThematicStatusPermission, UserContractStatusPermission
|
|
from contracts.models import UserCompanyTeamAccess
|
|
|
|
User = get_user_model()
|
|
|
|
EXPORT_VERSION = 2
|
|
|
|
|
|
class Command(BaseCommand):
|
|
help = 'Exporte les configurations utilisateur en JSON.'
|
|
|
|
def add_arguments(self, parser):
|
|
parser.add_argument(
|
|
'--output', '-o',
|
|
metavar='FICHIER',
|
|
default=None,
|
|
help='Chemin du fichier de sortie. Si absent, affiche sur stdout.',
|
|
)
|
|
parser.add_argument(
|
|
'--user',
|
|
metavar='USERNAME_OR_EMAIL',
|
|
action='append',
|
|
default=[],
|
|
dest='users',
|
|
help='Limite l\'export à ces utilisateurs (répétable). Accepte username ou email.',
|
|
)
|
|
|
|
def handle(self, *args, **options):
|
|
qs = UserConfig.objects.select_related(
|
|
'user', 'default_thematic', 'company'
|
|
).prefetch_related(
|
|
'roles',
|
|
'accessible_views',
|
|
'linked_configs__user',
|
|
'userthematics__thematic',
|
|
'userthematics__status_permissions',
|
|
'usercontractaccess_set__contract',
|
|
'usercontractaccess_set__status_permissions',
|
|
'userwarehouses__warehouse',
|
|
'team_accesses__team__company',
|
|
'userlocations__warehouse_location',
|
|
)
|
|
|
|
identifiers = options['users']
|
|
if identifiers:
|
|
qs = qs.filter(
|
|
user__username__in=identifiers
|
|
) | qs.filter(
|
|
user__email__in=identifiers
|
|
)
|
|
qs = qs.distinct()
|
|
if not qs.exists():
|
|
self.stderr.write(self.style.ERROR(
|
|
f'Aucun utilisateur trouvé pour : {", ".join(identifiers)}'
|
|
))
|
|
return
|
|
|
|
payload = {
|
|
'version': EXPORT_VERSION,
|
|
'exported_at': __import__('datetime').datetime.utcnow().isoformat() + 'Z',
|
|
'count': qs.count(),
|
|
'users': [self._serialize_config(cfg) for cfg in qs],
|
|
}
|
|
|
|
output_json = json.dumps(payload, indent=2, ensure_ascii=False)
|
|
|
|
output_path = options['output']
|
|
if output_path:
|
|
with open(output_path, 'w', encoding='utf-8') as fh:
|
|
fh.write(output_json)
|
|
self.stdout.write(self.style.SUCCESS(
|
|
f'{payload["count"]} configuration(s) exportée(s) vers {output_path}'
|
|
))
|
|
else:
|
|
sys.stdout.write(output_json + '\n')
|
|
|
|
# ------------------------------------------------------------------
|
|
|
|
def _serialize_config(self, cfg):
|
|
return {
|
|
'username': cfg.user.username,
|
|
'email': cfg.user.email,
|
|
'first_name': cfg.user.first_name,
|
|
'last_name': cfg.user.last_name,
|
|
'is_intern': cfg.is_intern,
|
|
'generic_email': cfg.generic_email,
|
|
'default_thematic': cfg.default_thematic.code if cfg.default_thematic else None,
|
|
'company': cfg.company.name if cfg.company else None,
|
|
'limit_assets_to_contracts': cfg.limit_assets_to_contracts,
|
|
'limit_interventions_to_contracts': cfg.limit_interventions_to_contracts,
|
|
'limit_shortcuts_to_contracts': cfg.limit_shortcuts_to_contracts,
|
|
'hide_intervention_map_by_default': cfg.hide_intervention_map_by_default,
|
|
'auto_logout_hours': cfg.auto_logout_hours,
|
|
'can_add_unique_tag_documents': cfg.can_add_unique_tag_documents,
|
|
'roles': list(cfg.roles.values_list('name', flat=True)),
|
|
'accessible_views': list(cfg.accessible_views.values_list('code', flat=True)),
|
|
'linked_configs': list(cfg.linked_configs.values_list('user__username', flat=True)),
|
|
'thematics': [self._serialize_thematic(ut) for ut in cfg.userthematics.all()],
|
|
'contracts': [self._serialize_contract(uc) for uc in cfg.usercontractaccess_set.all()],
|
|
'warehouses': [self._serialize_warehouse(wa) for wa in cfg.userwarehouses.all()],
|
|
'locations': [self._serialize_location(la) for la in cfg.userlocations.all()],
|
|
'team_accesses': [self._serialize_team(ta) for ta in cfg.team_accesses.all()],
|
|
}
|
|
|
|
def _serialize_thematic(self, ut):
|
|
return {
|
|
'thematic': ut.thematic.code,
|
|
'can_view_assets': ut.can_view_assets,
|
|
'can_edit_assets': ut.can_edit_assets,
|
|
'can_view_interventions': ut.can_view_interventions,
|
|
'can_edit_interventions': ut.can_edit_interventions,
|
|
'can_edit_locations': ut.can_edit_locations,
|
|
'can_process_observations': ut.can_process_observations,
|
|
'status_permissions': [
|
|
{
|
|
'status': sp.status,
|
|
'can_view': sp.can_view,
|
|
'can_edit': sp.can_edit,
|
|
'can_change_status_to': sp.can_change_status_to,
|
|
}
|
|
for sp in ut.status_permissions.all()
|
|
],
|
|
}
|
|
|
|
def _serialize_contract(self, uc):
|
|
return {
|
|
'contract': uc.contract.contract_number,
|
|
'can_view_posts': uc.can_view_posts,
|
|
'can_view_prices': uc.can_view_prices,
|
|
'can_view_interventions': uc.can_view_interventions,
|
|
'can_view_assets': uc.can_view_assets,
|
|
'can_create_interventions': uc.can_create_interventions,
|
|
'can_check_interventions': uc.can_check_interventions,
|
|
'can_approve': uc.can_approve,
|
|
'status_permissions': [
|
|
{
|
|
'status': sp.status,
|
|
'can_view': sp.can_view,
|
|
'can_edit': sp.can_edit,
|
|
'can_change_status_to': sp.can_change_status_to,
|
|
}
|
|
for sp in uc.status_permissions.all()
|
|
],
|
|
}
|
|
|
|
def _serialize_warehouse(self, wa):
|
|
return {
|
|
'warehouse': wa.warehouse.code,
|
|
'can_view': wa.can_view,
|
|
'can_manage': wa.can_manage,
|
|
'can_administer': wa.can_administer,
|
|
'can_manage_preparation_orders': wa.can_manage_preparation_orders,
|
|
'can_manage_purchase_orders': wa.can_manage_purchase_orders,
|
|
'can_validate_inventory': wa.can_validate_inventory,
|
|
'is_default': wa.is_default,
|
|
}
|
|
|
|
def _serialize_location(self, la):
|
|
return {
|
|
'location_code': la.warehouse_location.code,
|
|
'can_perform_inventory': la.can_perform_inventory,
|
|
'can_validate_inventory': la.can_validate_inventory,
|
|
}
|
|
|
|
def _serialize_team(self, ta):
|
|
return {
|
|
'team': ta.team.name,
|
|
'company': ta.team.company.name,
|
|
'can_view': ta.can_view,
|
|
'can_edit': ta.can_edit,
|
|
'can_tag': ta.can_tag,
|
|
}
|