Exemplo n.º 1
0
 def _load_objects(request, object_class):
     objs = object_class.objects
     if hasattr(objs, 'prepare_related'):
         objs = objs.prepare_related()
     if 'filter_column' in request.GET and 'filter_value' in request.GET:
         column = request.GET['filter_column']
         value = request.GET['filter_value']
         if value.isdigit():
             value = int(value)
         objs = objs.filter(**{column: value})
     else:
         objs = objs.all()
     if object_class == FlashcardAnswer:
         user_id = get_user_id(request, allow_override=True)
         item_filter = get_filter(request)
         if len(item_filter) != 0:
             item_ids = Item.objects.filter_all_reachable_leaves(
                 item_filter, get_language(request))
             objs = objs.filter(item_asked__in=item_ids)
         objs = objs.filter(user_id=user_id).order_by('-time')
     if object_class == Flashcard or object_class == settings.PROSO_FLASHCARDS.get("term_extension", Term) or \
             object_class == settings.PROSO_FLASHCARDS.get("context_extension", Context) or object_class == Category:
         language = get_language(request)
         objs = objs.filter(lang=language)
     return objs
Exemplo n.º 2
0
def schedule_email_with_discount_code(user,
                                      discount_percentage=50,
                                      dry=False,
                                      output_dir=None):
    discount_code = DiscountCode.objects.filter(
        identifier='email_user_discount_code_{}'.format(user.id)).first()
    if discount_code is None:
        discount_code = DiscountCode.objects.create(
            identifier='email_user_discount_code_{}'.format(user.id),
            usage_limit=1,
            code=DiscountCode.objects.generate_code(),
            discount_percentage=discount_percentage)
    request = get_current_request(force=False)
    if request is not None:
        language = get_language(request)
    else:
        last_answer = Answer.objects.filter(user=user).order_by('-id').first()
        language = last_answer.lang if last_answer is not None else 'en'
    language = canonize_language_for_email(language)
    ScheduledEmail.objects.schedule_more(
        '*****@*****.**',
        'Anatom: Děkujeme, že sis vybral(a) nás'
        if language == 'cs' else 'Practice Anatomy: Thank you chose us',
        os.path.join(settings.BASE_DIR, 'anatomy', 'templates', 'email',
                     'thanks_discount_code_{}.html'.format(language)),
        users=[user],
        template_kwargs={'discount_code': discount_code},
        dry=dry,
        output_dir=output_dir)
Exemplo n.º 3
0
def schedule_welcome_email(sender, instance, created=False, **kwargs):
    if not created:
        return
    if instance.user.email is None or instance.user.email == '':
        return
    request = get_current_request(force=False)
    if request is None:
        return
    language = get_language(request)
    language = canonize_language_for_email(language)
    ScheduledEmail.objects.schedule_more(
        '*****@*****.**',
        'Anatom: Vítej' if language == 'cs' else 'Practice Anatomy: Welcome',
        os.path.join(settings.BASE_DIR, 'anatomy', 'templates', 'email',
                     'welcome_{}.html'.format(language)),
        users=[instance.user])
    # reminder e-mails
    templates = glob.glob(
        os.path.join(settings.BASE_DIR, 'anatomy', 'templates', 'email',
                     'relation_question_{}_*.html'.format(language)))
    random.shuffle(templates)
    shifts = [1, 3, 7]
    last_datetime = datetime.datetime.now()
    for i, template in enumerate(templates):
        shift = shifts[min(i, len(shifts) - 1)]
        last_datetime = last_datetime + datetime.timedelta(days=shift)
        ScheduledEmail.objects.schedule_more(
            '*****@*****.**',
            'Anatom: Otázka dne'
            if language == 'cs' else 'Practice Anatomy: Today\'s question',
            template,
            users=[instance.user],
            scheduled=last_datetime)
Exemplo n.º 4
0
 def _load_objects(request, object_class):
     objs = object_class.objects
     if hasattr(objs, 'prepare_related'):
         objs = objs.prepare_related().filter(active=True)
     db_filter = proso_common.views.get_db_filter(request)
     objs = objs.filter(lang=get_language(request)) if db_filter is None else objs.filter(**db_filter)
     return objs
Exemplo n.º 5
0
 def _load_objects(request, object_class):
     objs = object_class.objects.prepare_related()
     db_filter = proso_common.views.get_db_filter(request)
     objs = objs.all() if db_filter is None else objs.filter(**db_filter)
     if object_class == Concept:
         objs = objs.filter(active=True, lang=get_language(request))
     return objs
