├── .gitignore ├── AWS-EVENT-deploy-eks.sh ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── ON-YOUR-OWN-deploy-eks.sh ├── README.md ├── THIRD-PARTY-LICENSES.txt ├── buildspec.yaml ├── cdk ├── eks │ ├── .gitignore │ ├── .npmignore │ ├── README.md │ ├── bin │ │ └── eks.ts │ ├── cdk.json │ ├── jest.config.js │ ├── lib │ │ ├── eks-stack.ts │ │ └── node-role-policy-doc.ts │ ├── package.json │ ├── test │ │ └── eks.test.ts │ ├── tsconfig.json │ └── yarn.lock ├── lambda_authorizer │ └── package │ │ └── app.py └── root │ ├── .gitignore │ ├── .npmignore │ ├── README.md │ ├── bin │ └── root.ts │ ├── cdk.json │ ├── jest.config.js │ ├── lib │ ├── admin │ │ └── admin-stack.ts │ ├── apigateway-stack │ │ └── apigateway-stack.ts │ ├── baseline-infra │ │ └── baseline-infra-stack.ts │ ├── root-stack.ts │ ├── tenant-infra │ │ ├── codebuild-role-policy-doc.ts │ │ └── tenant-infra-stack.ts │ └── utils.ts │ ├── package.json │ ├── test │ └── root.test.ts │ ├── tsconfig.json │ └── yarn.lock ├── client └── web │ ├── admin │ ├── .browserslistrc │ ├── .dockerignore │ ├── .editorconfig │ ├── .gitignore │ ├── Dockerfile │ ├── README.md │ ├── amplify │ │ ├── .config │ │ │ └── project-config.json │ │ ├── README.md │ │ ├── backend │ │ │ ├── auth │ │ │ │ └── admin211a75b9 │ │ │ │ │ └── parameters.json │ │ │ ├── backend-config.json │ │ │ └── tags.json │ │ ├── cli.json │ │ └── team-provider-info.json │ ├── angular.json │ ├── codepipeline │ │ └── buildspec.yml │ ├── e2e │ │ ├── protractor.conf.js │ │ ├── src │ │ │ ├── app.e2e-spec.ts │ │ │ └── app.po.ts │ │ └── tsconfig.json │ ├── k8s │ │ ├── template.txt │ │ └── template.yaml │ ├── karma.conf.js │ ├── nginx.conf │ ├── package-lock.json │ ├── package.json │ ├── setenv.sh │ ├── src │ │ ├── app │ │ │ ├── _nav.ts │ │ │ ├── app-routing.module.ts │ │ │ ├── app.component.html │ │ │ ├── app.component.scss │ │ │ ├── app.component.spec.ts │ │ │ ├── app.component.ts │ │ │ ├── app.module.ts │ │ │ ├── cognito.guard.ts │ │ │ ├── containers │ │ │ │ ├── default-layout │ │ │ │ │ ├── default-layout.component.html │ │ │ │ │ ├── default-layout.component.ts │ │ │ │ │ └── index.ts │ │ │ │ └── index.ts │ │ │ ├── interceptors │ │ │ │ ├── auth.interceptor.ts │ │ │ │ └── index.ts │ │ │ ├── models │ │ │ │ └── greeting.ts │ │ │ ├── tenants │ │ │ │ ├── create.component.html │ │ │ │ ├── create.component.ts │ │ │ │ ├── models │ │ │ │ │ └── tenant.ts │ │ │ │ ├── tenant-detail.component.html │ │ │ │ ├── tenant-detail.component.ts │ │ │ │ ├── tenant-list.component.html │ │ │ │ ├── tenant-list.component.ts │ │ │ │ ├── tenant-routing.module.ts │ │ │ │ ├── tenant.module.ts │ │ │ │ └── tenant.service.ts │ │ │ ├── users │ │ │ │ ├── models │ │ │ │ │ └── user.ts │ │ │ │ ├── user-create │ │ │ │ │ ├── user-create.component.html │ │ │ │ │ └── user-create.component.ts │ │ │ │ ├── user-detail │ │ │ │ │ ├── user-detail.component.html │ │ │ │ │ └── user-detail.component.ts │ │ │ │ ├── user-list │ │ │ │ │ ├── user-list.component.html │ │ │ │ │ └── user-list.component.ts │ │ │ │ ├── users-routing.module.ts │ │ │ │ ├── users.module.ts │ │ │ │ └── users.service.ts │ │ │ └── views │ │ │ │ ├── auth │ │ │ │ ├── auth-routing.module.ts │ │ │ │ ├── auth.module.ts │ │ │ │ └── login-info │ │ │ │ │ ├── login-info.component.html │ │ │ │ │ ├── login-info.component.scss │ │ │ │ │ └── login-info.component.ts │ │ │ │ ├── dashboard │ │ │ │ ├── dashboard-routing.module.ts │ │ │ │ ├── dashboard.component.html │ │ │ │ ├── dashboard.component.ts │ │ │ │ └── dashboard.module.ts │ │ │ │ └── error │ │ │ │ ├── 404.component.html │ │ │ │ ├── 404.component.ts │ │ │ │ ├── 500.component.html │ │ │ │ ├── 500.component.ts │ │ │ │ ├── unauthorized.component.html │ │ │ │ ├── unauthorized.component.scss │ │ │ │ └── unauthorized.component.ts │ │ ├── assets │ │ │ ├── .gitkeep │ │ │ └── img │ │ │ │ └── brand │ │ │ │ ├── adminapp.png │ │ │ │ ├── logo.svg │ │ │ │ └── sygnet.svg │ │ ├── favicon.ico │ │ ├── index.html │ │ ├── main.ts │ │ ├── polyfills.ts │ │ ├── scss │ │ │ ├── _custom.scss │ │ │ ├── _variables.scss │ │ │ ├── style.scss │ │ │ └── vendors │ │ │ │ ├── _variables.scss │ │ │ │ └── chart.js │ │ │ │ └── chart.scss │ │ └── test.ts │ ├── tsconfig.app.json │ ├── tsconfig.json │ ├── tsconfig.spec.json │ ├── tslint.json │ └── yarn.lock │ └── application │ ├── .gitignore │ ├── Dockerfile │ ├── README.md │ ├── amplify │ ├── .config │ │ └── project-config.json │ ├── README.md │ ├── backend │ │ ├── auth │ │ │ └── application465cad6c │ │ │ │ └── parameters.json │ │ ├── backend-config.json │ │ └── tags.json │ ├── cli.json │ └── team-provider-info.json │ ├── angular.json │ ├── browserslist │ ├── e2e │ ├── app.e2e-spec.ts │ ├── app.po.ts │ └── tsconfig.e2e.json │ ├── k8s │ ├── template.txt │ └── template.yaml │ ├── karma.conf.js │ ├── nginx.conf │ ├── package-lock.json │ ├── package.json │ ├── protractor.conf.js │ ├── proxy-conf.json │ ├── src │ ├── app │ │ ├── _nav.ts │ │ ├── app.component.css │ │ ├── app.component.spec.ts │ │ ├── app.component.ts │ │ ├── app.module.ts │ │ ├── app.routing.ts │ │ ├── auth-info.ts │ │ ├── cognito.guard.ts │ │ ├── containers │ │ │ ├── default-layout │ │ │ │ ├── default-layout.component.html │ │ │ │ ├── default-layout.component.ts │ │ │ │ └── index.ts │ │ │ └── index.ts │ │ ├── interceptors │ │ │ ├── auth.interceptor.ts │ │ │ └── index.ts │ │ ├── orders │ │ │ ├── models │ │ │ │ ├── order.interface.ts │ │ │ │ └── orderproduct.interface.ts │ │ │ ├── orders-create │ │ │ │ ├── orders-create.component.html │ │ │ │ └── orders-create.component.ts │ │ │ ├── orders-detail │ │ │ │ ├── orders-detail.component.html │ │ │ │ ├── orders-detail.component.scss │ │ │ │ └── orders-detail.component.ts │ │ │ ├── orders-list │ │ │ │ ├── orders-list.component.html │ │ │ │ └── orders-list.component.ts │ │ │ ├── orders-routing.module.ts │ │ │ ├── orders.module.ts │ │ │ └── orders.service.ts │ │ ├── products │ │ │ ├── models │ │ │ │ └── product.interface.ts │ │ │ ├── product-create │ │ │ │ ├── product-create.component.html │ │ │ │ └── product-create.component.ts │ │ │ ├── product-edit │ │ │ │ ├── product-edit.component.html │ │ │ │ └── product-edit.component.ts │ │ │ ├── product-list │ │ │ │ ├── product-list.component.html │ │ │ │ └── product-list.component.ts │ │ │ ├── product.service.ts │ │ │ ├── products-routing.module.ts │ │ │ └── products.module.ts │ │ ├── users │ │ │ ├── models │ │ │ │ └── user.ts │ │ │ ├── user-create │ │ │ │ ├── user-create.component.html │ │ │ │ └── user-create.component.ts │ │ │ ├── user-detail │ │ │ │ ├── user-detail.component.html │ │ │ │ └── user-detail.component.ts │ │ │ ├── user-list │ │ │ │ ├── user-list.component.html │ │ │ │ └── user-list.component.ts │ │ │ ├── users-routing.module.ts │ │ │ ├── users.module.ts │ │ │ └── users.service.ts │ │ └── views │ │ │ ├── auth │ │ │ ├── auth-routing.module.ts │ │ │ ├── auth.module.ts │ │ │ ├── login-info │ │ │ │ ├── login-info.component.html │ │ │ │ ├── login-info.component.scss │ │ │ │ └── login-info.component.ts │ │ │ └── models │ │ │ │ └── config-params.ts │ │ │ ├── dashboard │ │ │ ├── dashboard-routing.module.ts │ │ │ ├── dashboard.component.html │ │ │ ├── dashboard.component.ts │ │ │ └── dashboard.module.ts │ │ │ └── error │ │ │ ├── 404.component.html │ │ │ ├── 404.component.ts │ │ │ ├── 500.component.html │ │ │ └── 500.component.ts │ ├── assets │ │ ├── .gitkeep │ │ └── img │ │ │ └── brand │ │ │ ├── logo.svg │ │ │ ├── saascommerce.png │ │ │ └── sygnet.svg │ ├── environments │ │ ├── environment.prod.ts │ │ └── environment.ts │ ├── index.html │ ├── main.ts │ ├── polyfills.ts │ ├── scss │ │ ├── _custom.scss │ │ ├── _variables.scss │ │ ├── style.scss │ │ └── vendors │ │ │ ├── _variables.scss │ │ │ └── chart.js │ │ │ └── chart.scss │ ├── test.ts │ ├── tsconfig.app.json │ ├── tsconfig.spec.json │ └── typings.d.ts │ ├── tsconfig.app.json │ ├── tsconfig.json │ ├── tsconfig.spec.json │ ├── tslint.json │ └── yarn.lock ├── deploy.sh ├── scripts ├── deploy-admin.sh ├── deploy-app-services.sh ├── deploy-application.sh ├── deploy-core-services.sh ├── deploy-order.sh ├── deploy-product.sh ├── deploy-remaining-shared-services.sh ├── deploy-tenant-management.sh ├── deploy-tenant-registration.sh ├── deploy-user-management.sh ├── nginx-ingress-config.yaml ├── policy │ └── deny-traffic-policy.yaml ├── re-deploy.sh ├── resize-cloud9-ebs-vol.sh └── templates │ ├── cloud9-envsetup.sh │ ├── ee-setup.sh │ ├── ee-template.yaml │ ├── eks-node-instance-policy.json │ ├── envsetup.sh │ ├── ingress-master-resource.yaml │ └── nginx-ingress-config.yaml ├── services ├── application │ ├── .eslintrc.js │ ├── .gitignore │ ├── .prettierrc │ ├── Dockerfile.order │ ├── Dockerfile.product │ ├── README.md │ ├── apps │ │ ├── order │ │ │ ├── k8s │ │ │ │ ├── template.txt │ │ │ │ └── template.yaml │ │ │ ├── src │ │ │ │ ├── main.ts │ │ │ │ └── orders │ │ │ │ │ ├── dto │ │ │ │ │ ├── create-order.dto.ts │ │ │ │ │ ├── order-product.dto.ts │ │ │ │ │ └── update-order.dto.ts │ │ │ │ │ ├── entities │ │ │ │ │ └── order.entity.ts │ │ │ │ │ ├── orders.controller.spec.ts │ │ │ │ │ ├── orders.controller.ts │ │ │ │ │ ├── orders.module.ts │ │ │ │ │ ├── orders.service.spec.ts │ │ │ │ │ └── orders.service.ts │ │ │ ├── test │ │ │ │ └── jest-e2e.json │ │ │ └── tsconfig.app.json │ │ ├── product │ │ │ ├── k8s │ │ │ │ ├── template.txt │ │ │ │ └── template.yaml │ │ │ ├── src │ │ │ │ ├── main.ts │ │ │ │ └── products │ │ │ │ │ ├── dto │ │ │ │ │ ├── create-product.dto.ts │ │ │ │ │ └── update-product.dto.ts │ │ │ │ │ ├── entities │ │ │ │ │ └── product.entity.ts │ │ │ │ │ ├── products.controller.spec.ts │ │ │ │ │ ├── products.controller.ts │ │ │ │ │ ├── products.module.ts │ │ │ │ │ ├── products.service.spec.ts │ │ │ │ │ └── products.service.ts │ │ │ ├── test │ │ │ │ └── jest-e2e.json │ │ │ └── tsconfig.app.json │ │ └── user │ │ │ ├── k8s │ │ │ └── template.yaml │ │ │ ├── src │ │ │ ├── main.ts │ │ │ └── users │ │ │ │ ├── dto │ │ │ │ ├── create-user.dto.ts │ │ │ │ └── update-user.dto.ts │ │ │ │ ├── entities │ │ │ │ └── user.entity.ts │ │ │ │ ├── users.controller.spec.ts │ │ │ │ ├── users.controller.ts │ │ │ │ ├── users.module.ts │ │ │ │ ├── users.service.spec.ts │ │ │ │ └── users.service.ts │ │ │ ├── test │ │ │ └── jest-e2e.json │ │ │ └── tsconfig.app.json │ ├── libs │ │ ├── auth │ │ │ ├── src │ │ │ │ ├── auth-config.ts │ │ │ │ ├── auth.decorator.ts │ │ │ │ ├── auth.module.ts │ │ │ │ ├── credential-vendor.ts │ │ │ │ ├── index.ts │ │ │ │ ├── jwt-auth.guard.ts │ │ │ │ ├── jwt.strategy.ts │ │ │ │ └── policies.json │ │ │ └── tsconfig.lib.json │ │ └── client-factory │ │ │ ├── src │ │ │ ├── client-factory.module.ts │ │ │ ├── client-factory.service.spec.ts │ │ │ ├── client-factory.service.ts │ │ │ └── index.ts │ │ │ └── tsconfig.lib.json │ ├── nest-cli.json │ ├── package-lock.json │ ├── package.json │ ├── tsconfig.build.json │ ├── tsconfig.json │ └── yarn.lock └── shared │ ├── .dockerignore │ ├── .eslintrc.js │ ├── .gitignore │ ├── .prettierrc │ ├── Dockerfile.tenant-management │ ├── Dockerfile.tenant-registration │ ├── Dockerfile.user-management │ ├── README.md │ ├── apps │ ├── tenant-management │ │ ├── k8s │ │ │ ├── partial-template.txt │ │ │ ├── template.txt │ │ │ └── template.yaml │ │ ├── src │ │ │ ├── main.ts │ │ │ └── tenants │ │ │ │ ├── dto │ │ │ │ ├── create-tenant.dto.ts │ │ │ │ └── update-tenant.dto.ts │ │ │ │ ├── entities │ │ │ │ └── tenant.entity.ts │ │ │ │ ├── tenants.controller.spec.ts │ │ │ │ ├── tenants.controller.ts │ │ │ │ ├── tenants.module.ts │ │ │ │ ├── tenants.service.spec.ts │ │ │ │ └── tenants.service.ts │ │ ├── test │ │ │ └── jest-e2e.json │ │ └── tsconfig.app.json │ ├── tenant-registration │ │ ├── k8s │ │ │ ├── partial-template.txt │ │ │ ├── template.txt │ │ │ └── template.yaml │ │ ├── src │ │ │ ├── idp-service │ │ │ │ ├── idp.service.spec.ts │ │ │ │ └── idp.service.ts │ │ │ ├── main.ts │ │ │ ├── models │ │ │ │ └── types.ts │ │ │ ├── registration │ │ │ │ ├── constants.ts │ │ │ │ ├── dto │ │ │ │ │ ├── create-registration.dto.ts │ │ │ │ │ └── update-registration.dto.ts │ │ │ │ ├── entities │ │ │ │ │ ├── registration.entity.spec.ts │ │ │ │ │ └── registration.entity.ts │ │ │ │ ├── registration.controller.spec.ts │ │ │ │ ├── registration.controller.ts │ │ │ │ ├── registration.module.ts │ │ │ │ ├── registration.service.spec.ts │ │ │ │ └── registration.service.ts │ │ │ └── utils │ │ │ │ └── utils.ts │ │ ├── test │ │ │ └── jest-e2e.json │ │ └── tsconfig.app.json │ └── user-management │ │ ├── k8s │ │ ├── partial-template.txt │ │ ├── template.txt │ │ └── template.yaml │ │ ├── src │ │ ├── main.ts │ │ └── users │ │ │ ├── dto │ │ │ └── create-tenant-user.dto.ts.ts │ │ │ ├── users.controller.ts │ │ │ ├── users.module.ts │ │ │ └── users.service.ts │ │ ├── test │ │ └── jest-e2e.json │ │ └── tsconfig.app.json │ ├── libs │ ├── auth │ │ ├── src │ │ │ ├── auth.config.ts │ │ │ ├── auth.module.ts │ │ │ ├── index.ts │ │ │ ├── jwt-auth.guard.ts │ │ │ └── jwt.strategy.ts │ │ └── tsconfig.lib.json │ └── client-factory │ │ ├── src │ │ ├── client-factory.module.ts │ │ ├── client-factory.service.spec.ts │ │ ├── client-factory.service.ts │ │ └── index.ts │ │ └── tsconfig.lib.json │ ├── nest-cli.json │ ├── package-lock.json │ ├── package.json │ ├── tsconfig.build.json │ ├── tsconfig.json │ └── yarn.lock ├── setup.sh └── update-provisioning-status.sh /AWS-EVENT-deploy-eks.sh: -------------------------------------------------------------------------------- 1 | 2 | 3 | # Deploys an Amazon EKS cluster. 4 | # Once deployment is complete, copy the output values and apply to cdk/root/lib/root-stack.ts 5 | 6 | cd cdk/existing-eks-stack 7 | yarn && yarn run build 8 | cdk bootstrap 9 | cdk deploy 10 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | ## Code of Conduct 2 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). 3 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact 4 | opensource-codeofconduct@amazon.com with any additional questions or comments. 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | this software and associated documentation files (the "Software"), to deal in 5 | the Software without restriction, including without limitation the rights to 6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 7 | the Software, and to permit persons to whom the Software is furnished to do so. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 10 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 11 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 12 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 13 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 14 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 15 | 16 | -------------------------------------------------------------------------------- /ON-YOUR-OWN-deploy-eks.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | #Deploys an Amazon EKS cluster. 4 | #Once deployment is complete, copy the output values and apply to cdk/root/lib/root-stack.ts 5 | cd cdk/eks 6 | yarn && yarn run build 7 | cdk bootstrap 8 | cdk deploy 9 | 10 | export ELBURL=$(aws cloudformation describe-stacks --stack-name EksStack --query "Stacks[0].Outputs[?OutputKey=='ELBURL'].OutputValue" --output text) 11 | export CODEBUILD_ARN=$(aws cloudformation describe-stacks --stack-name EksStack --query "Stacks[0].Outputs[?OutputKey=='EksCodebuildArn'].OutputValue" --output text) 12 | export IAM_ROLE_ARN=$(aws cloudformation describe-stacks --stack-name EksStack --query "Stacks[0].Outputs[?OutputKey=='RoleUsedByTVM'].OutputValue" --output text) 13 | 14 | echo "export ELBURL=${ELBURL}" | tee -a ~/.bash_profile 15 | echo "export IAM_ROLE_ARN=${IAM_ROLE_ARN}" | tee -a ~/.bash_profile 16 | echo "export CODEBUILD_ARN=${CODEBUILD_ARN}" | tee -a ~/.bash_profile 17 | -------------------------------------------------------------------------------- /cdk/eks/.gitignore: -------------------------------------------------------------------------------- 1 | *.js 2 | !jest.config.js 3 | *.d.ts 4 | node_modules 5 | 6 | # CDK asset staging directory 7 | .cdk.staging 8 | cdk.out 9 | -------------------------------------------------------------------------------- /cdk/eks/.npmignore: -------------------------------------------------------------------------------- 1 | *.ts 2 | !*.d.ts 3 | 4 | # CDK asset staging directory 5 | .cdk.staging 6 | cdk.out 7 | -------------------------------------------------------------------------------- /cdk/eks/README.md: -------------------------------------------------------------------------------- 1 | # Welcome to your CDK TypeScript project! 2 | 3 | This is a blank project for TypeScript development with CDK. 4 | 5 | The `cdk.json` file tells the CDK Toolkit how to execute your app. 6 | 7 | ## Useful commands 8 | 9 | * `npm run build` compile typescript to js 10 | * `npm run watch` watch for changes and compile 11 | * `npm run test` perform the jest unit tests 12 | * `cdk deploy` deploy this stack to your default AWS account/region 13 | * `cdk diff` compare deployed stack with current state 14 | * `cdk synth` emits the synthesized CloudFormation template 15 | -------------------------------------------------------------------------------- /cdk/eks/bin/eks.ts: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | import 'source-map-support/register'; 3 | 4 | import { EksStack } from '../lib/eks-stack'; 5 | import { App } from 'aws-cdk-lib'; 6 | 7 | const app = new App(); 8 | new EksStack(app, 'EksStack', { 9 | /* If you don't specify 'env', this stack will be environment-agnostic. 10 | * Account/Region-dependent features and context lookups will not work, 11 | * but a single synthesized template can be deployed anywhere. */ 12 | 13 | /* Uncomment the next line to specialize this stack for the AWS Account 14 | * and Region that are implied by the current CLI configuration. */ 15 | // env: { account: process.env.CDK_DEFAULT_ACCOUNT, region: process.env.CDK_DEFAULT_REGION }, 16 | 17 | /* Uncomment the next line if you know exactly what Account and Region you 18 | * want to deploy the stack to. */ 19 | // env: { account: '123456789012', region: 'us-east-1' }, 20 | 21 | /* For more information, see https://docs.aws.amazon.com/cdk/latest/guide/environments.html */ 22 | }); 23 | -------------------------------------------------------------------------------- /cdk/eks/cdk.json: -------------------------------------------------------------------------------- 1 | { 2 | "app": "npx ts-node --prefer-ts-exts bin/eks.ts", 3 | "context": { 4 | "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, 5 | "@aws-cdk/core:stackRelativeExports": true, 6 | "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, 7 | "@aws-cdk/aws-lambda:recognizeVersionProps": true, 8 | "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /cdk/eks/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | testEnvironment: 'node', 3 | roots: ['/test'], 4 | testMatch: ['**/*.test.ts'], 5 | transform: { 6 | '^.+\\.tsx?$': 'ts-jest' 7 | } 8 | }; 9 | -------------------------------------------------------------------------------- /cdk/eks/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "eks", 3 | "version": "0.1.0", 4 | "bin": { 5 | "eks": "bin/eks.js" 6 | }, 7 | "scripts": { 8 | "build": "tsc", 9 | "watch": "tsc -w", 10 | "test": "jest", 11 | "cdk": "cdk" 12 | }, 13 | "devDependencies": { 14 | "@types/jest": "^26.0.10", 15 | "@types/node": "10.17.27", 16 | "aws-cdk-lib": "^2.3.0", 17 | "jest": "^26.4.2", 18 | "ts-jest": "^26.2.0", 19 | "ts-node": "^9.0.0", 20 | "typescript": "~3.9.7" 21 | }, 22 | "dependencies": { 23 | "assert": "^2.0.0", 24 | "assertion": "^1.3.35", 25 | "aws-cdk-lib": "^2.3.0", 26 | "aws-lambda": "^1.0.7", 27 | "constructs": "^10.0.0", 28 | "source-map-support": "^0.5.16", 29 | "uuid": "^8.3.2" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /cdk/eks/test/eks.test.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | 6 | import {Match } from 'aws-cdk-lib/assertions'; 7 | import * as cdk from 'aws-cdk-lib'; 8 | import * as Eks from '../lib/eks-stack'; 9 | 10 | test('Empty Stack', () => { 11 | const app = new cdk.App(); 12 | // WHEN 13 | const stack = new Eks.EksStack(app, 'MyTestStack'); 14 | // THEN 15 | expect(stack).toEqual( 16 | Match.objectEquals( 17 | { 18 | Resources: {}, 19 | }, 20 | ) 21 | ); 22 | }); 23 | -------------------------------------------------------------------------------- /cdk/eks/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2018", 4 | "module": "commonjs", 5 | "lib": [ 6 | "es2018" 7 | ], 8 | "declaration": true, 9 | "strict": true, 10 | "noImplicitAny": true, 11 | "strictNullChecks": true, 12 | "noImplicitThis": true, 13 | "alwaysStrict": true, 14 | "noUnusedLocals": false, 15 | "noUnusedParameters": false, 16 | "noImplicitReturns": true, 17 | "noFallthroughCasesInSwitch": false, 18 | "inlineSourceMap": true, 19 | "inlineSources": true, 20 | "experimentalDecorators": true, 21 | "strictPropertyInitialization": false, 22 | "typeRoots": [ 23 | "./node_modules/@types" 24 | ] 25 | }, 26 | "exclude": [ 27 | "node_modules", 28 | "cdk.out" 29 | ] 30 | } 31 | -------------------------------------------------------------------------------- /cdk/root/.gitignore: -------------------------------------------------------------------------------- 1 | *.js 2 | !jest.config.js 3 | *.d.ts 4 | node_modules 5 | 6 | # CDK asset staging directory 7 | .cdk.staging 8 | cdk.out 9 | -------------------------------------------------------------------------------- /cdk/root/.npmignore: -------------------------------------------------------------------------------- 1 | *.ts 2 | !*.d.ts 3 | 4 | # CDK asset staging directory 5 | .cdk.staging 6 | cdk.out 7 | -------------------------------------------------------------------------------- /cdk/root/README.md: -------------------------------------------------------------------------------- 1 | # Welcome to your CDK TypeScript project! 2 | 3 | This is a blank project for TypeScript development with CDK. 4 | 5 | The `cdk.json` file tells the CDK Toolkit how to execute your app. 6 | 7 | ## Useful commands 8 | 9 | * `npm run build` compile typescript to js 10 | * `npm run watch` watch for changes and compile 11 | * `npm run test` perform the jest unit tests 12 | * `cdk deploy` deploy this stack to your default AWS account/region 13 | * `cdk diff` compare deployed stack with current state 14 | * `cdk synth` emits the synthesized CloudFormation template 15 | -------------------------------------------------------------------------------- /cdk/root/bin/root.ts: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | import 'source-map-support/register'; 3 | import { RootStack } from '../lib/root-stack'; 4 | import { App } from 'aws-cdk-lib'; 5 | 6 | const app = new App(); 7 | new RootStack(app, 'RootStack'); 8 | -------------------------------------------------------------------------------- /cdk/root/cdk.json: -------------------------------------------------------------------------------- 1 | { 2 | "app": "npx ts-node --prefer-ts-exts bin/root.ts", 3 | "context": { 4 | "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, 5 | "@aws-cdk/core:stackRelativeExports": true, 6 | "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, 7 | "@aws-cdk/aws-lambda:recognizeVersionProps": true, 8 | "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /cdk/root/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | roots: ['/test'], 3 | testMatch: ['**/*.test.ts'], 4 | transform: { 5 | '^.+\\.tsx?$': 'ts-jest' 6 | } 7 | }; 8 | -------------------------------------------------------------------------------- /cdk/root/lib/tenant-infra/codebuild-role-policy-doc.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | 6 | import * as iam from 'aws-cdk-lib/aws-iam'; 7 | import { Construct } from 'constructs'; 8 | 9 | export function getCodeBuildRole(parent: Construct, account: string, region: string): iam.Role { 10 | return new iam.Role(parent, 'CodeBuildRole', { 11 | assumedBy: new iam.ServicePrincipal('codebuild.amazonaws.com'), 12 | description: 'Role assigned to our tenant onboarding code build project', 13 | inlinePolicies: { 14 | TenantOnboardingPolicy: getCodeBuildPolicyDoc(account, region), 15 | }, 16 | }); 17 | } 18 | 19 | function getCodeBuildPolicyDoc(account: string, region: string): iam.PolicyDocument { 20 | return new iam.PolicyDocument({ 21 | assignSids: false, 22 | statements: [ 23 | new iam.PolicyStatement({ 24 | effect: iam.Effect.ALLOW, 25 | actions: ['sts:AssumeRole'], 26 | resources: [`arn:aws:iam::${account}:role/*`], 27 | }), 28 | new iam.PolicyStatement({ 29 | effect: iam.Effect.ALLOW, 30 | actions: ['cloudformation:DescribeStacks'], 31 | resources: [`arn:aws:cloudformation:${region}:${account}:stack/*`], 32 | }), 33 | ], 34 | }); 35 | } 36 | -------------------------------------------------------------------------------- /cdk/root/lib/utils.ts: -------------------------------------------------------------------------------- 1 | const getTimeString = () => { 2 | const date = new Date(); 3 | var yyyy = date.getFullYear().toString(); 4 | var MM = pad(date.getMonth() + 1, 2); 5 | var dd = pad(date.getDate(), 2); 6 | var hh = pad(date.getHours(), 2); 7 | var mm = pad(date.getMinutes(), 2); 8 | var ss = pad(date.getSeconds(), 2); 9 | return yyyy + MM + dd + hh + mm + ss; 10 | }; 11 | 12 | const pad = (n: number, l: number) => { 13 | var str = '' + n; 14 | while (str.length < l) { 15 | str = '0' + str; 16 | } 17 | return str; 18 | }; 19 | 20 | export default getTimeString; 21 | -------------------------------------------------------------------------------- /cdk/root/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "root", 3 | "version": "0.1.0", 4 | "bin": { 5 | "root": "bin/root.js" 6 | }, 7 | "scripts": { 8 | "build": "tsc", 9 | "watch": "tsc -w", 10 | "test": "jest", 11 | "cdk": "cdk" 12 | }, 13 | "devDependencies": { 14 | "@aws-cdk/assert": "^2.13.0", 15 | "@types/jest": "^26.0.10", 16 | "@types/node": "10.17.27", 17 | "aws-cdk": "^2.3.0", 18 | "jest": "^26.4.2", 19 | "ts-jest": "^28.0.5", 20 | "ts-node": "^9.0.0", 21 | "typescript": "~3.9.7" 22 | }, 23 | "dependencies": { 24 | "@cnakazawa/watch": "^1.0.4", 25 | "aws-cdk-lib": "^2.3.0", 26 | "aws-lambda": "^1.0.7", 27 | "constructs": "^10.0.0", 28 | "jest-haste-map": "^28.1.1", 29 | "json5": "^2.2.1", 30 | "minimist": "^1.2.6", 31 | "sane": "^5.0.1", 32 | "source-map-support": "^0.5.16" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /cdk/root/test/root.test.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | 6 | import { Match } from 'aws-cdk-lib/assertions'; 7 | import * as cdk from 'aws-cdk-lib'; 8 | import * as Root from '../lib/root-stack'; 9 | 10 | test('Empty Stack', () => { 11 | const app = new cdk.App(); 12 | // WHEN 13 | const stack = new Root.RootStack(app, 'MyTestStack'); 14 | // THEN 15 | expect(stack).toEqual( 16 | Match.objectEquals( 17 | { 18 | Resources: {}, 19 | }, 20 | ) 21 | ); 22 | }); 23 | -------------------------------------------------------------------------------- /cdk/root/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2018", 4 | "module": "commonjs", 5 | "lib": ["es2018"], 6 | "declaration": true, 7 | "strict": true, 8 | "noImplicitAny": true, 9 | "strictNullChecks": true, 10 | "noImplicitThis": true, 11 | "alwaysStrict": true, 12 | "noUnusedLocals": false, 13 | "noUnusedParameters": false, 14 | "noImplicitReturns": true, 15 | "noFallthroughCasesInSwitch": false, 16 | "inlineSourceMap": true, 17 | "inlineSources": true, 18 | "experimentalDecorators": true, 19 | "strictPropertyInitialization": false, 20 | "typeRoots": ["./node_modules/@types"] 21 | }, 22 | "exclude": ["cdk.out"] 23 | } 24 | -------------------------------------------------------------------------------- /client/web/admin/.browserslistrc: -------------------------------------------------------------------------------- 1 | # This file is used by the build system to adjust CSS and JS output to support the specified browsers below. 2 | # For additional information regarding the format and rule options, please see: 3 | # https://github.com/browserslist/browserslist#queries 4 | 5 | # For the full list of supported browsers by the Angular framework, please see: 6 | # https://angular.io/guide/browser-support 7 | 8 | # You can see what browsers were selected by your queries by running: 9 | # npx browserslist 10 | 11 | last 1 Chrome version 12 | last 1 Firefox version 13 | last 2 Edge major versions 14 | last 2 Safari major versions 15 | last 2 iOS major versions 16 | Firefox ESR 17 | not IE 11 # Angular supports IE 11 only as an opt-in. To opt-in, remove the 'not' prefix on this line. 18 | -------------------------------------------------------------------------------- /client/web/admin/.dockerignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /client/web/admin/.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see https://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.ts] 12 | quote_type = single 13 | 14 | [*.md] 15 | max_line_length = off 16 | trim_trailing_whitespace = false 17 | -------------------------------------------------------------------------------- /client/web/admin/.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # compiled output 4 | /dist 5 | /tmp 6 | /out-tsc 7 | # Only exists if Bazel was run 8 | /bazel-out 9 | 10 | # dependencies 11 | /node_modules 12 | 13 | # profiling files 14 | chrome-profiler-events*.json 15 | speed-measure-plugin*.json 16 | 17 | # IDEs and editors 18 | /.idea 19 | .project 20 | .classpath 21 | .c9/ 22 | *.launch 23 | .settings/ 24 | *.sublime-workspace 25 | 26 | # IDE - VSCode 27 | .vscode/* 28 | !.vscode/settings.json 29 | !.vscode/tasks.json 30 | !.vscode/launch.json 31 | !.vscode/extensions.json 32 | .history/* 33 | 34 | # misc 35 | /.sass-cache 36 | /connect.lock 37 | /coverage 38 | /libpeerconnection.log 39 | npm-debug.log 40 | yarn-error.log 41 | testem.log 42 | /typings 43 | 44 | # System Files 45 | .DS_Store 46 | Thumbs.db 47 | 48 | # We want to exclude the environment settings here because we're rewriting all the time upon build 49 | # This is NOT something you would normally do in an Angular project 50 | environments/ 51 | 52 | #amplify 53 | amplify/\#current-cloud-backend 54 | amplify/.config/local-* 55 | amplify/logs 56 | amplify/mock-data 57 | amplify/backend/amplify-meta.json 58 | amplify/backend/awscloudformation 59 | amplify/backend/.temp 60 | build/ 61 | dist/ 62 | node_modules/ 63 | aws-exports.js 64 | awsconfiguration.json 65 | amplifyconfiguration.json 66 | amplifyconfiguration.dart 67 | amplify-build-config.json 68 | amplify-gradle-config.json 69 | amplifytools.xcconfig 70 | .secret-* 71 | -------------------------------------------------------------------------------- /client/web/admin/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM public.ecr.aws/bitnami/node:16.5.0 AS build 2 | WORKDIR /usr/src/app 3 | COPY package.json yarn.lock ./ 4 | RUN yarn 5 | COPY . . 6 | RUN yarn build:prod 7 | 8 | FROM public.ecr.aws/nginx/nginx:1.21 9 | COPY nginx.conf /etc/nginx/conf.d/default.conf 10 | COPY --from=build /usr/src/app/dist/admin /usr/share/nginx/html/admin 11 | -------------------------------------------------------------------------------- /client/web/admin/README.md: -------------------------------------------------------------------------------- 1 | # Admin 2 | 3 | This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 11.2.9. 4 | 5 | ## Development server 6 | 7 | Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files. 8 | 9 | ## Code scaffolding 10 | 11 | Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`. 12 | 13 | ## Build 14 | 15 | Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `--prod` flag for a production build. 16 | 17 | ## Running unit tests 18 | 19 | Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io). 20 | 21 | ## Running end-to-end tests 22 | 23 | Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/). 24 | 25 | ## Further help 26 | 27 | To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI Overview and Command Reference](https://angular.io/cli) page. 28 | -------------------------------------------------------------------------------- /client/web/admin/amplify/.config/project-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "projectName": "admin", 3 | "version": "3.1", 4 | "frontend": "javascript", 5 | "javascript": { 6 | "framework": "angular", 7 | "config": { 8 | "SourceDir": "src", 9 | "DistributionDir": "dist/admin", 10 | "BuildCommand": "npm run-script build", 11 | "StartCommand": "ng serve" 12 | } 13 | }, 14 | "providers": [ 15 | "awscloudformation" 16 | ] 17 | } -------------------------------------------------------------------------------- /client/web/admin/amplify/README.md: -------------------------------------------------------------------------------- 1 | # Getting Started with Amplify CLI 2 | This directory was generated by [Amplify CLI](https://docs.amplify.aws/cli). 3 | 4 | Helpful resources: 5 | - Amplify documentation: https://docs.amplify.aws 6 | - Amplify CLI documentation: https://docs.amplify.aws/cli 7 | - More details on this folder & generated files: https://docs.amplify.aws/cli/reference/files 8 | - Join Amplify's community: https://amplify.aws/community/ 9 | -------------------------------------------------------------------------------- /client/web/admin/amplify/backend/auth/admin211a75b9/parameters.json: -------------------------------------------------------------------------------- 1 | { 2 | "authSelections": "userPoolOnly", 3 | "resourceName": "admin211a75b9", 4 | "serviceType": "imported", 5 | "region": "us-west-2" 6 | } -------------------------------------------------------------------------------- /client/web/admin/amplify/backend/backend-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "auth": { 3 | "admin211a75b9": { 4 | "service": "Cognito", 5 | "serviceType": "imported", 6 | "providerPlugin": "awscloudformation", 7 | "dependsOn": [], 8 | "customAuth": false 9 | } 10 | } 11 | } -------------------------------------------------------------------------------- /client/web/admin/amplify/backend/tags.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "Key": "user:Stack", 4 | "Value": "{project-env}" 5 | }, 6 | { 7 | "Key": "user:Application", 8 | "Value": "{project-name}" 9 | } 10 | ] -------------------------------------------------------------------------------- /client/web/admin/amplify/cli.json: -------------------------------------------------------------------------------- 1 | { 2 | "features": { 3 | "graphqltransformer": { 4 | "addmissingownerfields": true, 5 | "validatetypenamereservedwords": true, 6 | "useexperimentalpipelinedtransformer": false, 7 | "enableiterativegsiupdates": true, 8 | "secondarykeyasgsi": true, 9 | "skipoverridemutationinputtypes": true 10 | }, 11 | "frontend-ios": { 12 | "enablexcodeintegration": true 13 | }, 14 | "auth": { 15 | "enablecaseinsensitivity": true, 16 | "useinclusiveterminology": true 17 | }, 18 | "codegen": { 19 | "useappsyncmodelgenplugin": true, 20 | "usedocsgeneratorplugin": true, 21 | "usetypesgeneratorplugin": true, 22 | "cleangeneratedmodelsdirectory": true, 23 | "retaincasestyle": true 24 | }, 25 | "appsync": { 26 | "generategraphqlpermissions": true 27 | } 28 | } 29 | } -------------------------------------------------------------------------------- /client/web/admin/amplify/team-provider-info.json: -------------------------------------------------------------------------------- 1 | { 2 | "dev": { 3 | "awscloudformation": { 4 | "AuthRoleName": "amplify-admin-dev-100251-authRole", 5 | "UnauthRoleArn": "arn:aws:iam::540983619545:role/amplify-admin-dev-100251-unauthRole", 6 | "AuthRoleArn": "arn:aws:iam::540983619545:role/amplify-admin-dev-100251-authRole", 7 | "Region": "us-west-2", 8 | "DeploymentBucketName": "amplify-admin-dev-100251-deployment", 9 | "UnauthRoleName": "amplify-admin-dev-100251-unauthRole", 10 | "StackName": "amplify-admin-dev-100251", 11 | "StackId": "arn:aws:cloudformation:us-west-2:540983619545:stack/amplify-admin-dev-100251/e20b5980-bcb1-11eb-947e-02ff9399efdf", 12 | "AmplifyAppId": "dwk6eu8k5kgue" 13 | }, 14 | "categories": { 15 | "auth": { 16 | "admin211a75b9": { 17 | "userPoolId": "us-west-2_xL5xFoQ4T", 18 | "userPoolName": "AdminUserPoolD0AF18CF-AQtUMFrihX3X", 19 | "webClientId": "7navfejaco7l9g9een24is3hia", 20 | "nativeClientId": "7navfejaco7l9g9een24is3hia" 21 | } 22 | } 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /client/web/admin/codepipeline/buildspec.yml: -------------------------------------------------------------------------------- 1 | version: 0.2 2 | 3 | phases: 4 | pre_build: 5 | commands: 6 | - echo Logging in to Amazon ECR... 7 | - aws --version 8 | - REGISTRY=$(echo $ADMINAPPLICATIONECR| cut -d'/' -f 1) 9 | - aws ecr get-login-password --region $REGION | docker login --username AWS --password-stdin $REGISTRY 10 | - COMMIT_HASH=$(echo $CODEBUILD_RESOLVED_SOURCE_VERSION | cut -c 1-7) 11 | - IMAGE_TAG=${COMMIT_HASH:=latest} 12 | build: 13 | commands: 14 | - echo Build started on `date` 15 | - echo Building the Docker image... 16 | - cd client/web/admin 17 | - chmod +x setenv.sh 18 | - ./setenv.sh $ELBURL $REGION $USERPOOLID $APPCLIENTID 19 | - docker build -t $ADMINAPPLICATIONECR:latest . 20 | - docker tag $ADMINAPPLICATIONECR:latest $ADMINAPPLICATIONECR:$IMAGE_TAG 21 | post_build: 22 | commands: 23 | - echo Build completed on `date` 24 | - echo Pushing the Docker images... 25 | - docker push $ADMINAPPLICATIONECR:latest 26 | - docker push $ADMINAPPLICATIONECR:$IMAGE_TAG 27 | - echo $ADMINAPPLICATIONECR:$IMAGE_TAG 28 | -------------------------------------------------------------------------------- /client/web/admin/e2e/protractor.conf.js: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | // Protractor configuration file, see link for more information 3 | // https://github.com/angular/protractor/blob/master/lib/config.ts 4 | 5 | const { SpecReporter, StacktraceOption } = require('jasmine-spec-reporter'); 6 | 7 | /** 8 | * @type { import("protractor").Config } 9 | */ 10 | exports.config = { 11 | allScriptsTimeout: 11000, 12 | specs: [ 13 | './src/**/*.e2e-spec.ts' 14 | ], 15 | capabilities: { 16 | browserName: 'chrome' 17 | }, 18 | directConnect: true, 19 | SELENIUM_PROMISE_MANAGER: false, 20 | baseUrl: 'http://localhost:4200/', 21 | framework: 'jasmine', 22 | jasmineNodeOpts: { 23 | showColors: true, 24 | defaultTimeoutInterval: 30000, 25 | print: function() {} 26 | }, 27 | onPrepare() { 28 | require('ts-node').register({ 29 | project: require('path').join(__dirname, './tsconfig.json') 30 | }); 31 | jasmine.getEnv().addReporter(new SpecReporter({ 32 | spec: { 33 | displayStacktrace: StacktraceOption.PRETTY 34 | } 35 | })); 36 | } 37 | }; -------------------------------------------------------------------------------- /client/web/admin/e2e/src/app.e2e-spec.ts: -------------------------------------------------------------------------------- 1 | import { browser, logging } from 'protractor'; 2 | import { AppPage } from './app.po'; 3 | 4 | describe('workspace-project App', () => { 5 | let page: AppPage; 6 | 7 | beforeEach(() => { 8 | page = new AppPage(); 9 | }); 10 | 11 | it('should display welcome message', async () => { 12 | await page.navigateTo(); 13 | expect(await page.getTitleText()).toEqual('admin app is running!'); 14 | }); 15 | 16 | afterEach(async () => { 17 | // Assert that there are no errors emitted from the browser 18 | const logs = await browser.manage().logs().get(logging.Type.BROWSER); 19 | expect(logs).not.toContain(jasmine.objectContaining({ 20 | level: logging.Level.SEVERE, 21 | } as logging.Entry)); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /client/web/admin/e2e/src/app.po.ts: -------------------------------------------------------------------------------- 1 | import { browser, by, element } from 'protractor'; 2 | 3 | export class AppPage { 4 | async navigateTo(): Promise { 5 | return browser.get(browser.baseUrl); 6 | } 7 | 8 | async getTitleText(): Promise { 9 | return element(by.css('app-root .content span')).getText(); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /client/web/admin/e2e/tsconfig.json: -------------------------------------------------------------------------------- 1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */ 2 | { 3 | "extends": "../tsconfig.json", 4 | "compilerOptions": { 5 | "outDir": "../out-tsc/e2e", 6 | "module": "commonjs", 7 | "target": "es2018", 8 | "types": [ 9 | "jasmine", 10 | "node" 11 | ] 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /client/web/admin/k8s/template.txt: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: admin-application 5 | spec: 6 | replicas: 1 7 | selector: 8 | matchLabels: 9 | app: admin-application 10 | template: 11 | metadata: 12 | labels: 13 | app: admin-application 14 | spec: 15 | containers: 16 | - name: admin-application 17 | image: $ADMINAPPLICATIONECR:latest 18 | imagePullPolicy: Always 19 | ports: 20 | - containerPort: 80 21 | name: "http" 22 | --- 23 | apiVersion: v1 24 | kind: Service 25 | metadata: 26 | name: admin-application-service 27 | spec: 28 | selector: 29 | app: admin-application 30 | ports: 31 | - name: http 32 | protocol: TCP 33 | port: 80 34 | targetPort: 80 35 | type: NodePort 36 | --- 37 | apiVersion: networking.k8s.io/v1 38 | kind: Ingress 39 | metadata: 40 | name: admin-application-service-ingress 41 | annotations: 42 | kubernetes.io/ingress.class: "nginx" 43 | nginx.org/mergeable-ingress-type: "minion" 44 | spec: 45 | rules: 46 | - host: $ELBURL 47 | http: 48 | paths: 49 | - backend: 50 | service: 51 | name: admin-application-service 52 | port: 53 | number: 80 54 | path: /admin 55 | pathType: Prefix 56 | -------------------------------------------------------------------------------- /client/web/admin/k8s/template.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: admin-application 5 | spec: 6 | replicas: 1 7 | selector: 8 | matchLabels: 9 | app: admin-application 10 | template: 11 | metadata: 12 | labels: 13 | app: admin-application 14 | spec: 15 | containers: 16 | - name: admin-application 17 | image: ADMIN_APPLICATION_ECR:latest 18 | imagePullPolicy: Always 19 | ports: 20 | - containerPort: 80 21 | name: "http" 22 | --- 23 | apiVersion: v1 24 | kind: Service 25 | metadata: 26 | name: admin-application-service 27 | spec: 28 | selector: 29 | app: admin-application 30 | ports: 31 | - name: http 32 | protocol: TCP 33 | port: 80 34 | targetPort: 80 35 | type: NodePort 36 | --- 37 | apiVersion: networking.k8s.io/v1 38 | kind: Ingress 39 | metadata: 40 | name: admin-application-service-ingress 41 | annotations: 42 | kubernetes.io/ingress.class: "nginx" 43 | nginx.org/mergeable-ingress-type: "minion" 44 | spec: 45 | rules: 46 | - host: ELB_URL 47 | http: 48 | paths: 49 | - backend: 50 | service: 51 | name: admin-application-service 52 | port: 53 | number: 80 54 | path: /admin 55 | pathType: Prefix 56 | -------------------------------------------------------------------------------- /client/web/admin/karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration file, see link for more information 2 | // https://karma-runner.github.io/1.0/config/configuration-file.html 3 | 4 | module.exports = function (config) { 5 | config.set({ 6 | basePath: '', 7 | frameworks: ['jasmine', '@angular-devkit/build-angular'], 8 | plugins: [ 9 | require('karma-jasmine'), 10 | require('karma-chrome-launcher'), 11 | require('karma-jasmine-html-reporter'), 12 | require('karma-coverage'), 13 | require('@angular-devkit/build-angular/plugins/karma') 14 | ], 15 | client: { 16 | jasmine: { 17 | // you can add configuration options for Jasmine here 18 | // the possible options are listed at https://jasmine.github.io/api/edge/Configuration.html 19 | // for example, you can disable the random execution with `random: false` 20 | // or set a specific seed with `seed: 4321` 21 | }, 22 | clearContext: false // leave Jasmine Spec Runner output visible in browser 23 | }, 24 | jasmineHtmlReporter: { 25 | suppressAll: true // removes the duplicated traces 26 | }, 27 | coverageReporter: { 28 | dir: require('path').join(__dirname, './coverage/admin'), 29 | subdir: '.', 30 | reporters: [ 31 | { type: 'html' }, 32 | { type: 'text-summary' } 33 | ] 34 | }, 35 | reporters: ['progress', 'kjhtml'], 36 | port: 9876, 37 | colors: true, 38 | logLevel: config.LOG_INFO, 39 | autoWatch: true, 40 | browsers: ['Chrome'], 41 | singleRun: false, 42 | restartOnFileChange: true 43 | }); 44 | }; 45 | -------------------------------------------------------------------------------- /client/web/admin/nginx.conf: -------------------------------------------------------------------------------- 1 | server { 2 | listen 80; 3 | 4 | location /admin { 5 | alias /usr/share/nginx/html/admin/; 6 | index index.html; 7 | try_files $uri $uri/ index.html =404; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /client/web/admin/setenv.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #set -x 3 | : "${ELBURL:=$1}" 4 | : "${REGION:=$2}" 5 | : "${USERPOOLID:=$3}" 6 | : "${APPCLIENTID:=$4}" 7 | 8 | cat << EoF > ./src/environments/environment.prod.ts 9 | export const environment = { 10 | production: true, 11 | apiUrl: 'http://$ELBURL', 12 | }; 13 | 14 | EoF 15 | cat << EoF > ./src/environments/environment.ts 16 | export const environment = { 17 | production: true, 18 | apiUrl: 'http://$ELBURL', 19 | }; 20 | EoF 21 | 22 | cat << EoF > ./src/aws-exports.js 23 | const awsmobile = { 24 | "aws_project_region": "$REGION", 25 | "aws_cognito_region": "$REGION", 26 | "aws_user_pools_id": "$USERPOOLID", 27 | "aws_user_pools_web_client_id": "$APPCLIENTID", 28 | }; 29 | 30 | 31 | export default awsmobile; 32 | EoF 33 | -------------------------------------------------------------------------------- /client/web/admin/src/app/_nav.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | import { INavData } from '@coreui/angular'; 6 | 7 | export const navItems: INavData[] = [ 8 | { 9 | name: 'Dashboard', 10 | url: '/dashboard', 11 | icon: 'icon-graph', 12 | }, 13 | { 14 | name: 'Tenants', 15 | url: '/tenants', 16 | icon: 'icon-layers', 17 | }, 18 | ]; 19 | -------------------------------------------------------------------------------- /client/web/admin/src/app/app.component.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | pp.modul 5 | -------------------------------------------------------------------------------- /client/web/admin/src/app/app.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-saas-factory-eks-saas-api-gateway-tiering-and-throttling/5374aedde1470fc23bdbdc5fe58da16f873642b1/client/web/admin/src/app/app.component.scss -------------------------------------------------------------------------------- /client/web/admin/src/app/app.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | import { RouterTestingModule } from '@angular/router/testing'; 3 | import { AppComponent } from './app.component'; 4 | 5 | describe('AppComponent', () => { 6 | beforeEach(async () => { 7 | await TestBed.configureTestingModule({ 8 | imports: [ 9 | RouterTestingModule 10 | ], 11 | declarations: [ 12 | AppComponent 13 | ], 14 | }).compileComponents(); 15 | }); 16 | 17 | it('should create the app', () => { 18 | const fixture = TestBed.createComponent(AppComponent); 19 | const app = fixture.componentInstance; 20 | expect(app).toBeTruthy(); 21 | }); 22 | 23 | it(`should have as title 'admin'`, () => { 24 | const fixture = TestBed.createComponent(AppComponent); 25 | const app = fixture.componentInstance; 26 | expect(app.title).toEqual('admin'); 27 | }); 28 | 29 | it('should render title', () => { 30 | const fixture = TestBed.createComponent(AppComponent); 31 | fixture.detectChanges(); 32 | const compiled = fixture.nativeElement; 33 | expect(compiled.querySelector('.content span').textContent).toContain('admin app is running!'); 34 | }); 35 | }); 36 | -------------------------------------------------------------------------------- /client/web/admin/src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | import { Component, OnInit } from '@angular/core'; 6 | import { Router, NavigationEnd } from '@angular/router'; 7 | import { tap, filter } from 'rxjs/operators'; 8 | 9 | @Component({ 10 | selector: 'app-root', 11 | templateUrl: './app.component.html', 12 | styleUrls: ['./app.component.scss'], 13 | }) 14 | export class AppComponent implements OnInit { 15 | constructor(private router: Router) {} 16 | 17 | ngOnInit() { 18 | this.router.events.subscribe((evt) => { 19 | if (!(evt instanceof NavigationEnd)) { 20 | return; 21 | } 22 | window.scrollTo(0, 0); 23 | }); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /client/web/admin/src/app/cognito.guard.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | import { Injectable } from '@angular/core'; 6 | import { 7 | ActivatedRouteSnapshot, 8 | CanActivate, 9 | Router, 10 | RouterStateSnapshot, 11 | } from '@angular/router'; 12 | import { Auth } from 'aws-amplify'; 13 | import { from, Observable, of } from 'rxjs'; 14 | import { map } from 'rxjs/operators'; 15 | 16 | @Injectable({ providedIn: 'root' }) 17 | export class CognitoGuard implements CanActivate { 18 | constructor(private router: Router) {} 19 | 20 | canActivate( 21 | route: ActivatedRouteSnapshot, 22 | state: RouterStateSnapshot 23 | ): Observable { 24 | function getResolvedUrl(route: ActivatedRouteSnapshot): string { 25 | return route.pathFromRoot 26 | .map((v) => v.url.map((segment) => segment.toString()).join('')) 27 | .join('/'); 28 | } 29 | 30 | return from(Auth.currentSession()).pipe( 31 | map((sesh) => { 32 | const isAuthorized = sesh.isValid(); 33 | console.log( 34 | 'AuthorizationGuard, canActivate isAuthorized: ' + isAuthorized 35 | ); 36 | if (!isAuthorized) { 37 | this.router.navigate(['/unauthorized']); 38 | return false; 39 | } 40 | return true; 41 | }) 42 | ); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /client/web/admin/src/app/containers/default-layout/default-layout.component.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | import { Component, OnInit } from '@angular/core'; 6 | import { Router } from '@angular/router'; 7 | import { Auth } from 'aws-amplify'; 8 | import { from, Observable } from 'rxjs'; 9 | import { map } from 'rxjs/operators'; 10 | import { navItems } from '../../_nav'; 11 | 12 | @Component({ 13 | selector: 'app-dashboard', 14 | templateUrl: './default-layout.component.html', 15 | }) 16 | export class DefaultLayoutComponent implements OnInit { 17 | public sidebarMinimized = false; 18 | public navItems = navItems; 19 | isAuthenticated$: Observable; 20 | username$: Observable; 21 | 22 | constructor(private router: Router) {} 23 | 24 | ngOnInit(): void { 25 | const session$ = from(Auth.currentSession()); 26 | this.isAuthenticated$ = session$.pipe(map((sesh) => sesh.isValid())); 27 | this.username$ = session$.pipe( 28 | map((sesh) => sesh.getAccessToken().payload.email) 29 | ); 30 | } 31 | 32 | toggleMinimize(e): void { 33 | this.sidebarMinimized = e; 34 | } 35 | 36 | logout(): void { 37 | Auth.signOut(); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /client/web/admin/src/app/containers/default-layout/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | export * from './default-layout.component'; 6 | -------------------------------------------------------------------------------- /client/web/admin/src/app/containers/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | export * from './default-layout'; 6 | -------------------------------------------------------------------------------- /client/web/admin/src/app/interceptors/auth.interceptor.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | 6 | import { Injectable } from '@angular/core'; 7 | import { 8 | HttpRequest, 9 | HttpHandler, 10 | HttpEvent, 11 | HttpInterceptor, 12 | } from '@angular/common/http'; 13 | import { from, Observable } from 'rxjs'; 14 | import { Auth } from 'aws-amplify'; 15 | import { map, switchMap } from 'rxjs/operators'; 16 | 17 | @Injectable() 18 | export class AuthInterceptor implements HttpInterceptor { 19 | constructor() {} 20 | idToken: string; 21 | 22 | intercept( 23 | req: HttpRequest, 24 | next: HttpHandler 25 | ): Observable> { 26 | const session$ = from(Auth.currentSession()); 27 | 28 | return session$.pipe( 29 | map((sesh) => sesh.getIdToken()), 30 | switchMap((tok) => { 31 | req = req.clone({ 32 | headers: req.headers.set( 33 | 'Authorization', 34 | 'Bearer ' + tok.getJwtToken() 35 | ), 36 | }); 37 | return next.handle(req); 38 | }) 39 | ); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /client/web/admin/src/app/interceptors/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | 6 | import { HTTP_INTERCEPTORS } from '@angular/common/http'; 7 | 8 | import { AuthInterceptor } from './auth.interceptor'; 9 | 10 | /** Http interceptor providers in outside-in order */ 11 | export const HttpInterceptorProviders = [ 12 | { provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true }, 13 | ]; 14 | -------------------------------------------------------------------------------- /client/web/admin/src/app/models/greeting.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | export interface Greeting { 6 | message: string; 7 | } 8 | -------------------------------------------------------------------------------- /client/web/admin/src/app/tenants/models/tenant.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | export interface Tenant { 6 | name: string; 7 | url: string; 8 | } 9 | -------------------------------------------------------------------------------- /client/web/admin/src/app/tenants/tenant-detail.component.html: -------------------------------------------------------------------------------- 1 |

