added tag methods and new result and tag schema

This commit is contained in:
lukew3 2021-05-21 23:41:43 -04:00
parent 0b58c1de0c
commit 519abe07bf
12 changed files with 230 additions and 196 deletions

View file

@ -1,9 +1,50 @@
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const tagSchema = new Schema({
name: { type: String, required: true },
//should be pb storage here i think
});
const resultSchema = new Schema({
wpm: { type: Number, required: true },
rawWpm: { type: Number, required: true },
correctChars: { type: Number, required: true },
incorrectChars: { type: Number, required: true },
allChars: { type: Number, required: true },
acc: { type: Number, required: true },
mode: { type: String, required: true }, //is this always string type?
mode2: { type: Number, required: true }, //is this always number type?
quoteLength: { type: Number, required: true },
timestamp: { type: Number, required: true }, //can this be removed if timestamps are added to mongoose
language: { type: String, required: true },
restartCount: { type: Number, required: true },
incompleteTestSeconds: { type: Number, required: true },
testDuration: { type: Number, required: true },
afkDuration: { type: Number, required: true },
theme: { type: String, required: true },
tags: [{ type: String }], //the id of each tag
keySpacing: { type: String, required: true },
keyDuration: { type: String, required: true },
consistency: { type: Number, required: true },
keyConsistency: { type: Number, required: true },
chartData: {
//should chartData have it's own schema?
wpm: [{ type: Number }],
raw: [{ type: Number }],
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
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 },
});
const configSchema = new Schema({});
const userSchema = new Schema(
{
results: [{ type: Schema.Types.Mixed, default: {} }],
results: [{ type: resultSchema, default: {} }],
personalBests: {
custom: { type: Schema.Types.Mixed, default: {} },
time: { type: Schema.Types.Mixed, default: {} },
@ -12,7 +53,7 @@ const userSchema = new Schema(
},
name: { type: String, required: true },
presets: [{ type: Schema.Types.Mixed, default: {} }],
tags: [{ type: Schema.Types.Mixed, default: {} }],
tags: [{ type: tagSchema, default: {} }],
favouriteThemes: [],
refactored: { type: Boolean, default: true },
banned: { type: Boolean, default: false },

View file

@ -1184,6 +1184,101 @@ app.post("/api/checkLeaderboards", (req, res) => {
});
*/
function isTagPresetNameValid(name) {
if (name === null || name === undefined || name === "") return false;
if (name.length > 16) return false;
return /^[0-9a-zA-Z_.-]+$/.test(name);
}
//could use /api/tags/add instead
app.post("/api/addTag", authenticateToken, (req, res) => {
try {
if (!isTagPresetNameValid(req.body.tagName)) return { resultCode: -1 };
User.findOne({ name: req.name }, (err, user) => {
if (err) res.status(500).send({ error: err });
if (user.tags.includes(req.body.tagName)) {
return { resultCode: -999, message: "Duplicate tag" };
}
const tagObj = { name: req.body.tagName };
user.tags.push(tagObj);
user.save();
})
.then((updatedUser) => {
console.log(`user ${req.name} created a tag: ${req.body.tagName}`);
return {
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 };
});
} catch (e) {
console.error(`error adding tag for ${req.name} - ${e}`);
return { resultCode: -999, message: e.message };
}
});
app.post("/api/editTag", authenticateToken, (req, res) => {
try {
if (!isTagPresetNameValid(req.body.tagName)) return { resultCode: -1 };
User.findOne({ name: req.name }, (err, user) => {
if (err) res.status(500).send({ error: err });
for (var i = 0; i < user.tags.length; i++) {
if (user.tags[i]._id == req.body.tagId) {
user.tags[i].name = req.body.tagName;
}
}
user.save();
})
.then((updatedUser) => {
console.log(`user ${req.name} updated a tag: ${req.name}`);
return {
resultCode: 1,
};
})
.catch((e) => {
console.error(
`error while updating tag for user ${req.name}: ${e.message}`
);
return { resultCode: -999, message: e.message };
});
} catch (e) {
console.error(`error updating tag for ${req.name} - ${e}`);
return { resultCode: -999, message: e.message };
}
});
app.post("/api/removeTag", authenticateToken, (req, res) => {
try {
User.findOne({ name: req.name }, (err, user) => {
if (err) res.status(500).send({ error: err });
for (var i = 0; i < user.tags.length; i++) {
if (user.tags[i]._id == req.body.tagId) {
user.tags.splice(i, 1);
}
}
user.save();
})
.then((updatedUser) => {
console.log(`user ${req.name} deleted a tag`);
return {
resultCode: 1,
};
})
.catch((e) => {
console.error(`error deleting tag for user ${req.name}: ${e.message}`);
return { resultCode: -999 };
});
} catch (e) {
console.error(`error deleting tag for ${req.name} - ${e}`);
return { resultCode: -999 };
}
});
// ANALYTICS API
function newAnalyticsEvent(event, data) {

View file

@ -759,96 +759,6 @@ function updateDiscordRole(discordId, wpm) {
});
}
function isTagPresetNameValid(name) {
if (name === null || name === undefined || name === "") return false;
if (name.length > 16) return false;
return /^[0-9a-zA-Z_.-]+$/.test(name);
}
exports.addTag = functions.https.onCall((request, response) => {
try {
if (!isTagPresetNameValid(request.name)) {
return { resultCode: -1 };
} else {
return db
.collection(`users/${request.uid}/tags`)
.add({
name: request.name,
})
.then((e) => {
console.log(`user ${request.uid} created a tag: ${request.name}`);
return {
resultCode: 1,
id: e.id,
};
})
.catch((e) => {
console.error(
`error while creating tag for user ${request.uid}: ${e.message}`
);
return { resultCode: -999, message: e.message };
});
}
} catch (e) {
console.error(`error adding tag for ${request.uid} - ${e}`);
return { resultCode: -999, message: e.message };
}
});
exports.editTag = functions.https.onCall((request, response) => {
try {
if (!isTagPresetNameValid(request.name)) {
return { resultCode: -1 };
} else {
return db
.collection(`users/${request.uid}/tags`)
.doc(request.tagid)
.update({
name: request.name,
})
.then((e) => {
console.log(`user ${request.uid} updated a tag: ${request.name}`);
return {
resultCode: 1,
};
})
.catch((e) => {
console.error(
`error while updating tag for user ${request.uid}: ${e.message}`
);
return { resultCode: -999, message: e.message };
});
}
} catch (e) {
console.error(`error updating tag for ${request.uid} - ${e}`);
return { resultCode: -999, message: e.message };
}
});
exports.removeTag = functions.https.onCall((request, response) => {
try {
return db
.collection(`users/${request.uid}/tags`)
.doc(request.tagid)
.delete()
.then((e) => {
console.log(`user ${request.uid} deleted a tag`);
return {
resultCode: 1,
};
})
.catch((e) => {
console.error(
`error deleting tag for user ${request.uid}: ${e.message}`
);
return { resultCode: -999 };
});
} catch (e) {
console.error(`error deleting tag for ${request.uid} - ${e}`);
return { resultCode: -999 };
}
});
exports.updateResultTags = functions.https.onCall((request, response) => {
try {
let validTags = true;
@ -1122,21 +1032,6 @@ exports.removePreset = functions.https.onCall((request, response) => {
}
});
function generate(n) {
var add = 1,
max = 12 - add;
if (n > max) {
return generate(max) + generate(n - max);
}
max = Math.pow(10, n + add);
var min = max / 10; // Math.pow(10, n) basically
var number = Math.floor(Math.random() * (max - min + 1)) + min;
return ("" + number).substring(add);
}
class Leaderboard {
constructor(size, mode, mode2, type, starting) {
this.size = size;

View file

@ -224,7 +224,7 @@ function loadMoreLines() {
if (result.tags !== undefined && result.tags.length > 0) {
result.tags.forEach((tag) => {
DB.getSnapshot().tags.forEach((snaptag) => {
if (tag === snaptag.id) {
if (tag === snaptag._id) {
tagNames += snaptag.name + ", ";
}
});

View file

@ -98,7 +98,7 @@ export function getFilter(group, filter) {
export function loadTags(tags) {
tags.forEach((tag) => {
defaultResultFilters.tags[tag.id] = true;
defaultResultFilters.tags[tag._id] = true;
});
}
@ -301,7 +301,7 @@ export function updateTags() {
DB.getSnapshot().tags.forEach((tag) => {
$(
".pageAccount .content .filterButtons .buttonsAndTitle.tags .buttons"
).append(`<div class="button" filter="${tag.id}">${tag.name}</div>`);
).append(`<div class="button" filter="${tag._id}">${tag.name}</div>`);
});
} else {
$(".pageAccount .content .filterButtons .buttonsAndTitle.tags").addClass(
@ -408,7 +408,7 @@ $(".pageAccount .topFilters .button.currentConfigFilter").click((e) => {
DB.getSnapshot().tags.forEach((tag) => {
if (tag.active === true) {
filters["tags"]["none"] = false;
filters["tags"][tag.id] = true;
filters["tags"][tag._id] = true;
}
});

View file

@ -213,11 +213,11 @@ export function updateTagCommands() {
}
commandsTags.list.push({
id: "toggleTag" + tag.id,
id: "toggleTag" + tag._id,
display: dis,
sticky: true,
exec: () => {
TagController.toggle(tag.id);
TagController.toggle(tag._id);
TestUI.updateModesNotice();
let txt = tag.name;
@ -228,11 +228,11 @@ export function updateTagCommands() {
}
if (Commandline.isSingleListCommandLineActive()) {
$(
`#commandLine .suggestions .entry[command='toggleTag${tag.id}']`
`#commandLine .suggestions .entry[command='toggleTag${tag._id}']`
).html("Change tags > " + txt);
} else {
$(
`#commandLine .suggestions .entry[command='toggleTag${tag.id}']`
`#commandLine .suggestions .entry[command='toggleTag${tag._id}']`
).html(txt);
}
},

View file

@ -480,7 +480,7 @@ export async function saveConfig(config) {
// export async functio(tagId, wpm) {
// function cont() {
// dbSnapshot.tags.forEach((tag) => {
// if (tag.id === tagId) {
// if (tag._id === tagId) {
// tag.pb = wpm;
// }
// });

View file

@ -5,6 +5,7 @@ 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";
export function show(action, id, name) {
if (action === "add") {
@ -66,74 +67,77 @@ function apply() {
hide();
if (action === "add") {
Loader.show();
CloudFunctions.addTag({
uid: DB.currentUser().uid,
name: inputVal,
}).then((e) => {
Loader.hide();
let status = e.data.resultCode;
if (status === 1) {
Notifications.add("Tag added", 1, 2);
DB.getSnapshot().tags.push({
name: inputVal,
id: e.data.id,
});
ResultTagsPopup.updateButtons();
Settings.update();
ResultFilters.updateTags();
} else if (status === -1) {
Notifications.add("Invalid tag name", 0);
} else if (status < -1) {
Notifications.add("Unknown error: " + e.data.message, -1);
}
});
axiosInstance
.post("/api/addTag", {
tagName: inputVal,
})
.then((e) => {
Loader.hide();
let status = e.data.resultCode;
if (status === 1) {
Notifications.add("Tag added", 1, 2);
DB.getSnapshot().tags.push({
name: inputVal,
id: e.data.id,
});
ResultTagsPopup.updateButtons();
Settings.update();
ResultFilters.updateTags();
} else if (status === -1) {
Notifications.add("Invalid tag name", 0);
} else if (status < -1) {
Notifications.add("Unknown error: " + e.data.message, -1);
}
});
} else if (action === "edit") {
Loader.show();
CloudFunctions.editTag({
uid: DB.currentUser().uid,
name: inputVal,
tagid: tagid,
}).then((e) => {
Loader.hide();
let status = e.data.resultCode;
if (status === 1) {
Notifications.add("Tag updated", 1);
DB.getSnapshot().tags.forEach((tag) => {
if (tag.id === tagid) {
tag.name = inputVal;
}
});
ResultTagsPopup.updateButtons();
Settings.update();
ResultFilters.updateTags();
} else if (status === -1) {
Notifications.add("Invalid tag name", 0);
} else if (status < -1) {
Notifications.add("Unknown error: " + e.data.message, -1);
}
});
axiosInstance
.post("/api/editTag", {
tagName: inputVal,
tagId: tagid,
})
.then((e) => {
Loader.hide();
let status = e.data.resultCode;
if (status === 1) {
Notifications.add("Tag updated", 1);
DB.getSnapshot().tags.forEach((tag) => {
if (tag._id === tagid) {
tag.name = inputVal;
}
});
ResultTagsPopup.updateButtons();
Settings.update();
ResultFilters.updateTags();
} else if (status === -1) {
Notifications.add("Invalid tag name", 0);
} else if (status < -1) {
Notifications.add("Unknown error: " + e.data.message, -1);
}
});
} else if (action === "remove") {
Loader.show();
CloudFunctions.removeTag({
uid: DB.currentUser().uid,
tagid: tagid,
}).then((e) => {
Loader.hide();
let status = e.data.resultCode;
if (status === 1) {
Notifications.add("Tag removed", 1);
DB.getSnapshot().tags.forEach((tag, index) => {
if (tag.id === tagid) {
DB.getSnapshot().tags.splice(index, 1);
}
});
ResultTagsPopup.updateButtons();
Settings.update();
ResultFilters.updateTags();
} else if (status < -1) {
Notifications.add("Unknown error: " + e.data.message, -1);
}
});
axiosInstance
.post("/api/removeTag", {
tagId: tagid,
})
.then((e) => {
Loader.hide();
let status = e.data.resultCode;
if (status === 1) {
Notifications.add("Tag removed", 1);
DB.getSnapshot().tags.forEach((tag, index) => {
if (tag._id === tagid) {
DB.getSnapshot().tags.splice(index, 1);
}
});
ResultTagsPopup.updateButtons();
Settings.update();
ResultFilters.updateTags();
} else if (status < -1) {
Notifications.add("Unknown error: " + e.data.message, -1);
}
});
}
}

View file

@ -34,7 +34,7 @@ export function updateButtons() {
$("#resultEditTagsPanel .buttons").empty();
DB.getSnapshot().tags.forEach((tag) => {
$("#resultEditTagsPanel .buttons").append(
`<div class="button tag" tagid="${tag.id}">${tag.name}</div>`
`<div class="button tag" tagid="${tag._id}">${tag.name}</div>`
);
});
}
@ -104,7 +104,7 @@ $("#resultEditTagsPanel .confirmButton").click((e) => {
if (newtags.length > 0) {
newtags.forEach((tag) => {
DB.getSnapshot().tags.forEach((snaptag) => {
if (tag === snaptag.id) {
if (tag === snaptag._id) {
tagNames += snaptag.name + ", ";
}
});

View file

@ -406,11 +406,11 @@ function showActiveTags() {
DB.getSnapshot().tags.forEach((tag) => {
if (tag.active === true) {
$(
`.pageSettings .section.tags .tagsList .tag[id='${tag.id}'] .active`
`.pageSettings .section.tags .tagsList .tag[id='${tag._id}'] .active`
).html('<i class="fas fa-check-square"></i>');
} else {
$(
`.pageSettings .section.tags .tagsList .tag[id='${tag.id}'] .active`
`.pageSettings .section.tags .tagsList .tag[id='${tag._id}'] .active`
).html('<i class="fas fa-square"></i>');
}
});
@ -457,7 +457,7 @@ function refreshTagsSettingsSection() {
tagPbString = `PB: ${tag.pb}`;
}
tagsEl.append(`
<div class="tag" id="${tag.id}">
<div class="tag" id="${tag._id}">
<div class="active" active="${tag.active}">
<i class="fas fa-${tag.active ? "check-" : ""}square"></i>
</div>

View file

@ -7,7 +7,7 @@ export function saveActiveToLocalStorage() {
try {
DB.getSnapshot().tags.forEach((tag) => {
if (tag.active === true) {
tags.push(tag.id);
tags.push(tag._id);
}
});
// let d = new Date();
@ -23,7 +23,7 @@ export function saveActiveToLocalStorage() {
export function toggle(tagid, nosave = false) {
DB.getSnapshot().tags.forEach((tag) => {
if (tag.id === tagid) {
if (tag._id === tagid) {
if (tag.active === undefined) {
tag.active = true;
} else {

View file

@ -1298,7 +1298,7 @@ export function finish(difficultyFailed = false) {
DB.getSnapshot().tags.forEach((tag) => {
if (tag.active === true) {
activeTags.push(tag);
activeTagsIds.push(tag.id);
activeTagsIds.push(tag._id);
}
});
} catch (e) {}
@ -1466,7 +1466,7 @@ export function finish(difficultyFailed = false) {
let annotationSide = "left";
activeTags.forEach(async (tag) => {
let tpb = await DB.getLocalTagPB(
tag.id,
tag._id,
Config.mode,
mode2,
Config.punctuation,
@ -1474,13 +1474,13 @@ export function finish(difficultyFailed = false) {
Config.difficulty
);
$("#result .stats .tags .bottom").append(`
<div tagid="${tag.id}" aria-label="PB: ${tpb}" data-balloon-pos="up">${tag.name}<i class="fas fa-crown hidden"></i></div>
<div tagid="${tag._id}" aria-label="PB: ${tpb}" data-balloon-pos="up">${tag.name}<i class="fas fa-crown hidden"></i></div>
`);
if (Config.mode != "quote") {
if (tpb < stats.wpm) {
//new pb for that tag
DB.saveLocalTagPB(
tag.id,
tag._id,
Config.mode,
mode2,
Config.punctuation,
@ -1492,12 +1492,11 @@ export function finish(difficultyFailed = false) {
consistency
);
$(
`#result .stats .tags .bottom div[tagid="${tag.id}"] .fas`
`#result .stats .tags .bottom div[tagid="${tag._id}"] .fas`
).removeClass("hidden");
$(`#result .stats .tags .bottom div[tagid="${tag.id}"]`).attr(
"aria-label",
"+" + Misc.roundTo2(stats.wpm - tpb)
);
$(
`#result .stats .tags .bottom div[tagid="${tag._id}"]`
).attr("aria-label", "+" + Misc.roundTo2(stats.wpm - tpb));
// console.log("new pb for tag " + tag.name);
} else {
ChartController.result.options.annotation.annotations.push({