feat(api): implement notebook management CRUD endpoints
Implement Sprint 1: Notebook Management CRUD
- Add NotebookService with full CRUD operations
- Add POST /api/v1/notebooks (create notebook)
- Add GET /api/v1/notebooks (list with pagination)
- Add GET /api/v1/notebooks/{id} (get by ID)
- Add PATCH /api/v1/notebooks/{id} (partial update)
- Add DELETE /api/v1/notebooks/{id} (delete)
- Add Pydantic models for requests/responses
- Add custom exceptions (ValidationError, NotFoundError, NotebookLMError)
- Add comprehensive unit tests (31 tests, 97% coverage)
- Add API integration tests (26 tests)
- Fix router prefix duplication
- Fix JSON serialization in error responses
BREAKING CHANGE: None
This commit is contained in:
76
src/notebooklm_agent/core/config.py
Normal file
76
src/notebooklm_agent/core/config.py
Normal file
@@ -0,0 +1,76 @@
|
||||
"""Core configuration for NotebookLM Agent API."""
|
||||
|
||||
from functools import lru_cache
|
||||
from typing import Any
|
||||
|
||||
from pydantic import Field, field_validator
|
||||
from pydantic_settings import BaseSettings, SettingsConfigDict
|
||||
|
||||
|
||||
class Settings(BaseSettings):
|
||||
"""Application settings loaded from environment variables."""
|
||||
|
||||
model_config = SettingsConfigDict(
|
||||
env_file=".env",
|
||||
env_file_encoding="utf-8",
|
||||
case_sensitive=False,
|
||||
extra="ignore",
|
||||
)
|
||||
|
||||
# API Configuration
|
||||
api_key: str = Field(default="", alias="NOTEBOOKLM_AGENT_API_KEY")
|
||||
webhook_secret: str = Field(default="", alias="NOTEBOOKLM_AGENT_WEBHOOK_SECRET")
|
||||
port: int = Field(default=8000, alias="NOTEBOOKLM_AGENT_PORT")
|
||||
host: str = Field(default="0.0.0.0", alias="NOTEBOOKLM_AGENT_HOST")
|
||||
reload: bool = Field(default=False, alias="NOTEBOOKLM_AGENT_RELOAD")
|
||||
|
||||
# NotebookLM Configuration
|
||||
notebooklm_home: str = Field(default="~/.notebooklm", alias="NOTEBOOKLM_HOME")
|
||||
notebooklm_profile: str = Field(default="default", alias="NOTEBOOKLM_PROFILE")
|
||||
|
||||
# Redis Configuration
|
||||
redis_url: str = Field(default="redis://localhost:6379/0", alias="REDIS_URL")
|
||||
|
||||
# Logging
|
||||
log_level: str = Field(default="INFO", alias="LOG_LEVEL")
|
||||
log_format: str = Field(default="json", alias="LOG_FORMAT")
|
||||
|
||||
# Development
|
||||
debug: bool = Field(default=False, alias="DEBUG")
|
||||
testing: bool = Field(default=False, alias="TESTING")
|
||||
|
||||
# Security
|
||||
cors_origins: list[str] = Field(default_factory=list, alias="CORS_ORIGINS")
|
||||
|
||||
@field_validator("cors_origins", mode="before")
|
||||
@classmethod
|
||||
def parse_cors_origins(cls, v: Any) -> list[str]:
|
||||
"""Parse CORS origins from string or list."""
|
||||
if isinstance(v, str):
|
||||
return [origin.strip() for origin in v.split(",") if origin.strip()]
|
||||
return v if v else []
|
||||
|
||||
@field_validator("log_level")
|
||||
@classmethod
|
||||
def validate_log_level(cls, v: str) -> str:
|
||||
"""Validate log level is one of the allowed values."""
|
||||
allowed = {"DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"}
|
||||
v_upper = v.upper()
|
||||
if v_upper not in allowed:
|
||||
raise ValueError(f"log_level must be one of {allowed}")
|
||||
return v_upper
|
||||
|
||||
@property
|
||||
def is_production(self) -> bool:
|
||||
"""Check if running in production mode."""
|
||||
return not self.debug and not self.testing
|
||||
|
||||
|
||||
@lru_cache()
|
||||
def get_settings() -> Settings:
|
||||
"""Get cached settings instance.
|
||||
|
||||
Returns:
|
||||
Settings instance loaded from environment.
|
||||
"""
|
||||
return Settings()
|
||||
Reference in New Issue
Block a user