3553-fix(travel_summary): vn-check change value to ng-model #862
|
@ -137,7 +137,8 @@ module.exports = class Docker {
|
||||||
user: this.dbConf.username,
|
user: this.dbConf.username,
|
||||||
password: this.dbConf.password,
|
password: this.dbConf.password,
|
||||||
host: this.dbConf.host,
|
host: this.dbConf.host,
|
||||||
port: this.dbConf.port
|
port: this.dbConf.port,
|
||||||
|
connectTimeout: maxInterval
|
||||||
};
|
};
|
||||||
|
|
||||||
log('Waiting for MySQL init process...');
|
log('Waiting for MySQL init process...');
|
||||||
|
|
|
@ -20,6 +20,9 @@
|
||||||
"MailForward": {
|
"MailForward": {
|
||||||
"dataSource": "vn"
|
"dataSource": "vn"
|
||||||
},
|
},
|
||||||
|
"RoleConfig": {
|
||||||
|
"dataSource": "vn"
|
||||||
|
},
|
||||||
"RoleInherit": {
|
"RoleInherit": {
|
||||||
"dataSource": "vn"
|
"dataSource": "vn"
|
||||||
},
|
},
|
||||||
|
|
|
@ -114,17 +114,22 @@ module.exports = Self => {
|
||||||
'bcryptPassword',
|
'bcryptPassword',
|
||||||
'updated'
|
'updated'
|
||||||
],
|
],
|
||||||
include: {
|
include: [
|
||||||
relation: 'roles',
|
{
|
||||||
scope: {
|
relation: 'roles',
|
||||||
include: {
|
scope: {
|
||||||
relation: 'inherits',
|
include: {
|
||||||
scope: {
|
relation: 'inherits',
|
||||||
fields: ['name']
|
scope: {
|
||||||
|
fields: ['name']
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}, {
|
||||||
|
relation: 'role',
|
||||||
|
fields: ['name']
|
||||||
}
|
}
|
||||||
}
|
]
|
||||||
});
|
});
|
||||||
|
|
||||||
let info = {
|
let info = {
|
||||||
|
|
|
@ -0,0 +1,103 @@
|
||||||
|
|
||||||
|
module.exports = Self => {
|
||||||
|
Self.getSynchronizer = async function() {
|
||||||
|
return await Self.findOne({fields: ['id']});
|
||||||
|
};
|
||||||
|
|
||||||
|
Object.assign(Self.prototype, {
|
||||||
|
async init() {
|
||||||
|
const [row] = await Self.rawSql('SELECT VERSION() AS `version`');
|
||||||
|
if (row.version.includes('MariaDB'))
|
||||||
|
this.dbType = 'MariaDB';
|
||||||
|
else
|
||||||
|
this.dbType = 'MySQL';
|
||||||
|
},
|
||||||
|
|
||||||
|
async syncUser(userName, info, password) {
|
||||||
|
const mysqlHost = '%';
|
||||||
|
|
||||||
|
let mysqlUser = userName;
|
||||||
|
if (this.dbType == 'MySQL') mysqlUser = `!${mysqlUser}`;
|
||||||
|
|
||||||
|
const [row] = await Self.rawSql(
|
||||||
|
`SELECT COUNT(*) AS nRows
|
||||||
|
FROM mysql.user
|
||||||
|
WHERE User = ?
|
||||||
|
AND Host = ?`,
|
||||||
|
[mysqlUser, mysqlHost]
|
||||||
|
);
|
||||||
|
let userExists = row.nRows > 0;
|
||||||
|
|
||||||
|
let isUpdatable = true;
|
||||||
|
if (this.dbType == 'MariaDB') {
|
||||||
|
const [row] = await Self.rawSql(
|
||||||
|
`SELECT Priv AS priv
|
||||||
|
FROM mysql.global_priv
|
||||||
|
WHERE User = ?
|
||||||
|
AND Host = ?`,
|
||||||
|
[mysqlUser, mysqlHost]
|
||||||
|
);
|
||||||
|
const priv = row && JSON.parse(row.priv);
|
||||||
|
const role = priv && priv.default_role;
|
||||||
|
isUpdatable = !row || (role && role.startsWith('z-'));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isUpdatable) {
|
||||||
|
console.warn(`RoleConfig.syncUser(): User '${userName}' cannot be updated, not managed by me`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (info.hasAccount) {
|
||||||
|
if (password) {
|
||||||
|
if (!userExists) {
|
||||||
|
await Self.rawSql('CREATE USER ?@? IDENTIFIED BY ?',
|
||||||
|
[mysqlUser, mysqlHost, password]
|
||||||
|
);
|
||||||
|
userExists = true;
|
||||||
|
} else {
|
||||||
|
switch (this.dbType) {
|
||||||
|
case 'MariaDB':
|
||||||
|
await Self.rawSql('ALTER USER ?@? IDENTIFIED BY ?',
|
||||||
|
[mysqlUser, mysqlHost, password]
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
await Self.rawSql('SET PASSWORD FOR ?@? = PASSWORD(?)',
|
||||||
|
[mysqlUser, mysqlHost, password]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (userExists && this.dbType == 'MariaDB') {
|
||||||
|
let role = `z-${info.user.role().name}`;
|
||||||
|
|
||||||
|
try {
|
||||||
|
await Self.rawSql('REVOKE ALL, GRANT OPTION FROM ?@?',
|
||||||
|
[mysqlUser, mysqlHost]
|
||||||
|
);
|
||||||
|
} catch (err) {
|
||||||
|
if (err.code == 'ER_REVOKE_GRANTS')
|
||||||
|
console.warn(`${err.code}: ${err.sqlMessage}: ${err.sql}`);
|
||||||
|
else
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
await Self.rawSql('GRANT ? TO ?@?',
|
||||||
|
[role, mysqlUser, mysqlHost]
|
||||||
|
);
|
||||||
|
|
||||||
|
if (role) {
|
||||||
|
await Self.rawSql('SET DEFAULT ROLE ? FOR ?@?',
|
||||||
|
[role, mysqlUser, mysqlHost]
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
await Self.rawSql('SET DEFAULT ROLE NONE FOR ?@?',
|
||||||
|
[mysqlUser, mysqlHost]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (userExists)
|
||||||
|
await Self.rawSql('DROP USER ?@?', [mysqlUser, mysqlHost]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
|
@ -0,0 +1,21 @@
|
||||||
|
{
|
||||||
|
"name": "RoleConfig",
|
||||||
|
"base": "VnModel",
|
||||||
|
"options": {
|
||||||
|
"mysql": {
|
||||||
|
"table": "account.roleConfig"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"mixins": {
|
||||||
|
"AccountSynchronizer": {}
|
||||||
|
},
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"type": "number",
|
||||||
|
"id": true
|
||||||
|
},
|
||||||
|
"mysqlPassword": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -10,64 +10,68 @@ module.exports = Self => {
|
||||||
accepts: [
|
accepts: [
|
||||||
{
|
{
|
||||||
arg: 'filter',
|
arg: 'filter',
|
||||||
type: 'Object',
|
type: 'object',
|
||||||
description: 'Filter defining where, order, offset, and limit - must be a JSON-encoded string',
|
description: 'Filter defining where, order, offset, and limit - must be a JSON-encoded string',
|
||||||
http: {source: 'query'}
|
http: {source: 'query'}
|
||||||
}, {
|
}, {
|
||||||
arg: 'search',
|
arg: 'search',
|
||||||
type: 'String',
|
type: 'string',
|
||||||
description: 'Searchs the travel by id',
|
description: 'Searchs the travel by id',
|
||||||
http: {source: 'query'}
|
http: {source: 'query'}
|
||||||
}, {
|
}, {
|
||||||
arg: 'id',
|
arg: 'id',
|
||||||
type: 'Integer',
|
type: 'integer',
|
||||||
description: 'The travel id',
|
description: 'The travel id',
|
||||||
http: {source: 'query'}
|
http: {source: 'query'}
|
||||||
}, {
|
}, {
|
||||||
arg: 'shippedFrom',
|
arg: 'shippedFrom',
|
||||||
type: 'Date',
|
type: 'date',
|
||||||
description: 'The shipped from date filter',
|
description: 'The shipped from date filter',
|
||||||
http: {source: 'query'}
|
http: {source: 'query'}
|
||||||
}, {
|
}, {
|
||||||
arg: 'shippedTo',
|
arg: 'shippedTo',
|
||||||
type: 'Date',
|
type: 'date',
|
||||||
description: 'The shipped to date filter',
|
description: 'The shipped to date filter',
|
||||||
http: {source: 'query'}
|
http: {source: 'query'}
|
||||||
}, {
|
}, {
|
||||||
arg: 'landedFrom',
|
arg: 'landedFrom',
|
||||||
type: 'Date',
|
type: 'date',
|
||||||
description: 'The landed from date filter',
|
description: 'The landed from date filter',
|
||||||
http: {source: 'query'}
|
http: {source: 'query'}
|
||||||
}, {
|
}, {
|
||||||
arg: 'landedTo',
|
arg: 'landedTo',
|
||||||
type: 'Date',
|
type: 'date',
|
||||||
description: 'The landed to date filter',
|
description: 'The landed to date filter',
|
||||||
http: {source: 'query'}
|
http: {source: 'query'}
|
||||||
}, {
|
}, {
|
||||||
arg: 'agencyFk',
|
arg: 'agencyFk',
|
||||||
type: 'Number',
|
type: 'number',
|
||||||
description: 'The agencyModeFk id',
|
description: 'The agencyModeFk id',
|
||||||
http: {source: 'query'}
|
http: {source: 'query'}
|
||||||
}, {
|
}, {
|
||||||
arg: 'warehouseOutFk',
|
arg: 'warehouseOutFk',
|
||||||
type: 'Number',
|
type: 'number',
|
||||||
description: 'The warehouseOutFk filter',
|
description: 'The warehouseOutFk filter',
|
||||||
http: {source: 'query'}
|
http: {source: 'query'}
|
||||||
}, {
|
}, {
|
||||||
arg: 'warehouseInFk',
|
arg: 'warehouseInFk',
|
||||||
type: 'Number',
|
type: 'number',
|
||||||
description: 'The warehouseInFk filter',
|
description: 'The warehouseInFk filter',
|
||||||
http: {source: 'query'}
|
http: {source: 'query'}
|
||||||
}, {
|
}, {
|
||||||
arg: 'totalEntries',
|
arg: 'totalEntries',
|
||||||
type: 'Number',
|
type: 'number',
|
||||||
description: 'The totalEntries filter',
|
description: 'The totalEntries filter',
|
||||||
http: {source: 'query'}
|
http: {source: 'query'}
|
||||||
}, {
|
}, {
|
||||||
arg: 'ref',
|
arg: 'ref',
|
||||||
type: 'string',
|
type: 'string',
|
||||||
description: 'The reference'
|
description: 'The reference'
|
||||||
}
|
}, {
|
||||||
|
arg: 'continent',
|
||||||
|
type: 'string',
|
||||||
|
description: 'The continent code'
|
||||||
|
},
|
||||||
],
|
],
|
||||||
returns: {
|
returns: {
|
||||||
type: ['Object'],
|
type: ['Object'],
|
||||||
|
@ -102,6 +106,7 @@ module.exports = Self => {
|
||||||
case 'warehouseOutFk':
|
case 'warehouseOutFk':
|
||||||
case 'warehouseInFk':
|
case 'warehouseInFk':
|
||||||
case 'totalEntries':
|
case 'totalEntries':
|
||||||
|
case 'continent':
|
||||||
param = `t.${param}`;
|
param = `t.${param}`;
|
||||||
return {[param]: value};
|
return {[param]: value};
|
||||||
}
|
}
|
||||||
|
@ -129,11 +134,15 @@ module.exports = Self => {
|
||||||
t.totalEntries,
|
t.totalEntries,
|
||||||
am.name agencyModeName,
|
am.name agencyModeName,
|
||||||
win.name warehouseInName,
|
win.name warehouseInName,
|
||||||
wout.name warehouseOutName
|
wout.name warehouseOutName,
|
||||||
|
cnt.code continent
|
||||||
FROM vn.travel t
|
FROM vn.travel t
|
||||||
JOIN vn.agencyMode am ON am.id = t.agencyFk
|
JOIN vn.agencyMode am ON am.id = t.agencyFk
|
||||||
JOIN vn.warehouse win ON win.id = t.warehouseInFk
|
JOIN vn.warehouse win ON win.id = t.warehouseInFk
|
||||||
JOIN vn.warehouse wout ON wout.id = t.warehouseOutFk) AS t`
|
JOIN vn.warehouse wout ON wout.id = t.warehouseOutFk
|
||||||
|
JOIN warehouse wo ON wo.id = t.warehouseOutFk
|
||||||
|
JOIN country c ON c.id = wo.countryFk
|
||||||
|
LEFT JOIN continent cnt ON cnt.id = c.continentFk) AS t`
|
||||||
);
|
);
|
||||||
|
|
||||||
stmt.merge(conn.makeSuffix(filter));
|
stmt.merge(conn.makeSuffix(filter));
|
||||||
|
|
|
@ -70,4 +70,16 @@ describe('Travel filter()', () => {
|
||||||
|
|
||||||
expect(result.length).toEqual(1);
|
expect(result.length).toEqual(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should return the travel matching "continent"', async() => {
|
||||||
|
const ctx = {
|
||||||
|
args: {
|
||||||
|
continent: 'EU',
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = await app.models.Travel.filter(ctx);
|
||||||
|
|
||||||
|
expect(result.length).toEqual(5);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -93,6 +93,15 @@
|
||||||
value-field="id">
|
value-field="id">
|
||||||
</vn-autocomplete>
|
</vn-autocomplete>
|
||||||
</vn-horizontal>
|
</vn-horizontal>
|
||||||
|
<vn-horizontal class="vn-px-lg">
|
||||||
|
<vn-autocomplete vn-one
|
||||||
|
label="Continent Out"
|
||||||
|
ng-model="filter.continent"
|
||||||
|
url="Continents"
|
||||||
|
show-field="name"
|
||||||
|
value-field="code">
|
||||||
|
</vn-autocomplete>
|
||||||
|
</vn-horizontal>
|
||||||
<vn-horizontal class="vn-px-lg vn-pb-lg vn-mt-lg">
|
<vn-horizontal class="vn-px-lg vn-pb-lg vn-mt-lg">
|
||||||
<vn-submit label="Search"></vn-submit>
|
<vn-submit label="Search"></vn-submit>
|
||||||
</vn-horizontal>
|
</vn-horizontal>
|
||||||
|
|
Loading…
Reference in New Issue