Initial implementation of Postgres data and Hasura
This commit is contained in:
parent
aa517df377
commit
42711ac5ae
@ -28,6 +28,10 @@ object Dependencies {
|
||||
// BigBlueButton
|
||||
val bbbCommons = "0.0.22-SNAPSHOT"
|
||||
|
||||
// Database
|
||||
val slick = "3.4.1"
|
||||
val postgresql = "42.5.0"
|
||||
|
||||
// Test
|
||||
val scalaTest = "3.2.11"
|
||||
val mockito = "2.23.0"
|
||||
@ -55,6 +59,10 @@ object Dependencies {
|
||||
val apacheLang = "org.apache.commons" % "commons-lang3" % Versions.lang
|
||||
|
||||
val bbbCommons = "org.bigbluebutton" % "bbb-common-message_2.13" % Versions.bbbCommons
|
||||
|
||||
val slick = "com.typesafe.slick" %% "slick" % Versions.slick
|
||||
val slickHikaricp = "com.typesafe.slick" %% "slick-hikaricp" % Versions.slick
|
||||
val postgresql = "org.postgresql" % "postgresql" % Versions.postgresql
|
||||
}
|
||||
|
||||
object Test {
|
||||
@ -87,5 +95,8 @@ object Dependencies {
|
||||
Compile.apacheLang,
|
||||
Compile.akkaHttp,
|
||||
Compile.akkaHttpSprayJson,
|
||||
Compile.bbbCommons) ++ testing
|
||||
Compile.bbbCommons,
|
||||
Compile.slick,
|
||||
Compile.slickHikaricp,
|
||||
Compile.postgresql) ++ testing
|
||||
}
|
||||
|
@ -0,0 +1,42 @@
|
||||
package org.bigbluebutton.core.apps.users
|
||||
|
||||
import org.bigbluebutton.common2.msgs._
|
||||
import org.bigbluebutton.core.apps.{ PermissionCheck, RightsManagementTrait }
|
||||
import org.bigbluebutton.core.models.{ UserState, Users2x }
|
||||
import org.bigbluebutton.core.running.{ LiveMeeting, OutMsgRouter }
|
||||
|
||||
trait ChangeUserMobileFlagReqMsgHdlr extends RightsManagementTrait {
|
||||
this: UsersApp =>
|
||||
|
||||
val liveMeeting: LiveMeeting
|
||||
val outGW: OutMsgRouter
|
||||
|
||||
def handleChangeUserMobileFlagReqMsg(msg: ChangeUserMobileFlagReqMsg): Unit = {
|
||||
log.info("handleChangeUserMobileFlagReqMsg: mobile={} userId={}", msg.body.mobile, msg.body.userId)
|
||||
|
||||
def broadcastUserMobileChanged(user: UserState, mobile: Boolean): Unit = {
|
||||
val routingChange = Routing.addMsgToClientRouting(
|
||||
MessageTypes.BROADCAST_TO_MEETING,
|
||||
liveMeeting.props.meetingProp.intId, user.intId
|
||||
)
|
||||
val envelopeChange = BbbCoreEnvelope(UserMobileFlagChangedEvtMsg.NAME, routingChange)
|
||||
val headerChange = BbbClientMsgHeader(UserMobileFlagChangedEvtMsg.NAME, liveMeeting.props.meetingProp.intId,
|
||||
user.intId)
|
||||
|
||||
val bodyChange = UserMobileFlagChangedEvtMsgBody(user.intId, mobile)
|
||||
val eventChange = UserMobileFlagChangedEvtMsg(headerChange, bodyChange)
|
||||
val msgEventChange = BbbCommonEnvCoreMsg(envelopeChange, eventChange)
|
||||
outGW.send(msgEventChange)
|
||||
}
|
||||
|
||||
for {
|
||||
user <- Users2x.findWithIntId(liveMeeting.users2x, msg.body.userId)
|
||||
} yield {
|
||||
if (user.mobile != msg.body.mobile) {
|
||||
val userMobile = Users2x.setMobile(liveMeeting.users2x, user)
|
||||
broadcastUserMobileChanged(userMobile, msg.body.mobile)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -4,6 +4,7 @@ import org.bigbluebutton.common2.msgs._
|
||||
import org.bigbluebutton.core.models._
|
||||
import org.bigbluebutton.core.running.{ LiveMeeting, OutMsgRouter }
|
||||
import org.bigbluebutton.core2.message.senders.{ MsgBuilder, Sender }
|
||||
import scala.util.Random
|
||||
|
||||
trait RegisterUserReqMsgHdlr {
|
||||
this: UsersApp =>
|
||||
@ -54,13 +55,16 @@ trait RegisterUserReqMsgHdlr {
|
||||
|
||||
val guestStatus = msg.body.guestStatus
|
||||
|
||||
val colorOptions = List("#7b1fa2", "#6a1b9a", "#4a148c", "#5e35b1", "#512da8", "#4527a0", "#311b92",
|
||||
"#3949ab", "#303f9f", "#283593", "#1a237e", "#1976d2", "#1565c0", "#0d47a1", "#0277bd", "#01579b")
|
||||
val userColor = colorOptions(Random.nextInt(colorOptions.length))
|
||||
|
||||
val regUser = RegisteredUsers.create(msg.body.intUserId, msg.body.extUserId,
|
||||
msg.body.name, msg.body.role, msg.body.authToken,
|
||||
msg.body.avatarURL, msg.body.guest, msg.body.authed, guestStatus, msg.body.excludeFromDashboard, false)
|
||||
msg.body.avatarURL, userColor, msg.body.guest, msg.body.authed, guestStatus, msg.body.excludeFromDashboard, false)
|
||||
|
||||
checkUserConcurrentAccesses(regUser)
|
||||
|
||||
RegisteredUsers.add(liveMeeting.registeredUsers, regUser)
|
||||
RegisteredUsers.add(liveMeeting.registeredUsers, regUser, liveMeeting.props.meetingProp.intId)
|
||||
|
||||
log.info("Register user success. meetingId=" + liveMeeting.props.meetingProp.intId
|
||||
+ " userId=" + msg.body.extUserId + " user=" + regUser)
|
||||
|
@ -158,6 +158,7 @@ class UsersApp(
|
||||
with SelectRandomViewerReqMsgHdlr
|
||||
with AssignPresenterReqMsgHdlr
|
||||
with ChangeUserPinStateReqMsgHdlr
|
||||
with ChangeUserMobileFlagReqMsgHdlr
|
||||
with EjectUserFromMeetingCmdMsgHdlr
|
||||
with EjectUserFromMeetingSysMsgHdlr
|
||||
with MuteUserCmdMsgHdlr {
|
||||
|
@ -8,6 +8,8 @@ import org.bigbluebutton.core.models._
|
||||
import org.bigbluebutton.core.apps.users.UsersApp
|
||||
import org.bigbluebutton.core2.MeetingStatus2x
|
||||
|
||||
import scala.util.Random
|
||||
|
||||
trait UserJoinedVoiceConfEvtMsgHdlr extends SystemConfiguration {
|
||||
this: MeetingActor =>
|
||||
|
||||
@ -19,6 +21,10 @@ trait UserJoinedVoiceConfEvtMsgHdlr extends SystemConfiguration {
|
||||
val guestPolicy = GuestsWaiting.getGuestPolicy(liveMeeting.guestsWaiting)
|
||||
val isDialInUser = msg.body.intId.startsWith(IntIdPrefixType.DIAL_IN)
|
||||
|
||||
val colorOptions = List("#7b1fa2", "#6a1b9a", "#4a148c", "#5e35b1", "#512da8", "#4527a0", "#311b92",
|
||||
"#3949ab", "#303f9f", "#283593", "#1a237e", "#1976d2", "#1565c0", "#0d47a1", "#0277bd", "#01579b")
|
||||
val userColor = colorOptions(Random.nextInt(colorOptions.length))
|
||||
|
||||
def notifyModeratorsOfGuestWaiting(guest: GuestWaiting, users: Users2x, meetingId: String): Unit = {
|
||||
val moderators = Users2x.findAll(users).filter(p => p.role == Roles.MODERATOR_ROLE)
|
||||
moderators foreach { mod =>
|
||||
@ -32,9 +38,9 @@ trait UserJoinedVoiceConfEvtMsgHdlr extends SystemConfiguration {
|
||||
|
||||
def registerUserInRegisteredUsers() = {
|
||||
val regUser = RegisteredUsers.create(msg.body.intId, msg.body.voiceUserId,
|
||||
msg.body.callerIdName, Roles.VIEWER_ROLE, "",
|
||||
"", true, true, GuestStatus.WAIT, true, false)
|
||||
RegisteredUsers.add(liveMeeting.registeredUsers, regUser)
|
||||
msg.body.callerIdName, Roles.VIEWER_ROLE, "", "", userColor,
|
||||
true, true, GuestStatus.WAIT, true, false)
|
||||
RegisteredUsers.add(liveMeeting.registeredUsers, regUser, liveMeeting.props.meetingProp.intId)
|
||||
}
|
||||
|
||||
def registerUserInUsers2x() = {
|
||||
@ -48,9 +54,11 @@ trait UserJoinedVoiceConfEvtMsgHdlr extends SystemConfiguration {
|
||||
guestStatus = GuestStatus.WAIT,
|
||||
emoji = "none",
|
||||
pin = false,
|
||||
mobile = false,
|
||||
presenter = false,
|
||||
locked = MeetingStatus2x.getPermissions(liveMeeting.status).lockOnJoin,
|
||||
avatar = "",
|
||||
color = userColor,
|
||||
clientType = "",
|
||||
pickExempted = false,
|
||||
userLeftFlag = UserLeftFlag(false, 0)
|
||||
|
@ -0,0 +1,9 @@
|
||||
package org.bigbluebutton.core.db
|
||||
|
||||
import slick.jdbc.PostgresProfile.api._
|
||||
import scala.concurrent.ExecutionContext.Implicits.global
|
||||
|
||||
object DatabaseConnection {
|
||||
val db = Database.forConfig("postgres")
|
||||
// implicit val session: Session = db.createSession()
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
package org.bigbluebutton.core.db
|
||||
|
||||
import org.bigbluebutton.core.models.{RegisteredUser, UserState, VoiceUserState, WebcamStream}
|
||||
import slick.jdbc.PostgresProfile.api._
|
||||
|
||||
import scala.concurrent.ExecutionContext.Implicits.global
|
||||
import scala.util.{Failure, Success, Try}
|
||||
|
||||
case class UserCameraDbModel(
|
||||
streamId: String,
|
||||
userId: String,
|
||||
)
|
||||
|
||||
class UserCameraDbTableDef(tag: Tag) extends Table[UserCameraDbModel](tag, None, "user_camera") {
|
||||
override def * = (
|
||||
streamId, userId) <> (UserCameraDbModel.tupled, UserCameraDbModel.unapply)
|
||||
val streamId = column[String]("streamId", O.PrimaryKey)
|
||||
val userId = column[String]("userId")
|
||||
}
|
||||
|
||||
object UserCameraDAO {
|
||||
// val usersTable = TableQuery[UserTableDef]
|
||||
|
||||
def insert(webcam: WebcamStream) = {
|
||||
DatabaseConnection.db.run(
|
||||
TableQuery[UserCameraDbTableDef].forceInsert(
|
||||
UserCameraDbModel(
|
||||
streamId = webcam.streamId,
|
||||
userId = webcam.userId
|
||||
)
|
||||
)
|
||||
).onComplete {
|
||||
case Success(rowsAffected) => {
|
||||
println(s"$rowsAffected row(s) inserted!")
|
||||
}
|
||||
case Failure(e) => println(s"Error inserting webcam: $e")
|
||||
}
|
||||
}
|
||||
|
||||
def delete(streamId: String) = {
|
||||
DatabaseConnection.db.run(
|
||||
TableQuery[UserCameraDbTableDef]
|
||||
.filter(_.streamId === streamId)
|
||||
.delete
|
||||
).onComplete {
|
||||
case Success(rowsAffected) => println(s"Webcam ${streamId} deleted")
|
||||
case Failure(e) => println(s"Error deleting webcam: $e")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,211 @@
|
||||
package org.bigbluebutton.core.db
|
||||
import org.bigbluebutton.core.models.{RegisteredUser, UserState, VoiceUserState}
|
||||
import slick.jdbc.PostgresProfile.api._
|
||||
|
||||
import scala.concurrent.ExecutionContext.Implicits.global
|
||||
import scala.util.{Failure, Success, Try}
|
||||
|
||||
case class UserDbModel(
|
||||
userId: String,
|
||||
extId: String,
|
||||
meetingId: String,
|
||||
name: String,
|
||||
avatar: String = "",
|
||||
color: String = "",
|
||||
emoji: String = "",
|
||||
guest: Boolean,
|
||||
guestStatus: String = "",
|
||||
mobile: Boolean,
|
||||
// excludeFromDashboard: Boolean,
|
||||
role: String,
|
||||
authed: Boolean = false,
|
||||
joined: Boolean = false,
|
||||
leftFlag: Boolean = false,
|
||||
ejected: Boolean = false,
|
||||
ejectReason: String = "",
|
||||
banned: Boolean = false,
|
||||
loggedOut: Boolean = false,
|
||||
registeredOn: Long,
|
||||
presenter: Boolean = false,
|
||||
pinned: Boolean = false,
|
||||
locked: Boolean = false,
|
||||
// registeredOn: Option[Long]
|
||||
// registeredOn: Option[LocalDate]
|
||||
)
|
||||
|
||||
class UserDbTableDef(tag: Tag) extends Table[UserDbModel](tag, None, "user") {
|
||||
override def * = (
|
||||
userId, extId, meetingId, name, avatar, color, emoji, guest, guestStatus, mobile, role, authed, joined,
|
||||
leftFlag, ejected, ejectReason, banned, loggedOut, registeredOn, presenter, pinned, locked) <> (UserDbModel.tupled, UserDbModel.unapply)
|
||||
val userId = column[String]("userId", O.PrimaryKey)
|
||||
val extId = column[String]("extId")
|
||||
val meetingId = column[String]("meetingId")
|
||||
val name = column[String]("name")
|
||||
val avatar = column[String]("avatar")
|
||||
val color = column[String]("color")
|
||||
val emoji = column[String]("emoji")
|
||||
val guest = column[Boolean]("guest")
|
||||
val guestStatus = column[String]("guestStatus")
|
||||
val mobile = column[Boolean]("mobile")
|
||||
// val excludeFromDashboard = column[Boolean]("excludeFromDashboard")
|
||||
val role = column[String]("role")
|
||||
val authed = column[Boolean]("authed")
|
||||
val joined = column[Boolean]("joined")
|
||||
val leftFlag = column[Boolean]("leftFlag")
|
||||
val ejected = column[Boolean]("ejected")
|
||||
val ejectReason = column[String]("ejectReason")
|
||||
val banned = column[Boolean]("banned")
|
||||
val loggedOut = column[Boolean]("loggedOut")
|
||||
val registeredOn = column[Long]("registeredOn")
|
||||
val presenter = column[Boolean]("presenter")
|
||||
val pinned = column[Boolean]("pinned")
|
||||
val locked = column[Boolean]("locked")
|
||||
// val registeredOn: Rep[Option[Long]] = column[Option[Long]]("registeredOn")
|
||||
// val registeredOn: Rep[Option[LocalDate]] = column[Option[LocalDate]]("registeredOn")
|
||||
}
|
||||
|
||||
object UserDAO {
|
||||
// val usersTable = TableQuery[UserTableDef]
|
||||
|
||||
def insert(meetingId: String, regUser: RegisteredUser) = {
|
||||
DatabaseConnection.db.run(
|
||||
TableQuery[UserDbTableDef].forceInsert(
|
||||
UserDbModel(
|
||||
userId = regUser.id,
|
||||
extId = regUser.externId,
|
||||
meetingId = meetingId,
|
||||
name = regUser.name,
|
||||
avatar = regUser.avatarURL,
|
||||
color = regUser.color,
|
||||
guest = regUser.guest,
|
||||
guestStatus = regUser.guestStatus,
|
||||
mobile = false,
|
||||
// excludeFromDashboard = regUser.excludeFromDashboard,
|
||||
role = regUser.role,
|
||||
authed = regUser.authed,
|
||||
registeredOn = regUser.registeredOn
|
||||
)
|
||||
)
|
||||
).onComplete {
|
||||
case Success(rowsAffected) => {
|
||||
println(s"$rowsAffected row(s) inserted!")
|
||||
}
|
||||
case Failure(e) => println(s"Error inserting user: $e")
|
||||
}
|
||||
}
|
||||
|
||||
def update(regUser: RegisteredUser) = {
|
||||
DatabaseConnection.db.run(
|
||||
TableQuery[UserDbTableDef]
|
||||
.filter(_.userId === regUser.id)
|
||||
.map(u => (u.guest, u.guestStatus, u.role, u.authed, u.joined, u.banned, u.loggedOut))
|
||||
.update((regUser.guest, regUser.guestStatus, regUser.role, regUser.authed, regUser.joined, regUser.banned, regUser.loggedOut))
|
||||
).onComplete {
|
||||
case Success(rowsAffected) => println(s"$rowsAffected row(s) updated")
|
||||
case Failure(e) => println(s"Error updating user: $e")
|
||||
}
|
||||
}
|
||||
|
||||
def update(userState: UserState) = {
|
||||
DatabaseConnection.db.run(
|
||||
TableQuery[UserDbTableDef]
|
||||
.filter(_.userId === userState.intId)
|
||||
.map(u => (u.presenter, u.pinned, u.locked, u.emoji, u.mobile, u.leftFlag))
|
||||
.update((userState.presenter, userState.pin, userState.locked, userState.emoji, userState.mobile, userState.userLeftFlag.left))
|
||||
// "guest" bool NULL
|
||||
// "guestStatus" varchar (255)
|
||||
// "role" varchar (255) NULL
|
||||
// "ejected" bool null
|
||||
// "eject_reason" varchar (255)
|
||||
// "talking" bool NULL
|
||||
// "emoji" varchar
|
||||
// ,
|
||||
).onComplete {
|
||||
case Success(rowsAffected) => println(s"$rowsAffected row(s) updated")
|
||||
case Failure(e) => println(s"Error updating user: $e")
|
||||
}
|
||||
}
|
||||
|
||||
// def deleteVoiceUser(userIntId: String) = {
|
||||
//
|
||||
//
|
||||
// val a : String = ""
|
||||
// val b : Boolean = null
|
||||
//
|
||||
// DatabaseConnection.db.run(
|
||||
// TableQuery[UserDbTableDef]
|
||||
// .filter(_.intId === userIntId)
|
||||
// .map(u => (u.voiceUserId, u.talking, u.muted, u.listenOnly))
|
||||
// .update((a, b, b, b))
|
||||
// ).onComplete {
|
||||
// case Success(rowsAffected) => println(s"$rowsAffected row(s) updated")
|
||||
// case Failure(e) => println(s"Error updating user: $e")
|
||||
// }
|
||||
// }
|
||||
|
||||
//
|
||||
// //TODO talking
|
||||
// def updateTalking(userIntId: String, talking: Boolean) = {
|
||||
// DatabaseConnection.db.run(
|
||||
// TableQuery[UserDbTableDef]
|
||||
// .filter(_.intId === userIntId)
|
||||
// .map(u => (u.talking))
|
||||
// .update((talking))
|
||||
// ).onComplete {
|
||||
// case Success(rowsAffected) => println(s"$rowsAffected row(s) updated")
|
||||
// case Failure(e) => println(s"Error updating user: $e")
|
||||
// }
|
||||
// }
|
||||
|
||||
def delete(regUser: RegisteredUser) = {
|
||||
DatabaseConnection.db.run(
|
||||
TableQuery[UserDbTableDef]
|
||||
.filter(_.userId === regUser.id)
|
||||
.delete
|
||||
).onComplete {
|
||||
case Success(rowsAffected) => println(s"User ${regUser.id} deleted")
|
||||
case Failure(e) => println(s"Error deleting user: $e")
|
||||
}
|
||||
}
|
||||
|
||||
def insert(user: UserDbModel) = {
|
||||
DatabaseConnection.db.run(
|
||||
TableQuery[UserDbTableDef].forceInsert(user)
|
||||
).onComplete {
|
||||
case Success(rowsAffected) => println(s"$rowsAffected row(s) updated")
|
||||
case Failure(e) => println(s"Error updating user: $e")
|
||||
}
|
||||
}
|
||||
|
||||
def updateUserJoined(intId: String, joined: Boolean) = {
|
||||
|
||||
// TableQuery[UserDbTableDef].update()
|
||||
|
||||
// val query = TableQuery[UserDbTableDef].filter(_.intId === user.intId).map(_.joined).update(true)
|
||||
// DatabaseConnection.db.run(query).onComplete {
|
||||
// case Success(rowsAffected) => println(s"$rowsAffected row(s) updated")
|
||||
// case Failure(e) => println(s"Error updating user: $e")
|
||||
// }
|
||||
|
||||
// val updateOperation: DBIO[Int] = all
|
||||
// .filter(_.registrationHash === hash)
|
||||
// .map(u => (u.field1, u.field2, u.field3))
|
||||
// .update((newValue1, newValue2, newValue3))
|
||||
|
||||
DatabaseConnection.db.run(
|
||||
TableQuery[UserDbTableDef]
|
||||
.filter(_.userId === intId)
|
||||
.map(_.joined)
|
||||
.update(joined)
|
||||
).map { updatedRows =>
|
||||
{
|
||||
if (updatedRows >= 0) {
|
||||
println(s"$updatedRows row(s) updated")
|
||||
} else {
|
||||
println(s"$updatedRows row(s) updated")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,167 @@
|
||||
package org.bigbluebutton.core.db
|
||||
|
||||
import org.bigbluebutton.core.models.{RegisteredUser, UserState, VoiceUserState, WebcamStream}
|
||||
import slick.jdbc.PostgresProfile.api._
|
||||
|
||||
import scala.concurrent.ExecutionContext.Implicits.global
|
||||
import scala.util.{Failure, Success, Try}
|
||||
|
||||
case class UserMicrophoneDbModel(
|
||||
voiceUserId: String,
|
||||
userId: String,
|
||||
// meetingId: String,
|
||||
callerName: String,
|
||||
callerNum: String,
|
||||
callingWith: String,
|
||||
joined: Boolean,
|
||||
listenOnly: Boolean,
|
||||
muted: Boolean,
|
||||
spoke: Boolean,
|
||||
talking: Boolean,
|
||||
floor: Boolean,
|
||||
lastFloorTime: String,
|
||||
voiceConf: String,
|
||||
color: String,
|
||||
startTime: Option[Long],
|
||||
endTime: Option[Long],
|
||||
)
|
||||
|
||||
class UserMicrophoneDbTableDef(tag: Tag) extends Table[UserMicrophoneDbModel](tag, None, "user_microphone") {
|
||||
override def * = (
|
||||
voiceUserId, userId, callerName, callerNum, callingWith, joined, listenOnly,
|
||||
muted, spoke, talking, floor, lastFloorTime, voiceConf, color, startTime, endTime
|
||||
) <> (UserMicrophoneDbModel.tupled, UserMicrophoneDbModel.unapply)
|
||||
val voiceUserId = column[String]("voiceUserId", O.PrimaryKey)
|
||||
val userId = column[String]("userId")
|
||||
val callerName = column[String]("callerName")
|
||||
val callerNum = column[String]("callerNum")
|
||||
val callingWith = column[String]("callingWith")
|
||||
val joined = column[Boolean]("joined")
|
||||
val listenOnly = column[Boolean]("listenOnly")
|
||||
val muted = column[Boolean]("muted")
|
||||
val spoke = column[Boolean]("spoke")
|
||||
val talking = column[Boolean]("talking")
|
||||
val floor = column[Boolean]("floor")
|
||||
val lastFloorTime = column[String]("lastFloorTime")
|
||||
val voiceConf = column[String]("voiceConf")
|
||||
val color = column[String]("color")
|
||||
val startTime = column[Option[Long]]("startTime")
|
||||
val endTime = column[Option[Long]]("endTime")
|
||||
}
|
||||
|
||||
|
||||
object UserMicrophoneDAO {
|
||||
// val usersTable = TableQuery[UserTableDef]
|
||||
|
||||
def insert(voiceUserState: VoiceUserState) = {
|
||||
DatabaseConnection.db.run(
|
||||
TableQuery[UserMicrophoneDbTableDef].forceInsert(
|
||||
UserMicrophoneDbModel(
|
||||
voiceUserId = voiceUserState.voiceUserId,
|
||||
userId = voiceUserState.intId,
|
||||
callerName = voiceUserState.callerName,
|
||||
callerNum = voiceUserState.callerNum,
|
||||
callingWith = voiceUserState.callingWith,
|
||||
joined = true,
|
||||
listenOnly = voiceUserState.listenOnly,
|
||||
muted = voiceUserState.muted,
|
||||
spoke = false,
|
||||
talking = voiceUserState.talking,
|
||||
floor = voiceUserState.floor,
|
||||
lastFloorTime = voiceUserState.lastFloorTime,
|
||||
voiceConf = "",
|
||||
color = "",
|
||||
startTime = None,
|
||||
endTime = None
|
||||
)
|
||||
)
|
||||
).onComplete {
|
||||
case Success(rowsAffected) => {
|
||||
println(s"$rowsAffected row(s) inserted!")
|
||||
}
|
||||
case Failure(e) => println(s"Error inserting voice: $e")
|
||||
}
|
||||
}
|
||||
|
||||
def update(voiceUserState: VoiceUserState) = {
|
||||
DatabaseConnection.db.run(
|
||||
TableQuery[UserMicrophoneDbTableDef]
|
||||
.filter(_.voiceUserId === voiceUserState.voiceUserId)
|
||||
.map(u => (u.listenOnly, u.muted, u.floor, u.lastFloorTime))
|
||||
.update((voiceUserState.listenOnly, voiceUserState.muted, voiceUserState.floor, voiceUserState.lastFloorTime))
|
||||
).onComplete {
|
||||
case Success(rowsAffected) => println(s"$rowsAffected row(s) updated")
|
||||
case Failure(e) => println(s"Error updating user: $e")
|
||||
}
|
||||
}
|
||||
|
||||
// updateFloor
|
||||
|
||||
def updateTalking(voiceUserState: VoiceUserState) = {
|
||||
// DatabaseConnection.db.run(sql"SELECT * FROM $users".as[(Int, Double, String)]).onComplete {
|
||||
val now = System.currentTimeMillis()
|
||||
|
||||
val updateSql = if(voiceUserState.talking) {
|
||||
sqlu"""UPDATE user_microphone SET
|
||||
"talking" = true,
|
||||
"spoke" = true,
|
||||
"endTime" = null,
|
||||
"startTime" = (case when "talking" is false then $now else "startTime" end)
|
||||
WHERE "voiceUserId" = ${voiceUserState.voiceUserId}"""
|
||||
} else {
|
||||
sqlu"""UPDATE user_microphone SET
|
||||
"talking" = false,
|
||||
"startTime" = null,
|
||||
"endTime" = (case when "talking" is true then $now else "endTime" end)
|
||||
WHERE "voiceUserId" = ${voiceUserState.voiceUserId}"""
|
||||
}
|
||||
|
||||
DatabaseConnection.db.run(updateSql).onComplete {
|
||||
case Success(rowsAffected) => println(s"$rowsAffected row(s) updated with talking: ${voiceUserState.talking}")
|
||||
case Failure(e) => println(s"Error updating voice talking: $e")
|
||||
}
|
||||
}
|
||||
|
||||
def updateFloor(voiceUserState: VoiceUserState) = {
|
||||
DatabaseConnection.db.run(
|
||||
TableQuery[UserMicrophoneDbTableDef]
|
||||
.filter(_.voiceUserId === voiceUserState.voiceUserId)
|
||||
.map(u => (u.listenOnly, u.muted))
|
||||
.update((voiceUserState.listenOnly, voiceUserState.muted))
|
||||
).onComplete {
|
||||
case Success(rowsAffected) => println(s"$rowsAffected row(s) updated")
|
||||
case Failure(e) => println(s"Error updating user: $e")
|
||||
}
|
||||
}
|
||||
|
||||
// updateTalking
|
||||
|
||||
//talking
|
||||
//spoke
|
||||
//startTime
|
||||
//endTime
|
||||
|
||||
def delete(voiceUserId: String) = {
|
||||
DatabaseConnection.db.run(
|
||||
TableQuery[UserMicrophoneDbTableDef]
|
||||
.filter(_.voiceUserId === voiceUserId)
|
||||
.delete
|
||||
).onComplete {
|
||||
case Success(rowsAffected) => println(s"Voice ${voiceUserId} deleted")
|
||||
case Failure(e) => println(s"Error deleting voice: $e")
|
||||
}
|
||||
}
|
||||
|
||||
def deleteUser(userId: String) = {
|
||||
DatabaseConnection.db.run(
|
||||
TableQuery[UserMicrophoneDbTableDef]
|
||||
.filter(_.userId === userId)
|
||||
.delete
|
||||
).onComplete {
|
||||
case Success(rowsAffected) => println(s"Voice of user ${userId} deleted")
|
||||
case Failure(e) => println(s"Error deleting voice: $e")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -1,11 +1,12 @@
|
||||
package org.bigbluebutton.core.models
|
||||
|
||||
import com.softwaremill.quicklens._
|
||||
import org.bigbluebutton.core.db.{UserDAO, UserDbModel}
|
||||
import org.bigbluebutton.core.domain.BreakoutRoom2x
|
||||
|
||||
object RegisteredUsers {
|
||||
def create(userId: String, extId: String, name: String, roles: String,
|
||||
token: String, avatar: String, guest: Boolean, authenticated: Boolean,
|
||||
token: String, avatar: String, color: String, guest: Boolean, authenticated: Boolean,
|
||||
guestStatus: String, excludeFromDashboard: Boolean, loggedOut: Boolean): RegisteredUser = {
|
||||
new RegisteredUser(
|
||||
userId,
|
||||
@ -14,6 +15,7 @@ object RegisteredUsers {
|
||||
roles,
|
||||
token,
|
||||
avatar,
|
||||
color,
|
||||
guest,
|
||||
authenticated,
|
||||
guestStatus,
|
||||
@ -76,7 +78,7 @@ object RegisteredUsers {
|
||||
regUsers.toVector.size
|
||||
}
|
||||
|
||||
def add(users: RegisteredUsers, user: RegisteredUser): Vector[RegisteredUser] = {
|
||||
def add(users: RegisteredUsers, user: RegisteredUser, meetingId: String): Vector[RegisteredUser] = {
|
||||
|
||||
findWithExternUserId(user.externId, users) match {
|
||||
case Some(u) =>
|
||||
@ -85,18 +87,20 @@ object RegisteredUsers {
|
||||
// will fail and can't join.
|
||||
// ralam april 21, 2020
|
||||
val bannedUser = user.copy(banned = true)
|
||||
UserDAO.insert(meetingId, bannedUser)
|
||||
users.save(bannedUser)
|
||||
} else {
|
||||
// If user hasn't been ejected, we allow user to join
|
||||
// as the user might be joining using 2 browsers for
|
||||
// better management of meeting.
|
||||
// ralam april 21, 2020
|
||||
UserDAO.insert(meetingId, user)
|
||||
users.save(user)
|
||||
}
|
||||
case None =>
|
||||
UserDAO.insert(meetingId, user)
|
||||
users.save(user)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private def banOrEjectUser(ejectedUser: RegisteredUser, users: RegisteredUsers, ban: Boolean): RegisteredUser = {
|
||||
@ -110,9 +114,11 @@ object RegisteredUsers {
|
||||
// ralam april 21, 2020
|
||||
val u = ejectedUser.modify(_.banned).setTo(true)
|
||||
users.save(u)
|
||||
UserDAO.update(u)
|
||||
u
|
||||
} else {
|
||||
users.delete(ejectedUser.id)
|
||||
UserDAO.delete(ejectedUser)
|
||||
ejectedUser
|
||||
}
|
||||
}
|
||||
@ -128,6 +134,7 @@ object RegisteredUsers {
|
||||
guestStatus: String): RegisteredUser = {
|
||||
val u = user.modify(_.guestStatus).setTo(guestStatus)
|
||||
users.save(u)
|
||||
UserDAO.update(u)
|
||||
u
|
||||
}
|
||||
|
||||
@ -135,6 +142,7 @@ object RegisteredUsers {
|
||||
role: String): RegisteredUser = {
|
||||
val u = user.modify(_.role).setTo(role)
|
||||
users.save(u)
|
||||
UserDAO.update(u)
|
||||
u
|
||||
}
|
||||
|
||||
@ -148,6 +156,7 @@ object RegisteredUsers {
|
||||
def updateUserJoin(users: RegisteredUsers, user: RegisteredUser): RegisteredUser = {
|
||||
val u = user.copy(joined = true)
|
||||
users.save(u)
|
||||
UserDAO.update(u)
|
||||
u
|
||||
}
|
||||
|
||||
@ -160,6 +169,7 @@ object RegisteredUsers {
|
||||
def setUserLoggedOutFlag(users: RegisteredUsers, user: RegisteredUser): RegisteredUser = {
|
||||
val u = user.copy(loggedOut = true)
|
||||
users.save(u)
|
||||
UserDAO.update(u)
|
||||
u
|
||||
}
|
||||
|
||||
@ -191,6 +201,7 @@ case class RegisteredUser(
|
||||
role: String,
|
||||
authToken: String,
|
||||
avatarURL: String,
|
||||
color: String,
|
||||
guest: Boolean,
|
||||
authed: Boolean,
|
||||
guestStatus: String,
|
||||
|
@ -1,6 +1,7 @@
|
||||
package org.bigbluebutton.core.models
|
||||
|
||||
import com.softwaremill.quicklens._
|
||||
import org.bigbluebutton.core.db.UserDAO
|
||||
import org.bigbluebutton.core.util.TimeUtil
|
||||
import org.bigbluebutton.core2.message.senders.MsgBuilder
|
||||
|
||||
@ -34,6 +35,7 @@ object Users2x {
|
||||
} yield {
|
||||
val newUser = u.copy(userLeftFlag = UserLeftFlag(true, System.currentTimeMillis()))
|
||||
users.save(newUser)
|
||||
UserDAO.update(newUser)
|
||||
newUser
|
||||
}
|
||||
}
|
||||
@ -107,6 +109,13 @@ object Users2x {
|
||||
newUserState
|
||||
}
|
||||
|
||||
def setMobile(users: Users2x, u: UserState): UserState = {
|
||||
val newUserState = modify(u)(_.mobile).setTo(true)
|
||||
users.save(newUserState)
|
||||
UserDAO.update((newUserState))
|
||||
newUserState
|
||||
}
|
||||
|
||||
def ejectFromMeeting(users: Users2x, intId: String): Option[UserState] = {
|
||||
for {
|
||||
_ <- users.remove(intId)
|
||||
@ -122,6 +131,7 @@ object Users2x {
|
||||
} yield {
|
||||
val newUser = u.modify(_.presenter).setTo(true)
|
||||
users.save(newUser)
|
||||
UserDAO.update(newUser)
|
||||
newUser
|
||||
}
|
||||
}
|
||||
@ -132,6 +142,7 @@ object Users2x {
|
||||
} yield {
|
||||
val newUser = u.modify(_.presenter).setTo(false)
|
||||
users.save(newUser)
|
||||
UserDAO.update(newUser)
|
||||
newUser
|
||||
}
|
||||
}
|
||||
@ -163,6 +174,7 @@ object Users2x {
|
||||
} yield {
|
||||
val newUser = u.modify(_.pin).setTo(pin)
|
||||
users.save(newUser)
|
||||
UserDAO.update(newUser)
|
||||
newUser
|
||||
}
|
||||
}
|
||||
@ -173,6 +185,7 @@ object Users2x {
|
||||
} yield {
|
||||
val newUser = u.modify(_.emoji).setTo(emoji)
|
||||
users.save(newUser)
|
||||
UserDAO.update(newUser)
|
||||
newUser
|
||||
}
|
||||
}
|
||||
@ -183,6 +196,7 @@ object Users2x {
|
||||
} yield {
|
||||
val newUser = u.modify(_.locked).setTo(locked)
|
||||
users.save(newUser)
|
||||
UserDAO.update(newUser)
|
||||
newUser
|
||||
}
|
||||
}
|
||||
@ -354,12 +368,14 @@ case class UserState(
|
||||
role: String,
|
||||
guest: Boolean,
|
||||
pin: Boolean,
|
||||
mobile: Boolean,
|
||||
authed: Boolean,
|
||||
guestStatus: String,
|
||||
emoji: String,
|
||||
locked: Boolean,
|
||||
presenter: Boolean,
|
||||
avatar: String,
|
||||
color: String,
|
||||
roleChangedOn: Long = System.currentTimeMillis(),
|
||||
lastActivityTime: Long = System.currentTimeMillis(),
|
||||
lastInactivityInspect: Long = 0,
|
||||
|
@ -1,6 +1,7 @@
|
||||
package org.bigbluebutton.core.models
|
||||
|
||||
import com.softwaremill.quicklens._
|
||||
import org.bigbluebutton.core.db.{ UserDAO, UserMicrophoneDAO }
|
||||
|
||||
object VoiceUsers {
|
||||
def findWithVoiceUserId(users: VoiceUsers, voiceUserId: String): Option[VoiceUserState] = {
|
||||
@ -30,9 +31,11 @@ object VoiceUsers {
|
||||
|
||||
def add(users: VoiceUsers, user: VoiceUserState): Unit = {
|
||||
users.save(user)
|
||||
UserMicrophoneDAO.insert(user)
|
||||
}
|
||||
|
||||
def removeWithIntId(users: VoiceUsers, intId: String): Option[VoiceUserState] = {
|
||||
UserMicrophoneDAO.deleteUser(intId)
|
||||
users.remove(intId)
|
||||
}
|
||||
|
||||
@ -52,6 +55,7 @@ object VoiceUsers {
|
||||
.modify(_.talking).setTo(false)
|
||||
.modify(_.lastStatusUpdateOn).setTo(System.currentTimeMillis())
|
||||
users.save(vu)
|
||||
UserMicrophoneDAO.update(vu)
|
||||
vu
|
||||
}
|
||||
}
|
||||
@ -64,6 +68,8 @@ object VoiceUsers {
|
||||
.modify(_.talking).setTo(talking)
|
||||
.modify(_.lastStatusUpdateOn).setTo(System.currentTimeMillis())
|
||||
users.save(vu)
|
||||
UserMicrophoneDAO.updateTalking(vu)
|
||||
|
||||
vu
|
||||
}
|
||||
}
|
||||
@ -76,6 +82,7 @@ object VoiceUsers {
|
||||
.modify(_.lastFloorTime).setTo(timestamp)
|
||||
.modify(_.lastStatusUpdateOn).setTo(System.currentTimeMillis())
|
||||
users.save(vu)
|
||||
UserMicrophoneDAO.update(vu)
|
||||
vu
|
||||
}
|
||||
}
|
||||
@ -87,6 +94,7 @@ object VoiceUsers {
|
||||
val vu = u.modify(_.floor).setTo(floor)
|
||||
.modify(_.lastStatusUpdateOn).setTo(System.currentTimeMillis())
|
||||
users.save(vu)
|
||||
UserMicrophoneDAO.update(vu)
|
||||
vu
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,7 @@
|
||||
package org.bigbluebutton.core.models
|
||||
|
||||
import org.bigbluebutton.core.db.UserCameraDAO
|
||||
|
||||
import collection.immutable.HashMap
|
||||
|
||||
object Webcams {
|
||||
@ -15,14 +17,20 @@ object Webcams {
|
||||
|
||||
def addWebcamStream(webcams: Webcams, webcam: WebcamStream): Option[WebcamStream] = {
|
||||
findWithStreamId(webcams, webcam.streamId) match {
|
||||
case None => Some(webcams.save(webcam))
|
||||
case None => {
|
||||
UserCameraDAO.insert(webcam)
|
||||
Some(webcams.save(webcam))
|
||||
}
|
||||
case _ => None
|
||||
}
|
||||
}
|
||||
|
||||
def removeWebcamStream(webcams: Webcams, streamId: String): Option[WebcamStream] = {
|
||||
for {
|
||||
webcam <- webcams.remove(streamId)
|
||||
webcam <- {
|
||||
UserCameraDAO.delete(streamId)
|
||||
webcams.remove(streamId)
|
||||
}
|
||||
} yield webcam
|
||||
}
|
||||
|
||||
|
@ -109,6 +109,8 @@ class ReceivedJsonMsgHandlerActor(
|
||||
routeGenericMsg[UserActivitySignCmdMsg](envelope, jsonNode)
|
||||
case ChangeUserPinStateReqMsg.NAME =>
|
||||
routeGenericMsg[ChangeUserPinStateReqMsg](envelope, jsonNode)
|
||||
case ChangeUserMobileFlagReqMsg.NAME =>
|
||||
routeGenericMsg[ChangeUserMobileFlagReqMsg](envelope, jsonNode)
|
||||
case SelectRandomViewerReqMsg.NAME =>
|
||||
routeGenericMsg[SelectRandomViewerReqMsg](envelope, jsonNode)
|
||||
|
||||
|
@ -63,9 +63,11 @@ trait HandlerHelpers extends SystemConfiguration {
|
||||
guestStatus = regUser.guestStatus,
|
||||
emoji = "none",
|
||||
pin = false,
|
||||
mobile = false,
|
||||
presenter = false,
|
||||
locked = MeetingStatus2x.getPermissions(liveMeeting.status).lockOnJoin,
|
||||
avatar = regUser.avatarURL,
|
||||
color = regUser.color,
|
||||
clientType = clientType,
|
||||
pickExempted = false,
|
||||
userLeftFlag = UserLeftFlag(false, 0)
|
||||
|
@ -388,6 +388,7 @@ class MeetingActor(
|
||||
case m: ChangeUserEmojiCmdMsg => handleChangeUserEmojiCmdMsg(m)
|
||||
case m: SelectRandomViewerReqMsg => usersApp.handleSelectRandomViewerReqMsg(m)
|
||||
case m: ChangeUserPinStateReqMsg => usersApp.handleChangeUserPinStateReqMsg(m)
|
||||
case m: ChangeUserMobileFlagReqMsg => usersApp.handleChangeUserMobileFlagReqMsg(m)
|
||||
|
||||
// Client requested to eject user
|
||||
case m: EjectUserFromMeetingCmdMsg =>
|
||||
|
@ -77,6 +77,7 @@ class AnalyticsActor(val includeChat: Boolean) extends Actor with ActorLogging {
|
||||
case m: UserDisconnectedFromGlobalAudioMsg => logMessage(msg)
|
||||
case m: AssignPresenterReqMsg => logMessage(msg)
|
||||
case m: ChangeUserPinStateReqMsg => logMessage(msg)
|
||||
case m: ChangeUserMobileFlagReqMsg => logMessage(msg)
|
||||
case m: ScreenshareRtmpBroadcastStartedVoiceConfEvtMsg => logMessage(msg)
|
||||
case m: ScreenshareRtmpBroadcastStoppedVoiceConfEvtMsg => logMessage(msg)
|
||||
case m: ScreenshareRtmpBroadcastStartedEvtMsg => logMessage(msg)
|
||||
|
@ -13,7 +13,7 @@ object UserJoinedMeetingEvtMsgBuilder {
|
||||
guestStatus = userState.guestStatus,
|
||||
emoji = userState.emoji,
|
||||
pin = userState.pin,
|
||||
presenter = userState.presenter, locked = userState.locked, avatar = userState.avatar,
|
||||
presenter = userState.presenter, locked = userState.locked, avatar = userState.avatar, color = userState.color,
|
||||
clientType = userState.clientType)
|
||||
|
||||
val event = UserJoinedMeetingEvtMsg(meetingId, userState.intId, body)
|
||||
|
@ -51,7 +51,7 @@ trait FakeTestData {
|
||||
def createUserVoiceAndCam(liveMeeting: LiveMeeting, role: String, guest: Boolean, authed: Boolean, callingWith: String,
|
||||
muted: Boolean, talking: Boolean, listenOnly: Boolean): UserState = {
|
||||
|
||||
val ruser1 = FakeUserGenerator.createFakeRegisteredUser(liveMeeting.registeredUsers, Roles.MODERATOR_ROLE, true, false)
|
||||
val ruser1 = FakeUserGenerator.createFakeRegisteredUser(liveMeeting.registeredUsers, Roles.MODERATOR_ROLE, true, false, liveMeeting.props.meetingProp.intId)
|
||||
|
||||
val vuser1 = FakeUserGenerator.createFakeVoiceUser(ruser1, "webrtc", muted = false, talking = true, listenOnly = false)
|
||||
VoiceUsers.add(liveMeeting.voiceUsers, vuser1)
|
||||
@ -67,8 +67,8 @@ trait FakeTestData {
|
||||
|
||||
def createFakeUser(liveMeeting: LiveMeeting, regUser: RegisteredUser): UserState = {
|
||||
UserState(intId = regUser.id, extId = regUser.externId, name = regUser.name, role = regUser.role, pin = false,
|
||||
guest = regUser.guest, authed = regUser.authed, guestStatus = regUser.guestStatus,
|
||||
emoji = "none", locked = false, presenter = false, avatar = regUser.avatarURL, clientType = "unknown",
|
||||
mobile = false, guest = regUser.guest, authed = regUser.authed, guestStatus = regUser.guestStatus,
|
||||
emoji = "none", locked = false, presenter = false, avatar = regUser.avatarURL, color = "#ff6242", clientType = "unknown",
|
||||
pickExempted = false, userLeftFlag = UserLeftFlag(false, 0))
|
||||
}
|
||||
|
||||
|
@ -45,17 +45,18 @@ object FakeUserGenerator {
|
||||
|
||||
private def getRandomElement(list: Seq[String], random: Random): String = list(random.nextInt(list.length))
|
||||
|
||||
def createFakeRegisteredUser(users: RegisteredUsers, role: String, guest: Boolean, authed: Boolean): RegisteredUser = {
|
||||
def createFakeRegisteredUser(users: RegisteredUsers, role: String, guest: Boolean, authed: Boolean, meetingId: String): RegisteredUser = {
|
||||
val name = getRandomElement(firstNames, random) + " " + getRandomElement(lastNames, random)
|
||||
val id = "w_" + RandomStringGenerator.randomAlphanumericString(16)
|
||||
val extId = RandomStringGenerator.randomAlphanumericString(16)
|
||||
val authToken = RandomStringGenerator.randomAlphanumericString(16)
|
||||
val avatarURL = "https://www." + RandomStringGenerator.randomAlphanumericString(32) + ".com/" +
|
||||
RandomStringGenerator.randomAlphanumericString(10) + ".png"
|
||||
val color = "#ff6242"
|
||||
|
||||
val ru = RegisteredUsers.create(userId = id, extId, name, role,
|
||||
authToken, avatarURL, guest, authed, guestStatus = GuestStatus.ALLOW, false, false)
|
||||
RegisteredUsers.add(users, ru)
|
||||
authToken, avatarURL, color, guest, authed, guestStatus = GuestStatus.ALLOW, false, false)
|
||||
RegisteredUsers.add(users, ru, meetingId)
|
||||
ru
|
||||
}
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
[Unit]
|
||||
Description=BigBlueButton Apps (Akka)
|
||||
Requires=network.target
|
||||
Wants=redis-server.service bbb-fsesl-akka.service
|
||||
After=redis-server.service bbb-fsesl-akka.service
|
||||
Wants=redis-server.service bbb-fsesl-akka.service postgresql.service
|
||||
After=redis-server.service bbb-fsesl-akka.service postgresql.service
|
||||
PartOf=bigbluebutton.target
|
||||
|
||||
[Service]
|
||||
|
@ -16,7 +16,7 @@ object TestDataGen {
|
||||
val ru = RegisteredUsers.create(userId = id, extId, name, role,
|
||||
authToken, avatarURL, guest, authed, GuestStatus.ALLOW, false)
|
||||
|
||||
RegisteredUsers.add(users, ru)
|
||||
RegisteredUsers.add(users, ru, meetingId = "test")
|
||||
ru
|
||||
}
|
||||
|
||||
@ -43,8 +43,8 @@ object TestDataGen {
|
||||
def createUserFor(liveMeeting: LiveMeeting, regUser: RegisteredUser, presenter: Boolean): UserState = {
|
||||
val u = UserState(intId = regUser.id, extId = regUser.externId, name = regUser.name, role = regUser.role,
|
||||
guest = regUser.guest, authed = regUser.authed, guestStatus = regUser.guestStatus,
|
||||
emoji = "none", locked = false, presenter = false, avatar = regUser.avatarURL, clientType = "unknown",
|
||||
userLeftFlag = UserLeftFlag(false, 0))
|
||||
emoji = "none", locked = false, presenter = false, avatar = regUser.avatarURL, color = "#ff6242",
|
||||
clientType = "unknown", userLeftFlag = UserLeftFlag(false, 0))
|
||||
Users2x.add(liveMeeting.users2x, u)
|
||||
u
|
||||
}
|
||||
|
@ -35,6 +35,21 @@ redis {
|
||||
keyExpiry=1209600
|
||||
}
|
||||
|
||||
postgres {
|
||||
dataSourceClass = "org.postgresql.ds.PGSimpleDataSource"
|
||||
properties = {
|
||||
serverName = "localhost"
|
||||
portNumber = "5432"
|
||||
databaseName = "bigbluebutton"
|
||||
user = "postgres"
|
||||
password = "bigbluebutton"
|
||||
}
|
||||
numThreads = 1
|
||||
maxConnections = 1
|
||||
}
|
||||
|
||||
|
||||
|
||||
expire {
|
||||
# time in seconds
|
||||
lastUserLeft = 60
|
||||
|
@ -88,11 +88,22 @@ case class UserJoinedMeetingEvtMsg(
|
||||
header: BbbClientMsgHeader,
|
||||
body: UserJoinedMeetingEvtMsgBody
|
||||
) extends BbbCoreMsg
|
||||
case class UserJoinedMeetingEvtMsgBody(intId: String, extId: String, name: String, role: String,
|
||||
guest: Boolean, authed: Boolean, guestStatus: String,
|
||||
case class UserJoinedMeetingEvtMsgBody(
|
||||
intId: String,
|
||||
extId: String,
|
||||
name: String,
|
||||
role: String,
|
||||
guest: Boolean,
|
||||
authed: Boolean,
|
||||
guestStatus: String,
|
||||
emoji: String,
|
||||
pin: Boolean,
|
||||
presenter: Boolean, locked: Boolean, avatar: String, clientType: String)
|
||||
presenter: Boolean,
|
||||
locked: Boolean,
|
||||
avatar: String,
|
||||
color: String,
|
||||
clientType: String
|
||||
)
|
||||
|
||||
/**
|
||||
* Sent by client to get all users in a meeting.
|
||||
@ -189,6 +200,20 @@ object UserEmojiChangedEvtMsg { val NAME = "UserEmojiChangedEvtMsg" }
|
||||
case class UserEmojiChangedEvtMsg(header: BbbClientMsgHeader, body: UserEmojiChangedEvtMsgBody) extends BbbCoreMsg
|
||||
case class UserEmojiChangedEvtMsgBody(userId: String, emoji: String)
|
||||
|
||||
/**
|
||||
* Sent from client about a user mobile flag.
|
||||
*/
|
||||
object ChangeUserMobileFlagReqMsg { val NAME = "ChangeUserMobileFlagReqMsg" }
|
||||
case class ChangeUserMobileFlagReqMsg(header: BbbClientMsgHeader, body: ChangeUserMobileFlagReqMsgBody) extends StandardMsg
|
||||
case class ChangeUserMobileFlagReqMsgBody(userId: String, mobile: Boolean)
|
||||
|
||||
/**
|
||||
* Sent to all clients about a user mobile flag.
|
||||
*/
|
||||
object UserMobileFlagChangedEvtMsg { val NAME = "UserMobileFlagChangedEvtMsg" }
|
||||
case class UserMobileFlagChangedEvtMsg(header: BbbClientMsgHeader, body: UserMobileFlagChangedEvtMsgBody) extends BbbCoreMsg
|
||||
case class UserMobileFlagChangedEvtMsgBody(userId: String, mobile: Boolean)
|
||||
|
||||
object AssignPresenterReqMsg { val NAME = "AssignPresenterReqMsg" }
|
||||
case class AssignPresenterReqMsg(header: BbbClientMsgHeader, body: AssignPresenterReqMsgBody) extends StandardMsg
|
||||
case class AssignPresenterReqMsgBody(requesterId: String, newPresenterId: String, newPresenterName: String, assignedBy: String)
|
||||
|
25
bbb-graphql-server/bbb-graphql-server.service
Normal file
25
bbb-graphql-server/bbb-graphql-server.service
Normal file
@ -0,0 +1,25 @@
|
||||
[Unit]
|
||||
Description=BigBlueButton GraphQL Server
|
||||
Requires=network.target
|
||||
Wants=postgresql.service
|
||||
After=postgresql.service
|
||||
PartOf=bigbluebutton.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=bigbluebutton
|
||||
Group=bigbluebutton
|
||||
WorkingDirectory=/usr/share/bbb-web
|
||||
EnvironmentFile=/etc/default/bbb-graphql-server
|
||||
ExecStart=/usr/local/bin/hasura-graphql-engine serve
|
||||
ExecReload=/bin/kill -HUP $MAINPID
|
||||
Restart=always
|
||||
RestartSec=60
|
||||
SuccessExitStatus=143
|
||||
TimeoutStopSec=5
|
||||
PermissionsStartOnly=true
|
||||
LimitNOFILE=1024
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target bigbluebutton.target
|
||||
|
74
bbb-graphql-server/bbb_schema.sql
Normal file
74
bbb-graphql-server/bbb_schema.sql
Normal file
@ -0,0 +1,74 @@
|
||||
drop table if exists "user";
|
||||
|
||||
CREATE TABLE public."user" (
|
||||
"userId" varchar(255) NOT NULL,
|
||||
"extId" varchar(255) NULL,
|
||||
"meetingId" varchar(255) NULL,
|
||||
"name" varchar(255) NULL,
|
||||
"avatar" varchar(255) NULL,
|
||||
"color" varchar(7) null,
|
||||
"emoji" varchar,
|
||||
"guest" bool NULL,
|
||||
"guestStatus" varchar(255),
|
||||
"mobile" bool null,
|
||||
-- "excludeFromDashboard" bool NULL,
|
||||
"role" varchar(255) NULL,
|
||||
"authed" bool NULL,
|
||||
"joined" bool NULL,
|
||||
"leftFlag" bool null,
|
||||
"ejected" bool null,
|
||||
"ejectReason" varchar(255),
|
||||
"banned" bool NULL,
|
||||
"loggedOut" bool NULL,
|
||||
"registeredOn" int8 NULL,
|
||||
"presenter" bool null,
|
||||
"pinned" bool NULL,
|
||||
"locked" bool null,
|
||||
CONSTRAINT user_pkey PRIMARY KEY ("userId")
|
||||
);
|
||||
|
||||
create index "user_meetingId" on "user"("meetingId");
|
||||
|
||||
drop view if exists "v_user_microphone";
|
||||
drop table if exists "user_microphone";
|
||||
|
||||
create table "user_microphone" (
|
||||
"voiceUserId" varchar(255) primary key,
|
||||
"userId" varchar(255) references "user"("userId"),
|
||||
"callerName" varchar(255),
|
||||
"callerNum" varchar(255),
|
||||
"callingWith" varchar(255),
|
||||
"joined" boolean null,
|
||||
"listenOnly" boolean null,
|
||||
"muted" boolean null,
|
||||
"spoke" boolean null,
|
||||
"talking" boolean null,
|
||||
"floor" boolean null,
|
||||
"lastFloorTime" varchar(25),
|
||||
"voiceConf" varchar(255),
|
||||
"color" varchar(7),
|
||||
"endTime" bigint null,
|
||||
"startTime" bigint null
|
||||
);
|
||||
|
||||
create index "user_microphone_userId" on "user_microphone"("userId");
|
||||
|
||||
create or replace view "v_user_microphone" as
|
||||
select u."meetingId", "user_microphone".*
|
||||
from "user_microphone"
|
||||
join "user" u on u."userId" = "user_microphone"."userId";
|
||||
|
||||
drop view if exists "v_user_camera";
|
||||
drop table if exists "user_camera";
|
||||
|
||||
create table "user_camera" (
|
||||
"streamId" varchar(255) primary key,
|
||||
"userId" varchar(255) NOT NULL references "user"("userId")
|
||||
);
|
||||
|
||||
create index "user_camera_userId" on "user_camera"("userId");
|
||||
|
||||
create or replace view "v_user_camera" as
|
||||
select u."meetingId", "user_camera".*
|
||||
from "user_camera"
|
||||
join "user" u on u."userId" = user_camera."userId";
|
6
bbb-graphql-server/config.yaml
Normal file
6
bbb-graphql-server/config.yaml
Normal file
@ -0,0 +1,6 @@
|
||||
version: 3
|
||||
endpoint: http://localhost:8080
|
||||
metadata_directory: metadata
|
||||
actions:
|
||||
kind: synchronous
|
||||
handler_webhook_baseurl: http://localhost:3000
|
5
bbb-graphql-server/hasura-config.env
Normal file
5
bbb-graphql-server/hasura-config.env
Normal file
@ -0,0 +1,5 @@
|
||||
HASURA_GRAPHQL_DATABASE_URL=postgres://postgres:bigbluebutton@localhost:5432/hasura_app
|
||||
#HASURA_GRAPHQL_METADATA_DATABASE_URL=postgres://postgres:bigbluebutton@localhost:5432/hasura_app
|
||||
#HASURA_GRAPHQL_NO_OF_RETRIES
|
||||
HASURA_GRAPHQL_ENABLE_CONSOLE=true
|
||||
HASURA_GRAPHQL_LIVE_QUERIES_MULTIPLEXED_REFETCH_INTERVAL=500
|
69
bbb-graphql-server/install-hasura.sh
Executable file
69
bbb-graphql-server/install-hasura.sh
Executable file
@ -0,0 +1,69 @@
|
||||
#!/bin/bash
|
||||
if [ "$EUID" -ne 0 ]; then
|
||||
echo "Please run this script as root ( or with sudo )" ;
|
||||
exit 1;
|
||||
fi;
|
||||
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
# sudo apt -y install postgresql postgresql-contrib postgresql-client postgresql-client-common
|
||||
# sudo -u postgres psql -c "SELECT version();"
|
||||
# sudo -u postgres psql -c "ALTER USER postgres PASSWORD 'bigbluebutton';"
|
||||
|
||||
# psql -U postgres -d myDataBase -a -f myInsertFile
|
||||
|
||||
|
||||
# Install Postgresql
|
||||
sudo apt update
|
||||
sudo apt install postgresql postgresql-contrib -y
|
||||
sudo -u postgres psql -c "ALTER USER postgres PASSWORD 'bigbluebutton'"
|
||||
sudo -u postgres psql -c "create database bigbluebutton"
|
||||
sudo -u postgres psql -U postgres -d bigbluebutton -a -f bbb_schema.sql
|
||||
sudo -u postgres psql -c "create database hasura_app"
|
||||
|
||||
echo "Postgresql installed!"
|
||||
|
||||
|
||||
|
||||
# sudo vi /etc/postgresql/12/main/postgresql.conf
|
||||
# listen_addresses = '*'
|
||||
|
||||
# sudo vi /etc/postgresql/12/main/pg_hba.conf
|
||||
# host all all 0.0.0.0/0 md5
|
||||
# host all all ::/0 md5
|
||||
|
||||
|
||||
# sudo docker run --name hasura --rm --net=host -itd -e HASURA_GRAPHQL_DATABASE_URL=postgres://postgres:bigbluebutton@bbb26.bbbvm.imdt.com.br:5432/hasura_app -e HASURA_GRAPHQL_ENABLE_CONSOLE=true -e HASURA_GRAPHQL_LIVE_QUERIES_MULTIPLEXED_REFETCH_INTERVAL=100 hasura/graphql-engine:v2.20.0
|
||||
|
||||
|
||||
|
||||
# Install Hasura graphql
|
||||
wget https://graphql-engine-cdn.hasura.io/server/latest/linux-amd64 -O /usr/local/bin/hasura-graphql-engine
|
||||
chmod +x /usr/local/bin/hasura-graphql-engine
|
||||
apt-get install -y gnupg2 curl apt-transport-https ca-certificates libkrb5-3 libpq5 libnuma1 unixodbc-dev libmariadb-dev-compat mariadb-client-10.3
|
||||
|
||||
|
||||
cp ./hasura-config.env /etc/default/bbb-graphql-server
|
||||
|
||||
cp ./bbb-graphql-server.service /lib/systemd/system/bbb-graphql-server.service
|
||||
|
||||
sudo systemctl enable bbb-graphql-server
|
||||
sudo systemctl start bbb-graphql-server
|
||||
|
||||
# Install Hasura CLI
|
||||
curl -L https://github.com/hasura/graphql-engine/raw/stable/cli/get.sh | bash
|
||||
|
||||
# Apply BBB metadata in Hasura
|
||||
/usr/local/bin/hasura metadata apply
|
||||
|
||||
echo ""
|
||||
echo ""
|
||||
echo "Bbb-graphql-server Installed!"
|
||||
echo "http://bbb26.bbbvm.imdt.com.br:8080/console"
|
||||
|
||||
# /usr/local/bin/hasura-graphql-engine serve
|
||||
|
||||
# hasura init bbb-graphql --endpoint http://localhost:8080
|
||||
|
||||
# deb http://apt.postgresql.org/pub/repos/apt focal-pgdg main" > /etc/apt/sources.list.d/pgdg.list && curl -s https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-key add - && apt-get -y update && apt-get install -y postgresql-client-14 && find /usr/bin -name 'pg*' -not -path '/usr/bin/pg_dump' -delete
|
||||
|
0
bbb-graphql-server/metadata/actions.graphql
Normal file
0
bbb-graphql-server/metadata/actions.graphql
Normal file
6
bbb-graphql-server/metadata/actions.yaml
Normal file
6
bbb-graphql-server/metadata/actions.yaml
Normal file
@ -0,0 +1,6 @@
|
||||
actions: []
|
||||
custom_types:
|
||||
enums: []
|
||||
input_objects: []
|
||||
objects: []
|
||||
scalars: []
|
1
bbb-graphql-server/metadata/allow_list.yaml
Normal file
1
bbb-graphql-server/metadata/allow_list.yaml
Normal file
@ -0,0 +1 @@
|
||||
[]
|
1
bbb-graphql-server/metadata/api_limits.yaml
Normal file
1
bbb-graphql-server/metadata/api_limits.yaml
Normal file
@ -0,0 +1 @@
|
||||
{}
|
1
bbb-graphql-server/metadata/backend_configs.yaml
Normal file
1
bbb-graphql-server/metadata/backend_configs.yaml
Normal file
@ -0,0 +1 @@
|
||||
{}
|
1
bbb-graphql-server/metadata/cron_triggers.yaml
Normal file
1
bbb-graphql-server/metadata/cron_triggers.yaml
Normal file
@ -0,0 +1 @@
|
||||
[]
|
@ -0,0 +1,66 @@
|
||||
table:
|
||||
name: user
|
||||
schema: public
|
||||
object_relationships:
|
||||
- name: camera
|
||||
using:
|
||||
manual_configuration:
|
||||
column_mapping:
|
||||
userId: userId
|
||||
insertion_order: null
|
||||
remote_table:
|
||||
name: v_user_camera
|
||||
schema: public
|
||||
array_relationships:
|
||||
- name: microphones
|
||||
using:
|
||||
manual_configuration:
|
||||
column_mapping:
|
||||
userId: userId
|
||||
insertion_order: null
|
||||
remote_table:
|
||||
name: v_user_microphone
|
||||
schema: public
|
||||
- name: user_cameras
|
||||
using:
|
||||
foreign_key_constraint_on:
|
||||
column: userId
|
||||
table:
|
||||
name: user_camera
|
||||
schema: public
|
||||
- name: user_microphones
|
||||
using:
|
||||
foreign_key_constraint_on:
|
||||
column: userId
|
||||
table:
|
||||
name: user_microphone
|
||||
schema: public
|
||||
select_permissions:
|
||||
- role: bbb_client
|
||||
permission:
|
||||
columns:
|
||||
- authed
|
||||
- avatar
|
||||
- banned
|
||||
- color
|
||||
- ejectReason
|
||||
- ejected
|
||||
- emoji
|
||||
- extId
|
||||
- guest
|
||||
- guestStatus
|
||||
- joined
|
||||
- leftFlag
|
||||
- locked
|
||||
- loggedOut
|
||||
- meetingId
|
||||
- mobile
|
||||
- name
|
||||
- pinned
|
||||
- presenter
|
||||
- role
|
||||
- userId
|
||||
filter:
|
||||
meetingId:
|
||||
_eq: X-Hasura-MeetingId
|
||||
allow_aggregations: true
|
@ -0,0 +1,3 @@
|
||||
table:
|
||||
name: user_camera
|
||||
schema: public
|
@ -0,0 +1,3 @@
|
||||
table:
|
||||
name: user_microphone
|
||||
schema: public
|
@ -0,0 +1,13 @@
|
||||
table:
|
||||
name: v_user_camera
|
||||
schema: public
|
||||
select_permissions:
|
||||
- role: bbb_client
|
||||
permission:
|
||||
columns:
|
||||
- meetingId
|
||||
- streamId
|
||||
- userId
|
||||
filter:
|
||||
meetingId:
|
||||
_eq: X-Hasura-MeetingId
|
@ -0,0 +1,27 @@
|
||||
table:
|
||||
name: v_user_microphone
|
||||
schema: public
|
||||
select_permissions:
|
||||
- role: bbb_client
|
||||
permission:
|
||||
columns:
|
||||
- meetingId
|
||||
- voiceUserId
|
||||
- userId
|
||||
- callerName
|
||||
- callerNum
|
||||
- callingWith
|
||||
- joined
|
||||
- listenOnly
|
||||
- muted
|
||||
- spoke
|
||||
- talking
|
||||
- floor
|
||||
- lastFloorTime
|
||||
- voiceConf
|
||||
- color
|
||||
- endTime
|
||||
- startTime
|
||||
filter:
|
||||
meetingId:
|
||||
_eq: X-Hasura-MeetingId
|
@ -0,0 +1,5 @@
|
||||
- "!include public_user.yaml"
|
||||
- "!include public_user_camera.yaml"
|
||||
- "!include public_user_microphone.yaml"
|
||||
- "!include public_v_user_camera.yaml"
|
||||
- "!include public_v_user_microphone.yaml"
|
28
bbb-graphql-server/metadata/databases/databases.yaml
Normal file
28
bbb-graphql-server/metadata/databases/databases.yaml
Normal file
@ -0,0 +1,28 @@
|
||||
- name: default
|
||||
kind: postgres
|
||||
configuration:
|
||||
connection_info:
|
||||
database_url:
|
||||
from_env: HASURA_GRAPHQL_DATABASE_URL
|
||||
isolation_level: read-committed
|
||||
pool_settings:
|
||||
connection_lifetime: 600
|
||||
idle_timeout: 180
|
||||
max_connections: 50
|
||||
retries: 1
|
||||
use_prepared_statements: true
|
||||
tables: "!include default/tables/tables.yaml"
|
||||
- name: BigBlueButton
|
||||
kind: postgres
|
||||
configuration:
|
||||
connection_info:
|
||||
database_url:
|
||||
connection_parameters:
|
||||
database: bigbluebutton
|
||||
host: localhost
|
||||
password: bigbluebutton
|
||||
port: 5432
|
||||
username: postgres
|
||||
isolation_level: read-committed
|
||||
use_prepared_statements: false
|
||||
tables: "!include BigBlueButton/tables/tables.yaml"
|
@ -0,0 +1 @@
|
||||
[]
|
@ -0,0 +1 @@
|
||||
disabled_for_roles: []
|
1
bbb-graphql-server/metadata/inherited_roles.yaml
Normal file
1
bbb-graphql-server/metadata/inherited_roles.yaml
Normal file
@ -0,0 +1 @@
|
||||
[]
|
1
bbb-graphql-server/metadata/metrics_config.yaml
Normal file
1
bbb-graphql-server/metadata/metrics_config.yaml
Normal file
@ -0,0 +1 @@
|
||||
{}
|
1
bbb-graphql-server/metadata/network.yaml
Normal file
1
bbb-graphql-server/metadata/network.yaml
Normal file
@ -0,0 +1 @@
|
||||
{}
|
1
bbb-graphql-server/metadata/opentelemetry.yaml
Normal file
1
bbb-graphql-server/metadata/opentelemetry.yaml
Normal file
@ -0,0 +1 @@
|
||||
{}
|
1
bbb-graphql-server/metadata/query_collections.yaml
Normal file
1
bbb-graphql-server/metadata/query_collections.yaml
Normal file
@ -0,0 +1 @@
|
||||
[]
|
1
bbb-graphql-server/metadata/remote_schemas.yaml
Normal file
1
bbb-graphql-server/metadata/remote_schemas.yaml
Normal file
@ -0,0 +1 @@
|
||||
[]
|
1
bbb-graphql-server/metadata/rest_endpoints.yaml
Normal file
1
bbb-graphql-server/metadata/rest_endpoints.yaml
Normal file
@ -0,0 +1 @@
|
||||
[]
|
1
bbb-graphql-server/metadata/version.yaml
Normal file
1
bbb-graphql-server/metadata/version.yaml
Normal file
@ -0,0 +1 @@
|
||||
version: 3
|
@ -4,6 +4,7 @@ import Logger from '/imports/startup/server/logger';
|
||||
import GuestUsers from '/imports/api/guest-users/';
|
||||
import updatePositionInWaitingQueue from '../methods/updatePositionInWaitingQueue';
|
||||
|
||||
//TODO receive color from akka-apps
|
||||
const COLOR_LIST = [
|
||||
'#7b1fa2', '#6a1b9a', '#4a148c', '#5e35b1', '#512da8', '#4527a0',
|
||||
'#311b92', '#3949ab', '#303f9f', '#283593', '#1a237e', '#1976d2', '#1565c0',
|
||||
|
@ -8,6 +8,7 @@ import handleEmojiStatus from './handlers/emojiStatus';
|
||||
import handleChangeRole from './handlers/changeRole';
|
||||
import handleUserPinChanged from './handlers/userPinChanged';
|
||||
import handleUserInactivityInspect from './handlers/userInactivityInspect';
|
||||
import handleChangeMobileFlag from "/imports/api/users/server/handlers/changeMobileFlag";
|
||||
|
||||
RedisPubSub.on('PresenterAssignedEvtMsg', handlePresenterAssigned);
|
||||
RedisPubSub.on('UserJoinedMeetingEvtMsg', handleUserJoined);
|
||||
@ -15,6 +16,7 @@ RedisPubSub.on('UserLeftMeetingEvtMsg', handleRemoveUser);
|
||||
RedisPubSub.on('ValidateAuthTokenRespMsg', handleValidateAuthToken);
|
||||
RedisPubSub.on('UserEmojiChangedEvtMsg', handleEmojiStatus);
|
||||
RedisPubSub.on('UserRoleChangedEvtMsg', handleChangeRole);
|
||||
RedisPubSub.on('UserMobileFlagChangedEvtMsg', handleChangeMobileFlag);
|
||||
RedisPubSub.on('UserLeftFlagUpdatedEvtMsg', handleUserLeftFlagUpdated);
|
||||
RedisPubSub.on('UserPinStateChangedEvtMsg', handleUserPinChanged);
|
||||
RedisPubSub.on('UserInactivityInspectMsg', handleUserInactivityInspect);
|
||||
|
@ -0,0 +1,13 @@
|
||||
import { check } from 'meteor/check';
|
||||
import setMobile from '/imports/api/users/server/modifiers/setMobile';
|
||||
|
||||
export default function handleChangeMobileFlag(payload, meetingId) {
|
||||
check(payload.body, Object);
|
||||
check(meetingId, String);
|
||||
|
||||
const { userId, mobile } = payload.body;
|
||||
|
||||
if(mobile) {
|
||||
setMobile(meetingId, userId);
|
||||
}
|
||||
}
|
@ -2,17 +2,27 @@ import { check } from 'meteor/check';
|
||||
import Logger from '/imports/startup/server/logger';
|
||||
import setMobile from '../modifiers/setMobile';
|
||||
import { extractCredentials } from '/imports/api/common/server/helpers';
|
||||
import RedisPubSub from "/imports/startup/server/redis";
|
||||
|
||||
export default function setMobileUser() {
|
||||
try {
|
||||
const REDIS_CONFIG = Meteor.settings.private.redis;
|
||||
const CHANNEL = REDIS_CONFIG.channels.toAkkaApps;
|
||||
const EVENT_NAME = 'ChangeUserMobileFlagReqMsg';
|
||||
|
||||
const { meetingId, requesterUserId } = extractCredentials(this.userId);
|
||||
|
||||
check(meetingId, String);
|
||||
check(requesterUserId, String);
|
||||
|
||||
const payload = {
|
||||
userId: requesterUserId,
|
||||
mobile: true,
|
||||
};
|
||||
|
||||
Logger.verbose(`Mobile user ${requesterUserId} from meeting ${meetingId}`);
|
||||
|
||||
setMobile(meetingId, requesterUserId);
|
||||
RedisPubSub.publishUserMessage(CHANNEL, EVENT_NAME, meetingId, requesterUserId, payload);
|
||||
} catch (err) {
|
||||
Logger.error(`Exception while invoking method setMobileUser ${err.stack}`);
|
||||
}
|
||||
|
@ -10,12 +10,6 @@ import { lowercaseTrim } from '/imports/utils/string-utils';
|
||||
|
||||
import addVoiceUser from '/imports/api/voice-users/server/modifiers/addVoiceUser';
|
||||
|
||||
const COLOR_LIST = [
|
||||
'#7b1fa2', '#6a1b9a', '#4a148c', '#5e35b1', '#512da8', '#4527a0',
|
||||
'#311b92', '#3949ab', '#303f9f', '#283593', '#1a237e', '#1976d2', '#1565c0',
|
||||
'#0d47a1', '#0277bd', '#01579b',
|
||||
];
|
||||
|
||||
export default function addUser(meetingId, userData) {
|
||||
const user = userData;
|
||||
|
||||
@ -34,6 +28,7 @@ export default function addUser(meetingId, userData) {
|
||||
presenter: Boolean,
|
||||
locked: Boolean,
|
||||
avatar: String,
|
||||
color: String,
|
||||
pin: Boolean,
|
||||
clientType: String,
|
||||
});
|
||||
@ -46,14 +41,9 @@ export default function addUser(meetingId, userData) {
|
||||
};
|
||||
const Meeting = Meetings.findOne({ meetingId });
|
||||
|
||||
/* While the akka-apps dont generate a color we just pick one
|
||||
from a list based on the userId */
|
||||
const color = COLOR_LIST[stringHash(user.intId) % COLOR_LIST.length];
|
||||
|
||||
const userInfos = {
|
||||
meetingId,
|
||||
sortName: lowercaseTrim(user.name),
|
||||
color,
|
||||
speechLocale: '',
|
||||
mobile: false,
|
||||
breakoutProps: {
|
||||
|
Loading…
Reference in New Issue
Block a user