diff --git a/models/player.js b/models/player.js index c5bebbd89..b64972574 100644 --- a/models/player.js +++ b/models/player.js @@ -1,78 +1,106 @@ -const mongoose = require('mongoose') +const mongoose = require("mongoose") const playerSchema = new mongoose.Schema({ - name: {type: String, required: true }, + name: { type: String, required: true }, unique_id: { type: String, unique: true, required: true }, alias: String, twitter: String, weapons: [String], topTotal: { - type: [{ + type: [ + { type: mongoose.Schema.Types.ObjectId, - ref: 'Placement' - } - ], validate: [arrayLimit, '{PATH} exceeds the limit of 4']}, + ref: "Placement" + } + ], + validate: [arrayLimit, "{PATH} exceeds the limit of 4"] + }, topTotalScore: Number, topShooter: { - type: [{ + type: [ + { type: mongoose.Schema.Types.ObjectId, - ref: 'Placement' - } - ], validate: [arrayLimit, '{PATH} exceeds the limit of 4']}, + ref: "Placement" + } + ], + validate: [arrayLimit, "{PATH} exceeds the limit of 4"] + }, topShooterScore: Number, topBlaster: { - type: [{ + type: [ + { type: mongoose.Schema.Types.ObjectId, - ref: 'Placement' - } - ], validate: [arrayLimit, '{PATH} exceeds the limit of 4']}, + ref: "Placement" + } + ], + validate: [arrayLimit, "{PATH} exceeds the limit of 4"] + }, topBlasterScore: Number, topRoller: { - type: [{ + type: [ + { type: mongoose.Schema.Types.ObjectId, - ref: 'Placement' - } - ], validate: [arrayLimit, '{PATH} exceeds the limit of 4']}, + ref: "Placement" + } + ], + validate: [arrayLimit, "{PATH} exceeds the limit of 4"] + }, topRollerScore: Number, topCharger: { - type: [{ + type: [ + { type: mongoose.Schema.Types.ObjectId, - ref: 'Placement' - } - ], validate: [arrayLimit, '{PATH} exceeds the limit of 4']}, + ref: "Placement" + } + ], + validate: [arrayLimit, "{PATH} exceeds the limit of 4"] + }, topChargerScore: Number, topSlosher: { - type: [{ + type: [ + { type: mongoose.Schema.Types.ObjectId, - ref: 'Placement' - } - ], validate: [arrayLimit, '{PATH} exceeds the limit of 4']}, + ref: "Placement" + } + ], + validate: [arrayLimit, "{PATH} exceeds the limit of 4"] + }, topSlosherScore: Number, topSplatling: { - type: [{ + type: [ + { type: mongoose.Schema.Types.ObjectId, - ref: 'Placement' - } - ], validate: [arrayLimit, '{PATH} exceeds the limit of 4']}, + ref: "Placement" + } + ], + validate: [arrayLimit, "{PATH} exceeds the limit of 4"] + }, topSplatlingScore: Number, topDualies: { - type: [{ + type: [ + { type: mongoose.Schema.Types.ObjectId, - ref: 'Placement' - } - ], validate: [arrayLimit, '{PATH} exceeds the limit of 4']}, + ref: "Placement" + } + ], + validate: [arrayLimit, "{PATH} exceeds the limit of 4"] + }, topDualiesScore: Number, topBrella: { - type: [{ + type: [ + { type: mongoose.Schema.Types.ObjectId, - ref: 'Placement' - } - ], validate: [arrayLimit, '{PATH} exceeds the limit of 4']}, - topBrellaScore: Number + ref: "Placement" + } + ], + validate: [arrayLimit, "{PATH} exceeds the limit of 4"] + }, + topBrellaScore: Number, + weaponsCount: Number }) function arrayLimit(val) { return val.length <= 4 } -module.exports = mongoose.model('Player', playerSchema) \ No newline at end of file +module.exports = mongoose.model("Player", playerSchema) diff --git a/react-ui/package-lock.json b/react-ui/package-lock.json index 420cadab4..b45093d67 100644 --- a/react-ui/package-lock.json +++ b/react-ui/package-lock.json @@ -7958,6 +7958,11 @@ "verror": "1.10.0" } }, + "jstz": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/jstz/-/jstz-2.1.1.tgz", + "integrity": "sha512-8hfl5RD6P7rEeIbzStBz3h4f+BQHfq/ABtoU6gXKQv5OcZhnmrIpG7e1pYaZ8hS9e0mp+bxUj08fnDUbKctYyA==" + }, "jsx-ast-utils": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-2.2.1.tgz", diff --git a/react-ui/package.json b/react-ui/package.json index 408803a98..8e8b8767c 100644 --- a/react-ui/package.json +++ b/react-ui/package.json @@ -6,6 +6,7 @@ "@apollo/react-hooks": "^3.1.1", "apollo-boost": "^0.4.4", "graphql": "^14.5.8", + "jstz": "^2.1.1", "react": "^16.10.1", "react-color": "^2.17.3", "react-dom": "^16.10.1", diff --git a/react-ui/public/robots.txt b/react-ui/public/robots.txt index 01b0f9a10..6f27bb66a 100644 --- a/react-ui/public/robots.txt +++ b/react-ui/public/robots.txt @@ -1,2 +1,2 @@ -# https://www.robotstxt.org/robotstxt.html User-agent: * +Disallow: \ No newline at end of file diff --git a/react-ui/src/assets/xleaderboardIcons/all.png b/react-ui/src/assets/xleaderboardIcons/all.png new file mode 100644 index 000000000..5e4edc051 Binary files /dev/null and b/react-ui/src/assets/xleaderboardIcons/all.png differ diff --git a/react-ui/src/assets/xleaderboardIcons/blasters.png b/react-ui/src/assets/xleaderboardIcons/blasters.png new file mode 100644 index 000000000..f462ef570 Binary files /dev/null and b/react-ui/src/assets/xleaderboardIcons/blasters.png differ diff --git a/react-ui/src/assets/xleaderboardIcons/brellas.png b/react-ui/src/assets/xleaderboardIcons/brellas.png new file mode 100644 index 000000000..679e27de4 Binary files /dev/null and b/react-ui/src/assets/xleaderboardIcons/brellas.png differ diff --git a/react-ui/src/assets/xleaderboardIcons/chargers.png b/react-ui/src/assets/xleaderboardIcons/chargers.png new file mode 100644 index 000000000..5c7a28ddc Binary files /dev/null and b/react-ui/src/assets/xleaderboardIcons/chargers.png differ diff --git a/react-ui/src/assets/xleaderboardIcons/dualies.png b/react-ui/src/assets/xleaderboardIcons/dualies.png new file mode 100644 index 000000000..0b50fd237 Binary files /dev/null and b/react-ui/src/assets/xleaderboardIcons/dualies.png differ diff --git a/react-ui/src/assets/xleaderboardIcons/flex.png b/react-ui/src/assets/xleaderboardIcons/flex.png new file mode 100644 index 000000000..b173e69d6 Binary files /dev/null and b/react-ui/src/assets/xleaderboardIcons/flex.png differ diff --git a/react-ui/src/assets/xleaderboardIcons/rollers.png b/react-ui/src/assets/xleaderboardIcons/rollers.png new file mode 100644 index 000000000..ece415367 Binary files /dev/null and b/react-ui/src/assets/xleaderboardIcons/rollers.png differ diff --git a/react-ui/src/assets/xleaderboardIcons/shooters.png b/react-ui/src/assets/xleaderboardIcons/shooters.png new file mode 100644 index 000000000..99ef8f35d Binary files /dev/null and b/react-ui/src/assets/xleaderboardIcons/shooters.png differ diff --git a/react-ui/src/assets/xleaderboardIcons/sloshers.png b/react-ui/src/assets/xleaderboardIcons/sloshers.png new file mode 100644 index 000000000..f5e9ebc8c Binary files /dev/null and b/react-ui/src/assets/xleaderboardIcons/sloshers.png differ diff --git a/react-ui/src/assets/xleaderboardIcons/splatlings.png b/react-ui/src/assets/xleaderboardIcons/splatlings.png new file mode 100644 index 000000000..8d1404abe Binary files /dev/null and b/react-ui/src/assets/xleaderboardIcons/splatlings.png differ diff --git a/react-ui/src/components/calendar/Calendar.js b/react-ui/src/components/calendar/Calendar.js new file mode 100644 index 000000000..b5fcd794b --- /dev/null +++ b/react-ui/src/components/calendar/Calendar.js @@ -0,0 +1,77 @@ +import React, { useState, useEffect, useRef } from "react" +import { Button, Segment } from "semantic-ui-react" +import jstz from "jstz" + +import useWindowDimensions from "../../utils/useWindowDimensions" + +const PageCalendar = () => { + const [showCode, setShowCode] = useState(false) + const { containerWidth } = useWindowDimensions() + const calenderDiv = useRef(null) + + const iFrameHTML = `` + + //This is a weird solution but I couldn't get it working just setting the iframe src from a variable + useEffect(() => { + document.title = "Competitive Calendar - sendou.ink" + calenderDiv.current.innerHTML = iFrameHTML + }, [iFrameHTML]) + + return ( +
+
+ + {showCode && ( + +

+ + 💰 + {" "} + - Has prizes +
+ + 🎭 + {" "} + - Unconventional ruleset +
+ + 🔒 + {" "} + - Limited registration +
+ + 🤝 + {" "} + - Local event +
+ + 🎲 + {" "} + - Solo registration available +
+ + 👀 + {" "} + - No open registration +

+
+ )} +
+
+ If an event is missing you can contact{" "} + Kbot about it. +
+ You can add the calendar to your personal Google Calendar by pressing the + plus button above. If you are using other kind of calendar program you can + try{" "} + + this link + {" "} + instead. +
+ ) +} + +export default PageCalendar diff --git a/react-ui/src/components/root/MainMenu.js b/react-ui/src/components/root/MainMenu.js index 6f18e53fa..834b6446d 100644 --- a/react-ui/src/components/root/MainMenu.js +++ b/react-ui/src/components/root/MainMenu.js @@ -19,36 +19,36 @@ const MainMenu = () => { - + Maplist Generator - + Rotation - + Map Planner - + Calendar - + Builds - + Leaderboards - + Top 500 Browser - + Trends diff --git a/react-ui/src/components/root/Routes.js b/react-ui/src/components/root/Routes.js index 13e9e9f64..d0a3b434e 100644 --- a/react-ui/src/components/root/Routes.js +++ b/react-ui/src/components/root/Routes.js @@ -5,6 +5,8 @@ import Loading from "../common/Loading" const MapListGenerator = lazy(() => import("../maps/MapListGenerator")) const Rotations = lazy(() => import("../rotation/Rotations")) const MapPlanner = lazy(() => import("../plans/MapPlanner")) +const Calendar = lazy(() => import("../calendar/Calendar")) +const XLeaderboard = lazy(() => import("../xleaderboard/XLeaderboard")) const Routes = () => { return ( @@ -19,6 +21,12 @@ const Routes = () => { + + + + + + ) diff --git a/react-ui/src/components/xleaderboard/FlexLeaderboard.js b/react-ui/src/components/xleaderboard/FlexLeaderboard.js new file mode 100644 index 000000000..8ec7b1746 --- /dev/null +++ b/react-ui/src/components/xleaderboard/FlexLeaderboard.js @@ -0,0 +1,72 @@ +import React, { useEffect } from "react" +import { Table, Icon, Popup, Segment } from "semantic-ui-react" +import { useQuery } from "@apollo/react-hooks" +import { Link } from "react-router-dom" + +import { topFlex } from "../../graphql/queries/topFlex" +import Error from "../common/Error" +import Loading from "../common/Loading" + +const FlexLeaderboard = () => { + useEffect(() => { + document.title = "Flex Leaderboard - sendou.ink" + }, []) + const result = useQuery(topFlex) + + if (result.loading) { + return ( +
+ +
+ ) + } + if (result.error) { + return + } + const leaderboard = result.data["topFlex"] + + return ( + + + + + Name + + Power + } + content="Flex Power is the amount of unique weapons the player has reached top 500 with. Different kits count as unique weapons but reskins (e.g. Tentatek & Octoshot) don't." + position="bottom center" + /> + + Total Power + + + + + {leaderboard.map((player, index) => ( + + {index + 1} + + + {player.alias ? player.alias : player.name} + + {player.twitter ? ( + + + + ) : null} + + {player.weaponsCount} + {player.topTotalScore} + + ))} + +
+ ) +} + +export default FlexLeaderboard diff --git a/react-ui/src/components/xleaderboard/FourWeapons.js b/react-ui/src/components/xleaderboard/FourWeapons.js new file mode 100644 index 000000000..c3a407759 --- /dev/null +++ b/react-ui/src/components/xleaderboard/FourWeapons.js @@ -0,0 +1,33 @@ +import React from "react" +import { Popup } from "semantic-ui-react" +import weaponDict from "../../utils/english_internal.json" +import { modes, months } from "../../utils/lists" + +const FourWeapons = ({ weapons }) => { + return ( + <> + {weapons.map(w => { + const mode = modes[w.mode] + const month = months[w.month] + return ( + + } + header={w.name} + content={`${w.x_power} (${w.rank} ${mode} - ${month} ${w.year})`} + /> + ) + })} + + ) +} + +export default FourWeapons diff --git a/react-ui/src/components/xleaderboard/WeaponLeaderboard.js b/react-ui/src/components/xleaderboard/WeaponLeaderboard.js new file mode 100644 index 000000000..4e25cd6ca --- /dev/null +++ b/react-ui/src/components/xleaderboard/WeaponLeaderboard.js @@ -0,0 +1,77 @@ +import React, { useEffect } from "react" +import { Table, Icon, Popup } from "semantic-ui-react" +import { useQuery } from "@apollo/react-hooks" +import { Link } from "react-router-dom" + +import FourWeapons from "./FourWeapons" +import Loading from "../common/Loading" +import Error from "../common/Error" + +const WeaponLeaderboard = ({ query, queryName, scoreField, weaponsField }) => { + useEffect(() => { + document.title = `${weaponsField.substring(3)} Leaderboard - sendou.ink` + }, [weaponsField]) + + const result = useQuery(query) + + if (result.loading) { + return ( +
+ +
+ ) + } + if (result.error) { + return + } + + const leaderboard = result.data[queryName] + return ( +
+ + + + + Name + + Power + } + content="Leaderboard explanation" + position="bottom center" + /> + + Weapons + + + + + {leaderboard.map((player, index) => ( + + {index + 1} + + + {player.alias ? player.alias : player.name} + + {player.twitter ? ( + + + + ) : null} + + {player[scoreField]} + + + + + ))} + +
+
+ ) +} + +export default WeaponLeaderboard diff --git a/react-ui/src/components/xleaderboard/XLeaderboard.js b/react-ui/src/components/xleaderboard/XLeaderboard.js new file mode 100644 index 000000000..0d1226156 --- /dev/null +++ b/react-ui/src/components/xleaderboard/XLeaderboard.js @@ -0,0 +1,14 @@ +import React from "react" +import XLeaderBoardMenu from "./XLeaderboardMenu" +import XLeaderboardRoutes from "./XLeaderboardRoutes" + +const XLeaderboard = () => { + return ( + <> + + + + ) +} + +export default XLeaderboard diff --git a/react-ui/src/components/xleaderboard/XLeaderboardMenu.js b/react-ui/src/components/xleaderboard/XLeaderboardMenu.js new file mode 100644 index 000000000..17b8385be --- /dev/null +++ b/react-ui/src/components/xleaderboard/XLeaderboardMenu.js @@ -0,0 +1,215 @@ +import React from "react" +import { Menu, Responsive } from "semantic-ui-react" +import { NavLink } from "react-router-dom" + +import allIcon from "../../assets/xleaderboardIcons/all.png" +import flexIcon from "../../assets/xleaderboardIcons/flex.png" +import blasterIcon from "../../assets/xleaderboardIcons/blasters.png" +import brellaIcon from "../../assets/xleaderboardIcons/brellas.png" +import chargerIcon from "../../assets/xleaderboardIcons/chargers.png" +import dualieIcon from "../../assets/xleaderboardIcons/dualies.png" +import rollerIcon from "../../assets/xleaderboardIcons/rollers.png" +import shooterIcon from "../../assets/xleaderboardIcons/shooters.png" +import slosherIcon from "../../assets/xleaderboardIcons/sloshers.png" +import splatlingIcon from "../../assets/xleaderboardIcons/splatlings.png" + +const XLeaderBoardMenu = () => { + const wpnIcon = { + paddingBottom: "5px" + } + return ( +
+
+ + + + All Icon + All + + + + Flex icon + Flex + + + + Shooter Icon + Shooters + + + + Blaster Icon + Blasters + + + + Roller Icon + Rollers + + + + Charger Icon + Chargers + + + + Splatling Icon + Splatlings + + + + Slosher Icon + Sloshers + + + + Dualie Icon + Dualies + + + + Brella Icon + Brellas + + + + + + + All Icon + All + + + + Flex icon + Flex + + + + Shooter Icon + Shooters + + + + Blaster Icon + Blasters + + + + Roller Icon + Rollers + + + + Charger Icon + Chargers + + + + + Splatling Icon + Splatlings + + + + Slosher Icon + Sloshers + + + + Dualie Icon + Dualies + + + + Brella Icon + Brellas + + + +
+
+ ) +} + +export default XLeaderBoardMenu diff --git a/react-ui/src/components/xleaderboard/XLeaderboardRoutes.js b/react-ui/src/components/xleaderboard/XLeaderboardRoutes.js new file mode 100644 index 000000000..f715e9ab9 --- /dev/null +++ b/react-ui/src/components/xleaderboard/XLeaderboardRoutes.js @@ -0,0 +1,135 @@ +import React from "react" +import { Route } from "react-router-dom" +import WeaponLeaderboard from "./WeaponLeaderboard" +import { topTotalPlayers } from "../../graphql/queries/topPlayers" +import { topShooterPlayers } from "../../graphql/queries/topShooters" +import { topBlasterPlayers } from "../../graphql/queries/topBlasters" +import { topBrellaPlayers } from "../../graphql/queries/topBrellas" +import { topChargerPlayers } from "../../graphql/queries/topChargers" +import { topDualiesPlayers } from "../../graphql/queries/topDualies" +import { topRollerPlayers } from "../../graphql/queries/topRollers" +import { topSlosherPlayers } from "../../graphql/queries/topSloshers" +import { topSplatlingPlayers } from "../../graphql/queries/topSplatlings" +import FlexLeaderboard from "./FlexLeaderboard" + +const XLeaderboardRoutes = () => { + return ( + <> + ( + + )} + /> + } + /> + ( + + )} + /> + ( + + )} + /> + ( + + )} + /> + ( + + )} + /> + ( + + )} + /> + ( + + )} + /> + ( + + )} + /> + ( + + )} + /> + + ) +} + +export default XLeaderboardRoutes diff --git a/react-ui/src/graphql/queries/links.js b/react-ui/src/graphql/queries/links.js new file mode 100644 index 000000000..79669ede4 --- /dev/null +++ b/react-ui/src/graphql/queries/links.js @@ -0,0 +1,12 @@ +import { gql } from 'apollo-boost' + +export const links = gql` +{ + links { + title + url + description + type + } +} +` \ No newline at end of file diff --git a/react-ui/src/graphql/queries/playerInfo.js b/react-ui/src/graphql/queries/playerInfo.js new file mode 100644 index 000000000..c554a6d1e --- /dev/null +++ b/react-ui/src/graphql/queries/playerInfo.js @@ -0,0 +1,34 @@ +import { gql } from 'apollo-boost' + +export const playerInfo = gql` +query playerInfo($uid: String, $twitter: String) { + playerInfo(uid: $uid, twitter: $twitter) { + player { + name + weapons + alias + twitter + discord_id + topTotalScore + topShooterScore + topBlasterScore + topRollerScore + topChargerScore + topSlosherScore + topSplatlingScore + topDualiesScore + topBrellaScore + } + placements { + id + name + weapon + rank + mode + x_power + month + year + } + } +} +` \ No newline at end of file diff --git a/react-ui/src/graphql/queries/seachForTrend.js b/react-ui/src/graphql/queries/seachForTrend.js new file mode 100644 index 000000000..3674d2d21 --- /dev/null +++ b/react-ui/src/graphql/queries/seachForTrend.js @@ -0,0 +1,16 @@ +import { gql } from 'apollo-boost' + +export const searchForTrend = gql` +query searchForTrend($weapon: String!) { + searchForTrend(weapon: $weapon) { + weapon + counts { + year + SZ + TC + RM + CB + } + } +} +` \ No newline at end of file diff --git a/react-ui/src/graphql/queries/searchForBuilds.js b/react-ui/src/graphql/queries/searchForBuilds.js new file mode 100644 index 000000000..42349de59 --- /dev/null +++ b/react-ui/src/graphql/queries/searchForBuilds.js @@ -0,0 +1,16 @@ +import { gql } from 'apollo-boost' + +export const searchForBuilds = gql` +query searchForBuilds($discord_id: String!) { + searchForBuilds(discord_id: $discord_id) { + id + weapon + title + headgear + clothing + shoes + updatedAt + top + } +} +` \ No newline at end of file diff --git a/react-ui/src/graphql/queries/searchForBuildsByWeapon.js b/react-ui/src/graphql/queries/searchForBuildsByWeapon.js new file mode 100644 index 000000000..61aaf17c9 --- /dev/null +++ b/react-ui/src/graphql/queries/searchForBuildsByWeapon.js @@ -0,0 +1,23 @@ +import { gql } from 'apollo-boost' + +export const searchForBuildsByWeapon = gql` +query searchForBuildsByWeapon($weapon: String!, $page: Int) { + searchForBuildsByWeapon(weapon: $weapon, page: $page) { + builds { + id + discord_id + top + headgear + clothing + shoes + title + updatedAt + discord_user { + username + discriminator + } + } + pageCount + } +} +` \ No newline at end of file diff --git a/react-ui/src/graphql/queries/searchForPlacements.js b/react-ui/src/graphql/queries/searchForPlacements.js new file mode 100644 index 000000000..47a0e44df --- /dev/null +++ b/react-ui/src/graphql/queries/searchForPlacements.js @@ -0,0 +1,40 @@ +import { gql } from 'apollo-boost' + +export const searchForPlacements = gql` +query searchForPlacements( + $name: String + $weapon: String + $mode: Int + $unique_id: String + $month: Int + $year: Int + $page: Int +) { + searchForPlacements( + name: $name + weapon: $weapon + mode: $mode + unique_id: $unique_id + month: $month + year: $year + page: $page + ) { + placements { + name + x_power + weapon + rank + id + unique_id + month + year + mode + player { + twitter + } + } + pageCount + } +} + +` \ No newline at end of file diff --git a/react-ui/src/graphql/queries/searchForPlayers.js b/react-ui/src/graphql/queries/searchForPlayers.js new file mode 100644 index 000000000..480771eed --- /dev/null +++ b/react-ui/src/graphql/queries/searchForPlayers.js @@ -0,0 +1,12 @@ +import { gql } from 'apollo-boost' + +export const searchForPlayers = gql` +query searchForPlayers($name: String!, $exact: Boolean) { + searchForPlayers(name: $name, exact: $exact) { + name + x_power + weapon + unique_id + } +} +` \ No newline at end of file diff --git a/react-ui/src/graphql/queries/searchForUser.js b/react-ui/src/graphql/queries/searchForUser.js new file mode 100644 index 000000000..cd2043a97 --- /dev/null +++ b/react-ui/src/graphql/queries/searchForUser.js @@ -0,0 +1,14 @@ +import { gql } from 'apollo-boost' + +export const searchForUser = gql` +query searchForUser($discord_id: String) { + searchForUser(discord_id: $discord_id) { + username + discriminator + discord_id + avatar + twitch_name + twitter_name + } +} +` \ No newline at end of file diff --git a/react-ui/src/graphql/queries/topBlasters.js b/react-ui/src/graphql/queries/topBlasters.js new file mode 100644 index 000000000..142820668 --- /dev/null +++ b/react-ui/src/graphql/queries/topBlasters.js @@ -0,0 +1,23 @@ +import { gql } from 'apollo-boost' + +export const topBlasterPlayers = gql` +{ + topBlasterPlayers { + id + unique_id + name + alias + twitter + topBlasterScore + topBlaster { + name + weapon + mode + x_power + rank + month + year + } + } +} +` \ No newline at end of file diff --git a/react-ui/src/graphql/queries/topBrellas.js b/react-ui/src/graphql/queries/topBrellas.js new file mode 100644 index 000000000..3317e29e4 --- /dev/null +++ b/react-ui/src/graphql/queries/topBrellas.js @@ -0,0 +1,23 @@ +import { gql } from 'apollo-boost' + +export const topBrellaPlayers = gql` +{ + topBrellaPlayers { + id + unique_id + name + alias + twitter + topBrellaScore + topBrella { + name + weapon + mode + x_power + rank + month + year + } + } +} +` \ No newline at end of file diff --git a/react-ui/src/graphql/queries/topChargers.js b/react-ui/src/graphql/queries/topChargers.js new file mode 100644 index 000000000..e2e399991 --- /dev/null +++ b/react-ui/src/graphql/queries/topChargers.js @@ -0,0 +1,23 @@ +import { gql } from 'apollo-boost' + +export const topChargerPlayers = gql` +{ + topChargerPlayers { + id + unique_id + name + alias + twitter + topChargerScore + topCharger { + name + weapon + mode + x_power + rank + month + year + } + } +} +` \ No newline at end of file diff --git a/react-ui/src/graphql/queries/topDualies.js b/react-ui/src/graphql/queries/topDualies.js new file mode 100644 index 000000000..74170cb4d --- /dev/null +++ b/react-ui/src/graphql/queries/topDualies.js @@ -0,0 +1,23 @@ +import { gql } from 'apollo-boost' + +export const topDualiesPlayers = gql` +{ + topDualiesPlayers { + id + unique_id + name + alias + twitter + topDualiesScore + topDualies { + name + weapon + mode + x_power + rank + month + year + } + } +} +` \ No newline at end of file diff --git a/react-ui/src/graphql/queries/topFlex.js b/react-ui/src/graphql/queries/topFlex.js new file mode 100644 index 000000000..d304ba9b1 --- /dev/null +++ b/react-ui/src/graphql/queries/topFlex.js @@ -0,0 +1,15 @@ +import { gql } from 'apollo-boost' + +export const topFlex = gql` +{ + topFlex { + id + unique_id + name + alias + twitter + weaponsCount + topTotalScore + } +} +` \ No newline at end of file diff --git a/react-ui/src/graphql/queries/topPlayers.js b/react-ui/src/graphql/queries/topPlayers.js new file mode 100644 index 000000000..51118f663 --- /dev/null +++ b/react-ui/src/graphql/queries/topPlayers.js @@ -0,0 +1,23 @@ +import { gql } from 'apollo-boost' + +export const topTotalPlayers = gql` +{ + topTotalPlayers { + id + unique_id + name + alias + twitter + topTotalScore + topTotal { + name + weapon + mode + x_power + rank + month + year + } + } +} +` \ No newline at end of file diff --git a/react-ui/src/graphql/queries/topPlayersOfWeapon.js b/react-ui/src/graphql/queries/topPlayersOfWeapon.js new file mode 100644 index 000000000..5fee09dc2 --- /dev/null +++ b/react-ui/src/graphql/queries/topPlayersOfWeapon.js @@ -0,0 +1,19 @@ +import { gql } from 'apollo-boost' + +export const topPlayersOfWeapon = gql` +query topPlayers($weapon: String!) { + topPlayers(weapon: $weapon) { + modeCount + placements { + id + name + rank + mode + x_power + unique_id + month + year + } + } +} +` \ No newline at end of file diff --git a/react-ui/src/graphql/queries/topRollers.js b/react-ui/src/graphql/queries/topRollers.js new file mode 100644 index 000000000..f318883df --- /dev/null +++ b/react-ui/src/graphql/queries/topRollers.js @@ -0,0 +1,23 @@ +import { gql } from 'apollo-boost' + +export const topRollerPlayers = gql` +{ + topRollerPlayers { + id + unique_id + name + alias + twitter + topRollerScore + topRoller { + name + weapon + mode + x_power + rank + month + year + } + } +} +` \ No newline at end of file diff --git a/react-ui/src/graphql/queries/topShooters.js b/react-ui/src/graphql/queries/topShooters.js new file mode 100644 index 000000000..d72713b0d --- /dev/null +++ b/react-ui/src/graphql/queries/topShooters.js @@ -0,0 +1,23 @@ +import { gql } from 'apollo-boost' + +export const topShooterPlayers = gql` +{ + topShooterPlayers { + id + unique_id + name + alias + twitter + topShooterScore + topShooter { + name + weapon + mode + x_power + rank + month + year + } + } +} +` \ No newline at end of file diff --git a/react-ui/src/graphql/queries/topSloshers.js b/react-ui/src/graphql/queries/topSloshers.js new file mode 100644 index 000000000..4924869ca --- /dev/null +++ b/react-ui/src/graphql/queries/topSloshers.js @@ -0,0 +1,23 @@ +import { gql } from 'apollo-boost' + +export const topSlosherPlayers = gql` +{ + topSlosherPlayers { + id + unique_id + name + alias + twitter + topSlosherScore + topSlosher { + name + weapon + mode + x_power + rank + month + year + } + } +} +` \ No newline at end of file diff --git a/react-ui/src/graphql/queries/topSplatlings.js b/react-ui/src/graphql/queries/topSplatlings.js new file mode 100644 index 000000000..4f4520e17 --- /dev/null +++ b/react-ui/src/graphql/queries/topSplatlings.js @@ -0,0 +1,23 @@ +import { gql } from 'apollo-boost' + +export const topSplatlingPlayers = gql` +{ + topSplatlingPlayers { + id + unique_id + name + alias + twitter + topSplatlingScore + topSplatling { + name + weapon + mode + x_power + rank + month + year + } + } +} +` \ No newline at end of file diff --git a/react-ui/src/graphql/queries/userLean.js b/react-ui/src/graphql/queries/userLean.js new file mode 100644 index 000000000..039883f51 --- /dev/null +++ b/react-ui/src/graphql/queries/userLean.js @@ -0,0 +1,11 @@ +import { gql } from 'apollo-boost' + +export const userLean = gql` +{ + user { + username + avatar + discord_id + } +} +` \ No newline at end of file diff --git a/react-ui/src/index.js b/react-ui/src/index.js index a1e270e80..c0dd40471 100644 --- a/react-ui/src/index.js +++ b/react-ui/src/index.js @@ -8,7 +8,12 @@ import { BrowserRouter as Router } from "react-router-dom" import "semantic-ui-css/semantic.min.css" import "./index.css" -const client = new ApolloClient({ uri: "https://www.sendou.ink/graphql" }) +const client = new ApolloClient({ + uri: + process.env.REACT_APP_APOLLO_URI === "local" + ? "http://localhost:3001/graphql" + : "https://www.sendou.ink/graphql" +}) ReactDOM.render( diff --git a/react-ui/src/utils/lists.js b/react-ui/src/utils/lists.js index 28c7c2f6c..9ed6e434d 100644 --- a/react-ui/src/utils/lists.js +++ b/react-ui/src/utils/lists.js @@ -1,3 +1,27 @@ +export const modes = [ + "", + "Splat Zones", + "Tower Control", + "Rainmaker", + "Clam Blitz" +] + +export const months = [ + "", + "January", + "February", + "March", + "April", + "May", + "June", + "July", + "August", + "September", + "October", + "November", + "December" +] + export const weapons = [ "Sploosh-o-matic", "Neo Sploosh-o-matic", diff --git a/schemas/player.js b/schemas/player.js index a6b3b4184..5e880aaed 100644 --- a/schemas/player.js +++ b/schemas/player.js @@ -1,25 +1,27 @@ -const { UserInputError, AuthenticationError, gql } = require('apollo-server-express') -const Player = require('../models/player') -const User = require('../models/user') +const { + UserInputError, + AuthenticationError, + gql +} = require("apollo-server-express") +const Player = require("../models/player") +const User = require("../models/user") const typeDef = gql` extend type Query { playerCount: Int! - topTotalPlayers (amount: Int): [Player!]! - topShooterPlayers (amount: Int): [Player!]! - topBlasterPlayers (amount: Int): [Player!]! - topRollerPlayers (amount: Int): [Player!]! - topChargerPlayers (amount: Int): [Player!]! - topSlosherPlayers (amount: Int): [Player!]! - topSplatlingPlayers (amount: Int): [Player!]! - topDualiesPlayers (amount: Int): [Player!]! - topBrellaPlayers (amount: Int): [Player!]! + topTotalPlayers(amount: Int): [Player!]! + topShooterPlayers(amount: Int): [Player!]! + topBlasterPlayers(amount: Int): [Player!]! + topRollerPlayers(amount: Int): [Player!]! + topChargerPlayers(amount: Int): [Player!]! + topSlosherPlayers(amount: Int): [Player!]! + topSplatlingPlayers(amount: Int): [Player!]! + topDualiesPlayers(amount: Int): [Player!]! + topBrellaPlayers(amount: Int): [Player!]! + topFlex: [Player!]! } extend type Mutation { - updateTwitter( - unique_id: String! - twitter: String! - ): Boolean + updateTwitter(unique_id: String!, twitter: String!): Boolean } type Player { id: ID! @@ -47,30 +49,38 @@ const typeDef = gql` topDualiesScore: Float topBrella: [Placement] topBrellaScore: Float + weaponsCount: Int } ` const resolvers = { Query: { playerCount: () => Player.collection.countDocuments(), + topFlex: async (root, args) => { + return Player.find({}) + .sort({ weaponsCount: "desc", topTotalScore: "desc" }) + .limit(50) + }, topTotalPlayers: (root, args) => { if (!args.amount) { args.amount = 50 } if (args.amount < 1 || args.amount > 50) { - throw new UserInputError('amount requested has to be between 1 and 50', { - invalidArgs: args, - }) + throw new UserInputError( + "amount requested has to be between 1 and 50", + { + invalidArgs: args + } + ) } - - return Player - .find({ topTotalScore: { $ne: null} }) - .sort({ "topTotalScore": "desc" }) + + return Player.find({ topTotalScore: { $ne: null } }) + .sort({ topTotalScore: "desc" }) .limit(args.amount) - .populate("topTotal", {"unique_id": 0}) + .populate("topTotal", { unique_id: 0 }) .catch(e => { throw new UserInputError(e.message, { - invalidArgs: args, + invalidArgs: args }) }) }, @@ -80,16 +90,18 @@ const resolvers = { } if (args.amount < 1 || args.amount > 50) { - throw new UserInputError('amount requested has to be between 1 and 50', { - invalidArgs: args, - }) + throw new UserInputError( + "amount requested has to be between 1 and 50", + { + invalidArgs: args + } + ) } - return Player - .find({ topShooterScore: { $ne: null} }) - .sort({ "topShooterScore": "desc" }) + return Player.find({ topShooterScore: { $ne: null } }) + .sort({ topShooterScore: "desc" }) .limit(args.amount) - .populate("topShooter", {"unique_id": 0}) + .populate("topShooter", { unique_id: 0 }) }, topBlasterPlayers: (root, args) => { if (!args.amount) { @@ -97,16 +109,18 @@ const resolvers = { } if (args.amount < 1 || args.amount > 50) { - throw new UserInputError('amount requested has to be between 1 and 50', { - invalidArgs: args, - }) + throw new UserInputError( + "amount requested has to be between 1 and 50", + { + invalidArgs: args + } + ) } - return Player - .find({ topBlasterScore: { $ne: null} }) - .sort({ "topBlasterScore": "desc" }) + return Player.find({ topBlasterScore: { $ne: null } }) + .sort({ topBlasterScore: "desc" }) .limit(args.amount) - .populate("topBlaster", {"unique_id": 0}) + .populate("topBlaster", { unique_id: 0 }) }, topRollerPlayers: (root, args) => { if (!args.amount) { @@ -114,16 +128,18 @@ const resolvers = { } if (args.amount < 1 || args.amount > 50) { - throw new UserInputError('amount requested has to be between 1 and 50', { - invalidArgs: args, - }) + throw new UserInputError( + "amount requested has to be between 1 and 50", + { + invalidArgs: args + } + ) } - return Player - .find({ topRollerScore: { $ne: null} }) - .sort({ "topRollerScore": "desc" }) + return Player.find({ topRollerScore: { $ne: null } }) + .sort({ topRollerScore: "desc" }) .limit(args.amount) - .populate("topRoller", {"unique_id": 0}) + .populate("topRoller", { unique_id: 0 }) }, topChargerPlayers: (root, args) => { if (!args.amount) { @@ -131,16 +147,18 @@ const resolvers = { } if (args.amount < 1 || args.amount > 50) { - throw new UserInputError('amount requested has to be between 1 and 50', { - invalidArgs: args, - }) + throw new UserInputError( + "amount requested has to be between 1 and 50", + { + invalidArgs: args + } + ) } - return Player - .find({ topChargerScore: { $ne: null} }) - .sort({ "topChargerScore": "desc" }) + return Player.find({ topChargerScore: { $ne: null } }) + .sort({ topChargerScore: "desc" }) .limit(args.amount) - .populate("topCharger", {"unique_id": 0}) + .populate("topCharger", { unique_id: 0 }) }, topSlosherPlayers: (root, args) => { if (!args.amount) { @@ -148,16 +166,18 @@ const resolvers = { } if (args.amount < 1 || args.amount > 50) { - throw new UserInputError('amount requested has to be between 1 and 50', { - invalidArgs: args, - }) + throw new UserInputError( + "amount requested has to be between 1 and 50", + { + invalidArgs: args + } + ) } - return Player - .find({ topSlosherScore: { $ne: null} }) - .sort({ "topSlosherScore": "desc" }) + return Player.find({ topSlosherScore: { $ne: null } }) + .sort({ topSlosherScore: "desc" }) .limit(args.amount) - .populate("topSlosher", {"unique_id": 0}) + .populate("topSlosher", { unique_id: 0 }) }, topSplatlingPlayers: (root, args) => { if (!args.amount) { @@ -165,16 +185,18 @@ const resolvers = { } if (args.amount < 1 || args.amount > 50) { - throw new UserInputError('amount requested has to be between 1 and 50', { - invalidArgs: args, - }) + throw new UserInputError( + "amount requested has to be between 1 and 50", + { + invalidArgs: args + } + ) } - return Player - .find({ topSplatlingScore: { $ne: null} }) - .sort({ "topSplatlingScore": "desc" }) + return Player.find({ topSplatlingScore: { $ne: null } }) + .sort({ topSplatlingScore: "desc" }) .limit(args.amount) - .populate("topSplatling", {"unique_id": 0}) + .populate("topSplatling", { unique_id: 0 }) }, topDualiesPlayers: (root, args) => { if (!args.amount) { @@ -182,16 +204,18 @@ const resolvers = { } if (args.amount < 1 || args.amount > 50) { - throw new UserInputError('amount requested has to be between 1 and 50', { - invalidArgs: args, - }) + throw new UserInputError( + "amount requested has to be between 1 and 50", + { + invalidArgs: args + } + ) } - return Player - .find({ topDualiesScore: { $ne: null} }) - .sort({ "topDualiesScore": "desc" }) + return Player.find({ topDualiesScore: { $ne: null } }) + .sort({ topDualiesScore: "desc" }) .limit(args.amount) - .populate("topDualies", {"unique_id": 0}) + .populate("topDualies", { unique_id: 0 }) }, topBrellaPlayers: (root, args) => { if (!args.amount) { @@ -199,29 +223,34 @@ const resolvers = { } if (args.amount < 1 || args.amount > 50) { - throw new UserInputError('amount requested has to be between 1 and 50', { - invalidArgs: args, - }) + throw new UserInputError( + "amount requested has to be between 1 and 50", + { + invalidArgs: args + } + ) } - return Player - .find({ topBrellaScore: { $ne: null} }) - .sort({ "topBrellaScore": "desc" }) + return Player.find({ topBrellaScore: { $ne: null } }) + .sort({ topBrellaScore: "desc" }) .limit(args.amount) - .populate("topBrella", {"unique_id": 0}) - }, + .populate("topBrella", { unique_id: 0 }) + } }, Mutation: { updateTwitter: async (root, args, ctx) => { - if (ctx.user.discord_id !== process.env.ADMIN_ID) throw new AuthenticationError('not admin') + if (ctx.user.discord_id !== process.env.ADMIN_ID) + throw new AuthenticationError("not admin") - const player = await Player.findOne({ unique_id: args.unique_id.trim() }).catch(e => { + const player = await Player.findOne({ + unique_id: args.unique_id.trim() + }).catch(e => { throw new UserInputError(e.message, { - invalidArgs: args, + invalidArgs: args }) }) - if (!player) throw new UserInputError + if (!player) throw new UserInputError() player.twitter = args.twitter.trim().toLowerCase() @@ -229,26 +258,27 @@ const resolvers = { await player.save() } catch (error) { throw new UserInputError(error.message, { - invalidArgs: args, + invalidArgs: args }) } - + return true } }, Player: { - discord_id: async (root) => { + discord_id: async root => { if (!root.twitter) return null - const user = await User - .findOne({ twitter_name: root.twitter }) - .catch(e => { - throw new UserInputError, { - invalidArgs: args, - } - }) + const user = await User.findOne({ twitter_name: root.twitter }).catch( + e => { + throw (new UserInputError(), + { + invalidArgs: args + }) + } + ) if (!user) return null - + return user.discord_id } } @@ -257,4 +287,4 @@ const resolvers = { module.exports = { Player: typeDef, playerResolvers: resolvers -} \ No newline at end of file +} diff --git a/scripts/.vscode/settings.json b/scripts/.vscode/settings.json new file mode 100644 index 000000000..44aef9f94 --- /dev/null +++ b/scripts/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "python.formatting.provider": "black" +} \ No newline at end of file diff --git a/scripts/xrank.py b/scripts/xrank.py index cf86115fd..63de64b6f 100644 --- a/scripts/xrank.py +++ b/scripts/xrank.py @@ -5,50 +5,158 @@ import calendar import pymongo from config import uri -shooters = ["Sploosh-o-matic", "Neo Sploosh-o-matic", "Sploosh-o-matic 7", -"Splattershot Jr.", "Custom Splattershot Jr.", "Kensa Splattershot Jr.", -"Splash-o-matic", "Neo Splash-o-matic", "Aerospray MG", "Aerospray RG", -"Aerospray PG", "Splattershot", "Tentatek Splattershot", "Kensa Splattershot", -".52 Gal", ".52 Gal Deco", "Kensa .52 Gal", "N-ZAP '85", "N-ZAP '89", -"N-ZAP '83", "Splattershot Pro", "Forge Splattershot Pro", "Kensa Splattershot Pro", -".96 Gal", ".96 Gal Deco", "Jet Squelcher", "Custom Jet Squelcher", -"L-3 Nozzlenose", "L-3 Nozzlenose D", "Kensa L-3 Nozzlenose", -"H-3 Nozzlenose", "H-3 Nozzlenose D", "Cherry H-3 Nozzlenose", "Squeezer", -"Foil Squeezer"] +shooters = [ + "Sploosh-o-matic", + "Neo Sploosh-o-matic", + "Sploosh-o-matic 7", + "Splattershot Jr.", + "Custom Splattershot Jr.", + "Kensa Splattershot Jr.", + "Splash-o-matic", + "Neo Splash-o-matic", + "Aerospray MG", + "Aerospray RG", + "Aerospray PG", + "Splattershot", + "Tentatek Splattershot", + "Kensa Splattershot", + ".52 Gal", + ".52 Gal Deco", + "Kensa .52 Gal", + "N-ZAP '85", + "N-ZAP '89", + "N-ZAP '83", + "Splattershot Pro", + "Forge Splattershot Pro", + "Kensa Splattershot Pro", + ".96 Gal", + ".96 Gal Deco", + "Jet Squelcher", + "Custom Jet Squelcher", + "L-3 Nozzlenose", + "L-3 Nozzlenose D", + "Kensa L-3 Nozzlenose", + "H-3 Nozzlenose", + "H-3 Nozzlenose D", + "Cherry H-3 Nozzlenose", + "Squeezer", + "Foil Squeezer", +] -blasters = ["Luna Blaster", "Luna Blaster Neo", "Kensa Luna Blaster", -"Blaster", "Custom Blaster", "Range Blaster", "Custom Range Blaster", -"Grim Range Blaster", "Rapid Blaster", "Rapid Blaster Deco", "Kensa Rapid Blaster", -"Rapid Blaster Pro", "Rapid Blaster Pro Deco", "Clash Blaster", "Clash Blaster Neo"] +blasters = [ + "Luna Blaster", + "Luna Blaster Neo", + "Kensa Luna Blaster", + "Blaster", + "Custom Blaster", + "Range Blaster", + "Custom Range Blaster", + "Grim Range Blaster", + "Rapid Blaster", + "Rapid Blaster Deco", + "Kensa Rapid Blaster", + "Rapid Blaster Pro", + "Rapid Blaster Pro Deco", + "Clash Blaster", + "Clash Blaster Neo", +] -rollers = ["Carbon Roller", "Carbon Roller Deco", "Splat Roller", "Krak-On Splat Roller", -"Kensa Splat Roller", "Dynamo Roller", "Gold Dynamo Roller", "Kensa Dynamo Roller", -"Flingza Roller", "Foil Flingza Roller", "Inkbrush", "Inkbrush Nouveau", -"Permanent Inkbrush", "Octobrush", "Octobrush Nouveau", "Kensa Octobrush"] +rollers = [ + "Carbon Roller", + "Carbon Roller Deco", + "Splat Roller", + "Krak-On Splat Roller", + "Kensa Splat Roller", + "Dynamo Roller", + "Gold Dynamo Roller", + "Kensa Dynamo Roller", + "Flingza Roller", + "Foil Flingza Roller", + "Inkbrush", + "Inkbrush Nouveau", + "Permanent Inkbrush", + "Octobrush", + "Octobrush Nouveau", + "Kensa Octobrush", +] -chargers = ["Classic Squiffer", "New Squiffer", "Fresh Squiffer", "Splat Charger", -"Firefin Splat Charger", "Kensa Charger", "Splatterscope", "Firefin Splatterscope", -"Kensa Splatterscope", "E-liter 4K", "Custom E-liter 4K", "E-liter 4K Scope", -"Custom E-liter 4K Scope", "Bamboozler 14 Mk I", "Bamboozler 14 Mk II", -"Bamboozler 14 Mk III", "Goo Tuber", "Custom Goo Tuber"] +chargers = [ + "Classic Squiffer", + "New Squiffer", + "Fresh Squiffer", + "Splat Charger", + "Firefin Splat Charger", + "Kensa Charger", + "Splatterscope", + "Firefin Splatterscope", + "Kensa Splatterscope", + "E-liter 4K", + "Custom E-liter 4K", + "E-liter 4K Scope", + "Custom E-liter 4K Scope", + "Bamboozler 14 Mk I", + "Bamboozler 14 Mk II", + "Bamboozler 14 Mk III", + "Goo Tuber", + "Custom Goo Tuber", +] -sloshers = ["Slosher", "Slosher Deco", "Soda Slosher", "Tri-Slosher", -"Tri-Slosher Nouveau", "Sloshing Machine", "Sloshing Machine Neo", -"Kensa Sloshing Machine", "Bloblobber", "Bloblobber Deco", "Explosher", -"Custom Explosher"] +sloshers = [ + "Slosher", + "Slosher Deco", + "Soda Slosher", + "Tri-Slosher", + "Tri-Slosher Nouveau", + "Sloshing Machine", + "Sloshing Machine Neo", + "Kensa Sloshing Machine", + "Bloblobber", + "Bloblobber Deco", + "Explosher", + "Custom Explosher", +] -splatlings = ["Mini Splatling", "Zink Mini Splatling", "Kensa Mini Splatling", -"Heavy Splatling", "Heavy Splatling Deco", "Heavy Splatling Remix", -"Hydra Splatling", "Custom Hydra Splatling", "Ballpoint Splatling", -"Ballpoint Splatling Nouveau", "Nautilus 47", "Nautilus 79"] +splatlings = [ + "Mini Splatling", + "Zink Mini Splatling", + "Kensa Mini Splatling", + "Heavy Splatling", + "Heavy Splatling Deco", + "Heavy Splatling Remix", + "Hydra Splatling", + "Custom Hydra Splatling", + "Ballpoint Splatling", + "Ballpoint Splatling Nouveau", + "Nautilus 47", + "Nautilus 79", +] -dualies = ["Dapple Dualies", "Dapple Dualies Nouveau", "Clear Dapple Dualies", -"Splat Dualies", "Enperry Splat Dualies", "Kensa Splat Dualies", "Glooga Dualies", -"Glooga Dualies Deco", "Kensa Glooga Dualies", "Dualie Squelchers", -"Custom Dualie Squelchers", "Dark Tetra Dualies", "Light Tetra Dualies"] +dualies = [ + "Dapple Dualies", + "Dapple Dualies Nouveau", + "Clear Dapple Dualies", + "Splat Dualies", + "Enperry Splat Dualies", + "Kensa Splat Dualies", + "Glooga Dualies", + "Glooga Dualies Deco", + "Kensa Glooga Dualies", + "Dualie Squelchers", + "Custom Dualie Squelchers", + "Dark Tetra Dualies", + "Light Tetra Dualies", +] -brellas = ["Splat Brella", "Sorella Brella", "Tenta Brella", "Tenta Sorella Brella", -"Tenta Camo Brella", "Undercover Brella", "Undercover Sorella Brella", "Kensa Undercover Brella"] +brellas = [ + "Splat Brella", + "Sorella Brella", + "Tenta Brella", + "Tenta Sorella Brella", + "Tenta Camo Brella", + "Undercover Brella", + "Undercover Sorella Brella", + "Kensa Undercover Brella", +] client = pymongo.MongoClient(uri) db = client.production @@ -57,136 +165,162 @@ script_dir = os.path.dirname(__file__) rel_path = "xrank_data/*.json" abs_file_path = os.path.join(script_dir, rel_path) -year = 2019 # needs to be updated manually when we process data from different years +year = 2019 # needs to be updated manually when we process data from different years + def resolve_top_array(key_name, player, result, x_power): - if key_name not in player: - player[key_name] = [result.inserted_id] - else: - if len(player[key_name]) <= 3: - player[key_name].append(result.inserted_id) + if key_name not in player: + player[key_name] = [result.inserted_id] else: - lowest_power = 10000 - lowest_power_index = -1 - sum_of_powers = x_power - for index, placement_id in enumerate(player[key_name]): - high_placement = db.placements.find_one({ "_id": placement_id }) - if high_placement is None: - raise ValueError(f'Placement id {placement_id} not found in the database.') - sum_of_powers += high_placement["x_power"] - if high_placement["x_power"] < x_power: - if high_placement["x_power"] < lowest_power: - lowest_power = high_placement["x_power"] - lowest_power_index = index - - if lowest_power_index != -1: - player[key_name][lowest_power_index] = result.inserted_id - sum_of_powers -= lowest_power - power_score = round((sum_of_powers / 4), 1) - player[f"{key_name}Score"] = power_score - return player - -for filepath in glob.iglob(abs_file_path): # iterate through .json files in the xrank_data folder - if filepath.endswith(".json"): - path_without_folder = filepath.replace("xrank_data\\", "") - file_parts = path_without_folder.split("_") - print(path_without_folder) - month = list(calendar.month_name).index(file_parts[0].capitalize()) - - if "splat" in file_parts[1]: - mode = 1 - elif "tower" in file_parts[1]: - mode = 2 - elif "rainmaker" in file_parts[1]: - mode = 3 - else: - mode = 4 - with open(filepath) as f: - data = json.load(f) - for placement in data: - if placement["cheater"]: - continue - - rank = placement["rank"] - if rank > 500: - break - - name = placement["name"] - x_power = placement["x_power"] - unique_id = placement["unique_id"] - - weapon = placement["weapon"]["name"].strip() - # If weapon is one of the reskins it gets converted to the regular version - if weapon == "Hero Shot Replica": - weapon = "Splattershot" - elif weapon == "Octo Shot Replica": - weapon = "Tentatek Splattershot" - elif weapon == "Hero Blaster Replica": - weapon = "Blaster" - elif weapon == "Hero Roller Replica": - weapon = "Splat Roller" - elif weapon == "Herobrush Replica": - weapon = "Octobrush" - elif weapon == "Hero Charger Replica": - weapon = "Splat Charger" - elif weapon == "Hero Slosher Replica": - weapon = "Slosher" - elif weapon == "Hero Splatling Replica": - weapon = "Heavy Splatling" - elif weapon == "Hero Dualie Replicas": - weapon = "Splat Dualies" - elif weapon == "Hero Brella Replica": - weapon = "Splat Brella" - - print(f"{month} {year} - {mode} - {name} {unique_id} {rank} {x_power} {weapon}") - - placement_document = {"name": name, - "weapon": weapon, - "rank": rank, - "mode": mode, - "x_power": x_power, - "unique_id": unique_id, - "month": month, - "year": year} - - result = db.placements.insert_one(placement_document) - - player = db.players.find_one({ "unique_id": unique_id }) - - if player is None: - player = {"name": name, - "unique_id": unique_id, - "weapons": [weapon]} + if len(player[key_name]) <= 3: + player[key_name].append(result.inserted_id) else: - player["name"] = name - playerWeapons = player["weapons"] - playerWeapons.append(weapon) - player["weapons"] = list(dict.fromkeys(playerWeapons)) - - player = resolve_top_array("topTotal", player, result, x_power) - - if weapon in shooters: - player = resolve_top_array("topShooter", player, result, x_power) - elif weapon in blasters: - player = resolve_top_array("topBlaster", player, result, x_power) - elif weapon in rollers: - player = resolve_top_array("topRoller", player, result, x_power) - elif weapon in chargers: - player = resolve_top_array("topCharger", player, result, x_power) - elif weapon in sloshers: - player = resolve_top_array("topSlosher", player, result, x_power) - elif weapon in splatlings: - player = resolve_top_array("topSplatling", player, result, x_power) - elif weapon in dualies: - player = resolve_top_array("topDualies", player, result, x_power) - elif weapon in brellas: - player = resolve_top_array("topBrella", player, result, x_power) - else: - raise ValueError(f'Weapon "{weapon}"doesn\'t belong in any category') + lowest_power = 10000 + lowest_power_index = -1 + sum_of_powers = x_power + for index, placement_id in enumerate(player[key_name]): + high_placement = db.placements.find_one({"_id": placement_id}) + if high_placement is None: + raise ValueError( + f"Placement id {placement_id} not found in the database." + ) + sum_of_powers += high_placement["x_power"] + if high_placement["x_power"] < x_power: + if high_placement["x_power"] < lowest_power: + lowest_power = high_placement["x_power"] + lowest_power_index = index - if len(player["topTotal"]) == 1: # if player was just added - db.players.insert_one(player) - else: - db.players.find_one_and_replace({"unique_id": unique_id}, player) + if lowest_power_index != -1: + player[key_name][lowest_power_index] = result.inserted_id + sum_of_powers -= lowest_power + power_score = round((sum_of_powers / 4), 1) + player[f"{key_name}Score"] = power_score + return player - + +for filepath in glob.iglob( + abs_file_path +): # iterate through .json files in the xrank_data folder + if filepath.endswith(".json"): + path_without_folder = filepath.replace("xrank_data\\", "") + file_parts = path_without_folder.split("_") + print(path_without_folder) + month = list(calendar.month_name).index(file_parts[0].capitalize()) + + if "splat" in file_parts[1]: + mode = 1 + elif "tower" in file_parts[1]: + mode = 2 + elif "rainmaker" in file_parts[1]: + mode = 3 + else: + mode = 4 + with open(filepath) as f: + data = json.load(f) + for placement in data: + if placement["cheater"]: + continue + + rank = placement["rank"] + if rank > 500: + break + + name = placement["name"] + x_power = placement["x_power"] + unique_id = placement["unique_id"] + + weapon = placement["weapon"]["name"].strip() + # If weapon is one of the reskins it gets converted to the regular version + if weapon == "Hero Shot Replica": + weapon = "Splattershot" + elif weapon == "Octo Shot Replica": + weapon = "Tentatek Splattershot" + elif weapon == "Hero Blaster Replica": + weapon = "Blaster" + elif weapon == "Hero Roller Replica": + weapon = "Splat Roller" + elif weapon == "Herobrush Replica": + weapon = "Octobrush" + elif weapon == "Hero Charger Replica": + weapon = "Splat Charger" + elif weapon == "Hero Slosher Replica": + weapon = "Slosher" + elif weapon == "Hero Splatling Replica": + weapon = "Heavy Splatling" + elif weapon == "Hero Dualie Replicas": + weapon = "Splat Dualies" + elif weapon == "Hero Brella Replica": + weapon = "Splat Brella" + + print( + f"{month} {year} - {mode} - {name} {unique_id} {rank} {x_power} {weapon}" + ) + + placement_document = { + "name": name, + "weapon": weapon, + "rank": rank, + "mode": mode, + "x_power": x_power, + "unique_id": unique_id, + "month": month, + "year": year, + } + + result = db.placements.insert_one(placement_document) + + player = db.players.find_one({"unique_id": unique_id}) + + if player is None: + player = {"name": name, "unique_id": unique_id, "weapons": [weapon]} + else: + player["name"] = name + playerWeapons = player["weapons"] + playerWeapons.append(weapon) + player["weapons"] = list(dict.fromkeys(playerWeapons)) + + player = resolve_top_array("topTotal", player, result, x_power) + + if weapon in shooters: + player = resolve_top_array("topShooter", player, result, x_power) + elif weapon in blasters: + player = resolve_top_array("topBlaster", player, result, x_power) + elif weapon in rollers: + player = resolve_top_array("topRoller", player, result, x_power) + elif weapon in chargers: + player = resolve_top_array("topCharger", player, result, x_power) + elif weapon in sloshers: + player = resolve_top_array("topSlosher", player, result, x_power) + elif weapon in splatlings: + player = resolve_top_array("topSplatling", player, result, x_power) + elif weapon in dualies: + player = resolve_top_array("topDualies", player, result, x_power) + elif weapon in brellas: + player = resolve_top_array("topBrella", player, result, x_power) + else: + raise ValueError( + f'Weapon "{weapon}"doesn\'t belong in any category' + ) + + if len(player["topTotal"]) == 1: # if player was just added + db.players.insert_one(player) + else: + db.players.find_one_and_replace({"unique_id": unique_id}, player) + +# Updating weaponsCount +players = db.players.find({}) +for document in players: + amount_of_weapons = len(document["weapons"]) + if "weaponsCount" not in document or amount_of_weapons != document["weaponsCount"]: + db.players.update_one( + {"unique_id": document["unique_id"]}, + {"$set": {"weaponsCount": amount_of_weapons}}, + ) + if "weaponsCount" in document: + print( + f"{document['name']} updated! {document['weaponsCount']} -> {amount_of_weapons}" + ) + else: + print(f"New player: {document['name']} with {amount_of_weapons} weapons!") + +print("All done with updating the weaponsCount attributes.")