Fix issues in last position of all users, add tests, closes #9

This commit is contained in:
Bartek Fabiszewski 2019-03-02 23:53:45 +01:00
parent 25c1b24c49
commit 5c8381d29e
8 changed files with 212 additions and 118 deletions

View File

@ -150,6 +150,87 @@ class InternalAPITest extends UloggerAPITestCase {
$this->assertEquals((string) $position->trackname, $this->testTrackName, "Wrong trackname");
}
public function testGetPositionsUserLatest() {
$this->assertTrue($this->authenticate(), "Authentication failed");
$trackId = $this->addTestTrack($this->testUserId);
$this->addTestPosition($this->testUserId, $trackId, $this->testTimestamp);
$this->addTestPosition($this->testUserId, $trackId, $this->testTimestamp + 3);
$this->assertEquals(1, $this->getConnection()->getRowCount("tracks"), "Wrong row count");
$this->assertEquals(2, $this->getConnection()->getRowCount("positions"), "Wrong row count");
$userId = $this->addTestUser($this->testUser, password_hash($this->testPass, PASSWORD_DEFAULT));
$trackId2 = $this->addTestTrack($userId);
$this->addTestPosition($userId, $trackId2, $this->testTimestamp + 2);
$this->addTestPosition($userId, $trackId2, $this->testTimestamp + 1);
$this->assertEquals(2, $this->getConnection()->getRowCount("tracks"), "Wrong row count");
$this->assertEquals(4, $this->getConnection()->getRowCount("positions"), "Wrong row count");
$options = [
"http_errors" => false,
"query" => [ "userid" => $this->testUserId, "last" => 1 ],
];
$response = $this->http->get("/utils/getpositions.php", $options);
$this->assertEquals(200, $response->getStatusCode(), "Unexpected status code");
$xml = $this->getXMLfromResponse($response);
$this->assertTrue($xml !== false, "XML object is false");
$this->assertEquals($xml->position->count(), 1, "Wrong count of positions");
$position = $xml->position[0];
$this->assertEquals((int) $position["id"], 2, "Wrong position id");
$this->assertEquals((float) $position->latitude, $this->testLat, "Wrong latitude");
$this->assertEquals((float) $position->longitude, $this->testLon, "Wrong longitude");
$this->assertEquals((int) $position->timestamp, $this->testTimestamp + 3, "Wrong timestamp");
$this->assertEquals((string) $position->username, $this->testAdminUser, "Wrong username");
$this->assertEquals((string) $position->trackname, $this->testTrackName, "Wrong trackname");
}
public function testGetPositionsAllUsersLatest() {
$this->assertTrue($this->authenticate(), "Authentication failed");
$userId = $this->addTestUser($this->testUser, password_hash($this->testPass, PASSWORD_DEFAULT));
$trackId = $this->addTestTrack($this->testUserId);
$this->addTestPosition($this->testUserId, $trackId, $this->testTimestamp);
$this->addTestPosition($this->testUserId, $trackId, $this->testTimestamp + 3);
$this->assertEquals(1, $this->getConnection()->getRowCount("tracks"), "Wrong row count");
$this->assertEquals(2, $this->getConnection()->getRowCount("positions"), "Wrong row count");
$trackName = "Track 2";
$trackId2 = $this->addTestTrack($userId, $trackName);
$this->addTestPosition($userId, $trackId2, $this->testTimestamp + 2);
$this->addTestPosition($userId, $trackId2, $this->testTimestamp + 1);
$this->assertEquals(2, $this->getConnection()->getRowCount("tracks"), "Wrong row count");
$this->assertEquals(4, $this->getConnection()->getRowCount("positions"), "Wrong row count");
$options = [
"http_errors" => false,
"query" => [ "last" => 1 ],
];
$response = $this->http->get("/utils/getpositions.php", $options);
$this->assertEquals(200, $response->getStatusCode(), "Unexpected status code");
$xml = $this->getXMLfromResponse($response);
$this->assertTrue($xml !== false, "XML object is false");
$this->assertEquals($xml->position->count(), 2, "Wrong count of positions");
$position = $xml->position[0];
$this->assertEquals((int) $position["id"], 2, "Wrong position id");
$this->assertEquals((float) $position->latitude, $this->testLat, "Wrong latitude");
$this->assertEquals((float) $position->longitude, $this->testLon, "Wrong longitude");
$this->assertEquals((int) $position->timestamp, $this->testTimestamp + 3, "Wrong timestamp");
$this->assertEquals((string) $position->username, $this->testAdminUser, "Wrong username");
$this->assertEquals((string) $position->trackname, $this->testTrackName, "Wrong trackname");
$position = $xml->position[1];
$this->assertEquals((int) $position["id"], 3, "Wrong position id");
$this->assertEquals((float) $position->latitude, $this->testLat, "Wrong latitude");
$this->assertEquals((float) $position->longitude, $this->testLon, "Wrong longitude");
$this->assertEquals((int) $position->timestamp, $this->testTimestamp + 2, "Wrong timestamp");
$this->assertEquals((string) $position->username, $this->testUser, "Wrong username");
$this->assertEquals((string) $position->trackname, $trackName, "Wrong trackname");
}
public function testGetPositionsNoTrackId() {
$this->assertTrue($this->authenticate(), "Authentication failed");
@ -169,15 +250,7 @@ class InternalAPITest extends UloggerAPITestCase {
$xml = $this->getXMLfromResponse($response);
$this->assertTrue($xml !== false, "XML object is false");
$this->assertEquals($xml->position->count(), 1, "Wrong count of positions");
$position = $xml->position[0];
$this->assertEquals((int) $position["id"], 2, "Wrong position id");
$this->assertEquals((float) $position->latitude, $this->testLat, "Wrong latitude");
$this->assertEquals((float) $position->longitude, $this->testLon, "Wrong longitude");
$this->assertEquals((int) $position->timestamp, $this->testTimestamp + 1, "Wrong timestamp");
$this->assertEquals((string) $position->username, $this->testAdminUser, "Wrong username");
$this->assertEquals((string) $position->trackname, $this->testTrackName, "Wrong trackname");
$this->assertEquals(0, $xml->position->count(), "Wrong count of positions");
}
public function testGetPositionsNoUserId() {
@ -199,8 +272,8 @@ class InternalAPITest extends UloggerAPITestCase {
$xml = $this->getXMLfromResponse($response);
$this->assertTrue($xml !== false, "XML object is not false");
$this->assertEquals($xml->position->count(), 0, "Wrong count of positions");
$this->assertTrue($xml !== false, "XML object is false");
$this->assertEquals(0, $xml->position->count(), "Wrong count of positions");
}
public function testGetPositionsNoAuth() {

View File

@ -106,6 +106,38 @@ class PositionTest extends UloggerDatabaseTestCase {
$this->assertEquals($lastPosition->id, $pos4, "Wrong last position (user)");
}
public function testGetLastAllUsers() {
$userId = $this->addTestUser();
$userId2 = $this->addTestUser($this->testUser2);
$trackId1 = $this->addTestTrack($userId);
$trackId2 = $this->addTestTrack($userId);
$pos1 = $this->addTestPosition($userId, $trackId1, $this->testTimestamp + 3);
$pos2 = $this->addTestPosition($userId2, $trackId2, $this->testTimestamp + 1);
$pos3 = $this->addTestPosition($userId, $trackId1, $this->testTimestamp);
$pos4 = $this->addTestPosition($userId2, $trackId2, $this->testTimestamp + 2);
$this->assertEquals(2, $this->getConnection()->getRowCount('tracks'), "Wrong row count");
$this->assertEquals(4, $this->getConnection()->getRowCount('positions'), "Wrong row count");
$posArr = uPosition::getLastAllUsers();
$this->assertEquals(2, count($posArr), "Wrong row count");
foreach ($posArr as $position) {
/** @var uPosition $position */
switch ($position->id) {
case 1:
$this->assertEquals($this->testTimestamp + 3, $position->timestamp);
$this->assertEquals($userId, $position->userId);
$this->assertEquals($trackId1, $position->trackId);
break;
case 4:
$this->assertEquals($this->testTimestamp + 2, $position->timestamp);
$this->assertEquals($userId2, $position->userId);
$this->assertEquals($trackId2, $position->trackId);
break;
default:
$this->assert("Unexpected position: {$position->id}");
}
}
}
public function testGetAll() {
$userId = $this->addTestUser();
$userId2 = $this->addTestUser($this->testUser2);

View File

@ -203,53 +203,33 @@
}
/**
* Get last position data from database
* (for all users)
* Get last positions for all users
*
* @return array|bool Array of uPosition positions, false on error
*/
public static function getLastAllUsers() {
$query = "SELECT
p.id,
UNIX_TIMESTAMP(p.time) AS tstamp,
p.user_id,
p.track_id,
p.latitude,
p.longitude,
p.altitude,
p.speed,
p.bearing,
p.accuracy,
p.provider,
p.comment,
p.image_id,
u.login
FROM
" . self::db()->table('positions') . " p
LEFT JOIN " . self::db()->table('users') . " u
ON ( p.user_id = u.id )
$query = "SELECT p.id, " . self::db()->unix_timestamp('p.time') . " AS tstamp, p.user_id, p.track_id,
p.latitude, p.longitude, p.altitude, p.speed, p.bearing, p.accuracy, p.provider,
p.comment, p.image_id, u.login, t.name
FROM " . self::db()->table('positions') . " p
LEFT JOIN " . self::db()->table('users') . " u ON (p.user_id = u.id)
LEFT JOIN " . self::db()->table('tracks') . " t ON (p.track_id = t.id)
WHERE p.id = (
SELECT
p2.id
FROM
" . self::db()->table('positions') . " p2
WHERE
p2.user_id = p.user_id
ORDER BY
p2.time DESC,
p2.id DESC
SELECT p2.id FROM " . self::db()->table('positions') . " p2
WHERE p2.user_id = p.user_id
ORDER BY p2.time DESC, p2.id DESC
LIMIT 1
)";
$result = self::db()->query($query);
if ($result === false) {
return false;
}
$positionsArr = [];
while ($row = $result->fetch_assoc()) {
try {
$result = self::db()->query($query);
while ($row = $result->fetch()) {
$positionsArr[] = self::rowToObject($row);
}
$result->close();
} catch (PDOException $e) {
// TODO: handle exception
syslog(LOG_ERR, $e->getMessage());
}
return $positionsArr;
}
@ -281,8 +261,8 @@
LEFT JOIN " . self::db()->table('tracks') . " t ON (p.track_id = t.id)
$where
ORDER BY p.time, p.id";
try {
$positionsArr = [];
try {
$result = self::db()->query($query);
while ($row = $result->fetch()) {
$positionsArr[] = self::rowToObject($row);

View File

@ -68,9 +68,9 @@ function displayTrack(xml, update) {
var p = parsePosition(positions[i], i);
totalMeters += p.distance;
totalSeconds += p.seconds;
p['totalMeters'] = totalMeters;
p['totalSeconds'] = totalSeconds;
p['coordinates'] = new google.maps.LatLng(p.latitude, p.longitude);
p.totalMeters = totalMeters;
p.totalSeconds = totalSeconds;
p.coordinates = new google.maps.LatLng(p.latitude, p.longitude);
// set marker
setMarker(p, i, posLen);
// update polyline
@ -126,7 +126,7 @@ function setMarker(p, i, posLen) {
// marker
var marker = new google.maps.Marker({
map: map,
position: p.coordinates,
position: new google.maps.LatLng(p.latitude, p.longitude),
title: (new Date(p.timestamp * 1000)).toLocaleString()
});
if (latest == 1) { marker.setIcon('images/marker-red.png') }
@ -179,6 +179,15 @@ function getBounds() {
return [lon_sw, lat_sw, lon_ne, lat_ne];
}
function zoomToExtent() {
var latlngbounds = new google.maps.LatLngBounds();
for (var i = 0; i < markers.length; i++) {
var coordinates = new google.maps.LatLng(markers[i].position.lat(), markers[i].position.lng());
latlngbounds.extend(coordinates);
}
map.fitBounds(latlngbounds);
}
function zoomToBounds(b) {
var sw = new google.maps.LatLng(b[1], b[0]);
var ne = new google.maps.LatLng(b[3], b[2]);

View File

@ -290,6 +290,7 @@ function cleanup() {
document.getElementById('map-canvas').innerHTML = '';
}
function displayTrack(xml, update) {
altitudes = {};
var totalMeters = 0;
@ -301,8 +302,8 @@ function displayTrack(xml, update) {
var p = parsePosition(positions[i], i);
totalMeters += p.distance;
totalSeconds += p.seconds;
p['totalMeters'] = totalMeters;
p['totalSeconds'] = totalSeconds;
p.totalMeters = totalMeters;
p.totalSeconds = totalSeconds;
// set marker
setMarker(p, i, posLen);
// update polyline
@ -409,6 +410,10 @@ function getBounds() {
return [lon_sw, lat_sw, lon_ne, lat_ne];
}
function zoomToExtent() {
map.getView().fit(layerMarkers.getSource().getExtent())
}
function zoomToBounds(b) {
var bounds = ol.proj.transformExtent(b, 'EPSG:4326', 'EPSG:900913');
map.getView().fit(bounds);

View File

@ -134,16 +134,6 @@ function getXHR() {
return xmlhttp;
}
function reload(userid, trackid){
var usersSelect = document.getElementsByName('user')[0];
if (usersSelect[usersSelect.selectedIndex].text == lang['allusers']) {
loadLastPositionAllUsers();
}
else{
loadTrack(userid, trackid, 0);
}
}
function loadTrack(userid, trackid, update) {
var title = document.getElementById('track').getElementsByClassName('menutitle')[0];
if (trackid < 0) { return; }
@ -170,7 +160,6 @@ function loadTrack(userid, trackid, update) {
}
function loadLastPositionAllUsers() {
if (latest == 1) { trackid = 0; }
var xhr = getXHR();
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
@ -179,16 +168,22 @@ function loadLastPositionAllUsers() {
var xml = xhr.responseXML;
var positions = xml.getElementsByTagName('position');
var posLen = positions.length;
var timestampMax = 0;
for (var i = 0; i < posLen; i++) {
var p = parsePosition(positions[i], i);
// set marker
setMarker(p, i, posLen);
if (p.timestamp > timestampMax) {
timestampMax = p.timestamp;
}
}
zoomToExtent();
updateSummary(timestampMax);
}
xhr = null;
}
}
xhr.open('GET', 'utils/getpositions.php?trackid=' + trackid + '&userid=' + userid + '&last=' + latest, true);
xhr.open('GET', 'utils/getpositions.php?last=' + latest, true);
xhr.send();
}
@ -264,15 +259,6 @@ function getPopupHtml(p, i, count) {
'<img class="icon" alt="' + lang['tdistance'] + '" title="' + lang['tdistance'] + '" src="images/distance_blue.svg"> ' +
(p.totalMeters.toKm() * factor_km).toFixed(2) + ' ' + unit_km + '<br>' + '</div>';
}
if (p.username == null){
p.username = lang["nousername"];
}
if (p.trackname == null){
p.trackname = lang["notrackname"];
}
if (p.comments == null){
p.comments = lang["nocomment"];
}
var popup =
'<div id="popup">' +
'<div id="pheader">' +
@ -407,27 +393,22 @@ Number.prototype.toKmH = function() {
return Math.round(this * 3600 / 10) / 100;
};
// negate value
// toggle latest
function toggleLatest() {
var usersSelect = document.getElementsByName('user')[0];
if (latest == 0) {
if (usersSelect.options[usersSelect.length-1].text != lang['allusers']){
var option = document.createElement("option");
option.text = lang['allusers'];
if (usersSelect.length >= 2){
usersSelect.add(option);
}
if (!hasAllUsers() && usersSelect.length > 2) {
usersSelect.options.add(new Option('- ' + lang['allusers'] + ' -', 'all'), usersSelect.options[1]);
}
latest = 1;
loadTrack(userid, 0, 1);
}
else {
if (usersSelect.options[usersSelect.length-1].text == lang['allusers']){
usersSelect.remove(usersSelect.length-1);
} else {
if (hasAllUsers()) {
usersSelect.selectedIndex = 0;
usersSelect.remove(1);
}
latest = 0;
loadTrack(userid, trackid, 1);
}
}
@ -449,17 +430,10 @@ function selectTrack(f) {
function selectUser(f) {
userid = f.options[f.selectedIndex].value;
if (f.options[f.selectedIndex].text == lang['allusers']){
var trackSelect = document.getElementsByName('track')[0];
var length = trackSelect.options.length;
for (i = 0; i < length; i++) {
trackSelect.options[i] = null;
}
if (isSelectedAllUsers()) {
clearOptions(document.getElementsByName('track')[0]);
loadLastPositionAllUsers();
}
else{
document.getElementById('latest').checked = false;
} else {
getTracks(userid);
}
}
@ -514,23 +488,41 @@ function clearOptions(el) {
}
}
function reload(userid, trackid) {
if (isSelectedAllUsers()) {
loadLastPositionAllUsers();
} else {
loadTrack(userid, trackid, 0);
}
}
function autoReload() {
if (live == 0) {
live = 1;
var usersSelect = document.getElementsByName('user')[0];
if (usersSelect[usersSelect.selectedIndex].text == lang['allusers']) {
if (isSelectedAllUsers()) {
auto = setInterval(function () { loadLastPositionAllUsers(); }, interval * 1000);
}
else{
} else {
auto = setInterval(function () { loadTrack(userid, trackid, 0); }, interval * 1000);
}
}
else {
} else {
live = 0;
clearInterval(auto);
}
}
function isSelectedAllUsers() {
var usersSelect = document.getElementsByName('user')[0];
return usersSelect[usersSelect.selectedIndex].value == 'all';
}
function hasAllUsers() {
var usersSelect = document.getElementsByName('user')[0];
if (usersSelect.length > 2 && usersSelect.options[1].value == 'all') {
return true;
}
return false;
}
function setTime() {
var i = parseInt(prompt(lang['newinterval']));
if (!isNaN(i) && i != interval) {
@ -600,7 +592,11 @@ function waitAndInit(api) {
zoomToBounds(savedBounds);
update = 0;
}
if (latest && isSelectedAllUsers()) {
loadLastPositionAllUsers();
} else {
loadTrack(userid, trackid, update);
}
// save current api as default
setCookie('api', api, 30);
}

View File

@ -121,9 +121,9 @@ $lang["iparsefailure"] = "Parsing failed";
$lang["idatafailure"] = "No track data in imported file";
$lang["isizefailure"] = "The uploaded file size should not exceed %d bytes"; // substitutes number of bytes
$lang["imultiple"] = "Notice, multiple tracks imported (%d)"; // substitutes number of imported tracks
$lang["allusers"] = "All Users";
$lang["notrackname"] = "No Track";
$lang["nousername"] = "No User";
$lang["nocomment"] = "No Comment";
$lang["allusers"] = "All users";
$lang["notrackname"] = "No track";
$lang["nousername"] = "No user";
$lang["nocomment"] = "No comment";
?>

View File

@ -34,7 +34,7 @@ if ($userId) {
if ($trackId) {
// get all track data
$positionsArr = uPosition::getAll($userId, $trackId);
} else {
} else if ($last) {
// get data only for latest point
$position = uPosition::getLast($userId);
if ($position->isValid) {
@ -42,9 +42,8 @@ if ($userId) {
}
}
}
}
else{
if ($last) {
} else if ($last) {
if (uConfig::$public_tracks || ($auth->isAuthenticated() && ($auth->isAdmin()))) {
$positionsArr = uPosition::getLastAllUsers();
}
}
@ -72,9 +71,9 @@ foreach ($positionsArr as $position) {
$xml->writeElement("username", $position->userLogin);
$xml->writeElement("trackid", $position->trackId);
$xml->writeElement("trackname", $position->trackName);
$distance = isset($prevPosition) ? $position->distanceTo($prevPosition) : 0;
$distance = !$last && isset($prevPosition) ? $position->distanceTo($prevPosition) : 0;
$xml->writeElement("distance", round($distance));
$seconds = isset($prevPosition) ? $position->secondsTo($prevPosition) : 0;
$seconds = !$last && isset($prevPosition) ? $position->secondsTo($prevPosition) : 0;
$xml->writeElement("seconds", $seconds);
$xml->endElement();
$prevPosition = $position;