From c5cae445741c00aca8caac091f0455cfa62a58b4 Mon Sep 17 00:00:00 2001 From: Steven Gao Date: Sun, 5 Jan 2025 23:38:36 -0500 Subject: [PATCH 01/26] fix webp --- routes/index.js | 2 +- src/frontend-scripts/components/section-main/Settings.jsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/routes/index.js b/routes/index.js index c12dda462..0d927592e 100644 --- a/routes/index.js +++ b/routes/index.js @@ -487,7 +487,7 @@ module.exports = () => { }); } else { ProcessImage(username, raw, (resp, err) => { - res.json({ message: err || resp }); + res.json({ message: err ? err.message : '' || resp }); }); } }) diff --git a/src/frontend-scripts/components/section-main/Settings.jsx b/src/frontend-scripts/components/section-main/Settings.jsx index 4741012e8..9b11fc6b2 100644 --- a/src/frontend-scripts/components/section-main/Settings.jsx +++ b/src/frontend-scripts/components/section-main/Settings.jsx @@ -778,7 +778,7 @@ class Settings extends React.Component { }) .then(data => { this.setState({ - cardbackUploadStatus: data.message, + cardbackUploadStatus: data.message ? data.message.toString() : '', isUploaded: data.message === 'Image uploaded successfully.' ? this.state.preview : '', preview: '' }); From b8a31cb8e6de7e8d17711be9030f83dfd586bbd0 Mon Sep 17 00:00:00 2001 From: Steven Gao Date: Tue, 7 Jan 2025 14:30:44 -0500 Subject: [PATCH 02/26] preliminary work --- models/account.js | 288 +++++++----------- routes/accounts.js | 22 +- routes/index.js | 12 +- routes/socket/models.js | 22 +- routes/socket/user-requests.js | 26 +- .../components/section-main/Players.jsx | 2 +- .../components/section-main/Profile.jsx | 8 +- views/game.pug | 2 +- 8 files changed, 147 insertions(+), 235 deletions(-) diff --git a/models/account.js b/models/account.js index bd2f448a7..8ae6e26d9 100644 --- a/models/account.js +++ b/models/account.js @@ -1,81 +1,101 @@ const mongoose = require('mongoose'); const passportLocalMongoose = require('passport-local-mongoose'); + const { Schema } = mongoose; -const Account = new Schema({ - username: { - type: String, - required: true, - unique: true + +const GameSettings = new Schema({ + playerPronouns: String, + staff: { + disableVisibleElo: Boolean, + disableVisibleXP: Boolean, + disableStaffColor: Boolean, + incognito: Boolean + }, + isRainbow: Boolean, + newReport: Boolean, + hasUnseenBadge: Boolean, + customCardback: { + fileExtension: String, // always 'png' + saveTime: String, + id: String + }, + enableTimestamps: Boolean, + enableRightSidebarInGame: Boolean, + disablePlayerColorsInChat: Boolean, + disablePlayerCardbacks: Boolean, + disableHelpMessages: Boolean, + disableHelpIcons: Boolean, + disableConfetti: Boolean, + disableCrowns: Boolean, + disableSeasonal: Boolean, + disableAggregations: Boolean, + disableKillConfirmation: Boolean, + soundStatus: String, + unbanTime: Date, + unTimeoutTime: Date, + fontSize: Number, + fontFamily: String, + isPrivate: Boolean, + privateToggleTime: Number, + blacklist: Array, + tournyWins: Array, + hasChangedName: Boolean, + previousSeasonAward: String, + specialTournamentStatus: String, + disableElo: Boolean, + fullheight: Boolean, + safeForWork: Boolean, + keyboardShortcuts: String, + notifyForNewLobby: Boolean, + gameFilters: { + public: Boolean, + private: Boolean, + unstarted: Boolean, + inProgress: Boolean, + completed: Boolean, + custom: Boolean, + casual: Boolean, + timedMode: Boolean, + standard: Boolean, + rainbow: Boolean }, + blacklist: Array, + gameNotes: { + top: Number, + left: Number, + width: Number, + height: Number + }, + playerNotes: Array, + ignoreIPBans: Boolean, + truncatedSize: Number, + claimCharacters: String, + claimButtons: String +}); + +const Stats = new Schema({ + xp: { type: Number, default: 0 }, + elo: { type: Number, default: 1600 }, + wins: { type: Number, default: 0 }, + losses: { type: Number, default: 0 }, + rainbowWins: { type: Number, default: 0 }, + rainbowLosses: { type: Number, default: 0 } +}); + +const SeasonStats = new Schema({ + type: Map, + of: Stats, + default: {} +}); + +const Account = new Schema({ + username: { type: String, required: true, unique: true }, password: String, isLocal: Boolean, staffRole: String, isContributor: Boolean, - hasNotDismissedSignupModal: Boolean, - gameSettings: { - playerPronouns: String, - staffDisableVisibleElo: Boolean, - staffDisableVisibleXP: Boolean, - staffDisableStaffColor: Boolean, - staffIncognito: Boolean, - isRainbow: Boolean, - newReport: Boolean, - hasUnseenBadge: Boolean, - customCardback: String, - customCardbackSaveTime: String, - customCardbackUid: String, - enableTimestamps: Boolean, - enableRightSidebarInGame: Boolean, - disablePlayerColorsInChat: Boolean, - disablePlayerCardbacks: Boolean, - disableHelpMessages: Boolean, - disableHelpIcons: Boolean, - disableConfetti: Boolean, - disableCrowns: Boolean, - disableSeasonal: Boolean, - disableAggregations: Boolean, - disableKillConfirmation: Boolean, - soundStatus: String, - unbanTime: Date, - unTimeoutTime: Date, - fontSize: Number, - fontFamily: String, - isPrivate: Boolean, - privateToggleTime: Number, - blacklist: Array, - tournyWins: Array, - hasChangedName: Boolean, - previousSeasonAward: String, - specialTournamentStatus: String, - disableElo: Boolean, - fullheight: Boolean, - safeForWork: Boolean, - keyboardShortcuts: String, - notifyForNewLobby: Boolean, - gameFilters: { - pub: Boolean, - priv: Boolean, - unstarted: Boolean, - inprogress: Boolean, - completed: Boolean, - customgame: Boolean, - casualgame: Boolean, - timedMode: Boolean, - standard: Boolean, - rainbow: Boolean - }, - gameNotes: { - top: Number, - left: Number, - width: Number, - height: Number - }, - playerNotes: Array, - ignoreIPBans: Boolean, - truncatedSize: Number, - claimCharacters: String, - claimButtons: String - }, + dismissedSignupModal: Boolean, + gameSettings: GameSettings, verification: { email: String }, @@ -89,98 +109,8 @@ const Account = new Schema({ touLastAgreed: String, bio: String, games: Array, - wins: Number, - losses: Number, - rainbowWins: Number, - rainbowLosses: Number, - winsSeason1: Number, - lossesSeason1: Number, - rainbowWinsSeason1: Number, - rainbowLossesSeason1: Number, - winsSeason2: Number, - lossesSeason2: Number, - rainbowWinsSeason2: Number, - rainbowLossesSeason2: Number, - winsSeason3: Number, - lossesSeason3: Number, - rainbowWinsSeason3: Number, - rainbowLossesSeason3: Number, - winsSeason4: Number, - lossesSeason4: Number, - rainbowWinsSeason4: Number, - rainbowLossesSeason4: Number, - winsSeason5: Number, - lossesSeason5: Number, - rainbowWinsSeason5: Number, - rainbowLossesSeason5: Number, - winsSeason6: Number, - lossesSeason6: Number, - rainbowWinsSeason6: Number, - rainbowLossesSeason6: Number, - winsSeason7: Number, - lossesSeason7: Number, - rainbowWinsSeason7: Number, - rainbowLossesSeason7: Number, - winsSeason8: Number, - lossesSeason8: Number, - rainbowWinsSeason8: Number, - rainbowLossesSeason8: Number, - winsSeason9: Number, - lossesSeason9: Number, - rainbowWinsSeason9: Number, - rainbowLossesSeason9: Number, - winsSeason10: Number, - lossesSeason10: Number, - rainbowWinsSeason10: Number, - rainbowLossesSeason10: Number, - winsSeason11: Number, - lossesSeason11: Number, - rainbowWinsSeason11: Number, - rainbowLossesSeason11: Number, - winsSeason12: Number, - lossesSeason12: Number, - rainbowWinsSeason12: Number, - rainbowLossesSeason12: Number, - winsSeason13: Number, - lossesSeason13: Number, - rainbowWinsSeason13: Number, - rainbowLossesSeason13: Number, - winsSeason14: Number, - lossesSeason14: Number, - rainbowWinsSeason14: Number, - rainbowLossesSeason14: Number, - winsSeason15: Number, - lossesSeason15: Number, - rainbowWinsSeason15: Number, - rainbowLossesSeason15: Number, - winsSeason16: Number, - lossesSeason16: Number, - rainbowWinsSeason16: Number, - rainbowLossesSeason16: Number, - winsSeason17: Number, - lossesSeason17: Number, - rainbowWinsSeason17: Number, - rainbowLossesSeason17: Number, - winsSeason18: Number, - lossesSeason18: Number, - rainbowWinsSeason18: Number, - rainbowLossesSeason18: Number, - winsSeason19: Number, - lossesSeason19: Number, - rainbowWinsSeason19: Number, - rainbowLossesSeason19: Number, - winsSeason20: Number, - lossesSeason20: Number, - rainbowWinsSeason20: Number, - rainbowLossesSeason20: Number, - winsSeason21: Number, - lossesSeason21: Number, - rainbowWinsSeason21: Number, - rainbowLossesSeason21: Number, - winsSeason22: Number, - lossesSeason22: Number, - rainbowWinsSeason22: Number, - rainbowLossesSeason22: Number, + overall: Stats, + seasons: SeasonStats, previousDayElo: Number, previousDayXP: Number, created: Date, @@ -188,30 +118,32 @@ const Account = new Schema({ lastCompletedGame: Date, lastVersionSeen: String, isFixed: Boolean, - eloSeason: Number, - eloOverall: Number, hashUid: String, - discordUsername: String, - discordDiscriminator: String, - discordMFA: Boolean, - discordUID: String, - githubUsername: String, - githubMFA: Boolean, - warnings: Array, // {text: String, moderator: String, time: Date, acknowledged: Boolean}, + discord: { + username: String, + discriminator: String, + mfa: Boolean, + uid: String + }, + github: { + username: String, + mfa: Boolean + }, + warnings: Array, // { text: String, moderator: String, time: Date, acknowledged: Boolean }, feedbackSubmissions: Array, // { time: Date, text: String } - primaryColor: String, - secondaryColor: String, - tertiaryColor: String, - backgroundColor: String, - textColor: String, + colors: { + primary: String, + secondary: String, + tertiary: String, + background: String, + text: String + }, eloPercentile: { seasonal: Number, overall: Number }, isRainbowSeason: Boolean, isRainbowOverall: Boolean, - xpOverall: { type: Number, default: 0 }, - xpSeason: { type: Number, default: 0 }, dateRainbowOverall: Date, badges: [{ id: String, text: String, title: String, dateAwarded: Date }], maxElo: { type: Number, default: 1600 }, diff --git a/routes/accounts.js b/routes/accounts.js index a9e0039bd..46b600e9e 100644 --- a/routes/accounts.js +++ b/routes/accounts.js @@ -262,11 +262,13 @@ const continueSignup = config => { soundStatus: 'pack2' }, verified: true, - wins: 0, - losses: 0, + overall: { + wins: 0, + losses: 0 + }, created: new Date(), signupIP: signupIP, - hasNotDismissedSignupModal: true, + dismissedSignupModal: false, verification: { email: type === 'discord' ? profile.email : profile._json.email }, @@ -390,9 +392,9 @@ module.exports.accounts = torIpsParam => { username: req.user.username, verified: req.user.verified, email: req.user.verification ? req.user.verification.email : '', - discordUsername: req.user.discordUsername, - discordDiscriminator: req.user.discordDiscriminator, - githubUsername: req.user.githubUsername + discordUsername: req.user.discord.username, + discordDiscriminator: req.user.discor.discriminator, + githubUsername: req.user.github.username }); }); @@ -467,7 +469,7 @@ module.exports.accounts = torIpsParam => { const save = { username, isLocal: true, - hasNotDismissedSignupModal: true, + dismissedSignupModal: false, gameSettings: { soundStatus: 'pack2', isPrivate @@ -477,8 +479,10 @@ module.exports.accounts = torIpsParam => { }, verified: false, games: [], - wins: 0, - losses: 0, + overall: { + wins: 0, + losses: 0 + }, created: new Date(), signupIP, lastConnectedIP: signupIP diff --git a/routes/index.js b/routes/index.js index 0d927592e..ca61f0c61 100644 --- a/routes/index.js +++ b/routes/index.js @@ -168,8 +168,8 @@ module.exports = () => { checkBadgesAccount(account); const { blacklist } = account.gameSettings; - const backgroundColor = account.backgroundColor || DEFAULTTHEMECOLORS.baseBackgroundColor; - const textColor = account.textColor || DEFAULTTHEMECOLORS.baseTextColor; + const backgroundColor = account.colors.background || DEFAULTTHEMECOLORS.baseBackgroundColor; + const textColor = account.colors.text || DEFAULTTHEMECOLORS.baseTextColor; const [backgroundHue, backgroundSaturation, backgroundLightness] = getHSLcolors(backgroundColor); const [textHue, textSaturation, textLightness] = getHSLcolors(textColor); @@ -182,13 +182,13 @@ module.exports = () => { isContributor: account.isContributor || false, isTournamentMod: account.isTournamentMod || false, verified: req.user.verified, - hasNotDismissedSignupModal: account.hasNotDismissedSignupModal, + dismissedSignupModal: account.dismissedSignupModal, username, gameSettings: gameSettingsWithoutBlacklist, blacklist, - primaryColor: account.primaryColor || DEFAULTTHEMECOLORS.primaryColor, - secondaryColor: account.secondaryColor || DEFAULTTHEMECOLORS.secondaryColor, - tertiaryColor: account.tertiaryColor || DEFAULTTHEMECOLORS.tertiaryColor, + primaryColor: account.colors.primary || DEFAULTTHEMECOLORS.primaryColor, + secondaryColor: account.colors.secondary || DEFAULTTHEMECOLORS.secondaryColor, + tertiaryColor: account.colors.tertiary || DEFAULTTHEMECOLORS.tertiaryColor, backgroundColor, secondaryBackgroundColor: `hsl(${backgroundHue}, ${backgroundSaturation}%, ${ backgroundLightness > 50 ? backgroundLightness - 7 : backgroundLightness + 7 diff --git a/routes/socket/models.js b/routes/socket/models.js index 38a0c579b..8b3d2fa02 100644 --- a/routes/socket/models.js +++ b/routes/socket/models.js @@ -147,14 +147,7 @@ module.exports.formattedUserList = isAEM => { .map(user => ({ userName: user.userName, playerPronouns: user.playerPronouns, - wins: prune(user.wins), - losses: prune(user.losses), - rainbowWins: prune(user.rainbowWins), - rainbowLosses: prune(user.rainbowLosses), isPrivate: prune(user.isPrivate), - staffDisableVisibleElo: prune(user.staffDisableVisibleElo), - staffDisableVisibleXP: prune(user.staffDisableVisibleXP), - staffDisableStaffColor: prune(user.staffDisableStaffColor), // Tournaments are disabled, no point sending this. // tournyWins: user.tournyWins, @@ -162,27 +155,20 @@ module.exports.formattedUserList = isAEM => { // Blacklists are sent in the sendUserGameSettings event. // blacklist: user.blacklist, customCardback: user.customCardback, - customCardbackUid: user.customCardbackUid, - eloOverall: user.eloOverall ? Math.floor(user.eloOverall) : undefined, - xpOverall: user.xpOverall ? Math.floor(user.xpOverall) : undefined, - eloSeason: user.eloSeason ? Math.floor(user.eloSeason) : undefined, - xpSeason: user.xpSeason ? Math.floor(user.xpSeason) : undefined, + overall: user.overall, isRainbowOverall: user.isRainbowOverall, isRainbowSeason: user.isRainbowSeason, status: user.status && user.status.type && user.status.type != 'none' ? user.status : undefined, - winsSeason: prune(user[`winsSeason${CURRENTSEASONNUMBER}`]), - lossesSeason: prune(user[`lossesSeason${CURRENTSEASONNUMBER}`]), - rainbowWinsSeason: prune(user[`rainbowWinsSeason${CURRENTSEASONNUMBER}`]), - rainbowLossesSeason: prune(user[`rainbowLossesSeason${CURRENTSEASONNUMBER}`]), + season: user.seasons ? user.seasons[CURRENTSEASONNUMBER] : {}, previousSeasonAward: user.previousSeasonAward, specialTournamentStatus: user.specialTournamentStatus, timeLastGameCreated: user.timeLastGameCreated, staffRole: prune(user.staffRole), - staffIncognito: prune(user.staffIncognito), + staff: user.staff, isContributor: prune(user.isContributor) // oldData: user })) - .filter(user => isAEM || !user.staffIncognito); + .filter(user => isAEM || !user.staff || !user.staff.incognito); }; const userListEmitter = { diff --git a/routes/socket/user-requests.js b/routes/socket/user-requests.js index d03eb9a98..0df9affd9 100644 --- a/routes/socket/user-requests.js +++ b/routes/socket/user-requests.js @@ -203,37 +203,27 @@ module.exports.sendUserGameSettings = socket => { playerPronouns: account.gameSettings.playerPronouns, staffRole: account.staffRole || '', isContributor: account.isContributor || false, - staffDisableVisibleElo: account.gameSettings.staffDisableVisibleElo, - staffDisableVisibleXP: account.gameSettings.staffDisableVisibleXP, - staffDisableStaffColor: account.gameSettings.staffDisableStaffColor, - staffIncognito: account.gameSettings.staffIncognito, - wins: account.wins, - losses: account.losses, - rainbowWins: account.rainbowWins, - rainbowLosses: account.rainbowLosses, + staffDisableVisibleElo: account.gameSettings.staff.disableVisibleElo, + staffDisableVisibleXP: account.gameSettings.staff.disableVisibleXP, + staffDisableStaffColor: account.gameSettings.staff.disableStaffColor, + staffIncognito: account.gameSettings.staff.incognito, isRainbowOverall: account.isRainbowOverall, isRainbowSeason: account.isRainbowSeason, isPrivate: account.gameSettings.isPrivate, tournyWins: account.gameSettings.tournyWins, blacklist: account.gameSettings.blacklist, - customCardback: account.gameSettings.customCardback, - customCardbackUid: account.gameSettings.customCardbackUid, + customCardback: account.gameSettings.customCardback.fileExtension, + customCardbackUid: account.gameSettings.customCardback.id, previousSeasonAward: account.gameSettings.previousSeasonAward, specialTournamentStatus: account.gameSettings.specialTournamentStatus, - eloOverall: account.eloOverall, - xpOverall: account.xpOverall, - eloSeason: account.eloSeason, - xpSeason: account.xpSeason, + overall: account.overall, + season: account.seasons ? account.seasons[CURRENTSEASONNUMBER] : {}, status: { type: 'none', gameId: null } }; - userListInfo[`winsSeason${CURRENTSEASONNUMBER}`] = account[`winsSeason${CURRENTSEASONNUMBER}`]; - userListInfo[`lossesSeason${CURRENTSEASONNUMBER}`] = account[`lossesSeason${CURRENTSEASONNUMBER}`]; - userListInfo[`rainbowWinsSeason${CURRENTSEASONNUMBER}`] = account[`rainbowWinsSeason${CURRENTSEASONNUMBER}`]; - userListInfo[`rainbowLossesSeason${CURRENTSEASONNUMBER}`] = account[`rainbowLossesSeason${CURRENTSEASONNUMBER}`]; userList.push(userListInfo); sendUserList(); } diff --git a/src/frontend-scripts/components/section-main/Players.jsx b/src/frontend-scripts/components/section-main/Players.jsx index afabf33a4..ab526e1e6 100644 --- a/src/frontend-scripts/components/section-main/Players.jsx +++ b/src/frontend-scripts/components/section-main/Players.jsx @@ -306,7 +306,7 @@ class Players extends React.Component { (!gameInfo.general.private || isStaff || userInfo.isSeated) && (!userInfo.userName || !(userInfo.userName && userInfo.gameSettings && userInfo.gameSettings.disablePlayerCardbacks)) ? { - backgroundImage: `url(../images/custom-cardbacks/${player.userName}.${player.customCardback}?${player.customCardbackUid})` + backgroundImage: `url(../images/custom-cardbacks/${player.userName}.${player.customCardback.fileExtension}?${player.customCardback.id})` } : { backgroundImage: `url(../images/default_cardback.png)` diff --git a/src/frontend-scripts/components/section-main/Profile.jsx b/src/frontend-scripts/components/section-main/Profile.jsx index 4cc37040c..b87836968 100644 --- a/src/frontend-scripts/components/section-main/Profile.jsx +++ b/src/frontend-scripts/components/section-main/Profile.jsx @@ -76,13 +76,13 @@ class ProfileWrapper extends React.Component { rows={[ [ 'Elo', - this.props.profile.staffDisableVisibleElo ? '---' : this.props.profile.eloSeason || 1600, - this.props.profile.staffDisableVisibleElo ? '---' : this.props.profile.eloOverall || 1600 + this.props.profile.staffDisableVisibleElo ? '---' : this.props.profile.seasons[this.props.profile.seasons.length - 1].elo || 1600, + this.props.profile.staffDisableVisibleElo ? '---' : this.props.profile.overall.elo || 1600 ], [ 'XP', - this.props.profile.staffDisableVisibleXP ? '---' : this.props.profile.xpSeason || 0, - this.props.profile.staffDisableVisibleXP ? '---' : this.props.profile.xpOverall || 0 + this.props.profile.staffDisableVisibleXP ? '---' : this.props.profile.seasons[this.props.profile.seasons.length - 1].xp || 0, + this.props.profile.staffDisableVisibleXP ? '---' : this.props.profile.overall.xp || 0 ] ]} /> diff --git a/views/game.pug b/views/game.pug index 8e530451d..183b6a4a9 100644 --- a/views/game.pug +++ b/views/game.pug @@ -15,7 +15,7 @@ block content var gameSettings = !{JSON.stringify(gameSettings).replace(/<\//g, '<\\/')} var verified = #{verified} var staffRole = '#{staffRole}' - var hasNotDismissedSignupModal = #{hasNotDismissedSignupModal} + var dismissedSignupModal = #{dismissedSignupModal} var isTournamentMod = #{isTournamentMod} gameSettings.blacklist = !{JSON.stringify(blacklist).replace(/<\//g, '<\\/')} From 351f755c8aa1777dda7b89a2f9d2bbfd97207c81 Mon Sep 17 00:00:00 2001 From: Steven Gao Date: Wed, 8 Jan 2025 00:05:46 -0500 Subject: [PATCH 03/26] some work done, mostly to move staff --- routes/image-processor.js | 24 +- routes/index.js | 216 ++++++++++++------ routes/socket/user-events/chat.js | 4 +- routes/socket/user-events/join-game.js | 4 +- routes/socket/user-events/mod-dms.js | 2 +- routes/socket/user-events/settings.js | 28 +-- routes/socket/user-requests.js | 5 +- .../components/section-main/Creategame.jsx | 2 +- .../section-main/DisplayLobbies.jsx | 16 +- .../components/section-main/Players.jsx | 2 +- .../components/section-main/Profile.jsx | 10 +- .../components/section-main/Settings.jsx | 71 ++++-- .../components/section-right/Playerlist.jsx | 52 +++-- src/frontend-scripts/constants.js | 7 +- src/frontend-scripts/node-constants.js | 8 +- 15 files changed, 289 insertions(+), 162 deletions(-) diff --git a/routes/image-processor.js b/routes/image-processor.js index af53337eb..702547c45 100644 --- a/routes/image-processor.js +++ b/routes/image-processor.js @@ -13,44 +13,56 @@ module.exports.ProcessImage = (username, raw, callback) => { callback(null, err); return; } + img.resize(70, 95).getBuffer(Jimp.MIME_PNG, (err2, buff) => { if (err2) { callback(null, err2); return; } + const streamPass = new Stream.PassThrough(); streamPass.end(buff); streamPass .pipe(new Crusher(['-brute', '-rem', 'alla', '-c', '2', '-force', '-fix'])) .pipe(fs.createWriteStream(`public/images/custom-cardbacks/${username}.png`)); + Account.findOne({ username: username }).then(account => { - account.gameSettings.customCardback = 'png'; - account.gameSettings.customCardbackSaveTime = Date.now().toString(); - account.gameSettings.customCardbackUid = Math.random() + account.gameSettings.customCardback = account.gameSettings.customCardback || {}; + account.gameSettings.customCardback.fileExtension = 'png'; + account.gameSettings.customCardback.saveTime = Date.now().toString(); + account.gameSettings.customCardback.id = Math.random() .toString(36) .substring(2); + account.save(() => { const user = userList.find(u => u.userName === username); + if (user) { - user.customCardback = 'png'; - user.customCardbackUid = account.gameSettings.customCardbackUid; + user.customCardback = user.customCardback || {}; + user.customCardback.fileExtension = 'png'; + user.customCardback.id = account.gameSettings.customCardback.id; userListEmitter.send = true; } + Object.keys(games).forEach(uid => { const game = games[uid]; const foundUser = game.publicPlayersState.find(user => user.userName === username); + if (foundUser) { - foundUser.customCardback = ''; + foundUser.customCardback = {}; // reset cardback? sendCommandChatsUpdate(game); sendGameList(); } }); + const socketId = Object.keys(io.sockets.sockets).find( socketId => io.sockets.sockets[socketId].handshake.session.passport && io.sockets.sockets[socketId].handshake.session.passport.user === username ); + if (socketId && io.sockets.sockets[socketId]) { io.sockets.sockets[socketId].emit('gameSettings', account.gameSettings); } + callback('Image uploaded successfully.'); }); }); diff --git a/routes/index.js b/routes/index.js index ca61f0c61..18b86a34c 100644 --- a/routes/index.js +++ b/routes/index.js @@ -13,7 +13,7 @@ const { ProcessImage } = require('./image-processor'); const savedTorIps = require('../utils/savedtorips'); const fetch = require('node-fetch'); const prodCacheBustToken = require('./prodCacheBustToken'); -const { DEFAULTTHEMECOLORS } = require('../src/frontend-scripts/node-constants'); +const { DEFAULTTHEMECOLORS, CURRENTSEASONNUMBER } = require('../src/frontend-scripts/node-constants'); const { checkBadgesAccount } = require('./socket/badges'); const moment = require('moment'); @@ -165,6 +165,7 @@ module.exports = () => { console.log(err); return; } + checkBadgesAccount(account); const { blacklist } = account.gameSettings; @@ -173,7 +174,8 @@ module.exports = () => { const [backgroundHue, backgroundSaturation, backgroundLightness] = getHSLcolors(backgroundColor); const [textHue, textSaturation, textLightness] = getHSLcolors(textColor); - const gameSettingsWithoutBlacklist = Object.assign({}, account.gameSettings); + const gameSettingsWithoutBlacklist = { ...account.gameSettings }; + delete gameSettingsWithoutBlacklist.blacklist; const gameObj = { @@ -207,6 +209,7 @@ module.exports = () => { account.lastConnectedIP = ip; account.lastConnected = new Date(); + if ( (account.ipHistory && account.ipHistory.length === 0) || (account.ipHistory.length > 0 && account.ipHistory[account.ipHistory.length - 1].ip !== ip) @@ -216,6 +219,7 @@ module.exports = () => { ip: ip }); } + account.save(() => { res.render('game', gameObj); }); @@ -280,82 +284,156 @@ module.exports = () => { const username = req.query.username; getProfile(username).then(profile => { + let _profile; + if (!profile) { - res.status(404).send('Profile not found'); - } else { - Account.findOne({ username }, (err, account) => { - const _profile = profile.toObject(); + const noData = { + events: 0, + successes: 0 + }; + + const noTeamData = { + fascist: noData, + liberal: noData + }; - if (err) { - return new Error(err); + const noPlayerNumberData = { + 5: noTeamData, + 6: noTeamData, + 7: noTeamData, + 8: noTeamData, + 9: noTeamData, + 10: noTeamData, + fascist: noData, + liberal: noData + }; + + _profile = { + recentGames: [], + stats: { + actions: { + legacyShotAccuracy: noData, + legacyVoteAccuracy: noData, + shotAccuracy: noData, + voteAccuracy: noData + }, + matches: { + allMatches: noData, + casualMatches: noTeamData, + emoteMatches: noTeamData, + fascist: noData, + greyMatches: noPlayerNumberData, + legacyMatches: noData, + liberal: noData, + practiceMatches: noTeamData, + rainbowMatches: noPlayerNumberData, + silentMatches: noTeamData + } } - if (account) { - _profile.created = moment(account.created).format('MM/DD/YYYY'); - _profile.customCardback = account.gameSettings.customCardback; - _profile.bio = account.bio; - _profile.lastConnected = !!account.lastConnected ? moment(account.lastConnected).format('MM/DD/YYYY') : ''; - _profile.badges = account.badges || []; - _profile.eloPercentile = Object.keys(account.eloPercentile).length ? account.eloPercentile : undefined; - _profile.maxElo = account.gameSettings.staffDisableVisibleElo ? undefined : Math.round(Number.parseFloat(account.maxElo || 1600)); - _profile.pastElo = account.gameSettings.staffDisableVisibleElo + }; + } else { + _profile = profile.toObject(); + } + + Account.findOne({ username }, (err, account) => { + if (err) { + return new Error(err); + } + + if (account) { + _profile.created = moment(account.created).format('MM/DD/YYYY'); + _profile.customCardback = account.gameSettings.customCardback; + _profile.bio = account.bio; + _profile.lastConnected = !!account.lastConnected ? moment(account.lastConnected).format('MM/DD/YYYY') : ''; + _profile.badges = account.badges || []; + _profile.eloPercentile = Object.keys(account.eloPercentile).length ? account.eloPercentile : undefined; + _profile.maxElo = + account.gameSettings.staff && account.gameSettings.staff.disableVisibleElo ? undefined : Math.round(Number.parseFloat(account.maxElo || 1600)); + _profile.pastElo = + account.gameSettings.staff && account.gameSettings.staff.disableVisibleElo ? undefined : account.pastElo.toObject().length ? account.pastElo.toObject() : [{ date: new Date(), value: Math.round(Number.parseFloat(account.eloOverall || 1600)) }]; - _profile.xpOverall = account.gameSettings.staffDisableVisibleXP ? undefined : Math.floor(account.xpOverall || 0); - _profile.eloOverall = account.gameSettings.staffDisableVisibleElo ? undefined : Math.floor(account.eloOverall || 1600); - _profile.xpSeason = account.gameSettings.staffDisableVisibleXP ? undefined : Math.floor(account.xpSeason || 0); - _profile.eloSeason = account.gameSettings.staffDisableVisibleElo ? undefined : Math.floor(account.eloSeason || 1600); - _profile.isRainbowOverall = account.isRainbowOverall; - _profile.isRainbowSeason = account.isRainbowSeason; - _profile.staffRole = account.staffRole; - _profile.staffDisableVisibleXP = account.gameSettings.staffDisableVisibleXP; - _profile.staffDisableVisibleElo = account.gameSettings.staffDisableVisibleElo; - _profile.playerPronouns = account.gameSettings.playerPronouns || ''; - - Account.findOne({ username: authedUser }).then(acc => { - if (acc && account.username === acc.username) { - acc.gameSettings.hasUnseenBadge = false; - acc.save(); + + _profile.overall = account.overall; + + const defaultSeason = { + wins: 0, + losses: 0, + rainbowWins: 0, + rainbowLosses: 0, + elo: 1600, + xp: 0 + }; + + _profile.season = account.seasons ? account.seasons[CURRENTSEASONNUMBER] || defaultSeason : defaultSeason; + + if (account.staffRole) { + if (account.gameSettings.staff && account.gameSettings.staff.disableVisibleElo) { + delete _profile.overall.elo; + delete _profile.season.elo; + } + + if (account.gameSettings.staff && account.gameSettings.staff.disableVisibleXP) { + delete _profile.overall.xp; + delete _profile.season.xp; + } + } + + _profile.isRainbowOverall = account.isRainbowOverall; + _profile.isRainbowSeason = account.isRainbowSeason; + _profile.staffRole = account.staffRole; + _profile.staffDisableVisibleXP = account.gameSettings.staff && account.gameSettings.staff.disableVisibleXP; + _profile.staffDisableVisibleElo = account.gameSettings.staff && account.gameSettings.staff.disableVisibleElo; + _profile.playerPronouns = account.gameSettings.playerPronouns || ''; + + Account.findOne({ username: authedUser }).then(acc => { + if (acc && account.username === acc.username) { + acc.gameSettings.hasUnseenBadge = false; + acc.save(); + } + + if ( + acc && + acc.staffRole && + (acc.staffRole === 'moderator' || acc.staffRole === 'editor' || acc.staffRole === 'admin' || acc.staffRole === 'trialmod') + ) { + try { + _profile.lastConnectedIP = '-' + obfIP(account.lastConnectedIP); + } catch (e) { + _profile.lastConnectedIP = "Couldn't find IP"; + console.log(e); } - if ( - acc && - acc.staffRole && - (acc.staffRole === 'moderator' || acc.staffRole === 'editor' || acc.staffRole === 'admin' || acc.staffRole === 'trialmod') - ) { - try { - _profile.lastConnectedIP = '-' + obfIP(account.lastConnectedIP); - } catch (e) { - _profile.lastConnectedIP = "Couldn't find IP"; - console.log(e); - } - try { - _profile.signupIP = '-' + obfIP(account.signupIP); - } catch (e) { - _profile.signupIP = "Couldn't find IP"; - console.log(e); - } - _profile.lastConnected = moment(account.lastConnected).format('MM/DD/YYYY h:mm'); - _profile.created = moment(account.created).format('MM/DD/YYYY h:mm'); - if (acc.staffRole !== 'trialmod') { - _profile.blacklist = account.gameSettings.blacklist; - } - } else { - _profile.lastConnectedIP = undefined; - _profile.signupIP = undefined; + + try { + _profile.signupIP = '-' + obfIP(account.signupIP); + } catch (e) { + _profile.signupIP = "Couldn't find IP"; + console.log(e); } - if (account.gameSettings.isPrivate && !_profile.lastConnectedIP) { - // They are private and lastConnectedIP is set to undefined (ie. requester is not AEM) - res.status(404).send('Profile not found'); - return; + _profile.lastConnected = moment(account.lastConnected).format('MM/DD/YYYY h:mm'); + _profile.created = moment(account.created).format('MM/DD/YYYY h:mm'); + + if (acc.staffRole !== 'trialmod') { + _profile.blacklist = account.gameSettings.blacklist; } + } else { + _profile.lastConnectedIP = undefined; + _profile.signupIP = undefined; + } - res.json(_profile); - }); - } - }); - } + if (account.gameSettings.isPrivate && !_profile.lastConnectedIP) { + // They are private and lastConnectedIP is set to undefined (ie. requester is not AEM) + res.status(404).send('Profile not found'); + return; + } + + res.json(_profile); + }); + } + }); }); }); @@ -474,13 +552,15 @@ module.exports = () => { Account.findOne({ username }) .then(account => { + account.gameSettings.customCardback = account.gameSettings.customCardback || {}; + if (!account.isRainbowOverall) { res.json({ message: 'You need to be rainbow to upload a cardback.' }); } else if ( - new Date(account.gameSettings.customCardbackSaveTime) && - Date.now() - new Date(account.gameSettings.customCardbackSaveTime).getTime() < 30000 + new Date(account.gameSettings.customCardback.saveTime) && + Date.now() - new Date(account.gameSettings.customCardback.saveTime).getTime() < 30000 ) { res.json({ message: 'You can only change your cardback once every 30 seconds.' diff --git a/routes/socket/user-events/chat.js b/routes/socket/user-events/chat.js index 93e550e36..062049990 100644 --- a/routes/socket/user-events/chat.js +++ b/routes/socket/user-events/chat.js @@ -118,7 +118,7 @@ module.exports.handleNewGeneralChat = async (socket, passport, data, modUserName const staffUserNames = [...modUserNames, ...editorUserNames, ...adminUserNames]; const AEM = staffUserNames.includes(passport.user) || newStaff.modUserNames.includes(passport.user) || newStaff.editorUserNames.includes(passport.user); - if (AEM && user.staffIncognito) { + if (AEM && user.staff && user.staff.incognito) { newChat.hiddenUsername = newChat.userName; newChat.staffRole = 'moderator'; newChat.userName = 'Incognito'; @@ -364,7 +364,7 @@ module.exports.handleAddNewGameChat = async (socket, passport, data, game, modUs return 'admin'; } })(); - if (AEM && user.staffIncognito) { + if (AEM && user.staff && user.staff.incognito) { data.hiddenUsername = data.userName; data.staffRole = 'moderator'; data.userName = 'Incognito'; diff --git a/routes/socket/user-events/join-game.js b/routes/socket/user-events/join-game.js index a0f1cf8f1..6667c73bb 100644 --- a/routes/socket/user-events/join-game.js +++ b/routes/socket/user-events/join-game.js @@ -55,9 +55,7 @@ const updateSeatedUser = (socket, passport, data) => { tournyWins: account.gameSettings.tournyWins, previousSeasonAward: account.gameSettings.previousSeasonAward, specialTournamentStatus: account.gameSettings.specialTournamentStatus, - staffDisableVisibleElo: account.gameSettings.staffDisableVisibleElo, - staffDisableVisibleXP: account.gameSettings.staffDisableVisibleXP, - staffDisableStaffColor: account.gameSettings.staffDisableStaffColor, + staff: account.gameSettings.staff, cardStatus: { cardDisplayed: false, isFlipped: false, diff --git a/routes/socket/user-events/mod-dms.js b/routes/socket/user-events/mod-dms.js index 10c6aecb1..bd5c58ba8 100644 --- a/routes/socket/user-events/mod-dms.js +++ b/routes/socket/user-events/mod-dms.js @@ -9,7 +9,7 @@ module.exports.handleOpenChat = (socket, data, modUserNames, editorUserNames, ad if (data.aemMember !== passport.user) return; const aemMember = userList.find(x => x.userName === data.aemMember); - if (aemMember && aemMember.staffIncognito) { + if (aemMember && aemMember.staff && aemMember.staff.incognito) { socket.emit('sendAlert', 'You cannot start or join a chat while Incognito.'); return; } diff --git a/routes/socket/user-events/settings.js b/routes/socket/user-events/settings.js index 61e79df53..bcb21f7a2 100644 --- a/routes/socket/user-events/settings.js +++ b/routes/socket/user-events/settings.js @@ -85,28 +85,17 @@ module.exports.handleUpdatedGameSettings = (socket, passport, data) => { 'claimButtons' ]; - if ( - allowedSettings.includes(setting) || - (setting === 'staffDisableVisibleElo' && (aem || veteran)) || - (setting === 'staffDisableVisibleXP' && (aem || veteran)) || - (setting === 'staffIncognito' && aem) || - (setting === 'staffDisableStaffColor' && (aem || veteran)) - ) { + if (allowedSettings.includes(setting) || (setting === 'staff' && (aem || veteran))) { account.gameSettings[setting] = data[setting]; } - if (setting === 'staffIncognito' && aem) { + if (setting === 'staff' && aem) { const userListInfo = { userName: passport.user, playerPronouns: account.gameSettings.playerPronouns, staffRole: account.staffRole || '', isContributor: account.isContributor || false, - staffDisableVisibleElo: account.gameSettings.staffDisableVisibleElo, - staffDisableVisibleXP: account.gameSettings.staffDisableVisibleXP, - staffDisableStaffColor: account.gameSettings.staffDisableStaffColor, - staffIncognito: account.gameSettings.staffIncognito, - wins: account.wins, - losses: account.losses, + staff: account.gameSettings.staff, rainbowWins: account.rainbowWins, rainbowLosses: account.rainbowLosses, isRainbowOverall: account.isRainbowOverall, @@ -118,20 +107,15 @@ module.exports.handleUpdatedGameSettings = (socket, passport, data) => { customCardbackUid: account.gameSettings.customCardbackUid, previousSeasonAward: account.gameSettings.previousSeasonAward, specialTournamentStatus: account.gameSettings.specialTournamentStatus, - eloOverall: account.eloOverall, - xpOverall: account.xpOverall, - eloSeason: account.eloSeason, - xpSeason: account.xpSeason, + overall: account.overall, + season: {}, status: { type: 'none', gameId: null } }; - userListInfo[`winsSeason${currentSeasonNumber}`] = account[`winsSeason${currentSeasonNumber}`]; - userListInfo[`lossesSeason${currentSeasonNumber}`] = account[`lossesSeason${currentSeasonNumber}`]; - userListInfo[`rainbowWinsSeason${currentSeasonNumber}`] = account[`rainbowWinsSeason${currentSeasonNumber}`]; - userListInfo[`rainbowLossesSeason${currentSeasonNumber}`] = account[`rainbowLossesSeason${currentSeasonNumber}`]; + userListInfo.season = account.seasons ? account.seasons[currentSeasonNumber] : {}; if (userIdx !== -1) userList.splice(userIdx, 1); userList.push(userListInfo); sendUserList(); diff --git a/routes/socket/user-requests.js b/routes/socket/user-requests.js index 0df9affd9..4381b4851 100644 --- a/routes/socket/user-requests.js +++ b/routes/socket/user-requests.js @@ -203,10 +203,7 @@ module.exports.sendUserGameSettings = socket => { playerPronouns: account.gameSettings.playerPronouns, staffRole: account.staffRole || '', isContributor: account.isContributor || false, - staffDisableVisibleElo: account.gameSettings.staff.disableVisibleElo, - staffDisableVisibleXP: account.gameSettings.staff.disableVisibleXP, - staffDisableStaffColor: account.gameSettings.staff.disableStaffColor, - staffIncognito: account.gameSettings.staff.incognito, + staff: account.gameSettings.staff, isRainbowOverall: account.isRainbowOverall, isRainbowSeason: account.isRainbowSeason, isPrivate: account.gameSettings.isPrivate, diff --git a/src/frontend-scripts/components/section-main/Creategame.jsx b/src/frontend-scripts/components/section-main/Creategame.jsx index 6b92f6963..c1401ee30 100644 --- a/src/frontend-scripts/components/section-main/Creategame.jsx +++ b/src/frontend-scripts/components/section-main/Creategame.jsx @@ -1772,7 +1772,7 @@ export default class Creategame extends React.Component { // Can happen when refreshing. const player = userList.list.find(p => p.userName === userInfo.userName); if (!player) errs.push('Not logged in, please refresh.'); - if (player && player.staffIncognito) errs.push(`You're incognito`); + if (player && player.staff && player.staff.incognito) errs.push(`You're incognito`); else if (this.state.isEloLimited) { const playerElo = (player && player.eloSeason && Math.min(2100, player.eloSeason)) || 1600; const playerEloNonseason = (player && player.eloOverall && Math.min(2100, player.eloOverall)) || 1600; diff --git a/src/frontend-scripts/components/section-main/DisplayLobbies.jsx b/src/frontend-scripts/components/section-main/DisplayLobbies.jsx index 154a2f7b7..d64979bae 100644 --- a/src/frontend-scripts/components/section-main/DisplayLobbies.jsx +++ b/src/frontend-scripts/components/section-main/DisplayLobbies.jsx @@ -358,12 +358,16 @@ const DisplayLobbies = props => { const userStats = userList.list ? userList.list.find(el => el.userName === player.userName) : null; if (userStats) { - players[index].wins = userStats.wins; - players[index].losses = userStats.losses; - players[index].winsSeason = userStats.winsSeason; - players[index].lossesSeason = userStats.lossesSeason; - players[index].eloOverall = userStats.eloOverall; - players[index].eloSeason = userStats.eloSeason; + players[index].wins = userStats.overall.wins; + players[index].losses = userStats.overall.losses; + players[index].eloOverall = userStats.overall.elo; + + if (userStats.season) { + players[index].winsSeason = userStats.season.wins; + players[index].lossesSeason = userStats.season.losses; + players[index].eloSeason = userStats.season.elo; + } + players[index].isRainbowOverall = userStats.isRainbowOverall; players[index].isRainbowSeason = userStats.isRainbowSeason; players[index].staffRole = userStats.staffRole; diff --git a/src/frontend-scripts/components/section-main/Players.jsx b/src/frontend-scripts/components/section-main/Players.jsx index ab526e1e6..806ec0df5 100644 --- a/src/frontend-scripts/components/section-main/Players.jsx +++ b/src/frontend-scripts/components/section-main/Players.jsx @@ -499,7 +499,7 @@ class Players extends React.Component { const user = userList.list ? userList.list.find(user => user.userName === userInfo.userName) : null; if (userInfo.userName) { - if (user && user.staffIncognito) { + if (user && user.staff && user.staff.incognito) { $(this.incognitoModal).modal('show'); } else if (userInfo.gameSettings.unbanTime && new Date(userInfo.gameSettings.unbanTime) > new Date()) { Swal.fire('Sorry, this service is currently unavailable.'); diff --git a/src/frontend-scripts/components/section-main/Profile.jsx b/src/frontend-scripts/components/section-main/Profile.jsx index b87836968..f8393adde 100644 --- a/src/frontend-scripts/components/section-main/Profile.jsx +++ b/src/frontend-scripts/components/section-main/Profile.jsx @@ -23,6 +23,7 @@ const mapDispatchToProps = dispatch => ({ class ProfileWrapper extends React.Component { constructor(props) { super(props); + this.state = { bioStatus: 'displayed', blacklistClicked: false, @@ -40,6 +41,7 @@ class ProfileWrapper extends React.Component { if (name !== newName) { updatedState = { ...updatedState, profileUser: newName, blacklistClicked: false }; } + return updatedState; } @@ -76,13 +78,13 @@ class ProfileWrapper extends React.Component { rows={[ [ 'Elo', - this.props.profile.staffDisableVisibleElo ? '---' : this.props.profile.seasons[this.props.profile.seasons.length - 1].elo || 1600, - this.props.profile.staffDisableVisibleElo ? '---' : this.props.profile.overall.elo || 1600 + this.props.profile.staff && this.props.profile.staff.disableVisibleElo ? '---' : this.props.profile.season.elo || 1600, + this.props.profile.staff && this.props.profile.staff.disableVisibleElo ? '---' : this.props.profile.overall.elo || 1600 ], [ 'XP', - this.props.profile.staffDisableVisibleXP ? '---' : this.props.profile.seasons[this.props.profile.seasons.length - 1].xp || 0, - this.props.profile.staffDisableVisibleXP ? '---' : this.props.profile.overall.xp || 0 + this.props.profile.staff && this.props.profile.staff.disableVisibleXP ? '---' : this.props.profile.season.xp || 0, + this.props.profile.staff && this.props.profile.staff.disableVisibleXP ? '---' : this.props.profile.overall.xp || 0 ] ]} /> diff --git a/src/frontend-scripts/components/section-main/Settings.jsx b/src/frontend-scripts/components/section-main/Settings.jsx index 9b11fc6b2..3470bd62e 100644 --- a/src/frontend-scripts/components/section-main/Settings.jsx +++ b/src/frontend-scripts/components/section-main/Settings.jsx @@ -44,10 +44,12 @@ class Settings extends React.Component { isPrivate: '', failedNameChangeMessage: '', soundSelected: 'Pack 1', - staffDisableVisibleElo: '', - staffDisableVisibleXP: '', - staffDisableStaffColor: '', - staffIncognito: '', + staff: { + disableVisibleElo: '', + disableVisibleXP: '', + disableStaffColor: '', + incognito: '' + }, fullheight: false, truncatedSize: 250, safeForWork: false, @@ -92,10 +94,13 @@ class Settings extends React.Component { isPrivate: gameSettings.isPrivate || '', fullheight: gameSettings.fullheight || false, soundSelected: gameSettings.soundStatus || 'Off', - staffDisableVisibleElo: gameSettings.staffDisableVisibleElo || false, - staffDisableVisibleXP: gameSettings.staffDisableVisibleXP || false, - staffDisableStaffColor: gameSettings.staffDisableStaffColor || false, - staffIncognito: gameSettings.staffIncognito || false, + staff: { + disableVisibleElo: false, + disableVisibleXP: false, + disableStaffColor: false, + incognito: false, + ...(gameSettings.staff || {}) + }, truncatedSize: gameSettings.truncatedSize || 250, safeForWork: gameSettings.safeForWork || false, keyboardShortcuts: gameSettings.keyboardShortcuts || 'disable', @@ -716,6 +721,7 @@ class Settings extends React.Component { this.setState({ cardbackUploadStatus: 'Cropping...' }); + try { const img = new Image(); img.onload = () => { @@ -1083,8 +1089,15 @@ class Settings extends React.Component { this.toggleGameSettings('staffDisableStaffColor')} + checked={Boolean(this.state.staff.disableStaffColor)} + onChange={() => { + const obj = { + staff: this.state.staff + }; + obj.staff.disableStaffColor = !obj.staff.disableStaffColor; + this.props.socket.emit('updateGameSettings', obj); + this.setState(obj); + }} />