Merge branch 'dev' of https://gitea.verdnatura.es/verdnatura/salix into 2569-travel_extra_community
gitea/salix/pipeline/head There was a failure building this commit
Details
gitea/salix/pipeline/head There was a failure building this commit
Details
This commit is contained in:
commit
f4e9fc83ec
|
@ -1,4 +1,5 @@
|
|||
const md5 = require('md5');
|
||||
const UserError = require('vn-loopback/util/user-error');
|
||||
|
||||
module.exports = Self => {
|
||||
Self.remoteMethod('login', {
|
||||
|
@ -12,7 +13,7 @@ module.exports = Self => {
|
|||
}, {
|
||||
arg: 'password',
|
||||
type: 'String',
|
||||
description: 'The user name or email'
|
||||
description: 'The password'
|
||||
}
|
||||
],
|
||||
returns: {
|
||||
|
@ -29,44 +30,41 @@ module.exports = Self => {
|
|||
let $ = Self.app.models;
|
||||
let token;
|
||||
let usesEmail = user.indexOf('@') !== -1;
|
||||
|
||||
let userInfo = usesEmail
|
||||
? {email: user}
|
||||
: {username: user};
|
||||
let instance = await $.User.findOne({
|
||||
fields: ['username', 'password'],
|
||||
where: userInfo
|
||||
});
|
||||
|
||||
let loginInfo = Object.assign({password}, userInfo);
|
||||
let where = usesEmail
|
||||
? {email: user}
|
||||
: {name: user};
|
||||
let account = await Self.findOne({
|
||||
fields: ['active', 'password'],
|
||||
where
|
||||
});
|
||||
|
||||
let validCredentials = instance && (
|
||||
await instance.hasPassword(password) ||
|
||||
account.password == md5(password || '')
|
||||
);
|
||||
|
||||
if (validCredentials) {
|
||||
if (!account.active)
|
||||
throw new UserError('User disabled');
|
||||
|
||||
try {
|
||||
token = await $.User.login(loginInfo, 'user');
|
||||
try {
|
||||
let instance = await $.User.findOne({
|
||||
fields: ['username'],
|
||||
where: userInfo
|
||||
});
|
||||
await $.UserAccount.sync(instance.username, password);
|
||||
} catch (err) {
|
||||
console.warn(err);
|
||||
}
|
||||
} catch (err) {
|
||||
if (err.code != 'LOGIN_FAILED')
|
||||
throw err;
|
||||
|
||||
let where = usesEmail
|
||||
? {email: user}
|
||||
: {name: user};
|
||||
Object.assign(where, {
|
||||
password: md5(password || '')
|
||||
});
|
||||
|
||||
let instance = await Self.findOne({
|
||||
fields: ['name'],
|
||||
where
|
||||
});
|
||||
if (!instance) throw err;
|
||||
|
||||
await $.UserAccount.sync(instance.name, password);
|
||||
token = await $.User.login(loginInfo, 'user');
|
||||
}
|
||||
|
||||
let loginInfo = Object.assign({password}, userInfo);
|
||||
token = await $.User.login(loginInfo, 'user');
|
||||
return {token: token.id};
|
||||
};
|
||||
};
|
||||
|
|
|
@ -53,9 +53,6 @@
|
|||
"Warehouse": {
|
||||
"dataSource": "vn"
|
||||
},
|
||||
"Sip": {
|
||||
"dataSource": "vn"
|
||||
},
|
||||
"SageWithholding": {
|
||||
"dataSource": "vn"
|
||||
},
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
"base": "User",
|
||||
"options": {
|
||||
"mysql": {
|
||||
"table": "salix.user"
|
||||
"table": "salix.User"
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
|
|
|
@ -13,10 +13,24 @@ ALTER TABLE account.ldapConfig MODIFY COLUMN password varchar(255) NOT NULL COMM
|
|||
|
||||
ALTER TABLE account.sambaConfig DROP COLUMN sshUser;
|
||||
ALTER TABLE account.sambaConfig DROP COLUMN sshPassword;
|
||||
ALTER TABLE account.sambaConfig CHANGE host adController varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL NULL COMMENT 'The hosname of domain controller';
|
||||
ALTER TABLE account.sambaConfig MODIFY COLUMN adController varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL NULL COMMENT 'The hosname of domain controller';
|
||||
ALTER TABLE account.sambaConfig CHANGE host adController varchar(255) DEFAULT NULL NULL COMMENT 'The hosname of domain controller';
|
||||
ALTER TABLE account.sambaConfig MODIFY COLUMN adController varchar(255) DEFAULT NULL NULL COMMENT 'The hosname of domain controller';
|
||||
|
||||
ALTER TABLE account.sambaConfig DROP COLUMN userDn;
|
||||
ALTER TABLE account.sambaConfig ADD adDomain varchar(255) NOT NULL AFTER id;
|
||||
ALTER TABLE account.sambaConfig ADD verifyCert TINYINT UNSIGNED NOT NULL DEFAULT TRUE AFTER adPassword;
|
||||
ALTER TABLE account.sambaConfig MODIFY COLUMN adController varchar(255) NOT NULL COMMENT 'The hosname of domain controller';
|
||||
|
||||
ALTER TABLE account.user
|
||||
ADD COLUMN `realm` varchar(512) CHARACTER SET utf8 DEFAULT NULL AFTER id,
|
||||
ADD COLUMN `emailVerified` tinyint(1) DEFAULT NULL AFTER email,
|
||||
ADD COLUMN `verificationToken` varchar(512) DEFAULT NULL AFTER emailVerified;
|
||||
|
||||
DROP TABLE salix.user;
|
||||
|
||||
CREATE OR REPLACE VIEW salix.User
|
||||
AS SELECT id, realm, name AS username, bcryptPassword AS password, email, emailVerified, verificationToken
|
||||
FROM account.user;
|
||||
|
||||
ALTER TABLE account.`user`
|
||||
MODIFY COLUMN bcryptPassword varchar(512) DEFAULT NULL NULL;
|
||||
|
|
|
@ -1,13 +1,12 @@
|
|||
|
||||
UPDATE `salix`.`ACL` SET `principalId` = 'deliveryBoss' WHERE (`id` = '194');
|
||||
UPDATE `salix`.`ACL` SET `principalId` = 'claimManager' WHERE (`id` = '97');
|
||||
UPDATE `salix`.`ACL` SET `principalId` = 'claimManager' WHERE (`id` = '100');
|
||||
UPDATE `salix`.`ACL` SET `principalId` = 'claimManager' WHERE (`id` = '103');
|
||||
UPDATE `salix`.`ACL` SET `principalId` = 'claimManager' WHERE (`id` = '202');
|
||||
|
||||
INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`) VALUES ('Town', '*', 'WRITE', 'ALLOW', 'ROLE', 'deliveryBoss');
|
||||
INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`) VALUES ('Province', '*', 'WRITE', 'ALLOW', 'ROLE', 'deliveryBoss');
|
||||
INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`) VALUES ('Supplier', '*', 'READ', 'ALLOW', 'ROLE', 'employee');
|
||||
INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`) VALUES ('Supplier', '*', 'WRITE', 'ALLOW', 'ROLE', 'administrative');
|
||||
INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`) VALUES ('SupplierLog', '*', 'READ', 'ALLOW', 'ROLE', 'employee');
|
||||
INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`) VALUES ('SupplierContact', '*', 'WRITE', 'ALLOW', 'ROLE', 'administrative');
|
||||
INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`) VALUES ('Town', '*', 'WRITE', 'ALLOW', 'ROLE', 'deliveryBoss');
|
||||
INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`) VALUES ('Province', '*', 'WRITE', 'ALLOW', 'ROLE', 'deliveryBoss');
|
||||
INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`) VALUES ('SupplierContact', '*', 'WRITE', 'ALLOW', 'ROLE', 'administrative');
|
|
@ -0,0 +1,20 @@
|
|||
CREATE TABLE `vn`.supplierFreighter
|
||||
(
|
||||
supplierFk INT NOT NULL,
|
||||
CONSTRAINT supplierFreighter_pk
|
||||
PRIMARY KEY (supplierFk),
|
||||
CONSTRAINT supplier_id_fk
|
||||
FOREIGN KEY (supplierFk) REFERENCES supplier (id)
|
||||
ON UPDATE CASCADE ON DELETE CASCADE
|
||||
);
|
||||
|
||||
INSERT IGNORE INTO `vn`.supplierFreighter (supplierFk) VALUES (286);
|
||||
INSERT IGNORE INTO `vn`.supplierFreighter (supplierFk) VALUES (454);
|
||||
INSERT IGNORE INTO `vn`.supplierFreighter (supplierFk) VALUES (582);
|
||||
INSERT IGNORE INTO `vn`.supplierFreighter (supplierFk) VALUES (470);
|
||||
INSERT IGNORE INTO `vn`.supplierFreighter (supplierFk) VALUES (775);
|
||||
INSERT IGNORE INTO `vn`.supplierFreighter (supplierFk) VALUES (812);
|
||||
INSERT IGNORE INTO `vn`.supplierFreighter (supplierFk) VALUES (1112);
|
||||
INSERT IGNORE INTO `vn`.supplierFreighter (supplierFk) VALUES (1242);
|
||||
INSERT IGNORE INTO `vn`.supplierFreighter (supplierFk) VALUES (1281);
|
||||
INSERT IGNORE INTO `vn`.supplierFreighter (supplierFk) VALUES (1765);
|
|
@ -0,0 +1,7 @@
|
|||
ALTER TABLE `vn`.travel
|
||||
DROP FOREIGN KEY travel_ibfk_4;
|
||||
|
||||
ALTER TABLE `vn`.travel
|
||||
ADD CONSTRAINT supplierFreighter_fk_4
|
||||
FOREIGN KEY (cargoSupplierFk) REFERENCES supplierFreighter (supplierFk)
|
||||
ON UPDATE CASCADE ON DELETE SET NULL;
|
|
@ -439,7 +439,7 @@ INSERT INTO `vn`.`bankEntity`(`id`, `countryFk`, `name`, `bic`)
|
|||
(2100, 1, 'Caixa Bank', 'CAIXESBB');
|
||||
|
||||
INSERT INTO `vn`.`supplierAccount`(`id`, `supplierFk`, `iban`, `bankEntityFk`)
|
||||
VALUES
|
||||
VALUES
|
||||
(241, 442, 'ES111122333344111122221111', 128);
|
||||
|
||||
INSERT INTO `vn`.`company`(`id`, `code`, `supplierAccountFk`, `workerManagerFk`, `companyCode`, `sage200Company`, `expired`)
|
||||
|
@ -1226,6 +1226,11 @@ INSERT INTO `vn`.`supplierContact`(`id`, `supplierFk`, `phone`, `mobile`, `email
|
|||
(3, 2, 321654987, NULL, 'supplier2@email.es', NULL, NULL),
|
||||
(4, 442, 321654987, NULL, NULL, 'observation442', NULL);
|
||||
|
||||
INSERT INTO `vn`.`supplierFreighter` (`supplierFk`)
|
||||
VALUES
|
||||
(1),
|
||||
(2);
|
||||
|
||||
INSERT INTO `cache`.`cache_calc`(`id`, `cache_id`, `cacheName`, `params`, `last_refresh`, `expires`, `created`, `connection_id`)
|
||||
VALUES
|
||||
(1, 2, 'available', CONCAT_WS('/',1,CURDATE()), CURRENT_TIMESTAMP(), DATE_ADD(CURRENT_TIMESTAMP(),INTERVAL 15 MINUTE), CURDATE(), NULL),
|
||||
|
@ -1240,16 +1245,16 @@ INSERT INTO `vn`.`ticketWeekly`(`ticketFk`, `weekDay`)
|
|||
(4, 4),
|
||||
(5, 6);
|
||||
|
||||
INSERT INTO `vn`.`travel`(`id`,`shipped`, `landed`, `warehouseInFk`, `warehouseOutFk`, `agencyFk`, `m3`, `kg`,`ref`, `totalEntries`)
|
||||
INSERT INTO `vn`.`travel`(`id`,`shipped`, `landed`, `warehouseInFk`, `warehouseOutFk`, `agencyFk`, `m3`, `kg`,`ref`, `totalEntries`, `cargoSupplierFk`)
|
||||
VALUES
|
||||
(1, DATE_ADD(CURDATE(), INTERVAL -2 MONTH), DATE_ADD(CURDATE(), INTERVAL -2 MONTH), 1, 2, 1, 100.00, 1000, 'first travel', 1),
|
||||
(2, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), DATE_ADD(CURDATE(), INTERVAL -1 MONTH), 1, 2, 1, 150, 2000, 'second travel', 2),
|
||||
(3, CURDATE(), CURDATE(), 1, 2, 1, 0.00, 0.00, 'third travel', 1),
|
||||
(4, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), DATE_ADD(CURDATE(), INTERVAL -1 MONTH), 1, 2, 1, 50.00, 500, 'fourth travel', 0),
|
||||
(5, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), DATE_ADD(CURDATE(), INTERVAL -1 MONTH), 3, 2, 1, 50.00, 500, 'fifth travel', 1),
|
||||
(6, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), DATE_ADD(CURDATE(), INTERVAL -1 MONTH), 4, 2, 1, 50.00, 500, 'sixth travel', 1),
|
||||
(7, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), DATE_ADD(CURDATE(), INTERVAL -1 MONTH), 5, 2, 1, 50.00, 500, 'seventh travel', 2),
|
||||
(8, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), DATE_ADD(CURDATE(), INTERVAL -1 MONTH), 5, 2, 1, 50.00, 500, 'eight travel', 1);
|
||||
(1, DATE_ADD(CURDATE(), INTERVAL -2 MONTH), DATE_ADD(CURDATE(), INTERVAL -2 MONTH), 1, 2, 1, 100.00, 1000, 'first travel', 1, 1),
|
||||
(2, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), DATE_ADD(CURDATE(), INTERVAL -1 MONTH), 1, 2, 1, 150, 2000, 'second travel', 2, 2),
|
||||
(3, CURDATE(), CURDATE(), 1, 2, 1, 0.00, 0.00, 'third travel', 1, 1),
|
||||
(4, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), DATE_ADD(CURDATE(), INTERVAL -1 MONTH), 1, 2, 1, 50.00, 500, 'fourth travel', 0, 2),
|
||||
(5, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), DATE_ADD(CURDATE(), INTERVAL -1 MONTH), 3, 2, 1, 50.00, 500, 'fifth travel', 1, 1),
|
||||
(6, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), DATE_ADD(CURDATE(), INTERVAL -1 MONTH), 4, 2, 1, 50.00, 500, 'sixth travel', 1, 2),
|
||||
(7, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), DATE_ADD(CURDATE(), INTERVAL -1 MONTH), 5, 2, 1, 50.00, 500, 'seventh travel', 2, 1),
|
||||
(8, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), DATE_ADD(CURDATE(), INTERVAL -1 MONTH), 5, 2, 1, 50.00, 500, 'eight travel', 1, 2);
|
||||
|
||||
INSERT INTO `vn`.`entry`(`id`, `supplierFk`, `created`, `travelFk`, `isConfirmed`, `companyFk`, `ref`,`isInventory`, `isRaid`, `notes`, `evaNotes`)
|
||||
VALUES
|
||||
|
|
|
@ -496,7 +496,8 @@ export default {
|
|||
moveToTicketInput: 'form vn-input-number[ng-model="$ctrl.transfer.ticketId"] input',
|
||||
moveToTicketButton: '.vn-popover.shown vn-icon[icon="arrow_forward_ios"]',
|
||||
moveToNewTicketButton: '.vn-popover.shown vn-button[label="New ticket"]',
|
||||
stateMenuButton: 'vn-ticket-sale vn-tool-bar > vn-button-menu[label="State"]'
|
||||
stateMenuButton: 'vn-ticket-sale vn-tool-bar > vn-button-menu[label="State"]',
|
||||
moreMenuState: 'body > div > div > div.content > div.filter.ng-scope > vn-textfield'
|
||||
},
|
||||
ticketTracking: {
|
||||
createStateButton: 'vn-float-button'
|
||||
|
|
|
@ -43,7 +43,9 @@ describe('Worker calendar path', () => {
|
|||
await page.waitToClick(selectors.workerCalendar.furlough);
|
||||
await page.waitFor(reasonableTimeBetweenClicks);
|
||||
await page.waitToClick(selectors.workerCalendar.mayTwelfth);
|
||||
await page.waitFor(reasonableTimeBetweenClicks);
|
||||
await page.waitToClick(selectors.workerCalendar.mayThirteenth);
|
||||
await page.waitFor(reasonableTimeBetweenClicks);
|
||||
await page.waitToClick(selectors.workerCalendar.mayFourteenth);
|
||||
|
||||
await page.waitFor(reasonableTimeBetweenClicks);
|
||||
|
@ -85,7 +87,9 @@ describe('Worker calendar path', () => {
|
|||
await page.waitToClick(selectors.workerCalendar.furlough);
|
||||
await page.waitFor(reasonableTimeBetweenClicks);
|
||||
await page.waitToClick(selectors.workerCalendar.mayTwelfth);
|
||||
await page.waitFor(reasonableTimeBetweenClicks);
|
||||
await page.waitToClick(selectors.workerCalendar.mayThirteenth);
|
||||
await page.waitFor(reasonableTimeBetweenClicks);
|
||||
await page.waitToClick(selectors.workerCalendar.mayFourteenth);
|
||||
|
||||
await page.waitFor(reasonableTimeBetweenClicks);
|
||||
|
|
|
@ -35,9 +35,23 @@ describe('Ticket Edit sale path', () => {
|
|||
});
|
||||
|
||||
it(`should set the ticket as libre`, async() => {
|
||||
const searchValue = 'libre';
|
||||
await page.waitToClick(selectors.ticketSales.stateMenuButton);
|
||||
await page.write('body > div > div > div.content > div.filter.ng-scope > vn-textfield', 'libre');
|
||||
await page.waitFor(500);
|
||||
await page.write(selectors.ticketSales.moreMenuState, searchValue);
|
||||
try {
|
||||
await page.waitForFunction(searchValue => {
|
||||
const element = document.querySelector('li.active');
|
||||
if (element)
|
||||
return element.innerText.toLowerCase().includes(searchValue.toLowerCase());
|
||||
}, {}, searchValue);
|
||||
} catch (error) {
|
||||
const builtSelector = await page.selectorFormater(selectors.ticketSales.moreMenuState);
|
||||
const inputValue = await page.evaluate(() => {
|
||||
return document.querySelector('.vn-drop-down.shown vn-textfield input').value;
|
||||
});
|
||||
throw new Error(`${builtSelector} value is ${inputValue}! ${error}`);
|
||||
}
|
||||
await page.waitForState('ticket.card.sale');
|
||||
await page.keyboard.press('Enter');
|
||||
const message = await page.waitForSnackbar();
|
||||
|
||||
|
|
|
@ -9,10 +9,18 @@ module.exports = Self => {
|
|||
this.synchronizers.push(synchronizer);
|
||||
},
|
||||
|
||||
async getInstance() {
|
||||
let instance = await Self.findOne({
|
||||
fields: ['homedir', 'shell', 'idBase']
|
||||
});
|
||||
await instance.synchronizerInit();
|
||||
return instance;
|
||||
},
|
||||
|
||||
async syncUsers() {
|
||||
let instance = await Self.getInstance();
|
||||
|
||||
let usersToSync = instance.getUsers();
|
||||
let usersToSync = await instance.synchronizerGetUsers();
|
||||
usersToSync = Array.from(usersToSync.values())
|
||||
.sort((a, b) => a.localeCompare(b));
|
||||
|
||||
|
@ -20,9 +28,9 @@ module.exports = Self => {
|
|||
try {
|
||||
console.log(`Synchronizing user '${userName}'`);
|
||||
await instance.synchronizerSyncUser(userName);
|
||||
console.log(` -> '${userName}' sinchronized`);
|
||||
console.log(` -> User '${userName}' sinchronized`);
|
||||
} catch (err) {
|
||||
console.error(` -> '${userName}' synchronization error:`, err.message);
|
||||
console.error(` -> User '${userName}' synchronization error:`, err.message);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -50,14 +58,6 @@ module.exports = Self => {
|
|||
|
||||
async getSynchronizer() {
|
||||
return await Self.findOne();
|
||||
},
|
||||
|
||||
async getInstance() {
|
||||
let instance = await Self.findOne({
|
||||
fields: ['homedir', 'shell', 'idBase']
|
||||
});
|
||||
await instance.synchronizerInit();
|
||||
return instance;
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -171,34 +171,8 @@ module.exports = Self => {
|
|||
},
|
||||
|
||||
async syncUser(userName, info, password) {
|
||||
let $ = app.models;
|
||||
let {user} = info;
|
||||
|
||||
if (user && user.active) {
|
||||
let bcryptPassword = password
|
||||
? $.User.hashPassword(password)
|
||||
: user.bcryptPassword;
|
||||
|
||||
await $.Account.upsertWithWhere({id: user.id},
|
||||
{bcryptPassword}
|
||||
);
|
||||
|
||||
let dbUser = {
|
||||
id: user.id,
|
||||
username: userName,
|
||||
email: user.email,
|
||||
created: user.created,
|
||||
updated: user.updated
|
||||
};
|
||||
if (bcryptPassword)
|
||||
dbUser.password = bcryptPassword;
|
||||
|
||||
if (await $.user.exists(user.id))
|
||||
await $.user.replaceById(user.id, dbUser);
|
||||
else
|
||||
await $.user.create(dbUser);
|
||||
} else
|
||||
await $.user.destroyAll({username: userName});
|
||||
if (info.user && password)
|
||||
await app.models.user.setPassword(info.user.id, password);
|
||||
},
|
||||
|
||||
async getUsers(usersToSync) {
|
||||
|
|
|
@ -35,109 +35,104 @@ module.exports = Self => {
|
|||
accountConfig
|
||||
} = this;
|
||||
|
||||
let {user} = info;
|
||||
let newEntry;
|
||||
|
||||
let res = await client.search(this.userDn, {
|
||||
scope: 'sub',
|
||||
attributes: ['userPassword', 'sambaNTPassword'],
|
||||
filter: `&(uid=${userName})`
|
||||
});
|
||||
if (info.hasAccount) {
|
||||
let {user} = info;
|
||||
|
||||
let oldUser;
|
||||
await new Promise((resolve, reject) => {
|
||||
res.on('error', reject);
|
||||
res.on('searchEntry', e => oldUser = e.object);
|
||||
res.on('end', resolve);
|
||||
});
|
||||
let oldUser = await client.searchOne(this.userDn, {
|
||||
scope: 'sub',
|
||||
attributes: ['userPassword', 'sambaNTPassword'],
|
||||
filter: `&(uid=${userName})`
|
||||
});
|
||||
|
||||
let nickname = user.nickname || userName;
|
||||
let nameArgs = nickname.trim().split(' ');
|
||||
let sn = nameArgs.length > 1
|
||||
? nameArgs.splice(1).join(' ')
|
||||
: '-';
|
||||
|
||||
newEntry = {
|
||||
uid: userName,
|
||||
objectClass: [
|
||||
'inetOrgPerson',
|
||||
'posixAccount',
|
||||
'sambaSamAccount'
|
||||
],
|
||||
cn: nickname,
|
||||
displayName: nickname,
|
||||
givenName: nameArgs[0],
|
||||
sn,
|
||||
mail: info.corporateMail,
|
||||
preferredLanguage: user.lang || 'en',
|
||||
homeDirectory: `${accountConfig.homedir}/${userName}`,
|
||||
loginShell: accountConfig.shell,
|
||||
uidNumber: info.uidNumber,
|
||||
gidNumber: accountConfig.idBase + user.roleFk,
|
||||
sambaSID: '-'
|
||||
};
|
||||
|
||||
if (password) {
|
||||
let salt = crypto
|
||||
.randomBytes(8)
|
||||
.toString('base64');
|
||||
|
||||
let hash = crypto.createHash('sha1');
|
||||
hash.update(password);
|
||||
hash.update(salt, 'binary');
|
||||
let digest = hash.digest('binary');
|
||||
|
||||
let ssha = Buffer
|
||||
.from(digest + salt, 'binary')
|
||||
.toString('base64');
|
||||
|
||||
Object.assign(newEntry, {
|
||||
userPassword: `{SSHA}${ssha}`,
|
||||
sambaNTPassword: nthash(password)
|
||||
});
|
||||
} else if (oldUser) {
|
||||
Object.assign(newEntry, {
|
||||
userPassword: oldUser.userPassword,
|
||||
sambaNTPassword: oldUser.sambaNTPassword
|
||||
});
|
||||
}
|
||||
|
||||
for (let prop in newEntry) {
|
||||
if (newEntry[prop] == null)
|
||||
delete newEntry[prop];
|
||||
}
|
||||
}
|
||||
|
||||
// Remove and recreate (if applicable) user
|
||||
|
||||
let dn = `uid=${userName},${this.userDn}`;
|
||||
let operation;
|
||||
|
||||
try {
|
||||
let dn = `uid=${userName},${this.userDn}`;
|
||||
await client.del(dn);
|
||||
operation = 'delete';
|
||||
} catch (e) {
|
||||
if (e.name !== 'NoSuchObjectError') throw e;
|
||||
}
|
||||
|
||||
if (!info.hasAccount) {
|
||||
if (oldUser)
|
||||
console.log(` -> '${userName}' removed from LDAP`);
|
||||
return;
|
||||
if (info.hasAccount) {
|
||||
await client.add(dn, newEntry);
|
||||
operation = 'add';
|
||||
}
|
||||
|
||||
let nickname = user.nickname || userName;
|
||||
let nameArgs = nickname.trim().split(' ');
|
||||
let sn = nameArgs.length > 1
|
||||
? nameArgs.splice(1).join(' ')
|
||||
: '-';
|
||||
|
||||
let dn = `uid=${userName},${this.userDn}`;
|
||||
let newEntry = {
|
||||
uid: userName,
|
||||
objectClass: [
|
||||
'inetOrgPerson',
|
||||
'posixAccount',
|
||||
'sambaSamAccount'
|
||||
],
|
||||
cn: nickname,
|
||||
displayName: nickname,
|
||||
givenName: nameArgs[0],
|
||||
sn,
|
||||
mail: info.corporateMail,
|
||||
preferredLanguage: user.lang || 'en',
|
||||
homeDirectory: `${accountConfig.homedir}/${userName}`,
|
||||
loginShell: accountConfig.shell,
|
||||
uidNumber: info.uidNumber,
|
||||
gidNumber: accountConfig.idBase + user.roleFk,
|
||||
sambaSID: '-'
|
||||
};
|
||||
|
||||
if (password) {
|
||||
let salt = crypto
|
||||
.randomBytes(8)
|
||||
.toString('base64');
|
||||
|
||||
let hash = crypto.createHash('sha1');
|
||||
hash.update(password);
|
||||
hash.update(salt, 'binary');
|
||||
let digest = hash.digest('binary');
|
||||
|
||||
let ssha = Buffer
|
||||
.from(digest + salt, 'binary')
|
||||
.toString('base64');
|
||||
|
||||
Object.assign(newEntry, {
|
||||
userPassword: `{SSHA}${ssha}`,
|
||||
sambaNTPassword: nthash(password)
|
||||
});
|
||||
} else if (oldUser) {
|
||||
Object.assign(newEntry, {
|
||||
userPassword: oldUser.userPassword,
|
||||
sambaNTPassword: oldUser.sambaNTPassword
|
||||
});
|
||||
}
|
||||
|
||||
for (let prop in newEntry) {
|
||||
if (newEntry[prop] == null)
|
||||
delete newEntry[prop];
|
||||
}
|
||||
|
||||
await client.add(dn, newEntry);
|
||||
if (operation === 'delete')
|
||||
console.log(` -> User '${userName}' removed from LDAP`);
|
||||
},
|
||||
|
||||
async syncUserGroups(userName, info) {
|
||||
let {client} = this;
|
||||
|
||||
let res = await client.search(this.groupDn, {
|
||||
let opts = {
|
||||
scope: 'sub',
|
||||
attributes: ['dn'],
|
||||
filter: `&(memberUid=${userName})(objectClass=posixGroup)`
|
||||
});
|
||||
|
||||
let oldGroups = [];
|
||||
await new Promise((resolve, reject) => {
|
||||
res.on('error', reject);
|
||||
res.on('searchEntry', e => oldGroups.push(e.object));
|
||||
res.on('end', resolve);
|
||||
});
|
||||
};
|
||||
let oldGroups = await client.searchAll(this.groupDn, opts);
|
||||
|
||||
let reqs = [];
|
||||
for (let oldGroup of oldGroups) {
|
||||
|
@ -167,17 +162,13 @@ module.exports = Self => {
|
|||
async getUsers(usersToSync) {
|
||||
let {client} = this;
|
||||
|
||||
let res = await client.search(this.userDn, {
|
||||
let opts = {
|
||||
scope: 'sub',
|
||||
attributes: ['uid'],
|
||||
filter: `uid=*`
|
||||
});
|
||||
|
||||
await new Promise((resolve, reject) => {
|
||||
res.on('error', reject);
|
||||
res.on('searchEntry', e => usersToSync.add(e.object.uid));
|
||||
res.on('end', resolve);
|
||||
});
|
||||
};
|
||||
await client.searchForeach(this.userDn, opts,
|
||||
o => usersToSync.add(o.uid));
|
||||
},
|
||||
|
||||
async syncRoles() {
|
||||
|
@ -187,30 +178,7 @@ module.exports = Self => {
|
|||
accountConfig
|
||||
} = this;
|
||||
|
||||
// Delete roles
|
||||
|
||||
let opts = {
|
||||
scope: 'sub',
|
||||
attributes: ['dn'],
|
||||
filter: 'objectClass=posixGroup'
|
||||
};
|
||||
let res = await client.search(this.groupDn, opts);
|
||||
|
||||
let reqs = [];
|
||||
await new Promise((resolve, reject) => {
|
||||
res.on('error', err => {
|
||||
if (err.name === 'NoSuchObjectError')
|
||||
err = new Error(`Object '${this.groupDn}' does not exist`);
|
||||
reject(err);
|
||||
});
|
||||
res.on('searchEntry', e => {
|
||||
reqs.push(client.del(e.object.dn));
|
||||
});
|
||||
res.on('end', resolve);
|
||||
});
|
||||
await Promise.all(reqs);
|
||||
|
||||
// Recreate roles
|
||||
// Prepare data
|
||||
|
||||
let roles = await $.Role.find({
|
||||
fields: ['id', 'name', 'description']
|
||||
|
@ -238,6 +206,20 @@ module.exports = Self => {
|
|||
return {key: user.roleFk, val: user.name};
|
||||
});
|
||||
|
||||
// Delete roles
|
||||
|
||||
let opts = {
|
||||
scope: 'sub',
|
||||
attributes: ['dn'],
|
||||
filter: 'objectClass=posixGroup'
|
||||
};
|
||||
let reqs = [];
|
||||
await client.searchForeach(this.groupDn, opts,
|
||||
o => reqs.push(client.del(o.dn)));
|
||||
await Promise.all(reqs);
|
||||
|
||||
// Recreate roles
|
||||
|
||||
reqs = [];
|
||||
for (let role of roles) {
|
||||
let newEntry = {
|
||||
|
@ -263,3 +245,15 @@ module.exports = Self => {
|
|||
}
|
||||
});
|
||||
};
|
||||
|
||||
function toMap(array, fn) {
|
||||
let map = new Map();
|
||||
for (let item of array) {
|
||||
let keyVal = fn(item);
|
||||
if (!keyVal) continue;
|
||||
let key = keyVal.key;
|
||||
if (!map.has(key)) map.set(key, []);
|
||||
map.get(key).push(keyVal.val);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
|
|
@ -2,6 +2,14 @@
|
|||
const ldap = require('../util/ldapjs-extra');
|
||||
const ssh = require('node-ssh');
|
||||
|
||||
/**
|
||||
* Summary of userAccountControl flags:
|
||||
* https://docs.microsoft.com/en-us/troubleshoot/windows-server/identity/useraccountcontrol-manipulate-account-properties
|
||||
*/
|
||||
const UserAccountControlFlags = {
|
||||
ACCOUNTDISABLE: 2
|
||||
};
|
||||
|
||||
module.exports = Self => {
|
||||
Self.getSynchronizer = async function() {
|
||||
return await Self.findOne({
|
||||
|
@ -55,8 +63,16 @@ module.exports = Self => {
|
|||
async syncUser(userName, info, password) {
|
||||
let {sshClient} = this;
|
||||
|
||||
let sambaUser = await this.adClient.searchOne(this.usersDn(), {
|
||||
scope: 'sub',
|
||||
attributes: ['userAccountControl'],
|
||||
filter: `(&(objectClass=user)(sAMAccountName=${userName}))`
|
||||
});
|
||||
let isEnabled = sambaUser
|
||||
&& !(sambaUser.userAccountControl & UserAccountControlFlags.ACCOUNTDISABLE);
|
||||
|
||||
if (info.hasAccount) {
|
||||
try {
|
||||
if (!sambaUser) {
|
||||
await sshClient.exec('samba-tool user create', [
|
||||
userName,
|
||||
'--uid-number', `${info.uidNumber}`,
|
||||
|
@ -71,58 +87,42 @@ module.exports = Self => {
|
|||
userName,
|
||||
'0027'
|
||||
]);
|
||||
} catch (e) {}
|
||||
|
||||
await sshClient.exec('samba-tool user enable', [
|
||||
userName
|
||||
]);
|
||||
|
||||
}
|
||||
if (!isEnabled) {
|
||||
await sshClient.exec('samba-tool user enable', [
|
||||
userName
|
||||
]);
|
||||
}
|
||||
if (password) {
|
||||
await sshClient.exec('samba-tool user setpassword', [
|
||||
userName,
|
||||
'--newpassword', password
|
||||
]);
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
await sshClient.exec('samba-tool user disable', [
|
||||
userName
|
||||
]);
|
||||
console.log(` -> '${userName}' disabled on Samba`);
|
||||
} catch (e) {}
|
||||
} else if (isEnabled) {
|
||||
await sshClient.exec('samba-tool user disable', [
|
||||
userName
|
||||
]);
|
||||
console.log(` -> User '${userName}' disabled on Samba`);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets Samba enabled users.
|
||||
*
|
||||
* Summary of userAccountControl flags:
|
||||
* https://docs.microsoft.com/en-us/troubleshoot/windows-server/identity/useraccountcontrol-manipulate-account-properties
|
||||
*
|
||||
* @param {Set} usersToSync
|
||||
*/
|
||||
async getUsers(usersToSync) {
|
||||
let {adClient} = this;
|
||||
let usersDn = this.usersDn();
|
||||
const LDAP_MATCHING_RULE_BIT_AND = '1.2.840.113556.1.4.803';
|
||||
let filter = `!(userAccountControl:${LDAP_MATCHING_RULE_BIT_AND}:=${UserAccountControlFlags.ACCOUNTDISABLE})`;
|
||||
|
||||
let opts = {
|
||||
scope: 'sub',
|
||||
attributes: ['sAMAccountName'],
|
||||
filter: '(&(objectClass=user)(!(userAccountControl:1.2.840.113556.1.4.803:=2)))'
|
||||
filter: `(&(objectClass=user)(${filter}))`
|
||||
};
|
||||
let res = await adClient.search(usersDn, opts);
|
||||
|
||||
await new Promise((resolve, reject) => {
|
||||
res.on('error', err => {
|
||||
if (err.name === 'NoSuchObjectError')
|
||||
err = new Error(`Object '${usersDn}' does not exist`);
|
||||
reject(err);
|
||||
});
|
||||
res.on('searchEntry', e => {
|
||||
usersToSync.add(e.object.sAMAccountName);
|
||||
});
|
||||
res.on('end', resolve);
|
||||
});
|
||||
await this.adClient.searchForeach(this.usersDn(), opts,
|
||||
o => usersToSync.add(o.sAMAccountName));
|
||||
}
|
||||
});
|
||||
};
|
||||
|
|
|
@ -26,5 +26,36 @@ function createClient(opts) {
|
|||
'starttls',
|
||||
'unbind'
|
||||
]);
|
||||
|
||||
Object.assign(client, {
|
||||
async searchForeach(base, options, eachFn, controls) {
|
||||
let res = await this.search(base, options);
|
||||
|
||||
await new Promise((resolve, reject) => {
|
||||
res.on('error', err => {
|
||||
if (err.name === 'NoSuchObjectError')
|
||||
err = new Error(`Object '${base}' does not exist`);
|
||||
reject(err);
|
||||
});
|
||||
res.on('searchEntry', e => eachFn(e.object));
|
||||
res.on('end', resolve);
|
||||
});
|
||||
},
|
||||
|
||||
async searchAll(base, options, controls) {
|
||||
let elements = [];
|
||||
await this.searchForeach(base, options,
|
||||
o => elements.push(o), controls);
|
||||
return elements;
|
||||
},
|
||||
|
||||
async searchOne(base, options, controls) {
|
||||
let object;
|
||||
await this.searchForeach(base, options,
|
||||
o => object = o, controls);
|
||||
return object;
|
||||
}
|
||||
});
|
||||
|
||||
return client;
|
||||
}
|
||||
|
|
|
@ -31,8 +31,8 @@ describe('Component vnTicketIndex', () => {
|
|||
|
||||
describe('compareDate()', () => {
|
||||
it('should return warning when the date is the present', () => {
|
||||
let curDate = new Date();
|
||||
let result = controller.compareDate(curDate);
|
||||
let today = new Date();
|
||||
let result = controller.compareDate(today);
|
||||
|
||||
expect(result).toEqual('warning');
|
||||
});
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
<vn-table model="model">
|
||||
<vn-thead>
|
||||
<vn-tr>
|
||||
<vn-th field="id" number>Id</vn-th>
|
||||
<vn-th field="id" number filter-enabled="false">Id</vn-th>
|
||||
<vn-th field="ref">Reference</vn-th>
|
||||
<vn-th field="agencyFk">Agency</vn-th>
|
||||
<vn-th field="warehouseOutFk">Warehouse Out</vn-th>
|
||||
|
@ -26,13 +26,21 @@
|
|||
class="clickable vn-tr search-result"
|
||||
ui-sref="travel.card.summary({id: {{::travel.id}}})">
|
||||
<vn-td number>{{::travel.id}}</vn-td>
|
||||
<vn-td expand>{{::travel.ref}}</vn-td>
|
||||
<vn-td expand>{{::travel.agencyModeName}}</vn-td>
|
||||
<vn-td expand>{{::travel.warehouseOutName}}</vn-td>
|
||||
<vn-td center expand>{{::travel.shipped | date:'dd/MM/yyyy'}}</vn-td>
|
||||
<vn-td><vn-check ng-model="travel.isDelivered" disabled="true"></vn-check></vn-td>
|
||||
<vn-td>{{::travel.ref}}</vn-td>
|
||||
<vn-td>{{::travel.agencyModeName}}</vn-td>
|
||||
<vn-td>{{::travel.warehouseOutName}}</vn-td>
|
||||
<vn-td center expand>
|
||||
<span class="chip {{$ctrl.compareDate(travel.shipped)}}">
|
||||
{{::travel.shipped | date:'dd/MM/yyyy'}}
|
||||
</span>
|
||||
</vn-td>
|
||||
<vn-td center><vn-check ng-model="travel.isDelivered" disabled="true"></vn-check></vn-td>
|
||||
<vn-td expand>{{::travel.warehouseInName}}</vn-td>
|
||||
<vn-td center expand>{{::travel.landed | date:'dd/MM/yyyy'}}</vn-td>
|
||||
<vn-td center expand>
|
||||
<span class="chip {{$ctrl.compareDate(travel.landed)}}">
|
||||
{{::travel.landed | date:'dd/MM/yyyy'}}
|
||||
</span>
|
||||
</vn-td>
|
||||
<vn-td center><vn-check ng-model="travel.isReceived" disabled="true"></vn-check></vn-td>
|
||||
<vn-td shrink>
|
||||
<vn-horizontal class="buttons">
|
||||
|
@ -70,4 +78,28 @@
|
|||
on-accept="$ctrl.onCloneAccept($data)"
|
||||
question="Do you want to clone this travel?"
|
||||
message="All it's properties will be copied">
|
||||
</vn-confirm>
|
||||
</vn-confirm>
|
||||
<vn-contextmenu vn-id="contextmenu" targets="['vn-data-viewer']" model="model"
|
||||
expr-builder="$ctrl.exprBuilder(param, value)">
|
||||
<slot-menu>
|
||||
<vn-item translate
|
||||
ng-if="contextmenu.isFilterAllowed()"
|
||||
ng-click="contextmenu.filterBySelection()">
|
||||
Filter by selection
|
||||
</vn-item>
|
||||
<vn-item translate
|
||||
ng-if="contextmenu.isFilterAllowed()"
|
||||
ng-click="contextmenu.excludeSelection()">
|
||||
Exclude selection
|
||||
</vn-item>
|
||||
<vn-item translate
|
||||
ng-if="contextmenu.isFilterAllowed()"
|
||||
ng-click="contextmenu.removeFilter()" >
|
||||
Remove filter
|
||||
</vn-item>
|
||||
<vn-item translate
|
||||
ng-click="contextmenu.removeAllFilters()" >
|
||||
Remove all filters
|
||||
</vn-item>
|
||||
</slot-menu>
|
||||
</vn-contextmenu>
|
|
@ -18,6 +18,49 @@ export default class Controller extends Section {
|
|||
});
|
||||
this.$state.go('travel.create', {q: params});
|
||||
}
|
||||
|
||||
compareDate(date) {
|
||||
let today = new Date();
|
||||
today.setHours(0, 0, 0, 0);
|
||||
|
||||
date = new Date(date);
|
||||
date.setHours(0, 0, 0, 0);
|
||||
|
||||
const timeDifference = today - date;
|
||||
if (timeDifference == 0) return 'warning';
|
||||
if (timeDifference < 0) return 'success';
|
||||
}
|
||||
|
||||
exprBuilder(param, value) {
|
||||
switch (param) {
|
||||
case 'search':
|
||||
return /^\d+$/.test(value)
|
||||
? {'t.id': value}
|
||||
: {'t.ref': {like: `%${value}%`}};
|
||||
case 'ref':
|
||||
return {'t.ref': {like: `%${value}%`}};
|
||||
case 'shipped':
|
||||
return {'t.shipped': {between: this.dateRange(value)}};
|
||||
case 'landed':
|
||||
return {'t.landed': {between: this.dateRange(value)}};
|
||||
case 'id':
|
||||
case 'agencyFk':
|
||||
case 'warehouseOutFk':
|
||||
case 'warehouseInFk':
|
||||
case 'totalEntries':
|
||||
param = `t.${param}`;
|
||||
return {[param]: value};
|
||||
}
|
||||
}
|
||||
|
||||
dateRange(value) {
|
||||
const minHour = new Date(value);
|
||||
minHour.setHours(0, 0, 0, 0);
|
||||
const maxHour = new Date(value);
|
||||
maxHour.setHours(23, 59, 59, 59);
|
||||
|
||||
return [minHour, maxHour];
|
||||
}
|
||||
}
|
||||
|
||||
ngModule.vnComponent('vnTravelIndex', {
|
||||
|
|
|
@ -47,4 +47,32 @@ describe('Travel Component vnTravelIndex', () => {
|
|||
expect(controller.$state.go).toHaveBeenCalledWith('travel.create', {q: queryParams});
|
||||
});
|
||||
});
|
||||
|
||||
describe('compareDate()', () => {
|
||||
it('should return warning if the date passed to compareDate() is todays', () => {
|
||||
const today = new Date();
|
||||
|
||||
const result = controller.compareDate(today);
|
||||
|
||||
expect(result).toEqual('warning');
|
||||
});
|
||||
|
||||
it('should return success if the date passed to compareDate() is in the future', () => {
|
||||
const tomorrow = new Date();
|
||||
tomorrow.setDate(tomorrow.getDate() + 1);
|
||||
|
||||
const result = controller.compareDate(tomorrow);
|
||||
|
||||
expect(result).toEqual('success');
|
||||
});
|
||||
|
||||
it('should return undefined if the date passed to compareDate() is in the past', () => {
|
||||
const yesterday = new Date();
|
||||
yesterday.setDate(yesterday.getDate() - 1);
|
||||
|
||||
const result = controller.compareDate(yesterday);
|
||||
|
||||
expect(result).toBeUndefined();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
"name": "Workers",
|
||||
"icon" : "icon-worker",
|
||||
"validations" : true,
|
||||
"dependencies": ["account"],
|
||||
"menus": {
|
||||
"main": [
|
||||
{"state": "worker.index", "icon": "icon-worker"},
|
||||
|
|
|
@ -5883,7 +5883,7 @@
|
|||
},
|
||||
"util": {
|
||||
"version": "0.10.3",
|
||||
"resolved": "http://registry.npmjs.org/util/-/util-0.10.3.tgz",
|
||||
"resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz",
|
||||
"integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
|
@ -6854,7 +6854,7 @@
|
|||
"base": {
|
||||
"version": "0.11.2",
|
||||
"resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz",
|
||||
"integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==",
|
||||
"integrity": "sha1-e95c7RRbbVUakNuH+DxVi060io8=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"cache-base": "^1.0.1",
|
||||
|
@ -7366,7 +7366,7 @@
|
|||
"cache-base": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz",
|
||||
"integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==",
|
||||
"integrity": "sha1-Cn9GQWgxyLZi7jb+TnxZ129marI=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"collection-visit": "^1.0.0",
|
||||
|
@ -7574,7 +7574,7 @@
|
|||
"class-utils": {
|
||||
"version": "0.3.6",
|
||||
"resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz",
|
||||
"integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==",
|
||||
"integrity": "sha1-+TNprouafOAv1B+q0MqDAzGQxGM=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"arr-union": "^3.1.0",
|
||||
|
@ -10003,7 +10003,7 @@
|
|||
},
|
||||
"file-loader": {
|
||||
"version": "1.1.11",
|
||||
"resolved": "http://registry.npmjs.org/file-loader/-/file-loader-1.1.11.tgz",
|
||||
"resolved": "https://registry.npmjs.org/file-loader/-/file-loader-1.1.11.tgz",
|
||||
"integrity": "sha512-TGR4HU7HUsGg6GCOPJnFk06RhWgEWFLAGWiT6rcD+GRC2keU3s9RGJ+b3Z6/U73jwwNb2gKLJ7YCrp+jvU4ALg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
|
@ -11189,7 +11189,7 @@
|
|||
"global-modules": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz",
|
||||
"integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==",
|
||||
"integrity": "sha1-bXcPDrUjrHgWTXK15xqIdyZcw+o=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"global-prefix": "^1.0.1",
|
||||
|
@ -13376,7 +13376,7 @@
|
|||
"is-plain-object": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz",
|
||||
"integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==",
|
||||
"integrity": "sha1-LBY7P6+xtgbZ0Xko8FwqHDjgdnc=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"isobject": "^3.0.1"
|
||||
|
@ -22306,7 +22306,7 @@
|
|||
"dependencies": {
|
||||
"jsesc": {
|
||||
"version": "0.5.0",
|
||||
"resolved": "http://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz",
|
||||
"resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz",
|
||||
"integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=",
|
||||
"dev": true
|
||||
}
|
||||
|
@ -22648,7 +22648,7 @@
|
|||
},
|
||||
"safe-regex": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "http://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz",
|
||||
"resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz",
|
||||
"integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
|
@ -22862,7 +22862,7 @@
|
|||
"dependencies": {
|
||||
"source-map": {
|
||||
"version": "0.4.4",
|
||||
"resolved": "http://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz",
|
||||
"integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
|
@ -23323,7 +23323,7 @@
|
|||
"snapdragon-node": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz",
|
||||
"integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==",
|
||||
"integrity": "sha1-bBdfhv8UvbByRWPo88GwIaKGhTs=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"define-property": "^1.0.0",
|
||||
|
@ -23374,7 +23374,7 @@
|
|||
"snapdragon-util": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz",
|
||||
"integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==",
|
||||
"integrity": "sha1-+VZHlIbyrNeXAGk/b3uAXkWrVuI=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"kind-of": "^3.2.0"
|
||||
|
@ -23658,7 +23658,7 @@
|
|||
"split-string": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz",
|
||||
"integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==",
|
||||
"integrity": "sha1-fLCd2jqGWFcFxks5pkZgOGguj+I=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"extend-shallow": "^3.0.0"
|
||||
|
@ -24960,7 +24960,7 @@
|
|||
"touch": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz",
|
||||
"integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==",
|
||||
"integrity": "sha1-/jZfX3XsntTlaCXgu3bSSrdK+Ds=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"nopt": "~1.0.10"
|
||||
|
@ -26731,7 +26731,7 @@
|
|||
},
|
||||
"xmlbuilder": {
|
||||
"version": "9.0.7",
|
||||
"resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz",
|
||||
"resolved": "http://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz",
|
||||
"integrity": "sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0="
|
||||
},
|
||||
"xmlchars": {
|
||||
|
|
Loading…
Reference in New Issue