예제 #1
0
    def get_gamepage(self, game, no_refresh=False):
        key = self.get_gamepage_memkey(game)
        gamepage = memcache.get(key)
        if gamepage is None and not no_refresh:
            # Not in memcache, so construct the gamepage and store it in
            # memcache.
            # Gamepage is a list of dictionaries. These dictionaries have up
            # to 5 keys, 'category', 'bk_runner', 'bk_time', 'bk_video' and
            # 'infolist'.
            gamepage = []

            # Grab the game model
            game_model = self.get_game_model(util.get_code(game))
            if game_model is None:
                logging.error("Could not create " + key + " due to no " + "game model")
                return None
            gameinfolist = json.loads(game_model.info)

            # Use a projection query to get all of the unique
            # username, category pairs
            q = db.Query(runs.Runs, projection=("username", "category"), distinct=True)
            q.ancestor(runs.key())
            q.filter("game =", game)
            q.order("category")
            cur_category = None
            for run in q.run(limit=1000):
                if run.category != cur_category:
                    # New category
                    d = dict(category=run.category, category_code=util.get_code(run.category), infolist=[])
                    gamepage.append(d)
                    cur_category = run.category
                    # Check for a best known time for this category
                    for gameinfo in gameinfolist:
                        if gameinfo["category"] == run.category:
                            d["bk_runner"] = gameinfo.get("bk_runner")
                            d["bk_time"] = util.seconds_to_timestr(gameinfo.get("bk_seconds"))
                            d["bk_date"] = util.datestr_to_date(gameinfo.get("bk_datestr"))[0]
                            d["bk_video"] = gameinfo.get("bk_video")
                            break

                # Add the info to the gamepage
                info = self.get_runinfo(run.username, game, run.category)
                d["infolist"].append(info)

            # For each category, sort the runlist by seconds, breaking ties
            # by date
            for runlist in gamepage:
                runlist["infolist"].sort(key=lambda x: util.get_valid_date(x["pb_date"]))
                runlist["infolist"].sort(key=itemgetter("pb_seconds"))

            # Sort the categories by number of runners
            gamepage.sort(key=lambda x: len(x["infolist"]), reverse=True)

            if memcache.set(key, gamepage):
                logging.debug("Set " + key + " in memcache")
            else:
                logging.warning("Failed to set " + key + " in memcache")
        elif gamepage is not None:
            logging.debug("Got " + key + " from memcache")
        return gamepage
예제 #2
0
    def update_runlist_for_runner_put( self, params ):
        user = params[ 'user' ]
        game = params[ 'game' ]
        game_code = params[ 'game_code' ]
        category = params[ 'category' ]
        time = params[ 'time' ]
        video = params[ 'video' ]
        version = params[ 'version' ]
        notes = params[ 'notes' ]
        date = params[ 'date' ]
        datetime_created = params[ 'datetime_created' ]
        run_id = params[ 'run_id' ]

        # Update runlist for runner in memcache
        runlist = self.get_runlist_for_runner( user.username, 
                                               no_refresh=True )
        if runlist is not None:
            runlist.insert( 0, dict( run_id = run_id,
                                     game = game, 
                                     game_code = game_code,
                                     category = category, 
                                     time = time,
                                     date = date, 
                                     datetime_created = datetime_created,
                                     video = video,
                                     version = version,
                                     notes = notes ) )
            runlist.sort( key=lambda x: util.get_valid_date( x['date'] ),
                          reverse=True )
            self.update_cache_runlist_for_runner( user.username, runlist )
