Add input validation for project and request names
This commit is contained in:
parent
0710cd34b7
commit
92d507ad4d
@ -758,6 +758,62 @@ class RosterWindow(Adw.ApplicationWindow):
|
|||||||
|
|
||||||
# Project Management Methods
|
# Project Management Methods
|
||||||
|
|
||||||
|
def _validate_project_name(self, name: str) -> tuple[bool, str]:
|
||||||
|
"""
|
||||||
|
Validate project name.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
name: The project name to validate
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Tuple of (is_valid, error_message)
|
||||||
|
"""
|
||||||
|
# Check if empty
|
||||||
|
if not name or not name.strip():
|
||||||
|
return False, "Project name cannot be empty"
|
||||||
|
|
||||||
|
# Check length (max 100 characters)
|
||||||
|
if len(name) > 100:
|
||||||
|
return False, "Project name is too long (max 100 characters)"
|
||||||
|
|
||||||
|
# Check for invalid characters (file system unsafe characters)
|
||||||
|
invalid_chars = ['/', '\\', ':', '*', '?', '"', '<', '>', '|', '\0']
|
||||||
|
for char in invalid_chars:
|
||||||
|
if char in name:
|
||||||
|
return False, f"Project name cannot contain '{char}'"
|
||||||
|
|
||||||
|
# Check if it's only whitespace
|
||||||
|
if name.strip() == '':
|
||||||
|
return False, "Project name cannot be only whitespace"
|
||||||
|
|
||||||
|
return True, ""
|
||||||
|
|
||||||
|
def _validate_request_name(self, name: str) -> tuple[bool, str]:
|
||||||
|
"""
|
||||||
|
Validate request name.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
name: The request name to validate
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Tuple of (is_valid, error_message)
|
||||||
|
"""
|
||||||
|
# Check if empty
|
||||||
|
if not name or not name.strip():
|
||||||
|
return False, "Request name cannot be empty"
|
||||||
|
|
||||||
|
# Check length (max 200 characters)
|
||||||
|
if len(name) > 200:
|
||||||
|
return False, "Request name is too long (max 200 characters)"
|
||||||
|
|
||||||
|
# Check for invalid characters (file system unsafe characters)
|
||||||
|
invalid_chars = ['/', '\\', ':', '*', '?', '"', '<', '>', '|', '\0']
|
||||||
|
for char in invalid_chars:
|
||||||
|
if char in name:
|
||||||
|
return False, f"Request name cannot contain '{char}'"
|
||||||
|
|
||||||
|
return True, ""
|
||||||
|
|
||||||
def _load_projects(self) -> None:
|
def _load_projects(self) -> None:
|
||||||
"""Load and display projects."""
|
"""Load and display projects."""
|
||||||
# Clear existing
|
# Clear existing
|
||||||
@ -796,9 +852,13 @@ class RosterWindow(Adw.ApplicationWindow):
|
|||||||
def on_response(dlg, response):
|
def on_response(dlg, response):
|
||||||
if response == "create":
|
if response == "create":
|
||||||
name = entry.get_text().strip()
|
name = entry.get_text().strip()
|
||||||
if name:
|
is_valid, error_msg = self._validate_project_name(name)
|
||||||
|
if is_valid:
|
||||||
self.project_manager.add_project(name)
|
self.project_manager.add_project(name)
|
||||||
self._load_projects()
|
self._load_projects()
|
||||||
|
self._show_toast(f"Project '{name}' created")
|
||||||
|
else:
|
||||||
|
self._show_toast(error_msg)
|
||||||
|
|
||||||
dialog.connect("response", on_response)
|
dialog.connect("response", on_response)
|
||||||
dialog.present(self)
|
dialog.present(self)
|
||||||
@ -848,9 +908,13 @@ class RosterWindow(Adw.ApplicationWindow):
|
|||||||
if response == "save":
|
if response == "save":
|
||||||
new_name = entry.get_text().strip()
|
new_name = entry.get_text().strip()
|
||||||
new_icon = icon_button.selected_icon
|
new_icon = icon_button.selected_icon
|
||||||
if new_name:
|
is_valid, error_msg = self._validate_project_name(new_name)
|
||||||
|
if is_valid:
|
||||||
self.project_manager.update_project(project.id, new_name, new_icon)
|
self.project_manager.update_project(project.id, new_name, new_icon)
|
||||||
self._load_projects()
|
self._load_projects()
|
||||||
|
self._show_toast(f"Project updated")
|
||||||
|
else:
|
||||||
|
self._show_toast(error_msg)
|
||||||
|
|
||||||
dialog.connect("response", on_response)
|
dialog.connect("response", on_response)
|
||||||
dialog.present(self)
|
dialog.present(self)
|
||||||
@ -982,7 +1046,8 @@ class RosterWindow(Adw.ApplicationWindow):
|
|||||||
def on_response(dlg, response):
|
def on_response(dlg, response):
|
||||||
if response == "save":
|
if response == "save":
|
||||||
name = entry.get_text().strip()
|
name = entry.get_text().strip()
|
||||||
if name:
|
is_valid, error_msg = self._validate_request_name(name)
|
||||||
|
if is_valid:
|
||||||
selected = dropdown.get_selected()
|
selected = dropdown.get_selected()
|
||||||
project = projects[selected]
|
project = projects[selected]
|
||||||
# Check for duplicate name
|
# Check for duplicate name
|
||||||
@ -998,6 +1063,8 @@ class RosterWindow(Adw.ApplicationWindow):
|
|||||||
|
|
||||||
# Clear modified flag on current tab
|
# Clear modified flag on current tab
|
||||||
self._mark_tab_as_saved(saved_request.id, name, request, scripts)
|
self._mark_tab_as_saved(saved_request.id, name, request, scripts)
|
||||||
|
else:
|
||||||
|
self._show_toast(error_msg)
|
||||||
|
|
||||||
dialog.connect("response", on_response)
|
dialog.connect("response", on_response)
|
||||||
dialog.present(self)
|
dialog.present(self)
|
||||||
@ -1094,7 +1161,8 @@ class RosterWindow(Adw.ApplicationWindow):
|
|||||||
def on_response(dlg, response):
|
def on_response(dlg, response):
|
||||||
if response == "save":
|
if response == "save":
|
||||||
name = entry.get_text().strip()
|
name = entry.get_text().strip()
|
||||||
if name:
|
is_valid, error_msg = self._validate_request_name(name)
|
||||||
|
if is_valid:
|
||||||
# Check for duplicate name
|
# Check for duplicate name
|
||||||
existing = self.project_manager.find_request_by_name(project.id, name)
|
existing = self.project_manager.find_request_by_name(project.id, name)
|
||||||
if existing:
|
if existing:
|
||||||
@ -1108,6 +1176,8 @@ class RosterWindow(Adw.ApplicationWindow):
|
|||||||
|
|
||||||
# Clear modified flag on current tab
|
# Clear modified flag on current tab
|
||||||
self._mark_tab_as_saved(saved_request.id, name, request)
|
self._mark_tab_as_saved(saved_request.id, name, request)
|
||||||
|
else:
|
||||||
|
self._show_toast(error_msg)
|
||||||
|
|
||||||
dialog.connect("response", on_response)
|
dialog.connect("response", on_response)
|
||||||
dialog.present(self)
|
dialog.present(self)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user