Exemplo n.º 6
0
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__)
Exemplo n.º 7
0
def user_stats_bulk(request):
    """
    Get statistics for selected users and concepts

    since:
      time as timestamp - get stats changed since
    users:
      list of identifiers of users
    concepts (Optional):
      list of identifiers of concepts
    language:
      language of concepts
    """

    language = get_language(request)
    users = load_query_json(request.GET, "users")
    since = None
    if 'since' in request.GET:
        since = datetime.datetime.fromtimestamp(int(request.GET['since']))
    concepts = None
    if "concepts" in request.GET:
        concepts = Concept.objects.filter(lang=language, active=True,
                                          identifier__in=load_query_json(request.GET, "concepts"))
    stats = UserStat.objects.get_user_stats(users, language, concepts=concepts, since=since)
    data = {"users": []}
    for user, s in stats.items():
        data["users"].append({
            "user_id": user,
            "concepts": s,
        })
    return render_json(request, data, template='concepts_json.html', help_text=user_stats_bulk.__doc__)
Exemplo n.º 8
0
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")
Exemplo n.º 9
0
 def _load_objects(request, object_class):
     objs = object_class.objects.prepare_related()
     db_filter = proso_common.views.get_db_filter(request)
     objs = objs.all() if db_filter is None else objs.filter(**db_filter)
     if object_class == Concept:
         objs = objs.filter(active=True, lang=get_language(request))
     return objs
Exemplo n.º 10
0
def item2object(request, json_list, nested):
    if any([x.get('object_type', '') != 'item' for x in json_list]):
        raise Exception('Only items can be translated to objects!')
    item_ids = [x['id'] for x in json_list]
    translated = models.Item.objects.translate_item_ids(item_ids, get_language(request), is_nested=nested)
    for object_json in json_list:
        for key, value in translated[object_json['id']].items():
            object_json[key] = value
Exemplo n.º 11
0
def to_practice(request):
    practice_filter = get_filter(request)
    item_ids = Item.objects.filter_all_reachable_leaves(practice_filter, get_language(request))
    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')
    result = [Item.objects.item_id_to_json(item_id) for item_id in item_ids]
    return render_json(request, result, template='models_json.html', help_text=to_practice.__doc__)
Exemplo n.º 12
0
def plans(request):
    lang = get_language(request)
    discount_code = get_discount_code(request)
    if discount_code is not None:
        discount_code.is_valid(request.user, throw_exception=True)
    return render_json(request, [
        p.to_json(lang=lang, discount_code=discount_code)
        for p in SubscriptionPlan.objects.prepare_related().filter(active=True)
    ],
                       template='subscription_json.html')
Exemplo n.º 13
0
def plans(request):
    lang = get_language(request)
    discount_code = get_discount_code(request)
    if discount_code is not None:
        discount_code.is_valid(request.user, throw_exception=True)
    return render_json(
        request,
        [p.to_json(lang=lang, discount_code=discount_code) for p in SubscriptionPlan.objects.prepare_related().filter(active=True)],
        template='subscription_json.html'
    )
Exemplo n.º 14
0
 def _load_objects(request, object_class):
     objs = object_class.objects
     if hasattr(objs, 'prepare_related'):
         objs = objs.prepare_related()
     db_filter = proso_common.views.get_db_filter(request)
     objs = objs.all() if db_filter is None else objs.filter(**db_filter)
     if object_class == FlashcardAnswer:
         user_id = get_user_id(request, allow_override=True)
         item_filter = get_filter(request)
         if len(item_filter) != 0:
             item_ids = Item.objects.filter_all_reachable_leaves(item_filter, get_language(request))
             objs = objs.filter(item_asked__in=item_ids)
         objs = objs.filter(user_id=user_id).order_by('-time')
     if object_class == Flashcard or object_class == settings.PROSO_FLASHCARDS.get("term_extension", Term) or \
             object_class == settings.PROSO_FLASHCARDS.get("context_extension", Context) or object_class == Category:
         language = get_language(request)
         objs = objs.filter(lang=language)
     if object_class in [Flashcard, Category, Context]:
         objs = objs.filter(active=True)
     return objs
Exemplo n.º 15
0
def answers(request):
    limit = min(int(request.GET.get('limit', 10)), 1000)
    user_id = get_user_id(request)
    item_ids = Item.objects.filter_all_reachable_leaves(
        get_filter(request), get_language(request))
    found_answers = Answer.objects.answers(
        Answer.objects.filter(item_asked_id__in=item_ids,
                              user_id=user_id).order_by('-id').values_list(
                                  'id', flat=True)[:limit])
    return render_json(request,
                       found_answers,
                       template='models_json.html',
                       help_text=answers.__doc__)
Exemplo n.º 16
0
 def _load_objects(request, object_class):
     objs = object_class.objects.prepare_related()
     if 'filter_column' in request.GET and 'filter_value' in request.GET:
         column = request.GET['filter_column']
         value = request.GET['filter_value']
         if value.isdigit():
             value = int(value)
         objs = objs.filter(**{column: value})
     else:
         objs = objs.all()
     if object_class == Concept:
         objs = objs.filter(active=True, lang=get_language(request))
     return objs
Exemplo n.º 17
0
 def _load_objects(request, object_class):
     objs = object_class.objects.prepare_related()
     if 'filter_column' in request.GET and 'filter_value' in request.GET:
         column = request.GET['filter_column']
         value = request.GET['filter_value']
         if value.isdigit():
             value = int(value)
         objs = objs.filter(**{column: value})
     else:
         objs = objs.all()
     if object_class == Concept:
         objs = objs.filter(active=True, lang=get_language(request))
     return objs
Exemplo n.º 18
0
def user_stats_bulk(request):
    """
    Get statistics for selected users and concepts

    since:
      time as timestamp - get stats changed since
    users:
      list of identifiers of users
    concepts (Optional):
      list of identifiers of concepts
    language:
      language of concepts
    """

    language = get_language(request)
    users = load_query_json(request.GET, "users")
    if request.user.is_staff:
        if not hasattr(request.user, 'userprofile') or User.objects.filter(
                pk__in=users, userprofile__classes__owner=request.user.
                userprofile).count() < len(users):
            return render_json(
                request, {
                    'error':
                    _('Some requested users are not in owned classes'),
                    'error_type': 'permission_denied'
                },
                template='concepts_json.html',
                status=401)
    since = None
    if 'since' in request.GET:
        since = datetime.datetime.fromtimestamp(int(request.GET['since']))
    concepts = None
    if "concepts" in request.GET:
        concepts = Concept.objects.filter(lang=language,
                                          active=True,
                                          identifier__in=load_query_json(
                                              request.GET, "concepts"))
    stats = UserStat.objects.get_user_stats(users,
                                            language,
                                            concepts=concepts,
                                            since=since)
    data = {"users": []}
    for user, s in stats.items():
        data["users"].append({
            "user_id": user,
            "concepts": s,
        })
    return render_json(request,
                       data,
                       template='concepts_json.html',
                       help_text=user_stats_bulk.__doc__)
Exemplo n.º 19
0
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
Exemplo n.º 20
0
def tag_values(request):
    """
    Get tags types and values with localized names

    language:
      language of tags
    """

    data = defaultdict(lambda: {"values": {}})
    for tag in Tag.objects.filter(lang=get_language(request)):
        data[tag.type]["name"] = tag.type_name
        data[tag.type]["values"][tag.value] = tag.value_name

    return render_json(request, data, template='concepts_json.html', help_text=tag_values.__doc__)
Exemplo n.º 21
0
 def _load_objects(request, object_class):
     objs = object_class.objects
     if hasattr(objs, 'prepare_related'):
         objs = objs.prepare_related()
     if 'filter_column' in request.GET and 'filter_value' in request.GET:
         column = request.GET['filter_column']
         value = request.GET['filter_value']
         if value.isdigit():
             value = int(value)
         objs = objs.filter(**{column: value})
     else:
         objs = objs.all()
     if object_class == FlashcardAnswer:
         user_id = get_user_id(request, allow_override=True)
         item_filter = get_filter(request)
         if len(item_filter) != 0:
             item_ids = Item.objects.filter_all_reachable_leaves(item_filter, get_language(request))
             objs = objs.filter(item_asked__in=item_ids)
         objs = objs.filter(user_id=user_id).order_by('-time')
     if object_class == Flashcard or object_class == settings.PROSO_FLASHCARDS.get("term_extension", Term) or \
             object_class == settings.PROSO_FLASHCARDS.get("context_extension", Context) or object_class == Category:
         language = get_language(request)
         objs = objs.filter(lang=language)
     return objs
Exemplo n.º 22
0
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=get_time_for_knowledge_overview(request))
    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")
