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

1079 by William Grant
Merge setup-refactor branch. This completely breaks existing installations;
1
#!/usr/bin/env python
2
# IVLE - Informatics Virtual Learning Environment
3
# Copyright (C) 2007-2008 The University of Melbourne
4
#
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.
9
#
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.
14
#
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
18
19
# Program: Marks
20
# Author:  Matt Giuca
21
# Date:    17/4/2008
22
23
# Script to calculate the marks for all students for a particular subject.
24
# Requires root to run.
25
26
import sys
27
import os
28
import re
29
import csv
30
import time
31
from xml.dom import minidom
32
33
import ivle.db
1080.1.60 by Matt Giuca
ivle.worksheet: Added calculate_score. This is a nice clean Storm port of
34
import ivle.database
35
import ivle.worksheet
1079 by William Grant
Merge setup-refactor branch. This completely breaks existing installations;
36
import ivle.conf
37
38
if os.getuid() != 0:
39
    print >>sys.stderr, "Must run %s as root." % os.path.basename(sys.argv[0])
40
    sys.exit()
41
42
if len(sys.argv) <= 1:
43
    print >>sys.stderr, "Usage: %s subject" % os.path.basename(sys.argv[0])
44
    sys.exit()
45
46
# Regex for valid identifiers (subject/worksheet names)
47
re_ident = re.compile("[0-9A-Za-z_]+")
48
49
# This code copy/edited from www/apps/tutorial/__init__.py
50
def is_valid_subjname(subject):
51
    m = re_ident.match(subject)
52
    return m is not None and m.end() == len(subject)
53
54
subject = sys.argv[1]
55
56
# Subject names must be valid identifiers
57
if not is_valid_subjname(subject):
58
    print >>sys.stderr, "Invalid subject name: %s." % repr(subject)
59
    sys.exit()
60
61
def get_userdata(user):
62
    """
63
    Given a User object, returns a list of strings for the user data which
64
    will be part of the output for this user.
65
    (This is not marks, it's other user data).
66
    """
67
    last_login = (None if user.last_login is None else
68
                    time.strftime("%d/%m/%y", user.last_login))
69
    return [user.studentid, user.login, user.fullname, last_login]
70
userdata_header = ["Student ID", "Login", "Full name", "Last login"]
71
72
def get_assessable_worksheets(subject):
73
    """
74
    Given a subject name, returns a list of strings - the worksheet names (not
75
    primary key IDs) for all assessable worksheets for that subject.
76
    May raise Exceptions, which are fatal.
77
    """
78
    # NOTE: This code is copy/edited from
79
    # www/apps/tutorial/__init__.py:handle_subject_menu
80
    # Should be factored out of there.
81
82
    # Parse the subject description file
83
    # The subject directory must have a file "subject.xml" in it,
84
    # or it does not exist (raise exception).
85
    try:
86
        subjectfile = open(os.path.join(ivle.conf.subjects_base, subject,
87
            "subject.xml"))
88
    except:
89
        raise Exception("Subject %s not found." % repr(subject))
90
91
    assessable_worksheets = []
92
    # Read in data about the subject
93
    subjectdom = minidom.parse(subjectfile)
94
    subjectfile.close()
95
    # TEMP: All of this is for a temporary XML format, which will later
96
    # change.
97
    worksheetsdom = subjectdom.documentElement
98
    worksheets = []     # List of string IDs
99
    for worksheetdom in worksheetsdom.childNodes:
100
        if worksheetdom.nodeType == worksheetdom.ELEMENT_NODE:
101
            # (Note: assessable will default to False, unless it is explicitly
102
            # set to "true").
103
            if worksheetdom.getAttribute("assessable") == "true":
104
                assessable_worksheets.append(worksheetdom.getAttribute("id"))
105
106
    return assessable_worksheets
107
108
def get_marks_header(worksheets):
109
    """
110
    Given a list of strings - the assessable worksheets - returns a new list
111
    of strings - the column headings for the marks section of the CSV output.
112
    """
113
    return worksheets + ["Total %", "Mark"]
114
1080.1.60 by Matt Giuca
ivle.worksheet: Added calculate_score. This is a nice clean Storm port of
115
def get_marks_user(subject, worksheet_names, user):
1079 by William Grant
Merge setup-refactor branch. This completely breaks existing installations;
116
    """
117
    Given a subject, a list of strings (the assessable worksheets), and a user
118
    object, returns the user's percentage for each worksheet, overall, and
119
    their final mark, as a list of strings, in a manner which corresponds to
120
    the headings produced by get_marks_header.
121
    """
122
    # NOTE: This code is copy/edited from
123
    # www/apps/tutorial/__init__.py:handle_subject_menu
124
    # Should be factored out of there.
125
126
    worksheet_pcts = []
127
    # As we go, calculate the total score for this subject
128
    # (Assessable worksheets only, mandatory problems only)
129
    problems_done = 0
130
    problems_total = 0
131
1080.1.60 by Matt Giuca
ivle.worksheet: Added calculate_score. This is a nice clean Storm port of
132
    for worksheet_name in worksheet_names:
133
        worksheet = ivle.database.Worksheet.get_by_name(store,
134
            subject, worksheet_name)
135
        # We simply ignore optional exercises here
136
        mand_done, mand_total, _, _ = (
137
            ivle.worksheet.calculate_score(store, user, worksheet))
138
        worksheet_pcts.append(float(mand_done) / mand_total)
139
        problems_done += mand_done
140
        problems_total += mand_total
1079 by William Grant
Merge setup-refactor branch. This completely breaks existing installations;
141
    problems_pct = float(problems_done) / problems_total
142
    problems_pct_int = (100 * problems_done) / problems_total
143
    # XXX Marks calculation (should be abstracted out of here!)
144
    # percent / 16, rounded down, with a maximum mark of 5
145
    max_mark = 5
146
    mark = min(problems_pct_int / 16, max_mark)
147
    return worksheet_pcts + [problems_pct, mark]
148
149
def writeuser(subject, worksheets, user, csvfile):
150
    userdata = get_userdata(user)
151
    marksdata = get_marks_user(subject, worksheets, user)
152
    csvfile.writerow(userdata + marksdata)
153
154
try:
155
    # Get the list of assessable worksheets from the subject.xml file,
156
    # and the list of all users from the DB.
157
    worksheets = get_assessable_worksheets(subject)
158
    db = ivle.db.DB()
1080.1.60 by Matt Giuca
ivle.worksheet: Added calculate_score. This is a nice clean Storm port of
159
    store = ivle.database.get_store()
1079 by William Grant
Merge setup-refactor branch. This completely breaks existing installations;
160
    list = db.get_users()
161
except Exception, message:
162
    print >>sys.stderr, "Error: " + str(message)
163
    sys.exit(1)
164
165
# Start writing the CSV file - header
166
csvfile = csv.writer(sys.stdout)
167
csvfile.writerow(userdata_header + get_marks_header(worksheets))
168
169
list.sort(key=lambda user: user.login)
170
for user in list:
171
    writeuser(subject, worksheets, user, csvfile)
172