From ed4718922e857659c6cdf7a4cb6631e54a274584 Mon Sep 17 00:00:00 2001 From: carlosjr Date: Tue, 17 May 2022 15:37:52 +0200 Subject: [PATCH 01/13] prevented logs on non-existent clients --- modules/client/back/models/client.js | 32 ++++++++++++++++------------ 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/modules/client/back/models/client.js b/modules/client/back/models/client.js index 5ed777ab5..89bda7aba 100644 --- a/modules/client/back/models/client.js +++ b/modules/client/back/models/client.js @@ -446,7 +446,7 @@ module.exports = Self => { const app = require('vn-loopback/server/server'); app.on('started', function() { - let account = app.models.Account; + const account = app.models.Account; account.observe('before save', async ctx => { if (ctx.isNewInstance) return; @@ -454,22 +454,26 @@ module.exports = Self => { }); account.observe('after save', async ctx => { - let changes = ctx.data || ctx.instance; + const changes = ctx.data || ctx.instance; if (!ctx.isNewInstance && changes) { - let oldData = ctx.hookState.oldInstance; - let hasChanges = oldData.name != changes.name || oldData.active != changes.active; + const oldData = ctx.hookState.oldInstance; + const hasChanges = oldData.name != changes.name || oldData.active != changes.active; if (!hasChanges) return; - let userId = ctx.options.accessToken.userId; - let logRecord = { - originFk: oldData.id, - userFk: userId, - action: 'update', - changedModel: 'Account', - oldInstance: {name: oldData.name, active: oldData.active}, - newInstance: {name: changes.name, active: changes.active} - }; - await Self.app.models.ClientLog.create(logRecord); + const isClient = await Self.app.models.Client.findById(oldData.id); + if (isClient) { + const userId = ctx.options.accessToken.userId; + const logRecord = { + originFk: oldData.id, + userFk: userId, + action: 'update', + changedModel: 'Account', + oldInstance: {name: oldData.name, active: oldData.active}, + newInstance: {name: changes.name, active: changes.active} + }; + + await Self.app.models.ClientLog.create(logRecord); + } } }); }); From 4647d6e54e94b34a253870642fe27cb75c5bd724 Mon Sep 17 00:00:00 2001 From: carlosjr Date: Tue, 17 May 2022 15:38:24 +0200 Subject: [PATCH 02/13] e2e path for activate/deactivate user on account/descriptor --- e2e/helpers/selectors.js | 1 + .../01_create_and_basic_data.spec.js | 49 ++++++++++++------- .../02_alias_create_and_basic_data.spec.js | 2 +- 3 files changed, 33 insertions(+), 19 deletions(-) diff --git a/e2e/helpers/selectors.js b/e2e/helpers/selectors.js index 29176489c..b46410a23 100644 --- a/e2e/helpers/selectors.js +++ b/e2e/helpers/selectors.js @@ -55,6 +55,7 @@ export default { setPassword: '.vn-menu [name="setPassword"]', activateAccount: '.vn-menu [name="enableAccount"]', activateUser: '.vn-menu [name="activateUser"]', + deactivateUser: '.vn-menu [name="deactivateUser"]', newPassword: 'vn-textfield[ng-model="$ctrl.newPassword"]', repeatPassword: 'vn-textfield[ng-model="$ctrl.repeatPassword"]', newRole: 'vn-autocomplete[ng-model="$ctrl.newRole"]', diff --git a/e2e/paths/14-account/01_create_and_basic_data.spec.js b/e2e/paths/14-account/01_create_and_basic_data.spec.js index 4048413ba..0fc657375 100644 --- a/e2e/paths/14-account/01_create_and_basic_data.spec.js +++ b/e2e/paths/14-account/01_create_and_basic_data.spec.js @@ -36,8 +36,7 @@ describe('Account create and basic data path', () => { await page.waitForState('account.card.basicData'); }); - it('should reload the section and check the name is as expected', async() => { - await page.reloadSection('account.card.basicData'); + it('should check the name is as expected', async() => { const result = await page.waitToGetProperty(selectors.accountBasicData.name, 'value'); expect(result).toEqual('Remy'); @@ -103,25 +102,39 @@ describe('Account create and basic data path', () => { }); }); - // creating the account without the active property set to true seems to be creating an active user anyways - // describe('activate user', () => { - // it(`should check the inactive user icon is present in the descriptor`, async() => { - // await page.waitForSelector(selectors.accountDescriptor.activeUserIcon, {visible: true}); - // }); + describe('deactivate user', () => { + it(`should check the inactive user icon isn't present in the descriptor just yet`, async() => { + await page.waitForNumberOfElements(selectors.accountDescriptor.activeUserIcon, 0); + }); - // it('should activate the user using the descriptor menu', async() => { - // await page.waitToClick(selectors.accountDescriptor.menuButton); - // await page.waitToClick(selectors.accountDescriptor.activateUser); - // await page.waitToClick(selectors.accountDescriptor.acceptButton); - // const message = await page.waitForSnackbar(); + it('should deactivate the user using the descriptor menu', async() => { + await page.waitToClick(selectors.accountDescriptor.menuButton); + await page.waitToClick(selectors.accountDescriptor.deactivateUser); + await page.waitToClick(selectors.accountDescriptor.acceptButton); + const message = await page.waitForSnackbar(); - // expect(message.text).toContain('user enabled?'); - // }); + expect(message.text).toContain('User deactivated!'); + }); - // it('should check the inactive user icon is not present anymore', async() => { - // await page.waitForNumberOfElements(selectors.accountDescriptor.activeUserIcon, 0); - // }); - // }); + it('should check the inactive user icon is now present', async() => { + await page.waitForNumberOfElements(selectors.accountDescriptor.activeUserIcon, 1); + }); + }); + + describe('activate user', () => { + it('should activate the user using the descriptor menu', async() => { + await page.waitToClick(selectors.accountDescriptor.menuButton); + await page.waitToClick(selectors.accountDescriptor.activateUser); + await page.waitToClick(selectors.accountDescriptor.acceptButton); + const message = await page.waitForSnackbar(); + + expect(message.text).toContain('User activated!'); + }); + + it('should check the inactive user icon is not present anymore', async() => { + await page.waitForNumberOfElements(selectors.accountDescriptor.activeUserIcon, 0); + }); + }); describe('mail forwarding', () => { it('should activate the mail forwarding and set the recipent email', async() => { diff --git a/e2e/paths/14-account/02_alias_create_and_basic_data.spec.js b/e2e/paths/14-account/02_alias_create_and_basic_data.spec.js index 0514899bc..dd35dd740 100644 --- a/e2e/paths/14-account/02_alias_create_and_basic_data.spec.js +++ b/e2e/paths/14-account/02_alias_create_and_basic_data.spec.js @@ -56,7 +56,7 @@ describe('Account Alias create and basic data path', () => { expect(result).toContain('psykers'); }); - it('should search for the IT alias group then access to the users section then check the role listed is the expected one', async() => { + it('should search IT alias then access the user section to check the role listed is the expected one', async() => { await page.accessToSearchResult('IT'); await page.accessToSection('account.alias.card.users'); const rolesCount = await page.countElement(selectors.accountAliasUsers.anyResult); From f3cca1c9307d0a11f1b8fff984ba09857d24463f Mon Sep 17 00:00:00 2001 From: vicent Date: Wed, 15 Jun 2022 14:24:35 +0200 Subject: [PATCH 03/13] fix: warehouse changed from 'silla' to 'algemesi' --- modules/entry/back/methods/entry/latestBuysFilter.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/modules/entry/back/methods/entry/latestBuysFilter.js b/modules/entry/back/methods/entry/latestBuysFilter.js index 35252e107..8cb0b32db 100644 --- a/modules/entry/back/methods/entry/latestBuysFilter.js +++ b/modules/entry/back/methods/entry/latestBuysFilter.js @@ -96,6 +96,7 @@ module.exports = Self => { }); Self.latestBuysFilter = async(ctx, filter, options) => { + const models = Self.app.models; const myOptions = {}; if (typeof options == 'object') @@ -143,7 +144,10 @@ module.exports = Self => { const stmts = []; let stmt; - stmts.push('CALL cache.visible_refresh(@calc_id, FALSE, 1)'); + const warehouse = await models.Warehouse.findOne({where: {code: 'ALG'}}, myOptions); + stmt = new ParameterizedSQL(`CALL cache.visible_refresh(@calc_id, FALSE, ?)`, [warehouse.id]); + console.log(stmt); + stmts.push(stmt); const date = new Date(); date.setHours(0, 0, 0, 0); From f41b9b0b57641fdfc551b1a06b5d96548be07082 Mon Sep 17 00:00:00 2001 From: vicent Date: Wed, 15 Jun 2022 14:25:31 +0200 Subject: [PATCH 04/13] refator: delete console.log --- modules/entry/back/methods/entry/latestBuysFilter.js | 1 - 1 file changed, 1 deletion(-) diff --git a/modules/entry/back/methods/entry/latestBuysFilter.js b/modules/entry/back/methods/entry/latestBuysFilter.js index 8cb0b32db..9a21d4472 100644 --- a/modules/entry/back/methods/entry/latestBuysFilter.js +++ b/modules/entry/back/methods/entry/latestBuysFilter.js @@ -146,7 +146,6 @@ module.exports = Self => { const warehouse = await models.Warehouse.findOne({where: {code: 'ALG'}}, myOptions); stmt = new ParameterizedSQL(`CALL cache.visible_refresh(@calc_id, FALSE, ?)`, [warehouse.id]); - console.log(stmt); stmts.push(stmt); const date = new Date(); From 84ffe3f59432a6bb4bff6c3e8aadd6008af0361b Mon Sep 17 00:00:00 2001 From: vicent Date: Thu, 16 Jun 2022 09:58:15 +0200 Subject: [PATCH 05/13] feat: delete from ticketCollection and sectorCollection when a ticket is deleted --- .../ticket/back/methods/ticket/setDeleted.js | 19 ++++++++++++++++ modules/ticket/back/model-config.json | 3 +++ .../ticket/back/models/ticket-collection.json | 22 +++++++++++++++++++ 3 files changed, 44 insertions(+) create mode 100644 modules/ticket/back/models/ticket-collection.json diff --git a/modules/ticket/back/methods/ticket/setDeleted.js b/modules/ticket/back/methods/ticket/setDeleted.js index 38bd6e7b5..c683dcffd 100644 --- a/modules/ticket/back/methods/ticket/setDeleted.js +++ b/modules/ticket/back/methods/ticket/setDeleted.js @@ -142,6 +142,25 @@ module.exports = Self => { const updatedTicket = await ticket.updateAttribute('isDeleted', true, myOptions); + const [ticketCollection] = await models.TicketCollection.find({ + fields: ['id'], + where: { + ticketFk: ticket.id + } + }); + + if (ticketCollection) + await models.TicketCollection.destroyById(ticketCollection.id, myOptions); + + await Self.rawSql(` + DELETE sc + FROM vn.saleGroup sg + JOIN vn.sectorCollectionSaleGroup scsg ON scsg.saleGroupFk = sg.id + JOIN vn.sectorCollection sc ON sc.id = scsg.sectorCollectionFk + JOIN vn.saleGroupDetail sgd ON sgd.saleGroupFk = sg.id + JOIN vn.sale s ON s.id = sgd.saleFk + WHERE s.ticketFk = ?;`, [ticket.id], myOptions); + if (tx) await tx.commit(); return updatedTicket; diff --git a/modules/ticket/back/model-config.json b/modules/ticket/back/model-config.json index 41885ee33..e75c7415e 100644 --- a/modules/ticket/back/model-config.json +++ b/modules/ticket/back/model-config.json @@ -44,6 +44,9 @@ "Ticket": { "dataSource": "vn" }, + "TicketCollection": { + "dataSource": "vn" + }, "TicketDms": { "dataSource": "vn" }, diff --git a/modules/ticket/back/models/ticket-collection.json b/modules/ticket/back/models/ticket-collection.json new file mode 100644 index 000000000..e941ac2ce --- /dev/null +++ b/modules/ticket/back/models/ticket-collection.json @@ -0,0 +1,22 @@ +{ + "name": "TicketCollection", + "base": "VnModel", + "options": { + "mysql": { + "table": "ticketCollection" + } + }, + "properties": { + "id": { + "id": true, + "type": "number" + } + }, + "relations": { + "ticket": { + "type": "belongsTo", + "model": "Ticket", + "foreignKey": "ticketFk" + } + } +} \ No newline at end of file From c49f5632996c2b709e3eccd741a45192aee6590d Mon Sep 17 00:00:00 2001 From: vicent Date: Thu, 16 Jun 2022 10:59:17 +0200 Subject: [PATCH 06/13] feat: add fixtures --- db/dump/fixtures.sql | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/db/dump/fixtures.sql b/db/dump/fixtures.sql index 9f3a5e717..29d57073c 100644 --- a/db/dump/fixtures.sql +++ b/db/dump/fixtures.sql @@ -1129,19 +1129,17 @@ INSERT INTO `vn`.`collection`(`id`, `workerFk`, `stateFk`, `created`, `trainFk`) (1, 1106, 5, DATE_ADD(util.VN_CURDATE(),INTERVAL +1 DAY), 1), (2, 1106, 14, util.VN_CURDATE(), 1); -INSERT INTO `vn`.`ticketCollection`(`id`, `ticketFk`, `collectionFk`) +INSERT INTO `vn`.`ticketCollection`(`ticketFk`, `collectionFk`, `level`) VALUES - (2, 2, 1), - (3, 3, 2); + (1, 1, 1), + (2, 1, NULL), + (3, 2, NULL), + (23, 1, NULL); INSERT INTO `vn`.`parking` (`column`, `row`, `sectorFk`, `code`, `pickingOrder`) VALUES ('100', '01', 1, '100-01', 1); -INSERT INTO `vn`.`ticketCollection` (`ticketFk`, `collectionFk`, `level`) - VALUES - (1, 1, 1); - INSERT INTO `vn`.`genus`(`id`, `name`) VALUES (1, 'Abelia'), @@ -2593,4 +2591,20 @@ INSERT INTO `vn`.`mdbBranch` (`name`) INSERT INTO `vn`.`mdbVersion` (`app`, `branchFk`, `version`) VALUES ('tpv', 'test', '1'), - ('lab', 'master', '1'); \ No newline at end of file + ('lab', 'master', '1'); + +INSERT INTO `vn`.`saleGroup` (`userFk`, `parkingFk`, `sectorFk`) + VALUES + (1, 1, 1); + +INSERT INTO `vn`.`saleGroupDetail` (`saleFk`, `saleGroupFk`) + VALUES + (31, 1); + +INSERT INTO `vn`.`sectorCollection` (`userFk`, `sectorFk`) + VALUES + (1, 1); + +INSERT INTO `vn`.`sectorCollectionSaleGroup` (`sectorCollectionFk`, `saleGroupFk`) + VALUES + (1, 1); From 00e48f5257ee5976dd905f3b32436b532b68a7fc Mon Sep 17 00:00:00 2001 From: vicent Date: Thu, 16 Jun 2022 10:59:31 +0200 Subject: [PATCH 07/13] feat: add backTest --- .../back/methods/ticket/specs/filter.spec.js | 2 +- .../methods/ticket/specs/setDeleted.spec.js | 70 +++++++++++++++++++ 2 files changed, 71 insertions(+), 1 deletion(-) diff --git a/modules/ticket/back/methods/ticket/specs/filter.spec.js b/modules/ticket/back/methods/ticket/specs/filter.spec.js index 4b583fc87..020bc5747 100644 --- a/modules/ticket/back/methods/ticket/specs/filter.spec.js +++ b/modules/ticket/back/methods/ticket/specs/filter.spec.js @@ -213,7 +213,7 @@ describe('ticket filter()', () => { const filter = {}; const result = await models.Ticket.filter(ctx, filter, options); - expect(result.length).toEqual(2); + expect(result.length).toEqual(3); await tx.rollback(); } catch (e) { diff --git a/modules/ticket/back/methods/ticket/specs/setDeleted.spec.js b/modules/ticket/back/methods/ticket/specs/setDeleted.spec.js index 9b629e634..4551377df 100644 --- a/modules/ticket/back/methods/ticket/specs/setDeleted.spec.js +++ b/modules/ticket/back/methods/ticket/specs/setDeleted.spec.js @@ -8,6 +8,12 @@ describe('ticket setDeleted()', () => { accessToken: {userId: userId}, }; + beforeEach(() => { + spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({ + active: activeCtx + }); + }); + it('should throw an error if the given ticket has a claim', async() => { const tx = await models.Ticket.beginTransaction({}); @@ -29,6 +35,70 @@ describe('ticket setDeleted()', () => { expect(error.message).toEqual('You must delete the claim id %d first'); }); + it('should delete a sectorCollection row', async() => { + const tx = await models.Ticket.beginTransaction({}); + + try { + const options = {transaction: tx}; + + const ctx = { + req: { + accessToken: {userId: 9}, + headers: {origin: 'http://localhost:5000'}, + } + }; + ctx.req.__ = value => { + return value; + }; + const ticketId = 23; + + await models.Ticket.setDeleted(ctx, ticketId, options); + + const [sectorCollection] = await models.Ticket.rawSql( + `SELECT COUNT(*) numberRows + FROM vn.sectorCollection`, [], options); + + expect(sectorCollection.numberRows).toEqual(0); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } + }); + + it('should delete a ticketCollection row', async() => { + const tx = await models.Ticket.beginTransaction({}); + + try { + const options = {transaction: tx}; + + const ctx = { + req: { + accessToken: {userId: 9}, + headers: {origin: 'http://localhost:5000'}, + } + }; + ctx.req.__ = value => { + return value; + }; + const ticketId = 23; + + await models.Ticket.setDeleted(ctx, ticketId, options); + + const [ticketCollection] = await models.Ticket.rawSql( + `SELECT COUNT(*) numberRows + FROM vn.ticketCollection`, [], options); + + expect(ticketCollection.numberRows).toEqual(3); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } + }); + it('should delete ticket, remove stowaway and itemshelving then change stowaway state to "FIXING" ', async() => { pending('test excluded by task #3693'); const tx = await models.Ticket.beginTransaction({}); From 0f44f072eee2af6b0958be8da9e6139cb49335eb Mon Sep 17 00:00:00 2001 From: carlosjr Date: Thu, 16 Jun 2022 11:32:42 +0200 Subject: [PATCH 08/13] refactor(client): added updateUser and setPassword methods to client module --- back/methods/account/set-password.js | 5 +- db/changes/10481-june/00-ACL.sql | 4 ++ db/changes/10481-june/delete.keep | 0 loopback/locale/en.json | 3 +- loopback/locale/es.json | 3 +- .../client/back/methods/client/setPassword.js | 32 ++++++++++ .../methods/client/specs/setPassword.spec.js | 27 ++++++++ .../methods/client/specs/updateUser.spec.js | 55 ++++++++++++++++ .../client/back/methods/client/updateUser.js | 60 +++++++++++++++++ modules/client/back/models/client.js | 64 ++++++++++--------- modules/client/front/web-access/index.html | 4 +- modules/client/front/web-access/index.js | 17 ++++- modules/client/front/web-access/index.spec.js | 6 +- 13 files changed, 239 insertions(+), 41 deletions(-) create mode 100644 db/changes/10481-june/00-ACL.sql delete mode 100644 db/changes/10481-june/delete.keep create mode 100644 modules/client/back/methods/client/setPassword.js create mode 100644 modules/client/back/methods/client/specs/setPassword.spec.js create mode 100644 modules/client/back/methods/client/specs/updateUser.spec.js create mode 100644 modules/client/back/methods/client/updateUser.js diff --git a/back/methods/account/set-password.js b/back/methods/account/set-password.js index fc54b5abe..ab4d3b3fe 100644 --- a/back/methods/account/set-password.js +++ b/back/methods/account/set-password.js @@ -1,16 +1,15 @@ - module.exports = Self => { Self.remoteMethod('setPassword', { description: 'Sets the user password', accepts: [ { arg: 'id', - type: 'Number', + type: 'number', description: 'The user id', http: {source: 'path'} }, { arg: 'newPassword', - type: 'String', + type: 'string', description: 'The new password', required: true } diff --git a/db/changes/10481-june/00-ACL.sql b/db/changes/10481-june/00-ACL.sql new file mode 100644 index 000000000..3236ff1fd --- /dev/null +++ b/db/changes/10481-june/00-ACL.sql @@ -0,0 +1,4 @@ +INSERT INTO `salix`.`ACL` (model,property,accessType,permission,principalType,principalId) + VALUES + ('Client','setPassword','WRITE','ALLOW','ROLE','salesPerson'), + ('Client','updateUser','WRITE','ALLOW','ROLE','salesPerson'); diff --git a/db/changes/10481-june/delete.keep b/db/changes/10481-june/delete.keep deleted file mode 100644 index e69de29bb..000000000 diff --git a/loopback/locale/en.json b/loopback/locale/en.json index b7e9b43d3..c9dca734f 100644 --- a/loopback/locale/en.json +++ b/loopback/locale/en.json @@ -123,5 +123,6 @@ "The worker has hours recorded that day": "The worker has hours recorded that day", "isWithoutNegatives": "isWithoutNegatives", "routeFk": "routeFk", - "Not enough privileges to edit a client with verified data": "Not enough privileges to edit a client with verified data" + "Not enough privileges to edit a client with verified data": "Not enough privileges to edit a client with verified data", + "Can't change the password of another worker": "Can't change the password of another worker" } \ No newline at end of file diff --git a/loopback/locale/es.json b/loopback/locale/es.json index 9e2b8989b..23c2281c3 100644 --- a/loopback/locale/es.json +++ b/loopback/locale/es.json @@ -226,5 +226,6 @@ "reference duplicated": "Referencia duplicada", "This ticket is already a refund": "Este ticket ya es un abono", "isWithoutNegatives": "isWithoutNegatives", - "routeFk": "routeFk" + "routeFk": "routeFk", + "Can't change the password of another worker": "No se puede cambiar la contraseƱa de otro trabajador" } \ No newline at end of file diff --git a/modules/client/back/methods/client/setPassword.js b/modules/client/back/methods/client/setPassword.js new file mode 100644 index 000000000..19675d0e8 --- /dev/null +++ b/modules/client/back/methods/client/setPassword.js @@ -0,0 +1,32 @@ +module.exports = Self => { + Self.remoteMethod('setPassword', { + description: 'Sets the password of a non-worker client', + accepts: [ + { + arg: 'id', + type: 'number', + description: 'The user id', + http: {source: 'path'} + }, { + arg: 'newPassword', + type: 'string', + description: 'The new password', + required: true + } + ], + http: { + path: `/:id/setPassword`, + verb: 'PATCH' + } + }); + + Self.setPassword = async function(id, newPassword) { + const models = Self.app.models; + + const isWorker = await models.Worker.findById(id); + if (isWorker) + throw new Error(`Can't change the password of another worker`); + + await models.Account.setPassword(id, newPassword); + }; +}; diff --git a/modules/client/back/methods/client/specs/setPassword.spec.js b/modules/client/back/methods/client/specs/setPassword.spec.js new file mode 100644 index 000000000..e0de20249 --- /dev/null +++ b/modules/client/back/methods/client/specs/setPassword.spec.js @@ -0,0 +1,27 @@ +const models = require('vn-loopback/server/server').models; + +describe('Client setPassword', () => { + it('should throw an error the setPassword target is not just a client but a worker', async() => { + let error; + + try { + await models.Client.setPassword(1106, 'newPass?'); + } catch (e) { + error = e; + } + + expect(error.message).toEqual(`Can't change the password of another worker`); + }); + + it('should change the password of the client', async() => { + let error; + + try { + await models.Client.setPassword(1101, 't0pl3v3l.p455w0rd!'); + } catch (e) { + error = e; + } + + expect(error).toBeUndefined(); + }); +}); diff --git a/modules/client/back/methods/client/specs/updateUser.spec.js b/modules/client/back/methods/client/specs/updateUser.spec.js new file mode 100644 index 000000000..49acfda97 --- /dev/null +++ b/modules/client/back/methods/client/specs/updateUser.spec.js @@ -0,0 +1,55 @@ +const models = require('vn-loopback/server/server').models; +const LoopBackContext = require('loopback-context'); +describe('Client updateUser', () => { + const employeeId = 1; + const activeCtx = { + accessToken: {userId: employeeId}, + http: { + req: { + headers: {origin: 'http://localhost'} + } + } + }; + const ctx = {req: {accessToken: {userId: employeeId}}}; + + beforeEach(() => { + spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({ + active: activeCtx + }); + }); + + it('should throw an error the target user is not just a client but a worker', async() => { + let error; + try { + await models.Client.updateUser(ctx, 1106, 'test', true); + } catch (e) { + error = e; + } + + expect(error.message).toEqual(`Can't update the user details of another worker`); + }); + + it('should update the user data', async() => { + let error; + + const tx = await models.Client.beginTransaction({}); + + try { + const options = {transaction: tx}; + + const clientID = 1105; + + await models.Client.updateUser(ctx, clientID, 'test', true, options); + const client = await models.Account.findById(clientID, null, options); + + expect(client.name).toEqual('test'); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } + + expect(error).toBeUndefined(); + }); +}); diff --git a/modules/client/back/methods/client/updateUser.js b/modules/client/back/methods/client/updateUser.js new file mode 100644 index 000000000..26fcd6026 --- /dev/null +++ b/modules/client/back/methods/client/updateUser.js @@ -0,0 +1,60 @@ +module.exports = Self => { + Self.remoteMethodCtx('updateUser', { + description: 'Updates the user information', + accepts: [ + { + arg: 'id', + type: 'number', + description: 'The user id', + http: {source: 'path'} + }, + { + arg: 'name', + type: 'string', + description: 'the user name' + }, + { + arg: 'isActive', + type: 'boolean', + description: 'whether the user is active or not' + }, + ], + http: { + path: '/:id/updateUser', + verb: 'PATCH' + } + }); + + Self.updateUser = async function(ctx, id, name, isActive, options) { + const models = Self.app.models; + let tx; + const myOptions = {}; + + if (typeof options == 'object') + Object.assign(myOptions, options); + + if (!myOptions.transaction) { + tx = await models.Account.beginTransaction({}); + myOptions.transaction = tx; + } + + try { + const isWorker = await models.Worker.findById(id, null, myOptions); + if (isWorker) + throw new Error(`Can't update the user details of another worker`); + + const user = await models.Account.findById(id, null, myOptions); + + const data = {}; + if (name) data.name = name; + if (isActive != undefined) data.active = isActive; + + await user.updateAttributes(data, myOptions); + + if (tx) await tx.commit(); + } catch (e) { + if (tx) await tx.rollback(); + throw e; + } + }; +}; diff --git a/modules/client/back/models/client.js b/modules/client/back/models/client.js index 90a9b9e23..696934db7 100644 --- a/modules/client/back/models/client.js +++ b/modules/client/back/models/client.js @@ -8,30 +8,32 @@ const LoopBackContext = require('loopback-context'); module.exports = Self => { // Methods - require('../methods/client/getCard')(Self); - require('../methods/client/createWithUser')(Self); - require('../methods/client/hasCustomerRole')(Self); - require('../methods/client/canCreateTicket')(Self); - require('../methods/client/isValidClient')(Self); require('../methods/client/addressesPropagateRe')(Self); + require('../methods/client/canBeInvoiced')(Self); + require('../methods/client/canCreateTicket')(Self); + require('../methods/client/checkDuplicated')(Self); + require('../methods/client/confirmTransaction')(Self); + require('../methods/client/consumption')(Self); + require('../methods/client/createAddress')(Self); + require('../methods/client/createReceipt')(Self); + require('../methods/client/createWithUser')(Self); + require('../methods/client/extendedListFilter')(Self); + require('../methods/client/getAverageInvoiced')(Self); + require('../methods/client/getCard')(Self); require('../methods/client/getDebt')(Self); require('../methods/client/getMana')(Self); - require('../methods/client/getAverageInvoiced')(Self); - require('../methods/client/summary')(Self); - require('../methods/client/updateFiscalData')(Self); require('../methods/client/getTransactions')(Self); - require('../methods/client/confirmTransaction')(Self); - require('../methods/client/canBeInvoiced')(Self); - require('../methods/client/uploadFile')(Self); + require('../methods/client/hasCustomerRole')(Self); + require('../methods/client/isValidClient')(Self); require('../methods/client/lastActiveTickets')(Self); require('../methods/client/sendSms')(Self); - require('../methods/client/createAddress')(Self); + require('../methods/client/setPassword')(Self); + require('../methods/client/summary')(Self); require('../methods/client/updateAddress')(Self); - require('../methods/client/consumption')(Self); - require('../methods/client/createReceipt')(Self); + require('../methods/client/updateFiscalData')(Self); require('../methods/client/updatePortfolio')(Self); - require('../methods/client/checkDuplicated')(Self); - require('../methods/client/extendedListFilter')(Self); + require('../methods/client/updateUser')(Self); + require('../methods/client/uploadFile')(Self); // Validations @@ -446,7 +448,7 @@ module.exports = Self => { const app = require('vn-loopback/server/server'); app.on('started', function() { - let account = app.models.Account; + const account = app.models.Account; account.observe('before save', async ctx => { if (ctx.isNewInstance) return; @@ -456,20 +458,24 @@ module.exports = Self => { account.observe('after save', async ctx => { let changes = ctx.data || ctx.instance; if (!ctx.isNewInstance && changes) { - let oldData = ctx.hookState.oldInstance; - let hasChanges = oldData.name != changes.name || oldData.active != changes.active; + const oldData = ctx.hookState.oldInstance; + const hasChanges = oldData.name != changes.name || oldData.active != changes.active; if (!hasChanges) return; - let userId = ctx.options.accessToken.userId; - let logRecord = { - originFk: oldData.id, - userFk: userId, - action: 'update', - changedModel: 'Account', - oldInstance: {name: oldData.name, active: oldData.active}, - newInstance: {name: changes.name, active: changes.active} - }; - await Self.app.models.ClientLog.create(logRecord); + const isClient = await Self.app.models.Client.count({id: oldData.id}); + if (isClient) { + const loopBackContext = LoopBackContext.getCurrentContext(); + const userId = loopBackContext.active.accessToken.userId; + const logRecord = { + originFk: oldData.id, + userFk: userId, + action: 'update', + changedModel: 'Account', + oldInstance: {name: oldData.name, active: oldData.active}, + newInstance: {name: changes.name, active: changes.active} + }; + await Self.app.models.ClientLog.create(logRecord); + } } }); }); diff --git a/modules/client/front/web-access/index.html b/modules/client/front/web-access/index.html index 610497994..c807489d6 100644 --- a/modules/client/front/web-access/index.html +++ b/modules/client/front/web-access/index.html @@ -1,11 +1,11 @@ -
+ { + this.$http.patch(`Clients/${this.client.id}/setPassword`, data).then(() => { this.vnApp.showSuccess(this.$t('Data saved!')); }); } catch (e) { @@ -59,6 +59,17 @@ export default class Controller extends Section { return true; } + + onSubmit() { + const data = { + name: this.account.name, + isActive: this.account.isActive, + }; + + this.$http.patch(`Clients/${this.client.id}/updateUser`, data).then(() => { + this.vnApp.showSuccess(this.$t('Data saved!')); + }); + } } Controller.$inject = ['$element', '$scope']; diff --git a/modules/client/front/web-access/index.spec.js b/modules/client/front/web-access/index.spec.js index 00fa12781..c1bb47a8e 100644 --- a/modules/client/front/web-access/index.spec.js +++ b/modules/client/front/web-access/index.spec.js @@ -52,7 +52,7 @@ describe('Component VnClientWebAccess', () => { }); describe('checkConditions()', () => { - it(`should perform a query to check if the client is valid and then store a boolean into the controller`, () => { + it('should perform a query to check if the client is valid', () => { controller.client = {id: '1234'}; expect(controller.canEnableCheckBox).toBeTruthy(); @@ -82,7 +82,9 @@ describe('Component VnClientWebAccess', () => { controller.newPassword = 'm24x8'; controller.repeatPassword = 'm24x8'; controller.canChangePassword = true; - $httpBackend.expectPATCH('Accounts/1234', {password: 'm24x8'}).respond('done'); + + const query = `Clients/${controller.client.id}/setPassword`; + $httpBackend.expectPATCH(query, {newPassword: controller.newPassword}).respond('done'); controller.onPassChange(); $httpBackend.flush(); }); From 5dd91a0be9bd812378dd57ba6420881c2f12727e Mon Sep 17 00:00:00 2001 From: carlosjr Date: Thu, 16 Jun 2022 12:08:58 +0200 Subject: [PATCH 09/13] excluded web access e2e path for another task to fix it. --- e2e/paths/02-client/07_edit_web_access.spec.js | 1 + 1 file changed, 1 insertion(+) diff --git a/e2e/paths/02-client/07_edit_web_access.spec.js b/e2e/paths/02-client/07_edit_web_access.spec.js index bcd476f6b..241430b06 100644 --- a/e2e/paths/02-client/07_edit_web_access.spec.js +++ b/e2e/paths/02-client/07_edit_web_access.spec.js @@ -2,6 +2,7 @@ import selectors from '../../helpers/selectors'; import getBrowser from '../../helpers/puppeteer'; describe('Client Edit web access path', () => { + panding('#4170 e2e account descriptor'); let browser; let page; beforeAll(async() => { From 869c9caf98accffb53d8786551842d1181367808 Mon Sep 17 00:00:00 2001 From: carlosjr Date: Thu, 16 Jun 2022 14:53:35 +0200 Subject: [PATCH 10/13] corrected a typo --- e2e/paths/02-client/07_edit_web_access.spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/e2e/paths/02-client/07_edit_web_access.spec.js b/e2e/paths/02-client/07_edit_web_access.spec.js index 241430b06..ad7c84a3e 100644 --- a/e2e/paths/02-client/07_edit_web_access.spec.js +++ b/e2e/paths/02-client/07_edit_web_access.spec.js @@ -2,7 +2,7 @@ import selectors from '../../helpers/selectors'; import getBrowser from '../../helpers/puppeteer'; describe('Client Edit web access path', () => { - panding('#4170 e2e account descriptor'); + pending('#4170 e2e account descriptor'); let browser; let page; beforeAll(async() => { From e151e35f7e8a0d92a0827a5cf0aa12db75c8addb Mon Sep 17 00:00:00 2001 From: carlosjr Date: Thu, 16 Jun 2022 16:25:21 +0200 Subject: [PATCH 11/13] replaced isActive by active as per it's model and updated original data in controller --- .../back/methods/client/specs/updateUser.spec.js | 11 +++++++---- modules/client/back/methods/client/updateUser.js | 10 +++------- modules/client/front/web-access/index.js | 6 +++--- 3 files changed, 13 insertions(+), 14 deletions(-) diff --git a/modules/client/back/methods/client/specs/updateUser.spec.js b/modules/client/back/methods/client/specs/updateUser.spec.js index 49acfda97..4dc969906 100644 --- a/modules/client/back/methods/client/specs/updateUser.spec.js +++ b/modules/client/back/methods/client/specs/updateUser.spec.js @@ -10,7 +10,10 @@ describe('Client updateUser', () => { } } }; - const ctx = {req: {accessToken: {userId: employeeId}}}; + const ctx = { + req: {accessToken: {userId: employeeId}}, + args: {name: 'test', active: true} + }; beforeEach(() => { spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({ @@ -21,7 +24,8 @@ describe('Client updateUser', () => { it('should throw an error the target user is not just a client but a worker', async() => { let error; try { - await models.Client.updateUser(ctx, 1106, 'test', true); + const clientID = 1106; + await models.Client.updateUser(ctx, clientID); } catch (e) { error = e; } @@ -38,8 +42,7 @@ describe('Client updateUser', () => { const options = {transaction: tx}; const clientID = 1105; - - await models.Client.updateUser(ctx, clientID, 'test', true, options); + await models.Client.updateUser(ctx, clientID, options); const client = await models.Account.findById(clientID, null, options); expect(client.name).toEqual('test'); diff --git a/modules/client/back/methods/client/updateUser.js b/modules/client/back/methods/client/updateUser.js index 26fcd6026..dd5b9f9fe 100644 --- a/modules/client/back/methods/client/updateUser.js +++ b/modules/client/back/methods/client/updateUser.js @@ -14,7 +14,7 @@ module.exports = Self => { description: 'the user name' }, { - arg: 'isActive', + arg: 'active', type: 'boolean', description: 'whether the user is active or not' }, @@ -25,7 +25,7 @@ module.exports = Self => { } }); - Self.updateUser = async function(ctx, id, name, isActive, options) { + Self.updateUser = async function(ctx, id, options) { const models = Self.app.models; let tx; const myOptions = {}; @@ -45,11 +45,7 @@ module.exports = Self => { const user = await models.Account.findById(id, null, myOptions); - const data = {}; - if (name) data.name = name; - if (isActive != undefined) data.active = isActive; - - await user.updateAttributes(data, myOptions); + await user.updateAttributes(ctx.args, myOptions); if (tx) await tx.commit(); } catch (e) { diff --git a/modules/client/front/web-access/index.js b/modules/client/front/web-access/index.js index eb72ecab3..71f876284 100644 --- a/modules/client/front/web-access/index.js +++ b/modules/client/front/web-access/index.js @@ -63,11 +63,11 @@ export default class Controller extends Section { onSubmit() { const data = { name: this.account.name, - isActive: this.account.isActive, + active: this.account.active }; - this.$http.patch(`Clients/${this.client.id}/updateUser`, data).then(() => { - this.vnApp.showSuccess(this.$t('Data saved!')); + this.$.watcher.notifySaved(); + this.$.watcher.updateOriginalData(); }); } } From 9e70b8c5fda291c98bcfb6cbbe5b4adda24bc995 Mon Sep 17 00:00:00 2001 From: carlosjr Date: Fri, 17 Jun 2022 09:28:54 +0200 Subject: [PATCH 12/13] web access user changed to a non-worker --- .../02-client/07_edit_web_access.spec.js | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/e2e/paths/02-client/07_edit_web_access.spec.js b/e2e/paths/02-client/07_edit_web_access.spec.js index ad7c84a3e..70ec4b5ea 100644 --- a/e2e/paths/02-client/07_edit_web_access.spec.js +++ b/e2e/paths/02-client/07_edit_web_access.spec.js @@ -2,14 +2,13 @@ import selectors from '../../helpers/selectors'; import getBrowser from '../../helpers/puppeteer'; describe('Client Edit web access path', () => { - pending('#4170 e2e account descriptor'); let browser; let page; beforeAll(async() => { browser = await getBrowser(); page = browser.page; await page.loginAndModule('employee', 'client'); - await page.accessToSearchResult('Bruce Banner'); + await page.accessToSearchResult('1105'); await page.accessToSection('client.card.webAccess'); }); @@ -27,7 +26,7 @@ describe('Client Edit web access path', () => { it(`should update the name`, async() => { await page.clearInput(selectors.clientWebAccess.userName); - await page.write(selectors.clientWebAccess.userName, 'Hulk'); + await page.write(selectors.clientWebAccess.userName, 'Legion'); await page.waitToClick(selectors.clientWebAccess.saveButton); const message = await page.waitForSnackbar(); @@ -44,30 +43,30 @@ describe('Client Edit web access path', () => { it('should confirm web access name have been updated', async() => { const result = await page.waitToGetProperty(selectors.clientWebAccess.userName, 'value'); - expect(result).toEqual('Hulk'); + expect(result).toEqual('Legion'); }); it(`should navigate to the log section`, async() => { await page.accessToSection('client.card.log'); }); - it(`should confirm the last log is showing the updated client name and no modifications on the active checkbox`, async() => { + it(`should confirm the last log shows the updated client name and no modifications on active checkbox`, async() => { let lastModificationPreviousValue = await page .waitToGetProperty(selectors.clientLog.lastModificationPreviousValue, 'innerText'); let lastModificationCurrentValue = await page .waitToGetProperty(selectors.clientLog.lastModificationCurrentValue, 'innerText'); - expect(lastModificationPreviousValue).toEqual('name BruceBanner active false'); - expect(lastModificationCurrentValue).toEqual('name Hulk active false'); + expect(lastModificationPreviousValue).toEqual('name MaxEisenhardt active false'); + expect(lastModificationCurrentValue).toEqual('name Legion active false'); }); - it(`should confirm the penultimate log is showing the updated avtive field and no modifications on the client name`, async() => { + it(`should confirm the penultimate log shows the updated active and no modifications on client name`, async() => { let penultimateModificationPreviousValue = await page .waitToGetProperty(selectors.clientLog.penultimateModificationPreviousValue, 'innerText'); let penultimateModificationCurrentValue = await page .waitToGetProperty(selectors.clientLog.penultimateModificationCurrentValue, 'innerText'); - expect(penultimateModificationPreviousValue).toEqual('name BruceBanner active true'); - expect(penultimateModificationCurrentValue).toEqual('name BruceBanner active false'); + expect(penultimateModificationPreviousValue).toEqual('name MaxEisenhardt active true'); + expect(penultimateModificationCurrentValue).toEqual('name MaxEisenhardt active false'); }); }); From e775c67b1b9435fabd833d615ea58452ad823b2a Mon Sep 17 00:00:00 2001 From: alexm Date: Fri, 17 Jun 2022 09:44:59 +0200 Subject: [PATCH 13/13] rename --- db/changes/{10480-june => 10470-family}/00-creditInsurance.sql | 0 .../{10480-june => 10470-family}/01-creditInsuranceTriggers.sql | 0 db/changes/{10481-june => 10480-june}/00-ACL.sql | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename db/changes/{10480-june => 10470-family}/00-creditInsurance.sql (100%) rename db/changes/{10480-june => 10470-family}/01-creditInsuranceTriggers.sql (100%) rename db/changes/{10481-june => 10480-june}/00-ACL.sql (100%) diff --git a/db/changes/10480-june/00-creditInsurance.sql b/db/changes/10470-family/00-creditInsurance.sql similarity index 100% rename from db/changes/10480-june/00-creditInsurance.sql rename to db/changes/10470-family/00-creditInsurance.sql diff --git a/db/changes/10480-june/01-creditInsuranceTriggers.sql b/db/changes/10470-family/01-creditInsuranceTriggers.sql similarity index 100% rename from db/changes/10480-june/01-creditInsuranceTriggers.sql rename to db/changes/10470-family/01-creditInsuranceTriggers.sql diff --git a/db/changes/10481-june/00-ACL.sql b/db/changes/10480-june/00-ACL.sql similarity index 100% rename from db/changes/10481-june/00-ACL.sql rename to db/changes/10480-june/00-ACL.sql