diff --git a/netlify/functions/feedback-management.js b/netlify/functions/feedback-management.mts similarity index 82% rename from netlify/functions/feedback-management.js rename to netlify/functions/feedback-management.mts index 9bc88669932cec..051317beeafcd4 100644 --- a/netlify/functions/feedback-management.js +++ b/netlify/functions/feedback-management.mts @@ -1,7 +1,8 @@ -const querystring = require('node:querystring'); -const { App, AwsLambdaReceiver } = require('@slack/bolt'); -const { JWT } = require('google-auth-library'); -const { sheets } = require('@googleapis/sheets'); +import querystring from 'node:querystring'; +import { App, AwsLambdaReceiver, BlockAction, ButtonAction } from '@slack/bolt'; +import { JWT } from 'google-auth-library'; +import { sheets } from '@googleapis/sheets'; +import { Handler } from '@netlify/functions'; const X_FEEBACKS_CHANNEL_ID = 'C04U3R2V9UK'; const JOY_FEEBACKS_CHANNEL_ID = 'C050VE13HDL'; @@ -35,7 +36,7 @@ const spreadSheetsIds = { // Setup of the slack bot (taken from https://slack.dev/bolt-js/deployments/aws-lambda) const awsLambdaReceiver = new AwsLambdaReceiver({ - signingSecret: process.env.SLACK_SIGNING_SECRET, + signingSecret: process.env.SLACK_SIGNING_SECRET!, }); const app = new App({ @@ -45,27 +46,30 @@ const app = new App({ }); // Define slack actions to answer -app.action('delete_action', async ({ ack, body, client, logger }) => { +app.action>('delete_action', async ({ ack, body, client, logger }) => { try { await ack(); const { user: { username }, - channel: { id: channelId }, + channel, message, actions: [{ value }], } = body; + const channelId = channel?.id; + const { comment, currentLocationURL = '', commmentSectionURL = '' } = JSON.parse(value); const googleAuth = new JWT({ email: 'service-account-804@docs-feedbacks.iam.gserviceaccount.com', - key: process.env.G_SHEET_TOKEN.replace(/\\n/g, '\n'), + key: process.env.G_SHEET_TOKEN!.replace(/\\n/g, '\n'), scopes: ['https://www.googleapis.com/auth/spreadsheets'], }); const service = sheets({ version: 'v4', auth: googleAuth }); - await service.spreadsheets.values.append({ + // @ts-ignore + service.spreadsheets.values.append({ spreadsheetId: spreadSheetsIds.forLater, range: 'Deleted messages!A:D', valueInputOption: 'USER_ENTERED', @@ -73,9 +77,13 @@ app.action('delete_action', async ({ ack, body, client, logger }) => { values: [[username, comment, currentLocationURL, commmentSectionURL]], }, }); + + if (!channelId) { + throw Error('feedback-management: Unknonw channel Id'); + } await client.chat.delete({ channel: channelId, - ts: message.ts, + ts: message!.ts, as_user: true, token: process.env.SLACK_BOT_TOKEN, }); @@ -89,31 +97,37 @@ app.action('save_message', async ({ ack, body, client, logger }) => { await ack(); const { user: { username }, - channel: { id: channelId }, + channel, message, actions: [{ value }], - } = body; + } = body as BlockAction; + const channelId = channel?.id; const { comment, currentLocationURL = '', commmentSectionURL = '' } = JSON.parse(value); const googleAuth = new JWT({ email: 'service-account-804@docs-feedbacks.iam.gserviceaccount.com', - key: process.env.G_SHEET_TOKEN.replace(/\\n/g, '\n'), + key: process.env.G_SHEET_TOKEN!.replace(/\\n/g, '\n'), scopes: ['https://www.googleapis.com/auth/spreadsheets'], }); const service = sheets({ version: 'v4', auth: googleAuth }); - await service.spreadsheets.values.append({ + // @ts-ignore + service.spreadsheets.values.append({ spreadsheetId: spreadSheetsIds.forLater, range: 'Sheet1!A:D', valueInputOption: 'USER_ENTERED', - resource: { + updates: { values: [[username, comment, currentLocationURL, commmentSectionURL]], }, }); - await client.chat.postMessage({ + + if (!channelId) { + throw Error('feedback-management: Unknonw channel Id'); + } + client.chat.postMessage({ channel: channelId, - thread_ts: message.ts, + thread_ts: message!.ts, as_user: true, text: `Saved in `, }); @@ -122,11 +136,8 @@ app.action('save_message', async ({ ack, body, client, logger }) => { } }); -/** - * @param {object} event - * @param {object} context - */ -exports.handler = async (event, context, callback) => { +// eslint-disable-next-line import/prefer-default-export +export const handler: Handler = async (event, context, callback) => { if (event.httpMethod !== 'POST') { return { statusCode: 404 }; } @@ -227,8 +238,9 @@ from ${commmentSectionURL} unfurl_media: false, }); } else { - const handler = await awsLambdaReceiver.start(); - return handler(event, context, callback); + const awsHandler = await awsLambdaReceiver.start(); + // @ts-ignore + return awsHandler(event, context, callback); } } catch (error) { // eslint-disable-next-line no-console diff --git a/package.json b/package.json index a8bf59a37a6a95..25199be27cb63c 100644 --- a/package.json +++ b/package.json @@ -84,6 +84,7 @@ "dependencies": { "@googleapis/sheets": "^5.0.5", "@slack/bolt": "^3.17.1", + "@netlify/functions": "^2.6.0", "execa": "^8.0.1", "google-auth-library": "^9.6.3" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b13e0946fa8755..f4acf9102e22a8 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -34,6 +34,9 @@ importers: '@googleapis/sheets': specifier: ^5.0.5 version: 5.0.5 + '@netlify/functions': + specifier: ^2.6.0 + version: 2.6.0 '@slack/bolt': specifier: ^3.17.1 version: 3.17.1 @@ -5603,6 +5606,26 @@ packages: - '@types/react' dev: false + /@netlify/functions@2.6.0: + resolution: {integrity: sha512-vU20tij0fb4nRGACqb+5SQvKd50JYyTyEhQetCMHdakcJFzjLDivvRR16u1G2Oy4A7xNAtGJF1uz8reeOtTVcQ==} + engines: {node: '>=14.0.0'} + dependencies: + '@netlify/serverless-functions-api': 1.14.0 + dev: false + + /@netlify/node-cookies@0.1.0: + resolution: {integrity: sha512-OAs1xG+FfLX0LoRASpqzVntVV/RpYkgpI0VrUnw2u0Q1qiZUzcPffxRK8HF3gc4GjuhG5ahOEMJ9bswBiZPq0g==} + engines: {node: ^14.16.0 || >=16.0.0} + dev: false + + /@netlify/serverless-functions-api@1.14.0: + resolution: {integrity: sha512-HUNETLNvNiC2J+SB/YuRwJA9+agPrc0azSoWVk8H85GC+YE114hcS5JW+dstpKwVerp2xILE3vNWN7IMXP5Q5Q==} + engines: {node: ^14.18.0 || >=16.0.0} + dependencies: + '@netlify/node-cookies': 0.1.0 + urlpattern-polyfill: 8.0.2 + dev: false + /@next/env@13.5.1: resolution: {integrity: sha512-CIMWiOTyflFn/GFx33iYXkgLSQsMQZV4jB91qaj/TfxGaGOXxn8C1j72TaUSPIyN7ziS/AYG46kGmnvuk1oOpg==} @@ -20990,6 +21013,10 @@ packages: punycode: 1.3.2 querystring: 0.2.0 + /urlpattern-polyfill@8.0.2: + resolution: {integrity: sha512-Qp95D4TPJl1kC9SKigDcqgyM2VDVO4RiJc2d4qe5GrYm+zbIQCWWKAFaJNQ4BhdFeDGwBmAxqJBwWSJDb9T3BQ==} + dev: false + /use-count-up@3.0.1(react@18.2.0): resolution: {integrity: sha512-jlVsXJYje6jh+xwQaCEYrwHoB+nRyillNEmr21bhe9kw7tpRzyrSq9jQs9UOlo+8hCFkuOmjUihL3IjEK/piVg==} peerDependencies: