Working on checkTagPb, fixed keySpacingStats not saving err,

This commit is contained in:
lukew3 2021-05-25 13:39:37 -04:00
parent db042db540
commit 308d87d565
6 changed files with 199 additions and 51 deletions

View file

@ -3,7 +3,7 @@ const Schema = mongoose.Schema;
const tagSchema = new Schema({
name: { type: String, required: true },
//should be pb storage here i think
personalBests: { type: Schema.Types.Mixed },
});
const resultSchema = new Schema({
@ -35,7 +35,7 @@ const resultSchema = new Schema({
err: [{ type: Number }],
},
customText: { type: Schema.Types.Mixed },
keySpacingStats: String, //not sure that this needs to exist, it's set as null in all of mine
keySpacingStats: { type: Schema.Types.Mixed }, //not sure that this needs to exist, it's set as null in all of mine
name: { type: String, required: true }, //name of the user who took the test //should probably be typistName/username or something
isPb: { type: Boolean, required: true },
});

View file

@ -1,9 +1,11 @@
## Todo
- Get google login working
- Transfer leaderboard and other cloud functions
- Reverse list of results on account page
- spinning wheel on account page should dissapear after data is loaded
- Account data should be updated when new result is added/test completed
- Add email verification
- Tests started and completed doesn't increment when quitting a running test
- Joined date doesn't look the same as it did before
- Personal bests items should not be arrays
- should be objects that are set on new pb
@ -11,17 +13,26 @@
- Result is duplicated in analytics
- Does entire result need to be stored in analytics
- Should result be stored in seperate collection and then referenced in user doc and analytics?
- Loader should hide after tag is added, deleted, or edited
- Fix localhost, production, development server detection
- Should be a setting in the .env
- Maybe it could be set through package.json
- When a specific script is run, a certain mode will be activated
- Tests started and completed doesn't increment when quitting a running test
- Doesn't work as I expected in live version either, no issue
## After beta is ready
- Are personal bests calculated from actual result data?
- Setting a low pb after resetting personal bests doesn't register on the scoreboard
- make sure refresh token won't expire
- make refresh token expire after session if don't remeber me is set?
- Keep jwt and refresh in cookies?
- Get somebody else to check over security due to my lack of expertise
- Work on transfering data from firebase to mongo
## After release
- Investigate and improve efficiency after mongo merge or during review
- I'm not sure about this but it might be worthwhile to use redis to store userdata up to a certain point
- Users who have been requested in the last hour will be stored in the redis database so that their data can be sent again without having to search a large database
- After an hour without a new request they can be removed from memory
- User data should not be requested from the server every time a test is submitted, result should just be appended to results

View file

@ -173,7 +173,7 @@ async function checkIfPB(uid, obj, userdata) {
});
//checked all pbs, nothing found - meaning this is a new pb
if (!found) {
pbs[obj.mode][obj.mode2].push({
pbs[obj.mode][obj.mode2] = {
language: obj.language,
difficulty: obj.difficulty,
punctuation: obj.punctuation,
@ -182,7 +182,7 @@ async function checkIfPB(uid, obj, userdata) {
raw: obj.rawWpm,
timestamp: Date.now(),
consistency: obj.consistency,
});
};
toUpdate = true;
}
} catch (e) {
@ -215,8 +215,159 @@ async function checkIfPB(uid, obj, userdata) {
}
async function checkIfTagPB(uid, obj, userdata) {
//Add functionality before release
return true;
//function returns a list of tag ids where a pb was set //i think
if (obj.tags.length === 0) {
return [];
}
if (obj.mode == "quote") {
return [];
}
let dbtags = []; //tags from database: include entire document: name, id, pbs
let restags = obj.tags; //result tags
try {
let snap;
await User.findOne({ name: userdata.name }, (err, user) => {
snap = user.tags;
});
snap.forEach((doc) => {
//if (restags.includes(doc._id)) {
//if (restags.indexOf((doc._id).toString()) > -1) {
if (restags.includes(doc._id.toString())) {
//not sure what this is supposed to do
/*
let data = doc.data();
data.id = doc.id;
dbtags.push(data);
*/
dbtags.push(doc);
}
});
} catch {
return [];
}
let ret = [];
for (let i = 0; i < dbtags.length; i++) {
let pbs = null;
try {
pbs = dbtags[i].personalBests;
if (pbs === undefined || pbs === {}) {
throw new Error("pb is undefined");
}
} catch (e) {
console.log("PBs undefined");
//undefined personal best = new personal best
await User.findOne({ name: userdata.name }, (err, user) => {
//it might be more convenient if tags was an object with ids as the keys
for (let j = 0; j < user.tags.length; j++) {
console.log(user.tags[j]);
if (user.tags[j]._id.toString() == dbtags[i]._id.toString()) {
user.tags[j].personalBests = {
[obj.mode]: {
[obj.mode2]: {
language: obj.language,
difficulty: obj.difficulty,
punctuation: obj.punctuation,
wpm: obj.wpm,
acc: obj.acc,
raw: obj.rawWpm,
timestamp: Date.now(),
consistency: obj.consistency,
},
},
};
}
pbs = user.tags[j].personalBests;
}
user.save();
}).then((updatedUser) => {
ret.push(dbtags[i]._id.toString());
});
continue;
}
let toUpdate = false;
let found = false;
try {
if (pbs[obj.mode] === undefined) {
pbs[obj.mode] = { [obj.mode2]: [] };
} else if (pbs[obj.mode][obj.mode2] === undefined) {
pbs[obj.mode][obj.mode2] = [];
}
pbs[obj.mode][obj.mode2].forEach((pb) => {
if (
pb.punctuation === obj.punctuation &&
pb.difficulty === obj.difficulty &&
pb.language === obj.language
) {
//entry like this already exists, compare wpm
found = true;
if (pb.wpm < obj.wpm) {
//new pb
pb.wpm = obj.wpm;
pb.acc = obj.acc;
pb.raw = obj.rawWpm;
pb.timestamp = Date.now();
pb.consistency = obj.consistency;
toUpdate = true;
} else {
//no pb
return false;
}
}
});
//checked all pbs, nothing found - meaning this is a new pb
if (!found) {
console.log("Semi-new pb");
pbs[obj.mode][obj.mode2] = {
language: obj.language,
difficulty: obj.difficulty,
punctuation: obj.punctuation,
wpm: obj.wpm,
acc: obj.acc,
raw: obj.rawWpm,
timestamp: Date.now(),
consistency: obj.consistency,
};
toUpdate = true;
}
} catch (e) {
// console.log(e);
console.log("Catch pb");
console.log(e);
pbs[obj.mode] = {};
pbs[obj.mode][obj.mode2] = [
{
language: obj.language,
difficulty: obj.difficulty,
punctuation: obj.punctuation,
wpm: obj.wpm,
acc: obj.acc,
raw: obj.rawWpm,
timestamp: Date.now(),
consistency: obj.consistency,
},
];
toUpdate = true;
}
if (toUpdate) {
console.log("Adding new pb at end");
await User.findOne({ name: userdata.name }, (err, user) => {
//it might be more convenient if tags was an object with ids as the keys
for (let j = 0; j < user.tags.length; j++) {
console.log(user.tags[j]);
console.log(dbtags[i]);
if (user.tags[j]._id.toString() === dbtags[i]._id.toString()) {
console.log("Made it inside the if");
user.tags[j].personalBests = dbtags[i].personalBests;
}
}
user.save();
});
ret.push(dbtags[i]._id.toString());
}
}
console.log(ret);
return ret;
}
async function stripAndSave(uid, obj) {
@ -495,7 +646,7 @@ app.get("/api/fetchSnapshot", authenticateToken, (req, res) => {
let snap = user;
delete snap.password;
//return user data
res.json({ snap: snap });
res.send({ snap: snap });
});
});
@ -742,7 +893,7 @@ app.post("/api/testCompleted", authenticateToken, (req, res) => {
// emailVerified
// ),
checkIfPB(request.uid, request.obj, userdata),
checkIfTagPB(request.uid, request.obj),
checkIfTagPB(request.uid, request.obj, userdata),
])
.then(async (values) => {
// let globallb = values[0].insertedAt;
@ -1295,20 +1446,20 @@ app.post("/api/addTag", authenticateToken, (req, res) => {
})
.then((updatedUser) => {
console.log(`user ${req.name} created a tag: ${req.body.tagName}`);
return {
res.json({
resultCode: 1,
id: updatedUser.tags[updatedUser.tags.length - 1]._id,
};
});
})
.catch((e) => {
console.error(
`error while creating tag for user ${req.name}: ${e.message}`
);
return { resultCode: -999, message: e.message };
res.json({ resultCode: -999, message: e.message });
});
} catch (e) {
console.error(`error adding tag for ${req.name} - ${e}`);
return { resultCode: -999, message: e.message };
res.json({ resultCode: -999, message: e.message });
}
});
@ -1326,19 +1477,17 @@ app.post("/api/editTag", authenticateToken, (req, res) => {
})
.then((updatedUser) => {
console.log(`user ${req.name} updated a tag: ${req.name}`);
return {
resultCode: 1,
};
res.json({ resultCode: 1 });
})
.catch((e) => {
console.error(
`error while updating tag for user ${req.name}: ${e.message}`
);
return { resultCode: -999, message: e.message };
res.json({ resultCode: -999, message: e.message });
});
} catch (e) {
console.error(`error updating tag for ${req.name} - ${e}`);
return { resultCode: -999, message: e.message };
res.json({ resultCode: -999, message: e.message });
}
});
@ -1355,17 +1504,15 @@ app.post("/api/removeTag", authenticateToken, (req, res) => {
})
.then((updatedUser) => {
console.log(`user ${req.name} deleted a tag`);
return {
resultCode: 1,
};
res.json({ resultCode: 1 });
})
.catch((e) => {
console.error(`error deleting tag for user ${req.name}: ${e.message}`);
return { resultCode: -999 };
res.json({ resultCode: -999 });
});
} catch (e) {
console.error(`error deleting tag for ${req.name} - ${e}`);
return { resultCode: -999 };
res.json({ resultCode: -999 });
}
});
@ -1376,12 +1523,12 @@ app.post("/api/resetPersonalBests", authenticateToken, (req, res) => {
user.personalBests = {};
user.save();
});
return true;
res.status(200).send({ status: "Reset Pbs successfully" });
} catch (e) {
console.log(
`something went wrong when deleting personal bests for ${uid}: ${e.message}`
);
return false;
res.status(500).send({ status: "Reset Pbs successfully" });
}
});
// ANALYTICS API

