197:@router.post("/accounts/import-config") 198-async def import_client_config(file: UploadFile = File(...), 199- user: User = Depends(get_current_user_csrf), 200- db: AsyncSession = Depends(get_db), request: Request = None): 201- """Import & validate a Google OAuth client_secret JSON (never echoed back).""" 202- from app.core.config import settings 203- content = await file.read() 204- if len(content) > 1024 * 512: 205- raise HTTPException(413, "File too large (max 512 KB)") 206- if not file.filename.lower().endswith(".json"): 207- raise HTTPException(400, "Only .json configuration files are accepted") 208- try: 209- parsed = gmail_service.parse_client_json(content) 210- except gmail_service.GmailOauthError as e: 211- raise HTTPException(400, str(e)) 212- row = OAuthClientConfig( 213- name=parsed["project_id"] or file.filename[:100], 214- user_id=user.id, 215- client_id=parsed["client_id"], 216- client_secret=parsed["client_secret"], # encrypted via property setter 217- project_id=parsed["project_id"], 218- redirect_uri=f"{settings.BASE_URL}/auth/google/callback", 219- ) 220- db.add(row) 221- await db.commit() 222- await log_audit(db, user.id, "oauth_config.imported", "oauth_client_config", row.id, 223- {"project": parsed["project_id"]}, request.client.host if request else None) 224- return {"ok": True, "id": row.id, "project_id": parsed["project_id"], 225- "client_id_preview": parsed["client_id"][:12] + "…", 226- "redirect_uri": row.redirect_uri} 227- 228- 229-@router.patch("/accounts/{account_id}") 230-async def update_account(account_id: int, payload: AccountUpdate, 231- user: User = Depends(get_current_user_csrf), 232- db: AsyncSession = Depends(get_db)): 233- account = await db.get(GmailAccount, account_id) 234- if not account or account.user_id != user.id: 235- raise HTTPException(404, "Account not found") 236- if payload.sending_method in ("api", "smtp"): 237- account.sending_method = payload.sending_method 238- account.daily_limit = max(1, payload.daily_limit) 239- account.campaign_limit = max(1, payload.campaign_limit) 240- await db.commit() 241- return _account_out(account)