Don't give points when downloading own doc
[oweals/karmaworld.git] / karmaworld / apps / notes / views.py
index da1eaa709b81c172981937fca40139507d6c2c1d..b6cdaf46057075b82a5a4e6a02955c1ca9cac799 100644 (file)
@@ -4,24 +4,29 @@
 
 import traceback
 import logging
+from django.contrib import messages
 
 from django.core import serializers
+from django.core.exceptions import ValidationError
 from django.forms.formsets import formset_factory
+from karmaworld.apps.courses.forms import CourseForm
 from karmaworld.apps.courses.models import Course
 from karmaworld.apps.notes.search import SearchIndex
+from karmaworld.apps.quizzes.create_quiz import quiz_from_keywords
 from karmaworld.apps.quizzes.forms import KeywordForm
 from karmaworld.apps.quizzes.models import Keyword
+from karmaworld.apps.quizzes.tasks import submit_extract_keywords_hit, get_extract_keywords_results
 from karmaworld.apps.users.models import NoteKarmaEvent
 from karmaworld.utils.ajax_utils import *
 
-from django.http import HttpResponse, HttpResponseBadRequest
-from django.views.generic import DetailView, ListView
+from django.http import HttpResponse, HttpResponseBadRequest, HttpResponseForbidden
+from django.views.generic import DetailView, ListView, TemplateView
 from django.views.generic import FormView
 from django.views.generic import View
 from django.views.generic.detail import SingleObjectMixin
 
-from karmaworld.apps.notes.models import Note
-from karmaworld.apps.notes.forms import NoteForm
+from karmaworld.apps.notes.models import Note, KEYWORD_MTURK_THRESHOLD
+from karmaworld.apps.notes.forms import NoteForm, NoteDeleteForm
 
 
 logger = logging.getLogger(__name__)
@@ -32,76 +37,51 @@ FLAG_FIELD = 'flags'
 USER_PROFILE_FLAGS_FIELD = 'flagged_notes'
 
 
+def note_page_context_helper(note, request, context):
+
+    if request.method == 'POST':
+        context['note_edit_form'] = NoteForm(request.POST)
+    else:
+        tags_string = ','.join([str(tag) for tag in note.tags.all()])
+        context['note_edit_form'] = NoteForm(initial={'name': note.name,
+                                                      'tags': tags_string})
+
+    context['note_delete_form'] = NoteDeleteForm(initial={'note': note.id})
+
+    if note.is_pdf():
+        context['pdf_controls'] = True
+
+    if request.user.is_authenticated():
+        try:
+            request.user.get_profile().thanked_notes.get(pk=note.pk)
+            context['already_thanked'] = True
+        except ObjectDoesNotExist:
+            pass
+
+        try:
+            request.user.get_profile().flagged_notes.get(pk=note.pk)
+            context['already_flagged'] = True
+        except ObjectDoesNotExist:
+            pass
+
+
 class NoteDetailView(DetailView):
     """ Class-based view for the note html page """
     model = Note
     context_object_name = u"note" # name passed to template
-    keyword_form_class = formset_factory(KeywordForm)
-
-    def post(self, request, *args, **kwargs):
-        formset = self.keyword_form_class(request.POST)
-        if formset.is_valid():
-            self.keyword_form_valid(formset)
-            self.keyword_formset = self.keyword_form_class(initial=self.get_initial_keywords())
-            return super(NoteDetailView, self).get(request, *args, **kwargs)
-        else:
-            self.keyword_formset = formset
-            return super(NoteDetailView, self).get(request, *args, **kwargs)
-
-    def get(self, request, *args, **kwargs):
-        self.keyword_formset = self.keyword_form_class(initial=self.get_initial_keywords())
-        return super(NoteDetailView, self).get(request, *args, **kwargs)
+    template_name = 'notes/note_base.html'
 
     def get_context_data(self, **kwargs):
         """ Generate custom context for the page rendering a Note
             + if pdf, set the `pdf` flag
         """
 
-        kwargs['keyword_prototype_form'] = KeywordForm
-        kwargs['keyword_formset'] = self.keyword_formset
-        kwargs['keywords'] = Keyword.objects.filter(note=self.object)
-
-        if self.object.is_pdf():
-            kwargs['pdf_controls'] = True
+        kwargs['show_note_container'] = True
 
-        if self.request.user.is_authenticated():
-            try:
-                self.request.user.get_profile().thanked_notes.get(pk=self.object.pk)
-                kwargs['already_thanked'] = True
-            except ObjectDoesNotExist:
-                pass
-
-            try:
-                self.request.user.get_profile().flagged_notes.get(pk=self.object.pk)
-                kwargs['already_flagged'] = True
-            except ObjectDoesNotExist:
-                pass
+        note_page_context_helper(self.object, self.request, kwargs)
 
         return super(NoteDetailView, self).get_context_data(**kwargs)
 
-    def get_initial_keywords(self):
-        existing_keywords = self.get_object().keyword_set.order_by('id')
-        initial_data = [{'keyword': keyword.word, 'definition': keyword.definition, 'id': keyword.pk}
-                        for keyword in existing_keywords]
-        return initial_data
-
-    def keyword_form_valid(self, formset):
-        for form in formset:
-            word = form['keyword'].data
-            definition = form['definition'].data
-            id = form['id'].data
-            if word == '':
-                continue
-            try:
-                keyword_object = Keyword.objects.get(id=id)
-            except (ValueError, ObjectDoesNotExist):
-                keyword_object = Keyword()
-
-            keyword_object.note = self.get_object()
-            keyword_object.word = word
-            keyword_object.definition = definition
-            keyword_object.save()
-
 
 class NoteSaveView(FormView, SingleObjectMixin):
     """ Save a Note and then view the page, 
@@ -110,7 +90,16 @@ class NoteSaveView(FormView, SingleObjectMixin):
     """
     form_class = NoteForm
     model = Note
-    template_name = 'notes/note_detail.html'
+    template_name = 'notes/note_base.html'
+
+    def post(self, request, *args, **kwargs):
+        self.object = self.get_object()
+        if self.object.user != request.user:
+            raise ValidationError("Only the owner of a note can edit it.")
+        return super(NoteSaveView, self).post(request, *args, **kwargs)
+
+    def get_success_url(self):
+        return self.object.get_absolute_url()
 
     def get_context_data(self, **kwargs):
         context = {
@@ -118,26 +107,14 @@ class NoteSaveView(FormView, SingleObjectMixin):
         }
         return super(NoteSaveView, self).get_context_data(**context)
 
-    def get_success_url(self):
-        """ On form submission success, redirect to what url """
-        #TODO: redirect to note slug if possible (auto-slugify)
-        return u'/{school_slug}/{course_slug}?url=/{school_slug}/{course_slug}/{pk}&name={name}&thankyou'.format(
-                school_slug=self.object.course.school.slug,
-                course_slug=self.object.course.slug,
-                pk=self.object.pk,
-                name=self.object.name
-            )
-
     def form_valid(self, form):
         """ Actions to take if the submitted form is valid
             namely, saving the new data to the existing note object
         """
-        self.object = self.get_object()
         if len(form.cleaned_data['name'].strip()) > 0:
             self.object.name = form.cleaned_data['name']
-        self.object.year = form.cleaned_data['year']
         # use *arg expansion to pass tags a list of tags
-        self.object.tags.add(*form.cleaned_data['tags'])
+        self.object.tags.set(*form.cleaned_data['tags'])
         # User has submitted this form, so set the SHOW flag
         self.object.is_hidden = False
         self.object.save()
@@ -159,13 +136,114 @@ class NoteView(View):
         return view(request, *args, **kwargs)
 
     def post(self, request, *args, **kwargs):
-        if request.POST['action'] == 'tags-form':
-            view = NoteSaveView.as_view()
-        else:
-            view = NoteDetailView.as_view()
+        view = NoteSaveView.as_view()
         return view(request, *args, **kwargs)
 
 
