mirror of
https://github.com/n8n-io/n8n.git
synced 2024-09-11 13:15:28 +03:00
💥 Fix typo reponse => response
This commit is contained in:
parent
1ff456d77c
commit
4d6e25c28e
@ -107,28 +107,28 @@ export class ActiveWorkflowRunner {
|
||||
*/
|
||||
async executeWebhook(httpMethod: WebhookHttpMethod, path: string, req: express.Request, res: express.Response): Promise<IResponseCallbackData> {
|
||||
if (this.activeWorkflows === null) {
|
||||
throw new ResponseHelper.ReponseError('The "activeWorkflows" instance did not get initialized yet.', 404, 404);
|
||||
throw new ResponseHelper.ResponseError('The "activeWorkflows" instance did not get initialized yet.', 404, 404);
|
||||
}
|
||||
|
||||
const webhookData: IWebhookData | undefined = this.activeWebhooks!.get(httpMethod, path);
|
||||
|
||||
if (webhookData === undefined) {
|
||||
// The requested webhook is not registred
|
||||
throw new ResponseHelper.ReponseError('The requested webhook is not registred.', 404, 404);
|
||||
throw new ResponseHelper.ResponseError('The requested webhook is not registred.', 404, 404);
|
||||
}
|
||||
|
||||
// Get the node which has the webhook defined to know where to start from and to
|
||||
// get additional data
|
||||
const workflowStartNode = webhookData.workflow.getNode(webhookData.node);
|
||||
if (workflowStartNode === null) {
|
||||
throw new ResponseHelper.ReponseError('Could not find node to process webhook.', 404, 404);
|
||||
throw new ResponseHelper.ResponseError('Could not find node to process webhook.', 404, 404);
|
||||
}
|
||||
const executionMode = 'webhook';
|
||||
|
||||
const workflowData = await Db.collections.Workflow!.findOne(webhookData.workflow.id!);
|
||||
|
||||
if (workflowData === undefined) {
|
||||
throw new ResponseHelper.ReponseError(`Could not find workflow with id "${webhookData.workflow.id}"`, 404, 404);
|
||||
throw new ResponseHelper.ResponseError(`Could not find workflow with id "${webhookData.workflow.id}"`, 404, 404);
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
|
@ -13,10 +13,10 @@ import {
|
||||
* Special Error which allows to return also an error code and http status code
|
||||
*
|
||||
* @export
|
||||
* @class ReponseError
|
||||
* @class ResponseError
|
||||
* @extends {Error}
|
||||
*/
|
||||
export class ReponseError extends Error {
|
||||
export class ResponseError extends Error {
|
||||
|
||||
// The HTTP status code of response
|
||||
httpStatusCode?: number;
|
||||
@ -25,15 +25,15 @@ export class ReponseError extends Error {
|
||||
errorCode?: number;
|
||||
|
||||
/**
|
||||
* Creates an instance of ReponseError.
|
||||
* Creates an instance of ResponseError.
|
||||
* @param {string} message The error message
|
||||
* @param {number} [errorCode] The error code which can be used by frontend to identify the actual error
|
||||
* @param {number} [httpStatusCode] The HTTP status code the response should have
|
||||
* @memberof ReponseError
|
||||
* @memberof ResponseError
|
||||
*/
|
||||
constructor(message: string, errorCode?: number, httpStatusCode?: number) {
|
||||
super(message);
|
||||
this.name = 'ReponseError';
|
||||
this.name = 'ResponseError';
|
||||
|
||||
if (errorCode) {
|
||||
this.errorCode = errorCode;
|
||||
@ -71,7 +71,7 @@ export function sendSuccessResponse(res: Response, data: any, raw?: boolean, res
|
||||
}
|
||||
|
||||
|
||||
export function sendErrorResponse(res: Response, error: ReponseError) {
|
||||
export function sendErrorResponse(res: Response, error: ResponseError) {
|
||||
let httpStatusCode = 500;
|
||||
if (error.httpStatusCode) {
|
||||
httpStatusCode = error.httpStatusCode;
|
||||
|
@ -208,7 +208,7 @@ class App {
|
||||
|
||||
this.app.use((req: express.Request, res: express.Response, next: express.NextFunction) => {
|
||||
if (Db.collections.Workflow === null) {
|
||||
const error = new ResponseHelper.ReponseError('Database is not ready!', undefined, 503);
|
||||
const error = new ResponseHelper.ResponseError('Database is not ready!', undefined, 503);
|
||||
return ResponseHelper.sendErrorResponse(res, error);
|
||||
}
|
||||
|
||||
@ -246,10 +246,10 @@ class App {
|
||||
// Reads and returns workflow data from an URL
|
||||
this.app.get('/rest/workflows/from-url', ResponseHelper.send(async (req: express.Request, res: express.Response): Promise<IWorkflowResponse> => {
|
||||
if (req.query.url === undefined) {
|
||||
throw new ResponseHelper.ReponseError(`The parameter "url" is missing!`, undefined, 400);
|
||||
throw new ResponseHelper.ResponseError(`The parameter "url" is missing!`, undefined, 400);
|
||||
}
|
||||
if (!req.query.url.match(/^http[s]?:\/\/.*\.json$/i)) {
|
||||
throw new ResponseHelper.ReponseError(`The parameter "url" is not valid! It does not seem to be a URL pointing to a n8n workflow JSON file.`, undefined, 400);
|
||||
throw new ResponseHelper.ResponseError(`The parameter "url" is not valid! It does not seem to be a URL pointing to a n8n workflow JSON file.`, undefined, 400);
|
||||
}
|
||||
const data = await requestPromise.get(req.query.url);
|
||||
|
||||
@ -257,14 +257,14 @@ class App {
|
||||
try {
|
||||
workflowData = JSON.parse(data);
|
||||
} catch (error) {
|
||||
throw new ResponseHelper.ReponseError(`The URL does not point to valid JSON file!`, undefined, 400);
|
||||
throw new ResponseHelper.ResponseError(`The URL does not point to valid JSON file!`, undefined, 400);
|
||||
}
|
||||
|
||||
// Do a very basic check if it is really a n8n-workflow-json
|
||||
if (workflowData === undefined || workflowData.nodes === undefined || !Array.isArray(workflowData.nodes) ||
|
||||
workflowData.connections === undefined || typeof workflowData.connections !== 'object' ||
|
||||
Array.isArray(workflowData.connections)) {
|
||||
throw new ResponseHelper.ReponseError(`The data in the file does not seem to be a n8n workflow JSON file!`, undefined, 400);
|
||||
throw new ResponseHelper.ResponseError(`The data in the file does not seem to be a n8n workflow JSON file!`, undefined, 400);
|
||||
}
|
||||
|
||||
return workflowData;
|
||||
@ -343,13 +343,13 @@ class App {
|
||||
|
||||
// We sadly get nothing back from "update". Neither if it updated a record
|
||||
// nor the new value. So query now the hopefully updated entry.
|
||||
const reponseData = await Db.collections.Workflow!.findOne(id);
|
||||
const responseData = await Db.collections.Workflow!.findOne(id);
|
||||
|
||||
if (reponseData === undefined) {
|
||||
throw new ResponseHelper.ReponseError(`Workflow with id "${id}" could not be found to be updated.`, undefined, 400);
|
||||
if (responseData === undefined) {
|
||||
throw new ResponseHelper.ResponseError(`Workflow with id "${id}" could not be found to be updated.`, undefined, 400);
|
||||
}
|
||||
|
||||
if (reponseData.active === true) {
|
||||
if (responseData.active === true) {
|
||||
// When the workflow is supposed to be active add it again
|
||||
try {
|
||||
await this.activeWorkflowRunner.add(id);
|
||||
@ -359,7 +359,7 @@ class App {
|
||||
await Db.collections.Workflow!.update(id, newWorkflowData);
|
||||
|
||||
// Also set it in the returned data
|
||||
reponseData.active = false;
|
||||
responseData.active = false;
|
||||
|
||||
// Now return the original error for UI to display
|
||||
throw error;
|
||||
@ -367,8 +367,8 @@ class App {
|
||||
}
|
||||
|
||||
// Convert to response format in which the id is a string
|
||||
(reponseData as IWorkflowBase as IWorkflowResponse).id = reponseData.id.toString();
|
||||
return reponseData as IWorkflowBase as IWorkflowResponse;
|
||||
(responseData as IWorkflowBase as IWorkflowResponse).id = responseData.id.toString();
|
||||
return responseData as IWorkflowBase as IWorkflowResponse;
|
||||
}));
|
||||
|
||||
|
||||
@ -569,7 +569,7 @@ class App {
|
||||
|
||||
const checkResult = await Db.collections.Credentials!.findOne(findQuery);
|
||||
if (checkResult !== undefined) {
|
||||
throw new ResponseHelper.ReponseError(`Credentials with the same type and name exist already.`, undefined, 400);
|
||||
throw new ResponseHelper.ResponseError(`Credentials with the same type and name exist already.`, undefined, 400);
|
||||
}
|
||||
|
||||
// Encrypt the data
|
||||
@ -616,7 +616,7 @@ class App {
|
||||
|
||||
const checkResult = await Db.collections.Credentials!.findOne(findQuery);
|
||||
if (checkResult !== undefined) {
|
||||
throw new ResponseHelper.ReponseError(`Credentials with the same type and name exist already.`, undefined, 400);
|
||||
throw new ResponseHelper.ResponseError(`Credentials with the same type and name exist already.`, undefined, 400);
|
||||
}
|
||||
|
||||
const encryptionKey = await UserSettings.getEncryptionKey();
|
||||
@ -637,18 +637,18 @@ class App {
|
||||
|
||||
// We sadly get nothing back from "update". Neither if it updated a record
|
||||
// nor the new value. So query now the hopefully updated entry.
|
||||
const reponseData = await Db.collections.Credentials!.findOne(id);
|
||||
const responseData = await Db.collections.Credentials!.findOne(id);
|
||||
|
||||
if (reponseData === undefined) {
|
||||
throw new ResponseHelper.ReponseError(`Credentials with id "${id}" could not be found to be updated.`, undefined, 400);
|
||||
if (responseData === undefined) {
|
||||
throw new ResponseHelper.ResponseError(`Credentials with id "${id}" could not be found to be updated.`, undefined, 400);
|
||||
}
|
||||
|
||||
// Remove the encrypted data as it is not needed in the frontend
|
||||
reponseData.data = '';
|
||||
responseData.data = '';
|
||||
|
||||
// Convert to response format in which the id is a string
|
||||
(reponseData as unknown as ICredentialsResponse).id = reponseData.id.toString();
|
||||
return reponseData as unknown as ICredentialsResponse;
|
||||
(responseData as unknown as ICredentialsResponse).id = responseData.id.toString();
|
||||
return responseData as unknown as ICredentialsResponse;
|
||||
}));
|
||||
|
||||
|
||||
@ -837,7 +837,7 @@ class App {
|
||||
const fullExecutionDataFlatted = await Db.collections.Execution!.findOne(req.params.id);
|
||||
|
||||
if (fullExecutionDataFlatted === undefined) {
|
||||
throw new ResponseHelper.ReponseError(`The execution with the id "${req.params.id}" does not exist.`, 404, 404);
|
||||
throw new ResponseHelper.ResponseError(`The execution with the id "${req.params.id}" does not exist.`, 404, 404);
|
||||
}
|
||||
|
||||
const fullExecutionData = ResponseHelper.unflattenExecutionData(fullExecutionDataFlatted);
|
||||
|
@ -57,14 +57,14 @@ export class TestWebhooks {
|
||||
|
||||
if (webhookData === undefined) {
|
||||
// The requested webhook is not registred
|
||||
throw new ResponseHelper.ReponseError('The requested webhook is not registred.', 404, 404);
|
||||
throw new ResponseHelper.ResponseError('The requested webhook is not registred.', 404, 404);
|
||||
}
|
||||
|
||||
// Get the node which has the webhook defined to know where to start from and to
|
||||
// get additional data
|
||||
const workflowStartNode = webhookData.workflow.getNode(webhookData.node);
|
||||
if (workflowStartNode === null) {
|
||||
throw new ResponseHelper.ReponseError('Could not find node to process webhook.', 404, 404);
|
||||
throw new ResponseHelper.ResponseError('Could not find node to process webhook.', 404, 404);
|
||||
}
|
||||
|
||||
const webhookKey = this.activeWebhooks!.getWebhookKey(webhookData.httpMethod, webhookData.path);
|
||||
|
@ -110,20 +110,20 @@ export function getWorkflowWebhooks(workflow: Workflow, additionalData: IWorkflo
|
||||
if (nodeType === undefined) {
|
||||
const errorMessage = `The type of the webhook node "${workflowStartNode.name}" is not known.`;
|
||||
responseCallback(new Error(errorMessage), {});
|
||||
throw new ResponseHelper.ReponseError(errorMessage, 500, 500);
|
||||
throw new ResponseHelper.ResponseError(errorMessage, 500, 500);
|
||||
}
|
||||
|
||||
// Get the responseMode
|
||||
const reponseMode = webhookData.workflow.getSimpleParameterValue(workflowStartNode, webhookData.webhookDescription['reponseMode'], 'onReceived');
|
||||
const responseCode = webhookData.workflow.getSimpleParameterValue(workflowStartNode, webhookData.webhookDescription['responseCode'], 200);
|
||||
const responseMode = webhookData.workflow.getSimpleParameterValue(workflowStartNode, webhookData.webhookDescription['responseMode'], 'onReceived');
|
||||
const responseCode = webhookData.workflow.getSimpleParameterValue(workflowStartNode, webhookData.webhookDescription['responseCode'], 200) as number;
|
||||
|
||||
if (!['onReceived', 'lastNode'].includes(reponseMode as string)) {
|
||||
if (!['onReceived', 'lastNode'].includes(responseMode as string)) {
|
||||
// If the mode is not known we error. Is probably best like that instead of using
|
||||
// the default that people know as early as possible (probably already testing phase)
|
||||
// that something does not resolve properly.
|
||||
const errorMessage = `The response mode ${reponseMode} is not valid!.`;
|
||||
const errorMessage = `The response mode ${responseMode} is not valid!.`;
|
||||
responseCallback(new Error(errorMessage), {});
|
||||
throw new ResponseHelper.ReponseError(errorMessage, 500, 500);
|
||||
throw new ResponseHelper.ResponseError(errorMessage, 500, 500);
|
||||
}
|
||||
|
||||
// Prepare everything that is needed to run the workflow
|
||||
@ -170,7 +170,7 @@ export function getWorkflowWebhooks(workflow: Workflow, additionalData: IWorkflo
|
||||
|
||||
// Now that we know that the workflow should run we can return the default respons
|
||||
// directly if responseMode it set to "onReceived" and a respone should be sent
|
||||
if (reponseMode === 'onReceived' && didSendResponse === false) {
|
||||
if (responseMode === 'onReceived' && didSendResponse === false) {
|
||||
// Return response directly and do not wait for the workflow to finish
|
||||
if (webhookResultData.webhookResponse !== undefined) {
|
||||
// Data to respond with is given
|
||||
@ -179,8 +179,6 @@ export function getWorkflowWebhooks(workflow: Workflow, additionalData: IWorkflo
|
||||
responseCode,
|
||||
});
|
||||
} else {
|
||||
console.log('k1: ' + responseCode);
|
||||
|
||||
responseCallback(null, {
|
||||
data: {
|
||||
message: 'Workflow got started.',
|
||||
@ -268,15 +266,15 @@ export function getWorkflowWebhooks(workflow: Workflow, additionalData: IWorkflo
|
||||
return data;
|
||||
}
|
||||
|
||||
const reponseData = webhookData.workflow.getSimpleParameterValue(workflowStartNode, webhookData.webhookDescription['reponseData'], 'firstEntryJson');
|
||||
const responseData = webhookData.workflow.getSimpleParameterValue(workflowStartNode, webhookData.webhookDescription['responseData'], 'firstEntryJson');
|
||||
|
||||
if (didSendResponse === false) {
|
||||
let data: IDataObject | IDataObject[];
|
||||
|
||||
if (reponseData === 'firstEntryJson') {
|
||||
if (responseData === 'firstEntryJson') {
|
||||
// Return the JSON data of the first entry
|
||||
data = returnData.data!.main[0]![0].json;
|
||||
} else if (reponseData === 'firstEntryBinary') {
|
||||
} else if (responseData === 'firstEntryBinary') {
|
||||
// Return the binary data of the first entry
|
||||
data = returnData.data!.main[0]![0];
|
||||
if (data.binary === undefined) {
|
||||
@ -323,7 +321,7 @@ export function getWorkflowWebhooks(workflow: Workflow, additionalData: IWorkflo
|
||||
responseCallback(new Error('There was a problem executing the workflow.'), {});
|
||||
}
|
||||
|
||||
throw new ResponseHelper.ReponseError(e.message, 500, 500);
|
||||
throw new ResponseHelper.ResponseError(e.message, 500, 500);
|
||||
});
|
||||
|
||||
return executionId;
|
||||
@ -333,7 +331,7 @@ export function getWorkflowWebhooks(workflow: Workflow, additionalData: IWorkflo
|
||||
responseCallback(new Error('There was a problem executing the workflow.'), {});
|
||||
}
|
||||
|
||||
throw new ResponseHelper.ReponseError(e.message, 500, 500);
|
||||
throw new ResponseHelper.ResponseError(e.message, 500, 500);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -54,7 +54,7 @@ function unflattenExecutionData (fullExecutionData: IExecutionFlattedResponse):
|
||||
return returnData;
|
||||
}
|
||||
|
||||
export class ReponseError extends Error {
|
||||
export class ResponseError extends Error {
|
||||
// The HTTP status code of response
|
||||
httpStatusCode?: number;
|
||||
|
||||
@ -65,16 +65,16 @@ export class ReponseError extends Error {
|
||||
serverStackTrace?: string;
|
||||
|
||||
/**
|
||||
* Creates an instance of ReponseError.
|
||||
* Creates an instance of ResponseError.
|
||||
* @param {string} message The error message
|
||||
* @param {number} [errorCode] The error code which can be used by frontend to identify the actual error
|
||||
* @param {number} [httpStatusCode] The HTTP status code the response should have
|
||||
* @param {string} [stack] The stack trace
|
||||
* @memberof ReponseError
|
||||
* @memberof ResponseError
|
||||
*/
|
||||
constructor (message: string, errorCode?: number, httpStatusCode?: number, stack?: string) {
|
||||
super(message);
|
||||
this.name = 'ReponseError';
|
||||
this.name = 'ResponseError';
|
||||
|
||||
if (errorCode) {
|
||||
this.errorCode = errorCode;
|
||||
@ -113,12 +113,12 @@ export const restApi = Vue.extend({
|
||||
return response.data.data;
|
||||
} catch (error) {
|
||||
if (error.message === 'Network Error') {
|
||||
throw new ReponseError('API-Server can not be reached. It is probably down.');
|
||||
throw new ResponseError('API-Server can not be reached. It is probably down.');
|
||||
}
|
||||
|
||||
const errorResponseData = error.response.data;
|
||||
if (errorResponseData !== undefined && errorResponseData.message !== undefined) {
|
||||
throw new ReponseError(errorResponseData.message, errorResponseData.code, error.response.status, errorResponseData.stack);
|
||||
throw new ResponseError(errorResponseData.message, errorResponseData.code, error.response.status, errorResponseData.stack);
|
||||
}
|
||||
|
||||
throw error;
|
||||
|
@ -40,7 +40,7 @@ export class AsanaTrigger implements INodeType {
|
||||
{
|
||||
name: 'default',
|
||||
httpMethod: 'POST',
|
||||
reponseMode: 'onReceived',
|
||||
responseMode: 'onReceived',
|
||||
path: 'webhook',
|
||||
},
|
||||
],
|
||||
|
@ -28,7 +28,7 @@ export class ChargebeeTrigger implements INodeType {
|
||||
{
|
||||
name: 'default',
|
||||
httpMethod: 'POST',
|
||||
reponseMode: 'onReceived',
|
||||
responseMode: 'onReceived',
|
||||
path: 'webhook',
|
||||
},
|
||||
],
|
||||
|
@ -40,7 +40,7 @@ export class GithubTrigger implements INodeType {
|
||||
{
|
||||
name: 'default',
|
||||
httpMethod: 'POST',
|
||||
reponseMode: 'onReceived',
|
||||
responseMode: 'onReceived',
|
||||
path: 'webhook',
|
||||
},
|
||||
],
|
||||
|
@ -69,7 +69,7 @@ export class PipedriveTrigger implements INodeType {
|
||||
{
|
||||
name: 'default',
|
||||
httpMethod: 'POST',
|
||||
reponseMode: 'onReceived',
|
||||
responseMode: 'onReceived',
|
||||
path: 'webhook',
|
||||
},
|
||||
],
|
||||
|
@ -41,13 +41,13 @@ export class TrelloTrigger implements INodeType {
|
||||
{
|
||||
name: 'setup',
|
||||
httpMethod: 'GET',
|
||||
reponseMode: 'onReceived',
|
||||
responseMode: 'onReceived',
|
||||
path: 'webhook',
|
||||
},
|
||||
{
|
||||
name: 'default',
|
||||
httpMethod: 'POST',
|
||||
reponseMode: 'onReceived',
|
||||
responseMode: 'onReceived',
|
||||
path: 'webhook',
|
||||
},
|
||||
],
|
||||
|
@ -72,8 +72,8 @@ export class Webhook implements INodeType {
|
||||
name: 'default',
|
||||
httpMethod: '={{$parameter["httpMethod"]}}',
|
||||
responseCode: '={{$parameter["responseCode"]}}',
|
||||
reponseMode: '={{$parameter["reponseMode"]}}',
|
||||
reponseData: '={{$parameter["reponseData"]}}',
|
||||
responseMode: '={{$parameter["responseMode"]}}',
|
||||
responseData: '={{$parameter["responseData"]}}',
|
||||
responseBinaryPropertyName: '={{$parameter["responseBinaryPropertyName"]}}',
|
||||
path: '={{$parameter["path"]}}',
|
||||
},
|
||||
@ -139,8 +139,8 @@ export class Webhook implements INodeType {
|
||||
description: 'The HTTP Response code to return',
|
||||
},
|
||||
{
|
||||
displayName: 'Reponse Mode',
|
||||
name: 'reponseMode',
|
||||
displayName: 'Response Mode',
|
||||
name: 'responseMode',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
@ -158,12 +158,12 @@ export class Webhook implements INodeType {
|
||||
description: 'When and how to respond to the webhook.',
|
||||
},
|
||||
{
|
||||
displayName: 'Reponse Data',
|
||||
name: 'reponseData',
|
||||
displayName: 'Response Data',
|
||||
name: 'responseData',
|
||||
type: 'options',
|
||||
displayOptions: {
|
||||
show: {
|
||||
reponseMode: [
|
||||
responseMode: [
|
||||
'lastNode',
|
||||
],
|
||||
},
|
||||
@ -196,7 +196,7 @@ export class Webhook implements INodeType {
|
||||
default: 'data',
|
||||
displayOptions: {
|
||||
show: {
|
||||
reponseData: [
|
||||
responseData: [
|
||||
'firstEntryBinary'
|
||||
],
|
||||
},
|
||||
|
@ -462,8 +462,8 @@ export interface IWebhookDescription {
|
||||
name: string;
|
||||
path: string;
|
||||
responseBinaryPropertyName?: string;
|
||||
reponseMode?: WebhookResponseMode | string;
|
||||
reponseData?: WebhookResponseData | string;
|
||||
responseMode?: WebhookResponseMode | string;
|
||||
responseData?: WebhookResponseData | string;
|
||||
}
|
||||
|
||||
export type WebhookHttpMethod = 'GET' | 'POST';
|
||||
|
@ -977,16 +977,16 @@ export class Workflow {
|
||||
if (mode === 'manual') {
|
||||
// In manual mode we do not just start the trigger function we also
|
||||
// want to be able to get informed as soon as the first data got emitted
|
||||
const triggerReponse = await nodeType.trigger!.call(triggerFunctions);
|
||||
const triggerResponse = await nodeType.trigger!.call(triggerFunctions);
|
||||
|
||||
// Add the manual trigger response which resolves when the first time data got emitted
|
||||
triggerReponse!.manualTriggerResponse = new Promise((resolve) => {
|
||||
triggerResponse!.manualTriggerResponse = new Promise((resolve) => {
|
||||
triggerFunctions.emit = ((resolve) => (data: INodeExecutionData[][]) => {
|
||||
resolve(data);
|
||||
})(resolve);
|
||||
});
|
||||
|
||||
return triggerReponse;
|
||||
return triggerResponse;
|
||||
} else {
|
||||
// In all other modes simply start the trigger
|
||||
return nodeType.trigger!.call(triggerFunctions);
|
||||
|
Loading…
Reference in New Issue
Block a user