Private
Public Access
Post a welcome message when an admin adds someone to a room (#72)
Attributed to the admin doing the adding rather than a new system/bot sender concept, since every message today requires a real user_id and the admin is already a real, in-scope user for the request. Broadcasts room_added before the welcome message itself, so the new member's client learns the room exists before it sees an unread update for it. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -39,8 +39,9 @@ from app.schemas.webhook import (
|
|||||||
WebhookIncomingRead,
|
WebhookIncomingRead,
|
||||||
)
|
)
|
||||||
from app.services.link_preview_service import get_link_previews_for_urls
|
from app.services.link_preview_service import get_link_previews_for_urls
|
||||||
from app.services.message_events import broadcast_room_added
|
from app.services.message_events import broadcast_new_message, broadcast_room_added
|
||||||
from app.services.message_service import (
|
from app.services.message_service import (
|
||||||
|
create_message,
|
||||||
get_reactions_for_messages,
|
get_reactions_for_messages,
|
||||||
list_recent_messages,
|
list_recent_messages,
|
||||||
list_room_attachments,
|
list_room_attachments,
|
||||||
@@ -655,7 +656,35 @@ async def add_member_endpoint(
|
|||||||
raise HTTPException(status_code=404, detail="No user with that ID")
|
raise HTTPException(status_code=404, detail="No user with that ID")
|
||||||
except AlreadyMemberError:
|
except AlreadyMemberError:
|
||||||
raise HTTPException(status_code=409, detail="That user is already a member")
|
raise HTTPException(status_code=409, detail="That user is already a member")
|
||||||
|
|
||||||
|
# room_added first -- the new member's client needs to know this room
|
||||||
|
# exists before it can make sense of an unread_update for it, which the
|
||||||
|
# welcome message below would otherwise trigger out of order.
|
||||||
await broadcast_room_added(request.app.state.broadcaster, data.user_id, room)
|
await broadcast_room_added(request.app.state.broadcaster, data.user_id, room)
|
||||||
|
|
||||||
|
# #72: attributed to the admin doing the adding, not a new system/bot
|
||||||
|
# sender concept -- they're already a real, in-scope user for this
|
||||||
|
# request, and every Message row requires a real user_id today.
|
||||||
|
welcome_name = membership.user.display_name or membership.user.username
|
||||||
|
welcome_message = await create_message(
|
||||||
|
db, room.id, current_user.id, f"Welcome to #{room.name}, {welcome_name}!"
|
||||||
|
)
|
||||||
|
# Same "sending implies having seen the room" reasoning as ws/chat.py's
|
||||||
|
# own live-message path -- without it, the admin's own client would show
|
||||||
|
# this room as unread from a message they effectively just sent.
|
||||||
|
await mark_room_read(db, room.id, current_user.id)
|
||||||
|
await broadcast_new_message(
|
||||||
|
db,
|
||||||
|
request.app.state.broadcaster,
|
||||||
|
request.app.state.presence,
|
||||||
|
request.app.state.focus_presence,
|
||||||
|
request.app.state.global_presence,
|
||||||
|
str(request.base_url),
|
||||||
|
room.id,
|
||||||
|
welcome_message,
|
||||||
|
current_user,
|
||||||
|
)
|
||||||
|
|
||||||
online_ids = await request.app.state.global_presence.online_user_ids([membership.user_id])
|
online_ids = await request.app.state.global_presence.online_user_ids([membership.user_id])
|
||||||
return RoomMemberRead(
|
return RoomMemberRead(
|
||||||
user_id=membership.user_id,
|
user_id=membership.user_id,
|
||||||
|
|||||||
@@ -484,6 +484,27 @@ async def test_add_member_directly(client, db_session, monkeypatch):
|
|||||||
assert "added" in calls[0]["subject"].lower()
|
assert "added" in calls[0]["subject"].lower()
|
||||||
|
|
||||||
|
|
||||||
|
async def test_add_member_posts_welcome_message(client, db_session, monkeypatch):
|
||||||
|
# #72: attributed to the admin who added them, since there's no
|
||||||
|
# system/bot sender concept -- mirrors test_add_member_directly's setup.
|
||||||
|
_fake_send_email(monkeypatch)
|
||||||
|
alice = await register_and_login(client, db_session, username="alice")
|
||||||
|
room_id = (await client.post("/api/rooms", json={"name": "general"})).json()["id"]
|
||||||
|
|
||||||
|
await client.post("/api/auth/logout")
|
||||||
|
bob = await register_and_login(client, db_session, username="bob")
|
||||||
|
|
||||||
|
await client.post("/api/auth/logout")
|
||||||
|
await login_as(client, "alice")
|
||||||
|
resp = await client.post(f"/api/rooms/{room_id}/members", json={"user_id": bob["id"]})
|
||||||
|
assert resp.status_code == 201, resp.text
|
||||||
|
|
||||||
|
history = (await client.get(f"/api/rooms/{room_id}/messages")).json()
|
||||||
|
welcome_messages = [m for m in history if m["username"] == "alice"]
|
||||||
|
assert len(welcome_messages) == 1
|
||||||
|
assert welcome_messages[0]["content"] == "Welcome to #general, bob!"
|
||||||
|
|
||||||
|
|
||||||
async def test_add_member_requires_admin_role(client, db_session, monkeypatch):
|
async def test_add_member_requires_admin_role(client, db_session, monkeypatch):
|
||||||
_fake_send_email(monkeypatch)
|
_fake_send_email(monkeypatch)
|
||||||
await register_and_login(client, db_session, username="alice")
|
await register_and_login(client, db_session, username="alice")
|
||||||
|
|||||||
Reference in New Issue
Block a user