Features: simple admin menu, public tracks
This commit is contained in:
parent
0d396a34ec
commit
41eb7df3fc
3
README
3
README
@ -24,8 +24,9 @@ Features:
|
|||||||
Todo
|
Todo
|
||||||
- install script
|
- install script
|
||||||
- custom icons
|
- custom icons
|
||||||
- admin page (users management)
|
- admin menu (users management)
|
||||||
- track editing
|
- track editing
|
||||||
|
- track display filters (accurracy, provider)
|
||||||
|
|
||||||
License
|
License
|
||||||
- GPL
|
- GPL
|
||||||
|
92
adduser.php
Normal file
92
adduser.php
Normal 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
79
admin.js
Normal 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()">×</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;
|
||||||
|
}
|
9
auth.php
9
auth.php
@ -95,7 +95,7 @@ if ($require_authentication || defined('headless')) {
|
|||||||
$query = $mysqli->prepare("SELECT id, login, password FROM users WHERE login=? LIMIT 1");
|
$query = $mysqli->prepare("SELECT id, login, password FROM users WHERE login=? LIMIT 1");
|
||||||
$query->bind_param('s', $user);
|
$query->bind_param('s', $user);
|
||||||
$query->execute();
|
$query->execute();
|
||||||
$query->bind_result($rec_ID, $rec_user, $rec_pass);
|
$query->bind_result($rec_id, $rec_user, $rec_pass);
|
||||||
$query->fetch();
|
$query->fetch();
|
||||||
$query->free_result();
|
$query->free_result();
|
||||||
//correct pass
|
//correct pass
|
||||||
@ -111,14 +111,9 @@ if ($require_authentication || defined('headless')) {
|
|||||||
if (($user == $admin_user) && !empty($admin_user)) {
|
if (($user == $admin_user) && !empty($admin_user)) {
|
||||||
$_SESSION['admin'] = $admin_user;
|
$_SESSION['admin'] = $admin_user;
|
||||||
}
|
}
|
||||||
$_SESSION['auth'] = $rec_ID;
|
$_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 {
|
|
||||||
$url = str_replace("//", "/", $_SERVER['HTTP_HOST'].dirname($_SERVER['SCRIPT_NAME'])."/index.php");
|
$url = str_replace("//", "/", $_SERVER['HTTP_HOST'].dirname($_SERVER['SCRIPT_NAME'])."/index.php");
|
||||||
header("Location: $ssl://$url");
|
header("Location: $ssl://$url");
|
||||||
}
|
|
||||||
exit();
|
exit();
|
||||||
} else {
|
} else {
|
||||||
// unsuccessful
|
// unsuccessful
|
||||||
|
@ -57,14 +57,14 @@ $dbname = ""; // database name
|
|||||||
// (0 = no, 1 = yes)
|
// (0 = no, 1 = yes)
|
||||||
$require_authentication = 1;
|
$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
|
// admin user who has access to all users locations
|
||||||
// none if empty
|
// none if empty
|
||||||
$admin_user = "";
|
$admin_user = "";
|
||||||
|
|
||||||
// allow automatic registration of new users
|
|
||||||
// (0 = no, 1 = yes)
|
|
||||||
$allow_registration = 0;
|
|
||||||
|
|
||||||
// Default interval in seconds for live auto reload
|
// Default interval in seconds for live auto reload
|
||||||
$interval = 10;
|
$interval = 10;
|
||||||
|
|
||||||
|
21
index.php
21
index.php
@ -19,7 +19,8 @@
|
|||||||
*/
|
*/
|
||||||
require_once("auth.php");
|
require_once("auth.php");
|
||||||
|
|
||||||
if ($auth && !$admin) {
|
if ($auth && !$admin && !$public_tracks) {
|
||||||
|
// only authorized user tracks
|
||||||
// get username
|
// get username
|
||||||
$query = "SELECT login FROM users WHERE id='$auth' LIMIT 1";
|
$query = "SELECT login FROM users WHERE id='$auth' LIMIT 1";
|
||||||
$result = $mysqli->query($query);
|
$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>)';
|
$user_form = '<u>'.$lang_user.'</u><br />'.$user.' (<a href="logout.php">'.$lang_logout.'</a>)';
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// free access or admin user
|
// public access or admin user
|
||||||
// prepare user select form
|
// prepare user select form
|
||||||
if ($admin) {
|
if ($admin) {
|
||||||
$user = $admin_user;
|
$user = $admin_user;
|
||||||
@ -71,7 +72,7 @@ $track_form = '
|
|||||||
<form>
|
<form>
|
||||||
<select name="track" onchange="selectTrack(this)">';
|
<select name="track" onchange="selectTrack(this)">';
|
||||||
$userid = "";
|
$userid = "";
|
||||||
if ($auth && !$admin) {
|
if ($auth && !$admin && !$public_tracks) {
|
||||||
// display track of authenticated user
|
// display track of authenticated user
|
||||||
$userid = $auth;
|
$userid = $auth;
|
||||||
} elseif ($last_id) {
|
} elseif ($last_id) {
|
||||||
@ -124,6 +125,18 @@ $units_form = '
|
|||||||
</select>
|
</select>
|
||||||
</form>
|
</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
|
print
|
||||||
'<!DOCTYPE html>
|
'<!DOCTYPE html>
|
||||||
@ -176,6 +189,7 @@ else {
|
|||||||
';
|
';
|
||||||
}
|
}
|
||||||
print '
|
print '
|
||||||
|
'.$admin_script.'
|
||||||
<script type="text/javascript" src="//www.google.com/jsapi"></script>
|
<script type="text/javascript" src="//www.google.com/jsapi"></script>
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
google.load("visualization", "1", {packages:["corechart"]});
|
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(\'kml\',userid,trackid)">kml</a><br />
|
||||||
<a href="javascript:void(0);" onclick="load(\'gpx\',userid,trackid)">gpx</a><br />
|
<a href="javascript:void(0);" onclick="load(\'gpx\',userid,trackid)">gpx</a><br />
|
||||||
</div>
|
</div>
|
||||||
|
'.$admin_menu.'
|
||||||
</div>
|
</div>
|
||||||
<div id="menu-close" onclick="toggleMenu();">»</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>
|
<div id="footer"><a target="_blank" href="https://github.com/bfabiszewski/ulogger-server"><span class="mi">μ</span>logger</a> '.$version.'</div>
|
||||||
|
15
lang.php
15
lang.php
@ -53,6 +53,9 @@ switch($lang) {
|
|||||||
$lang_units = "Units";
|
$lang_units = "Units";
|
||||||
$lang_metric = "Metric";
|
$lang_metric = "Metric";
|
||||||
$lang_imperial = "Imperial/US";
|
$lang_imperial = "Imperial/US";
|
||||||
|
$lang_adminmenu = "Administration";
|
||||||
|
$lang_adduser = "Add user";
|
||||||
|
$lang_userexists = "User exists";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "pl":
|
case "pl":
|
||||||
@ -89,6 +92,9 @@ switch($lang) {
|
|||||||
$lang_units = "Jednostki";
|
$lang_units = "Jednostki";
|
||||||
$lang_metric = "Metryczne";
|
$lang_metric = "Metryczne";
|
||||||
$lang_imperial = "Anglosaskie";
|
$lang_imperial = "Anglosaskie";
|
||||||
|
$lang_adminmenu = "Administracja";
|
||||||
|
$lang_adduser = "Dodaj użytkownika";
|
||||||
|
$lang_userexists = "Użytkownik istnieje";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "de":
|
case "de":
|
||||||
@ -125,6 +131,11 @@ switch($lang) {
|
|||||||
$lang_units = "Maßsystem";
|
$lang_units = "Maßsystem";
|
||||||
$lang_metric = "Metrisches";
|
$lang_metric = "Metrisches";
|
||||||
$lang_imperial = "Angloamerikanisches";
|
$lang_imperial = "Angloamerikanisches";
|
||||||
|
$lang_adminmenu = "Verwaltung";
|
||||||
|
|
||||||
|
// todo: translate
|
||||||
|
$lang_adduser = "Add user";
|
||||||
|
$lang_userexists = "User exists";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "hu":
|
case "hu":
|
||||||
@ -161,6 +172,10 @@ switch($lang) {
|
|||||||
$lang_units = "Mértékegység";
|
$lang_units = "Mértékegység";
|
||||||
$lang_metric = "Metrikus";
|
$lang_metric = "Metrikus";
|
||||||
$lang_imperial = "Imperal/US";
|
$lang_imperial = "Imperal/US";
|
||||||
|
$lang_adminmenu = "Adminisztráció";
|
||||||
|
// todo: translate
|
||||||
|
$lang_adduser = "Add user";
|
||||||
|
$lang_userexists = "User exists";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
|
44
main.css
44
main.css
@ -187,3 +187,47 @@ select {
|
|||||||
padding-right:0.1em;
|
padding-right:0.1em;
|
||||||
font-style:italic;
|
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;
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user