699 lines
24 KiB
JavaScript
699 lines
24 KiB
JavaScript
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
|
// See LICENSE.txt for license information.
|
|
|
|
/* eslint-disable camelcase, no-console */
|
|
|
|
const axios = require('axios');
|
|
const ClientOAuth2 = require('client-oauth2');
|
|
const express = require('express');
|
|
|
|
const postMessageAs = require('./utils/post_message_as');
|
|
const webhookUtils = require('./utils/webhook_utils');
|
|
const port = 3000;
|
|
|
|
const {
|
|
SITE_URL,
|
|
WEBHOOK_BASE_URL,
|
|
ADMIN_USERNAME,
|
|
ADMIN_PASSWORD,
|
|
} = process.env; // eslint-disable-line no-process-env
|
|
|
|
const server = express();
|
|
server.use(express.json());
|
|
server.use(express.urlencoded({extended: true}));
|
|
|
|
// Log all incoming requests (minimal for test performance)
|
|
server.use((req, res, next) => {
|
|
console.log(`[${req.method}] ${req.url}`);
|
|
next();
|
|
});
|
|
|
|
// Add error handling for failed requests
|
|
server.use((err, req, res, next) => {
|
|
console.error('=== SERVER ERROR ===');
|
|
console.error('Error:', err);
|
|
console.error('Request URL:', req.url);
|
|
console.error('Request Method:', req.method);
|
|
console.error('=== END SERVER ERROR ===');
|
|
next(err);
|
|
});
|
|
|
|
process.title = process.argv[2];
|
|
|
|
server.get('/', ping);
|
|
server.post('/message_menus', postMessageMenus);
|
|
server.post('/dialog_request', onDialogRequest);
|
|
server.post('/simple_dialog_request', onSimpleDialogRequest);
|
|
server.post('/user_and_channel_dialog_request', onUserAndChannelDialogRequest);
|
|
server.post('/dialog_submit', onDialogSubmit);
|
|
server.post('/boolean_dialog_request', onBooleanDialogRequest);
|
|
server.post('/simple_dialog_error_request', onSimpleDialogErrorRequest);
|
|
server.post('/select_fields_dialog_request', onSelectFieldsDialogRequest);
|
|
server.post('/multiselect_dynamic_dialog_request', onMultiselectDynamicDialogRequest);
|
|
server.post('/dynamic_options', getDynamicOptions);
|
|
server.post('/dynamic_multiselect_options', getDynamicMultiselectOptions);
|
|
server.post('/multiform_dialog_request', onMultiformDialogRequest);
|
|
server.post('/multiform_dialog_submit', onMultiformDialogSubmit);
|
|
server.post('/field_refresh_dialog_request', onFieldRefreshDialogRequest);
|
|
server.post('/field_refresh_dialog_submit', onFieldRefreshDialogSubmit);
|
|
server.post('/slack_compatible_message_response', postSlackCompatibleMessageResponse);
|
|
server.post('/send_message_to_channel', postSendMessageToChannel);
|
|
server.post('/post_outgoing_webhook', postOutgoingWebhook);
|
|
server.post('/send_oauth_credentials', postSendOauthCredentials);
|
|
server.get('/start_oauth', getStartOAuth);
|
|
server.get('/complete_oauth', getCompleteOauth);
|
|
server.post('/postOAuthMessage', postOAuthMessage);
|
|
|
|
function ping(req, res) {
|
|
const baseUrl = SITE_URL || 'http://localhost:8065';
|
|
const webhookBaseUrl = WEBHOOK_BASE_URL || 'http://localhost:3000';
|
|
|
|
return res.json({
|
|
message: 'I\'m alive!',
|
|
baseUrl,
|
|
webhookBaseUrl,
|
|
});
|
|
}
|
|
|
|
server.listen(port, () => console.log(`Webhook test server listening on port ${port}!`));
|
|
|
|
let appID;
|
|
let appSecret;
|
|
let client;
|
|
let authedUser;
|
|
function postSendOauthCredentials(req, res) {
|
|
appID = req.body.appID.trim();
|
|
appSecret = req.body.appSecret.trim();
|
|
client = new ClientOAuth2({
|
|
clientId: appID,
|
|
clientSecret: appSecret,
|
|
authorizationUri: getBaseUrl() + '/oauth/authorize',
|
|
accessTokenUri: getBaseUrl() + '/oauth/access_token',
|
|
redirectUri: getWebhookBaseUrl() + '/complete_oauth',
|
|
});
|
|
return res.status(200).send('OK');
|
|
}
|
|
|
|
function getStartOAuth(req, res) {
|
|
return res.redirect(client.code.getUri());
|
|
}
|
|
|
|
function getCompleteOauth(req, res) {
|
|
client.code.getToken(req.originalUrl).then((user) => {
|
|
authedUser = user;
|
|
return res.status(200).send('OK');
|
|
}).catch((reason) => {
|
|
return res.status(reason.status).send(reason);
|
|
});
|
|
}
|
|
|
|
async function postOAuthMessage(req, res) {
|
|
const {channelId, message, rootId, createAt} = req.body;
|
|
const apiUrl = getBaseUrl() + '/api/v4/posts';
|
|
authedUser.sign({
|
|
method: 'post',
|
|
url: apiUrl,
|
|
});
|
|
try {
|
|
await axios({
|
|
url: apiUrl,
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
'X-Requested-With': 'XMLHttpRequest',
|
|
Authorization: 'Bearer ' + authedUser.accessToken,
|
|
},
|
|
method: 'post',
|
|
data: {
|
|
channel_id: channelId,
|
|
message,
|
|
type: '',
|
|
create_at: createAt,
|
|
root_id: rootId,
|
|
},
|
|
});
|
|
} catch (err) {
|
|
// Do nothing
|
|
}
|
|
return res.status(200).send('OK');
|
|
}
|
|
|
|
function postSlackCompatibleMessageResponse(req, res) {
|
|
const {spoiler, skipSlackParsing} = req.body.context;
|
|
|
|
res.setHeader('Content-Type', 'application/json');
|
|
return res.json({
|
|
ephemeral_text: spoiler,
|
|
skip_slack_parsing: skipSlackParsing,
|
|
});
|
|
}
|
|
|
|
function postMessageMenus(req, res) {
|
|
let responseData = {};
|
|
const {body} = req;
|
|
if (body && body.context.action === 'do_something') {
|
|
responseData = {
|
|
ephemeral_text: `Ephemeral | ${body.type} ${body.data_source} option: ${body.context.selected_option}`,
|
|
};
|
|
}
|
|
|
|
res.setHeader('Content-Type', 'application/json');
|
|
return res.json(responseData);
|
|
}
|
|
|
|
async function openDialog(dialog) {
|
|
const baseUrl = getBaseUrl();
|
|
await axios({
|
|
method: 'post',
|
|
url: `${baseUrl}/api/v4/actions/dialogs/open`,
|
|
data: dialog,
|
|
});
|
|
}
|
|
|
|
function onDialogRequest(req, res) {
|
|
const {body} = req;
|
|
if (body.trigger_id) {
|
|
const webhookBaseUrl = getWebhookBaseUrl();
|
|
const dialog = webhookUtils.getFullDialog(body.trigger_id, webhookBaseUrl);
|
|
openDialog(dialog);
|
|
}
|
|
|
|
res.setHeader('Content-Type', 'application/json');
|
|
return res.json({text: 'Full dialog triggered via slash command!'});
|
|
}
|
|
|
|
function onSimpleDialogRequest(req, res) {
|
|
const {body} = req;
|
|
if (body.trigger_id) {
|
|
const webhookBaseUrl = getWebhookBaseUrl();
|
|
const dialog = webhookUtils.getSimpleDialog(body.trigger_id, webhookBaseUrl);
|
|
openDialog(dialog);
|
|
}
|
|
|
|
res.setHeader('Content-Type', 'application/json');
|
|
return res.json({text: 'Simple dialog triggered via slash command!'});
|
|
}
|
|
|
|
function onUserAndChannelDialogRequest(req, res) {
|
|
const {body} = req;
|
|
if (body.trigger_id) {
|
|
const webhookBaseUrl = getWebhookBaseUrl();
|
|
const dialog = webhookUtils.getUserAndChannelDialog(body.trigger_id, webhookBaseUrl);
|
|
openDialog(dialog);
|
|
}
|
|
|
|
res.setHeader('Content-Type', 'application/json');
|
|
return res.json({text: 'Simple dialog triggered via slash command!'});
|
|
}
|
|
|
|
function onBooleanDialogRequest(req, res) {
|
|
const {body} = req;
|
|
if (body.trigger_id) {
|
|
const webhookBaseUrl = getWebhookBaseUrl();
|
|
const dialog = webhookUtils.getBooleanDialog(body.trigger_id, webhookBaseUrl);
|
|
openDialog(dialog);
|
|
}
|
|
|
|
res.setHeader('Content-Type', 'application/json');
|
|
return res.json({text: 'Simple dialog triggered via slash command!'});
|
|
}
|
|
|
|
function onSimpleDialogErrorRequest(req, res) {
|
|
const {body} = req;
|
|
if (body.trigger_id) {
|
|
const webhookBaseUrl = getWebhookBaseUrl();
|
|
|
|
// Create a simple dialog that will submit to the error endpoint
|
|
const dialog = {
|
|
trigger_id: body.trigger_id,
|
|
url: `${webhookBaseUrl}/dialog_submit_error`,
|
|
dialog: {
|
|
callback_id: 'simpleerrorcallbackid',
|
|
title: 'Simple Dialog Error Test',
|
|
icon_url: 'http://www.mattermost.org/wp-content/uploads/2016/04/icon.png',
|
|
submit_label: 'Submit Test',
|
|
notify_on_cancel: true,
|
|
state: 'somestate',
|
|
elements: [
|
|
{
|
|
display_name: 'Optional Text Field',
|
|
name: 'optional_text',
|
|
type: 'text',
|
|
default: '',
|
|
placeholder: 'Enter some text (will trigger error)...',
|
|
help_text: 'This field will trigger a server error for testing',
|
|
optional: true,
|
|
min_length: 0,
|
|
max_length: 100,
|
|
},
|
|
],
|
|
},
|
|
};
|
|
openDialog(dialog);
|
|
}
|
|
|
|
res.setHeader('Content-Type', 'application/json');
|
|
return res.json({text: 'Error dialog triggered via slash command!'});
|
|
}
|
|
|
|
function onSelectFieldsDialogRequest(req, res) {
|
|
const {body} = req;
|
|
if (body.trigger_id) {
|
|
const webhookBaseUrl = getWebhookBaseUrl();
|
|
|
|
// Create a focused dialog with select field types for testing
|
|
const dialog = {
|
|
trigger_id: body.trigger_id,
|
|
url: `${webhookBaseUrl}/dialog_submit`,
|
|
dialog: {
|
|
callback_id: 'selectfieldscallbackid',
|
|
title: 'Select Fields Dialog Test',
|
|
icon_url: 'http://www.mattermost.org/wp-content/uploads/2016/04/icon.png',
|
|
submit_label: 'Submit Test',
|
|
notify_on_cancel: true,
|
|
state: 'somestate',
|
|
elements: [
|
|
{
|
|
display_name: 'Radio Option Selector',
|
|
name: 'someradiooptions',
|
|
type: 'radio',
|
|
help_text: 'Choose your department',
|
|
optional: false,
|
|
options: [
|
|
{
|
|
text: 'Engineering',
|
|
value: 'engineering',
|
|
},
|
|
{
|
|
text: 'Sales',
|
|
value: 'sales',
|
|
},
|
|
{
|
|
text: 'Marketing',
|
|
value: 'marketing',
|
|
},
|
|
],
|
|
},
|
|
{
|
|
display_name: 'Option Selector',
|
|
name: 'someoptionselector',
|
|
type: 'select',
|
|
subtype: '',
|
|
default: '',
|
|
placeholder: 'Select an option...',
|
|
help_text: 'Choose from static options',
|
|
optional: false,
|
|
min_length: 0,
|
|
max_length: 0,
|
|
data_source: '',
|
|
options: [
|
|
{
|
|
text: 'Option1',
|
|
value: 'opt1',
|
|
},
|
|
{
|
|
text: 'Option2',
|
|
value: 'opt2',
|
|
},
|
|
{
|
|
text: 'Option3',
|
|
value: 'opt3',
|
|
},
|
|
],
|
|
},
|
|
{
|
|
display_name: 'User Selector',
|
|
name: 'someuserselector',
|
|
type: 'select',
|
|
subtype: '',
|
|
default: '',
|
|
placeholder: 'Select a user...',
|
|
help_text: 'Choose a user from the team',
|
|
optional: false,
|
|
min_length: 0,
|
|
max_length: 0,
|
|
data_source: 'users',
|
|
options: null,
|
|
},
|
|
{
|
|
display_name: 'Channel Selector',
|
|
name: 'somechannelselector',
|
|
type: 'select',
|
|
subtype: '',
|
|
default: '',
|
|
placeholder: 'Select a channel...',
|
|
help_text: 'Choose a channel from the list',
|
|
optional: true,
|
|
min_length: 0,
|
|
max_length: 0,
|
|
data_source: 'channels',
|
|
options: null,
|
|
},
|
|
],
|
|
},
|
|
};
|
|
openDialog(dialog);
|
|
}
|
|
|
|
res.setHeader('Content-Type', 'application/json');
|
|
return res.json({text: 'Select fields dialog triggered via slash command!'});
|
|
}
|
|
|
|
function onDialogSubmit(req, res) {
|
|
const {body} = req;
|
|
|
|
res.setHeader('Content-Type', 'application/json');
|
|
|
|
let message;
|
|
if (body.cancelled) {
|
|
message = 'Dialog cancelled';
|
|
sendSysadminResponse(message, body.channel_id);
|
|
} else {
|
|
const submission = body.submission || {};
|
|
|
|
// Debug logging for dialog submissions (can be removed in production)
|
|
console.log('[POST] /dialog_submit - callback_id:', body.callback_id);
|
|
|
|
// For boolean dialog, post detailed submission values to channel
|
|
if (body.callback_id === 'booleancallbackid') {
|
|
const booleanValues = {
|
|
required_boolean: submission.required_boolean,
|
|
optional_boolean: submission.optional_boolean,
|
|
boolean_default_true: submission.boolean_default_true,
|
|
boolean_default_false: submission.boolean_default_false,
|
|
};
|
|
|
|
console.log('Boolean dialog submitted');
|
|
|
|
// Post structured submission results to channel for e2e verification
|
|
message = `Boolean Dialog Submitted:
|
|
- required_boolean: ${booleanValues.required_boolean}
|
|
- optional_boolean: ${booleanValues.optional_boolean}
|
|
- boolean_default_true: ${booleanValues.boolean_default_true}
|
|
- boolean_default_false: ${booleanValues.boolean_default_false}`;
|
|
} else if (body.callback_id === 'textfieldscallbackid') {
|
|
const textValues = {
|
|
text_field: submission.text_field,
|
|
required_text: submission.required_text,
|
|
email_field: submission.email_field,
|
|
number_field: submission.number_field,
|
|
password_field: submission.password_field,
|
|
textarea_field: submission.textarea_field,
|
|
};
|
|
|
|
console.log('Text fields dialog submitted');
|
|
|
|
// Post structured submission results to channel for e2e verification
|
|
message = `Text Fields Dialog Submitted:
|
|
- text_field: ${textValues.text_field}
|
|
- required_text: ${textValues.required_text}
|
|
- email_field: ${textValues.email_field}
|
|
- number_field: ${textValues.number_field}
|
|
- password_field: ${textValues.password_field}
|
|
- textarea_field: ${textValues.textarea_field}`;
|
|
} else if (body.callback_id === 'selectfieldscallbackid') {
|
|
const selectValues = {
|
|
someradiooptions: submission.someradiooptions,
|
|
someoptionselector: submission.someoptionselector,
|
|
someuserselector: submission.someuserselector,
|
|
somechannelselector: submission.somechannelselector,
|
|
};
|
|
|
|
console.log('Select fields dialog submitted');
|
|
|
|
// Post structured submission results to channel for e2e verification
|
|
message = `Select Fields Dialog Submitted:
|
|
- someradiooptions: ${selectValues.someradiooptions}
|
|
- someoptionselector: ${selectValues.someoptionselector}
|
|
- someuserselector: ${selectValues.someuserselector}
|
|
- somechannelselector: ${selectValues.somechannelselector}`;
|
|
} else {
|
|
message = `Dialog submitted with values: ${JSON.stringify(submission)}`;
|
|
}
|
|
|
|
sendSysadminResponse(message, body.channel_id);
|
|
}
|
|
|
|
return res.json({text: message});
|
|
}
|
|
|
|
/**
|
|
* @route "POST /send_message_to_channel?type={messageType}&channel_id={channelId}"
|
|
* @query type - message type of empty string for regular message if not provided (default), "system_message", etc
|
|
* @query channel_id - channel where to send the message
|
|
*/
|
|
function postSendMessageToChannel(req, res) {
|
|
const channelId = req.query.channel_id;
|
|
const response = {
|
|
response_type: 'in_channel',
|
|
text: 'Extra response 2',
|
|
channel_id: channelId,
|
|
extra_responses: [{
|
|
response_type: 'in_channel',
|
|
text: 'Hello World',
|
|
channel_id: channelId,
|
|
}],
|
|
};
|
|
|
|
if (req.query.type) {
|
|
response.type = req.query.type;
|
|
}
|
|
|
|
res.json(response);
|
|
}
|
|
|
|
function getWebhookBaseUrl() {
|
|
return WEBHOOK_BASE_URL || 'http://localhost:3000';
|
|
}
|
|
|
|
function getBaseUrl() {
|
|
return SITE_URL || 'http://localhost:8065';
|
|
}
|
|
|
|
// Convenient way to send response in a channel by using sysadmin account
|
|
function sendSysadminResponse(message, channelId) {
|
|
const username = ADMIN_USERNAME || 'sysadmin';
|
|
const password = ADMIN_PASSWORD || 'Sys@dmin-sample1';
|
|
const baseUrl = getBaseUrl();
|
|
postMessageAs(baseUrl, {sender: {username, password}, message, channelId});
|
|
}
|
|
|
|
const responseTypes = ['in_channel', 'comment'];
|
|
|
|
function getWebhookResponse(body, {responseType, username, iconUrl}) {
|
|
const payload = Object.entries(body).map(([key, value]) => `- ${key}: "${value}"`).join('\n');
|
|
|
|
return `
|
|
\`\`\`
|
|
#### Outgoing Webhook Payload
|
|
${payload}
|
|
#### Webhook override to Mattermost instance
|
|
- response_type: "${responseType}"
|
|
- type: ""
|
|
- username: "${username}"
|
|
- icon_url: "${iconUrl}"
|
|
\`\`\`
|
|
`;
|
|
}
|
|
|
|
/**
|
|
* @route "POST /post_outgoing_webhook?override_username={username}&override_icon_url={iconUrl}&response_type={comment}"
|
|
* @query override_username - the user name that overrides the user name defined by the outgoing webhook
|
|
* @query override_icon_url - the user icon url that overrides the user icon url defined by the outgoing webhook
|
|
* @query response_type - "in_channel" (default) or "comment"
|
|
*/
|
|
function postOutgoingWebhook(req, res) {
|
|
const {body, query} = req;
|
|
if (!body) {
|
|
res.status(404).send({error: 'Invalid data'});
|
|
}
|
|
|
|
const responseType = query.response_type || responseTypes[0];
|
|
const username = query.override_username || '';
|
|
const iconUrl = query.override_icon_url || '';
|
|
|
|
const response = {
|
|
text: getWebhookResponse(body, {responseType, username, iconUrl}),
|
|
username,
|
|
icon_url: iconUrl,
|
|
type: '',
|
|
response_type: responseType,
|
|
};
|
|
res.status(200).send(response);
|
|
}
|
|
|
|
function onMultiselectDynamicDialogRequest(req, res) {
|
|
const {body} = req;
|
|
|
|
if (body.trigger_id) {
|
|
const webhookBaseUrl = getWebhookBaseUrl();
|
|
const dialog = webhookUtils.getMultiselectDynamicDialog(body.trigger_id, webhookBaseUrl);
|
|
openDialog(dialog);
|
|
}
|
|
|
|
res.setHeader('Content-Type', 'application/json');
|
|
return res.json({text: 'Multiselect dynamic dialog triggered via slash command!'});
|
|
}
|
|
|
|
function getDynamicOptions(req, res) {
|
|
const {body} = req;
|
|
const searchTerm = body.user_input || '';
|
|
|
|
// Respond immediately for test performance
|
|
const response = webhookUtils.getDynamicOptionsResponse(searchTerm);
|
|
res.status(200).json(response);
|
|
}
|
|
|
|
function getDynamicMultiselectOptions(req, res) {
|
|
const {body} = req;
|
|
const searchTerm = body.user_input || '';
|
|
|
|
// Respond immediately for test performance
|
|
const response = webhookUtils.getDynamicMultiselectOptionsResponse(searchTerm);
|
|
res.status(200).json(response);
|
|
}
|
|
|
|
// Multiform dialog endpoints
|
|
function onMultiformDialogRequest(req, res) {
|
|
const {body} = req;
|
|
|
|
if (body.trigger_id) {
|
|
const webhookBaseUrl = getWebhookBaseUrl();
|
|
const dialog = webhookUtils.getMultiformDialog(body.trigger_id, webhookBaseUrl, 1);
|
|
openDialog(dialog);
|
|
}
|
|
|
|
res.setHeader('Content-Type', 'application/json');
|
|
return res.json({text: 'Multiform dialog triggered via slash command!'});
|
|
}
|
|
|
|
function onMultiformDialogSubmit(req, res) {
|
|
const {body} = req;
|
|
|
|
const callbackId = body.callback_id;
|
|
let response;
|
|
|
|
if (callbackId === 'multiform_step_1') {
|
|
// Return step 2 dialog
|
|
const webhookBaseUrl = getWebhookBaseUrl();
|
|
const step2Dialog = webhookUtils.getMultiformDialog(body.trigger_id, webhookBaseUrl, 2);
|
|
|
|
response = {
|
|
type: 'form',
|
|
form: step2Dialog.dialog,
|
|
};
|
|
} else if (callbackId === 'multiform_step_2') {
|
|
// Return step 3 dialog
|
|
const webhookBaseUrl = getWebhookBaseUrl();
|
|
const step3Dialog = webhookUtils.getMultiformDialog(body.trigger_id, webhookBaseUrl, 3);
|
|
|
|
response = {
|
|
type: 'form',
|
|
form: step3Dialog.dialog,
|
|
};
|
|
} else if (callbackId === 'multiform_step_3') {
|
|
// Final submission - send success message to channel
|
|
const submissionText = Object.entries(body.submission).
|
|
map(([key, value]) => `${key}: ${value}`).
|
|
join('\n');
|
|
|
|
const message = `Multiform submission completed!\n\`\`\`\n${submissionText}\n\`\`\``;
|
|
sendSysadminResponse(message, body.channel_id);
|
|
|
|
response = {};
|
|
} else if (body.cancelled) {
|
|
// Handle cancellation
|
|
let stepNumber;
|
|
if (callbackId === 'multiform_step_1') {
|
|
stepNumber = 1;
|
|
} else if (callbackId === 'multiform_step_2') {
|
|
stepNumber = 2;
|
|
} else {
|
|
stepNumber = 3;
|
|
}
|
|
const message = `Multiform dialog was cancelled at step ${stepNumber}`;
|
|
sendSysadminResponse(message, body.channel_id);
|
|
response = {};
|
|
}
|
|
|
|
res.status(200).json(response);
|
|
}
|
|
|
|
// Field refresh dialog endpoints
|
|
function onFieldRefreshDialogRequest(req, res) {
|
|
const {body} = req;
|
|
|
|
if (body.trigger_id) {
|
|
const webhookBaseUrl = getWebhookBaseUrl();
|
|
|
|
// Start with basic field refresh dialog (no project type selected)
|
|
const dialog = webhookUtils.getFieldRefreshDialog(body.trigger_id, webhookBaseUrl);
|
|
openDialog(dialog);
|
|
}
|
|
|
|
res.setHeader('Content-Type', 'application/json');
|
|
return res.json({text: 'Field refresh dialog triggered via slash command!'});
|
|
}
|
|
|
|
function onFieldRefreshDialogSubmit(req, res) {
|
|
const {body} = req;
|
|
|
|
let response;
|
|
|
|
// Check if this is a refresh request (indicated by 'type': 'refresh' or selected_field)
|
|
if (body.type === 'refresh' || body.submission.selected_field) {
|
|
|
|
// Get the current project type from submission
|
|
const projectType = body.submission.project_type;
|
|
|
|
if (projectType && projectType !== 'unknown_type') {
|
|
// Return refreshed dialog with project-specific fields
|
|
const webhookBaseUrl = getWebhookBaseUrl();
|
|
const refreshedDialog = webhookUtils.getFieldRefreshDialog(body.trigger_id, webhookBaseUrl, projectType);
|
|
|
|
response = {
|
|
type: 'form',
|
|
form: refreshedDialog.dialog,
|
|
};
|
|
} else {
|
|
// Invalid project type - return error or basic dialog
|
|
const webhookBaseUrl = getWebhookBaseUrl();
|
|
const basicDialog = webhookUtils.getFieldRefreshDialog(body.trigger_id, webhookBaseUrl);
|
|
|
|
response = {
|
|
type: 'form',
|
|
form: basicDialog.dialog,
|
|
};
|
|
}
|
|
} else if (body.cancelled) {
|
|
// Handle cancellation
|
|
const message = 'Field refresh dialog was cancelled';
|
|
sendSysadminResponse(message, body.channel_id);
|
|
response = {};
|
|
} else {
|
|
// Final submission - send success message to channel
|
|
const submissionText = Object.entries(body.submission).
|
|
map(([key, value]) => `${key}: ${value}`).
|
|
join('\n');
|
|
|
|
const message = `Field refresh dialog submitted successfully!\n\`\`\`\n${submissionText}\n\`\`\``;
|
|
sendSysadminResponse(message, body.channel_id);
|
|
|
|
response = {};
|
|
}
|
|
|
|
res.status(200).json(response);
|
|
}
|
|
|
|
// Catch-all route for unmatched requests
|
|
server.use((req, res) => {
|
|
res.status(404).json({
|
|
error: 'Not Found',
|
|
method: req.method,
|
|
url: req.originalUrl,
|
|
message: 'This endpoint does not exist on the webhook server',
|
|
});
|
|
});
|
|
|
|
server.listen(port, () => {
|
|
console.log(`Webhook test server listening on port ${port}!`);
|
|
});
|