Create quizzes based on keywords
authorCharles Connell <charles@connells.org>
Mon, 24 Feb 2014 22:15:40 +0000 (17:15 -0500)
committerCharles Connell <charles@connells.org>
Mon, 24 Feb 2014 22:15:40 +0000 (17:15 -0500)
karmaworld/apps/notes/admin.py
karmaworld/apps/notes/models.py
karmaworld/apps/quizzes/admin.py
karmaworld/apps/quizzes/create_quiz.py [new file with mode: 0644]
karmaworld/apps/quizzes/management/commands/create_quiz.py [new file with mode: 0644]
karmaworld/apps/quizzes/migrations/0002_rename_flashcard_fields.py [new file with mode: 0644]
karmaworld/apps/quizzes/models.py
karmaworld/assets/js/quiz.js
karmaworld/templates/quizzes/quiz.html
karmaworld/urls.py

index 90e17e698f46103c34f14ed5304cef17de0bd21d..7a4a65a24764ef39892215007bcb8fad3211025d 100644 (file)
@@ -14,5 +14,6 @@ class NoteAdmin(admin.ModelAdmin):
     autocomplete_lookup_fields = {
         'fk': ('course', 'user'),
     }
+    list_display = ('fp_file', 'upstream_link', 'name', 'id')
 
 admin.site.register(Note, NoteAdmin)
index b73e4cef25e3e700c78382b4441ca02c82c603fa..54e453fdd30080c587fd1408ad9f1c74d9efa45d 100644 (file)
@@ -242,7 +242,7 @@ class Note(Document):
         ordering = ['-uploaded_at']
 
     def __unicode__(self):
