fix(channel): enforce read-only for members and polish chat info
Some checks failed
CI / test (push) Failing after 26s
Some checks failed
CI / test (push) Failing after 26s
- block send/forward in channels for member role on backend - expose my_role in chat payload for client-side permissions - hide message composer for channel members and show read-only notice - hide members management sections for private/saved chats in info panel - return enriched chat detail via serialize_chat_for_user
This commit is contained in:
@@ -96,13 +96,12 @@ async def get_chat(
|
||||
current_user: User = Depends(get_current_user),
|
||||
) -> ChatDetailRead:
|
||||
chat, members = await get_chat_for_user(db, chat_id=chat_id, user_id=current_user.id)
|
||||
return ChatDetailRead(
|
||||
id=chat.id,
|
||||
type=chat.type,
|
||||
title=chat.title,
|
||||
pinned_message_id=chat.pinned_message_id,
|
||||
created_at=chat.created_at,
|
||||
members=members,
|
||||
base = await serialize_chat_for_user(db, user_id=current_user.id, chat=chat)
|
||||
return ChatDetailRead.model_validate(
|
||||
{
|
||||
**base.model_dump(),
|
||||
"members": members,
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@ class ChatRead(BaseModel):
|
||||
counterpart_username: str | None = None
|
||||
counterpart_is_online: bool | None = None
|
||||
counterpart_last_seen_at: datetime | None = None
|
||||
my_role: ChatMemberRole | None = None
|
||||
created_at: datetime
|
||||
|
||||
|
||||
|
||||
@@ -18,6 +18,10 @@ from app.users.repository import get_user_by_id
|
||||
|
||||
async def serialize_chat_for_user(db: AsyncSession, *, user_id: int, chat: Chat) -> ChatRead:
|
||||
display_title = chat.title
|
||||
my_role = None
|
||||
membership = await repository.get_chat_member(db, chat_id=chat.id, user_id=user_id)
|
||||
if membership:
|
||||
my_role = membership.role
|
||||
members_count: int | None = None
|
||||
online_count: int | None = None
|
||||
subscribers_count: int | None = None
|
||||
@@ -70,6 +74,7 @@ async def serialize_chat_for_user(db: AsyncSession, *, user_id: int, chat: Chat)
|
||||
"counterpart_username": counterpart_username,
|
||||
"counterpart_is_online": counterpart_is_online,
|
||||
"counterpart_last_seen_at": counterpart_last_seen_at,
|
||||
"my_role": my_role,
|
||||
"created_at": chat.created_at,
|
||||
}
|
||||
)
|
||||
|
||||
@@ -14,6 +14,14 @@ from app.notifications.service import dispatch_message_notifications
|
||||
|
||||
async def create_chat_message(db: AsyncSession, *, sender_id: int, payload: MessageCreateRequest) -> Message:
|
||||
await ensure_chat_membership(db, chat_id=payload.chat_id, user_id=sender_id)
|
||||
chat = await chats_repository.get_chat_by_id(db, payload.chat_id)
|
||||
if not chat:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Chat not found")
|
||||
membership = await chats_repository.get_chat_member(db, chat_id=payload.chat_id, user_id=sender_id)
|
||||
if not membership:
|
||||
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="You are not a member of this chat")
|
||||
if chat.type == ChatType.CHANNEL and membership.role == ChatMemberRole.MEMBER:
|
||||
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="Only admins can post in channels")
|
||||
if payload.reply_to_message_id is not None:
|
||||
reply_to = await repository.get_message_by_id(db, payload.reply_to_message_id)
|
||||
if not reply_to or reply_to.chat_id != payload.chat_id:
|
||||
@@ -229,6 +237,14 @@ async def forward_message(
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Source message not found")
|
||||
await ensure_chat_membership(db, chat_id=source.chat_id, user_id=sender_id)
|
||||
await ensure_chat_membership(db, chat_id=payload.target_chat_id, user_id=sender_id)
|
||||
target_chat = await chats_repository.get_chat_by_id(db, payload.target_chat_id)
|
||||
if not target_chat:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Chat not found")
|
||||
target_membership = await chats_repository.get_chat_member(db, chat_id=payload.target_chat_id, user_id=sender_id)
|
||||
if not target_membership:
|
||||
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="You are not a member of this chat")
|
||||
if target_chat.type == ChatType.CHANNEL and target_membership.role == ChatMemberRole.MEMBER:
|
||||
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="Only admins can post in channels")
|
||||
forwarded = await repository.create_message(
|
||||
db,
|
||||
chat_id=payload.target_chat_id,
|
||||
|
||||
Reference in New Issue
Block a user