]> git.xonotic.org Git - xonotic/xonstat.git/blobdiff - xonstat/views/submission.py
Allow opting out of the ranking process.
[xonotic/xonstat.git] / xonstat / views / submission.py
index 55e1fd73245c047c476a679496cb48971830b466..908bf8667a9c45416dc299098407706b7a6623c0 100644 (file)
@@ -6,7 +6,7 @@ import re
 
 import pyramid.httpexceptions
 from sqlalchemy import Sequence
-from sqlalchemy.orm.exc import MultipleResultsFound, NoResultFound
+from sqlalchemy.orm.exc import NoResultFound
 from xonstat.elo import EloProcessor
 from xonstat.models import DBSession, Server, Map, Game, PlayerGameStat, PlayerWeaponStat
 from xonstat.models import PlayerRank, PlayerCaptime
@@ -91,6 +91,8 @@ class Submission(object):
         # does any human have a fastest cap?
         self.human_fastest = False
 
+        self.parse()
+
     def next_item(self):
         """Returns the next key:value pair off the queue."""
         try:
@@ -127,7 +129,7 @@ class Submission(object):
         """Construct a player events listing from the submission."""
 
         # all of the keys related to player records
-        player_keys = ['i', 'n', 't', 'e']
+        player_keys = ['i', 'n', 't', 'r', 'e']
 
         player = {key: pid}
 
@@ -338,7 +340,7 @@ def has_minimum_real_players(settings, submission):
     except:
         minimum_required_players = 2
 
-    return len(submission.human_players) >= minimum_required_players
+    return len(submission.humans) >= minimum_required_players
 
 
 def do_precondition_checks(settings, submission):
@@ -1046,21 +1048,29 @@ def submit_stats(request):
     """
     Entry handler for POST stats submissions.
     """
-    try:
-        # placeholder for the actual session
-        session = None
+    # placeholder for the actual session
+    session = None
 
+    try:
         log.debug("\n----- BEGIN REQUEST BODY -----\n" + request.body +
-                "----- END REQUEST BODY -----\n\n")
+                  "----- END REQUEST BODY -----\n\n")
 
         (idfp, status) = verify_request(request)
-        submission = Submission(request.body, request.headers)
+        try:
+            submission = Submission(request.body, request.headers)
+        except:
+            msg = "Invalid submission"
+            log.debug(msg)
+            raise pyramid.httpexceptions.HTTPUnprocessableEntity(
+                body=msg,
+                content_type="text/plain"
+            )
 
         do_precondition_checks(request.registry.settings, submission)
 
-        #----------------------------------------------------------------------
+        #######################################################################
         # Actual setup (inserts/updates) below here
-        #----------------------------------------------------------------------
+        #######################################################################
         session = DBSession()
 
         # All game types create Game, Server, Map, and Player records
@@ -1089,36 +1099,44 @@ def submit_stats(request):
         )
 
         events_by_hashkey = {elem["P"]: elem for elem in submission.humans + submission.bots}
-        get_or_create_players(session, game, gmap, events_by_hashkey)
+        players_by_hashkey = get_or_create_players(session, events_by_hashkey)
 
-        # keep track of the players we've seen
-        player_ids = []
         pgstats = []
-        hashkeys = {}
-        for events in submission.humans + submission.bots:
-            player = get_or_create_player(session, events['P'], events.get('n', None))
+        elo_pgstats = []
+        player_ids = []
+        hashkeys_by_player_id = {}
+        for hashkey, player in players_by_hashkey.items():
+            events = events_by_hashkey[hashkey]
             pgstat = create_game_stat(session, game, gmap, player, events)
             pgstats.append(pgstat)
 
+            # player ranking opt-out
+            if 'r' in events and events['r'] != "0":
+                log.debug("excluding player {} from Elo calculations".format(events['i']))
+                elo_pgstats.append(pgstat)
+
             if player.player_id > 1:
                 create_anticheats(session, pgstat, game, player, events)
 
             if player.player_id > 2:
                 player_ids.append(player.player_id)
-                hashkeys[player.player_id] = events['P']
+                hashkeys_by_player_id[player.player_id] = hashkey
 
             if should_do_weapon_stats(submission.game_type_cd) and player.player_id > 1:
                 create_weapon_stats(session, submission.version, game, player, pgstat, events)
 
-        # store them on games for easy access
+        # player_ids for human players get stored directly on games for fast indexing
         game.players = player_ids
 
         for events in submission.teams:
             create_team_stat(session, game, events)
 
         if server.elo_ind and gametype_elo_eligible(submission.game_type_cd):
-            ep = EloProcessor(session, game, pgstats)
+            ep = EloProcessor(session, game, elo_pgstats)
             ep.save(session)
+            elos = ep.wip
+        else:
+            elos = {}
 
         session.commit()
         log.debug('Success! Stats recorded.')
@@ -1135,8 +1153,8 @@ def submit_stats(request):
                 "game": game,
                 "gmap": gmap,
                 "player_ids": player_ids,
-                "hashkeys": hashkeys,
-                "elos": ep.wip,
+                "hashkeys": hashkeys_by_player_id,
+                "elos": elos,
                 "ranks": ranks,
         }