|
1 # Python imports |
|
2 import doctest |
|
3 import logging |
|
4 import os |
|
5 import traceback |
|
6 import random |
|
7 |
|
8 |
|
9 # # AppEngine imports |
|
10 |
|
11 from django.contrib.auth.models import User |
|
12 |
|
13 from testappproj.testapp.models import * |
|
14 from django.http import HttpResponse |
|
15 |
|
16 # from google.appengine.api import users |
|
17 # from google.appengine.ext.webapp import template |
|
18 |
|
19 # from google.appengine.ext import db |
|
20 # from google.appengine.ext.db import djangoforms |
|
21 |
|
22 |
|
23 # Django imports |
|
24 #from django.conf import settings |
|
25 #settings._target = None |
|
26 #os.environ['DJANGO_SETTINGS_MODULE'] = 'settings' |
|
27 #import django |
|
28 from django import http |
|
29 from django import shortcuts |
|
30 from django.template import Context ,RequestContext |
|
31 from django.template.loader import get_template |
|
32 |
|
33 # Local imports |
|
34 from forms import * |
|
35 import models |
|
36 from helpers import bulkuploader as pykataupload |
|
37 from datetime import date |
|
38 from django.contrib.auth.decorators import permission_required |
|
39 from models import Problem |
|
40 |
|
41 |
|
42 def respond(request, user,template, params=None): |
|
43 """Helper to render a response, passing standard stuff to the response. |
|
44 |
|
45 Args: |
|
46 request: The request object. |
|
47 user: The User object representing the current user; or None if nobody |
|
48 is logged in. |
|
49 template: The template name; '.html' is appended automatically. |
|
50 params: A dict giving the template parameters; modified in-place. |
|
51 |
|
52 Returns: |
|
53 Whatever render_to_response(template, params) returns. |
|
54 |
|
55 Raises: |
|
56 Whatever render_to_response(template, params) raises. |
|
57 """ |
|
58 if params is None: |
|
59 params = {} |
|
60 if user: |
|
61 params['user'] = user |
|
62 params['sign_out'] = 1 |
|
63 # params['is_admin'] = (users.is_current_user_admin()) |
|
64 else: |
|
65 params['sign_in'] = 1 |
|
66 # if not template.endswith('.html'): |
|
67 template += '.html' |
|
68 return shortcuts.render_to_response(template, params) |
|
69 |
|
70 def execute_test_cases(request, test_cases, g): |
|
71 li = [] |
|
72 |
|
73 solved = True |
|
74 for e in test_cases: |
|
75 if not e.want: |
|
76 exec e.source in g |
|
77 continue |
|
78 call = e.source.strip() |
|
79 got = eval(e.source.strip(), g) |
|
80 expected = eval(e.want, g) |
|
81 |
|
82 if got == expected: |
|
83 status = 'pass' |
|
84 else: |
|
85 status = 'fail' |
|
86 solved = False |
|
87 li.append([call, expected, "%r" % got, status]) |
|
88 |
|
89 return li, solved |
|
90 |
|
91 |
|
92 |
|
93 |
|
94 def index(request): |
|
95 """ need to change user in the django.contrib way""" |
|
96 |
|
97 user = request.user |
|
98 |
|
99 return respond(request , user, 'index') |
|
100 |
|
101 # def contribution(request): |
|
102 # # user = users.get_current_user() |
|
103 # return respond(request, user, 'contribution') |
|
104 |
|
105 # def help(request): |
|
106 # # user = users.get_current_user() |
|
107 # return respond(request, user, 'help') |
|
108 |
|
109 # def about(request): |
|
110 # # user = users.get_current_user() |
|
111 # return respond(request, user, 'about') |
|
112 |
|
113 # def vision(request): |
|
114 # # user = users.get_current_user() |
|
115 # return respond(request, user, 'vision') |
|
116 |
|
117 # def statements(request): |
|
118 # # user = users.get_current_user() |
|
119 # return respond(request, user, 'statements') |
|
120 |
|
121 |
|
122 def get_pu(problem): |
|
123 ''' |
|
124 returns: |
|
125 - "USER_NOT_SIGNED_IN": user not signed in. returning this to prevent saving anonymous user's potentially crappy solution and display it to every anonymous visitor |
|
126 - "PU_NOT_FOUND": for signed in users when no solution has been attempted. |
|
127 - ProblemUser: for signed in users when a solution has been attempted |
|
128 |
|
129 ''' |
|
130 # user = users.get_current_user() |
|
131 # if not user: |
|
132 # return "USER_NOT_SIGNED_IN" |
|
133 pu_query = models.ProblemUser.all().filter('problem = ', problem).filter('user =', users.get_current_user()) |
|
134 pu_results = pu_query.fetch(1) |
|
135 if pu_results: |
|
136 return pu_results[0] |
|
137 return "PU_NOT_FOUND" |
|
138 |
|
139 # def is_solved(problem): |
|
140 # pu = get_pu(problem) |
|
141 # if pu == "PU_NOT_FOUND" or pu == "USER_NOT_SIGNED_IN": return False |
|
142 # return pu.solved |
|
143 |
|
144 def problems(request, category=None): |
|
145 user = request.user |
|
146 |
|
147 # if category is None: |
|
148 # problems = db.GqlQuery('SELECT * FROM Problem ORDER BY created DESC') |
|
149 # else: |
|
150 # problems = db.GqlQuery('SELECT * FROM Problem WHERE categories = :1 ORDER BY created DESC', category) |
|
151 |
|
152 |
|
153 |
|
154 |
|
155 # entries = [] |
|
156 # for problem in problems: |
|
157 # e = dict(problem=problem, |
|
158 # username=problem.author.nickname().partition('@')[0], |
|
159 # solved=is_solved(problem)) |
|
160 # entries.append(e) |
|
161 # problems = entries |
|
162 entries=[] |
|
163 all_sessions=set([element.session for element in Problem.objects.all()]) |
|
164 print all_sessions |
|
165 |
|
166 # for problem in problems: |
|
167 # e = dict(problem=problem.description, |
|
168 # username=user.username, |
|
169 # problem_id=problem.id |
|
170 |
|
171 # ) |
|
172 # entries.append(e) |
|
173 |
|
174 # print entries |
|
175 |
|
176 |
|
177 #get problems to solve from each session. |
|
178 for session in all_sessions: |
|
179 get_problem=random.Random().choice(Problem.objects.filter(session=session)) |
|
180 e = dict(problem=get_problem.description, |
|
181 username=user.username, |
|
182 problem_id=get_problem.id, |
|
183 session =get_problem.session |
|
184 ) |
|
185 entries.append(e) |
|
186 |
|
187 |
|
188 return respond(request, user, 'problems',{'entries' : entries } ) |
|
189 |
|
190 def code(request, problem_id): |
|
191 |
|
192 print problem_id |
|
193 problem = Problem.objects.get(id=int(problem_id)) |
|
194 |
|
195 if problem is None: |
|
196 return http.HttpResponseNotFound('No such problem.') |
|
197 |
|
198 # pu = get_pu(problem) |
|
199 # if pu == "PU_NOT_FOUND": # user is attempting problem for the first time |
|
200 # pu = models.ProblemUser(problem=problem, user=users.get_current_user(), solution='', solved=False) |
|
201 # pu.put() |
|
202 # pu = None |
|
203 |
|
204 return respond(request, request.user ,'code' , ) |
|
205 |
|
206 def run(request): |
|
207 user = request.user |
|
208 problem_id = request.POST.get('problem_id') |
|
209 if problem_id: |
|
210 problem = Problem.objects.get(id=int(problem_id)) |
|
211 |
|
212 if problem is None: |
|
213 return http.HttpResponseNotFound('No such problem.') |
|
214 |
|
215 user_code = request.POST.get('user_code') |
|
216 |
|
217 if not user_code: |
|
218 return http.HttpResponse('bad request') |
|
219 |
|
220 # pu = get_pu(problem) |
|
221 # # update ProblemUser object for this user |
|
222 # if (pu.__class__ == models.ProblemUser): |
|
223 # pu.solution = user_code |
|
224 # pu.put() |
|
225 |
|
226 user_code = user_code.replace('\r\n', '\n') |
|
227 user_code += '\n\n' |
|
228 |
|
229 errors = '' |
|
230 |
|
231 |
|
232 try: |
|
233 print user_code |
|
234 compiled = compile(user_code, 'error_file', 'exec') |
|
235 g = {} |
|
236 exec compiled in g |
|
237 |
|
238 # s = problem.tests.replace('\r\n', '\n') |
|
239 # s += '\n\n' |
|
240 # test_cases = doctest.DocTestParser().get_examples(s) |
|
241 # results, solved = execute_test_cases(request, test_cases, g) |
|
242 # if solved: |
|
243 # pu = get_pu(problem) |
|
244 # if pu.__class__ == models.ProblemUser: |
|
245 # pu.solved = True |
|
246 # pu.put() |
|
247 # else: |
|
248 # pu = get_pu(problem) |
|
249 # if pu.__class__ == models.ProblemUser: |
|
250 # pu.solved = False |
|
251 # pu.put() |
|
252 except: |
|
253 errors = traceback.format_exc() |
|
254 return respond(request, user, 'traceback', {'errors': errors}) |
|
255 results="solved" |
|
256 return respond(request, request.user, 'run', {'results': results}) |
|
257 |
|
258 |
|
259 @permission_required('testapp.add_problem' , login_url="/code/1234") |
|
260 def new_edit(request, problem_id=None, internal=False): |
|
261 |
|
262 |
|
263 |
|
264 # internal indicates that it is being called internally by uploader |
|
265 # |
|
266 user = request.user |
|
267 # print user.get_all_permissions() |
|
268 print user.username |
|
269 if user.is_anonymous() : |
|
270 return http.HttpResponseForbidden('You must be an signed in to create edit a problem.') |
|
271 |
|
272 if problem_id is None: |
|
273 creating_new = True |
|
274 else: |
|
275 creating_new = False |
|
276 |
|
277 # problem = None |
|
278 # if problem_id: |
|
279 # problem = models.Problem.get(db.Key.from_path(models.Problem.kind(), int(problem_id))) |
|
280 # if problem.author != user and not users.is_current_user_admin(): |
|
281 # return http.HttpResponseForbidden('You can only edit your own problems.') |
|
282 # if problem is None: |
|
283 # return http.HttpResponseNotFound('No such problem.') |
|
284 |
|
285 # formset = ProblemForm(data=request.POST) |
|
286 # instance=formset.save() |
|
287 # # upload_form = UploadForm(data=request.POST) |
|
288 |
|
289 if request.method == 'POST': |
|
290 form = ProblemForm(request.POST) |
|
291 else: |
|
292 form = ProblemForm() |
|
293 |
|
294 |
|
295 |
|
296 if not request.POST: |
|
297 return respond(request, user, 'new_edit_problem', {'form':form, 'problem':None, 'creating':creating_new }) |
|
298 |
|
299 # print form |
|
300 #errors = form.errors |
|
301 #print str(errors)+"errors" |
|
302 |
|
303 |
|
304 #if not errors: |
|
305 # try: |
|
306 |
|
307 if form.is_valid(): |
|
308 |
|
309 description = form.cleaned_data['Description'] |
|
310 problem_type=form.cleaned_data['Problem_type'] |
|
311 solution=form.cleaned_data['Solution'] |
|
312 session=form.cleaned_data['Session'] |
|
313 |
|
314 author = user.username |
|
315 created = date.today() |
|
316 modified=date.today() |
|
317 |
|
318 problem=Problem(description=description,problem_type=problem_type,solution=solution,session=session,author=author,created=created,modified=modified) |
|
319 |
|
320 problem.save() |
|
321 print "saved" |
|
322 else: |
|
323 print "form is valid" |
|
324 print form.errors |
|
325 |
|
326 # print form.errors |
|
327 # except ValueError, err: |
|
328 # errors['__all__'] = unicode(err) |
|
329 |
|
330 |
|
331 # if errors: |
|
332 # print "new world" |
|
333 # if internal: |
|
334 |
|
335 # print errors |
|
336 # return ('error',errors) |
|
337 # return respond(request, user, 'new_edit_problem', |
|
338 # {'form': form, 'problem':problem, 'creating':creating_new,'error':errors}) |
|
339 |
|
340 # if creating_new: |
|
341 # # if internal: |
|
342 # # if len(request.POST['user_id'])>0: |
|
343 # # logging.info(request.POST) |
|
344 # # problem.author = users.User(request.POST['user_id']) |
|
345 # # else: |
|
346 # # problem.author = user |
|
347 # # else: |
|
348 |
|
349 |
|
350 |
|
351 |
|
352 |
|
353 |
|
354 # l = [] |
|
355 # for x in problem.categories: |
|
356 # l.extend(x.split()) |
|
357 # problem.categories = l |
|
358 # problem.put() |
|
359 |
|
360 if internal: |
|
361 return ('success','success') |
|
362 |
|
363 |
|
364 return http.HttpResponseRedirect('/problems') |
|
365 |
|
366 def upload(request): |
|
367 """ upload handler, validates the form and calls handle_uploaded_file |
|
368 for processing further |
|
369 """ |
|
370 user = request.user |
|
371 if user is None: |
|
372 return http.HttpResponseForbidden('You must be an signed in to create/edit a problem.') |
|
373 |
|
374 if request.method == 'POST': |
|
375 form = UploadForm(request.POST, request.FILES) |
|
376 if form.is_valid(): |
|
377 submission_report = handle_uploaded_file(request) |
|
378 print "testing" |
|
379 print submission_report |
|
380 |
|
381 return respond(request, user, 'upload', {'report':submission_report}) |
|
382 else: |
|
383 return http.HttpResponseForbidden('Oops something went wrong with the upload') |
|
384 |
|
385 def handle_uploaded_file(request): |
|
386 """ Handles uploaded data, pushes it to existing problem creating code |
|
387 TODO: 1. make efficient by putting actual database code Here |
|
388 2. Add more security and validation |
|
389 """ |
|
390 submission_data = request.FILES['file'].read() |
|
391 if '#---' in submission_data: |
|
392 all_submissions = submission_data.split('#---')[1:-1] |
|
393 # ^^ ignoring the first null and last __main__ code |
|
394 all_submissions = [ pykataupload.Submission(x) for x in all_submissions ] |
|
395 report = [] |
|
396 |
|
397 for key,each_submission in enumerate(all_submissions): |
|
398 # TODO: handle these later by TaskQueues to avoid timeouts on big uploads |
|
399 # a good way would be to have ajax based status coming back to this page |
|
400 # about each problem in the uploaded file, their status, progress etc. |
|
401 each_submission.parse() |
|
402 request.POST.clear() |
|
403 request.POST.update (each_submission.data_dict) |
|
404 upload_status, upload_response = new_edit(request, internal=True) |
|
405 |
|
406 report.append ({'status':upload_status, 'name':each_submission['name'], |
|
407 'upload_response':upload_response}) |
|
408 |
|
409 # Yay this hack works :D |
|
410 return report |
|
411 else: |
|
412 return http.HttpResponseForbidden('The file you uploaded is not in appropriate format.') |
|
413 |
|
414 def shell(request): |
|
415 """ need to change user in the django.contrib way""" |
|
416 |
|
417 user = request.user |
|
418 statement=request.GET.get('statement','') |
|
419 if statement is not '': |
|
420 |
|
421 # the python compiler doesn't like network line endings |
|
422 statement = statement.replace('\r\n', '\n') |
|
423 |
|
424 # add a couple newlines at the end of the statement. this makes |
|
425 # single-line expressions such as 'class Foo: pass' evaluate happily. |
|
426 statement += '\n\n' |
|
427 print "statement"+statement |
|
428 # log and compile the statement up front |
|
429 try: |
|
430 logging.info('Compiling and evaluating:\n%s' % statement) |
|
431 compiled = compile(statement, '<string>', 'single') |
|
432 except: |
|
433 return HttpResponse(traceback.format_exc(),mimetype="text/plain") |
|
434 # pass |
|
435 return HttpResponse("",mimetype="text/plain") |
|
436 else: |
|
437 return respond(request, user, 'shell') |
|
438 |
|
439 |