Skip to content

Commit 3f0578f

Browse files
committedSep 8, 2021
first-commit
0 parents  commit 3f0578f

16 files changed

+9878
-0
lines changed
 

‎.env

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
MicrosoftAppId=bbd30b23-febd-48b9-a812-0c3fc32f177c
2+
MicrosoftAppPassword=+!jZrvAXAH@Sz3r6nh@9qIXc

‎.eslintrc.js

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
/* eslint-disable */
2+
module.exports = {
3+
"extends": "standard",
4+
"rules": {
5+
"semi": [2, "always"],
6+
"indent": [2, 4],
7+
"no-return-await": 0,
8+
"space-before-function-paren": [2, {
9+
"named": "never",
10+
"anonymous": "never",
11+
"asyncArrow": "always"
12+
}],
13+
"template-curly-spacing": [2, "always"]
14+
}
15+
};

‎.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
node_modules/
2+
npm-debug.log

‎README.md

+108
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
# Proactive Messages
2+
3+
Bot Framework v4 proactive messages bot sample
4+
5+
This bot has been created using [Bot Framework](https://dev.botframework.com), it shows how to send proactive messages to users by capturing a conversation reference, then using it later to initialize outbound messages.
6+
7+
## Concepts introduced in this sample
8+
9+
Typically, each message that a bot sends to the user directly relates to the user's prior input. In some cases, a bot may need to send the user a message that is not directly related to the current topic of conversation. These types of messages are called proactive messages.
10+
11+
Proactive messages can be useful in a variety of scenarios. If a bot sets a timer or reminder, it will need to notify the user when the time arrives. Or, if a bot receives a notification from an external system, it may need to communicate that information to the user immediately. For example, if the user has previously asked the bot to monitor the price of a product, the bot can alert the user if the price of the product has dropped by 20%. Or, if a bot requires some time to compile a response to the user's question, it may inform the user of the delay and allow the conversation to continue in the meantime. When the bot finishes compiling the response to the question, it will share that information with the user.
12+
13+
This project has a notify endpoint that will trigger the proactive messages to be sent to
14+
all users who have previously messaged the bot.
15+
16+
## Prerequisites
17+
18+
- [Node.js](https://nodejs.org) version 10.14 or higher
19+
20+
```bash
21+
# determine node version
22+
node --version
23+
```
24+
25+
## To try this sample
26+
27+
- Clone the repository
28+
29+
```bash
30+
git clone https://github.com/microsoft/botbuilder-samples.git
31+
```
32+
33+
- In a terminal, navigate to `samples/javascript_nodejs/16.proactive-messages`
34+
35+
```bash
36+
cd samples/javascript_nodejs/16.proactive-messages
37+
```
38+
39+
- Install modules
40+
41+
```bash
42+
npm install
43+
```
44+
45+
- Start the bot
46+
47+
```bash
48+
npm start
49+
```
50+
51+
## Testing the bot using Bot Framework Emulator
52+
53+
[Bot Framework Emulator](https://github.com/microsoft/botframework-emulator) is a desktop application that allows bot developers to test and debug their bots on localhost or running remotely through a tunnel.
54+
55+
- Install the Bot Framework Emulator version 4.9.0 or greater from [here](https://github.com/Microsoft/BotFramework-Emulator/releases)
56+
57+
### Connect to the bot using Bot Framework Emulator
58+
59+
- Launch Bot Framework Emulator
60+
- File -> Open Bot
61+
- Enter a Bot URL of `http://localhost:3978/api/messages`
62+
63+
With the Bot Framework Emulator connected to your running bot, the sample will not respond to an HTTP GET that will trigger a proactive message. The proactive message can be triggered from the command line using `curl` or similar tooling, or can be triggered by opening a browser windows and nagivating to `http://localhost:3978/api/notify`.
64+
65+
### Using curl
66+
67+
- Send a get request to `http://localhost:3978/api/notify` to proactively message users from the bot.
68+
69+
```bash
70+
curl get http://localhost:3978/api/notify
71+
```
72+
73+
- Using the Bot Framwork Emulator, notice a message was proactively sent to the user from the bot.
74+
75+
### Using the Browser
76+
77+
- Launch a web browser
78+
- Navigate to `http://localhost:3978/api/notify`
79+
- Using the Bot Framwork Emulator, notice a message was proactively sent to the user from the bot.
80+
81+
## Interacting with the bots
82+
83+
In addition to responding to incoming messages, bots are frequently called on to send "proactive" messages based on activity, scheduled tasks, or external events.
84+
85+
In order to send a proactive message using Bot Framework, the bot must first capture a conversation reference from an incoming message using `TurnContext.getConversationReference()`. This reference can be stored for later use.
86+
87+
To send proactive messages, acquire a conversation reference, then use `adapter.continueConversation()` to create a TurnContext object that will allow the bot to deliver the new outgoing message.
88+
89+
## Deploy this bot to Azure
90+
91+
To learn more about deploying a bot to Azure, see [Deploy your bot to Azure](https://aka.ms/azuredeployment) for a complete list of deployment instructions.
92+
93+
## Further reading
94+
95+
- [Bot Framework Documentation](https://docs.botframework.com)
96+
- [Bot Basics](https://docs.microsoft.com/azure/bot-service/bot-builder-basics?view=azure-bot-service-4.0)
97+
- [Send proactive messages](https://docs.microsoft.com/en-us/azure/bot-service/bot-builder-howto-proactive-message?view=azure-bot-service-4.0&tabs=js)
98+
- [continueConversation Method](https://docs.microsoft.com/en-us/javascript/api/botbuilder/botframeworkadapter#continueconversation)
99+
- [getConversationReference Method](https://docs.microsoft.com/en-us/javascript/api/botbuilder-core/turncontext#getconversationreference)
100+
- [Activity processing](https://docs.microsoft.com/en-us/azure/bot-service/bot-builder-concept-activity-processing?view=azure-bot-service-4.0)
101+
- [Azure Bot Service Introduction](https://docs.microsoft.com/azure/bot-service/bot-service-overview-introduction?view=azure-bot-service-4.0)
102+
- [Azure Bot Service Documentation](https://docs.microsoft.com/azure/bot-service/?view=azure-bot-service-4.0)
103+
- [Azure CLI](https://docs.microsoft.com/cli/azure/?view=azure-cli-latest)
104+
- [Azure Portal](https://portal.azure.com)
105+
- [Language Understanding using LUIS](https://docs.microsoft.com/en-us/azure/cognitive-services/luis/)
106+
- [Channels and Bot Connector Service](https://docs.microsoft.com/en-us/azure/bot-service/bot-concepts?view=azure-bot-service-4.0)
107+
- [Restify](https://www.npmjs.com/package/restify)
108+
- [dotenv](https://www.npmjs.com/package/dotenv)

‎bots/proactiveBot.js

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
const { ActivityHandler, TurnContext } = require('botbuilder');
5+
6+
class ProactiveBot extends ActivityHandler {
7+
constructor(conversationReferences) {
8+
super();
9+
10+
// Dependency injected dictionary for storing ConversationReference objects used in NotifyController to proactively message users
11+
this.conversationReferences = conversationReferences;
12+
13+
this.onConversationUpdate(async (context, next) => {
14+
this.addConversationReference(context.activity);
15+
16+
await next();
17+
});
18+
19+
}
20+
21+
addConversationReference(activity) {
22+
const conversationReference = TurnContext.getConversationReference(activity);
23+
this.conversationReferences[conversationReference.conversation.id] = conversationReference;
24+
}
25+
}
26+
27+
module.exports.ProactiveBot = ProactiveBot;

‎contacts/list.csv

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
birthday,name,department,gender
2+
01/09,Carolina Souza,Desenvolvimento,F
3+
08/09,Teste,Desenvolvimento,M
4+
12/08,João Paulo,Desenvolvimento,M
5+
12/08,João Paulo,Desenvolvimento,M
6+
12/08,João Paulo,Desenvolvimento,M
7+
12/08,João Paulo,Desenvolvimento,M
8+
12/08,João Paulo,Desenvolvimento,M
9+
12/08,João Paulo,Desenvolvimento,M
10+
17/08,Maria Targino,Calculo Trabalhista,F
+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
{
2+
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
3+
"contentVersion": "1.0.0.0",
4+
"parameters": {
5+
"groupLocation": {
6+
"value": ""
7+
},
8+
"groupName": {
9+
"value": ""
10+
},
11+
"appId": {
12+
"value": ""
13+
},
14+
"appSecret": {
15+
"value": ""
16+
},
17+
"botId": {
18+
"value": ""
19+
},
20+
"botSku": {
21+
"value": ""
22+
},
23+
"newAppServicePlanName": {
24+
"value": ""
25+
},
26+
"newAppServicePlanSku": {
27+
"value": {
28+
"name": "S1",
29+
"tier": "Standard",
30+
"size": "S1",
31+
"family": "S",
32+
"capacity": 1
33+
}
34+
},
35+
"newAppServicePlanLocation": {
36+
"value": ""
37+
},
38+
"newWebAppName": {
39+
"value": ""
40+
}
41+
}
42+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
{
2+
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
3+
"contentVersion": "1.0.0.0",
4+
"parameters": {
5+
"appId": {
6+
"value": ""
7+
},
8+
"appSecret": {
9+
"value": ""
10+
},
11+
"botId": {
12+
"value": ""
13+
},
14+
"botSku": {
15+
"value": ""
16+
},
17+
"newAppServicePlanName": {
18+
"value": ""
19+
},
20+
"newAppServicePlanSku": {
21+
"value": {
22+
"name": "S1",
23+
"tier": "Standard",
24+
"size": "S1",
25+
"family": "S",
26+
"capacity": 1
27+
}
28+
},
29+
"appServicePlanLocation": {
30+
"value": ""
31+
},
32+
"existingAppServicePlan": {
33+
"value": ""
34+
},
35+
"newWebAppName": {
36+
"value": ""
37+
}
38+
}
39+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
{
2+
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
3+
"contentVersion": "1.0.0.0",
4+
"parameters": {
5+
"groupLocation": {
6+
"type": "string",
7+
"metadata": {
8+
"description": "Specifies the location of the Resource Group."
9+
}
10+
},
11+
"groupName": {
12+
"type": "string",
13+
"metadata": {
14+
"description": "Specifies the name of the Resource Group."
15+
}
16+
},
17+
"appId": {
18+
"type": "string",
19+
"metadata": {
20+
"description": "Active Directory App ID, set as MicrosoftAppId in the Web App's Application Settings."
21+
}
22+
},
23+
"appSecret": {
24+
"type": "string",
25+
"metadata": {
26+
"description": "Active Directory App Password, set as MicrosoftAppPassword in the Web App's Application Settings."
27+
}
28+
},
29+
"botId": {
30+
"type": "string",
31+
"metadata": {
32+
"description": "The globally unique and immutable bot ID. Also used to configure the displayName of the bot, which is mutable."
33+
}
34+
},
35+
"botSku": {
36+
"type": "string",
37+
"metadata": {
38+
"description": "The pricing tier of the Bot Service Registration. Acceptable values are F0 and S1."
39+
}
40+
},
41+
"newAppServicePlanName": {
42+
"type": "string",
43+
"metadata": {
44+
"description": "The name of the App Service Plan."
45+
}
46+
},
47+
"newAppServicePlanSku": {
48+
"type": "object",
49+
"defaultValue": {
50+
"name": "S1",
51+
"tier": "Standard",
52+
"size": "S1",
53+
"family": "S",
54+
"capacity": 1
55+
},
56+
"metadata": {
57+
"description": "The SKU of the App Service Plan. Defaults to Standard values."
58+
}
59+
},
60+
"newAppServicePlanLocation": {
61+
"type": "string",
62+
"metadata": {
63+
"description": "The location of the App Service Plan. Defaults to \"westus\"."
64+
}
65+
},
66+
"newWebAppName": {
67+
"type": "string",
68+
"defaultValue": "",
69+
"metadata": {
70+
"description": "The globally unique name of the Web App. Defaults to the value passed in for \"botId\"."
71+
}
72+
}
73+
},
74+
"variables": {
75+
"appServicePlanName": "[parameters('newAppServicePlanName')]",
76+
"resourcesLocation": "[parameters('newAppServicePlanLocation')]",
77+
"webAppName": "[if(empty(parameters('newWebAppName')), parameters('botId'), parameters('newWebAppName'))]",
78+
"siteHost": "[concat(variables('webAppName'), '.azurewebsites.net')]",
79+
"botEndpoint": "[concat('https://', variables('siteHost'), '/api/messages')]",
80+
"resourceGroupId": "[concat(subscription().id, '/resourceGroups/', parameters('groupName'))]"
81+
},
82+
"resources": [
83+
{
84+
"name": "[parameters('groupName')]",
85+
"type": "Microsoft.Resources/resourceGroups",
86+
"apiVersion": "2018-05-01",
87+
"location": "[parameters('groupLocation')]",
88+
"properties": {}
89+
},
90+
{
91+
"type": "Microsoft.Resources/deployments",
92+
"apiVersion": "2018-05-01",
93+
"name": "storageDeployment",
94+
"resourceGroup": "[parameters('groupName')]",
95+
"dependsOn": [
96+
"[resourceId('Microsoft.Resources/resourceGroups/', parameters('groupName'))]"
97+
],
98+
"properties": {
99+
"mode": "Incremental",
100+
"template": {
101+
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
102+
"contentVersion": "1.0.0.0",
103+
"parameters": {},
104+
"variables": {},
105+
"resources": [
106+
{
107+
"comments": "Create a new App Service Plan",
108+
"type": "Microsoft.Web/serverfarms",
109+
"name": "[variables('appServicePlanName')]",
110+
"apiVersion": "2018-02-01",
111+
"location": "[variables('resourcesLocation')]",
112+
"sku": "[parameters('newAppServicePlanSku')]",
113+
"properties": {
114+
"name": "[variables('appServicePlanName')]"
115+
}
116+
},
117+
{
118+
"comments": "Create a Web App using the new App Service Plan",
119+
"type": "Microsoft.Web/sites",
120+
"apiVersion": "2015-08-01",
121+
"location": "[variables('resourcesLocation')]",
122+
"kind": "app",
123+
"dependsOn": [
124+
"[concat(variables('resourceGroupId'), '/providers/Microsoft.Web/serverfarms/', variables('appServicePlanName'))]"
125+
],
126+
"name": "[variables('webAppName')]",
127+
"properties": {
128+
"name": "[variables('webAppName')]",
129+
"serverFarmId": "[variables('appServicePlanName')]",
130+
"siteConfig": {
131+
"appSettings": [
132+
{
133+
"name": "WEBSITE_NODE_DEFAULT_VERSION",
134+
"value": "10.14.1"
135+
},
136+
{
137+
"name": "MicrosoftAppId",
138+
"value": "[parameters('appId')]"
139+
},
140+
{
141+
"name": "MicrosoftAppPassword",
142+
"value": "[parameters('appSecret')]"
143+
}
144+
],
145+
"cors": {
146+
"allowedOrigins": [
147+
"https://botservice.hosting.portal.azure.net",
148+
"https://hosting.onecloud.azure-test.net/"
149+
]
150+
}
151+
}
152+
}
153+
},
154+
{
155+
"apiVersion": "2017-12-01",
156+
"type": "Microsoft.BotService/botServices",
157+
"name": "[parameters('botId')]",
158+
"location": "global",
159+
"kind": "bot",
160+
"sku": {
161+
"name": "[parameters('botSku')]"
162+
},
163+
"properties": {
164+
"name": "[parameters('botId')]",
165+
"displayName": "[parameters('botId')]",
166+
"endpoint": "[variables('botEndpoint')]",
167+
"msaAppId": "[parameters('appId')]",
168+
"developerAppInsightsApplicationId": null,
169+
"developerAppInsightKey": null,
170+
"publishingCredentials": null,
171+
"storageResourceId": null
172+
},
173+
"dependsOn": [
174+
"[concat(variables('resourceGroupId'), '/providers/Microsoft.Web/sites/', variables('webAppName'))]"
175+
]
176+
}
177+
],
178+
"outputs": {}
179+
}
180+
}
181+
}
182+
]
183+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
{
2+
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
3+
"contentVersion": "1.0.0.0",
4+
"parameters": {
5+
"appId": {
6+
"type": "string",
7+
"metadata": {
8+
"description": "Active Directory App ID, set as MicrosoftAppId in the Web App's Application Settings."
9+
}
10+
},
11+
"appSecret": {
12+
"type": "string",
13+
"metadata": {
14+
"description": "Active Directory App Password, set as MicrosoftAppPassword in the Web App's Application Settings. Defaults to \"\"."
15+
}
16+
},
17+
"botId": {
18+
"type": "string",
19+
"metadata": {
20+
"description": "The globally unique and immutable bot ID. Also used to configure the displayName of the bot, which is mutable."
21+
}
22+
},
23+
"botSku": {
24+
"defaultValue": "F0",
25+
"type": "string",
26+
"metadata": {
27+
"description": "The pricing tier of the Bot Service Registration. Acceptable values are F0 and S1."
28+
}
29+
},
30+
"newAppServicePlanName": {
31+
"type": "string",
32+
"defaultValue": "",
33+
"metadata": {
34+
"description": "The name of the new App Service Plan."
35+
}
36+
},
37+
"newAppServicePlanSku": {
38+
"type": "object",
39+
"defaultValue": {
40+
"name": "S1",
41+
"tier": "Standard",
42+
"size": "S1",
43+
"family": "S",
44+
"capacity": 1
45+
},
46+
"metadata": {
47+
"description": "The SKU of the App Service Plan. Defaults to Standard values."
48+
}
49+
},
50+
"appServicePlanLocation": {
51+
"type": "string",
52+
"metadata": {
53+
"description": "The location of the App Service Plan."
54+
}
55+
},
56+
"existingAppServicePlan": {
57+
"type": "string",
58+
"defaultValue": "",
59+
"metadata": {
60+
"description": "Name of the existing App Service Plan used to create the Web App for the bot."
61+
}
62+
},
63+
"newWebAppName": {
64+
"type": "string",
65+
"defaultValue": "",
66+
"metadata": {
67+
"description": "The globally unique name of the Web App. Defaults to the value passed in for \"botId\"."
68+
}
69+
}
70+
},
71+
"variables": {
72+
"defaultAppServicePlanName": "[if(empty(parameters('existingAppServicePlan')), 'createNewAppServicePlan', parameters('existingAppServicePlan'))]",
73+
"useExistingAppServicePlan": "[not(equals(variables('defaultAppServicePlanName'), 'createNewAppServicePlan'))]",
74+
"servicePlanName": "[if(variables('useExistingAppServicePlan'), parameters('existingAppServicePlan'), parameters('newAppServicePlanName'))]",
75+
"resourcesLocation": "[parameters('appServicePlanLocation')]",
76+
"webAppName": "[if(empty(parameters('newWebAppName')), parameters('botId'), parameters('newWebAppName'))]",
77+
"siteHost": "[concat(variables('webAppName'), '.azurewebsites.net')]",
78+
"botEndpoint": "[concat('https://', variables('siteHost'), '/api/messages')]"
79+
},
80+
"resources": [
81+
{
82+
"comments": "Create a new App Service Plan if no existing App Service Plan name was passed in.",
83+
"type": "Microsoft.Web/serverfarms",
84+
"condition": "[not(variables('useExistingAppServicePlan'))]",
85+
"name": "[variables('servicePlanName')]",
86+
"apiVersion": "2018-02-01",
87+
"location": "[variables('resourcesLocation')]",
88+
"sku": "[parameters('newAppServicePlanSku')]",
89+
"properties": {
90+
"name": "[variables('servicePlanName')]"
91+
}
92+
},
93+
{
94+
"comments": "Create a Web App using an App Service Plan",
95+
"type": "Microsoft.Web/sites",
96+
"apiVersion": "2015-08-01",
97+
"location": "[variables('resourcesLocation')]",
98+
"kind": "app",
99+
"dependsOn": [
100+
"[resourceId('Microsoft.Web/serverfarms', variables('servicePlanName'))]"
101+
],
102+
"name": "[variables('webAppName')]",
103+
"properties": {
104+
"name": "[variables('webAppName')]",
105+
"serverFarmId": "[resourceId('Microsoft.Web/serverfarms', variables('servicePlanName'))]",
106+
"siteConfig": {
107+
"appSettings": [
108+
{
109+
"name": "WEBSITE_NODE_DEFAULT_VERSION",
110+
"value": "10.14.1"
111+
},
112+
{
113+
"name": "MicrosoftAppId",
114+
"value": "[parameters('appId')]"
115+
},
116+
{
117+
"name": "MicrosoftAppPassword",
118+
"value": "[parameters('appSecret')]"
119+
}
120+
],
121+
"cors": {
122+
"allowedOrigins": [
123+
"https://botservice.hosting.portal.azure.net",
124+
"https://hosting.onecloud.azure-test.net/"
125+
]
126+
}
127+
}
128+
}
129+
},
130+
{
131+
"apiVersion": "2017-12-01",
132+
"type": "Microsoft.BotService/botServices",
133+
"name": "[parameters('botId')]",
134+
"location": "global",
135+
"kind": "bot",
136+
"sku": {
137+
"name": "[parameters('botSku')]"
138+
},
139+
"properties": {
140+
"name": "[parameters('botId')]",
141+
"displayName": "[parameters('botId')]",
142+
"endpoint": "[variables('botEndpoint')]",
143+
"msaAppId": "[parameters('appId')]",
144+
"developerAppInsightsApplicationId": null,
145+
"developerAppInsightKey": null,
146+
"publishingCredentials": null,
147+
"storageResourceId": null
148+
},
149+
"dependsOn": [
150+
"[resourceId('Microsoft.Web/sites/', variables('webAppName'))]"
151+
]
152+
}
153+
]
154+
}

‎index.js

+106
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
// index.js is used to setup and configure your bot
5+
6+
// Import required packages
7+
const path = require('path');
8+
const csv = require('csvtojson');
9+
const validateContactList = require('./utils/contactListValidation');
10+
const generateBirthdayMessage = require('./utils/generateBirthdayMessage');
11+
12+
// Note: Ensure you have a .env file and include the MicrosoftAppId and MicrosoftAppPassword.
13+
const ENV_FILE = path.join(__dirname, '.env');
14+
require('dotenv').config({ path: ENV_FILE });
15+
16+
const restify = require('restify');
17+
18+
// Import required bot services.
19+
// See https://aka.ms/bot-services to learn more about the different parts of a bot.
20+
const { BotFrameworkAdapter } = require('botbuilder');
21+
22+
// This bot's main dialog.
23+
const { ProactiveBot } = require('./bots/proactiveBot');
24+
25+
// Create adapter.
26+
// See https://aka.ms/about-bot-adapter to learn more about adapters.
27+
const adapter = new BotFrameworkAdapter({
28+
appId: process.env.MicrosoftAppId,
29+
appPassword: process.env.MicrosoftAppPassword
30+
});
31+
32+
// Catch-all for errors.
33+
adapter.onTurnError = async (context, error) => {
34+
// This check writes out errors to console log .vs. app insights.
35+
// NOTE: In production environment, you should consider logging this to Azure
36+
// application insights. See https://aka.ms/bottelemetry for telemetry
37+
// configuration instructions.
38+
console.error(`\n [onTurnError] unhandled error: ${ error }`);
39+
40+
// Send a trace activity, which will be displayed in Bot Framework Emulator
41+
await context.sendTraceActivity(
42+
'OnTurnError Trace',
43+
`${ error }`,
44+
'https://www.botframework.com/schemas/error',
45+
'TurnError'
46+
);
47+
48+
// Send a message to the user
49+
await context.sendActivity('The bot encountered an error or bug.');
50+
await context.sendActivity('To continue to run this bot, please fix the bot source code.');
51+
};
52+
53+
// Create the main dialog.
54+
const conversationReferences = {};
55+
const bot = new ProactiveBot(conversationReferences);
56+
57+
// Create HTTP server.
58+
const server = restify.createServer();
59+
server.listen(process.env.port || process.env.PORT || 3978, function() {
60+
console.log(`\n${ server.name } listening to ${ server.url }`);
61+
console.log('\nGet Bot Framework Emulator: https://aka.ms/botframework-emulator');
62+
console.log('\nTo talk to your bot, open the emulator select "Open Bot"');
63+
});
64+
65+
// Listen for incoming activities and route them to your bot main dialog.
66+
server.post('/api/messages', (req, res) => {
67+
adapter.processActivity(req, res, async (turnContext) => {
68+
// route to main dialog.
69+
await bot.run(turnContext);
70+
});
71+
});
72+
73+
// Listen for incoming notifications and send proactive messages to users.
74+
server.get('/api/notify', async (req, res) => {
75+
try {
76+
const message = await searchBirthday(res);
77+
if (message === undefined) {
78+
res.end();
79+
return;
80+
}
81+
for (const conversationReference of Object.values(conversationReferences)) {
82+
await adapter.continueConversation(conversationReference, async turnContext => {
83+
await turnContext.sendActivity(message);
84+
});
85+
}
86+
res.end();
87+
console.log(message);
88+
} catch (err) {
89+
console.log(err);
90+
}
91+
});
92+
93+
const searchBirthday = async (res) => {
94+
let contacts = await csv().fromFile(`./contacts/list.csv`);
95+
const today = (new Date()).toLocaleDateString('pt-br', {day: '2-digit', month: '2-digit'});
96+
97+
let birthdays = contacts.filter(contact => contact.birthday === today);
98+
validateContactList(birthdays);
99+
100+
if (birthdays.length < 1)
101+
return console.log("\nNão há aniversariantes no dia de hoje.\n");
102+
103+
const message = generateBirthdayMessage(birthdays);
104+
105+
return message;
106+
};

‎models/Person.js

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
class Person {
2+
constructor(name, birthday, department, gender) {
3+
this.name = name;
4+
this.gender = gender;
5+
this.birthday = this.birthdayValidation(birthday);
6+
this.department = this.departmentValidation(department);
7+
};
8+
9+
birthdayValidation(str) {
10+
if (str.length > 5 || !str.includes("/")) throw new Error(`Data do contato de nome: ${this.name} está inválida.`);
11+
12+
const strNumberParts = str.split("/");
13+
14+
const day = Number(strNumberParts[0]);
15+
const month = Number(strNumberParts[1]);
16+
17+
if (!day || !month || (new Date(`${month}/${day}/2001`)).toLocaleDateString('pt-br', {day: '2-digit', month: '2-digit'}) === "Invalid Date")
18+
throw new Error(`Data do contato de nome: ${this.name} está inválida`);
19+
20+
return str;
21+
}
22+
23+
departmentValidation(str) {
24+
if (!/^([^0-9]*)$/.test(str))
25+
throw new Error(`Departamento do contato de nome: ${this.name} está inválida.`);
26+
27+
return str;
28+
}
29+
}
30+
31+
module.exports = Person;

‎package-lock.json

+9,083
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎package.json

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
{
2+
"name": "proactive-messaging-bot",
3+
"version": "1.0.0",
4+
"description": "Bot Builder v4 proactive messaging sample",
5+
"author": "Microsoft",
6+
"license": "MIT",
7+
"main": "index.js",
8+
"scripts": {
9+
"start": "node ./index.js",
10+
"watch": "nodemon ./index.js",
11+
"lint": "eslint .",
12+
"test": "echo \"Error: no test specified\" && exit 1"
13+
},
14+
"repository": {
15+
"type": "git",
16+
"url": "https://github.com/Microsoft/BotBuilder-Samples.git"
17+
},
18+
"dependencies": {
19+
"botbuilder": "~4.14.0",
20+
"botbuilder-dialogs": "~4.14.0",
21+
"dotenv": "^8.2.0",
22+
"csvtojson": "^2.0.10",
23+
"fetch-ponyfill": "^7.0.0",
24+
"moment": "^2.29.1",
25+
"path": "^0.12.7",
26+
"restify": "~8.5.1"
27+
},
28+
"devDependencies": {
29+
"eslint": "^7.0.0",
30+
"eslint-config-standard": "^14.1.1",
31+
"eslint-plugin-import": "^2.20.2",
32+
"eslint-plugin-node": "^11.1.0",
33+
"eslint-plugin-promise": "^4.2.1",
34+
"eslint-plugin-standard": "^4.0.1",
35+
"nodemon": "~2.0.4"
36+
}
37+
}

‎utils/contactListValidation.js

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
const Person = require("../models/Person");
2+
3+
const contactListValidation = (list) => {
4+
for (let person of list) {
5+
const { name, birthday, department, gender } = person;
6+
7+
if (!(name, birthday, department, gender)) {
8+
throw new Error('Um ou mais campos do seu arquivo .csv estão em um formato errado.');
9+
};
10+
11+
const contact = new Person(name, birthday, department, gender);
12+
13+
if (!(contact.birthday && contact.name && contact.department)) {
14+
throw new Error(`Campos CSV com o nome de: '${name}' estão inválidos.`)
15+
}
16+
};
17+
};
18+
19+
module.exports = contactListValidation;

‎utils/generateBirthdayMessage.js

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
const generateBirthdayMessage = (contacts) => {
2+
const today = (new Date()).toLocaleDateString('pt-br', {day: '2-digit', month: '2-digit', year: 'numeric'});
3+
4+
if (contacts.length === 1) {
5+
const contact = contacts[0];
6+
return `🎉 Hoje, ${today} ${contact.gender === 'F' ? 'a' : 'o'} aniversariante é ${contact.name} - ${contact.department} 🎉
7+
Receba os votos de um feliz aniversário de toda a família KRS!
8+
Desejamos que você tenha um dia maravilhoso, que não faltem as homenagens e o carinho.
9+
Que a sua vida continue sempre em ritmo ascendente, com muito crescimento, realizações pessoais e profissionais.
10+
Desejamos a você muitas felicidades e mais anos de vida com saúde, paz e amor 🎊🎉🥳`;
11+
} else {
12+
return `Hoje, ${today} os aniversariantes são:${contacts.map(e => ` ${e.name}`)} 🎉 !
13+
Recebam os votos de um feliz aniversário de toda a família KRS!
14+
Desejamos que vocês tenham um dia maravilhoso, que não faltem as homenagens e o carinho.
15+
Que a vida de vocês continue sempre em ritmo ascendente, com muito crescimento, realizações pessoais e profissionais.
16+
Desejamos a vocês muitas felicidades e mais anos de vida com saúde, paz e amor 🎊🎉🥳`;
17+
}
18+
};
19+
20+
module.exports = generateBirthdayMessage;

0 commit comments

Comments
 (0)
Please sign in to comment.