Skip to content

Commit c9cc4ba

Browse files
committed
add AWS deployment
1 parent 8dc5086 commit c9cc4ba

7 files changed

+1970
-0
lines changed

.gitignore

+5
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,8 @@ node_modules
3131
.env.*
3232
.idea/
3333
.envrc
34+
35+
aws/config.sh
36+
aws/build/
37+
aws/api-swagger.json
38+
aws/sam-output.yml

aws/api-swagger-template.json

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
{
2+
"swagger": "2.0",
3+
"info": {
4+
"version": "1.0.0",
5+
"title": "%ApiTitle%"
6+
},
7+
"basePath": "/",
8+
"schemes": ["https"],
9+
"consumes": ["application/json"],
10+
"produces": ["application/json"],
11+
"paths": {
12+
"/": {
13+
"x-amazon-apigateway-any-method": {
14+
"x-amazon-apigateway-integration": {
15+
"uri": "arn:aws:apigateway:%Region%:lambda:path/2015-03-31/functions/arn:aws:lambda:%Region%:%AccountId%:function:${stageVariables.ExpressFunction}/invocations",
16+
"passthroughBehavior": "when_no_match",
17+
"httpMethod": "POST",
18+
"type": "aws_proxy"
19+
}
20+
}
21+
},
22+
"/{proxy+}": {
23+
"x-amazon-apigateway-any-method": {
24+
"parameters": [
25+
{
26+
"name": "proxy",
27+
"in": "path",
28+
"required": true,
29+
"type": "string"
30+
}
31+
],
32+
"x-amazon-apigateway-integration": {
33+
"uri": "arn:aws:apigateway:%Region%:lambda:path/2015-03-31/functions/arn:aws:lambda:%Region%:%AccountId%:function:${stageVariables.ExpressFunction}/invocations",
34+
"httpMethod": "POST",
35+
"type": "aws_proxy"
36+
}
37+
}
38+
}
39+
},
40+
"x-amazon-apigateway-binary-media-types": ["*/*"]
41+
}

aws/config.example.sh

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#!/bin/bash
2+
3+
StackName=SlackInviteAutomation
4+
5+
S3BucketArtifacts=your-artifact-bucket
6+
S3PrefixArtifacts=cloudformation/slack-invite-automation
7+
8+
CommunityName="Your Community Name"
9+
SlackUrl=yourcommunity.slack.com
10+
SlackToken=xoxp-xxx-xxx-xxx-xxx
11+
InviteToken=
12+
RecaptchaSiteKey=
13+
RecaptchaSecretKey=
14+
Locale=en
15+

aws/deploy.sh

