Skip to content

Commit

Permalink
Changement de remontée
Browse files Browse the repository at this point in the history
  • Loading branch information
artragis committed Sep 27, 2020
1 parent 14c21ca commit 44fdd11
Show file tree
Hide file tree
Showing 7 changed files with 197 additions and 42 deletions.
75 changes: 67 additions & 8 deletions assets/js/charts.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,35 @@
t = v * (1 - s * (1 - f))

switch (i) {
case 0: r = v; g = t; b = p; break
case 1: r = q; g = v; b = p; break
case 2: r = p; g = v; b = t; break
case 3: r = p; g = q; b = v; break
case 4: r = t; g = p; b = v; break
default: r = v; g = p; b = q
case 0:
r = v
g = t
b = p
break
case 1:
r = q
g = v
b = p
break
case 2:
r = p
g = v
b = t
break
case 3:
r = p
g = q
b = v
break
case 4:
r = t
g = p
b = v
break
default:
r = v
g = p
b = q
}

return [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)]
Expand Down Expand Up @@ -77,7 +100,38 @@
responsive: true
}

var charts = []
const charts = []

function setupPie($objects) {
$objects.each((_, object) => {
const $object = $(object)
const labels = $object.data('label')
const data = $object.data('values')
const nbColors = labels.length
const allColors = []
let n = 0
for (let i = 0; i < nbColors; i++) {
const color = hsvToRgb(n, 100, 80)
allColors.push(`rgb(${color[0]}, ${color[1]}, ${color[2]})`)
n += 360 / nbColors
}
console.log(allColors)
const config = {
type: 'pie',
data: {
labels: labels,
datasets: [{
label: 'Réponse',
data: data,
backgroundColor: allColors
}]
},
options: basicOptions
}
charts.push(new window.Chart($object, config))
})
}

