2023-01-27 03:22:44 -08:00
import type { OptionsWithUri } from 'request' ;
2023-03-09 09:13:15 -08:00
import type {
IDataObject ,
IExecuteFunctions ,
ILoadOptionsFunctions ,
IOAuth2Options ,
} from 'n8n-workflow' ;
2020-05-11 16:56:27 -07:00
2023-07-10 06:03:21 -07:00
import { NodeOperationError , jsonParse } from 'n8n-workflow' ;
2020-07-25 10:58:38 -07:00
2023-06-16 07:26:35 -07:00
import get from 'lodash/get' ;
2020-03-05 15:25:18 -08:00
2022-08-17 08:50:24 -07:00
export async function slackApiRequest (
2023-08-16 06:52:41 -07:00
this : IExecuteFunctions | ILoadOptionsFunctions ,
2022-08-17 08:50:24 -07:00
method : string ,
resource : string ,
body : object = { } ,
query : object = { } ,
2023-02-03 08:04:37 -08:00
headers : { } | undefined = undefined ,
option : { } = { } ,
// tslint:disable-next-line:no-any
2022-08-17 08:50:24 -07:00
) : Promise < any > {
2020-03-05 15:25:18 -08:00
const authenticationMethod = this . getNodeParameter ( 'authentication' , 0 , 'accessToken' ) as string ;
2020-03-08 15:22:33 -07:00
let options : OptionsWithUri = {
2020-03-05 15:25:18 -08:00
method ,
2023-02-03 08:04:37 -08:00
headers : headers ? ? {
2020-10-22 06:46:03 -07:00
'Content-Type' : 'application/json; charset=utf-8' ,
2020-03-05 15:25:18 -08:00
} ,
body ,
qs : query ,
uri : ` https://slack.com/api ${ resource } ` ,
2020-10-22 06:46:03 -07:00
json : true ,
2020-03-05 15:25:18 -08:00
} ;
2020-03-08 15:22:33 -07:00
options = Object . assign ( { } , options , option ) ;
2020-03-05 15:25:18 -08:00
if ( Object . keys ( body ) . length === 0 ) {
delete options . body ;
}
if ( Object . keys ( query ) . length === 0 ) {
delete options . qs ;
}
2020-10-01 23:50:37 -07:00
2022-04-19 03:36:01 -07:00
const oAuth2Options : IOAuth2Options = {
tokenType : 'Bearer' ,
property : 'authed_user.access_token' ,
} ;
2020-07-25 10:58:38 -07:00
2023-02-03 08:04:37 -08:00
const credentialType = authenticationMethod === 'accessToken' ? 'slackApi' : 'slackOAuth2Api' ;
const response = await this . helpers . requestWithAuthentication . call (
this ,
credentialType ,
options ,
{
oauth2 : oAuth2Options ,
} ,
) ;
2021-11-03 17:55:04 -07:00
2023-02-03 08:04:37 -08:00
if ( response . ok === false ) {
if ( response . error === 'paid_teams_only' ) {
2022-08-17 08:50:24 -07:00
throw new NodeOperationError (
this . getNode ( ) ,
2023-02-03 08:04:37 -08:00
` Your current Slack plan does not include the resource ' ${
this . getNodeParameter ( 'resource' , 0 ) as string
} ' ` ,
{
description :
2023-02-16 02:45:03 -08:00
'Hint: Upgrade to a Slack plan that includes the functionality you want to use.' ,
2023-12-07 07:57:02 -08:00
level : 'warning' ,
2023-02-03 08:04:37 -08:00
} ,
) ;
} else if ( response . error === 'missing_scope' ) {
throw new NodeOperationError (
this . getNode ( ) ,
'Your Slack credential is missing required Oauth Scopes' ,
{
description : ` Add the following scope(s) to your Slack App: ${ response . needed } ` ,
2023-12-07 07:57:02 -08:00
level : 'warning' ,
2023-02-03 08:04:37 -08:00
} ,
2022-08-17 08:50:24 -07:00
) ;
2020-10-01 23:50:37 -07:00
}
2023-02-03 08:04:37 -08:00
throw new NodeOperationError (
this . getNode ( ) ,
'Slack error response: ' + JSON . stringify ( response . error ) ,
) ;
}
if ( response . ts !== undefined ) {
Object . assign ( response , { message_timestamp : response.ts } ) ;
delete response . ts ;
2020-03-05 15:25:18 -08:00
}
2023-02-03 08:04:37 -08:00
return response ;
2020-03-05 15:25:18 -08:00
}
2022-08-17 08:50:24 -07:00
export async function slackApiRequestAllItems (
this : IExecuteFunctions | ILoadOptionsFunctions ,
propertyName : string ,
method : string ,
endpoint : string ,
2023-02-03 08:04:37 -08:00
// tslint:disable-next-line:no-any
2022-08-17 08:50:24 -07:00
body : any = { } ,
query : IDataObject = { } ,
2023-02-03 08:04:37 -08:00
// tslint:disable-next-line:no-any
2022-08-17 08:50:24 -07:00
) : Promise < any > {
2020-03-05 15:25:18 -08:00
const returnData : IDataObject [ ] = [ ] ;
let responseData ;
2020-03-08 15:22:33 -07:00
query . page = 1 ;
2021-10-18 21:04:58 -07:00
//if the endpoint uses legacy pagination use count
//https://api.slack.com/docs/pagination#classic
if ( endpoint . includes ( 'files.list' ) ) {
query . count = 100 ;
} else {
2021-10-19 20:52:53 -07:00
query . limit = 100 ;
2021-10-18 21:04:58 -07:00
}
2020-03-05 15:25:18 -08:00
do {
2023-02-27 19:39:43 -08:00
responseData = await slackApiRequest . call ( this , method , endpoint , body as IDataObject , query ) ;
2023-02-23 07:16:05 -08:00
query . cursor = get ( responseData , 'response_metadata.next_cursor' ) ;
2020-03-08 15:22:33 -07:00
query . page ++ ;
2023-02-03 08:04:37 -08:00
returnData . push . apply (
returnData ,
2023-02-27 19:39:43 -08:00
( responseData [ propertyName ] . matches as IDataObject [ ] ) ? ? responseData [ propertyName ] ,
2023-02-03 08:04:37 -08:00
) ;
2020-03-05 15:25:18 -08:00
} while (
2022-12-02 12:54:28 -08:00
( responseData . response_metadata ? . next_cursor !== undefined &&
2020-12-13 01:47:52 -08:00
responseData . response_metadata . next_cursor !== '' &&
responseData . response_metadata . next_cursor !== null ) ||
2022-12-02 12:54:28 -08:00
( responseData . paging ? . pages !== undefined &&
2020-12-13 01:47:52 -08:00
responseData . paging . page !== undefined &&
2023-02-03 08:04:37 -08:00
responseData . paging . page < responseData . paging . pages ) ||
( responseData [ propertyName ] . paging ? . pages !== undefined &&
responseData [ propertyName ] . paging . page !== undefined &&
responseData [ propertyName ] . paging . page < responseData [ propertyName ] . paging . pages )
2020-03-05 15:25:18 -08:00
) ;
return returnData ;
}
2020-05-05 10:22:02 -07:00
2023-10-03 01:18:59 -07:00
export function getMessageContent (
this : IExecuteFunctions | ILoadOptionsFunctions ,
i : number ,
nodeVersion : number ,
instanceId? : string ,
) {
2023-07-10 06:03:21 -07:00
const includeLinkToWorkflow = this . getNodeParameter (
'otherOptions.includeLinkToWorkflow' ,
i ,
nodeVersion >= 2.1 ? true : false ,
) as IDataObject ;
const { id } = this . getWorkflow ( ) ;
2023-10-03 01:18:59 -07:00
const automatedMessage = ` _Automated with this < ${ this . getInstanceBaseUrl ( ) } workflow/ ${ id } ?utm_source=n8n-internal&utm_medium=powered_by&utm_campaign= ${ encodeURIComponent (
'n8n-nodes-base.slack' ,
) } $ { instanceId ? '_' + instanceId : '' } | n8n workflow > _ ` ;
2023-07-10 06:03:21 -07:00
const messageType = this . getNodeParameter ( 'messageType' , i ) as string ;
let content : IDataObject = { } ;
const text = this . getNodeParameter ( 'text' , i , '' ) as string ;
switch ( messageType ) {
case 'text' :
content = {
text : includeLinkToWorkflow ? ` ${ text } \ n ${ automatedMessage } ` : text ,
} ;
break ;
case 'block' :
content = jsonParse ( this . getNodeParameter ( 'blocksUi' , i ) as string ) ;
if ( includeLinkToWorkflow && Array . isArray ( content . blocks ) ) {
content . blocks . push ( {
type : 'section' ,
text : {
type : 'mrkdwn' ,
text : automatedMessage ,
} ,
} ) ;
}
if ( text ) {
content . text = text ;
}
break ;
case 'attachment' :
content = { attachments : this.getNodeParameter ( 'attachments' , i ) } as IDataObject ;
if ( includeLinkToWorkflow && Array . isArray ( content . attachments ) ) {
content . attachments . push ( {
text : automatedMessage ,
} ) ;
}
break ;
default :
throw new NodeOperationError (
this . getNode ( ) ,
` The message type " ${ messageType } " is not known! ` ,
) ;
}
return content ;
}
2023-02-03 08:04:37 -08:00
// tslint:disable-next-line:no-any
2022-08-17 08:50:24 -07:00
export function validateJSON ( json : string | undefined ) : any {
2020-05-05 10:22:02 -07:00
let result ;
try {
result = JSON . parse ( json ! ) ;
} catch ( exception ) {
result = undefined ;
}
return result ;
}