Skip to content

Commit c69d842

Browse files
authored
Merge pull request #2751 from simonredfern/develop
IsOpenRoom
2 parents 5d17bda + 98dfb4c commit c69d842

File tree

13 files changed

+279
-62
lines changed

13 files changed

+279
-62
lines changed

obp-api/src/main/scala/bootstrap/liftweb/Boot.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -762,7 +762,7 @@ class Boot extends MdcLoggable {
762762

763763
def schemifyAll() = {
764764
Schemifier.schemify(true, Schemifier.infoF _, ToSchemify.models: _*)
765-
// Create default system-level "general" chat room (all_users_are_participants = true)
765+
// Create default system-level "general" chat room (is_open_room = true)
766766
code.chat.ChatRoomTrait.chatRoomProvider.vend.getOrCreateDefaultRoom()
767767
}
768768

obp-api/src/main/scala/code/api/util/ApiRole.scala

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1379,10 +1379,10 @@ object ApiRole extends MdcLoggable{
13791379
lazy val canArchiveBankChatRoom = CanArchiveBankChatRoom()
13801380
case class CanArchiveSystemChatRoom(requiresBankId: Boolean = false) extends ApiRole
13811381
lazy val canArchiveSystemChatRoom = CanArchiveSystemChatRoom()
1382-
case class CanSetBankChatRoomAUAP(requiresBankId: Boolean = true) extends ApiRole
1383-
lazy val canSetBankChatRoomAUAP = CanSetBankChatRoomAUAP()
1384-
case class CanSetSystemChatRoomAUAP(requiresBankId: Boolean = false) extends ApiRole
1385-
lazy val canSetSystemChatRoomAUAP = CanSetSystemChatRoomAUAP()
1382+
case class CanSetBankChatRoomIsOpenRoom(requiresBankId: Boolean = true) extends ApiRole
1383+
lazy val canSetBankChatRoomIsOpenRoom = CanSetBankChatRoomIsOpenRoom()
1384+
case class CanSetSystemChatRoomIsOpenRoom(requiresBankId: Boolean = false) extends ApiRole
1385+
lazy val canSetSystemChatRoomIsOpenRoom = CanSetSystemChatRoomIsOpenRoom()
13861386

13871387
private val dynamicApiRoles = new ConcurrentHashMap[String, ApiRole]
13881388

obp-api/src/main/scala/code/api/util/Glossary.scala

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5140,13 +5140,13 @@ object Glossary extends MdcLoggable {
51405140
|### Chat Rooms
51415141
|A Chat Room is a named space where participants exchange messages.
51425142
|
5143-
|A system-level room called **general** is created automatically at startup with **all_users_are_participants = true** — meaning every authenticated user can read and send messages without needing an explicit Participant record.
5143+
|A system-level room called **general** is created automatically at startup with **is_open_room = true** — meaning every authenticated user can read and send messages without needing an explicit Participant record.
51445144
|
51455145
|Each room has:
51465146
|- A unique **joining key** (UUID) that can be shared to invite others. The key can be refreshed to revoke access.
51475147
|- A **name** that is unique within its scope (per bank, or globally for system-level rooms).
51485148
|- An optional **bank_id** — if set, the room is scoped to that bank. If empty, it is a system-level room.
5149-
|- An **all_users_are_participants** flag — if true, all authenticated users are treated as implicit participants without needing a database record. They can read and send messages but have no special permissions.
5149+
|- An **is_open_room** flag — if true, all authenticated users are treated as implicit participants without needing a database record. They can read and send messages but have no special permissions.
51505150
|
51515151
|### Participants
51525152
|A Participant is a user or consumer (application/bot) that belongs to a Chat Room. Participants can:
@@ -5192,13 +5192,22 @@ object Glossary extends MdcLoggable {
51925192
|### Polling
51935193
|Clients retrieve new messages by polling the GET messages endpoint with a **since** parameter (timestamp). This avoids the complexity of WebSocket infrastructure while providing a simple, reliable mechanism for near-real-time updates.
51945194
|
5195+
|### gRPC Streaming (real-time)
5196+
|For clients that need true real-time updates without polling, OBP exposes a **ChatStreamService** over gRPC (see `chat.proto`, package `code.obp.grpc.chat.g1`). It provides four server-streaming / bidirectional RPCs:
5197+
|- **StreamMessages(StreamMessagesRequest) → stream ChatMessageEvent** — push new/edited/deleted messages for a given chat room as they happen.
5198+
|- **StreamTyping(stream TypingEvent) → stream TypingIndicator** — bidirectional stream: clients send their own typing state, server fans out typing indicators from other participants.
5199+
|- **StreamPresence(StreamPresenceRequest) → stream PresenceEvent** — online/offline updates for participants in a room.
5200+
|- **StreamUnreadCounts(StreamUnreadCountsRequest) → stream UnreadCountEvent** — per-room unread counters for the authenticated user.
5201+
|
5202+
|gRPC calls are authenticated via the same credentials as REST (see `AuthInterceptor`). The REST polling endpoints remain the canonical API; the gRPC streams are an optional push channel for clients that want lower latency and less request overhead.
5203+
|
51955204
|## API Endpoints
51965205
|
5197-
|All chat endpoints are available in two forms:
5206+
|All chat REST endpoints are available in two forms:
51985207
|- **Bank-scoped**: /banks/BANK_ID/chat-rooms/...
51995208
|- **System-level**: /chat-rooms/...
52005209
|
5201-
|See the API Explorer for the full list of Chat endpoints, tagged with **Chat**.
5210+
|See the API Explorer for the full list of Chat endpoints, tagged with **Chat**. For the real-time streaming surface, see `chat.proto` / `ChatStreamServiceImpl`.
52025211
|
52035212
""")
52045213

obp-api/src/main/scala/code/api/util/migration/Migration.scala

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ object Migration extends MdcLoggable {
115115
updateConsentViewAddJwtPayload(startedBeforeSchemifier)
116116
updateConsentViewAddJwtExpiresAt(startedBeforeSchemifier)
117117
updateAccountAccessWithViewsViewUnionAll(startedBeforeSchemifier)
118+
migrateChatRoomIsOpenRoom()
118119
}
119120

120121
private def dummyScript(): Boolean = {
@@ -649,6 +650,13 @@ object Migration extends MdcLoggable {
649650
}
650651
}
651652
}
653+
654+
private def migrateChatRoomIsOpenRoom(): Boolean = {
655+
val name = nameOf(migrateChatRoomIsOpenRoom)
656+
runOnce(name) {
657+
MigrationOfChatRoomIsOpenRoom.migrateColumn(name)
658+
}
659+
}
652660
}
653661

654662
/**
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
package code.api.util.migration
2+
3+
import code.api.util.APIUtil
4+
import code.api.util.migration.Migration.{DbFunction, saveLog}
5+
import code.chat.ChatRoom
6+
import net.liftweb.common.Full
7+
import net.liftweb.db.DB
8+
import net.liftweb.mapper.Schemifier
9+
import net.liftweb.util.DefaultConnectionIdentifier
10+
11+
object MigrationOfChatRoomIsOpenRoom {
12+
13+
/**
14+
* Migrate the old `allusersareparticipants` column to the new `isopenroom` column.
15+
*
16+
* Schemifier will have already created the new `isopenroom` column (defaulting to false).
17+
* This migration copies data from the old column and then drops it.
18+
*
19+
* If the old column does not exist (fresh install), this is a no-op.
20+
*/
21+
def migrateColumn(name: String): Boolean = {
22+
DbFunction.tableExists(ChatRoom) match {
23+
case true =>
24+
val startDate = System.currentTimeMillis()
25+
val commitId: String = APIUtil.gitCommit
26+
27+
// Check if the old column exists before attempting migration
28+
val oldColumnExists = try {
29+
DB.use(DefaultConnectionIdentifier) { conn =>
30+
val rs = conn.getMetaData.getColumns(null, null, "chatroom", "allusersareparticipants")
31+
val exists = rs.next()
32+
rs.close()
33+
exists
34+
}
35+
} catch {
36+
case _: Throwable => false
37+
}
38+
39+
if (!oldColumnExists) {
40+
val endDate = System.currentTimeMillis()
41+
val comment = "Old column allusersareparticipants does not exist (fresh install). No migration needed."
42+
saveLog(name, commitId, true, startDate, endDate, comment)
43+
return true
44+
}
45+
46+
var isSuccessful = false
47+
48+
val executedSql =
49+
DbFunction.maybeWrite(true, Schemifier.infoF _) {
50+
APIUtil.getPropsValue("db.driver") match {
51+
case Full(dbDriver) if dbDriver.contains("com.microsoft.sqlserver.jdbc.SQLServerDriver") =>
52+
() =>
53+
"""
54+
|UPDATE chatroom SET isopenroom = allusersareparticipants WHERE allusersareparticipants IS NOT NULL;
55+
|ALTER TABLE chatroom DROP COLUMN allusersareparticipants;
56+
|""".stripMargin
57+
case _ =>
58+
// PostgreSQL and MySQL
59+
() =>
60+
"""
61+
|UPDATE chatroom SET isopenroom = allusersareparticipants WHERE allusersareparticipants IS NOT NULL;
62+
|ALTER TABLE chatroom DROP COLUMN allusersareparticipants;
63+
|""".stripMargin
64+
}
65+
}
66+
67+
val endDate = System.currentTimeMillis()
68+
val comment: String =
69+
s"""Executed SQL:
70+
|$executedSql
71+
|""".stripMargin
72+
isSuccessful = true
73+
saveLog(name, commitId, isSuccessful, startDate, endDate, comment)
74+
isSuccessful
75+
76+
case false =>
77+
val startDate = System.currentTimeMillis()
78+
val commitId: String = APIUtil.gitCommit
79+
val isSuccessful = false
80+
val endDate = System.currentTimeMillis()
81+
val comment: String =
82+
s"""${ChatRoom._dbTableNameLC} table does not exist"""
83+
saveLog(name, commitId, isSuccessful, startDate, endDate, comment)
84+
isSuccessful
85+
}
86+
}
87+
}

0 commit comments

Comments
 (0)