|
|
@@ -0,0 +1,126 @@
|
|
|
+import datetime
|
|
|
+from typing import Annotated
|
|
|
+from uuid import UUID
|
|
|
+
|
|
|
+from fastapi import APIRouter, Depends, Query, HTTPException, Request
|
|
|
+from sqlalchemy import select
|
|
|
+from sqlalchemy.orm import Session
|
|
|
+
|
|
|
+from app.core.config import settings
|
|
|
+from app.models import User, Sms, ServerStatus
|
|
|
+from app.schemas.responses import SMSResponse, SMSServerStatus, EnumServerStatus
|
|
|
+from app.api import deps
|
|
|
+
|
|
|
+router = APIRouter(prefix="/sms-sender", tags=["sms_sender"])
|
|
|
+
|
|
|
+
|
|
|
+@router.get("/sms/to-send", response_model=list[SMSResponse])
|
|
|
+async def list_sms_to_send(
|
|
|
+ current_user: User = Depends(deps.get_current_user),
|
|
|
+ session: Session = Depends(deps.get_session),
|
|
|
+ max_delay: Annotated[
|
|
|
+ int | None, Query(description="the maximum delay a sms should be send with")
|
|
|
+ ] = 10,
|
|
|
+):
|
|
|
+ """List sms that should be send by now"""
|
|
|
+
|
|
|
+ now = datetime.datetime.now()
|
|
|
+ min_sending_time = now - datetime.timedelta(minutes=max_delay)
|
|
|
+ results = session.execute(
|
|
|
+ select(Sms).where(
|
|
|
+ (Sms.sending_time > min_sending_time)
|
|
|
+ & (Sms.sending_time < now)
|
|
|
+ & (Sms.send_time == None) # noqa: E711
|
|
|
+ )
|
|
|
+ )
|
|
|
+ return results.scalars().all()
|
|
|
+
|
|
|
+
|
|
|
+@router.post("/sms/send-now/{sms_id}", response_model=SMSResponse)
|
|
|
+async def send_sms_now(
|
|
|
+ request: Request,
|
|
|
+ sms_id: UUID,
|
|
|
+ current_user: User = Depends(deps.get_current_user),
|
|
|
+ session: Session = Depends(deps.get_session),
|
|
|
+):
|
|
|
+ """Update the SMS to be sent now"""
|
|
|
+ sms = session.get(Sms, sms_id)
|
|
|
+ if sms is None:
|
|
|
+ raise HTTPException(status_code=404, detail="SMS not found")
|
|
|
+ elif sms.send_time is not None:
|
|
|
+ raise HTTPException(status_code=400, detail="SMS has already been sent")
|
|
|
+ else:
|
|
|
+ sms.send_time = datetime.datetime.now()
|
|
|
+ session.commit()
|
|
|
+ await update_status(request, current_user, session)
|
|
|
+ return sms
|
|
|
+
|
|
|
+
|
|
|
+@router.get("/sms/not-send", response_model=list[SMSResponse])
|
|
|
+async def list_not_sent(
|
|
|
+ current_user: User = Depends(deps.get_current_user),
|
|
|
+ session: Session = Depends(deps.get_session),
|
|
|
+):
|
|
|
+ """List sms that are not sent"""
|
|
|
+ results = session.execute(select(Sms).where((Sms.send_time == None))) # noqa: E711
|
|
|
+ return results.scalars().all()
|
|
|
+
|
|
|
+
|
|
|
+@router.get("/sms/future", response_model=list[SMSResponse])
|
|
|
+async def list_future_sms(
|
|
|
+ current_user: User = Depends(deps.get_current_user),
|
|
|
+ session: Session = Depends(deps.get_session),
|
|
|
+):
|
|
|
+ """List sms that should be sent in the future"""
|
|
|
+ results = session.execute(select(Sms).where(Sms.sending_time > datetime.datetime.now()))
|
|
|
+ return results.scalars().all()
|
|
|
+
|
|
|
+
|
|
|
+@router.post("/status")
|
|
|
+async def update_status(
|
|
|
+ request: Request,
|
|
|
+ current_user: User = Depends(deps.get_current_user),
|
|
|
+ session: Session = Depends(deps.get_session),
|
|
|
+):
|
|
|
+ """Update the status of the SMS server"""
|
|
|
+ status = session.query(ServerStatus).filter_by(id=1).first()
|
|
|
+
|
|
|
+ if not status:
|
|
|
+ status = ServerStatus(id=1)
|
|
|
+
|
|
|
+ status.host = request.client.host
|
|
|
+ status.user_agent = request.headers.get("user-agent", "unknown")
|
|
|
+ session.add(status)
|
|
|
+ session.commit()
|
|
|
+
|
|
|
+ return {"message": "Status updated successfully"}
|
|
|
+
|
|
|
+
|
|
|
+INACTIVITY_THRESHOLD_SECONDS = 180
|
|
|
+
|
|
|
+
|
|
|
+@router.get("/status", response_model=SMSServerStatus)
|
|
|
+async def get_status(
|
|
|
+ current_user: User = Depends(deps.get_current_user),
|
|
|
+ session: Session = Depends(deps.get_session),
|
|
|
+):
|
|
|
+ """Get the latest status of the SMS server"""
|
|
|
+ status: ServerStatus | None = session.query(ServerStatus).filter_by(id=1).first()
|
|
|
+ now = datetime.datetime.now()
|
|
|
+ if not status:
|
|
|
+ return SMSServerStatus(
|
|
|
+ updated_at=now, host="N/A", user_agent="N/A", message=EnumServerStatus.INVALID
|
|
|
+ )
|
|
|
+ else:
|
|
|
+ msg = (
|
|
|
+ EnumServerStatus.INACTIVE
|
|
|
+ if (now - status.updated_at).total_seconds()
|
|
|
+ > settings.INACTIVITY_SMS_SENDER_THRESHOLD_SECONDS
|
|
|
+ else EnumServerStatus.ACTIVE
|
|
|
+ )
|
|
|
+ return SMSServerStatus(
|
|
|
+ updated_at=status.updated_at,
|
|
|
+ host=status.host,
|
|
|
+ user_agent=status.user_agent,
|
|
|
+ message=msg,
|
|
|
+ )
|