Exemplo n.º 23
0
def tag_values(request):
    """
    Get tags types and values with localized names

    language:
      language of tags
    """

    data = defaultdict(lambda: {"values": {}})
    for tag in Tag.objects.filter(lang=get_language(request)):
        data[tag.type]["name"] = tag.type_name
        data[tag.type]["values"][tag.value] = tag.value_name

    return render_json(request,
                       data,
                       template='concepts_json.html',
                       help_text=tag_values.__doc__)
Exemplo n.º 24
0
def to_practice(request):
    practice_filter = get_filter(request)
    item_ids = Item.objects.filter_all_reachable_leaves(
        practice_filter, get_language(request))
    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')
    result = [Item.objects.item_id_to_json(item_id) for item_id in item_ids]
    return render_json(request,
                       result,
                       template='models_json.html',
                       help_text=to_practice.__doc__)
Exemplo n.º 25
0
def to_practice_counts(request):
    """
    Get number of items available to practice.

    filters:                -- use this or body
      json as in BODY
    language:
      language of the items

    BODY
      json in following format:
      {
        "#identifier": []         -- custom identifier (str) and filter
        ...
      }
    """
    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 or len(data) == 0:
        return render_json(request, {},
                           template='models_json.html',
                           help_text=to_practice_counts.__doc__)
    language = get_language(request)
    timer('to_practice_counts')
    filter_names, filter_filters = list(zip(*sorted(data.items())))
    reachable_leaves = Item.objects.filter_all_reachable_leaves_many(
        filter_filters, language)
    response = {
        group_id: {
            'filter': data[group_id],
            'number_of_items': len(items),
        }
        for group_id, items in zip(filter_names, reachable_leaves)
    }
    LOGGER.debug(
        "to_practice_counts - getting items in groups took %s seconds",
        (timer('to_practice_counts')))
    return render_json(request,
                       response,
                       template='models_json.html',
                       help_text=to_practice_counts.__doc__)
Exemplo n.º 26
0
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])
Exemplo n.º 27
0
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_identifier = request.GET['item'] if 'item' in request.GET else None
    item_secondary_identifier = request.GET[
        'item_secondary'] if 'item_secondary' in request.GET else None
    translated = Item.objects.translate_identifiers([
        i
        for i in [item_identifier, item_secondary_identifier] if i is not None
    ], get_language(request))
    item = translated.get(item_identifier)
    item_secondary = translated.get(item_secondary_identifier)
    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')
Exemplo n.º 28
0
def user_stats_bulk(request):
    """
    Get statistics for selected users and concepts

    since:
      time as timestamp - get stats changed since
    users:
      list of identifiers of users
    concepts (Optional):
      list of identifiers of concepts
    language:
      language of concepts
    """

    language = get_language(request)
    users = load_query_json(request.GET, "users")
    since = None
    if 'since' in request.GET:
        since = datetime.datetime.fromtimestamp(int(request.GET['since']))
    concepts = None
    if "concepts" in request.GET:
        concepts = Concept.objects.filter(lang=language,
                                          active=True,
                                          identifier__in=load_query_json(
                                              request.GET, "concepts"))
    stats = UserStat.objects.get_user_stats(users,
                                            language,
                                            concepts=concepts,
                                            since=since)
    data = {"users": []}
    for user, s in stats.items():
        data["users"].append({
            "user_id": user,
            "concepts": s,
        })
    return render_json(request,
                       data,
                       template='concepts_json.html',
                       help_text=user_stats_bulk.__doc__)
Exemplo n.º 29
0
def user_stats_bulk(request):
    """
    Get statistics for selected users and concepts

    since:
      time as timestamp - get stats changed since
    users:
      list of identifiers of users
    concepts (Optional):
      list of identifiers of concepts
    language:
      language of concepts
    """

    language = get_language(request)
    users = load_query_json(request.GET, "users")
    if request.user.is_staff:
        if not hasattr(request.user, 'userprofile') or User.objects.filter(pk__in=users,
                       userprofile__classes__owner=request.user.userprofile).count() < len(users):
            return render_json(request, {
                'error': _('Some requested users are not in owned classes'),
                'error_type': 'permission_denied'
            }, template='concepts_json.html', status=401)
    since = None
    if 'since' in request.GET:
        since = datetime.datetime.fromtimestamp(int(request.GET['since']))
    concepts = None
    if "concepts" in request.GET:
        concepts = Concept.objects.filter(lang=language, active=True,
                                          identifier__in=load_query_json(request.GET, "concepts"))
    stats = UserStat.objects.get_user_stats(users, language, concepts=concepts, since=since)
    data = {"users": []}
    for user, s in stats.items():
        data["users"].append({
            "user_id": user,
            "concepts": s,
        })
    return render_json(request, data, template='concepts_json.html', help_text=user_stats_bulk.__doc__)
