Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion Backend/app/db/db.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@

# Initialize async SQLAlchemy components
try:
engine = create_async_engine(DATABASE_URL, echo=True, connect_args={"ssl": "require"})
engine = create_async_engine(
DATABASE_URL, echo=True, connect_args={"ssl": "require"}
)

AsyncSessionLocal = sessionmaker(
bind=engine, class_=AsyncSession, expire_on_commit=False
Expand All @@ -31,3 +33,8 @@
engine = None
AsyncSessionLocal = None
Base = None


async def get_db():
async with AsyncSessionLocal() as session:
yield session
54 changes: 54 additions & 0 deletions Backend/app/db/seed.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
from datetime import datetime, timezone
from db.db import AsyncSessionLocal
from models.models import User


async def seed_db():
users = [
{
"id": "aabb1fd8-ba93-4e8c-976e-35e5c40b809c",
"username": "creator1",
"email": "creator1@example.com",
"password": "password123",
"role": "creator",
"bio": "Lifestyle and travel content creator",
},
{
"id": "6dbfcdd5-795f-49c1-8f7a-a5538b8c6f6f",
"username": "brand1",
"email": "brand1@example.com",
"password": "password123",
"role": "brand",
"bio": "Sustainable fashion brand looking for influencers",
},
]

# Insert or update the users
async with AsyncSessionLocal() as session:
for user_data in users:
# Check if user exists
existing_user = await session.execute(
User.__table__.select().where(User.email == user_data["email"])
)
existing_user = existing_user.scalar_one_or_none()

if existing_user:
continue
else:
# Create new user
user = User(
id=user_data["id"],
username=user_data["username"],
email=user_data["email"],
password_hash=user_data[
"password"
], # Using plain password directly
role=user_data["role"],
bio=user_data["bio"],
)
session.add(user)
print(f"Created user: {user_data['email']}")

# Commit the session
await session.commit()
print("βœ… Users seeded successfully.")
23 changes: 21 additions & 2 deletions Backend/app/main.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from db.db import engine
from models import models
from db.seed import seed_db
from models import models, chat
from routes.post import router as post_router
from routes.chat import router as chat_router
from sqlalchemy.exc import SQLAlchemyError
import logging
import os
Expand All @@ -11,28 +14,44 @@
# Load environment variables
load_dotenv()


# Async function to create database tables with exception handling
async def create_tables():
try:
async with engine.begin() as conn:
await conn.run_sync(models.Base.metadata.create_all)
await conn.run_sync(chat.Base.metadata.create_all)
print("βœ… Tables created successfully or already exist.")
except SQLAlchemyError as e:
print(f"❌ Error creating tables: {e}")

#Lifespan context manager for startup and shutdown events

# Lifespan context manager for startup and shutdown events
@asynccontextmanager
async def lifespan(app: FastAPI):
print("App is starting...")
await create_tables()
await seed_db()
yield
print("App is shutting down...")


# Initialize FastAPI
app = FastAPI(lifespan=lifespan)

# Add CORS middleware
app.add_middleware(
CORSMiddleware,
allow_origins=["http://localhost:5173"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)

# Include the routes
app.include_router(post_router)
app.include_router(chat_router)


@app.get("/")
async def home():
Expand Down
54 changes: 54 additions & 0 deletions Backend/app/models/chat.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
from sqlalchemy import Column, String, ForeignKey, DateTime, Enum, UniqueConstraint
from sqlalchemy.orm import relationship
from datetime import datetime, timezone
from db.db import Base
import uuid
import enum


def generate_uuid():
return str(uuid.uuid4())


class MessageStatus(enum.Enum):
SENT = "sent"
DELIVERED = "delivered"
SEEN = "seen"


class ChatList(Base):
__tablename__ = "chat_list"

id = Column(String, primary_key=True, default=generate_uuid)
user1_id = Column(String, ForeignKey("users.id"), nullable=False)
user2_id = Column(String, ForeignKey("users.id"), nullable=False)
last_message_time = Column(
DateTime(timezone=True), default=lambda: datetime.now(timezone.utc)
)

user1 = relationship("User", foreign_keys=[user1_id], backref="chatlist_user1")
user2 = relationship("User", foreign_keys=[user2_id], backref="chatlist_user2")

__table_args__ = (UniqueConstraint("user1_id", "user2_id", name="unique_chat"),)


class ChatMessage(Base):
__tablename__ = "chat_messages"

id = Column(String, primary_key=True, default=generate_uuid)
sender_id = Column(String, ForeignKey("users.id"), nullable=False)
receiver_id = Column(String, ForeignKey("users.id"), nullable=False)
message = Column(String, nullable=False)
status = Column(
Enum(MessageStatus), default=MessageStatus.SENT
) # Using the enum class
created_at = Column(
DateTime(timezone=True), default=lambda: datetime.now(timezone.utc)
)

sender = relationship("User", foreign_keys=[sender_id], backref="sent_messages")
receiver = relationship(
"User", foreign_keys=[receiver_id], backref="received_messages"
)
chat_list_id = Column(String, ForeignKey("chat_list.id"), nullable=False)
chat = relationship("ChatList", backref="messages")
72 changes: 61 additions & 11 deletions Backend/app/models/models.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,25 @@
from sqlalchemy import Column, String, Integer, ForeignKey, Float, Text, JSON, DECIMAL, TIMESTAMP
from sqlalchemy import (
Column,
String,
Integer,
ForeignKey,
Float,
Text,
JSON,
DECIMAL,
DateTime,
Boolean,
)
from sqlalchemy.orm import relationship
from datetime import datetime, timezone
from db.db import Base
import uuid


def generate_uuid():
return str(uuid.uuid4())


# User Table (Creators & Brands)
class User(Base):
__tablename__ = "users"
Expand All @@ -18,13 +31,30 @@ class User(Base):
role = Column(String, nullable=False) # 'creator' or 'brand'
profile_image = Column(Text, nullable=True)
bio = Column(Text, nullable=True)
created_at = Column(TIMESTAMP, default=lambda: datetime.now(timezone.utc))
created_at = Column(
DateTime(timezone=True), default=lambda: datetime.now(timezone.utc)
)

is_online = Column(Boolean, default=False) # βœ… Track if user is online
last_seen = Column(
DateTime(timezone=True), default=lambda: datetime.now(timezone.utc)
)

audience = relationship("AudienceInsights", back_populates="user", uselist=False)
sponsorships = relationship("Sponsorship", back_populates="brand")
posts = relationship("UserPost", back_populates="user")
applications = relationship("SponsorshipApplication", back_populates="creator")
payments = relationship("SponsorshipPayment", back_populates="creator")
payments = relationship(
"SponsorshipPayment",
foreign_keys="[SponsorshipPayment.creator_id]",
back_populates="creator",
)
brand_payments = relationship(
"SponsorshipPayment",
foreign_keys="[SponsorshipPayment.brand_id]",
back_populates="brand",
)


# Audience Insights Table
class AudienceInsights(Base):
Expand All @@ -38,10 +68,13 @@ class AudienceInsights(Base):
average_views = Column(Integer)
time_of_attention = Column(Integer) # in seconds
price_expectation = Column(DECIMAL(10, 2))
created_at = Column(TIMESTAMP, default=lambda: datetime.now(timezone.utc))
created_at = Column(
DateTime(timezone=True), default=lambda: datetime.now(timezone.utc)
)

user = relationship("User", back_populates="audience")


# Sponsorship Table (For Brands)
class Sponsorship(Base):
__tablename__ = "sponsorships"
Expand All @@ -54,11 +87,14 @@ class Sponsorship(Base):
budget = Column(DECIMAL(10, 2))
engagement_minimum = Column(Float)
status = Column(String, default="open")
created_at = Column(TIMESTAMP, default=lambda: datetime.now(timezone.utc))
created_at = Column(
DateTime(timezone=True), default=lambda: datetime.now(timezone.utc)
)

brand = relationship("User", back_populates="sponsorships")
applications = relationship("SponsorshipApplication", back_populates="sponsorship")


# User Posts Table
class UserPost(Base):
__tablename__ = "user_posts"
Expand All @@ -70,10 +106,13 @@ class UserPost(Base):
post_url = Column(Text, nullable=True)
category = Column(String, nullable=True)
engagement_metrics = Column(JSON) # {"likes": 500, "comments": 100, "shares": 50}
created_at = Column(TIMESTAMP, default=lambda: datetime.now(timezone.utc))
created_at = Column(
DateTime(timezone=True), default=lambda: datetime.now(timezone.utc)
)

user = relationship("User", back_populates="posts")


# Sponsorship Applications Table
class SponsorshipApplication(Base):
__tablename__ = "sponsorship_applications"
Expand All @@ -84,11 +123,14 @@ class SponsorshipApplication(Base):
post_id = Column(String, ForeignKey("user_posts.id"), nullable=True)
proposal = Column(Text, nullable=False)
status = Column(String, default="pending")
applied_at = Column(TIMESTAMP, default=datetime.utcnow)
applied_at = Column(
DateTime(timezone=True), default=lambda: datetime.now(timezone.utc)
)

creator = relationship("User", back_populates="applications")
sponsorship = relationship("Sponsorship", back_populates="applications")


# Collaborations Table
class Collaboration(Base):
__tablename__ = "collaborations"
Expand All @@ -98,7 +140,10 @@ class Collaboration(Base):
creator_2_id = Column(String, ForeignKey("users.id"), nullable=False)
collaboration_details = Column(Text, nullable=False)
status = Column(String, default="pending")
created_at = Column(TIMESTAMP,default=lambda: datetime.now(timezone.utc))
created_at = Column(
DateTime(timezone=True), default=lambda: datetime.now(timezone.utc)
)


# Sponsorship Payments Table
class SponsorshipPayment(Base):
Expand All @@ -110,6 +155,11 @@ class SponsorshipPayment(Base):
sponsorship_id = Column(String, ForeignKey("sponsorships.id"), nullable=False)
amount = Column(DECIMAL(10, 2), nullable=False)
status = Column(String, default="pending")
transaction_date = Column(TIMESTAMP, default=datetime.utcnow)

creator = relationship("User", back_populates="payments")
transaction_date = Column(
DateTime(timezone=True), default=lambda: datetime.now(timezone.utc)
)

creator = relationship("User", foreign_keys=[creator_id], back_populates="payments")
brand = relationship(
"User", foreign_keys=[brand_id], back_populates="brand_payments"
)
Loading