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…
	
	Add table
		Add a link
		
	
		Reference in a new issue