added auth and data collection
This commit is contained in:
15
.gitignore
vendored
15
.gitignore
vendored
@@ -21,3 +21,18 @@
|
|||||||
npm-debug.log*
|
npm-debug.log*
|
||||||
yarn-debug.log*
|
yarn-debug.log*
|
||||||
yarn-error.log*
|
yarn-error.log*
|
||||||
|
|
||||||
|
#amplify
|
||||||
|
amplify/\#current-cloud-backend
|
||||||
|
amplify/.config/local-*
|
||||||
|
amplify/mock-data
|
||||||
|
amplify/backend/amplify-meta.json
|
||||||
|
amplify/backend/awscloudformation
|
||||||
|
build/
|
||||||
|
dist/
|
||||||
|
node_modules/
|
||||||
|
aws-exports.js
|
||||||
|
awsconfiguration.json
|
||||||
|
amplifyconfiguration.json
|
||||||
|
amplify-gradle-config.json
|
||||||
|
amplifyxc.config
|
||||||
17
amplify/.config/project-config.json
Normal file
17
amplify/.config/project-config.json
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"projectName": "hpiot-react",
|
||||||
|
"version": "3.0",
|
||||||
|
"frontend": "javascript",
|
||||||
|
"javascript": {
|
||||||
|
"framework": "react",
|
||||||
|
"config": {
|
||||||
|
"SourceDir": "src",
|
||||||
|
"DistributionDir": "build",
|
||||||
|
"BuildCommand": "npm run-script build",
|
||||||
|
"StartCommand": "npm run-script start"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"providers": [
|
||||||
|
"awscloudformation"
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,369 @@
|
|||||||
|
AWSTemplateFormatVersion: 2010-09-09
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
env:
|
||||||
|
Type: String
|
||||||
|
authRoleArn:
|
||||||
|
Type: String
|
||||||
|
unauthRoleArn:
|
||||||
|
Type: String
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
identityPoolName:
|
||||||
|
Type: String
|
||||||
|
|
||||||
|
allowUnauthenticatedIdentities:
|
||||||
|
Type: String
|
||||||
|
|
||||||
|
resourceNameTruncated:
|
||||||
|
Type: String
|
||||||
|
|
||||||
|
userPoolName:
|
||||||
|
Type: String
|
||||||
|
|
||||||
|
autoVerifiedAttributes:
|
||||||
|
Type: CommaDelimitedList
|
||||||
|
|
||||||
|
mfaConfiguration:
|
||||||
|
Type: String
|
||||||
|
|
||||||
|
mfaTypes:
|
||||||
|
Type: CommaDelimitedList
|
||||||
|
|
||||||
|
smsAuthenticationMessage:
|
||||||
|
Type: String
|
||||||
|
|
||||||
|
smsVerificationMessage:
|
||||||
|
Type: String
|
||||||
|
|
||||||
|
emailVerificationSubject:
|
||||||
|
Type: String
|
||||||
|
|
||||||
|
emailVerificationMessage:
|
||||||
|
Type: String
|
||||||
|
|
||||||
|
defaultPasswordPolicy:
|
||||||
|
Type: String
|
||||||
|
|
||||||
|
passwordPolicyMinLength:
|
||||||
|
Type: Number
|
||||||
|
|
||||||
|
passwordPolicyCharacters:
|
||||||
|
Type: CommaDelimitedList
|
||||||
|
|
||||||
|
requiredAttributes:
|
||||||
|
Type: CommaDelimitedList
|
||||||
|
|
||||||
|
userpoolClientGenerateSecret:
|
||||||
|
Type: String
|
||||||
|
|
||||||
|
userpoolClientRefreshTokenValidity:
|
||||||
|
Type: Number
|
||||||
|
|
||||||
|
userpoolClientWriteAttributes:
|
||||||
|
Type: CommaDelimitedList
|
||||||
|
|
||||||
|
userpoolClientReadAttributes:
|
||||||
|
Type: CommaDelimitedList
|
||||||
|
|
||||||
|
userpoolClientLambdaRole:
|
||||||
|
Type: String
|
||||||
|
|
||||||
|
userpoolClientSetAttributes:
|
||||||
|
Type: String
|
||||||
|
|
||||||
|
resourceName:
|
||||||
|
Type: String
|
||||||
|
|
||||||
|
authSelections:
|
||||||
|
Type: String
|
||||||
|
|
||||||
|
useDefault:
|
||||||
|
Type: String
|
||||||
|
|
||||||
|
usernameAttributes:
|
||||||
|
Type: CommaDelimitedList
|
||||||
|
|
||||||
|
userPoolGroupList:
|
||||||
|
Type: CommaDelimitedList
|
||||||
|
|
||||||
|
dependsOn:
|
||||||
|
Type: CommaDelimitedList
|
||||||
|
|
||||||
|
Conditions:
|
||||||
|
ShouldNotCreateEnvResources: !Equals [ !Ref env, NONE ]
|
||||||
|
|
||||||
|
Resources:
|
||||||
|
|
||||||
|
|
||||||
|
# BEGIN SNS ROLE RESOURCE
|
||||||
|
SNSRole:
|
||||||
|
# Created to allow the UserPool SMS Config to publish via the Simple Notification Service during MFA Process
|
||||||
|
Type: AWS::IAM::Role
|
||||||
|
Properties:
|
||||||
|
RoleName: !If [ShouldNotCreateEnvResources, 'hpiotr8c9024fb_sns-role', !Join ['',[ 'sns', !Select [3, !Split ['-', !Ref 'AWS::StackName']], '-', !Ref env]]]
|
||||||
|
AssumeRolePolicyDocument:
|
||||||
|
Version: "2012-10-17"
|
||||||
|
Statement:
|
||||||
|
- Sid: ""
|
||||||
|
Effect: "Allow"
|
||||||
|
Principal:
|
||||||
|
Service: "cognito-idp.amazonaws.com"
|
||||||
|
Action:
|
||||||
|
- "sts:AssumeRole"
|
||||||
|
Condition:
|
||||||
|
StringEquals:
|
||||||
|
sts:ExternalId: hpiotr8c9024fb_role_external_id
|
||||||
|
Policies:
|
||||||
|
-
|
||||||
|
PolicyName: hpiotr8c9024fb-sns-policy
|
||||||
|
PolicyDocument:
|
||||||
|
Version: "2012-10-17"
|
||||||
|
Statement:
|
||||||
|
-
|
||||||
|
Effect: "Allow"
|
||||||
|
Action:
|
||||||
|
- "sns:Publish"
|
||||||
|
Resource: "*"
|
||||||
|
# BEGIN USER POOL RESOURCES
|
||||||
|
UserPool:
|
||||||
|
# Created upon user selection
|
||||||
|
# Depends on SNS Role for Arn if MFA is enabled
|
||||||
|
Type: AWS::Cognito::UserPool
|
||||||
|
UpdateReplacePolicy: Retain
|
||||||
|
Properties:
|
||||||
|
UserPoolName: !If [ShouldNotCreateEnvResources, !Ref userPoolName, !Join ['',[!Ref userPoolName, '-', !Ref env]]]
|
||||||
|
|
||||||
|
Schema:
|
||||||
|
|
||||||
|
-
|
||||||
|
Name: email
|
||||||
|
Required: true
|
||||||
|
Mutable: true
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
AutoVerifiedAttributes: !Ref autoVerifiedAttributes
|
||||||
|
|
||||||
|
|
||||||
|
EmailVerificationMessage: !Ref emailVerificationMessage
|
||||||
|
EmailVerificationSubject: !Ref emailVerificationSubject
|
||||||
|
|
||||||
|
Policies:
|
||||||
|
PasswordPolicy:
|
||||||
|
MinimumLength: !Ref passwordPolicyMinLength
|
||||||
|
RequireLowercase: false
|
||||||
|
RequireNumbers: false
|
||||||
|
RequireSymbols: false
|
||||||
|
RequireUppercase: false
|
||||||
|
|
||||||
|
UsernameAttributes: !Ref usernameAttributes
|
||||||
|
|
||||||
|
MfaConfiguration: !Ref mfaConfiguration
|
||||||
|
SmsVerificationMessage: !Ref smsVerificationMessage
|
||||||
|
SmsConfiguration:
|
||||||
|
SnsCallerArn: !GetAtt SNSRole.Arn
|
||||||
|
ExternalId: hpiotr8c9024fb_role_external_id
|
||||||
|
|
||||||
|
|
||||||
|
UserPoolClientWeb:
|
||||||
|
# Created provide application access to user pool
|
||||||
|
# Depends on UserPool for ID reference
|
||||||
|
Type: "AWS::Cognito::UserPoolClient"
|
||||||
|
Properties:
|
||||||
|
ClientName: hpiotr8c9024fb_app_clientWeb
|
||||||
|
|
||||||
|
RefreshTokenValidity: !Ref userpoolClientRefreshTokenValidity
|
||||||
|
UserPoolId: !Ref UserPool
|
||||||
|
DependsOn: UserPool
|
||||||
|
UserPoolClient:
|
||||||
|
# Created provide application access to user pool
|
||||||
|
# Depends on UserPool for ID reference
|
||||||
|
Type: "AWS::Cognito::UserPoolClient"
|
||||||
|
Properties:
|
||||||
|
ClientName: hpiotr8c9024fb_app_client
|
||||||
|
|
||||||
|
GenerateSecret: !Ref userpoolClientGenerateSecret
|
||||||
|
RefreshTokenValidity: !Ref userpoolClientRefreshTokenValidity
|
||||||
|
UserPoolId: !Ref UserPool
|
||||||
|
DependsOn: UserPool
|
||||||
|
# BEGIN USER POOL LAMBDA RESOURCES
|
||||||
|
UserPoolClientRole:
|
||||||
|
# Created to execute Lambda which gets userpool app client config values
|
||||||
|
Type: 'AWS::IAM::Role'
|
||||||
|
Properties:
|
||||||
|
RoleName: !If [ShouldNotCreateEnvResources, !Ref userpoolClientLambdaRole, !Join ['',['upClientLambdaRole', !Select [3, !Split ['-', !Ref 'AWS::StackName']], '-', !Ref env]]]
|
||||||
|
AssumeRolePolicyDocument:
|
||||||
|
Version: '2012-10-17'
|
||||||
|
Statement:
|
||||||
|
- Effect: Allow
|
||||||
|
Principal:
|
||||||
|
Service:
|
||||||
|
- lambda.amazonaws.com
|
||||||
|
Action:
|
||||||
|
- 'sts:AssumeRole'
|
||||||
|
DependsOn: UserPoolClient
|
||||||
|
UserPoolClientLambda:
|
||||||
|
# Lambda which gets userpool app client config values
|
||||||
|
# Depends on UserPool for id
|
||||||
|
# Depends on UserPoolClientRole for role ARN
|
||||||
|
Type: 'AWS::Lambda::Function'
|
||||||
|
Properties:
|
||||||
|
Code:
|
||||||
|
ZipFile: !Join
|
||||||
|
- |+
|
||||||
|
- - 'const response = require(''cfn-response'');'
|
||||||
|
- 'const aws = require(''aws-sdk'');'
|
||||||
|
- 'const identity = new aws.CognitoIdentityServiceProvider();'
|
||||||
|
- 'exports.handler = (event, context, callback) => {'
|
||||||
|
- ' if (event.RequestType == ''Delete'') { '
|
||||||
|
- ' response.send(event, context, response.SUCCESS, {})'
|
||||||
|
- ' }'
|
||||||
|
- ' if (event.RequestType == ''Update'' || event.RequestType == ''Create'') {'
|
||||||
|
- ' const params = {'
|
||||||
|
- ' ClientId: event.ResourceProperties.clientId,'
|
||||||
|
- ' UserPoolId: event.ResourceProperties.userpoolId'
|
||||||
|
- ' };'
|
||||||
|
- ' identity.describeUserPoolClient(params).promise()'
|
||||||
|
- ' .then((res) => {'
|
||||||
|
- ' response.send(event, context, response.SUCCESS, {''appSecret'': res.UserPoolClient.ClientSecret});'
|
||||||
|
- ' })'
|
||||||
|
- ' .catch((err) => {'
|
||||||
|
- ' response.send(event, context, response.FAILED, {err});'
|
||||||
|
- ' });'
|
||||||
|
- ' }'
|
||||||
|
- '};'
|
||||||
|
Handler: index.handler
|
||||||
|
Runtime: nodejs10.x
|
||||||
|
Timeout: '300'
|
||||||
|
Role: !GetAtt
|
||||||
|
- UserPoolClientRole
|
||||||
|
- Arn
|
||||||
|
DependsOn: UserPoolClientRole
|
||||||
|
UserPoolClientLambdaPolicy:
|
||||||
|
# Sets userpool policy for the role that executes the Userpool Client Lambda
|
||||||
|
# Depends on UserPool for Arn
|
||||||
|
# Marked as depending on UserPoolClientRole for easier to understand CFN sequencing
|
||||||
|
Type: 'AWS::IAM::Policy'
|
||||||
|
Properties:
|
||||||
|
PolicyName: hpiotr8c9024fb_userpoolclient_lambda_iam_policy
|
||||||
|
Roles:
|
||||||
|
- !Ref UserPoolClientRole
|
||||||
|
PolicyDocument:
|
||||||
|
Version: '2012-10-17'
|
||||||
|
Statement:
|
||||||
|
- Effect: Allow
|
||||||
|
Action:
|
||||||
|
- 'cognito-idp:DescribeUserPoolClient'
|
||||||
|
Resource: !GetAtt UserPool.Arn
|
||||||
|
DependsOn: UserPoolClientLambda
|
||||||
|
UserPoolClientLogPolicy:
|
||||||
|
# Sets log policy for the role that executes the Userpool Client Lambda
|
||||||
|
# Depends on UserPool for Arn
|
||||||
|
# Marked as depending on UserPoolClientLambdaPolicy for easier to understand CFN sequencing
|
||||||
|
Type: 'AWS::IAM::Policy'
|
||||||
|
Properties:
|
||||||
|
PolicyName: hpiotr8c9024fb_userpoolclient_lambda_log_policy
|
||||||
|
Roles:
|
||||||
|
- !Ref UserPoolClientRole
|
||||||
|
PolicyDocument:
|
||||||
|
Version: 2012-10-17
|
||||||
|
Statement:
|
||||||
|
- Effect: Allow
|
||||||
|
Action:
|
||||||
|
- 'logs:CreateLogGroup'
|
||||||
|
- 'logs:CreateLogStream'
|
||||||
|
- 'logs:PutLogEvents'
|
||||||
|
Resource: !Sub
|
||||||
|
- arn:aws:logs:${region}:${account}:log-group:/aws/lambda/${lambda}:log-stream:*
|
||||||
|
- { region: !Ref "AWS::Region", account: !Ref "AWS::AccountId", lambda: !Ref UserPoolClientLambda}
|
||||||
|
DependsOn: UserPoolClientLambdaPolicy
|
||||||
|
UserPoolClientInputs:
|
||||||
|
# Values passed to Userpool client Lambda
|
||||||
|
# Depends on UserPool for Id
|
||||||
|
# Depends on UserPoolClient for Id
|
||||||
|
# Marked as depending on UserPoolClientLambdaPolicy for easier to understand CFN sequencing
|
||||||
|
Type: 'Custom::LambdaCallout'
|
||||||
|
Properties:
|
||||||
|
ServiceToken: !GetAtt UserPoolClientLambda.Arn
|
||||||
|
clientId: !Ref UserPoolClient
|
||||||
|
userpoolId: !Ref UserPool
|
||||||
|
DependsOn: UserPoolClientLogPolicy
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# BEGIN IDENTITY POOL RESOURCES
|
||||||
|
|
||||||
|
|
||||||
|
IdentityPool:
|
||||||
|
# Always created
|
||||||
|
Type: AWS::Cognito::IdentityPool
|
||||||
|
Properties:
|
||||||
|
IdentityPoolName: !If [ShouldNotCreateEnvResources, 'hpiotreact8c9024fb_identitypool_8c9024fb', !Join ['',['hpiotreact8c9024fb_identitypool_8c9024fb', '__', !Ref env]]]
|
||||||
|
|
||||||
|
CognitoIdentityProviders:
|
||||||
|
- ClientId: !Ref UserPoolClient
|
||||||
|
ProviderName: !Sub
|
||||||
|
- cognito-idp.${region}.amazonaws.com/${client}
|
||||||
|
- { region: !Ref "AWS::Region", client: !Ref UserPool}
|
||||||
|
- ClientId: !Ref UserPoolClientWeb
|
||||||
|
ProviderName: !Sub
|
||||||
|
- cognito-idp.${region}.amazonaws.com/${client}
|
||||||
|
- { region: !Ref "AWS::Region", client: !Ref UserPool}
|
||||||
|
|
||||||
|
AllowUnauthenticatedIdentities: !Ref allowUnauthenticatedIdentities
|
||||||
|
|
||||||
|
|
||||||
|
DependsOn: UserPoolClientInputs
|
||||||
|
|
||||||
|
|
||||||
|
IdentityPoolRoleMap:
|
||||||
|
# Created to map Auth and Unauth roles to the identity pool
|
||||||
|
# Depends on Identity Pool for ID ref
|
||||||
|
Type: AWS::Cognito::IdentityPoolRoleAttachment
|
||||||
|
Properties:
|
||||||
|
IdentityPoolId: !Ref IdentityPool
|
||||||
|
Roles:
|
||||||
|
unauthenticated: !Ref unauthRoleArn
|
||||||
|
authenticated: !Ref authRoleArn
|
||||||
|
DependsOn: IdentityPool
|
||||||
|
|
||||||
|
|
||||||
|
Outputs :
|
||||||
|
|
||||||
|
IdentityPoolId:
|
||||||
|
Value: !Ref 'IdentityPool'
|
||||||
|
Description: Id for the identity pool
|
||||||
|
IdentityPoolName:
|
||||||
|
Value: !GetAtt IdentityPool.Name
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
UserPoolId:
|
||||||
|
Value: !Ref 'UserPool'
|
||||||
|
Description: Id for the user pool
|
||||||
|
UserPoolName:
|
||||||
|
Value: !Ref userPoolName
|
||||||
|
AppClientIDWeb:
|
||||||
|
Value: !Ref 'UserPoolClientWeb'
|
||||||
|
Description: The user pool app client id for web
|
||||||
|
AppClientID:
|
||||||
|
Value: !Ref 'UserPoolClient'
|
||||||
|
Description: The user pool app client id
|
||||||
|
AppClientSecret:
|
||||||
|
Value: !GetAtt UserPoolClientInputs.appSecret
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
53
amplify/backend/auth/hpiotreact8c9024fb/parameters.json
Normal file
53
amplify/backend/auth/hpiotreact8c9024fb/parameters.json
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
{
|
||||||
|
"identityPoolName": "hpiotreact8c9024fb_identitypool_8c9024fb",
|
||||||
|
"allowUnauthenticatedIdentities": false,
|
||||||
|
"resourceNameTruncated": "hpiotr8c9024fb",
|
||||||
|
"userPoolName": "hpiotreact8c9024fb_userpool_8c9024fb",
|
||||||
|
"autoVerifiedAttributes": [
|
||||||
|
"email"
|
||||||
|
],
|
||||||
|
"mfaConfiguration": "OFF",
|
||||||
|
"mfaTypes": [
|
||||||
|
"SMS Text Message"
|
||||||
|
],
|
||||||
|
"smsAuthenticationMessage": "Your authentication code is {####}",
|
||||||
|
"smsVerificationMessage": "Your verification code is {####}",
|
||||||
|
"emailVerificationSubject": "Your verification code",
|
||||||
|
"emailVerificationMessage": "Your verification code is {####}",
|
||||||
|
"defaultPasswordPolicy": false,
|
||||||
|
"passwordPolicyMinLength": 8,
|
||||||
|
"passwordPolicyCharacters": [],
|
||||||
|
"requiredAttributes": [
|
||||||
|
"email"
|
||||||
|
],
|
||||||
|
"userpoolClientGenerateSecret": true,
|
||||||
|
"userpoolClientRefreshTokenValidity": 30,
|
||||||
|
"userpoolClientWriteAttributes": [
|
||||||
|
"email"
|
||||||
|
],
|
||||||
|
"userpoolClientReadAttributes": [
|
||||||
|
"email"
|
||||||
|
],
|
||||||
|
"userpoolClientLambdaRole": "hpiotr8c9024fb_userpoolclient_lambda_role",
|
||||||
|
"userpoolClientSetAttributes": false,
|
||||||
|
"resourceName": "hpiotreact8c9024fb",
|
||||||
|
"authSelections": "identityPoolAndUserPool",
|
||||||
|
"authRoleArn": {
|
||||||
|
"Fn::GetAtt": [
|
||||||
|
"AuthRole",
|
||||||
|
"Arn"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"unauthRoleArn": {
|
||||||
|
"Fn::GetAtt": [
|
||||||
|
"UnauthRole",
|
||||||
|
"Arn"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"useDefault": "default",
|
||||||
|
"usernameAttributes": [
|
||||||
|
"email"
|
||||||
|
],
|
||||||
|
"userPoolGroupList": [],
|
||||||
|
"dependsOn": []
|
||||||
|
}
|
||||||
16
amplify/backend/backend-config.json
Normal file
16
amplify/backend/backend-config.json
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"hosting": {
|
||||||
|
"S3AndCloudFront": {
|
||||||
|
"service": "S3AndCloudFront",
|
||||||
|
"providerPlugin": "awscloudformation"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"auth": {
|
||||||
|
"hpiotreact8c9024fb": {
|
||||||
|
"service": "Cognito",
|
||||||
|
"providerPlugin": "awscloudformation",
|
||||||
|
"dependsOn": [],
|
||||||
|
"customAuth": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
3
amplify/backend/hosting/S3AndCloudFront/parameters.json
Normal file
3
amplify/backend/hosting/S3AndCloudFront/parameters.json
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"bucketName": "hpiot-react"
|
||||||
|
}
|
||||||
113
amplify/backend/hosting/S3AndCloudFront/template.json
Normal file
113
amplify/backend/hosting/S3AndCloudFront/template.json
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
{
|
||||||
|
"AWSTemplateFormatVersion": "2010-09-09",
|
||||||
|
"Description": "Hosting resource stack creation using Amplify CLI",
|
||||||
|
"Parameters": {
|
||||||
|
"env": {
|
||||||
|
"Type": "String"
|
||||||
|
},
|
||||||
|
"bucketName": {
|
||||||
|
"Type": "String"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Conditions": {
|
||||||
|
"ShouldNotCreateEnvResources": {
|
||||||
|
"Fn::Equals": [
|
||||||
|
{
|
||||||
|
"Ref": "env"
|
||||||
|
},
|
||||||
|
"NONE"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Resources": {
|
||||||
|
"S3Bucket": {
|
||||||
|
"Type": "AWS::S3::Bucket",
|
||||||
|
"DeletionPolicy": "Retain",
|
||||||
|
"Properties": {
|
||||||
|
"BucketName": {
|
||||||
|
"Fn::If": [
|
||||||
|
"ShouldNotCreateEnvResources",
|
||||||
|
{
|
||||||
|
"Ref": "bucketName"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Fn::Join": [
|
||||||
|
"",
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"Ref": "bucketName"
|
||||||
|
},
|
||||||
|
"-",
|
||||||
|
{
|
||||||
|
"Ref": "env"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"AccessControl": "Private",
|
||||||
|
"WebsiteConfiguration": {
|
||||||
|
"IndexDocument": "index.html",
|
||||||
|
"ErrorDocument": "index.html"
|
||||||
|
},
|
||||||
|
"CorsConfiguration": {
|
||||||
|
"CorsRules": [
|
||||||
|
{
|
||||||
|
"AllowedHeaders": [
|
||||||
|
"Authorization",
|
||||||
|
"Content-Length"
|
||||||
|
],
|
||||||
|
"AllowedMethods": [
|
||||||
|
"GET"
|
||||||
|
],
|
||||||
|
"AllowedOrigins": [
|
||||||
|
"*"
|
||||||
|
],
|
||||||
|
"MaxAge": 3000
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Outputs": {
|
||||||
|
"Region": {
|
||||||
|
"Value": {
|
||||||
|
"Ref": "AWS::Region"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"HostingBucketName": {
|
||||||
|
"Description": "Hosting bucket name",
|
||||||
|
"Value": {
|
||||||
|
"Ref": "S3Bucket"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"WebsiteURL": {
|
||||||
|
"Value": {
|
||||||
|
"Fn::GetAtt": [
|
||||||
|
"S3Bucket",
|
||||||
|
"WebsiteURL"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"Description": "URL for website hosted on S3"
|
||||||
|
},
|
||||||
|
"S3BucketSecureURL": {
|
||||||
|
"Value": {
|
||||||
|
"Fn::Join": [
|
||||||
|
"",
|
||||||
|
[
|
||||||
|
"https://",
|
||||||
|
{
|
||||||
|
"Fn::GetAtt": [
|
||||||
|
"S3Bucket",
|
||||||
|
"DomainName"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"Description": "Name of S3 bucket to hold website content"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
20
amplify/team-provider-info.json
Normal file
20
amplify/team-provider-info.json
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"hpiot": {
|
||||||
|
"awscloudformation": {
|
||||||
|
"AuthRoleName": "amplify-hpiot-react-hpiot-162610-authRole",
|
||||||
|
"UnauthRoleArn": "arn:aws:iam::860246592755:role/amplify-hpiot-react-hpiot-162610-unauthRole",
|
||||||
|
"AuthRoleArn": "arn:aws:iam::860246592755:role/amplify-hpiot-react-hpiot-162610-authRole",
|
||||||
|
"Region": "us-east-1",
|
||||||
|
"DeploymentBucketName": "amplify-hpiot-react-hpiot-162610-deployment",
|
||||||
|
"UnauthRoleName": "amplify-hpiot-react-hpiot-162610-unauthRole",
|
||||||
|
"StackName": "amplify-hpiot-react-hpiot-162610",
|
||||||
|
"StackId": "arn:aws:cloudformation:us-east-1:860246592755:stack/amplify-hpiot-react-hpiot-162610/1913c1f0-64a8-11ea-baa2-0ee5b74c6229",
|
||||||
|
"AmplifyAppId": "d3hyexpjn33q6q"
|
||||||
|
},
|
||||||
|
"categories": {
|
||||||
|
"auth": {
|
||||||
|
"hpiotreact8c9024fb": {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
4109
package-lock.json
generated
4109
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
11
package.json
11
package.json
@@ -6,9 +6,14 @@
|
|||||||
"@testing-library/jest-dom": "^4.2.4",
|
"@testing-library/jest-dom": "^4.2.4",
|
||||||
"@testing-library/react": "^9.5.0",
|
"@testing-library/react": "^9.5.0",
|
||||||
"@testing-library/user-event": "^7.2.1",
|
"@testing-library/user-event": "^7.2.1",
|
||||||
"react": "^16.13.0",
|
"aws-amplify": "^2.2.6",
|
||||||
"react-dom": "^16.13.0",
|
"aws-amplify-react": "^3.1.7",
|
||||||
"react-scripts": "3.4.0"
|
"npx": "^10.2.2",
|
||||||
|
"react": "^16.13.1",
|
||||||
|
"react-charts": "^2.0.0-beta.6",
|
||||||
|
"react-dom": "^16.13.1",
|
||||||
|
"react-scripts": "3.4.0",
|
||||||
|
"recharts": "^1.8.5"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "react-scripts start",
|
"start": "react-scripts start",
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
|
|
||||||
.App-header {
|
.App-header {
|
||||||
background-color: #282c34;
|
background-color: #282c34;
|
||||||
min-height: 100vh;
|
min-height: 4vh;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|||||||
165
src/App.js
165
src/App.js
@@ -1,26 +1,163 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import logo from './logo.svg';
|
|
||||||
import './App.css';
|
import './App.css';
|
||||||
|
import LineChart from './charts/LineChart';
|
||||||
|
import BarChart from './charts/BarChart';
|
||||||
|
import { WebSocketSubject } from 'rxjs/webSocket';
|
||||||
|
import { Subject } from 'rxjs';
|
||||||
|
import Amplify from 'aws-amplify';
|
||||||
|
import awsconfig from './aws-exports';
|
||||||
|
import { withAuthenticator } from 'aws-amplify-react'; // or 'aws-amplify-react-native';
|
||||||
|
import {Auth} from 'aws-amplify';
|
||||||
|
Amplify.configure(awsconfig);
|
||||||
|
|
||||||
|
|
||||||
|
let serverMessages = [];
|
||||||
|
let socket$ = new WebSocketSubject();
|
||||||
|
let roles = [];
|
||||||
|
let groups = [];
|
||||||
|
let currentRole = "";
|
||||||
|
let roleSubject = new Subject();
|
||||||
|
let token = "";
|
||||||
|
|
||||||
|
|
||||||
|
function connect() {
|
||||||
|
connectWS(token, currentRole);
|
||||||
|
subscribeWS();
|
||||||
|
socket$.next({action: 'getDashboardData', policy: currentRole});
|
||||||
|
}
|
||||||
|
|
||||||
|
function connectWS(token, role) {
|
||||||
|
socket$ = new WebSocketSubject('wss://3fseaywb8b.execute-api.us-east-1.amazonaws.com/prototype?token=' + token +
|
||||||
|
'&role=' + role);
|
||||||
|
//console.log(socket$);
|
||||||
|
}
|
||||||
|
|
||||||
|
function subscribeWS() {
|
||||||
|
socket$.subscribe((message) => {
|
||||||
|
console.log(message);
|
||||||
|
if (message instanceof Array) {
|
||||||
|
message.forEach(element => {
|
||||||
|
updateList(element);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
updateList(message);
|
||||||
|
}
|
||||||
|
serverMessages.sort((a, b) => a.location.localeCompare(b.location));
|
||||||
|
console.log(serverMessages);
|
||||||
|
},
|
||||||
|
(err) => console.error(err),
|
||||||
|
() => console.warn('Complete: Websocket closed')
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
function updateList(obj) {
|
||||||
|
//console.log(serverMessages);
|
||||||
|
//console.log(obj);
|
||||||
|
const index = serverMessages.findIndex((e) => e.location === obj.location);
|
||||||
|
|
||||||
|
if (index === -1) {
|
||||||
|
serverMessages.push(obj);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
Object.keys(obj).forEach(element => {
|
||||||
|
serverMessages[index][element] = obj[element];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function setRole(index) {
|
||||||
|
currentRole = roles[index];
|
||||||
|
roleSubject.next(currentRole);
|
||||||
|
socket$.complete();
|
||||||
|
serverMessages = [];
|
||||||
|
connect();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class Dashboard extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
promiseIsResolved: false
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
updateList(obj) {
|
||||||
|
//console.log(serverMessages);
|
||||||
|
//console.log(obj);
|
||||||
|
const index = serverMessages.findIndex((e) => e.location === obj.location);
|
||||||
|
|
||||||
|
if (index === -1) {
|
||||||
|
serverMessages.push(obj);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
Object.keys(obj).forEach(element => {
|
||||||
|
serverMessages[index][element] = obj[element];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
componentDidMount(){
|
||||||
|
Auth.currentAuthenticatedUser().then(data => {
|
||||||
|
//console.log(data);
|
||||||
|
roles = data.signInUserSession.idToken.payload['cognito:roles'];
|
||||||
|
groups = data.signInUserSession.idToken.payload['cognito:groups'];
|
||||||
|
groups.forEach( (element, index, array) => {
|
||||||
|
array[index] = element.replace(/_/g, ' ');
|
||||||
|
});
|
||||||
|
currentRole = data.signInUserSession.idToken.payload['cognito:roles'][0];
|
||||||
|
token = data.signInUserSession.accessToken.jwtToken;
|
||||||
|
roleSubject.subscribe({
|
||||||
|
next: r => r
|
||||||
|
});
|
||||||
|
socket$ = new WebSocketSubject('wss://3fseaywb8b.execute-api.us-east-1.amazonaws.com/prototype?token=' + token +
|
||||||
|
'&role=' + currentRole);
|
||||||
|
socket$.subscribe((message) => {
|
||||||
|
console.log(message);
|
||||||
|
if (message instanceof Array) {
|
||||||
|
message.forEach(element => {
|
||||||
|
this.updateList(element);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.updateList(message);
|
||||||
|
}
|
||||||
|
serverMessages.sort((a, b) => a.location.localeCompare(b.location));
|
||||||
|
this.setState({promiseIsResolved: true});
|
||||||
|
console.log(serverMessages);
|
||||||
|
},
|
||||||
|
(err) => console.error(err),
|
||||||
|
() => console.warn('Complete: Websocket closed')
|
||||||
|
);
|
||||||
|
socket$.next({action: 'getDashboardData', policy: currentRole});
|
||||||
|
|
||||||
|
}).catch((err) =>
|
||||||
|
err
|
||||||
|
);
|
||||||
|
}
|
||||||
|
render() {
|
||||||
|
if(!this.state.promiseIsResolved){return null}
|
||||||
|
else{
|
||||||
|
return (
|
||||||
|
<div className="Dashboard">
|
||||||
|
<BarChart data = {serverMessages}/>
|
||||||
|
<LineChart data = {serverMessages}/>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
return (
|
return (
|
||||||
<div className="App">
|
<div className="App">
|
||||||
<header className="App-header">
|
<header className="App-header">
|
||||||
<img src={logo} className="App-logo" alt="logo" />
|
<div className="Nav-bar"><p>This is where the nav-bar will be</p></div>
|
||||||
<p>
|
|
||||||
Edit <code>src/App.js</code> and save to reload.
|
|
||||||
</p>
|
|
||||||
<a
|
|
||||||
className="App-link"
|
|
||||||
href="https://reactjs.org"
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
>
|
|
||||||
Learn React
|
|
||||||
</a>
|
|
||||||
</header>
|
</header>
|
||||||
|
<Dashboard />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default App;
|
export default withAuthenticator(App, {includeGreetings: true});
|
||||||
|
|||||||
16
src/aws-exports-old.js
Normal file
16
src/aws-exports-old.js
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
// WARNING: DO NOT EDIT. This file is automatically generated by AWS Amplify. It will be overwritten.
|
||||||
|
|
||||||
|
const awsmobile = {
|
||||||
|
"aws_project_region": "us-east-1",
|
||||||
|
"aws_content_delivery_bucket": "hpiot-react-hpiot",
|
||||||
|
"aws_content_delivery_bucket_region": "us-east-1",
|
||||||
|
"aws_content_delivery_url": "http://hpiot-react-hpiot.s3-website-us-east-1.amazonaws.com",
|
||||||
|
"aws_cognito_identity_pool_id": "us-east-1:20972146-c6fe-4ada-a723-d1debcc7d074",
|
||||||
|
"aws_cognito_region": "us-east-1",
|
||||||
|
"aws_user_pools_id": "us-east-1_L6XsGIASX",
|
||||||
|
"aws_user_pools_web_client_id": "63ieddff77nfc3i151m8l8k3ip",
|
||||||
|
"oauth": {}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export default awsmobile;
|
||||||
35
src/charts/BarChart.js
Normal file
35
src/charts/BarChart.js
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
import React, { PureComponent } from 'react';
|
||||||
|
import {
|
||||||
|
BarChart, Bar, Cell, XAxis, YAxis, CartesianGrid, Tooltip, Legend,
|
||||||
|
} from 'recharts';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
export default class Example extends PureComponent {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
data: this.props.data,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<BarChart
|
||||||
|
width={1000}
|
||||||
|
height={600}
|
||||||
|
data={this.state.data}
|
||||||
|
margin={{
|
||||||
|
top: 5, right: 30, left: 20, bottom: 5,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<CartesianGrid strokeDasharray="3 3" />
|
||||||
|
<XAxis dataKey="location" />
|
||||||
|
<YAxis />
|
||||||
|
<Tooltip />
|
||||||
|
<Legend />
|
||||||
|
<Bar dataKey="volumeflow" fill="#8884d8" />
|
||||||
|
<Bar dataKey="depth" fill="#82ca9d" />
|
||||||
|
</BarChart>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
142
src/charts/LineChart.js
Normal file
142
src/charts/LineChart.js
Normal file
@@ -0,0 +1,142 @@
|
|||||||
|
import React, { PureComponent } from 'react';
|
||||||
|
import {
|
||||||
|
Label, LineChart, Line, CartesianGrid, XAxis, YAxis, Tooltip, ReferenceArea,
|
||||||
|
} from 'recharts';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const getAxisYDomain = (from, to, ref, offset, data) => {
|
||||||
|
const refData = data.slice(from - 1, to);
|
||||||
|
let [bottom, top] = [refData[0][ref], refData[0][ref]];
|
||||||
|
refData.forEach((d) => {
|
||||||
|
if (d[ref] > top) top = d[ref];
|
||||||
|
if (d[ref] < bottom) bottom = d[ref];
|
||||||
|
});
|
||||||
|
|
||||||
|
return [(bottom | 0) - offset, (top | 0) + offset];
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export default class Example extends PureComponent {
|
||||||
|
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
data: this.props.data,
|
||||||
|
left: 'dataMin',
|
||||||
|
right: 'dataMax',
|
||||||
|
refAreaLeft: '',
|
||||||
|
refAreaRight: '',
|
||||||
|
top: 'dataMax+1',
|
||||||
|
bottom: 'dataMin-1',
|
||||||
|
top2: 'dataMax+20',
|
||||||
|
bottom2: 'dataMin-20',
|
||||||
|
animation: true,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
zoom() {
|
||||||
|
let { refAreaLeft, refAreaRight, data } = this.state;
|
||||||
|
|
||||||
|
if (refAreaLeft === refAreaRight || refAreaRight === '') {
|
||||||
|
this.setState(() => ({
|
||||||
|
refAreaLeft: '',
|
||||||
|
refAreaRight: '',
|
||||||
|
}));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// xAxis domain
|
||||||
|
if (refAreaLeft > refAreaRight) [refAreaLeft, refAreaRight] = [refAreaRight, refAreaLeft];
|
||||||
|
|
||||||
|
// yAxis domain
|
||||||
|
const [bottom, top] = getAxisYDomain(refAreaLeft, refAreaRight, 'volumeflow', 5, this.state.data);
|
||||||
|
const [bottom2, top2] = getAxisYDomain(refAreaLeft, refAreaRight, 'depth', 50, this.state.data);
|
||||||
|
|
||||||
|
this.setState(() => ({
|
||||||
|
refAreaLeft: '',
|
||||||
|
refAreaRight: '',
|
||||||
|
data: data.slice(),
|
||||||
|
left: refAreaLeft,
|
||||||
|
right: refAreaRight,
|
||||||
|
bottom,
|
||||||
|
top,
|
||||||
|
bottom2,
|
||||||
|
top2,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
zoomOut() {
|
||||||
|
const { data } = this.state;
|
||||||
|
this.setState(() => ({
|
||||||
|
data: data.slice(),
|
||||||
|
refAreaLeft: '',
|
||||||
|
refAreaRight: '',
|
||||||
|
left: 'dataMin',
|
||||||
|
right: 'dataMax',
|
||||||
|
top: 'dataMax+1',
|
||||||
|
bottom: 'dataMin',
|
||||||
|
top2: 'dataMax+50',
|
||||||
|
bottom2: 'dataMin+50',
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const {
|
||||||
|
data, barIndex, left, right, refAreaLeft, refAreaRight, top, bottom, top2, bottom2,
|
||||||
|
} = this.state;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="highlight-bar-charts" style={{ userSelect: 'none' }}>
|
||||||
|
<button
|
||||||
|
// href="javascript: void(0);"
|
||||||
|
className="btn update"
|
||||||
|
onClick={this.zoomOut.bind(this)}
|
||||||
|
>
|
||||||
|
Zoom Out
|
||||||
|
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<LineChart
|
||||||
|
width={800}
|
||||||
|
height={400}
|
||||||
|
data={data}
|
||||||
|
onMouseDown={e => this.setState({ refAreaLeft: e.activeLabel })}
|
||||||
|
onMouseMove={e => this.state.refAreaLeft && this.setState({ refAreaRight: e.activeLabel })}
|
||||||
|
onMouseUp={this.zoom.bind(this)}
|
||||||
|
>
|
||||||
|
<CartesianGrid strokeDasharray="3 3" />
|
||||||
|
<XAxis
|
||||||
|
allowDataOverflow
|
||||||
|
dataKey="timestamp"
|
||||||
|
domain={[left, right]}
|
||||||
|
type="number"
|
||||||
|
/>
|
||||||
|
<YAxis
|
||||||
|
allowDataOverflow
|
||||||
|
domain={[bottom, top]}
|
||||||
|
type="number"
|
||||||
|
yAxisId="1"
|
||||||
|
/>
|
||||||
|
<YAxis
|
||||||
|
orientation="right"
|
||||||
|
allowDataOverflow
|
||||||
|
domain={[bottom2, top2]}
|
||||||
|
type="number"
|
||||||
|
yAxisId="2"
|
||||||
|
/>
|
||||||
|
<Tooltip />
|
||||||
|
<Line yAxisId="1" type="natural" dataKey="volumeflow" stroke="#8884d8" animationDuration={300} />
|
||||||
|
<Line yAxisId="2" type="natural" dataKey="depth" stroke="#82ca9d" animationDuration={300} />
|
||||||
|
|
||||||
|
|
||||||
|
{
|
||||||
|
(refAreaLeft && refAreaRight) ? (
|
||||||
|
<ReferenceArea yAxisId="1" x1={refAreaLeft} x2={refAreaRight} strokeOpacity={0.3} />) : null
|
||||||
|
}
|
||||||
|
</LineChart>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user