testappproj/testapp/views.py
author amit@thunder
Mon, 31 May 2010 19:18:57 +0530
changeset 2 654c583fd78e
parent 1 0eda880b3d25
child 3 34d0c21e3352
permissions -rwxr-xr-x
Made some changes and templates

# Python imports
import doctest
import logging
import os
import traceback
import random
import StringIO
import sys

# # AppEngine imports

from django.contrib.auth.models import User 

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



# 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
from django.contrib.auth.decorators import permission_required
from models import Problem
from django.contrib.auth.decorators import login_required 
from models import Score 
import time


# def handle_uploaded_file(f):
#   print f  
#   destination = open('some/file/name.txt', 'wb+')
#   for chunk in f.chunks():
#     destination.write(chunk)
#   destination.close()



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_plotting_test_cases(user_code , solution_image,problem_id , username):
  
  print  user_code 
  print "solution"+solution_image

  image_name = username+'_'+str(problem_id)+'_'+time.time()
  
  code="""from pylab import *
  %s
  show()"""%user_code

  solved=False
  # create file-like string to capture output
  codeOut = StringIO.StringIO()
  codeErr = StringIO.StringIO()



  # capture output and errors
  sys.stdout = codeOut
  sys.stderr = codeErr

  exec code

# restore stdout and stderr
  sys.stdout = sys.__stdout__
  sys.stderr = sys.__stderr__



  
  
  s = codeOut.getvalue()
  
  s=unicode(s)
  

  print s.strip()
  print solution.strip()
  
 
     
  if solution.strip() == s.strip():
    solved =True

  errors=codeErr.getvalue()
  
  

  codeOut.close()
  codeErr.close()

  return solved,errors

def execute_test_cases(code , solution):
  
  print code 
  print "solution"+solution


  solved=False
  # create file-like string to capture output
  codeOut = StringIO.StringIO()
  codeErr = StringIO.StringIO()



  # capture output and errors
  sys.stdout = codeOut
  sys.stderr = codeErr

  exec code

# restore stdout and stderr
  sys.stdout = sys.__stdout__
  sys.stderr = sys.__stderr__



  
  
  s = codeOut.getvalue()
  
  s=unicode(s)
  

  print s.strip()
  print solution.strip()
  
 
     
  if solution.strip() == s.strip():
    solved =True

  errors=codeErr.getvalue()
  
  

  codeOut.close()
  codeErr.close()

  return solved,errors



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
@login_required(function=None, redirect_field_name='next')
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=[]
  all_sessions=set([element.session  for element in Problem.objects.all()])
  print all_sessions

  # for problem in problems:
  #    e = dict(problem=problem.description,
  #             username=user.username,
  #             problem_id=problem.id
             
  #             )
  #    entries.append(e)
  
#  print entries

  
  #get problems to solve from each session.
  for session in all_sessions: 
    get_problem=random.Random().choice(Problem.objects.filter(session=session))
    e = dict(problem=get_problem.description,
             username=user.username,
             problem_id=get_problem.id,
             session =get_problem.session
               )
    entries.append(e)
    

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



@login_required(function=None, redirect_field_name='next')
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
  print problem.id
  return respond(request, request.user ,'code' ,{'problem' : problem } )

def run(request):
  user = request.user 
  print request.POST

  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) 
  solved,errors = execute_test_cases(user_code,problem.solution)
    # 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()
  
  
  

  if solved==True:
    
    #user is answering his first question
    try:
   # print user.id
      score_for_user= Score.objects.get(user=user)
      score_for_user.total_credits+=problem.credit
      score_for_user.save()
    
   # user has answered questions previously
    except Score.DoesNotExist:
#      print user.id 
      score_new_user=user.id
      score_total_credits=problem.credit
      score=Score(user_id=user.id,total_credits=score_total_credits)
      score.save()
  


  else:
    print "oops"
  results=solved
      
  return respond(request, request.user, 'run', {'results': results})
  

@permission_required('testapp.add_problem' , login_url="/code/1234")
def new_edit(request, problem_id=None, internal=False):
  


  # internal indicates that it is being called internally by uploader
  
  user = request.user
  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
    
  if request.method == 'POST':
    form = ProblemForm(request.POST, request.FILES)
  else:
    form = ProblemForm()

  

  if not request.POST:
    return respond(request, user, 'new_edit_problem', {'form':form, 'problem':None, 'creating':creating_new })
  

  
  
  if form.is_valid():
    
    description = form.cleaned_data['Description']
    problem_type=form.cleaned_data['Problem_type']
    solution=form.cleaned_data['Solution']
    session=form.cleaned_data['Session']
    credit=form.cleaned_data['Credit']
   # solution_image=form.cleaned_data['Solution_Image']
    solution_image=request.FILES['Solution_Image']

    author = user.username
    created = date.today()
    modified=date.today()
    
    # print request.FILES 
    # print "this is solution"+solution
    # print "this is solution_image"+solution_image
  

    problem=Problem(description=description,problem_type=problem_type,solution_image=solution_image,session=session,author=author,created=created,modified=modified,credit=credit)
    
    problem.save() 
    print "saved"
  else:
    print "form is valid"
    print form.errors

#  print form.errors
  #  except ValueError, err:
  #    errors['__all__'] = unicode(err)
      

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

  # 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:
    


    
  
   
#  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
  statement=request.GET.get('statement','')
  if  statement is not '':
    
    # the python compiler doesn't like network line endings
    statement = statement.replace('\r\n', '\n')

    # add a couple newlines at the end of the statement. this makes
    # single-line expressions such as 'class Foo: pass' evaluate happily.
    statement += '\n\n'
    print "statement"+statement 
    # log and compile the statement up front
    try:
      logging.info('Compiling and evaluating:\n%s' % statement)
      compiled = compile(statement, '<string>', 'single')
    except:
       return HttpResponse(traceback.format_exc(),mimetype="text/plain")  
#      pass
    return HttpResponse("",mimetype="text/plain")
  else:
    return respond(request, user, 'shell')