- 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
121 lines
3.5 KiB
Python
121 lines
3.5 KiB
Python
"""Database module for SocialPhoto."""
|
|
import sqlite3
|
|
from pathlib import Path
|
|
from typing import Optional
|
|
|
|
DATABASE_PATH = Path(__file__).parent.parent / "socialphoto.db"
|
|
|
|
|
|
def get_db_connection() -> sqlite3.Connection:
|
|
"""Get a database connection with row factory."""
|
|
conn = sqlite3.connect(DATABASE_PATH, check_same_thread=False)
|
|
conn.row_factory = sqlite3.Row
|
|
return conn
|
|
|
|
|
|
def get_db() -> sqlite3.Connection:
|
|
"""Dependency for FastAPI routes."""
|
|
conn = get_db_connection()
|
|
try:
|
|
yield conn
|
|
finally:
|
|
conn.close()
|
|
|
|
|
|
def init_db() -> None:
|
|
"""Initialize the database with all tables."""
|
|
conn = get_db_connection()
|
|
cursor = conn.cursor()
|
|
|
|
# Users table
|
|
cursor.execute("""
|
|
CREATE TABLE IF NOT EXISTS users (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
username TEXT UNIQUE NOT NULL,
|
|
email TEXT UNIQUE NOT NULL,
|
|
password_hash TEXT NOT NULL,
|
|
avatar_url TEXT DEFAULT '/static/default-avatar.png',
|
|
bio TEXT DEFAULT '',
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
)
|
|
""")
|
|
|
|
# Posts table
|
|
cursor.execute("""
|
|
CREATE TABLE IF NOT EXISTS posts (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
user_id INTEGER NOT NULL REFERENCES users(id),
|
|
image_path TEXT NOT NULL,
|
|
caption TEXT DEFAULT '',
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
)
|
|
""")
|
|
|
|
# Comments table
|
|
cursor.execute("""
|
|
CREATE TABLE IF NOT EXISTS comments (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
post_id INTEGER NOT NULL REFERENCES posts(id),
|
|
user_id INTEGER NOT NULL REFERENCES users(id),
|
|
content TEXT NOT NULL,
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
)
|
|
""")
|
|
|
|
# Likes table
|
|
cursor.execute("""
|
|
CREATE TABLE IF NOT EXISTS likes (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
post_id INTEGER NOT NULL REFERENCES posts(id),
|
|
user_id INTEGER NOT NULL REFERENCES users(id),
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
UNIQUE(post_id, user_id)
|
|
)
|
|
""")
|
|
|
|
# Dislikes table
|
|
cursor.execute("""
|
|
CREATE TABLE IF NOT EXISTS dislikes (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
post_id INTEGER NOT NULL REFERENCES posts(id),
|
|
user_id INTEGER NOT NULL REFERENCES users(id),
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
UNIQUE(post_id, user_id)
|
|
)
|
|
""")
|
|
|
|
# Follows table
|
|
cursor.execute("""
|
|
CREATE TABLE IF NOT EXISTS follows (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
follower_id INTEGER NOT NULL REFERENCES users(id),
|
|
following_id INTEGER NOT NULL REFERENCES users(id),
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
UNIQUE(follower_id, following_id)
|
|
)
|
|
""")
|
|
|
|
# Comment likes table
|
|
cursor.execute("""
|
|
CREATE TABLE IF NOT EXISTS comment_likes (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
comment_id INTEGER NOT NULL REFERENCES comments(id),
|
|
user_id INTEGER NOT NULL REFERENCES users(id),
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
UNIQUE(comment_id, user_id)
|
|
)
|
|
""")
|
|
|
|
conn.commit()
|
|
conn.close()
|
|
|
|
|
|
def row_to_dict(row: sqlite3.Row) -> dict:
|
|
"""Convert a sqlite Row to a dictionary."""
|
|
return dict(row)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
init_db()
|
|
print("Database initialized successfully.")
|