Commit ebc0db3dc2231f189437d2ae0be93e6a737b55dc
1 parent
1e152bf2
Exists in
master
and in
3 other branches
saving progress on report view
Showing
8 changed files
with
299 additions
and
63 deletions
Show diff stats
amadeus/static/css/base/amadeus.css
@@ -1209,4 +1209,10 @@ div.dataTables_wrapper div.dataTables_paginate { | @@ -1209,4 +1209,10 @@ div.dataTables_wrapper div.dataTables_paginate { | ||
1209 | width: 15%; | 1209 | width: 15%; |
1210 | text-align: center; | 1210 | text-align: center; |
1211 | } | 1211 | } |
1212 | + | ||
1213 | +#report-header li { | ||
1214 | + display: inline; | ||
1215 | + margin-right: 10px; | ||
1216 | + font-size: 16px; | ||
1217 | +} | ||
1212 | /* End Reports */ | 1218 | /* End Reports */ |
1213 | \ No newline at end of file | 1219 | \ No newline at end of file |
reports/forms.py
@@ -5,12 +5,12 @@ import datetime | @@ -5,12 +5,12 @@ import datetime | ||
5 | 5 | ||
6 | 6 | ||
7 | class CreateInteractionReportForm(forms.Form): | 7 | class CreateInteractionReportForm(forms.Form): |
8 | - topic = forms.ChoiceField(required=True, label= _("topics to select data from")) | ||
9 | - init_date = forms.DateField(required=True) | ||
10 | - end_date = forms.DateField(required=True) | 8 | + topic = forms.ChoiceField( label= _("topics to select data from")) |
9 | + init_date = forms.DateField() | ||
10 | + end_date = forms.DateField() | ||
11 | 11 | ||
12 | - from_mural = forms.BooleanField() | ||
13 | - from_messages = forms.BooleanField() | 12 | + from_mural = forms.BooleanField(required=False) |
13 | + from_messages = forms.BooleanField(required=False) | ||
14 | 14 | ||
15 | class Meta: | 15 | class Meta: |
16 | fields = ('topic', 'init_date', 'end_date', 'from_mural' , 'from_messages') | 16 | fields = ('topic', 'init_date', 'end_date', 'from_mural' , 'from_messages') |
@@ -22,3 +22,4 @@ class CreateInteractionReportForm(forms.Form): | @@ -22,3 +22,4 @@ class CreateInteractionReportForm(forms.Form): | ||
22 | topics = list(initial['topic']) | 22 | topics = list(initial['topic']) |
23 | 23 | ||
24 | self.fields['topic'].choices = [(topic.id, topic.name) for topic in topics] | 24 | self.fields['topic'].choices = [(topic.id, topic.name) for topic in topics] |
25 | + self.fields['topic'].choices.append((_("all"), _("all"))) |
reports/templates/reports/_form.html
@@ -11,6 +11,21 @@ | @@ -11,6 +11,21 @@ | ||
11 | {% render_field field class='form-control' %} | 11 | {% render_field field class='form-control' %} |
12 | {% endif %} | 12 | {% endif %} |
13 | 13 | ||
14 | + {% if field.errors %} | ||
15 | + <div class="row"> | ||
16 | + </br> | ||
17 | + <div class="alert alert-danger alert-dismissible" role="alert"> | ||
18 | + <button type="button" class="close" data-dismiss="alert" aria-label="Close"> | ||
19 | + <span aria-hidden="true">×</span> | ||
20 | + </button> | ||
21 | + <ul> | ||
22 | + {% for error in field.errors %} | ||
23 | + <li>{{ error }}</li> | ||
24 | + {% endfor %} | ||
25 | + </ul> | ||
26 | + </div> | ||
27 | + </div> | ||
28 | + {% endif %} | ||
14 | {% endfor %} | 29 | {% endfor %} |
15 | <div class="row text-center"> | 30 | <div class="row text-center"> |
16 | <input type="submit" value="Search" class="btn btn-success btn-raised" /> | 31 | <input type="submit" value="Search" class="btn btn-success btn-raised" /> |
@@ -0,0 +1,44 @@ | @@ -0,0 +1,44 @@ | ||
1 | +{% extends 'base.html' %} | ||
2 | + | ||
3 | +{% load static i18n pagination %} | ||
4 | +{% load django_bootstrap_breadcrumbs %} | ||
5 | +{% load widget_tweaks %} | ||
6 | + | ||
7 | +{% block breadcrumbs %} | ||
8 | + {{ block.super }} | ||
9 | + | ||
10 | + {% breadcrumb 'analytics' '' %} | ||
11 | +{% endblock %} | ||
12 | + | ||
13 | +{% block content %} | ||
14 | + | ||
15 | + <div class="panel panel-info topic-panel"> | ||
16 | + <div class="panel-heading"> | ||
17 | + <div class="row"> | ||
18 | + <div class="col-md-12 category-header"> | ||
19 | + <h4 class="panel-title" style="margin-top: 10px; margin-bottom: 8px"> | ||
20 | + <span>{% trans "Analytics" %}</span> | ||
21 | + </h4> | ||
22 | + </div> | ||
23 | + </div> | ||
24 | + </div> | ||
25 | + </div> | ||
26 | + | ||
27 | + <div id="core-subjects-options-div"> | ||
28 | + <ul class="core-subjects-options report-menu-choice"> | ||
29 | + <li class="active"> | ||
30 | + {% trans "Interaction Data" %} | ||
31 | + </li> | ||
32 | + <li> | ||
33 | + {% trans "Report Card" %} | ||
34 | + </li> | ||
35 | + <li> | ||
36 | + {% trans "Participation" %} | ||
37 | + </li> | ||
38 | + </ul> | ||
39 | + </div> | ||
40 | + | ||
41 | + {% include "reports/_form.html" %} | ||
42 | + | ||
43 | + | ||
44 | +{% endblock content %} | ||
0 | \ No newline at end of file | 45 | \ No newline at end of file |
reports/templates/reports/report.html
@@ -1,57 +0,0 @@ | @@ -1,57 +0,0 @@ | ||
1 | -{% extends 'base.html' %} | ||
2 | - | ||
3 | -{% load static i18n pagination %} | ||
4 | -{% load django_bootstrap_breadcrumbs %} | ||
5 | -{% load widget_tweaks %} | ||
6 | - | ||
7 | -{% block breadcrumbs %} | ||
8 | - {{ block.super }} | ||
9 | - | ||
10 | - {% breadcrumb 'analytics' '' %} | ||
11 | -{% endblock %} | ||
12 | - | ||
13 | -{% block content %} | ||
14 | - | ||
15 | - <div class="panel panel-info topic-panel"> | ||
16 | - <div class="panel-heading"> | ||
17 | - <div class="row"> | ||
18 | - <div class="col-md-12 category-header"> | ||
19 | - <h4 class="panel-title" style="margin-top: 10px; margin-bottom: 8px"> | ||
20 | - <span>{% trans "Analytics" %}</span> | ||
21 | - </h4> | ||
22 | - </div> | ||
23 | - </div> | ||
24 | - </div> | ||
25 | - </div> | ||
26 | - | ||
27 | - <div id="core-subjects-options-div"> | ||
28 | - <ul class="core-subjects-options report-menu-choice"> | ||
29 | - <li class="active"> | ||
30 | - {% trans "Interaction Data" %} | ||
31 | - </li> | ||
32 | - <li> | ||
33 | - {% trans "Report Card" %} | ||
34 | - </li> | ||
35 | - <li> | ||
36 | - {% trans "Participation" %} | ||
37 | - </li> | ||
38 | - </ul> | ||
39 | - </div> | ||
40 | - | ||
41 | - {% include "reports/_form.html" %} | ||
42 | - | ||
43 | - {% for user, datum in data.items %} | ||
44 | - | ||
45 | - | ||
46 | - <p> | ||
47 | - <ul> | ||
48 | - | ||
49 | - {{user}} : | ||
50 | - {% for key, value in datum.items %} | ||
51 | - <li>{{key}}: {{value}}</li> | ||
52 | - {% endfor %} | ||
53 | - </ul> | ||
54 | - | ||
55 | - </p> | ||
56 | - {% endfor %} | ||
57 | -{% endblock content %} | ||
58 | \ No newline at end of file | 0 | \ No newline at end of file |
@@ -0,0 +1,87 @@ | @@ -0,0 +1,87 @@ | ||
1 | +{% extends 'base.html' %} | ||
2 | + | ||
3 | +{% load static i18n pagination %} | ||
4 | +{% load django_bootstrap_breadcrumbs %} | ||
5 | +{% load widget_tweaks %} | ||
6 | + | ||
7 | +{% block breadcrumbs %} | ||
8 | + {{ block.super }} | ||
9 | + | ||
10 | + {% breadcrumb 'analytics' '' %} | ||
11 | +{% endblock %} | ||
12 | + | ||
13 | +{% block content %} | ||
14 | + | ||
15 | + {% if messages %} | ||
16 | + {% for message in messages %} | ||
17 | + <div class="alert alert-{{ message.tags }} alert-dismissible" role="alert"> | ||
18 | + <button type="button" class="close" data-dismiss="alert" aria-label="Close"> | ||
19 | + <span aria-hidden="true">×</span> | ||
20 | + </button> | ||
21 | + <p>{{ message }}</p> | ||
22 | + </div> | ||
23 | + {% endfor %} | ||
24 | + {% endif %} | ||
25 | + | ||
26 | + | ||
27 | + <div class="panel panel-info topic-panel"> | ||
28 | + <div class="panel-heading"> | ||
29 | + <div class="row"> | ||
30 | + <div class="col-md-12 category-header"> | ||
31 | + <h4 class="panel-title" style="margin-top: 10px; margin-bottom: 8px"> | ||
32 | + <span>{% trans "Analytics" %}</span> | ||
33 | + </h4> | ||
34 | + </div> | ||
35 | + </div> | ||
36 | + </div> | ||
37 | + </div> | ||
38 | + | ||
39 | + <div id="core-subjects-options-div"> | ||
40 | + <ul class="core-subjects-options report-menu-choice"> | ||
41 | + <li class="active"> | ||
42 | + {% trans "Interaction Data" %} | ||
43 | + </li> | ||
44 | + <li> | ||
45 | + {% trans "Report Card" %} | ||
46 | + </li> | ||
47 | + <li> | ||
48 | + {% trans "Participation" %} | ||
49 | + </li> | ||
50 | + </ul> | ||
51 | + </div> | ||
52 | + | ||
53 | + <div class="col-md-12"> | ||
54 | + <ul id="report-header"> | ||
55 | + <li><b>{% trans "Subject" %}:</b> {{subject_name}}</li> | ||
56 | + <li><b>{% trans "Topic" %}:</b> {{topic_name}}</li> | ||
57 | + <li><b>{% trans "Initial Date" %}:</b> {{init_date}}</li> | ||
58 | + <li><b>{% trans "End Date" %}:</b> {{end_date}}</li> | ||
59 | + <li><button class="btn btn-success btn-raised">{% trans "new search" %}</button></li> | ||
60 | + | ||
61 | + </ul> | ||
62 | + <div class="table-responsive"> | ||
63 | + <table class="table table-stripped"> | ||
64 | + <thead> | ||
65 | + <tr> | ||
66 | + {% for key in data.keys %} | ||
67 | + <th>{{key}}</th> | ||
68 | + {% endfor %} | ||
69 | + </tr> | ||
70 | + </thead> | ||
71 | + <tbody> | ||
72 | + | ||
73 | + {% for value_dict in data.values %} | ||
74 | + <tr> | ||
75 | + {% for key, value in value_dict.items %} | ||
76 | + <td>{{value}}</td> | ||
77 | + {% endfor %} | ||
78 | + </tr> | ||
79 | + {% endfor %} | ||
80 | + </tbody> | ||
81 | + | ||
82 | + </table> | ||
83 | + </div> | ||
84 | + </div> | ||
85 | + | ||
86 | + | ||
87 | +{% endblock content %} | ||
0 | \ No newline at end of file | 88 | \ No newline at end of file |
reports/urls.py
@@ -4,4 +4,5 @@ from . import views | @@ -4,4 +4,5 @@ from . import views | ||
4 | 4 | ||
5 | urlpatterns = [ | 5 | urlpatterns = [ |
6 | url(r'^create/interactions/$', views.ReportView.as_view(), name='create_interaction'), | 6 | url(r'^create/interactions/$', views.ReportView.as_view(), name='create_interaction'), |
7 | + url(r'^view/interactions/$', views.ViewReportView.as_view(), name='view_report'), | ||
7 | ] | 8 | ] |
8 | \ No newline at end of file | 9 | \ No newline at end of file |
reports/views.py
@@ -3,6 +3,9 @@ from django.http import HttpResponse, JsonResponse | @@ -3,6 +3,9 @@ from django.http import HttpResponse, JsonResponse | ||
3 | from django.utils.translation import ugettext_lazy as _ | 3 | from django.utils.translation import ugettext_lazy as _ |
4 | 4 | ||
5 | from django import forms | 5 | from django import forms |
6 | +from django.core.urlresolvers import reverse_lazy | ||
7 | + | ||
8 | +from django.contrib import messages | ||
6 | 9 | ||
7 | import django.views.generic as generic | 10 | import django.views.generic as generic |
8 | from mural.models import SubjectPost, Comment, MuralVisualizations | 11 | from mural.models import SubjectPost, Comment, MuralVisualizations |
@@ -15,7 +18,7 @@ from log.models import Log | @@ -15,7 +18,7 @@ from log.models import Log | ||
15 | 18 | ||
16 | 19 | ||
17 | class ReportView(LoginRequiredMixin, generic.FormView): | 20 | class ReportView(LoginRequiredMixin, generic.FormView): |
18 | - template_name = "reports/report.html" | 21 | + template_name = "reports/create.html" |
19 | form_class = CreateInteractionReportForm | 22 | form_class = CreateInteractionReportForm |
20 | 23 | ||
21 | def get_initial(self): | 24 | def get_initial(self): |
@@ -30,3 +33,139 @@ class ReportView(LoginRequiredMixin, generic.FormView): | @@ -30,3 +33,139 @@ class ReportView(LoginRequiredMixin, generic.FormView): | ||
30 | initial['topic'] = topics | 33 | initial['topic'] = topics |
31 | initial['end_date'] = date.today() | 34 | initial['end_date'] = date.today() |
32 | return initial | 35 | return initial |
36 | + | ||
37 | + | ||
38 | + def get_success_url(self): | ||
39 | + | ||
40 | + messages.success(self.request, _("Report created successfully")) | ||
41 | + | ||
42 | + get_params = "?" | ||
43 | + #passing form data through GET | ||
44 | + for key, value in self.form_data.items(): | ||
45 | + get_params += key + "=" + str(value) + "&" | ||
46 | + | ||
47 | + | ||
48 | + #retrieving subject id for data purposes | ||
49 | + for key, value in self.request.GET.items(): | ||
50 | + get_params += key + "=" + str(value) | ||
51 | + | ||
52 | + return reverse_lazy('subjects:reports:view_report', kwargs={}) + get_params | ||
53 | + | ||
54 | + def post(self, request, *args, **kwargs): | ||
55 | + """ | ||
56 | + Handles POST requests, instantiating a form instance with the passed | ||
57 | + POST variables and then checked for validity. | ||
58 | + """ | ||
59 | + form = self.get_form() | ||
60 | + if form.is_valid(): | ||
61 | + | ||
62 | + self.form_data = form.cleaned_data | ||
63 | + return self.form_valid(form) | ||
64 | + else: | ||
65 | + return self.form_invalid(form) | ||
66 | + | ||
67 | + | ||
68 | +class ViewReportView(LoginRequiredMixin, generic.TemplateView): | ||
69 | + template_name = "reports/view.html" | ||
70 | + | ||
71 | + | ||
72 | + def get_context_data(self, **kwargs): | ||
73 | + context = {} | ||
74 | + params_data = self.request.GET | ||
75 | + subject = Subject.objects.get(id=params_data['subject_id']) | ||
76 | + context['subject_name'] = subject.name | ||
77 | + context['topic_name'] = params_data['topic'] | ||
78 | + context['init_date'] = params_data['init_date'] | ||
79 | + context['end_date'] = params_data['end_date'] | ||
80 | + | ||
81 | + if params_data['from_mural']: | ||
82 | + context['data'] = self.get_mural_data(subject, params_data['init_date'], params_data['end_date']) | ||
83 | + return context | ||
84 | + | ||
85 | + def get_mural_data(self, subject, init_date, end_date): | ||
86 | + data = {} | ||
87 | + students = subject.students.all() | ||
88 | + formats = ["%d/%m/%Y", "%m/%d/%Y"] #so it accepts english and portuguese date formats | ||
89 | + for fmt in formats: | ||
90 | + try: | ||
91 | + init_date = datetime.strptime(init_date, fmt) | ||
92 | + end_date = datetime.strptime(end_date, fmt) | ||
93 | + except ValueError: | ||
94 | + pass | ||
95 | + | ||
96 | + | ||
97 | + for student in students: | ||
98 | + interactions = {} | ||
99 | + interactions['username'] = student.social_name | ||
100 | + | ||
101 | + help_posts_made_by_user = SubjectPost.objects.filter(action="help",space__id=subject.id, user=student, | ||
102 | + create_date__range=(init_date, end_date)) | ||
103 | + | ||
104 | + #number of help posts created by the student | ||
105 | + interactions['doubts_count'] = help_posts_made_by_user.count() | ||
106 | + | ||
107 | + help_posts = SubjectPost.objects.filter(action="help", create_date__range=(init_date, end_date), | ||
108 | + space__id=subject.id) | ||
109 | + | ||
110 | + #comments count on help posts created by the student | ||
111 | + interactions['comments_count'] = Comment.objects.filter(post__in = help_posts.filter(user=student), | ||
112 | + create_date__range=(init_date, end_date)).count() | ||
113 | + | ||
114 | + | ||
115 | + #count the amount of comments made by the student on posts made by one of the professors | ||
116 | + interactions['comments_professor_count'] = Comment.objects.filter(post__in = help_posts.filter(user__in= subject.professor.all()), create_date__range=(init_date, end_date), | ||
117 | + user=student).count() | ||
118 | + | ||
119 | + #comments made by the user on other users posts | ||
120 | + interactions['comments_on_others_count'] = Comment.objects.filter(post__in = help_posts.exclude(user=student), | ||
121 | + create_date__range=(init_date, end_date), | ||
122 | + user= student).count() | ||
123 | + | ||
124 | + | ||
125 | + | ||
126 | + comments_by_teacher = Comment.objects.filter(user__in=subject.professor.all()) | ||
127 | + help_posts_ids = [] | ||
128 | + for comment in comments_by_teacher: | ||
129 | + help_posts_ids.append(comment.post.id) | ||
130 | + #number of help posts created by the user that the teacher commented on | ||
131 | + interactions['help_posts_commented_by_teacher'] = help_posts.filter(user=student, id__in = help_posts_ids).count() | ||
132 | + | ||
133 | + | ||
134 | + comments_by_others = Comment.objects.filter(user__in=subject.students.exclude(id = student.id)) | ||
135 | + help_posts_ids = [] | ||
136 | + for comment in comments_by_teacher: | ||
137 | + help_posts_ids.append(comment.post.id) | ||
138 | + #number of help posts created by the user others students commented on | ||
139 | + interactions['help_posts_commented_by_others'] = help_posts.filter(user=student, id__in = help_posts_ids).count() | ||
140 | + | ||
141 | + #Number of student visualizations on the mural of the subject | ||
142 | + interactions['mural_visualizations_count'] = MuralVisualizations.objects.filter(post__in = SubjectPost.objects.filter(space__id=subject.id), | ||
143 | + user = student).count() | ||
144 | + | ||
145 | + | ||
146 | + #VAR20 - number of access to mural between 6 a.m to 12a.m. | ||
147 | + interactions['access_subject_between_6_to_12_am'] = Log.objects.filter(action="access", resource="subject", | ||
148 | + user_id= student.id, context__contains = {'subject_id' : subject.id}, datetime__hour__range = (5, 11)).count() | ||
149 | + | ||
150 | + #VAR21 - number of access to mural between 6 a.m to 12a.m. | ||
151 | + interactions['access_subject_between_0_to_6_pm'] = Log.objects.filter(action="access", resource="subject", | ||
152 | + user_id= student.id, context__contains = {'subject_id' : subject.id}, datetime__hour__range = (11, 17)).count() | ||
153 | + #VAR22 | ||
154 | + interactions['access_subject_between_6_to_12_pm'] = Log.objects.filter(action="access", resource="subject", | ||
155 | + user_id= student.id, context__contains = {'subject_id' : subject.id}, datetime__hour__range = (17, 23)).count() | ||
156 | + | ||
157 | + #VAR23 | ||
158 | + interactions['access_subject_between_0_to_6_am'] = Log.objects.filter(action="access", resource="subject", | ||
159 | + user_id= student.id, context__contains = {'subject_id' : subject.id}, datetime__hour__range = (23, 5)).count() | ||
160 | + | ||
161 | + #VAR24 through 30 | ||
162 | + day_numbers = [0, 1, 2, 3, 4, 5, 6] | ||
163 | + day_names = ["sunday", "monday", "tuesday", "wednesday", "thursday", "friday", "saturday"] | ||
164 | + for day_num in day_numbers: | ||
165 | + interactions['access_subject_'+day_names[day_num]] = Log.objects.filter(action="access", resource="subject", | ||
166 | + user_id= student.id, context__contains = {'subject_id' : subject.id}, datetime__week_day = day_num).count() | ||
167 | + | ||
168 | + data[student] = interactions | ||
169 | + print(data) | ||
170 | + return data | ||
171 | + |