Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(html5): Added captionLocale property and related logic #20272

Merged
merged 12 commits into from
Jun 3, 2024
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -20,32 +20,6 @@ class CaptionModel {
return None
}

def updateTranscriptOwner(name: String, locale: String, ownerId: String): Map[String, TranscriptVO] = {
var updatedTranscripts = new HashMap[String, TranscriptVO]

// clear owner from previous locale
if (ownerId.length > 0) {
findTranscriptByOwnerId(ownerId).foreach(t => {
val oldTranscript = t._2.copy(ownerId = "")

transcripts += t._1 -> oldTranscript
updatedTranscripts += t._1 -> oldTranscript
})
}
// change the owner if it does exist
if (transcripts contains name) {
val newTranscript = transcripts(name).copy(ownerId = ownerId)

transcripts += name -> newTranscript
updatedTranscripts += name -> newTranscript
} else { // create the locale if it doesn't exist
val addedTranscript = createTranscript(name, locale, ownerId)
updatedTranscripts += name -> addedTranscript
}

updatedTranscripts
}

def getHistory(): Map[String, TranscriptVO] = {
transcripts
}
Expand Down Expand Up @@ -97,20 +71,6 @@ class CaptionModel {
locale
}

def checkCaptionOwnerLogOut(userId: String): Option[(String, TranscriptVO)] = {
var rtnTranscript: Option[(String, TranscriptVO)] = None

if (userId.length > 0) {
findTranscriptByOwnerId(userId).foreach(t => {
val oldTranscript = t._2.copy(ownerId = "")

transcripts += t._1 -> oldTranscript
rtnTranscript = Some((t._1, oldTranscript))
})
}
rtnTranscript
}

def isUserCaptionOwner(userId: String, name: String): Boolean = {
var isOwner: Boolean = false;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,10 @@ class CaptionApp2x(implicit val context: ActorContext) extends RightsManagementT
liveMeeting.captionModel.getHistory()
}

def updateCaptionOwner(liveMeeting: LiveMeeting, name: String, locale: String, userId: String): Map[String, TranscriptVO] = {
liveMeeting.captionModel.updateTranscriptOwner(name, locale, userId)
}

def editCaptionHistory(liveMeeting: LiveMeeting, userId: String, startIndex: Integer, endIndex: Integer, name: String, text: String): Boolean = {
liveMeeting.captionModel.editHistory(userId, startIndex, endIndex, name, text)
}

def checkCaptionOwnerLogOut(liveMeeting: LiveMeeting, userId: String): Option[(String, TranscriptVO)] = {
liveMeeting.captionModel.checkCaptionOwnerLogOut(userId)
}

def isUserCaptionOwner(liveMeeting: LiveMeeting, userId: String, name: String): Boolean = {
liveMeeting.captionModel.isUserCaptionOwner(userId, name)
}
Expand Down Expand Up @@ -75,46 +67,25 @@ class CaptionApp2x(implicit val context: ActorContext) extends RightsManagementT
broadcastEvent(msg, getCaptionHistory(liveMeeting))
}

def handle(msg: UpdateCaptionOwnerPubMsg, liveMeeting: LiveMeeting, bus: MessageBus): Unit = {
def broadcastUpdateCaptionOwnerEvent(name: String, locale: String, newOwnerId: String): Unit = {
val routing = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, liveMeeting.props.meetingProp.intId, newOwnerId)
val envelope = BbbCoreEnvelope(UpdateCaptionOwnerEvtMsg.NAME, routing)
val header = BbbClientMsgHeader(UpdateCaptionOwnerEvtMsg.NAME, liveMeeting.props.meetingProp.intId, newOwnerId)
def handle(msg: AddCaptionLocalePubMsg, liveMeeting: LiveMeeting, bus: MessageBus): Unit = {
def broadcastAddCaptionLocaleEvent(locale: String, userId: String): Unit = {
val routing = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, liveMeeting.props.meetingProp.intId, userId)
val envelope = BbbCoreEnvelope(AddCaptionLocaleEvtMsg.NAME, routing)
val header = BbbClientMsgHeader(AddCaptionLocaleEvtMsg.NAME, liveMeeting.props.meetingProp.intId, userId)

val body = UpdateCaptionOwnerEvtMsgBody(name, locale, newOwnerId)
val event = UpdateCaptionOwnerEvtMsg(header, body)
val body = AddCaptionLocaleEvtMsgBody(locale)
val event = AddCaptionLocaleEvtMsg(header, body)
val msgEvent = BbbCommonEnvCoreMsg(envelope, event)
bus.outGW.send(msgEvent)
CaptionLocaleDAO.insertOrUpdateCaptionLocale(liveMeeting.props.meetingProp.intId, locale, CaptionTypes.TYPED, newOwnerId)
CaptionLocaleDAO.insertOrUpdateCaptionLocale(liveMeeting.props.meetingProp.intId, locale, CaptionTypes.TYPED, userId)
}

if (permissionFailed(PermissionCheck.MOD_LEVEL, PermissionCheck.VIEWER_LEVEL, liveMeeting.users2x, msg.header.userId)) {
val meetingId = liveMeeting.props.meetingProp.intId
val reason = "No permission to change caption owners."
val reason = "No permission to add caption locale."
PermissionCheck.ejectUserForFailedPermission(meetingId, msg.header.userId, reason, bus.outGW, liveMeeting)
} else {
updateCaptionOwner(liveMeeting, msg.body.name, msg.body.locale, msg.body.ownerId).foreach(f => {
broadcastUpdateCaptionOwnerEvent(f._1, f._2.locale, f._2.ownerId)
})
}
}

def handleUserLeavingMsg(userId: String, liveMeeting: LiveMeeting, bus: MessageBus): Unit = {
def broadcastUpdateCaptionOwnerEvent(name: String, locale: String, newOwnerId: String): Unit = {
val routing = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, liveMeeting.props.meetingProp.intId, newOwnerId)
val envelope = BbbCoreEnvelope(UpdateCaptionOwnerEvtMsg.NAME, routing)
val header = BbbClientMsgHeader(UpdateCaptionOwnerEvtMsg.NAME, liveMeeting.props.meetingProp.intId, newOwnerId)

val body = UpdateCaptionOwnerEvtMsgBody(name, locale, newOwnerId)
val event = UpdateCaptionOwnerEvtMsg(header, body)
val msgEvent = BbbCommonEnvCoreMsg(envelope, event)
bus.outGW.send(msgEvent)
}

for {
transcriptInfo <- checkCaptionOwnerLogOut(liveMeeting, userId)
GuiLeme marked this conversation as resolved.
Show resolved Hide resolved
} yield {
broadcastUpdateCaptionOwnerEvent(transcriptInfo._1, transcriptInfo._2.locale, transcriptInfo._2.ownerId)
broadcastAddCaptionLocaleEvent(msg.body.locale, msg.header.userId)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package org.bigbluebutton.core.apps.users

import org.bigbluebutton.common2.msgs._
import org.bigbluebutton.core.apps.RightsManagementTrait
import org.bigbluebutton.core.models.{ UserState, Users2x }
import org.bigbluebutton.core.running.{ LiveMeeting, OutMsgRouter }

trait SetUserCaptionLocaleMsgHdlr extends RightsManagementTrait {
this: UsersApp =>

val liveMeeting: LiveMeeting
val outGW: OutMsgRouter

def handleSetUserCaptionLocaleReqMsg(msg: SetUserCaptionLocaleReqMsg): Unit = {
log.info("handleSetUserCaptionLocaleReqMsg: locale={} provider={} userId={}", msg.body.locale, msg.body.provider, msg.header.userId)

def broadcastUserCaptionLocaleChanged(user: UserState, locale: String, provider: String): Unit = {
val routingChange = Routing.addMsgToClientRouting(
MessageTypes.BROADCAST_TO_MEETING,
liveMeeting.props.meetingProp.intId, user.intId
)
val envelopeChange = BbbCoreEnvelope(UserCaptionLocaleChangedEvtMsg.NAME, routingChange)
val headerChange = BbbClientMsgHeader(UserCaptionLocaleChangedEvtMsg.NAME, liveMeeting.props.meetingProp.intId, user.intId)

val bodyChange = UserCaptionLocaleChangedEvtMsgBody(locale, provider)
val eventChange = UserCaptionLocaleChangedEvtMsg(headerChange, bodyChange)
val msgEventChange = BbbCommonEnvCoreMsg(envelopeChange, eventChange)
outGW.send(msgEventChange)
}

for {
user <- Users2x.findWithIntId(liveMeeting.users2x, msg.header.userId)
} yield {
Users2x.setUserCaptionLocale(liveMeeting.users2x, msg.header.userId, msg.body.locale)
broadcastUserCaptionLocaleChanged(user, msg.body.locale, msg.body.provider)
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,7 @@ class UsersApp(
with RegisterUserReqMsgHdlr
with ChangeUserRoleCmdMsgHdlr
with SetUserSpeechLocaleMsgHdlr
with SetUserCaptionLocaleMsgHdlr
with SetUserSpeechOptionsMsgHdlr
with SyncGetUsersMeetingRespMsgHdlr
with LogoutAndEndMeetingCmdMsgHdlr
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,28 +8,28 @@ case class CaptionLocaleDbModel(
meetingId: String,
locale: String,
captionType: String,
ownerUserId: String,
createdBy: String,
updatedAt: java.sql.Timestamp
)

class CaptionLocaleTableDef(tag: Tag) extends Table[CaptionLocaleDbModel](tag, None, "caption_locale") {
val meetingId = column[String]("meetingId", O.PrimaryKey)
val locale = column[String]("locale", O.PrimaryKey)
val captionType = column[String]("captionType", O.PrimaryKey)
val ownerUserId = column[String]("ownerUserId")
val createdBy = column[String]("createdBy")
val updatedAt = column[java.sql.Timestamp]("updatedAt")
def * = (meetingId, locale, captionType, ownerUserId, updatedAt) <> (CaptionLocaleDbModel.tupled, CaptionLocaleDbModel.unapply)
def * = (meetingId, locale, captionType, createdBy, updatedAt) <> (CaptionLocaleDbModel.tupled, CaptionLocaleDbModel.unapply)
}

object CaptionLocaleDAO {
def insertOrUpdateCaptionLocale(meetingId: String, locale: String, captionType: String, ownerUserId: String) = {
def insertOrUpdateCaptionLocale(meetingId: String, locale: String, captionType: String, userId: String) = {
DatabaseConnection.db.run(
TableQuery[CaptionLocaleTableDef].insertOrUpdate(
CaptionLocaleDbModel(
meetingId = meetingId,
locale = locale,
captionType = captionType,
ownerUserId = ownerUserId,
createdBy = userId,
updatedAt = new java.sql.Timestamp(System.currentTimeMillis())
)
)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
package org.bigbluebutton.core.db

import org.bigbluebutton.core.models.{UserState}
import org.bigbluebutton.core.models.UserState
import slick.jdbc.PostgresProfile.api._

import scala.concurrent.ExecutionContext.Implicits.global
import scala.util.{Failure, Success}


case class UserEjectColumnsDbModel(
ejected: Boolean = false,
ejectReason: Option[String],
ejectReasonCode: Option[String],
ejectedByModerator: Option[String],
)
case class UserStateDbModel(
meetingId: String,
userId: String,
Expand All @@ -19,22 +26,20 @@ case class UserStateDbModel(
clientType: String,
disconnected: Boolean = false,
expired: Boolean = false,
ejected: Boolean = false,
ejectReason: Option[String],
ejectReasonCode: Option[String],
ejectedByModerator: Option[String],
ejectColumns: UserEjectColumnsDbModel,
presenter: Boolean = false,
pinned: Boolean = false,
locked: Boolean = false,
speechLocale: String,
captionLocale: String,
inactivityWarningDisplay: Boolean = false,
inactivityWarningTimeoutSecs: Option[Long],
)

class UserStateDbTableDef(tag: Tag) extends Table[UserStateDbModel](tag, None, "user") {
override def * = (
meetingId, userId,emoji,away,raiseHand,guestStatus,guestStatusSetByModerator,guestLobbyMessage,mobile,clientType,disconnected,
expired,ejected,ejectReason,ejectReasonCode,ejectedByModerator,presenter,pinned,locked,speechLocale,
expired,ejectColumns,presenter,pinned,locked,speechLocale, captionLocale,
inactivityWarningDisplay, inactivityWarningTimeoutSecs) <> (UserStateDbModel.tupled, UserStateDbModel.unapply)
val meetingId = column[String]("meetingId", O.PrimaryKey)
val userId = column[String]("userId", O.PrimaryKey)
Expand All @@ -52,10 +57,12 @@ class UserStateDbTableDef(tag: Tag) extends Table[UserStateDbModel](tag, None, "
val ejectReason = column[Option[String]]("ejectReason")
val ejectReasonCode = column[Option[String]]("ejectReasonCode")
val ejectedByModerator = column[Option[String]]("ejectedByModerator")
val ejectColumns = (ejected, ejectReason, ejectReasonCode, ejectedByModerator) <> (UserEjectColumnsDbModel.tupled, UserEjectColumnsDbModel.unapply)
val presenter = column[Boolean]("presenter")
val pinned = column[Boolean]("pinned")
val locked = column[Boolean]("locked")
val speechLocale = column[String]("speechLocale")
val captionLocale = column[String]("captionLocale")
val inactivityWarningDisplay = column[Boolean]("inactivityWarningDisplay")
val inactivityWarningTimeoutSecs = column[Option[Long]]("inactivityWarningTimeoutSecs")
}
Expand All @@ -66,8 +73,20 @@ object UserStateDAO {
TableQuery[UserStateDbTableDef]
.filter(_.meetingId === userState.meetingId)
.filter(_.userId === userState.intId)
.map(u => (u.presenter, u.pinned, u.locked, u.speechLocale, u.emoji, u.away, u.raiseHand, u.mobile, u.clientType, u.disconnected))
.update((userState.presenter, userState.pin, userState.locked, userState.speechLocale, userState.emoji, userState.away, userState.raiseHand, userState.mobile, userState.clientType, userState.userLeftFlag.left))
.map(u => (u.presenter, u.pinned, u.locked, u.speechLocale, u.captionLocale, u.emoji, u.away, u.raiseHand, u.mobile, u.clientType, u.disconnected))
.update((
userState.presenter,
userState.pin,
userState.locked,
userState.speechLocale,
userState.captionLocale,
userState.emoji,
userState.away,
userState.raiseHand,
userState.mobile,
userState.clientType,
userState.userLeftFlag.left
))
).onComplete {
case Success(rowsAffected) => DatabaseConnection.logger.debug(s"$rowsAffected row(s) updated on user table!")
case Failure(e) => DatabaseConnection.logger.error(s"Error updating user: $e")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,17 @@ object Users2x {
}
}

def setUserCaptionLocale(users: Users2x, intId: String, locale: String): Option[UserState] = {
for {
u <- findWithIntId(users, intId)
} yield {
val newUser = u.modify(_.captionLocale).setTo(locale)
UserStateDAO.update(newUser)
users.save(newUser)
newUser
}
}

def hasPresenter(users: Users2x): Boolean = {
findPresenter(users) match {
case Some(p) => true
Expand Down Expand Up @@ -431,7 +442,9 @@ case class UserState(
lastInactivityInspect: Long = 0,
clientType: String,
userLeftFlag: UserLeftFlag,
speechLocale: String = ""
speechLocale: String = "",
captionLocale: String = ""

)

case class UserIdAndName(id: String, name: String)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,8 @@ class ReceivedJsonMsgHandlerActor(
routeGenericMsg[UserConnectionAliveReqMsg](envelope, jsonNode)
case SetUserSpeechLocaleReqMsg.NAME =>
routeGenericMsg[SetUserSpeechLocaleReqMsg](envelope, jsonNode)
case SetUserCaptionLocaleReqMsg.NAME =>
routeGenericMsg[SetUserCaptionLocaleReqMsg](envelope, jsonNode)
case SetUserSpeechOptionsReqMsg.NAME =>
routeGenericMsg[SetUserSpeechOptionsReqMsg](envelope, jsonNode)

Expand Down Expand Up @@ -347,8 +349,8 @@ class ReceivedJsonMsgHandlerActor(
// Caption
case EditCaptionHistoryPubMsg.NAME =>
routeGenericMsg[EditCaptionHistoryPubMsg](envelope, jsonNode)
case UpdateCaptionOwnerPubMsg.NAME =>
routeGenericMsg[UpdateCaptionOwnerPubMsg](envelope, jsonNode)
case AddCaptionLocalePubMsg.NAME =>
routeGenericMsg[AddCaptionLocalePubMsg](envelope, jsonNode)
case SendCaptionHistoryReqMsg.NAME =>
routeGenericMsg[SendCaptionHistoryReqMsg](envelope, jsonNode)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -438,7 +438,6 @@ class MeetingActor(
case m: RecordAndClearPreviousMarkersCmdMsg =>
state = usersApp.handleRecordAndClearPreviousMarkersCmdMsg(m, state)
updateUserLastActivity(m.body.setBy)
case m: GetRecordingStatusReqMsg => usersApp.handleGetRecordingStatusReqMsg(m)
case m: ChangeUserEmojiCmdMsg =>
handleChangeUserEmojiCmdMsg(m)
updateUserLastActivity(m.header.userId)
Expand All @@ -464,6 +463,8 @@ class MeetingActor(
case m: UserConnectionAliveReqMsg => usersApp.handleUserConnectionAliveReqMsg(m)
case m: SetUserSpeechLocaleReqMsg => usersApp.handleSetUserSpeechLocaleReqMsg(m)
case m: SetUserSpeechOptionsReqMsg => usersApp.handleSetUserSpeechOptionsReqMsg(m)
case m: GetRecordingStatusReqMsg => usersApp.handleGetRecordingStatusReqMsg(m)
case m: SetUserCaptionLocaleReqMsg => usersApp.handleSetUserCaptionLocaleReqMsg(m)

// Client requested to eject user
case m: EjectUserFromMeetingCmdMsg =>
Expand Down Expand Up @@ -642,7 +643,7 @@ class MeetingActor(

// Caption
case m: EditCaptionHistoryPubMsg => captionApp2x.handle(m, liveMeeting, msgBus)
case m: UpdateCaptionOwnerPubMsg => captionApp2x.handle(m, liveMeeting, msgBus)
case m: AddCaptionLocalePubMsg => captionApp2x.handle(m, liveMeeting, msgBus)
case m: SendCaptionHistoryReqMsg => captionApp2x.handle(m, liveMeeting, msgBus)

// Guests
Expand Down Expand Up @@ -1032,8 +1033,6 @@ class MeetingActor(

RegisteredUsers.updateUserJoin(liveMeeting.registeredUsers, ru, joined = false)

captionApp2x.handleUserLeavingMsg(leftUser.intId, liveMeeting, msgBus)

// send a user left event for the clients to update
val userLeftMeetingEvent = MsgBuilder.buildUserLeftMeetingEvtMsg(liveMeeting.props.meetingProp.intId, u.intId)
outGW.send(userLeftMeetingEvent)
Expand Down
Loading
Loading