Skip to content

Commit 633d744

Browse files
committed
Merge branch 'main' into eeen17/mainscreen-api
2 parents 0ed2f76 + 0b13478 commit 633d744

40 files changed

+2012
-232
lines changed

Makefile

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,9 +80,13 @@ deploy_dev: check_account_dev build
8080
invalidate_cloudfront:
8181
@echo "Creating CloudFront invalidation..."
8282
$(eval DISTRIBUTION_ID := $(shell aws cloudformation describe-stacks --stack-name $(application_key) --query "Stacks[0].Outputs[?OutputKey=='CloudfrontDistributionId'].OutputValue" --output text))
83+
$(eval DISTRIBUTION_ID_2 := $(shell aws cloudformation describe-stacks --stack-name $(application_key) --query "Stacks[0].Outputs[?OutputKey=='CloudfrontSecondaryDistributionId'].OutputValue" --output text))
8384
$(eval INVALIDATION_ID := $(shell aws cloudfront create-invalidation --distribution-id $(DISTRIBUTION_ID) --paths "/*" --query 'Invalidation.Id' --output text --no-cli-page))
85+
$(eval INVALIDATION_ID_2 := $(shell aws cloudfront create-invalidation --distribution-id $(DISTRIBUTION_ID_2) --paths "/*" --query 'Invalidation.Id' --output text --no-cli-page))
8486
@echo "Waiting on job $(INVALIDATION_ID)..."
8587
aws cloudfront wait invalidation-completed --distribution-id $(DISTRIBUTION_ID) --id $(INVALIDATION_ID)
88+
@echo "Waiting on job $(INVALIDATION_ID_2)..."
89+
aws cloudfront wait invalidation-completed --distribution-id $(DISTRIBUTION_ID_2) --id $(INVALIDATION_ID_2)
8690
@echo "CloudFront invalidation completed!"
8791

8892
install:

cloudformation/iam.yml

Lines changed: 22 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ Parameters:
1616
SqsQueueArn:
1717
Type: String
1818

19+
Conditions:
20+
IsDev: !Equals [!Ref RunEnvironment, "dev"]
21+
1922
Resources:
2023
# Managed Policy for Common Lambda Permissions
2124
CommonLambdaManagedPolicy:
@@ -73,8 +76,6 @@ Resources:
7376
- Sid: DynamoDBCacheAccess
7477
Effect: Allow
7578
Action:
76-
- dynamodb:BatchGetItem
77-
- dynamodb:BatchWriteItem
7879
- dynamodb:ConditionCheckItem
7980
- dynamodb:PutItem
8081
- dynamodb:DescribeTable
@@ -84,15 +85,6 @@ Resources:
8485
- dynamodb:UpdateItem
8586
Resource:
8687
- Fn::Sub: arn:aws:dynamodb:${AWS::Region}:${AWS::AccountId}:table/infra-core-api-cache
87-
Condition:
88-
ForAllValues:StringEquals:
89-
dynamodb:LeadingKeys:
90-
- testing # add any keys that must be accessible
91-
ForAllValues:StringLike:
92-
dynamodb:Attributes:
93-
- primaryKey
94-
- expireAt
95-
- "*"
9688

9789
- Sid: DynamoDBRateLimitTableAccess
9890
Effect: Allow
@@ -185,28 +177,6 @@ Resources:
185177
Effect: Allow
186178
Resource:
187179
- Fn::Sub: arn:aws:secretsmanager:${AWS::Region}:${AWS::AccountId}:secret:infra-core-api-entra*
188-
- Action:
189-
- dynamodb:BatchGetItem
190-
- dynamodb:GetItem
191-
- dynamodb:Query
192-
- dynamodb:DescribeTable
193-
- dynamodb:BatchWriteItem
194-
- dynamodb:ConditionCheckItem
195-
- dynamodb:PutItem
196-
- dynamodb:DeleteItem
197-
- dynamodb:UpdateItem
198-
Effect: Allow
199-
Resource:
200-
- Fn::Sub: arn:aws:dynamodb:${AWS::Region}:${AWS::AccountId}:table/infra-core-api-cache
201-
Condition:
202-
ForAllValues:StringEquals:
203-
dynamodb:LeadingKeys:
204-
- entra_id_access_token # add any keys that must be accessible
205-
ForAllValues:StringLike:
206-
dynamodb:Attributes:
207-
- primaryKey
208-
- expireAt
209-
- "*"
210180

211181
# SQS Lambda IAM Role
212182
SqsLambdaIAMRole:
@@ -241,6 +211,25 @@ Resources:
241211
ForAllValues:StringLike:
242212
ses:Recipients:
243213
- "*@illinois.edu"
214+
- PolicyName: ses-sales
215+
PolicyDocument:
216+
Version: "2012-10-17"
217+
Statement:
218+
- Action:
219+
- ses:SendEmail
220+
- ses:SendRawEmail
221+
Effect: Allow
222+
Resource: "*"
223+
Condition:
224+
StringEquals:
225+
ses:FromAddress:
226+
Fn::Sub: "sales@${SesEmailDomain}"
227+
ForAllValues:StringLike:
228+
ses:Recipients:
229+
- !If
230+
- IsDev
231+
- "*@illinois.edu"
232+
- "*"
244233

245234

246235
EdgeLambdaIAMRole:

cloudformation/main.yml

Lines changed: 107 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,13 @@ Parameters:
77
Type: String
88
AllowedValues: ["dev", "prod"]
99
AlertSNSArn:
10-
Description: SNS Queue to send alarm alerts to (prod only)
10+
Description: SNS Queue to send general alarm alerts to (prod only)
1111
Type: String
1212
Default: arn:aws:sns:us-east-1:298118738376:infra-monitor-alerts
13+
PriorityAlertSNSArn:
14+
Description: SNS Queue to send priority alarm alerts to (prod only)
15+
Type: String
16+
Default: arn:aws:sns:us-east-1:298118738376:infra-core-api-priority-alerts
1317
ApplicationPrefix:
1418
Type: String
1519
Description: Application prefix, no ending dash
@@ -24,11 +28,11 @@ Parameters:
2428
AllowedValues: [true, false]
2529
SqsLambdaTimeout:
2630
Description: How long the SQS lambda is permitted to run (in seconds)
27-
Default: 300
31+
Default: 180
2832
Type: Number
2933
SqsMessageTimeout:
30-
Description: MessageVisibilityTimeout for the SQS Lambda queue (should be at least 6xSqsLambdaTimeout)
31-
Default: 1800
34+
Description: MessageVisibilityTimeout for the SQS Lambda queue (should be at least (numMaxRetry + 1)*SqsLambdaTimeout)
35+
Default: 720
3236
Type: Number
3337
S3BucketPrefix:
3438
Description: S3 bucket prefix which will ensure global uniqueness
@@ -119,7 +123,7 @@ Resources:
119123
GWApiId: !Ref AppApiGateway
120124
GWHostedZoneId:
121125
!FindInMap [ApiGwConfig, !Ref RunEnvironment, HostedZoneId]
122-
CloudfrontDomain: !GetAtt [AppFrontendCloudfrontDistribution, DomainName]
126+
CloudfrontDomain: !GetAtt [AppIcalCloudfrontDistribution, DomainName]
123127

124128
LinkryDomainProxy:
125129
Type: AWS::Serverless::Application
@@ -139,7 +143,7 @@ Resources:
139143
GWApiId: !Ref AppApiGateway
140144
GWHostedZoneId:
141145
!FindInMap [ApiGwConfig, !Ref RunEnvironment, HostedZoneId]
142-
CloudfrontDomain: !GetAtt [AppFrontendCloudfrontDistribution, DomainName]
146+
CloudfrontDomain: !GetAtt [AppIcalCloudfrontDistribution, DomainName]
143147

144148
CoreUrlProd:
145149
Type: AWS::Serverless::Application
@@ -258,6 +262,17 @@ Resources:
258262
FunctionResponseTypes:
259263
- ReportBatchItemFailures
260264

265+
SQSLambdaEventMappingSales:
266+
Type: AWS::Lambda::EventSourceMapping
267+
DependsOn:
268+
- AppSqsLambdaFunction
269+
Properties:
270+
BatchSize: 5
271+
EventSourceArn: !GetAtt AppSQSQueues.Outputs.SalesEmailQueueArn
272+
FunctionName: !Sub ${ApplicationPrefix}-sqs-lambda
273+
FunctionResponseTypes:
274+
- ReportBatchItemFailures
275+
261276
MembershipRecordsTable:
262277
Type: "AWS::DynamoDB::Table"
263278
DeletionPolicy: "Retain"
@@ -515,7 +530,7 @@ Resources:
515530
ComparisonOperator: "LessThanThreshold"
516531
Threshold: "1"
517532
AlarmActions:
518-
- !Ref AlertSNSArn
533+
- !Ref PriorityAlertSNSArn
519534
Dimensions:
520535
- Name: "ApiName"
521536
Value: !Sub ${ApplicationPrefix}-gateway
@@ -534,7 +549,7 @@ Resources:
534549
ComparisonOperator: "GreaterThanThreshold"
535550
Threshold: "2"
536551
AlarmActions:
537-
- !Ref AlertSNSArn
552+
- !Ref PriorityAlertSNSArn
538553
Dimensions:
539554
- Name: "ApiName"
540555
Value: !Sub ${ApplicationPrefix}-gateway
@@ -547,13 +562,16 @@ Resources:
547562
AlarmDescription: "Items are present in the application DLQ, meaning some messages failed to process."
548563
Namespace: "AWS/SQS"
549564
MetricName: "ApproximateNumberOfMessagesVisible"
550-
Statistic: "Sum"
551-
Period: "60"
552-
EvaluationPeriods: "1"
565+
Statistic: "Maximum"
566+
Period: 60
567+
EvaluationPeriods: 1
553568
ComparisonOperator: "GreaterThanThreshold"
554-
Threshold: "0"
569+
Threshold: 0
570+
Dimensions:
571+
- Name: QueueName
572+
Value: !Sub ${ApplicationPrefix}-sqs-dlq
555573
AlarmActions:
556-
- !Ref AlertSNSArn
574+
- !Ref PriorityAlertSNSArn
557575

558576
APILambdaPermission:
559577
Type: AWS::Lambda::Permission
@@ -608,20 +626,6 @@ Resources:
608626
- ApiGwConfig
609627
- !Ref RunEnvironment
610628
- UiDomainName
611-
- !Join
612-
- ""
613-
- - "go."
614-
- !FindInMap
615-
- ApiGwConfig
616-
- !Ref RunEnvironment
617-
- EnvDomainName
618-
- !Join
619-
- ""
620-
- - "ical."
621-
- !FindInMap
622-
- ApiGwConfig
623-
- !Ref RunEnvironment
624-
- EnvDomainName
625629

626630
DefaultCacheBehavior:
627631
TargetOriginId: S3WebsiteOrigin
@@ -749,19 +753,95 @@ Resources:
749753
Properties:
750754
FunctionName: !Ref AppFrontendEdgeLambda
751755

