def current_custom_configs(): result = [] global _custom_configs global _custom_config_filters if _custom_configs.get(currentThread()) is None: user_id = get_user_id() _custom_configs[currentThread( )] = CustomConfig.objects.current_custom_configs(user_id) def _filter_config(config): c_key, c_value = next(iter(config['condition'].items())) if c_key is None: return True all_nones = True for config_filter in _custom_config_filters.get(currentThread(), {}).values(): filter_result = config_filter(c_key, c_value) if filter_result is not None: all_nones = False if not filter_result: return False return not all_nones customs = _custom_configs.get(currentThread()) if customs is not None: for key, configs in customs.items(): valid_configs = [c for c in configs if _filter_config(c)] if len(valid_configs): result.append((key, valid_configs[0]['content'])) return result
def read(request, key): if 'user' in request.GET: user = get_user_id(request) else: user = None item = int(request.GET['item']) if 'item' in request.GET else None item_secondary = int(request.GET['item_secondary']) if 'item_secondary' in request.GET else None time = get_time(request) environment = get_environment() if is_time_overridden(request): environment.shift_time(time) value = environment.read(key, user=user, item=item, item_secondary=item_secondary) if value is None: return render_json( request, {'error': 'value with key "%s" not found' % key}, template='models_json.html', status=404) else: return render_json( request, { 'object_type': 'value', 'key': key, 'item_primary_id': item, 'item_secondary_id': item_secondary, 'user_id': user, 'value': value }, template='models_json.html' )
def practice_image(request): user_id = get_user_id(request) limit = min(int(request.GET.get('limit', 10)), 100) item_ids = Item.objects.filter_all_reachable_leaves(get_filter(request), get_language(request)) answers = Answer.objects.filter(user_id=user_id).filter(item_asked_id__in=item_ids).order_by('-id')[:limit] predictive_model = get_predictive_model() environment = get_environment() predictions = predictive_model.predict_more_items(environment, user=-1, items=item_ids, time=datetime.datetime.now()) items_in_order = list(zip(*sorted(zip(predictions, item_ids), reverse=True)))[1] if len(item_ids) > 1 else [] item_prediction = dict(list(zip(item_ids, predictions))) item_position = dict(list(zip(items_in_order, list(range(len(item_ids)))))) svg = proso.svg.Printer() answers = sorted(list(answers), key=lambda a: a.id) SQUARE_SIZE = 10 OFFSET_X = SQUARE_SIZE OFFSET_Y = SQUARE_SIZE * 3 for i, item in enumerate(items_in_order): svg.print_square(OFFSET_X + SQUARE_SIZE * i, OFFSET_Y - SQUARE_SIZE, SQUARE_SIZE, int(255 * item_prediction[item])) for i, answer in enumerate(answers): for j in range(len(items_in_order)): svg.print_square(OFFSET_X + SQUARE_SIZE * j, OFFSET_Y + SQUARE_SIZE * i, SQUARE_SIZE, 255, border_color=200) color = 'green' if answer.item_asked_id == answer.item_answered_id else 'red' svg.print_square( OFFSET_X + SQUARE_SIZE * item_position[answer.item_asked_id], OFFSET_Y + SQUARE_SIZE * i, SQUARE_SIZE, color, border_color=0) svg.print_text(OFFSET_X + SQUARE_SIZE * (len(items_in_order) + 1), OFFSET_Y + SQUARE_SIZE * i + 0.8 * SQUARE_SIZE, answer.time.strftime('%H:%M:%S %Y-%m-%d'), font_size=10) return HttpResponse(str(svg), content_type="image/svg+xml")
def audit(request, key): if 'user' in request.GET: user = get_user_id(request) else: user = None limit = 100 if request.user.is_staff: limit = request.GET.get('limit', limit) item = int(request.GET['item']) if 'item' in request.GET else None item_secondary = int(request.GET['item_secondary']) if 'item_secondary' in request.GET else None time = get_time(request) environment = get_environment() if is_time_overridden(request): environment.shift_time(time) values = environment.audit( key, user=user, item=item, item_secondary=item_secondary, limit=limit) def _to_json_audit(audit): (time, value) = audit return { 'object_type': 'value', 'key': key, 'item_primary_id': item, 'item_secondary_id': item_secondary, 'user_id': user, 'value': value, 'time': time.strftime('%Y-%m-%d %H:%M:%S') } return render_json(request, list(map(_to_json_audit, values)), template='models_json.html')
def user_stats(request): """ JSON of user stats of the user GET parameters: html (bool): turn on the HTML version of the API, defaults to false user (int): identifier of the user, defaults to logged user concepts (list): list of identifiers of concepts, defaults to all concepts lang (str): language of requested concepts, defaults to language from django """ user = get_user_id(request) language = get_language(request) concepts = None # meaning all concept if "concepts" in request.GET: concepts = Concept.objects.filter(lang=language, active=True, identifier__in=load_query_json( request.GET, "concepts")) data = UserStat.objects.get_user_stats(user, language, concepts) return render_json(request, data, template='concepts_json.html', help_text=user_stats.__doc__)
def current_custom_configs(): result = [] global _custom_configs global _custom_config_filters if _custom_configs.get(currentThread()) is None: user_id = get_user_id() _custom_configs[currentThread()] = CustomConfig.objects.current_custom_configs(user_id) def _filter_config(config): c_key, c_value = next(iter(config['condition'].items())) if c_key is None: return True all_nones = True for config_filter in _custom_config_filters.get(currentThread(), {}).values(): filter_result = config_filter(c_key, c_value) if filter_result is not None: all_nones = False if not filter_result: return False return not all_nones customs = _custom_configs.get(currentThread()) if customs is not None: for key, configs in customs.items(): valid_configs = [c for c in configs if _filter_config(c)] if len(valid_configs): result.append((key, valid_configs[0]['content'])) return result
def read(request, key): if 'user' in request.GET: user = get_user_id(request) else: user = None item = int(request.GET['item']) if 'item' in request.GET else None item_secondary = int(request.GET['item_secondary'] ) if 'item_secondary' in request.GET else None time = get_time(request) environment = get_environment() if is_time_overridden(request): environment.shift_time(time) value = environment.read(key, user=user, item=item, item_secondary=item_secondary) if value is None: return render_json(request, {'error': 'value with key "%s" not found' % key}, template='models_json.html', status=404) else: return render_json(request, { 'object_type': 'value', 'key': key, 'item_primary_id': item, 'item_secondary_id': item_secondary, 'user_id': user, 'value': value }, template='models_json.html')
def status(request): user_id = get_user_id(request) time = get_time(request) environment = get_environment() if is_time_overridden(request): environment.shift_time(time) return render_json(request, { 'object_type': 'status', 'number_of_answers': environment.number_of_answers(user=user_id), 'number_of_correct_answers': environment.number_of_correct_answers(user=user_id), 'environment_info': get_active_environment_info(), }, template='models_json.html')
def answer_question(request): if request.method == 'GET': return render(request, 'user_answer.html', {}, help_text=answer_question.__doc__) elif request.method == 'POST': with transaction.atomic(): user_id = get_user_id(request) to_save = json_body(request.body.decode("utf-8")) for answer in to_save['answers']: question = get_object_or_404(UserQuestion, pk=answer['question']) if 'open_answer' in answer and 'closed_answer' in answer: return render_json(request, { 'error': _('The answer can not contain both open and closed part'), 'error_type': 'answer_closed_open_both' }, template='user_json.html', status=400) if 'open_answer' not in answer and 'closed_answer' not in answer: return render_json(request, { 'error': _('The answer has to contain either open, or closed part.'), 'error_type': 'answer_closed_open_missing' }, template='user_json.html', status=400) if question.answer_type == UserQuestion.TYPE_CLOSED and 'closed_answer' not in answer: return render_json(request, { 'error': _('The answer has to contain closed part.'), 'error_type': 'answer_closed_missing' }, template='user_json.html', status=400) if question.answer_type == UserQuestion.TYPE_OPEN and 'open_answer' not in answer: return render_json(request, { 'error': _('The answer has to contain open part.'), 'error_type': 'answer_open_missing' }, template='user_json.html', status=400) user_answer = None if not question.repeat: user_answer = UserQuestionAnswer.objects.filter(user_id=user_id, question__identifier=question.identifier).first() status = 202 if user_answer is None: status = 201 user_answer = UserQuestionAnswer(user_id=user_id, question=question) if 'closed_answer' in answer: user_answer.closed_answer = get_object_or_404(UserQuestionPossibleAnswer, pk=answer['closed_answer']) if user_answer.closed_answer.question_id != question.id: return render_json(request, { 'error': _('The given question and question for the given closed answer does not match.'), 'error_type': 'closed_answer_no_match' }, template='user_json.html', status=400) else: user_answer.closed_answer = None user_answer.open_answer = answer['open_answer'] if 'open_answer' in answer else None user_answer.save() return HttpResponse('ok', status=status) else: return HttpResponseBadRequest("method %s is not allowed".format(request.method))
def user_answers(request, json_list, nested): if nested: return user_id = get_user_id(request) user_answers = defaultdict(list) for user_answer in UserQuestionAnswer.objects.select_related('question', 'closed_answer').filter(user_id=user_id): user_answers[user_answer.question.identifier].append(user_answer) for question in json_list: possible_answers = {ans['identifier']: ans for ans in question['possible_answers']} question_user_answers = [ans.to_json(nested=True) for ans in user_answers[question['identifier']]] for ans in question_user_answers: if 'closed_answer' in ans: ans['closed_answer'] = possible_answers[ans['closed_answer']['identifier']] question['user_answers'] = question_user_answers
def number_of_correct_answers(request, json_list, nested): if 'stats' not in request.GET: return object_item_ids = [x['item_id'] for x in json_list] user = get_user_id(request) leaves = models.Item.objects.get_leaves(object_item_ids, language=get_language(request)) all_leaves = set(flatten(leaves.values())) number_of_correct_answers = _environment(request).number_of_correct_answers_more_items( user=user, items=all_leaves) for object_json in json_list: num = sum([number_of_correct_answers[leave] for leave in leaves[object_json['item_id']]]) object_json['number_of_correct_answers'] = num object_json['practiced_correctly'] = num > 0 return json_list
def prediction(request, json_list, nested): if 'stats' not in request.GET: return object_item_ids = [x['item_id'] for x in json_list] user = get_user_id(request) time = models.get_time_for_knowledge_overview(request) predictions = _predictive_model().predict_more_items(_environment(request), user, object_item_ids, time) mastery_threshold = get_mastery_trashold() for object_json, prediction in zip(json_list, predictions): object_json['prediction'] = float("{0:.2f}".format(prediction)) object_json['mastered'] = prediction >= mastery_threshold if "new_user_predictions" in request.GET: user = -1 predictions = _predictive_model().predict_more_items(_environment(request), user, object_item_ids, time) for object_json, prediction in zip(json_list, predictions): object_json['new_user_prediction'] = float("{0:.2f}".format(prediction)) return json_list
def practice_image(request): user_id = get_user_id(request) limit = min(int(request.GET.get('limit', 10)), 100) item_ids = Item.objects.filter_all_reachable_leaves( get_filter(request), get_language(request)) answers = Answer.objects.filter(user_id=user_id).filter( item_asked_id__in=item_ids).order_by('-id')[:limit] predictive_model = get_predictive_model() environment = get_environment() predictions = predictive_model.predict_more_items( environment, user=-1, items=item_ids, time=datetime.datetime.now()) items_in_order = list( zip(*sorted(zip(predictions, item_ids), reverse=True)))[1] if len(item_ids) > 1 else [] item_prediction = dict(list(zip(item_ids, predictions))) item_position = dict(list(zip(items_in_order, list(range(len(item_ids)))))) svg = proso.svg.Printer() answers = sorted(list(answers), key=lambda a: a.id) SQUARE_SIZE = 10 OFFSET_X = SQUARE_SIZE OFFSET_Y = SQUARE_SIZE * 3 for i, item in enumerate(items_in_order): svg.print_square(OFFSET_X + SQUARE_SIZE * i, OFFSET_Y - SQUARE_SIZE, SQUARE_SIZE, int(255 * item_prediction[item])) for i, answer in enumerate(answers): for j in range(len(items_in_order)): svg.print_square(OFFSET_X + SQUARE_SIZE * j, OFFSET_Y + SQUARE_SIZE * i, SQUARE_SIZE, 255, border_color=200) color = 'green' if answer.item_asked_id == answer.item_answered_id else 'red' svg.print_square(OFFSET_X + SQUARE_SIZE * item_position[answer.item_asked_id], OFFSET_Y + SQUARE_SIZE * i, SQUARE_SIZE, color, border_color=0) svg.print_text(OFFSET_X + SQUARE_SIZE * (len(items_in_order) + 1), OFFSET_Y + SQUARE_SIZE * i + 0.8 * SQUARE_SIZE, answer.time.strftime('%H:%M:%S %Y-%m-%d'), font_size=10) return HttpResponse(str(svg), content_type="image/svg+xml")
def avg_prediction(request, json_list, nested): if 'stats' not in request.GET: return object_item_ids = [x['item_id'] for x in json_list] leaves = models.Item.objects.get_leaves(object_item_ids, language=get_language(request)) all_leaves = list(set(flatten(leaves.values()))) user = get_user_id(request) time = models.get_time_for_knowledge_overview(request) predictions = dict(list(zip(all_leaves, _predictive_model().predict_more_items( _environment(request), user, all_leaves, time )))) mastery_threshold = get_mastery_trashold() for object_json in json_list: leaf_predictions = [predictions[leave] for leave in leaves[object_json['item_id']]] object_json['avg_predicton'] = numpy.mean(leaf_predictions) object_json['mastered'] = sum([p > mastery_threshold for p in leaf_predictions])
def user_answers(request, json_list, nested): if nested: return user_id = get_user_id(request) user_answers = defaultdict(list) for user_answer in UserQuestionAnswer.objects.select_related( 'question', 'closed_answer').filter(user_id=user_id): user_answers[user_answer.question.identifier].append(user_answer) for question in json_list: possible_answers = { ans['identifier']: ans for ans in question['possible_answers'] } question_user_answers = [ ans.to_json(nested=True) for ans in user_answers[question['identifier']] ] for ans in question_user_answers: if 'closed_answer' in ans: ans['closed_answer'] = possible_answers[ans['closed_answer'] ['identifier']] question['user_answers'] = question_user_answers
def user_stats(request): """ JSON of user stats of the user GET parameters: html (bool): turn on the HTML version of the API, defaults to false user (int): identifier of the user, defaults to logged user concepts (list): list of identifiers of concepts, defaults to all concepts lang (str): language of requested concepts, defaults to language from django """ user = get_user_id(request) language = get_language(request) concepts = None # meaning all concept if "concepts" in request.GET: concepts = Concept.objects.filter(lang=language, active=True, identifier__in=load_query_json(request.GET, "concepts")) data = UserStat.objects.get_user_stats(user, language, concepts) return render_json(request, data, template='concepts_json.html', help_text=user_stats.__doc__)
def audit(request, key): if 'user' in request.GET: user = get_user_id(request) else: user = None limit = 100 if request.user.is_staff: limit = request.GET.get('limit', limit) item = int(request.GET['item']) if 'item' in request.GET else None item_secondary = int(request.GET['item_secondary'] ) if 'item_secondary' in request.GET else None time = get_time(request) environment = get_environment() if is_time_overridden(request): environment.shift_time(time) values = environment.audit(key, user=user, item=item, item_secondary=item_secondary, limit=limit) def _to_json_audit(audit): (time, value) = audit return { 'object_type': 'value', 'key': key, 'item_primary_id': item, 'item_secondary_id': item_secondary, 'user_id': user, 'value': value, 'time': time.strftime('%Y-%m-%d %H:%M:%S') } return render_json(request, list(map(_to_json_audit, values)), template='models_json.html')
def user_stats(request): """ Get user statistics for selected groups of items time: time in format '%Y-%m-%d_%H:%M:%S' used for practicing user: identifier of the user (only for stuff users) username: username of user (only for users with public profile) filters: -- use this or body json as in BODY mastered: use model to compute number of mastered items - can be slowed language: language of the items BODY json in following format: { "#identifier": [] -- custom identifier (str) and filter ... } """ timer('user_stats') response = {} data = None if request.method == "POST": data = json.loads(request.body.decode("utf-8"))["filters"] if "filters" in request.GET: data = load_query_json(request.GET, "filters") if data is None: return render_json(request, {}, template='models_user_stats.html', help_text=user_stats.__doc__) environment = get_environment() if is_time_overridden(request): environment.shift_time(get_time(request)) user_id = get_user_id(request) language = get_language(request) filter_names, filter_filters = list(zip(*sorted(data.items()))) reachable_leaves = Item.objects.filter_all_reachable_leaves_many( filter_filters, language) all_leaves = flatten(reachable_leaves) answers = dict( list( zip(all_leaves, environment.number_of_answers_more_items(all_leaves, user_id)))) correct_answers = dict( list( zip( all_leaves, environment.number_of_correct_answers_more_items( all_leaves, user_id)))) if request.GET.get("mastered"): timer('user_stats_mastered') mastery_threshold = get_mastery_trashold() predictions = get_predictive_model().predict_more_items( environment, user_id, all_leaves, get_time(request)) mastered = dict( list(zip(all_leaves, [p >= mastery_threshold for p in predictions]))) LOGGER.debug( "user_stats - getting predictions for flashcards took %s seconds", (timer('user_stats_mastered'))) for identifier, items in zip(filter_names, reachable_leaves): if len(items) == 0: response[identifier] = { "filter": data[identifier], "number_of_flashcards": 0, } else: response[identifier] = { "filter": data[identifier], "number_of_flashcards": len(items), "number_of_practiced_flashcards": sum(answers[i] > 0 for i in items), "number_of_answers": sum(answers[i] for i in items), "number_of_correct_answers": sum(correct_answers[i] for i in items), } if request.GET.get("mastered"): response[identifier]["number_of_mastered_flashcards"] = sum( mastered[i] for i in items) return render_json(request, response, template='models_user_stats.html', help_text=user_stats.__doc__)
def questions_to_ask(request): language = get_language(request) user_id = get_user_id(request) questions = UserQuestion.objects.questions_to_ask(user_id, language) return render_json(request, list(questions), template='user_json.html')
def profile(request, status=200): """ Get the user's profile. If the user has no assigned profile, the HTTP 404 is returned. Make a POST request to modify the user's profile. GET parameters: html turn on the HTML version of the API username: username of user (only for users with public profile) stats: attache addition user statistics POST parameters (JSON): send_emails: switcher turning on sending e-mails to user public: swicher making the user's profile publicly available user: password: user's password password_check: user's password again to check it first_name (optional): user's first name last_name (optional): user's last name """ if request.method == 'GET': if request.GET.get("username", False): try: user_profile = User.objects.get(username=request.GET.get("username"), userprofile__public=True).userprofile except ObjectDoesNotExist: raise Http404("user not found or have not public profile") else: user_id = get_user_id(request) if get_config('proso_user', 'google.openid.migration', default=True) and not is_user_id_overridden(request): migrated_user = migrate_google_openid_user(request.user) if migrated_user is not None: auth.logout(request) migrated_user.backend = 'social.backends.google.GoogleOAuth2' auth.login(request, migrated_user) user_profile = get_object_or_404(UserProfile, user_id=user_id) return render_json( request, user_profile, status=status, template='user_profile.html', help_text=profile.__doc__) elif request.method == 'POST': with transaction.atomic(): to_save = json_body(request.body.decode("utf-8")) user_id = get_user_id(request) user_profile = get_object_or_404(UserProfile, user_id=user_id) user = to_save.get('user', None) if 'send_emails' in to_save: user_profile.send_emails = bool(to_save['send_emails']) if 'public' in to_save: user_profile.public = bool(to_save['public']) if user: error = _save_user(request, user, new=False) if error: return render_json(request, error, template='user_json.html', status=400) if 'properties' in to_save: user_profile.save_properties(to_save['properties']) user_profile.save() request.method = "GET" return profile(request, status=202) else: return HttpResponseBadRequest("method %s is not allowed".format(request.method))
def practice(request): """ Return the given number of questions to practice adaptively. In case of POST request, try to save the answer(s). GET parameters: filter: list of lists of identifiers (may be prefixed by minus sign to mark complement) language: language (str) of flashcards avoid: list of item ids to avoid limit: number of returned questions (default 10, maximum 100) time: time in format '%Y-%m-%d_%H:%M:%S' used for practicing user: identifier for the practicing user (only for stuff users) stats: turn on the enrichment of the objects by some statistics html: turn on the HTML version of the API BODY: see answer resource """ if request.user.id is None: # Google Bot return render_json( request, { 'error': _('There is no user available for the practice.'), 'error_type': 'user_undefined' }, status=400, template='models_json.html') limit = min(int(request.GET.get('limit', 10)), 100) # prepare user = get_user_id(request) time = get_time(request) avoid = load_query_json(request.GET, "avoid", "[]") practice_filter = get_filter(request) practice_context = PracticeContext.objects.from_content(practice_filter) environment = get_environment() item_selector = get_item_selector() if is_time_overridden(request): environment.shift_time(time) # save answers if request.method == 'POST': _save_answers(request, practice_context) if len(practice_filter) > 0: item_ids = Item.objects.filter_all_reachable_leaves( practice_filter, get_language(request)) else: item_ids = Item.objects.get_all_available_leaves() item_ids = list(set(item_ids) - set(avoid)) if len(item_ids) == 0: return render_json( request, { 'error': _('There is no item for the given filter to practice.'), 'error_type': 'empty_practice' }, status=404, template='models_json.html') selected_items, meta = item_selector.select(environment, user, item_ids, time, practice_context.id, limit, items_in_queue=len(avoid)) result = [] for item, item_meta in zip(selected_items, meta): question = { 'object_type': 'question', 'payload': Item.objects.item_id_to_json(item), } if item_meta is not None: question['meta'] = item_meta result.append(question) return render_json(request, result, template='models_json.html', help_text=practice.__doc__)
def user_stats(request): """ Get user statistics for selected groups of items time: time in format '%Y-%m-%d_%H:%M:%S' used for practicing user: identifier of the user (only for stuff users) username: username of user (only for users with public profile) filters: -- use this or body json as in BODY mastered: use model to compute number of mastered items - can be slowed language: language of the items BODY json in following format: { "#identifier": [] -- custom identifier (str) and filter ... } """ timer('user_stats') response = {} data = None if request.method == "POST": data = json.loads(request.body.decode("utf-8"))["filters"] if "filters" in request.GET: data = load_query_json(request.GET, "filters") if data is None: return render_json(request, {}, template='models_user_stats.html', help_text=user_stats.__doc__) environment = get_environment() if is_time_overridden(request): environment.shift_time(get_time(request)) user_id = get_user_id(request) language = get_language(request) filter_names, filter_filters = list(zip(*sorted(data.items()))) reachable_leaves = Item.objects.filter_all_reachable_leaves_many(filter_filters, language) all_leaves = flatten(reachable_leaves) answers = dict(list(zip(all_leaves, environment.number_of_answers_more_items(all_leaves, user_id)))) correct_answers = dict(list(zip(all_leaves, environment.number_of_correct_answers_more_items(all_leaves, user_id)))) if request.GET.get("mastered"): timer('user_stats_mastered') mastery_threshold = get_mastery_trashold() predictions = get_predictive_model().predict_more_items(environment, user_id, all_leaves, get_time(request)) mastered = dict(list(zip(all_leaves, [p >= mastery_threshold for p in predictions]))) LOGGER.debug("user_stats - getting predictions for flashcards took %s seconds", (timer('user_stats_mastered'))) for identifier, items in zip(filter_names, reachable_leaves): if len(items) == 0: response[identifier] = { "filter": data[identifier], "number_of_flashcards": 0, } else: response[identifier] = { "filter": data[identifier], "number_of_flashcards": len(items), "number_of_practiced_flashcards": sum(answers[i] > 0 for i in items), "number_of_answers": sum(answers[i] for i in items), "number_of_correct_answers": sum(correct_answers[i] for i in items), } if request.GET.get("mastered"): response[identifier]["number_of_mastered_flashcards"]= sum(mastered[i] for i in items) return render_json(request, response, template='models_user_stats.html', help_text=user_stats.__doc__)
def profile(request, status=200): """ Get the user's profile. If the user has no assigned profile, the HTTP 404 is returned. Make a POST request to modify the user's profile. GET parameters: html turn on the HTML version of the API username: username of user (only for users with public profile) stats: attache addition user statistics POST parameters (JSON): send_emails: switcher turning on sending e-mails to user public: swicher making the user's profile publicly available user: password: user's password password_check: user's password again to check it first_name (optional): user's first name last_name (optional): user's last name """ if request.method == 'GET': if request.GET.get("username", False): try: user_profile = User.objects.get( username=request.GET.get("username"), userprofile__public=True).userprofile except ObjectDoesNotExist: raise Http404("user not found or have not public profile") else: user_id = get_user_id(request) if get_config('proso_user', 'google.openid.migration', default=True) and not is_user_id_overridden(request): migrated_user = migrate_google_openid_user(request.user) if migrated_user is not None: auth.logout(request) migrated_user.backend = 'social.backends.google.GoogleOAuth2' auth.login(request, migrated_user) user_profile = get_object_or_404(UserProfile, user_id=user_id) return render_json(request, user_profile, status=status, template='user_profile.html', help_text=profile.__doc__) elif request.method == 'POST': with transaction.atomic(): to_save = json_body(request.body.decode("utf-8")) user_id = get_user_id(request) user_profile = get_object_or_404(UserProfile, user_id=user_id) user = to_save.get('user', None) if 'send_emails' in to_save: user_profile.send_emails = bool(to_save['send_emails']) if 'public' in to_save: user_profile.public = bool(to_save['public']) if user: error = _save_user(request, user, new=False) if error: return render_json(request, error, template='user_json.html', status=400) if 'properties' in to_save: user_profile.save_properties(to_save['properties']) user_profile.save() request.method = "GET" return profile(request, status=202) else: return HttpResponseBadRequest("method %s is not allowed".format( request.method))
def practice(request): """ Return the given number of questions to practice adaptively. In case of POST request, try to save the answer(s). GET parameters: filter: list of lists of identifiers (may be prefixed by minus sign to mark complement) language: language (str) of flashcards avoid: list of item ids to avoid limit: number of returned questions (default 10, maximum 100) time: time in format '%Y-%m-%d_%H:%M:%S' used for practicing user: identifier for the practicing user (only for stuff users) stats: turn on the enrichment of the objects by some statistics html: turn on the HTML version of the API BODY: see answer resource """ if request.user.id is None: # Google Bot return render_json(request, { 'error': _('There is no user available for the practice.'), 'error_type': 'user_undefined' }, status=400, template='models_json.html') limit = min(int(request.GET.get('limit', 10)), 100) # prepare user = get_user_id(request) time = get_time(request) avoid = load_query_json(request.GET, "avoid", "[]") practice_filter = get_filter(request) practice_context = PracticeContext.objects.from_content(practice_filter) environment = get_environment() item_selector = get_item_selector() if is_time_overridden(request): environment.shift_time(time) # save answers if request.method == 'POST': _save_answers(request, practice_context) if len(practice_filter) > 0: item_ids = Item.objects.filter_all_reachable_leaves(practice_filter, get_language(request)) else: item_ids = Item.objects.get_all_available_leaves() item_ids = list(set(item_ids) - set(avoid)) if len(item_ids) == 0: return render_json(request, { 'error': _('There is no item for the given filter to practice.'), 'error_type': 'empty_practice' }, status=404, template='models_json.html') selected_items, meta = item_selector.select(environment, user, item_ids, time, practice_context.id, limit, items_in_queue=len(avoid)) result = [] for item, item_meta in zip(selected_items, meta): question = { 'object_type': 'question', 'payload': Item.objects.item_id_to_json(item), } if item_meta is not None: question['meta'] = item_meta result.append(question) return render_json(request, result, template='models_json.html', help_text=practice.__doc__)