test #4
43
app.js
43
app.js
|
@ -1,25 +1,12 @@
|
|||
|
||||
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;
|
||||
__webpack_public_path__ = _PUBLIC_PATH;
|
||||
|
||||
require('hedera/hedera');
|
||||
|
||||
window.onload = function ()
|
||||
{
|
||||
window.onload = function() {
|
||||
loadLocale(main);
|
||||
}
|
||||
|
||||
function main (req)
|
||||
{
|
||||
function main(req) {
|
||||
if (req)
|
||||
onLocaleLoad(req);
|
||||
|
||||
|
@ -27,43 +14,45 @@ function main (req)
|
|||
hederaWeb.run();
|
||||
}
|
||||
|
||||
function loadLocale (cb)
|
||||
{
|
||||
function loadLocale(cb) {
|
||||
Vn.Locale.init();
|
||||
var lang = Vn.Locale.language;
|
||||
|
||||
var req = require.context('js', true, /locale\/en.yml$/);
|
||||
onLocaleLoad(req);
|
||||
|
||||
switch (lang)
|
||||
{
|
||||
switch (lang) {
|
||||
case 'ca':
|
||||
require([], function() {
|
||||
cb (require.context ('js', true, /locale\/ca.yml$/)); });
|
||||
cb(require.context('js', true, /locale\/ca.yml$/));
|
||||
});
|
||||
break;
|
||||
case 'es':
|
||||
require([], function() {
|
||||
cb (require.context ('js', true, /locale\/es.yml$/)); });
|
||||
cb(require.context('js', true, /locale\/es.yml$/));
|
||||
});
|
||||
break;
|
||||
case 'fr':
|
||||
require([], function() {
|
||||
cb (require.context ('js', true, /locale\/fr.yml$/)); });
|
||||
cb(require.context('js', true, /locale\/fr.yml$/));
|
||||
});
|
||||
break;
|
||||
case 'mn':
|
||||
require([], function() {
|
||||
cb (require.context ('js', true, /locale\/mn.yml$/)); });
|
||||
cb(require.context('js', true, /locale\/mn.yml$/));
|
||||
});
|
||||
break;
|
||||
case 'pt':
|
||||
require([], function() {
|
||||
cb (require.context ('js', true, /locale\/pt.yml$/)); });
|
||||
cb(require.context('js', true, /locale\/pt.yml$/));
|
||||
});
|
||||
break;
|
||||
default:
|
||||
cb();
|
||||
}
|
||||
}
|
||||
|
||||
function onLocaleLoad (req)
|
||||
{
|
||||
function onLocaleLoad(req) {
|
||||
var keys = req.keys();
|
||||
|
||||
for (var i = 0; i < keys.length; i++)
|
||||
|
|
|
@ -1,18 +0,0 @@
|
|||
CREATE OR REPLACE
|
||||
ALGORITHM = UNDEFINED
|
||||
DEFINER=`root`@`%`
|
||||
VIEW `hedera`.`myTicketService` AS
|
||||
select
|
||||
`s`.`id` AS `id`,
|
||||
`s`.`description` AS `description`,
|
||||
`s`.`quantity` AS `quantity`,
|
||||
`s`.`price` AS `price`,
|
||||
`s`.`taxClassFk` AS `taxClassFk`,
|
||||
`s`.`ticketFk` AS `ticketFk`,
|
||||
`s`.`ticketServiceTypeFk` AS `ticketServiceTypeFk`
|
||||
from
|
||||
(`vn`.`ticketService` `s`
|
||||
join `hedera`.`myTicket` `t` on
|
||||
(`s`.`ticketFk` = `t`.`id`)) WITH CASCADED CHECK OPTION;
|
||||
|
||||
GRANT SELECT ON TABLE hedera.myTicketService TO account@'localhost';
|
|
@ -1,18 +0,0 @@
|
|||
|
||||
DROP PROCEDURE IF EXISTS hedera.myTicket_getServices;
|
||||
DELIMITER $$
|
||||
CREATE DEFINER=`root`@`%` PROCEDURE `hedera`.`myTicket_getServices`(vSelf INT)
|
||||
BEGIN
|
||||
/**
|
||||
* Returns a current user ticket services.
|
||||
*
|
||||
* @param vSelf The ticket identifier
|
||||
* @select The ticket services
|
||||
*/
|
||||
SELECT id, description, quantity, price
|
||||
FROM myTicketService
|
||||
WHERE ticketFk = vSelf;
|
||||
END$$
|
||||
DELIMITER ;
|
||||
|
||||
GRANT EXECUTE ON PROCEDURE hedera.myTicket_getServices TO account@'localhost';
|
|
@ -1 +0,0 @@
|
|||
CALL account.role_sync;
|
|
@ -1,4 +1,4 @@
|
|||
hedera-web (1.407.66) stable; urgency=low
|
||||
hedera-web (1.407.67) stable; urgency=low
|
||||
|
||||
* Initial Release.
|
||||
|
||||
|
|
|
@ -5,8 +5,6 @@ Hedera.Conf = new Class({
|
|||
,activate: function() {
|
||||
this.$('user-model').setInfo('c', 'myClient', 'hedera');
|
||||
|
||||
console.log(this.hash.get('verificationToken'));
|
||||
|
||||
if (this.hash.get('verificationToken'))
|
||||
this.onPassChangeClick();
|
||||
}
|
||||
|
@ -45,9 +43,12 @@ Hedera.Conf = new Class({
|
|||
this.conn.send('core/restore-password', params,
|
||||
this._onPassChange.bind(this));
|
||||
} else {
|
||||
let userId = this.gui.user.id;
|
||||
params.oldPassword = oldPassword;
|
||||
this.conn.send('core/change-password', params,
|
||||
this._onPassChange.bind(this));
|
||||
this.conn.lbSend('PATCH',
|
||||
`Accounts/${userId}/changePassword`, params,
|
||||
this._onPassChange.bind(this)
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
Htk.Toast.showError(e.message);
|
||||
|
@ -55,7 +56,7 @@ Hedera.Conf = new Class({
|
|||
}
|
||||
|
||||
,_onPassChange: function(json, error) {
|
||||
if (json) {
|
||||
if (!error) {
|
||||
this.$('change-password').hide();
|
||||
this.hash.unset('verificationToken');
|
||||
Htk.Toast.showMessage(_('Password changed!'));
|
||||
|
|
|
@ -1,12 +1,10 @@
|
|||
|
||||
Hedera.Connections = new Class
|
||||
({
|
||||
Hedera.Connections = new Class({
|
||||
Extends: Hedera.Form
|
||||
|
||||
,_timeoutId: null
|
||||
|
||||
,onModelStatusChange: function (model, status)
|
||||
{
|
||||
,onModelStatusChange: function(model) {
|
||||
if (!model.ready)
|
||||
return;
|
||||
|
||||
|
@ -16,37 +14,31 @@ Hedera.Connections = new Class
|
|||
this._timeoutId = setTimeout(this.onRefreshClick.bind(this), 60000);
|
||||
}
|
||||
|
||||
,deactivate: function ()
|
||||
{
|
||||
,deactivate: function() {
|
||||
clearTimeout(this._timeoutId);
|
||||
}
|
||||
|
||||
,onRefreshClick: function ()
|
||||
{
|
||||
,onRefreshClick: function() {
|
||||
this.$('sessions').refresh();
|
||||
}
|
||||
|
||||
,onAccessLogClick: function (button, form)
|
||||
{
|
||||
,onAccessLogClick: function(button, form) {
|
||||
this.hash.set({
|
||||
'form': 'admin/access-log'
|
||||
,'user': form.get ('userId')
|
||||
form: 'admin/access-log'
|
||||
,user: form.get('userId')
|
||||
});
|
||||
}
|
||||
|
||||
,onChangeUserClick: function (button, form)
|
||||
{
|
||||
,onChangeUserClick: function(button, form) {
|
||||
this.gui.supplantUser(form.get('user'),
|
||||
this._onUserSupplant.bind(this));
|
||||
}
|
||||
|
||||
,_onUserSupplant: function (userName)
|
||||
{
|
||||
this.hash.set ({'form': 'ecomerce/orders'});
|
||||
,_onUserSupplant: function() {
|
||||
this.hash.set({form: 'ecomerce/orders'});
|
||||
}
|
||||
|
||||
,sessionsFunc: function ()
|
||||
{
|
||||
,sessionsFunc: function() {
|
||||
return 1;
|
||||
}
|
||||
});
|
||||
|
|
|
@ -50,7 +50,7 @@
|
|||
<htk-text form="iter" column="value7"/>
|
||||
</p>
|
||||
<p>
|
||||
@<htk-text form="iter" column="id"/>
|
||||
#<htk-text form="iter" column="id"/>
|
||||
</p>
|
||||
<p>
|
||||
<htk-text form="iter" column="image"/>
|
||||
|
|
|
@ -50,7 +50,7 @@
|
|||
<htk-text form="iter" column="nickname"/>
|
||||
</p>
|
||||
<p>
|
||||
@<htk-text form="iter" column="id"/> -
|
||||
#<htk-text form="iter" column="id"/> -
|
||||
<htk-text form="iter" column="name"/>
|
||||
</p>
|
||||
<div class="clear"/>
|
||||
|
|
|
@ -1,18 +1,15 @@
|
|||
|
||||
Hedera.Users = new Class
|
||||
({
|
||||
Hedera.Users = new Class({
|
||||
Extends: Hedera.Form
|
||||
|
||||
,onAccessLogClick: function (button, form)
|
||||
{
|
||||
,onAccessLogClick: function(button, form) {
|
||||
this.hash.set({
|
||||
'form': 'admin/access-log'
|
||||
,'user': form.get('id')
|
||||
});
|
||||
}
|
||||
|
||||
,rendererFunc: function (scope, form)
|
||||
{
|
||||
,rendererFunc: function(scope, form) {
|
||||
var isEnabled = form.get('active')
|
||||
scope.$('disabled').style.display = isEnabled ?
|
||||
'none' : 'block';
|
||||
|
@ -20,14 +17,12 @@ Hedera.Users = new Class
|
|||
'block' : 'none';
|
||||
}
|
||||
|
||||
,onChangeUserClick: function (button, form)
|
||||
{
|
||||
,onChangeUserClick: function(button, form) {
|
||||
this.gui.supplantUser(form.get('name'),
|
||||
this.onUserSupplant.bind(this));
|
||||
}
|
||||
|
||||
,onUserSupplant: function ()
|
||||
{
|
||||
,onUserSupplant: function() {
|
||||
this.hash.set({form: 'ecomerce/orders'});
|
||||
}
|
||||
});
|
||||
|
|
|
@ -406,7 +406,7 @@
|
|||
<htk-text form="card" column="subName"/>
|
||||
</p>
|
||||
<p>
|
||||
@<htk-text form="card" column="id"/>
|
||||
#<htk-text form="card" column="id"/>
|
||||
</p>
|
||||
<p>
|
||||
<htk-text form="card" column="stems" format="_%.0d Units"/>
|
||||
|
|
|
@ -56,7 +56,7 @@
|
|||
<htk-text form="iter" column="landed" format="%D"/>
|
||||
</p>
|
||||
<p>
|
||||
@<htk-text form="iter" column="id"/>
|
||||
#<htk-text form="iter" column="id"/>
|
||||
</p>
|
||||
<p>
|
||||
<htk-text form="iter" column="nickname"/>
|
||||
|
|
|
@ -19,9 +19,13 @@ Hedera.Ticket = new Class({
|
|||
},
|
||||
|
||||
onPrintClick: function() {
|
||||
var batch = new Sql.Batch();
|
||||
batch.addValue('ticket', this.$('ticket-id').value);
|
||||
this.gui.openReport('delivery-note', batch);
|
||||
let params = Vn.Url.makeUri({
|
||||
authorization: this.conn.token,
|
||||
ticketId: this.$('ticket-id').value,
|
||||
recipientId: this.gui.user.id,
|
||||
type: 'deliveryNote'
|
||||
});
|
||||
window.open(`/api/report/delivery-note?${params}`);
|
||||
},
|
||||
|
||||
repeaterFunc: function(res, form) {
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
<htk-loader class="head" form="ticket">
|
||||
<div>
|
||||
<p class="important ticket-id">
|
||||
@<htk-text column="id" form="ticket"/>
|
||||
#<htk-text column="id" form="ticket"/>
|
||||
</p>
|
||||
<p>
|
||||
<t>Preparation</t> <htk-text form="ticket" column="shipped" format="%D"/>
|
||||
|
@ -151,7 +151,7 @@
|
|||
<htk-text form="iter" column="name"/>
|
||||
</h2>
|
||||
<p>
|
||||
@<htk-text form="iter" column="id"/>
|
||||
#<htk-text form="iter" column="id"/>
|
||||
</p>
|
||||
<p class="amount">
|
||||
<htk-text form="iter" column="quantity"/>
|
||||
|
|
|
@ -4,16 +4,14 @@ var Result = require ('./result');
|
|||
/**
|
||||
* This class stores the database results.
|
||||
**/
|
||||
module.exports = new Class
|
||||
({
|
||||
module.exports = new Class({
|
||||
results: null
|
||||
,error: null
|
||||
|
||||
/**
|
||||
* Initilizes the resultset object.
|
||||
**/
|
||||
,initialize: function (results, error)
|
||||
{
|
||||
,initialize: function(results, error) {
|
||||
this.results = results;
|
||||
this.error = error;
|
||||
}
|
||||
|
@ -23,13 +21,11 @@ module.exports = new Class
|
|||
*
|
||||
* @return {Db.Err} the error or null if no errors hapened
|
||||
**/
|
||||
,getError: function ()
|
||||
{
|
||||
,getError: function() {
|
||||
return this.error;
|
||||
}
|
||||
|
||||
,fetch: function ()
|
||||
{
|
||||
,fetch: function() {
|
||||
if (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
|
||||
**/
|
||||
,fetchResult: function ()
|
||||
{
|
||||
,fetchResult: function() {
|
||||
var result = this.fetch();
|
||||
|
||||
if (result !== null)
|
||||
{
|
||||
if (result !== null) {
|
||||
if (result.data instanceof Array)
|
||||
return new Result(result);
|
||||
else
|
||||
|
@ -65,8 +59,7 @@ module.exports = new Class
|
|||
*
|
||||
* @return {Array} the row if success, %null otherwise
|
||||
**/
|
||||
,fetchRow: function ()
|
||||
{
|
||||
,fetchRow: function() {
|
||||
var result = this.fetch();
|
||||
|
||||
if (result !== null
|
||||
|
@ -77,13 +70,28 @@ module.exports = new Class
|
|||
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.
|
||||
*
|
||||
* @return {Object} the value if success, %null otherwise
|
||||
**/
|
||||
,fetchValue: function ()
|
||||
{
|
||||
,fetchValue: function() {
|
||||
var row = this.fetchRow();
|
||||
|
||||
if (row instanceof Array && row.length > 0)
|
||||
|
|
|
@ -54,7 +54,7 @@ module.exports = new Class({
|
|||
this.unref();
|
||||
}
|
||||
|
||||
,_onWindowError: function(message, file, line, col, err) {
|
||||
,_onWindowError: function(message, file, line) {
|
||||
var error = new Error(message);
|
||||
error.fileName = file;
|
||||
error.lineNumber = line;
|
||||
|
@ -68,12 +68,15 @@ module.exports = new Class({
|
|||
Htk.Toast.showError(_('Invalid login'));
|
||||
this._logout();
|
||||
break;
|
||||
case 'Forbidden':
|
||||
Htk.Toast.showError(_('You don\'t have enough privileges'));
|
||||
break;
|
||||
case 'UserDisabled':
|
||||
Htk.Toast.showError(_('User disabled'));
|
||||
this._logout();
|
||||
break;
|
||||
case 'SessionExpired':
|
||||
Htk.Toast.showError(_('You\'ve been too idle'));
|
||||
Htk.Toast.showError(_('Session expired'));
|
||||
this._logout();
|
||||
break;
|
||||
case 'OutdatedVersion':
|
||||
|
@ -81,6 +84,14 @@ module.exports = new Class({
|
|||
break;
|
||||
default:
|
||||
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 {
|
||||
console.error(error);
|
||||
|
|
|
@ -48,7 +48,7 @@ module.exports = new Class({
|
|||
|
||||
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 url FROM imageConfig;'
|
||||
+'SELECT dbproduccion FROM vn2008.tblContadores;'
|
||||
|
@ -121,8 +121,8 @@ module.exports = new Class({
|
|||
,onMainQueryDone: function(resultSet) {
|
||||
// Retrieving the user name
|
||||
|
||||
var userName = resultSet.fetchValue();
|
||||
Vn.Node.setText(this.$('user-name'), userName);
|
||||
this.user = resultSet.fetchObject();
|
||||
Vn.Node.setText(this.$('user-name'), this.user.nickname);
|
||||
|
||||
// Retrieving configuration parameters
|
||||
|
||||
|
|
|
@ -9,7 +9,8 @@ Login phone: +34 607 562 391
|
|||
Password forgotten? Push here: ¿Has oblidat la teva contrasenya?
|
||||
Yet you are not a customer?: Encara no ets client?
|
||||
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: >-
|
||||
Usuari o contrasenya incorrectes, recorda que s'hi distingeix entre majúscula
|
||||
i minúscula
|
||||
|
|
|
@ -10,7 +10,8 @@ Password forgotten? Push here: Password forgotten? Push here
|
|||
Yet you are not a customer?: Yet you are not a customer?
|
||||
Sign up: Sign up
|
||||
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'
|
||||
User disabled: >-
|
||||
Authentication is correct but the user account has been disabled, please
|
||||
|
|
|
@ -10,7 +10,8 @@ Password forgotten? Push here: ¿Has olvidado tu contraseña?
|
|||
Yet you are not a customer?: ¿Todavía no eres cliente?
|
||||
Sign up: Registrarme
|
||||
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: >-
|
||||
Usuario o contraseña incorrectos, recuerda que se hace distinción entre
|
||||
mayúsculas y minúsculas
|
||||
|
|
|
@ -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?
|
||||
Sign up: Inscription
|
||||
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: >-
|
||||
Utilisateur ou mot de passe incorrect, n'oubliez pas de distinction entre
|
||||
majuscules et minuscules
|
||||
|
|
|
@ -9,7 +9,6 @@ Login phone: +34 607 562 391
|
|||
Password forgotten? Push here: Нууц үг мартсан? энд түлхэх
|
||||
Yet you are not a customer?: Гэсэн хэдий ч та хэрэглэгчийн биш гэж үү?
|
||||
Sign up: бүртгүүлэх
|
||||
You've been too idle: 'Та нар ч бас зогссон байсан, чуулган хугацаа дууссан байна'
|
||||
Invalid login: 'Хэрэглэгчийн нэр эсвэл нууц үг буруу, Тэр хэргийг мэдрэмтгий гэдгийг санаарай'
|
||||
Please write your user name: Хэрэглэгчийн нэрээ бичнэ үү
|
||||
A mail has been sent wich you can recover your password: Мэйл та нууц үгээ сэргээх боломжтой А байна илгээсэн
|
||||
|
|
|
@ -9,7 +9,8 @@ Login phone: +34 963 242 100
|
|||
Password forgotten? Push here: Não lembro minha palavra-passe
|
||||
Yet you are not a customer?: Ainda não és cliente?
|
||||
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: >-
|
||||
Usuário ou Palavra-Passe incorreto, lembre-se de diferenciar maiusculas e
|
||||
minusculas
|
||||
|
|
|
@ -1,51 +1,44 @@
|
|||
|
||||
var Css = require ('./login.css');
|
||||
require('./login.css');
|
||||
var Tpl = require('./login.xml');
|
||||
|
||||
module.exports = new Class
|
||||
({
|
||||
module.exports = new Class({
|
||||
Extends: Htk.Component,
|
||||
Properties:
|
||||
{
|
||||
conn:
|
||||
{
|
||||
type: Db.Connection
|
||||
,set: function (x)
|
||||
{
|
||||
,set: function(x) {
|
||||
this.link({_conn: x}, {'loading-changed': this._onConnLoadChange});
|
||||
}
|
||||
,get: function ()
|
||||
{
|
||||
,get: function() {
|
||||
return this._conn;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
,initialize: function (props)
|
||||
{
|
||||
,initialize: function(props) {
|
||||
this.parent(props);
|
||||
this.builderInitString(Tpl);
|
||||
|
||||
this.$('social-bar').conn = this._conn;
|
||||
|
||||
var self = this;
|
||||
this.$('form').onsubmit = function ()
|
||||
{
|
||||
this.$('form').onsubmit = function() {
|
||||
self._onSubmit();
|
||||
return false;
|
||||
};
|
||||
}
|
||||
|
||||
,_onConnLoadChange: function (conn, isLoading)
|
||||
{
|
||||
,_onConnLoadChange: function(conn, isLoading) {
|
||||
if (isLoading)
|
||||
this.$('spinner').start();
|
||||
else
|
||||
this.$('spinner').stop();
|
||||
}
|
||||
|
||||
,show: function ()
|
||||
{
|
||||
,show: function() {
|
||||
document.body.appendChild(this.node);
|
||||
|
||||
var lastUser = localStorage.getItem('hederaLastUser');
|
||||
|
@ -56,8 +49,7 @@ module.exports = new Class
|
|||
this._focusUserInput();
|
||||
}
|
||||
|
||||
,_onSubmit: function ()
|
||||
{
|
||||
,_onSubmit: function() {
|
||||
this._conn.open(
|
||||
this.$('user').value,
|
||||
this.$('pass').value,
|
||||
|
@ -67,48 +59,40 @@ module.exports = new Class
|
|||
this._disableUi(true);
|
||||
}
|
||||
|
||||
,_onConnOpen: function (conn, success, error)
|
||||
{
|
||||
,_onConnOpen: function(conn, success, error) {
|
||||
this.$('pass').value = '';
|
||||
this._disableUi(false);
|
||||
|
||||
if (success)
|
||||
{
|
||||
if (success) {
|
||||
var user = this.$('user').value;
|
||||
|
||||
if (user)
|
||||
localStorage.setItem('hederaLastUser', user);
|
||||
|
||||
this.signalEmit('login');
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
this._focusUserInput();
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
,hide: function ()
|
||||
{
|
||||
,hide: function() {
|
||||
Vn.Node.remove(this.node);
|
||||
}
|
||||
|
||||
,_focusUserInput: function ()
|
||||
{
|
||||
,_focusUserInput: function() {
|
||||
var userEntry = this.$('user');
|
||||
userEntry.focus();
|
||||
userEntry.select();
|
||||
}
|
||||
|
||||
,_disableUi: function (disabled)
|
||||
{
|
||||
,_disableUi: function(disabled) {
|
||||
this.$('user').disabled = disabled;
|
||||
this.$('pass').disabled = disabled;
|
||||
this.$('submit').disabled = disabled;
|
||||
}
|
||||
|
||||
,onPasswordLost: function ()
|
||||
{
|
||||
,onPasswordLost: function() {
|
||||
var user = this.$('user').value;
|
||||
|
||||
if (!user)
|
||||
|
@ -118,8 +102,7 @@ module.exports = new Class
|
|||
this._onPasswordRecovered.bind(this));
|
||||
}
|
||||
|
||||
,_onPasswordRecovered: function (json, error)
|
||||
{
|
||||
,_onPasswordRecovered: function(json, error) {
|
||||
if (error)
|
||||
throw error;
|
||||
|
||||
|
|
|
@ -5,8 +5,7 @@ var JsonException = require ('./json-exception');
|
|||
/**
|
||||
* Handler for JSON rest connections.
|
||||
**/
|
||||
module.exports = new Class
|
||||
({
|
||||
module.exports = new Class({
|
||||
Extends: Object
|
||||
|
||||
,_connected: false
|
||||
|
@ -16,14 +15,12 @@ module.exports = new Class
|
|||
/**
|
||||
* Initilizes the connection object.
|
||||
**/
|
||||
,initialize: function ()
|
||||
{
|
||||
,initialize: function() {
|
||||
this.parent();
|
||||
this.fetchToken();
|
||||
}
|
||||
|
||||
,fetchToken: function ()
|
||||
{
|
||||
,fetchToken: function() {
|
||||
var token = null;
|
||||
|
||||
if (sessionStorage.getItem('vnToken'))
|
||||
|
@ -34,8 +31,7 @@ module.exports = new Class
|
|||
this.token = token;
|
||||
}
|
||||
|
||||
,clearToken: function ()
|
||||
{
|
||||
,clearToken: function() {
|
||||
this.token = null;
|
||||
localStorage.removeItem('vnToken');
|
||||
sessionStorage.removeItem('vnToken');
|
||||
|
@ -49,30 +45,25 @@ module.exports = new Class
|
|||
* @param {Boolean} remember Specifies if the user should be remembered
|
||||
* @param {Function} openCallback The function to call when operation is done
|
||||
**/
|
||||
,open: function (user, pass, remember, callback)
|
||||
{
|
||||
if (user !== null && user !== undefined)
|
||||
{
|
||||
,open: function(user, pass, remember, callback) {
|
||||
if (user !== null && user !== undefined) {
|
||||
var params = {
|
||||
user: user
|
||||
,password: pass
|
||||
,remember: remember
|
||||
};
|
||||
}
|
||||
else
|
||||
} else
|
||||
var params = null;
|
||||
|
||||
this.send ('core/login', params,
|
||||
this.lbSend('POST', 'Accounts/login', params,
|
||||
this._onOpen.bind(this, callback, remember));
|
||||
}
|
||||
|
||||
/*
|
||||
* Called when open operation is done.
|
||||
*/
|
||||
,_onOpen: function (callback, remember, json, error)
|
||||
{
|
||||
if (json && json.login)
|
||||
{
|
||||
,_onOpen: function(callback, remember, json, error) {
|
||||
if (json) {
|
||||
this._connected = true;
|
||||
this.token = json.token;
|
||||
|
||||
|
@ -80,8 +71,7 @@ module.exports = new Class
|
|||
storage.setItem('vnToken', this.token);
|
||||
|
||||
this.signalEmit('openned');
|
||||
}
|
||||
else
|
||||
} else
|
||||
this._closeClient();
|
||||
|
||||
if (callback)
|
||||
|
@ -93,45 +83,40 @@ module.exports = new Class
|
|||
*
|
||||
* @param {Function} callback The function to call when operation is done
|
||||
**/
|
||||
,close: function (callback)
|
||||
{
|
||||
this._closeClient ();
|
||||
this.send ('core/logout', null,
|
||||
,close: function(callback) {
|
||||
this.lbSend('POST', 'Accounts/logout', null,
|
||||
this._onClose.bind(this, callback));
|
||||
this._closeClient();
|
||||
}
|
||||
|
||||
/*
|
||||
* Called when close operation is done.
|
||||
*/
|
||||
,_onClose: function (callback, json, error)
|
||||
{
|
||||
,_onClose: function(callback, json, error) {
|
||||
this.signalEmit('closed');
|
||||
|
||||
if (callback)
|
||||
callback (this, json === true, error);
|
||||
callback(this, null, error);
|
||||
}
|
||||
|
||||
,_closeClient: function ()
|
||||
{
|
||||
,_closeClient: function() {
|
||||
this._connected = false;
|
||||
this.clearToken();
|
||||
}
|
||||
|
||||
/**
|
||||
* Suppants another user.
|
||||
* Supplants another user.
|
||||
*
|
||||
* @param {String} user The user name
|
||||
* @param {Function} callback The callback function
|
||||
**/
|
||||
,supplantUser: function (user, callback)
|
||||
{
|
||||
,supplantUser: function(user, callback) {
|
||||
var params = {supplantUser: user};
|
||||
this.send ('core/supplant', params,
|
||||
this.send('client/supplant', params,
|
||||
this._onUserSupplant.bind(this, callback));
|
||||
}
|
||||
|
||||
,_onUserSupplant: function (callback, json, error)
|
||||
{
|
||||
,_onUserSupplant: function(callback, json) {
|
||||
if (json)
|
||||
this.token = json;
|
||||
|
||||
|
@ -142,8 +127,8 @@ module.exports = new Class
|
|||
/**
|
||||
* Ends the user supplanting and restores the last login.
|
||||
**/
|
||||
,supplantEnd: function ()
|
||||
{
|
||||
,supplantEnd: function() {
|
||||
this.lbSend('POST', 'Accounts/logout');
|
||||
this.fetchToken();
|
||||
}
|
||||
|
||||
|
@ -155,8 +140,7 @@ module.exports = new Class
|
|||
* @param {Map} params The params to pass to the service
|
||||
* @param {Function} callback The response callback
|
||||
**/
|
||||
,send: function (restService, params, callback)
|
||||
{
|
||||
,send: function(restService, params, callback) {
|
||||
if (!params)
|
||||
params = {};
|
||||
|
||||
|
@ -165,8 +149,7 @@ module.exports = new Class
|
|||
this.sendWithUrl(params, callback, 'POST', '.');
|
||||
}
|
||||
|
||||
,sendForm: function (form, callback)
|
||||
{
|
||||
,sendForm: function(form, callback) {
|
||||
var params = {};
|
||||
var elements = form.elements;
|
||||
|
||||
|
@ -177,15 +160,13 @@ module.exports = new Class
|
|||
this.sendWithUrl(params, callback, 'POST', form.action);
|
||||
}
|
||||
|
||||
,sendFormMultipart: function (form, callback)
|
||||
{
|
||||
,sendFormMultipart: function(form, callback) {
|
||||
var formData = new FormData(form);
|
||||
|
||||
if (this.token)
|
||||
formData.append ('token', this.token);
|
||||
|
||||
var request = new XMLHttpRequest();
|
||||
request.open('POST', form.action, true);
|
||||
if (this.token)
|
||||
request.setRequestHeader('Authorization', this.token);
|
||||
request.onreadystatechange =
|
||||
this._onStateChange.bind(this, request, callback);
|
||||
request.send(formData);
|
||||
|
@ -193,13 +174,11 @@ module.exports = new Class
|
|||
this._addRequest();
|
||||
}
|
||||
|
||||
,sendFormData: function (formData, callback)
|
||||
{
|
||||
if (this.token)
|
||||
formData.append ('token', this.token);
|
||||
|
||||
,sendFormData: function(formData, callback) {
|
||||
var request = new XMLHttpRequest();
|
||||
request.open('POST', '', true);
|
||||
if (this.token)
|
||||
request.setRequestHeader('Authorization', this.token);
|
||||
request.onreadystatechange =
|
||||
this._onStateChange.bind(this, request, callback);
|
||||
request.send(formData);
|
||||
|
@ -210,15 +189,13 @@ module.exports = new Class
|
|||
/*
|
||||
* Called when REST response is received.
|
||||
*/
|
||||
,sendWithUrl: function (params, callback, method, url)
|
||||
{
|
||||
if (this.token)
|
||||
params['token'] = this.token;
|
||||
|
||||
,sendWithUrl: function(params, callback, method, url) {
|
||||
var request = new XMLHttpRequest();
|
||||
request.open(method, url, true);
|
||||
request.setRequestHeader('Content-Type',
|
||||
'application/x-www-form-urlencoded');
|
||||
if (this.token)
|
||||
request.setRequestHeader('Authorization', this.token);
|
||||
request.onreadystatechange =
|
||||
this._onStateChange.bind(this, request, callback);
|
||||
request.send(Vn.Url.makeUri(params));
|
||||
|
@ -226,16 +203,28 @@ module.exports = new Class
|
|||
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++;
|
||||
|
||||
if (this._requestsCount === 1)
|
||||
this.signalEmit('loading-changed', true);
|
||||
}
|
||||
|
||||
,_onStateChange: function (request, callback)
|
||||
{
|
||||
,_onStateChange: function(request, callback) {
|
||||
if (request.readyState !== 4)
|
||||
return;
|
||||
|
||||
|
@ -248,8 +237,7 @@ module.exports = new Class
|
|||
var error = null;
|
||||
|
||||
try {
|
||||
if (request.status == 0)
|
||||
{
|
||||
if (request.status == 0) {
|
||||
var ex = new JsonException();
|
||||
ex.message = _('The server does not respond, please check your Internet connection');
|
||||
throw ex;
|
||||
|
@ -262,30 +250,32 @@ module.exports = new Class
|
|||
.getResponseHeader('Content-Type')
|
||||
.split(';')[0]
|
||||
.trim();
|
||||
} catch (err) {
|
||||
console.warn(err);
|
||||
}
|
||||
catch (e) {}
|
||||
|
||||
if (contentType != 'application/json')
|
||||
{
|
||||
if (contentType != 'application/json') {
|
||||
var ex = new JsonException();
|
||||
ex.message = request.statusText;
|
||||
ex.code = request.status;
|
||||
throw ex;
|
||||
}
|
||||
|
||||
var json = JSON.parse (request.responseText);
|
||||
var jsData = json.data;
|
||||
//var jsWarns = json.warnings;
|
||||
var json;
|
||||
var jsData;
|
||||
|
||||
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;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
var exception = jsData.exception;
|
||||
var error = jsData.error;
|
||||
|
||||
if (exception)
|
||||
if (exception) {
|
||||
exception = exception
|
||||
.replace(/\\/g, '.')
|
||||
.replace(/Exception$/, '')
|
||||
|
@ -298,11 +288,17 @@ module.exports = new Class
|
|||
ex.file = jsData.file;
|
||||
ex.line = jsData.line;
|
||||
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;
|
||||
}
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
} catch (e) {
|
||||
data = null;
|
||||
error = e;
|
||||
}
|
||||
|
@ -311,14 +307,11 @@ module.exports = new Class
|
|||
try {
|
||||
callback(data, error);
|
||||
error = null;
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
} catch (e) {
|
||||
error = e;
|
||||
}
|
||||
|
||||
if (error)
|
||||
{
|
||||
if (error) {
|
||||
if (error.exception == 'SessionExpired')
|
||||
this.clearToken();
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "hedera-web",
|
||||
"version": "1.407.66",
|
||||
"version": "1.407.67",
|
||||
"description": "Verdnatura web page",
|
||||
"license": "GPL-3.0",
|
||||
"repository": {
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
</vn-group>
|
||||
<div id="report" class="sheet">
|
||||
<h2>
|
||||
@<htk-text column="id" form="ticket"/>
|
||||
#<htk-text column="id" form="ticket"/>
|
||||
</h2>
|
||||
<div class="header">
|
||||
<div>
|
||||
|
|
|
@ -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']);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
<?php
|
||||
|
||||
class Logout extends Vn\Web\JsonRequest {
|
||||
function run($db) {
|
||||
$this->service->logout();
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
|
@ -7,4 +7,3 @@ class Supplant extends Vn\Web\JsonRequest {
|
|||
return $this->service->createToken($_REQUEST['supplantUser']);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
105
rest/dms/add.php
105
rest/dms/add.php
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -31,13 +31,12 @@ class RestService extends Service {
|
|||
$_REQUEST['method'], $class, './rest');
|
||||
$method->service = $this;
|
||||
|
||||
if ($method::SECURITY == Security::DEFINER) {
|
||||
$isAuthorized = $db->getValue('SELECT myUser_checkRestPriv(#)',
|
||||
[$_REQUEST['method']]);
|
||||
|
||||
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;
|
||||
} else
|
||||
$methodDb = $this->getUserDb($_SESSION['user']);
|
||||
|
@ -71,6 +70,8 @@ class RestService extends Service {
|
|||
$status = 401;
|
||||
} catch (BadLoginException $e) {
|
||||
$status = 401;
|
||||
} catch (ForbiddenException $e) {
|
||||
$status = 403;
|
||||
} catch (Lib\UserException $e) {
|
||||
$status = 400;
|
||||
} catch (\Exception $e) {
|
||||
|
|
111
web/service.php
111
web/service.php
|
@ -2,6 +2,8 @@
|
|||
|
||||
namespace Vn\Web;
|
||||
|
||||
include __DIR__.'/uid.php';
|
||||
|
||||
use Vn\Db;
|
||||
use Vn\Lib\Locale;
|
||||
use Vn\Lib\UserException;
|
||||
|
@ -21,6 +23,11 @@ class SessionExpiredException extends UserException {}
|
|||
*/
|
||||
class BadLoginException extends UserException {}
|
||||
|
||||
/**
|
||||
* Thrown when user credentials are invalid.
|
||||
*/
|
||||
class ForbiddenException extends UserException {}
|
||||
|
||||
/**
|
||||
* Thrown when user credentials are invalid.
|
||||
*/
|
||||
|
@ -130,62 +137,26 @@ abstract class Service {
|
|||
*/
|
||||
function login() {
|
||||
$db = $this->db;
|
||||
$anonymousUser = FALSE;
|
||||
$anonymousUser = TRUE;
|
||||
|
||||
if (isset($_POST['user']) && !empty($_POST['password'])) {
|
||||
$user = strtolower($_POST['user']);
|
||||
|
||||
$passwordHash = $db->getValue(
|
||||
'SELECT bcryptPassword FROM account.user WHERE `name` = #',
|
||||
[$user]
|
||||
if (!empty($_SERVER['HTTP_AUTHORIZATION'])) {
|
||||
$userId = $db->getValue(
|
||||
'SELECT userId FROM salix.AccessToken
|
||||
WHERE id = #
|
||||
AND NOW() <= TIMESTAMPADD(SECOND, ttl, created)',
|
||||
[$_SERVER['HTTP_AUTHORIZATION']]
|
||||
);
|
||||
|
||||
$passwordOk = !empty($passwordHash)
|
||||
&& 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())
|
||||
if (!$userId)
|
||||
throw new SessionExpiredException();
|
||||
|
||||
$user = $jwtPayload['sub'];
|
||||
}
|
||||
else {
|
||||
$anonymousUser = FALSE;
|
||||
$user = $db->getValue(
|
||||
'SELECT `name` FROM account.user WHERE id = #',
|
||||
[$userId]
|
||||
);
|
||||
} else
|
||||
$user = $db->getValue('SELECT guestUser FROM config');
|
||||
$anonymousUser = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$anonymousUser) {
|
||||
$isActive = $db->getValue(
|
||||
|
@ -217,6 +188,12 @@ abstract class Service {
|
|||
* Logouts the current user. Cleans the last saved used credentials.
|
||||
*/
|
||||
function logout() {
|
||||
if (!empty($_SERVER['HTTP_AUTHORIZATION']))
|
||||
$db->query(
|
||||
'DELETE FROM salix.AccessToken WHERE id = #',
|
||||
[$_SERVER['HTTP_AUTHORIZATION']]
|
||||
);
|
||||
|
||||
unset($_SESSION['user']);
|
||||
}
|
||||
|
||||
|
@ -248,15 +225,45 @@ abstract class Service {
|
|||
return $userDb;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a authentication token for the specified $user.
|
||||
*
|
||||
* @param {string} $user The user name
|
||||
* @param {boolean} $remember Wether to create long live token
|
||||
* @return {string} The generated token
|
||||
*/
|
||||
function createToken($user, $remember = FALSE) {
|
||||
if ($remember)
|
||||
$tokenLife = 2 * WEEK;
|
||||
else
|
||||
$tokenLife = 30 * MIN;
|
||||
|
||||
$token = uid(DEFAULT_TOKEN_LEN);
|
||||
$userId = $this->db->getValue(
|
||||
'SELECT id FROM account.user WHERE `name` = #',
|
||||
[$user]
|
||||
);
|
||||
|
||||
$this->db->query(
|
||||
'INSERT INTO salix.AccessToken
|
||||
SET id = #,
|
||||
ttl = #,
|
||||
created = NOW(),
|
||||
userId = #',
|
||||
[$token, $tokenLife, $userId]
|
||||
);
|
||||
|
||||
return $token;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a JWT authentication token for the specified $user.
|
||||
*
|
||||
* @param {string} $user The user name
|
||||
* @param {boolean} $remember Wether to create long live token
|
||||
* @param {boolean} $recover Wether to enable recovery mode on login
|
||||
* @return {string} The JWT generated token
|
||||
*/
|
||||
function createToken($user, $remember = FALSE) {
|
||||
function createJwtToken($user, $remember = FALSE) {
|
||||
if ($remember)
|
||||
$tokenLife = WEEK;
|
||||
else
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
<?php
|
||||
|
||||
namespace Vn\Web;
|
||||
|
||||
const DEFAULT_TOKEN_LEN = 64;
|
||||
const UIDCHARS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_';
|
||||
|
||||
function uid($length) {
|
||||
$bytes = bin2hex(random_bytes($length));
|
||||
$r = '';
|
||||
for ($i = 0; $i < $length; $i++)
|
||||
$r .= UIDCHARS[hexdec(substr($bytes, $i * 2, 2)) % 64];
|
||||
return $r;
|
||||
}
|
|
@ -79,7 +79,14 @@ var devConfig = {
|
|||
host: '0.0.0.0',
|
||||
port: wpConfig.devServerPort,
|
||||
headers: {'Access-Control-Allow-Origin': '*'},
|
||||
stats: { chunks: false }
|
||||
stats: { chunks: false },
|
||||
proxy: {
|
||||
'/api': 'http://localhost:3000',
|
||||
'/': {
|
||||
target: 'http://localhost/projects/hedera-web',
|
||||
bypass: (req) => req.path !== '/' ? req.path : null
|
||||
}
|
||||
}
|
||||
},
|
||||
devtool: 'eval'
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue