feat: add avatars to members
This commit is contained in:
parent
437c93463d
commit
66a5dfb433
3 changed files with 60 additions and 3 deletions
|
@ -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)
|
||||
|
|
|
@ -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=[])
|
||||
|
|
|
@ -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()
|
||||
|
|
Loading…
Reference in a new issue