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 EditGroupChatMessageReqMsgHdlr
|
||||
with DeleteGroupChatMessageReqMsgHdlr
|
||||
with SendGroupChatMessageReactionReqMsgHdlr
|
||||
with DeleteGroupChatMessageReactionReqMsgHdlr
|
||||
with SendGroupChatMessageFromApiSysPubMsgHdlr
|
||||
with SetGroupChatVisibleReqMsgHdlr
|
||||
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)
|
||||
case DeleteGroupChatMessageReqMsg.NAME =>
|
||||
routeGenericMsg[DeleteGroupChatMessageReqMsg](envelope, jsonNode)
|
||||
case SendGroupChatMessageReactionReqMsg.NAME =>
|
||||
routeGenericMsg[SendGroupChatMessageReactionReqMsg](envelope, jsonNode)
|
||||
case DeleteGroupChatMessageReactionReqMsg.NAME =>
|
||||
routeGenericMsg[DeleteGroupChatMessageReactionReqMsg](envelope, jsonNode)
|
||||
case GetGroupChatMsgsReqMsg.NAME =>
|
||||
routeGenericMsg[GetGroupChatMsgsReqMsg](envelope, jsonNode)
|
||||
case CreateGroupChatReqMsg.NAME =>
|
||||
|
@ -327,4 +327,22 @@ trait HandlerHelpers extends SystemConfiguration {
|
||||
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 =>
|
||||
state = groupChatApp.handle(m, state, liveMeeting, msgBus)
|
||||
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
|
||||
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: EditGroupChatMessageReqMsg => logChatMessage(msg)
|
||||
case m: DeleteGroupChatMessageReqMsg => logChatMessage(msg)
|
||||
case m: DeleteGroupChatMessageReqMsg => logChatMessage(msg)
|
||||
case m: DeleteGroupChatMessageReqMsg => logChatMessage(msg)
|
||||
case m: GroupChatMessageBroadcastEvtMsg => logChatMessage(msg)
|
||||
case m: GetGroupChatMsgsReqMsg => 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 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" }
|
||||
case class UserTypingPubMsg(header: BbbClientMsgHeader, body: UserTypingPubMsgBody) extends StandardMsg
|
||||
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"
|
||||
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
|
||||
|
||||
|
||||
|
@ -109,6 +109,14 @@ type Mutation {
|
||||
): Boolean
|
||||
}
|
||||
|
||||
type Mutation {
|
||||
chatDeleteMessageReaction(
|
||||
chatId: String!
|
||||
messageId: String!
|
||||
reactionEmoji: String!
|
||||
): Boolean
|
||||
}
|
||||
|
||||
type Mutation {
|
||||
chatEditMessage(
|
||||
chatId: String!
|
||||
@ -136,6 +144,14 @@ type Mutation {
|
||||
): Boolean
|
||||
}
|
||||
|
||||
type Mutation {
|
||||
chatSendMessageReaction(
|
||||
chatId: String!
|
||||
messageId: String!
|
||||
reactionEmoji: String!
|
||||
): Boolean
|
||||
}
|
||||
|
||||
type Mutation {
|
||||
chatSetLastSeen: Boolean
|
||||
}
|
||||
|
@ -101,6 +101,12 @@ actions:
|
||||
handler: '{{HASURA_BBB_GRAPHQL_ACTIONS_ADAPTER_URL}}'
|
||||
permissions:
|
||||
- role: bbb_client
|
||||
- name: chatDeleteMessageReaction
|
||||
definition:
|
||||
kind: synchronous
|
||||
handler: '{{HASURA_BBB_GRAPHQL_ACTIONS_ADAPTER_URL}}'
|
||||
permissions:
|
||||
- role: bbb_client
|
||||
- name: chatEditMessage
|
||||
definition:
|
||||
kind: synchronous
|
||||
@ -125,6 +131,12 @@ actions:
|
||||
handler: '{{HASURA_BBB_GRAPHQL_ACTIONS_ADAPTER_URL}}'
|
||||
permissions:
|
||||
- role: bbb_client
|
||||
- name: chatSendMessageReaction
|
||||
definition:
|
||||
kind: synchronous
|
||||
handler: '{{HASURA_BBB_GRAPHQL_ACTIONS_ADAPTER_URL}}'
|
||||
permissions:
|
||||
- role: bbb_client
|
||||
- name: chatSetLastSeen
|
||||
definition:
|
||||
kind: synchronous
|
||||
|
@ -36,6 +36,17 @@ object_relationships:
|
||||
remote_table:
|
||||
name: v_user_ref
|
||||
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:
|
||||
- role: bbb_client
|
||||
permission:
|
||||
|
@ -36,6 +36,17 @@ object_relationships:
|
||||
remote_table:
|
||||
name: v_user_ref
|
||||
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:
|
||||
- role: bbb_client
|
||||
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_message_private.yaml"
|
||||
- "!include public_v_chat_message_public.yaml"
|
||||
- "!include public_v_chat_message_reaction.yaml"
|
||||
- "!include public_v_chat_user.yaml"
|
||||
- "!include public_v_current_time.yaml"
|
||||
- "!include public_v_externalVideo.yaml"
|
||||
|
Loading…
Reference in New Issue
Block a user