Ejemplo n.º 1
0
    def get_runlist_for_runner( self, username, page_num ):
        key = self.get_runlist_for_runner_memkey( username )
        cached_runlists = memcache.get( key )
        if cached_runlists is None:
            cached_runlists = dict( )
        res = cached_runlists.get( page_num )
        if res is None:
            # Not in memcache, so construct the runlist and store in memcache.
            res = dict( page_num=page_num,
                        has_next=True )
            runlist = [ ]
            try:
                q = runs.Runs.all( )
                q.ancestor( runs.key() )
                q.filter( 'username ='******'-date' )
                q.order( '-datetime_created' )
                c = memcache.get( self.get_runlist_for_runner_cursor_memkey(
                    username, page_num ) )
                if c:
                    try:
                        q.with_cursor( start_cursor=c )
                    except BadRequestError:
                        res['page_num'] = 1
                else:
                    res['page_num'] = 1
                for run in q.run( limit = self.RUNLIST_PAGE_LIMIT ):
                    runlist.append( dict(
                        run_id = str( run.key().id() ),
                        game = run.game,
                        game_code = util.get_code( run.game ),
                        category = run.category,
                        category_code = util.get_code( run.category ),
                        time = util.
                        seconds_to_timestr( run.seconds ),
                        date = run.date,
                        datetime_created = run.datetime_created,
                        video = run.video,
                        version = run.version,
                        notes = run.notes ) )
                c = q.cursor( )
                cursor_key = self.get_runlist_for_runner_cursor_memkey(
                    username, res['page_num'] + 1 )
                if memcache.set( cursor_key, c ):
                    logging.debug( "Set " + cursor_key + " in memcache" )
                else:
                    logging.warning( "Failed to set new " + cursor_key
                                     + " in memcache" )
                if len( runlist ) < self.RUNLIST_PAGE_LIMIT:
                    res['has_next'] = False
            except apiproxy_errors.OverQuotaError, msg:
                logging.error( msg )
                return self.OVER_QUOTA_ERROR

            res['runlist'] = runlist
            cached_runlists[ res['page_num'] ] = res
            if memcache.set( key, cached_runlists ):
                logging.debug( "Set " + key + " in memcache" )
            else:
                logging.warning( "Failed to set " + key + " in memcache" )
Ejemplo n.º 2
0
    def get_runlist_for_runner(self, username, no_refresh=False):
        key = self.get_runlist_for_runner_memkey(username)
        runlist = memcache.get(key)
        if runlist is None and not no_refresh:
            # Not in memcache, so construct the runlist and store in memcache.
            runlist = []
            q = runs.Runs.all()
            q.ancestor(runs.key())
            q.filter("username ="******"-date")
            q.order("-datetime_created")
            for run in q.run(limit=1000):
                runlist.append(
                    dict(
                        run_id=str(run.key().id()),
                        game=run.game,
                        game_code=util.get_code(run.game),
                        category=run.category,
                        time=util.seconds_to_timestr(run.seconds),
                        date=run.date,
                        datetime_created=run.datetime_created,
                        video=run.video,
                        version=run.version,
                        notes=run.notes,
                    )
                )

            if memcache.set(key, runlist):
                logging.debug("Set " + key + " in memcache")
            else:
                logging.warning("Failed to set " + key + " in memcache")
        elif runlist is not None:
            logging.debug("Got " + key + " from memcache")
        return runlist
Ejemplo n.º 3
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
Ejemplo n.º 4
0
    def get(self):
        # Make sure it's me
        user = self.get_user()
        if not user:
            self.error(404)
            self.render("404.html", user=user)
            return
        elif user == self.OVER_QUOTA_ERROR:
            self.error(403)
            self.render("403.html")
            return
        elif user.username != "rggibson":
            self.error(404)
            self.render("404.html", user=user)
            return

        # Convert seconds to float
        count = 0
        try:
            q = db.Query(runs.Runs)
            q.ancestor(runs.key())
            for run in q.run(limit=1000000):
                count += 1
                if not isinstance(run.seconds, float):
                    run.seconds = float(run.seconds)
                    run.put()
        except apiproxy_errors.OverQuotaError, message:
            logging.error(message)
            self.write("Over quota error caught after " + str(count) +
                       "runs:<br>" + message)
            return
Ejemplo n.º 5
0
    def get_runlist_for_runner(self, username, no_refresh=False):
        key = self.get_runlist_for_runner_memkey(username)
        runlist = memcache.get(key)
        if runlist is None and not no_refresh:
            # Not in memcache, so construct the runlist and store in memcache.
            runlist = []
            try:
                q = runs.Runs.all()
                q.ancestor(runs.key())
                q.filter('username ='******'-date')
                q.order('-datetime_created')
                for run in q.run(limit=1000):
                    runlist.append(
                        dict(run_id=str(run.key().id()),
                             game=run.game,
                             game_code=util.get_code(run.game),
                             category=run.category,
                             category_code=util.get_code(run.category),
                             time=util.seconds_to_timestr(run.seconds),
                             date=run.date,
                             datetime_created=run.datetime_created,
                             video=run.video,
                             version=run.version,
                             notes=run.notes))
            except apiproxy_errors.OverQuotaError, msg:
                logging.error(msg)
                return self.OVER_QUOTA_ERROR

            if memcache.set(key, runlist):
                logging.debug("Set " + key + " in memcache")
            else:
                logging.warning("Failed to set " + key + " in memcache")
Ejemplo n.º 6
0
 def num_runs( self, username, game, category, limit ):
     q = db.Query( runs.Runs, keys_only=True )
     q.ancestor( runs.key() )
     q.filter( 'username ='******'game =', game )
     q.filter( 'category =', category )
     return q.count( limit=limit )
Ejemplo n.º 7
0
    def get_runlist_for_runner( self, username, no_refresh=False ):
        key = self.get_runlist_for_runner_memkey( username )
        runlist = memcache.get( key )
        if runlist is None and not no_refresh:
            # Not in memcache, so construct the runlist and store in memcache.
            runlist = [ ]
            try:
                q = runs.Runs.all( )
                q.ancestor( runs.key() )
                q.filter( 'username ='******'-date' )
                q.order( '-datetime_created' )
                for run in q.run( limit = 1000 ):
                    runlist.append( dict( run_id = str( run.key().id() ),
                                          game = run.game,
                                          game_code = util.get_code( run.game ),
                                          category = run.category,
                                          category_code = util.get_code( 
                                              run.category ),
                                          time = util.
                                          seconds_to_timestr( run.seconds ),
                                          date = run.date,
                                          datetime_created = run.datetime_created,
                                          video = run.video,
                                          version = run.version,
                                          notes = run.notes ) )
            except apiproxy_errors.OverQuotaError, msg:
                logging.error( msg )
                return self.OVER_QUOTA_ERROR

            if memcache.set( key, runlist ):
                logging.debug( "Set " + key + " in memcache" )
            else:
                logging.warning( "Failed to set " + key + " in memcache" )
Ejemplo n.º 8
0
    def cleanup_games(self):
        # Grab all of the categories, indexed by game
        categories = self.get_categories()
        if categories == self.OVER_QUOTA_ERROR:
            return
        categories_modified = False

        games_to_delete = []
        for game, categorylist in categories.iteritems():
            # Grab the game model
            game_code = util.get_code(game)
            game_model = self.get_game_model(game_code)
            if game_model == self.OVER_QUOTA_ERROR:
                return
            gameinfolist = json.loads(game_model.info)
            game_model_modified = False
            glist = [(i, gameinfo) for i, gameinfo in enumerate(gameinfolist)]
            for i, gameinfo in reversed(glist):
                # Leave it if the category is marked as a base category
                if (gameinfo.get('is_base_category')
                        and game != "Luigi's Mansion"
                        and game != "Super Mario Bros.: The Lost Levels"
                        and game != "The Legend of Zelda: A Link to the Past"
                        and game != "Mega Man 9"):
                    continue
                # Check if there is a run for this game and category
                try:
                    q = db.Query(runs.Runs, keys_only=True)
                    q.ancestor(runs.key())
                    q.filter('game =', game)
                    q.filter('category =', gameinfo['category'])
                    num_runs = q.count(limit=1)
                    if num_runs == 0:
                        # Remove this category
                        del gameinfolist[i]
                        logging.info("Removed " + gameinfo['category'] +
                                     " from " + game)
                        game_model_modified = True
                        # Remove this category in memcache too
                        for j, category in enumerate(categorylist):
                            if category == gameinfo['category']:
                                del categorylist[j]
                                categories_modified = True
                                break
                        else:
                            logging.error("ERROR: Could not find in " +
                                          "categories")
                except apiproxy_errors.OverQuotaError, msg:
                    logging.error(msg)
            # Remove the game if no more categories exist
            if len(gameinfolist) == 0:
                game_model.delete()
                games_to_delete.append(game)
                logging.info(game + " deleted")
                self.update_cache_game_model(game_code, None)
            # Update database and memcache if necessary
            elif game_model_modified:
                game_model.info = json.dumps(gameinfolist)
                game_model.put()
                self.update_cache_game_model(game_code, game_model)
Ejemplo n.º 9
0
    def cleanup_games(self):
        # Grab all of the categories, indexed by game
        categories = self.get_categories()
        categories_modified = False

        games_to_delete = []
        for game, categorylist in categories.iteritems():
            # Grab the game model
            game_code = util.get_code(game)
            game_model = self.get_game_model(game_code)
            gameinfolist = json.loads(game_model.info)
            game_model_modified = False
            glist = [(i, gameinfo) for i, gameinfo in enumerate(gameinfolist)]
            for i, gameinfo in reversed(glist):
                # Leave it if the category is marked as a base category
                if (
                    gameinfo.get("is_base_category")
                    and game != "Luigi's Mansion"
                    and game != "Super Mario Bros.: The Lost Levels"
                    and game != "The Legend of Zelda: A Link to the Past"
                ):
                    continue
                # Check if there is a run for this game and category
                q = db.Query(runs.Runs, keys_only=True)
                q.ancestor(runs.key())
                q.filter("game =", game)
                q.filter("category =", gameinfo["category"])
                num_runs = q.count(limit=1)
                if num_runs == 0:
                    # Remove this category
                    del gameinfolist[i]
                    logging.info("Removed " + gameinfo["category"] + " from " + game)
                    game_model_modified = True
                    # Remove this category in memcache too
                    for j, category in enumerate(categorylist):
                        if category == gameinfo["category"]:
                            del categorylist[j]
                            categories_modified = True
                            break
                    else:
                        logging.error("ERROR: Could not find in categories")
            # Remove the game if no more categories exist
            if len(gameinfolist) == 0:
                game_model.delete()
                games_to_delete.append(game)
                logging.info(game + " deleted")
                self.update_cache_game_model(game_code, None)
            # Update database and memcache if necessary
            elif game_model_modified:
                game_model.info = json.dumps(gameinfolist)
                game_model.put()
                self.update_cache_game_model(game_code, game_model)

        # Finally, update categories in memcache if necessary
        if categories_modified:
            for game in games_to_delete:
                del categories[game]
            self.update_cache_categories(categories)
