Files
instagram-clone/app/routes/feed.py
OpenClaw Agent a3eca3b7da feat: implement Instagram clone SocialPhoto API
- FastAPI backend with SQLite database
- JWT authentication (register, login)
- User profiles with follow/unfollow
- Posts with image upload and likes/dislikes
- Comments with likes
- Global and personalized feed
- Comprehensive pytest test suite (37 tests)

TASK-ID: 758f4029-702
2026-04-16 03:20:48 +00:00

125 lines
4.0 KiB
Python

"""Feed routes for SocialPhoto."""
import sqlite3
from typing import List
from fastapi import APIRouter, Depends, Query
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
router = APIRouter(prefix="/feed", tags=["Feed"])
security = HTTPBearer()
@router.get("", response_model=FeedResponse)
async def get_followed_feed(
limit: int = Query(default=20, ge=1, le=100),
offset: int = Query(default=0, ge=0),
credentials: HTTPAuthorizationCredentials = Depends(security),
conn: sqlite3.Connection = Depends(get_db),
) -> FeedResponse:
"""Get feed of posts from users you follow."""
user_id = await get_current_user_id(credentials)
cursor = conn.cursor()
# Get posts from followed users
cursor.execute(
"""
SELECT
p.id, p.user_id, u.username, p.image_path, p.caption, p.created_at,
(SELECT COUNT(*) FROM likes WHERE post_id = p.id) as likes_count,
(SELECT COUNT(*) FROM dislikes WHERE post_id = p.id) as dislikes_count,
(SELECT COUNT(*) FROM comments WHERE post_id = p.id) as comments_count
FROM posts p
JOIN users u ON p.user_id = u.id
WHERE p.user_id IN (
SELECT following_id FROM follows WHERE follower_id = ?
)
ORDER BY p.created_at DESC
LIMIT ? OFFSET ?
""",
(user_id, limit, offset),
)
posts = []
for row in cursor.fetchall():
post = row_to_dict(row)
posts.append(
PostResponse(
id=post["id"],
user_id=post["user_id"],
username=post["username"],
image_url=f"/uploads/{post['image_path'].split('/')[-1]}",
caption=post["caption"],
likes_count=post["likes_count"],
dislikes_count=post["dislikes_count"],
comments_count=post["comments_count"],
created_at=post["created_at"],
)
)
# Get total count
cursor.execute(
"""
SELECT COUNT(*) as total
FROM posts p
WHERE p.user_id IN (
SELECT following_id FROM follows WHERE follower_id = ?
)
""",
(user_id,),
)
total = cursor.fetchone()["total"]
return FeedResponse(posts=posts, total=total, limit=limit, offset=offset)
@router.get("/global", response_model=FeedResponse)
async def get_global_feed(
limit: int = Query(default=20, ge=1, le=100),
offset: int = Query(default=0, ge=0),
conn: sqlite3.Connection = Depends(get_db),
) -> FeedResponse:
"""Get global feed of all posts."""
cursor = conn.cursor()
cursor.execute(
"""
SELECT
p.id, p.user_id, u.username, p.image_path, p.caption, p.created_at,
(SELECT COUNT(*) FROM likes WHERE post_id = p.id) as likes_count,
(SELECT COUNT(*) FROM dislikes WHERE post_id = p.id) as dislikes_count,
(SELECT COUNT(*) FROM comments WHERE post_id = p.id) as comments_count
FROM posts p
JOIN users u ON p.user_id = u.id
ORDER BY p.created_at DESC
LIMIT ? OFFSET ?
""",
(limit, offset),
)
posts = []
for row in cursor.fetchall():
post = row_to_dict(row)
posts.append(
PostResponse(
id=post["id"],
user_id=post["user_id"],
username=post["username"],
image_url=f"/uploads/{post['image_path'].split('/')[-1]}",
caption=post["caption"],
likes_count=post["likes_count"],
dislikes_count=post["dislikes_count"],
comments_count=post["comments_count"],
created_at=post["created_at"],
)
)
# Get total count
cursor.execute("SELECT COUNT(*) as total FROM posts")
total = cursor.fetchone()["total"]
return FeedResponse(posts=posts, total=total, limit=limit, offset=offset)