feat: add avatars to members

This commit is contained in:
sam 2024-03-30 04:33:23 +01:00
parent 437c93463d
commit 66a5dfb433
Signed by: sam
GPG key ID: B4EF20DDE721CAA1
3 changed files with 60 additions and 3 deletions

View file

@ -2,6 +2,7 @@ from pydantic import Field
from quart import Blueprint, g
from quart_schema import validate_request, validate_response
from foxnouns import tasks
from foxnouns.auth import require_auth
from foxnouns.db import Member
from foxnouns.db.aio import async_session
@ -54,4 +55,7 @@ async def create_member(data: MemberCreateModel):
# we have to do it manually.
await member.awaitable_attrs.user
if data.avatar:
tasks.process_member_avatar.delay(member.id, data.avatar)
return FullMemberModel.model_validate(member)

View file

@ -18,6 +18,8 @@ class MemberPatchModel(BasePatchModel):
)
bio: str | None = Field(max_length=1024, default=None)
avatar: str | None = Field(max_length=1_000_000, default=None)
names: list[FieldEntry] = Field(default=[])
pronouns: list[PronounEntry] = Field(default=[])
fields: list[ProfileField] = Field(default=[])

View file

@ -8,7 +8,7 @@ from celery.utils.log import get_task_logger
from minio import Minio
from sqlalchemy import select, update
from foxnouns.db import User
from foxnouns.db import Member, User
from foxnouns.db.sync import session
from foxnouns.settings import MINIO, REDIS_URL
@ -44,7 +44,7 @@ def convert_avatar(uri: str) -> bytes:
@app.task
def process_user_avatar(user_id: int, avatar: str):
def process_user_avatar(user_id: int, avatar: str) -> None:
with session() as conn:
user = conn.scalar(select(User).where(User.id == user_id))
if not user:
@ -71,7 +71,7 @@ def process_user_avatar(user_id: int, avatar: str):
@app.task
def delete_user_avatar(user_id: int):
def delete_user_avatar(user_id: int) -> None:
with session() as conn:
user = conn.scalar(select(User).where(User.id == user_id))
if not user:
@ -87,3 +87,54 @@ def delete_user_avatar(user_id: int):
with session() as conn:
conn.execute(update(User).values(avatar=None).where(User.id == user_id))
conn.commit()
@app.task
def process_member_avatar(member_id: int, avatar: str) -> None:
with session() as conn:
member = conn.scalar(select(Member).where(Member.id == member_id))
if not member:
raise ValueError(
"process_member_avatar was passed the ID of a nonexistent member"
)
img = convert_avatar(avatar)
hash = hashlib.new("sha256", data=img).hexdigest()
old_hash = member.avatar
minio.put_object(
bucket,
f"members/{member_id}/avatars/{hash}.webp",
BytesIO(img),
len(img),
"image/webp",
)
with session() as conn:
conn.execute(update(Member).values(avatar=hash).where(Member.id == member_id))
conn.commit()
if old_hash:
minio.remove_object(bucket, f"members/{member_id}/avatars/{old_hash}.webp")
@app.task
def delete_member_avatar(member_id: int) -> None:
with session() as conn:
member = conn.scalar(select(Member).where(Member.id == member_id))
if not member:
raise ValueError(
"delete_member_avatar was passed the ID of a nonexistent member"
)
if not member.avatar:
logger.info(
"delete_member_avatar was called for a member with a null avatar (%d)",
member_id,
)
return
minio.remove_object(bucket, f"members/{member_id}/avatars/{member.avatar}.webp")
with session() as conn:
conn.execute(update(Member).values(avatar=None).where(Member.id == member_id))
conn.commit()