~azzar1/unity/add-show-desktop-key

« back to all changes in this revision

Viewing changes to ivle/webapp/tutorial/marks.py

Add an XHTMLUnauthorizedView which redirects unauthenticated users to the
login page if a page raises an Unauthorized. Alter UserSettingsView to raise
one in the right cases, for testing.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# IVLE
2
 
# Copyright (C) 2007-2010 The University of Melbourne
3
 
#
4
 
# This program is free software; you can redistribute it and/or modify
5
 
# it under the terms of the GNU General Public License as published by
6
 
# the Free Software Foundation; either version 2 of the License, or
7
 
# (at your option) any later version.
8
 
#
9
 
# This program is distributed in the hope that it will be useful,
10
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
 
# GNU General Public License for more details.
13
 
#
14
 
# You should have received a copy of the GNU General Public License
15
 
# along with this program; if not, write to the Free Software
16
 
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17
 
 
18
 
# Author: Matt Giuca
19
 
 
20
 
"""Worksheet marks reporting functionality.
21
 
 
22
 
Displays students' worksheet marks to users with sufficient privileges.
23
 
"""
24
 
 
25
 
import datetime
26
 
import csv
27
 
import urllib
28
 
 
29
 
import ivle.database
30
 
import ivle.worksheet.utils
31
 
from ivle.webapp.base.views import BaseView
32
 
from ivle.webapp.base.xhtml import XHTMLView
33
 
from ivle.webapp.media import media_url
34
 
 
35
 
class WorksheetsMarksView(XHTMLView):
36
 
    """View for presenting all students' individual marks for worksheets."""
37
 
    permission = 'view_worksheet_marks'
38
 
    template = 'templates/worksheets_marks.html'
39
 
    tab = 'subjects'
40
 
 
41
 
    def populate(self, req, ctx):
42
 
        error = None
43
 
        offering = self.context
44
 
        ctx['req'] = req
45
 
        ctx['context'] = offering
46
 
        ctx['urllib'] = urllib
47
 
        ctx['WorksheetsMarksCSVView'] = WorksheetsMarksCSVView
48
 
 
49
 
        # User may supply a "cutoff date" to calculate marks as of that date
50
 
        # Default to current time
51
 
        cutoff = offering.worksheet_cutoff or datetime.datetime.now()
52
 
        data = dict(req.get_fieldstorage())
53
 
        if data.get('cutoff') is not None:
54
 
            try:
55
 
                cutoff = datetime.datetime.strptime(data.get('cutoff'),
56
 
                                                    "%Y-%m-%d %H:%M:%S")
57
 
            except ValueError:
58
 
                error = (
59
 
                    "Invalid date format: '%s' (must be YYYY-MM-DD H:M:S)."
60
 
                        % data.get('cutoff'))
61
 
        ctx['cutoff'] = cutoff
62
 
        ctx['error'] = error
63
 
 
64
 
        # "worksheets" is a list of (assessable, published) worksheet names
65
 
        worksheets = offering.worksheets.find(assessable=True, published=True)
66
 
        ctx['worksheets'] = [ws.name for ws in worksheets]
67
 
 
68
 
        # "students" is a list of tuples:
69
 
        # (user, worksheet_pcts, total_pct, mark)
70
 
        # user is a User object, worksheet_pcts is a list of floats (one per
71
 
        # worksheet), total_pct is a float, mark is an int
72
 
        ctx['students'] = students = []
73
 
        # Get all users enrolled in this offering
74
 
        users = req.store.find(ivle.database.User,
75
 
                       ivle.database.User.id == ivle.database.Enrolment.user_id,
76
 
                       offering.id == ivle.database.Enrolment.offering).order_by(
77
 
                            ivle.database.User.login)
78
 
        for user in users:
79
 
            worksheet_pcts, total_pct, mark = get_marks_user(req, worksheets,
80
 
                                                user, as_of=cutoff)
81
 
            students.append((user, worksheet_pcts, total_pct, mark))
82
 
 
83
 
class WorksheetsMarksCSVView(BaseView):
84
 
    """View for presenting all students' individual marks for worksheets."""
85
 
    permission = 'view_worksheet_marks'
86
 
    template = 'templates/worksheets_marks.html'
87
 
    tab = 'subjects'
88
 
 
89
 
    def render(self, req):
90
 
        offering = self.context
91
 
 
92
 
        # User may supply a "cutoff date" to calculate marks as of that date
93
 
        # Default to current time
94
 
        cutoff = offering.worksheet_cutoff or datetime.datetime.now()
