def search_params_submit(user, post): """ Called when user submits a search params query. """ lexForm = LexiconForm(post) timeForm = TimeForm(post) fwForm = FindWordsForm(post) num_q_form = NumQuestionsForm(post) # form bound to the POST data if not (lexForm.is_valid() and timeForm.is_valid() and fwForm.is_valid() and num_q_form.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']) quiz_time = int(round(timeForm.cleaned_data['quizTime'] * 60)) questions_per_round = num_q_form.cleaned_data['num_questions'] search = searchForAlphagrams(fwForm.cleaned_data, lex) wwg = WordwallsGame() tablenum = wwg.initialize_by_search_params(user, search, quiz_time, questions_per_round) 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'] logger.debug('Selected in form: %s, %s, %s', dcForm.cleaned_data['challenge'], dcForm.cleaned_data['challengeDate'], lexForm.cleaned_data['lexicon']) if not chDate or chDate > date.today(): chDate = date.today() tablenum = wwg.initialize_daily_challenge(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 edit_saved_list(request, sl): """ A helper function (not a view) that saves an already existing list with new data and returns an HTTP response. Note: We do not save the original alphagrams here. These should be assumed to never change after an initial sync. """ body = json.loads(request.body) if sl.numAlphagrams != body.get('numAlphagrams'): return response('The alphagrams for this list do not match.', status=400) sl.numCurAlphagrams = body.get('numCurAlphagrams') sl.numFirstMissed = body.get('numFirstMissed') sl.numMissed = body.get('numMissed') sl.goneThruOnce = body.get('goneThruOnce') sl.questionIndex = body.get('questionIndex') sl.curQuestions = json.dumps(body.get('curQuestions')) sl.missed = json.dumps(body.get('missed')) sl.firstMissed = json.dumps(body.get('firstMissed')) try: sl.full_clean() except ValidationError as e: return response(str(e), status=400) sl.save() # Get stars. stars = body.get('starTags', {}) if stars: save_stars(request, stars, sl) return response(sl.to_python())
def api_random_toughie(request): from wordwalls.management.commands.genMissedBingoChalls import ( challengeDateFromReqDate) # from the PREVIOUS toughies challenge chdate = challengeDateFromReqDate(date.today()) - timedelta(days=7 * 20) try: dc = DailyChallenge.objects.get( lexicon=Lexicon.objects.get(pk=4), date=chdate, name=DailyChallengeName.objects.get( name=DailyChallengeName.WEEKS_BINGO_TOUGHIES)) except DailyChallenge.DoesNotExist: return response({"error": "No such daily challenge."}) alphs = json.loads(dc.alphagrams) alpha = Alphagram.objects.get(pk=random.choice(alphs)) words = Word.objects.filter(alphagram=alpha) wordString = " ".join([word.word for word in words]) alphaString = alpha.alphagram html = """ <script> $("#toughie").hover(function() { $(this).text("%s"); }, function() { $(this).text("%s"); });</script> <div id="toughie" style="font-size: 32px;">%s</div> """ % (wordString, alphaString, alphaString) return response({"html": html})
def savedListPk(request, slpk, option): if request.method == 'GET': return render(request, 'whitleyCards/quiz.html') elif request.method == 'POST': action = request.POST['action'] if action == 'getInitialSet': data = getQuizChunkFromSavedList(slpk, 0, int(option)) return response({ 'data': data[0], 'nextMinP': data[1], 'nextMaxP': data[2], 'numAlphas': data[3] }) elif action == 'getNextSet': minP = int(request.POST['minP']) if minP == -1: # quiz is over return response({'data': []}) maxP = int(request.POST['maxP']) logger.info("getting set %s, %s", minP, maxP) data = getQuizChunkFromSavedList(slpk, minP, int(option)) return response({ 'data': data[0], 'nextMinP': data[1], 'nextMaxP': data[2] })
def namedListPk(request, nlpk): if request.method == 'GET': return render(request, 'whitleyCards/quiz.html') elif request.method == 'POST': action = request.POST['action'] if action == 'getInitialSet': data = getQuizChunkFromNamedList(nlpk, 0) return response({ 'data': data[0], 'nextMinP': data[1], 'nextMaxP': data[2], 'numAlphas': NamedList.objects.get(pk=nlpk).numQuestions }) elif action == 'getNextSet': minP = int(request.POST['minP']) if minP == -1: # quiz is over return response({'data': []}) maxP = int(request.POST['maxP']) # these are now indices logger.info("getting set %s, %s", minP, maxP) data = getQuizChunkFromNamedList(nlpk, minP) return response({ 'data': data[0], 'nextMinP': data[1], 'nextMaxP': data[2] })
def new_quiz(request): """ Creates a new quiz but doesn't create any 'card' models. Card models will only be used for cardbox in future. """ body = json.loads(request.raw_post_data) params = validate_params(body['min'], body['max'], body['length'], body['lex']) if isinstance(params, basestring): return response(params, status=400) p_min, p_max, length, lexicon = params min_pk = alphProbToProbPK(p_min, lexicon.pk, length) max_pk = alphProbToProbPK(p_max, lexicon.pk, length) alpha_pks = range(min_pk, max_pk + 1) li, q_map = savedlist_from_alpha_pks(alpha_pks, lexicon) if len(q_map) > 0: # Generate a quiz name. quiz_name = '%s %ss (%s to %s)' % (lexicon.lexiconName, length, p_min, p_max) else: quiz_name = '' return response({'list': li.to_python(), 'q_map': q_map, 'quiz_name': quiz_name})
def new_quiz(request): """ Creates a new quiz but doesn't create any 'card' models. Card models will only be used for cardbox in future. """ body = json.loads(request.body) params = validate_params(body['min'], body['max'], body['length'], body['lex']) if isinstance(params, basestring): return response(params, status=400) p_min, p_max, length, lexicon = params min_pk = alphProbToProbPK(p_min, lexicon.pk, length) max_pk = alphProbToProbPK(p_max, lexicon.pk, length) alpha_pks = range(min_pk, max_pk + 1) li, q_map = savedlist_from_alpha_pks(alpha_pks, lexicon) if len(q_map) > 0: # Generate a quiz name. quiz_name = '%s %ss (%s to %s)' % (lexicon.lexiconName, length, p_min, p_max) else: quiz_name = '' return response({ 'list': li.to_python(), 'q_map': q_map, 'quiz_name': quiz_name })
def edit_saved_list(request, sl): """ A helper function (not a view) that saves an already existing list with new data and returns an HTTP response. Note: We do not save the original alphagrams here. These should be assumed to never change after an initial sync. """ body = json.loads(request.body) if sl.numAlphagrams != body.get('numAlphagrams'): return response('The alphagrams for this list do not match.', status=400) sl.numCurAlphagrams = body.get('numCurAlphagrams') sl.numFirstMissed = body.get('numFirstMissed') sl.numMissed = body.get('numMissed') sl.goneThruOnce = body.get('goneThruOnce') sl.questionIndex = body.get('questionIndex') sl.curQuestions = json.dumps(body.get('curQuestions')) sl.missed = json.dumps(body.get('missed')) sl.firstMissed = json.dumps(body.get('firstMissed')) try: sl.full_clean() except ValidationError as e: return response(str(e), status=400) sl.save() return response(sl.to_python())
def handle_homepage_post(profile, request): numAlphas = profile.wordwallsSaveListSize limit = 0 if not profile.member: limit = settings.SAVE_LIST_LIMIT_NONMEMBER if 'action' not in request.POST: return response({'success': False, 'error': _('Your request was not successful. You may ' 'be using an incompatible browser, please ' 'upgrade it.')}) logger.debug(request.POST) # Call one of various functions depending on action. actions_dict = { 'getSavedListList': get_saved_lists, 'getNamedListList': get_named_lists, 'getSavedListNumAlphas': lambda x, y: response({'na': numAlphas, 'l': limit}), 'challengeSubmit': challenge_submit, 'searchParamsSubmit': search_params_submit, 'savedListsSubmit': saved_lists_submit, 'savedListDelete': saved_list_delete, 'namedListsSubmit': named_lists_submit } if request.POST['action'] == 'getDcResults': return get_dc_results(request.user, request.POST, request.LANGUAGE_CODE) return actions_dict[request.POST['action']](request.user, request.POST)
def prob_range(request, lexid, length, minP, maxP): lexicon = Lexicon.objects.get(pk=lexid) if request.method == 'GET': return render(request, 'whitleyCards/quiz.html') elif request.method == 'POST': action = request.POST['action'] if action == 'getInitialSet': minP = int(minP) maxP = int(maxP) data = getQuizChunkByProb(lexicon, length, minP, maxP) return response({'data': data[0], 'nextMinP': data[1], 'nextMaxP': data[2], 'numAlphas': maxP-minP+1}) elif action == 'getNextSet': minP = int(request.POST['minP']) if minP == -1: # quiz is over return response({'data': []}) maxP = int(request.POST['maxP']) logger.debug("getting set %s, %s", minP, maxP) data = getQuizChunkByProb(lexicon, length, minP, maxP) return response({'data': data[0], 'nextMinP': data[1], 'nextMaxP': data[2]})
def csrf_failure(request, reason=''): session = request.session headers = { k: v for k, v in request.META.items() if k.startswith('HTTP') or k in ('CONTENT_LENGTH', 'CONTENT_TYPE') } logger.warning( 'CSRF Failure, user=%s, headers=%s, reason=%s, ' 'session: key=%s, items=%s', request.user, headers, reason, session.session_key, session.items()) # Depending on the request type, send the appropriate response. ERROR_MSG = 'CSRF token failure. Please log out and log in again.' try: body = json.loads(request.body) except (KeyError, ValueError): body = None if body and 'jsonrpc' in body: return response( { 'jsonrpc': '2.0', 'error': { 'code': 403, 'message': ERROR_MSG }, 'id': body['id'], }, StatusCode.FORBIDDEN) # Otherwise return response({'error': ERROR_MSG}, StatusCode.FORBIDDEN)
def search(request, lex_id, paramsb64): if request.method == 'GET': return render(request, 'whitleyCards/quiz.html') elif request.method == 'POST': action = request.POST['action'] lex = Lexicon.objects.get(pk=lex_id) search_params = build_search_criteria( request.user, lex, search_criteria_from_b64(paramsb64)) questions = word_search(search_params, expand=True) if action == 'getInitialSet': data = getQuizChunkByQuestions(lex, questions, 0, is_q_obj=True) return response({ 'data': data[0], 'nextMinP': data[1], 'nextMaxP': data[2], 'numAlphas': questions.size(), }) elif action == 'getNextSet': # minP and maxP are more like indices now. minP = int(request.POST['minP']) if minP == -1: # quiz is over return response({'data': []}) maxP = int(request.POST['maxP']) logger.info("getting set %s, %s", minP, maxP) data = getQuizChunkByQuestions(lex, questions, minP, is_q_obj=True) return response({ 'data': data[0], 'nextMinP': data[1], 'nextMaxP': data[2] })
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 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 new_quiz(request): """ Create a new quiz but doesn't create any 'card' models. Card models will only be used for cardbox in future. """ body = json.loads(request.body) logger.debug(body) lexicon = Lexicon.objects.get(lexiconName=body['lexicon']) try: search_description = build_search_criteria(request.user, lexicon, body['searchCriteria']) except GameInitException as e: return response(str(e), status=400) questions = word_search(search_description, expand=True) if questions.size() == 0: return response('No questions were found.', status=400) wl = WordList() wl.initialize_list(list(questions.to_python()), lexicon, None, shuffle=True, save=False) q_map = generate_question_map(questions) quiz_name = temporary_list_name(search_description, lexicon.lexiconName) # XXX add 1000-question limit? return response({ 'list': wl.to_python(), 'q_map': q_map, 'quiz_name': quiz_name, })
def new_quiz(request): """ Create a new quiz but doesn't create any 'card' models. Card models will only be used for cardbox in future. """ body = json.loads(request.body) logger.debug(body) lexicon = Lexicon.objects.get(lexiconName=body['lexicon']) try: search_description = build_search_criteria( request.user, lexicon, body['searchCriteria'] ) except GameInitException as e: return response(str(e), status=400) questions = word_search(search_description) if questions.size() == 0: return response('No questions were found.', status=400) wl = WordList() wl.initialize_list(list(questions.to_python()), lexicon, None, shuffle=True, save=False) q_map = generate_question_map(questions) quiz_name = temporary_list_name(search_description, lexicon.lexiconName) # XXX add 1000-question limit? return response({ 'list': wl.to_python(), 'q_map': q_map, 'quiz_name': quiz_name, })
def named_lists_submit(user, post): lexForm = LexiconForm(post) timeForm = TimeForm(post) nlForm = NamedListForm(post) num_q_form = NumQuestionsForm(post) if not (lexForm.is_valid() and timeForm.is_valid() and nlForm.is_valid() and num_q_form.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() questions_per_round = num_q_form.cleaned_data['num_questions'] tablenum = wwg.initialize_by_named_list( lex, user, nlForm.cleaned_data['namedList'], quizTime, questions_per_round) if tablenum == 0: raise Http404 return response({'url': reverse('wordwalls_table', args=(tablenum,)), 'success': True})
def healthz(request): if request.method == 'OPTIONS': return response('OK') if request.method == 'GET': return response('OK') elif request.method == 'POST': return response('OKPOST') return response('Bad method.', StatusCode.BAD_REQUEST)
def createQuiz(request): if request.method == 'GET': return render(request, 'whitleyCards/index.html', {'accessedWithGet': True}) elif request.method == 'POST': action = request.POST.get('action') if action == 'searchParamsFlashcard': lexForm = LexiconForm(request.POST) # form bound to the POST data fwForm = FindWordsForm(request.POST) if lexForm.is_valid() and fwForm.is_valid(): lex = Lexicon.objects.get( lexiconName=lexForm.cleaned_data['lexicon']) asd = searchForAlphagrams(fwForm.cleaned_data, lex) return response({ 'url': reverse('flashcards_by_prob_range', args=(asd['lexicon'].pk, asd['length'], asd['min'], asd['max'])), 'success': True}) elif action == 'namedListsFlashcard': lexForm = LexiconForm(request.POST) nlForm = NamedListForm(request.POST) if lexForm.is_valid() and nlForm.is_valid(): lex = Lexicon.objects.get( lexiconName=lexForm.cleaned_data['lexicon']) # lex doesn't matter return response({ 'url': reverse( 'flashcards_by_namedList_pk', args=(nlForm.cleaned_data['namedList'].pk,)), 'success': True}) elif (action == 'savedListsFlashcardEntire' or action == 'savedListsFlashcardFM'): lexForm = LexiconForm(request.POST) slForm = SavedListForm(request.POST) if lexForm.is_valid() and slForm.is_valid(): lex = Lexicon.objects.get( lexiconName=lexForm.cleaned_data['lexicon']) # lex doesn't matter if request.POST['action'] == 'savedListsFlashcardEntire': option = SavedListForm.RESTART_LIST_CHOICE elif request.POST['action'] == 'savedListsFlashcardFM': option = SavedListForm.FIRST_MISSED_CHOICE return response({ 'url': reverse('flashcards_by_savedList_pk', args=(slForm.cleaned_data['wordList'].pk, option)), 'success': True}) # don't do any checking right now for user access to # other user lists. why? maybe people can share lists # this way as long as we're not letting the users delete # lists, i think it should be fine. return response({'success': False, 'error': 'Did you select a list to flashcard?'}, status=400)
def saved_list_sync(request): """ Accept a POST of a NEW saved list. """ if request.method != 'POST': return response('This endpoint only accepts a POST.', status=400) body = json.loads(request.body) profile = request.user.aerolithprofile num_saved_alphas = profile.wordwallsSaveListSize limit = settings.SAVE_LIST_LIMIT_NONMEMBER logger.info('Syncing %s' % body) orig_qs = body.get('origQuestions') # Try getting a saved list with the same name, lexicon, and user. sl = WordList.objects.filter(user=request.user, lexicon__lexiconName=body.get('lexicon'), name=body.get('name')) if len(sl): return response('A list by that name already exists. Please remove ' 'that saved list and try again.', status=400) if (num_saved_alphas + len(orig_qs)) > limit and not profile.member: return response( 'This list would exceed your total list size limit. You can ' 'remove this limit by upgrading your membership!', status=400) sl = WordList( user=request.user, lexicon=Lexicon.objects.get(lexiconName=body.get('lexicon')), name=body.get('name'), numAlphagrams=body.get('numAlphagrams'), numCurAlphagrams=body.get('numCurAlphagrams'), numFirstMissed=body.get('numFirstMissed'), numMissed=body.get('numMissed'), goneThruOnce=body.get('goneThruOnce'), questionIndex=body.get('questionIndex'), origQuestions=json.dumps(orig_qs), curQuestions=json.dumps(body.get('curQuestions')), missed=json.dumps(body.get('missed')), firstMissed=json.dumps(body.get('firstMissed')), is_temporary=False, version=2 ) try: sl.full_clean() except ValidationError as e: return response('Your saved list is improperly formatted: %s', e) sl.save() profile.wordwallsSaveListSize += len(orig_qs) profile.save() # Get stars. stars = body.get('starTags', {}) if stars: save_stars(request, stars, sl) return response(sl.to_python())
def saved_list_sync(request): """ Accept a POST of a NEW saved list. """ if request.method != 'POST': return response('This endpoint only accepts a POST.', status=400) body = json.loads(request.body) profile = request.user.aerolithprofile num_saved_alphas = profile.wordwallsSaveListSize limit = settings.SAVE_LIST_LIMIT_NONMEMBER logger.info('Syncing %s' % body) orig_qs = body.get('origQuestions') # Try getting a saved list with the same name, lexicon, and user. sl = WordList.objects.filter(user=request.user, lexicon__lexiconName=body.get('lexicon'), name=body.get('name')) if len(sl): return response( 'A list by that name already exists. Please remove ' 'that saved list and try again.', status=400) if (num_saved_alphas + len(orig_qs)) > limit and not profile.member: return response( 'This list would exceed your total list size limit. You can ' 'remove this limit by upgrading your membership!', status=400) sl = WordList(user=request.user, lexicon=Lexicon.objects.get(lexiconName=body.get('lexicon')), name=body.get('name'), numAlphagrams=body.get('numAlphagrams'), numCurAlphagrams=body.get('numCurAlphagrams'), numFirstMissed=body.get('numFirstMissed'), numMissed=body.get('numMissed'), goneThruOnce=body.get('goneThruOnce'), questionIndex=body.get('questionIndex'), origQuestions=json.dumps(orig_qs), curQuestions=json.dumps(body.get('curQuestions')), missed=json.dumps(body.get('missed')), firstMissed=json.dumps(body.get('firstMissed')), is_temporary=False, version=2) try: sl.full_clean() except ValidationError as e: return response('Your saved list is improperly formatted: %s', e) sl.save() profile.wordwallsSaveListSize += len(orig_qs) profile.save() # Get stars. stars = body.get('starTags', {}) if stars: save_stars(request, stars, sl) return response(sl.to_python())
def word_lookup(request): lexicon = request.GET.get('lexicon') letters = request.GET.get('letters') if letters.startswith('!'): return alphagram_history_search(request) try: results = anagram_letters(lexicon, letters) except WDBError as e: return response(str(e), StatusCode.BAD_REQUEST) return response(results)
def word_lookup(request): lexicon = request.GET.get('lexicon') letters = request.GET.get('letters') if letters.startswith('!'): return alphagram_history_search(request) try: results = anagram_letters(lexicon, letters) except MacondoError as e: return response(str(e), StatusCode.BAD_REQUEST) return response(results)
def saved_list_delete(user, post): lexForm = LexiconForm(post) slForm = SavedListForm(post) if not (lexForm.is_valid() and slForm.is_valid()): return response({'success': False, 'error': _('You did not select a list to delete.')}) deletedListPk = slForm.cleaned_data['wordList'].pk deleteSavedList(slForm.cleaned_data['wordList'], user) return response({'deleted': True, 'wordList': deletedListPk})
def configure(request): if request.method != "POST": return response("Must use POST.", StatusCode.FORBIDDEN) # XXX: User can put any old JSON here. We should do some backend # validation. prefs = json.loads(request.body) profile = request.user.aerolithprofile profile.customWordwallsStyle = json.dumps(prefs) profile.save() return response("OK")
def saved_list_delete(user, post): lexForm = LexiconForm(post) slForm = SavedListForm(post) if not (lexForm.is_valid() and slForm.is_valid()): return response({ 'success': False, 'error': 'You did not select a list to delete.' }) deletedListPk = slForm.cleaned_data['wordList'].pk deleteSavedList(slForm.cleaned_data['wordList'], user) return response({'deleted': True, 'wordList': deletedListPk})
def start_game(request, id): if gargoyle.is_active('disable_games', request): return response( {'serverMsg': _( 'The Aerolith server is currently undergoing ' 'maintenance. Please try again in a few minutes.')}) wwg = WordwallsGame() quiz_params = wwg.start_quiz(id, request.user) if 'error' in quiz_params: return response(quiz_params, StatusCode.BAD_REQUEST) return response(quiz_params)
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 api_challengers(request): if request.method != 'GET': return response('Must use GET.', StatusCode.BAD_REQUEST) lex = request.GET.get('lexicon') ch_id = request.GET.get('challenge') # YYYY-mm-dd dt = request.GET.get('date') try: ch_date = datetime.strptime(dt, '%Y-%m-%d') except (ValueError, TypeError): ch_date = date.today() return response(challengers(ch_date, lex, ch_id))
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 saved_lists_delete(request): list_ids = json.loads(request.body) sls = [] for l in list_ids: try: sls.append(WordList.objects.get(user=request.user, id=l)) except WordList.DoesNotExist: return response('List id %s was not found.' % l, status=404) profile = request.user.aerolithprofile for l in sls: profile.wordwallsSaveListSize -= l.numAlphagrams l.delete() profile.save() return response('OK')
def questions_for_prob_range(request): """ Get a list of questions for a probability range. """ if request.method != 'POST': return response('Must use POST', StatusCode.BAD_REQUEST) body = json.loads(request.body) lexicon_name = body['lexicon'] pmin = body['pmin'] pmax = body['pmax'] length = body['length'] try: lex = Lexicon.objects.get(lexiconName=lexicon_name) except Lexicon.DoesNotExist: return response('Bad Lexicon', StatusCode.BAD_REQUEST) return response(question_list_from_probabilities(lex, pmin, pmax, length))
def question_map(request): if request.method != 'GET': return response('This endpoint only accepts GET', status=400) try: sl = SavedList.objects.get(user=request.user, id=request.GET.get('listId')) except SavedList.DoesNotExist: return response('This list does not exist!', status=404) qs = json.loads(sl.origQuestions) logger.debug('Generating question map for %s questions.' % len(qs)) map = generate_question_map(qs) logger.debug('Map generated, returning.') return response(map)
def saved_list(request, id): try: sl = WordList.objects.get(user=request.user, id=id) except WordList.DoesNotExist: return response('This list does not exist on the server!', status=404) if request.method == 'DELETE': profile = request.user.aerolithprofile saved_alphas = profile.wordwallsSaveListSize profile.wordwallsSaveListSize = saved_alphas - sl.numAlphagrams sl.delete() profile.save() return response('OK') elif request.method == 'GET': # Check 'action'. action = request.GET.get('action') l_obj = sl.to_python() if action == 'continue': pass elif action == 'firstmissed': l_obj = sl.to_python() if l_obj['goneThruOnce'] is False: return response( 'Cannot quiz on first missed unless you have ' 'gone through the entire quiz.', status=400) # Reset the list object to first missed but don't actually save it. # The user sync or PUT will take care of any saves. l_obj['questionIndex'] = 0 l_obj['curQuestions'] = l_obj['firstMissed'] l_obj['numCurAlphagrams'] = l_obj['numFirstMissed'] l_obj['numMissed'] = 0 l_obj['missed'] = [] elif action == 'reset': l_obj = sl.to_python() # Again, reset will not actually save, so this is a GET. # Sync or PUT take care of saving. l_obj['questionIndex'] = 0 l_obj['curQuestions'] = list(range(l_obj['numAlphagrams'])) l_obj['numCurAlphagrams'] = l_obj['numAlphagrams'] l_obj['firstMissed'] = [] l_obj['numFirstMissed'] = 0 l_obj['missed'] = [] l_obj['numMissed'] = 0 l_obj['goneThruOnce'] = False logger.info('Returning response %s' % l_obj) return response(l_obj) elif request.method == 'PUT': # Edit a saved list. return edit_saved_list(request, sl)
def question_map(request): if request.method != 'GET': return response('This endpoint only accepts GET', status=400) try: sl = SavedList.objects.get(user=request.user, id=request.GET.get('listId')) except SavedList.DoesNotExist: return response('This list does not exist!', status=404) qs = json.loads(sl.origQuestions) t1 = time.time() logger.debug('Generating question map for %s questions.' % len(qs)) map = generate_question_map(qs) logger.debug('Map generated, returning. Time: %s s.' % (time.time() - t1)) return response(map)
def questions_for_prob_range(request): """ Get a list of questions for a probability range. """ if request.method != 'POST': return response('Must use POST', StatusCode.BAD_REQUEST) body = json.loads(request.body) lexicon_name = body['lexicon'] pmin = body['pmin'] pmax = body['pmax'] length = body['length'] try: lex = Lexicon.objects.get(lexiconName=lexicon_name) except Lexicon.DoesNotExist: return response('Bad Lexicon', StatusCode.BAD_REQUEST) return response( expanded_question_list_from_probabilities(lex, pmin, pmax, length))
def saved_list(request, id): try: sl = SavedList.objects.get(user=request.user, id=id) except SavedList.DoesNotExist: return response('This list does not exist on the server!', status=404) if request.method == 'DELETE': profile = request.user.get_profile() saved_alphas = profile.wordwallsSaveListSize profile.wordwallsSaveListSize = saved_alphas - sl.numAlphagrams sl.delete() profile.save() return response('OK') elif request.method == 'GET': # Check 'action'. action = request.GET.get('action') l_obj = sl.to_python() if action == 'continue': pass elif action == 'firstmissed': l_obj = sl.to_python() if l_obj['goneThruOnce'] is False: return response('Cannot quiz on first missed unless you have ' 'gone through the entire quiz.', status=400) # Reset the list object to first missed but don't actually save it. # The user sync will take care of any saves. l_obj['questionIndex'] = 0 l_obj['curQuestions'] = l_obj['firstMissed'] l_obj['numCurAlphagrams'] = l_obj['numFirstMissed'] l_obj['numMissed'] = 0 l_obj['missed'] = [] elif action == 'reset': l_obj = sl.to_python() # Again, reset will not actually save, so this is a GET. Sync takes # care of saving. l_obj['questionIndex'] = 0 l_obj['curQuestions'] = range(l_obj['numAlphagrams']) l_obj['numCurAlphagrams'] = l_obj['numAlphagrams'] l_obj['firstMissed'] = [] l_obj['numFirstMissed'] = 0 l_obj['missed'] = [] l_obj['numMissed'] = 0 l_obj['goneThruOnce'] = False logger.debug('Returning response %s' % l_obj) return response(l_obj) elif request.method == 'PUT': # Edit a saved list. return edit_saved_list(request, sl)
def saved_lists_get(request): query_params = request.GET qargs = {'user': request.user} lexicon = query_params.get('lexicon') lexicon_id = query_params.get('lexicon_id') temporary = query_params.get('temp') last_saved_human = False order_by = 'id' if lexicon: # Search by name qargs['lexicon__lexiconName'] = lexicon elif lexicon_id: # Search by id qargs['lexicon__pk'] = lexicon_id if temporary: qargs['is_temporary'] = temporary == '1' if query_params.get('order_by') == 'modified': order_by = '-lastSaved' if query_params.get('last_saved') == 'human': last_saved_human = True lists = WordList.objects.filter(**qargs).order_by(order_by) profile = request.user.aerolithprofile limit = 0 if not profile.member: limit = settings.SAVE_LIST_LIMIT_NONMEMBER return response({ 'lists': [sl.to_python_reduced(last_saved_human) for sl in lists], 'count': lists.count(), 'limits': { 'total': limit, 'current': profile.wordwallsSaveListSize, } })
def load_into_cardbox(request): body = json.loads(request.raw_post_data) lexicon = Lexicon.objects.get(lexiconName=body['lex'].upper()) min_pk = alphProbToProbPK(int(body['min']), lexicon.pk, int(body['length'])) max_pk = alphProbToProbPK(int(body['max']), lexicon.pk, int(body['length'])) rg = range(min_pk, max_pk + 1) # For every alphagram, see if we already have a card for this user, # if not, create it. user_cards = Card.objects.filter(user=request.user) start = time.time() now = datetime.today() for ppk in rg: # Create a new card. try: card = Card(alphagram=Alphagram.objects.get(probability_pk=ppk), user=request.user, next_scheduled=now) except Alphagram.DoesNotExist: continue try: card.save() except IntegrityError: # Already exists, don't save again. pass logger.debug('Created Cards in %s s' % (time.time() - start)) return response({'num_cards': Card.objects.filter( user=request.user).count() })
def get_saved_lists(user, post): """ Gets a list of saved lists. """ lex = post.get('lexicon') lt = getSavedListList(lex, user) return response(lt)
def special_challenges(request): lex = request.GET.get("lexicon") ch_date = date_from_request_dict(request.GET) try: lex = Lexicon.objects.get(pk=lex) except Lexicon.DoesNotExist: return bad_request("Bad lexicon.") challenges = DailyChallenge.objects.filter( date=ch_date, lexicon=lex, name__orderPriority=DailyChallengeName.SPECIAL_CHALLENGE_ORDER_PRIORITY, ).order_by( # noqa "id" ) resp = [] for challenge in challenges: resp.append( { "id": challenge.name.id, "seconds": challenge.seconds, "numQuestions": len(json.loads(challenge.alphagrams)), "name": challenge.visible_name, "orderPriority": challenge.name.orderPriority, } ) return response(resp)
def saved_lists_get(request): query_params = request.GET qargs = {'user': request.user} lexicon = query_params.get('lexicon') lexicon_id = query_params.get('lexicon_id') temporary = query_params.get('temp') last_saved_human = False order_by = 'id' if lexicon: # Search by name qargs['lexicon__lexiconName'] = lexicon elif lexicon_id: # Search by id qargs['lexicon__pk'] = lexicon_id if temporary: qargs['is_temporary'] = temporary == '1' if query_params.get('order_by') == 'modified': order_by = '-lastSaved' if query_params.get('last_saved') == 'human': last_saved_human = True lists = WordList.objects.filter(**qargs).order_by(order_by) profile = request.user.aerolithprofile limit = 0 if not profile.member: limit = settings.SAVE_LIST_LIMIT_NONMEMBER return response({'lists': [sl.to_python_reduced(last_saved_human) for sl in lists], 'count': lists.count(), 'limits': { 'total': limit, 'current': profile.wordwallsSaveListSize, } })
def challengers(dt, lex, ch_id): try: lex = Lexicon.objects.get(pk=lex) ch_name = DailyChallengeName.objects.get(pk=ch_id) except ObjectDoesNotExist: return response('Bad lexicon or challenge.', StatusCode.BAD_REQUEST) return getLeaderboardData(lex, ch_name, dt)
def get_named_lists(user, post): """ Gets a list of "named" lists; these are the default lists that come with Aerolith. """ lex = post.get('lexicon') lt = getNamedListList(lex) return response(lt)
def list_questions_view(request): """ Get list of questions - `get_questions_from_alph_dicts` as an API view. Use POST since GET should not accept a request body in the standard. """ if request.method != 'POST': return response('Must use POST', StatusCode.BAD_REQUEST) body = json.loads(request.body) lexicon_name = body['lexicon'] questions = body['questions'] try: lex = Lexicon.objects.get(lexiconName=lexicon_name) except Lexicon.DoesNotExist: return response('Bad Lexicon', StatusCode.BAD_REQUEST) return response(generate_question_list_from_alphagrams(lex, questions))
def list_questions_view(request): """ Get list of questions - `questions_from_alpha_dicts` as an API view. Use POST since GET should not accept a request body in the standard. """ if request.method != 'POST': return response('Must use POST', StatusCode.BAD_REQUEST) body = json.loads(request.body) lexicon_name = body['lexicon'] questions = body['questions'] try: lex = Lexicon.objects.get(lexiconName=lexicon_name) except Lexicon.DoesNotExist: return response('Bad Lexicon', StatusCode.BAD_REQUEST) return response(generate_question_list_from_alphagrams(lex, questions))
def jwt_req(request): if not request.user.is_authenticated: return response({ 'error': 'Must log in', }, status=StatusCode.FORBIDDEN) token = jwt.encode( { 'iss': 'aerolith.org', 'sub': request.user.pk, 'usn': request.user.username, 'exp': int(time.time()) + JWT_EXPIRATION }, settings.SECRET_KEY, algorithm='HS256') return response({ 'token': token.decode('utf-8'), })
def saved_list_sync(request): """ Accept a POST of a new saved list. """ if request.method != 'POST': return response('This endpoint only accepts a POST.', status=400) body = json.loads(request.raw_post_data) profile = request.user.get_profile() saved_alphas = profile.wordwallsSaveListSize limit = base.settings.SAVE_LIST_LIMIT_NONMEMBER logger.debug('Syncing %s' % body) orig_qs = body.get('origQuestions') # Try getting a saved list with the same name, lexicon, and user. sl = SavedList.objects.filter(user=request.user, lexicon__lexiconName=body.get('lexicon'), name=body.get('name')) if len(sl): return response('A list by that name already exists. Please remove ' 'that saved list and try again.', status=400) sl = SavedList() sl.user = request.user sl.lexicon = Lexicon.objects.get(lexiconName=body.get('lexicon')) sl.name = body.get('name') if (saved_alphas + len(orig_qs)) > limit and not profile.member: return response( 'This list would exceed your total list size limit. You can ' 'remove this limit by upgrading your membership!', status=400) sl.numAlphagrams = body.get('numAlphagrams') sl.numCurAlphagrams = body.get('numCurAlphagrams') sl.numFirstMissed = body.get('numFirstMissed') sl.numMissed = body.get('numMissed') sl.goneThruOnce = body.get('goneThruOnce') sl.questionIndex = body.get('questionIndex') sl.origQuestions = json.dumps(orig_qs) sl.curQuestions = json.dumps(body.get('curQuestions')) sl.missed = json.dumps(body.get('missed')) sl.firstMissed = json.dumps(body.get('firstMissed')) sl.save() profile.wordwallsSaveListSize += len(orig_qs) profile.save() return response(sl.to_python())
def saved_list_sync(request): """ Accept a POST of a new saved list. """ if request.method != 'POST': return response('This endpoint only accepts a POST.', status=400) body = json.loads(request.body) profile = request.user.get_profile() saved_alphas = profile.wordwallsSaveListSize limit = base.settings.SAVE_LIST_LIMIT_NONMEMBER logger.debug('Syncing %s' % body) orig_qs = body.get('origQuestions') # Try getting a saved list with the same name, lexicon, and user. sl = SavedList.objects.filter(user=request.user, lexicon__lexiconName=body.get('lexicon'), name=body.get('name')) if len(sl): return response('A list by that name already exists. Please remove ' 'that saved list and try again.', status=400) sl = SavedList() sl.user = request.user sl.lexicon = Lexicon.objects.get(lexiconName=body.get('lexicon')) sl.name = body.get('name') if (saved_alphas + len(orig_qs)) > limit and not profile.member: return response( 'This list would exceed your total list size limit. You can ' 'remove this limit by upgrading your membership!', status=400) sl.numAlphagrams = body.get('numAlphagrams') sl.numCurAlphagrams = body.get('numCurAlphagrams') sl.numFirstMissed = body.get('numFirstMissed') sl.numMissed = body.get('numMissed') sl.goneThruOnce = body.get('goneThruOnce') sl.questionIndex = body.get('questionIndex') sl.origQuestions = json.dumps(orig_qs) sl.curQuestions = json.dumps(body.get('curQuestions')) sl.missed = json.dumps(body.get('missed')) sl.firstMissed = json.dumps(body.get('firstMissed')) sl.save() profile.wordwallsSaveListSize += len(orig_qs) profile.save() return response(sl.to_python())
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 configure(request): if request.method != "POST": return bad_request("Must use POST.") # XXX: User can put any old JSON here. We should do some backend # validation. prefs = json.loads(request.body) profile = request.user.aerolithprofile profile.customWordwallsStyle = json.dumps(prefs) profile.save() return response("OK")
def question_map(request): """ Stand-alone endpoint for loading a question map. This is usually called after the user makes a request to load a remote quiz. XXX: Maybe should not be two endpoints. See new_quiz in flashcards.views """ if request.method != 'GET': return response('This endpoint only accepts GET', status=400) try: sl = WordList.objects.get(user=request.user, id=request.GET.get('listId')) except WordList.DoesNotExist: return response('This list does not exist!', status=404) t1 = time.time() q_map = generate_question_map_from_alphagrams(sl.lexicon, json.loads(sl.origQuestions)) logger.debug('Map generated, returning. Time: %s s.' % (time.time() - t1)) return response(q_map)
def saved_lists_get(request): query_params = request.GET qargs = {'user': request.user} lexicon = query_params.get('lexicon') temporary = query_params.get('temp') if lexicon: qargs['lexicon__lexiconName'] = lexicon if temporary: qargs['is_temporary'] = temporary == '1' lists = WordList.objects.filter(**qargs) return response({'lists': [sl.to_python_reduced() for sl in lists], 'count': lists.count()})
def question_map(request): """ Stand-alone endpoint for loading a question map. This is usually called after the user makes a request to load a remote quiz. XXX: Maybe should not be two endpoints. See new_quiz in flashcards.views """ if request.method != 'GET': return response('This endpoint only accepts GET', status=400) try: sl = WordList.objects.get(user=request.user, id=request.GET.get('listId')) except WordList.DoesNotExist: return response('This list does not exist!', status=404) t1 = time.time() q_map = generate_question_map_from_alphagrams(sl.lexicon, json.loads(sl.origQuestions)) logger.info('Map generated, returning. Time: %s s.' % (time.time() - t1)) return response(q_map)