v2.8.0 WIP: create/upload files + commit history + labels sync
- POST /api/gitea/projects/{owner}/{repo}/upload (binary upload)
- get_file_commits() in GiteaClient
- GET /api/gitea/projects/{owner}/{repo}/commits (per-file history)
- POST .../sync-labels (Gitea labels → FlowDeck tags)
- New file form + upload button in gitea_workspace.html topbar
This commit is contained in:
@@ -106,6 +106,31 @@ async def save_file(request: Request, owner: str, repo: str):
|
||||
return JSONResponse({"error": str(e)}, status_code=502)
|
||||
|
||||
|
||||
# ── Upload file (binary) ──
|
||||
@router.post("/projects/{owner}/{repo}/upload")
|
||||
async def upload_file(request: Request, owner: str, repo: str):
|
||||
"""Upload a binary file to the repo."""
|
||||
import base64
|
||||
gitea = _require_gitea(request)
|
||||
try:
|
||||
form = await request.form()
|
||||
except Exception:
|
||||
return JSONResponse({"error": "Invalid form data"}, status_code=400)
|
||||
file = form.get("file")
|
||||
folder = form.get("folder", "")
|
||||
message = form.get("message", "Upload via FlowDeck")
|
||||
if not file:
|
||||
return JSONResponse({"error": "No file provided"}, status_code=400)
|
||||
try:
|
||||
content = await file.read()
|
||||
encoded = base64.b64encode(content).decode("utf-8")
|
||||
path = f"{folder.strip('/')}/{file.filename}".strip("/") if folder.strip("/") else file.filename
|
||||
result = await gitea.create_or_update_file(owner, repo, path, encoded, message, sha=None)
|
||||
return {"status": "ok", "path": path, "commit": result.get("commit", {})}
|
||||
except Exception as e:
|
||||
return JSONResponse({"error": str(e)}, status_code=502)
|
||||
|
||||
|
||||
# ── Delete file ──
|
||||
@router.delete("/projects/{owner}/{repo}/file")
|
||||
async def delete_file(request: Request, owner: str, repo: str):
|
||||
@@ -266,3 +291,48 @@ async def delete_private_page(owner: str, repo: str, page_id: int, request: Requ
|
||||
)
|
||||
conn.commit()
|
||||
return {"status": "ok"}
|
||||
|
||||
|
||||
# ── Commit history for a file ──
|
||||
@router.get("/projects/{owner}/{repo}/commits")
|
||||
async def file_commits(request: Request, owner: str, repo: str, path: str = ""):
|
||||
"""Get recent commits for a specific file."""
|
||||
gitea = _require_gitea(request)
|
||||
try:
|
||||
commits = await gitea.get_file_commits(owner, repo, path)
|
||||
return {"commits": commits}
|
||||
except Exception as e:
|
||||
return JSONResponse({"error": str(e)}, status_code=502)
|
||||
|
||||
|
||||
# ── Sync labels to tags ──
|
||||
@router.post("/projects/{owner}/{repo}/sync-labels")
|
||||
async def sync_labels(request: Request, owner: str, repo: str):
|
||||
"""Sync Gitea labels to FlowDeck tags for the current user."""
|
||||
from app.auth.session import get_current_user as gcu
|
||||
from app.db import get_conn
|
||||
user = await gcu(request)
|
||||
if not user:
|
||||
return JSONResponse({"error": "Not authenticated"}, status_code=401)
|
||||
gitea = _require_gitea(request)
|
||||
try:
|
||||
labels = await gitea.get_labels(owner, repo)
|
||||
except Exception:
|
||||
labels = []
|
||||
imported = 0
|
||||
with get_conn() as conn:
|
||||
for label in labels:
|
||||
name = label.get("name", "")
|
||||
color = label.get("color", "#787774")
|
||||
if not name: continue
|
||||
existing = conn.execute(
|
||||
"SELECT id FROM tags WHERE name=? AND user_id=?", (name, user["id"])
|
||||
).fetchone()
|
||||
if not existing:
|
||||
conn.execute(
|
||||
"INSERT INTO tags (name, color, user_id) VALUES (?, ?, ?)",
|
||||
(name, f"#{color}", user["id"]),
|
||||
)
|
||||
imported += 1
|
||||
conn.commit()
|
||||
return {"status": "ok", "imported": imported, "total": len(labels)}
|
||||
|
||||
Reference in New Issue
Block a user