Skip to content
This repository has been archived by the owner on Oct 19, 2021. It is now read-only.

Commit

Permalink
Release 0.3
Browse files Browse the repository at this point in the history
Please see release page for change log.
  • Loading branch information
PhlexPlexico authored Aug 19, 2019
2 parents f4c735f + 4faa321 commit 444aa2f
Show file tree
Hide file tree
Showing 31 changed files with 668 additions and 214 deletions.
8 changes: 8 additions & 0 deletions .github/FUNDING.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# These are supported funding model platforms

github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
patreon: #
open_collective: # Replace with a single Open Collective username
ko_fi: phlexplexico
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
[![GitHub Downloads](https://img.shields.io/github/downloads/phlexplexico/get5-web/total.svg?label=Downloads)](https://github.com/phlexplexico/get5-web/releases/latest)
---

**Status: Supported, No Longer Under Development**
**Status: Supported**



Expand Down
15 changes: 9 additions & 6 deletions get5/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
import logging.handlers
import re
import sys
import os
import os

import logos
import steamid
Expand All @@ -43,10 +43,11 @@
# Import the Flask Framework
app = Flask(__name__, instance_relative_config=True)
app.config.from_pyfile('prod_config.py')
# Using match config of utf-8.
app.config['JSON_AS_ASCII'] = False
LOGO_FOLDER = os.path.realpath(os.path.join(os.getcwd(), os.path.dirname(__file__), 'static', 'resource', 'csgo', 'resource', 'flash', 'econ', 'tournaments', 'teams'))
PANO_LOGO_FOLDER = os.path.realpath(os.path.join(os.getcwd(), os.path.dirname(__file__), 'static', 'resource', 'csgo', 'materials', 'panorama', 'images', 'tournaments', 'teams'))

LOGO_FOLDER = os.path.realpath(os.path.join(os.getcwd(), os.path.dirname(
__file__), 'static', 'resource', 'csgo', 'resource', 'flash', 'econ', 'tournaments', 'teams'))
PANO_LOGO_FOLDER = os.path.realpath(os.path.join(os.getcwd(), os.path.dirname(
__file__), 'static', 'resource', 'csgo', 'materials', 'panorama', 'images', 'tournaments', 'teams'))
app.config['LOGO_FOLDER'] = LOGO_FOLDER
app.config['PANO_LOGO_FOLDER'] = PANO_LOGO_FOLDER
# Setup caching
Expand Down Expand Up @@ -90,7 +91,7 @@

# Find version info
app.jinja_env.globals.update(COMMIT_STRING=util.get_version())
#Set our webpanel name.
# Set our webpanel name.
app.jinja_env.globals.update(WEBPANEL_NAME=app.config['WEBPANEL_NAME'])

# Setup any data structures needed
Expand Down Expand Up @@ -120,6 +121,7 @@ def register_blueprints():
from stats import stats_blueprint
app.register_blueprint(stats_blueprint)


@app.route('/login')
@oid.loginhandler
def login():
Expand Down Expand Up @@ -244,6 +246,7 @@ def add_val(name, value):
'LOG_PATH': None,
'DEBUG': False,
'TESTING': False,
'JSON_AS_ASCII': False,
'SQLALCHEMY_DATABASE_URI': 'mysql://user:password@host/db',
'SQLALCHEMY_TRACK_MODIFICATIONS': False,
'STEAM_API_KEY': '???',
Expand Down
5 changes: 5 additions & 0 deletions get5/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,12 @@ def match_api_check(request, match):
if match.finalized():
raise BadRequestError('Match already finalized')


def match_demo_api_check(request, match):
if match.api_key != request.values.get('key'):
raise BadRequestError('Wrong API key')


@api_blueprint.route('/match/<int:matchid>/finish', methods=['POST'])
@limiter.limit('60 per hour', key_func=rate_limit_key)
def match_finish(matchid):
Expand Down Expand Up @@ -83,6 +85,7 @@ def match_finish(matchid):
app.logger.info('Finished match {}, winner={}'.format(match, winner))
return 'Success'


@api_blueprint.route('/match/<int:matchid>/map/<int:mapnumber>/start', methods=['POST'])
@limiter.limit('60 per hour', key_func=rate_limit_key)
def match_map_start(matchid, mapnumber):
Expand Down Expand Up @@ -139,6 +142,7 @@ def match_veto_update(matchid):
teamName, request.values.get('map')))
return 'Success'


@api_blueprint.route('/match/<int:matchid>/map/<int:mapnumber>/demo', methods=['POST'])
@limiter.limit('60 per hour', key_func=rate_limit_key)
def match_demo_name(matchid, mapnumber):
Expand All @@ -154,6 +158,7 @@ def match_demo_name(matchid, mapnumber):
app.logger.info("Made it through the demo post.")
return 'Success'


@api_blueprint.route('/match/<int:matchid>/map/<int:mapnumber>/finish', methods=['POST'])
@limiter.limit('60 per hour', key_func=rate_limit_key)
def match_map_finish(matchid, mapnumber):
Expand Down
16 changes: 8 additions & 8 deletions get5/api_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,14 +64,14 @@ def test_match_stats(self):
# Send a player stats update
response = self.app.post(
'/match/1/map/0/player/76561198053858673/update',
data={
'roundsplayed': '5',
'kills': '5',
'deaths': '3',
'damage': '500',
'team': 'team1',
'key': matchkey,
})
data={
'roundsplayed': '5',
'kills': '5',
'deaths': '3',
'damage': '500',
'team': 'team1',
'key': matchkey,
})
self.assertEqual(response.status_code, 200)
playerstats = PlayerStats.query.filter_by(
match_id=1, map_id=1, steam_id=76561198053858673).first()
Expand Down
4 changes: 2 additions & 2 deletions get5/get5_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,9 @@ def create_test_data(self):
db.session.commit()

Match.create(user, team1.id, team2.id, '', '', 1, False,
'Map {MAPNUMBER}', ['de_dust2', 'de_cache', 'de_mirage'], season.id, 'always_knife', 'CT', server.id)
'Map {MAPNUMBER}', ['de_dust2', 'de_cache', 'de_mirage'], season.id, 'always_knife', 'CT', True, server.id, 0, 0, None)
db.session.commit()

vetoBan = Veto.create(1, 'EnvyUs', 'de_dust2', 'ban')
vetoPick = Veto.create(1, 'EnvyUs', 'de_overpass', 'pick')
db.session.commit()
db.session.commit()
76 changes: 66 additions & 10 deletions get5/leaderboard.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@
import steamid
import get5
from get5 import app, db, BadRequestError, config_setting
from models import User, Team, Match, GameServer, MapStats, Season
from models import User, Team, Match, GameServer, MapStats, PlayerStats, Season
from collections import OrderedDict, defaultdict
from datetime import datetime
from statistics import mean
import util
import re
from copy import deepcopy
Expand All @@ -21,24 +22,26 @@ def getLeaderboard(seasonid=None):
seasonsBoard = False
else:
totalMatches = Match.query.order_by(-Match.id).filter(
Match.cancelled == False, Match.end_time.isnot(None),
Match.cancelled == False, Match.end_time.isnot(None),
Match.season_id == seasonid, Match.winner.isnot(None))
seasonsBoard = True
season = Season.query.get_or_404(seasonid)
allTeams = Team.query.order_by(-Team.id)
# Shoutouts to n3rds.
dTeamStandings = defaultdict(lambda: {'teamid': 0, 'wins': 0, 'losses': 0, 'rounddiff': 0})
dTeamStandings = defaultdict(
lambda: {'teamid': 0, 'wins': 0, 'losses': 0, 'rounddiff': 0})
# Build our own object with team and links, rank, and round diff?
# Building our own object requires matches, map_stats for each match.
# Just build a dictionary with each match and stats?
for match in totalMatches:
for match in totalMatches:
map_stats = MapStats.query.filter_by(
match_id=match.id)
# Get the losing team, and scores for round difference.
for all_stats in map_stats:
winningRounds = 0
losingRounds = 0
# Get each winner ID and create a list that returns the Team Name, amount of wins for now.
# Get each winner ID and create a list that returns the Team Name,
# amount of wins for now.
winningTeam = Team.query.filter_by(id=all_stats.winner).first()
if all_stats.winner == match.team1_id:
losingTeam = Team.query.filter_by(id=match.team2_id).first()
Expand All @@ -52,13 +55,13 @@ def getLeaderboard(seasonid=None):
# Update winning and losing teams.
dTeamStandings[winningTeam.name]['teamid'] = winningTeam.id
dTeamStandings[winningTeam.name]['wins'] += 1
dTeamStandings[winningTeam.name]['rounddiff'] += (winningRounds - losingRounds)
dTeamStandings[winningTeam.name][
'rounddiff'] += (winningRounds - losingRounds)
dTeamStandings[losingTeam.name]['teamid'] = losingTeam.id
dTeamStandings[losingTeam.name]['losses'] += 1
dTeamStandings[losingTeam.name]['rounddiff'] += (losingRounds - winningRounds)
dTeamStandings[losingTeam.name][
'rounddiff'] += (losingRounds - winningRounds)



