Merge branch 'dev' into 2381-mariaDB

This commit is contained in:
Juan Ferrer 2020-09-28 10:41:16 +02:00
commit 82de0a30a4
40 changed files with 1030 additions and 295 deletions

2
Jenkinsfile vendored
View File

@ -134,7 +134,7 @@ pipeline {
} }
} }
if (!env.COMMITTER_EMAIL) return if (!env.COMMITTER_EMAIL || currentBuild.currentResult == 'SUCCESS') return;
try { try {
mail( mail(
to: env.COMMITTER_EMAIL, to: env.COMMITTER_EMAIL,

View File

@ -0,0 +1,178 @@
const Imap = require('imap');
module.exports = Self => {
Self.remoteMethod('checkInbox', {
description: 'Check an email inbox and process it',
accessType: 'READ',
returns:
{
arg: 'body',
type: 'file',
root: true
},
http: {
path: `/checkInbox`,
verb: 'GET'
}
});
Self.checkInbox = async() => {
let imapConfig = await Self.app.models.WorkerTimeControlParams.findOne();
let imap = new Imap({
user: imapConfig.mailUser,
password: imapConfig.mailPass,
host: imapConfig.mailHost,
port: 993,
tls: true
});
let isEmailOk;
let uid;
let emailBody;
function openInbox(cb) {
imap.openBox('INBOX', true, cb);
}
imap.once('ready', function() {
openInbox(function(err, box) {
if (err) throw err;
let f = imap.seq.fetch('1:*', {
bodies: ['HEADER.FIELDS (FROM SUBJECT)', '1'],
struct: true
});
f.on('message', function(msg, seqno) {
isEmailOk = false;
msg.on('body', function(stream, info) {
let buffer = '';
let bufferCopy = '';
stream.on('data', function(chunk) {
buffer = chunk.toString('utf8');
if (info.which === '1' && bufferCopy.length == 0)
bufferCopy = buffer.replace(/\s/g, ' ');
});
stream.on('end', function() {
if (bufferCopy.length > 0) {
emailBody = bufferCopy.toUpperCase().trim();
const bodyPositionOK = emailBody.match(/\bOK\b/i);
if (bodyPositionOK != null && (bodyPositionOK.index == 0 || bodyPositionOK.index == 122))
isEmailOk = true;
else
isEmailOk = false;
}
});
msg.once('attributes', function(attrs) {
uid = attrs.uid;
});
msg.once('end', function() {
if (info.which === 'HEADER.FIELDS (FROM SUBJECT)') {
if (isEmailOk) {
imap.move(uid, 'exito', function(err) {
});
emailConfirm(buffer);
} else {
imap.move(uid, 'error', function(err) {
});
emailReply(buffer, emailBody);
}
}
});
});
});
f.once('end', function() {
imap.end();
});
});
});
imap.connect();
return 'Leer emails de gestion horaria';
};
async function emailConfirm(buffer) {
const now = new Date();
const from = JSON.stringify(Imap.parseHeader(buffer).from);
const subject = JSON.stringify(Imap.parseHeader(buffer).subject);
const timeControlDate = await getEmailDate(subject);
const week = timeControlDate[0];
const year = timeControlDate[1];
const user = await getUser(from);
let workerMail;
if (user.id != null) {
workerMail = await Self.app.models.WorkerTimeControlMail.findOne({
where: {
week: week,
year: year,
workerFk: user.id
}
});
}
if (workerMail != null) {
await workerMail.updateAttributes({
updated: now,
state: 'CONFIRMED'
});
}
}
async function emailReply(buffer, emailBody) {
const now = new Date();
const from = JSON.stringify(Imap.parseHeader(buffer).from);
const subject = JSON.stringify(Imap.parseHeader(buffer).subject);
const timeControlDate = await getEmailDate(subject);
const week = timeControlDate[0];
const year = timeControlDate[1];
const user = await getUser(from);
let workerMail;
if (user.id != null) {
workerMail = await Self.app.models.WorkerTimeControlMail.findOne({
where: {
week: week,
year: year,
workerFk: user.id
}
});
if (workerMail != null) {
await workerMail.updateAttributes({
updated: now,
state: 'REVISE',
emailResponse: emailBody
});
} else
await sendMail(user, subject, emailBody);
}
}
async function getUser(workerEmail) {
const userEmail = workerEmail.match(/(?<=<)(.*?)(?=>)/);
let [user] = await Self.rawSql(`SELECT u.id,u.name FROM account.user u
LEFT JOIN account.mailForward m on m.account = u.id
WHERE forwardTo =? OR
CONCAT(u.name,'@verdnatura.es') = ?`,
[userEmail[0], userEmail[0]]);
return user;
}
async function getEmailDate(subject) {
const date = subject.match(/\d+/g);
return date;
}
async function sendMail(user, subject, emailBody) {
const sendTo = 'rrhh@verdnatura.es';
const emailSubject = subject + ' ' + user.name;
await Self.app.models.Mail.create({
sender: sendTo,
subject: emailSubject,
body: emailBody
});
}
};

View File

@ -73,6 +73,12 @@
}, },
"UserLog": { "UserLog": {
"dataSource": "vn" "dataSource": "vn"
},
"WorkerTimeControlParams": {
"dataSource": "vn"
},
"WorkerTimeControlMail": {
"dataSource": "vn"
} }
} }

View File

@ -0,0 +1,42 @@
{
"name": "WorkerTimeControlMail",
"base": "VnModel",
"options": {
"mysql": {
"table": "workerTimeControlMail"
}
},
"properties": {
"id": {
"id": true,
"type": "Number",
"required": true
},
"workerFk": {
"type": "Number"
},
"year": {
"type": "Number"
},
"week": {
"type": "Number"
},
"state": {
"type": "String"
},
"updated": {
"type": "Date"
},
"emailResponse": {
"type": "String"
}
},
"acls": [
{
"accessType": "READ",
"principalType": "ROLE",
"principalId": "$everyone",
"permission": "ALLOW"
}
]
}

View File

@ -0,0 +1,3 @@
module.exports = Self => {
require('../methods/imap-time-control/checkInbox')(Self);
};

View File

@ -0,0 +1,35 @@
{
"name": "WorkerTimeControlParams",
"description": "imap config",
"base": "VnModel",
"options": {
"mysql": {
"table": "workerTimeControlParams"
}
},
"properties": {
"mailHost": {
"type": "String"
},
"mailUser": {
"type": "String"
},
"mailPass": {
"type": "String"
},
"mailSuccessFolder": {
"type": "String"
},
"mailErrorFolder": {
"type": "String"
}
},
"acls": [
{
"accessType": "READ",
"principalType": "ROLE",
"principalId": "$everyone",
"permission": "ALLOW"
}
]
}

File diff suppressed because one or more lines are too long

View File

