def test_given_score_and_ThreeDisapprovingReviewerOfWhichTwoAgree_then_NonAgreeingReviewerAndPLayerAreCheater(self): score = {'score' : 99, 'proof' : "sdsd", 'time' : 0} playerId = "test" createPlayer(playerId, playerId) service.start(playerId) service.setScore(playerId, score) playerKey = Key.from_path('Player', playerId) createReviewerAndReview("test2", playerKey, {'score':3, 'time': 0}) createReviewerAndReview("test3", playerKey, {'score':999, 'time': 0}) createReviewerAndReview("test4", playerKey, {'score':3, 'time': 0}) verifiedScore = VerifiedScore.get_by_key_name("verified", parent=playerKey) playerRecord = Record.get_by_key_name('record', parent=playerKey) self.assertTrue(verifiedScore is None or verifiedScore.value == 0) self.assertEqual(playerRecord.numCheat, 1) playerKey = Key.from_path('Player', 'test3') playerRecord = Record.get_by_key_name('record', parent=playerKey) self.assertEqual(playerRecord.numCheat, 1)
def test_given_score_and_TwoDisapprovingButNonAgreeingReviewerAndOneApprovingReviewer_then_NonApprovingReviewerAreCheater_and_playerVerifiedScoreIsUpdated(self): score = {'score' : 3, 'proof' : "sdsd", 'time' : 0} playerId = "test" createPlayer(playerId, playerId) service.start(playerId) service.setScore(playerId, score) playerKey = Key.from_path('Player', playerId) createReviewerAndReview("test2", playerKey, {'score':99, 'time': 0}) createReviewerAndReview("test3", playerKey, {'score':999, 'time': 0}) createReviewerAndReview("test4", playerKey, {'score':3, 'time': 0}) verifiedScoreWrapper = VerifiedScoreWrapper.get_by_key_name('verifiedScore', parent=playerKey) verifiedScore = verifiedScoreWrapper.verified self.assertEqual(verifiedScore.value, 3) playerKey = Key.from_path('Player', 'test2') playerRecord = Record.get_by_key_name('record', parent=playerKey) self.assertEqual(playerRecord.numCheat, 1) playerKey = Key.from_path('Player', 'test3') playerRecord = Record.get_by_key_name('record', parent=playerKey) self.assertEqual(playerRecord.numCheat, 1)
def test_given_aAdminReviewerTryingToReviewAsAdmin_ItShouldSucceedAndDeclareNonAgreeingConflictingReviewerAsCheaters(self): setReviewTimeUnit(0) score = {'score' : 99, 'proof' : "sdsd", 'time' : 0} playerId = "test" createPlayer(playerId, playerId) service.start(playerId) service.setScore(playerId, score) playerKey = Key.from_path('Player', playerId) createReviewerAndReview("test2", playerKey, {'score':3, 'time': 0}) createReviewerAndReview("test3", playerKey, {'score':999, 'time': 0}) createReviewerAndReview("test4", playerKey, {'score':3, 'time': 0}, True) verifiedScore = VerifiedScore.get_by_key_name("verified", parent=playerKey) playerRecord = Record.get_by_key_name('record', parent=playerKey) self.assertTrue(verifiedScore is None or verifiedScore.value == 0) self.assertEqual(playerRecord.numCheat, 1) playerKey = Key.from_path('Player', 'test3') playerRecord = Record.get_by_key_name('record', parent=playerKey) self.assertEqual(playerRecord.numCheat, 1) playerKey = Key.from_path('Player', 'test2') playerRecord = Record.get_by_key_name('record', parent=playerKey) self.assertEqual(playerRecord.numCheat, 0)
def test_given_aAdminReviewerDisapprovingAnAlreadyVerifiedScore_ItShouldDeclareVerifierAsACheaterAndOtherAsNonCheaters(self): setReviewTimeUnit(0) score = {'score' : 99, 'proof' : "sdsd", 'time' : 0} playerId = "test" createPlayer(playerId, playerId) service.start(playerId) service.setScore(playerId, score) playerKey = Key.from_path('Player', playerId) createReviewerAndReview("test2", playerKey, {'score':3, 'time': 0}) createReviewerAndReview("test3", playerKey, {'score':999, 'time': 0}) createReviewerAndReview("test4", playerKey, {'score':99, 'time': 0}) # verified verifiedScoreWrapper = VerifiedScoreWrapper.get_by_key_name('verifiedScore', parent=playerKey) verifiedScore = verifiedScoreWrapper.verified playerRecord = Record.get_by_key_name('record', parent=playerKey) self.assertTrue(verifiedScore.value == 99) self.assertEqual(playerRecord.numCheat, 0) createPlayer('admin1', 'admin1') admin = getAdmin() admin.playerList.append('admin1') setAdmin(admin) service.getHighestNonApprovedScore('admin1') service.approveScore('admin1', {'score':3, 'time': 0}) verifiedScoreWrapper = VerifiedScoreWrapper.get_by_key_name('verifiedScore', parent=playerKey) playerRecord = Record.get_by_key_name('record', parent=playerKey) self.assertTrue(verifiedScoreWrapper is None) self.assertEqual(playerRecord.numCheat, 1) playerKey = Key.from_path('Player', 'test3') playerRecord = Record.get_by_key_name('record', parent=playerKey) self.assertEqual(playerRecord.numCheat, 0) playerKey = Key.from_path('Player', 'test2') playerRecord = Record.get_by_key_name('record', parent=playerKey) self.assertEqual(playerRecord.numCheat, 0) playerKey = Key.from_path('Player', 'test4') playerRecord = Record.get_by_key_name('record', parent=playerKey) self.assertEqual(playerRecord.numCheat, 1)
def _start(): playerKey = Key.from_path('Player', playerId) rand = random.SystemRandom() seed = struct.pack("4L", rand.randint(1, MAX_INT32_VALUE), rand.randint(1, MAX_INT32_VALUE), rand.randint(1, MAX_INT32_VALUE), rand.randint(1, MAX_INT32_VALUE)) playSession = PlaySession(key_name='playSession', seed=seed, version=config.currentGameMechanicVersion, seedDateTime=datetime.datetime.now(), parent=playerKey) playSession.put() today = datetime.date.today() playerRecord = Record.get_by_key_name('record', parent=playerKey) if playerRecord.lastDayPlayed != today: playerRecord.numDaysPlayed += 1 playerRecord.lastDayPlayed = today playerRecord.put() seedList = struct.unpack("4L", playSession.seed) return {'result': {'seed': seedList, 'version': playSession.version}}
def _approveScore(): scoreToApprove = db.get(scoreToApproveKey) if scoreToApprove is None: return {'cheater': None, 'nonCheaters': []} approvedPlayerKey = scoreToApprove.parent_key() cheater = None nonCheaters = [] if scoreToApprove.value == scoreValue and scoreToApprove.time == scoreTime: scoreToApprove.approvedByAdmin = True scoreToApprove.put() else: approvedPlayerRecord = Record.get_by_key_name( 'record', parent=approvedPlayerKey) approvedPlayerRecord.numCheat += 1 approvedPlayerRecord.put() cheater = Key.from_path('Player', scoreToApprove.verifier) for nonCheaterId in scoreToApprove.conflictingReviewers: nonCheaters.append(Key.from_path('Player', nonCheaterId)) scoreToApprove.delete() db.delete( Key.from_path('VerifiedScoreWrapper', 'verifiedScore', parent=approvedPlayerKey)) return {'cheater': cheater, 'nonCheaters': nonCheaters}
def get(self): stats = getStats() lastPlayerRecords = Record.gql( "WHERE lastReviewAttemptDateTime > :firstDate ORDER BY lastReviewAttemptDateTime DESC", firstDate=datetime.datetime.min).fetch( 1, config.nbPlayerPerTimeUnit - 1) if lastPlayerRecords is None or len(lastPlayerRecords) == 0: stats = setDefaultStats() else: lastPlayerRecordConsidered = lastPlayerRecords[0] now = datetime.datetime.now() timedelta = now - lastPlayerRecordConsidered.lastReviewAttemptDateTime #milliseconds newReviewTimeUnit = (timedelta.microseconds + (timedelta.seconds + timedelta.days * 24 * 3600) * 10**6) / 10**3 reviewTimeUnitWeight = stats.reviewTimeUnitWeight stats.reviewTimeUnit = ( reviewTimeUnitWeight * stats.reviewTimeUnit + newReviewTimeUnit) / (reviewTimeUnitWeight + 1) stats.reviewTimeUnitWeight = reviewTimeUnitWeight + 1 setStats(stats) self.response.out.write(str(stats.reviewTimeUnit))
def test_given_goodScoreWithWrongTime_thenPlayerIsCheater(self): score = {'score' : 3, 'proof' : "sdsd", 'time' : 0} playerId = "test" createPlayer(playerId, playerId) service.start(playerId) service.setScore(playerId, score) playerKey = Key.from_path('Player', playerId) createReviewerAndReview("test2", playerKey, {'score':3, 'time': 3}) createReviewerAndReview("test3", playerKey, {'score':3, 'time': 3}) verifiedScore = VerifiedScore.get_by_key_name("verified", parent=playerKey) self.assertTrue(verifiedScore is None or verifiedScore.value == 0) playerRecord = Record.get_by_key_name('record', parent=playerKey) self.assertEqual(playerRecord.numCheat, 1)
def _start(): playerKey = Key.from_path('Player', playerId) rand = random.SystemRandom() seed = struct.pack("4L", rand.randint(1, MAX_INT32_VALUE), rand.randint(1, MAX_INT32_VALUE), rand.randint(1, MAX_INT32_VALUE), rand.randint(1, MAX_INT32_VALUE)) playSession = PlaySession(key_name='playSession', seed=seed, version=config.currentGameMechanicVersion, seedDateTime=datetime.datetime.now(), parent=playerKey) playSession.put() today = datetime.date.today() playerRecord = Record.get_by_key_name('record', parent=playerKey) if playerRecord.lastDayPlayed != today: playerRecord.numDaysPlayed += 1 playerRecord.lastDayPlayed = today playerRecord.put() seedList = struct.unpack("4L", playSession.seed) return {'result' : { 'seed' : seedList, 'version': playSession.version } }
def test_given_score_and_twoDisapprovingButAgreeingReviewers_then_playerIsCheater_and_verfiedScoreDoNotChange(self): score = {'score' : 99, 'proof' : "sdsd", 'time' : 0} playerId = "test" createPlayer(playerId, playerId) service.start(playerId) service.setScore(playerId, score) playerKey = Key.from_path('Player', playerId) createReviewerAndReview("test2", playerKey, {'score':3, 'time': 0}) createReviewerAndReview("test3", playerKey, {'score':3, 'time': 0}) verifiedScore = VerifiedScore.get_by_key_name("verified", parent=playerKey) self.assertTrue(verifiedScore is None or verifiedScore.value == 0) playerRecord = Record.get_by_key_name('record', parent=playerKey) self.assertEqual(playerRecord.numCheat, 1)
def _approveScore(): scoreToApprove = db.get(scoreToApproveKey) if scoreToApprove is None: return {'cheater' : None, 'nonCheaters': []} approvedPlayerKey = scoreToApprove.parent_key() cheater = None nonCheaters = [] if scoreToApprove.value == scoreValue and scoreToApprove.time == scoreTime: scoreToApprove.approvedByAdmin = True scoreToApprove.put() else: approvedPlayerRecord = Record.get_by_key_name('record', parent=approvedPlayerKey) approvedPlayerRecord.numCheat += 1 approvedPlayerRecord.put() cheater = Key.from_path('Player', scoreToApprove.verifier) for nonCheaterId in scoreToApprove.conflictingReviewers: nonCheaters.append(Key.from_path('Player', nonCheaterId)) scoreToApprove.delete() db.delete(Key.from_path('VerifiedScoreWrapper', 'verifiedScore', parent = approvedPlayerKey)) return {'cheater' : cheater, 'nonCheaters': nonCheaters}
def _cheaterUpdate(cheaterKey): cheaterRecord = Record.get_by_key_name('record', parent=cheaterKey) cheaterRecord.numCheat+=1 cheaterRecord.put()
def _cheaterUpdate(cheaterKey): cheaterRecord = Record.get_by_key_name('record', parent=cheaterKey) cheaterRecord.numCheat += 1 cheaterRecord.put()
def _checkConflicts(scoreToReviewKey, scoreValue, scoreTime, playerId, adminMode): playerKey = Key.from_path('Player', playerId) scoreToReview = db.get(scoreToReviewKey) if scoreToReview is None: return [] cheaters = [] conflictResolved = False if scoreToReview.value == scoreValue and scoreToReview.time == scoreTime: # delete the score (unverified) and reset a verifiedScore reviewedPlayerKey = scoreToReview.parent_key() verifiedScore = VerifiedScore( parent=reviewedPlayerKey, value=scoreToReview.value, proof=scoreToReview.proof, time=scoreToReview.time, seed=scoreToReview.seed, version=scoreToReview.version, conflictingReviewers=scoreToReview.conflictingReviewers, verifier=playerId, approvedByAdmin=adminMode) verifiedScore.put() verifiedScoreWrapper = VerifiedScoreWrapper.get_by_key_name( "verifiedScore", parent=reviewedPlayerKey) if verifiedScoreWrapper is None: verifiedScoreWrapper = VerifiedScoreWrapper( key_name='verifiedScore', parent=reviewedPlayerKey, verified=verifiedScore) else: verifiedScoreWrapper.verified.delete() verifiedScoreWrapper.verified = verifiedScore verifiedScoreWrapper.put() reviewedPlayerRecord = Record.get_by_key_name('record', parent=reviewedPlayerKey) reviewedPlayerRecord.numScoreVerified += 1 reviewedPlayerRecord.put() db.delete( Key.from_path('PendingScore', 'pendingScore', parent=reviewedPlayerKey)) #delete conflicts and set conflicting reviewers as cheater conflicts = ReviewConflict.gql("WHERE ANCESTOR IS :score", score=scoreToReview).fetch( 100) # shoud not be more than 2 for conflict in conflicts: if ReviewConflict.player.get_value_for_datastore( conflict) == playerKey and not adminMode: pass #TODO : raise Exception("this player has been able to review two times the same score!") if conflict.scoreValue != scoreValue or conflict.scoreTime != scoreTime: cheaters.append( ReviewConflict.player.get_value_for_datastore(conflict)) conflict.delete() scoreToReview.delete() conflictResolved = True else: #check whether a conflict exist with the same score value, if that is the case, player has cheated conflicts = ReviewConflict.gql("WHERE ANCESTOR IS :score", score=scoreToReview).fetch( 100) # should not be more than 3 if adminMode: conflictResolved = True # player is cheater no need to check anything else else: for conflict in conflicts: if ReviewConflict.player.get_value_for_datastore( conflict) == playerKey: pass #TODO : raise Exception("this player has been able to review two times the same score!") elif conflict.scoreValue == scoreValue and conflict.scoreTime == scoreTime: conflictResolved = True break #player is a cheater if conflictResolved: reviewedPlayerKey = scoreToReview.parent_key() reviewedPlayerRecord = Record.get_by_key_name( 'record', parent=reviewedPlayerKey) reviewedPlayerRecord.numCheat += 1 reviewedPlayerRecord.put() #remove stuffs and assign cheater status to reviewer for conflict in conflicts: if conflict.scoreValue != scoreValue or conflict.scoreTime != scoreTime: cheaters.append( ReviewConflict.player.get_value_for_datastore( conflict)) conflict.delete() scoreToReview.delete() db.delete( Key.from_path('PendingScore', 'pendingScore', parent=reviewedPlayerKey)) else: scoreToReview.conflictingReviewers.append(playerId) scoreToReview.put() newConflict = ReviewConflict(player=playerKey, scoreValue=scoreValue, scoreTime=scoreTime, parent=scoreToReview) newConflict.put() return cheaters
def approveScore(playerId, score): admin = getAdmin() try: admin.playerList.index(playerId) except ValueError: return getErrorResponse(ADMIN_ONLY) scoreValue = score['score'] scoreTime = score['time'] playerKey = Key.from_path('Player', playerId) approveSession = ApproveSession.get_by_key_name('approveSession', parent=playerKey) if approveSession is None: return getErrorResponse(NOTHING_TO_REVIEW) scoreToApproveKey = ApproveSession.currentScoreToApprove.get_value_for_datastore( approveSession) # We are done with it approveSession.delete() def _approveScore(): scoreToApprove = db.get(scoreToApproveKey) if scoreToApprove is None: return {'cheater': None, 'nonCheaters': []} approvedPlayerKey = scoreToApprove.parent_key() cheater = None nonCheaters = [] if scoreToApprove.value == scoreValue and scoreToApprove.time == scoreTime: scoreToApprove.approvedByAdmin = True scoreToApprove.put() else: approvedPlayerRecord = Record.get_by_key_name( 'record', parent=approvedPlayerKey) approvedPlayerRecord.numCheat += 1 approvedPlayerRecord.put() cheater = Key.from_path('Player', scoreToApprove.verifier) for nonCheaterId in scoreToApprove.conflictingReviewers: nonCheaters.append(Key.from_path('Player', nonCheaterId)) scoreToApprove.delete() db.delete( Key.from_path('VerifiedScoreWrapper', 'verifiedScore', parent=approvedPlayerKey)) return {'cheater': cheater, 'nonCheaters': nonCheaters} try: result = db.run_in_transaction(_approveScore) except TransactionFailedError: return getErrorResponse(APPROVESCORE_TRANSACTION_FAILURE, 0) cheater = result['cheater'] nonCheaters = result['nonCheaters'] if cheater is not None: cheaterRecord = Record.get_by_key_name('record', parent=cheater) cheaterRecord.numCheat += 1 cheaterRecord.put() if nonCheaters: def _nonCheaterUpdate(nonCheaterKey): cheaterRecord = Record.get_by_key_name('record', parent=nonCheaterKey) cheaterRecord.numCheat -= 1 cheaterRecord.put() for nonCheaterKey in nonCheaters: db.run_in_transaction(_nonCheaterUpdate, nonCheaterKey) return {'result': {'message': 'approvement submited'}}
def _nonCheaterUpdate(nonCheaterKey): cheaterRecord = Record.get_by_key_name('record', parent=nonCheaterKey) cheaterRecord.numCheat -= 1 cheaterRecord.put()
def _nonCheaterUpdate(nonCheaterKey): cheaterRecord = Record.get_by_key_name('record', parent=nonCheaterKey) cheaterRecord.numCheat-=1 cheaterRecord.put()
def approveScore(playerId, score): admin = getAdmin() try: admin.playerList.index(playerId) except ValueError: return getErrorResponse(ADMIN_ONLY) scoreValue = score['score'] scoreTime = score['time'] playerKey = Key.from_path('Player', playerId) approveSession = ApproveSession.get_by_key_name('approveSession', parent=playerKey) if approveSession is None: return getErrorResponse(NOTHING_TO_REVIEW) scoreToApproveKey = ApproveSession.currentScoreToApprove.get_value_for_datastore(approveSession) # We are done with it approveSession.delete() def _approveScore(): scoreToApprove = db.get(scoreToApproveKey) if scoreToApprove is None: return {'cheater' : None, 'nonCheaters': []} approvedPlayerKey = scoreToApprove.parent_key() cheater = None nonCheaters = [] if scoreToApprove.value == scoreValue and scoreToApprove.time == scoreTime: scoreToApprove.approvedByAdmin = True scoreToApprove.put() else: approvedPlayerRecord = Record.get_by_key_name('record', parent=approvedPlayerKey) approvedPlayerRecord.numCheat += 1 approvedPlayerRecord.put() cheater = Key.from_path('Player', scoreToApprove.verifier) for nonCheaterId in scoreToApprove.conflictingReviewers: nonCheaters.append(Key.from_path('Player', nonCheaterId)) scoreToApprove.delete() db.delete(Key.from_path('VerifiedScoreWrapper', 'verifiedScore', parent = approvedPlayerKey)) return {'cheater' : cheater, 'nonCheaters': nonCheaters} try: result = db.run_in_transaction(_approveScore) except TransactionFailedError: return getErrorResponse(APPROVESCORE_TRANSACTION_FAILURE, 0) cheater = result['cheater'] nonCheaters = result['nonCheaters'] if cheater is not None: cheaterRecord = Record.get_by_key_name('record', parent=cheater) cheaterRecord.numCheat+=1 cheaterRecord.put() if nonCheaters: def _nonCheaterUpdate(nonCheaterKey): cheaterRecord = Record.get_by_key_name('record', parent=nonCheaterKey) cheaterRecord.numCheat-=1 cheaterRecord.put() for nonCheaterKey in nonCheaters: db.run_in_transaction(_nonCheaterUpdate,nonCheaterKey) return {'result' : { 'message' : 'approvement submited'} }
def _increaseNumScoreReviewed(): playerRecord = Record.get_by_key_name('record', parent=playerKey) playerRecord.numScoreReviewed += 1 playerRecord.put()
def getRandomScore(playerId): playerKey = Key.from_path('Player', playerId) playerRecord = Record.get_by_key_name('record', parent=playerKey) # do not review if you are a cheater if playerRecord.numCheat > 0: return getErrorResponse(CHEATER_BLOCKED) reviewTimeUnitMilliseconds = getReviewTimeUnit() reviewTimeUnit = datetime.timedelta(milliseconds=reviewTimeUnitMilliseconds) now =datetime.datetime.now() oldEnoughTime = now - reviewTimeUnit delay = 2000 + random.random() * 5000 + ceil(reviewTimeUnitMilliseconds * (1 + random.random() * 2)) if delay > MAX_INT32_VALUE: delay = MAX_INT32_VALUE def _updateLastReviewAttemptDateTime(): if playerRecord.lastReviewAttemptDateTime is not None and playerRecord.lastReviewAttemptDateTime > oldEnoughTime: # TODO : check whethe rthis randomize stuff is good or not: return {'result' : {'message' : 'You already posted enough reviews, retry later', 'retry' : delay } } # could be 2 * reviewTimeUnit / config.nbPlayerPerTimeUnit playerRecord.lastReviewAttemptDateTime = datetime.datetime.now() playerRecord.put() return None reviewSession = ReviewSession.get_by_key_name('reviewSession', parent=playerKey) if reviewSession is None: try: result = db.run_in_transaction(_updateLastReviewAttemptDateTime) except TransactionFailedError: result = getErrorResponse(LASTREVIEWUPDATE_TRANSACTION_FAILURE, 0) if result is not None: return result # do not allow reviewer to jump on a just posted review. basically the reviewer should have lots of potential review to take from and other reviewer shoudl compete with potentialScoresToReview = db.GqlQuery("SELECT * FROM NonVerifiedScore WHERE dateTime < :oldEnoughTime ORDER BY dateTime ASC", oldEnoughTime=oldEnoughTime).fetch(5) scoreToReview = None for score in potentialScoresToReview: if score.parent_key() != playerKey: try: score.conflictingReviewers.index(playerId) except ValueError: # the current reviewer did not review this score yet scoreToReview = score break if scoreToReview is None: return {'result' : {'message' : 'Nothing to review for now', 'retry' : delay } } reviewSession = ReviewSession(key_name='reviewSession', currentScoreToReview=scoreToReview, parent=playerKey) reviewSession.put() else: try: scoreToReview = reviewSession.currentScoreToReview except ReferencePropertyResolveError: scoreToReview = None # in case score has been approved just now, it could have been removed if scoreToReview is not None: seedList = struct.unpack("4L", scoreToReview.seed) return {'result' : { 'proof' : scoreToReview.proof, 'seed' : seedList, 'version' : scoreToReview.version} } return {'result' : {'message' : 'Nothing to review for now (just done)', 'retry' : delay} }
def _checkConflicts(scoreToReviewKey, scoreValue, scoreTime, playerId, adminMode): playerKey = Key.from_path('Player', playerId) scoreToReview = db.get(scoreToReviewKey) if scoreToReview is None: return [] cheaters = [] conflictResolved = False if scoreToReview.value == scoreValue and scoreToReview.time == scoreTime: # delete the score (unverified) and reset a verifiedScore reviewedPlayerKey = scoreToReview.parent_key() verifiedScore = VerifiedScore(parent=reviewedPlayerKey, value=scoreToReview.value, proof=scoreToReview.proof, time=scoreToReview.time, seed=scoreToReview.seed, version=scoreToReview.version, conflictingReviewers=scoreToReview.conflictingReviewers, verifier=playerId, approvedByAdmin=adminMode) verifiedScore.put() verifiedScoreWrapper = VerifiedScoreWrapper.get_by_key_name("verifiedScore", parent=reviewedPlayerKey) if verifiedScoreWrapper is None: verifiedScoreWrapper = VerifiedScoreWrapper(key_name='verifiedScore', parent=reviewedPlayerKey, verified=verifiedScore) else: verifiedScoreWrapper.verified.delete() verifiedScoreWrapper.verified = verifiedScore verifiedScoreWrapper.put() reviewedPlayerRecord = Record.get_by_key_name('record', parent=reviewedPlayerKey) reviewedPlayerRecord.numScoreVerified += 1 reviewedPlayerRecord.put() db.delete(Key.from_path('PendingScore', 'pendingScore', parent = reviewedPlayerKey)) #delete conflicts and set conflicting reviewers as cheater conflicts = ReviewConflict.gql("WHERE ANCESTOR IS :score", score=scoreToReview).fetch(100) # shoud not be more than 2 for conflict in conflicts: if ReviewConflict.player.get_value_for_datastore(conflict) == playerKey and not adminMode: pass #TODO : raise Exception("this player has been able to review two times the same score!") if conflict.scoreValue != scoreValue or conflict.scoreTime != scoreTime: cheaters.append(ReviewConflict.player.get_value_for_datastore(conflict)) conflict.delete() scoreToReview.delete() conflictResolved = True else: #check whether a conflict exist with the same score value, if that is the case, player has cheated conflicts = ReviewConflict.gql("WHERE ANCESTOR IS :score", score=scoreToReview).fetch(100) # should not be more than 3 if adminMode: conflictResolved = True # player is cheater no need to check anything else else: for conflict in conflicts: if ReviewConflict.player.get_value_for_datastore(conflict) == playerKey: pass #TODO : raise Exception("this player has been able to review two times the same score!") elif conflict.scoreValue == scoreValue and conflict.scoreTime == scoreTime: conflictResolved = True break #player is a cheater if conflictResolved: reviewedPlayerKey = scoreToReview.parent_key() reviewedPlayerRecord = Record.get_by_key_name('record', parent=reviewedPlayerKey) reviewedPlayerRecord.numCheat+=1 reviewedPlayerRecord.put() #remove stuffs and assign cheater status to reviewer for conflict in conflicts: if conflict.scoreValue != scoreValue or conflict.scoreTime != scoreTime: cheaters.append(ReviewConflict.player.get_value_for_datastore(conflict)) conflict.delete() scoreToReview.delete() db.delete(Key.from_path('PendingScore', 'pendingScore', parent = reviewedPlayerKey)) else: scoreToReview.conflictingReviewers.append(playerId) scoreToReview.put() newConflict = ReviewConflict(player=playerKey,scoreValue=scoreValue,scoreTime=scoreTime, parent=scoreToReview) newConflict.put() return cheaters
def getRandomScore(playerId): playerKey = Key.from_path('Player', playerId) playerRecord = Record.get_by_key_name('record', parent=playerKey) # do not review if you are a cheater if playerRecord.numCheat > 0: return getErrorResponse(CHEATER_BLOCKED) reviewTimeUnitMilliseconds = getReviewTimeUnit() reviewTimeUnit = datetime.timedelta( milliseconds=reviewTimeUnitMilliseconds) now = datetime.datetime.now() oldEnoughTime = now - reviewTimeUnit delay = 2000 + random.random() * 5000 + ceil(reviewTimeUnitMilliseconds * (1 + random.random() * 2)) if delay > MAX_INT32_VALUE: delay = MAX_INT32_VALUE def _updateLastReviewAttemptDateTime(): if playerRecord.lastReviewAttemptDateTime is not None and playerRecord.lastReviewAttemptDateTime > oldEnoughTime: # TODO : check whethe rthis randomize stuff is good or not: return { 'result': { 'message': 'You already posted enough reviews, retry later', 'retry': delay } } # could be 2 * reviewTimeUnit / config.nbPlayerPerTimeUnit playerRecord.lastReviewAttemptDateTime = datetime.datetime.now() playerRecord.put() return None reviewSession = ReviewSession.get_by_key_name('reviewSession', parent=playerKey) if reviewSession is None: try: result = db.run_in_transaction(_updateLastReviewAttemptDateTime) except TransactionFailedError: result = getErrorResponse(LASTREVIEWUPDATE_TRANSACTION_FAILURE, 0) if result is not None: return result # do not allow reviewer to jump on a just posted review. basically the reviewer should have lots of potential review to take from and other reviewer shoudl compete with potentialScoresToReview = db.GqlQuery( "SELECT * FROM NonVerifiedScore WHERE dateTime < :oldEnoughTime ORDER BY dateTime ASC", oldEnoughTime=oldEnoughTime).fetch(5) scoreToReview = None for score in potentialScoresToReview: if score.parent_key() != playerKey: try: score.conflictingReviewers.index(playerId) except ValueError: # the current reviewer did not review this score yet scoreToReview = score break if scoreToReview is None: return { 'result': { 'message': 'Nothing to review for now', 'retry': delay } } reviewSession = ReviewSession(key_name='reviewSession', currentScoreToReview=scoreToReview, parent=playerKey) reviewSession.put() else: try: scoreToReview = reviewSession.currentScoreToReview except ReferencePropertyResolveError: scoreToReview = None # in case score has been approved just now, it could have been removed if scoreToReview is not None: seedList = struct.unpack("4L", scoreToReview.seed) return { 'result': { 'proof': scoreToReview.proof, 'seed': seedList, 'version': scoreToReview.version } } return { 'result': { 'message': 'Nothing to review for now (just done)', 'retry': delay } }