├── .gitignore ├── .prettierrc ├── package.json ├── slackbot └── index.js ├── serverless.yml ├── notion └── index.js └── handler.js /.gitignore: -------------------------------------------------------------------------------- 1 | # package directories 2 | node_modules 3 | jspm_packages 4 | 5 | # Serverless directories 6 | .serverless -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "arrowParens": "avoid", 3 | "tabWidth": 2, 4 | "semi": false, 5 | "trailingComma": "es5", 6 | "endOfLine": "lf", 7 | "singleQuote": false 8 | } 9 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "notion-feedback-bot", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "", 10 | "license": "ISC", 11 | "dependencies": { 12 | "@notionhq/client": "^0.2.3" 13 | }, 14 | "devDependencies": { 15 | "prettier": "^2.3.2", 16 | "serverless": "^2.52.0" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /slackbot/index.js: -------------------------------------------------------------------------------- 1 | exports.composeListOfSuggestions = function (suggestions) { 2 | const list = [ 3 | { 4 | type: "header", 5 | text: { 6 | type: "plain_text", 7 | text: "Listado de sugerencias recibidas 🚀", 8 | emoji: true, 9 | }, 10 | }, 11 | ] 12 | for (let suggestion of suggestions) { 13 | list.push({ 14 | type: "section", 15 | text: { 16 | type: "mrkdwn", 17 | text: suggestion.suggestion, 18 | }, 19 | }) 20 | list.push({ 21 | type: "divider", 22 | }) 23 | } 24 | const response = { 25 | response_type: "ephemeral", 26 | blocks: list, 27 | } 28 | return response 29 | } 30 | -------------------------------------------------------------------------------- /serverless.yml: -------------------------------------------------------------------------------- 1 | service: sls 2 | 3 | provider: 4 | name: aws 5 | runtime: nodejs14.x 6 | stage: prod 7 | region: eu-west-1 8 | memory: 128 9 | timeout: 2 10 | logRetentionInDays: 1 11 | # you can add statements to the Lambda function's IAM Role here 12 | # iamRoleStatements: 13 | # - Effect: "Allow" 14 | # Action: 15 | # - "s3:ListBucket" 16 | # Resource: { "Fn::Join" : ["", ["arn:aws:s3:::", { "Ref" : "ServerlessDeploymentBucket" } ] ] } 17 | # - Effect: "Allow" 18 | # Action: 19 | # - "s3:PutObject" 20 | # Resource: 21 | # Fn::Join: 22 | # - "" 23 | # - - "arn:aws:s3:::" 24 | # - "Ref" : "ServerlessDeploymentBucket" 25 | # - "/*" 26 | 27 | # you can define service wide environment variables here 28 | # environment: 29 | # variable1: value1 30 | 31 | # you can add packaging information here 32 | package: 33 | include: 34 | - handler.js 35 | - node_modules/** 36 | - notion/** 37 | - slackbot/** 38 | 39 | functions: 40 | suggestions: 41 | handler: handler.suggestion 42 | events: 43 | - http: 44 | path: suggestion 45 | method: post 46 | environment: 47 | NOTION_KEY: ${ssm:/notion-bettabot-key~true} 48 | NOTION_SUGGESTIONS_DB_ID: ${ssm:/notion-bettabot-suggestions-db~true} 49 | -------------------------------------------------------------------------------- /notion/index.js: -------------------------------------------------------------------------------- 1 | const { Client } = require("@notionhq/client") 2 | 3 | const notion = new Client({ auth: process.env.NOTION_KEY }) 4 | 5 | const notionDatabaseId = process.env.NOTION_SUGGESTIONS_DB_ID 6 | 7 | function getSuggestionValuesFromPage(page) { 8 | console.log(page.properties.Suggestion.title[0].text.content) 9 | return { 10 | id: page.id, 11 | suggestion: page.properties.Suggestion.title[0].text.content, 12 | } 13 | } 14 | 15 | exports.getSuggestionsFromNotionDatabase = async function () { 16 | const pages = [] 17 | let cursor = undefined 18 | let next_cursor = undefined 19 | do { 20 | const { results, next_cursor } = await notion.databases.query({ 21 | database_id: notionDatabaseId, 22 | start_cursor: cursor, 23 | }) 24 | pages.push(...results) 25 | cursor = next_cursor 26 | } while (next_cursor != undefined) 27 | console.log(`${pages.length} suggestions successfully fetched.`) 28 | return pages.map(page => getSuggestionValuesFromPage(page)) 29 | } 30 | 31 | exports.addSuggestionToNotionDatabase = async function (suggestionText) { 32 | await notion.pages.create({ 33 | parent: { database_id: notionDatabaseId }, 34 | properties: { 35 | Suggestion: { 36 | title: [{ type: "text", text: { content: suggestionText } }], 37 | }, 38 | }, 39 | }) 40 | console.log(`New suggestion saved`) 41 | } 42 | -------------------------------------------------------------------------------- /handler.js: -------------------------------------------------------------------------------- 1 | const qs = require("querystring") 2 | const { 3 | getSuggestionsFromNotionDatabase, 4 | addSuggestionToNotionDatabase, 5 | } = require("./notion") 6 | const { composeListOfSuggestions } = require("./slackbot") 7 | 8 | module.exports.suggestion = (event, context, callback) => { 9 | const query = qs.parse(event.body) 10 | console.log(query) 11 | const [option, ...suggestionText] = query.text.split(" ") 12 | console.log(option, suggestionText) 13 | switch (option) { 14 | case "list": 15 | handleListOfSuggestions(callback) 16 | break 17 | case "add": 18 | handleAddSuggestion(suggestionText.join(" "), callback) 19 | break 20 | default: 21 | handleDefault(event, callback) 22 | } 23 | } 24 | 25 | async function handleListOfSuggestions(callback) { 26 | const suggestions = await getSuggestionsFromNotionDatabase() 27 | const formattedSlackMessage = composeListOfSuggestions(suggestions) 28 | const response = { 29 | statusCode: 200, 30 | body: JSON.stringify(formattedSlackMessage), 31 | headers: { 32 | "Content-Type": "application/json", 33 | }, 34 | } 35 | 36 | callback(null, response) 37 | } 38 | 39 | async function handleAddSuggestion(suggestionText, callback) { 40 | await addSuggestionToNotionDatabase(suggestionText) 41 | const response = { 42 | statusCode: 200, 43 | body: "Gracias por la sugerencia! ❤️", 44 | } 45 | 46 | callback(null, response) 47 | } 48 | 49 | function handleDefault(event, callback) { 50 | const response = { 51 | statusCode: 200, 52 | body: "No te he entendido, prueba a usar (/suggestion list) o (/suggestion add [texto]) 🚀", 53 | } 54 | 55 | callback(null, response) 56 | } 57 | --------------------------------------------------------------------------------