testappproj/testapp/views.py~
author amit@thunder
Mon, 17 May 2010 22:33:59 +0530
changeset 0 0b061d58aea3
permissions -rw-r--r--
First commit to Fossee of testapp has the basic Pykata framework on django with some specific changes to Problems model and some views to suit an exam like system

# Python imports
import doctest
import logging
import os
import traceback

# # AppEngine imports

from django.contrib.auth.models import User 

from testappproj.testapp.models import *
from django.http import HttpResponse

# from google.appengine.api import users
# from google.appengine.ext.webapp import template 

# from google.appengine.ext import db
# from google.appengine.ext.db import djangoforms


# Django imports 
#from django.conf import settings
#settings._target = None
#os.environ['DJANGO_SETTINGS_MODULE'] = 'settings'
#import django
from django import http
from django import shortcuts
from django.template import Context ,RequestContext
from django.template.loader import get_template

# Local imports
from forms import *
import models
from helpers import bulkuploader as pykataupload
from datetime import date


def respond(request, user,template, params=None):
  """Helper to render a response, passing standard stuff to the response.

  Args:
    request: The request object.
    user: The User object representing the current user; or None if nobody
      is logged in.
    template: The template name; '.html' is appended automatically.
    params: A dict giving the template parameters; modified in-place.

  Returns:
    Whatever render_to_response(template, params) returns.

  Raises:
    Whatever render_to_response(template, params) raises.
  """
  if params is None:
     params = {}
  if user:
    params['user'] = user
    params['sign_out'] = 1
  #   params['is_admin'] = (users.is_current_user_admin())
  else:
    params['sign_in'] = 1
  # if not template.endswith('.html'):
  template += '.html'
  return shortcuts.render_to_response(template, params)

def execute_test_cases(request, test_cases, g):
  li = []
  
  solved = True
  for e in test_cases:
    if not e.want:
      exec e.source in g
      continue
    call = e.source.strip()
    got = eval(e.source.strip(), g)
    expected = eval(e.want, g)
    
    if got == expected:
      status = 'pass'
    else:
      status = 'fail'
      solved = False
    li.append([call, expected, "%r" % got, status])

  return li, solved




def index(request):
  """ need to change user in the django.contrib way"""

  user = request.user
  
  return respond(request , user, 'index')

# def contribution(request):
# #  user = users.get_current_user()
#   return respond(request, user, 'contribution')
  
# def help(request):
# #  user = users.get_current_user()
#   return respond(request, user, 'help')
  
# def about(request):
# #  user = users.get_current_user()
#   return respond(request, user, 'about')

# def vision(request):
# #  user = users.get_current_user()
#   return respond(request, user, 'vision')

# def statements(request):
# #  user = users.get_current_user()
#   return respond(request, user, 'statements')


def get_pu(problem):
  '''
  returns:
   - "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
   - "PU_NOT_FOUND": for signed in users when no solution has been attempted.
   - ProblemUser: for signed in users when a solution has been attempted
  
  '''
#  user = users.get_current_user()
#  if not user:
#    return "USER_NOT_SIGNED_IN"
  pu_query = models.ProblemUser.all().filter('problem = ', problem).filter('user =', users.get_current_user())
  pu_results = pu_query.fetch(1)
  if pu_results: 
    return pu_results[0]
  return "PU_NOT_FOUND"
   
def is_solved(problem):
  pu = get_pu(problem)
  if pu == "PU_NOT_FOUND" or pu == "USER_NOT_SIGNED_IN": return False
  return pu.solved

def problems(request, category=None):
  user = request.user
  
  # if category is None:
  #   problems = db.GqlQuery('SELECT * FROM Problem ORDER BY created DESC')
  # else:
  #   problems = db.GqlQuery('SELECT * FROM Problem WHERE categories = :1 ORDER BY created DESC', category)
  
  


  # entries = []
  # for problem in problems:
  #   e = dict(problem=problem,
  #            username=problem.author.nickname().partition('@')[0],
  #            solved=is_solved(problem))
  #   entries.append(e)
  # problems = entries
  entries=[]
  problems=Problem.objects.all()
  for problem in problems:
     e = dict(problem=problem.name,
              username=user.username,
              problem_id=problem.id
              )
     entries.append(e)
  
#  print entries



  return respond(request, user, 'problems',{'entries' : entries }  )

def code(request, problem_id):
  
  print problem_id
  problem = Problem.objects.get(id=int(problem_id))

  if problem is None:
    return http.HttpResponseNotFound('No such problem.')
  
#  pu = get_pu(problem)
#  if pu == "PU_NOT_FOUND":  # user is attempting problem for the first time
#    pu = models.ProblemUser(problem=problem, user=users.get_current_user(), solution='', solved=False)
#    pu.put()
#    pu = None

  return respond(request, request.user ,'code' , )

