Corin1998 commited on
Commit
105ee76
·
verified ·
1 Parent(s): 10288f0

Update app/main.py

Browse files
Files changed (1) hide show
  1. app/main.py +1 -107
app/main.py CHANGED
@@ -29,7 +29,7 @@ Base.metadata.create_all(bind=engine)
29
  # FastAPI app
30
  app = FastAPI(title="GrowthOps OS", version="0.1.0")
31
 
32
- # CORS (tighten as needed)
33
  app.add_middleware(
34
  CORSMiddleware,
35
  allow_origins=["*"],
@@ -38,10 +38,7 @@ app.add_middleware(
38
  allow_headers=["*"],
39
  )
40
 
41
- # Prometheus counter
42
  API_CALLS = Counter("growthops_api_calls", "Total API calls", ["path", "method", "status"])
43
-
44
- # Jinja templates for /admin
45
  templates = Jinja2Templates(directory="templates")
46
 
47
  class AuditMiddleware(BaseHTTPMiddleware):
@@ -171,106 +168,3 @@ def create_plan(p: PlanCreate, current: User = Depends(require_tenant_admin), db
171
  @app.post("/subscriptions", response_model=SimpleMessage)
172
  def create_subscription(s: SubscriptionCreate, current: User = Depends(require_tenant_admin), db: Session = Depends(get_db)):
173
  sub = Subscription(tenant_id=s.tenant_id, plan_id=s.plan_id, active=True)
174
- db.add(sub)
175
- db.commit()
176
- return {"message": "ok"}
177
-
178
- # ------------------ Marketplace-like Apps ------------------
179
- @app.post("/apps", response_model=SimpleMessage)
180
- def register_app(a: AppCreate, current: User = Depends(require_tenant_admin), db: Session = Depends(get_db)):
181
- appm = App(name=a.name, description=a.description, callback_url=a.callback_url)
182
- db.add(appm)
183
- db.commit()
184
- return {"message": "ok"}
185
-
186
- @app.post("/apps/{app_id}/install", response_model=SimpleMessage)
187
- def install_app(app_id: int, req: InstallAppRequest, current: User = Depends(require_tenant_admin), db: Session = Depends(get_db)):
188
- inst = InstalledApp(tenant_id=req.tenant_id, app_id=app_id)
189
- db.add(inst)
190
- db.commit()
191
- return {"message": "installed"}
192
-
193
- @app.post("/apps/{app_id}/sso", response_model=TokenOut)
194
- def issue_sso_token(app_id: int, req: SSORequest, current: User = Depends(get_current_user), db: Session = Depends(get_db)):
195
- token = create_access_token(sub=f"user:{req.user_id}:tenant:{req.tenant_id}", expires_in=req.expires_in)
196
- return {"access_token": token, "token_type": "bearer"}
197
-
198
- # ------------------ Jobs (Celery) ------------------
199
- @app.post("/jobs/pptx", response_model=SimpleMessage)
200
- def job_pptx(body: JobCreateRequest, current: User = Depends(get_current_user)):
201
- res = generate_pptx.delay(title=body.payload.get("title", "GrowthOps Report"), items=body.payload.get("items", []))
202
- return {"message": "queued", "data": {"task_id": res.id}}
203
-
204
- @app.post("/jobs/docx", response_model=SimpleMessage)
205
- def job_docx(body: JobCreateRequest, current: User = Depends(get_current_user)):
206
- res = generate_docx.delay(title=body.payload.get("title", "GrowthOps Summary"), body=body.payload.get("body", "Hello"))
207
- return {"message": "queued", "data": {"task_id": res.id}}
208
-
209
- @app.get("/jobs/{task_id}", response_model=SimpleMessage)
210
- def job_status(task_id: str):
211
- asyncres = celery_app.AsyncResult(task_id)
212
- data = {"state": asyncres.state}
213
- if asyncres.successful():
214
- data["result"] = asyncres.result
215
- return {"message": "ok", "data": data}
216
-
217
- # ------------------ Files ------------------
218
- @app.get("/files/{filename}")
219
- def download_file(filename: str):
220
- path = f"/data/exports/{filename}"
221
- if not os.path.exists(path):
222
- raise HTTPException(404, "not found")
223
- return FileResponse(path, filename=filename)
224
-
225
- # ------------------ Audit / Errors ------------------
226
- @app.get("/audit", response_model=list[dict])
227
- def list_audit(current: User = Depends(require_tenant_admin), db: Session = Depends(get_db)):
228
- rows = db.query(AuditLog).order_by(AuditLog.id.desc()).limit(200).all()
229
- return [{
230
- "id": r.id, "path": r.path, "method": r.method, "status_code": r.status_code, "created_at": r.created_at.isoformat()
231
- } for r in rows]
232
-
233
- @app.get("/errors", response_model=list[dict])
234
- def list_errors(current: User = Depends(require_tenant_admin), db: Session = Depends(get_db)):
235
- rows = db.query(ErrorLog).order_by(ErrorLog.id.desc()).limit(200).all()
236
- return [{
237
- "id": r.id, "path": r.path, "error": r.error, "created_at": r.created_at.isoformat()
238
- } for r in rows]
239
-
240
- # ------------------ Admin UI (Jinja + HTMX) ------------------
241
- @app.get("/", response_class=HTMLResponse)
242
- def root():
243
- return HTMLResponse("<meta http-equiv='refresh' content='0; url=/admin'/>")
244
-
245
- @app.get("/admin", response_class=HTMLResponse)
246
- def admin_home(request: Request, db: Session = Depends(get_db)):
247
- tenants = db.query(Tenant).all()
248
- users = db.query(User).order_by(User.id.desc()).limit(20).all()
249
- audits = db.query(AuditLog).order_by(AuditLog.id.desc()).limit(10).all()
250
- return templates.TemplateResponse("admin/home.html", {"request": request, "tenants": tenants, "users": users, "audits": audits})
251
-
252
- # HTMX fragment: tenants table (GET for initial refresh, POST to create)
253
- @app.get("/admin/tenants", response_class=HTMLResponse)
254
- def admin_tenants_fragment(request: Request, db: Session = Depends(get_db)):
255
- tenants = db.query(Tenant).all()
256
- return templates.TemplateResponse("admin/tenants_fragment.html", {"request": request, "tenants": tenants})
257
-
258
- @app.post("/admin/tenants", response_class=HTMLResponse)
259
- def admin_create_tenant_fragment(
260
- request: Request,
261
- name: str = Form(...),
262
- current: User = Depends(require_tenant_admin),
263
- db: Session = Depends(get_db),
264
- ):
265
- if db.query(Tenant).filter(Tenant.name == name).first():
266
- raise HTTPException(400, "Tenant exists")
267
- tenant = Tenant(name=name)
268
- db.add(tenant)
269
- db.commit()
270
- tenants = db.query(Tenant).all()
271
- return templates.TemplateResponse("admin/tenants_fragment.html", {"request": request, "tenants": tenants})
272
-
273
- # Entrypoint for HF
274
- if __name__ == "__main__":
275
- import uvicorn, os
276
- uvicorn.run("app.main:app", host="0.0.0.0", port=int(os.getenv("PORT", "7860")), reload=False)
 
29
  # FastAPI app
30
  app = FastAPI(title="GrowthOps OS", version="0.1.0")
31
 
32
+ # CORS
33
  app.add_middleware(
34
  CORSMiddleware,
35
  allow_origins=["*"],
 
38
  allow_headers=["*"],
39
  )
40
 
 
41
  API_CALLS = Counter("growthops_api_calls", "Total API calls", ["path", "method", "status"])
 
 
42
  templates = Jinja2Templates(directory="templates")
43
 
44
  class AuditMiddleware(BaseHTTPMiddleware):
 
168
  @app.post("/subscriptions", response_model=SimpleMessage)
169
  def create_subscription(s: SubscriptionCreate, current: User = Depends(require_tenant_admin), db: Session = Depends(get_db)):
170
  sub = Subscription(tenant_id=s.tenant_id, plan_id=s.plan_id, active=True)