Exemplo n.º 30
0
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__)
Exemplo n.º 31
0
def to_practice_counts(request):
    """
    Get number of items available to practice.

    filters:                -- use this or body
      json as in BODY
    language:
      language of the items

    BODY
      json in following format:
      {
        "#identifier": []         -- custom identifier (str) and filter
        ...
      }
    """
    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_json.html', help_text=to_practice_counts.__doc__)
    language = get_language(request)
    timer('to_practice_counts')
    filter_names, filter_filters = list(zip(*sorted(data.items())))
    reachable_leaves = Item.objects.filter_all_reachable_leaves_many(filter_filters, language)
    response = {
        group_id: {
            'filter': data[group_id],
            'number_of_items': len(items),
        }
        for group_id, items in zip(filter_names, reachable_leaves)
    }
    LOGGER.debug("flashcard_counts - getting flashcards in groups took %s seconds", (timer('to_practice_counts')))
    return render_json(request, response, template='models_json.html', help_text=to_practice_counts.__doc__)
Exemplo n.º 32
0
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__)
Exemplo n.º 33
0
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__)
Exemplo n.º 34
0
def answers_per_month(request):
    try:
        from pylab import rcParams
        import matplotlib.pyplot as plt
        import pandas
        import seaborn as sns
    except ImportError:
        return HttpResponse('Can not import python packages for analysis.',
                            status=503)
    categories = load_query_json(request.GET, "categories", "[]")
    translated = Item.objects.translate_identifiers(categories,
                                                    get_language(request))
    translated_inverted = {item: name for name, item in translated.items()}
    children = pandas.DataFrame([{
        'item': item,
        'category': translated_inverted[category]
    } for category, items in Item.objects.get_reachable_children(
        list(translated.values()), get_language(request)).items()
                                 for item in items])
    with connection.cursor() as cursor:
        cursor.execute('''
            SELECT item_id, date_part('month', time), COUNT(1)
            FROM proso_models_answer
            GROUP BY 1, 2
            ''')
        data = []
        for item, month, answers in cursor:
            data.append({
                'item': item,
                'month': month,
                'answers': answers,
            })
    data = pandas.DataFrame(data)
    if len(children) == 0:
        data['category'] = data['item'].apply(lambda i: 'category/all')
    else:
        data = pandas.merge(data, children, on='item', how='inner')

    if 'percentage' in request.GET:

        def _percentage(group):
            total = group['answers'].sum()
            return group.groupby('category').apply(lambda g: 100 * g[
                'answers'].sum() / total).reset_index().rename(
                    columns={0: 'answers'})

        data = data.groupby('month').apply(_percentage).reset_index()

    def _apply(group):
        group['answers_cumsum'] = group['answers'].cumsum()
        return group

    data = data.sort_values(by=['category'],
                            ascending=False).groupby('month').apply(_apply)
    data['month'] = data['month'].astype(int)
    sns.set(style='white')
    rcParams['figure.figsize'] = 15, 10
    palette = sns.color_palette("hls", max(5, len(categories)))
    fig = plt.figure()
    for i, category in enumerate(sorted(data['category'].unique())):
        item_data = data[data['category'] == category]
        sns.barplot(x='month',
                    y='answers_cumsum',
                    data=item_data,
                    label=category.split('/')[1],
                    color=palette[i % len(palette)],
                    ci=None)
    plt.ylabel('Answers' + (' (%)' if 'percentage' in request.GET else ''))
    plt.xlabel('Month')
    plt.title('Answers per Month')
    if 'percentage' in request.GET:
        plt.ylim(0, 100)
    plt.legend(loc='center left', bbox_to_anchor=(1, 0.5))

    response = HttpResponse(content_type='image/png')
    canvas = FigureCanvas(fig)
    canvas.print_png(response)
    return response
