|
from fastapi import FastAPI, Request, HTTPException, UploadFile, File, Form |
|
from pydantic import BaseModel |
|
import uuid |
|
from fastapi.responses import RedirectResponse |
|
from fastapi.middleware.cors import CORSMiddleware |
|
import os |
|
import requests |
|
from urllib.parse import urlencode |
|
import aiofiles |
|
|
|
app = FastAPI() |
|
deployments = {} |
|
|
|
|
|
GITHUB_CLIENT_ID = os.getenv("GITHUB_CLIENT_ID", "your_github_client_id") |
|
GITHUB_CLIENT_SECRET = os.getenv("GITHUB_CLIENT_SECRET", "your_github_client_secret") |
|
GITHUB_OAUTH_REDIRECT = os.getenv("GITHUB_OAUTH_REDIRECT", "http://localhost:7860/github/callback") |
|
|
|
|
|
user_tokens = {} |
|
|
|
|
|
user_selected_repo = {} |
|
|
|
|
|
env_files = {} |
|
|
|
app.add_middleware( |
|
CORSMiddleware, |
|
allow_origins=["*"], |
|
allow_credentials=True, |
|
allow_methods=["*"], |
|
allow_headers=["*"], |
|
) |
|
|
|
class DeployRequest(BaseModel): |
|
github_url: str |
|
user_id: str |
|
|
|
class RepoSelectRequest(BaseModel): |
|
user_id: str |
|
repo_full_name: str |
|
|
|
@app.post("/deploy") |
|
async def deploy(req: DeployRequest): |
|
|
|
deploy_id = str(uuid.uuid4()) |
|
deployments[deploy_id] = { |
|
"github_url": req.github_url, |
|
"user_id": req.user_id, |
|
"status": "deploying", |
|
"url": None |
|
} |
|
|
|
deployments[deploy_id]["status"] = "success" |
|
deployments[deploy_id]["url"] = f"https://demo-deployment/{deploy_id}" |
|
return {"deploy_id": deploy_id} |
|
|
|
@app.get("/status/{deploy_id}") |
|
async def status(deploy_id: str): |
|
if deploy_id in deployments: |
|
return deployments[deploy_id] |
|
return {"error": "Not found"} |
|
|
|
@app.get("/github/login") |
|
def github_login(user_id: str): |
|
params = { |
|
"client_id": GITHUB_CLIENT_ID, |
|
"redirect_uri": GITHUB_OAUTH_REDIRECT, |
|
"scope": "repo", |
|
"state": user_id |
|
} |
|
url = f"https://github.com/login/oauth/authorize?{urlencode(params)}" |
|
return {"auth_url": url} |
|
|
|
@app.get("/github/callback") |
|
def github_callback(code: str, state: str): |
|
|
|
token_url = "https://github.com/login/oauth/access_token" |
|
headers = {"Accept": "application/json"} |
|
data = { |
|
"client_id": GITHUB_CLIENT_ID, |
|
"client_secret": GITHUB_CLIENT_SECRET, |
|
"code": code, |
|
"redirect_uri": GITHUB_OAUTH_REDIRECT, |
|
"state": state |
|
} |
|
resp = requests.post(token_url, headers=headers, data=data) |
|
token = resp.json().get("access_token") |
|
if token: |
|
user_tokens[state] = token |
|
return RedirectResponse(url=f"https://t.me/your_bot_username?start=github_connected") |
|
return {"error": "Failed to get token"} |
|
|
|
@app.get("/github/repos") |
|
def github_repos(user_id: str): |
|
token = user_tokens.get(user_id) |
|
if not token: |
|
raise HTTPException(status_code=401, detail="User not authenticated with GitHub.") |
|
headers = {"Authorization": f"token {token}", "Accept": "application/vnd.github.v3+json"} |
|
resp = requests.get("https://api.github.com/user/repos", headers=headers) |
|
if resp.status_code != 200: |
|
raise HTTPException(status_code=resp.status_code, detail="Failed to fetch repos.") |
|
repos = resp.json() |
|
|
|
return [{"name": r["name"], "full_name": r["full_name"]} for r in repos] |
|
|
|
@app.post("/repo/select") |
|
def select_repo(req: RepoSelectRequest): |
|
user_selected_repo[req.user_id] = req.repo_full_name |
|
return {"message": "Repo selected", "repo_full_name": req.repo_full_name} |
|
|
|
@app.post("/env/upload") |
|
async def upload_env(user_id: str = Form(...), file: UploadFile = File(...)): |
|
content = await file.read() |
|
|
|
repo_full_name = user_selected_repo.get(user_id) |
|
if not repo_full_name: |
|
return {"error": "No repo selected for user."} |
|
env_files[(user_id, repo_full_name)] = content.decode() |
|
return {"message": ".env uploaded", "repo_full_name": repo_full_name} |