0
1
Fork 0

LDAP sync, PHP code updated with dev, webpack 3, balancing

This commit is contained in:
Juan Ferrer Toribio 2017-11-29 11:01:48 +01:00
parent b6bd44c98f
commit 883e5e0dcc
43 changed files with 380 additions and 369 deletions

3
README.md Normal file
View File

@ -0,0 +1,3 @@
# Hedera
Hedera is the main page for Verdnatura.

21
app.js
View File

@ -1,18 +1,21 @@
var host = window.location.host.split(':')[0]; var assetsPath;
if (_DEV_MODE) if (_DEV_MODE)
host = host +':9000'; {
var host = window.location.host.split(':')[0];
assetsPath = 'http://'+ host +':'+ _DEV_SERVER_PORT +'/'+ _PUBLIC_PATH;
}
else
assetsPath = _PUBLIC_PATH;
__webpack_public_path__ = '//'+ host +'/build/'; __webpack_public_path__ = assetsPath;
require ('hedera/hedera'); require ('hedera/hedera');
window.onload = function () window.onload = function ()
{ {
Vn.Locale.init (); loadLocale (main);
var lang = Vn.Locale.language;
loadLocale (lang, main);
} }
function main (req) function main (req)
@ -26,8 +29,11 @@ function main (req)
hederaWeb.run (); hederaWeb.run ();
} }
function loadLocale (lang, cb) function loadLocale (cb)
{ {
Vn.Locale.init ();
var lang = Vn.Locale.language;
switch (lang) switch (lang)
{ {
case 'ca': case 'ca':
@ -55,4 +61,3 @@ function loadLocale (lang, 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 (1.405.18) stable; urgency=low hedera-web (1.405.23) stable; urgency=low
* Initial Release. * Initial Release.

3
debian/install vendored
View File

@ -12,3 +12,6 @@ index.php usr/share/hedera-web
package.json usr/share/hedera-web package.json usr/share/hedera-web
build usr/share/hedera-web build usr/share/hedera-web
manifest.json usr/share/hedera-web manifest.json usr/share/hedera-web
LICENSE usr/share/hedera-web
README.md usr/share/hedera-web
webpack.config.json usr/share/hedera-web

View File

@ -17,7 +17,7 @@ Hedera.Catalog = new Class
} }
else else
{ {
var query = 'CALL basket_configure_for_guest ()'; var query = 'CALL basketConfigureForGuest';
this.conn.execQuery (query, this.loadUi.bind (this)); this.conn.execQuery (query, this.loadUi.bind (this));
} }
} }

View File

@ -56,7 +56,7 @@ Hedera.Checkout = new Class
{ {
this.disableButtons (true); this.disableButtons (true);
var query = 'CALL basket_configure (#date, #method, #agency, #address)'; var query = 'CALL basketConfigure (#date, #method, #agency, #address)';
var batch = new Sql.Batch (); var batch = new Sql.Batch ();
batch.addParam ('method', this.$('method')); batch.addParam ('method', this.$('method'));

View File

@ -21,17 +21,9 @@
</custom> </custom>
</db-model> </db-model>
</db-form> </db-form>
<db-model id="agencies" auto-load="false" result-index="1" on-status-changed="onAgenciesReady"> <db-model id="agencies" auto-load="false" on-status-changed="onAgenciesReady">
<custom> <custom>
CALL agency_list_from_date (#date, #address); CALL vn.agencyListForMethod(#date, #address, 'AGENCY')
SELECT a.Id_Agencia, a.description
FROM t_agency t
JOIN vn2008.Agencias a ON a.Id_Agencia = t.agency_id
JOIN vn2008.Vistas v ON a.Vista = v.vista_id
WHERE a.web != FALSE
AND v.code = 'AGENCY'
ORDER BY a.description;
DROP TEMPORARY TABLE t_agency;
</custom> </custom>
<sql-batch property="batch"> <sql-batch property="batch">
<custom> <custom>
@ -40,17 +32,9 @@
</custom> </custom>
</sql-batch> </sql-batch>
</db-model> </db-model>
<db-model id="warehouses" auto-load="false" result-index="1" on-status-changed="onWarehousesReady"> <db-model id="warehouses" auto-load="false" on-status-changed="onWarehousesReady">
<custom> <custom>
CALL agency_list_from_date (#date, #address); CALL vn.agencyListForMethod(#date, #address, 'PICKUP')
SELECT a.Id_Agencia, a.description
FROM t_agency t
JOIN vn2008.Agencias a ON a.Id_Agencia = t.agency_id
JOIN vn2008.Vistas v ON a.Vista = v.vista_id
WHERE a.web != FALSE
AND v.code = 'PICKUP'
ORDER BY a.description;
DROP TEMPORARY TABLE t_agency;
</custom> </custom>
<sql-batch property="batch"> <sql-batch property="batch">
<custom> <custom>

View File

@ -3,7 +3,7 @@ module.exports =
{ {
check: function (conn, callback) check: function (conn, callback)
{ {
conn.execQuery ('CALL basket_check ()', conn.execQuery ('CALL basketCheck',
this._onBasketCheck.bind (this, callback)); this._onBasketCheck.bind (this, callback));
} }

View File

@ -1,17 +1,26 @@
{ {
"name": "hedera-web", "name": "hedera-web",
"version": "1.0.0", "version": "1.405.23",
"description": "Verdnatura web page", "description": "Verdnatura web page",
"license": "GPL-3.0",
"repository": {
"type": "git",
"url": "https://git.verdnatura.es/hedera-web"
},
"devDependencies": { "devDependencies": {
"assets-webpack-plugin": "^3.5.1",
"bundle-loader": "^0.5.4", "bundle-loader": "^0.5.4",
"css-loader": "^0.25.0", "css-loader": "^0.25.0",
"eslint": "^3.16.1",
"file-loader": "^0.9.0", "file-loader": "^0.9.0",
"json-loader": "^0.5.4", "json-loader": "^0.5.4",
"raw-loader": "^0.5.1", "raw-loader": "^0.5.1",
"style-loader": "^0.13.1", "style-loader": "^0.19.0",
"url-loader": "^0.5.7", "url-loader": "^0.5.7",
"webpack": "^1.13.3", "webpack": "^3.6.0",
"webpack-dev-server": "^1.16.2" "webpack-chunk-hash": "^0.5.0",
"webpack-dev-server": "^2.9.1",
"webpack-merge": "^4.1.0"
}, },
"dependencies": { "dependencies": {
"mootools": "^1.5.2", "mootools": "^1.5.2",
@ -19,7 +28,7 @@
}, },
"scripts": { "scripts": {
"dev": "webpack-dev-server --progress --colors --hot", "dev": "webpack-dev-server --progress --colors --hot",
"build": "rm -f build/* ; webpack --progress --colors", "build": "rm -rf build/ ; webpack --progress --colors",
"clean": "rm -rf build/" "clean": "rm -rf build/"
} }
} }

View File

@ -1,9 +0,0 @@
<script type="text/javascript">
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-49049601-1', 'verdnatura.es');
ga('send', 'pageview');
</script>

View File

@ -1,17 +0,0 @@
<?php
use Vn\Lib\Locale;
echo '<meta name="content-language" content="'. Locale::get () .'"/>'."\n\t\t";
if ($result = $db->query ('SELECT name, content FROM metatag'))
{
while ($row = $result->fetch_assoc ())
echo "<meta name=\"{$row['name']}\" content=\"{$row['content']}\"/>\n\t\t";
$result->free ();
}
$url = _DEV_MODE ? "http://{$_SERVER['SERVER_NAME']}:9000/" : '';
$this->includeJs ("{$url}build/hedera-web.js");

View File

@ -1,5 +1,10 @@
<!DOCTYPE html> <?php
$lang = Vn\Lib\Locale::get ();
$result = $db->query ('SELECT name, content FROM metatag');
?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"> <html xmlns="http://www.w3.org/1999/xhtml">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
@ -11,7 +16,15 @@
<link rel="icon" type="image/svg+xml" href="image/icon.svg" sizes="any"/> <link rel="icon" type="image/svg+xml" href="image/icon.svg" sizes="any"/>
<link rel="manifest" href="manifest.json"/> <link rel="manifest" href="manifest.json"/>
<meta name="theme-color" content="#009688"/> <meta name="theme-color" content="#009688"/>
<?php include 'head.php' ?> <meta name="content-language" content="<?=$lang?>"/>
<?php while ($row = $result->fetch_object ()): ?>
<meta name="<?=$row->name?>" content="<?=$row->content?>"/>
<?php endwhile ?>
<?php foreach (getWebpackAssets () as $js): ?>
<script type="text/javascript" src="<?=$js?>"></script>
<?php endforeach ?>
<title>Verdnatura</title> <title>Verdnatura</title>
</head> </head>

View File

@ -1,4 +0,0 @@
{
"PaymentComplete": "Pagament acabat, ja pots tornar a la nostra pàgina web."
,"ReturnToWeb": "Tornar a Verdnatura"
}

View File

@ -1,4 +0,0 @@
{
"PaymentComplete": "Payment completed, you can return to our website."
,"ReturnToWeb": "Back to Verdnatura"
}

View File

@ -1,4 +0,0 @@
{
"PaymentComplete": "Pago terminado, ya puedes volver a nuestra página web."
,"ReturnToWeb": "Volver a Verdnatura"
}

View File

@ -1,4 +0,0 @@
{
"PaymentComplete": "Paiement terminé, merci par votre confiance, maintenant vous pouvez revenir à notre site."
,"ReturnToWeb": "Retour au Verdnatura"
}

View File

@ -1,4 +0,0 @@
{
"PaymentComplete": "Payment completed, you can return to our website."
,"ReturnToWeb": "Back to Verdnatura"
}

View File

@ -1,4 +0,0 @@
{
"PaymentComplete": "Pagamento terminado, já podes voltar a nossa página web."
,"ReturnToWeb": "Voltar a Verdnatura"
}

View File

@ -1,16 +0,0 @@
*
{
font-family: 'Roboto';
font-size: 10pt;
}
div
{
position: absolute;
width: 48em;
height: 10em;
margin-left: -24em;
margin-top: -5em;
top: 50%;
left: 50%;
text-align: center;
}

View File

@ -1,22 +0,0 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<meta name="viewport" content="user-scalable=no"/>
<link href="http://fonts.googleapis.com/css?family=Roboto" rel="stylesheet" type="text/css"/>
<link rel="stylesheet" type="text/css" href="<?=$dir?>/style.css"/>
<title>Verdnatura</title>
</head>
<body>
<div>
<img src="image/logo.svg" alt="Verdnatura"/>
<p>
<?=s('PaymentComplete')?>
</p>
<p>
<a href="?page=web#!module=orders"><?=s('ReturnToWeb')?></a>
</p>
</div>
</body>
</html>

View File

@ -1,5 +1,4 @@
<!DOCTYPE html> <!DOCTYPE html>
<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"/>

View File

@ -1,5 +1,4 @@
<!DOCTYPE html> <!DOCTYPE html>
<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"/>

View File

@ -75,10 +75,19 @@ class Account
[$userName] [$userName]
); );
$nameArgs = explode (' ', $user->nickname);
$givenName = $nameArgs[0];
if (count ($nameArgs) > 1)
$sn = $nameArgs[1];
if (empty ($sn))
$sn = 'Empty';
$info = [ $info = [
'cn' => $userName, 'cn' => $user->nickname,
'sn' => $userName,
'displayName' => $user->nickname, 'displayName' => $user->nickname,
'givenName' => $givenName,
'sn' => $sn,
'mail' => "$userName@{$domain}", 'mail' => "$userName@{$domain}",
'userPassword' => sshaEncode ($password), 'userPassword' => sshaEncode ($password),
'preferredLanguage' => $user->lang 'preferredLanguage' => $user->lang

View File

@ -73,4 +73,3 @@ class AccessVersion extends Vn\Web\JsonRequest
return TRUE; return TRUE;
} }
} }

View File

@ -43,4 +43,3 @@ class ExchangeRate extends Vn\Lib\Method
$db->queryFromFile (__DIR__.'/exrate-add'); $db->queryFromFile (__DIR__.'/exrate-add');
} }
} }

