diff --git a/app/main.py b/app/main.py index 3849dc8..de7428b 100644 --- a/app/main.py +++ b/app/main.py @@ -1,12 +1,18 @@ """FastAPI application entry point.""" from contextlib import asynccontextmanager +from pathlib import Path from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware +from fastapi.staticfiles import StaticFiles from app.core.config import settings from app.db.database import engine, Base -from app.routers.auth import router as auth_router +from app.routers.auth import router as auth_router # noqa: F401 +from app.routes.posts import router as posts_router +from app.routes.users import router as users_router +from app.routes.comments import router as comments_router +from app.routes.feed import router as feed_router @asynccontextmanager @@ -37,6 +43,15 @@ app.add_middleware( # Include routers app.include_router(auth_router) +app.include_router(posts_router) +app.include_router(users_router) +app.include_router(comments_router) +app.include_router(feed_router) + +# Mount static files for uploads +UPLOAD_DIR = Path(__file__).parent.parent / "uploads" +UPLOAD_DIR.mkdir(parents=True, exist_ok=True) +app.mount("/uploads", StaticFiles(directory=str(UPLOAD_DIR)), name="uploads") @app.get("/") diff --git a/app/models.py b/app/models.py deleted file mode 100644 index f7e3c3f..0000000 --- a/app/models.py +++ /dev/null @@ -1,109 +0,0 @@ -"""Pydantic models for SocialPhoto API.""" -from datetime import datetime -from typing import Optional, List - -from pydantic import BaseModel, ConfigDict, EmailStr, Field - - -# Auth Models -class UserRegister(BaseModel): - """Request model for user registration.""" - username: str = Field(..., min_length=3, max_length=50) - email: EmailStr - password: str = Field(..., min_length=6) - - -class UserLogin(BaseModel): - """Request model for user login.""" - username: str - password: str - - -class Token(BaseModel): - """Response model for JWT token.""" - access_token: str - token_type: str = "bearer" - - -# User Models -class UserBase(BaseModel): - """Base user model.""" - username: str - email: str - avatar_url: Optional[str] = "/static/default-avatar.png" - bio: Optional[str] = "" - - -class UserResponse(UserBase): - """Response model for user data.""" - id: int - created_at: datetime - - model_config = ConfigDict(from_attributes=True) - - -class UserStats(BaseModel): - """User statistics model.""" - posts_count: int - followers_count: int - following_count: int - - -# Post Models -class PostCreate(BaseModel): - """Request model for creating a post.""" - caption: Optional[str] = "" - - -class PostResponse(BaseModel): - """Response model for post data.""" - id: int - user_id: int - username: str - image_url: str - caption: str - likes_count: int - dislikes_count: int - comments_count: int - created_at: datetime - - model_config = ConfigDict(from_attributes=True) - - -class PostDetail(PostResponse): - """Detailed post response with user info.""" - user: UserResponse - - -# Comment Models -class CommentCreate(BaseModel): - """Request model for creating a comment.""" - content: str = Field(..., min_length=1, max_length=500) - - -class CommentResponse(BaseModel): - """Response model for comment data.""" - id: int - post_id: int - user_id: int - username: str - content: str - likes_count: int - created_at: datetime - - model_config = ConfigDict(from_attributes=True) - - -# Feed Models -class FeedResponse(BaseModel): - """Response model for feed.""" - posts: List[PostResponse] - total: int - limit: int - offset: int - - -# Error Models -class ErrorResponse(BaseModel): - """Standard error response.""" - detail: str diff --git a/app/models/__init__.py b/app/models/__init__.py index 48da878..6c22bca 100644 --- a/app/models/__init__.py +++ b/app/models/__init__.py @@ -1,4 +1,6 @@ """Models package.""" + +# SQLAlchemy models from app.models.user import User __all__ = ["User"] diff --git a/app/routes/auth.py b/app/routes/auth.py index 1f787f5..bcdc436 100644 --- a/app/routes/auth.py +++ b/app/routes/auth.py @@ -6,8 +6,8 @@ from fastapi import APIRouter, Depends, HTTPException, status from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer from app.auth import create_access_token, hash_password, verify_password -from app.database import get_db, row_to_dict -from app.models import Token, UserLogin, UserRegister +from app.db.database import get_db, row_to_dict +from app.schemas import Token, UserLogin, UserRegister router = APIRouter(prefix="/auth", tags=["Authentication"]) security = HTTPBearer() diff --git a/app/routes/feed.py b/app/routes/feed.py index 8a04caf..eeb6abb 100644 --- a/app/routes/feed.py +++ b/app/routes/feed.py @@ -7,7 +7,7 @@ from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer from app.auth import get_current_user_id from app.database import get_db, row_to_dict -from app.models import FeedResponse, PostResponse +from app.schemas import FeedResponse, PostResponse router = APIRouter(prefix="/feed", tags=["Feed"]) security = HTTPBearer() diff --git a/app/routes/posts.py b/app/routes/posts.py index bdc6cc6..2fbfcd0 100644 --- a/app/routes/posts.py +++ b/app/routes/posts.py @@ -12,7 +12,7 @@ from fastapi.responses import FileResponse from app.auth import get_current_user_id from app.database import get_db, row_to_dict -from app.models import CommentCreate, CommentResponse, PostResponse +from app.schemas import CommentCreate, CommentResponse, PostResponse router = APIRouter(prefix="/posts", tags=["Posts"]) security = HTTPBearer() diff --git a/app/routes/users.py b/app/routes/users.py index d7b2411..5459f56 100644 --- a/app/routes/users.py +++ b/app/routes/users.py @@ -7,7 +7,7 @@ from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer from app.auth import get_current_user_id from app.database import get_db, row_to_dict -from app.models import PostResponse, UserResponse, UserStats +from app.schemas import PostResponse, UserResponse, UserStats router = APIRouter(prefix="/users", tags=["Users"]) security = HTTPBearer() diff --git a/app/schemas/__init__.py b/app/schemas/__init__.py index 055a844..f1eaf88 100644 --- a/app/schemas/__init__.py +++ b/app/schemas/__init__.py @@ -6,4 +6,24 @@ from app.schemas.auth import ( UserResponse, ) -__all__ = ["Token", "UserLogin", "UserRegister", "UserResponse"] +# Post schemas +from app.schemas.post import CommentCreate, CommentResponse, PostResponse + +# User schemas +from app.schemas.user import UserBase, UserStats + +# Feed schemas +from app.schemas.feed import FeedResponse + +__all__ = [ + "Token", + "UserLogin", + "UserRegister", + "UserResponse", + "CommentCreate", + "CommentResponse", + "PostResponse", + "UserBase", + "UserStats", + "FeedResponse", +] diff --git a/app/schemas/feed.py b/app/schemas/feed.py new file mode 100644 index 0000000..59cff34 --- /dev/null +++ b/app/schemas/feed.py @@ -0,0 +1,14 @@ +"""Feed schemas for SocialPhoto API.""" +from typing import List + +from pydantic import BaseModel + +from app.schemas.post import PostResponse + + +class FeedResponse(BaseModel): + """Response model for feed.""" + posts: List[PostResponse] + total: int + limit: int + offset: int diff --git a/app/schemas/post.py b/app/schemas/post.py new file mode 100644 index 0000000..a268c24 --- /dev/null +++ b/app/schemas/post.py @@ -0,0 +1,48 @@ +"""Post schemas for SocialPhoto API.""" +from datetime import datetime +from typing import Optional + +from pydantic import BaseModel, ConfigDict, Field + + +class PostCreate(BaseModel): + """Request model for creating a post.""" + caption: Optional[str] = "" + + +class PostResponse(BaseModel): + """Response model for post data.""" + id: int + user_id: int + username: str + image_url: str + caption: str + likes_count: int + dislikes_count: int + comments_count: int + created_at: datetime + + model_config = ConfigDict(from_attributes=True) + + +class PostDetail(PostResponse): + """Detailed post response with user info.""" + user: "UserResponse" # noqa: F821 + + +class CommentCreate(BaseModel): + """Request model for creating a comment.""" + content: str = Field(..., min_length=1, max_length=500) + + +class CommentResponse(BaseModel): + """Response model for comment data.""" + id: int + post_id: int + user_id: int + username: str + content: str + likes_count: int + created_at: datetime + + model_config = ConfigDict(from_attributes=True) diff --git a/app/schemas/user.py b/app/schemas/user.py new file mode 100644 index 0000000..d0e9a86 --- /dev/null +++ b/app/schemas/user.py @@ -0,0 +1,20 @@ +"""User schemas for SocialPhoto API.""" +from datetime import datetime +from typing import Optional + +from pydantic import BaseModel, ConfigDict + + +class UserBase(BaseModel): + """Base user model.""" + username: str + email: str + avatar_url: Optional[str] = "/static/default-avatar.png" + bio: Optional[str] = "" + + +class UserStats(BaseModel): + """User statistics model.""" + posts_count: int + followers_count: int + following_count: int