diff --git a/sharepoint_browser.py b/sharepoint_browser.py index 3ea4c59..193ffc2 100644 --- a/sharepoint_browser.py +++ b/sharepoint_browser.py @@ -8,6 +8,7 @@ import requests import msal import wx import wx.lib.newevent +import webbrowser # --- STIHÅNDTERING (Til EXE-brug) --- if getattr(sys, 'frozen', False): @@ -85,6 +86,7 @@ STRINGS = { "msg_rename": "Omdøb", "msg_rename_prompt": "Indtast det nye navn for '{name}':", "msg_rename_title": "Omdøb emne", + "msg_open_browser": "Åbn i browser", "msg_upload_here": "Upload fil her", "msg_upload_folder_here": "Upload mappe her", "msg_new_folder_here": "Opret ny mappe her", @@ -113,7 +115,8 @@ STRINGS = { "msg_update_success": "Succes! '{name}' er opdateret.", "msg_update_failed_code": "Upload fejlede: {code}", "msg_unknown_error": "Ukendt fejl", - "type_unknown": "Ukendt" + "type_unknown": "Ukendt", + "status_login_needed": "Session udløbet. Log ind igen." }, "en": { "title": "SharePoint Explorer", @@ -149,6 +152,7 @@ STRINGS = { "msg_rename": "Rename", "msg_rename_prompt": "Enter new name for '{name}':", "msg_rename_title": "Rename item", + "msg_open_browser": "Open in browser", "msg_upload_here": "Upload file here", "msg_upload_folder_here": "Upload folder here", "msg_new_folder_here": "Create new folder here", @@ -177,7 +181,8 @@ STRINGS = { "msg_update_success": "Success! '{name}' has been updated.", "msg_update_failed_code": "Upload failed: {code}", "msg_unknown_error": "Unknown error", - "type_unknown": "Unknown" + "type_unknown": "Unknown", + "status_login_needed": "Session expired. Please login again." } } @@ -257,6 +262,9 @@ class SharePointApp(wx.Frame): # Threading/Sync til filredigering self.edit_wait_event = threading.Event() + # MSAL Cache + self.msal_app = msal.PublicClientApplication(CLIENT_ID, authority=AUTHORITY) + self.InitUI() self.Centre() self.Show() @@ -400,6 +408,12 @@ class SharePointApp(wx.Frame): if len(selected_indices) == 1: item = selected_items[0] + + if item.get("web_url"): + browser_item = menu.Append(wx.ID_ANY, self.get_txt("msg_open_browser")) + self.Bind(wx.EVT_MENU, lambda e: webbrowser.open(item["web_url"]), browser_item) + menu.AppendSeparator() + if item['type'] == "FILE": edit_item = menu.Append(wx.ID_ANY, self.get_txt("msg_edit_file")) self.Bind(wx.EVT_MENU, lambda e: threading.Thread(target=self.process_file, args=(item['id'], item['name']), daemon=True).start(), edit_item) @@ -707,42 +721,44 @@ class SharePointApp(wx.Frame): def ensure_valid_token(self): """Sikrer at vi har et gyldigt token. Returnerer True hvis OK.""" try: - app = msal.PublicClientApplication(CLIENT_ID, authority=AUTHORITY) - accounts = app.get_accounts() + accounts = self.msal_app.get_accounts() if not accounts: + self.set_status(self.get_txt("status_login_needed")) return False - result = app.acquire_token_silent(SCOPES, account=accounts[0]) + result = self.msal_app.acquire_token_silent(SCOPES, account=accounts[0]) if result and "access_token" in result: self.access_token = result["access_token"] self.headers = {'Authorization': f'Bearer {self.access_token}'} return True - except: - pass + except Exception as e: + print(f"Token refresh error: {e}") + + self.set_status(self.get_txt("status_login_needed")) return False def login(self, event): self.set_status(self.get_txt("status_logging_in")) - app = msal.PublicClientApplication(CLIENT_ID, authority=AUTHORITY) - accounts = app.get_accounts() + accounts = self.msal_app.get_accounts() result = None if accounts: - result = app.acquire_token_silent(SCOPES, account=accounts[0]) + result = self.msal_app.acquire_token_silent(SCOPES, account=accounts[0]) if not result or "access_token" not in result: - result = app.acquire_token_interactive(scopes=SCOPES) + result = self.msal_app.acquire_token_interactive(scopes=SCOPES) if "access_token" in result: self.access_token = result["access_token"] self.headers = {'Authorization': f'Bearer {self.access_token}'} self.login_btn.Disable() + # self.login_btn.Hide() # Valgfrit: Skjul login knap helt når vi er inde self.login_btn.SetLabel(self.get_txt("btn_logged_in")) self.login_btn.SetBackgroundColour(wx.Colour(200, 200, 200)) # Grå self.home_btn.Enable() self.load_sites() else: self.set_status(self.get_txt("status_login_failed")) - wx.MessageBox(result.get("error_description", self.get_txt("msg_unknown_error")), self.get_txt("msg_error"), wx.OK | wx.ICON_ERROR) + wx.CallAfter(wx.MessageBox, result.get("error_description", self.get_txt("msg_unknown_error")), self.get_txt("msg_error"), wx.OK | wx.ICON_ERROR) def load_sites(self, event=None): self.set_status(self.get_txt("status_fetching_sites")) @@ -790,7 +806,10 @@ class SharePointApp(wx.Frame): self.list_ctrl.SetItem(i, 1, self.get_txt("type_site")) self.list_ctrl.SetItem(i, 2, "") # Størrelse self.list_ctrl.SetItem(i, 3, "") # Sidst ændret - self.current_items.append({"type": "SITE", "id": site['id'], "name": name, "size": None, "modified": ""}) + self.current_items.append({ + "type": "SITE", "id": site['id'], "name": name, + "size": None, "modified": "", "web_url": site.get('webUrl') + }) def on_tree_expanding(self, event): item = event.GetItem() @@ -907,7 +926,8 @@ class SharePointApp(wx.Frame): for drive in drives: items_data.append({ "type": "DRIVE", "id": drive['id'], "name": drive.get('name', ''), - "drive_id": drive['id'], "modified": "", "size": None + "drive_id": drive['id'], "modified": "", "size": None, + "web_url": drive.get('webUrl') }) elif data['type'] in ["DRIVE", "FOLDER"]: drive_id = data['drive_id'] @@ -927,7 +947,8 @@ class SharePointApp(wx.Frame): "type": "FOLDER" if is_folder else "FILE", "id": item['id'], "name": item['name'], "drive_id": drive_id, "modified": modified, - "size": item.get('size') if not is_folder else None + "size": item.get('size') if not is_folder else None, + "web_url": item.get('webUrl') }) wx.CallAfter(self._populate_list_ctrl, items_data, data)