readded calendar and xleaderboard

This commit is contained in:
Sendou
2019-10-11 20:07:47 +03:00
parent b4d73794a5
commit 3b4217ca4a
48 changed files with 1592 additions and 312 deletions

View File

@@ -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)
module.exports = mongoose.model("Player", playerSchema)

View File

@@ -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",

View File

@@ -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",

View File

@@ -1,2 +1,2 @@
# https://www.robotstxt.org/robotstxt.html
User-agent: *
Disallow:

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

View File

@@ -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 = `<iframe title="calendar" src="https://calendar.google.com/calendar/embed?height=600&amp;wkst=2&amp;bgcolor=%23ffffff&amp;src=NDNnYnJlamkxbnQyZTY1dWJuZzdvYWkxZGtAZ3JvdXAuY2FsZW5kYXIuZ29vZ2xlLmNvbQ&amp;color=%23E67C73&amp;showTitle=0&amp;showNav=1&amp;showDate=1&amp;showPrint=0&amp;showCalendars=0&amp;ctz=${jstz
.determine()
.name()}" style=border-width: 0 width=${containerWidth} height="1000" frameBorder="0" scrolling="no"></iframe>`
//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 (
<div>
<div>
<Button onClick={() => setShowCode(!showCode)}>Show emoji code</Button>
{showCode && (
<Segment raised compact>
<h4>
<span role="img" aria-label="money bag emoji">
💰
</span>{" "}
- Has prizes
<br />
<span role="img" aria-label="masks emoji">
🎭
</span>{" "}
- Unconventional ruleset
<br />
<span role="img" aria-label="lock emoji">
🔒
</span>{" "}
- Limited registration
<br />
<span role="img" aria-label="handshake emoji">
🤝
</span>{" "}
- Local event
<br />
<span role="img" aria-label="dice emoji">
🎲
</span>{" "}
- Solo registration available
<br />
<span role="img" aria-label="eyes emoji">
👀
</span>{" "}
- No open registration
</h4>
</Segment>
)}
</div>
<div style={{ paddingTop: "15px" }} ref={calenderDiv}></div>
If an event is missing you can contact{" "}
<a href="https://twitter.com/Kbot_273">Kbot</a> about it.
<br />
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{" "}
<a href="https://calendar.google.com/calendar/ical/43gbreji1nt2e65ubng7oai1dk%40group.calendar.google.com/public/basic.ics">
this link
</a>{" "}
instead.
</div>
)
}
export default PageCalendar

View File

@@ -19,36 +19,36 @@ const MainMenu = () => {
<Dropdown item text="Tools">
<Dropdown.Menu style={dropdownStyle}>
<Dropdown.Item as={NavLink} exact to="/maps">
<Dropdown.Item as={NavLink} to="/maps">
Maplist Generator
</Dropdown.Item>
<Dropdown.Item as={NavLink} exact to="/rotation">
<Dropdown.Item as={NavLink} to="/rotation">
Rotation
</Dropdown.Item>
<Dropdown.Item as={NavLink} exact to="/plans">
<Dropdown.Item as={NavLink} to="/plans">
Map Planner
</Dropdown.Item>
<Dropdown.Item as={NavLink} exact to="/calendar">
<Dropdown.Item as={NavLink} to="/calendar">
Calendar
</Dropdown.Item>
</Dropdown.Menu>
</Dropdown>
<Dropdown item text="Collections">
<Dropdown.Menu style={dropdownStyle}>
<Dropdown.Item as={NavLink} exact to="/builds">
<Dropdown.Item as={NavLink} to="/builds">
Builds
</Dropdown.Item>
</Dropdown.Menu>
</Dropdown>
<Dropdown item text="X Rank">
<Dropdown.Menu style={dropdownStyle}>
<Dropdown.Item as={NavLink} exact to="/xleaderboard">
<Dropdown.Item as={NavLink} to="/xleaderboard">
Leaderboards
</Dropdown.Item>
<Dropdown.Item as={NavLink} exact to="/xsearch">
<Dropdown.Item as={NavLink} to="/xsearch">
Top 500 Browser
</Dropdown.Item>
<Dropdown.Item as={NavLink} exact to="/trends">
<Dropdown.Item as={NavLink} to="/trends">
Trends
</Dropdown.Item>
</Dropdown.Menu>

View File

@@ -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 = () => {
<Route path="/plans">
<MapPlanner />
</Route>
<Route path="/calendar">
<Calendar />
</Route>
<Route path="/xleaderboard">
<XLeaderboard />
</Route>
</Switch>
</Suspense>
)

View File

@@ -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 (
<div style={{ paddingTop: "2em" }}>
<Loading />
</div>
)
}
if (result.error) {
return <Error />
}
const leaderboard = result.data["topFlex"]
return (
<Table basic="very">
<Table.Header>
<Table.Row>
<Table.HeaderCell></Table.HeaderCell>
<Table.HeaderCell>Name</Table.HeaderCell>
<Table.HeaderCell>
Power
<Popup
trigger={<Icon name="question circle" />}
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"
/>
</Table.HeaderCell>
<Table.HeaderCell>Total Power</Table.HeaderCell>
</Table.Row>
</Table.Header>
<Table.Body>
{leaderboard.map((player, index) => (
<Table.Row key={player.id}>
<Table.Cell>{index + 1}</Table.Cell>
<Table.Cell>
<Link
to={`/xsearch/p/${player.unique_id}`}
style={{ color: "black" }}
>
<u>{player.alias ? player.alias : player.name}</u>
</Link>
{player.twitter ? (
<a href={`https://twitter.com/${player.twitter}`}>
<Icon style={{ paddingLeft: "5px" }} name="twitter" />
</a>
) : null}
</Table.Cell>
<Table.Cell>{player.weaponsCount}</Table.Cell>
<Table.Cell>{player.topTotalScore}</Table.Cell>
</Table.Row>
))}
</Table.Body>
</Table>
)
}
export default FlexLeaderboard