Ejemplo n.º 10
0
    def update_runinfo_delete( self, user, old_run ):
        # Update avg, num runs
        runinfo = self.get_runinfo( user.username, old_run['game'],
                                    old_run['category'], no_refresh=True )
        if runinfo is None:
            return
        if runinfo == self.OVER_QUOTA_ERROR:
            self.update_cache_runinfo( user.username, game, category, None )
            return

        if runinfo['num_runs'] <= 0:
            logging.error( "Failed to update runinfo due to nonpositive "
                           + "num_runs " + str( runinfo['num_runs'] ) )
            self.update_cache_runinfo( user.username, old_run['game'],
                                       old_run['category'], None )
            return

        if( runinfo['num_runs'] > 1 ):
            runinfo['avg_seconds'] -= ( 1.0 * old_run['seconds'] 
                                        / runinfo['num_runs'] )
            runinfo['num_runs'] -= 1
            runinfo['avg_seconds'] *= ( 1.0 * ( runinfo['num_runs'] + 1 ) 
                                        / runinfo['num_runs'] )
            runinfo['avg_time'] = util.seconds_to_timestr( 
                runinfo['avg_seconds'] )
            if( runinfo['pb_seconds'] == old_run['seconds'] ):
                # We need to replace the pb too
                try:
                    q = db.Query( runs.Runs, projection=('seconds', 'date', 
                                                         'video', 'version') )
                    q.ancestor( runs.key() )
                    q.filter( 'username ='******'game =', old_run['game'] )
                    q.filter( 'category =', old_run['category'] )
                    q.order( 'seconds' )
                    q.order( 'date' )
                    pb_run = q.get( )
                    if pb_run:
                        runinfo['pb_seconds'] = pb_run.seconds
                        runinfo['pb_time'] = util.seconds_to_timestr( 
                            pb_run.seconds )
                        runinfo['pb_date'] = pb_run.date
                        runinfo['video'] = pb_run.video
                        runinfo['version'] = pb_run.version
                    else:
                        logging.error( "Unable to update runinfo due to no "
                                       + "new pb found" )
                        self.update_cache_runinfo( user.username,
                                                   old_run['game'],
                                                   old_run['category'], None )
                        return
                except apiproxy_errors.OverQuotaError, msg:
                    logging.error( msg )
                    self.update_cache_runinfo( user.username, old_run['game'],
                                               old_run['category'], None )
                    return
            self.update_cache_runinfo( user.username, old_run['game'],
                                       old_run['category'], runinfo )
Ejemplo n.º 11
0
    def get( self ):
        # Grab all of the categories, indexed by game
        categories = self.get_categories( )
        categories_modified = False

        games_to_delete = [ ]
        for game, categorylist in categories.iteritems( ):
            # Grab the game model
            game_code = util.get_code( game )
            game_model = self.get_game_model( game_code )
            gameinfolist = json.loads( game_model.info )
            game_model_modified = False
            glist = [ ( i, gameinfo ) 
                      for i, gameinfo in enumerate( gameinfolist ) ]
            for i, gameinfo in reversed( glist ):
                # Leave it if the category is marked as a base category
                if gameinfo.get( 'is_base_category' ):
                    continue
                # Check if there is a run for this game and category
                q = db.Query( runs.Runs, keys_only=True )
                q.ancestor( runs.key() )
                q.filter( 'game =', game )
                q.filter( 'category =', gameinfo['category'] )
                num_runs = q.count( limit=1 )
                if num_runs == 0:
                    # Remove this category
                    del gameinfolist[ i ]
                    logging.debug( "Removed " + gameinfo['category'] 
                                   + " from " + game )
                    game_model_modified = True
                    # Remove this category in memcache too
                    for j, category in enumerate( categorylist ):
                        if category == gameinfo['category']:
                            del categorylist[ j ]
                            categories_modified = True
                            break
                    else:
                        logging.debug( "ERROR: Could not find in categories" )
            # Remove the game if no more categories exist
            if len( gameinfolist ) == 0:
                game_model.delete( )
                games_to_delete.append( game )
                logging.debug( game + " deleted" )
                self.update_cache_game_model( game_code, None )
            # Update database and memcache if necessary
            elif game_model_modified:
                game_model.info = json.dumps( gameinfolist )
                game_model.put( )
                self.update_cache_game_model( game_code, game_model )
        
        # Finally, update categories in memcache if necessary
        if categories_modified:
            for game in games_to_delete:
                del categories[ game ]
            self.update_cache_categories( categories )
Ejemplo n.º 12
0
 def update_games_delete(self, game_model, category, delta_num_pbs):
     # Check if any runs exist now for this category
     num_category_runs = 1
     try:
         q = db.Query(runs.Runs, keys_only=True)
         q.ancestor(runs.key())
         q.filter("game =", game_model.game)
         q.filter("category =", category)
         num_category_runs = q.count(limit=1)
     except apiproxy_errors.OverQuotaError, msg:
         logging.error(msg)
Ejemplo n.º 13
0
 def num_runs( self, username, game, category, limit ):
     try:
         q = db.Query( runs.Runs, keys_only=True )
         q.ancestor( runs.key() )
         q.filter( 'username ='******'game =', game )
         q.filter( 'category =', category )
         return q.count( limit=limit )
     except apiproxy_errors.OverQuotaError, msg:
         logging.error( msg )
         return 0
Ejemplo n.º 14
0
 def num_runs(self, username, game, category, limit):
     try:
         q = db.Query(runs.Runs, keys_only=True)
         q.ancestor(runs.key())
         q.filter('username ='******'game =', game)
         q.filter('category =', category)
         return q.count(limit=limit)
     except apiproxy_errors.OverQuotaError, msg:
         logging.error(msg)
         return 0
Ejemplo n.º 15
0
    def get_runinfo(self, username, game, category, no_refresh=False):
        key = self.get_runinfo_memkey(username, game, category)
        runinfo = memcache.get(key)
        if runinfo is None and not no_refresh:
            # Not in memcache, so constrcut the runinfo dictionary
            pb_run = None
            avg_seconds = 0
            num_runs = 0
            try:
                q = db.Query(runs.Runs,
                             projection=('seconds', 'date', 'video',
                                         'version'))
                q.ancestor(runs.key())
                q.filter('username ='******'game =', game)
                q.filter('category =', category)
                q.order('-date')  # Cut off old runs
                for run in q.run(limit=100000):
                    num_runs += 1
                    avg_seconds += (1.0 / num_runs) * (run.seconds -
                                                       avg_seconds)
                    if (pb_run is None or run.seconds <= pb_run.seconds):
                        pb_run = run

                runinfo = dict(username=username,
                               username_code=util.get_code(username),
                               category=category,
                               category_code=util.get_code(category),
                               pb_seconds=None,
                               pb_time=None,
                               pb_date=None,
                               num_runs=num_runs,
                               avg_seconds=avg_seconds,
                               avg_time=util.seconds_to_timestr(avg_seconds,
                                                                dec_places=0),
                               video=None)
            except apiproxy_errors.OverQuotaError, msg:
                logging.error(msg)
                return self.OVER_QUOTA_ERROR
            # Set the pb time
            if pb_run:
                runinfo['pb_seconds'] = pb_run.seconds
                runinfo['pb_time'] = util.seconds_to_timestr(pb_run.seconds)
                runinfo['pb_date'] = pb_run.date
                runinfo['video'] = pb_run.video
                runinfo['version'] = pb_run.version

            if memcache.set(key, runinfo):
                logging.debug("Set " + key + " in memcache")
            else:
                logging.warning("Failed to set " + key + " in memcache")
Ejemplo n.º 16
0
    def get_pblist(self, username, no_refresh=False):
        key = self.get_pblist_memkey(username)
        pblist = memcache.get(key)
        if pblist is None and not no_refresh:
            # Not in memcache, so construct the pblist and store in memcache.
            # pblist is a list of dictionaries with 3 indices, 'game',
            # 'game_code' and 'infolist'.  The infolist is another list of
            # dictionaries containing all the info for each pb of the game.
            pblist = []
            try:
                # Use a projection query to get all of the unique game, category
                # pairs
                q = db.Query(runs.Runs,
                             projection=('game', 'category'),
                             distinct=True)
                q.ancestor(runs.key())
                q.filter('username ='******'game')
                q.order('category')
                cur_game = None
                for run in q.run(limit=1000):
                    if run.game != cur_game:
                        # New game
                        pb = dict(game=run.game,
                                  game_code=util.get_code(run.game),
                                  num_runs=0,
                                  infolist=[])
                        pblist.append(pb)
                        cur_game = run.game

                    # Add runinfo to pblist
                    info = self.get_runinfo(username, run.game, run.category)
                    if info == self.OVER_QUOTA_ERROR:
                        return self.OVER_QUOTA_ERROR
                    pb['infolist'].append(info)
                    pb['num_runs'] += info['num_runs']
            except apiproxy_errors.OverQuotaError, msg:
                logging.error(msg)
                return self.OVER_QUOTA_ERROR

            # Sort the categories for a game by num_runs
            for pb in pblist:
                pb['infolist'].sort(key=itemgetter('num_runs'), reverse=True)

            # Sort the games by number of runs
            pblist.sort(key=itemgetter('num_runs'), reverse=True)

            if memcache.set(key, pblist):
                logging.debug("Set " + key + " in memcache")
            else:
                logging.warning("Failed to set " + key + " in memcache")
Ejemplo n.º 17
0
    def get_runinfo( self, username, game, category, no_refresh=False ):
        key = self.get_runinfo_memkey( username, game, category )
        runinfo = memcache.get( key )
        if runinfo is None and not no_refresh:
            # Not in memcache, so constrcut the runinfo dictionary
            pb_run = None
            avg_seconds = 0
            num_runs = 0
            try:
                q = db.Query( runs.Runs, 
                              projection=('seconds', 'date', 'video',
                                          'version') )
                q.ancestor( runs.key() )
                q.filter('username ='******'game =', game)
                q.filter('category =', category)
                q.order('-date') # Cut off old runs
                for run in q.run( limit = 100000 ):
                    num_runs += 1
                    avg_seconds += ( 1.0 / num_runs ) * ( 
                        run.seconds - avg_seconds )
                    if( pb_run is None or run.seconds <= pb_run.seconds ):
                        pb_run = run

                runinfo = dict( username = username,
                                username_code = util.get_code( username ),
                                category = category, 
                                category_code = util.get_code( category ),
                                pb_seconds = None,
                                pb_time = None,
                                pb_date = None,
                                num_runs = num_runs,
                                avg_seconds = avg_seconds,
                                avg_time = util.seconds_to_timestr(
                                    avg_seconds, dec_places=0),
                                video = None )
            except apiproxy_errors.OverQuotaError, msg:
                logging.error( msg )
                return self.OVER_QUOTA_ERROR
            # Set the pb time
            if pb_run:
                runinfo['pb_seconds'] = pb_run.seconds
                runinfo['pb_time'] = util.seconds_to_timestr( pb_run.seconds )
                runinfo['pb_date'] = pb_run.date
                runinfo['video'] = pb_run.video
                runinfo['version'] = pb_run.version
                
            if memcache.set( key, runinfo ):
                logging.debug( "Set " + key + " in memcache" )
            else:
                logging.warning( "Failed to set " + key + " in memcache" )
