Features: simple admin menu, public tracks

This commit is contained in:
Bartek Fabiszewski 2017-02-17 16:41:39 +01:00
parent 0d396a34ec
commit 41eb7df3fc
8 changed files with 258 additions and 17 deletions

3
README
View File

@ -24,8 +24,9 @@ Features:
Todo
- install script
- custom icons
- admin page (users management)
- admin menu (users management)
- track editing
- track display filters (accurracy, provider)
License
- GPL

92
adduser.php Normal file
View File

@ -0,0 +1,92 @@
<?php
/* μlogger
*
* Copyright(C) 2017 Bartek Fabiszewski (www.fabiszewski.net)
*
* This is free software; you can redistribute it and/or modify it under
* the terms of the GNU Library General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
require_once("auth.php");
/**
* Exit with xml response
* @param boolean $isError Error if true
* @param string $errorMessage Optional error message
*/
function exitWithStatus($isError, $errorMessage = NULL) {
header("Content-type: text/xml");
$xml = new XMLWriter();
$xml->openURI("php://output");
$xml->startDocument("1.0");
$xml->setIndent(true);
$xml->startElement('root');
$xml->writeElement("error", (int) $isError);
if ($isError) {
$xml->writeElement("message", $errorMessage);
}
$xml->endElement();
$xml->endDocument();
$xml->flush();
exit;
}
/**
* Check if login is allowed
* @param string $login Login
*/
function checkUser($login) {
global $mysqli;
$sql = "SELECT id FROM users WHERE login = ?";
$query = $mysqli->prepare($sql);
$query->bind_param('s', $login);
$query->execute();
if ($query->errno) {
exitWithStatus(true, $query->error);
}
$query->store_result();
if ($query->num_rows) {
exitWithStatus(true, "User exists");
}
$query->free_result();
$query->close();
}
/**
* Add new user to database
* @param string $login Login
* @param string $hash Password hash
*/
function insertUser($login, $hash) {
global $mysqli;
$sql = "INSERT INTO users (login, password) VALUES (?, ?)";
$query = $mysqli->prepare($sql);
$query->bind_param('ss', $login, $hash);
$query->execute();
if ($query->errno) {
exitWithStatus(true, $query->error);
$isError = false;
}
$query->close();
}
$login = isset($_REQUEST['login']) ? trim($_REQUEST['login']) : NULL;
$hash = isset($_REQUEST['pass']) ? password_hash($_REQUEST['pass'], PASSWORD_DEFAULT) : NULL;
if ($admin && !empty($login) && !empty($hash)) {
checkUser($login);
insertUser($login, $hash);
}
exitWithStatus(false);
?>

79
admin.js Normal file
View File

@ -0,0 +1,79 @@
/* μlogger
*
* Copyright(C) 2017 Bartek Fabiszewski (www.fabiszewski.net)
*
* This is free software; you can redistribute it and/or modify it under
* the terms of the GNU Library General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
function showModal(contentHTML) {
var div = document.createElement("div");
div.setAttribute("id", "modal");
div.innerHTML = '<div id="modal-header"><button type="button" onclick="removeModal()">&times;</button></div><div id="modal-body"></div>';
document.body.appendChild(div);
var modalBody = document.getElementById('modal-body');
modalBody.innerHTML = contentHTML;
}
function removeModal() {
document.body.removeChild(document.getElementById('modal'));
}
function addUser() {
var form = '<form id="userForm" method="post" onsubmit="submitUser(); return false">';
form += '<label><b>User name</b></label><input type="text" placeholder="Enter user login" name="login" required>';
form += '<label><b>Password</b></label><input type="password" placeholder="Enter Password" name="pass" required>';
form += '<label><b>Repeat password</b></label><input type="password" placeholder="Enter Password" name="pass2" required>';
form += '<button type="button" onclick="removeModal()">Cancel</button><button type="submit">Submit</button>';
form += '</form>';
showModal(form);
}
function submitUser() {
var form = document.getElementById('userForm');
var login = form.elements['login'].value;
var pass = form.elements['pass'].value;
var pass2 = form.elements['pass2'].value;
if (!login || !pass || !pass2) {
alert("All fields are required");
return;
}
if (pass != pass2) {
alert("Passwords don't match");
return;
}
var xhr = getXHR();
xhr.onreadystatechange = function() {
if (xhr.readyState==4 && xhr.status==200) {
var xml = xhr.responseXML;
var message = "";
if (xml) {
var root = xml.getElementsByTagName('root');
if (root.length && getNode(root[0], 'error') == 0) {
removeModal();
alert("User successfully added");
return;
}
errorMsg = getNode(root[0], 'message');
if (errorMsg) { message = errorMsg; }
}
alert("Something went wrong\n" + message);
xhr = null;
}
}
xhr.open('POST', 'adduser.php', true);
xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
xhr.send('login=' + login + '&pass=' + pass);
return;
}

View File

@ -95,7 +95,7 @@ if ($require_authentication || defined('headless')) {
$query = $mysqli->prepare("SELECT id, login, password FROM users WHERE login=? LIMIT 1");
$query->bind_param('s', $user);
$query->execute();
$query->bind_result($rec_ID, $rec_user, $rec_pass);
$query->bind_result($rec_id, $rec_user, $rec_pass);
$query->fetch();
$query->free_result();
//correct pass
@ -111,14 +111,9 @@ if ($require_authentication || defined('headless')) {
if (($user == $admin_user) && !empty($admin_user)) {
$_SESSION['admin'] = $admin_user;
}
$_SESSION['auth'] = $rec_ID;
if (defined('headless')) {
$url = str_replace("//", "/", $_SERVER['HTTP_HOST'].dirname($_SERVER['SCRIPT_NAME'])."/client/index.php");
header("Location: $ssl://$url");
} else {
$_SESSION['auth'] = $rec_id;
$url = str_replace("//", "/", $_SERVER['HTTP_HOST'].dirname($_SERVER['SCRIPT_NAME'])."/index.php");
header("Location: $ssl://$url");
}
exit();
} else {
// unsuccessful

View File

@ -57,14 +57,14 @@ $dbname = ""; // database name
// (0 = no, 1 = yes)
$require_authentication = 1;
// all users tracks are visible to authenticated user
// (0 = no, 1 = yes)
$public_tracks = 0;
// admin user who has access to all users locations
// none if empty
$admin_user = "";
// allow automatic registration of new users
// (0 = no, 1 = yes)
$allow_registration = 0;
// Default interval in seconds for live auto reload
$interval = 10;

View File

@ -19,7 +19,8 @@
*/
require_once("auth.php");
if ($auth && !$admin) {
if ($auth && !$admin && !$public_tracks) {
// only authorized user tracks
// get username
$query = "SELECT login FROM users WHERE id='$auth' LIMIT 1";
$result = $mysqli->query($query);
@ -30,7 +31,7 @@ if ($auth && !$admin) {
$user_form = '<u>'.$lang_user.'</u><br />'.$user.' (<a href="logout.php">'.$lang_logout.'</a>)';
}
else {
// free access or admin user
// public access or admin user
// prepare user select form
if ($admin) {
$user = $admin_user;
@ -71,7 +72,7 @@ $track_form = '
<form>
<select name="track" onchange="selectTrack(this)">';
$userid = "";
if ($auth && !$admin) {
if ($auth && !$admin && !$public_tracks) {
// display track of authenticated user
$userid = $auth;
} elseif ($last_id) {
@ -124,6 +125,18 @@ $units_form = '
</select>
</form>
';
// admin menu
$admin_menu = '';
$admin_script = '';
if ($admin) {
$admin_menu = '
<div id="admin_menu">
<u>'.$lang_adminmenu.'</u><br />
<a href="javascript:void(0);" onclick="addUser()">'.$lang_adduser.'</a><br />
</div>
';
$admin_script = '<script type="text/javascript" src="admin.js"></script>';
}
print
'<!DOCTYPE html>
@ -176,6 +189,7 @@ else {
';
}
print '
'.$admin_script.'
<script type="text/javascript" src="//www.google.com/jsapi"></script>
<script type="text/javascript">
google.load("visualization", "1", {packages:["corechart"]});
@ -211,6 +225,7 @@ print '
<a href="javascript:void(0);" onclick="load(\'kml\',userid,trackid)">kml</a><br />
<a href="javascript:void(0);" onclick="load(\'gpx\',userid,trackid)">gpx</a><br />
</div>
'.$admin_menu.'
</div>
<div id="menu-close" onclick="toggleMenu();">»</div>
<div id="footer"><a target="_blank" href="https://github.com/bfabiszewski/ulogger-server"><span class="mi">μ</span>logger</a> '.$version.'</div>

View File

@ -53,6 +53,9 @@ switch($lang) {
$lang_units = "Units";
$lang_metric = "Metric";
$lang_imperial = "Imperial/US";
$lang_adminmenu = "Administration";
$lang_adduser = "Add user";
$lang_userexists = "User exists";
break;
case "pl":
@ -89,6 +92,9 @@ switch($lang) {
$lang_units = "Jednostki";
$lang_metric = "Metryczne";
$lang_imperial = "Anglosaskie";
$lang_adminmenu = "Administracja";
$lang_adduser = "Dodaj użytkownika";
$lang_userexists = "Użytkownik istnieje";
break;
case "de":
@ -125,6 +131,11 @@ switch($lang) {
$lang_units = "Maßsystem";
$lang_metric = "Metrisches";
$lang_imperial = "Angloamerikanisches";
$lang_adminmenu = "Verwaltung";
// todo: translate
$lang_adduser = "Add user";
$lang_userexists = "User exists";
break;
case "hu":
@ -161,6 +172,10 @@ switch($lang) {
$lang_units = "Mértékegység";
$lang_metric = "Metrikus";
$lang_imperial = "Imperal/US";
$lang_adminmenu = "Adminisztráció";
// todo: translate
$lang_adduser = "Add user";
$lang_userexists = "User exists";
break;
}
?>

View File

@ -187,3 +187,47 @@ select {
padding-right:0.1em;
font-style:italic;
}
#modal {
display: block;
position: fixed;
z-index: 10010;
left: 0;
top: 0;
width: 100%;
height: 100%;
overflow: auto;
background-color: black; /* fallback */
background-color: rgba(0,0,0,0.4);
padding-top: 10%;
}
#modal-header {
top: 10px;
position: relative;
text-align: right;
margin: 0 auto;
width: 40%;
min-width: 300px;
}
#modal-body {
font-size: 0.9em;
font-family: Verdana, sans-serif;
color: white;
background-color: #666;
margin: 0 auto 15% auto;
border: 1px solid #888;
width: 40%;
min-width: 300px;
padding: 1%;
}
#modal input[type=text], #modal input[type=password] {
width: 100%;
padding: 0.4em;
margin: 0.8em 0;
display: inline-block;
border: 1px solid #ccc;
box-sizing: border-box;
}