2
# IVLE - Informatics Virtual Learning Environment
3
# Copyright (C) 2007-2009 The University of Melbourne
5
# This program is free software; you can redistribute it and/or modify
6
# it under the terms of the GNU General Public License as published by
7
# the Free Software Foundation; either version 2 of the License, or
8
# (at your option) any later version.
10
# This program is distributed in the hope that it will be useful,
11
# but WITHOUT ANY WARRANTY; without even the implied warranty of
12
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
# GNU General Public License for more details.
15
# You should have received a copy of the GNU General Public License
16
# along with this program; if not, write to the Free Software
17
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22
# Script to calculate the marks for all students for a particular subject.
23
# Requires root to run.
32
print >>sys.stderr, "Must run %s as root." % os.path.basename(sys.argv[0])
37
import ivle.worksheet.utils
39
def get_userdata(user):
41
Given a User object, returns a list of strings for the user data which
42
will be part of the output for this user.
43
(This is not marks, it's other user data).
45
last_login = (None if user.last_login is None else
46
user.last_login.strftime("%d/%m/%y"))
47
return [user.studentid, user.login, user.fullname, last_login]
49
userdata_header = ["Student ID", "Login", "Full name", "Last login"]
50
def get_header(worksheets):
52
Given a list of Worksheet objects (the assessable worksheets), returns a
53
list of strings -- the column headings for the marks section of the CSV
56
return (userdata_header + [ws.name for ws in worksheets]
57
+ ["Total %", "Mark"])
59
def get_marks_user(worksheets, user, as_of=None):
60
"""Gets marks for a particular user for a particular set of worksheets.
61
@param worksheets: List of Worksheet objects to get marks for.
62
@param user: User to get marks for.
63
@param as_of: Optional datetime. If supplied, gets the marks as of as_of.
64
@returns: The user's percentage for each worksheet, overall, and
65
their final mark, as a list of strings, in a manner which corresponds to
66
the headings produced by get_marks_header.
69
# As we go, calculate the total score for this subject
70
# (Assessable worksheets only, mandatory problems only)
74
for worksheet in worksheets:
75
# We simply ignore optional exercises here
76
mand_done, mand_total, _, _ = (
77
ivle.worksheet.utils.calculate_score(store, user, worksheet,
80
worksheet_pcts.append(float(mand_done) / mand_total)
82
# Avoid Div0, just give everyone 0 marks if there are none
83
worksheet_pcts.append(0.0)
84
problems_done += mand_done
85
problems_total += mand_total
87
ivle.worksheet.utils.calculate_mark(problems_done, problems_total))
88
return worksheet_pcts + [float(percent)/100, mark]
90
def writeuser(worksheets, user, csvfile, cutoff=None):
91
userdata = get_userdata(user)
92
marksdata = get_marks_user(worksheets, user, cutoff)
93
data = userdata + marksdata
94
# CSV writer can't handle non-ASCII characters. Encode to UTF-8.
95
data = [unicode(x).encode('utf-8') for x in data]
96
csvfile.writerow(data)
103
usage = """usage: %prog [options] subject
105
Reports each student's marks for a given subject offering."""
108
parser = optparse.OptionParser(usage)
109
parser.add_option("-s", "--semester",
110
action="store", dest="semester", metavar="YEAR/SEMESTER",
111
help="Semester of the subject's offering (eg. 2009/1). "
112
"Defaults to the currently active semester.",
114
parser.add_option("-c", "--cutoff",
115
action="store", dest="cutoff", metavar="DATE",
116
help="Cutoff date (calculate the marks as of this date). "
119
(options, args) = parser.parse_args(argv[1:])
125
subject_name = unicode(args[0])
127
if options.semester is None:
128
year, semester = None, None
131
year, semester = options.semester.split('/')
132
if len(year) == 0 or len(semester) == 0:
135
parser.error('Invalid semester (must have form "year/semester")')
137
if options.cutoff is not None:
139
cutoff = datetime.datetime.strptime(options.cutoff,
142
parser.error("Invalid date format: '%s' "
143
"(must be YYYY-MM-DD H:M:S)." % options.cutoff)
147
store = ivle.database.get_store(ivle.config.Config(plugins=False))
149
# Get the subject from the DB
150
subject = store.find(ivle.database.Subject,
151
ivle.database.Subject.short_name == subject_name).one()
153
print >>sys.stderr, "No subject with short name '%s'" % subject_name
156
# Get the offering from the DB
158
# None specified - get the current offering from the DB
159
offerings = list(subject.active_offerings())
160
if len(offerings) == 0:
161
print >>sys.stderr, ("No active offering for subject '%s'"
164
elif len(offerings) > 1:
165
print >>sys.stderr, ("Multiple active offerings for subject '%s':"
167
print >>sys.stderr, "Please use one of:"
168
for offering in offerings:
169
print >>sys.stderr, (" --semester=%s/%s"
170
% (offering.semester.year, offering.semester.semester))
173
offering = offerings[0]
175
# Get the offering for the specified semester
176
offering = subject.offering_for_semester(year, semester)
178
print >>sys.stderr, (
179
"No offering for subject '%s' in semester %s/%s"
180
% (subject_name, year, semester))
183
# Get the list of assessable worksheets
184
worksheets = offering.worksheets.find(assessable=True)
186
# Start writing the CSV file - header
187
csvfile = csv.writer(sys.stdout)
188
csvfile.writerow(get_header(worksheets))
190
# Get all users enrolled in this offering
191
users = store.find(ivle.database.User,
192
ivle.database.User.id == ivle.database.Enrolment.user_id,
193
offering.id == ivle.database.Enrolment.offering).order_by(
194
ivle.database.User.login)
196
writeuser(worksheets, user, csvfile, cutoff)
198
if __name__ == "__main__":
199
sys.exit(main(sys.argv))