feat: register local agent project workspaces

This commit is contained in:
Hamza Ayed
2026-10-04 01:57:44 +03:00
parent d29275043a
commit 1feeb372a4
12 changed files with 806 additions and 45 deletions
+41 -3
View File
@@ -64,8 +64,26 @@ def _roots_for_user(user_id: str | None) -> tuple[Path, ...]:
roots = configured_roots()
from app import auth, database
registered_roots: list[Path] = []
if user_id is not None:
for value in database.list_workspace_roots(user_id):
try:
root = Path(value).expanduser().resolve(strict=True)
except (OSError, RuntimeError):
continue
if root.is_dir() and root not in registered_roots:
registered_roots.append(root)
def combine(*groups: tuple[Path, ...] | list[Path]) -> tuple[Path, ...]:
combined: list[Path] = []
for group in groups:
for root in group:
if root not in combined:
combined.append(root)
return tuple(combined)
if user_id is None or user_id == database.LOCAL_USER_ID:
return roots
return combine(roots, registered_roots)
email = auth.account_email(user_id)
if email is None:
@@ -110,9 +128,29 @@ def _roots_for_user(user_id: str | None) -> tuple[Path, ...]:
if first_root == second_root or first_root in second_root.parents or second_root in first_root.parents:
raise ValueError("جذور مساحة العمل لحسابين مختلفين متداخلة في إعداد الخادم.")
assigned = resolved_by_email.get(email.casefold())
if not assigned:
if not assigned and not registered_roots:
raise WorkspaceAccessDenied("لم يخصص مسؤول الخادم مساحة عمل لهذا الحساب.")
return assigned
# For authenticated accounts, the global roots are validation boundaries,
# not grants. Keep account access limited to its explicit assignment plus
# folders that account registered from its local desktop.
return combine(assigned or (), registered_roots)
def validate_workspace_registration(value: str, *, must_exist: bool = True) -> Path:
"""Resolve a directory explicitly selected in the local desktop app."""
if not value.strip():
raise ValueError("اختر مجلد مشروع صالحًا.")
try:
root = Path(value).expanduser().resolve(strict=must_exist)
except (OSError, RuntimeError) as exc:
raise ValueError("مجلد المشروع غير موجود أو غير متاح.") from exc
if must_exist and not root.is_dir():
raise ValueError("يجب اختيار مجلد صالح للمشروع.")
if root == Path(root.anchor):
raise ValueError("اختر مجلد مشروع محددًا، وليس جذر القرص.")
if root.name.startswith(".") or root.name in IGNORED_PARTS:
raise ValueError("لا يمكن تسجيل مجلد مخفي أو مستثنى كمشروع.")
return root
def selected_root(value: str | None, *, user_id: str | None = None) -> Path | None: