Annotations
[oweals/karmaworld.git] / karmaworld / apps / notes / views.py
1 #!/usr/bin/env python
2 # -*- coding:utf8 -*-
3 # Copyright (C) 2012  FinalsClub Foundation
4
5 import json
6 import traceback
7 import logging
8
9 from django.core import serializers
10 from django.core.exceptions import ObjectDoesNotExist
11 from karmaworld.apps.courses.models import Course
12 from karmaworld.apps.notes.search import SearchIndex
13 from karmaworld.apps.users.models import NoteKarmaEvent
14 from karmaworld.utils.ajax_utils import *
15
16 import os
17
18 from django.conf import settings
19 from django.http import HttpResponse, HttpResponseBadRequest, HttpResponseNotFound
20 from django.views.generic import DetailView, ListView
21 from django.views.generic import FormView
22 from django.views.generic import View
23 from django.views.generic.detail import SingleObjectMixin
24
25 from karmaworld.apps.notes.models import Note
26 from karmaworld.apps.notes.forms import NoteForm
27
28
29 logger = logging.getLogger(__name__)
30
31 THANKS_FIELD = 'thanks'
32 USER_PROFILE_THANKS_FIELD = 'thanked_notes'
33 FLAG_FIELD = 'flags'
34 USER_PROFILE_FLAGS_FIELD = 'flagged_notes'
35
36
37 class NoteDetailView(DetailView):
38     """ Class-based view for the note html page """
39     model = Note
40     context_object_name = u"note" # name passed to template
41
42     def get_context_data(self, **kwargs):
43         """ Generate custom context for the page rendering a Note
44             + if pdf, set the `pdf` flag
45         """
46         if self.object.is_pdf():
47             kwargs['pdf_controls'] = True
48
49         if self.request.user.is_authenticated():
50             try:
51                 self.request.user.get_profile().thanked_notes.get(pk=self.object.pk)
52                 kwargs['already_thanked'] = True
53             except ObjectDoesNotExist:
54                 pass
55
56             try:
57                 self.request.user.get_profile().flagged_notes.get(pk=self.object.pk)
58                 kwargs['already_flagged'] = True
59             except ObjectDoesNotExist:
60                 pass
61
62         return super(NoteDetailView, self).get_context_data(**kwargs)
63
64
65 class NoteSaveView(FormView, SingleObjectMixin):
66     """ Save a Note and then view the page, 
67         behaves the same as NoteDetailView, except for saving the
68         NoteForm ModelForm
69     """
70     form_class = NoteForm
71     model = Note
72     template_name = 'notes/note_detail.html'
73
74     def get_context_data(self, **kwargs):
75         context = {
76             'object': self.get_object(),
77         }
78         print "get context for NoteSaveView"
79         return super(NoteSaveView, self).get_context_data(**context)
80
81     def get_success_url(self):
82         """ On form submission success, redirect to what url """
83         #TODO: redirect to note slug if possible (auto-slugify)
84         return u'/{school_slug}/{course_slug}?url=/{school_slug}/{course_slug}/{pk}&name={name}&thankyou'.format(
85                 school_slug=self.object.course.school.slug,
86                 course_slug=self.object.course.slug,
87                 pk=self.object.pk,
88                 name=self.object.name
89             )
90
91     def form_valid(self, form):
92         """ Actions to take if the submitted form is valid
93             namely, saving the new data to the existing note object
94         """
95         self.object = self.get_object()
96         if len(form.cleaned_data['name'].strip()) > 0:
97             self.object.name = form.cleaned_data['name']
98         self.object.year = form.cleaned_data['year']
99         # use *arg expansion to pass tags a list of tags
100         self.object.tags.add(*form.cleaned_data['tags'])
101         # User has submitted this form, so set the SHOW flag
102         self.object.is_hidden = False
103         self.object.save()
104         return super(NoteSaveView, self).form_valid(form)
105
106     def form_invalid(self, form):
107         """ Do stuff when the form is invalid !!! TODO """
108         # TODO: implement def form_invalid for returning a form with input and error
109         print "running form_invalid"
110         print form
111         print form.errors
112
113
114 class NoteView(View):
115     """ Notes superclass that wraps http methods """
116
117     def get(self, request, *args, **kwargs):
118         view = NoteDetailView.as_view()
119         return view(request, *args, **kwargs)
120
121     def post(self, request, *args, **kwargs):
122         view = NoteSaveView.as_view()
123         return view(request, *args, **kwargs)
124
125
126 class RawNoteDetailView(DetailView):
127     """ Class-based view for the raw note html for iframes """
128     template_name = u'notes/note_raw.html'
129     context_object_name = u"note"
130     model = Note
131
132
133 class NoteSearchView(ListView):
134     template_name = 'notes/search_results.html'
135
136     def get_queryset(self):
137         if not 'query' in self.request.GET:
138             return Note.objects.none()
139
140         if 'page' in self.request.GET:
141             page = int(self.request.GET['page'])
142         else:
143             page = 0
144
145         try:
146             index = SearchIndex()
147
148             if 'course_id' in self.request.GET:
149                 raw_results = index.search(self.request.GET['query'],
150                                                   self.request.GET['course_id'],
151                                                   page=page)
152             else:
153                 raw_results = index.search(self.request.GET['query'],
154                                             page=page)
155
156         except Exception:
157             logger.error("Error with IndexDen:\n" + traceback.format_exc())
158             self.error = True
159             return Note.objects.none()
160         else:
161             self.error = False
162
163         instances = Note.objects.in_bulk(raw_results.ordered_ids)
164         results = []
165         for id in raw_results.ordered_ids:
166             if id in instances:
167                 results.append((instances[id], raw_results.snippet_dict[id]))
168         self.has_more = raw_results.has_more
169
170         return results
171
172     def get_context_data(self, **kwargs):
173         if 'query' in self.request.GET:
174             kwargs['query'] = self.request.GET['query']
175
176         if 'course_id' in self.request.GET:
177             kwargs['course'] = Course.objects.get(id=self.request.GET['course_id'])
178
179         if self.error:
180             kwargs['error'] = True
181             return super(NoteSearchView, self).get_context_data(**kwargs)
182
183         # If query returned more search results than could
184         # fit on one page, show "Next" button
185         if self.has_more:
186             kwargs['has_next'] = True
187             if 'page' in self.request.GET:
188                 kwargs['next_page'] = int(self.request.GET['page']) + 1
189             else:
190                 kwargs['next_page'] = 1
191
192         # If the user is looking at a search result page
193         # that isn't the first one, show "Prev" button
194         if 'page' in self.request.GET and \
195             int(self.request.GET['page']) > 0:
196             kwargs['has_prev'] = True
197             kwargs['prev_page'] = int(self.request.GET['page']) - 1
198
199         return super(NoteSearchView, self).get_context_data(**kwargs)
200
201
202 def process_note_thank_events(request_user, note):
203     # Give points to the person who uploaded this note
204     if note.user != request_user and note.user:
205         NoteKarmaEvent.create_event(note.user, note, NoteKarmaEvent.THANKS)
206
207
208 def thank_note(request, pk):
209     """Record that somebody has thanked a note."""
210     return ajax_increment(Note, request, pk, THANKS_FIELD, USER_PROFILE_THANKS_FIELD, process_note_thank_events)
211
212
213 def process_note_flag_events(request_user, note):
214     # Take a point away from person flagging this note
215     if request_user.is_authenticated():
216         NoteKarmaEvent.create_event(request_user, note, NoteKarmaEvent.GIVE_FLAG)
217     # If this is the 6th time this note has been flagged,
218     # punish the uploader
219     if note.flags == 6 and note.user:
220         NoteKarmaEvent.create_event(note.user, note, NoteKarmaEvent.GET_FLAGGED)
221
222
223 def flag_note(request, pk):
224     """Record that somebody has flagged a note."""
225     return ajax_increment(Note, request, pk, FLAG_FIELD, USER_PROFILE_FLAGS_FIELD, process_note_flag_events)
226
227
228 def process_downloaded_note(request_user, note):
229     """Record that somebody has downloaded a note"""
230     if request_user.is_authenticated() and request_user != note.user:
231         NoteKarmaEvent.create_event(request_user, note, NoteKarmaEvent.DOWNLOADED_NOTE)
232     if request_user.is_authenticated() and note.user:
233         NoteKarmaEvent.create_event(note.user, note, NoteKarmaEvent.HAD_NOTE_DOWNLOADED)
234
235
236 def downloaded_note(request, pk):
237     """Record that somebody has flagged a note."""
238     return ajax_pk_base(Note, request, pk, process_downloaded_note)
239
240
241 def edit_note_tags(request, pk):
242     """
243     Saves the posted string of tags
244     """
245     if request.method == "POST" and request.is_ajax() and request.user.is_authenticated() and request.user.get_profile().can_edit_items():
246         note = Note.objects.get(pk=pk)
247         note.tags.set(request.body)
248
249         note_json = serializers.serialize('json', [note,])
250         resp = json.loads(note_json)[0]
251         resp['fields']['tags'] = list(note.tags.names())
252
253         return HttpResponse(json.dumps(resp), mimetype="application/json")
254     else:
255         return HttpResponseBadRequest(json.dumps({'status': 'fail', 'message': 'Invalid request'}),
256                                       mimetype="application/json")
257