X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=karmaworld%2Fapps%2Fnotes%2Fviews.py;h=b6cdaf46057075b82a5a4e6a02955c1ca9cac799;hb=5891561378249ef4b188e534f48e1257783eb3f0;hp=873628895b38a5f67212c84e79c3224f5349b320;hpb=bf2d0b9f1c80736f92bf2d064e5688dcdbe53404;p=oweals%2Fkarmaworld.git diff --git a/karmaworld/apps/notes/views.py b/karmaworld/apps/notes/views.py index 8736288..b6cdaf4 100644 --- a/karmaworld/apps/notes/views.py +++ b/karmaworld/apps/notes/views.py @@ -2,84 +2,83 @@ # -*- coding:utf8 -*- # Copyright (C) 2012 FinalsClub Foundation -import json import traceback import logging -from django.core.exceptions import ObjectDoesNotExist +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_increment import * - -import os +from karmaworld.utils.ajax_utils import * -from django.conf import settings -from django.http import HttpResponse, HttpResponseBadRequest, HttpResponseNotFound -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__) -PDF_MIMETYPES = ( - 'application/pdf', - 'application/vnd.ms-powerpoint', - 'application/vnd.openxmlformats-officedocument.presentationml.presentation' -) +THANKS_FIELD = 'thanks' +USER_PROFILE_THANKS_FIELD = 'thanked_notes' +FLAG_FIELD = 'flags' +USER_PROFILE_FLAGS_FIELD = 'flagged_notes' + +def note_page_context_helper(note, request, context): -def is_pdf(self): - if self.object.file_type == 'pdf': - return True - return False + 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}) -def is_ppt(self): - if self.object.file_type == 'ppt': - return True - return False + if note.is_pdf(): + context['pdf_controls'] = True -THANKS_FIELD = 'thanks' -USER_PROFILE_THANKS_FIELD = 'thanked_notes' -FLAG_FIELD = 'flags' -USER_PROFILE_FLAGS_FIELD = 'flagged_notes' + 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 + 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 """ - # not current using these - #kwargs['hostname'] = Site.objects.get_current() - - kwargs['pdf'] = is_pdf(self) - kwargs['ppt'] = is_ppt(self) - if self.object.mimetype in PDF_MIMETYPES: - 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) @@ -91,35 +90,31 @@ 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 = { 'object': self.get_object(), } - print "get context for NoteSaveView" 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() @@ -145,31 +140,108 @@ class NoteView(View): return view(request, *args, **kwargs) -class RawNoteDetailView(DetailView): - """ Class-based view for the raw note html for iframes """ - template_name = u'notes/note_raw.html' - context_object_name = u"note" - model = Note +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 PDFView(DetailView): - """ Render PDF files in an iframe based on ID""" - template_name = u'partial/pdfembed.html' +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): - """ Generate a path to the pdf file associated with this note - by generating a path to the MEDIA_URL by hand """ + note = Note.objects.get(slug=self.kwargs['slug']) + + note_page_context_helper(note, self.request, kwargs) - if is_ppt(self): - kwargs['pdf_path'] = "{0}{1}".format(settings.MEDIA_URL, - os.path.basename(self.object.pdf_file.name)) - elif is_pdf(self): - kwargs['pdf_path'] = self.object.fp_file - #kwargs['pdf_path'] = "{0}{1}".format(settings.MEDIA_URL, - # os.path.basename(self.object.note_file.name)) + kwargs['note'] = note + kwargs['questions'] = quiz_from_keywords(note) + kwargs['show_quiz'] = True - return super(PDFView, self).get_context_data(**kwargs) + return super(NoteQuizView, self).get_context_data(**kwargs) class NoteSearchView(ListView): @@ -246,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.""" @@ -271,12 +348,29 @@ 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) def downloaded_note(request, pk): """Record that somebody has flagged a note.""" - return ajax_base(Note, request, pk, process_downloaded_note) + return ajax_pk_base(Note, request, pk, process_downloaded_note) +def edit_note_tags(request, pk): + """ + Saves the posted string of tags + """ + if request.method == "POST" and request.is_ajax() and request.user.is_authenticated() and request.user.get_profile().can_edit_items(): + note = Note.objects.get(pk=pk) + note.tags.set(request.body) + + note_json = serializers.serialize('json', [note,]) + resp = json.loads(note_json)[0] + resp['fields']['tags'] = list(note.tags.names()) + + return HttpResponse(json.dumps(resp), mimetype="application/json") + else: + return HttpResponseBadRequest(json.dumps({'status': 'fail', 'message': 'Invalid request'}), + mimetype="application/json") +