View File

@ -9,60 +9,25 @@ class Mail extends Vn\Lib\Method
$db->selectDb ('vn2008'); $db->selectDb ('vn2008');
$db->query ('START TRANSACTION'); $db->query ('START TRANSACTION');
$conf = $db->getRow ( $mailer = new Vn\Web\Mailer ($db);
'SELECT host, port, secure, sender, sender_name, user, password
FROM hedera.mail_config'
);
$res = $db->query ( $res = $db->query (
'SELECT * FROM mail WHERE sent = 0 ORDER BY DATE_ODBC DESC 'SELECT * FROM mail WHERE sent = 0 ORDER BY DATE_ODBC DESC
LIMIT 20 FOR UPDATE'); LIMIT 20 FOR UPDATE');
$count = 0; $count = 0;
while ($row = $res->fetch_assoc ()) while ($row = $res->fetch_object ())
{ {
$sent = 1; $sent = 1;
$status = 'OK'; $status = 'OK';
try { try {
//if (!preg_match ('/^[\w\._%-]+@[\w\.-]+\.[A-Za-z]{2,4}$/', $mailTo)) $mail = $mailer->createObject ($row->to, $row->text, $row->subject);
// throw new Exception ('Destination mail has invalid sintax'); $mail->AddReplyTo ($row->reply_to, $conf->sender_name);
$mail = new PHPMailer (); if (!empty ($row->path))
$mail->isSMTP ();
$mail->Host = $conf['host'];
if (!empty ($conf['user']))
{ {
$mail->SMTPAuth = TRUE; $attachment = '/mnt/cluster/pdfs/'. $row->path;
$mail->Username = $conf['user'];
$mail->Password = base64_decode ($conf['password']);
}
else
$mail->SMTPAuth = FALSE;
if ($conf['secure'])
{
$mail->SMTPSecure = 'ssl';
$mail->Port = 465;
}
$mail->setFrom ($conf['sender'], $conf['sender_name']);
$mail->AddReplyTo ($row['reply_to'], $conf['sender_name']);
$mailList = explode (',', $row['to']);
foreach ($mailList as $to)
$mail->AddAddress ($to);
$mail->IsHTML (TRUE);
$mail->Subject = $row['subject'];
$mail->Body = ' '. $row['text'];
$mail->CharSet = 'UTF-8';
if (!empty ($row['path']))
{
$attachment = '/mnt/cluster/pdfs/'. $row['path'];
if (file_exists ($attachment)) if (file_exists ($attachment))
$mail->AddAttachment ($attachment, ''); $mail->AddAttachment ($attachment, '');
@ -89,5 +54,3 @@ class Mail extends Vn\Lib\Method
echo "Total $count mails sent\n"; echo "Total $count mails sent\n";
} }
} }

View File

@ -48,5 +48,3 @@ class Sms extends Vn\Web\JsonRequest
return TRUE; return TRUE;
} }
} }

