0
1
Fork 0
This commit is contained in:
Juan Ferrer Toribio 2016-10-04 17:27:49 +02:00
parent 6988bb9f84
commit 66bb2a57f2
32 changed files with 507 additions and 355 deletions

3
app.js
View File

@ -1,6 +1,5 @@
var Hedera = require ('hedera/hedera');
Vn.includeCss ('pages/main/style.css');
window.onload = function ()
{
@ -25,7 +24,7 @@ function loadLocale (lang, cb)
switch (lang)
{
case 'ca':
require ([], function (){
require ([], function () {
cb (require.context ('locale/ca/js')); });
break;
case 'es':

View File

@ -7,7 +7,7 @@ Hedera.Address = new Class
{
this.$('model').setInfo ('a', 'address_view', 'hedera', ['id'], 'id');
this.$('model').setDefault ('customer_id', 'a',
new Sql.Func ({schema: 'account', name: 'user_get_id'}));
new Sql.Function ({schema: 'account', name: 'user_get_id'}));
}
,onStatusChange: function (form)

View File

@ -36,11 +36,11 @@ Hedera.Connections = new Class
,onChangeUserClick: function (button, form)
{
this.gui.supplantUser (form.get ('user_id'),
this.onUserSupplant.bind (this));
this.gui.supplantUser (form.get ('user'),
this._onUserSupplant.bind (this));
}
,onUserSupplant: function (userName)
,_onUserSupplant: function (userName)
{
this.hash.set ({'form': 'ecomerce/orders'});
}

View File

@ -23,9 +23,9 @@
<db-model property="model" id="sessions" on-status-changed="onModelStatusChange">
<custom>
SELECT s.id, e.user_id, c.Cliente, e.date_time login, is_new,
s.date_time last_activity, a.platform, a.browser, a.version
FROM user_session s
JOIN visit_user e ON s.visit_user_id = e.id
s.lastUpdate last_activity, a.platform, a.browser, a.version, u.name user
FROM userSession s
JOIN visit_user e ON s.userVisit = e.id
JOIN visit_access c ON e.access_id = c.id
JOIN visit_agent a ON c.agent_id = a.id
JOIN visit v ON a.visit_id = v.id

View File

@ -2,41 +2,50 @@
Hedera.Shelves = new Class
({
Extends: Hedera.Form
,activate: function ()
{
this.$('date').value = new Date ();
}
,onConfigChange: function ()
{
var c = this.$('config');
this.$('warehouse').value = c.get ('warehouse_id');
this.$('shelf').value = c.get ('shelf_id');
this.$('reign').value = c.get ('reino_id');
this.$('family').value = c.get ('family_id');
this.$('filter').value = c.get ('name_prefix');
this.$('max-amount').value = c.get ('max_amount');
this.$('show-packing').value = c.get ('show_packing');
this.$('stack').value = c.get ('stack');
this.$('report-title').value = c.get ('name');
var fields = [
'realm'
,'family'
,'warehouse'
,'shelf'
,'namePrefix'
,'maxAmount'
,'reportTitle'
,'showPacking'
,'stack'
];
for (var i = 0; i < fields.length; i++)
this.$(fields[i]).value = this.$('config').get (fields[i]);
}
,onPreviewClick: function ()
{
var batch = new Sql.Batch ();
batch.addValues ({
'shelf': this.$('shelf').value,
'wh': this.$('warehouse').value,
'date': this.$('date').value,
'family': this.$('family').value,
'filter': this.$('filter').value,
'title': this.$('report-title').value,
'max-amount': this.$('max-amount').value,
'show-packing': this.$('show-packing').value,
'stack': this.$('stack').value,
'use-ids': this.$('use-ids').value,
});
{
var fields = [
'family'
,'warehouse'
,'shelf'
,'namePrefix'
,'maxAmount'
,'reportTitle'
,'showPacking'
,'stack'
,'useIds'
,'date'
];
var batch = new Sql.Batch ();
for (var i = 0; i < fields.length; i++)
batch.addValue (fields[i], this.$(fields[i]).value);
this.gui.openReport ('shelves-report', batch);
}
});

View File

@ -2,10 +2,10 @@
<vn-group>
<db-model property="model" id="configs-model">
<custom>
SELECT c.id, c.name, c.name_prefix, c.warehouse_id, c.family_id,
c.shelf_id, c.max_amount, c.show_packing, c.stack, t.reino_id
FROM shelf_config c
JOIN vn2008.Tipos t ON t.tipo_id = c.family_id
SELECT c.id, c.name reportTitle, c.namePrefix, c.warehouse, c.family,
c.shelf, c.maxAmount, c.showPacking, c.stack, t.reino_id realm
FROM shelfConfig c
JOIN vn2008.Tipos t ON t.tipo_id = c.family
</custom>
</db-model>
</vn-group>
@ -36,8 +36,8 @@
</div>
<div class="form-group">
<label><t>Reign</t></label>
<htk-combo id="reign">
<db-model property="model" id="reigns">
<htk-combo id="realm">
<db-model property="model" id="realms">
<custom>
SELECT id, reino FROM vn2008.reinos
WHERE display != FALSE ORDER BY reino
@ -51,11 +51,11 @@
<db-model property="model">
<custom>
SELECT tipo_id, Tipo FROM vn2008.Tipos
WHERE reino_id = #reign ORDER BY Tipo
WHERE reino_id = #realm ORDER BY Tipo
</custom>
<sql-batch property="batch">
<custom>
<item name="reign" param="reign"/>
<item name="realm" param="realm"/>
</custom>
</sql-batch>
</db-model>
@ -84,19 +84,19 @@
</div>
<div class="form-group">
<label><t>Name prefix</t></label>
<htk-entry id="filter"/>
<htk-entry id="namePrefix"/>
</div>
<div class="form-group">
<label><t>Limit amount per item</t></label>
<htk-entry id="max-amount"/>
<htk-entry id="maxAmount"/>
</div>
<div class="form-group">
<label><t>Title</t></label>
<htk-entry id="report-title"/>
<htk-entry id="reportTitle"/>
</div>
<div class="form-group">
<label><t>Show packing</t></label>
<htk-check id="show-packing"/>
<htk-check id="showPacking"/>
</div>
<div class="form-group">
<label><t>Stack different items</t></label>
@ -104,7 +104,7 @@
</div>
<div class="form-group">
<label><t>Use ids instead of names</t></label>
<htk-check id="use-ids"/>
<htk-check id="useIds"/>
</div>
</div>
</div>

View File

@ -35,13 +35,13 @@
form="iter"
column="id"
tip="_AccessAsUser"
image="image/incognito.svg"
icon="incognito"
on-click="onChangeUserClick"/>
<htk-button
form="iter"
column="id"
tip="_AccessLog"
image="image/gnome.svg"
icon="gnome"
on-click="onAccessLogClick"/>
<p class="important">
<htk-text form="iter" column="Cliente"/>

View File

@ -13,7 +13,7 @@ Hedera.Users = new Class
,onChangeUserClick: function (button, form)
{
this.gui.supplantUser (form.get ('id'),
this.gui.supplantUser (form.get ('name'),
this.onUserSupplant.bind (this));
}

View File

@ -500,8 +500,8 @@ Vn.Filter = new Class
icon: 'close',
alt: _('Close')
});
button.appendChild (icon);
button.appendChild (icon.node);
var text = this._label = document.createTextNode ('');
li.appendChild (text);

View File

@ -215,7 +215,7 @@
<htk-popup id="success-dialog" modal="true" on-closed="onPopupClose">
<div property="child-node" class="dialog">
<div>
<img src="image/ok.svg" alt="_Ok"/>
<htk-icon icon="ok" alt="_Ok"/>
<p><t>Order confirmed successfully</t></p>
<div class="clear"/>
</div>

View File

@ -10,7 +10,7 @@ Hedera.New = new Class
{
this.$('model').mode = Db.Model.Mode.ON_DEMAND;
this.$('model').setDefault ('user_id', 'news',
new Sql.Func ({schema: 'account', name: 'user_get_id'}));
new Sql.Function ({schema: 'account', name: 'userGetId'}));
this.$('html-editor').id = 'html-editor';
tinymce.init ({
@ -72,4 +72,3 @@ Hedera.New = new Class
});
});

View File

@ -1219,7 +1219,7 @@ Model.implement
if (pkValue)
equalOp.exprs.add (new Sql.Value ({value: pkValue}));
else if (column.flags & Connection.Flag.AI && !useOldValues)
equalOp.exprs.add (new Sql.Func ({name: 'LAST_INSERT_ID'}));
equalOp.exprs.add (new Sql.Function ({name: 'LAST_INSERT_ID'}));
else
return null;
}

