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