Add storage layer with FileStorage, MarkdownReader, and MarkdownWriter classes. Add data models (Project, Session, Note, Change).
119 lines
3.0 KiB
Python
119 lines
3.0 KiB
Python
"""Project service for project management."""
|
|
|
|
import uuid
|
|
from datetime import datetime
|
|
from pathlib import Path
|
|
from typing import Optional
|
|
|
|
from ..models import Project
|
|
|
|
|
|
_PROJECTS_ROOT = Path("projects")
|
|
|
|
|
|
def get_projects_root() -> Path:
|
|
"""Return the root directory for all projects."""
|
|
return _PROJECTS_ROOT
|
|
|
|
|
|
def _get_project_meta_path(slug: str) -> Path:
|
|
"""Return the path to the project's meta/project.yaml file."""
|
|
return _PROJECTS_ROOT / slug / "meta" / "project.yaml"
|
|
|
|
|
|
def _get_project_readme_path(slug: str) -> Path:
|
|
"""Return the path to the project's README.md file."""
|
|
return _PROJECTS_ROOT / slug / "README.md"
|
|
|
|
|
|
def create_project(
|
|
name: str,
|
|
slug: str,
|
|
description: str = "",
|
|
type: str = "misc",
|
|
tags: Optional[list[str]] = None,
|
|
repo_path: Optional[Path] = None,
|
|
) -> Project:
|
|
"""
|
|
Create a new project and return the Project instance.
|
|
Note: This does not write any files - that is handled by storage.
|
|
"""
|
|
if tags is None:
|
|
tags = []
|
|
|
|
project = Project(
|
|
id=str(uuid.uuid4()),
|
|
name=name,
|
|
slug=slug,
|
|
description=description,
|
|
type=type,
|
|
status="inbox",
|
|
tags=tags,
|
|
root_path=_PROJECTS_ROOT / slug,
|
|
repo_path=repo_path,
|
|
created_at=datetime.now(),
|
|
updated_at=datetime.now(),
|
|
)
|
|
return project
|
|
|
|
|
|
def get_project(slug: str) -> Optional[Project]:
|
|
"""
|
|
Get a project by slug.
|
|
Note: This reads from file system - placeholder for storage integration.
|
|
"""
|
|
meta_path = _get_project_meta_path(slug)
|
|
if not meta_path.exists():
|
|
return None
|
|
# TODO: Load from storage (YAML)
|
|
return None
|
|
|
|
|
|
def update_project(slug: str, **kwargs) -> Optional[Project]:
|
|
"""
|
|
Update a project's attributes.
|
|
Note: This does not persist - that is handled by storage.
|
|
"""
|
|
project = get_project(slug)
|
|
if project is None:
|
|
return None
|
|
|
|
for key, value in kwargs.items():
|
|
if hasattr(project, key):
|
|
setattr(project, key, value)
|
|
|
|
project.updated_at = datetime.now()
|
|
return project
|
|
|
|
|
|
def list_projects() -> list[Project]:
|
|
"""
|
|
List all projects.
|
|
Note: This reads from file system - placeholder for storage integration.
|
|
"""
|
|
projects_root = get_projects_root()
|
|
if not projects_root.exists():
|
|
return []
|
|
|
|
projects = []
|
|
for item in projects_root.iterdir():
|
|
if item.is_dir() and not item.name.startswith("."):
|
|
project = get_project(item.name)
|
|
if project is not None:
|
|
projects.append(project)
|
|
|
|
return projects
|
|
|
|
|
|
def ensure_project_structure(slug: str) -> None:
|
|
"""
|
|
Ensure the project directory structure exists.
|
|
Creates: sessions/, docs/, assets/, meta/
|
|
Note: This creates directories only - actual file writing is storage's job.
|
|
"""
|
|
project_root = _PROJECTS_ROOT / slug
|
|
directories = ["sessions", "docs", "assets", "meta"]
|
|
|
|
for directory in directories:
|
|
(project_root / directory).mkdir(parents=True, exist_ok=True)
|