Skip to content
Permalink
Browse files
Seed the project with deploy to Azure botton and basic action response
  • Loading branch information
tony-zhu committed May 17, 2018
1 parent eae9ecd commit f68dfed1fca9d700e1164894983b997693c49da8
Showing with 266 additions and 60 deletions.
  1. +26 −60 .gitignore
  2. +3 −0 .gitmodules
  3. +4 −0 README.md
  4. +65 −0 action/ActionProcessor.js
  5. +16 −0 action/function.json
  6. +20 −0 action/index.js
  7. +116 −0 azuredeploy.json
  8. +1 −0 host.json
  9. +15 −0 package.json
@@ -1,61 +1,27 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# Runtime data
pids
*.pid
*.seed
*.pid.lock

# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov

# Coverage directory used by tools like istanbul
coverage

# nyc test coverage
.nyc_output

# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt

# Bower dependency directory (https://bower.io/)
bower_components

# node-waf configuration
.lock-wscript

# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release

# Dependency directories
node_modules/
jspm_packages/

# TypeScript v1 declaration files
typings/

# Optional npm cache directory
.npm

# Optional eslint cache
.eslintcache

# Optional REPL history
.node_repl_history

# Output of 'npm pack'
*.tgz

# Yarn Integrity file
.yarn-integrity

# dotenv environment variables file
.env

# next.js build output
.next
bin
obj
csx
.vs
edge
Publish
.vscode

*.user
*.suo
*.cscfg
*.Cache
project.lock.json

/packages
/node_modules
/TestResults

/tools/NuGet.exe
/App_Data
/secrets
/data
.secrets
appsettings.json
local.settings.json
npm-debug.log
@@ -0,0 +1,3 @@
[submodule "outlook-actionable-messages-node-token-validation"]
path = outlook-actionable-messages-node-token-validation
url = git@github.com:OfficeDev/outlook-actionable-messages-node-token-validation.git
@@ -1,4 +1,8 @@

# HelloActionableMessages