function setupChart($object, formatter) {
var $dataX = $object.data('time')
var times = []
Expand All @@ -95,7 +149,7 @@
}
}
var n = 0
for (var o in allObjectData) {
for (const o in allObjectData) {
if (o.indexOf('views') > -1) {
var label = $object.data('label-' + o)
var color = hsvToRgb(n, 100, 80)
Expand Down Expand Up @@ -167,7 +221,12 @@
if ($('#sessions-graph').length) {
setupChart($('#sessions-graph'))
}
const quizzCharts = $('.quizz-chart')
if (quizzCharts.length) {
setupPie(quizzCharts)
}
}

drawCharts()

// Tab management
Expand Down
35 changes: 25 additions & 10 deletions assets/js/content-quizz.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,16 +62,19 @@ function computeForm(formdata, answers) {

function markBadAnswers(names, answers) {
const toAdd = []
names.forEach(({name}) => {
names.forEach(({ name }) => {
document.querySelectorAll('input[name="' + name + '"]').forEach(field => {
if (answers[name][parseInt(field.getAttribute('value'), 10)] && !field.checked) {
field.parentElement.classList.add('quizz-forget')
toAdd.push({name: name, value: field.getAttribute('value')})
toAdd.push({
name: name,
value: field.getAttribute('value')
})
}
})
document.querySelector(`.custom-block[data-name=${name}]`).classList.add('quizz-bad')
})
names.forEach(({name, value}) => {
names.forEach(({ name, value }) => {
document.querySelector(`input[type=checkbox][name="${name}"][value="${value}"]`)
.parentElement.classList.add('quizz-bad')
})
Expand All @@ -94,25 +97,37 @@ document.querySelectorAll('form.quizz').forEach(form => {
questions.push(result.name)
}
})
const statistics = {}
const statistics = {
expected: {},
result: {}
}
Object.keys(answers).forEach(name => {
const element = document.querySelector(`.custom-block[data-name="${name}"]`)
const title = document.querySelector(`.custom-block[data-name="${name}"] .custom-block-heading`).textContent
statistics.result[title] = {
evaluation: 'bad',
labels: []
}
statistics.expected[title] = {}
const availableResponses = element.querySelectorAll('input')
for (let i = 0; i < availableResponses.length; i++) {
statistics.expected[title][availableResponses[i].parentElement.textContent] = answers[name][i]
}
element.querySelectorAll('input:checked')
.forEach(node => statistics.result[title].labels.push(node.parentElement.textContent.trim()))
if (!element.classList.contains('quizz-bad')) {
element.classList.add('quizz-good')
statistics[title] = 'ok'
} else {
statistics[title] = 'bad'
statistics.result[title].evaluation = 'ok'
}
})
const csrfmiddlewaretoken = document.querySelector("input[name='csrfmiddlewaretoken']").value
const csrfmiddlewaretoken = document.querySelector('input[name=\'csrfmiddlewaretoken\']').value
const xhttp = new XMLHttpRequest()
xhttp.open('POST', form.getAttribute('action'))
xhttp.setRequestHeader('X-Requested-With', 'XMLHttpRequest')
xhttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded')
xhttp.setRequestHeader('Content-Type', 'application/json')
xhttp.setRequestHeader('X-CSRFToken', csrfmiddlewaretoken)
statistics.url = form.parentElement.previousElementSibling.firstElementChild.href
xhttp.send(Object.keys(statistics).map(k => encodeURIComponent(k) + '=' + encodeURIComponent(statistics[k])).join('&'))
xhttp.send(JSON.stringify(statistics))
// here send result
console.log(result)
})
Expand Down
28 changes: 17 additions & 11 deletions templates/misc/quizz.graph.part.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,21 @@


<div id="{{ tab_name }}" class="tabcontent">
<div class="stat-graph">
<h3>{% trans graph_title %}</h3>
<canvas
id="{{ canvas_id }}"
{% for url in stats %}
data-views-{{ forloop.counter0 }}="[{% for view in quizz_url.stats|dict_get:metric %}{{view|dict_get:metric}} {% if not forloop.last %},{% endif %}{% endfor %}]"
data-label-views-{{ forloop.counter0 }}="{{url.label}}"
{% endfor %}
data-time='[{% for view in stats.0.stats|dict_get:metric %}"{{view.date}}"{% if not forloop.last %},{% endif %} {% endfor %}]'>
</canvas>
</div>
{% for url, questions in quizz.items %}
<header>
<h3{{ url }}></h3>
</header>
{% for question, stats in questions.items %}
<article class="stat-graph">
<h4>{% trans graph_title %} {{ question }}</h4>
<ul>
{% for answer_name, answer_stats in stats.responses.items %}
<li class="{% if answer_stats.good %}quizz-forget{% endif %}">{{ answer_name }}
<progress aria-label="{% trans 'Résultat pour' %} {{ answer_name }}" max="{{ stats.total }}" value="{{ answer_stats.nb }}"/>
</li>
{% endfor %}
</ul>
</article>
{% endfor %}
{% endfor %}
</div>
2 changes: 1 addition & 1 deletion templates/tutorialv2/export/chapter.html
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ <h2 id="{{ extract.position_in_parent }}-{{ extract.slug }}">
{% if extract.text %}
<div class="extract-wrapper {% if extract.is_quizz %}quizz{% endif %}">
{% if extract.is_quizz %}
<form action="{% url 'content:answer-quizz' content.pk public_content.content_public_slug %}" class="quizz">
<form action="{% url 'content:answer-quizz' content.pk content.slug %}" class="quizz">
{% endif %}
{{ extract.get_text|emarkdown:is_js }}
{% if extract.is_quizz %}
Expand Down
2 changes: 1 addition & 1 deletion templates/tutorialv2/stats/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ <h2 class="ico-after ico-tutorials">
{% include "misc/graph.part.html" with tab_name="tab-users-graph-content" graph_title="Évolution du nombre de visiteurs" canvas_id="users-graph" metric="users" %}
{% include "misc/graph.part.html" with tab_name="tab-new-users-graph-content" graph_title="Évolution du nombre de nouveaux visiteurs" canvas_id="new-users-graph" metric="newUsers" %}
{% include "misc/graph.part.html" with tab_name="tab-sessions-graph-content" graph_title="Évolution du nombre de sessions" canvas_id="sessions-graph" metric="sessions" %}
{% include "misc/graph.part.html" with tab_name="tab-quizz-content" graph_title="Réponses au quizz" canvas_id="quizz-graph" metric="quizz" %}
{% include "misc/quizz.graph.part.html" with tab_name="tab-quizz-content" graph_title="Réponses à" canvas_id="quizz-graph" %}


{% if cumulative_stats_by_url %}
Expand Down
21 changes: 18 additions & 3 deletions zds/tutorialv2/models/quizz.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,26 @@
from zds.tutorialv2.models.database import PublishableContent


class QuizzStat(models.Model):
class QuizzQuestion(models.Model):
url = models.TextField(name='url', verbose_name='url', null=False, blank=False)
question = models.TextField(name="question", verbose_name="question", null=False, blank=False)


class QuizzAvailableAnswer(models.Model):
label = models.TextField(name="label", verbose_name="Intitulé de la réponse")
good_answer = models.BooleanField(name="is_good", verbose_name="Est une réponse attendue", default=False)
related_question = models.ForeignKey(QuizzQuestion, name="related_question", verbose_name="Question liée",
on_delete=models.CASCADE)


class QuizzUserAnswer(models.Model):
related_content = models.ForeignKey(PublishableContent,
verbose_name='Tutoriel lié',
blank=True, null=True,
on_delete=models.CASCADE)
url = models.TextField(name='url', verbose_name='url', null=False, blank=False)
question = models.TextField(name="question", verbose_name="question", null=False, blank=False)
answer = models.TextField(name="answer", verbose_name="anwser", null=False, blank=False)
date_answer = models.DateField(name="date_answer", verbose_name="Date of answer", null=False, auto_now=True)
related_question = models.ForeignKey(QuizzQuestion, name="related_question", verbose_name="Question liée",
on_delete=models.CASCADE)
full_answer_id = models.CharField(name="full_answer_id", verbose_name="Indentifiant de la réponse utilisateur",
blank=False, max_length=64, default='id')
76 changes: 68 additions & 8 deletions zds/tutorialv2/views/statistics.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
from collections import defaultdict, OrderedDict
import uuid
from collections import defaultdict, OrderedDict, Counter
from datetime import timedelta, datetime, date
from json import loads

from django.conf import settings
from django.contrib import messages
from django.core.exceptions import PermissionDenied
from django.db.models import Count
from django.utils.translation import ugettext_lazy as _
from django.views.generic import FormView

Expand All @@ -14,19 +17,41 @@

from zds.tutorialv2.forms import ContentCompareStatsURLForm, QuizzStatsForm
from zds.tutorialv2.mixins import SingleOnlineContentDetailViewMixin, SingleOnlineContentFormViewMixin
from zds.tutorialv2.models.quizz import QuizzStat
from zds.tutorialv2.models.quizz import QuizzUserAnswer, QuizzQuestion, QuizzAvailableAnswer
from zds.tutorialv2.utils import NamedUrl


class ContentQuizzStatistics(SingleOnlineContentFormViewMixin):
form_class = QuizzStatsForm

def post(self, request, *args, **kwargs):
request.POST = loads(request.body)
super(ContentQuizzStatistics, self).post(request, *args, **kwargs)

def form_valid(self, form):
url = form.cleaned_data['url']
answers = {k: v for k, v in self.request.POST.items() if k != 'url'}
for question, answer in answers.items():
stat = QuizzStat(related_content=self.object, url=url, answer=answer, question=question)
stat.save()
answers = {k: v for k, v in self.request.POST['result'].items()}
resp_id = str(uuid.uuid4())
for question, answers in answers.items():
db_question = QuizzQuestion.objects.filter(question=question, url=url).first()
if not db_question:
db_question = QuizzQuestion(question=question, url=url)
db_question.save()
given_available_answers = self.request.POST['expected'][question]
answers_labels = list(given_available_answers.keys())
known_labels = QuizzAvailableAnswer.objects.filter(related_question=db_question,
label__in=answers_labels).values_list('label', flat=True)
not_existing_answers = [l for l in answers_labels if l not in known_labels]
QuizzAvailableAnswer.objects.exclude(label__in=answers_labels).filter(related_question=db_question).delete()

for label in not_existing_answers:
db_answer = QuizzAvailableAnswer(related_question=db_question, label=label,
is_good=given_available_answers[label])
db_answer.save()
for answer in answers['labels']:
stat = QuizzUserAnswer(related_content=self.object, related_question=db_question,
full_answer_id=resp_id, answer=answer)
stat.save()
self.success_url = self.object.get_absolute_url_online()
return super(ContentQuizzStatistics, self).form_valid(form)

Expand Down Expand Up @@ -188,7 +213,6 @@ def get_stats(self, urls, report, display_mode, start, end):
stats[m] = sorted(stats[m], key=lambda k: k['date'])
element = {'label': url.name, 'stats': stats}
api_raw.append(element)

return api_raw

def get_simple_stat(self, report, info):
Expand Down Expand Up @@ -331,13 +355,49 @@ def get_context_data(self, **kwargs):
start_date, end_date = self.get_start_and_end_dates()
display_mode = self.get_display_mode(urls)
all_stats = self.get_all_stats(urls, start_date, end_date, display_mode)

quizz_stats = {}
base_questions = list(QuizzUserAnswer.objects
.filter(date_answer__range=(start_date, end_date),
related_content__pk=self.object.pk)
.values_list('related_question', flat=True))
total_per_question = list(QuizzUserAnswer.objects.values('related_question__pk')
.filter(related_question__pk__in=base_questions,
date_answer__range=(start_date, end_date))
.annotate(nb=Count('full_answer_id')))
total_per_question = {a['related_question__pk']: a['nb'] for a in
total_per_question}
total_per_label = list(QuizzUserAnswer.objects.values(
'related_question__pk', 'related_question__question', 'related_question__url', 'answer').
filter(related_question__in=base_questions,
date_answer__range=(start_date, end_date))
.annotate(nb=Count('answer')))

for base_question in set(base_questions):
full_answers_total = {}
url = ''
question = ''
for available_answer in QuizzAvailableAnswer.objects.filter(
related_question__pk=base_question).prefetch_related('related_question').all():
full_answers_total[available_answer.label] = {'good': available_answer.is_good, 'nb': 0}
url = available_answer.related_question.url
question = available_answer.related_question.question
for r in total_per_label:
if r['related_question__pk'] == base_question and \
r['answer'].strip() == available_answer.label.strip():
full_answers_total[available_answer.label]['nb'] = r['nb']
if url not in quizz_stats:
quizz_stats[url] = OrderedDict()
quizz_stats[url][question] = {
'total': total_per_question[base_question],
'responses': full_answers_total
}
context.update({
'display': display_mode,
'urls': urls,
'stats': all_stats[0], # Graph
'cumulative_stats_by_url': all_stats[1], # Table data
'referrers': all_stats[2],
'keywords': all_stats[3],
'quizz': quizz_stats
})
return context

0 comments on commit 44fdd11

Please sign in to comment.