147 lines
5.2 KiB
Python
147 lines
5.2 KiB
Python
from pathlib import Path
|
|
from log import Logger
|
|
import re
|
|
|
|
PLUGINS_DIR = Path(__file__).parent / "plugins"
|
|
HTML_DIR = Path(__file__).parent / "../html"
|
|
MARKDOWN_DIR = Path(__file__).parent / ".." / "markdown"
|
|
|
|
class Actions:
|
|
def _safe_read_file(self, path):
|
|
"""Safe file reading with path validation"""
|
|
try:
|
|
p = Path(path)
|
|
# Prevent directory traversal
|
|
if ".." in str(p.parts):
|
|
raise ValueError("Path traversal not allowed")
|
|
return p.read_text(encoding="utf-8")
|
|
except Exception as e:
|
|
Logger.log_lua_error(f"Error reading file {path}: {e}")
|
|
return None
|
|
@staticmethod
|
|
def _safe_write_file(self, path, content):
|
|
"""Safe file writing with path validation"""
|
|
try:
|
|
p = Path(path)
|
|
# Prevent directory traversal
|
|
if ".." in str(p.parts):
|
|
raise ValueError("Path traversal not allowed")
|
|
p.write_text(content, encoding="utf-8")
|
|
return True
|
|
except Exception as e:
|
|
Logger.log_lua_error(f"Error writing file {path}: {e}")
|
|
return False
|
|
|
|
# HTML/Markdown content operations
|
|
@staticmethod
|
|
def _read_content(self, base_dir, filename):
|
|
"""Read content from HTML or Markdown directory"""
|
|
try:
|
|
path = base_dir / filename
|
|
if not path.is_relative_to(base_dir):
|
|
raise ValueError("Invalid path")
|
|
if path.exists():
|
|
return path.read_text(encoding="utf-8")
|
|
return None
|
|
except Exception as e:
|
|
Logger.log_lua_error(f"Error reading {filename}: {e}")
|
|
return None
|
|
|
|
|
|
@staticmethod
|
|
def _write_content(self, base_dir, filename, content):
|
|
"""Write content to HTML or Markdown directory"""
|
|
try:
|
|
path = base_dir / filename
|
|
if not path.is_relative_to(base_dir):
|
|
raise ValueError("Invalid path")
|
|
path.write_text(content, encoding="utf-8")
|
|
return True
|
|
except Exception as e:
|
|
Logger.log_lua_error(f"Error writing {filename}: {e}")
|
|
return False
|
|
|
|
@staticmethod
|
|
def _list_files(self, base_dir, extension):
|
|
"""List files with given extension"""
|
|
try:
|
|
return [f.name for f in base_dir.glob(f"*{extension}")]
|
|
except Exception as e:
|
|
Logger.log_lua_error(f"Error listing files: {e}")
|
|
return []
|
|
|
|
# HTML manipulation helpers
|
|
@staticmethod
|
|
def _html_find_tag(self, html, tag):
|
|
"""Find first occurrence of HTML tag"""
|
|
pattern = f"<{tag}[^>]*>.*?</{tag}>"
|
|
match = re.search(pattern, html, re.DOTALL | re.IGNORECASE)
|
|
return match.group(0) if match else None
|
|
|
|
@staticmethod
|
|
def _html_replace_tag(self, html, tag, new_content):
|
|
"""Replace HTML tag content"""
|
|
pattern = f"(<{tag}[^>]*>).*?(</{tag}>)"
|
|
return re.sub(pattern, f"\\1{new_content}\\2", html, flags=re.DOTALL | re.IGNORECASE)
|
|
|
|
@staticmethod
|
|
def _html_insert_before(self, html, marker, content):
|
|
"""Insert content before a marker"""
|
|
return html.replace(marker, content + marker)
|
|
|
|
@staticmethod
|
|
def _html_insert_after(self, html, marker, content):
|
|
"""Insert content after a marker"""
|
|
return html.replace(marker, marker + content)
|
|
|
|
@staticmethod
|
|
def _html_wrap_content(self, html, tag, wrapper_tag, attrs=""):
|
|
"""Wrap tag content with another tag"""
|
|
pattern = f"(<{tag}[^>]*>)(.*?)(</{tag}>)"
|
|
def replacer(match):
|
|
open_tag, content, close_tag = match.groups()
|
|
return f"{open_tag}<{wrapper_tag} {attrs}>{content}</{wrapper_tag}>{close_tag}"
|
|
return re.sub(pattern, replacer, html, flags=re.DOTALL | re.IGNORECASE)
|
|
|
|
# Markdown manipulation helpers
|
|
@staticmethod
|
|
def _md_add_header(self, markdown, level, text):
|
|
"""Add header to markdown"""
|
|
prefix = "#" * level
|
|
return f"{prefix} {text}\n\n{markdown}"
|
|
|
|
@staticmethod
|
|
def _md_replace_section(self, markdown, header, new_content):
|
|
"""Replace markdown section"""
|
|
# Find section starting with header
|
|
pattern = f"(#{1,6}\\s+{re.escape(header)}.*?)(?=#{1,6}\\s+|$)"
|
|
return re.sub(pattern, f"## {header}\n\n{new_content}\n\n", markdown, flags=re.DOTALL)
|
|
|
|
@staticmethod
|
|
def _md_append_content(self, markdown, content):
|
|
"""Append content to markdown"""
|
|
return markdown.rstrip() + "\n\n" + content
|
|
|
|
# JSON conversion helpers
|
|
@staticmethod
|
|
def _table_to_json(self, lua_table):
|
|
"""Convert Lua table to JSON string"""
|
|
import json
|
|
try:
|
|
# Convert lupa table to Python dict
|
|
py_dict = dict(lua_table)
|
|
return json.dumps(py_dict)
|
|
except Exception as e:
|
|
Logger.log_lua_error(f"Error converting table to JSON: {e}")
|
|
return "{}"
|
|
|
|
@staticmethod
|
|
def _json_to_table(self, json_str):
|
|
"""Convert JSON string to Lua table"""
|
|
import json
|
|
try:
|
|
return json.loads(json_str)
|
|
except Exception as e:
|
|
Logger.log_lua_error(f"Error parsing JSON: {e}")
|
|
return {}
|