View File

@ -50,4 +50,3 @@ class VisitsSync extends Vn\Lib\Method
$result->free (); $result->free ();
} }
} }

View File

@ -23,9 +23,8 @@ class DbSessionHandler implements \SessionHandlerInterface
function read ($sessionId) function read ($sessionId)
{ {
$this->db->query ('DO GET_LOCK(#, 10)', [$sessionId]);
$sessionData = $this->db->getValue ( $sessionData = $this->db->getValue (
'SELECT data FROM userSession WHERE ssid = # FOR UPDATE', [$sessionId]); 'SELECT data FROM userSession WHERE ssid = #', [$sessionId]);
return isset ($sessionData) ? $sessionData : ''; return isset ($sessionData) ? $sessionData : '';
} }
@ -37,7 +36,6 @@ class DbSessionHandler implements \SessionHandlerInterface
ON DUPLICATE KEY UPDATE ON DUPLICATE KEY UPDATE
data = VALUES(data), lastUpdate = VALUES(lastUpdate)', data = VALUES(data), lastUpdate = VALUES(lastUpdate)',
[$sessionId, $sessionData]); [$sessionId, $sessionData]);
$this->db->query ('DO RELEASE_LOCK(#)', [$sessionId]);
return TRUE; return TRUE;
} }
@ -56,4 +54,3 @@ class DbSessionHandler implements \SessionHandlerInterface
return TRUE; return TRUE;
} }
} }

