Moved channel URLs to channels_urls table. Create CRUD endpoints for new table.
All checks were successful
AWS Deploy on Push / build (push) Successful in 1m8s

This commit is contained in:
2025-05-23 11:36:04 -05:00
parent f11d533fac
commit c96ee307db
4 changed files with 142 additions and 13 deletions

View File

@@ -1,4 +1,4 @@
from .db import Base, ChannelDB
from .schemas import ChannelCreate, ChannelUpdate, ChannelResponse
from .db import Base, ChannelDB, ChannelURL
from .schemas import ChannelCreate, ChannelUpdate, ChannelResponse, ChannelURLCreate, ChannelURLResponse
__all__ = ["Base", "ChannelDB", "ChannelCreate", "ChannelUpdate", "ChannelResponse"]
__all__ = ["Base", "ChannelDB", "ChannelCreate", "ChannelUpdate", "ChannelResponse", "ChannelURL", "ChannelURLCreate", "ChannelURLResponse"]

View File

@@ -1,8 +1,9 @@
from datetime import datetime, timezone
import uuid
from sqlalchemy import Column, String, JSON, DateTime, UniqueConstraint
from sqlalchemy import Column, String, JSON, DateTime, UniqueConstraint, ForeignKey
from sqlalchemy.dialects.postgresql import UUID
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relationship
Base = declarative_base()
@@ -20,6 +21,21 @@ class ChannelDB(Base):
UniqueConstraint('group_title', 'name', name='uix_group_title_name'),
)
tvg_logo = Column(String)
urls = Column(JSON) # Stores list of URLs as JSON
created_at = Column(DateTime, default=lambda: datetime.now(timezone.utc))
updated_at = Column(DateTime, default=lambda: datetime.now(timezone.utc), onupdate=lambda: datetime.now(timezone.utc))
updated_at = Column(DateTime, default=lambda: datetime.now(timezone.utc), onupdate=lambda: datetime.now(timezone.utc))
# Relationship with ChannelURL
urls = relationship("ChannelURL", back_populates="channel", cascade="all, delete-orphan")
class ChannelURL(Base):
"""SQLAlchemy model for channel URLs"""
__tablename__ = "channels_urls"
id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
channel_id = Column(UUID(as_uuid=True), ForeignKey('channels.id', ondelete='CASCADE'), nullable=False)
url = Column(String, nullable=False)
created_at = Column(DateTime, default=lambda: datetime.now(timezone.utc))
updated_at = Column(DateTime, default=lambda: datetime.now(timezone.utc), onupdate=lambda: datetime.now(timezone.utc))
# Relationship with ChannelDB
channel = relationship("ChannelDB", back_populates="urls")

View File

@@ -3,22 +3,49 @@ from typing import List
from uuid import UUID
from pydantic import BaseModel
class ChannelURLCreate(BaseModel):
"""Pydantic model for creating channel URLs"""
url: str
class ChannelURLBase(ChannelURLCreate):
"""Base Pydantic model for channel URL responses"""
id: UUID
created_at: datetime
updated_at: datetime
class Config:
from_attributes = True
class ChannelURLResponse(ChannelURLBase):
"""Pydantic model for channel URL responses"""
pass
class ChannelCreate(BaseModel):
"""Pydantic model for creating channels"""
urls: List[str]
urls: List[str] # List of URLs to create with the channel
name: str
group_title: str
tvg_id: str
tvg_logo: str
tvg_name: str
class ChannelUpdate(ChannelCreate):
class ChannelUpdate(BaseModel):
"""Pydantic model for updating channels"""
pass
name: str | None = None
group_title: str | None = None
tvg_id: str | None = None
tvg_logo: str | None = None
tvg_name: str | None = None
class ChannelResponse(ChannelCreate):
class ChannelResponse(BaseModel):
"""Pydantic model for channel responses"""
id: UUID
name: str
group_title: str
tvg_id: str
tvg_logo: str
tvg_name: str
urls: List[ChannelURLResponse] # List of URL objects without channel_id
created_at: datetime
updated_at: datetime

View File

@@ -4,7 +4,15 @@ from typing import List
from uuid import UUID
from sqlalchemy import and_
from app.models import ChannelDB, ChannelCreate, ChannelUpdate, ChannelResponse
from app.models import (
ChannelDB,
ChannelURL,
ChannelCreate,
ChannelUpdate,
ChannelResponse,
ChannelURLCreate,
ChannelURLResponse,
)
from app.utils.database import get_db
from app.auth.dependencies import get_current_user, require_roles
from app.models.auth import CognitoUser
@@ -36,10 +44,21 @@ def create_channel(
detail="Channel with same group_title and name already exists"
)
db_channel = ChannelDB(**channel.model_dump())
# Create channel without URLs first
channel_data = channel.model_dump()
urls = channel_data.pop('urls', [])
db_channel = ChannelDB(**channel_data)
db.add(db_channel)
db.commit()
db.refresh(db_channel)
# Add URLs
for url in urls:
db_url = ChannelURL(channel_id=db_channel.id, url=url)
db.add(db_url)
db.commit()
db.refresh(db_channel)
return db_channel
@router.get("/{channel_id}", response_model=ChannelResponse)
@@ -121,4 +140,71 @@ def list_channels(
user: CognitoUser = Depends(get_current_user)
):
"""List all channels with pagination"""
return db.query(ChannelDB).offset(skip).limit(limit).all()
return db.query(ChannelDB).offset(skip).limit(limit).all()
# URL Management Endpoints
@router.post("/{channel_id}/urls", response_model=ChannelURLResponse, status_code=status.HTTP_201_CREATED)
@require_roles("admin")
def add_channel_url(
channel_id: UUID,
url: ChannelURLCreate,
db: Session = Depends(get_db),
user: CognitoUser = Depends(get_current_user)
):
"""Add a new URL to a channel"""
channel = db.query(ChannelDB).filter(ChannelDB.id == channel_id).first()
if not channel:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail="Channel not found"
)
db_url = ChannelURL(channel_id=channel_id, url=url.url)
db.add(db_url)
db.commit()
db.refresh(db_url)
return db_url
@router.delete("/{channel_id}/urls/{url_id}", status_code=status.HTTP_204_NO_CONTENT)
@require_roles("admin")
def delete_channel_url(
channel_id: UUID,
url_id: UUID,
db: Session = Depends(get_db),
user: CognitoUser = Depends(get_current_user)
):
"""Delete a URL from a channel"""
url = db.query(ChannelURL).filter(
and_(
ChannelURL.id == url_id,
ChannelURL.channel_id == channel_id
)
).first()
if not url:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail="URL not found"
)
db.delete(url)
db.commit()
return None
@router.get("/{channel_id}/urls", response_model=List[ChannelURLResponse])
@require_roles("admin")
def list_channel_urls(
channel_id: UUID,
db: Session = Depends(get_db),
user: CognitoUser = Depends(get_current_user)
):
"""List all URLs for a channel"""
channel = db.query(ChannelDB).filter(ChannelDB.id == channel_id).first()
if not channel:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail="Channel not found"
)
return db.query(ChannelURL).filter(ChannelURL.channel_id == channel_id).all()