예제 #3
0
    def update_runlist_for_runner_put(self, params):
        user = params['user']
        game = params['game']
        game_code = params['game_code']
        category = params['category']
        time = params['time']
        video = params['video']
        version = params['version']
        notes = params['notes']
        date = params['date']
        datetime_created = params['datetime_created']
        run_id = params['run_id']

        # Update runlist for runner in memcache
        runlist = self.get_runlist_for_runner(user.username, no_refresh=True)
        if runlist == self.OVER_QUOTA_ERROR:
            self.update_cache_runlist_for_runner(user.username, None)
        elif runlist is not None:
            runlist.insert(
                0,
                dict(run_id=run_id,
                     game=game,
                     game_code=game_code,
                     category=category,
                     category_code=util.get_code(category),
                     time=time,
                     date=date,
                     datetime_created=datetime_created,
                     video=video,
                     version=version,
                     notes=notes))
            runlist.sort(key=lambda x: util.get_valid_date(x['date']),
                         reverse=True)
            self.update_cache_runlist_for_runner(user.username, runlist)
예제 #4
0
    def update_runlist_for_runner_put(self, params):
        user = params["user"]
        game = params["game"]
        game_code = params["game_code"]
        category = params["category"]
        time = params["time"]
        video = params["video"]
        version = params["version"]
        notes = params["notes"]
        date = params["date"]
        datetime_created = params["datetime_created"]
        run_id = params["run_id"]

        # Update runlist for runner in memcache
        cached_runlists = self.get_cached_runlists_for_runner(user.username)
        if cached_runlists is not None:
            res = cached_runlists.get(1)
            if res is not None:
                res["runlist"].insert(
                    0,
                    dict(
                        run_id=run_id,
                        game=game,
                        game_code=game_code,
                        category=category,
                        category_code=util.get_code(category),
                        time=time,
                        date=date,
                        datetime_created=datetime_created,
                        video=video,
                        version=version,
                        notes=notes,
                    ),
                )
                res["runlist"].sort(key=lambda x: util.get_valid_date(x["date"]), reverse=True)
                self.update_cache_runlist_for_runner(user.username, cached_runlists)
예제 #5
0
    def put_existing_run( self, params ):
        user = params[ 'user' ]
        game = params[ 'game' ]
        game_code = params[ 'game_code' ]
        category = params[ 'category' ]
        seconds = params[ 'seconds' ]
        time = params[ 'time' ]
        video = params[ 'video' ]
        version = params[ 'version' ]
        notes = params[ 'notes' ]
        valid = params[ 'valid' ]
        run_id = params[ 'run_id' ]

        # Grab the old run, which we will update to be the new run
        new_run = self.get_run_by_id( run_id )
        if ( new_run is None 
             or ( not user.is_mod and new_run.username != user.username ) ):
            return False

        # Get the owner of this run
        if new_run.username != user.username:
            runner = self.get_runner( util.get_code( new_run.username ) )
            params['user'] = runner
        else:
            runner = user

        # Store the contents of the old run
        old_run = dict( game = new_run.game,
                        category = new_run.category,
                        seconds = new_run.seconds )

        # Update the run
        try:
            new_run.game = game
            new_run.category = category
            new_run.seconds = seconds
            new_run.date = params['date']
            new_run.version = version
            new_run.notes = notes
        except db.BadValueError:
            valid = False
        if video:
            try:
                new_run.video = video
            except db.BadValueError:
                params['video_error'] = "Invalid video URL"
                valid = False
        elif new_run.video:
            new_run.video = None
            
        if not valid:
            return False
            
        new_run.put( )
        logging.debug( "Put updated run for runner " + runner.username
                       + ", game = " + game + ", category = " + category
                       + ", time= " + time + ", run_id = " + run_id )

        # Figure out the change in num_pbs for the old and new game, as well
        # as the runner
        delta_num_pbs_old = 0
        delta_num_pbs_new = 0
        if game != old_run['game'] or category != old_run['category']:
            num_runs = self.num_runs( runner.username, old_run[ 'game' ], 
                                      old_run[ 'category' ], 1 )
            if num_runs == 0:
                delta_num_pbs_old = -1
            num_runs = self.num_runs( runner.username, game, category, 2 )
            if num_runs == 1:
                delta_num_pbs_new = 1
            
        # Update games.Games and runners.Runners
        self.update_runner( runner, delta_num_pbs_old + delta_num_pbs_new )
        if game == old_run['game']:
            self.update_games_delete( params['game_model'], delta_num_pbs_old )
        else:
            self.update_games_delete( self.get_game_model( util.get_code( 
                        old_run['game'] ) ), delta_num_pbs_old )
        self.update_games_put( params, delta_num_pbs_new )

        # Update memcache with the removal of the old run and addition of the
        # new run.
        self.update_cache_run_by_id( run_id, new_run )
        # Must update runinfo before pblist and gamepage as in put_new_run()
        self.update_runinfo_delete( runner, old_run )
        self.update_runinfo_put( params )
        self.update_pblist_delete( runner, old_run )
        self.update_pblist_put( params )
        self.update_gamepage_delete( runner, old_run )
        self.update_gamepage_put( params )
        self.update_user_has_run_delete( runner, old_run )
        self.update_cache_user_has_run( runner.username, game, True )

        # Update gamelist and runnerlist in memcache
        if delta_num_pbs_old == -1:
            self.update_gamelist_delete( old_run )
            self.update_runnerlist_delete( runner )
        if delta_num_pbs_new == 1:
            self.update_gamelist_put( params )
            self.update_runnerlist_put( params )

        # Replace the old run in the runlist for runner in memcache
        runlist = self.get_runlist_for_runner( runner.username, 
                                               no_refresh=True )
        if runlist:
            for run in runlist:
                if run[ 'run_id' ] == run_id:
                    run[ 'game' ] = game
                    run[ 'game_code' ] = game_code
                    run[ 'category' ] = category
                    run[ 'time' ] = time
                    run[ 'date' ] = new_run.date
                    run[ 'video' ] = video
                    run[ 'version' ] = version
                    run[ 'notes' ] = notes
                    runlist.sort( key=lambda x: util.get_valid_date( 
                        x['date'] ), reverse=True )
                    self.update_cache_runlist_for_runner( runner.username, 
                                                          runlist )
                    break

        # Check to see if we need to replace the last run for this user
        last_run = self.get_last_run( runner.username, no_refresh=True )
        if( last_run is not None 
            and new_run.key().id() == last_run.key().id() ):
            self.update_cache_last_run( runner.username, new_run )

        return True
예제 #6
0
    def update_gamepage_put( self, params ):
        user = params[ 'user' ]
        game = params[ 'game' ]
        category = params[ 'category' ]
        seconds = params[ 'seconds' ]
        time = params[ 'time' ]
        date = params[ 'date' ]
        video = params[ 'video' ]
        is_bkt = params[ 'is_bkt' ]

        # Update gamepage in memcache
        gamepage = self.get_gamepage( game, no_refresh=True )
        if gamepage is None:
            return

        for d in gamepage:
            if d[ 'category' ] == category:
                if is_bkt:
                    # Update best known time for this category
                    d['bk_runner'] = user.username
                    d['bk_time'] = util.seconds_to_timestr( seconds )
                    d['bk_date'] = date
                    d['bk_video'] = video
                for i, runinfo in enumerate( d['infolist'] ):
                    if runinfo['username'] == user.username:
                        # User has run this category before
                        d['infolist'][i] = self.get_runinfo( user.username, 
                                                             game, category )
                        d['infolist'].sort( key=lambda x: util.get_valid_date(
                                x['pb_date'] ) )
                        d['infolist'].sort( key=itemgetter('pb_seconds') )
                        self.update_cache_gamepage( game, gamepage )
                        return
                
                # Category found, but user has not prev. run this category
                runinfo = self.get_runinfo( user.username, game, category )
                d['infolist'].append( runinfo )
                d['infolist'].sort( key=lambda x: util.get_valid_date(
                        x['pb_date'] ) )                
                d['infolist'].sort( key=itemgetter('pb_seconds') )
                gamepage.sort( key=lambda x: len(x['infolist']), reverse=True )
                self.update_cache_gamepage( game, gamepage )
                return
        
        # This is a new category for this game
        runinfo = self.get_runinfo( user.username, game, category )
        d = dict( category=category, 
                  category_code=util.get_code( category ),
                  infolist=[runinfo] )
        # Check for best known time. Since we update games.Games before 
        # updating gamepage, this will catch the case for when is_bkt is true.
        game_model = self.get_game_model( util.get_code( game ) )
        if game_model is None:
            logging.error( "Failed to update gamepage for " + game )
            self.update_cache_gamepage( game, None )
            return
        gameinfolist = json.loads( game_model.info )
        for gameinfo in gameinfolist:
            if gameinfo['category'] == category:
                d['bk_runner'] = gameinfo.get( 'bk_runner' )
                d['bk_time'] = util.seconds_to_timestr( 
                        gameinfo.get( 'bk_seconds' ) )
                d['bk_date'] = util.datestr_to_date( 
                    gameinfo.get( 'bk_datestr' ) )[ 0 ]
                d['bk_video'] = gameinfo.get( 'bk_video' )
                break
        gamepage.append( d )
        self.update_cache_gamepage( game, gamepage )
