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

« back to all changes in this revision

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

  • Committer: drtomc
  • Date: 2007-12-11 03:26:29 UTC
  • Revision ID: svn-v3-trunk0:2b9c9e99-6f39-0410-b283-7f802c844ae2:trunk:25
A bit more work on the userdb stuff.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# IVLE - Informatics Virtual Learning Environment
2
 
# Copyright (C) 2007-2008 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
 
# Module: TutorialService
19
 
# Author: Matt Giuca
20
 
# Date:   25/1/2008
21
 
 
22
 
# Provides the AJAX backend for the tutorial application.
23
 
# This allows several actions to be performed on the code the student has
24
 
# typed into one of the exercise boxes.
25
 
 
26
 
# Calling syntax
27
 
# Path must be empty.
28
 
# The arguments determine what is to be done on this file.
29
 
 
30
 
# "action". One of the tutorialservice actions.
31
 
# "exercise" - The path to a exercise file (including the .xml extension),
32
 
#              relative to the subjects base directory.
33
 
# action "save" or "test" (POST only):
34
 
#   "code" - Full text of the student's code being submitted.
35
 
# action "getattempts": No arguments. Returns a list of
36
 
#   {'date': 'formatted_date', 'complete': bool} dicts.
37
 
# action "getattempt":
38
 
#   "date" - Formatted date. Gets most recent attempt before (and including)
39
 
#   that date.
40
 
#   Returns JSON string containing code, or null.
41
 
 
42
 
# Returns a JSON response string indicating the results.
43
 
 
44
 
import os
45
 
import time
46
 
import datetime
47
 
 
48
 
import cjson
49
 
 
50
 
from ivle import util
51
 
from ivle import console
52
 
import ivle.database
53
 
import ivle.worksheet
54
 
import ivle.conf
55
 
import ivle.webapp.tutorial.test # XXX: Really .test, not real test.
56
 
 
57
 
from ivle.webapp.base.rest import JSONRESTView
58
 
import ivle.database
59
 
from ivle.webapp.base.rest import named_operation
60
 
 
61
 
# If True, getattempts or getattempt will allow browsing of inactive/disabled
62
 
# attempts. If False, will not allow this.
63
 
HISTORY_ALLOW_INACTIVE = False
64
 
 
65
 
TIMESTAMP_FORMAT = '%Y-%m-%d %H:%M:%S'
66
 
 
67
 
 
68
 
class AttemptsRESTView(JSONRESTView):
69
 
    '''
70
 
    Class to return a list of attempts for a given exercise, or add an Attempt
71
 
    '''
72
 
    def GET(self, req):
73
 
        """Handles a GET Attempts action."""
74
 
        exercise = ivle.database.Exercise.get_by_name(req.store, 
75
 
                                                        self.exercise)
76
 
        user = ivle.database.User.get_by_login(req.store, self.username)
77
 
 
78
 
        attempts = ivle.worksheet.get_exercise_attempts(req.store, user,
79
 
                            exercise, allow_inactive=HISTORY_ALLOW_INACTIVE)
80
 
        # attempts is a list of ExerciseAttempt objects. Convert to dictionaries
81
 
        time_fmt = lambda dt: datetime.datetime.strftime(dt, TIMESTAMP_FORMAT)
82
 
        attempts = [{'date': time_fmt(a.date), 'complete': a.complete}
83
 
                for a in attempts]
84
 
                
85
 
        return attempts
86
 
        
87
 
    def PUT(self, req, data):
88
 
        ''' Tests the given submission '''
89
 
        exercisefile = util.open_exercise_file(self.exercise)
90
 
        if exercisefile is None:
91
 
            req.throw_error(req.HTTP_NOT_FOUND,
92
 
                "The exercise was not found.")
93
 
 
94
 
        # Start a console to run the tests on
95
 
        jail_path = os.path.join(ivle.conf.jail_base, req.user.login)
96
 
        working_dir = os.path.join("/home", req.user.login)
97
 
        cons = console.Console(req.user.unixid, jail_path, working_dir)
98
 
 
99
 
        # Parse the file into a exercise object using the test suite
100
 
        exercise_obj = ivle.webapp.tutorial.test.parse_exercise_file(
101
 
                                                            exercisefile, cons)
102
 
        exercisefile.close()
103
 
 
104
 
        # Run the test cases. Get the result back as a JSONable object.
105
 
        # Return it.
106
 
        test_results = exercise_obj.run_tests(data['code'])
107
 
 
108
 
        # Close the console
109
 
        cons.close()
110
 
 
111
 
        # Get the Exercise from the database
112
 
        exercise = ivle.database.Exercise.get_by_name(req.store, self.exercise)
113
 
 
114
 
        attempt = ivle.database.ExerciseAttempt(user=req.user,
115
 
                                                exercise=exercise,
116
 
                                                date=datetime.datetime.now(),
117
 
                                                complete=test_results['passed'],
118
 
                                                # XXX
119
 
                                                text=unicode(data['code']))
120
 
 
121
 
        req.store.add(attempt)
122
 
        req.store.commit()
123
 
        # Query the DB to get an updated score on whether or not this problem
124
 
        # has EVER been completed (may be different from "passed", if it has
125
 
        # been completed before), and the total number of attempts.
126
 
        completed, attempts = ivle.worksheet.get_exercise_status(req.store,
127
 
            req.user, exercise)
128
 
        test_results["completed"] = completed
129
 
        test_results["attempts"] = attempts
130
 
 
131
 
        return test_results
132
 
        
133
 
 
134
 
class AttemptRESTView(JSONRESTView):
135
 
    '''
136
 
    View used to extract the data of a specified attempt
137
 
    '''
138
 
    
139
 
    def GET(self, req):
140
 
        # Get an actual date object, rather than a string
141
 
        date = datetime.datetime.strptime(self.date, TIMESTAMP_FORMAT)
142
 
        
143
 
        exercise = ivle.database.Exercise.get_by_name(req.store, self.exercise)
144
 
        attempt = ivle.worksheet.get_exercise_attempt(req.store, req.user,
145
 
            exercise, as_of=date, allow_inactive=HISTORY_ALLOW_INACTIVE)
146
 
        if attempt is not None:
147
 
            attempt = attempt.text
148
 
        # attempt may be None; will write "null"
149
 
        return {'code': attempt}
150
 
        
151
 
class ExerciseRESTView(JSONRESTView):
152
 
    '''
153
 
    Handles a save action. This saves the user's code without executing it.
154
 
    '''
155
 
    @named_operation
156
 
    def save(self, req, text):
157
 
        # Need to open JUST so we know this is a real exercise.
158
 
        # (This avoids users submitting code for bogus exercises).
159
 
        exercisefile = util.open_exercise_file(self.exercise)
160
 
        if exercisefile is None:
161
 
            req.throw_error(req.HTTP_NOT_FOUND,
162
 
                "The exercise was not found.")
163
 
        exercisefile.close()
164
 
 
165
 
        exercise = ivle.database.Exercise.get_by_name(req.store, self.exercise)
166
 
        ivle.worksheet.save_exercise(req.store, req.user, exercise,
167
 
                                     unicode(text), datetime.datetime.now())
168
 
        req.store.commit()
169
 
        return {"result": "ok"}