From d53fe82cc77fa1d67cfd0cae96cac7b30f606e7e Mon Sep 17 00:00:00 2001 From: Arlo Filley Date: Fri, 11 Nov 2022 19:54:52 +0000 Subject: [PATCH] created api routes for signup login and getting user tests --- src/main.rs | 9 +++- src/sql.rs | 46 ++++++++++++++++ website/api/api.js | 43 ++++++++------- website/api/user.js | 6 +-- website/index.html | 1 + website/index.js | 6 ++- website/screens/endscreen.js | 4 ++ website/screens/loginscreen.js | 98 ++++++++++++++++++++++++++++++++++ website/screens/startscreen.js | 16 +++++- website/ui_elements/textbox.js | 2 +- 10 files changed, 205 insertions(+), 26 deletions(-) create mode 100644 website/screens/loginscreen.js diff --git a/src/main.rs b/src/main.rs index 72e92b9..e37559a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -14,6 +14,7 @@ use rocket::{ json::Json } }; +use crate::sql::Test; #[get("/")] fn test() -> String { @@ -80,10 +81,16 @@ fn login(username: &str, password: &str) -> String { user_id.to_string() } +#[get("/get_user_tests/")] +fn get_user_tests(user_id: u32) -> Json> { + let tests = sql::get_user_tests(user_id).expect("error finding user_id"); + Json(tests) +} + #[launch] fn rocket() -> Rocket { rocket::build() .mount("/test", routes![test]) // testing only, should return "Hello world" - .mount("/api", routes![post_test, create_user, login]) + .mount("/api", routes![post_test, create_user, login, get_user_tests]) .mount("/typing", FileServer::from(relative!("website"))) // hosts the fileserver } \ No newline at end of file diff --git a/src/sql.rs b/src/sql.rs index 1b059d8..bdde447 100644 --- a/src/sql.rs +++ b/src/sql.rs @@ -1,4 +1,5 @@ use rusqlite::{Connection, Result}; +use rocket::serde::Serialize; fn get_connection() -> rusqlite::Connection { Connection::open("database/database.sqlite") @@ -143,4 +144,49 @@ pub fn find_user( } Ok(user_id) +} + +#[derive(Serialize)] +#[serde(crate = "rocket::serde")] +pub struct Test { + test_type: String, + test_length: u32, + test_time: u32, + test_seed: i64, + quote_id: i32, + wpm: u8, + accuracy: u8, +} + +pub fn get_user_tests( + user_id: u32 +) -> Result> { + let connection = get_connection(); + let mut statement = connection.prepare( + "SELECT test_type, test_length, test_time, test_seed, quote_id, wpm, accuracy + FROM tests + WHERE user_id=:user_id", + )?; + + let mut user_id: u32 = 0; + + let test_iter = statement + .query_map(&[(":user_id", &user_id.to_string())], |row| { + Ok( Test { + test_type: row.get(0)?, + test_length: row.get(1)?, + test_time: row.get(2)?, + test_seed: row.get(3)?, + quote_id: row.get(4)?, + wpm: row.get(5)?, + accuracy: row.get(6)? + }) + })?; + + let mut tests: Vec = vec![]; + for test in test_iter { + tests.push(test.unwrap()); + } + + Ok(tests) } \ No newline at end of file diff --git a/website/api/api.js b/website/api/api.js index cbb30d9..72b79c9 100644 --- a/website/api/api.js +++ b/website/api/api.js @@ -54,7 +54,7 @@ class API { * Validates all the parameters used for the postTest function which it then calls */ validateTest() { - const test = screenManager.textbox.getLetters(); + const test = screenManager.screen.textbox.getLetters(); const testType = "words"; let testLength = test.length; let testTime = screenManager.timer.getTime(); @@ -62,7 +62,7 @@ class API { const quoteId = 0; let wpm; const accuracy = 0; - const userId = 0; + const userId = Number(user.userId); // this is the wpm calculation factoring in the time of test // it assumes that all words are 5 characters long because on average @@ -184,26 +184,33 @@ class API { xhr.send( JSON.stringify(user) ); + + this.login(username, password); } login(pUsername, pPassword) { - if (localStorage.getItem("userId") === null) { + if (localStorage.userId === null || localStorage.userId === 0 || localStorage.userId === undefined) { let xhr = new XMLHttpRequest(); - xhr.open('GET', `${this.url}/login/${pUsername}/${pPassword}`); - xhr.send(); - xhr.onload = () => { - user.userId = Number(xhr.response); - if (user.userId > 0) { - user.username = pUsername - localStorage.setItem("userId", user.userId); - localStorage.setItem("username", pUsername); - localStorage.setItem("password", pPassword); - } - - }; - } else { - this.userId = localStorage.getItem("userId"); - this.username = localStorage.getItem("username"); + xhr.open('GET', `${this.url}login/${pUsername}/${pPassword}`); + xhr.send(); + xhr.onload = () => { + user.userId = Number(xhr.response); + if (user.userId > 0) { + user.username = pUsername + localStorage.setItem("userId", user.userId); + localStorage.setItem("username", pUsername); + localStorage.setItem("password", pPassword); + } + }; + } else if (localStorage.userId > 0) { + user.userId = localStorage.userId; + user.username = localStorage.username; + user.password = localStorage.password; } } + + logout() { + user = new User(); + localStorage.clear(); + } } \ No newline at end of file diff --git a/website/api/user.js b/website/api/user.js index f0870da..c58db7d 100644 --- a/website/api/user.js +++ b/website/api/user.js @@ -1,7 +1,7 @@ class User { constructor() { - this.username; - this.password; - this.userId; + this.username = "not logged in"; + this.password = "there"; + this.userId = 0; } } \ No newline at end of file diff --git a/website/index.html b/website/index.html index 78bf674..ed3c5dc 100644 --- a/website/index.html +++ b/website/index.html @@ -23,6 +23,7 @@ + diff --git a/website/index.js b/website/index.js index ee14eae..fe6daef 100644 --- a/website/index.js +++ b/website/index.js @@ -1,4 +1,4 @@ -let canvas, api, screenManager; +let canvas, api, screenManager, user; function setup() { // Creating the canvas @@ -11,6 +11,10 @@ function setup() { api = new API(); screenManager = new ScreenManager(); screenManager.setScreen(new StartScreen()); + user = new User(); + + // will log the user in if there details are in local storage + api.login(); } // this function is called once per frame and draws all other elements diff --git a/website/screens/endscreen.js b/website/screens/endscreen.js index ebf1d29..1df4e6f 100644 --- a/website/screens/endscreen.js +++ b/website/screens/endscreen.js @@ -10,4 +10,8 @@ class EndScreen { fill(0); text("Test Complete\nPress enter to start another test", 0, 0, windowWidth - 100, windowHeight - 100); } + + letterTyped() { + screenManager.setScreen(new StartScreen()); + } } \ No newline at end of file diff --git a/website/screens/loginscreen.js b/website/screens/loginscreen.js new file mode 100644 index 0000000..826ac64 --- /dev/null +++ b/website/screens/loginscreen.js @@ -0,0 +1,98 @@ +class LoginScreen { + constructor() { + this.textboxes = [ + new Textbox( + 120,250, + 500,100, + 0, + true, + "#000", + false, "#000", + "#000" + ), + + new Textbox( + 120,400, + 500,100, + 0, + true, + "#000", + false,"000", + "#000" + ) + ] + + this.buttons = [ + new Button( + 100,200, + 500,100, + 0, + true, + "#000", + false,"#000", + "#fff","" + ), + + new Button( + 100,350, + 500,100, + 0, + true, + "#000", + false,"#000", + "#fff","" + ), + + new Button( + 700,300, + 100,50, + 0, + true, + "#000", + false,"#000", + "#00ff00","Login" + ), + ] + + this.activeTextBox = 0 + // keeps track of which textbox the user last clicked on + } + + /** + * Draws the SignUpScreen class with all + * appropriate elements + */ + draw() { + background("#eeeee4"); + for (let i = 0; i < this.buttons.length; i++) { + this.buttons[i].draw(); + } + + for (let i = 0; i < this.textboxes.length; i++) { + this.textboxes[i].draw(); + } + + text("Username", 110, 175); + text("Password", 110, 325); + + if (this.buttons[0].isPressed()) { + this.activeTextBox=0; + } else if (this.buttons[1].isPressed()) { + this.activeTextBox=1; + } else if (this.buttons[2].isPressed()) { + api.login( + this.textboxes[0].getWords(), + this.textboxes[1].getWords() + ) + screenManager.setScreen(new StartScreen()); + } + } + + /** + * + * @param {key} key + */ + letterTyped(key) { + this.textboxes[this.activeTextBox].letterTyped(key); + } +} \ No newline at end of file diff --git a/website/screens/startscreen.js b/website/screens/startscreen.js index 5d38130..d9593e4 100644 --- a/website/screens/startscreen.js +++ b/website/screens/startscreen.js @@ -1,6 +1,10 @@ class StartScreen { constructor() { - this.buttons = [new Button(0,0,100,30,0,true,"#fff",false,"#000","#000","Sign Up")] + this.buttons = [ + new Button(0,0,100,30,0,true,"#fff",false,"#000","#000","Sign Up"), + new Button(110,0,100,30,0,true,"#fff",false,"#000","#000","Login"), + new Button(220,0,100,30,0,true,"#fff",false,"#000","#000","Logout"), + ] } draw() { @@ -10,9 +14,17 @@ class StartScreen { fill("#000"); text("Press enter to start test", 0, 0, windowWidth - 100, windowHeight - 100); this.buttons[0].draw(); + this.buttons[1].draw(); + this.buttons[2].draw(); if (this.buttons[0].isPressed()) { screenManager.setScreen(new SignUpScreen()); - } + } else if (this.buttons[1].isPressed()) { + screenManager.setScreen(new LoginScreen()); + } else if (this.buttons[2].isPressed()) { + api.logout(); + } + fill("#000"); + text(`${user.username}`, windowWidth-100, 15); } letterTyped(key) { diff --git a/website/ui_elements/textbox.js b/website/ui_elements/textbox.js index bae59ad..1e2d2f7 100644 --- a/website/ui_elements/textbox.js +++ b/website/ui_elements/textbox.js @@ -133,7 +133,7 @@ class Textbox { if (pKey === "Backspace" && this.letters.length > 0) { this.letters.pop(); - this.words.substring(0, this.words.length-1) + this.words = this.words.substring(0, this.words.length-1) return; }