Ejemplo n.º 18
0
 def get_run_by_id(self, run_id):
     key = self.get_run_by_id_memkey(run_id)
     run = memcache.get(key)
     if run is None:
         # Not in memcache, so get the run from database and store in
         # memcache.
         run = runs.Runs.get_by_id(long(run_id), parent=runs.key())
         if memcache.set(key, run):
             logging.debug("Set run in memcache for run_id" + str(run_id))
         else:
             logging.warning("Failed to set new run for run_id" + str(run_id) + " in memcache")
     else:
         logging.debug("Got run with run_id " + str(run_id) + " from " + "memcache")
     return run
Ejemplo n.º 19
0
    def get_pblist( self, username, no_refresh=False ):
        key = self.get_pblist_memkey( username )
        pblist = memcache.get( key )
        if pblist is None and not no_refresh:
            # Not in memcache, so construct the pblist and store in memcache.
            # pblist is a list of dictionaries with 3 indices, 'game', 
            # 'game_code' and 'infolist'.  The infolist is another list of 
            # dictionaries containing all the info for each pb of the game.
            pblist = [ ]
            try:
                # Use a projection query to get all of the unique game, category
                # pairs
                q = db.Query( runs.Runs, projection=('game', 'category'), 
                              distinct=True )
                q.ancestor( runs.key() )
                q.filter( 'username ='******'game' )
                q.order( 'category' )
                cur_game = None
                for run in q.run( limit = 1000 ):
                    if run.game != cur_game:
                        # New game
                        pb = dict( game = run.game, 
                                   game_code = util.get_code( run.game ),
                                   num_runs = 0,
                                   infolist = [ ] )
                        pblist.append( pb )
                        cur_game = run.game                

                    # Add runinfo to pblist
                    info = self.get_runinfo( username, run.game, run.category )
                    if info == self.OVER_QUOTA_ERROR:
                        return self.OVER_QUOTA_ERROR
                    pb['infolist'].append( info )
                    pb['num_runs'] += info['num_runs']
            except apiproxy_errors.OverQuotaError, msg:
                logging.error( msg )
                return self.OVER_QUOTA_ERROR

            # Sort the categories for a game by num_runs
            for pb in pblist:
                pb['infolist'].sort( key=itemgetter('num_runs'), reverse=True )

            # Sort the games by number of runs
            pblist.sort( key=itemgetter('num_runs'), reverse=True )

            if memcache.set( key, pblist ):
                logging.debug( "Set " + key + " in memcache" )
            else:
                logging.warning( "Failed to set " + key + " in memcache" )
Ejemplo n.º 20
0
    def get_runinfo(self, username, game, category, no_refresh=False):
        key = self.get_runinfo_memkey(username, game, category)
        runinfo = memcache.get(key)
        if runinfo is None and not no_refresh:
            # Not in memcache, so constrcut the runinfo dictionary
            q = db.Query(runs.Runs, projection=("seconds", "date", "video", "version"))
            q.ancestor(runs.key())
            q.filter("username ="******"game =", game)
            q.filter("category =", category)
            q.order("-date")  # Cut off old runs
            pb_run = None
            avg_seconds = 0
            num_runs = 0
            for run in q.run(limit=100000):
                num_runs += 1
                avg_seconds += (1.0 / num_runs) * (run.seconds - avg_seconds)
                if pb_run is None or run.seconds <= pb_run.seconds:
                    pb_run = run

            runinfo = dict(
                username=username,
                username_code=util.get_code(username),
                category=category,
                category_code=util.get_code(category),
                pb_seconds=None,
                pb_time=None,
                pb_date=None,
                num_runs=num_runs,
                avg_seconds=avg_seconds,
                avg_time=util.seconds_to_timestr(avg_seconds),
                video=None,
            )
            # Set the pb time
            if pb_run:
                runinfo["pb_seconds"] = pb_run.seconds
                runinfo["pb_time"] = util.seconds_to_timestr(pb_run.seconds)
                runinfo["pb_date"] = pb_run.date
                runinfo["video"] = pb_run.video
                runinfo["version"] = pb_run.version

            if memcache.set(key, runinfo):
                logging.debug("Set " + key + " in memcache")
            else:
                logging.warning("Failed to set " + key + " in memcache")
        elif runinfo is not None:
            logging.debug("Got " + key + " from memcache")
        return runinfo
Ejemplo n.º 21
0
 def get_run_by_id(self, run_id):
     key = self.get_run_by_id_memkey(run_id)
     run = memcache.get(key)
     if run is None:
         # Not in memcache, so get the run from database and store in
         # memcache.
         try:
             run = runs.Runs.get_by_id(long(run_id), parent=runs.key())
         except apiproxy_errors.OverQuotaError, msg:
             logging.error(msg)
             return self.OVER_QUOTA_ERROR
         if memcache.set(key, run):
             logging.debug("Set run in memcache for run_id" + str(run_id))
         else:
             logging.warning("Failed to set new run for run_id" +
                             str(run_id) + " in memcache")
Ejemplo n.º 22
0
 def get_run_by_id(self, run_id):
     key = self.get_run_by_id_memkey(run_id)
     run = memcache.get(key)
     if run is None:
         # Not in memcache, so get the run from database and store in
         # memcache.
         run = runs.Runs.get_by_id(long(run_id), parent=runs.key())
         if memcache.set(key, run):
             logging.debug("Set run in memcache for run_id" + str(run_id))
         else:
             logging.warning("Failed to set new run for run_id" +
                             str(run_id) + " in memcache")
     else:
         logging.debug("Got run with run_id " + str(run_id) + " from " +
                       "memcache")
     return run
Ejemplo n.º 23
0
 def get_last_run(self, username, no_refresh=False):
     key = self.get_last_run_memkey(username)
     run = memcache.get(key)
     if run is None and not no_refresh:
         # Not in memcache, so check datastore
         q = db.Query(runs.Runs)
         q.ancestor(runs.key())
         q.filter('username ='******'-datetime_created')
         run = q.get()
         if memcache.set(key, run):
             logging.debug("Set " + key + " in memcache")
         else:
             logging.warning("Failed to set " + key + " in memcache")
     elif run is not None:
         logging.debug("Got " + key + " from memcache")
     return run
Ejemplo n.º 24
0
 def get_run_by_id( self, run_id ):
     key = self.get_run_by_id_memkey( run_id )
     run = memcache.get( key )
     if run is None:
         # Not in memcache, so get the run from database and store in
         # memcache.
         try:
             run = runs.Runs.get_by_id( long( run_id ), parent=runs.key() )
         except apiproxy_errors.OverQuotaError, msg:
             logging.error( msg )
             return self.OVER_QUOTA_ERROR
         if memcache.set( key, run ):
             logging.debug( "Set run in memcache for run_id" 
                            + str( run_id ) )
         else:
             logging.warning( "Failed to set new run for run_id" 
                              + str( run_id ) + " in memcache" )
Ejemplo n.º 25
0
 def get_last_run(self, username, no_refresh=False):
     key = self.get_last_run_memkey(username)
     run = memcache.get(key)
     if run is None and not no_refresh:
         # Not in memcache, so check datastore
         q = db.Query(runs.Runs)
         q.ancestor(runs.key())
         q.filter("username ="******"-datetime_created")
         run = q.get()
         if memcache.set(key, run):
             logging.debug("Set " + key + " in memcache")
         else:
             logging.warning("Failed to set " + key + " in memcache")
     elif run is not None:
         logging.debug("Got " + key + " from memcache")
     return run
Ejemplo n.º 26
0
    def get_last_run( self, username, no_refresh=False ):
        key = self.get_last_run_memkey( username )
        run = memcache.get( key )
        if run is None and not no_refresh:
            # Not in memcache, so check datastore
            try:
                q = db.Query( runs.Runs )
                q.ancestor( runs.key() )
                q.filter( 'username ='******'-datetime_created' )
                run = q.get( )
            except apiproxy_errors.OverQuotaError, msg:
                logging.error( msg )
                return self.OVER_QUOTA_ERROR

            if memcache.set( key, run ):
                logging.debug( "Set " + key + " in memcache" )
            else:
                logging.warning( "Failed to set " + key + " in memcache" )
Ejemplo n.º 27
0
    def get_pblist(self, username, no_refresh=False):
        key = self.get_pblist_memkey(username)
        pblist = memcache.get(key)
        if pblist is None and not no_refresh:
            # Not in memcache, so construct the pblist and store in memcache.
            # pblist is a list of dictionaries with 3 indices, 'game',
            # 'game_code' and 'infolist'.  The infolist is another list of
            # dictionaries containing all the info for each pb of the game.
            pblist = []
            # Use a projection query to get all of the unique game, category
            # pairs
            q = db.Query(runs.Runs, projection=("game", "category"), distinct=True)
            q.ancestor(runs.key())
            q.filter("username ="******"game")
            q.order("category")
            cur_game = None
            for run in q.run(limit=1000):
                if run.game != cur_game:
                    # New game
                    pb = dict(game=run.game, game_code=util.get_code(run.game), num_runs=0, infolist=[])
                    pblist.append(pb)
                    cur_game = run.game

                # Add runinfo to pblist
                info = self.get_runinfo(username, run.game, run.category)
                pb["infolist"].append(info)
                pb["num_runs"] += info["num_runs"]

            # Sort the categories for a game by num_runs
            for pb in pblist:
                pb["infolist"].sort(key=itemgetter("num_runs"), reverse=True)

            # Sort the games by number of runs
            pblist.sort(key=itemgetter("num_runs"), reverse=True)

            if memcache.set(key, pblist):
                logging.debug("Set " + key + " in memcache")
            else:
                logging.warning("Failed to set " + key + " in memcache")
        elif pblist is not None:
            logging.debug("Got " + key + " from memcache")
        return pblist
Ejemplo n.º 28
0
    def get_last_run(self, username, no_refresh=False):
        key = self.get_last_run_memkey(username)
        run = memcache.get(key)
        if run is None and not no_refresh:
            # Not in memcache, so check datastore
            try:
                q = db.Query(runs.Runs)
                q.ancestor(runs.key())
                q.filter('username ='******'-datetime_created')
                run = q.get()
            except apiproxy_errors.OverQuotaError, msg:
                logging.error(msg)
                return self.OVER_QUOTA_ERROR

            if memcache.set(key, run):
                logging.debug("Set " + key + " in memcache")
            else:
                logging.warning("Failed to set " + key + " in memcache")
Ejemplo n.º 29
0
 def get_user_has_run(self, username, game, no_refresh=False):
     key = self.get_user_has_run_memkey(username, game)
     user_has_run = memcache.get(key)
     if user_has_run is None and not no_refresh:
         # Not in memcache, so check datastore
         q = db.Query(runs.Runs, keys_only=True)
         q.ancestor(runs.key())
         q.filter("username ="******"game =", game)
         num = q.count(limit=1)
         if num > 0:
             user_has_run = True
         else:
             user_has_run = False
         if memcache.set(key, user_has_run):
             logging.debug("Set " + key + " in memcache")
         else:
             logging.warning("Failed to set " + key + " in memcache")
     elif user_has_run is not None:
         logging.debug("Got " + key + " from memcache")
     return user_has_run
Ejemplo n.º 30
0
 def get_user_has_run(self, username, game, no_refresh=False):
     key = self.get_user_has_run_memkey(username, game)
     user_has_run = memcache.get(key)
     if user_has_run is None and not no_refresh:
         # Not in memcache, so check datastore
         q = db.Query(runs.Runs, keys_only=True)
         q.ancestor(runs.key())
         q.filter('username ='******'game =', game)
         num = q.count(limit=1)
         if num > 0:
             user_has_run = True
         else:
             user_has_run = False
         if memcache.set(key, user_has_run):
             logging.debug("Set " + key + " in memcache")
         else:
             logging.warning("Failed to set " + key + " in memcache")
     elif user_has_run is not None:
         logging.debug("Got " + key + " from memcache")
     return user_has_run
Ejemplo n.º 31
0
 def get_user_has_run(self, username, game, no_refresh=False):
     key = self.get_user_has_run_memkey(username, game)
     user_has_run = memcache.get(key)
     if user_has_run is None and not no_refresh:
         # Not in memcache, so check datastore
         try:
             q = db.Query(runs.Runs, keys_only=True)
             q.ancestor(runs.key())
             q.filter('username ='******'game =', game)
             num = q.count(limit=1)
             if num > 0:
                 user_has_run = True
             else:
                 user_has_run = False
         except apiproxy_errors.OverQuotaError, msg:
             logging.error(msg)
             return self.OVER_QUOTA_ERROR
         if memcache.set(key, user_has_run):
             logging.debug("Set " + key + " in memcache")
         else:
             logging.warning("Failed to set " + key + " in memcache")
Ejemplo n.º 32
0
 def get_user_has_run( self, username, game, no_refresh=False ):
     key = self.get_user_has_run_memkey( username, game )
     user_has_run = memcache.get( key )
     if user_has_run is None and not no_refresh:
         # Not in memcache, so check datastore
         try:
             q = db.Query( runs.Runs, keys_only=True )
             q.ancestor( runs.key() )
             q.filter( 'username ='******'game =', game )
             num = q.count( limit=1 )
             if num > 0:
                 user_has_run = True
             else:
                 user_has_run = False
         except apiproxy_errors.OverQuotaError, msg:
             logging.error( msg )
             return self.OVER_QUOTA_ERROR
         if memcache.set( key, user_has_run ):
             logging.debug( "Set " + key + " in memcache" )
         else:
             logging.warning( "Failed to set " + key + " in memcache" )
Ejemplo n.º 33
0
    def get( self ):
        # Make sure it's me
        user = self.get_user( )
        if not user or user.username != "rggibson":
            self.error( 404 )
            self.render( "404.html", user=user )
            return

        # Convert seconds to float
        q = db.Query( runs.Runs )
        q.ancestor( runs.key() )
        count = 0
        for run in q.run( limit=1000000 ):
            count += 1
            if not isinstance( run.seconds, float ):
                try:
                    run.seconds = float( run.seconds )
                    run.put( )
                except apiproxy_errors.OverQuotaError, message:
                    logging.error( message )
                    self.write( "Over quota error caught after "
                                + str( count ) + "runs:<br>" + message )
                    return
Ejemplo n.º 34
0
    def get_pblist( self, username, page_num, show_all ):
        key = self.get_pblist_memkey( username )
        cached_pblists = memcache.get( key )
        if cached_pblists is None:
            cached_pblists = dict( )
        res = cached_pblists.get( page_num )
        if res is None or ( show_all and not res['show_all'] ):
            pblist = [ ]
            c = None
            if res is None:
                res = dict( page_num=page_num, has_next=False,
                            show_all=show_all )
                # Not in memcache, so construct the pblist and store in
                # memcache.
                # pblist is a list of dictionaries with 3 indices, 'game', 
                # 'game_code' and 'infolist'.  The infolist is another list of 
                # dictionaries containing all the info for each pb of the game.
                c = memcache.get( self.get_pblist_cursor_memkey(
                    username, page_num ) )
            else:
                # Need to update this page to a show_all
                res['show_all'] = show_all
                res['has_next'] = False
                res['page_num'] = page_num
                if page_num == 1:
                    # Can try to start from normal page 2
                    pblist = res['pblist']
                    c = memcache.get( self.get_pblist_cursor_memkey(
                        username, page_num + 1 ) )
                        
            try:
                q = db.Query( runs.Runs,
                              projection=['game', 'category', 'seconds',
                                          'date', 'video', 'version'] )
                q.ancestor( runs.key() )
                q.filter( 'username ='******'game' )
                q.order( 'category' )
                q.order( 'seconds' )
                if c:
                    try:
                        q.with_cursor( start_cursor=c )
                    except BadRequestError:
                        res['page_num'] = 1
                        pblist = [ ]
                else:
                    res['page_num'] = 1
                    pblist = [ ]
                cur_game = None
                pb = None
                if len( pblist ) > 0:
                    cur_game = pblist[ -1 ]['game']
                    pb = pblist[ -1 ]
                cur_category = None
                info = None
                cursor_to_save = c
                last_cursor = None
                runs_queried = 0
                limit = self.PB_PAGE_LIMIT
                if show_all:
                    limit = self.PB_PAGE_SHOW_ALL_LIMIT
                for run in q.run( limit=limit ):
                    if run.game != cur_game:
                        # New game
                        pb = dict( game = run.game,
                                   game_code = util.get_code( run.game ),
                                   num_runs = 0,
                                   infolist = [ ] )
                        pblist.append( pb )
                        cur_game = run.game
                        cur_category = None

                    if run.category != cur_category:
                        # New category
                        info = dict( username = username,
                                     username_code = util.get_code( username ),
                                     category = run.category,
                                     category_code = util.get_code(
                                         run.category ),
                                     pb_seconds = run.seconds,
                                     pb_time = util.seconds_to_timestr(
                                         run.seconds ),
                                     pb_date = run.date,
                                     num_runs = 1,
                                     avg_seconds = run.seconds,
                                     avg_time = util.seconds_to_timestr(
                                         run.seconds, dec_places=0 ),
                                     video = run.video,
                                     version = run.version )
                        pb['infolist'].append( info )
                        cur_category = run.category
                        if last_cursor is not None:
                            cursor_to_save = last_cursor
                    else:
                        # Repeat game, category
                        info['num_runs'] += 1
                        info['avg_seconds'] += ( 1.0 / info['num_runs'] ) * (
                            run.seconds - info['avg_seconds'] )
                        info['avg_time'] = util.seconds_to_timestr(
                            info['avg_seconds'], dec_places=0 )
                    pb['num_runs'] += 1
                    runs_queried += 1
                    last_cursor = q.cursor( )
                
                if runs_queried < limit:
                    # Made it to the end
                    cursor_to_save = q.cursor( )
                    if res['page_num'] == 1:
                        res['show_all'] = True
                else:
                    res['has_next'] = True

                    # Last category found is possibly incomplete, so remove
                    del pblist[ -1 ]['infolist'][ -1 ]
                    if len( pblist[ -1 ]['infolist'] ) <= 0:
                        del pblist[ -1 ]
                        if len( pblist ) <= 0:
                            # Too many runs for this game, category
                            pb = dict(
                                game = cur_game,
                                game_code = util.get_code( cur_game ),
                                num_runs = 0,
                                infolist = [ dict( 
                                    username=username,
                                    username_code = util.get_code(
                                        username ),
                                    category=( 'TOO MANY RUNS FOR '
                                               + 'CATEGORY: '
                                               + cur_category
                                               + ' (max is '
                                               + str( self.PB_PAGE_LIMIT - 1 )
                                               + ', please delete some runs)' ),
                                    category_code=util.get_code(
                                        cur_category ),
                                    pb_seconds=0,
                                    pb_time=util.seconds_to_timestr( 0 ),
                                    pb_date=None,
                                    num_runs=0,
                                    avg_seconds=0,
                                    avg_time=util.seconds_to_timestr( 0 ),
                                    video=None ) ] )
                            pblist.append( pb )
                    if res['show_all']:
                        # Over limit even with show all
                        res['has_next'] = False
                        pb = dict( game='TOO MANY RUNS TO SHOW ALL',
                                   game_code='???',
                                   num_runs=0,
                                   infolist=[ dict(
                                       username=username,
                                       username_code = util.get_code(
                                           username ),
                                       category=( 'MAX IS ' + str(
                                           self.PB_PAGE_SHOW_ALL_LIMIT )
                                                  + ', PLEASE DELETE '
                                                  + 'SOME RUNS' ),
                                       category_code='???',
                                       pb_seconds=0,
                                       pb_time=util.seconds_to_timestr( 0 ),
                                       pb_date=None,
                                       num_runs=0,
                                       avg_seconds=0,
                                       avg_time=util.seconds_to_timestr( 0 ),
                                       video=None ) ] )
                        res['pblist'] = [ pb ]
                        return res

                cursor_key = self.get_pblist_cursor_memkey(
                    username, res['page_num'] + 1 )
                if memcache.set( cursor_key, cursor_to_save ):
                    logging.debug( 'Set ' + cursor_key + " in memcache" )
                else:
                    logging.warning( 'Failed to set ' + cursor_key
                                     + ' in memcache' )
            except apiproxy_errors.OverQuotaError, msg:
                logging.error( msg )
                return self.OVER_QUOTA_ERROR

            # Sort the categories for a game by num_runs
            for pb in pblist:
                pb['infolist'].sort( key=itemgetter('num_runs'), reverse=True )

            res['pblist'] = pblist
            cached_pblists[ res['page_num'] ] = res
            if memcache.set( key, cached_pblists ):
                logging.debug( "Set " + key + " in memcache" )
            else:
                logging.warning( "Failed to set " + key + " in memcache" )
Ejemplo n.º 35
0
 # Check if any runs exist now for this category
 num_category_runs = 1
 try:
     q = db.Query(runs.Runs, keys_only=True)
     q.ancestor(runs.key())
     q.filter("game =", game_model.game)
     q.filter("category =", category)
     num_category_runs = q.count(limit=1)
 except apiproxy_errors.OverQuotaError, msg:
     logging.error(msg)
 if num_category_runs <= 0:
     # Check if any runs exist now for this game at all
     num_runs = 1
     try:
         q = db.Query(runs.Runs, keys_only=True)
         q.ancestor(runs.key())
         q.filter("game =", game_model.game)
         num_runs = q.count(limit=1)
     except apiproxy_errors.OverQuotaError, msg:
         logging.error(msg)
     if num_runs <= 0:
         # No runs exist. Delete this game from the db
         game = game_model.game
         game_model.delete()
         logging.info(game + " deleted")
         self.update_cache_game_model(util.get_code(game), None)
         # From gamelist in memcache too
         cached_gamelists = self.get_cached_gamelists()
         if cached_gamelists is not None:
             done = False
             for page_num, res in cached_gamelists.iteritems():
Ejemplo n.º 36
0
    def change_categories( self, params ):
        res = ''

        # Grab the old game model
        old_game_code = util.get_code( params['old_game'] )
        if old_game_code == params['new_game_code']:
            old_game_model = params['new_game_model']
        else:
            old_game_model = self.get_game_model( old_game_code )
        if old_game_model == self.OVER_QUOTA_ERROR:
            self.error( 403 )
            self.render( "403.html" )
            return
        if old_game_model is None:
            return "Did not find game [" + params['old_game'] + "]"

        if params['new_game_model'] is None:
            # New game does not exist, so create it
            params['new_game_model'] = games.Games( 
                game = params['new_game'],
                info = json.dumps( [ ] ),
                num_pbs = 0,
                parent = games.key( ),
                key_name = params['new_game_code'] )
            res += ( 'Created new game model for game [' + params['new_game'] 
                     + ']<br>' )
        
        if not params['new_category_found']:
            # Add the new category to the new game model
            gameinfolist = json.loads( params['new_game_model'].info )
            d = dict( category=params['new_category'], 
                      bk_runner=None,
                      bk_seconds=None,
                      bk_video=None,
                      bk_datestr=None,
                      bk_updater=None )
            gameinfolist.append( d )
            params['new_game_model'].info = json.dumps( gameinfolist )
            res += 'Added new category [' + params['new_category'] + ']<br>'

        # Grab the gameinfo for the old game
        oldgameinfolist = json.loads( old_game_model.info )
        oldgameinfo = None
        for g in oldgameinfolist:
            if( util.get_code( params['old_category'] ) == util.get_code( 
                    g['category'] ) ):
                oldgameinfo = g
                break
        if oldgameinfo is None:
            return "Did not find old category [" + params['old_category'] + ']'

        # Grab the gameinfo for the new game
        newgameinfolist = json.loads( params['new_game_model'].info )
        newgameinfo = None
        for g in newgameinfolist:
            if( util.get_code( params['new_category'] ) == util.get_code( 
                    g['category'] ) ):
                newgameinfo = g
                break
        if newgameinfo is None:
            return "Did not find new category [" + params['new_category'] + ']'

        # Update best known time if necessary
        if( oldgameinfo.get( 'bk_seconds' ) is not None
            and ( newgameinfo.get( 'bk_seconds' ) is None 
                  or oldgameinfo.get( 'bk_seconds' ) 
                  < newgameinfo.get( 'bk_seconds' ) ) ):
            newgameinfo['bk_seconds'] = oldgameinfo.get( 'bk_seconds' )
            newgameinfo['bk_runner'] = oldgameinfo.get( 'bk_runner' )
            newgameinfo['bk_datestr'] = oldgameinfo.get( 'bk_datestr' )
            newgameinfo['bk_video'] = oldgameinfo.get( 'bk_video' )
            newgameinfo['bk_updater'] = oldgameinfo.get( 'bk_updater' )
            params['new_game_model'].info = json.dumps( newgameinfolist )
            res += 'Updated bkt<br>'

        if not memcache.flush_all( ):
            res += "Failed to flush memcache<br>"

        # Update num_pbs for old game, new game
        res += ( 'Previous num_pbs for old game, category = ' 
                 + str( old_game_model.num_pbs ) + '<br>' )
        res += ( 'Previous num_pbs for new game, category = ' 
                 + str( params['new_game_model'].num_pbs ) + '<br>' )
        try:
            q = db.Query( runs.Runs, projection=['username'], distinct=True )
            q.ancestor( runs.key() )
            q.filter( 'game =', params['old_game'] )
            q.filter( 'category =', params['old_category'] )
            for run in q.run( limit=1000 ):
                old_game_model.num_pbs -= 1
                q2 = db.Query( runs.Runs )
                q2.ancestor( runs.key() )
                q2.filter( 'game =', params['new_game'] )
                q2.filter( 'category =', params['new_category'] )
                q2.filter( 'username ='******'new_game_model'].num_pbs += 1
                else:
                    # Need to decrement runner's num_pbs
                    runner = self.get_runner( util.get_code( run.username ) )
                    if runner == self.OVER_QUOTA_ERROR:
                        return 'Over quota error'
                    runner.num_pbs -= 1
                    runner.put( )
                    res += ( "Updated " + run.username + " num_pbs from "
                             + str( runner.num_pbs + 1 ) + " to " 
                             + str( runner.num_pbs ) + "<br>" )
        except apiproxy_errors.OverQuotaError, msg:
            logging.error( msg )
            return "Ran out of quota"
Ejemplo n.º 37
0
    def put_new_run( self, params ):
        user = params.get( 'user' )
        game = params.get( 'game' )
        category = params.get( 'category' )
        seconds = params.get( 'seconds' )
        time = params.get( 'time' )
        video = params.get( 'video' )
        version = params.get( 'version' )
        notes = params.get( 'notes' )
        valid = params.get( 'valid' )

        # Add a new run to the database
        try:
            new_run = runs.Runs( username = user.username,
                                 game = game,
                                 category = category,
                                 seconds = seconds,
                                 date = params[ 'date' ],
                                 version = version,
                                 notes = notes,
                                 parent = runs.key() )
            try:
                if video:
                    new_run.video = video
            except db.BadValueError:
                params[ 'video_error' ] = "Invalid video URL"
                valid = False
        except db.BadValueError:
            valid = False
        
        if not valid:
            return False

        new_run.put( )
        params[ 'run_id' ] = str( new_run.key().id() )
        params[ 'datetime_created' ] = new_run.datetime_created
        logging.debug( "Put new run for runner " + user.username
                       + ", game = " + game + ", category = " + category 
                       + ", time = " + time )

        # Check whether this is the first run for this username, game,
        # category combination.  This will determine whether we need to update
        # the gamelist and runnerlist, as well as update the num_pbs
        # for the game and runner.
        delta_num_pbs = 0
        num_runs = self.num_runs( user.username, game, category, 2 )
        if num_runs == 1:
            delta_num_pbs = 1

        # Update games.Games, runners.Runners
        self.update_runner( user, delta_num_pbs )
        self.update_games_put( params, delta_num_pbs )

        # Update memcache
        self.update_cache_run_by_id( new_run.key().id(), new_run )
        # Must update runinfo before updating pblist, gamepage since these 
        # both rely on runinfo being up to date
        self.update_runinfo_put( params )
        self.update_pblist_put( params )
        self.update_gamepage_put( params )
        self.update_runlist_for_runner_put( params )
        self.update_cache_user_has_run( user.username, game, True )
        self.update_cache_last_run( user.username, new_run )
                     
        if num_runs <= 0:
            logging.error( "Unexpected count [" + str(count) 
                           + "] for number of runs for "
                           + username + ", " + game + ", " + category )
            self.update_cache_gamelist( None )
            self.update_cache_runnerlist( None )
        if delta_num_pbs == 1:
            self.update_gamelist_put( params )
            self.update_runnerlist_put( params )

        return True
Ejemplo n.º 38
0
    def update_runinfo_delete( self, user, old_run ):
        # Update avg, num runs
        runinfo = self.get_runinfo( user.username, old_run['game'],
                                    old_run['category'], no_refresh=True )
        if runinfo is None:
            return

        if runinfo['num_runs'] <= 0:
            logging.error( "Failed to update runinfo due to nonpositive "
                           + "num_runs " + str( runinfo['num_runs'] ) )
            self.update_cache_runinfo( user.username, old_run['game'],
                                       old_run['category'], None )
            return

        if( runinfo['num_runs'] > 1 ):
            runinfo['avg_seconds'] -= ( 1.0 * old_run['seconds'] 
                                        / runinfo['num_runs'] )
            runinfo['num_runs'] -= 1
            runinfo['avg_seconds'] *= ( 1.0 * ( runinfo['num_runs'] + 1 ) 
                                        / runinfo['num_runs'] )
            runinfo['avg_time'] = util.seconds_to_timestr( 
                runinfo['avg_seconds'] )
            if( runinfo['pb_seconds'] == old_run['seconds'] ):
                # We need to replace the pb too
                q = db.Query( runs.Runs, projection=('seconds', 'date', 
                                                     'video', 'version') )
                q.ancestor( runs.key() )
                q.filter( 'username ='******'game =', old_run['game'] )
                q.filter( 'category =', old_run['category'] )
                q.order( 'seconds' )
                q.order( 'date' )
                pb_run = q.get( )
                if pb_run:
                    runinfo['pb_seconds'] = pb_run.seconds
                    runinfo['pb_time'] = util.seconds_to_timestr( 
                        pb_run.seconds )
                    runinfo['pb_date'] = pb_run.date
                    runinfo['video'] = pb_run.video
                    runinfo['version'] = pb_run.version
                else:
                    logging.error( "Unable to update runinfo due to no new "
                                   + "pb found" )
                    self.update_cache_runinfo( user.username, old_run['game'],
                                               old_run['category'], None )
                    return
            self.update_cache_runinfo( user.username, old_run['game'],
                                       old_run['category'], runinfo )
        else:
            # No other runs for game, category combo
            self.update_cache_runinfo( user.username, old_run['game'],
                                       old_run['category'], 
                                       dict( username=user.username,
                                             username_code=util.get_code(
                                                 user.username ),
                                             category=old_run['category'],
                                             category_code=util.get_code(
                                                 old_run['category'] ),
                                             pb_seconds=None,
                                             pb_time=None,
                                             pb_date=None,
                                             num_runs=0,
                                             avg_seconds=0,
                                             avg_time='0:00',
                                             video=None,
                                             version=None ) )
Ejemplo n.º 39
0
    def update_runinfo_delete(self, user, old_run):
        # Update avg, num runs
        runinfo = self.get_runinfo(user.username,
                                   old_run['game'],
                                   old_run['category'],
                                   no_refresh=True)
        if runinfo is None:
            return
        if runinfo == self.OVER_QUOTA_ERROR:
            self.update_cache_runinfo(user.username, game, category, None)
            return

        if runinfo['num_runs'] <= 0:
            logging.error("Failed to update runinfo due to nonpositive " +
                          "num_runs " + str(runinfo['num_runs']))
            self.update_cache_runinfo(user.username, old_run['game'],
                                      old_run['category'], None)
            return

        if (runinfo['num_runs'] > 1):
            runinfo['avg_seconds'] -= (1.0 * old_run['seconds'] /
                                       runinfo['num_runs'])
            runinfo['num_runs'] -= 1
            runinfo['avg_seconds'] *= (1.0 * (runinfo['num_runs'] + 1) /
                                       runinfo['num_runs'])
            runinfo['avg_time'] = util.seconds_to_timestr(
                runinfo['avg_seconds'])
            if (runinfo['pb_seconds'] == old_run['seconds']):
                # We need to replace the pb too
                try:
                    q = db.Query(runs.Runs,
                                 projection=('seconds', 'date', 'video',
                                             'version'))
                    q.ancestor(runs.key())
                    q.filter('username ='******'game =', old_run['game'])
                    q.filter('category =', old_run['category'])
                    q.order('seconds')
                    q.order('date')
                    pb_run = q.get()
                    if pb_run:
                        runinfo['pb_seconds'] = pb_run.seconds
                        runinfo['pb_time'] = util.seconds_to_timestr(
                            pb_run.seconds)
                        runinfo['pb_date'] = pb_run.date
                        runinfo['video'] = pb_run.video
                        runinfo['version'] = pb_run.version
                    else:
                        logging.error("Unable to update runinfo due to no " +
                                      "new pb found")
                        self.update_cache_runinfo(user.username,
                                                  old_run['game'],
                                                  old_run['category'], None)
                        return
                except apiproxy_errors.OverQuotaError, msg:
                    logging.error(msg)
                    self.update_cache_runinfo(user.username, old_run['game'],
                                              old_run['category'], None)
                    return
            self.update_cache_runinfo(user.username, old_run['game'],
                                      old_run['category'], runinfo)
Ejemplo n.º 40
0
    def put_new_run(self, params):
        user = params.get('user')
        game = params.get('game')
        category = params.get('category')
        seconds = params.get('seconds')
        time = params.get('time')
        video = params.get('video')
        version = params.get('version')
        notes = params.get('notes')
        valid = params.get('valid')

        # Add a new run to the database
        try:
            new_run = runs.Runs(username=user.username,
                                game=game,
                                category=category,
                                seconds=seconds,
                                date=params['date'],
                                version=version,
                                notes=notes,
                                parent=runs.key())
            try:
                if video:
                    new_run.video = video
            except db.BadValueError:
                params['video_error'] = "Invalid video URL"
                valid = False
        except db.BadValueError:
            valid = False

        if not valid:
            return False

        new_run.put()
        params['run_id'] = str(new_run.key().id())
        params['datetime_created'] = new_run.datetime_created
        logging.debug("Put new run for runner " + user.username + ", game = " +
                      game + ", category = " + category + ", time = " + time)

        # Check whether this is the first run for this username, game,
        # category combination.  This will determine whether we need to update
        # the gamelist and runnerlist, as well as update the num_pbs
        # for the game and runner.
        delta_num_pbs = 0
        num_runs = self.num_runs(user.username, game, category, 2)
        if num_runs == 1:
            delta_num_pbs = 1

        # Update games.Games, runners.Runners
        self.update_runner(user, delta_num_pbs)
        self.update_games_put(params, delta_num_pbs)

        # Update memcache
        self.update_cache_run_by_id(new_run.key().id(), new_run)
        # Must update runinfo before updating pblist, gamepage since these
        # both rely on runinfo being up to date
        self.update_runinfo_put(params)
        self.update_pblist_put(params)
        self.update_gamepage_put(params)
        self.update_runlist_for_runner_put(params)
        self.update_cache_user_has_run(user.username, game, True)
        self.update_cache_last_run(user.username, new_run)

        if num_runs <= 0:
            logging.error("Unexpected count [" + str(count) +
                          "] for number of runs for " + username + ", " +
                          game + ", " + category)
            self.update_cache_gamelist(None, get_num_pbs=True)
            self.update_cache_gamelist(None, get_num_pbs=False)
            self.update_cache_runnerlist(None)
        if delta_num_pbs == 1:
            self.update_gamelist_put(params)
            self.update_runnerlist_put(params)

        return True
Ejemplo n.º 41
0
    def update_pblist_delete(self, user, old_run):
        # Update pblist with the removal of the old run
        cached_pblists = self.get_cached_pblists(user.username)
        if cached_pblists is None:
            return

        for page_num, res in cached_pblists.iteritems():
            pblist = res["pblist"]
            for i, pb in enumerate(pblist):
                if pb["game"] == old_run["game"]:
                    pb["num_runs"] -= 1
                    for j, info in enumerate(pb["infolist"]):
                        if info["category"] == old_run["category"]:
                            if info["num_runs"] <= 1:
                                # No other runs for game, category combo
                                del pb["infolist"][j]
                                if len(pb["infolist"]) <= 0:
                                    del cached_pblists[page_num]["pblist"][i]
                                self.update_cache_pblist(user.username, cached_pblists)
                                return
                            else:
                                new_avg = (info["avg_seconds"] * info["num_runs"]) - old_run["seconds"]
                                info["num_runs"] -= 1
                                info["avg_seconds"] = 1.0 * new_avg / info["num_runs"]
                                info["avg_time"] = util.seconds_to_timestr(info["avg_seconds"], dec_places=0)
                                if info["pb_seconds"] >= old_run["seconds"]:
                                    # Update our PB for this game, category
                                    q = db.Query(runs.Runs, projection=["seconds", "date", "video", "version"])
                                    q.ancestor(runs.key())
                                    q.filter("username ="******"game =", old_run["game"])
                                    q.filter("category =", old_run["category"])
                                    q.order("seconds")
                                    for run in q.run(limit=1):
                                        info["pb_seconds"] = run.seconds
                                        info["pb_time"] = util.seconds_to_timestr(run.seconds)
                                        info["pb_date"] = run.date
                                        info["video"] = run.video
                                        info["version"] = run.version
                                        break
                                    else:
                                        logging.error(
                                            "Failed to update PB for "
                                            + user.username
                                            + ", "
                                            + old_run["game"]
                                            + ", "
                                            + old_run["category"]
                                            + " on pblist_delete"
                                        )
                                        self.update_cache_pblist(user.username, None)
                                        return

                            pb["infolist"][j] = info
                            pb["infolist"].sort(key=itemgetter("category"))
                            pb["infolist"].sort(key=itemgetter("num_runs"), reverse=True)
                            self.update_cache_pblist(user.username, cached_pblists)
                            return
                    # Couldn't find this game, category in memcache, so nothing
                    # to update
                    return
Ejemplo n.º 42
0
    def get( self ):
        QUERY_LIMIT = 1000
        cursor_key = 'fixerupper-cursor'
        
        # Make sure it's me
        user = self.get_user( )
        if not user:
            self.error( 404 )
            self.render( "404.html", user=user )
            return
        elif user == self.OVER_QUOTA_ERROR:
            self.error( 403 )
            self.render( "403.html" )
            return
        elif user.username != "rggibson":
            self.error( 404 )
            self.render( "404.html", user=user )
            return

        c = self.request.get( 'c', default_value=None )

        try:
            # Add missing games and categories back in + update num_pbs
            q = db.Query( runs.Runs, projection=[ 'game', 'category',
                                                  'username' ],
                          distinct=True )
            q.ancestor( runs.key( ) )
            q.order( 'game' )
            if c is None:
                c = memcache.get( cursor_key )
            if c:
                try:
                    q.with_cursor( start_cursor=c )
                    logging.info( "Fixer upper using cursor " + c )
                except BadRequestErro:
                    logging.error( "FixerUpper failed to use cursor" )
                    pass
            game_model = None
            categories = None
            infolist = None
            old_num_pbs = None
            do_update = None
            cursor_to_save = c
            prev_cursor = c
            num_runs = 0
            for run in q.run( limit=QUERY_LIMIT ):
                if game_model is None or game_model.game != run.game:
                    # New game
                    if game_model is not None:
                        # Save previous game model
                        game_model.info = json.dumps( infolist )
                        if do_update or game_model.num_pbs != old_num_pbs:
                            game_model.put( )
                            self.update_cache_game_model( game_code,
                                                          game_model )
                        cursor_to_save = prev_cursor

                    game_code = util.get_code( run.game )
                    game_model = self.get_game_model( game_code )
                    if game_model is None:
                        # Make a new game model
                        game_model = games.Games( game=run.game,
                                                  info=json.dumps( [ ] ),
                                                  num_pbs=0,
                                                  parent=games.key(),
                                                  key_name=game_code )      
                        logging.info( "Fixerupper put new game " + run.game
                                      + " in datastore." )
                    categories = game_model.categories( )
                    infolist = json.loads( game_model.info )
                    old_num_pbs = game_model.num_pbs
                    do_update = False
                    game_model.num_pbs = 0

                game_model.num_pbs += 1
                if run.category not in categories:
                    # Add category
                    infolist.append( dict( category=run.category,
                                           bk_runner=None,
                                           bk_seconds=None, bk_datestr=None,
                                           bk_video=None, bk_updater=None ) )
                    logging.info( "Fixerupper added category " + run.category
                                  + " to " + run.game )
                    categories.append( run.category )
                    do_update = True
                prev_cursor = q.cursor( )
                num_runs += 1
            if game_model is not None and num_runs < QUERY_LIMIT:
                # Save last game model
                game_model.info = json.dumps( infolist )
                game_model.put( )
                self.update_cache_game_model( game_code, game_model )
                cursor_to_save = prev_cursor

            if cursor_to_save == memcache.get( cursor_key ):
                logging.error( "No games updated by FixerUpper." )
                if game_model is not None:
                    logging.error( "Last game was " + game_model.game )
                self.write( "FixerUpper failed to update any games<br>" )
                return

            if memcache.set( cursor_key, cursor_to_save ):
                s = "FixerUpper finished and saved cursor " + cursor_to_save
                if game_model is not None:
                    s += "<br>Last game was " + game_model.game
                self.write( s )
            else:
                self.write( "FixerUpper finished but failed to save cursor "
                            + cursor_to_save )

        except apiproxy_errors.OverQuotaError, msg:
            logging.error( msg )
            self.write( "FixerUpper failed with over quota error<br>" )
            return
Ejemplo n.º 43
0
    def change_categories(self, params):
        res = ''

        # Grab the old game model
        old_game_code = util.get_code(params['old_game'])
        if old_game_code == params['new_game_code']:
            old_game_model = params['new_game_model']
        else:
            old_game_model = self.get_game_model(old_game_code)
        if old_game_model == self.OVER_QUOTA_ERROR:
            self.error(403)
            self.render("403.html")
            return
        if old_game_model is None:
            return "Did not find game [" + params['old_game'] + "]"

        if params['new_game_model'] is None:
            # New game does not exist, so create it
            params['new_game_model'] = games.Games(
                game=params['new_game'],
                info=json.dumps([]),
                num_pbs=0,
                parent=games.key(),
                key_name=params['new_game_code'])
            res += ('Created new game model for game [' + params['new_game'] +
                    ']<br>')

        if not params['new_category_found']:
            # Add the new category to the new game model
            gameinfolist = json.loads(params['new_game_model'].info)
            d = dict(category=params['new_category'],
                     bk_runner=None,
                     bk_seconds=None,
                     bk_video=None,
                     bk_datestr=None,
                     bk_updater=None)
            gameinfolist.append(d)
            params['new_game_model'].info = json.dumps(gameinfolist)
            res += 'Added new category [' + params['new_category'] + ']<br>'

        # Grab the gameinfo for the old game
        oldgameinfolist = json.loads(old_game_model.info)
        oldgameinfo = None
        for g in oldgameinfolist:
            if (util.get_code(params['old_category']) == util.get_code(
                    g['category'])):
                oldgameinfo = g
                break
        if oldgameinfo is None:
            return "Did not find old category [" + params['old_category'] + ']'

        # Grab the gameinfo for the new game
        newgameinfolist = json.loads(params['new_game_model'].info)
        newgameinfo = None
        for g in newgameinfolist:
            if (util.get_code(params['new_category']) == util.get_code(
                    g['category'])):
                newgameinfo = g
                break
        if newgameinfo is None:
            return "Did not find new category [" + params['new_category'] + ']'

        # Update best known time if necessary
        if (oldgameinfo.get('bk_seconds') is not None and
            (newgameinfo.get('bk_seconds') is None or
             oldgameinfo.get('bk_seconds') < newgameinfo.get('bk_seconds'))):
            newgameinfo['bk_seconds'] = oldgameinfo.get('bk_seconds')
            newgameinfo['bk_runner'] = oldgameinfo.get('bk_runner')
            newgameinfo['bk_datestr'] = oldgameinfo.get('bk_datestr')
            newgameinfo['bk_video'] = oldgameinfo.get('bk_video')
            newgameinfo['bk_updater'] = oldgameinfo.get('bk_updater')
            params['new_game_model'].info = json.dumps(newgameinfolist)
            res += 'Updated bkt<br>'

        if not memcache.flush_all():
            res += "Failed to flush memcache<br>"

        # Update num_pbs for old game, new game
        res += ('Previous num_pbs for old game, category = ' +
                str(old_game_model.num_pbs) + '<br>')
        res += ('Previous num_pbs for new game, category = ' +
                str(params['new_game_model'].num_pbs) + '<br>')
        try:
            q = db.Query(runs.Runs, projection=['username'], distinct=True)
            q.ancestor(runs.key())
            q.filter('game =', params['old_game'])
            q.filter('category =', params['old_category'])
            for run in q.run(limit=1000):
                old_game_model.num_pbs -= 1
                q2 = db.Query(runs.Runs)
                q2.ancestor(runs.key())
                q2.filter('game =', params['new_game'])
                q2.filter('category =', params['new_category'])
                q2.filter('username ='******'new_game_model'].num_pbs += 1
                else:
                    # Need to decrement runner's num_pbs
                    runner = self.get_runner(util.get_code(run.username))
                    if runner == self.OVER_QUOTA_ERROR:
                        return 'Over quota error'
                    runner.num_pbs -= 1
                    runner.put()
                    res += ("Updated " + run.username + " num_pbs from " +
                            str(runner.num_pbs + 1) + " to " +
                            str(runner.num_pbs) + "<br>")
        except apiproxy_errors.OverQuotaError, msg:
            logging.error(msg)
            return "Ran out of quota"
Ejemplo n.º 44
0
    def post(self, run_id):
        user = self.get_user()
        if not user:
            self.redirect("/")
            return

        # Get the run
        run = runs.Runs.get_by_id(long(run_id), parent=runs.key())
        if (not run or (not user.is_mod and run.username != user.username)):
            self.error(404)
            self.render("404.html", user=user)
            return

        # Grab the owner of the run
        if run.username == user.username:
            runner = user
        else:
            runner = self.get_runner(util.get_code(run.username))

        # Delete the run
        run.delete()

        # Update memcache
        old_run = dict(game=run.game,
                       category=run.category,
                       seconds=run.seconds)
        self.update_cache_run_by_id(run_id, None)

        # Update games, runner
        delta_num_pbs = 0
        num_runs = self.num_runs(runner.username, run.game, run.category, 1)
        if num_runs == 0:
            delta_num_pbs = -1
        self.update_runner(runner, delta_num_pbs)
        self.update_games_delete(
            self.get_game_model(util.get_code(old_run['game'])), delta_num_pbs)

        # Must update runinfo before pblist and gamepage because pblist and
        # gamepage rely on accurate runinfo
        self.update_runinfo_delete(runner, old_run)
        self.update_pblist_delete(runner, old_run)
        self.update_gamepage_delete(runner, old_run)
        self.update_user_has_run_delete(runner, old_run)
        if num_runs <= 0:
            self.update_gamelist_delete(old_run)
            self.update_runnerlist_delete(runner)

        # Update runlist for runner in memcache
        runlist = self.get_runlist_for_runner(runner.username, no_refresh=True)
        if runlist:
            for i, run in enumerate(runlist):
                if run['run_id'] == run_id:
                    del runlist[i]
                    self.update_cache_runlist_for_runner(
                        runner.username, runlist)
                    break

        # Update last run
        last_run = self.get_last_run(runner.username, no_refresh=True)
        if last_run is not None and last_run.key().id() == long(run_id):
            self.update_cache_last_run(runner.username, None)

        # Done with deletion
        self.redirect("/runner/" + util.get_code(runner.username) +
                      "?q=view-all")
Ejemplo n.º 45
0
    def get_gamepage( self, game, category, page_num ):
        if category is None:
            return dict( has_next=False, page_num=0, d=None )

        category_code = util.get_code( category )
        key = self.get_gamepage_memkey( game, category_code )
        cached_gamepages = memcache.get( key )
        if cached_gamepages is None:
            cached_gamepages = dict( )
        gamepage = cached_gamepages.get( page_num )
        if gamepage is None:
            # Not in memcache, so construct the gamepage and store it in 
            # memcache.
            # gamepage['d'] has up to 7 keys:
            # 'category', 'category_code', 'bk_runner', 'bk_time',
            # 'bk_date', 'bk_video' and 'infolist'.
            gamepage = dict( page_num=page_num,
                             has_next=True )
            d = dict( category=category,
                      category_code=category_code,
                      infolist=[ ] )

            # 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 dict( has_next=False, page_num=0, d=None )
            if game_model == self.OVER_QUOTA_ERROR:
                return self.OVER_QUOTA_ERROR
            gameinfolist = json.loads( game_model.info )

            # Check for a best known time for this category
            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
            try:
                # Get 1 run per username
                q = db.Query( runs.Runs,
                              projection=['username', 'seconds',
                                          'date', 'video', 'version'] )
                q.ancestor( runs.key() )
                q.filter( 'game =', game )
                q.filter( 'category =', category )
                q.order( 'seconds' )
                q.order( 'date' )
                usernames_seen = set( )
                cached_cursor = memcache.get( self.get_gamepage_cursor_memkey(
                    game, category_code, page_num ) )
                if cached_cursor:
                    try:
                        q.with_cursor( start_cursor=cached_cursor['c'] )
                        usernames_seen = cached_cursor['usernames_seen']
                    except BadRequestError:
                        gamepage['page_num'] = page_num
                else:
                    gamepage['page_num'] = 1
                num_runs = 0
                for run in q.run( limit = self.GAMEPAGE_PAGE_LIMIT ):
                    num_runs += 1
                    if run.username in usernames_seen:
                        continue
                    # Add the info to the gamepage
                    info = dict( username = run.username,
                                 username_code = util.get_code(
                                     run.username ),
                                 category = category,
                                 category_code = category_code,
                                 pb_seconds = run.seconds,
                                 pb_time = util.seconds_to_timestr(
                                     run.seconds ),
                                 pb_date = run.date,
                                 video = run.video,
                                 version = run.version )
                    d['infolist'].append( info )
                    usernames_seen.add( run.username )
                if num_runs < self.GAMEPAGE_PAGE_LIMIT:
                    gamepage['has_next'] = False
                else:
                    c = q.cursor( )
                    cached_cursor = dict( c=c, usernames_seen=usernames_seen )
                    cursor_key = self.get_gamepage_cursor_memkey(
                        game, category_code, gamepage['page_num'] + 1 )
                    if memcache.set( cursor_key, cached_cursor ):
                        logging.debug( "Set " + cursor_key + " in memcache" )
                    else:
                        logging.warning( "Failed to set new " + cursor_key
                                         + " in memcache" )
            except apiproxy_errors.OverQuotaError, msg:
                logging.error( msg )
                return self.OVER_QUOTA_ERROR

            gamepage['d'] = d
            cached_gamepages[ gamepage['page_num'] ] = gamepage
            if memcache.set( key, cached_gamepages ):
                logging.debug( "Set " + key + " in memcache" )
            else:
                logging.warning( "Failed to set " + key + " in memcache" )
Ejemplo n.º 46
0
class ChangeCategories(runhandler.RunHandler):
    def get(self):
        # Get the user
        user = self.get_user()
        if not user:
            self.redirect("/")
            return
        elif user == self.OVER_QUOTA_ERROR:
            self.error(403)
            self.render("403.html")
            return

        # Make sure user is a mod
        if not user.is_mod:
            self.error(404)
            self.render("404.html", user=user)
            return

        params = dict(user=user, categories=self.get_categories())
        if params['categories'] == self.OVER_QUOTA_ERROR:
            self.error(403)
            self.render("403.html", user=user)
            return

        self.render("change_categories.html", **params)

    def post(self):
        # Get the user
        user = self.get_user()
        if not user:
            self.redirect("/")
            return
        elif user == self.OVER_QUOTA_ERROR:
            self.error(403)
            self.render("403.html")
            return

        # Make sure user is a mod
        if not user.is_mod:
            self.error(404)
            self.render("404.html", user=user)
            return

        old_game = self.request.get('old-game')
        old_category = self.request.get('old-category')
        new_game = self.request.get('new-game')
        new_category = self.request.get('new-category')

        params = dict(user=user,
                      old_game=old_game,
                      old_category=old_category,
                      new_game=new_game,
                      new_category=new_category)

        valid = True

        # Make sure the new game doesn't already exist under a similar name
        new_game_code = util.get_code(new_game)
        new_game_model = self.get_game_model(new_game_code)
        if not new_game_code:
            params['new_game_error'] = "New game cannot be blank"
            valid = False
        if new_game_model == self.OVER_QUOTA_ERROR:
            self.error(403)
            self.render("403.html", user=user)
            return
        elif new_game_model is not None and new_game != new_game_model.game:
            params['new_game_error'] = ("New game already exists under [" +
                                        new_game_model.game +
                                        "] (case sensitive)." +
                                        " Hit submit again to confirm.")
            params['new_game'] = new_game_model.game
            valid = False
        elif not games.valid_game_or_category(new_game):
            params['new_game_error'] = ("Game name must not use any 'funny'" +
                                        " characters and can be up to 100 " +
                                        "characters long")
            valid = False
        params['new_game_code'] = new_game_code
        params['new_game_model'] = new_game_model

        # Make sure the category doesn't already exist under a similar name
        new_category_code = util.get_code(new_category)
        new_category_found = False
        if not new_category_code:
            params['new_category_error'] = "Category cannot be blank"
            valid = False
        elif new_game_model is not None:
            infolist = json.loads(new_game_model.info)
            for info in infolist:
                if new_category_code == util.get_code(info['category']):
                    new_category_found = True
                    if new_category != info['category']:
                        params['new_category_error'] = (
                            "Category already exists " + "under [" +
                            info['category'] + "] " + "(case sensitive). " +
                            "Hit submit again to " + "confirm.")
                        params['new_category'] = info['category']
                        valid = False
                    break
        if (not new_category_found
                and not games.valid_game_or_category(new_category)):
            params['new_category_error'] = (
                "Category must not use any 'funny'" +
                " characters and can be up to 100 " + "characters long")
            valid = False
        params['new_category_found'] = new_category_found

        if not valid:
            self.render("change_categories.html", **params)
            return

        changes = self.change_categories(params)

        logging.info(changes)

        # Render changes
        self.write(changes)

    @db.transactional(xg=True)
    def change_categories(self, params):
        res = ''

        # Grab the old game model
        old_game_code = util.get_code(params['old_game'])
        if old_game_code == params['new_game_code']:
            old_game_model = params['new_game_model']
        else:
            old_game_model = self.get_game_model(old_game_code)
        if old_game_model == self.OVER_QUOTA_ERROR:
            self.error(403)
            self.render("403.html")
            return
        if old_game_model is None:
            return "Did not find game [" + params['old_game'] + "]"

        if params['new_game_model'] is None:
            # New game does not exist, so create it
            params['new_game_model'] = games.Games(
                game=params['new_game'],
                info=json.dumps([]),
                num_pbs=0,
                parent=games.key(),
                key_name=params['new_game_code'])
            res += ('Created new game model for game [' + params['new_game'] +
                    ']<br>')

        if not params['new_category_found']:
            # Add the new category to the new game model
            gameinfolist = json.loads(params['new_game_model'].info)
            d = dict(category=params['new_category'],
                     bk_runner=None,
                     bk_seconds=None,
                     bk_video=None,
                     bk_datestr=None,
                     bk_updater=None)
            gameinfolist.append(d)
            params['new_game_model'].info = json.dumps(gameinfolist)
            res += 'Added new category [' + params['new_category'] + ']<br>'

        # Grab the gameinfo for the old game
        oldgameinfolist = json.loads(old_game_model.info)
        oldgameinfo = None
        for g in oldgameinfolist:
            if (util.get_code(params['old_category']) == util.get_code(
                    g['category'])):
                oldgameinfo = g
                break
        if oldgameinfo is None:
            return "Did not find old category [" + params['old_category'] + ']'

        # Grab the gameinfo for the new game
        newgameinfolist = json.loads(params['new_game_model'].info)
        newgameinfo = None
        for g in newgameinfolist:
            if (util.get_code(params['new_category']) == util.get_code(
                    g['category'])):
                newgameinfo = g
                break
        if newgameinfo is None:
            return "Did not find new category [" + params['new_category'] + ']'

        # Update best known time if necessary
        if (oldgameinfo.get('bk_seconds') is not None and
            (newgameinfo.get('bk_seconds') is None or
             oldgameinfo.get('bk_seconds') < newgameinfo.get('bk_seconds'))):
            newgameinfo['bk_seconds'] = oldgameinfo.get('bk_seconds')
            newgameinfo['bk_runner'] = oldgameinfo.get('bk_runner')
            newgameinfo['bk_datestr'] = oldgameinfo.get('bk_datestr')
            newgameinfo['bk_video'] = oldgameinfo.get('bk_video')
            newgameinfo['bk_updater'] = oldgameinfo.get('bk_updater')
            params['new_game_model'].info = json.dumps(newgameinfolist)
            res += 'Updated bkt<br>'

        if not memcache.flush_all():
            res += "Failed to flush memcache<br>"

        # Update num_pbs for old game, new game
        res += ('Previous num_pbs for old game, category = ' +
                str(old_game_model.num_pbs) + '<br>')
        res += ('Previous num_pbs for new game, category = ' +
                str(params['new_game_model'].num_pbs) + '<br>')
        try:
            q = db.Query(runs.Runs, projection=['username'], distinct=True)
            q.ancestor(runs.key())
            q.filter('game =', params['old_game'])
            q.filter('category =', params['old_category'])
            for run in q.run(limit=1000):
                old_game_model.num_pbs -= 1
                q2 = db.Query(runs.Runs)
                q2.ancestor(runs.key())
                q2.filter('game =', params['new_game'])
                q2.filter('category =', params['new_category'])
                q2.filter('username ='******'new_game_model'].num_pbs += 1
                else:
                    # Need to decrement runner's num_pbs
                    runner = self.get_runner(util.get_code(run.username))
                    if runner == self.OVER_QUOTA_ERROR:
                        return 'Over quota error'
                    runner.num_pbs -= 1
                    runner.put()
                    res += ("Updated " + run.username + " num_pbs from " +
                            str(runner.num_pbs + 1) + " to " +
                            str(runner.num_pbs) + "<br>")
        except apiproxy_errors.OverQuotaError, msg:
            logging.error(msg)
            return "Ran out of quota"

        res += ('Updated num_pbs for old game, category = ' +
                str(old_game_model.num_pbs) + '<br>')
        res += ('Updated num_pbs for new game, category = ' +
                str(params['new_game_model'].num_pbs) + '<br>')

        # Update old, new game models in database
        old_game_model.put()
        if old_game_code != params['new_game_code']:
            params['new_game_model'].put()

        # Change the runs
        res += "<br>Changed runs:<br>"
        try:
            q = db.Query(runs.Runs)
            q.ancestor(runs.key())
            q.filter('game =', params['old_game'])
            q.filter('category =', params['old_category'])
            for run in q.run(limit=10000):
                # Update the run
                run.game = params['new_game']
                run.category = params['new_category']
                run.put()
                res += ('Runner=' + run.username + ' time=' +
                        util.seconds_to_timestr(run.seconds) + '<br>')
        except apiproxy_errors.OverQuotaError, msg:
            logging.error(msg)
            return "Ran out of quota when changing runs"
Ejemplo n.º 47
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")
Ejemplo n.º 48
0
    def post( self, run_id ):
        user = self.get_user( )
        if not user:
            self.redirect( "/" )
            return
        elif user == self.OVER_QUOTA_ERROR:
            self.error( 403 )
            self.render( "403.html" )
            return

        # Get the run
        run = runs.Runs.get_by_id( long( run_id ), parent=runs.key() )
        if( not run or 
            ( not user.is_mod and run.username != user.username ) ):
            self.error( 404 ) 
            self.render( "404.html", user=user )
            return

        # Grab the owner of the run
        if run.username == user.username:
            runner = user
        else:
            runner = self.get_runner( util.get_code( run.username ) )
            if runner == self.OVER_QUOTA_ERROR:
                self.error( 403 )
                self.render( "403.html", user=user )
                return

        # Delete the run
        run.delete( )

        # Update memcache
        old_run = dict( game = run.game, category = run.category,
                        seconds = run.seconds )
        self.update_cache_run_by_id( run_id, None )

        # Update games, runner
        delta_num_pbs = 0
        num_runs = self.num_runs( runner.username, run.game, run.category, 1 )
        if num_runs == 0:
            delta_num_pbs = -1
        self.update_runner( runner, delta_num_pbs )
        game_model = self.get_game_model( util.get_code( old_run['game'] ) )
        if game_model == self.OVER_QUOTA_ERROR:
            self.error( 403 )
            self.render( "403.html", user=user )
            return
        self.update_games_delete( game_model, run.category, delta_num_pbs )

        self.update_pblist_delete( runner, old_run )
        self.update_gamepage_delete( runner, old_run )
        self.update_user_has_run_delete( runner, old_run )
        if num_runs <= 0:
            self.update_gamelist_delete( old_run )
            self.update_runnerlist_delete( runner )

        # Update 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 i, run in enumerate( res['runlist'] ):
                    if run[ 'run_id' ] == run_id:
                        del cached_runlists[ page_num ]['runlist'][ i ]
                        self.update_cache_runlist_for_runner( runner.username,
                                                              cached_runlists )
                        found_run = True
                        break

        # Update last run
        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 last_run.key( ).id( ) == long( run_id ):
            self.update_cache_last_run( runner.username, None )

        # Done with deletion
        self.redirect( "/runner/" + util.get_code( runner.username )
                       + "?q=view-all" )
Ejemplo n.º 49
0
    def change_categories( self, params ):
        res = ''

        # Grab the old game model
        old_game_code = util.get_code( params['old_game'] )
        if old_game_code == params['new_game_code']:
            old_game_model = params['new_game_model']
        else:
            old_game_model = self.get_game_model( old_game_code )
        if old_game_model is None:
            return "Did not find game [" + params['old_game'] + "]"

        if params['new_game_model'] is None:
            # New game does not exist, so create it
            params['new_game_model'] = games.Games( 
                game = params['new_game'],
                info = json.dumps( [ ] ),
                num_pbs = 0,
                parent = games.key( ),
                key_name = params['new_game_code'] )
            res += ( 'Created new game model for game [' + params['new_game'] 
                     + ']<br>' )
        
        if not params['new_category_found']:
            # Add the new category to the new game model
            gameinfolist = json.loads( params['new_game_model'].info )
            d = dict( category=params['new_category'], 
                      bk_runner=None,
                      bk_seconds=None,
                      bk_video=None,
                      bk_datestr=None,
                      bk_updater=None )
            gameinfolist.append( d )
            params['new_game_model'].info = json.dumps( gameinfolist )
            res += 'Added new category [' + params['new_category'] + ']<br>'

        # Grab the gameinfo for the old game
        oldgameinfolist = json.loads( old_game_model.info )
        oldgameinfo = None
        for g in oldgameinfolist:
            if( util.get_code( params['old_category'] ) == util.get_code( 
                    g['category'] ) ):
                oldgameinfo = g
                break
        if oldgameinfo is None:
            return "Did not find old category [" + params['old_category'] + ']'

        # Grab the gameinfo for the new game
        newgameinfolist = json.loads( params['new_game_model'].info )
        newgameinfo = None
        for g in newgameinfolist:
            if( util.get_code( params['new_category'] ) == util.get_code( 
                    g['category'] ) ):
                newgameinfo = g
                break
        if newgameinfo is None:
            return "Did not find new category [" + params['new_category'] + ']'

        # Update best known time if necessary
        if( oldgameinfo.get( 'bk_seconds' ) is not None
            and ( newgameinfo.get( 'bk_seconds' ) is None 
                  or oldgameinfo.get( 'bk_seconds' ) 
                  < newgameinfo.get( 'bk_seconds' ) ) ):
            newgameinfo['bk_seconds'] = oldgameinfo.get( 'bk_seconds' )
            newgameinfo['bk_runner'] = oldgameinfo.get( 'bk_runner' )
            newgameinfo['bk_datestr'] = oldgameinfo.get( 'bk_datestr' )
            newgameinfo['bk_video'] = oldgameinfo.get( 'bk_video' )
            newgameinfo['bk_updater'] = oldgameinfo.get( 'bk_updater' )
            params['new_game_model'].info = json.dumps( newgameinfolist )
            res += 'Updated bkt<br>'

        # Update num_pbs for old game, new game
        res += ( 'Previous num_pbs for old game, category = ' 
                 + str( old_game_model.num_pbs ) + '<br>' )
        res += ( 'Previous num_pbs for new game, category = ' 
                 + str( params['new_game_model'].num_pbs ) + '<br>' )
        q = db.Query( runs.Runs, projection=['username'], distinct=True )
        q.ancestor( runs.key() )
        q.filter( 'game =', params['old_game'] )
        q.filter( 'category =', params['old_category'] )
        for run in q.run( limit=1000 ):
            old_game_model.num_pbs -= 1
            q2 = db.Query( runs.Runs )
            q2.ancestor( runs.key() )
            q2.filter( 'game =', params['new_game'] )
            q2.filter( 'category =', params['new_category'] )
            q2.filter( 'username ='******'new_game_model'].num_pbs += 1
            else:
                # Need to decrement runner's num_pbs
                runner = self.get_runner( util.get_code( run.username ) )
                runner.num_pbs -= 1
                runner.put( )
                res += ( "Updated " + run.username + " num_pbs from "
                         + str( runner.num_pbs + 1 ) + " to " 
                         + str( runner.num_pbs ) + "<br>" )
                
        res += ( 'Updated num_pbs for old game, category = ' 
                 + str( old_game_model.num_pbs ) + '<br>' )
        res += ( 'Updated num_pbs for new game, category = ' 
                 + str( params['new_game_model'].num_pbs ) + '<br>' )

        # Update old, new game models in database
        old_game_model.put( )
        if old_game_code != params['new_game_code']:
            params['new_game_model'].put( )

        # Change the runs
        res += "<br>Changed runs:<br>"
        q = db.Query( runs.Runs )
        q.ancestor( runs.key() )
        q.filter( 'game =', params['old_game'] )
        q.filter( 'category =', params['old_category'] )
        for run in q.run( limit = 10000 ):
            # Update the run
            run.game = params['new_game']
            run.category = params['new_category']
            run.put( )
            res += ( 'Runner=' + run.username + ' time=' 
                     + util.seconds_to_timestr( run.seconds ) + '<br>' )

        if not memcache.flush_all( ):
            res += "Failed to flush memcache<br>"

        # All dun
        return res