[![Deploy to Azure](http://azuredeploy.net/deploybutton.png)](https://azuredeploy.net/)

# Contributing

This project welcomes contributions and suggestions. Most contributions require you to agree to a
@@ -0,0 +1,65 @@
var validation = require('../outlook-actionable-messages-node-token-validation/ActionableMessageTokenValidator');

class ActionProcessor{
static process(headers, body, cb, logFun = null){
var auth = headers['authorization'].trim().split(' ');
if (auth.length == 2 && auth[0].toLowerCase() == 'bearer') {
var token = auth[1];
}else{
cb({
status: 401,
body: "Invalid auth header"
});
return;
}

var validator = new validation.ActionableMessageTokenValidator();

// Set targetUrl with your service domain URL.
// For example, if the service URL is https://api.xyz.com/finance/expense?id=1234,
// then set it to https://api.xyz.com
var targetUrl = null;

// validateToken will verify the following
// 1. The token is issued by Microsoft and its digital signature is valid.
// 2. The token has not expired.
// 3. The audience claim matches the service domain URL.
validator.validateToken(
token,
null,
function (err, result) {
if (err) {
logFun('error: ' + err.message);
cb({
status: 401,
body: err.message
});
return;
}
// We have a valid token. We will verify the sender and the action performer.
// You should replace the code below with your own validation logic.
// In this example, we verify that the email is sent by expense@contoso.com
// and the action performer is someone with a @contoso.com email address.
//
// You should also return the CARD-ACTION-STATUS header in the response.
// The value of the header will be displayed to the user.

var card = {
"@type": "MessageCard",
"@context": "http://schema.org/extensions",
"summary": "Hello " + result.actionPerformer + ". Your action email was from " + result.sender,
"title": "Hello " + result.actionPerformer,
"themeColor": "009F9C"
}

cb({
status: 200,
headers: {'CARD-UPDATE-IN-BODY': 'true'},
body: card
})
});

}
}

exports.ActionProcessor = ActionProcessor;
@@ -0,0 +1,16 @@
{
"disabled": false,
"bindings": [
{
"authLevel": "function",
"type": "httpTrigger",
"direction": "in",
"name": "req"
},
{
"type": "http",
"direction": "out",
"name": "res"
}
]
}
@@ -0,0 +1,20 @@
var processor = require('./ActionProcessor');

module.exports = function (context, req) {
context.log('JavaScript HTTP trigger function processed a request.');

if (req.body) {

processor.ActionProcessor.process(req.headers, req.body, function(res){
context.res = res;
context.done();
}, context.log)
}
else {
context.res = {
status: 400,
body: "Invalid request"
};
context.done();
}
};
@@ -0,0 +1,116 @@
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"appName": {
"type": "string",
"metadata": {
"description": "The name of the function app that you wish to create."
}
},
"storageAccountType": {
"type": "string",
"defaultValue": "Standard_LRS",
"allowedValues": [
"Standard_LRS",
"Standard_GRS",
"Standard_RAGRS"
],
"metadata": {
"description": "Storage Account type"
}
},
"repoUrl": {
"type": "string"
},
"branch": {
"type": "string"
}
},
"variables": {
"functionAppName": "[parameters('appName')]",
"hostingPlanName": "[parameters('appName')]",
"storageAccountName": "[concat(uniquestring(resourceGroup().id), 'azfunctions')]",
"storageAccountid": "[concat(resourceGroup().id,'/providers/','Microsoft.Storage/storageAccounts/', variables('storageAccountName'))]"
},
"resources": [
{
"type": "Microsoft.Storage/storageAccounts",
"name": "[variables('storageAccountName')]",
"apiVersion": "2016-12-01",
"location": "[resourceGroup().location]",
"kind": "Storage",
"sku": {
"name": "[parameters('storageAccountType')]"
}
},
{
"type": "Microsoft.Web/serverfarms",
"apiVersion": "2015-04-01",
"name": "[variables('hostingPlanName')]",
"location": "[resourceGroup().location]",
"properties": {
"name": "[variables('hostingPlanName')]",
"computeMode": "Dynamic",
"sku": "Dynamic"
}
},
{
"apiVersion": "2015-08-01",
"type": "Microsoft.Web/sites",
"name": "[variables('functionAppName')]",
"location": "[resourceGroup().location]",
"kind": "functionapp",
"dependsOn": [
"[resourceId('Microsoft.Web/serverfarms', variables('hostingPlanName'))]",
"[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]"
],
"properties": {
"serverFarmId": "[resourceId('Microsoft.Web/serverfarms', variables('hostingPlanName'))]",
"siteConfig": {
"appSettings": [
{
"name": "AzureWebJobsDashboard",
"value": "[concat('DefaultEndpointsProtocol=https;AccountName=', variables('storageAccountName'), ';AccountKey=', listKeys(variables('storageAccountid'),'2015-05-01-preview').key1)]"
},
{
"name": "AzureWebJobsStorage",
"value": "[concat('DefaultEndpointsProtocol=https;AccountName=', variables('storageAccountName'), ';AccountKey=', listKeys(variables('storageAccountid'),'2015-05-01-preview').key1)]"
},
{
"name": "WEBSITE_CONTENTAZUREFILECONNECTIONSTRING",
"value": "[concat('DefaultEndpointsProtocol=https;AccountName=', variables('storageAccountName'), ';AccountKey=', listKeys(variables('storageAccountid'),'2015-05-01-preview').key1)]"
},
{
"name": "WEBSITE_CONTENTSHARE",
"value": "[toLower(variables('functionAppName'))]"
},
{
"name": "FUNCTIONS_EXTENSION_VERSION",
"value": "~1"
},
{
"name": "WEBSITE_NODE_DEFAULT_VERSION",
"value": "6.5.0"
}
]
}
},
"resources": [
{
"apiVersion": "2015-08-01",
"name": "web",
"type": "sourcecontrols",
"dependsOn": [
"[resourceId('Microsoft.Web/sites/', parameters('appName'))]"
],
"properties": {
"RepoUrl": "[parameters('repoUrl')]",
"branch": "[parameters('branch')]",
"IsManualIntegration": "true"
}
}
]
}
]
}
@@ -0,0 +1 @@
{ }
@@ -0,0 +1,15 @@
{
"name": "helloactionablemessages",
"version": "1.0.0",
"description": "Actionable Message Sample",
"scripts": {
"code": "func host start --debug vscode"
},
"dependencies": {
"jsonwebtoken": "7.x",
"request": "2.x",
"rsa-pem-from-mod-exp": "^0.8.4",
"base64url": "^1.0.6"
},
"license": "MIT"
}

0 comments on commit f68dfed

Please sign in to comment.