Export results to csv
[edumed.git] / wtem / admin.py
1 # -*- coding: utf-8 -*-
2
3 import os
4
5 from django.contrib import admin
6 from django import forms
7 from django.utils import simplejson
8 from django.utils.safestring import mark_safe
9 from django.core.urlresolvers import reverse
10 from django.conf.urls import url, patterns
11 from django.shortcuts import render
12 from django.contrib.auth.models import User
13 from .models import Submission, Assignment, Attachment, exercises
14 from .middleware import get_current_request
15
16
17 def get_user_exercises(user):
18     try:
19         assignment = Assignment.objects.get(user = user)
20         return [e for e in exercises if e['id'] in assignment.exercises]
21     except Assignment.DoesNotExist:
22         return []
23
24
25 readonly_fields = ('submitted_by', 'first_name', 'last_name', 'email', 'key', 'key_sent')
26
27 class AttachmentWidget(forms.Widget):
28     def render(self, name, value, *args, **kwargs):
29         if value:
30             a_tag = '<a href="%s">%s</a>' % (value, value)
31         else:
32             a_tag = 'brak'
33         return mark_safe(('<input type="hidden" name="%s" value="%s"/>' + a_tag) % (name, value))
34
35 class SubmissionFormBase(forms.ModelForm):
36     class Meta:
37         model = Submission
38         exclude = ('answers', 'marks', 'contact') + readonly_fields
39
40
41 def get_open_answer(answers, exercise):
42     def get_option(options, id):
43         for option in options:
44             if option['id'] == int(id):
45                 return option
46
47     exercise_id = str(exercise['id'])
48     answer = answers[exercise_id]
49     if exercise['type'] == 'open':
50         if isinstance(answer, list):
51             toret = ''
52             for part in answer:
53                 field = get_option(exercise['fields'], part['id'])
54                 toret += '- %s:\n\n%s\n\n' % (field['caption'], part['text'])
55         else:
56             toret = answer
57     if exercise['type'] == 'edumed_wybor':
58         ok = set(map(str, exercise['answer'])) == set(map(str,answer['closed_part']))
59         toret = u'Czesc testowa [%s]:\n' % ('poprawna' if ok else 'niepoprawna')
60         for selected in answer['closed_part']:
61             option = get_option(exercise['options'], selected)
62             toret += '%s: %s\n' % (selected, option['text'])
63         else:
64             toret += u'<nie wybrano odpowiedzi>\n'
65         toret += u'\nCzesc otwarta (%s):\n\n' % ' '.join(exercise['open_part'])
66         toret += answer['open_part']
67
68     return toret
69
70
71 def get_form(request, submission):
72     fields = dict()
73     if submission.answers:
74         answers = simplejson.loads(submission.answers)
75         user_exercises = get_user_exercises(request.user)
76         for exercise in exercises:
77             if exercise not in user_exercises:
78                 continue
79             
80             answer_field_name = 'exercise_%s' % exercise['id']
81             mark_field_name = 'markof_%s_by_%s' % (exercise['id'], request.user.id)
82             if exercise['type'] in ('open', 'file_upload') or exercise.get('open_part', None):
83                 if exercise['type'] == 'file_upload':
84                     try:
85                         attachment = Attachment.objects.get(submission = submission, exercise_id = exercise['id'])
86                     except Attachment.DoesNotExist:
87                         attachment = None
88                     widget = AttachmentWidget
89                     initial = attachment.file.url if attachment else None
90                 else:
91                     widget = forms.Textarea(attrs={'readonly':True})
92                     initial = get_open_answer(answers, exercise)
93
94                 fields[answer_field_name] = forms.CharField(
95                         widget = widget,
96                         initial = initial,
97                         label = 'Rozwiązanie zadania %s' % exercise['id']
98                 )
99
100                 fields[mark_field_name] = forms.ChoiceField(
101                     choices = [(None, '-')] + [(i,i) for i in range(exercise['max_points']+1)],
102                     initial = submission.get_mark(user_id = request.user.id, exercise_id = exercise['id']),
103                     label = u'Twoja ocena zadania %s' % exercise['id']
104                 )
105
106     if not request.user.is_superuser:
107         class Meta(SubmissionFormBase.Meta):
108             pass
109         Meta.exclude += ('examiners',)
110         fields['Meta'] = Meta
111
112     return type('SubmissionForm', (SubmissionFormBase,), fields)
113
114
115 class SubmissionAdmin(admin.ModelAdmin):
116     list_display = ('__unicode__', 'todo', 'examiners_repr')
117     readonly_fields = readonly_fields
118
119     def get_form(self, request, obj, **kwargs):
120         return get_form(request, obj)
121     
122     def submitted_by(self, instance):
123         if instance.contact:
124             return '<a href="%s">%s</a>' % (
125                 reverse('admin:contact_contact_change', args = [instance.contact.id]),
126                 instance.contact.contact
127             )
128         return '-'
129     submitted_by.allow_tags = True
130     submitted_by.short_description = "Zgłoszony/a przez"
131
132     def todo(self, submission):
133         user = get_current_request().user
134         user_exercises = get_user_exercises(user)
135         user_marks = submission.marks.get(str(user.id), {})
136         return ','.join([str(e['id']) for e in user_exercises if str(e['id']) not in user_marks.keys()])
137     todo.short_description = 'Twoje nieocenione zadania'
138
139     def examiners_repr(self, submission):
140         return ', '.join([u.username for u in submission.examiners.all()])
141     examiners_repr.short_description = 'Przypisani do zgłoszenia'
142
143     def save_model(self, request, submission, form, change):
144         for name, value in form.cleaned_data.items():
145             if name.startswith('markof_'):
146                 parts = name.split('_')
147                 exercise_id = parts[1]
148                 user_id = parts[3]
149                 submission.set_mark(user_id = user_id, exercise_id = exercise_id, mark = value)
150         submission.save()
151
152     def changelist_view(self, request, extra_context=None):
153         context = dict(examiners = [])
154         assignments = Assignment.objects.all()
155         if not request.user.is_superuser:
156             assignments = assignments.filter(user = request.user)
157         for assignment in assignments:
158             examiner = dict(name = assignment.user.username, todo = 0)
159             for submission in Submission.objects.filter(examiners = assignment.user):
160                 for exercise_id in assignment.exercises:
161                     if submission.get_mark(user_id = assignment.user.id, exercise_id = exercise_id) is None:
162                         examiner['todo'] += 1
163             context['examiners'].append(examiner)
164         return super(SubmissionAdmin, self).changelist_view(request, extra_context = context)
165
166     def queryset(self, request):
167         qs = super(SubmissionAdmin, self).queryset(request)
168         if not request.user.is_superuser:
169             qs = qs.filter(examiners = request.user)
170         return qs
171
172     def get_urls(self):
173         urls = super(SubmissionAdmin, self).get_urls()
174         return patterns('',
175             url(r'^report/$', self.admin_site.admin_view(report_view), name='wtem_admin_report')
176         ) + super(SubmissionAdmin, self).get_urls()
177
178
179 class SubmissionsSet:
180     def __init__(self, submissions):
181         self.submissions = submissions
182         self.examiners_by_exercise = dict()
183         for submission in submissions:
184             for user_id, marks in submission.marks.items():
185                 user = User.objects.get(pk=user_id)
186                 for exercise_id in marks.keys():
187                     examiners = self.examiners_by_exercise.setdefault(exercise_id, [])
188                     if not user in examiners:
189                         examiners.append(user)
190
191 def report_view(request):
192     submissions = Submission.objects.all()
193     submissions = sorted(submissions, key = lambda s: -s.final_result)
194     return render(request, 'wtem/admin_report.csv', dict(
195         submissionsSet = SubmissionsSet(submissions),
196         exercise_ids = map(str, range(1,len(exercises)+1))
197     ))
198
199 admin.site.register(Submission, SubmissionAdmin)
200 admin.site.register(Assignment)