Skip to content

Commit

Permalink
Merge pull request #314 from g-ongenae/feature/add-logo-url-to-bank
Browse files Browse the repository at this point in the history
[FEAT] Add logoUrl to bank
  • Loading branch information
meriamBenSassi authored Sep 7, 2021
2 parents d063642 + ed80619 commit f799483
Show file tree
Hide file tree
Showing 7 changed files with 118 additions and 18 deletions.
1 change: 1 addition & 0 deletions src/aggregator/interfaces/bridge.interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,7 @@ export interface BridgeBank {
name: string;
country_code: string;
automatic_refresh: boolean;
logo_url: string;
}

/**
Expand Down
12 changes: 12 additions & 0 deletions src/aggregator/services/aggregator.service.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { createHmac } from 'crypto';
import { HttpStatus, Injectable } from '@nestjs/common';
import { config } from 'node-config-ts';
import { AccountBank } from '../../algoan/dto/analysis.inputs';
import {
AuthenticationResponse,
BridgeAccount,
Expand Down Expand Up @@ -120,6 +121,17 @@ export class AggregatorService {
return this.bridgeClient.getResourceName(accessToken, bridgeUri, clientConfig);
}

/**
* Get a bridge bank information by uri
*/
public async getBankInformation(
accessToken: string,
bridgeUri: string,
clientConfig?: ClientConfig,
): Promise<AccountBank> {
return this.bridgeClient.getBankInformation(accessToken, bridgeUri, clientConfig);
}

/**
* Returns the Bridge Personal information for a user
*/
Expand Down
13 changes: 8 additions & 5 deletions src/aggregator/services/bridge/bridge-v2.utils.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { HttpModule } from '@nestjs/common';
import { Test, TestingModule } from '@nestjs/testing';

import { AlgoanModule } from '../../../algoan/algoan.module';
import { AccountLoanType, AccountType, AccountUsage } from '../../../algoan/dto/analysis.enum';
import { Account, AccountTransaction } from '../../../algoan/dto/analysis.inputs';
Expand All @@ -12,14 +11,18 @@ import { mapBridgeAccount, mapBridgeTransactions } from './bridge-v2.utils';

describe('Bridge Utils for Algoan v2 (Customer, Analysis)', () => {
let aggregatorService: AggregatorService;
let aggregatorSpy;
let aggregatorSpyBank;
let aggregatorSpyCategory;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
imports: [AppModule, HttpModule, AlgoanModule, AggregatorModule],
}).compile();

aggregatorService = module.get<AggregatorService>(AggregatorService);
aggregatorSpy = jest
aggregatorSpyBank = jest
.spyOn(aggregatorService, 'getBankInformation')
.mockReturnValue(Promise.resolve({ name: 'mockResourceName' }));
aggregatorSpyCategory = jest
.spyOn(aggregatorService, 'getResourceName')
.mockReturnValue(Promise.resolve('mockResourceName'));
});
Expand Down Expand Up @@ -58,7 +61,7 @@ describe('Bridge Utils for Algoan v2 (Customer, Analysis)', () => {
aggregatorService,
);

expect(aggregatorSpy).toHaveBeenCalledWith('mockAccessToken', mockAccount.bank.resource_uri, undefined);
expect(aggregatorSpyBank).toHaveBeenCalledWith('mockAccessToken', mockAccount.bank.resource_uri, undefined);
expect(mappedAccount).toEqual(expectedAccounts);
});

Expand All @@ -77,6 +80,6 @@ describe('Bridge Utils for Algoan v2 (Customer, Analysis)', () => {
const mappedTransaction = await mapBridgeTransactions([mockTransaction], 'mockAccessToken', aggregatorService);

expect(mappedTransaction).toEqual(expectedTransaction);
expect(aggregatorSpy).toBeCalledWith('mockAccessToken', mockTransaction.category.resource_uri, undefined);
expect(aggregatorSpyCategory).toBeCalledWith('mockAccessToken', mockTransaction.category.resource_uri, undefined);
});
});
3 changes: 1 addition & 2 deletions src/aggregator/services/bridge/bridge-v2.utils.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import * as moment from 'moment-timezone';

