Initial implementation of Postgres data and Hasura
This commit is contained in:
parent
aa517df377
commit
42711ac5ae
@ -28,6 +28,10 @@ object Dependencies {
|
|||||||
// BigBlueButton
|
// BigBlueButton
|
||||||
val bbbCommons = "0.0.22-SNAPSHOT"
|
val bbbCommons = "0.0.22-SNAPSHOT"
|
||||||
|
|
||||||
|
// Database
|
||||||
|
val slick = "3.4.1"
|
||||||
|
val postgresql = "42.5.0"
|
||||||
|
|
||||||
// Test
|
// Test
|
||||||
val scalaTest = "3.2.11"
|
val scalaTest = "3.2.11"
|
||||||
val mockito = "2.23.0"
|
val mockito = "2.23.0"
|
||||||
@ -55,6 +59,10 @@ object Dependencies {
|
|||||||
val apacheLang = "org.apache.commons" % "commons-lang3" % Versions.lang
|
val apacheLang = "org.apache.commons" % "commons-lang3" % Versions.lang
|
||||||
|
|
||||||
val bbbCommons = "org.bigbluebutton" % "bbb-common-message_2.13" % Versions.bbbCommons
|
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 {
|
object Test {
|
||||||
@ -87,5 +95,8 @@ object Dependencies {
|
|||||||
Compile.apacheLang,
|
Compile.apacheLang,
|
||||||
Compile.akkaHttp,
|
Compile.akkaHttp,
|
||||||
Compile.akkaHttpSprayJson,
|
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.models._
|
||||||
import org.bigbluebutton.core.running.{ LiveMeeting, OutMsgRouter }
|
import org.bigbluebutton.core.running.{ LiveMeeting, OutMsgRouter }
|
||||||
import org.bigbluebutton.core2.message.senders.{ MsgBuilder, Sender }
|
import org.bigbluebutton.core2.message.senders.{ MsgBuilder, Sender }
|
||||||
|
import scala.util.Random
|
||||||
|
|
||||||
trait RegisterUserReqMsgHdlr {
|
trait RegisterUserReqMsgHdlr {
|
||||||
this: UsersApp =>
|
this: UsersApp =>
|
||||||
@ -54,13 +55,16 @@ trait RegisterUserReqMsgHdlr {
|
|||||||
|
|
||||||
val guestStatus = msg.body.guestStatus
|
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,
|
val regUser = RegisteredUsers.create(msg.body.intUserId, msg.body.extUserId,
|
||||||
msg.body.name, msg.body.role, msg.body.authToken,
|
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)
|
checkUserConcurrentAccesses(regUser)
|
||||||
|
RegisteredUsers.add(liveMeeting.registeredUsers, regUser, liveMeeting.props.meetingProp.intId)
|
||||||
RegisteredUsers.add(liveMeeting.registeredUsers, regUser)
|
|
||||||
|
|
||||||
log.info("Register user success. meetingId=" + liveMeeting.props.meetingProp.intId
|
log.info("Register user success. meetingId=" + liveMeeting.props.meetingProp.intId
|
||||||
+ " userId=" + msg.body.extUserId + " user=" + regUser)
|
+ " userId=" + msg.body.extUserId + " user=" + regUser)
|
||||||
|
@ -158,6 +158,7 @@ class UsersApp(
|
|||||||
with SelectRandomViewerReqMsgHdlr
|
with SelectRandomViewerReqMsgHdlr
|
||||||
with AssignPresenterReqMsgHdlr
|
with AssignPresenterReqMsgHdlr
|
||||||
with ChangeUserPinStateReqMsgHdlr
|
with ChangeUserPinStateReqMsgHdlr
|
||||||
|
with ChangeUserMobileFlagReqMsgHdlr
|
||||||
with EjectUserFromMeetingCmdMsgHdlr
|
with EjectUserFromMeetingCmdMsgHdlr
|
||||||
with EjectUserFromMeetingSysMsgHdlr
|
with EjectUserFromMeetingSysMsgHdlr
|
||||||
with MuteUserCmdMsgHdlr {
|
with MuteUserCmdMsgHdlr {
|
||||||
|
@ -8,6 +8,8 @@ import org.bigbluebutton.core.models._
|
|||||||
import org.bigbluebutton.core.apps.users.UsersApp
|
import org.bigbluebutton.core.apps.users.UsersApp
|
||||||
import org.bigbluebutton.core2.MeetingStatus2x
|
import org.bigbluebutton.core2.MeetingStatus2x
|
||||||
|
|
||||||
|
import scala.util.Random
|
||||||
|
|
||||||
trait UserJoinedVoiceConfEvtMsgHdlr extends SystemConfiguration {
|
trait UserJoinedVoiceConfEvtMsgHdlr extends SystemConfiguration {
|
||||||
this: MeetingActor =>
|
this: MeetingActor =>
|
||||||
|
|
||||||
@ -19,6 +21,10 @@ trait UserJoinedVoiceConfEvtMsgHdlr extends SystemConfiguration {
|
|||||||
val guestPolicy = GuestsWaiting.getGuestPolicy(liveMeeting.guestsWaiting)
|
val guestPolicy = GuestsWaiting.getGuestPolicy(liveMeeting.guestsWaiting)
|
||||||
val isDialInUser = msg.body.intId.startsWith(IntIdPrefixType.DIAL_IN)
|
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 = {
|
def notifyModeratorsOfGuestWaiting(guest: GuestWaiting, users: Users2x, meetingId: String): Unit = {
|
||||||
val moderators = Users2x.findAll(users).filter(p => p.role == Roles.MODERATOR_ROLE)
|
val moderators = Users2x.findAll(users).filter(p => p.role == Roles.MODERATOR_ROLE)
|
||||||
moderators foreach { mod =>
|
moderators foreach { mod =>
|
||||||
@ -32,9 +38,9 @@ trait UserJoinedVoiceConfEvtMsgHdlr extends SystemConfiguration {
|
|||||||
|
|
||||||
def registerUserInRegisteredUsers() = {
|
def registerUserInRegisteredUsers() = {
|
||||||
val regUser = RegisteredUsers.create(msg.body.intId, msg.body.voiceUserId,
|
val regUser = RegisteredUsers.create(msg.body.intId, msg.body.voiceUserId,
|
||||||
msg.body.callerIdName, Roles.VIEWER_ROLE, "",
|
msg.body.callerIdName, Roles.VIEWER_ROLE, "", "", userColor,
|
||||||
"", true, true, GuestStatus.WAIT, true, false)
|
true, true, GuestStatus.WAIT, true, false)
|
||||||
RegisteredUsers.add(liveMeeting.registeredUsers, regUser)
|
RegisteredUsers.add(liveMeeting.registeredUsers, regUser, liveMeeting.props.meetingProp.intId)
|
||||||
}
|
}
|
||||||
|
|
||||||
def registerUserInUsers2x() = {
|
def registerUserInUsers2x() = {
|
||||||
@ -48,9 +54,11 @@ trait UserJoinedVoiceConfEvtMsgHdlr extends SystemConfiguration {
|
|||||||
guestStatus = GuestStatus.WAIT,
|
guestStatus = GuestStatus.WAIT,
|
||||||
emoji = "none",
|
emoji = "none",
|
||||||
pin = false,
|
pin = false,
|
||||||
|
mobile = false,
|
||||||
presenter = false,
|
presenter = false,
|
||||||
locked = MeetingStatus2x.getPermissions(liveMeeting.status).lockOnJoin,
|
locked = MeetingStatus2x.getPermissions(liveMeeting.status).lockOnJoin,
|
||||||
avatar = "",
|
avatar = "",
|
||||||
|
color = userColor,
|
||||||
clientType = "",
|
clientType = "",
|
||||||
pickExempted = false,
|
pickExempted = false,
|
||||||
userLeftFlag = UserLeftFlag(false, 0)
|
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
|
package org.bigbluebutton.core.models
|
||||||
|
|
||||||
import com.softwaremill.quicklens._
|
import com.softwaremill.quicklens._
|
||||||
|
import org.bigbluebutton.core.db.{UserDAO, UserDbModel}
|
||||||
import org.bigbluebutton.core.domain.BreakoutRoom2x
|
import org.bigbluebutton.core.domain.BreakoutRoom2x
|
||||||
|
|
||||||
object RegisteredUsers {
|
object RegisteredUsers {
|
||||||
def create(userId: String, extId: String, name: String, roles: String,
|
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 = {
|
guestStatus: String, excludeFromDashboard: Boolean, loggedOut: Boolean): RegisteredUser = {
|
||||||
new RegisteredUser(
|
new RegisteredUser(
|
||||||
userId,
|
userId,
|
||||||
@ -14,6 +15,7 @@ object RegisteredUsers {
|
|||||||
roles,
|
roles,
|
||||||
token,
|
token,
|
||||||
avatar,
|
avatar,
|
||||||
|
color,
|
||||||
guest,
|
guest,
|
||||||
authenticated,
|
authenticated,
|
||||||
guestStatus,
|
guestStatus,
|
||||||
@ -76,7 +78,7 @@ object RegisteredUsers {
|
|||||||
regUsers.toVector.size
|
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 {
|
findWithExternUserId(user.externId, users) match {
|
||||||
case Some(u) =>
|
case Some(u) =>
|
||||||
@ -85,18 +87,20 @@ object RegisteredUsers {
|
|||||||
// will fail and can't join.
|
// will fail and can't join.
|
||||||
// ralam april 21, 2020
|
// ralam april 21, 2020
|
||||||
val bannedUser = user.copy(banned = true)
|
val bannedUser = user.copy(banned = true)
|
||||||
|
UserDAO.insert(meetingId, bannedUser)
|
||||||
users.save(bannedUser)
|
users.save(bannedUser)
|
||||||
} else {
|
} else {
|
||||||
// If user hasn't been ejected, we allow user to join
|
// If user hasn't been ejected, we allow user to join
|
||||||
// as the user might be joining using 2 browsers for
|
// as the user might be joining using 2 browsers for
|
||||||
// better management of meeting.
|
// better management of meeting.
|
||||||
// ralam april 21, 2020
|
// ralam april 21, 2020
|
||||||
|
UserDAO.insert(meetingId, user)
|
||||||
users.save(user)
|
users.save(user)
|
||||||
}
|
}
|
||||||
case None =>
|
case None =>
|
||||||
|
UserDAO.insert(meetingId, user)
|
||||||
users.save(user)
|
users.save(user)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private def banOrEjectUser(ejectedUser: RegisteredUser, users: RegisteredUsers, ban: Boolean): RegisteredUser = {
|
private def banOrEjectUser(ejectedUser: RegisteredUser, users: RegisteredUsers, ban: Boolean): RegisteredUser = {
|
||||||
@ -110,9 +114,11 @@ object RegisteredUsers {
|
|||||||
// ralam april 21, 2020
|
// ralam april 21, 2020
|
||||||
val u = ejectedUser.modify(_.banned).setTo(true)
|
val u = ejectedUser.modify(_.banned).setTo(true)
|
||||||
users.save(u)
|
users.save(u)
|
||||||
|
UserDAO.update(u)
|
||||||
u
|
u
|
||||||
} else {
|
} else {
|
||||||
users.delete(ejectedUser.id)
|
users.delete(ejectedUser.id)
|
||||||
|
UserDAO.delete(ejectedUser)
|
||||||
ejectedUser
|
ejectedUser
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -128,6 +134,7 @@ object RegisteredUsers {
|
|||||||
guestStatus: String): RegisteredUser = {
|
guestStatus: String): RegisteredUser = {
|
||||||
val u = user.modify(_.guestStatus).setTo(guestStatus)
|
val u = user.modify(_.guestStatus).setTo(guestStatus)
|
||||||
users.save(u)
|
users.save(u)
|
||||||
|
UserDAO.update(u)
|
||||||
u
|
u
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -135,6 +142,7 @@ object RegisteredUsers {
|
|||||||
role: String): RegisteredUser = {
|
role: String): RegisteredUser = {
|
||||||
val u = user.modify(_.role).setTo(role)
|
val u = user.modify(_.role).setTo(role)
|
||||||
users.save(u)
|
users.save(u)
|
||||||
|
UserDAO.update(u)
|
||||||
u
|
u
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -148,6 +156,7 @@ object RegisteredUsers {
|
|||||||
def updateUserJoin(users: RegisteredUsers, user: RegisteredUser): RegisteredUser = {
|
def updateUserJoin(users: RegisteredUsers, user: RegisteredUser): RegisteredUser = {
|
||||||
val u = user.copy(joined = true)
|
val u = user.copy(joined = true)
|
||||||
users.save(u)
|
users.save(u)
|
||||||
|
UserDAO.update(u)
|
||||||
u
|
u
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -160,6 +169,7 @@ object RegisteredUsers {
|
|||||||
def setUserLoggedOutFlag(users: RegisteredUsers, user: RegisteredUser): RegisteredUser = {
|
def setUserLoggedOutFlag(users: RegisteredUsers, user: RegisteredUser): RegisteredUser = {
|
||||||
val u = user.copy(loggedOut = true)
|
val u = user.copy(loggedOut = true)
|
||||||
users.save(u)
|
users.save(u)
|
||||||
|
UserDAO.update(u)
|
||||||
u
|
u
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -191,6 +201,7 @@ case class RegisteredUser(
|
|||||||
role: String,
|
role: String,
|
||||||
authToken: String,
|
authToken: String,
|
||||||
avatarURL: String,
|
avatarURL: String,
|
||||||
|
color: String,
|
||||||
guest: Boolean,
|
guest: Boolean,
|
||||||
authed: Boolean,
|
authed: Boolean,
|
||||||
guestStatus: String,
|
guestStatus: String,
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package org.bigbluebutton.core.models
|
package org.bigbluebutton.core.models
|
||||||
|
|
||||||
import com.softwaremill.quicklens._
|
import com.softwaremill.quicklens._
|
||||||
|
import org.bigbluebutton.core.db.UserDAO
|
||||||
import org.bigbluebutton.core.util.TimeUtil
|
import org.bigbluebutton.core.util.TimeUtil
|
||||||
import org.bigbluebutton.core2.message.senders.MsgBuilder
|
import org.bigbluebutton.core2.message.senders.MsgBuilder
|
||||||
|
|
||||||
@ -34,6 +35,7 @@ object Users2x {
|
|||||||
} yield {
|
} yield {
|
||||||
val newUser = u.copy(userLeftFlag = UserLeftFlag(true, System.currentTimeMillis()))
|
val newUser = u.copy(userLeftFlag = UserLeftFlag(true, System.currentTimeMillis()))
|
||||||
users.save(newUser)
|
users.save(newUser)
|
||||||
|
UserDAO.update(newUser)
|
||||||
newUser
|
newUser
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -107,6 +109,13 @@ object Users2x {
|
|||||||
newUserState
|
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] = {
|
def ejectFromMeeting(users: Users2x, intId: String): Option[UserState] = {
|
||||||
for {
|
for {
|
||||||
_ <- users.remove(intId)
|
_ <- users.remove(intId)
|
||||||
@ -122,6 +131,7 @@ object Users2x {
|
|||||||
} yield {
|
} yield {
|
||||||
val newUser = u.modify(_.presenter).setTo(true)
|
val newUser = u.modify(_.presenter).setTo(true)
|
||||||
users.save(newUser)
|
users.save(newUser)
|
||||||
|
UserDAO.update(newUser)
|
||||||
newUser
|
newUser
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -132,6 +142,7 @@ object Users2x {
|
|||||||
} yield {
|
} yield {
|
||||||
val newUser = u.modify(_.presenter).setTo(false)
|
val newUser = u.modify(_.presenter).setTo(false)
|
||||||
users.save(newUser)
|
users.save(newUser)
|
||||||
|
UserDAO.update(newUser)
|
||||||
newUser
|
newUser
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -163,6 +174,7 @@ object Users2x {
|
|||||||
} yield {
|
} yield {
|
||||||
val newUser = u.modify(_.pin).setTo(pin)
|
val newUser = u.modify(_.pin).setTo(pin)
|
||||||
users.save(newUser)
|
users.save(newUser)
|
||||||
|
UserDAO.update(newUser)
|
||||||
newUser
|
newUser
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -173,6 +185,7 @@ object Users2x {
|
|||||||
} yield {
|
} yield {
|
||||||
val newUser = u.modify(_.emoji).setTo(emoji)
|
val newUser = u.modify(_.emoji).setTo(emoji)
|
||||||
users.save(newUser)
|
users.save(newUser)
|
||||||
|
UserDAO.update(newUser)
|
||||||
newUser
|
newUser
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -183,6 +196,7 @@ object Users2x {
|
|||||||
} yield {
|
} yield {
|
||||||
val newUser = u.modify(_.locked).setTo(locked)
|
val newUser = u.modify(_.locked).setTo(locked)
|
||||||
users.save(newUser)
|
users.save(newUser)
|
||||||
|
UserDAO.update(newUser)
|
||||||
newUser
|
newUser
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -354,12 +368,14 @@ case class UserState(
|
|||||||
role: String,
|
role: String,
|
||||||
guest: Boolean,
|
guest: Boolean,
|
||||||
pin: Boolean,
|
pin: Boolean,
|
||||||
|
mobile: Boolean,
|
||||||
authed: Boolean,
|
authed: Boolean,
|
||||||
guestStatus: String,
|
guestStatus: String,
|
||||||
emoji: String,
|
emoji: String,
|
||||||
locked: Boolean,
|
locked: Boolean,
|
||||||
presenter: Boolean,
|
presenter: Boolean,
|
||||||
avatar: String,
|
avatar: String,
|
||||||
|
color: String,
|
||||||
roleChangedOn: Long = System.currentTimeMillis(),
|
roleChangedOn: Long = System.currentTimeMillis(),
|
||||||
lastActivityTime: Long = System.currentTimeMillis(),
|
lastActivityTime: Long = System.currentTimeMillis(),
|
||||||
lastInactivityInspect: Long = 0,
|
lastInactivityInspect: Long = 0,
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package org.bigbluebutton.core.models
|
package org.bigbluebutton.core.models
|
||||||
|
|
||||||
import com.softwaremill.quicklens._
|
import com.softwaremill.quicklens._
|
||||||
|
import org.bigbluebutton.core.db.{ UserDAO, UserMicrophoneDAO }
|
||||||
|
|
||||||
object VoiceUsers {
|
object VoiceUsers {
|
||||||
def findWithVoiceUserId(users: VoiceUsers, voiceUserId: String): Option[VoiceUserState] = {
|
def findWithVoiceUserId(users: VoiceUsers, voiceUserId: String): Option[VoiceUserState] = {
|
||||||
@ -30,9 +31,11 @@ object VoiceUsers {
|
|||||||
|
|
||||||
def add(users: VoiceUsers, user: VoiceUserState): Unit = {
|
def add(users: VoiceUsers, user: VoiceUserState): Unit = {
|
||||||
users.save(user)
|
users.save(user)
|
||||||
|
UserMicrophoneDAO.insert(user)
|
||||||
}
|
}
|
||||||
|
|
||||||
def removeWithIntId(users: VoiceUsers, intId: String): Option[VoiceUserState] = {
|
def removeWithIntId(users: VoiceUsers, intId: String): Option[VoiceUserState] = {
|
||||||
|
UserMicrophoneDAO.deleteUser(intId)
|
||||||
users.remove(intId)
|
users.remove(intId)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -52,6 +55,7 @@ object VoiceUsers {
|
|||||||
.modify(_.talking).setTo(false)
|
.modify(_.talking).setTo(false)
|
||||||
.modify(_.lastStatusUpdateOn).setTo(System.currentTimeMillis())
|
.modify(_.lastStatusUpdateOn).setTo(System.currentTimeMillis())
|
||||||
users.save(vu)
|
users.save(vu)
|
||||||
|
UserMicrophoneDAO.update(vu)
|
||||||
vu
|
vu
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -64,6 +68,8 @@ object VoiceUsers {
|
|||||||
.modify(_.talking).setTo(talking)
|
.modify(_.talking).setTo(talking)
|
||||||
.modify(_.lastStatusUpdateOn).setTo(System.currentTimeMillis())
|
.modify(_.lastStatusUpdateOn).setTo(System.currentTimeMillis())
|
||||||
users.save(vu)
|
users.save(vu)
|
||||||
|
UserMicrophoneDAO.updateTalking(vu)
|
||||||
|
|
||||||
vu
|
vu
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -76,6 +82,7 @@ object VoiceUsers {
|
|||||||
.modify(_.lastFloorTime).setTo(timestamp)
|
.modify(_.lastFloorTime).setTo(timestamp)
|
||||||
.modify(_.lastStatusUpdateOn).setTo(System.currentTimeMillis())
|
.modify(_.lastStatusUpdateOn).setTo(System.currentTimeMillis())
|
||||||
users.save(vu)
|
users.save(vu)
|
||||||
|
UserMicrophoneDAO.update(vu)
|
||||||
vu
|
vu
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -87,6 +94,7 @@ object VoiceUsers {
|
|||||||
val vu = u.modify(_.floor).setTo(floor)
|
val vu = u.modify(_.floor).setTo(floor)
|
||||||
.modify(_.lastStatusUpdateOn).setTo(System.currentTimeMillis())
|
.modify(_.lastStatusUpdateOn).setTo(System.currentTimeMillis())
|
||||||
users.save(vu)
|
users.save(vu)
|
||||||
|
UserMicrophoneDAO.update(vu)
|
||||||
vu
|
vu
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
package org.bigbluebutton.core.models
|
package org.bigbluebutton.core.models
|
||||||
|
|
||||||
|
import org.bigbluebutton.core.db.UserCameraDAO
|
||||||
|
|
||||||
import collection.immutable.HashMap
|
import collection.immutable.HashMap
|
||||||
|
|
||||||
object Webcams {
|
object Webcams {
|
||||||
@ -15,14 +17,20 @@ object Webcams {
|
|||||||
|
|
||||||
def addWebcamStream(webcams: Webcams, webcam: WebcamStream): Option[WebcamStream] = {
|
def addWebcamStream(webcams: Webcams, webcam: WebcamStream): Option[WebcamStream] = {
|
||||||
findWithStreamId(webcams, webcam.streamId) match {
|
findWithStreamId(webcams, webcam.streamId) match {
|
||||||
case None => Some(webcams.save(webcam))
|
case None => {
|
||||||
|
UserCameraDAO.insert(webcam)
|
||||||
|
Some(webcams.save(webcam))
|
||||||
|
}
|
||||||
case _ => None
|
case _ => None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def removeWebcamStream(webcams: Webcams, streamId: String): Option[WebcamStream] = {
|
def removeWebcamStream(webcams: Webcams, streamId: String): Option[WebcamStream] = {
|
||||||
for {
|
for {
|
||||||
webcam <- webcams.remove(streamId)
|
webcam <- {
|
||||||
|
UserCameraDAO.delete(streamId)
|
||||||
|
webcams.remove(streamId)
|
||||||
|
}
|
||||||
} yield webcam
|
} yield webcam
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,6 +109,8 @@ class ReceivedJsonMsgHandlerActor(
|
|||||||
routeGenericMsg[UserActivitySignCmdMsg](envelope, jsonNode)
|
routeGenericMsg[UserActivitySignCmdMsg](envelope, jsonNode)
|
||||||
case ChangeUserPinStateReqMsg.NAME =>
|
case ChangeUserPinStateReqMsg.NAME =>
|
||||||
routeGenericMsg[ChangeUserPinStateReqMsg](envelope, jsonNode)
|
routeGenericMsg[ChangeUserPinStateReqMsg](envelope, jsonNode)
|
||||||
|
case ChangeUserMobileFlagReqMsg.NAME =>
|
||||||
|
routeGenericMsg[ChangeUserMobileFlagReqMsg](envelope, jsonNode)
|
||||||
case SelectRandomViewerReqMsg.NAME =>
|
case SelectRandomViewerReqMsg.NAME =>
|
||||||
routeGenericMsg[SelectRandomViewerReqMsg](envelope, jsonNode)
|
routeGenericMsg[SelectRandomViewerReqMsg](envelope, jsonNode)
|
||||||
|
|
||||||
|
@ -63,9 +63,11 @@ trait HandlerHelpers extends SystemConfiguration {
|
|||||||
guestStatus = regUser.guestStatus,
|
guestStatus = regUser.guestStatus,
|
||||||
emoji = "none",
|
emoji = "none",
|
||||||
pin = false,
|
pin = false,
|
||||||
|
mobile = false,
|
||||||
presenter = false,
|
presenter = false,
|
||||||
locked = MeetingStatus2x.getPermissions(liveMeeting.status).lockOnJoin,
|
locked = MeetingStatus2x.getPermissions(liveMeeting.status).lockOnJoin,
|
||||||
avatar = regUser.avatarURL,
|
avatar = regUser.avatarURL,
|
||||||
|
color = regUser.color,
|
||||||
clientType = clientType,
|
clientType = clientType,
|
||||||
pickExempted = false,
|
pickExempted = false,
|
||||||
userLeftFlag = UserLeftFlag(false, 0)
|
userLeftFlag = UserLeftFlag(false, 0)
|
||||||
|
@ -388,6 +388,7 @@ class MeetingActor(
|
|||||||
case m: ChangeUserEmojiCmdMsg => handleChangeUserEmojiCmdMsg(m)
|
case m: ChangeUserEmojiCmdMsg => handleChangeUserEmojiCmdMsg(m)
|
||||||
case m: SelectRandomViewerReqMsg => usersApp.handleSelectRandomViewerReqMsg(m)
|
case m: SelectRandomViewerReqMsg => usersApp.handleSelectRandomViewerReqMsg(m)
|
||||||
case m: ChangeUserPinStateReqMsg => usersApp.handleChangeUserPinStateReqMsg(m)
|
case m: ChangeUserPinStateReqMsg => usersApp.handleChangeUserPinStateReqMsg(m)
|
||||||
|
case m: ChangeUserMobileFlagReqMsg => usersApp.handleChangeUserMobileFlagReqMsg(m)
|
||||||
|
|
||||||
// Client requested to eject user
|
// Client requested to eject user
|
||||||
case m: EjectUserFromMeetingCmdMsg =>
|
case m: EjectUserFromMeetingCmdMsg =>
|
||||||
|
@ -77,6 +77,7 @@ class AnalyticsActor(val includeChat: Boolean) extends Actor with ActorLogging {
|
|||||||
case m: UserDisconnectedFromGlobalAudioMsg => logMessage(msg)
|
case m: UserDisconnectedFromGlobalAudioMsg => logMessage(msg)
|
||||||
case m: AssignPresenterReqMsg => logMessage(msg)
|
case m: AssignPresenterReqMsg => logMessage(msg)
|
||||||
case m: ChangeUserPinStateReqMsg => logMessage(msg)
|
case m: ChangeUserPinStateReqMsg => logMessage(msg)
|
||||||
|
case m: ChangeUserMobileFlagReqMsg => logMessage(msg)
|
||||||
case m: ScreenshareRtmpBroadcastStartedVoiceConfEvtMsg => logMessage(msg)
|
case m: ScreenshareRtmpBroadcastStartedVoiceConfEvtMsg => logMessage(msg)
|
||||||
case m: ScreenshareRtmpBroadcastStoppedVoiceConfEvtMsg => logMessage(msg)
|
case m: ScreenshareRtmpBroadcastStoppedVoiceConfEvtMsg => logMessage(msg)
|
||||||
case m: ScreenshareRtmpBroadcastStartedEvtMsg => logMessage(msg)
|
case m: ScreenshareRtmpBroadcastStartedEvtMsg => logMessage(msg)
|
||||||
|
@ -13,7 +13,7 @@ object UserJoinedMeetingEvtMsgBuilder {
|
|||||||
guestStatus = userState.guestStatus,
|
guestStatus = userState.guestStatus,
|
||||||
emoji = userState.emoji,
|
emoji = userState.emoji,
|
||||||
pin = userState.pin,
|
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)
|
clientType = userState.clientType)
|
||||||
|
|
||||||
val event = UserJoinedMeetingEvtMsg(meetingId, userState.intId, body)
|
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,
|
def createUserVoiceAndCam(liveMeeting: LiveMeeting, role: String, guest: Boolean, authed: Boolean, callingWith: String,
|
||||||
muted: Boolean, talking: Boolean, listenOnly: Boolean): UserState = {
|
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)
|
val vuser1 = FakeUserGenerator.createFakeVoiceUser(ruser1, "webrtc", muted = false, talking = true, listenOnly = false)
|
||||||
VoiceUsers.add(liveMeeting.voiceUsers, vuser1)
|
VoiceUsers.add(liveMeeting.voiceUsers, vuser1)
|
||||||
@ -67,8 +67,8 @@ trait FakeTestData {
|
|||||||
|
|
||||||
def createFakeUser(liveMeeting: LiveMeeting, regUser: RegisteredUser): UserState = {
|
def createFakeUser(liveMeeting: LiveMeeting, regUser: RegisteredUser): UserState = {
|
||||||
UserState(intId = regUser.id, extId = regUser.externId, name = regUser.name, role = regUser.role, pin = false,
|
UserState(intId = regUser.id, extId = regUser.externId, name = regUser.name, role = regUser.role, pin = false,
|
||||||
guest = regUser.guest, authed = regUser.authed, guestStatus = regUser.guestStatus,
|
mobile = false, guest = regUser.guest, authed = regUser.authed, guestStatus = regUser.guestStatus,
|
||||||
emoji = "none", locked = false, presenter = false, avatar = regUser.avatarURL, clientType = "unknown",
|
emoji = "none", locked = false, presenter = false, avatar = regUser.avatarURL, color = "#ff6242", clientType = "unknown",
|
||||||
pickExempted = false, userLeftFlag = UserLeftFlag(false, 0))
|
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))
|
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 name = getRandomElement(firstNames, random) + " " + getRandomElement(lastNames, random)
|
||||||
val id = "w_" + RandomStringGenerator.randomAlphanumericString(16)
|
val id = "w_" + RandomStringGenerator.randomAlphanumericString(16)
|
||||||
val extId = RandomStringGenerator.randomAlphanumericString(16)
|
val extId = RandomStringGenerator.randomAlphanumericString(16)
|
||||||
val authToken = RandomStringGenerator.randomAlphanumericString(16)
|
val authToken = RandomStringGenerator.randomAlphanumericString(16)
|
||||||
val avatarURL = "https://www." + RandomStringGenerator.randomAlphanumericString(32) + ".com/" +
|
val avatarURL = "https://www." + RandomStringGenerator.randomAlphanumericString(32) + ".com/" +
|
||||||
RandomStringGenerator.randomAlphanumericString(10) + ".png"
|
RandomStringGenerator.randomAlphanumericString(10) + ".png"
|
||||||
|
val color = "#ff6242"
|
||||||
|
|
||||||
val ru = RegisteredUsers.create(userId = id, extId, name, role,
|
val ru = RegisteredUsers.create(userId = id, extId, name, role,
|
||||||
authToken, avatarURL, guest, authed, guestStatus = GuestStatus.ALLOW, false, false)
|
authToken, avatarURL, color, guest, authed, guestStatus = GuestStatus.ALLOW, false, false)
|
||||||
RegisteredUsers.add(users, ru)
|
RegisteredUsers.add(users, ru, meetingId)
|
||||||
ru
|
ru
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
[Unit]
|
[Unit]
|
||||||
Description=BigBlueButton Apps (Akka)
|
Description=BigBlueButton Apps (Akka)
|
||||||
Requires=network.target
|
Requires=network.target
|
||||||
Wants=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
|
After=redis-server.service bbb-fsesl-akka.service postgresql.service
|
||||||
PartOf=bigbluebutton.target
|
PartOf=bigbluebutton.target
|
||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
|
@ -16,7 +16,7 @@ object TestDataGen {
|
|||||||
val ru = RegisteredUsers.create(userId = id, extId, name, role,
|
val ru = RegisteredUsers.create(userId = id, extId, name, role,
|
||||||
authToken, avatarURL, guest, authed, GuestStatus.ALLOW, false)
|
authToken, avatarURL, guest, authed, GuestStatus.ALLOW, false)
|
||||||
|
|
||||||
RegisteredUsers.add(users, ru)
|
RegisteredUsers.add(users, ru, meetingId = "test")
|
||||||
ru
|
ru
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -43,8 +43,8 @@ object TestDataGen {
|
|||||||
def createUserFor(liveMeeting: LiveMeeting, regUser: RegisteredUser, presenter: Boolean): UserState = {
|
def createUserFor(liveMeeting: LiveMeeting, regUser: RegisteredUser, presenter: Boolean): UserState = {
|
||||||
val u = UserState(intId = regUser.id, extId = regUser.externId, name = regUser.name, role = regUser.role,
|
val u = UserState(intId = regUser.id, extId = regUser.externId, name = regUser.name, role = regUser.role,
|
||||||
guest = regUser.guest, authed = regUser.authed, guestStatus = regUser.guestStatus,
|
guest = regUser.guest, authed = regUser.authed, guestStatus = regUser.guestStatus,
|
||||||
emoji = "none", locked = false, presenter = false, avatar = regUser.avatarURL, clientType = "unknown",
|
emoji = "none", locked = false, presenter = false, avatar = regUser.avatarURL, color = "#ff6242",
|
||||||
userLeftFlag = UserLeftFlag(false, 0))
|
clientType = "unknown", userLeftFlag = UserLeftFlag(false, 0))
|
||||||
Users2x.add(liveMeeting.users2x, u)
|
Users2x.add(liveMeeting.users2x, u)
|
||||||
u
|
u
|
||||||
}
|
}
|
||||||
|
@ -35,6 +35,21 @@ redis {
|
|||||||
keyExpiry=1209600
|
keyExpiry=1209600
|
||||||
}
|
}
|
||||||
|
|
||||||
|
postgres {
|
||||||
|
dataSourceClass = "org.postgresql.ds.PGSimpleDataSource"
|
||||||
|
properties = {
|
||||||
|
serverName = "localhost"
|
||||||
|
portNumber = "5432"
|
||||||
|
databaseName = "bigbluebutton"
|
||||||
|
user = "postgres"
|
||||||
|
password = "bigbluebutton"
|
||||||
|
}
|
||||||
|
numThreads = 1
|
||||||
|
maxConnections = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
expire {
|
expire {
|
||||||
# time in seconds
|
# time in seconds
|
||||||
lastUserLeft = 60
|
lastUserLeft = 60
|
||||||
|
@ -88,11 +88,22 @@ case class UserJoinedMeetingEvtMsg(
|
|||||||
header: BbbClientMsgHeader,
|
header: BbbClientMsgHeader,
|
||||||
body: UserJoinedMeetingEvtMsgBody
|
body: UserJoinedMeetingEvtMsgBody
|
||||||
) extends BbbCoreMsg
|
) extends BbbCoreMsg
|
||||||
case class UserJoinedMeetingEvtMsgBody(intId: String, extId: String, name: String, role: String,
|
case class UserJoinedMeetingEvtMsgBody(
|
||||||
guest: Boolean, authed: Boolean, guestStatus: String,
|
intId: String,
|
||||||
|
extId: String,
|
||||||
|
name: String,
|
||||||
|
role: String,
|
||||||
|
guest: Boolean,
|
||||||
|
authed: Boolean,
|
||||||
|
guestStatus: String,
|
||||||
emoji: String,
|
emoji: String,
|
||||||
pin: Boolean,
|
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.
|
* 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 UserEmojiChangedEvtMsg(header: BbbClientMsgHeader, body: UserEmojiChangedEvtMsgBody) extends BbbCoreMsg
|
||||||
case class UserEmojiChangedEvtMsgBody(userId: String, emoji: String)
|
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" }
|
object AssignPresenterReqMsg { val NAME = "AssignPresenterReqMsg" }
|
||||||
case class AssignPresenterReqMsg(header: BbbClientMsgHeader, body: AssignPresenterReqMsgBody) extends StandardMsg
|
case class AssignPresenterReqMsg(header: BbbClientMsgHeader, body: AssignPresenterReqMsgBody) extends StandardMsg
|
||||||
case class AssignPresenterReqMsgBody(requesterId: String, newPresenterId: String, newPresenterName: String, assignedBy: String)
|
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 GuestUsers from '/imports/api/guest-users/';
|
||||||
import updatePositionInWaitingQueue from '../methods/updatePositionInWaitingQueue';
|
import updatePositionInWaitingQueue from '../methods/updatePositionInWaitingQueue';
|
||||||
|
|
||||||
|
//TODO receive color from akka-apps
|
||||||
const COLOR_LIST = [
|
const COLOR_LIST = [
|
||||||
'#7b1fa2', '#6a1b9a', '#4a148c', '#5e35b1', '#512da8', '#4527a0',
|
'#7b1fa2', '#6a1b9a', '#4a148c', '#5e35b1', '#512da8', '#4527a0',
|
||||||
'#311b92', '#3949ab', '#303f9f', '#283593', '#1a237e', '#1976d2', '#1565c0',
|
'#311b92', '#3949ab', '#303f9f', '#283593', '#1a237e', '#1976d2', '#1565c0',
|
||||||
|
@ -8,6 +8,7 @@ import handleEmojiStatus from './handlers/emojiStatus';
|
|||||||
import handleChangeRole from './handlers/changeRole';
|
import handleChangeRole from './handlers/changeRole';
|
||||||
import handleUserPinChanged from './handlers/userPinChanged';
|
import handleUserPinChanged from './handlers/userPinChanged';
|
||||||
import handleUserInactivityInspect from './handlers/userInactivityInspect';
|
import handleUserInactivityInspect from './handlers/userInactivityInspect';
|
||||||
|
import handleChangeMobileFlag from "/imports/api/users/server/handlers/changeMobileFlag";
|
||||||
|
|
||||||
RedisPubSub.on('PresenterAssignedEvtMsg', handlePresenterAssigned);
|
RedisPubSub.on('PresenterAssignedEvtMsg', handlePresenterAssigned);
|
||||||
RedisPubSub.on('UserJoinedMeetingEvtMsg', handleUserJoined);
|
RedisPubSub.on('UserJoinedMeetingEvtMsg', handleUserJoined);
|
||||||
@ -15,6 +16,7 @@ RedisPubSub.on('UserLeftMeetingEvtMsg', handleRemoveUser);
|
|||||||
RedisPubSub.on('ValidateAuthTokenRespMsg', handleValidateAuthToken);
|
RedisPubSub.on('ValidateAuthTokenRespMsg', handleValidateAuthToken);
|
||||||
RedisPubSub.on('UserEmojiChangedEvtMsg', handleEmojiStatus);
|
RedisPubSub.on('UserEmojiChangedEvtMsg', handleEmojiStatus);
|
||||||
RedisPubSub.on('UserRoleChangedEvtMsg', handleChangeRole);
|
RedisPubSub.on('UserRoleChangedEvtMsg', handleChangeRole);
|
||||||
|
RedisPubSub.on('UserMobileFlagChangedEvtMsg', handleChangeMobileFlag);
|
||||||
RedisPubSub.on('UserLeftFlagUpdatedEvtMsg', handleUserLeftFlagUpdated);
|
RedisPubSub.on('UserLeftFlagUpdatedEvtMsg', handleUserLeftFlagUpdated);
|
||||||
RedisPubSub.on('UserPinStateChangedEvtMsg', handleUserPinChanged);
|
RedisPubSub.on('UserPinStateChangedEvtMsg', handleUserPinChanged);
|
||||||
RedisPubSub.on('UserInactivityInspectMsg', handleUserInactivityInspect);
|
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 Logger from '/imports/startup/server/logger';
|
||||||
import setMobile from '../modifiers/setMobile';
|
import setMobile from '../modifiers/setMobile';
|
||||||
import { extractCredentials } from '/imports/api/common/server/helpers';
|
import { extractCredentials } from '/imports/api/common/server/helpers';
|
||||||
|
import RedisPubSub from "/imports/startup/server/redis";
|
||||||
|
|
||||||
export default function setMobileUser() {
|
export default function setMobileUser() {
|
||||||
try {
|
try {
|
||||||
|
const REDIS_CONFIG = Meteor.settings.private.redis;
|
||||||
|
const CHANNEL = REDIS_CONFIG.channels.toAkkaApps;
|
||||||
|
const EVENT_NAME = 'ChangeUserMobileFlagReqMsg';
|
||||||
|
|
||||||
const { meetingId, requesterUserId } = extractCredentials(this.userId);
|
const { meetingId, requesterUserId } = extractCredentials(this.userId);
|
||||||
|
|
||||||
check(meetingId, String);
|
check(meetingId, String);
|
||||||
check(requesterUserId, String);
|
check(requesterUserId, String);
|
||||||
|
|
||||||
|
const payload = {
|
||||||
|
userId: requesterUserId,
|
||||||
|
mobile: true,
|
||||||
|
};
|
||||||
|
|
||||||
Logger.verbose(`Mobile user ${requesterUserId} from meeting ${meetingId}`);
|
Logger.verbose(`Mobile user ${requesterUserId} from meeting ${meetingId}`);
|
||||||
|
|
||||||
setMobile(meetingId, requesterUserId);
|
RedisPubSub.publishUserMessage(CHANNEL, EVENT_NAME, meetingId, requesterUserId, payload);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
Logger.error(`Exception while invoking method setMobileUser ${err.stack}`);
|
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';
|
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) {
|
export default function addUser(meetingId, userData) {
|
||||||
const user = userData;
|
const user = userData;
|
||||||
|
|
||||||
@ -34,6 +28,7 @@ export default function addUser(meetingId, userData) {
|
|||||||
presenter: Boolean,
|
presenter: Boolean,
|
||||||
locked: Boolean,
|
locked: Boolean,
|
||||||
avatar: String,
|
avatar: String,
|
||||||
|
color: String,
|
||||||
pin: Boolean,
|
pin: Boolean,
|
||||||
clientType: String,
|
clientType: String,
|
||||||
});
|
});
|
||||||
@ -46,14 +41,9 @@ export default function addUser(meetingId, userData) {
|
|||||||
};
|
};
|
||||||
const Meeting = Meetings.findOne({ meetingId });
|
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 = {
|
const userInfos = {
|
||||||
meetingId,
|
meetingId,
|
||||||
sortName: lowercaseTrim(user.name),
|
sortName: lowercaseTrim(user.name),
|
||||||
color,
|
|
||||||
speechLocale: '',
|
speechLocale: '',
|
||||||
mobile: false,
|
mobile: false,
|
||||||
breakoutProps: {
|
breakoutProps: {
|
||||||
|
Loading…
Reference in New Issue
Block a user