def test_cant_overwrite_list(self): table_id, user = self.setup_quiz(p_min=5, p_max=15, length=8) wwg = WordwallsGame() # Try saving the word list. LIST_NAME = 'This is my NWL list.' resp = wwg.save(user, table_id, LIST_NAME) self.assertFalse(resp['success'])
def named_lists_submit(user, post): lexForm = LexiconForm(post) timeForm = TimeForm(post) nlForm = NamedListForm(post) if not (lexForm.is_valid() and timeForm.is_valid() and nlForm.is_valid()): return response({ 'success': False, 'error': 'Please check that you have selected a ' 'list and that your quiz time is greater ' 'than 1 minute.' }) lex = Lexicon.objects.get(lexiconName=lexForm.cleaned_data['lexicon']) quizTime = int(round(timeForm.cleaned_data['quizTime'] * 60)) wwg = WordwallsGame() tablenum = wwg.initializeByNamedList(lex, user, nlForm.cleaned_data['namedList'], quizTime) if tablenum == 0: raise Http404 return response({ 'url': reverse('wordwalls_table', args=(tablenum, )), 'success': True })
def table_rpc(request, tableid): body = json.loads(request.body) req_id = body.get('id', 0) if body.get('jsonrpc') != '2.0': return bad_rpc_response(req_id, 'Wrong RPC version') method = body.get('method') params = body.get('params') if not method: return bad_rpc_response(req_id, 'Bad RPC method') wwg = WordwallsGame() permitted = wwg.allow_access(request.user, tableid) if not permitted: return bad_rpc_response(req_id, 'No access to table {}'.format(tableid)) handler = method_lookup(method) if not handler: return bad_rpc_response(req_id, 'RPC method {} does not exist.'.format(method)) try: ret = handler(request.user, tableid, params) except RPCError as e: return bad_rpc_response(req_id, str(e)) return rpc_response(req_id, ret)
def search_params_submit(user, post): """ Called when user submits a search params query. """ lexForm = LexiconForm(post) timeForm = TimeForm(post) fwForm = FindWordsForm(post) # form bound to the POST data if not (lexForm.is_valid() and timeForm.is_valid() and fwForm.is_valid()): return response({ 'success': False, 'error': 'There was something wrong with your ' 'search parameters or time selection.' }) lex = Lexicon.objects.get(lexiconName=lexForm.cleaned_data['lexicon']) quizTime = int(round(timeForm.cleaned_data['quizTime'] * 60)) alphasSearchDescription = searchForAlphagrams(fwForm.cleaned_data, lex) wwg = WordwallsGame() tablenum = wwg.initializeBySearchParams(user, alphasSearchDescription, quizTime) return response({ 'url': reverse('wordwalls_table', args=(tablenum, )), 'success': True })
def challenge_submit(user, post): """ Called when a challenge is submitted. """ lexForm = LexiconForm(post) dcForm = DailyChallengesForm(post) if not (lexForm.is_valid() and dcForm.is_valid()): return response({ 'success': False, 'error': 'No challenge was selected.' }) lex = Lexicon.objects.get(lexiconName=lexForm.cleaned_data['lexicon']) wwg = WordwallsGame() challengeName = DailyChallengeName.objects.get( name=dcForm.cleaned_data['challenge']) chDate = dcForm.cleaned_data['challengeDate'] if not chDate or chDate > date.today(): chDate = date.today() tablenum = wwg.initializeByDailyChallenge(user, lex, challengeName, chDate) if tablenum == 0: return response({ 'success': False, 'error': 'Challenge does not exist.' }) return response({ 'url': reverse('wordwalls_table', args=(tablenum, )), 'success': True })
def test_guess_same_word(self): table_id, user = self.setup_quiz(p_min=5, p_max=15, length=8) wwg = WordwallsGame() with transaction.atomic(): wwg.start_quiz(table_id, user) def guess_fn(w, user): with closing(connection): with transaction.atomic(): wwg.guess(w, table_id, user, sleep=1) user_1 = User.objects.get(username='******') user_2 = User.objects.get(username='******') threads = [] word = 'ELATIONS' threads.append(threading.Thread(target=guess_fn, args=(word, user))) threads.append(threading.Thread(target=guess_fn, args=(word, user_1))) threads.append(threading.Thread(target=guess_fn, args=(word, user_2))) for t in threads: t.start() for t in threads: t.join() st = wwg.state(table_id) self.assertFalse(word in st['answerHash']) self.assertTrue(word in st['originalAnswerHash']) self.assertTrue(word in st['solvers']) self.assertTrue( st['solvers'][word] in ['cesar', 'user_4738', 'user_131'])
def round_1(self): table_id, user = self.setup_quiz(p_min=5, p_max=15, length=8) wwg = WordwallsGame() # Let's guess some of the words from the 5-15 range words_to_guess = [ 'ABCDEFGH', # miss AEROLITE 'IDOLATER', # miss TAILORED 'OUTRAISE', 'SAUTOIRE', 'ALIENORS', 'AILERONS', '', # miss ANEROIDS/ANODISER 'SEDATION', # miss ASTONIED 'DELATION', '', # miss all of the AEILNOST words. 'ASTEROID', 'ELATERIN', # miss ENTAILER and TREENAIL 'DETAINER', 'RETAINED' ] # Guess all the words 3 times. (5, 5 and 1) for i in range(3): params = wwg.start_quiz(table_id, user) if i != 2: self.assertEqual(len(params['questions']), 5) else: self.assertEqual(len(params['questions']), 1) for w in words_to_guess: wwg.guess(w, table_id, user) wwg.give_up(user, table_id) return table_id, user
def test_continue_unfinished_list(self): LIST_NAME = "i live in a giant bucket" word_list = WordList.objects.get(name=LIST_NAME) # Continue the list. table_id = self.wwg.initialize_by_saved_list( self.lex, self.user, word_list, SavedListForm.CONTINUE_LIST_CHOICE, 240) word_list = WordList.objects.get(name=LIST_NAME) self.assert_wl(word_list, { 'numAlphagrams': 11, 'numCurAlphagrams': 11, 'numFirstMissed': 0, 'numMissed': 3, 'goneThruOnce': False, 'questionIndex': 10, 'is_temporary': False, 'name': LIST_NAME }) # Start the quiz; we should only get one question. wwg = WordwallsGame() params = wwg.start_quiz(table_id, self.user) self.assertEqual(len(params['questions']), 1) self.assertEqual(params['questions'][0]['a'], 'AEIORSTU') # Miss it. gave_up = wwg.give_up(self.user, table_id) self.assertTrue(gave_up) word_list = WordList.objects.get(name=LIST_NAME) self.assert_wl(word_list, { 'numAlphagrams': 11, 'numCurAlphagrams': 11, 'numFirstMissed': 4, 'numMissed': 4, 'goneThruOnce': True, 'questionIndex': 15, 'is_temporary': False, 'name': LIST_NAME, }) self.assertEqual(set([0, 2, 3, 10]), set(json.loads(word_list.firstMissed)))
def table(request, tableid=None): if request.method == 'POST': return handle_table_post(request, tableid) # Otherwise, it's a GET wwg = WordwallsGame() if tableid: # Check if the user is allowed to enter this table. permitted = wwg.allow_access(request.user, tableid) if gargoyle.is_active('disable_games', request): permitted = False if not permitted: return render(request, 'wordwalls/notPermitted.html', {'tablenum': tableid}) params = wwg.get_add_params(tableid) # Add styling params from user's profile (for styling table # tiles, backgrounds, etc) profile = request.user.aerolithprofile style = profile.customWordwallsStyle if style != "": params['style'] = style meta_info = get_create_meta_info() usermeta = get_user_meta_info(request.user) wgm = None if tableid: wgm = wwg.get_wgm(tableid, False) return render( request, 'wordwalls/table.html', { 'tablenum': tableid if tableid else 0, 'current_host': wgm.host.username if wgm else '', 'multiplayer': (json.dumps(wgm.playerType == WordwallsGameModel. MULTIPLAYER_GAME if wgm else False)), 'user': json.dumps(usermeta), 'addParams': json.dumps(params), 'avatarUrl': profile.avatarUrl, 'lexicon': wgm.lexicon.lexiconName if wgm else None, 'default_lexicon': profile.defaultLexicon.pk, 'challenge_info': json.dumps(meta_info['challenge_info']), 'available_lexica': json.dumps(meta_info['lexica']), 'intercom_app_id': settings.INTERCOM_APP_ID, # Use the webpack server if DEBUG is on. XXX This might not actually # be a good test; consider using an IS_PRODUCTION flag. 'STATIC_SRV': (settings.WEBPACK_DEV_SERVER_URL if (settings.USE_WEBPACK_DEV_SERVER and settings.DEBUG) else '') })
def test_missed_behavior(self): wwg = WordwallsGame() table_id, user = self.round_1() wgm = wwg.get_wgm(table_id) word_list = wgm.word_list self.assert_wl(word_list, { 'numAlphagrams': 11, 'numCurAlphagrams': 11, 'numFirstMissed': 6, 'numMissed': 6, 'goneThruOnce': True, 'questionIndex': 15, 'is_temporary': True }) qs = json.loads(word_list.origQuestions) self.assertEqual(len(qs), 11) # Now start the quiz again. Should get missed words. self.round_2(table_id, user) wgm = wwg.get_wgm(table_id) word_list = wgm.word_list self.assert_wl(word_list, { 'numAlphagrams': 11, 'numCurAlphagrams': 6, 'numFirstMissed': 6, 'numMissed': 2, 'goneThruOnce': True, 'questionIndex': 10, 'is_temporary': True }) qs = json.loads(word_list.origQuestions) self.assertEqual(len(qs), 11) # Finally, let's solve the final two alphagrams. self.round_3(table_id, user) wgm = wwg.get_wgm(table_id) word_list = wgm.word_list self.assert_wl(word_list, { 'numAlphagrams': 11, 'numCurAlphagrams': 2, 'numFirstMissed': 6, 'numMissed': 0, 'goneThruOnce': True, 'questionIndex': 5, 'is_temporary': True }) # And try to start the quiz again. params = wwg.start_quiz(table_id, user) self.assertTrue('quiz is done' in params['error']) wgm = wwg.get_wgm(table_id) word_list = wgm.word_list self.assert_wl(word_list, { 'numAlphagrams': 11, 'numCurAlphagrams': 0, 'numFirstMissed': 6, 'numMissed': 0, 'goneThruOnce': True, 'questionIndex': 0, 'is_temporary': True }) # Try saving the word list. LIST_NAME = 'my cool lišt' resp = wwg.save(user, table_id, LIST_NAME) self.assertTrue(resp['success']) self.assertEqual(resp['listname'], LIST_NAME) wgm = wwg.get_wgm(table_id) word_list = wgm.word_list self.assert_wl(word_list, { 'numAlphagrams': 11, 'numCurAlphagrams': 0, 'numFirstMissed': 6, 'numMissed': 0, 'goneThruOnce': True, 'questionIndex': 0, 'is_temporary': False, 'name': LIST_NAME })
def test_replace_challenge(self): result = self.client.post('/wordwalls/api/new_challenge/', data=json.dumps({ 'lexicon': 9, 'challenge': 14, 'date': '2013-11-29', 'tablenum': 0 }), content_type='application/json') self.assertEqual(result.status_code, 200) content = json.loads(result.content) response = self.client.get('/wordwalls/table/{0}/'.format( content['tablenum'])) addl_params = json.loads(response.context['addParams']) tablenum = int(response.context['tablenum']) self.assertEqual(addl_params['tempListName'], 'NWL18 Today\'s 15s - 2013-11-29') game = WordwallsGame() old_word_list = game.get_wgm(tablenum, lock=False).word_list self.assertTrue(old_word_list.is_temporary) self.assertTrue(old_word_list.pk > 0) old_pk = old_word_list.pk result = self.client.post('/wordwalls/api/new_challenge/', data=json.dumps({ 'tablenum': tablenum, 'lexicon': 12, 'challenge': 7, 'date': '2016-10-12' }), content_type='application/json') result_obj = json.loads(result.content) self.assertEqual(result_obj['tablenum'], tablenum) expected_list_name = 'CSW19 Today\'s 8s - 2016-10-12' self.assertEqual(result_obj['list_name'], expected_list_name) self.assertFalse(result_obj['autosave']) game = WordwallsGame() wl = game.get_wgm(tablenum, lock=False).word_list orig_questions = json.loads(wl.origQuestions) self.assertEqual(len(orig_questions), 50) self.assertEqual(len(orig_questions[28]['q']), 8) # Check that old word list got deleted. with self.assertRaises(WordwallsGameModel.DoesNotExist): WordwallsGameModel.objects.get(pk=old_pk)
def start(user, tableid, params): wwg = WordwallsGame() quiz_params = wwg.start_quiz(tableid, user) if 'error' in quiz_params: raise RPCError(quiz_params['error']) # If this is a multiplayer game, should broadcast to group. # if wwg.is_multiplayer(tableid): # broadcast_to_table(tableid, BroadcastTypes.GAME_PAYLOAD, quiz_params) return quiz_params
def api_answers(request): if request.method != "GET": return bad_request("Must use GET.") tablenum = request.GET.get("tablenum") wwg = WordwallsGame() answer_list = wwg.answer_list(tablenum) if answer_list: return response(answer_list) return bad_request("Could not fetch answer list")
def access_to_table(tablenum, user): """Return whether user has access to table. For now we just use the wordwalls game model. We should fix the logic for multiplayer afterwards.""" if tablenum == 0: # A table num of 0 implies that the user is not currently in a # table. Return true to allow the logic to proceed. return True game = WordwallsGame() return game.allow_access(user, tablenum)
def test_continue_finished_list(self): """ Continue a list that is tested through all the way.""" LIST_NAME = 'This is my list.' word_list = WordList.objects.get(name=LIST_NAME) table_id = self.wwg.initialize_by_saved_list( self.lex, self.user, word_list, SavedListForm.CONTINUE_LIST_CHOICE, 240) self.assertNotEqual(table_id, 0) wwg = WordwallsGame() params = wwg.start_quiz(table_id, self.user) self.assertTrue('quiz is done' in params['error'])
def test_quiz_ends_after_time(self, timer_ran_out): # Mock timer running out by the time the guess comes in. timer_ran_out.return_value = True table_id, user = self.setup_quiz() wwg = WordwallsGame() wwg.start_quiz(table_id, user) guess_state = wwg.guess('CATS', table_id, user) self.assertFalse(guess_state['going']) self.assertEqual(guess_state['alphagram'], '') wgm = wwg.get_wgm(table_id) state = json.loads(wgm.currentGameState) self.assertFalse(state['quizGoing'])
def test_quiz_params_correct(self): table_id, user = self.setup_quiz() wwg = WordwallsGame() params = wwg.start_quiz(table_id, user) self.assertEqual(len(params['questions']), 50) self.assertEqual(params['time'], 240) self.assertEqual(params['gameType'], 'regular') self.assertEqual(params['serverMsg'], 'These are questions 1 through 50 of 81.') guess_state = wwg.guess('CATS', table_id, user) self.assertTrue(guess_state['going']) self.assertEqual(guess_state['alphagram'], '')
def api_challengers_by_tablenum(request): if request.method != "GET": return bad_request("Must use GET.") tablenum = request.GET.get("tablenum") tiebreaker = request.GET.get("tiebreaker", "errors") wwg = WordwallsGame() dc_id = wwg.get_dc_id(tablenum) if dc_id > 0: dc = DailyChallenge.objects.get(pk=dc_id) leaderboard_data = get_leaderboard_data_for_dc_instance(dc, tiebreaker) return response(leaderboard_data) return bad_request("No such daily challenge.")
def load_raw_questions(request, parsed_req_body): try: tablenum = WordwallsGame().initialize_by_raw_questions( parsed_req_body["lexicon"], request.user, parsed_req_body["raw_questions"], parsed_req_body["quiz_time_secs"], parsed_req_body["questions_per_round"], use_table=parsed_req_body["tablenum"], multiplayer=parsed_req_body["multiplayer"], ) except GameInitException as e: return bad_request(str(e)) return table_response(tablenum)
def test_firstmissed_allowed(self): LIST_NAME = 'list the sécond' word_list = WordList.objects.get(name=LIST_NAME) table_id = self.wwg.initialize_by_saved_list( self.lex, self.user, word_list, SavedListForm.FIRST_MISSED_CHOICE, 240) self.assertNotEqual(table_id, 0) wwg = WordwallsGame() params = wwg.start_quiz(table_id, self.user) self.assertEqual(len(params['questions']), 6) self.assertEqual( set([q['a'] for q in params['questions']]), set(['AEEILORT', 'AEEILNRT', 'ADEINOST', 'ADEINORS', 'AEILNOST', 'ADEILORT']))
def start_game(request, id): if gargoyle.is_active('disable_games', request): return response({ 'serverMsg': 'Unable to start game as this is temporarily ' 'disabled. Please try again in a few minutes.' }) wwg = WordwallsGame() gameReady = wwg.startRequest(request.user, id) if not gameReady: return response({"serverMsg": request.user.username}) else: quizParams = wwg.startQuiz(id, request.user) return response(quizParams)
def test_can_save_loaded_list(self): """ Can we save a list we just loaded? """ LIST_NAME = 'list the sécond' num_lists_before = WordList.objects.filter(user=self.user).count() word_list = WordList.objects.get(name=LIST_NAME) table_id = self.wwg.initialize_by_saved_list( self.lex, self.user, word_list, SavedListForm.CONTINUE_LIST_CHOICE, 240) self.assertNotEqual(table_id, 0) wwg = WordwallsGame() resp = wwg.save(self.user, table_id, LIST_NAME) self.assertTrue(resp['success']) self.assertEqual(resp['listname'], LIST_NAME) self.assertEqual(num_lists_before, WordList.objects.filter(user=self.user).count())
def handle_table_post(request, tableid): """ XXX: This function should be separated into several RPC style API functions. See rpc.py. """ action = request.POST['action'] logger.info('user=%s, action=%s, table=%s', request.user, action, tableid) if not tableid or int(tableid) == 0: # Kind of hacky. return response( { 'success': False, 'error': _('Table does not exist, please load a new word list.') }, status=StatusCode.BAD_REQUEST) if action == "save": wwg = WordwallsGame() ret = wwg.save(request.user, tableid, request.POST['listname']) return response(ret) elif action == "giveUpAndSave": wwg = WordwallsGame() ret = wwg.give_up_and_save(request.user, tableid, request.POST['listname']) logger.info("Give up and saving returned: %s", ret) return response(ret) elif action == "savePrefs": # XXX: Obsolete me, replace with a direct post to a prefs endpoint profile = request.user.aerolithprofile profile.customWordwallsStyle = request.POST['prefs'] profile.save() return response({'success': True}) return response({ 'success': False, 'error': _('Unhandled action.') }, status=StatusCode.BAD_REQUEST)
def setup_quiz(self, p_min=10, p_max=90, length=8): """ A helper function to start a quiz. """ wwg = WordwallsGame() user = User.objects.get(username='******') lex = Lexicon.objects.get(lexiconName='NWL18') search = [ SearchDescription.lexicon(lex), SearchDescription.length(length, length), SearchDescription.probability_range(p_min, p_max) ] logger.debug('In setup_quiz, word lists: %s', WordList.objects.all()) table_id = wwg.initialize_by_search_params(user, search, 240) return table_id, user
def test_range_list_long(self): table_id = self.wwg.initialize_by_named_list( self.lex, self.user, NamedList.objects.get(pk=3099), 240) self.assertNotEqual(table_id, 0) wgm = self.wwg.get_wgm(table_id) word_list = wgm.word_list self.assert_wl(word_list, { 'numAlphagrams': 21063, 'numCurAlphagrams': 21063, 'numFirstMissed': 0, 'numMissed': 0, 'goneThruOnce': False, 'questionIndex': 0, 'is_temporary': True }) orig_questions = set(json.dumps(q) for q in json.loads(word_list.origQuestions)) self.assertEqual(len(orig_questions), 21063) # Start the quiz. wwg = WordwallsGame() params = wwg.start_quiz(table_id, self.user) self.assertEqual(len(params['questions']), 50)
def log(request): body = json.loads(request.body) if body['type'] == 'nothost': tablenum = body['tablenum'] current_host = body['currentHost'] username = body['username'] multiplayer = body['tableIsMultiplayer'] wgm = None if tablenum: wwg = WordwallsGame() wgm = wwg.get_wgm(tablenum, False) actual_host = wgm.host.username if wgm.host else None players_in = ', '.join([u.username for u in wgm.inTable.all()]) logger.info( '[event=nothost] tablenum=%s current_host=%s username=%s ' 'multiplayer=%s actual_host=%s players_in="%s"', tablenum, current_host, username, multiplayer, actual_host, players_in) return response('OK')
def guess(user, tableid, params): g = params['guess'] wrong_answers = params.get('wrongAnswers', 0) wwg = WordwallsGame() state = wwg.guess(g.strip(), tableid, user, wrong_answers=wrong_answers) if state is None: raise RPCError('Quiz is already over.') game_packet = { 'g': state['going'], 'C': state['alphagram'], 'w': state['word'], 'a': state['already_solved'], 's': state['solver'] } # If this is a multiplayer game, should broadcast to group. # if wwg.is_multiplayer(tableid): # broadcast_to_table(tableid, BroadcastTypes.GUESS_RESPONSE, game_packet) return game_packet
def test_word_list_created(self): logger.debug('In test_word_list_created') table_id, user = self.setup_quiz() wwg = WordwallsGame() wgm = wwg.get_wgm(table_id) word_list = wgm.word_list self.assert_wl(word_list, { 'version': 2, 'lexicon': Lexicon.objects.get(lexiconName='NWL18'), 'user': user, 'numAlphagrams': 81, 'numCurAlphagrams': 81, 'numFirstMissed': 0, 'numMissed': 0, 'goneThruOnce': False, 'questionIndex': 0, 'is_temporary': True }) # The name should be a random uuid. self.assertEqual(len(word_list.name), 32) qs = json.loads(word_list.origQuestions) self.assertEqual(len(qs), 81) # Search for one in particular self.assertTrue({'q': 'AEEINRSU', 'a': ['UNEASIER']} in qs)
def load_aerolith_list(request, parsed_req_body): """ Load an Aerolith list (a pre-defined list) into this table. """ try: named_list = NamedList.objects.get(pk=parsed_req_body["selectedList"]) except NamedList.DoesNotExist: return bad_request("List does not exist.") except (TypeError, ValueError): return bad_request("Please select a list.") tablenum = WordwallsGame().initialize_by_named_list( parsed_req_body["lexicon"], request.user, named_list, parsed_req_body["quiz_time_secs"], parsed_req_body["questions_per_round"], use_table=parsed_req_body["tablenum"], multiplayer=parsed_req_body["multiplayer"], ) return table_response(tablenum)
def test_continue_gonethru_list(self): LIST_NAME = 'list the sécond' word_list = WordList.objects.get(name=LIST_NAME) table_id = self.wwg.initialize_by_saved_list( self.lex, self.user, word_list, SavedListForm.CONTINUE_LIST_CHOICE, 240) self.assertNotEqual(table_id, 0) wwg = WordwallsGame() params = wwg.start_quiz(table_id, self.user) self.assertEqual(len(params['questions']), 1) self.assertEqual(params['questions'][0]['a'], 'ADEILORT') # Miss it. gave_up = wwg.give_up(self.user, table_id) self.assertTrue(gave_up) word_list = WordList.objects.get(name=LIST_NAME) self.assert_wl(word_list, { 'numAlphagrams': 11, 'numCurAlphagrams': 6, 'numFirstMissed': 6, 'numMissed': 1, 'goneThruOnce': True, 'questionIndex': 10, 'is_temporary': False, 'name': LIST_NAME })