ozellik: google oauth, gmail-drive araclari ve admin durum kartlarini ekle

This commit is contained in:
2026-03-22 18:50:06 +03:00
parent 177fd8e1a7
commit ad847b1cf4
20 changed files with 970 additions and 14 deletions

View File

@@ -1,12 +1,27 @@
from fastapi import APIRouter, Depends
from pathlib import Path
from fastapi import APIRouter, Depends, Request
from fastapi.responses import HTMLResponse, RedirectResponse
from pydantic import BaseModel
from sqlalchemy.orm import Session
from app.admin.services import AdminService
from app.config import get_settings as get_app_settings
from app.db import SecretORM, get_session
from app.google.auth import GoogleAuthError, GoogleAuthManager
from app.llm.ollama_client import OllamaClient
from app.models import AutomationRecord, MemoryRecord, OllamaStatus, RuntimeSettings, TelegramStatus, UserProfileRecord, UserRecord
from app.models import (
AnythingLLMStatus,
AutomationRecord,
GoogleIntegrationStatus,
MemoryRecord,
OllamaStatus,
RuntimeSettings,
TelegramStatus,
UserProfileRecord,
UserRecord,
)
from app.tools.second_brain import SecondBrainTool
router = APIRouter(prefix="/admin", tags=["admin"])
@@ -16,10 +31,29 @@ class SecretPayload(BaseModel):
value: str
class GoogleClientPayload(BaseModel):
client_id: str
client_secret: str
def get_admin_service(session: Session = Depends(get_session)) -> AdminService:
return AdminService(session)
def get_google_auth_manager() -> GoogleAuthManager:
return GoogleAuthManager(get_app_settings(), Path(__file__).resolve().parents[2])
def sync_google_client_file(service: AdminService, manager: GoogleAuthManager) -> None:
settings = get_app_settings()
client_id_record = service.session.get(SecretORM, "google_client_id")
client_secret_record = service.session.get(SecretORM, "google_client_secret")
client_id = (client_id_record.value if client_id_record else settings.google_client_id).strip()
client_secret = (client_secret_record.value if client_secret_record else settings.google_client_secret).strip()
if client_id and client_secret:
manager.write_client_secrets_file(client_id, client_secret)
@router.get("/dashboard")
def get_dashboard(service: AdminService = Depends(get_admin_service)):
return service.dashboard()
@@ -77,6 +111,18 @@ def post_secret(payload: SecretPayload, service: AdminService = Depends(get_admi
return {"status": "ok"}
@router.post("/integrations/google/client")
def post_google_client(
payload: GoogleClientPayload,
service: AdminService = Depends(get_admin_service),
manager: GoogleAuthManager = Depends(get_google_auth_manager),
):
service.save_secret("google_client_id", payload.client_id.strip())
service.save_secret("google_client_secret", payload.client_secret.strip())
sync_google_client_file(service, manager)
return {"status": "ok"}
@router.get("/integrations/llm", response_model=OllamaStatus)
@router.get("/integrations/ollama", response_model=OllamaStatus)
async def get_llm_status(service: AdminService = Depends(get_admin_service)):
@@ -94,3 +140,116 @@ async def get_llm_status(service: AdminService = Depends(get_admin_service)):
@router.get("/integrations/telegram", response_model=TelegramStatus)
def get_telegram_status(service: AdminService = Depends(get_admin_service)):
return service.telegram_status()
@router.get("/integrations/anythingllm", response_model=AnythingLLMStatus)
async def get_anythingllm_status(service: AdminService = Depends(get_admin_service)):
runtime = service.get_runtime_settings()
settings = get_app_settings()
secret = service.session.get(SecretORM, "anythingllm_api_key")
tool = SecondBrainTool(
base_url=runtime.anythingllm_base_url,
workspace_slug=runtime.anythingllm_workspace_slug,
api_key=secret.value if secret else settings.anythingllm_api_key,
)
status = await tool.status()
return AnythingLLMStatus(
reachable=bool(status.get("reachable")),
workspace_found=bool(status.get("workspace_found")),
base_url=runtime.anythingllm_base_url,
workspace_slug=runtime.anythingllm_workspace_slug,
message=str(status.get("message", "")),
)
@router.get("/integrations/google", response_model=GoogleIntegrationStatus)
def get_google_status(
request: Request,
service: AdminService = Depends(get_admin_service),
manager: GoogleAuthManager = Depends(get_google_auth_manager),
):
sync_google_client_file(service, manager)
client_configured, connected, message = manager.oauth_status()
connect_url = str(request.url_for("google_oauth_connect"))
return GoogleIntegrationStatus(
client_configured=client_configured,
connected=connected,
connect_url=connect_url,
message=message,
)
@router.get("/integrations/google/connect", name="google_oauth_connect")
def google_oauth_connect(
request: Request,
service: AdminService = Depends(get_admin_service),
manager: GoogleAuthManager = Depends(get_google_auth_manager),
):
redirect_uri = str(request.url_for("google_oauth_callback"))
try:
sync_google_client_file(service, manager)
authorization_url = manager.begin_web_oauth(redirect_uri)
except GoogleAuthError as exc:
return HTMLResponse(
(
"<html><body style='font-family: sans-serif; padding: 24px;'>"
f"<h2>Google connect failed</h2><p>{exc}</p>"
"<p>Add your client_secret.json file, then try the connect button again.</p>"
"</body></html>"
),
status_code=400,
)
return RedirectResponse(url=authorization_url)
@router.get("/integrations/google/callback", response_class=HTMLResponse, name="google_oauth_callback")
def google_oauth_callback(
request: Request,
state: str | None = None,
error: str | None = None,
manager: GoogleAuthManager = Depends(get_google_auth_manager),
):
if error:
return HTMLResponse(
(
"<html><body style='font-family: sans-serif; padding: 24px;'>"
f"<h2>Google connect failed</h2><p>{error}</p>"
"<p>You can close this tab and try again from the WiseClaw admin panel.</p>"
"</body></html>"
),
status_code=400,
)
if not state:
return HTMLResponse(
(
"<html><body style='font-family: sans-serif; padding: 24px;'>"
"<h2>Google connect failed</h2><p>Missing OAuth state.</p>"
"<p>You can close this tab and try again from the WiseClaw admin panel.</p>"
"</body></html>"
),
status_code=400,
)
try:
manager.complete_web_oauth(str(request.url_for("google_oauth_callback")), state, str(request.url))
except Exception as exc:
return HTMLResponse(
(
"<html><body style='font-family: sans-serif; padding: 24px;'>"
f"<h2>Google connect failed</h2><p>{exc}</p>"
"<p>You can close this tab and try again from the WiseClaw admin panel.</p>"
"</body></html>"
),
status_code=400,
)
return HTMLResponse(
(
"<html><body style='font-family: sans-serif; padding: 24px;'>"
"<h2>Google account connected</h2>"
"<p>WiseClaw can now use your Gmail and Google Drive tools.</p>"
"<p>You can close this tab and refresh the admin panel.</p>"
"</body></html>"
)
)

View File

@@ -169,7 +169,11 @@ class AdminService:
def get_secret_mask(self, key: str) -> str:
record = self.session.get(SecretORM, key)
value = record.value if record else ""
if record is not None:
value = record.value
else:
settings = get_settings()
value = str(getattr(settings, key, "") or "")
if len(value) < 4:
return ""
return f"{value[:2]}***{value[-2:]}"