View File

@@ -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 (
<Popup
key={`${mode}${month}${w.year}`}
trigger={
<img
style={{ height: "60px", width: "60px" }}
src={`https://raw.githubusercontent.com/Leanny/leanny.github.io/master/splat2/weapons/Wst_${
weaponDict[w["weapon"]]
}.png`}
alt={w.name}
/>
}
header={w.name}
content={`${w.x_power} (${w.rank} ${mode} - ${month} ${w.year})`}
/>
)
})}
</>
)
}
export default FourWeapons

View File

@@ -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 (
<div style={{ paddingTop: "2em" }}>
<Loading />
</div>
)
}
if (result.error) {
return <Error />
}
const leaderboard = result.data[queryName]
return (
<div style={{ margin: "1.5em" }}>
<Table basic="very">
<Table.Header>
<Table.Row>
<Table.HeaderCell />
<Table.HeaderCell>Name</Table.HeaderCell>
<Table.HeaderCell>
Power
<Popup
trigger={<Icon name="question circle" />}
content="Leaderboard explanation"
position="bottom center"
/>
</Table.HeaderCell>
<Table.HeaderCell>Weapons</Table.HeaderCell>
</Table.Row>
</Table.Header>
<Table.Body>
{leaderboard.map((player, index) => (
<Table.Row key={player.id}>
<Table.Cell>{index + 1}</Table.Cell>
<Table.Cell>
<Link
to={`/xsearch/p/${player.unique_id}`}
style={{ color: "black" }}
>
<u>{player.alias ? player.alias : player.name}</u>
</Link>
{player.twitter ? (
<a href={`https://twitter.com/${player.twitter}`}>
<Icon style={{ paddingLeft: "5px" }} name="twitter" />
</a>
) : null}
</Table.Cell>
<Table.Cell>{player[scoreField]}</Table.Cell>
<Table.Cell>
<FourWeapons weapons={player[weaponsField]} />
</Table.Cell>
</Table.Row>
))}
</Table.Body>
</Table>
</div>
)
}
export default WeaponLeaderboard

View File

@@ -0,0 +1,14 @@
import React from "react"
import XLeaderBoardMenu from "./XLeaderboardMenu"
import XLeaderboardRoutes from "./XLeaderboardRoutes"
const XLeaderboard = () => {
return (
<>
<XLeaderBoardMenu />
<XLeaderboardRoutes />
</>
)
}
export default XLeaderboard

View File

