Update app.py
Browse files
app.py
CHANGED
@@ -1,14 +1,46 @@
|
|
1 |
-
from fastapi import FastAPI, Request
|
2 |
from pydantic import BaseModel
|
3 |
import uuid
|
|
|
|
|
|
|
|
|
|
|
|
|
4 |
|
5 |
app = FastAPI()
|
6 |
deployments = {}
|
7 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
8 |
class DeployRequest(BaseModel):
|
9 |
github_url: str
|
10 |
user_id: str
|
11 |
|
|
|
|
|
|
|
|
|
12 |
@app.post("/deploy")
|
13 |
async def deploy(req: DeployRequest):
|
14 |
# Simulate deployment
|
@@ -28,4 +60,62 @@ async def deploy(req: DeployRequest):
|
|
28 |
async def status(deploy_id: str):
|
29 |
if deploy_id in deployments:
|
30 |
return deployments[deploy_id]
|
31 |
-
return {"error": "Not found"}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from fastapi import FastAPI, Request, HTTPException, UploadFile, File, Form
|
2 |
from pydantic import BaseModel
|
3 |
import uuid
|
4 |
+
from fastapi.responses import RedirectResponse
|
5 |
+
from fastapi.middleware.cors import CORSMiddleware
|
6 |
+
import os
|
7 |
+
import requests
|
8 |
+
from urllib.parse import urlencode
|
9 |
+
import aiofiles
|
10 |
|
11 |
app = FastAPI()
|
12 |
deployments = {}
|
13 |
|
14 |
+
# GitHub OAuth config (replace with your own client_id and client_secret)
|
15 |
+
GITHUB_CLIENT_ID = os.getenv("GITHUB_CLIENT_ID", "your_github_client_id")
|
16 |
+
GITHUB_CLIENT_SECRET = os.getenv("GITHUB_CLIENT_SECRET", "your_github_client_secret")
|
17 |
+
GITHUB_OAUTH_REDIRECT = os.getenv("GITHUB_OAUTH_REDIRECT", "http://localhost:7860/github/callback")
|
18 |
+
|
19 |
+
# In-memory user token storage (for demo; use DB in production)
|
20 |
+
user_tokens = {}
|
21 |
+
|
22 |
+
# In-memory user selected repo storage (for demo)
|
23 |
+
user_selected_repo = {}
|
24 |
+
|
25 |
+
# In-memory .env storage: {(user_id, repo_full_name): env_content}
|
26 |
+
env_files = {}
|
27 |
+
|
28 |
+
app.add_middleware(
|
29 |
+
CORSMiddleware,
|
30 |
+
allow_origins=["*"],
|
31 |
+
allow_credentials=True,
|
32 |
+
allow_methods=["*"],
|
33 |
+
allow_headers=["*"],
|
34 |
+
)
|
35 |
+
|
36 |
class DeployRequest(BaseModel):
|
37 |
github_url: str
|
38 |
user_id: str
|
39 |
|
40 |
+
class RepoSelectRequest(BaseModel):
|
41 |
+
user_id: str
|
42 |
+
repo_full_name: str
|
43 |
+
|
44 |
@app.post("/deploy")
|
45 |
async def deploy(req: DeployRequest):
|
46 |
# Simulate deployment
|
|
|
60 |
async def status(deploy_id: str):
|
61 |
if deploy_id in deployments:
|
62 |
return deployments[deploy_id]
|
63 |
+
return {"error": "Not found"}
|
64 |
+
|
65 |
+
@app.get("/github/login")
|
66 |
+
def github_login(user_id: str):
|
67 |
+
params = {
|
68 |
+
"client_id": GITHUB_CLIENT_ID,
|
69 |
+
"redirect_uri": GITHUB_OAUTH_REDIRECT,
|
70 |
+
"scope": "repo",
|
71 |
+
"state": user_id
|
72 |
+
}
|
73 |
+
url = f"https://github.com/login/oauth/authorize?{urlencode(params)}"
|
74 |
+
return {"auth_url": url}
|
75 |
+
|
76 |
+
@app.get("/github/callback")
|
77 |
+
def github_callback(code: str, state: str):
|
78 |
+
# state is user_id
|
79 |
+
token_url = "https://github.com/login/oauth/access_token"
|
80 |
+
headers = {"Accept": "application/json"}
|
81 |
+
data = {
|
82 |
+
"client_id": GITHUB_CLIENT_ID,
|
83 |
+
"client_secret": GITHUB_CLIENT_SECRET,
|
84 |
+
"code": code,
|
85 |
+
"redirect_uri": GITHUB_OAUTH_REDIRECT,
|
86 |
+
"state": state
|
87 |
+
}
|
88 |
+
resp = requests.post(token_url, headers=headers, data=data)
|
89 |
+
token = resp.json().get("access_token")
|
90 |
+
if token:
|
91 |
+
user_tokens[state] = token
|
92 |
+
return RedirectResponse(url=f"https://t.me/your_bot_username?start=github_connected")
|
93 |
+
return {"error": "Failed to get token"}
|
94 |
+
|
95 |
+
@app.get("/github/repos")
|
96 |
+
def github_repos(user_id: str):
|
97 |
+
token = user_tokens.get(user_id)
|
98 |
+
if not token:
|
99 |
+
raise HTTPException(status_code=401, detail="User not authenticated with GitHub.")
|
100 |
+
headers = {"Authorization": f"token {token}", "Accept": "application/vnd.github.v3+json"}
|
101 |
+
resp = requests.get("https://api.github.com/user/repos", headers=headers)
|
102 |
+
if resp.status_code != 200:
|
103 |
+
raise HTTPException(status_code=resp.status_code, detail="Failed to fetch repos.")
|
104 |
+
repos = resp.json()
|
105 |
+
# Return only repo name and full_name for selection
|
106 |
+
return [{"name": r["name"], "full_name": r["full_name"]} for r in repos]
|
107 |
+
|
108 |
+
@app.post("/repo/select")
|
109 |
+
def select_repo(req: RepoSelectRequest):
|
110 |
+
user_selected_repo[req.user_id] = req.repo_full_name
|
111 |
+
return {"message": "Repo selected", "repo_full_name": req.repo_full_name}
|
112 |
+
|
113 |
+
@app.post("/env/upload")
|
114 |
+
async def upload_env(user_id: str = Form(...), file: UploadFile = File(...)):
|
115 |
+
content = await file.read()
|
116 |
+
# Find selected repo for user
|
117 |
+
repo_full_name = user_selected_repo.get(user_id)
|
118 |
+
if not repo_full_name:
|
119 |
+
return {"error": "No repo selected for user."}
|
120 |
+
env_files[(user_id, repo_full_name)] = content.decode()
|
121 |
+
return {"message": ".env uploaded", "repo_full_name": repo_full_name}
|