+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
#!/bin/bash
2+
3+
# "set -e" makes it so if any step fails, the script aborts:
4+
set -e
5+
6+
cd "${BASH_SOURCE%/*}"
7+
source ./config.sh
8+
9+
AwsRegion=$(aws configure get region)
10+
AwsAccountId=$(aws sts get-caller-identity --output text --query Account)
11+
12+
# Build Lambda package
13+
rm -rf build
14+
mkdir build
15+
cd ..
16+
cp -r app.js config.js lib locales package-lock.json package.json public routes views aws/build
17+
cd aws/build
18+
cp ../src/* .
19+
npm install
20+
npm install aws-serverless-express
21+
cd ..
22+
23+
# Replace variables (Region and AccountId) in API Swagger template
24+
cat api-swagger-template.json | sed -e "s/%Region%/${AwsRegion}/g" | sed -e "s/%AccountId%/${AwsAccountId}/g" | sed -e "s/%ApiTitle%/${StackName}/g"> api-swagger.json
25+
26+
# Package SAM template (loads Lambda dist zips to S3 locations)
27+
aws cloudformation package \
28+
--template-file sam-template.json \
29+
--output-template-file sam-output.yml \
30+
--s3-bucket "${S3BucketArtifacts}" \
31+
--s3-prefix "${S3PrefixArtifacts}"
32+
33+
# Deploy CloudFormation stack
34+
aws cloudformation deploy \
35+
--template-file sam-output.yml \
36+
--stack-name "${StackName}" \
37+
--capabilities CAPABILITY_IAM \
38+
--parameter-overrides \
39+
CommunityName="${CommunityName}" \
40+
SlackUrl="${SlackUrl}" \
41+
SlackToken="${SlackToken}" \
42+
InviteToken="${InviteToken}" \
43+
RecaptchaSiteKey="${RecaptchaSiteKey}" \
44+
RecaptchaSecretKey="${RecaptchaSecretKey}" \
45+
Locale="${Locale}"
46+

aws/sam-template.json

+92
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
{
2+
"AWSTemplateFormatVersion": "2010-09-09",
3+
"Transform": "AWS::Serverless-2016-10-31",
4+
"Description": "Slack Invite Automation",
5+
"Parameters": {
6+
"CommunityName": {
7+
"Type": "String",
8+
"Description": "Name of your Slack community (e.g., \"Example Team\")"
9+
},
10+
"SlackUrl": {
11+
"Type": "String",
12+
"Description": "URL host for your Slack community (e.g., \"exampleteam.slack.com\")"
13+
},
14+
"SlackToken": {
15+
"Type": "String",
16+
"NoEcho": true,
17+
"Description": "Slack access token"
18+
},
19+
"InviteToken": {
20+
"Type": "String",
21+
"Description": "Optional invite token"
22+
},
23+
"RecaptchaSiteKey": {
24+
"Type": "String",
25+
"Description": "Optional Recaptcha site key"
26+
},
27+
"RecaptchaSecretKey": {
28+
"Type": "String",
29+
"NoEcho": true,
30+
"Description": "Optional Recaptcha secret key"
31+
},
32+
"Locale": {
33+
"Type": "String",
34+
"Description": "Optional locale string (e.g., \"it\")"
35+
}
36+
},
37+
"Resources": {
38+
"SlackInviteApi": {
39+
"Type": "AWS::Serverless::Api",
40+
"Properties": {
41+
"DefinitionUri": "api-swagger.json",
42+
"StageName": "Api",
43+
"Variables": {
44+
"ExpressFunction": { "Ref": "ExpressFunction" }
45+
}
46+
}
47+
},
48+
"ExpressFunction": {
49+
"Type": "AWS::Serverless::Function",
50+
"Properties": {
51+
"FunctionName": { "Fn::Sub": "${AWS::StackName}-Express" },
52+
"Description": "Express API handler",
53+
"CodeUri": "build/",
54+
"Handler": "lambda.handler",
55+
"Runtime": "nodejs8.10",
56+
"MemorySize": 1024,
57+
"Timeout": 10,
58+
"Tracing": "Active",
59+
"Policies": ["AWSXrayWriteOnlyAccess"],
60+
"Environment": {
61+
"Variables": {
62+
"COMMUNITY_NAME": { "Ref": "CommunityName" },
63+
"SLACK_URL": { "Ref": "SlackUrl" },
64+
"SLACK_TOKEN": { "Ref": "SlackToken" },
65+
"INVITE_TOKEN": { "Ref": "InviteToken" },
66+
"RECAPTCHA_SITE": { "Ref": "RecaptchaSiteKey" },
67+
"RECAPTCHA_SECRET": { "Ref": "RecaptchaSecretKey" },
68+
"LOCALE": { "Ref": "Locale" }
69+
}
70+
},
71+
"Events": {
72+
"ExpressProxyApiRoot": {
73+
"Type": "Api",
74+
"Properties": {
75+
"RestApiId": { "Ref": "SlackInviteApi" },
76+
"Path": "/",
77+
"Method": "ANY"
78+
}
79+
},
80+
"ExpressProxyApiGreedy": {
81+
"Type": "Api",
82+
"Properties": {
83+
"RestApiId": { "Ref": "SlackInviteApi" },
84+
"Path": "/{proxy+}",
85+
"Method": "ANY"
86+
}
87+
}
88+
}
89+
}
90+
}
91+
}
92+
}

aws/src/lambda.js

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
'use strict';
2+
3+
const awsServerlessExpress = require('aws-serverless-express');
4+
const app = require('./app');
5+
6+
// NOTE: If you get ERR_CONTENT_DECODING_FAILED in your browser, this is likely
7+
// due to a compressed response (e.g. gzip) which has not been handled correctly
8+
// by aws-serverless-express and/or API Gateway. Add the necessary MIME types to
9+
// binaryMimeTypes below, then redeploy (`npm run package-deploy`)
10+
const binaryMimeTypes = [
11+
'application/javascript',
12+
'application/json',
13+
'application/octet-stream',
14+
'application/xml',
15+
'font/eot',
16+
'font/opentype',
17+
'font/otf',
18+
'image/jpeg',
19+
'image/png',
20+
'image/svg+xml',
21+
'text/comma-separated-values',
22+
'text/css',
23+
'text/html',
24+
'text/javascript',
25+
'text/plain',
26+
'text/text',
27+
'text/xml',
28+
];
29+
30+
const server = awsServerlessExpress.createServer(app, null, binaryMimeTypes);
31+
32+
exports.handler = (event, context) => awsServerlessExpress.proxy(server, event, context);

0 commit comments

Comments
 (0)