mirror of
https://github.com/monkeytypegame/monkeytype.git
synced 2025-02-04 04:51:16 +08:00
Working on checkTagPb, fixed keySpacingStats not saving err,
This commit is contained in:
parent
db042db540
commit
308d87d565
6 changed files with 199 additions and 51 deletions
|
@ -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 },
|
||||
});
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
32
src/js/db.js
32
src/js/db.js
|
@ -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) {
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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";
|
||||
|
|
Loading…
Reference in a new issue