View File

@ -15,14 +15,12 @@ module.exports = new Class
this.link ({_conn: x},
{'loading-changed': this._onConnLoadChange });
var sql = 'SELECT default_form, image_dir, image_host FROM config;'
+'SELECT production_domain, test_domain FROM config;'
+'SELECT name FROM customer_user;'
+'CALL form_list ();';
var sql = 'SELECT name FROM customer_user;'
+'SELECT default_form, image_dir, image_host FROM config;'
+'SELECT production_domain, test_domain FROM config;';
x.execQuery (sql, this.onMainQueryDone.bind (this));
if (Vn.Cookie.check ('hedera_supplant'))
this.supplantUser (Vn.Cookie.get ('hedera_supplant'));
this.loadMenu ();
}
,get: function ()
{
@ -45,7 +43,6 @@ module.exports = new Class
,initialize: function (props)
{
this.builderInitString (Tpl);
this.loadingCount = 0;
this.$('background').onclick = function () {};
@ -133,6 +130,11 @@ module.exports = new Class
,onMainQueryDone: function (resultSet)
{
// Retrieving the user name
var userName = resultSet.fetchValue ();
Vn.Node.setText (this.$('user-name'), userName);
// Retrieving configuration parameters
var res = resultSet.fetchResult ();
@ -165,16 +167,19 @@ module.exports = new Class
else
Vn.Node.hide (this.$('test-link'));
// Retrieving the user name
// Loading the default form
var userName = resultSet.fetchValue ();
if (userName)
{
var span = this.$('user-name');
span.appendChild (document.createTextNode (userName));
}
this._onFormChange ();
}
,loadMenu: function ()
{
var sql = 'CALL form_list ()';
this._conn.execQuery (sql, this._onMenuLoad.bind (this));
}
,_onMenuLoad: function (resultSet)
{
// Retrieving menu sections
var res = resultSet.fetchResult ();
@ -191,105 +196,10 @@ module.exports = new Class
sectionMap[parent].push (i);
}
Vn.Node.removeChilds (this.$('main-menu'));
this.createMenu (res, sectionMap, null, this.$('main-menu'));
// Loading the default form
this._onFormChange ();
}
//++++++++++++++++++++++++++++++++++++++++++++++++++++++ Navigation bar
,_onScroll: function ()
{
if (this._scrollTimeout === null)
this._scrollTimeout = setTimeout (
this._scrollTimeoutFunc.bind (this), 150);
}
,_scrollTimeoutFunc: function ()
{
if (!this._shown)
return;
var navbar = this.$('top-bar');
var yOffset = Vn.Browser.getPageYOffset ();
var showNavbar = this._lastYOffset > yOffset || yOffset < navbar.offsetHeight;
if (showNavbar !== this._navbarVisible)
{
if (showNavbar)
var translateY = 0;
else
var translateY = -navbar.offsetHeight;
navbar.style.transform =
'translateZ(0) translateY('+ translateY +'px)';
}
this._navbarVisible = showNavbar;
this._lastYOffset = yOffset;
this._scrollTimeout = null;
}
//++++++++++++++++++++++++++++++++++++++++++++++++++++++ Background
,showBackground: function ()
{
Vn.Node.addClass (this.$('background'), 'show');
}
,hideBackground: function ()
{
Vn.Node.removeClass (this.$('background'), 'show');
}
//++++++++++++++++++++++++++++++++++++++++++++++++++++++ Menu
,showMenu: function ()
{
this.showBackground ();
Vn.Node.addClass (this.$('left-panel'), 'show');
this.menuShown = true;
this.hideMenuCallback = this.hideMenu.bind (this);
document.addEventListener ('click', this.hideMenuCallback);
}
,hideMenu: function ()
{
if (!this.menuShown)
return;
this.hideBackground ();
Vn.Node.removeClass (this.$('left-panel'), 'show');
this.menuShown = false;
document.removeEventListener ('click', this.hideMenuCallback);
this.hideMenuCallback = null;
}
//++++++++++++++++++++++++++++++++++++++++++++++++++++++ Spinner
,loaderPush: function ()
{
this.loadingCount++;
if (this.loadingCount == 1)
this.$('loader').start ();
}
,loaderPop: function ()
{
if (this.loadingCount == 0)
return;
this.loadingCount--;
if (this.loadingCount == 0)
this.$('loader').stop ();
}
//++++++++++++++++++++++++++++++++++++++++++++++++++++++ Menu
,createMenu: function (res, sectionMap, parent, ul)
@ -362,6 +272,96 @@ module.exports = new Class
this.timeout = 0;
}
}
,showMenu: function ()
{
this.showBackground ();
Vn.Node.addClass (this.$('left-panel'), 'show');
this.menuShown = true;
this.hideMenuCallback = this.hideMenu.bind (this);
document.addEventListener ('click', this.hideMenuCallback);
}
,hideMenu: function ()
{
if (!this.menuShown)
return;
this.hideBackground ();
Vn.Node.removeClass (this.$('left-panel'), 'show');
this.menuShown = false;
document.removeEventListener ('click', this.hideMenuCallback);
this.hideMenuCallback = null;
}
//++++++++++++++++++++++++++++++++++++++++++++++++++++++ Navigation bar
,_onScroll: function ()
{
if (this._scrollTimeout === null)
this._scrollTimeout = setTimeout (
this._scrollTimeoutFunc.bind (this), 150);
}
,_scrollTimeoutFunc: function ()
{
if (!this._shown)
return;
var navbar = this.$('top-bar');
var yOffset = Vn.Browser.getPageYOffset ();
var showNavbar = this._lastYOffset > yOffset || yOffset < navbar.offsetHeight;
if (showNavbar !== this._navbarVisible)
{
if (showNavbar)
var translateY = 0;
else
var translateY = -navbar.offsetHeight;
navbar.style.transform =
'translateZ(0) translateY('+ translateY +'px)';
}
this._navbarVisible = showNavbar;
this._lastYOffset = yOffset;
this._scrollTimeout = null;
}
//++++++++++++++++++++++++++++++++++++++++++++++++++++++ Background
,showBackground: function ()
{
Vn.Node.addClass (this.$('background'), 'show');
}
,hideBackground: function ()
{
Vn.Node.removeClass (this.$('background'), 'show');
}
//++++++++++++++++++++++++++++++++++++++++++++++++++++++ Spinner
,loaderPush: function ()
{
this.loadingCount++;
if (this.loadingCount == 1)
this.$('loader').start ();
}
,loaderPop: function ()
{
if (this.loadingCount == 0)
return;
this.loadingCount--;
if (this.loadingCount == 0)
this.$('loader').stop ();
}
//++++++++++++++++++++++++++++++++++++++++++++++++++++++ Forms
@ -501,50 +501,38 @@ module.exports = new Class
//++++++++++++++++++++++++++++++++++++++++++++++++++++++ Supplant
,supplantUser: function (userId, callback)
,supplantUser: function (user, callback)
{
var batch = new Sql.Batch ();
batch.addValue ('user', userId);
var query = 'UPDATE user_session_view SET user_id = #user;'+
'SELECT Cliente FROM vn2008.Clientes WHERE Id_cliente = #user';
this._conn.execQuery (query,
this._onUserSupplant.bind (this, userId, callback), batch);
this._conn.supplantUser (user,
this._onUserSupplant.bind (this, callback));
}
,_onUserSupplant: function (userId, callback, resultSet)
,_onUserSupplant: function (callback, supplantOk)
{
this._supplantClear ();
Vn.Cookie.set ('hedera_supplant', userId);
if (!supplantOk)
return;
resultSet.fetchResult ();
var userName = resultSet.fetchValue ();
Vn.Node.setText (this.$('supplanted'), userName);
Vn.Node.show (this.$('supplant'));
this.loadMenu ();
var sql = 'SELECT name FROM customer_user';
this._conn.execQuery (sql, this._onSupplantName.bind (this));
if (callback)
callback ();
}
,_supplantClear: function ()
,_onSupplantName: function (resultSet)
{
if (Vn.Cookie.check ('hedera_supplant'))
{
Vn.Node.hide (this.$('supplant'));
Vn.Cookie.unset ('hedera_supplant');
}
var userName = resultSet.fetchValue ();
Vn.Node.setText (this.$('supplanted'), userName);
Vn.Node.show (this.$('supplant'));
}
,onSupplantExitClick: function ()
{
var query = 'UPDATE user_session_view SET user_id = account.user_get_id ()'
this._conn.execQuery (query, this.supplantExit.bind (this));
}
,supplantExit: function ()
{
this._supplantClear ();
Vn.Node.hide (this.$('supplant'));
this._conn.supplantEnd ();
this.loadMenu ();
this._onFormChange ();
}

View File

@ -1,10 +1,4 @@
body
{
overflow: auto;
height: 100%;
}
.vn-login
{
color: #333;
@ -55,12 +49,11 @@ body
{
position: absolute;
padding: 1em;
max-width: 15em;
max-width: 16em;
top: 50%;
left: 50%;
margin-top: -20em;
margin-left: -8.5em;
margin-left: -9em;
}
@media (max-height: 630px)
{

View File

@ -71,9 +71,15 @@
body
{
color: #333;
font-family: 'Roboto', 'Verdana', 'Sans';
background-color: #EEE;
color: #333;
position: absolute;
height: 100%;
width: 100%;
margin: 0;
overflow: auto;
z-index: -2;
}
label,
button,

View File

@ -7,7 +7,7 @@ Sql = module.exports = {
,Batch : require ('./batch')
,List : require ('./list')
,Expr : require ('./expr')
,Valuee : require ('./value')
,Value : require ('./value')
,Field : require ('./field')
,Function : require ('./function')
,Operation : require ('./operation')

View File

@ -34,7 +34,13 @@ module.exports = new Class
if (index !== undefined)
return result.objects[index];
else if (this._parentResult)
var object = this._addedMap[objectId];
if (object !== undefined)
return object;
if (this._parentResult)
return this._parentResult.getById (objectId);
return null;
@ -150,12 +156,14 @@ module.exports = new Class
{
var l = this._links[i];
var addedObject = this._addedMap[l.objectId];
if (addedObject)
{
if (l.prop)
objects[l.context.id][l.prop] = addedObject;
else
objects[l.context.id].appendChild (addedObject);
}
else
this._showError ('Referenced unexistent object with id \'%s\'',
l.objectId);
@ -190,7 +198,7 @@ module.exports = new Class
for (var i = this._links.length - 1; i >= 0; i--)
{
var l = this._links[i];
var contextId = this._contextMap[l.objectId]
var contextId = this._contextMap[l.objectId];
if (contextId != undefined)
{

View File

@ -19,17 +19,21 @@ module.exports = new Class
,initialize: function ()
{
this.parent ();
if (localStorage.getItem ('vnToken'))
this._token = localStorage.getItem ('vnToken');
this._token = this.fetchToken ();
}
,fetchToken: function ()
{
if (sessionStorage.getItem ('vnToken'))
this._token = sessionStorage.getItem ('vnToken');
return sessionStorage.getItem ('vnToken');
if (localStorage.getItem ('vnToken'))
return localStorage.getItem ('vnToken');
}
/**
* Opens the connection to the REST service.
*
* @param {string} user The user name
* @param {String} user The user name
* @param {String} password The user password
* @param {Boolean} remember Specifies if the user should be remembered
* @param {Function} openCallback The function to call when operation is done
@ -105,6 +109,40 @@ module.exports = new Class
sessionStorage.removeItem ('vnToken');
}
/**
* Suppants another user.
*
* @param {String} user The user name
* @param {Function} callback The callback function
**/
,supplantUser: function (user, callback)
{
var params = {'supplantUser': user};
this.send ('core/supplant', params,
this._onUserSupplant.bind (this, callback));
}
,_onUserSupplant: function (callback, json, error)
{
if (json)
{
this._token = json;
this._isSupplant = true;
}
if (callback)
callback (json != null);
}
/**
* Ends the user supplanting and restores the last login.
**/
,supplantEnd: function ()
{
this._isSupplant = false;
this._token = this.fetchToken ();
}
/**
* Executes the specified REST service with the given params and calls
* the callback when response is received.

View File

@ -21,7 +21,8 @@ module.exports =
Vn.Node.removeChilds (node);
if (text)
node.appendChild (document.createTextNode (text));
node.appendChild (
node.ownerDocument.createTextNode (text));
}
,addClass: function (node, className)

View File

@ -0,0 +1,5 @@
{
"Start": "Start"
,"End": "End"
,"Pallet": "Pallet"
}

View File

@ -0,0 +1,5 @@
{
"Start": "Inicio"
,"End": "Fin"
,"Pallet": "Palé"
}

View File

@ -10,13 +10,15 @@
"style-loader": "*",
"file-loader": "*",
"json-loader": "*",
"raw-loader": "*"
"raw-loader": "*",
"bundle-loader": "*"
},
"dependencies": {
"mootools": "^1.5.2",
"tinymce": "^4.4.3"
},
"scripts": {
"dev": "webpack-dev-server --devtool eval --inline --progress --colors"
"dev": "webpack-dev-server --progress --colors --inline --hot",
"build": "rm build/* ; webpack --progress --colors"
}
}

View File

@ -12,7 +12,7 @@ if ($result = $db->query ('SELECT name, content FROM metatag'))
$result->free ();
}
if (DEBUG_MODE)
if (_DEBUG_MODE)
{
$this->includeJs ('http://localhost:8080/webpack-dev-server.js');
$this->includeJs ('http://localhost:8080/build/hedera-web.js');

View File

@ -1,11 +0,0 @@
body
{
position: absolute;
height: 100%;
width: 100%;
z-index: -2;
background-color: #EEE;
overflow: hidden;
}

View File

@ -5,21 +5,22 @@ Hedera.ShelvesReport = new Class
,nItem: -1
,nColors: 5
,trayThickness: 2
,trayMargin: 5
,open: function (batch)
{
this.batch = batch;
this.title = batch.getValue ('title');
this.maxAmount = batch.getValue ('max-amount');
this.showPacking = batch.getValue ('show-packing');
this.title = batch.getValue ('reportTitle');
this.maxAmount = batch.getValue ('maxAmount');
this.showPacking = batch.getValue ('showPacking');
this.stack = batch.getValue ('stack');
this.useIds = batch.getValue ('use-ids');
this.useIds = batch.getValue ('useIds');
var query =
'SELECT id, name, width, height, depth, max_height, tray_height, '+
'first_tray_elevation, tray_density, vspacing, hspacing '+
'SELECT id, name, nTrays, topTrayHeight, trayHeight, width, depth '+
'FROM shelf WHERE id = #shelf; '+
'CALL itemAllocator (#wh, #date, #family, #filter, #use-ids)';
'CALL itemAllocator (#warehouse, #date, #family, #namePrefix, #useIds)';
this.conn.execQuery (query, this.onQueryExec.bind (this), this.batch);
}
@ -33,29 +34,28 @@ Hedera.ShelvesReport = new Class
// Calculates the scale
var maxWidth = 170;
var maxHeight = 200;
var maxWidth = 160;
var maxHeight = 160;
var scale = maxWidth / res.get ('width');
var shelfWidth = res.get ('width');
var shelfHeight = res.get ('trayHeight') * (res.get ('nTrays') - 1) + res.get ('topTrayHeight');
if (res.get ('max_height') * scale > maxHeight)
scale = maxHeight / res.get ('max_height');
var scale = maxWidth / shelfWidth;
if (shelfHeight * scale > maxHeight)
scale = maxHeight / shelfHeight;
// Gets the shelf dimensions
// Calculates the shelf dimensions
var shelf = this.shelf =
{
width: res.get ('width') * scale
,height: res.get ('height') * scale
nTrays: res.get ('nTrays')
,trayHeight: res.get ('trayHeight') * scale
,topTrayHeight: res.get ('topTrayHeight') * scale
,width: res.get ('width') * scale
,depth: res.get ('depth') * scale
,maxHeight: res.get ('max_height') * scale
,trayHeight: res.get ('tray_height') * scale
,firstTrayElevation: res.get ('first_tray_elevation') * scale
,trayDensity: res.get ('tray_density') * scale
,vspacing: res.get ('vspacing') * scale
,hspacing: res.get ('hspacing') * scale
};
// Gets the items
var items = this.items = [];
@ -100,15 +100,11 @@ Hedera.ShelvesReport = new Class
alloc.shelfFunc = this.drawShelf.bind (this);
alloc.boxFunc = this.drawBox.bind (this);
alloc.stack = this.stack;
alloc.nTrays = Math.ceil (
(shelf.height - shelf.firstTrayElevation) /
(shelf.trayHeight + shelf.trayDensity)
);
alloc.width = shelf.width - shelf.hspacing * 2;
alloc.nTrays = shelf.nTrays;
alloc.width = shelf.width;
alloc.depth = shelf.depth;
alloc.trayHeight = shelf.trayHeight - shelf.vspacing;
alloc.topTrayHeight = shelf.maxHeight - shelf.vspacing
- shelf.firstTrayElevation - (alloc.nTrays - 1) * shelf.trayHeight;
alloc.trayHeight = shelf.trayHeight;
alloc.topTrayHeight = shelf.topTrayHeight;
// Opens the report
@ -168,7 +164,7 @@ Hedera.ShelvesReport = new Class
// Draws the shelves
this.alloc.run ();
this.drawShelfEnding ();
this.drawShelfRange (this.lastItem, false);
}
,drawShelf: function (allocator, item)
@ -190,54 +186,65 @@ Hedera.ShelvesReport = new Class
title.className = 'title';
title.appendChild (this.doc.createTextNode (this.title));
sheet.appendChild (title);
if (this.subtitles)
this.drawShelfRange (this.lastItem, false);
this.subtitles = this.doc.createElement ('div');
sheet.appendChild (this.subtitles);
var subtitle = this.doc.createElement ('h2');
subtitle.className = 'subtitle';
subtitle.appendChild (this.doc.createTextNode (this.getName (item)));
sheet.appendChild (subtitle);
this.drawShelfEnding ();
this.lastSubtitle = subtitle;
this.drawShelfRange (item, true);
this.lastSubtitles = this.subtitles;
// Draws the shelf
var trayWidth = shelf.width + this.trayMargin * 2;
var shelfHeight = shelf.trayHeight * (shelf.nTrays - 1) + shelf.topTrayHeight
+ (this.trayThickness + this.trayMargin) * shelf.nTrays;
var shelfDiv = this.shelfDiv = this.doc.createElement ('div');
shelfDiv.className = 'shelf';
shelfDiv.style.width = this.mm (shelf.width);
shelfDiv.style.height = this.mm (shelf.maxHeight);
shelfDiv.style.width = this.mm (trayWidth);
shelfDiv.style.height = this.mm (shelfHeight);
sheet.appendChild (shelfDiv);
// Draws trays
var lastTrayY = shelf.firstTrayElevation;
if (shelf.trayHeight > 0)
while (lastTrayY + shelf.trayDensity < shelf.height)
for (var i = 0; i < shelf.nTrays; i++)
{
var tray = this.doc.createElement ('div');
tray.className = 'tray';
tray.style.width = this.mm (shelf.width);
tray.style.height = this.mm (shelf.trayDensity);
tray.style.bottom = this.mm (lastTrayY);
tray.style.bottom = this.mm ((shelf.trayHeight + this.trayThickness + this.trayMargin) * i);
tray.style.width = this.mm (trayWidth);
tray.style.height = this.mm (this.trayThickness);
shelfDiv.appendChild (tray);
lastTrayY += shelf.trayHeight + shelf.trayDensity;
}
}
,drawShelfEnding: function ()
,drawShelfRange: function (item, isFirst)
{
if (this.lastSubtitle)
this.lastSubtitle.appendChild (this.doc.createTextNode (
' - '+ this.getName (this.lastItem)));
var labelText = isFirst ? _('Start') : _('End');
var label = this.doc.createElement ('label');
label.className = 'range-label';
label.appendChild (this.doc.createTextNode (labelText));
this.subtitles.appendChild (label);
var subtitle = this.doc.createElement ('h2');
subtitle.className = 'subtitle';
subtitle.appendChild (this.doc.createTextNode (this.getItemLabel (item)));
this.subtitles.appendChild (subtitle);
}
,getName: function (item)
,getItemLabel: function (item)
{
if (this.useIds)
return item.id.toLocaleString ();
if (!this.useIds)
{
var packing = this.showPacking ? (' x'+ item.packing) : '';
return item.name + packing;
}
else
return item.name.charAt (0).toUpperCase ();
return item.id.toLocaleString ();
}
,mm: function (size)
@ -252,10 +259,10 @@ Hedera.ShelvesReport = new Class
var shelf = this.shelf;
var x = allocator.trayX + shelf.hspacing;
var y = allocator.trayY
+ shelf.firstTrayElevation + shelf.trayDensity
+ allocator.currentTray * (shelf.trayHeight + shelf.trayDensity);
var x = allocator.trayX + this.trayMargin;
var y = allocator.trayY + this.trayThickness
+ this.trayMargin * allocator.currentTray
+ allocator.currentTray * (shelf.trayHeight + this.trayThickness);
var box = this.doc.createElement ('div');
box.className = 'box';
@ -273,21 +280,28 @@ Hedera.ShelvesReport = new Class
Vn.Node.addClass (box, 'color'+ nColor);
if (amount == 0 || allocator.firstShelfBox)
{
var fontSize = item.boxWidth / 5.2;
if (fontSize > item.boxHeight - 1)
fontSize = item.boxHeight - 1;
if (this.useIds)
var labelText = item.id.toLocaleString ();
else
var labelText = item.name;
{
var boxLabel = this.doc.createElement ('div');
boxLabel.className = 'box-label';
boxLabel.style.fontSize = this.mm (fontSize);
boxLabel.appendChild (this.doc.createTextNode (labelText));
if (this.useIds)
{
var fontSize = item.boxWidth / 5.2;
if (fontSize > item.boxHeight - 1)
fontSize = item.boxHeight - 1;
boxLabel.style.fontSize = this.mm (fontSize);
var cssClass = 'id';
}
else
var cssClass = 'name';
boxLabel.className = 'box-label '+ cssClass;
var labelText = this.doc.createTextNode (this.getItemLabel (item));
boxLabel.appendChild (labelText);
box.appendChild (boxLabel);
}

View File

@ -9,11 +9,17 @@ h1
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
margin-bottom: 4mm;
}
label.range-label
{
color: #777;
}
h2.subtitle
{
margin: 0;
font-size: 400%;
font-size: 200%;
margin-bottom: 2mm;
font-weight: normal;
color: #333;
}
@ -47,13 +53,16 @@ h1.page-number
border-bottom: 0;
box-sizing: border-box;
}
.box .box-label
.box-label
{
text-align: right;
font-size: 55%;
font-size: 2.55mm;
word-wrap: break-word;
box-sizing: border-box;
padding: 0 4%;
padding: 1% 2%;
}
.box-label.id
{
text-align: right;
}
.color0
{

View File

@ -1,27 +1,22 @@
<?php
const MIN = 60;
const HOUR = 60 * MIN;
const DAY = 24 * HOUR;
const WEEK = 7 * DAY;
class Login extends Vn\Web\JsonRequest
{
function run ($db)
{
$this->updateCredentials ($db);
try {
$this->updateCredentials ($db);
//$this->updateCredentialsLdap ($db);
}
catch (Exception $e)
{
error_log ($e->getMessage ());
}
if (!empty ($_POST['remember']))
$tokenLife = WEEK;
else
$tokenLife = 30 * MIN;
$payload = [
'sub' => $_SESSION['user'],
'exp' => time () + $tokenLife
];
$key = $db->getValue ('SELECT jwtKey FROM config');
$token = Vn\Web\Jwt::encode ($payload, $key);
$token = $this->service->createToken (
$_SESSION['user'],
!empty ($_POST['remember'])
);
return [
'login' => TRUE,
@ -29,6 +24,27 @@ class Login extends Vn\Web\JsonRequest
];
}
/**
* Updates the user credentials in other user databases like Samba
* LDAP .
**/
function updateCredentialsLdap ($db)
{
$host = $ldapConf['host'];
if ($ldapConf->secure)
$ldapHost = "ldaps://$host";
else
$ldapHost = "ldap://$host";
$ldap = ldap_connect ($ldapHost, $ldapConf['port']);
if (!ldap_bind ($ldap, $ldapConf['user'], $ldapConf['password']))
throw new Exception ('LDAP authentication failed');
error_log ('Connected to LDAP!');
}
/**
* Updates the user credentials in other user databases like Samba.
**/
@ -51,18 +67,19 @@ class Login extends Vn\Web\JsonRequest
$sshConf = $db->getRow ('SELECT host, user, password FROM ssh_config');
$ssh = ssh2_connect ($sshConf['host']);
$sshOk = $ssh && ssh2_auth_password ($ssh,
if (!$ssh)
throw new Exception ("Can't connect to SSH server {$sshConf['host']}");
$sshAuth = ssh2_auth_password ($ssh,
$sshConf['user'], base64_decode ($sshConf['password']));
if (!$sshOk)
{
error_log ("Can't connect to SSH server {$sshConf['host']}");
return;
}
if (!$sshAuth)
throw new Exception ("SSH authentication failed");
$user = $this->escape ($_SESSION['user']);
$pass = $this->escape ($_POST['password']);
ssh2_exec ($ssh, "samba-tool user create \"$user\" \"$pass\"");
$stream = ssh2_exec ($ssh, "samba-tool user create \"$user\" \"$pass\"");
}
/**

13
rest/core/supplant.php Executable file
View File

@ -0,0 +1,13 @@
<?php
class Supplant extends Vn\Web\JsonRequest
{
const PARAMS = ['supplantUser'];
function run ($db)
{
return $this->service->createToken ($_REQUEST['supplantUser']);
}
}
?>

30
split-plugin.js Normal file
View File

@ -0,0 +1,30 @@
const util = require('util');
function SplitPlugin () {}
module.exports = SplitPlugin;
SplitPlugin.prototype.apply = function (compiler)
{
compiler.plugin("this-compilation", function (compilation)
{
compilation.plugin(["optimize-chunks", "optimize-extracted-chunks"], function (chunks)
{
/* console.log ("\n");
chunks.forEach (function processChunk (chunk, idx)
{
chunk.modules.forEach (function (module)
{
console.log (module.userRequest);
console.log ("+"+module.resource);
console.log ("+"+module.index);
console.log (util.inspect (module, { showHidden: false, depth: 2 }));
});
});
console.log ("\n");
*/ });
});
};

View File

@ -14,7 +14,7 @@ class HtmlService extends Service
$db = $this->db;
if (!$this->isHttps ()
&& $db->getValue ('SELECT https FROM config') && !DEBUG_MODE)
&& $db->getValue ('SELECT https FROM config') && !_DEBUG_MODE)
{
header ("Location: https://{$_SERVER['SERVER_NAME']}{$_SERVER['REQUEST_URI']}");
exit (0);

View File

@ -5,6 +5,11 @@ namespace Vn\Web;
use Vn\Lib\Locale;
use Vn\Lib\UserException;
const MIN = 60;
const HOUR = 60 * MIN;
const DAY = 24 * HOUR;
const WEEK = 7 * DAY;
/**
* Thrown when user credentials could not be fetched.
**/
@ -129,9 +134,7 @@ abstract class Service
function login ()
{
$db = $this->db;
$user = NULL;
$wasLoged = isset ($_SESSION['user']);
if (isset ($_POST['user']) && isset ($_POST['password']))
{
@ -175,7 +178,7 @@ abstract class Service
// Registering the user access
if (isset ($_SESSION['access'])
&& (!isset ($_SESSION['visitUser']) || $wasLoged))
&& !isset ($_SESSION['visitUser']))
{
$_SESSION['visitUser'] = TRUE;
@ -210,6 +213,28 @@ abstract class Service
'SELECT password FROM account.user WHERE name = #', [$user]);
return $this->userDb = $this->app->createConnection ($user, $password);
}
/**
* Generates a JWT authentication token for the specified $user.
*
* @param {string} $user The user name
* @param {boolean} $remember Wether to create long live token
* @return {string} The JWT generated token
**/
function createToken ($user, $remember = FALSE)
{
if ($remember)
$tokenLife = WEEK;
else
$tokenLife = 30 * MIN;
$payload = [
'sub' => $user,
'exp' => time () + $tokenLife
];
$key = $this->db->getValue ('SELECT jwtKey FROM config');
return Jwt::encode ($payload, $key);
}
/**
* Runs a method.

View File

@ -1,34 +1,36 @@
var webpack = require ('webpack');
var path = require ('path');
var SplitPlugin = require ('./split-plugin');
var devMode = true;
module.exports =
{
entry: ['./app.js'],
output: {
entry: ['./app.js'],
output: {
path: path.join (__dirname, 'build'),
filename: 'hedera-web.js',
chunkFilename: 'chunk.[id].js',
publicPath: devMode ? 'http://localhost:8080/build/' : 'build/',
},
module: {
},
module: {
loaders: [
{ test: /\.css$/, loader: 'style!css' },
{ test: /\.json$/, loader: 'json' },
{ test: /\.xml$/, loader: 'raw' }
]
},
resolve: {
},
resolve: {
modulesDirectories: [__dirname +'/js', __dirname, 'node_modules'],
fallback: process.env.NODE_PATH,
},
resolveLoader: {
},
resolveLoader: {
fallback: process.env.NODE_PATH
},
},
plugins: [
/* new webpack.IgnorePlugin (new RegExp ('.{2}/(forms|pages|rest)'))
new SplitPlugin (),
/* new webpack.IgnorePlugin (new RegExp ('/.{2}/(forms|pages|rest)'))
new webpack.optimize.UglifyJsPlugin ({minimize: true})
*/ ]
};
@ -41,15 +43,15 @@ var langs = fs.readdirSync ('./locale');
for (var lang in languages)
configs.push (
{
entry: './locale.js',
output: {
entry: './locale.js',
output: {
path: __dirname +'/build',
filename: 'lang.'+ lang +'.js'
},
module: {
},
module: {
loaders: [
{ test: /\.json$/, loader: 'json' }
]
}
}
});
*/