#3806 Salix backend
gitea/hedera-web/pipeline/head This commit looks good Details

This commit is contained in:
Juan Ferrer 2022-05-05 15:56:17 +02:00
parent f5e1b11df9
commit aa4d1edd32
27 changed files with 389 additions and 635 deletions

43
app.js
View File

@ -1,25 +1,12 @@
__webpack_public_path__ = _PUBLIC_PATH;
var assetsPath;
if (_DEV_MODE)
{
var host = window.location.host.split(':')[0];
assetsPath = 'http://'+ host +':'+ _DEV_SERVER_PORT +'/'+ _PUBLIC_PATH;
}
else
assetsPath = _PUBLIC_PATH;
__webpack_public_path__ = assetsPath;
require('hedera/hedera'); require('hedera/hedera');
window.onload = function () window.onload = function() {
{
loadLocale(main); loadLocale(main);
} }
function main (req) function main(req) {
{
if (req) if (req)
onLocaleLoad(req); onLocaleLoad(req);
@ -27,43 +14,45 @@ function main (req)
hederaWeb.run(); hederaWeb.run();
} }
function loadLocale (cb) function loadLocale(cb) {
{
Vn.Locale.init(); Vn.Locale.init();
var lang = Vn.Locale.language; var lang = Vn.Locale.language;
var req = require.context('js', true, /locale\/en.yml$/); var req = require.context('js', true, /locale\/en.yml$/);
onLocaleLoad(req); onLocaleLoad(req);
switch (lang) switch (lang) {
{
case 'ca': case 'ca':
require([], function() { require([], function() {
cb (require.context ('js', true, /locale\/ca.yml$/)); }); cb(require.context('js', true, /locale\/ca.yml$/));
});
break; break;
case 'es': case 'es':
require([], function() { require([], function() {
cb (require.context ('js', true, /locale\/es.yml$/)); }); cb(require.context('js', true, /locale\/es.yml$/));
});
break; break;
case 'fr': case 'fr':
require([], function() { require([], function() {
cb (require.context ('js', true, /locale\/fr.yml$/)); }); cb(require.context('js', true, /locale\/fr.yml$/));
});
break; break;
case 'mn': case 'mn':
require([], function() { require([], function() {
cb (require.context ('js', true, /locale\/mn.yml$/)); }); cb(require.context('js', true, /locale\/mn.yml$/));
});
break; break;
case 'pt': case 'pt':
require([], function() { require([], function() {
cb (require.context ('js', true, /locale\/pt.yml$/)); }); cb(require.context('js', true, /locale\/pt.yml$/));
});
break; break;
default: default:
cb(); cb();
} }
} }
function onLocaleLoad (req) function onLocaleLoad(req) {
{
var keys = req.keys(); var keys = req.keys();
for (var i = 0; i < keys.length; i++) for (var i = 0; i < keys.length; i++)

View File

@ -5,8 +5,6 @@ Hedera.Conf = new Class({
,activate: function() { ,activate: function() {
this.$('user-model').setInfo('c', 'myClient', 'hedera'); this.$('user-model').setInfo('c', 'myClient', 'hedera');
console.log(this.hash.get('verificationToken'));
if (this.hash.get('verificationToken')) if (this.hash.get('verificationToken'))
this.onPassChangeClick(); this.onPassChangeClick();
} }
@ -45,9 +43,12 @@ Hedera.Conf = new Class({
this.conn.send('core/restore-password', params, this.conn.send('core/restore-password', params,
this._onPassChange.bind(this)); this._onPassChange.bind(this));
} else { } else {
let userId = this.gui.user.id;
params.oldPassword = oldPassword; params.oldPassword = oldPassword;
this.conn.send('core/change-password', params, this.conn.lbSend('PATCH',
this._onPassChange.bind(this)); `Accounts/${userId}/changePassword`, params,
this._onPassChange.bind(this)
);
} }
} catch (e) { } catch (e) {
Htk.Toast.showError(e.message); Htk.Toast.showError(e.message);
@ -55,7 +56,7 @@ Hedera.Conf = new Class({
} }
,_onPassChange: function(json, error) { ,_onPassChange: function(json, error) {
if (json) { if (!error) {
this.$('change-password').hide(); this.$('change-password').hide();
this.hash.unset('verificationToken'); this.hash.unset('verificationToken');
Htk.Toast.showMessage(_('Password changed!')); Htk.Toast.showMessage(_('Password changed!'));

View File

@ -1,12 +1,10 @@
Hedera.Connections = new Class Hedera.Connections = new Class({
({
Extends: Hedera.Form Extends: Hedera.Form
,_timeoutId: null ,_timeoutId: null
,onModelStatusChange: function (model, status) ,onModelStatusChange: function(model) {
{
if (!model.ready) if (!model.ready)
return; return;
@ -16,37 +14,31 @@ Hedera.Connections = new Class
this._timeoutId = setTimeout(this.onRefreshClick.bind(this), 60000); this._timeoutId = setTimeout(this.onRefreshClick.bind(this), 60000);
} }
,deactivate: function () ,deactivate: function() {
{
clearTimeout(this._timeoutId); clearTimeout(this._timeoutId);
} }
,onRefreshClick: function () ,onRefreshClick: function() {
{
this.$('sessions').refresh(); this.$('sessions').refresh();
} }
,onAccessLogClick: function (button, form) ,onAccessLogClick: function(button, form) {
{
this.hash.set({ this.hash.set({
'form': 'admin/access-log' form: 'admin/access-log'
,'user': form.get ('userId') ,user: form.get('userId')
}); });
} }
,onChangeUserClick: function (button, form) ,onChangeUserClick: function(button, form) {
{
this.gui.supplantUser(form.get('user'), this.gui.supplantUser(form.get('user'),
this._onUserSupplant.bind(this)); this._onUserSupplant.bind(this));
} }
,_onUserSupplant: function (userName) ,_onUserSupplant: function() {
{ this.hash.set({form: 'ecomerce/orders'});
this.hash.set ({'form': 'ecomerce/orders'});
} }
,sessionsFunc: function () ,sessionsFunc: function() {
{
return 1; return 1;
} }
}); });

View File

@ -1,18 +1,15 @@
Hedera.Users = new Class Hedera.Users = new Class({
({
Extends: Hedera.Form Extends: Hedera.Form
,onAccessLogClick: function (button, form) ,onAccessLogClick: function(button, form) {
{
this.hash.set({ this.hash.set({
'form': 'admin/access-log' 'form': 'admin/access-log'
,'user': form.get('id') ,'user': form.get('id')
}); });
} }
,rendererFunc: function (scope, form) ,rendererFunc: function(scope, form) {
{
var isEnabled = form.get('active') var isEnabled = form.get('active')
scope.$('disabled').style.display = isEnabled ? scope.$('disabled').style.display = isEnabled ?
'none' : 'block'; 'none' : 'block';
@ -20,14 +17,12 @@ Hedera.Users = new Class
'block' : 'none'; 'block' : 'none';
} }
,onChangeUserClick: function (button, form) ,onChangeUserClick: function(button, form) {
{
this.gui.supplantUser(form.get('name'), this.gui.supplantUser(form.get('name'),
this.onUserSupplant.bind(this)); this.onUserSupplant.bind(this));
} }
,onUserSupplant: function () ,onUserSupplant: function() {
{
this.hash.set({form: 'ecomerce/orders'}); this.hash.set({form: 'ecomerce/orders'});
} }
}); });

View File

@ -19,9 +19,13 @@ Hedera.Ticket = new Class({
}, },
onPrintClick: function() { onPrintClick: function() {
var batch = new Sql.Batch(); let params = Vn.Url.makeUri({
batch.addValue('ticket', this.$('ticket-id').value); authorization: this.conn.token,
this.gui.openReport('delivery-note', batch); ticketId: this.$('ticket-id').value,
recipientId: this.gui.user.id,
type: 'deliveryNote'
});
window.open(`/api/report/delivery-note?${params}`);
}, },
repeaterFunc: function(res, form) { repeaterFunc: function(res, form) {

View File

@ -4,16 +4,14 @@ var Result = require ('./result');
/** /**
* This class stores the database results. * This class stores the database results.
**/ **/
module.exports = new Class module.exports = new Class({
({
results: null results: null
,error: null ,error: null
/** /**
* Initilizes the resultset object. * Initilizes the resultset object.
**/ **/
,initialize: function (results, error) ,initialize: function(results, error) {
{
this.results = results; this.results = results;
this.error = error; this.error = error;
} }
@ -23,13 +21,11 @@ module.exports = new Class
* *
* @return {Db.Err} the error or null if no errors hapened * @return {Db.Err} the error or null if no errors hapened
**/ **/
,getError: function () ,getError: function() {
{
return this.error; return this.error;
} }
,fetch: function () ,fetch: function() {
{
if (this.error) if (this.error)
throw this.error; throw this.error;
@ -45,12 +41,10 @@ module.exports = new Class
* *
* @return {Db.Result} the result or %null if error or there are no more results * @return {Db.Result} the result or %null if error or there are no more results
**/ **/
,fetchResult: function () ,fetchResult: function() {
{
var result = this.fetch(); var result = this.fetch();
if (result !== null) if (result !== null) {
{
if (result.data instanceof Array) if (result.data instanceof Array)
return new Result(result); return new Result(result);
else else
@ -65,8 +59,7 @@ module.exports = new Class
* *
* @return {Array} the row if success, %null otherwise * @return {Array} the row if success, %null otherwise
**/ **/
,fetchRow: function () ,fetchRow: function() {
{
var result = this.fetch(); var result = this.fetch();
if (result !== null if (result !== null
@ -77,13 +70,28 @@ module.exports = new Class
return null; return null;
} }
,fetchObject: function() {
var result = this.fetch();
if (result !== null
&& result.data instanceof Array
&& result.data.length > 0) {
var row = result.data[0];
var object = {};
for(var i = 0; i < row.length; i++)
object[result.columns[i].name] = row[i];
return object;
}
return null;
}
/** /**
* Fetchs the first row and column value from the next resultset. * Fetchs the first row and column value from the next resultset.
* *
* @return {Object} the value if success, %null otherwise * @return {Object} the value if success, %null otherwise
**/ **/
,fetchValue: function () ,fetchValue: function() {
{
var row = this.fetchRow(); var row = this.fetchRow();
if (row instanceof Array && row.length > 0) if (row instanceof Array && row.length > 0)

View File

@ -54,7 +54,7 @@ module.exports = new Class({
this.unref(); this.unref();
} }
,_onWindowError: function(message, file, line, col, err) { ,_onWindowError: function(message, file, line) {
var error = new Error(message); var error = new Error(message);
error.fileName = file; error.fileName = file;
error.lineNumber = line; error.lineNumber = line;
@ -68,12 +68,15 @@ module.exports = new Class({
Htk.Toast.showError(_('Invalid login')); Htk.Toast.showError(_('Invalid login'));
this._logout(); this._logout();
break; break;
case 'Forbidden':
Htk.Toast.showError(_('You don\'t have enough privileges'));
break;
case 'UserDisabled': case 'UserDisabled':
Htk.Toast.showError(_('User disabled')); Htk.Toast.showError(_('User disabled'));
this._logout(); this._logout();
break; break;
case 'SessionExpired': case 'SessionExpired':
Htk.Toast.showError(_('You\'ve been too idle')); Htk.Toast.showError(_('Session expired'));
this._logout(); this._logout();
break; break;
case 'OutdatedVersion': case 'OutdatedVersion':
@ -81,6 +84,14 @@ module.exports = new Class({
break; break;
default: default:
Htk.Toast.showError(error.message); Htk.Toast.showError(error.message);
} else if (error.statusCode)
switch (error.statusCode) {
case 401:
Htk.Toast.showError(_('Invalid login'));
this._logout();
break;
default:
Htk.Toast.showError(error.message);
} }
else { else {
console.error(error); console.error(error);

View File

@ -48,7 +48,7 @@ module.exports = new Class({
this.$('social-bar').conn = this._conn; this.$('social-bar').conn = this._conn;
var sql = 'SELECT nickname FROM account.myUser;' var sql = 'SELECT id, name, nickname FROM account.myUser;'
+'SELECT defaultForm FROM config;' +'SELECT defaultForm FROM config;'
+'SELECT url FROM imageConfig;' +'SELECT url FROM imageConfig;'
+'SELECT dbproduccion FROM vn2008.tblContadores;' +'SELECT dbproduccion FROM vn2008.tblContadores;'
@ -121,8 +121,8 @@ module.exports = new Class({
,onMainQueryDone: function(resultSet) { ,onMainQueryDone: function(resultSet) {
// Retrieving the user name // Retrieving the user name
var userName = resultSet.fetchValue(); this.user = resultSet.fetchObject();
Vn.Node.setText(this.$('user-name'), userName); Vn.Node.setText(this.$('user-name'), this.user.nickname);
// Retrieving configuration parameters // Retrieving configuration parameters

View File

@ -9,7 +9,8 @@ Login phone: +34 607 562 391
Password forgotten? Push here: ¿Has oblidat la teva contrasenya? Password forgotten? Push here: ¿Has oblidat la teva contrasenya?
Yet you are not a customer?: Encara no ets client? Yet you are not a customer?: Encara no ets client?
Sign up: Registrarme Sign up: Registrarme
You've been too idle: Has estat massa temps inactiu i la sessió ha expirat You don't have enough privileges: No tens prou privilegis
Session expired: La sessió ha expirat
Invalid login: >- Invalid login: >-
Usuari o contrasenya incorrectes, recorda que s'hi distingeix entre majúscula Usuari o contrasenya incorrectes, recorda que s'hi distingeix entre majúscula
i minúscula i minúscula

View File

@ -10,7 +10,8 @@ Password forgotten? Push here: Password forgotten? Push here
Yet you are not a customer?: Yet you are not a customer? Yet you are not a customer?: Yet you are not a customer?
Sign up: Sign up Sign up: Sign up
Sign up link: http://bit.ly/2wLntMl Sign up link: http://bit.ly/2wLntMl
You've been too idle: You have been idle too long and your session has expired You don't have enough privileges: You don't have enough privileges
Session expired: Your session has expired
Invalid login: 'Username or password incorrect, remember that it is case-sensitive' Invalid login: 'Username or password incorrect, remember that it is case-sensitive'
User disabled: >- User disabled: >-
Authentication is correct but the user account has been disabled, please Authentication is correct but the user account has been disabled, please

View File

@ -10,7 +10,8 @@ Password forgotten? Push here: ¿Has olvidado tu contraseña?
Yet you are not a customer?: ¿Todavía no eres cliente? Yet you are not a customer?: ¿Todavía no eres cliente?
Sign up: Registrarme Sign up: Registrarme
Sign up link: http://bit.ly/2wLntMl Sign up link: http://bit.ly/2wLntMl
You've been too idle: Has estado demasiado tiempo inactivo y la sesión ha expirado You don't have enough privileges: No tienes suficientes privilegios
Session expired: La sesión ha expirado
Invalid login: >- Invalid login: >-
Usuario o contraseña incorrectos, recuerda que se hace distinción entre Usuario o contraseña incorrectos, recuerda que se hace distinción entre
mayúsculas y minúsculas mayúsculas y minúsculas

View File

@ -10,7 +10,8 @@ Password forgotten? Push here: as tu oublié ton mot de passe?
Yet you are not a customer?: Êtes-vous Pas encore client? Yet you are not a customer?: Êtes-vous Pas encore client?
Sign up: Inscription Sign up: Inscription
Sign up link: http://bit.ly/2msCil1 Sign up link: http://bit.ly/2msCil1
You've been too idle: Il a eu le temps de trop paresseux et votre session a expiré You don't have enough privileges: Vous n'avez pas assez de privilèges
Session expired: Et votre session a expiré
Invalid login: >- Invalid login: >-
Utilisateur ou mot de passe incorrect, n'oubliez pas de distinction entre Utilisateur ou mot de passe incorrect, n'oubliez pas de distinction entre
majuscules et minuscules majuscules et minuscules

View File

@ -9,7 +9,6 @@ Login phone: +34 607 562 391
Password forgotten? Push here: Нууц үг мартсан? энд түлхэх Password forgotten? Push here: Нууц үг мартсан? энд түлхэх
Yet you are not a customer?: Гэсэн хэдий ч та хэрэглэгчийн биш гэж үү? Yet you are not a customer?: Гэсэн хэдий ч та хэрэглэгчийн биш гэж үү?
Sign up: бүртгүүлэх Sign up: бүртгүүлэх
You've been too idle: 'Та нар ч бас зогссон байсан, чуулган хугацаа дууссан байна'
Invalid login: 'Хэрэглэгчийн нэр эсвэл нууц үг буруу, Тэр хэргийг мэдрэмтгий гэдгийг санаарай' Invalid login: 'Хэрэглэгчийн нэр эсвэл нууц үг буруу, Тэр хэргийг мэдрэмтгий гэдгийг санаарай'
Please write your user name: Хэрэглэгчийн нэрээ бичнэ үү Please write your user name: Хэрэглэгчийн нэрээ бичнэ үү
A mail has been sent wich you can recover your password: Мэйл та нууц үгээ сэргээх боломжтой А байна илгээсэн A mail has been sent wich you can recover your password: Мэйл та нууц үгээ сэргээх боломжтой А байна илгээсэн

View File

@ -9,7 +9,8 @@ Login phone: +34 963 242 100
Password forgotten? Push here: Não lembro minha palavra-passe Password forgotten? Push here: Não lembro minha palavra-passe
Yet you are not a customer?: Ainda não és cliente? Yet you are not a customer?: Ainda não és cliente?
Sign up: Cadastrar-se Sign up: Cadastrar-se
You've been too idle: 'Muito tempo de inatividade, a sessão foi finalizada' You don't have enough privileges: Você não tem privilégios suficientes
Session expired: 'A sessão foi finalizada'
Invalid login: >- Invalid login: >-
Usuário ou Palavra-Passe incorreto, lembre-se de diferenciar maiusculas e Usuário ou Palavra-Passe incorreto, lembre-se de diferenciar maiusculas e
minusculas minusculas

View File

@ -1,51 +1,44 @@
var Css = require ('./login.css'); require('./login.css');
var Tpl = require('./login.xml'); var Tpl = require('./login.xml');
module.exports = new Class module.exports = new Class({
({
Extends: Htk.Component, Extends: Htk.Component,
Properties: Properties:
{ {
conn: conn:
{ {
type: Db.Connection type: Db.Connection
,set: function (x) ,set: function(x) {
{
this.link({_conn: x}, {'loading-changed': this._onConnLoadChange}); this.link({_conn: x}, {'loading-changed': this._onConnLoadChange});
} }
,get: function () ,get: function() {
{
return this._conn; return this._conn;
} }
} }
} }
,initialize: function (props) ,initialize: function(props) {
{
this.parent(props); this.parent(props);
this.builderInitString(Tpl); this.builderInitString(Tpl);
this.$('social-bar').conn = this._conn; this.$('social-bar').conn = this._conn;
var self = this; var self = this;
this.$('form').onsubmit = function () this.$('form').onsubmit = function() {
{
self._onSubmit(); self._onSubmit();
return false; return false;
}; };
} }
,_onConnLoadChange: function (conn, isLoading) ,_onConnLoadChange: function(conn, isLoading) {
{
if (isLoading) if (isLoading)
this.$('spinner').start(); this.$('spinner').start();
else else
this.$('spinner').stop(); this.$('spinner').stop();
} }
,show: function () ,show: function() {
{
document.body.appendChild(this.node); document.body.appendChild(this.node);
var lastUser = localStorage.getItem('hederaLastUser'); var lastUser = localStorage.getItem('hederaLastUser');
@ -56,8 +49,7 @@ module.exports = new Class
this._focusUserInput(); this._focusUserInput();
} }
,_onSubmit: function () ,_onSubmit: function() {
{
this._conn.open( this._conn.open(
this.$('user').value, this.$('user').value,
this.$('pass').value, this.$('pass').value,
@ -67,48 +59,40 @@ module.exports = new Class
this._disableUi(true); this._disableUi(true);
} }
,_onConnOpen: function (conn, success, error) ,_onConnOpen: function(conn, success, error) {
{
this.$('pass').value = ''; this.$('pass').value = '';
this._disableUi(false); this._disableUi(false);
if (success) if (success) {
{
var user = this.$('user').value; var user = this.$('user').value;
if (user) if (user)
localStorage.setItem('hederaLastUser', user); localStorage.setItem('hederaLastUser', user);
this.signalEmit('login'); this.signalEmit('login');
} } else {
else
{
this._focusUserInput(); this._focusUserInput();
throw error; throw error;
} }
} }
,hide: function () ,hide: function() {
{
Vn.Node.remove(this.node); Vn.Node.remove(this.node);
} }
,_focusUserInput: function () ,_focusUserInput: function() {
{
var userEntry = this.$('user'); var userEntry = this.$('user');
userEntry.focus(); userEntry.focus();
userEntry.select(); userEntry.select();
} }
,_disableUi: function (disabled) ,_disableUi: function(disabled) {
{
this.$('user').disabled = disabled; this.$('user').disabled = disabled;
this.$('pass').disabled = disabled; this.$('pass').disabled = disabled;
this.$('submit').disabled = disabled; this.$('submit').disabled = disabled;
} }
,onPasswordLost: function () ,onPasswordLost: function() {
{
var user = this.$('user').value; var user = this.$('user').value;
if (!user) if (!user)
@ -118,8 +102,7 @@ module.exports = new Class
this._onPasswordRecovered.bind(this)); this._onPasswordRecovered.bind(this));
} }
,_onPasswordRecovered: function (json, error) ,_onPasswordRecovered: function(json, error) {
{
if (error) if (error)
throw error; throw error;

View File

@ -5,8 +5,7 @@ var JsonException = require ('./json-exception');
/** /**
* Handler for JSON rest connections. * Handler for JSON rest connections.
**/ **/
module.exports = new Class module.exports = new Class({
({
Extends: Object Extends: Object
,_connected: false ,_connected: false
@ -16,14 +15,12 @@ module.exports = new Class
/** /**
* Initilizes the connection object. * Initilizes the connection object.
**/ **/
,initialize: function () ,initialize: function() {
{
this.parent(); this.parent();
this.fetchToken(); this.fetchToken();
} }
,fetchToken: function () ,fetchToken: function() {
{
var token = null; var token = null;
if (sessionStorage.getItem('vnToken')) if (sessionStorage.getItem('vnToken'))
@ -34,8 +31,7 @@ module.exports = new Class
this.token = token; this.token = token;
} }
,clearToken: function () ,clearToken: function() {
{
this.token = null; this.token = null;
localStorage.removeItem('vnToken'); localStorage.removeItem('vnToken');
sessionStorage.removeItem('vnToken'); sessionStorage.removeItem('vnToken');
@ -49,30 +45,25 @@ module.exports = new Class
* @param {Boolean} remember Specifies if the user should be remembered * @param {Boolean} remember Specifies if the user should be remembered
* @param {Function} openCallback The function to call when operation is done * @param {Function} openCallback The function to call when operation is done
**/ **/
,open: function (user, pass, remember, callback) ,open: function(user, pass, remember, callback) {
{ if (user !== null && user !== undefined) {
if (user !== null && user !== undefined)
{
var params = { var params = {
user: user user: user
,password: pass ,password: pass
,remember: remember ,remember: remember
}; };
} } else
else
var params = null; var params = null;
this.send ('core/login', params, this.lbSend('POST', 'Accounts/login', params,
this._onOpen.bind(this, callback, remember)); this._onOpen.bind(this, callback, remember));
} }
/* /*
* Called when open operation is done. * Called when open operation is done.
*/ */
,_onOpen: function (callback, remember, json, error) ,_onOpen: function(callback, remember, json, error) {
{ if (json) {
if (json && json.login)
{
this._connected = true; this._connected = true;
this.token = json.token; this.token = json.token;
@ -80,8 +71,7 @@ module.exports = new Class
storage.setItem('vnToken', this.token); storage.setItem('vnToken', this.token);
this.signalEmit('openned'); this.signalEmit('openned');
} } else
else
this._closeClient(); this._closeClient();
if (callback) if (callback)
@ -93,45 +83,40 @@ module.exports = new Class
* *
* @param {Function} callback The function to call when operation is done * @param {Function} callback The function to call when operation is done
**/ **/
,close: function (callback) ,close: function(callback) {
{ this.lbSend('POST', 'Accounts/logout', null,
this._closeClient ();
this.send ('core/logout', null,
this._onClose.bind(this, callback)); this._onClose.bind(this, callback));
this._closeClient();
} }
/* /*
* Called when close operation is done. * Called when close operation is done.
*/ */
,_onClose: function (callback, json, error) ,_onClose: function(callback, json, error) {
{
this.signalEmit('closed'); this.signalEmit('closed');
if (callback) if (callback)
callback (this, json === true, error); callback(this, null, error);
} }
,_closeClient: function () ,_closeClient: function() {
{
this._connected = false; this._connected = false;
this.clearToken(); this.clearToken();
} }
/** /**
* Suppants another user. * Supplants another user.
* *
* @param {String} user The user name * @param {String} user The user name
* @param {Function} callback The callback function * @param {Function} callback The callback function
**/ **/
,supplantUser: function (user, callback) ,supplantUser: function(user, callback) {
{
var params = {supplantUser: user}; var params = {supplantUser: user};
this.send ('core/supplant', params, this.send('client/supplant', params,
this._onUserSupplant.bind(this, callback)); this._onUserSupplant.bind(this, callback));
} }
,_onUserSupplant: function (callback, json, error) ,_onUserSupplant: function(callback, json) {
{
if (json) if (json)
this.token = json; this.token = json;
@ -142,8 +127,7 @@ module.exports = new Class
/** /**
* Ends the user supplanting and restores the last login. * Ends the user supplanting and restores the last login.
**/ **/
,supplantEnd: function () ,supplantEnd: function() {
{
this.fetchToken(); this.fetchToken();
} }
@ -155,8 +139,7 @@ module.exports = new Class
* @param {Map} params The params to pass to the service * @param {Map} params The params to pass to the service
* @param {Function} callback The response callback * @param {Function} callback The response callback
**/ **/
,send: function (restService, params, callback) ,send: function(restService, params, callback) {
{
if (!params) if (!params)
params = {}; params = {};
@ -165,8 +148,7 @@ module.exports = new Class
this.sendWithUrl(params, callback, 'POST', '.'); this.sendWithUrl(params, callback, 'POST', '.');
} }
,sendForm: function (form, callback) ,sendForm: function(form, callback) {
{
var params = {}; var params = {};
var elements = form.elements; var elements = form.elements;
@ -177,15 +159,13 @@ module.exports = new Class
this.sendWithUrl(params, callback, 'POST', form.action); this.sendWithUrl(params, callback, 'POST', form.action);
} }
,sendFormMultipart: function (form, callback) ,sendFormMultipart: function(form, callback) {
{
var formData = new FormData(form); var formData = new FormData(form);
if (this.token)
formData.append ('token', this.token);
var request = new XMLHttpRequest(); var request = new XMLHttpRequest();
request.open('POST', form.action, true); request.open('POST', form.action, true);
if (this.token)
request.setRequestHeader('Authorization', this.token);
request.onreadystatechange = request.onreadystatechange =
this._onStateChange.bind(this, request, callback); this._onStateChange.bind(this, request, callback);
request.send(formData); request.send(formData);
@ -193,13 +173,11 @@ module.exports = new Class
this._addRequest(); this._addRequest();
} }
,sendFormData: function (formData, callback) ,sendFormData: function(formData, callback) {
{
if (this.token)
formData.append ('token', this.token);
var request = new XMLHttpRequest(); var request = new XMLHttpRequest();
request.open('POST', '', true); request.open('POST', '', true);
if (this.token)
request.setRequestHeader('Authorization', this.token);
request.onreadystatechange = request.onreadystatechange =
this._onStateChange.bind(this, request, callback); this._onStateChange.bind(this, request, callback);
request.send(formData); request.send(formData);
@ -210,15 +188,13 @@ module.exports = new Class
/* /*
* Called when REST response is received. * Called when REST response is received.
*/ */
,sendWithUrl: function (params, callback, method, url) ,sendWithUrl: function(params, callback, method, url) {
{
if (this.token)
params['token'] = this.token;
var request = new XMLHttpRequest(); var request = new XMLHttpRequest();
request.open(method, url, true); request.open(method, url, true);
request.setRequestHeader('Content-Type', request.setRequestHeader('Content-Type',
'application/x-www-form-urlencoded'); 'application/x-www-form-urlencoded');
if (this.token)
request.setRequestHeader('Authorization', this.token);
request.onreadystatechange = request.onreadystatechange =
this._onStateChange.bind(this, request, callback); this._onStateChange.bind(this, request, callback);
request.send(Vn.Url.makeUri(params)); request.send(Vn.Url.makeUri(params));
@ -226,16 +202,28 @@ module.exports = new Class
this._addRequest(); this._addRequest();
} }
,_addRequest: function () ,lbSend: function(method, url, params, callback) {
{ var request = new XMLHttpRequest();
request.open(method, `api/${url}`, true);
request.setRequestHeader('Content-Type',
'application/json;charset=utf-8');
if (this.token)
request.setRequestHeader('Authorization', this.token);
request.onreadystatechange =
this._onStateChange.bind(this, request, callback);
request.send(params && JSON.stringify(params));
this._addRequest();
}
,_addRequest: function() {
this._requestsCount++; this._requestsCount++;
if (this._requestsCount === 1) if (this._requestsCount === 1)
this.signalEmit('loading-changed', true); this.signalEmit('loading-changed', true);
} }
,_onStateChange: function (request, callback) ,_onStateChange: function(request, callback) {
{
if (request.readyState !== 4) if (request.readyState !== 4)
return; return;
@ -248,8 +236,7 @@ module.exports = new Class
var error = null; var error = null;
try { try {
if (request.status == 0) if (request.status == 0) {
{
var ex = new JsonException(); var ex = new JsonException();
ex.message = _('The server does not respond, please check your Internet connection'); ex.message = _('The server does not respond, please check your Internet connection');
throw ex; throw ex;
@ -262,30 +249,32 @@ module.exports = new Class
.getResponseHeader('Content-Type') .getResponseHeader('Content-Type')
.split(';')[0] .split(';')[0]
.trim(); .trim();
} catch (err) {
console.warn(err);
} }
catch (e) {}
if (contentType != 'application/json') if (contentType != 'application/json') {
{
var ex = new JsonException(); var ex = new JsonException();
ex.message = request.statusText; ex.message = request.statusText;
ex.code = request.status; ex.code = request.status;
throw ex; throw ex;
} }
var json = JSON.parse (request.responseText); var json;
var jsData = json.data; var jsData;
//var jsWarns = json.warnings;
if (request.status == 200) if (request.responseText)
{ json = JSON.parse(request.responseText);
if (json)
jsData = json.data || json;
if (request.status >= 200 && request.status < 300) {
data = jsData; data = jsData;
} } else {
else
{
var exception = jsData.exception; var exception = jsData.exception;
var error = jsData.error;
if (exception) if (exception) {
exception = exception exception = exception
.replace(/\\/g, '.') .replace(/\\/g, '.')
.replace(/Exception$/, '') .replace(/Exception$/, '')
@ -298,11 +287,17 @@ module.exports = new Class
ex.file = jsData.file; ex.file = jsData.file;
ex.line = jsData.line; ex.line = jsData.line;
ex.trace = jsData.trace; ex.trace = jsData.trace;
} else if (error) {
var ex = new Error();
ex.name = error.name;
ex.message = error.message;
ex.code = error.code;
ex.statusCode = request.status;
}
throw ex; throw ex;
} }
} } catch (e) {
catch (e)
{
data = null; data = null;
error = e; error = e;
} }
@ -311,14 +306,11 @@ module.exports = new Class
try { try {
callback(data, error); callback(data, error);
error = null; error = null;
} } catch (e) {
catch (e)
{
error = e; error = e;
} }
if (error) if (error) {
{
if (error.exception == 'SessionExpired') if (error.exception == 'SessionExpired')
this.clearToken(); this.clearToken();

30
rest/client/supplant.php Normal file
View File

@ -0,0 +1,30 @@
<?php
use Vn\Web;
class Supplant extends Vn\Web\JsonRequest {
const PARAMS = ['supplantUser'];
function run($db) {
$userId = $db->getValue(
'SELECT id FROM account.user WHERE `name` = #',
[$_REQUEST['supplantUser']]
);
$isClient = $db->getValue(
'SELECT COUNT(*) > 0 FROM vn.client WHERE id = #',
[$userId]
);
if (!$isClient)
throw new Web\ForbiddenException(s('The user is not a client'));
$isWorker = $db->getValue(
'SELECT COUNT(*) > 0 FROM vn.worker WHERE id = #',
[$userId]
);
if ($isWorker)
throw new Web\ForbiddenException(s('Workers cannot be supplanted'));
return $this->service->createToken($_REQUEST['supplantUser']);
}
}

View File

@ -1,21 +0,0 @@
<?php
include __DIR__.'/account.php';
/**
* Updates the user password.
**/
class ChangePassword extends Vn\Web\JsonRequest {
const PARAMS = ['oldPassword', 'newPassword'];
function run($db) {
$oldPassword = $_REQUEST['oldPassword'];
$newPassword = $_REQUEST['newPassword'];
$db->query('CALL account.myUser_changePassword(#, #)',
[$oldPassword, $newPassword]);
Account::sync($db, $_SESSION['user'], $newPassword);
return TRUE;
}
}

View File

@ -1,30 +0,0 @@
<?php
include __DIR__.'/account.php';
class Login extends Vn\Web\JsonRequest {
function run($db) {
if (!$_POST['user'] || !$_POST['password'])
throw new Vn\Web\BadLoginException();
try {
Account::trySync($db
,strtolower($_POST['user'])
,$_POST['password']
);
} catch (Exception $e) {
error_log($e->getMessage());
}
$token = $this->service->createToken(
$_SESSION['user'],
!empty($_POST['remember'])
);
return [
'login' => TRUE,
'token' => $token
];
}
}

View File

@ -1,9 +0,0 @@
<?php
class Logout extends Vn\Web\JsonRequest {
function run($db) {
$this->service->logout();
return TRUE;
}
}

View File

@ -7,4 +7,3 @@ class Supplant extends Vn\Web\JsonRequest {
return $this->service->createToken($_REQUEST['supplantUser']); return $this->service->createToken($_REQUEST['supplantUser']);
} }
} }

View File

@ -1,17 +0,0 @@
<?php
include __DIR__.'/account.php';
/**
* Updates the user credentials on external systems like Samba, create
* home directory, create mailbox, etc.
**/
class SyncUser extends Vn\Web\JsonRequest {
const PARAMS = ['syncUser'];
function run($db) {
Account::sync($db, $_REQUEST['syncUser'], NULL);
return TRUE;
}
}

View File

@ -1,105 +0,0 @@
<?php
use Vn\Lib;
/**
* Adds a document to the Document Management System.
**/
class Add extends Vn\Web\JsonRequest {
function run($db) {
// XXX: Uncomment only to test the script
//$_REQUEST['description'] = 'description';
$description = empty($_REQUEST['description']) ?
NULL : $_REQUEST['description'];
$baseDir = _DATA_DIR .'/'. $this->app->getName();
$docsDir = "$baseDir/dms";
$tempDir = "$baseDir/.dms";
$digXDir = 3;
$zerosDir = '';
for ($i = 0; $i < $digXDir; $i++)
$zerosDir .= '0';
// Checks document restrictions
if (empty($_FILES['doc']['name']))
throw new Lib\UserException('File not choosed');
$maxSize = $db->getValue('SELECT max_size FROM dms_config');
if ($_FILES['doc']['size'] > $maxSize * 1048576)
throw new Lib\UserException(sprintf('File size exceeds size: %d MB', $maxSize));
try {
// Registers the document in the database
$db->query('START TRANSACTION');
$db->query('INSERT INTO dms_document SET description = #', [$description]);
$docId =(string) $db->getValue('SELECT LAST_INSERT_ID()');
$len = strlen($docId);
$neededLevels = ceil($len / $digXDir) - 1;
$dirLevels = $db->getValue(
'SELECT dir_levels FROM dms_config LOCK IN SHARE MODE');
if ($dirLevels > $neededLevels)
$neededLevels = $dirLevels;
// Reorganizes the file repository if necessary
if ($dirLevels < $neededLevels)
$dirLevels = $db->getValue(
'SELECT dir_levels FROM dms_config FOR UPDATE');
if ($dirLevels < $neededLevels) {
if (is_dir($docsDir)) {
$dif =($neededLevels - $dirLevels) - 1;
$newDir = $docsDir;
for ($i = 0; $i < $dif; $i++)
$newDir .= "/$zerosDir";
$success = rename($docsDir, $tempDir)
&& mkdir($newDir, 0770, TRUE)
&& rename($tempDir, "$newDir/$zerosDir");
if (!$success)
throw new Exception('Error while reorganizing directory tree');
}
$curLevels = $db->query('UPDATE dms_config SET dir_levels = #',
[$neededLevels]);
}
// Saves the document to the repository
$padLen =($neededLevels + 1) * $digXDir;
$paddedId = str_pad($docId, $padLen, '0', STR_PAD_LEFT);
$saveDir = $docsDir;
for ($i = 0; $i < $neededLevels; $i++)
$saveDir .= '/'. substr($paddedId, $i * $digXDir, $digXDir);
if (!file_exists($saveDir))
mkdir($saveDir, 0770, TRUE);
$savePath = "$saveDir/". substr($paddedId, -$digXDir);
move_uploaded_file($_FILES['doc']['tmp_name'], $savePath);
$db->query('COMMIT');
return $docId;
} catch (Exception $e) {
$db->query('ROLLBACK');
throw $e;
}
}
}

View File

@ -1,52 +0,0 @@
<?php
use Vn\Lib;
class Sms extends Vn\Web\JsonRequest {
const PARAMS = [
'destination'
,'message'
];
const OK_STATES = [
0, // Ok
200 // Processing
];
function run($db) {
$smsConfig = $db->getObject('SELECT uri, user, password, title FROM vn.smsConfig');
$sClient = new SoapClient($smsConfig->uri);
$xmlString = $sClient->sendSMS(
$smsConfig->user
,$smsConfig->password
,$smsConfig->title
,$_REQUEST['destination']
,$_REQUEST['message']
);
$xmlResponse = new SimpleXMLElement($xmlString);
$res = $xmlResponse->sms;
$db->query(
'INSERT INTO vn.sms SET
`senderFk` = account.myUser_getId(),
`destinationFk` = #,
`destination` = #,
`message` = #,
`statusCode` = #,
`status` = #',
[
empty($_REQUEST['destinationId']) ? NULL : $_REQUEST['destinationId']
,$_REQUEST['destination']
,$_REQUEST['message']
,$res->codigo
,$res->descripcion
]
);
if (!in_array((int) $res->codigo, self::OK_STATES))
throw new Lib\UserException($res->descripcion);
return TRUE;
}
}

View File

@ -31,13 +31,12 @@ class RestService extends Service {
$_REQUEST['method'], $class, './rest'); $_REQUEST['method'], $class, './rest');
$method->service = $this; $method->service = $this;
if ($method::SECURITY == Security::DEFINER) {
$isAuthorized = $db->getValue('SELECT myUser_checkRestPriv(#)', $isAuthorized = $db->getValue('SELECT myUser_checkRestPriv(#)',
[$_REQUEST['method']]); [$_REQUEST['method']]);
if (!$isAuthorized) if (!$isAuthorized)
throw new UserException(s('You don\'t have enough privileges')); throw new ForbiddenException(s('You don\'t have enough privileges'));
if ($method::SECURITY == Security::DEFINER) {
$methodDb = $db; $methodDb = $db;
} else } else
$methodDb = $this->getUserDb($_SESSION['user']); $methodDb = $this->getUserDb($_SESSION['user']);
@ -71,6 +70,8 @@ class RestService extends Service {
$status = 401; $status = 401;
} catch (BadLoginException $e) { } catch (BadLoginException $e) {
$status = 401; $status = 401;
} catch (ForbiddenException $e) {
$status = 403;
} catch (Lib\UserException $e) { } catch (Lib\UserException $e) {
$status = 400; $status = 400;
} catch (\Exception $e) { } catch (\Exception $e) {

View File

@ -21,6 +21,11 @@ class SessionExpiredException extends UserException {}
*/ */
class BadLoginException extends UserException {} class BadLoginException extends UserException {}
/**
* Thrown when user credentials are invalid.
*/
class ForbiddenException extends UserException {}
/** /**
* Thrown when user credentials are invalid. * Thrown when user credentials are invalid.
*/ */
@ -130,62 +135,26 @@ abstract class Service {
*/ */
function login() { function login() {
$db = $this->db; $db = $this->db;
$anonymousUser = FALSE; $anonymousUser = TRUE;
if (isset($_POST['user']) && !empty($_POST['password'])) { if (!empty($_SERVER['HTTP_AUTHORIZATION'])) {
$user = strtolower($_POST['user']); $userId = $db->getValue(
'SELECT userId FROM salix.AccessToken
$passwordHash = $db->getValue( WHERE id = #
'SELECT bcryptPassword FROM account.user WHERE `name` = #', AND NOW() <= TIMESTAMPADD(SECOND, ttl, created)',
[$user] [$_SERVER['HTTP_AUTHORIZATION']]
); );
$passwordOk = !empty($passwordHash) if (!$userId)
&& password_verify($_POST['password'], $passwordHash);
// XXX: Compatibility with old MD5 passwords
if (empty($passwordHash)) {
$md5Password = $db->getValue(
'SELECT `password` FROM account.user
WHERE active AND `name` = #',
[$user]
);
$passwordOk = !empty($md5Password)
&& $md5Password == md5($_POST['password']);
}
if (!$passwordOk) {
sleep(3);
throw new BadLoginException();
}
} else {
if (isset($_POST['token']) || isset($_GET['token'])) {
if (isset($_POST['token']))
$token = $_POST['token'];
if (isset($_GET['token']))
$token = $_GET['token'];
$key = $db->getValue('SELECT jwtKey FROM config');
try {
$jwtPayload = Jwt::decode($token, $key);
} catch (\Exception $e) {
throw new BadLoginException($e->getMessage());
}
$expiration = $jwtPayload['exp'];
if (empty($expiration) || $expiration <= time())
throw new SessionExpiredException(); throw new SessionExpiredException();
$user = $jwtPayload['sub']; $anonymousUser = FALSE;
} $user = $db->getValue(
else { 'SELECT `name` FROM account.user WHERE id = #',
[$userId]
);
} else
$user = $db->getValue('SELECT guestUser FROM config'); $user = $db->getValue('SELECT guestUser FROM config');
$anonymousUser = TRUE;
}
}
if (!$anonymousUser) { if (!$anonymousUser) {
$isActive = $db->getValue( $isActive = $db->getValue(
@ -217,6 +186,12 @@ abstract class Service {
* Logouts the current user. Cleans the last saved used credentials. * Logouts the current user. Cleans the last saved used credentials.
*/ */
function logout() { function logout() {
if (!empty($_SERVER['HTTP_AUTHORIZATION']))
$db->query(
'DELETE FROM salix.AccessToken WHERE id = #',
[$_SERVER['HTTP_AUTHORIZATION']]
);
unset($_SESSION['user']); unset($_SESSION['user']);
} }

View File

@ -79,7 +79,11 @@ var devConfig = {
host: '0.0.0.0', host: '0.0.0.0',
port: wpConfig.devServerPort, port: wpConfig.devServerPort,
headers: {'Access-Control-Allow-Origin': '*'}, headers: {'Access-Control-Allow-Origin': '*'},
stats: { chunks: false } stats: { chunks: false },
proxy: {
'/api': 'http://localhost:3000',
'/': 'http://localhost/projects/hedera-web'
}
}, },
devtool: 'eval' devtool: 'eval'
}; };