View File

@ -2,21 +2,31 @@
namespace Vn\Web; namespace Vn\Web;
require_once __DIR__.'/html.php';
use Vn\Lib\Locale; use Vn\Lib\Locale;
/** /**
* Base class for services that sends response as HTML format. * Base class for services that sends response as HTML format.
**/ */
class HtmlService extends Service 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);
} }
@ -94,44 +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 getUrl ($fileName)
{
/* if (file_exists ($fileName))
$mTime = '?'. strftime ('%G%m%d%H%M%S', filemtime ($fileName));
else
*/ $mTime = '?'. $this->getVersion ();
return $fileName.$mTime;
}
function includeJs ($fileName)
{
echo '<script type="text/javascript" src="'. $this->getUrl ($fileName) .'"></script>'."\n\t\t";
}
function includeLib ($libName)
{
$args = func_get_args ();
$localeJs = 'locale/'. Locale::get () .'/js/'. $libName .'.js';
if (file_exists ($localeJs))
$this->includeJs ($localeJs);
for ($i = 1; $i < count ($args); $i++)
$this->includeJs ("js/$libName/{$args[$i]}.js");
}
function includeCss ($fileName)
{
echo '<link rel="stylesheet" type="text/css" href="'. $this->getUrl ($fileName) .'"/>'."\n\t\t";
} }
function isMobile () function isMobile ()
@ -140,4 +118,3 @@ class HtmlService extends Service
return preg_match ($re, $_SERVER['HTTP_USER_AGENT']); return preg_match ($re, $_SERVER['HTTP_USER_AGENT']);
} }
} }

