0
1
Fork 0
This commit is contained in:
Juan Ferrer Toribio 2017-03-09 13:30:39 +01:00
parent b7ec06ffdc
commit 043c11a4ed
26 changed files with 227 additions and 206 deletions

1
app.js
View File

@ -61,4 +61,3 @@ function loadLocale (cb)
cb (require.context ('js', true, /locale\/en.json$/)); }); cb (require.context ('js', true, /locale\/en.json$/)); });
} }
} }

2
debian/changelog vendored
View File

@ -1,4 +1,4 @@
hedera-web (2.0.1) stable; urgency=low hedera-web (2.0.3) stable; urgency=low
* Initial Release. * Initial Release.

2
debian/control vendored
View File

@ -9,7 +9,7 @@ Vcs-Git: git://www.verdnatura.es/var/git/hedera-web
Package: hedera-web Package: hedera-web
Architecture: all Architecture: all
Depends: apache2, php5-mysql, php5-mcrypt, php5-ssh2, php-vn-lib, php-acpu, nodejs, npm Depends: apache2, php5-mysql, php5-mcrypt, php5-ssh2, php5-apcu, php-vn-lib, nodejs, npm
Suggests: php-text-captcha, php5-imap Suggests: php-text-captcha, php5-imap
Section: misc Section: misc
Priority: optional Priority: optional

3
debian/install vendored
View File

@ -10,5 +10,6 @@ reports usr/share/hedera-web
rest usr/share/hedera-web rest usr/share/hedera-web
index.php usr/share/hedera-web index.php usr/share/hedera-web
package.json usr/share/hedera-web package.json usr/share/hedera-web
build usr/share/hedera-web
manifest.json usr/share/hedera-web manifest.json usr/share/hedera-web
webpack.config.json usr/share/hedera-web
build usr/share/hedera-web

View File

@ -8,9 +8,10 @@
} }
.basket .head .basket .head
{ {
padding: 0;
padding-bottom: 2em; padding-bottom: 2em;
margin: 0;
border-bottom: 1px solid #DDD; border-bottom: 1px solid #DDD;
margin-bottom: 1em;
} }
.basket .head p .basket .head p
{ {
@ -22,13 +23,9 @@
/* Lines */ /* Lines */
.basket .lines
{
padding: .8em 0;
}
.basket .line .basket .line
{ {
padding: 1em 0; padding: .5em 0;
} }
.basket .line > .delete .basket .line > .delete
{ {
@ -48,7 +45,7 @@
.basket .line > p .basket .line > p
{ {
margin: .1em 0; margin: .1em 0;
margin-left: 7.5em; margin-left: 6em;
} }
.basket .line .subtotal .basket .line .subtotal
{ {

View File

@ -26,7 +26,6 @@
</htk-text> </htk-text>
</p> </p>
</div> </div>
<div class="lines">
<htk-repeater form-id="iter" renderer="repeaterFunc"> <htk-repeater form-id="iter" renderer="repeaterFunc">
<db-model id="items" property="model" updatable="true"> <db-model id="items" property="model" updatable="true">
<custom> <custom>
@ -70,6 +69,5 @@
</custom> </custom>
</htk-repeater> </htk-repeater>
</div> </div>
</div>
</div> </div>
</vn> </vn>

View File

@ -2,14 +2,6 @@
{ {
color: #555; color: #555;
} }
.confirm .card
{
padding: 2.2em 2.5em;
}
.confirm .summary
{
margin-bottom: 1em;
}
.confirm .address .confirm .address
{ {
margin-top: .8em; margin-top: .8em;
@ -119,4 +111,3 @@
{ {
margin: .1em 0; margin: .1em 0;
} }

View File

@ -31,13 +31,18 @@
{ {
padding: .5em 0; padding: .5em 0;
} }
.ticket .line > .photo
{
margin-right: 1em;
float: left;
border-radius: 50%;
height: 3.2em;
width: 3.2em;
}
.ticket .line p .ticket .line p
{ {
margin: .1em 0; margin: .1em 0;
} margin-left: 4em;
.ticket .amount
{
float: left;
} }
.ticket .subtotal .ticket .subtotal
{ {

View File

@ -69,8 +69,9 @@
<htk-repeater form-id="iter" renderer="repeaterFunc"> <htk-repeater form-id="iter" renderer="repeaterFunc">
<db-model property="model" id="movements"> <db-model property="model" id="movements">
<custom> <custom>
SELECT m.item_id, amount, concept, Categoria, Medida, Tallos, Color, SELECT m.item_id, m.amount, m.concept,
Abreviatura, IF(fixed != FALSE, price, NULL) price, fixed, discount IF(m.fixed != FALSE, m.price, NULL) price, m.fixed, m.discount,
o.Abreviatura, a.Categoria, a.Medida, a.Tallos, a.Color, a.Foto
FROM ticket_row_view m FROM ticket_row_view m
INNER JOIN vn2008.Articles a INNER JOIN vn2008.Articles a
ON m.item_id = a.Id_Article AND ticket_id = #ticket ON m.item_id = a.Id_Article AND ticket_id = #ticket
@ -86,6 +87,13 @@
</db-model> </db-model>
<custom> <custom>
<div class="line"> <div class="line">
<htk-image
form="iter"
column="Foto"
class="photo"
directory="catalog"
subdir="200x200"
full-dir="900x900"/>
<p class="concept"> <p class="concept">
<htk-text form="iter" column="concept"/> <htk-text form="iter" column="concept"/>
<htk-text form="iter" column="Medida"/> <htk-text form="iter" column="Medida"/>
@ -94,9 +102,9 @@
<p class="amount"> <p class="amount">
<htk-text form="iter" column="amount"/> x <htk-text form="iter" column="amount"/> x
<htk-text form="iter" column="price" format="%.2d€"/> <htk-text form="iter" column="price" format="%.2d€"/>
</p> <span class="subtotal">
<p class="subtotal">
<htk-text id="subtotal" format="%.2d€"/> <htk-text id="subtotal" format="%.2d€"/>
</span>
</p> </p>
<div class="clear"/> <div class="clear"/>
</div> </div>

BIN
image/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.4 KiB

View File

@ -5,4 +5,3 @@ require_once 'vn-autoload.php';
$webApp = new Vn\Web\App ('hedera-web'); $webApp = new Vn\Web\App ('hedera-web');
$webApp->run (); $webApp->run ();

View File

@ -48,7 +48,7 @@ module.exports = new Class
gui.show (); gui.show ();
} }
,_onLogout: function (gui) ,_onLogout: function ()
{ {
this.clearAutoLogin (); this.clearAutoLogin ();
this._freeGui (); this._freeGui ();

View File

@ -44,7 +44,7 @@ module.exports = new Class
this.$('spinner').stop (); this.$('spinner').stop ();
} }
,show: function (firstLogin) ,show: function ()
{ {
document.body.appendChild (this.node); document.body.appendChild (this.node);
@ -114,7 +114,7 @@ module.exports = new Class
if (!user) if (!user)
Htk.Toast.showError (_('Please write your user name')); Htk.Toast.showError (_('Please write your user name'));
else else
this._conn.send ('core/recover-password', {'user': user}, this._conn.send ('core/recover-password', {'recoverUser': user},
this._onPasswordRecovered.bind (this)); this._onPasswordRecovered.bind (this));
} }

View File

@ -100,4 +100,3 @@ module.exports = new Class
this.doc.body.appendChild (res.$('report')); this.doc.body.appendChild (res.$('report'));
} }
}); });

View File

@ -99,7 +99,7 @@ th.cell-radio
} }
td.cell-button td.cell-button
{ {
max-width: 1px; width: 1em;
text-align: center; text-align: center;
} }
td.cell-button > button td.cell-button > button
@ -633,4 +633,3 @@ td.cell-image .htk-image
{ {
to {-webkit-transform: rotate(360deg);} to {-webkit-transform: rotate(360deg);}
} }

