@@ -12870,7 +12870,7 @@ trait APIMethods600 {
1287012870 x => unboxFullOrFail(x, callContext, s"$UnknownError Cannot add creator as participant", 400)
1287112871 }
1287212872 } yield {
12873- (JSONFactory600.createChatRoomJson(room), HttpCode.`201`(callContext))
12873+ (JSONFactory600.createChatRoomJson(room, participantCount = computeParticipantCount(room.chatRoomId) ), HttpCode.`201`(callContext))
1287412874 }
1287512875 }
1287612876 }
@@ -12941,7 +12941,7 @@ trait APIMethods600 {
1294112941 x => unboxFullOrFail(x, callContext, s"$UnknownError Cannot add creator as participant", 400)
1294212942 }
1294312943 } yield {
12944- (JSONFactory600.createChatRoomJson(room), HttpCode.`201`(callContext))
12944+ (JSONFactory600.createChatRoomJson(room, participantCount = computeParticipantCount(room.chatRoomId) ), HttpCode.`201`(callContext))
1294512945 }
1294612946 }
1294712947 }
@@ -12999,8 +12999,11 @@ trait APIMethods600 {
1299912999 unreadCounts <- Future {
1300013000 computeUnreadCounts(rooms, u.userId)
1300113001 }
13002+ participantCounts <- Future {
13003+ computeParticipantCounts(rooms)
13004+ }
1300213005 } yield {
13003- (JSONFactory600.createChatRoomsJson(rooms, unreadCounts), HttpCode.`200`(callContext))
13006+ (JSONFactory600.createChatRoomsJson(rooms, unreadCounts, participantCounts ), HttpCode.`200`(callContext))
1300413007 }
1300513008 }
1300613009 }
@@ -13058,8 +13061,11 @@ trait APIMethods600 {
1305813061 unreadCounts <- Future {
1305913062 computeUnreadCounts(rooms, u.userId)
1306013063 }
13064+ participantCounts <- Future {
13065+ computeParticipantCounts(rooms)
13066+ }
1306113067 } yield {
13062- (JSONFactory600.createChatRoomsJson(rooms, unreadCounts), HttpCode.`200`(callContext))
13068+ (JSONFactory600.createChatRoomsJson(rooms, unreadCounts, participantCounts ), HttpCode.`200`(callContext))
1306313069 }
1306413070 }
1306513071 }
@@ -13122,7 +13128,7 @@ trait APIMethods600 {
1312213128 x => unboxFullOrFail(x, callContext, NotChatRoomParticipant, 403)
1312313129 }
1312413130 } yield {
13125- (JSONFactory600.createChatRoomJson(room), HttpCode.`200`(callContext))
13131+ (JSONFactory600.createChatRoomJson(room, participantCount = computeParticipantCount(room.chatRoomId) ), HttpCode.`200`(callContext))
1312613132 }
1312713133 }
1312813134 }
@@ -13185,7 +13191,7 @@ trait APIMethods600 {
1318513191 x => unboxFullOrFail(x, callContext, NotChatRoomParticipant, 403)
1318613192 }
1318713193 } yield {
13188- (JSONFactory600.createChatRoomJson(room), HttpCode.`200`(callContext))
13194+ (JSONFactory600.createChatRoomJson(room, participantCount = computeParticipantCount(room.chatRoomId) ), HttpCode.`200`(callContext))
1318913195 }
1319013196 }
1319113197 }
@@ -13258,7 +13264,7 @@ trait APIMethods600 {
1325813264 x => unboxFullOrFail(x, callContext, s"$UnknownError Cannot update chat room", 400)
1325913265 }
1326013266 } yield {
13261- (JSONFactory600.createChatRoomJson(updatedRoom), HttpCode.`200`(callContext))
13267+ (JSONFactory600.createChatRoomJson(updatedRoom, participantCount = computeParticipantCount(updatedRoom.chatRoomId) ), HttpCode.`200`(callContext))
1326213268 }
1326313269 }
1326413270 }
@@ -13331,7 +13337,7 @@ trait APIMethods600 {
1333113337 x => unboxFullOrFail(x, callContext, s"$UnknownError Cannot update chat room", 400)
1333213338 }
1333313339 } yield {
13334- (JSONFactory600.createChatRoomJson(updatedRoom), HttpCode.`200`(callContext))
13340+ (JSONFactory600.createChatRoomJson(updatedRoom, participantCount = computeParticipantCount(updatedRoom.chatRoomId) ), HttpCode.`200`(callContext))
1333513341 }
1333613342 }
1333713343 }
@@ -13490,7 +13496,7 @@ trait APIMethods600 {
1349013496 x => unboxFullOrFail(x, callContext, s"$UnknownError Cannot archive chat room", 400)
1349113497 }
1349213498 } yield {
13493- (JSONFactory600.createChatRoomJson(archivedRoom), HttpCode.`200`(callContext))
13499+ (JSONFactory600.createChatRoomJson(archivedRoom, participantCount = computeParticipantCount(archivedRoom.chatRoomId) ), HttpCode.`200`(callContext))
1349413500 }
1349513501 }
1349613502 }
@@ -13555,7 +13561,7 @@ trait APIMethods600 {
1355513561 x => unboxFullOrFail(x, callContext, s"$UnknownError Cannot archive chat room", 400)
1355613562 }
1355713563 } yield {
13558- (JSONFactory600.createChatRoomJson(archivedRoom), HttpCode.`200`(callContext))
13564+ (JSONFactory600.createChatRoomJson(archivedRoom, participantCount = computeParticipantCount(archivedRoom.chatRoomId) ), HttpCode.`200`(callContext))
1355913565 }
1356013566 }
1356113567 }
@@ -13624,7 +13630,7 @@ trait APIMethods600 {
1362413630 x => unboxFullOrFail(x, callContext, s"$UnknownError Cannot update chat room", 400)
1362513631 }
1362613632 } yield {
13627- (JSONFactory600.createChatRoomJson(updatedRoom), HttpCode.`200`(callContext))
13633+ (JSONFactory600.createChatRoomJson(updatedRoom, participantCount = computeParticipantCount(updatedRoom.chatRoomId) ), HttpCode.`200`(callContext))
1362813634 }
1362913635 }
1363013636 }
@@ -13693,7 +13699,7 @@ trait APIMethods600 {
1369313699 x => unboxFullOrFail(x, callContext, s"$UnknownError Cannot update chat room", 400)
1369413700 }
1369513701 } yield {
13696- (JSONFactory600.createChatRoomJson(updatedRoom), HttpCode.`200`(callContext))
13702+ (JSONFactory600.createChatRoomJson(updatedRoom, participantCount = computeParticipantCount(updatedRoom.chatRoomId) ), HttpCode.`200`(callContext))
1369713703 }
1369813704 }
1369913705 }
@@ -16343,10 +16349,99 @@ trait APIMethods600 {
1634316349 }
1634416350 }
1634516351 }
16352+ participantCounts <- Future {
16353+ computeParticipantCounts(roomsAndCounts.map(_._1))
16354+ }
1634616355 } yield {
1634716356 val rooms = roomsAndCounts.map(_._1)
1634816357 val unreadCounts = roomsAndCounts.map { case (room, count) => room.chatRoomId -> count }.toMap
16349- (JSONFactory600.createChatRoomsJson(rooms, unreadCounts), HttpCode.`200`(callContext))
16358+ (JSONFactory600.createChatRoomsJson(rooms, unreadCounts, participantCounts), HttpCode.`200`(callContext))
16359+ }
16360+ }
16361+ }
16362+
16363+ // 25b. searchChatRooms
16364+ staticResourceDocs += ResourceDoc(
16365+ searchChatRooms,
16366+ implementedInApiVersion,
16367+ nameOf(searchChatRooms),
16368+ "POST",
16369+ "/chat-rooms/search",
16370+ "Search Chat Rooms",
16371+ s"""Search chat rooms the current user is a participant of, filtered by the supplied criteria.
16372+ |
16373+ |Currently supports filtering by participant set:
16374+ |
16375+ |- `with_user_ids` (array of user_id strings, required): only return rooms where the current user
16376+ | AND every listed user_id are participants. Pass an empty list to match all of the current user's rooms.
16377+ |- `exact_participants` (boolean, optional, default `false`): if `true`, the room's participant set
16378+ | must equal exactly `{current user} ∪ with_user_ids` with no extras. Open rooms are excluded
16379+ | from exact-participant searches because their participant set is implicitly "everyone".
16380+ |
16381+ |Primary use case: a client looking up an existing 1-on-1 direct-message room before creating one,
16382+ |by calling with `with_user_ids: [<other user_id>]` and `exact_participants: true`.
16383+ |
16384+ |The response shape is the same as `Get My Chat Rooms`.
16385+ |
16386+ |Authentication is Required
16387+ |
16388+ |""".stripMargin,
16389+ ChatRoomSearchRequestJsonV600(
16390+ with_user_ids = List("user-id-123"),
16391+ exact_participants = Some(true)
16392+ ),
16393+ ChatRoomsJsonV600(chat_rooms = List(ChatRoomJsonV600(
16394+ chat_room_id = "chat-room-id-123",
16395+ bank_id = "",
16396+ name = "DM with robert.x.0.gh",
16397+ description = "",
16398+ joining_key = "abc123key",
16399+ created_by = "user-id-456",
16400+ created_by_username = "alice",
16401+ created_by_provider = "https://github.com",
16402+ is_open_room = false,
16403+ is_archived = false,
16404+ last_message_at = Some(new java.util.Date()),
16405+ last_message_preview = Some("Hello!"),
16406+ last_message_sender = Some("alice"),
16407+ unread_count = Some(0),
16408+ created_at = new java.util.Date(),
16409+ updated_at = new java.util.Date()
16410+ ))),
16411+ List(
16412+ $AuthenticatedUserIsRequired,
16413+ InvalidJsonFormat,
16414+ UnknownError
16415+ ),
16416+ List(apiTagChat),
16417+ None
16418+ )
16419+
16420+ lazy val searchChatRooms: OBPEndpoint = {
16421+ case "chat-rooms" :: "search" :: Nil JsonPost json -> _ => {
16422+ cc => implicit val ec = EndpointContext(Some(cc))
16423+ for {
16424+ (Full(u), callContext) <- authenticatedAccess(cc)
16425+ postJson <- NewStyle.function.tryons(s"$InvalidJsonFormat The Json body should be the $ChatRoomSearchRequestJsonV600", 400, callContext) {
16426+ json.extract[ChatRoomSearchRequestJsonV600]
16427+ }
16428+ rooms <- Future {
16429+ code.chat.ChatRoomTrait.chatRoomProvider.vend.searchChatRoomsForUserWithParticipants(
16430+ u.userId,
16431+ postJson.with_user_ids,
16432+ postJson.exact_participants.getOrElse(false)
16433+ )
16434+ } map {
16435+ x => unboxFullOrFail(x, callContext, s"$UnknownError Cannot search chat rooms", 400)
16436+ }
16437+ unreadCounts <- Future {
16438+ computeUnreadCounts(rooms, u.userId)
16439+ }
16440+ participantCounts <- Future {
16441+ computeParticipantCounts(rooms)
16442+ }
16443+ } yield {
16444+ (JSONFactory600.createChatRoomsJson(rooms, unreadCounts, participantCounts), HttpCode.`200`(callContext))
1635016445 }
1635116446 }
1635216447 }
@@ -16589,6 +16684,24 @@ trait APIMethods600 {
1658916684 }
1659016685 }
1659116686
16687+ /**
16688+ * Compute the participant count for a single chat room.
16689+ */
16690+ private def computeParticipantCount(chatRoomId: String): Long = {
16691+ code.chat.ParticipantTrait.participantProvider.vend
16692+ .getParticipants(chatRoomId)
16693+ .map(_.length.toLong)
16694+ .openOr(0L)
16695+ }
16696+
16697+ /**
16698+ * Compute the participant count for each given room.
16699+ * One DB query per room — same N+1 pattern as `computeUnreadCounts`.
16700+ */
16701+ private def computeParticipantCounts(rooms: List[code.chat.ChatRoomTrait]): Map[String, Long] = {
16702+ rooms.map(room => room.chatRoomId -> computeParticipantCount(room.chatRoomId)).toMap
16703+ }
16704+
1659216705 /**
1659316706 * Compute unread counts for a list of rooms for a given user.
1659416707 * For open rooms, counts only mentions. For private rooms, counts all unread messages.
0 commit comments