66
web/html.php Normal file
View File

@ -0,0 +1,66 @@
<?php
function getUrl ($fileName)
{
if (file_exists ($fileName))
$mTime = '?'. strftime ('%G%m%d%H%M%S', filemtime ($fileName));
else
$mTime = '?'. $this->getVersion ();
return $fileName.$mTime;
}
function js ($fileName)
{
return '<script type="text/javascript" src="'. getUrl ($fileName) .'"></script>'."\n";
}
function css ($fileName)
{
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

@ -6,7 +6,7 @@ use Vn\Lib;
/** /**
* Base class for JSON application. * Base class for JSON application.
**/ */
class JsonService extends RestService class JsonService extends RestService
{ {
private $warnings = NULL; private $warnings = NULL;
@ -17,16 +17,9 @@ 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 ();
// Checks the client version
if (!empty ($_COOKIE['vnVersion']))
$clientVersion = (int) $_COOKIE['vnVersion'];
if (isset ($clientVersion)
&& $clientVersion < $this->getVersion ())
throw new OutdatedVersionException ();
$json = $this->loadMethod (__NAMESPACE__.'\JsonRequest'); $json = $this->loadMethod (__NAMESPACE__.'\JsonRequest');
$this->replyJson ($json); $this->replyJson ($json);
@ -117,4 +110,3 @@ class JsonService extends RestService
throw $e; throw $e;
} }
} }

View File

@ -86,4 +86,3 @@ class Jwt
return base64_decode (str_pad ($data, $remainder, '=', STR_PAD_RIGHT)); return base64_decode (str_pad ($data, $remainder, '=', STR_PAD_RIGHT));
} }
} }

View File

