Add support for chat message reactions.
It introduces the graphql prop `reactions` to the type `chat_message_public` and `chat_message_private`. It also add two mutations `chatSendMessageReaction` and `chatDeleteMessageReaction`.
This commit is contained in:
parent
b3403ffdf5
commit
e19cbdbb58
@ -0,0 +1,69 @@
|
|||||||
|
package org.bigbluebutton.core.apps.groupchats
|
||||||
|
|
||||||
|
import org.bigbluebutton.common2.msgs._
|
||||||
|
import org.bigbluebutton.core.apps.PermissionCheck
|
||||||
|
import org.bigbluebutton.core.bus.MessageBus
|
||||||
|
import org.bigbluebutton.core.db.ChatMessageReactionDAO
|
||||||
|
import org.bigbluebutton.core.domain.MeetingState2x
|
||||||
|
import org.bigbluebutton.core.models.{ Roles, Users2x }
|
||||||
|
import org.bigbluebutton.core.running.{ HandlerHelpers, LiveMeeting }
|
||||||
|
import org.bigbluebutton.core2.MeetingStatus2x
|
||||||
|
|
||||||
|
trait DeleteGroupChatMessageReactionReqMsgHdlr extends HandlerHelpers {
|
||||||
|
this: GroupChatHdlrs =>
|
||||||
|
|
||||||
|
def handle(msg: DeleteGroupChatMessageReactionReqMsg, state: MeetingState2x, liveMeeting: LiveMeeting, bus: MessageBus): MeetingState2x = {
|
||||||
|
val chatDisabled: Boolean = liveMeeting.props.meetingProp.disabledFeatures.contains("chat")
|
||||||
|
var chatLocked: Boolean = false
|
||||||
|
var chatLockedForUser: Boolean = false
|
||||||
|
|
||||||
|
var newState = state
|
||||||
|
|
||||||
|
for {
|
||||||
|
user <- Users2x.findWithIntId(liveMeeting.users2x, msg.header.userId)
|
||||||
|
groupChat <- state.groupChats.find(msg.body.chatId)
|
||||||
|
} yield {
|
||||||
|
if (groupChat.access == GroupChatAccess.PUBLIC && user.userLockSettings.disablePublicChat && user.role != Roles.MODERATOR_ROLE) {
|
||||||
|
chatLockedForUser = true
|
||||||
|
}
|
||||||
|
|
||||||
|
val userIsModerator = user.role != Roles.MODERATOR_ROLE
|
||||||
|
|
||||||
|
if (!userIsModerator && user.locked) {
|
||||||
|
val permissions = MeetingStatus2x.getPermissions(liveMeeting.status)
|
||||||
|
if (groupChat.access == GroupChatAccess.PRIVATE) {
|
||||||
|
val modMembers = groupChat.users.filter(cu => Users2x.findWithIntId(liveMeeting.users2x, cu.id) match {
|
||||||
|
case Some(user) => user.role == Roles.MODERATOR_ROLE
|
||||||
|
case None => false
|
||||||
|
})
|
||||||
|
// don't lock private chats that involve a moderator
|
||||||
|
if (modMembers.isEmpty) {
|
||||||
|
chatLocked = permissions.disablePrivChat
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
chatLocked = permissions.disablePubChat
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!chatDisabled && !(applyPermissionCheck && chatLocked) && !chatLockedForUser) {
|
||||||
|
for {
|
||||||
|
gcMessage <- groupChat.msgs.find(gcm => gcm.id == msg.body.messageId)
|
||||||
|
} yield {
|
||||||
|
val chatIsPrivate = groupChat.access == GroupChatAccess.PRIVATE
|
||||||
|
val userIsAParticipant = groupChat.users.exists(u => u.id == user.intId)
|
||||||
|
|
||||||
|
if ((chatIsPrivate && userIsAParticipant) || !chatIsPrivate) {
|
||||||
|
val event = buildGroupChatMessageReactionDeletedEvtMsg(liveMeeting.props.meetingProp.intId, msg.header.userId, msg.body.chatId, gcMessage.id, msg.body.reactionEmoji)
|
||||||
|
bus.outGW.send(event)
|
||||||
|
ChatMessageReactionDAO.insert(liveMeeting.props.meetingProp.intId, gcMessage.id, msg.header.userId, msg.body.reactionEmoji)
|
||||||
|
} else {
|
||||||
|
val reason = "User isn't a participant of the chat"
|
||||||
|
PermissionCheck.ejectUserForFailedPermission(msg.header.meetingId, msg.header.userId, reason, bus.outGW, liveMeeting)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
newState
|
||||||
|
}
|
||||||
|
}
|
@ -11,6 +11,8 @@ class GroupChatHdlrs(implicit val context: ActorContext)
|
|||||||
with SendGroupChatMessageMsgHdlr
|
with SendGroupChatMessageMsgHdlr
|
||||||
with EditGroupChatMessageReqMsgHdlr
|
with EditGroupChatMessageReqMsgHdlr
|
||||||
with DeleteGroupChatMessageReqMsgHdlr
|
with DeleteGroupChatMessageReqMsgHdlr
|
||||||
|
with SendGroupChatMessageReactionReqMsgHdlr
|
||||||
|
with DeleteGroupChatMessageReactionReqMsgHdlr
|
||||||
with SendGroupChatMessageFromApiSysPubMsgHdlr
|
with SendGroupChatMessageFromApiSysPubMsgHdlr
|
||||||
with SetGroupChatVisibleReqMsgHdlr
|
with SetGroupChatVisibleReqMsgHdlr
|
||||||
with SetGroupChatLastSeenReqMsgHdlr {
|
with SetGroupChatLastSeenReqMsgHdlr {
|
||||||
|
@ -0,0 +1,69 @@
|
|||||||
|
package org.bigbluebutton.core.apps.groupchats
|
||||||
|
|
||||||
|
import org.bigbluebutton.common2.msgs._
|
||||||
|
import org.bigbluebutton.core.apps.PermissionCheck
|
||||||
|
import org.bigbluebutton.core.bus.MessageBus
|
||||||
|
import org.bigbluebutton.core.db.ChatMessageReactionDAO
|
||||||
|
import org.bigbluebutton.core.domain.MeetingState2x
|
||||||
|
import org.bigbluebutton.core.models.{ Roles, Users2x }
|
||||||
|
import org.bigbluebutton.core.running.{ HandlerHelpers, LiveMeeting }
|
||||||
|
import org.bigbluebutton.core2.MeetingStatus2x
|
||||||
|
|
||||||
|
trait SendGroupChatMessageReactionReqMsgHdlr extends HandlerHelpers {
|
||||||
|
this: GroupChatHdlrs =>
|
||||||
|
|
||||||
|
def handle(msg: SendGroupChatMessageReactionReqMsg, state: MeetingState2x, liveMeeting: LiveMeeting, bus: MessageBus): MeetingState2x = {
|
||||||
|
val chatDisabled: Boolean = liveMeeting.props.meetingProp.disabledFeatures.contains("chat")
|
||||||
|
var chatLocked: Boolean = false
|
||||||
|
var chatLockedForUser: Boolean = false
|
||||||
|
|
||||||
|
var newState = state
|
||||||
|
|
||||||
|
for {
|
||||||
|
user <- Users2x.findWithIntId(liveMeeting.users2x, msg.header.userId)
|
||||||
|
groupChat <- state.groupChats.find(msg.body.chatId)
|
||||||
|
} yield {
|
||||||
|
if (groupChat.access == GroupChatAccess.PUBLIC && user.userLockSettings.disablePublicChat && user.role != Roles.MODERATOR_ROLE) {
|
||||||
|
chatLockedForUser = true
|
||||||
|
}
|
||||||
|
|
||||||
|
val userIsModerator = user.role != Roles.MODERATOR_ROLE
|
||||||
|
|
||||||
|
if (!userIsModerator && user.locked) {
|
||||||
|
val permissions = MeetingStatus2x.getPermissions(liveMeeting.status)
|
||||||
|
if (groupChat.access == GroupChatAccess.PRIVATE) {
|
||||||
|
val modMembers = groupChat.users.filter(cu => Users2x.findWithIntId(liveMeeting.users2x, cu.id) match {
|
||||||
|
case Some(user) => user.role == Roles.MODERATOR_ROLE
|
||||||
|
case None => false
|
||||||
|
})
|
||||||
|
// don't lock private chats that involve a moderator
|
||||||
|
if (modMembers.isEmpty) {
|
||||||
|
chatLocked = permissions.disablePrivChat
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
chatLocked = permissions.disablePubChat
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!chatDisabled && !(applyPermissionCheck && chatLocked) && !chatLockedForUser) {
|
||||||
|
for {
|
||||||
|
gcMessage <- groupChat.msgs.find(gcm => gcm.id == msg.body.messageId)
|
||||||
|
} yield {
|
||||||
|
val chatIsPrivate = groupChat.access == GroupChatAccess.PRIVATE
|
||||||
|
val userIsAParticipant = groupChat.users.exists(u => u.id == user.intId)
|
||||||
|
|
||||||
|
if ((chatIsPrivate && userIsAParticipant) || !chatIsPrivate) {
|
||||||
|
val event = buildGroupChatMessageReactionSentEvtMsg(liveMeeting.props.meetingProp.intId, msg.header.userId, msg.body.chatId, gcMessage.id, msg.body.reactionEmoji)
|
||||||
|
bus.outGW.send(event)
|
||||||
|
ChatMessageReactionDAO.insert(liveMeeting.props.meetingProp.intId, gcMessage.id, msg.header.userId, msg.body.reactionEmoji)
|
||||||
|
} else {
|
||||||
|
val reason = "User isn't a participant of the chat"
|
||||||
|
PermissionCheck.ejectUserForFailedPermission(msg.header.meetingId, msg.header.userId, reason, bus.outGW, liveMeeting)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
newState
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,51 @@
|
|||||||
|
package org.bigbluebutton.core.db
|
||||||
|
|
||||||
|
import slick.jdbc.PostgresProfile.api._
|
||||||
|
import slick.lifted.{ ProvenShape }
|
||||||
|
|
||||||
|
case class ChatMessageReactionDbModel(
|
||||||
|
meetingId: String,
|
||||||
|
messageId: String,
|
||||||
|
userId: String,
|
||||||
|
reactionEmoji: String,
|
||||||
|
createdAt: java.sql.Timestamp
|
||||||
|
)
|
||||||
|
|
||||||
|
class ChatMessageReactionDbTableDef(tag: Tag) extends Table[ChatMessageReactionDbModel](tag, "chat_message_reaction") {
|
||||||
|
val meetingId = column[String]("meetingId")
|
||||||
|
val messageId = column[String]("messageId", O.PrimaryKey)
|
||||||
|
val userId = column[String]("userId", O.PrimaryKey)
|
||||||
|
val reactionEmoji = column[String]("reactionEmoji", O.PrimaryKey)
|
||||||
|
val createdAt = column[java.sql.Timestamp]("createdAt")
|
||||||
|
|
||||||
|
override def * : ProvenShape[ChatMessageReactionDbModel] = (meetingId, messageId, userId, reactionEmoji, createdAt) <> (ChatMessageReactionDbModel.tupled, ChatMessageReactionDbModel.unapply)
|
||||||
|
}
|
||||||
|
|
||||||
|
object ChatMessageReactionDAO {
|
||||||
|
def insert(meetingId: String, messageId: String, userId: String, reactionEmoji: String) = {
|
||||||
|
DatabaseConnection.enqueue(
|
||||||
|
TableQuery[ChatMessageReactionDbTableDef].forceInsert(
|
||||||
|
ChatMessageReactionDbModel(
|
||||||
|
meetingId = meetingId,
|
||||||
|
messageId = messageId,
|
||||||
|
userId = userId,
|
||||||
|
reactionEmoji = reactionEmoji,
|
||||||
|
createdAt = new java.sql.Timestamp(System.currentTimeMillis())
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
def delete(meetingId: String, messageId: String, userId: String, reactionEmoji: String) = {
|
||||||
|
DatabaseConnection.enqueue(
|
||||||
|
TableQuery[ChatMessageReactionDbTableDef]
|
||||||
|
.filter(_.meetingId === meetingId)
|
||||||
|
.filter(_.messageId === messageId)
|
||||||
|
.filter(_.userId === userId)
|
||||||
|
.filter(_.reactionEmoji === reactionEmoji)
|
||||||
|
.delete
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -410,6 +410,10 @@ class ReceivedJsonMsgHandlerActor(
|
|||||||
routeGenericMsg[EditGroupChatMessageReqMsg](envelope, jsonNode)
|
routeGenericMsg[EditGroupChatMessageReqMsg](envelope, jsonNode)
|
||||||
case DeleteGroupChatMessageReqMsg.NAME =>
|
case DeleteGroupChatMessageReqMsg.NAME =>
|
||||||
routeGenericMsg[DeleteGroupChatMessageReqMsg](envelope, jsonNode)
|
routeGenericMsg[DeleteGroupChatMessageReqMsg](envelope, jsonNode)
|
||||||
|
case SendGroupChatMessageReactionReqMsg.NAME =>
|
||||||
|
routeGenericMsg[SendGroupChatMessageReactionReqMsg](envelope, jsonNode)
|
||||||
|
case DeleteGroupChatMessageReactionReqMsg.NAME =>
|
||||||
|
routeGenericMsg[DeleteGroupChatMessageReactionReqMsg](envelope, jsonNode)
|
||||||
case GetGroupChatMsgsReqMsg.NAME =>
|
case GetGroupChatMsgsReqMsg.NAME =>
|
||||||
routeGenericMsg[GetGroupChatMsgsReqMsg](envelope, jsonNode)
|
routeGenericMsg[GetGroupChatMsgsReqMsg](envelope, jsonNode)
|
||||||
case CreateGroupChatReqMsg.NAME =>
|
case CreateGroupChatReqMsg.NAME =>
|
||||||
|
@ -327,4 +327,22 @@ trait HandlerHelpers extends SystemConfiguration {
|
|||||||
BbbCommonEnvCoreMsg(envelope, event)
|
BbbCommonEnvCoreMsg(envelope, event)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def buildGroupChatMessageReactionSentEvtMsg(meetingId: String, userId: String, chatId: String, messageId: String, reactionEmoji: String): BbbCommonEnvCoreMsg = {
|
||||||
|
val routing = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, meetingId, userId)
|
||||||
|
val envelope = BbbCoreEnvelope(GroupChatMessageReactionSentEvtMsg.NAME, routing)
|
||||||
|
val header = BbbClientMsgHeader(GroupChatMessageReactionSentEvtMsg.NAME, meetingId, userId)
|
||||||
|
val body = GroupChatMessageReactionSentEvtMsgBody(chatId, messageId, reactionEmoji)
|
||||||
|
val event = GroupChatMessageReactionSentEvtMsg(header, body)
|
||||||
|
BbbCommonEnvCoreMsg(envelope, event)
|
||||||
|
}
|
||||||
|
|
||||||
|
def buildGroupChatMessageReactionDeletedEvtMsg(meetingId: String, userId: String, chatId: String, messageId: String, reactionEmoji: String): BbbCommonEnvCoreMsg = {
|
||||||
|
val routing = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, meetingId, userId)
|
||||||
|
val envelope = BbbCoreEnvelope(GroupChatMessageReactionDeletedEvtMsg.NAME, routing)
|
||||||
|
val header = BbbClientMsgHeader(GroupChatMessageReactionDeletedEvtMsg.NAME, meetingId, userId)
|
||||||
|
val body = GroupChatMessageReactionDeletedEvtMsgBody(chatId, messageId, reactionEmoji)
|
||||||
|
val event = GroupChatMessageReactionDeletedEvtMsg(header, body)
|
||||||
|
BbbCommonEnvCoreMsg(envelope, event)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -711,6 +711,12 @@ class MeetingActor(
|
|||||||
case m: DeleteGroupChatMessageReqMsg =>
|
case m: DeleteGroupChatMessageReqMsg =>
|
||||||
state = groupChatApp.handle(m, state, liveMeeting, msgBus)
|
state = groupChatApp.handle(m, state, liveMeeting, msgBus)
|
||||||
updateUserLastActivity(m.header.userId)
|
updateUserLastActivity(m.header.userId)
|
||||||
|
case m: SendGroupChatMessageReactionReqMsg =>
|
||||||
|
state = groupChatApp.handle(m, state, liveMeeting, msgBus)
|
||||||
|
updateUserLastActivity(m.header.userId)
|
||||||
|
case m: DeleteGroupChatMessageReactionReqMsg =>
|
||||||
|
state = groupChatApp.handle(m, state, liveMeeting, msgBus)
|
||||||
|
updateUserLastActivity(m.header.userId)
|
||||||
|
|
||||||
// Plugin
|
// Plugin
|
||||||
case m: PluginDataChannelPushEntryMsg => pluginHdlrs.handle(m, state, liveMeeting)
|
case m: PluginDataChannelPushEntryMsg => pluginHdlrs.handle(m, state, liveMeeting)
|
||||||
|
@ -138,6 +138,8 @@ class AnalyticsActor(val includeChat: Boolean) extends Actor with ActorLogging {
|
|||||||
case m: SendGroupChatMessageMsg => logChatMessage(msg)
|
case m: SendGroupChatMessageMsg => logChatMessage(msg)
|
||||||
case m: EditGroupChatMessageReqMsg => logChatMessage(msg)
|
case m: EditGroupChatMessageReqMsg => logChatMessage(msg)
|
||||||
case m: DeleteGroupChatMessageReqMsg => logChatMessage(msg)
|
case m: DeleteGroupChatMessageReqMsg => logChatMessage(msg)
|
||||||
|
case m: DeleteGroupChatMessageReqMsg => logChatMessage(msg)
|
||||||
|
case m: DeleteGroupChatMessageReqMsg => logChatMessage(msg)
|
||||||
case m: GroupChatMessageBroadcastEvtMsg => logChatMessage(msg)
|
case m: GroupChatMessageBroadcastEvtMsg => logChatMessage(msg)
|
||||||
case m: GetGroupChatMsgsReqMsg => logChatMessage(msg)
|
case m: GetGroupChatMsgsReqMsg => logChatMessage(msg)
|
||||||
case m: GetGroupChatMsgsRespMsg => logChatMessage(msg)
|
case m: GetGroupChatMsgsRespMsg => logChatMessage(msg)
|
||||||
|
@ -135,6 +135,22 @@ object GroupChatMessageDeletedEvtMsg { val NAME = "GroupChatMessageDeletedEvtMsg
|
|||||||
case class GroupChatMessageDeletedEvtMsg(header: BbbClientMsgHeader, body: GroupChatMessageDeletedEvtMsgBody) extends BbbCoreMsg
|
case class GroupChatMessageDeletedEvtMsg(header: BbbClientMsgHeader, body: GroupChatMessageDeletedEvtMsgBody) extends BbbCoreMsg
|
||||||
case class GroupChatMessageDeletedEvtMsgBody(chatId: String, messageId: String)
|
case class GroupChatMessageDeletedEvtMsgBody(chatId: String, messageId: String)
|
||||||
|
|
||||||
|
object SendGroupChatMessageReactionReqMsg { val NAME = "SendGroupChatMessageReactionReqMsg" }
|
||||||
|
case class SendGroupChatMessageReactionReqMsg(header: BbbClientMsgHeader, body: SendGroupChatMessageReactionReqMsgBody) extends StandardMsg
|
||||||
|
case class SendGroupChatMessageReactionReqMsgBody(chatId: String, messageId: String, reactionEmoji: String)
|
||||||
|
|
||||||
|
object GroupChatMessageReactionSentEvtMsg { val NAME = "GroupChatMessageReactionSentEvtMsg" }
|
||||||
|
case class GroupChatMessageReactionSentEvtMsg(header: BbbClientMsgHeader, body: GroupChatMessageReactionSentEvtMsgBody) extends BbbCoreMsg
|
||||||
|
case class GroupChatMessageReactionSentEvtMsgBody(chatId: String, messageId: String, reactionEmoji: String)
|
||||||
|
|
||||||
|
object DeleteGroupChatMessageReactionReqMsg { val NAME = "DeleteGroupChatMessageReactionReqMsg" }
|
||||||
|
case class DeleteGroupChatMessageReactionReqMsg(header: BbbClientMsgHeader, body: DeleteGroupChatMessageReactionReqMsgBody) extends StandardMsg
|
||||||
|
case class DeleteGroupChatMessageReactionReqMsgBody(chatId: String, messageId: String, reactionEmoji: String)
|
||||||
|
|
||||||
|
object GroupChatMessageReactionDeletedEvtMsg { val NAME = "GroupChatMessageReactionDeletedEvtMsg" }
|
||||||
|
case class GroupChatMessageReactionDeletedEvtMsg(header: BbbClientMsgHeader, body: GroupChatMessageReactionDeletedEvtMsgBody) extends BbbCoreMsg
|
||||||
|
case class GroupChatMessageReactionDeletedEvtMsgBody(chatId: String, messageId: String, reactionEmoji: String)
|
||||||
|
|
||||||
object UserTypingPubMsg { val NAME = "UserTypingPubMsg" }
|
object UserTypingPubMsg { val NAME = "UserTypingPubMsg" }
|
||||||
case class UserTypingPubMsg(header: BbbClientMsgHeader, body: UserTypingPubMsgBody) extends StandardMsg
|
case class UserTypingPubMsg(header: BbbClientMsgHeader, body: UserTypingPubMsgBody) extends StandardMsg
|
||||||
case class UserTypingPubMsgBody(chatId: String)
|
case class UserTypingPubMsgBody(chatId: String)
|
||||||
|
32
bbb-graphql-actions/src/actions/chatDeleteMessageReaction.ts
Normal file
32
bbb-graphql-actions/src/actions/chatDeleteMessageReaction.ts
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
import { RedisMessage } from '../types';
|
||||||
|
import {throwErrorIfInvalidInput} from "../imports/validation";
|
||||||
|
|
||||||
|
export default function buildRedisMessage(sessionVariables: Record<string, unknown>, input: Record<string, unknown>): RedisMessage {
|
||||||
|
throwErrorIfInvalidInput(input,
|
||||||
|
[
|
||||||
|
{name: 'chatId', type: 'string', required: true},
|
||||||
|
{name: 'messageId', type: 'string', required: true},
|
||||||
|
{name: 'reactionEmoji', type: 'string', required: true},
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
const eventName = `DeleteGroupChatMessageReactionReqMsg`;
|
||||||
|
const routing = {
|
||||||
|
meetingId: sessionVariables['x-hasura-meetingid'] as String,
|
||||||
|
userId: sessionVariables['x-hasura-userid'] as String
|
||||||
|
};
|
||||||
|
|
||||||
|
const header = {
|
||||||
|
name: eventName,
|
||||||
|
meetingId: routing.meetingId,
|
||||||
|
userId: routing.userId
|
||||||
|
};
|
||||||
|
|
||||||
|
const body = {
|
||||||
|
chatId: input.chatId,
|
||||||
|
messageId: input.messageId,
|
||||||
|
reactionEmoji: input.reactionEmoji,
|
||||||
|
};
|
||||||
|
|
||||||
|
return { eventName, routing, header, body };
|
||||||
|
}
|
32
bbb-graphql-actions/src/actions/chatSendMessageReaction.ts
Normal file
32
bbb-graphql-actions/src/actions/chatSendMessageReaction.ts
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
import { RedisMessage } from '../types';
|
||||||
|
import {throwErrorIfInvalidInput} from "../imports/validation";
|
||||||
|
|
||||||
|
export default function buildRedisMessage(sessionVariables: Record<string, unknown>, input: Record<string, unknown>): RedisMessage {
|
||||||
|
throwErrorIfInvalidInput(input,
|
||||||
|
[
|
||||||
|
{name: 'chatId', type: 'string', required: true},
|
||||||
|
{name: 'messageId', type: 'string', required: true},
|
||||||
|
{name: 'reactionEmoji', type: 'string', required: true},
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
const eventName = `SendGroupChatMessageReactionReqMsg`;
|
||||||
|
const routing = {
|
||||||
|
meetingId: sessionVariables['x-hasura-meetingid'] as String,
|
||||||
|
userId: sessionVariables['x-hasura-userid'] as String
|
||||||
|
};
|
||||||
|
|
||||||
|
const header = {
|
||||||
|
name: eventName,
|
||||||
|
meetingId: routing.meetingId,
|
||||||
|
userId: routing.userId
|
||||||
|
};
|
||||||
|
|
||||||
|
const body = {
|
||||||
|
chatId: input.chatId,
|
||||||
|
messageId: input.messageId,
|
||||||
|
reactionEmoji: input.reactionEmoji,
|
||||||
|
};
|
||||||
|
|
||||||
|
return { eventName, routing, header, body };
|
||||||
|
}
|
@ -1135,6 +1135,21 @@ LEFT JOIN "chat_user" chat_with ON chat_with."meetingId" = cm."meetingId"
|
|||||||
AND chat_with."userId" != cu."userId"
|
AND chat_with."userId" != cu."userId"
|
||||||
WHERE cm."chatId" != 'MAIN-PUBLIC-GROUP-CHAT';
|
WHERE cm."chatId" != 'MAIN-PUBLIC-GROUP-CHAT';
|
||||||
|
|
||||||
|
CREATE TABLE "chat_message_reaction" (
|
||||||
|
"meetingId" varchar(100),
|
||||||
|
"messageId" varchar(100) REFERENCES "chat_message"("messageId") ON DELETE CASCADE,
|
||||||
|
"userId" varchar(100) not null,
|
||||||
|
"reactionEmoji" varchar(25),
|
||||||
|
"createdAt" timestamp with time zone,
|
||||||
|
CONSTRAINT chat_message_reaction_pk PRIMARY KEY ("messageId", "userId", "reactionEmoji"),
|
||||||
|
FOREIGN KEY ("meetingId", "userId") REFERENCES "user"("meetingId","userId") ON DELETE CASCADE
|
||||||
|
);
|
||||||
|
CREATE INDEX "chat_message_reaction_meeting_message_idx" ON "chat_message_reaction"("meetingId","messageId");
|
||||||
|
CREATE INDEX "chat_message_reaction_meeting_message_idx_rev" ON "chat_message_reaction"("messageId", "meetingId");
|
||||||
|
|
||||||
|
CREATE OR REPLACE VIEW "v_chat_message_reaction" AS SELECT * FROM "chat_message_reaction";
|
||||||
|
|
||||||
|
|
||||||
--============ Presentation / Annotation
|
--============ Presentation / Annotation
|
||||||
|
|
||||||
|
|
||||||
|
@ -109,6 +109,14 @@ type Mutation {
|
|||||||
): Boolean
|
): Boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Mutation {
|
||||||
|
chatDeleteMessageReaction(
|
||||||
|
chatId: String!
|
||||||
|
messageId: String!
|
||||||
|
reactionEmoji: String!
|
||||||
|
): Boolean
|
||||||
|
}
|
||||||
|
|
||||||
type Mutation {
|
type Mutation {
|
||||||
chatEditMessage(
|
chatEditMessage(
|
||||||
chatId: String!
|
chatId: String!
|
||||||
@ -136,6 +144,14 @@ type Mutation {
|
|||||||
): Boolean
|
): Boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Mutation {
|
||||||
|
chatSendMessageReaction(
|
||||||
|
chatId: String!
|
||||||
|
messageId: String!
|
||||||
|
reactionEmoji: String!
|
||||||
|
): Boolean
|
||||||
|
}
|
||||||
|
|
||||||
type Mutation {
|
type Mutation {
|
||||||
chatSetLastSeen: Boolean
|
chatSetLastSeen: Boolean
|
||||||
}
|
}
|
||||||
|
@ -101,6 +101,12 @@ actions:
|
|||||||
handler: '{{HASURA_BBB_GRAPHQL_ACTIONS_ADAPTER_URL}}'
|
handler: '{{HASURA_BBB_GRAPHQL_ACTIONS_ADAPTER_URL}}'
|
||||||
permissions:
|
permissions:
|
||||||
- role: bbb_client
|
- role: bbb_client
|
||||||
|
- name: chatDeleteMessageReaction
|
||||||
|
definition:
|
||||||
|
kind: synchronous
|
||||||
|
handler: '{{HASURA_BBB_GRAPHQL_ACTIONS_ADAPTER_URL}}'
|
||||||
|
permissions:
|
||||||
|
- role: bbb_client
|
||||||
- name: chatEditMessage
|
- name: chatEditMessage
|
||||||
definition:
|
definition:
|
||||||
kind: synchronous
|
kind: synchronous
|
||||||
@ -125,6 +131,12 @@ actions:
|
|||||||
handler: '{{HASURA_BBB_GRAPHQL_ACTIONS_ADAPTER_URL}}'
|
handler: '{{HASURA_BBB_GRAPHQL_ACTIONS_ADAPTER_URL}}'
|
||||||
permissions:
|
permissions:
|
||||||
- role: bbb_client
|
- role: bbb_client
|
||||||
|
- name: chatSendMessageReaction
|
||||||
|
definition:
|
||||||
|
kind: synchronous
|
||||||
|
handler: '{{HASURA_BBB_GRAPHQL_ACTIONS_ADAPTER_URL}}'
|
||||||
|
permissions:
|
||||||
|
- role: bbb_client
|
||||||
- name: chatSetLastSeen
|
- name: chatSetLastSeen
|
||||||
definition:
|
definition:
|
||||||
kind: synchronous
|
kind: synchronous
|
||||||
|
@ -36,6 +36,17 @@ object_relationships:
|
|||||||
remote_table:
|
remote_table:
|
||||||
name: v_user_ref
|
name: v_user_ref
|
||||||
schema: public
|
schema: public
|
||||||
|
array_relationships:
|
||||||
|
- name: reactions
|
||||||
|
using:
|
||||||
|
manual_configuration:
|
||||||
|
column_mapping:
|
||||||
|
meetingId: meetingId
|
||||||
|
messageId: messageId
|
||||||
|
insertion_order: null
|
||||||
|
remote_table:
|
||||||
|
name: v_chat_message_reaction
|
||||||
|
schema: public
|
||||||
select_permissions:
|
select_permissions:
|
||||||
- role: bbb_client
|
- role: bbb_client
|
||||||
permission:
|
permission:
|
||||||
|
@ -36,6 +36,17 @@ object_relationships:
|
|||||||
remote_table:
|
remote_table:
|
||||||
name: v_user_ref
|
name: v_user_ref
|
||||||
schema: public
|
schema: public
|
||||||
|
array_relationships:
|
||||||
|
- name: reactions
|
||||||
|
using:
|
||||||
|
manual_configuration:
|
||||||
|
column_mapping:
|
||||||
|
meetingId: meetingId
|
||||||
|
messageId: messageId
|
||||||
|
insertion_order: null
|
||||||
|
remote_table:
|
||||||
|
name: v_chat_message_reaction
|
||||||
|
schema: public
|
||||||
select_permissions:
|
select_permissions:
|
||||||
- role: bbb_client
|
- role: bbb_client
|
||||||
permission:
|
permission:
|
||||||
|
@ -0,0 +1,33 @@
|
|||||||
|
table:
|
||||||
|
name: v_chat_message_reaction
|
||||||
|
schema: public
|
||||||
|
configuration:
|
||||||
|
column_config: {}
|
||||||
|
custom_column_names: {}
|
||||||
|
custom_name: chat_message_reaction
|
||||||
|
custom_root_fields: {}
|
||||||
|
object_relationships:
|
||||||
|
- name: user
|
||||||
|
using:
|
||||||
|
manual_configuration:
|
||||||
|
column_mapping:
|
||||||
|
meetingId: meetingId
|
||||||
|
userId: userId
|
||||||
|
insertion_order: null
|
||||||
|
remote_table:
|
||||||
|
name: v_user_ref
|
||||||
|
schema: public
|
||||||
|
select_permissions:
|
||||||
|
- role: bbb_client
|
||||||
|
permission:
|
||||||
|
columns:
|
||||||
|
- createdAt
|
||||||
|
- reactionEmoji
|
||||||
|
- userId
|
||||||
|
filter:
|
||||||
|
meetingId:
|
||||||
|
_eq: X-Hasura-MeetingId
|
||||||
|
allow_aggregations: true
|
||||||
|
query_root_fields: []
|
||||||
|
subscription_root_fields: []
|
||||||
|
comment: ""
|
@ -7,6 +7,7 @@
|
|||||||
- "!include public_v_chat.yaml"
|
- "!include public_v_chat.yaml"
|
||||||
- "!include public_v_chat_message_private.yaml"
|
- "!include public_v_chat_message_private.yaml"
|
||||||
- "!include public_v_chat_message_public.yaml"
|
- "!include public_v_chat_message_public.yaml"
|
||||||
|
- "!include public_v_chat_message_reaction.yaml"
|
||||||
- "!include public_v_chat_user.yaml"
|
- "!include public_v_chat_user.yaml"
|
||||||
- "!include public_v_current_time.yaml"
|
- "!include public_v_current_time.yaml"
|
||||||
- "!include public_v_externalVideo.yaml"
|
- "!include public_v_externalVideo.yaml"
|
||||||
|
Loading…
Reference in New Issue
Block a user