Skip to content

Commit

Permalink
Merge pull request #7 from vtexdocs/logs
Browse files Browse the repository at this point in the history
adding error logs
  • Loading branch information
PedroAntunesCosta authored Jul 17, 2024
2 parents b330d63 + 45b12ba commit 0380b01
Show file tree
Hide file tree
Showing 7 changed files with 125 additions and 32 deletions.
9 changes: 8 additions & 1 deletion manifest.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "docs-in-tickets",
"vendor": "vtexhelp",
"version": "1.0.3",
"version": "1.0.4",
"title": "Docs in Tickets",
"description": "Process information about documentation links sent in support tickets.",
"categories": [],
Expand All @@ -28,6 +28,13 @@
"path": "*"
}
},
{
"name": "outbound-access",
"attrs": {
"host": "hooks.slack.com",
"path": "*"
}
},
{
"name": "outbound-access",
"attrs": {
Expand Down
5 changes: 5 additions & 0 deletions node/clients/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { IOClients } from '@vtex/api'

import RedshiftClient from './redshift'
import ZendeskClient from './zendesk'
import SlackClient from './slack'

// Extend the default IOClients implementation with our own custom clients.
export class Clients extends IOClients {
Expand All @@ -12,4 +13,8 @@ export class Clients extends IOClients {
public get zendesk() {
return this.getOrSet('zendesk', ZendeskClient)
}

public get slack() {
return this.getOrSet('slack', SlackClient)
}
}
41 changes: 41 additions & 0 deletions node/clients/slack.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// sendLog sends a message to the slack channel #docs-in-tickets-logs.
// ref: https://api.slack.com/messaging/webhooks

import { ExternalClient } from '@vtex/api'
import type { IOContext, InstanceOptions } from '@vtex/api'

const url = 'https://hooks.slack.com/services/xxxxxxxxxx'
const requestHeaders = {
'Content-Type': 'application/json',
}

export default class SlackClient extends ExternalClient {
constructor(ctx: IOContext, options?: InstanceOptions) {
super('https://hooks.slack.com', ctx, {
...options,
retries: 2,
timeout: 2000,
headers: requestHeaders,
})
}

public async sendLog(log: string, type: string) {

const logTypeMap: { [key: string]: string} = {
info: ':ms_information_3d:',
warning: ':warning: *Warning*',
error: ':error: *Error*'
}
const typeMarker = logTypeMap[type] || ''

return this.http.post(
url,
{
text: `${typeMarker}\n${log}`
},
{
headers: requestHeaders,
}
)
}
}
11 changes: 6 additions & 5 deletions node/clients/zendesk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@

import { ExternalClient, IOContext, InstanceOptions } from '@vtex/api'

const username = 'xxxxxxxxxxxxxxxxx'
const token = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
// These are the real credentials
const username = 'xxxxxxxxxx'
const token = 'xxxxxxxxxx'
const authValue = btoa(`${username}/token:${token}`)

// Below are sandbox auth variables, just to facilitate debugging. Note that the format is different.
// const username = 'xxxxxxxxxxxxxxxxx'
// const token = 'xxxxxxxxxxxxxxxxx'
// Below are sandbox auth variables, just to facilitate debugging. Note that the authvalue format is different.
// const username = 'xxxxxxxxxx'
// const token = 'xxxxxxxxxx'
// const authValue = btoa(`${username}:${token}`)

const requestHeaders = {
Expand Down
18 changes: 18 additions & 0 deletions node/middlewares/errorLogs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Returning and logging errors

export async function returnError(
zendeskTicket: string,
status: number,
errorMessage: string,
ctx: Context
) {

const slack = ctx.clients.slack
slack.sendLog(`ticket: ${zendeskTicket}\n${errorMessage}`, 'error')

ctx.status = status
ctx.response.body = {
ticketId: zendeskTicket,
message: errorMessage
}
}
36 changes: 29 additions & 7 deletions node/middlewares/processTicket.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import { or } from 'ramda'

import type { MessageData } from '../clients/redshift'
import { returnError } from './errorLogs'

// Defining URLs that will be used to parse and process the comment data
// Substrings to look for and to exclude
Expand All @@ -24,22 +25,35 @@ export async function processTicket(
ctx: Context,
next: () => Promise<Record<string, unknown>>
) {
console.info('Running processTicket')
console.log('Running processTicket')

const requestBody = ctx.state.body
console.info(requestBody)
const zendeskTicket = requestBody.ticketId

const zendesk = ctx.clients.zendesk
const redshift = ctx.clients.redshift

let allCommentsWithUrls = []
let page = 1
interface Comment {
html_body: string,
id: number,
author_id: number,
created_at: string
}
let ticketComments: Array<Comment>
let nextPage: number

while (1==1) {
const zendeskData = await zendesk.getComments(zendeskTicket, page)
const ticketComments = zendeskData.comments
const nextPage = zendeskData.next_page

try {
const zendeskData = await zendesk.getComments(zendeskTicket, page)
ticketComments = zendeskData.comments
nextPage = zendeskData.next_page
} catch (error) {
returnError(zendeskTicket, 500, `Error trying to get ticket data from Zendesk >>> ${error}`, ctx)
return
}

// Iterate over comments
for (const comment of ticketComments) {
Expand Down Expand Up @@ -99,7 +113,13 @@ export async function processTicket(

allCommentsWithUrls.push(messageData)

await redshift.saveMessage(messageData)
try {
console.log('try redshift')
await redshift.saveMessage(messageData)
console.log(messageData.numberOfArticleUrls)
} catch (error) {
returnError(zendeskTicket, 500, `Error trying to save comment data to RedShift >>> ${error}`, ctx)
}
}
}

Expand All @@ -115,7 +135,9 @@ export async function processTicket(
message: 'ticket processed',
docsUrlsData: allCommentsWithUrls,
}
console.info(allCommentsWithUrls)

console.log(`comments processed: ${allCommentsWithUrls.length}`)
console.log('processTicket done')

await next()
}
37 changes: 18 additions & 19 deletions node/middlewares/verifyZendeskSignature.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@
// https://developer.zendesk.com/documentation/webhooks/verifying/#verifying-the-signature
import bodyParser from 'co-body'
import * as crypto from 'crypto'
import { returnError } from './errorLogs'

const ZENDESK_SECRET_KEY_PRODUCTION = "xxxxxxxxxxxxxxxxx"
const ZENDESK_SECRET_KEY_SANDBOX = "xxxxxxxxxxxxxxxxxx"
const ZENDESK_SECRET_KEY_PRODUCTION = "xxxxxxxxxx"
const ZENDESK_SECRET_KEY_SANDBOX = "xxxxxxxxxx"
const SIGNING_SECRET_ALGORITHM = "sha256"

export async function verifyZendeskSignature (
Expand All @@ -27,43 +28,41 @@ export async function verifyZendeskSignature (
return (comparison === 0)
}

const requestBody = await bodyParser(ctx.req, { returnRawBody: true })
ctx.state.body = requestBody.parsed
console.log(requestBody.parsed.ticketId)

if (requestBody.parsed.ticketId == undefined) {
returnError('undefined', 400, 'ticketId not found.', ctx)
}

const zendeskTicket = requestBody.parsed.ticketId

if (ctx.request.headers['x-zendesk-webhook-signature'] !== undefined) {
const requestBody = await bodyParser(ctx.req, { returnRawBody: true })
ctx.state.body = requestBody.parsed
console.info(ctx.state.body)

const requestSignature: string = ctx.request.headers["x-zendesk-webhook-signature"] as string
const requestSignatureTimestamp: string = ctx.request.headers["x-zendesk-webhook-signature-timestamp"] as string

if (isValidSignature(requestSignature, requestBody.raw, requestSignatureTimestamp, ZENDESK_SECRET_KEY_PRODUCTION)) {

console.info('Zendesk production signature verified successfully.')
// console.info('Zendesk production signature verified successfully.')
await next()

} else {

if (isValidSignature(requestSignature, requestBody.raw, requestSignatureTimestamp, ZENDESK_SECRET_KEY_SANDBOX)) {

console.info('Zendesk sandbox signature verified successfully.')
// console.info('Zendesk sandbox signature verified successfully.')
await next()

} else {

ctx.status = 400
ctx.response.body = {
message: 'Zendesk signature not valid.'
}
console.info('Zendesk signature not valid.')
returnError(zendeskTicket, 400, 'Zendesk signature not valid.', ctx)
return

}

}
} else {
ctx.status = 400
ctx.response.body = {
message: 'Zendesk signature not found.'
}
console.info('Zendesk signature not found')
returnError(zendeskTicket, 400, `Zendesk signature not found.`, ctx)
return
}
}

0 comments on commit 0380b01

Please sign in to comment.