Skip to content

Commit

Permalink
Merge pull request #7 from TrustlyInc/DEV
Browse files Browse the repository at this point in the history
Update main branch
  • Loading branch information
renatodelpupo authored Apr 22, 2024
2 parents c3d0a4f + f6e1bc1 commit b6f0f48
Show file tree
Hide file tree
Showing 13 changed files with 198 additions and 45 deletions.
File renamed without changes.
30 changes: 30 additions & 0 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
### Description

_(Insert pull request description)_

---

### Relevant Commits

_(List of main updates)_

---

### Requirements

_(Please check if your pull request fulfills the following requirements)_

- [ ] Changes were properly tested (attach evidence if applicable)
- [ ] Repository's code-style/linting compliant

---

### Evidence

_(Insert any evidence related to this pull request. Leave it as **"None"** or **"Not applicable"** if you have nothing to add)_

---

### Additional Information

_(Insert any additional information related to this pull request, as more context or Jira ticket. Leave it as **"None"** or **"Not applicable"** if you have nothing to add)_
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
/dist
/node_modules

# environment variables file
.env

# Logs
logs
*.log
Expand Down
18 changes: 12 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
Alpha Merchant App - Simple Backend
</p>


## Description

Simple backend to demonstrate how to implement the endpoints to integrate with Trustly.
Expand All @@ -19,24 +18,31 @@ $ git clone https://github.com/TrustlyInc/trustly-nestjs-example.git
```

## Configuring Trustly API credentials
In the `.development.env` file replace environment variables values:
- ACCESS_ID
- ACCESS_KEY
- BASE_URL

Copy the `.env.example` file to a new `.env` file and fill out your environment variables.

## Install dependencies

```bash
# install dependencies
$ npm install
```

## Running the app

```bash
# development
$ npm run start:dev
```

## Swagger

```
http://localhost:8080/api
```
```

# Contributing

You can participate in this project by submitting bugs and feature requests in the [Issues](https://github.com/TrustlyInc/trustly-nestjs-example/issues) tab. Please, add [@lukevance](https://github.com/lukevance) as an assignee.

If you are interested in fixing issues and contributing directly to the code base, feel free to open a Pull Request with your changes. Please, make sure to fulfill our [Pull Request Template](https://github.com/TrustlyInc/trustly-nestjs-example/blob/main/.github/pull_request_template.md) and add [@lukevance](https://github.com/lukevance) as code reviewer.
6 changes: 5 additions & 1 deletion src/Dtos/establish.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,8 @@ export class EstablishDto {
account: AccountDto;
@ApiProperty()
transactionId: any;
}
}

export interface EstablishDto {
[key: string]: string | object;
}
59 changes: 33 additions & 26 deletions src/RequestSignature/request-signature.controller.ts
Original file line number Diff line number Diff line change
@@ -1,41 +1,48 @@
import { Body, Controller, Get, Post, RawBodyRequest, Req } from '@nestjs/common';
import {
Body,
Controller,
Post,
RawBodyRequest,
Req,
Res,
} from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { ApiParam, ApiCreatedResponse} from '@nestjs/swagger'
import { ApiParam, ApiCreatedResponse } from '@nestjs/swagger';
import { RequestSignatureService } from './request-signature.service';
import { normalizeEstablishData } from './request-signature.utils';
import { EstablishDto } from '../Dtos/establish.dto';
import { CustomerDto } from 'src/Dtos/customer.dto';
import { AddressDto } from 'src/Dtos/address.dto';
import { Response } from 'express';

@Controller()
export class RequestSignatureController {
constructor(private readonly requestSignatureService: RequestSignatureService, private readonly configService: ConfigService) {}
constructor(
private readonly requestSignatureService: RequestSignatureService,
private readonly configService: ConfigService
) {}

ACCESS_KEY = this.configService.get<String>('ACCESS_KEY')
ACCESS_KEY = this.configService.get<String>('ACCESS_KEY');

@Post('/signature')
@ApiParam({name: 'establish', required: true, schema: new EstablishDto() })
@ApiParam({ name: 'establish', required: true, schema: new EstablishDto() })
@ApiCreatedResponse({
type: String,
})
createRequestSignature(@Body() establish: EstablishDto, @Req() req: RawBodyRequest<Request>): string {
let rawBody = req.rawBody;
createRequestSignature(
@Body() establish: EstablishDto,
@Req() req: RawBodyRequest<Request>,
@Res() res: Response
): object {
const rawBody = req.rawBody;

if (rawBody){
let json = JSON.parse(rawBody.toString());
if (rawBody) {
establish = normalizeEstablishData(establish, rawBody);
}

if(json['customer.name']){
let address = new AddressDto();
address.country = json['customer.address.country'];

let customer = new CustomerDto();
customer.name = json['customer.name'];
customer.address = address;

establish.customer = customer;
}

}

return this.requestSignatureService.getRequestSignature(establish, this.ACCESS_KEY as string);
return res.json(
this.requestSignatureService.getRequestSignature(
establish,
this.ACCESS_KEY as string
)
);
}
}
}
21 changes: 21 additions & 0 deletions src/RequestSignature/request-signature.utils.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { EstablishDto } from '../Dtos/establish.dto';
import { normalizeEstablishData } from './request-signature.utils';

describe('normalizeEstablishData', () => {
test('converts dot notation into nested object', () => {
const dotNotationExample = { 'customer.address.country': 'US' };
const nestedObjectExpectation = {
customer: { address: { country: 'US' } },
};

const establish = {
...new EstablishDto(),
...dotNotationExample,
};
const rawBody = Buffer.from(JSON.stringify(dotNotationExample), 'utf-8');

const result = normalizeEstablishData(establish, rawBody);

expect(result).toEqual(nestedObjectExpectation);
});
});
22 changes: 21 additions & 1 deletion src/RequestSignature/request-signature.utils.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { EstablishDto } from '../Dtos/establish.dto';
import { convertDotNotationIntoNestedObject } from '../utils/normalize';

const CryptoSignature = require('crypto');

Expand Down Expand Up @@ -72,4 +73,23 @@ export const generateSignature = (establishData: EstablishDto, accessKey: string

const requestSignature = CryptoSignature.createHmac('sha1', accessKey).update(query).digest('base64');
return requestSignature;
}
};

export const normalizeEstablishData = (
establish: EstablishDto,
rawBody: Buffer
) => {
// Remove dot notations
for (const key in establish) {
if (key.includes('.')) delete establish[key];
}

// Add as nested objects
const jsonBody = JSON.parse(rawBody.toString());
const objectLiteralBody = convertDotNotationIntoNestedObject(jsonBody);
for (const key in objectLiteralBody) {
establish[key] = objectLiteralBody[key];
}

return establish;
};
4 changes: 2 additions & 2 deletions src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@ import { TransactionModule } from './transaction/transaction.module';
@Module({
imports: [
ConfigModule.forRoot({
envFilePath: '.development.env'
envFilePath: '.env',
}),
ServeStaticModule.forRoot({
rootPath: join(__dirname, '..', 'client'),
}),
TransactionModule
TransactionModule,
],
controllers: [RequestSignatureController],
providers: [RequestSignatureService],
Expand Down
1 change: 1 addition & 0 deletions src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { AppModule } from './app.module';

async function bootstrap() {
const app = await NestFactory.create<NestExpressApplication>(AppModule, {
cors: true,
rawBody: true,
});

Expand Down
16 changes: 7 additions & 9 deletions src/transaction/transaction.module.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,17 @@
import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { HttpModule } from "@nestjs/axios";
import { HttpModule } from '@nestjs/axios';
import { TransactionService } from './transaction.service';
import { TransactionController } from './transaction.controller';

@Module({
imports: [
ConfigModule.forRoot({
envFilePath: '.development.env'
}),
HttpModule,
],
imports: [
ConfigModule.forRoot({
envFilePath: '.env',
}),
HttpModule,
],
controllers: [TransactionController],
providers: [TransactionService],
})

export class TransactionModule {}

41 changes: 41 additions & 0 deletions src/utils/normalize.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { convertDotNotationIntoNestedObject } from './normalize';

describe('convertDotNotationIntoNestedObject', () => {
test('converts dot notation into nested object', () => {
const input = {
'customer.address.country': 'US',
'customer.email': '[email protected]',
'customer.name': 'John',
};

const expectedOutput = {
customer: {
address: {
country: 'US',
},
email: '[email protected]',
name: 'John',
},
};

const result = convertDotNotationIntoNestedObject(input);

expect(result).toEqual(expectedOutput);
});

test('returns the same object reference for object literal input', () => {
const input = {
customer: {
address: {
country: 'US',
},
email: '[email protected]',
name: 'John',
},
};

const result = convertDotNotationIntoNestedObject(input);

expect(result).toEqual(input);
});
});
22 changes: 22 additions & 0 deletions src/utils/normalize.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
type NestedObject = { [key: string]: NestedObject | string };

export function convertDotNotationIntoNestedObject(
obj: NestedObject
): NestedObject {
const result: NestedObject = {};

for (const key in obj) {
const parts = key.split('.');
let current: NestedObject = result;

for (let i = 0; i < parts.length - 1; i++) {
const part = parts[i];
current[part] = current[part] || {};
current = current[part] as NestedObject;
}

current[parts[parts.length - 1]] = obj[key];
}

return result;
}

0 comments on commit b6f0f48

Please sign in to comment.