views.py 6.79 KB
Newer Older
1
"""Views provided by the education package"""
2
import os
3
from datetime import datetime, date
Jan's avatar
Jan committed
4
5

from django.contrib.auth.decorators import login_required
6
from django.core.exceptions import PermissionDenied
7
from django.shortcuts import get_object_or_404, render
8
from django.utils import timezone
Jan's avatar
Jan committed
9
10
11
from django.utils.translation import ugettext_lazy as _
from sendfile import sendfile

12
from members.decorators import membership_required
Jan's avatar
Jan committed
13
14
15
16
17
from .forms import AddExamForm, AddSummaryForm
from .models import Category, Course, Exam, Summary


def courses(request):
18
19
    """
    Renders an overview of the courses
20

21
22
23
    :param request: the request object
    :return: HttpResponse 200 containing the HTML as body
    """
Jan's avatar
Jan committed
24
    categories = Category.objects.all()
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
    courses = [
        {
            'course_code': x.course_code,
            'name': x.name,
            'categories': x.categories.all(),
            'document_count': sum([x.summary_set.filter(accepted=True).count(),
                                   x.exam_set.filter(accepted=True).count()] +
                                  [c.summary_set.filter(accepted=True).count()
                                   + c.exam_set.filter(accepted=True).count()
                                   for c in
                                   x.old_courses.all()]),
            'url': x.get_absolute_url()
        } for x in
        Course.objects.order_by('name_' + request.LANGUAGE_CODE).filter(
            until=None)
    ]

Jan's avatar
Jan committed
42
    return render(request, 'education/courses.html',
43
                  {'courses': courses, 'categories': categories})
Jan's avatar
Jan committed
44
45
46


def course(request, id):
47
48
    """
    Renders the detail page of one specific course
49

50
51
52
53
    :param request: the request object
    :param id: the primary key of the selected course
    :return: HttpResponse 200 containing the HTML as body
    """
Jan's avatar
Jan committed
54
55
56
    obj = get_object_or_404(Course, pk=id)
    courses = list(obj.old_courses.all())
    courses.append(obj)
57
    items = {}
Jan's avatar
Jan committed
58
    for course in courses:
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
        for summary in course.summary_set.filter(accepted=True):
            if summary.year not in items:
                items[summary.year] = {'summaries': [], 'exams': [],
                                       'legacy': course if course.pk != obj.pk
                                       else None}
            items[summary.year]['summaries'].append({
                "year": summary.year,
                "name": "{} {}".format(_("Summary"), summary.name),
                "id": summary.id
            })
        for exam in course.exam_set.filter(accepted=True):
            if exam.year not in items:
                items[exam.year] = {'summaries': [], 'exams': [],
                                    'legacy': course if course.pk != obj.pk
                                    else None}
            items[exam.year]['exams'].append({
                "type": "exam",
                "year": exam.year, "name":
                    "{} {}".format(dict(Exam.EXAM_TYPES)[exam.type],
                                   exam.name),
                "id": exam.id
            })
Jan's avatar
Jan committed
81
82

    return render(request, 'education/course.html',
83
84
                  {'course': obj, 'items': sorted(items.items(),
                                                  key=lambda x: x[0])})
Jan's avatar
Jan committed
85
86
87


@login_required
88
@membership_required
Jan's avatar
Jan committed
89
def exam(request, id):
90
91
    """
    Fetches and outputs the specified exam
92

93
94
95
96
    :param request: the request object
    :param id: the id of the exam
    :return: 302 if not authenticated else 200 with the file as body
    """
Jan's avatar
Jan committed
97
    exam = get_object_or_404(Exam, id=int(id))
98
99
100
101

    exam.download_count += 1
    exam.save()

Jan's avatar
Jan committed
102
103
104
105
106
107
108
    ext = os.path.splitext(exam.file.path)[1]
    filename = '{}-exam{}{}'.format(exam.course.name, exam.year, ext)
    return sendfile(request, exam.file.path,
                    attachment=True, attachment_filename=filename)


@login_required
109
@membership_required
Jan's avatar
Jan committed
110
def summary(request, id):
111
112
    """
    Fetches and outputs the specified summary
113

114
115
116
117
    :param request: the request object
    :param id: the id of the summary
    :return: 302 if not authenticated else 200 with the file as body
    """
Jan's avatar
Jan committed
118
    obj = get_object_or_404(Summary, id=int(id))
119
120
121
122

    obj.download_count += 1
    obj.save()

Jan's avatar
Jan committed
123
124
125
126
127
128
129
130
    ext = os.path.splitext(obj.file.path)[1]
    filename = '{}-summary{}{}'.format(obj.course.name, obj.year, ext)
    return sendfile(request, obj.file.path,
                    attachment=True, attachment_filename=filename)


@login_required
def submit_exam(request, id=None):
131
132
    """
    Renders the form to submit a new exam
133

134
135
136
137
    :param request: the request object
    :param id: the course id (optional)
    :return: 302 if not authenticated else 200 with the form HTML as body
    """
Jan's avatar
Jan committed
138
139
140
141
142
143
144
    saved = False

    if request.POST:
        form = AddExamForm(request.POST, request.FILES)
        if form.is_valid():
            saved = True
            obj = form.save(commit=False)
145
            obj.uploader = request.member
Jan's avatar
Jan committed
146
147
148
149
150
151
            obj.uploader_date = datetime.now()
            obj.save()

            form = AddExamForm()
    else:
        obj = Exam()
152
        obj.exam_date = date.today()
Jan's avatar
Jan committed
153
154
155
156
157
158
159
160
161
162
        if id is not None:
            obj.course = Course.objects.get(id=id)
        form = AddExamForm(instance=obj)

    return render(request, 'education/add_exam.html',
                  {'form': form, 'saved': saved})


@login_required
def submit_summary(request, id=None):
163
164
    """
    Renders the form to submit a new summary
165

166
167
168
169
    :param request: the request object
    :param id: the course id (optional)
    :return: 302 if not authenticated else 200 with the form HTML as body
    """
Jan's avatar
Jan committed
170
171
172
    saved = False

    if request.POST:
173
        form = AddSummaryForm(request.POST, request.FILES)
Jan's avatar
Jan committed
174
175
176
        if form.is_valid():
            saved = True
            obj = form.save(commit=False)
177
            obj.uploader = request.member
Jan's avatar
Jan committed
178
            obj.uploader_date = datetime.now()
179
            obj.save()
Jan's avatar
Jan committed
180
181

            obj = Summary()
182
            obj.author = request.member.get_full_name()
Jan's avatar
Jan committed
183
184
185
186
187
            form = AddSummaryForm(instance=obj)
    else:
        obj = Summary()
        if id is not None:
            obj.course = Course.objects.get(id=id)
188
        obj.author = request.member.get_full_name()
Jan's avatar
Jan committed
189
190
191
192
193
194
195
196
        form = AddSummaryForm(instance=obj)

    return render(request, 'education/add_summary.html',
                  {'form': form, 'saved': saved})


@login_required
def books(request):
197
198
199
    """
    Renders a page with information about book sale
    Only available to members and to-be members
200

201
202
203
    :param request: the request object
    :return: 403 if no active membership else 200 with the page HTML as body
    """
204
    if (request.member and request.member.is_authenticated and
205
206
207
208
        (request.member.current_membership or
         (request.member.earliest_membership and
          request.member.earliest_membership.since > timezone.now().date())
         )):
209
        return render(request, 'education/books.html')
210
    raise PermissionDenied