tenant-detail works!

2 | -------------------------------------------------------------------------------- /client/web/admin/src/app/tenants/tenant-detail.component.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | 6 | import { Component, OnInit } from '@angular/core'; 7 | 8 | @Component({ 9 | selector: 'app-tenant-detail', 10 | templateUrl: './tenant-detail.component.html', 11 | styles: [], 12 | }) 13 | export class TenantDetailComponent implements OnInit { 14 | constructor() {} 15 | 16 | ngOnInit(): void {} 17 | } 18 | -------------------------------------------------------------------------------- /client/web/admin/src/app/tenants/tenant-list.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 | 8 | 13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 | All Tenants 21 |
22 |
23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 |
IdTenant NameE-MailPlan
{{ tenant.tenant_id }}{{ tenant.companyName }}{{ tenant.email }}{{ tenant.plan }}
41 |
42 |
43 |
44 |
45 |
46 | -------------------------------------------------------------------------------- /client/web/admin/src/app/tenants/tenant-list.component.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | 6 | import { Component, OnInit } from '@angular/core'; 7 | import { Observable } from 'rxjs'; 8 | import { Tenant } from './models/tenant'; 9 | import { TenantService } from './tenant.service'; 10 | 11 | @Component({ 12 | selector: 'app-tenant-list', 13 | templateUrl: './tenant-list.component.html', 14 | styles: [], 15 | }) 16 | export class TenantListComponent implements OnInit { 17 | constructor(private tenantSvc: TenantService) {} 18 | tenants: Observable; 19 | 20 | ngOnInit(): void { 21 | this.tenants = this.tenantSvc.getTenants(); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /client/web/admin/src/app/tenants/tenant-routing.module.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | 6 | import { NgModule } from '@angular/core'; 7 | import { Routes, RouterModule } from '@angular/router'; 8 | import { CognitoGuard } from '../cognito.guard'; 9 | import { CreateComponent } from './create.component'; 10 | import { TenantDetailComponent } from './tenant-detail.component'; 11 | import { TenantListComponent } from './tenant-list.component'; 12 | 13 | const routes: Routes = [ 14 | { 15 | path: '', 16 | data: { 17 | title: 'Tenant Management', 18 | }, 19 | children: [ 20 | { 21 | path: '', 22 | component: TenantListComponent, 23 | data: { 24 | title: 'Tenant List', 25 | }, 26 | canActivate: [CognitoGuard], 27 | }, 28 | { 29 | path: 'create', 30 | component: CreateComponent, 31 | data: { 32 | title: 'Create New Tenant', 33 | }, 34 | canActivate: [CognitoGuard], 35 | }, 36 | { 37 | path: ':id', 38 | component: TenantDetailComponent, 39 | data: { 40 | title: 'Tenant Detail', 41 | }, 42 | canActivate: [CognitoGuard], 43 | }, 44 | ], 45 | }, 46 | ]; 47 | 48 | @NgModule({ 49 | imports: [RouterModule.forChild(routes)], 50 | exports: [RouterModule], 51 | }) 52 | export class TenantRoutingModule {} 53 | -------------------------------------------------------------------------------- /client/web/admin/src/app/tenants/tenant.module.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | 6 | import { NgModule } from '@angular/core'; 7 | import { CommonModule } from '@angular/common'; 8 | import { HttpClientModule } from '@angular/common/http'; 9 | 10 | import { TenantRoutingModule } from './tenant-routing.module'; 11 | import { TenantListComponent } from './tenant-list.component'; 12 | import { TenantDetailComponent } from './tenant-detail.component'; 13 | import { CreateComponent } from './create.component'; 14 | import { FormsModule, ReactiveFormsModule } from '@angular/forms'; 15 | import { AlertModule } from 'ngx-bootstrap/alert'; 16 | 17 | @NgModule({ 18 | declarations: [TenantListComponent, TenantDetailComponent, CreateComponent], 19 | imports: [ 20 | CommonModule, 21 | HttpClientModule, 22 | FormsModule, 23 | ReactiveFormsModule, 24 | TenantRoutingModule, 25 | AlertModule.forRoot(), 26 | ], 27 | providers: [HttpClientModule], 28 | }) 29 | export class TenantModule {} 30 | -------------------------------------------------------------------------------- /client/web/admin/src/app/tenants/tenant.service.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | import { HttpClient } from '@angular/common/http'; 6 | import { Injectable } from '@angular/core'; 7 | import { Observable } from 'rxjs'; 8 | import { environment } from '../../environments/environment'; 9 | import { Tenant } from './models/tenant'; 10 | 11 | @Injectable({ 12 | providedIn: 'root', 13 | }) 14 | export class TenantService { 15 | constructor(private http: HttpClient) {} 16 | baseUrl = `${environment.apiUrl}/api`; 17 | tenantsApiUrl = `${this.baseUrl}/tenants`; 18 | registrationApiUrl = `${this.baseUrl}/registration`; 19 | 20 | // TODO strongly-type these anys as tenants once we dial in what the tenant call should return 21 | getTenants(): Observable { 22 | return this.http.get(this.tenantsApiUrl); 23 | } 24 | 25 | createTenant(tenant: any): Observable { 26 | return this.http.post(this.registrationApiUrl, tenant); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /client/web/admin/src/app/users/models/user.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | export interface User { 6 | email: string; 7 | created?: string; 8 | modified?: string; 9 | enabled?: boolean; 10 | status?: string; 11 | verified?: boolean; 12 | } 13 | -------------------------------------------------------------------------------- /client/web/admin/src/app/users/user-create/user-create.component.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | import { Component, OnInit } from '@angular/core'; 6 | import { FormBuilder, FormGroup, Validators } from '@angular/forms'; 7 | import { UsersService } from '../users.service'; 8 | 9 | @Component({ 10 | selector: 'app-user-create', 11 | templateUrl: './user-create.component.html', 12 | styles: [], 13 | }) 14 | export class UserCreateComponent implements OnInit { 15 | userForm: FormGroup; 16 | error: boolean = false; 17 | success: boolean = false; 18 | 19 | constructor(private fb: FormBuilder, private userSvc: UsersService) { 20 | this.userForm = this.fb.group({ 21 | email: [null, [Validators.email, Validators.required]], 22 | }); 23 | } 24 | 25 | ngOnInit(): void {} 26 | 27 | isFieldInvalid(field: string) { 28 | const formField = this.userForm.get(field); 29 | return formField.invalid && (formField.dirty || formField.touched); 30 | } 31 | 32 | displayFieldCss(field: string) { 33 | return { 34 | 'is-invalid': this.isFieldInvalid(field), 35 | }; 36 | } 37 | 38 | hasRequiredError(field: string) { 39 | return this.hasError(field, 'required'); 40 | } 41 | 42 | hasError(field: string, error: any) { 43 | const formField = this.userForm.get(field); 44 | return !!formField.errors[error]; 45 | } 46 | 47 | onSubmit() { 48 | const user = this.userForm.value; 49 | this.userSvc.create(user).subscribe( 50 | () => (this.success = true), 51 | (err) => (this.error = true) 52 | ); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /client/web/admin/src/app/users/user-detail/user-detail.component.html: -------------------------------------------------------------------------------- 1 |

user-detail works!

2 | -------------------------------------------------------------------------------- /client/web/admin/src/app/users/user-detail/user-detail.component.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | import { Component, OnInit } from '@angular/core'; 6 | 7 | @Component({ 8 | selector: 'app-user-detail', 9 | templateUrl: './user-detail.component.html', 10 | styles: [], 11 | }) 12 | export class UserDetailComponent implements OnInit { 13 | constructor() {} 14 | 15 | ngOnInit(): void {} 16 | } 17 | -------------------------------------------------------------------------------- /client/web/admin/src/app/users/user-list/user-list.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 | Users Table 6 |
7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 |
EmailCreated DateModified DateVerifiedStatusEnabled
{{user.email}}{{user.created | date}}{{user.modified | date}}{{user.verified}}{{user.status}}{{user.enabled}}
30 |
31 | 32 |
33 |
34 |
35 |
36 |
37 | -------------------------------------------------------------------------------- /client/web/admin/src/app/users/user-list/user-list.component.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | import { Component, OnInit } from '@angular/core'; 6 | import { Observable, of } from 'rxjs'; 7 | import { User } from '../models/user'; 8 | import { UsersService } from '../users.service'; 9 | 10 | @Component({ 11 | selector: 'app-user-list', 12 | templateUrl: './user-list.component.html', 13 | styles: [], 14 | }) 15 | export class UserListComponent implements OnInit { 16 | users: Observable; 17 | 18 | constructor(private userSvc: UsersService) { 19 | this.users = userSvc.fetch(); 20 | } 21 | 22 | ngOnInit(): void {} 23 | } 24 | -------------------------------------------------------------------------------- /client/web/admin/src/app/users/users-routing.module.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | import { NgModule } from '@angular/core'; 6 | import { Routes, RouterModule } from '@angular/router'; 7 | import { CognitoGuard } from '../cognito.guard'; 8 | import { UserCreateComponent } from './user-create/user-create.component'; 9 | import { UserDetailComponent } from './user-detail/user-detail.component'; 10 | import { UserListComponent } from './user-list/user-list.component'; 11 | 12 | const routes: Routes = [ 13 | { 14 | path: '', 15 | redirectTo: 'list', 16 | }, 17 | { 18 | path: 'list', 19 | data: { 20 | title: 'All Users', 21 | }, 22 | component: UserListComponent, 23 | canActivate: [CognitoGuard], 24 | }, 25 | { 26 | path: 'create', 27 | data: { 28 | title: 'Create User', 29 | }, 30 | component: UserCreateComponent, 31 | canActivate: [CognitoGuard], 32 | }, 33 | { 34 | path: 'detail/:userId', 35 | data: { 36 | title: 'View User Detail', 37 | }, 38 | component: UserDetailComponent, 39 | canActivate: [CognitoGuard], 40 | }, 41 | ]; 42 | 43 | @NgModule({ 44 | imports: [RouterModule.forChild(routes)], 45 | exports: [RouterModule], 46 | }) 47 | export class UsersRoutingModule {} 48 | -------------------------------------------------------------------------------- /client/web/admin/src/app/users/users.module.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | import { NgModule } from '@angular/core'; 6 | import { CommonModule } from '@angular/common'; 7 | 8 | import { UsersRoutingModule } from './users-routing.module'; 9 | import { UserListComponent } from './user-list/user-list.component'; 10 | import { UserCreateComponent } from './user-create/user-create.component'; 11 | import { UserDetailComponent } from './user-detail/user-detail.component'; 12 | import { FormsModule, ReactiveFormsModule } from '@angular/forms'; 13 | import { AlertModule } from 'ngx-bootstrap/alert'; 14 | 15 | @NgModule({ 16 | declarations: [UserListComponent, UserCreateComponent, UserDetailComponent], 17 | imports: [ 18 | AlertModule.forRoot(), 19 | CommonModule, 20 | UsersRoutingModule, 21 | FormsModule, 22 | ReactiveFormsModule, 23 | ], 24 | }) 25 | export class UsersModule {} 26 | -------------------------------------------------------------------------------- /client/web/admin/src/app/users/users.service.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | import { HttpClient } from '@angular/common/http'; 6 | import { Injectable } from '@angular/core'; 7 | import { from, Observable, of } from 'rxjs'; 8 | import { find, mergeMap } from 'rxjs/operators'; 9 | import { environment } from '../../environments/environment'; 10 | import { User } from './models/user'; 11 | 12 | @Injectable({ 13 | providedIn: 'root', 14 | }) 15 | export class UsersService { 16 | apiUrl: string; 17 | 18 | constructor(private http: HttpClient) { 19 | this.apiUrl = `${environment.apiUrl}/users`; 20 | } 21 | 22 | fetch(): Observable { 23 | return this.http.get(this.apiUrl); 24 | } 25 | 26 | get(email: string): Observable { 27 | return this.fetch().pipe( 28 | mergeMap((users) => users), 29 | find((u) => u.email == email) 30 | ); 31 | } 32 | 33 | create(user: User): Observable { 34 | return this.http.post(this.apiUrl, user); 35 | } 36 | 37 | update(email: string, user: User) {} 38 | } 39 | -------------------------------------------------------------------------------- /client/web/admin/src/app/views/auth/auth-routing.module.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | import { NgModule } from '@angular/core'; 6 | import { Routes, RouterModule } from '@angular/router'; 7 | import { LoginInfoComponent } from './login-info/login-info.component'; 8 | 9 | const routes: Routes = [ 10 | { 11 | path: 'info', 12 | component: LoginInfoComponent, 13 | }, 14 | ]; 15 | 16 | @NgModule({ 17 | imports: [RouterModule.forChild(routes)], 18 | exports: [RouterModule], 19 | }) 20 | export class AuthRoutingModule {} 21 | -------------------------------------------------------------------------------- /client/web/admin/src/app/views/auth/auth.module.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | import { NgModule } from '@angular/core'; 6 | import { CommonModule } from '@angular/common'; 7 | 8 | import { AuthRoutingModule } from './auth-routing.module'; 9 | import { LoginInfoComponent } from './login-info/login-info.component'; 10 | 11 | @NgModule({ 12 | declarations: [LoginInfoComponent], 13 | imports: [CommonModule, AuthRoutingModule], 14 | }) 15 | export class AuthModule {} 16 | -------------------------------------------------------------------------------- /client/web/admin/src/app/views/auth/login-info/login-info.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 | 8 |
9 |
10 |
11 |
12 |
13 |
Access Token
14 |
15 |
16 |               
17 |                 {{accessToken$ | async}}
18 |               
19 |             
20 |
21 |
22 |
23 |
24 |
25 |
ID Token
26 |
27 |
28 |               
29 |                 {{idToken$ | async}}
30 |               
31 |             
32 |
33 |
34 |
35 |
36 |
37 | 38 |
39 | 40 |
41 | Is Authenticated: {{ isAuthenticated$ | async }} 42 |
43 | userData 44 |
{{ session$ | async | json }}
45 |
46 |
47 | 48 | 49 | 50 |
51 | You are NOT authenticated 52 |
53 | -------------------------------------------------------------------------------- /client/web/admin/src/app/views/auth/login-info/login-info.component.scss: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this 5 | * software and associated documentation files (the "Software"), to deal in the Software 6 | * without restriction, including without limitation the rights to use, copy, modify, 7 | * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to 8 | * permit persons to whom the Software is furnished to do so. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 11 | * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 12 | * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 13 | * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 14 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 15 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 16 | */ 17 | pre, code { 18 | font-family: monospace, monospace; 19 | } 20 | pre { 21 | white-space: pre-wrap; /* css-3 */ 22 | white-space: -moz-pre-wrap; /* Mozilla, since 1999 */ 23 | white-space: -pre-wrap; /* Opera 4-6 */ 24 | white-space: -o-pre-wrap; /* Opera 7 */ 25 | word-wrap: break-word; /* Internet Explorer 5.5+ */ 26 | overflow: auto; 27 | } 28 | 29 | -------------------------------------------------------------------------------- /client/web/admin/src/app/views/auth/login-info/login-info.component.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | import { Component, OnInit } from '@angular/core'; 6 | import { from, Observable, pipe } from 'rxjs'; 7 | import { Auth } from 'aws-amplify'; 8 | import { CognitoUserSession } from 'amazon-cognito-identity-js'; 9 | import { map } from 'rxjs/operators'; 10 | 11 | @Component({ 12 | selector: 'app-login-info', 13 | templateUrl: './login-info.component.html', 14 | styleUrls: ['login-info.component.scss'], 15 | }) 16 | export class LoginInfoComponent implements OnInit { 17 | session$: Observable; 18 | userData$: Observable; 19 | isAuthenticated$: Observable; 20 | checkSessionChanged$: Observable; 21 | idToken$: Observable; 22 | accessToken$: Observable; 23 | checkSessionChanged: any; 24 | 25 | constructor() {} 26 | 27 | ngOnInit(): void { 28 | this.session$ = from(Auth.currentSession()); 29 | this.accessToken$ = this.session$.pipe( 30 | map((sesh) => sesh.getAccessToken().getJwtToken()) 31 | ); 32 | this.idToken$ = this.session$.pipe( 33 | map((sesh) => sesh.getIdToken().getJwtToken()) 34 | ); 35 | this.isAuthenticated$ = this.session$.pipe(map((sesh) => sesh.isValid())); 36 | } 37 | 38 | logout() { 39 | Auth.signOut(); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /client/web/admin/src/app/views/dashboard/dashboard-routing.module.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | import { NgModule } from '@angular/core'; 6 | import { Routes, RouterModule } from '@angular/router'; 7 | 8 | import { DashboardComponent } from './dashboard.component'; 9 | 10 | const routes: Routes = [ 11 | { 12 | path: '', 13 | component: DashboardComponent, 14 | data: { 15 | title: 'Dashboard', 16 | }, 17 | }, 18 | ]; 19 | 20 | @NgModule({ 21 | imports: [RouterModule.forChild(routes)], 22 | exports: [RouterModule], 23 | }) 24 | export class DashboardRoutingModule {} 25 | -------------------------------------------------------------------------------- /client/web/admin/src/app/views/dashboard/dashboard.module.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | import { NgModule } from '@angular/core'; 6 | import { FormsModule } from '@angular/forms'; 7 | import { ChartsModule } from 'ng2-charts'; 8 | import { BsDropdownModule } from 'ngx-bootstrap/dropdown'; 9 | import { ButtonsModule } from 'ngx-bootstrap/buttons'; 10 | 11 | import { DashboardComponent } from './dashboard.component'; 12 | import { DashboardRoutingModule } from './dashboard-routing.module'; 13 | import { CommonModule } from '@angular/common'; 14 | 15 | @NgModule({ 16 | imports: [ 17 | CommonModule, 18 | FormsModule, 19 | DashboardRoutingModule, 20 | ChartsModule, 21 | BsDropdownModule, 22 | ButtonsModule.forRoot(), 23 | ], 24 | declarations: [DashboardComponent], 25 | }) 26 | export class DashboardModule {} 27 | -------------------------------------------------------------------------------- /client/web/admin/src/app/views/error/404.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 |
6 |

404

7 |

Oops! You're lost.

8 |

The page you are looking for was not found.

9 |
10 |
11 |
12 | 13 |
14 | 15 | 16 | 17 | 18 |
19 |
20 |
21 |
22 |
23 | -------------------------------------------------------------------------------- /client/web/admin/src/app/views/error/404.component.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | import { Component } from '@angular/core'; 6 | 7 | @Component({ 8 | templateUrl: '404.component.html', 9 | }) 10 | export class P404Component { 11 | constructor() {} 12 | } 13 | -------------------------------------------------------------------------------- /client/web/admin/src/app/views/error/500.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 |
6 |

500

7 |

Houston, we have a problem!

8 |

The page you are looking for is temporarily unavailable.

9 |
10 |
11 |
12 | 13 |
14 | 15 | 16 | 17 | 18 |
19 |
20 |
21 |
22 |
23 | -------------------------------------------------------------------------------- /client/web/admin/src/app/views/error/500.component.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | import { Component } from '@angular/core'; 6 | 7 | @Component({ 8 | templateUrl: '500.component.html', 9 | }) 10 | export class P500Component { 11 | constructor() {} 12 | } 13 | -------------------------------------------------------------------------------- /client/web/admin/src/app/views/error/unauthorized.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |

Unauthorized

4 |

You must login to view this content.

5 |
6 |
7 | -------------------------------------------------------------------------------- /client/web/admin/src/app/views/error/unauthorized.component.scss: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this 5 | * software and associated documentation files (the "Software"), to deal in the Software 6 | * without restriction, including without limitation the rights to use, copy, modify, 7 | * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to 8 | * permit persons to whom the Software is furnished to do so. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 11 | * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 12 | * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 13 | * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 14 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 15 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 16 | */ 17 | .center-screen { 18 | display: flex; 19 | flex-direction: column; 20 | justify-content: center; 21 | align-items: center; 22 | text-align: center; 23 | min-height: 100vh; 24 | } 25 | -------------------------------------------------------------------------------- /client/web/admin/src/app/views/error/unauthorized.component.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | import { Component, OnInit } from '@angular/core'; 6 | 7 | @Component({ 8 | selector: 'app-unauthorized', 9 | templateUrl: './unauthorized.component.html', 10 | styleUrls: ['./unauthorized.component.scss'], 11 | }) 12 | export class UnauthorizedComponent implements OnInit { 13 | constructor() {} 14 | 15 | ngOnInit(): void {} 16 | 17 | login() { 18 | // this.oidcSecurityService.authorize(); 19 | return false; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /client/web/admin/src/assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-saas-factory-eks-saas-api-gateway-tiering-and-throttling/5374aedde1470fc23bdbdc5fe58da16f873642b1/client/web/admin/src/assets/.gitkeep -------------------------------------------------------------------------------- /client/web/admin/src/assets/img/brand/adminapp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-saas-factory-eks-saas-api-gateway-tiering-and-throttling/5374aedde1470fc23bdbdc5fe58da16f873642b1/client/web/admin/src/assets/img/brand/adminapp.png -------------------------------------------------------------------------------- /client/web/admin/src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-saas-factory-eks-saas-api-gateway-tiering-and-throttling/5374aedde1470fc23bdbdc5fe58da16f873642b1/client/web/admin/src/favicon.ico -------------------------------------------------------------------------------- /client/web/admin/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Admin 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /client/web/admin/src/main.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | import { enableProdMode } from '@angular/core'; 6 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 7 | 8 | import { AppModule } from './app/app.module'; 9 | import { environment } from './environments/environment'; 10 | import Amplify from 'aws-amplify'; 11 | import aws_exports from './aws-exports'; 12 | Amplify.configure(aws_exports); 13 | 14 | if (environment.production) { 15 | enableProdMode(); 16 | } 17 | 18 | platformBrowserDynamic() 19 | .bootstrapModule(AppModule) 20 | .catch((err) => console.error(err)); 21 | -------------------------------------------------------------------------------- /client/web/admin/src/scss/_custom.scss: -------------------------------------------------------------------------------- 1 | // Here you can add other styles 2 | -------------------------------------------------------------------------------- /client/web/admin/src/scss/_variables.scss: -------------------------------------------------------------------------------- 1 | // Variable overrides 2 | -------------------------------------------------------------------------------- /client/web/admin/src/scss/style.scss: -------------------------------------------------------------------------------- 1 | // If you want to override variables do it here 2 | @import "variables"; 3 | 4 | // Import styles 5 | @import "~@coreui/coreui/scss/coreui"; 6 | 7 | // If you want to add something do it here 8 | @import "custom"; 9 | @import "~/node_modules/font-awesome/scss/font-awesome.scss"; 10 | $fa-font-path: "node_modules/font-awesome/fonts"; 11 | -------------------------------------------------------------------------------- /client/web/admin/src/scss/vendors/_variables.scss: -------------------------------------------------------------------------------- 1 | // Override Boostrap variables 2 | @import "../variables"; 3 | @import "~bootstrap/scss/mixins"; 4 | @import "~@coreui/coreui/scss/variables"; 5 | -------------------------------------------------------------------------------- /client/web/admin/src/scss/vendors/chart.js/chart.scss: -------------------------------------------------------------------------------- 1 | // Import variables 2 | @import '../variables'; 3 | 4 | .chart-legend, 5 | .bar-legend, 6 | .line-legend, 7 | .pie-legend, 8 | .radar-legend, 9 | .polararea-legend, 10 | .doughnut-legend { 11 | list-style-type: none; 12 | margin-top: 5px; 13 | text-align: center; 14 | -webkit-padding-start: 0; 15 | -moz-padding-start: 0; 16 | padding-left: 0; 17 | } 18 | .chart-legend li, 19 | .bar-legend li, 20 | .line-legend li, 21 | .pie-legend li, 22 | .radar-legend li, 23 | .polararea-legend li, 24 | .doughnut-legend li { 25 | display: inline-block; 26 | white-space: nowrap; 27 | position: relative; 28 | margin-bottom: 4px; 29 | @include border-radius($border-radius); 30 | padding: 2px 8px 2px 28px; 31 | font-size: smaller; 32 | cursor: default; 33 | } 34 | .chart-legend li span, 35 | .bar-legend li span, 36 | .line-legend li span, 37 | .pie-legend li span, 38 | .radar-legend li span, 39 | .polararea-legend li span, 40 | .doughnut-legend li span { 41 | display: block; 42 | position: absolute; 43 | left: 0; 44 | top: 0; 45 | width: 20px; 46 | height: 20px; 47 | @include border-radius($border-radius); 48 | } 49 | -------------------------------------------------------------------------------- /client/web/admin/src/test.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | // This file is required by karma.conf.js and loads recursively all the .spec and framework files 6 | 7 | import 'zone.js/testing'; 8 | import { getTestBed } from '@angular/core/testing'; 9 | import { 10 | BrowserDynamicTestingModule, 11 | platformBrowserDynamicTesting, 12 | } from '@angular/platform-browser-dynamic/testing'; 13 | 14 | declare const require: { 15 | context( 16 | path: string, 17 | deep?: boolean, 18 | filter?: RegExp 19 | ): { 20 | keys(): string[]; 21 | (id: string): T; 22 | }; 23 | }; 24 | 25 | // First, initialize the Angular testing environment. 26 | getTestBed().initTestEnvironment( 27 | BrowserDynamicTestingModule, 28 | platformBrowserDynamicTesting() 29 | ); 30 | // Then we find all the tests. 31 | const context = require.context('./', true, /\.spec\.ts$/); 32 | // And load the modules. 33 | context.keys().map(context); 34 | -------------------------------------------------------------------------------- /client/web/admin/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */ 2 | { 3 | "extends": "./tsconfig.json", 4 | "compilerOptions": { 5 | "outDir": "./out-tsc/app", 6 | "types": [] 7 | }, 8 | "files": [ 9 | "src/main.ts", 10 | "src/polyfills.ts" 11 | ], 12 | "include": [ 13 | "src/**/*.d.ts" 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /client/web/admin/tsconfig.json: -------------------------------------------------------------------------------- 1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */ 2 | { 3 | "compileOnSave": false, 4 | "compilerOptions": { 5 | "baseUrl": "./", 6 | "outDir": "./dist/out-tsc", 7 | // "forceConsistentCasingInFileNames": true, 8 | // "strict": true, 9 | // "noImplicitReturns": true, 10 | // "noFallthroughCasesInSwitch": true, 11 | // "sourceMap": true, 12 | "declaration": false, 13 | // "downlevelIteration": true, 14 | "experimentalDecorators": true, 15 | "moduleResolution": "node", 16 | "importHelpers": true, 17 | "target": "es2015", 18 | "module": "es2020", 19 | "lib": [ 20 | "es2018", 21 | "dom" 22 | ] 23 | }, 24 | "angularCompilerOptions": { 25 | "enableI18nLegacyMessageIdFormat": false, 26 | // "strictInjectionParameters": true, 27 | // "strictInputAccessModifiers": true, 28 | // "strictTemplates": true 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /client/web/admin/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */ 2 | { 3 | "extends": "./tsconfig.json", 4 | "compilerOptions": { 5 | "outDir": "./out-tsc/spec", 6 | "types": [ 7 | "jasmine" 8 | ] 9 | }, 10 | "files": [ 11 | "src/test.ts", 12 | "src/polyfills.ts" 13 | ], 14 | "include": [ 15 | "src/**/*.spec.ts", 16 | "src/**/*.d.ts" 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /client/web/application/.gitignore: -------------------------------------------------------------------------------- 1 | #amplify 2 | amplify/\#current-cloud-backend 3 | amplify/.config/local-* 4 | amplify/logs 5 | amplify/mock-data 6 | amplify/backend/amplify-meta.json 7 | amplify/backend/awscloudformation 8 | amplify/backend/.temp 9 | build/ 10 | dist/ 11 | node_modules/ 12 | aws-exports.js 13 | awsconfiguration.json 14 | amplifyconfiguration.json 15 | amplifyconfiguration.dart 16 | amplify-build-config.json 17 | amplify-gradle-config.json 18 | amplifytools.xcconfig 19 | .secret-* -------------------------------------------------------------------------------- /client/web/application/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM public.ecr.aws/bitnami/node:16.5.0 AS build 2 | WORKDIR /usr/src/app 3 | COPY package.json yarn.lock ./ 4 | RUN yarn 5 | COPY . . 6 | RUN yarn build:prod 7 | 8 | FROM public.ecr.aws/nginx/nginx:1.21 9 | COPY nginx.conf /etc/nginx/conf.d/default.conf 10 | COPY --from=build /usr/src/app/dist /usr/share/nginx/html/app 11 | -------------------------------------------------------------------------------- /client/web/application/amplify/.config/project-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "projectName": "application", 3 | "version": "3.1", 4 | "frontend": "javascript", 5 | "javascript": { 6 | "framework": "angular", 7 | "config": { 8 | "SourceDir": "src", 9 | "DistributionDir": "dist", 10 | "BuildCommand": "npm run-script build", 11 | "StartCommand": "ng serve" 12 | } 13 | }, 14 | "providers": [ 15 | "awscloudformation" 16 | ] 17 | } -------------------------------------------------------------------------------- /client/web/application/amplify/README.md: -------------------------------------------------------------------------------- 1 | # Getting Started with Amplify CLI 2 | This directory was generated by [Amplify CLI](https://docs.amplify.aws/cli). 3 | 4 | Helpful resources: 5 | - Amplify documentation: https://docs.amplify.aws 6 | - Amplify CLI documentation: https://docs.amplify.aws/cli 7 | - More details on this folder & generated files: https://docs.amplify.aws/cli/reference/files 8 | - Join Amplify's community: https://amplify.aws/community/ 9 | -------------------------------------------------------------------------------- /client/web/application/amplify/backend/auth/application465cad6c/parameters.json: -------------------------------------------------------------------------------- 1 | { 2 | "authSelections": "userPoolOnly", 3 | "resourceName": "application465cad6c", 4 | "serviceType": "imported", 5 | "region": "us-west-2" 6 | } -------------------------------------------------------------------------------- /client/web/application/amplify/backend/backend-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "auth": { 3 | "application465cad6c": { 4 | "service": "Cognito", 5 | "serviceType": "imported", 6 | "providerPlugin": "awscloudformation", 7 | "dependsOn": [], 8 | "customAuth": false 9 | } 10 | } 11 | } -------------------------------------------------------------------------------- /client/web/application/amplify/backend/tags.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "Key": "user:Stack", 4 | "Value": "{project-env}" 5 | }, 6 | { 7 | "Key": "user:Application", 8 | "Value": "{project-name}" 9 | } 10 | ] -------------------------------------------------------------------------------- /client/web/application/amplify/cli.json: -------------------------------------------------------------------------------- 1 | { 2 | "features": { 3 | "graphqltransformer": { 4 | "addmissingownerfields": true, 5 | "validatetypenamereservedwords": true, 6 | "useexperimentalpipelinedtransformer": false, 7 | "enableiterativegsiupdates": true, 8 | "secondarykeyasgsi": true, 9 | "skipoverridemutationinputtypes": true 10 | }, 11 | "frontend-ios": { 12 | "enablexcodeintegration": true 13 | }, 14 | "auth": { 15 | "enablecaseinsensitivity": true, 16 | "useinclusiveterminology": true 17 | }, 18 | "codegen": { 19 | "useappsyncmodelgenplugin": true, 20 | "usedocsgeneratorplugin": true, 21 | "usetypesgeneratorplugin": true, 22 | "cleangeneratedmodelsdirectory": true, 23 | "retaincasestyle": true 24 | }, 25 | "appsync": { 26 | "generategraphqlpermissions": true 27 | } 28 | } 29 | } -------------------------------------------------------------------------------- /client/web/application/amplify/team-provider-info.json: -------------------------------------------------------------------------------- 1 | { 2 | "dev": { 3 | "awscloudformation": { 4 | "AuthRoleName": "amplify-application-dev-134609-authRole", 5 | "UnauthRoleArn": "arn:aws:iam::540983619545:role/amplify-application-dev-134609-unauthRole", 6 | "AuthRoleArn": "arn:aws:iam::540983619545:role/amplify-application-dev-134609-authRole", 7 | "Region": "us-west-2", 8 | "DeploymentBucketName": "amplify-application-dev-134609-deployment", 9 | "UnauthRoleName": "amplify-application-dev-134609-unauthRole", 10 | "StackName": "amplify-application-dev-134609", 11 | "StackId": "arn:aws:cloudformation:us-west-2:540983619545:stack/amplify-application-dev-134609/63e76620-cc88-11eb-ae44-02424844b205", 12 | "AmplifyAppId": "d2aksi6oczkkcd" 13 | }, 14 | "categories": { 15 | "auth": { 16 | "application465cad6c": { 17 | "userPoolId": "us-west-2_5KTTs8gio", 18 | "userPoolName": "AdminUserPoolD0AF18CF-s2hWZ6v6YfXP", 19 | "webClientId": "19nmj7lfou7a7jdgjmgsal8qup", 20 | "nativeClientId": "19nmj7lfou7a7jdgjmgsal8qup" 21 | } 22 | } 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /client/web/application/browserslist: -------------------------------------------------------------------------------- 1 | # This file is used by the build system to adjust CSS and JS output to support the specified browsers below. 2 | # For additional information regarding the format and rule options, please see: 3 | # https://github.com/browserslist/browserslist#queries 4 | 5 | # You can see what browsers were selected by your queries by running: 6 | # npx browserslist 7 | 8 | > 0.5% 9 | last 2 versions 10 | Firefox ESR 11 | not dead 12 | not IE 9-11 # For IE 9-11 support, remove 'not'. -------------------------------------------------------------------------------- /client/web/application/e2e/app.po.ts: -------------------------------------------------------------------------------- 1 | import { browser, by, element } from 'protractor'; 2 | 3 | export class AppDashboard { 4 | 5 | getBrowser() { 6 | return browser; 7 | } 8 | 9 | navigateTo() { 10 | return browser.get('/'); 11 | } 12 | 13 | getParagraphText() { 14 | return element(by.xpath('/html/body/app-dashboard/div/main/div/ng-component/div/div[2]/div[1]/div[1]/div[1]/h4')).getText(); 15 | } 16 | getBody() { 17 | return element(by.xpath('/html/body')); 18 | } 19 | getByCss(selector) { 20 | return element.all(by.css(selector)); 21 | } 22 | getFooterText() { 23 | return element(by.className('app-footer')).getText(); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /client/web/application/e2e/tsconfig.e2e.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/e2e", 5 | "module": "commonjs", 6 | "target": "es5", 7 | "types":[ 8 | "jasmine", 9 | "node" 10 | ] 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /client/web/application/k8s/template.txt: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: application 5 | spec: 6 | replicas: 1 7 | selector: 8 | matchLabels: 9 | app: application 10 | template: 11 | metadata: 12 | labels: 13 | app: application 14 | spec: 15 | containers: 16 | - name: application 17 | image: $APPLICATIONECR:latest 18 | imagePullPolicy: Always 19 | ports: 20 | - containerPort: 80 21 | name: "http" 22 | --- 23 | apiVersion: v1 24 | kind: Service 25 | metadata: 26 | name: application-service 27 | spec: 28 | selector: 29 | app: application 30 | ports: 31 | - name: http 32 | protocol: TCP 33 | port: 80 34 | targetPort: 80 35 | type: NodePort 36 | --- 37 | apiVersion: networking.k8s.io/v1 38 | kind: Ingress 39 | metadata: 40 | name: application-service-ingress 41 | annotations: 42 | kubernetes.io/ingress.class: "nginx" 43 | nginx.org/mergeable-ingress-type: "minion" 44 | spec: 45 | rules: 46 | - host: $ELBURL 47 | http: 48 | paths: 49 | - backend: 50 | service: 51 | name: application-service 52 | port: 53 | number: 80 54 | path: /$TENANTPATH 55 | pathType: Prefix 56 | -------------------------------------------------------------------------------- /client/web/application/k8s/template.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: application 5 | spec: 6 | replicas: 1 7 | selector: 8 | matchLabels: 9 | app: application 10 | template: 11 | metadata: 12 | labels: 13 | app: application 14 | spec: 15 | containers: 16 | - name: application 17 | image: APPLICATION_ECR_REPO:latest 18 | imagePullPolicy: Always 19 | ports: 20 | - containerPort: 80 21 | name: "http" 22 | --- 23 | apiVersion: v1 24 | kind: Service 25 | metadata: 26 | name: application-service 27 | spec: 28 | selector: 29 | app: application 30 | ports: 31 | - name: http 32 | protocol: TCP 33 | port: 80 34 | targetPort: 80 35 | type: NodePort 36 | --- 37 | apiVersion: networking.k8s.io/v1 38 | kind: Ingress 39 | metadata: 40 | name: application-service-ingress 41 | annotations: 42 | kubernetes.io/ingress.class: "nginx" 43 | nginx.org/mergeable-ingress-type: "minion" 44 | spec: 45 | rules: 46 | - host: ELB_URL 47 | http: 48 | paths: 49 | - backend: 50 | service: 51 | name: application-service 52 | port: 53 | number: 80 54 | path: /TENANT_PATH 55 | pathType: Prefix 56 | -------------------------------------------------------------------------------- /client/web/application/nginx.conf: -------------------------------------------------------------------------------- 1 | server { 2 | listen 80; 3 | 4 | location ~(?:\/.*?)(\/.*) { 5 | alias /usr/share/nginx/html/app/; 6 | index index.html; 7 | try_files $uri $uri/ $uri $1 $1/index.html =404; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /client/web/application/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "eks-ref-arch-application", 3 | "scripts": { 4 | "ng": "ng", 5 | "start": "ng serve", 6 | "build": "ng build", 7 | "watch": "ng build --watch --configuration development", 8 | "test": "ng test" 9 | }, 10 | "private": true, 11 | "dependencies": { 12 | "@angular/animations": "^14.0.0", 13 | "@angular/cdk": "14.0.4", 14 | "@angular/common": "^14.0.0", 15 | "@angular/compiler": "^14.0.0", 16 | "@angular/core": "^14.0.0", 17 | "@angular/forms": "^14.0.0", 18 | "@angular/material": "14.0.4", 19 | "@angular/platform-browser": "^14.0.0", 20 | "@angular/platform-browser-dynamic": "^14.0.0", 21 | "@angular/router": "^14.0.0", 22 | "@aws-amplify/ui-angular": "^2.4.14", 23 | "aws-amplify": "^4.3.27", 24 | "bootstrap": "5.1.3", 25 | "chart.js": "^3.8.0", 26 | "chartjs-plugin-datalabels": "^2.0.0", 27 | "ng2-charts": "^4.0.0", 28 | "rxjs": "~7.5.0", 29 | "tslib": "^2.3.0", 30 | "zone.js": "~0.11.4" 31 | }, 32 | "devDependencies": { 33 | "@angular-devkit/build-angular": "^14.0.5", 34 | "@angular/cli": "~14.0.5", 35 | "@angular/compiler-cli": "^14.0.0", 36 | "@types/jasmine": "~4.0.0", 37 | "jasmine-core": "~4.1.0", 38 | "karma": "~6.3.0", 39 | "karma-chrome-launcher": "~3.1.0", 40 | "karma-coverage": "~2.2.0", 41 | "karma-jasmine": "~5.0.0", 42 | "karma-jasmine-html-reporter": "~1.7.0", 43 | "typescript": "~4.7.2" 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /client/web/application/protractor.conf.js: -------------------------------------------------------------------------------- 1 | // Protractor configuration file, see link for more information 2 | // https://github.com/angular/protractor/blob/master/lib/config.ts 3 | 4 | const { SpecReporter } = require('jasmine-spec-reporter'); 5 | 6 | exports.config = { 7 | allScriptsTimeout: 11000, 8 | specs: [ 9 | './e2e/**/*.e2e-spec.ts' 10 | ], 11 | capabilities: { 12 | 'browserName': 'chrome' 13 | }, 14 | directConnect: true, 15 | baseUrl: 'http://localhost:4200/', 16 | framework: 'jasmine', 17 | jasmineNodeOpts: { 18 | showColors: true, 19 | defaultTimeoutInterval: 30000, 20 | print: function() {} 21 | }, 22 | onPrepare() { 23 | require('ts-node').register({ 24 | project: 'e2e/tsconfig.e2e.json' 25 | }); 26 | jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } })); 27 | } 28 | }; 29 | -------------------------------------------------------------------------------- /client/web/application/proxy-conf.json: -------------------------------------------------------------------------------- 1 | { 2 | "/api": { 3 | "target": "http://localhost:5000", 4 | "secure": false 5 | } 6 | } -------------------------------------------------------------------------------- /client/web/application/src/app/app.component.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-saas-factory-eks-saas-api-gateway-tiering-and-throttling/5374aedde1470fc23bdbdc5fe58da16f873642b1/client/web/application/src/app/app.component.css -------------------------------------------------------------------------------- /client/web/application/src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | import { Component, OnInit } from '@angular/core'; 6 | import { Router, NavigationEnd } from '@angular/router'; 7 | import { tap, filter } from 'rxjs/operators'; 8 | 9 | @Component({ 10 | selector: 'body', 11 | template: ` 12 | 13 | `, 14 | }) 15 | export class AppComponent implements OnInit { 16 | constructor(private router: Router) {} 17 | 18 | ngOnInit() { 19 | this.router.events.subscribe((evt) => { 20 | if (!(evt instanceof NavigationEnd)) { 21 | return; 22 | } 23 | window.scrollTo(0, 0); 24 | }); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /client/web/application/src/app/auth-info.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | export interface AuthInfo { 6 | aws_project_region: string; 7 | aws_cognito_region: string; 8 | aws_user_pools_id: string; 9 | aws_user_pools_web_client_id: string; 10 | } 11 | -------------------------------------------------------------------------------- /client/web/application/src/app/cognito.guard.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | import { Injectable } from '@angular/core'; 6 | import { ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot } from '@angular/router'; 7 | import { Auth } from 'aws-amplify'; 8 | import { from, Observable, of } from 'rxjs'; 9 | import { map } from 'rxjs/operators'; 10 | 11 | @Injectable({ providedIn: 'root' }) 12 | export class CognitoGuard implements CanActivate { 13 | constructor(private router: Router) {} 14 | 15 | canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable { 16 | const sesh = Auth.currentSession().catch((err) => { 17 | return of({ isValid: false }); 18 | }); 19 | 20 | console.log(sesh); 21 | return from(Auth.currentSession()).pipe( 22 | map((sesh) => { 23 | const isAuthorized = sesh.isValid(); 24 | console.log('AuthorizationGuard, canActivate isAuthorized: ' + isAuthorized); 25 | if (!isAuthorized) { 26 | this.router.navigate(['/unauthorized']); 27 | return false; 28 | } 29 | return true; 30 | }) 31 | ); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /client/web/application/src/app/containers/default-layout/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | export * from './default-layout.component'; 6 | -------------------------------------------------------------------------------- /client/web/application/src/app/containers/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | export * from './default-layout'; 6 | -------------------------------------------------------------------------------- /client/web/application/src/app/interceptors/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | import { HTTP_INTERCEPTORS } from '@angular/common/http'; 6 | 7 | import { AuthInterceptor } from './auth.interceptor'; 8 | 9 | /** Http interceptor providers in outside-in order */ 10 | export const httpInterceptorProviders = [ 11 | { provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true }, 12 | ]; 13 | -------------------------------------------------------------------------------- /client/web/application/src/app/orders/models/order.interface.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | import { OrderProduct } from './orderproduct.interface'; 6 | 7 | export interface Order { 8 | id: string; 9 | name: string; 10 | products: OrderProduct[]; 11 | } 12 | -------------------------------------------------------------------------------- /client/web/application/src/app/orders/models/orderproduct.interface.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | export interface OrderProduct { 6 | productId: string; 7 | price: number; 8 | quantity: number; 9 | } 10 | -------------------------------------------------------------------------------- /client/web/application/src/app/orders/orders-list/orders-list.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
Orders Table
5 |
6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 26 | 27 | 28 | 29 | 30 |
NameLine ItemsTotal
17 | {{ order.name }} 25 | {{ order.products?.length || 0 }}{{ sum(order) | currency }}
31 |
32 | 33 |
34 |
35 |
36 |
37 |
38 | -------------------------------------------------------------------------------- /client/web/application/src/app/orders/orders-list/orders-list.component.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | import { Component, OnInit } from '@angular/core'; 6 | import { Observable } from 'rxjs'; 7 | import { Order } from '../models/order.interface'; 8 | import { OrdersService } from '../orders.service'; 9 | 10 | @Component({ 11 | selector: 'app-orders-list', 12 | templateUrl: './orders-list.component.html', 13 | styles: [], 14 | }) 15 | export class OrdersListComponent implements OnInit { 16 | orders: Observable; 17 | constructor(private orderSvc: OrdersService) {} 18 | 19 | ngOnInit(): void { 20 | this.orders = this.orderSvc.fetch(); 21 | } 22 | 23 | sum(order: Order): number { 24 | return order.products.map((p) => p.price * p.quantity).reduce((acc, curr) => acc + curr); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /client/web/application/src/app/orders/orders-routing.module.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | import { NgModule } from '@angular/core'; 6 | import { Routes, RouterModule } from '@angular/router'; 7 | import { CognitoGuard } from '../cognito.guard'; 8 | import { OrdersCreateComponent } from './orders-create/orders-create.component'; 9 | import { OrdersDetailComponent } from './orders-detail/orders-detail.component'; 10 | import { OrdersListComponent } from './orders-list/orders-list.component'; 11 | 12 | const routes: Routes = [ 13 | { 14 | path: '', 15 | redirectTo: 'list', 16 | }, 17 | { 18 | path: 'list', 19 | data: { 20 | title: 'All Orders', 21 | }, 22 | component: OrdersListComponent, 23 | canActivate: [CognitoGuard], 24 | }, 25 | { 26 | path: 'create', 27 | data: { 28 | title: 'Create Order', 29 | }, 30 | component: OrdersCreateComponent, 31 | canActivate: [CognitoGuard], 32 | }, 33 | { 34 | path: 'detail/:orderId', 35 | data: { 36 | title: 'View Order Detail', 37 | }, 38 | component: OrdersDetailComponent, 39 | canActivate: [CognitoGuard], 40 | }, 41 | ]; 42 | 43 | @NgModule({ 44 | imports: [RouterModule.forChild(routes)], 45 | exports: [RouterModule], 46 | }) 47 | export class OrdersRoutingModule {} 48 | -------------------------------------------------------------------------------- /client/web/application/src/app/orders/orders.module.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | import { NgModule } from '@angular/core'; 6 | import { CommonModule } from '@angular/common'; 7 | import { FormsModule, ReactiveFormsModule } from '@angular/forms'; 8 | 9 | import { OrdersRoutingModule } from './orders-routing.module'; 10 | import { OrdersListComponent } from './orders-list/orders-list.component'; 11 | import { OrdersCreateComponent } from './orders-create/orders-create.component'; 12 | import { OrdersDetailComponent } from './orders-detail/orders-detail.component'; 13 | 14 | import { PopoverModule } from 'ngx-bootstrap/popover'; 15 | 16 | @NgModule({ 17 | declarations: [OrdersListComponent, OrdersCreateComponent, OrdersDetailComponent], 18 | imports: [ 19 | CommonModule, 20 | FormsModule, 21 | OrdersRoutingModule, 22 | PopoverModule.forRoot(), 23 | ReactiveFormsModule, 24 | ], 25 | }) 26 | export class OrdersModule {} 27 | -------------------------------------------------------------------------------- /client/web/application/src/app/products/models/product.interface.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | export interface Product { 6 | product_id: string; 7 | name: string; 8 | price: number; 9 | description: string; 10 | } 11 | -------------------------------------------------------------------------------- /client/web/application/src/app/products/product-create/product-create.component.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | import { Component, OnInit } from '@angular/core'; 6 | import { FormBuilder, FormGroup, Validators } from '@angular/forms'; 7 | import { Router } from '@angular/router'; 8 | import { ProductService } from '../product.service'; 9 | 10 | @Component({ 11 | selector: 'app-product-create', 12 | templateUrl: './product-create.component.html', 13 | styles: [], 14 | }) 15 | export class ProductCreateComponent implements OnInit { 16 | constructor( 17 | private router: Router, 18 | private productSvc: ProductService, 19 | private fb: FormBuilder 20 | ) {} 21 | productForm: FormGroup; 22 | files: File[]; 23 | 24 | ngOnInit(): void { 25 | this.productForm = this.fb.group({ 26 | name: ['', Validators.required], 27 | price: ['', Validators.required], 28 | description: '', 29 | }); 30 | } 31 | 32 | submit() { 33 | this.productSvc.post(this.productForm.value).subscribe( 34 | () => { 35 | this.router.navigate(['products']); 36 | }, 37 | (err) => { 38 | alert(err); 39 | console.error(err); 40 | } 41 | ); 42 | } 43 | 44 | cancel() { 45 | this.router.navigate(['products']); 46 | } 47 | 48 | onSelect(event: { addedFiles: any }) { 49 | console.log(event); 50 | this.files.push(...event.addedFiles); 51 | } 52 | 53 | onRemove(event: File) { 54 | console.log(event); 55 | this.files.splice(this.files.indexOf(event), 1); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /client/web/application/src/app/products/product-list/product-list.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
Products Table
5 |
6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 26 | 27 | 28 | 29 | 30 |
NamePriceDescription
17 | {{ product.name }} 25 | {{ product.price | currency }}{{ product.description }}
31 |
32 | 33 |
34 |
35 |
36 |
37 |
38 | -------------------------------------------------------------------------------- /client/web/application/src/app/products/product-list/product-list.component.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | import { Component, EventEmitter, OnInit, Output } from '@angular/core'; 6 | import { Router } from '@angular/router'; 7 | import { Observable } from 'rxjs'; 8 | import { Product } from '../models/product.interface'; 9 | import { ProductService } from '../product.service'; 10 | 11 | @Component({ 12 | selector: 'app-product-list', 13 | templateUrl: './product-list.component.html', 14 | styles: ['td > a { cursor: pointer; } '], 15 | }) 16 | export class ProductListComponent implements OnInit { 17 | products$: Observable; 18 | 19 | constructor(private productSvc: ProductService, private router: Router) {} 20 | 21 | ngOnInit(): void { 22 | this.refresh(); 23 | } 24 | 25 | onEdit(product: Product) { 26 | this.router.navigate(['products', 'edit', product.product_id]); 27 | return false; 28 | } 29 | 30 | onRemove(product: Product) { 31 | this.productSvc.delete(product); 32 | this.refresh(); 33 | } 34 | 35 | onCreate() { 36 | this.router.navigate(['products', 'create']); 37 | } 38 | 39 | refresh() { 40 | this.products$ = this.productSvc.fetch(); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /client/web/application/src/app/products/products-routing.module.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | import { NgModule } from '@angular/core'; 6 | import { Routes, RouterModule } from '@angular/router'; 7 | import { CognitoGuard } from '../cognito.guard'; 8 | import { ProductCreateComponent } from './product-create/product-create.component'; 9 | import { ProductEditComponent } from './product-edit/product-edit.component'; 10 | import { ProductListComponent } from './product-list/product-list.component'; 11 | 12 | const routes: Routes = [ 13 | { 14 | path: '', 15 | redirectTo: 'list', 16 | }, 17 | { 18 | path: 'list', 19 | data: { 20 | title: 'Product List', 21 | }, 22 | component: ProductListComponent, 23 | canActivate: [CognitoGuard], 24 | }, 25 | { 26 | path: 'create', 27 | data: { 28 | title: 'Create new Product', 29 | }, 30 | component: ProductCreateComponent, 31 | canActivate: [CognitoGuard], 32 | }, 33 | { 34 | path: 'edit/:productId', 35 | data: { 36 | title: 'Edit Product', 37 | }, 38 | component: ProductEditComponent, 39 | canActivate: [CognitoGuard], 40 | }, 41 | ]; 42 | 43 | @NgModule({ 44 | imports: [RouterModule.forChild(routes)], 45 | exports: [RouterModule], 46 | }) 47 | export class ProductsRoutingModule {} 48 | -------------------------------------------------------------------------------- /client/web/application/src/app/products/products.module.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | import { NgModule } from '@angular/core'; 6 | import { CommonModule } from '@angular/common'; 7 | import { FormsModule, ReactiveFormsModule } from '@angular/forms'; 8 | 9 | import { ProductsRoutingModule } from './products-routing.module'; 10 | import { ProductListComponent } from './product-list/product-list.component'; 11 | import { ProductCreateComponent } from './product-create/product-create.component'; 12 | import { ProductEditComponent } from './product-edit/product-edit.component'; 13 | 14 | // 3P components 15 | import { PopoverModule } from 'ngx-bootstrap/popover'; 16 | 17 | @NgModule({ 18 | declarations: [ProductListComponent, ProductCreateComponent, ProductEditComponent], 19 | imports: [ 20 | CommonModule, 21 | FormsModule, 22 | PopoverModule.forRoot(), 23 | ProductsRoutingModule, 24 | ReactiveFormsModule, 25 | ], 26 | }) 27 | export class ProductsModule {} 28 | -------------------------------------------------------------------------------- /client/web/application/src/app/users/models/user.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | export interface User { 6 | email: string; 7 | created?: string; 8 | modified?: string; 9 | enabled?: boolean; 10 | status?: string; 11 | verified?: boolean; 12 | } 13 | -------------------------------------------------------------------------------- /client/web/application/src/app/users/user-detail/user-detail.component.html: -------------------------------------------------------------------------------- 1 |

user-detail works!

2 | -------------------------------------------------------------------------------- /client/web/application/src/app/users/user-detail/user-detail.component.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | import { Component, OnInit } from '@angular/core'; 6 | 7 | @Component({ 8 | selector: 'app-user-detail', 9 | templateUrl: './user-detail.component.html', 10 | styles: [], 11 | }) 12 | export class UserDetailComponent implements OnInit { 13 | constructor() {} 14 | 15 | ngOnInit(): void {} 16 | } 17 | -------------------------------------------------------------------------------- /client/web/application/src/app/users/user-list/user-list.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 | Users Table 6 |
7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 |
EmailCreated DateModified DateVerifiedStatusEnabled
{{user.email}}{{user.created | date}}{{user.modified | date}}{{user.verified}}{{user.status}}{{user.enabled}}
30 |
31 | 32 |
33 |
34 |
35 |
36 |
37 | -------------------------------------------------------------------------------- /client/web/application/src/app/users/user-list/user-list.component.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | import { Component, OnInit } from '@angular/core'; 6 | import { Observable, of } from 'rxjs'; 7 | import { User } from '../models/user'; 8 | import { UsersService } from '../users.service'; 9 | 10 | @Component({ 11 | selector: 'app-user-list', 12 | templateUrl: './user-list.component.html', 13 | styles: [], 14 | }) 15 | export class UserListComponent implements OnInit { 16 | users: Observable; 17 | 18 | constructor(private userSvc: UsersService) { 19 | this.users = userSvc.fetch(); 20 | } 21 | 22 | ngOnInit(): void {} 23 | } 24 | -------------------------------------------------------------------------------- /client/web/application/src/app/users/users-routing.module.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | import { NgModule } from '@angular/core'; 6 | import { Routes, RouterModule } from '@angular/router'; 7 | import { CognitoGuard } from '../cognito.guard'; 8 | import { UserCreateComponent } from './user-create/user-create.component'; 9 | import { UserDetailComponent } from './user-detail/user-detail.component'; 10 | import { UserListComponent } from './user-list/user-list.component'; 11 | 12 | const routes: Routes = [ 13 | { 14 | path: '', 15 | redirectTo: 'list', 16 | }, 17 | { 18 | path: 'list', 19 | data: { 20 | title: 'All Users', 21 | }, 22 | component: UserListComponent, 23 | canActivate: [CognitoGuard], 24 | }, 25 | { 26 | path: 'create', 27 | data: { 28 | title: 'Create User', 29 | }, 30 | component: UserCreateComponent, 31 | canActivate: [CognitoGuard], 32 | }, 33 | { 34 | path: 'detail/:userId', 35 | data: { 36 | title: 'View User Detail', 37 | }, 38 | component: UserDetailComponent, 39 | canActivate: [CognitoGuard], 40 | }, 41 | ]; 42 | 43 | @NgModule({ 44 | imports: [RouterModule.forChild(routes)], 45 | exports: [RouterModule], 46 | }) 47 | export class UsersRoutingModule {} 48 | -------------------------------------------------------------------------------- /client/web/application/src/app/users/users.module.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | import { NgModule } from '@angular/core'; 6 | import { CommonModule } from '@angular/common'; 7 | 8 | import { UsersRoutingModule } from './users-routing.module'; 9 | import { UserListComponent } from './user-list/user-list.component'; 10 | import { UserCreateComponent } from './user-create/user-create.component'; 11 | import { UserDetailComponent } from './user-detail/user-detail.component'; 12 | import { FormsModule, ReactiveFormsModule } from '@angular/forms'; 13 | import { AlertModule } from 'ngx-bootstrap/alert'; 14 | 15 | @NgModule({ 16 | declarations: [UserListComponent, UserCreateComponent, UserDetailComponent], 17 | imports: [ 18 | AlertModule.forRoot(), 19 | CommonModule, 20 | UsersRoutingModule, 21 | FormsModule, 22 | ReactiveFormsModule, 23 | ], 24 | }) 25 | export class UsersModule {} 26 | -------------------------------------------------------------------------------- /client/web/application/src/app/users/users.service.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | import { HttpClient } from '@angular/common/http'; 6 | import { Injectable } from '@angular/core'; 7 | import { Observable, of } from 'rxjs'; 8 | import { find, mergeMap } from 'rxjs/operators'; 9 | import { environment } from '../../environments/environment'; 10 | import { User } from './models/user'; 11 | 12 | @Injectable({ 13 | providedIn: 'root', 14 | }) 15 | export class UsersService { 16 | apiUrl: string; 17 | 18 | constructor(private http: HttpClient) { 19 | this.apiUrl = `${environment.apiUrl}/users`; 20 | } 21 | 22 | fetch(): Observable { 23 | return this.http.get(this.apiUrl); 24 | } 25 | 26 | get(email: string): Observable { 27 | return this.fetch().pipe( 28 | mergeMap((users) => users), 29 | find((u) => u.email === email) 30 | ); 31 | } 32 | 33 | create(user: User): Observable { 34 | return this.http.post(this.apiUrl, user); 35 | } 36 | 37 | update(email: string, user: User) {} 38 | } 39 | -------------------------------------------------------------------------------- /client/web/application/src/app/views/auth/auth-routing.module.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | import { NgModule } from '@angular/core'; 6 | import { Routes, RouterModule } from '@angular/router'; 7 | import { LoginInfoComponent } from './login-info/login-info.component'; 8 | 9 | const routes: Routes = [ 10 | { 11 | path: 'info', 12 | component: LoginInfoComponent, 13 | }, 14 | ]; 15 | 16 | @NgModule({ 17 | imports: [RouterModule.forChild(routes)], 18 | exports: [RouterModule], 19 | }) 20 | export class AuthRoutingModule {} 21 | -------------------------------------------------------------------------------- /client/web/application/src/app/views/auth/auth.module.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | import { NgModule } from '@angular/core'; 6 | import { CommonModule } from '@angular/common'; 7 | 8 | import { AuthRoutingModule } from './auth-routing.module'; 9 | import { LoginInfoComponent } from './login-info/login-info.component'; 10 | 11 | @NgModule({ 12 | declarations: [LoginInfoComponent], 13 | imports: [CommonModule, AuthRoutingModule], 14 | }) 15 | export class AuthModule {} 16 | -------------------------------------------------------------------------------- /client/web/application/src/app/views/auth/login-info/login-info.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 | 6 |
7 |
8 |
9 |
10 |
11 |
Access Token
12 |
13 |
14 |               
15 |                 {{accessToken$ | async}}
16 |               
17 |             
18 |
19 |
20 |
21 |
22 |
23 |
ID Token
24 |
25 |
26 |               
27 |                 {{idToken$ | async}}
28 |               
29 |             
30 |
31 |
32 |
33 |
34 |
35 | 36 |
37 | 38 |
39 | Is Authenticated: {{ isAuthenticated$ | async }} 40 |
41 | userData 42 |
{{ session$ | async | json }}
43 |
44 |
45 | 46 | 47 | 48 |
49 | You are NOT authenticated 50 |
51 | -------------------------------------------------------------------------------- /client/web/application/src/app/views/auth/login-info/login-info.component.scss: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this 5 | * software and associated documentation files (the "Software"), to deal in the Software 6 | * without restriction, including without limitation the rights to use, copy, modify, 7 | * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to 8 | * permit persons to whom the Software is furnished to do so. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 11 | * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 12 | * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 13 | * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 14 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 15 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 16 | */ 17 | pre, code { 18 | font-family: monospace, monospace; 19 | } 20 | pre { 21 | white-space: pre-wrap; /* css-3 */ 22 | white-space: -moz-pre-wrap; /* Mozilla, since 1999 */ 23 | white-space: -pre-wrap; /* Opera 4-6 */ 24 | white-space: -o-pre-wrap; /* Opera 7 */ 25 | word-wrap: break-word; /* Internet Explorer 5.5+ */ 26 | overflow: auto; 27 | } 28 | 29 | -------------------------------------------------------------------------------- /client/web/application/src/app/views/auth/login-info/login-info.component.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | import { Component, OnInit } from '@angular/core'; 6 | import { from, Observable, pipe } from 'rxjs'; 7 | import { Auth } from 'aws-amplify'; 8 | import { CognitoUserSession } from 'amazon-cognito-identity-js'; 9 | import { map } from 'rxjs/operators'; 10 | 11 | @Component({ 12 | selector: 'app-login-info', 13 | templateUrl: './login-info.component.html', 14 | styleUrls: ['login-info.component.scss'], 15 | }) 16 | export class LoginInfoComponent implements OnInit { 17 | session$: Observable; 18 | userData$: Observable; 19 | isAuthenticated$: Observable; 20 | checkSessionChanged$: Observable; 21 | idToken$: Observable; 22 | accessToken$: Observable; 23 | checkSessionChanged: any; 24 | 25 | constructor() {} 26 | 27 | ngOnInit(): void { 28 | this.session$ = from(Auth.currentSession()); 29 | this.accessToken$ = this.session$.pipe(map((sesh) => sesh.getAccessToken().getJwtToken())); 30 | this.idToken$ = this.session$.pipe(map((sesh) => sesh.getIdToken().getJwtToken())); 31 | this.isAuthenticated$ = this.session$.pipe(map((sesh) => sesh.isValid())); 32 | } 33 | 34 | async logout() { 35 | await Auth.signOut({ global: true }); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /client/web/application/src/app/views/auth/models/config-params.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | export interface ConfigParams { 6 | clearHashAfterLogin: boolean; 7 | clientId: string; 8 | issuer: string; 9 | nonceStateSeparator: string; 10 | redirectUri: string; 11 | responseType: string; 12 | scope: string; 13 | sessionChecksEnabled: boolean; 14 | showDebugInformation: boolean; 15 | silentRefreshRedirectUri: string; 16 | silentRefreshTimeout: number; 17 | start_checksession: boolean; 18 | strictDiscoveryDocumentValidation: boolean; 19 | timeoutFactor: number; 20 | useSilentRefresh: boolean; 21 | cognitoDomain?: string; 22 | } 23 | -------------------------------------------------------------------------------- /client/web/application/src/app/views/dashboard/dashboard-routing.module.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | import { NgModule } from '@angular/core'; 6 | import { Routes, RouterModule } from '@angular/router'; 7 | 8 | import { DashboardComponent } from './dashboard.component'; 9 | 10 | const routes: Routes = [ 11 | { 12 | path: '', 13 | component: DashboardComponent, 14 | data: { 15 | title: 'Dashboard', 16 | }, 17 | }, 18 | ]; 19 | 20 | @NgModule({ 21 | imports: [RouterModule.forChild(routes)], 22 | exports: [RouterModule], 23 | }) 24 | export class DashboardRoutingModule {} 25 | -------------------------------------------------------------------------------- /client/web/application/src/app/views/dashboard/dashboard.module.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | import { NgModule } from '@angular/core'; 6 | import { FormsModule } from '@angular/forms'; 7 | import { ChartsModule } from 'ng2-charts'; 8 | import { BsDropdownModule } from 'ngx-bootstrap/dropdown'; 9 | import { ButtonsModule } from 'ngx-bootstrap/buttons'; 10 | 11 | import { DashboardComponent } from './dashboard.component'; 12 | import { DashboardRoutingModule } from './dashboard-routing.module'; 13 | 14 | @NgModule({ 15 | imports: [ 16 | FormsModule, 17 | DashboardRoutingModule, 18 | ChartsModule, 19 | BsDropdownModule, 20 | ButtonsModule.forRoot(), 21 | ], 22 | declarations: [DashboardComponent], 23 | }) 24 | export class DashboardModule {} 25 | -------------------------------------------------------------------------------- /client/web/application/src/app/views/error/404.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 |
6 |

404

7 |

Oops! You're lost.

8 |

The page you are looking for was not found.

9 |
10 |
11 |
12 | 13 |
14 | 15 | 16 | 17 | 18 |
19 |
20 |
21 |
22 |
23 | -------------------------------------------------------------------------------- /client/web/application/src/app/views/error/404.component.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | import { Component } from '@angular/core'; 6 | 7 | @Component({ 8 | templateUrl: '404.component.html', 9 | }) 10 | export class P404Component { 11 | constructor() {} 12 | } 13 | -------------------------------------------------------------------------------- /client/web/application/src/app/views/error/500.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 |
6 |

500

7 |

Houston, we have a problem!

8 |

The page you are looking for is temporarily unavailable.

9 |
10 |
11 |
12 | 13 |
14 | 15 | 16 | 17 | 18 |
19 |
20 |
21 |
22 |
23 | -------------------------------------------------------------------------------- /client/web/application/src/app/views/error/500.component.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | import { Component } from '@angular/core'; 6 | 7 | @Component({ 8 | templateUrl: '500.component.html', 9 | }) 10 | export class P500Component { 11 | constructor() {} 12 | } 13 | -------------------------------------------------------------------------------- /client/web/application/src/assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-saas-factory-eks-saas-api-gateway-tiering-and-throttling/5374aedde1470fc23bdbdc5fe58da16f873642b1/client/web/application/src/assets/.gitkeep -------------------------------------------------------------------------------- /client/web/application/src/assets/img/brand/saascommerce.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-saas-factory-eks-saas-api-gateway-tiering-and-throttling/5374aedde1470fc23bdbdc5fe58da16f873642b1/client/web/application/src/assets/img/brand/saascommerce.png -------------------------------------------------------------------------------- /client/web/application/src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true, 3 | apiUrl: 'http://a3f9ada670df0482a906443c476976d2-e7f760d8ef4e6d87.elb.us-west-2.amazonaws.com', 4 | }; 5 | -------------------------------------------------------------------------------- /client/web/application/src/environments/environment.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true, 3 | apiUrl: 'http://a3f9ada670df0482a906443c476976d2-e7f760d8ef4e6d87.elb.us-west-2.amazonaws.com', 4 | }; 5 | -------------------------------------------------------------------------------- /client/web/application/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | AWS - EKS Workshop 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /client/web/application/src/main.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | import { enableProdMode } from '@angular/core'; 6 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 7 | 8 | import { AppModule } from './app/app.module'; 9 | import { environment } from './environments/environment'; 10 | // import Amplify from 'aws-amplify'; 11 | // import aws_exports from './aws-exports'; 12 | // Amplify.configure(aws_exports); 13 | 14 | if (environment.production) { 15 | enableProdMode(); 16 | } 17 | 18 | platformBrowserDynamic() 19 | .bootstrapModule(AppModule, { 20 | useJit: true, 21 | preserveWhitespaces: true, 22 | }) 23 | .catch((err) => console.log(err)); 24 | -------------------------------------------------------------------------------- /client/web/application/src/scss/_custom.scss: -------------------------------------------------------------------------------- 1 | // Here you can add other styles 2 | -------------------------------------------------------------------------------- /client/web/application/src/scss/_variables.scss: -------------------------------------------------------------------------------- 1 | // Variable overrides 2 | -------------------------------------------------------------------------------- /client/web/application/src/scss/style.scss: -------------------------------------------------------------------------------- 1 | // If you want to override variables do it here 2 | @import "variables"; 3 | 4 | // Import styles 5 | @import "~@coreui/coreui/scss/coreui"; 6 | 7 | // If you want to add something do it here 8 | @import "custom"; 9 | -------------------------------------------------------------------------------- /client/web/application/src/scss/vendors/_variables.scss: -------------------------------------------------------------------------------- 1 | // Override Boostrap variables 2 | @import "../variables"; 3 | @import "~bootstrap/scss/mixins"; 4 | @import "~@coreui/coreui/scss/variables"; 5 | -------------------------------------------------------------------------------- /client/web/application/src/scss/vendors/chart.js/chart.scss: -------------------------------------------------------------------------------- 1 | // Import variables 2 | @import '../variables'; 3 | 4 | .chart-legend, 5 | .bar-legend, 6 | .line-legend, 7 | .pie-legend, 8 | .radar-legend, 9 | .polararea-legend, 10 | .doughnut-legend { 11 | list-style-type: none; 12 | margin-top: 5px; 13 | text-align: center; 14 | -webkit-padding-start: 0; 15 | -moz-padding-start: 0; 16 | padding-left: 0; 17 | } 18 | .chart-legend li, 19 | .bar-legend li, 20 | .line-legend li, 21 | .pie-legend li, 22 | .radar-legend li, 23 | .polararea-legend li, 24 | .doughnut-legend li { 25 | display: inline-block; 26 | white-space: nowrap; 27 | position: relative; 28 | margin-bottom: 4px; 29 | @include border-radius($border-radius); 30 | padding: 2px 8px 2px 28px; 31 | font-size: smaller; 32 | cursor: default; 33 | } 34 | .chart-legend li span, 35 | .bar-legend li span, 36 | .line-legend li span, 37 | .pie-legend li span, 38 | .radar-legend li span, 39 | .polararea-legend li span, 40 | .doughnut-legend li span { 41 | display: block; 42 | position: absolute; 43 | left: 0; 44 | top: 0; 45 | width: 20px; 46 | height: 20px; 47 | @include border-radius($border-radius); 48 | } 49 | -------------------------------------------------------------------------------- /client/web/application/src/test.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | import 'zone.js/testing'; 6 | import { getTestBed } from '@angular/core/testing'; 7 | import { 8 | BrowserDynamicTestingModule, 9 | platformBrowserDynamicTesting, 10 | } from '@angular/platform-browser-dynamic/testing'; 11 | 12 | declare const require: any; 13 | 14 | // First, initialize the Angular testing environment. 15 | getTestBed().initTestEnvironment(BrowserDynamicTestingModule, platformBrowserDynamicTesting()); 16 | // Then we find all the tests. 17 | const context = require.context('./', true, /\.spec\.ts$/); 18 | // And load the modules. 19 | context.keys().map(context); 20 | -------------------------------------------------------------------------------- /client/web/application/src/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/app", 5 | "baseUrl": "./", 6 | "module": "es2020", 7 | "target": "es2015", 8 | "types": [], 9 | "paths": { 10 | "@angular/*": [ 11 | "../node_modules/@angular/*" 12 | ] 13 | } 14 | }, 15 | "angularCompilerOptions": { 16 | "enableIvy": true, 17 | "importHelpers": true 18 | }, 19 | "files": [ 20 | "main.ts", 21 | "polyfills.ts" 22 | ], 23 | "include": [ 24 | "**/*.d.ts" 25 | ], 26 | "exclude": [ 27 | "src/**/*.spec.ts", 28 | "src/test.ts", 29 | "src/environments/environment.prod.ts" 30 | ] 31 | } 32 | -------------------------------------------------------------------------------- /client/web/application/src/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */ 2 | { 3 | "extends": "../tsconfig.json", 4 | "compilerOptions": { 5 | "outDir": "../out-tsc/spec", 6 | "baseUrl": "./", 7 | "module": "commonjs", 8 | "types": [ 9 | "jasmine", 10 | "node" 11 | ] 12 | }, 13 | "files": [ 14 | "test.ts", 15 | "polyfills.ts" 16 | ], 17 | "include": [ 18 | "**/*.spec.ts", 19 | "**/*.d.ts" 20 | ] 21 | } 22 | -------------------------------------------------------------------------------- /client/web/application/src/typings.d.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | /* SystemJS module definition */ 6 | declare var module: NodeModule; 7 | interface NodeModule { 8 | id: string; 9 | } 10 | -------------------------------------------------------------------------------- /client/web/application/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "./out-tsc/app", 5 | "types": [] 6 | }, 7 | "files": [ 8 | "src/main.ts", 9 | "src/polyfills.ts" 10 | ], 11 | "include": [ 12 | "src/**/*.d.ts" 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /client/web/application/tsconfig.json: -------------------------------------------------------------------------------- 1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */ 2 | { 3 | "compileOnSave": false, 4 | "compilerOptions": { 5 | "importHelpers": true, 6 | "outDir": "./dist/out-tsc", 7 | "sourceMap": true, 8 | "declaration": false, 9 | "moduleResolution": "node", 10 | "experimentalDecorators": true, 11 | "module": "es2020", 12 | "target": "es2015", 13 | "typeRoots": [ 14 | "node_modules/@types" 15 | ], 16 | "lib": [ 17 | "esnext", 18 | "dom" 19 | ] 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /client/web/application/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "./out-tsc/spec", 5 | "types": [ 6 | "jasmine", 7 | "node" 8 | ] 9 | }, 10 | "files": [ 11 | "src/test.ts", 12 | "src/polyfills.ts" 13 | ], 14 | "include": [ 15 | "src/**/*.spec.ts", 16 | "src/**/*.d.ts" 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /scripts/deploy-app-services.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | # SPDX-License-Identifier: MIT-0 4 | 5 | source ./scripts/deploy-application.sh 6 | TENANTPATH=app envsubst < ./client/web/application/k8s/template.txt > ./client/web/application/k8s/template.yaml 7 | kubectl apply -f ./client/web/application/k8s/template.yaml 8 | 9 | source ./scripts/deploy-product.sh 10 | TENANTPATH=app envsubst < ./services/application/apps/product/k8s/template.txt > ./services/application/apps/product/k8s/template.yaml 11 | kubectl apply -f ./services/application/apps/product/k8s/template.yaml 12 | 13 | source ./scripts/deploy-order.sh 14 | TENANTPATH=app envsubst < ./services/application/apps/order/k8s/template.txt > ./services/application/apps/order/k8s/template.yaml 15 | kubectl apply -f ./services/application/apps/order/k8s/template.yaml 16 | 17 | kubectl rollout restart deploy application 18 | kubectl rollout restart deploy product 19 | kubectl rollout restart deploy order 20 | -------------------------------------------------------------------------------- /scripts/deploy-application.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | # SPDX-License-Identifier: MIT-0 4 | 5 | export APPLICATIONECR=$(aws cloudformation describe-stacks --stack-name RootStack --query "Stacks[0].Outputs[?OutputKey=='ApplicationECR'].OutputValue" --output text) 6 | export REGION=$(aws cloudformation describe-stacks --stack-name RootStack --query "Stacks[0].Outputs[?OutputKey=='AWSRegion'].OutputValue" --output text) 7 | 8 | cat << EoF > ./client/web/application/src/environments/environment.prod.ts 9 | export const environment = { 10 | production: true, 11 | restApiUrl: '$REST_API_URL', 12 | apiUrl: 'http://$ELBURL', 13 | }; 14 | 15 | EoF 16 | cat << EoF > ./client/web/application/src/environments/environment.ts 17 | export const environment = { 18 | production: true, 19 | restApiUrl: '$REST_API_URL', 20 | apiUrl: 'http://$ELBURL', 21 | }; 22 | EoF 23 | CWD=$(pwd) 24 | cd ./client/web/application 25 | REGISTRY=$(echo $APPLICATIONECR| cut -d'/' -f 1) 26 | APPLICATIONIMAGENAME=$(echo $APPLICATIONECR| cut -d'/' -f 2) 27 | 28 | aws ecr get-login-password --region $REGION | docker login --username AWS --password-stdin $REGISTRY 29 | docker build -t app-image:latest . 30 | docker tag app-image:latest $APPLICATIONECR:latest 31 | docker push $APPLICATIONECR:latest 32 | 33 | cd $CWD 34 | echo '************************' 35 | echo '************************' 36 | echo '' 37 | echo 'APPLICATION_ECR_REPO:' $APPLICATIONECR 38 | echo 'ELB_URL:' $ELBURL 39 | echo 'TENANT_PATH: app' 40 | echo '' 41 | -------------------------------------------------------------------------------- /scripts/deploy-core-services.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | # SPDX-License-Identifier: MIT-0 4 | 5 | source ./scripts/deploy-admin.sh 6 | envsubst < ./client/web/admin/k8s/template.txt > ./client/web/admin/k8s/template.yaml 7 | kubectl apply -f ./client/web/admin/k8s/template.yaml 8 | 9 | source ./scripts/deploy-tenant-registration.sh 10 | envsubst < ./services/shared/apps/tenant-registration/k8s/template.txt > ./services/shared/apps/tenant-registration/k8s/template.yaml 11 | kubectl apply -f ./services/shared/apps/tenant-registration/k8s/template.yaml 12 | 13 | source ./scripts/deploy-tenant-management.sh 14 | envsubst < ./services/shared/apps/tenant-management/k8s/template.txt > ./services/shared/apps/tenant-management/k8s/template.yaml 15 | kubectl apply -f ./services/shared/apps/tenant-management/k8s/template.yaml 16 | 17 | source ./scripts/deploy-user-management.sh 18 | envsubst < ./services/shared/apps/user-management/k8s/template.txt > ./services/shared/apps/user-management/k8s/template.yaml 19 | kubectl apply -f ./services/shared/apps/user-management/k8s/template.yaml 20 | 21 | kubectl rollout restart deploy admin-application 22 | kubectl rollout restart deploy tenant-registration 23 | kubectl rollout restart deploy tenant-management 24 | kubectl rollout restart deploy user-management 25 | -------------------------------------------------------------------------------- /scripts/deploy-remaining-shared-services.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | # SPDX-License-Identifier: MIT-0 4 | 5 | source ./scripts/deploy-tenant-management.sh 6 | envsubst < ./services/shared/apps/tenant-management/k8s/template.txt > ./services/shared/apps/tenant-management/k8s/template.yaml 7 | kubectl apply -f ./services/shared/apps/tenant-management/k8s/template.yaml 8 | 9 | source ./scripts/deploy-user-management.sh 10 | envsubst < ./services/shared/apps/user-management/k8s/template.txt > ./services/shared/apps/user-management/k8s/template.yaml 11 | kubectl apply -f ./services/shared/apps/user-management/k8s/template.yaml 12 | 13 | kubectl rollout restart deploy tenant-registration -------------------------------------------------------------------------------- /scripts/deploy-user-management.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | # SPDX-License-Identifier: MIT-0 4 | 5 | export USERMANAGEMENTECR=$(aws cloudformation describe-stacks --stack-name RootStack --query "Stacks[0].Outputs[?OutputKey=='UserManagementECR'].OutputValue" --output text) 6 | export REGION=$(aws cloudformation describe-stacks --stack-name RootStack --query "Stacks[0].Outputs[?OutputKey=='AWSRegion'].OutputValue" --output text) 7 | export USERPOOLID=$(aws cloudformation describe-stacks --stack-name RootStack --query "Stacks[0].Outputs[?OutputKey=='AdminUserPoolId'].OutputValue" --output text) 8 | export APPCLIENTID=$(aws cloudformation describe-stacks --stack-name RootStack --query "Stacks[0].Outputs[?OutputKey=='AdminAppClientId'].OutputValue" --output text) 9 | CWD=$(pwd) 10 | cd ./services/shared 11 | REGISTRY=$(echo $USERMANAGEMENTECR| cut -d'/' -f 1) 12 | 13 | aws ecr get-login-password --region $REGION | docker login --username AWS --password-stdin $REGISTRY 14 | docker build -t user-mgmt-svc:latest -f Dockerfile.user-management . 15 | docker tag user-mgmt-svc:latest $USERMANAGEMENTECR:latest 16 | docker push $USERMANAGEMENTECR:latest 17 | 18 | echo "The following values will need to be plugged into the User Management Kubernetes manifest before deployment." 19 | echo "**PLEASE DO NOT CLOSE THIS WINDOW**" 20 | echo "" 21 | echo 'USER_MANAGEMENT_ECR_REPO:' $USERMANAGEMENTECR 22 | cd $CWD 23 | 24 | envsubst < ./services/shared/apps/user-management/k8s/partial-template.txt > ./services/shared/apps/user-management/k8s/template.yaml 25 | -------------------------------------------------------------------------------- /scripts/nginx-ingress-config.yaml: -------------------------------------------------------------------------------- 1 | controller: 2 | publishService: 3 | enabled: true 4 | service: 5 | annotations: 6 | service.beta.kubernetes.io/aws-load-balancer-type: nlb 7 | service.beta.kubernetes.io/aws-load-balancer-backend-protocol: http 8 | service.beta.kubernetes.io/aws-load-balancer-ssl-ports: "443" 9 | service.beta.kubernetes.io/aws-load-balancer-connection-idle-timeout: "3600" 10 | targetPorts: 11 | https: http -------------------------------------------------------------------------------- /scripts/policy/deny-traffic-policy.yaml: -------------------------------------------------------------------------------- 1 | kind: NetworkPolicy 2 | apiVersion: networking.k8s.io/v1 3 | metadata: 4 | name: deny-from-other-namespaces 5 | spec: 6 | podSelector: 7 | matchLabels: 8 | ingress: 9 | - from: 10 | - podSelector: {} -------------------------------------------------------------------------------- /scripts/templates/ingress-master-resource.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: networking.k8s.io/v1 2 | kind: Ingress 3 | metadata: 4 | name: workshop-ingress-master 5 | annotations: 6 | kubernetes.io/ingress.class: "nginx" 7 | nginx.org/mergeable-ingress-type: "master" 8 | spec: 9 | rules: 10 | - host: ELB_URL -------------------------------------------------------------------------------- /scripts/templates/nginx-ingress-config.yaml: -------------------------------------------------------------------------------- 1 | 2 | controller: 3 | publishService: 4 | enabled: true 5 | service: 6 | annotations: 7 | service.beta.kubernetes.io/aws-load-balancer-type: nlb 8 | service.beta.kubernetes.io/aws-load-balancer-backend-protocol: http 9 | service.beta.kubernetes.io/aws-load-balancer-ssl-ports: "443" 10 | service.beta.kubernetes.io/aws-load-balancer-connection-idle-timeout: "3600" 11 | targetPorts: 12 | https: http -------------------------------------------------------------------------------- /services/application/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | parser: '@typescript-eslint/parser', 3 | parserOptions: { 4 | project: 'tsconfig.json', 5 | sourceType: 'module', 6 | tsconfigRootDir: __dirname, 7 | }, 8 | plugins: ['@typescript-eslint/eslint-plugin'], 9 | extends: [ 10 | 'plugin:@typescript-eslint/recommended', 11 | 'plugin:prettier/recommended', 12 | ], 13 | root: true, 14 | env: { 15 | node: true, 16 | jest: true, 17 | }, 18 | ignorePatterns: ['.eslintrc.js'], 19 | rules: { 20 | '@typescript-eslint/interface-name-prefix': 'off', 21 | '@typescript-eslint/explicit-function-return-type': 'off', 22 | '@typescript-eslint/explicit-module-boundary-types': 'off', 23 | '@typescript-eslint/no-explicit-any': 'off', 24 | }, 25 | }; 26 | -------------------------------------------------------------------------------- /services/application/.gitignore: -------------------------------------------------------------------------------- 1 | # compiled output 2 | /dist 3 | /node_modules 4 | 5 | # Logs 6 | logs 7 | *.log 8 | npm-debug.log* 9 | yarn-debug.log* 10 | yarn-error.log* 11 | lerna-debug.log* 12 | 13 | # OS 14 | .DS_Store 15 | 16 | # Tests 17 | /coverage 18 | /.nyc_output 19 | 20 | # IDEs and editors 21 | /.idea 22 | .project 23 | .classpath 24 | .c9/ 25 | *.launch 26 | .settings/ 27 | *.sublime-workspace 28 | 29 | # IDE - VSCode 30 | .vscode/* 31 | !.vscode/settings.json 32 | !.vscode/tasks.json 33 | !.vscode/launch.json 34 | !.vscode/extensions.json -------------------------------------------------------------------------------- /services/application/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true, 3 | "trailingComma": "all" 4 | } -------------------------------------------------------------------------------- /services/application/Dockerfile.order: -------------------------------------------------------------------------------- 1 | FROM public.ecr.aws/bitnami/node:16.5.0 AS build 2 | WORKDIR /app 3 | COPY package.json yarn.lock ./ 4 | RUN yarn 5 | COPY . . 6 | RUN yarn build 7 | 8 | FROM public.ecr.aws/bitnami/node:16.5.0 9 | WORKDIR /app 10 | COPY --from=build /app ./ 11 | EXPOSE 3003 12 | CMD ["npm", "run", "start:order"] 13 | -------------------------------------------------------------------------------- /services/application/Dockerfile.product: -------------------------------------------------------------------------------- 1 | FROM public.ecr.aws/bitnami/node:16.5.0 AS build 2 | WORKDIR /app 3 | COPY package.json yarn.lock ./ 4 | RUN yarn 5 | COPY . . 6 | RUN yarn build product 7 | 8 | FROM public.ecr.aws/bitnami/node:16.5.0 9 | WORKDIR /app 10 | COPY --from=build /app ./ 11 | EXPOSE 3005 12 | CMD ["npm", "run", "start:product"] 13 | -------------------------------------------------------------------------------- /services/application/apps/order/src/main.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | 6 | import { NestFactory } from '@nestjs/core'; 7 | import { OrdersModule } from './orders/orders.module'; 8 | 9 | async function bootstrap() { 10 | const app = await NestFactory.create(OrdersModule); 11 | app.setGlobalPrefix('/*/api'); 12 | app.enableCors({ 13 | allowedHeaders: '*', 14 | origin: '*', 15 | methods: '*', 16 | }); 17 | await app.listen(3010); 18 | } 19 | bootstrap(); 20 | -------------------------------------------------------------------------------- /services/application/apps/order/src/orders/dto/create-order.dto.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | import { OrderProductDto } from './order-product.dto'; 6 | 7 | export class CreateOrderDto { 8 | name: string; 9 | products: OrderProductDto[]; 10 | } 11 | -------------------------------------------------------------------------------- /services/application/apps/order/src/orders/dto/order-product.dto.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | export class OrderProductDto { 6 | productId: string; 7 | price: number; 8 | quantity: number; 9 | } 10 | -------------------------------------------------------------------------------- /services/application/apps/order/src/orders/dto/update-order.dto.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | import { PartialType } from '@nestjs/mapped-types'; 6 | import { CreateOrderDto } from './create-order.dto'; 7 | 8 | export class UpdateOrderDto extends PartialType(CreateOrderDto) {} 9 | -------------------------------------------------------------------------------- /services/application/apps/order/src/orders/entities/order.entity.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | export class Order {} 6 | -------------------------------------------------------------------------------- /services/application/apps/order/src/orders/orders.controller.spec.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | import { Test, TestingModule } from '@nestjs/testing'; 6 | import { OrdersController } from './orders.controller'; 7 | import { OrdersService } from './orders.service'; 8 | 9 | describe('OrdersController', () => { 10 | let controller: OrdersController; 11 | 12 | beforeEach(async () => { 13 | const module: TestingModule = await Test.createTestingModule({ 14 | controllers: [OrdersController], 15 | providers: [OrdersService], 16 | }).compile(); 17 | 18 | controller = module.get(OrdersController); 19 | }); 20 | 21 | it('should be defined', () => { 22 | expect(controller).toBeDefined(); 23 | }); 24 | }); 25 | -------------------------------------------------------------------------------- /services/application/apps/order/src/orders/orders.controller.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | import { Controller, Get, Post, Body, Param, UseGuards } from '@nestjs/common'; 6 | import { OrdersService } from './orders.service'; 7 | import { CreateOrderDto } from './dto/create-order.dto'; 8 | import { TenantCredentials } from '@app/auth/auth.decorator'; 9 | import { JwtAuthGuard } from '@app/auth/jwt-auth.guard'; 10 | 11 | @Controller('orders') 12 | export class OrdersController { 13 | constructor(private readonly ordersService: OrdersService) {} 14 | 15 | @Post() 16 | @UseGuards(JwtAuthGuard) 17 | create(@Body() createOrderDto: CreateOrderDto, @TenantCredentials() tenant) { 18 | return this.ordersService.create(createOrderDto, tenant.tenantId); 19 | } 20 | 21 | @Get() 22 | @UseGuards(JwtAuthGuard) 23 | findAll(@TenantCredentials() tenant) { 24 | return this.ordersService.findAll(tenant?.tenantId); 25 | } 26 | 27 | @Get(':id') 28 | @UseGuards(JwtAuthGuard) 29 | findOne(@Param('id') id: string, @TenantCredentials() tenant) { 30 | return this.ordersService.findOne(id, tenant?.tenantId); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /services/application/apps/order/src/orders/orders.module.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | import { Module } from '@nestjs/common'; 6 | import { OrdersService } from './orders.service'; 7 | import { OrdersController } from './orders.controller'; 8 | import { AuthModule } from '@app/auth'; 9 | import { ConfigModule } from '@nestjs/config'; 10 | import { ClientFactoryModule } from '@app/client-factory'; 11 | 12 | @Module({ 13 | imports: [ 14 | AuthModule, 15 | ConfigModule.forRoot({ isGlobal: true }), 16 | ClientFactoryModule, 17 | ], 18 | controllers: [OrdersController], 19 | providers: [OrdersService], 20 | }) 21 | export class OrdersModule {} 22 | -------------------------------------------------------------------------------- /services/application/apps/order/src/orders/orders.service.spec.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | import { Test, TestingModule } from '@nestjs/testing'; 6 | import { OrdersService } from './orders.service'; 7 | 8 | describe('OrdersService', () => { 9 | let service: OrdersService; 10 | 11 | beforeEach(async () => { 12 | const module: TestingModule = await Test.createTestingModule({ 13 | providers: [OrdersService], 14 | }).compile(); 15 | 16 | service = module.get(OrdersService); 17 | }); 18 | 19 | it('should be defined', () => { 20 | expect(service).toBeDefined(); 21 | }); 22 | }); 23 | -------------------------------------------------------------------------------- /services/application/apps/order/test/jest-e2e.json: -------------------------------------------------------------------------------- 1 | { 2 | "moduleFileExtensions": ["js", "json", "ts"], 3 | "rootDir": ".", 4 | "testEnvironment": "node", 5 | "testRegex": ".e2e-spec.ts$", 6 | "transform": { 7 | "^.+\\.(t|j)s$": "ts-jest" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /services/application/apps/order/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "declaration": false, 5 | "outDir": "../../dist/apps/order" 6 | }, 7 | "include": ["src/**/*"], 8 | "exclude": ["node_modules", "dist", "test", "**/*spec.ts"] 9 | } 10 | -------------------------------------------------------------------------------- /services/application/apps/product/src/main.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | import { NestFactory } from '@nestjs/core'; 6 | import { ProductsModule } from './products/products.module'; 7 | 8 | async function bootstrap() { 9 | const app = await NestFactory.create(ProductsModule); 10 | app.setGlobalPrefix('/*/api'); 11 | app.enableCors({ 12 | allowedHeaders: '*', 13 | origin: '*', 14 | methods: '*', 15 | }); 16 | await app.listen(3005); 17 | } 18 | bootstrap(); 19 | -------------------------------------------------------------------------------- /services/application/apps/product/src/products/dto/create-product.dto.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | export class CreateProductDto { 6 | name: string; 7 | price: number; 8 | description: string; 9 | } 10 | -------------------------------------------------------------------------------- /services/application/apps/product/src/products/dto/update-product.dto.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | import { PartialType } from '@nestjs/mapped-types'; 6 | import { CreateProductDto } from './create-product.dto'; 7 | 8 | export class UpdateProductDto extends PartialType(CreateProductDto) {} 9 | -------------------------------------------------------------------------------- /services/application/apps/product/src/products/entities/product.entity.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | export class Product { 6 | constructor( 7 | private id: string, 8 | private price: number, 9 | private name: string, 10 | private description: string, 11 | ) {} 12 | } 13 | -------------------------------------------------------------------------------- /services/application/apps/product/src/products/products.controller.spec.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | import { ClientFactoryService } from '@app/client-factory'; 6 | import { Test, TestingModule } from '@nestjs/testing'; 7 | import { ProductsController } from './products.controller'; 8 | import { ProductsService } from './products.service'; 9 | 10 | describe('ProductsController', () => { 11 | let controller: ProductsController; 12 | 13 | beforeEach(async () => { 14 | const module: TestingModule = await Test.createTestingModule({ 15 | controllers: [ProductsController], 16 | providers: [ProductsService, ClientFactoryService], 17 | }).compile(); 18 | 19 | controller = module.get(ProductsController); 20 | }); 21 | 22 | it('should be defined', () => { 23 | expect(controller).toBeDefined(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /services/application/apps/product/src/products/products.module.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | import { Module } from '@nestjs/common'; 6 | import { ProductsService } from './products.service'; 7 | import { ProductsController } from './products.controller'; 8 | import { AuthModule } from '@app/auth'; 9 | import { ConfigModule } from '@nestjs/config'; 10 | import { ClientFactoryModule } from '@app/client-factory'; 11 | 12 | @Module({ 13 | imports: [ 14 | AuthModule, 15 | ConfigModule.forRoot({ isGlobal: true }), 16 | ClientFactoryModule, 17 | ], 18 | controllers: [ProductsController], 19 | providers: [ProductsService], 20 | }) 21 | export class ProductsModule {} 22 | -------------------------------------------------------------------------------- /services/application/apps/product/src/products/products.service.spec.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | import { ClientFactoryService } from '@app/client-factory'; 6 | import { Test, TestingModule } from '@nestjs/testing'; 7 | import { ProductsService } from './products.service'; 8 | 9 | describe('ProductsService', () => { 10 | let service: ProductsService; 11 | 12 | beforeEach(async () => { 13 | const module: TestingModule = await Test.createTestingModule({ 14 | providers: [ProductsService, ClientFactoryService], 15 | }).compile(); 16 | 17 | service = module.get(ProductsService); 18 | }); 19 | 20 | it('should be defined', () => { 21 | expect(service).toBeDefined(); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /services/application/apps/product/test/jest-e2e.json: -------------------------------------------------------------------------------- 1 | { 2 | "moduleFileExtensions": ["js", "json", "ts"], 3 | "rootDir": ".", 4 | "testEnvironment": "node", 5 | "testRegex": ".e2e-spec.ts$", 6 | "transform": { 7 | "^.+\\.(t|j)s$": "ts-jest" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /services/application/apps/product/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "declaration": false, 5 | "outDir": "../../dist/apps/product" 6 | }, 7 | "include": ["src/**/*"], 8 | "exclude": ["node_modules", "dist", "test", "**/*spec.ts"] 9 | } 10 | -------------------------------------------------------------------------------- /services/application/apps/user/src/main.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | import { NestFactory } from '@nestjs/core'; 6 | import { UsersModule } from './users/users.module'; 7 | 8 | async function bootstrap() { 9 | const app = await NestFactory.create(UsersModule); 10 | app.setGlobalPrefix('/*/api'); 11 | await app.listen(3003); 12 | } 13 | bootstrap(); 14 | -------------------------------------------------------------------------------- /services/application/apps/user/src/users/dto/create-user.dto.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | export class CreateUserDto { 6 | email: string; 7 | } 8 | -------------------------------------------------------------------------------- /services/application/apps/user/src/users/dto/update-user.dto.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | import { PartialType } from '@nestjs/mapped-types'; 6 | import { CreateUserDto } from './create-user.dto'; 7 | 8 | export class UpdateUserDto extends PartialType(CreateUserDto) {} 9 | -------------------------------------------------------------------------------- /services/application/apps/user/src/users/entities/user.entity.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | export class User {} 6 | -------------------------------------------------------------------------------- /services/application/apps/user/src/users/users.controller.spec.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | import { Test, TestingModule } from '@nestjs/testing'; 6 | import { UsersController } from './users.controller'; 7 | import { UsersService } from './users.service'; 8 | 9 | describe('UsersController', () => { 10 | let controller: UsersController; 11 | 12 | beforeEach(async () => { 13 | const module: TestingModule = await Test.createTestingModule({ 14 | controllers: [UsersController], 15 | providers: [UsersService], 16 | }).compile(); 17 | 18 | controller = module.get(UsersController); 19 | }); 20 | 21 | it('should be defined', () => { 22 | expect(controller).toBeDefined(); 23 | }); 24 | }); 25 | -------------------------------------------------------------------------------- /services/application/apps/user/src/users/users.controller.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | import { 6 | Controller, 7 | Get, 8 | Post, 9 | Body, 10 | Patch, 11 | Param, 12 | Delete, 13 | UseGuards, 14 | } from '@nestjs/common'; 15 | import { UsersService } from './users.service'; 16 | import { CreateUserDto } from './dto/create-user.dto'; 17 | import { UpdateUserDto } from './dto/update-user.dto'; 18 | import { JwtAuthGuard } from '@app/auth/jwt-auth.guard'; 19 | import { TenantCredentials } from '@app/auth/auth.decorator'; 20 | 21 | @Controller('users') 22 | export class UsersController { 23 | constructor(private readonly usersService: UsersService) {} 24 | 25 | @Post() 26 | @UseGuards(JwtAuthGuard) 27 | create(@Body() createUserDto: CreateUserDto, @TenantCredentials() tenant) { 28 | return this.usersService.create( 29 | tenant.tenantId, 30 | tenant.userPoolId, 31 | createUserDto, 32 | ); 33 | } 34 | 35 | @Get() 36 | @UseGuards(JwtAuthGuard) 37 | findAll(@TenantCredentials() tenant) { 38 | return this.usersService.findAll(tenant.userPoolId, tenant.tenantId); 39 | } 40 | 41 | @Get(':id') 42 | findOne(@Param('id') id: string) { 43 | return this.usersService.findOne(+id); 44 | } 45 | 46 | @Patch(':id') 47 | update(@Param('id') id: string, @Body() updateUserDto: UpdateUserDto) { 48 | return this.usersService.update(+id, updateUserDto); 49 | } 50 | 51 | @Delete(':id') 52 | remove(@Param('id') id: string) { 53 | return this.usersService.remove(+id); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /services/application/apps/user/src/users/users.module.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | import { Module } from '@nestjs/common'; 6 | import { UsersService } from './users.service'; 7 | import { UsersController } from './users.controller'; 8 | import { AuthModule } from '@app/auth'; 9 | import { ConfigModule } from '@nestjs/config'; 10 | 11 | @Module({ 12 | imports: [AuthModule, ConfigModule.forRoot({ isGlobal: true })], 13 | controllers: [UsersController], 14 | providers: [UsersService], 15 | }) 16 | export class UsersModule {} 17 | -------------------------------------------------------------------------------- /services/application/apps/user/src/users/users.service.spec.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | import { Test, TestingModule } from '@nestjs/testing'; 6 | import { UsersService } from './users.service'; 7 | 8 | describe('UsersService', () => { 9 | let service: UsersService; 10 | 11 | beforeEach(async () => { 12 | const module: TestingModule = await Test.createTestingModule({ 13 | providers: [UsersService], 14 | }).compile(); 15 | 16 | service = module.get(UsersService); 17 | }); 18 | 19 | it('should be defined', () => { 20 | expect(service).toBeDefined(); 21 | }); 22 | }); 23 | -------------------------------------------------------------------------------- /services/application/apps/user/test/jest-e2e.json: -------------------------------------------------------------------------------- 1 | { 2 | "moduleFileExtensions": ["js", "json", "ts"], 3 | "rootDir": ".", 4 | "testEnvironment": "node", 5 | "testRegex": ".e2e-spec.ts$", 6 | "transform": { 7 | "^.+\\.(t|j)s$": "ts-jest" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /services/application/apps/user/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "declaration": false, 5 | "outDir": "../../dist/apps/user" 6 | }, 7 | "include": ["src/**/*"], 8 | "exclude": ["node_modules", "dist", "test", "**/*spec.ts"] 9 | } 10 | -------------------------------------------------------------------------------- /services/application/libs/auth/src/auth-config.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | import { Injectable } from '@nestjs/common'; 6 | 7 | @Injectable() 8 | export class AuthConfig { 9 | public userPoolId: string = process.env.COGNITO_USER_POOL_ID; 10 | public clientId: string = process.env.COGNITO_CLIENT_ID; 11 | public region: string = process.env.COGNITO_REGION; 12 | public authority = `https://cognito-idp.${process.env.COGNITO_REGION}.amazonaws.com/${process.env.COGNITO_USER_POOL_ID}`; 13 | } 14 | -------------------------------------------------------------------------------- /services/application/libs/auth/src/auth.decorator.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | import { createParamDecorator, ExecutionContext } from '@nestjs/common'; 6 | 7 | export const TenantCredentials = createParamDecorator( 8 | (data: unknown, ctx: ExecutionContext) => { 9 | const request = ctx.switchToHttp().getRequest(); 10 | return request.user; 11 | }, 12 | ); 13 | -------------------------------------------------------------------------------- /services/application/libs/auth/src/auth.module.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | import { ConfigModule } from '@nestjs/config'; 6 | import { PassportModule } from '@nestjs/passport'; 7 | import { Module } from '@nestjs/common'; 8 | 9 | import { AuthConfig } from './auth-config'; 10 | import { JwtStrategy } from './jwt.strategy'; 11 | 12 | @Module({ 13 | imports: [ 14 | ConfigModule.forRoot({ isGlobal: true }), 15 | PassportModule.register({ defaultStrategy: 'jwt' }), 16 | ], 17 | providers: [JwtStrategy, AuthConfig], 18 | exports: [JwtStrategy], 19 | }) 20 | export class AuthModule {} 21 | -------------------------------------------------------------------------------- /services/application/libs/auth/src/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | export * from './auth.module'; 6 | -------------------------------------------------------------------------------- /services/application/libs/auth/src/jwt-auth.guard.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | import { Injectable } from '@nestjs/common'; 6 | import { AuthGuard } from '@nestjs/passport'; 7 | 8 | @Injectable() 9 | export class JwtAuthGuard extends AuthGuard('jwt') {} 10 | -------------------------------------------------------------------------------- /services/application/libs/auth/src/jwt.strategy.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | import { ExtractJwt, Strategy } from 'passport-jwt'; 6 | import { PassportStrategy } from '@nestjs/passport'; 7 | import { Injectable } from '@nestjs/common'; 8 | import { passportJwtSecret } from 'jwks-rsa'; 9 | import { AuthConfig } from './auth-config'; 10 | 11 | @Injectable() 12 | export class JwtStrategy extends PassportStrategy(Strategy) { 13 | constructor(private authConfig: AuthConfig) { 14 | super({ 15 | secretOrKeyProvider: passportJwtSecret({ 16 | cache: true, 17 | rateLimit: true, 18 | jwksRequestsPerMinute: 5, 19 | jwksUri: `${authConfig.authority}/.well-known/jwks.json`, 20 | }), 21 | 22 | jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(), 23 | audience: authConfig.clientId, 24 | issuer: authConfig.authority, 25 | algorithms: ['RS256'], 26 | }); 27 | } 28 | 29 | async validate(payload: any) { 30 | const match = payload.iss.match(/([a-z\d\_\-]+)(\/*|)$/gi); 31 | return { 32 | userId: payload.sub, 33 | username: payload['cognito:username'], 34 | tenantId: payload['custom:tenant-id'], 35 | email: payload.email, 36 | userPoolId: match && match[0], 37 | appClientId: payload.aud, 38 | }; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /services/application/libs/auth/src/policies.json: -------------------------------------------------------------------------------- 1 | { 2 | "dynamodbLeadingKey": { 3 | "Version": "2012-10-17", 4 | "Statement": [ 5 | { 6 | "Effect": "Allow", 7 | "Action": ["dynamodb:*"], 8 | "Resource": ["arn:aws:dynamodb:*:*:table/{{table}}"], 9 | "Condition": { 10 | "ForAllValues:StringEquals": { 11 | "dynamodb:LeadingKeys": ["{{tenant}}"] 12 | } 13 | } 14 | } 15 | ] 16 | }, 17 | "s3": { 18 | "Version": "2012-10-17", 19 | "Statement": [ 20 | { 21 | "Effect": "Allow", 22 | "Action": ["dynamodb:*"], 23 | "Resource": ["arn:aws:dynamodb:*:*:table/{{table}}"], 24 | "Condition": { 25 | "ForAllValues:StringEquals": { 26 | "dynamodb:LeadingKeys": ["{{tenant}}"] 27 | } 28 | } 29 | } 30 | ] 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /services/application/libs/auth/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "declaration": true, 5 | "outDir": "../../dist/libs/auth", 6 | "resolveJsonModule": true 7 | }, 8 | "include": ["src/**/*"], 9 | "exclude": ["node_modules", "dist", "test", "**/*spec.ts"] 10 | } 11 | -------------------------------------------------------------------------------- /services/application/libs/client-factory/src/client-factory.module.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | import { Module } from '@nestjs/common'; 6 | import { ClientFactoryService } from './client-factory.service'; 7 | 8 | @Module({ 9 | providers: [ClientFactoryService], 10 | exports: [ClientFactoryService], 11 | }) 12 | export class ClientFactoryModule {} 13 | -------------------------------------------------------------------------------- /services/application/libs/client-factory/src/client-factory.service.spec.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | import { Test, TestingModule } from '@nestjs/testing'; 6 | import { ClientFactoryService } from './client-factory.service'; 7 | 8 | describe('ClientFactoryService', () => { 9 | let service: ClientFactoryService; 10 | 11 | beforeEach(async () => { 12 | const module: TestingModule = await Test.createTestingModule({ 13 | providers: [ClientFactoryService], 14 | }).compile(); 15 | 16 | service = module.get(ClientFactoryService); 17 | }); 18 | 19 | it('should be defined', () => { 20 | expect(service).toBeDefined(); 21 | }); 22 | }); 23 | -------------------------------------------------------------------------------- /services/application/libs/client-factory/src/client-factory.service.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | import { 6 | CredentialConfig, 7 | CredentialVendor, 8 | PolicyType, 9 | } from '@app/auth/credential-vendor'; 10 | import { DynamoDBClient } from '@aws-sdk/client-dynamodb'; 11 | import { DynamoDBDocumentClient } from '@aws-sdk/lib-dynamodb'; 12 | import { Injectable } from '@nestjs/common'; 13 | 14 | @Injectable() 15 | export class ClientFactoryService { 16 | public async getClient( 17 | tenantId: string, 18 | credentialConfig?: CredentialConfig, 19 | ) { 20 | const credentialVendor = new CredentialVendor(tenantId); 21 | const creds = await credentialVendor.getCredentials( 22 | credentialConfig || { 23 | policyType: PolicyType.DynamoDBLeadingKey, 24 | attributes: { 25 | tenant: tenantId, 26 | }, 27 | }, 28 | ); 29 | return DynamoDBDocumentClient.from( 30 | new DynamoDBClient({ 31 | credentials: { 32 | accessKeyId: creds.AccessKeyId, 33 | secretAccessKey: creds.SecretAccessKey, 34 | sessionToken: creds.SessionToken, 35 | expiration: creds.Expiration, 36 | }, 37 | }), 38 | ); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /services/application/libs/client-factory/src/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | export * from './client-factory.module'; 6 | export * from './client-factory.service'; 7 | -------------------------------------------------------------------------------- /services/application/libs/client-factory/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "declaration": true, 5 | "outDir": "../../dist/libs/client-factory" 6 | }, 7 | "include": ["src/**/*"], 8 | "exclude": ["node_modules", "dist", "test", "**/*spec.ts"] 9 | } 10 | -------------------------------------------------------------------------------- /services/application/tsconfig.build.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "exclude": ["node_modules", "test", "dist", "**/*spec.ts"] 4 | } 5 | -------------------------------------------------------------------------------- /services/application/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "declaration": true, 5 | "removeComments": true, 6 | "emitDecoratorMetadata": true, 7 | "experimentalDecorators": true, 8 | "allowSyntheticDefaultImports": true, 9 | "target": "es2017", 10 | "sourceMap": true, 11 | "outDir": "./dist", 12 | "baseUrl": "./", 13 | "incremental": true, 14 | "resolveJsonModule": true, 15 | "paths": { 16 | "@app/auth": [ 17 | "libs/auth/src" 18 | ], 19 | "@app/auth/*": [ 20 | "libs/auth/src/*" 21 | ], 22 | "@app/client-factory": [ 23 | "libs/client-factory/src" 24 | ], 25 | "@app/client-factory/*": [ 26 | "libs/client-factory/src/*" 27 | ] 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /services/shared/.dockerignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /services/shared/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | parser: '@typescript-eslint/parser', 3 | parserOptions: { 4 | project: 'tsconfig.json', 5 | sourceType: 'module', 6 | tsconfigRootDir: __dirname, 7 | }, 8 | plugins: ['@typescript-eslint/eslint-plugin'], 9 | extends: [ 10 | 'plugin:@typescript-eslint/recommended', 11 | 'plugin:prettier/recommended', 12 | ], 13 | root: true, 14 | env: { 15 | node: true, 16 | jest: true, 17 | }, 18 | ignorePatterns: ['.eslintrc.js'], 19 | rules: { 20 | '@typescript-eslint/interface-name-prefix': 'off', 21 | '@typescript-eslint/explicit-function-return-type': 'off', 22 | '@typescript-eslint/explicit-module-boundary-types': 'off', 23 | '@typescript-eslint/no-explicit-any': 'off', 24 | }, 25 | }; 26 | -------------------------------------------------------------------------------- /services/shared/.gitignore: -------------------------------------------------------------------------------- 1 | # compiled output 2 | /dist 3 | /node_modules 4 | 5 | # Logs 6 | logs 7 | *.log 8 | npm-debug.log* 9 | yarn-debug.log* 10 | yarn-error.log* 11 | lerna-debug.log* 12 | 13 | # OS 14 | .DS_Store 15 | 16 | # Tests 17 | /coverage 18 | /.nyc_output 19 | 20 | # IDEs and editors 21 | /.idea 22 | .project 23 | .classpath 24 | .c9/ 25 | *.launch 26 | .settings/ 27 | *.sublime-workspace 28 | 29 | # IDE - VSCode 30 | .vscode/* 31 | !.vscode/settings.json 32 | !.vscode/tasks.json 33 | !.vscode/launch.json 34 | !.vscode/extensions.json -------------------------------------------------------------------------------- /services/shared/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true, 3 | "trailingComma": "all" 4 | } -------------------------------------------------------------------------------- /services/shared/Dockerfile.tenant-management: -------------------------------------------------------------------------------- 1 | FROM public.ecr.aws/bitnami/node:16.5.0 AS build 2 | WORKDIR /app 3 | COPY package.json yarn.lock ./ 4 | RUN yarn 5 | COPY . . 6 | RUN yarn build tenant-management 7 | 8 | FROM public.ecr.aws/bitnami/node:16.5.0 9 | WORKDIR /app 10 | COPY --from=build /app ./ 11 | EXPOSE 3001 12 | CMD ["npm", "run", "start:tm"] 13 | -------------------------------------------------------------------------------- /services/shared/Dockerfile.tenant-registration: -------------------------------------------------------------------------------- 1 | FROM public.ecr.aws/bitnami/node:16.5.0 AS build 2 | WORKDIR /app 3 | COPY package.json yarn.lock ./ 4 | RUN yarn 5 | COPY . . 6 | RUN yarn build tenant-registration 7 | 8 | FROM public.ecr.aws/bitnami/node:16.5.0 9 | WORKDIR /app 10 | COPY --from=build /app ./ 11 | EXPOSE 3000 12 | CMD ["npm", "run", "start:tr"] 13 | -------------------------------------------------------------------------------- /services/shared/Dockerfile.user-management: -------------------------------------------------------------------------------- 1 | FROM public.ecr.aws/bitnami/node:16.5.0 AS build 2 | WORKDIR /app 3 | COPY package.json yarn.lock ./ 4 | RUN yarn 5 | COPY . . 6 | RUN yarn build user-management 7 | 8 | FROM public.ecr.aws/bitnami/node:16.5.0 9 | WORKDIR /app 10 | COPY --from=build /app ./ 11 | CMD ["npm", "run", "start:um"] 12 | -------------------------------------------------------------------------------- /services/shared/apps/tenant-management/src/main.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | import { NestFactory } from '@nestjs/core'; 6 | import { TenantsModule } from './tenants/tenants.module'; 7 | 8 | async function bootstrap() { 9 | const app = await NestFactory.create(TenantsModule); 10 | app.setGlobalPrefix('api'); 11 | app.enableCors({ 12 | allowedHeaders: '*', 13 | origin: '*', 14 | methods: '*', 15 | }); 16 | await app.listen(3001); 17 | } 18 | bootstrap(); 19 | -------------------------------------------------------------------------------- /services/shared/apps/tenant-management/src/tenants/dto/create-tenant.dto.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | export class CreateTenantDto {} 6 | -------------------------------------------------------------------------------- /services/shared/apps/tenant-management/src/tenants/dto/update-tenant.dto.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | import { PartialType } from '@nestjs/mapped-types'; 6 | import { CreateTenantDto } from './create-tenant.dto'; 7 | 8 | export class UpdateTenantDto extends PartialType(CreateTenantDto) {} 9 | -------------------------------------------------------------------------------- /services/shared/apps/tenant-management/src/tenants/entities/tenant.entity.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | export class Tenant {} 6 | -------------------------------------------------------------------------------- /services/shared/apps/tenant-management/src/tenants/tenants.controller.spec.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | import { Test, TestingModule } from '@nestjs/testing'; 6 | import { TenantsController } from './tenants.controller'; 7 | import { TenantsService } from './tenants.service'; 8 | 9 | describe('TenantsController', () => { 10 | let controller: TenantsController; 11 | 12 | beforeEach(async () => { 13 | const module: TestingModule = await Test.createTestingModule({ 14 | controllers: [TenantsController], 15 | providers: [TenantsService], 16 | }).compile(); 17 | 18 | controller = module.get(TenantsController); 19 | }); 20 | 21 | it('should be defined', () => { 22 | expect(controller).toBeDefined(); 23 | }); 24 | }); 25 | -------------------------------------------------------------------------------- /services/shared/apps/tenant-management/src/tenants/tenants.controller.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | import { 6 | Controller, 7 | Get, 8 | Body, 9 | Patch, 10 | Param, 11 | Delete, 12 | Req, 13 | } from '@nestjs/common'; 14 | import { TenantsService } from './tenants.service'; 15 | import { UpdateTenantDto } from './dto/update-tenant.dto'; 16 | import { Request } from 'express'; 17 | 18 | @Controller('tenants') 19 | export class TenantsController { 20 | constructor(private readonly tenantsService: TenantsService) {} 21 | 22 | @Get() 23 | findAll() { 24 | return this.tenantsService.findAll(); 25 | } 26 | 27 | @Get('/auth-info') 28 | getAuthInfo(@Req() req: Request) { 29 | return this.tenantsService.getAuthInfo(req.headers.referer); 30 | } 31 | 32 | @Get(':id') 33 | findOne(@Param('id') id: string) { 34 | return this.tenantsService.findOne(+id); 35 | } 36 | 37 | @Patch(':id') 38 | update(@Param('id') id: string, @Body() updateTenantDto: UpdateTenantDto) { 39 | return this.tenantsService.update(+id, updateTenantDto); 40 | } 41 | 42 | @Delete(':id') 43 | remove(@Param('id') id: string) { 44 | return this.tenantsService.remove(+id); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /services/shared/apps/tenant-management/src/tenants/tenants.module.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | import { Module } from '@nestjs/common'; 6 | import { ConfigModule } from '@nestjs/config'; 7 | 8 | import { TenantsService } from './tenants.service'; 9 | import { TenantsController } from './tenants.controller'; 10 | import { ClientFactoryModule } from 'libs/client-factory/src'; 11 | 12 | @Module({ 13 | imports: [ClientFactoryModule, ConfigModule.forRoot()], 14 | controllers: [TenantsController], 15 | providers: [TenantsService], 16 | }) 17 | export class TenantsModule {} 18 | -------------------------------------------------------------------------------- /services/shared/apps/tenant-management/src/tenants/tenants.service.spec.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | import { Test, TestingModule } from '@nestjs/testing'; 6 | import { TenantsService } from './tenants.service'; 7 | 8 | describe('TenantsService', () => { 9 | let service: TenantsService; 10 | 11 | beforeEach(async () => { 12 | const module: TestingModule = await Test.createTestingModule({ 13 | providers: [TenantsService], 14 | }).compile(); 15 | 16 | service = module.get(TenantsService); 17 | }); 18 | 19 | it('should be defined', () => { 20 | expect(service).toBeDefined(); 21 | }); 22 | }); 23 | -------------------------------------------------------------------------------- /services/shared/apps/tenant-management/test/jest-e2e.json: -------------------------------------------------------------------------------- 1 | { 2 | "moduleFileExtensions": ["js", "json", "ts"], 3 | "rootDir": ".", 4 | "testEnvironment": "node", 5 | "testRegex": ".e2e-spec.ts$", 6 | "transform": { 7 | "^.+\\.(t|j)s$": "ts-jest" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /services/shared/apps/tenant-management/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "declaration": false, 5 | "outDir": "../../dist/apps/tenant-management" 6 | }, 7 | "include": ["src/**/*"], 8 | "exclude": ["node_modules", "dist", "test", "**/*spec.ts"] 9 | } 10 | -------------------------------------------------------------------------------- /services/shared/apps/tenant-registration/src/idp-service/idp.service.spec.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | import { ClientFactoryService } from '@app/client-factory'; 6 | import { Test, TestingModule } from '@nestjs/testing'; 7 | import { IdpService } from './idp.service'; 8 | 9 | describe('IdpService', () => { 10 | let service: IdpService; 11 | 12 | beforeEach(async () => { 13 | const module: TestingModule = await Test.createTestingModule({ 14 | providers: [IdpService, ClientFactoryService], 15 | }).compile(); 16 | 17 | service = module.get(IdpService); 18 | }); 19 | 20 | it('should be defined', () => { 21 | expect(service).toBeDefined(); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /services/shared/apps/tenant-registration/src/main.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | import { NestFactory } from '@nestjs/core'; 6 | import { RegistrationModule } from './registration/registration.module'; 7 | 8 | async function bootstrap() { 9 | const app = await NestFactory.create(RegistrationModule); 10 | app.setGlobalPrefix('api'); 11 | await app.listen(3000); 12 | } 13 | bootstrap(); 14 | -------------------------------------------------------------------------------- /services/shared/apps/tenant-registration/src/models/types.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | export enum PLAN_TYPE { 6 | Basic = 'basic', 7 | Standard = 'standard', 8 | Premium = 'premium', 9 | } 10 | 11 | export enum USERPOOL_TYPE { 12 | Pooled = 'pooled', 13 | Siloed = 'siloed', 14 | } 15 | -------------------------------------------------------------------------------- /services/shared/apps/tenant-registration/src/registration/constants.ts: -------------------------------------------------------------------------------- 1 | export const USER_SERVICE = 'USER_SERVICE'; 2 | export const USER_SERVICE_PORT = parseInt( 3 | process.env.USER_MANAGEMENT_SERVICE_PORT, 4 | ); 5 | export const USER_SERVICE_HOST = process.env.USER_MANAGEMENT_SERVICE_HOST; 6 | export const CREATE_TENANT_USER = 'createTenantUser'; 7 | -------------------------------------------------------------------------------- /services/shared/apps/tenant-registration/src/registration/dto/create-registration.dto.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | import { PLAN_TYPE } from '../../models/types'; 6 | 7 | export class CreateRegistrationDto { 8 | email: string; 9 | companyName: string; 10 | plan: PLAN_TYPE; 11 | } 12 | -------------------------------------------------------------------------------- /services/shared/apps/tenant-registration/src/registration/dto/update-registration.dto.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | import { PartialType } from '@nestjs/mapped-types'; 6 | import { CreateRegistrationDto } from './create-registration.dto'; 7 | 8 | export class UpdateRegistrationDto extends PartialType(CreateRegistrationDto) {} 9 | -------------------------------------------------------------------------------- /services/shared/apps/tenant-registration/src/registration/entities/registration.entity.spec.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | import { PLAN_TYPE } from '../../models/types'; 6 | import { Registration } from './registration.entity'; 7 | 8 | describe('Registration.Entity', () => { 9 | let sut: Registration; 10 | 11 | it('should handle undefined inputs', () => { 12 | sut = new Registration( 13 | '12345', 14 | 'bob@mail.com', 15 | PLAN_TYPE.Premium, 16 | undefined, 17 | ); 18 | expect(sut.Path).toBe(''); 19 | }); 20 | 21 | it('should trim non alpha characters', () => { 22 | sut = new Registration( 23 | '12345', 24 | 'bob@mail.com', 25 | PLAN_TYPE.Premium, 26 | "Bob's wholesale foods", 27 | ); 28 | expect(sut.Path).toBe('bobswholesalefoods'); 29 | }); 30 | 31 | it('should lowercase inputs', () => { 32 | sut = new Registration( 33 | '12345', 34 | 'fred@flintstone.com', 35 | PLAN_TYPE.Basic, 36 | 'FREDS BASIC BURGERS', 37 | ); 38 | expect(sut.Path).toBe('fredsbasicburgers'); 39 | }); 40 | }); 41 | -------------------------------------------------------------------------------- /services/shared/apps/tenant-registration/src/registration/entities/registration.entity.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | import { PLAN_TYPE } from '../../models/types'; 6 | 7 | export class Registration { 8 | constructor( 9 | public tenantId: string, 10 | public email: string, 11 | public plan: PLAN_TYPE, 12 | public companyName: string, 13 | public apiKey: string, 14 | ) {} 15 | userPoolType: string; 16 | 17 | public get Path() { 18 | return this.companyName?.replace(/\W/g, '').toLowerCase() || ''; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /services/shared/apps/tenant-registration/src/registration/registration.controller.spec.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | import { Test, TestingModule } from '@nestjs/testing'; 6 | import { IdpService } from '../idp-service/idp.service'; 7 | import { RegistrationController } from './registration.controller'; 8 | import { RegistrationService } from './registration.service'; 9 | import { UsersModule } from '../users/users.module'; 10 | import { ClientFactoryService } from '@app/client-factory'; 11 | 12 | describe('RegistrationController', () => { 13 | let controller: RegistrationController; 14 | 15 | beforeEach(async () => { 16 | const module: TestingModule = await Test.createTestingModule({ 17 | controllers: [RegistrationController], 18 | imports: [UsersModule], 19 | providers: [RegistrationService, IdpService, ClientFactoryService], 20 | }).compile(); 21 | 22 | controller = module.get(RegistrationController); 23 | }); 24 | 25 | it('should be defined', () => { 26 | expect(controller).toBeDefined(); 27 | }); 28 | }); 29 | -------------------------------------------------------------------------------- /services/shared/apps/tenant-registration/src/registration/registration.controller.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | import { Controller, Get, Post, Body } from '@nestjs/common'; 6 | import { RegistrationService } from './registration.service'; 7 | import { CreateRegistrationDto } from './dto/create-registration.dto'; 8 | 9 | @Controller('registration') 10 | export class RegistrationController { 11 | constructor(private readonly registrationService: RegistrationService) {} 12 | 13 | @Post() 14 | create(@Body() createRegistrationDto: CreateRegistrationDto) { 15 | return this.registrationService.create(createRegistrationDto); 16 | } 17 | 18 | @Get() 19 | healthCheck() { 20 | return JSON.stringify({ 21 | status: 'OK', 22 | message: 'Tenant Registration Service is live.', 23 | }); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /services/shared/apps/tenant-registration/src/registration/registration.module.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | import { Module } from '@nestjs/common'; 6 | import { ConfigModule } from '@nestjs/config'; 7 | import { ClientsModule, Transport } from '@nestjs/microservices'; 8 | import { ClientFactoryModule } from 'libs/client-factory/src'; 9 | 10 | import { IdpService } from '../idp-service/idp.service'; 11 | import { 12 | USER_SERVICE, 13 | USER_SERVICE_HOST, 14 | USER_SERVICE_PORT, 15 | } from './constants'; 16 | import { RegistrationController } from './registration.controller'; 17 | import { RegistrationService } from './registration.service'; 18 | 19 | @Module({ 20 | imports: [ 21 | ClientFactoryModule, 22 | ConfigModule.forRoot(), 23 | ClientsModule.register([ 24 | { 25 | name: USER_SERVICE, 26 | transport: Transport.TCP, 27 | options: { 28 | port: USER_SERVICE_PORT, 29 | host: USER_SERVICE_HOST, 30 | }, 31 | }, 32 | ]), 33 | ], 34 | controllers: [RegistrationController], 35 | providers: [RegistrationService, IdpService], 36 | }) 37 | export class RegistrationModule {} 38 | -------------------------------------------------------------------------------- /services/shared/apps/tenant-registration/src/registration/registration.service.spec.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | import { Test, TestingModule } from '@nestjs/testing'; 6 | import { UsersService } from '../users/users.service'; 7 | import { IdpService } from '../idp-service/idp.service'; 8 | import { RegistrationService } from './registration.service'; 9 | import { ClientFactoryService } from '@app/client-factory'; 10 | 11 | describe('RegistrationService', () => { 12 | let service: RegistrationService; 13 | 14 | beforeEach(async () => { 15 | const module: TestingModule = await Test.createTestingModule({ 16 | providers: [ 17 | RegistrationService, 18 | IdpService, 19 | ClientFactoryService, 20 | UsersService, 21 | ], 22 | }).compile(); 23 | 24 | service = module.get(RegistrationService); 25 | }); 26 | 27 | it('should be defined', () => { 28 | expect(service).toBeDefined(); 29 | }); 30 | }); 31 | -------------------------------------------------------------------------------- /services/shared/apps/tenant-registration/src/utils/utils.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | export function getTimeString() { 6 | const date = new Date(); 7 | const yyyy = date.getFullYear().toString(); 8 | const MM = pad(date.getMonth() + 1, 2); 9 | const dd = pad(date.getDate(), 2); 10 | const hh = pad(date.getHours(), 2); 11 | const mm = pad(date.getMinutes(), 2); 12 | const ss = pad(date.getSeconds(), 2); 13 | return yyyy + MM + dd + hh + mm + ss; 14 | } 15 | 16 | function pad(n: number, l: number) { 17 | let str = '' + n; 18 | while (str.length < l) { 19 | str = '0' + str; 20 | } 21 | return str; 22 | } 23 | -------------------------------------------------------------------------------- /services/shared/apps/tenant-registration/test/jest-e2e.json: -------------------------------------------------------------------------------- 1 | { 2 | "moduleFileExtensions": ["js", "json", "ts"], 3 | "rootDir": ".", 4 | "testEnvironment": "node", 5 | "testRegex": ".e2e-spec.ts$", 6 | "transform": { 7 | "^.+\\.(t|j)s$": "ts-jest" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /services/shared/apps/tenant-registration/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "declaration": false, 5 | "outDir": "../../dist/apps/tenant-registration" 6 | }, 7 | "include": ["src/**/*"], 8 | "exclude": ["node_modules", "dist", "test", "**/*spec.ts"] 9 | } 10 | -------------------------------------------------------------------------------- /services/shared/apps/user-management/k8s/partial-template.txt: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: user-management 5 | spec: 6 | replicas: 1 7 | selector: 8 | matchLabels: 9 | app: user-management 10 | template: 11 | metadata: 12 | labels: 13 | app: user-management 14 | spec: 15 | containers: 16 | - name: user-management 17 | image: USER_MANAGEMENT_ECR_REPO:latest 18 | imagePullPolicy: Always 19 | ports: 20 | - containerPort: 3015 21 | env: 22 | - name: AWS_REGION 23 | value: "$REGION" 24 | - name: COGNITO_USER_POOL_ID 25 | value: "$USERPOOLID" 26 | --- 27 | apiVersion: v1 28 | kind: Service 29 | metadata: 30 | name: user-management 31 | spec: 32 | selector: 33 | app: user-management 34 | ports: 35 | - name: http 36 | protocol: TCP 37 | port: 3015 38 | targetPort: 3015 39 | -------------------------------------------------------------------------------- /services/shared/apps/user-management/k8s/template.txt: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: user-management 5 | spec: 6 | replicas: 1 7 | selector: 8 | matchLabels: 9 | app: user-management 10 | template: 11 | metadata: 12 | labels: 13 | app: user-management 14 | spec: 15 | containers: 16 | - name: user-management 17 | image: $USERMANAGEMENTECR:latest 18 | imagePullPolicy: Always 19 | ports: 20 | - containerPort: 3015 21 | env: 22 | - name: AWS_REGION 23 | value: "$REGION" 24 | - name: COGNITO_USER_POOL_ID 25 | value: "$USERPOOLID" 26 | --- 27 | apiVersion: v1 28 | kind: Service 29 | metadata: 30 | name: user-management 31 | spec: 32 | selector: 33 | app: user-management 34 | ports: 35 | - name: http 36 | protocol: TCP 37 | port: 3015 38 | targetPort: 3015 39 | -------------------------------------------------------------------------------- /services/shared/apps/user-management/k8s/template.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: user-management 5 | spec: 6 | replicas: 1 7 | selector: 8 | matchLabels: 9 | app: user-management 10 | template: 11 | metadata: 12 | labels: 13 | app: user-management 14 | spec: 15 | containers: 16 | - name: user-management 17 | image: $USERMANAGEMENTECR:latest 18 | imagePullPolicy: Always 19 | ports: 20 | - containerPort: 3015 21 | env: 22 | - name: AWS_REGION 23 | value: "$REGION" 24 | - name: COGNITO_USER_POOL_ID 25 | value: "$USERPOOLID" 26 | --- 27 | apiVersion: v1 28 | kind: Service 29 | metadata: 30 | name: user-management 31 | spec: 32 | selector: 33 | app: user-management 34 | ports: 35 | - name: http 36 | protocol: TCP 37 | port: 3015 38 | targetPort: 3015 39 | -------------------------------------------------------------------------------- /services/shared/apps/user-management/src/main.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | */ 5 | import { NestFactory } from '@nestjs/core'; 6 | import { 7 | Transport, 8 | MicroserviceOptions, 9 | TcpOptions, 10 | } from '@nestjs/microservices'; 11 | import { UsersModule } from './users/users.module'; 12 | 13 | async function bootstrap() { 14 | const options: TcpOptions = { 15 | transport: Transport.TCP, 16 | options: { 17 | host: '0.0.0.0', 18 | port: 3015, 19 | }, 20 | }; 21 | const app = await NestFactory.createMicroservice( 22 | UsersModule, 23 | options, 24 | ); 25 | await app.listen(() => { 26 | console.log('Users microservice is listening...'); 27 | }); 28 | } 29 | bootstrap(); 30 | -------------------------------------------------------------------------------- /services/shared/apps/user-management/src/users/dto/create-tenant-user.dto.ts.ts: -------------------------------------------------------------------------------- 1 | export class CreateTenantUserDto { 2 | userPoolId: string; 3 | email: string; 4 | tenantId: string; 5 | companyName: string; 6 | plan: string; 7 | apiKey: string; 8 | path: string; 9 | } 10 | -------------------------------------------------------------------------------- /services/shared/apps/user-management/src/users/users.controller.ts: -------------------------------------------------------------------------------- 1 | import { Controller } from '@nestjs/common'; 2 | import { MessagePattern, Payload } from '@nestjs/microservices'; 3 | import { UsersService } from './users.service'; 4 | import { CreateTenantUserDto } from './dto/create-tenant-user.dto.ts'; 5 | 6 | @Controller() 7 | export class UsersController { 8 | constructor(private readonly usersService: UsersService) {} 9 | 10 | @MessagePattern('createTenantUser') 11 | createTenantUser(@Payload() createTenantUserDto: CreateTenantUserDto) { 12 | return this.usersService.createTenantUser(createTenantUserDto); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /services/shared/apps/user-management/src/users/users.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { UsersService } from './users.service'; 3 | import { UsersController } from './users.controller'; 4 | 5 | @Module({ 6 | controllers: [UsersController], 7 | providers: [UsersService], 8 | }) 9 | export class UsersModule {} 10 | -------------------------------------------------------------------------------- /services/shared/apps/user-management/src/users/users.service.ts: -------------------------------------------------------------------------------- 1 | import { 2 | AdminCreateUserCommand, 3 | CognitoIdentityProviderClient, 4 | } from '@aws-sdk/client-cognito-identity-provider'; 5 | import { Injectable } from '@nestjs/common'; 6 | import { CreateTenantUserDto } from './dto/create-tenant-user.dto.ts'; 7 | 8 | @Injectable() 9 | export class UsersService { 10 | async createTenantUser(createTenantUserDto: CreateTenantUserDto) { 11 | const { userPoolId, email, companyName, tenantId, plan, apiKey, path } = 12 | createTenantUserDto; 13 | console.log('Adding tenant user with path', userPoolId, email, tenantId, path); 14 | let pathToUse; 15 | if(plan == 'basic') 16 | pathToUse = 'app' 17 | else 18 | pathToUse = path; 19 | const client = new CognitoIdentityProviderClient({}); 20 | const cmd = new AdminCreateUserCommand({ 21 | UserPoolId: userPoolId, 22 | Username: email, 23 | UserAttributes: [ 24 | { Name: 'custom:tenant-id', Value: tenantId }, 25 | { Name: 'custom:company-name', Value: companyName }, 26 | { Name: 'email', Value: email }, 27 | { Name: 'email_verified', Value: 'true' }, 28 | { Name: 'custom:plan', Value: plan }, 29 | { Name: 'custom:api-key', Value: apiKey }, 30 | { Name: 'custom:path', Value: pathToUse }, 31 | ], 32 | }); 33 | const res = await client.send(cmd); 34 | console.log('Successfully added user:', res.User); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /services/shared/apps/user-management/test/jest-e2e.json: -------------------------------------------------------------------------------- 1 | { 2 | "moduleFileExtensions": ["js", "json", "ts"], 3 | "rootDir": ".", 4 | "testEnvironment": "node", 5 | "testRegex": ".e2e-spec.ts$", 6 | "transform": { 7 | "^.+\\.(t|j)s$": "ts-jest" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /services/shared/apps/user-management/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "declaration": false, 5 | "outDir": "../../dist/apps/user-management" 6 | }, 7 | "include": ["src/**/*"], 8 | "exclude": ["node_modules", "dist", "test", "**/*spec.ts"] 9 | } 10 | -------------------------------------------------------------------------------- /services/shared/libs/auth/src/auth.config.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@nestjs/common'; 2 | 3 | @Injectable() 4 | export class AuthConfig { 5 | public userPoolId: string = process.env.COGNITO_USER_POOL_ID; 6 | public clientId: string = process.env.COGNITO_CLIENT_ID; 7 | public region: string = process.env.COGNITO_REGION; 8 | public authority = `https://cognito-idp.${process.env.COGNITO_REGION}.amazonaws.com/${process.env.COGNITO_USER_POOL_ID}`; 9 | } 10 | -------------------------------------------------------------------------------- /services/shared/libs/auth/src/auth.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { PassportModule } from '@nestjs/passport'; 3 | import { AuthConfig } from './auth.config'; 4 | import { JwtStrategy } from './jwt.strategy'; 5 | 6 | @Module({ 7 | imports: [PassportModule.register({ defaultStrategy: 'jwt' })], 8 | providers: [JwtStrategy, AuthConfig], 9 | exports: [JwtStrategy], 10 | }) 11 | export class AuthModule {} 12 | -------------------------------------------------------------------------------- /services/shared/libs/auth/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './auth.module'; 2 | -------------------------------------------------------------------------------- /services/shared/libs/auth/src/jwt-auth.guard.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@nestjs/common'; 2 | import { AuthGuard } from '@nestjs/passport'; 3 | 4 | @Injectable() 5 | export class JwtAuthGuard extends AuthGuard('jwt') {} 6 | -------------------------------------------------------------------------------- /services/shared/libs/auth/src/jwt.strategy.ts: -------------------------------------------------------------------------------- 1 | import { ExtractJwt, Strategy } from 'passport-jwt'; 2 | import { PassportStrategy } from '@nestjs/passport'; 3 | import { Injectable } from '@nestjs/common'; 4 | import { AuthConfig } from './auth.config'; 5 | import { passportJwtSecret } from 'jwks-rsa'; 6 | 7 | @Injectable() 8 | export class JwtStrategy extends PassportStrategy(Strategy) { 9 | constructor(private authConfig: AuthConfig) { 10 | super({ 11 | secretOrKeyProvider: passportJwtSecret({ 12 | cache: true, 13 | rateLimit: true, 14 | jwksRequestsPerMinute: 5, 15 | jwksUri: `${authConfig.authority}/.well-known/jwks.json`, 16 | }), 17 | 18 | jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(), 19 | audience: authConfig.clientId, 20 | issuer: authConfig.authority, 21 | algorithms: ['RS256'], 22 | }); 23 | } 24 | 25 | async validate(payload: any) { 26 | return { userId: payload.sub, username: payload.username }; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /services/shared/libs/auth/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "declaration": true, 5 | "outDir": "../../dist/libs/auth" 6 | }, 7 | "include": ["src/**/*"], 8 | "exclude": ["node_modules", "dist", "test", "**/*spec.ts"] 9 | } 10 | -------------------------------------------------------------------------------- /services/shared/libs/client-factory/src/client-factory.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { ConfigModule } from '@nestjs/config'; 3 | import { ClientFactoryService } from './client-factory.service'; 4 | 5 | @Module({ 6 | imports: [ConfigModule.forRoot()], 7 | providers: [ClientFactoryService], 8 | exports: [ClientFactoryService], 9 | }) 10 | export class ClientFactoryModule {} 11 | -------------------------------------------------------------------------------- /services/shared/libs/client-factory/src/client-factory.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { Test, TestingModule } from '@nestjs/testing'; 2 | import { ClientFactoryService } from './client-factory.service'; 3 | 4 | describe('ClientFactoryService', () => { 5 | let service: ClientFactoryService; 6 | 7 | beforeEach(async () => { 8 | const module: TestingModule = await Test.createTestingModule({ 9 | providers: [ClientFactoryService], 10 | }).compile(); 11 | 12 | service = module.get(ClientFactoryService); 13 | }); 14 | 15 | it('should be defined', () => { 16 | expect(service).toBeDefined(); 17 | }); 18 | }); 19 | -------------------------------------------------------------------------------- /services/shared/libs/client-factory/src/client-factory.service.ts: -------------------------------------------------------------------------------- 1 | import { DynamoDBClient } from '@aws-sdk/client-dynamodb'; 2 | import { DynamoDBDocumentClient } from '@aws-sdk/lib-dynamodb'; 3 | import { Injectable } from '@nestjs/common'; 4 | 5 | @Injectable() 6 | export class ClientFactoryService { 7 | public get client(): DynamoDBDocumentClient { 8 | console.log('REGION:', process.env.AWS_REGION); 9 | const client = DynamoDBDocumentClient.from( 10 | new DynamoDBClient({ region: process.env.AWS_REGION }), 11 | ); 12 | return client; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /services/shared/libs/client-factory/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './client-factory.module'; 2 | export * from './client-factory.service'; 3 | -------------------------------------------------------------------------------- /services/shared/libs/client-factory/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "declaration": true, 5 | "outDir": "../../dist/libs/client-factory" 6 | }, 7 | "include": ["src/**/*"], 8 | "exclude": ["node_modules", "dist", "test", "**/*spec.ts"] 9 | } 10 | -------------------------------------------------------------------------------- /services/shared/tsconfig.build.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "exclude": ["node_modules", "test", "dist", "**/*spec.ts"] 4 | } 5 | -------------------------------------------------------------------------------- /services/shared/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "declaration": true, 5 | "removeComments": true, 6 | "emitDecoratorMetadata": true, 7 | "experimentalDecorators": true, 8 | "allowSyntheticDefaultImports": true, 9 | "target": "es2017", 10 | "sourceMap": true, 11 | "outDir": "./dist", 12 | "baseUrl": "./", 13 | "incremental": true, 14 | "paths": { 15 | "@app/auth": [ 16 | "libs/auth/src" 17 | ], 18 | "@app/auth/*": [ 19 | "libs/auth/src/*" 20 | ], 21 | "@app/client-factory": [ 22 | "libs/client-factory/src" 23 | ], 24 | "@app/client-factory/*": [ 25 | "libs/client-factory/src/*" 26 | ] 27 | } 28 | } 29 | } -------------------------------------------------------------------------------- /update-provisioning-status.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -x 2 | : "${TENANTSTACKTABLE:=$1}" 3 | : "${TENANTNAME:=$2}" 4 | 5 | aws dynamodb update-item \ 6 | --table-name $TENANTSTACKTABLE \ 7 | --key '{"TenantName":{"S":"'$TENANTNAME'"}}' \ 8 | --update-expression "SET #D=:d" \ 9 | --expression-attribute-names '{"#D":"DeploymentStatus"}' \ 10 | --expression-attribute-values '{":d":{"S":"Provisioned"}}' --------------------------------------------------------------------------------