mirror of
https://github.com/monkeytypegame/monkeytype.git
synced 2024-11-12 02:17:21 +08:00
175 lines
4.9 KiB
JavaScript
175 lines
4.9 KiB
JavaScript
const { ObjectID } = require("mongodb");
|
|
const MonkeyError = require("../handlers/error");
|
|
const { mongoDB } = require("../init/mongodb");
|
|
const UserDAO = require("./user");
|
|
|
|
class ResultDAO {
|
|
static async addResult(uid, result) {
|
|
let user;
|
|
try {
|
|
user = await UserDAO.getUser(uid);
|
|
} catch (e) {
|
|
user = null;
|
|
}
|
|
if (!user) throw new MonkeyError(404, "User not found");
|
|
if (result.uid === undefined) result.uid = uid;
|
|
let res = await mongoDB().collection("results").insertOne(result);
|
|
return {
|
|
insertedId: res.insertedId,
|
|
};
|
|
}
|
|
|
|
static async deleteAll(uid) {
|
|
return await mongoDB().collection("results").deleteMany({ uid });
|
|
}
|
|
|
|
static async updateTags(uid, resultid, tags) {
|
|
const result = await mongoDB()
|
|
.collection("results")
|
|
.findOne({ _id: ObjectID(resultid), uid });
|
|
if (!result) throw new MonkeyError(404, "Result not found");
|
|
const userTags = await UserDAO.getTags(uid);
|
|
const userTagIds = userTags.map((tag) => tag._id.toString());
|
|
let validTags = true;
|
|
tags.forEach((tagId) => {
|
|
if (!userTagIds.includes(tagId)) validTags = false;
|
|
});
|
|
if (!validTags)
|
|
throw new MonkeyError(400, "One of the tag id's is not vaild");
|
|
return await mongoDB()
|
|
.collection("results")
|
|
.updateOne({ _id: ObjectID(resultid), uid }, { $set: { tags } });
|
|
}
|
|
|
|
static async getResult(uid, id) {
|
|
const result = await mongoDB().collection("results").findOne({ id, uid });
|
|
if (!result) throw new MonkeyError(404, "Result not found");
|
|
return result;
|
|
}
|
|
|
|
static async getResults(uid, start, end) {
|
|
start = start ?? 0;
|
|
end = end ?? 1000;
|
|
const result = await mongoDB()
|
|
.collection("results")
|
|
.find({ uid })
|
|
.sort({ timestamp: -1 })
|
|
.skip(start)
|
|
.limit(end)
|
|
.toArray(); // this needs to be changed to later take patreon into consideration
|
|
if (!result) throw new MonkeyError(404, "Result not found");
|
|
return result;
|
|
}
|
|
|
|
static async getLeaderboard(type, mode, mode2) {
|
|
let count;
|
|
let startDate = new Date();
|
|
let start = 0;
|
|
if (type == "global") count = 999;
|
|
else if (type == "daily") {
|
|
count = 100;
|
|
startDate.setUTCHours(0, 0, 0, 0); // next midnight UTC
|
|
start = startDate.getTime();
|
|
}
|
|
const leaders = await mongoDB()
|
|
.collection("results")
|
|
.aggregate([
|
|
{
|
|
$match: {
|
|
mode: mode,
|
|
mode2: parseInt(mode2),
|
|
timestamp: { $gt: start },
|
|
},
|
|
},
|
|
{ $sort: { wpm: -1 } },
|
|
{
|
|
$group: {
|
|
_id: "$name",
|
|
doc: { $first: "$$ROOT" },
|
|
},
|
|
},
|
|
{
|
|
$replaceRoot: {
|
|
newRoot: "$doc",
|
|
},
|
|
},
|
|
{ $limit: count },
|
|
])
|
|
.toArray();
|
|
let board = [];
|
|
leaders.forEach((entry) => {
|
|
board.push({
|
|
name: entry.name,
|
|
wpm: entry.wpm,
|
|
acc: entry.acc,
|
|
raw: entry.rawWpm,
|
|
consistency: entry.consistency,
|
|
mode: entry.mode,
|
|
mode2: entry.mode2,
|
|
timestamp: entry.timestamp,
|
|
});
|
|
});
|
|
board.sort((a, b) => {
|
|
return b.wpm - a.wpm;
|
|
});
|
|
let leaderboard = {
|
|
type: type,
|
|
size: board.length,
|
|
board: board,
|
|
};
|
|
if (type == "daily") {
|
|
var d = new Date();
|
|
d.setUTCHours(24, 0, 0, 0); // next midnight UTC
|
|
leaderboard.resetTime = d;
|
|
}
|
|
return leaderboard;
|
|
}
|
|
|
|
static async checkLeaderboardQualification(uid, result) {
|
|
function processLb(user, lb, result) {
|
|
let board = lb.board;
|
|
let data = {};
|
|
data.foundAt = board.indexOf(
|
|
board.find((entry) => entry.name === user.name)
|
|
);
|
|
let maxSize = 100;
|
|
if (lb.type === "global") maxSize = 999;
|
|
if (
|
|
result.wpm < board[board.length - 1].wpm &&
|
|
board.length === maxSize
|
|
) {
|
|
data.insertedAt = -1;
|
|
} else {
|
|
for (let i = board.length - 1; i > 0; i--) {
|
|
if (result.wpm < board[i].wpm) {
|
|
data.insertedAt = i + 1;
|
|
break;
|
|
}
|
|
}
|
|
if (data.insertedAt === undefined) data.insertedAt = 0;
|
|
}
|
|
return data;
|
|
}
|
|
|
|
const user = await mongoDB().collection("users").findOne({ uid: uid });
|
|
//might need to check if email is verified with firebase
|
|
if (user.emailVerified === false) return { needsToVerifyEmail: true };
|
|
if (user.name === undefined) return { noName: true };
|
|
if (user.banned) return { banned: true };
|
|
const globalLb = await this.getLeaderboard(
|
|
"global",
|
|
result.mode,
|
|
result.mode2
|
|
);
|
|
const dailyLb = await this.getLeaderboard(
|
|
"daily",
|
|
result.mode,
|
|
result.mode2
|
|
);
|
|
const globalData = processLb(user, globalLb, result);
|
|
const dailyData = processLb(user, dailyLb, result);
|
|
return { global: globalData, daily: dailyData };
|
|
}
|
|
}
|
|
|
|
module.exports = ResultDAO;
|