# Sort teams via lexigraphical sort, very inefficient but it works for now.
dTeamStandings = OrderedDict(
sorted(dTeamStandings.items(), key=lambda x: (x[1].get('wins'), x[1].get('losses'), x[1].get('rounddiff')), reverse=True))
Expand All @@ -69,6 +72,46 @@ def getLeaderboard(seasonid=None):
return render_template('leaderboard.html', standings=dTeamStandings, user=g.user, seasonsBoard=seasonsBoard)


def getPlayerLeaderboard(seasonid=None):
dctPlayer = {'steamid': '', 'steamurl': '', 'name': '', 'kills': 0, 'deaths': 0, 'kdr': 0.0, 'assists': 0, 'adr': 0.0,
'3k': 0, '4k': 0, '5k': 0, '1v1': 0, '1v2': 0, '1v3': 0, '1v4': 0, '1v5': 0, 'rating': 0.0, 'hsp': 0.0, 'trp': 0, 'fba': 0}
lstAllPlayerDict = []
playerValues = PlayerStats.query.all()
# Filter through every steam ID
for player in playerValues:
if any(d.get('steamid', None) == player.get_steam_id() for d in lstAllPlayerDict):
continue
# query match id to find season if we have one.
if (seasonid):
curMatch = Match.query.filter_by(id=player.match_id).first()
if (curMatch.season_id != seasonid):
continue
totalStats = PlayerStats.query.filter_by(
steam_id=player.get_steam_id())
dctPlayer['steamid'] = (player.get_steam_id())
dctPlayer['steamurl'] = (player.get_steam_url())
dctPlayer['name'] = (player.get_player_name())
dctPlayer['kills'] = (sum(c.kills for c in totalStats))
dctPlayer['deaths'] = (sum(c.deaths for c in totalStats))
dctPlayer['kdr'] = (mean(c.get_kdr() for c in totalStats))
dctPlayer['assists'] = (sum(c.assists for c in totalStats))
dctPlayer['adr'] = (mean(c.get_adr() for c in totalStats))
dctPlayer['3k'] = (sum(c.k3 for c in totalStats))
dctPlayer['4k'] = (sum(c.k4 for c in totalStats))
dctPlayer['5k'] = (sum(c.k5 for c in totalStats))
dctPlayer['1v1'] = (sum(c.v1 for c in totalStats))
dctPlayer['1v2'] = (sum(c.v2 for c in totalStats))
dctPlayer['1v3'] = (sum(c.v3 for c in totalStats))
dctPlayer['1v4'] = (sum(c.v4 for c in totalStats))
dctPlayer['1v5'] = (sum(c.v5 for c in totalStats))
dctPlayer['rating'] = (mean(c.get_rating() for c in totalStats))
dctPlayer['hsp'] = (mean(c.get_hsp() for c in totalStats))
dctPlayer['trp'] = (sum(c.roundsplayed for c in totalStats))
dctPlayer['fba'] = (sum(c.flashbang_assists for c in totalStats))
lstAllPlayerDict.append(dctPlayer)
dctPlayer = {}
return lstAllPlayerDict

leaderboard_blueprint = Blueprint('leaderboard', __name__)


Expand All @@ -77,6 +120,19 @@ def leaderboard():
return getLeaderboard()


@leaderboard_blueprint.route('/leaderboard/season/<int:seasonid>/')
@leaderboard_blueprint.route('/leaderboard/season/<int:seasonid>')
def seasonal_leaderboard(seasonid):
return getLeaderboard(seasonid)


@leaderboard_blueprint.route('/leaderboard/season/<int:seasonid>/players')
def seasonal_player_leaderboard(seasonid):
season = Season.query.get_or_404(seasonid)
playerValues = getPlayerLeaderboard(seasonid)
return render_template('statleaderboard.html', board=playerValues, season=season.name)


@leaderboard_blueprint.route('/leaderboard/players')
def player_leaderboard():
playerValues = getPlayerLeaderboard()
return render_template('statleaderboard.html', board=playerValues)
18 changes: 15 additions & 3 deletions get5/leaderboard_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,26 @@ def test_render_pages_loggedin(self):
with c.session_transaction() as sess:
sess['user_id'] = 1
self.assertEqual(self.app.get('/leaderboard').status_code, 200)
self.assertEqual(self.app.get('/leaderboard/season/1/').status_code, 200)
self.assertEqual(self.app.get(
'/leaderboard/season/1').status_code, 200)
self.assertEqual(self.app.get(
'/leaderboard/players').status_code, 200)
self.assertEqual(self.app.get(
'/leaderboard/season/1/players').status_code, 200)

def test_render_pages_not_loggedin(self):
self.assertEqual(self.app.get('/leaderboard').status_code, 200)
self.assertEqual(self.app.get('/leaderboard/season/1/').status_code, 200)
self.assertEqual(self.app.get(
'/leaderboard/season/1').status_code, 200)
self.assertEqual(self.app.get('/leaderboard/players').status_code, 200)
self.assertEqual(self.app.get(
'/leaderboard/season/1/players').status_code, 200)

def test_render_pages_not_found(self):
self.assertEqual(self.app.get('/leaderboard/season/2/').status_code, 404)
self.assertEqual(self.app.get(
'/leaderboard/season/2').status_code, 404)
self.assertEqual(self.app.get(
'/leaderboard/season/2/players').status_code, 404)

if __name__ == '__main__':
unittest.main()
29 changes: 16 additions & 13 deletions get5/logos.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@

_logos = set()


def get_pano_dir():
return os.path.realpath(os.path.join(os.getcwd(), os.path.dirname(__file__), 'static', 'resource', 'csgo', 'materials', 'panorama', 'images', 'tournaments', 'teams'))
return os.path.realpath(os.path.join(os.getcwd(), os.path.dirname(__file__), 'static', 'resource', 'csgo', 'materials', 'panorama', 'images', 'tournaments', 'teams'))


def get_logo_dir():
return os.path.realpath(os.path.join(os.getcwd(), os.path.dirname(__file__), 'static', 'resource', 'csgo', 'resource', 'flash', 'econ', 'tournaments', 'teams'))
Expand All @@ -21,12 +23,13 @@ def initialize_logos():
team_tag = os.path.splitext(team_tag_filename)[0]
_logos.add(team_tag)

for filename in glob.glob(os.path.join(pano_logo_path, '*.svg')):
team_tag_filename = os.path.basename(filename)
# Remove the extension
team_tag = os.path.splitext(team_tag_filename)[0]
if not has_logo(team_tag):
_logos.add(team_tag)
for filename in glob.glob(os.path.join(pano_logo_path, '*.svg')):
team_tag_filename = os.path.basename(filename)
# Remove the extension
team_tag = os.path.splitext(team_tag_filename)[0]
if not has_logo(team_tag):
_logos.add(team_tag)


def add_new_logo(tag):
global _logos
Expand All @@ -44,9 +47,9 @@ def get_logo_choices():


def get_logo_img(tag):
if has_logo(tag) and os.path.isfile(os.path.join(get_logo_dir(),'{}.png'.format(tag))):
return '/static/resource/csgo/resource/flash/econ/tournaments/teams/{}.png'.format(tag)
elif has_logo(tag) and os.path.isfile(os.path.join(get_pano_dir(),'{}.svg'.format(tag))):
return '/static/resource/csgo/materials/panorama/images/tournaments/teams/{}.svg'.format(tag)
else:
return None
if has_logo(tag) and os.path.isfile(os.path.join(get_logo_dir(), '{}.png'.format(tag))):
return '/static/resource/csgo/resource/flash/econ/tournaments/teams/{}.png'.format(tag)
elif has_logo(tag) and os.path.isfile(os.path.join(get_pano_dir(), '{}.svg'.format(tag))):
return '/static/resource/csgo/materials/panorama/images/tournaments/teams/{}.svg'.format(tag)
else:
return None
Loading

0 comments on commit 444aa2f

Please sign in to comment.