import { AccountLoanType, AccountType, AccountUsage } from '../../../algoan/dto/analysis.enum';
import { Account, AccountOwner, AccountTransaction } from '../../../algoan/dto/analysis.inputs';
import {
Expand Down Expand Up @@ -53,8 +52,8 @@ const fromBridgeToAlgoanAccounts = async (
bic: undefined,
name: account.name,
bank: {
...(await aggregator.getBankInformation(accessToken, account.bank.resource_uri, clientConfig)),
id: account.bank?.id?.toString(),
name: await aggregator.getResourceName(accessToken, account.bank.resource_uri, clientConfig),
},
details: {
savings: mapAccountType(account.type) === AccountType.SAVINGS ? {} : undefined,
Expand Down
40 changes: 36 additions & 4 deletions src/aggregator/services/bridge/bridge.client.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
BridgeAccount,
BridgeAccountType,
BridgeBank,
BridgeCategory,
BridgeTransaction,
ConnectItemResponse,
ListResponse,
Expand Down Expand Up @@ -327,13 +328,44 @@ describe('BridgeClient', () => {
});

it('can get a resources name by its uri', async () => {
const mockBank: BridgeBank = {
const mockCategory: BridgeCategory = {
id: 10,
resource_uri: '/v2/mockResourceUri',
resource_type: 'category',
name: 'mockBankCategory',
};
const result: AxiosResponse = {
data: mockCategory,
status: 200,
statusText: '',
headers: {},
config: {},
};

const spy = jest.spyOn(httpService, 'get').mockImplementationOnce(() => of(result));

const resp = await service.getResourceName('mockAccessToken', mockCategory.resource_uri);
expect(resp).toBe('mockBankCategory');

expect(spy).toHaveBeenCalledWith('https://sync.bankin.com/v2/mockResourceUri', {
headers: {
Authorization: 'Bearer mockAccessToken',
'Client-Id': config.bridge.clientId,
'Client-Secret': config.bridge.clientSecret,
'Bankin-Version': config.bridge.bankinVersion,
},
});
});

it('can get a bank information by its uri', async () => {
const mockBank: BridgeBank = {
id: 10,
resource_uri: '/v2/banks/mockResourceUri',
resource_type: 'bank',
name: 'mockBankName',
country_code: 'FR',
automatic_refresh: false,
logo_url: 'logo',
};
const result: AxiosResponse = {
data: mockBank,
Expand All @@ -345,10 +377,10 @@ describe('BridgeClient', () => {

const spy = jest.spyOn(httpService, 'get').mockImplementationOnce(() => of(result));

const resp = await service.getResourceName('mockAccessToken', mockBank.resource_uri);
expect(resp).toBe('mockBankName');
const resp = await service.getBankInformation('mockAccessToken', mockBank.resource_uri);
expect(resp).toEqual({ name: 'mockBankName', logoUrl: 'logo' });

expect(spy).toHaveBeenCalledWith('https://sync.bankin.com/v2/mockResourceUri', {
expect(spy).toHaveBeenCalledWith('https://sync.bankin.com/v2/banks/mockResourceUri', {
headers: {
Authorization: 'Bearer mockAccessToken',
'Client-Id': config.bridge.clientId,
Expand Down
45 changes: 44 additions & 1 deletion src/aggregator/services/bridge/bridge.client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { AxiosError, AxiosRequestConfig, AxiosResponse } from 'axios';
import { Cache } from 'cache-manager';
import { isNil } from 'lodash';
import { config } from 'node-config-ts';
import { AccountBank } from '../../../algoan/dto/analysis.inputs';
import {
AuthenticationResponse,
BridgeAccount,
Expand Down Expand Up @@ -203,7 +204,7 @@ export class BridgeClient {
}

try {
const resp: AxiosResponse<BridgeBank | BridgeCategory> = await this.httpService
const resp: AxiosResponse<BridgeCategory> = await this.httpService
.get(url, {
headers: {
Authorization: `Bearer ${accessToken}`,
Expand All @@ -225,6 +226,48 @@ export class BridgeClient {
}
}

/**
* Get a bridge bank information resource by uri
*/
public async getBankInformation(
accessToken: string,
bridgeUri: string,
clientConfig?: ClientConfig,
): Promise<AccountBank> {
const url: string = `${config.bridge.baseUrl}${bridgeUri}`;

const cached: AccountBank | undefined = await this.cacheManager.get(url);
if (cached !== undefined) {
return cached;
}

try {
const resp: AxiosResponse<BridgeBank> = await this.httpService
.get(url, {
headers: {
Authorization: `Bearer ${accessToken}`,
...BridgeClient.getHeaders(clientConfig),
},
})
.toPromise();

const bankInfo: AccountBank = {
name: resp.data.name,
logoUrl: resp.data.logo_url,
};
await this.cacheManager.set(url, bankInfo, { ttl: 86400 });

return bankInfo;
} catch (err) {
this.logger.warn({
message: `An error occurred while retrieving ${bridgeUri}`,
err,
});

return { name: 'UNKNOWN' };
}
}

/**
* Delete a user
* @param clientConfig Client configuration attached to Algoan's service account
Expand Down
22 changes: 16 additions & 6 deletions src/hooks/services/hooks.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,9 @@ describe('HooksService', () => {
{ ...mockTransaction, date, account: { ...mockTransaction.account, id: mockAccount.id } },
])
.mockResolvedValue([{ ...mockTransaction, account: { ...mockTransaction.account, id: mockAccount.id } }]);
const bankInformationSpy = jest
.spyOn(aggregatorService, 'getBankInformation')
.mockResolvedValue({ name: 'mockBankName' });
const resourceNameSpy = jest.spyOn(aggregatorService, 'getResourceName').mockResolvedValue('mockResourceName');
const deleteUserSpy = jest.spyOn(aggregatorService, 'deleteUser').mockResolvedValue();

Expand All @@ -211,7 +214,7 @@ describe('HooksService', () => {
balanceDate: '2019-04-06T13:53:12.000Z',
bank: {
id: '6',
name: 'mockResourceName',
name: 'mockBankName',
},
bic: undefined,
currency: 'USD',
Expand Down Expand Up @@ -275,7 +278,7 @@ describe('HooksService', () => {
balanceDate: '2019-04-06T13:53:12.000Z',
bank: {
id: '6',
name: 'mockResourceName',
name: 'mockBankName',
},
bic: undefined,
currency: 'USD',
Expand Down Expand Up @@ -307,7 +310,8 @@ describe('HooksService', () => {
expect(accessTokenSpy).toBeCalledWith(customerMock.id, mockServiceAccountConfig);
expect(accountSpy).toBeCalledWith('mockPermToken', mockServiceAccountConfig);
expect(userInfoSpy).toBeCalledWith('mockPermToken', mockServiceAccountConfig);
expect(resourceNameSpy).toBeCalledTimes(4);
expect(bankInformationSpy).toBeCalledTimes(2);
expect(resourceNameSpy).toBeCalledTimes(2);
expect(transactionSpy).toBeCalledTimes(2);
expect(transactionSpy).toBeCalledWith('mockPermToken', undefined, mockServiceAccountConfig);
expect(deleteUserSpy).toHaveBeenNthCalledWith(
Expand Down Expand Up @@ -355,6 +359,9 @@ describe('HooksService', () => {
{ ...mockTransaction, date, account: { ...mockTransaction.account, id: mockAccount.id } },
])
.mockResolvedValue([{ ...mockTransaction, account: { ...mockTransaction.account, id: mockAccount.id } }]);
const bankInformationSpy = jest
.spyOn(aggregatorService, 'getBankInformation')
.mockResolvedValue({ name: 'mockBankName', logoUrl: 'logo' });
const resourceNameSpy = jest.spyOn(aggregatorService, 'getResourceName').mockResolvedValue('mockResourceName');
const deleteUserSpy = jest.spyOn(aggregatorService, 'deleteUser').mockResolvedValue();

Expand All @@ -381,7 +388,8 @@ describe('HooksService', () => {
balanceDate: '2019-04-06T13:53:12.000Z',
bank: {
id: '6',
name: 'mockResourceName',
name: 'mockBankName',
logoUrl: 'logo',
},
bic: undefined,
currency: 'USD',
Expand Down Expand Up @@ -445,7 +453,8 @@ describe('HooksService', () => {
balanceDate: '2019-04-06T13:53:12.000Z',
bank: {
id: '6',
name: 'mockResourceName',
name: 'mockBankName',
logoUrl: 'logo',
},
bic: undefined,
currency: 'USD',
Expand Down Expand Up @@ -477,7 +486,8 @@ describe('HooksService', () => {
expect(accessTokenSpy).toBeCalledWith(customerMock.id, mockServiceAccountConfig);
expect(accountSpy).toBeCalledWith('mockPermToken', mockServiceAccountConfig);
expect(userInfoSpy).toBeCalledWith('mockPermToken', mockServiceAccountConfig);
expect(resourceNameSpy).toBeCalledTimes(4);
expect(bankInformationSpy).toBeCalledTimes(2);
expect(resourceNameSpy).toBeCalledTimes(2);
expect(transactionSpy).toBeCalledTimes(2);
expect(transactionSpy).toBeCalledWith('mockPermToken', undefined, mockServiceAccountConfig);
expect(deleteUserSpy).toHaveBeenNthCalledWith(
Expand Down

0 comments on commit f799483

Please sign in to comment.