mirror of
https://github.com/monkeytypegame/monkeytype.git
synced 2024-11-13 19:16:51 +08:00
373 lines
10 KiB
JavaScript
373 lines
10 KiB
JavaScript
const MonkeyError = require("../handlers/error");
|
|
const { mongoDB } = require("../init/mongodb");
|
|
const { ObjectID } = require("mongodb");
|
|
const { checkAndUpdatePb } = require("../handlers/pb");
|
|
const { updateAuthEmail } = require("../handlers/auth");
|
|
const { isUsernameValid } = require("../handlers/validation");
|
|
|
|
class UsersDAO {
|
|
static async addUser(name, email, uid) {
|
|
const user = await mongoDB().collection("users").findOne({ uid });
|
|
if (user)
|
|
throw new MonkeyError(400, "User document already exists", "addUser");
|
|
return await mongoDB()
|
|
.collection("users")
|
|
.insertOne({ name, email, uid, addedAt: Date.now() });
|
|
}
|
|
|
|
static async deleteUser(uid) {
|
|
return await mongoDB().collection("users").deleteOne({ uid });
|
|
}
|
|
|
|
static async updateName(uid, name) {
|
|
const nameDoc = await mongoDB()
|
|
.collection("users")
|
|
.findOne({ name: { $regex: new RegExp(`^${name}$`, "i") } });
|
|
if (nameDoc) throw new MonkeyError(409, "Username already taken");
|
|
let user = await mongoDB().collection("users").findOne({ uid });
|
|
if (
|
|
Date.now() - user.lastNameChange < 2592000000 &&
|
|
isUsernameValid(user.name)
|
|
) {
|
|
throw new MonkeyError(409, "You can change your name once every 30 days");
|
|
}
|
|
return await mongoDB()
|
|
.collection("users")
|
|
.updateOne({ uid }, { $set: { name, lastNameChange: Date.now() } });
|
|
}
|
|
|
|
static async clearPb(uid) {
|
|
return await mongoDB()
|
|
.collection("users")
|
|
.updateOne({ uid }, { $set: { personalBests: {} } });
|
|
}
|
|
|
|
static async isNameAvailable(name) {
|
|
const nameDoc = await mongoDB().collection("users").findOne({ name });
|
|
if (nameDoc) {
|
|
return false;
|
|
} else {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
static async updateQuoteRatings(uid, quoteRatings) {
|
|
const user = await mongoDB().collection("users").findOne({ uid });
|
|
if (!user)
|
|
throw new MonkeyError(404, "User not found", "updateQuoteRatings");
|
|
await mongoDB()
|
|
.collection("users")
|
|
.updateOne({ uid }, { $set: { quoteRatings } });
|
|
return true;
|
|
}
|
|
|
|
static async updateEmail(uid, email) {
|
|
const user = await mongoDB().collection("users").findOne({ uid });
|
|
if (!user) throw new MonkeyError(404, "User not found", "update email");
|
|
await updateAuthEmail(uid, email);
|
|
await mongoDB().collection("users").updateOne({ uid }, { $set: { email } });
|
|
return true;
|
|
}
|
|
|
|
static async getUser(uid) {
|
|
const user = await mongoDB().collection("users").findOne({ uid });
|
|
if (!user) throw new MonkeyError(404, "User not found", "get user");
|
|
return user;
|
|
}
|
|
|
|
static async getUserByDiscordId(discordId) {
|
|
const user = await mongoDB().collection("users").findOne({ discordId });
|
|
if (!user)
|
|
throw new MonkeyError(404, "User not found", "get user by discord id");
|
|
return user;
|
|
}
|
|
|
|
static async addTag(uid, name) {
|
|
let _id = ObjectID();
|
|
await mongoDB()
|
|
.collection("users")
|
|
.updateOne({ uid }, { $push: { tags: { _id, name } } });
|
|
return {
|
|
_id,
|
|
name,
|
|
};
|
|
}
|
|
|
|
static async getTags(uid) {
|
|
const user = await mongoDB().collection("users").findOne({ uid });
|
|
if (!user) throw new MonkeyError(404, "User not found", "get tags");
|
|
return user.tags;
|
|
}
|
|
|
|
static async editTag(uid, _id, name) {
|
|
const user = await mongoDB().collection("users").findOne({ uid });
|
|
if (!user) throw new MonkeyError(404, "User not found", "edit tag");
|
|
if (
|
|
user.tags === undefined ||
|
|
user.tags.filter((t) => t._id == _id).length === 0
|
|
)
|
|
throw new MonkeyError(404, "Tag not found");
|
|
return await mongoDB()
|
|
.collection("users")
|
|
.updateOne(
|
|
{
|
|
uid: uid,
|
|
"tags._id": ObjectID(_id),
|
|
},
|
|
{ $set: { "tags.$.name": name } }
|
|
);
|
|
}
|
|
|
|
static async removeTag(uid, _id) {
|
|
const user = await mongoDB().collection("users").findOne({ uid });
|
|
if (!user) throw new MonkeyError(404, "User not found", "remove tag");
|
|
if (
|
|
user.tags === undefined ||
|
|
user.tags.filter((t) => t._id == _id).length === 0
|
|
)
|
|
throw new MonkeyError(404, "Tag not found");
|
|
return await mongoDB()
|
|
.collection("users")
|
|
.updateOne(
|
|
{
|
|
uid: uid,
|
|
"tags._id": ObjectID(_id),
|
|
},
|
|
{ $pull: { tags: { _id: ObjectID(_id) } } }
|
|
);
|
|
}
|
|
|
|
static async removeTagPb(uid, _id) {
|
|
const user = await mongoDB().collection("users").findOne({ uid });
|
|
if (!user) throw new MonkeyError(404, "User not found", "remove tag pb");
|
|
if (
|
|
user.tags === undefined ||
|
|
user.tags.filter((t) => t._id == _id).length === 0
|
|
)
|
|
throw new MonkeyError(404, "Tag not found");
|
|
return await mongoDB()
|
|
.collection("users")
|
|
.updateOne(
|
|
{
|
|
uid: uid,
|
|
"tags._id": ObjectID(_id),
|
|
},
|
|
{ $set: { "tags.$.personalBests": {} } }
|
|
);
|
|
}
|
|
|
|
static async updateLbMemory(uid, mode, mode2, language, rank) {
|
|
const user = await mongoDB().collection("users").findOne({ uid });
|
|
if (!user) throw new MonkeyError(404, "User not found", "update lb memory");
|
|
if (user.lbMemory === undefined) user.lbMemory = {};
|
|
if (user.lbMemory[mode] === undefined) user.lbMemory[mode] = {};
|
|
if (user.lbMemory[mode][mode2] === undefined)
|
|
user.lbMemory[mode][mode2] = {};
|
|
user.lbMemory[mode][mode2][language] = rank;
|
|
return await mongoDB()
|
|
.collection("users")
|
|
.updateOne(
|
|
{ uid },
|
|
{
|
|
$set: { lbMemory: user.lbMemory },
|
|
}
|
|
);
|
|
}
|
|
|
|
static async checkIfPb(uid, result) {
|
|
const user = await mongoDB().collection("users").findOne({ uid });
|
|
if (!user) throw new MonkeyError(404, "User not found", "check if pb");
|
|
|
|
const {
|
|
mode,
|
|
mode2,
|
|
acc,
|
|
consistency,
|
|
difficulty,
|
|
lazyMode,
|
|
language,
|
|
punctuation,
|
|
rawWpm,
|
|
wpm,
|
|
funbox,
|
|
} = result;
|
|
|
|
if (funbox !== "none" && funbox !== "plus_one" && funbox !== "plus_two") {
|
|
return false;
|
|
}
|
|
|
|
if (mode === "quote") {
|
|
return false;
|
|
}
|
|
|
|
let lbpb = user.lbPersonalBests;
|
|
if (!lbpb) lbpb = {};
|
|
|
|
let pb = checkAndUpdatePb(
|
|
user.personalBests,
|
|
lbpb,
|
|
mode,
|
|
mode2,
|
|
acc,
|
|
consistency,
|
|
difficulty,
|
|
lazyMode,
|
|
language,
|
|
punctuation,
|
|
rawWpm,
|
|
wpm
|
|
);
|
|
|
|
if (pb.isPb) {
|
|
await mongoDB()
|
|
.collection("users")
|
|
.updateOne({ uid }, { $set: { personalBests: pb.obj } });
|
|
if (pb.lbObj) {
|
|
await mongoDB()
|
|
.collection("users")
|
|
.updateOne({ uid }, { $set: { lbPersonalBests: pb.lbObj } });
|
|
}
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
static async checkIfTagPb(uid, result) {
|
|
const user = await mongoDB().collection("users").findOne({ uid });
|
|
if (!user) throw new MonkeyError(404, "User not found", "check if tag pb");
|
|
|
|
if (user.tags === undefined || user.tags.length === 0) {
|
|
return [];
|
|
}
|
|
|
|
const {
|
|
mode,
|
|
mode2,
|
|
acc,
|
|
consistency,
|
|
difficulty,
|
|
lazyMode,
|
|
language,
|
|
punctuation,
|
|
rawWpm,
|
|
wpm,
|
|
tags,
|
|
funbox,
|
|
} = result;
|
|
|
|
if (funbox !== "none" && funbox !== "plus_one" && funbox !== "plus_two") {
|
|
return [];
|
|
}
|
|
|
|
if (mode === "quote") {
|
|
return [];
|
|
}
|
|
|
|
let tagsToCheck = [];
|
|
user.tags.forEach((tag) => {
|
|
tags.forEach((resultTag) => {
|
|
if (resultTag == tag._id) {
|
|
tagsToCheck.push(tag);
|
|
}
|
|
});
|
|
});
|
|
|
|
let ret = [];
|
|
|
|
tagsToCheck.forEach(async (tag) => {
|
|
let tagpb = checkAndUpdatePb(
|
|
tag.personalBests,
|
|
undefined,
|
|
mode,
|
|
mode2,
|
|
acc,
|
|
consistency,
|
|
difficulty,
|
|
lazyMode,
|
|
language,
|
|
punctuation,
|
|
rawWpm,
|
|
wpm
|
|
);
|
|
if (tagpb.isPb) {
|
|
ret.push(tag._id);
|
|
await mongoDB()
|
|
.collection("users")
|
|
.updateOne(
|
|
{ uid, "tags._id": ObjectID(tag._id) },
|
|
{ $set: { "tags.$.personalBests": tagpb.obj } }
|
|
);
|
|
}
|
|
});
|
|
|
|
return ret;
|
|
}
|
|
|
|
static async resetPb(uid) {
|
|
const user = await mongoDB().collection("users").findOne({ uid });
|
|
if (!user) throw new MonkeyError(404, "User not found", "reset pb");
|
|
return await mongoDB()
|
|
.collection("users")
|
|
.updateOne({ uid }, { $set: { personalBests: {} } });
|
|
}
|
|
|
|
static async updateTypingStats(uid, restartCount, timeTyping) {
|
|
const user = await mongoDB().collection("users").findOne({ uid });
|
|
if (!user)
|
|
throw new MonkeyError(404, "User not found", "update typing stats");
|
|
|
|
return await mongoDB()
|
|
.collection("users")
|
|
.updateOne(
|
|
{ uid },
|
|
{
|
|
$inc: {
|
|
startedTests: restartCount + 1,
|
|
completedTests: 1,
|
|
timeTyping,
|
|
},
|
|
}
|
|
);
|
|
}
|
|
|
|
static async linkDiscord(uid, discordId) {
|
|
const user = await mongoDB().collection("users").findOne({ uid });
|
|
if (!user) throw new MonkeyError(404, "User not found", "link discord");
|
|
return await mongoDB()
|
|
.collection("users")
|
|
.updateOne({ uid }, { $set: { discordId } });
|
|
}
|
|
|
|
static async unlinkDiscord(uid) {
|
|
const user = await mongoDB().collection("users").findOne({ uid });
|
|
if (!user) throw new MonkeyError(404, "User not found", "unlink discord");
|
|
return await mongoDB()
|
|
.collection("users")
|
|
.updateOne({ uid }, { $set: { discordId: null } });
|
|
}
|
|
|
|
static async incrementBananas(uid, wpm) {
|
|
const user = await mongoDB().collection("users").findOne({ uid });
|
|
if (!user)
|
|
throw new MonkeyError(404, "User not found", "increment bananas");
|
|
|
|
let best60;
|
|
try {
|
|
best60 = Math.max(...user.personalBests.time[60].map((best) => best.wpm));
|
|
} catch (e) {
|
|
best60 = undefined;
|
|
}
|
|
|
|
if (best60 === undefined || wpm >= best60 - best60 * 0.25) {
|
|
//increment when no record found or wpm is within 25% of the record
|
|
return await mongoDB()
|
|
.collection("users")
|
|
.updateOne({ uid }, { $inc: { bananas: 1 } });
|
|
} else {
|
|
return null;
|
|
}
|
|
}
|
|
}
|
|
|
|
module.exports = UsersDAO;
|