def run(request):
  user = request.user 
  problem_id = request.POST.get('problem_id')
  if problem_id:
    problem = Problem.objects.get(id=int(problem_id))

    if problem is None:
      return http.HttpResponseNotFound('No such problem.')
  
  user_code = request.POST.get('user_code')

  if not user_code:
    return http.HttpResponse('bad request')
  
  # pu = get_pu(problem)
  # # update ProblemUser object for this user
  # if (pu.__class__ == models.ProblemUser):
  #   pu.solution = user_code
  #   pu.put()

  user_code = user_code.replace('\r\n', '\n')
  user_code += '\n\n'

  errors = ''
  
  
  try:
    print user_code
    compiled = compile(user_code, 'error_file', 'exec')
    g = {}
    exec compiled in g

#    s = problem.tests.replace('\r\n', '\n')
#    s += '\n\n'
    # test_cases = doctest.DocTestParser().get_examples(s) 
    # results, solved = execute_test_cases(request, test_cases, g)
    # if solved:
    #   pu = get_pu(problem)
    #   if pu.__class__ == models.ProblemUser:
    #     pu.solved = True
    #     pu.put()
    # else:
    #   pu = get_pu(problem)
    #   if pu.__class__ == models.ProblemUser:
    #     pu.solved = False
    #     pu.put()
  except:
    errors = traceback.format_exc()
    return respond(request, user, 'traceback', {'errors': errors})
  results="solved"
  return respond(request, request.user, 'run', {'results': results})
  
def new_edit(request, problem_id=None, internal=False):
  # internal indicates that it is being called internally by uploader
  #
  user = request.user
  print user.username
  if user.is_anonymous() :
    return http.HttpResponseForbidden('You must be an signed in to create edit a problem.')

  if problem_id is None:
    creating_new = True
  else:
    creating_new = False
    
  problem = None
  # if problem_id:
  #   problem = models.Problem.get(db.Key.from_path(models.Problem.kind(), int(problem_id)))
  #   if problem.author != user and not users.is_current_user_admin():
  #     return http.HttpResponseForbidden('You can only edit your own problems.')
  #   if problem is None:
  #     return http.HttpResponseNotFound('No such problem.')  
 
  form = ProblemForm(data=request.POST or None, instance=problem)
  upload_form = UploadForm(data=request.POST)

  if not request.POST:
    return respond(request, user, 'new_edit_problem', {'form':form, 'problem':problem, 'creating':creating_new , 'upload_form' : upload_form })
  
  
  errors = form.errors
  if not errors:
    try:
      problem = form.save(commit=False)
    except ValueError, err:
      errors['__all__'] = unicode(err)
      

  if errors:
    print "new world"
    if internal:
      return ('error',errors)
    return respond(request, user, 'new_edit_problem', 
                         {'form': form, 'problem':problem, 'creating':creating_new})

  if creating_new:
    # if internal:
    #   if len(request.POST['user_id'])>0:
    #     logging.info(request.POST)
    #     problem.author = users.User(request.POST['user_id'])
    #   else:
    #     problem.author = user
    # else:
    


    
    problem.author = user.username
    problem.created = date.today()
    problem. modified=date.today()

    problem.save()  
#  l = []
  # for x in problem.categories:
  #   l.extend(x.split())
  # problem.categories = l
  # problem.put()

  if internal:
    return ('success','success')
  

  return http.HttpResponseRedirect('/problems')

def upload(request): 
  """ upload handler, validates the form and calls handle_uploaded_file
      for processing further
  """
  user = request.user
  if user is None:
    return http.HttpResponseForbidden('You must be an signed in to create/edit a problem.')

  if request.method == 'POST':
    form = UploadForm(request.POST, request.FILES)
    if form.is_valid():
      submission_report = handle_uploaded_file(request)
      print "testing"
      print submission_report

      return respond(request, user, 'upload', {'report':submission_report})
    else:
      return http.HttpResponseForbidden('Oops something went wrong with the upload')

def handle_uploaded_file(request):
  """ Handles uploaded data, pushes it to existing problem creating code
      TODO: 1. make efficient by putting actual database code Here
            2. Add more security and validation
  """
  submission_data = request.FILES['file'].read()
  if '#---' in submission_data:
    all_submissions = submission_data.split('#---')[1:-1]
    # ^^ ignoring the first null and last __main__ code
    all_submissions = [ pykataupload.Submission(x) for x in all_submissions ]
    report = []

    for key,each_submission in enumerate(all_submissions):
      # TODO: handle these later by TaskQueues to avoid timeouts on big uploads
      # a good way would be to have ajax based status coming back to this page
      # about each problem in the uploaded file, their status, progress etc.
      each_submission.parse()
      request.POST.clear()
      request.POST.update (each_submission.data_dict)
      upload_status, upload_response = new_edit(request, internal=True)

      report.append ({'status':upload_status, 'name':each_submission['name'], 
                          'upload_response':upload_response})

      # Yay this hack works :D
    return report
  else:
    return http.HttpResponseForbidden('The file you uploaded is not in appropriate format.')

def shell(request):
  """ need to change user in the django.contrib way"""

  user = request.user
  print request.GET.get('statement')
  return respond(request , user, 'shell')