3 # Copyright (C) 2014 FinalsClub Foundation
4 from itertools import chain
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
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
21 class QuizView(DetailView):
22 queryset = Quiz.objects.all()
24 context_object_name = 'quiz' # name passed to template
25 template_name = 'quizzes/quiz.html'
27 def get_context_data(self, **kwargs):
29 for cls in ALL_QUESTION_CLASSES:
31 [(cls.__name__, o) for o in cls.objects.filter(quiz=self.object)]
34 result_list = sorted(chain.from_iterable(all_questions),
35 key=lambda o: o[1].timestamp,
38 kwargs['questions'] = result_list
39 kwargs['quiz'] = self.object
41 return super(QuizView, self).get_context_data(**kwargs)
44 class KeywordEditView(FormView):
45 template_name = 'quizzes/keyword_edit.html'
46 form_class = formset_factory(KeywordForm)
48 def get(self, requests, *args, **kwargs):
50 return super(KeywordEditView, self).get(requests, *args, **kwargs)
52 def post(self, requests, *args, **kwargs):
54 return super(KeywordEditView, self).post(requests, *args, **kwargs)
56 def lookup_note(self):
57 self.note = Note.objects.get(slug=self.kwargs['slug'])
59 def get_success_url(self):
60 return reverse('keyword_edit', args=(self.note.course.school.slug, self.note.course.slug, self.note.slug))
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]
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)
73 def form_valid(self, formset):
75 word = form['keyword'].data
76 definition = form['definition'].data
81 keyword_object = Keyword.objects.get(id=id)
82 except (ValueError, ObjectDoesNotExist):
83 keyword_object = Keyword()
85 keyword_object.note = self.note
86 keyword_object.word = word
87 keyword_object.definition = definition
90 return super(KeywordEditView, self).form_valid(formset)
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")
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'])
109 if question_type_class is MultipleChoiceQuestion:
110 answer = MultipleChoiceOption.objects.get(id=request.POST['answer'])
111 if answer.question == question and answer.correct:
114 elif question_type_class is TrueFalseQuestion:
115 answer = request.POST['answer'] == 'true'
116 correct = question.true == answer
118 elif question_type_class is FlashCardQuestion:
119 answer = request.POST['answer'].lower()
120 correct = question.keyword_side.lower() == answer
123 return HttpResponseBadRequest(json.dumps({'status': 'fail',
124 'message': e.message,
125 'exception': e.__class__.__name__}),
126 mimetype="application/json")
128 return HttpResponse(json.dumps({'correct': correct}), mimetype="application/json")
131 def set_keyword(annotation_uri, keyword, definition, ranges):
133 keyword = Keyword.objects.get(note_id=annotation_uri, word=keyword, ranges=ranges)
134 keyword.definition = definition
136 except ObjectDoesNotExist:
137 Keyword.objects.create(note_id=annotation_uri, word=keyword, definition=definition, ranges=ranges)
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
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'])
153 if not request.user.is_authenticated():
154 return HttpResponseForbidden(json.dumps({'status': 'fail', 'message': "Only authenticated users may set keywords"}),
155 mimetype="application/json")
158 if request.method in ('POST', 'PUT'):
159 set_keyword(annotation_uri, keyword, definition, ranges)
160 elif request.method == 'DELETE':
161 delete_keyword(annotation_uri, keyword, definition, ranges)
163 return HttpResponseNotFound(json.dumps({'status': 'fail', 'message': e.message}),
164 mimetype="application/json")
167 def set_delete_keyword_annotator(request):
168 return ajax_base(request, process_set_delete_keyword, ('POST', 'PUT', 'DELETE'))
171 def get_keywords_annotator(request):
172 annotation_uri = request.GET['uri']
175 keywords = Keyword.objects.filter(note_id=annotation_uri).exclude(ranges=None)
177 'total': len(keywords),
180 for keyword in keywords:
182 'quote': keyword.word,
183 'text': keyword.definition,
184 'ranges': json.loads(keyword.ranges),
185 'created': keyword.timestamp.isoformat(),
187 keywords_data['rows'].append(keyword_data)
189 return HttpResponse(json.dumps(keywords_data), mimetype='application/json')
191 except ObjectDoesNotExist, e:
192 return HttpResponseNotFound(json.dumps({'status': 'fail', 'message': e.message}),
193 mimetype="application/json")
196 def get_keywords_datatables(request):
197 annotation_uri = request.GET['uri']
200 keywords = Keyword.objects.filter(note_id=annotation_uri)
202 'total': len(keywords),
205 for keyword in keywords:
207 'quote': keyword.word,
208 'text': keyword.definition,
209 'ranges': json.loads(keyword.ranges),
210 'created': keyword.timestamp.isoformat(),
212 keywords_data['rows'].append(keyword_data)
214 return HttpResponse(json.dumps(keywords_data), mimetype='application/json')
216 except ObjectDoesNotExist, e:
217 return HttpResponseNotFound(json.dumps({'status': 'fail', 'message': e.message}),
218 mimetype="application/json")