diff --git a/config.example.json b/config.example.json index 18f77a1..c97367e 100644 --- a/config.example.json +++ b/config.example.json @@ -18,5 +18,6 @@ "log_file": null, "window_width": 1024, "window_height": 768, - "enable_logging": true + "enable_logging": true, + "enable_checkout": false } diff --git a/src/webdrop_bridge/config.py b/src/webdrop_bridge/config.py index d744945..d0ff52e 100644 --- a/src/webdrop_bridge/config.py +++ b/src/webdrop_bridge/config.py @@ -58,6 +58,8 @@ class Config: window_height: Initial window height in pixels window_title: Main window title (default: "{app_name} v{app_version}") enable_logging: Whether to write logs to file + enable_checkout: Whether to check asset checkout status and show checkout dialog + on drag. Disabled by default as checkout support is optional. Raises: ConfigurationError: If configuration values are invalid @@ -78,6 +80,7 @@ class Config: window_height: int = 768 window_title: str = "" enable_logging: bool = True + enable_checkout: bool = False @classmethod def from_file(cls, config_path: Path) -> "Config": @@ -106,10 +109,7 @@ class Config: # Parse URL mappings mappings = [ - URLMapping( - url_prefix=m["url_prefix"], - local_path=m["local_path"] - ) + URLMapping(url_prefix=m["url_prefix"], local_path=m["local_path"]) for m in data.get("url_mappings", []) ] @@ -138,11 +138,12 @@ class Config: app_name = data.get("app_name", "WebDrop Bridge") stored_window_title = data.get("window_title", "") - + # Regenerate default window titles on version upgrade # If the stored title matches the pattern "{app_name} v{version}", regenerate it # with the current version. This ensures the title updates automatically on upgrades. import re + version_pattern = re.compile(rf"^{re.escape(app_name)}\s+v[\d.]+$") if stored_window_title and version_pattern.match(stored_window_title): # Detected a default-pattern title with old version, regenerate @@ -170,6 +171,7 @@ class Config: window_height=data.get("window_height", 768), window_title=window_title, enable_logging=data.get("enable_logging", True), + enable_checkout=data.get("enable_checkout", False), ) @classmethod @@ -195,8 +197,9 @@ class Config: app_name = os.getenv("APP_NAME", "WebDrop Bridge") # Version always comes from __init__.py for consistency from webdrop_bridge import __version__ + app_version = __version__ - + log_level = os.getenv("LOG_LEVEL", "INFO").upper() log_file_str = os.getenv("LOG_FILE", None) allowed_roots_str = os.getenv("ALLOWED_ROOTS", "Z:/,C:/Users/Public") @@ -208,13 +211,13 @@ class Config: default_title = f"{app_name} v{app_version}" window_title = os.getenv("WINDOW_TITLE", default_title) enable_logging = os.getenv("ENABLE_LOGGING", "true").lower() == "true" + enable_checkout = os.getenv("ENABLE_CHECKOUT", "false").lower() == "true" # Validate log level valid_levels = {"DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"} if log_level not in valid_levels: raise ConfigurationError( - f"Invalid LOG_LEVEL: {log_level}. " - f"Must be one of: {', '.join(valid_levels)}" + f"Invalid LOG_LEVEL: {log_level}. " f"Must be one of: {', '.join(valid_levels)}" ) # Validate and parse allowed roots @@ -225,9 +228,7 @@ class Config: if not root_path.exists(): logger.warning(f"Allowed root does not exist: {p.strip()}") elif not root_path.is_dir(): - raise ConfigurationError( - f"Allowed root '{p.strip()}' is not a directory" - ) + raise ConfigurationError(f"Allowed root '{p.strip()}' is not a directory") else: allowed_roots.append(root_path) except ConfigurationError: @@ -240,8 +241,7 @@ class Config: # Validate window dimensions if window_width <= 0 or window_height <= 0: raise ConfigurationError( - f"Window dimensions must be positive: " - f"{window_width}x{window_height}" + f"Window dimensions must be positive: " f"{window_width}x{window_height}" ) # Create log file path if logging enabled @@ -261,10 +261,11 @@ class Config: raise ConfigurationError("WEBAPP_URL cannot be empty") # Parse allowed URLs (empty string = no restriction) - allowed_urls = [ - url.strip() for url in allowed_urls_str.split(",") - if url.strip() - ] if allowed_urls_str else [] + allowed_urls = ( + [url.strip() for url in allowed_urls_str.split(",") if url.strip()] + if allowed_urls_str + else [] + ) # Parse URL mappings (Azure Blob Storage → Local Paths) # Format: url_prefix1=local_path1;url_prefix2=local_path2 @@ -282,10 +283,7 @@ class Config: ) url_prefix, local_path_str = mapping.split("=", 1) url_mappings.append( - URLMapping( - url_prefix=url_prefix.strip(), - local_path=local_path_str.strip() - ) + URLMapping(url_prefix=url_prefix.strip(), local_path=local_path_str.strip()) ) except (ValueError, OSError) as e: raise ConfigurationError( @@ -305,6 +303,7 @@ class Config: window_height=window_height, window_title=window_title, enable_logging=enable_logging, + enable_checkout=enable_checkout, ) def to_file(self, config_path: Path) -> None: @@ -312,18 +311,14 @@ class Config: Args: config_path: Path to save configuration to - + Creates parent directories if they don't exist. """ data = { "app_name": self.app_name, "webapp_url": self.webapp_url, "url_mappings": [ - { - "url_prefix": m.url_prefix, - "local_path": m.local_path - } - for m in self.url_mappings + {"url_prefix": m.url_prefix, "local_path": m.local_path} for m in self.url_mappings ], "allowed_roots": [str(p) for p in self.allowed_roots], "allowed_urls": self.allowed_urls, @@ -336,6 +331,7 @@ class Config: "window_height": self.window_height, "window_title": self.window_title, "enable_logging": self.enable_logging, + "enable_checkout": self.enable_checkout, } config_path.parent.mkdir(parents=True, exist_ok=True) @@ -350,6 +346,7 @@ class Config: Path to default config file in user's AppData/Roaming """ import platform + if platform.system() == "Windows": base = Path.home() / "AppData" / "Roaming" else: @@ -359,7 +356,7 @@ class Config: @staticmethod def get_default_log_dir() -> Path: """Get the default directory for log files. - + Always uses user's AppData directory to ensure permissions work correctly in both development and installed scenarios. @@ -367,6 +364,7 @@ class Config: Path to default logs directory in user's AppData/Roaming """ import platform + if platform.system() == "Windows": base = Path.home() / "AppData" / "Roaming" else: diff --git a/src/webdrop_bridge/ui/main_window.py b/src/webdrop_bridge/ui/main_window.py index ad6d12e..1d84308 100644 --- a/src/webdrop_bridge/ui/main_window.py +++ b/src/webdrop_bridge/ui/main_window.py @@ -638,8 +638,8 @@ class MainWindow(QMainWindow): """ logger.info(f"Drag started: {source} -> {local_path}") - # Ask user if they want to check out the asset - if source.startswith("http"): + # Ask user if they want to check out the asset (only when enabled in config) + if source.startswith("http") and self.config.enable_checkout: self._prompt_checkout(source, local_path) def _prompt_checkout(self, azure_url: str, local_path: str) -> None: