171 lines
4.9 KiB
Python
171 lines
4.9 KiB
Python
from fastapi import APIRouter, Depends, HTTPException
|
|
from pydantic import BaseModel, EmailStr
|
|
from ...services.email_service import email_service
|
|
from ...services.bounce_service import bounce_service
|
|
from ...api.dependencies import get_admin_user
|
|
from ...models.models import User
|
|
from typing import Dict, Any, List
|
|
from ...core.database import get_db
|
|
from sqlalchemy.orm import Session
|
|
|
|
router = APIRouter()
|
|
|
|
router = APIRouter()
|
|
|
|
|
|
class TestEmailRequest(BaseModel):
|
|
to_email: EmailStr
|
|
subject: str
|
|
message: str
|
|
|
|
|
|
class WelcomeEmailRequest(BaseModel):
|
|
to_email: EmailStr
|
|
first_name: str
|
|
|
|
|
|
@router.post("/test-email")
|
|
async def send_test_email(
|
|
request: TestEmailRequest,
|
|
current_user: User = Depends(get_admin_user),
|
|
db: Session = Depends(get_db)
|
|
):
|
|
"""Send a test email (admin only)"""
|
|
html_body = f"<html><body><p>{request.message}</p></body></html>"
|
|
result = await email_service.send_email(
|
|
to_email=request.to_email,
|
|
subject=request.subject,
|
|
html_body=html_body,
|
|
text_body=request.message,
|
|
db=db
|
|
)
|
|
return {"success": True, "result": result}
|
|
|
|
|
|
@router.post("/test-welcome-email")
|
|
async def send_test_welcome_email(
|
|
request: WelcomeEmailRequest,
|
|
current_user: User = Depends(get_admin_user)
|
|
):
|
|
"""Send a test welcome email (admin only)"""
|
|
result = await email_service.send_welcome_email(
|
|
to_email=request.to_email,
|
|
first_name=request.first_name
|
|
)
|
|
return {"success": True, "result": result}
|
|
|
|
|
|
@router.post("/webhooks/smtp2go/bounce")
|
|
async def smtp2go_bounce_webhook(
|
|
webhook_data: Dict[str, Any],
|
|
db: Session = Depends(get_db)
|
|
):
|
|
"""
|
|
Webhook endpoint for SMTP2GO bounce notifications
|
|
This endpoint should be configured in SMTP2GO webhook settings
|
|
"""
|
|
try:
|
|
bounces_created = bounce_service.process_smtp2go_webhook(webhook_data, db)
|
|
return {
|
|
"success": True,
|
|
"bounces_processed": len(bounces_created),
|
|
"message": f"Successfully processed {len(bounces_created)} bounce events"
|
|
}
|
|
except Exception as e:
|
|
raise HTTPException(status_code=500, detail=f"Failed to process bounce webhook: {str(e)}")
|
|
|
|
|
|
@router.get("/bounces")
|
|
async def get_bounce_list(
|
|
skip: int = 0,
|
|
limit: int = 100,
|
|
current_user: User = Depends(get_admin_user),
|
|
db: Session = Depends(get_db)
|
|
):
|
|
"""Get list of email bounces (admin only)"""
|
|
from ...models.models import EmailBounce
|
|
|
|
bounces = db.query(EmailBounce).offset(skip).limit(limit).all()
|
|
total = db.query(EmailBounce).count()
|
|
|
|
return {
|
|
"bounces": [
|
|
{
|
|
"id": bounce.id,
|
|
"email": bounce.email,
|
|
"bounce_type": bounce.bounce_type.value,
|
|
"bounce_reason": bounce.bounce_reason,
|
|
"bounce_date": bounce.bounce_date.isoformat(),
|
|
"is_active": bounce.is_active,
|
|
"smtp2go_message_id": bounce.smtp2go_message_id
|
|
}
|
|
for bounce in bounces
|
|
],
|
|
"total": total,
|
|
"skip": skip,
|
|
"limit": limit
|
|
}
|
|
|
|
|
|
@router.get("/bounces/stats")
|
|
async def get_bounce_statistics(
|
|
current_user: User = Depends(get_admin_user),
|
|
db: Session = Depends(get_db)
|
|
):
|
|
"""Get bounce statistics (admin only)"""
|
|
stats = bounce_service.get_bounce_statistics(db)
|
|
return stats
|
|
|
|
|
|
@router.get("/bounces/{email}")
|
|
async def get_bounce_history(
|
|
email: str,
|
|
current_user: User = Depends(get_admin_user)
|
|
):
|
|
"""Get bounce history for a specific email (admin only)"""
|
|
bounces = bounce_service.get_bounce_history(email)
|
|
|
|
return {
|
|
"email": email,
|
|
"bounces": [
|
|
{
|
|
"id": bounce.id,
|
|
"bounce_type": bounce.bounce_type.value,
|
|
"bounce_reason": bounce.bounce_reason,
|
|
"bounce_date": bounce.bounce_date.isoformat(),
|
|
"is_active": bounce.is_active,
|
|
"smtp2go_message_id": bounce.smtp2go_message_id
|
|
}
|
|
for bounce in bounces
|
|
]
|
|
}
|
|
|
|
|
|
@router.post("/bounces/cleanup")
|
|
async def cleanup_old_bounces(
|
|
days_old: int = 365,
|
|
current_user: User = Depends(get_admin_user),
|
|
db: Session = Depends(get_db)
|
|
):
|
|
"""Clean up old soft bounces (admin only)"""
|
|
cleaned_count = bounce_service.cleanup_old_bounces(days_old, db)
|
|
return {
|
|
"success": True,
|
|
"message": f"Cleaned up {cleaned_count} old soft bounce records"
|
|
}
|
|
|
|
|
|
@router.delete("/bounces/deactivate/{bounce_id}")
|
|
async def deactivate_bounce(
|
|
bounce_id: int,
|
|
current_user: User = Depends(get_admin_user),
|
|
db: Session = Depends(get_db)
|
|
):
|
|
"""Deactivate a bounce record (mark as resolved) (admin only)"""
|
|
success = bounce_service.deactivate_bounce(bounce_id, db)
|
|
|
|
if not success:
|
|
raise HTTPException(status_code=404, detail="Bounce record not found")
|
|
|
|
return {"success": True, "message": "Bounce record deactivated"}
|