Merge branch 'dev' into 2575-image_download
gitea/salix/pipeline/head This commit looks good
Details
gitea/salix/pipeline/head This commit looks good
Details
This commit is contained in:
commit
6fc14d569c
|
@ -29,27 +29,41 @@ module.exports = Self => {
|
||||||
let $ = Self.app.models;
|
let $ = Self.app.models;
|
||||||
let token;
|
let token;
|
||||||
let usesEmail = user.indexOf('@') !== -1;
|
let usesEmail = user.indexOf('@') !== -1;
|
||||||
|
let userInfo = usesEmail
|
||||||
|
? {email: user}
|
||||||
|
: {username: user};
|
||||||
|
|
||||||
let loginInfo = {password};
|
let loginInfo = Object.assign({password}, userInfo);
|
||||||
|
|
||||||
if (usesEmail)
|
|
||||||
loginInfo.email = user;
|
|
||||||
else
|
|
||||||
loginInfo.username = user;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
token = await $.User.login(loginInfo, 'user');
|
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) {
|
} catch (err) {
|
||||||
if (err.code != 'LOGIN_FAILED' || usesEmail)
|
if (err.code != 'LOGIN_FAILED')
|
||||||
throw err;
|
throw err;
|
||||||
|
|
||||||
let filter = {where: {name: user}};
|
let where = usesEmail
|
||||||
let instance = await Self.findOne(filter);
|
? {email: user}
|
||||||
|
: {name: user};
|
||||||
|
Object.assign(where, {
|
||||||
|
password: md5(password || '')
|
||||||
|
});
|
||||||
|
|
||||||
if (!instance || instance.password !== md5(password || ''))
|
let instance = await Self.findOne({
|
||||||
throw err;
|
fields: ['name'],
|
||||||
|
where
|
||||||
|
});
|
||||||
|
if (!instance) throw err;
|
||||||
|
|
||||||
await $.UserAccount.sync(user, password);
|
await $.UserAccount.sync(instance.name, password);
|
||||||
token = await $.User.login(loginInfo, 'user');
|
token = await $.User.login(loginInfo, 'user');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,2 +0,0 @@
|
||||||
INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`)
|
|
||||||
VALUES ('Buy', '*', '*', 'ALLOW', 'ROLE', 'buyer');
|
|
|
@ -1,2 +0,0 @@
|
||||||
ALTER TABLE `vn`.`accountingType`
|
|
||||||
ADD COLUMN `receiptDescription` VARCHAR(50) NULL COMMENT 'Descripción por defecto al crear nuevo recibo' AFTER `description`;
|
|
|
@ -1,119 +0,0 @@
|
||||||
USE `vn`;
|
|
||||||
DROP procedure IF EXISTS `ticket_close`;
|
|
||||||
|
|
||||||
DELIMITER $$
|
|
||||||
USE `vn`$$
|
|
||||||
CREATE DEFINER=`root`@`%` PROCEDURE `ticket_close`(vTicketFk INT)
|
|
||||||
BEGIN
|
|
||||||
/**
|
|
||||||
* Realiza el cierre de todos los
|
|
||||||
* tickets de la tabla ticketClosure.
|
|
||||||
*
|
|
||||||
* @param vTicketFk Id del ticket
|
|
||||||
*/
|
|
||||||
DECLARE vDone BOOL;
|
|
||||||
DECLARE vClientFk INT;
|
|
||||||
DECLARE vCurTicketFk INT;
|
|
||||||
DECLARE vIsTaxDataChecked BOOL;
|
|
||||||
DECLARE vCompanyFk INT;
|
|
||||||
DECLARE vShipped DATE;
|
|
||||||
DECLARE vNewInvoiceId INT;
|
|
||||||
DECLARE vHasDailyInvoice BOOL;
|
|
||||||
DECLARE vWithPackage BOOL;
|
|
||||||
DECLARE vHasToInvoice BOOL;
|
|
||||||
|
|
||||||
DECLARE cur CURSOR FOR
|
|
||||||
SELECT ticketFk FROM tmp.ticketClosure;
|
|
||||||
|
|
||||||
DECLARE CONTINUE HANDLER FOR NOT FOUND SET vDone = TRUE;
|
|
||||||
DECLARE EXIT HANDLER FOR SQLEXCEPTION BEGIN
|
|
||||||
RESIGNAL;
|
|
||||||
END;
|
|
||||||
|
|
||||||
DROP TEMPORARY TABLE IF EXISTS tmp.ticketClosure;
|
|
||||||
CREATE TEMPORARY TABLE tmp.ticketClosure
|
|
||||||
SELECT vTicketFk AS ticketFk;
|
|
||||||
|
|
||||||
INSERT INTO tmp.ticketClosure
|
|
||||||
SELECT id FROM stowaway s
|
|
||||||
WHERE s.shipFk = vTicketFk;
|
|
||||||
OPEN cur;
|
|
||||||
|
|
||||||
proc: LOOP
|
|
||||||
SET vDone = FALSE;
|
|
||||||
|
|
||||||
FETCH cur INTO vCurTicketFk;
|
|
||||||
|
|
||||||
IF vDone THEN
|
|
||||||
LEAVE proc;
|
|
||||||
END IF;
|
|
||||||
|
|
||||||
-- ticketClosure start
|
|
||||||
SELECT
|
|
||||||
c.id,
|
|
||||||
c.isTaxDataChecked,
|
|
||||||
t.companyFk,
|
|
||||||
t.shipped,
|
|
||||||
co.hasDailyInvoice,
|
|
||||||
w.isManaged,
|
|
||||||
c.hasToInvoice
|
|
||||||
INTO vClientFk,
|
|
||||||
vIsTaxDataChecked,
|
|
||||||
vCompanyFk,
|
|
||||||
vShipped,
|
|
||||||
vHasDailyInvoice,
|
|
||||||
vWithPackage,
|
|
||||||
vHasToInvoice
|
|
||||||
FROM ticket t
|
|
||||||
JOIN `client` c ON c.id = t.clientFk
|
|
||||||
JOIN province p ON p.id = c.provinceFk
|
|
||||||
JOIN country co ON co.id = p.countryFk
|
|
||||||
JOIN warehouse w ON w.id = t.warehouseFk
|
|
||||||
WHERE t.id = vCurTicketFk;
|
|
||||||
|
|
||||||
INSERT INTO ticketPackaging (ticketFk, packagingFk, quantity)
|
|
||||||
(SELECT vCurTicketFk, p.id, COUNT(*)
|
|
||||||
FROM expedition e
|
|
||||||
JOIN packaging p ON p.itemFk = e.itemFk
|
|
||||||
WHERE e.ticketFk = vCurTicketFk AND p.isPackageReturnable
|
|
||||||
AND vWithPackage
|
|
||||||
GROUP BY p.itemFk);
|
|
||||||
|
|
||||||
-- No retornables o no catalogados
|
|
||||||
INSERT INTO sale (itemFk, ticketFk, concept, quantity, price, isPriceFixed)
|
|
||||||
(SELECT e.itemFk, vCurTicketFk, i.name, COUNT(*) AS amount, getSpecialPrice(e.itemFk, vClientFk), 1
|
|
||||||
FROM expedition e
|
|
||||||
JOIN item i ON i.id = e.itemFk
|
|
||||||
LEFT JOIN packaging p ON p.itemFk = i.id
|
|
||||||
WHERE e.ticketFk = vCurTicketFk AND IFNULL(p.isPackageReturnable, 0) = 0
|
|
||||||
AND getSpecialPrice(e.itemFk, vClientFk) > 0
|
|
||||||
GROUP BY e.itemFk);
|
|
||||||
|
|
||||||
CALL vn.zonePromo_Make();
|
|
||||||
|
|
||||||
IF(vHasDailyInvoice) AND vHasToInvoice THEN
|
|
||||||
|
|
||||||
-- Facturacion rapida
|
|
||||||
CALL ticketTrackingAdd(vCurTicketFk, 'DELIVERED', NULL);
|
|
||||||
-- Facturar si está contabilizado
|
|
||||||
IF vIsTaxDataChecked THEN
|
|
||||||
CALL invoiceOut_newFromClient(
|
|
||||||
vClientFk,
|
|
||||||
(SELECT invoiceSerial(vClientFk, vCompanyFk, 'M')),
|
|
||||||
vShipped,
|
|
||||||
vCompanyFk,
|
|
||||||
NULL,
|
|
||||||
vNewInvoiceId);
|
|
||||||
END IF;
|
|
||||||
ELSE
|
|
||||||
CALL ticketTrackingAdd(vCurTicketFk, (SELECT vn.getAlert3State(vCurTicketFk)), NULL);
|
|
||||||
END IF;
|
|
||||||
END LOOP;
|
|
||||||
|
|
||||||
CLOSE cur;
|
|
||||||
|
|
||||||
DROP TEMPORARY TABLE IF EXISTS tmp.ticketClosure;
|
|
||||||
END$$
|
|
||||||
|
|
||||||
DELIMITER ;
|
|
||||||
|
|
|
@ -1,7 +0,0 @@
|
||||||
ALTER TABLE `vn`.`entryLog`
|
|
||||||
ADD COLUMN `changedModel` varchar(45) CHARACTER SET utf8 COLLATE utf8_unicode_ci DEFAULT NULL,
|
|
||||||
ADD COLUMN `oldInstance` text CHARACTER SET utf8 COLLATE utf8_unicode_ci,
|
|
||||||
ADD COLUMN `newInstance` text CHARACTER SET utf8 COLLATE utf8_unicode_ci,
|
|
||||||
ADD COLUMN `changedModelId` int(11) DEFAULT NULL,
|
|
||||||
ADD COLUMN `changedModelValue` varchar(45) CHARACTER SET utf8 COLLATE utf8_unicode_ci DEFAULT NULL;
|
|
||||||
|
|
|
@ -1,9 +0,0 @@
|
||||||
ALTER TABLE `vn`.`ticketService`
|
|
||||||
DROP FOREIGN KEY `ticketServiceIvaGroup`;
|
|
||||||
ALTER TABLE `vn`.`ticketService`
|
|
||||||
CHANGE COLUMN `taxClassFk` `taxClassFk` TINYINT(3) UNSIGNED NOT NULL DEFAULT 2 ;
|
|
||||||
ALTER TABLE `vn`.`ticketService`
|
|
||||||
ADD CONSTRAINT `ticketServiceIvaGroup`
|
|
||||||
FOREIGN KEY (`taxClassFk`)
|
|
||||||
REFERENCES `vn`.`taxClass` (`id`)
|
|
||||||
ON UPDATE CASCADE;
|
|
|
@ -1,129 +0,0 @@
|
||||||
|
|
||||||
ALTER TABLE `account`.`role`
|
|
||||||
MODIFY COLUMN `hasLogin` tinyint(3) unsigned DEFAULT 1 NOT NULL;
|
|
||||||
|
|
||||||
ALTER TABLE `account`.`roleInherit`
|
|
||||||
ADD UNIQUE( `role`, `inheritsFrom`);
|
|
||||||
|
|
||||||
ALTER TABLE `account`.`roleInherit`
|
|
||||||
DROP PRIMARY KEY;
|
|
||||||
|
|
||||||
ALTER TABLE `account`.`roleInherit`
|
|
||||||
ADD `id` INT UNSIGNED NOT NULL AUTO_INCREMENT FIRST,
|
|
||||||
ADD PRIMARY KEY (`id`);
|
|
||||||
|
|
||||||
ALTER TABLE `account`.`mailAlias`
|
|
||||||
ADD `description` VARCHAR(255) NULL AFTER `alias`;
|
|
||||||
|
|
||||||
ALTER TABLE `account`.`mailAliasAccount`
|
|
||||||
ADD UNIQUE( `mailAlias`, `account`);
|
|
||||||
|
|
||||||
ALTER TABLE `account`.`mailAliasAccount`
|
|
||||||
DROP PRIMARY KEY;
|
|
||||||
|
|
||||||
ALTER TABLE `account`.`mailAliasAccount`
|
|
||||||
ADD `id` INT UNSIGNED NOT NULL AUTO_INCREMENT FIRST,
|
|
||||||
ADD PRIMARY KEY (`id`);
|
|
||||||
|
|
||||||
ALTER TABLE account.ldapConfig
|
|
||||||
ADD groupDn varchar(255) NULL;
|
|
||||||
|
|
||||||
UPDATE account.ldapConfig SET groupDn = 'ou=groups,dc=verdnatura,dc=es';
|
|
||||||
|
|
||||||
DROP PROCEDURE IF EXISTS account.user_syncPassword;
|
|
||||||
|
|
||||||
ALTER TABLE account.`user`
|
|
||||||
MODIFY COLUMN sync tinyint(4) DEFAULT 0 NOT NULL COMMENT 'Deprecated';
|
|
||||||
|
|
||||||
CREATE TABLE account.userSync (
|
|
||||||
name varchar(30) NOT NULL,
|
|
||||||
CONSTRAINT userSync_PK PRIMARY KEY (name)
|
|
||||||
)
|
|
||||||
ENGINE=InnoDB
|
|
||||||
DEFAULT CHARSET=utf8
|
|
||||||
COLLATE=utf8_general_ci;
|
|
||||||
|
|
||||||
USE account;
|
|
||||||
|
|
||||||
DELIMITER $$
|
|
||||||
|
|
||||||
DROP TRIGGER IF EXISTS account.user_beforeUpdate$$
|
|
||||||
CREATE DEFINER=`root`@`%` TRIGGER `user_beforeUpdate`
|
|
||||||
BEFORE UPDATE ON `user` FOR EACH ROW
|
|
||||||
BEGIN
|
|
||||||
IF !(NEW.`name` <=> OLD.`name`) THEN
|
|
||||||
CALL user_checkName (NEW.`name`);
|
|
||||||
END IF;
|
|
||||||
|
|
||||||
IF !(NEW.`password` <=> OLD.`password`) THEN
|
|
||||||
SET NEW.bcryptPassword = NULL;
|
|
||||||
SET NEW.lastPassChange = NOW();
|
|
||||||
END IF;
|
|
||||||
END$$
|
|
||||||
|
|
||||||
DROP TRIGGER IF EXISTS account.user_afterUpdate$$
|
|
||||||
CREATE DEFINER=`root`@`%` TRIGGER `user_afterUpdate`
|
|
||||||
AFTER UPDATE ON `user` FOR EACH ROW
|
|
||||||
BEGIN
|
|
||||||
INSERT IGNORE INTO userSync SET `name` = NEW.`name`;
|
|
||||||
|
|
||||||
IF !(OLD.`name` <=> NEW.`name`) THEN
|
|
||||||
INSERT IGNORE INTO userSync SET `name` = OLD.`name`;
|
|
||||||
END IF;
|
|
||||||
|
|
||||||
IF !(NEW.`role` <=> OLD.`role`)
|
|
||||||
THEN
|
|
||||||
INSERT INTO vn.mail SET
|
|
||||||
`sender` = 'jgallego@verdnatura.es',
|
|
||||||
`replyTo` = 'jgallego@verdnatura.es',
|
|
||||||
`subject` = 'Rol modificado',
|
|
||||||
`body` = CONCAT(myUserGetName(), ' ha modificado el rol del usuario ',
|
|
||||||
NEW.`name`, ' de ', OLD.role, ' a ', NEW.role);
|
|
||||||
END IF;
|
|
||||||
END$$
|
|
||||||
|
|
||||||
CREATE DEFINER=`root`@`%` TRIGGER `user_afterInsert`
|
|
||||||
AFTER INSERT ON `user` FOR EACH ROW
|
|
||||||
BEGIN
|
|
||||||
INSERT IGNORE INTO userSync SET `name` = NEW.`name`;
|
|
||||||
END$$
|
|
||||||
|
|
||||||
CREATE DEFINER=`root`@`%` TRIGGER `user_afterDelete`
|
|
||||||
AFTER DELETE ON `user` FOR EACH ROW
|
|
||||||
BEGIN
|
|
||||||
INSERT IGNORE INTO userSync SET `name` = OLD.`name`;
|
|
||||||
END$$
|
|
||||||
|
|
||||||
DROP TRIGGER IF EXISTS account.account_afterInsert$$
|
|
||||||
CREATE DEFINER=`root`@`%` TRIGGER `account_afterInsert`
|
|
||||||
AFTER INSERT ON `account` FOR EACH ROW
|
|
||||||
BEGIN
|
|
||||||
INSERT IGNORE INTO userSync (`name`)
|
|
||||||
SELECT `name` FROM `user` WHERE id = NEW.id;
|
|
||||||
END$$
|
|
||||||
|
|
||||||
DROP TRIGGER IF EXISTS account.account_afterDelete$$
|
|
||||||
CREATE DEFINER=`root`@`%` TRIGGER `account_afterDelete`
|
|
||||||
AFTER DELETE ON `account` FOR EACH ROW
|
|
||||||
BEGIN
|
|
||||||
INSERT IGNORE INTO userSync (`name`)
|
|
||||||
SELECT `name` FROM `user` WHERE id = OLD.id;
|
|
||||||
END$$
|
|
||||||
|
|
||||||
DROP TRIGGER IF EXISTS account.role_beforeInsert$$
|
|
||||||
CREATE DEFINER=`root`@`%` TRIGGER role_beforeInsert
|
|
||||||
BEFORE INSERT ON `role` FOR EACH ROW
|
|
||||||
BEGIN
|
|
||||||
CALL role_checkName(NEW.`name`);
|
|
||||||
END
|
|
||||||
|
|
||||||
DROP TRIGGER IF EXISTS account.role_beforeUpdate$$
|
|
||||||
CREATE DEFINER=`root`@`%` TRIGGER role_beforeUpdate
|
|
||||||
BEFORE UPDATE ON `role` FOR EACH ROW
|
|
||||||
BEGIN
|
|
||||||
IF !(NEW.`name` <=> OLD.`name`) THEN
|
|
||||||
CALL role_checkName (NEW.`name`);
|
|
||||||
END IF;
|
|
||||||
END$$
|
|
||||||
|
|
||||||
DELIMITER ;
|
|
|
@ -1,13 +0,0 @@
|
||||||
DROP PROCEDURE IF EXISTS account.myUserChangePassword;
|
|
||||||
|
|
||||||
DELIMITER $$
|
|
||||||
CREATE DEFINER=`root`@`%` PROCEDURE `account`.`myUserChangePassword`(vOldPassword VARCHAR(255), vPassword VARCHAR(255))
|
|
||||||
BEGIN
|
|
||||||
/**
|
|
||||||
* @deprecated Use myUser_changePassword()
|
|
||||||
*/
|
|
||||||
CALL myUser_changePassword(vOldPassword, vPassword);
|
|
||||||
END$$
|
|
||||||
DELIMITER ;
|
|
||||||
|
|
||||||
GRANT EXECUTE ON PROCEDURE account.myUserChangePassword TO account@localhost;
|
|
|
@ -1,15 +0,0 @@
|
||||||
DROP FUNCTION IF EXISTS account.myUserCheckLogin;
|
|
||||||
|
|
||||||
DELIMITER $$
|
|
||||||
CREATE DEFINER=`root`@`%` FUNCTION `account`.`myUserCheckLogin`() RETURNS tinyint(1)
|
|
||||||
READS SQL DATA
|
|
||||||
DETERMINISTIC
|
|
||||||
BEGIN
|
|
||||||
/**
|
|
||||||
* @deprecated Use myUser_checkLogin()
|
|
||||||
*/
|
|
||||||
RETURN myUser_checkLogin();
|
|
||||||
END$$
|
|
||||||
DELIMITER ;
|
|
||||||
|
|
||||||
GRANT EXECUTE ON FUNCTION account.myUserCheckLogin TO guest@localhost;
|
|
|
@ -1,15 +0,0 @@
|
||||||
DROP FUNCTION IF EXISTS account.myUserGetId;
|
|
||||||
|
|
||||||
DELIMITER $$
|
|
||||||
CREATE DEFINER=`root`@`%` FUNCTION `account`.`myUserGetId`() RETURNS int(11)
|
|
||||||
READS SQL DATA
|
|
||||||
DETERMINISTIC
|
|
||||||
BEGIN
|
|
||||||
/**
|
|
||||||
* @deprecated Use myUser_getId()
|
|
||||||
*/
|
|
||||||
RETURN myUser_getId();
|
|
||||||
END$$
|
|
||||||
DELIMITER ;
|
|
||||||
|
|
||||||
GRANT EXECUTE ON FUNCTION account.myUserGetId TO guest@localhost;
|
|
|
@ -1,15 +0,0 @@
|
||||||
DROP FUNCTION IF EXISTS account.myUserGetName;
|
|
||||||
|
|
||||||
DELIMITER $$
|
|
||||||
CREATE DEFINER=`root`@`%` FUNCTION `account`.`myUserGetName`() RETURNS varchar(30) CHARSET utf8
|
|
||||||
NO SQL
|
|
||||||
DETERMINISTIC
|
|
||||||
BEGIN
|
|
||||||
/**
|
|
||||||
* @deprecated Use myUser_getName()
|
|
||||||
*/
|
|
||||||
RETURN myUser_getName();
|
|
||||||
END$$
|
|
||||||
DELIMITER ;
|
|
||||||
|
|
||||||
GRANT EXECUTE ON FUNCTION account.myUserGetName TO guest@localhost;
|
|
|
@ -1,14 +0,0 @@
|
||||||
DROP FUNCTION IF EXISTS account.myUserHasRole;
|
|
||||||
|
|
||||||
DELIMITER $$
|
|
||||||
CREATE DEFINER=`root`@`%` FUNCTION `account`.`myUserHasRole`(vRoleName VARCHAR(255)) RETURNS tinyint(1)
|
|
||||||
DETERMINISTIC
|
|
||||||
BEGIN
|
|
||||||
/**
|
|
||||||
* @deprecated Use myUser_hasRole()
|
|
||||||
*/
|
|
||||||
RETURN myUser_hasRole(vRoleName);
|
|
||||||
END$$
|
|
||||||
DELIMITER ;
|
|
||||||
|
|
||||||
GRANT EXECUTE ON FUNCTION account.myUserHasRole TO guest@localhost;
|
|
|
@ -1,14 +0,0 @@
|
||||||
DROP FUNCTION IF EXISTS account.myUserHasRoleId;
|
|
||||||
|
|
||||||
DELIMITER $$
|
|
||||||
CREATE DEFINER=`root`@`%` FUNCTION `account`.`myUserHasRoleId`(vRoleId INT) RETURNS tinyint(1)
|
|
||||||
DETERMINISTIC
|
|
||||||
BEGIN
|
|
||||||
/**
|
|
||||||
* @deprecated Use myUser_hasRoleId()
|
|
||||||
*/
|
|
||||||
RETURN myUser_hasRoleId(vRoleId);
|
|
||||||
END$$
|
|
||||||
DELIMITER ;
|
|
||||||
|
|
||||||
GRANT EXECUTE ON FUNCTION account.myUserHasRoleId TO guest@localhost;
|
|
|
@ -1,17 +0,0 @@
|
||||||
DROP PROCEDURE IF EXISTS account.myUser_changePassword;
|
|
||||||
|
|
||||||
DELIMITER $$
|
|
||||||
CREATE DEFINER=`root`@`%` PROCEDURE `account`.`myUser_changePassword`(vOldPassword VARCHAR(255), vPassword VARCHAR(255))
|
|
||||||
BEGIN
|
|
||||||
/**
|
|
||||||
* Changes the current user password, if user is in recovery mode ignores the
|
|
||||||
* current password.
|
|
||||||
*
|
|
||||||
* @param vOldPassword The current password
|
|
||||||
* @param vPassword The new password
|
|
||||||
*/
|
|
||||||
CALL user_changePassword(myUser_getId(), vOldPassword, vPassword);
|
|
||||||
END$$
|
|
||||||
DELIMITER ;
|
|
||||||
|
|
||||||
GRANT EXECUTE ON PROCEDURE account.myUser_changePassword TO account@localhost;
|
|
|
@ -1,29 +0,0 @@
|
||||||
DROP FUNCTION IF EXISTS account.myUser_checkLogin;
|
|
||||||
|
|
||||||
DELIMITER $$
|
|
||||||
CREATE DEFINER=`root`@`%` FUNCTION `account`.`myUser_checkLogin`() RETURNS tinyint(1)
|
|
||||||
READS SQL DATA
|
|
||||||
DETERMINISTIC
|
|
||||||
BEGIN
|
|
||||||
/**
|
|
||||||
* Checks that variables @userId and @userName haven't been altered.
|
|
||||||
*
|
|
||||||
* @return %TRUE if they are unaltered or unset, otherwise %FALSE
|
|
||||||
*/
|
|
||||||
DECLARE vSignature VARCHAR(128);
|
|
||||||
DECLARE vKey VARCHAR(255);
|
|
||||||
|
|
||||||
IF @userId IS NOT NULL
|
|
||||||
AND @userName IS NOT NULL
|
|
||||||
AND @userSignature IS NOT NULL
|
|
||||||
THEN
|
|
||||||
SELECT loginKey INTO vKey FROM userConfig;
|
|
||||||
SET vSignature = util.hmacSha2(256, CONCAT_WS('/', @userId, @userName), vKey);
|
|
||||||
RETURN vSignature = @userSignature;
|
|
||||||
END IF;
|
|
||||||
|
|
||||||
RETURN FALSE;
|
|
||||||
END$$
|
|
||||||
DELIMITER ;
|
|
||||||
|
|
||||||
GRANT EXECUTE ON FUNCTION account.myUser_checkLogin TO guest@localhost;
|
|
|
@ -1,27 +0,0 @@
|
||||||
DROP FUNCTION IF EXISTS account.myUser_getId;
|
|
||||||
|
|
||||||
DELIMITER $$
|
|
||||||
CREATE DEFINER=`root`@`%` FUNCTION `account`.`myUser_getId`() RETURNS int(11)
|
|
||||||
READS SQL DATA
|
|
||||||
DETERMINISTIC
|
|
||||||
BEGIN
|
|
||||||
/**
|
|
||||||
* Returns the current user id.
|
|
||||||
*
|
|
||||||
* @return The user id
|
|
||||||
*/
|
|
||||||
DECLARE vUser INT DEFAULT NULL;
|
|
||||||
|
|
||||||
IF myUser_checkLogin()
|
|
||||||
THEN
|
|
||||||
SET vUser = @userId;
|
|
||||||
ELSE
|
|
||||||
SELECT id INTO vUser FROM user
|
|
||||||
WHERE name = LEFT(USER(), INSTR(USER(), '@') - 1);
|
|
||||||
END IF;
|
|
||||||
|
|
||||||
RETURN vUser;
|
|
||||||
END$$
|
|
||||||
DELIMITER ;
|
|
||||||
|
|
||||||
GRANT EXECUTE ON FUNCTION account.myUser_getId TO guest@localhost;
|
|
|
@ -1,27 +0,0 @@
|
||||||
DROP FUNCTION IF EXISTS account.myUser_getName;
|
|
||||||
|
|
||||||
DELIMITER $$
|
|
||||||
$$
|
|
||||||
CREATE DEFINER=`root`@`%` FUNCTION `account`.`myUser_getName`() RETURNS varchar(30) CHARSET utf8
|
|
||||||
NO SQL
|
|
||||||
DETERMINISTIC
|
|
||||||
BEGIN
|
|
||||||
/**
|
|
||||||
* Returns the current user name.
|
|
||||||
*
|
|
||||||
* @return The user name
|
|
||||||
*/
|
|
||||||
DECLARE vUser VARCHAR(30) DEFAULT NULL;
|
|
||||||
|
|
||||||
IF myUser_checkLogin()
|
|
||||||
THEN
|
|
||||||
SET vUser = @userName;
|
|
||||||
ELSE
|
|
||||||
SET vUser = LEFT(USER(), INSTR(USER(), '@') - 1);
|
|
||||||
END IF;
|
|
||||||
|
|
||||||
RETURN vUser;
|
|
||||||
END$$
|
|
||||||
DELIMITER ;
|
|
||||||
|
|
||||||
GRANT EXECUTE ON FUNCTION account.myUser_getName TO guest@localhost;
|
|
|
@ -1,17 +0,0 @@
|
||||||
DROP FUNCTION IF EXISTS account.myUser_hasRole;
|
|
||||||
|
|
||||||
DELIMITER $$
|
|
||||||
CREATE DEFINER=`root`@`%` FUNCTION `account`.`myUser_hasRole`(vRoleName VARCHAR(255)) RETURNS tinyint(1)
|
|
||||||
DETERMINISTIC
|
|
||||||
BEGIN
|
|
||||||
/**
|
|
||||||
* Checks if current user has/inherits a role.
|
|
||||||
*
|
|
||||||
* @param vRoleName Role to check
|
|
||||||
* @return %TRUE if it has role, %FALSE otherwise
|
|
||||||
*/
|
|
||||||
RETURN user_hasRole(myUser_getName(), vRoleName);
|
|
||||||
END$$
|
|
||||||
DELIMITER ;
|
|
||||||
|
|
||||||
GRANT EXECUTE ON FUNCTION account.myUser_hasRole TO guest@localhost;
|
|
|
@ -1,17 +0,0 @@
|
||||||
DROP FUNCTION IF EXISTS account.myUser_hasRoleId;
|
|
||||||
|
|
||||||
DELIMITER $$
|
|
||||||
CREATE DEFINER=`root`@`%` FUNCTION `account`.`myUser_hasRoleId`(vRoleId INT) RETURNS tinyint(1)
|
|
||||||
DETERMINISTIC
|
|
||||||
BEGIN
|
|
||||||
/**
|
|
||||||
* Checks if current user has/inherits a role.
|
|
||||||
*
|
|
||||||
* @param vRoleName Role id to check
|
|
||||||
* @return %TRUE if it has role, %FALSE otherwise
|
|
||||||
*/
|
|
||||||
RETURN user_hasRoleId(myUserGetName(), vRoleId);
|
|
||||||
END$$
|
|
||||||
DELIMITER ;
|
|
||||||
|
|
||||||
GRANT EXECUTE ON FUNCTION account.myUser_hasRoleId TO guest@localhost;
|
|
|
@ -1,29 +0,0 @@
|
||||||
DROP PROCEDURE IF EXISTS account.myUser_login;
|
|
||||||
|
|
||||||
DELIMITER $$
|
|
||||||
CREATE DEFINER=`root`@`%` PROCEDURE `account`.`myUser_login`(vUserName VARCHAR(255), vPassword VARCHAR(255))
|
|
||||||
READS SQL DATA
|
|
||||||
BEGIN
|
|
||||||
/**
|
|
||||||
* Logs in using the user credentials.
|
|
||||||
*
|
|
||||||
* @param vUserName The user name
|
|
||||||
* @param vPassword The user password
|
|
||||||
*/
|
|
||||||
DECLARE vAuthIsOk BOOLEAN DEFAULT FALSE;
|
|
||||||
|
|
||||||
SELECT COUNT(*) = 1 INTO vAuthIsOk FROM user
|
|
||||||
WHERE name = vUserName
|
|
||||||
AND password = MD5(vPassword)
|
|
||||||
AND active;
|
|
||||||
|
|
||||||
IF vAuthIsOk
|
|
||||||
THEN
|
|
||||||
CALL myUser_loginWithName (vUserName);
|
|
||||||
ELSE
|
|
||||||
CALL util.throw ('INVALID_CREDENTIALS');
|
|
||||||
END IF;
|
|
||||||
END$$
|
|
||||||
DELIMITER ;
|
|
||||||
|
|
||||||
GRANT EXECUTE ON PROCEDURE account.myUser_login TO guest@localhost;
|
|
|
@ -1,25 +0,0 @@
|
||||||
DROP PROCEDURE IF EXISTS account.myUser_loginWithKey;
|
|
||||||
|
|
||||||
DELIMITER $$
|
|
||||||
CREATE DEFINER=`root`@`%` PROCEDURE `account`.`myUser_loginWithKey`(vUserName VARCHAR(255), vKey VARCHAR(255))
|
|
||||||
READS SQL DATA
|
|
||||||
BEGIN
|
|
||||||
/**
|
|
||||||
* Logs in using the user name and MySQL master key.
|
|
||||||
*
|
|
||||||
* @param vUserName The user name
|
|
||||||
* @param vKey The MySQL master key
|
|
||||||
*/
|
|
||||||
DECLARE vLoginKey VARCHAR(255);
|
|
||||||
|
|
||||||
SELECT loginKey INTO vLoginKey FROM userConfig;
|
|
||||||
|
|
||||||
IF vLoginKey = vKey THEN
|
|
||||||
CALL myUser_loginWithName(vUserName);
|
|
||||||
ELSE
|
|
||||||
CALL util.throw('INVALID_KEY');
|
|
||||||
END IF;
|
|
||||||
END$$
|
|
||||||
DELIMITER ;
|
|
||||||
|
|
||||||
GRANT EXECUTE ON PROCEDURE account.myUser_loginWithKey TO guest@localhost;
|
|
|
@ -1,26 +0,0 @@
|
||||||
DROP PROCEDURE IF EXISTS account.myUser_loginWithName;
|
|
||||||
|
|
||||||
DELIMITER $$
|
|
||||||
CREATE DEFINER=`root`@`%` PROCEDURE `account`.`myUser_loginWithName`(vUserName VARCHAR(255))
|
|
||||||
READS SQL DATA
|
|
||||||
BEGIN
|
|
||||||
/**
|
|
||||||
* Logs in using only the user name. This procedure is intended to be executed
|
|
||||||
* by users with a high level of privileges so that normal users should not have
|
|
||||||
* execute permissions on it.
|
|
||||||
*
|
|
||||||
* @param vUserName The user name
|
|
||||||
*/
|
|
||||||
DECLARE vUserId INT DEFAULT NULL;
|
|
||||||
DECLARE vKey VARCHAR(255);
|
|
||||||
|
|
||||||
SELECT id INTO vUserId FROM user
|
|
||||||
WHERE name = vUserName;
|
|
||||||
|
|
||||||
SELECT loginKey INTO vKey FROM userConfig;
|
|
||||||
|
|
||||||
SET @userId = vUserId;
|
|
||||||
SET @userName = vUserName;
|
|
||||||
SET @userSignature = util.hmacSha2(256, CONCAT_WS('/', vUserId, vUserName), vKey);
|
|
||||||
END$$
|
|
||||||
DELIMITER ;
|
|
|
@ -1,15 +0,0 @@
|
||||||
DROP PROCEDURE IF EXISTS account.myUser_logout;
|
|
||||||
|
|
||||||
DELIMITER $$
|
|
||||||
CREATE DEFINER=`root`@`%` PROCEDURE `account`.`myUser_logout`()
|
|
||||||
BEGIN
|
|
||||||
/**
|
|
||||||
* Logouts the user.
|
|
||||||
*/
|
|
||||||
SET @userId = NULL;
|
|
||||||
SET @userName = NULL;
|
|
||||||
SET @userSignature = NULL;
|
|
||||||
END$$
|
|
||||||
DELIMITER ;
|
|
||||||
|
|
||||||
GRANT EXECUTE ON PROCEDURE account.myUser_logout TO account@localhost;
|
|
|
@ -1,52 +0,0 @@
|
||||||
DROP FUNCTION IF EXISTS account.passwordGenerate;
|
|
||||||
|
|
||||||
DELIMITER $$
|
|
||||||
CREATE DEFINER=`root`@`%` FUNCTION `account`.`passwordGenerate`() RETURNS text CHARSET utf8
|
|
||||||
BEGIN
|
|
||||||
/**
|
|
||||||
* Generates a random password that meets the minimum requirements.
|
|
||||||
*
|
|
||||||
* @return Generated password
|
|
||||||
*/
|
|
||||||
DECLARE vMinLength TINYINT;
|
|
||||||
DECLARE vMinAlpha TINYINT;
|
|
||||||
DECLARE vMinUpper TINYINT;
|
|
||||||
DECLARE vMinDigits TINYINT;
|
|
||||||
DECLARE vMinPunct TINYINT;
|
|
||||||
DECLARE vAlpha TINYINT DEFAULT 0;
|
|
||||||
DECLARE vUpper TINYINT DEFAULT 0;
|
|
||||||
DECLARE vDigits TINYINT DEFAULT 0;
|
|
||||||
DECLARE vPunct TINYINT DEFAULT 0;
|
|
||||||
DECLARE vRandIndex INT;
|
|
||||||
DECLARE vPwd TEXT DEFAULT '';
|
|
||||||
|
|
||||||
DECLARE vAlphaChars TEXT DEFAULT 'abcdefghijklmnopqrstuvwxyz';
|
|
||||||
DECLARE vUpperChars TEXT DEFAULT 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
|
|
||||||
DECLARE vDigitChars TEXT DEFAULT '1234567890';
|
|
||||||
DECLARE vPunctChars TEXT DEFAULT '!$%&()=.';
|
|
||||||
|
|
||||||
SELECT length, nAlpha, nUpper, nDigits, nPunct
|
|
||||||
INTO vMinLength, vMinAlpha, vMinUpper, vMinDigits, vMinPunct FROM userPassword;
|
|
||||||
|
|
||||||
WHILE LENGTH(vPwd) < vMinLength OR vAlpha < vMinAlpha
|
|
||||||
OR vUpper < vMinUpper OR vDigits < vMinDigits OR vPunct < vMinPunct DO
|
|
||||||
SET vRandIndex = FLOOR((RAND() * 4) + 1);
|
|
||||||
|
|
||||||
CASE
|
|
||||||
WHEN vRandIndex = 1 THEN
|
|
||||||
SET vPwd = CONCAT(vPwd, SUBSTRING(vAlphaChars, FLOOR((RAND() * 26) + 1), 1));
|
|
||||||
SET vAlpha = vAlpha + 1;
|
|
||||||
WHEN vRandIndex = 2 THEN
|
|
||||||
SET vPwd = CONCAT(vPwd, SUBSTRING(vUpperChars, FLOOR((RAND() * 26) + 1), 1));
|
|
||||||
SET vUpper = vUpper + 1;
|
|
||||||
WHEN vRandIndex = 3 THEN
|
|
||||||
SET vPwd = CONCAT(vPwd, SUBSTRING(vDigitChars, FLOOR((RAND() * 10) + 1), 1));
|
|
||||||
SET vDigits = vDigits + 1;
|
|
||||||
WHEN vRandIndex = 4 THEN
|
|
||||||
SET vPwd = CONCAT(vPwd, SUBSTRING(vPunctChars, FLOOR((RAND() * LENGTH(vPunctChars)) + 1), 1));
|
|
||||||
SET vPunct = vPunct + 1;
|
|
||||||
END CASE;
|
|
||||||
END WHILE;
|
|
||||||
RETURN vPwd;
|
|
||||||
END$$
|
|
||||||
DELIMITER ;
|
|
|
@ -1,18 +0,0 @@
|
||||||
DROP PROCEDURE IF EXISTS account.role_checkName;
|
|
||||||
|
|
||||||
DELIMITER $$
|
|
||||||
CREATE DEFINER=`root`@`%` PROCEDURE account.role_checkName(vRoleName VARCHAR(255))
|
|
||||||
BEGIN
|
|
||||||
/**
|
|
||||||
* Checks that role name meets the necessary syntax requirements, otherwise it
|
|
||||||
* throws an exception.
|
|
||||||
* Role name must be written in camelCase.
|
|
||||||
*
|
|
||||||
* @param vRoleName The role name
|
|
||||||
*/
|
|
||||||
IF BINARY vRoleName NOT REGEXP '^[a-z][a-zA-Z]+$' THEN
|
|
||||||
SIGNAL SQLSTATE '45000'
|
|
||||||
SET MESSAGE_TEXT = 'Role name must be written in camelCase';
|
|
||||||
END IF;
|
|
||||||
END$$
|
|
||||||
DELIMITER ;
|
|
|
@ -1,66 +0,0 @@
|
||||||
DROP PROCEDURE IF EXISTS account.role_getDescendents;
|
|
||||||
|
|
||||||
DELIMITER $$
|
|
||||||
CREATE DEFINER=`root`@`%` PROCEDURE `account`.`role_getDescendents`(vSelf INT)
|
|
||||||
BEGIN
|
|
||||||
/**
|
|
||||||
* Gets the identifiers of all the subroles implemented by a role (Including
|
|
||||||
* itself).
|
|
||||||
*
|
|
||||||
* @param vSelf The role identifier
|
|
||||||
* @table tmp.role Subroles implemented by the role
|
|
||||||
*/
|
|
||||||
DECLARE vIsRoot BOOL;
|
|
||||||
|
|
||||||
DROP TEMPORARY TABLE IF EXISTS
|
|
||||||
tmp.role, parents, childs;
|
|
||||||
|
|
||||||
CREATE TEMPORARY TABLE tmp.role
|
|
||||||
(UNIQUE (id))
|
|
||||||
ENGINE = MEMORY
|
|
||||||
SELECT vSelf AS id;
|
|
||||||
|
|
||||||
CREATE TEMPORARY TABLE parents
|
|
||||||
ENGINE = MEMORY
|
|
||||||
SELECT vSelf AS id;
|
|
||||||
|
|
||||||
CREATE TEMPORARY TABLE childs
|
|
||||||
LIKE parents;
|
|
||||||
|
|
||||||
REPEAT
|
|
||||||
DELETE FROM childs;
|
|
||||||
INSERT INTO childs
|
|
||||||
SELECT DISTINCT r.inheritsFrom id
|
|
||||||
FROM parents p
|
|
||||||
JOIN roleInherit r ON r.role = p.id
|
|
||||||
LEFT JOIN tmp.role t ON t.id = r.inheritsFrom
|
|
||||||
WHERE t.id IS NULL;
|
|
||||||
|
|
||||||
DELETE FROM parents;
|
|
||||||
INSERT INTO parents
|
|
||||||
SELECT * FROM childs;
|
|
||||||
|
|
||||||
INSERT INTO tmp.role
|
|
||||||
SELECT * FROM childs;
|
|
||||||
|
|
||||||
UNTIL ROW_COUNT() <= 0
|
|
||||||
END REPEAT;
|
|
||||||
|
|
||||||
-- If it is root all the roles are added
|
|
||||||
|
|
||||||
SELECT COUNT(*) > 0 INTO vIsRoot
|
|
||||||
FROM tmp.role t
|
|
||||||
JOIN role r ON r.id = t.id
|
|
||||||
WHERE r.`name` = 'root';
|
|
||||||
|
|
||||||
IF vIsRoot THEN
|
|
||||||
INSERT IGNORE INTO tmp.role (id)
|
|
||||||
SELECT id FROM role;
|
|
||||||
END IF;
|
|
||||||
|
|
||||||
-- Cleaning
|
|
||||||
|
|
||||||
DROP TEMPORARY TABLE
|
|
||||||
parents, childs;
|
|
||||||
END$$
|
|
||||||
DELIMITER ;
|
|
|
@ -1,53 +0,0 @@
|
||||||
DROP PROCEDURE IF EXISTS account.role_sync;
|
|
||||||
|
|
||||||
DELIMITER $$
|
|
||||||
CREATE DEFINER=`root`@`%` PROCEDURE `account`.`role_sync`()
|
|
||||||
BEGIN
|
|
||||||
/**
|
|
||||||
* Synchronize the @roleRole table with the current role hierarchy. This
|
|
||||||
* procedure must be called every time the @roleInherit table is modified so
|
|
||||||
* that the changes made on it are effective.
|
|
||||||
*/
|
|
||||||
DECLARE vRoleId INT;
|
|
||||||
DECLARE vDone BOOL;
|
|
||||||
|
|
||||||
DECLARE cur CURSOR FOR
|
|
||||||
SELECT id FROM role;
|
|
||||||
|
|
||||||
DECLARE CONTINUE HANDLER FOR NOT FOUND SET vDone = TRUE;
|
|
||||||
|
|
||||||
DROP TEMPORARY TABLE IF EXISTS tRoleRole;
|
|
||||||
CREATE TEMPORARY TABLE tRoleRole
|
|
||||||
ENGINE = MEMORY
|
|
||||||
SELECT * FROM roleRole LIMIT 0;
|
|
||||||
|
|
||||||
OPEN cur;
|
|
||||||
|
|
||||||
l: LOOP
|
|
||||||
SET vDone = FALSE;
|
|
||||||
FETCH cur INTO vRoleId;
|
|
||||||
|
|
||||||
IF vDone THEN
|
|
||||||
LEAVE l;
|
|
||||||
END IF;
|
|
||||||
|
|
||||||
CALL role_getDescendents(vRoleId);
|
|
||||||
|
|
||||||
INSERT INTO tRoleRole (role, inheritsFrom)
|
|
||||||
SELECT vRoleId, id FROM tmp.role;
|
|
||||||
|
|
||||||
DROP TEMPORARY TABLE tmp.role;
|
|
||||||
END LOOP;
|
|
||||||
|
|
||||||
CLOSE cur;
|
|
||||||
|
|
||||||
START TRANSACTION;
|
|
||||||
DELETE FROM roleRole;
|
|
||||||
INSERT INTO roleRole SELECT * FROM tRoleRole;
|
|
||||||
COMMIT;
|
|
||||||
|
|
||||||
DROP TEMPORARY TABLE tRoleRole;
|
|
||||||
|
|
||||||
CALL role_syncPrivileges;
|
|
||||||
END$$
|
|
||||||
DELIMITER ;
|
|
|
@ -1,499 +0,0 @@
|
||||||
DROP PROCEDURE IF EXISTS account.role_syncPrivileges;
|
|
||||||
|
|
||||||
DELIMITER $$
|
|
||||||
CREATE DEFINER=`root`@`%` PROCEDURE `account`.`role_syncPrivileges`()
|
|
||||||
BEGIN
|
|
||||||
/**
|
|
||||||
* Synchronizes permissions of MySQL role users based on role hierarchy.
|
|
||||||
* The computed role users of permission mix will be named according to
|
|
||||||
* pattern z-[role_name].
|
|
||||||
*
|
|
||||||
* If any@localhost user exists, it will be taken as a template for basic
|
|
||||||
* attributes.
|
|
||||||
*
|
|
||||||
* Warning! This procedure should only be called when MySQL privileges
|
|
||||||
* are modified. If role hierarchy is modified, you must call the role_sync()
|
|
||||||
* procedure wich calls this internally.
|
|
||||||
*/
|
|
||||||
DECLARE vIsMysql BOOL DEFAULT VERSION() NOT LIKE '%MariaDB%';
|
|
||||||
DECLARE vVersion INT DEFAULT SUBSTRING_INDEX(VERSION(), '.', 1);
|
|
||||||
DECLARE vTplUser VARCHAR(255) DEFAULT 'any';
|
|
||||||
DECLARE vTplHost VARCHAR(255) DEFAULT '%';
|
|
||||||
DECLARE vRoleHost VARCHAR(255) DEFAULT 'localhost';
|
|
||||||
DECLARE vAllHost VARCHAR(255) DEFAULT '%';
|
|
||||||
DECLARE vPrefix VARCHAR(2) DEFAULT 'z-';
|
|
||||||
DECLARE vPrefixedLike VARCHAR(255);
|
|
||||||
DECLARE vPassword VARCHAR(255) DEFAULT '';
|
|
||||||
|
|
||||||
-- Deletes computed role users
|
|
||||||
|
|
||||||
SET vPrefixedLike = CONCAT(vPrefix, '%');
|
|
||||||
|
|
||||||
DELETE FROM mysql.user
|
|
||||||
WHERE `User` LIKE vPrefixedLike;
|
|
||||||
|
|
||||||
DELETE FROM mysql.db
|
|
||||||
WHERE `User` LIKE vPrefixedLike;
|
|
||||||
|
|
||||||
DELETE FROM mysql.tables_priv
|
|
||||||
WHERE `User` LIKE vPrefixedLike;
|
|
||||||
|
|
||||||
DELETE FROM mysql.columns_priv
|
|
||||||
WHERE `User` LIKE vPrefixedLike;
|
|
||||||
|
|
||||||
DELETE FROM mysql.procs_priv
|
|
||||||
WHERE `User` LIKE vPrefixedLike;
|
|
||||||
|
|
||||||
DELETE FROM mysql.proxies_priv
|
|
||||||
WHERE `Proxied_user` LIKE vPrefixedLike;
|
|
||||||
|
|
||||||
-- Temporary tables
|
|
||||||
|
|
||||||
DROP TEMPORARY TABLE IF EXISTS tRole;
|
|
||||||
CREATE TEMPORARY TABLE tRole
|
|
||||||
(INDEX (id))
|
|
||||||
ENGINE = MEMORY
|
|
||||||
SELECT
|
|
||||||
id,
|
|
||||||
`name` role,
|
|
||||||
CONCAT(vPrefix, `name`) prefixedRole
|
|
||||||
FROM role
|
|
||||||
WHERE hasLogin;
|
|
||||||
|
|
||||||
DROP TEMPORARY TABLE IF EXISTS tRoleInherit;
|
|
||||||
CREATE TEMPORARY TABLE tRoleInherit
|
|
||||||
(INDEX (inheritsFrom))
|
|
||||||
ENGINE = MEMORY
|
|
||||||
SELECT
|
|
||||||
r.prefixedRole,
|
|
||||||
ri.`name` inheritsFrom
|
|
||||||
FROM tRole r
|
|
||||||
JOIN roleRole rr ON rr.role = r.id
|
|
||||||
JOIN role ri ON ri.id = rr.inheritsFrom;
|
|
||||||
|
|
||||||
-- Recreate role users
|
|
||||||
|
|
||||||
IF vIsMysql THEN
|
|
||||||
DROP TEMPORARY TABLE IF EXISTS tUser;
|
|
||||||
CREATE TEMPORARY TABLE tUser
|
|
||||||
SELECT
|
|
||||||
r.prefixedRole `User`,
|
|
||||||
vTplHost `Host`,
|
|
||||||
IFNULL(t.`authentication_string`,
|
|
||||||
'') `authentication_string`,
|
|
||||||
IFNULL(t.`plugin`,
|
|
||||||
'mysql_native_password') `plugin`,
|
|
||||||
IFNULL(IF('' != u.`ssl_type`,
|
|
||||||
u.`ssl_type`, t.`ssl_type`),
|
|
||||||
'') `ssl_type`,
|
|
||||||
IFNULL(IF('' != u.`ssl_cipher`,
|
|
||||||
u.`ssl_cipher`, t.`ssl_cipher`),
|
|
||||||
'') `ssl_cipher`,
|
|
||||||
IFNULL(IF('' != u.`x509_issuer`,
|
|
||||||
u.`x509_issuer`, t.`x509_issuer`),
|
|
||||||
'') `x509_issuer`,
|
|
||||||
IFNULL(IF('' != u.`x509_subject`,
|
|
||||||
u.`x509_subject`, t.`x509_subject`),
|
|
||||||
'') `x509_subject`,
|
|
||||||
IFNULL(IF(0 != u.`max_questions`,
|
|
||||||
u.`max_questions`, t.`max_questions`),
|
|
||||||
0) `max_questions`,
|
|
||||||
IFNULL(IF(0 != u.`max_updates`,
|
|
||||||
u.`max_updates`, t.`max_updates`),
|
|
||||||
0) `max_updates`,
|
|
||||||
IFNULL(IF(0 != u.`max_connections`,
|
|
||||||
u.`max_connections`, t.`max_connections`),
|
|
||||||
0) `max_connections`,
|
|
||||||
IFNULL(IF(0 != u.`max_user_connections`,
|
|
||||||
u.`max_user_connections`, t.`max_user_connections`),
|
|
||||||
0) `max_user_connections`
|
|
||||||
FROM tRole r
|
|
||||||
LEFT JOIN mysql.user t
|
|
||||||
ON t.`User` = vTplUser
|
|
||||||
AND t.`Host` = vRoleHost
|
|
||||||
LEFT JOIN mysql.user u
|
|
||||||
ON u.`User` = r.role
|
|
||||||
AND u.`Host` = vRoleHost;
|
|
||||||
|
|
||||||
IF vVersion <= 5 THEN
|
|
||||||
SELECT `Password` INTO vPassword
|
|
||||||
FROM mysql.user
|
|
||||||
WHERE `User` = vTplUser
|
|
||||||
AND `Host` = vRoleHost;
|
|
||||||
|
|
||||||
INSERT INTO mysql.user (
|
|
||||||
`User`,
|
|
||||||
`Host`,
|
|
||||||
`Password`,
|
|
||||||
`authentication_string`,
|
|
||||||
`plugin`,
|
|
||||||
`ssl_type`,
|
|
||||||
`ssl_cipher`,
|
|
||||||
`x509_issuer`,
|
|
||||||
`x509_subject`,
|
|
||||||
`max_questions`,
|
|
||||||
`max_updates`,
|
|
||||||
`max_connections`,
|
|
||||||
`max_user_connections`
|
|
||||||
)
|
|
||||||
SELECT
|
|
||||||
`User`,
|
|
||||||
`Host`,
|
|
||||||
vPassword,
|
|
||||||
`authentication_string`,
|
|
||||||
`plugin`,
|
|
||||||
`ssl_type`,
|
|
||||||
`ssl_cipher`,
|
|
||||||
`x509_issuer`,
|
|
||||||
`x509_subject`,
|
|
||||||
`max_questions`,
|
|
||||||
`max_updates`,
|
|
||||||
`max_connections`,
|
|
||||||
`max_user_connections`
|
|
||||||
FROM tUser;
|
|
||||||
ELSE
|
|
||||||
INSERT INTO mysql.user (
|
|
||||||
`User`,
|
|
||||||
`Host`,
|
|
||||||
`authentication_string`,
|
|
||||||
`plugin`,
|
|
||||||
`ssl_type`,
|
|
||||||
`ssl_cipher`,
|
|
||||||
`x509_issuer`,
|
|
||||||
`x509_subject`,
|
|
||||||
`max_questions`,
|
|
||||||
`max_updates`,
|
|
||||||
`max_connections`,
|
|
||||||
`max_user_connections`
|
|
||||||
)
|
|
||||||
SELECT
|
|
||||||
`User`,
|
|
||||||
`Host`,
|
|
||||||
`authentication_string`,
|
|
||||||
`plugin`,
|
|
||||||
`ssl_type`,
|
|
||||||
`ssl_cipher`,
|
|
||||||
`x509_issuer`,
|
|
||||||
`x509_subject`,
|
|
||||||
`max_questions`,
|
|
||||||
`max_updates`,
|
|
||||||
`max_connections`,
|
|
||||||
`max_user_connections`
|
|
||||||
FROM tUser;
|
|
||||||
END IF;
|
|
||||||
|
|
||||||
DROP TEMPORARY TABLE IF EXISTS tUser;
|
|
||||||
ELSE
|
|
||||||
INSERT INTO mysql.global_priv (
|
|
||||||
`User`,
|
|
||||||
`Host`,
|
|
||||||
`Priv`
|
|
||||||
)
|
|
||||||
SELECT
|
|
||||||
r.prefixedRole,
|
|
||||||
vTplHost,
|
|
||||||
JSON_MERGE_PATCH(
|
|
||||||
IFNULL(t.`Priv`, '{}'),
|
|
||||||
IFNULL(u.`Priv`, '{}'),
|
|
||||||
JSON_OBJECT(
|
|
||||||
'mysql_old_password', JSON_VALUE(t.`Priv`, '$.mysql_old_password'),
|
|
||||||
'mysql_native_password', JSON_VALUE(t.`Priv`, '$.mysql_native_password'),
|
|
||||||
'authentication_string', JSON_VALUE(t.`Priv`, '$.authentication_string')
|
|
||||||
)
|
|
||||||
)
|
|
||||||
FROM tRole r
|
|
||||||
LEFT JOIN mysql.global_priv t
|
|
||||||
ON t.`User` = vTplUser
|
|
||||||
AND t.`Host` = vRoleHost
|
|
||||||
LEFT JOIN mysql.global_priv u
|
|
||||||
ON u.`User` = r.role
|
|
||||||
AND u.`Host` = vRoleHost;
|
|
||||||
END IF;
|
|
||||||
|
|
||||||
INSERT INTO mysql.proxies_priv (
|
|
||||||
`User`,
|
|
||||||
`Host`,
|
|
||||||
`Proxied_user`,
|
|
||||||
`Proxied_host`,
|
|
||||||
`Grantor`
|
|
||||||
)
|
|
||||||
SELECT
|
|
||||||
'',
|
|
||||||
vAllHost,
|
|
||||||
prefixedRole,
|
|
||||||
vTplHost,
|
|
||||||
CONCAT(prefixedRole, '@', vTplHost)
|
|
||||||
FROM tRole;
|
|
||||||
|
|
||||||
-- Copies global privileges
|
|
||||||
|
|
||||||
DROP TEMPORARY TABLE IF EXISTS tUserPriv;
|
|
||||||
|
|
||||||
IF vIsMysql THEN
|
|
||||||
CREATE TEMPORARY TABLE tUserPriv
|
|
||||||
(INDEX (prefixedRole))
|
|
||||||
ENGINE = MEMORY
|
|
||||||
SELECT
|
|
||||||
r.prefixedRole,
|
|
||||||
MAX(u.`Select_priv`) `Select_priv`,
|
|
||||||
MAX(u.`Insert_priv`) `Insert_priv`,
|
|
||||||
MAX(u.`Update_priv`) `Update_priv`,
|
|
||||||
MAX(u.`Delete_priv`) `Delete_priv`,
|
|
||||||
MAX(u.`Create_priv`) `Create_priv`,
|
|
||||||
MAX(u.`Drop_priv`) `Drop_priv`,
|
|
||||||
MAX(u.`Reload_priv`) `Reload_priv`,
|
|
||||||
MAX(u.`Shutdown_priv`) `Shutdown_priv`,
|
|
||||||
MAX(u.`Process_priv`) `Process_priv`,
|
|
||||||
MAX(u.`File_priv`) `File_priv`,
|
|
||||||
MAX(u.`Grant_priv`) `Grant_priv`,
|
|
||||||
MAX(u.`References_priv`) `References_priv`,
|
|
||||||
MAX(u.`Index_priv`) `Index_priv`,
|
|
||||||
MAX(u.`Alter_priv`) `Alter_priv`,
|
|
||||||
MAX(u.`Show_db_priv`) `Show_db_priv`,
|
|
||||||
MAX(u.`Super_priv`) `Super_priv`,
|
|
||||||
MAX(u.`Create_tmp_table_priv`) `Create_tmp_table_priv`,
|
|
||||||
MAX(u.`Lock_tables_priv`) `Lock_tables_priv`,
|
|
||||||
MAX(u.`Execute_priv`) `Execute_priv`,
|
|
||||||
MAX(u.`Repl_slave_priv`) `Repl_slave_priv`,
|
|
||||||
MAX(u.`Repl_client_priv`) `Repl_client_priv`,
|
|
||||||
MAX(u.`Create_view_priv`) `Create_view_priv`,
|
|
||||||
MAX(u.`Show_view_priv`) `Show_view_priv`,
|
|
||||||
MAX(u.`Create_routine_priv`) `Create_routine_priv`,
|
|
||||||
MAX(u.`Alter_routine_priv`) `Alter_routine_priv`,
|
|
||||||
MAX(u.`Create_user_priv`) `Create_user_priv`,
|
|
||||||
MAX(u.`Event_priv`) `Event_priv`,
|
|
||||||
MAX(u.`Trigger_priv`) `Trigger_priv`,
|
|
||||||
MAX(u.`Create_tablespace_priv`) `Create_tablespace_priv`
|
|
||||||
FROM tRoleInherit r
|
|
||||||
JOIN mysql.user u
|
|
||||||
ON u.`User` = r.inheritsFrom
|
|
||||||
AND u.`Host`= vRoleHost
|
|
||||||
GROUP BY r.prefixedRole;
|
|
||||||
|
|
||||||
UPDATE mysql.user u
|
|
||||||
JOIN tUserPriv t
|
|
||||||
ON u.`User` = t.prefixedRole
|
|
||||||
AND u.`Host` = vTplHost
|
|
||||||
SET
|
|
||||||
u.`Select_priv`
|
|
||||||
= t.`Select_priv`,
|
|
||||||
u.`Insert_priv`
|
|
||||||
= t.`Insert_priv`,
|
|
||||||
u.`Update_priv`
|
|
||||||
= t.`Update_priv`,
|
|
||||||
u.`Delete_priv`
|
|
||||||
= t.`Delete_priv`,
|
|
||||||
u.`Create_priv`
|
|
||||||
= t.`Create_priv`,
|
|
||||||
u.`Drop_priv`
|
|
||||||
= t.`Drop_priv`,
|
|
||||||
u.`Reload_priv`
|
|
||||||
= t.`Reload_priv`,
|
|
||||||
u.`Shutdown_priv`
|
|
||||||
= t.`Shutdown_priv`,
|
|
||||||
u.`Process_priv`
|
|
||||||
= t.`Process_priv`,
|
|
||||||
u.`File_priv`
|
|
||||||
= t.`File_priv`,
|
|
||||||
u.`Grant_priv`
|
|
||||||
= t.`Grant_priv`,
|
|
||||||
u.`References_priv`
|
|
||||||
= t.`References_priv`,
|
|
||||||
u.`Index_priv`
|
|
||||||
= t.`Index_priv`,
|
|
||||||
u.`Alter_priv`
|
|
||||||
= t.`Alter_priv`,
|
|
||||||
u.`Show_db_priv`
|
|
||||||
= t.`Show_db_priv`,
|
|
||||||
u.`Super_priv`
|
|
||||||
= t.`Super_priv`,
|
|
||||||
u.`Create_tmp_table_priv`
|
|
||||||
= t.`Create_tmp_table_priv`,
|
|
||||||
u.`Lock_tables_priv`
|
|
||||||
= t.`Lock_tables_priv`,
|
|
||||||
u.`Execute_priv`
|
|
||||||
= t.`Execute_priv`,
|
|
||||||
u.`Repl_slave_priv`
|
|
||||||
= t.`Repl_slave_priv`,
|
|
||||||
u.`Repl_client_priv`
|
|
||||||
= t.`Repl_client_priv`,
|
|
||||||
u.`Create_view_priv`
|
|
||||||
= t.`Create_view_priv`,
|
|
||||||
u.`Show_view_priv`
|
|
||||||
= t.`Show_view_priv`,
|
|
||||||
u.`Create_routine_priv`
|
|
||||||
= t.`Create_routine_priv`,
|
|
||||||
u.`Alter_routine_priv`
|
|
||||||
= t.`Alter_routine_priv`,
|
|
||||||
u.`Create_user_priv`
|
|
||||||
= t.`Create_user_priv`,
|
|
||||||
u.`Event_priv`
|
|
||||||
= t.`Event_priv`,
|
|
||||||
u.`Trigger_priv`
|
|
||||||
= t.`Trigger_priv`,
|
|
||||||
u.`Create_tablespace_priv`
|
|
||||||
= t.`Create_tablespace_priv`;
|
|
||||||
ELSE
|
|
||||||
CREATE TEMPORARY TABLE tUserPriv
|
|
||||||
(INDEX (prefixedRole))
|
|
||||||
SELECT
|
|
||||||
r.prefixedRole,
|
|
||||||
BIT_OR(JSON_VALUE(p.`Priv`, '$.access')) access
|
|
||||||
FROM tRoleInherit r
|
|
||||||
JOIN mysql.global_priv p
|
|
||||||
ON p.`User` = r.inheritsFrom
|
|
||||||
AND p.`Host`= vRoleHost
|
|
||||||
GROUP BY r.prefixedRole;
|
|
||||||
|
|
||||||
UPDATE mysql.global_priv p
|
|
||||||
JOIN tUserPriv t
|
|
||||||
ON p.`User` = t.prefixedRole
|
|
||||||
AND p.`Host` = vTplHost
|
|
||||||
SET
|
|
||||||
p.`Priv` = JSON_SET(p.`Priv`, '$.access', t.access);
|
|
||||||
END IF;
|
|
||||||
|
|
||||||
DROP TEMPORARY TABLE tUserPriv;
|
|
||||||
|
|
||||||
-- Copy schema level privileges
|
|
||||||
|
|
||||||
INSERT INTO mysql.db (
|
|
||||||
`User`,
|
|
||||||
`Host`,
|
|
||||||
`Db`,
|
|
||||||
`Select_priv`,
|
|
||||||
`Insert_priv`,
|
|
||||||
`Update_priv`,
|
|
||||||
`Delete_priv`,
|
|
||||||
`Create_priv`,
|
|
||||||
`Drop_priv`,
|
|
||||||
`Grant_priv`,
|
|
||||||
`References_priv`,
|
|
||||||
`Index_priv`,
|
|
||||||
`Alter_priv`,
|
|
||||||
`Create_tmp_table_priv`,
|
|
||||||
`Lock_tables_priv`,
|
|
||||||
`Create_view_priv`,
|
|
||||||
`Show_view_priv`,
|
|
||||||
`Create_routine_priv`,
|
|
||||||
`Alter_routine_priv`,
|
|
||||||
`Execute_priv`,
|
|
||||||
`Event_priv`,
|
|
||||||
`Trigger_priv`
|
|
||||||
)
|
|
||||||
SELECT
|
|
||||||
r.prefixedRole,
|
|
||||||
vTplHost,
|
|
||||||
t.`Db`,
|
|
||||||
MAX(t.`Select_priv`),
|
|
||||||
MAX(t.`Insert_priv`),
|
|
||||||
MAX(t.`Update_priv`),
|
|
||||||
MAX(t.`Delete_priv`),
|
|
||||||
MAX(t.`Create_priv`),
|
|
||||||
MAX(t.`Drop_priv`),
|
|
||||||
MAX(t.`Grant_priv`),
|
|
||||||
MAX(t.`References_priv`),
|
|
||||||
MAX(t.`Index_priv`),
|
|
||||||
MAX(t.`Alter_priv`),
|
|
||||||
MAX(t.`Create_tmp_table_priv`),
|
|
||||||
MAX(t.`Lock_tables_priv`),
|
|
||||||
MAX(t.`Create_view_priv`),
|
|
||||||
MAX(t.`Show_view_priv`),
|
|
||||||
MAX(t.`Create_routine_priv`),
|
|
||||||
MAX(t.`Alter_routine_priv`),
|
|
||||||
MAX(t.`Execute_priv`),
|
|
||||||
MAX(t.`Event_priv`),
|
|
||||||
MAX(t.`Trigger_priv`)
|
|
||||||
FROM tRoleInherit r
|
|
||||||
JOIN mysql.db t
|
|
||||||
ON t.`User` = r.inheritsFrom
|
|
||||||
AND t.`Host`= vRoleHost
|
|
||||||
GROUP BY r.prefixedRole, t.`Db`;
|
|
||||||
|
|
||||||
-- Copy table level privileges
|
|
||||||
|
|
||||||
INSERT INTO mysql.tables_priv (
|
|
||||||
`User`,
|
|
||||||
`Host`,
|
|
||||||
`Db`,
|
|
||||||
`Table_name`,
|
|
||||||
`Grantor`,
|
|
||||||
`Timestamp`,
|
|
||||||
`Table_priv`,
|
|
||||||
`Column_priv`
|
|
||||||
)
|
|
||||||
SELECT
|
|
||||||
r.prefixedRole,
|
|
||||||
vTplHost,
|
|
||||||
t.`Db`,
|
|
||||||
t.`Table_name`,
|
|
||||||
t.`Grantor`,
|
|
||||||
MAX(t.`Timestamp`),
|
|
||||||
IFNULL(GROUP_CONCAT(NULLIF(t.`Table_priv`, '')), ''),
|
|
||||||
IFNULL(GROUP_CONCAT(NULLIF(t.`Column_priv`, '')), '')
|
|
||||||
FROM tRoleInherit r
|
|
||||||
JOIN mysql.tables_priv t
|
|
||||||
ON t.`User` = r.inheritsFrom
|
|
||||||
AND t.`Host`= vRoleHost
|
|
||||||
GROUP BY r.prefixedRole, t.`Db`, t.`Table_name`;
|
|
||||||
|
|
||||||
-- Copy column level privileges
|
|
||||||
|
|
||||||
INSERT INTO mysql.columns_priv (
|
|
||||||
`User`,
|
|
||||||
`Host`,
|
|
||||||
`Db`,
|
|
||||||
`Table_name`,
|
|
||||||
`Column_name`,
|
|
||||||
`Timestamp`,
|
|
||||||
`Column_priv`
|
|
||||||
)
|
|
||||||
SELECT
|
|
||||||
r.prefixedRole,
|
|
||||||
vTplHost,
|
|
||||||
t.`Db`,
|
|
||||||
t.`Table_name`,
|
|
||||||
t.`Column_name`,
|
|
||||||
MAX(t.`Timestamp`),
|
|
||||||
IFNULL(GROUP_CONCAT(NULLIF(t.`Column_priv`, '')), '')
|
|
||||||
FROM tRoleInherit r
|
|
||||||
JOIN mysql.columns_priv t
|
|
||||||
ON t.`User` = r.inheritsFrom
|
|
||||||
AND t.`Host`= vRoleHost
|
|
||||||
GROUP BY r.prefixedRole, t.`Db`, t.`Table_name`, t.`Column_name`;
|
|
||||||
|
|
||||||
-- Copy routine privileges
|
|
||||||
|
|
||||||
INSERT IGNORE INTO mysql.procs_priv (
|
|
||||||
`User`,
|
|
||||||
`Host`,
|
|
||||||
`Db`,
|
|
||||||
`Routine_name`,
|
|
||||||
`Routine_type`,
|
|
||||||
`Grantor`,
|
|
||||||
`Timestamp`,
|
|
||||||
`Proc_priv`
|
|
||||||
)
|
|
||||||
SELECT
|
|
||||||
r.prefixedRole,
|
|
||||||
vTplHost,
|
|
||||||
t.`Db`,
|
|
||||||
t.`Routine_name`,
|
|
||||||
t.`Routine_type`,
|
|
||||||
t.`Grantor`,
|
|
||||||
t.`Timestamp`,
|
|
||||||
t.`Proc_priv`
|
|
||||||
FROM tRoleInherit r
|
|
||||||
JOIN mysql.procs_priv t
|
|
||||||
ON t.`User` = r.inheritsFrom
|
|
||||||
AND t.`Host`= vRoleHost;
|
|
||||||
|
|
||||||
-- Free memory
|
|
||||||
|
|
||||||
DROP TEMPORARY TABLE
|
|
||||||
tRole,
|
|
||||||
tRoleInherit;
|
|
||||||
|
|
||||||
FLUSH PRIVILEGES;
|
|
||||||
END$$
|
|
||||||
DELIMITER ;
|
|
|
@ -1,15 +0,0 @@
|
||||||
DROP FUNCTION IF EXISTS account.userGetId;
|
|
||||||
|
|
||||||
DELIMITER $$
|
|
||||||
CREATE DEFINER=`root`@`%` FUNCTION `account`.`userGetId`() RETURNS int(11)
|
|
||||||
READS SQL DATA
|
|
||||||
DETERMINISTIC
|
|
||||||
BEGIN
|
|
||||||
/**
|
|
||||||
* @deprecated Use myUser_getId()
|
|
||||||
*/
|
|
||||||
RETURN myUser_getId();
|
|
||||||
END$$
|
|
||||||
DELIMITER ;
|
|
||||||
|
|
||||||
GRANT EXECUTE ON FUNCTION account.userGetId TO guest@localhost;
|
|
|
@ -1,11 +0,0 @@
|
||||||
DROP FUNCTION IF EXISTS account.userGetMysqlRole;
|
|
||||||
|
|
||||||
DELIMITER $$
|
|
||||||
CREATE DEFINER=`root`@`%` FUNCTION `account`.`userGetMysqlRole`(vUserName VARCHAR(255)) RETURNS varchar(255) CHARSET utf8
|
|
||||||
BEGIN
|
|
||||||
/**
|
|
||||||
* @deprecated Use user_getMysqlRole()
|
|
||||||
*/
|
|
||||||
RETURN user_getMysqlRole();
|
|
||||||
END$$
|
|
||||||
DELIMITER ;
|
|
|
@ -1,15 +0,0 @@
|
||||||
DROP FUNCTION IF EXISTS account.userGetName;
|
|
||||||
|
|
||||||
DELIMITER $$
|
|
||||||
CREATE DEFINER=`root`@`%` FUNCTION `account`.`userGetName`() RETURNS varchar(30) CHARSET utf8
|
|
||||||
NO SQL
|
|
||||||
DETERMINISTIC
|
|
||||||
BEGIN
|
|
||||||
/**
|
|
||||||
* @deprecated Use myUser_getName()
|
|
||||||
*/
|
|
||||||
RETURN myUser_getName();
|
|
||||||
END$$
|
|
||||||
DELIMITER ;
|
|
||||||
|
|
||||||
GRANT EXECUTE ON FUNCTION account.userGetName TO guest@localhost;
|
|
|
@ -1,11 +0,0 @@
|
||||||
DROP FUNCTION IF EXISTS account.userGetNameFromId;
|
|
||||||
|
|
||||||
DELIMITER $$
|
|
||||||
CREATE DEFINER=`root`@`%` FUNCTION `account`.`userGetNameFromId`(vSelf INT) RETURNS varchar(30) CHARSET utf8
|
|
||||||
BEGIN
|
|
||||||
/**
|
|
||||||
* @deprecated Use user_getNameFromId();
|
|
||||||
*/
|
|
||||||
RETURN user_getNameFromId(vSelf);
|
|
||||||
END$$
|
|
||||||
DELIMITER ;
|
|
|
@ -1,12 +0,0 @@
|
||||||
DROP FUNCTION IF EXISTS account.userHasRole;
|
|
||||||
|
|
||||||
DELIMITER $$
|
|
||||||
CREATE DEFINER=`root`@`%` FUNCTION `account`.`userHasRole`(vUserName VARCHAR(255), vRoleName VARCHAR(255)) RETURNS tinyint(1)
|
|
||||||
DETERMINISTIC
|
|
||||||
BEGIN
|
|
||||||
/**
|
|
||||||
* @deprecated Use user_hasRole()
|
|
||||||
*/
|
|
||||||
RETURN user_hasRole(vUserName, vRoleName);
|
|
||||||
END$$
|
|
||||||
DELIMITER ;
|
|
|
@ -1,12 +0,0 @@
|
||||||
DROP FUNCTION IF EXISTS account.userHasRoleId;
|
|
||||||
|
|
||||||
DELIMITER $$
|
|
||||||
CREATE DEFINER=`root`@`%` FUNCTION `account`.`userHasRoleId`(vUser VARCHAR(255), vRoleId INT) RETURNS tinyint(1)
|
|
||||||
DETERMINISTIC
|
|
||||||
BEGIN
|
|
||||||
/**
|
|
||||||
* @deprecated Use user_hasRoleId()
|
|
||||||
*/
|
|
||||||
RETURN user_hasRoleId(vUser, vRoleId);
|
|
||||||
END$$
|
|
||||||
DELIMITER ;
|
|
|
@ -1,14 +0,0 @@
|
||||||
DROP PROCEDURE IF EXISTS account.userLogin;
|
|
||||||
|
|
||||||
DELIMITER $$
|
|
||||||
CREATE DEFINER=`root`@`%` PROCEDURE `account`.`userLogin`(vUserName VARCHAR(255), vPassword VARCHAR(255))
|
|
||||||
READS SQL DATA
|
|
||||||
BEGIN
|
|
||||||
/**
|
|
||||||
* @deprecated Use myUser_login()
|
|
||||||
*/
|
|
||||||
CALL myUser_login(vUserName, vPassword);
|
|
||||||
END$$
|
|
||||||
DELIMITER ;
|
|
||||||
|
|
||||||
GRANT EXECUTE ON PROCEDURE account.userLogin TO guest@localhost;
|
|
|
@ -1,14 +0,0 @@
|
||||||
DROP PROCEDURE IF EXISTS account.userLoginWithKey;
|
|
||||||
|
|
||||||
DELIMITER $$
|
|
||||||
CREATE DEFINER=`root`@`%` PROCEDURE `account`.`userLoginWithKey`(vUserName VARCHAR(255), vKey VARCHAR(255))
|
|
||||||
READS SQL DATA
|
|
||||||
BEGIN
|
|
||||||
/**
|
|
||||||
* @deprecated Use myUser_loginWithKey()
|
|
||||||
*/
|
|
||||||
CALL myUser_loginWithKey(vUserName, vKey);
|
|
||||||
END$$
|
|
||||||
DELIMITER ;
|
|
||||||
|
|
||||||
GRANT EXECUTE ON PROCEDURE account.userLoginWithKey TO guest@localhost;
|
|
|
@ -1,12 +0,0 @@
|
||||||
DROP PROCEDURE IF EXISTS account.userLoginWithName;
|
|
||||||
|
|
||||||
DELIMITER $$
|
|
||||||
CREATE DEFINER=`root`@`%` PROCEDURE `account`.`userLoginWithName`(vUserName VARCHAR(255))
|
|
||||||
READS SQL DATA
|
|
||||||
BEGIN
|
|
||||||
/**
|
|
||||||
* @deprecated Use myUser_loginWithName()
|
|
||||||
*/
|
|
||||||
CALL myUser_loginWithName(vUserName);
|
|
||||||
END$$
|
|
||||||
DELIMITER ;
|
|
|
@ -1,14 +0,0 @@
|
||||||
DROP PROCEDURE IF EXISTS account.myUserLogout;
|
|
||||||
|
|
||||||
DELIMITER $$
|
|
||||||
$$
|
|
||||||
CREATE DEFINER=`root`@`%` PROCEDURE `account`.`myUserLogout`()
|
|
||||||
BEGIN
|
|
||||||
/**
|
|
||||||
* @deprecated Use myUser_Logout()
|
|
||||||
*/
|
|
||||||
CALL myUser_logout;
|
|
||||||
END$$
|
|
||||||
DELIMITER ;
|
|
||||||
|
|
||||||
GRANT EXECUTE ON PROCEDURE account.myUserLogout TO account@localhost;
|
|
|
@ -1,16 +0,0 @@
|
||||||
DROP PROCEDURE IF EXISTS account.userSetPassword;
|
|
||||||
|
|
||||||
DELIMITER $$
|
|
||||||
CREATE DEFINER=`root`@`%` PROCEDURE `account`.`userSetPassword`(vUserName VARCHAR(255), vPassword VARCHAR(255))
|
|
||||||
BEGIN
|
|
||||||
/**
|
|
||||||
* @deprecated Use user_setPassword()
|
|
||||||
*/
|
|
||||||
DECLARE vUserId INT;
|
|
||||||
|
|
||||||
SELECT id INTO vUserId
|
|
||||||
FROM user WHERE `name` = vUserName;
|
|
||||||
|
|
||||||
CALL user_setPassword(vUserId, vPassword);
|
|
||||||
END$$
|
|
||||||
DELIMITER ;
|
|
|
@ -1,27 +0,0 @@
|
||||||
DROP PROCEDURE IF EXISTS account.user_changePassword;
|
|
||||||
|
|
||||||
DELIMITER $$
|
|
||||||
CREATE DEFINER=`root`@`%` PROCEDURE account.user_changePassword(vSelf INT, vOldPassword VARCHAR(255), vPassword VARCHAR(255))
|
|
||||||
BEGIN
|
|
||||||
/**
|
|
||||||
* Changes the user password.
|
|
||||||
*
|
|
||||||
* @param vSelf The user id
|
|
||||||
* @param vOldPassword The current password
|
|
||||||
* @param vPassword The new password
|
|
||||||
*/
|
|
||||||
DECLARE vPasswordOk BOOL;
|
|
||||||
DECLARE vUserName VARCHAR(255);
|
|
||||||
|
|
||||||
SELECT `password` = MD5(vOldPassword), `name`
|
|
||||||
INTO vPasswordOk, vUserName
|
|
||||||
FROM user WHERE id = vSelf;
|
|
||||||
|
|
||||||
IF NOT vPasswordOk THEN
|
|
||||||
SIGNAL SQLSTATE '45000'
|
|
||||||
SET MESSAGE_TEXT = 'Invalid password';
|
|
||||||
END IF;
|
|
||||||
|
|
||||||
CALL user_setPassword(vSelf, vPassword);
|
|
||||||
END$$
|
|
||||||
DELIMITER ;
|
|
|
@ -1,17 +0,0 @@
|
||||||
DROP PROCEDURE IF EXISTS account.user_checkName;
|
|
||||||
|
|
||||||
DELIMITER $$
|
|
||||||
CREATE DEFINER=`root`@`%` PROCEDURE `account`.`user_checkName`(vUserName VARCHAR(255))
|
|
||||||
BEGIN
|
|
||||||
/**
|
|
||||||
* Checks that username meets the necessary syntax requirements, otherwise it
|
|
||||||
* throws an exception.
|
|
||||||
* The user name must only contain lowercase letters or, starting with second
|
|
||||||
* character, numbers or underscores.
|
|
||||||
*/
|
|
||||||
IF vUserName NOT REGEXP '^[a-z0-9_-]*$' THEN
|
|
||||||
SIGNAL SQLSTATE '45000'
|
|
||||||
SET MESSAGE_TEXT = 'INVALID_USER_NAME';
|
|
||||||
END IF;
|
|
||||||
END$$
|
|
||||||
DELIMITER ;
|
|
|
@ -1,22 +0,0 @@
|
||||||
DROP FUNCTION IF EXISTS account.user_getMysqlRole;
|
|
||||||
|
|
||||||
DELIMITER $$
|
|
||||||
CREATE DEFINER=`root`@`%` FUNCTION `account`.`user_getMysqlRole`(vUserName VARCHAR(255)) RETURNS varchar(255) CHARSET utf8
|
|
||||||
BEGIN
|
|
||||||
/**
|
|
||||||
* From a username, it returns the associated MySQL wich should be used when
|
|
||||||
* using external authentication systems.
|
|
||||||
*
|
|
||||||
* @param vUserName The user name
|
|
||||||
* @return The associated MySQL role
|
|
||||||
*/
|
|
||||||
DECLARE vRole VARCHAR(255);
|
|
||||||
|
|
||||||
SELECT CONCAT(IF(r.hasLogin, 'z-', ''), r.name) INTO vRole
|
|
||||||
FROM role r
|
|
||||||
JOIN user u ON u.role = r.id
|
|
||||||
WHERE u.name = vUserName;
|
|
||||||
|
|
||||||
RETURN vRole;
|
|
||||||
END$$
|
|
||||||
DELIMITER ;
|
|
|
@ -1,20 +0,0 @@
|
||||||
DROP FUNCTION IF EXISTS account.user_getNameFromId;
|
|
||||||
|
|
||||||
DELIMITER $$
|
|
||||||
CREATE DEFINER=`root`@`%` FUNCTION `account`.`user_getNameFromId`(vSelf INT) RETURNS varchar(30) CHARSET utf8
|
|
||||||
BEGIN
|
|
||||||
/**
|
|
||||||
* Gets user name from it's id.
|
|
||||||
*
|
|
||||||
* @param vSelf The user id
|
|
||||||
* @return The user name
|
|
||||||
*/
|
|
||||||
DECLARE vName VARCHAR(30);
|
|
||||||
|
|
||||||
SELECT `name` INTO vName
|
|
||||||
FROM user
|
|
||||||
WHERE id = vSelf;
|
|
||||||
|
|
||||||
RETURN vName;
|
|
||||||
END$$
|
|
||||||
DELIMITER ;
|
|
|
@ -1,25 +0,0 @@
|
||||||
DROP FUNCTION IF EXISTS account.user_hasRole;
|
|
||||||
|
|
||||||
DELIMITER $$
|
|
||||||
CREATE DEFINER=`root`@`%` FUNCTION `account`.`user_hasRole`(vUserName VARCHAR(255), vRoleName VARCHAR(255)) RETURNS tinyint(1)
|
|
||||||
DETERMINISTIC
|
|
||||||
BEGIN
|
|
||||||
/**
|
|
||||||
* Checks if user has/inherits a role.
|
|
||||||
*
|
|
||||||
* @param vUserName The user name
|
|
||||||
* @param vRoleName Role to check
|
|
||||||
* @return %TRUE if it has role, %FALSE otherwise
|
|
||||||
*/
|
|
||||||
DECLARE vHasRole BOOL DEFAULT FALSE;
|
|
||||||
|
|
||||||
SELECT COUNT(*) > 0 INTO vHasRole
|
|
||||||
FROM user u
|
|
||||||
JOIN roleRole rr ON rr.role = u.role
|
|
||||||
JOIN role r ON r.id = rr.inheritsFrom
|
|
||||||
WHERE u.`name` = vUserName
|
|
||||||
AND r.`name` = vRoleName COLLATE 'utf8_unicode_ci';
|
|
||||||
|
|
||||||
RETURN vHasRole;
|
|
||||||
END$$
|
|
||||||
DELIMITER ;
|
|
|
@ -1,25 +0,0 @@
|
||||||
DROP FUNCTION IF EXISTS account.user_hasRoleId;
|
|
||||||
|
|
||||||
DELIMITER $$
|
|
||||||
CREATE DEFINER=`root`@`%` FUNCTION `account`.`user_hasRoleId`(vUser VARCHAR(255), vRoleId INT) RETURNS tinyint(1)
|
|
||||||
DETERMINISTIC
|
|
||||||
BEGIN
|
|
||||||
/**
|
|
||||||
* Checks if user has/inherits a role.
|
|
||||||
*
|
|
||||||
* @param vUserName The user name
|
|
||||||
* @param vRoleId Role id to check
|
|
||||||
* @return %TRUE if it has role, %FALSE otherwise
|
|
||||||
*/
|
|
||||||
DECLARE vHasRole BOOL DEFAULT FALSE;
|
|
||||||
|
|
||||||
SELECT COUNT(*) > 0 INTO vHasRole
|
|
||||||
FROM user u
|
|
||||||
JOIN roleRole rr ON rr.role = u.role
|
|
||||||
JOIN role r ON r.id = rr.inheritsFrom
|
|
||||||
WHERE u.`name` = vUser
|
|
||||||
AND r.id = vRoleId;
|
|
||||||
|
|
||||||
RETURN vHasRole;
|
|
||||||
END$$
|
|
||||||
DELIMITER ;
|
|
|
@ -1,21 +0,0 @@
|
||||||
DROP PROCEDURE IF EXISTS account.user_setPassword;
|
|
||||||
|
|
||||||
DELIMITER $$
|
|
||||||
CREATE DEFINER=`root`@`%` PROCEDURE account.user_setPassword(vSelf INT, vPassword VARCHAR(255))
|
|
||||||
BEGIN
|
|
||||||
/**
|
|
||||||
* Change the password of the passed as a parameter. Only administrators should
|
|
||||||
* have execute privileges on the procedure since it does not request the user's
|
|
||||||
* current password.
|
|
||||||
*
|
|
||||||
* @param vSelf The user id
|
|
||||||
* @param vPassword New password
|
|
||||||
*/
|
|
||||||
CALL user_checkPassword(vPassword);
|
|
||||||
|
|
||||||
UPDATE user SET
|
|
||||||
`password` = MD5(vPassword),
|
|
||||||
`recoverPass` = FALSE
|
|
||||||
WHERE id = vSelf;
|
|
||||||
END$$
|
|
||||||
DELIMITER ;
|
|
|
@ -1 +0,0 @@
|
||||||
UPDATE salix.ACL t SET t.principalId = 'salesAssistant' WHERE t.id = 234
|
|
|
@ -1,37 +0,0 @@
|
||||||
CREATE TABLE `vn`.campaign
|
|
||||||
(
|
|
||||||
id INT AUTO_INCREMENT,
|
|
||||||
code ENUM('mothersDay', 'allSaints', 'valentinesDay') NOT NULL,
|
|
||||||
dated DATE DEFAULT CURDATE() NOT NULL,
|
|
||||||
scopeDays INT NOT NULL DEFAULT '15',
|
|
||||||
CONSTRAINT campaign_pk
|
|
||||||
PRIMARY KEY (id)
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE UNIQUE INDEX campaign_dated_uindex
|
|
||||||
ON `vn`.campaign (dated);
|
|
||||||
|
|
||||||
-- TODOS SANTOS
|
|
||||||
INSERT INTO `vn`.campaign(code, dated)
|
|
||||||
SELECT 'allSaints' AS code, dated
|
|
||||||
FROM `vn`.time
|
|
||||||
WHERE dated >= CONCAT(YEAR(CURDATE()) - 1, '-01-01')
|
|
||||||
AND month = 11
|
|
||||||
AND day = 1;
|
|
||||||
|
|
||||||
-- SAN VALENTIN
|
|
||||||
INSERT INTO `vn`.campaign(code, dated)
|
|
||||||
SELECT 'valentinesDay' AS code, dated
|
|
||||||
FROM `vn`.time
|
|
||||||
WHERE dated >= CONCAT(YEAR(CURDATE()) - 1, '-01-01')
|
|
||||||
AND month = 2
|
|
||||||
AND day = 14;
|
|
||||||
|
|
||||||
-- DIA DE LA MADRE
|
|
||||||
INSERT INTO `vn`.campaign(code, dated)
|
|
||||||
SELECT 'mothersDay' AS code, dated
|
|
||||||
FROM `vn`.time
|
|
||||||
WHERE dated >= CONCAT(YEAR(CURDATE()) - 1, '-01-01')
|
|
||||||
AND month = 5
|
|
||||||
AND WEEK(dated, 5) - WEEK(DATE_SUB(dated, INTERVAL DAYOFMONTH(dated) - 1 DAY), 5) + 1 = 1 -- WEEK OF MONTH
|
|
||||||
AND DAYOFWEEK(dated) = 1;
|
|
|
@ -1,4 +0,0 @@
|
||||||
ALTER TABLE `vn`.department
|
|
||||||
ADD notificationEmail VARCHAR(150) null;
|
|
||||||
|
|
||||||
UPDATE vn.department t SET t.notificationEmail = 'direccioncomercial@verdnatura.es' WHERE t.id = 43
|
|
|
@ -8,3 +8,15 @@ ALTER TABLE account.ldapConfig DROP COLUMN `filter`;
|
||||||
ALTER TABLE account.ldapConfig CHANGE baseDn userDn varchar(255) DEFAULT NULL NULL COMMENT 'The base DN to do the query';
|
ALTER TABLE account.ldapConfig CHANGE baseDn userDn varchar(255) DEFAULT NULL NULL COMMENT 'The base DN to do the query';
|
||||||
ALTER TABLE account.ldapConfig CHANGE host server varchar(255) NOT NULL COMMENT 'The hostname of LDAP server';
|
ALTER TABLE account.ldapConfig CHANGE host server varchar(255) NOT NULL COMMENT 'The hostname of LDAP server';
|
||||||
ALTER TABLE account.ldapConfig MODIFY COLUMN password varchar(255) NOT NULL COMMENT 'The LDAP password';
|
ALTER TABLE account.ldapConfig MODIFY COLUMN password varchar(255) NOT NULL COMMENT 'The LDAP password';
|
||||||
|
|
||||||
|
-- Updated
|
||||||
|
|
||||||
|
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 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';
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
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', '*', 'WRITE', 'ALLOW', 'ROLE', 'administrative');
|
||||||
|
INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`) VALUES ('SupplierContact', '*', 'WRITE', 'ALLOW', 'ROLE', 'administrative');
|
|
@ -0,0 +1,3 @@
|
||||||
|
UPDATE `vn`.`claimState` SET `roleFk` = '72' WHERE (`id` = '3');
|
||||||
|
UPDATE `vn`.`claimState` SET `roleFk` = '72' WHERE (`id` = '4');
|
||||||
|
UPDATE `vn`.`claimState` SET `roleFk` = '72' WHERE (`id` = '5');
|
|
@ -0,0 +1,9 @@
|
||||||
|
ALTER TABLE `vn`.`observationType`
|
||||||
|
ADD COLUMN `code` VARCHAR(45) NOT NULL AFTER `description`;
|
||||||
|
|
||||||
|
UPDATE `vn`.`observationType` SET `code` = 'itemPicker' WHERE (`id` = '1');
|
||||||
|
UPDATE `vn`.`observationType` SET `code` = 'packager' WHERE (`id` = '2');
|
||||||
|
UPDATE `vn`.`observationType` SET `code` = 'salesPerson' WHERE (`id` = '4');
|
||||||
|
UPDATE `vn`.`observationType` SET `code` = 'administrative' WHERE (`id` = '5');
|
||||||
|
UPDATE `vn`.`observationType` SET `code` = 'weight' WHERE (`id` = '6');
|
||||||
|
UPDATE `vn`.`observationType` SET `code` = 'delivery' WHERE (`id` = '3');
|
|
@ -0,0 +1,20 @@
|
||||||
|
CREATE TABLE `vn`.`supplierLog` (
|
||||||
|
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||||
|
`originFk` int(11) NOT NULL,
|
||||||
|
`userFk` int(10) unsigned NOT NULL,
|
||||||
|
`action` set('insert','update','delete') COLLATE utf8_unicode_ci NOT NULL,
|
||||||
|
`creationDate` timestamp NULL DEFAULT current_timestamp(),
|
||||||
|
`description` text CHARACTER SET utf8 DEFAULT NULL,
|
||||||
|
`changedModel` varchar(45) COLLATE utf8_unicode_ci DEFAULT NULL,
|
||||||
|
`oldInstance` text COLLATE utf8_unicode_ci DEFAULT NULL,
|
||||||
|
`newInstance` text COLLATE utf8_unicode_ci DEFAULT NULL,
|
||||||
|
`changedModelId` int(11) DEFAULT NULL,
|
||||||
|
`changedModelValue` varchar(45) COLLATE utf8_unicode_ci DEFAULT NULL,
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
KEY `logSupplier_ibfk_1` (`originFk`),
|
||||||
|
KEY `supplierLog_ibfk_2` (`userFk`),
|
||||||
|
CONSTRAINT `supplierLog_ibfk_1` FOREIGN KEY (`originFk`) REFERENCES `supplier` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
|
||||||
|
CONSTRAINT `supplierLog_ibfk_2` FOREIGN KEY (`userFk`) REFERENCES `account`.`user` (`id`) ON UPDATE CASCADE
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
DROP TRIGGER IF EXISTS `vn`.`ticket_afterUpdate`;
|
||||||
|
|
||||||
|
DELIMITER $$
|
||||||
|
USE `vn`$$
|
||||||
|
CREATE DEFINER=`root`@`%` TRIGGER `ticket_afterUpdate`
|
||||||
|
AFTER UPDATE ON `ticket`
|
||||||
|
FOR EACH ROW
|
||||||
|
BEGIN
|
||||||
|
IF !(NEW.id <=> OLD.id)
|
||||||
|
OR !(NEW.warehouseFk <=> OLD.warehouseFk)
|
||||||
|
OR !(NEW.shipped <=> OLD.shipped) THEN
|
||||||
|
CALL stock.log_add('ticket', NEW.id, OLD.id);
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
IF NEW.clientFk = 2067 AND !(NEW.clientFk <=> OLD.clientFk) THEN
|
||||||
|
-- Fallo que se insertan no se sabe como tickets en este cliente
|
||||||
|
INSERT INTO vn.mail SET
|
||||||
|
`sender` = 'jgallego@verdnatura.es',
|
||||||
|
`replyTo` = 'jgallego@verdnatura.es',
|
||||||
|
`subject` = 'Modificado ticket al cliente 2067',
|
||||||
|
`body` = CONCAT(account.myUserGetName(), ' ha modificado el ticket ',
|
||||||
|
NEW.id);
|
||||||
|
END IF;
|
||||||
|
END$$
|
||||||
|
DELIMITER ;
|
|
@ -0,0 +1,107 @@
|
||||||
|
USE `vn`;
|
||||||
|
DROP procedure IF EXISTS `ticket_componentPreview`;
|
||||||
|
|
||||||
|
DELIMITER $$
|
||||||
|
USE `vn`$$
|
||||||
|
CREATE DEFINER=`root`@`%` PROCEDURE `ticket_componentPreview`(
|
||||||
|
vTicketFk INT,
|
||||||
|
vLanded DATE,
|
||||||
|
vAddressFk INT,
|
||||||
|
vZoneFk INT,
|
||||||
|
vWarehouseFk SMALLINT)
|
||||||
|
BEGIN
|
||||||
|
/**
|
||||||
|
* Calcula los componentes de los articulos de un ticket
|
||||||
|
*
|
||||||
|
* @param vTicketFk id del ticket
|
||||||
|
* @param vLanded nueva fecha de entrega
|
||||||
|
* @param vAddressFk nuevo consignatario
|
||||||
|
* @param vZoneFk nueva zona
|
||||||
|
* @param vWarehouseFk nuevo warehouse
|
||||||
|
*
|
||||||
|
* @return tmp.ticketComponentPreview (warehouseFk, itemFk, componentFk, cost)
|
||||||
|
*/
|
||||||
|
DECLARE vHasDataChanged BOOL DEFAULT FALSE;
|
||||||
|
DECLARE vHasAddressChanged BOOL;
|
||||||
|
DECLARE vHasZoneChanged BOOL DEFAULT FALSE;
|
||||||
|
DECLARE vHasWarehouseChanged BOOL DEFAULT FALSE;
|
||||||
|
|
||||||
|
DECLARE vShipped DATE;
|
||||||
|
DECLARE vAddressTypeRateFk INT DEFAULT NULL;
|
||||||
|
DECLARE vAgencyModeTypeRateFk INT DEFAULT NULL;
|
||||||
|
|
||||||
|
DECLARE vHasChangeAll BOOL DEFAULT FALSE;
|
||||||
|
|
||||||
|
SELECT DATE(landed) <> vLanded,
|
||||||
|
addressFk <> vAddressFk,
|
||||||
|
zoneFk <> vZoneFk,
|
||||||
|
warehouseFk <> vWarehouseFk
|
||||||
|
INTO
|
||||||
|
vHasDataChanged,
|
||||||
|
vHasAddressChanged,
|
||||||
|
vHasZoneChanged,
|
||||||
|
vHasWarehouseChanged
|
||||||
|
FROM vn.ticket t
|
||||||
|
WHERE t.id = vTicketFk;
|
||||||
|
|
||||||
|
IF vHasDataChanged OR vHasWarehouseChanged THEN
|
||||||
|
SET vHasChangeAll = TRUE;
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
IF vHasAddressChanged THEN
|
||||||
|
SET vAddressTypeRateFk = 5;
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
IF vHasZoneChanged THEN
|
||||||
|
SET vAgencyModeTypeRateFk = 6;
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
SELECT TIMESTAMPADD(DAY, -travelingDays, vLanded) INTO vShipped
|
||||||
|
FROM zone
|
||||||
|
WHERE id = vZoneFk;
|
||||||
|
|
||||||
|
CALL buyUltimate(vWarehouseFk, vShipped);
|
||||||
|
|
||||||
|
DROP TEMPORARY TABLE IF EXISTS tmp.ticketLot;
|
||||||
|
CREATE TEMPORARY TABLE tmp.ticketLot ENGINE = MEMORY (
|
||||||
|
SELECT
|
||||||
|
vWarehouseFk AS warehouseFk,
|
||||||
|
NULL AS available,
|
||||||
|
s.itemFk,
|
||||||
|
bu.buyFk,
|
||||||
|
vZoneFk zoneFk
|
||||||
|
FROM sale s
|
||||||
|
LEFT JOIN tmp.buyUltimate bu ON bu.itemFk = s.itemFk
|
||||||
|
WHERE s.ticketFk = vTicketFk
|
||||||
|
GROUP BY bu.warehouseFk, bu.itemFk);
|
||||||
|
|
||||||
|
CALL catalog_componentPrepare();
|
||||||
|
CALL catalog_componentCalculate(vZoneFk, vAddressFk, vShipped, vWarehouseFk);
|
||||||
|
|
||||||
|
REPLACE INTO tmp.ticketComponent (warehouseFk, itemFk, componentFk, cost)
|
||||||
|
SELECT t.warehouseFk, s.itemFk, sc.componentFk, sc.value
|
||||||
|
FROM saleComponent sc
|
||||||
|
JOIN sale s ON s.id = sc.saleFk
|
||||||
|
JOIN ticket t ON t.id = s.ticketFk
|
||||||
|
JOIN `component` c ON c.id = sc.componentFk
|
||||||
|
WHERE s.ticketFk = vTicketFk
|
||||||
|
AND (c.isRenewable = FALSE
|
||||||
|
OR
|
||||||
|
(NOT vHasChangeAll
|
||||||
|
AND (NOT (c.typeFk <=> vAddressTypeRateFk
|
||||||
|
OR c.typeFk <=> vAgencyModeTypeRateFk))));
|
||||||
|
|
||||||
|
DROP TEMPORARY TABLE IF EXISTS tmp.ticketComponentPreview;
|
||||||
|
CREATE TEMPORARY TABLE tmp.ticketComponentPreview
|
||||||
|
SELECT * FROM tmp.ticketComponent;
|
||||||
|
|
||||||
|
CALL catalog_componentPurge();
|
||||||
|
DROP TEMPORARY TABLE tmp.buyUltimate;
|
||||||
|
|
||||||
|
IF vShipped IS NULL THEN
|
||||||
|
CALL util.throw('NO_ZONE_AVAILABLE');
|
||||||
|
END IF;
|
||||||
|
END$$
|
||||||
|
|
||||||
|
DELIMITER ;
|
||||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
|
@ -87,5 +87,6 @@ TABLES=(
|
||||||
sage
|
sage
|
||||||
TiposIva
|
TiposIva
|
||||||
TiposTransacciones
|
TiposTransacciones
|
||||||
|
TiposRetencion
|
||||||
)
|
)
|
||||||
dump_tables ${TABLES[@]}
|
dump_tables ${TABLES[@]}
|
|
@ -272,9 +272,9 @@ export default {
|
||||||
firstRequestItemID: 'vn-item-request vn-tbody > vn-tr:nth-child(1) > vn-td-editable:nth-child(7)',
|
firstRequestItemID: 'vn-item-request vn-tbody > vn-tr:nth-child(1) > vn-td-editable:nth-child(7)',
|
||||||
firstRequestQuantity: 'vn-item-request vn-tbody > vn-tr:nth-child(1) > vn-td-editable:nth-child(8)',
|
firstRequestQuantity: 'vn-item-request vn-tbody > vn-tr:nth-child(1) > vn-td-editable:nth-child(8)',
|
||||||
firstRequestConcept: 'vn-item-request vn-tbody > vn-tr:nth-child(1) > vn-td:nth-child(9)',
|
firstRequestConcept: 'vn-item-request vn-tbody > vn-tr:nth-child(1) > vn-td:nth-child(9)',
|
||||||
secondRequestStatus: 'vn-item-request vn-tbody > vn-tr:nth-child(2) > vn-td:nth-child(10)',
|
|
||||||
firstRequestStatus: 'vn-item-request vn-tbody > vn-tr:nth-child(1) > vn-td:nth-child(10)',
|
firstRequestStatus: 'vn-item-request vn-tbody > vn-tr:nth-child(1) > vn-td:nth-child(10)',
|
||||||
secondRequestDecline: 'vn-item-request vn-tbody > vn-tr:nth-child(1) vn-icon-button[icon="thumb_down"]',
|
secondRequestStatus: 'vn-item-request vn-tbody > vn-tr:nth-child(2) > vn-td:nth-child(10)',
|
||||||
|
secondRequestDecline: 'vn-item-request vn-tr:nth-child(2) vn-icon-button[icon="thumb_down"]',
|
||||||
declineReason: 'vn-textarea[ng-model="$ctrl.denyObservation"]'
|
declineReason: 'vn-textarea[ng-model="$ctrl.denyObservation"]'
|
||||||
},
|
},
|
||||||
itemBasicData: {
|
itemBasicData: {
|
||||||
|
@ -613,7 +613,7 @@ export default {
|
||||||
isPaidWithManaCheckbox: 'vn-claim-action vn-check[ng-model="$ctrl.claim.isChargedToMana"]'
|
isPaidWithManaCheckbox: 'vn-claim-action vn-check[ng-model="$ctrl.claim.isChargedToMana"]'
|
||||||
},
|
},
|
||||||
ordersIndex: {
|
ordersIndex: {
|
||||||
secondSearchResultTotal: 'vn-order-index vn-card > vn-table > div > vn-tbody vn-tr:nth-child(2) vn-td:nth-child(9)',
|
secondSearchResultTotal: 'vn-order-index vn-card > vn-table > div > vn-tbody .vn-tr:nth-child(2) vn-td:nth-child(9)',
|
||||||
advancedSearchButton: 'vn-order-search-panel vn-submit[label="Search"]',
|
advancedSearchButton: 'vn-order-search-panel vn-submit[label="Search"]',
|
||||||
openAdvancedSearch: 'vn-searchbar vn-icon[icon="arrow_drop_down"]',
|
openAdvancedSearch: 'vn-searchbar vn-icon[icon="arrow_drop_down"]',
|
||||||
advancedSearchShowEmptyCheckbox: 'vn-order-search-panel vn-check[label="Show empty"]',
|
advancedSearchShowEmptyCheckbox: 'vn-order-search-panel vn-check[label="Show empty"]',
|
||||||
|
|
|
@ -28,7 +28,7 @@ describe('Item request path', () => {
|
||||||
expect(filledConcept).toContain('Melee weapon heavy shield 1x0.5m');
|
expect(filledConcept).toContain('Melee weapon heavy shield 1x0.5m');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should the status of the request should now be accepted', async() => {
|
it('should check the status of the request should now be accepted', async() => {
|
||||||
let status = await page.waitToGetProperty(selectors.itemRequest.firstRequestStatus, 'innerText');
|
let status = await page.waitToGetProperty(selectors.itemRequest.firstRequestStatus, 'innerText');
|
||||||
|
|
||||||
expect(status).toContain('Accepted');
|
expect(status).toContain('Accepted');
|
||||||
|
@ -38,7 +38,7 @@ describe('Item request path', () => {
|
||||||
await page.waitToClick(selectors.itemRequest.secondRequestDecline);
|
await page.waitToClick(selectors.itemRequest.secondRequestDecline);
|
||||||
await page.write(selectors.itemRequest.declineReason, 'Not quite as expected');
|
await page.write(selectors.itemRequest.declineReason, 'Not quite as expected');
|
||||||
await page.respondToDialog('accept');
|
await page.respondToDialog('accept');
|
||||||
let status = await page.waitToGetProperty(selectors.itemRequest.firstRequestStatus, 'innerText');
|
let status = await page.waitToGetProperty(selectors.itemRequest.secondRequestStatus, 'innerText');
|
||||||
|
|
||||||
expect(status).toContain('Denied');
|
expect(status).toContain('Denied');
|
||||||
});
|
});
|
||||||
|
|
|
@ -165,7 +165,7 @@ export default class Contextmenu {
|
||||||
removeFilter() {
|
removeFilter() {
|
||||||
const userFilter = this.model.userFilter;
|
const userFilter = this.model.userFilter;
|
||||||
const userParams = this.model.userParams;
|
const userParams = this.model.userParams;
|
||||||
const where = userFilter.where;
|
const where = userFilter && userFilter.where;
|
||||||
|
|
||||||
let filterKey = this.fieldName;
|
let filterKey = this.fieldName;
|
||||||
if (this.exprBuilder) {
|
if (this.exprBuilder) {
|
||||||
|
@ -173,9 +173,11 @@ export default class Contextmenu {
|
||||||
param: filterKey,
|
param: filterKey,
|
||||||
value: null
|
value: null
|
||||||
});
|
});
|
||||||
[filterKey] = Object.keys(param);
|
if (param) [filterKey] = Object.keys(param);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!where) return;
|
||||||
|
|
||||||
const whereKeys = Object.keys(where);
|
const whereKeys = Object.keys(where);
|
||||||
for (let key of whereKeys)
|
for (let key of whereKeys)
|
||||||
removeProp(where, filterKey, key);
|
removeProp(where, filterKey, key);
|
||||||
|
|
|
@ -62,4 +62,5 @@ Go up: Ir arriba
|
||||||
Loading...: Cargando...
|
Loading...: Cargando...
|
||||||
No results found: Sin resultados
|
No results found: Sin resultados
|
||||||
No data: Sin datos
|
No data: Sin datos
|
||||||
Load more: Cargar más
|
Load more: Cargar más
|
||||||
|
Undo changes: Deshacer cambios
|
|
@ -0,0 +1,15 @@
|
||||||
|
|
||||||
|
module.exports = Self => {
|
||||||
|
Self.remoteMethod('test', {
|
||||||
|
description: 'Tests connector configuration',
|
||||||
|
http: {
|
||||||
|
path: `/test`,
|
||||||
|
verb: 'GET'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Self.test = async function() {
|
||||||
|
let connector = await Self.getSynchronizer();
|
||||||
|
await connector.test();
|
||||||
|
};
|
||||||
|
};
|
|
@ -1,6 +1,4 @@
|
||||||
|
|
||||||
const SyncEngine = require('../../util/sync-engine');
|
|
||||||
|
|
||||||
module.exports = Self => {
|
module.exports = Self => {
|
||||||
Self.remoteMethod('sync', {
|
Self.remoteMethod('sync', {
|
||||||
description: 'Synchronizes the user with the other user databases',
|
description: 'Synchronizes the user with the other user databases',
|
||||||
|
@ -11,17 +9,6 @@ module.exports = Self => {
|
||||||
});
|
});
|
||||||
|
|
||||||
Self.sync = async function() {
|
Self.sync = async function() {
|
||||||
let engine = new SyncEngine();
|
await Self.app.models.AccountConfig.syncRoles();
|
||||||
await engine.init(Self.app.models);
|
|
||||||
|
|
||||||
let err;
|
|
||||||
try {
|
|
||||||
await engine.syncRoles();
|
|
||||||
} catch (e) {
|
|
||||||
err = e;
|
|
||||||
}
|
|
||||||
|
|
||||||
await engine.deinit();
|
|
||||||
if (err) throw err;
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
|
|
||||||
const SyncEngine = require('../../util/sync-engine');
|
|
||||||
|
|
||||||
module.exports = Self => {
|
module.exports = Self => {
|
||||||
Self.remoteMethod('syncAll', {
|
Self.remoteMethod('syncAll', {
|
||||||
description: 'Synchronizes user database with LDAP and Samba',
|
description: 'Synchronizes user database with LDAP and Samba',
|
||||||
|
@ -11,26 +9,6 @@ module.exports = Self => {
|
||||||
});
|
});
|
||||||
|
|
||||||
Self.syncAll = async function() {
|
Self.syncAll = async function() {
|
||||||
let $ = Self.app.models;
|
await Self.app.models.AccountConfig.syncUsers();
|
||||||
|
|
||||||
let engine = new SyncEngine();
|
|
||||||
await engine.init($);
|
|
||||||
|
|
||||||
let usersToSync = await engine.getUsers();
|
|
||||||
usersToSync = Array.from(usersToSync.values())
|
|
||||||
.sort((a, b) => a.localeCompare(b));
|
|
||||||
|
|
||||||
for (let user of usersToSync) {
|
|
||||||
try {
|
|
||||||
console.log(`Synchronizing user '${user}'`);
|
|
||||||
await engine.sync(user);
|
|
||||||
console.log(` -> '${user}' sinchronized`);
|
|
||||||
} catch (err) {
|
|
||||||
console.error(` -> '${user}' synchronization error:`, err.message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
await engine.deinit();
|
|
||||||
await $.RoleInherit.sync();
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -12,6 +12,10 @@ module.exports = Self => {
|
||||||
arg: 'password',
|
arg: 'password',
|
||||||
type: 'string',
|
type: 'string',
|
||||||
description: 'The password'
|
description: 'The password'
|
||||||
|
}, {
|
||||||
|
arg: 'force',
|
||||||
|
type: 'boolean',
|
||||||
|
description: 'Whether to force synchronization'
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
http: {
|
http: {
|
||||||
|
@ -20,8 +24,8 @@ module.exports = Self => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Self.syncById = async function(id, password) {
|
Self.syncById = async function(id, password, force) {
|
||||||
let user = await Self.app.models.Account.findById(id, {fields: ['name']});
|
let user = await Self.app.models.Account.findById(id, {fields: ['name']});
|
||||||
await Self.sync(user.name, password);
|
await Self.sync(user.name, password, force);
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
|
|
||||||
const SyncEngine = require('../../util/sync-engine');
|
|
||||||
|
|
||||||
module.exports = Self => {
|
module.exports = Self => {
|
||||||
Self.remoteMethod('sync', {
|
Self.remoteMethod('sync', {
|
||||||
description: 'Synchronizes the user with the other user databases',
|
description: 'Synchronizes the user with the other user databases',
|
||||||
|
@ -14,6 +12,10 @@ module.exports = Self => {
|
||||||
arg: 'password',
|
arg: 'password',
|
||||||
type: 'string',
|
type: 'string',
|
||||||
description: 'The password'
|
description: 'The password'
|
||||||
|
}, {
|
||||||
|
arg: 'force',
|
||||||
|
type: 'boolean',
|
||||||
|
description: 'Whether to force synchronization'
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
http: {
|
http: {
|
||||||
|
@ -22,7 +24,7 @@ module.exports = Self => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Self.sync = async function(userName, password) {
|
Self.sync = async function(userName, password, force) {
|
||||||
let $ = Self.app.models;
|
let $ = Self.app.models;
|
||||||
|
|
||||||
let user = await $.Account.findOne({
|
let user = await $.Account.findOne({
|
||||||
|
@ -31,21 +33,9 @@ module.exports = Self => {
|
||||||
});
|
});
|
||||||
let isSync = !await $.UserSync.exists(userName);
|
let isSync = !await $.UserSync.exists(userName);
|
||||||
|
|
||||||
if (user && isSync) return;
|
if (!force && isSync && user) return;
|
||||||
|
await $.AccountConfig.syncUser(userName, password);
|
||||||
let err;
|
await $.UserSync.destroyById(userName);
|
||||||
let engine = new SyncEngine();
|
|
||||||
await engine.init($);
|
|
||||||
|
|
||||||
try {
|
|
||||||
await engine.sync(userName, password, true);
|
|
||||||
await $.UserSync.destroyById(userName);
|
|
||||||
} catch (e) {
|
|
||||||
err = e;
|
|
||||||
}
|
|
||||||
|
|
||||||
await engine.deinit();
|
|
||||||
if (err) throw err;
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,78 @@
|
||||||
|
|
||||||
|
const app = require('vn-loopback/server/server');
|
||||||
|
const UserError = require('vn-loopback/util/user-error');
|
||||||
|
|
||||||
|
module.exports = function(Self, options) {
|
||||||
|
require('../methods/account-synchronizer/test')(Self);
|
||||||
|
|
||||||
|
Self.once('attached', function() {
|
||||||
|
app.models.AccountConfig.addSynchronizer(Self);
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mixin for user synchronizers.
|
||||||
|
*
|
||||||
|
* @property {Array<Model>} $
|
||||||
|
* @property {Object} accountConfig
|
||||||
|
* @property {Object} mailConfig
|
||||||
|
*/
|
||||||
|
let Mixin = {
|
||||||
|
/**
|
||||||
|
* Initalizes the synchronizer.
|
||||||
|
*/
|
||||||
|
async init() {},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deinitalizes the synchronizer.
|
||||||
|
*/
|
||||||
|
async deinit() {},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get users to synchronize.
|
||||||
|
*
|
||||||
|
* @param {Set} usersToSync Set where users are added
|
||||||
|
*/
|
||||||
|
async getUsers(usersToSync) {},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Synchronizes a user.
|
||||||
|
*
|
||||||
|
* @param {Object} info User information
|
||||||
|
* @param {String} userName The user name
|
||||||
|
* @param {String} password Thepassword
|
||||||
|
*/
|
||||||
|
async syncUser(info, userName, password) {},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Synchronizes user groups.
|
||||||
|
*
|
||||||
|
* @param {Object} info User information
|
||||||
|
* @param {String} userName The user name
|
||||||
|
*/
|
||||||
|
async syncUserGroups(info, userName) {},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Synchronizes roles.
|
||||||
|
*/
|
||||||
|
async syncRoles() {},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests synchronizer configuration.
|
||||||
|
*/
|
||||||
|
async test() {
|
||||||
|
try {
|
||||||
|
await this.init();
|
||||||
|
await this.deinit();
|
||||||
|
} catch (e) {
|
||||||
|
let err = new UserError(e.message);
|
||||||
|
err.name = e.name;
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
for (let method in Mixin) {
|
||||||
|
if (!Self.prototype[method])
|
||||||
|
Self.prototype[method] = Mixin[method];
|
||||||
|
}
|
||||||
|
};
|
|
@ -29,6 +29,12 @@
|
||||||
"SambaConfig": {
|
"SambaConfig": {
|
||||||
"dataSource": "vn"
|
"dataSource": "vn"
|
||||||
},
|
},
|
||||||
|
"Sip": {
|
||||||
|
"dataSource": "vn"
|
||||||
|
},
|
||||||
|
"SipConfig": {
|
||||||
|
"dataSource": "vn"
|
||||||
|
},
|
||||||
"UserAccount": {
|
"UserAccount": {
|
||||||
"dataSource": "vn"
|
"dataSource": "vn"
|
||||||
},
|
},
|
||||||
|
|
|
@ -0,0 +1,223 @@
|
||||||
|
|
||||||
|
const app = require('vn-loopback/server/server');
|
||||||
|
|
||||||
|
module.exports = Self => {
|
||||||
|
Object.assign(Self, {
|
||||||
|
synchronizers: [],
|
||||||
|
|
||||||
|
addSynchronizer(synchronizer) {
|
||||||
|
this.synchronizers.push(synchronizer);
|
||||||
|
},
|
||||||
|
|
||||||
|
async syncUsers() {
|
||||||
|
let instance = await Self.getInstance();
|
||||||
|
|
||||||
|
let usersToSync = instance.getUsers();
|
||||||
|
usersToSync = Array.from(usersToSync.values())
|
||||||
|
.sort((a, b) => a.localeCompare(b));
|
||||||
|
|
||||||
|
for (let userName of usersToSync) {
|
||||||
|
try {
|
||||||
|
console.log(`Synchronizing user '${userName}'`);
|
||||||
|
await instance.synchronizerSyncUser(userName);
|
||||||
|
console.log(` -> '${userName}' sinchronized`);
|
||||||
|
} catch (err) {
|
||||||
|
console.error(` -> '${userName}' synchronization error:`, err.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await instance.synchronizerDeinit();
|
||||||
|
await Self.syncRoles();
|
||||||
|
},
|
||||||
|
|
||||||
|
async syncUser(userName, password) {
|
||||||
|
let instance = await Self.getInstance();
|
||||||
|
try {
|
||||||
|
await instance.synchronizerSyncUser(userName, password, true);
|
||||||
|
} finally {
|
||||||
|
await instance.synchronizerDeinit();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
async syncRoles() {
|
||||||
|
let instance = await Self.getInstance();
|
||||||
|
try {
|
||||||
|
await instance.synchronizerSyncRoles();
|
||||||
|
} finally {
|
||||||
|
await instance.synchronizerDeinit();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
async getSynchronizer() {
|
||||||
|
return await Self.findOne();
|
||||||
|
},
|
||||||
|
|
||||||
|
async getInstance() {
|
||||||
|
let instance = await Self.findOne({
|
||||||
|
fields: ['homedir', 'shell', 'idBase']
|
||||||
|
});
|
||||||
|
await instance.synchronizerInit();
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Object.assign(Self.prototype, {
|
||||||
|
async synchronizerInit() {
|
||||||
|
let mailConfig = await app.models.MailConfig.findOne({
|
||||||
|
fields: ['domain']
|
||||||
|
});
|
||||||
|
|
||||||
|
let synchronizers = [];
|
||||||
|
|
||||||
|
for (let Synchronizer of Self.synchronizers) {
|
||||||
|
let synchronizer = await Synchronizer.getSynchronizer();
|
||||||
|
if (!synchronizer) continue;
|
||||||
|
Object.assign(synchronizer, {
|
||||||
|
accountConfig: this
|
||||||
|
});
|
||||||
|
await synchronizer.init();
|
||||||
|
synchronizers.push(synchronizer);
|
||||||
|
}
|
||||||
|
|
||||||
|
Object.assign(this, {
|
||||||
|
synchronizers,
|
||||||
|
domain: mailConfig.domain
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
async synchronizerDeinit() {
|
||||||
|
for (let synchronizer of this.synchronizers)
|
||||||
|
await synchronizer.deinit();
|
||||||
|
},
|
||||||
|
|
||||||
|
async synchronizerSyncUser(userName, password, syncGroups) {
|
||||||
|
let $ = app.models;
|
||||||
|
|
||||||
|
if (!userName) return;
|
||||||
|
userName = userName.toLowerCase();
|
||||||
|
|
||||||
|
// Skip conflicting users
|
||||||
|
if (['administrator', 'root'].indexOf(userName) >= 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
let user = await $.Account.findOne({
|
||||||
|
where: {name: userName},
|
||||||
|
fields: [
|
||||||
|
'id',
|
||||||
|
'nickname',
|
||||||
|
'email',
|
||||||
|
'lang',
|
||||||
|
'roleFk',
|
||||||
|
'sync',
|
||||||
|
'active',
|
||||||
|
'created',
|
||||||
|
'bcryptPassword',
|
||||||
|
'updated'
|
||||||
|
],
|
||||||
|
include: {
|
||||||
|
relation: 'roles',
|
||||||
|
scope: {
|
||||||
|
include: {
|
||||||
|
relation: 'inherits',
|
||||||
|
scope: {
|
||||||
|
fields: ['name']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let info = {
|
||||||
|
user,
|
||||||
|
hasAccount: false
|
||||||
|
};
|
||||||
|
|
||||||
|
if (user) {
|
||||||
|
let exists = await $.UserAccount.exists(user.id);
|
||||||
|
Object.assign(info, {
|
||||||
|
hasAccount: user.active && exists,
|
||||||
|
corporateMail: `${userName}@${this.domain}`,
|
||||||
|
uidNumber: this.idBase + user.id
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let errs = [];
|
||||||
|
|
||||||
|
for (let synchronizer of this.synchronizers) {
|
||||||
|
try {
|
||||||
|
await synchronizer.syncUser(userName, info, password);
|
||||||
|
if (syncGroups)
|
||||||
|
await synchronizer.syncUserGroups(userName, info);
|
||||||
|
} catch (err) {
|
||||||
|
errs.push(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (errs.length) throw errs[0];
|
||||||
|
},
|
||||||
|
|
||||||
|
async synchronizerGetUsers() {
|
||||||
|
let usersToSync = new Set();
|
||||||
|
|
||||||
|
for (let synchronizer of this.synchronizers)
|
||||||
|
await synchronizer.getUsers(usersToSync);
|
||||||
|
|
||||||
|
return usersToSync;
|
||||||
|
},
|
||||||
|
|
||||||
|
async synchronizerSyncRoles() {
|
||||||
|
for (let synchronizer of this.synchronizers)
|
||||||
|
await synchronizer.syncRoles();
|
||||||
|
},
|
||||||
|
|
||||||
|
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});
|
||||||
|
},
|
||||||
|
|
||||||
|
async getUsers(usersToSync) {
|
||||||
|
let accounts = await app.models.UserAccount.find({
|
||||||
|
fields: ['id'],
|
||||||
|
include: {
|
||||||
|
relation: 'user',
|
||||||
|
scope: {
|
||||||
|
fields: ['name'],
|
||||||
|
where: {active: true}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
for (let account of accounts) {
|
||||||
|
let user = account.user();
|
||||||
|
if (!user) continue;
|
||||||
|
usersToSync.add(user.name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
|
@ -6,6 +6,9 @@
|
||||||
"table": "account.accountConfig"
|
"table": "account.accountConfig"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"mixins": {
|
||||||
|
"AccountSynchronizer": {}
|
||||||
|
},
|
||||||
"properties": {
|
"properties": {
|
||||||
"id": {
|
"id": {
|
||||||
"type": "number",
|
"type": "number",
|
||||||
|
|
|
@ -0,0 +1,265 @@
|
||||||
|
|
||||||
|
const app = require('vn-loopback/server/server');
|
||||||
|
const ldap = require('../util/ldapjs-extra');
|
||||||
|
const crypto = require('crypto');
|
||||||
|
const nthash = require('smbhash').nthash;
|
||||||
|
|
||||||
|
module.exports = Self => {
|
||||||
|
Self.getSynchronizer = async function() {
|
||||||
|
return await Self.findOne({
|
||||||
|
fields: [
|
||||||
|
'server',
|
||||||
|
'rdn',
|
||||||
|
'password',
|
||||||
|
'userDn',
|
||||||
|
'groupDn'
|
||||||
|
]
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
Object.assign(Self.prototype, {
|
||||||
|
async init() {
|
||||||
|
this.client = ldap.createClient({
|
||||||
|
url: this.server
|
||||||
|
});
|
||||||
|
await this.client.bind(this.rdn, this.password);
|
||||||
|
},
|
||||||
|
|
||||||
|
async deinit() {
|
||||||
|
await this.client.unbind();
|
||||||
|
},
|
||||||
|
|
||||||
|
async syncUser(userName, info, password) {
|
||||||
|
let {
|
||||||
|
client,
|
||||||
|
accountConfig
|
||||||
|
} = this;
|
||||||
|
|
||||||
|
let {user} = info;
|
||||||
|
|
||||||
|
let res = await client.search(this.userDn, {
|
||||||
|
scope: 'sub',
|
||||||
|
attributes: ['userPassword', 'sambaNTPassword'],
|
||||||
|
filter: `&(uid=${userName})`
|
||||||
|
});
|
||||||
|
|
||||||
|
let oldUser;
|
||||||
|
await new Promise((resolve, reject) => {
|
||||||
|
res.on('error', reject);
|
||||||
|
res.on('searchEntry', e => oldUser = e.object);
|
||||||
|
res.on('end', resolve);
|
||||||
|
});
|
||||||
|
|
||||||
|
try {
|
||||||
|
let dn = `uid=${userName},${this.userDn}`;
|
||||||
|
await client.del(dn);
|
||||||
|
} catch (e) {
|
||||||
|
if (e.name !== 'NoSuchObjectError') throw e;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!info.hasAccount) {
|
||||||
|
if (oldUser)
|
||||||
|
console.log(` -> '${userName}' removed from LDAP`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
},
|
||||||
|
|
||||||
|
async syncUserGroups(userName, info) {
|
||||||
|
let {client} = this;
|
||||||
|
|
||||||
|
let res = await client.search(this.groupDn, {
|
||||||
|
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 reqs = [];
|
||||||
|
for (let oldGroup of oldGroups) {
|
||||||
|
let change = new ldap.Change({
|
||||||
|
operation: 'delete',
|
||||||
|
modification: {memberUid: userName}
|
||||||
|
});
|
||||||
|
reqs.push(client.modify(oldGroup.dn, change));
|
||||||
|
}
|
||||||
|
await Promise.all(reqs);
|
||||||
|
|
||||||
|
if (!info.hasAccount) return;
|
||||||
|
|
||||||
|
reqs = [];
|
||||||
|
for (let role of info.user.roles()) {
|
||||||
|
let change = new ldap.Change({
|
||||||
|
operation: 'add',
|
||||||
|
modification: {memberUid: userName}
|
||||||
|
});
|
||||||
|
let roleName = role.inherits().name;
|
||||||
|
let dn = `cn=${roleName},${this.groupDn}`;
|
||||||
|
reqs.push(client.modify(dn, change));
|
||||||
|
}
|
||||||
|
await Promise.all(reqs);
|
||||||
|
},
|
||||||
|
|
||||||
|
async getUsers(usersToSync) {
|
||||||
|
let {client} = this;
|
||||||
|
|
||||||
|
let res = await client.search(this.userDn, {
|
||||||
|
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);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
async syncRoles() {
|
||||||
|
let $ = app.models;
|
||||||
|
let {
|
||||||
|
client,
|
||||||
|
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
|
||||||
|
|
||||||
|
let roles = await $.Role.find({
|
||||||
|
fields: ['id', 'name', 'description']
|
||||||
|
});
|
||||||
|
let roleRoles = await $.RoleRole.find({
|
||||||
|
fields: ['role', 'inheritsFrom']
|
||||||
|
});
|
||||||
|
let roleMap = toMap(roleRoles, e => {
|
||||||
|
return {key: e.inheritsFrom, val: e.role};
|
||||||
|
});
|
||||||
|
|
||||||
|
let accounts = await $.UserAccount.find({
|
||||||
|
fields: ['id'],
|
||||||
|
include: {
|
||||||
|
relation: 'user',
|
||||||
|
scope: {
|
||||||
|
fields: ['name', 'roleFk'],
|
||||||
|
where: {active: true}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
let accountMap = toMap(accounts, e => {
|
||||||
|
let user = e.user();
|
||||||
|
if (!user) return;
|
||||||
|
return {key: user.roleFk, val: user.name};
|
||||||
|
});
|
||||||
|
|
||||||
|
reqs = [];
|
||||||
|
for (let role of roles) {
|
||||||
|
let newEntry = {
|
||||||
|
objectClass: ['top', 'posixGroup'],
|
||||||
|
cn: role.name,
|
||||||
|
description: role.description,
|
||||||
|
gidNumber: accountConfig.idBase + role.id
|
||||||
|
};
|
||||||
|
|
||||||
|
let memberUid = [];
|
||||||
|
for (let subrole of roleMap.get(role.id) || [])
|
||||||
|
memberUid = memberUid.concat(accountMap.get(subrole) || []);
|
||||||
|
|
||||||
|
if (memberUid.length) {
|
||||||
|
memberUid.sort((a, b) => a.localeCompare(b));
|
||||||
|
newEntry.memberUid = memberUid;
|
||||||
|
}
|
||||||
|
|
||||||
|
let dn = `cn=${role.name},${this.groupDn}`;
|
||||||
|
reqs.push(client.add(dn, newEntry));
|
||||||
|
}
|
||||||
|
await Promise.all(reqs);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
|
@ -6,6 +6,9 @@
|
||||||
"table": "account.ldapConfig"
|
"table": "account.ldapConfig"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"mixins": {
|
||||||
|
"AccountSynchronizer": {}
|
||||||
|
},
|
||||||
"properties": {
|
"properties": {
|
||||||
"id": {
|
"id": {
|
||||||
"type": "number",
|
"type": "number",
|
||||||
|
|
|
@ -0,0 +1,128 @@
|
||||||
|
|
||||||
|
const ldap = require('../util/ldapjs-extra');
|
||||||
|
const ssh = require('node-ssh');
|
||||||
|
|
||||||
|
module.exports = Self => {
|
||||||
|
Self.getSynchronizer = async function() {
|
||||||
|
return await Self.findOne({
|
||||||
|
fields: [
|
||||||
|
'host',
|
||||||
|
'adDomain',
|
||||||
|
'adController',
|
||||||
|
'adUser',
|
||||||
|
'adPassword',
|
||||||
|
'verifyCert'
|
||||||
|
]
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
Object.assign(Self.prototype, {
|
||||||
|
async init() {
|
||||||
|
let sshClient = new ssh.NodeSSH();
|
||||||
|
await sshClient.connect({
|
||||||
|
host: this.adController,
|
||||||
|
username: this.adUser,
|
||||||
|
password: this.adPassword
|
||||||
|
});
|
||||||
|
|
||||||
|
let adUser = `cn=${this.adUser},${this.usersDn()}`;
|
||||||
|
|
||||||
|
let adClient = ldap.createClient({
|
||||||
|
url: `ldaps://${this.adController}:636`,
|
||||||
|
tlsOptions: {rejectUnauthorized: this.verifyCert}
|
||||||
|
});
|
||||||
|
await adClient.bind(adUser, this.adPassword);
|
||||||
|
|
||||||
|
Object.assign(this, {
|
||||||
|
sshClient,
|
||||||
|
adClient
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
async deinit() {
|
||||||
|
await this.sshClient.dispose();
|
||||||
|
await this.adClient.unbind();
|
||||||
|
},
|
||||||
|
|
||||||
|
usersDn() {
|
||||||
|
let dnBase = this.adDomain
|
||||||
|
.split('.')
|
||||||
|
.map(part => `dc=${part}`)
|
||||||
|
.join(',');
|
||||||
|
return `cn=Users,${dnBase}`;
|
||||||
|
},
|
||||||
|
|
||||||
|
async syncUser(userName, info, password) {
|
||||||
|
let {sshClient} = this;
|
||||||
|
|
||||||
|
if (info.hasAccount) {
|
||||||
|
try {
|
||||||
|
await sshClient.exec('samba-tool user create', [
|
||||||
|
userName,
|
||||||
|
'--uid-number', `${info.uidNumber}`,
|
||||||
|
'--mail-address', info.corporateMail,
|
||||||
|
'--random-password'
|
||||||
|
]);
|
||||||
|
await sshClient.exec('samba-tool user setexpiry', [
|
||||||
|
userName,
|
||||||
|
'--noexpiry'
|
||||||
|
]);
|
||||||
|
await sshClient.exec('mkhomedir_helper', [
|
||||||
|
userName,
|
||||||
|
'0027'
|
||||||
|
]);
|
||||||
|
} catch (e) {}
|
||||||
|
|
||||||
|
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) {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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();
|
||||||
|
|
||||||
|
let opts = {
|
||||||
|
scope: 'sub',
|
||||||
|
attributes: ['sAMAccountName'],
|
||||||
|
filter: '(&(objectClass=user)(!(userAccountControl:1.2.840.113556.1.4.803:=2)))'
|
||||||
|
};
|
||||||
|
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);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
|
@ -6,20 +6,21 @@
|
||||||
"table": "account.sambaConfig"
|
"table": "account.sambaConfig"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"mixins": {
|
||||||
|
"AccountSynchronizer": {}
|
||||||
|
},
|
||||||
"properties": {
|
"properties": {
|
||||||
"id": {
|
"id": {
|
||||||
"type": "number",
|
"type": "number",
|
||||||
"id": true
|
"id": true
|
||||||
},
|
},
|
||||||
"host": {
|
"adDomain": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"required": true
|
"required": true
|
||||||
},
|
},
|
||||||
"sshUser": {
|
"adController": {
|
||||||
"type": "string"
|
"type": "string",
|
||||||
},
|
"required": true
|
||||||
"sshPassword": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
},
|
||||||
"adUser": {
|
"adUser": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
|
@ -27,8 +28,8 @@
|
||||||
"adPassword": {
|
"adPassword": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"userDn": {
|
"verifyCert": {
|
||||||
"type": "string"
|
"type": "Boolean"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
|
||||||
|
const app = require('vn-loopback/server/server');
|
||||||
|
|
||||||
|
module.exports = Self => {
|
||||||
|
Self.getSynchronizer = async function() {
|
||||||
|
return await Self.findOne({fields: ['id']});
|
||||||
|
};
|
||||||
|
|
||||||
|
Object.assign(Self.prototype, {
|
||||||
|
async syncUser(userName, info, password) {
|
||||||
|
if (!info.hasAccount || !password) return;
|
||||||
|
|
||||||
|
await app.models.Account.rawSql('CALL pbx.sip_setPassword(?, ?)',
|
||||||
|
[info.user.id, password]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
|
@ -0,0 +1,19 @@
|
||||||
|
{
|
||||||
|
"name": "SipConfig",
|
||||||
|
"base": "VnModel",
|
||||||
|
"options": {
|
||||||
|
"mysql": {
|
||||||
|
"table": "pbx.sipConfig"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"mixins": {
|
||||||
|
"AccountSynchronizer": {}
|
||||||
|
},
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"type": "Number",
|
||||||
|
"id": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
|
||||||
module.exports = Self => {
|
module.exports = Self => {
|
||||||
Self.validatesUniquenessOf('extension', {
|
Self.validatesUniquenessOf('extension', {
|
||||||
message: `The extension must be unique`
|
message: `The extension must be unique`
|
|
@ -1,52 +0,0 @@
|
||||||
/**
|
|
||||||
* Base class for user synchronizators.
|
|
||||||
*
|
|
||||||
* @property {Array<Model>} $
|
|
||||||
* @property {Object} accountConfig
|
|
||||||
* @property {Object} mailConfig
|
|
||||||
*/
|
|
||||||
class SyncConnector {
|
|
||||||
/**
|
|
||||||
* Initalizes the connector.
|
|
||||||
*/
|
|
||||||
async init() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get users to synchronize.
|
|
||||||
*
|
|
||||||
* @param {Set} usersToSync Set where users are added
|
|
||||||
*/
|
|
||||||
async getUsers(usersToSync) {}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Synchronizes a user.
|
|
||||||
*
|
|
||||||
* @param {Object} info User information
|
|
||||||
* @param {String} userName The user name
|
|
||||||
* @param {String} password Thepassword
|
|
||||||
*/
|
|
||||||
async sync(info, userName, password) {}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Synchronizes user groups.
|
|
||||||
*
|
|
||||||
* @param {User} user Instace of user
|
|
||||||
* @param {String} userName The user name
|
|
||||||
*/
|
|
||||||
async syncGroups(user, userName) {}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Synchronizes roles.
|
|
||||||
*/
|
|
||||||
async syncRoles() {}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Deinitalizes the connector.
|
|
||||||
*/
|
|
||||||
async deinit() {}
|
|
||||||
}
|
|
||||||
|
|
||||||
SyncConnector.connectors = [];
|
|
||||||
module.exports = SyncConnector;
|
|
|
@ -1,57 +0,0 @@
|
||||||
|
|
||||||
const SyncConnector = require('./sync-connector');
|
|
||||||
|
|
||||||
class SyncDb extends SyncConnector {
|
|
||||||
async sync(info, userName, password) {
|
|
||||||
let {$} = this;
|
|
||||||
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});
|
|
||||||
}
|
|
||||||
|
|
||||||
async getUsers(usersToSync) {
|
|
||||||
let accounts = await this.$.UserAccount.find({
|
|
||||||
fields: ['id'],
|
|
||||||
include: {
|
|
||||||
relation: 'user',
|
|
||||||
scope: {
|
|
||||||
fields: ['name'],
|
|
||||||
where: {active: true}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
for (let account of accounts) {
|
|
||||||
let user = account.user();
|
|
||||||
if (!user) continue;
|
|
||||||
usersToSync.add(user.name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SyncConnector.connectors.push(SyncDb);
|
|
||||||
module.exports = SyncDb;
|
|
|
@ -1,127 +0,0 @@
|
||||||
|
|
||||||
const SyncConnector = require('./sync-connector');
|
|
||||||
require('./sync-db');
|
|
||||||
require('./sync-sip');
|
|
||||||
require('./sync-ldap');
|
|
||||||
require('./sync-samba');
|
|
||||||
|
|
||||||
module.exports = class SyncEngine {
|
|
||||||
async init($) {
|
|
||||||
let accountConfig = await $.AccountConfig.findOne({
|
|
||||||
fields: ['homedir', 'shell', 'idBase']
|
|
||||||
});
|
|
||||||
let mailConfig = await $.MailConfig.findOne({
|
|
||||||
fields: ['domain']
|
|
||||||
});
|
|
||||||
|
|
||||||
let connectors = [];
|
|
||||||
|
|
||||||
for (let ConnectorClass of SyncConnector.connectors) {
|
|
||||||
let connector = new ConnectorClass();
|
|
||||||
Object.assign(connector, {
|
|
||||||
engine: this,
|
|
||||||
$,
|
|
||||||
accountConfig,
|
|
||||||
mailConfig
|
|
||||||
});
|
|
||||||
if (!await connector.init()) continue;
|
|
||||||
connectors.push(connector);
|
|
||||||
}
|
|
||||||
|
|
||||||
Object.assign(this, {
|
|
||||||
connectors,
|
|
||||||
$,
|
|
||||||
accountConfig,
|
|
||||||
mailConfig
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async deinit() {
|
|
||||||
for (let connector of this.connectors)
|
|
||||||
await connector.deinit();
|
|
||||||
}
|
|
||||||
|
|
||||||
async sync(userName, password, syncGroups) {
|
|
||||||
let {
|
|
||||||
$,
|
|
||||||
accountConfig,
|
|
||||||
mailConfig
|
|
||||||
} = this;
|
|
||||||
|
|
||||||
if (!userName) return;
|
|
||||||
userName = userName.toLowerCase();
|
|
||||||
|
|
||||||
// Skip conflicting users
|
|
||||||
if (['administrator', 'root'].indexOf(userName) >= 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
let user = await $.Account.findOne({
|
|
||||||
where: {name: userName},
|
|
||||||
fields: [
|
|
||||||
'id',
|
|
||||||
'nickname',
|
|
||||||
'email',
|
|
||||||
'lang',
|
|
||||||
'roleFk',
|
|
||||||
'sync',
|
|
||||||
'active',
|
|
||||||
'created',
|
|
||||||
'bcryptPassword',
|
|
||||||
'updated'
|
|
||||||
],
|
|
||||||
include: {
|
|
||||||
relation: 'roles',
|
|
||||||
scope: {
|
|
||||||
include: {
|
|
||||||
relation: 'inherits',
|
|
||||||
scope: {
|
|
||||||
fields: ['name']
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
let info = {
|
|
||||||
user,
|
|
||||||
hasAccount: false
|
|
||||||
};
|
|
||||||
|
|
||||||
if (user) {
|
|
||||||
let exists = await $.UserAccount.exists(user.id);
|
|
||||||
Object.assign(info, {
|
|
||||||
hasAccount: user.active && exists,
|
|
||||||
corporateMail: `${userName}@${mailConfig.domain}`,
|
|
||||||
uidNumber: accountConfig.idBase + user.id
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
let errs = [];
|
|
||||||
|
|
||||||
for (let connector of this.connectors) {
|
|
||||||
try {
|
|
||||||
await connector.sync(info, userName, password);
|
|
||||||
if (syncGroups)
|
|
||||||
await connector.syncGroups(info, userName);
|
|
||||||
} catch (err) {
|
|
||||||
errs.push(err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (errs.length) throw errs[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
async syncRoles() {
|
|
||||||
for (let connector of this.connectors)
|
|
||||||
await connector.syncRoles();
|
|
||||||
}
|
|
||||||
|
|
||||||
async getUsers() {
|
|
||||||
let usersToSync = new Set();
|
|
||||||
|
|
||||||
for (let connector of this.connectors)
|
|
||||||
await connector.getUsers(usersToSync);
|
|
||||||
|
|
||||||
return usersToSync;
|
|
||||||
}
|
|
||||||
};
|
|
|
@ -1,292 +0,0 @@
|
||||||
|
|
||||||
const SyncConnector = require('./sync-connector');
|
|
||||||
const nthash = require('smbhash').nthash;
|
|
||||||
const ldap = require('./ldapjs-extra');
|
|
||||||
const crypto = require('crypto');
|
|
||||||
|
|
||||||
class SyncLdap extends SyncConnector {
|
|
||||||
async init() {
|
|
||||||
let ldapConfig = await this.$.LdapConfig.findOne({
|
|
||||||
fields: [
|
|
||||||
'server',
|
|
||||||
'rdn',
|
|
||||||
'password',
|
|
||||||
'userDn',
|
|
||||||
'groupDn'
|
|
||||||
]
|
|
||||||
});
|
|
||||||
if (!ldapConfig) return false;
|
|
||||||
|
|
||||||
let client = ldap.createClient({
|
|
||||||
url: ldapConfig.server
|
|
||||||
});
|
|
||||||
await client.bind(ldapConfig.rdn, ldapConfig.password);
|
|
||||||
|
|
||||||
Object.assign(this, {
|
|
||||||
ldapConfig,
|
|
||||||
client
|
|
||||||
});
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
async deinit() {
|
|
||||||
if (this.client)
|
|
||||||
await this.client.unbind();
|
|
||||||
}
|
|
||||||
|
|
||||||
async sync(info, userName, password) {
|
|
||||||
let {
|
|
||||||
ldapConfig,
|
|
||||||
client,
|
|
||||||
accountConfig
|
|
||||||
} = this;
|
|
||||||
|
|
||||||
let {user} = info;
|
|
||||||
|
|
||||||
let res = await client.search(ldapConfig.userDn, {
|
|
||||||
scope: 'sub',
|
|
||||||
attributes: ['userPassword', 'sambaNTPassword'],
|
|
||||||
filter: `&(uid=${userName})`
|
|
||||||
});
|
|
||||||
|
|
||||||
let oldUser;
|
|
||||||
await new Promise((resolve, reject) => {
|
|
||||||
res.on('error', reject);
|
|
||||||
res.on('searchEntry', e => oldUser = e.object);
|
|
||||||
res.on('end', resolve);
|
|
||||||
});
|
|
||||||
|
|
||||||
try {
|
|
||||||
let dn = `uid=${userName},${ldapConfig.userDn}`;
|
|
||||||
await client.del(dn);
|
|
||||||
} catch (e) {
|
|
||||||
if (e.name !== 'NoSuchObjectError') throw e;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!info.hasAccount) {
|
|
||||||
if (oldUser)
|
|
||||||
console.log(` -> '${userName}' removed from LDAP`);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let nickname = user.nickname || userName;
|
|
||||||
let nameArgs = nickname.trim().split(' ');
|
|
||||||
let sn = nameArgs.length > 1
|
|
||||||
? nameArgs.splice(1).join(' ')
|
|
||||||
: '-';
|
|
||||||
|
|
||||||
let dn = `uid=${userName},${ldapConfig.userDn}`;
|
|
||||||
let newEntry = {
|
|
||||||
uid: userName,
|
|
||||||
objectClass: [
|
|
||||||
'inetOrgPerson',
|
|
||||||
'posixAccount',
|
|
||||||
'sambaSamAccount'
|
|
||||||
],
|
|
||||||
cn: nickname,
|
|
||||||
displayName: nickname,
|
|
||||||
givenName: nameArgs[0],
|
|
||||||
sn,
|
|
||||||
mail: info.corporateMail,
|
|
||||||
preferredLanguage: user.lang,
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
async syncGroups(info, userName) {
|
|
||||||
let {
|
|
||||||
ldapConfig,
|
|
||||||
client
|
|
||||||
} = this;
|
|
||||||
|
|
||||||
let res = await client.search(ldapConfig.groupDn, {
|
|
||||||
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 reqs = [];
|
|
||||||
for (let oldGroup of oldGroups) {
|
|
||||||
let change = new ldap.Change({
|
|
||||||
operation: 'delete',
|
|
||||||
modification: {memberUid: userName}
|
|
||||||
});
|
|
||||||
reqs.push(client.modify(oldGroup.dn, change));
|
|
||||||
}
|
|
||||||
await Promise.all(reqs);
|
|
||||||
|
|
||||||
if (!info.hasAccount) return;
|
|
||||||
|
|
||||||
reqs = [];
|
|
||||||
for (let role of info.user.roles()) {
|
|
||||||
let change = new ldap.Change({
|
|
||||||
operation: 'add',
|
|
||||||
modification: {memberUid: userName}
|
|
||||||
});
|
|
||||||
let roleName = role.inherits().name;
|
|
||||||
let dn = `cn=${roleName},${ldapConfig.groupDn}`;
|
|
||||||
reqs.push(client.modify(dn, change));
|
|
||||||
}
|
|
||||||
await Promise.all(reqs);
|
|
||||||
}
|
|
||||||
|
|
||||||
async getUsers(usersToSync) {
|
|
||||||
let {
|
|
||||||
ldapConfig,
|
|
||||||
client
|
|
||||||
} = this;
|
|
||||||
|
|
||||||
let res = await client.search(ldapConfig.userDn, {
|
|
||||||
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);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async syncRoles() {
|
|
||||||
let {
|
|
||||||
$,
|
|
||||||
ldapConfig,
|
|
||||||
client,
|
|
||||||
accountConfig
|
|
||||||
} = this;
|
|
||||||
|
|
||||||
// Delete roles
|
|
||||||
|
|
||||||
let opts = {
|
|
||||||
scope: 'sub',
|
|
||||||
attributes: ['dn'],
|
|
||||||
filter: 'objectClass=posixGroup'
|
|
||||||
};
|
|
||||||
let res = await client.search(ldapConfig.groupDn, opts);
|
|
||||||
|
|
||||||
let reqs = [];
|
|
||||||
await new Promise((resolve, reject) => {
|
|
||||||
res.on('error', err => {
|
|
||||||
if (err.name === 'NoSuchObjectError')
|
|
||||||
err = new Error(`Object '${ldapConfig.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
|
|
||||||
|
|
||||||
let roles = await $.Role.find({
|
|
||||||
fields: ['id', 'name', 'description']
|
|
||||||
});
|
|
||||||
let roleRoles = await $.RoleRole.find({
|
|
||||||
fields: ['role', 'inheritsFrom']
|
|
||||||
});
|
|
||||||
let roleMap = toMap(roleRoles, e => {
|
|
||||||
return {key: e.inheritsFrom, val: e.role};
|
|
||||||
});
|
|
||||||
|
|
||||||
let accounts = await $.UserAccount.find({
|
|
||||||
fields: ['id'],
|
|
||||||
include: {
|
|
||||||
relation: 'user',
|
|
||||||
scope: {
|
|
||||||
fields: ['name', 'roleFk'],
|
|
||||||
where: {active: true}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
let accountMap = toMap(accounts, e => {
|
|
||||||
let user = e.user();
|
|
||||||
if (!user) return;
|
|
||||||
return {key: user.roleFk, val: user.name};
|
|
||||||
});
|
|
||||||
|
|
||||||
reqs = [];
|
|
||||||
for (let role of roles) {
|
|
||||||
let newEntry = {
|
|
||||||
objectClass: ['top', 'posixGroup'],
|
|
||||||
cn: role.name,
|
|
||||||
description: role.description,
|
|
||||||
gidNumber: accountConfig.idBase + role.id
|
|
||||||
};
|
|
||||||
|
|
||||||
let memberUid = [];
|
|
||||||
for (let subrole of roleMap.get(role.id) || [])
|
|
||||||
memberUid = memberUid.concat(accountMap.get(subrole) || []);
|
|
||||||
|
|
||||||
if (memberUid.length) {
|
|
||||||
memberUid.sort((a, b) => a.localeCompare(b));
|
|
||||||
newEntry.memberUid = memberUid;
|
|
||||||
}
|
|
||||||
|
|
||||||
let dn = `cn=${role.name},${ldapConfig.groupDn}`;
|
|
||||||
reqs.push(client.add(dn, newEntry));
|
|
||||||
}
|
|
||||||
await Promise.all(reqs);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SyncConnector.connectors.push(SyncLdap);
|
|
||||||
module.exports = SyncLdap;
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
|
@ -1,124 +0,0 @@
|
||||||
|
|
||||||
const SyncConnector = require('./sync-connector');
|
|
||||||
const ssh = require('node-ssh');
|
|
||||||
const ldap = require('./ldapjs-extra');
|
|
||||||
|
|
||||||
class SyncSamba extends SyncConnector {
|
|
||||||
async init() {
|
|
||||||
let sambaConfig = await this.$.SambaConfig.findOne({
|
|
||||||
fields: [
|
|
||||||
'host',
|
|
||||||
'sshUser',
|
|
||||||
'sshPassword',
|
|
||||||
'adUser',
|
|
||||||
'adPassword',
|
|
||||||
'userDn'
|
|
||||||
]
|
|
||||||
});
|
|
||||||
if (!sambaConfig) return false;
|
|
||||||
|
|
||||||
let client = new ssh.NodeSSH();
|
|
||||||
await client.connect({
|
|
||||||
host: sambaConfig.host,
|
|
||||||
username: sambaConfig.sshUser,
|
|
||||||
password: sambaConfig.sshPassword
|
|
||||||
});
|
|
||||||
|
|
||||||
let adClient = ldap.createClient({
|
|
||||||
url: `ldaps://${sambaConfig.host}:636`,
|
|
||||||
tlsOptions: {rejectUnauthorized: false}
|
|
||||||
});
|
|
||||||
await adClient.bind(sambaConfig.adUser, sambaConfig.adPassword);
|
|
||||||
|
|
||||||
Object.assign(this, {
|
|
||||||
sambaConfig,
|
|
||||||
client,
|
|
||||||
adClient
|
|
||||||
});
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
async deinit() {
|
|
||||||
if (!this.client) return;
|
|
||||||
await this.client.dispose();
|
|
||||||
await this.adClient.unbind();
|
|
||||||
}
|
|
||||||
|
|
||||||
async sync(info, userName, password) {
|
|
||||||
let {client} = this;
|
|
||||||
|
|
||||||
if (info.hasAccount) {
|
|
||||||
try {
|
|
||||||
await client.exec('samba-tool user create', [
|
|
||||||
userName,
|
|
||||||
'--uid-number', `${info.uidNumber}`,
|
|
||||||
'--mail-address', info.corporateMail,
|
|
||||||
'--random-password'
|
|
||||||
]);
|
|
||||||
await client.exec('samba-tool user setexpiry', [
|
|
||||||
userName,
|
|
||||||
'--noexpiry'
|
|
||||||
]);
|
|
||||||
await client.exec('mkhomedir_helper', [
|
|
||||||
userName,
|
|
||||||
'0027'
|
|
||||||
]);
|
|
||||||
} catch (e) {}
|
|
||||||
|
|
||||||
await client.exec('samba-tool user enable', [
|
|
||||||
userName
|
|
||||||
]);
|
|
||||||
|
|
||||||
if (password) {
|
|
||||||
await client.exec('samba-tool user setpassword', [
|
|
||||||
userName,
|
|
||||||
'--newpassword', password
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
await client.exec('samba-tool user disable', [
|
|
||||||
userName
|
|
||||||
]);
|
|
||||||
console.log(` -> '${userName}' disabled on Samba`);
|
|
||||||
} catch (e) {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets enabled users from Samba.
|
|
||||||
*
|
|
||||||
* 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 {
|
|
||||||
sambaConfig,
|
|
||||||
adClient
|
|
||||||
} = this;
|
|
||||||
|
|
||||||
let opts = {
|
|
||||||
scope: 'sub',
|
|
||||||
attributes: ['sAMAccountName'],
|
|
||||||
filter: '(&(objectClass=user)(!(userAccountControl:1.2.840.113556.1.4.803:=2)))'
|
|
||||||
};
|
|
||||||
let res = await adClient.search(sambaConfig.userDn, opts);
|
|
||||||
|
|
||||||
await new Promise((resolve, reject) => {
|
|
||||||
res.on('error', err => {
|
|
||||||
if (err.name === 'NoSuchObjectError')
|
|
||||||
err = new Error(`Object '${sambaConfig.userDn}' does not exist`);
|
|
||||||
reject(err);
|
|
||||||
});
|
|
||||||
res.on('searchEntry', e => {
|
|
||||||
usersToSync.add(e.object.sAMAccountName);
|
|
||||||
});
|
|
||||||
res.on('end', resolve);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SyncConnector.connectors.push(SyncSamba);
|
|
||||||
module.exports = SyncSamba;
|
|
|
@ -1,15 +0,0 @@
|
||||||
|
|
||||||
const SyncConnector = require('./sync-connector');
|
|
||||||
|
|
||||||
class SyncSip extends SyncConnector {
|
|
||||||
async sync(info, userName, password) {
|
|
||||||
if (!info.hasAccount || !password) return;
|
|
||||||
|
|
||||||
await this.$.Account.rawSql('CALL pbx.sip_setPassword(?, ?)',
|
|
||||||
[info.user.id, password]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SyncConnector.connectors.push(SyncSip);
|
|
||||||
module.exports = SyncSip;
|
|
|
@ -12,7 +12,7 @@
|
||||||
<vn-card class="vn-pa-lg" vn-focus>
|
<vn-card class="vn-pa-lg" vn-focus>
|
||||||
<vn-vertical>
|
<vn-vertical>
|
||||||
<vn-textfield
|
<vn-textfield
|
||||||
label="Homedir"
|
label="Homedir base"
|
||||||
ng-model="$ctrl.config.homedir"
|
ng-model="$ctrl.config.homedir"
|
||||||
rule="AccountConfig">
|
rule="AccountConfig">
|
||||||
</vn-textfield>
|
</vn-textfield>
|
||||||
|
@ -22,7 +22,7 @@
|
||||||
rule="AccountConfig">
|
rule="AccountConfig">
|
||||||
</vn-textfield>
|
</vn-textfield>
|
||||||
<vn-input-number
|
<vn-input-number
|
||||||
label="Id base"
|
label="User and role base id"
|
||||||
ng-model="$ctrl.config.idBase"
|
ng-model="$ctrl.config.idBase"
|
||||||
rule="AccountConfig">
|
rule="AccountConfig">
|
||||||
</vn-input-number>
|
</vn-input-number>
|
||||||
|
@ -58,6 +58,21 @@
|
||||||
ng-if="watcher.dataChanged()"
|
ng-if="watcher.dataChanged()"
|
||||||
ng-click="watcher.loadOriginalData()">
|
ng-click="watcher.loadOriginalData()">
|
||||||
</vn-button>
|
</vn-button>
|
||||||
|
<vn-button
|
||||||
|
ng-if="!watcher.dataChanged()"
|
||||||
|
label="Synchronize all"
|
||||||
|
ng-click="$ctrl.onSynchronizeAll()">
|
||||||
|
</vn-button>
|
||||||
|
<vn-button
|
||||||
|
ng-if="!watcher.dataChanged()"
|
||||||
|
label="Synchronize user"
|
||||||
|
ng-click="syncUser.show()">
|
||||||
|
</vn-button>
|
||||||
|
<vn-button
|
||||||
|
ng-if="!watcher.dataChanged()"
|
||||||
|
label="Synchronize roles"
|
||||||
|
ng-click="$ctrl.onSynchronizeRoles()">
|
||||||
|
</vn-button>
|
||||||
</vn-button-bar>
|
</vn-button-bar>
|
||||||
<vn-submit
|
<vn-submit
|
||||||
icon="save"
|
icon="save"
|
||||||
|
@ -66,3 +81,25 @@
|
||||||
fixed-bottom-right>
|
fixed-bottom-right>
|
||||||
</vn-submit>
|
</vn-submit>
|
||||||
</form>
|
</form>
|
||||||
|
<vn-dialog
|
||||||
|
vn-id="syncUser"
|
||||||
|
on-accept="$ctrl.onUserSync()"
|
||||||
|
on-close="$ctrl.onSyncClose()">
|
||||||
|
<tpl-body>
|
||||||
|
<vn-textfield
|
||||||
|
label="Username"
|
||||||
|
ng-model="$ctrl.syncUser"
|
||||||
|
vn-focus>
|
||||||
|
</vn-textfield>
|
||||||
|
<vn-textfield
|
||||||
|
label="Password"
|
||||||
|
ng-model="$ctrl.syncPassword"
|
||||||
|
type="password"
|
||||||
|
info="If password is not specified, just user attributes are synchronized">
|
||||||
|
</vn-textfield>
|
||||||
|
</tpl-body>
|
||||||
|
<tpl-buttons>
|
||||||
|
<input type="button" response="cancel" translate-attr="{value: 'Cancel'}"/>
|
||||||
|
<button response="accept" translate>Synchronize</button>
|
||||||
|
</tpl-buttons>
|
||||||
|
</vn-dialog>
|
|
@ -0,0 +1,38 @@
|
||||||
|
import ngModule from '../module';
|
||||||
|
import Section from 'salix/components/section';
|
||||||
|
import UserError from 'core/lib/user-error';
|
||||||
|
|
||||||
|
export default class Controller extends Section {
|
||||||
|
onSynchronizeAll() {
|
||||||
|
this.vnApp.showSuccess(this.$t('Synchronizing in the background'));
|
||||||
|
this.$http.patch(`UserAccounts/syncAll`)
|
||||||
|
.then(() => this.vnApp.showSuccess(this.$t('Users synchronized!')));
|
||||||
|
}
|
||||||
|
|
||||||
|
onUserSync() {
|
||||||
|
if (!this.syncUser)
|
||||||
|
throw new UserError('Please enter the username');
|
||||||
|
|
||||||
|
let params = {
|
||||||
|
password: this.syncPassword,
|
||||||
|
force: true
|
||||||
|
};
|
||||||
|
return this.$http.patch(`UserAccounts/${this.syncUser}/sync`, params)
|
||||||
|
.then(() => this.vnApp.showSuccess(this.$t('User synchronized!')));
|
||||||
|
}
|
||||||
|
|
||||||
|
onSynchronizeRoles() {
|
||||||
|
this.$http.patch(`RoleInherits/sync`)
|
||||||
|
.then(() => this.vnApp.showSuccess(this.$t('Roles synchronized!')));
|
||||||
|
}
|
||||||
|
|
||||||
|
onSyncClose() {
|
||||||
|
this.syncUser = '';
|
||||||
|
this.syncPassword = '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ngModule.component('vnAccountAccounts', {
|
||||||
|
template: require('./index.html'),
|
||||||
|
controller: Controller
|
||||||
|
});
|
|
@ -1,16 +1,16 @@
|
||||||
Host: Host
|
Accounts: Cuentas
|
||||||
RDN: RDN
|
Homedir base: Directorio base para carpetas de usuario
|
||||||
Base DN: DN base
|
Shell: Intérprete de línea de comandos
|
||||||
Password should be base64 encoded: La contraseña debe estar codificada en base64
|
User and role base id: Id base usuarios y roles
|
||||||
Filter: Filtro
|
Synchronize all: Sincronizar todo
|
||||||
Group DN: DN grupos
|
|
||||||
Synchronize now: Sincronizar ahora
|
|
||||||
Synchronize user: Sincronizar usuario
|
Synchronize user: Sincronizar usuario
|
||||||
|
Synchronize roles: Sincronizar roles
|
||||||
If password is not specified, just user attributes are synchronized: >-
|
If password is not specified, just user attributes are synchronized: >-
|
||||||
Si la contraseña no se especifica solo se sincronizarán lo atributos del usuario
|
Si la contraseña no se especifica solo se sincronizarán lo atributos del usuario
|
||||||
Synchronizing in the background: Sincronizando en segundo plano
|
Synchronizing in the background: Sincronizando en segundo plano
|
||||||
LDAP users synchronized: Usuarios LDAP sincronizados
|
Users synchronized!: ¡Usuarios sincronizados!
|
||||||
Username: Nombre de usuario
|
Username: Nombre de usuario
|
||||||
Synchronize: Sincronizar
|
Synchronize: Sincronizar
|
||||||
Please enter the username: Por favor introduce el nombre de usuario
|
Please enter the username: Por favor introduce el nombre de usuario
|
||||||
User synchronized: Usuario sincronizado
|
User synchronized!: ¡Usuario sincronizado!
|
||||||
|
Roles synchronized!: ¡Roles sincronizados!
|
|
@ -13,8 +13,5 @@ ngModule.component('vnUserBasicData', {
|
||||||
controller: Controller,
|
controller: Controller,
|
||||||
require: {
|
require: {
|
||||||
card: '^vnUserCard'
|
card: '^vnUserCard'
|
||||||
},
|
|
||||||
bindings: {
|
|
||||||
user: '<'
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -17,4 +17,4 @@ import './aliases';
|
||||||
import './roles';
|
import './roles';
|
||||||
import './ldap';
|
import './ldap';
|
||||||
import './samba';
|
import './samba';
|
||||||
import './posix';
|
import './accounts';
|
||||||
|
|
|
@ -48,21 +48,16 @@
|
||||||
</vn-vertical>
|
</vn-vertical>
|
||||||
</vn-card>
|
</vn-card>
|
||||||
<vn-button-bar>
|
<vn-button-bar>
|
||||||
|
<vn-button
|
||||||
|
disabled="watcher.dataChanged()"
|
||||||
|
label="Test connection"
|
||||||
|
ng-click="$ctrl.onTestConection()">
|
||||||
|
</vn-button>
|
||||||
<vn-button
|
<vn-button
|
||||||
label="Undo changes"
|
label="Undo changes"
|
||||||
ng-if="watcher.dataChanged()"
|
ng-if="watcher.dataChanged()"
|
||||||
ng-click="watcher.loadOriginalData()">
|
ng-click="watcher.loadOriginalData()">
|
||||||
</vn-button>
|
</vn-button>
|
||||||
<vn-button
|
|
||||||
label="Synchronize now"
|
|
||||||
ng-if="watcher.hasData"
|
|
||||||
ng-click="$ctrl.onSynchronizeAll()">
|
|
||||||
</vn-button>
|
|
||||||
<vn-button
|
|
||||||
label="Synchronize user"
|
|
||||||
ng-if="watcher.hasData"
|
|
||||||
ng-click="syncUser.show()">
|
|
||||||
</vn-button>
|
|
||||||
</vn-button-bar>
|
</vn-button-bar>
|
||||||
<vn-submit
|
<vn-submit
|
||||||
icon="save"
|
icon="save"
|
||||||
|
@ -71,25 +66,3 @@
|
||||||
fixed-bottom-right>
|
fixed-bottom-right>
|
||||||
</vn-submit>
|
</vn-submit>
|
||||||
</form>
|
</form>
|
||||||
<vn-dialog
|
|
||||||
vn-id="syncUser"
|
|
||||||
on-accept="$ctrl.onUserSync()"
|
|
||||||
on-close="$ctrl.onPassClose()">
|
|
||||||
<tpl-body>
|
|
||||||
<vn-textfield
|
|
||||||
label="Username"
|
|
||||||
ng-model="$ctrl.syncUser"
|
|
||||||
vn-focus>
|
|
||||||
</vn-textfield>
|
|
||||||
<vn-textfield
|
|
||||||
label="Password"
|
|
||||||
ng-model="$ctrl.syncPassword"
|
|
||||||
type="password"
|
|
||||||
info="If password is not specified, just user attributes are synchronized">
|
|
||||||
</vn-textfield>
|
|
||||||
</tpl-body>
|
|
||||||
<tpl-buttons>
|
|
||||||
<input type="button" response="cancel" translate-attr="{value: 'Cancel'}"/>
|
|
||||||
<button response="accept" translate>Synchronize</button>
|
|
||||||
</tpl-buttons>
|
|
||||||
</vn-dialog>
|
|
||||||
|
|
|
@ -1,26 +1,10 @@
|
||||||
import ngModule from '../module';
|
import ngModule from '../module';
|
||||||
import Section from 'salix/components/section';
|
import Section from 'salix/components/section';
|
||||||
import UserError from 'core/lib/user-error';
|
|
||||||
|
|
||||||
export default class Controller extends Section {
|
export default class Controller extends Section {
|
||||||
onSynchronizeAll() {
|
onTestConection() {
|
||||||
this.vnApp.showSuccess(this.$t('Synchronizing in the background'));
|
this.$http.get(`LdapConfigs/test`)
|
||||||
this.$http.patch(`UserAccounts/syncAll`)
|
.then(() => this.vnApp.showSuccess(this.$t('LDAP connection established!')));
|
||||||
.then(() => this.vnApp.showSuccess(this.$t('Users synchronized!')));
|
|
||||||
}
|
|
||||||
|
|
||||||
onUserSync() {
|
|
||||||
if (!this.syncUser)
|
|
||||||
throw new UserError('Please enter the username');
|
|
||||||
|
|
||||||
let params = {password: this.syncPassword};
|
|
||||||
return this.$http.patch(`UserAccounts/${this.syncUser}/sync`, params)
|
|
||||||
.then(() => this.vnApp.showSuccess(this.$t('User synchronized!')));
|
|
||||||
}
|
|
||||||
|
|
||||||
onSyncClose() {
|
|
||||||
this.syncUser = '';
|
|
||||||
this.syncPassword = '';
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,13 +4,5 @@ RDN: RDN
|
||||||
User DN: DN usuarios
|
User DN: DN usuarios
|
||||||
Filter: Filtro
|
Filter: Filtro
|
||||||
Group DN: DN grupos
|
Group DN: DN grupos
|
||||||
Synchronize now: Sincronizar ahora
|
Test connection: Probar conexión
|
||||||
Synchronize user: Sincronizar usuario
|
LDAP connection established!: ¡Conexión con LDAP establecida!
|
||||||
If password is not specified, just user attributes are synchronized: >-
|
|
||||||
Si la contraseña no se especifica solo se sincronizarán lo atributos del usuario
|
|
||||||
Synchronizing in the background: Sincronizando en segundo plano
|
|
||||||
Users synchronized!: ¡Usuarios sincronizados!
|
|
||||||
Username: Nombre de usuario
|
|
||||||
Synchronize: Sincronizar
|
|
||||||
Please enter the username: Por favor introduce el nombre de usuario
|
|
||||||
User synchronized!: ¡Usuario sincronizado!
|
|
||||||
|
|
|
@ -1,9 +0,0 @@
|
||||||
import ngModule from '../module';
|
|
||||||
import Section from 'salix/components/section';
|
|
||||||
|
|
||||||
export default class Controller extends Section {}
|
|
||||||
|
|
||||||
ngModule.component('vnAccountPosix', {
|
|
||||||
template: require('./index.html'),
|
|
||||||
controller: Controller
|
|
||||||
});
|
|
|
@ -9,7 +9,7 @@
|
||||||
{"state": "account.index", "icon": "face"},
|
{"state": "account.index", "icon": "face"},
|
||||||
{"state": "account.role", "icon": "group"},
|
{"state": "account.role", "icon": "group"},
|
||||||
{"state": "account.alias", "icon": "email"},
|
{"state": "account.alias", "icon": "email"},
|
||||||
{"state": "account.posix", "icon": "accessibility"},
|
{"state": "account.accounts", "icon": "accessibility"},
|
||||||
{"state": "account.ldap", "icon": "account_tree"},
|
{"state": "account.ldap", "icon": "account_tree"},
|
||||||
{"state": "account.samba", "icon": "desktop_windows"},
|
{"state": "account.samba", "icon": "desktop_windows"},
|
||||||
{"state": "account.acl", "icon": "check"},
|
{"state": "account.acl", "icon": "check"},
|
||||||
|
@ -67,34 +67,22 @@
|
||||||
"url": "/basic-data",
|
"url": "/basic-data",
|
||||||
"state": "account.card.basicData",
|
"state": "account.card.basicData",
|
||||||
"component": "vn-user-basic-data",
|
"component": "vn-user-basic-data",
|
||||||
"description": "Basic data",
|
"description": "Basic data"
|
||||||
"params": {
|
|
||||||
"user": "$ctrl.user"
|
|
||||||
}
|
|
||||||
}, {
|
}, {
|
||||||
"url": "/roles",
|
"url": "/roles",
|
||||||
"state": "account.card.roles",
|
"state": "account.card.roles",
|
||||||
"component": "vn-user-roles",
|
"component": "vn-user-roles",
|
||||||
"description": "Inherited roles",
|
"description": "Inherited roles"
|
||||||
"params": {
|
|
||||||
"user": "$ctrl.user"
|
|
||||||
}
|
|
||||||
}, {
|
}, {
|
||||||
"url": "/mail-forwarding",
|
"url": "/mail-forwarding",
|
||||||
"state": "account.card.mailForwarding",
|
"state": "account.card.mailForwarding",
|
||||||
"component": "vn-user-mail-forwarding",
|
"component": "vn-user-mail-forwarding",
|
||||||
"description": "Mail forwarding",
|
"description": "Mail forwarding"
|
||||||
"params": {
|
|
||||||
"user": "$ctrl.user"
|
|
||||||
}
|
|
||||||
}, {
|
}, {
|
||||||
"url": "/aliases",
|
"url": "/aliases",
|
||||||
"state": "account.card.aliases",
|
"state": "account.card.aliases",
|
||||||
"component": "vn-user-aliases",
|
"component": "vn-user-aliases",
|
||||||
"description": "Mail aliases",
|
"description": "Mail aliases"
|
||||||
"params": {
|
|
||||||
"user": "$ctrl.user"
|
|
||||||
}
|
|
||||||
}, {
|
}, {
|
||||||
"url": "/role?q",
|
"url": "/role?q",
|
||||||
"state": "account.role",
|
"state": "account.role",
|
||||||
|
@ -178,10 +166,10 @@
|
||||||
"component": "vn-alias-users",
|
"component": "vn-alias-users",
|
||||||
"description": "Users"
|
"description": "Users"
|
||||||
}, {
|
}, {
|
||||||
"url": "/posix",
|
"url": "/accounts",
|
||||||
"state": "account.posix",
|
"state": "account.accounts",
|
||||||
"component": "vn-account-posix",
|
"component": "vn-account-accounts",
|
||||||
"description": "Posix",
|
"description": "Accounts",
|
||||||
"acl": ["developer"]
|
"acl": ["developer"]
|
||||||
}, {
|
}, {
|
||||||
"url": "/ldap",
|
"url": "/ldap",
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
name="form"
|
name="form"
|
||||||
ng-submit="watcher.submit()"
|
ng-submit="watcher.submit()"
|
||||||
class="vn-w-md">
|
class="vn-w-md">
|
||||||
<vn-card class="vn-pa-lg" vn-focus>
|
<vn-card class="vn-pa-lg" vn-focus>
|
||||||
<vn-vertical>
|
<vn-vertical>
|
||||||
<vn-check
|
<vn-check
|
||||||
label="Enable synchronization"
|
label="Enable synchronization"
|
||||||
|
@ -20,19 +20,13 @@
|
||||||
ng-if="watcher.hasData"
|
ng-if="watcher.hasData"
|
||||||
class="vn-mt-md">
|
class="vn-mt-md">
|
||||||
<vn-textfield
|
<vn-textfield
|
||||||
label="Host"
|
label="AD domain"
|
||||||
ng-model="$ctrl.config.host"
|
ng-model="$ctrl.config.adDomain"
|
||||||
rule="SambaConfig">
|
rule="SambaConfig">
|
||||||
</vn-textfield>
|
</vn-textfield>
|
||||||
<vn-textfield
|
<vn-textfield
|
||||||
label="SSH user"
|
label="Domain controller"
|
||||||
ng-model="$ctrl.config.sshUser"
|
ng-model="$ctrl.config.adController"
|
||||||
rule="SambaConfig">
|
|
||||||
</vn-textfield>
|
|
||||||
<vn-textfield
|
|
||||||
label="SSH password"
|
|
||||||
ng-model="$ctrl.config.sshPassword"
|
|
||||||
type="password"
|
|
||||||
rule="SambaConfig">
|
rule="SambaConfig">
|
||||||
</vn-textfield>
|
</vn-textfield>
|
||||||
<vn-textfield
|
<vn-textfield
|
||||||
|
@ -46,14 +40,18 @@
|
||||||
type="password"
|
type="password"
|
||||||
rule="SambaConfig">
|
rule="SambaConfig">
|
||||||
</vn-textfield>
|
</vn-textfield>
|
||||||
<vn-textfield
|
<vn-check
|
||||||
label="User DN"
|
label="Verify certificate"
|
||||||
ng-model="$ctrl.config.userDn"
|
ng-model="$ctrl.config.verifyCert">
|
||||||
rule="SambaConfig">
|
</vn-check>
|
||||||
</vn-textfield>
|
|
||||||
</vn-vertical>
|
</vn-vertical>
|
||||||
</vn-card>
|
</vn-card>
|
||||||
<vn-button-bar>
|
<vn-button-bar>
|
||||||
|
<vn-button
|
||||||
|
disabled="watcher.dataChanged()"
|
||||||
|
label="Test connection"
|
||||||
|
ng-click="$ctrl.onTestConection()">
|
||||||
|
</vn-button>
|
||||||
<vn-button
|
<vn-button
|
||||||
label="Undo changes"
|
label="Undo changes"
|
||||||
ng-if="watcher.dataChanged()"
|
ng-if="watcher.dataChanged()"
|
||||||
|
|
|
@ -1,7 +1,12 @@
|
||||||
import ngModule from '../module';
|
import ngModule from '../module';
|
||||||
import Section from 'salix/components/section';
|
import Section from 'salix/components/section';
|
||||||
|
|
||||||
export default class Controller extends Section {}
|
export default class Controller extends Section {
|
||||||
|
onTestConection() {
|
||||||
|
this.$http.get(`SambaConfigs/test`)
|
||||||
|
.then(() => this.vnApp.showSuccess(this.$t('Samba connection established!')));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ngModule.component('vnAccountSamba', {
|
ngModule.component('vnAccountSamba', {
|
||||||
template: require('./index.html'),
|
template: require('./index.html'),
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
Enable synchronization: Habilitar sincronización
|
Enable synchronization: Habilitar sincronización
|
||||||
Host: Host
|
Domain controller: Controlador de dominio
|
||||||
SSH user: Usuario SSH
|
AD domain: Dominio AD
|
||||||
SSH password: Contraseña SSH
|
|
||||||
AD user: Usuario AD
|
AD user: Usuario AD
|
||||||
AD password: Contraseña AD
|
AD password: Contraseña AD
|
||||||
User DN: DN usuarios
|
Verify certificate: Verificar certificado
|
||||||
|
Test connection: Probar conexión
|
||||||
|
Samba connection established!: ¡Conexión con Samba establecida!
|
||||||
|
|
|
@ -30,10 +30,10 @@
|
||||||
<vn-thead>
|
<vn-thead>
|
||||||
<vn-tr>
|
<vn-tr>
|
||||||
<vn-th expand>Date</vn-th>
|
<vn-th expand>Date</vn-th>
|
||||||
<vn-th number order="DESC">Id</vn-th>
|
<vn-th number order="DESC" shrink>Id</vn-th>
|
||||||
<vn-th>State</vn-th>
|
<vn-th>State</vn-th>
|
||||||
<vn-th>Reference</vn-th>
|
<vn-th>Reference</vn-th>
|
||||||
<vn-th>Client</vn-th>
|
<vn-th expand>Client</vn-th>
|
||||||
<vn-th number>In</vn-th>
|
<vn-th number>In</vn-th>
|
||||||
<vn-th number>Out</vn-th>
|
<vn-th number>Out</vn-th>
|
||||||
<vn-th number>Balance</vn-th>
|
<vn-th number>Balance</vn-th>
|
||||||
|
@ -54,7 +54,7 @@
|
||||||
{{::sale.shipped | date:'dd/MM/yyyy' }}
|
{{::sale.shipped | date:'dd/MM/yyyy' }}
|
||||||
</span>
|
</span>
|
||||||
</vn-td>
|
</vn-td>
|
||||||
<vn-td number>
|
<vn-td number shrink>
|
||||||
<span class="link"
|
<span class="link"
|
||||||
ng-click="$ctrl.showDescriptor($event, sale)"
|
ng-click="$ctrl.showDescriptor($event, sale)"
|
||||||
name="origin">
|
name="origin">
|
||||||
|
@ -63,7 +63,7 @@
|
||||||
</vn-td>
|
</vn-td>
|
||||||
<vn-td>{{::sale.stateName | dashIfEmpty}}</vn-td>
|
<vn-td>{{::sale.stateName | dashIfEmpty}}</vn-td>
|
||||||
<vn-td>{{::sale.reference | dashIfEmpty}}</vn-td>
|
<vn-td>{{::sale.reference | dashIfEmpty}}</vn-td>
|
||||||
<vn-td class="truncate">
|
<vn-td class="truncate" expand>
|
||||||
<span ng-if="::!sale.isTicket">
|
<span ng-if="::!sale.isTicket">
|
||||||
{{::sale.name | dashIfEmpty}}
|
{{::sale.name | dashIfEmpty}}
|
||||||
</span>
|
</span>
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue