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 (
+
+
+ setShowCode(!showCode)}>Show emoji code
+ {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 (
+
+ )
+}
+
+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.")