@@ -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 (
<div className="ui centered grid">
<div className="center aligned column">
<Responsive minWidth={800}>
<Menu compact icon="labeled">
<Menu.Item name="all" as={NavLink} exact to="/xleaderboard">
<img style={wpnIcon} src={allIcon} alt="All Icon" />
All
</Menu.Item>
<Menu.Item name="flex" as={NavLink} exact to="/xleaderboard/flex">
<img style={wpnIcon} src={flexIcon} alt="Flex icon" />
Flex
</Menu.Item>
<Menu.Item
name="shooters"
as={NavLink}
exact
to="/xleaderboard/shooters"
>
<img style={wpnIcon} src={shooterIcon} alt="Shooter Icon" />
Shooters
</Menu.Item>
<Menu.Item
name="blasters"
as={NavLink}
exact
to="/xleaderboard/blasters"
>
<img style={wpnIcon} src={blasterIcon} alt="Blaster Icon" />
Blasters
</Menu.Item>
<Menu.Item
name="rollers"
as={NavLink}
exact
to="/xleaderboard/rollers"
>
<img style={wpnIcon} src={rollerIcon} alt="Roller Icon" />
Rollers
</Menu.Item>
<Menu.Item
name="chargers"
as={NavLink}
exact
to="/xleaderboard/chargers"
>
<img style={wpnIcon} src={chargerIcon} alt="Charger Icon" />
Chargers
</Menu.Item>
<Menu.Item
name="splatlings"
as={NavLink}
exact
to="/xleaderboard/splatlings"
>
<img style={wpnIcon} src={splatlingIcon} alt="Splatling Icon" />
Splatlings
</Menu.Item>
<Menu.Item
name="sloshers"
as={NavLink}
exact
to="/xleaderboard/sloshers"
>
<img style={wpnIcon} src={slosherIcon} alt="Slosher Icon" />
Sloshers
</Menu.Item>
<Menu.Item
name="dualies"
as={NavLink}
exact
to="/xleaderboard/dualies"
>
<img style={wpnIcon} src={dualieIcon} alt="Dualie Icon" />
Dualies
</Menu.Item>
<Menu.Item
name="brella"
as={NavLink}
exact
to="/xleaderboard/brellas"
>
<img style={wpnIcon} src={brellaIcon} alt="Brella Icon" />
Brellas
</Menu.Item>
</Menu>
</Responsive>
<Responsive maxWidth={799}>
<Menu compact icon="labeled">
<Menu.Item name="all" as={NavLink} exact to="/xleaderboard">
<img style={wpnIcon} src={allIcon} alt="All Icon" />
All
</Menu.Item>
</Menu>
<Menu.Item name="flex" as={NavLink} exact to="/xleaderboard/flex">
<img style={wpnIcon} src={flexIcon} alt="Flex icon" />
Flex
</Menu.Item>
<Menu compact icon="labeled">
<Menu.Item
name="shooters"
as={NavLink}
exact
to="/xleaderboard/shooters"
>
<img style={wpnIcon} src={shooterIcon} alt="Shooter Icon" />
Shooters
</Menu.Item>
<Menu.Item
name="blasters"
as={NavLink}
exact
to="/xleaderboard/blasters"
>
<img style={wpnIcon} src={blasterIcon} alt="Blaster Icon" />
Blasters
</Menu.Item>
<Menu.Item
name="rollers"
as={NavLink}
exact
to="/xleaderboard/rollers"
>
<img style={wpnIcon} src={rollerIcon} alt="Roller Icon" />
Rollers
</Menu.Item>
<Menu.Item
name="chargers"
as={NavLink}
exact
to="/xleaderboard/chargers"
>
<img style={wpnIcon} src={chargerIcon} alt="Charger Icon" />
Chargers
</Menu.Item>
</Menu>
<Menu compact icon="labeled">
<Menu.Item
name="splatlings"
as={NavLink}
exact
to="/xleaderboard/splatlings"
>
<img style={wpnIcon} src={splatlingIcon} alt="Splatling Icon" />
Splatlings
</Menu.Item>
<Menu.Item
name="sloshers"
as={NavLink}
exact
to="/xleaderboard/sloshers"
>
<img style={wpnIcon} src={slosherIcon} alt="Slosher Icon" />
Sloshers
</Menu.Item>
<Menu.Item
name="dualies"
as={NavLink}
exact
to="/xleaderboard/dualies"
>
<img style={wpnIcon} src={dualieIcon} alt="Dualie Icon" />
Dualies
</Menu.Item>
<Menu.Item
name="brella"
as={NavLink}
exact
to="/xleaderboard/brellas"
>
<img style={wpnIcon} src={brellaIcon} alt="Brella Icon" />
Brellas
</Menu.Item>
</Menu>
</Responsive>
</div>
</div>
)
}
export default XLeaderBoardMenu

View File

@@ -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 (
<>
<Route
exact
path="/xleaderboard"
render={() => (
<WeaponLeaderboard
query={topTotalPlayers}
queryName="topTotalPlayers"
scoreField="topTotalScore"
weaponsField="topTotal"
/>
)}
/>
<Route
exact
path="/xleaderboard/flex"
render={() => <FlexLeaderboard />}
/>
<Route
exact
path="/xleaderboard/shooters"
render={() => (
<WeaponLeaderboard
query={topShooterPlayers}
queryName="topShooterPlayers"
scoreField="topShooterScore"
weaponsField="topShooter"
/>
)}
/>
<Route
exact
path="/xleaderboard/blasters"
render={() => (
<WeaponLeaderboard
query={topBlasterPlayers}
queryName="topBlasterPlayers"
scoreField="topBlasterScore"
weaponsField="topBlaster"
/>
)}
/>
<Route
exact
path="/xleaderboard/rollers"
render={() => (
<WeaponLeaderboard
query={topRollerPlayers}
queryName="topRollerPlayers"
scoreField="topRollerScore"
weaponsField="topRoller"
/>
)}
/>
<Route
exact
path="/xleaderboard/chargers"
render={() => (
<WeaponLeaderboard
query={topChargerPlayers}
queryName="topChargerPlayers"
scoreField="topChargerScore"
weaponsField="topCharger"
/>
)}
/>
<Route
exact
path="/xleaderboard/splatlings"
render={() => (
<WeaponLeaderboard
query={topSplatlingPlayers}
queryName="topSplatlingPlayers"
scoreField="topSplatlingScore"
weaponsField="topSplatling"
/>
)}
/>
<Route
exact
path="/xleaderboard/sloshers"
render={() => (
<WeaponLeaderboard
query={topSlosherPlayers}
queryName="topSlosherPlayers"
scoreField="topSlosherScore"
weaponsField="topSlosher"
/>
)}
/>
<Route
exact
path="/xleaderboard/dualies"
render={() => (
<WeaponLeaderboard
query={topDualiesPlayers}
queryName="topDualiesPlayers"
scoreField="topDualiesScore"
weaponsField="topDualies"
/>
)}
/>
<Route
exact
path="/xleaderboard/brellas"
render={() => (
<WeaponLeaderboard
query={topBrellaPlayers}
queryName="topBrellaPlayers"
scoreField="topBrellaScore"
weaponsField="topBrella"
/>
)}
/>
</>
)
}
export default XLeaderboardRoutes

12
react-ui/src/graphql/queries/links.js vendored Normal file
View File

@@ -0,0 +1,12 @@
import { gql } from 'apollo-boost'
export const links = gql`
{
links {
title
url
description
type
}
}
`

View File

@@ -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
}
}
}
`

View File

@@ -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
}
}
}
`

View File

@@ -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
}
}
`

View File

@@ -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
}
}
`

View File

@@ -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
}
}
`

View File

@@ -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
}
}
`

View File

@@ -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
}
}
`

View File

@@ -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
}
}
}
`

View File

@@ -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
}
}
}
`

View File

@@ -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
}
}
}
`

View File

@@ -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
}
}
}
`

15
react-ui/src/graphql/queries/topFlex.js vendored Normal file
View File

@@ -0,0 +1,15 @@
import { gql } from 'apollo-boost'
export const topFlex = gql`
{
topFlex {
id
unique_id
name
alias
twitter
weaponsCount
topTotalScore
}
}
`

View File

@@ -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
}
}
}
`

View File

@@ -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
}
}
}
`

View File

@@ -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
}
}
}
`

View File

@@ -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
}
}
}
`

View File

@@ -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
}
}
}
`

View File

@@ -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
}
}
}
`

View File

@@ -0,0 +1,11 @@
import { gql } from 'apollo-boost'
export const userLean = gql`
{
user {
username
avatar
discord_id
}
}
`

View File

@@ -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(
<Router>

View File

@@ -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",

View File

@@ -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
}
}

3
scripts/.vscode/settings.json vendored Normal file
View File

@@ -0,0 +1,3 @@
{
"python.formatting.provider": "black"
}

View File

@@ -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.")