feat: implement full arch design dashboard #1
|
|
@ -0,0 +1,42 @@
|
||||||
|
import uuid
|
||||||
|
from datetime import datetime, timezone
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
from app.modules.project.domain.entities import Project
|
||||||
|
from app.modules.project.domain.repositories import ProjectRepository
|
||||||
|
from app.shared.kernel.exceptions import NotFoundError, ValidationError
|
||||||
|
|
||||||
|
|
||||||
|
class ProjectService:
|
||||||
|
def __init__(self, repository: ProjectRepository) -> None:
|
||||||
|
self._repo = repository
|
||||||
|
|
||||||
|
def list_projects(self) -> list[Project]:
|
||||||
|
return self._repo.list_all()
|
||||||
|
|
||||||
|
def create_project(
|
||||||
|
self, name: str, design_dir: str, code_dir: str | None = None,
|
||||||
|
) -> Project:
|
||||||
|
if not Path(design_dir).is_dir():
|
||||||
|
raise ValidationError(f"Design directory does not exist: {design_dir}")
|
||||||
|
project = Project(
|
||||||
|
id=str(uuid.uuid4()),
|
||||||
|
name=name,
|
||||||
|
design_dir=design_dir,
|
||||||
|
code_dir=code_dir,
|
||||||
|
created_at=datetime.now(timezone.utc),
|
||||||
|
)
|
||||||
|
self._repo.save(project)
|
||||||
|
return project
|
||||||
|
|
||||||
|
def get_project(self, project_id: str) -> Project:
|
||||||
|
project = self._repo.get_by_id(project_id)
|
||||||
|
if project is None:
|
||||||
|
raise NotFoundError("Project", project_id)
|
||||||
|
return project
|
||||||
|
|
||||||
|
def delete_project(self, project_id: str) -> None:
|
||||||
|
project = self._repo.get_by_id(project_id)
|
||||||
|
if project is None:
|
||||||
|
raise NotFoundError("Project", project_id)
|
||||||
|
self._repo.delete(project_id)
|
||||||
|
|
@ -42,3 +42,42 @@ def test_delete(repo: JsonProjectRepository):
|
||||||
|
|
||||||
def test_get_nonexistent_returns_none(repo: JsonProjectRepository):
|
def test_get_nonexistent_returns_none(repo: JsonProjectRepository):
|
||||||
assert repo.get_by_id("nope") is None
|
assert repo.get_by_id("nope") is None
|
||||||
|
|
||||||
|
|
||||||
|
# --- Service tests ---
|
||||||
|
|
||||||
|
from app.modules.project.application.services import ProjectService
|
||||||
|
from app.shared.kernel.exceptions import NotFoundError, ValidationError
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def service(tmp_path: Path) -> ProjectService:
|
||||||
|
repo = JsonProjectRepository(tmp_path / "projects.json")
|
||||||
|
return ProjectService(repo)
|
||||||
|
|
||||||
|
|
||||||
|
def test_create_project_validates_design_dir(service: ProjectService, tmp_path: Path):
|
||||||
|
design_dir = tmp_path / "design"
|
||||||
|
design_dir.mkdir()
|
||||||
|
project = service.create_project("test", str(design_dir))
|
||||||
|
assert project.name == "test"
|
||||||
|
assert project.id # UUID generated
|
||||||
|
|
||||||
|
|
||||||
|
def test_create_project_rejects_missing_dir(service: ProjectService):
|
||||||
|
with pytest.raises(ValidationError):
|
||||||
|
service.create_project("test", "/nonexistent/path")
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_project_not_found(service: ProjectService):
|
||||||
|
with pytest.raises(NotFoundError):
|
||||||
|
service.get_project("nonexistent")
|
||||||
|
|
||||||
|
|
||||||
|
def test_delete_project(service: ProjectService, tmp_path: Path):
|
||||||
|
design_dir = tmp_path / "design"
|
||||||
|
design_dir.mkdir()
|
||||||
|
p = service.create_project("test", str(design_dir))
|
||||||
|
service.delete_project(p.id)
|
||||||
|
with pytest.raises(NotFoundError):
|
||||||
|
service.get_project(p.id)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user