From d2120cdc3d772e49346a4855827b8ff102efbeee Mon Sep 17 00:00:00 2001 From: alexm Date: Mon, 17 Jul 2023 14:24:50 +0200 Subject: [PATCH 01/10] refs #5762 feat: multiplatform recover-password and change-password --- back/methods/vn-user/recover-password.js | 9 +++++++-- back/methods/vn-user/sign-in.js | 10 ++-------- back/models/vn-user.js | 11 +++++++---- front/salix/components/change-password/index.js | 14 +++----------- front/salix/components/login/index.js | 2 +- front/salix/routes.js | 2 +- .../back/methods/account/change-password.js | 13 +++++++------ .../methods/account/specs/change-password.spec.js | 14 +++++++------- 8 files changed, 35 insertions(+), 40 deletions(-) diff --git a/back/methods/vn-user/recover-password.js b/back/methods/vn-user/recover-password.js index b87bb14d46..b5d183ba39 100644 --- a/back/methods/vn-user/recover-password.js +++ b/back/methods/vn-user/recover-password.js @@ -7,6 +7,11 @@ module.exports = Self => { type: 'string', description: 'The user name or email', required: true + }, + { + arg: 'directory', + type: 'string', + description: 'The directory for mail' } ], http: { @@ -15,7 +20,7 @@ module.exports = Self => { } }); - Self.recoverPassword = async function(user) { + Self.recoverPassword = async function(user, directory) { const models = Self.app.models; const usesEmail = user.indexOf('@') !== -1; @@ -29,7 +34,7 @@ module.exports = Self => { } try { - await Self.resetPassword({email: user, emailTemplate: 'recover-password'}); + await Self.resetPassword({email: user, emailTemplate: 'recover-password', directory}); } catch (err) { if (err.code === 'EMAIL_NOT_FOUND') return; diff --git a/back/methods/vn-user/sign-in.js b/back/methods/vn-user/sign-in.js index 73cc705de0..b9e0d2f705 100644 --- a/back/methods/vn-user/sign-in.js +++ b/back/methods/vn-user/sign-in.js @@ -53,19 +53,13 @@ module.exports = Self => { return Self.validateLogin(user, password); }; - Self.passExpired = async(vnUser, myOptions) => { + Self.passExpired = async vnUser => { const today = Date.vnNew(); today.setHours(0, 0, 0, 0); if (vnUser.passExpired && vnUser.passExpired.getTime() <= today.getTime()) { - const $ = Self.app.models; - const changePasswordToken = await $.AccessToken.create({ - scopes: ['changePassword'], - userId: vnUser.id - }, myOptions); const err = new UserError('Pass expired', 'passExpired'); - changePasswordToken.twoFactor = vnUser.twoFactor ? true : false; - err.details = {token: changePasswordToken}; + err.details = {userId: vnUser.id, twoFactor: vnUser.twoFactor ? true : false}; throw err; } }; diff --git a/back/models/vn-user.js b/back/models/vn-user.js index 11d4bf250d..f47dc47e28 100644 --- a/back/models/vn-user.js +++ b/back/models/vn-user.js @@ -99,10 +99,13 @@ module.exports = function(Self) { const origin = headers.origin; const user = await Self.app.models.VnUser.findById(info.user.id); + let directory = info.options?.directory ?? '/#!/reset-password?access_token=$token$'; + directory = directory.replace('$token$', info.accessToken.id); + const params = { recipient: info.email, lang: user.lang, - url: `${origin}/#!/reset-password?access_token=${info.accessToken.id}` + url: origin + directory }; const options = Object.assign({}, info.options); @@ -158,9 +161,9 @@ module.exports = function(Self) { } }; - Self.sharedClass._methods.find(method => method.name == 'changePassword').ctor.settings.acls = - Self.sharedClass._methods.find(method => method.name == 'changePassword').ctor.settings.acls - .filter(acl => acl.property != 'changePassword'); + // Self.sharedClass._methods.find(method => method.name == 'changePassword').ctor.settings.acls = + // Self.sharedClass._methods.find(method => method.name == 'changePassword').ctor.settings.acls + // .filter(acl => acl.property != 'changePassword'); // FIXME: https://redmine.verdnatura.es/issues/5761 // Self.afterRemote('prototype.patchAttributes', async(ctx, instance) => { diff --git a/front/salix/components/change-password/index.js b/front/salix/components/change-password/index.js index 797d4dc963..7e30bf54ed 100644 --- a/front/salix/components/change-password/index.js +++ b/front/salix/components/change-password/index.js @@ -15,9 +15,6 @@ export default class Controller { } $onInit() { - if (!this.$state.params.id) - this.$state.go('login'); - this.$http.get('UserPasswords/findOne') .then(res => { this.passRequirements = res.data; @@ -25,7 +22,7 @@ export default class Controller { } submit() { - const userId = this.$state.params.userId; + const userId = parseInt(this.$state.params.userId); const oldPassword = this.oldPassword; const newPassword = this.newPassword; const repeatPassword = this.repeatPassword; @@ -36,18 +33,13 @@ export default class Controller { if (newPassword != this.repeatPassword) throw new UserError(`Passwords don't match`); - const headers = { - Authorization: this.$state.params.id - }; - this.$http.patch('Accounts/change-password', { - id: userId, + userId, oldPassword, newPassword, code - }, - {headers} + } ).then(() => { this.vnApp.showSuccess(this.$translate.instant('Password updated!')); this.$state.go('login'); diff --git a/front/salix/components/login/index.js b/front/salix/components/login/index.js index be4fb39267..7d8cd20493 100644 --- a/front/salix/components/login/index.js +++ b/front/salix/components/login/index.js @@ -36,7 +36,7 @@ export default class Controller { const err = req.data?.error; if (err?.code == 'passExpired') - this.$state.go('change-password', err.details.token); + this.$state.go('change-password', err.details); this.loading = false; this.password = ''; diff --git a/front/salix/routes.js b/front/salix/routes.js index 5a2c030bc1..8621f83c76 100644 --- a/front/salix/routes.js +++ b/front/salix/routes.js @@ -45,7 +45,7 @@ function config($stateProvider, $urlRouterProvider) { }) .state('change-password', { parent: 'outLayout', - url: '/change-password?id&userId&twoFactor', + url: '/change-password?userId&twoFactor', description: 'Change password', template: '' }) diff --git a/modules/account/back/methods/account/change-password.js b/modules/account/back/methods/account/change-password.js index a739f37d00..49af93110c 100644 --- a/modules/account/back/methods/account/change-password.js +++ b/modules/account/back/methods/account/change-password.js @@ -1,12 +1,15 @@ const UserError = require('vn-loopback/util/user-error'); module.exports = Self => { - Self.remoteMethodCtx('changePassword', { + Self.remoteMethod('changePassword', { description: 'Changes the user password', - accessType: 'WRITE', - accessScopes: ['changePassword'], accepts: [ { + arg: 'userId', + type: 'integer', + description: 'The user id', + required: true + }, { arg: 'oldPassword', type: 'string', description: 'The old password', @@ -28,9 +31,7 @@ module.exports = Self => { } }); - Self.changePassword = async function(ctx, oldPassword, newPassword, code, options) { - const userId = ctx.req.accessToken.userId; - + Self.changePassword = async function(userId, oldPassword, newPassword, code, options) { const myOptions = {}; if (typeof options == 'object') Object.assign(myOptions, options); diff --git a/modules/account/back/methods/account/specs/change-password.spec.js b/modules/account/back/methods/account/specs/change-password.spec.js index 045f984931..2fa3010afb 100644 --- a/modules/account/back/methods/account/specs/change-password.spec.js +++ b/modules/account/back/methods/account/specs/change-password.spec.js @@ -1,7 +1,7 @@ const {models} = require('vn-loopback/server/server'); describe('account changePassword()', () => { - const ctx = {req: {accessToken: {userId: 70}}}; + const userId = 70; const unauthCtx = { req: { headers: {}, @@ -20,7 +20,7 @@ describe('account changePassword()', () => { try { const options = {transaction: tx}; - await models.Account.changePassword(ctx, 'wrongPassword', 'nightmare.9999', null, options); + await models.Account.changePassword(userId, 'wrongPassword', 'nightmare.9999', null, options); await tx.rollback(); } catch (e) { await tx.rollback(); @@ -37,8 +37,8 @@ describe('account changePassword()', () => { try { const options = {transaction: tx}; - await models.Account.changePassword(ctx, 'nightmare', 'nightmare.9999', null, options); - await models.Account.changePassword(ctx, 'nightmare.9999', 'nightmare.9999', null, options); + await models.Account.changePassword(userId, 'nightmare', 'nightmare.9999', null, options); + await models.Account.changePassword(userId, 'nightmare.9999', 'nightmare.9999', null, options); await tx.rollback(); } catch (e) { await tx.rollback(); @@ -54,7 +54,7 @@ describe('account changePassword()', () => { try { const options = {transaction: tx}; - await models.Account.changePassword(ctx, 'nightmare', 'nightmare.9999', null, options); + await models.Account.changePassword(userId, 'nightmare', 'nightmare.9999', null, options); await tx.rollback(); } catch (e) { await tx.rollback(); @@ -86,8 +86,8 @@ describe('account changePassword()', () => { } try { - const authCode = await models.AuthCode.findOne({where: {userFk: 70}}, options); - await models.Account.changePassword(ctx, 'nightmare', 'nightmare.9999', authCode.code, options); + const authCode = await models.AuthCode.findOne({where: {userFk: userId}}, options); + await models.Account.changePassword(userId, 'nightmare', 'nightmare.9999', authCode.code, options); await tx.rollback(); } catch (e) { await tx.rollback(); From 125d908c5d5395a5ed48900cae4ba062ce17b739 Mon Sep 17 00:00:00 2001 From: alexm Date: Mon, 17 Jul 2023 14:41:15 +0200 Subject: [PATCH 02/10] refs #5762 uncomment --- back/models/vn-user.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/back/models/vn-user.js b/back/models/vn-user.js index f47dc47e28..163649718e 100644 --- a/back/models/vn-user.js +++ b/back/models/vn-user.js @@ -161,9 +161,9 @@ module.exports = function(Self) { } }; - // Self.sharedClass._methods.find(method => method.name == 'changePassword').ctor.settings.acls = - // Self.sharedClass._methods.find(method => method.name == 'changePassword').ctor.settings.acls - // .filter(acl => acl.property != 'changePassword'); + Self.sharedClass._methods.find(method => method.name == 'changePassword').ctor.settings.acls = + Self.sharedClass._methods.find(method => method.name == 'changePassword').ctor.settings.acls + .filter(acl => acl.property != 'changePassword'); // FIXME: https://redmine.verdnatura.es/issues/5761 // Self.afterRemote('prototype.patchAttributes', async(ctx, instance) => { From 15dee8bef442e17c56375e382c6c5d6ba5f19316 Mon Sep 17 00:00:00 2001 From: alexm Date: Mon, 17 Jul 2023 15:19:36 +0200 Subject: [PATCH 03/10] refs #5976 refactor: transaferSale call setDeleted --- db/changes/233001/00-setDeleted_acl.sql | 6 ++++++ .../ticket/back/methods/ticket/specs/transferSales.spec.js | 2 ++ modules/ticket/back/methods/ticket/transferSales.js | 7 ++----- 3 files changed, 10 insertions(+), 5 deletions(-) create mode 100644 db/changes/233001/00-setDeleted_acl.sql diff --git a/db/changes/233001/00-setDeleted_acl.sql b/db/changes/233001/00-setDeleted_acl.sql new file mode 100644 index 0000000000..1030965dd4 --- /dev/null +++ b/db/changes/233001/00-setDeleted_acl.sql @@ -0,0 +1,6 @@ +UPDATE `salix`.`ACL` + SET principalId='salesperson' + WHERE + model='Ticket' + AND property='setDeleted' + AND accessType='WRITE'; diff --git a/modules/ticket/back/methods/ticket/specs/transferSales.spec.js b/modules/ticket/back/methods/ticket/specs/transferSales.spec.js index 5626889178..61c788b646 100644 --- a/modules/ticket/back/methods/ticket/specs/transferSales.spec.js +++ b/modules/ticket/back/methods/ticket/specs/transferSales.spec.js @@ -5,6 +5,8 @@ describe('sale transferSales()', () => { const userId = 1101; const activeCtx = { accessToken: {userId: userId}, + headers: {origin: ''}, + __: value => value }; const ctx = {req: activeCtx}; diff --git a/modules/ticket/back/methods/ticket/transferSales.js b/modules/ticket/back/methods/ticket/transferSales.js index 0eee50d5fc..00fc02f381 100644 --- a/modules/ticket/back/methods/ticket/transferSales.js +++ b/modules/ticket/back/methods/ticket/transferSales.js @@ -96,11 +96,8 @@ module.exports = Self => { } const isTicketEmpty = await models.Ticket.isEmpty(id, myOptions); - if (isTicketEmpty) { - await originalTicket.updateAttributes({ - isDeleted: true - }, myOptions); - } + if (isTicketEmpty) + await models.Ticket.setDeleted(ctx, id, myOptions); if (tx) await tx.commit(); From f07ac89cb6ea7b68033b702a36e13b2b2ec5d32a Mon Sep 17 00:00:00 2001 From: alexm Date: Tue, 18 Jul 2023 15:01:04 +0200 Subject: [PATCH 04/10] refs #5976 add custom error --- loopback/locale/es.json | 3 ++- .../ticket/back/methods/ticket/setDeleted.js | 4 +-- .../back/methods/ticket/transferSales.js | 27 +++++++++++++++---- 3 files changed, 26 insertions(+), 8 deletions(-) diff --git a/loopback/locale/es.json b/loopback/locale/es.json index 784ff5e6e2..16b0af7f56 100644 --- a/loopback/locale/es.json +++ b/loopback/locale/es.json @@ -305,5 +305,6 @@ "The renew period has not been exceeded": "El periodo de renovación no ha sido superado", "Valid priorities": "Prioridades válidas: %d", "Negative basis of tickets": "Base negativa para los tickets: {{ticketsIds}}", - "You cannot assign an alias that you are not assigned to": "No puede asignar un alias que no tenga asignado" + "You cannot assign an alias that you are not assigned to": "No puede asignar un alias que no tenga asignado", + "This ticket cannot be left empty.": "Este ticket no se puede dejar vacío. %d" } diff --git a/modules/ticket/back/methods/ticket/setDeleted.js b/modules/ticket/back/methods/ticket/setDeleted.js index 878cce0561..46c0add6b2 100644 --- a/modules/ticket/back/methods/ticket/setDeleted.js +++ b/modules/ticket/back/methods/ticket/setDeleted.js @@ -41,8 +41,8 @@ module.exports = Self => { const isEditable = await Self.isEditable(ctx, id, myOptions); - if (!isEditable) - throw new UserError(`The sales of this ticket can't be modified`); + throw new UserError(`The sales of this ticket can't be modified`); + // if (!isEditable) // Check if ticket has refunds const ticketRefunds = await models.TicketRefund.find({ diff --git a/modules/ticket/back/methods/ticket/transferSales.js b/modules/ticket/back/methods/ticket/transferSales.js index 00fc02f381..2e4bf023d4 100644 --- a/modules/ticket/back/methods/ticket/transferSales.js +++ b/modules/ticket/back/methods/ticket/transferSales.js @@ -37,6 +37,7 @@ module.exports = Self => { const userId = ctx.req.accessToken.userId; const models = Self.app.models; const myOptions = {userId}; + const $t = ctx.req.__; // $translate let tx; if (typeof options == 'object') @@ -78,9 +79,9 @@ module.exports = Self => { const saleIds = sales.map(sale => sale.id); - const hasClaimedSales = await models.ClaimBeginning.findOne({where: {saleFk: {inq: saleIds}}}); - if (ticketId != id && hasClaimedSales) - throw new UserError(`Can't transfer claimed sales`); + // const hasClaimedSales = await models.ClaimBeginning.findOne({where: {saleFk: {inq: saleIds}}}); + // if (ticketId != id && hasClaimedSales) + // throw new UserError(`Can't transfer claimed sales`); for (const sale of sales) { const originalSale = map.get(sale.id); @@ -96,14 +97,30 @@ module.exports = Self => { } const isTicketEmpty = await models.Ticket.isEmpty(id, myOptions); - if (isTicketEmpty) - await models.Ticket.setDeleted(ctx, id, myOptions); + if (isTicketEmpty) { + try { + await models.Ticket.setDeleted(ctx, id, myOptions); + } catch (e) { + console.log('e:', e); + console.log('e.message:', e.message); + console.log('e translation:', $t(e.message, {})); + if (e.statusCode === 400) { + throw new UserError( + `This ticket cannot be left empty.`, + 'TRANSFER_SET_DELETED', + $t(e.message) + ); + } + throw e; + } + } if (tx) await tx.commit(); return {id: ticketId}; } catch (e) { if (tx) await tx.rollback(); + console.log('e.UserError:', e); throw e; } }; From 2c79056f3464b4f526a72143567f948e7e4a831f Mon Sep 17 00:00:00 2001 From: alexm Date: Wed, 19 Jul 2023 13:44:04 +0200 Subject: [PATCH 05/10] refs #5976 error extended --- loopback/locale/en.json | 3 ++- loopback/locale/es.json | 2 +- modules/route/front/roadmap/index/index.js | 2 -- modules/ticket/back/methods/ticket/setDeleted.js | 4 ++-- modules/ticket/back/methods/ticket/transferSales.js | 12 ++++-------- 5 files changed, 9 insertions(+), 14 deletions(-) diff --git a/loopback/locale/en.json b/loopback/locale/en.json index 030afbe9e3..dde24ddc6d 100644 --- a/loopback/locale/en.json +++ b/loopback/locale/en.json @@ -178,5 +178,6 @@ "The renew period has not been exceeded": "The renew period has not been exceeded", "You can not use the same password": "You can not use the same password", "Valid priorities": "Valid priorities: %d", - "Negative basis of tickets": "Negative basis of tickets: {{ticketsIds}}" + "Negative basis of tickets": "Negative basis of tickets: {{ticketsIds}}", + "This ticket cannot be left empty.": "This ticket cannot be left empty. %s" } diff --git a/loopback/locale/es.json b/loopback/locale/es.json index 16b0af7f56..c12b980fa1 100644 --- a/loopback/locale/es.json +++ b/loopback/locale/es.json @@ -306,5 +306,5 @@ "Valid priorities": "Prioridades válidas: %d", "Negative basis of tickets": "Base negativa para los tickets: {{ticketsIds}}", "You cannot assign an alias that you are not assigned to": "No puede asignar un alias que no tenga asignado", - "This ticket cannot be left empty.": "Este ticket no se puede dejar vacío. %d" + "This ticket cannot be left empty.": "Este ticket no se puede dejar vacío. %s" } diff --git a/modules/route/front/roadmap/index/index.js b/modules/route/front/roadmap/index/index.js index 3ffc5b4b1b..c5f5ef9d1c 100644 --- a/modules/route/front/roadmap/index/index.js +++ b/modules/route/front/roadmap/index/index.js @@ -46,8 +46,6 @@ class Controller extends Section { } deleteRoadmaps() { - console.log(this.checked); - for (const roadmap of this.checked) { this.$http.delete(`Roadmaps/${roadmap.id}`) .then(() => this.$.model.refresh()) diff --git a/modules/ticket/back/methods/ticket/setDeleted.js b/modules/ticket/back/methods/ticket/setDeleted.js index 46c0add6b2..878cce0561 100644 --- a/modules/ticket/back/methods/ticket/setDeleted.js +++ b/modules/ticket/back/methods/ticket/setDeleted.js @@ -41,8 +41,8 @@ module.exports = Self => { const isEditable = await Self.isEditable(ctx, id, myOptions); - throw new UserError(`The sales of this ticket can't be modified`); - // if (!isEditable) + if (!isEditable) + throw new UserError(`The sales of this ticket can't be modified`); // Check if ticket has refunds const ticketRefunds = await models.TicketRefund.find({ diff --git a/modules/ticket/back/methods/ticket/transferSales.js b/modules/ticket/back/methods/ticket/transferSales.js index 2e4bf023d4..de52e2f188 100644 --- a/modules/ticket/back/methods/ticket/transferSales.js +++ b/modules/ticket/back/methods/ticket/transferSales.js @@ -79,9 +79,9 @@ module.exports = Self => { const saleIds = sales.map(sale => sale.id); - // const hasClaimedSales = await models.ClaimBeginning.findOne({where: {saleFk: {inq: saleIds}}}); - // if (ticketId != id && hasClaimedSales) - // throw new UserError(`Can't transfer claimed sales`); + const hasClaimedSales = await models.ClaimBeginning.findOne({where: {saleFk: {inq: saleIds}}}); + if (ticketId != id && hasClaimedSales) + throw new UserError(`Can't transfer claimed sales`); for (const sale of sales) { const originalSale = map.get(sale.id); @@ -101,14 +101,11 @@ module.exports = Self => { try { await models.Ticket.setDeleted(ctx, id, myOptions); } catch (e) { - console.log('e:', e); - console.log('e.message:', e.message); - console.log('e translation:', $t(e.message, {})); if (e.statusCode === 400) { throw new UserError( `This ticket cannot be left empty.`, 'TRANSFER_SET_DELETED', - $t(e.message) + $t(e.message, ...e.translateArgs) ); } throw e; @@ -120,7 +117,6 @@ module.exports = Self => { return {id: ticketId}; } catch (e) { if (tx) await tx.rollback(); - console.log('e.UserError:', e); throw e; } }; From b188ae6f570d406cf01664dc9e98706f2ae3c1f1 Mon Sep 17 00:00:00 2001 From: alexm Date: Wed, 19 Jul 2023 14:14:35 +0200 Subject: [PATCH 06/10] refs #5976 fix: e2e --- db/changes/233001/00-setDeleted_acl.sql | 2 +- e2e/paths/05-ticket/14_create_ticket.spec.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/db/changes/233001/00-setDeleted_acl.sql b/db/changes/233001/00-setDeleted_acl.sql index 1030965dd4..cdeff95228 100644 --- a/db/changes/233001/00-setDeleted_acl.sql +++ b/db/changes/233001/00-setDeleted_acl.sql @@ -1,5 +1,5 @@ UPDATE `salix`.`ACL` - SET principalId='salesperson' + SET principalId='salesPerson' WHERE model='Ticket' AND property='setDeleted' diff --git a/e2e/paths/05-ticket/14_create_ticket.spec.js b/e2e/paths/05-ticket/14_create_ticket.spec.js index 80c288a01b..1f9c0c40a3 100644 --- a/e2e/paths/05-ticket/14_create_ticket.spec.js +++ b/e2e/paths/05-ticket/14_create_ticket.spec.js @@ -10,7 +10,7 @@ describe('Ticket create path', () => { beforeAll(async() => { browser = await getBrowser(); page = browser.page; - await page.loginAndModule('employee', 'ticket'); + await page.loginAndModule('salesPerson', 'ticket'); }); afterAll(async() => { From 3e8bb221e036e66add3b0b09a107d489ec0ad526 Mon Sep 17 00:00:00 2001 From: Juan Ferrer Toribio Date: Wed, 2 Aug 2023 09:29:09 +0200 Subject: [PATCH 07/10] refs #5762 Securify fix for recovery url --- back/models/vn-user.js | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/back/models/vn-user.js b/back/models/vn-user.js index 163649718e..3e4a08b6e3 100644 --- a/back/models/vn-user.js +++ b/back/models/vn-user.js @@ -98,14 +98,22 @@ module.exports = function(Self) { const headers = httpRequest.headers; const origin = headers.origin; + const defaultHash = '/reset-password?access_token=$token$'; + const recoverHashes = { + hedera: 'verificationToken=$token$' + }; + + // FIXME: Change with: info.options?.app + const app = info.options?.directory; + let recoverHash = app ? recoverHashes[app] : defaultHash; + recoverHash = recoverHash.replace('$token$', info.accessToken.id); + const user = await Self.app.models.VnUser.findById(info.user.id); - let directory = info.options?.directory ?? '/#!/reset-password?access_token=$token$'; - directory = directory.replace('$token$', info.accessToken.id); const params = { recipient: info.email, lang: user.lang, - url: origin + directory + url: origin + '/#!' + recoverHash }; const options = Object.assign({}, info.options); From 4c199f66b2641d76c8154844551d07c98cf61fe3 Mon Sep 17 00:00:00 2001 From: alexm Date: Fri, 4 Aug 2023 14:33:38 +0200 Subject: [PATCH 08/10] refs #5762 refactor: recoverPassword use app param --- back/methods/vn-user/recover-password.js | 6 +++--- back/models/vn-user.js | 3 +-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/back/methods/vn-user/recover-password.js b/back/methods/vn-user/recover-password.js index b5d183ba39..b0f7122b43 100644 --- a/back/methods/vn-user/recover-password.js +++ b/back/methods/vn-user/recover-password.js @@ -9,7 +9,7 @@ module.exports = Self => { required: true }, { - arg: 'directory', + arg: 'app', type: 'string', description: 'The directory for mail' } @@ -20,7 +20,7 @@ module.exports = Self => { } }); - Self.recoverPassword = async function(user, directory) { + Self.recoverPassword = async function(user, app) { const models = Self.app.models; const usesEmail = user.indexOf('@') !== -1; @@ -34,7 +34,7 @@ module.exports = Self => { } try { - await Self.resetPassword({email: user, emailTemplate: 'recover-password', directory}); + await Self.resetPassword({email: user, emailTemplate: 'recover-password', app}); } catch (err) { if (err.code === 'EMAIL_NOT_FOUND') return; diff --git a/back/models/vn-user.js b/back/models/vn-user.js index 7b919ec298..cf210b61b8 100644 --- a/back/models/vn-user.js +++ b/back/models/vn-user.js @@ -101,8 +101,7 @@ module.exports = function(Self) { hedera: 'verificationToken=$token$' }; - // FIXME: Change with: info.options?.app - const app = info.options?.directory; + const app = info.options?.app; let recoverHash = app ? recoverHashes[app] : defaultHash; recoverHash = recoverHash.replace('$token$', info.accessToken.id); From c5e853b028651db9c94d1467e479cae317c6e91d Mon Sep 17 00:00:00 2001 From: alexm Date: Tue, 8 Aug 2023 13:35:36 +0200 Subject: [PATCH 09/10] refs #5976 correct sql folder --- db/changes/{233001 => 233401}/00-setDeleted_acl.sql | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename db/changes/{233001 => 233401}/00-setDeleted_acl.sql (100%) diff --git a/db/changes/233001/00-setDeleted_acl.sql b/db/changes/233401/00-setDeleted_acl.sql similarity index 100% rename from db/changes/233001/00-setDeleted_acl.sql rename to db/changes/233401/00-setDeleted_acl.sql From afc0c980650db7633ad07477dd504dffd2d14d1b Mon Sep 17 00:00:00 2001 From: alexm Date: Thu, 10 Aug 2023 11:05:37 +0200 Subject: [PATCH 10/10] Merge branch 'test' of https://gitea.verdnatura.es/verdnatura/salix into dev --- CHANGELOG.md | 5 +- db/changes/233202/00-ticketSmsACL.sql | 3 + modules/client/front/sms/index.html | 4 +- .../back/methods/route/getExternalCmrs.js | 133 ++++++++++++++++++ modules/route/back/models/route.js | 1 + modules/ticket/front/index.js | 1 + modules/ticket/front/routes.json | 12 +- modules/ticket/front/sms/index.html | 2 + modules/ticket/front/sms/index.js | 21 +++ package-lock.json | 2 +- 10 files changed, 179 insertions(+), 5 deletions(-) create mode 100644 db/changes/233202/00-ticketSmsACL.sql create mode 100644 modules/route/back/methods/route/getExternalCmrs.js create mode 100644 modules/ticket/front/sms/index.html create mode 100644 modules/ticket/front/sms/index.js diff --git a/CHANGELOG.md b/CHANGELOG.md index 15fe58d7f1..1f35709327 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,17 +15,20 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed -## [2332.01] - 2023-08-09 +## [2332.01] - 2023-08-10 ### Added - (Trabajadores -> Gestión documental) Soporte para Docuware - (General -> Agencia) Soporte para Viaexpress +- (Tickets -> SMS) Nueva sección en Lilium ### Changed - (General -> Tickets) Devuelve el motivo por el cual no es editable - (Desplegables -> Trabajadores) Mejorados +- (General -> Clientes) Razón social y dirección en mayúsculas ### Fixed +- (Clientes -> SMS) Al pasar el ratón por encima muestra el mensaje completo ## [2330.01] - 2023-07-27 diff --git a/db/changes/233202/00-ticketSmsACL.sql b/db/changes/233202/00-ticketSmsACL.sql new file mode 100644 index 0000000000..a25a876f86 --- /dev/null +++ b/db/changes/233202/00-ticketSmsACL.sql @@ -0,0 +1,3 @@ +INSERT INTO `salix`.`ACL` (model, property, accessType, permission, principalType, principalId) + VALUES + ('TicketSms', 'find', 'READ', 'ALLOW', 'ROLE', 'salesPerson'); diff --git a/modules/client/front/sms/index.html b/modules/client/front/sms/index.html index 9abadd3128..e2bc0785e3 100644 --- a/modules/client/front/sms/index.html +++ b/modules/client/front/sms/index.html @@ -8,7 +8,7 @@ auto-load="true"> - + @@ -27,7 +27,7 @@ {{::clientSms.sms.destination}} - {{::clientSms.sms.message}} + {{::clientSms.sms.message}} {{::clientSms.sms.status}} {{::clientSms.sms.created | date:'dd/MM/yyyy HH:mm'}} diff --git a/modules/route/back/methods/route/getExternalCmrs.js b/modules/route/back/methods/route/getExternalCmrs.js new file mode 100644 index 0000000000..5b08cf34ae --- /dev/null +++ b/modules/route/back/methods/route/getExternalCmrs.js @@ -0,0 +1,133 @@ +const ParameterizedSQL = require('loopback-connector').ParameterizedSQL; +const buildFilter = require('vn-loopback/util/filter').buildFilter; +const mergeFilters = require('vn-loopback/util/filter').mergeFilters; + +module.exports = Self => { + Self.remoteMethod('getExternalCmrs', { + description: 'Returns an array of external cmrs', + accessType: 'READ', + accepts: [ + { + arg: 'filter', + type: 'object', + description: 'Filter defining where, order, offset, and limit - must be a JSON-encoded string', + }, + { + arg: 'cmrFk', + type: 'integer', + description: 'Searchs the route by id', + }, + { + arg: 'ticketFk', + type: 'integer', + description: 'The worker id', + }, + { + arg: 'country', + type: 'string', + description: 'The agencyMode id', + }, + { + arg: 'clientFk', + type: 'integer', + description: 'The vehicle id', + }, + { + arg: 'hasCmrDms', + type: 'boolean', + description: 'The vehicle id', + }, + { + arg: 'shipped', + type: 'date', + description: 'The to date filter', + }, + ], + returns: { + type: ['object'], + root: true + }, + http: { + path: `/getExternalCmrs`, + verb: 'GET' + } + }); + + Self.getExternalCmrs = async( + filter, + cmrFk, + ticketFk, + country, + clientFk, + hasCmrDms, + shipped, + options + ) => { + const params = { + cmrFk, + ticketFk, + country, + clientFk, + hasCmrDms, + shipped, + }; + const conn = Self.dataSource.connector; + + let where = buildFilter(params, (param, value) => {return {[param]: value}}); + filter = mergeFilters(filter, {where}); + + if (!filter.where) { + const yesterday = new Date(); + yesterday.setDate(yesterday.getDate() - 1); + filter.where = {'shipped': yesterday.toISOString().split('T')[0]} + } + + const myOptions = {}; + + if (typeof options == 'object') + Object.assign(myOptions, options); + + let stmts = []; + const stmt = new ParameterizedSQL(` + SELECT * + FROM ( + SELECT t.cmrFk, + t.id ticketFk, + co.country, + t.clientFk, + sub.id hasCmrDms, + DATE(t.shipped) shipped + FROM ticket t + JOIN ticketState ts ON ts.ticketFk = t.id + JOIN state s ON s.id = ts.stateFk + JOIN alertLevel al ON al.id = s.alertLevel + JOIN client c ON c.id = t.clientFk + JOIN address a ON a.id = t.addressFk + JOIN province p ON p.id = a.provinceFk + JOIN country co ON co.id = p.countryFk + JOIN agencyMode am ON am.id = t.agencyModeFk + JOIN deliveryMethod dm ON dm.id = am.deliveryMethodFk + JOIN warehouse w ON w.id = t.warehouseFk + LEFT JOIN ( + SELECT td.ticketFk, d.id + FROM ticketDms td + JOIN dms d ON d.id = td.dmsFk + JOIN dmsType dt ON dt.id = d.dmsTypeFk + WHERE dt.name = 'cmr' + ) sub ON sub.ticketFk = t.id + WHERE co.code <> 'ES' + AND am.name <> 'ABONO' + AND w.code = 'ALG' + AND dm.code = 'DELIVERY' + AND t.cmrFk + ) sub + `); + + stmt.merge(conn.makeSuffix(filter)); + const itemsIndex = stmts.push(stmt) - 1; + + const sql = ParameterizedSQL.join(stmts, ';'); + const result = await conn.executeStmt(sql); + return itemsIndex === 0 ? result : result[itemsIndex]; + }; +}; diff --git a/modules/route/back/models/route.js b/modules/route/back/models/route.js index a8d44cd05f..7e61acf25f 100644 --- a/modules/route/back/models/route.js +++ b/modules/route/back/models/route.js @@ -15,6 +15,7 @@ module.exports = Self => { require('../methods/route/sendSms')(Self); require('../methods/route/downloadZip')(Self); require('../methods/route/cmr')(Self); + require('../methods/route/getExternalCmrs')(Self); Self.validate('kmStart', validateDistance, { message: 'Distance must be lesser than 1000' diff --git a/modules/ticket/front/index.js b/modules/ticket/front/index.js index 029dc16a41..d805cb0f8c 100644 --- a/modules/ticket/front/index.js +++ b/modules/ticket/front/index.js @@ -36,3 +36,4 @@ import './future'; import './future-search-panel'; import './advance'; import './advance-search-panel'; +import './sms'; diff --git a/modules/ticket/front/routes.json b/modules/ticket/front/routes.json index c86b3a1efc..e403ab02dc 100644 --- a/modules/ticket/front/routes.json +++ b/modules/ticket/front/routes.json @@ -26,7 +26,8 @@ {"state": "ticket.card.components", "icon": "icon-components"}, {"state": "ticket.card.saleTracking", "icon": "assignment"}, {"state": "ticket.card.dms.index", "icon": "cloud_download"}, - {"state": "ticket.card.boxing", "icon": "science"} + {"state": "ticket.card.boxing", "icon": "science"}, + {"state": "ticket.card.sms", "icon": "sms"} ] }, "keybindings": [ @@ -287,6 +288,15 @@ "state": "ticket.advance", "component": "vn-ticket-advance", "description": "Advance tickets" + }, + { + "url": "/sms", + "state": "ticket.card.sms", + "component": "vn-ticket-sms", + "description": "Sms", + "params": { + "ticket": "$ctrl.ticket" + } } ] } diff --git a/modules/ticket/front/sms/index.html b/modules/ticket/front/sms/index.html new file mode 100644 index 0000000000..7fb3b870e0 --- /dev/null +++ b/modules/ticket/front/sms/index.html @@ -0,0 +1,2 @@ + + diff --git a/modules/ticket/front/sms/index.js b/modules/ticket/front/sms/index.js new file mode 100644 index 0000000000..69d54aafe8 --- /dev/null +++ b/modules/ticket/front/sms/index.js @@ -0,0 +1,21 @@ +import ngModule from '../module'; +import Section from 'salix/components/section'; + +class Controller extends Section { + constructor($element, $) { + super($element, $); + } + + async $onInit() { + this.$state.go('ticket.card.summary', {id: this.$params.id}); + window.location.href = await this.vnApp.getUrl(`ticket/${this.$params.id}/sms`); + } +} + +ngModule.vnComponent('vnTicketSms', { + template: require('./index.html'), + controller: Controller, + bindings: { + ticket: '<' + } +}); diff --git a/package-lock.json b/package-lock.json index f87e3f64b8..10b5e6b022 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "salix-back", - "version": "23.34.01", + "version": "23.32.02", "lockfileVersion": 2, "requires": true, "packages": {