Add enable_checkout configuration option and update drag handling logic

This commit is contained in:
claudi 2026-02-25 13:34:37 +01:00
parent 986793632e
commit cbd1f3f77c
3 changed files with 30 additions and 31 deletions

View file

@ -18,5 +18,6 @@
"log_file": null,
"window_width": 1024,
"window_height": 768,
"enable_logging": true
"enable_logging": true,
"enable_checkout": false
}

View file

@ -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:

View file

@ -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: