2023-10-17 15:15:41 +01:00
|
|
|
/**
|
|
|
|
* @file This file provides abstracted functions to interact with the api
|
|
|
|
* @author Arlo Filley
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This class provides all the useful methods to interact with the api.
|
|
|
|
*/
|
|
|
|
class API {
|
|
|
|
constructor() { this.url = "/api"; }
|
|
|
|
|
2024-03-25 09:40:43 +00:00
|
|
|
async createTest() {
|
|
|
|
const test = screenManager.screen.textbox.getLetters();
|
2023-10-17 15:15:41 +01:00
|
|
|
const testType = "words";
|
2024-03-25 09:40:43 +00:00
|
|
|
const testLength = test.length;
|
|
|
|
const testTime = screenManager.screen.timer.getTime();
|
2023-10-17 15:15:41 +01:00
|
|
|
const testSeed = 0;
|
|
|
|
const quoteId = 0;
|
|
|
|
const userId = Number(user.userId);
|
2024-03-25 09:40:43 +00:00
|
|
|
const testContent = screenManager.screen.textbox.getTestContent();
|
|
|
|
|
|
|
|
let correctLetters = 0;
|
|
|
|
test.forEach((letter, index) => {
|
|
|
|
if (letter === testContent[index]) correctLetters++;
|
|
|
|
});
|
|
|
|
|
|
|
|
const accuracy = Math.round((correctLetters / test.length) * 100);
|
|
|
|
const wpm = Math.round((correctLetters / 5) * (60 / testTime));
|
|
|
|
|
|
|
|
const validations = [
|
|
|
|
{value: testType, type: "string"},
|
|
|
|
{value: testLength, type: "number", min: 0},
|
|
|
|
{value: testTime, type: "number", min: 1},
|
|
|
|
{value: testSeed, type: "number", min: 0},
|
|
|
|
{value: quoteId, type: "number", min: 0},
|
|
|
|
{value: wpm, type: "number", min: 0},
|
|
|
|
{value: accuracy, type: "number", min: 0, max: 100},
|
|
|
|
{value: userId, type: "number", min: 0}
|
|
|
|
];
|
|
|
|
|
|
|
|
for (let {value, type, min, max} of validations) {
|
|
|
|
if (typeof value !== type || value < min || (max !== undefined && value > max)) {
|
|
|
|
console.error(`Validation failed for value: ${value}, Type: ${type}, Min: ${min}, Max: ${max}`);
|
|
|
|
return;
|
2023-10-17 15:15:41 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-03-25 09:40:43 +00:00
|
|
|
const data = {
|
|
|
|
test_type: testType,
|
|
|
|
test_length: testLength,
|
|
|
|
test_time: testTime,
|
|
|
|
test_seed: testSeed,
|
|
|
|
quote_id: quoteId,
|
|
|
|
wpm: wpm,
|
|
|
|
accuracy: accuracy,
|
|
|
|
user_id: userId,
|
|
|
|
secret: user.secret
|
|
|
|
};
|
2023-10-17 15:15:41 +01:00
|
|
|
|
2024-03-25 09:40:43 +00:00
|
|
|
try {
|
|
|
|
const response = await fetch(`${this.url}/user/test`, {
|
|
|
|
method: "POST",
|
|
|
|
headers: {
|
|
|
|
'Content-Type': 'application/json'
|
|
|
|
},
|
|
|
|
body: JSON.stringify(data)
|
|
|
|
});
|
|
|
|
|
|
|
|
if (!response.ok) {
|
|
|
|
throw new Error('Network response was not ok');
|
|
|
|
}
|
2023-10-17 15:15:41 +01:00
|
|
|
|
2024-03-25 09:40:43 +00:00
|
|
|
// const responseData = await response.json();
|
|
|
|
// console.log(responseData);
|
|
|
|
user.lastTest = data; // Consider updating user.lastTest only on successful response
|
|
|
|
window.location.href = "/typing/pages/end/index.html"
|
|
|
|
} catch (error) {
|
|
|
|
console.error('There has been a problem with your fetch operation:', error);
|
2023-10-17 15:15:41 +01:00
|
|
|
}
|
2024-03-25 09:40:43 +00:00
|
|
|
}
|
2023-10-17 15:15:41 +01:00
|
|
|
|
2024-03-25 09:40:43 +00:00
|
|
|
/**
|
|
|
|
* Fetches the latest test for a given user.
|
|
|
|
* @param {number} userId The user's ID.
|
|
|
|
* @param {string} secret The secret key for authentication.
|
|
|
|
* @returns {Promise<Object>} The latest test object or an error message.
|
|
|
|
*/
|
|
|
|
async getLatestUserTest() {
|
|
|
|
let userId = Number(user.userId);
|
|
|
|
let secret = user.secret;
|
|
|
|
const url = `${this.url}/user/test/${userId}/${secret}`;
|
|
|
|
|
|
|
|
try {
|
|
|
|
const response = await fetch(url);
|
|
|
|
if (!response.ok) {
|
|
|
|
// Handle HTTP errors
|
|
|
|
throw new Error(`HTTP error! status: ${response.status}`);
|
|
|
|
}
|
|
|
|
const data = await response.json();
|
|
|
|
console.log("Successfully fetched latest test:", data);
|
|
|
|
return data;
|
|
|
|
} catch (error) {
|
|
|
|
console.error("Error fetching the latest user test:", error);
|
|
|
|
return null; // or handle as needed
|
2023-10-17 15:15:41 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* takes a validated name and password and sends
|
|
|
|
* a post request to make a user with the given
|
|
|
|
* username and password
|
|
|
|
* @param {String} username
|
|
|
|
* @param {String} password
|
|
|
|
* @returns
|
|
|
|
*/
|
|
|
|
createUser( username, password ) {
|
|
|
|
console.log( username, password );
|
|
|
|
const user = {
|
|
|
|
username: username,
|
|
|
|
password: password
|
|
|
|
};
|
|
|
|
|
|
|
|
const xhr = new XMLHttpRequest();
|
2024-03-25 09:40:43 +00:00
|
|
|
xhr.open( "POST", `${this.url}/user/create/` );
|
2023-10-17 15:15:41 +01:00
|
|
|
|
|
|
|
xhr.send( JSON.stringify(user) );
|
|
|
|
|
|
|
|
xhr.onload = () => {
|
|
|
|
if (xhr.status === 500) {
|
|
|
|
alert("Sorry, looks like your username isn't unique");
|
|
|
|
console.error("Sorry, looks like your username isn't unique")
|
|
|
|
} else {
|
|
|
|
this.login(username, password);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* takes a validated name and password and sends
|
|
|
|
* a post request to make a user with the given
|
|
|
|
* username and password
|
|
|
|
* @param {String} username
|
|
|
|
* @param {String} password
|
|
|
|
* @param {boolean} initial
|
|
|
|
* @returns
|
|
|
|
*/
|
|
|
|
login(pUsername, pPassword, initial = false) {
|
|
|
|
// If Local Storage has the information we need there is no need to make a request to the server
|
|
|
|
if (localStorage.getItem("username") === pUsername || (initial && localStorage.length === 3) ) {
|
|
|
|
user.userId = localStorage.getItem("userId");
|
|
|
|
user.secret = localStorage.getItem("secret");
|
|
|
|
user.username = localStorage.getItem("username");
|
|
|
|
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// Variable Validation
|
|
|
|
if (pUsername == undefined || pPassword == undefined) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
let xhr = new XMLHttpRequest();
|
2024-03-25 09:40:43 +00:00
|
|
|
xhr.open('GET', `${this.url}/user/login/${pUsername}/${pPassword}`);
|
2023-10-17 15:15:41 +01:00
|
|
|
xhr.send();
|
|
|
|
xhr.onload = () => {
|
|
|
|
let response = JSON.parse(xhr.response);
|
|
|
|
|
|
|
|
// If there is an error with the login we need
|
|
|
|
if (xhr.response === null) {
|
|
|
|
alert("Error Logging in, maybe check your password");
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
user.userId = response.user_id;
|
|
|
|
user.username = pUsername
|
|
|
|
user.secret = response.secret;
|
|
|
|
|
|
|
|
localStorage.setItem("userId", user.userId);
|
|
|
|
localStorage.setItem("username", pUsername);
|
|
|
|
localStorage.setItem("secret", user.secret);
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
logout() {
|
|
|
|
user = new User();
|
|
|
|
user.username = "no one";
|
|
|
|
user.password = "";
|
|
|
|
user.userId = 0;
|
|
|
|
user.tests = [];
|
|
|
|
localStorage.clear();
|
|
|
|
this.getTest();
|
|
|
|
}
|
|
|
|
|
|
|
|
getUserTests() {
|
|
|
|
if (user.userId === 0) {
|
|
|
|
user.tests = undefined;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
let xhr = new XMLHttpRequest();
|
|
|
|
|
2024-03-25 09:40:43 +00:00
|
|
|
xhr.open('GET', `${this.url}/user/tests/${user.userId}/${user.secret}`);
|
2023-10-17 15:15:41 +01:00
|
|
|
xhr.send();
|
|
|
|
xhr.onload = () => {
|
|
|
|
user.tests = JSON.parse(xhr.response);
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2024-03-25 09:40:43 +00:00
|
|
|
async getLeaderBoard() {
|
|
|
|
try {
|
|
|
|
const response = await fetch(`${this.url}/leaderboard/`);
|
|
|
|
if (!response.ok) {
|
|
|
|
throw new Error('Network response was not ok.');
|
|
|
|
}
|
|
|
|
user.leaderboard = await response.json();
|
|
|
|
} catch (error) {
|
|
|
|
console.error('Failed to fetch leaderboard:', error);
|
|
|
|
}
|
2023-10-17 15:15:41 +01:00
|
|
|
}
|
2024-03-25 09:40:43 +00:00
|
|
|
|
|
|
|
|
|
|
|
async getTest() {
|
|
|
|
try {
|
|
|
|
const response = await fetch(`${this.url}/test/`);
|
|
|
|
if (!response.ok) {
|
|
|
|
throw new Error('Network response was not ok.');
|
|
|
|
}
|
2023-10-17 15:15:41 +01:00
|
|
|
|
|
|
|
const effectiveWidth = (windowWidth - 200) / 13;
|
2024-03-25 09:40:43 +00:00
|
|
|
let textArr = await response.json();
|
2023-10-17 15:15:41 +01:00
|
|
|
let finalText = [];
|
|
|
|
let text = "";
|
|
|
|
for (let i = 0; i < textArr.length; i++) {
|
|
|
|
if (text.length + textArr[i].length < effectiveWidth) {
|
|
|
|
text += `${textArr[i]} `
|
|
|
|
} else {
|
|
|
|
finalText.push(text.substring(0,text.length-1));
|
|
|
|
text = `${textArr[i]} `;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
user.nextTest = finalText;
|
2024-03-25 09:40:43 +00:00
|
|
|
} catch (error) {
|
|
|
|
console.error('Failed to fetch a test:', error);
|
|
|
|
}
|
2023-10-17 15:15:41 +01:00
|
|
|
}
|
|
|
|
}
|