View file

@ -1,17 +1,11 @@
import { loadTags } from "./result-filters";
import * as AccountButton from "./account-button";
import * as CloudFunctions from "./cloud-functions";
import * as Notifications from "./notifications";
import axiosInstance from "./axios-instance";
import Cookies from "js-cookie";
//const db = firebase.firestore();
//db.settings({ experimentalForceLongPolling: true });
let dbSnapshot = null;
//I think that a lot of these functions could be simplified by api calls
export function updateName(uid, name) {
//db.collection(`users`).doc(uid).set({ name: name }, { merge: true });
axiosInstance.post("/api/updateName", {
@ -57,7 +51,6 @@ export function currentUser() {
export async function initSnapshot() {
//send api request with token that returns tags, presets, and data needed for snap
if (currentUser() == null) return false;
const token = Cookies.get("accessToken");
await axiosInstance
.get("/api/fetchSnapshot")
.then((response) => {
@ -335,21 +328,20 @@ export async function getLocalTagPB(
) {
function cont() {
let ret = 0;
let filteredtag = dbSnapshot.tags.filter((t) => t.id === tagId)[0];
let filteredtag = dbSnapshot.tags.filter((t) => t._id === tagId)[0];
try {
filteredtag.personalBests[mode][mode2].forEach((pb) => {
if (
pb.punctuation == punctuation &&
pb.difficulty == difficulty &&
pb.language == language
) {
ret = pb.wpm;
}
});
return ret;
const pb = filteredtag.personalBests[mode][mode2];
if (
pb.punctuation == punctuation &&
pb.difficulty == difficulty &&
pb.language == language
) {
ret = pb.wpm;
}
} catch (e) {
return ret;
console.log(e);
}
return ret;
}
let retval;
@ -375,7 +367,7 @@ export async function saveLocalTagPB(
) {
if (mode == "quote") return;
function cont() {
let filteredtag = dbSnapshot.tags.filter((t) => t.id === tagId)[0];
let filteredtag = dbSnapshot.tags.filter((t) => t._id === tagId)[0];
try {
let found = false;
if (filteredtag.personalBests[mode][mode2] === undefined) {

View file

@ -2,7 +2,6 @@ import * as ResultTagsPopup from "./result-tags-popup";
import * as ResultFilters from "./result-filters";
import * as Loader from "./loader";
import * as DB from "./db";
import * as CloudFunctions from "./cloud-functions";
import * as Notifications from "./notifications";
import * as Settings from "./settings";
import axiosInstance from "./axios-instance";

View file

@ -25,7 +25,6 @@ import * as OutOfFocus from "./out-of-focus";
import * as AccountButton from "./account-button";
import * as DB from "./db";
import * as ThemeColors from "./theme-colors";
import * as CloudFunctions from "./cloud-functions";
import * as TestLeaderboards from "./test-leaderboards";
import * as Replay from "./replay.js";
import axiosInstance from "./axios-instance";