Skip to content

Commit

Permalink
Merge branch 'release/server-v2.0.0'
Browse files Browse the repository at this point in the history
  • Loading branch information
rsnitsch committed Apr 7, 2023
2 parents 48cbea0 + 91ea13b commit 6c4908e
Show file tree
Hide file tree
Showing 12 changed files with 108 additions and 57 deletions.
12 changes: 8 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,23 @@ This project allows you to compare your Trackmania 2020 records with your friend

In the browser, it looks like this:

![Screenshot 1](https://github.com/rsnitsch/trackmania-records/raw/develop/screenshot1.png "Screenshot 1")
![Screenshot 1](docs/screenshot1.png "Screenshot 1")

It also features a total time comparison:

![Screenshot 2](https://github.com/rsnitsch/trackmania-records/raw/develop/screenshot2.png "Screenshot 2")
![Screenshot 2](docs/screenshot2.png "Screenshot 2")

Advanced statistics for a certain user can be displayed by appending `?user=name` to the URL (address in your browser):

![Screenshot 3 showing advanced user statistics feature](docs/advanced_user_stats.png "Advanced user statistics")

## Setup

### 1. Install web application
### 1. Install web application (server)

Please refer to: https://github.com/rsnitsch/trackmania-records/tree/develop/server

### 2. Install uploader
### 2. Install uploader (client)

The uploader is what extracts your trackmania records from the autosaved replay files on
your computer and sends them to the web application.
Expand Down
6 changes: 6 additions & 0 deletions TODOs.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# TODOs

- Server: Display a meaningful message if no track set is complete so the users understand
why nothing is displayed (complete = a record is known for each of the 25 tracks)
- Server: Properly sort the displayed track sets by year and season.
- Server: Make it easy to user the ?user= feature
3 changes: 1 addition & 2 deletions client/README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
trackmania-records - Uploader
=============================
# trackmania-records - Uploader (client)

This is the uploader for trackmania-records, a Trackmania 2020 records sharing/comparison tool.

Expand Down
Binary file added docs/advanced_user_stats.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
File renamed without changes
File renamed without changes
2 changes: 1 addition & 1 deletion server/README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# trackmania-records - Web application
# trackmania-records - Web application (server)

This is the web application part of trackmania-records, a Trackmania 2020
records sharing tool. The web application is where all your records (and the
Expand Down
16 changes: 8 additions & 8 deletions server/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
version: "3"
services:
webserver:
image: php:7.4-apache
volumes:
- ./html/:/var/www/html
ports:
- "127.0.0.1:8080:80"
version: "3"
services:
webserver:
image: php:8.2-apache
volumes:
- ./html/:/var/www/html
ports:
- "127.0.0.1:8080:80"
78 changes: 43 additions & 35 deletions server/html/index.php
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
<?php
include('version.php');

// TODO: Improve generation of upload.php URL (currently it just uses hostname + "/upload.php")

header("Content-Security-Policy: default-src 'self'");
Expand All @@ -22,14 +24,8 @@ function getBestTimeByUser($bestTimes, $user) {
return null;
}

function tableForTrackSet($trackSet, $selectedUser) {
if ($trackSet == "Training")
$count = 25;
else if ($trackSet == "Summer 2020" or $trackSet == "Fall 2020") {
$count = 25;
} else {
throw Exception("Unknown track set");
}
function tableForTrackSet($pdo, $trackSet, $selectedUser) {
$count = 25;

echo " <h2>".htmlspecialchars($trackSet)." - Records</h2>";
?>
Expand All @@ -50,46 +46,42 @@ function tableForTrackSet($trackSet, $selectedUser) {
</tr>
<?php
try {
$pdo = new \PDO("sqlite:database.db");
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);


for ($i = 1; $i <= 25; $i++) {
$track = sprintf("$trackSet - %02d", $i);

for ($trackNumber = 1; $trackNumber <= 25; $trackNumber++) {
// Determine best time for track.
$st = $pdo->prepare("SELECT user, best FROM records WHERE track = :track ORDER BY best ASC");
$st->bindParam(':track', $track, PDO::PARAM_STR);
$st = $pdo->prepare("SELECT user, best FROM records WHERE trackSet = :trackSet AND trackNumber = :trackNumber ORDER BY best ASC");
$st->bindParam(':trackSet', $trackSet, PDO::PARAM_STR);
$st->bindParam(':trackNumber', $trackNumber, PDO::PARAM_INT);
$st->execute();
$bestTimes = $st->fetchAll();
//print_r($bestTimes);
$bestTime = $bestTimes[0]['best'];

// Get users that have driven this time.
$st = $pdo->prepare("SELECT user FROM records WHERE track = :track AND best = :best ORDER BY LOWER(user)");
$st->bindParam(':track', $track, PDO::PARAM_STR);
$st = $pdo->prepare("SELECT user FROM records WHERE trackSet = :trackSet AND trackNumber = :trackNumber AND best = :best ORDER BY LOWER(user)");
$st->bindParam(':trackSet', $trackSet, PDO::PARAM_STR);
$st->bindParam(':trackNumber', $trackNumber, PDO::PARAM_INT);
$st->bindParam(':best', $bestTime, PDO::PARAM_INT);
$st->execute();
$users = $st->fetchAll(PDO::FETCH_COLUMN, 0);
//print_r($users);

if ($trackSet == "Summer 2020" or $trackSet == "Fall 2020") {
if ($i <= 5) {
if ($trackSet != "Training") {
if ($trackNumber <= 5) {
$tableColorClass = " class='whiteTracks'";
} else if ($i <= 10) {
} else if ($trackNumber <= 10) {
$tableColorClass = " class='greenTracks'";
} else if ($i <= 15) {
} else if ($trackNumber <= 15) {
$tableColorClass = " class='blueTracks'";
} else if ($i <= 20) {
} else if ($trackNumber <= 20) {
$tableColorClass = " class='redTracks'";
} else if ($i <= 25) {
} else if ($trackNumber <= 25) {
$tableColorClass = " class='blackTracks'";
}
} else {
$tableColorClass = "";
}
?> <tr<?php echo $tableColorClass; ?>>
<td><?php echo $track; ?></td>
<td><?php echo $trackSet." - ".$trackNumber; ?></td>
<td><?php echo htmlspecialchars($bestTime / 1000.0); ?>s</td>
<td><?php echo htmlspecialchars(implode(', ', $users)); ?></td>
<?php
Expand Down Expand Up @@ -129,8 +121,8 @@ function tableForTrackSet($trackSet, $selectedUser) {
$pdo = new \PDO("sqlite:database.db");
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

$st = $pdo->prepare("SELECT user, SUM(best) AS total_time, COUNT(track) AS count FROM records WHERE track LIKE :track_set GROUP BY user HAVING count = 25 ORDER BY count DESC, total_time ASC");
$st->bindValue('track_set', addcslashes("$trackSet", "?%")."%", PDO::PARAM_STR);
$st = $pdo->prepare("SELECT user, SUM(best) AS total_time, COUNT(trackNumber) AS count FROM records WHERE trackSet = :track_set GROUP BY user HAVING count = 25 ORDER BY count DESC, total_time ASC");
$st->bindValue('track_set', $trackSet, PDO::PARAM_STR);
$st->execute();
while ($row = $st->fetch()) {
//print_r($row);
Expand All @@ -141,8 +133,8 @@ function tableForTrackSet($trackSet, $selectedUser) {
<?php
}

$st = $pdo->prepare("SELECT user, SUM(best) AS total_time, COUNT(track) AS count FROM records WHERE track LIKE :track_set GROUP BY user HAVING count < 25 ORDER BY count DESC, total_time ASC");
$st->bindValue('track_set', addcslashes("$trackSet", "?%")."%", PDO::PARAM_STR);
$st = $pdo->prepare("SELECT user, SUM(best) AS total_time, COUNT(trackNumber) AS count FROM records WHERE trackSet = :track_set GROUP BY user HAVING count < 25 ORDER BY count DESC, total_time ASC");
$st->bindValue('track_set', $trackSet, PDO::PARAM_STR);
$st->execute();
while ($row = $st->fetch()) {
//print_r($row);
Expand Down Expand Up @@ -175,9 +167,20 @@ function tableForTrackSet($trackSet, $selectedUser) {

<?php
if (file_exists("database.db")) {
tableForTrackSet("Fall 2020", $selectedUser);
tableForTrackSet("Summer 2020", $selectedUser);
tableForTrackSet("Training", $selectedUser);
try {
$pdo = new \PDO("sqlite:database.db");
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

// Display all track sets for which at least one user has driven *all* tracks.
$st = $pdo->prepare("SELECT DISTINCT trackSet, COUNT(trackNumber) AS count FROM records GROUP BY trackSet, user HAVING count = 25");
$st->execute();
$rows = $st->fetchAll();
foreach ($rows as $row) {
tableForTrackSet($pdo, $row['trackSet'], $selectedUser);
}
} catch (PDOException $e) {
echo 'Database error: '.htmlspecialchars($e->getMessage());
}
} else {
echo "<p>No records have been uploaded yet...</p>";
}
Expand All @@ -198,7 +201,12 @@ function tableForTrackSet($trackSet, $selectedUser) {

<hr>

<p class="small">trackmania-records is opensource: <a href="https://github.com/rsnitsch/trackmania-records">github.com/rsnitsch/trackmania-records</a></p>
<footer>
<p class="small">
trackmania-records server v<?php echo SERVER_VERSION; ?>.
This software is opensource: <a href="https://github.com/rsnitsch/trackmania-records">github.com/rsnitsch/trackmania-records</a>
</p>
</footer>
</div>
</body>
</html>
</html>
18 changes: 11 additions & 7 deletions server/html/upload.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,10 @@
$commands = ['CREATE TABLE IF NOT EXISTS records (
game TEXT NOT NULL,
user TEXT NOT NULL,
track TEXT NOT NULL,
trackSet TEXT NOT NULL,
trackNumber INTEGER NOT NULL,
best INTEGER NOT NULL,
PRIMARY KEY (game, user, track)
PRIMARY KEY (game, user, trackSet, trackNumber)
)'];

foreach ($commands as $command) {
Expand All @@ -45,19 +46,22 @@
//print_r($record);

$user = $record['user'];
$track = $record['track'];
$trackSet = substr($record['trackSet'], 0, strpos($record['trackSet'], ' - '));
$trackNumber = intval(substr($record['trackSet'], strpos($record['trackSet'], ' - ') + 3));
$best = intval($record['best']);

// Delete previous record.
$st = $pdo->prepare('DELETE FROM records WHERE user = :user AND track = :track');
$st = $pdo->prepare('DELETE FROM records WHERE user = :user AND trackSet = :trackSet AND trackNumber = :trackNumber');
$st->bindParam(':user', $user, PDO::PARAM_STR);
$st->bindParam(':track', $track, PDO::PARAM_STR);
$st->bindParam(':trackSet', $trackSet, PDO::PARAM_STR);
$st->bindParam(':trackNumber', $trackNumber, PDO::PARAM_INT);
$st->execute();

// Add new record.
$st = $pdo->prepare("INSERT INTO records (game, user, track, best) VALUES ('Trackmania 2020', :user, :track, :best)");
$st = $pdo->prepare("INSERT INTO records (game, user, trackSet, trackNumber, best) VALUES ('Trackmania 2020', :user, :trackSet, :trackNumber, :best)");
$st->bindParam(':user', $user, PDO::PARAM_STR);
$st->bindParam(':track', $track, PDO::PARAM_STR);
$st->bindParam(':trackSet', $trackSet, PDO::PARAM_STR);
$st->bindParam(':trackNumber', $trackNumber, PDO::PARAM_INT);
$st->bindParam(':best', $best, PDO::PARAM_INT);
$st->execute();
}
Expand Down
2 changes: 2 additions & 0 deletions server/html/version.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
<?php
define('SERVER_VERSION', '2.0.0');
28 changes: 28 additions & 0 deletions server/migration.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
-- SQL code for migrating the server from v1.0.0 to v2.0.0 table format:
BEGIN TRANSACTION;

-- From v2.0.0 onwards the track column is split into two columns: trackSet ("Summer 2020") and trackNumber (1 to 25).
ALTER TABLE records ADD COLUMN trackSet TEXT;
ALTER TABLE records ADD COLUMN trackNumber INTEGER;
UPDATE records SET trackSet = SUBSTR(track, 0, INSTR(track, " - "));
UPDATE records SET trackNumber = CAST(SUBSTR(track, INSTR(track, " - ")+3) AS INTEGER);

-- Add NOT NULL constraints for the new columns. For this we have to create a new table because
-- SQLite does not support adding the NOT NULL constraint to existing columns.
CREATE TABLE records_temp (
game TEXT NOT NULL,
user TEXT NOT NULL,
trackSet TEXT NOT NULL,
trackNumber INTEGER NOT NULL,
best INTEGER NOT NULL,
PRIMARY KEY (game, user, trackSet, trackNumber)
);

-- Copy data from old table.
INSERT INTO records_temp SELECT game, user, trackSet, trackNumber, best FROM records;

-- Replace the old table.
DROP TABLE records;
ALTER TABLE records_temp RENAME TO records;

COMMIT;

0 comments on commit 6c4908e

Please sign in to comment.