Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JCN-373-campos-opcionales #9

Merged
merged 8 commits into from
Apr 26, 2022
Merged
Show file tree
Hide file tree
Changes from 5 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
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).

## [Unreleased]
### Added
- `additionalFields` getter in **ModelClient** for customizing client fields
- **API Client Created** and **EventListener Client Created** `postSaveHook()` receives the created client object in second parameter.

## [5.2.5] - 2021-12-02
### Fixed
Expand Down
67 changes: 59 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ To skip the fetch of the credentials, it can be used the setting `skipFetchCrede
}
```

### ClientModel
### :sparkles::new::sparkles: ClientModel
At `./[MS_PATH]/models/client.js`

```js
Expand All @@ -157,6 +157,50 @@ const { ModelClient } = require('@janiscommerce/client-creator');
module.exports = ModelClient;
```

:new: **Additional Fields**
Additional fields is a *getter* that allows the service to customize the clients fields, this is useful when a service needs their own custom data in clients.

> #### :information_source: This will affect Client Created API and EventListener and also Client Updated EventListener behavior
> When a client is created or modified, the current client will be obtained from ID service and **only the additional fields that exist in the getter** will be saved in the service along with the basic client fields.

#### Example:
```js
'use strict';
const { ModelClient } = require('@janiscommerce/client-creator');

module.exports = class MyModelClient extends ModelClient {

static get additionalFields() {

return [
'myAdditionalField',
'anotherAdditionalField'
]
}
};
```

#### If a new client is created with these additional fields:
```json
{
"name": "Some Client",
"code": "some-client",
"myAdditionalField": "some-additional-data",
"anotherAdditionalField": "another-additional-data",
"unusedAdditionalField": "unused-data"
}
```

#### The client will be saved in the service with only the specified additional fields:
```json
{
"name": "Some Client",
"code": "some-client",
"myAdditionalField": "some-additional-data",
"anotherAdditionalField": "another-additional-data"
}
```

### APICreate
At `./[MS_PATH]/api/client/post.js`

Expand Down Expand Up @@ -262,11 +306,12 @@ The `APICreate` and `listeners` have a hook for post processing the client or cl

#### APICreate

#### `postSaveHook(clientCodes)`
Receives the clientCodes from the API.
#### `postSaveHook(clientCodes, clients)`
Receives the clientCodes and clients from the API.

gastonpereyra marked this conversation as resolved.
Show resolved Hide resolved
Parameters:
- clientCodes `string Array`: The client created codes.
- clients `object Array`: The clients created objects that were saved.

##### Example
```js
Expand All @@ -275,25 +320,30 @@ const { APICreate } = require('@janiscommerce/client-creator');

class ClientCreateAPI extends APICreate {

async postSaveHook(clientCodes) {
async postSaveHook(clientCodes, clients) {

await myPostSaveMethod(clientCodes);

clientCodes.forEach(clientCode => {
console.log(`Saved client ${clientCode}, now i'm gonna do something great`);
})

clients.forEach(({ databases, status }) => {
console.log(`This epic client has ${databases.length} databases and its status is ${status}`)
})
}
}

module.exports = ClientCreateAPI;
```

#### Listener Created
#### `postSaveHook(clientCode)`
Receives the clientCode from the event.
#### `postSaveHook(clientCode, client)`
Receives the clientCode and client from the event.

Parameters:
- clientCode `string`: The client created code.gs of the created client.
- clientCode `string`: The client created code of the created client.
- client `object`: The client created object that was saved.

It can be implemented as the example bellow:
##### Example
Expand All @@ -304,8 +354,9 @@ const { ListenerCreated } = require('@janiscommerce/client-creator');

class ClientCreateListener extends ListenerCreated {

async postSaveHook(clientCode) {
async postSaveHook(clientCode, client) {
console.log(`Saved client ${clientCode}, now i'm gonna do something great`);
console.log(`Saved client has ${client.databases.length} databases! Whoaaa`)
}
}

Expand Down
35 changes: 30 additions & 5 deletions lib/api-create.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
'use strict';

const logger = require('lllog')();