95
 
        data = dict(req.get_fieldstorage())
96
 
        if data.get('cutoff') is not None:
97
 
            try:
98
 
                cutoff = datetime.datetime.strptime(data.get('cutoff'),
99
 
                                                    "%Y-%m-%d %H:%M:%S")
100
 
            except ValueError:
101
 
                req.write(
102
 
                    "Invalid date format: '%s' (must be YYYY-MM-DD H:M:S)."
103
 
                        % data.get('cutoff'))
104
 
                return
105
 
 
106
 
        req.content_type = "text/csv"
107
 
        req.headers_out.add('Content-Disposition',
108
 
            "attachment; filename=marks-%s-%ss%s.csv" %
109
 
            (offering.subject.short_name, offering.semester.year,
110
 
             offering.semester.semester))
111
 
 
112
 
        # "worksheets" is a list of (assessable, published) worksheet names
113
 
        worksheets = offering.worksheets.find(assessable=True, published=True)
114
 
 
115
 
        # Start writing the CSV file - header
116
 
        csvfile = csv.writer(req)
117
 
        csvfile.writerow(csv_get_header(worksheets))
118
 
 
119
 
        # Get all users enrolled in this offering
120
 
        users = req.store.find(ivle.database.User,
121
 
                   ivle.database.User.id == ivle.database.Enrolment.user_id,
122
 
                   offering.id == ivle.database.Enrolment.offering).order_by(
123
 
                        ivle.database.User.login)
124
 
        for user in users:
125
 
            csv_writeuser(req, worksheets, user, csvfile, cutoff)
126
 
 
127
 
def get_marks_user(req, worksheets, user, as_of=None):
128
 
    """Gets marks for a particular user for a particular set of worksheets.
129
 
    @param worksheets: List of Worksheet objects to get marks for.
130
 
    @param user: User to get marks for.
131
 
    @param as_of: Optional datetime. If supplied, gets the marks as of as_of.
132
 
    @returns: (worksheet_pcts, total_pct, mark)
133
 
    """
134
 
    worksheet_pcts = []
135
 
    # As we go, calculate the total score for this subject
136
 
    # (Assessable worksheets only, mandatory problems only)
137
 
    problems_done = 0
138
 
    problems_total = 0
139
 
 
140
 
    for worksheet in worksheets:
141
 
        # We simply ignore optional exercises here
142
 
        mand_done, mand_total, _, _ = (
143
 
            ivle.worksheet.utils.calculate_score(req.store, user, worksheet,
144
 
                                                 as_of))
145
 
        if mand_total > 0:
146
 
            worksheet_pcts.append(float(mand_done) / mand_total)
147
 
        else:
148
 
            # Avoid Div0, just give everyone 0 marks if there are none
149
 
            worksheet_pcts.append(0.0)
150
 
        problems_done += mand_done
151
 
        problems_total += mand_total
152
 
    percent, mark, _ = (
153
 
        ivle.worksheet.utils.calculate_mark(problems_done, problems_total))
154
 
    return (worksheet_pcts, float(percent)/100, mark)
155
 
 
156
 
def csv_get_userdata(user):
157
 
    """
158
 
    Given a User object, returns a list of strings for the user data which
159
 
    will be part of the output for this user.
160
 
    (This is not marks, it's other user data).
161
 
    """
162
 
    last_login = ("" if user.last_login is None else
163
 
                    user.last_login.strftime("%Y-%m-%d"))
164
 
    return [user.studentid or "", user.login, user.fullname, last_login]
165
 
 
166
 
csv_userdata_header = ["Student ID", "Login", "Full name", "Last login"]
167
 
def csv_get_header(worksheets):
168
 
    """
169
 
    Given a list of Worksheet objects (the assessable worksheets), returns a
170
 
    list of strings -- the column headings for the marks section of the CSV
171
 
    output.
172
 
    """
173
 
    return (csv_userdata_header + [ws.name for ws in worksheets]
174
 
            + ["Total %", "Mark"])
175
 
 
176
 
def csv_writeuser(req, worksheets, user, csvfile, cutoff=None):
177
 
    userdata = csv_get_userdata(user)
178
 
    worksheet_pcts, total_pct, mark = get_marks_user(req, worksheets, user,
179
 
                                                     cutoff)
180
 
    data = userdata + worksheet_pcts + [total_pct, mark]
181
 
    # CSV writer can't handle non-ASCII characters. Encode to UTF-8.
182
 
    data = [unicode(x).encode('utf-8') for x in data]
183
 
    csvfile.writerow(data)