-        return u"Note at {0} (from {1})".format(self.fp_file, self.upstream_link)
+        return u"Note at {0} (from {1}) ({2})".format(self.fp_file, self.upstream_link, self.id)
 
     def natural_key(self):
         """
index 66481a177eab1923445ccc017e3b9e5941e4d7c9..ea1b8b8577280ad56e2fe7eadc538242a31d8e45 100644 (file)
@@ -24,7 +24,7 @@ class MultipleChoiceQuestionInlineAdmin(NestedStackedInline):
 
 class FlashCardQuestionInlineAdmin(NestedStackedInline):
     model = FlashCardQuestion
-    list_display = ('sideA', 'sideB', 'quiz')
+    list_display = ('keyword_side', 'definition_side', 'quiz')
 
 
 class TrueFalseQuestionInlineAdmin(NestedStackedInline):
diff --git a/karmaworld/apps/quizzes/create_quiz.py b/karmaworld/apps/quizzes/create_quiz.py
new file mode 100644 (file)
index 0000000..4441e6c
--- /dev/null
@@ -0,0 +1,100 @@
+import random
+from karmaworld.apps.notes.models import Note
+from karmaworld.apps.quizzes.models import MultipleChoiceQuestion, Quiz, TrueFalseQuestion, MultipleChoiceOption, \
+    Keyword, FlashCardQuestion
+
+KEYWORD_MULTIPLE_CHOICE = 1
+DEFINITION_MULTIPLE_CHOICE = 2
+KEYWORD_DEFINITION_TRUE_FALSE = 3
+FLASHCARD_KEYWORD_BLANK = 4
+GENERATED_QUESTION_TYPE = (
+    KEYWORD_MULTIPLE_CHOICE,
+    DEFINITION_MULTIPLE_CHOICE,
+    KEYWORD_DEFINITION_TRUE_FALSE,
+    FLASHCARD_KEYWORD_BLANK,
+)
+
+MULTIPLE_CHOICE_CHOICES = 4
+
+
+def _create_keyword_multiple_choice(keyword, keywords, quiz):
+    question_object = MultipleChoiceQuestion.objects.create(
+        question_text=keyword.definition,
+        quiz=quiz)
+
+    MultipleChoiceOption.objects.create(
+        text=keyword.word,
+        correct=True,
+        question=question_object)
+
+    for other_keyword in random.sample(keywords.exclude(id=keyword.id), MULTIPLE_CHOICE_CHOICES - 1):
+        MultipleChoiceOption.objects.create(
+            text=other_keyword.word,
+            correct=False,
+            question=question_object)
+
+
+def _create_definition_multiple_choice(keyword, keywords, quiz):
+    question_object = MultipleChoiceQuestion.objects.create(
+        question_text=keyword.word,
+        quiz=quiz)
+
+    MultipleChoiceOption.objects.create(
+        text=keyword.definition,
+        correct=True,
+        question=question_object)
+
+    for other_keyword in random.sample(keywords.exclude(id=keyword.id), MULTIPLE_CHOICE_CHOICES - 1):
+        MultipleChoiceOption.objects.create(
+            text=other_keyword.definition,
+            correct=False,
+            question=question_object)
+
+
+def _create_keyword_definition_true_false(keyword, keywords, quiz):
+    true = random.choice((True, False))
+
+    if true:
+        definition = keyword.definition
+    else:
+        other_keyword = keywords.exclude(id=keyword.id)
+        definition = other_keyword.definition
+
+    question_text = 'Is the following a correct definition of {w}:<br/>{d}'. \
+        format(w=keyword.word, d=definition)
+
+    TrueFalseQuestion.objects.create(
+        text=question_text,
+        quiz=quiz,
+        true=true)
+
+
+def _create_keyword_flashcard_blank(keyword, quiz):
+    FlashCardQuestion.objects.create(
+        definition_side=keyword.definition,
+        keyword_side=keyword.word,
+        quiz=quiz)
+
+
+def quiz_from_keywords(note_id):
+    note_object = Note.objects.get(id=note_id)
+    quiz_object = Quiz.objects.create(note=note_object, name=note_object.name)
+    keywords = Keyword.objects.filter(note=note_object)
+
+    for keyword in keywords:
+        if keyword.word and keyword.definition:
+            question_type = random.choice(GENERATED_QUESTION_TYPE)
+
+            if question_type is KEYWORD_MULTIPLE_CHOICE:
+                _create_keyword_multiple_choice(keyword, keywords, quiz_object)
+
+            elif question_type is DEFINITION_MULTIPLE_CHOICE:
+                _create_definition_multiple_choice(keyword, keywords, quiz_object)
+
+            elif question_type is KEYWORD_DEFINITION_TRUE_FALSE:
+                _create_keyword_definition_true_false(keyword, keywords, quiz_object)
+
+            elif question_type is FLASHCARD_KEYWORD_BLANK:
+                _create_keyword_flashcard_blank(keyword, quiz_object)
+
+
diff --git a/karmaworld/apps/quizzes/management/commands/create_quiz.py b/karmaworld/apps/quizzes/management/commands/create_quiz.py
new file mode 100644 (file)
index 0000000..a0a49da
--- /dev/null
@@ -0,0 +1,20 @@
+#!/usr/bin/env python
+# -*- coding:utf8 -*-
+# Copyright (C) 2014  FinalsClub Foundation
+from argparse import ArgumentError
+from django.core.management import BaseCommand
+from karmaworld.apps.quizzes.create_quiz import quiz_from_keywords
+
+
+class Command(BaseCommand):
+    args = '<note ID>'
+    help = """
+           Create a quiz out of the keywords and definitions
+           already on file for the given note.
+           """
+
+    def handle(self, *args, **kwargs):
+        if len(args) != 1:
+            raise ArgumentError("Incorrect arguments, see usage")
+        quiz_from_keywords(args[0])
+
diff --git a/karmaworld/apps/quizzes/migrations/0002_rename_flashcard_fields.py b/karmaworld/apps/quizzes/migrations/0002_rename_flashcard_fields.py
new file mode 100644 (file)
index 0000000..854d6ce
--- /dev/null
@@ -0,0 +1,17 @@
+# -*- coding: utf-8 -*-
+from south.utils import datetime_utils as datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+
+class Migration(SchemaMigration):
+
+    def forwards(self, orm):
+        db.rename_column(u'quizzes_flashcardquestion', 'sideA', 'keyword_side')
+        db.rename_column(u'quizzes_flashcardquestion', 'sideB', 'definition_side')
+
+
+    def backwards(self, orm):
+        db.rename_column(u'quizzes_flashcardquestion', 'keyword_side', 'sideA')
+        db.rename_column(u'quizzes_flashcardquestion', 'definition_side', 'sideB')
index 6e659dd31edb2981ff5506b38b4e7381118eebc7..cd161b5a5232c212cdc9bd129ad8c2e089f3ed00 100644 (file)
@@ -87,14 +87,14 @@ class MultipleChoiceOption(models.Model):
 
 
 class FlashCardQuestion(BaseQuizQuestion):
-    sideA = models.CharField(max_length=2048, verbose_name='Side A')
-    sideB = models.CharField(max_length=2048, verbose_name='Side B')
+    keyword_side = models.CharField(max_length=2048, verbose_name='Keyword')
+    definition_side = models.CharField(max_length=2048, verbose_name='Definition')
 
     class Meta:
         verbose_name = 'Flash card question'
 
     def __unicode__(self):
-        return self.sideA + ' / ' + self.sideB
+        return self.keyword_side + ' / ' + self.definition_side
 
 
 class TrueFalseQuestion(BaseQuizQuestion):
index 5fa8dbd3390d33e93eabdbac4ac1409d5383f24b..fb863015eaa7b41cfdadbdb293c1cc8495ac4aad 100644 (file)
@@ -23,7 +23,7 @@ function addForm(event) {
   var definitionInput = newForm.find('.definition');
   definitionInput.attr('id', newIdRoot + 'definition');
   definitionInput.attr('name', newNameRoot + 'definition');
-  definitionInput.keydown(addForm);
+  definitionInput.keydown(tabHandler);
 
   var objectIdInput = newForm.find('.object-id');
   objectIdInput.attr('id', newIdRoot + 'id');
index ad622410dba43393e1ec33925744defeead26b86..364c5b5ca3dfd180b61993ad089e9689f422e5b6 100644 (file)
@@ -88,8 +88,8 @@
             {% if 'FlashCardQuestion' in item.0 %}
               {% with question=item.1 %}
                 <div class="question flash-card">
-                  <p>{{ question.sideA }}</p>
-                  <p>{{ question.sideB }}</p>
+                  <p>{{ question.keyword_side }}</p>
+                  <p>{{ question.definition_side }}</p>
                 </div>
               {% endwith %}
             {% endif %}
index 56f6ed2c95b5fe0069db2e8faf57ec8a0e2ac27e..0834cd8eb62cfc421f76a1d9ec18ec020eb6f02b 100644 (file)
@@ -114,7 +114,7 @@ urlpatterns = patterns('',
         NoteView.as_view(), name='note_detail'),
 
     # Quizzes
-    url(r'^note/' + SLUG.format('school_') + '/' + SLUG.format('course_') +'/'+ SLUG.format('') +'/quiz/$',
+    url(r'^quiz/(?P<pk>[\d]+)/$',
         QuizView.as_view(), name='quiz'),
     url(r'^note/' + SLUG.format('school_') + '/' + SLUG.format('course_') +'/'+ SLUG.format('') +'/keywords/$',
         KeywordEditView.as_view(), name='keyword_edit'),