From 98a172645861c031d0b07a4067a31cd53e898e01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20Garc=C3=ADa?= Date: Thu, 20 Nov 2025 02:59:38 +0100 Subject: [PATCH 1/6] feat: rocketchat addon --- .../addons/rocketchat/assets/logo.png | Bin 0 -> 16290 bytes .../rocketchat/class-rocketchat-addon.php | 84 ++++++ .../class-rocketchat-form-bridge.php | 78 ++++++ forms-bridge/addons/rocketchat/hooks.php | 260 ++++++++++++++++++ .../addons/rocketchat/jobs/create-dm.php | 57 ++++ .../addons/rocketchat/templates/contact.php | 97 +++++++ .../rocketchat/templates/direct-message.php | 94 +++++++ .../addons/rocketchat/templates/support.php | 118 ++++++++ forms-bridge/deps/http | 2 +- 9 files changed, 789 insertions(+), 1 deletion(-) create mode 100644 forms-bridge/addons/rocketchat/assets/logo.png create mode 100644 forms-bridge/addons/rocketchat/class-rocketchat-addon.php create mode 100644 forms-bridge/addons/rocketchat/class-rocketchat-form-bridge.php create mode 100644 forms-bridge/addons/rocketchat/hooks.php create mode 100644 forms-bridge/addons/rocketchat/jobs/create-dm.php create mode 100644 forms-bridge/addons/rocketchat/templates/contact.php create mode 100644 forms-bridge/addons/rocketchat/templates/direct-message.php create mode 100644 forms-bridge/addons/rocketchat/templates/support.php diff --git a/forms-bridge/addons/rocketchat/assets/logo.png b/forms-bridge/addons/rocketchat/assets/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..2d8bbe422a67f686ee73d92392d6cc9d4abd864e GIT binary patch literal 16290 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 '__rocketchat-' . time(), + 'endpoint' => '/api/v1/users.list', + 'method' => 'GET', + 'backend' => $backend, + ) + ); + + $response = $bridge->submit( array( 'status' => 'active' ) ); + + if ( is_wp_error( $response ) ) { + Logger::log( 'Rocket.Chat backend ping error response', Logger::ERROR ); + Logger::log( $response, Logger::ERROR ); + return false; + } + + return true; + } + + /** + * Performs an introspection of the backend endpoint and returns API fields. + * + * @param string $endpoint API endpoint. + * @param string $backend Backend name. + * @param string|null $method HTTP method. + * + * @return array List of fields and content type of the endpoint. + */ + public function get_endpoint_schema( $endpoint, $backend, $method = null ) { + return array(); + } +} + +Rocketchat_Addon::setup(); diff --git a/forms-bridge/addons/rocketchat/class-rocketchat-form-bridge.php b/forms-bridge/addons/rocketchat/class-rocketchat-form-bridge.php new file mode 100644 index 00000000..0b0ea594 --- /dev/null +++ b/forms-bridge/addons/rocketchat/class-rocketchat-form-bridge.php @@ -0,0 +1,78 @@ +backend(); + + $message_attachments = array(); + foreach ( $attachments as $name => $path ) { + $info = pathinfo( $path ); + $filename = $info['basename']; + + $response = $backend->post( + '/api/v1/rooms.media/' . $room_id, + array( + 'msg' => $name, + ), + array( + 'Content-Type' => 'multipart/form-data', + ), + array( + 'file' => $path, + ) + ); + + if ( is_wp_error( $response ) ) { + return $response; + } + + if ( ! $response['data']['success'] ) { + return new WP_Error( 'rocketchat_upload', __( 'Can not upload a file to Rocket.Chat', 'forms-bridge' ), $response['data'] ); + } + + unset( $payload[ $name ] ); + unset( $payload[ $name . '_filename' ] ); + + $message_attachments[] = array( + 'title' => $filename, + 'title_link' => $response['data']['file']['url'], + 'title_link_download' => true, + ); + } + + $payload['attachments'] = $message_attachments; + } + + return parent::submit( $payload, array() ); + } +} diff --git a/forms-bridge/addons/rocketchat/hooks.php b/forms-bridge/addons/rocketchat/hooks.php new file mode 100644 index 00000000..98b75086 --- /dev/null +++ b/forms-bridge/addons/rocketchat/hooks.php @@ -0,0 +1,260 @@ + array( + array( + 'ref' => '#backend', + 'name' => 'name', + 'description' => __( + 'Label of the Rocket.Chat API backend connection', + 'forms-bridge' + ), + 'default' => 'Rocket.Chat API', + ), + array( + 'ref' => '#backend/headers[]', + 'name' => 'X-Auth-Token', + 'label' => __( 'Personal Access Token', 'forms-bridge' ), + 'description' => __( + 'Use Personal Access Tokens to interact securely with the Rocket.Chat API', + 'forms-bridge', + ), + 'type' => 'text', + 'required' => true, + ), + array( + 'ref' => '#backend/headers[]', + 'name' => 'X-User-Id', + 'label' => __( 'User Id', 'forms-bridge' ), + 'description' => __( + 'Displayed when the Personal Access Token is created', + 'forms-bridge', + ), + 'type' => 'text', + 'required' => true, + ), + array( + 'ref' => '#bridge', + 'name' => 'method', + 'value' => 'POST', + ), + array( + 'ref' => '#bridge/custom_fields[]', + 'name' => 'emoji', + 'label' => __( 'Emoji', 'forms-bridge' ), + 'description' => __( 'If provided, the avatar will be displayed as an emoji', 'forms-bridge' ), + 'type' => 'select', + 'options' => array( + array( + 'value' => ':smile:', + 'label' => '😄', + ), + array( + 'value' => ':grinning:', + 'label' => '😀', + ), + array( + 'value' => ':laughing:', + 'label' => '😂', + ), + array( + 'value' => ':wink:', + 'label' => '😉', + ), + array( + 'value' => ':blush:', + 'label' => '😊', + ), + array( + 'value' => ':heart_eyes:', + 'label' => '😍', + ), + array( + 'value' => ':sunglasses:', + 'label' => '😎', + ), + array( + 'value' => ':rocket:', + 'label' => '🚀', + ), + array( + 'value' => ':alien:', + 'label' => '👽', + ), + array( + 'value' => ':robot:', + 'label' => '🤖', + ), + array( + 'value' => ':ghost:', + 'label' => '👻', + ), + array( + 'value' => ':cat:', + 'label' => '🐱', + ), + array( + 'value' => ':dog:', + 'label' => '🐶', + ), + array( + 'value' => ':panda_face:', + 'label' => '🐼', + ), + array( + 'value' => ':owl:', + 'label' => '🦉', + ), + array( + 'value' => ':fox_face:', + 'label' => '🦊', + ), + array( + 'value' => ':fire:', + 'label' => '🔥', + ), + array( + 'value' => ':sparkles:', + 'label' => '✨', + ), + array( + 'value' => ':star:', + 'label' => '⭐', + ), + array( + 'value' => ':crescent_moon:', + 'label' => '🌙', + ), + array( + 'value' => ':rainbow:', + 'label' => '🌈', + ), + array( + 'value' => ':tada:', + 'label' => '🎉', + ), + array( + 'value' => ':confetti_ball:', + 'label' => '🎊', + ), + array( + 'value' => ':bulb:', + 'label' => '💡', + ), + array( + 'value' => ':gift:', + 'label' => '🎁', + ), + array( + 'value' => ':trophy:', + 'label' => '🏆', + ), + array( + 'value' => ':microphone:', + 'label' => '🎤', + ), + array( + 'value' => ':headphones:', + 'label' => '🎧', + ), + array( + 'value' => ':camera:', + 'label' => '📷', + ), + array( + 'value' => ':video_game:', + 'label' => '🎮', + ), + array( + 'value' => ':book:', + 'label' => '📖', + ), + array( + 'value' => ':coffee:', + 'label' => '☕', + ), + array( + 'value' => ':pizza:', + 'label' => '🍕', + ), + array( + 'value' => ':hamburger:', + 'label' => '🍔', + ), + array( + 'value' => ':fries:', + 'label' => '🍟', + ), + array( + 'value' => ':cookie:', + 'label' => '🍪', + ), + array( + 'value' => ':cake:', + 'label' => '🍰', + ), + array( + 'value' => ':icecream:', + 'label' => '🍦', + ), + array( + 'value' => ':beer:', + 'label' => '🍺', + ), + array( + 'value' => ':wine_glass:', + 'label' => '🍷', + ), + array( + 'value' => ':earth_americas:', + 'label' => '🌎', + ), + array( + 'value' => ':milky_way:', + 'label' => '🌌', + ), + ), + ), + ), + 'bridge' => array( + 'method' => 'POST', + ), + ), + $defaults, + $schema, + ); + }, + 10, + 3 +); + +add_filter( + 'forms_bridge_bridge_schema', + function ( $schema, $addon ) { + if ( 'rocketchat' !== $addon ) { + return $schema; + } + + $schema['properties']['method']['enum'] = array( 'GET', 'POST' ); + return $schema; + }, + 10, + 2 +); diff --git a/forms-bridge/addons/rocketchat/jobs/create-dm.php b/forms-bridge/addons/rocketchat/jobs/create-dm.php new file mode 100644 index 00000000..cdbc57c6 --- /dev/null +++ b/forms-bridge/addons/rocketchat/jobs/create-dm.php @@ -0,0 +1,57 @@ + __( 'Create DM', 'forms-bridge' ), + 'description' => __( 'Creates a direct message session with a user', 'forms-bridge' ), + 'method' => 'forms_bridge_rocketchat_create_dm', + 'input' => array( + array( + 'name' => 'username', + 'schema' => array( 'type' => 'string' ), + 'required' => true, + ), + ), + 'output' => array( + array( + 'name' => 'roomId', + 'schema' => array( 'type' => 'string' ), + ), + ), +); + +/** + * Open DM job method. + * + * @param array $payload Bridge payload. + * @param Form_Bridge $bridge Bridge object. + * + * @return array + */ +function forms_bridge_rocketchat_create_dm( $payload, $bridge ) { + $response = $bridge->patch( + array( + 'endpoint' => '/api/v1/dm.create', + 'method' => 'POST', + ) + )->submit( array( 'username' => $payload['username'] ) ); + + if ( is_wp_error( $response ) ) { + return $response; + } + + $room_id = $response['data']['room']['rid']; + $payload['roomId'] = $room_id; + + return $payload; +} diff --git a/forms-bridge/addons/rocketchat/templates/contact.php b/forms-bridge/addons/rocketchat/templates/contact.php new file mode 100644 index 00000000..88a8dffc --- /dev/null +++ b/forms-bridge/addons/rocketchat/templates/contact.php @@ -0,0 +1,97 @@ + __( 'Contacts Channel', 'forms-bridge' ), + 'description' => __( + 'Contact form template. The resulting bridge will notify form submissions in a Slack channel', + 'forms-bridge' + ), + 'fields' => array( + array( + 'ref' => '#bridge', + 'name' => 'endpoint', + 'value' => '/api/v1/chat.postMessage', + ), + array( + 'ref' => '#bridge/custom_fields[]', + 'name' => 'channel', + 'label' => __( 'Channel', 'forms-bridge' ), + 'description' => __( + 'Name of the channel where messages will be sent', + 'forms-bridge' + ), + 'type' => 'select', + 'options' => array( + 'endpoint' => '/api/v1/rooms.get', + 'finger' => array( + 'value' => 'update[]._id', + 'label' => 'update[].name', + ), + ), + 'required' => true, + ), + array( + 'ref' => '#form', + 'name' => 'title', + 'default' => __( 'Contacts', 'forms-bridge' ), + ), + ), + 'form' => array( + 'title' => __( 'Contacts', 'forms-bridge' ), + 'fields' => array( + array( + 'name' => 'your-name', + 'label' => __( 'Your name', 'forms-bridge' ), + 'type' => 'text', + 'required' => true, + ), + array( + 'name' => 'your-email', + 'label' => __( 'Your email', 'forms-bridge' ), + 'type' => 'email', + 'required' => true, + ), + array( + 'name' => 'comments', + 'label' => __( 'Comments', 'forms-bridge' ), + 'type' => 'textarea', + ), + ), + ), + 'bridge' => array( + 'endpoint' => '/api/v1/chat.postMessage', + 'mutations' => array( + array( + array( + 'from' => 'your-name', + 'to' => 'text.name', + 'cast' => 'string', + ), + array( + 'from' => 'your-email', + 'to' => 'text.email', + 'cast' => 'string', + ), + array( + 'from' => '?comments', + 'to' => 'text.comments', + 'cast' => 'string', + ), + array( + 'from' => 'text', + 'to' => 'text', + 'cast' => 'pretty_json', + ), + ), + ), + ), +); diff --git a/forms-bridge/addons/rocketchat/templates/direct-message.php b/forms-bridge/addons/rocketchat/templates/direct-message.php new file mode 100644 index 00000000..64011fee --- /dev/null +++ b/forms-bridge/addons/rocketchat/templates/direct-message.php @@ -0,0 +1,94 @@ + __( 'Direct Messages', 'forms-bridge' ), + 'description' => __( + 'Contact form template. The resulting bridge will send form submissions as direct messages in Rocket.Chat', + 'forms-bridge' + ), + 'fields' => array( + array( + 'ref' => '#bridge', + 'name' => 'endpoint', + 'value' => '/api/v1/chat.postMessage', + ), + array( + 'ref' => '#bridge/custom_fields[]', + 'name' => 'username', + 'label' => __( 'User', 'forms-bridge' ), + 'type' => 'select', + 'options' => array( + 'endpoint' => '/api/v1/users.listByStatus', + 'finger' => array( + 'value' => 'users[].username', + 'label' => 'users[].name', + ), + ), + 'required' => true, + ), + array( + 'ref' => '#form', + 'name' => 'title', + 'default' => __( 'Direct Messages', 'forms-bridge' ), + ), + ), + 'form' => array( + 'title' => __( 'Direct Messages', 'forms-bridge' ), + 'fields' => array( + array( + 'name' => 'your-name', + 'label' => __( 'Your name', 'forms-bridge' ), + 'type' => 'text', + 'required' => true, + ), + array( + 'name' => 'your-email', + 'label' => __( 'Your email', 'forms-bridge' ), + 'type' => 'email', + 'required' => true, + ), + array( + 'name' => 'comments', + 'label' => __( 'Comments', 'forms-bridge' ), + 'type' => 'textarea', + ), + ), + ), + 'bridge' => array( + 'endpoint' => '/api/v1/chat.postMessage', + 'workflow' => array( 'create-dm' ), + 'mutations' => array( + array( + array( + 'from' => 'your-name', + 'to' => 'text.name', + 'cast' => 'string', + ), + array( + 'from' => 'your-email', + 'to' => 'text.email', + 'cast' => 'string', + ), + array( + 'from' => '?comments', + 'to' => 'text.comments', + 'cast' => 'string', + ), + array( + 'from' => 'text', + 'to' => 'text', + 'cast' => 'pretty_json', + ), + ), + ), + ), +); diff --git a/forms-bridge/addons/rocketchat/templates/support.php b/forms-bridge/addons/rocketchat/templates/support.php new file mode 100644 index 00000000..6a824706 --- /dev/null +++ b/forms-bridge/addons/rocketchat/templates/support.php @@ -0,0 +1,118 @@ + __( 'Support Channel', 'forms-bridge' ), + 'description' => __( + 'Support form template. The resulting bridge will notify form submissions in a Rocket.Chat channel', + 'forms-bridge' + ), + 'fields' => array( + array( + 'ref' => '#bridge', + 'name' => 'endpoint', + 'value' => '/api/v1/chat.postMessage', + ), + array( + 'ref' => '#bridge/custom_fields[]', + 'name' => 'roomId', + 'label' => __( 'Channel', 'forms-bridge' ), + 'description' => __( + 'Name of the channel where messages will be sent', + 'forms-bridge' + ), + 'type' => 'select', + 'options' => array( + 'endpoint' => '/api/v1/rooms.get', + 'finger' => array( + 'value' => 'update[]._id', + 'label' => 'update[].name', + ), + ), + 'required' => true, + ), + array( + 'ref' => '#form', + 'name' => 'title', + 'default' => __( 'Support', 'forms-bridge' ), + ), + ), + 'form' => array( + 'title' => __( 'Support', 'forms-bridge' ), + 'fields' => array( + array( + 'name' => 'your-name', + 'label' => __( 'Your name', 'forms-bridge' ), + 'type' => 'text', + 'required' => true, + ), + array( + 'name' => 'your-email', + 'label' => __( 'Your email', 'forms-bridge' ), + 'type' => 'email', + 'required' => true, + ), + array( + 'name' => 'subject', + 'label' => __( 'Subject', 'forms-bridge' ), + 'type' => 'select', + 'options' => array( + array( + 'value' => 'Option 1', + 'label' => 'Option 1', + ), + array( + 'value' => 'Option 2', + 'label' => 'Option 2', + ), + ), + 'required' => true, + ), + array( + 'name' => 'comments', + 'label' => __( 'Comments', 'forms-bridge' ), + 'type' => 'textarea', + ), + ), + ), + 'bridge' => array( + 'endpoint' => '/api/v1/chat.postMessage', + 'mutations' => array( + array( + array( + 'from' => 'your-name', + 'to' => 'text.name', + 'cast' => 'string', + ), + array( + 'from' => 'your-email', + 'to' => 'text.email', + 'cast' => 'string', + ), + array( + 'from' => 'subject', + 'to' => 'text.subject', + 'cast' => 'string', + ), + array( + 'from' => '?comments', + 'to' => 'text.comments', + 'cast' => 'string', + ), + array( + 'from' => 'text', + 'to' => 'text', + 'cast' => 'pretty_json', + ), + ), + ), + ), +); diff --git a/forms-bridge/deps/http b/forms-bridge/deps/http index 803b7a4d..7218bf42 160000 --- a/forms-bridge/deps/http +++ b/forms-bridge/deps/http @@ -1 +1 @@ -Subproject commit 803b7a4de09d1a382792a5c1b857a4a3974186bb +Subproject commit 7218bf42d6b821abb7ea04dccdef686e7d6ee98d From dd42503754f03e114aba1fd70f70167e54b6cad4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20Garc=C3=ADa?= Date: Thu, 20 Nov 2025 03:16:33 +0100 Subject: [PATCH 2/6] feat: rename channel to roomId on rocket contact template --- forms-bridge/addons/rocketchat/templates/contact.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/forms-bridge/addons/rocketchat/templates/contact.php b/forms-bridge/addons/rocketchat/templates/contact.php index 88a8dffc..23d70397 100644 --- a/forms-bridge/addons/rocketchat/templates/contact.php +++ b/forms-bridge/addons/rocketchat/templates/contact.php @@ -23,7 +23,7 @@ ), array( 'ref' => '#bridge/custom_fields[]', - 'name' => 'channel', + 'name' => 'roomId', 'label' => __( 'Channel', 'forms-bridge' ), 'description' => __( 'Name of the channel where messages will be sent', From 8bb963a77ab76a6b43368d692c974408385ae2de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20Garc=C3=ADa?= Date: Thu, 20 Nov 2025 03:45:12 +0100 Subject: [PATCH 3/6] feat: use filename as messages attachments titles --- .../addons/slack/class-slack-form-bridge.php | 23 +++++++++---------- .../addons/slack/templates/support.php | 21 +++++++++++++++++ .../addons/zulip/class-zulip-form-bridge.php | 5 +++- 3 files changed, 36 insertions(+), 13 deletions(-) diff --git a/forms-bridge/addons/slack/class-slack-form-bridge.php b/forms-bridge/addons/slack/class-slack-form-bridge.php index dc9fb18d..725d2cb7 100644 --- a/forms-bridge/addons/slack/class-slack-form-bridge.php +++ b/forms-bridge/addons/slack/class-slack-form-bridge.php @@ -85,19 +85,14 @@ public function submit( $payload = array(), $attachments = array() ) { foreach ( $attachments as $name => $file_id ) { $files[] = array( 'id' => $file_id, - 'title' => $name, + 'title' => $filename, ); } $response = $backend->post( '/api/files.completeUploadExternal', - array( - 'files' => wp_json_encode( $files ), - 'channel_id' => $payload['channel'] ?? $payload['channel_id'] ?? null, - ), - array( - 'Content-Type' => 'application/x-www-form-urlencoded', - ), + array( 'files' => wp_json_encode( $files ) ), + array( 'Content-Type' => 'application/x-www-form-urlencoded' ), ); if ( is_wp_error( $response ) ) { @@ -110,13 +105,17 @@ public function submit( $payload = array(), $attachments = array() ) { $annex = "\n\n----\n" . esc_html( __( 'Attachments', 'forms-bridge' ) ) . ":\n"; - foreach ( $response['data']['files'] as $upload ) { - $annex .= "* [{$upload['name']}]({$upload['permalink']})\n"; - } - if ( isset( $payload['markdown_text'] ) ) { + foreach ( $response['data']['files'] as $upload ) { + $annex .= "* [{$upload['name']}]({$upload['permalink']})\n"; + } + $payload['markdown_text'] .= $annex; } else { + foreach ( $response['data']['files'] as $upload ) { + $annex .= "* {$upload['name']}: {$upload['permalink']}\n"; + } + $payload['text'] .= $annex; } } diff --git a/forms-bridge/addons/slack/templates/support.php b/forms-bridge/addons/slack/templates/support.php index e4470b16..551678a6 100644 --- a/forms-bridge/addons/slack/templates/support.php +++ b/forms-bridge/addons/slack/templates/support.php @@ -42,6 +42,22 @@ 'type' => 'email', 'required' => true, ), + array( + 'name' => 'subject', + 'label' => __( 'Subject', 'forms-bridge' ), + 'type' => 'select', + 'options' => array( + array( + 'value' => 'Option 1', + 'label' => 'Option 1', + ), + array( + 'value' => 'Option 2', + 'label' => 'Option 2', + ), + ), + 'required' => true, + ), array( 'name' => 'comments', 'label' => __( 'Comments', 'forms-bridge' ), @@ -63,6 +79,11 @@ 'to' => 'text.email', 'cast' => 'string', ), + array( + 'from' => 'subject', + 'to' => 'text.subject', + 'cast' => 'string', + ), array( 'from' => '?comments', 'to' => 'text.comments', diff --git a/forms-bridge/addons/zulip/class-zulip-form-bridge.php b/forms-bridge/addons/zulip/class-zulip-form-bridge.php index c437ec51..7f27172b 100644 --- a/forms-bridge/addons/zulip/class-zulip-form-bridge.php +++ b/forms-bridge/addons/zulip/class-zulip-form-bridge.php @@ -46,6 +46,9 @@ public function submit( $payload = array(), $attachments = array() ) { $attachments = Forms_Bridge::attachments( $uploads ); foreach ( $attachments as $name => $path ) { + $info = pathinfo( $path ); + $filename = $info['basename']; + $response = $backend->post( '/api/v1/user_uploads', array(), array(), array( $name => $path ) ); if ( is_wp_error( $response ) ) { @@ -57,7 +60,7 @@ public function submit( $payload = array(), $attachments = array() ) { unset( $payload[ $name ] ); unset( $payload[ $name . '_filename' ] ); - $annex .= "* [{$name}]({$response['data']['url']})\n"; + $annex .= "* [{$filename}]({$response['data']['url']})\n"; } $payload['content'] .= $annex; From 47c30b8e25cdceb36b525bf9fbbd18a1f844183e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20Garc=C3=ADa?= Date: Thu, 20 Nov 2025 04:05:16 +0100 Subject: [PATCH 4/6] feat: slack template credentail descriptions --- forms-bridge/addons/slack/hooks.php | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/forms-bridge/addons/slack/hooks.php b/forms-bridge/addons/slack/hooks.php index 38d9c854..589e168c 100644 --- a/forms-bridge/addons/slack/hooks.php +++ b/forms-bridge/addons/slack/hooks.php @@ -40,18 +40,20 @@ function ( $defaults, $addon, $schema ) { 'value' => 'https://slack.com/oauth/v2', ), array( - 'ref' => '#credential', - 'name' => 'client_id', - 'label' => __( 'Client ID', 'forms-bridge' ), - 'type' => 'text', - 'required' => true, + 'ref' => '#credential', + 'name' => 'client_id', + 'label' => __( 'Client ID', 'forms-bridge' ), + 'description' => __( 'Register Forms Bridge as an app on Slack API and get its Client ID', 'forms-bridge' ), + 'type' => 'text', + 'required' => true, ), array( - 'ref' => '#credential', - 'name' => 'client_secret', - 'label' => __( 'Client secret', 'forms-bridge' ), - 'type' => 'text', - 'required' => true, + 'ref' => '#credential', + 'name' => 'client_secret', + 'label' => __( 'Client Secret', 'forms-bridge' ), + 'description' => __( 'Register Forms Bridge as an app on Slack API and get its Client Secret', 'forms-bridge' ), + 'type' => 'text', + 'required' => true, ), array( 'ref' => '#credential', From cf9cd941e6a45d3884f3169c598d887570aaf90c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20Garc=C3=ADa?= Date: Thu, 20 Nov 2025 04:05:37 +0100 Subject: [PATCH 5/6] fix: zulip oa introspection --- forms-bridge/addons/zulip/class-zulip-addon.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/forms-bridge/addons/zulip/class-zulip-addon.php b/forms-bridge/addons/zulip/class-zulip-addon.php index b32f9098..39ac3ad5 100644 --- a/forms-bridge/addons/zulip/class-zulip-addon.php +++ b/forms-bridge/addons/zulip/class-zulip-addon.php @@ -100,7 +100,7 @@ public function get_endpoint_schema( $endpoint, $backend, $method = null ) { $oa_explorer = new OpenAPI( $data ); $method = strtolower( $method ?? 'post' ); - $path = preg_replace( '', '', $endpoint ); + $path = preg_replace( '/^\/api\/v1/', '', $endpoint ); $source = in_array( $method, array( 'post', 'put', 'patch' ), true ) ? 'body' : 'query'; $params = $oa_explorer->params( $path, $method, $source ); From 3457a80a55345d362e041b7a1464d57adc952eb8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20Garc=C3=ADa?= Date: Thu, 20 Nov 2025 04:05:58 +0100 Subject: [PATCH 6/6] fix: openapi refs merges --- forms-bridge/includes/class-openapi.php | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/forms-bridge/includes/class-openapi.php b/forms-bridge/includes/class-openapi.php index 420d49c2..ea25a457 100644 --- a/forms-bridge/includes/class-openapi.php +++ b/forms-bridge/includes/class-openapi.php @@ -180,7 +180,7 @@ public function params( $path, $method = null, $source = null ) { $param = &$parameters[ $i ]; if ( 'body' === $param['in'] && isset( $param['schema'] ) ) { if ( isset( $param['schema']['$ref'] ) ) { - $param['schema'] = $this->get_ref( $param['schema']['$ref'] ); + $param['schema'] = array_merge( $param['schema'], $this->get_ref( $param['schema']['$ref'] ) ); } if ( isset( $param['schema']['properties'] ) && is_array( $param['schema']['properties'] ) ) { @@ -225,16 +225,22 @@ function ( $param ) use ( $source ) { for ( $i = 0; $i < $l; $i++ ) { $param = &$parameters[ $i ]; + if ( isset( $param['$ref'] ) ) { + $parameters[ $i ] = array_merge( $param, $this->get_ref( $param['$ref'] ) ); + } elseif ( isset( $param['schema']['$ref'] ) ) { + $param['schema'] = array_merge( $param['schema'], $this->get_ref( $param['schema']['$ref'] ) ); + } + + if ( isset( $param['anyOf'] ) ) { + $param['schema'] = $param['anyOf'][0]; + } elseif ( isset( $param['oneOf'] ) ) { + $param['schema'] = $param['oneOf'][0]; + } + if ( isset( $param['type'] ) && ! isset( $param['schema'] ) ) { $param['schema'] = array( 'type' => $param['type'] ); unset( $param['type'] ); } - - if ( isset( $param['$ref'] ) ) { - $parameters[ $i ] = $this->get_ref( $param['$ref'] ); - } elseif ( isset( $param['schema']['$ref'] ) ) { - $param['schema'] = $this->get_ref( $param['schema']['$ref'] ); - } } return $parameters; @@ -274,7 +280,7 @@ private function body_to_params( $body ) { foreach ( $body['content'] as $encoding => $obj ) { if ( isset( $obj['schema']['$ref'] ) ) { - $obj['schema'] = $this->get_ref( $obj['schema']['$ref'] ); + $obj['schema'] = array_merge( $obj['schema'], $this->get_ref( $obj['schema']['$ref'] ) ); } foreach ( $obj['schema']['properties'] as $name => $defn ) {