Merge branch 'dev' of https://gitea.verdnatura.es/verdnatura/salix into 4074-download-user-ACL
This commit is contained in:
commit
5a38ae5b36
17
CHANGELOG.md
17
CHANGELOG.md
|
@ -5,17 +5,28 @@ All notable changes to this project will be documented in this file.
|
|||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [2314.01] - 2023-04-20
|
||||
## [2316.01] - 2023-05-04
|
||||
|
||||
### Added
|
||||
-
|
||||
-
|
||||
|
||||
### Changed
|
||||
-
|
||||
- (Artículo -> Precio fijado) Modificado el buscador superior por uno lateral
|
||||
|
||||
### Fixed
|
||||
-
|
||||
|
||||
|
||||
## [2314.01] - 2023-04-20
|
||||
|
||||
### Added
|
||||
- (Clientes -> Morosos) Ahora se puede filtrar por las columnas "Desde" y "Fecha Ú. O.". También se envia un email al comercial cuando se añade una nota.
|
||||
- (Monitor tickets) Muestra un icono al lado de la zona, si el ticket es frágil y se envía por agencia
|
||||
- (Facturas recibidas -> Bases negativas) Nueva sección
|
||||
|
||||
### Fixed
|
||||
- (Clientes -> Morosos) Ahora se mantienen los elementos seleccionados al hacer sroll.
|
||||
|
||||
## [2312.01] - 2023-04-06
|
||||
|
||||
### Added
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
const app = require('vn-loopback/server/server');
|
||||
const models = require('vn-loopback/server/server').models;
|
||||
|
||||
describe('campaign latest()', () => {
|
||||
it('should return the campaigns from the last year', async() => {
|
||||
const now = Date.vnNew();
|
||||
const result = await app.models.Campaign.latest();
|
||||
const result = await models.Campaign.latest();
|
||||
const randomIndex = Math.floor(Math.random() * result.length);
|
||||
const campaignDated = result[randomIndex].dated;
|
||||
|
||||
|
@ -14,7 +14,7 @@ describe('campaign latest()', () => {
|
|||
it('should return the campaigns from the current year', async() => {
|
||||
const now = Date.vnNew();
|
||||
const currentYear = now.getFullYear();
|
||||
const result = await app.models.Campaign.latest({
|
||||
const result = await models.Campaign.latest({
|
||||
where: {dated: {like: `%${currentYear}%`}}
|
||||
});
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
const app = require('vn-loopback/server/server');
|
||||
const {models} = require('vn-loopback/server/server');
|
||||
|
||||
describe('campaign upcoming()', () => {
|
||||
it('should return the upcoming campaign but from the last year', async() => {
|
||||
const response = await app.models.Campaign.upcoming();
|
||||
const response = await models.Campaign.upcoming();
|
||||
const campaignDated = response.dated;
|
||||
const now = Date.vnNew();
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ module.exports = Self => {
|
|||
Self.send = async(ctx, to, message) => {
|
||||
const models = Self.app.models;
|
||||
const accessToken = ctx.req.accessToken;
|
||||
const sender = await models.Account.findById(accessToken.userId);
|
||||
const sender = await models.VnUser.findById(accessToken.userId);
|
||||
const recipient = to.replace('@', '');
|
||||
|
||||
if (sender.name != recipient) {
|
||||
|
|
|
@ -29,8 +29,8 @@ module.exports = Self => {
|
|||
|
||||
const models = Self.app.models;
|
||||
const userId = ctx.req.accessToken.userId;
|
||||
const sender = await models.Account.findById(userId, {fields: ['id']});
|
||||
const recipient = await models.Account.findById(recipientId, null);
|
||||
const sender = await models.VnUser.findById(userId, {fields: ['id']});
|
||||
const recipient = await models.VnUser.findById(recipientId, null);
|
||||
|
||||
// Prevent sending messages to yourself
|
||||
if (recipientId == userId) return false;
|
||||
|
|
|
@ -58,7 +58,7 @@ module.exports = Self => {
|
|||
const models = Self.app.models;
|
||||
|
||||
const recipientName = chat.recipient.slice(1);
|
||||
const recipient = await models.Account.findOne({
|
||||
const recipient = await models.VnUser.findOne({
|
||||
where: {
|
||||
name: recipientName
|
||||
}
|
||||
|
@ -104,7 +104,7 @@ module.exports = Self => {
|
|||
}
|
||||
|
||||
const models = Self.app.models;
|
||||
const sender = await models.Account.findById(senderFk);
|
||||
const sender = await models.VnUser.findById(senderFk);
|
||||
|
||||
const login = await Self.getServiceAuth();
|
||||
const avatar = `${login.host}/avatar/${sender.name}`;
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
const app = require('vn-loopback/server/server');
|
||||
const {models} = require('vn-loopback/server/server');
|
||||
|
||||
describe('Chat notifyIssue()', () => {
|
||||
const ctx = {req: {accessToken: {userId: 1}}};
|
||||
ctx.req.__ = value => {
|
||||
return value;
|
||||
};
|
||||
const chatModel = app.models.Chat;
|
||||
const osTicketModel = app.models.OsTicket;
|
||||
const chatModel = models.Chat;
|
||||
const osTicketModel = models.OsTicket;
|
||||
const departmentId = 31;
|
||||
|
||||
it(`should not call to the send() method and neither return a response`, async() => {
|
||||
|
@ -29,7 +29,7 @@ describe('Chat notifyIssue()', () => {
|
|||
// eslint-disable-next-line max-len
|
||||
const expectedMessage = `@all ➔ There's a new urgent ticket:\r\n[ID: 00001 - Issue title @batman](https://cau.verdnatura.es/scp/tickets.php?id=1)`;
|
||||
|
||||
const department = await app.models.Department.findById(departmentId);
|
||||
const department = await models.Department.findById(departmentId);
|
||||
let orgChatName = department.chatName;
|
||||
await department.updateAttribute('chatName', 'IT');
|
||||
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
const app = require('vn-loopback/server/server');
|
||||
const {models} = require('vn-loopback/server/server');
|
||||
|
||||
describe('Chat send()', () => {
|
||||
it('should return true as response', async() => {
|
||||
let ctx = {req: {accessToken: {userId: 1}}};
|
||||
let response = await app.models.Chat.send(ctx, '@salesPerson', 'I changed something');
|
||||
let response = await models.Chat.send(ctx, '@salesPerson', 'I changed something');
|
||||
|
||||
expect(response).toEqual(true);
|
||||
});
|
||||
|
||||
it('should return false as response', async() => {
|
||||
let ctx = {req: {accessToken: {userId: 18}}};
|
||||
let response = await app.models.Chat.send(ctx, '@salesPerson', 'I changed something');
|
||||
let response = await models.Chat.send(ctx, '@salesPerson', 'I changed something');
|
||||
|
||||
expect(response).toEqual(false);
|
||||
});
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
const app = require('vn-loopback/server/server');
|
||||
const {models} = require('vn-loopback/server/server');
|
||||
|
||||
describe('getSectors()', () => {
|
||||
it('return list of sectors', async() => {
|
||||
let response = await app.models.Collection.getSectors();
|
||||
let response = await models.Collection.getSectors();
|
||||
|
||||
expect(response.length).toBeGreaterThan(0);
|
||||
expect(response[0].id).toEqual(1);
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
const app = require('vn-loopback/server/server');
|
||||
const {models} = require('vn-loopback/server/server');
|
||||
|
||||
describe('newCollection()', () => {
|
||||
it('should return a new collection', async() => {
|
||||
pending('#3400 analizar que hacer con rutas de back collection');
|
||||
let ctx = {req: {accessToken: {userId: 1106}}};
|
||||
let response = await app.models.Collection.newCollection(ctx, 1, 1, 1);
|
||||
let response = await models.Collection.newCollection(ctx, 1, 1, 1);
|
||||
|
||||
expect(response.length).toBeGreaterThan(0);
|
||||
expect(response[0].ticketFk).toEqual(2);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
const app = require('vn-loopback/server/server');
|
||||
const {models} = require('vn-loopback/server/server');
|
||||
|
||||
describe('dms downloadFile()', () => {
|
||||
let dmsId = 1;
|
||||
|
@ -6,7 +6,7 @@ describe('dms downloadFile()', () => {
|
|||
it('should return a response for an employee with text content-type', async() => {
|
||||
let workerId = 1107;
|
||||
let ctx = {req: {accessToken: {userId: workerId}}};
|
||||
const result = await app.models.Dms.downloadFile(ctx, dmsId);
|
||||
const result = await models.Dms.downloadFile(ctx, dmsId);
|
||||
|
||||
expect(result[1]).toEqual('text/plain');
|
||||
});
|
||||
|
@ -16,7 +16,7 @@ describe('dms downloadFile()', () => {
|
|||
let ctx = {req: {accessToken: {userId: clientId}}};
|
||||
|
||||
let error;
|
||||
await app.models.Dms.downloadFile(ctx, dmsId).catch(e => {
|
||||
await models.Dms.downloadFile(ctx, dmsId).catch(e => {
|
||||
error = e;
|
||||
}).finally(() => {
|
||||
expect(error.message).toEqual(`You don't have enough privileges`);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
const app = require('vn-loopback/server/server');
|
||||
const {models} = require('vn-loopback/server/server');
|
||||
|
||||
describe('dms removeFile()', () => {
|
||||
let dmsId = 1;
|
||||
|
@ -8,7 +8,7 @@ describe('dms removeFile()', () => {
|
|||
let ctx = {req: {accessToken: {userId: clientId}}};
|
||||
|
||||
let error;
|
||||
await app.models.Dms.removeFile(ctx, dmsId).catch(e => {
|
||||
await models.Dms.removeFile(ctx, dmsId).catch(e => {
|
||||
error = e;
|
||||
}).finally(() => {
|
||||
expect(error.message).toEqual(`You don't have enough privileges`);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
const app = require('vn-loopback/server/server');
|
||||
const {models} = require('vn-loopback/server/server');
|
||||
|
||||
describe('dms updateFile()', () => {
|
||||
it(`should return an error for a user without enough privileges`, async() => {
|
||||
|
@ -11,7 +11,7 @@ describe('dms updateFile()', () => {
|
|||
let ctx = {req: {accessToken: {userId: clientId}}, args: {dmsTypeId: dmsTypeId}};
|
||||
|
||||
let error;
|
||||
await app.models.Dms.updateFile(ctx, dmsId, warehouseId, companyId, dmsTypeId).catch(e => {
|
||||
await models.Dms.updateFile(ctx, dmsId, warehouseId, companyId, dmsTypeId).catch(e => {
|
||||
error = e;
|
||||
}).finally(() => {
|
||||
expect(error.message).toEqual(`You don't have enough privileges`);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
const app = require('vn-loopback/server/server');
|
||||
const {models} = require('vn-loopback/server/server');
|
||||
|
||||
describe('dms uploadFile()', () => {
|
||||
it(`should return an error for a user without enough privileges`, async() => {
|
||||
|
@ -7,7 +7,7 @@ describe('dms uploadFile()', () => {
|
|||
let ctx = {req: {accessToken: {userId: clientId}}, args: {dmsTypeId: ticketDmsTypeId}};
|
||||
|
||||
let error;
|
||||
await app.models.Dms.uploadFile(ctx).catch(e => {
|
||||
await models.Dms.uploadFile(ctx).catch(e => {
|
||||
error = e;
|
||||
}).finally(() => {
|
||||
expect(error.message).toEqual(`You don't have enough privileges`);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
const app = require('vn-loopback/server/server');
|
||||
const {models} = require('vn-loopback/server/server');
|
||||
|
||||
describe('image download()', () => {
|
||||
const collection = 'user';
|
||||
|
@ -8,7 +8,7 @@ describe('image download()', () => {
|
|||
|
||||
it('should return the image content-type of the user', async() => {
|
||||
const userId = 9;
|
||||
const image = await app.models.Image.download(ctx, collection, size, userId);
|
||||
const image = await models.Image.download(ctx, collection, size, userId);
|
||||
const contentType = image[1];
|
||||
|
||||
expect(contentType).toEqual('image/png');
|
||||
|
@ -16,7 +16,7 @@ describe('image download()', () => {
|
|||
|
||||
it(`should return false if the user doesn't have image`, async() => {
|
||||
const userId = 1110;
|
||||
const image = await app.models.Image.download(ctx, collection, size, userId);
|
||||
const image = await models.Image.download(ctx, collection, size, userId);
|
||||
|
||||
expect(image).toBeFalse();
|
||||
});
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
const app = require('vn-loopback/server/server');
|
||||
const {models} = require('vn-loopback/server/server');
|
||||
|
||||
describe('image upload()', () => {
|
||||
describe('as buyer', () => {
|
||||
|
@ -16,7 +16,7 @@ describe('image upload()', () => {
|
|||
|
||||
let error;
|
||||
try {
|
||||
await app.models.Image.upload(ctx);
|
||||
await models.Image.upload(ctx);
|
||||
} catch (err) {
|
||||
error = err;
|
||||
}
|
||||
|
@ -25,7 +25,7 @@ describe('image upload()', () => {
|
|||
});
|
||||
|
||||
it('should call to the TempContainer upload method for the collection "catalog"', async() => {
|
||||
const containerModel = app.models.TempContainer;
|
||||
const containerModel = models.TempContainer;
|
||||
spyOn(containerModel, 'upload');
|
||||
|
||||
const ctx = {req: {accessToken: {userId: buyerId}},
|
||||
|
@ -36,7 +36,7 @@ describe('image upload()', () => {
|
|||
};
|
||||
|
||||
try {
|
||||
await app.models.Image.upload(ctx);
|
||||
await models.Image.upload(ctx);
|
||||
} catch (err) { }
|
||||
|
||||
expect(containerModel.upload).toHaveBeenCalled();
|
||||
|
@ -49,7 +49,7 @@ describe('image upload()', () => {
|
|||
const itemId = 4;
|
||||
|
||||
it('should be able to call to the TempContainer upload method for the collection "user"', async() => {
|
||||
const containerModel = app.models.TempContainer;
|
||||
const containerModel = models.TempContainer;
|
||||
spyOn(containerModel, 'upload');
|
||||
|
||||
const ctx = {req: {accessToken: {userId: marketingId}},
|
||||
|
@ -60,14 +60,14 @@ describe('image upload()', () => {
|
|||
};
|
||||
|
||||
try {
|
||||
await app.models.Image.upload(ctx);
|
||||
await models.Image.upload(ctx);
|
||||
} catch (err) { }
|
||||
|
||||
expect(containerModel.upload).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should be able to call to the TempContainer upload method for the collection "catalog"', async() => {
|
||||
const containerModel = app.models.TempContainer;
|
||||
const containerModel = models.TempContainer;
|
||||
spyOn(containerModel, 'upload');
|
||||
|
||||
const ctx = {req: {accessToken: {userId: marketingId}},
|
||||
|
@ -78,7 +78,7 @@ describe('image upload()', () => {
|
|||
};
|
||||
|
||||
try {
|
||||
await app.models.Image.upload(ctx);
|
||||
await models.Image.upload(ctx);
|
||||
} catch (err) { }
|
||||
|
||||
expect(containerModel.upload).toHaveBeenCalled();
|
||||
|
@ -91,7 +91,7 @@ describe('image upload()', () => {
|
|||
const itemId = 4;
|
||||
|
||||
it('should upload a file for the collection "user" and call to the TempContainer upload method', async() => {
|
||||
const containerModel = app.models.TempContainer;
|
||||
const containerModel = models.TempContainer;
|
||||
spyOn(containerModel, 'upload');
|
||||
|
||||
const ctx = {req: {accessToken: {userId: hhrrId}},
|
||||
|
@ -102,7 +102,7 @@ describe('image upload()', () => {
|
|||
};
|
||||
|
||||
try {
|
||||
await app.models.Image.upload(ctx);
|
||||
await models.Image.upload(ctx);
|
||||
} catch (err) { }
|
||||
|
||||
expect(containerModel.upload).toHaveBeenCalled();
|
||||
|
@ -118,7 +118,7 @@ describe('image upload()', () => {
|
|||
|
||||
let error;
|
||||
try {
|
||||
await app.models.Image.upload(ctx);
|
||||
await models.Image.upload(ctx);
|
||||
} catch (err) {
|
||||
error = err;
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
const UserError = require('vn-loopback/util/user-error');
|
||||
const fs = require('fs-extra');
|
||||
const fs = require('fs/promises');
|
||||
const path = require('path');
|
||||
const uuid = require('uuid');
|
||||
|
||||
module.exports = Self => {
|
||||
Self.remoteMethodCtx('upload', {
|
||||
|
@ -36,7 +35,7 @@ module.exports = Self => {
|
|||
const fileOptions = {};
|
||||
const args = ctx.args;
|
||||
|
||||
let srcFile;
|
||||
let tempFilePath;
|
||||
try {
|
||||
const hasWriteRole = await models.ImageCollection.hasWriteRole(ctx, args.collection);
|
||||
if (!hasWriteRole)
|
||||
|
@ -53,15 +52,20 @@ module.exports = Self => {
|
|||
});
|
||||
|
||||
const file = await TempContainer.getFile(tempContainer.name, uploadedFile.name);
|
||||
srcFile = path.join(file.client.root, file.container, file.name);
|
||||
tempFilePath = path.join(file.client.root, file.container, file.name);
|
||||
|
||||
const fileName = `${uuid.v4()}.png`;
|
||||
await models.Image.registerImage(args.collection, srcFile, fileName, args.id);
|
||||
} catch (e) {
|
||||
if (fs.existsSync(srcFile))
|
||||
await fs.unlink(srcFile);
|
||||
const fileName = `${args.id}.png`;
|
||||
|
||||
throw e;
|
||||
await models.Image.resize({
|
||||
collectionName: args.collection,
|
||||
srcFile: tempFilePath,
|
||||
fileName: fileName,
|
||||
entityId: args.id
|
||||
});
|
||||
} finally {
|
||||
try {
|
||||
await fs.unlink(tempFilePath);
|
||||
} catch (error) { }
|
||||
}
|
||||
};
|
||||
};
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
const app = require('vn-loopback/server/server');
|
||||
const {models} = require('vn-loopback/server/server');
|
||||
const LoopBackContext = require('loopback-context');
|
||||
|
||||
describe('getStarredModules()', () => {
|
||||
|
@ -19,13 +19,13 @@ describe('getStarredModules()', () => {
|
|||
});
|
||||
|
||||
it(`should return the starred modules for a given user`, async() => {
|
||||
const newStarred = await app.models.StarredModule.create({workerFk: 9, moduleFk: 'customer', position: 1});
|
||||
const starredModules = await app.models.StarredModule.getStarredModules(ctx);
|
||||
const newStarred = await models.StarredModule.create({workerFk: 9, moduleFk: 'customer', position: 1});
|
||||
const starredModules = await models.StarredModule.getStarredModules(ctx);
|
||||
|
||||
expect(starredModules.length).toEqual(1);
|
||||
expect(starredModules[0].moduleFk).toEqual('customer');
|
||||
|
||||
// restores
|
||||
await app.models.StarredModule.destroyById(newStarred.id);
|
||||
await models.StarredModule.destroyById(newStarred.id);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
const app = require('vn-loopback/server/server');
|
||||
const {models} = require('vn-loopback/server/server');
|
||||
const LoopBackContext = require('loopback-context');
|
||||
|
||||
describe('setPosition()', () => {
|
||||
|
@ -21,7 +21,7 @@ describe('setPosition()', () => {
|
|||
});
|
||||
|
||||
it('should increase the orders module position by replacing it with clients and vice versa', async() => {
|
||||
const tx = await app.models.StarredModule.beginTransaction({});
|
||||
const tx = await models.StarredModule.beginTransaction({});
|
||||
|
||||
const filter = {
|
||||
where: {
|
||||
|
@ -32,24 +32,24 @@ describe('setPosition()', () => {
|
|||
|
||||
try {
|
||||
const options = {transaction: tx};
|
||||
await app.models.StarredModule.toggleStarredModule(ctx, 'order', options);
|
||||
await app.models.StarredModule.toggleStarredModule(ctx, 'customer', options);
|
||||
await models.StarredModule.toggleStarredModule(ctx, 'order', options);
|
||||
await models.StarredModule.toggleStarredModule(ctx, 'customer', options);
|
||||
|
||||
let orders = await app.models.StarredModule.findOne(filter, options);
|
||||
let orders = await models.StarredModule.findOne(filter, options);
|
||||
|
||||
filter.where.moduleFk = 'customer';
|
||||
let clients = await app.models.StarredModule.findOne(filter, options);
|
||||
let clients = await models.StarredModule.findOne(filter, options);
|
||||
|
||||
expect(orders.position).toEqual(1);
|
||||
expect(clients.position).toEqual(2);
|
||||
|
||||
await app.models.StarredModule.setPosition(ctx, 'customer', 'left', options);
|
||||
await models.StarredModule.setPosition(ctx, 'customer', 'left', options);
|
||||
|
||||
filter.where.moduleFk = 'customer';
|
||||
clients = await app.models.StarredModule.findOne(filter, options);
|
||||
clients = await models.StarredModule.findOne(filter, options);
|
||||
|
||||
filter.where.moduleFk = 'order';
|
||||
orders = await app.models.StarredModule.findOne(filter, options);
|
||||
orders = await models.StarredModule.findOne(filter, options);
|
||||
|
||||
expect(clients.position).toEqual(1);
|
||||
expect(orders.position).toEqual(2);
|
||||
|
@ -62,7 +62,7 @@ describe('setPosition()', () => {
|
|||
});
|
||||
|
||||
it('should decrease the orders module position by replacing it with clients and vice versa', async() => {
|
||||
const tx = await app.models.StarredModule.beginTransaction({});
|
||||
const tx = await models.StarredModule.beginTransaction({});
|
||||
|
||||
const filter = {
|
||||
where: {
|
||||
|
@ -73,24 +73,24 @@ describe('setPosition()', () => {
|
|||
|
||||
try {
|
||||
const options = {transaction: tx};
|
||||
await app.models.StarredModule.toggleStarredModule(ctx, 'order', options);
|
||||
await app.models.StarredModule.toggleStarredModule(ctx, 'customer', options);
|
||||
await models.StarredModule.toggleStarredModule(ctx, 'order', options);
|
||||
await models.StarredModule.toggleStarredModule(ctx, 'customer', options);
|
||||
|
||||
let orders = await app.models.StarredModule.findOne(filter, options);
|
||||
let orders = await models.StarredModule.findOne(filter, options);
|
||||
|
||||
filter.where.moduleFk = 'customer';
|
||||
let clients = await app.models.StarredModule.findOne(filter, options);
|
||||
let clients = await models.StarredModule.findOne(filter, options);
|
||||
|
||||
expect(orders.position).toEqual(1);
|
||||
expect(clients.position).toEqual(2);
|
||||
|
||||
await app.models.StarredModule.setPosition(ctx, 'order', 'right', options);
|
||||
await models.StarredModule.setPosition(ctx, 'order', 'right', options);
|
||||
|
||||
filter.where.moduleFk = 'order';
|
||||
orders = await app.models.StarredModule.findOne(filter, options);
|
||||
orders = await models.StarredModule.findOne(filter, options);
|
||||
|
||||
filter.where.moduleFk = 'customer';
|
||||
clients = await app.models.StarredModule.findOne(filter, options);
|
||||
clients = await models.StarredModule.findOne(filter, options);
|
||||
|
||||
expect(orders.position).toEqual(2);
|
||||
expect(clients.position).toEqual(1);
|
||||
|
@ -103,7 +103,7 @@ describe('setPosition()', () => {
|
|||
});
|
||||
|
||||
it('should switch two modules after adding and deleting several modules', async() => {
|
||||
const tx = await app.models.StarredModule.beginTransaction({});
|
||||
const tx = await models.StarredModule.beginTransaction({});
|
||||
|
||||
const filter = {
|
||||
where: {
|
||||
|
@ -115,29 +115,29 @@ describe('setPosition()', () => {
|
|||
try {
|
||||
const options = {transaction: tx};
|
||||
|
||||
await app.models.StarredModule.toggleStarredModule(ctx, 'customer', options);
|
||||
await app.models.StarredModule.toggleStarredModule(ctx, 'order', options);
|
||||
await app.models.StarredModule.toggleStarredModule(ctx, 'customer', options);
|
||||
await app.models.StarredModule.toggleStarredModule(ctx, 'order', options);
|
||||
await app.models.StarredModule.toggleStarredModule(ctx, 'item', options);
|
||||
await app.models.StarredModule.toggleStarredModule(ctx, 'claim', options);
|
||||
await app.models.StarredModule.toggleStarredModule(ctx, 'customer', options);
|
||||
await app.models.StarredModule.toggleStarredModule(ctx, 'order', options);
|
||||
await app.models.StarredModule.toggleStarredModule(ctx, 'zone', options);
|
||||
await models.StarredModule.toggleStarredModule(ctx, 'customer', options);
|
||||
await models.StarredModule.toggleStarredModule(ctx, 'order', options);
|
||||
await models.StarredModule.toggleStarredModule(ctx, 'customer', options);
|
||||
await models.StarredModule.toggleStarredModule(ctx, 'order', options);
|
||||
await models.StarredModule.toggleStarredModule(ctx, 'item', options);
|
||||
await models.StarredModule.toggleStarredModule(ctx, 'claim', options);
|
||||
await models.StarredModule.toggleStarredModule(ctx, 'customer', options);
|
||||
await models.StarredModule.toggleStarredModule(ctx, 'order', options);
|
||||
await models.StarredModule.toggleStarredModule(ctx, 'zone', options);
|
||||
|
||||
const items = await app.models.StarredModule.findOne(filter, options);
|
||||
const items = await models.StarredModule.findOne(filter, options);
|
||||
|
||||
filter.where.moduleFk = 'claim';
|
||||
const claims = await app.models.StarredModule.findOne(filter, options);
|
||||
const claims = await models.StarredModule.findOne(filter, options);
|
||||
|
||||
filter.where.moduleFk = 'customer';
|
||||
let clients = await app.models.StarredModule.findOne(filter, options);
|
||||
let clients = await models.StarredModule.findOne(filter, options);
|
||||
|
||||
filter.where.moduleFk = 'order';
|
||||
let orders = await app.models.StarredModule.findOne(filter, options);
|
||||
let orders = await models.StarredModule.findOne(filter, options);
|
||||
|
||||
filter.where.moduleFk = 'zone';
|
||||
const zones = await app.models.StarredModule.findOne(filter, options);
|
||||
const zones = await models.StarredModule.findOne(filter, options);
|
||||
|
||||
expect(items.position).toEqual(1);
|
||||
expect(claims.position).toEqual(2);
|
||||
|
@ -145,13 +145,13 @@ describe('setPosition()', () => {
|
|||
expect(orders.position).toEqual(4);
|
||||
expect(zones.position).toEqual(5);
|
||||
|
||||
await app.models.StarredModule.setPosition(ctx, 'customer', 'right', options);
|
||||
await models.StarredModule.setPosition(ctx, 'customer', 'right', options);
|
||||
|
||||
filter.where.moduleFk = 'order';
|
||||
orders = await app.models.StarredModule.findOne(filter, options);
|
||||
orders = await models.StarredModule.findOne(filter, options);
|
||||
|
||||
filter.where.moduleFk = 'customer';
|
||||
clients = await app.models.StarredModule.findOne(filter, options);
|
||||
clients = await models.StarredModule.findOne(filter, options);
|
||||
|
||||
expect(orders.position).toEqual(3);
|
||||
expect(clients.position).toEqual(4);
|
||||
|
@ -164,7 +164,7 @@ describe('setPosition()', () => {
|
|||
});
|
||||
|
||||
it('should switch two modules after adding and deleting a module between them', async() => {
|
||||
const tx = await app.models.StarredModule.beginTransaction({});
|
||||
const tx = await models.StarredModule.beginTransaction({});
|
||||
|
||||
const filter = {
|
||||
where: {
|
||||
|
@ -176,25 +176,25 @@ describe('setPosition()', () => {
|
|||
try {
|
||||
const options = {transaction: tx};
|
||||
|
||||
await app.models.StarredModule.toggleStarredModule(ctx, 'item', options);
|
||||
await app.models.StarredModule.toggleStarredModule(ctx, 'customer', options);
|
||||
await app.models.StarredModule.toggleStarredModule(ctx, 'claim', options);
|
||||
await app.models.StarredModule.toggleStarredModule(ctx, 'order', options);
|
||||
await app.models.StarredModule.toggleStarredModule(ctx, 'zone', options);
|
||||
await models.StarredModule.toggleStarredModule(ctx, 'item', options);
|
||||
await models.StarredModule.toggleStarredModule(ctx, 'customer', options);
|
||||
await models.StarredModule.toggleStarredModule(ctx, 'claim', options);
|
||||
await models.StarredModule.toggleStarredModule(ctx, 'order', options);
|
||||
await models.StarredModule.toggleStarredModule(ctx, 'zone', options);
|
||||
|
||||
const items = await app.models.StarredModule.findOne(filter, options);
|
||||
const items = await models.StarredModule.findOne(filter, options);
|
||||
|
||||
filter.where.moduleFk = 'customer';
|
||||
let clients = await app.models.StarredModule.findOne(filter, options);
|
||||
let clients = await models.StarredModule.findOne(filter, options);
|
||||
|
||||
filter.where.moduleFk = 'claim';
|
||||
const claims = await app.models.StarredModule.findOne(filter, options);
|
||||
const claims = await models.StarredModule.findOne(filter, options);
|
||||
|
||||
filter.where.moduleFk = 'order';
|
||||
let orders = await app.models.StarredModule.findOne(filter, options);
|
||||
let orders = await models.StarredModule.findOne(filter, options);
|
||||
|
||||
filter.where.moduleFk = 'zone';
|
||||
const zones = await app.models.StarredModule.findOne(filter, options);
|
||||
const zones = await models.StarredModule.findOne(filter, options);
|
||||
|
||||
expect(items.position).toEqual(1);
|
||||
expect(clients.position).toEqual(2);
|
||||
|
@ -202,14 +202,14 @@ describe('setPosition()', () => {
|
|||
expect(orders.position).toEqual(4);
|
||||
expect(zones.position).toEqual(5);
|
||||
|
||||
await app.models.StarredModule.toggleStarredModule(ctx, 'claim', options);
|
||||
await app.models.StarredModule.setPosition(ctx, 'customer', 'right', options);
|
||||
await models.StarredModule.toggleStarredModule(ctx, 'claim', options);
|
||||
await models.StarredModule.setPosition(ctx, 'customer', 'right', options);
|
||||
|
||||
filter.where.moduleFk = 'customer';
|
||||
clients = await app.models.StarredModule.findOne(filter, options);
|
||||
clients = await models.StarredModule.findOne(filter, options);
|
||||
|
||||
filter.where.moduleFk = 'order';
|
||||
orders = await app.models.StarredModule.findOne(filter, options);
|
||||
orders = await models.StarredModule.findOne(filter, options);
|
||||
|
||||
expect(orders.position).toEqual(2);
|
||||
expect(clients.position).toEqual(4);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
const app = require('vn-loopback/server/server');
|
||||
const {models} = require('vn-loopback/server/server');
|
||||
const LoopBackContext = require('loopback-context');
|
||||
|
||||
describe('toggleStarredModule()', () => {
|
||||
|
@ -21,16 +21,16 @@ describe('toggleStarredModule()', () => {
|
|||
});
|
||||
|
||||
it('should create a new starred module and then remove it by calling the method again with same args', async() => {
|
||||
const starredModule = await app.models.StarredModule.toggleStarredModule(ctx, 'order');
|
||||
let starredModules = await app.models.StarredModule.getStarredModules(ctx);
|
||||
const starredModule = await models.StarredModule.toggleStarredModule(ctx, 'order');
|
||||
let starredModules = await models.StarredModule.getStarredModules(ctx);
|
||||
|
||||
expect(starredModules.length).toEqual(1);
|
||||
expect(starredModule.moduleFk).toEqual('order');
|
||||
expect(starredModule.workerFk).toEqual(activeCtx.accessToken.userId);
|
||||
expect(starredModule.position).toEqual(starredModules.length);
|
||||
|
||||
await app.models.StarredModule.toggleStarredModule(ctx, 'order');
|
||||
starredModules = await app.models.StarredModule.getStarredModules(ctx);
|
||||
await models.StarredModule.toggleStarredModule(ctx, 'order');
|
||||
starredModules = await models.StarredModule.getStarredModules(ctx);
|
||||
|
||||
expect(starredModules.length).toEqual(0);
|
||||
});
|
||||
|
|
|
@ -22,7 +22,7 @@ module.exports = Self => {
|
|||
let userId = ctx.req.accessToken.userId;
|
||||
let models = Self.app.models;
|
||||
|
||||
let user = await models.Account.findById(userId, {
|
||||
let user = await Self.findById(userId, {
|
||||
fields: ['id', 'name', 'nickname', 'email', 'lang'],
|
||||
include: {
|
||||
relation: 'userConfig',
|
|
@ -1,9 +1,14 @@
|
|||
const UserError = require('vn-loopback/util/user-error');
|
||||
|
||||
module.exports = Self => {
|
||||
Self.remoteMethodCtx('privileges', {
|
||||
Self.remoteMethod('privileges', {
|
||||
description: 'Change role and hasGrant if user has privileges',
|
||||
accepts: [
|
||||
{
|
||||
arg: 'ctx',
|
||||
type: 'Object',
|
||||
http: {source: 'context'}
|
||||
},
|
||||
{
|
||||
arg: 'id',
|
||||
type: 'number',
|
||||
|
@ -39,9 +44,9 @@ module.exports = Self => {
|
|||
if (typeof options == 'object')
|
||||
Object.assign(myOptions, options);
|
||||
|
||||
const user = await models.Account.findById(userId, {fields: ['hasGrant']}, myOptions);
|
||||
const user = await Self.findById(userId, {fields: ['hasGrant']}, myOptions);
|
||||
|
||||
const userToUpdate = await models.Account.findById(id, {
|
||||
const userToUpdate = await Self.findById(id, {
|
||||
fields: ['id', 'name', 'hasGrant', 'roleFk', 'password'],
|
||||
include: {
|
||||
relation: 'role',
|
||||
|
@ -54,7 +59,7 @@ module.exports = Self => {
|
|||
if (!user.hasGrant)
|
||||
throw new UserError(`You don't have grant privilege`);
|
||||
|
||||
const hasRoleFromUser = await models.Account.hasRole(userId, userToUpdate.role().name, myOptions);
|
||||
const hasRoleFromUser = await Self.hasRole(userId, userToUpdate.role().name, myOptions);
|
||||
|
||||
if (!hasRoleFromUser)
|
||||
throw new UserError(`You don't own the role and you can't assign it to another user`);
|
||||
|
@ -64,7 +69,7 @@ module.exports = Self => {
|
|||
|
||||
if (roleFk) {
|
||||
const role = await models.Role.findById(roleFk, {fields: ['name']}, myOptions);
|
||||
const hasRole = await models.Account.hasRole(userId, role.name, myOptions);
|
||||
const hasRole = await Self.hasRole(userId, role.name, myOptions);
|
||||
|
||||
if (!hasRole)
|
||||
throw new UserError(`You don't own the role and you can't assign it to another user`);
|
||||
|
@ -73,6 +78,6 @@ module.exports = Self => {
|
|||
}
|
||||
|
||||
await userToUpdate.save(userToUpdate);
|
||||
await models.UserAccount.sync(userToUpdate.name);
|
||||
await models.Account.sync(userToUpdate.name);
|
||||
};
|
||||
};
|
|
@ -20,7 +20,7 @@ module.exports = Self => {
|
|||
|
||||
const usesEmail = user.indexOf('@') !== -1;
|
||||
if (!usesEmail) {
|
||||
const account = await models.Account.findOne({
|
||||
const account = await models.VnUser.findOne({
|
||||
fields: ['email'],
|
||||
where: {name: user}
|
||||
});
|
||||
|
@ -28,7 +28,7 @@ module.exports = Self => {
|
|||
}
|
||||
|
||||
try {
|
||||
await models.user.resetPassword({email: user, emailTemplate: 'recover-password'});
|
||||
await Self.resetPassword({email: user, emailTemplate: 'recover-password'});
|
||||
} catch (err) {
|
||||
if (err.code === 'EMAIL_NOT_FOUND')
|
||||
return;
|
|
@ -1,14 +1,14 @@
|
|||
const md5 = require('md5');
|
||||
const UserError = require('vn-loopback/util/user-error');
|
||||
|
||||
module.exports = Self => {
|
||||
Self.remoteMethod('login', {
|
||||
Self.remoteMethod('signIn', {
|
||||
description: 'Login a user with username/email and password',
|
||||
accepts: [
|
||||
{
|
||||
arg: 'user',
|
||||
type: 'String',
|
||||
description: 'The user name or email',
|
||||
http: {source: 'form'},
|
||||
required: true
|
||||
}, {
|
||||
arg: 'password',
|
||||
|
@ -21,20 +21,20 @@ module.exports = Self => {
|
|||
root: true
|
||||
},
|
||||
http: {
|
||||
path: `/login`,
|
||||
path: `/signIn`,
|
||||
verb: 'POST'
|
||||
}
|
||||
});
|
||||
|
||||
Self.login = async function(user, password) {
|
||||
let $ = Self.app.models;
|
||||
Self.signIn = async function(user, password) {
|
||||
let models = Self.app.models;
|
||||
let token;
|
||||
let usesEmail = user.indexOf('@') !== -1;
|
||||
|
||||
let userInfo = usesEmail
|
||||
? {email: user}
|
||||
: {username: user};
|
||||
let instance = await $.User.findOne({
|
||||
let instance = await Self.findOne({
|
||||
fields: ['username', 'password'],
|
||||
where: userInfo
|
||||
});
|
||||
|
@ -42,29 +42,27 @@ module.exports = Self => {
|
|||
let where = usesEmail
|
||||
? {email: user}
|
||||
: {name: user};
|
||||
let account = await Self.findOne({
|
||||
fields: ['active', 'password'],
|
||||
let vnUser = await Self.findOne({
|
||||
fields: ['active'],
|
||||
where
|
||||
});
|
||||
|
||||
let validCredentials = instance && (
|
||||
await instance.hasPassword(password) ||
|
||||
account.password == md5(password || '')
|
||||
);
|
||||
let validCredentials = instance
|
||||
&& await instance.hasPassword(password);
|
||||
|
||||
if (validCredentials) {
|
||||
if (!account.active)
|
||||
if (!vnUser.active)
|
||||
throw new UserError('User disabled');
|
||||
|
||||
try {
|
||||
await $.UserAccount.sync(instance.username, password);
|
||||
await models.Account.sync(instance.username, password);
|
||||
} catch (err) {
|
||||
console.warn(err);
|
||||
}
|
||||
}
|
||||
|
||||
let loginInfo = Object.assign({password}, userInfo);
|
||||
token = await $.User.login(loginInfo, 'user');
|
||||
token = await Self.login(loginInfo, 'user');
|
||||
return {token: token.id};
|
||||
};
|
||||
};
|
|
@ -1,6 +1,6 @@
|
|||
const models = require('vn-loopback/server/server').models;
|
||||
|
||||
describe('account privileges()', () => {
|
||||
describe('VnUser privileges()', () => {
|
||||
const employeeId = 1;
|
||||
const developerId = 9;
|
||||
const sysadminId = 66;
|
||||
|
@ -10,13 +10,13 @@ describe('account privileges()', () => {
|
|||
|
||||
it('should throw an error when user not has privileges', async() => {
|
||||
const ctx = {req: {accessToken: {userId: developerId}}};
|
||||
const tx = await models.Account.beginTransaction({});
|
||||
const tx = await models.VnUser.beginTransaction({});
|
||||
|
||||
let error;
|
||||
try {
|
||||
const options = {transaction: tx};
|
||||
|
||||
await models.Account.privileges(ctx, employeeId, null, true, options);
|
||||
await models.VnUser.privileges(ctx, employeeId, null, true, options);
|
||||
|
||||
await tx.rollback();
|
||||
} catch (e) {
|
||||
|
@ -29,13 +29,13 @@ describe('account privileges()', () => {
|
|||
|
||||
it('should throw an error when user has privileges but not has the role', async() => {
|
||||
const ctx = {req: {accessToken: {userId: sysadminId}}};
|
||||
const tx = await models.Account.beginTransaction({});
|
||||
const tx = await models.VnUser.beginTransaction({});
|
||||
|
||||
let error;
|
||||
try {
|
||||
const options = {transaction: tx};
|
||||
|
||||
await models.Account.privileges(ctx, employeeId, rootId, null, options);
|
||||
await models.VnUser.privileges(ctx, employeeId, rootId, null, options);
|
||||
|
||||
await tx.rollback();
|
||||
} catch (e) {
|
||||
|
@ -48,13 +48,13 @@ describe('account privileges()', () => {
|
|||
|
||||
it('should throw an error when user has privileges but not has the role from user', async() => {
|
||||
const ctx = {req: {accessToken: {userId: sysadminId}}};
|
||||
const tx = await models.Account.beginTransaction({});
|
||||
const tx = await models.VnUser.beginTransaction({});
|
||||
|
||||
let error;
|
||||
try {
|
||||
const options = {transaction: tx};
|
||||
|
||||
await models.Account.privileges(ctx, itBossId, developerId, null, options);
|
||||
await models.VnUser.privileges(ctx, itBossId, developerId, null, options);
|
||||
|
||||
await tx.rollback();
|
||||
} catch (e) {
|
||||
|
@ -67,7 +67,7 @@ describe('account privileges()', () => {
|
|||
|
||||
it('should change role', async() => {
|
||||
const ctx = {req: {accessToken: {userId: sysadminId}}};
|
||||
const tx = await models.Account.beginTransaction({});
|
||||
const tx = await models.VnUser.beginTransaction({});
|
||||
|
||||
const options = {transaction: tx};
|
||||
const agency = await models.Role.findOne({
|
||||
|
@ -79,8 +79,8 @@ describe('account privileges()', () => {
|
|||
let error;
|
||||
let result;
|
||||
try {
|
||||
await models.Account.privileges(ctx, clarkKent, agency.id, null, options);
|
||||
result = await models.Account.findById(clarkKent, null, options);
|
||||
await models.VnUser.privileges(ctx, clarkKent, agency.id, null, options);
|
||||
result = await models.VnUser.findById(clarkKent, null, options);
|
||||
|
||||
await tx.rollback();
|
||||
} catch (e) {
|
||||
|
@ -94,14 +94,14 @@ describe('account privileges()', () => {
|
|||
|
||||
it('should change hasGrant', async() => {
|
||||
const ctx = {req: {accessToken: {userId: sysadminId}}};
|
||||
const tx = await models.Account.beginTransaction({});
|
||||
const tx = await models.VnUser.beginTransaction({});
|
||||
|
||||
let error;
|
||||
let result;
|
||||
try {
|
||||
const options = {transaction: tx};
|
||||
await models.Account.privileges(ctx, clarkKent, null, true, options);
|
||||
result = await models.Account.findById(clarkKent, null, options);
|
||||
await models.VnUser.privileges(ctx, clarkKent, null, true, options);
|
||||
result = await models.VnUser.findById(clarkKent, null, options);
|
||||
|
||||
await tx.rollback();
|
||||
} catch (e) {
|
|
@ -1,25 +1,25 @@
|
|||
const app = require('vn-loopback/server/server');
|
||||
const {models} = require('vn-loopback/server/server');
|
||||
|
||||
describe('account login()', () => {
|
||||
describe('VnUser signIn()', () => {
|
||||
describe('when credentials are correct', () => {
|
||||
it('should return the token', async() => {
|
||||
let login = await app.models.Account.login('salesAssistant', 'nightmare');
|
||||
let accessToken = await app.models.AccessToken.findById(login.token);
|
||||
let login = await models.VnUser.signIn('salesAssistant', 'nightmare');
|
||||
let accessToken = await models.AccessToken.findById(login.token);
|
||||
let ctx = {req: {accessToken: accessToken}};
|
||||
|
||||
expect(login.token).toBeDefined();
|
||||
|
||||
await app.models.Account.logout(ctx);
|
||||
await models.VnUser.signOut(ctx);
|
||||
});
|
||||
|
||||
it('should return the token if the user doesnt exist but the client does', async() => {
|
||||
let login = await app.models.Account.login('PetterParker', 'nightmare');
|
||||
let accessToken = await app.models.AccessToken.findById(login.token);
|
||||
let login = await models.VnUser.signIn('PetterParker', 'nightmare');
|
||||
let accessToken = await models.AccessToken.findById(login.token);
|
||||
let ctx = {req: {accessToken: accessToken}};
|
||||
|
||||
expect(login.token).toBeDefined();
|
||||
|
||||
await app.models.Account.logout(ctx);
|
||||
await models.VnUser.signOut(ctx);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -28,7 +28,7 @@ describe('account login()', () => {
|
|||
let error;
|
||||
|
||||
try {
|
||||
await app.models.Account.login('IDontExist', 'TotallyWrongPassword');
|
||||
await models.VnUser.signIn('IDontExist', 'TotallyWrongPassword');
|
||||
} catch (e) {
|
||||
error = e;
|
||||
}
|
|
@ -1,13 +1,13 @@
|
|||
const app = require('vn-loopback/server/server');
|
||||
const {models} = require('vn-loopback/server/server');
|
||||
|
||||
describe('account logout()', () => {
|
||||
describe('VnUser signOut()', () => {
|
||||
it('should logout and remove token after valid login', async() => {
|
||||
let loginResponse = await app.models.Account.login('buyer', 'nightmare');
|
||||
let accessToken = await app.models.AccessToken.findById(loginResponse.token);
|
||||
let loginResponse = await models.VnUser.signOut('buyer', 'nightmare');
|
||||
let accessToken = await models.AccessToken.findById(loginResponse.token);
|
||||
let ctx = {req: {accessToken: accessToken}};
|
||||
|
||||
let logoutResponse = await app.models.Account.logout(ctx);
|
||||
let tokenAfterLogout = await app.models.AccessToken.findById(loginResponse.token);
|
||||
let logoutResponse = await models.VnUser.signOut(ctx);
|
||||
let tokenAfterLogout = await models.AccessToken.findById(loginResponse.token);
|
||||
|
||||
expect(logoutResponse).toBeTrue();
|
||||
expect(tokenAfterLogout).toBeNull();
|
||||
|
@ -18,7 +18,7 @@ describe('account logout()', () => {
|
|||
let ctx = {req: {accessToken: {id: 'invalidToken'}}};
|
||||
|
||||
try {
|
||||
response = await app.models.Account.logout(ctx);
|
||||
response = await models.VnUser.signOut(ctx);
|
||||
} catch (e) {
|
||||
error = e;
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ describe('account logout()', () => {
|
|||
let ctx = {req: {accessToken: null}};
|
||||
|
||||
try {
|
||||
response = await app.models.Account.logout(ctx);
|
||||
response = await models.VnUser.signOut(ctx);
|
||||
} catch (e) {
|
||||
error = e;
|
||||
}
|
|
@ -1,7 +1,4 @@
|
|||
{
|
||||
"Account": {
|
||||
"dataSource": "vn"
|
||||
},
|
||||
"AccountingType": {
|
||||
"dataSource": "vn"
|
||||
},
|
||||
|
@ -125,10 +122,10 @@
|
|||
"UserConfigView": {
|
||||
"dataSource": "vn"
|
||||
},
|
||||
"UserLog": {
|
||||
"Warehouse": {
|
||||
"dataSource": "vn"
|
||||
},
|
||||
"Warehouse": {
|
||||
"VnUser": {
|
||||
"dataSource": "vn"
|
||||
},
|
||||
"OsTicket": {
|
||||
|
|
|
@ -1,140 +0,0 @@
|
|||
/* eslint max-len: ["error", { "code": 150 }]*/
|
||||
const md5 = require('md5');
|
||||
const LoopBackContext = require('loopback-context');
|
||||
const {Email} = require('vn-print');
|
||||
|
||||
module.exports = Self => {
|
||||
require('../methods/account/login')(Self);
|
||||
require('../methods/account/logout')(Self);
|
||||
require('../methods/account/acl')(Self);
|
||||
require('../methods/account/change-password')(Self);
|
||||
require('../methods/account/set-password')(Self);
|
||||
require('../methods/account/recover-password')(Self);
|
||||
require('../methods/account/validate-token')(Self);
|
||||
require('../methods/account/privileges')(Self);
|
||||
require('../methods/account/user-acl')(Self);
|
||||
|
||||
// Validations
|
||||
|
||||
Self.validatesFormatOf('email', {
|
||||
message: 'Invalid email',
|
||||
allowNull: true,
|
||||
allowBlank: true,
|
||||
with: /^[\w|.|-]+@[\w|-]+(\.[\w|-]+)*(,[\w|.|-]+@[\w|-]+(\.[\w|-]+)*)*$/
|
||||
});
|
||||
|
||||
Self.validatesUniquenessOf('name', {
|
||||
message: `A client with that Web User name already exists`
|
||||
});
|
||||
|
||||
Self.observe('before save', async function(ctx) {
|
||||
if (ctx.currentInstance && ctx.currentInstance.id && ctx.data && ctx.data.password)
|
||||
ctx.data.password = md5(ctx.data.password);
|
||||
});
|
||||
|
||||
Self.afterRemote('prototype.patchAttributes', async(ctx, instance) => {
|
||||
if (!ctx.args || !ctx.args.data.email) return;
|
||||
const models = Self.app.models;
|
||||
|
||||
const loopBackContext = LoopBackContext.getCurrentContext();
|
||||
const httpCtx = {req: loopBackContext.active};
|
||||
const httpRequest = httpCtx.req.http.req;
|
||||
const headers = httpRequest.headers;
|
||||
const origin = headers.origin;
|
||||
const url = origin.split(':');
|
||||
|
||||
const userId = ctx.instance.id;
|
||||
const user = await models.user.findById(userId);
|
||||
|
||||
class Mailer {
|
||||
async send(verifyOptions, cb) {
|
||||
const params = {
|
||||
url: verifyOptions.verifyHref,
|
||||
recipient: verifyOptions.to,
|
||||
lang: ctx.req.getLocale()
|
||||
};
|
||||
|
||||
const email = new Email('email-verify', params);
|
||||
email.send();
|
||||
|
||||
cb(null, verifyOptions.to);
|
||||
}
|
||||
}
|
||||
|
||||
const options = {
|
||||
type: 'email',
|
||||
to: instance.email,
|
||||
from: {},
|
||||
redirect: `${origin}/#!/account/${instance.id}/basic-data?emailConfirmed`,
|
||||
template: false,
|
||||
mailer: new Mailer,
|
||||
host: url[1].split('/')[2],
|
||||
port: url[2],
|
||||
protocol: url[0],
|
||||
user: Self
|
||||
};
|
||||
|
||||
await user.verify(options);
|
||||
});
|
||||
|
||||
Self.remoteMethod('getCurrentUserData', {
|
||||
description: 'Gets the current user data',
|
||||
accepts: [
|
||||
{
|
||||
arg: 'ctx',
|
||||
type: 'object',
|
||||
http: {source: 'context'}
|
||||
}
|
||||
],
|
||||
returns: {
|
||||
type: 'object',
|
||||
root: true
|
||||
},
|
||||
http: {
|
||||
verb: 'GET',
|
||||
path: '/getCurrentUserData'
|
||||
}
|
||||
});
|
||||
|
||||
Self.getCurrentUserData = async function(ctx) {
|
||||
let userId = ctx.req.accessToken.userId;
|
||||
return await Self.findById(userId, {
|
||||
fields: ['id', 'name', 'nickname']
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Checks if user has a role.
|
||||
*
|
||||
* @param {Integer} userId The user id
|
||||
* @param {String} name The role name
|
||||
* @param {object} options Options
|
||||
* @return {Boolean} %true if user has the role, %false otherwise
|
||||
*/
|
||||
Self.hasRole = async function(userId, name, options) {
|
||||
let roles = await Self.getRoles(userId, options);
|
||||
return roles.some(role => role == name);
|
||||
};
|
||||
|
||||
/**
|
||||
* Get all user roles.
|
||||
*
|
||||
* @param {Integer} userId The user id
|
||||
* @param {object} options Options
|
||||
* @return {object} User role list
|
||||
*/
|
||||
Self.getRoles = async(userId, options) => {
|
||||
let result = await Self.rawSql(
|
||||
`SELECT r.name
|
||||
FROM account.user u
|
||||
JOIN account.roleRole rr ON rr.role = u.role
|
||||
JOIN account.role r ON r.id = rr.inheritsFrom
|
||||
WHERE u.id = ?`, [userId], options);
|
||||
|
||||
let roles = [];
|
||||
for (const role of result)
|
||||
roles.push(role.name);
|
||||
|
||||
return roles;
|
||||
};
|
||||
};
|
|
@ -54,8 +54,8 @@ module.exports = Self => {
|
|||
const writeRole = dmsType.writeRole() && dmsType.writeRole().name;
|
||||
const requiredRole = readRole || writeRole;
|
||||
|
||||
const hasRequiredRole = await models.Account.hasRole(myUserId, requiredRole, options);
|
||||
const isRoot = await models.Account.hasRole(myUserId, 'root', options);
|
||||
const hasRequiredRole = await models.VnUser.hasRole(myUserId, requiredRole, options);
|
||||
const isRoot = await models.VnUser.hasRole(myUserId, 'root', options);
|
||||
|
||||
if (isRoot || hasRequiredRole)
|
||||
return true;
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
"relations": {
|
||||
"user": {
|
||||
"type": "belongsTo",
|
||||
"model": "Account",
|
||||
"model": "VnUser",
|
||||
"foreignKey": "userFk"
|
||||
}
|
||||
},
|
||||
|
|
|
@ -53,8 +53,8 @@ module.exports = Self => {
|
|||
const writeRole = collection.writeRole() && collection.writeRole().name;
|
||||
const requiredRole = readRole || writeRole;
|
||||
|
||||
const hasRequiredRole = await models.Account.hasRole(myUserId, requiredRole, options);
|
||||
const isRoot = await models.Account.hasRole(myUserId, 'root', options);
|
||||
const hasRequiredRole = await models.VnUser.hasRole(myUserId, requiredRole, options);
|
||||
const isRoot = await models.VnUser.hasRole(myUserId, 'root', options);
|
||||
|
||||
if (isRoot || hasRequiredRole)
|
||||
return true;
|
||||
|
|
|
@ -1,161 +1,110 @@
|
|||
const fs = require('fs-extra');
|
||||
const sharp = require('sharp');
|
||||
const path = require('path');
|
||||
const readChunk = require('read-chunk');
|
||||
const imageType = require('image-type');
|
||||
const bmp = require('bmp-js');
|
||||
const gm = require('gm');
|
||||
|
||||
module.exports = Self => {
|
||||
require('../methods/image/download')(Self);
|
||||
require('../methods/image/upload')(Self);
|
||||
|
||||
// Function extracted from jimp package (utils)
|
||||
function scan(image, x, y, w, h, f) {
|
||||
// round input
|
||||
x = Math.round(x);
|
||||
y = Math.round(y);
|
||||
w = Math.round(w);
|
||||
h = Math.round(h);
|
||||
|
||||
for (let _y = y; _y < y + h; _y++) {
|
||||
for (let _x = x; _x < x + w; _x++) {
|
||||
const idx = (image.bitmap.width * _y + _x) << 2;
|
||||
f.call(image, _x, _y, idx);
|
||||
}
|
||||
}
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
// Function extracted from jimp package (type-bmp)
|
||||
function fromAGBR(bitmap) {
|
||||
return scan({bitmap}, 0, 0, bitmap.width, bitmap.height, function(
|
||||
x,
|
||||
y,
|
||||
index
|
||||
) {
|
||||
const alpha = this.bitmap.data[index + 0];
|
||||
const blue = this.bitmap.data[index + 1];
|
||||
const green = this.bitmap.data[index + 2];
|
||||
const red = this.bitmap.data[index + 3];
|
||||
|
||||
this.bitmap.data[index + 0] = red;
|
||||
this.bitmap.data[index + 1] = green;
|
||||
this.bitmap.data[index + 2] = blue;
|
||||
this.bitmap.data[index + 3] = bitmap.is_with_alpha ? alpha : 0xff;
|
||||
}).bitmap;
|
||||
}
|
||||
|
||||
Self.registerImage = async(collectionName, srcFilePath, fileName, entityId) => {
|
||||
Self.resize = async function({collectionName, srcFile, fileName, entityId}) {
|
||||
const models = Self.app.models;
|
||||
const tx = await Self.beginTransaction({});
|
||||
const myOptions = {transaction: tx};
|
||||
|
||||
try {
|
||||
const collection = await models.ImageCollection.findOne({
|
||||
const collection = await models.ImageCollection.findOne(
|
||||
{
|
||||
fields: [
|
||||
'id',
|
||||
'name',
|
||||
'maxWidth',
|
||||
'maxHeight',
|
||||
'model',
|
||||
'property'
|
||||
'property',
|
||||
],
|
||||
where: {name: collectionName},
|
||||
include: {
|
||||
relation: 'sizes',
|
||||
scope: {
|
||||
fields: ['width', 'height', 'crop']
|
||||
}
|
||||
}
|
||||
}, myOptions);
|
||||
fields: ['width', 'height', 'crop'],
|
||||
},
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
const data = {
|
||||
// Insert image row
|
||||
await models.Image.upsertWithWhere(
|
||||
{
|
||||
name: fileName,
|
||||
collectionFk: collectionName
|
||||
};
|
||||
const newImage = await Self.upsertWithWhere(data, {
|
||||
},
|
||||
{
|
||||
name: fileName,
|
||||
collectionFk: collectionName,
|
||||
updated: Date.vnNow()
|
||||
}, myOptions);
|
||||
|
||||
// Resizes and saves the image
|
||||
const container = await models.ImageContainer.container(collectionName);
|
||||
const rootPath = container.client.root;
|
||||
const collectionDir = path.join(rootPath, collectionName);
|
||||
const dstDir = path.join(collectionDir, 'full');
|
||||
const dstFile = path.join(dstDir, fileName);
|
||||
|
||||
const buffer = readChunk.sync(srcFilePath, 0, 12);
|
||||
const type = imageType(buffer);
|
||||
|
||||
let sharpOptions;
|
||||
let imgSrc = srcFilePath;
|
||||
if (type.mime == 'image/bmp') {
|
||||
const bmpBuffer = fs.readFileSync(srcFilePath);
|
||||
const bmpData = fromAGBR(bmp.decode(bmpBuffer));
|
||||
imgSrc = bmpData.data;
|
||||
sharpOptions = {
|
||||
raw: {
|
||||
width: bmpData.width,
|
||||
height: bmpData.height,
|
||||
channels: 4
|
||||
},
|
||||
failOn: 'none'
|
||||
};
|
||||
updated: Date.vnNow() / 1000,
|
||||
}
|
||||
);
|
||||
|
||||
const resizeOpts = {
|
||||
withoutEnlargement: true,
|
||||
fit: 'inside'
|
||||
};
|
||||
// Update entity image file name
|
||||
const model = models[collection.model];
|
||||
if (!model) throw new Error('No matching model found');
|
||||
|
||||
await fs.mkdir(dstDir, {recursive: true});
|
||||
await sharp(imgSrc, sharpOptions)
|
||||
.resize(collection.maxWidth, collection.maxHeight, resizeOpts)
|
||||
.png()
|
||||
.toFile(dstFile);
|
||||
const entity = await model.findById(entityId);
|
||||
if (entity) {
|
||||
await entity.updateAttribute(
|
||||
collection.property,
|
||||
fileName
|
||||
);
|
||||
}
|
||||
|
||||
const sizes = collection.sizes();
|
||||
for (let size of sizes) {
|
||||
const dstDir = path.join(collectionDir, `${size.width}x${size.height}`);
|
||||
const dstFile = path.join(dstDir, fileName);
|
||||
const resizeOpts = {
|
||||
withoutEnlargement: true,
|
||||
fit: size.crop ? 'cover' : 'inside'
|
||||
};
|
||||
// Resize
|
||||
const container = await models.ImageContainer.container(
|
||||
collectionName
|
||||
);
|
||||
const rootPath = container.client.root;
|
||||
const collectionDir = path.join(rootPath, collectionName);
|
||||
|
||||
await fs.mkdir(dstDir, {recursive: true});
|
||||
await sharp(imgSrc, sharpOptions)
|
||||
.resize(size.width, size.height, resizeOpts)
|
||||
.png()
|
||||
.toFile(dstFile);
|
||||
}
|
||||
// To max size
|
||||
const {maxWidth, maxHeight} = collection;
|
||||
const fullSizePath = path.join(collectionDir, 'full');
|
||||
const toFullSizePath = `${fullSizePath}/${fileName}`;
|
||||
|
||||
const model = models[collection.model];
|
||||
await fs.mkdir(fullSizePath, {recursive: true});
|
||||
await new Promise((resolve, reject) => {
|
||||
gm(srcFile)
|
||||
.resize(maxWidth, maxHeight, '>')
|
||||
.setFormat('png')
|
||||
.quality(100)
|
||||
.write(toFullSizePath, function(err) {
|
||||
if (err) reject(err);
|
||||
if (!err) resolve();
|
||||
});
|
||||
});
|
||||
|
||||
if (!model)
|
||||
throw new Error('Matching model not found');
|
||||
// To collection sizes
|
||||
for (const size of collection.sizes()) {
|
||||
const {width, height} = size;
|
||||
|
||||
const item = await model.findById(entityId, null, myOptions);
|
||||
if (item) {
|
||||
await item.updateAttribute(
|
||||
collection.property,
|
||||
fileName,
|
||||
myOptions
|
||||
);
|
||||
}
|
||||
const sizePath = path.join(collectionDir, `${width}x${height}`);
|
||||
const toSizePath = `${sizePath}/${fileName}`;
|
||||
|
||||
if (fs.existsSync(srcFilePath))
|
||||
await fs.unlink(srcFilePath);
|
||||
await fs.mkdir(sizePath, {recursive: true});
|
||||
await new Promise((resolve, reject) => {
|
||||
const gmInstance = gm(srcFile);
|
||||
|
||||
await tx.commit();
|
||||
if (size.crop) {
|
||||
gmInstance
|
||||
.resize(width, height, '^')
|
||||
.gravity('Center')
|
||||
.crop(width, height);
|
||||
}
|
||||
|
||||
return newImage;
|
||||
} catch (e) {
|
||||
await tx.rollback();
|
||||
throw e;
|
||||
if (!size.crop) gmInstance.resize(width, height, '>');
|
||||
|
||||
gmInstance
|
||||
.setFormat('png')
|
||||
.quality(100)
|
||||
.write(toSizePath, function(err) {
|
||||
if (err) reject(err);
|
||||
if (!err) resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
};
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
},
|
||||
"author": {
|
||||
"type": "belongsTo",
|
||||
"model": "Account",
|
||||
"model": "VnUser",
|
||||
"foreignKey": "authorFk"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
},
|
||||
"user": {
|
||||
"type": "belongsTo",
|
||||
"model": "Account",
|
||||
"model": "VnUser",
|
||||
"foreignKey": "userFk"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
const app = require('vn-loopback/server/server');
|
||||
const {models} = require('vn-loopback/server/server');
|
||||
|
||||
describe('loopback model Company', () => {
|
||||
it('should check that the company FTH doesnt exists', async() => {
|
||||
let result = await app.models.Company.findOne({where: {code: 'FTH'}});
|
||||
let result = await models.Company.findOne({where: {code: 'FTH'}});
|
||||
|
||||
expect(result).toBeFalsy();
|
||||
});
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
const app = require('vn-loopback/server/server');
|
||||
const {models} = require('vn-loopback/server/server');
|
||||
describe('Dms', () => {
|
||||
const Dms = app.models.Dms;
|
||||
const Dms = models.Dms;
|
||||
|
||||
describe('getFile()', () => {
|
||||
it('should return a response with text content-type', async() => {
|
||||
|
@ -23,7 +23,7 @@ describe('Dms', () => {
|
|||
it('should return an error for a record does not exists', async() => {
|
||||
let error = {};
|
||||
try {
|
||||
await app.models.Dms.getFile('NotExistentId');
|
||||
await models.Dms.getFile('NotExistentId');
|
||||
} catch (e) {
|
||||
error = e;
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
const models = require('vn-loopback/server/server').models;
|
||||
const LoopBackContext = require('loopback-context');
|
||||
|
||||
describe('account recoverPassword()', () => {
|
||||
describe('VnUser recoverPassword()', () => {
|
||||
const userId = 1107;
|
||||
|
||||
const activeCtx = {
|
||||
|
@ -21,9 +21,9 @@ describe('account recoverPassword()', () => {
|
|||
|
||||
it('should send email with token', async() => {
|
||||
const userId = 1107;
|
||||
const user = await models.Account.findById(userId);
|
||||
const user = await models.VnUser.findById(userId);
|
||||
|
||||
await models.Account.recoverPassword(user.email);
|
||||
await models.VnUser.recoverPassword(user.email);
|
||||
|
||||
const result = await models.AccessToken.findOne({where: {userId: userId}});
|
||||
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
const models = require('vn-loopback/server/server').models;
|
||||
|
||||
describe('loopback model Account', () => {
|
||||
describe('loopback model VnUser', () => {
|
||||
it('should return true if the user has the given role', async() => {
|
||||
let result = await models.Account.hasRole(1, 'employee');
|
||||
let result = await models.VnUser.hasRole(1, 'employee');
|
||||
|
||||
expect(result).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should return false if the user doesnt have the given role', async() => {
|
||||
let result = await models.Account.hasRole(1, 'administrator');
|
||||
let result = await models.VnUser.hasRole(1, 'administrator');
|
||||
|
||||
expect(result).toBeFalsy();
|
||||
});
|
|
@ -26,7 +26,7 @@
|
|||
"relations": {
|
||||
"user": {
|
||||
"type": "belongsTo",
|
||||
"model": "Account",
|
||||
"model": "VnUser",
|
||||
"foreignKey": "userFk"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,9 +39,9 @@
|
|||
"model": "Company",
|
||||
"foreignKey": "companyFk"
|
||||
},
|
||||
"account": {
|
||||
"VnUser": {
|
||||
"type": "belongsTo",
|
||||
"model": "Account",
|
||||
"model": "VnUser",
|
||||
"foreignKey": "userFk"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,27 +0,0 @@
|
|||
const LoopBackContext = require('loopback-context');
|
||||
const {Email} = require('vn-print');
|
||||
|
||||
module.exports = function(Self) {
|
||||
Self.on('resetPasswordRequest', async function(info) {
|
||||
const loopBackContext = LoopBackContext.getCurrentContext();
|
||||
const httpCtx = {req: loopBackContext.active};
|
||||
const httpRequest = httpCtx.req.http.req;
|
||||
const headers = httpRequest.headers;
|
||||
const origin = headers.origin;
|
||||
|
||||
const user = await Self.app.models.Account.findById(info.user.id);
|
||||
const params = {
|
||||
recipient: info.email,
|
||||
lang: user.lang,
|
||||
url: `${origin}/#!/reset-password?access_token=${info.accessToken.id}`
|
||||
};
|
||||
|
||||
const options = Object.assign({}, info.options);
|
||||
for (const param in options)
|
||||
params[param] = options[param];
|
||||
|
||||
const email = new Email(options.emailTemplate, params);
|
||||
|
||||
return email.send();
|
||||
});
|
||||
};
|
|
@ -1,19 +0,0 @@
|
|||
{
|
||||
"name": "user",
|
||||
"base": "User",
|
||||
"options": {
|
||||
"mysql": {
|
||||
"table": "salix.User"
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
"id": {
|
||||
"id": true,
|
||||
"type": "number",
|
||||
"forceId": false
|
||||
},
|
||||
"username":{
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,110 @@
|
|||
const vnModel = require('vn-loopback/common/models/vn-model');
|
||||
const LoopBackContext = require('loopback-context');
|
||||
const {Email} = require('vn-print');
|
||||
|
||||
module.exports = function(Self) {
|
||||
vnModel(Self);
|
||||
|
||||
require('../methods/vn-user/signIn')(Self);
|
||||
require('../methods/vn-user/acl')(Self);
|
||||
require('../methods/vn-user/recover-password')(Self);
|
||||
require('../methods/vn-user/validate-token')(Self);
|
||||
require('../methods/vn-user/privileges')(Self);
|
||||
|
||||
// Validations
|
||||
|
||||
Self.validatesFormatOf('email', {
|
||||
message: 'Invalid email',
|
||||
allowNull: true,
|
||||
allowBlank: true,
|
||||
with: /^[\w|.|-]+@[\w|-]+(\.[\w|-]+)*(,[\w|.|-]+@[\w|-]+(\.[\w|-]+)*)*$/
|
||||
});
|
||||
|
||||
Self.validatesUniquenessOf('name', {
|
||||
message: `A client with that Web User name already exists`
|
||||
});
|
||||
|
||||
Self.remoteMethod('getCurrentUserData', {
|
||||
description: 'Gets the current user data',
|
||||
accepts: [
|
||||
{
|
||||
arg: 'ctx',
|
||||
type: 'Object',
|
||||
http: {source: 'context'}
|
||||
}
|
||||
],
|
||||
returns: {
|
||||
type: 'Object',
|
||||
root: true
|
||||
},
|
||||
http: {
|
||||
verb: 'GET',
|
||||
path: '/getCurrentUserData'
|
||||
}
|
||||
});
|
||||
|
||||
Self.getCurrentUserData = async function(ctx) {
|
||||
let userId = ctx.req.accessToken.userId;
|
||||
return await Self.findById(userId, {
|
||||
fields: ['id', 'name', 'nickname']
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Checks if user has a role.
|
||||
*
|
||||
* @param {Integer} userId The user id
|
||||
* @param {String} name The role name
|
||||
* @param {Object} options Options
|
||||
* @return {Boolean} %true if user has the role, %false otherwise
|
||||
*/
|
||||
Self.hasRole = async function(userId, name, options) {
|
||||
const roles = await Self.getRoles(userId, options);
|
||||
return roles.some(role => role == name);
|
||||
};
|
||||
|
||||
/**
|
||||
* Get all user roles.
|
||||
*
|
||||
* @param {Integer} userId The user id
|
||||
* @param {Object} options Options
|
||||
* @return {Object} User role list
|
||||
*/
|
||||
Self.getRoles = async(userId, options) => {
|
||||
const result = await Self.rawSql(
|
||||
`SELECT r.name
|
||||
FROM account.user u
|
||||
JOIN account.roleRole rr ON rr.role = u.role
|
||||
JOIN account.role r ON r.id = rr.inheritsFrom
|
||||
WHERE u.id = ?`, [userId], options);
|
||||
|
||||
const roles = [];
|
||||
for (const role of result)
|
||||
roles.push(role.name);
|
||||
|
||||
return roles;
|
||||
};
|
||||
|
||||
Self.on('resetPasswordRequest', async function(info) {
|
||||
const loopBackContext = LoopBackContext.getCurrentContext();
|
||||
const httpCtx = {req: loopBackContext.active};
|
||||
const httpRequest = httpCtx.req.http.req;
|
||||
const headers = httpRequest.headers;
|
||||
const origin = headers.origin;
|
||||
|
||||
const user = await Self.app.models.VnUser.findById(info.user.id);
|
||||
const params = {
|
||||
recipient: info.email,
|
||||
lang: user.lang,
|
||||
url: `${origin}/#!/reset-password?access_token=${info.accessToken.id}`
|
||||
};
|
||||
|
||||
const options = Object.assign({}, info.options);
|
||||
for (const param in options)
|
||||
params[param] = options[param];
|
||||
|
||||
const email = new Email(options.emailTemplate, params);
|
||||
|
||||
return email.send();
|
||||
});
|
||||
};
|
|
@ -1,11 +1,13 @@
|
|||
{
|
||||
"name": "Account",
|
||||
"base": "VnModel",
|
||||
"name": "VnUser",
|
||||
"base": "User",
|
||||
"validateUpsert": true,
|
||||
"options": {
|
||||
"mysql": {
|
||||
"table": "account.user"
|
||||
}
|
||||
},
|
||||
"resetPasswordTokenTTL": "604800",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "number",
|
||||
|
@ -15,6 +17,19 @@
|
|||
"type": "string",
|
||||
"required": true
|
||||
},
|
||||
"username": {
|
||||
"type": "string",
|
||||
"mysql": {
|
||||
"columnName": "name"
|
||||
}
|
||||
},
|
||||
"password": {
|
||||
"type": "string",
|
||||
"required": true,
|
||||
"mysql": {
|
||||
"columnName": "bcryptPassword"
|
||||
}
|
||||
},
|
||||
"roleFk": {
|
||||
"type": "number",
|
||||
"mysql": {
|
||||
|
@ -27,10 +42,6 @@
|
|||
"lang": {
|
||||
"type": "string"
|
||||
},
|
||||
"password": {
|
||||
"type": "string",
|
||||
"required": true
|
||||
},
|
||||
"bcryptPassword": {
|
||||
"type": "string"
|
||||
},
|
||||
|
@ -40,9 +51,6 @@
|
|||
"email": {
|
||||
"type": "string"
|
||||
},
|
||||
"emailVerified": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"created": {
|
||||
"type": "date"
|
||||
},
|
||||
|
@ -86,7 +94,7 @@
|
|||
},
|
||||
"acls": [
|
||||
{
|
||||
"property": "login",
|
||||
"property": "signIn",
|
||||
"accessType": "EXECUTE",
|
||||
"principalType": "ROLE",
|
||||
"principalId": "$everyone",
|
||||
|
@ -100,13 +108,6 @@
|
|||
"permission": "ALLOW"
|
||||
},
|
||||
{
|
||||
"property": "logout",
|
||||
"accessType": "EXECUTE",
|
||||
"principalType": "ROLE",
|
||||
"principalId": "$authenticated",
|
||||
"permission": "ALLOW"
|
||||
},
|
||||
{
|
||||
"property": "validateToken",
|
||||
"accessType": "EXECUTE",
|
||||
"principalType": "ROLE",
|
|
@ -0,0 +1,18 @@
|
|||
INSERT INTO `salix`.`ACL` (model, property, accessType, permission, principalType, principalId)
|
||||
VALUES ('VnUser', '*', '*', 'ALLOW', 'ROLE', 'employee');
|
||||
|
||||
INSERT INTO `salix`.`ACL` (id, model, property, accessType, permission, principalType, principalId)
|
||||
VALUES ('VnUser', 'acl', 'READ', 'ALLOW', 'ROLE', 'account');
|
||||
|
||||
INSERT INTO `salix`.`ACL` (id, model, property, accessType, permission, principalType, principalId)
|
||||
VALUES ('VnUser', 'getCurrentUserData', 'READ', 'ALLOW', 'ROLE', 'account');
|
||||
|
||||
INSERT INTO `salix`.`ACL` (id, model, property, accessType, permission, principalType, principalId)
|
||||
VALUES ('VnUser', 'changePassword', '*', 'ALLOW', 'ROLE', 'account');
|
||||
|
||||
|
||||
|
||||
UPDATE `hedera`.`imageCollection` t
|
||||
SET t.model = 'VnUser'
|
||||
WHERE t.id = 6;
|
||||
|
|
@ -0,0 +1 @@
|
|||
ALTER TABLE `vn`.`ticketConfig` ADD daysForWarningClaim INT DEFAULT 2 NOT NULL COMMENT 'dias restantes hasta que salte el aviso de reclamación fuerade plazo';
|
|
@ -0,0 +1,2 @@
|
|||
INSERT INTO `salix`.`ACL` ( model, property, accessType, permission, principalType, principalId)
|
||||
VALUES('Mail', '*', '*', 'ALLOW', 'ROLE', 'employee');
|
|
@ -0,0 +1,74 @@
|
|||
DROP TABLE `vn`.`dmsRecover`;
|
||||
|
||||
ALTER TABLE `vn`.`delivery` DROP FOREIGN KEY delivery_FK;
|
||||
ALTER TABLE `vn`.`delivery` DROP COLUMN addressFk;
|
||||
ALTER TABLE `vn`.`delivery` ADD ticketFk INT NOT NULL;
|
||||
ALTER TABLE `vn`.`delivery` ADD CONSTRAINT delivery_ticketFk_FK FOREIGN KEY (`ticketFk`) REFERENCES `vn`.`ticket`(`id`);
|
||||
|
||||
DELETE FROM `salix`.`ACL` WHERE `property` = 'saveSign';
|
||||
INSERT INTO `salix`.`ACL` (`model`,`property`,`accessType`,`permission`,`principalId`)
|
||||
VALUES
|
||||
('Ticket','saveSign','WRITE','ALLOW','employee');
|
||||
|
||||
DROP PROCEDURE IF EXISTS vn.route_getTickets;
|
||||
|
||||
DELIMITER $$
|
||||
$$
|
||||
CREATE DEFINER=`root`@`localhost` PROCEDURE `vn`.`route_getTickets`(vRouteFk INT)
|
||||
BEGIN
|
||||
/**
|
||||
* Pasado un RouteFk devuelve la información
|
||||
* de sus tickets.
|
||||
*
|
||||
* @param vRouteFk
|
||||
*
|
||||
* @select Información de los tickets
|
||||
*/
|
||||
|
||||
SELECT
|
||||
t.id Id,
|
||||
t.clientFk Client,
|
||||
a.id Address,
|
||||
t.packages Packages,
|
||||
a.street AddressName,
|
||||
a.postalCode PostalCode,
|
||||
a.city City,
|
||||
sub2.itemPackingTypeFk PackingType,
|
||||
c.phone ClientPhone,
|
||||
c.mobile ClientMobile,
|
||||
a.phone AddressPhone,
|
||||
a.mobile AddressMobile,
|
||||
d.longitude Longitude,
|
||||
d.latitude Latitude,
|
||||
wm.mediaValue SalePersonPhone,
|
||||
tob.Note Note,
|
||||
t.isSigned Signed
|
||||
FROM ticket t
|
||||
JOIN client c ON t.clientFk = c.id
|
||||
JOIN address a ON t.addressFk = a.id
|
||||
LEFT JOIN delivery d ON t.id = d.ticketFk
|
||||
LEFT JOIN workerMedia wm ON wm.workerFk = c.salesPersonFk
|
||||
LEFT JOIN
|
||||
(SELECT tob.description Note, t.id
|
||||
FROM ticketObservation tob
|
||||
JOIN ticket t ON tob.ticketFk = t.id
|
||||
JOIN observationType ot ON ot.id = tob.observationTypeFk
|
||||
WHERE t.routeFk = vRouteFk
|
||||
AND ot.code = 'delivery'
|
||||
)tob ON tob.id = t.id
|
||||
LEFT JOIN
|
||||
(SELECT sub.ticketFk,
|
||||
CONCAT('(', GROUP_CONCAT(DISTINCT sub.itemPackingTypeFk ORDER BY sub.items DESC SEPARATOR ','), ') ') itemPackingTypeFk
|
||||
FROM (SELECT s.ticketFk , i.itemPackingTypeFk, COUNT(*) items
|
||||
FROM ticket t
|
||||
JOIN sale s ON s.ticketFk = t.id
|
||||
JOIN item i ON i.id = s.itemFk
|
||||
WHERE t.routeFk = vRouteFk
|
||||
GROUP BY t.id,i.itemPackingTypeFk)sub
|
||||
GROUP BY sub.ticketFk
|
||||
) sub2 ON sub2.ticketFk = t.id
|
||||
WHERE t.routeFk = vRouteFk
|
||||
GROUP BY t.id
|
||||
ORDER BY t.priority;
|
||||
END$$
|
||||
DELIMITER ;
|
|
@ -0,0 +1,67 @@
|
|||
DELETE FROM `salix`.`ACL` WHERE `property` = 'saveSign';
|
||||
INSERT INTO `salix`.`ACL` (`model`,`property`,`accessType`,`permission`,`principalId`)
|
||||
VALUES
|
||||
('Ticket','saveSign','WRITE','ALLOW','employee');
|
||||
|
||||
DROP PROCEDURE IF EXISTS vn.route_getTickets;
|
||||
|
||||
DELIMITER $$
|
||||
$$
|
||||
CREATE DEFINER=`root`@`localhost` PROCEDURE `vn`.`route_getTickets`(vRouteFk INT)
|
||||
BEGIN
|
||||
/**
|
||||
* Pasado un RouteFk devuelve la información
|
||||
* de sus tickets.
|
||||
*
|
||||
* @param vRouteFk
|
||||
*
|
||||
* @select Información de los tickets
|
||||
*/
|
||||
|
||||
SELECT
|
||||
t.id Id,
|
||||
t.clientFk Client,
|
||||
a.id Address,
|
||||
t.packages Packages,
|
||||
a.street AddressName,
|
||||
a.postalCode PostalCode,
|
||||
a.city City,
|
||||
sub2.itemPackingTypeFk PackingType,
|
||||
c.phone ClientPhone,
|
||||
c.mobile ClientMobile,
|
||||
a.phone AddressPhone,
|
||||
a.mobile AddressMobile,
|
||||
d.longitude Longitude,
|
||||
d.latitude Latitude,
|
||||
wm.mediaValue SalePersonPhone,
|
||||
tob.Note Note,
|
||||
t.isSigned Signed
|
||||
FROM ticket t
|
||||
JOIN client c ON t.clientFk = c.id
|
||||
JOIN address a ON t.addressFk = a.id
|
||||
LEFT JOIN delivery d ON t.id = d.ticketFk
|
||||
LEFT JOIN workerMedia wm ON wm.workerFk = c.salesPersonFk
|
||||
LEFT JOIN
|
||||
(SELECT tob.description Note, t.id
|
||||
FROM ticketObservation tob
|
||||
JOIN ticket t ON tob.ticketFk = t.id
|
||||
JOIN observationType ot ON ot.id = tob.observationTypeFk
|
||||
WHERE t.routeFk = vRouteFk
|
||||
AND ot.code = 'delivery'
|
||||
)tob ON tob.id = t.id
|
||||
LEFT JOIN
|
||||
(SELECT sub.ticketFk,
|
||||
CONCAT('(', GROUP_CONCAT(DISTINCT sub.itemPackingTypeFk ORDER BY sub.items DESC SEPARATOR ','), ') ') itemPackingTypeFk
|
||||
FROM (SELECT s.ticketFk , i.itemPackingTypeFk, COUNT(*) items
|
||||
FROM ticket t
|
||||
JOIN sale s ON s.ticketFk = t.id
|
||||
JOIN item i ON i.id = s.itemFk
|
||||
WHERE t.routeFk = vRouteFk
|
||||
GROUP BY t.id,i.itemPackingTypeFk)sub
|
||||
GROUP BY sub.ticketFk
|
||||
) sub2 ON sub2.ticketFk = t.id
|
||||
WHERE t.routeFk = vRouteFk
|
||||
GROUP BY t.id
|
||||
ORDER BY t.priority;
|
||||
END$$
|
||||
DELIMITER ;
|
|
@ -0,0 +1,83 @@
|
|||
CREATE TABLE `vn`.`dmsRecover` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`ticketFk` int(11) DEFAULT NULL,
|
||||
`sign` text DEFAULT NULL,
|
||||
`created` timestamp NULL DEFAULT current_timestamp(),
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `ticketFk_idx` (`ticketFk`),
|
||||
CONSTRAINT `ticketFk` FOREIGN KEY (`ticketFk`) REFERENCES `ticket` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=31917 DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci;
|
||||
|
||||
ALTER TABLE `vn`.`delivery` ADD addressFk INT;
|
||||
|
||||
DROP PROCEDURE IF EXISTS `vn`.`route_getTickets`;
|
||||
|
||||
DELIMITER $$
|
||||
$$
|
||||
CREATE DEFINER=`root`@`localhost` PROCEDURE `vn`.`route_getTickets`(vRouteFk INT)
|
||||
BEGIN
|
||||
/**
|
||||
* Pasado un RouteFk devuelve la información
|
||||
* de sus tickets.
|
||||
*
|
||||
* @param vRouteFk
|
||||
* @select Información de los tickets
|
||||
*/
|
||||
SELECT *
|
||||
FROM (
|
||||
SELECT t.id Id,
|
||||
t.clientFk Client,
|
||||
a.id Address,
|
||||
a.nickname ClientName,
|
||||
t.packages Packages,
|
||||
a.street AddressName,
|
||||
a.postalCode PostalCode,
|
||||
a.city City,
|
||||
sub2.itemPackingTypeFk PackingType,
|
||||
c.phone ClientPhone,
|
||||
c.mobile ClientMobile,
|
||||
a.phone AddressPhone,
|
||||
a.mobile AddressMobile,
|
||||
d.longitude Longitude,
|
||||
d.latitude Latitude,
|
||||
wm.mediaValue SalePersonPhone,
|
||||
tob.description Note,
|
||||
t.isSigned Signed,
|
||||
t.priority
|
||||
FROM ticket t
|
||||
JOIN client c ON t.clientFk = c.id
|
||||
JOIN address a ON t.addressFk = a.id
|
||||
LEFT JOIN delivery d ON d.addressFk = a.id
|
||||
LEFT JOIN workerMedia wm ON wm.workerFk = c.salesPersonFk
|
||||
LEFT JOIN(
|
||||
SELECT tob.description, t.id
|
||||
FROM ticketObservation tob
|
||||
JOIN ticket t ON tob.ticketFk = t.id
|
||||
JOIN observationType ot ON ot.id = tob.observationTypeFk
|
||||
WHERE t.routeFk = vRouteFk
|
||||
AND ot.code = 'delivery'
|
||||
)tob ON tob.id = t.id
|
||||
LEFT JOIN(
|
||||
SELECT sub.ticketFk,
|
||||
CONCAT('(',
|
||||
GROUP_CONCAT(DISTINCT sub.itemPackingTypeFk
|
||||
ORDER BY sub.items DESC SEPARATOR ','),
|
||||
') ') itemPackingTypeFk
|
||||
FROM (
|
||||
SELECT s.ticketFk, i.itemPackingTypeFk, COUNT(*) items
|
||||
FROM ticket t
|
||||
JOIN sale s ON s.ticketFk = t.id
|
||||
JOIN item i ON i.id = s.itemFk
|
||||
WHERE t.routeFk = vRouteFk
|
||||
GROUP BY t.id, i.itemPackingTypeFk
|
||||
)sub
|
||||
GROUP BY sub.ticketFk
|
||||
)sub2 ON sub2.ticketFk = t.id
|
||||
WHERE t.routeFk = vRouteFk
|
||||
ORDER BY d.id DESC
|
||||
LIMIT 10000000000000000000
|
||||
)sub3
|
||||
GROUP BY sub3.id
|
||||
ORDER BY sub3.priority;
|
||||
END$$
|
||||
DELIMITER ;
|
|
@ -0,0 +1 @@
|
|||
DROP TRIGGER IF EXISTS `vn`.`claimBeginning_afterInsert`;
|
|
@ -0,0 +1,72 @@
|
|||
DROP TRIGGER IF EXISTS `vn`.`client_beforeUpdate`;
|
||||
USE `vn`;
|
||||
|
||||
DELIMITER $$
|
||||
$$
|
||||
CREATE DEFINER=`root`@`localhost` TRIGGER `vn`.`client_beforeUpdate`
|
||||
BEFORE UPDATE ON `client`
|
||||
FOR EACH ROW
|
||||
BEGIN
|
||||
DECLARE vText VARCHAR(255) DEFAULT NULL;
|
||||
DECLARE vPayMethodFk INT;
|
||||
-- Comprueba que el formato de los teléfonos es válido
|
||||
|
||||
IF !(NEW.phone <=> OLD.phone) AND (NEW.phone <> '') THEN
|
||||
CALL pbx.phone_isValid(NEW.phone);
|
||||
END IF;
|
||||
|
||||
IF !(NEW.mobile <=> OLD.mobile) AND (NEW.mobile <> '')THEN
|
||||
CALL pbx.phone_isValid(NEW.mobile);
|
||||
END IF;
|
||||
|
||||
SELECT id INTO vPayMethodFk
|
||||
FROM vn.payMethod
|
||||
WHERE code = 'bankDraft';
|
||||
|
||||
IF NEW.payMethodFk = vPayMethodFk AND NEW.dueDay = 0 THEN
|
||||
SET NEW.dueDay = 5;
|
||||
END IF;
|
||||
|
||||
-- Avisar al comercial si ha llegado la documentación sepa/core
|
||||
|
||||
IF NEW.hasSepaVnl AND !OLD.hasSepaVnl THEN
|
||||
SET vText = 'Sepa de VNL';
|
||||
END IF;
|
||||
|
||||
IF NEW.hasCoreVnl AND !OLD.hasCoreVnl THEN
|
||||
SET vText = 'Core de VNL';
|
||||
END IF;
|
||||
|
||||
IF vText IS NOT NULL
|
||||
THEN
|
||||
INSERT INTO mail(receiver, replyTo, `subject`, body)
|
||||
SELECT
|
||||
CONCAT(IF(ac.id,u.name, 'jgallego'), '@verdnatura.es'),
|
||||
'administracion@verdnatura.es',
|
||||
CONCAT('Cliente ', NEW.id),
|
||||
CONCAT('Recibida la documentación: ', vText)
|
||||
FROM worker w
|
||||
LEFT JOIN account.user u ON w.userFk = u.id AND u.active
|
||||
LEFT JOIN account.account ac ON ac.id = u.id
|
||||
WHERE w.id = NEW.salesPersonFk;
|
||||
END IF;
|
||||
|
||||
IF NEW.salespersonFk IS NULL AND OLD.salespersonFk IS NOT NULL THEN
|
||||
IF (SELECT COUNT(clientFk)
|
||||
FROM clientProtected
|
||||
WHERE clientFk = NEW.id
|
||||
) > 0 THEN
|
||||
CALL util.throw("HAS_CLIENT_PROTECTED");
|
||||
END IF;
|
||||
END IF;
|
||||
|
||||
IF !(NEW.salesPersonFk <=> OLD.salesPersonFk) THEN
|
||||
SET NEW.lastSalesPersonFk = IFNULL(NEW.salesPersonFk, OLD.salesPersonFk);
|
||||
END IF;
|
||||
|
||||
IF !(NEW.businessTypeFk <=> OLD.businessTypeFk) AND (NEW.businessTypeFk = 'individual' OR OLD.businessTypeFk = 'individual') THEN
|
||||
SET NEW.isTaxDataChecked = 0;
|
||||
END IF;
|
||||
|
||||
END$$
|
||||
DELIMITER ;
|
|
@ -0,0 +1,70 @@
|
|||
DROP TABLE IF EXISTS `vn`.`dmsRecover`;
|
||||
|
||||
ALTER TABLE `vn`.`delivery` DROP COLUMN addressFk;
|
||||
ALTER TABLE `vn`.`delivery` DROP CONSTRAINT delivery_ticketFk_FK;
|
||||
ALTER TABLE `vn`.`delivery` DROP COLUMN ticketFk;
|
||||
ALTER TABLE `vn`.`delivery` ADD ticketFk INT DEFAULT NULL;
|
||||
ALTER TABLE `vn`.`delivery` ADD CONSTRAINT delivery_ticketFk_FK FOREIGN KEY (`ticketFk`) REFERENCES `vn`.`ticket`(`id`);
|
||||
|
||||
DROP PROCEDURE IF EXISTS vn.route_getTickets;
|
||||
|
||||
DELIMITER $$
|
||||
$$
|
||||
CREATE DEFINER=`root`@`localhost` PROCEDURE `vn`.`route_getTickets`(vRouteFk INT)
|
||||
BEGIN
|
||||
/**
|
||||
* Pasado un RouteFk devuelve la información
|
||||
* de sus tickets.
|
||||
*
|
||||
* @param vRouteFk
|
||||
*
|
||||
* @select Información de los tickets
|
||||
*/
|
||||
|
||||
SELECT
|
||||
t.id Id,
|
||||
t.clientFk Client,
|
||||
a.id Address,
|
||||
t.packages Packages,
|
||||
a.street AddressName,
|
||||
a.postalCode PostalCode,
|
||||
a.city City,
|
||||
sub2.itemPackingTypeFk PackingType,
|
||||
c.phone ClientPhone,
|
||||
c.mobile ClientMobile,
|
||||
a.phone AddressPhone,
|
||||
a.mobile AddressMobile,
|
||||
d.longitude Longitude,
|
||||
d.latitude Latitude,
|
||||
wm.mediaValue SalePersonPhone,
|
||||
tob.Note Note,
|
||||
t.isSigned Signed
|
||||
FROM ticket t
|
||||
JOIN client c ON t.clientFk = c.id
|
||||
JOIN address a ON t.addressFk = a.id
|
||||
LEFT JOIN delivery d ON t.id = d.ticketFk
|
||||
LEFT JOIN workerMedia wm ON wm.workerFk = c.salesPersonFk
|
||||
LEFT JOIN
|
||||
(SELECT tob.description Note, t.id
|
||||
FROM ticketObservation tob
|
||||
JOIN ticket t ON tob.ticketFk = t.id
|
||||
JOIN observationType ot ON ot.id = tob.observationTypeFk
|
||||
WHERE t.routeFk = vRouteFk
|
||||
AND ot.code = 'delivery'
|
||||
)tob ON tob.id = t.id
|
||||
LEFT JOIN
|
||||
(SELECT sub.ticketFk,
|
||||
CONCAT('(', GROUP_CONCAT(DISTINCT sub.itemPackingTypeFk ORDER BY sub.items DESC SEPARATOR ','), ') ') itemPackingTypeFk
|
||||
FROM (SELECT s.ticketFk , i.itemPackingTypeFk, COUNT(*) items
|
||||
FROM ticket t
|
||||
JOIN sale s ON s.ticketFk = t.id
|
||||
JOIN item i ON i.id = s.itemFk
|
||||
WHERE t.routeFk = vRouteFk
|
||||
GROUP BY t.id,i.itemPackingTypeFk)sub
|
||||
GROUP BY sub.ticketFk
|
||||
) sub2 ON sub2.ticketFk = t.id
|
||||
WHERE t.routeFk = vRouteFk
|
||||
GROUP BY t.id
|
||||
ORDER BY t.priority;
|
||||
END$$
|
||||
DELIMITER ;
|
|
@ -0,0 +1,13 @@
|
|||
DROP TRIGGER IF EXISTS `vn`.`invoiceOut_afterInsert`;
|
||||
USE vn;
|
||||
|
||||
DELIMITER $$
|
||||
$$
|
||||
CREATE DEFINER=`root`@`localhost` TRIGGER `vn`.`invoiceOut_afterInsert`
|
||||
AFTER INSERT ON `invoiceOut`
|
||||
FOR EACH ROW
|
||||
BEGIN
|
||||
CALL clientRisk_update(NEW.clientFk, NEW.companyFk, NEW.amount);
|
||||
END$$
|
||||
DELIMITER ;
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`)
|
||||
VALUES
|
||||
('InvoiceIn', 'negativeBases', 'READ', 'ALLOW', 'ROLE', 'administrative'),
|
||||
('InvoiceIn', 'negativeBasesCsv', 'READ', 'ALLOW', 'ROLE', 'administrative');
|
|
@ -0,0 +1,14 @@
|
|||
CREATE TABLE `vn`.`workerObservation` (
|
||||
`id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`workerFk` int(10) unsigned DEFAULT NULL,
|
||||
`userFk` int(10) unsigned DEFAULT NULL,
|
||||
`text` text COLLATE utf8mb3_unicode_ci NOT NULL,
|
||||
`created` timestamp NOT NULL DEFAULT current_timestamp(),
|
||||
PRIMARY KEY (`id`),
|
||||
CONSTRAINT `workerFk_workerObservation_FK` FOREIGN KEY (`workerFk`) REFERENCES `vn`.`worker` (`id`) ON UPDATE CASCADE,
|
||||
CONSTRAINT `userFk_workerObservation_FK` FOREIGN KEY (`userFk`) REFERENCES `account`.`user`(`id`) ON UPDATE CASCADE
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci COMMENT='Todas las observaciones referentes a un trabajador';
|
||||
|
||||
INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`)
|
||||
VALUES
|
||||
('WorkerObservation', '*', '*', 'ALLOW', 'ROLE', 'hr');
|
|
@ -0,0 +1,21 @@
|
|||
create or replace definer = root@localhost view User as
|
||||
select `account`.`user`.`id` AS `id`,
|
||||
`account`.`user`.`realm` AS `realm`,
|
||||
`account`.`user`.`name` AS `name`,
|
||||
`account`.`user`.`nickname` AS `nickname`,
|
||||
`account`.`user`.`bcryptPassword` AS `password`,
|
||||
`account`.`user`.`role` AS `role`,
|
||||
`account`.`user`.`active` AS `active`,
|
||||
`account`.`user`.`email` AS `email`,
|
||||
`account`.`user`.`emailVerified` AS `emailVerified`,
|
||||
`account`.`user`.`verificationToken` AS `verificationToken`,
|
||||
`account`.`user`.`lang` AS `lang`,
|
||||
`account`.`user`.`lastPassChange` AS `lastPassChange`,
|
||||
`account`.`user`.`created` AS `created`,
|
||||
`account`.`user`.`updated` AS `updated`,
|
||||
`account`.`user`.`image` AS `image`,
|
||||
`account`.`user`.`recoverPass` AS `recoverPass`,
|
||||
`account`.`user`.`sync` AS `sync`,
|
||||
`account`.`user`.`hasGrant` AS `hasGrant`
|
||||
from `account`.`user`;
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`)
|
||||
VALUES
|
||||
('Defaulter', 'observationEmail', 'WRITE', 'ALLOW', 'ROLE', 'employee');
|
|
@ -0,0 +1,21 @@
|
|||
INSERT INTO `salix`.`ACL` (model, property, accessType, permission, principalType, principalId)
|
||||
VALUES
|
||||
('VnUser', '*', '*', 'ALLOW', 'ROLE', 'employee'),
|
||||
('VnUser','acl','READ','ALLOW','ROLE','account'),
|
||||
('VnUser','getCurrentUserData','READ','ALLOW','ROLE','account'),
|
||||
('VnUser','changePassword', 'WRITE', 'ALLOW', 'ROLE', 'account'),
|
||||
('Account','exists','READ','ALLOW','ROLE','account');
|
||||
|
||||
INSERT INTO `salix`.`ACL` (model, property, accessType, permission, principalType, principalId)
|
||||
VALUES
|
||||
('Account','exists','READ','ALLOW','ROLE','account');
|
||||
|
||||
DELETE FROM `salix`.`ACL` WHERE (model, property) = ('Account', 'acl');
|
||||
DELETE FROM `salix`.`ACL` WHERE (model, property) = ('Account', 'getCurrentUserData');
|
||||
DELETE FROM `salix`.`ACL` WHERE (model, property) = ('Account', 'changePassword');
|
||||
DELETE FROM `salix`.`ACL` WHERE model = 'UserAccount';
|
||||
|
||||
UPDATE `hedera`.`imageCollection` t
|
||||
SET t.model = 'VnUser'
|
||||
WHERE t.id = 6;
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`)
|
||||
VALUES
|
||||
('UserLog', '*', 'READ', 'ALLOW', 'ROLE', 'employee'),
|
||||
('RoleLog', '*', 'READ', 'ALLOW', 'ROLE', 'employee');
|
|
@ -98,20 +98,20 @@ INSERT INTO `hedera`.`tpvConfig`(`id`, `currency`, `terminal`, `transactionType`
|
|||
VALUES
|
||||
(1, 978, 1, 0, 2000, 9, 0);
|
||||
|
||||
INSERT INTO `account`.`user`(`id`,`name`,`nickname`, `password`,`role`,`active`,`email`,`lang`, `image`)
|
||||
INSERT INTO `account`.`user`(`id`,`name`,`nickname`, `bcryptPassword`, `password`,`role`,`active`,`email`,`lang`, `image`)
|
||||
VALUES
|
||||
(1101, 'BruceWayne', 'Bruce Wayne', 'ac754a330530832ba1bf7687f577da91', 2, 1, 'BruceWayne@mydomain.com', 'es', 'e7723f0b24ff05b32ed09d95196f2f29'),
|
||||
(1102, 'PetterParker', 'Petter Parker', 'ac754a330530832ba1bf7687f577da91', 2, 1, 'PetterParker@mydomain.com', 'en', 'e7723f0b24ff05b32ed09d95196f2f29'),
|
||||
(1103, 'ClarkKent', 'Clark Kent', 'ac754a330530832ba1bf7687f577da91', 2, 1, 'ClarkKent@mydomain.com', 'fr', 'e7723f0b24ff05b32ed09d95196f2f29'),
|
||||
(1104, 'TonyStark', 'Tony Stark', 'ac754a330530832ba1bf7687f577da91', 2, 1, 'TonyStark@mydomain.com', 'es', 'e7723f0b24ff05b32ed09d95196f2f29'),
|
||||
(1105, 'MaxEisenhardt', 'Max Eisenhardt', 'ac754a330530832ba1bf7687f577da91', 2, 1, 'MaxEisenhardt@mydomain.com', 'pt', 'e7723f0b24ff05b32ed09d95196f2f29'),
|
||||
(1106, 'DavidCharlesHaller', 'David Charles Haller', 'ac754a330530832ba1bf7687f577da91', 1, 1, 'DavidCharlesHaller@mydomain.com', 'en', 'e7723f0b24ff05b32ed09d95196f2f29'),
|
||||
(1107, 'HankPym', 'Hank Pym', 'ac754a330530832ba1bf7687f577da91', 1, 1, 'HankPym@mydomain.com', 'en', 'e7723f0b24ff05b32ed09d95196f2f29'),
|
||||
(1108, 'CharlesXavier', 'Charles Xavier', 'ac754a330530832ba1bf7687f577da91', 1, 1, 'CharlesXavier@mydomain.com', 'en', 'e7723f0b24ff05b32ed09d95196f2f29'),
|
||||
(1109, 'BruceBanner', 'Bruce Banner', 'ac754a330530832ba1bf7687f577da91', 1, 1, 'BruceBanner@mydomain.com', 'en', 'e7723f0b24ff05b32ed09d95196f2f29'),
|
||||
(1110, 'JessicaJones', 'Jessica Jones', 'ac754a330530832ba1bf7687f577da91', 1, 1, 'JessicaJones@mydomain.com', 'en', NULL),
|
||||
(1111, 'Missing', 'Missing', 'ac754a330530832ba1bf7687f577da91', 2, 0, NULL, 'en', NULL),
|
||||
(1112, 'Trash', 'Trash', 'ac754a330530832ba1bf7687f577da91', 2, 0, NULL, 'en', NULL);
|
||||
(1101, 'BruceWayne', 'Bruce Wayne', '$2b$10$UzQHth.9UUQ1T5aiQJ21lOU0oVlbxoqH4PFM9V8T90KNSAcg0eEL2', 'ac754a330530832ba1bf7687f577da91', 2, 1, 'BruceWayne@mydomain.com', 'es', 'e7723f0b24ff05b32ed09d95196f2f29'),
|
||||
(1102, 'PetterParker', 'Petter Parker', '$2b$10$UzQHth.9UUQ1T5aiQJ21lOU0oVlbxoqH4PFM9V8T90KNSAcg0eEL2', 'ac754a330530832ba1bf7687f577da91', 2, 1, 'PetterParker@mydomain.com', 'en', 'e7723f0b24ff05b32ed09d95196f2f29'),
|
||||
(1103, 'ClarkKent', 'Clark Kent', '$2b$10$UzQHth.9UUQ1T5aiQJ21lOU0oVlbxoqH4PFM9V8T90KNSAcg0eEL2', 'ac754a330530832ba1bf7687f577da91', 2, 1, 'ClarkKent@mydomain.com', 'fr', 'e7723f0b24ff05b32ed09d95196f2f29'),
|
||||
(1104, 'TonyStark', 'Tony Stark', '$2b$10$UzQHth.9UUQ1T5aiQJ21lOU0oVlbxoqH4PFM9V8T90KNSAcg0eEL2', 'ac754a330530832ba1bf7687f577da91', 2, 1, 'TonyStark@mydomain.com', 'es', 'e7723f0b24ff05b32ed09d95196f2f29'),
|
||||
(1105, 'MaxEisenhardt', 'Max Eisenhardt', '$2b$10$UzQHth.9UUQ1T5aiQJ21lOU0oVlbxoqH4PFM9V8T90KNSAcg0eEL2', 'ac754a330530832ba1bf7687f577da91', 2, 1, 'MaxEisenhardt@mydomain.com', 'pt', 'e7723f0b24ff05b32ed09d95196f2f29'),
|
||||
(1106, 'DavidCharlesHaller', 'David Charles Haller', '$2b$10$UzQHth.9UUQ1T5aiQJ21lOU0oVlbxoqH4PFM9V8T90KNSAcg0eEL2', 'ac754a330530832ba1bf7687f577da91', 1, 1, 'DavidCharlesHaller@mydomain.com', 'en', 'e7723f0b24ff05b32ed09d95196f2f29'),
|
||||
(1107, 'HankPym', 'Hank Pym', '$2b$10$UzQHth.9UUQ1T5aiQJ21lOU0oVlbxoqH4PFM9V8T90KNSAcg0eEL2', 'ac754a330530832ba1bf7687f577da91', 1, 1, 'HankPym@mydomain.com', 'en', 'e7723f0b24ff05b32ed09d95196f2f29'),
|
||||
(1108, 'CharlesXavier', 'Charles Xavier', '$2b$10$UzQHth.9UUQ1T5aiQJ21lOU0oVlbxoqH4PFM9V8T90KNSAcg0eEL2', 'ac754a330530832ba1bf7687f577da91', 1, 1, 'CharlesXavier@mydomain.com', 'en', 'e7723f0b24ff05b32ed09d95196f2f29'),
|
||||
(1109, 'BruceBanner', 'Bruce Banner', '$2b$10$UzQHth.9UUQ1T5aiQJ21lOU0oVlbxoqH4PFM9V8T90KNSAcg0eEL2', 'ac754a330530832ba1bf7687f577da91', 1, 1, 'BruceBanner@mydomain.com', 'en', 'e7723f0b24ff05b32ed09d95196f2f29'),
|
||||
(1110, 'JessicaJones', 'Jessica Jones', '$2b$10$UzQHth.9UUQ1T5aiQJ21lOU0oVlbxoqH4PFM9V8T90KNSAcg0eEL2', 'ac754a330530832ba1bf7687f577da91', 1, 1, 'JessicaJones@mydomain.com', 'en', NULL),
|
||||
(1111, 'Missing', 'Missing', '$2b$10$UzQHth.9UUQ1T5aiQJ21lOU0oVlbxoqH4PFM9V8T90KNSAcg0eEL2', 'ac754a330530832ba1bf7687f577da91', 2, 0, NULL, 'en', NULL),
|
||||
(1112, 'Trash', 'Trash', '$2b$10$UzQHth.9UUQ1T5aiQJ21lOU0oVlbxoqH4PFM9V8T90KNSAcg0eEL2', 'ac754a330530832ba1bf7687f577da91', 2, 0, NULL, 'en', NULL);
|
||||
|
||||
INSERT INTO `account`.`mailAlias`(`id`, `alias`, `description`, `isPublic`)
|
||||
VALUES
|
||||
|
@ -1774,12 +1774,12 @@ INSERT INTO `vn`.`claimState`(`id`, `code`, `description`, `roleFk`, `priority`,
|
|||
( 6, 'mana', 'Mana', 72, 4, 0),
|
||||
( 7, 'lack', 'Faltas', 72, 2, 0);
|
||||
|
||||
INSERT INTO `vn`.`claim`(`id`, `ticketCreated`, `claimStateFk`, `clientFk`, `workerFk`, `responsibility`, `isChargedToMana`, `created`, `packages`, `rma`)
|
||||
INSERT INTO `vn`.`claim`(`id`, `ticketCreated`, `claimStateFk`, `clientFk`, `workerFk`, `responsibility`, `isChargedToMana`, `created`, `packages`, `rma`, `ticketFk`)
|
||||
VALUES
|
||||
(1, util.VN_CURDATE(), 1, 1101, 18, 3, 0, util.VN_CURDATE(), 0, '02676A049183'),
|
||||
(2, util.VN_CURDATE(), 2, 1101, 18, 3, 0, util.VN_CURDATE(), 1, NULL),
|
||||
(3, util.VN_CURDATE(), 3, 1101, 18, 1, 1, util.VN_CURDATE(), 5, NULL),
|
||||
(4, util.VN_CURDATE(), 3, 1104, 18, 5, 0, util.VN_CURDATE(), 10, NULL);
|
||||
(1, util.VN_CURDATE(), 1, 1101, 18, 3, 0, util.VN_CURDATE(), 0, '02676A049183', 11),
|
||||
(2, util.VN_CURDATE(), 2, 1101, 18, 3, 0, util.VN_CURDATE(), 1, NULL, 16),
|
||||
(3, util.VN_CURDATE(), 3, 1101, 18, 1, 1, util.VN_CURDATE(), 5, NULL, 7),
|
||||
(4, util.VN_CURDATE(), 3, 1104, 18, 5, 0, util.VN_CURDATE(), 10, NULL, 8);
|
||||
|
||||
INSERT INTO `vn`.`claimObservation` (`claimFk`, `workerFk`, `text`, `created`)
|
||||
VALUES
|
||||
|
|
|
@ -414,7 +414,7 @@ export default {
|
|||
saveFieldsButton: '.vn-popover.shown vn-button[label="Save"] > button'
|
||||
},
|
||||
itemFixedPrice: {
|
||||
add: 'vn-fixed-price vn-icon-button[icon="add_circle"]',
|
||||
add: 'vn-fixed-price vn-icon-button[vn-tooltip="Add fixed price"]',
|
||||
firstItemID: 'vn-fixed-price tr:nth-child(2) vn-autocomplete[ng-model="price.itemFk"]',
|
||||
fourthFixedPrice: 'vn-fixed-price tr:nth-child(5)',
|
||||
fourthItemID: 'vn-fixed-price tr:nth-child(5) vn-autocomplete[ng-model="price.itemFk"]',
|
||||
|
@ -426,7 +426,19 @@ export default {
|
|||
fourthStarted: 'vn-fixed-price tr:nth-child(5) vn-date-picker[ng-model="price.started"]',
|
||||
fourthEnded: 'vn-fixed-price tr:nth-child(5) vn-date-picker[ng-model="price.ended"]',
|
||||
fourthDeleteIcon: 'vn-fixed-price tr:nth-child(5) > td:nth-child(9) > vn-icon-button[icon="delete"]',
|
||||
orderColumnId: 'vn-fixed-price th[field="itemFk"]'
|
||||
orderColumnId: 'vn-fixed-price th[field="itemFk"]',
|
||||
removeWarehouseFilter: 'vn-searchbar > form > vn-textfield > div.container > div.prepend > prepend > div > span:nth-child(1) > vn-icon > i',
|
||||
generalSearchFilter: 'vn-fixed-price-search-panel vn-textfield[ng-model="$ctrl.filter.search"]',
|
||||
reignFilter: 'vn-fixed-price-search-panel vn-horizontal.item-category vn-one',
|
||||
typeFilter: 'vn-fixed-price-search-panel vn-autocomplete[ng-model="$ctrl.filter.typeFk"]',
|
||||
buyerFilter: 'vn-fixed-price-search-panel vn-autocomplete[ng-model="$ctrl.filter.buyerFk"]',
|
||||
warehouseFilter: 'vn-fixed-price-search-panel vn-autocomplete[ng-model="$ctrl.filter.warehouseFk"]',
|
||||
mineFilter: 'vn-fixed-price-search-panel vn-check[ng-model="$ctrl.filter.mine"]',
|
||||
hasMinPriceFilter: 'vn-fixed-price-search-panel vn-check[ng-model="$ctrl.filter.hasMinPrice"]',
|
||||
addTag: 'vn-fixed-price-search-panel vn-icon-button[icon="add_circle"]',
|
||||
tagFilter: 'vn-fixed-price-search-panel vn-autocomplete[ng-model="itemTag.tagFk"]',
|
||||
tagValueFilter: 'vn-fixed-price-search-panel vn-autocomplete[ng-model="itemTag.value"]',
|
||||
chip: 'vn-fixed-price-search-panel vn-chip > vn-icon'
|
||||
},
|
||||
itemCreateView: {
|
||||
temporalName: 'vn-item-create vn-textfield[ng-model="$ctrl.item.provisionalName"]',
|
||||
|
@ -987,6 +999,12 @@ export default {
|
|||
locker: 'vn-worker-basic-data vn-input-number[ng-model="$ctrl.worker.locker"]',
|
||||
saveButton: 'vn-worker-basic-data button[type=submit]'
|
||||
},
|
||||
workerNotes: {
|
||||
addNoteFloatButton: 'vn-worker-note vn-icon[icon="add"]',
|
||||
note: 'vn-note-worker-create vn-textarea[ng-model="$ctrl.note.text"]',
|
||||
saveButton: 'vn-note-worker-create button[type=submit]',
|
||||
firstNoteText: 'vn-worker-note .text'
|
||||
},
|
||||
workerPbx: {
|
||||
extension: 'vn-worker-pbx vn-textfield[ng-model="$ctrl.worker.sip.extension"]',
|
||||
saveButton: 'vn-worker-pbx button[type=submit]'
|
||||
|
|
|
@ -90,7 +90,7 @@ describe('SmartTable SearchBar integration', () => {
|
|||
await page.waitToClick(selectors.itemFixedPrice.orderColumnId);
|
||||
const result = await page.waitToGetProperty(selectors.itemFixedPrice.firstItemID, 'value');
|
||||
|
||||
expect(result).toEqual('13');
|
||||
expect(result).toEqual('3');
|
||||
});
|
||||
|
||||
it('should reload page and have same order', async() => {
|
||||
|
@ -99,7 +99,7 @@ describe('SmartTable SearchBar integration', () => {
|
|||
});
|
||||
const result = await page.waitToGetProperty(selectors.itemFixedPrice.firstItemID, 'value');
|
||||
|
||||
expect(result).toEqual('13');
|
||||
expect(result).toEqual('3');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -28,22 +28,4 @@ describe('Client log path', () => {
|
|||
it('should navigate to the log section', async() => {
|
||||
await page.accessToSection('client.card.log');
|
||||
});
|
||||
|
||||
it('should check the previous value of the last logged change', async() => {
|
||||
let lastModificationPreviousValue = await page
|
||||
.waitToGetProperty(selectors.clientLog.lastModificationPreviousValue, 'innerText');
|
||||
|
||||
expect(lastModificationPreviousValue).toContain('DavidCharlesHaller');
|
||||
});
|
||||
|
||||
it('should check the current value of the last logged change', async() => {
|
||||
let lastModificationPreviousValue = await page
|
||||
.waitToGetProperty(selectors.clientLog.lastModificationPreviousValue, 'innerText');
|
||||
|
||||
let lastModificationCurrentValue = await page.
|
||||
waitToGetProperty(selectors.clientLog.lastModificationCurrentValue, 'innerText');
|
||||
|
||||
expect(lastModificationPreviousValue).toEqual('DavidCharlesHaller');
|
||||
expect(lastModificationCurrentValue).toEqual('this is a test');
|
||||
});
|
||||
});
|
||||
|
|
|
@ -50,7 +50,7 @@ describe('Client defaulter path', () => {
|
|||
expect(message.text).toContain(`The message can't be empty`);
|
||||
});
|
||||
|
||||
it('shoul checked all defaulters', async() => {
|
||||
it('should checked all defaulters', async() => {
|
||||
await page.loginAndModule('insurance', 'client');
|
||||
await page.accessToSection('client.defaulter');
|
||||
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
import selectors from '../../helpers/selectors';
|
||||
import getBrowser from '../../helpers/puppeteer';
|
||||
|
||||
describe('Worker Add notes path', () => {
|
||||
let browser;
|
||||
let page;
|
||||
beforeAll(async() => {
|
||||
browser = await getBrowser();
|
||||
page = browser.page;
|
||||
await page.loginAndModule('hr', 'worker');
|
||||
await page.accessToSearchResult('Bruce Banner');
|
||||
await page.accessToSection('worker.card.note.index');
|
||||
});
|
||||
|
||||
afterAll(async() => {
|
||||
await browser.close();
|
||||
});
|
||||
|
||||
it(`should reach the notes index`, async() => {
|
||||
await page.waitForState('worker.card.note.index');
|
||||
});
|
||||
|
||||
it(`should click on the add note button`, async() => {
|
||||
await page.waitToClick(selectors.workerNotes.addNoteFloatButton);
|
||||
await page.waitForState('worker.card.note.create');
|
||||
});
|
||||
|
||||
it(`should create a note`, async() => {
|
||||
await page.waitForSelector(selectors.workerNotes.note);
|
||||
await page.type(`${selectors.workerNotes.note} textarea`, 'Meeting with Black Widow 21st 9am');
|
||||
await page.waitToClick(selectors.workerNotes.saveButton);
|
||||
const message = await page.waitForSnackbar();
|
||||
|
||||
expect(message.text).toContain('Data saved!');
|
||||
});
|
||||
|
||||
it('should confirm the note was created', async() => {
|
||||
const result = await page.waitToGetProperty(selectors.workerNotes.firstNoteText, 'innerText');
|
||||
|
||||
expect(result).toEqual('Meeting with Black Widow 21st 9am');
|
||||
});
|
||||
});
|
|
@ -42,23 +42,4 @@ describe('Item log path', () => {
|
|||
await page.waitForSelector(selectors.itemsIndex.createItemButton);
|
||||
await page.waitForState('item.index');
|
||||
});
|
||||
|
||||
it(`should search for the created item and navigate to it's log section`, async() => {
|
||||
await page.accessToSearchResult('Knowledge artifact');
|
||||
await page.accessToSection('item.card.log');
|
||||
});
|
||||
|
||||
it(`should confirm the log is showing 4 entries`, async() => {
|
||||
await page.waitForSelector(selectors.itemLog.anyLineCreated);
|
||||
const anyLineCreatedCount = await page.countElement(selectors.itemLog.anyLineCreated);
|
||||
|
||||
expect(anyLineCreatedCount).toEqual(4);
|
||||
});
|
||||
|
||||
xit(`should confirm the log is showing the intrastat for the created item`, async() => {
|
||||
const fifthLineCreatedProperty = await page
|
||||
.waitToGetProperty(selectors.itemLog.fifthLineCreatedProperty, 'innerText');
|
||||
|
||||
expect(fifthLineCreatedProperty).toEqual('05080000');
|
||||
});
|
||||
});
|
||||
|
|
|
@ -4,19 +4,69 @@ import getBrowser from '../../helpers/puppeteer';
|
|||
describe('Item fixed prices path', () => {
|
||||
let browser;
|
||||
let page;
|
||||
let httpRequest;
|
||||
|
||||
beforeAll(async() => {
|
||||
browser = await getBrowser();
|
||||
page = browser.page;
|
||||
await page.loginAndModule('buyer', 'item');
|
||||
await page.accessToSection('item.fixedPrice');
|
||||
page.on('request', req => {
|
||||
if (req.url().includes(`FixedPrices/filter`))
|
||||
httpRequest = req.url();
|
||||
});
|
||||
});
|
||||
|
||||
afterAll(async() => {
|
||||
await browser.close();
|
||||
});
|
||||
|
||||
it('should click on the add new foxed price button', async() => {
|
||||
await page.doSearch();
|
||||
it('should filter using all the fields', async() => {
|
||||
await page.write(selectors.itemFixedPrice.generalSearchFilter, 'item');
|
||||
await page.keyboard.press('Enter');
|
||||
|
||||
expect(httpRequest).toContain('search=item');
|
||||
|
||||
await page.click(selectors.itemFixedPrice.chip);
|
||||
await page.click(selectors.itemFixedPrice.reignFilter);
|
||||
|
||||
expect(httpRequest).toContain('categoryFk');
|
||||
|
||||
await page.autocompleteSearch(selectors.itemFixedPrice.typeFilter, 'Alstroemeria');
|
||||
|
||||
expect(httpRequest).toContain('typeFk');
|
||||
|
||||
await page.click(selectors.itemFixedPrice.chip);
|
||||
await page.autocompleteSearch(selectors.itemFixedPrice.buyerFilter, 'buyerNick');
|
||||
|
||||
expect(httpRequest).toContain('buyerFk');
|
||||
|
||||
await page.click(selectors.itemFixedPrice.chip);
|
||||
await page.autocompleteSearch(selectors.itemFixedPrice.warehouseFilter, 'Algemesi');
|
||||
|
||||
expect(httpRequest).toContain('warehouseFk');
|
||||
|
||||
await page.click(selectors.itemFixedPrice.chip);
|
||||
await page.click(selectors.itemFixedPrice.mineFilter);
|
||||
|
||||
expect(httpRequest).toContain('mine=true');
|
||||
|
||||
await page.click(selectors.itemFixedPrice.chip);
|
||||
await page.click(selectors.itemFixedPrice.hasMinPriceFilter);
|
||||
|
||||
expect(httpRequest).toContain('hasMinPrice=true');
|
||||
|
||||
await page.click(selectors.itemFixedPrice.chip);
|
||||
await page.click(selectors.itemFixedPrice.addTag);
|
||||
await page.autocompleteSearch(selectors.itemFixedPrice.tagFilter, 'Color');
|
||||
await page.autocompleteSearch(selectors.itemFixedPrice.tagValueFilter, 'Brown');
|
||||
|
||||
expect(httpRequest).toContain('tags');
|
||||
|
||||
await page.click(selectors.itemFixedPrice.chip);
|
||||
});
|
||||
|
||||
it('should click on the add new fixed price button', async() => {
|
||||
await page.waitToClick(selectors.itemFixedPrice.add);
|
||||
await page.waitForSelector(selectors.itemFixedPrice.fourthFixedPrice);
|
||||
});
|
||||
|
@ -35,9 +85,7 @@ describe('Item fixed prices path', () => {
|
|||
});
|
||||
|
||||
it('should reload the section and check the created price has the expected ID', async() => {
|
||||
await page.accessToSection('item.index');
|
||||
await page.accessToSection('item.fixedPrice');
|
||||
await page.doSearch();
|
||||
await page.goto(`http://localhost:5000/#!/item/fixed-price`);
|
||||
|
||||
const result = await page.waitToGetProperty(selectors.itemFixedPrice.fourthItemID, 'value');
|
||||
|
||||
|
|
|
@ -249,6 +249,7 @@ describe('Ticket Edit sale path', () => {
|
|||
await page.waitToClick(selectors.ticketSales.thirdSaleCheckbox);
|
||||
await page.waitToClick(selectors.ticketSales.moreMenu);
|
||||
await page.waitToClick(selectors.ticketSales.moreMenuCreateClaim);
|
||||
await page.waitToClick(selectors.globalItems.acceptButton);
|
||||
await page.waitForState('claim.card.basicData');
|
||||
});
|
||||
|
||||
|
|
|
@ -29,20 +29,4 @@ describe('Ticket expeditions and log path', () => {
|
|||
|
||||
expect(result).toEqual(3);
|
||||
});
|
||||
|
||||
it(`should confirm the expedition deleted is shown now in the ticket log`, async() => {
|
||||
await page.accessToSection('ticket.card.log');
|
||||
const user = await page
|
||||
.waitToGetProperty(selectors.ticketLog.user, 'innerText');
|
||||
|
||||
const action = await page
|
||||
.waitToGetProperty(selectors.ticketLog.action, 'innerText');
|
||||
|
||||
const id = await page
|
||||
.waitToGetProperty(selectors.ticketLog.id, 'innerText');
|
||||
|
||||
expect(user).toContain('production');
|
||||
expect(action).toContain('Deletes');
|
||||
expect(id).toEqual('2');
|
||||
});
|
||||
});
|
||||
|
|
|
@ -31,30 +31,4 @@ describe('Ticket log path', () => {
|
|||
|
||||
expect(message.text).toContain('Data saved!');
|
||||
});
|
||||
|
||||
it('should navigate to the log section', async() => {
|
||||
await page.accessToSection('ticket.card.log');
|
||||
});
|
||||
|
||||
it('should set the viewport width to 1920 to see the table full width', async() => {
|
||||
await page.setViewport({
|
||||
width: 1920,
|
||||
height: 0,
|
||||
});
|
||||
|
||||
const result = await page.waitToGetProperty(selectors.ticketLog.firstTD, 'innerText');
|
||||
|
||||
expect(result.length).not.toBeGreaterThan('20');
|
||||
});
|
||||
|
||||
it('should set the viewport width to 800 to see the table shrink and move data to the 1st column', async() => {
|
||||
await page.setViewport({
|
||||
width: 800,
|
||||
height: 0,
|
||||
});
|
||||
|
||||
const result = await page.waitToGetProperty(selectors.ticketLog.firstTD, 'innerText');
|
||||
|
||||
expect(result.length).toBeGreaterThan('15');
|
||||
});
|
||||
});
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
import getBrowser from '../../helpers/puppeteer';
|
||||
|
||||
describe('InvoiceIn negative bases path', () => {
|
||||
let browser;
|
||||
let page;
|
||||
const httpRequests = [];
|
||||
|
||||
beforeAll(async() => {
|
||||
browser = await getBrowser();
|
||||
page = browser.page;
|
||||
page.on('request', req => {
|
||||
if (req.url().includes(`InvoiceIns/negativeBases`))
|
||||
httpRequests.push(req.url());
|
||||
});
|
||||
await page.loginAndModule('administrative', 'invoiceIn');
|
||||
await page.accessToSection('invoiceIn.negative-bases');
|
||||
});
|
||||
|
||||
afterAll(async() => {
|
||||
await browser.close();
|
||||
});
|
||||
|
||||
it('should show negative bases in a date range', async() => {
|
||||
const request = httpRequests.find(req =>
|
||||
req.includes(`from`) && req.includes(`to`));
|
||||
|
||||
expect(request).toBeDefined();
|
||||
});
|
||||
});
|
|
@ -29,14 +29,4 @@ describe('Zone descriptor path', () => {
|
|||
|
||||
expect(count).toEqual(0);
|
||||
});
|
||||
|
||||
it('should check the ticket whom lost the zone and see evidence on the logs', async() => {
|
||||
await page.waitToClick(selectors.globalItems.homeButton);
|
||||
await page.selectModule('ticket');
|
||||
await page.accessToSearchResult('20');
|
||||
await page.accessToSection('ticket.card.log');
|
||||
const lastChanges = await page.waitToGetProperty(selectors.ticketLog.changes, 'innerText');
|
||||
|
||||
expect(lastChanges).toContain('1');
|
||||
});
|
||||
});
|
||||
|
|
|
@ -64,14 +64,4 @@ describe('Supplier basic data path', () => {
|
|||
|
||||
expect(result).toEqual('Some notes');
|
||||
});
|
||||
|
||||
it('should navigate to the log section', async() => {
|
||||
await page.accessToSection('supplier.card.log');
|
||||
});
|
||||
|
||||
it('should check the changes have been recorded', async() => {
|
||||
const result = await page.waitToGetProperty('vn-tr table tr:nth-child(3) td.after', 'innerText');
|
||||
|
||||
expect(result).toEqual('Some notes');
|
||||
});
|
||||
});
|
||||
|
|
|
@ -23,7 +23,7 @@ describe('Account ACL path', () => {
|
|||
|
||||
it('should create new acl', async() => {
|
||||
await page.autocompleteSearch(selectors.accountAcl.role, 'sysadmin');
|
||||
await page.autocompleteSearch(selectors.accountAcl.model, 'UserAccount');
|
||||
await page.autocompleteSearch(selectors.accountAcl.model, 'Account');
|
||||
await page.autocompleteSearch(selectors.accountAcl.accessType, '*');
|
||||
await page.autocompleteSearch(selectors.accountAcl.permission, 'ALLOW');
|
||||
await page.waitToClick(selectors.accountAcl.save);
|
||||
|
|
|
@ -7,7 +7,7 @@ describe('Directive acl', () => {
|
|||
beforeEach(ngModule('vnCore'));
|
||||
|
||||
beforeEach(inject(($httpBackend, aclService) => {
|
||||
$httpBackend.whenGET('Accounts/acl')
|
||||
$httpBackend.whenGET('VnUsers/acl')
|
||||
.respond({
|
||||
user: {id: 1, name: 'myUser'},
|
||||
roles: [
|
||||
|
|
|
@ -4,7 +4,7 @@ describe('Service acl', () => {
|
|||
beforeEach(ngModule('vnCore'));
|
||||
|
||||
beforeEach(inject((_aclService_, $httpBackend) => {
|
||||
$httpBackend.when('GET', `Accounts/acl`).respond({
|
||||
$httpBackend.when('GET', `VnUsers/acl`).respond({
|
||||
roles: [
|
||||
{role: {name: 'foo'}},
|
||||
{role: {name: 'bar'}},
|
||||
|
|
|
@ -11,7 +11,7 @@ class AclService {
|
|||
}
|
||||
|
||||
load() {
|
||||
return this.$http.get('Accounts/acl').then(async res => {
|
||||
return this.$http.get('VnUsers/acl').then(async res => {
|
||||
this.user = res.data.user;
|
||||
this.roles = {};
|
||||
|
||||
|
|
|
@ -59,7 +59,7 @@ export default class Auth {
|
|||
password: password || undefined
|
||||
};
|
||||
|
||||
return this.$http.post('Accounts/login', params).then(
|
||||
return this.$http.post('VnUsers/signIn', params).then(
|
||||
json => this.onLoginOk(json, remember));
|
||||
}
|
||||
|
||||
|
@ -76,7 +76,7 @@ export default class Auth {
|
|||
}
|
||||
|
||||
logout() {
|
||||
let promise = this.$http.post('Accounts/logout', null, {
|
||||
let promise = this.$http.post('VnUsers/logout', null, {
|
||||
headers: {Authorization: this.vnToken.token}
|
||||
}).catch(() => {});
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ export class Layout extends Component {
|
|||
}
|
||||
|
||||
getUserData() {
|
||||
this.$http.get('Accounts/getCurrentUserData').then(json => {
|
||||
this.$http.get('VnUsers/getCurrentUserData').then(json => {
|
||||
this.$.$root.user = json.data;
|
||||
window.localStorage.currentUserWorkerId = json.data.id;
|
||||
});
|
||||
|
|
|
@ -15,7 +15,7 @@ describe('Component vnLayout', () => {
|
|||
|
||||
describe('getUserData()', () => {
|
||||
it(`should set the user name property in the controller`, () => {
|
||||
$httpBackend.expect('GET', `Accounts/getCurrentUserData`).respond({name: 'batman'});
|
||||
$httpBackend.expect('GET', `VnUsers/getCurrentUserData`).respond({name: 'batman'});
|
||||
controller.getUserData();
|
||||
$httpBackend.flush();
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ export default class Controller {
|
|||
user: this.user
|
||||
};
|
||||
|
||||
this.$http.post('Accounts/recoverPassword', params)
|
||||
this.$http.post('VnUsers/recoverPassword', params)
|
||||
.then(() => {
|
||||
this.goToLogin();
|
||||
});
|
||||
|
|
|
@ -162,14 +162,8 @@ export default class UploadPhoto extends Component {
|
|||
if (!this.newPhoto.files)
|
||||
throw new Error(`Select an image`);
|
||||
|
||||
const viewportType = this.viewportSelection;
|
||||
const output = viewportType.output;
|
||||
const options = {
|
||||
type: 'blob',
|
||||
size: {
|
||||
width: output.width,
|
||||
height: output.height
|
||||
}
|
||||
};
|
||||
return this.editor.result(options)
|
||||
.then(blob => this.newPhoto.blob = blob)
|
||||
|
|
|
@ -1,6 +1,20 @@
|
|||
const app = require('vn-loopback/server/server');
|
||||
const LoopBackContext = require('loopback-context');
|
||||
|
||||
describe('Model crud()', () => {
|
||||
beforeAll(async() => {
|
||||
const activeCtx = {
|
||||
accessToken: {userId: 9},
|
||||
http: {
|
||||
req: {
|
||||
headers: {origin: 'http://localhost'}
|
||||
}
|
||||
}
|
||||
};
|
||||
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({
|
||||
active: activeCtx
|
||||
});
|
||||
});
|
||||
let insertId;
|
||||
const barcodeModel = app.models.ItemBarcode;
|
||||
|
||||
|
|
|
@ -1,6 +1,21 @@
|
|||
const models = require('vn-loopback/server/server').models;
|
||||
const LoopBackContext = require('loopback-context');
|
||||
|
||||
describe('Model rewriteDbError()', () => {
|
||||
beforeAll(async() => {
|
||||
const activeCtx = {
|
||||
accessToken: {userId: 9},
|
||||
http: {
|
||||
req: {
|
||||
headers: {origin: 'http://localhost'}
|
||||
}
|
||||
}
|
||||
};
|
||||
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({
|
||||
active: activeCtx
|
||||
});
|
||||
});
|
||||
|
||||
it('should extend rewriteDbError properties to any model passed', () => {
|
||||
const exampleModel = models.ItemTag;
|
||||
|
||||
|
|
|
@ -229,7 +229,7 @@ module.exports = function(Self) {
|
|||
async checkAcls(ctx, actionType) {
|
||||
let userId = ctx.req.accessToken.userId;
|
||||
let models = this.app.models;
|
||||
let userRoles = await models.Account.getRoles(userId);
|
||||
let userRoles = await models.VnUser.getRoles(userId);
|
||||
let data = ctx.args.data;
|
||||
let modelAcls;
|
||||
|
||||
|
|
|
@ -154,5 +154,8 @@
|
|||
"Valid priorities: 1,2,3": "Valid priorities: 1,2,3",
|
||||
"Warehouse inventory not set": "Almacén inventario no está establecido",
|
||||
"Component cost not set": "Componente coste no está estabecido",
|
||||
"Tickets with associated refunds can't be deleted. This ticket is associated with refund Nº 2": "Tickets with associated refunds can't be deleted. This ticket is associated with refund Nº 2"
|
||||
}
|
||||
"Tickets with associated refunds can't be deleted. This ticket is associated with refund Nº 2": "Tickets with associated refunds can't be deleted. This ticket is associated with refund Nº 2",
|
||||
"Description cannot be blank": "Description cannot be blank",
|
||||
"Added observation": "Added observation",
|
||||
"Comment added to client": "Comment added to client"
|
||||
}
|
|
@ -268,8 +268,12 @@
|
|||
"Exists an invoice with a previous date": "Existe una factura con fecha anterior",
|
||||
"Invoice date can't be less than max date": "La fecha de factura no puede ser inferior a la fecha límite",
|
||||
"Warehouse inventory not set": "El almacén inventario no está establecido",
|
||||
"This locker has already been assigned": "Esta taquilla ya ha sido asignada",
|
||||
"This locker has already been assigned": "Esta taquilla ya ha sido asignada",
|
||||
"Tickets with associated refunds": "No se pueden borrar tickets con abonos asociados. Este ticket está asociado al abono Nº {{id}}",
|
||||
"Not exist this branch": "La rama no existe",
|
||||
"This ticket cannot be signed because it has not been boxed": "Este ticket no puede firmarse porque no ha sido encajado"
|
||||
"This ticket cannot be signed because it has not been boxed": "Este ticket no puede firmarse porque no ha sido encajado",
|
||||
"Insert a date range": "Inserte un rango de fechas",
|
||||
"Added observation": "{{user}} añadió esta observacion: {{text}}",
|
||||
"Comment added to client": "Observación añadida al cliente {{clientFk}}",
|
||||
"Cannot create a new claimBeginning from a different ticket": "No se puede crear una línea de reclamación de un ticket diferente al origen"
|
||||
}
|
||||
|
|
|
@ -1,41 +1,9 @@
|
|||
const mysql = require('mysql');
|
||||
const MySQL = require('loopback-connector-mysql').MySQL;
|
||||
const EnumFactory = require('loopback-connector-mysql').EnumFactory;
|
||||
const { Transaction, SQLConnector, ParameterizedSQL } = require('loopback-connector');
|
||||
const {Transaction, SQLConnector, ParameterizedSQL} = require('loopback-connector');
|
||||
const fs = require('fs');
|
||||
|
||||
const limitSet = new Set([
|
||||
'save',
|
||||
'updateOrCreate',
|
||||
'replaceOrCreate',
|
||||
'replaceById',
|
||||
'update'
|
||||
]);
|
||||
|
||||
const opOpts = {
|
||||
update: [
|
||||
'update',
|
||||
'replaceById',
|
||||
// |insert
|
||||
'save',
|
||||
'updateOrCreate',
|
||||
'replaceOrCreate'
|
||||
],
|
||||
delete: [
|
||||
'destroy',
|
||||
'destroyAll'
|
||||
],
|
||||
insert: [
|
||||
'create'
|
||||
]
|
||||
};
|
||||
|
||||
const opMap = new Map();
|
||||
for (const op in opOpts) {
|
||||
for (const met of opOpts[op])
|
||||
opMap.set(met, op);
|
||||
}
|
||||
|
||||
class VnMySQL extends MySQL {
|
||||
/**
|
||||
* Promisified version of execute().
|
||||
|
@ -253,49 +221,49 @@ class VnMySQL extends MySQL {
|
|||
}
|
||||
|
||||
create(model, data, opts, cb) {
|
||||
const ctx = { data };
|
||||
const ctx = {data};
|
||||
this.invokeMethod('create',
|
||||
arguments, model, ctx, opts, cb);
|
||||
}
|
||||
|
||||
createAll(model, data, opts, cb) {
|
||||
const ctx = { data };
|
||||
const ctx = {data};
|
||||
this.invokeMethod('createAll',
|
||||
arguments, model, ctx, opts, cb);
|
||||
}
|
||||
|
||||
save(model, data, opts, cb) {
|
||||
const ctx = { data };
|
||||
const ctx = {data};
|
||||
this.invokeMethod('save',
|
||||
arguments, model, ctx, opts, cb);
|
||||
}
|
||||
|
||||
updateOrCreate(model, data, opts, cb) {
|
||||
const ctx = { data };
|
||||
const ctx = {data};
|
||||
this.invokeMethod('updateOrCreate',
|
||||
arguments, model, ctx, opts, cb);
|
||||
}
|
||||
|
||||
replaceOrCreate(model, data, opts, cb) {
|
||||
const ctx = { data };
|
||||
const ctx = {data};
|
||||
this.invokeMethod('replaceOrCreate',
|
||||
arguments, model, ctx, opts, cb);
|
||||
}
|
||||
|
||||
destroyAll(model, where, opts, cb) {
|
||||
const ctx = { where };
|
||||
const ctx = {where};
|
||||
this.invokeMethod('destroyAll',
|
||||
arguments, model, ctx, opts, cb);
|
||||
}
|
||||
|
||||
update(model, where, data, opts, cb) {
|
||||
const ctx = { where, data };
|
||||
const ctx = {where, data};
|
||||
this.invokeMethod('update',
|
||||
arguments, model, ctx, opts, cb);
|
||||
}
|
||||
|
||||
replaceById(model, id, data, opts, cb) {
|
||||
const ctx = { id, data };
|
||||
const ctx = {id, data};
|
||||
this.invokeMethod('replaceById',
|
||||
arguments, model, ctx, opts, cb);
|
||||
}
|
||||
|
@ -311,91 +279,34 @@ class VnMySQL extends MySQL {
|
|||
return super[method].apply(this, args);
|
||||
|
||||
this.invokeMethodP(method, [...args], model, ctx, opts)
|
||||
.then(res => cb(...res), cb);
|
||||
.then(res => cb(...[null].concat(res)), cb);
|
||||
}
|
||||
|
||||
async invokeMethodP(method, args, model, ctx, opts) {
|
||||
const Model = this.getModelDefinition(model).model;
|
||||
const settings = Model.definition.settings;
|
||||
let tx;
|
||||
if (!opts.transaction) {
|
||||
tx = await Transaction.begin(this, {});
|
||||
opts = Object.assign({ transaction: tx, httpCtx: opts.httpCtx }, opts);
|
||||
opts = Object.assign({transaction: tx, httpCtx: opts.httpCtx}, opts);
|
||||
}
|
||||
|
||||
try {
|
||||
// Fetch old values (update|delete) or login
|
||||
let where, id, data, idName, limit, op, oldInstances, newInstances;
|
||||
const hasGrabUser = settings.log && settings.log.grabUser;
|
||||
if (hasGrabUser) {
|
||||
const userId = opts.httpCtx && opts.httpCtx.active.accessToken.userId;
|
||||
const user = await Model.app.models.Account.findById(userId, { fields: ['name'] }, opts);
|
||||
const userId = opts.httpCtx && opts.httpCtx.active.accessToken.userId;
|
||||
if (userId) {
|
||||
const user = await Model.app.models.VnUser.findById(userId, {fields: ['name']}, opts);
|
||||
await this.executeP(`CALL account.myUser_loginWithName(?)`, [user.name], opts);
|
||||
}
|
||||
else {
|
||||
where = ctx.where;
|
||||
id = ctx.id;
|
||||
data = ctx.data;
|
||||
idName = this.idName(model);
|
||||
|
||||
limit = limitSet.has(method);
|
||||
|
||||
op = opMap.get(method);
|
||||
|
||||
if (!where) {
|
||||
if (id) where = { [idName]: id };
|
||||
else where = { [idName]: data[idName] };
|
||||
}
|
||||
|
||||
// Fetch old values
|
||||
switch (op) {
|
||||
case 'update':
|
||||
case 'delete':
|
||||
// Single entity operation
|
||||
const stmt = this.buildSelectStmt(op, data, idName, model, where, limit);
|
||||
stmt.merge(`FOR UPDATE`);
|
||||
oldInstances = await this.executeStmt(stmt, opts);
|
||||
}
|
||||
}
|
||||
|
||||
const res = await new Promise(resolve => {
|
||||
const res = await new Promise((resolve, reject) => {
|
||||
const fnArgs = args.slice(0, -2);
|
||||
fnArgs.push(opts, (...args) => resolve(args));
|
||||
fnArgs.push(opts, (err, ...args) => {
|
||||
if (err) return reject(err);
|
||||
resolve(args);
|
||||
});
|
||||
super[method].apply(this, fnArgs);
|
||||
});
|
||||
|
||||
if (hasGrabUser)
|
||||
await this.executeP(`CALL account.myUser_logout()`, null, opts);
|
||||
else {
|
||||
// Fetch new values
|
||||
const ids = [];
|
||||
|
||||
switch (op) {
|
||||
case 'insert':
|
||||
case 'update': {
|
||||
switch (method) {
|
||||
case 'createAll':
|
||||
for (const row of res[1])
|
||||
ids.push(row[idName]);
|
||||
break;
|
||||
case 'create':
|
||||
ids.push(res[1]);
|
||||
break;
|
||||
case 'update':
|
||||
if (data[idName] != null)
|
||||
ids.push(data[idName]);
|
||||
break;
|
||||
}
|
||||
|
||||
const newWhere = ids.length ? { [idName]: ids } : where;
|
||||
|
||||
const stmt = this.buildSelectStmt(op, data, idName, model, newWhere, limit);
|
||||
newInstances = await this.executeStmt(stmt, opts);
|
||||
}
|
||||
}
|
||||
|
||||
await this.createLogRecord(oldInstances, newInstances, model, opts);
|
||||
}
|
||||
if (userId) await this.executeP(`CALL account.myUser_logout()`, null, opts);
|
||||
if (tx) await tx.commit();
|
||||
return res;
|
||||
} catch (err) {
|
||||
|
@ -403,125 +314,6 @@ class VnMySQL extends MySQL {
|
|||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
buildSelectStmt(op, data, idName, model, where, limit) {
|
||||
const Model = this.getModelDefinition(model).model;
|
||||
const properties = Object.keys(Model.definition.properties);
|
||||
|
||||
const fields = data ? Object.keys(data) : [];
|
||||
if (op == 'delete')
|
||||
properties.forEach(property => fields.push(property));
|
||||
else {
|
||||
const log = Model.definition.settings.log;
|
||||
fields.push(idName);
|
||||
if (log.relation) fields.push(Model.relations[log.relation].keyFrom);
|
||||
if (log.showField) fields.push(log.showField);
|
||||
else {
|
||||
const showFieldNames = ['name', 'description', 'code', 'nickname'];
|
||||
for (const field of showFieldNames) {
|
||||
if (properties.includes(field)) {
|
||||
log.showField = field;
|
||||
fields.push(field);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const stmt = new ParameterizedSQL(
|
||||
'SELECT ' +
|
||||
this.buildColumnNames(model, { fields }) +
|
||||
' FROM ' +
|
||||
this.tableEscaped(model)
|
||||
);
|
||||
stmt.merge(this.buildWhere(model, where));
|
||||
if (limit) stmt.merge(`LIMIT 1`);
|
||||
|
||||
return stmt;
|
||||
}
|
||||
|
||||
async createLogRecord(oldInstances, newInstances, model, opts) {
|
||||
function setActionType() {
|
||||
if (oldInstances && newInstances)
|
||||
return 'update';
|
||||
else if (!oldInstances && newInstances)
|
||||
return 'insert';
|
||||
return 'delete';
|
||||
}
|
||||
|
||||
const action = setActionType();
|
||||
if (!newInstances && action != 'delete') return;
|
||||
|
||||
const Model = this.getModelDefinition(model).model;
|
||||
const models = Model.app.models;
|
||||
const definition = Model.definition;
|
||||
const log = definition.settings.log;
|
||||
|
||||
const primaryKey = this.idName(model);
|
||||
const originRelation = log.relation;
|
||||
const originFkField = originRelation
|
||||
? Model.relations[originRelation].keyFrom
|
||||
: primaryKey;
|
||||
|
||||
// Prevent adding logs when deleting a principal entity (Client, Zone...)
|
||||
if (action == 'delete' && !originRelation) return;
|
||||
|
||||
function map(instances) {
|
||||
const map = new Map();
|
||||
if (!instances) return;
|
||||
for (const instance of instances)
|
||||
map.set(instance[primaryKey], instance);
|
||||
return map;
|
||||
}
|
||||
|
||||
const changedModel = definition.name;
|
||||
const userFk = opts.httpCtx && opts.httpCtx.active.accessToken.userId;
|
||||
const oldMap = map(oldInstances);
|
||||
const newMap = map(newInstances);
|
||||
const ids = (oldMap || newMap).keys();
|
||||
|
||||
const logEntries = [];
|
||||
|
||||
function insertValuesLogEntry(logEntry, instance) {
|
||||
logEntry.originFk = instance[originFkField];
|
||||
logEntry.changedModelId = instance[primaryKey];
|
||||
if (log.showField) logEntry.changedModelValue = instance[log.showField];
|
||||
}
|
||||
|
||||
for (const id of ids) {
|
||||
const oldI = oldMap && oldMap.get(id);
|
||||
const newI = newMap && newMap.get(id);
|
||||
|
||||
const logEntry = {
|
||||
action,
|
||||
userFk,
|
||||
changedModel,
|
||||
};
|
||||
|
||||
if (newI) {
|
||||
insertValuesLogEntry(logEntry, newI);
|
||||
// Delete unchanged properties
|
||||
if (oldI) {
|
||||
Object.keys(oldI).forEach(prop => {
|
||||
const hasChanges = oldI[prop] instanceof Date ?
|
||||
oldI[prop]?.getTime() != newI[prop]?.getTime() :
|
||||
oldI[prop] != newI[prop];
|
||||
|
||||
if (!hasChanges) {
|
||||
delete oldI[prop];
|
||||
delete newI[prop];
|
||||
}
|
||||
});
|
||||
}
|
||||
} else
|
||||
insertValuesLogEntry(logEntry, oldI);
|
||||
|
||||
logEntry.oldInstance = oldI;
|
||||
logEntry.newInstance = newI;
|
||||
logEntries.push(logEntry);
|
||||
}
|
||||
await models[log.model].create(logEntries, opts);
|
||||
}
|
||||
}
|
||||
|
||||
exports.VnMySQL = VnMySQL;
|
||||
|
@ -542,7 +334,7 @@ exports.initialize = function initialize(dataSource, callback) {
|
|||
|
||||
if (callback) {
|
||||
if (dataSource.settings.lazyConnect) {
|
||||
process.nextTick(function () {
|
||||
process.nextTick(function() {
|
||||
callback();
|
||||
});
|
||||
} else
|
||||
|
@ -550,13 +342,13 @@ exports.initialize = function initialize(dataSource, callback) {
|
|||
}
|
||||
};
|
||||
|
||||
MySQL.prototype.connect = function (callback) {
|
||||
MySQL.prototype.connect = function(callback) {
|
||||
const self = this;
|
||||
const options = generateOptions(this.settings);
|
||||
|
||||
if (this.client) {
|
||||
if (callback) {
|
||||
process.nextTick(function () {
|
||||
process.nextTick(function() {
|
||||
callback(null, self.client);
|
||||
});
|
||||
}
|
||||
|
@ -565,7 +357,7 @@ MySQL.prototype.connect = function (callback) {
|
|||
|
||||
function connectionHandler(options, callback) {
|
||||
const client = mysql.createPool(options);
|
||||
client.getConnection(function (err, connection) {
|
||||
client.getConnection(function(err, connection) {
|
||||
const conn = connection;
|
||||
if (!err) {
|
||||
if (self.debug)
|
||||
|
@ -645,30 +437,27 @@ function generateOptions(settings) {
|
|||
return options;
|
||||
}
|
||||
|
||||
|
||||
SQLConnector.prototype.all = function find(model, filter, options, cb) {
|
||||
const self = this;
|
||||
// Order by id if no order is specified
|
||||
filter = filter || {};
|
||||
const stmt = this.buildSelect(model, filter, options);
|
||||
this.execute(stmt.sql, stmt.params, options, function (err, data) {
|
||||
if (err) {
|
||||
this.execute(stmt.sql, stmt.params, options, function(err, data) {
|
||||
if (err)
|
||||
return cb(err, []);
|
||||
}
|
||||
|
||||
try {
|
||||
const objs = data.map(function (obj) {
|
||||
const objs = data.map(function(obj) {
|
||||
return self.fromRow(model, obj);
|
||||
});
|
||||
if (filter && filter.include) {
|
||||
self.getModelDefinition(model).model.include(
|
||||
objs, filter.include, options, cb,
|
||||
);
|
||||
} else {
|
||||
} else
|
||||
cb(null, objs);
|
||||
}
|
||||
} catch (error) {
|
||||
cb(error, [])
|
||||
cb(error, []);
|
||||
}
|
||||
});
|
||||
};
|
||||
};
|
||||
|
|
|
@ -28,7 +28,11 @@
|
|||
},
|
||||
"session": {},
|
||||
"auth": {
|
||||
"loopback#token": {}
|
||||
"loopback#token": {
|
||||
"params": {
|
||||
"currentUserLiteral": "me"
|
||||
}
|
||||
}
|
||||
},
|
||||
"auth:after": {
|
||||
"./middleware/current-user": {},
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
"relations": {
|
||||
"user": {
|
||||
"type": "belongsTo",
|
||||
"model": "user",
|
||||
"model": "VnUser",
|
||||
"foreignKey": "userId"
|
||||
}
|
||||
}
|
||||
|
@ -41,9 +41,6 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"user": {
|
||||
"dataSource": "vn"
|
||||
},
|
||||
"Schema": {
|
||||
"dataSource": "vn"
|
||||
},
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
module.exports = Self => {
|
||||
Self.remoteMethod('changePassword', {
|
||||
description: 'Changes the user password',
|
||||
accessType: 'WRITE',
|
||||
accepts: [
|
||||
{
|
||||
arg: 'id',
|
||||
|
@ -29,6 +30,6 @@ module.exports = Self => {
|
|||
Self.changePassword = async function(id, oldPassword, newPassword) {
|
||||
await Self.rawSql(`CALL account.user_changePassword(?, ?, ?)`,
|
||||
[id, oldPassword, newPassword]);
|
||||
await Self.app.models.UserAccount.syncById(id, newPassword);
|
||||
await Self.app.models.Account.syncById(id, newPassword);
|
||||
};
|
||||
};
|
|
@ -0,0 +1,27 @@
|
|||
module.exports = Self => {
|
||||
Self.remoteMethod('login', {
|
||||
description: 'Login a user with username/email and password',
|
||||
accepts: [
|
||||
{
|
||||
arg: 'user',
|
||||
type: 'String',
|
||||
description: 'The user name or email',
|
||||
required: true
|
||||
}, {
|
||||
arg: 'password',
|
||||
type: 'String',
|
||||
description: 'The password'
|
||||
}
|
||||
],
|
||||
returns: {
|
||||
type: 'object',
|
||||
root: true
|
||||
},
|
||||
http: {
|
||||
path: `/login`,
|
||||
verb: 'POST'
|
||||
}
|
||||
});
|
||||
|
||||
Self.login = async(user, password) => Self.app.models.VnUser.signIn(user, password);
|
||||
};
|
|
@ -18,8 +18,5 @@ module.exports = Self => {
|
|||
}
|
||||
});
|
||||
|
||||
Self.logout = async function(ctx) {
|
||||
await Self.app.models.User.logout(ctx.req.accessToken.id);
|
||||
return true;
|
||||
};
|
||||
Self.logout = async ctx => Self.app.models.VnUser.logout(ctx.req.accessToken.id);
|
||||
};
|
|
@ -1,6 +1,7 @@
|
|||
module.exports = Self => {
|
||||
Self.remoteMethod('setPassword', {
|
||||
description: 'Sets the user password',
|
||||
accessType: 'WRITE',
|
||||
accepts: [
|
||||
{
|
||||
arg: 'id',
|
||||
|
@ -23,6 +24,6 @@ module.exports = Self => {
|
|||
Self.setPassword = async function(id, newPassword) {
|
||||
await Self.rawSql(`CALL account.user_setPassword(?, ?)`,
|
||||
[id, newPassword]);
|
||||
await Self.app.models.UserAccount.syncById(id, newPassword);
|
||||
await Self.app.models.Account.syncById(id, newPassword);
|
||||
};
|
||||
};
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue