Insert Poll result as Chat msg in graphql

This commit is contained in:
Gustavo Trott 2023-05-24 10:56:22 -03:00
parent ed2c94eaea
commit d1a60157e5
10 changed files with 147 additions and 47 deletions

View File

@ -33,7 +33,12 @@ object GroupChatApp {
def addGroupChatMessage(meetingId: String, chat: GroupChat, chats: GroupChats,
msg: GroupChatMessage): GroupChats = {
ChatMessageDAO.insert(meetingId, chat.id, msg)
if (msg.sender.id == SystemUser.ID) {
ChatMessageDAO.insertSystemMsg(meetingId, chat.id, msg.message, "default", Map(), msg.sender.name)
} else {
ChatMessageDAO.insert(meetingId, chat.id, msg)
}
val c = chat.add(msg)
chats.update(c)
}

View File

@ -2,12 +2,15 @@ package org.bigbluebutton.core.apps.polls
import org.bigbluebutton.common2.domain.SimplePollResultOutVO
import org.bigbluebutton.common2.msgs._
import org.bigbluebutton.core.apps.groupchats.GroupChatApp
import org.bigbluebutton.core.bus.MessageBus
import org.bigbluebutton.core.domain.MeetingState2x
import org.bigbluebutton.core.models.Polls
import org.bigbluebutton.core.running.LiveMeeting
import org.bigbluebutton.core.apps.{ PermissionCheck, RightsManagementTrait }
import org.bigbluebutton.core2.message.senders.{ MsgBuilder }
import org.bigbluebutton.core.db.{ ChatMessageDAO, JsonUtils }
import org.bigbluebutton.core2.message.senders.MsgBuilder
import spray.json.DefaultJsonProtocol.jsonFormat2
trait ShowPollResultReqMsgHdlr extends RightsManagementTrait {
this: PollApp2x =>
@ -54,6 +57,27 @@ trait ShowPollResultReqMsgHdlr extends RightsManagementTrait {
for {
(result, annotationProp) <- Polls.handleShowPollResultReqMsg(state, msg.header.userId, msg.body.pollId, liveMeeting)
} yield {
//it will be used to render the chat message (will be stored as json in chat-msg metadata)
val resultAsSimpleMap = Map(
"id" -> result.id,
"questionType" -> result.questionType,
"questionText" -> result.questionText.getOrElse(""),
"answers" -> {
for {
answer <- result.answers
} yield {
Map(
"id" -> answer.id,
"key" -> answer.key,
"numVotes" -> answer.numVotes
)
}
},
"numRespondents" -> result.numRespondents,
"numResponders" -> result.numResponders,
)
ChatMessageDAO.insertSystemMsg(liveMeeting.props.meetingProp.intId, GroupChatApp.MAIN_PUBLIC_CHAT, "", "poll", resultAsSimpleMap, "")
broadcastEvent(msg, result, annotationProp)
}
}

View File

@ -1,10 +1,10 @@
package org.bigbluebutton.core.db
import slick.jdbc.PostgresProfile.api._
import org.bigbluebutton.core.models.GroupChatMessage
import org.bigbluebutton.core.models.{GroupChatFactory, GroupChatMessage}
import scala.concurrent.ExecutionContext.Implicits.global
import scala.util.{ Failure, Success }
import scala.util.{Failure, Success}
case class ChatMessageDbModel(
messageId: String,
@ -14,7 +14,9 @@ case class ChatMessageDbModel(
createdTime: Long,
chatEmphasizedText: Boolean,
message: String,
senderId: String,
messageType: String,
messageMetadata: String,
senderId: Option[String],
senderName: String,
senderRole: String
)
@ -27,13 +29,15 @@ class ChatMessageDbTableDef(tag: Tag) extends Table[ChatMessageDbModel](tag, Non
val createdTime = column[Long]("createdTime")
val chatEmphasizedText = column[Boolean]("chatEmphasizedText")
val message = column[String]("message")
val senderId = column[String]("senderId")
val messageType = column[String]("messageType")
val messageMetadata = column[String]("messageMetadata")
val senderId = column[Option[String]]("senderId")
val senderName = column[String]("senderName")
val senderRole = column[String]("senderRole")
// val chat = foreignKey("chat_message_chat_fk", (chatId, meetingId), ChatTable.chats)(c => (c.chatId, c.meetingId), onDelete = ForeignKeyAction.Cascade)
// val sender = foreignKey("chat_message_sender_fk", senderId, UserTable.users)(_.userId, onDelete = ForeignKeyAction.SetNull)
override def * = (messageId, chatId, meetingId, correlationId, createdTime, chatEmphasizedText, message, senderId, senderName, senderRole) <> (ChatMessageDbModel.tupled, ChatMessageDbModel.unapply)
override def * = (messageId, chatId, meetingId, correlationId, createdTime, chatEmphasizedText, message, messageType, messageMetadata, senderId, senderName, senderRole) <> (ChatMessageDbModel.tupled, ChatMessageDbModel.unapply)
}
object ChatMessageDAO {
@ -48,7 +52,9 @@ object ChatMessageDAO {
createdTime = groupChatMessage.timestamp,
chatEmphasizedText = groupChatMessage.chatEmphasizedText,
message = groupChatMessage.message,
senderId = groupChatMessage.sender.id,
messageType = "default",
messageMetadata = "",
senderId = Some(groupChatMessage.sender.id),
senderName = groupChatMessage.sender.name,
senderRole = groupChatMessage.sender.role,
)
@ -63,4 +69,34 @@ object ChatMessageDAO {
case Failure(e) => DatabaseConnection.logger.debug(s"Error inserting ChatMessage: $e")
}
}
def insertSystemMsg(meetingId: String, chatId: String, message: String, messageType: String, messageMetadata: Map[String,Any], senderName: String) = {
DatabaseConnection.db.run(
TableQuery[ChatMessageDbTableDef].insertOrUpdate(
ChatMessageDbModel(
messageId = GroupChatFactory.genId(),
chatId = chatId,
meetingId = meetingId,
correlationId = "",
createdTime = System.currentTimeMillis(),
chatEmphasizedText = false,
message = message,
messageType = messageType,
messageMetadata = JsonUtils.mapToJson(messageMetadata),
senderId = None,
senderName = senderName,
senderRole = ""
)
)
).onComplete {
case Success(rowsAffected) => {
DatabaseConnection.logger.debug(s"$rowsAffected row(s) inserted on ChatMessage(system) table!")
//Set chat visible for all participant users
ChatUserDAO.updateChatVisible(meetingId, chatId)
}
case Failure(e) => DatabaseConnection.logger.debug(s"Error inserting ChatMessage(system): $e")
}
}
}

View File

@ -33,12 +33,12 @@ object JsonUtils {
case d: Double => JsNumber(d)
case m: Map[_, _] => JsObject(m.asInstanceOf[Map[String, Any]].map { case (k, v) => k -> write(v) })
case l: List[_] => JsArray(l.map(write).toVector)
case a: Array[_] => JsArray(a.map(write).toVector)
case _ => throw new IllegalArgumentException(s"Unsupported type: ${x.getClass.getName}")
// case _ => JsNull
}
}
// Cria um JsonWriter implícito para o tipo Map[String, Any]
implicit val mapFormat: JsonWriter[Map[String, Any]] = new JsonWriter[Map[String, Any]] {
def write(m: Map[String, Any]): JsValue = {
JsObject(m.map { case (k, v) => k -> AnyJsonWriter.write(v) })

View File

@ -19,6 +19,18 @@ DROP TABLE IF EXISTS "chat_user";
DROP TABLE IF EXISTS "chat_message";
DROP TABLE IF EXISTS "chat";
drop view if exists "v_poll_response";
drop view if exists "v_poll_user";
drop view if exists "v_poll_option";
drop view if exists "v_poll";
drop table if exists "poll_response";
drop table if exists "poll_option";
drop table if exists "poll";
drop view if exists "v_external_video";
drop table if exists "external_video";
drop view if exists "v_screenshare";
drop table if exists "screenshare";
DROP VIEW IF EXISTS "v_user_camera";
DROP VIEW IF EXISTS "v_user_voice";
--DROP VIEW IF EXISTS "v_user_whiteboard";
@ -54,18 +66,6 @@ DROP TABLE IF EXISTS "meeting_usersPolicies";
DROP TABLE IF EXISTS "meeting_group";
DROP TABLE IF EXISTS "meeting";
drop view if exists "v_poll_response";
drop view if exists "v_poll_user";
drop view if exists "v_poll_option";
drop view if exists "v_poll";
drop table if exists "poll_response";
drop table if exists "poll_option";
drop table if exists "poll";
drop view if exists "v_external_video";
drop table if exists "external_video";
drop view if exists "v_screenshare";
drop table if exists "screenshare";
DROP FUNCTION IF EXISTS "update_user_presenter_trigger_func";
DROP FUNCTION IF EXISTS "update_pres_presentation_current_trigger_func";
@ -494,14 +494,7 @@ create index "idx_user_connectionStatus_meetingId" on "user_connectionStatus"("m
--FROM "user" u
--LEFT JOIN "user_connectionStatus" uc ON uc."userId" = u."userId";
create table "user_custom_parameter"(
"userId" varchar(50) PRIMARY KEY REFERENCES "user"("userId") ON DELETE CASCADE,
"meetingId" varchar(100) REFERENCES "meeting"("meetingId") ON DELETE CASCADE,
"parameter" varchar(255),
"value" varchar(255)
);
create index "idx_user_custom_parameter_parameter" on "user_custom_parameter"("userId","parameter");
create index "idx_user_custom_parameter_meetingId" on "user_custom_parameter"("meetingId");
-- ===================== CHAT TABLES
@ -565,7 +558,9 @@ CREATE TABLE "chat_message" (
"correlationId" varchar(100),
"createdTime" bigint,
"chatEmphasizedText" boolean,
"message" TEXT,
"message" text,
"messageType" varchar(50),
"messageMetadata" text,
"senderId" varchar(100),
"senderName" varchar(255),
"senderRole" varchar(20),

View File

@ -27,6 +27,8 @@ select_permissions:
- createdTimeAsDate
- message
- messageId
- messageMetadata
- messageType
- senderId
- senderName
- senderRole

View File

@ -20,16 +20,18 @@ select_permissions:
- role: bbb_client
permission:
columns:
- createdTime
- chatEmphasizedText
- chatId
- correlationId
- createdTime
- createdTimeAsDate
- message
- messageId
- messageMetadata
- messageType
- senderId
- senderName
- senderRole
- message
- createdTimeAsDate
filter:
meetingId:
_eq: X-Hasura-MeetingId

View File

@ -0,0 +1,36 @@
#!/bin/bash
export LANGUAGE="en_US.UTF-8"
export LC_ALL="en_US.UTF-8"
akka_apps_status=$(systemctl is-active "bbb-apps-akka")
hasura_status=$(systemctl is-active "bbb-graphql-server")
if [ "$akka_apps_status" = "active" ]; then
echo "Stopping Akka-apps"
sudo systemctl stop bbb-apps-akka
fi
if [ "$hasura_status" = "active" ]; then
echo "Stopping Hasura"
sudo systemctl start bbb-graphql-server
fi
echo "Restarting database bbb_graphql"
sudo -u postgres psql -c "SELECT pg_terminate_backend(pg_stat_activity.pid) FROM pg_stat_activity WHERE datname = 'bbb_graphql'"
sudo -u postgres psql -c "drop database if exists bbb_graphql"
sudo -u postgres psql -c "create database bbb_graphql"
echo "Creating tables in bbb_graphql"
sudo -u postgres psql -U postgres -d bbb_graphql -a -f bbb_schema.sql --set ON_ERROR_STOP=on
echo "Applying new metadata to Hasura"
/usr/local/bin/hasura metadata apply
if [ "$hasura_status" = "active" ]; then
echo "Starting Hasura"
sudo systemctl start bbb-graphql-server
fi
if [ "$akka_apps_status" = "active" ]; then
echo "Starting Akka-apps"
sudo systemctl start bbb-apps-akka
fi

View File

@ -38,11 +38,11 @@ const ChatMesssage: React.FC<ChatMessageProps> = ({ message, previousMessage, la
{
sameSender ? null : (
<ChatAvatar
avatar={message.user.avatar}
color={message.user.color}
moderator={message.user.isModerator}
avatar={message.user?.avatar}
color={message.user?.color}
moderator={message.user?.isModerator}
>
{message.user.name.toLowerCase().slice(0, 2) || " "}
{message.user?.name.toLowerCase().slice(0, 2) || " "}
</ChatAvatar>
)
}
@ -52,10 +52,10 @@ const ChatMesssage: React.FC<ChatMessageProps> = ({ message, previousMessage, la
<ChatUserContent>
<ChatUserName
>
{message.user.name}
{message.user?.name}
</ChatUserName>
{
message.user.isOnline ? null : (
message.user?.isOnline ? null : (
<ChatUserOffline
>
{`(${intl.formatMessage(intlMessages.offline)})`}
@ -71,7 +71,7 @@ const ChatMesssage: React.FC<ChatMessageProps> = ({ message, previousMessage, la
}
<ChatMessage
sameSender={sameSender}
emphasizedMessage={message.user.isModerator}
emphasizedMessage={message.user?.isModerator}
>
{message.message}
</ChatMessage>
@ -80,4 +80,4 @@ const ChatMesssage: React.FC<ChatMessageProps> = ({ message, previousMessage, la
);
};
export default ChatMesssage;
export default ChatMesssage;

View File

@ -36,8 +36,8 @@ const verifyIfIsPrivateChat = (message: unknown): message is ChatMessagePrivateS
}
const ChatListPage: React.FC<ChatListPageProps> = ({ messages, lastSenderPreviousPage, page }) => {
const ChatListPage: React.FC<ChatListPageProps> = ({ messages, lastSenderPreviousPage, page }) => {
return (
<div id={`messagePage-${page}`}>
{
@ -68,7 +68,7 @@ const ChatListPageContainer: React.FC<ChatListPageContainerProps> = ({
const chatQuery = isPublicChat
? CHAT_MESSAGE_PUBLIC_SUBSCRIPTION
: CHAT_MESSAGE_PRIVATE_SUBSCRIPTION;
const defaultVariables = { offset: (page)*pageSize, limit: pageSize };
const defaultVariables = { offset: (page)*pageSize, limit: pageSize };
const variables = isPublicChat ? defaultVariables : { ...defaultVariables, requestedChatId: chatId };
const {
data: chatMessageData,
@ -89,9 +89,9 @@ const ChatListPageContainer: React.FC<ChatListPageContainerProps> = ({
}
if (messages.length > 0) {
setLastSender(page, messages[messages.length-1].user.userId);
setLastSender(page, messages[messages.length-1].user?.userId);
}
return (
<ChatListPage
messages={messages}
@ -101,4 +101,4 @@ const ChatListPageContainer: React.FC<ChatListPageContainerProps> = ({
);
}
export default ChatListPageContainer;
export default ChatListPageContainer;