Exemplo n.º 35
0
def answers_per_month(request):
    try:
        from pylab import rcParams
        import matplotlib.pyplot as plt
        import pandas
        import seaborn as sns
    except ImportError:
        return HttpResponse('Can not import python packages for analysis.', status=503)
    categories = load_query_json(request.GET, "categories", "[]")
    translated = Item.objects.translate_identifiers(categories, get_language(request))
    translated_inverted = {item: name for name, item in translated.items()}
    children = pandas.DataFrame([
        {'item': item, 'category': translated_inverted[category]}
        for category, items in Item.objects.get_reachable_children(
            list(translated.values()), get_language(request)
        ).items()
        for item in items
    ])
    with connection.cursor() as cursor:
        cursor.execute(
            '''
            SELECT item_id, date_part('month', time), COUNT(1)
            FROM proso_models_answer
            GROUP BY 1, 2
            '''
        )
        data = []
        for item, month, answers in cursor:
            data.append({
                'item': item,
                'month': month,
                'answers': answers,
            })
    data = pandas.DataFrame(data)
    if len(children) == 0:
        data['category'] = data['item'].apply(lambda i: 'category/all')
    else:
        data = pandas.merge(data, children, on='item', how='inner')

    if 'percentage' in request.GET:
        def _percentage(group):
            total = group['answers'].sum()
            return group.groupby('category').apply(lambda g: 100 * g['answers'].sum() / total).reset_index().rename(columns={0: 'answers'})
        data = data.groupby('month').apply(_percentage).reset_index()

    def _apply(group):
        group['answers_cumsum'] = group['answers'].cumsum()
        return group
    data = data.sort_values(by=['category'], ascending=False).groupby('month').apply(_apply)
    data['month'] = data['month'].astype(int)
    sns.set(style='white')
    rcParams['figure.figsize'] = 15, 10
    palette = sns.color_palette("hls", max(5, len(categories)))
    fig = plt.figure()
    for i, category in enumerate(sorted(data['category'].unique())):
        item_data = data[data['category'] == category]
        sns.barplot(
            x='month',
            y='answers_cumsum',
            data=item_data,
            label=category.split('/')[1],
            color=palette[i % len(palette)],
            ci=None
        )
    plt.ylabel('Answers' + (' (%)' if 'percentage' in request.GET else ''))
    plt.xlabel('Month')
    plt.title('Answers per Month')
    if 'percentage' in request.GET:
        plt.ylim(0, 100)
    plt.legend(loc='center left', bbox_to_anchor=(1, 0.5))

    response = HttpResponse(content_type='image/png')
    canvas = FigureCanvas(fig)
    canvas.print_png(response)
    return response
Exemplo n.º 36
0
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')
Exemplo n.º 37
0
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')
Exemplo n.º 38
0
def answers(request):
    limit = min(int(request.GET.get('limit', 10)), 1000)
    user_id = get_user_id(request)
    item_ids = Item.objects.filter_all_reachable_leaves(get_filter(request), get_language(request))
    found_answers = Answer.objects.answers(Answer.objects.filter(item_asked_id__in=item_ids, user_id=user_id).order_by('-id').values_list('id', flat=True)[:limit])
    return render_json(request, found_answers, template='models_json.html', help_text=answers.__doc__)
Exemplo n.º 39
0
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 = sorted(list(set(flatten(reachable_leaves))))
    answers = environment.number_of_answers_more_items(all_leaves, user_id)
    correct_answers = 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 = Item.objects.predict_for_overview(
            environment, user_id, all_leaves)
        mastered = dict(
            list(zip(all_leaves,
                     [p >= mastery_threshold for p in predictions])))
        LOGGER.debug(
            "user_stats - getting predictions for items 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_items": 0,
            }
        else:
            response[identifier] = {
                "filter":
                data[identifier],
                "number_of_items":
                len(items),
                "number_of_practiced_items":
                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_items"] = sum(
                    mastered[i] for i in items)
    return render_json(request,
                       response,
                       template='models_user_stats.html',
                       help_text=user_stats.__doc__)
Exemplo n.º 40
0
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 items
        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, False)
    elif request.method == 'GET':
        PracticeSet.objects.filter(answer__user_id=request.user.id).update(
            finished=True)

    if limit > 0:
        item_ids = Item.objects.filter_all_reachable_leaves(
            practice_filter, get_language(request))
        item_ids = list(set(item_ids) - set(avoid))
        limit_size = get_config('proso_models',
                                'practice.limit_item_set_size_to_select_from',
                                default=None)
        if limit_size is not None and limit_size < len(item_ids):
            item_ids = sample(item_ids, limit_size)
        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)
    else:
        result = []

    return render_json(request,
                       result,
                       template='models_json.html',
                       help_text=practice.__doc__)