View File

@ -1,6 +1,6 @@
{ {
"name": "hedera-web", "name": "hedera-web",
"version": "2.0.1", "version": "2.0.3",
"description": "Verdnatura web page", "description": "Verdnatura web page",
"devDependencies": { "devDependencies": {
"assets-webpack-plugin": "^3.5.1", "assets-webpack-plugin": "^3.5.1",

View File

@ -1,47 +1,7 @@
<?php <?php
$lang = Vn\Lib\Locale::get (); $lang = Vn\Lib\Locale::get ();
$result = $db->query('SELECT name, content FROM metatag'); $result = $db->query ('SELECT name, content FROM metatag');
$wpConfig = json_decode (file_get_contents ('webpack.config.json'));
$buildDir = $wpConfig->buildDir;
$devServerPort = $wpConfig->devServerPort;
$host = $_SERVER['SERVER_NAME'];
$assets = new stdClass();
if (!_DEV_MODE)
{
$wpAssets = json_decode (file_get_contents ("$buildDir/webpack-assets.json"));
$manifestJs = $wpAssets->manifest->js;
$mainJs = $wpAssets->main->js;
unset ($wpAssets->manifest);
unset ($wpAssets->main);
foreach ($wpAssets as $name => $asset)
if (property_exists ($asset, 'js'))
$assets->$name = $asset->js;
}
else
{
$devServerPath = "http://$host:$devServerPort/$buildDir";
$manifestJs = "$devServerPath/manifest.js";
$mainJs = "$devServerPath/main.js";
unset ($wpConfig->entry->main);
foreach ($wpConfig->entry as $asset => $files)
$assets->$asset = "$devServerPath/$asset.js";
}
$jsFiles = [];
$jsFiles[] = $manifestJs;
foreach ($assets as $jsFile)
$jsFiles[] = $jsFile;
$jsFiles[] = $mainJs;
?> ?>
<!DOCTYPE html> <!DOCTYPE html>
@ -58,11 +18,11 @@ $jsFiles[] = $mainJs;
<meta name="theme-color" content="#009688"/> <meta name="theme-color" content="#009688"/>
<meta name="content-language" content="<?=$lang?>"/> <meta name="content-language" content="<?=$lang?>"/>
<?php while ($row = $result->fetch_object()): ?> <?php while ($row = $result->fetch_object ()): ?>
<meta name="<?=$row->name?>" content="<?=$row->content?>"/> <meta name="<?=$row->name?>" content="<?=$row->content?>"/>
<?php endwhile ?> <?php endwhile ?>
<?php foreach ($jsFiles as $js): ?> <?php foreach (getWebpackAssets () as $js): ?>
<script type="text/javascript" src="<?=$js?>"></script> <script type="text/javascript" src="<?=$js?>"></script>
<?php endforeach ?> <?php endforeach ?>

View File

@ -0,0 +1,3 @@
{
"Import": "Importe"
}

View File

@ -56,7 +56,7 @@
<htk-column-text title="_S1" column="Medida"/> <htk-column-text title="_S1" column="Medida"/>
<htk-column-text title="_Cat" column="Categoria"/> <htk-column-text title="_Cat" column="Categoria"/>
<htk-column-spin title="_Price" column="price" unit="€" digits="2"/> <htk-column-spin title="_Price" column="price" unit="€" digits="2"/>
<htk-column-spin title="_Subtotal" unit="€" digits="2" renderer="subtotalRenderer"/> <htk-column-spin title="_Import" unit="€" digits="2" renderer="subtotalRenderer"/>
</htk-grid> </htk-grid>
<p class="footer"> <p class="footer">
<htk-text format="%.2d€"> <htk-text format="%.2d€">

View File

@ -4,7 +4,7 @@ use Vn\Web;
class RecoverPassword extends Vn\Web\JsonRequest class RecoverPassword extends Vn\Web\JsonRequest
{ {
const PARAMS = ['user']; const PARAMS = ['recoverUser'];
function run ($db) function run ($db)
{ {
@ -13,14 +13,14 @@ class RecoverPassword extends Vn\Web\JsonRequest
FROM vn2008.Clientes c FROM vn2008.Clientes c
JOIN account.user u ON u.id = c.Id_Cliente JOIN account.user u ON u.id = c.Id_Cliente
WHERE u.name = #', WHERE u.name = #',
[$_REQUEST['user']] [$_REQUEST['recoverUser']]
); );
if (!($user['active'] && $user['mail'])) if (!($user['active'] && $user['mail']))
return TRUE; return TRUE;
$service = $this->service; $service = $this->service;
$token = $service->createToken ($_REQUEST['user'], FALSE, TRUE); $token = $service->createToken ($_REQUEST['recoverUser'], FALSE, TRUE);
$url = $service->getUrl () ."#!form=account/conf&token=$token"; $url = $service->getUrl () ."#!form=account/conf&token=$token";
$report = new Vn\Web\Report ($db, 'recover-password', ['url' => $url]); $report = new Vn\Web\Report ($db, 'recover-password', ['url' => $url]);

View File

@ -13,12 +13,20 @@ class HtmlService extends Service
{ {
function run () function run ()
{ {
$eFlag =
E_ERROR
| E_USER_ERROR;
set_error_handler ([$this, 'errorHandler'], $eFlag);
set_exception_handler ([$this, 'errorHandler']);
$this->init ();
$db = $this->db; $db = $this->db;
if (!$this->isHttps () if (!$this->isHttps ()
&& $db->getValue ('SELECT https FROM config') && !_DEV_MODE) && $db->getValue ('SELECT https FROM config') && !_DEV_MODE)
{ {
header ("Location: https://{$_SERVER['SERVER_NAME']}{$_SERVER['REQUEST_URI']}"); header ("Location: https://{$this->getUri()}");
exit (0); exit (0);
} }
@ -96,11 +104,12 @@ class HtmlService extends Service
//header ("Content-Security-Policy: default-src *; img-src *;"); //header ("Content-Security-Policy: default-src *; img-src *;");
} }
function globalErrorHandler () function errorHandler ()
{ {
$this->printHeader (); $this->printHeader ();
include (__DIR__.'/unavailable.html'); include (__DIR__.'/unavailable.html');
exit (0); exit (0);
return FALSE;
} }
function isMobile () function isMobile ()

View File

@ -3,27 +3,9 @@
function getUrl ($fileName) function getUrl ($fileName)
{ {
if (file_exists ($fileName)) if (file_exists ($fileName))
{ $mTime = '?'. strftime ('%G%m%d%H%M%S', filemtime ($fileName));
$hashes = apc_fetch ("$appName.hashes", $success);
if (!$success)
{
apc_store ("$appName.version", $version);
$hashes = [];
}
if (!isset ($hashes[$fileName]))
{
$hash = md5_file($fileName);
$hashes[$fileName] = $hash;
}
else else
$hash = $hashes[$fileName]; $mTime = '?'. $this->getVersion ();
$mTime = "?$hash";
}
else
$mTime = '';
return $fileName.$mTime; return $fileName.$mTime;
} }
@ -37,3 +19,48 @@ function css ($fileName)
{ {
return '<link rel="stylesheet" type="text/css" href="'. getUrl ($fileName) .'"/>'."\n"; return '<link rel="stylesheet" type="text/css" href="'. getUrl ($fileName) .'"/>'."\n";
} }
function getWebpackAssets ()
{
$wpConfig = json_decode (file_get_contents ('webpack.config.json'));
$buildDir = $wpConfig->buildDir;
$devServerPort = $wpConfig->devServerPort;
$host = $_SERVER['SERVER_NAME'];
$assets = new stdClass();
if (!_DEV_MODE)
{
$wpAssets = json_decode (file_get_contents ("$buildDir/webpack-assets.json"));
$manifestJs = $wpAssets->manifest->js;
$mainJs = $wpAssets->main->js;
unset ($wpAssets->manifest);
unset ($wpAssets->main);
foreach ($wpAssets as $name => $asset)
if (property_exists ($asset, 'js'))
$assets->$name = $asset->js;
}
else
{
$devServerPath = "http://$host:$devServerPort/$buildDir";
$manifestJs = "$devServerPath/manifest.js";
$mainJs = "$devServerPath/main.js";
unset ($wpConfig->entry->main);
foreach ($wpConfig->entry as $asset => $files)
$assets->$asset = "$devServerPath/$asset.js";
}
$jsFiles = [];
$jsFiles[] = $manifestJs;
foreach ($assets as $jsFile)
$jsFiles[] = $jsFile;
$jsFiles[] = $mainJs;
return $jsFiles;
}

View File

@ -17,6 +17,7 @@ class JsonService extends RestService
set_error_handler ([$this, 'errorHandler'], E_ALL); set_error_handler ([$this, 'errorHandler'], E_ALL);
set_exception_handler ([$this, 'exceptionHandler']); set_exception_handler ([$this, 'exceptionHandler']);
$this->init ();
$this->startSession (); $this->startSession ();
$this->checkVersion (); $this->checkVersion ();

View File

@ -3,6 +3,8 @@
namespace Vn\Web; namespace Vn\Web;
use Vn\Lib; use Vn\Lib;
use Vn\Lib\Locale;
use Vn\Lib\UserException;
/** /**
* Base class for REST application. * Base class for REST application.
@ -15,10 +17,47 @@ class RestService extends Service
set_error_handler ([$this, 'errorHandler'], E_ALL); set_error_handler ([$this, 'errorHandler'], E_ALL);
set_exception_handler ([$this, 'exceptionHandler']); set_exception_handler ([$this, 'exceptionHandler']);
$this->init ();
$this->startSession (); $this->startSession ();
$this->loadMethod (__NAMESPACE__.'\RestRequest'); $this->loadMethod (__NAMESPACE__.'\RestRequest');
} }
/**
* Runs a REST method.
*/
function loadMethod ($class)
{
$db = $this->db;
$this->login ();
$method = $this->app->loadMethod (
$_REQUEST['method'], $class, './rest');
$method->service = $this;
if ($method::SECURITY == Security::DEFINER)
{
$isAuthorized = $db->getValue ('SELECT userCheckRestPriv (#)',
[$_REQUEST['method']]);
if (!$isAuthorized)
throw new UserException (s('You don\'t have enough privileges'));
$methodDb = $db;
}
else
$methodDb = $this->getUserDb ($_SESSION['user']);
if ($method::PARAMS !== NULL && !$method->checkParams ($_REQUEST, $method::PARAMS))
throw new UserException (s('Missing parameters'));
Locale::addPath ("rest/{$_REQUEST['method']}");
$res = $method->run ($methodDb);
$db->query ('CALL account.userLogout ()');
return $res;
}
function statusFromException ($e) function statusFromException ($e)
{ {
try { try {

View File

@ -37,7 +37,11 @@ abstract class Service
function __construct ($app) function __construct ($app)
{ {
$this->app = $app; $this->app = $app;
$this->db = $app->getSysConn (); }
function init ()
{
$this->db = $this->app->getSysConn ();
} }
/** /**
@ -45,7 +49,7 @@ abstract class Service
*/ */
function startSession () function startSession ()
{ {
$db = $this->db; $db = $this->app->getSysConn ();
ini_set ('session.cookie_secure', $this->isHttps ()); ini_set ('session.cookie_secure', $this->isHttps ());
ini_set ('session.hash_function', 'sha256'); ini_set ('session.hash_function', 'sha256');
@ -147,7 +151,10 @@ abstract class Service
catch (\Vn\Db\Exception $e) catch (\Vn\Db\Exception $e)
{ {
if ($e->getMessage () == 'INVALID_CREDENTIALS') if ($e->getMessage () == 'INVALID_CREDENTIALS')
{
sleep (3);
throw new BadLoginException (); throw new BadLoginException ();
}
else else
throw $e; throw $e;
} }
@ -259,42 +266,6 @@ abstract class Service
return Jwt::encode ($payload, $key); return Jwt::encode ($payload, $key);
} }
/**
* Runs a method.
*/
function loadMethod ($class)
{
$db = $this->db;
$this->login ();
$method = $this->app->loadMethod (
$_REQUEST['method'], $class, './rest');
$method->service = $this;
if ($method::SECURITY == Security::DEFINER)
{
$isAuthorized = $db->getValue ('SELECT userCheckRestPriv (#)',
[$_REQUEST['method']]);
if (!$isAuthorized)
throw new UserException (s('You don\'t have enough privileges'));
$methodDb = $db;
}
else
$methodDb = $this->getUserDb ($_SESSION['user']);
if ($method::PARAMS !== NULL && !$method->checkParams ($_REQUEST, $method::PARAMS))
throw new UserException (s('Missing parameters'));
Locale::addPath ("rest/{$_REQUEST['method']}");
$res = $method->run ($methodDb);
$db->query ('CALL account.userLogout ()');
return $res;
}
/** /**
* Obtains the application version number. It is extracted and * Obtains the application version number. It is extracted and
* cached from package.json file. * cached from package.json file.
@ -345,6 +316,16 @@ abstract class Service
return isset ($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on'; return isset ($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on';
} }
/**
* Returns the current URI without the GET part.
*
* @return string The current URI
*/
function getUri ()
{
return "{$_SERVER['SERVER_NAME']}{$_SERVER['REQUEST_URI']}";
}
/** /**
* Returns the current URL without the GET part. * Returns the current URL without the GET part.
* *
@ -353,7 +334,7 @@ abstract class Service
function getUrl () function getUrl ()
{ {
$proto = $this->isHttps () ? 'https' : 'http'; $proto = $this->isHttps () ? 'https' : 'http';
return "$proto://{$_SERVER['SERVER_NAME']}{$_SERVER['REQUEST_URI']}"; return "$proto://{$this->getUri()}";
} }
} }

View File

@ -3,36 +3,41 @@
<html xmlns="http://www.w3.org/1999/xhtml"> <html xmlns="http://www.w3.org/1999/xhtml">
<head> <head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<title>No disponible - Verdnatura</title> <title>Not available - Verdnatura</title>
<style type="text/css"> <style type="text/css">
body body
{ {
font-size: 16pt; font-size: 16pt;
font-family: Sans;
} }
div div
{ {
position: absolute; position: absolute;
width: 36em; width: 32em;
margin-top: -7em; margin-top: -7em;
margin-left: -18em; margin-left: -18em;
top: 50%; top: 50%;
left: 50%; left: 50%;
text-align: center; text-align: center;
} }
div h2
{
font-weight: normal;
}
div a div a
{ {
color: #444; color: #2962FF;
text-decoration: none;
} }
</style> </style>
</head> </head>
<body> <body>
<div> <div>
<h2> <h2>
Estamos teniendo problemas; por favor, We are having problems; Please wait a few minutes and try again.
espera unos minutos e int&eacute;ntalo de nuevo.
</h2> </h2>
<a href="javascript: location.reload (true)"> <a href="javascript: location.reload (true)">
Intentarlo de nuevo Try it again
</a> </a>
</div> </div>
</body> </body>