const { API } = require('@janiscommerce/api');
const { struct } = require('@janiscommerce/superstruct');

const { Invoker } = require('@janiscommerce/lambda');
const MicroserviceCall = require('@janiscommerce/microservice-call');

const ModelFetcher = require('./helpers/model-fetcher');
const ModelClient = require('./model-client');

module.exports = class ClientCreateAPI extends API {

Expand All @@ -18,17 +20,26 @@ module.exports = class ClientCreateAPI extends API {

async process({ clients: clientCodes } = this.data) {

const clientsToCreate = await ModelClient.formatForCreate(clientCodes);

const ClientModel = ModelFetcher.get(); // se tiene que usar el modelo del servicio

const model = new ClientModel();

const clients = ClientModel.additionalFields ? await this.getClients(clientCodes) : clientCodes.map(code => ({ code }));
gastonpereyra marked this conversation as resolved.
Show resolved Hide resolved

if(!clients) {
logger.error('Unable to get Janis ID clients, they won\'t be created.');
return;
}

if(clients.length !== clientCodes.length)
logger.warn('Some clients couldn\'t be obtained from Janis ID service, they won\'t be created.');

const clientsToCreate = await ClientModel.formatForCreate(clients);

await model.multiSave(clientsToCreate);

await Invoker.call('MongoDBIndexCreator');

return this.postSaveHook(clientCodes);
return this.postSaveHook(clientCodes, clientsToCreate);
}

/**
Expand All @@ -37,4 +48,18 @@ module.exports = class ClientCreateAPI extends API {
async postSaveHook() {
return true;
}

async getClients(clientCodes) {

const msCall = new MicroserviceCall();

const { statusCode, body } = await msCall.safeList('id', 'client', { filters: { clientCode: clientCodes } });

if(statusCode >= 500) {
const errorMessage = body && body.message ? `${body.message}` : 'Service failed';
throw new Error(`Failed to get Janis ID clients: ${errorMessage}`);
}

return statusCode < 400 && body.length && body;
}
};
16 changes: 14 additions & 2 deletions lib/helpers/client-formatter.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,24 @@ module.exports = class ClientFormatter {
return this._statusActive;
}

static format(code) {
return {
static format({ code, ...client }, additionalFields) {

const formattedClient = {
code,
databases: this.prepareDatabases(code),
status: this.statusActive
};

if(!additionalFields)
return formattedClient;

Object.entries(client).forEach(([key, value]) => {

if(additionalFields.includes(key))
formattedClient[key] = value;
});
gastonpereyra marked this conversation as resolved.
Show resolved Hide resolved

return formattedClient;
}

static prepareDatabases(code) {
Expand Down
32 changes: 27 additions & 5 deletions lib/listener-created.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
'use strict';

const logger = require('lllog')();

const { EventListener } = require('@janiscommerce/event-listener');

const MongoDBIndexCreator = require('@janiscommerce/mongodb-index-creator');
const MicroserviceCall = require('@janiscommerce/microservice-call');

const ModelFetcher = require('./helpers/model-fetcher');
const ModelClient = require('./model-client');

const mongoDBIndexCreator = new MongoDBIndexCreator();

Expand All @@ -19,17 +21,37 @@ module.exports = class ClientCreatedListener extends EventListener {

const clientCode = this.eventId;

const formattedClient = await ModelClient.formatForCreate(clientCode);

const ClientModel = ModelFetcher.get(); // se tiene que usar el modelo del servicio

const model = new ClientModel();

const client = ClientModel.additionalFields ? await this.getClient(clientCode) : { code: clientCode };

if(!client) {
logger.error('Unable to get Janis ID client, it won\'t be created.');
return;
}

const [formattedClient] = await ClientModel.formatForCreate([client]);

await model.save(formattedClient);

await mongoDBIndexCreator.executeForClientCode(clientCode);

return this.postSaveHook(clientCode);
return this.postSaveHook(clientCode, formattedClient);
}

async getClient(clientCode) {
gastonpereyra marked this conversation as resolved.
Show resolved Hide resolved

const msCall = new MicroserviceCall();

const { statusCode, body } = await msCall.safeList('id', 'client', { filters: { clientCode }, limit: 1 });

if(statusCode >= 500) {
const errorMessage = body && body.message ? `${body.message}` : 'Service failed';
throw new Error(`Failed to get Janis ID client: ${errorMessage}`);
}

return statusCode < 400 && body[0];
}

/**
Expand Down
41 changes: 29 additions & 12 deletions lib/listener-updated.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
'use strict';

const logger = require('lllog')();

const { EventListener } = require('@janiscommerce/event-listener');
const MicroserviceCall = require('@janiscommerce/microservice-call');

Expand All @@ -17,8 +19,10 @@ module.exports = class ClientUpdatedListener extends EventListener {

const updatedClient = await this.getUpdatedClient(clientId);

if(!updatedClient)
if(!updatedClient) {
logger.error('Unable to get Janis ID client, it won\'t be updated.');
return;
}

await this.updateServiceClient(updatedClient);

Expand All @@ -29,26 +33,39 @@ module.exports = class ClientUpdatedListener extends EventListener {

const msCall = new MicroserviceCall();

const response = await msCall.safeCall('id', 'client', 'get', null, null, { id: clientId });
const { statusCode, body } = await msCall.safeCall('id', 'client', 'get', null, null, { id: clientId });

if(msCall.shouldRetry(response)) {
const msCallError = (response.body && response.body.message) ? `${response.body.message}` : 'Unable to get Janis ID client';
throw new Error(msCallError);
if(statusCode >= 500) {
const errorMessage = body && body.message ? `${body.message}` : 'Service failed';
gastonpereyra marked this conversation as resolved.
Show resolved Hide resolved
throw new Error(`Failed to get Janis ID client: ${errorMessage}`);
}

return response.statusCode < 400 && response.body;
return statusCode < 400 && body;
}

updateServiceClient(updatedClient) {
updateServiceClient({ code, status, ...updatedClient }) {

const ClientModel = ModelFetcher.get();
const model = new ClientModel();

return model.update({
status: updatedClient.status
}, {
code: updatedClient.code
});
const fieldsToUpdate = { status };
const fieldsToRemove = {};

if(ClientModel.additionalFields) {

if(!Array.isArray(ClientModel.additionalFields))
gastonpereyra marked this conversation as resolved.
Show resolved Hide resolved
throw new Error('Invalid getter \'additionalFields\': Should be an array.');

ClientModel.additionalFields.forEach(fieldName => {

if(updatedClient[fieldName])
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Acá está el mismo problema con los valores falsy..

fieldsToUpdate[fieldName] = updatedClient[fieldName];
else
fieldsToRemove[fieldName] = '';
});
}

return model.update({ ...fieldsToUpdate, ...Object.keys(fieldsToRemove).length && { $unset: fieldsToRemove } }, { code });
}

/**
Expand Down
16 changes: 8 additions & 8 deletions lib/model-client.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,17 +30,17 @@ module.exports = class Client extends Model {
return ['databases'];
}

static async formatForCreate(clientCodes) {

await ClientFormatter.prepareSettings();
static get additionalFields() {
gastonpereyra marked this conversation as resolved.
Show resolved Hide resolved
return undefined;
}

const isMultiple = Array.isArray(clientCodes);
static async formatForCreate(clients) {

if(!isMultiple)
clientCodes = [clientCodes];
if(this.additionalFields && !Array.isArray(this.additionalFields))
throw new Error('Invalid getter \'additionalFields\': Should be an array.');

const formattedClients = clientCodes.map(clientCode => ClientFormatter.format(clientCode));
await ClientFormatter.prepareSettings();

return isMultiple ? formattedClients : formattedClients[0];
return clients.map(client => ClientFormatter.format(client, this.additionalFields));
}
};
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
"@janiscommerce/model": "^5.5.0",
"@janiscommerce/mongodb-index-creator": "^2.3.0",
"@janiscommerce/settings": "^1.0.1",
"@janiscommerce/superstruct": "^1.2.0"
"@janiscommerce/superstruct": "^1.2.0",
"lllog": "^1.1.2"
}
}
Loading