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

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

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

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

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

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

            if memcache.set(key, gamepage):
                logging.debug("Set " + key + " in memcache")
            else:
                logging.warning("Failed to set " + key + " in memcache")
        elif gamepage is not None:
            logging.debug("Got " + key + " from memcache")
        return gamepage
Beispiel #2
0
    def update_gamepage_put( self, params ):
        user = params[ 'user' ]
        game = params[ 'game' ]
        category = params[ 'category' ]
        seconds = params[ 'seconds' ]
        time = params[ 'time' ]
        date = params[ 'date' ]
        video = params[ 'video' ]
        is_bkt = params[ 'is_bkt' ]

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

        for d in gamepage:
            if d[ 'category' ] == category:
                if is_bkt:
                    # Update best known time for this category
                    d['bk_runner'] = user.username
                    d['bk_time'] = util.seconds_to_timestr( seconds )
                    d['bk_date'] = date
                    d['bk_video'] = video
                for i, runinfo in enumerate( d['infolist'] ):
                    if runinfo['username'] == user.username:
                        # User has run this category before
                        d['infolist'][i] = self.get_runinfo( user.username, 
                                                             game, category )
                        d['infolist'].sort( key=lambda x: util.get_valid_date(
                                x['pb_date'] ) )
                        d['infolist'].sort( key=itemgetter('pb_seconds') )
                        self.update_cache_gamepage( game, gamepage )
                        return
                
                # Category found, but user has not prev. run this category
                runinfo = self.get_runinfo( user.username, game, category )
                d['infolist'].append( runinfo )
                d['infolist'].sort( key=lambda x: util.get_valid_date(
                        x['pb_date'] ) )                
                d['infolist'].sort( key=itemgetter('pb_seconds') )
                gamepage.sort( key=lambda x: len(x['infolist']), reverse=True )
                self.update_cache_gamepage( game, gamepage )
                return
        
        # This is a new category for this game
        runinfo = self.get_runinfo( user.username, game, category )
        d = dict( category=category, 
                  category_code=util.get_code( category ),
                  infolist=[runinfo] )
        # Check for best known time. Since we update games.Games before 
        # updating gamepage, this will catch the case for when is_bkt is true.
        game_model = self.get_game_model( util.get_code( game ) )
        if game_model is None:
            logging.error( "Failed to update gamepage for " + game )
            self.update_cache_gamepage( game, None )
            return
        gameinfolist = json.loads( game_model.info )
        for gameinfo in gameinfolist:
            if gameinfo['category'] == category:
                d['bk_runner'] = gameinfo.get( 'bk_runner' )
                d['bk_time'] = util.seconds_to_timestr( 
                        gameinfo.get( 'bk_seconds' ) )
                d['bk_date'] = util.datestr_to_date( 
                    gameinfo.get( 'bk_datestr' ) )[ 0 ]
                d['bk_video'] = gameinfo.get( 'bk_video' )
                break
        gamepage.append( d )
        self.update_cache_gamepage( game, gamepage )
Beispiel #3
0
    def post( self ):
        user = self.get_user( )
        if not user:
            self.redirect( "/" )
            return

        game = self.request.get( 'game' )
        category = self.request.get( 'category' )
        time = self.request.get( 'time' )
        datestr = self.request.get( 'date' )
        video = self.request.get( 'video' )
        version = self.request.get( 'version' )
        notes = self.request.get( 'notes' )
        is_bkt = self.request.get( 'bkt', default_value="no" )
        if is_bkt == "yes":
            is_bkt = True
        else:
            is_bkt = False
        run_id = self.request.get( 'edit' )

        params = dict( user = user, game = game, category = category, 
                       time = time, datestr = datestr, video = video, 
                       version = version, notes = notes, run_id = run_id, 
                       is_bkt = is_bkt )

        valid = True

        # Make sure the game doesn't already exist under a similar name
        game_code = util.get_code( game )
        game_model = self.get_game_model( game_code )
        if not game_code:
            params['game_error'] = "Game cannot be blank"
            valid = False
        elif game_model is not None and game != game_model.game:
            params['game_error'] = ( "Game already exists under [" 
                                     + game_model.game + "] (case sensitive)."
                                     + " Hit submit again to confirm." )
            params['game'] = game_model.game
            valid = False
        elif not valid_game_or_category( game ):
            params['game_error'] = ( "Game name must not use any 'funny'"
                                     + " characters and can be up to 100 "
                                     + "characters long" )
            valid = False
        params[ 'game_code' ] = game_code
        params[ 'game_model' ] = game_model

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

        # Parse the time into seconds, ensure it is valid
        ( seconds, time_error ) = util.timestr_to_seconds( time )
        if seconds is None:
            params['time_error'] = "Invalid time: " + time_error
            params['seconds'] = -1
            valid = False
        else:
            time = util.seconds_to_timestr( seconds ) # Enforce standard form
            params[ 'time' ] = time
            params[ 'seconds' ] = seconds

        # Parse the date, ensure it is valid
        ( params['date'], params['date_error'] ) = util.datestr_to_date( 
            datestr )
        if params['date_error']:
            params['date_error'] = "Invalid date: " + params['date_error']
            valid = False
                
        # Check that if this is a best known time, that it beats the old
        # best known time
        if is_bkt and game_model is not None:
            gameinfolist = json.loads( game_model.info )
            for gameinfo in gameinfolist:
                if gameinfo['category'] == params['category']:
                    if( gameinfo.get( 'bk_seconds' ) is not None
                        and gameinfo['bk_seconds'] <= seconds ):
                        s = ( "This time does not beat current best known "
                              + "time of " + util.seconds_to_timestr( 
                                  gameinfo.get( 'bk_seconds' ) ) 
                              + " by " + gameinfo['bk_runner'] 
                              + " (if best known time is incorrect, you can "
                              + "update best known time after submission)" )
                        params['bkt_error'] = s
                        params['is_bkt'] = False
                        valid = False
                    break

        # Make sure that the notes are not too long
        if len( notes ) > 140:
            params['notes_error'] = "Notes must be at most 140 characters"
            valid = False

        params['valid'] = valid
        
        if run_id:
            success = self.put_existing_run( params )
        else:
            success = self.put_new_run( params )
        if success:
            self.redirect( "/runner/" + util.get_code( user.username )
                           + "?q=view-all" )
        else:
            # Grab all of the games for autocompleting
            params['categories'] = self.get_categories( )            
            params['user'] = user
            self.render( "submit.html", **params )
Beispiel #4
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")
Beispiel #5
0
    def post(self):
        user = self.get_user()
        if not user:
            self.redirect("/")
            return

        game = self.request.get('game')
        category = self.request.get('category')
        time = self.request.get('time')
        datestr = self.request.get('date')
        video = self.request.get('video')
        version = self.request.get('version')
        notes = self.request.get('notes')
        is_bkt = self.request.get('bkt', default_value="no")
        if is_bkt == "yes":
            is_bkt = True
        else:
            is_bkt = False
        run_id = self.request.get('edit')

        params = dict(user=user,
                      game=game,
                      category=category,
                      time=time,
                      datestr=datestr,
                      video=video,
                      version=version,
                      notes=notes,
                      run_id=run_id,
                      is_bkt=is_bkt)

        valid = True

        # Make sure the game doesn't already exist under a similar name
        game_code = util.get_code(game)
        game_model = self.get_game_model(game_code)
        if not game_code:
            params['game_error'] = "Game cannot be blank"
            valid = False
        elif game_model is not None and game != game_model.game:
            params['game_error'] = ("Game already exists under [" +
                                    game_model.game + "] (case sensitive)." +
                                    " Hit submit again to confirm.")
            params['game'] = game_model.game
            valid = False
        elif not games.valid_game_or_category(game):
            params['game_error'] = ("Game name must not use any 'funny'" +
                                    " characters and can be up to 100 " +
                                    "characters long")
            valid = False
        params['game_code'] = game_code
        params['game_model'] = game_model

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

        # Parse the time into seconds, ensure it is valid
        (seconds, time_error) = util.timestr_to_seconds(time)
        if seconds is None:
            params['time_error'] = "Invalid time: " + time_error
            params['seconds'] = -1
            valid = False
        else:
            time = util.seconds_to_timestr(seconds)  # Enforce standard form
            params['time'] = time
            params['seconds'] = seconds

        # Parse the date, ensure it is valid
        (params['date'], params['date_error']) = util.datestr_to_date(datestr)
        if params['date_error']:
            params['date_error'] = "Invalid date: " + params['date_error']
            valid = False

        # Check that if this is a best known time, then it beats the old
        # best known time.
        if is_bkt and game_model is not None:
            gameinfolist = json.loads(game_model.info)
            for gameinfo in gameinfolist:
                if gameinfo['category'] == params['category']:
                    if (gameinfo.get('bk_seconds') is not None
                            and gameinfo['bk_seconds'] <= seconds):
                        s = ("This time does not beat current best known " +
                             "time of " + util.seconds_to_timestr(
                                 gameinfo.get('bk_seconds')) + " by " +
                             gameinfo['bk_runner'] +
                             " (if best known time is incorrect, you can " +
                             "update best known time after submission)")
                        params['bkt_error'] = s
                        params['is_bkt'] = False
                        valid = False
                    break

        # Check that if this is not the best known time, then it doesn't beat
        # the old best known time
        if not is_bkt and game_model is not None:
            gameinfolist = json.loads(game_model.info)
            for gameinfo in gameinfolist:
                if gameinfo['category'] == params['category']:
                    if (gameinfo.get('bk_seconds') is not None
                            and seconds < gameinfo['bk_seconds']):
                        s = (
                            "This time beats the current best known time of " +
                            util.seconds_to_timestr(gameinfo.get('bk_seconds'))
                            + " by " + gameinfo['bk_runner'] +
                            " (if best known time is incorrect, you can " +
                            "update best known time after submission)")
                        params['bkt_error'] = s
                        params['is_bkt'] = True
                        valid = False
                    break

        # Make sure that the notes are not too long
        if len(notes) > 140:
            params['notes_error'] = "Notes must be at most 140 characters"
            valid = False

        params['valid'] = valid

        if run_id:
            success = self.put_existing_run(params)
        else:
            success = self.put_new_run(params)
        if success:
            self.redirect("/runner/" + util.get_code(user.username) +
                          "?q=view-all")
        else:
            # Grab all of the games for autocompleting
            params['categories'] = self.get_categories()
            params['user'] = user
            self.render("submit.html", **params)
Beispiel #6
0
    def update_gamepage_put(self, params):
        user = params['user']
        game = params['game']
        category = params['category']
        seconds = params['seconds']
        time = params['time']
        date = params['date']
        video = params['video']
        is_bkt = params['is_bkt']

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

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

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

        # This is a new category for this game
        runinfo = self.get_runinfo(user.username, game, category)
        if runinfo == self.OVER_QUOTA_ERROR:
            self.update_cache_gamepage(game, gamepage)
            return
        d = dict(category=category,
                 category_code=util.get_code(category),
                 infolist=[runinfo])
        # Check for best known time. Since we update games.Games before
        # updating gamepage, this will catch the case for when is_bkt is true.
        game_model = self.get_game_model(util.get_code(game))
        if game_model is None:
            logging.error("Failed to update gamepage for " + game)
            self.update_cache_gamepage(game, None)
            return
        if game_model == self.OVER_QUOTA_ERROR:
            self.update_cache_gamepage(game, None)
            return
        gameinfolist = json.loads(game_model.info)
        for gameinfo in gameinfolist:
            if gameinfo['category'] == category:
                d['bk_runner'] = gameinfo.get('bk_runner')
                d['bk_time'] = util.seconds_to_timestr(
                    gameinfo.get('bk_seconds'))
                d['bk_date'] = util.datestr_to_date(
                    gameinfo.get('bk_datestr'))[0]
                d['bk_video'] = gameinfo.get('bk_video')
                break
        gamepage.append(d)
        self.update_cache_gamepage(game, gamepage)
Beispiel #7
0
    def post( self, game_code ):
        user = self.get_user( )
        if user == self.OVER_QUOTA_ERROR:
            self.error( 403 )
            self.render( "403.html" )
            return
        return_url = self.request.get( 'from' )
        if not return_url:
            return_url = "/"

        # Get the category
        category_code = self.request.get( 'c' )
        if user is None or category_code is None:
            self.error( 404 )
            self.render( "404.html", user=user )
            return
        
        # Have to take the code of the category code because of percent
        # encoded plusses
        category_code = util.get_code( category_code )
        
        # Check to make sure that the user has run this game
        game_model = self.get_game_model( game_code )
        if game_model == self.OVER_QUOTA_ERROR:
            self.error( 403 )
            self.render( "403.html", user=user )
            return
        user_has_run = self.get_user_has_run( user.username, game_model.game )
        if user_has_run == self.OVER_QUOTA_ERROR:
            self.error( 403 )
            self.render( "403.html", user=user )
            return
        if not user_has_run and not user.is_mod:
            self.error( 404 )
            self.render( "404.html", user=user )
            return

        # Find the corresponding gameinfo for this category
        gameinfolist = json.loads( game_model.info )
        gameinfo = None
        for g in gameinfolist:
            if util.get_code( g['category'] ) == category_code:
                gameinfo = g
                break
        if gameinfo is None:
            self.error( 404 )
            self.render( "404.html", user=user )
            return

        # Get the inputs
        username = self.request.get( 'username' )
        time = self.request.get( 'time' )
        datestr = self.request.get( 'date' )
        video = self.request.get( 'video' )

        params = dict( user=user, game=game_model.game, game_code=game_code,
                       category=gameinfo['category'], username=username,
                       time=time, datestr=datestr, video=video, 
                       return_url=return_url )

        # Are we updating?
        if gameinfo.get( 'bk_runner' ) is None:
            params['updating'] = False
        else:
            params['updating'] = True

        valid = True

        # Check for where we came from
        if return_url[ 0 : len( '/runner/' ) ] == '/runner/':
            params['from_runnerpage'] = True
        else:
            params['from_runnerpage'] = False

        if not username and not time and not datestr and not video:
            gameinfo['bk_runner'] = None
            gameinfo['bk_seconds'] = None
            gameinfo['bk_datestr'] = None
            gameinfo['bk_video'] = None
            date = None
        else:
            # Make sure we got a username
            if not username:
                params['username_error'] = "You must enter a runner"
                valid = False

            # Parse the time into seconds, ensure it is valid
            ( seconds, time_error ) = util.timestr_to_seconds( time )
            if not seconds:
                params['time_error'] = "Invalid time: " + time_error
                valid = False

            # Parse the date, ensure it is valid
            ( date, date_error ) = util.datestr_to_date( datestr )
            if date_error:
                params['date_error'] = "Invalid date: " + date_error
                valid = False

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

            time = util.seconds_to_timestr( seconds ) # Standard format
            params['time'] = time

            # Store the best known time
            gameinfo['bk_runner'] = username
            gameinfo['bk_seconds'] = seconds
            gameinfo['bk_datestr'] = datestr
            gameinfo['bk_video'] = video

        gameinfo['bk_updater'] = user.username
        game_model.info = json.dumps( gameinfolist )
        game_model.put( )

        # Update game_model in memcache
        self.update_cache_game_model( game_code, game_model )

        # Update gamepage in memcache
        cached_gamepages = self.get_cached_gamepages( game_model.game,
                                                      category_code )
        if cached_gamepages is not None:
            for page_num, gamepage in cached_gamepages.iteritems( ):
                d = gamepage['d']
                d['bk_runner'] = gameinfo['bk_runner']
                d['bk_time'] = util.seconds_to_timestr(
                    gameinfo['bk_seconds'] )
                d['bk_date'] = date
                d['bk_video'] = gameinfo['bk_video']
            self.update_cache_gamepage( game_model.game, category_code,
                                        cached_gamepages )

        # All dun
        self.redirect( return_url )
Beispiel #8
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" )
Beispiel #9
0
    def post( self, game_code ):
        user = self.get_user( )
        if user == self.OVER_QUOTA_ERROR:
            self.error( 403 )
            self.render( "403.html" )
            return
        return_url = self.request.get( 'from' )
        if not return_url:
            return_url = "/"

        # Get the category
        category_code = self.request.get( 'c' )
        if user is None or category_code is None:
            self.error( 404 )
            self.render( "404.html", user=user )
            return
        
        # Have to take the code of the category code because of percent
        # encoded plusses
        category_code = util.get_code( category_code )
        
        # Check to make sure that the user has run this game
        game_model = self.get_game_model( game_code )
        if game_model == self.OVER_QUOTA_ERROR:
            self.error( 403 )
            self.render( "403.html", user=user )
            return
        user_has_run = self.get_user_has_run( user.username, game_model.game )
        if user_has_run == self.OVER_QUOTA_ERROR:
            self.error( 403 )
            self.render( "403.html", user=user )
            return
        if not user_has_run and not user.is_mod:
            self.error( 404 )
            self.render( "404.html", user=user )
            return

        # Find the corresponding gameinfo for this category
        gameinfolist = json.loads( game_model.info )
        gameinfo = None
        for g in gameinfolist:
            if util.get_code( g['category'] ) == category_code:
                gameinfo = g
                break
        if gameinfo is None:
            self.error( 404 )
            self.render( "404.html", user=user )
            return

        # Get the inputs
        username = self.request.get( 'username' )
        time = self.request.get( 'time' )
        datestr = self.request.get( 'date' )
        video = self.request.get( 'video' )

        params = dict( user=user, game=game_model.game, game_code=game_code,
                       category=gameinfo['category'], username=username,
                       time=time, datestr=datestr, video=video, 
                       return_url=return_url )

        # Are we updating?
        if gameinfo.get( 'bk_runner' ) is None:
            params['updating'] = False
        else:
            params['updating'] = True

        valid = True

        # Check for where we came from
        if return_url[ 0 : len( '/runner/' ) ] == '/runner/':
            params['from_runnerpage'] = True
        else:
            params['from_runnerpage'] = False

        if not username and not time and not datestr and not video:
            gameinfo['bk_runner'] = None
            gameinfo['bk_seconds'] = None
            gameinfo['bk_datestr'] = None
            gameinfo['bk_video'] = None
            date = None
        else:
            # Make sure we got a username
            if not username:
                params['username_error'] = "You must enter a runner"
                valid = False

            # Parse the time into seconds, ensure it is valid
            ( seconds, time_error ) = util.timestr_to_seconds( time )
            if not seconds:
                params['time_error'] = "Invalid time: " + time_error
                valid = False

            # Parse the date, ensure it is valid
            ( date, date_error ) = util.datestr_to_date( datestr )
            if date_error:
                params['date_error'] = "Invalid date: " + date_error
                valid = False

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

            time = util.seconds_to_timestr( seconds ) # Standard format
            params['time'] = time

            # Store the best known time
            gameinfo['bk_runner'] = username
            gameinfo['bk_seconds'] = seconds
            gameinfo['bk_datestr'] = datestr
            gameinfo['bk_video'] = video

        gameinfo['bk_updater'] = user.username
        game_model.info = json.dumps( gameinfolist )
        game_model.put( )

        # Update game_model in memcache
        self.update_cache_game_model( game_code, game_model )

        # Update gamepage in memcache
        gamepage = self.get_gamepage( game_model.game, no_refresh=True )
        if gamepage == self.OVER_QUOTA_ERROR:
            self.update_cache_gamepage( game, None )
        elif gamepage is not None:
            for d in gamepage:
                if d['category'] == gameinfo['category']:
                    d['bk_runner'] = gameinfo['bk_runner']
                    d['bk_time'] = util.seconds_to_timestr( 
                        gameinfo['bk_seconds'] )
                    d['bk_date'] = date
                    d['bk_video'] = gameinfo['bk_video']
                    break
            self.update_cache_gamepage( game_model.game, gamepage )

        # All dun
        self.redirect( return_url )
Beispiel #10
0
    def post( self, game_code ):
        user = self.get_user( )
        if not user:
            self.redirect( "/" )
            return
        elif user == self.OVER_QUOTA_ERROR:
            self.error( 403 )
            self.render( "403.html" )
            return

        category = self.request.get( 'category' )
        time = self.request.get( 'time' )
        datestr = self.request.get( 'date' )
        video = self.request.get( 'video' )
        version = self.request.get( 'version' )
        notes = self.request.get( 'notes' )
        is_bkt = self.request.get( 'bkt', default_value="no" )
        if is_bkt == "yes":
            is_bkt = True
        else:
            is_bkt = False
        run_id = self.request.get( 'edit' )

        # Have to take the code of the game code because of percent
        # encoded plusses
        game_code = util.get_code( game_code )

        params = dict( user = user, game_code = game_code,
                       category = category, 
                       time = time, datestr = datestr, video = video, 
                       version = version, notes = notes, run_id = run_id, 
                       is_bkt = is_bkt )

        valid = True

        # Make sure the game already exists
        game_model = self.get_game_model( game_code )
        game = ''
        if not game_code:
            params['game_error'] = "Game cannot be blank"
            valid = False
        elif game_model is None:
            params['game_error'] = ( "That's weird, we could not find any "
                                     + "records for that game" )
            valid = False
        elif game_model == self.OVER_QUOTA_ERROR:
            params['game_error'] = ( "PB Tracker is currently over its quota"
                                     + " limit for the day. Please try again "
                                     + "tomorrow." )
            valid = False
        else:
            game = game_model.game
        params[ 'game' ] = game
        params[ 'game_model' ] = game_model

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

        # Parse the time into seconds, ensure it is valid
        ( seconds, time_error ) = util.timestr_to_seconds( time )
        if seconds is None:
            params['time_error'] = "Invalid time: " + time_error
            params['seconds'] = -1
            valid = False
        else:
            time = util.seconds_to_timestr( seconds ) # Enforce standard form
            params[ 'time' ] = time
            params[ 'seconds' ] = seconds

        # Parse the date, ensure it is valid
        ( params['date'], params['date_error'] ) = util.datestr_to_date( 
            datestr )
        if params['date_error']:
            params['date_error'] = "Invalid date: " + params['date_error']
            valid = False
                
        # Check that if this is a best known time, then it beats the old
        # best known time.
        if is_bkt and game_model is not None:
            gameinfolist = json.loads( game_model.info )
            for gameinfo in gameinfolist:
                if gameinfo['category'] == params['category']:
                    if( gameinfo.get( 'bk_seconds' ) is not None
                        and gameinfo['bk_seconds'] <= seconds ):
                        s = ( "This time does not beat current best known "
                              + "time of " + util.seconds_to_timestr( 
                                  gameinfo.get( 'bk_seconds' ) ) 
                              + " by " + gameinfo['bk_runner'] 
                              + " (if best known time is incorrect, you can "
                              + "update best known time after submission)" )
                        params['bkt_error'] = s
                        params['is_bkt'] = False
                        valid = False
                    break
                
        # Check that if this is not the best known time, then it doesn't beat
        # the old best known time
        if not is_bkt and game_model is not None:
            gameinfolist = json.loads( game_model.info )
            for gameinfo in gameinfolist:
                if gameinfo['category'] == params['category']:
                    if( gameinfo.get( 'bk_seconds' ) is not None
                        and seconds < gameinfo['bk_seconds'] ):
                        s = ( "This time beats the current best known time of "
                              + util.seconds_to_timestr( 
                                gameinfo.get( 'bk_seconds' ) )
                              + " by " + gameinfo['bk_runner']
                              + " (if best known time is incorrect, you can "
                              + "update best known time after submission)" )
                        params['bkt_error'] = s
                        params['is_bkt'] = True
                        valid = False
                    break

        # Make sure that the notes are not too long
        if len( notes ) > 140:
            params['notes_error'] = "Notes must be at most 140 characters"
            valid = False

        params['valid'] = valid
        
        if run_id:
            success = self.put_existing_run( params )
        else:
            success = self.put_new_run( params )
        if success:
            self.redirect( "/runner/" + util.get_code( user.username )
                           + "?q=view-all" )
        elif game_model is not None:
            try:
                # Grab all of the categories for autocompleting
                params['categories'] = game_model.categories( )
                params['user'] = user
                self.render( "submit.html", **params )
            except DeadlineExceededError, msg:
                logging.error( msg )
                self.error( 403 )
                self.render( "deadline_exceeded.html", user=user )