+class NoteDeleteView(FormView):
+    form_class = NoteDeleteForm
+
+    def form_valid(self, form):
+        self.note = Note.objects.get(id=form.cleaned_data['note'])
+        self.note.is_hidden = True
+        self.note.save()
+
+        messages.success(self.request, 'The note "{0}" was deleted successfully.'.format(self.note.name))
+
+        return super(FormView, self).form_valid(form)
+
+    def get_success_url(self):
+        return self.note.course.get_absolute_url()
+
+
+class NoteKeywordsView(FormView, SingleObjectMixin):
+    """ Class-based view for the note html page """
+    model = Note
+    context_object_name = u"note" # name passed to template
+    form_class = formset_factory(KeywordForm)
+    template_name = 'notes/note_base.html'
+
+    def get_object(self, queryset=None):
+        return Note.objects.get(slug=self.kwargs['slug'])
+
+    def post(self, request, *args, **kwargs):
+        self.object = self.get_object()
+        if not self.request.user.is_authenticated():
+            raise ValidationError("Only authenticated users may set keywords.")
+
+        formset = self.form_class(request.POST)
+        if formset.is_valid():
+            self.keyword_form_valid(formset)
+            self.keyword_formset = self.form_class(initial=self.get_initial_keywords())
+            return super(NoteKeywordsView, self).get(request, *args, **kwargs)
+        else:
+            self.keyword_formset = formset
+            return super(NoteKeywordsView, self).get(request, *args, **kwargs)
+
+    def get(self, request, *args, **kwargs):
+        self.object = self.get_object()
+        self.keyword_formset = self.form_class(initial=self.get_initial_keywords())
+        return super(NoteKeywordsView, self).get(request, *args, **kwargs)
+
+    def get_context_data(self, **kwargs):
+        kwargs['keyword_prototype_form'] = KeywordForm
+        kwargs['keyword_formset'] = self.keyword_formset
+        kwargs['keywords'] = Keyword.objects.filter(note=self.get_object())
+        kwargs['show_keywords'] = True
+
+        note_page_context_helper(self.get_object(), self.request, kwargs)
+
+        return super(NoteKeywordsView, self).get_context_data(**kwargs)
+
+    def get_initial_keywords(self):
+        existing_keywords = self.get_object().keyword_set.order_by('id')
+        initial_data = [{'keyword': keyword.word, 'definition': keyword.definition, 'id': keyword.pk}
+                        for keyword in existing_keywords]
+        return initial_data
+
+    def keyword_form_valid(self, formset):
+        for form in formset:
+            word = form['keyword'].data
+            definition = form['definition'].data
+            id = form['id'].data
+            # If the user has deleted an existing keyword
+            if not word and not definition and id:
+                try:
+                    keyword_object = Keyword.objects.get(id=id)
+                    keyword_object.delete()
+                except (ValueError, ObjectDoesNotExist):
+                    pass
+
+            # otherwise get or create a keyword
+            elif word or definition:
+                try:
+                    keyword_object = Keyword.objects.get(id=id)
+                except (ValueError, ObjectDoesNotExist):
+                    keyword_object = Keyword()
+                    NoteKarmaEvent.create_event(self.request.user, self.get_object(), NoteKarmaEvent.CREATED_KEYWORD)
+
+                keyword_object.note = self.get_object()
+                keyword_object.word = word
+                keyword_object.definition = definition
+                keyword_object.unreviewed = False
+                keyword_object.save()
+
+
+class NoteQuizView(TemplateView):
+    template_name = 'notes/note_base.html'
+
+    def get_context_data(self, **kwargs):
+        note = Note.objects.get(slug=self.kwargs['slug'])
+
+        note_page_context_helper(note, self.request, kwargs)
+
+        kwargs['note'] = note
+        kwargs['questions'] = quiz_from_keywords(note)
+        kwargs['show_quiz'] = True
+
+        return super(NoteQuizView, self).get_context_data(**kwargs)
+
+
 class NoteSearchView(ListView):
     template_name = 'notes/search_results.html'
 
@@ -240,6 +318,11 @@ def process_note_thank_events(request_user, note):
     if note.user != request_user and note.user:
         NoteKarmaEvent.create_event(note.user, note, NoteKarmaEvent.THANKS)
 
+    # If note thanks exceeds a threshold, create a Mechanical
+    # Turk task to get some keywords for it
+    if note.thanks == KEYWORD_MTURK_THRESHOLD:
+        submit_extract_keywords_hit.delay(note)
+
 
 def thank_note(request, pk):
     """Record that somebody has thanked a note."""
@@ -265,7 +348,7 @@ def process_downloaded_note(request_user, note):
     """Record that somebody has downloaded a note"""
     if request_user.is_authenticated() and request_user != note.user:
         NoteKarmaEvent.create_event(request_user, note, NoteKarmaEvent.DOWNLOADED_NOTE)
-    if request_user.is_authenticated() and note.user:
+    if request_user.is_authenticated() and note.user and note.user != request_user:
         NoteKarmaEvent.create_event(note.user, note, NoteKarmaEvent.HAD_NOTE_DOWNLOADED)