Files
LetterFeed/backend/app/crud/newsletters.py
2025-07-24 13:20:22 +02:00

141 lines
4.6 KiB
Python

from nanoid import generate
from sqlalchemy import func, or_
from sqlalchemy.orm import Session
from app.core.logging import get_logger
from app.models.entries import Entry
from app.models.newsletters import Newsletter, Sender
from app.schemas.newsletters import NewsletterCreate, NewsletterUpdate
logger = get_logger(__name__)
def get_newsletter_by_identifier(db: Session, identifier: str):
"""Retrieve a single newsletter by its ID or slug."""
logger.debug(f"Querying for newsletter with identifier={identifier}")
result = (
db.query(Newsletter, func.count(Entry.id))
.outerjoin(Entry, Newsletter.id == Entry.newsletter_id)
.filter(or_(Newsletter.id == identifier, Newsletter.slug == identifier))
.group_by(Newsletter.id)
.first()
)
if result:
newsletter, count = result
newsletter.entries_count = count
return newsletter
return None
def get_newsletter_by_slug(db: Session, slug: str):
"""Retrieve a newsletter by its slug."""
return db.query(Newsletter).filter(Newsletter.slug == slug).first()
def get_newsletters(db: Session, skip: int = 0, limit: int = 100):
"""Retrieve a list of newsletters."""
logger.debug(f"Querying for newsletters with skip={skip}, limit={limit}")
results = (
db.query(Newsletter, func.count(Entry.id))
.outerjoin(Entry, Newsletter.id == Entry.newsletter_id)
.group_by(Newsletter.id)
.order_by(Newsletter.id)
.offset(skip)
.limit(limit)
.all()
)
newsletters_with_count = []
for newsletter, count in results:
newsletter.entries_count = count
newsletters_with_count.append(newsletter)
return newsletters_with_count
def create_newsletter(db: Session, newsletter: NewsletterCreate):
"""Create a new newsletter."""
logger.info(f"Creating new newsletter with name '{newsletter.name}'")
if newsletter.slug and get_newsletter_by_slug(db, newsletter.slug):
return None # Indicates a conflict
db_newsletter = Newsletter(
id=generate(size=10),
name=newsletter.name,
slug=newsletter.slug,
extract_content=newsletter.extract_content,
move_to_folder=newsletter.move_to_folder,
)
db.add(db_newsletter)
db.commit()
db.refresh(db_newsletter)
for email in newsletter.sender_emails:
db_sender = Sender(id=generate(), email=email, newsletter_id=db_newsletter.id)
db.add(db_sender)
db.commit()
db.refresh(db_newsletter)
logger.info(f"Successfully created newsletter with id={db_newsletter.id}")
db_newsletter.entries_count = 0
return db_newsletter
def update_newsletter(
db: Session, newsletter_id: str, newsletter_update: NewsletterUpdate
):
"""Update an existing newsletter."""
logger.info(f"Updating newsletter with id={newsletter_id}")
db_newsletter = db.query(Newsletter).filter(Newsletter.id == newsletter_id).first()
if not db_newsletter:
return None
if newsletter_update.slug:
existing_newsletter = get_newsletter_by_slug(db, newsletter_update.slug)
if existing_newsletter and existing_newsletter.id != newsletter_id:
return "conflict" # Indicates a conflict
update_data = newsletter_update.model_dump(exclude_unset=True)
for key, value in update_data.items():
if key == "sender_emails":
continue
setattr(db_newsletter, key, value)
# More efficient sender update
existing_emails = {sender.email for sender in db_newsletter.senders}
new_emails = set(newsletter_update.sender_emails)
# Remove senders that are no longer in the list
for sender in db_newsletter.senders:
if sender.email not in new_emails:
db.delete(sender)
# Add new senders
for email in new_emails:
if email not in existing_emails:
db_sender = Sender(
id=generate(), email=email, newsletter_id=db_newsletter.id
)
db.add(db_sender)
db.commit()
db.refresh(db_newsletter)
logger.info(f"Successfully updated newsletter with id={db_newsletter.id}")
return get_newsletter_by_identifier(db, newsletter_id)
def delete_newsletter(db: Session, newsletter_id: str):
"""Delete a newsletter by its ID."""
logger.info(f"Deleting newsletter with id={newsletter_id}")
db_newsletter = get_newsletter_by_identifier(db, newsletter_id)
if not db_newsletter:
return None
db.delete(db_newsletter)
db.commit()
logger.info(f"Successfully deleted newsletter with id={newsletter_id}")
return db_newsletter