@ -8,46 +8,58 @@ use Vn\Lib\UserException;
class Mailer class Mailer
{ {
static function send ($db, $mailTo, $body, $subject) private $conf;
function __construct ($db)
{ {
$conf = $db->getRow ( $this->conf = $db->getObject (
'SELECT host, port, secure, sender, sender_name, user, password 'SELECT host, port, secure, sender, sender_name, user, password
FROM mail_config' FROM hedera.mail_config'
); );
}
function createObject ($mailTo, $body, $subject)
{
$conf = $this->conf;
$mail = new \PHPMailer (); $mail = new \PHPMailer ();
$mail->isSMTP (); $mail->isSMTP ();
$mail->Host = $conf['host']; $mail->Host = $conf->host;
if (!empty ($conf['user'])) if (!empty ($conf->user))
{ {
$mail->SMTPAuth = TRUE; $mail->SMTPAuth = TRUE;
$mail->Username = $conf['user']; $mail->Username = $conf->user;
$mail->Password = base64_decode ($conf['password']); $mail->Password = base64_decode ($conf->password);
} }
else else
$mail->SMTPAuth = FALSE; $mail->SMTPAuth = FALSE;
if ($conf['secure']) if ($conf->secure)
{ {
$mail->SMTPSecure = 'ssl'; $mail->SMTPSecure = 'ssl';
$mail->Port = 465; $mail->Port = 465;
} }
$mail->setFrom ($conf['sender'], $conf['sender_name']); $mail->setFrom ($conf->sender, $conf->sender_name);
$mail->IsHTML (TRUE);
$mail->Subject = $subject;
$mail->Body = $body;
$mail->CharSet = 'UTF-8';
$mailList = explode (',', $mailTo); $mailList = explode (',', $mailTo);
foreach ($mailList as $to) foreach ($mailList as $to)
$mail->AddAddress ($to); $mail->AddAddress ($to);
$mail->IsHTML (TRUE); return $mail;
$mail->Subject = $subject; }
$mail->Body = $body;
$mail->CharSet = 'UTF-8'; function send ($mailTo, $body, $subject)
{
$mail = $this->createObject ($mailTo, $body, $subject);
if (!$mail->Send ()) if (!$mail->Send ())
throw new UserException ('Send error: '.$mail->ErrorInfo); throw new UserException ('Send error: '.$mail->ErrorInfo);
} }
} }

View File

@ -38,7 +38,7 @@ class Report
function sendMail ($mail) function sendMail ($mail)
{ {
Mailer::send ($this->db, $mail, $this->html, $this->title); $mailer = new Mailer ($this->db);
$mailer->send ($mail, $this->html, $this->title);
} }
} }

View File

@ -18,4 +18,3 @@ abstract class RestRequest extends \Vn\Lib\Method
var $service; var $service;
} }

View File

@ -3,10 +3,12 @@
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.
**/ */
class RestService extends Service class RestService extends Service
{ {
function run () function run ()
@ -15,9 +17,56 @@ 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/'. dirname ($_REQUEST['method']));
$res = NULL;
try {
$res = $method->run ($methodDb);
}
catch (Db\Exception $e)
{
if ($e->getCode () == 1644)
throw new UserException (s($e->getMessage ()));
}
$db->query ('CALL account.userLogout ()');
return $res;
}
function statusFromException ($e) function statusFromException ($e)
{ {
@ -58,4 +107,3 @@ class RestService extends Service
throw $e; throw $e;
} }
} }

View File

@ -13,22 +13,22 @@ const WEEK = 7 * DAY;
/** /**
* Thrown when user credentials could not be fetched. * Thrown when user credentials could not be fetched.
**/ */
class SessionExpiredException extends UserException {} class SessionExpiredException extends UserException {}
/** /**
* Thrown when user credentials are invalid. * Thrown when user credentials are invalid.
**/ */
class BadLoginException extends UserException {} class BadLoginException extends UserException {}
/** /**
* Thrown when client version is outdated. * Thrown when client version is outdated.
**/ */
class OutdatedVersionException extends UserException {} class OutdatedVersionException extends UserException {}
/** /**
* Main class for web applications. * Main class for web applications.
**/ */
abstract class Service abstract class Service
{ {
protected $app; protected $app;
@ -38,15 +38,19 @@ 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 ();
} }
/** /**
* Starts the user session. * Starts the user session.
**/ */
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');
@ -131,7 +135,7 @@ abstract class Service
* using base64_decode(). * using base64_decode().
* *
* return Db\Conn The database connection * return Db\Conn The database connection
**/ */
function login () function login ()
{ {
$db = $this->db; $db = $this->db;
@ -148,7 +152,10 @@ abstract class Service
catch (Db\Exception $e) catch (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;
} }
@ -211,7 +218,7 @@ abstract class Service
/** /**
* Logouts the current user. Cleans the last saved used credentials. * Logouts the current user. Cleans the last saved used credentials.
**/ */
function logout () function logout ()
{ {
unset ($_SESSION['user']); unset ($_SESSION['user']);
@ -222,7 +229,7 @@ abstract class Service
* is the current logged user. * is the current logged user.
* *
* @return {Db\Conn} The database connection * @return {Db\Conn} The database connection
**/ */
function getUserDb ($user) function getUserDb ($user)
{ {
if ($this->userDb) if ($this->userDb)
@ -240,7 +247,7 @@ abstract class Service
* @param {boolean} $remember Wether to create long live token * @param {boolean} $remember Wether to create long live token
* @param {boolean} $recover Wether to enable recovery mode on login * @param {boolean} $recover Wether to enable recovery mode on login
* @return {string} The JWT generated token * @return {string} The JWT generated token
**/ */
function createToken ($user, $remember = FALSE, $recover = FALSE) function createToken ($user, $remember = FALSE, $recover = FALSE)
{ {
if ($remember) if ($remember)
@ -259,100 +266,75 @@ abstract class Service
$key = $this->db->getValue ('SELECT jwtKey FROM config'); $key = $this->db->getValue ('SELECT jwtKey FROM config');
return Jwt::encode ($payload, $key); return Jwt::encode ($payload, $key);
} }
/**
* Obtains the application version number. It is extracted and
* cached from package.json file.
*
* @return string The version number
*/
function getVersion ()
{
$appName = $this->app->getName ();
$version = apc_fetch("$appName.version", $success);
if (!$success)
{
if (file_exists ('package.json'))
{
$package = json_decode (file_get_contents ('package.json'));
$version = $package->version;
}
else
$version = '0.0.0';
apc_store ("$appName.version", $version);
}
return $version;
}
/** /**
* Runs a method. * Checks the client version.
**/ */
function loadMethod ($class) function checkVersion ()
{ {
$db = $this->db; if (!empty ($_COOKIE['vnVersion']))
$this->login (); $clientVersion = $_COOKIE['vnVersion'];
$method = $this->app->loadMethod ( if (isset ($clientVersion)
$_REQUEST['method'], $class, './rest'); && $clientVersion < $this->getVersion ())
$method->service = $this; throw new OutdatedVersionException ();
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/'. dirname ($_REQUEST['method']));
$res = NULL;
try {
$res = $method->run ($methodDb);
}
catch (Db\Exception $e)
{
if ($e->getCode () == 1644)
throw new UserException (s($e->getMessage ()));
}
$db->query ('CALL account.userLogout ()');
return $res;
} }
/** /**
* Checks if the HTTP connection is secure. * Checks if the HTTP connection is secure.
* *
* @return boolean Return %TRUE if its secure, %FALSE otherwise * @return boolean Return %TRUE if its secure, %FALSE otherwise
**/ */
function isHttps () function isHttps ()
{ {
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.
* *
* @return string The current URL * @return string The current URL
**/ */
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()}";
}
/**
* Obtains the application version number. It is based on de last
* modification date of the main script.
*
* @return string The version number
**/
function getVersion ()
{
return (int) strftime ('%G%m%d%H%M%S',
filectime ($_SERVER['SCRIPT_FILENAME']));
}
/**
* Obtains the relative path to document root from an absolute path.
*
* @return string The relative path
**/
function getDir ($absoluteDir)
{
error_log ("Absolute: $absoluteDir");
error_log ("Root: {$_SERVER['DOCUMENT_ROOT']}");
error_log ("Script: {$_SERVER['SCRIPT_FILENAME']}");
error_log ("Self: {$_SERVER['PHP_SELF']}");
$rootLen = strlen ($_SERVER['DOCUMENT_ROOT']);
return substr ($absoluteDir, $rootLen);
} }
} }

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>

View File

@ -9,7 +9,7 @@ class Util
* *
* @param string file The file path * @param string file The file path
* @param boolean useXsendfile Wether to use the apache module Xsendfile * @param boolean useXsendfile Wether to use the apache module Xsendfile
**/ */
static function printFile ($file, $useXsendfile = FALSE) static function printFile ($file, $useXsendfile = FALSE)
{ {
if (!file_exists ($file)) if (!file_exists ($file))
@ -41,4 +41,3 @@ class Util
} }
} }
} }

