Done login flow to obtain session cookie + more base code

* Added templating system for .php files inside _templates/
* Use templating system with tpl* functions in base.php
* Added templating to include scripts and other properties for tpl .php files
* Added http.js, a regular JS helper for xhr-related operations
* Added COOKIE check in PHP to redirect to APP_DIR
This commit is contained in:
Niko 2022-02-09 22:22:41 +01:00
parent 56bca7e0a0
commit 46f922721d
6 changed files with 172 additions and 11 deletions

View File

@ -0,0 +1,2 @@
</body>
</html>

View File

@ -0,0 +1,14 @@
<html>
<head>
<title><?php echo $title ?></title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- TODO: include later
<link rel="manifest" href="/manifest.json">
<link rel="stylesheet" href="/fonts/forkawesome/css/fork-awesome.min.css">
<script type="application/javascript" src="/js/dayjs.min.js"></script>
<script type="application/javascript" src="/js/relativeTime.js"></script>
<script type="application/javascript" src="/js/updateLocale.js"></script>
-->
<?php tpl_scripts($scripts ?? null) ?>
</head>
<body>

87
web/src/app/js/http.js Normal file
View File

@ -0,0 +1,87 @@
function isVisible(element) {
const rect = element.getBoundingClientRect();
return (
rect.top >= 0 &&
rect.left >= 0 &&
rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
rect.right <= (window.innerWidth || document.documentElement.clientWidth)
);
}
function html2text(html) {
var e = document.createElement('div');
e.innerHTML = html;
const result = e.innerText;
e.remove();
return result;
}
function JSON_to_URLEncoded(element,key,list) {
var list = list || [];
if (typeof(element) == 'object') {
for (var idx in element)
JSON_to_URLEncoded(element[idx],key?key+'['+idx+']':idx,list);
} else {
list.push(key+'='+encodeURIComponent(element));
}
return list.join('&');
}
// source: https://www.geeksforgeeks.org/how-to-get-the-javascript-function-parameter-names-values-dynamically/
function _get_func_params(func) {
// String representaation of the function code
var str = func.toString();
// Remove comments of the form /* ... */
// Removing comments of the form //
// Remove body of the function { ... }
// removing '=>' if func is arrow function
str = str.replace(/\/\*[\s\S]*?\*\//g, '')
.replace(/\/\/(.)*/g, '')
.replace(/{[\s\S]*}/, '')
.replace(/=>/g, '')
.trim();
// Start parameter names after first '('
var start = str.indexOf("(") + 1;
// End parameter names is just before last ')'
var end = str.length - 1;
var result = str.substring(start, end).split(", ");
var params = [];
result.forEach(element => {
// Removing any default value
element = element.replace(/=[\s\S]*/g, '').trim();
if(element.length > 0)
params.push(element);
});
return params;
}
const http = {
request: function(method, path, payload, callbk) {
payload = payload || null;
callbk = callbk || null;
const oReq = new XMLHttpRequest();
oReq.addEventListener("load", function() {
if (callbk) {
const ps = _get_func_params(callbk);
if (ps.includes('data') || ps.includes('text') ||
ps.includes('html') || ps.includes('plain'))
callbk(this.responseText);
else if (ps.includes('json') || ps.includes('js')) {
try { callbk(JSON.parse(this.responseText)) }
catch (SyntaxError) { callbk(undefined) }
}
}
});
oReq.open(method, path);
oReq.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
oReq.send(JSON_to_URLEncoded(payload));
},
get: function(path, payload, callbk) {
return http.request('GET', path, payload, callbk);
},
post: function(path, payload, callbk) {
return http.request('POST', path, payload, callbk);
},
};

View File

@ -3,3 +3,34 @@
function s($name) {
echo $name;
}
function tpl($ns, $args=[]) {
$ns = str_replace('.','/',$ns);
$__tfile = "_templates/$ns.php";
if (file_exists($__tfile)) {
unset($ns);
extract($args);
unset($args);
require $__tfile;
}
}
function tpl_script($script) {
$suffix = '';
if (getenv('env') === DEV)
$suffix = '?_='.microtime();
echo APP_DIR.'/js/'.$script.'.js'.$suffix;
}
function tpl_scripts($scripts) {
foreach ($scripts as $script) {
$script = str_replace('.', '/', $script);
?><script type="application/javascript" src="<?php tpl_script($script) ?>"></script><?php
}
}
function cookie_redirect_app() {
// TODO: also check if cookie is valid to redirect
if (isset($_COOKIE['fedilove_session']))
redirect(APP_DIR);
}

View File

@ -2,23 +2,27 @@
chdir( $_SERVER['DOCUMENT_ROOT'] );
define('APP_DIR', '/app');
define('PROD', 'prod');
define('DEV', 'dev');
$env = getenv('ENV');
if (!in_array($env, [PROD, DEV]))
$env = DEV;
putenv('env='.$env);
if ($env === PROD) {
ini_set('display_errors', 0);
}
$uri = rtrim(trim($_SERVER['REQUEST_URI']),'/');
$simple_uri = preg_replace('/^\/app\//', '/', $uri);
$s_uri = preg_replace('/^'.preg_quote(
APP_DIR,'/').'\//', '/', $uri);
function req_pub($name) { require "public/$name.php"; die; }
function redirect($url) { header('Location: '.$url); die; }
# Public URLs
switch ($simple_uri)
switch ($s_uri)
{
case '/': req_pub('home');
case '/login': req_pub('login');

View File

@ -1,11 +1,34 @@
<?php require 'base.php' ?>
<?php
<?php cookie_redirect_app() ?>
<?php tpl('pub.header', [
'title' => ' s(login)',
'scripts' => ['http']
]) ?>
?>
<form id="login">
<span>Email</span>
<form id="login" onsubmit="return loginAction(event)">
<span><?php s('email') ?></span>
<input type="email" name="email" /><br>
<span>Password</span>
<span><?php s('password') ?></span>
<input type="password" name="password" /><br>
<input type="submit" value="<?php s('log_in') ?>" />
</form>
<script>
function loginAction(e) {
const payload = {
email: e.target.querySelector('*[name="email"]').value,
password: e.target.querySelector('*[name="password"]').value,
};
http.post('/api/v1/accounts/login', payload, function(json) {
if (json.error !== undefined)
console.error('TODO: to-screen: '+json.error);
else if (json.result !== undefined && json.result === 1)
window.location.href = '<?php echo APP_DIR ?>';
else
console.error('TODO: to-screen: unknown_error');
});
e.preventDefault();
return false;
}
</script>
<?php tpl('pub.footer') ?>