chats: add chat avatars and profile view-only modal
All checks were successful
CI / test (push) Successful in 23s

This commit is contained in:
2026-03-08 13:53:29 +03:00
parent f7413bc626
commit bc9d943d11
10 changed files with 236 additions and 114 deletions

View File

@@ -15,6 +15,7 @@ from app.chats.schemas import (
ChatNotificationSettingsUpdate,
ChatInviteLinkRead,
ChatPinMessageRequest,
ChatProfileUpdateRequest,
ChatRead,
ChatTitleUpdateRequest,
)
@@ -40,6 +41,16 @@ async def _can_view_last_seen(*, db: AsyncSession, target_user, viewer_user_id:
return await is_user_in_contacts(db, owner_user_id=target_user.id, candidate_user_id=viewer_user_id)
async def _can_view_avatar(*, db: AsyncSession, target_user, viewer_user_id: int) -> bool:
if target_user.id == viewer_user_id:
return True
if target_user.privacy_avatar == "everyone":
return True
if target_user.privacy_avatar == "nobody":
return False
return await is_user_in_contacts(db, owner_user_id=target_user.id, candidate_user_id=viewer_user_id)
async def _can_invite_to_group(*, db: AsyncSession, target_user, actor_user_id: int) -> bool:
if target_user.id == actor_user_id:
return False
@@ -66,6 +77,7 @@ async def serialize_chat_for_user(
counterpart_user_id: int | None = None
counterpart_name: str | None = None
counterpart_username: str | None = None
counterpart_avatar_url: str | None = None
counterpart_is_online: bool | None = None
counterpart_last_seen_at = None
if chat.is_saved:
@@ -81,6 +93,8 @@ async def serialize_chat_for_user(
counterpart_username = counterpart.username
presence_allowed = await _can_view_last_seen(db=db, target_user=counterpart, viewer_user_id=user_id)
counterpart_last_seen_at = counterpart.last_seen_at if presence_allowed else None
avatar_allowed = await _can_view_avatar(db=db, target_user=counterpart, viewer_user_id=user_id)
counterpart_avatar_url = counterpart.avatar_url if avatar_allowed else None
presence = await get_users_online_map([counterpart_id])
if counterpart:
presence_allowed = await _can_view_last_seen(db=db, target_user=counterpart, viewer_user_id=user_id)
@@ -114,6 +128,7 @@ async def serialize_chat_for_user(
"public_id": chat.public_id,
"type": chat.type,
"title": chat.title,
"avatar_url": chat.avatar_url,
"display_title": display_title,
"handle": chat.handle,
"description": chat.description,
@@ -130,6 +145,7 @@ async def serialize_chat_for_user(
"counterpart_user_id": counterpart_user_id,
"counterpart_name": counterpart_name,
"counterpart_username": counterpart_username,
"counterpart_avatar_url": counterpart_avatar_url,
"counterpart_is_online": counterpart_is_online,
"counterpart_last_seen_at": counterpart_last_seen_at,
"last_message_text": last_message.text if last_message else None,
@@ -300,6 +316,29 @@ async def update_chat_title_for_user(
return chat
async def update_chat_profile_for_user(
db: AsyncSession,
*,
chat_id: int,
user_id: int,
payload: ChatProfileUpdateRequest,
) -> Chat:
chat, membership = await _get_chat_and_membership(db, chat_id=chat_id, user_id=user_id)
_ensure_group_or_channel(chat.type)
_ensure_manage_permission(membership.role)
if payload.title is not None:
chat.title = payload.title.strip() or chat.title
if payload.description is not None:
chat.description = payload.description.strip() or None
if payload.avatar_url is not None:
chat.avatar_url = payload.avatar_url.strip() or None
await db.commit()
await db.refresh(chat)
return chat
async def add_chat_member_for_user(
db: AsyncSession,
*,
@@ -454,6 +493,7 @@ async def discover_public_chats_for_user(db: AsyncSession, *, user_id: int, quer
"public_id": chat.public_id,
"type": chat.type,
"title": chat.title,
"avatar_url": chat.avatar_url,
"handle": chat.handle,
"description": chat.description,
"is_public": chat.is_public,