Reverting half-merged commits b6f336c6a13b2a41b2c29b35884277aea9daca50 and 3d4edeb156...
[oweals/karmaworld.git] / karmaworld / apps / courses / views.py
1 #!/usr/bin/env python
2 # -*- coding:utf8 -*-
3 # Copyright (C) 2012  FinalsClub Foundation
4 """ Views for the KarmaNotes Courses app """
5
6 import json
7
8 from django.core.exceptions import MultipleObjectsReturned
9 from django.core.exceptions import ObjectDoesNotExist
10
11 from django.http import HttpResponse, HttpResponseBadRequest, HttpResponseNotFound
12 from django.views.generic import DetailView
13 from django.views.generic import TemplateView
14 from django.views.generic.edit import ProcessFormView
15 from django.views.generic.edit import ModelFormMixin
16 from django.views.generic.list import ListView
17
18 from karmaworld.apps.courses.forms import CourseForm
19 from karmaworld.apps.courses.models import Course
20 from karmaworld.apps.courses.models import School
21 from karmaworld.apps.notes.models import Note
22
23
24 class CourseListView(ListView, ModelFormMixin, ProcessFormView):
25     """ Simple ListView for the front page that includes the CourseForm """
26     model = Course
27     form_class = CourseForm
28     object = Course()
29
30     def get_context_data(self, **kwargs):
31         """ Add the CourseForm to ListView context """
32         # get the original context
33         context = super(CourseListView, self).get_context_data(**kwargs)
34         # get the total number of notes
35         context['note_count'] = Note.objects.count()
36         # get the course form for the form at the bottom of the homepage
37         context['course_form'] = kwargs.get('course_form', CourseForm())
38         if context['course_form'].errors:
39             # if there was an error in the form
40             context['jump_to_form'] = True
41
42         # Include "Add Course" button in header
43         context['display_add_course'] = True
44
45         return context
46
47     def get_success_url(self):
48         """ On form submission success, redirect to what url """
49         return u'/{school_slug}/{course_slug}'.format(
50                 school_slug=self.object.school.slug,
51                 course_slug=self.object.slug)
52
53     def form_invalid(self, form, **kwargs):
54         """ override form_invalid to populate object_list on redirect """
55         kwargs['is_error'] = True
56         kwargs['course_form'] = form
57         self.object_list = self.get_queryset()
58         kwargs['object_list'] = self.object_list
59         return self.render_to_response(self.get_context_data(**kwargs))
60
61
62
63 class CourseDetailView(DetailView):
64     """ Class-based view for the course html page """
65     model = Course
66     context_object_name = u"course" # name passed to template
67
68     def get_context_data(self, **kwargs):
69         """ filter the Course.note_set to return no Drafts """
70         kwargs = super(CourseDetailView, self).get_context_data()
71         kwargs['note_set'] = self.object.note_set.filter(is_hidden=False)
72
73         # Include "Add Note" button in header
74         kwargs['display_add_note'] = True
75
76         return kwargs
77
78
79 class AboutView(TemplateView):
80     """ Display the About page with the Schools leaderboard """
81     template_name = "about.html"
82
83     def get_context_data(self, **kwargs):
84         """ get the list of schools with the most files for leaderboard """
85         context = { 'params': kwargs,
86                     'schools': School.objects.filter(file_count__gt=0).order_by('-file_count')[:20] }
87         return context
88
89
90 def school_list(request):
91     """ Return JSON describing Schools that match q query on name """
92     if not (request.method == 'POST' and request.is_ajax()
93                         and request.POST.has_key('q')):
94         #return that the api call failed
95         return HttpResponseBadRequest(json.dumps({'status':'fail'}), mimetype="application/json")
96
97     # if an ajax get request with a 'q' name query
98     # get the schools as a id name dict,
99     _query = request.POST['q']
100     matching_school_aliases = list(School.objects.filter(alias__icontains=_query))
101     matching_school_names = list(School.objects.filter(name__icontains=_query)[:20])
102     _schools = matching_school_aliases[:2] + matching_school_names
103     schools = [{'id': s.id, 'name': s.name} for s in _schools]
104
105     # return as json
106     return HttpResponse(json.dumps({'status':'success', 'schools': schools}), mimetype="application/json")
107
108
109 def school_course_list(request):
110     """Return JSON describing courses we know of at the given school
111      that match the query """
112     if not (request.method == 'POST' and request.is_ajax()
113                         and request.POST.has_key('q')
114                         and request.POST.has_key('school_id')):
115         # return that the api call failed
116         return HttpResponseBadRequest(json.dumps({'status': 'fail', 'message': 'query parameters missing'}),
117                                     mimetype="application/json")
118
119     _query = request.POST['q']
120     try:
121       _school_id = int(request.POST['school_id'])
122     except:
123       return HttpResponseBadRequest(json.dumps({'status': 'fail',
124                                               'message': 'could not convert school id to integer'}),
125                                   mimetype="application/json")
126
127     # Look up the school
128     try:
129         school = School.objects.get(id__exact=_school_id)
130     except (MultipleObjectsReturned, ObjectDoesNotExist):
131         return HttpResponseBadRequest(json.dumps({'status': 'fail',
132                                                 'message': 'school id did not match exactly one school'}),
133                                     mimetype="application/json")
134
135     # Look up matching courses
136     _courses = Course.objects.filter(school__exact=school.id, name__icontains=_query)
137     courses = [{'name': c.name} for c in _courses]
138
139     # return as json
140     return HttpResponse(json.dumps({'status':'success', 'courses': courses}),
141                         mimetype="application/json")
142
143
144 def school_course_instructor_list(request):
145     """Return JSON describing instructors we know of at the given school
146        teaching the given course
147        that match the query """
148     if not(request.method == 'POST' and request.is_ajax()
149                         and request.POST.has_key('q')
150                         and request.POST.has_key('course_name')
151                         and request.POST.has_key('school_id')):
152         # return that the api call failed
153         return HttpResponseBadRequest(json.dumps({'status': 'fail', 'message': 'query parameters missing'}),
154                                     mimetype="application/json")
155
156     _query = request.POST['q']
157     _course_name = request.POST['course_name']
158     try:
159       _school_id = int(request.POST['school_id'])
160     except:
161       return HttpResponseBadRequest(json.dumps({'status': 'fail',
162                                               'message':'could not convert school id to integer'}),
163                                   mimetype="application/json")
164
165     # Look up the school
166     try:
167         school = School.objects.get(id__exact=_school_id)
168     except (MultipleObjectsReturned, ObjectDoesNotExist):
169         return HttpResponseBadRequest(json.dumps({'status': 'fail',
170                                                 'message': 'school id did not match exactly one school'}),
171                                     mimetype="application/json")
172
173     # Look up matching courses
174     _courses = Course.objects.filter(school__exact=school.id,
175                                      name__exact=_course_name,
176                                      instructor_name__icontains=_query)
177     instructors = [{'name': c.instructor_name, 'url': c.get_absolute_url()} for c in _courses]
178
179     # return as json
180     return HttpResponse(json.dumps({'status':'success', 'instructors': instructors}),
181                         mimetype="application/json")
182
183 def ajaxIncrementBase(request, pk, field):
184     """Increment a note's field by one."""
185     if not (request.method == 'POST' and request.is_ajax()):
186         # return that the api call failed
187         return HttpResponseBadRequest(json.dumps({'status': 'fail', 'message': 'must be a POST ajax request'}),
188                                     mimetype="application/json")
189
190     try:
191         note = Course.objects.get(pk=pk)
192         note.__dict__[field] += 1
193         note.save()
194     except ObjectDoesNotExist:
195         return HttpResponseNotFound(json.dumps({'status': 'fail', 'message': 'note id does not match a note'}),
196                                     mimetype="application/json")
197
198     return HttpResponse(status=204)
199
200 def flag_course(request, pk):
201     """Record that somebody has flagged a note."""
202     return ajaxIncrementBase(request, pk, 'flags')
203