feat: add rclone support to import command and implement duplicate document skipping during sync

This commit is contained in:
kdeterme 2026-08-21 15:04:08 +02:00
parent dda68cabec
commit 0ab5fee09b

View file

@ -1,4 +1,5 @@
import os
import subprocess
from django.core.management.base import BaseCommand, CommandError
from django.contrib.contenttypes.models import ContentType
from django.contrib.auth import get_user_model
@ -15,15 +16,20 @@ User = get_user_model()
class Command(BaseCommand):
help = (
"Imports As-Built documents from a local directory into the "
"'Electromechanics / As-Built' subfolder of specified structures."
"Imports As-Built documents from a local directory or via rclone from OneDrive "
"into the 'Electromechanics / As-Built' subfolder of specified structures."
)
def add_arguments(self, parser):
parser.add_argument(
"--source-dir",
required=True,
help="Path to the directory containing files/folders to import.",
default="/tmp/as_built_sync",
help="Path to local directory containing files/folders to import (default: /tmp/as_built_sync).",
)
parser.add_argument(
"--rclone-remote",
default=None,
help="Optional rclone remote path (e.g. 'onedrive:DPO_TUNNEL_EM_AS-BUILT') to sync before import.",
)
parser.add_argument(
"--structures",
@ -49,17 +55,32 @@ class Command(BaseCommand):
def handle(self, *args, **options):
source_dir = options["source_dir"]
rclone_remote = options["rclone_remote"]
target_codes = options["structures"]
dry_run = options["dry_run"]
username = options["user"]
tag_name = options["tag"]
if not os.path.isdir(source_dir):
raise CommandError(f"Source directory '{source_dir}' does not exist or is not a directory.")
if dry_run:
self.stdout.write(self.style.WARNING("DRY RUN — no changes will be committed."))
# Optionnel: Synchronisation via rclone si un remote est spécifié
if rclone_remote:
self.stdout.write(self.style.NOTICE(f"Syncing from rclone remote '{rclone_remote}' to '{source_dir}'..."))
os.makedirs(source_dir, exist_ok=True)
rclone_cmd = ["rclone", "copy", rclone_remote, source_dir]
rclone_conf = os.path.join(os.getcwd(), "rclone.conf")
if os.path.exists(rclone_conf):
rclone_cmd.extend(["--config", rclone_conf])
res = subprocess.run(rclone_cmd, capture_output=True, text=True)
if res.returncode != 0:
raise CommandError(f"rclone sync failed:\n{res.stderr}")
self.stdout.write(self.style.SUCCESS("rclone sync completed successfully."))
if not os.path.isdir(source_dir):
raise CommandError(f"Source directory '{source_dir}' does not exist or is not a directory.")
# Creator user lookup
creator_user = None
if username:
@ -134,6 +155,7 @@ class Command(BaseCommand):
structures = Structure.objects.all()
total_imported = 0
total_skipped = 0
for structure in structures:
# Check if there is a dedicated subfolder for this structure code or name in source_dir
@ -173,12 +195,24 @@ class Command(BaseCommand):
continue
self.stdout.write(f" Target subfolder: Electromechanics / As-Built (ID: {as_built_folder.pk or 'dry-run'})")
self.stdout.write(f" Found {len(files_to_import)} file(s) to import.")
self.stdout.write(f" Found {len(files_to_import)} file(s) to process.")
for file_path in files_to_import:
rel_name = os.path.basename(file_path)
doc_title = os.path.splitext(rel_name)[0]
# Deduplication check
if as_built_folder.pk:
existing_doc = ManagedDocument.objects.filter(
folders=as_built_folder,
title=doc_title,
is_archived=False
).first()
if existing_doc:
self.stdout.write(f" Document '{rel_name}' already exists in As-Built folder (Doc ID: {existing_doc.pk}). Skipped.")
total_skipped += 1
continue
if dry_run:
self.stdout.write(f" [Dry-run] Would import '{rel_name}' into structure {structure.code}")
total_imported += 1
@ -216,4 +250,4 @@ class Command(BaseCommand):
self.stdout.write(self.style.SUCCESS(f" Imported '{rel_name}' (Doc ID: {doc.pk})"))
total_imported += 1
self.stdout.write(self.style.SUCCESS(f"\nDone! Total documents imported: {total_imported}"))
self.stdout.write(self.style.SUCCESS(f"\nDone! Imported: {total_imported}, Skipped (already imported): {total_skipped}"))