diff --git a/graphql-schemas/detailedtournament.js b/graphql-schemas/detailedtournament.js index 1a73d5d72..002e14d74 100644 --- a/graphql-schemas/detailedtournament.js +++ b/graphql-schemas/detailedtournament.js @@ -13,6 +13,10 @@ const { } = require("../utils/validators") const typeDef = gql` + extend type Query { + plusDraftCups: DraftCupCollection! + } + extend type Mutation { addDetailedTournament( plus_server: PlusServer! @@ -22,6 +26,11 @@ const typeDef = gql` ): Boolean! } + type DraftCupCollection { + leaderboards: [Leaderboard!]! + tournaments: [DetailedTournament!]! + } + input DetailedTournamentInput { name: String! bracket_url: String! @@ -36,7 +45,7 @@ const typeDef = gql` bracket_url: String! date: String! top_3_team_names: [String!]! - top_3_discord_ids: [[String!]!]! + top_3_discord_users: [[User!]!]! participant_discord_ids: [String!]! type: EventType! } @@ -48,6 +57,7 @@ const typeDef = gql` } type DetailedMatch { + tournament_id: DetailedTournament! round_name: String! round_number: Int! map_details: [DetailedMap!]! @@ -63,7 +73,6 @@ const typeDef = gql` } type DetailedMap { - tournament_id: DetailedTournament! stage: String! mode: Mode! "Duration of the round in seconds" @@ -117,7 +126,7 @@ const typeDef = gql` } type TournamentPlayer { - discord_id: String! + discord_user: User! "Number of first places" first: Int! "Number of second places" @@ -147,7 +156,120 @@ const typeDef = gql` } ` +async function updateLeaderboard(top_3_discord_ids, type) { + let leaderboard = await Leaderboard.findOne({ type }) + + if (!leaderboard) leaderboard = { players: [] } + + const newPlayers = [] + + top_3_discord_ids.forEach((team, index) => { + const placement = ["first", "second", "third"][index] + team.forEach(discord_id => { + const foundPlayer = leaderboard.players.find( + player => discord_id === player.discord_id + ) + if (foundPlayer) { + foundPlayer[placement] = foundPlayer[placement] + 1 + } else { + const newPlayer = { discord_id, first: 0, second: 0, third: 0 } + newPlayer[placement] = newPlayer[placement] + 1 + newPlayers.push(newPlayer) + } + }) + }) + + const newLeaderboard = { + players: [...leaderboard.players, ...newPlayers], + type, + } + newLeaderboard.players.sort( + (a, b) => + b.first * 4 + + b.second * 2 + + b.third - + (a.first * 4 + a.second * 2 + a.third) + ) + + await Leaderboard.findOneAndUpdate({ type }, newLeaderboard, { upsert: true }) +} + +async function generateStats(type) { + const matches = await DetailedMatch.find({}) + const stats = {} + matches.forEach(match => { + match.map_details.forEach(map_detail => { + const { duration, winners, losers } = map_detail + ;[winners, losers].forEach((teamInfo, index) => { + teamInfo.players.forEach(player => { + const { + discord_id, + weapon, + kills, + assists, + deaths, + specials, + paint, + } = player + if (!stats[discord_id]) { + stats[discord_id] = {} + } + ;[weapon, "ALL"].forEach(weaponOrAll => { + const weaponStats = stats[discord_id][weaponOrAll] + ? stats[discord_id][weaponOrAll] + : { + discord_id, + weapon: weaponOrAll, + kills: 0, + assists: 0, + deaths: 0, + specials: 0, + paint: 0, + seconds_played: 0, + games_played: 0, + wins: 0, + type, + } + weaponStats.kills = weaponStats.kills + kills + weaponStats.assists = weaponStats.assists + assists + weaponStats.deaths = weaponStats.deaths + deaths + weaponStats.specials = weaponStats.specials + specials + weaponStats.paint = weaponStats.paint + paint + weaponStats.seconds_played = weaponStats.seconds_played + duration + weaponStats.games_played = weaponStats.games_played + 1 + weaponStats.wins = weaponStats.wins + (index === 0 ? 1 : 0) + + stats[discord_id][weaponOrAll] = weaponStats + }) + }) + }) + }) + }) + + const statsForDb = [] + Object.keys(stats).forEach(discord_id => { + Object.keys(stats[discord_id]).forEach(weapon => { + statsForDb.push(stats[discord_id][weapon]) + }) + }) + + PlayerStat.deleteMany({ type }) + await PlayerStat.insertMany(statsForDb) +} + const resolvers = { + Query: { + plusDraftCups: async (root, args) => { + const leaderboards = await Leaderboard.find() + .or([{ type: "DRAFTONE" }, { type: "DRAFTTWO" }]) + .populate("players.discord_user") + const tournaments = await DetailedTournament.find() + .or([{ type: "DRAFTONE" }, { type: "DRAFTTWO" }]) + .populate("top_3_discord_users") + + return { leaderboards, tournaments } + }, + }, Mutation: { addDetailedTournament: async (root, args) => { if (args.lanistaToken !== process.env.LANISTA_TOKEN) { @@ -166,20 +288,24 @@ const resolvers = { ...maptInputProblems.flat(3), ] + const eventType = args.plus_server === "TWO" ? "DRAFTTWO" : "DRAFTONE" if (problems.length > 0) { throw new UserInputError(problems.join(",")) } - - const eventType = args.plus_server === "TWO" ? "DRAFTTWO" : "DRAFTONE" const tournament = args.tournament tournament.type = eventType - //const savedTournament = await DetailedTournament.create(tournament) + const savedTournament = await DetailedTournament.create(tournament) - //put matches in db - //update leaderboard - // stats? + args.matches.forEach(match => { + match.tournament_id = savedTournament._id + match.type = eventType + }) + await DetailedMatch.insertMany(args.matches) + + await updateLeaderboard(args.tournament.top_3_discord_ids, eventType) + await generateStats(eventType) return true }, }, diff --git a/mongoose-models/detailedmatch.js b/mongoose-models/detailedmatch.js index 4511b569a..c0fd7b08f 100644 --- a/mongoose-models/detailedmatch.js +++ b/mongoose-models/detailedmatch.js @@ -20,10 +20,6 @@ const TeamInfo = { } const Map = { - tournament_id: { - type: mongoose.Schema.Types.ObjectId, - ref: "DetailedTournament", - }, stage: String, mode: String, duration: Number, @@ -32,9 +28,13 @@ const Map = { } const detailedMatchSchema = new mongoose.Schema({ + tournament_id: { + type: mongoose.Schema.Types.ObjectId, + ref: "DetailedTournament", + }, round_number: Number, round_name: String, - match_details: [Map], + map_details: [Map], type: String, }) diff --git a/mongoose-models/detailedtournament.js b/mongoose-models/detailedtournament.js index 52042bcf5..41b32ad3e 100644 --- a/mongoose-models/detailedtournament.js +++ b/mongoose-models/detailedtournament.js @@ -10,4 +10,10 @@ const detailedTournamentSchema = new mongoose.Schema({ type: String, }) +detailedTournamentSchema.virtual("top_3_discord_users", { + ref: "User", + localField: "top_3_discord_ids", + foreignField: "discord_id", +}) + module.exports = mongoose.model("DetailedTournament", detailedTournamentSchema) diff --git a/mongoose-models/leaderboard.js b/mongoose-models/leaderboard.js index 2c0aca5ee..1e628a18f 100644 --- a/mongoose-models/leaderboard.js +++ b/mongoose-models/leaderboard.js @@ -12,4 +12,11 @@ const leaderboardSchema = new mongoose.Schema({ type: String, }) +leaderboardSchema.virtual("players.discord_user", { + ref: "User", + localField: "players.discord_id", + foreignField: "discord_id", + justOne: true, +}) + module.exports = mongoose.model("Leaderboard", leaderboardSchema)