Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file modified .DS_Store
Binary file not shown.
26 changes: 8 additions & 18 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,20 +1,10 @@
.terraform/
.shelltool/
makefiles/
passwd

.npm/
.esbuild/
.serverlessrc
.npmrc
.config/
.yarn/
.cache/
*.js
!jest.config.js
*.d.ts
node_modules
**/node_modules
.dccache
.env
coverage/
.vscode

dist/
# CDK asset staging directory
.cdk.staging
cdk.out
.env
.DS_Store
6 changes: 6 additions & 0 deletions .npmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
*.ts
!*.d.ts

# CDK asset staging directory
.cdk.staging
cdk.out
5 changes: 5 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.DS_Store
node_modules
/build
.env
.env.*
7 changes: 7 additions & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"printWidth": 100,
"singleQuote": true,
"trailingComma": "all",
"tabWidth": 2,
"semi": true
}
3 changes: 3 additions & 0 deletions README.diego.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Arquitectura

![alt text](image.png)
12 changes: 12 additions & 0 deletions bin/io-node-challenge.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#!/usr/bin/env node
import 'source-map-support/register';
import * as cdk from 'aws-cdk-lib';
import { config } from 'dotenv';

import { IoNodeChallengeStack } from '../lib/io-node-challenge-stack';

config();

const app = new cdk.App();
// eslint-disable-next-line no-new
new IoNodeChallengeStack(app, 'IoNodeChallengeStack');
72 changes: 72 additions & 0 deletions cdk.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
{
"app": "npx ts-node --prefer-ts-exts bin/io-node-challenge.ts",
"watch": {
"include": [
"**"
],
"exclude": [
"README.md",
"cdk*.json",
"**/*.d.ts",
"**/*.js",
"tsconfig.json",
"package*.json",
"yarn.lock",
"node_modules",
"test"
]
},
"context": {
"@aws-cdk/aws-lambda:recognizeLayerVersion": true,
"@aws-cdk/core:checkSecretUsage": true,
"@aws-cdk/core:target-partitions": [
"aws",
"aws-cn"
],
"@aws-cdk-containers/ecs-service-extensions:enableDefaultLogDriver": true,
"@aws-cdk/aws-ec2:uniqueImdsv2TemplateName": true,
"@aws-cdk/aws-ecs:arnFormatIncludesClusterName": true,
"@aws-cdk/aws-iam:minimizePolicies": true,
"@aws-cdk/core:validateSnapshotRemovalPolicy": true,
"@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true,
"@aws-cdk/aws-s3:createDefaultLoggingPolicy": true,
"@aws-cdk/aws-sns-subscriptions:restrictSqsDescryption": true,
"@aws-cdk/aws-apigateway:disableCloudWatchRole": true,
"@aws-cdk/core:enablePartitionLiterals": true,
"@aws-cdk/aws-events:eventsTargetQueueSameAccount": true,
"@aws-cdk/aws-ecs:disableExplicitDeploymentControllerForCircuitBreaker": true,
"@aws-cdk/aws-iam:importedRoleStackSafeDefaultPolicyName": true,
"@aws-cdk/aws-s3:serverAccessLogsUseBucketPolicy": true,
"@aws-cdk/aws-route53-patters:useCertificate": true,
"@aws-cdk/customresources:installLatestAwsSdkDefault": false,
"@aws-cdk/aws-rds:databaseProxyUniqueResourceName": true,
"@aws-cdk/aws-codedeploy:removeAlarmsFromDeploymentGroup": true,
"@aws-cdk/aws-apigateway:authorizerChangeDeploymentLogicalId": true,
"@aws-cdk/aws-ec2:launchTemplateDefaultUserData": true,
"@aws-cdk/aws-secretsmanager:useAttachedSecretResourcePolicyForSecretTargetAttachments": true,
"@aws-cdk/aws-redshift:columnId": true,
"@aws-cdk/aws-stepfunctions-tasks:enableEmrServicePolicyV2": true,
"@aws-cdk/aws-ec2:restrictDefaultSecurityGroup": true,
"@aws-cdk/aws-apigateway:requestValidatorUniqueId": true,
"@aws-cdk/aws-kms:aliasNameRef": true,
"@aws-cdk/aws-autoscaling:generateLaunchTemplateInsteadOfLaunchConfig": true,
"@aws-cdk/core:includePrefixInUniqueNameGeneration": true,
"@aws-cdk/aws-efs:denyAnonymousAccess": true,
"@aws-cdk/aws-opensearchservice:enableOpensearchMultiAzWithStandby": true,
"@aws-cdk/aws-lambda-nodejs:useLatestRuntimeVersion": true,
"@aws-cdk/aws-efs:mountTargetOrderInsensitiveLogicalId": true,
"@aws-cdk/aws-rds:auroraClusterChangeScopeOfInstanceParameterGroupWithEachParameters": true,
"@aws-cdk/aws-appsync:useArnForSourceApiAssociationIdentifier": true,
"@aws-cdk/aws-rds:preventRenderingDeprecatedCredentials": true,
"@aws-cdk/aws-codepipeline-actions:useNewDefaultBranchForCodeCommitSource": true,
"@aws-cdk/aws-cloudwatch-actions:changeLambdaPermissionLogicalIdForLambdaAction": true,
"@aws-cdk/aws-codepipeline:crossAccountKeysDefaultValueToFalse": true,
"@aws-cdk/aws-codepipeline:defaultPipelineTypeToV2": true,
"@aws-cdk/aws-kms:reduceCrossAccountRegionPolicyScope": true,
"@aws-cdk/aws-eks:nodegroupNameAttribute": true,
"@aws-cdk/aws-ec2:ebsDefaultGp3Volume": true,
"@aws-cdk/aws-ecs:removeDefaultDeploymentAlarm": true,
"@aws-cdk/custom-resources:logApiResponseDataPropertyTrueDefault": false,
"@aws-cdk/aws-s3:keepNotificationInImportedBucket": false
}
}
Binary file added image.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
25 changes: 5 additions & 20 deletions jest.config.js
Original file line number Diff line number Diff line change
@@ -1,23 +1,8 @@
module.exports = {
testEnvironment: "node",
collectCoverage: true,
verbose: true,
passWithNoTests: true,
testMatch: ["**/*.(test|steps).+(ts|tsx|js)"],
setupFiles: ["dotenv/config"],
coveragePathIgnorePatterns: ["/node_modules/", "/test/", "/dist/"],
modulePathIgnorePatterns: ["<rootDir>/dist/"],
testEnvironment: 'node',
roots: ['<rootDir>/lib'],
testMatch: ['**/*.test.ts'],
transform: {
"^.+\\.tsx?$": [
"ts-jest",
{
diagnostics: false,
testEnvironment: "node",
collectCoverage: true,
},
],
},
moduleNameMapper: {
"src/(.*)": "<rootDir>/src/$1",
},
'^.+\\.tsx?$': 'ts-jest'
}
};
25 changes: 25 additions & 0 deletions lib/intrastructure/Tables.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import * as dynamodb from 'aws-cdk-lib/aws-dynamodb';
import { Construct } from 'constructs';

