2026-04-10 13:39:14 +02:00

186 lines
6.2 KiB
Python

import streamlit as st
from pathlib import Path
WORKSPACE = Path("workspace")
WORKSPACE.mkdir(exist_ok=True)
class FileManager:
def __init__(self, base_path=Path("workspace")) -> None:
self.base_path = Path(base_path)
self.base_path.mkdir(exist_ok=True)
def create_folder(self, relative_path: str, name: str) -> bool:
if not name:
st.error(f"Invalid folder name: {name}")
return False
if "/" in name or "\\" in name:
st.error(f"Invalid folder name (no slashes allowed): {name}")
return False
name = Path(name)
if relative_path:
relative_path = Path(relative_path)
else:
relative_path = Path()
folder_path = (self.base_path / relative_path / name).resolve()
if not str(folder_path).startswith(str(self.base_path.resolve())):
st.error(f"Access denied: {relative_path}")
return False
try:
folder_path.mkdir(exist_ok=False)
return True
except FileExistsError:
st.warning(f"Folder already exists: {relative_path}")
return False
except Exception as e:
st.error(f"Error creating folder {relative_path}: {str(e)}")
return False
def create_file(self, relative_path: str, name: str) -> bool:
if not name or name.strip() == "" :
st.error(f"Invalid file name: {name}")
return False
name = Path(name)
if not name.suffix:
name = name.with_suffix(".txt") # Default to .txt if no extension provided
if relative_path:
relative_path = Path(relative_path)
else:
relative_path = Path()
file_path = (self.base_path / relative_path / name).resolve()
if not str(file_path).startswith(str(self.base_path.resolve())):
st.error(f"Access denied: {relative_path}")
return False
try:
file_path.touch(exist_ok=False)
return True
except FileExistsError:
st.warning(f"File already exists: {relative_path}")
return False
except Exception as e:
st.error(f"Error creating file {relative_path}: {str(e)}")
return False
def read_file(self, relative_path: Path) -> str:
file_path = (relative_path).resolve()
if not file_path.exists():
st.error(f"File not found: {relative_path}")
return ""
if not file_path.is_file():
st.error(f"Path is not a file: {relative_path}")
return ""
if not str(file_path).startswith(str(self.base_path.resolve())):
st.error(f"Access denied: {relative_path}")
return ""
try:
with open(file_path, "r") as f:
return f.read()
except FileNotFoundError:
st.error(f"File not found: {relative_path}")
return ""
except Exception as e:
st.error(f"Error reading file {relative_path}: {str(e)}")
return ""
def save_file(self, relative_path: str, content: str):
file_path = (Path(relative_path)).resolve()
if not str(file_path).startswith(str(self.base_path.resolve())):
st.error(f"Access denied: {relative_path}")
return False
try:
with open(file_path, "w") as f:
f.write(content)
return True
except Exception as e:
st.error(f"Error saving file {relative_path}: {str(e)}")
return False
def rename_file(self, old_relative_path: str, new_name: str) -> bool:
if not new_name or new_name.strip() == "":
st.error(f"Invalid file name: {new_name}")
return False
file_type = Path(old_relative_path).suffix
new_name = Path(new_name)
if not Path(new_name).suffix == file_type:
new_name = Path(new_name).with_suffix(file_type) # Ensure the file extension remains the same
old_file_path = (Path(old_relative_path)).resolve()
new_file_path = old_file_path.parent / new_name
if not str(old_file_path).startswith(str(self.base_path.resolve())) or not str(new_file_path).startswith(str(self.base_path.resolve())):
st.error(f"Access denied: {old_relative_path}")
return False
try:
old_file_path.rename(new_file_path)
return True
except FileNotFoundError:
st.error(f"File not found: {old_relative_path}")
return False
def delete_folder(self, relative_path) -> bool:
folder_path = (self.base_path / relative_path).resolve()
if not str(folder_path).startswith(str(self.base_path.resolve())):
st.error(f"Access denied: {relative_path}")
return False
if not folder_path.exists():
st.error(f"Folder not found: {relative_path}")
return False
try:
import shutil
shutil.rmtree(folder_path)
return True
except Exception as e:
st.error(f"Error deleting folder {relative_path}: {str(e)}")
return False
def delete_file(self, relative_path):
file_path = Path(relative_path).resolve()
if not str(file_path).startswith(str(self.base_path.resolve())):
st.error(f"Access denied: {relative_path}")
return False
try:
file_path.unlink()
return True
except FileNotFoundError:
st.error(f"File not found: {relative_path}")
return False
except Exception as e:
st.error(f"Error deleting file {relative_path}: {str(e)}")
return False
def get_file_tree(self):
def build_tree(path: Path):
tree = {}
for item in sorted(path.iterdir()):
if item.is_dir():
tree[item.name] = build_tree(item)
else:
tree[item.name] = None
return tree
return build_tree(self.base_path)
if __name__ == "__main__":
FileManager()