feat: add path tracking to items and improve checkout/checkin logic with discard support

This commit is contained in:
Martin Tranberg
2026-04-01 10:17:58 +02:00
parent 62725f9be6
commit e14012d2a5

View File

@@ -1751,7 +1751,8 @@ class SharePointApp(wx.Frame):
self.list_ctrl.SetItem(i, 3, "") # Sidst ændret
self.current_items.append({
"type": "SITE", "id": site['id'], "name": name,
"size": None, "modified": "", "web_url": site.get('webUrl')
"size": None, "modified": "", "web_url": site.get('webUrl'),
"path": ["SharePoint", name]
})
def on_tree_expanding(self, event):
@@ -1873,10 +1874,12 @@ class SharePointApp(wx.Frame):
drives = res.json().get('value', [])
drives.sort(key=lambda x: x.get('name', '').lower())
for drive in drives:
name = drive.get('name', '')
items_data.append({
"type": "DRIVE", "id": drive['id'], "name": drive.get('name', ''),
"type": "DRIVE", "id": drive['id'], "name": name,
"drive_id": drive['id'], "modified": "", "size": None,
"web_url": drive.get('webUrl')
"web_url": drive.get('webUrl'),
"path": data['path'] + [name]
})
elif data['type'] in ["DRIVE", "FOLDER"]:
drive_id = data['drive_id']
@@ -1898,7 +1901,8 @@ class SharePointApp(wx.Frame):
"drive_id": drive_id, "modified": modified,
"size": item.get('size') if not is_folder else None,
"web_url": item.get('webUrl'),
"hash": item.get('file', {}).get('hashes', {}).get('quickXorHash') if not is_folder else None
"hash": item.get('file', {}).get('hashes', {}).get('quickXorHash') if not is_folder else None,
"path": data['path'] + [item['name']]
})
wx.CallAfter(self._populate_list_ctrl, items_data, data)
@@ -2192,14 +2196,20 @@ class SharePointApp(wx.Frame):
if remote_hash and ENABLE_HASH_VALIDATION:
file_size = os.path.getsize(get_long_path(local_path))
if file_size <= (HASH_THRESHOLD_MB * 1024 * 1024):
original_hash = quickxorhash(local_path)
if original_hash != remote_hash:
logger.warning(f"Hash mismatch for {file_name}: local={original_hash}, remote={remote_hash}")
# Vi bruger fjern-hash direkte som vores 'original', hvis den er tilgængelig.
# Vi tjekker dog lige at downloaden rent faktisk matchede.
local_check = quickxorhash(local_path)
if local_check == remote_hash:
original_hash = remote_hash
logger.info(f"Download ok for {file_name}. Bruger XOR hash til ændrings-detektering.")
else:
logger.warning(f"Hash mismatch efter download af {file_name}!")
self.show_info(f"Advarsel: Filens integritet kunne ikke bekræftes (XorHash mismatch)", wx.ICON_WARNING)
original_hash = local_check
# Hvis vi ikke beregnede hash pga. størrelse eller manglende remote_hash, gør det nu for lokal detektering
if original_hash is None:
# Her bruger vi SHA256 af hastighedsårsager hvis XOR ikke er absolut nødvendig til lokal sammenligning
# Her bruger vi SHA256 af hastighedsårsager til lokal sammenligning (før/efter)
sha256 = hashlib.sha256()
with open(get_long_path(local_path), 'rb') as f:
while True:
@@ -2207,9 +2217,16 @@ class SharePointApp(wx.Frame):
if not chunk: break
sha256.update(chunk)
original_hash = "SHA256:" + sha256.hexdigest()
logger.info(f"Bruger lokal SHA256 til ændrings-detektering for {file_name}")
# Checkout
requests.post(f"{base_url}/checkout", headers=self.headers)
is_checked_out = False
checkout_res = requests.post(f"{base_url}/checkout", headers=self.headers)
if checkout_res.status_code in [200, 201, 204]:
is_checked_out = True
logger.info(f"Fil {file_name} udtjekket succesfuldt.")
else:
logger.warning(f"Kunne ikke udtjekke {file_name} (Status: {checkout_res.status_code}). Fortsætter dog...")
# 3. Åbn & Overvåg
self.set_status(self.get_txt("msg_opening_file", name=file_name))
@@ -2259,18 +2276,29 @@ class SharePointApp(wx.Frame):
new_hash = quickxorhash(local_path)
if original_hash == new_hash:
logger.info(f"Ingen ændringer fundet i {file_name}. (Hash: {new_hash[:16]}...) Springer upload over.")
self.set_status(self.get_txt("msg_file_unchanged"))
if is_checked_out:
logger.info(f"Annullerer udtjekning (discardCheckout) for {file_name}...")
res = requests.post(f"{base_url}/discardCheckout", headers=self.headers)
if res.status_code in [200, 204]:
is_checked_out = False
else:
# 5. Upload (kun hvis ændret)
logger.info(f"Ændring fundet! Uploader {file_name}...")
self.set_status(self.get_txt("msg_updating_changes"))
with open(local_path, 'rb') as f:
upload_res = requests.put(f"{base_url}/content", headers=self.headers, data=f)
if upload_res.status_code not in [200, 201]:
raise Exception(f"{self.get_txt('msg_update_failed_code', code=upload_res.status_code)}")
# 6. Checkin (Uanset om ændret eller ej, for at frigive lås)
self.set_status(self.get_txt("msg_checking_in", name=file_name))
requests.post(f"{base_url}/checkin", headers=self.headers, json={"comment": "SP Explorer Edit"})
# 6. Checkin (Kun hvis vi faktisk uploadede noget)
if is_checked_out:
self.set_status(self.get_txt("msg_checking_in", name=file_name))
res = requests.post(f"{base_url}/checkin", headers=self.headers, json={"comment": "SP Explorer Edit"})
if res.status_code in [200, 201, 204]:
is_checked_out = False
# Oprydning: Slet fil og derefter mappe
try:
@@ -2287,6 +2315,11 @@ class SharePointApp(wx.Frame):
self.set_status(f"{self.get_txt('msg_error')}: {str(e)}")
self.show_info(f"{self.get_txt('msg_error')}: {e}", wx.ICON_ERROR)
finally:
if is_checked_out:
# Emergency cleanup hvis vi stadig har fat i filen (f.eks. ved crash eller afbrydelse)
logger.info(f"Rydder op: Kalder discardCheckout for {file_name}...")
requests.post(f"{base_url}/discardCheckout", headers=self.headers)
if item_id in self.active_edits:
del self.active_edits[item_id]
self.update_edit_ui()