mirror of
https://github.com/rzmk/learnhouse.git
synced 2025-12-19 04:19:25 +00:00
feat: use OAuth for stripe connect
This commit is contained in:
parent
93c0838fab
commit
0449d6f87c
9 changed files with 266 additions and 50 deletions
|
|
@ -74,7 +74,9 @@ class RedisConfig(BaseModel):
|
|||
class InternalStripeConfig(BaseModel):
|
||||
stripe_secret_key: str | None
|
||||
stripe_publishable_key: str | None
|
||||
stripe_webhook_secret: str | None
|
||||
stripe_webhook_standard_secret: str | None
|
||||
stripe_webhook_connect_secret: str | None
|
||||
stripe_client_id: str | None
|
||||
|
||||
|
||||
class InternalPaymentsConfig(BaseModel):
|
||||
|
|
@ -275,7 +277,9 @@ def get_learnhouse_config() -> LearnHouseConfig:
|
|||
# Payments config
|
||||
env_stripe_secret_key = os.environ.get("LEARNHOUSE_STRIPE_SECRET_KEY")
|
||||
env_stripe_publishable_key = os.environ.get("LEARNHOUSE_STRIPE_PUBLISHABLE_KEY")
|
||||
env_stripe_webhook_secret = os.environ.get("LEARNHOUSE_STRIPE_WEBHOOK_SECRET")
|
||||
env_stripe_webhook_standard_secret = os.environ.get("LEARNHOUSE_STRIPE_WEBHOOK_STANDARD_SECRET")
|
||||
env_stripe_webhook_connect_secret = os.environ.get("LEARNHOUSE_STRIPE_WEBHOOK_CONNECT_SECRET")
|
||||
env_stripe_client_id = os.environ.get("LEARNHOUSE_STRIPE_CLIENT_ID")
|
||||
|
||||
stripe_secret_key = env_stripe_secret_key or yaml_config.get("payments_config", {}).get(
|
||||
"stripe", {}
|
||||
|
|
@ -285,9 +289,17 @@ def get_learnhouse_config() -> LearnHouseConfig:
|
|||
"stripe", {}
|
||||
).get("stripe_publishable_key")
|
||||
|
||||
stripe_webhook_secret = env_stripe_webhook_secret or yaml_config.get("payments_config", {}).get(
|
||||
stripe_webhook_standard_secret = env_stripe_webhook_standard_secret or yaml_config.get("payments_config", {}).get(
|
||||
"stripe", {}
|
||||
).get("stripe_webhook_secret")
|
||||
).get("stripe_webhook_standard_secret")
|
||||
|
||||
stripe_webhook_connect_secret = env_stripe_webhook_connect_secret or yaml_config.get("payments_config", {}).get(
|
||||
"stripe", {}
|
||||
).get("stripe_webhook_connect_secret")
|
||||
|
||||
stripe_client_id = env_stripe_client_id or yaml_config.get("payments_config", {}).get(
|
||||
"stripe", {}
|
||||
).get("stripe_client_id")
|
||||
|
||||
# Create HostingConfig and DatabaseConfig objects
|
||||
hosting_config = HostingConfig(
|
||||
|
|
@ -335,7 +347,9 @@ def get_learnhouse_config() -> LearnHouseConfig:
|
|||
stripe=InternalStripeConfig(
|
||||
stripe_secret_key=stripe_secret_key,
|
||||
stripe_publishable_key=stripe_publishable_key,
|
||||
stripe_webhook_secret=stripe_webhook_secret
|
||||
stripe_webhook_standard_secret=stripe_webhook_standard_secret,
|
||||
stripe_webhook_connect_secret=stripe_webhook_connect_secret,
|
||||
stripe_client_id=stripe_client_id
|
||||
)
|
||||
)
|
||||
)
|
||||
|
|
|
|||
|
|
@ -41,7 +41,8 @@ payments_config:
|
|||
stripe:
|
||||
stripe_secret_key: ""
|
||||
stripe_publishable_key: ""
|
||||
stripe_webhook_secret: ""
|
||||
stripe_webhook_standard_secret: ""
|
||||
stripe_client_id: ""
|
||||
|
||||
ai_config:
|
||||
chromadb_config:
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ from src.services.payments.payments_courses import (
|
|||
get_courses_by_product,
|
||||
)
|
||||
from src.services.payments.payments_users import get_owned_courses
|
||||
from src.services.payments.payments_stripe import create_checkout_session, update_stripe_account_id
|
||||
from src.services.payments.payments_stripe import create_checkout_session, handle_stripe_oauth_callback, update_stripe_account_id
|
||||
from src.services.payments.payments_access import check_course_paid_access
|
||||
from src.services.payments.payments_customers import get_customers
|
||||
from src.services.payments.payments_stripe import generate_stripe_connect_link
|
||||
|
|
@ -165,7 +165,14 @@ async def api_handle_connected_accounts_stripe_webhook(
|
|||
request: Request,
|
||||
db_session: Session = Depends(get_db_session),
|
||||
):
|
||||
return await handle_stripe_webhook(request, db_session)
|
||||
return await handle_stripe_webhook(request, "standard", db_session)
|
||||
|
||||
@router.post("/stripe/webhook/connect")
|
||||
async def api_handle_connected_accounts_stripe_webhook_connect(
|
||||
request: Request,
|
||||
db_session: Session = Depends(get_db_session),
|
||||
):
|
||||
return await handle_stripe_webhook(request, "connect", db_session)
|
||||
|
||||
# Payments checkout
|
||||
|
||||
|
|
@ -246,3 +253,13 @@ async def api_generate_stripe_connect_link(
|
|||
return await generate_stripe_connect_link(
|
||||
request, org_id, redirect_uri, current_user, db_session
|
||||
)
|
||||
|
||||
@router.get("/stripe/oauth/callback")
|
||||
async def stripe_oauth_callback(
|
||||
request: Request,
|
||||
code: str,
|
||||
org_id: int,
|
||||
current_user: PublicUser = Depends(get_current_user),
|
||||
db_session: Session = Depends(get_db_session),
|
||||
):
|
||||
return await handle_stripe_oauth_callback(request, org_id, code, current_user, db_session)
|
||||
|
|
@ -52,7 +52,8 @@ async def get_stripe_internal_credentials(
|
|||
return {
|
||||
"stripe_secret_key": learnhouse_config.payments_config.stripe.stripe_secret_key,
|
||||
"stripe_publishable_key": learnhouse_config.payments_config.stripe.stripe_publishable_key,
|
||||
"stripe_webhook_secret": learnhouse_config.payments_config.stripe.stripe_webhook_secret,
|
||||
"stripe_webhook_standard_secret": learnhouse_config.payments_config.stripe.stripe_webhook_standard_secret,
|
||||
"stripe_webhook_connect_secret": learnhouse_config.payments_config.stripe.stripe_webhook_connect_secret,
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -332,30 +333,20 @@ async def generate_stripe_connect_link(
|
|||
# Get credentials
|
||||
creds = await get_stripe_internal_credentials()
|
||||
stripe.api_key = creds.get("stripe_secret_key")
|
||||
|
||||
# Get learnhouse config for client_id
|
||||
learnhouse_config = get_learnhouse_config()
|
||||
client_id = learnhouse_config.payments_config.stripe.stripe_client_id
|
||||
|
||||
if not client_id:
|
||||
raise HTTPException(status_code=400, detail="Stripe client ID not configured")
|
||||
|
||||
try:
|
||||
# Try to get existing account ID
|
||||
stripe_acc_id = await get_stripe_connected_account_id(request, org_id, current_user, db_session)
|
||||
except HTTPException:
|
||||
# If no account exists, create one
|
||||
stripe_account = await create_stripe_account(
|
||||
request,
|
||||
org_id,
|
||||
"standard",
|
||||
current_user,
|
||||
db_session
|
||||
)
|
||||
stripe_acc_id = stripe_account
|
||||
state = f"org_id={org_id}"
|
||||
|
||||
# Generate OAuth link for existing accounts
|
||||
oauth_link = f"https://connect.stripe.com/oauth/authorize?response_type=code&client_id={client_id}&scope=read_write&redirect_uri={redirect_uri}&state={state}"
|
||||
|
||||
# Generate OAuth link
|
||||
connect_link = stripe.AccountLink.create(
|
||||
account=str(stripe_acc_id),
|
||||
type="account_onboarding",
|
||||
return_url=redirect_uri,
|
||||
refresh_url=redirect_uri,
|
||||
)
|
||||
|
||||
return {"connect_url": connect_link.url}
|
||||
return {"connect_url": oauth_link}
|
||||
|
||||
async def create_stripe_account(
|
||||
request: Request,
|
||||
|
|
@ -438,3 +429,45 @@ async def update_stripe_account_id(
|
|||
)
|
||||
|
||||
return {"message": "Stripe account ID updated successfully"}
|
||||
|
||||
async def handle_stripe_oauth_callback(
|
||||
request: Request,
|
||||
org_id: int,
|
||||
code: str,
|
||||
current_user: PublicUser | AnonymousUser | InternalUser,
|
||||
db_session: Session,
|
||||
):
|
||||
"""
|
||||
Handle the OAuth callback from Stripe and complete the account connection
|
||||
"""
|
||||
creds = await get_stripe_internal_credentials()
|
||||
stripe.api_key = creds.get("stripe_secret_key")
|
||||
|
||||
try:
|
||||
# Exchange the authorization code for an access token
|
||||
response = stripe.OAuth.token(
|
||||
grant_type='authorization_code',
|
||||
code=code,
|
||||
)
|
||||
|
||||
connected_account_id = response.stripe_user_id
|
||||
if not connected_account_id:
|
||||
raise HTTPException(status_code=400, detail="No account ID received from Stripe")
|
||||
|
||||
# Now connected_account_id is guaranteed to be a string
|
||||
await update_stripe_account_id(
|
||||
request,
|
||||
org_id,
|
||||
connected_account_id,
|
||||
current_user,
|
||||
db_session,
|
||||
)
|
||||
|
||||
return {"success": True, "account_id": connected_account_id}
|
||||
|
||||
except stripe.StripeError as e:
|
||||
logging.error(f"Error connecting Stripe account: {str(e)}")
|
||||
raise HTTPException(
|
||||
status_code=400,
|
||||
detail=f"Error connecting Stripe account: {str(e)}"
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
from typing import Literal
|
||||
from fastapi import HTTPException, Request
|
||||
from sqlmodel import Session, select
|
||||
import stripe
|
||||
|
|
@ -15,11 +16,12 @@ logger = logging.getLogger(__name__)
|
|||
|
||||
async def handle_stripe_webhook(
|
||||
request: Request,
|
||||
webhook_type: Literal["connect", "standard"],
|
||||
db_session: Session,
|
||||
) -> dict:
|
||||
# Get Stripe credentials
|
||||
creds = await get_stripe_internal_credentials()
|
||||
webhook_secret = creds.get('stripe_webhook_secret')
|
||||
webhook_secret = creds.get(f'stripe_webhook_{webhook_type}_secret')
|
||||
stripe.api_key = creds.get("stripe_secret_key")
|
||||
|
||||
if not webhook_secret:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue