feat: endpoint for caddy
This commit is contained in:
parent
165385358f
commit
db20c498c2
|
|
@ -1,4 +1,4 @@
|
||||||
from fastapi import APIRouter, Depends, Security
|
from fastapi import APIRouter, Depends
|
||||||
from middleware.auth_dependency import auth_required
|
from middleware.auth_dependency import auth_required
|
||||||
from fastapi.security import HTTPBearer
|
from fastapi.security import HTTPBearer
|
||||||
|
|
||||||
|
|
@ -8,7 +8,7 @@ bearer_scheme = HTTPBearer(scheme_name="Bearer Authentication")
|
||||||
from .endpoints import clinics, doctors, calender, appointments, patients, admin, auth, s3, users, clinicDoctor, dashboard, call_transcripts, notifications,sns, stripe
|
from .endpoints import clinics, doctors, calender, appointments, patients, admin, auth, s3, users, clinicDoctor, dashboard, call_transcripts, notifications,sns, stripe
|
||||||
|
|
||||||
api_router = APIRouter()
|
api_router = APIRouter()
|
||||||
# api_router.include_router(twilio.router, prefix="/twilio")
|
|
||||||
api_router.include_router(clinics.router, prefix="/clinics", tags=["clinics"], dependencies=[Depends(auth_required)])
|
api_router.include_router(clinics.router, prefix="/clinics", tags=["clinics"], dependencies=[Depends(auth_required)])
|
||||||
|
|
||||||
api_router.include_router(doctors.router, prefix="/doctors", tags=["doctors"])
|
api_router.include_router(doctors.router, prefix="/doctors", tags=["doctors"])
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
from fastapi import APIRouter, BackgroundTasks
|
from fastapi import APIRouter, BackgroundTasks, Request, status
|
||||||
from services.authService import AuthService
|
from services.authService import AuthService
|
||||||
from schemas.CreateSchemas import UserCreate
|
from schemas.CreateSchemas import UserCreate
|
||||||
from schemas.ApiResponse import ApiResponse
|
from schemas.ApiResponse import ApiResponse
|
||||||
|
|
@ -59,3 +59,9 @@ async def verify_otp(data: AuthOTP):
|
||||||
data="OK",
|
data="OK",
|
||||||
message="OTP verified successfully"
|
message="OTP verified successfully"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@router.get("/is-valid-domain")
|
||||||
|
async def is_valid_domain(req:Request):
|
||||||
|
host = req.headers.get("host")
|
||||||
|
is_valid = await ClinicServices().is_valid_domain(host)
|
||||||
|
return status.HTTP_200_OK if is_valid else status.HTTP_404_NOT_FOUND
|
||||||
|
|
|
||||||
|
|
@ -11,19 +11,19 @@ stripe_service = StripeServices()
|
||||||
# async def create_checkout_session(user_id: int):
|
# async def create_checkout_session(user_id: int):
|
||||||
# return await stripe_service.create_checkout_session(1)
|
# return await stripe_service.create_checkout_session(1)
|
||||||
|
|
||||||
# @router.post("/create-subscription-checkout")
|
@router.post("/create-subscription-checkout")
|
||||||
# async def create_subscription_checkout():
|
async def create_subscription_checkout():
|
||||||
# return await stripe_service.create_subscription_checkout(
|
return await stripe_service.create_subscription_checkout(
|
||||||
# fees_to_be={
|
fees_to_be={
|
||||||
# "per_call_charges": 10,
|
"per_call_charges": 10,
|
||||||
# "setup_fees": 100,
|
"setup_fees": 100,
|
||||||
# "subscription_fees": 100,
|
"subscription_fees": 100,
|
||||||
# "total": 210
|
"total": 210
|
||||||
# },
|
},
|
||||||
# clinic_id=1,
|
clinic_id=1,
|
||||||
# account_id="acct_1RT1UFPTNqn2kWQ8",
|
account_id="acct_1RT1UFPTNqn2kWQ8",
|
||||||
# customer_id="cus_SNn49FDltUcSLP"
|
customer_id="cus_SNn49FDltUcSLP"
|
||||||
# )
|
)
|
||||||
|
|
||||||
@router.get("/create-stripe-account-link", dependencies=[Depends(auth_required)])
|
@router.get("/create-stripe-account-link", dependencies=[Depends(auth_required)])
|
||||||
async def create_stripe_account_link(req:Request):
|
async def create_stripe_account_link(req:Request):
|
||||||
|
|
|
||||||
|
|
@ -1,183 +0,0 @@
|
||||||
# import asyncio
|
|
||||||
# import json
|
|
||||||
# import logging
|
|
||||||
# import os
|
|
||||||
# from fastapi import APIRouter, Request, WebSocket, status
|
|
||||||
# from twilio.twiml.voice_response import VoiceResponse, Connect
|
|
||||||
# from twilio.rest import Client
|
|
||||||
# from fastapi import WebSocket, Request, Response
|
|
||||||
# from enum import Enum
|
|
||||||
# from typing import Optional
|
|
||||||
|
|
||||||
# from services.bot import run_bot
|
|
||||||
# from services.call_state import CallState
|
|
||||||
|
|
||||||
# logger = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
|
|
||||||
# router = APIRouter()
|
|
||||||
|
|
||||||
# BASE_WS_URL = "wss://13.229.247.61:8000/api/twilio"
|
|
||||||
# BASE_URL = "http://13.229.247.61:8000/api/twilio"
|
|
||||||
|
|
||||||
# DTMF_SWITCH_KEY = "*" # Key to switch between models
|
|
||||||
|
|
||||||
# LOG_EVENT_TYPES = [
|
|
||||||
# "error",
|
|
||||||
# "response.content.done",
|
|
||||||
# "rate_limits.updated",
|
|
||||||
# "response.done",
|
|
||||||
# "input_audio_buffer.committed",
|
|
||||||
# "input_audio_buffer.speech_stopped",
|
|
||||||
# "input_audio_buffer.speech_started",
|
|
||||||
# "session.created",
|
|
||||||
# ]
|
|
||||||
|
|
||||||
# SHOW_TIMING_MATH = False
|
|
||||||
|
|
||||||
# MENU_OPTIONS = """
|
|
||||||
# Press 1 for Model 1.
|
|
||||||
# Press 2 for Model 2.
|
|
||||||
# Press 3 for Model 3.
|
|
||||||
# Press 4 for Model 4.
|
|
||||||
# Press 5 for Model 5.
|
|
||||||
# Press 0 to repeat the options.
|
|
||||||
# """
|
|
||||||
|
|
||||||
# call_state = CallState
|
|
||||||
|
|
||||||
|
|
||||||
# # Define model options as enum for type safety
|
|
||||||
# class ModelOption(int, Enum):
|
|
||||||
# MODEL_1 = 1
|
|
||||||
# MODEL_2 = 2
|
|
||||||
# MODEL_3 = 3
|
|
||||||
# MODEL_4 = 4
|
|
||||||
# MODEL_5 = 5
|
|
||||||
|
|
||||||
|
|
||||||
# @router.post("/call")
|
|
||||||
# async def get_call():
|
|
||||||
|
|
||||||
# SID = os.getenv("TWILIO_SID")
|
|
||||||
# AUTH_TOKEN = os.getenv("TWILIO_AUTH")
|
|
||||||
|
|
||||||
# client = Client(SID, AUTH_TOKEN)
|
|
||||||
|
|
||||||
# call = client.calls.create(
|
|
||||||
# from_="+14149466486",
|
|
||||||
# to="+917984372159",
|
|
||||||
# record=True,
|
|
||||||
# url=f"{BASE_URL}/receive",
|
|
||||||
# )
|
|
||||||
|
|
||||||
# return status.HTTP_200_OK
|
|
||||||
|
|
||||||
|
|
||||||
# # @router.websocket("/media-stream/{id}")
|
|
||||||
# # async def handle_media_stream(websocket: WebSocket, id: int):
|
|
||||||
# # """Handle WebSocket connections between Twilio and OpenAI."""
|
|
||||||
# # print(f"Client connected with id: {id}")
|
|
||||||
# # await websocket.accept()
|
|
||||||
# # start_data = websocket.iter_text()
|
|
||||||
# # await start_data.__anext__()
|
|
||||||
# # call_data = json.loads(await start_data.__anext__())
|
|
||||||
# # print(call_data, flush=True)
|
|
||||||
# # stream_sid = call_data["start"]["streamSid"]
|
|
||||||
# # print("WebSocket connection accepted")
|
|
||||||
# # await run_bot(websocket, stream_sid, False, option=id)
|
|
||||||
|
|
||||||
|
|
||||||
# @router.websocket("/media-stream/{id}")
|
|
||||||
# async def handle_media_stream(websocket: WebSocket, id: int):
|
|
||||||
# """Handle WebSocket connections between Twilio and OpenAI."""
|
|
||||||
# logger.info(f"Client connected with id: {id}")
|
|
||||||
# print(f"Client connected with id: {id}")
|
|
||||||
# await websocket.accept()
|
|
||||||
# start_data = websocket.iter_text()
|
|
||||||
# await start_data.__anext__()
|
|
||||||
# call_data = json.loads(await start_data.__anext__())
|
|
||||||
# print(call_data, flush=True)
|
|
||||||
# logger.info(call_data)
|
|
||||||
# stream_sid = call_data["start"]["streamSid"]
|
|
||||||
# print("WebSocket connection accepted")
|
|
||||||
# logger.info("WebSocket connection accepted")
|
|
||||||
# await run_bot(websocket, stream_sid, False, option=id)
|
|
||||||
|
|
||||||
|
|
||||||
# # @router.post("/receive")
|
|
||||||
# # async def receive_call(req: Request):
|
|
||||||
# # print("----------------- received call -----------------")
|
|
||||||
|
|
||||||
# # resp = VoiceResponse()
|
|
||||||
# # connect = Connect()
|
|
||||||
# # connect.stream(
|
|
||||||
# # url=f"wss://allegedly-known-wasp.ngrok-free.app/api/twilio/media-stream"
|
|
||||||
# # )
|
|
||||||
# # resp.append(connect)
|
|
||||||
# # return Response(content=str(resp), media_type="application/xml")
|
|
||||||
|
|
||||||
|
|
||||||
# @router.post("/receive")
|
|
||||||
# async def receive_call(req: Request):
|
|
||||||
# print("----------------- received call -----------------")
|
|
||||||
# resp = VoiceResponse()
|
|
||||||
|
|
||||||
# # Gather DTMF input
|
|
||||||
# gather = resp.gather(
|
|
||||||
# num_digits=1, action="/api/twilio/handle-key", method="POST", timeout=10
|
|
||||||
# )
|
|
||||||
|
|
||||||
# # Initial greeting and menu options
|
|
||||||
# gather.say(MENU_OPTIONS)
|
|
||||||
|
|
||||||
# # If no input received, redirect back to the main menu
|
|
||||||
# resp.redirect("/api/twilio/receive")
|
|
||||||
|
|
||||||
# return Response(content=str(resp), media_type="application/xml")
|
|
||||||
|
|
||||||
|
|
||||||
# @router.post("/handle-key")
|
|
||||||
# async def handle_key_press(req: Request):
|
|
||||||
# """Process the key pressed by the caller and connect to the appropriate model."""
|
|
||||||
# try:
|
|
||||||
# form_data = await req.form()
|
|
||||||
# digits_pressed = form_data.get("Digits", "")
|
|
||||||
# print(f"User pressed: {digits_pressed}")
|
|
||||||
|
|
||||||
# resp = VoiceResponse()
|
|
||||||
|
|
||||||
# if digits_pressed == "0":
|
|
||||||
# # Repeat options
|
|
||||||
# resp.redirect("/api/twilio/receive")
|
|
||||||
# elif digits_pressed in "12345":
|
|
||||||
# # Valid model selection
|
|
||||||
# model_id = int(digits_pressed)
|
|
||||||
# resp.say(f"You have selected model {model_id}.")
|
|
||||||
|
|
||||||
# # Connect to WebSocket
|
|
||||||
# connect = Connect()
|
|
||||||
# connect.stream(url=f"{BASE_WS_URL}/media-stream/{model_id}")
|
|
||||||
# resp.append(connect)
|
|
||||||
# else:
|
|
||||||
# # Invalid selection
|
|
||||||
# resp.say("Invalid selection. Please try again.")
|
|
||||||
# resp.redirect("/api/twilio/receive")
|
|
||||||
|
|
||||||
# return Response(content=str(resp), media_type="application/xml")
|
|
||||||
|
|
||||||
# except Exception as e:
|
|
||||||
# print(f"Error handling key press: {str(e)}")
|
|
||||||
# resp = VoiceResponse()
|
|
||||||
# resp.say(
|
|
||||||
# "We encountered a problem processing your request. Please try again later."
|
|
||||||
# )
|
|
||||||
# return Response(content=str(resp), media_type="application/xml")
|
|
||||||
|
|
||||||
|
|
||||||
# @router.post("/error")
|
|
||||||
# async def read_item(req: Request):
|
|
||||||
# print(await req.body())
|
|
||||||
# print(await req.form())
|
|
||||||
# logger.error(await req.body())
|
|
||||||
# return status.HTTP_200_OK
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
from database import get_db
|
from database import get_db
|
||||||
from sqlalchemy.orm import Session, joinedload
|
from sqlalchemy.orm import Session, joinedload
|
||||||
from schemas.UpdateSchemas import ClinicStatusUpdate, ClinicUpdate
|
from schemas.UpdateSchemas import ClinicUpdate
|
||||||
from schemas.ResponseSchemas import Clinic, ClinicOfferResponse
|
from schemas.ResponseSchemas import Clinic, ClinicOfferResponse
|
||||||
from typing import List, Literal, Optional, Union
|
from typing import Literal, Optional, Union
|
||||||
from exceptions import ResourceNotFoundException, ValidationException
|
from exceptions import ResourceNotFoundException, ValidationException
|
||||||
from enums.enums import ClinicStatus, UserType
|
from enums.enums import ClinicStatus, UserType
|
||||||
from exceptions.unauthorized_exception import UnauthorizedException
|
from exceptions.unauthorized_exception import UnauthorizedException
|
||||||
|
|
@ -18,6 +18,7 @@ from loguru import logger
|
||||||
from sqlalchemy import func
|
from sqlalchemy import func
|
||||||
|
|
||||||
from exceptions.db_exceptions import DBExceptionHandler
|
from exceptions.db_exceptions import DBExceptionHandler
|
||||||
|
|
||||||
class ClinicServices:
|
class ClinicServices:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.db: Session = next(get_db())
|
self.db: Session = next(get_db())
|
||||||
|
|
@ -424,3 +425,18 @@ class ClinicServices:
|
||||||
DBExceptionHandler.handle_exception(e, context="deleting clinic offer")
|
DBExceptionHandler.handle_exception(e, context="deleting clinic offer")
|
||||||
finally:
|
finally:
|
||||||
self.db.close()
|
self.db.close()
|
||||||
|
|
||||||
|
async def is_valid_domain(self, domain:str):
|
||||||
|
|
||||||
|
subdomain = domain.split(".")[0]
|
||||||
|
|
||||||
|
# allow main domain, backend and admin domains
|
||||||
|
if(subdomain in ["toBeDomain", "backend", "admin"]):
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
# check if any clinic has domain
|
||||||
|
clinic_domain = self.db.query(Clinic).filter(Clinic.domain == subdomain).first()
|
||||||
|
if clinic_domain:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
|
||||||
|
|
@ -193,6 +193,7 @@ class StripeServices:
|
||||||
finally:
|
finally:
|
||||||
self.db.close()
|
self.db.close()
|
||||||
|
|
||||||
|
# NOTE: in case when checkout session expired or not created
|
||||||
async def create_payment_session(self, user):
|
async def create_payment_session(self, user):
|
||||||
try:
|
try:
|
||||||
if user["userType"] != UserType.CLINIC_ADMIN:
|
if user["userType"] != UserType.CLINIC_ADMIN:
|
||||||
|
|
@ -252,46 +253,34 @@ class StripeServices:
|
||||||
finally:
|
finally:
|
||||||
self.db.close()
|
self.db.close()
|
||||||
|
|
||||||
async def create_checkout_session(self, user_id: int):
|
# NOTE: This is not used
|
||||||
try:
|
# async def create_checkout_session(self, user_id: int):
|
||||||
checkout_session = await stripe.checkout.Session.create_async(
|
# try:
|
||||||
payment_method_types=["card"],
|
# checkout_session = await stripe.checkout.Session.create_async(
|
||||||
line_items=[
|
# payment_method_types=["card"],
|
||||||
{
|
# line_items=[
|
||||||
"price_data": {
|
# {
|
||||||
"currency": "aud",
|
# "price_data": {
|
||||||
"product_data": {
|
# "currency": "aud",
|
||||||
"name": "Willio Voice Subscription",
|
# "product_data": {
|
||||||
},
|
# "name": "Willio Voice Subscription",
|
||||||
"unit_amount": 5000,
|
# },
|
||||||
},
|
# "unit_amount": 5000,
|
||||||
"quantity": 1,
|
# },
|
||||||
}
|
# "quantity": 1,
|
||||||
],
|
# }
|
||||||
expand=["payment_intent"],
|
# ],
|
||||||
mode="payment",
|
# expand=["payment_intent"],
|
||||||
payment_intent_data={"metadata": {"order_id": "1"}},
|
# mode="payment",
|
||||||
success_url=f"{self.redirect_url}auth/waiting",
|
# payment_intent_data={"metadata": {"order_id": "1"}},
|
||||||
cancel_url=f"{self.redirect_url}auth/waiting",
|
# success_url=f"{self.redirect_url}auth/waiting",
|
||||||
metadata={"user_id": user_id},
|
# cancel_url=f"{self.redirect_url}auth/waiting",
|
||||||
)
|
# metadata={"user_id": user_id},
|
||||||
return checkout_session
|
# )
|
||||||
except stripe.error.StripeError as e:
|
# return checkout_session
|
||||||
self.logger.error(f"Error creating checkout session: {e}")
|
# except stripe.error.StripeError as e:
|
||||||
raise
|
# self.logger.error(f"Error creating checkout session: {e}")
|
||||||
|
# raise
|
||||||
async def create_setup_fees(self, customer_id: str, amount: int):
|
|
||||||
try:
|
|
||||||
setup_intent = await stripe.InvoiceItem.create_async(
|
|
||||||
customer=customer_id,
|
|
||||||
amount=amount,
|
|
||||||
currency="aud",
|
|
||||||
description="Setup Fees",
|
|
||||||
)
|
|
||||||
return setup_intent
|
|
||||||
except stripe.error.StripeError as e:
|
|
||||||
self.logger.error(f"Error creating setup intent: {e}")
|
|
||||||
raise
|
|
||||||
|
|
||||||
async def create_subscription_checkout(
|
async def create_subscription_checkout(
|
||||||
self, fees_to_be: dict, clinic_id: int, account_id: str, customer_id: str
|
self, fees_to_be: dict, clinic_id: int, account_id: str, customer_id: str
|
||||||
|
|
@ -313,6 +302,7 @@ class StripeServices:
|
||||||
), # Convert to cents
|
), # Convert to cents
|
||||||
"recurring": {
|
"recurring": {
|
||||||
"interval": "year",
|
"interval": "year",
|
||||||
|
"interval_count": 3, #NOTE: max 3 years supported by stripe
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"quantity": 1,
|
"quantity": 1,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue