CS-Coursework/public/api/api.js

247 lines
7.9 KiB
JavaScript

/**
* @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"; }
async createTest() {
const test = screenManager.screen.textbox.getLetters();
const testType = "words";
const testLength = test.length;
const testTime = screenManager.screen.timer.getTime();
const testSeed = 0;
const quoteId = 0;
const userId = Number(user.userId);
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;
}
}
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
};
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');
}
// 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);
}
}
/**
* 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
}
}
/**
* 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();
xhr.open( "POST", `${this.url}/user/create/` );
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();
xhr.open('GET', `${this.url}/user/login/${pUsername}/${pPassword}`);
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();
xhr.open('GET', `${this.url}/user/tests/${user.userId}/${user.secret}`);
xhr.send();
xhr.onload = () => {
user.tests = JSON.parse(xhr.response);
};
}
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);
}
}
async getTest() {
try {
const response = await fetch(`${this.url}/test/`);
if (!response.ok) {
throw new Error('Network response was not ok.');
}
const effectiveWidth = (windowWidth - 200) / 13;
let textArr = await response.json();
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;
} catch (error) {
console.error('Failed to fetch a test:', error);
}
}
}