From 42711ac5aeaf1c36618dbc5a26fa4130c95e0450 Mon Sep 17 00:00:00 2001 From: Gustavo Trott Date: Wed, 8 Mar 2023 12:23:45 -0300 Subject: [PATCH] Initial implementation of Postgres data and Hasura --- akka-bbb-apps/project/Dependencies.scala | 13 +- .../ChangeUserMobileFlagReqMsgHdlr.scala | 42 ++++ .../apps/users/RegisterUserReqMsgHdlr.scala | 10 +- .../core/apps/users/UsersApp.scala | 1 + .../voice/UserJoinedVoiceConfEvtMsgHdlr.scala | 16 +- .../core/db/DatabaseConnection.scala | 9 + .../bigbluebutton/core/db/UserCameraDAO.scala | 52 +++++ .../org/bigbluebutton/core/db/UserDAO.scala | 211 ++++++++++++++++++ .../core/db/UserMicrophoneDAO.scala | 167 ++++++++++++++ .../core/models/RegisteredUsers.scala | 17 +- .../bigbluebutton/core/models/Users2x.scala | 16 ++ .../core/models/VoiceUsers.scala | 8 + .../bigbluebutton/core/models/Webcams.scala | 14 +- .../senders/ReceivedJsonMsgHandlerActor.scala | 2 + .../core/running/HandlerHelpers.scala | 2 + .../core/running/MeetingActor.scala | 9 +- .../bigbluebutton/core2/AnalyticsActor.scala | 1 + .../UserJoinedMeetingEvtMsgBuilder.scala | 2 +- .../core2/testdata/FakeTestData.scala | 6 +- .../core2/testdata/FakeUserGenerator.scala | 7 +- .../systemloader/systemd/start-template | 4 +- .../core2/testdata/TestDataGen.scala | 6 +- .../src/universal/conf/application.conf | 15 ++ .../common2/msgs/UsersMsgs.scala | 35 ++- bbb-graphql-server/bbb-graphql-server.service | 25 +++ bbb-graphql-server/bbb_schema.sql | 74 ++++++ bbb-graphql-server/config.yaml | 6 + bbb-graphql-server/hasura-config.env | 5 + bbb-graphql-server/install-hasura.sh | 69 ++++++ bbb-graphql-server/metadata/actions.graphql | 0 bbb-graphql-server/metadata/actions.yaml | 6 + bbb-graphql-server/metadata/allow_list.yaml | 1 + bbb-graphql-server/metadata/api_limits.yaml | 1 + .../metadata/backend_configs.yaml | 1 + .../metadata/cron_triggers.yaml | 1 + .../BigBlueButton/tables/public_user.yaml | 66 ++++++ .../tables/public_user_camera.yaml | 3 + .../tables/public_user_microphone.yaml | 3 + .../tables/public_v_user_camera.yaml | 13 ++ .../tables/public_v_user_microphone.yaml | 27 +++ .../BigBlueButton/tables/tables.yaml | 5 + .../metadata/databases/databases.yaml | 28 +++ .../databases/default/tables/tables.yaml | 1 + .../graphql_schema_introspection.yaml | 1 + .../metadata/inherited_roles.yaml | 1 + .../metadata/metrics_config.yaml | 1 + bbb-graphql-server/metadata/network.yaml | 1 + .../metadata/opentelemetry.yaml | 1 + .../metadata/query_collections.yaml | 1 + .../metadata/remote_schemas.yaml | 1 + .../metadata/rest_endpoints.yaml | 1 + bbb-graphql-server/metadata/version.yaml | 1 + .../handlers/guestsWaitingForApproval.js | 1 + .../imports/api/users/server/eventHandlers.js | 2 + .../users/server/handlers/changeMobileFlag.js | 13 ++ .../api/users/server/methods/setMobileUser.js | 12 +- .../api/users/server/modifiers/addUser.js | 12 +- 57 files changed, 1002 insertions(+), 47 deletions(-) create mode 100644 akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/users/ChangeUserMobileFlagReqMsgHdlr.scala create mode 100644 akka-bbb-apps/src/main/scala/org/bigbluebutton/core/db/DatabaseConnection.scala create mode 100644 akka-bbb-apps/src/main/scala/org/bigbluebutton/core/db/UserCameraDAO.scala create mode 100644 akka-bbb-apps/src/main/scala/org/bigbluebutton/core/db/UserDAO.scala create mode 100644 akka-bbb-apps/src/main/scala/org/bigbluebutton/core/db/UserMicrophoneDAO.scala create mode 100644 bbb-graphql-server/bbb-graphql-server.service create mode 100644 bbb-graphql-server/bbb_schema.sql create mode 100644 bbb-graphql-server/config.yaml create mode 100644 bbb-graphql-server/hasura-config.env create mode 100755 bbb-graphql-server/install-hasura.sh create mode 100644 bbb-graphql-server/metadata/actions.graphql create mode 100644 bbb-graphql-server/metadata/actions.yaml create mode 100644 bbb-graphql-server/metadata/allow_list.yaml create mode 100644 bbb-graphql-server/metadata/api_limits.yaml create mode 100644 bbb-graphql-server/metadata/backend_configs.yaml create mode 100644 bbb-graphql-server/metadata/cron_triggers.yaml create mode 100644 bbb-graphql-server/metadata/databases/BigBlueButton/tables/public_user.yaml create mode 100644 bbb-graphql-server/metadata/databases/BigBlueButton/tables/public_user_camera.yaml create mode 100644 bbb-graphql-server/metadata/databases/BigBlueButton/tables/public_user_microphone.yaml create mode 100644 bbb-graphql-server/metadata/databases/BigBlueButton/tables/public_v_user_camera.yaml create mode 100644 bbb-graphql-server/metadata/databases/BigBlueButton/tables/public_v_user_microphone.yaml create mode 100644 bbb-graphql-server/metadata/databases/BigBlueButton/tables/tables.yaml create mode 100644 bbb-graphql-server/metadata/databases/databases.yaml create mode 100644 bbb-graphql-server/metadata/databases/default/tables/tables.yaml create mode 100644 bbb-graphql-server/metadata/graphql_schema_introspection.yaml create mode 100644 bbb-graphql-server/metadata/inherited_roles.yaml create mode 100644 bbb-graphql-server/metadata/metrics_config.yaml create mode 100644 bbb-graphql-server/metadata/network.yaml create mode 100644 bbb-graphql-server/metadata/opentelemetry.yaml create mode 100644 bbb-graphql-server/metadata/query_collections.yaml create mode 100644 bbb-graphql-server/metadata/remote_schemas.yaml create mode 100644 bbb-graphql-server/metadata/rest_endpoints.yaml create mode 100644 bbb-graphql-server/metadata/version.yaml create mode 100644 bigbluebutton-html5/imports/api/users/server/handlers/changeMobileFlag.js diff --git a/akka-bbb-apps/project/Dependencies.scala b/akka-bbb-apps/project/Dependencies.scala index ae92f4034f..ac977775c3 100755 --- a/akka-bbb-apps/project/Dependencies.scala +++ b/akka-bbb-apps/project/Dependencies.scala @@ -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 } diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/users/ChangeUserMobileFlagReqMsgHdlr.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/users/ChangeUserMobileFlagReqMsgHdlr.scala new file mode 100644 index 0000000000..ae1479a4e8 --- /dev/null +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/users/ChangeUserMobileFlagReqMsgHdlr.scala @@ -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) + } + } + + } +} diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/users/RegisterUserReqMsgHdlr.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/users/RegisterUserReqMsgHdlr.scala index cee8251428..9346ba2286 100755 --- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/users/RegisterUserReqMsgHdlr.scala +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/users/RegisterUserReqMsgHdlr.scala @@ -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) diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/users/UsersApp.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/users/UsersApp.scala index 5d597bbfb8..5d821efc35 100755 --- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/users/UsersApp.scala +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/users/UsersApp.scala @@ -158,6 +158,7 @@ class UsersApp( with SelectRandomViewerReqMsgHdlr with AssignPresenterReqMsgHdlr with ChangeUserPinStateReqMsgHdlr + with ChangeUserMobileFlagReqMsgHdlr with EjectUserFromMeetingCmdMsgHdlr with EjectUserFromMeetingSysMsgHdlr with MuteUserCmdMsgHdlr { diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/voice/UserJoinedVoiceConfEvtMsgHdlr.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/voice/UserJoinedVoiceConfEvtMsgHdlr.scala index 5ea211ffec..16668c9006 100755 --- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/voice/UserJoinedVoiceConfEvtMsgHdlr.scala +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/voice/UserJoinedVoiceConfEvtMsgHdlr.scala @@ -2,12 +2,14 @@ package org.bigbluebutton.core.apps.voice import org.bigbluebutton.SystemConfiguration import org.bigbluebutton.common2.msgs._ -import org.bigbluebutton.core.running.{ LiveMeeting, MeetingActor, OutMsgRouter } +import org.bigbluebutton.core.running.{LiveMeeting, MeetingActor, OutMsgRouter} import org.bigbluebutton.core2.message.senders.MsgBuilder 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) diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/db/DatabaseConnection.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/db/DatabaseConnection.scala new file mode 100644 index 0000000000..6973fe451f --- /dev/null +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/db/DatabaseConnection.scala @@ -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() +} diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/db/UserCameraDAO.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/db/UserCameraDAO.scala new file mode 100644 index 0000000000..e672041e95 --- /dev/null +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/db/UserCameraDAO.scala @@ -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") + } + } + + +} diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/db/UserDAO.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/db/UserDAO.scala new file mode 100644 index 0000000000..2118996a28 --- /dev/null +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/db/UserDAO.scala @@ -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") + } + } + } + } + +} diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/db/UserMicrophoneDAO.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/db/UserMicrophoneDAO.scala new file mode 100644 index 0000000000..5bb59af412 --- /dev/null +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/db/UserMicrophoneDAO.scala @@ -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") + } + } + + +} diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/models/RegisteredUsers.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/models/RegisteredUsers.scala index 5169ba5068..c19990ffb1 100755 --- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/models/RegisteredUsers.scala +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/models/RegisteredUsers.scala @@ -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, diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/models/Users2x.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/models/Users2x.scala index b0e9c8498e..a9179ebb41 100755 --- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/models/Users2x.scala +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/models/Users2x.scala @@ -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, diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/models/VoiceUsers.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/models/VoiceUsers.scala index b89414f50b..b55d9a36e6 100755 --- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/models/VoiceUsers.scala +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/models/VoiceUsers.scala @@ -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 } } diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/models/Webcams.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/models/Webcams.scala index 075849b56d..f0e0dfa024 100755 --- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/models/Webcams.scala +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/models/Webcams.scala @@ -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 + 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 } diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/pubsub/senders/ReceivedJsonMsgHandlerActor.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/pubsub/senders/ReceivedJsonMsgHandlerActor.scala index edfee4f9d3..98808f3e90 100755 --- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/pubsub/senders/ReceivedJsonMsgHandlerActor.scala +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/pubsub/senders/ReceivedJsonMsgHandlerActor.scala @@ -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) diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/running/HandlerHelpers.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/running/HandlerHelpers.scala index eb852acc7d..857459c85d 100755 --- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/running/HandlerHelpers.scala +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/running/HandlerHelpers.scala @@ -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) diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/running/MeetingActor.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/running/MeetingActor.scala index c7b3032cbd..3c62400cff 100755 --- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/running/MeetingActor.scala +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/running/MeetingActor.scala @@ -384,10 +384,11 @@ class MeetingActor( case m: RecordAndClearPreviousMarkersCmdMsg => state = usersApp.handleRecordAndClearPreviousMarkersCmdMsg(m, state) updateUserLastActivity(m.body.setBy) - case m: GetRecordingStatusReqMsg => usersApp.handleGetRecordingStatusReqMsg(m) - case m: ChangeUserEmojiCmdMsg => handleChangeUserEmojiCmdMsg(m) - case m: SelectRandomViewerReqMsg => usersApp.handleSelectRandomViewerReqMsg(m) - case m: ChangeUserPinStateReqMsg => usersApp.handleChangeUserPinStateReqMsg(m) + case m: GetRecordingStatusReqMsg => usersApp.handleGetRecordingStatusReqMsg(m) + 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 => diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core2/AnalyticsActor.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core2/AnalyticsActor.scala index be964dc2eb..5949199738 100755 --- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core2/AnalyticsActor.scala +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core2/AnalyticsActor.scala @@ -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) diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core2/message/senders/UserJoinedMeetingEvtMsgBuilder.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core2/message/senders/UserJoinedMeetingEvtMsgBuilder.scala index 21fb32ad50..4a6d3d7a9a 100755 --- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core2/message/senders/UserJoinedMeetingEvtMsgBuilder.scala +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core2/message/senders/UserJoinedMeetingEvtMsgBuilder.scala @@ -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) diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core2/testdata/FakeTestData.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core2/testdata/FakeTestData.scala index b892fa7b06..6424a6a515 100755 --- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core2/testdata/FakeTestData.scala +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core2/testdata/FakeTestData.scala @@ -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)) } diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core2/testdata/FakeUserGenerator.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core2/testdata/FakeUserGenerator.scala index 47bf72abad..17b05d55ff 100755 --- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core2/testdata/FakeUserGenerator.scala +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core2/testdata/FakeUserGenerator.scala @@ -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 } diff --git a/akka-bbb-apps/src/templates/systemloader/systemd/start-template b/akka-bbb-apps/src/templates/systemloader/systemd/start-template index cf2f7a5f5b..8ade30967a 100644 --- a/akka-bbb-apps/src/templates/systemloader/systemd/start-template +++ b/akka-bbb-apps/src/templates/systemloader/systemd/start-template @@ -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] diff --git a/akka-bbb-apps/src/test/scala/org/bigbluebutton/core2/testdata/TestDataGen.scala b/akka-bbb-apps/src/test/scala/org/bigbluebutton/core2/testdata/TestDataGen.scala index 566c5caf1b..f004738f0e 100755 --- a/akka-bbb-apps/src/test/scala/org/bigbluebutton/core2/testdata/TestDataGen.scala +++ b/akka-bbb-apps/src/test/scala/org/bigbluebutton/core2/testdata/TestDataGen.scala @@ -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 } diff --git a/akka-bbb-apps/src/universal/conf/application.conf b/akka-bbb-apps/src/universal/conf/application.conf index 3f5ce4803f..482e1218a3 100755 --- a/akka-bbb-apps/src/universal/conf/application.conf +++ b/akka-bbb-apps/src/universal/conf/application.conf @@ -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 diff --git a/bbb-common-message/src/main/scala/org/bigbluebutton/common2/msgs/UsersMsgs.scala b/bbb-common-message/src/main/scala/org/bigbluebutton/common2/msgs/UsersMsgs.scala index 9bb8888262..6736acef1b 100755 --- a/bbb-common-message/src/main/scala/org/bigbluebutton/common2/msgs/UsersMsgs.scala +++ b/bbb-common-message/src/main/scala/org/bigbluebutton/common2/msgs/UsersMsgs.scala @@ -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, - emoji: String, - pin: Boolean, - presenter: Boolean, locked: Boolean, avatar: String, clientType: 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, + 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) diff --git a/bbb-graphql-server/bbb-graphql-server.service b/bbb-graphql-server/bbb-graphql-server.service new file mode 100644 index 0000000000..bc7f85a733 --- /dev/null +++ b/bbb-graphql-server/bbb-graphql-server.service @@ -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 + diff --git a/bbb-graphql-server/bbb_schema.sql b/bbb-graphql-server/bbb_schema.sql new file mode 100644 index 0000000000..4172501eaa --- /dev/null +++ b/bbb-graphql-server/bbb_schema.sql @@ -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"; \ No newline at end of file diff --git a/bbb-graphql-server/config.yaml b/bbb-graphql-server/config.yaml new file mode 100644 index 0000000000..725c8005e8 --- /dev/null +++ b/bbb-graphql-server/config.yaml @@ -0,0 +1,6 @@ +version: 3 +endpoint: http://localhost:8080 +metadata_directory: metadata +actions: + kind: synchronous + handler_webhook_baseurl: http://localhost:3000 diff --git a/bbb-graphql-server/hasura-config.env b/bbb-graphql-server/hasura-config.env new file mode 100644 index 0000000000..baa165e98f --- /dev/null +++ b/bbb-graphql-server/hasura-config.env @@ -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 \ No newline at end of file diff --git a/bbb-graphql-server/install-hasura.sh b/bbb-graphql-server/install-hasura.sh new file mode 100755 index 0000000000..97e315d8d9 --- /dev/null +++ b/bbb-graphql-server/install-hasura.sh @@ -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 + diff --git a/bbb-graphql-server/metadata/actions.graphql b/bbb-graphql-server/metadata/actions.graphql new file mode 100644 index 0000000000..e69de29bb2 diff --git a/bbb-graphql-server/metadata/actions.yaml b/bbb-graphql-server/metadata/actions.yaml new file mode 100644 index 0000000000..1edb4c2ffc --- /dev/null +++ b/bbb-graphql-server/metadata/actions.yaml @@ -0,0 +1,6 @@ +actions: [] +custom_types: + enums: [] + input_objects: [] + objects: [] + scalars: [] diff --git a/bbb-graphql-server/metadata/allow_list.yaml b/bbb-graphql-server/metadata/allow_list.yaml new file mode 100644 index 0000000000..fe51488c70 --- /dev/null +++ b/bbb-graphql-server/metadata/allow_list.yaml @@ -0,0 +1 @@ +[] diff --git a/bbb-graphql-server/metadata/api_limits.yaml b/bbb-graphql-server/metadata/api_limits.yaml new file mode 100644 index 0000000000..0967ef424b --- /dev/null +++ b/bbb-graphql-server/metadata/api_limits.yaml @@ -0,0 +1 @@ +{} diff --git a/bbb-graphql-server/metadata/backend_configs.yaml b/bbb-graphql-server/metadata/backend_configs.yaml new file mode 100644 index 0000000000..0967ef424b --- /dev/null +++ b/bbb-graphql-server/metadata/backend_configs.yaml @@ -0,0 +1 @@ +{} diff --git a/bbb-graphql-server/metadata/cron_triggers.yaml b/bbb-graphql-server/metadata/cron_triggers.yaml new file mode 100644 index 0000000000..fe51488c70 --- /dev/null +++ b/bbb-graphql-server/metadata/cron_triggers.yaml @@ -0,0 +1 @@ +[] diff --git a/bbb-graphql-server/metadata/databases/BigBlueButton/tables/public_user.yaml b/bbb-graphql-server/metadata/databases/BigBlueButton/tables/public_user.yaml new file mode 100644 index 0000000000..b10fc69195 --- /dev/null +++ b/bbb-graphql-server/metadata/databases/BigBlueButton/tables/public_user.yaml @@ -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 diff --git a/bbb-graphql-server/metadata/databases/BigBlueButton/tables/public_user_camera.yaml b/bbb-graphql-server/metadata/databases/BigBlueButton/tables/public_user_camera.yaml new file mode 100644 index 0000000000..462c23e553 --- /dev/null +++ b/bbb-graphql-server/metadata/databases/BigBlueButton/tables/public_user_camera.yaml @@ -0,0 +1,3 @@ +table: + name: user_camera + schema: public diff --git a/bbb-graphql-server/metadata/databases/BigBlueButton/tables/public_user_microphone.yaml b/bbb-graphql-server/metadata/databases/BigBlueButton/tables/public_user_microphone.yaml new file mode 100644 index 0000000000..d4d0106174 --- /dev/null +++ b/bbb-graphql-server/metadata/databases/BigBlueButton/tables/public_user_microphone.yaml @@ -0,0 +1,3 @@ +table: + name: user_microphone + schema: public diff --git a/bbb-graphql-server/metadata/databases/BigBlueButton/tables/public_v_user_camera.yaml b/bbb-graphql-server/metadata/databases/BigBlueButton/tables/public_v_user_camera.yaml new file mode 100644 index 0000000000..0917270791 --- /dev/null +++ b/bbb-graphql-server/metadata/databases/BigBlueButton/tables/public_v_user_camera.yaml @@ -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 diff --git a/bbb-graphql-server/metadata/databases/BigBlueButton/tables/public_v_user_microphone.yaml b/bbb-graphql-server/metadata/databases/BigBlueButton/tables/public_v_user_microphone.yaml new file mode 100644 index 0000000000..0e96a3e6ae --- /dev/null +++ b/bbb-graphql-server/metadata/databases/BigBlueButton/tables/public_v_user_microphone.yaml @@ -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 diff --git a/bbb-graphql-server/metadata/databases/BigBlueButton/tables/tables.yaml b/bbb-graphql-server/metadata/databases/BigBlueButton/tables/tables.yaml new file mode 100644 index 0000000000..27853ff3e8 --- /dev/null +++ b/bbb-graphql-server/metadata/databases/BigBlueButton/tables/tables.yaml @@ -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" diff --git a/bbb-graphql-server/metadata/databases/databases.yaml b/bbb-graphql-server/metadata/databases/databases.yaml new file mode 100644 index 0000000000..372c24c1b9 --- /dev/null +++ b/bbb-graphql-server/metadata/databases/databases.yaml @@ -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" diff --git a/bbb-graphql-server/metadata/databases/default/tables/tables.yaml b/bbb-graphql-server/metadata/databases/default/tables/tables.yaml new file mode 100644 index 0000000000..fe51488c70 --- /dev/null +++ b/bbb-graphql-server/metadata/databases/default/tables/tables.yaml @@ -0,0 +1 @@ +[] diff --git a/bbb-graphql-server/metadata/graphql_schema_introspection.yaml b/bbb-graphql-server/metadata/graphql_schema_introspection.yaml new file mode 100644 index 0000000000..61a4dcac29 --- /dev/null +++ b/bbb-graphql-server/metadata/graphql_schema_introspection.yaml @@ -0,0 +1 @@ +disabled_for_roles: [] diff --git a/bbb-graphql-server/metadata/inherited_roles.yaml b/bbb-graphql-server/metadata/inherited_roles.yaml new file mode 100644 index 0000000000..fe51488c70 --- /dev/null +++ b/bbb-graphql-server/metadata/inherited_roles.yaml @@ -0,0 +1 @@ +[] diff --git a/bbb-graphql-server/metadata/metrics_config.yaml b/bbb-graphql-server/metadata/metrics_config.yaml new file mode 100644 index 0000000000..0967ef424b --- /dev/null +++ b/bbb-graphql-server/metadata/metrics_config.yaml @@ -0,0 +1 @@ +{} diff --git a/bbb-graphql-server/metadata/network.yaml b/bbb-graphql-server/metadata/network.yaml new file mode 100644 index 0000000000..0967ef424b --- /dev/null +++ b/bbb-graphql-server/metadata/network.yaml @@ -0,0 +1 @@ +{} diff --git a/bbb-graphql-server/metadata/opentelemetry.yaml b/bbb-graphql-server/metadata/opentelemetry.yaml new file mode 100644 index 0000000000..0967ef424b --- /dev/null +++ b/bbb-graphql-server/metadata/opentelemetry.yaml @@ -0,0 +1 @@ +{} diff --git a/bbb-graphql-server/metadata/query_collections.yaml b/bbb-graphql-server/metadata/query_collections.yaml new file mode 100644 index 0000000000..fe51488c70 --- /dev/null +++ b/bbb-graphql-server/metadata/query_collections.yaml @@ -0,0 +1 @@ +[] diff --git a/bbb-graphql-server/metadata/remote_schemas.yaml b/bbb-graphql-server/metadata/remote_schemas.yaml new file mode 100644 index 0000000000..fe51488c70 --- /dev/null +++ b/bbb-graphql-server/metadata/remote_schemas.yaml @@ -0,0 +1 @@ +[] diff --git a/bbb-graphql-server/metadata/rest_endpoints.yaml b/bbb-graphql-server/metadata/rest_endpoints.yaml new file mode 100644 index 0000000000..fe51488c70 --- /dev/null +++ b/bbb-graphql-server/metadata/rest_endpoints.yaml @@ -0,0 +1 @@ +[] diff --git a/bbb-graphql-server/metadata/version.yaml b/bbb-graphql-server/metadata/version.yaml new file mode 100644 index 0000000000..0a70affa4b --- /dev/null +++ b/bbb-graphql-server/metadata/version.yaml @@ -0,0 +1 @@ +version: 3 diff --git a/bigbluebutton-html5/imports/api/guest-users/server/handlers/guestsWaitingForApproval.js b/bigbluebutton-html5/imports/api/guest-users/server/handlers/guestsWaitingForApproval.js index 0f221d2d22..e1446ef96a 100644 --- a/bigbluebutton-html5/imports/api/guest-users/server/handlers/guestsWaitingForApproval.js +++ b/bigbluebutton-html5/imports/api/guest-users/server/handlers/guestsWaitingForApproval.js @@ -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', diff --git a/bigbluebutton-html5/imports/api/users/server/eventHandlers.js b/bigbluebutton-html5/imports/api/users/server/eventHandlers.js index fea9ed8ebf..3f429042b9 100644 --- a/bigbluebutton-html5/imports/api/users/server/eventHandlers.js +++ b/bigbluebutton-html5/imports/api/users/server/eventHandlers.js @@ -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); diff --git a/bigbluebutton-html5/imports/api/users/server/handlers/changeMobileFlag.js b/bigbluebutton-html5/imports/api/users/server/handlers/changeMobileFlag.js new file mode 100644 index 0000000000..24c4b07c5b --- /dev/null +++ b/bigbluebutton-html5/imports/api/users/server/handlers/changeMobileFlag.js @@ -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); + } +} diff --git a/bigbluebutton-html5/imports/api/users/server/methods/setMobileUser.js b/bigbluebutton-html5/imports/api/users/server/methods/setMobileUser.js index fa6dd68dc1..11083e74d7 100644 --- a/bigbluebutton-html5/imports/api/users/server/methods/setMobileUser.js +++ b/bigbluebutton-html5/imports/api/users/server/methods/setMobileUser.js @@ -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}`); } diff --git a/bigbluebutton-html5/imports/api/users/server/modifiers/addUser.js b/bigbluebutton-html5/imports/api/users/server/modifiers/addUser.js index 243f5cb522..665964b8fe 100755 --- a/bigbluebutton-html5/imports/api/users/server/modifiers/addUser.js +++ b/bigbluebutton-html5/imports/api/users/server/modifiers/addUser.js @@ -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: {