134 lines
No EOL
5.1 KiB
Python
134 lines
No EOL
5.1 KiB
Python
"""
|
|
Management command: migrate_project_permissions
|
|
================================================
|
|
Migre les droits existants vers le nouveau modèle de permissions de projets.
|
|
|
|
Deux opérations :
|
|
1. UserThematics.can_view_interventions = True -> can_view_projects = True
|
|
2. Lecture du fichier JSON exporte par `export_project_members` :
|
|
- tout role -> ProjectUserAccess(can_view=True)
|
|
- role='owner' -> ProjectUserAccess(can_edit=True)
|
|
|
|
Flux recommande en production :
|
|
1. python manage.py export_project_members
|
|
2. python manage.py migrate projects 0020_projectteamaccess_projectuseraccess
|
|
3. python manage.py migrate common 0064_userthematics_project_permissions
|
|
4. python manage.py migrate_project_permissions [--input project_members_export.json]
|
|
5. python manage.py migrate projects 0021_remove_projectmember
|
|
|
|
Usage :
|
|
python manage.py migrate_project_permissions [--dry-run] [--input fichier.json]
|
|
"""
|
|
|
|
import json
|
|
from pathlib import Path
|
|
|
|
from django.core.management.base import BaseCommand, CommandError
|
|
from django.db import transaction
|
|
|
|
DEFAULT_INPUT = Path("project_members_export.json")
|
|
|
|
|
|
class Command(BaseCommand):
|
|
help = "Migre les droits existants vers le nouveau modele de permissions de projets."
|
|
|
|
def add_arguments(self, parser):
|
|
parser.add_argument(
|
|
'--dry-run',
|
|
action='store_true',
|
|
help="Simule la migration sans ecrire en base.",
|
|
)
|
|
parser.add_argument(
|
|
'--input', '-i',
|
|
type=Path,
|
|
default=DEFAULT_INPUT,
|
|
help=f"Fichier JSON exporte par export_project_members (defaut : {DEFAULT_INPUT})",
|
|
)
|
|
|
|
def handle(self, *args, **options):
|
|
dry_run = options['dry_run']
|
|
|
|
if dry_run:
|
|
self.stdout.write(self.style.WARNING("=== MODE DRY-RUN : aucune ecriture en base ===\n"))
|
|
|
|
self._migrate_thematics(dry_run)
|
|
self._import_members(options['input'], dry_run)
|
|
|
|
self.stdout.write(self.style.SUCCESS("\nMigration des permissions terminee."))
|
|
|
|
def _migrate_thematics(self, dry_run):
|
|
from common.models import UserThematics
|
|
|
|
qs = UserThematics.objects.filter(can_view_interventions=True, can_view_projects=False)
|
|
count = qs.count()
|
|
self.stdout.write(
|
|
f"[Thematiques] {count} enregistrement(s) a mettre a jour "
|
|
"(can_view_interventions=True -> can_view_projects=True)."
|
|
)
|
|
if count and not dry_run:
|
|
with transaction.atomic():
|
|
updated = qs.update(can_view_projects=True)
|
|
self.stdout.write(self.style.SUCCESS(f" -> {updated} mis a jour."))
|
|
|
|
def _import_members(self, input_path, dry_run):
|
|
from projects.models import ProjectUserAccess
|
|
|
|
if not input_path.exists():
|
|
raise CommandError(
|
|
f"Fichier introuvable : '{input_path}'. "
|
|
"Lancez d'abord : python manage.py export_project_members"
|
|
)
|
|
|
|
data = json.loads(input_path.read_text(encoding='utf-8'))
|
|
total = len(data)
|
|
self.stdout.write(f"[ProjectMember] {total} entree(s) a importer depuis '{input_path}'.")
|
|
|
|
created = updated = skipped = 0
|
|
|
|
with transaction.atomic():
|
|
for row in data:
|
|
project_id = row['project_id']
|
|
user_id = row['member_id']
|
|
can_edit = row['role'] == 'owner'
|
|
|
|
existing = ProjectUserAccess.objects.filter(
|
|
project_id=project_id, user_id=user_id
|
|
).first()
|
|
|
|
if existing:
|
|
changed = False
|
|
if not existing.can_view:
|
|
existing.can_view = True
|
|
changed = True
|
|
if can_edit and not existing.can_edit:
|
|
existing.can_edit = True
|
|
changed = True
|
|
if changed:
|
|
if not dry_run:
|
|
existing.save(update_fields=['can_view', 'can_edit'])
|
|
updated += 1
|
|
self.stdout.write(
|
|
f" MODIFIE user_id={user_id} -> project_id={project_id} "
|
|
f"(can_view=True, can_edit={existing.can_edit})"
|
|
)
|
|
else:
|
|
skipped += 1
|
|
else:
|
|
if not dry_run:
|
|
ProjectUserAccess.objects.create(
|
|
project_id=project_id,
|
|
user_id=user_id,
|
|
can_view=True,
|
|
can_edit=can_edit,
|
|
)
|
|
created += 1
|
|
self.stdout.write(
|
|
f" CREE user_id={user_id} -> project_id={project_id} "
|
|
f"(can_view=True, can_edit={can_edit})"
|
|
)
|
|
|
|
self.stdout.write(
|
|
self.style.SUCCESS(
|
|
f" -> {created} cree(s), {updated} mis a jour, {skipped} inchange(s)."
|
|
)
|
|
) |