Admin user editing, knight-rider demos, self-contained user seeds
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -1,12 +1,20 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import re
|
||||
import shutil
|
||||
from pathlib import Path
|
||||
|
||||
from editor_app import config
|
||||
|
||||
DEFAULT_MAIN_PY = 'print("Hello, World!")\n'
|
||||
|
||||
# Self-contained demos copied from shipped `workspace/code/` (stdlib + machine/neopixel/time only).
|
||||
_CANONICAL_DEMO_FILENAMES = (
|
||||
"pattern_rainbow_demo.py",
|
||||
"pattern_twinkle_demo.py",
|
||||
"pattern_chase_demo.py",
|
||||
)
|
||||
|
||||
|
||||
def safe_workspace_leaf(username: str, user_id: int) -> str:
|
||||
base = re.sub(r"[^a-zA-Z0-9._-]+", "-", username.strip()).strip("-").lower() or "user"
|
||||
@@ -18,10 +26,41 @@ def user_workspace_root(user_id: int, username: str, workspace_root: Path | None
|
||||
return root / "users" / safe_workspace_leaf(username, user_id)
|
||||
|
||||
|
||||
def _seed_canonical_demos_into_code(code_dir: Path) -> None:
|
||||
src_root = config.PROJECT_ROOT.resolve() / "workspace" / "code"
|
||||
for filename in _CANONICAL_DEMO_FILENAMES:
|
||||
dst = code_dir / filename
|
||||
if dst.exists():
|
||||
continue
|
||||
src = src_root / filename
|
||||
if src.is_file():
|
||||
dst.write_text(src.read_text(encoding="utf-8"), encoding="utf-8")
|
||||
|
||||
|
||||
def ensure_default_code_main(user_root: Path) -> None:
|
||||
"""Ensure code/ exists and add a starter main.py when missing."""
|
||||
"""Ensure code/ has main.py and self-contained NeoPixel demos (copied from repo workspace/code/)."""
|
||||
code_dir = user_root / "code"
|
||||
code_dir.mkdir(parents=True, exist_ok=True)
|
||||
main_py = code_dir / "main.py"
|
||||
if not main_py.exists():
|
||||
main_py.write_text(DEFAULT_MAIN_PY, encoding="utf-8")
|
||||
_seed_canonical_demos_into_code(code_dir)
|
||||
|
||||
|
||||
def rename_user_workspace_leaf(
|
||||
user_id: int, old_username: str, new_username: str, workspace_root: Path | None = None
|
||||
) -> None:
|
||||
"""Rename per-user workspace directory when login name changes."""
|
||||
root = (workspace_root or config.WORKSPACE_ROOT).resolve()
|
||||
users_dir = root / "users"
|
||||
src = users_dir / safe_workspace_leaf(old_username, user_id)
|
||||
dst = users_dir / safe_workspace_leaf(new_username, user_id)
|
||||
if src.resolve() == dst.resolve():
|
||||
return
|
||||
dst.parent.mkdir(parents=True, exist_ok=True)
|
||||
if dst.exists():
|
||||
raise ValueError("Workspace folder for new username already exists; pick another username.")
|
||||
if src.exists():
|
||||
shutil.move(str(src), str(dst))
|
||||
else:
|
||||
ensure_default_code_main(dst)
|
||||
|
||||
Reference in New Issue
Block a user