@ -774,10 +774,16 @@ INSERT INTO `vn`.`item`(`id`, `typeFk`, `size`, `inkFk`, `stems`, `originFk`, `d
(12, 3, 30, 'RED', 1, 2, NULL, 2, 06021010, 1, 4751000000, 0, NULL, 0, 82, 2, NULL, 0), (12, 3, 30, 'RED', 1, 2, NULL, 2, 06021010, 1, 4751000000, 0, NULL, 0, 82, 2, NULL, 0),
(13, 5, 30, 'RED', 1, 2, NULL, NULL, 06021010, 0, 4751000000, 0, NULL, 0, 83, 2, NULL, 0), (13, 5, 30, 'RED', 1, 2, NULL, NULL, 06021010, 0, 4751000000, 0, NULL, 0, 83, 2, NULL, 0),
(14, 5, 90, 'BLU', 1, 2, NULL, NULL, 06021010, 0, 4751000000, 0, NULL, 0, 84, 2, NULL, 0), (14, 5, 90, 'BLU', 1, 2, NULL, NULL, 06021010, 0, 4751000000, 0, NULL, 0, 84, 2, NULL, 0),
(15, 4, NULL, NULL, NULL, 1, NULL, NULL, 06021010, 0, 4751000000, 0, NULL, 0, 67350, 2, NULL, 0), (15, 4, NULL, NULL, NULL, 1, NULL, NULL, 06021010, 0, 4751000000, 0, NULL, 0, 88, 2, NULL, 0),
(16, 4, NULL, NULL, NULL, 1, NULL, NULL, 06021010, 0, 4751000000, 0, NULL, 0, 67350, 2, NULL, 0), (16, 4, NULL, NULL, NULL, 1, NULL, NULL, 06021010, 0, 4751000000, 0, NULL, 0, 88, 2, NULL, 0),
(71, 4, NULL, NULL, NULL, 1, NULL, NULL, 06021010, 1, 4751000000, 0, NULL, 0, 88, 2, NULL, 0); (71, 4, NULL, NULL, NULL, 1, NULL, NULL, 06021010, 1, 4751000000, 0, NULL, 0, 88, 2, NULL, 0);
INSERT INTO `vn`.`priceFixed`(`id`, `itemFk`, `rate0`, `rate1`, `rate2`, `rate3`, `started`, `ended`, `bonus`, `warehouseFk`, `created`)
VALUES
(1, 1, 0, 0, 2.5, 2, CURDATE(), DATE_ADD(CURDATE(), INTERVAL +1 MONTH), 0, 1, CURDATE()),
(3, 3, 10, 10, 10, 10, CURDATE(), DATE_ADD(CURDATE(), INTERVAL +1 MONTH), 0, 1, CURDATE()),
(4, 5, 8.5, 10, 7.5, 6, CURDATE(), DATE_ADD(CURDATE(), INTERVAL +1 MONTH), 1, 2, CURDATE());
INSERT INTO `vn`.`expedition`(`id`, `agencyModeFk`, `ticketFk`, `isBox`, `created`, `itemFk`, `counter`, `checked`, `workerFk`) INSERT INTO `vn`.`expedition`(`id`, `agencyModeFk`, `ticketFk`, `isBox`, `created`, `itemFk`, `counter`, `checked`, `workerFk`)
VALUES VALUES
(1, 1, 1, 71, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), 1, 1, 1, 18), (1, 1, 1, 71, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), 1, 1, 1, 18),
@ -1069,105 +1075,107 @@ INSERT INTO `vn`.`itemBotanical`(`itemFk`, `botanical`, `genusFk`, `specieFk`)
INSERT INTO `vn`.`itemTag`(`id`,`itemFk`,`tagFk`,`value`,`priority`) INSERT INTO `vn`.`itemTag`(`id`,`itemFk`,`tagFk`,`value`,`priority`)
VALUES VALUES
(1 , 1, 56, 'Ranged weapon', 1), (1, 1, 56, 'Ranged weapon', 1),
(2 , 1, 58, 'longbow', 2), (2, 1, 58, 'longbow', 2),
(3 , 1, 27, '2m', 3), (3, 1, 27, '2m', 3),
(4 , 1, 36, 'Stark Industries', 4), (4, 1, 36, 'Stark Industries', 4),
(5 , 1, 1, 'Brown', 5), (5, 1, 1, 'Brown', 5),
(6 , 1, 67, '+1 precission', 6), (6, 1, 67, '+1 precission', 6),
(7 , 1, 23, '1', 7), (7, 1, 23, '1', 7),
(8 , 2, 56, 'Melee weapon', 1), (8, 2, 56, 'Melee weapon', 1),
(9 , 2, 58, 'combat fist', 2), (9, 2, 58, 'combat fist', 2),
(10, 2, 27, '15cm', 3), (10, 2, 27, '15cm', 3),
(11, 2, 36, 'Stark Industries', 4), (11, 2, 36, 'Stark Industries', 4),
(12, 2, 1, 'Silver', 5), (12, 2, 1, 'Silver', 5),
(13, 2, 67, 'Concussion', 6), (13, 2, 67, 'Concussion', 6),
(14, 2, 23, '2', 7), (14, 2, 23, '2', 7),
(15, 3, 56, 'Ranged weapon', 1), (15, 3, 56, 'Ranged weapon', 1),
(16, 3, 58, 'sniper rifle', 2), (16, 3, 58, 'sniper rifle', 2),
(17, 3, 4, '300mm', 3), (17, 3, 4, '300mm', 3),
(18, 3, 36, 'Stark Industries', 4), (18, 3, 36, 'Stark Industries', 4),
(19, 3, 1, 'Green', 5), (19, 3, 1, 'Green', 5),
(20, 3, 67, 'precission', 6), (20, 3, 67, 'precission', 6),
(21, 3, 23, '3', 7), (21, 3, 23, '3', 7),
(22, 4, 56, 'Melee weapon', 1), (22, 4, 56, 'Melee weapon', 1),
(23, 4, 58, 'heavy shield', 2), (23, 4, 58, 'heavy shield', 2),
(24, 4, 4, '1x0.5m', 3), (24, 4, 4, '1x0.5m', 3),
(25, 4, 36, 'Stark Industries', 4), (25, 4, 36, 'Stark Industries', 4),
(26, 4, 1, 'Black', 5), (26, 4, 1, 'Black', 5),
(27, 4, 67, 'containtment', 6), (27, 4, 67, 'containtment', 6),
(28, 4, 23, '4', 7), (28, 4, 23, '4', 7),
(29, 5, 56, 'Ranged weapon', 1), (29, 5, 56, 'Ranged weapon', 1),
(30, 5, 58, 'pistol', 2), (30, 5, 58, 'pistol', 2),
(31, 5, 27, '9mm', 3), (31, 5, 27, '9mm', 3),
(32, 5, 36, 'Stark Industries', 4), (32, 5, 36, 'Stark Industries', 4),
(33, 5, 1, 'Silver', 5), (33, 5, 1, 'Silver', 5),
(34, 5, 67, 'rapid fire', 6), (34, 5, 67, 'rapid fire', 6),
(35, 5, 23, '5', 7), (35, 5, 23, '5', 7),
(36, 6, 56, 'Container', 1), (36, 6, 56, 'Container', 1),
(37, 6, 58, 'ammo box', 2), (37, 6, 58, 'ammo box', 2),
(38, 6, 27, '1m', 3), (38, 6, 27, '1m', 3),
(39, 6, 36, 'Stark Industries', 4), (39, 6, 36, 'Stark Industries', 4),
(40, 6, 1, 'Green', 5), (40, 6, 1, 'Green', 5),
(41, 6, 67, 'supply', 6), (41, 6, 67, 'supply', 6),
(42, 6, 23, '6', 7), (42, 6, 23, '6', 7),
(43, 7, 56, 'Container', 1), (43, 7, 56, 'Container', 1),
(44, 7, 58, 'medical box', 2), (44, 7, 58, 'medical box', 2),
(45, 7, 27, '1m', 3), (45, 7, 27, '1m', 3),
(46, 7, 36, 'Stark Industries', 4), (46, 7, 36, 'Stark Industries', 4),
(47, 7, 1, 'White', 5), (47, 7, 1, 'White', 5),
(48, 7, 67, 'supply', 6), (48, 7, 67, 'supply', 6),
(49, 7, 23, '7', 7), (49, 7, 23, '7', 7),
(50, 8, 56, 'Ranged Reinforced weapon', 1), (50, 8, 56, 'Ranged Reinforced weapon', 1),
(51, 8, 58, '+1 longbow', 2), (51, 8, 58, '+1 longbow', 2),
(52, 8, 27, '2m', 3), (52, 8, 27, '2m', 3),
(53, 8, 36, 'Stark Industries', 4), (53, 8, 36, 'Stark Industries', 4),
(54, 8, 1, 'Brown', 5), (54, 8, 1, 'Brown', 5),
(55, 8, 67, 'precission', 6), (55, 8, 67, 'precission', 6),
(56, 8, 23, '8', 7), (56, 8, 23, '8', 7),
(57, 9, 56, 'Melee Reinforced weapon', 1), (57, 9, 56, 'Melee Reinforced weapon', 1),
(58, 9, 58, 'combat fist', 2), (58, 9, 58, 'combat fist', 2),
(59, 9, 27, '15cm', 3), (59, 9, 27, '15cm', 3),
(60, 9, 36, 'Stark Industries', 4), (60, 9, 36, 'Stark Industries', 4),
(61, 9, 1, 'Silver', 5), (61, 9, 1, 'Silver', 5),
(62, 9, 67, 'Concussion', 6), (62, 9, 67, 'Concussion', 6),
(63, 9, 23, '9', 7), (63, 9, 23, '9', 7),
(64, 10, 56, 'Ranged Reinforced weapon', 1), (64, 10, 56, 'Ranged Reinforced weapon', 1),
(65, 10, 58, 'sniper rifle', 2), (65, 10, 58, 'sniper rifle', 2),
(66, 10, 4, '300mm', 3), (66, 10, 4, '300mm', 3),
(67, 10, 36, 'Stark Industries', 4), (67, 10, 36, 'Stark Industries', 4),
(68, 10, 1, 'Green', 5), (68, 10, 1, 'Green', 5),
(69, 10, 67, 'precission', 6), (69, 10, 67, 'precission', 6),
(70, 10, 23, '10', 7), (70, 10, 23, '10', 7),
(71, 11, 56, 'Melee Reinforced weapon', 1), (71, 11, 56, 'Melee Reinforced weapon', 1),
(72, 11, 58, 'heavy shield', 2), (72, 11, 58, 'heavy shield', 2),
(73, 11, 4, '1x0.5m', 3), (73, 11, 4, '1x0.5m', 3),
(74, 11, 36, 'Stark Industries', 4), (74, 11, 36, 'Stark Industries', 4),
(75, 11, 1, 'Black', 5), (75, 11, 1, 'Black', 5),
(76, 11, 67, 'containtment', 6), (76, 11, 67, 'containtment', 6),
(77, 11, 23, '11', 7), (77, 11, 23, '11', 7),
(78, 12, 56, 'Ranged Reinforced weapon', 1), (78, 12, 56, 'Ranged Reinforced weapon', 1),
(79, 12, 58, 'pistol', 2), (79, 12, 58, 'pistol', 2),
(80, 12, 27, '9mm', 3), (80, 12, 27, '9mm', 3),
(81, 12, 36, 'Stark Industries', 4), (81, 12, 36, 'Stark Industries', 4),
(82, 12, 1, 'Silver', 5), (82, 12, 1, 'Silver', 5),
(83, 12, 67, 'rapid fire', 6), (83, 12, 67, 'rapid fire', 6),
(84, 12, 23, '12', 7), (84, 12, 23, '12', 7),
(85, 13, 56, 'Chest', 1), (85, 13, 56, 'Chest', 1),
(86, 13, 58, 'ammo box', 2), (86, 13, 58, 'ammo box', 2),
(87, 13, 27, '1m', 3), (87, 13, 27, '1m', 3),
(88, 13, 36, 'Stark Industries', 4), (88, 13, 36, 'Stark Industries', 4),
(89, 13, 1, 'Green', 5), (89, 13, 1, 'Green', 5),
(90, 13, 67, 'supply', 6), (90, 13, 67, 'supply', 6),
(91, 13, 23, '13', 7), (91, 13, 23, '13', 7),
(92, 14, 56, 'Chest', 1), (92, 14, 56, 'Chest', 1),
(93, 14, 58, 'medical box', 2), (93, 14, 58, 'medical box', 2),
(94, 14, 27, '1m', 3), (94, 14, 27, '1m', 3),
(95, 14, 36, 'Stark Industries', 4), (95, 14, 36, 'Stark Industries', 4),
(96, 14, 1, 'White', 5), (96, 14, 1, 'White', 5),
(97, 14, 67, 'supply', 6), (97, 14, 67, 'supply', 6),
(98, 14, 23, '1', 7), (98, 14, 23, '1', 7),
(99, 71, 92, 'Shipping cost', 2); (99, 15, 92, 'Shipping cost', 2),
(100, 16, 92, 'Shipping cost', 2),
(101, 71, 92, 'Shipping cost', 2);
INSERT INTO `vn`.`itemTypeTag`(`id`, `itemTypeFk`, `tagFk`, `priority`) INSERT INTO `vn`.`itemTypeTag`(`id`, `itemTypeFk`, `tagFk`, `priority`)
VALUES VALUES

View File

@ -1,7 +1,7 @@
const app = require('vn-loopback/server/server'); const app = require('vn-loopback/server/server');
const ParameterizedSQL = require('loopback-connector').ParameterizedSQL; const ParameterizedSQL = require('loopback-connector').ParameterizedSQL;
// #2257 xdescribe dbtest workerTimeControl_check() // #2261 xdescribe dbtest workerTimeControl_check()
xdescribe('worker workerTimeControl_check()', () => { xdescribe('worker workerTimeControl_check()', () => {
it(`should throw an error if the worker can't sign on that tablet`, async() => { it(`should throw an error if the worker can't sign on that tablet`, async() => {
let stmts = []; let stmts = [];

View File

@ -50,7 +50,7 @@ describe('Ticket Edit basic data path', () => {
}); });
it(`should edit the ticket agency then check there are no zones for it`, async() => { it(`should edit the ticket agency then check there are no zones for it`, async() => {
await page.autocompleteSearch(selectors.ticketBasicData.agency, 'Entanglement'); await page.autocompleteSearch(selectors.ticketBasicData.agency, 'Super-Man delivery');
await page.waitFor(1000); await page.waitFor(1000);
let emptyZone = await page let emptyZone = await page
.expectPropertyValue(selectors.ticketBasicData.zone, 'value', ''); .expectPropertyValue(selectors.ticketBasicData.zone, 'value', '');
@ -59,6 +59,7 @@ describe('Ticket Edit basic data path', () => {
}); });
it(`should edit the ticket zone then check the agency is for the new zone`, async() => { it(`should edit the ticket zone then check the agency is for the new zone`, async() => {
await page.clearInput(selectors.ticketBasicData.agency);
await page.autocompleteSearch(selectors.ticketBasicData.zone, 'Zone expensive A'); await page.autocompleteSearch(selectors.ticketBasicData.zone, 'Zone expensive A');
let zone = await page let zone = await page
.waitToGetProperty(selectors.ticketBasicData.agency, 'value'); .waitToGetProperty(selectors.ticketBasicData.agency, 'value');

View File

@ -248,7 +248,8 @@ export default class Autocomplete extends Field {
'where', 'where',
'order', 'order',
'limit', 'limit',
'searchFunction' 'searchFunction',
'whereFunction'
]); ]);
} }
@ -290,6 +291,7 @@ ngModule.vnComponent('vnAutocomplete', {
limit: '<?', limit: '<?',
translateFields: '<?', translateFields: '<?',
searchFunction: '&?', searchFunction: '&?',
whereFunction: '&?',
fetchFunction: '<?' fetchFunction: '<?'
}, },
transclude: { transclude: {

View File

@ -55,7 +55,7 @@
} }
&.event .day-number { &.event .day-number {
background-color: $color-main; background-color: $color-main;
color: $color-font-dark; color: $color-font-bg;
} }
& > .day-number { & > .day-number {
display: flex; display: flex;

View File

@ -409,6 +409,9 @@ export default class DropDown extends Popover {
? null ? null
: this.searchFunction({$search: this._search}); : this.searchFunction({$search: this._search});
if (this.whereFunction)
this.where = this.whereFunction();
Object.assign(filter, { Object.assign(filter, {
fields: this.getFields(), fields: this.getFields(),
include: this.include, include: this.include,

View File

@ -34,5 +34,8 @@
}, },
"UserSync": { "UserSync": {
"dataSource": "vn" "dataSource": "vn"
},
"Mail": {
"dataSource": "vn"
} }
} }

View File

@ -0,0 +1,35 @@
{
"name": "Mail",
"base": "VnModel",
"options": {
"mysql": {
"table": "mail"
}
},
"properties": {
"id": {
"id": true,
"type": "Number"
},
"sender": {
"type": "String"
},
"replyTo": {
"type": "String"
},
"subject": {
"type": "String"
},
"body": {
"type": "String"
}
},
"acls": [
{
"accessType": "READ",
"principalType": "ROLE",
"principalId": "$everyone",
"permission": "ALLOW"
}
]
}

View File

@ -29,6 +29,6 @@ describe('ticket editableStates()', () => {
let result = await app.models.State.editableStates(ctx, filter); let result = await app.models.State.editableStates(ctx, filter);
let pickerDesignedState = result.some(state => state.code == 'PICKER_DESIGNED'); let pickerDesignedState = result.some(state => state.code == 'PICKER_DESIGNED');
expect(pickerDesignedState).toBeFalsy(); expect(pickerDesignedState).toBeTruthy();
}); });
}); });

View File

@ -30,7 +30,7 @@ describe('state isEditable()', () => {
it('should return false if the state is not editable for the given role', async() => { it('should return false if the state is not editable for the given role', async() => {
const employeeRole = 1; const employeeRole = 1;
const asignedState = 20; const asignedState = 13;
let ctx = {req: {accessToken: {userId: employeeRole}}}; let ctx = {req: {accessToken: {userId: employeeRole}}};
let result = await app.models.State.isEditable(ctx, asignedState); let result = await app.models.State.isEditable(ctx, asignedState);

View File

@ -40,15 +40,17 @@ module.exports = Self => {
params.workerFk = worker.id; params.workerFk = worker.id;
} }
let ticket = await models.TicketState.findById( let ticketState = await models.TicketState.findById(
params.ticketFk, params.ticketFk,
{fields: ['stateFk']} {fields: ['stateFk']}
); );
let oldStateAllowed = await models.State.isEditable(ctx, ticket.stateFk); let oldStateAllowed;
if (ticketState)
oldStateAllowed = await models.State.isEditable(ctx, ticketState.stateFk);
let newStateAllowed = await models.State.isEditable(ctx, params.stateFk); let newStateAllowed = await models.State.isEditable(ctx, params.stateFk);
let isAllowed = oldStateAllowed && newStateAllowed; let isAllowed = (!ticketState || oldStateAllowed == true) && newStateAllowed == true;
if (!isAllowed) if (!isAllowed)
throw new UserError(`You don't have enough privileges`, 'ACCESS_DENIED'); throw new UserError(`You don't have enough privileges`, 'ACCESS_DENIED');

View File

@ -161,8 +161,13 @@ module.exports = Self => {
if (value) { if (value) {
return {and: [ return {and: [
{'st.alertLevel': 0}, {'st.alertLevel': 0},
{'st.code': {neq: 'OK'}}, {'st.code': {nin: [
{'st.code': {neq: 'BOARDING'}} 'OK',
'BOARDING',
'PRINTED',
'PRINTED_AUTO',
'PICKER_DESIGNED'
]}}
]}; ]};
} else { } else {
return {and: [ return {and: [

View File

@ -7,8 +7,10 @@
<form name="form"> <form name="form">
<vn-card class="vn-w-md vn-pa-lg"> <vn-card class="vn-w-md vn-pa-lg">
<vn-horizontal> <vn-horizontal>
<vn-autocomplete vn-one <vn-autocomplete
vn-one
vn-id="client" vn-id="client"
required="true"
url="Clients" url="Clients"
label="Client" label="Client"
show-field="name" show-field="name"
@ -18,7 +20,9 @@
initial-data="$ctrl.clientId" initial-data="$ctrl.clientId"
order="id"> order="id">
</vn-autocomplete> </vn-autocomplete>
<vn-autocomplete vn-one <vn-autocomplete
vn-one
required="true"
data="$ctrl.addresses" data="$ctrl.addresses"
label="Address" label="Address"
show-field="nickname" show-field="nickname"
@ -41,6 +45,7 @@
</append> </append>
</vn-autocomplete> </vn-autocomplete>
<vn-autocomplete vn-one <vn-autocomplete vn-one
required="true"
url="Warehouses" url="Warehouses"
label="Warehouse" label="Warehouse"
show-field="name" show-field="name"
@ -49,8 +54,9 @@
</vn-autocomplete> </vn-autocomplete>
</vn-horizontal> </vn-horizontal>
<vn-horizontal> <vn-horizontal>
<vn-autocomplete <vn-autocomplete
vn-one vn-one
required="true"
url="Companies" url="Companies"
label="Company" label="Company"
show-field="code" show-field="code"
@ -60,20 +66,24 @@
</vn-autocomplete> </vn-autocomplete>
<vn-autocomplete <vn-autocomplete
vn-one vn-one
url="AgencyModes/isActive" vn-id="agencyMode"
url="AgencyModes/byWarehouse"
label="Agency" label="Agency"
show-field="name" show-field="name"
value-field="id" value-field="id"
ng-model="$ctrl.agencyModeId"> ng-model="$ctrl.agencyModeId"
where-function="$ctrl.agencyModeWhere()">
</vn-autocomplete> </vn-autocomplete>
<vn-autocomplete <vn-autocomplete
vn-one vn-one
data="zones" required="true"
url="Zones/includingExpired"
label="Zone" label="Zone"
show-field="name" show-field="name"
value-field="id" value-field="id"
ng-model="$ctrl.zoneId" ng-model="$ctrl.zoneId"
vn-acl="productionBoss"> vn-acl="productionBoss"
where-function="$ctrl.zoneWhere()">
<tpl-item> <tpl-item>
<span>{{::name}} - Max. {{::hour | date: 'HH:mm'}} h.</span> <span>{{::name}} - Max. {{::hour | date: 'HH:mm'}} h.</span>
</tpl-item> </tpl-item>
@ -82,16 +92,19 @@
<vn-horizontal> <vn-horizontal>
<vn-date-picker <vn-date-picker
vn-one vn-one
required="true"
label="Shipped" label="Shipped"
ng-model="$ctrl.shipped"> ng-model="$ctrl.shipped">
</vn-date-picker> </vn-date-picker>
<vn-input-time <vn-input-time
vn-one vn-one
required="true"
label="Shipped hour" label="Shipped hour"
ng-model="$ctrl.shipped"> ng-model="$ctrl.shipped">
</vn-input-time> </vn-input-time>
<vn-date-picker <vn-date-picker
vn-one vn-one
required="true"
label="Landed" label="Landed"
ng-model="$ctrl.landed"> ng-model="$ctrl.landed">
</vn-date-picker> </vn-date-picker>

View File

@ -56,12 +56,8 @@ class Controller extends Component {
set warehouseId(value) { set warehouseId(value) {
if (value != this.ticket.warehouseFk) { if (value != this.ticket.warehouseFk) {
this.ticket.warehouseFk = value; this.ticket.warehouseFk = value;
this.getShipped({ this.ticket.agencyModeFk = null;
landed: this.ticket.landed, this.ticket.zoneFk = null;
addressFk: this.ticket.addressFk,
agencyModeFk: this.ticket.agencyModeFk,
warehouseFk: value
});
} }
} }
@ -75,8 +71,7 @@ class Controller extends Component {
shipped: value, shipped: value,
addressFk: this.ticket.addressFk, addressFk: this.ticket.addressFk,
agencyModeFk: this.ticket.agencyModeFk, agencyModeFk: this.ticket.agencyModeFk,
warehouseFk: this.ticket.warehouseFk, warehouseFk: this.ticket.warehouseFk
showExpiredZones: false
}); });
} }
@ -101,12 +96,17 @@ class Controller extends Component {
set agencyModeId(value) { set agencyModeId(value) {
if (value != this.ticket.agencyModeFk) { if (value != this.ticket.agencyModeFk) {
this.ticket.agencyModeFk = value; this.ticket.agencyModeFk = value;
if (!value) return;
const agencyMode = this.$.agencyMode.selection;
this.ticket.warehouseFk = agencyMode.warehouseFk;
this.getLanded({ this.getLanded({
shipped: this.ticket.shipped, shipped: this.ticket.shipped,
addressFk: this.ticket.addressFk, addressFk: this.ticket.addressFk,
agencyModeFk: value, agencyModeFk: value,
warehouseFk: this.ticket.warehouseFk, warehouseFk: this.ticket.warehouseFk
showExpiredZones: false
}); });
} }
} }
@ -241,6 +241,27 @@ class Controller extends Component {
|| !this.ticket.companyFk || !this.ticket.shipped || !this.ticket.landed || !this.ticket.companyFk || !this.ticket.shipped || !this.ticket.landed
|| !this.ticket.zoneFk; || !this.ticket.zoneFk;
} }
zoneWhere() {
if (this.ticket.agencyModeFk) {
return {
shipped: this.ticket.shipped,
addressFk: this.ticket.addressFk,
agencyModeFk: this.ticket.agencyModeFk,
warehouseFk: this.ticket.warehouseFk
};
}
return {};
}
agencyModeWhere() {
if (this.warehouseId) {
return {
warehouseFk: this.warehouseId
};
}
return {};
}
} }
ngModule.vnComponent('vnTicketBasicDataStepOne', { ngModule.vnComponent('vnTicketBasicDataStepOne', {

View File

@ -94,16 +94,7 @@ describe('Ticket', () => {
jest.spyOn(controller, 'getShipped'); jest.spyOn(controller, 'getShipped');
controller.ticket.warehouseId = 1; controller.ticket.warehouseId = 1;
controller.warehouseId = 2; controller.warehouseId = 2;
const landed = new Date();
const expectedResult = {
landed: landed,
addressFk: 121,
agencyModeFk: 7,
warehouseFk: 2
};
controller.landed = landed;
expect(controller.getShipped).toHaveBeenCalledWith(expectedResult);
expect(controller.ticket.warehouseFk).toEqual(2); expect(controller.ticket.warehouseFk).toEqual(2);
}); });
}); });
@ -125,7 +116,6 @@ describe('Ticket', () => {
shipped: shipped, shipped: shipped,
addressFk: 121, addressFk: 121,
agencyModeFk: 7, agencyModeFk: 7,
showExpiredZones: false,
warehouseFk: 1 warehouseFk: 1
}; };
controller.shipped = shipped; controller.shipped = shipped;
@ -170,14 +160,14 @@ describe('Ticket', () => {
describe('agencyModeId() setter', () => { describe('agencyModeId() setter', () => {
it('should set agencyModeId property and call getLanded() method', () => { it('should set agencyModeId property and call getLanded() method', () => {
jest.spyOn(controller, 'getLanded'); jest.spyOn(controller, 'getLanded');
controller.$.agencyMode = {selection: {warehouseFk: 1}};
const shipped = new Date(); const shipped = new Date();
const agencyModeId = 8; const agencyModeId = 8;
const expectedResult = { const expectedResult = {
shipped: shipped, shipped: shipped,
addressFk: 121, addressFk: 121,
agencyModeFk: agencyModeId, agencyModeFk: agencyModeId,
warehouseFk: 1, warehouseFk: 1
showExpiredZones: false,
}; };
controller.ticket.shipped = shipped; controller.ticket.shipped = shipped;
controller.agencyModeId = 8; controller.agencyModeId = 8;
@ -363,5 +353,31 @@ describe('Ticket', () => {
expect(controller.landed).toEqual(landed); expect(controller.landed).toEqual(landed);
}); });
}); });
describe('zoneWhere() getter', () => {
it('should return an object containing filter properties', async() => {
const shipped = new Date();
controller.ticket.shipped = shipped;
const expectedResult = {
addressFk: 121,
agencyModeFk: 7,
shipped: shipped,
warehouseFk: 1
};
const result = controller.zoneWhere();
expect(result).toEqual(expect.objectContaining(expectedResult));
});
});
describe('agencyModeWhere() getter', () => {
it('should return an object containing the warehouseFk property', async() => {
const expectedResult = {warehouseFk: 1};
const result = controller.agencyModeWhere();
expect(result).toEqual(expect.objectContaining(expectedResult));
});
});
}); });
}); });

View File

@ -161,7 +161,8 @@
</div> </div>
<vn-popup vn-id="summary"> <vn-popup vn-id="summary">
<vn-ticket-summary <vn-ticket-summary
ticket="$ctrl.selectedTicket"> ticket="$ctrl.selectedTicket"
model="model">
</vn-ticket-summary> </vn-ticket-summary>
</vn-popup> </vn-popup>
<vn-client-descriptor-popover <vn-client-descriptor-popover

View File

@ -57,8 +57,12 @@ class Controller extends Section {
this.vnApp.showSuccess(this.$t('Data saved!')); this.vnApp.showSuccess(this.$t('Data saved!'));
if (this.card) if (this.card)
this.card.reload(); this.card.reload();
else else {
this.getSummary(); this.getSummary();
// Refresh index model
if (this.model)
this.model.refresh();
}
}); });
} }
@ -78,7 +82,8 @@ ngModule.vnComponent('vnTicketSummary', {
template: require('./index.html'), template: require('./index.html'),
controller: Controller, controller: Controller,
bindings: { bindings: {
ticket: '<' ticket: '<',
model: '<?'
}, },
require: { require: {
card: '?^vnTicketCard' card: '?^vnTicketCard'

View File

@ -31,6 +31,9 @@
"userFk": { "userFk": {
"type" : "Number", "type" : "Number",
"required": true "required": true
},
"bossFk": {
"type" : "Number"
} }
}, },
"relations": { "relations": {

View File

@ -38,7 +38,7 @@
order="DESC"> order="DESC">
</vn-autocomplete> </vn-autocomplete>
</div> </div>
<div class="vn-pt-md" style="overflow: hidden;"> <div class="input vn-py-md" style="overflow: hidden;">
<vn-chip ng-repeat="absenceType in absenceTypes" ng-class="::{'selectable': $ctrl.isSubordinate}" <vn-chip ng-repeat="absenceType in absenceTypes" ng-class="::{'selectable': $ctrl.isSubordinate}"
ng-click="$ctrl.pick(absenceType)"> ng-click="$ctrl.pick(absenceType)">
<vn-avatar <vn-avatar
@ -48,6 +48,13 @@
{{absenceType.name}} {{absenceType.name}}
</vn-chip> </vn-chip>
</div> </div>
<div class="vn-py-md">
<vn-chip>
<vn-avatar class="festive">
</vn-avatar>
<span translate>Festive</span>
</vn-chip>
</div>
</div> </div>
</vn-side-menu> </vn-side-menu>
<vn-confirm <vn-confirm

View File

@ -85,8 +85,16 @@ class Controller extends Section {
this.events = {}; this.events = {};
this.calendar = data.calendar; this.calendar = data.calendar;
let addEvent = (day, event) => { let addEvent = (day, newEvent) => {
this.events[new Date(day).getTime()] = event; const timestamp = new Date(day).getTime();
const event = this.events[timestamp];
if (event) {
const oldName = event.name;
Object.assign(event, newEvent);
event.name = `${oldName}, ${event.name}`;
} else
this.events[timestamp] = newEvent;
}; };
if (data.holidays) { if (data.holidays) {
@ -97,7 +105,7 @@ class Controller extends Section {
addEvent(holiday.dated, { addEvent(holiday.dated, {
name: holidayName, name: holidayName,
color: '#ff0' className: 'festive'
}); });
}); });
} }
@ -127,7 +135,12 @@ class Controller extends Section {
let dayNumber = element.firstElementChild; let dayNumber = element.firstElementChild;
dayNumber.title = event.name; dayNumber.title = event.name;
dayNumber.style.backgroundColor = event.color; dayNumber.style.backgroundColor = event.color;
dayNumber.style.color = 'rgba(0, 0, 0, 0.7)';
if (event.border)
dayNumber.style.border = event.border;
if (event.className)
dayNumber.classList.add(event.className);
} }
pick(absenceType) { pick(absenceType) {

View File

@ -95,7 +95,7 @@ describe('Worker', () => {
let events = controller.events; let events = controller.events;
expect(events[today.getTime()].name).toEqual('Holiday'); expect(events[today.getTime()].name).toEqual('New year, Holiday');
expect(events[tomorrow.getTime()].name).toEqual('Easter'); expect(events[tomorrow.getTime()].name).toEqual('Easter');
expect(events[yesterday.getTime()].name).toEqual('Leave'); expect(events[yesterday.getTime()].name).toEqual('Leave');
expect(events[yesterday.getTime()].color).toEqual('#bbb'); expect(events[yesterday.getTime()].color).toEqual('#bbb');

View File

@ -1,5 +1,6 @@
Calendar: Calendario Calendar: Calendario
Holidays: Vacaciones Holidays: Vacaciones
Festive: Festivo
Used: Utilizados Used: Utilizados
Year: Año Year: Año
of: de of: de

View File

@ -36,4 +36,17 @@ vn-worker-calendar {
top: 16px; top: 16px;
right: 16px right: 16px
} }
vn-side-menu div > .input {
border-color: rgba(0, 0, 0, 0.3);
border-bottom: 1px solid rgba(0, 0, 0, 0.3);
}
.festive {
background-color:white;
border: 2px solid $color-alert;
width: 24px;
min-width: 24px;
height: 24px
}
} }

View File

@ -0,0 +1,38 @@
const ParameterizedSQL = require('loopback-connector').ParameterizedSQL;
const mergeFilters = require('vn-loopback/util/filter').mergeFilters;
module.exports = Self => {
Self.remoteMethod('byWarehouse', {
description: 'Returns a list of agencies from a warehouse',
accepts: [{
arg: 'filter',
type: 'Object',
description: `Filter defining where, order, offset, and limit - must be a JSON-encoded string`
}],
returns: {
type: ['object'],
root: true
},
http: {
path: `/byWarehouse`,
verb: 'GET'
}
});
Self.byWarehouse = async filter => {
const conn = Self.dataSource.connector;
const where = {isActive: true};
filter = mergeFilters(filter, {where});
let stmt = new ParameterizedSQL(
`SELECT id, name, warehouseFk
FROM (
SELECT DISTINCT am.id, am.name, am.isActive, zw.warehouseFk
FROM zoneWarehouse zw
JOIN zone z ON z.id = zw.zoneFk
JOIN agencyMode am ON am.id = z.agencyModeFk) am`);
stmt.merge(conn.makeSuffix(filter));
return conn.executeStmt(stmt);
};
};

View File

@ -0,0 +1,21 @@
const app = require('vn-loopback/server/server');
describe('AgencyMode byWarehhouse()', () => {
const warehouseId = 1;
it('should return all the agencies', async() => {
const where = {};
const agencies = await app.models.AgencyMode.byWarehouse({where});
expect(agencies.length).toBeGreaterThan(10);
});
it('should return only the agencies for a warehouse', async() => {
const where = {warehouseFk: warehouseId};
const agencies = await app.models.AgencyMode.byWarehouse({where});
const validWarehouse = agencies.every(agency => agency.warehouseFk = warehouseId);
expect(agencies.length).toEqual(6);
expect(validWarehouse).toBeTruthy();
});
});

View File

@ -1,7 +1,7 @@
const ParameterizedSQL = require('loopback-connector').ParameterizedSQL; const ParameterizedSQL = require('loopback-connector').ParameterizedSQL;
module.exports = Self => { module.exports = Self => {
Self.remoteMethod('getLanded', { Self.remoteMethodCtx('getLanded', {
description: 'Returns the first shipped and landed possible for params', description: 'Returns the first shipped and landed possible for params',
accessType: 'READ', accessType: 'READ',
accepts: [{ accepts: [{
@ -23,11 +23,6 @@ module.exports = Self => {
arg: 'warehouseFk', arg: 'warehouseFk',
type: 'number', type: 'number',
required: true required: true
},
{
arg: 'showExpiredZones',
type: 'boolean',
required: true
}], }],
returns: { returns: {
type: 'object', type: 'object',
@ -39,7 +34,13 @@ module.exports = Self => {
} }
}); });
Self.getLanded = async(shipped, addressFk, agencyModeFk, warehouseFk, showExpiredZones) => { Self.getLanded = async(ctx, shipped, addressFk, agencyModeFk, warehouseFk) => {
const userId = ctx.req.accessToken.userId;
const models = Self.app.models;
const isProductionBoss = await models.Account.hasRole(userId, 'productionBoss');
let showExpired = false;
if (isProductionBoss) showExpired = true;
let stmts = []; let stmts = [];
stmts.push(new ParameterizedSQL( stmts.push(new ParameterizedSQL(
`CALL vn.zone_getLanded(?, ?, ?, ?, ?)`, [ `CALL vn.zone_getLanded(?, ?, ?, ?, ?)`, [
@ -47,7 +48,7 @@ module.exports = Self => {
addressFk, addressFk,
agencyModeFk, agencyModeFk,
warehouseFk, warehouseFk,
showExpiredZones showExpired
] ]
)); ));

View File

@ -2,13 +2,13 @@ const app = require('vn-loopback/server/server');
describe('agency getLanded()', () => { describe('agency getLanded()', () => {
it('should return a landing date', async() => { it('should return a landing date', async() => {
const ctx = {req: {accessToken: {userId: 1}}};
const shipped = new Date(); const shipped = new Date();
shipped.setDate(shipped.getDate() + 1); shipped.setDate(shipped.getDate() + 1);
const addressFk = 121; const addressFk = 121;
const agencyModeFk = 7; const agencyModeFk = 7;
const warehouseFk = 1; const warehouseFk = 1;
const showExpiredZones = true; let result = await app.models.Agency.getLanded(ctx, shipped, addressFk, agencyModeFk, warehouseFk);
let result = await app.models.Agency.getLanded(shipped, addressFk, agencyModeFk, warehouseFk, showExpiredZones);
expect(result.landed).toBeDefined(); expect(result.landed).toBeDefined();
}); });

View File

@ -0,0 +1,71 @@
const ParameterizedSQL = require('loopback-connector').ParameterizedSQL;
const mergeFilters = require('vn-loopback/util/filter').mergeFilters;
module.exports = Self => {
Self.remoteMethodCtx('includingExpired', {
description: 'Returns a list of agencies from a warehouse',
accepts: [{
arg: 'filter',
type: 'Object',
description: `Filter defining where, order, offset, and limit - must be a JSON-encoded string`
}],
returns: {
type: ['object'],
root: true
},
http: {
path: `/includingExpired`,
verb: 'GET'
}
});
Self.includingExpired = async(ctx, filter) => {
const userId = ctx.req.accessToken.userId;
const conn = Self.dataSource.connector;
const models = Self.app.models;
const where = filter.where;
const stmts = [];
let stmt;
const filterByAvailability = where.shipped && where.addressFk
&& where.agencyModeFk && where.warehouseFk;
if (filterByAvailability) {
const isProductionBoss = await models.Account.hasRole(userId, 'productionBoss');
let showExpired = false;
if (isProductionBoss) showExpired = true;
stmt = new ParameterizedSQL(`CALL vn.zone_getLanded(?, ?, ?, ?, ?)`, [
where.shipped,
where.addressFk,
where.agencyModeFk,
where.warehouseFk,
showExpired]);
stmts.push(stmt);
}
delete where.shipped;
delete where.addressFk;
delete where.warehouseFk;
stmt = new ParameterizedSQL(
`SELECT id, name, agencyModeFk
FROM vn.zone z`);
if (filterByAvailability)
stmt.merge(`JOIN tmp.zoneGetLanded zgl ON zgl.zoneFk = z.id`);
stmt.merge(conn.makeWhere(filter.where));
let index;
if (stmts.length)
index = stmts.push(stmt) - 1;
else stmts.push(stmt);
const sql = ParameterizedSQL.join(stmts, ';');
const result = await conn.executeStmt(sql);
return index ? result[index] : result;
};
};

View File

@ -0,0 +1,40 @@
const app = require('vn-loopback/server/server');
describe('zone includingExpired()', () => {
const inhousePickupId = 1;
const addressId = 101;
const warehouseId = 1;
it('should return an array containing all zones', async() => {
const ctx = {req: {accessToken: {userId: 1}}};
const where = {};
const result = await app.models.Zone.includingExpired(ctx, {where});
expect(result.length).toBeGreaterThan(2);
});
it('should return an array containing zones from the agencyMode "Inhouse pickup"', async() => {
const ctx = {req: {accessToken: {userId: 1}}};
const where = {agencyModeFk: inhousePickupId};
const result = await app.models.Zone.includingExpired(ctx, {where});
const validAgency = result.every(zone => zone.agencyModeFk = inhousePickupId);
expect(result.length).toEqual(3);
expect(validAgency).toBeTruthy();
});
it('should return an array containing available zones', async() => {
const ctx = {req: {accessToken: {userId: 1}}};
const where = {
shipped: new Date(),
addressFk: addressId,
agencyModeFk: inhousePickupId,
warehouseFk: warehouseId
};
const result = await app.models.Zone.includingExpired(ctx, {where});
const firstZone = result[0];
expect(firstZone.name).toEqual('Zone pickup A');
});
});

View File

@ -0,0 +1,3 @@
module.exports = Self => {
require('../methods/agency-mode/byWarehouse')(Self);
};

View File

@ -5,6 +5,7 @@ module.exports = Self => {
require('../methods/zone/toggleIsIncluded')(Self); require('../methods/zone/toggleIsIncluded')(Self);
require('../methods/zone/getUpcomingDeliveries')(Self); require('../methods/zone/getUpcomingDeliveries')(Self);
require('../methods/zone/deleteZone')(Self); require('../methods/zone/deleteZone')(Self);
require('../methods/zone/includingExpired')(Self);
Self.validatesPresenceOf('agencyModeFk', { Self.validatesPresenceOf('agencyModeFk', {
message: `Agency cannot be blank` message: `Agency cannot be blank`

386
package-lock.json generated
View File

@ -2954,6 +2954,22 @@
} }
} }
}, },
"@babel/runtime-corejs3": {
"version": "7.11.2",
"resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.11.2.tgz",
"integrity": "sha512-qh5IR+8VgFz83VBa6OkaET6uN/mJOhHONuy3m1sgF0CV6mXdPSEBdA7e1eUbVvyNtANjMbg22JUv71BaDXLY6A==",
"requires": {
"core-js-pure": "^3.0.0",
"regenerator-runtime": "^0.13.4"
},
"dependencies": {
"regenerator-runtime": {
"version": "0.13.7",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz",
"integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew=="
}
}
},
"@babel/template": { "@babel/template": {
"version": "7.6.0", "version": "7.6.0",
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.6.0.tgz", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.6.0.tgz",
@ -4935,11 +4951,6 @@
"@types/yargs": "^13.0.0" "@types/yargs": "^13.0.0"
} }
}, },
"@kyleshockey/object-assign-deep": {
"version": "0.4.2",
"resolved": "https://registry.npmjs.org/@kyleshockey/object-assign-deep/-/object-assign-deep-0.4.2.tgz",
"integrity": "sha1-hJAPDu/DcnmPR1G1JigwuCCJIuw="
},
"@sindresorhus/is": { "@sindresorhus/is": {
"version": "0.14.0", "version": "0.14.0",
"resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz",
@ -6692,6 +6703,7 @@
"version": "6.26.0", "version": "6.26.0",
"resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz",
"integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=",
"dev": true,
"requires": { "requires": {
"core-js": "^2.4.0", "core-js": "^2.4.0",
"regenerator-runtime": "^0.11.0" "regenerator-runtime": "^0.11.0"
@ -7169,9 +7181,9 @@
} }
}, },
"btoa": { "btoa": {
"version": "1.1.2", "version": "1.2.1",
"resolved": "https://registry.npmjs.org/btoa/-/btoa-1.1.2.tgz", "resolved": "https://registry.npmjs.org/btoa/-/btoa-1.2.1.tgz",
"integrity": "sha1-PkC4FmP4HS3WWWpMtxSo3BbPq+A=" "integrity": "sha512-SB4/MIGlsiVkMcHmT+pSmIPoNDoHg+7cMzmt3Uxt628MTz2487DKSqK/fuhFBrkuqrYv5UCEnACpF4dTFNKc/g=="
}, },
"buffer": { "buffer": {
"version": "4.9.1", "version": "4.9.1",
@ -8014,7 +8026,8 @@
"core-js": { "core-js": {
"version": "2.6.9", "version": "2.6.9",
"resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.9.tgz", "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.9.tgz",
"integrity": "sha512-HOpZf6eXmnl7la+cUdMnLvUxKNqLUzJvgIziQ0DiF3JwSImNphIqdGqzj6hIKyX04MmV0poclQ7+wjWvxQyR2A==" "integrity": "sha512-HOpZf6eXmnl7la+cUdMnLvUxKNqLUzJvgIziQ0DiF3JwSImNphIqdGqzj6hIKyX04MmV0poclQ7+wjWvxQyR2A==",
"dev": true
}, },
"core-js-compat": { "core-js-compat": {
"version": "3.6.5", "version": "3.6.5",
@ -8034,6 +8047,11 @@
} }
} }
}, },
"core-js-pure": {
"version": "3.6.5",
"resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.6.5.tgz",
"integrity": "sha512-lacdXOimsiD0QyNf9BC/mxivNJ/ybBGJXQFKzRekp1WTHoVUWsUHEn+2T8GJAzzIhyOuXA+gOxCVN3l+5PLPUA=="
},
"core-util-is": { "core-util-is": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
@ -8086,23 +8104,11 @@
} }
}, },
"cross-fetch": { "cross-fetch": {
"version": "0.0.8", "version": "3.0.6",
"resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-0.0.8.tgz", "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.0.6.tgz",
"integrity": "sha1-Ae2U3EB98sAPGAf95wCnz6SKIFw=", "integrity": "sha512-KBPUbqgFjzWlVcURG+Svp9TlhA5uliYtiNx/0r8nv0pdypeQCRJ9IaSIc3q/x3q8t3F75cHuwxVql1HFGHCNJQ==",
"requires": { "requires": {
"node-fetch": "1.7.3", "node-fetch": "2.6.1"
"whatwg-fetch": "2.0.3"
},
"dependencies": {
"node-fetch": {
"version": "1.7.3",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz",
"integrity": "sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==",
"requires": {
"encoding": "^0.1.11",
"is-stream": "^1.0.1"
}
}
} }
}, },
"cross-spawn": { "cross-spawn": {
@ -8331,9 +8337,9 @@
"integrity": "sha1-9dJgKStmDghO/0zbyfCK0yR0SLU=" "integrity": "sha1-9dJgKStmDghO/0zbyfCK0yR0SLU="
}, },
"deep-extend": { "deep-extend": {
"version": "0.5.1", "version": "0.6.0",
"resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.5.1.tgz", "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
"integrity": "sha512-N8vBdOa+DF7zkRrDCsaOXoCs/E2fJfx9B9MrKnnSiHNh4ws7eSys6YQE4KvT1cecKmOASYQBhbKjeuDD9lT81w==" "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA=="
}, },
"deep-is": { "deep-is": {
"version": "0.1.3", "version": "0.1.3",
@ -8810,23 +8816,15 @@
"integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k=", "integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k=",
"dev": true "dev": true
}, },
"encode-3986": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/encode-3986/-/encode-3986-1.0.0.tgz",
"integrity": "sha1-lA1RSY+HQa3hhLda0UObMXwMemA="
},
"encodeurl": { "encodeurl": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
"integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k="
}, },
"encoding": { "encoding-japanese": {
"version": "0.1.12", "version": "1.0.30",
"resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz", "resolved": "https://registry.npmjs.org/encoding-japanese/-/encoding-japanese-1.0.30.tgz",
"integrity": "sha1-U4tm8+5izRq1HsMjgp0flIDHS+s=", "integrity": "sha512-bd/DFLAoJetvv7ar/KIpE3CNO8wEuyrt9Xuw6nSMiZ+Vrz/Q21BPsMHvARL2Wz6IKHKXgb+DWZqtRg1vql9cBg=="
"requires": {
"iconv-lite": "~0.4.13"
}
}, },
"end-of-stream": { "end-of-stream": {
"version": "1.4.1", "version": "1.4.1",
@ -12321,8 +12319,7 @@
"he": { "he": {
"version": "1.2.0", "version": "1.2.0",
"resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
"integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw=="
"dev": true
}, },
"helmet": { "helmet": {
"version": "3.21.2", "version": "3.21.2",
@ -12522,6 +12519,17 @@
} }
} }
}, },
"html-to-text": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/html-to-text/-/html-to-text-5.1.1.tgz",
"integrity": "sha512-Bci6bD/JIfZSvG4s0gW/9mMKwBRoe/1RWLxUME/d6WUSZCdY7T60bssf/jFf7EYXRyqU4P5xdClVqiYU0/ypdA==",
"requires": {
"he": "^1.2.0",
"htmlparser2": "^3.10.1",
"lodash": "^4.17.11",
"minimist": "^1.2.0"
}
},
"html-webpack-plugin": { "html-webpack-plugin": {
"version": "4.0.0-beta.11", "version": "4.0.0-beta.11",
"resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-4.0.0-beta.11.tgz", "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-4.0.0-beta.11.tgz",
@ -12757,6 +12765,38 @@
"integrity": "sha1-SMptcvbGo68Aqa1K5odr44ieKwk=", "integrity": "sha1-SMptcvbGo68Aqa1K5odr44ieKwk=",
"dev": true "dev": true
}, },
"imap": {
"version": "0.8.19",
"resolved": "https://registry.npmjs.org/imap/-/imap-0.8.19.tgz",
"integrity": "sha1-NniHOTSrCc6mukh0HyhNoq9Z2NU=",
"requires": {
"readable-stream": "1.1.x",
"utf7": ">=1.0.2"
},
"dependencies": {
"isarray": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
"integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8="
},
"readable-stream": {
"version": "1.1.14",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz",
"integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=",
"requires": {
"core-util-is": "~1.0.0",
"inherits": "~2.0.1",
"isarray": "0.0.1",
"string_decoder": "~0.10.x"
}
},
"string_decoder": {
"version": "0.10.31",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
"integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ="
}
}
},
"import-fresh": { "import-fresh": {
"version": "3.1.0", "version": "3.1.0",
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.1.0.tgz", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.1.0.tgz",
@ -13304,31 +13344,11 @@
"integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8="
}, },
"isomorphic-form-data": { "isomorphic-form-data": {
"version": "0.0.1", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/isomorphic-form-data/-/isomorphic-form-data-0.0.1.tgz", "resolved": "https://registry.npmjs.org/isomorphic-form-data/-/isomorphic-form-data-2.0.0.tgz",
"integrity": "sha1-Am9ifgMrDNhBPsyHVZKLlKRosGI=", "integrity": "sha512-TYgVnXWeESVmQSg4GLVbalmQ+B4NPi/H4eWxqALKj63KsUrcu301YDjBqaOw3h+cbak7Na4Xyps3BiptHtxTfg==",
"requires": { "requires": {
"form-data": "^1.0.0-rc3" "form-data": "^2.3.2"
},
"dependencies": {
"async": {
"version": "2.6.2",
"resolved": "https://registry.npmjs.org/async/-/async-2.6.2.tgz",
"integrity": "sha512-H1qVYh1MYhEEFLsP97cVKqCGo7KfCyTt6uEWqsTBr9SO84oK9Uwbyd/yCW+6rKJLHksBNUVWZDAjfS+Ccx0Bbg==",
"requires": {
"lodash": "^4.17.11"
}
},
"form-data": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-1.0.1.tgz",
"integrity": "sha1-rjFduaSQf6BlUCMEpm13M0de43w=",
"requires": {
"async": "^2.0.1",
"combined-stream": "^1.0.5",
"mime-types": "^2.1.11"
}
}
} }
}, },
"isstream": { "isstream": {
@ -18553,6 +18573,32 @@
"type-check": "~0.3.2" "type-check": "~0.3.2"
} }
}, },
"libbase64": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/libbase64/-/libbase64-1.2.1.tgz",
"integrity": "sha512-l+nePcPbIG1fNlqMzrh68MLkX/gTxk/+vdvAb388Ssi7UuUN31MI44w4Yf33mM3Cm4xDfw48mdf3rkdHszLNew=="
},
"libmime": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/libmime/-/libmime-5.0.0.tgz",
"integrity": "sha512-2Bm96d5ktnE217Ib1FldvUaPAaOst6GtZrsxJCwnJgi9lnsoAKIHyU0sae8rNx6DNYbjdqqh8lv5/b9poD8qOg==",
"requires": {
"encoding-japanese": "1.0.30",
"iconv-lite": "0.6.2",
"libbase64": "1.2.1",
"libqp": "1.1.0"
},
"dependencies": {
"iconv-lite": {
"version": "0.6.2",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.2.tgz",
"integrity": "sha512-2y91h5OpQlolefMPmUlivelittSWy0rP+oYVpn6A7GwVHNE8AWzoYOBNmlwks3LobaJxgHCYZAnyNo2GgpNRNQ==",
"requires": {
"safer-buffer": ">= 2.1.2 < 3.0.0"
}
}
}
},
"liboneandone": { "liboneandone": {
"version": "1.2.0", "version": "1.2.0",
"resolved": "https://registry.npmjs.org/liboneandone/-/liboneandone-1.2.0.tgz", "resolved": "https://registry.npmjs.org/liboneandone/-/liboneandone-1.2.0.tgz",
@ -18562,6 +18608,11 @@
"request": "^2.74.0" "request": "^2.74.0"
} }
}, },
"libqp": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/libqp/-/libqp-1.1.0.tgz",
"integrity": "sha1-9ebgatdLeU+1tbZpiL9yjvHe2+g="
},
"liftoff": { "liftoff": {
"version": "3.1.0", "version": "3.1.0",
"resolved": "https://registry.npmjs.org/liftoff/-/liftoff-3.1.0.tgz", "resolved": "https://registry.npmjs.org/liftoff/-/liftoff-3.1.0.tgz",
@ -18584,6 +18635,14 @@
"integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=", "integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=",
"dev": true "dev": true
}, },
"linkify-it": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-3.0.2.tgz",
"integrity": "sha512-gDBO4aHNZS6coiZCKVhSNh43F9ioIL4JwRjLZPkoLIY4yZFwg264Y5lu2x6rb1Js42Gh6Yqm2f6L2AJcnkzinQ==",
"requires": {
"uc.micro": "^1.0.1"
}
},
"load-json-file": { "load-json-file": {
"version": "1.1.0", "version": "1.1.0",
"resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz",
@ -19330,6 +19389,68 @@
"yallist": "^3.0.2" "yallist": "^3.0.2"
} }
}, },
"mailparser": {
"version": "2.8.0",
"resolved": "https://registry.npmjs.org/mailparser/-/mailparser-2.8.0.tgz",
"integrity": "sha512-Ja5H6/I1NKIFdFJF5HdZkaMGCN8F+1lu3870ZmrabkHQshhrPk4OWeEMiF0OVo82+6XJqemJPCg6pqgXaj3B6Q==",
"requires": {
"encoding-japanese": "1.0.30",
"he": "1.2.0",
"html-to-text": "5.1.1",
"iconv-lite": "0.6.2",
"libmime": "5.0.0",
"linkify-it": "3.0.2",
"mailsplit": "5.0.0",
"nodemailer": "6.4.10",
"tlds": "1.207.0"
},
"dependencies": {
"iconv-lite": {
"version": "0.6.2",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.2.tgz",
"integrity": "sha512-2y91h5OpQlolefMPmUlivelittSWy0rP+oYVpn6A7GwVHNE8AWzoYOBNmlwks3LobaJxgHCYZAnyNo2GgpNRNQ==",
"requires": {
"safer-buffer": ">= 2.1.2 < 3.0.0"
}
},
"nodemailer": {
"version": "6.4.10",
"resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.4.10.tgz",
"integrity": "sha512-j+pS9CURhPgk6r0ENr7dji+As2xZiHSvZeVnzKniLOw1eRAyM/7flP0u65tCnsapV8JFu+t0l/5VeHsCZEeh9g=="
}
}
},
"mailsplit": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/mailsplit/-/mailsplit-5.0.0.tgz",
"integrity": "sha512-HeXA0eyCKBtZqbr7uoeb3Nn2L7VV8Vm27x6/YBb0ZiNzRzLoNS2PqRgGYADwh0cBzLYtqddq40bSSirqLO2LGw==",
"requires": {
"libbase64": "1.2.1",
"libmime": "4.2.1",
"libqp": "1.1.0"
},
"dependencies": {
"iconv-lite": {
"version": "0.5.0",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.5.0.tgz",
"integrity": "sha512-NnEhI9hIEKHOzJ4f697DMz9IQEXr/MMJ5w64vN2/4Ai+wRnvV7SBrL0KLoRlwaKVghOc7LQ5YkPLuX146b6Ydw==",
"requires": {
"safer-buffer": ">= 2.1.2 < 3"
}
},
"libmime": {
"version": "4.2.1",
"resolved": "https://registry.npmjs.org/libmime/-/libmime-4.2.1.tgz",
"integrity": "sha512-09y7zjSc5im1aNsq815zgo4/G3DnIzym3aDOHsGq4Ee5vrX4PdgQRybAsztz9Rv0NhO+J5C0llEUloa3sUmjmA==",
"requires": {
"encoding-japanese": "1.0.30",
"iconv-lite": "0.5.0",
"libbase64": "1.2.1",
"libqp": "1.1.0"
}
}
}
},
"make-dir": { "make-dir": {
"version": "2.1.0", "version": "2.1.0",
"resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz",
@ -20202,9 +20323,9 @@
"integrity": "sha512-sSHCgWfJ+Lui/u+0msF3oyCgvdkhxDbkCS6Q8uiJquzOimkJBvX6hl5aSSA7DR1XbMpdM8r7phjcF63sF4rkKg==" "integrity": "sha512-sSHCgWfJ+Lui/u+0msF3oyCgvdkhxDbkCS6Q8uiJquzOimkJBvX6hl5aSSA7DR1XbMpdM8r7phjcF63sF4rkKg=="
}, },
"node-fetch": { "node-fetch": {
"version": "2.6.0", "version": "2.6.1",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.0.tgz", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz",
"integrity": "sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA==" "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw=="
}, },
"node-forge": { "node-forge": {
"version": "0.8.5", "version": "0.8.5",
@ -22028,7 +22149,8 @@
"regenerator-runtime": { "regenerator-runtime": {
"version": "0.11.1", "version": "0.11.1",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz",
"integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==" "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==",
"dev": true
}, },
"regenerator-transform": { "regenerator-transform": {
"version": "0.14.5", "version": "0.14.5",
@ -22928,7 +23050,7 @@
}, },
"sha.js": { "sha.js": {
"version": "2.4.11", "version": "2.4.11",
"resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", "resolved": "http://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz",
"integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==",
"dev": true, "dev": true,
"requires": { "requires": {
@ -24245,57 +24367,67 @@
} }
}, },
"swagger-client": { "swagger-client": {
"version": "3.9.0", "version": "3.11.0",
"resolved": "https://registry.npmjs.org/swagger-client/-/swagger-client-3.9.0.tgz", "resolved": "https://registry.npmjs.org/swagger-client/-/swagger-client-3.11.0.tgz",
"integrity": "sha512-uyCq2xoaAtmE0oIQ0fCfnsDoy/v97ANnAZywtyk4yumBP74xXp4NFlpZaqZJHN9K9dbPzgs3MH98VocZeM0ExQ==", "integrity": "sha512-5cM2S8qDmA0fwpGW71384Bik7MXI5D8XJz6uVHeH3X3gy9hZo8SDc7MeNShnxSLKAGIUHs9gIqjSeCrUftMNPw==",
"requires": { "requires": {
"@kyleshockey/js-yaml": "^1.0.1", "@babel/runtime-corejs3": "^7.11.2",
"@kyleshockey/object-assign-deep": "^0.4.0", "btoa": "^1.2.1",
"babel-runtime": "^6.26.0", "buffer": "^5.6.0",
"btoa": "1.1.2", "cookie": "~0.4.1",
"buffer": "^5.1.0", "cross-fetch": "^3.0.6",
"cookie": "^0.3.1", "deep-extend": "~0.6.0",
"cross-fetch": "0.0.8", "fast-json-patch": "^2.2.1",
"deep-extend": "^0.5.1", "isomorphic-form-data": "~2.0.0",
"encode-3986": "^1.0.0", "js-yaml": "^3.14.0",
"fast-json-patch": "^2.0.6", "lodash": "^4.17.19",
"isomorphic-form-data": "0.0.1", "qs": "^6.9.4",
"lodash": "^4.16.2",
"qs": "^6.3.0",
"querystring-browser": "^1.0.4", "querystring-browser": "^1.0.4",
"traverse": "^0.6.6", "traverse": "~0.6.6",
"url": "^0.11.0", "url": "~0.11.0"
"utf8-bytes": "0.0.1",
"utfstring": "^2.0.0"
}, },
"dependencies": { "dependencies": {
"@kyleshockey/js-yaml": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@kyleshockey/js-yaml/-/js-yaml-1.0.1.tgz",
"integrity": "sha512-coFyIk1LvTscq1cUU4nCCfYwv+cmG4fCP+wgDKgYZjhM4f++YwZy+g0k+1tUqa4GuUpBTEOGH2KUqKFFWdT73g==",
"requires": {
"argparse": "^1.0.7"
}
},
"buffer": { "buffer": {
"version": "5.2.1", "version": "5.6.0",
"resolved": "https://registry.npmjs.org/buffer/-/buffer-5.2.1.tgz", "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.6.0.tgz",
"integrity": "sha512-c+Ko0loDaFfuPWiL02ls9Xd3GO3cPVmUobQ6t3rXNUk304u6hGq+8N/kFi+QEIKhzK3uwolVhLzszmfLmMLnqg==", "integrity": "sha512-/gDYp/UtU0eA1ys8bOs9J6a+E/KWIY+DZ+Q2WESNUA0jFRsJOc0SNUO6xJ5SGA1xueg3NL65W6s+NY5l9cunuw==",
"requires": { "requires": {
"base64-js": "^1.0.2", "base64-js": "^1.0.2",
"ieee754": "^1.1.4" "ieee754": "^1.1.4"
} }
}, },
"cookie": { "cookie": {
"version": "0.3.1", "version": "0.4.1",
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz",
"integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=" "integrity": "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA=="
},
"fast-json-patch": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/fast-json-patch/-/fast-json-patch-2.2.1.tgz",
"integrity": "sha512-4j5uBaTnsYAV5ebkidvxiLUYOwjQ+JSFljeqfTxCrH9bDmlCQaOJFS84oDJ2rAXZq2yskmk3ORfoP9DCwqFNig==",
"requires": {
"fast-deep-equal": "^2.0.1"
}
},
"js-yaml": {
"version": "3.14.0",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz",
"integrity": "sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==",
"requires": {
"argparse": "^1.0.7",
"esprima": "^4.0.0"
}
}, },
"punycode": { "punycode": {
"version": "1.3.2", "version": "1.3.2",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz",
"integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=" "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0="
}, },
"qs": {
"version": "6.9.4",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.9.4.tgz",
"integrity": "sha512-A1kFqHekCTM7cz0udomYUoYNWjBebHm/5wzU/XqrBRBNWectVH0QIiN+NEcZ0Dte5hvzHwbr8+XQmguPhJ6WdQ=="
},
"url": { "url": {
"version": "0.11.0", "version": "0.11.0",
"resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz", "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz",
@ -24399,9 +24531,9 @@
}, },
"dependencies": { "dependencies": {
"bl": { "bl": {
"version": "4.0.2", "version": "4.0.3",
"resolved": "https://registry.npmjs.org/bl/-/bl-4.0.2.tgz", "resolved": "https://registry.npmjs.org/bl/-/bl-4.0.3.tgz",
"integrity": "sha512-j4OH8f6Qg2bGuWfRiltT2HYGx0e1QcBTrK9KAHNMwMZdQnDZFk0ZSYIpADjYCB3U12nicC5tVJwSIhwOWjb4RQ==", "integrity": "sha512-fs4G6/Hu4/EE+F75J8DuN/0IpQqNjAdC7aEQv7Qt8MHGUH7Ckv2MwTEEeN9QehD0pfIDkMI1bkHYkKy7xHyKIg==",
"requires": { "requires": {
"buffer": "^5.5.0", "buffer": "^5.5.0",
"inherits": "^2.0.4", "inherits": "^2.0.4",
@ -24669,6 +24801,11 @@
"setimmediate": "^1.0.4" "setimmediate": "^1.0.4"
} }
}, },
"tlds": {
"version": "1.207.0",
"resolved": "https://registry.npmjs.org/tlds/-/tlds-1.207.0.tgz",
"integrity": "sha512-k7d7Q1LqjtAvhtEOs3yN14EabsNO8ZCoY6RESSJDB9lst3bTx3as/m1UuAeCKzYxiyhR1qq72ZPhpSf+qlqiwg=="
},
"tmp": { "tmp": {
"version": "0.0.33", "version": "0.0.33",
"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
@ -24953,6 +25090,11 @@
"is-typedarray": "^1.0.0" "is-typedarray": "^1.0.0"
} }
}, },
"uc.micro": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz",
"integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA=="
},
"uglify-js": { "uglify-js": {
"version": "3.4.10", "version": "3.4.10",
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.4.10.tgz", "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.4.10.tgz",
@ -25293,15 +25435,20 @@
"integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==",
"dev": true "dev": true
}, },
"utf8-bytes": { "utf7": {
"version": "0.0.1", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/utf8-bytes/-/utf8-bytes-0.0.1.tgz", "resolved": "https://registry.npmjs.org/utf7/-/utf7-1.0.2.tgz",
"integrity": "sha1-EWsCVEjJtQAIHN+/H01sbDfYg30=" "integrity": "sha1-lV9JCq5lO6IguUVqCod2wZk2CZE=",
}, "requires": {
"utfstring": { "semver": "~5.3.0"
"version": "2.0.0", },
"resolved": "https://registry.npmjs.org/utfstring/-/utfstring-2.0.0.tgz", "dependencies": {
"integrity": "sha512-/ugBfyvIoLe9xqkFHio3CxXnpUKQ1p2LfTxPr6QTRj6GiwpHo73YGdh03UmAzDQNOWpNIE0J5nLss00L4xlWgg==" "semver": {
"version": "5.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz",
"integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8="
}
}
}, },
"util": { "util": {
"version": "0.11.1", "version": "0.11.1",
@ -26376,11 +26523,6 @@
"iconv-lite": "0.4.24" "iconv-lite": "0.4.24"
} }
}, },
"whatwg-fetch": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-2.0.3.tgz",
"integrity": "sha1-nITsLc9oGH/wC8ZOEnS0QhduHIQ="
},
"whatwg-mimetype": { "whatwg-mimetype": {
"version": "2.3.0", "version": "2.3.0",
"resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz", "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz",

View File

@ -16,6 +16,7 @@
"fs-extra": "^5.0.0", "fs-extra": "^5.0.0",
"helmet": "^3.21.2", "helmet": "^3.21.2",
"i18n": "^0.8.4", "i18n": "^0.8.4",
"imap": "^0.8.19",
"ldapjs": "^1.0.2", "ldapjs": "^1.0.2",
"loopback": "^3.26.0", "loopback": "^3.26.0",
"loopback-boot": "^2.27.1", "loopback-boot": "^2.27.1",
@ -24,6 +25,7 @@
"loopback-connector-mysql": "^5.4.3", "loopback-connector-mysql": "^5.4.3",
"loopback-connector-remote": "^3.4.1", "loopback-connector-remote": "^3.4.1",
"loopback-context": "^3.4.0", "loopback-context": "^3.4.0",
"mailparser": "^2.8.0",
"md5": "^2.2.1", "md5": "^2.2.1",
"node-ssh": "^11.0.0", "node-ssh": "^11.0.0",
"object-diff": "0.0.4", "object-diff": "0.0.4",