def post(self): logging.info("[TASK] UserUpdateFirebaseHandler") key_id = self.request.get('key_id') user = UsersController().get_by_key_id(int(key_id)) if not user: logging.error('User not found') return user_json = json.dumps(user.to_json() ) credentials = GoogleCredentials.get_application_default().create_scoped(_FIREBASE_SCOPES) http_auth = credentials.authorize(Http()) headers = {"Content-Type": "application/json"} URL = "%s/users/%s.json" % (FIREBASE_DATABASE_ROOT, user.firebaseUser) resp, content = http_auth.request(URL, "PUT", ##"PUT", ## Write or replace data to a defined path, user_json, headers=headers) logging.info(resp) logging.info(content)
def create(self, request): # Verify Firebase auth. #claims = firebase_helper.verify_auth_token(self.request_state) id_token = self.request_state.headers['x-metagame-auth'].split( ' ').pop() claims = google.oauth2.id_token.verify_firebase_token( id_token, HTTP_REQUEST) if not claims: ## TODO make this more modular, somehow. We have no idea who this user is at this point, so can't write to the firebase user record. logging.error('Firebase Unauth') response = RegionResponse(response_message='Firebase Unauth.', response_successful=False) return response authorized_user = UsersController().get_by_firebaseUser( claims['user_id']) if not authorized_user: logging.info('no user record found') return SeasonResponse( response_message='Error: No User Record Found. ', response_successful=False) if not authorized_user.admin: logging.info('no admin record found') return SeasonResponse( response_message='Error: No Admin Record Found. ', response_successful=False) region = RegionsController().create( description=request.description, title=request.title, datacenter_location=request.datacenter_location) """ credentials = AppAssertionCredentials( 'https://www.googleapis.com/auth/sqlservice.admin') http_auth = credentials.authorize(Http()) model_json = json.dumps(region.to_json()) #logging.info(model_json) headers = {"Content-Type": "application/json"} URL = "%s/regions/%s.json" % (FIREBASE_DATABASE_ROOT, region.key.id() ) logging.info(URL) resp, content = http_auth.request(URL, "PUT", ## Write or replace data to a defined path, model_json, headers=headers) """ #logging.info(resp) #logging.info(content) return RegionResponse(response_message="Region Created", response_successful=True)
def update(self, request): logging.info('update') # Verify Firebase auth. #claims = firebase_helper.verify_auth_token(self.request_state) id_token = self.request_state.headers['x-metagame-auth'].split(' ').pop() claims = google.oauth2.id_token.verify_firebase_token(id_token, HTTP_REQUEST) if not claims: ## TODO make this more modular, somehow. We have no idea who this user is at this point, so can't write to the firebase user record. logging.error('Firebase Unauth') response = SeasonResponse( response_message='Firebase Unauth.', response_successful=False ) return response authorized_user = UsersController().get_by_firebaseUser(claims['user_id']) if not authorized_user: logging.info('no user record found') return SeasonResponse(response_message='Error: No User Record Found. ', response_successful=False) if not authorized_user.admin: logging.info('no admin record found') return SeasonResponse(response_message='Error: No Admin Record Found. ', response_successful=False) startdate = dateutil.parser.parse(request.starts) enddate = dateutil.parser.parse(request.ends) ## get the model seasonController = SeasonsController() season=seasonController.get_by_key_id(int(request.key_id)) if not season: logging.error('season not found') return SeasonResponse(response_message="Season Not Found", response_successful=False) season.description = request.description season.title = request.title season.starts = startdate season.ends = enddate season.active = request.active season.closing = request.closing season.next = request.next season.currentRound = request.currentRound season.currentRoundPositioning = request.currentRoundPositioning season.currentRoundCombat = request.currentRoundCombat season.currentRoundResults = request.currentRoundResults seasonController.update(season) if request.active: taskUrl='/task/season/firebase/update' taskqueue.add(url=taskUrl, queue_name='firebaseUpdate', params={'key_id': season.key.id()}, countdown = 2,) return SeasonResponse(response_message="Season Updated")
def create(self, request): # Verify Firebase auth. #claims = firebase_helper.verify_auth_token(self.request_state) id_token = self.request_state.headers['x-metagame-auth'].split(' ').pop() claims = google.oauth2.id_token.verify_firebase_token(id_token, HTTP_REQUEST) if not claims: ## TODO make this more modular, somehow. We have no idea who this user is at this point, so can't write to the firebase user record. logging.error('Firebase Unauth') response = SeasonResponse( response_message='Firebase Unauth.', response_successful=False ) return response authorized_user = UsersController().get_by_firebaseUser(claims['user_id']) if not authorized_user: logging.info('no user record found') return SeasonResponse(response_message='Error: No User Record Found. ', response_successful=False) if not authorized_user.admin: logging.info('no admin record found') return SeasonResponse(response_message='Error: No Admin Record Found. ', response_successful=False) startdate = dateutil.parser.parse(request.starts) enddate = dateutil.parser.parse(request.ends) season=SeasonsController().create( description = request.description, title = request.title, starts = startdate, ends = enddate, active = request.active, currentRound = 0, currentRoundPositioning = True, currentRoundCombat = False, currentRoundResults = False ) ## we need this on firebase to show the current state of the season. if request.active: taskUrl='/task/season/firebase/update' taskqueue.add(url=taskUrl, queue_name='firebaseUpdate', params={'key_id': season.key.id()}, countdown = 2,) if AUTOMATIC_PHASE_CHANGE: ## requeue the task based on settings in config logging.info('starting phase change task') taskUrl='/task/season/stage_change' taskqueue.add(url=taskUrl, queue_name='seasonStageChange', countdown = ROUND_DURATION_POSITIONING,) return SeasonResponse(response_message="Season Created",response_successful=True)
def mapCollectionGet(self, request): """ Get a collection of maps """ logging.info("mapCollectionGet") # Verify Firebase auth. #logging.info(self.request_state) try: id_token = self.request_state.headers['x-metagame-auth'].split( ' ').pop() except: logging.error('Missing JWT') return MapCollection( response_message='Error: Authentication Token Missing.', response_successful=False) claims = google.oauth2.id_token.verify_firebase_token( id_token, HTTP_REQUEST) if not claims: logging.error('Firebase Unauth') return MapCollection( response_message='Error: Firebase Authentication Missing.', response_successful=False) authorized_user = UsersController().get_by_firebaseUser( claims['user_id']) if not authorized_user: logging.info('no user record found') return MapCollection( response_message='Error: No User Record Found. ', response_successful=False) if not authorized_user.admin: logging.info('no admin record found') return MapCollection( response_message='Error: No Admin Record Found. ', response_successful=False) mapController = MapsController() entities = mapController.list_by_regionKeyId(request.regionKeyId) entity_list = [] for entity in entities: entity_list.append( MapResponse(key_id=entity.key.id(), title=entity.title, created=entity.created.isoformat())) response = MapCollection(maps=entity_list, response_successful=True) return response
def get(self, request): logging.info('get') # Verify Firebase auth. #claims = firebase_helper.verify_auth_token(self.request_state) id_token = self.request_state.headers['x-metagame-auth'].split(' ').pop() claims = google.oauth2.id_token.verify_firebase_token(id_token, HTTP_REQUEST) if not claims: ## TODO make this more modular, somehow. We have no idea who this user is at this point, so can't write to the firebase user record. logging.error('Firebase Unauth') response = SeasonResponse( response_message='Firebase Unauth.', response_successful=False ) return response authorized_user = UsersController().get_by_firebaseUser(claims['user_id']) if not authorized_user: logging.info('no user record found') return SeasonResponse(response_message='Error: No User Record Found. ', response_successful=False) if not authorized_user.admin: logging.info('no admin record found') return SeasonResponse(response_message='Error: No Admin Record Found. ', response_successful=False) ## get the model seasonController = SeasonsController() season=seasonController.get_by_key_id(int(request.key_id)) if not season: logging.error('season not found') return SeasonResponse(response_message="Season Not Found", response_successful=False) return SeasonResponse( key_id = season.key.id(), title = season.title, description = season.description, starts = season.starts.isoformat(), ends = season.ends.isoformat(), active = season.active, closing = season.closing, next = season.next, currentRound = season.currentRound, currentRoundPositioning = season.currentRoundPositioning, currentRoundCombat = season.currentRoundCombat, currentRoundResults = season.currentRoundResults, response_message="Season Updated")
def post(self): """ Recieve Notification when a player stops meta game mode Requires http headers: Key, Sign Requires POST parameters: nonce """ ucontroller = UsersController() seasonsController = SeasonsController() factionController = FactionsController() zoneController = ZonesController() bidController = BidsController() ## make sure the API key matches first incomingApiKey = self.request.headers['Key'] if incomingApiKey != UETOPIA_ASSIGNED_GAME_API_KEY: logging.info('API key mismatch') return self.render_json_response( authorization = False, request_successful = False ) signature = self.request.headers['Sign'] logging.info("request.body: %s" % self.request.body) logging.info("params: ") logging.info(self.request.arguments()) logging.info("Headers: %s" %self.request.headers) sorted_params = self.request.body # Hash the params string to produce the Sign header value H = hmac.new(UETOPIA_ASSIGNED_GAME_API_SECRET, digestmod=hashlib.sha512) H.update(sorted_params) sign = H.hexdigest() logging.info("sign: %s" %sign) logging.info("Hsig: %s" %signature ) if sign != signature: logging.info('signature mismatch') return self.render_json_response( authorization = False, request_successful = False ) ## At this point, authorization was successful. Continue with the call. logging.info('auth success') ## parse the json out of the body. jsonstring = self.request.body logging.info(jsonstring) jsonobject = json.loads(jsonstring) ## make sure we have the player, and that it matches one we have already connected if 'player_key_id' not in jsonobject: logging.info('Did not find player_key_id in json') return self.render_json_response( authorization = True, request_successful = False ) user = ucontroller.get_by_uetopia_playerKeyId(jsonobject['player_key_id']) if not user: logging.info('user was not found. make sure they connect to metagame first.') return self.render_json_response( authorization = True, request_successful = False ) user.currentFactionKeyId = None user.currentFactionTag = None user.currentFactionLead = False user.currentFactionTeamLead = False ## update the user record. user.metaGameActive = False ucontroller.update(user) ## push out to firebase taskUrl='/task/user/firebase/update' taskqueue.add(url=taskUrl, queue_name='firebaseUpdate', params={'key_id': user.key.id()}, countdown = 2,) ## also update the zone if this user was controlling one. controlled_zone = zoneController.get_controlled_by_userCaptainKeyId(user.key.id()) if controlled_zone: logging.info('found a zone this user was controlling') controlled_zone.controlled = False controlled_zone.factionKeyId = None controlled_zone.factionTag = None controlled_zone.userCaptainKeyId = None controlled_zone.userCaptainTitle = None controlled_zone.uetopiaGamePlayerKeyId = None controlled_zone.teamTitle = None zoneController.update(controlled_zone) ## don't bother updating the map here. ## also check for any bids that are pending. pending_bid = bidController.get_unprocessed_by_userKeyId(user.key.id()) if pending_bid: logging.info('found a pending bid') ## maybe make it inactive or something more fancy if you want. Just deleting it for now. bidController.delete(pending_bid) ## return status success so that uetopia knows the call worked. return self.render_json_response( authorization = True, request_successful=True )
def create(self, request): # Verify Firebase auth. #claims = firebase_helper.verify_auth_token(self.request_state) id_token = self.request_state.headers['x-metagame-auth'].split( ' ').pop() claims = google.oauth2.id_token.verify_firebase_token( id_token, HTTP_REQUEST) if not claims: ## TODO make this more modular, somehow. We have no idea who this user is at this point, so can't write to the firebase user record. logging.error('Firebase Unauth') response = SeasonResponse(response_message='Firebase Unauth.', response_successful=False) return response authorized_user = UsersController().get_by_firebaseUser( claims['user_id']) if not authorized_user: logging.info('no user record found') return MapResponse( response_message='Error: No User Record Found. ', response_successful=False) if not authorized_user.admin: logging.info('no admin record found') return MapResponse( response_message='Error: No Admin Record Found. ', response_successful=False) ## Look up the season and region seasonController = SeasonsController() regionController = RegionsController() season = seasonController.get_by_key_id(request.seasonKeyId) if not season: logging.info('season not found by key') return MapResponse(response_message='Error: No Season Found. ', response_successful=False) region = regionController.get_by_key_id(request.regionKeyId) if not region: logging.info('region not found by key') return MapResponse(response_message='Error: No Region Found. ', response_successful=False) map = MapsController().create( description=request.description, title=request.title, seasonKeyId=season.key.id(), seasonTitle=season.title, seasonActive=season.active, regionKeyId=region.key.id(), regionTitle=region.title, regionDatacenterLocation=region.datacenter_location, zoneCountHorizontal=request.zoneCountHorizontal, zoneCountVertical=request.zoneCountVertical) """ credentials = AppAssertionCredentials( 'https://www.googleapis.com/auth/sqlservice.admin') http_auth = credentials.authorize(Http()) model_json = json.dumps(model.to_json()) #logging.info(model_json) headers = {"Content-Type": "application/json"} URL = "https://ue4topia.firebaseio.com/regions/%s.json" % model.key.id() resp, content = http_auth.request(URL, "PUT", ## Write or replace data to a defined path, model_json, headers=headers) """ #logging.info(resp) #logging.info(content) return MapResponse(response_message="Map Created", response_successful=True)
def post(self): logging.info("[TASK] SeasonStageChangeHandler") ## just use the active season #key_id = self.request.get('key_id') mapController = MapsController() zoneController = ZonesController() bidController = BidsController() seasonController = SeasonsController() factionsController = FactionsController() matchController = MatchController() usersController = UsersController() season = seasonController.get_active() if not season: logging.error('Season not found') return if not season.active: logging.error('Season not active') return ## Keep track of any factions that need bids refunded. refunding_faction_key_id_list = [] ## which stage are we currently on? if season.currentRoundPositioning: logging.info('currentRoundPositioning') ## - GO through each map ## - - Go through each zone ## - - - Find the high bid, timestamp if equal ## - - - Refund all other bids ## - - - - mark it as not high bid, add the faction to the task list, and process all refunds in a separate task for ech faction separately. ## - - - High bids with a defender - Fire off API call to start the match ## - - - Otherwise, team/faction/user takes control of the cell. ## - - Update the map ## Update the Season ## - Go through each map maps_for_this_season = mapController.list_by_seasonKeyId( season.key.id()) for map in maps_for_this_season: logging.info('processing map: %s' % map.title) zones = zoneController.list_by_mapKeyId(map.key.id()) for zone in zones: logging.info('processing zone: %s' % zone.title) ## get bids in reverse chrono - this way OLDER greater or equal bids can always push out NEWER bids bids = bidController.list_by_zoneKeyId(zone.key.id()) logging.info('found %s bids' % len(bids)) if len(bids) > 0: high_bid = None high_bid_amount = 0 ## This is a little confusing. ## We are checking if the bid in the loop is greater than the previous ## If it is, we are marking this one as "highest" - marking the previous as "not highest" and "processed" ## if it's not, we mark it as "processed" so it can get picked up in the faction refund task for bid in bids: if bid.bidAmount >= high_bid_amount: logging.info('found new high bid') # if there is a previous high bid, mark it as not high bid anymore if high_bid: logging.info( 'marking previous high bid processed') high_bid.highBid = False high_bid.bidProcessed = True ## add the faction key to the list, if it's not already there if bid.factionKeyId not in refunding_faction_key_id_list: refunding_faction_key_id_list.append( bid.factionKeyId) bid.highBid = True bid.bidProcessed = True high_bid = bid high_bid_amount = bid.bidAmount else: logging.info('found a lower bid') bid.highBid = False bid.bidProcessed = True ## add the faction key to the list, if it's not already there if bid.factionKeyId not in refunding_faction_key_id_list: refunding_faction_key_id_list.append( bid.factionKeyId) # save for bid in bids: bidController.update(bid) ## Now we have the highest bid in the high_bid variable ## does this zone have a defender? if zone.controlled: logging.info('this zone is controlled') ## also make sure that the defender is still active. They may have gone offline or something defending_user_captain = usersController.get_by_key_id( zone.userCaptainKeyId) if defending_user_captain and defending_user_captain.metaGameActive: logging.info('defender is still online') ## Create a match record for this, associate with teams factions and zone. match = matchController.create( title=zone.title, zoneKeyId=zone.key.id(), zoneTitle=zone.title, mapKeyId=zone.mapKeyId, mapTitle=zone.mapTitle, seasonKeyId=zone.seasonKeyId, seasonTitle=zone.seasonTitle, regionKeyId=zone.regionKeyId, regionTitle=zone.regionTitle, regionDatacenterLocation=zone. regionDatacenterLocation, #defenderTeamKeyId = zone., defenderTeamTitle=zone.teamTitle, defenderFactionKeyId=zone.factionKeyId, #defenderFactionTitle = zone., defenderFactionTag=zone.factionTag, defenderUserKeyId=zone.userCaptainKeyId, defenderUserTitle=zone.userCaptainTitle, defenderUetopiaGamePlayerKeyId=zone. uetopiaGamePlayerKeyId, attackerTeamKeyId=high_bid.teamKeyId, attackerTeamTitle=high_bid.teamTitle, attackerFactionKeyId=high_bid.factionKeyId, attackerFactionTitle=high_bid.factionTitle, attackerFactionTag=high_bid.factionTag, attackerUserKeyId=high_bid.userKeyId, attackerUserTitle=high_bid.userTitle, attackerUetopiaGamePlayerKeyId=high_bid. uetopiaGamePlayerKeyId, active=True, verified=False, expired=False, ) ## TODO - fire matchmaker API call uri = "/api/v1/game/metagame/match_begin" params = OrderedDict([ ("nonce", time.time()), ("encryption", "sha512"), ("attackingPlayerKeyId", match.attackerUetopiaGamePlayerKeyId), ("defendingPlayerKeyId", match.defenderUetopiaGamePlayerKeyId), #("gameModeKeyId", match.regionTitle), ("region", match.regionDatacenterLocation), ("metaMatchKeyId", match.key.id()) ]) params = urllib.urlencode(params) # Hash the params string to produce the Sign header value H = hmac.new(UETOPIA_ASSIGNED_GAME_API_SECRET, digestmod=hashlib.sha512) H.update(params) sign = H.hexdigest() headers = { "Content-type": "application/x-www-form-urlencoded", "Key": UETOPIA_ASSIGNED_GAME_API_KEY, "Sign": sign } conn = httplib.HTTPSConnection(UETOPIA_API_URL) conn.request("POST", uri, params, headers) response = conn.getresponse() #logging.info(response.read()) ## parse the response jsonstring = str(response.read()) logging.info(jsonstring) jsonobject = json.loads(jsonstring) # do something with the response if not jsonobject['request_successful']: logging.info( 'the validation request was unsuccessful' ) return logging.info('validation was successful') else: logging.info('Defender was not online') zone.controlled = True zone.factionKeyId = bid.factionKeyId zone.factionTag = bid.factionTag zone.userCaptainKeyId = bid.userKeyId zone.userCaptainTitle = bid.userTitle zone.uetopiaGamePlayerKeyId = bid.uetopiaGamePlayerKeyId zone.teamTitle = bid.teamTitle # save zoneController.update(zone) else: logging.info('Not controlled') zone.controlled = True zone.factionKeyId = bid.factionKeyId zone.factionTag = bid.factionTag zone.userCaptainKeyId = bid.userKeyId zone.userCaptainTitle = bid.userTitle zone.uetopiaGamePlayerKeyId = bid.uetopiaGamePlayerKeyId zone.teamTitle = bid.teamTitle # save zoneController.update(zone) # also update the user so we have the controlled map id ## Update Map ## push out to firebase taskUrl = '/task/map/firebase/update' taskqueue.add( url=taskUrl, queue_name='firebaseUpdate', params={'key_id': map.key.id()}, countdown=2, ) ## update season season.currentRoundCombat = True season.currentRoundPositioning = False season.currentRoundResults = False # save seasonController.update(season) ## push out to firebase taskUrl = '/task/season/firebase/update' taskqueue.add( url=taskUrl, queue_name='firebaseUpdate', params={'key_id': season.key.id()}, countdown=2, ) ## start a task to process bids for each of the factions for factionKeyId in refunding_faction_key_id_list: taskUrl = '/task/faction/process_bids' taskqueue.add( url=taskUrl, queue_name='factionProcessBids', params={'key_id': factionKeyId}, countdown=2, ) if AUTOMATIC_PHASE_CHANGE: ## requeue the task based on settings in config logging.info('requeueing task') taskUrl = '/task/season/stage_change' taskqueue.add( url=taskUrl, queue_name='seasonStageChange', countdown=ROUND_DURATION_COMBAT, ) elif season.currentRoundCombat: logging.info('currentRoundCombat') ## Time has run out on the round. ## All games should be finished by now. ## Any unplayed matches result in the zone returning back to uncontrolled. ## There could potentially be a lot of matches, so we are going to batch these. ## appengine can only support a maximum query size of 1000, so by batching, we can bypass this limitation curs = Cursor() more = True while more: active_matches, curs, more = matchController.list_active_page( start_cursor=curs) for match in active_matches: logging.info('processing active match') if match.verified: logging.info('found verified match') ## move the winning user/team/faction into the zone zone = zoneController.get_by_key_id(match.zoneKeyId) if zone: zone.controlled = True zone.factionKeyId = match.winningFactionKeyId zone.factionTag = match.winningFactionTitle zone.userCaptainKeyId = match.winningUserKeyId zone.userCaptainTitle = match.winningUserTitle zone.teamTitle = match.winningTeamTitle zone.uetopiaGamePlayerKeyId = match.winningUetopiaGamePlayerKeyId # save zoneController.update(zone) else: logging.info('zone was not found!') else: logging.info('found expired match') zone = zoneController.get_by_key_id(match.zoneKeyId) if zone: zone.controlled = False zone.factionKeyId = None zone.factionTag = None zone.userCaptainKeyId = None zone.userCaptainTitle = None zone.teamTitle = None zone.uetopiaGamePlayerKeyId = None # save zoneController.update(zone) else: logging.info('zone was not found!') ## mark the match inactive/processed if you want to keep the data around for mining ## in this example we are just going to delete it. matchController.delete(match) ## then switch modes to results. logging.info('match processing complete.') ## update season season.currentRoundCombat = False season.currentRoundPositioning = False season.currentRoundResults = True # save seasonController.update(season) ## push out to firebase taskUrl = '/task/season/firebase/update' taskqueue.add( url=taskUrl, queue_name='firebaseUpdate', params={'key_id': season.key.id()}, countdown=2, ) if AUTOMATIC_PHASE_CHANGE: ## requeue the task based on settings in config logging.info('requeueing task') taskUrl = '/task/season/stage_change' taskqueue.add( url=taskUrl, queue_name='seasonStageChange', countdown=ROUND_DURATION_RESULTS, ) else: logging.info('currentRoundResults') ## add up rewards for winning each zone, and add them into the facton record. ## TODO - allow building here, or some other action to utelize the materials. build defenses or whatever. ## - Go through each faction ## - - Get all of the zones the faction controls ## - - - sum up the changes ## - Update the faction curs = Cursor() more = True while more: active_factions, curs, more = factionsController.list_active_season_page( season.key.id(), start_cursor=curs) for faction in active_factions: logging.info('processing faction') ## get zones under this faction's control controlled_zones = zoneController.list_by_factionKeyId( faction.key.id()) for zone in controlled_zones: logging.info('found controlled zone') ## add values for this zone to the faction faction.energy = faction.energy + zone.energy faction.materials = faction.materials + zone.materials faction.control = faction.control + zone.control ## give every faction the defaults - even if they don't control any zones faction.energy = faction.energy + FACTION_ROUND_ENERGY faction.materials = faction.materials + FACTION_ROUND_MATERIALS faction.control = faction.control + FACTION_ROUND_CONTROL # save factionsController.update(faction) ## update firebase only if season is not over if datetime.datetime.now() < season.ends: taskUrl = '/task/faction/firebase/update' taskqueue.add( url=taskUrl, queue_name='firebaseUpdate', params={'key_id': faction.key.id()}, countdown=2, ) ## check to see if the season is over - if it is, calculate the winners, give rewards, something... ## if not, update the round number and switch modes to positioning. if datetime.datetime.now() > season.ends: logging.info('this season is over. ') ## TODO - mark it final, give rewards etc. curs = Cursor() more = True winning_faction = None winner_found = False ## get the winning faction from local db - we need them all anyway to reset, so just get them all sorted by control while more: logging.info('More is true') factions, curs, more = factionsController.list_active_season_page_by_control( season.key.id(), start_cursor=curs) for faction in factions: logging.info('found faction') ## the first record is our winner. if not winner_found: logging.info('found winner') winner_found = True winning_faction = faction ## get the faction leaders from local db faction_leaders = usersController.list_factionLeaders( faction.key.id()) ## divide up the materials points that the faction has accumulated among the faction leaders. ## any remainder will be given to the first record found. if len(faction_leaders): logging.info( 'found at least one faction leader') materials_earned_for_each_leader = faction.materials / len( faction_leaders) materials_remainder = faction.materials % len( faction_leaders) logging.info( 'materials_earned_for_each_leader: %s' % materials_earned_for_each_leader) logging.info('materials_remainder: %s' % materials_remainder) remainder_added = False for faction_lead in faction_leaders: logging.info('found a faction lead') ## DO DROPS uri = "/api/v1/game/player/%s/drops/create" % faction_lead.uetopia_playerKeyId json_values = ({ u'nonce': time.time(), u'encryption': "sha512", u'title': CURRENT_SEASON_WINNER_DROP['title'], u'description': CURRENT_SEASON_WINNER_DROP[ 'description'], u'uiIcon': CURRENT_SEASON_WINNER_DROP['uiIcon'], u'data': CURRENT_SEASON_WINNER_DROP['data'] }) entity_json = json.dumps(json_values) # Hash the params string to produce the Sign header value H = hmac.new( UETOPIA_ASSIGNED_GAME_API_SECRET, digestmod=hashlib.sha512) H.update(entity_json) sign = H.hexdigest() headers = { "Content-type": "application/x-www-form-urlencoded", "Key": UETOPIA_ASSIGNED_GAME_API_KEY, "Sign": sign } conn = httplib.HTTPSConnection( UETOPIA_API_URL) conn.request("POST", uri, entity_json, headers) response = conn.getresponse() #logging.info(response.read()) ## parse the response jsonstring = str(response.read()) logging.info(jsonstring) jsonobject = json.loads(jsonstring) # do something with the response? if not jsonobject['request_successful']: logging.info( 'the request was unsuccessful') logging.info('request was successful') ## empty out the faction's score to prepare for the next season? ## this could result in zombie factions persisting throughout the seasons. ## just going to delete it instead. ## it will get recreated the next time a player signs in factionsController.delete(faction) ## set the season to inactive. season.active = False seasonController.update(season) ## also dump firebase values for factions and active_season credentials = GoogleCredentials.get_application_default( ).create_scoped(_FIREBASE_SCOPES) http_auth = credentials.authorize(Http()) empty_json = json.dumps({}) # just empty headers = {"Content-Type": "application/json"} URL = "%s/factions.json" % (FIREBASE_DATABASE_ROOT) resp, content = http_auth.request( URL, "DELETE", ## We can delete data with a DELETE request empty_json, headers=headers) URL = "%s/active_season.json" % (FIREBASE_DATABASE_ROOT) resp, content = http_auth.request( URL, "DELETE", ## We can delete data with a DELETE request empty_json, headers=headers) ## also delete the maps out of the regions URL = "%s/regions.json" % (FIREBASE_DATABASE_ROOT) resp, content = http_auth.request( URL, "DELETE", ## We can delete data with a DELETE request empty_json, headers=headers) else: logging.info('season is not over, starting next round') ## clear out user moved bools ## there could be a lot of these, so we're going to bactch them like before. curs = Cursor() more = True while more: users_needing_round_reset, curs, more = usersController.list_roundActionUsed_page( start_cursor=curs) for user in users_needing_round_reset: logging.info('processing user') user.roundActionUsed = False usersController.update(user) random_offset = random.randint( 2, 10 ) ## if you have a lot of volume you can increase this up to 30 or 60 taskUrl = '/task/user/firebase/update' taskqueue.add( url=taskUrl, queue_name='firebaseUpdate', params={'key_id': user.key.id()}, countdown=random_offset, ) ## update season season.currentRound = season.currentRound + 1 season.currentRoundCombat = False season.currentRoundPositioning = True season.currentRoundResults = False # save seasonController.update(season) ## push season out to firebase taskUrl = '/task/season/firebase/update' taskqueue.add( url=taskUrl, queue_name='firebaseUpdate', params={'key_id': season.key.id()}, countdown=2, ) ## push maps out to firebase all_maps_for_this_season = mapController.list_by_seasonKeyId( season.key.id()) for map in all_maps_for_this_season: random_offset = random.randint(2, 10) taskUrl = '/task/map/firebase/update' taskqueue.add( url=taskUrl, queue_name='firebaseUpdate', params={'key_id': map.key.id()}, countdown=random_offset, ) if AUTOMATIC_PHASE_CHANGE: ## requeue the task based on settings in config logging.info('requeueing task') taskUrl = '/task/season/stage_change' taskqueue.add( url=taskUrl, queue_name='seasonStageChange', countdown=ROUND_DURATION_POSITIONING, )
def post(self): """ Recieve notification when a match is complete. Requires http headers: Key, Sign Requires POST parameters: nonce """ ucontroller = UsersController() seasonsController = SeasonsController() factionController = FactionsController() matchController = MatchController() zonesController = ZonesController() ## make sure the API key matches first incomingApiKey = self.request.headers['Key'] if incomingApiKey != UETOPIA_ASSIGNED_GAME_API_KEY: logging.info('API key mismatch') return self.render_json_response(authorization=False, request_successful=False) signature = self.request.headers['Sign'] logging.info("request.body: %s" % self.request.body) logging.info("params: ") logging.info(self.request.arguments()) logging.info("Headers: %s" % self.request.headers) sorted_params = self.request.body # Hash the params string to produce the Sign header value H = hmac.new(UETOPIA_ASSIGNED_GAME_API_SECRET, digestmod=hashlib.sha512) H.update(sorted_params) sign = H.hexdigest() logging.info("sign: %s" % sign) logging.info("Hsig: %s" % signature) if sign != signature: logging.info('signature mismatch') return self.render_json_response(authorization=False, request_successful=False) ## At this point, authorization was successful. Continue with the call. logging.info('auth success') ## parse the json out of the body. jsonstring = self.request.body logging.info(jsonstring) jsonobject = json.loads(jsonstring) ## make sure we have the player, and that it matches one we have already connected if 'match_key_id' not in jsonobject: logging.info('Did not find match_key_id in json') return self.render_json_response(authorization=True, request_successful=False) match = matchController.get_by_key_id(jsonobject['match_key_id']) if not match: logging.info('match was not found.') return self.render_json_response(authorization=True, request_successful=False) ## we need the active season too active_season = seasonsController.get_active() if not active_season: logging.info('active_season was not found.') return self.render_json_response(authorization=True, request_successful=False) ## grab information about the winner - this is a gameplayerkeyid if 'winning_user_key_id' in jsonobject: logging.info('Found winning_user_key_id in json') winning_user = ucontroller.get_by_uetopia_playerKeyId( jsonobject['winning_user_key_id']) if not winning_user: logging.info('winning user not found') return self.render_json_response(authorization=True, request_successful=False) ## make sure we have this group/faction in the database already. winning_faction = factionController.get_by_key_id( winning_user.currentFactionKeyId) if not winning_faction: logging.info('could not find the connected winning_faction') return self.render_json_response(authorization=True, request_successful=False) # get the zone associated with this match zone = zonesController.get_by_key_id(match.zoneKeyId) if not zone: logging.info('could not find the connected zone') return self.render_json_response(authorization=True, request_successful=False) ## was the winner the attacker or defender? if winning_user.key.id() == zone.userCaptainKeyId: logging.info('defender was the winner') ## get both users and set active to false. previous_defender = ucontroller.get_by_key_id( match.defenderUserKeyId) previous_defender.metaGameActive = False ucontroller.update(previous_defender) ## the attacker is not going to get picked up at the season round change step, so do it now. taskUrl = '/task/user/firebase/update' taskqueue.add( url=taskUrl, queue_name='firebaseUpdate', params={'key_id': previous_defender.key.id()}, countdown=2, ) previous_attacker = ucontroller.get_by_key_id( match.attackerUserKeyId) previous_attacker.metaGameActive = False ucontroller.update(previous_attacker) ## the attacker is not going to get picked up at the season round change step, so do it now. taskUrl = '/task/user/firebase/update' taskqueue.add( url=taskUrl, queue_name='firebaseUpdate', params={'key_id': previous_attacker.key.id()}, countdown=2, ) else: logging.info('attacker was the winner') ## change around the keys in the captain's user records. previous_controller_user = ucontroller.get_by_key_id( zone.userCaptainKeyId) if previous_controller_user: logging.info('found previous user record - cleaning it out') previous_controller_user.holdingZoneKeyId = None previous_controller_user.holdingZone = False previous_controller_user.holdingZoneTitle = None ## also set active to false. We need them to reenable meta mode in-game. previous_controller_user.metaGameActive = False ucontroller.update(previous_controller_user) ## the defender is not going to get picked up at the season round change step, so do it now. taskUrl = '/task/user/firebase/update' taskqueue.add( url=taskUrl, queue_name='firebaseUpdate', params={'key_id': previous_controller_user.key.id()}, countdown=2, ) winning_user.holdingZoneKeyId = zone.key.id() winning_user.holdingZone = True winning_user.holdingZoneTitle = zone.title ## also set active to false. We need them to reenable meta mode in-game. winning_user.metaGameActive = False ucontroller.update(winning_user) ## firebase? - just wait until the round is over and do them all ## in either case, just store the winning results in the match record so that we can process it when the round ends. match.winningUserKeyId = winning_user.key.id() match.winningUserTitle = winning_user.title match.winningTeamTitle = winning_user.currentTeamTitle match.winningFactionKeyId = winning_user.currentFactionKeyId match.winningFactionTitle = winning_user.currentFactionTag match.winningUetopiaGamePlayerKeyId = winning_user.uetopia_playerKeyId match.active = True match.verified = True match.expired = False # save match matchController.update(match) return self.render_json_response(authorization=True, request_successful=True)
def clientSignIn(self, request): """ Connect and verify a user's login token - This is called when a user signs in. """ logging.info('clientSignIn') # Verify Firebase auth. #logging.info(self.request_state) try: id_token = self.request_state.headers['x-metagame-auth'].split( ' ').pop() except: logging.error('Missing JWT') return ClientConnectResponse( response_message='Error: Authentication Token Missing.', response_successful=False) claims = google.oauth2.id_token.verify_firebase_token( id_token, HTTP_REQUEST) if not claims: logging.error('Firebase Unauth') response = ClientConnectResponse( user_id=None, refresh_token=True, response_message='Firebase Unauth.', response_successful=False) return response else: logging.info('claims verified') try: name = claims['name'] except: name = claims['email'] ## get this user or create if needed uController = UsersController() authorized_user = uController.get_by_firebaseUser( claims['user_id']) if not authorized_user: logging.info('no user record found') logging.info('creating new user') authorized_user = uController.create( firebaseUser=claims['user_id'], title=name, uetopia_connected=False, admin=False, metaGameActive=False, roundActionUsed=False, currentFactionKeyId=None, currentFactionTag=None, currentFactionLead=False, currentFactionTeamLead=False, currentTeamKeyId=None, currentTeamCaptain=False, holdingZoneKeyId=None, holdingZone=False, holdingZoneTitle=None) # push a chat out to discord http_auth = Http() headers = {"Content-Type": "application/json"} URL = ADMIN_DISCORD_WEBHOOK message = "%s | %s " % (name, claims['email']) discord_data = { "embeds": [{ "title": "New User", "url": "https://example.com", "description": message }] } data = json.dumps(discord_data) resp, content = http_auth.request(URL, "POST", data, headers=headers) else: logging.info('user found') #taskUrl='/task/user/firebase/update' #taskqueue.add(url=taskUrl, queue_name='firebaseUpdate', params={'key_id': authorized_user.key.id()}, countdown = 2,) response = ClientConnectResponse( user_id=claims['user_id'], uetopia_connected=authorized_user.uetopia_connected, response_message='Connected successfully.', response_successful=True) return response
def uetopiaValidate(self, request): """ Validate a user's uetopia security code and connect thier account.""" logging.info('uetopiaValidate') # Verify Firebase auth. #logging.info(self.request_state) try: id_token = self.request_state.headers['x-metagame-auth'].split( ' ').pop() except: logging.error('Missing JWT') return ClientConnectResponse( response_message='Error: Authentication Token Missing.', response_successful=False) claims = google.oauth2.id_token.verify_firebase_token( id_token, HTTP_REQUEST) if not claims: logging.error('Firebase Unauth') response = ClientConnectResponse( user_id=None, refresh_token=True, response_message='Firebase Unauth.', response_successful=False) return response logging.info('claims verified') try: name = claims['name'] except: name = claims['email'] ## get this user uController = UsersController() factionController = FactionsController() seasonController = SeasonsController() authorized_user = uController.get_by_firebaseUser(claims['user_id']) if not authorized_user: logging.warning( 'no user record found - this can happen on first sign in') response = ClientConnectResponse( user_id=claims['user_id'], uetopia_connected=False, response_message='No user record found', response_successful=False) ## Users do not get created in this call ever. It causes occasional duplicates because of the way firebase spams refreshes on the login screen. return response logging.info('user found') #Set up an API request to the uetopia backend to check this security code # we'll be sending the gameKeyId, and the user's security code # this security code will be erased regardless of the results of this request, so if it failed, the user must start over with a new code. uri = "/api/v1/game/metagame/verify" params = OrderedDict([("nonce", time.time()), ("encryption", "sha512"), ("securityCode", request.security_code)]) params = urllib.urlencode(params) # Hash the params string to produce the Sign header value H = hmac.new(UETOPIA_ASSIGNED_GAME_API_SECRET, digestmod=hashlib.sha512) H.update(params) sign = H.hexdigest() headers = { "Content-type": "application/x-www-form-urlencoded", "Key": UETOPIA_ASSIGNED_GAME_API_KEY, "Sign": sign } conn = httplib.HTTPSConnection(UETOPIA_API_URL) conn.request("POST", uri, params, headers) response = conn.getresponse() #logging.info(response.read()) ## parse the response jsonstring = str(response.read()) logging.info(jsonstring) jsonobject = json.loads(jsonstring) # do something with the response if not jsonobject['request_successful']: logging.info('the validation request was unsuccessful') response = ClientConnectResponse( user_id=claims['user_id'], uetopia_connected=False, response_message='Verification failed. %s' % jsonobject['error'], response_successful=False) return response logging.info('validation was successful') authorized_user.uetopia_connected = True authorized_user.uetopia_playerKeyId = jsonobject['player_key_id'] active_season_key = None active_season = seasonController.get_active() if active_season: logging.info('Active season found') active_season_key = active_season.key.id() ## grab information about the group and team if 'group_key_id' in jsonobject: logging.info('Found group_key_id in json') ## make sure we have this group/faction in the database already. faction = factionController.get_by_uetopia_groupKeyId( jsonobject['group_key_id']) if faction: logging.info('found an existing faction') ## check to see if the faction is in the active semester if not faction.activeSeasonKeyId: logging.info( 'this faction has not been active in the current semester yet. Setting defaults' ) faction.activeSeasonKeyId = active_season_key faction.energy = FACTION_STARTING_ENERGY faction.materials = FACTION_STARTING_MATERIALS faction.control = FACTION_STARTING_CONTROL factionController.update(faction) if faction.activeSeasonKeyId != active_season.key.id(): ## this should hopefully not happen, keeping it here just in case logging.error( 'this faction has the wrong season applied. This should not happen. Make sure this gets cleared out on season change.' ) faction.activeSeasonKeyId = active_season_key faction.energy = FACTION_STARTING_ENERGY faction.materials = FACTION_STARTING_MATERIALS faction.control = FACTION_STARTING_CONTROL factionController.update(faction) else: logging.info('faction not found - adding it') faction = factionController.create( tag=jsonobject['group_tag'], #title = ndb.StringProperty(indexed=False) #description = ndb.TextProperty(indexed=False) uetopia_groupKeyId=jsonobject['group_key_id'], activeSeasonKeyId=active_season_key, energy=FACTION_STARTING_ENERGY, materials=FACTION_STARTING_MATERIALS, control=FACTION_STARTING_CONTROL) ## with a faction, make sure the user has this faction selected, and there were no changes to the users permissions authorized_user.currentFactionKeyId = faction.key.id() authorized_user.currentFactionTag = jsonobject['group_tag'] try: authorized_user.currentFactionLead = jsonobject[ 'metagame_faction_lead'] except: authorized_user.currentFactionLead = False try: authorized_user.currentFactionTeamLead = jsonobject[ 'metagame_team_lead'] except: authorized_user.currentFactionTeamLead = False uController.update(authorized_user) ## check for team if jsonobject['team_key_id']: logging.info('found a team') ## we want to be able to send back the team captain status so that the JS client can prompt the user to take appropriate actions taskUrl = '/task/user/firebase/update' taskqueue.add( url=taskUrl, queue_name='firebaseUpdate', params={'key_id': authorized_user.key.id()}, countdown=2, ) response = ClientConnectResponse( response_message='Connected successfully.', response_successful=True) return response
def clientConnect(self, request): """ Connect and verify a user's login token - This is called when a user loads the website and is already logged in. also sometimes after signing in.""" logging.info('clientConnect') #user = endpoints.get_current_user() #logging.info(user) # Verify Firebase auth. #logging.info(self.request_state) try: id_token = self.request_state.headers['x-metagame-auth'].split( ' ').pop() except: logging.error('Missing JWT') return ClientConnectResponse( response_message='Error: Authentication Token Missing.', response_successful=False) claims = google.oauth2.id_token.verify_firebase_token( id_token, HTTP_REQUEST) if not claims: logging.error('Firebase Unauth') response = ClientConnectResponse( user_id=None, refresh_token=True, response_message='Firebase Unauth.', response_successful=False) return response else: logging.info('claims verified') try: name = claims['name'] except: name = claims['email'] ## get this user uController = UsersController() authorized_user = uController.get_by_firebaseUser( claims['user_id']) if not authorized_user: logging.warning( 'no user record found - this can happen on first sign in') response = ClientConnectResponse( user_id=claims['user_id'], uetopia_connected=False, response_message='No user record found', response_successful=False) ## Users do not get created in this call ever. It causes occasional duplicates because of the way firebase spams refreshes on the login screen. return response else: logging.info('user found') taskUrl = '/task/user/firebase/update' taskqueue.add( url=taskUrl, queue_name='firebaseUpdate', params={'key_id': authorized_user.key.id()}, countdown=2, ) response = ClientConnectResponse( user_id=claims['user_id'], uetopia_connected=authorized_user.uetopia_connected, refresh_token=False, response_message='Connected successfully.', response_successful=True) return response
def fill(self, request): # Verify Firebase auth. #claims = firebase_helper.verify_auth_token(self.request_state) id_token = self.request_state.headers['x-metagame-auth'].split( ' ').pop() claims = google.oauth2.id_token.verify_firebase_token( id_token, HTTP_REQUEST) if not claims: ## TODO make this more modular, somehow. We have no idea who this user is at this point, so can't write to the firebase user record. logging.error('Firebase Unauth') response = ZoneResponse(response_message='Firebase Unauth.', response_successful=False) return response authorized_user = UsersController().get_by_firebaseUser( claims['user_id']) if not authorized_user: logging.info('no user record found') return ZoneResponse( response_message='Error: No User Record Found. ', response_successful=False) if not authorized_user.admin: logging.info('no admin record found') return ZoneResponse( response_message='Error: No Admin Record Found. ', response_successful=False) ## Look up the map mapController = MapsController() zoneController = ZonesController() map = mapController.get_by_key_id(request.mapKeyId) if not map: logging.info('map not found by key') return ZoneResponse(response_message='Error: No map Found. ', response_successful=False) ## keep track of the results so we can push the whole json struct to firebase all at once. map_json = {} vertical_rows = [] # loop over the horizontal for verticalIndex in range(map.zoneCountVertical): logging.info('filling verticalIndex: %s' % verticalIndex) horizontal_row = [] for horizontalIndex in range(map.zoneCountHorizontal): logging.info('filling horizontalIndex') ## Roll to see which zone should fill here (defined in configuration.py) zoneToUse = random.randint(1, 100) logging.info('random roll: %s' % zoneToUse) ## loop over the zonetypes for zone_type in ZONE_TYPES: if zone_type['probability'] >= zoneToUse: logging.info('found zone') ## roll for energy, materials, control based on the zone type rand_energy = random.randint(zone_type['energyMin'], zone_type['energyMax']) rand_materials = random.randint( zone_type['materialsMin'], zone_type['materialsMax']) rand_control = random.randint(zone_type['controlMin'], zone_type['controlMax']) zone = zoneController.create( engine_travel_url=zone_type['engine_travel_url'], title=zone_type['title'], mapKeyId=map.key.id(), mapTitle=map.title, seasonKeyId=map.seasonKeyId, seasonTitle=map.seasonTitle, seasonActive=map.seasonActive, regionKeyId=map.regionKeyId, regionTitle=map.regionTitle, regionDatacenterLocation=map. regionDatacenterLocation, horizontalIndex=horizontalIndex, verticalIndex=verticalIndex, energy=rand_energy, materials=rand_materials, control=rand_control, validZone=zone_type['validZone']) horizontal_row.append(zone.to_json()) break vertical_rows.append(horizontal_row) #credentials = AppAssertionCredentials('https://www.googleapis.com/auth/sqlservice.admin') credentials = GoogleCredentials.get_application_default( ).create_scoped(_FIREBASE_SCOPES) http_auth = credentials.authorize(Http()) map.zones = vertical_rows map_json = map.to_json() model_json = json.dumps(map_json) #logging.info(model_json) headers = {"Content-Type": "application/json"} URL = "%s/regions/%s/maps/%s.json" % (FIREBASE_DATABASE_ROOT, map.regionKeyId, map.key.id()) logging.info(URL) resp, content = http_auth.request( URL, "PUT", ## Write or replace data to a defined path, model_json, headers=headers) #logging.info(resp) #logging.info(content) return ZoneResponse(response_message="Map Filled", response_successful=True)
def zoneBid(self, request): """ Bid to attack a zone """ logging.info("zoneBid") # Verify Firebase auth. #logging.info(self.request_state) try: id_token = self.request_state.headers['x-metagame-auth'].split( ' ').pop() except: logging.error('Missing JWT') return BidResponse( response_message='Error: Authentication Token Missing.', response_successful=False) claims = google.oauth2.id_token.verify_firebase_token( id_token, HTTP_REQUEST) if not claims: logging.error('Firebase Unauth') return BidResponse( response_message='Error: Firebase Authentication Missing.', response_successful=False) userController = UsersController() authorized_user = userController.get_by_firebaseUser(claims['user_id']) if not authorized_user: logging.info('no user record found') return BidResponse( response_message='Error: No User Record Found. ', response_successful=False) if not authorized_user.currentFactionTeamLead: logging.info( 'User does not have currentFactionTeamLead permission') return BidResponse( response_message= 'Error: You do not have the Team Lead permission. ', response_successful=False) if authorized_user.roundActionUsed: logging.info('User has already taken an action this round') return BidResponse( response_message= 'Error: You have already taken an action this round. ', response_successful=False) zoneController = ZonesController() bidController = BidsController() seasonController = SeasonsController() factionsController = FactionsController() ## check season - make sure positioning is set to true. season = seasonController.get_active() if not season: logging.info('No Active season found') return BidResponse( response_message='Error: The active season was not found. ', response_successful=False) if not season.currentRoundPositioning: logging.info('Positioning is not currently enabled - cannot bid') return BidResponse( response_message= 'Error: Positioning round is not active. Cannot bid.', response_successful=False) zone = zoneController.get_by_key_id(request.zoneKeyId) if not zone: logging.info('the zone was not found') return BidResponse( response_message='Error: The zone was not found. ', response_successful=False) ## check min/max if request.bidAmount < MINIMUM_BID: logging.info('bid below minimum') return BidResponse(response_message='Error: The bid was too low. ', response_successful=False) if request.bidAmount > MAXIMUM_BID: logging.info('bid above maximum') return BidResponse( response_message='Error: The bid was too high. ', response_successful=False) ## make sure the faction can afford it faction = factionsController.get_by_key_id( authorized_user.currentFactionKeyId) if not faction: logging.info('the faction was not found') return BidResponse( response_message='Error: The faction was not found. ', response_successful=False) if faction.energy < request.bidAmount: logging.info('the faction cannot afford this bid') return BidResponse( response_message='Error: The faction cannot afford this bid. ', response_successful=False) ## Check to see if this team was previously defending. If they were, we need to remove them from the defending zone immediately. defending_zone = zoneController.get_controlled_by_userCaptainKeyId( authorized_user.key.id()) if defending_zone: logging.info('found a zone that this user/team is defending') if defending_zone.key.id() == zone.key.id(): logging.info( 'it is the same zone. This should not happen. Ignoring') return BidResponse( response_message= 'Error: Cannot bid on a zone that is currently being defended.', response_successful=False) else: logging.info( 'This is a different zone. Moving the team out of the defended zone.' ) defending_zone.controlled = False defending_zone.factionKeyId = None defending_zone.factionTag = None defending_zone.userCaptainKeyId = None defending_zone.userCaptainTitle = None defending_zone.teamTitle = None #save zoneController.update(defending_zone) ## firebase update? Can just leave it for the next push I think.... ## Remove the amount from the faction ## TODO - use a more fault tolerant approach for serious projects. ## for now just subtracting faction.energy = faction.energy - request.bidAmount # and since we're about to update the faction anyway, make sure it has the current season key faction.activeSeasonKeyId = season.key.id() factionsController.update(faction) ## record the bid bidController.create( zoneKeyId=zone.key.id(), zoneTitle=zone.title, mapKeyId=zone.mapKeyId, mapTitle=zone.mapTitle, seasonKeyId=season.key.id(), seasonTitle=season.title, seasonActive=season.active, regionKeyId=zone.regionKeyId, regionTitle=zone.regionTitle, # connections to the user, party and faction #teamKeyId = ndb.IntegerProperty(indexed=False) #teamTitle = ndb.StringProperty(indexed=False) factionKeyId=faction.key.id(), factionTitle=faction.tag, factionTag=faction.tag, userKeyId=authorized_user.key.id(), userTitle=authorized_user.title, uetopiaGamePlayerKeyId=authorized_user.uetopia_playerKeyId, roundIndex=season.currentRound, bidAmount=request.bidAmount, highBid=False, bidProcessed=False, bidReturned=False, ) ## update the player - make the bid buttons and "waiting for move" dissapear authorized_user.roundActionUsed = True userController.update(authorized_user) taskUrl = '/task/user/firebase/update' taskqueue.add( url=taskUrl, queue_name='firebaseUpdate', params={'key_id': authorized_user.key.id()}, countdown=2, ) response = BidResponse(response_message="Bid placed.", response_successful=True) return response
def post(self): """ Recieve Notification when a player starts meta game mode Requires http headers: Key, Sign Requires POST parameters: nonce, securityCode """ ucontroller = UsersController() seasonsController = SeasonsController() factionController = FactionsController() ## make sure the API key matches first incomingApiKey = self.request.headers['Key'] if incomingApiKey != UETOPIA_ASSIGNED_GAME_API_KEY: logging.info('API key mismatch') return self.render_json_response(authorization=False, request_successful=False) signature = self.request.headers['Sign'] logging.info("request.body: %s" % self.request.body) logging.info("params: ") logging.info(self.request.arguments()) logging.info("Headers: %s" % self.request.headers) sorted_params = self.request.body # Hash the params string to produce the Sign header value H = hmac.new(UETOPIA_ASSIGNED_GAME_API_SECRET, digestmod=hashlib.sha512) H.update(sorted_params) sign = H.hexdigest() logging.info("sign: %s" % sign) logging.info("Hsig: %s" % signature) if sign != signature: logging.info('signature mismatch') return self.render_json_response(authorization=False, request_successful=False) ## At this point, authorization was successful. Continue with the call. logging.info('auth success') ## parse the json out of the body. jsonstring = self.request.body logging.info(jsonstring) jsonobject = json.loads(jsonstring) ## make sure we have the player, and that it matches one we have already connected if 'player_key_id' not in jsonobject: logging.info('Did not find player_key_id in json') return self.render_json_response(authorization=True, request_successful=False) user = ucontroller.get_by_uetopia_playerKeyId( jsonobject['player_key_id']) if not user: logging.info( 'user was not found. make sure they connect to metagame first.' ) return self.render_json_response(authorization=True, request_successful=False) ## we need the active season too active_season = seasonsController.get_active() if not active_season: logging.info('active_season was not found.') return self.render_json_response(authorization=True, request_successful=False) ## grab information about the group and team if 'group_key_id' in jsonobject: logging.info('Found group_key_id in json') ## make sure we have this group/faction in the database already. faction = factionController.get_by_uetopia_groupKeyId( jsonobject['group_key_id']) if faction: logging.info('found an existing faction') ## check to see if the faction is in the active semester if not faction.activeSeasonKeyId: logging.info( 'this faction has not been active in the current semester yet. Setting defaults' ) faction.activeSeasonKeyId = active_season.key.id() faction.energy = FACTION_STARTING_ENERGY faction.materials = FACTION_STARTING_MATERIALS faction.control = FACTION_STARTING_CONTROL factionController.update(faction) if faction.activeSeasonKeyId != active_season.key.id(): ## this should hopefully not happen, keeping it here just in case logging.error( 'this faction has the wrong season applied. This should not happen. Make sure this gets cleared out on season change.' ) faction.activeSeasonKeyId = active_season.key.id() faction.energy = FACTION_STARTING_ENERGY faction.materials = FACTION_STARTING_MATERIALS faction.control = FACTION_STARTING_CONTROL factionController.update(faction) else: logging.info('faction not found - adding it') faction = factionController.create( tag=jsonobject['group_tag'], #title = ndb.StringProperty(indexed=False) #description = ndb.TextProperty(indexed=False) uetopia_groupKeyId=jsonobject['group_key_id'], activeSeasonKeyId=active_season.key.id(), energy=FACTION_STARTING_ENERGY, materials=FACTION_STARTING_MATERIALS, control=FACTION_STARTING_CONTROL) ## with a faction, make sure the user has this faction selected, and there were no changes to the users permissions user.currentFactionKeyId = faction.key.id() user.currentFactionTag = jsonobject['group_tag'] user.currentFactionLead = jsonobject['metagame_faction_lead'] user.currentFactionTeamLead = jsonobject['metagame_team_lead'] if 'team_key_id' in jsonobject: logging.info('Found team_key_id in json') user.currentTeamKeyId = jsonobject['team_key_id'] user.currentTeamCaptain = jsonobject['team_captain'] ## update the user record. user.metaGameActive = True ucontroller.update(user) ## push out to firebase taskUrl = '/task/user/firebase/update' taskqueue.add( url=taskUrl, queue_name='firebaseUpdate', params={'key_id': user.key.id()}, countdown=2, ) ## return status success so that uetopia knows the call worked. ## TODO - anything else we need to send back to the uetopia backend at this stage? ## custom json probably... return self.render_json_response(authorization=True, request_successful=True)