export class Tables extends Construct {
accountsTable: dynamodb.Table;

transactionsTable: dynamodb.Table;

constructor(scope: Construct, id: string) {
super(scope, id);

const accountsTable = new dynamodb.Table(this, 'accounts', {
partitionKey: { name: 'id', type: dynamodb.AttributeType.STRING },
});

const transactionsTable = new dynamodb.Table(this, 'transactions', {
partitionKey: { name: 'source', type: dynamodb.AttributeType.STRING },
sortKey: { name: 'id', type: dynamodb.AttributeType.STRING },
stream: dynamodb.StreamViewType.NEW_IMAGE,
});

this.accountsTable = accountsTable;
this.transactionsTable = transactionsTable;
}
}
10 changes: 10 additions & 0 deletions lib/intrastructure/layers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import * as cdk from 'aws-cdk-lib';
import * as lambda from 'aws-cdk-lib/aws-lambda';
import { Construct } from 'constructs';

export const getPowertoolsLayer = (scope: Construct) =>
lambda.LayerVersion.fromLayerVersionArn(
scope,
'powertools-layer',
`arn:aws:lambda:${cdk.Stack.of(scope).region}:094274105915:layer:AWSLambdaPowertoolsTypeScriptV2:12`,
);
46 changes: 46 additions & 0 deletions lib/io-node-challenge-stack.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/* eslint-disable no-new */
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';

import { Tables } from './intrastructure/Tables';
import { AccountFunctions } from './services/accounts/infrastructure/AccountFunctions';
import { AccountsGateway } from './services/accounts/infrastructure/AccountsGateway';
import { DomainName } from './services/core/DomainName';
import { LambdaDynamodbStream } from './services/payments/infrastructure/dynamostreams-lambda';
import { PaymentStack } from './services/payments/infrastructure/PaymentStack';

export class IoNodeChallengeStack extends cdk.Stack {
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);

const DOMAIN_NAME = process.env.DOMAIN_NAME || '';
const domain = new DomainName(this, 'DomainName', DOMAIN_NAME);

const tables = new Tables(this, 'Tables');

new PaymentStack(
this,
'PaymentStack',
domain.version,
tables.accountsTable,
tables.transactionsTable,
);

new LambdaDynamodbStream(
this,
'LambdaDynamodbStream',
tables.transactionsTable,
tables.accountsTable,
);

const accountFunctions = new AccountFunctions(this, 'AccountFunctions', tables.accountsTable);

new AccountsGateway(
this,
'AccountsGateway',
accountFunctions.getAccountFunction,
accountFunctions.getAccountsFunction,
domain.version,
);
}
}
23 changes: 23 additions & 0 deletions lib/services/accounts/accounts.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { ScanCommand } from '@aws-sdk/client-dynamodb';

import { ACCOUNTS_TABLE } from '../common/constants';
import { getClient } from '../common/dynamodb';
import { Account } from '../common/types';

const client = getClient();

export const getAccounts = async (): Promise<Account[]> => {
const params = {
TableName: ACCOUNTS_TABLE,
};
console.info('getAccounts - pre', params);

const command = new ScanCommand(params);
const data = await client.send(command);

const accounts: Account[] = data.Items ? (data.Items as unknown as Account[]) : [];

console.info(`getAccounts - Success length: ${accounts.length}`);

return accounts;
};
49 changes: 49 additions & 0 deletions lib/services/accounts/get-account/get-account.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { handler } from './handler';
import { getAccountById } from '../../common/accounts';
import { getLogger } from '../../common/logger';

jest.mock('../../common/accounts');
jest.mock('../../common/logger');

describe('handler', () => {
// const mockLogger = {
// info: jest.fn(),
// };

beforeAll(() => {
// (getLogger as jest.Mock).mockReturnValue(mockLogger);
});

afterEach(() => {
jest.clearAllMocks();
});

it('should return account details', async () => {
const mockEvent = {
pathParameters: {
accountId: '123',
},
};

const mockAccountResponse = {
amount: 1000,
id: '123',
};

(getAccountById as jest.Mock).mockResolvedValue(mockAccountResponse);

const result = await handler(mockEvent);

expect(result).toEqual({
statusCode: 200,
body: JSON.stringify({
amount: 1000,
id: '123',
}),
});

// expect(mockLogger.info).toHaveBeenCalledWith('Event::::', JSON.stringify(mockEvent, null, 2));
// expect(mockLogger.info).toHaveBeenCalledWith('PathParameters::::', 'test....');
expect(getAccountById).toHaveBeenCalledWith('123');
});
});
19 changes: 19 additions & 0 deletions lib/services/accounts/get-account/handler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { getAccountById } from '../../common/accounts';
import { getLogger } from '../../common/logger';
import { Account } from '../../common/types';

export const handler = async (event: any) => {
const accountId = event.pathParameters?.accountId;

const accountResponse = await getAccountById(accountId);

const account: Partial<Account> = {
amount: accountResponse!.amount,
id: accountResponse!.id,
};

return {
statusCode: 200,
body: JSON.stringify(account),
};
};
25 changes: 25 additions & 0 deletions lib/services/accounts/get-accounts/handler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { getAccounts } from '../accounts';

export const handler = async (event: any) => {
console.info('Event:', event, typeof event);

const accounts = await getAccounts();

const transformAccount = (account: any) => {
return {
amount: parseFloat(account.amount.N),
// card_id: account.card_id.S,
id: account.id.S,
picture: account.picture.S,
person_name: account.person_name.S,
// security_code: account.security_code.S,
};
};

const transformedAccounts = accounts.map(transformAccount);

return {
statusCode: 200,
body: JSON.stringify(transformedAccounts),
};
};
Loading