756+
AppIcalCloudfrontDistribution:
757+
Type: AWS::CloudFront::Distribution
758+
Properties:
759+
DistributionConfig:
760+
Origins:
761+
- Id: ApiGatewayOrigin
762+
DomainName: !Sub "${AppApiGateway}.execute-api.${AWS::Region}.amazonaws.com"
763+
OriginPath: "/default"
764+
CustomOriginConfig:
765+
HTTPPort: 80
766+
HTTPSPort: 443
767+
OriginProtocolPolicy: https-only
768+
Enabled: true
769+
Aliases:
770+
- !Join
771+
- ""
772+
- - "go."
773+
- !FindInMap
774+
- ApiGwConfig
775+
- !Ref RunEnvironment
776+
- EnvDomainName
777+
- !Join
778+
- ""
779+
- - "ical."
780+
- !FindInMap
781+
- ApiGwConfig
782+
- !Ref RunEnvironment
783+
- EnvDomainName
784+
DefaultCacheBehavior:
785+
TargetOriginId: ApiGatewayOrigin
786+
ViewerProtocolPolicy: redirect-to-https
787+
AllowedMethods:
788+
- GET
789+
- HEAD
790+
- OPTIONS
791+
- PUT
792+
- POST
793+
- DELETE
794+
- PATCH
795+
CachedMethods:
796+
- GET
797+
- HEAD
798+
ForwardedValues:
799+
QueryString: false
800+
Cookies:
801+
Forward: none
802+
CachePolicyId: !Ref CloudfrontCachePolicy
803+
OriginRequestPolicyId: 216adef6-5c7f-47e4-b989-5492eafa07d3
804+
ViewerCertificate:
805+
AcmCertificateArn: !FindInMap
806+
- ApiGwConfig
807+
- !Ref RunEnvironment
808+
- EnvCertificateArn
809+
MinimumProtocolVersion: TLSv1.2_2021
810+
SslSupportMethod: sni-only
811+
HttpVersion: http2
812+
PriceClass: PriceClass_100
813+
814+
752815
Outputs:
753816
DomainName:
754817
Description: Domain name that the UI is hosted at
755818
Value: !FindInMap
756819
- ApiGwConfig
757820
- !Ref RunEnvironment
758821
- UiDomainName
822+
759823
CloudfrontCnameTarget:
760824
Description: CNAME record target to create for the domain name above (create the CNAME manually)
761825
Value:
762826
Fn::GetAtt:
763827
- AppFrontendCloudfrontDistribution
764828
- DomainName
829+
830+
CloudfrontSecondaryCnameTarget:
831+
Description: CNAME record target to create for the secondary domain names (create the CNAME manually)
832+
Value:
833+
Fn::GetAtt:
834+
- AppIcalCloudfrontDistribution
835+
- DomainName
836+
765837
CloudfrontDistributionId:
766838
Description: Cloudfront Distribution ID
767839
Value: !GetAtt AppFrontendCloudfrontDistribution.Id
840+
841+
CloudfrontSecondaryDistributionId:
842+
Description: Cloudfront Distribution ID
843+
Value: !GetAtt AppIcalCloudfrontDistribution.Id
844+
845+
SalesEmailQueueArn:
846+
Description: Sales Email Queue Arn
847+
Value: !GetAtt AppSQSQueues.Outputs.SalesEmailQueueArn

cloudformation/sqs.yml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ Resources:
1313
Properties:
1414
QueueName: !Sub ${QueueName}-dlq
1515
VisibilityTimeout: !Ref MessageTimeout
16+
MessageRetentionPeriod: 1209600
17+
1618
AppQueue:
1719
Type: AWS::SQS::Queue
1820
Properties:
@@ -24,6 +26,17 @@ Resources:
2426
- "AppDLQ"
2527
- "Arn"
2628
maxReceiveCount: 3
29+
SalesEmailQueue:
30+
Type: AWS::SQS::Queue
31+
Properties:
32+
QueueName: !Sub ${QueueName}-sales
33+
VisibilityTimeout: !Ref MessageTimeout
34+
RedrivePolicy:
35+
deadLetterTargetArn:
36+
Fn::GetAtt:
37+
- "AppDLQ"
38+
- "Arn"
39+
maxReceiveCount: 3
2740

2841
Outputs:
2942
MainQueueArn:
@@ -38,3 +51,9 @@ Outputs:
3851
Fn::GetAtt:
3952
- AppDLQ
4053
- Arn
54+
SalesEmailQueueArn:
55+
Description: Sales Email Queue Arn
56+
Value:
57+
Fn::GetAtt:
58+
- SalesEmailQueue
59+
- Arn

src/api/esbuild.config.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { build, context } from 'esbuild';
22
import { readFileSync } from 'fs';
33
import { resolve } from 'path';
4+
import copyStaticFiles from 'esbuild-copy-static-files';
45

56
const isWatching = !!process.argv.includes('--watch')
67
const nodePackage = JSON.parse(readFileSync(resolve(process.cwd(), 'package.json'), 'utf8'));
@@ -24,14 +25,17 @@ const buildOptions = {
2425
},
2526
banner: {
2627
js: `
27-
import path from 'path';
2828
import { fileURLToPath } from 'url';
2929
import { createRequire as topLevelCreateRequire } from 'module';
3030
const require = topLevelCreateRequire(import.meta.url);
3131
const __filename = fileURLToPath(import.meta.url);
3232
const __dirname = path.dirname(__filename);
3333
`.trim(),
3434
}, // Banner for compatibility with CommonJS
35+
plugins: [copyStaticFiles({
36+
src: './public',
37+
dest: resolve(process.cwd(), '../', '../', 'dist_devel', 'public'),
38+
})],
3539
};
3640

3741
if (isWatching) {

0 commit comments

Comments
 (0)