Add version information

Fixes #2.
And fix a silly bug with preferences when the number of possible signatures is not a multiple of 8...
This commit is contained in:
Florine W. Dekker 2020-10-01 19:33:30 +02:00
parent 1cb7fe0ed2
commit 21974c0b22
Signed by: FWDekker
GPG Key ID: B1B567AF58D6EE0F
5 changed files with 88 additions and 59 deletions

View File

@ -2,8 +2,11 @@
Allows a user to retrieve a random record from the _Fallout 76_ game files. Allows a user to retrieve a random record from the _Fallout 76_ game files.
The user can filter records by data type to avoid receiving uninteresting data types. The user can filter records by data type to avoid receiving uninteresting data types.
The back end, `api.php`, communicates with an SQLite database, `.fo76-dumps-ids.db`, containing only the `IDS.csv` dump The back end, `api.php`, communicates with an SQLite database, `.fo76-dumps-ids.db`, containing the `IDS.csv` dump from
from [the _Fallout 76_ data dumps repository](https://github.com/FWDekker/fo76-dumps/). [the _Fallout 76_ data dumps repository](https://github.com/FWDekker/fo76-dumps/), with an additional index
`sk_signature` on the signature column.
The database also has a table `meta` with text columns `key` and `value` that contain version information.
Additionally, the database has an index `sk_signature` on the signature column.
The database is not included in this repository. The database is not included in this repository.
The front end, `index.html`, sends asynchronous queries to the back end based on the user's settings. The front end, `index.html`, sends asynchronous queries to the back end based on the user's settings.
@ -13,7 +16,7 @@ refreshed.
## Development ## Development
### Requirements ### Requirements
* [npm](https://www.npmjs.com/) * [npm](https://www.npmjs.com/)
* a local PHP server * a local PHP 7 server
* a local copy of `.fo76-dumps-ids.db` * a local copy of `.fo76-dumps-ids.db`
### Setting up ### Setting up

View File

@ -1,6 +1,6 @@
{ {
"name": "random-fo76", "name": "random-fo76",
"version": "1.0.11", "version": "1.0.12",
"description": "Random Fallout 76 record.", "description": "Random Fallout 76 record.",
"author": "Felix W. Dekker", "author": "Felix W. Dekker",
"browser": "dist/bundle.js", "browser": "dist/bundle.js",

View File

@ -7,6 +7,15 @@ $action = $_GET["action"];
$db = new SQLite3(".fo76-dumps-ids.db", SQLITE3_OPEN_READONLY); $db = new SQLite3(".fo76-dumps-ids.db", SQLITE3_OPEN_READONLY);
switch ($action) { switch ($action) {
case "get-meta":
$results = $db->query("SELECT * FROM meta;");
$meta = [];
while ($row = $results->fetchArray())
$meta[$row["key"]] = $row["value"];
print(json_encode($meta));
break;
case "list-signatures": case "list-signatures":
$results = $db->query("SELECT DISTINCT Signature FROM IDs ORDER BY Signature;"); $results = $db->query("SELECT DISTINCT Signature FROM IDs ORDER BY Signature;");
@ -14,7 +23,7 @@ switch ($action) {
while ($row = $results->fetchArray()) while ($row = $results->fetchArray())
array_push($signatures, $row["Signature"]); array_push($signatures, $row["Signature"]);
print(json_encode($signatures, JSON_PRETTY_PRINT)); print(json_encode($signatures));
break; break;
case "get-random": case "get-random":
if (!isset($_GET["signatures"])) { if (!isset($_GET["signatures"])) {
@ -36,7 +45,7 @@ switch ($action) {
$results = $stmt->execute(); $results = $stmt->execute();
while ($row = $results->fetchArray(SQLITE3_ASSOC)) while ($row = $results->fetchArray(SQLITE3_ASSOC))
print(json_encode($row, JSON_PRETTY_PRINT)); print(json_encode($row));
break; break;
default: default:
print("null"); print("null");

View File

@ -27,6 +27,20 @@
<div id="header"></div> <div id="header"></div>
<!-- Metadata -->
<section class="container">
<table style="max-width: 300px;">
<tr>
<th>Game version</th>
<td id="gameVersion">loading...</td>
</tr>
<tr>
<th>Dumps version</th>
<td id="dumpsVersion">loading...</td>
</tr>
</table>
</section>
<!-- Input --> <!-- Input -->
<section class="container"> <section class="container">
<h2>Settings</h2> <h2>Settings</h2>
@ -34,14 +48,14 @@
<button id="signatureToggle" class="button button-outline" type="button">Select all signatures</button> <button id="signatureToggle" class="button button-outline" type="button">Select all signatures</button>
<fieldset id="signatures">Loading... please wait.</fieldset> <fieldset id="signatures">Loading... please wait.</fieldset>
<button id="submit" type="button">Get random record</button> <button id="submit" type="button">Fetch random record</button>
</form> </form>
</section> </section>
<!-- Output --> <!-- Output -->
<section class="container"> <section class="container">
<h2>Record</h2> <h2>Record</h2>
<pre><code id="output"></code></pre> <pre><code id="output">No record has been fetched yet</code></pre>
</section> </section>
</div> </div>
<div id="footer"></div> <div id="footer"></div>

View File

@ -5,6 +5,28 @@ const storageKey = "/tools/random-fo76//selected-signatures";
const signatureColCount = 8; const signatureColCount = 8;
/**
* Fetches the API response given a query.
*
* @param query the query to send to the API
* @param callback the function to execute with the array of signatures
* @param handle the function to execute if signatures could not be downloaded
*/
const fetchFromApi = (query, callback, handle) => {
fetch(`api.php?${query}`)
.then(response => {
if (!response.ok) {
if (handle) handle(response);
console.error(response);
throw new Error(`Failed to execute query '${query}' on API.`);
}
return response.json();
})
.then(response => callback(response));
}
/** /**
* Returns an array of the signatures that are currently selected. * Returns an array of the signatures that are currently selected.
*/ */
@ -83,26 +105,6 @@ const updateSignatureToggle = () => {
}; };
/**
* Downloads an array of signatures from the API.
*
* @param callback the function to execute with the array of signatures
* @param handle the function to execute if signatures could not be downloaded
*/
const downloadSignatures = (callback, handle) => {
fetch("api.php?action=list-signatures")
.then(response => {
if (!response.ok) {
if (handle) handle(response);
console.error(response);
throw new Error("Failed to fetch list of signatures.");
}
return response.json();
})
.then(signatures => callback(signatures));
};
/** /**
* Creates buttons for the signatures and adds them to the form. * Creates buttons for the signatures and adds them to the form.
* *
@ -145,28 +147,8 @@ const createSignatureButtons = signatures => {
row.appendChild(col); row.appendChild(col);
} }
}; if (row !== undefined)
form.appendChild(row);
/**
* Downloads a random record from the API.
*
* @param callback the function to execute with the record
* @param handle the function to execute if signatures could not be downloaded
*/
const downloadRandomRecord = (callback, handle) => {
const selectedSignatures = getSelectedSignatures();
fetch(`api.php?action=get-random&signatures=${selectedSignatures.join(",")}`)
.then(response => {
if (!response.ok) {
if (handle) handle(response);
console.error(response);
throw new Error("Failed to fetch random record.");
}
return response.text();
})
.then(record => callback(record));
}; };
/** /**
@ -175,13 +157,14 @@ const downloadRandomRecord = (callback, handle) => {
* @param record the record to display * @param record the record to display
*/ */
const showRecord = (record) => { const showRecord = (record) => {
$("#output").innerHTML = record; $("#output").innerHTML = JSON.stringify(record, null, 4);
const scrollingElement = (document.scrollingElement || document.body); const scrollingElement = (document.scrollingElement || document.body);
scrollingElement.scrollTop = scrollingElement.scrollHeight; scrollingElement.scrollTop = scrollingElement.scrollHeight;
}; };
// Apply template
doAfterLoad(() => { doAfterLoad(() => {
$("#nav").appendChild(nav("/Tools/Random FO76/")); $("#nav").appendChild(nav("/Tools/Random FO76/"));
$("#header").appendChild(header({ $("#header").appendChild(header({
@ -200,20 +183,40 @@ doAfterLoad(() => {
$("main").style.display = null; $("main").style.display = null;
}); });
// Load page from API
doAfterLoad(() => { doAfterLoad(() => {
$("#submit").onclick = () => { fetchFromApi("action=get-meta",
$("#output").innerHTML = "Fetching record... please wait"; meta => {
downloadRandomRecord(record => showRecord(record)); $("#gameVersion").innerHTML = meta["game_version"];
}; $("#dumpsVersion").innerHTML = meta["dumps_version"];
},
() => {
$("#gameVersion").innerHTML = "Error";
$("#dumpsVersion").innerHTML = "Error";
}
);
downloadSignatures( fetchFromApi("action=list-signatures",
signatures => { signatures => {
createSignatureButtons(signatures); createSignatureButtons(signatures);
loadSelectedSignaturesFromStorage(); loadSelectedSignaturesFromStorage();
}, },
errorResponse => { () => {
const form = $("#signatureForm"); const form = $("#signatureForm");
form.style.color = "red"; form.style.color = "red";
form.innerHTML = "Error: Failed to download signatures." form.innerHTML = "Error: Failed to download signatures. Try reloading the page.";
}); }
);
});
// Install handlers
doAfterLoad(() => {
$("#submit").onclick = () => {
$("#output").innerHTML = "Fetching record... please wait";
const selectedSignatures = getSelectedSignatures();
fetchFromApi(`action=get-random&signatures=${selectedSignatures.join(",")}`,
record => showRecord(record)
);
};
}); });