mirror of
https://github.com/monkeytypegame/monkeytype.git
synced 2025-10-06 13:40:16 +08:00
brought back firebase analytics and authentication
This commit is contained in:
parent
b44ac814cf
commit
fd30b5aa36
34 changed files with 6247 additions and 2085 deletions
5
.firebaserc_example
Normal file
5
.firebaserc_example
Normal file
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"projects": {
|
||||
"default": "your-firebase-project-id"
|
||||
}
|
||||
}
|
|
@ -1,16 +0,0 @@
|
|||
const mongoose = require("mongoose");
|
||||
const Schema = mongoose.Schema;
|
||||
|
||||
const analyticsSchema = new Schema(
|
||||
{
|
||||
event: { type: String, required: true },
|
||||
data: { type: Schema.Types.Mixed },
|
||||
},
|
||||
{
|
||||
timestamps: true,
|
||||
}
|
||||
);
|
||||
|
||||
const Analytics = mongoose.model("Analytics", analyticsSchema);
|
||||
|
||||
module.exports = { Analytics };
|
|
@ -16,6 +16,7 @@ const userSchema = new Schema(
|
|||
zen: { type: Schema.Types.Mixed, default: {} },
|
||||
},
|
||||
name: { type: String, required: true },
|
||||
uid: { type: String, required: true },
|
||||
presets: [{ type: presetSchema, default: {} }],
|
||||
tags: [{ type: tagSchema, default: {} }],
|
||||
favouriteThemes: [],
|
||||
|
@ -40,9 +41,7 @@ const userSchema = new Schema(
|
|||
started: { type: Number, default: 0 }, //number of started tests
|
||||
completed: { type: Number, default: 0 },
|
||||
},
|
||||
email: { type: String, required: true },
|
||||
password: { type: String, required: true },
|
||||
refreshTokens: [{ type: String, required: true }],
|
||||
email: { type: String },
|
||||
config: { type: configSchema, default: {} },
|
||||
bananas: {
|
||||
t60bananas: { type: Number, default: 0 },
|
||||
|
|
|
@ -1,19 +1,15 @@
|
|||
# Todo
|
||||
|
||||
- Get google login working
|
||||
- Account data should be updated when new result is added/test completed
|
||||
- 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
|
||||
- Tags and leaderboard are still buggy
|
||||
- Creating the first tag shows error "Unknown error, cannot read property \_id of undefined"
|
||||
- Check for tag pb doesn't always work
|
||||
- Leaderboard doesn't show the time until the daily reset
|
||||
- User's Leaderboard history is not edited, and therefore distance moved on leaderboard does not work properly
|
||||
- Account data should be updated when new result is added/test completed
|
||||
- Graph bugs out when new result is added but page is not refreshed
|
||||
- Graph loops back from earliest point to the new points
|
||||
- Results list isn't updated either
|
||||
- Save config doesn't actually return data?
|
||||
|
||||
### leaderboard
|
||||
|
||||
|
@ -25,7 +21,6 @@
|
|||
|
||||
## After beta is ready
|
||||
|
||||
- Get somebody else to check over security due to my lack of expertise
|
||||
- Work on transfering data from firebase to mongo
|
||||
- Make sure that development can be done on mac and windows computers as well
|
||||
- directories in server.js might cause issues
|
||||
|
@ -33,19 +28,6 @@
|
|||
- Could reverse processing of results, but that would add more complexity to code
|
||||
- Figure out why if (page == "account") pageTransition = false; gets rid of endless account loading bug when accessing via url
|
||||
|
||||
### Analytics / Admin panel
|
||||
|
||||
- Create admin panel or public stats page to make use of analytics data
|
||||
- What data needs to be in the analytics table
|
||||
- New Account, sessions, number of tests started, which tests people take and how fast they are taking them
|
||||
- Things like theme, popular languages, etc can be derived from user models
|
||||
- Wouldn't be able to see change over time if you went with this method
|
||||
- Could check and save once a day
|
||||
- Could use google analytics for easy data analysis
|
||||
- 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?
|
||||
|
||||
## User transfer
|
||||
|
||||
- Create a script to pull all data from monkeytype and move it to the new mongo server
|
||||
|
|
|
@ -1,39 +1,29 @@
|
|||
require("dotenv").config();
|
||||
const express = require("express");
|
||||
const bodyParser = require("body-parser");
|
||||
const mongoose = require("mongoose");
|
||||
const jwt = require("jsonwebtoken");
|
||||
const nodemailer = require("nodemailer");
|
||||
const bcrypt = require("bcrypt");
|
||||
const saltRounds = 10;
|
||||
const cors = require("cors");
|
||||
const admin = require("firebase-admin");
|
||||
const { User } = require("./models/user");
|
||||
const { Analytics } = require("./models/analytics");
|
||||
const { Leaderboard } = require("./models/leaderboard");
|
||||
|
||||
// Firebase admin setup
|
||||
//currently uses account key in functions to prevent repetition
|
||||
const serviceAccount = require("../functions/serviceAccountKey.json");
|
||||
|
||||
admin.initializeApp({
|
||||
credential: admin.credential.cert(serviceAccount),
|
||||
});
|
||||
// MIDDLEWARE & SETUP
|
||||
|
||||
const app = express();
|
||||
app.use(cors());
|
||||
|
||||
const port = process.env.PORT || "5000";
|
||||
const port = process.env.PORT || "5005";
|
||||
|
||||
mongoose.connect("mongodb://localhost:27017/monkeytype", {
|
||||
useNewUrlParser: true,
|
||||
useUnifiedTopology: true,
|
||||
});
|
||||
|
||||
let transporter = nodemailer.createTransport({
|
||||
service: "gmail",
|
||||
auth: {
|
||||
//should use OAuth in production
|
||||
//type: 'OAuth2',
|
||||
user: process.env.MAIL_ADDRESS,
|
||||
pass: process.env.MAIL_PASSWORD,
|
||||
//clientId: process.env.OAUTH_CLIENTID,
|
||||
//clientSecret: process.env.OAUTH_CLIENT_SECRET,
|
||||
//refreshToken: process.env.OAUTH_REFRESH_TOKEN
|
||||
},
|
||||
});
|
||||
|
||||
const mtRootDir = __dirname.substring(0, __dirname.length - 8); //will this work for windows and mac computers?
|
||||
app.use(express.static(mtRootDir + "/dist"));
|
||||
app.use(bodyParser.json());
|
||||
|
@ -78,16 +68,18 @@ Leaderboard.findOne((err, lb) => {
|
|||
clearDailyLeaderboards();
|
||||
});
|
||||
|
||||
function authenticateToken(req, res, next) {
|
||||
async function authenticateToken(req, res, next) {
|
||||
const authHeader = req.headers["authorization"];
|
||||
const token = authHeader && authHeader.split(" ")[1];
|
||||
if (token == null) return res.sendStatus(401);
|
||||
|
||||
jwt.verify(token, process.env.ACCESS_TOKEN_SECRET, (err, identity) => {
|
||||
if (err) return res.sendStatus(403);
|
||||
req.name = identity.name;
|
||||
const token = await admin
|
||||
.auth()
|
||||
.verifyIdToken(req.headers.authorization.split(" ")[1]);
|
||||
if (token == null) {
|
||||
return res.sendStatus(401);
|
||||
} else {
|
||||
req.name = token.name;
|
||||
req.uid = token.user_id;
|
||||
next();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// NON-ROUTE FUNCTIONS
|
||||
|
@ -174,7 +166,7 @@ async function checkIfPB(obj, userdata) {
|
|||
throw new Error("pb is undefined");
|
||||
}
|
||||
} catch (e) {
|
||||
User.findOne({ name: userdata.name }, (err, user) => {
|
||||
User.findOne({ uid: userdata.uid }, (err, user) => {
|
||||
user.personalBests = {
|
||||
[obj.mode]: {
|
||||
[obj.mode2]: [
|
||||
|
@ -260,7 +252,7 @@ async function checkIfPB(obj, userdata) {
|
|||
}
|
||||
|
||||
if (toUpdate) {
|
||||
User.findOne({ name: userdata.name }, (err, user) => {
|
||||
User.findOne({ uid: userdata.uid }, (err, user) => {
|
||||
user.personalBests = pbs;
|
||||
user.save();
|
||||
});
|
||||
|
@ -282,7 +274,7 @@ async function checkIfTagPB(obj, userdata) {
|
|||
let restags = obj.tags; //result tags
|
||||
try {
|
||||
let snap;
|
||||
await User.findOne({ name: userdata.name }, (err, user) => {
|
||||
await User.findOne({ uid: userdata.uid }, (err, user) => {
|
||||
snap = user.tags;
|
||||
});
|
||||
snap.forEach((doc) => {
|
||||
|
@ -312,7 +304,7 @@ async function checkIfTagPB(obj, userdata) {
|
|||
} catch (e) {
|
||||
console.log("PBs undefined");
|
||||
//undefined personal best = new personal best
|
||||
await User.findOne({ name: userdata.name }, (err, user) => {
|
||||
await User.findOne({ uid: userdata.uid }, (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]);
|
||||
|
@ -407,7 +399,7 @@ async function checkIfTagPB(obj, userdata) {
|
|||
|
||||
if (toUpdate) {
|
||||
console.log("Adding new pb at end");
|
||||
await User.findOne({ name: userdata.name }, (err, user) => {
|
||||
await User.findOne({ uid: userdata.uid }, (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]);
|
||||
|
@ -426,7 +418,7 @@ async function checkIfTagPB(obj, userdata) {
|
|||
return ret;
|
||||
}
|
||||
|
||||
async function stripAndSave(username, obj) {
|
||||
async function stripAndSave(uid, obj) {
|
||||
if (obj.bailedOut === false) delete obj.bailedOut;
|
||||
if (obj.blindMode === false) delete obj.blindMode;
|
||||
if (obj.difficulty === "normal") delete obj.difficulty;
|
||||
|
@ -438,13 +430,13 @@ async function stripAndSave(username, obj) {
|
|||
if (obj.numbers === false) delete obj.numbers;
|
||||
if (obj.punctuation === false) delete obj.punctuation;
|
||||
|
||||
await User.findOne({ name: username }, (err, user) => {
|
||||
await User.findOne({ uid: uid }, (err, user) => {
|
||||
user.results.push(obj);
|
||||
user.save();
|
||||
});
|
||||
}
|
||||
|
||||
function incrementT60Bananas(username, result, userData) {
|
||||
function incrementT60Bananas(uid, result, userData) {
|
||||
try {
|
||||
let best60;
|
||||
try {
|
||||
|
@ -464,7 +456,7 @@ function incrementT60Bananas(username, result, userData) {
|
|||
} else {
|
||||
//increment
|
||||
// console.log("checking");
|
||||
User.findOne({ name: username }, (err, user) => {
|
||||
User.findOne({ uid: uid }, (err, user) => {
|
||||
if (user.bananas === undefined) {
|
||||
user.bananas.t60bananas = 1;
|
||||
} else {
|
||||
|
@ -524,7 +516,7 @@ async function incrementGlobalTypingStats(userData, resultObj) {
|
|||
// timeTyping: roundTo2(newTime),
|
||||
// });
|
||||
incrementPublicTypingStats(resultObj.restartCount + 1, 1, tt);
|
||||
User.findOne({ name: userData.name }, (err, user) => {
|
||||
User.findOne({ uid: userData.uid }, (err, user) => {
|
||||
user.globalStats = {
|
||||
started: newStarted,
|
||||
completed: newCompleted,
|
||||
|
@ -538,8 +530,6 @@ async function incrementGlobalTypingStats(userData, resultObj) {
|
|||
}
|
||||
|
||||
async function incrementPublicTypingStats(started, completed, time) {
|
||||
//maybe this should be added to analytics
|
||||
//analytics should be able to track usage over time and show a graph
|
||||
/*
|
||||
try {
|
||||
time = roundTo2(time);
|
||||
|
@ -562,8 +552,54 @@ function isTagPresetNameValid(name) {
|
|||
return /^[0-9a-zA-Z_.-]+$/.test(name);
|
||||
}
|
||||
|
||||
function isUsernameValid(name) {
|
||||
if (name === null || name === undefined || name === "") return false;
|
||||
if (/miodec/.test(name.toLowerCase())) return false;
|
||||
if (/bitly/.test(name.toLowerCase())) return false;
|
||||
if (name.length > 14) return false;
|
||||
if (/^\..*/.test(name.toLowerCase())) return false;
|
||||
return /^[0-9a-zA-Z_.-]+$/.test(name);
|
||||
}
|
||||
|
||||
// API
|
||||
|
||||
app.get("/api/nameCheck/:name", (req, res) => {
|
||||
if (!isUsernameValid(req.params.name)) {
|
||||
res.status(200).send({
|
||||
resultCode: -2,
|
||||
message: "Username is not valid",
|
||||
});
|
||||
return;
|
||||
}
|
||||
User.findOne({ name: req.params.name }, (err, user) => {
|
||||
if (user) {
|
||||
res.status(200).send({
|
||||
resultCode: -1,
|
||||
message: "Username is taken",
|
||||
});
|
||||
return;
|
||||
} else {
|
||||
res.status(200).send({
|
||||
resultCode: 1,
|
||||
message: "Username is available",
|
||||
});
|
||||
return;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
app.post("/api/signUp", (req, res) => {
|
||||
const newuser = new User({
|
||||
name: req.body.name,
|
||||
email: req.body.email,
|
||||
uid: req.body.uid,
|
||||
});
|
||||
newuser.save();
|
||||
res.status(200);
|
||||
res.json({ user: newuser });
|
||||
return;
|
||||
});
|
||||
|
||||
app.post("/api/updateName", (req, res) => {
|
||||
//this might be a put/patch request
|
||||
//update the name of user with given uid
|
||||
|
@ -571,177 +607,6 @@ app.post("/api/updateName", (req, res) => {
|
|||
const name = req.body.name;
|
||||
});
|
||||
|
||||
function sendVerificationEmail(username, email) {
|
||||
const host = "localhost:5000";
|
||||
const hash = Math.random().toString(16).substr(2, 12);
|
||||
const link = `http://${host}/verifyEmail?name=${username}&hash=${hash}`;
|
||||
User.findOne({ name: username }, (err, user) => {
|
||||
user.verificationHashes.push(hash);
|
||||
user.save();
|
||||
});
|
||||
const mailOptions = {
|
||||
from: process.env.MAIL_ADDRESS,
|
||||
to: email,
|
||||
subject: "Monkeytype User Verification",
|
||||
text: `Hello ${username},\nFollow this link to verify your email address:\n${link}\nIf you didn’t ask to verify this address, you can ignore this email.\nThanks,\nYour monkeytype team`,
|
||||
};
|
||||
|
||||
transporter.sendMail(mailOptions, function (error, info) {
|
||||
if (error) {
|
||||
console.log(error);
|
||||
} else {
|
||||
console.log("Email sent: " + info.response);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
app.get("/verifyEmail", (req, res) => {
|
||||
let success = false;
|
||||
User.findOne({ name: req.query.name }, (err, user) => {
|
||||
if (user.verificationHashes.includes(req.query.hash)) {
|
||||
success = true;
|
||||
user.verificationHashes = [];
|
||||
user.verified = true;
|
||||
user.emailVerified = true;
|
||||
user.save();
|
||||
}
|
||||
}).then(() => {
|
||||
if (success) {
|
||||
res.send(
|
||||
"<h3>Email verified successfully</h3><p>Go back to <a href='https://monkeytype.com'>monkeytype</a></p>"
|
||||
);
|
||||
} else {
|
||||
res.send(
|
||||
"<h3>Email verification failed</h3><p>Go back to <a href='https://monkeytype.com'>monkeytype</a></p>"
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
app.post("/api/sendEmailVerification", authenticateToken, (req, res) => {
|
||||
User.findOne({ name: req.name }, (err, user) => {
|
||||
sendVerificationEmail(req.name, user.email);
|
||||
});
|
||||
res.sendStatus(200);
|
||||
});
|
||||
|
||||
app.post("/api/signIn", (req, res) => {
|
||||
/* Takes email and password */
|
||||
//Login and send tokens
|
||||
User.findOne({ email: req.body.email }, (err, user) => {
|
||||
if (err) res.status(500).send({ error: err });
|
||||
if (user === null) {
|
||||
res.status(500).send({ error: "No user found with that email" });
|
||||
return;
|
||||
}
|
||||
bcrypt.compare(req.body.password, user.password, (err, result) => {
|
||||
if (err)
|
||||
res.status(500).send({ error: "Error during password validation" });
|
||||
if (result) {
|
||||
//if password matches hash
|
||||
const accessToken = jwt.sign(
|
||||
{ name: user.name },
|
||||
process.env.ACCESS_TOKEN_SECRET
|
||||
);
|
||||
const refreshToken = jwt.sign(
|
||||
{ name: user.name },
|
||||
process.env.REFRESH_TOKEN_SECRET
|
||||
);
|
||||
user.refreshTokens.push(refreshToken);
|
||||
user.save();
|
||||
const retUser = {
|
||||
uid: user._id,
|
||||
name: user.name,
|
||||
email: user.email,
|
||||
emailVerified: user.emailVerified,
|
||||
metadata: { creationTime: user.createdAt },
|
||||
};
|
||||
res.json({
|
||||
accessToken: accessToken,
|
||||
refreshToken: refreshToken,
|
||||
user: retUser,
|
||||
});
|
||||
} else {
|
||||
//if password doesn't match hash
|
||||
res.status(500).send({ error: "Password invalid" });
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
app.post("/api/signUp", (req, res) => {
|
||||
/* Takes name, email, password */
|
||||
//check if name has been taken
|
||||
User.exists({ name: req.body.name }).then((exists) => {
|
||||
//should also check if email is used
|
||||
if (exists) {
|
||||
//user with that name already exists
|
||||
res.status(500).send({ error: "Username taken" });
|
||||
}
|
||||
bcrypt.hash(req.body.password, saltRounds, function (err, hash) {
|
||||
if (err) console.log(err);
|
||||
const newuser = new User({
|
||||
name: req.body.name,
|
||||
email: req.body.email,
|
||||
emailVerified: false,
|
||||
password: hash,
|
||||
});
|
||||
newuser
|
||||
.save()
|
||||
.then((user) => {
|
||||
//send email verification
|
||||
sendVerificationEmail(user.name, user.email);
|
||||
//add account created event to analytics
|
||||
|
||||
//return user data and access token
|
||||
const accessToken = jwt.sign(
|
||||
{ name: req.body.name },
|
||||
process.env.ACCESS_TOKEN_SECRET
|
||||
);
|
||||
const refreshToken = jwt.sign(
|
||||
{ name: user.name },
|
||||
process.env.REFRESH_TOKEN_SECRET
|
||||
);
|
||||
user.refreshTokens.push(refreshToken);
|
||||
user.save();
|
||||
const retUser = {
|
||||
uid: user._id,
|
||||
name: user.name,
|
||||
email: user.email,
|
||||
emailVerified: user.emailVerified,
|
||||
metadata: { creationTime: user.createdAt },
|
||||
};
|
||||
res.json({
|
||||
accessToken: accessToken,
|
||||
refreshToken: refreshToken,
|
||||
user: retUser,
|
||||
});
|
||||
})
|
||||
.catch((e) => {
|
||||
console.log(e);
|
||||
res.status(500).send({ error: "Error when adding user" });
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
app.post("/api/refreshToken", (req, res) => {
|
||||
const authHeader = req.headers["authorization"];
|
||||
const token = authHeader && authHeader.split(" ")[1];
|
||||
if (token == null) return res.sendStatus(401);
|
||||
jwt.verify(token, process.env.ACCESS_TOKEN_SECRET, (err, identity) => {
|
||||
if (err) return res.sendStatus(403);
|
||||
User.findOne({ name: identity.name }, (err, user) => {
|
||||
if (!user.refreshTokens.includes(token)) return res.sendStatus(403);
|
||||
const accessToken = jwt.sign(
|
||||
{ name: identity.name },
|
||||
process.env.ACCESS_TOKEN_SECRET
|
||||
);
|
||||
res.json({ accessToken: accessToken });
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
app.post("/api/passwordReset", (req, res) => {
|
||||
const email = req.body.email;
|
||||
//send email to the passed email requesting password reset
|
||||
|
@ -750,13 +615,15 @@ app.post("/api/passwordReset", (req, res) => {
|
|||
|
||||
app.get("/api/fetchSnapshot", authenticateToken, (req, res) => {
|
||||
/* Takes token and returns snap */
|
||||
User.findOne({ name: req.name }, (err, user) => {
|
||||
console.log("UID: " + req.uid);
|
||||
User.findOne({ uid: req.uid }, (err, user) => {
|
||||
if (err) res.status(500).send({ error: err });
|
||||
if (!user) res.status(200).send({ message: "No user found" }); //client doesn't do anything with this
|
||||
//populate snap object with data from user document
|
||||
let snap = user;
|
||||
delete snap.password;
|
||||
//return user data
|
||||
res.send({ snap: snap });
|
||||
return;
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -769,10 +636,7 @@ function stdDev(array) {
|
|||
}
|
||||
|
||||
app.post("/api/testCompleted", authenticateToken, (req, res) => {
|
||||
//return createdId
|
||||
//return user data
|
||||
//this is actually REALLY hard
|
||||
User.findOne({ name: req.name }, (err, user) => {
|
||||
User.findOne({ uid: req.uid }, (err, user) => {
|
||||
if (err) res.status(500).send({ error: err });
|
||||
request = req.body;
|
||||
if (request === undefined) {
|
||||
|
@ -780,7 +644,7 @@ app.post("/api/testCompleted", authenticateToken, (req, res) => {
|
|||
return;
|
||||
}
|
||||
try {
|
||||
if (req.name === undefined || request.obj === undefined) {
|
||||
if (req.uid === undefined || request.obj === undefined) {
|
||||
console.error(`error saving result for - missing input`);
|
||||
res.status(200).send({ data: { resultCode: -999 } });
|
||||
return;
|
||||
|
@ -790,7 +654,7 @@ app.post("/api/testCompleted", authenticateToken, (req, res) => {
|
|||
|
||||
if (obj.incompleteTestSeconds > 500)
|
||||
console.log(
|
||||
`FUCK, HIGH INCOMPLETE TEST SECONDS ${req.name}: ${JSON.stringify(
|
||||
`FUCK, HIGH INCOMPLETE TEST SECONDS ${req.uid}: ${JSON.stringify(
|
||||
obj
|
||||
)}`
|
||||
);
|
||||
|
@ -817,7 +681,7 @@ app.post("/api/testCompleted", authenticateToken, (req, res) => {
|
|||
if (errCount > 0) {
|
||||
console.error(
|
||||
`error saving result for ${
|
||||
req.name
|
||||
req.uid
|
||||
} error count ${errCount} - bad input - ${JSON.stringify(
|
||||
request.obj
|
||||
)}`
|
||||
|
@ -896,7 +760,7 @@ app.post("/api/testCompleted", authenticateToken, (req, res) => {
|
|||
};
|
||||
} catch (e) {
|
||||
console.error(
|
||||
`cant verify key spacing or duration for user ${req.name}! - ${e} - ${obj.keySpacing} ${obj.keyDuration}`
|
||||
`cant verify key spacing or duration for user ${req.uid}! - ${e} - ${obj.keySpacing} ${obj.keyDuration}`
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -911,7 +775,7 @@ app.post("/api/testCompleted", authenticateToken, (req, res) => {
|
|||
|
||||
// emailVerified = await admin
|
||||
// .auth()
|
||||
// .getUser(req.name)
|
||||
// .getUser(req.uid)
|
||||
// .then((user) => {
|
||||
// return user.emailVerified;
|
||||
// });
|
||||
|
@ -956,7 +820,7 @@ app.post("/api/testCompleted", authenticateToken, (req, res) => {
|
|||
console.error(
|
||||
`very close to bot detected threshold by user (${obj.wpm} ${
|
||||
obj.rawWpm
|
||||
} ${obj.acc}) ${req.name} ${name} - spacing ${JSON.stringify(
|
||||
} ${obj.acc}) ${req.uid} ${name} - spacing ${JSON.stringify(
|
||||
keySpacing
|
||||
)} duration ${JSON.stringify(keyDuration)}`
|
||||
);
|
||||
|
@ -979,7 +843,7 @@ app.post("/api/testCompleted", authenticateToken, (req, res) => {
|
|||
} catch (e) {}
|
||||
|
||||
// return db
|
||||
// .collection(`users/${req.name}/results`)
|
||||
// .collection(`users/${req.uid}/results`)
|
||||
// .add(obj)
|
||||
// .then((e) => {
|
||||
|
||||
|
@ -1012,7 +876,7 @@ app.post("/api/testCompleted", authenticateToken, (req, res) => {
|
|||
// console.log(values);
|
||||
|
||||
if (obj.mode === "time" && String(obj.mode2) === "60") {
|
||||
incrementT60Bananas(req.name, obj, userdata);
|
||||
incrementT60Bananas(req.uid, obj, userdata);
|
||||
}
|
||||
|
||||
await incrementGlobalTypingStats(userdata, obj);
|
||||
|
@ -1032,9 +896,7 @@ app.post("/api/testCompleted", authenticateToken, (req, res) => {
|
|||
logobj.keySpacing = "removed";
|
||||
logobj.keyDuration = "removed";
|
||||
console.log(
|
||||
`saved result for ${req.name} (new PB) - ${JSON.stringify(
|
||||
logobj
|
||||
)}`
|
||||
`saved result for ${req.uid} (new PB) - ${JSON.stringify(logobj)}`
|
||||
);
|
||||
/*
|
||||
User.findOne({ name: userdata.name }, (err, user2) => {
|
||||
|
@ -1053,7 +915,7 @@ app.post("/api/testCompleted", authenticateToken, (req, res) => {
|
|||
) {
|
||||
if (verified !== false) {
|
||||
console.log(
|
||||
`sending command to the bot to update the role for user ${req.name} with wpm ${obj.wpm}`
|
||||
`sending command to the bot to update the role for user ${req.uid} with wpm ${obj.wpm}`
|
||||
);
|
||||
updateDiscordRole(userdata.discordId, Math.round(obj.wpm));
|
||||
}
|
||||
|
@ -1065,17 +927,17 @@ app.post("/api/testCompleted", authenticateToken, (req, res) => {
|
|||
logobj.keyDuration = "removed";
|
||||
request.obj.isPb = false;
|
||||
console.log(
|
||||
`saved result for ${req.name} - ${JSON.stringify(logobj)}`
|
||||
`saved result for ${req.uid} - ${JSON.stringify(logobj)}`
|
||||
);
|
||||
returnobj.resultCode = 1;
|
||||
}
|
||||
stripAndSave(req.name, request.obj);
|
||||
stripAndSave(req.uid, request.obj);
|
||||
res.status(200).send({ data: returnobj });
|
||||
return;
|
||||
})
|
||||
.catch((e) => {
|
||||
console.error(
|
||||
`error saving result when checking for PB / checking leaderboards for ${req.name} - ${e.message}`
|
||||
`error saving result when checking for PB / checking leaderboards for ${req.uid} - ${e.message}`
|
||||
);
|
||||
res
|
||||
.status(200)
|
||||
|
@ -1084,7 +946,7 @@ app.post("/api/testCompleted", authenticateToken, (req, res) => {
|
|||
});
|
||||
} catch (e) {
|
||||
console.error(
|
||||
`error saving result for ${req.name} - ${JSON.stringify(
|
||||
`error saving result for ${req.uid} - ${JSON.stringify(
|
||||
request.obj
|
||||
)} - ${e}`
|
||||
);
|
||||
|
@ -1095,7 +957,7 @@ app.post("/api/testCompleted", authenticateToken, (req, res) => {
|
|||
});
|
||||
|
||||
app.get("/api/userResults", authenticateToken, (req, res) => {
|
||||
User.findOne({ name: req.name }, (err, user) => {
|
||||
User.findOne({ uid: req.uid }, (err, user) => {
|
||||
if (err) res.status(500).send({ error: err });
|
||||
});
|
||||
//return list of results
|
||||
|
@ -1110,8 +972,8 @@ function isConfigKeyValid(name) {
|
|||
|
||||
app.post("/api/saveConfig", authenticateToken, (req, res) => {
|
||||
try {
|
||||
if (req.name === undefined || req.body.obj === undefined) {
|
||||
console.error(`error saving config for ${req.name} - missing input`);
|
||||
if (req.uid === undefined || req.body.obj === undefined) {
|
||||
console.error(`error saving config for ${req.uid} - missing input`);
|
||||
return {
|
||||
resultCode: -1,
|
||||
message: "Missing input",
|
||||
|
@ -1150,7 +1012,7 @@ app.post("/api/saveConfig", authenticateToken, (req, res) => {
|
|||
});
|
||||
if (err) {
|
||||
console.error(
|
||||
`error saving config for ${req.name} - bad input - ${JSON.stringify(
|
||||
`error saving config for ${req.uid} - bad input - ${JSON.stringify(
|
||||
request.obj
|
||||
)}`
|
||||
);
|
||||
|
@ -1160,7 +1022,7 @@ app.post("/api/saveConfig", authenticateToken, (req, res) => {
|
|||
};
|
||||
}
|
||||
|
||||
User.findOne({ name: req.name }, (err, user) => {
|
||||
User.findOne({ uid: req.uid }, (err, user) => {
|
||||
if (err) res.status(500).send({ error: err });
|
||||
user.config = obj;
|
||||
//what does {merge: true} do in firebase
|
||||
|
@ -1174,7 +1036,7 @@ app.post("/api/saveConfig", authenticateToken, (req, res) => {
|
|||
})
|
||||
.catch((e) => {
|
||||
console.error(
|
||||
`error saving config to DB for ${req.name} - ${e.message}`
|
||||
`error saving config to DB for ${req.uid} - ${e.message}`
|
||||
);
|
||||
return {
|
||||
resultCode: -1,
|
||||
|
@ -1182,7 +1044,7 @@ app.post("/api/saveConfig", authenticateToken, (req, res) => {
|
|||
};
|
||||
});
|
||||
} catch (e) {
|
||||
console.error(`error saving config for ${req.name} - ${e}`);
|
||||
console.error(`error saving config for ${req.uid} - ${e}`);
|
||||
return {
|
||||
resultCode: -999,
|
||||
message: e,
|
||||
|
@ -1194,8 +1056,8 @@ app.post("/api/addPreset", authenticateToken, (req, res) => {
|
|||
try {
|
||||
if (!isTagPresetNameValid(req.body.obj.name)) {
|
||||
return { resultCode: -1 };
|
||||
} else if (req.name === undefined || req.body.obj === undefined) {
|
||||
console.error(`error saving config for ${req.name} - missing input`);
|
||||
} else if (req.uid === undefined || req.body.obj === undefined) {
|
||||
console.error(`error saving config for ${req.uid} - missing input`);
|
||||
res.json({
|
||||
resultCode: -1,
|
||||
message: "Missing input",
|
||||
|
@ -1233,7 +1095,7 @@ app.post("/api/addPreset", authenticateToken, (req, res) => {
|
|||
});
|
||||
if (err) {
|
||||
console.error(
|
||||
`error adding preset for ${req.name} - bad input - ${JSON.stringify(
|
||||
`error adding preset for ${req.uid} - bad input - ${JSON.stringify(
|
||||
req.body.obj
|
||||
)}`
|
||||
);
|
||||
|
@ -1243,7 +1105,7 @@ app.post("/api/addPreset", authenticateToken, (req, res) => {
|
|||
});
|
||||
}
|
||||
|
||||
User.findOne({ name: req.name }, (err, user) => {
|
||||
User.findOne({ uid: req.uid }, (err, user) => {
|
||||
if (user.presets.length >= 10) {
|
||||
res.json({
|
||||
resultCode: -2,
|
||||
|
@ -1263,7 +1125,7 @@ app.post("/api/addPreset", authenticateToken, (req, res) => {
|
|||
})
|
||||
.catch((e) => {
|
||||
console.error(
|
||||
`error adding preset to DB for ${req.name} - ${e.message}`
|
||||
`error adding preset to DB for ${req.uid} - ${e.message}`
|
||||
);
|
||||
res.json({
|
||||
resultCode: -1,
|
||||
|
@ -1272,7 +1134,7 @@ app.post("/api/addPreset", authenticateToken, (req, res) => {
|
|||
});
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(`error adding preset for ${req.name} - ${e}`);
|
||||
console.error(`error adding preset for ${req.uid} - ${e}`);
|
||||
res.json({
|
||||
resultCode: -999,
|
||||
message: e,
|
||||
|
@ -1285,7 +1147,7 @@ app.post("/api/editPreset", authenticateToken, (req, res) => {
|
|||
if (!isTagPresetNameValid(req.body.presetName)) {
|
||||
return { resultCode: -1 };
|
||||
} else {
|
||||
User.findOne({ name: req.name }, (err, user) => {
|
||||
User.findOne({ uid: req.uid }, (err, user) => {
|
||||
for (i = 0; i < user.presets.length; i++) {
|
||||
if (user.presets[i]._id.toString() == req.body.presetid.toString()) {
|
||||
user.presets[i] = {
|
||||
|
@ -1299,7 +1161,7 @@ app.post("/api/editPreset", authenticateToken, (req, res) => {
|
|||
})
|
||||
.then((e) => {
|
||||
console.log(
|
||||
`user ${req.name} updated a preset: ${req.body.presetName}`
|
||||
`user ${req.uid} updated a preset: ${req.body.presetName}`
|
||||
);
|
||||
res.send({
|
||||
resultCode: 1,
|
||||
|
@ -1307,20 +1169,20 @@ app.post("/api/editPreset", authenticateToken, (req, res) => {
|
|||
})
|
||||
.catch((e) => {
|
||||
console.error(
|
||||
`error while updating preset for user ${req.name}: ${e.message}`
|
||||
`error while updating preset for user ${req.uid}: ${e.message}`
|
||||
);
|
||||
res.send({ resultCode: -999, message: e.message });
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(`error updating preset for ${req.name} - ${e}`);
|
||||
console.error(`error updating preset for ${req.uid} - ${e}`);
|
||||
return { resultCode: -999, message: e.message };
|
||||
}
|
||||
});
|
||||
|
||||
app.post("/api/removePreset", authenticateToken, (req, res) => {
|
||||
try {
|
||||
User.findOne({ name: req.name }, (err, user) => {
|
||||
User.findOne({ uid: req.uid }, (err, user) => {
|
||||
for (i = 0; i < user.presets.length; i++) {
|
||||
if (user.presets[i]._id.toString() == req.body.presetid.toString()) {
|
||||
user.presets.splice(i, 1);
|
||||
|
@ -1330,17 +1192,17 @@ app.post("/api/removePreset", authenticateToken, (req, res) => {
|
|||
user.save();
|
||||
})
|
||||
.then((e) => {
|
||||
console.log(`user ${req.name} deleted a preset`);
|
||||
console.log(`user ${req.uid} deleted a preset`);
|
||||
res.send({ resultCode: 1 });
|
||||
})
|
||||
.catch((e) => {
|
||||
console.error(
|
||||
`error deleting preset for user ${req.name}: ${e.message}`
|
||||
`error deleting preset for user ${req.uid}: ${e.message}`
|
||||
);
|
||||
res.send({ resultCode: -999 });
|
||||
});
|
||||
} catch (e) {
|
||||
console.error(`error deleting preset for ${req.name} - ${e}`);
|
||||
console.error(`error deleting preset for ${req.uid} - ${e}`);
|
||||
res.send({ resultCode: -999 });
|
||||
}
|
||||
});
|
||||
|
@ -1355,7 +1217,7 @@ function isTagPresetNameValid(name) {
|
|||
app.post("/api/addTag", authenticateToken, (req, res) => {
|
||||
try {
|
||||
if (!isTagPresetNameValid(req.body.tagName)) return { resultCode: -1 };
|
||||
User.findOne({ name: req.name }, (err, user) => {
|
||||
User.findOne({ uid: req.uid }, (err, user) => {
|
||||
if (err) res.status(500).send({ error: err });
|
||||
if (user.tags.includes(req.body.tagName)) {
|
||||
return { resultCode: -999, message: "Duplicate tag" };
|
||||
|
@ -1365,7 +1227,7 @@ app.post("/api/addTag", authenticateToken, (req, res) => {
|
|||
user.save();
|
||||
})
|
||||
.then((updatedUser) => {
|
||||
console.log(`user ${req.name} created a tag: ${req.body.tagName}`);
|
||||
console.log(`user ${req.uid} created a tag: ${req.body.tagName}`);
|
||||
res.json({
|
||||
resultCode: 1,
|
||||
id: updatedUser.tags[updatedUser.tags.length - 1]._id,
|
||||
|
@ -1373,12 +1235,12 @@ app.post("/api/addTag", authenticateToken, (req, res) => {
|
|||
})
|
||||
.catch((e) => {
|
||||
console.error(
|
||||
`error while creating tag for user ${req.name}: ${e.message}`
|
||||
`error while creating tag for user ${req.uid}: ${e.message}`
|
||||
);
|
||||
res.json({ resultCode: -999, message: e.message });
|
||||
});
|
||||
} catch (e) {
|
||||
console.error(`error adding tag for ${req.name} - ${e}`);
|
||||
console.error(`error adding tag for ${req.uid} - ${e}`);
|
||||
res.json({ resultCode: -999, message: e.message });
|
||||
}
|
||||
});
|
||||
|
@ -1386,7 +1248,7 @@ app.post("/api/addTag", authenticateToken, (req, res) => {
|
|||
app.post("/api/editTag", authenticateToken, (req, res) => {
|
||||
try {
|
||||
if (!isTagPresetNameValid(req.body.tagName)) return { resultCode: -1 };
|
||||
User.findOne({ name: req.name }, (err, user) => {
|
||||
User.findOne({ uid: req.uid }, (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) {
|
||||
|
@ -1396,24 +1258,24 @@ app.post("/api/editTag", authenticateToken, (req, res) => {
|
|||
user.save();
|
||||
})
|
||||
.then((updatedUser) => {
|
||||
console.log(`user ${req.name} updated a tag: ${req.name}`);
|
||||
console.log(`user ${req.uid} updated a tag: ${req.body.tagName}`);
|
||||
res.json({ resultCode: 1 });
|
||||
})
|
||||
.catch((e) => {
|
||||
console.error(
|
||||
`error while updating tag for user ${req.name}: ${e.message}`
|
||||
`error while updating tag for user ${req.uid}: ${e.message}`
|
||||
);
|
||||
res.json({ resultCode: -999, message: e.message });
|
||||
});
|
||||
} catch (e) {
|
||||
console.error(`error updating tag for ${req.name} - ${e}`);
|
||||
console.error(`error updating tag for ${req.uid} - ${e}`);
|
||||
res.json({ resultCode: -999, message: e.message });
|
||||
}
|
||||
});
|
||||
|
||||
app.post("/api/removeTag", authenticateToken, (req, res) => {
|
||||
try {
|
||||
User.findOne({ name: req.name }, (err, user) => {
|
||||
User.findOne({ uid: req.uid }, (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) {
|
||||
|
@ -1423,22 +1285,22 @@ app.post("/api/removeTag", authenticateToken, (req, res) => {
|
|||
user.save();
|
||||
})
|
||||
.then((updatedUser) => {
|
||||
console.log(`user ${req.name} deleted a tag`);
|
||||
console.log(`user ${req.uid} deleted a tag`);
|
||||
res.json({ resultCode: 1 });
|
||||
})
|
||||
.catch((e) => {
|
||||
console.error(`error deleting tag for user ${req.name}: ${e.message}`);
|
||||
console.error(`error deleting tag for user ${req.uid}: ${e.message}`);
|
||||
res.json({ resultCode: -999 });
|
||||
});
|
||||
} catch (e) {
|
||||
console.error(`error deleting tag for ${req.name} - ${e}`);
|
||||
console.error(`error deleting tag for ${req.uid} - ${e}`);
|
||||
res.json({ resultCode: -999 });
|
||||
}
|
||||
});
|
||||
|
||||
app.post("/api/resetPersonalBests", authenticateToken, (req, res) => {
|
||||
try {
|
||||
User.findOne({ name: req.name }, (err, user) => {
|
||||
User.findOne({ uid: req.uid }, (err, user) => {
|
||||
if (err) res.status(500).send({ error: err });
|
||||
user.personalBests = {};
|
||||
user.save();
|
||||
|
@ -1522,9 +1384,11 @@ app.post("/api/attemptAddToLeaderboards", authenticateToken, (req, res) => {
|
|||
lb.board.length < lb.size ||
|
||||
result.wpm > lb.board.slice(-1)[0].wpm
|
||||
) {
|
||||
lb, (lbPosData = addToLeaderboard(lb, result, req.name));
|
||||
retData[lb.type] = lbPosData;
|
||||
lb.save();
|
||||
User.findOne({ uid: req.uid }, (err, user) => {
|
||||
lb, (lbPosData = addToLeaderboard(lb, result, user.name)); //should uid be added instead of name
|
||||
retData[lb.type] = lbPosData;
|
||||
lb.save();
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -1549,81 +1413,6 @@ app.get("/api/getLeaderboard/:type/:mode/:mode2", (req, res) => {
|
|||
);
|
||||
});
|
||||
|
||||
// ANALYTICS API
|
||||
|
||||
function newAnalyticsEvent(event, data) {
|
||||
let newEvent = {
|
||||
event: event,
|
||||
};
|
||||
if (data) newEvent.data = data;
|
||||
const newEventObj = new Analytics(newEvent);
|
||||
newEventObj.save();
|
||||
}
|
||||
|
||||
app.post("/api/analytics/usedCommandLine", (req, res) => {
|
||||
//save command used from command line to analytics
|
||||
newAnalyticsEvent("usedCommandLine", { command: req.body.command });
|
||||
res.sendStatus(200);
|
||||
});
|
||||
|
||||
app.post("/api/analytics/changedLanguage", (req, res) => {
|
||||
//save what a user changed their language to
|
||||
newAnalyticsEvent("changedLanguage", { language: req.body.language });
|
||||
res.sendStatus(200);
|
||||
});
|
||||
|
||||
app.post("/api/analytics/changedTheme", (req, res) => {
|
||||
//save what a user changed their theme to
|
||||
newAnalyticsEvent("changedTheme", { theme: req.body.theme });
|
||||
res.sendStatus(200);
|
||||
});
|
||||
|
||||
app.post("/api/analytics/testStarted", (req, res) => {
|
||||
//log that a test was started
|
||||
newAnalyticsEvent("testStarted");
|
||||
res.sendStatus(200);
|
||||
});
|
||||
|
||||
app.post("/api/analytics/testStartedNoLogin", (req, res) => {
|
||||
//log that a test was started without login
|
||||
newAnalyticsEvent("testStartedNoLogin");
|
||||
res.sendStatus(200);
|
||||
});
|
||||
|
||||
app.post("/api/analytics/testCompleted", (req, res) => {
|
||||
//log that a test was completed
|
||||
newAnalyticsEvent("testCompleted", {
|
||||
completedEvent: req.body.completedEvent,
|
||||
});
|
||||
res.sendStatus(200);
|
||||
});
|
||||
|
||||
app.post("/api/analytics/testCompletedNoLogin", (req, res) => {
|
||||
//log that a test was completed and user was not logged in
|
||||
newAnalyticsEvent("testCompletedNoLogin", {
|
||||
completedEvent: req.body.completedEvent,
|
||||
});
|
||||
res.sendStatus(200);
|
||||
});
|
||||
|
||||
app.post("/api/analytics/testCompletedInvalid", (req, res) => {
|
||||
//log that a test was completed and is invalid
|
||||
newAnalyticsEvent("testCompletedInvalid", {
|
||||
completedEvent: req.body.completedEvent,
|
||||
});
|
||||
res.sendStatus(200);
|
||||
});
|
||||
|
||||
// STATIC FILES
|
||||
app.get("/privacy-policy", (req, res) => {
|
||||
res.sendFile(mtRootDir + "/dist/privacy-policy.html");
|
||||
});
|
||||
|
||||
app.use((req, res, next) => {
|
||||
//sends index.html if the route is not found above
|
||||
res.sendFile(mtRootDir + "/dist/index.html");
|
||||
});
|
||||
|
||||
// LISTENER
|
||||
app.listen(port, () => {
|
||||
console.log(`Listening to requests on http://localhost:${port}`);
|
||||
|
|
24
firebase.json
Normal file
24
firebase.json
Normal file
|
@ -0,0 +1,24 @@
|
|||
{
|
||||
"hosting": {
|
||||
"public": "dist",
|
||||
"ignore": ["firebase.json", "**/.*", "**/node_modules/**"],
|
||||
"rewrites": [
|
||||
{
|
||||
"source": "/privacy-policy",
|
||||
"destination": "/privacy-policy.html"
|
||||
},
|
||||
{
|
||||
"source": "**",
|
||||
"destination": "/index.html"
|
||||
}
|
||||
],
|
||||
"cleanUrls": true,
|
||||
"trailingSlash": false
|
||||
}
|
||||
// },
|
||||
// "functions": {
|
||||
// "predeploy": [
|
||||
// "npm --prefix \"$RESOURCE_DIR\" run lint"
|
||||
// ]
|
||||
// }
|
||||
}
|
2718
functions/index.js
2718
functions/index.js
File diff suppressed because it is too large
Load diff
|
@ -1,372 +0,0 @@
|
|||
exports.requestTest = functions.https.onRequest((request, response) => {
|
||||
response.set("Access-Control-Allow-Origin", origin);
|
||||
response.set("Access-Control-Allow-Headers", "*");
|
||||
response.set("Access-Control-Allow-Credentials", "true");
|
||||
response.status(200).send({ data: "test" });
|
||||
});
|
||||
|
||||
exports.getPatreons = functions.https.onRequest(async (request, response) => {
|
||||
response.set("Access-Control-Allow-Origin", origin);
|
||||
response.set("Access-Control-Allow-Headers", "*");
|
||||
response.set("Access-Control-Allow-Credentials", "true");
|
||||
if (request.method === "OPTIONS") {
|
||||
// Send response to OPTIONS requests
|
||||
response.set("Access-Control-Allow-Methods", "POST, GET, OPTIONS");
|
||||
response.set("Access-Control-Allow-Headers", "Authorization,Content-Type");
|
||||
response.set("Access-Control-Max-Age", "3600");
|
||||
response.status(204).send("");
|
||||
return;
|
||||
}
|
||||
request = request.body.data;
|
||||
try {
|
||||
let patreon = await db.collection("patreon").doc("patreons").get();
|
||||
let data = patreon.data().list;
|
||||
|
||||
data = data.sort((a, b) => {
|
||||
return b.value - a.value;
|
||||
});
|
||||
|
||||
let ret = [];
|
||||
data.forEach((pdoc) => {
|
||||
ret.push(pdoc.name);
|
||||
});
|
||||
|
||||
response.status(200).send({ data: ret });
|
||||
return;
|
||||
} catch (e) {
|
||||
response.status(200).send({ e });
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
exports.clearTagPb = functions.https.onCall((request, response) => {
|
||||
//It looks like this button is not used anymore
|
||||
try {
|
||||
return db
|
||||
.collection(`users/${request.uid}/tags`)
|
||||
.doc(request.tagid)
|
||||
.update({
|
||||
pb: 0,
|
||||
})
|
||||
.then((e) => {
|
||||
return {
|
||||
resultCode: 1,
|
||||
};
|
||||
})
|
||||
.catch((e) => {
|
||||
console.error(
|
||||
`error deleting tag pb for user ${request.uid}: ${e.message}`
|
||||
);
|
||||
return {
|
||||
resultCode: -999,
|
||||
message: e.message,
|
||||
};
|
||||
});
|
||||
} catch (e) {
|
||||
console.error(`error deleting tag pb for ${request.uid} - ${e}`);
|
||||
return { resultCode: -999 };
|
||||
}
|
||||
});
|
||||
|
||||
exports.removeSmallTestsAndQPB = functions.https.onCall(
|
||||
async (request, response) => {
|
||||
let uid = request.uid;
|
||||
|
||||
try {
|
||||
let docs = await db
|
||||
.collection(`users/${uid}/results`)
|
||||
.where("mode", "==", "time")
|
||||
.where("mode2", "<", 15)
|
||||
.get();
|
||||
docs.forEach(async (doc) => {
|
||||
db.collection(`users/${uid}/results`).doc(doc.id).delete();
|
||||
});
|
||||
let docs2 = await db
|
||||
.collection(`users/${uid}/results`)
|
||||
.where("mode", "==", "words")
|
||||
.where("mode2", "<", 10)
|
||||
.get();
|
||||
docs2.forEach(async (doc) => {
|
||||
db.collection(`users/${uid}/results`).doc(doc.id).delete();
|
||||
});
|
||||
let docs3 = await db
|
||||
.collection(`users/${uid}/results`)
|
||||
.where("mode", "==", "custom")
|
||||
.where("testDuration", "<", 10)
|
||||
.get();
|
||||
docs3.forEach(async (doc) => {
|
||||
db.collection(`users/${uid}/results`).doc(doc.id).delete();
|
||||
});
|
||||
// console.log(`removing small tests for ${uid}: ${docs.size} time, ${docs2.size} words, ${docs3.size} custom`);
|
||||
let userdata = await db.collection(`users`).doc(uid).get();
|
||||
userdata = userdata.data();
|
||||
try {
|
||||
pbs = userdata.personalBests;
|
||||
// console.log(`removing ${Object.keys(pbs.quote).length} quote pb`);
|
||||
delete pbs.quote;
|
||||
await db.collection("users").doc(uid).update({ personalBests: pbs });
|
||||
} catch {}
|
||||
db.collection("users")
|
||||
.doc(uid)
|
||||
.set({ refactored: true }, { merge: true });
|
||||
console.log("removed small tests for " + uid);
|
||||
} catch (e) {
|
||||
console.log(`something went wrong for ${uid}: ${e.message}`);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
async function getAllNames() {
|
||||
// return admin
|
||||
// .auth()
|
||||
// .listUsers()
|
||||
// .then((data) => {
|
||||
// let names = [];
|
||||
// data.users.forEach((user) => {
|
||||
// names.push(user.name);
|
||||
// });
|
||||
// return names;
|
||||
// });
|
||||
|
||||
let ret = [];
|
||||
|
||||
async function getAll(nextPageToken) {
|
||||
// List batch of users, 1000 at a time.
|
||||
let listUsersResult = await admin.auth().listUsers(1000, nextPageToken);
|
||||
for (let i = 0; i < listUsersResult.users.length; i++) {
|
||||
ret.push(listUsersResult.users[i].name);
|
||||
}
|
||||
if (listUsersResult.pageToken) {
|
||||
// List next batch of users.
|
||||
await getAll(listUsersResult.pageToken);
|
||||
}
|
||||
}
|
||||
|
||||
await getAll();
|
||||
return ret;
|
||||
}
|
||||
|
||||
async function getAllUsers() {
|
||||
// return admin
|
||||
// .auth()
|
||||
// .listUsers()
|
||||
// .then((data) => {
|
||||
// let names = [];
|
||||
// data.users.forEach((user) => {
|
||||
// names.push(user.name);
|
||||
// });
|
||||
// return names;
|
||||
// });
|
||||
|
||||
let ret = [];
|
||||
|
||||
async function getAll(nextPageToken) {
|
||||
// List batch of users, 1000 at a time.
|
||||
let listUsersResult = await auth.listUsers(1000, nextPageToken);
|
||||
for (let i = 0; i < listUsersResult.users.length; i++) {
|
||||
let loopuser = listUsersResult.users[i];
|
||||
|
||||
//if custom claim is undefined check, if its true then ignore
|
||||
|
||||
// if (loopuser === undefined || loopuser.customClaims === undefined || loopuser.customClaims['nameChecked'] === undefined) {
|
||||
ret.push(listUsersResult.users[i]);
|
||||
// }
|
||||
|
||||
// console.log(loopuser.customClaims['asd']);
|
||||
|
||||
// let userdata = await db.collection('users').doc(listUsersResult.users[i].uid).get();
|
||||
|
||||
// let data = userdata.data();
|
||||
|
||||
// if (data === undefined || data.needsToChangeName === undefined) {
|
||||
// // console.log(data);
|
||||
// ret.push(listUsersResult.users[i]);
|
||||
// // console.log('user added');
|
||||
// } else {
|
||||
// // console.log('user already added');
|
||||
// }
|
||||
}
|
||||
if (listUsersResult.pageToken) {
|
||||
// List next batch of users.
|
||||
await getAll(listUsersResult.pageToken);
|
||||
}
|
||||
}
|
||||
await getAll();
|
||||
return ret;
|
||||
}
|
||||
|
||||
function isUsernameValid(name) {
|
||||
if (name === null || name === undefined || name === "") return false;
|
||||
if (/miodec/.test(name.toLowerCase())) return false;
|
||||
if (/bitly/.test(name.toLowerCase())) return false;
|
||||
if (name.length > 14) return false;
|
||||
if (/^\..*/.test(name.toLowerCase())) return false;
|
||||
return /^[0-9a-zA-Z_.-]+$/.test(name);
|
||||
}
|
||||
|
||||
async function incrementTestCounter(uid, userData) {
|
||||
try {
|
||||
if (userData.completedTests === undefined) {
|
||||
let results = await db.collection(`users/${uid}/results`).get();
|
||||
let count = results.docs.length;
|
||||
db.collection("users")
|
||||
.doc(uid)
|
||||
.update({
|
||||
completedTests: admin.firestore.FieldValue.increment(count),
|
||||
});
|
||||
db.collection("public")
|
||||
.doc("stats")
|
||||
.update({
|
||||
completedTests: admin.firestore.FieldValue.increment(count),
|
||||
});
|
||||
} else {
|
||||
db.collection("users")
|
||||
.doc(uid)
|
||||
.update({ completedTests: admin.firestore.FieldValue.increment(1) });
|
||||
db.collection("public")
|
||||
.doc("stats")
|
||||
.update({ completedTests: admin.firestore.FieldValue.increment(1) });
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(
|
||||
`Error while incrementing completed tests for user ${uid}: ${e}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
async function incrementStartedTestCounter(uid, num, userData) {
|
||||
try {
|
||||
if (userData.startedTests === undefined) {
|
||||
let stepSize = 1000;
|
||||
let results = [];
|
||||
let query = await db
|
||||
.collection(`users/${uid}/results`)
|
||||
.orderBy("timestamp", "desc")
|
||||
.limit(stepSize)
|
||||
.get();
|
||||
let lastDoc;
|
||||
while (query.docs.length > 0) {
|
||||
lastDoc = query.docs[query.docs.length - 1];
|
||||
query.docs.forEach((doc) => {
|
||||
results.push({ restartCount: doc.data().restartCount });
|
||||
});
|
||||
query = await db
|
||||
.collection(`users/${uid}/results`)
|
||||
.orderBy("timestamp", "desc")
|
||||
.limit(stepSize)
|
||||
.startAfter(lastDoc)
|
||||
.get();
|
||||
}
|
||||
|
||||
let count = 0;
|
||||
results.forEach((result) => {
|
||||
try {
|
||||
let rc = result.restartCount;
|
||||
if (rc === undefined) {
|
||||
rc = 0;
|
||||
}
|
||||
|
||||
count += parseInt(rc);
|
||||
} catch (e) {}
|
||||
});
|
||||
count += results.length;
|
||||
db.collection("users")
|
||||
.doc(uid)
|
||||
.update({
|
||||
startedTests: admin.firestore.FieldValue.increment(count),
|
||||
});
|
||||
db.collection("public")
|
||||
.doc("stats")
|
||||
.update({
|
||||
startedTests: admin.firestore.FieldValue.increment(count),
|
||||
});
|
||||
} else {
|
||||
db.collection("users")
|
||||
.doc(uid)
|
||||
.update({ startedTests: admin.firestore.FieldValue.increment(num) });
|
||||
db.collection("public")
|
||||
.doc("stats")
|
||||
.update({ startedTests: admin.firestore.FieldValue.increment(num) });
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(
|
||||
`Error while incrementing started tests for user ${uid}: ${e}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
exports.scheduledFunctionCrontab = functions.pubsub
|
||||
.schedule("00 00 * * *")
|
||||
.timeZone("Africa/Abidjan")
|
||||
.onRun((context) => {
|
||||
try {
|
||||
console.log("moving daily leaderboards to history");
|
||||
db.collection("leaderboards")
|
||||
.where("type", "==", "daily")
|
||||
.get()
|
||||
.then(async (res) => {
|
||||
for (let i = 0; i < res.docs.length; i++) {
|
||||
let doc = res.docs[i];
|
||||
|
||||
let lbdata = doc.data();
|
||||
|
||||
let winnerUid = lbdata.board[0].uid;
|
||||
await db
|
||||
.collection("users")
|
||||
.doc(winnerUid)
|
||||
.get()
|
||||
.then(async (userDoc) => {
|
||||
let userData = userDoc.data();
|
||||
let lbwins = userData.dailyLbWins;
|
||||
|
||||
let lbname = lbdata.mode + lbdata.mode2;
|
||||
|
||||
if (lbwins === undefined) {
|
||||
//first win ever
|
||||
lbwins = {
|
||||
[lbname]: 1,
|
||||
};
|
||||
} else {
|
||||
//object already exists
|
||||
if (lbwins[lbname] === undefined) {
|
||||
lbwins[lbname] = 1;
|
||||
} else {
|
||||
lbwins[lbname] = lbwins[lbname] + 1;
|
||||
}
|
||||
}
|
||||
await db.collection("users").doc(winnerUid).update({
|
||||
dailyLbWins: lbwins,
|
||||
});
|
||||
});
|
||||
|
||||
announceDailyLbResult(lbdata);
|
||||
t = new Date();
|
||||
// db.collection("leaderboards_history")
|
||||
// .doc(
|
||||
// `${t.getUTCDate()}_${t.getUTCMonth()}_${t.getUTCFullYear()}_${
|
||||
// lbdata.mode
|
||||
// }_${lbdata.mode2}`
|
||||
// )
|
||||
// .set(lbdata);
|
||||
db.collection("leaderboards").doc(doc.id).set(
|
||||
{
|
||||
board: [],
|
||||
},
|
||||
{ merge: true }
|
||||
);
|
||||
}
|
||||
});
|
||||
return null;
|
||||
} catch (e) {
|
||||
console.error(`error while moving daily leaderboards to history - ${e}`);
|
||||
}
|
||||
});
|
||||
|
||||
async function announceDailyLbResult(lbdata) {
|
||||
db.collection("bot-commands").add({
|
||||
command: "announceDailyLbResult",
|
||||
arguments: [lbdata],
|
||||
executed: false,
|
||||
requestTimestamp: Date.now(),
|
||||
});
|
||||
}
|
579
functions/package-lock.json
generated
579
functions/package-lock.json
generated
File diff suppressed because it is too large
Load diff
11
gulpfile.js
11
gulpfile.js
|
@ -1,6 +1,6 @@
|
|||
const { task, src, dest, series, watch } = require("gulp");
|
||||
const browserify = require("browserify");
|
||||
const axios = require("axios");
|
||||
const browserify = require("browserify");
|
||||
const babelify = require("babelify");
|
||||
const concat = require("gulp-concat");
|
||||
const del = require("del");
|
||||
|
@ -13,7 +13,14 @@ sass.compiler = require("dart-sass");
|
|||
|
||||
let eslintConfig = {
|
||||
parser: "babel-eslint",
|
||||
globals: ["jQuery", "$", "moment", "html2canvas", "ClipboardItem"],
|
||||
globals: [
|
||||
"jQuery",
|
||||
"$",
|
||||
"firebase",
|
||||
"moment",
|
||||
"html2canvas",
|
||||
"ClipboardItem",
|
||||
],
|
||||
envs: ["es6", "browser", "node"],
|
||||
rules: {
|
||||
"constructor-super": "error",
|
||||
|
|
3586
package-lock.json
generated
3586
package-lock.json
generated
File diff suppressed because it is too large
Load diff
12
package.json
12
package.json
|
@ -6,7 +6,7 @@
|
|||
"scripts": {
|
||||
"postinstall": "cd functions && npm install",
|
||||
"build": "npx gulp build",
|
||||
"start:dev": "npm run build && concurrently --kill-others \"npx gulp watch\" \"nodemon ./backend/server.js\"",
|
||||
"start:dev": "npm run build && concurrently --kill-others \"npx gulp watch\" \"nodemon ./backend/server.js\" \"firebase serve\"",
|
||||
"deploy:live:hosting": "npm run build && firebase deploy -P monkey-type --only hosting",
|
||||
"deploy:live:functions": "npm run build && firebase deploy -P monkey-type --only functions",
|
||||
"deploy:live": "npm run build && firebase deploy -P live"
|
||||
|
@ -30,7 +30,6 @@
|
|||
"gulp-eslint": "^6.0.0",
|
||||
"gulp-sass": "^4.1.0",
|
||||
"husky": "^4.3.0",
|
||||
"nodemon": "^2.0.7",
|
||||
"prettier": "2.1.2",
|
||||
"pretty-quick": "^3.1.0",
|
||||
"vinyl-buffer": "^1.0.1",
|
||||
|
@ -45,16 +44,15 @@
|
|||
"dependencies": {
|
||||
"@babel/runtime": "^7.12.5",
|
||||
"axios": "^0.21.1",
|
||||
"bcrypt": "^5.0.1",
|
||||
"chart.js": "^2.9.4",
|
||||
"chartjs-plugin-annotation": "^0.5.7",
|
||||
"chartjs-plugin-trendline": "^0.2.2",
|
||||
"dotenv": "^9.0.2",
|
||||
"cors": "^2.8.5",
|
||||
"express": "^4.17.1",
|
||||
"firebase-admin": "^9.9.0",
|
||||
"howler": "^2.2.1",
|
||||
"jsonwebtoken": "^8.5.1",
|
||||
"mongoose": "^5.12.8",
|
||||
"nodemailer": "^6.6.1",
|
||||
"mongoose": "^5.12.12",
|
||||
"nodemon": "^2.0.7",
|
||||
"tinycolor2": "^1.4.2"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,42 +14,52 @@ import * as DB from "./db";
|
|||
import * as TestLogic from "./test-logic";
|
||||
import * as UI from "./ui";
|
||||
import axiosInstance from "./axios-instance";
|
||||
//var gmailProvider = new firebase.auth.GoogleAuthProvider();
|
||||
|
||||
var gmailProvider = new firebase.auth.GoogleAuthProvider();
|
||||
|
||||
export function signIn() {
|
||||
$(".pageLogin .preloader").removeClass("hidden");
|
||||
let email = $(".pageLogin .login input")[0].value;
|
||||
let password = $(".pageLogin .login input")[1].value;
|
||||
axiosInstance
|
||||
.post("/api/signIn", {
|
||||
email: email,
|
||||
password: password,
|
||||
})
|
||||
.then((response) => {
|
||||
// UI.changePage("test");
|
||||
if ($(".pageLogin .login #rememberMe input").prop("checked")) {
|
||||
// TODO: set user login cookie that persists after session
|
||||
window.localStorage.setItem("accessToken", response.data.accessToken);
|
||||
window.localStorage.setItem("refreshToken", response.data.refreshToken);
|
||||
window.localStorage.setItem("user", JSON.stringify(response.data.user));
|
||||
} else {
|
||||
//set user login cookie to persist only as long as the session lives
|
||||
window.localStorage.setItem("accessToken", response.data.accessToken);
|
||||
window.localStorage.setItem("refreshToken", response.data.refreshToken);
|
||||
window.localStorage.setItem("user", JSON.stringify(response.data.user));
|
||||
}
|
||||
userStateChanged(response.data.user);
|
||||
})
|
||||
.catch((e) => {
|
||||
console.log("Could not be signed in");
|
||||
Notifications.add(e.message, -1);
|
||||
$(".pageLogin .preloader").addClass("hidden");
|
||||
});
|
||||
|
||||
if ($(".pageLogin .login #rememberMe input").prop("checked")) {
|
||||
//remember me
|
||||
firebase
|
||||
.auth()
|
||||
.setPersistence(firebase.auth.Auth.Persistence.LOCAL)
|
||||
.then(function () {
|
||||
return firebase
|
||||
.auth()
|
||||
.signInWithEmailAndPassword(email, password)
|
||||
.then((e) => {
|
||||
// UI.changePage("test");
|
||||
})
|
||||
.catch(function (error) {
|
||||
Notifications.add(error.message, -1);
|
||||
$(".pageLogin .preloader").addClass("hidden");
|
||||
});
|
||||
});
|
||||
} else {
|
||||
//dont remember
|
||||
firebase
|
||||
.auth()
|
||||
.setPersistence(firebase.auth.Auth.Persistence.SESSION)
|
||||
.then(function () {
|
||||
return firebase
|
||||
.auth()
|
||||
.signInWithEmailAndPassword(email, password)
|
||||
.then((e) => {
|
||||
// UI.changePage("test");
|
||||
})
|
||||
.catch(function (error) {
|
||||
Notifications.add(error.message, -1);
|
||||
$(".pageLogin .preloader").addClass("hidden");
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export async function signInWithGoogle() {
|
||||
console.log("Login with google temporarily unavailable");
|
||||
/*
|
||||
$(".pageLogin .preloader").removeClass("hidden");
|
||||
|
||||
if ($(".pageLogin .login #rememberMe input").prop("checked")) {
|
||||
|
@ -81,12 +91,9 @@ export async function signInWithGoogle() {
|
|||
$(".pageLogin .preloader").addClass("hidden");
|
||||
});
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
export function linkWithGoogle() {
|
||||
console.log("Link with google temporarily unavailable");
|
||||
/*
|
||||
firebase
|
||||
.auth()
|
||||
.currentUser.linkWithPopup(gmailProvider)
|
||||
|
@ -96,21 +103,23 @@ export function linkWithGoogle() {
|
|||
.catch(function (error) {
|
||||
console.log(error);
|
||||
});
|
||||
*/
|
||||
}
|
||||
|
||||
export function signOut() {
|
||||
//don't think I need an axios request here if I'm using jwt
|
||||
window.localStorage.removeItem("accessToken");
|
||||
window.localStorage.removeItem("refreshToken");
|
||||
window.localStorage.removeItem("user");
|
||||
Notifications.add("Signed out", 0, 2);
|
||||
AllTimeStats.clear();
|
||||
Settings.hideAccountSection();
|
||||
AccountButton.update();
|
||||
UI.changePage("login");
|
||||
DB.setSnapshot(null);
|
||||
userStateChanged(null);
|
||||
firebase
|
||||
.auth()
|
||||
.signOut()
|
||||
.then(function () {
|
||||
Notifications.add("Signed out", 0, 2);
|
||||
AllTimeStats.clear();
|
||||
Settings.hideAccountSection();
|
||||
AccountButton.update();
|
||||
UI.changePage("login");
|
||||
DB.setSnapshot(null);
|
||||
})
|
||||
.catch(function (error) {
|
||||
Notifications.add(error.message, -1);
|
||||
});
|
||||
}
|
||||
|
||||
function signUp() {
|
||||
|
@ -127,65 +136,131 @@ function signUp() {
|
|||
$(".pageLogin .register .button").removeClass("disabled");
|
||||
return;
|
||||
}
|
||||
|
||||
axiosInstance
|
||||
.post("/api/signUp", {
|
||||
name: nname,
|
||||
email: email,
|
||||
password: password,
|
||||
})
|
||||
.then((response) => {
|
||||
let usr = response.data.user;
|
||||
window.localStorage.setItem("accessToken", response.data.accessToken);
|
||||
window.localStorage.setItem("refreshToken", response.data.refreshToken);
|
||||
window.localStorage.setItem("user", JSON.stringify(response.data.user));
|
||||
//Cookies.set('refreshToken', response.data.refreshToken);
|
||||
AllTimeStats.clear();
|
||||
Notifications.add("Account created", 1, 3);
|
||||
$("#menu .icon-button.account .text").text(nname);
|
||||
$(".pageLogin .preloader").addClass("hidden");
|
||||
DB.setSnapshot({
|
||||
results: [],
|
||||
personalBests: {},
|
||||
tags: [],
|
||||
globalStats: {
|
||||
time: undefined,
|
||||
started: undefined,
|
||||
completed: undefined,
|
||||
},
|
||||
});
|
||||
if (TestLogic.notSignedInLastResult !== null) {
|
||||
TestLogic.setNotSignedInUid(usr.uid);
|
||||
CloudFunctions.testCompleted({
|
||||
uid: usr.uid,
|
||||
obj: TestLogic.notSignedInLastResult,
|
||||
});
|
||||
DB.getSnapshot().results.push(TestLogic.notSignedInLastResult);
|
||||
}
|
||||
UI.changePage("account");
|
||||
$(".pageLogin .register .button").removeClass("disabled");
|
||||
userStateChanged(usr);
|
||||
})
|
||||
.catch((error) => {
|
||||
//Notifications.add("Account not created. " + error.message, -1);
|
||||
Notifications.add(error, -1);
|
||||
axiosInstance.get(`/api/nameCheck/${nname}`).then((d) => {
|
||||
console.log(d.data);
|
||||
if (d.data.resultCode === -1) {
|
||||
Notifications.add("Name unavailable", -1);
|
||||
$(".pageLogin .preloader").addClass("hidden");
|
||||
$(".pageLogin .register .button").removeClass("disabled");
|
||||
return;
|
||||
});
|
||||
} else if (d.data.resultCode === -2) {
|
||||
Notifications.add(
|
||||
"Name cannot contain special characters or contain more than 14 characters. Can include _ . and -",
|
||||
-1
|
||||
);
|
||||
$(".pageLogin .preloader").addClass("hidden");
|
||||
$(".pageLogin .register .button").removeClass("disabled");
|
||||
return;
|
||||
} else if (d.data.resultCode === 1) {
|
||||
firebase
|
||||
.auth()
|
||||
.createUserWithEmailAndPassword(email, password)
|
||||
.then((user) => {
|
||||
// Account has been created here.
|
||||
// dontCheckUserName = true;
|
||||
let usr = user.user;
|
||||
//maybe there's a better place for the api call
|
||||
axiosInstance.post("/api/signUp", {
|
||||
name: nname,
|
||||
uid: usr.uid,
|
||||
email: email,
|
||||
});
|
||||
usr
|
||||
.updateProfile({
|
||||
displayName: nname,
|
||||
})
|
||||
.then(async function () {
|
||||
// Update successful.
|
||||
await firebase
|
||||
.firestore()
|
||||
.collection("users")
|
||||
.doc(usr.uid)
|
||||
.set({ name: nname }, { merge: true });
|
||||
usr.sendEmailVerification();
|
||||
AllTimeStats.clear();
|
||||
Notifications.add("Account created", 1, 3);
|
||||
$("#menu .icon-button.account .text").text(nname);
|
||||
try {
|
||||
firebase.analytics().logEvent("accountCreated", usr.uid);
|
||||
} catch (e) {
|
||||
console.log("Analytics unavailable");
|
||||
}
|
||||
$(".pageLogin .preloader").addClass("hidden");
|
||||
DB.setSnapshot({
|
||||
results: [],
|
||||
personalBests: {},
|
||||
tags: [],
|
||||
globalStats: {
|
||||
time: undefined,
|
||||
started: undefined,
|
||||
completed: undefined,
|
||||
},
|
||||
});
|
||||
if (TestLogic.notSignedInLastResult !== null) {
|
||||
TestLogic.setNotSignedInUid(usr.uid);
|
||||
CloudFunctions.testCompleted({
|
||||
uid: usr.uid,
|
||||
obj: TestLogic.notSignedInLastResult,
|
||||
});
|
||||
DB.getSnapshot().results.push(TestLogic.notSignedInLastResult);
|
||||
}
|
||||
UI.changePage("account");
|
||||
usr.sendEmailVerification();
|
||||
$(".pageLogin .register .button").removeClass("disabled");
|
||||
})
|
||||
.catch(function (error) {
|
||||
// An error happened.
|
||||
$(".pageLogin .register .button").removeClass("disabled");
|
||||
console.error(error);
|
||||
usr
|
||||
.delete()
|
||||
.then(function () {
|
||||
// User deleted.
|
||||
Notifications.add(
|
||||
"Account not created. " + error.message,
|
||||
-1
|
||||
);
|
||||
$(".pageLogin .preloader").addClass("hidden");
|
||||
})
|
||||
.catch(function (error) {
|
||||
// An error happened.
|
||||
$(".pageLogin .preloader").addClass("hidden");
|
||||
Notifications.add(
|
||||
"Something went wrong. " + error.message,
|
||||
-1
|
||||
);
|
||||
console.error(error);
|
||||
});
|
||||
});
|
||||
})
|
||||
.catch(function (error) {
|
||||
// Handle Errors here.
|
||||
$(".pageLogin .register .button").removeClass("disabled");
|
||||
Notifications.add(error.message, -1);
|
||||
$(".pageLogin .preloader").addClass("hidden");
|
||||
});
|
||||
} else {
|
||||
$(".pageLogin .preloader").addClass("hidden");
|
||||
Notifications.add(
|
||||
"Something went wrong when checking name: " + d.data.message,
|
||||
-1
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$(".pageLogin #forgotPasswordButton").click((e) => {
|
||||
let email = prompt("Email address");
|
||||
if (email) {
|
||||
axiosInstance
|
||||
.post("/api/passwordReset", {
|
||||
email: email,
|
||||
})
|
||||
.then(() => {
|
||||
firebase
|
||||
.auth()
|
||||
.sendPasswordResetEmail(email)
|
||||
.then(function () {
|
||||
// Email sent.
|
||||
Notifications.add("Email sent", 1, 2);
|
||||
})
|
||||
.catch((error) => {
|
||||
.catch(function (error) {
|
||||
// An error happened.
|
||||
Notifications.add(error.message, -1);
|
||||
});
|
||||
}
|
||||
|
@ -212,7 +287,7 @@ $(".signOut").click((e) => {
|
|||
signOut();
|
||||
});
|
||||
|
||||
export function userStateChanged(user) {
|
||||
firebase.auth().onAuthStateChanged(function (user) {
|
||||
if (user) {
|
||||
// User is signed in.
|
||||
$(".pageAccount .content p.accountVerificatinNotice").remove();
|
||||
|
@ -224,7 +299,7 @@ export function userStateChanged(user) {
|
|||
AccountButton.update();
|
||||
AccountButton.loading(true);
|
||||
Account.getDataAndInit();
|
||||
// var name = user.name;
|
||||
// var displayName = user.displayName;
|
||||
// var email = user.email;
|
||||
// var emailVerified = user.emailVerified;
|
||||
// var photoURL = user.photoURL;
|
||||
|
@ -236,8 +311,7 @@ export function userStateChanged(user) {
|
|||
// showFavouriteThemesAtTheTop();
|
||||
CommandlineLists.updateThemeCommands();
|
||||
|
||||
let text =
|
||||
"Account created on " + user.metadata.creationTime.substring(0, 10);
|
||||
let text = "Account created on " + user.metadata.creationTime;
|
||||
|
||||
const date1 = new Date(user.metadata.creationTime);
|
||||
const date2 = new Date();
|
||||
|
@ -275,7 +349,7 @@ export function userStateChanged(user) {
|
|||
ChallengeController.setup(challengeName);
|
||||
}, 1000);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$(".pageLogin .register input").keyup((e) => {
|
||||
if ($(".pageLogin .register .button").hasClass("disabled")) return;
|
||||
|
|
|
@ -27,7 +27,7 @@ export function getDataAndInit() {
|
|||
if (snap === null) {
|
||||
throw "Missing db snapshot. Client likely could not connect to the backend.";
|
||||
}
|
||||
let user = DB.currentUser(); // I think that this should be stored in cookie
|
||||
let user = firebase.auth().currentUser; // I think that this should be stored in cookie
|
||||
if (snap.name === undefined) {
|
||||
//verify username
|
||||
if (Misc.isUsernameValid(user.name)) {
|
||||
|
|
|
@ -1,14 +1,21 @@
|
|||
import axios from "axios";
|
||||
|
||||
const axiosInstance = axios.create();
|
||||
const axiosInstance = axios.create({
|
||||
baseURL: "http://localhost:5005",
|
||||
});
|
||||
|
||||
// Request interceptor for API calls
|
||||
axiosInstance.interceptors.request.use(
|
||||
async (config) => {
|
||||
const accessToken = window.localStorage.getItem("accessToken");
|
||||
if (accessToken) {
|
||||
let idToken;
|
||||
if (firebase.auth().currentUser != null) {
|
||||
idToken = await firebase.auth().currentUser.getIdToken();
|
||||
} else {
|
||||
idToken = null;
|
||||
}
|
||||
if (idToken) {
|
||||
config.headers = {
|
||||
Authorization: `Bearer ${accessToken}`,
|
||||
Authorization: `Bearer ${idToken}`,
|
||||
Accept: "application/json",
|
||||
"Content-Type": "application/json",
|
||||
};
|
||||
|
@ -25,35 +32,4 @@ axiosInstance.interceptors.request.use(
|
|||
}
|
||||
);
|
||||
|
||||
// Response interceptor for API calls
|
||||
axiosInstance.interceptors.response.use(
|
||||
(response) => {
|
||||
return response;
|
||||
},
|
||||
async function (error) {
|
||||
const originalRequest = error.config;
|
||||
if (error.response.status === 401 && !originalRequest._retry) {
|
||||
originalRequest._retry = true;
|
||||
const refreshToken = window.localStorage.getItem("refreshToken");
|
||||
await axios
|
||||
.post(
|
||||
`/api/refreshToken`,
|
||||
{},
|
||||
{ headers: { Authorization: `Bearer ${refreshToken}` } }
|
||||
)
|
||||
.then((response) => {
|
||||
window.localStorage.setItem("accessToken", response.data.accessToken);
|
||||
axios.defaults.headers.common["Authorization"] =
|
||||
"Bearer " + response.data.accessToken;
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log(error);
|
||||
axios.defaults.headers.common["Authorization"] = "Bearer failed";
|
||||
});
|
||||
return axiosInstance(originalRequest);
|
||||
}
|
||||
return Promise.reject(error);
|
||||
}
|
||||
);
|
||||
|
||||
export default axiosInstance;
|
||||
|
|
|
@ -4,7 +4,6 @@ import Config, * as UpdateConfig from "./config";
|
|||
import * as Focus from "./focus";
|
||||
import * as CommandlineLists from "./commandline-lists";
|
||||
import * as TestUI from "./test-ui";
|
||||
import axiosInstance from "./axios-instance";
|
||||
|
||||
let commandLineMouseMode = false;
|
||||
|
||||
|
@ -162,11 +161,13 @@ function trigger(command) {
|
|||
}
|
||||
});
|
||||
if (!subgroup && !input && !sticky) {
|
||||
axiosInstance
|
||||
.post("/api/analytics/usedCommandLine", { command: command })
|
||||
.catch(() => {
|
||||
console.log("Analytics unavailable");
|
||||
try {
|
||||
firebase.analytics().logEvent("usedCommandLine", {
|
||||
command: command,
|
||||
});
|
||||
} catch (e) {
|
||||
console.log("Analytics unavailable");
|
||||
}
|
||||
hide();
|
||||
}
|
||||
}
|
||||
|
@ -322,11 +323,13 @@ $("#commandInput input").keydown((e) => {
|
|||
}
|
||||
}
|
||||
});
|
||||
axiosInstance
|
||||
.post("/api/analytics/usedCommandLine", { command: command })
|
||||
.catch(() => {
|
||||
console.log("Analytics unavailable");
|
||||
try {
|
||||
firebase.analytics().logEvent("usedCommandLine", {
|
||||
command: command,
|
||||
});
|
||||
} catch (e) {
|
||||
console.log("Analytics unavailable");
|
||||
}
|
||||
hide();
|
||||
}
|
||||
return;
|
||||
|
|
|
@ -17,7 +17,6 @@ import * as UI from "./ui";
|
|||
import * as CommandlineLists from "./commandline-lists";
|
||||
import * as BackgroundFilter from "./custom-background-filter";
|
||||
import LayoutList from "./layouts";
|
||||
import axiosInstance from "./axios-instance";
|
||||
|
||||
export let localStorageConfig = null;
|
||||
export let dbConfigLoaded = false;
|
||||
|
@ -485,7 +484,7 @@ export function setPaceCaret(val, nosave) {
|
|||
val = "off";
|
||||
}
|
||||
if (document.readyState === "complete") {
|
||||
if (val == "pb" && DB.currentUser() === null) {
|
||||
if (val == "pb" && firebase.auth().currentUser === null) {
|
||||
Notifications.add("PB pace caret is unavailable without an account", 0);
|
||||
return;
|
||||
}
|
||||
|
@ -1244,11 +1243,13 @@ export function setLanguage(language, nosave) {
|
|||
language = "english";
|
||||
}
|
||||
config.language = language;
|
||||
axiosInstance
|
||||
.post("/api/analytics/changedLanguage", { language: language })
|
||||
.catch(() => {
|
||||
console.log("Analytics unavailable");
|
||||
try {
|
||||
firebase.analytics().logEvent("changedLanguage", {
|
||||
language: language,
|
||||
});
|
||||
} catch (e) {
|
||||
console.log("Analytics unavailable");
|
||||
}
|
||||
if (!nosave) saveToLocalStorage();
|
||||
}
|
||||
|
||||
|
@ -1563,8 +1564,10 @@ export function apply(configObj) {
|
|||
try {
|
||||
setEnableAds(configObj.enableAds, true);
|
||||
let addemo = false;
|
||||
//if the app is not running on production, play advertisement demo
|
||||
if (window.location.hostname === "localhost") {
|
||||
if (
|
||||
firebase.app().options.projectId === "monkey-type-dev-67af4" ||
|
||||
window.location.hostname === "localhost"
|
||||
) {
|
||||
addemo = true;
|
||||
}
|
||||
|
||||
|
|
16
src/js/db.js
16
src/js/db.js
|
@ -27,19 +27,9 @@ export function setSnapshot(newSnapshot) {
|
|||
dbSnapshot = newSnapshot;
|
||||
}
|
||||
|
||||
export function currentUser() {
|
||||
const token = window.localStorage.getItem("accessToken");
|
||||
if (token) {
|
||||
const user = JSON.parse(window.localStorage.getItem("user"));
|
||||
return user;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export async function initSnapshot() {
|
||||
//send api request with token that returns tags, presets, and data needed for snap
|
||||
if (currentUser() == null) return false;
|
||||
if (firebase.auth().currentUser == null) return false;
|
||||
await axiosInstance
|
||||
.get("/api/fetchSnapshot")
|
||||
.then((response) => {
|
||||
|
@ -53,7 +43,7 @@ export async function initSnapshot() {
|
|||
}
|
||||
|
||||
export async function getUserResults() {
|
||||
let user = currentUser();
|
||||
let user = firebase.auth().currentUser;
|
||||
if (user == null) return false;
|
||||
if (dbSnapshot === null) return false;
|
||||
if (dbSnapshot.results !== undefined) {
|
||||
|
@ -418,7 +408,7 @@ export function updateLbMemory(mode, mode2, type, value) {
|
|||
}
|
||||
|
||||
export async function saveConfig(config) {
|
||||
if (currentUser() !== null) {
|
||||
if (firebase.auth().currentUser !== null) {
|
||||
AccountButton.loading(true);
|
||||
axiosInstance
|
||||
.post("/api/saveConfig", {
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import * as UI from "./ui";
|
||||
import * as DB from "./db";
|
||||
|
||||
export function loading(truefalse) {
|
||||
if (truefalse) {
|
||||
|
@ -14,7 +13,7 @@ export function loading(truefalse) {
|
|||
}
|
||||
|
||||
export function update() {
|
||||
if (DB.currentUser() != null) {
|
||||
if (firebase.auth().currentUser != null) {
|
||||
UI.swapElements(
|
||||
$("#menu .icon-button.login"),
|
||||
$("#menu .icon-button.account"),
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import * as CloudFunctions from "./cloud-functions";
|
||||
import * as Loader from "./loader";
|
||||
import * as Notifications from "./notifications";
|
||||
import * as DB from "./db";
|
||||
|
@ -82,7 +81,8 @@ function update() {
|
|||
dailyData.board.forEach((entry) => {
|
||||
if (entry.hidden) return;
|
||||
let meClassString = "";
|
||||
if (entry.name == DB.currentUser().name) {
|
||||
//hacky way to get username because auth().currentUser.name isn't working after mongo switch
|
||||
if (DB.getSnapshot() && entry.name == DB.getSnapshot().name) {
|
||||
meClassString = ' class="me"';
|
||||
$("#leaderboardsWrapper table.daily tfoot").html(`
|
||||
<tr>
|
||||
|
@ -165,7 +165,7 @@ function update() {
|
|||
globalData.board.forEach((entry) => {
|
||||
if (entry.hidden) return;
|
||||
let meClassString = "";
|
||||
if (entry.name == DB.currentUser().name) {
|
||||
if (DB.getSnapshot() && entry.name == DB.getSnapshot().name) {
|
||||
meClassString = ' class="me"';
|
||||
$("#leaderboardsWrapper table.global tfoot").html(`
|
||||
<tr>
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
import * as Loader from "./loader";
|
||||
import * as DB from "./db";
|
||||
import axiosInstance from "./axios-instance";
|
||||
|
||||
export function getuid() {
|
||||
console.error("Only share this uid with Miodec and nobody else!");
|
||||
console.log(DB.currentUser().uid);
|
||||
console.log(firebase.auth().currentUser.uid);
|
||||
console.error("Only share this uid with Miodec and nobody else!");
|
||||
}
|
||||
|
||||
|
@ -315,7 +314,7 @@ export function migrateFromCookies() {
|
|||
|
||||
export function sendVerificationEmail() {
|
||||
Loader.show();
|
||||
let cu = DB.currentUser();
|
||||
let cu = firebase.auth().currentUser;
|
||||
axiosInstance
|
||||
.post("/api/sendEmailVerification", {})
|
||||
.then(() => {
|
||||
|
|
|
@ -86,7 +86,7 @@ $("#resultEditTagsPanel .confirmButton").click((e) => {
|
|||
Loader.show();
|
||||
hide();
|
||||
CloudFunctions.updateResultTags({
|
||||
uid: DB.currentUser().uid,
|
||||
uid: firebase.auth().currentUser.uid,
|
||||
tags: newtags,
|
||||
resultid: resultid,
|
||||
}).then((r) => {
|
||||
|
|
|
@ -7,9 +7,7 @@ import * as RouteController from "./route-controller";
|
|||
import * as UI from "./ui";
|
||||
import * as SignOutButton from "./sign-out-button";
|
||||
import * as AccountController from "./account-controller";
|
||||
import * as DB from "./db";
|
||||
|
||||
console.log("redy loaded");
|
||||
ManualRestart.set();
|
||||
Misc.migrateFromCookies();
|
||||
UpdateConfig.loadFromLocalStorage();
|
||||
|
@ -61,6 +59,5 @@ $(document).ready(() => {
|
|||
}
|
||||
});
|
||||
Settings.settingsFillPromise.then(Settings.update);
|
||||
let user = DB.currentUser();
|
||||
if (user) AccountController.userStateChanged(user);
|
||||
let user = firebase.auth().currentUser;
|
||||
});
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import * as Funbox from "./funbox";
|
||||
import * as UI from "./ui";
|
||||
import * as DB from "./db";
|
||||
|
||||
let mappedRoutes = {
|
||||
"/": "pageTest",
|
||||
|
@ -36,7 +35,7 @@ $(window).on("popstate", (e) => {
|
|||
// show about
|
||||
UI.changePage("about");
|
||||
} else if (state == "account" || state == "login") {
|
||||
if (DB.currentUser()) {
|
||||
if (firebase.auth().currentUser) {
|
||||
UI.changePage("account");
|
||||
} else {
|
||||
UI.changePage("login");
|
||||
|
|
|
@ -422,7 +422,7 @@ function showActiveTags() {
|
|||
|
||||
export function updateDiscordSection() {
|
||||
//no code and no discord
|
||||
if (DB.currentUser() == null) {
|
||||
if (firebase.auth().currentUser == null) {
|
||||
$(".pageSettings .section.discordIntegration").addClass("hidden");
|
||||
} else {
|
||||
if (DB.getSnapshot() == null) return;
|
||||
|
@ -453,7 +453,7 @@ function setActiveFunboxButton() {
|
|||
}
|
||||
|
||||
function refreshTagsSettingsSection() {
|
||||
if (DB.currentUser() !== null && DB.getSnapshot() !== null) {
|
||||
if (firebase.auth().currentUser !== null && DB.getSnapshot() !== null) {
|
||||
let tagsEl = $(".pageSettings .section.tags .tagsList").empty();
|
||||
DB.getSnapshot().tags.forEach((tag) => {
|
||||
let tagPbString = "No PB found";
|
||||
|
@ -480,7 +480,7 @@ function refreshTagsSettingsSection() {
|
|||
}
|
||||
|
||||
function refreshPresetsSettingsSection() {
|
||||
if (DB.currentUser() !== null && DB.getSnapshot() !== null) {
|
||||
if (firebase.auth().currentUser !== null && DB.getSnapshot() !== null) {
|
||||
let presetsEl = $(".pageSettings .section.presets .presetsList").empty();
|
||||
DB.getSnapshot().presets.forEach((preset) => {
|
||||
presetsEl.append(`
|
||||
|
@ -649,7 +649,7 @@ $(
|
|||
).click((e) => {
|
||||
Loader.show();
|
||||
CloudFunctions.generatePairingCode({
|
||||
uid: DB.currentUser().uid,
|
||||
uid: firebase.auth().currentUser.uid,
|
||||
})
|
||||
.then((ret) => {
|
||||
Loader.hide();
|
||||
|
@ -675,7 +675,7 @@ $(".pageSettings .section.discordIntegration #unlinkDiscordButton").click(
|
|||
if (confirm("Are you sure?")) {
|
||||
Loader.show();
|
||||
CloudFunctions.unlinkDiscord({
|
||||
uid: DB.currentUser().uid,
|
||||
uid: firebase.auth().currentUser.uid,
|
||||
}).then((ret) => {
|
||||
Loader.hide();
|
||||
console.log(ret);
|
||||
|
|
|
@ -153,7 +153,7 @@ list.updateEmail = new SimplePopup(
|
|||
try {
|
||||
Loader.show();
|
||||
CloudFunctions.updateEmail({
|
||||
uid: DB.currentUser().uid,
|
||||
uid: firebase.auth().currentUser.uid,
|
||||
previousEmail: previousEmail,
|
||||
newEmail: newEmail,
|
||||
}).then((data) => {
|
||||
|
@ -190,7 +190,7 @@ list.clearTagPb = new SimplePopup(
|
|||
let tagid = eval("this.parameters[0]");
|
||||
Loader.show();
|
||||
CloudFunctions.clearTagPb({
|
||||
uid: DB.currentUser().uid,
|
||||
uid: firebase.auth().currentUser.uid,
|
||||
tagid: tagid,
|
||||
})
|
||||
.then((res) => {
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import * as CloudFunctions from "./cloud-functions";
|
||||
import * as DB from "./db";
|
||||
import * as Notifications from "./notifications";
|
||||
import Config from "./config";
|
||||
|
@ -115,7 +114,7 @@ export function show(data, mode2) {
|
|||
string = globalLbString + "<br>" + dailyLbString;
|
||||
|
||||
// CloudFunctions.saveLbMemory({
|
||||
// uid: DB.currentUser().uid,
|
||||
// uid: firebase.auth().currentUser.uid,
|
||||
// obj: DB.getSnapshot().lbMemory,
|
||||
// }).then((d) => {
|
||||
// if (d.data.returnCode === 1) {
|
||||
|
|
|
@ -316,10 +316,10 @@ export function startTest() {
|
|||
UpdateConfig.setChangedBeforeDb(true);
|
||||
}
|
||||
try {
|
||||
if (DB.currentUser() != null) {
|
||||
axiosInstance.post("/api/analytics/testStarted");
|
||||
if (firebase.auth().currentUser != null) {
|
||||
firebase.analytics().logEvent("testStarted");
|
||||
} else {
|
||||
axiosInstance.post("/api/analytics/testStartedNoLogin");
|
||||
firebase.analytics().logEvent("testStartedNoLogin");
|
||||
}
|
||||
} catch (e) {
|
||||
console.log("Analytics unavailable");
|
||||
|
@ -1404,8 +1404,8 @@ export function finish(difficultyFailed = false) {
|
|||
stats.acc > 50 &&
|
||||
stats.acc <= 100
|
||||
) {
|
||||
if (DB.currentUser() != null) {
|
||||
completedEvent.uid = DB.currentUser().uid;
|
||||
if (firebase.auth().currentUser != null) {
|
||||
completedEvent.uid = firebase.auth().currentUser.uid;
|
||||
//check local pb
|
||||
AccountButton.loading(true);
|
||||
let dontShowCrown = false;
|
||||
|
@ -1638,13 +1638,13 @@ export function finish(difficultyFailed = false) {
|
|||
}
|
||||
}
|
||||
|
||||
axiosInstance
|
||||
.post("/api/analytics/testCompleted", {
|
||||
completedEvent: completedEvent,
|
||||
})
|
||||
.catch(() => {
|
||||
console.log("Analytics unavailable");
|
||||
});
|
||||
try {
|
||||
firebase
|
||||
.analytics()
|
||||
.logEvent("testCompleted", completedEvent);
|
||||
} catch (e) {
|
||||
console.log("Analytics unavailable");
|
||||
}
|
||||
|
||||
if (e.data.resultCode === 2) {
|
||||
//new pb
|
||||
|
@ -1679,29 +1679,25 @@ export function finish(difficultyFailed = false) {
|
|||
});
|
||||
});
|
||||
} else {
|
||||
axiosInstance
|
||||
.post("/api/analytics/testCompletedNoLogin", {
|
||||
completedEvent: completedEvent,
|
||||
})
|
||||
.catch((e) => {
|
||||
console.log("Analytics unavailable");
|
||||
});
|
||||
try {
|
||||
firebase.analytics().logEvent("testCompletedNoLogin", completedEvent);
|
||||
} catch (e) {
|
||||
console.log("Analytics unavailable");
|
||||
}
|
||||
notSignedInLastResult = completedEvent;
|
||||
}
|
||||
} else {
|
||||
Notifications.add("Test invalid", 0);
|
||||
TestStats.setInvalid();
|
||||
axiosInstance
|
||||
.post("/api/analytics/testCompletedInvalid", {
|
||||
completedEvent: completedEvent,
|
||||
})
|
||||
.catch((e) => {
|
||||
console.log("Analytics unavailable");
|
||||
});
|
||||
try {
|
||||
firebase.analytics().logEvent("testCompletedInvalid", completedEvent);
|
||||
} catch (e) {
|
||||
console.log("Analytics unavailable");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (DB.currentUser() != null) {
|
||||
if (firebase.auth().currentUser != null) {
|
||||
$("#result .loginTip").addClass("hidden");
|
||||
} else {
|
||||
$("#result .stats .leaderboards").addClass("hidden");
|
||||
|
|
|
@ -192,7 +192,7 @@ export function screenshot() {
|
|||
$(".pageTest .ssWatermark").addClass("hidden");
|
||||
$(".pageTest .buttons").removeClass("hidden");
|
||||
if (revealReplay) $("#resultReplay").removeClass("hidden");
|
||||
if (DB.currentUser() == null)
|
||||
if (firebase.auth().currentUser == null)
|
||||
$(".pageTest .loginTip").removeClass("hidden");
|
||||
}
|
||||
|
||||
|
|
|
@ -96,13 +96,13 @@ export function apply(themeName) {
|
|||
});
|
||||
}
|
||||
|
||||
axiosInstance
|
||||
.post("/api/analytics/changedTheme", {
|
||||
try {
|
||||
firebase.analytics().logEvent("changedTheme", {
|
||||
theme: themeName,
|
||||
})
|
||||
.catch((e) => {
|
||||
console.log("Analytics unavailable");
|
||||
});
|
||||
} catch (e) {
|
||||
console.log("Analytics unavailable");
|
||||
}
|
||||
setTimeout(() => {
|
||||
$(".keymap-key").attr("style", "");
|
||||
ChartController.updateAllChartColors();
|
||||
|
|
|
@ -14,7 +14,6 @@ import * as Settings from "./settings";
|
|||
import * as Account from "./account";
|
||||
import * as Leaderboards from "./leaderboards";
|
||||
import * as Funbox from "./funbox";
|
||||
import * as DB from "./db";
|
||||
|
||||
export let pageTransition = false;
|
||||
|
||||
|
@ -164,8 +163,10 @@ export function changePage(page) {
|
|||
TestConfig.hide();
|
||||
SignOutButton.hide();
|
||||
} else if (page == "account") {
|
||||
if (!DB.currentUser()) {
|
||||
console.log(`current user is ${DB.currentUser()}, going back to login`);
|
||||
if (!firebase.auth().currentUser) {
|
||||
console.log(
|
||||
`current user is ${firebase.auth().currentUser}, going back to login`
|
||||
);
|
||||
changePage("login");
|
||||
} else {
|
||||
setPageTransition(true);
|
||||
|
@ -188,7 +189,7 @@ export function changePage(page) {
|
|||
TestConfig.hide();
|
||||
}
|
||||
} else if (page == "login") {
|
||||
if (DB.currentUser() != null) {
|
||||
if (firebase.auth().currentUser != null) {
|
||||
changePage("account");
|
||||
} else {
|
||||
setPageTransition(true);
|
||||
|
|
|
@ -4258,7 +4258,18 @@
|
|||
<div id="nitropay_ad_right" class="hidden"></div>
|
||||
</div>
|
||||
</body>
|
||||
<!-- The core Firebase JS SDK is always required and must be listed first -->
|
||||
<script src="/__/firebase/8.0.2/firebase-app.js"></script>
|
||||
|
||||
<!-- TODO: Add SDKs for Firebase products that you want to use
|
||||
https://firebase.google.com/docs/web/setup#available-libraries -->
|
||||
<script src="/__/firebase/8.0.2/firebase-analytics.js"></script>
|
||||
<script src="/__/firebase/8.0.2/firebase-auth.js"></script>
|
||||
<script src="/__/firebase/8.0.2/firebase-firestore.js"></script>
|
||||
<script src="/__/firebase/8.0.2/firebase-functions.js"></script>
|
||||
|
||||
<!-- Initialize Firebase -->
|
||||
<script src="/__/firebase/init.js"></script>
|
||||
<script src="js/jquery-3.5.1.min.js"></script>
|
||||
<script src="js/jquery.color.min.js"></script>
|
||||
<script src="js/easing.js"></script>
|
||||
|
|
|
@ -32896,6 +32896,12 @@
|
|||
"source": "Steins;Gate",
|
||||
"length": 247,
|
||||
"id": 5538
|
||||
},
|
||||
{
|
||||
"text": "Any fool can write code that a computer can understand. Good programmers write code that humans can understand.",
|
||||
"source": "Martin Fowler",
|
||||
"length": 111,
|
||||
"id": 5539
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
Binary file not shown.
Loading…
Add table
Reference in a new issue