Spaces:
Running
Running
eheguy commited on
Commit ·
21614c2
1
Parent(s): f019835
Update to Razorpay Orders checkout
Browse files
main.py
CHANGED
|
@@ -15,7 +15,7 @@ if not os.getenv("GROQ_API_KEY") and os.getenv("HF_TOKEN"):
|
|
| 15 |
os.environ["GROQ_API_KEY"] = os.getenv("HF_TOKEN")
|
| 16 |
|
| 17 |
from humanizer import humanize_text
|
| 18 |
-
from usage import check_usage_limit, increment_usage, get_user_profile,
|
| 19 |
|
| 20 |
from fastapi.middleware.cors import CORSMiddleware
|
| 21 |
from fastapi import Request
|
|
@@ -74,7 +74,14 @@ class HumanizeResponse(BaseModel):
|
|
| 74 |
purpose: str
|
| 75 |
usage: dict # { count, limit, plan }
|
| 76 |
|
| 77 |
-
class
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 78 |
user_id: str
|
| 79 |
plan: str
|
| 80 |
|
|
@@ -136,72 +143,57 @@ async def get_user_plan(user_id: str):
|
|
| 136 |
raise HTTPException(status_code=404, detail="User not found")
|
| 137 |
return {"plan": profile.get("plan", "free")}
|
| 138 |
|
| 139 |
-
@app.post("/create-
|
| 140 |
-
async def
|
|
|
|
|
|
|
| 141 |
if request.plan not in ["starter", "pro"]:
|
| 142 |
raise HTTPException(status_code=400, detail="Invalid plan")
|
| 143 |
|
| 144 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 145 |
|
| 146 |
try:
|
| 147 |
-
|
| 148 |
-
"
|
| 149 |
-
"
|
| 150 |
-
"
|
| 151 |
-
|
| 152 |
-
|
| 153 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 154 |
}
|
| 155 |
-
subscription = razorpay_client.subscription.create(subscription_data)
|
| 156 |
-
return {"subscription_id": subscription["id"], "key_id": RAZORPAY_KEY_ID}
|
| 157 |
except Exception as e:
|
| 158 |
raise HTTPException(status_code=500, detail=str(e))
|
| 159 |
|
| 160 |
-
@app.post("/
|
| 161 |
-
async def
|
| 162 |
-
|
| 163 |
-
|
| 164 |
-
|
| 165 |
-
if not RAZORPAY_WEBHOOK_SECRET:
|
| 166 |
-
raise HTTPException(status_code=500, detail="Webhook secret not configured")
|
| 167 |
-
|
| 168 |
-
expected_signature = hmac.new(
|
| 169 |
-
key=RAZORPAY_WEBHOOK_SECRET.encode('utf-8'),
|
| 170 |
-
msg=payload,
|
| 171 |
-
digestmod='sha256'
|
| 172 |
-
).hexdigest()
|
| 173 |
-
|
| 174 |
-
if not hmac.compare_digest(expected_signature, signature):
|
| 175 |
-
raise HTTPException(status_code=400, detail="Invalid signature")
|
| 176 |
|
| 177 |
try:
|
| 178 |
-
|
| 179 |
-
|
|
|
|
|
|
|
|
|
|
| 180 |
|
| 181 |
-
if
|
| 182 |
-
|
| 183 |
-
|
| 184 |
-
|
| 185 |
-
|
|
|
|
| 186 |
|
| 187 |
-
plan_name = "free"
|
| 188 |
-
if plan_id == RAZORPAY_STARTER_PLAN_ID:
|
| 189 |
-
plan_name = "starter"
|
| 190 |
-
elif plan_id == RAZORPAY_PRO_PLAN_ID:
|
| 191 |
-
plan_name = "pro"
|
| 192 |
-
|
| 193 |
-
if user_id and plan_name != "free":
|
| 194 |
-
profile = get_user_profile(user_id)
|
| 195 |
-
if profile and profile.get("plan") != plan_name:
|
| 196 |
-
update_user_subscription(user_id, plan_name, subscription_id)
|
| 197 |
-
|
| 198 |
-
elif event in ["subscription.cancelled", "subscription.halted"]:
|
| 199 |
-
sub_entity = data.get("payload", {}).get("subscription", {}).get("entity", {})
|
| 200 |
-
user_id = sub_entity.get("notes", {}).get("user_id")
|
| 201 |
-
if user_id:
|
| 202 |
-
cancel_user_subscription(user_id)
|
| 203 |
-
|
| 204 |
return {"status": "ok"}
|
|
|
|
|
|
|
| 205 |
except Exception as e:
|
| 206 |
raise HTTPException(status_code=500, detail=str(e))
|
| 207 |
|
|
|
|
| 15 |
os.environ["GROQ_API_KEY"] = os.getenv("HF_TOKEN")
|
| 16 |
|
| 17 |
from humanizer import humanize_text
|
| 18 |
+
from usage import check_usage_limit, increment_usage, get_user_profile, upgrade_user_plan, cancel_user_subscription
|
| 19 |
|
| 20 |
from fastapi.middleware.cors import CORSMiddleware
|
| 21 |
from fastapi import Request
|
|
|
|
| 74 |
purpose: str
|
| 75 |
usage: dict # { count, limit, plan }
|
| 76 |
|
| 77 |
+
class CreateOrderRequest(BaseModel):
|
| 78 |
+
user_id: str
|
| 79 |
+
plan: str
|
| 80 |
+
|
| 81 |
+
class VerifyPaymentRequest(BaseModel):
|
| 82 |
+
razorpay_order_id: str
|
| 83 |
+
razorpay_payment_id: str
|
| 84 |
+
razorpay_signature: str
|
| 85 |
user_id: str
|
| 86 |
plan: str
|
| 87 |
|
|
|
|
| 143 |
raise HTTPException(status_code=404, detail="User not found")
|
| 144 |
return {"plan": profile.get("plan", "free")}
|
| 145 |
|
| 146 |
+
@app.post("/api/create-order")
|
| 147 |
+
async def create_order(request: CreateOrderRequest):
|
| 148 |
+
if not request.user_id:
|
| 149 |
+
raise HTTPException(status_code=401, detail="Unauthorized")
|
| 150 |
if request.plan not in ["starter", "pro"]:
|
| 151 |
raise HTTPException(status_code=400, detail="Invalid plan")
|
| 152 |
|
| 153 |
+
# Map plans to amounts (e.g. Starter = $9 = ₹750 = 75000 paise)
|
| 154 |
+
amount = 75000 if request.plan == "starter" else 150000
|
| 155 |
+
|
| 156 |
+
if amount < 100:
|
| 157 |
+
raise HTTPException(status_code=400, detail="Amount must be at least 100 paise")
|
| 158 |
|
| 159 |
try:
|
| 160 |
+
order_data = {
|
| 161 |
+
"amount": amount,
|
| 162 |
+
"currency": "INR",
|
| 163 |
+
"receipt": request.user_id
|
| 164 |
+
}
|
| 165 |
+
order = razorpay_client.order.create(order_data)
|
| 166 |
+
return {
|
| 167 |
+
"order_id": order["id"],
|
| 168 |
+
"amount": amount,
|
| 169 |
+
"currency": "INR",
|
| 170 |
+
"key_id": RAZORPAY_KEY_ID
|
| 171 |
}
|
|
|
|
|
|
|
| 172 |
except Exception as e:
|
| 173 |
raise HTTPException(status_code=500, detail=str(e))
|
| 174 |
|
| 175 |
+
@app.post("/api/verify-payment")
|
| 176 |
+
async def verify_payment(request: VerifyPaymentRequest):
|
| 177 |
+
if not request.razorpay_order_id or not request.razorpay_payment_id or not request.razorpay_signature:
|
| 178 |
+
raise HTTPException(status_code=400, detail="Missing required fields")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 179 |
|
| 180 |
try:
|
| 181 |
+
expected_signature = hmac.new(
|
| 182 |
+
key=RAZORPAY_KEY_SECRET.encode('utf-8'),
|
| 183 |
+
msg=(request.razorpay_order_id + "|" + request.razorpay_payment_id).encode('utf-8'),
|
| 184 |
+
digestmod='sha256'
|
| 185 |
+
).hexdigest()
|
| 186 |
|
| 187 |
+
if not hmac.compare_digest(expected_signature, request.razorpay_signature):
|
| 188 |
+
raise HTTPException(status_code=400, detail="Invalid signature")
|
| 189 |
+
|
| 190 |
+
profile = get_user_profile(request.user_id)
|
| 191 |
+
if profile and profile.get("plan") != request.plan:
|
| 192 |
+
upgrade_user_plan(request.user_id, request.plan)
|
| 193 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 194 |
return {"status": "ok"}
|
| 195 |
+
except HTTPException:
|
| 196 |
+
raise
|
| 197 |
except Exception as e:
|
| 198 |
raise HTTPException(status_code=500, detail=str(e))
|
| 199 |
|
usage.py
CHANGED
|
@@ -54,12 +54,11 @@ def increment_usage(user_id: str) -> None:
|
|
| 54 |
{"humanization_count": new_count}
|
| 55 |
).eq("id", user_id).execute()
|
| 56 |
|
| 57 |
-
def
|
| 58 |
-
"""Update user plan and reset usage."""
|
| 59 |
client = get_supabase()
|
| 60 |
client.table("profiles").update({
|
| 61 |
"plan": plan,
|
| 62 |
-
"razorpay_subscription_id": subscription_id,
|
| 63 |
"humanization_count": 0
|
| 64 |
}).eq("id", user_id).execute()
|
| 65 |
|
|
|
|
| 54 |
{"humanization_count": new_count}
|
| 55 |
).eq("id", user_id).execute()
|
| 56 |
|
| 57 |
+
def upgrade_user_plan(user_id: str, plan: str) -> None:
|
| 58 |
+
"""Update user plan for a one-time order and reset usage."""
|
| 59 |
client = get_supabase()
|
| 60 |
client.table("profiles").update({
|
| 61 |
"plan": plan,
|
|
|
|
| 62 |
"humanization_count": 0
|
| 63 |
}).eq("id", user_id).execute()
|
| 64 |
|