Merge pull request #20461 from GuiLeme/update-data-channel-function

feat(plugin): implement `ReplaceEntry()` function for data-channel
This commit is contained in:
Gustavo Trott 2024-06-19 08:36:34 -03:00 committed by GitHub
commit de686a2b8e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
18 changed files with 249 additions and 58 deletions

View File

@ -140,26 +140,26 @@ object ClientSettings extends SystemConfiguration {
} yield {
if (dataChannel.contains("name")) {
val channelName = dataChannel("name").toString
val writePermission = {
if (dataChannel.contains("writePermission")) {
dataChannel("writePermission") match {
val pushPermission = {
if (dataChannel.contains("pushPermission")) {
dataChannel("pushPermission") match {
case wPerm: List[String] => wPerm
case _ => {
logger.warn(s"Invalid writePermission for channel $channelName in plugin $pluginName")
logger.warn(s"Invalid pushPermission for channel $channelName in plugin $pluginName")
List()
}
}
} else {
logger.warn(s"Missing config writePermission for channel $channelName in plugin $pluginName")
logger.warn(s"Missing config pushPermission for channel $channelName in plugin $pluginName")
List()
}
}
val deletePermission = {
if (dataChannel.contains("deletePermission")) {
dataChannel("deletePermission") match {
val replaceOrDeletePermission = {
if (dataChannel.contains("replaceOrDeletePermission")) {
dataChannel("replaceOrDeletePermission") match {
case dPerm: List[String] => dPerm
case _ => {
logger.warn(s"Invalid deletePermission for channel $channelName in plugin $pluginName")
logger.warn(s"Invalid replaceOrDeletePermission for channel $channelName in plugin $pluginName")
List()
}
}
@ -168,7 +168,7 @@ object ClientSettings extends SystemConfiguration {
}
}
pluginDataChannels += (channelName -> DataChannel(channelName, writePermission, deletePermission))
pluginDataChannels += (channelName -> DataChannel(channelName, pushPermission, replaceOrDeletePermission))
}
}
case _ => logger.warn(s"Plugin $pluginName has an invalid dataChannels format")
@ -184,7 +184,7 @@ object ClientSettings extends SystemConfiguration {
pluginsFromConfig
}
case class DataChannel(name: String, writePermission: List[String], deletePermission: List[String])
case class DataChannel(name: String, pushPermission: List[String], replaceOrDeletePermission: List[String])
case class Plugin(name: String, url: String, dataChannels: Map[String, DataChannel])
}

View File

@ -25,21 +25,21 @@ trait PluginDataChannelDeleteEntryMsgHdlr extends HandlerHelpers {
println(s"Data channel '${msg.body.channelName}' not found in plugin '${msg.body.pluginName}'.")
} else {
val hasPermission = for {
deletePermission <- pluginsConfig(msg.body.pluginName).dataChannels(msg.body.channelName).deletePermission
replaceOrDeletePermission <- pluginsConfig(msg.body.pluginName).dataChannels(msg.body.channelName).replaceOrDeletePermission
} yield {
deletePermission.toLowerCase match {
replaceOrDeletePermission.toLowerCase match {
case "all" => true
case "moderator" => user.role == Roles.MODERATOR_ROLE
case "presenter" => user.presenter
case "sender" => {
val senderUserId = PluginDataChannelEntryDAO.getMessageSender(
case "creator" => {
val creatorUserId = PluginDataChannelEntryDAO.getEntryCreator(
meetingId,
msg.body.pluginName,
msg.body.channelName,
msg.body.subChannelName,
msg.body.entryId
)
senderUserId == msg.header.userId
creatorUserId == msg.header.userId
}
case _ => false
}

View File

@ -25,9 +25,9 @@ trait PluginDataChannelPushEntryMsgHdlr extends HandlerHelpers {
println(s"Data channel '${msg.body.channelName}' not found in plugin '${msg.body.pluginName}'.")
} else {
val hasPermission = for {
writePermission <- pluginsConfig(msg.body.pluginName).dataChannels(msg.body.channelName).writePermission
pushPermission <- pluginsConfig(msg.body.pluginName).dataChannels(msg.body.channelName).pushPermission
} yield {
writePermission.toLowerCase match {
pushPermission.toLowerCase match {
case "all" => true
case "moderator" => user.role == Roles.MODERATOR_ROLE
case "presenter" => user.presenter

View File

@ -0,0 +1,63 @@
package org.bigbluebutton.core.apps.plugin
import org.bigbluebutton.ClientSettings
import org.bigbluebutton.common2.msgs.PluginDataChannelReplaceEntryMsg
import org.bigbluebutton.core.db.{JsonUtils, PluginDataChannelEntryDAO}
import org.bigbluebutton.core.domain.MeetingState2x
import org.bigbluebutton.core.models.{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 {
val pluginsConfig = ClientSettings.getPluginsFromConfig(ClientSettings.clientSettingsFromFile)
if (!pluginsConfig.contains(msg.body.pluginName)) {
println(s"Plugin '${msg.body.pluginName}' not found.")
} else if (!pluginsConfig(msg.body.pluginName).dataChannels.contains(msg.body.channelName)) {
println(s"Data channel '${msg.body.channelName}' not found in plugin '${msg.body.pluginName}'.")
} else {
val hasPermission = for {
replaceOrDeletePermission <- pluginsConfig(msg.body.pluginName).dataChannels(msg.body.channelName).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 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

@ -25,9 +25,9 @@ trait PluginDataChannelResetMsgHdlr extends HandlerHelpers {
println(s"Data channel '${msg.body.channelName}' not found in plugin '${msg.body.pluginName}'.")
} else {
val hasPermission = for {
deletePermission <- pluginsConfig(msg.body.pluginName).dataChannels(msg.body.channelName).deletePermission
replaceOrDeletePermission <- pluginsConfig(msg.body.pluginName).dataChannels(msg.body.channelName).replaceOrDeletePermission
} yield {
deletePermission.toLowerCase match {
replaceOrDeletePermission.toLowerCase match {
case "all" => true
case "moderator" => user.role == Roles.MODERATOR_ROLE
case "presenter" => user.presenter

View File

@ -6,6 +6,7 @@ import org.bigbluebutton.common2.msgs.PluginDataChannelDeleteEntryMsgBody
class PluginHdlrs(implicit val context: ActorContext)
extends PluginDataChannelPushEntryMsgHdlr
with PluginDataChannelReplaceEntryMsgHdlr
with PluginDataChannelDeleteEntryMsgHdlr
with PluginDataChannelResetMsgHdlr {

View File

@ -2,6 +2,7 @@ package org.bigbluebutton.core.db
import PostgresProfile.api._
import org.bigbluebutton.core.db.DatabaseConnection.{db, logger}
import org.bigbluebutton.core.util.RandomStringGenerator
import spray.json.JsValue
import scala.concurrent.ExecutionContext.Implicits.global
@ -18,9 +19,9 @@ case class PluginDataChannelEntryDbModel(
pluginName: String,
channelName: String,
subChannelName: String,
// entryId: Option[String] = None,
entryId: Option[String] = None,
payloadJson: JsValue,
fromUserId: String,
createdBy: String,
toRoles: Option[List[String]],
toUserIds: Option[List[String]],
createdAt: java.sql.Timestamp,
@ -32,28 +33,29 @@ class PluginDataChannelEntryDbTableDef(tag: Tag) extends Table[PluginDataChannel
val pluginName = column[String]("pluginName", O.PrimaryKey)
val channelName = column[String]("channelName", O.PrimaryKey)
val subChannelName = column[String]("subChannelName")
// val entryId = column[Option[String]]("messageId", O.PrimaryKey) //// The messageId is generated by the database
val entryId = column[Option[String]]("entryId", O.PrimaryKey)
val payloadJson = column[JsValue]("payloadJson")
val fromUserId = column[String]("fromUserId")
val createdBy = column[String]("createdBy")
val toRoles = column[Option[List[String]]]("toRoles")
val toUserIds = column[Option[List[String]]]("toUserIds")
val createdAt = column[java.sql.Timestamp]("createdAt")
val deletedAt = column[Option[java.sql.Timestamp]]("deletedAt")
override def * = (meetingId, pluginName, channelName, subChannelName, payloadJson, fromUserId, toRoles, toUserIds, createdAt, deletedAt) <> (PluginDataChannelEntryDbModel.tupled, PluginDataChannelEntryDbModel.unapply)
override def * = (meetingId, pluginName, channelName, subChannelName, entryId, payloadJson, createdBy, toRoles, toUserIds, createdAt, deletedAt) <> (PluginDataChannelEntryDbModel.tupled, PluginDataChannelEntryDbModel.unapply)
}
object PluginDataChannelEntryDAO {
def insert(meetingId: String, pluginName: String, channelName: String, subChannelName: String, senderUserId: String,
def insert(meetingId: String, pluginName: String, channelName: String, subChannelName: String, createdBy: String,
payloadJson: Map[String, Any], toRoles: List[String], toUserIds: List[String]) = {
DatabaseConnection.db.run(
TableQuery[PluginDataChannelEntryDbTableDef].forceInsert(
PluginDataChannelEntryDbModel(
entryId = Some(RandomStringGenerator.randomAlphanumericString(50)),
meetingId = meetingId,
pluginName = pluginName,
channelName = channelName,
subChannelName = subChannelName,
payloadJson = JsonUtils.mapToJson(payloadJson),
fromUserId = senderUserId,
createdBy = createdBy,
toRoles = toRoles.map(_.toUpperCase).filter(Permission.allowedRoles.contains) match {
case Nil => None
case filtered => Some(filtered)
@ -86,9 +88,9 @@ object PluginDataChannelEntryDAO {
}
}
def getMessageSender(meetingId: String, pluginName: String, channelName: String,
subChannelName: String, entryId: String): String = {
val query = sql"""SELECT "fromUserId"
def getEntryCreator(meetingId: String, pluginName: String, channelName: String,
subChannelName: String, entryId: String): String = {
val query = sql"""SELECT "createdBy"
FROM "pluginDataChannelEntry"
WHERE "deletedAt" is null
AND "meetingId" = ${meetingId}
@ -123,4 +125,23 @@ object PluginDataChannelEntryDAO {
}
}
def replace(meetingId: String, pluginName: String, channelName: String,
subChannelName: String, entryId: String, payloadJson: JsValue) = {
DatabaseConnection.db.run(
TableQuery[PluginDataChannelEntryDbTableDef]
.filter(_.meetingId === meetingId)
.filter(_.pluginName === pluginName)
.filter(_.channelName === channelName)
.filter(_.subChannelName === subChannelName)
.filter(_.entryId === entryId)
.filter(_.deletedAt.isEmpty)
.map(_.payloadJson)
.update(payloadJson)
).onComplete {
case Success(rowsAffected) => DatabaseConnection.logger.debug(s"$rowsAffected row(s) updated with new payloadJson on pluginDataChannelEntry table!")
case Failure(e) => DatabaseConnection.logger.debug(s"Error updating with new payloadJson for table pluginDataChannelEntry: $e")
}
}
}

View File

@ -418,6 +418,9 @@ class ReceivedJsonMsgHandlerActor(
case PluginDataChannelPushEntryMsg.NAME =>
routeGenericMsg[PluginDataChannelPushEntryMsg](envelope, jsonNode)
case PluginDataChannelReplaceEntryMsg.NAME =>
routeGenericMsg[PluginDataChannelReplaceEntryMsg](envelope, jsonNode)
case PluginDataChannelDeleteEntryMsg.NAME =>
routeGenericMsg[PluginDataChannelDeleteEntryMsg](envelope, jsonNode)

View File

@ -714,9 +714,10 @@ class MeetingActor(
state = groupChatApp.handle(m, state, liveMeeting, msgBus)
// Plugin
case m: PluginDataChannelPushEntryMsg => pluginHdlrs.handle(m, state, liveMeeting)
case m: PluginDataChannelDeleteEntryMsg => pluginHdlrs.handle(m, state, liveMeeting)
case m: PluginDataChannelResetMsg => pluginHdlrs.handle(m, state, liveMeeting)
case m: PluginDataChannelPushEntryMsg => pluginHdlrs.handle(m, state, liveMeeting)
case m: PluginDataChannelReplaceEntryMsg => pluginHdlrs.handle(m, state, liveMeeting)
case m: PluginDataChannelDeleteEntryMsg => pluginHdlrs.handle(m, state, liveMeeting)
case m: PluginDataChannelResetMsg => pluginHdlrs.handle(m, state, liveMeeting)
// Webcams
case m: UserBroadcastCamStartMsg =>

View File

@ -16,20 +16,30 @@ case class PluginDataChannelPushEntryMsgBody(
toUserIds: List[String],
)
object PluginDataChannelReplaceEntryMsg { val NAME = "PluginDataChannelReplaceEntryMsg" }
case class PluginDataChannelReplaceEntryMsg(header: BbbClientMsgHeader, body: PluginDataChannelReplaceEntryMsgBody) extends StandardMsg
case class PluginDataChannelReplaceEntryMsgBody(
pluginName: String,
channelName: String,
subChannelName: String,
payloadJson: Map[String, Any],
entryId: String,
)
object PluginDataChannelDeleteEntryMsg { val NAME = "PluginDataChannelDeleteEntryMsg" }
case class PluginDataChannelDeleteEntryMsg(header: BbbClientMsgHeader, body: PluginDataChannelDeleteEntryMsgBody) extends StandardMsg
case class PluginDataChannelDeleteEntryMsgBody(
pluginName: String,
subChannelName: String,
channelName: String,
entryId: String
)
pluginName: String,
subChannelName: String,
channelName: String,
entryId: String
)
object PluginDataChannelResetMsg { val NAME = "PluginDataChannelResetMsg" }
case class PluginDataChannelResetMsg(header: BbbClientMsgHeader, body: PluginDataChannelResetMsgBody) extends StandardMsg
case class PluginDataChannelResetMsgBody(
pluginName: String,
subChannelName: String,
channelName: String
)
pluginName: String,
subChannelName: String,
channelName: String
)

View File

@ -0,0 +1,38 @@
import { RedisMessage } from '../types';
import { ValidationError } from '../types/ValidationError';
import {throwErrorIfInvalidInput} from "../imports/validation";
export default function buildRedisMessage(sessionVariables: Record<string, unknown>, input: Record<string, unknown>): RedisMessage {
throwErrorIfInvalidInput(input,
[
{name: 'pluginName', type: 'string', required: true},
{name: 'subChannelName', type: 'string', required: true},
{name: 'channelName', type: 'string', required: true},
{name: 'payloadJson', type: 'json', required: true},
{name: 'entryId', type: 'string', required: true},
]
)
const eventName = `PluginDataChannelReplaceEntryMsg`;
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 = {
pluginName: input.pluginName,
channelName: input.channelName,
subChannelName: input.subChannelName,
payloadJson: input.payloadJson,
entryId: input.entryId,
};
return { eventName, routing, header, body };
}

View File

@ -2033,13 +2033,13 @@ CREATE TABLE "pluginDataChannelEntry" (
"entryId" varchar(50) DEFAULT uuid_generate_v4(),
"subChannelName" varchar(255),
"payloadJson" jsonb,
"fromUserId" varchar(50),
"createdBy" varchar(50),
"toRoles" varchar[], --MODERATOR, VIEWER, PRESENTER
"toUserIds" varchar[],
"createdAt" timestamp with time zone DEFAULT current_timestamp,
"deletedAt" timestamp with time zone,
CONSTRAINT "pluginDataChannel_pkey" PRIMARY KEY ("meetingId","pluginName","channelName","entryId", "subChannelName"),
FOREIGN KEY ("meetingId", "fromUserId") REFERENCES "user"("meetingId","userId") ON DELETE CASCADE
FOREIGN KEY ("meetingId", "createdBy") REFERENCES "user"("meetingId","userId") ON DELETE CASCADE
);
create index "idx_pluginDataChannelEntry_pk_reverse" on "pluginDataChannelEntry"("pluginName", "meetingId", "channelName", "subChannelName");
create index "idx_pluginDataChannelEntry_pk_reverse_b" on "pluginDataChannelEntry"("channelName", "pluginName", "meetingId", "subChannelName");
@ -2048,7 +2048,7 @@ create index "idx_pluginDataChannelEntry_channelName" on "pluginDataChannelEntry
create index "idx_pluginDataChannelEntry_roles" on "pluginDataChannelEntry"("meetingId", "toRoles", "toUserIds", "createdAt") where "deletedAt" is null;
CREATE OR REPLACE VIEW "v_pluginDataChannelEntry" AS
SELECT u."meetingId", u."userId", m."pluginName", m."channelName", m."subChannelName", m."entryId", m."payloadJson", m."fromUserId", m."toRoles", m."createdAt"
SELECT u."meetingId", u."userId", m."pluginName", m."channelName", m."subChannelName", m."entryId", m."payloadJson", m."createdBy", m."toRoles", m."createdAt"
FROM "user" u
JOIN "pluginDataChannelEntry" m ON m."meetingId" = u."meetingId"
AND ((m."toRoles" IS NULL AND m."toUserIds" IS NULL)

View File

@ -234,6 +234,16 @@ type Mutation {
): Boolean
}
type Mutation {
pluginDataChannelReplaceEntry(
pluginName: String!
subChannelName: String!
channelName: String!
entryId: String!
payloadJson: String!
): Boolean
}
type Mutation {
pluginDataChannelReset(
pluginName: String!

View File

@ -203,6 +203,12 @@ actions:
handler: '{{HASURA_BBB_GRAPHQL_ACTIONS_ADAPTER_URL}}'
permissions:
- role: bbb_client
- name: pluginDataChannelReplaceEntry
definition:
kind: synchronous
handler: '{{HASURA_BBB_GRAPHQL_ACTIONS_ADAPTER_URL}}'
permissions:
- role: bbb_client
- name: pluginDataChannelReset
definition:
kind: synchronous

View File

@ -7,11 +7,11 @@ configuration:
custom_name: pluginDataChannelEntry
custom_root_fields: {}
object_relationships:
- name: sender
- name: creator
using:
manual_configuration:
column_mapping:
fromUserId: userId
createdBy: userId
meetingId: meetingId
insertion_order: null
remote_table:
@ -27,7 +27,7 @@ select_permissions:
- channelName
- entryId
- payloadJson
- fromUserId
- createdBy
- toRoles
filter:
_and:

View File

@ -5,12 +5,16 @@ import * as PluginSdk from 'bigbluebutton-html-plugin-sdk';
import {
DataChannelArguments,
PushEntryFunction, ObjectTo, ToRole, ToUserId,
ReplaceEntryFunctionArguments,
} from 'bigbluebutton-html-plugin-sdk/dist/cjs/data-channel/types';
import { DataChannelHooks } from 'bigbluebutton-html-plugin-sdk/dist/cjs/data-channel/enums';
import { HookEvents } from 'bigbluebutton-html-plugin-sdk/dist/cjs/core/enum';
import { HookEventWrapper, UpdatedEventDetails } from 'bigbluebutton-html-plugin-sdk/dist/cjs/core/types';
import { PLUGIN_DATA_CHANNEL_DELETE_MUTATION, PLUGIN_DATA_CHANNEL_PUSH_MUTATION, PLUGIN_DATA_CHANNEL_RESET_MUTATION } from '../mutations';
import {
PLUGIN_DATA_CHANNEL_DELETE_MUTATION, PLUGIN_DATA_CHANNEL_PUSH_MUTATION,
PLUGIN_DATA_CHANNEL_REPLACE_MUTATION, PLUGIN_DATA_CHANNEL_RESET_MUTATION,
} from '../mutations';
export interface DataChannelItemManagerWriterProps {
pluginName: string;
@ -46,9 +50,10 @@ const DataChannelItemManagerWriter: React.ElementType<DataChannelItemManagerWrit
dataChannelIdentifier,
} = props;
const [pushEntryFunctionPluginDataChannelMessage] = useMutation(PLUGIN_DATA_CHANNEL_PUSH_MUTATION);
const [deleteEntryFunctionPluginDataChannelMessage] = useMutation(PLUGIN_DATA_CHANNEL_DELETE_MUTATION);
const [resetFunctionPluginDataChannelMessage] = useMutation(PLUGIN_DATA_CHANNEL_RESET_MUTATION);
const [pushEntryFunctionPluginDataChannel] = useMutation(PLUGIN_DATA_CHANNEL_PUSH_MUTATION);
const [deleteEntryFunctionPluginDataChannel] = useMutation(PLUGIN_DATA_CHANNEL_DELETE_MUTATION);
const [resetFunctionPluginDataChannel] = useMutation(PLUGIN_DATA_CHANNEL_RESET_MUTATION);
const [replaceEntryFunctionPluginDataChannel] = useMutation(PLUGIN_DATA_CHANNEL_REPLACE_MUTATION);
const useDataChannelHandlerFunction = ((msg: object, objectsTo?: ObjectTo[]) => {
const argumentsOfPushEntryFunction = {
@ -82,7 +87,7 @@ const DataChannelItemManagerWriter: React.ElementType<DataChannelItemManagerWrit
if (rolesTo.length > 0) argumentsOfPushEntryFunction.variables.toRoles = rolesTo;
if (usersTo.length > 0) argumentsOfPushEntryFunction.variables.toUserIds = usersTo;
}
pushEntryFunctionPluginDataChannelMessage(argumentsOfPushEntryFunction);
pushEntryFunctionPluginDataChannel(argumentsOfPushEntryFunction);
}) as PushEntryFunction;
pluginApi.mapOfPushEntryFunctions[dataChannelIdentifier] = useDataChannelHandlerFunction;
@ -93,7 +98,7 @@ const DataChannelItemManagerWriter: React.ElementType<DataChannelItemManagerWrit
if (event.detail.hook === DataChannelHooks.DATA_CHANNEL_DELETE) {
const eventDetails = event.detail as UpdatedEventDetails<string>;
const hookArguments = eventDetails?.hookArguments as DataChannelArguments | undefined;
deleteEntryFunctionPluginDataChannelMessage({
deleteEntryFunctionPluginDataChannel({
variables: {
pluginName: hookArguments?.pluginName,
channelName: hookArguments?.channelName,
@ -104,7 +109,7 @@ const DataChannelItemManagerWriter: React.ElementType<DataChannelItemManagerWrit
} else if (event.detail.hook === DataChannelHooks.DATA_CHANNEL_RESET) {
const eventDetails = event.detail as UpdatedEventDetails<void>;
const hookArguments = eventDetails?.hookArguments as DataChannelArguments | undefined;
resetFunctionPluginDataChannelMessage({
resetFunctionPluginDataChannel({
variables: {
pluginName: hookArguments?.pluginName,
channelName: hookArguments?.channelName,
@ -114,10 +119,29 @@ const DataChannelItemManagerWriter: React.ElementType<DataChannelItemManagerWrit
}
}) as EventListener;
const replaceEntryHandler: EventListener = (
(event: HookEventWrapper<void>) => {
if (event.detail.hook === DataChannelHooks.DATA_CHANNEL_REPLACE) {
const eventDetails = event.detail as UpdatedEventDetails<ReplaceEntryFunctionArguments<object>>;
const hookArguments = eventDetails?.hookArguments as DataChannelArguments | undefined;
replaceEntryFunctionPluginDataChannel({
variables: {
pluginName: hookArguments?.pluginName,
channelName: hookArguments?.channelName,
subChannelName: hookArguments?.subChannelName,
entryId: eventDetails.data.entryId,
payloadJson: eventDetails.data.payloadJson,
},
});
}
}) as EventListener;
useEffect(() => {
window.addEventListener(HookEvents.UPDATED, deleteOrResetHandler);
window.addEventListener(HookEvents.UPDATED, replaceEntryHandler);
return () => {
window.removeEventListener(HookEvents.UPDATED, deleteOrResetHandler);
window.removeEventListener(HookEvents.UPDATED, replaceEntryHandler);
};
}, []);
return null;

View File

@ -36,3 +36,17 @@ export const PLUGIN_DATA_CHANNEL_DELETE_MUTATION = gql`
)
}
`;
export const PLUGIN_DATA_CHANNEL_REPLACE_MUTATION = gql`
mutation PluginDataChannelReplaceEntry($pluginName: String!,
$subChannelName: String!, $channelName: String!,
$payloadJson: json!, $entryId: String!) {
pluginDataChannelReplaceEntry(
entryId: $entryId,
pluginName: $pluginName,
channelName: $channelName,
subChannelName: $subChannelName,
payloadJson: $payloadJson
)
}
`;

View File

@ -16,7 +16,7 @@ const PLUGIN_DATA_CHANNEL_NEW_ITEMS = gql`
subChannelName,
entryId,
payloadJson,
fromUserId,
createdBy,
pluginName,
toRoles,
}
@ -40,7 +40,7 @@ const PLUGIN_DATA_CHANNEL_All_ITEMS = gql`
subChannelName,
entryId,
payloadJson,
fromUserId,
createdBy,
pluginName,
toRoles,
}
@ -65,7 +65,7 @@ const PLUGIN_DATA_CHANNEL_LATEST_ITEM = gql`
subChannelName,
entryId,
payloadJson,
fromUserId,
createdBy,
pluginName,
toRoles,
}