2021-10-20 20:35:51 -07:00
import { OptionsWithUri } from 'request' ;
2022-08-01 13:47:55 -07:00
import { IHookFunctions , IWebhookFunctions } from 'n8n-core' ;
2020-01-05 15:47:55 -08:00
import {
2021-10-20 20:35:51 -07:00
ICredentialsDecrypted ,
ICredentialTestFunctions ,
2020-01-06 10:33:22 -08:00
IDataObject ,
2020-01-05 15:47:55 -08:00
ILoadOptionsFunctions ,
2022-02-05 13:55:43 -08:00
INodeCredentialTestResult ,
2020-10-01 05:01:39 -07:00
INodePropertyOptions ,
2020-01-06 10:33:22 -08:00
INodeType ,
INodeTypeDescription ,
IWebhookResponseData ,
2020-01-05 15:47:55 -08:00
} from 'n8n-workflow' ;
2022-08-01 13:47:55 -07:00
import { bitbucketApiRequest , bitbucketApiRequestAllItems } from './GenericFunctions' ;
2020-01-05 15:47:55 -08:00
export class BitbucketTrigger implements INodeType {
description : INodeTypeDescription = {
displayName : 'Bitbucket Trigger' ,
2020-05-12 06:08:19 -07:00
name : 'bitbucketTrigger' ,
2021-06-12 12:00:37 -07:00
icon : 'file:bitbucket.svg' ,
2020-01-05 15:47:55 -08:00
group : [ 'trigger' ] ,
version : 1 ,
description : 'Handle Bitbucket events via webhooks' ,
defaults : {
name : 'Bitbucket Trigger' ,
} ,
inputs : [ ] ,
outputs : [ 'main' ] ,
credentials : [
{
name : 'bitbucketApi' ,
required : true ,
2021-10-20 20:35:51 -07:00
testedBy : 'bitbucketApiTest' ,
2020-10-22 06:46:03 -07:00
} ,
2020-01-05 15:47:55 -08:00
] ,
webhooks : [
{
name : 'default' ,
httpMethod : 'POST' ,
responseMode : 'onReceived' ,
path : 'webhook' ,
} ,
] ,
properties : [
{
displayName : 'Resource' ,
name : 'resource' ,
type : 'options' ,
2022-05-20 14:47:24 -07:00
noDataExpression : true ,
2020-01-05 15:47:55 -08:00
required : true ,
options : [
{
name : 'Repository' ,
value : 'repository' ,
} ,
2021-10-21 15:01:05 -07:00
{
name : 'Workspace' ,
value : 'workspace' ,
} ,
2020-01-05 15:47:55 -08:00
] ,
2021-10-21 15:01:05 -07:00
default : 'workspace' ,
2020-01-05 15:47:55 -08:00
} ,
{
2022-06-03 10:23:49 -07:00
displayName : 'Workspace Name or ID' ,
2021-10-21 15:01:05 -07:00
name : 'workspace' ,
2020-01-05 15:47:55 -08:00
type : 'options' ,
displayOptions : {
show : {
2022-08-01 13:47:55 -07:00
resource : [ 'workspace' , 'repository' ] ,
2020-10-22 06:46:03 -07:00
} ,
2020-01-05 15:47:55 -08:00
} ,
typeOptions : {
2021-10-21 15:01:05 -07:00
loadOptionsMethod : 'getWorkspaces' ,
2020-01-05 15:47:55 -08:00
} ,
required : true ,
default : '' ,
2022-08-01 13:47:55 -07:00
description :
'The repository of which to listen to the events. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.' ,
2020-01-05 15:47:55 -08:00
} ,
{
2022-06-20 07:54:01 -07:00
displayName : 'Event Names or IDs' ,
2020-01-05 15:47:55 -08:00
name : 'events' ,
type : 'multiOptions' ,
displayOptions : {
show : {
2022-08-01 13:47:55 -07:00
resource : [ 'workspace' ] ,
2020-10-22 06:46:03 -07:00
} ,
2020-01-05 15:47:55 -08:00
} ,
typeOptions : {
2021-10-21 15:01:05 -07:00
loadOptionsMethod : 'getWorkspaceEvents' ,
2020-01-05 15:47:55 -08:00
} ,
options : [ ] ,
required : true ,
default : [ ] ,
2022-08-01 13:47:55 -07:00
description :
'The events to listen to. Choose from the list, or specify IDs using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.' ,
2020-01-05 15:47:55 -08:00
} ,
{
2022-06-03 10:23:49 -07:00
displayName : 'Repository Name or ID' ,
2020-01-05 15:47:55 -08:00
name : 'repository' ,
type : 'options' ,
displayOptions : {
show : {
2022-08-01 13:47:55 -07:00
resource : [ 'repository' ] ,
2020-10-22 06:46:03 -07:00
} ,
2020-01-05 15:47:55 -08:00
} ,
typeOptions : {
loadOptionsMethod : 'getRepositories' ,
2022-08-01 13:47:55 -07:00
loadOptionsDependsOn : [ 'workspace' ] ,
2020-01-05 15:47:55 -08:00
} ,
required : true ,
default : '' ,
2022-08-01 13:47:55 -07:00
description :
'The repository of which to listen to the events. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.' ,
2020-01-05 15:47:55 -08:00
} ,
{
2022-06-20 07:54:01 -07:00
displayName : 'Event Names or IDs' ,
2020-01-05 15:47:55 -08:00
name : 'events' ,
type : 'multiOptions' ,
displayOptions : {
show : {
2022-08-01 13:47:55 -07:00
resource : [ 'repository' ] ,
2020-10-22 06:46:03 -07:00
} ,
2020-01-05 15:47:55 -08:00
} ,
typeOptions : {
loadOptionsMethod : 'getRepositoriesEvents' ,
} ,
options : [ ] ,
required : true ,
default : [ ] ,
2022-08-01 13:47:55 -07:00
description :
'The events to listen to. Choose from the list, or specify IDs using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.' ,
2020-01-05 15:47:55 -08:00
} ,
] ,
} ;
methods = {
2021-10-20 20:35:51 -07:00
credentialTest : {
2022-08-01 13:47:55 -07:00
async bitbucketApiTest (
this : ICredentialTestFunctions ,
credential : ICredentialsDecrypted ,
) : Promise < INodeCredentialTestResult > {
2021-10-20 20:35:51 -07:00
const credentials = credential . data ;
const options : OptionsWithUri = {
method : 'GET' ,
auth : {
user : credentials ! . username as string ,
password : credentials ! . appPassword as string ,
} ,
uri : 'https://api.bitbucket.org/2.0/user' ,
json : true ,
timeout : 5000 ,
} ;
try {
const response = await this . helpers . request ( options ) ;
if ( ! response . username ) {
return {
status : 'Error' ,
message : ` Token is not valid: ${ response . error } ` ,
} ;
}
} catch ( error ) {
return {
status : 'Error' ,
message : ` Settings are not valid: ${ error } ` ,
} ;
}
return {
status : 'OK' ,
message : 'Authentication successful!' ,
} ;
} ,
} ,
2020-01-05 15:47:55 -08:00
loadOptions : {
2021-10-21 15:01:05 -07:00
async getWorkspaceEvents ( this : ILoadOptionsFunctions ) : Promise < INodePropertyOptions [ ] > {
2020-01-05 15:47:55 -08:00
const returnData : INodePropertyOptions [ ] = [ ] ;
2022-08-01 13:47:55 -07:00
const events = await bitbucketApiRequestAllItems . call (
this ,
'values' ,
'GET' ,
'/hook_events/workspace' ,
) ;
2020-01-05 15:47:55 -08:00
for ( const event of events ) {
returnData . push ( {
2021-10-21 15:01:05 -07:00
name : event.event ,
value : event.event ,
description : event.description ,
2020-01-05 15:47:55 -08:00
} ) ;
}
return returnData ;
} ,
async getRepositoriesEvents ( this : ILoadOptionsFunctions ) : Promise < INodePropertyOptions [ ] > {
const returnData : INodePropertyOptions [ ] = [ ] ;
2022-08-01 13:47:55 -07:00
const events = await bitbucketApiRequestAllItems . call (
this ,
'values' ,
'GET' ,
'/hook_events/repository' ,
) ;
2020-01-05 15:47:55 -08:00
for ( const event of events ) {
returnData . push ( {
2021-10-21 15:01:05 -07:00
name : event.event ,
value : event.event ,
description : event.description ,
2020-01-05 15:47:55 -08:00
} ) ;
}
return returnData ;
} ,
async getRepositories ( this : ILoadOptionsFunctions ) : Promise < INodePropertyOptions [ ] > {
const returnData : INodePropertyOptions [ ] = [ ] ;
2021-10-21 15:01:05 -07:00
const workspace = this . getCurrentNodeParameter ( 'workspace' ) as string ;
2022-08-01 13:47:55 -07:00
const repositories = await bitbucketApiRequestAllItems . call (
this ,
'values' ,
'GET' ,
` /repositories/ ${ workspace } ` ,
) ;
2020-01-05 15:47:55 -08:00
for ( const repository of repositories ) {
returnData . push ( {
2021-10-21 15:01:05 -07:00
name : repository.slug ,
value : repository.slug ,
description : repository.description ,
2020-01-05 15:47:55 -08:00
} ) ;
}
return returnData ;
} ,
2021-10-21 15:01:05 -07:00
async getWorkspaces ( this : ILoadOptionsFunctions ) : Promise < INodePropertyOptions [ ] > {
2020-01-05 15:47:55 -08:00
const returnData : INodePropertyOptions [ ] = [ ] ;
2022-08-01 13:47:55 -07:00
const workspaces = await bitbucketApiRequestAllItems . call (
this ,
'values' ,
'GET' ,
` /workspaces ` ,
) ;
2021-10-21 15:01:05 -07:00
for ( const workspace of workspaces ) {
2020-01-05 15:47:55 -08:00
returnData . push ( {
2021-10-21 15:01:05 -07:00
name : workspace.name ,
value : workspace.slug ,
2020-01-05 15:47:55 -08:00
} ) ;
}
return returnData ;
} ,
} ,
} ;
2022-12-02 12:54:28 -08:00
2020-01-05 15:47:55 -08:00
// @ts-ignore
webhookMethods = {
default : {
async checkExists ( this : IHookFunctions ) : Promise < boolean > {
2020-01-06 10:33:22 -08:00
let endpoint = '' ;
2022-12-02 03:53:59 -08:00
const resource = this . getNodeParameter ( 'resource' , 0 ) ;
2021-10-21 15:01:05 -07:00
const workspace = this . getNodeParameter ( 'workspace' , 0 ) as string ;
const webhookUrl = this . getNodeWebhookUrl ( 'default' ) ;
2020-01-05 15:47:55 -08:00
const webhookData = this . getWorkflowStaticData ( 'node' ) ;
2021-10-21 15:01:05 -07:00
if ( resource === 'workspace' ) {
endpoint = ` /workspaces/ ${ workspace } /hooks ` ;
2020-01-05 15:47:55 -08:00
}
if ( resource === 'repository' ) {
const repository = this . getNodeParameter ( 'repository' , 0 ) as string ;
2021-10-21 15:01:05 -07:00
endpoint = ` /repositories/ ${ workspace } / ${ repository } /hooks ` ;
2020-01-05 15:47:55 -08:00
}
2021-10-21 15:01:05 -07:00
const { values : hooks } = await bitbucketApiRequest . call ( this , 'GET' , endpoint ) ;
for ( const hook of hooks ) {
if ( webhookUrl === hook . url && hook . active === true ) {
webhookData . webhookId = hook . uuid . replace ( '{' , '' ) . replace ( '}' , '' ) ;
return true ;
}
2020-01-05 15:47:55 -08:00
}
2021-10-21 15:01:05 -07:00
return false ;
2020-01-05 15:47:55 -08:00
} ,
async create ( this : IHookFunctions ) : Promise < boolean > {
2020-01-06 10:33:22 -08:00
let endpoint = '' ;
2020-01-05 15:47:55 -08:00
const webhookUrl = this . getNodeWebhookUrl ( 'default' ) ;
const webhookData = this . getWorkflowStaticData ( 'node' ) ;
const events = this . getNodeParameter ( 'events' ) as string [ ] ;
2022-12-02 03:53:59 -08:00
const resource = this . getNodeParameter ( 'resource' , 0 ) ;
2021-10-21 15:01:05 -07:00
const workspace = this . getNodeParameter ( 'workspace' , 0 ) as string ;
2020-01-05 15:47:55 -08:00
2021-10-21 15:01:05 -07:00
if ( resource === 'workspace' ) {
endpoint = ` /workspaces/ ${ workspace } /hooks ` ;
2020-01-05 15:47:55 -08:00
}
if ( resource === 'repository' ) {
const repository = this . getNodeParameter ( 'repository' , 0 ) as string ;
2021-10-21 15:01:05 -07:00
endpoint = ` /repositories/ ${ workspace } / ${ repository } /hooks ` ;
2020-01-05 15:47:55 -08:00
}
const body : IDataObject = {
2020-01-06 10:33:22 -08:00
description : 'n8n webhook' ,
2020-01-05 15:47:55 -08:00
url : webhookUrl ,
active : true ,
events ,
} ;
2022-12-02 12:54:28 -08:00
const responseData = await bitbucketApiRequest . call ( this , 'POST' , endpoint , body ) ;
2020-01-05 15:47:55 -08:00
webhookData . webhookId = responseData . uuid . replace ( '{' , '' ) . replace ( '}' , '' ) ;
return true ;
} ,
async delete ( this : IHookFunctions ) : Promise < boolean > {
2020-01-06 10:33:22 -08:00
let endpoint = '' ;
2020-01-05 15:47:55 -08:00
const webhookData = this . getWorkflowStaticData ( 'node' ) ;
2021-10-21 15:01:05 -07:00
const workspace = this . getNodeParameter ( 'workspace' , 0 ) as string ;
2022-12-02 03:53:59 -08:00
const resource = this . getNodeParameter ( 'resource' , 0 ) ;
2021-10-21 15:01:05 -07:00
if ( resource === 'workspace' ) {
endpoint = ` /workspaces/ ${ workspace } /hooks/ ${ webhookData . webhookId } ` ;
2020-01-05 15:47:55 -08:00
}
if ( resource === 'repository' ) {
const repository = this . getNodeParameter ( 'repository' , 0 ) as string ;
2021-10-21 15:01:05 -07:00
endpoint = ` /repositories/ ${ workspace } / ${ repository } /hooks/ ${ webhookData . webhookId } ` ;
2020-01-05 15:47:55 -08:00
}
try {
await bitbucketApiRequest . call ( this , 'DELETE' , endpoint ) ;
2021-10-21 15:01:05 -07:00
} catch ( error ) {
2020-01-05 15:47:55 -08:00
return false ;
}
delete webhookData . webhookId ;
return true ;
} ,
} ,
} ;
async webhook ( this : IWebhookFunctions ) : Promise < IWebhookResponseData > {
const req = this . getRequestObject ( ) ;
const headerData = this . getHeaderData ( ) as IDataObject ;
const webhookData = this . getWorkflowStaticData ( 'node' ) ;
if ( headerData [ 'x-hook-uuid' ] !== webhookData . webhookId ) {
return { } ;
}
return {
2022-08-01 13:47:55 -07:00
workflowData : [ this . helpers . returnJsonArray ( req . body ) ] ,
2020-01-05 15:47:55 -08:00
} ;
}
}