Working with avatars/

This commit is contained in:
2026-05-10 21:33:53 +02:00
parent 75236eb421
commit e340a8dc42
26 changed files with 745 additions and 456 deletions
+4 -1
View File
@@ -59,6 +59,9 @@ async def signup(request: Request):
)
uid = generate_uid()
avatar_style = form.get("avatar_style", "initials")
if avatar_style not in ("adventurer", "adventurer-neutral", "avataaars", "big-ears", "big-smile", "bottts", "croodles", "fun-emoji", "identicon", "initials", "lorelei", "micah", "miniavs", "notionists", "open-peeps", "personas", "pixel-art", "shapes", "thumbs"):
avatar_style = "initials"
users.insert({
"uid": uid,
"username": username,
@@ -68,7 +71,7 @@ async def signup(request: Request):
"location": "",
"git_link": "",
"website": "",
"avatar": "",
"avatar_style": avatar_style,
"role": "Member",
"level": 1,
"xp": 0,
+45
View File
@@ -0,0 +1,45 @@
import logging
import httpx
from fastapi import APIRouter, Request
from fastapi.responses import Response
from devplacepy.avatar import dicebear_proxy_url
logger = logging.getLogger(__name__)
router = APIRouter()
_cache = {}
def _initial_svg(seed: str) -> str:
initial = seed[:1].upper() if seed else "?"
return (
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">'
f'<rect width="100" height="100" rx="50" fill="#ff6b35"/>'
f'<text x="50" y="65" text-anchor="middle" fill="white" font-size="40" font-weight="700" font-family="sans-serif">{initial}</text></svg>'
)
@router.get("/{style}/{seed}")
async def avatar_proxy(request: Request, style: str, seed: str, size: int = 128):
cache_key = f"{style}:{seed}:{size}"
if cache_key in _cache:
return Response(content=_cache[cache_key], media_type="image/svg+xml")
if style == "initials" or not style:
svg = _initial_svg(seed)
_cache[cache_key] = svg
return Response(content=svg, media_type="image/svg+xml")
url = dicebear_proxy_url(style, seed, size)
try:
async with httpx.AsyncClient(timeout=3.0) as client:
resp = await client.get(url, follow_redirects=True)
content_type = resp.headers.get("content-type", "image/svg+xml")
body = resp.content
_cache[cache_key] = body
return Response(content=body, media_type=content_type)
except Exception as e:
logger.warning(f"Avatar proxy failed for {style}/{seed}: {e}")
svg = _initial_svg(seed)
_cache[cache_key] = svg
return Response(content=svg, media_type="image/svg+xml")
+13 -4
View File
@@ -61,10 +61,10 @@ async def view_post(request: Request, post_uid: str):
comments_table = get_table("comments")
raw_comments = list(comments_table.find(post_uid=post_uid, order_by=["created_at"]))
comments = []
comment_map = {}
for c in raw_comments:
commenter = users_table.find_one(uid=c["user_uid"])
comments.append({
comment_map[c["uid"]] = {
"comment": c,
"author": commenter,
"time_ago": time_ago(c["created_at"]),
@@ -72,13 +72,22 @@ async def view_post(request: Request, post_uid: str):
"up": len(list(get_table("votes").find(target_uid=c["uid"], value=1))),
"down": len(list(get_table("votes").find(target_uid=c["uid"], value=-1))),
},
})
"children": [],
}
top_level = []
for item in comment_map.values():
parent_uid = item["comment"].get("parent_uid")
if parent_uid and parent_uid in comment_map:
comment_map[parent_uid]["children"].append(item)
else:
top_level.append(item)
return templates.TemplateResponse("post.html", {
"request": request,
"user": user,
"post": post,
"author": author,
"comments": comments,
"comments": top_level,
"time_ago": time_ago(post["created_at"]),
})
+8 -2
View File
@@ -52,15 +52,21 @@ async def update_profile(request: Request):
location = form.get("location", "").strip()
git_link = form.get("git_link", "").strip()
website = form.get("website", "").strip()
avatar_style = form.get("avatar_style", "").strip()
users = get_table("users")
users.update({
update_data = {
"uid": user["uid"],
"bio": bio,
"location": location,
"git_link": git_link,
"website": website,
}, ["uid"])
}
valid_styles = ("adventurer", "adventurer-neutral", "avataaars", "big-ears", "big-smile", "bottts", "croodles", "fun-emoji", "identicon", "initials", "lorelei", "micah", "miniavs", "notionists", "open-peeps", "personas", "pixel-art", "shapes", "thumbs")
if avatar_style in valid_styles:
update_data["avatar_style"] = avatar_style
users.update(update_data, ["uid"])
logger.info(f"Profile updated for {user['username']}")
return RedirectResponse(url=f"/profile/{user['username']}", status_code=302)