feat(events): Add user custom data to events.xml (#20566)

* Send custom user data to akka apps

* Add user custom data to registered user

* Add user custom data to user join event

* Store user custom data in Redis

* Rename userCustomData to customParameters

* Rename xml tag to userdata
This commit is contained in:
Paul Trudel 2024-06-26 11:39:39 -04:00 committed by GitHub
parent aeaf206f33
commit b697667364
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
15 changed files with 80 additions and 34 deletions

View File

@ -63,6 +63,14 @@ trait RegisterUserReqMsgHdlr {
RegisteredUsers.add(liveMeeting.registeredUsers, regUser)
val userCustomData: Map[String, String] = msg.body.userCustomData.map {
case (k, v) => k -> v.toString
}
if (userCustomData.nonEmpty) {
RegisteredUsers.updateUserCustomData(liveMeeting.registeredUsers, regUser, userCustomData)
}
log.info("Register user success. meetingId=" + liveMeeting.props.meetingProp.intId
+ " userId=" + msg.body.extUserId + " user=" + regUser)

View File

@ -164,6 +164,12 @@ object RegisteredUsers {
u
}
def updateUserCustomData(users: RegisteredUsers, user: RegisteredUser, userCustomData: Map[String, String]): RegisteredUser = {
val u = user.modify(_.userCustomData).setTo(userCustomData)
users.save(u)
u
}
}
class RegisteredUsers {
@ -202,6 +208,7 @@ case class RegisteredUser(
joined: Boolean,
banned: Boolean,
loggedOut: Boolean,
lastBreakoutRoom: BreakoutRoom2x = null
lastBreakoutRoom: BreakoutRoom2x = null,
userCustomData: Map[String, String] = Map.empty
)

View File

@ -407,20 +407,21 @@ case class UserState(
guestStatus: String,
emoji: String,
reactionEmoji: String,
reactionChangedOn: Long = 0,
reactionChangedOn: Long = 0,
raiseHand: Boolean,
away: Boolean,
locked: Boolean,
presenter: Boolean,
avatar: String,
color: String,
roleChangedOn: Long = System.currentTimeMillis(),
lastActivityTime: Long = System.currentTimeMillis(),
lastInactivityInspect: Long = 0,
roleChangedOn: Long = System.currentTimeMillis(),
lastActivityTime: Long = System.currentTimeMillis(),
lastInactivityInspect: Long = 0,
clientType: String,
pickExempted: Boolean,
userLeftFlag: UserLeftFlag,
speechLocale: String = ""
speechLocale: String = "",
userCustomData: Map[String, String] = Map.empty
)
case class UserIdAndName(id: String, name: String)

View File

@ -19,8 +19,11 @@
package org.bigbluebutton.core.record.events
import spray.json._
class ParticipantJoinRecordEvent extends AbstractParticipantRecordEvent {
import ParticipantJoinRecordEvent._
import ParticipantJoinRecordEventJsonProtocol._
setEvent("ParticipantJoinEvent")
@ -43,6 +46,10 @@ class ParticipantJoinRecordEvent extends AbstractParticipantRecordEvent {
def setRole(role: String) {
eventMap.put(ROLE, role)
}
def setUserdata(userCustomData: Map[String, String]): Unit = {
eventMap.put(USER_DATA, userCustomData.toJson.compactPrint)
}
}
object ParticipantJoinRecordEvent {
@ -50,4 +57,9 @@ object ParticipantJoinRecordEvent {
protected final val EXT_USER_ID = "externalUserId"
protected final val NAME = "name"
protected final val ROLE = "role"
protected final val USER_DATA = "userdata"
}
object ParticipantJoinRecordEventJsonProtocol extends DefaultJsonProtocol {
}

View File

@ -73,7 +73,8 @@ trait HandlerHelpers extends SystemConfiguration {
color = regUser.color,
clientType = clientType,
pickExempted = false,
userLeftFlag = UserLeftFlag(false, 0)
userLeftFlag = UserLeftFlag(false, 0),
userCustomData = regUser.userCustomData
)
}

View File

@ -17,7 +17,7 @@ object UserJoinedMeetingEvtMsgBuilder {
away = userState.away,
pin = userState.pin,
presenter = userState.presenter, locked = userState.locked, avatar = userState.avatar, color = userState.color,
clientType = userState.clientType)
clientType = userState.clientType, userCustomData = userState.userCustomData)
val event = UserJoinedMeetingEvtMsg(meetingId, userState.intId, body)

View File

@ -357,6 +357,7 @@ class RedisRecorderActor(
ev.setExternalUserId(msg.body.extId)
ev.setName(msg.body.name)
ev.setRole(msg.body.role)
ev.setUserdata(msg.body.userCustomData)
record(msg.header.meetingId, ev.toMap.asJava)
}

View File

@ -7,7 +7,8 @@ case class RegisterUserReqMsg(
) extends BbbCoreMsg
case class RegisterUserReqMsgBody(meetingId: String, intUserId: String, name: String, role: String,
extUserId: String, authToken: String, avatarURL: String,
guest: Boolean, authed: Boolean, guestStatus: String, excludeFromDashboard: Boolean)
guest: Boolean, authed: Boolean, guestStatus: String, excludeFromDashboard: Boolean,
userCustomData: Map[String, AnyRef])
object UserRegisteredRespMsg { val NAME = "UserRegisteredRespMsg" }
case class UserRegisteredRespMsg(
@ -89,23 +90,24 @@ case class UserJoinedMeetingEvtMsg(
body: UserJoinedMeetingEvtMsgBody
) extends BbbCoreMsg
case class UserJoinedMeetingEvtMsgBody(
intId: String,
extId: String,
name: String,
role: String,
guest: Boolean,
authed: Boolean,
guestStatus: String,
emoji: String,
reactionEmoji: String,
raiseHand: Boolean,
away: Boolean,
pin: Boolean,
presenter: Boolean,
locked: Boolean,
avatar: String,
color: String,
clientType: String
intId: String,
extId: String,
name: String,
role: String,
guest: Boolean,
authed: Boolean,
guestStatus: String,
emoji: String,
reactionEmoji: String,
raiseHand: Boolean,
away: Boolean,
pin: Boolean,
presenter: Boolean,
locked: Boolean,
avatar: String,
color: String,
clientType: String,
userCustomData: Map[String, String]
)
/**

View File

@ -426,10 +426,19 @@ public class MeetingService implements MessageListener {
}
private void processRegisterUser(RegisterUser message) {
Map<String, Object> userCustomData = null;
Meeting meeting = meetings.get(message.meetingID);
if (meeting != null) {
userCustomData = meeting.getUserCustomData(message.externUserID);
}
if (userCustomData == null) {
userCustomData = new HashMap<>();
}
gw.registerUser(message.meetingID,
message.internalUserId, message.fullname, message.role,
message.externUserID, message.authToken, message.avatarURL, message.guest,
message.authed, message.guestStatus, message.excludeFromDashboard);
message.authed, message.guestStatus, message.excludeFromDashboard, userCustomData);
}
public Meeting getMeeting(String meetingId) {

View File

@ -51,7 +51,7 @@ public interface IBbbWebApiGWApp {
void registerUser(String meetingID, String internalUserId, String fullname, String role,
String externUserID, String authToken, String avatarURL,
Boolean guest, Boolean authed, String guestStatus, Boolean excludeFromDashboard);
Boolean guest, Boolean authed, String guestStatus, Boolean excludeFromDashboard, Map<String, Object> userCustomData);
void guestWaitingLeft(String meetingID, String internalUserId);
void destroyMeeting(DestroyMeetingMessage msg);

View File

@ -263,16 +263,18 @@ class BbbWebApiGWApp(
def registerUser(meetingId: String, intUserId: String, name: String,
role: String, extUserId: String, authToken: String, avatarURL: String,
guest: java.lang.Boolean, authed: java.lang.Boolean,
guestStatus: String, excludeFromDashboard: java.lang.Boolean): Unit = {
guestStatus: String, excludeFromDashboard: java.lang.Boolean, userCustomData: java.util.Map[String, AnyRef]): Unit = {
// meetingManagerActorRef ! new RegisterUser(meetingId = meetingId, intUserId = intUserId, name = name,
// role = role, extUserId = extUserId, authToken = authToken, avatarURL = avatarURL,
// guest = guest, authed = authed)
val ucd = userCustomData.asScala.toMap
val regUser = new RegisterUser(meetingId = meetingId, intUserId = intUserId, name = name,
role = role, extUserId = extUserId, authToken = authToken, avatarURL = avatarURL,
guest = guest.booleanValue(), authed = authed.booleanValue(), guestStatus = guestStatus,
excludeFromDashboard = excludeFromDashboard)
excludeFromDashboard = excludeFromDashboard, ucd)
val event = MsgBuilder.buildRegisterUserRequestToAkkaApps(regUser)
msgToAkkaAppsEventBus.publish(MsgToAkkaApps(toAkkaAppsChannel, event))

View File

@ -41,7 +41,7 @@ object MsgBuilder {
val body = RegisterUserReqMsgBody(meetingId = msg.meetingId, intUserId = msg.intUserId,
name = msg.name, role = msg.role, extUserId = msg.extUserId, authToken = msg.authToken,
avatarURL = msg.avatarURL, guest = msg.guest, authed = msg.authed, guestStatus = msg.guestStatus,
excludeFromDashboard = msg.excludeFromDashboard)
excludeFromDashboard = msg.excludeFromDashboard, msg.userCustomData)
val req = RegisterUserReqMsg(header, body)
BbbCommonEnvCoreMsg(envelope, req)
}

View File

@ -17,7 +17,7 @@ case class CreateBreakoutRoomMsg(meetingId: String, parentMeetingId: String,
case class AddUserSession(token: String, session: UserSession)
case class RegisterUser(meetingId: String, intUserId: String, name: String, role: String,
extUserId: String, authToken: String, avatarURL: String,
guest: Boolean, authed: Boolean, guestStatus: String, excludeFromDashboard: Boolean)
guest: Boolean, authed: Boolean, guestStatus: String, excludeFromDashboard: Boolean, userCustomData: Map[String, AnyRef])
case class CreateMeetingMsg(defaultProps: DefaultProps)

View File

@ -29,7 +29,7 @@ trait ToAkkaAppsSendersTrait extends SystemConfiguration {
val body = RegisterUserReqMsgBody(meetingId = msg.meetingId, intUserId = msg.intUserId,
name = msg.name, role = msg.role, extUserId = msg.extUserId, authToken = msg.authToken,
avatarURL = msg.avatarURL, guest = msg.guest, authed = msg.authed, guestStatus = msg.guestStatus,
excludeFromDashboard = msg.excludeFromDashboard)
excludeFromDashboard = msg.excludeFromDashboard, msg.userCustomData)
val req = RegisterUserReqMsg(header, body)
val message = BbbCommonEnvCoreMsg(envelope, req)
sendToBus(message)

View File

@ -33,6 +33,7 @@ export default async function addUser(meetingId, userData) {
color: String,
pin: Boolean,
clientType: String,
userCustomData: Match.Optional(Match.Any),
});
const userId = user.intId;
@ -43,6 +44,8 @@ export default async function addUser(meetingId, userData) {
};
const Meeting = await Meetings.findOneAsync({ meetingId });
const { userCustomData, ...restOfUser } = user;
const userInfos = {
meetingId,
sortName: lowercaseTrim(user.name),
@ -57,7 +60,7 @@ export default async function addUser(meetingId, userData) {
responseDelay: 0,
loggedOut: false,
left: false,
...flat(user),
...flat(restOfUser),
};
const modifier = {