mirror of
https://github.com/n8n-io/n8n.git
synced 2024-11-13 16:14:07 -08:00
feat(Mailhook Node): New node
This commit is contained in:
parent
497d637fc5
commit
c28ccb3e5c
|
@ -48,6 +48,7 @@ export interface FrontendSettings {
|
|||
};
|
||||
timezone: string;
|
||||
urlBaseWebhook: string;
|
||||
domain: string;
|
||||
urlBaseEditor: string;
|
||||
versionCli: string;
|
||||
nodeJsVersion: string;
|
||||
|
|
|
@ -100,6 +100,7 @@ export class FrontendService {
|
|||
workflowCallerPolicyDefaultOption: this.globalConfig.workflows.callerPolicyDefaultOption,
|
||||
timezone: this.globalConfig.generic.timezone,
|
||||
urlBaseWebhook: this.urlService.getWebhookBaseUrl(),
|
||||
domain: this.urlService.getDomain(),
|
||||
urlBaseEditor: instanceBaseUrl,
|
||||
binaryDataMode: config.getEnv('binaryDataManager.mode'),
|
||||
nodeJsVersion: process.version.replace(/^v/, ''),
|
||||
|
@ -250,6 +251,7 @@ export class FrontendService {
|
|||
// Update all urls, in case `WEBHOOK_URL` was updated by `--tunnel`
|
||||
const instanceBaseUrl = this.urlService.getInstanceBaseUrl();
|
||||
this.settings.urlBaseWebhook = this.urlService.getWebhookBaseUrl();
|
||||
this.settings.domain = this.urlService.getDomain();
|
||||
this.settings.urlBaseEditor = instanceBaseUrl;
|
||||
this.settings.oauthCallbackUrls = {
|
||||
oauth1: `${instanceBaseUrl}/${restEndpoint}/oauth1-credential/callback`,
|
||||
|
|
|
@ -21,6 +21,10 @@ export class UrlService {
|
|||
return urlBaseWebhook;
|
||||
}
|
||||
|
||||
getDomain() {
|
||||
return process.env.DOMAIN ?? new URL(this.getInstanceBaseUrl()).hostname;
|
||||
}
|
||||
|
||||
/** Return the n8n instance base URL without trailing slash */
|
||||
getInstanceBaseUrl(): string {
|
||||
const n8nBaseUrl = config.getEnv('editorBaseUrl') || this.getWebhookBaseUrl();
|
||||
|
|
|
@ -202,7 +202,7 @@ export class UserManagementMailer {
|
|||
|
||||
private get basePayload() {
|
||||
const baseUrl = this.urlService.getInstanceBaseUrl();
|
||||
const domain = new URL(baseUrl).hostname;
|
||||
const domain = this.urlService.getDomain();
|
||||
return { baseUrl, domain };
|
||||
}
|
||||
}
|
||||
|
|
|
@ -971,7 +971,8 @@ export async function getBase(
|
|||
currentNodeParameters?: INodeParameters,
|
||||
executionTimeoutTimestamp?: number,
|
||||
): Promise<IWorkflowExecuteAdditionalData> {
|
||||
const urlBaseWebhook = Container.get(UrlService).getWebhookBaseUrl();
|
||||
const urlService = Container.get(UrlService);
|
||||
const urlBaseWebhook = urlService.getWebhookBaseUrl();
|
||||
|
||||
const globalConfig = Container.get(GlobalConfig);
|
||||
|
||||
|
@ -988,6 +989,7 @@ export async function getBase(
|
|||
webhookBaseUrl: urlBaseWebhook + globalConfig.endpoints.webhook,
|
||||
webhookWaitingBaseUrl: urlBaseWebhook + globalConfig.endpoints.webhookWaiting,
|
||||
webhookTestBaseUrl: urlBaseWebhook + globalConfig.endpoints.webhookTest,
|
||||
domain: urlService.getDomain(),
|
||||
currentNodeParameters,
|
||||
executionTimeoutTimestamp,
|
||||
userId,
|
||||
|
|
|
@ -4572,6 +4572,9 @@ export function getExecuteHookFunctions(
|
|||
webhookData?.isTest,
|
||||
);
|
||||
},
|
||||
getDomain(): string {
|
||||
return additionalData.domain;
|
||||
},
|
||||
getWebhookName(): string {
|
||||
if (webhookData === undefined) {
|
||||
throw new ApplicationError('Only supported in webhook functions');
|
||||
|
|
|
@ -64,6 +64,7 @@
|
|||
"luxon": "catalog:",
|
||||
"n8n-design-system": "workspace:*",
|
||||
"n8n-workflow": "workspace:*",
|
||||
"nanoid": "catalog:",
|
||||
"pinia": "^2.2.4",
|
||||
"prettier": "^3.3.3",
|
||||
"qrcode.vue": "^3.3.4",
|
||||
|
|
|
@ -8,7 +8,7 @@ import type {
|
|||
IVersionNotificationSettings,
|
||||
} from '@n8n/api-types';
|
||||
import type { Scope } from '@n8n/permissions';
|
||||
import type { IMenuItem, NodeCreatorTag } from 'n8n-design-system';
|
||||
import type { NodeCreatorTag } from 'n8n-design-system';
|
||||
import type {
|
||||
GenericValue,
|
||||
IConnections,
|
||||
|
@ -883,6 +883,7 @@ export interface RootState {
|
|||
pushRef: string;
|
||||
urlBaseWebhook: string;
|
||||
urlBaseEditor: string;
|
||||
domain: string;
|
||||
instanceId: string;
|
||||
binaryDataMode: 'default' | 'filesystem' | 's3';
|
||||
}
|
||||
|
@ -890,51 +891,6 @@ export interface RootState {
|
|||
export interface NodeMetadataMap {
|
||||
[nodeName: string]: INodeMetadata;
|
||||
}
|
||||
export interface IRootState {
|
||||
activeExecutions: IExecutionsCurrentSummaryExtended[];
|
||||
activeWorkflows: string[];
|
||||
activeActions: string[];
|
||||
activeCredentialType: string | null;
|
||||
baseUrl: string;
|
||||
defaultLocale: string;
|
||||
endpointForm: string;
|
||||
endpointFormTest: string;
|
||||
endpointFormWaiting: string;
|
||||
endpointWebhook: string;
|
||||
endpointWebhookTest: string;
|
||||
endpointWebhookWaiting: string;
|
||||
executionId: string | null;
|
||||
executingNode: string[];
|
||||
executionWaitingForWebhook: boolean;
|
||||
pushConnectionActive: boolean;
|
||||
saveDataErrorExecution: string;
|
||||
saveDataSuccessExecution: string;
|
||||
saveManualExecutions: boolean;
|
||||
timezone: string;
|
||||
stateIsDirty: boolean;
|
||||
executionTimeout: number;
|
||||
maxExecutionTimeout: number;
|
||||
versionCli: string;
|
||||
oauthCallbackUrls: object;
|
||||
n8nMetadata: object;
|
||||
workflowExecutionData: IExecutionResponse | null;
|
||||
workflowExecutionPairedItemMappings: { [itemId: string]: Set<string> };
|
||||
lastSelectedNode: string | null;
|
||||
lastSelectedNodeOutputIndex: number | null;
|
||||
nodeViewOffsetPosition: XYPosition;
|
||||
nodeViewMoveInProgress: boolean;
|
||||
selectedNodes: INodeUi[];
|
||||
pushRef: string;
|
||||
urlBaseEditor: string;
|
||||
urlBaseWebhook: string;
|
||||
workflow: IWorkflowDb;
|
||||
workflowsById: IWorkflowsMap;
|
||||
sidebarMenuItems: IMenuItem[];
|
||||
instanceId: string;
|
||||
nodeMetadata: NodeMetadataMap;
|
||||
subworkflowExecutionError: Error | null;
|
||||
binaryDataMode: string;
|
||||
}
|
||||
|
||||
export interface CommunityPackageMap {
|
||||
[name: string]: PublicInstalledPackage;
|
||||
|
|
|
@ -4,6 +4,7 @@ import { useToast } from '@/composables/useToast';
|
|||
import {
|
||||
CHAT_TRIGGER_NODE_TYPE,
|
||||
FORM_TRIGGER_NODE_TYPE,
|
||||
MAILHOOK_TRIGGER_NODE_TYPE,
|
||||
OPEN_URL_PANEL_TRIGGER_NODE_TYPES,
|
||||
PRODUCTION_ONLY_TRIGGER_NODE_TYPES,
|
||||
} from '@/constants';
|
||||
|
@ -95,6 +96,18 @@ const baseText = computed(() => {
|
|||
copyMessage: i18n.baseText('nodeWebhooks.showMessage.message.formTrigger'),
|
||||
};
|
||||
|
||||
case MAILHOOK_TRIGGER_NODE_TYPE:
|
||||
return {
|
||||
toggleTitle: i18n.baseText('nodeWebhooks.webhookUrls.mailhookTrigger'),
|
||||
clickToDisplay: i18n.baseText('nodeWebhooks.clickToDisplayWebhookUrls.mailhookTrigger'),
|
||||
clickToHide: i18n.baseText('nodeWebhooks.clickToHideWebhookUrls.mailhookTrigger'),
|
||||
clickToCopy: i18n.baseText('nodeWebhooks.clickToCopyWebhookUrls.mailhookTrigger'),
|
||||
testUrl: i18n.baseText('nodeWebhooks.mailhook.testEmailId'),
|
||||
productionUrl: i18n.baseText('nodeWebhooks.mailhook.productionEmailId'),
|
||||
copyTitle: i18n.baseText('nodeWebhooks.showMessage.title.mailhookTrigger'),
|
||||
copyMessage: i18n.baseText('nodeWebhooks.showMessage.message.mailhookTrigger'),
|
||||
};
|
||||
|
||||
default:
|
||||
return {
|
||||
toggleTitle: i18n.baseText('nodeWebhooks.webhookUrls'),
|
||||
|
@ -127,6 +140,9 @@ function copyWebhookUrl(webhookData: IWebhookDescription): void {
|
|||
|
||||
function getWebhookUrlDisplay(webhookData: IWebhookDescription): string {
|
||||
if (props.node) {
|
||||
if (props.node.type === MAILHOOK_TRIGGER_NODE_TYPE) {
|
||||
return workflowHelpers.getMailhookEmailId(props.node);
|
||||
}
|
||||
return workflowHelpers.getWebhookUrl(
|
||||
webhookData,
|
||||
props.node,
|
||||
|
|
|
@ -1085,7 +1085,7 @@ export function useCanvasOperations({ router }: { router: ReturnType<typeof useR
|
|||
|
||||
function resolveNodeWebhook(node: INodeUi, nodeTypeDescription: INodeTypeDescription) {
|
||||
if (nodeTypeDescription.webhooks?.length) {
|
||||
node.webhookId = uuid();
|
||||
nodeHelpers.assignWebhookId(node);
|
||||
}
|
||||
|
||||
// if it's a webhook and the path is empty set the UUID as the default path
|
||||
|
@ -1657,7 +1657,7 @@ export function useCanvasOperations({ router }: { router: ReturnType<typeof useR
|
|||
(n) => n.webhookId === node.webhookId,
|
||||
);
|
||||
if (isDuplicate) {
|
||||
node.webhookId = uuid();
|
||||
nodeHelpers.assignWebhookId(node);
|
||||
|
||||
if (node.parameters.path) {
|
||||
node.parameters.path = node.webhookId as string;
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
import { ref, nextTick } from 'vue';
|
||||
import { useRoute } from 'vue-router';
|
||||
import { nanoid } from 'nanoid';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
import type { Connection, ConnectionDetachedParams } from '@jsplumb/core';
|
||||
import { useHistoryStore } from '@/stores/history.store';
|
||||
import {
|
||||
CUSTOM_API_CALL_KEY,
|
||||
FORM_TRIGGER_NODE_TYPE,
|
||||
MAILHOOK_TRIGGER_NODE_TYPE,
|
||||
NODE_OUTPUT_DEFAULT_KEY,
|
||||
PLACEHOLDER_FILLED_AT_EXECUTION_TIME,
|
||||
SPLIT_IN_BATCHES_NODE_TYPE,
|
||||
|
@ -1247,6 +1249,10 @@ export function useNodeHelpers() {
|
|||
canvasStore.jsPlumbInstance?.setSuspendDrawing(false, true);
|
||||
}
|
||||
|
||||
function assignWebhookId(node: INodeUi) {
|
||||
node.webhookId = node.type === MAILHOOK_TRIGGER_NODE_TYPE ? nanoid(16).toLowerCase() : uuid();
|
||||
}
|
||||
|
||||
return {
|
||||
hasProxyAuth,
|
||||
isCustomApiCallSelected,
|
||||
|
@ -1281,5 +1287,6 @@ export function useNodeHelpers() {
|
|||
removeConnectionByConnectionInfo,
|
||||
addPinDataConnections,
|
||||
removePinDataConnections,
|
||||
assignWebhookId,
|
||||
};
|
||||
}
|
||||
|
|
|
@ -706,6 +706,10 @@ export function useWorkflowHelpers(options: { router: ReturnType<typeof useRoute
|
|||
return NodeHelpers.getNodeWebhookUrl(baseUrl, workflowId, node, path, isFullPath);
|
||||
}
|
||||
|
||||
function getMailhookEmailId(node: INodeUi) {
|
||||
return `${node.webhookId}@${rootStore.domain}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a copy of provided node parameters with added resolvedExpressionValue
|
||||
* @param nodeParameters
|
||||
|
@ -1200,6 +1204,7 @@ export function useWorkflowHelpers(options: { router: ReturnType<typeof useRoute
|
|||
getNodeDataToSave,
|
||||
getWebhookExpressionValue,
|
||||
getWebhookUrl,
|
||||
getMailhookEmailId,
|
||||
resolveExpression,
|
||||
updateWorkflow,
|
||||
saveCurrentWorkflow,
|
||||
|
|
|
@ -196,6 +196,7 @@ export const SIMULATE_NODE_TYPE = 'n8n-nodes-base.simulate';
|
|||
export const SIMULATE_TRIGGER_NODE_TYPE = 'n8n-nodes-base.simulateTrigger';
|
||||
export const AI_TRANSFORM_NODE_TYPE = 'n8n-nodes-base.aiTransform';
|
||||
export const FORM_NODE_TYPE = 'n8n-nodes-base.form';
|
||||
export const MAILHOOK_TRIGGER_NODE_TYPE = 'n8n-nodes-base.mailhook';
|
||||
|
||||
export const CREDENTIAL_ONLY_NODE_PREFIX = 'n8n-creds-base';
|
||||
export const CREDENTIAL_ONLY_HTTP_NODE_VERSION = 4.1;
|
||||
|
@ -227,11 +228,15 @@ export const OPEN_URL_PANEL_TRIGGER_NODE_TYPES = [
|
|||
WEBHOOK_NODE_TYPE,
|
||||
FORM_TRIGGER_NODE_TYPE,
|
||||
CHAT_TRIGGER_NODE_TYPE,
|
||||
MAILHOOK_TRIGGER_NODE_TYPE,
|
||||
];
|
||||
|
||||
export const LIST_LIKE_NODE_OPERATIONS = ['getAll', 'getMany', 'read', 'search'];
|
||||
|
||||
export const PRODUCTION_ONLY_TRIGGER_NODE_TYPES = [CHAT_TRIGGER_NODE_TYPE];
|
||||
export const PRODUCTION_ONLY_TRIGGER_NODE_TYPES = [
|
||||
CHAT_TRIGGER_NODE_TYPE,
|
||||
MAILHOOK_TRIGGER_NODE_TYPE,
|
||||
];
|
||||
|
||||
// Node creator
|
||||
export const NODE_CREATOR_OPEN_SOURCES: Record<
|
||||
|
|
|
@ -1343,23 +1343,31 @@
|
|||
"nodeWebhooks.clickToCopyWebhookUrls": "Click to copy webhook URLs",
|
||||
"nodeWebhooks.clickToCopyWebhookUrls.formTrigger": "Click to copy Form URL",
|
||||
"nodeWebhooks.clickToCopyWebhookUrls.chatTrigger": "Click to copy Chat URL",
|
||||
"nodeWebhooks.clickToCopyWebhookUrls.mailhookTrigger": "Click to copy Email ID",
|
||||
"nodeWebhooks.clickToDisplayWebhookUrls": "Click to display webhook URLs",
|
||||
"nodeWebhooks.clickToDisplayWebhookUrls.formTrigger": "Click to display Form URL",
|
||||
"nodeWebhooks.clickToDisplayWebhookUrls.chatTrigger": "Click to display Chat URL",
|
||||
"nodeWebhooks.clickToDisplayWebhookUrls.mailhookTrigger": "Click to display Email IDs",
|
||||
"nodeWebhooks.clickToHideWebhookUrls": "Click to hide webhook URLs",
|
||||
"nodeWebhooks.clickToHideWebhookUrls.formTrigger": "Click to hide Form URL",
|
||||
"nodeWebhooks.clickToHideWebhookUrls.chatTrigger": "Click to hide Chat URL",
|
||||
"nodeWebhooks.clickToHideWebhookUrls.mailhookTrigger": "Click to hide Mailhook Email IDs",
|
||||
"nodeWebhooks.invalidExpression": "[INVALID EXPRESSION]",
|
||||
"nodeWebhooks.mailhook.testEmailId": "Test Email ID",
|
||||
"nodeWebhooks.mailhook.productionEmailId": "Production Email ID",
|
||||
"nodeWebhooks.productionUrl": "Production URL",
|
||||
"nodeWebhooks.showMessage.title": "URL copied",
|
||||
"nodeWebhooks.showMessage.title.formTrigger": "Form URL copied",
|
||||
"nodeWebhooks.showMessage.title.chatTrigger": "Chat URL copied",
|
||||
"nodeWebhooks.showMessage.title.mailhookTrigger": "Mailhook Email ID copied",
|
||||
"nodeWebhooks.showMessage.message.formTrigger": "Form submissions made via this URL will trigger the workflow when it's activated",
|
||||
"nodeWebhooks.showMessage.message.chatTrigger": "Chat submissions made via this URL will trigger the workflow when it's activated",
|
||||
"nodeWebhooks.showMessage.message.mailhookTrigger": "Incoming emails on this Email ID will trigger the workflow when it's activated",
|
||||
"nodeWebhooks.testUrl": "Test URL",
|
||||
"nodeWebhooks.webhookUrls": "Webhook URLs",
|
||||
"nodeWebhooks.webhookUrls.formTrigger": "Form URLs",
|
||||
"nodeWebhooks.webhookUrls.chatTrigger": "Chat URL",
|
||||
"nodeWebhooks.webhookUrls.mailhookTrigger": "Mailhook Email IDs",
|
||||
"onboardingWorkflow.stickyContent": "## 👇 Get started faster \nLightning tour of the key concepts [4 min] \n\n[![n8n quickstart video](/static/quickstart_thumbnail.png#full-width)](https://www.youtube.com/watch?v=1MwSoB0gnM4)",
|
||||
"openWorkflow.workflowImportError": "Could not import workflow",
|
||||
"openWorkflow.workflowNotFoundError": "Could not find workflow",
|
||||
|
|
|
@ -30,6 +30,7 @@ export const useRootStore = defineStore(STORES.ROOT, () => {
|
|||
pushRef: randomString(10).toLowerCase(),
|
||||
urlBaseWebhook: 'http://localhost:5678/',
|
||||
urlBaseEditor: 'http://localhost:5678',
|
||||
domain: 'localhost',
|
||||
instanceId: '',
|
||||
binaryDataMode: 'default',
|
||||
});
|
||||
|
@ -54,6 +55,8 @@ export const useRootStore = defineStore(STORES.ROOT, () => {
|
|||
() => `${state.value.urlBaseEditor}${state.value.endpointWebhookWaiting}`,
|
||||
);
|
||||
|
||||
const domain = computed(() => state.value.domain);
|
||||
|
||||
const pushRef = computed(() => state.value.pushRef);
|
||||
|
||||
const binaryDataMode = computed(() => state.value.binaryDataMode);
|
||||
|
@ -142,6 +145,10 @@ export const useRootStore = defineStore(STORES.ROOT, () => {
|
|||
state.value.endpointWebhookWaiting = endpointWebhookWaiting;
|
||||
};
|
||||
|
||||
const setDomain = (domain: string) => {
|
||||
state.value.domain = domain;
|
||||
};
|
||||
|
||||
const setTimezone = (timezone: string) => {
|
||||
state.value.timezone = timezone;
|
||||
setGlobalState({ defaultTimezone: timezone });
|
||||
|
@ -189,6 +196,7 @@ export const useRootStore = defineStore(STORES.ROOT, () => {
|
|||
webhookUrl,
|
||||
webhookTestUrl,
|
||||
webhookWaitingUrl,
|
||||
domain,
|
||||
restUrl,
|
||||
restCloudApiContext,
|
||||
restApiContext,
|
||||
|
@ -213,6 +221,7 @@ export const useRootStore = defineStore(STORES.ROOT, () => {
|
|||
setEndpointWebhook,
|
||||
setEndpointWebhookTest,
|
||||
setEndpointWebhookWaiting,
|
||||
setDomain,
|
||||
setTimezone,
|
||||
setExecutionTimeout,
|
||||
setMaxExecutionTimeout,
|
||||
|
|
|
@ -243,6 +243,7 @@ export const useSettingsStore = defineStore(STORES.SETTINGS, () => {
|
|||
rootStore.setEndpointWebhook(fetchedSettings.endpointWebhook);
|
||||
rootStore.setEndpointWebhookTest(fetchedSettings.endpointWebhookTest);
|
||||
rootStore.setEndpointWebhookWaiting(fetchedSettings.endpointWebhookWaiting);
|
||||
rootStore.setDomain(fetchedSettings.domain);
|
||||
rootStore.setTimezone(fetchedSettings.timezone);
|
||||
rootStore.setExecutionTimeout(fetchedSettings.executionTimeout);
|
||||
rootStore.setMaxExecutionTimeout(fetchedSettings.maxExecutionTimeout);
|
||||
|
|
|
@ -1923,7 +1923,7 @@ export default defineComponent({
|
|||
this.workflowHelpers.getCurrentWorkflow().nodes,
|
||||
).some((n) => n.webhookId === node.webhookId);
|
||||
if (isDuplicate) {
|
||||
node.webhookId = uuid();
|
||||
this.nodeHelpers.assignWebhookId(node);
|
||||
|
||||
if (node.parameters.path) {
|
||||
node.parameters.path = node.webhookId as string;
|
||||
|
@ -2389,7 +2389,7 @@ export default defineComponent({
|
|||
newNodeData.name = this.uniqueNodeName(localizedName);
|
||||
|
||||
if (nodeTypeData.webhooks?.length) {
|
||||
newNodeData.webhookId = uuid();
|
||||
this.nodeHelpers.assignWebhookId(newNodeData);
|
||||
}
|
||||
|
||||
await this.nodeHelpers.addNodes([newNodeData], undefined, trackHistory);
|
||||
|
|
87
packages/nodes-base/nodes/Mailhook/Mailhook.node.ts
Normal file
87
packages/nodes-base/nodes/Mailhook/Mailhook.node.ts
Normal file
|
@ -0,0 +1,87 @@
|
|||
import {
|
||||
IDataObject,
|
||||
IWebhookFunctions,
|
||||
INodeTypeDescription,
|
||||
INodeType,
|
||||
IWebhookResponseData,
|
||||
NodeConnectionType,
|
||||
IHookFunctions,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
// TODO: this should be picked up from a config object
|
||||
const baseUrl = 'http://localhost:8080/rest/mailhooks';
|
||||
const apiRequest = async (
|
||||
context: IHookFunctions,
|
||||
operation: 'checkExists' | 'create' | 'delete',
|
||||
) => {
|
||||
const { webhookId } = context.getNode();
|
||||
const domain = context.getDomain();
|
||||
const method = operation === 'checkExists' ? 'GET' : operation === 'create' ? 'POST' : 'DELETE';
|
||||
let url = baseUrl;
|
||||
if (operation !== 'create') {
|
||||
url += `/${webhookId}@${domain}`;
|
||||
}
|
||||
const response = await context.helpers.httpRequest({
|
||||
url,
|
||||
method,
|
||||
returnFullResponse: true,
|
||||
ignoreHttpStatusErrors: true,
|
||||
});
|
||||
return response.statusCode === 204;
|
||||
};
|
||||
|
||||
export class Mailhook implements INodeType {
|
||||
description: INodeTypeDescription = {
|
||||
displayName: 'Mailhook',
|
||||
name: 'mailhook',
|
||||
icon: 'file:mailhook.svg',
|
||||
group: ['trigger'],
|
||||
version: 1,
|
||||
description: 'Start a workflow on a Mailhook trigger',
|
||||
defaults: {
|
||||
name: 'Mailhook',
|
||||
color: '#4363AE',
|
||||
},
|
||||
inputs: [],
|
||||
outputs: [NodeConnectionType.Main],
|
||||
webhooks: [
|
||||
{
|
||||
name: 'default',
|
||||
httpMethod: 'POST',
|
||||
responseMode: 'onReceived',
|
||||
path: 'webhook',
|
||||
ndvHideMethod: true,
|
||||
},
|
||||
],
|
||||
properties: [],
|
||||
};
|
||||
|
||||
webhookMethods = {
|
||||
default: {
|
||||
async checkExists(this: IHookFunctions): Promise<boolean> {
|
||||
return await apiRequest(this, 'checkExists');
|
||||
},
|
||||
async create(this: IHookFunctions): Promise<boolean> {
|
||||
return await apiRequest(this, 'create');
|
||||
},
|
||||
async delete(this: IHookFunctions): Promise<boolean> {
|
||||
return await apiRequest(this, 'delete');
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
async webhook(this: IWebhookFunctions): Promise<IWebhookResponseData> {
|
||||
// The data to return and so start the workflow with
|
||||
const returnData: IDataObject[] = [];
|
||||
returnData.push({
|
||||
headers: this.getHeaderData(),
|
||||
params: this.getParamsData(),
|
||||
query: this.getQueryData(),
|
||||
body: this.getBodyData(),
|
||||
});
|
||||
|
||||
return {
|
||||
workflowData: [this.helpers.returnJsonArray(returnData)],
|
||||
};
|
||||
}
|
||||
}
|
4
packages/nodes-base/nodes/Mailhook/mailhook.svg
Normal file
4
packages/nodes-base/nodes/Mailhook/mailhook.svg
Normal file
|
@ -0,0 +1,4 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="0 0 40 40">
|
||||
<path d="M 7.885 9.683 L 20.885 19.683 L 33.885 9.683" stroke="#727db5" stroke-width="2" fill="transparent"/>
|
||||
<path d="M 8.011 21.45 L 21.011 31.45 L 34.011 21.45" stroke="#727db5" stroke-width="2" fill="transparent"/>
|
||||
</svg>
|
After Width: | Height: | Size: 314 B |
|
@ -604,6 +604,7 @@
|
|||
"dist/nodes/Mailcheck/Mailcheck.node.js",
|
||||
"dist/nodes/Mailchimp/Mailchimp.node.js",
|
||||
"dist/nodes/Mailchimp/MailchimpTrigger.node.js",
|
||||
"dist/nodes/Mailhook/Mailhook.node.js",
|
||||
"dist/nodes/MailerLite/MailerLite.node.js",
|
||||
"dist/nodes/MailerLite/MailerLiteTrigger.node.js",
|
||||
"dist/nodes/Mailgun/Mailgun.node.js",
|
||||
|
|
|
@ -1111,6 +1111,7 @@ export interface IHookFunctions
|
|||
getWebhookName(): string;
|
||||
getWebhookDescription(name: string): IWebhookDescription | undefined;
|
||||
getNodeWebhookUrl: (name: string) => string | undefined;
|
||||
getDomain(): string;
|
||||
getNodeParameter(
|
||||
parameterName: string,
|
||||
fallbackValue?: any,
|
||||
|
@ -2306,6 +2307,7 @@ export interface IWorkflowExecuteAdditionalData {
|
|||
webhookBaseUrl: string;
|
||||
webhookWaitingBaseUrl: string;
|
||||
webhookTestBaseUrl: string;
|
||||
domain: string;
|
||||
currentNodeParameters?: INodeParameters;
|
||||
executionTimeoutTimestamp?: number;
|
||||
userId?: string;
|
||||
|
|
|
@ -1444,6 +1444,9 @@ importers:
|
|||
n8n-workflow:
|
||||
specifier: workspace:*
|
||||
version: link:../workflow
|
||||
nanoid:
|
||||
specifier: 'catalog:'
|
||||
version: 3.3.6
|
||||
pinia:
|
||||
specifier: ^2.2.4
|
||||
version: 2.2.4(typescript@5.6.2)(vue@3.5.11(typescript@5.6.2))
|
||||
|
|
Loading…
Reference in a new issue