From c031664c5dab181f6e8745f389b6f864b59cc395 Mon Sep 17 00:00:00 2001 From: Josseline Perdomo Date: Tue, 6 Oct 2020 19:40:19 -0400 Subject: [PATCH 1/5] get last 3 timing given the user and question id endpoint --- routes/routes.js | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/routes/routes.js b/routes/routes.js index b133d8c..c5e08a9 100644 --- a/routes/routes.js +++ b/routes/routes.js @@ -38,5 +38,31 @@ router.post('/user/answers/question/:questionNumber', (req, res) => { }) }) +router.get('/user/answers/question/:questionNumber', (req, res) => { + let pageSize = 3; // TODO: define it in more stadarized way + + User.findOne({ + where: {id: req.body.userId} + }).then(user => { + + UserAnswers.findAll({ + where: {question_number: req.params.questionNumber, user_id: user.id}, + order: [ + ['created_at', 'DESC'] + ], + limit: pageSize + }).then(userAnswers => { + return res.json({ + previousTimingMs: userAnswers.map(userAnswer => userAnswer.elapsed_time_ms) + }) + }).catch(error => { + console.log(error); + return res.status(400).json(error.errors) // TODO: handle better error messages + }) + }).catch(error => { + console.log(error); + return res.status(400).json({message: "User doesn't exists."}) // TODO: handle better error messages + }) +}) module.exports = router; From 2a37b913adccee70757c9ca4fefc637b96d14362 Mon Sep 17 00:00:00 2001 From: Josseline Perdomo Date: Tue, 6 Oct 2020 21:29:33 -0400 Subject: [PATCH 2/5] - integrated history endpoint - param in query instead of body in endpoint request --- public/scripts/history.js | 18 ++++++-- public/scripts/main.js | 87 ++++++++++++++++++++------------------- routes/routes.js | 4 +- 3 files changed, 61 insertions(+), 48 deletions(-) diff --git a/public/scripts/history.js b/public/scripts/history.js index 2d9e015..8c63396 100644 --- a/public/scripts/history.js +++ b/public/scripts/history.js @@ -72,14 +72,26 @@ function clearHistory() { } // returns an array with timing data for a given question number -function getHistory(questionNo) { +async function getHistory(questionNo) { if (!loadHistory()) { console.error('Unable to load history for question ' + questionNo); return []; } - var record = _history[questionNo]; - return !!record ? record : []; + let url = new URL(document.URL + 'user/answers/question/' + questionNo); + let params = { + userId: 'guest' // TODO: get actual userId + } + url.search = new URLSearchParams(params).toString(); + + try{ + let response = await fetch(url); + let body = await response.json(); + return body.previousTimingMs; + }catch(error){ + console.error(error); + return []; + } } // record the time taken to answer a given question based on the question diff --git a/public/scripts/main.js b/public/scripts/main.js index 6cd0aa2..4706ad2 100644 --- a/public/scripts/main.js +++ b/public/scripts/main.js @@ -263,19 +263,19 @@ function updateTimingDisplay() { $('#timing-feedback').html(''); var questionNo = localStorage.getItem('questionNo'); // grab the last bits of timing data - var timings = getHistory(questionNo).slice(-3); - - // and then drop them into the boxes - timings.forEach(function(t, idx) { - var element = $('#timing-' + idx); - element.html(t / 1000 + ' sec'); - element.show(); - }) - - // hide the boxes if we don't have timing data - for (var i = timings.length; i < 3; i++) { - $('#timing-' + i).hide(); - } + getHistory(questionNo).then(timings => { + // and then drop them into the boxes + timings.forEach(function(t, idx) { + var element = $('#timing-' + idx); + element.html(t / 1000 + ' sec'); + element.show(); + }) + + // hide the boxes if we don't have timing data + for (var i = timings.length; i < 3; i++) { + $('#timing-' + i).hide(); + } + }); } function onIncorrect() { @@ -286,36 +286,37 @@ function onIncorrect() { }; function handleTimingFeedback(questionNo, curMS) { - var previousTimings = getHistory(questionNo); - if (previousTimings.length == 0) { - return; - } - - var average = previousTimings.reduce( - function(acc, cur) { return acc + cur }, - 0, - ) / previousTimings.length; - - var delta = average - curMS; - - var template = null; - if (delta > 0) { - template = "
You were faster by ${delta} sec!"; - } - if (delta < 0) { - template = "
You were slower by ${delta} sec."; - } - if (template === null) { - return; - } - - // convert MS to S - delta = Math.abs(delta) / 1000; - // now we want to trunate to 2 decimals; the `+` will let us only use 2 - // decimals if we actually need them, e.g., we want 1.5 not 1.50 - // cf. https://stackoverflow.com/a/12830454 - delta = +delta.toFixed(2); - $('#timing-feedback').html(template.replace('${delta}', delta)); + getHistory(questionNo).then(previousTimings => { + if (previousTimings.length == 0) { + return; + } + + var average = previousTimings.reduce( + function(acc, cur) { return acc + cur }, + 0, + ) / previousTimings.length; + + var delta = average - curMS; + + var template = null; + if (delta > 0) { + template = "
You were faster by ${delta} sec!"; + } + if (delta < 0) { + template = "
You were slower by ${delta} sec."; + } + if (template === null) { + return; + } + + // convert MS to S + delta = Math.abs(delta) / 1000; + // now we want to trunate to 2 decimals; the `+` will let us only use 2 + // decimals if we actually need them, e.g., we want 1.5 not 1.50 + // cf. https://stackoverflow.com/a/12830454 + delta = +delta.toFixed(2); + $('#timing-feedback').html(template.replace('${delta}', delta)); + }); } // Function to execute when correct keys are pressed. diff --git a/routes/routes.js b/routes/routes.js index c5e08a9..ee29184 100644 --- a/routes/routes.js +++ b/routes/routes.js @@ -42,7 +42,7 @@ router.get('/user/answers/question/:questionNumber', (req, res) => { let pageSize = 3; // TODO: define it in more stadarized way User.findOne({ - where: {id: req.body.userId} + where: {id: req.query.userId} }).then(user => { UserAnswers.findAll({ @@ -52,7 +52,7 @@ router.get('/user/answers/question/:questionNumber', (req, res) => { ], limit: pageSize }).then(userAnswers => { - return res.json({ + return res.status(200).json({ previousTimingMs: userAnswers.map(userAnswer => userAnswer.elapsed_time_ms) }) }).catch(error => { From 3a651b1eb77564dbafd254df5dceec0a32180c68 Mon Sep 17 00:00:00 2001 From: Josseline Perdomo Date: Tue, 6 Oct 2020 21:46:37 -0400 Subject: [PATCH 3/5] refactored history.js --- public/scripts/history.js | 95 +-------------------------------------- public/scripts/main.js | 2 - 2 files changed, 2 insertions(+), 95 deletions(-) diff --git a/public/scripts/history.js b/public/scripts/history.js index 8c63396..5d3ea57 100644 --- a/public/scripts/history.js +++ b/public/scripts/history.js @@ -1,111 +1,20 @@ -// global reference to the history; shouldn't be directly accessed outside -// this file. -// -// If we are using a remote backend cache the value here for easy access once -// we've done an initial retrieval -var _history = null; - -// this tracks if we're using local storage or some remote user system to -// keep timing data -var _historyUsesLocalStorage = true; - -// the key we store timing data under when in local storage mode -var _historyKey = 'response_history'; - /////////////////////////////////////////////////////////////////////////////// -// If we are storing things remotely the code to get them goes here -function getRemoteHistory() { - console.error('User accounts not yet implemented.'); - return null; -} - -// as above except saving -function saveRemoteHistory() { - console.error('User accounts not yet implementhed.'); - return false; -} - -// ensures that history has been loaded; returns true on success -function loadHistory() { - if (_history !== null) { - return true; - } - - if (!_historyUsesLocalStorage) { - var history = getRemoteHistory(); - if (history === null) { - console.error('Falling back to local history'); - } else { - _history = history; - return true; - } - } - - var history = localStorage.getItem(_historyKey); - if (history == null) { - localStorage.setItem(_historyKey, JSON.stringify({})); - history = "{}"; - } - _history = JSON.parse(history); - return true; -} - -// saves history; returns true on success -function saveHistory() { - if (!_historyUsesLocalStorage) { - if (saveRemoteHistory()) { - return true; - } - console.error('Falling back to local history'); - } - - localStorage.setItem(_historyKey, JSON.stringify(_history)); - return true; -} - -// clears historic timing data and saves the cleared state; returns true on -// success -function clearHistory() { - _history = {}; - return saveHistory(); -} - // returns an array with timing data for a given question number async function getHistory(questionNo) { - if (!loadHistory()) { - console.error('Unable to load history for question ' + questionNo); - return []; - } - let url = new URL(document.URL + 'user/answers/question/' + questionNo); let params = { userId: 'guest' // TODO: get actual userId } url.search = new URLSearchParams(params).toString(); - + try{ let response = await fetch(url); let body = await response.json(); return body.previousTimingMs; + }catch(error){ console.error(error); return []; } } - -// record the time taken to answer a given question based on the question -// number -function recordAnswer(questionNo, timeSpentMS) { - if (!loadHistory()) { - console.error('Unable to record new time for question ' + questionNo); - return false; - } - - // check for existing timing data, initialize if none found - if (!_history[questionNo]) { - _history[questionNo] = []; - } - _history[questionNo].push(timeSpentMS); - return true; -} \ No newline at end of file diff --git a/public/scripts/main.js b/public/scripts/main.js index 4706ad2..095ba59 100644 --- a/public/scripts/main.js +++ b/public/scripts/main.js @@ -324,8 +324,6 @@ function onSuccess() { var questionNo = localStorage.getItem("questionNo"); var thisAnswerMS = Date.now() - questionStartMS; handleTimingFeedback(questionNo, thisAnswerMS); - recordAnswer(questionNo, thisAnswerMS); - saveHistory(); document.querySelector("#textdiv span").textContent = 'Correct Keys pressed!'; clearPromptKeys(); clearPressedKeys(); From caf0c6708f663b842aa1b2cc3cb4092878d7afc6 Mon Sep 17 00:00:00 2001 From: Josseline Perdomo Date: Thu, 8 Oct 2020 17:12:52 -0400 Subject: [PATCH 4/5] fixed all the comments made in review stage --- public/scripts/history.js | 2 +- routes/routes.js | 38 ++++++++++++++++---------------------- 2 files changed, 17 insertions(+), 23 deletions(-) diff --git a/public/scripts/history.js b/public/scripts/history.js index 5d3ea57..f30e5ec 100644 --- a/public/scripts/history.js +++ b/public/scripts/history.js @@ -4,7 +4,7 @@ async function getHistory(questionNo) { let url = new URL(document.URL + 'user/answers/question/' + questionNo); let params = { - userId: 'guest' // TODO: get actual userId + userId: 'guest' } url.search = new URLSearchParams(params).toString(); diff --git a/routes/routes.js b/routes/routes.js index ee29184..6bba9dd 100644 --- a/routes/routes.js +++ b/routes/routes.js @@ -1,7 +1,10 @@ const express = require('express'); const router = express.Router(); -const{ User, UserAnswers } = require('../JS/orm'); +const { User, UserAnswers } = require('../JS/orm'); + +const ANSWER_HISTORY_LIMIT = 3; + router.get('/', (req, res) => { res.render('index'); @@ -39,29 +42,20 @@ router.post('/user/answers/question/:questionNumber', (req, res) => { }) router.get('/user/answers/question/:questionNumber', (req, res) => { - let pageSize = 3; // TODO: define it in more stadarized way - - User.findOne({ - where: {id: req.query.userId} - }).then(user => { - - UserAnswers.findAll({ - where: {question_number: req.params.questionNumber, user_id: user.id}, - order: [ - ['created_at', 'DESC'] - ], - limit: pageSize - }).then(userAnswers => { - return res.status(200).json({ - previousTimingMs: userAnswers.map(userAnswer => userAnswer.elapsed_time_ms) - }) - }).catch(error => { - console.log(error); - return res.status(400).json(error.errors) // TODO: handle better error messages + // TODO: When issue #74 be done, the userId should be handled differently from req object + UserAnswers.findAll({ + where: {question_number: req.params.questionNumber, user_id: req.query.userId}, + order: [ + ['created_at', 'DESC'] + ], + limit: ANSWER_HISTORY_LIMIT + }).then(userAnswers => { + return res.json({ + previousTimingMs: userAnswers.map(userAnswer => userAnswer.elapsed_time_ms) }) }).catch(error => { - console.log(error); - return res.status(400).json({message: "User doesn't exists."}) // TODO: handle better error messages + console.log(error); + return res.status(500).json(error.errors) // TODO: handle better error messages }) }) From 256de3fc9aaa38b4f2619c2a37e3372cf45ab074 Mon Sep 17 00:00:00 2001 From: Josseline Perdomo Date: Thu, 8 Oct 2020 20:01:09 -0400 Subject: [PATCH 5/5] added mock userId on the server --- public/scripts/history.js | 4 ---- routes/routes.js | 6 ++++-- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/public/scripts/history.js b/public/scripts/history.js index f30e5ec..e3516e0 100644 --- a/public/scripts/history.js +++ b/public/scripts/history.js @@ -3,10 +3,6 @@ // returns an array with timing data for a given question number async function getHistory(questionNo) { let url = new URL(document.URL + 'user/answers/question/' + questionNo); - let params = { - userId: 'guest' - } - url.search = new URLSearchParams(params).toString(); try{ let response = await fetch(url); diff --git a/routes/routes.js b/routes/routes.js index 6bba9dd..71be56a 100644 --- a/routes/routes.js +++ b/routes/routes.js @@ -42,9 +42,11 @@ router.post('/user/answers/question/:questionNumber', (req, res) => { }) router.get('/user/answers/question/:questionNumber', (req, res) => { - // TODO: When issue #74 be done, the userId should be handled differently from req object + // TODO: When issue #74 be done, the userId should be handled from req object + let userId = 'guest'; + UserAnswers.findAll({ - where: {question_number: req.params.questionNumber, user_id: req.query.userId}, + where: {question_number: req.params.questionNumber, user_id: userId}, order: [ ['created_at', 'DESC'] ],