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