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

« back to all changes in this revision

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

  • Committer: Matt Giuca
  • Date: 2009-12-08 05:05:20 UTC
  • Revision ID: matt.giuca@gmail.com-20091208050520-a4nmmjxwtmhip063
ivle-createdatadirs: Fixed exit -- if path already exists, log and exit(0).

Show diffs side-by-side

added added

removed removed

Lines of Context:
22
22
import os
23
23
import datetime
24
24
 
25
 
import ivle.util
 
25
import genshi
 
26
from storm.locals import Store
 
27
 
26
28
import ivle.console
27
29
import ivle.database
28
 
import ivle.worksheet
29
 
import ivle.conf
 
30
from ivle.database import Exercise, ExerciseAttempt, ExerciseSave, Worksheet, \
 
31
                          Offering, Subject, Semester, User, WorksheetExercise
 
32
import ivle.worksheet.utils
30
33
import ivle.webapp.tutorial.test
31
 
 
32
 
from ivle.webapp.base.rest import JSONRESTView, named_operation
 
34
from ivle.webapp.base.rest import (JSONRESTView, named_operation,
 
35
                                   require_permission)
33
36
from ivle.webapp.errors import NotFound
34
37
 
35
 
# If True, getattempts or getattempt will allow browsing of inactive/disabled
36
 
# attempts. If False, will not allow this.
37
 
HISTORY_ALLOW_INACTIVE = False
38
38
 
39
39
TIMESTAMP_FORMAT = '%Y-%m-%d %H:%M:%S'
40
40
 
41
 
 
42
41
class AttemptsRESTView(JSONRESTView):
43
42
    '''REST view of a user's attempts at an exercise.'''
44
 
    def __init__(self, req, subject, worksheet, exercise, username):
45
 
        # TODO: Find exercise within worksheet.
46
 
        self.user = ivle.database.User.get_by_login(req.store, username)
47
 
        if self.user is None:
48
 
            raise NotFound()
49
 
        self.exercise = exercise
50
43
 
 
44
    @require_permission('edit')
51
45
    def GET(self, req):
52
46
        """Handles a GET Attempts action."""
53
 
        exercise = ivle.database.Exercise.get_by_name(req.store, 
54
 
                                                        self.exercise)
55
 
 
56
 
        attempts = ivle.worksheet.get_exercise_attempts(req.store, self.user,
57
 
                            exercise, allow_inactive=HISTORY_ALLOW_INACTIVE)
 
47
        attempts = req.store.find(ExerciseAttempt, 
 
48
                ExerciseAttempt.ws_ex_id == self.context.worksheet_exercise.id,
 
49
                ExerciseAttempt.user_id == self.context.user.id)
58
50
        # attempts is a list of ExerciseAttempt objects. Convert to dictionaries
59
51
        time_fmt = lambda dt: datetime.datetime.strftime(dt, TIMESTAMP_FORMAT)
60
52
        attempts = [{'date': time_fmt(a.date), 'complete': a.complete}
63
55
        return attempts
64
56
 
65
57
 
 
58
    @require_permission('edit')
66
59
    def PUT(self, req, data):
67
 
        ''' Tests the given submission '''
68
 
        exercisefile = ivle.util.open_exercise_file(self.exercise)
69
 
        if exercisefile is None:
70
 
            raise NotFound()
71
 
 
 
60
        """ Tests the given submission """
72
61
        # Start a console to run the tests on
73
 
        jail_path = os.path.join(ivle.conf.jail_base, req.user.login)
 
62
        jail_path = os.path.join(req.config['paths']['jails']['mounts'],
 
63
                                 req.user.login)
74
64
        working_dir = os.path.join("/home", req.user.login)
75
 
        cons = ivle.console.Console(req.user.unixid, jail_path, working_dir)
 
65
        cons = ivle.console.Console(req.config, req.user.unixid, jail_path,
 
66
                                    working_dir)
76
67
 
77
68
        # Parse the file into a exercise object using the test suite
78
69
        exercise_obj = ivle.webapp.tutorial.test.parse_exercise_file(
79
 
                                                            exercisefile, cons)
80
 
        exercisefile.close()
 
70
                            self.context.worksheet_exercise.exercise, cons)
81
71
 
82
72
        # Run the test cases. Get the result back as a JSONable object.
83
73
        # Return it.
86
76
        # Close the console
87
77
        cons.close()
88
78
 
89
 
        # Get the Exercise from the database
90
 
        exercise = ivle.database.Exercise.get_by_name(req.store, self.exercise)
91
 
 
92
79
        attempt = ivle.database.ExerciseAttempt(user=req.user,
93
 
                                                exercise=exercise,
94
 
                                                date=datetime.datetime.now(),
95
 
                                                complete=test_results['passed'],
96
 
                                                # XXX
97
 
                                                text=unicode(data['code']))
 
80
            worksheet_exercise = self.context.worksheet_exercise,
 
81
            date = datetime.datetime.now(),
 
82
            complete = test_results['passed'],
 
83
            text = unicode(data['code'])
 
84
        )
98
85
 
99
86
        req.store.add(attempt)
100
87
 
101
88
        # Query the DB to get an updated score on whether or not this problem
102
89
        # has EVER been completed (may be different from "passed", if it has
103
90
        # been completed before), and the total number of attempts.
104
 
        completed, attempts = ivle.worksheet.get_exercise_status(req.store,
105
 
            req.user, exercise)
 
91
        completed, attempts = ivle.worksheet.utils.get_exercise_status(
 
92
                req.store, req.user, self.context.worksheet_exercise)
106
93
        test_results["completed"] = completed
107
94
        test_results["attempts"] = attempts
108
95
 
112
99
class AttemptRESTView(JSONRESTView):
113
100
    '''REST view of an exercise attempt.'''
114
101
 
115
 
    def __init__(self, req, subject, worksheet, exercise, username, date):
116
 
        # TODO: Find exercise within worksheet.
117
 
        user = ivle.database.User.get_by_login(req.store, username)
118
 
        if user is None:
119
 
            raise NotFound()
120
 
 
121
 
        try:
122
 
            date = datetime.datetime.strptime(date, TIMESTAMP_FORMAT)
123
 
        except ValueError:
124
 
            raise NotFound()
125
 
 
126
 
        exercise = ivle.database.Exercise.get_by_name(req.store, exercise)
127
 
        attempt = ivle.worksheet.get_exercise_attempt(req.store, user,
128
 
            exercise, as_of=date, allow_inactive=HISTORY_ALLOW_INACTIVE)
129
 
 
130
 
        if attempt is None:
131
 
            raise NotFound()
132
 
 
133
 
        self.context = attempt
134
 
 
 
102
    @require_permission('view')
135
103
    def GET(self, req):
136
104
        return {'code': self.context.text}
137
105
 
138
106
 
139
 
class ExerciseRESTView(JSONRESTView):
140
 
    '''REST view of an exercise.'''
141
 
    @named_operation
 
107
class WorksheetExerciseRESTView(JSONRESTView):
 
108
    '''REST view of a worksheet exercise.'''
 
109
 
 
110
    @named_operation('view')
142
111
    def save(self, req, text):
143
 
        # Need to open JUST so we know this is a real exercise.
144
 
        # (This avoids users submitting code for bogus exercises).
145
 
        exercisefile = ivle.util.open_exercise_file(self.exercise)
146
 
        if exercisefile is None:
147
 
            raise NotFound()
148
 
        exercisefile.close()
149
 
 
150
 
        exercise = ivle.database.Exercise.get_by_name(req.store, self.exercise)
151
 
        ivle.worksheet.save_exercise(req.store, req.user, exercise,
152
 
                                     unicode(text), datetime.datetime.now())
153
 
        return {"result": "ok"}
 
112
        # Find the appropriate WorksheetExercise to save to. If its not found,
 
113
        # the user is submitting against a non-existant worksheet/exercise
 
114
 
 
115
        old_save = req.store.find(ExerciseSave,
 
116
            ExerciseSave.ws_ex_id == self.context.id,
 
117
            ExerciseSave.user == req.user).one()
 
118
        
 
119
        #Overwrite the old, or create a new if there isn't one
 
120
        if old_save is None:
 
121
            new_save = ExerciseSave()
 
122
            req.store.add(new_save)
 
123
        else:
 
124
            new_save = old_save
 
125
        
 
126
        new_save.worksheet_exercise = self.context
 
127
        new_save.user = req.user
 
