0379a07f7edfaa835a406f53669b14c4af09ae55
[oweals/karmaworld.git] / karmaworld / apps / quizzes / views.py
1 #!/usr/bin/env python
2 # -*- coding:utf8 -*-
3 # Copyright (C) 2014  FinalsClub Foundation
4 from itertools import chain
5 import json
6 from django.core.exceptions import ObjectDoesNotExist
7 from django.core.urlresolvers import reverse
8 from django.forms.formsets import formset_factory
9 from django.http import HttpResponseRedirect, HttpResponseBadRequest, HttpResponseNotFound, HttpResponse
10
11 from django.views.generic import DetailView, FormView
12 from django.views.generic.detail import SingleObjectMixin
13 from django.views.generic.edit import FormMixin, ProcessFormView
14 from karmaworld.apps.notes.models import Note
15 from karmaworld.apps.quizzes.forms import KeywordForm
16 from karmaworld.apps.quizzes.models import Quiz, ALL_QUESTION_CLASSES, Keyword, BaseQuizQuestion, \
17     ALL_QUESTION_CLASSES_NAMES, MultipleChoiceQuestion, MultipleChoiceOption, TrueFalseQuestion, FlashCardQuestion
18 from karmaworld.utils import ajax_pk_base, ajax_base
19
20
21 class QuizView(DetailView):
22     queryset = Quiz.objects.all()
23     model = Quiz
24     context_object_name = 'quiz'  # name passed to template
25     template_name = 'quizzes/quiz.html'
26
27     def get_context_data(self, **kwargs):
28         all_questions = []
29         for cls in ALL_QUESTION_CLASSES:
30             all_questions.append(
31                 [(cls.__name__, o) for o in cls.objects.filter(quiz=self.object)]
32             )
33
34         result_list = sorted(chain.from_iterable(all_questions),
35                              key=lambda o: o[1].timestamp,
36                              reverse=True)
37
38         kwargs['questions'] = result_list
39         kwargs['quiz'] = self.object
40
41         return super(QuizView, self).get_context_data(**kwargs)
42
43
44 class KeywordEditView(FormView):
45     template_name = 'quizzes/keyword_edit.html'
46     form_class = formset_factory(KeywordForm)
47
48     def get(self, requests, *args, **kwargs):
49         self.lookup_note()
50         return super(KeywordEditView, self).get(requests, *args, **kwargs)
51
52     def post(self, requests, *args, **kwargs):
53         self.lookup_note()
54         return super(KeywordEditView, self).post(requests, *args, **kwargs)
55
56     def lookup_note(self):
57         self.note = Note.objects.get(slug=self.kwargs['slug'])
58
59     def get_success_url(self):
60         return reverse('keyword_edit', args=(self.note.course.school.slug, self.note.course.slug, self.note.slug))
61
62     def get_initial(self):
63         existing_keywords = self.note.keyword_set.order_by('id')
64         initial_data = [{'keyword': keyword.word, 'definition': keyword.definition, 'id': keyword.pk}
65                         for keyword in existing_keywords]
66         return initial_data
67
68     def get_context_data(self, **kwargs):
69         kwargs['note'] = self.note
70         kwargs['prototype_form'] = KeywordForm
71         return super(KeywordEditView, self).get_context_data(**kwargs)
72
73     def form_valid(self, formset):
74         for form in formset:
75             word = form['keyword'].data
76             definition = form['definition'].data
77             id = form['id'].data
78             if word == '':
79                 continue
80             try:
81                 keyword_object = Keyword.objects.get(id=id)
82             except (ValueError, ObjectDoesNotExist):
83                 keyword_object = Keyword()
84
85             keyword_object.note = self.note
86             keyword_object.word = word
87             keyword_object.definition = definition
88             keyword_object.save()
89
90         return super(KeywordEditView, self).form_valid(formset)
91
92
93 def quiz_answer(request):
94     """Handle an AJAX request checking if a quiz answer is correct"""
95     if not (request.method == 'POST' and request.is_ajax()):
96         # return that the api call failed
97         return HttpResponseBadRequest(json.dumps({'status': 'fail', 'message': 'must be a POST ajax request'}),
98                                       mimetype="application/json")
99
100     try:
101         question_type_str = request.POST['question_type']
102         if question_type_str not in ALL_QUESTION_CLASSES_NAMES:
103             raise Exception("Not a valid question type")
104         question_type_class = ALL_QUESTION_CLASSES_NAMES[question_type_str]
105         question = question_type_class.objects.get(id=request.POST['id'])
106
107         correct = False
108
109         if question_type_class is MultipleChoiceQuestion:
110             answer = MultipleChoiceOption.objects.get(id=request.POST['answer'])
111             if answer.question == question and answer.correct:
112                 correct = True
113
114         elif question_type_class is TrueFalseQuestion:
115             answer = request.POST['answer'] == 'true'
116             correct = question.true == answer
117
118         elif question_type_class is FlashCardQuestion:
119             answer = request.POST['answer'].lower()
120             correct = question.keyword_side.lower() == answer
121
122     except Exception, e:
123         return HttpResponseBadRequest(json.dumps({'status': 'fail',
124                                                   'message': e.message,
125                                                   'exception': e.__class__.__name__}),
126                                       mimetype="application/json")
127
128     return HttpResponse(json.dumps({'correct': correct}), mimetype="application/json")
129
130
131 def set_keyword(annotation_uri, keyword, definition, ranges):
132     try:
133         keyword = Keyword.objects.get(note_id=annotation_uri, word=keyword, ranges=ranges)
134         keyword.definition = definition
135         keyword.save()
136     except ObjectDoesNotExist:
137         Keyword.objects.create(note_id=annotation_uri, word=keyword, definition=definition, ranges=ranges)
138
139
140 def delete_keyword(annotation_uri, keyword, definition, ranges):
141     keyword = Keyword.objects.get(note_id=annotation_uri, word=keyword, definition=definition, ranges=ranges)
142     keyword.definition = definition
143     keyword.delete()
144
145
146 def process_set_delete_keyword(request):
147     annotator_data = json.loads(request.raw_post_data)
148     annotation_uri = annotator_data['uri']
149     keyword = annotator_data['quote']
150     definition = annotator_data['text']
151     ranges = json.dumps(annotator_data['ranges'])
152
153     try:
154         if request.method in ('POST', 'PUT'):
155             set_keyword(annotation_uri, keyword, definition, ranges)
156         elif request.method == 'DELETE':
157             delete_keyword(annotation_uri, keyword, definition, ranges)
158     except Exception, e:
159         return HttpResponseNotFound(json.dumps({'status': 'fail', 'message': e.message}),
160                                     mimetype="application/json")
161
162
163 def set_delete_keyword_annotator(request):
164     return ajax_base(request, process_set_delete_keyword, ('POST', 'PUT', 'DELETE'))
165
166
167 def get_keywords_annotator(request):
168     annotation_uri = request.GET['uri']
169
170     try:
171         keywords = Keyword.objects.filter(note_id=annotation_uri).exclude(ranges=None)
172         keywords_data = {
173             'total': len(keywords),
174             'rows': []
175         }
176         for keyword in keywords:
177             keyword_data = {
178                 'quote': keyword.word,
179                 'text': keyword.definition,
180                 'ranges': json.loads(keyword.ranges),
181                 'created': keyword.timestamp.isoformat(),
182             }
183             keywords_data['rows'].append(keyword_data)
184
185         return HttpResponse(json.dumps(keywords_data), mimetype='application/json')
186
187     except ObjectDoesNotExist, e:
188         return HttpResponseNotFound(json.dumps({'status': 'fail', 'message': e.message}),
189                                     mimetype="application/json")
190
191
192 def get_keywords_datatables(request):
193     annotation_uri = request.GET['uri']
194
195     try:
196         keywords = Keyword.objects.filter(note_id=annotation_uri)
197         keywords_data = {
198             'total': len(keywords),
199             'rows': []
200         }
201         for keyword in keywords:
202             keyword_data = {
203                 'quote': keyword.word,
204                 'text': keyword.definition,
205                 'ranges': json.loads(keyword.ranges),
206                 'created': keyword.timestamp.isoformat(),
207             }
208             keywords_data['rows'].append(keyword_data)
209
210         return HttpResponse(json.dumps(keywords_data), mimetype='application/json')
211
212     except ObjectDoesNotExist, e:
213         return HttpResponseNotFound(json.dumps({'status': 'fail', 'message': e.message}),
214                                     mimetype="application/json")
215