Merge branch 'new-server-side-architecture' into pr-21368

This commit is contained in:
Gustavo Trott 2024-10-14 14:50:52 -03:00 committed by GitHub
commit 5852a870af
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 139 additions and 192 deletions

View File

@ -1,60 +1,29 @@
package org.bigbluebutton.core.apps.plugin
import org.bigbluebutton.common2.msgs.PluginDataChannelDeleteEntryMsg
import org.bigbluebutton.core.apps.plugin.PluginHdlrHelpers.{ checkPermission, dataChannelCheckingLogic, defaultCreatorCheck }
import org.bigbluebutton.core.db.PluginDataChannelEntryDAO
import org.bigbluebutton.core.domain.MeetingState2x
import org.bigbluebutton.core.models.{ PluginModel, Roles, Users2x }
import org.bigbluebutton.core.running.{ HandlerHelpers, LiveMeeting }
trait PluginDataChannelDeleteEntryMsgHdlr extends HandlerHelpers {
def handle(msg: PluginDataChannelDeleteEntryMsg, state: MeetingState2x, liveMeeting: LiveMeeting): Unit = {
val pluginsDisabled: Boolean = liveMeeting.props.meetingProp.disabledFeatures.contains("plugins")
val meetingId = liveMeeting.props.meetingProp.intId
for {
_ <- if (!pluginsDisabled) Some(()) else None
user <- Users2x.findWithIntId(liveMeeting.users2x, msg.header.userId)
} yield {
PluginModel.getPluginByName(liveMeeting.plugins, msg.body.pluginName) match {
case Some(p) =>
p.manifest.content.dataChannels.getOrElse(List()).find(dc => dc.name == msg.body.channelName) match {
case Some(dc) =>
val hasPermission = for {
replaceOrDeletePermission <- dc.replaceOrDeletePermission
} yield {
replaceOrDeletePermission.toLowerCase match {
case "all" => true
case "moderator" => user.role == Roles.MODERATOR_ROLE
case "presenter" => user.presenter
case "creator" => {
val creatorUserId = PluginDataChannelEntryDAO.getEntryCreator(
meetingId,
msg.body.pluginName,
msg.body.channelName,
msg.body.subChannelName,
msg.body.entryId
)
creatorUserId == msg.header.userId
}
case _ => false
}
}
if (!hasPermission.contains(true)) {
println(s"No permission to delete in plugin: '${msg.body.pluginName}', data channel: '${msg.body.channelName}'.")
} else {
PluginDataChannelEntryDAO.delete(
meetingId,
msg.body.pluginName,
msg.body.channelName,
msg.body.subChannelName,
msg.body.entryId
)
}
case None => println(s"Data channel '${msg.body.channelName}' not found in plugin '${msg.body.pluginName}'.")
}
case None => println(s"Plugin '${msg.body.pluginName}' not found.")
dataChannelCheckingLogic(liveMeeting, msg.header.userId, msg.body.pluginName, msg.body.channelName, (user, dc, meetingId) => {
val hasPermission = checkPermission(user, dc.replaceOrDeletePermission, defaultCreatorCheck(
meetingId, msg.body, msg.header.userId
))
if (!hasPermission.contains(true)) {
println(s"No permission to delete in plugin: '${msg.body.pluginName}', data channel: '${msg.body.channelName}'.")
} else {
PluginDataChannelEntryDAO.delete(
meetingId,
msg.body.pluginName,
msg.body.channelName,
msg.body.subChannelName,
msg.body.entryId
)
}
}
})
}
}

View File

@ -1,54 +1,30 @@
package org.bigbluebutton.core.apps.plugin
import org.bigbluebutton.common2.msgs.PluginDataChannelPushEntryMsg
import org.bigbluebutton.core.apps.plugin.PluginHdlrHelpers.{ checkPermission, dataChannelCheckingLogic, defaultCreatorCheck }
import org.bigbluebutton.core.db.PluginDataChannelEntryDAO
import org.bigbluebutton.core.domain.MeetingState2x
import org.bigbluebutton.core.models.{ PluginModel, Roles, Users2x }
import org.bigbluebutton.core.running.{ HandlerHelpers, LiveMeeting }
trait PluginDataChannelPushEntryMsgHdlr extends HandlerHelpers {
def handle(msg: PluginDataChannelPushEntryMsg, state: MeetingState2x, liveMeeting: LiveMeeting): Unit = {
val pluginsDisabled: Boolean = liveMeeting.props.meetingProp.disabledFeatures.contains("plugins")
val meetingId = liveMeeting.props.meetingProp.intId
for {
_ <- if (!pluginsDisabled) Some(()) else None
user <- Users2x.findWithIntId(liveMeeting.users2x, msg.header.userId)
} yield {
PluginModel.getPluginByName(liveMeeting.plugins, msg.body.pluginName) match {
case Some(p) =>
p.manifest.content.dataChannels.getOrElse(List()).find(dc => dc.name == msg.body.channelName) match {
case Some(dc) =>
val hasPermission = for {
pushPermission <- dc.pushPermission
} yield {
pushPermission.toLowerCase match {
case "all" => true
case "moderator" => user.role == Roles.MODERATOR_ROLE
case "presenter" => user.presenter
case _ => false
}
}
if (!hasPermission.contains(true)) {
println(s"No permission to write in plugin: '${msg.body.pluginName}', data channel: '${msg.body.channelName}'.")
} else {
PluginDataChannelEntryDAO.insert(
meetingId,
msg.body.pluginName,
msg.body.channelName,
msg.body.subChannelName,
msg.header.userId,
msg.body.payloadJson,
msg.body.toRoles,
msg.body.toUserIds
)
}
case None => println(s"Data channel '${msg.body.channelName}' not found in plugin '${msg.body.pluginName}'.")
}
case None => println(s"Plugin '${msg.body.pluginName}' not found.")
dataChannelCheckingLogic(liveMeeting, msg.header.userId, msg.body.pluginName, msg.body.channelName, (user, dc, meetingId) => {
val hasPermission = checkPermission(user, dc.pushPermission)
if (!hasPermission.contains(true)) {
println(s"No permission to write in plugin: '${msg.body.pluginName}', data channel: '${msg.body.channelName}'.")
} else {
PluginDataChannelEntryDAO.insert(
meetingId,
msg.body.pluginName,
msg.body.channelName,
msg.body.subChannelName,
msg.header.userId,
msg.body.payloadJson,
msg.body.toRoles,
msg.body.toUserIds
)
}
}
})
}
}

View File

@ -1,62 +1,31 @@
package org.bigbluebutton.core.apps.plugin
import org.bigbluebutton.common2.msgs.PluginDataChannelReplaceEntryMsg
import org.bigbluebutton.core.apps.plugin.PluginHdlrHelpers.{checkPermission, dataChannelCheckingLogic, defaultCreatorCheck}
import org.bigbluebutton.core.db.{JsonUtils, PluginDataChannelEntryDAO}
import org.bigbluebutton.core.domain.MeetingState2x
import org.bigbluebutton.core.models.{PluginModel, Roles, Users2x}
import org.bigbluebutton.core.running.{HandlerHelpers, LiveMeeting}
trait PluginDataChannelReplaceEntryMsgHdlr extends HandlerHelpers {
def handle(msg: PluginDataChannelReplaceEntryMsg, state: MeetingState2x, liveMeeting: LiveMeeting): Unit = {
val pluginsDisabled: Boolean = liveMeeting.props.meetingProp.disabledFeatures.contains("plugins")
val meetingId = liveMeeting.props.meetingProp.intId
for {
_ <- if (!pluginsDisabled) Some(()) else None
user <- Users2x.findWithIntId(liveMeeting.users2x, msg.header.userId)
} yield {
PluginModel.getPluginByName(liveMeeting.plugins, msg.body.pluginName) match {
case Some(p) =>
p.manifest.content.dataChannels.getOrElse(List()).find(dc => dc.name == msg.body.channelName) match {
case Some(dc) =>
val hasPermission = for {
replaceOrDeletePermission <- dc.replaceOrDeletePermission
} yield {
replaceOrDeletePermission.toLowerCase match {
case "all" => true
case "moderator" => user.role == Roles.MODERATOR_ROLE
case "presenter" => user.presenter
case "creator" => {
val creatorUserId = PluginDataChannelEntryDAO.getEntryCreator(
meetingId,
msg.body.pluginName,
msg.body.channelName,
msg.body.subChannelName,
msg.body.entryId
)
creatorUserId == msg.header.userId
}
case _ => false
}
}
dataChannelCheckingLogic(liveMeeting, msg.header.userId, msg.body.pluginName, msg.body.channelName, (user, dc, meetingId) => {
val hasPermission = checkPermission(user, dc.replaceOrDeletePermission, defaultCreatorCheck(
meetingId, msg.body, msg.header.userId))
if (!hasPermission.contains(true)) {
println(s"No permission to write in plugin: '${msg.body.pluginName}', data channel: '${msg.body.channelName}'.")
} else {
PluginDataChannelEntryDAO.replace(
msg.header.meetingId,
msg.body.pluginName,
msg.body.channelName,
msg.body.subChannelName,
msg.body.entryId,
JsonUtils.mapToJson(msg.body.payloadJson),
)
}
case None => println(s"Data channel '${msg.body.channelName}' not found in plugin '${msg.body.pluginName}'.")
case None => println(s"Plugin '${msg.body.pluginName}' not found.")
}
if (!hasPermission.contains(true)) {
println(s"No permission to write in plugin: '${msg.body.pluginName}', data channel: '${msg.body.channelName}'.")
} else {
PluginDataChannelEntryDAO.replace(
msg.header.meetingId,
msg.body.pluginName,
msg.body.channelName,
msg.body.subChannelName,
msg.body.entryId,
JsonUtils.mapToJson(msg.body.payloadJson),
)
}
}
})
}
}

View File

@ -1,51 +1,27 @@
package org.bigbluebutton.core.apps.plugin
import org.bigbluebutton.ClientSettings
import org.bigbluebutton.common2.msgs.PluginDataChannelResetMsg
import org.bigbluebutton.core.apps.plugin.PluginHdlrHelpers.{ checkPermission, dataChannelCheckingLogic }
import org.bigbluebutton.core.db.PluginDataChannelEntryDAO
import org.bigbluebutton.core.domain.MeetingState2x
import org.bigbluebutton.core.models.{ PluginModel, Roles, Users2x }
import org.bigbluebutton.core.running.{ HandlerHelpers, LiveMeeting }
trait PluginDataChannelResetMsgHdlr extends HandlerHelpers {
def handle(msg: PluginDataChannelResetMsg, state: MeetingState2x, liveMeeting: LiveMeeting): Unit = {
val pluginsDisabled: Boolean = liveMeeting.props.meetingProp.disabledFeatures.contains("plugins")
val meetingId = liveMeeting.props.meetingProp.intId
dataChannelCheckingLogic(liveMeeting, msg.header.userId, msg.body.pluginName, msg.body.channelName, (user, dc, meetingId) => {
val hasPermission = checkPermission(user, dc.replaceOrDeletePermission)
for {
_ <- if (!pluginsDisabled) Some(()) else None
user <- Users2x.findWithIntId(liveMeeting.users2x, msg.header.userId)
} yield {
PluginModel.getPluginByName(liveMeeting.plugins, msg.body.pluginName) match {
case Some(p) =>
p.manifest.content.dataChannels.getOrElse(List()).find(dc => dc.name == msg.body.channelName) match {
case Some(dc) =>
val hasPermission = for {
replaceOrDeletePermission <- dc.replaceOrDeletePermission
} yield {
replaceOrDeletePermission.toLowerCase match {
case "all" => true
case "moderator" => user.role == Roles.MODERATOR_ROLE
case "presenter" => user.presenter
case _ => false
}
}
if (!hasPermission.contains(true)) {
println(s"No permission to delete (reset) in plugin: '${msg.body.pluginName}', data channel: '${msg.body.channelName}'.")
} else {
PluginDataChannelEntryDAO.reset(
meetingId,
msg.body.pluginName,
msg.body.channelName,
msg.body.subChannelName
)
}
case None => println(s"Data channel '${msg.body.channelName}' not found in plugin '${msg.body.pluginName}'.")
}
case None => println(s"Plugin '${msg.body.pluginName}' not found.")
if (!hasPermission.contains(true)) {
println(s"No permission to delete (reset) in plugin: '${msg.body.pluginName}', data channel: '${msg.body.channelName}'.")
} else {
PluginDataChannelEntryDAO.reset(
meetingId,
msg.body.pluginName,
msg.body.channelName,
msg.body.subChannelName
)
}
}
})
}
}

View File

@ -0,0 +1,50 @@
package org.bigbluebutton.core.apps.plugin
import org.bigbluebutton.common2.msgs.PluginDataChannelReplaceOrDeleteBaseBody
import org.bigbluebutton.core.db.PluginDataChannelEntryDAO
import org.bigbluebutton.core.models.{ DataChannel, PluginModel, Roles, UserState, Users2x }
import org.bigbluebutton.core.running.LiveMeeting
object PluginHdlrHelpers {
def checkPermission(user: UserState, permissionType: List[String], creatorCheck: => Boolean = false): List[Boolean] = {
permissionType.map(_.toLowerCase).map {
case "all" => true
case "moderator" => user.role == Roles.MODERATOR_ROLE
case "presenter" => user.presenter
case "creator" => creatorCheck
case _ => false
}
}
def defaultCreatorCheck[T <: PluginDataChannelReplaceOrDeleteBaseBody](meetingId: String, msgBody: T, userId: String): Boolean = {
val creatorUserId = PluginDataChannelEntryDAO.getEntryCreator(
meetingId,
msgBody.pluginName,
msgBody.channelName,
msgBody.subChannelName,
msgBody.entryId
)
creatorUserId == userId
}
def dataChannelCheckingLogic(liveMeeting: LiveMeeting, userId: String,
pluginName: String, channelName: String,
caseSomeDataChannelAndPlugin: (UserState, DataChannel, String) => Unit): Option[Unit] = {
val pluginsDisabled: Boolean = liveMeeting.props.meetingProp.disabledFeatures.contains("plugins")
val meetingId = liveMeeting.props.meetingProp.intId
for {
_ <- if (!pluginsDisabled) Some(()) else None
user <- Users2x.findWithIntId(liveMeeting.users2x, userId)
} yield {
PluginModel.getPluginByName(liveMeeting.plugins, pluginName) match {
case Some(p) =>
p.manifest.content.dataChannels.getOrElse(List()).find(dc => dc.name == channelName) match {
case Some(dc) =>
caseSomeDataChannelAndPlugin(user, dc, meetingId)
case None => println(s"Data channel '${channelName}' not found in plugin '${pluginName}'.")
}
case None => println(s"Plugin '${pluginName}' not found.")
}
}
}
}

View File

@ -7,6 +7,14 @@ import org.bigbluebutton.common2.domain.PluginLearningAnalyticsDashboardGenericD
/**
* Sent from graphql-actions to bbb-akka
*/
trait PluginDataChannelReplaceOrDeleteBaseBody{
val pluginName: String
val channelName: String
val subChannelName: String
val entryId: String
}
object PluginDataChannelPushEntryMsg { val NAME = "PluginDataChannelPushEntryMsg" }
case class PluginDataChannelPushEntryMsg(header: BbbClientMsgHeader, body: PluginDataChannelPushEntryMsgBody) extends StandardMsg
case class PluginDataChannelPushEntryMsgBody(
@ -20,13 +28,13 @@ case class PluginDataChannelPushEntryMsgBody(
object PluginDataChannelReplaceEntryMsg { val NAME = "PluginDataChannelReplaceEntryMsg" }
case class PluginDataChannelReplaceEntryMsg(header: BbbClientMsgHeader, body: PluginDataChannelReplaceEntryMsgBody) extends StandardMsg
case class PluginDataChannelReplaceEntryMsgBody(
case class PluginDataChannelReplaceEntryMsgBody (
pluginName: String,
channelName: String,
subChannelName: String,
payloadJson: Map[String, Any],
entryId: String,
)
) extends PluginDataChannelReplaceOrDeleteBaseBody
object PluginDataChannelDeleteEntryMsg { val NAME = "PluginDataChannelDeleteEntryMsg" }
case class PluginDataChannelDeleteEntryMsg(header: BbbClientMsgHeader, body: PluginDataChannelDeleteEntryMsgBody) extends StandardMsg
@ -35,7 +43,7 @@ case class PluginDataChannelDeleteEntryMsgBody(
subChannelName: String,
channelName: String,
entryId: String
)
) extends PluginDataChannelReplaceOrDeleteBaseBody
object PluginDataChannelResetMsg { val NAME = "PluginDataChannelResetMsg" }

View File

@ -27,10 +27,7 @@ import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.*;
import org.bigbluebutton.api.domain.*;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
@ -433,24 +430,26 @@ public class ParamsProcessorUtil {
private ArrayList<PluginsManifest> processPluginsManifests(String pluginsManifestsParam) {
ArrayList<PluginsManifest> pluginsManifests = new ArrayList<PluginsManifest>();
JsonElement pluginsManifestsJsonElement = new Gson().fromJson(pluginsManifestsParam, JsonElement.class);
if(pluginsManifestsJsonElement != null && pluginsManifestsJsonElement.isJsonArray()) {
JsonArray pluginsManifestsJson = pluginsManifestsJsonElement.getAsJsonArray();
for (JsonElement pluginsManifestJson : pluginsManifestsJson) {
if(pluginsManifestJson.isJsonObject()) {
JsonObject pluginsManifestJsonObj = pluginsManifestJson.getAsJsonObject();
if(pluginsManifestJsonObj.has("url")) {
String url = pluginsManifestJsonObj.get("url").getAsString();
PluginsManifest newPlugin = new PluginsManifest(url);
if(pluginsManifestJsonObj.has("checksum")) {
newPlugin.setChecksum(pluginsManifestJsonObj.get("checksum").getAsString());
try {
if (pluginsManifestsJsonElement != null && pluginsManifestsJsonElement.isJsonArray()) {
JsonArray pluginsManifestsJson = pluginsManifestsJsonElement.getAsJsonArray();
for (JsonElement pluginsManifestJson : pluginsManifestsJson) {
if (pluginsManifestJson.isJsonObject()) {
JsonObject pluginsManifestJsonObj = pluginsManifestJson.getAsJsonObject();
if (pluginsManifestJsonObj.has("url")) {
String url = pluginsManifestJsonObj.get("url").getAsString();
PluginsManifest newPlugin = new PluginsManifest(url);
if (pluginsManifestJsonObj.has("checksum")) {
newPlugin.setChecksum(pluginsManifestJsonObj.get("checksum").getAsString());
}
pluginsManifests.add(newPlugin);
}
pluginsManifests.add(newPlugin);
}
}
}
} catch(JsonSyntaxException err){
log.error("Error in pluginsManifests URL parameter's json structure.");
}
return pluginsManifests;