Commit 4103e88
Changed files (2)
src
database
src/database/github.py
@@ -11,8 +11,9 @@ from glom import glom
from httpx import AsyncClient
from loguru import logger
-from config import DB, PROXY, cache
+from config import DB, PROXY, TOKEN, TZ, cache
from networking import download_file, hx_req
+from utils import nowdt
async def list_assets(
@@ -343,3 +344,69 @@ async def gh_clean_assets(
num_del = len(files) - keep_latest
logger.success(f"Deleted {num_del} assets from {gh_user}/{gh_repo}, Release: {release_name}, Tag: {tag_name}")
return num_del
+
+
+async def list_gists(gh_token: str = TOKEN.GITHUB) -> list[dict]:
+ """List gists from user on GitHub."""
+ if not gh_token:
+ return []
+ headers = {"Accept": "application/vnd.github+json", "Authorization": f"Bearer {gh_token}", "X-GitHub-Api-Version": "2026-03-10"}
+ params = {"page": 1, "per_page": 100}
+ gists = []
+ resp = await hx_req("https://api.github.com/gists", headers=headers, params=params, proxy=PROXY.GITHUB)
+ if not isinstance(resp, list):
+ return []
+ gists.extend(resp)
+ while len(resp) == params["per_page"]:
+ params["page"] += 1
+ resp = await hx_req("https://api.github.com/gists", headers=headers, params=params, proxy=PROXY.GITHUB)
+ if not isinstance(resp, list):
+ return gists
+ gists.extend(resp)
+ return gists
+
+
+async def create_gist(content: str, filename: str, gh_token: str = TOKEN.GITHUB) -> str:
+ """Create a gist on GitHub."""
+ if not all([content, filename, gh_token]):
+ return ""
+ headers = {"Accept": "application/vnd.github+json", "Authorization": f"Bearer {gh_token}", "X-GitHub-Api-Version": "2026-03-10"}
+ today = nowdt(TZ).strftime("%Y-%m-%d")
+ gists = await list_gists(gh_token)
+ gist_id = next((x["id"] for x in gists if f"bennybot-{today}" == x["description"]), None)
+ if not gist_id:
+ # Create new gist
+ resp = await hx_req(
+ "https://api.github.com/gists",
+ "POST",
+ json_data={
+ "public": False,
+ "description": f"bennybot-{today}",
+ "files": {filename: {"content": content}},
+ },
+ check_keys=["id"],
+ headers=headers,
+ proxy=PROXY.GITHUB,
+ )
+ if "id" in resp:
+ return f"https://gists.github.com/{resp['id']}#file-{filename.replace('.', '-')}"
+ return ""
+
+ # update existing gist
+ gist = await hx_req(f"https://api.github.com/gists/{gist_id}", headers=headers, check_kv={"id": gist_id}, proxy=PROXY.GITHUB)
+ if "files" not in gist:
+ return ""
+
+ files = {k: {"content": v["content"]} for k, v in gist["files"].items()}
+ files[filename] = {"content": content}
+ resp = await hx_req(
+ f"https://api.github.com/gists/{gist_id}",
+ "PATCH",
+ json_data={"description": gist["description"], "files": files},
+ check_kv={"id": gist_id},
+ headers=headers,
+ proxy=PROXY.GITHUB,
+ )
+ if "id" in resp:
+ return f"https://gists.github.com/{gist_id}#file-{filename.replace('.', '-')}"
+ return ""
src/networking.py
@@ -34,7 +34,7 @@ async def log_resp(response: Response) -> None:
async def hx_req(
url,
- method: str = "GET",
+ method: Literal["GET", "POST", "PUT", "DELETE", "PATCH"] = "GET",
*,
transport: AsyncCurlTransport | AsyncHTTPTransport | None = None,
headers: dict | None = None,
@@ -104,7 +104,7 @@ async def hx_req(
event_hooks={"request": [log_req], "response": [log_resp]},
)
- if method not in ["GET", "POST", "PUT", "DELETE"]:
+ if method not in ["GET", "POST", "PUT", "DELETE", "PATCH"]:
error = f"Invalid method: {method}"
logger.error(error)
return {"hx_error": error}
@@ -116,6 +116,8 @@ async def hx_req(
response = await client.post(url, cookies=cookies, headers=headers, data=data, json=json_data, files=files, content=content_data, params=params)
elif method == "PUT":
response = await client.put(url, cookies=cookies, headers=headers, data=data, json=json_data, content=content_data, files=files, params=params)
+ elif method == "PATCH":
+ response = await client.patch(url, cookies=cookies, headers=headers, data=data, json=json_data, content=content_data, files=files, params=params)
else:
response = await client.delete(url, cookies=cookies, headers=headers, params=params)
response.raise_for_status()