예제 #7
0
    def get_gamepage(self, game, no_refresh=False):
        key = self.get_gamepage_memkey(game)
        gamepage = memcache.get(key)
        if gamepage is None and not no_refresh:
            # Not in memcache, so construct the gamepage and store it in
            # memcache.
            # Gamepage is a list of dictionaries. These dictionaries have up
            # to 5 keys, 'category', 'bk_runner', 'bk_time', 'bk_video' and
            # 'infolist'.
            gamepage = []

            # Grab the game model
            game_model = self.get_game_model(util.get_code(game))
            if game_model is None:
                logging.error("Could not create " + key + " due to no " +
                              "game model")
                return None
            if game_model == self.OVER_QUOTA_ERROR:
                return self.OVER_QUOTA_ERROR
            gameinfolist = json.loads(game_model.info)

            try:
                # Use a projection query to get all of the unique
                # username, category pairs
                q = db.Query(runs.Runs,
                             projection=('username', 'category'),
                             distinct=True)
                q.ancestor(runs.key())
                q.filter('game =', game)
                q.order('category')
                cur_category = None
                for run in q.run(limit=1000):
                    if run.category != cur_category:
                        # New category
                        d = dict(category=run.category,
                                 category_code=util.get_code(run.category),
                                 infolist=[])
                        gamepage.append(d)
                        cur_category = run.category
                        # Check for a best known time for this category
                        for gameinfo in gameinfolist:
                            if gameinfo['category'] == run.category:
                                d['bk_runner'] = gameinfo.get('bk_runner')
                                d['bk_time'] = util.seconds_to_timestr(
                                    gameinfo.get('bk_seconds'))
                                d['bk_date'] = util.datestr_to_date(
                                    gameinfo.get('bk_datestr'))[0]
                                d['bk_video'] = gameinfo.get('bk_video')
                                break

                    # Add the info to the gamepage
                    info = self.get_runinfo(run.username, game, run.category)
                    if info == self.OVER_QUOTA_ERROR:
                        return self.OVER_QUOTA_ERROR
                    d['infolist'].append(info)
            except apiproxy_errors.OverQuotaError, msg:
                logging.error(msg)
                return self.OVER_QUOTA_ERROR

            # For each category, sort the runlist by seconds, breaking ties
            # by date
            for runlist in gamepage:
                runlist['infolist'].sort(
                    key=lambda x: util.get_valid_date(x['pb_date']))
                runlist['infolist'].sort(key=itemgetter('pb_seconds'))

            # Sort the categories by number of runners
            gamepage.sort(key=lambda x: len(x['infolist']), reverse=True)

            if memcache.set(key, gamepage):
                logging.debug("Set " + key + " in memcache")
            else:
                logging.warning("Failed to set " + key + " in memcache")
예제 #8
0
    def put_existing_run(self, params):
        user = params['user']
        game = params['game']
        game_code = params['game_code']
        category = params['category']
        seconds = params['seconds']
        time = params['time']
        video = params['video']
        version = params['version']
        notes = params['notes']
        valid = params['valid']
        run_id = params['run_id']

        # Grab the old run, which we will update to be the new run
        new_run = self.get_run_by_id(run_id)
        if new_run == self.OVER_QUOTA_ERROR:
            return False
        if (new_run is None
                or (not user.is_mod and new_run.username != user.username)):
            return False

        # Get the owner of this run
        if new_run.username != user.username:
            runner = self.get_runner(util.get_code(new_run.username))
            if runner == self.OVER_QUOTA_ERROR:
                return False
            params['user'] = runner
        else:
            runner = user

        # Store the contents of the old run
        old_run = dict(game=new_run.game,
                       category=new_run.category,
                       seconds=new_run.seconds)
        old_game_model = self.get_game_model(util.get_code(old_run['game']))
        if old_game_model == self.OVER_QUOTA_ERROR:
            return False

        # Update the run
        try:
            new_run.game = game
            new_run.category = category
            new_run.seconds = seconds
            new_run.date = params['date']
            new_run.version = version
            new_run.notes = notes
        except db.BadValueError:
            valid = False
        if video:
            try:
                new_run.video = video
            except db.BadValueError:
                params['video_error'] = "Invalid video URL"
                valid = False
        elif new_run.video:
            new_run.video = None

        if not valid:
            return False

        new_run.put()
        logging.debug("Put updated run for runner " + runner.username +
                      ", game = " + game + ", category = " + category +
                      ", time= " + time + ", run_id = " + run_id)

        # Figure out the change in num_pbs for the old and new game, as well
        # as the runner
        delta_num_pbs_old = 0
        delta_num_pbs_new = 0
        if game != old_run['game'] or category != old_run['category']:
            num_runs = self.num_runs(runner.username, old_run['game'],
                                     old_run['category'], 1)
            if num_runs == 0:
                delta_num_pbs_old = -1
            num_runs = self.num_runs(runner.username, game, category, 2)
            if num_runs == 1:
                delta_num_pbs_new = 1

        # Update games.Games and runners.Runners
        self.update_runner(runner, delta_num_pbs_old + delta_num_pbs_new)
        if game == old_run['game']:
            self.update_games_delete(params['game_model'], delta_num_pbs_old)
        else:
            self.update_games_delete(old_game_model, delta_num_pbs_old)
        self.update_games_put(params, delta_num_pbs_new)

        # Update memcache with the removal of the old run and addition of the
        # new run.
        self.update_cache_run_by_id(run_id, new_run)
        # Must update runinfo before pblist and gamepage as in put_new_run()
        self.update_runinfo_delete(runner, old_run)
        self.update_runinfo_put(params)
        self.update_pblist_delete(runner, old_run)
        self.update_pblist_put(params)
        self.update_gamepage_delete(runner, old_run)
        self.update_gamepage_put(params)
        self.update_user_has_run_delete(runner, old_run)
        self.update_cache_user_has_run(runner.username, game, True)

        # Update gamelist and runnerlist in memcache
        if delta_num_pbs_old == -1:
            self.update_gamelist_delete(old_run)
            self.update_runnerlist_delete(runner)
        if delta_num_pbs_new == 1:
            self.update_gamelist_put(params)
            self.update_runnerlist_put(params)

        # Replace the old run in the runlist for runner in memcache
        runlist = self.get_runlist_for_runner(runner.username, no_refresh=True)
        if runlist == self.OVER_QUOTA_ERROR:
            self.update_cache_runlist_for_runner(runner.username, None)
        elif runlist is not None:
            for run in runlist:
                if run['run_id'] == run_id:
                    run['game'] = game
                    run['game_code'] = game_code
                    run['category'] = category
                    run['category_code'] = util.get_code(category)
                    run['time'] = time
                    run['date'] = new_run.date
                    run['video'] = video
                    run['version'] = version
                    run['notes'] = notes
                    runlist.sort(key=lambda x: util.get_valid_date(x['date']),
                                 reverse=True)
                    self.update_cache_runlist_for_runner(
                        runner.username, runlist)
                    break

        # Check to see if we need to replace the last run for this user
        last_run = self.get_last_run(runner.username, no_refresh=True)
        if last_run == self.OVER_QUOTA_ERROR:
            self.update_cache_last_run(runner.username, None)
        elif (last_run is not None
              and new_run.key().id() == last_run.key().id()):
            self.update_cache_last_run(runner.username, new_run)

        return True
예제 #9
0
    def update_gamepage_put(self, params):
        user = params['user']
        game = params['game']
        category = params['category']
        seconds = params['seconds']
        time = params['time']
        date = params['date']
        video = params['video']
        is_bkt = params['is_bkt']

        # Update gamepage in memcache
        gamepage = self.get_gamepage(game, no_refresh=True)
        if gamepage is None:
            return
        if gamepage == self.OVER_QUOTA_ERROR:
            self.update_cache_gamepage(game, None)
            return

        for d in gamepage:
            if d['category'] == category:
                if is_bkt:
                    # Update best known time for this category
                    d['bk_runner'] = user.username
                    d['bk_time'] = util.seconds_to_timestr(seconds)
                    d['bk_date'] = date
                    d['bk_video'] = video
                for i, runinfo in enumerate(d['infolist']):
                    if runinfo['username'] == user.username:
                        # User has run this category before
                        d['infolist'][i] = self.get_runinfo(
                            user.username, game, category)
                        if d['infolist'][i] == self.OVER_QUOTA_ERROR:
                            gamepage = None
                        else:
                            d['infolist'].sort(key=lambda x: util.
                                               get_valid_date(x['pb_date']))
                            d['infolist'].sort(key=itemgetter('pb_seconds'))
                        self.update_cache_gamepage(game, gamepage)
                        return

                # Category found, but user has not prev. run this category
                runinfo = self.get_runinfo(user.username, game, category)
                if runinfo == self.OVER_QUOTA_ERROR:
                    gamepage = None
                else:
                    d['infolist'].append(runinfo)
                    d['infolist'].sort(
                        key=lambda x: util.get_valid_date(x['pb_date']))
                    d['infolist'].sort(key=itemgetter('pb_seconds'))
                    gamepage.sort(key=lambda x: len(x['infolist']),
                                  reverse=True)
                self.update_cache_gamepage(game, gamepage)
                return

        # This is a new category for this game
        runinfo = self.get_runinfo(user.username, game, category)
        if runinfo == self.OVER_QUOTA_ERROR:
            self.update_cache_gamepage(game, gamepage)
            return
        d = dict(category=category,
                 category_code=util.get_code(category),
                 infolist=[runinfo])
        # Check for best known time. Since we update games.Games before
        # updating gamepage, this will catch the case for when is_bkt is true.
        game_model = self.get_game_model(util.get_code(game))
        if game_model is None:
            logging.error("Failed to update gamepage for " + game)
            self.update_cache_gamepage(game, None)
            return
        if game_model == self.OVER_QUOTA_ERROR:
            self.update_cache_gamepage(game, None)
            return
        gameinfolist = json.loads(game_model.info)
        for gameinfo in gameinfolist:
            if gameinfo['category'] == category:
                d['bk_runner'] = gameinfo.get('bk_runner')
                d['bk_time'] = util.seconds_to_timestr(
                    gameinfo.get('bk_seconds'))
                d['bk_date'] = util.datestr_to_date(
                    gameinfo.get('bk_datestr'))[0]
                d['bk_video'] = gameinfo.get('bk_video')
                break
        gamepage.append(d)
        self.update_cache_gamepage(game, gamepage)
예제 #10
0
    def put_existing_run(self, params):
        user = params["user"]
        game = params["game"]
        game_code = params["game_code"]
        category = params["category"]
        seconds = params["seconds"]
        time = params["time"]
        video = params["video"]
        version = params["version"]
        notes = params["notes"]
        valid = params["valid"]
        run_id = params["run_id"]

        # Grab the old run, which we will update to be the new run
        new_run = self.get_run_by_id(run_id)
        if new_run == self.OVER_QUOTA_ERROR:
            return False
        if new_run is None or (not user.is_mod and new_run.username != user.username):
            return False

        # Get the owner of this run
        if new_run.username != user.username:
            runner = self.get_runner(util.get_code(new_run.username))
            if runner == self.OVER_QUOTA_ERROR:
                return False
            params["user"] = runner
        else:
            runner = user

        # Store the contents of the old run
        old_run = dict(game=new_run.game, category=new_run.category, seconds=new_run.seconds)
        old_game_model = self.get_game_model(util.get_code(old_run["game"]))
        if old_game_model == self.OVER_QUOTA_ERROR:
            return False

        # Update the run
        try:
            new_run.game = game
            new_run.category = category
            new_run.seconds = seconds
            new_run.date = params["date"]
            new_run.version = version
            new_run.notes = notes
        except db.BadValueError:
            valid = False
        if video:
            try:
                new_run.video = video
            except db.BadValueError:
                params["video_error"] = "Invalid video URL"
                valid = False
        elif new_run.video:
            new_run.video = None

        if not valid:
            return False

        new_run.put()
        logging.debug(
            "Put updated run for runner "
            + runner.username
            + ", game = "
            + game
            + ", category = "
            + category
            + ", time= "
            + time
            + ", run_id = "
            + run_id
        )

        # Figure out the change in num_pbs for the old and new game, as well
        # as the runner
        delta_num_pbs_old = 0
        delta_num_pbs_new = 0
        if game != old_run["game"] or category != old_run["category"]:
            num_runs = self.num_runs(runner.username, old_run["game"], old_run["category"], 1)
            if num_runs == 0:
                delta_num_pbs_old = -1
            num_runs = self.num_runs(runner.username, game, category, 2)
            if num_runs == 1:
                delta_num_pbs_new = 1

        # Update games.Games and runners.Runners
        self.update_runner(runner, delta_num_pbs_old + delta_num_pbs_new)
        if game == old_run["game"]:
            self.update_games_delete(params["game_model"], old_run["category"], delta_num_pbs_old)
        else:
            self.update_games_delete(old_game_model, old_run["category"], delta_num_pbs_old)
        self.update_games_put(params, delta_num_pbs_new)

        # Update memcache with the removal of the old run and addition of the
        # new run.
        self.update_cache_run_by_id(run_id, new_run)
        self.update_pblist_delete(runner, old_run)
        self.update_pblist_put(params)
        self.update_gamepage_delete(runner, old_run)
        self.update_gamepage_put(params)
        self.update_user_has_run_delete(runner, old_run)
        self.update_cache_user_has_run(runner.username, game, True)

        # Update gamelist and runnerlist in memcache
        if delta_num_pbs_old == -1:
            self.update_gamelist_delete(old_run)
            self.update_runnerlist_delete(runner)
        if delta_num_pbs_new == 1:
            self.update_gamelist_put(params)
            self.update_runnerlist_put(params)

        # Replace the old run in the runlist for runner in memcache
        cached_runlists = self.get_cached_runlists_for_runner(runner.username)
        if cached_runlists is not None:
            found_run = False
            for page_num, res in cached_runlists.iteritems():
                if found_run:
                    break
                for run in res["runlist"]:
                    if run["run_id"] == run_id:
                        run["game"] = game
                        run["game_code"] = game_code
                        run["category"] = category
                        run["category_code"] = util.get_code(category)
                        run["time"] = time
                        run["date"] = new_run.date
                        run["video"] = video
                        run["version"] = version
                        run["notes"] = notes
                        res["runlist"].sort(key=lambda x: util.get_valid_date(x["date"]), reverse=True)
                        self.update_cache_runlist_for_runner(runner.username, cached_runlists)
                        found_run = True
                        break

        # Check to see if we need to replace the last run for this user
        last_run = self.get_last_run(runner.username, no_refresh=True)
        if last_run == self.OVER_QUOTA_ERROR:
            self.update_cache_last_run(runner.username, None)
        elif last_run is not None and new_run.key().id() == last_run.key().id():
            self.update_cache_last_run(runner.username, new_run)

        return True