├── .gitignore ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── buildspec.yml ├── lambdas ├── blog_resources │ └── DemoLayer │ │ ├── demoLayer.zip │ │ └── nodejs │ │ └── package.json ├── getFullTicket │ ├── getFullTicket.js │ └── package.json ├── getSentiment │ ├── getSentiment.js │ └── package.json ├── setPriority │ ├── package.json │ └── setPriority.js └── setTags │ ├── package.json │ └── setTags.js ├── package.yml ├── screenshots ├── stepFunctionExample2.png ├── zen_example_md.gif └── zendeskExample1.png ├── statemachine-example.asl.json ├── template-configuration.json └── template.yml /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/ 3 | getFullTicket/node_modules/ 4 | getSentiment/node_modules/ 5 | setPriority/node_modules/ 6 | setTags/node_modules/ 7 | /dist 8 | package.yml 9 | #sam 10 | 11 | # local env files 12 | .env.local 13 | .env.*.local 14 | .env 15 | 16 | # Log files 17 | npm-debug.log* 18 | yarn-debug.log* 19 | yarn-error.log* 20 | 21 | # Editor directories and files 22 | .idea 23 | .vscode 24 | *.suo 25 | *.ntvs* 26 | *.njsproj 27 | *.sln 28 | *.sw? -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | ## Code of Conduct 2 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). 3 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact 4 | opensource-codeofconduct@amazon.com with any additional questions or comments. 5 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing Guidelines 2 | 3 | Thank you for your interest in contributing to our project. Whether it's a bug report, new feature, correction, or additional 4 | documentation, we greatly value feedback and contributions from our community. 5 | 6 | Please read through this document before submitting any issues or pull requests to ensure we have all the necessary 7 | information to effectively respond to your bug report or contribution. 8 | 9 | 10 | ## Reporting Bugs/Feature Requests 11 | 12 | We welcome you to use the GitHub issue tracker to report bugs or suggest features. 13 | 14 | When filing an issue, please check existing open, or recently closed, issues to make sure somebody else hasn't already 15 | reported the issue. Please try to include as much information as you can. Details like these are incredibly useful: 16 | 17 | * A reproducible test case or series of steps 18 | * The version of our code being used 19 | * Any modifications you've made relevant to the bug 20 | * Anything unusual about your environment or deployment 21 | 22 | 23 | ## Contributing via Pull Requests 24 | Contributions via pull requests are much appreciated. Before sending us a pull request, please ensure that: 25 | 26 | 1. You are working against the latest source on the *master* branch. 27 | 2. You check existing open, and recently merged, pull requests to make sure someone else hasn't addressed the problem already. 28 | 3. You open an issue to discuss any significant work - we would hate for your time to be wasted. 29 | 30 | To send us a pull request, please: 31 | 32 | 1. Fork the repository. 33 | 2. Modify the source; please focus on the specific change you are contributing. If you also reformat all the code, it will be hard for us to focus on your change. 34 | 3. Ensure local tests pass. 35 | 4. Commit to your fork using clear commit messages. 36 | 5. Send us a pull request, answering any default questions in the pull request interface. 37 | 6. Pay attention to any automated CI failures reported in the pull request, and stay involved in the conversation. 38 | 39 | GitHub provides additional document on [forking a repository](https://help.github.com/articles/fork-a-repo/) and 40 | [creating a pull request](https://help.github.com/articles/creating-a-pull-request/). 41 | 42 | 43 | ## Finding contributions to work on 44 | Looking at the existing issues is a great way to find something to contribute on. As our projects, by default, use the default GitHub issue labels (enhancement/bug/duplicate/help wanted/invalid/question/wontfix), looking at any 'help wanted' issues is a great place to start. 45 | 46 | 47 | ## Code of Conduct 48 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). 49 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact 50 | opensource-codeofconduct@amazon.com with any additional questions or comments. 51 | 52 | 53 | ## Security issue notifications 54 | If you discover a potential security issue in this project we ask that you notify AWS/Amazon Security via our [vulnerability reporting page](http://aws.amazon.com/security/vulnerability-reporting/). Please do **not** create a public github issue. 55 | 56 | 57 | ## Licensing 58 | 59 | See the [LICENSE](LICENSE) file for our project's licensing. We will ask you to confirm the licensing of your contribution. 60 | 61 | We may ask you to sign a [Contributor License Agreement (CLA)](http://en.wikipedia.org/wiki/Contributor_License_Agreement) for larger changes. 62 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | 3 | MIT License 4 | Copyright [first edit year]-[latest edit year] Amazon.com, Inc. or its affiliates. All Rights Reserved. 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 7 | 8 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 9 | 10 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Automated ticket analysis and escalation 2 | 3 | ![Zendesk Ticket](screenshots/zen_example_md.gif) 4 | 5 | - [Automated ticket analysis and escalation](#automated-ticket-analysis-and-escalation) 6 | - [Intro](#intro) 7 | - [Requirements](#requirements) 8 | - [Installation Instructions](#installation-instructions) 9 | - [Parameter Details](#parameter-details) 10 | - [Escalation Wait time parameters](#escalation-wait-time-parameters) 11 | - [Zendesk Integration parameters](#zendesk-integration-parameters) 12 | - [How it works](#how-it-works) 13 | - [Set up](#set-up) 14 | - [Running the application](#running-the-application) 15 | - [Integrating Zendesk with Event Bridge](#integrating-zendesk-with-event-bridge) 16 | 17 | # Intro 18 | This application "listens" for a ticket creation event from Zendesk, analyses the ticket for negative sentiment, tags the ticket accordingly and invokes an automated workflow (Step function) that escalates the ticket's priority according to your SLA wait times. 19 | 20 | Important: this application uses various AWS services and there are costs associated with these services after the Free Tier usage - please see the [AWS pricing page](https://aws.amazon.com/pricing/) for details. This application also requires a Zendesk account. 21 | 22 | ```bash 23 | . 24 | ├── README.MD <-- This instructions file 25 | ├── screenshots <-- Screenshots 26 | └── lambdas <-- dir for the lambda functions 27 | │ └── getFullTicket <-- dir for the GettFullTicket Lambda Function 28 | │ │ └── getFullTicket.js <-- lambda function, uses Zendesk API to return Full ticket data 29 | │ │ └── package.json <-- NodeJS dependencies and scripts for this function 30 | │ └── getSentiment <-- dir for the getSentiment Lambda Function 31 | │ │ └── getSentiment.js <-- lambda function, invokes Comprehend:DetectSentiment 32 | │ │ └── package.json <-- NodeJS dependencies and scripts for this function 33 | │ └── setPriority <-- dir for the setPriority Lambda Function 34 | │ │ └── setPriority.js <-- lambda function, uses Zendesk api to update ticket priority 35 | │ │ └── package.json <-- NodeJS dependencies and scripts for this function 36 | │ └── setTags <-- dir for the setTags Lambda Function 37 | │ │ └── setTags.js <-- lambda function, uses Zendesk api to update ticket tags 38 | │ │ └── package.json <-- NodeJS dependencies and scripts for this function 39 | ├── template.yml <-- SAM template 40 | ├── buildspec.yml <-- CodeBuild template 41 | ├── LICENSE <-- MIT license file 42 | ``` 43 | 44 | ## Requirements 45 | 46 | - AWS CLI already configured with Administrator permission 47 | - Zendesk account with Event bridge integration enabled. 48 | 49 | ## Installation Instructions 50 | 51 | 1. [Create an AWS account](https://portal.aws.amazon.com/gp/aws/developer/registration/index.html) if you do not already have one and login. 52 | 2. [Create a Zendesk account](https://www.zendesk.com/register) and activate the Event Bridge integration via [this registration form](https://docs.google.com/forms/d/e/1FAIpQLSd_UXeXV5L7vGIyRY6gSL64pu2SS-CmquxNusex60QGR1d_TQ/viewform) 53 | 3. Go to the app's page on the [Serverless Application Repository](https://serverlessrepo.aws.amazon.com/applications/arn:aws:serverlessrepo:us-east-1:677501797858:applications~Automated-Support-Ticket-Moderator) and click "Deploy" 54 | 4. Provide the required app parameters (see parameter details below) and click "Deploy" 55 | 56 | ## Parameter Details 57 | ### Escalation Wait time parameters 58 | 59 | * `SLANormalWait`: provide a level 1 wait time for tickets that has priority status "normal" 60 | * `SLAHighWait`: provide a level 2 wait time for tickets that has priority status "High" 61 | * `SLAUrgentWait`: provide a level 3 wait time for tickets that has priority status "Urgent" 62 | 63 | ### Zendesk Integration parameters 64 | * `ZenDeskUsernameKey`: Your Zendesk agent username that will connect to the Zedesk API 65 | * `ZenDeskTokenKey`: Your Zendesk API Token 66 | * `ZenDeskDomainKey`: Your Unique Zendesk Domain name (excluding https:// and .com) 67 | for instructions on where to find these go to [Integrating Zendesk with Event Bridge](https://github.com/aws-samples/severless-ticket-sentiment-analysis-and-automated-escalation#integrating-zeddesk-with-event-bridge) 68 | 69 | ## How it works 70 | 71 | ![Step Functions Ticket](screenshots/stepFunctionExample2.png) 72 | 73 | - This application deploys 4 lambda functions that are orchestrated via a single step function. 74 | - The step function's execution is triggered when a ticket is created via an event bridge integration with Zendesk. 75 | - First the ticket's subject is a analysed for negative sentiment using AWS Comprehend. 76 | - If it is found to be negative, then an API call is made to Zendesk to retrieve the ticket's full metadata. 77 | - A tag `negative` is applied to the ticket. 78 | - The ticket now enters the escalation loop, if the ticket is not closed it's `priority` is escalated after each wait time is reached. 79 | - The step function exits when the ticket is closed, or the final escalation `urgent` wait time has passed. 80 | 81 | ## Set up 82 | 83 | - Deploy this serverless application with your Zendesk credentials and SLA wait times. 84 | - Create a Zendesk Event Bus with Event Bridge (instructions below). 85 | 86 | ## Running the application 87 | 88 | Once set up is complete, create a ticket in Zendesk and see it's tag and priority update over the course of the step function's life cycle. 89 | 90 | ## Integrating Zendesk with Event Bridge 91 | ![Zendesk Ticket](screenshots/zendeskExample1.png) 92 | - Follow these instructions to create a Zendesk Event bus. 93 | - [connect Zendesk to aws EventBridge](https://support.zendesk.com/hc/en-us/community/posts/360033236454-Sending-Zendesk-events-to-Amazon-EventBridge-) 94 | - Create a new Rule for the event bus. 95 | - Select Partner integration > Zendesk 96 | - Edit the event pattern with the JSON script below: 97 | ```javascript 98 | { 99 | "account": [ 100 | "{YourAWSAccountNumber}" 101 | ], 102 | "detail-type": [ 103 | "Support Ticket: Comment Created" 104 | ] 105 | } 106 | ``` 107 | - Select the Zendesk event bus. 108 | - Select Step Function State Machines as the target. 109 | - Select the new Sate machine. 110 | - Select `Create A new role for this resource`. 111 | - Make sure the rule is enabled. 112 | 113 | Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. 114 | SPDX-License-Identifier: MIT-0 115 | -------------------------------------------------------------------------------- /buildspec.yml: -------------------------------------------------------------------------------- 1 | version: 0.2 2 | 3 | phases: 4 | install: 5 | commands: 6 | # Install dependencies needed for running tests 7 | - npm install --prefix ./nodejs 8 | 9 | # Upgrade AWS CLI to the latest version 10 | - pip install --upgrade awscli 11 | pre_build: 12 | commands: 13 | # Discover and run unit tests in the 'tests' directory 14 | #- npm test 15 | build: 16 | commands: 17 | 18 | # Use AWS SAM to package the application by using AWS CloudFormation 19 | - aws cloudformation package --template template.yml --s3-bucket $S3_BUCKET --output-template template-export.yml 20 | - sam package --template-file template.yml --s3-bucket $S3_BUCKET --output-template-file package.yml 21 | 22 | post_build: 23 | commands: 24 | 25 | # Do not remove this statement. This command is required for AWS CodeStar projects. 26 | # Update the AWS Partition, AWS Region, account ID and project ID in the project ARN on template-configuration.json file so AWS CloudFormation can tag project resources. 27 | - sed -i.bak 's/\$PARTITION\$/'${PARTITION}'/g;s/\$AWS_REGION\$/'${AWS_REGION}'/g;s/\$ACCOUNT_ID\$/'${ACCOUNT_ID}'/g;s/\$PROJECT_ID\$/'${PROJECT_ID}'/g' template-configuration.json 28 | 29 | artifacts: 30 | type: zip 31 | files: 32 | - template-export.yml 33 | - template-configuration.json 34 | -------------------------------------------------------------------------------- /lambdas/blog_resources/DemoLayer/demoLayer.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/severless-ticket-sentiment-analysis-and-automated-escalation/9612933e94ff5cf338544887456d0b8d01b297a2/lambdas/blog_resources/DemoLayer/demoLayer.zip -------------------------------------------------------------------------------- /lambdas/blog_resources/DemoLayer/nodejs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nodejs", 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 | "axios": "^1.8.2" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /lambdas/getFullTicket/getFullTicket.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | MIT License 4 | Copyright [first edit year]-[latest edit year] Amazon.com, Inc. or its affiliates. All Rights Reserved. 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | */ 9 | const axios = require('axios') 10 | console.log('starting'); 11 | exports.handler = async (event) => { 12 | try { 13 | const res = await axios({ 14 | method:"get", 15 | url:`https://${process.env.ZenDeskDomain}.com/api/v2/tickets/${event.id}.json`, 16 | auth:{ 17 | username: `${process.env.ZenDeskUsername}/token`, 18 | password: process.env.ZenDeskPassword 19 | } 20 | }); 21 | 22 | return res.data.ticket; 23 | 24 | } catch (e) { 25 | console.log(e) 26 | return { 27 | statusCode: 400, 28 | body: JSON.stringify(e) 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /lambdas/getFullTicket/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ZendApplication", 3 | "version": "1.0.0", 4 | "description": "ZendApplicationfor NodeJS", 5 | "repository": "https://github.com/aws-samples/severless-ticket-sentiment-analysis-and-automated-escalation", 6 | "author": "SAM CLI", 7 | "license": "MIT", 8 | "dependencies": { 9 | "axios": "^1.8.2" 10 | }, 11 | "scripts": {}, 12 | "devDependencies": { 13 | "chai": "^5.2.0", 14 | "mocha": "^11.1.0" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /lambdas/getSentiment/getSentiment.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | MIT License 4 | Copyright [first edit year]-[latest edit year] Amazon.com, Inc. or its affiliates. All Rights Reserved. 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | */ 9 | var AWS = require('aws-sdk'); 10 | var comprehend = new AWS.Comprehend({apiVersion: '2017-11-27'}); 11 | 12 | exports.handler = async(event, context) => { 13 | const subject = event; 14 | var params = { LanguageCode: 'en', /* required */ 15 | Text: subject /* required */ 16 | } 17 | try { 18 | var data = await comprehend.detectSentiment(params).promise(); 19 | data.escalate=0 20 | } 21 | catch (err) { 22 | console.log(err); 23 | return err; 24 | } 25 | console.log(data) 26 | return data; 27 | }; -------------------------------------------------------------------------------- /lambdas/getSentiment/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ZendApplication", 3 | "version": "1.0.0", 4 | "description": "ZendApplicationfor NodeJS", 5 | "repository": "https://github.com/bls20AWS/severless-ticket-sentiment-analysys-and-automated-esculation", 6 | "author": "SAM CLI", 7 | "license": "MIT", 8 | "dependencies": { 9 | "aws-sdk": "^2.1692.0" 10 | }, 11 | "scripts": {}, 12 | "devDependencies": { 13 | "chai": "^5.2.0", 14 | "mocha": "^11.1.0" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /lambdas/setPriority/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ZendApplication", 3 | "version": "1.0.0", 4 | "description": "ZendApplicationfor NodeJS", 5 | "repository": "https://github.com/bls20AWS/severless-ticket-sentiment-analysys-and-automated-esculation", 6 | "author": "SAM CLI", 7 | "license": "MIT", 8 | "dependencies": { 9 | "axios": "^1.8.2" 10 | }, 11 | "scripts": {}, 12 | "devDependencies": { 13 | "chai": "^5.2.0", 14 | "mocha": "^11.1.0" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /lambdas/setPriority/setPriority.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | MIT License 4 | Copyright [first edit year]-[latest edit year] Amazon.com, Inc. or its affiliates. All Rights Reserved. 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | */ 9 | const axios = require('axios') 10 | exports.handler = async (event) => { 11 | 12 | var newEscalate = event.priority; 13 | switch(newEscalate){ 14 | case "": 15 | case null: 16 | newEscalate = 'normal'; 17 | break; 18 | case "normal": 19 | newEscalate = 'high'; 20 | break; 21 | case "high": 22 | newEscalate = 'urgent'; 23 | break; 24 | default: 25 | newEscalate = 'normal'; 26 | } 27 | 28 | try { 29 | const res = await axios({ 30 | method:"put", 31 | url:`https://${process.env.ZenDeskDomain}.com/api/v2/tickets/${event.id}.json`, 32 | auth:{ 33 | username: `${process.env.ZenDeskUsername}/token`, 34 | password: process.env.ZenDeskPassword 35 | }, 36 | data: { "ticket":{"priority":newEscalate,"type":"problem"}} 37 | }); 38 | return res.data.ticket; 39 | } catch (e) { 40 | console.log(e) 41 | return { 42 | statusCode: 400, 43 | body:'There was an error' 44 | } 45 | } 46 | } -------------------------------------------------------------------------------- /lambdas/setTags/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ZendApplication", 3 | "version": "1.0.0", 4 | "description": "ZendApplicationfor NodeJS", 5 | "repository": "https://github.com/bls20AWS/severless-ticket-sentiment-analysys-and-automated-esculation", 6 | "author": "SAM CLI", 7 | "license": "MIT", 8 | "dependencies": { 9 | "axios": "^1.8.2" 10 | }, 11 | "scripts": {}, 12 | "devDependencies": { 13 | "chai": "^5.2.0", 14 | "mocha": "^11.1.0" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /lambdas/setTags/setTags.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | MIT License 4 | Copyright [first edit year]-[latest edit year] Amazon.com, Inc. or its affiliates. All Rights Reserved. 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | */ 9 | const axios = require('axios') 10 | exports.handler = async (event) => { 11 | 12 | try { 13 | const response = await axios({ 14 | method:"post", 15 | url:`https://${process.env.ZenDeskDomain}.com/api/v2/tickets/${event.id}/tags.json`, 16 | auth:{ 17 | username: `${process.env.ZenDeskUsername}/token`, 18 | password: process.env.ZenDeskPassword 19 | }, 20 | data: { 21 | "tags": ['negative'] 22 | } 23 | }) 24 | const results = response.data 25 | return { 26 | statusCode: 200, 27 | body: results 28 | } 29 | } catch (err) { 30 | console.error(err) 31 | } 32 | } -------------------------------------------------------------------------------- /package.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09' 2 | Transform: 3 | - AWS::Serverless-2016-10-31 4 | Description: 'sam-app Sample SAM Template for sam-app 5 | 6 | ' 7 | Metadata: 8 | AWS::ServerlessRepo::Application: 9 | Name: Automated-Support-Ticket-Moderator 10 | Description: This application analyses Zendesk tickets for negative sentiment, 11 | tags them as 'negative' and applies a customizable escalation time frame. 12 | Author: Benjamin Smith 13 | SpdxLicenseId: MIT-0 14 | LicenseUrl: s3://severless-ticket-sentiment-analysis-and-automated-escalation/c4237cb282e57ea03a579d66a652cb3f 15 | ReadmeUrl: s3://severless-ticket-sentiment-analysis-and-automated-escalation/08c85fdab3af5ec4597a54ff7049f356 16 | Labels: 17 | - zendesk 18 | - moderation 19 | - sentiment 20 | - lambda 21 | - event Bridge 22 | - step functions 23 | HomePageUrl: https://github.com/aws-samples/severless-ticket-sentiment-analysys-and-automated-escalation 24 | SemanticVersion: 1.0.1 25 | SourceCodeUrl: https://github.com/aws-samples/severless-ticket-sentiment-analysys-and-automated-escalation/tree/1.0.0 26 | Parameters: 27 | Stage: 28 | Type: String 29 | Description: The name for a project pipeline stage, such as Staging or Prod, for 30 | which resources are provisioned and deployed. 31 | Default: '' 32 | ZenDeskUsernameKey: 33 | Description: Your agent username that will connect to the Zedesk API 34 | Type: String 35 | Default: ZenDeskUsername 36 | ZenDeskTokenKey: 37 | Description: Your API Token 38 | Type: String 39 | Default: ZenDeskToken 40 | ZenDeskDomainKey: 41 | Description: Your Unique Zendesk Domain name (excluding https:// and .com) 42 | Type: String 43 | Default: ZenDeskDomain 44 | SLAUrgentWait: 45 | Description: Urgent priority SLA wait time 46 | Type: String 47 | Default: 120 48 | SLAHighWait: 49 | Description: High priority SLA wait time 50 | Type: String 51 | Default: 120 52 | SLANormalWait: 53 | Description: Normal priority SLA wait time 54 | Type: String 55 | Default: 120 56 | EventSourceName: 57 | Description: The event source name generated by the Zendesk connector 58 | Type: String 59 | Default: '' 60 | Globals: 61 | Function: 62 | AutoPublishAlias: live 63 | Resources: 64 | ZenDeskDemoGetFullTicket: 65 | Type: AWS::Serverless::Function 66 | Properties: 67 | CodeUri: s3://severless-ticket-sentiment-analysis-and-automated-escalation/29a5110383ba75c318738b375cdae561 68 | Handler: getFullTicket.handler 69 | Runtime: nodejs14.x 70 | Role: 71 | Fn::GetAtt: 72 | - DemoLambdaExecutionRole 73 | - Arn 74 | Environment: 75 | Variables: 76 | ZenDeskUsername: 77 | Ref: ZenDeskUsernameKey 78 | ZenDeskPassword: 79 | Ref: ZenDeskTokenKey 80 | ZenDeskDomain: 81 | Ref: ZenDeskDomainKey 82 | ZenDeskDemoGetSentiment: 83 | Type: AWS::Serverless::Function 84 | Properties: 85 | CodeUri: s3://severless-ticket-sentiment-analysis-and-automated-escalation/6031eaec5573fb2adaa96645627435c9 86 | Handler: getSentiment.handler 87 | Runtime: nodejs14.x 88 | Role: 89 | Fn::GetAtt: 90 | - DemoLambdaExecutionRole 91 | - Arn 92 | Environment: null 93 | ZenDeskDemoSetTags: 94 | Type: AWS::Serverless::Function 95 | Properties: 96 | CodeUri: s3://severless-ticket-sentiment-analysis-and-automated-escalation/1989be8a590b85764342e96fae93d49a 97 | Handler: setTags.handler 98 | Runtime: nodejs14.x 99 | Role: 100 | Fn::GetAtt: 101 | - DemoLambdaExecutionRole 102 | - Arn 103 | Environment: 104 | Variables: 105 | ZenDeskUsername: 106 | Ref: ZenDeskUsernameKey 107 | ZenDeskPassword: 108 | Ref: ZenDeskTokenKey 109 | ZenDeskDomain: 110 | Ref: ZenDeskDomainKey 111 | ZenDeskDemoSetPriority: 112 | Type: AWS::Serverless::Function 113 | Properties: 114 | CodeUri: s3://severless-ticket-sentiment-analysis-and-automated-escalation/bbfa7302ac7ad61b71d97afb8adc867e 115 | Handler: setPriority.handler 116 | Runtime: nodejs14.x 117 | Role: 118 | Fn::GetAtt: 119 | - DemoLambdaExecutionRole 120 | - Arn 121 | Environment: 122 | Variables: 123 | ZenDeskUsername: 124 | Ref: ZenDeskUsernameKey 125 | ZenDeskPassword: 126 | Ref: ZenDeskTokenKey 127 | ZenDeskDomain: 128 | Ref: ZenDeskDomainKey 129 | ZendDemoStateMachine: 130 | Type: AWS::StepFunctions::StateMachine 131 | Properties: 132 | DefinitionString: 133 | Fn::Sub: "{\n \"Comment\": \"Understand the ticket sentiment, apply tags\ 134 | \ and check back when answered to ensure SLA's are met\",\n \"StartAt\"\ 135 | : \"FullTicketInfo\",\n \"States\": {\n\n \"FullTicketInfo\": {\n\ 136 | \ \"Type\" : \"Task\",\n \"Resource\": \"${ZenDeskDemoGetFullTicket.Arn}\"\ 137 | ,\n \"InputPath\": \"$.detail.ticket_event.ticket\",\n \"ResultPath\"\ 138 | : \"$\",\n \"Next\": \"GetSentiment\"\n },\n\n \"GetSentiment\"\ 139 | : {\n \"Type\": \"Task\",\n \"Resource\": \"${ZenDeskDemoGetSentiment.Arn}\"\ 140 | ,\n \"InputPath\": \"$.raw_subject\",\n \"ResultPath\": \"$.sentiment\"\ 141 | ,\n \"OutputPath\": \"$\",\n \"Next\": \"isNegative\"\n \ 142 | \ },\n\n \"isNegative\": {\n \"Type\" : \"Choice\",\n \"\ 143 | Choices\": [\n {\n \"Variable\": \"$.sentiment.Sentiment\"\ 144 | ,\n \"StringEquals\": \"NEGATIVE\",\n \"Next\": \"setTags\"\ 145 | \n }\n ],\n \"Default\": \"ClosedOrNotNegative\"\n \ 146 | \ },\n \n \n \n \"setTags\": {\n \"Type\" : \"Task\"\ 147 | ,\n \"Resource\": \"${ZenDeskDemoSetTags.Arn}\",\n \"ResultPath\"\ 148 | : \"$.tags\",\n \"OutputPath\": \"$\",\n \"Next\": \"isClosed\"\ 149 | \n },\n \n \n \"GetSLAWaitTime\": {\n \"Type\" : \"Choice\"\ 150 | ,\n \"Choices\": [\n {\n \"Variable\": \"$.priority\"\ 151 | ,\n \"StringEquals\": \"normal\",\n \"Next\": \"SLAHighWait\"\ 152 | \n },\n {\n \"Variable\": \"$.priority\",\n \ 153 | \ \"StringEquals\": \"high\",\n \"Next\": \"SLAUrgentWait\"\ 154 | \n },\n {\n \"Variable\": \"$.priority\",\n \ 155 | \ \"StringEquals\": \"urgent\",\n \"Next\": \"FinalEscalationState\"\ 156 | \n }\n ],\n \"Default\": \"SLANormalWait\"\n \ 157 | \ \n },\n \n \n \"FinalEscalationState\": {\n \ 158 | \ \"Comment\" : \"Ticket cannot be escalated further\",\n \"\ 159 | Type\": \"Succeed\"\n },\n \n \"EscalatePriority\": {\n \ 160 | \ \"Type\" : \"Task\",\n \"Resource\": \"${ZenDeskDemoSetPriority.Arn}\"\ 161 | ,\n \"InputPath\": \"$\",\n \"ResultPath\": \"$\",\n \ 162 | \ \"Next\": \"isClosed\"\n },\n\n \"SLANormalWait\": {\n \ 163 | \ \"Type\": \"Wait\",\n \"Seconds\": ${SLANormalWait},\n\ 164 | \ \"Next\": \"EscalatePriority\"\n },\n \n \"\ 165 | SLAHighWait\": {\n \"Type\": \"Wait\",\n \"Seconds\": ${SLAHighWait},\n\ 166 | \ \"Next\": \"EscalatePriority\"\n },\n \n \n\ 167 | \ \"SLAUrgentWait\": {\n \"Type\": \"Wait\",\n \"\ 168 | Seconds\":${SLAUrgentWait},\n \"Next\": \"EscalatePriority\"\n \ 169 | \ },\n\n \"isClosed\": {\n \"Type\" : \"Choice\",\n \ 170 | \ \"Choices\": [\n {\n \"Variable\": \"$.status\",\n\ 171 | \ \"StringEquals\": \"open\",\n \"Next\": \"GetSLAWaitTime\"\ 172 | \n }\n ],\n \"Default\": \"ClosedOrNotNegative\"\n \ 173 | \ },\n \n \"ClosedOrNotNegative\": {\n \"Type\": \"Pass\"\ 174 | ,\n \"Result\": {\n \"x-datum\": 1,\n \"y-datum\"\ 175 | : 1\n },\n \"ResultPath\": \"$.coords\",\n \"End\"\ 176 | : true\n }\n \n }\n }\n" 177 | RoleArn: 178 | Fn::GetAtt: 179 | - DemoStatesExecutionRole 180 | - Arn 181 | DemoLambdaExecutionRole: 182 | Description: Creating service role in IAM for AWS Lambda 183 | Type: AWS::IAM::Role 184 | Properties: 185 | RoleName: 186 | Fn::Sub: CodeStar-Execution${Stage} 187 | AssumeRolePolicyDocument: 188 | Statement: 189 | - Effect: Allow 190 | Principal: 191 | Service: 192 | - lambda.amazonaws.com 193 | Action: sts:AssumeRole 194 | Path: / 195 | ManagedPolicyArns: 196 | - Fn::Sub: arn:${AWS::Partition}:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole 197 | - Fn::Sub: arn:${AWS::Partition}:iam::aws:policy/ComprehendFullAccess 198 | DemoStatesExecutionRole: 199 | Type: AWS::IAM::Role 200 | Properties: 201 | AssumeRolePolicyDocument: 202 | Version: '2012-10-17' 203 | Statement: 204 | - Effect: Allow 205 | Principal: 206 | Service: 207 | - Fn::Sub: states.${AWS::Region}.amazonaws.com 208 | Action: sts:AssumeRole 209 | Path: / 210 | Policies: 211 | - PolicyName: StatesExecutionPolicy 212 | PolicyDocument: 213 | Version: '2012-10-17' 214 | Statement: 215 | - Effect: Allow 216 | Action: 217 | - lambda:InvokeFunction 218 | - comprehend:DetectSentiment 219 | Resource: '*' 220 | MyEventsRule: 221 | Type: AWS::Events::Rule 222 | Properties: 223 | Description: Events Rule with StepFunctionParams 224 | EventBusName: 225 | Ref: EventSourceName 226 | EventPattern: 227 | account: 228 | - Ref: AWS::AccountId 229 | detail-type: 230 | - 'Support Ticket: Comment Created' 231 | Targets: 232 | - Arn: 233 | Fn::GetAtt: 234 | - ZendDemoStateMachine 235 | - Arn 236 | RoleArn: 237 | Fn::GetAtt: 238 | - DemoStatesExecutionRole 239 | - Arn 240 | Id: NewTicketSFN 241 | DependsOn: 242 | - ZendDemoStateMachine 243 | - DemoStatesExecutionRole 244 | -------------------------------------------------------------------------------- /screenshots/stepFunctionExample2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/severless-ticket-sentiment-analysis-and-automated-escalation/9612933e94ff5cf338544887456d0b8d01b297a2/screenshots/stepFunctionExample2.png -------------------------------------------------------------------------------- /screenshots/zen_example_md.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/severless-ticket-sentiment-analysis-and-automated-escalation/9612933e94ff5cf338544887456d0b8d01b297a2/screenshots/zen_example_md.gif -------------------------------------------------------------------------------- /screenshots/zendeskExample1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/severless-ticket-sentiment-analysis-and-automated-escalation/9612933e94ff5cf338544887456d0b8d01b297a2/screenshots/zendeskExample1.png -------------------------------------------------------------------------------- /statemachine-example.asl.json: -------------------------------------------------------------------------------- 1 | { 2 | "Comment": "Understand the ticket sentiment, apply tags and check back when answered to ensure SLA's are met", 3 | "StartAt": "FullTicketInfo", 4 | "States": { 5 | "FullTicketInfo": { 6 | "Type" : "Task", 7 | "Resource": "${ZenDeskDemoGetFullTicket.Arn}", 8 | "InputPath": "$.detail.ticket_event.ticket", 9 | "ResultPath": "$", 10 | "Next": "GetSentiment" 11 | }, 12 | "GetSentiment": { 13 | "Type": "Task", 14 | "Resource": "${ZenDeskDemoGetSentiment.Arn}", 15 | "InputPath": "$.raw_subject", 16 | "ResultPath": "$.sentiment", 17 | "OutputPath": "$", 18 | "Next": "isNegative" 19 | }, 20 | "isNegative": { 21 | "Type" : "Choice", 22 | "Choices": [ 23 | { 24 | "Variable": "$.sentiment.Sentiment", 25 | "StringEquals": "NEGATIVE", 26 | "Next": "setTags" 27 | } 28 | ], 29 | "Default": "ClosedOrNotNegative" 30 | }, 31 | 32 | 33 | 34 | "setTags": { 35 | "Type" : "Task", 36 | "Resource": "${ZenDeskDemoSetTags.Arn}", 37 | "ResultPath": "$.tags", 38 | "OutputPath": "$", 39 | "Next": "isClosed" 40 | }, 41 | 42 | 43 | "GetSLAWaitTime": { 44 | "Type" : "Choice", 45 | "Choices": [ 46 | { 47 | "Variable": "$.priority", 48 | "StringEquals": "normal", 49 | "Next": "SLAHighWait" 50 | }, 51 | { 52 | "Variable": "$.priority", 53 | "StringEquals": "high", 54 | "Next": "SLAUrgentWait" 55 | }, 56 | { 57 | "Variable": "$.priority", 58 | "StringEquals": "urgent", 59 | "Next": "FinalEscalationState" 60 | } 61 | ], 62 | "Default": "SLANormalWait" 63 | 64 | }, 65 | 66 | 67 | "FinalEscalationState": { 68 | "Comment" : "Ticket cannot be escalated further", 69 | "Type": "Succeed" 70 | }, 71 | 72 | "EscalatePriority": { 73 | "Type" : "Task", 74 | "Resource": "${ZenDeskDemoSetPriority.Arn}", 75 | "InputPath": "$", 76 | "ResultPath": "$", 77 | "Next": "isClosed" 78 | }, 79 | "SLANormalWait": { 80 | "Type": "Wait", 81 | "Seconds": ${SLANormalWait}, 82 | "Next": "EscalatePriority" 83 | }, 84 | 85 | "SLAHighWait": { 86 | "Type": "Wait", 87 | "Seconds": ${SLAHighWait}, 88 | "Next": "EscalatePriority" 89 | }, 90 | 91 | 92 | "SLAUrgentWait": { 93 | "Type": "Wait", 94 | "Seconds":${SLAUrgentWait}, 95 | "Next": "EscalatePriority" 96 | }, 97 | "isClosed": { 98 | "Type" : "Choice", 99 | "Choices": [ 100 | { 101 | "Variable": "$.status", 102 | "StringEquals": "open", 103 | "Next": "GetSLAWaitTime" 104 | } 105 | ], 106 | "Default": "ClosedOrNotNegative" 107 | }, 108 | 109 | "ClosedOrNotNegative": { 110 | "Type": "Pass", 111 | "Result": { 112 | "x-datum": 1, 113 | "y-datum": 1 114 | }, 115 | "ResultPath": "$.coords", 116 | "End": true 117 | } 118 | 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /template-configuration.json: -------------------------------------------------------------------------------- 1 | { 2 | "Tags": 3 | { 4 | "awscodestar:projectArn":"arn:$PARTITION$:codestar:$AWS_REGION$:$ACCOUNT_ID$:project/$PROJECT_ID$" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /template.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09' 2 | Transform: 3 | - AWS::Serverless-2016-10-31 4 | Description: > 5 | sam-app 6 | Sample SAM Template for sam-app 7 | 8 | Metadata: 9 | AWS::ServerlessRepo::Application: 10 | Name: Automated-Support-Ticket-Moderator 11 | Description: This application analyses Zendesk tickets for negative sentiment, tags them as 'negative' and applies a customizable escalation time frame. 12 | Author: Benjamin Smith 13 | SpdxLicenseId: MIT-0 14 | LicenseUrl: LICENSE 15 | ReadmeUrl: README.md 16 | Labels: ['zendesk', 'moderation', 'sentiment', 'lambda','event Bridge','step functions'] 17 | HomePageUrl: https://github.com/aws-samples/severless-ticket-sentiment-analysys-and-automated-escalation 18 | SemanticVersion: 1.0.1 19 | SourceCodeUrl: https://github.com/aws-samples/severless-ticket-sentiment-analysys-and-automated-escalation/tree/1.0.0 20 | 21 | 22 | ########################################################################## 23 | # Code Star Params # 24 | ########################################################################## 25 | Parameters: 26 | # ProjectId: 27 | # Type: String 28 | # Description: AWS CodeStar projectID used to associate new resources to team members 29 | # CodeDeployRole: 30 | # Type: String 31 | # Description: IAM role to allow AWS CodeDeploy to manage deployment of AWS Lambda functions 32 | Stage: 33 | Type: String 34 | Description: The name for a project pipeline stage, such as Staging or Prod, for which resources are provisioned and deployed. 35 | Default: '' 36 | ########################################################################## 37 | # Lambda Environment Params: Zendesk Integration # 38 | ########################################################################## 39 | ZenDeskUsernameKey: 40 | Description: Your agent username that will connect to the Zedesk API 41 | Type: String 42 | Default: ZenDeskUsername 43 | ZenDeskTokenKey: 44 | Description: Your API Token 45 | Type: String 46 | Default: ZenDeskToken 47 | ZenDeskDomainKey: 48 | Description: Your Unique Zendesk Domain name (excluding https:// and .com) 49 | Type: String 50 | Default: ZenDeskDomain 51 | ########################################################################## 52 | # Lambda Environment Params : Escalation times # 53 | ########################################################################## 54 | SLAUrgentWait: 55 | Description: Urgent priority SLA wait time 56 | Type: String 57 | Default: 120 58 | SLAHighWait: 59 | Description: High priority SLA wait time 60 | Type: String 61 | Default: 120 62 | SLANormalWait: 63 | Description: Normal priority SLA wait time 64 | Type: String 65 | Default: 120 66 | ########################################################################## 67 | # Event Bridge Params : source name and acct ID # 68 | ########################################################################## 69 | EventSourceName: 70 | Description: The event source name generated by the Zendesk connector 71 | Type: String 72 | Default: '' 73 | 74 | 75 | 76 | Globals: 77 | Function: 78 | AutoPublishAlias: live 79 | Resources: 80 | ########################################################################## 81 | # Lambda Functions # 82 | ########################################################################## 83 | ZenDeskDemoGetFullTicket: 84 | Type: AWS::Serverless::Function # Function Resource: 85 | Properties: 86 | CodeUri: lambdas/getFullTicket 87 | Handler: getFullTicket.handler 88 | Runtime: nodejs14.x 89 | Role: 90 | Fn::GetAtt: 91 | - DemoLambdaExecutionRole 92 | - Arn 93 | Environment: # More info about Env Vars: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#environment-object 94 | Variables: 95 | ZenDeskUsername: !Ref ZenDeskUsernameKey 96 | ZenDeskPassword: !Ref ZenDeskTokenKey 97 | ZenDeskDomain: !Ref ZenDeskDomainKey 98 | ZenDeskDemoGetSentiment: 99 | Type: AWS::Serverless::Function # Function Resource: 100 | Properties: 101 | CodeUri: lambdas/getSentiment 102 | Handler: getSentiment.handler 103 | Runtime: nodejs14.x 104 | Role: 105 | Fn::GetAtt: 106 | - DemoLambdaExecutionRole 107 | - Arn 108 | Environment: # More info about Env Vars: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#environment-object 109 | ZenDeskDemoSetTags: 110 | Type: AWS::Serverless::Function # Function Resource: 111 | Properties: 112 | CodeUri: lambdas/setTags 113 | Handler: setTags.handler 114 | Runtime: nodejs14.x 115 | Role: 116 | Fn::GetAtt: 117 | - DemoLambdaExecutionRole 118 | - Arn 119 | Environment: # More info about Env Vars: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#environment-object 120 | Variables: 121 | ZenDeskUsername: !Ref ZenDeskUsernameKey 122 | ZenDeskPassword: !Ref ZenDeskTokenKey 123 | ZenDeskDomain: !Ref ZenDeskDomainKey 124 | ZenDeskDemoSetPriority: 125 | Type: AWS::Serverless::Function # Function Resource: 126 | Properties: 127 | CodeUri: lambdas/setPriority 128 | Handler: setPriority.handler 129 | Runtime: nodejs14.x 130 | Role: 131 | Fn::GetAtt: 132 | - DemoLambdaExecutionRole 133 | - Arn 134 | Environment: # More info about Env Vars: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#environment-object 135 | Variables: 136 | ZenDeskUsername: !Ref ZenDeskUsernameKey 137 | ZenDeskPassword: !Ref ZenDeskTokenKey 138 | ZenDeskDomain: !Ref ZenDeskDomainKey 139 | ########################################################################## 140 | # STEP FUNCTION # 141 | ########################################################################## 142 | ZendDemoStateMachine: 143 | Type: "AWS::StepFunctions::StateMachine" 144 | Properties: 145 | DefinitionString: !Sub | 146 | { 147 | "Comment": "Understand the ticket sentiment, apply tags and check back when answered to ensure SLA's are met", 148 | "StartAt": "FullTicketInfo", 149 | "States": { 150 | 151 | "FullTicketInfo": { 152 | "Type" : "Task", 153 | "Resource": "${ZenDeskDemoGetFullTicket.Arn}", 154 | "InputPath": "$.detail.ticket_event.ticket", 155 | "ResultPath": "$", 156 | "Next": "GetSentiment" 157 | }, 158 | 159 | "GetSentiment": { 160 | "Type": "Task", 161 | "Resource": "${ZenDeskDemoGetSentiment.Arn}", 162 | "InputPath": "$.raw_subject", 163 | "ResultPath": "$.sentiment", 164 | "OutputPath": "$", 165 | "Next": "isNegative" 166 | }, 167 | 168 | "isNegative": { 169 | "Type" : "Choice", 170 | "Choices": [ 171 | { 172 | "Variable": "$.sentiment.Sentiment", 173 | "StringEquals": "NEGATIVE", 174 | "Next": "setTags" 175 | } 176 | ], 177 | "Default": "ClosedOrNotNegative" 178 | }, 179 | 180 | 181 | 182 | "setTags": { 183 | "Type" : "Task", 184 | "Resource": "${ZenDeskDemoSetTags.Arn}", 185 | "ResultPath": "$.tags", 186 | "OutputPath": "$", 187 | "Next": "isClosed" 188 | }, 189 | 190 | 191 | "GetSLAWaitTime": { 192 | "Type" : "Choice", 193 | "Choices": [ 194 | { 195 | "Variable": "$.priority", 196 | "StringEquals": "normal", 197 | "Next": "SLAHighWait" 198 | }, 199 | { 200 | "Variable": "$.priority", 201 | "StringEquals": "high", 202 | "Next": "SLAUrgentWait" 203 | }, 204 | { 205 | "Variable": "$.priority", 206 | "StringEquals": "urgent", 207 | "Next": "FinalEscalationState" 208 | } 209 | ], 210 | "Default": "SLANormalWait" 211 | 212 | }, 213 | 214 | 215 | "FinalEscalationState": { 216 | "Comment" : "Ticket cannot be escalated further", 217 | "Type": "Succeed" 218 | }, 219 | 220 | "EscalatePriority": { 221 | "Type" : "Task", 222 | "Resource": "${ZenDeskDemoSetPriority.Arn}", 223 | "InputPath": "$", 224 | "ResultPath": "$", 225 | "Next": "isClosed" 226 | }, 227 | 228 | "SLANormalWait": { 229 | "Type": "Wait", 230 | "Seconds": ${SLANormalWait}, 231 | "Next": "EscalatePriority" 232 | }, 233 | 234 | "SLAHighWait": { 235 | "Type": "Wait", 236 | "Seconds": ${SLAHighWait}, 237 | "Next": "EscalatePriority" 238 | }, 239 | 240 | 241 | "SLAUrgentWait": { 242 | "Type": "Wait", 243 | "Seconds":${SLAUrgentWait}, 244 | "Next": "EscalatePriority" 245 | }, 246 | 247 | "isClosed": { 248 | "Type" : "Choice", 249 | "Choices": [ 250 | { 251 | "Variable": "$.status", 252 | "StringEquals": "open", 253 | "Next": "GetSLAWaitTime" 254 | } 255 | ], 256 | "Default": "ClosedOrNotNegative" 257 | }, 258 | 259 | "ClosedOrNotNegative": { 260 | "Type": "Pass", 261 | "Result": { 262 | "x-datum": 1, 263 | "y-datum": 1 264 | }, 265 | "ResultPath": "$.coords", 266 | "End": true 267 | } 268 | 269 | } 270 | } 271 | RoleArn: !GetAtt [ DemoStatesExecutionRole, Arn ] 272 | 273 | ########################################################################## 274 | # Roles # 275 | ########################################################################## 276 | 277 | DemoLambdaExecutionRole: 278 | Description: Creating service role in IAM for AWS Lambda 279 | Type: AWS::IAM::Role 280 | Properties: 281 | RoleName: !Sub 'CodeStar-Execution${Stage}' 282 | AssumeRolePolicyDocument: 283 | Statement: 284 | - Effect: Allow 285 | Principal: 286 | Service: [lambda.amazonaws.com] 287 | Action: sts:AssumeRole 288 | Path: / 289 | ManagedPolicyArns: 290 | - !Sub 'arn:${AWS::Partition}:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole' 291 | - !Sub 'arn:${AWS::Partition}:iam::aws:policy/ComprehendFullAccess' 292 | DemoStatesExecutionRole: 293 | Type: "AWS::IAM::Role" 294 | Properties: 295 | AssumeRolePolicyDocument: 296 | Version: "2012-10-17" 297 | Statement: 298 | - Effect: "Allow" 299 | Principal: 300 | Service: 301 | - !Sub states.${AWS::Region}.amazonaws.com 302 | Action: "sts:AssumeRole" 303 | Path: "/" 304 | Policies: 305 | - PolicyName: StatesExecutionPolicy 306 | PolicyDocument: 307 | Version: "2012-10-17" 308 | Statement: 309 | - Effect: Allow 310 | Action: 311 | - "lambda:InvokeFunction" 312 | - "comprehend:DetectSentiment" 313 | Resource: "*" 314 | ########################################################################## 315 | # EVENT BRIDGE # 316 | ########################################################################## 317 | MyEventsRule: 318 | Type: 'AWS::Events::Rule' 319 | Properties: 320 | Description: Events Rule with StepFunctionParams 321 | EventBusName: !Ref EventSourceName 322 | EventPattern: 323 | account: 324 | - !Ref "AWS::AccountId" 325 | detail-type: 326 | - 'Support Ticket: Comment Created' 327 | Targets: 328 | - 329 | Arn: 330 | Fn::GetAtt: 331 | - ZendDemoStateMachine 332 | - Arn 333 | RoleArn: 334 | Fn::GetAtt: 335 | - DemoStatesExecutionRole 336 | - Arn 337 | Id: NewTicketSFN 338 | DependsOn: 339 | - ZendDemoStateMachine 340 | - DemoStatesExecutionRole 341 | --------------------------------------------------------------------------------