View File

@ -1,21 +1,23 @@
var webpack = require ('webpack');
var path = require ('path'); var path = require ('path');
var webpack = require ('webpack');
var AssetsWebpackPlugin = require ('assets-webpack-plugin');
var WebpackChunkHash = require ('webpack-chunk-hash');
var merge = require ('webpack-merge');
var wpConfig = require ('./webpack.config.json');
var devMode = process.env.NODE_ENV !== 'production'; var devMode = process.env.NODE_ENV !== 'production';
var outputPath = path.join (__dirname, wpConfig.buildDir);
var publicPath = wpConfig.buildDir +'/';
var config = { var baseConfig = {
entry: ['./app.js'], entry: wpConfig.entry,
output: { output: {
path: path.join (__dirname, 'build'), path: outputPath,
filename: 'hedera-web.js', publicPath: publicPath
chunkFilename: 'chunk.[id].[chunkhash].js',
publicPath: 'build/'
}, },
module: { module: {
rules: [ rules: [
{ test: /\.css$/, loader: 'style-loader!css-loader' }, { test: /\.css$/, loader: 'style-loader!css-loader' },
{ test: /\.json$/, loader: 'json-loader' },
{ test: /\.xml$/, loader: 'raw-loader' }, { test: /\.xml$/, loader: 'raw-loader' },
{ test: /\.ttf$/, loader: 'file-loader' } { test: /\.ttf$/, loader: 'file-loader' }
] ]
@ -28,28 +30,59 @@ var config = {
'/usr/lib/node_modules' '/usr/lib/node_modules'
] ]
}, },
plugins: [ node: {
new webpack.DefinePlugin ({ _DEV_MODE: devMode }) __dirname: true
],
devServer: {
inline: true,
host: '0.0.0.0',
port: '9000',
headers: { "Access-Control-Allow-Origin": "*" }
}, },
devtool: 'eval-source-map' plugins: [
new webpack.DefinePlugin ({
_DEV_MODE: devMode,
_DEV_SERVER_PORT: wpConfig.devServerPort,
_PUBLIC_PATH: JSON.stringify (publicPath)
}),
new webpack.optimize.CommonsChunkPlugin ({
names: ['vendor', 'manifest']
})
],
watchOptions: {
ignored: /node_modules/
}
}; };
if (!devMode) var prodConfig = {
{ output: {
config.plugins.push ( filename: '[name].[chunkhash].js',
chunkFilename: 'chunk.[id].[chunkhash].js'
},
plugins: [
new webpack.optimize.UglifyJsPlugin ({ new webpack.optimize.UglifyJsPlugin ({
minimize: true, minimize: true,
compress: { warnings: false } compress: { warnings: false }
}) }),
); new AssetsWebpackPlugin ({
config.devtool = 'source-map'; path: outputPath
} }),
new webpack.HashedModuleIdsPlugin (),
new WebpackChunkHash ()
],
devtool: 'source-map'
};
module.exports = config; var devConfig = {
output: {
filename: '[name].js',
chunkFilename: 'chunk.[id].js'
},
plugins: [
new webpack.NamedModulesPlugin ()
],
devServer: {
host: '0.0.0.0',
port: wpConfig.devServerPort,
headers: { 'Access-Control-Allow-Origin': '*' },
stats: { chunks: false }
},
devtool: 'eval'
};
var mrgConfig = devMode ? devConfig : prodConfig;
module.exports = merge (baseConfig, mrgConfig);

8
webpack.config.json Normal file
View File

@ -0,0 +1,8 @@
{
"buildDir": "build",
"devServerPort": 9000,
"entry": {
"main": "./app.js",
"vendor": "mootools"
}
}