from __future__ import annotations import sqlite3 from backend.app.api.errors import AppError from backend.app.api.schemas import BookmarkDeleteResponse, BookmarkItem, BookmarkListResponse from backend.app.db.bookmark_repository import BookmarkRepository from backend.app.security.path_guard import PathGuard class BookmarkService: def __init__(self, path_guard: PathGuard, repository: BookmarkRepository): self._path_guard = path_guard self._repository = repository def create_bookmark(self, path: str, label: str) -> BookmarkItem: normalized_label = (label or "").strip() if not normalized_label: raise AppError( code="invalid_request", message="Label is required", status_code=400, details={"label": label}, ) resolved = self._path_guard.resolve_path(path) try: bookmark = self._repository.create_bookmark(path=resolved.relative, label=normalized_label) except sqlite3.IntegrityError: raise AppError( code="already_exists", message="Bookmark already exists for path", status_code=409, details={"path": resolved.relative}, ) return BookmarkItem(**bookmark) def list_bookmarks(self) -> BookmarkListResponse: items = [BookmarkItem(**row) for row in self._repository.list_bookmarks()] return BookmarkListResponse(items=items) def delete_bookmark(self, bookmark_id: int) -> BookmarkDeleteResponse: deleted = self._repository.delete_bookmark(bookmark_id) if not deleted: raise AppError( code="path_not_found", message="Bookmark was not found", status_code=404, details={"bookmark_id": str(bookmark_id)}, ) return BookmarkDeleteResponse(id=bookmark_id)