Compare commits
2 Commits
14e327989c
...
d3a7ce69e9
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d3a7ce69e9 | ||
|
|
2b82a7aa5c |
@@ -62,6 +62,14 @@ class SharePointApp(wx.Frame):
|
|||||||
self.tree_item_data = {} # Mappenoder -> {type, id, name, drive_id, path}
|
self.tree_item_data = {} # Mappenoder -> {type, id, name, drive_id, path}
|
||||||
self.tree_root = None
|
self.tree_root = None
|
||||||
self.is_navigating_back = False
|
self.is_navigating_back = False
|
||||||
|
self.is_editing = False # Låse-state ved filredigering
|
||||||
|
|
||||||
|
# System Ikoner (ArtProvider - mest basale for kompatibilitet)
|
||||||
|
self.image_list = wx.ImageList(16, 16)
|
||||||
|
self.idx_site = self.image_list.Add(wx.ArtProvider.GetBitmap(wx.ART_GO_HOME, wx.ART_OTHER, (16, 16))) # Site (Hus ikon)
|
||||||
|
self.idx_drive = self.image_list.Add(wx.ArtProvider.GetBitmap(wx.ART_HARDDISK, wx.ART_OTHER, (16, 16))) # Drive
|
||||||
|
self.idx_folder = self.image_list.Add(wx.ArtProvider.GetBitmap(wx.ART_FOLDER, wx.ART_OTHER, (16, 16))) # Folder
|
||||||
|
self.idx_file = self.image_list.Add(wx.ArtProvider.GetBitmap(wx.ART_NORMAL_FILE, wx.ART_OTHER, (16, 16))) # File
|
||||||
|
|
||||||
# Threading/Sync til filredigering
|
# Threading/Sync til filredigering
|
||||||
self.edit_wait_event = threading.Event()
|
self.edit_wait_event = threading.Event()
|
||||||
@@ -69,6 +77,7 @@ class SharePointApp(wx.Frame):
|
|||||||
self.InitUI()
|
self.InitUI()
|
||||||
self.Centre()
|
self.Centre()
|
||||||
self.Show()
|
self.Show()
|
||||||
|
self.Bind(wx.EVT_CLOSE, self.on_close_window)
|
||||||
|
|
||||||
def InitUI(self):
|
def InitUI(self):
|
||||||
panel = wx.Panel(self)
|
panel = wx.Panel(self)
|
||||||
@@ -132,11 +141,13 @@ class SharePointApp(wx.Frame):
|
|||||||
|
|
||||||
# Left side: Tree
|
# Left side: Tree
|
||||||
self.tree_ctrl = wx.TreeCtrl(self.splitter, style=wx.TR_DEFAULT_STYLE | wx.TR_HIDE_ROOT | wx.BORDER_SUNKEN)
|
self.tree_ctrl = wx.TreeCtrl(self.splitter, style=wx.TR_DEFAULT_STYLE | wx.TR_HIDE_ROOT | wx.BORDER_SUNKEN)
|
||||||
|
self.tree_ctrl.AssignImageList(self.image_list)
|
||||||
self.tree_ctrl.Bind(wx.EVT_TREE_ITEM_EXPANDING, self.on_tree_expanding)
|
self.tree_ctrl.Bind(wx.EVT_TREE_ITEM_EXPANDING, self.on_tree_expanding)
|
||||||
self.tree_ctrl.Bind(wx.EVT_TREE_SEL_CHANGED, self.on_tree_selected)
|
self.tree_ctrl.Bind(wx.EVT_TREE_SEL_CHANGED, self.on_tree_selected)
|
||||||
|
|
||||||
# Right side: File Area - ListCtrl
|
# Right side: File Area - ListCtrl
|
||||||
self.list_ctrl = wx.ListCtrl(self.splitter, style=wx.LC_REPORT | wx.BORDER_SUNKEN)
|
self.list_ctrl = wx.ListCtrl(self.splitter, style=wx.LC_REPORT | wx.BORDER_SUNKEN)
|
||||||
|
self.list_ctrl.AssignImageList(self.image_list, wx.IMAGE_LIST_SMALL)
|
||||||
self.list_ctrl.InsertColumn(0, "Navn", width=450)
|
self.list_ctrl.InsertColumn(0, "Navn", width=450)
|
||||||
self.list_ctrl.InsertColumn(1, "Type", width=150)
|
self.list_ctrl.InsertColumn(1, "Type", width=150)
|
||||||
self.list_ctrl.InsertColumn(2, "Sidst ændret", width=200)
|
self.list_ctrl.InsertColumn(2, "Sidst ændret", width=200)
|
||||||
@@ -186,6 +197,29 @@ class SharePointApp(wx.Frame):
|
|||||||
self.edit_wait_event.set()
|
self.edit_wait_event.set()
|
||||||
self.info_bar.Dismiss()
|
self.info_bar.Dismiss()
|
||||||
|
|
||||||
|
def on_close_window(self, event):
|
||||||
|
if self.is_editing:
|
||||||
|
self.show_info("Du er i gang med at redigere en fil. Luk din editor og gem ændringerne før du lukker programmet.", wx.ICON_WARNING, auto_hide=False)
|
||||||
|
return
|
||||||
|
event.Skip()
|
||||||
|
|
||||||
|
def lock_ui(self, lock=True):
|
||||||
|
def _do():
|
||||||
|
self.tree_ctrl.Enable(not lock)
|
||||||
|
self.list_ctrl.Enable(not lock)
|
||||||
|
self.back_btn.Enable(not lock if len(self.history) > 1 else False)
|
||||||
|
self.home_btn.Enable(not lock)
|
||||||
|
self.login_btn.Enable(not lock)
|
||||||
|
wx.CallAfter(_do)
|
||||||
|
|
||||||
|
def _refresh_current_view(self):
|
||||||
|
sel = self.tree_ctrl.GetSelection()
|
||||||
|
if sel.IsOk():
|
||||||
|
data = self.tree_item_data.get(sel)
|
||||||
|
if data:
|
||||||
|
# Kør i nuværende baggrundstråd hvis muligt, ellers ny
|
||||||
|
self._fetch_list_contents_bg(data)
|
||||||
|
|
||||||
def clear_main(self):
|
def clear_main(self):
|
||||||
self.list_ctrl.DeleteAllItems()
|
self.list_ctrl.DeleteAllItems()
|
||||||
self.current_items = []
|
self.current_items = []
|
||||||
@@ -280,7 +314,7 @@ class SharePointApp(wx.Frame):
|
|||||||
self.set_status(f"Fandt {len(sites)} sites.")
|
self.set_status(f"Fandt {len(sites)} sites.")
|
||||||
for site in sites:
|
for site in sites:
|
||||||
name = site.get('displayName', site.get('name'))
|
name = site.get('displayName', site.get('name'))
|
||||||
node = self.tree_ctrl.AppendItem(self.tree_root, name)
|
node = self.tree_ctrl.AppendItem(self.tree_root, name, image=self.idx_site)
|
||||||
self.tree_item_data[node] = {
|
self.tree_item_data[node] = {
|
||||||
"type": "SITE", "id": site['id'], "name": name,
|
"type": "SITE", "id": site['id'], "name": name,
|
||||||
"drive_id": None, "path": ["SharePoint", name], "loaded": False
|
"drive_id": None, "path": ["SharePoint", name], "loaded": False
|
||||||
@@ -292,7 +326,7 @@ class SharePointApp(wx.Frame):
|
|||||||
self.current_items = []
|
self.current_items = []
|
||||||
for i, site in enumerate(sites):
|
for i, site in enumerate(sites):
|
||||||
name = site.get('displayName', site.get('name'))
|
name = site.get('displayName', site.get('name'))
|
||||||
self.list_ctrl.InsertItem(i, name)
|
self.list_ctrl.InsertItem(i, name, self.idx_site)
|
||||||
self.list_ctrl.SetItem(i, 1, "Site")
|
self.list_ctrl.SetItem(i, 1, "Site")
|
||||||
self.current_items.append({"type": "SITE", "id": site['id'], "name": name})
|
self.current_items.append({"type": "SITE", "id": site['id'], "name": name})
|
||||||
|
|
||||||
@@ -338,7 +372,7 @@ class SharePointApp(wx.Frame):
|
|||||||
for drive in drives:
|
for drive in drives:
|
||||||
name = drive.get('name', 'Ukendt')
|
name = drive.get('name', 'Ukendt')
|
||||||
drive_id = drive['id']
|
drive_id = drive['id']
|
||||||
node = self.tree_ctrl.AppendItem(parent_node, name)
|
node = self.tree_ctrl.AppendItem(parent_node, name, image=self.idx_drive)
|
||||||
self.tree_item_data[node] = {
|
self.tree_item_data[node] = {
|
||||||
"type": "DRIVE", "id": drive_id, "name": name,
|
"type": "DRIVE", "id": drive_id, "name": name,
|
||||||
"drive_id": drive_id, "path": parent_data["path"] + [name], "loaded": False
|
"drive_id": drive_id, "path": parent_data["path"] + [name], "loaded": False
|
||||||
@@ -359,7 +393,7 @@ class SharePointApp(wx.Frame):
|
|||||||
for folder in folders:
|
for folder in folders:
|
||||||
name = folder['name']
|
name = folder['name']
|
||||||
folder_id = folder['id']
|
folder_id = folder['id']
|
||||||
node = self.tree_ctrl.AppendItem(parent_node, name)
|
node = self.tree_ctrl.AppendItem(parent_node, name, image=self.idx_folder)
|
||||||
self.tree_item_data[node] = {
|
self.tree_item_data[node] = {
|
||||||
"type": "FOLDER", "id": folder_id, "name": name,
|
"type": "FOLDER", "id": folder_id, "name": name,
|
||||||
"drive_id": parent_data["drive_id"], "path": parent_data["path"] + [name], "loaded": False
|
"drive_id": parent_data["drive_id"], "path": parent_data["path"] + [name], "loaded": False
|
||||||
@@ -373,6 +407,7 @@ class SharePointApp(wx.Frame):
|
|||||||
self.tree_ctrl.SelectItem(target_node)
|
self.tree_ctrl.SelectItem(target_node)
|
||||||
|
|
||||||
def on_tree_selected(self, event):
|
def on_tree_selected(self, event):
|
||||||
|
if self.is_editing: return
|
||||||
item = event.GetItem()
|
item = event.GetItem()
|
||||||
data = self.tree_item_data.get(item)
|
data = self.tree_item_data.get(item)
|
||||||
if not data:
|
if not data:
|
||||||
@@ -430,7 +465,12 @@ class SharePointApp(wx.Frame):
|
|||||||
self.list_ctrl.DeleteAllItems()
|
self.list_ctrl.DeleteAllItems()
|
||||||
self.current_items = []
|
self.current_items = []
|
||||||
for i, item in enumerate(items_data):
|
for i, item in enumerate(items_data):
|
||||||
self.list_ctrl.InsertItem(i, item['name'])
|
img_idx = self.idx_file
|
||||||
|
if item['type'] == "FOLDER": img_idx = self.idx_folder
|
||||||
|
elif item['type'] == "DRIVE": img_idx = self.idx_drive
|
||||||
|
elif item['type'] == "SITE": img_idx = self.idx_site
|
||||||
|
|
||||||
|
self.list_ctrl.InsertItem(i, item['name'], img_idx)
|
||||||
type_str = "Mappe" if item['type'] == "FOLDER" else "Fil" if item['type'] == "FILE" else "Bibliotek"
|
type_str = "Mappe" if item['type'] == "FOLDER" else "Fil" if item['type'] == "FILE" else "Bibliotek"
|
||||||
self.list_ctrl.SetItem(i, 1, type_str)
|
self.list_ctrl.SetItem(i, 1, type_str)
|
||||||
self.list_ctrl.SetItem(i, 2, item['modified'])
|
self.list_ctrl.SetItem(i, 2, item['modified'])
|
||||||
@@ -448,8 +488,9 @@ class SharePointApp(wx.Frame):
|
|||||||
self.current_folder_id = parent_data['id']
|
self.current_folder_id = parent_data['id']
|
||||||
|
|
||||||
def on_item_activated(self, event):
|
def on_item_activated(self, event):
|
||||||
idx = event.GetIndex()
|
if self.is_editing: return
|
||||||
item = self.current_items[idx]
|
item_idx = event.GetIndex()
|
||||||
|
item = self.current_items[item_idx]
|
||||||
|
|
||||||
if item['type'] in ["SITE", "DRIVE", "FOLDER"]:
|
if item['type'] in ["SITE", "DRIVE", "FOLDER"]:
|
||||||
self._sync_tree_selection(item['id'])
|
self._sync_tree_selection(item['id'])
|
||||||
@@ -475,6 +516,7 @@ class SharePointApp(wx.Frame):
|
|||||||
child, cookie = self.tree_ctrl.GetNextChild(selected, cookie)
|
child, cookie = self.tree_ctrl.GetNextChild(selected, cookie)
|
||||||
|
|
||||||
def go_back(self, event=None):
|
def go_back(self, event=None):
|
||||||
|
if self.is_editing: return
|
||||||
if len(self.history) > 1:
|
if len(self.history) > 1:
|
||||||
self.history.pop() # Remove current
|
self.history.pop() # Remove current
|
||||||
prev_item = self.history[-1] # Peak at previous
|
prev_item = self.history[-1] # Peak at previous
|
||||||
@@ -483,28 +525,33 @@ class SharePointApp(wx.Frame):
|
|||||||
self.is_navigating_back = False
|
self.is_navigating_back = False
|
||||||
|
|
||||||
def process_file(self, item_id, file_name):
|
def process_file(self, item_id, file_name):
|
||||||
base_url = f"https://graph.microsoft.com/v1.0/drives/{self.current_drive_id}/items/{item_id}"
|
self.is_editing = True
|
||||||
|
self.lock_ui(True)
|
||||||
try:
|
try:
|
||||||
# 1. Checkout
|
# 1. Lokation info
|
||||||
self.set_status(f"Tjekker '{file_name}' ud...")
|
site_id = self.current_site_id
|
||||||
checkout_res = requests.post(f"{base_url}/checkout", headers=self.headers)
|
drive_id = self.current_drive_id
|
||||||
|
base_url = f"https://graph.microsoft.com/v1.0/sites/{site_id}/drives/{drive_id}/items/{item_id}"
|
||||||
|
|
||||||
|
# Unik undermappe baseret på ID, men brug originalt filnavn indeni
|
||||||
|
item_hash = hashlib.md5(item_id.encode()).hexdigest()[:8]
|
||||||
|
working_dir = os.path.join(TEMP_DIR, item_hash)
|
||||||
|
if not os.path.exists(working_dir):
|
||||||
|
os.makedirs(working_dir)
|
||||||
|
|
||||||
|
local_path = os.path.join(working_dir, file_name)
|
||||||
|
|
||||||
# 2. Download
|
# 2. Download
|
||||||
self.set_status(f"Downloader '{file_name}'...")
|
self.set_status(f"Henter '{file_name}'...")
|
||||||
res = requests.get(f"{base_url}/content", headers=self.headers)
|
res = requests.get(f"{base_url}/content", headers=self.headers)
|
||||||
if res.status_code != 200:
|
if res.status_code != 200:
|
||||||
raise Exception(f"Download fejlede: {res.status_code}")
|
raise Exception(f"Kunne ikke hente fil: {res.status_code}")
|
||||||
|
|
||||||
short_hash = hashlib.md5(item_id.encode()).hexdigest()[:8]
|
|
||||||
file_dir = os.path.join(TEMP_DIR, short_hash)
|
|
||||||
if not os.path.exists(file_dir):
|
|
||||||
os.makedirs(file_dir)
|
|
||||||
|
|
||||||
local_path = os.path.join(file_dir, file_name)
|
|
||||||
|
|
||||||
with open(local_path, 'wb') as f:
|
with open(local_path, 'wb') as f:
|
||||||
f.write(res.content)
|
f.write(res.content)
|
||||||
|
|
||||||
|
# Checkout
|
||||||
|
requests.post(f"{base_url}/checkout", headers=self.headers)
|
||||||
|
|
||||||
# 3. Åbn & Overvåg
|
# 3. Åbn & Overvåg
|
||||||
self.set_status(f"Åbner '{file_name}'...")
|
self.set_status(f"Åbner '{file_name}'...")
|
||||||
@@ -534,8 +581,6 @@ class SharePointApp(wx.Frame):
|
|||||||
self.edit_wait_event.clear()
|
self.edit_wait_event.clear()
|
||||||
wx.CallAfter(self.done_btn.Show)
|
wx.CallAfter(self.done_btn.Show)
|
||||||
wx.CallAfter(self.Layout)
|
wx.CallAfter(self.Layout)
|
||||||
self.show_info(f"Vi kan ikke se om du har gemt '{file_name}'. Klik på den orange knap øverst når du er færdig.", wx.ICON_WARNING, auto_hide=False)
|
|
||||||
# Vent på event (fra done_btn knap)
|
|
||||||
self.edit_wait_event.wait()
|
self.edit_wait_event.wait()
|
||||||
wx.CallAfter(self.done_btn.Hide)
|
wx.CallAfter(self.done_btn.Hide)
|
||||||
wx.CallAfter(self.Layout)
|
wx.CallAfter(self.Layout)
|
||||||
@@ -551,15 +596,23 @@ class SharePointApp(wx.Frame):
|
|||||||
self.set_status(f"Tjekker '{file_name}' ind...")
|
self.set_status(f"Tjekker '{file_name}' ind...")
|
||||||
requests.post(f"{base_url}/checkin", headers=self.headers, json={"comment": "Opdateret via SP Explorer"})
|
requests.post(f"{base_url}/checkin", headers=self.headers, json={"comment": "Opdateret via SP Explorer"})
|
||||||
|
|
||||||
os.remove(local_path)
|
# Oprydning: Slet fil og derefter mappe
|
||||||
|
try:
|
||||||
|
os.remove(local_path)
|
||||||
|
os.rmdir(working_dir)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
self.set_status(f"Succes! '{file_name}' er opdateret.")
|
self.set_status(f"Succes! '{file_name}' er opdateret.")
|
||||||
self.show_info(f"Filen '{file_name}' er gemt og tjekket ind korrekt.", wx.ICON_INFORMATION)
|
self.show_info(f"Filen '{file_name}' er gemt og tjekket ind korrekt.", wx.ICON_INFORMATION)
|
||||||
|
self._refresh_current_view()
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.set_status(f"Fejl: {str(e)}")
|
self.set_status(f"Fejl: {str(e)}")
|
||||||
self.show_info(f"Der skete en fejl: {e}", wx.ICON_ERROR)
|
self.show_info(f"Der skete en fejl: {e}", wx.ICON_ERROR)
|
||||||
|
finally:
|
||||||
|
self.is_editing = False
|
||||||
|
self.lock_ui(False)
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
app = wx.App()
|
app = wx.App()
|
||||||
|
|||||||
Reference in New Issue
Block a user