128
        new_save.text = unicode(text)
 
129
        new_save.date = datetime.datetime.now()
 
130
 
 
131
        return {"result": "ok"}
 
132
 
 
133
 
 
134
# Note that this is the view of an existing worksheet. Creation is handled
 
135
# by OfferingRESTView (as offerings have worksheets)
 
136
class WorksheetRESTView(JSONRESTView):
 
137
    """View used to update a worksheet."""
 
138
 
 
139
    @named_operation('edit')
 
140
    def save(self, req, name, assessable, data, format):
 
141
        """Takes worksheet data and saves it."""
 
142
        self.context.name = unicode(name)
 
143
        self.context.assessable = self.convert_bool(assessable)
 
144
        self.context.data = unicode(data)
 
145
        self.context.format = unicode(format)
 
146
        ivle.worksheet.utils.update_exerciselist(self.context)
 
147
        
 
148
        return {"result": "ok"}
 
149
 
 
150
class WorksheetsRESTView(JSONRESTView):
 
151
    """View used to update and create Worksheets."""
 
152
 
 
153
    @named_operation('edit')
 
154
    def add_worksheet(self, req, identifier, name, assessable, data, format):
 
155
        """Takes worksheet data and adds it."""
 
156
        
 
157
        new_worksheet = Worksheet()
 
158
        new_worksheet.seq_no = self.context.worksheets.count()
 
159
        # Setting new_worksheet.offering implicitly adds new_worksheet,
 
160
        # hence worksheets.count MUST be called above it
 
161
        new_worksheet.offering = self.context
 
162
        new_worksheet.identifier = unicode(identifier)
 
163
        new_worksheet.name = unicode(name)
 
164
        new_worksheet.assessable = self.convert_bool(assessable)
 
165
        new_worksheet.data = unicode(data)
 
166
        new_worksheet.format = unicode(format)
 
167
        
 
168
        # This call is added for clarity, as the worksheet is implicitly added.        
 
169
        req.store.add(new_worksheet)
 
170
 
 
171
        ivle.worksheet.utils.update_exerciselist(new_worksheet)
 
172
 
 
173
        return {"result": "ok"}
 
174
 
 
175
    @named_operation('edit')
 
176
    def move_up(self, req, worksheetid):
 
177
        """Takes a list of worksheet-seq_no pairs and updates their 
 
178
        corresponding Worksheet objects to match."""
 
179
        
 
180
        worksheet_below = req.store.find(Worksheet,
 
181
            Worksheet.offering_id == self.context.id,
 
182
            Worksheet.identifier == unicode(worksheetid)).one()
 
183
        if worksheet_below is None:
 
184
            raise NotFound('worksheet_below')
 
185
        worksheet_above = req.store.find(Worksheet,
 
186
            Worksheet.offering_id == self.context.id,
 
187
            Worksheet.seq_no == (worksheet_below.seq_no - 1)).one()
 
188
        if worksheet_above is None:
 
189
            raise NotFound('worksheet_above')
 
190
 
 
191
        worksheet_below.seq_no = worksheet_below.seq_no - 1
 
192
        worksheet_above.seq_no = worksheet_above.seq_no + 1
 
193
        
 
194
        return {'result': 'ok'}
 
195
 
 
196
    @named_operation('edit')
 
197
    def move_down(self, req, worksheetid):
 
198
        """Takes a list of worksheet-seq_no pairs and updates their 
 
199
        corresponding Worksheet objects to match."""
 
200
        
 
201
        worksheet_above = req.store.find(Worksheet,
 
202
            Worksheet.offering_id == self.context.id,
 
203
            Worksheet.identifier == unicode(worksheetid)).one()
 
204
        if worksheet_above is None:
 
205
            raise NotFound('worksheet_below')
 
206
        worksheet_below = req.store.find(Worksheet,
 
207
            Worksheet.offering_id == self.context.id,
 
208
            Worksheet.seq_no == (worksheet_above.seq_no + 1)).one()
 
209
        if worksheet_below is None:
 
210
            raise NotFound('worksheet_above')
 
211
 
 
212
        worksheet_below.seq_no = worksheet_below.seq_no - 1
 
213
        worksheet_above.seq_no = worksheet_above.seq_no + 1
 
214
        
 
215
        return {'result': 'ok'}