pcodigo2web/view/pages/views.py

449 lines
19 KiB
Python

from django.http import HttpResponse
from django.http import HttpResponseRedirect
from django.shortcuts import render
from django.views.generic import View
from django.views.generic import TemplateView
from django.template.response import TemplateResponse
from django.utils.decorators import method_decorator
from django.contrib.auth.decorators import login_required
from django.contrib.auth.mixins import LoginRequiredMixin
from django.http import Http404
from django.urls import reverse
from django.utils.html import escape
from django.core.paginator import Paginator
from application import views as ctrl
from application import forms
#
# Trivial views
#
class SoonView(TemplateView):
template_name = "soon.html"
class LegalTosView(TemplateView):
template_name = "legal/tos.html"
class LegalPrivView(TemplateView):
template_name = "legal/privacy.html"
#
# ABSTRACT VIEWS
#
class TemplateViewLoggedIn(TemplateView, LoginRequiredMixin):
@method_decorator(login_required)
def dispatch(self, *args, **kwargs):
return super().dispatch(*args, **kwargs)
class UserPartEditFormView(TemplateViewLoggedIn):
''' Edits OneToOne fields - such as profiles '''
form = None
pagetitle = '??? Edit'
template_name = "forms/form.html"
on_success = 'index'
on_success_args = []
on_success_kwargs = {}
add_ip = False
add_user = False
'''def get_obj(self, bl, pk, ppk): pass'''
def get_redirection(self, user, model):
return reverse(
self.on_success,
None,
self.on_success_args,
self.on_success_kwargs
)
def build_form(self, bl=None, req_data=None, pk='0', ppk='0'):
obj = self.get_obj(bl,pk,ppk)
if self.add_ip:
obj.ip = bl._ip
if self.add_user:
obj.user = bl.user
return self.form(req_data,instance=obj)
def get(self,request,pk='0', ppk='0'):
rd = request.GET
if len(rd) == 0:
rd = None
return render(request,self.template_name,{
'title': self.pagetitle,
'form': self.build_form(ctrl.BusinessLogic(request), rd, pk, ppk),
})
def post(self,request,pk='0', ppk='0'):
bl = ctrl.BusinessLogic(request)
form = self.build_form(bl,request.POST, pk, ppk)
err = ''
saved = False
try:
if form.is_valid():
form.save()
saved = True
return HttpResponseRedirect(self.get_redirection(bl.user, form.instance))
except Exception as e:
err = escape(str(e)).strip().replace('\n','\n<br>\n')
return render(request, self.template_name,{
'title': self.pagetitle,
'form': form,
'err': err,
})
class CrudListView(TemplateViewLoggedIn):
''' Displays ForeingKey fields - such as lists '''
pagetitle = '???'
template_name = "forms/crudlist.html"
'''
pagetitle = '???'
template_name = "forms/crudlist.html"
item_template = None
edit_url_label = None
delete_url_label = None
def get_list_items(self, bl, ppk): pass
'''
def get(self,request,ppk='0'):
items = self.get_list_items(ctrl.BusinessLogic(request), ppk)
ll = ['0']
if ppk!='0': ll=[ppk,'0']
return render(request,self.template_name,{
'title': self.pagetitle,
'items': items,
'current_pk': ppk,
'item_template': self.item_template,
'addlink': reverse(self.edit_url_label,None,ll),
'delete_url_label': self.delete_url_label,
'edit_url_label': self.edit_url_label,
})
class CrudDeleteView(TemplateViewLoggedIn):
''' Deletes ForeingKey fields - such as list items '''
pagetitle = '???'
'''
pagetitle = '???'
def get_redirection(self, user, model): pass
def get_model(self, bl, pk): pass
'''
def get(self,request,pk='0'):
bl = ctrl.BusinessLogic(request)
redir = self.get_redirection(bl.user, None)
if pk!='0':
model = self.get_model(bl,pk)
redir = self.get_redirection(bl.user, model)
model.delete()
return HttpResponseRedirect(redir)
class CrudEditView(UserPartEditFormView):
''' Edits/adds ForeingKey fields - such as list items '''
pagetitle = '???'
template_name = "forms/form.html"
on_success = None
add_ip = True
add_user = True
manager = None
def get_obj(self, bl, pk, ppk):
if pk=='0':
obj = self.manager()
if ppk!='0':
self.insert_parent(obj, bl, ppk)
return obj
else: return self.manager.objects.get(pk=pk, user__pk=bl.user.pk)
#
# CONCRETE VIEWS
#
class HomeView(TemplateView):
template_name = "index.html"
def get(self,request):
bl = ctrl.BusinessLogic(request)
d = {}
d['bl'] = bl
d['loginform'] = False
if not bl.logged_in:
d['loginform'] = forms.AuthenticationForm()
else:
d['exercises'] = ctrl.models.Exercise.objects.filter(user__pk=bl.user.pk).order_by('-modified')
return render(
request,
self.template_name,
d
)
class SettingsView(TemplateViewLoggedIn):
template_name = "settings/index.html"
import io
import uuid
import zipfile
class ExerciseAddView(TemplateViewLoggedIn):
template_name = "exercise/add.html"
def post(self, request):
bl = ctrl.BusinessLogic(request)
form = forms.ExeciseAddForm(request.POST, request.FILES)
if form.is_valid():
f = form.cleaned_data
name = f['exc_name_prv'] if f['exc_name']=='provided' else str(f['f'])
if name is None or len(name)==0:
name = uuid.uuid4()
exc = ctrl.models.Exercise()
exc.title = name[:255]
exc.user = bl.user
exc.ip = bl._ip
exc.save()
if f['org']!='e':
fileIsName = f['org']=='f'
posPad = 0 if fileIsName else -1
zip = None
try:
zip = zipfile.ZipFile(request.FILES['f'])
except zipfile.BadZipfile:
return HttpResponse('Bad Zip file')
for fileinfo in zip.infolist():
if fileinfo.filename.endswith('/'):
continue
filepath = fileinfo.filename
if (
filepath.endswith('.c')
or
filepath.endswith('.cc')
or
filepath.endswith('.cpp')
or
filepath.endswith('.cxx')
or
filepath.endswith('.java')
):
filename = filepath.split('/')[filepath.count('/')+posPad]
ext = filepath.split('.')[-1]
code = zip.open(fileinfo,'r').read().decode('utf-8','ignore')
sub = ctrl.models.Submission()
sub.exercise = exc
sub.student = filename
sub.filename = str(uuid.uuid4())+'.'+ext
sub.code = code
sub.user = bl.user
sub.ip = bl._ip
sub.save()
return HttpResponseRedirect(reverse('index'))
else:
return HttpResponse('Invalid form')
class ExerciseView(CrudListView):
template_name = "exercise/view.html"
pagetitle = 'Submissions'
item_template = 'forms/listitem_exercise_submission.html'
edit_url_label = 'submission_edt'
delete_url_label = 'submission_del'
def get_list_items(self, bl, ppk): return ctrl.models.Submission.objects.filter(exercise__pk=ppk, user__pk=bl.user.pk).order_by('student')
class ExerciseDelView(CrudDeleteView):
def get_model(self, bl, pk): return ctrl.models.Exercise.objects.get(pk=pk, user__pk=bl.user.pk)
def get_redirection(self, user, model): return reverse('index')
class ExerciseEdtView(CrudEditView):
pagetitle = 'Exercise'
on_success = 'index'
form = forms.ExerciseForm
manager = ctrl.models.Exercise
class SubmissionDelView(CrudDeleteView):
def get_model(self, bl, pk): return ctrl.models.Submission.objects.get(pk=pk, user__pk=bl.user.pk)
def get_redirection(self, user, model):
if model is None: return reverse('index')
else: return reverse('exercise', None, [model.exercise.pk])
class SubmissionEdtView(CrudEditView):
pagetitle = 'Submission'
on_success = 'exercise'
form = forms.SubmissionForm
manager = ctrl.models.Submission
def insert_parent(self, obj, bl, ppk):
exc = ctrl.models.Exercise.objects.get(user__pk=bl.user.pk, pk=ppk)
obj.exercise = exc
def get_redirection(self, user, model):
self.on_success_args = [model.exercise.pk]
return super().get_redirection(user,model)
import json
import re
import graphviz
relPlaPCodigo = re.compile(r'''Variaveis;(.*)\n?\|\|>(.*);([0-9. ]+)\n?<\|\|\|\|>(.*);([0-9. ]+)\n?<\|\|Similaridade: ([0-9.]+)[^\)]+\)''')
class MetricsExplorer(TemplateViewLoggedIn):
template_name = "metrics/explorer.html"
def get(self, request, pk, filedownload=None):
bl = ctrl.BusinessLogic(request)
results = ctrl.models.Results.objects.filter(exercise__user__pk=bl.user.pk, exercise__pk=pk)
has_metrics = results.count()
mapacalor = None
graficosvg = None
plagiarism = None
plagiarism_structured = None
plagmap_svg = None
plagmap_dot = None
plagmap_pdf = None
plagmap_png = None
if has_metrics:
identidades = json.loads(results.get(label='identidades').data.decode())
graficosvg = results.get(label='graficosvg').data.decode()
graficopdf = results.get(label='graficopdf').data
mapacalor = results.get(label='mapacalor').data.decode()
simplagio = results.get(label='simplagio').data.decode()
tabmetricas = results.get(label='tabmetricas').data.decode()
plagiarism = results.get(label='plagiarism').data.decode()
plagiarism_structured = json.loads(results.get(label='plagiarism_structured').data.decode())
plagmap_svg = results.get(label='plagmap_svg').data.decode()
plagmap_dot = results.get(label='plagmap_dot').data.decode()
plagmap_pdf = results.get(label='plagmap_pdf').data
plagmap_png = results.get(label='plagmap_png').data
if filedownload is not None:
if filedownload == 'heatmap':
res = HttpResponse(mapacalor)
res.mimetype='application/force-download'
res['Content-Disposition'] = 'attachment; filename=%s' % 'heatmap.html'
return res
if filedownload == 'clusterssvg':
res = HttpResponse(graficosvg)
res.mimetype='application/force-download'
res['Content-Disposition'] = 'attachment; filename=%s' % 'clusters.svg'
return res
if filedownload == 'clusterspdf':
res = HttpResponse(graficopdf)
res.mimetype='application/force-download'
res['Content-Disposition'] = 'attachment; filename=%s' % 'clusters.pdf'
return res
if filedownload == 'plagiarism':
res = HttpResponse(json.dumps(plagiarism_structured))
res.mimetype='application/force-download'
res['Content-Disposition'] = 'attachment; filename=%s' % 'plagiarism.json'
return res
if filedownload == 'plagiarismmapdot':
res = HttpResponse(plagmap_dot)
res.mimetype='application/force-download'
res['Content-Disposition'] = 'attachment; filename=%s' % 'plagiarismmap.gv'
return res
if filedownload == 'plagiarismmappdf':
res = HttpResponse(plagmap_pdf)
res.mimetype='application/force-download'
res['Content-Disposition'] = 'attachment; filename=%s' % 'plagiarismmap.pdf'
return res
if filedownload == 'plagiarismmappng':
res = HttpResponse(plagmap_png)
res.mimetype='application/force-download'
res['Content-Disposition'] = 'attachment; filename=%s' % 'plagiarismmap.png'
return res
if filedownload == 'plagiarismmapsvg':
res = HttpResponse(plagmap_svg)
res.mimetype='application/force-download'
res['Content-Disposition'] = 'attachment; filename=%s' % 'plagiarismmap.svg'
return res
else:
raise Http404
else:
if filedownload is not None:
raise Http404
return render(request, self.template_name, {
'pk':pk,
'has_metrics':has_metrics,
'heatmap':mapacalor,
'clusters':graficosvg,
'plagiarism':plagiarism_structured,
'plagiarismmap':plagmap_svg,
# 'plagiarism_pretty':json.dumps(plagiarism_structured, sort_keys=True, indent=4)
})
import os
import subprocess
class MetricsExplorerRun(TemplateViewLoggedIn):
def get(self, request, pk):
bl = ctrl.BusinessLogic(request)
submissoes = os.path.join('workspace/submissoes_normalizadorStandalone/in',pk)
subprocess.run(['rm','-rf','workspace/submissoes'])
subprocess.run(['rm','-rf','workspace/submissoes_normalizadorStandalone/in'])
subprocess.run(['mkdir','-p','workspace/submissoes'])
subprocess.run(['mkdir','-p',submissoes])
exercise = ctrl.models.Exercise.objects.get(pk=pk, user__pk=bl.user.pk)
submissions = exercise.submissions.all()
for sb in submissions:
if not os.path.exists(os.path.join(submissoes,sb.student)):
os.makedirs(os.path.join(submissoes,sb.student))
with open(os.path.join(submissoes,sb.student,sb.filename),'wt') as f:
f.write(sb.code)
subprocess.run(['make','-C','workspace'])
my_env = os.environ.copy()
my_env["PATH"] = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
grf = os.path.join('workspace/processado/metricas',pk,'grafico')
subprocess.run(['inkscape', '--export-plain-svg', grf+'.svg', grf+'.eps'], env=my_env)
subprocess.run(['inkscape', '--export-pdf', grf+'.pdf', grf+'.eps'], env=my_env)
ctrl.models.Results.objects.filter(exercise = exercise).delete()
unsaved = list()
unsaved.append(ctrl.models.Results(exercise = exercise, label = 'identidades', data = open(os.path.join('workspace/submissoes',pk,'identidades.json'),'rb').read()))
unsaved.append(ctrl.models.Results(exercise = exercise, label = 'graficosvg', data = open(os.path.join('workspace/processado/metricas',pk,'grafico.svg'),'rb').read()))
unsaved.append(ctrl.models.Results(exercise = exercise, label = 'graficopdf', data = open(os.path.join('workspace/processado/metricas',pk,'grafico.pdf'),'rb').read()))
unsaved.append(ctrl.models.Results(exercise = exercise, label = 'mapacalor', data = open(os.path.join('workspace/processado/metricas',pk,'plot.html'),'rb').read()))
unsaved.append(ctrl.models.Results(exercise = exercise, label = 'tabmetricas', data = open(os.path.join('workspace/processado/metricas',pk,'tabelaParaMapaDeCalor.csv'),'rb').read()))
unsaved.append(ctrl.models.Results(exercise = exercise, label = 'simplagio', data = open(os.path.join('workspace/processado/plagio',pk,'relatorioplagio.csv'),'rb').read()))
identidades = json.loads(unsaved[0].data.decode())
plagiarism = '\n'.join('\n'.join(unsaved[-1].data.decode().splitlines()[2:]).split('\n\n'))
plagiarism_structured = relPlaPCodigo.findall(plagiarism)
for i,p in enumerate(plagiarism_structured):
plagiarism_structured[i]=[
float(p[5]),
'%7.4f%%'%(float(p[5])*100),
identidades.get(p[1],p[1]),
identidades.get(p[3],p[3]),
list([
['Aluno']+p[0].split(';'),
[identidades.get(p[1],p[1])]+[float(k) for k in p[2].split(' ')],
[identidades.get(p[3],p[3])]+[float(k) for k in p[4].split(' ')],
]),
list(zip(
['Aluno']+p[0].split(';'),
[identidades.get(p[1],p[1])]+[float(k) for k in p[2].split(' ')],
[identidades.get(p[3],p[3])]+[float(k) for k in p[4].split(' ')],
)),
]
plagiarism_structured.sort()
plagiarism_structured.reverse()
unsaved.append(ctrl.models.Results(exercise = exercise, label = 'plagiarism', data = plagiarism.encode()))
unsaved.append(ctrl.models.Results(exercise = exercise, label = 'plagiarism_structured', data = json.dumps(plagiarism_structured).encode()))
plagmap = os.path.join('workspace/processado/metricas',pk,'plagiarismmap')
dot = graphviz.Graph()
for plag in plagiarism_structured:
dot.node(plag[2])
dot.node(plag[3])
dot.edge(
plag[2], # alumni 1
plag[3], # alumni 2
plag[1], # similarity text
color="#"+('00'+hex(int((1-((plag[0]-0.9)*10))*255))[2:])[-2:]*3)
dot.render(plagmap+'.gv')
subprocess.run(['inkscape', '--export-plain-svg', plagmap+'.svg', plagmap+'.gv.pdf'])
subprocess.run(['inkscape', '--export-png', plagmap+'.png', plagmap+'.gv.pdf'])
unsaved.append(ctrl.models.Results(exercise = exercise, label = 'plagmap_png', data = open(plagmap+'.png','rb').read()))
unsaved.append(ctrl.models.Results(exercise = exercise, label = 'plagmap_svg', data = open(plagmap+'.svg','rb').read()))
unsaved.append(ctrl.models.Results(exercise = exercise, label = 'plagmap_dot', data = open(plagmap+'.gv','rb').read()))
unsaved.append(ctrl.models.Results(exercise = exercise, label = 'plagmap_pdf', data = open(plagmap+'.gv.pdf','rb').read()))
[data.save() for data in unsaved]
return HttpResponseRedirect(reverse('metrics_explorer',None,[pk]))
import time
class MetricsExplorerRunPoll(TemplateViewLoggedIn):
def get(self, request, pk, inc='0'):
time.sleep(.5)
return HttpResponseRedirect(reverse('metrics_explorer_run_poll',None,[pk,int(inc)+1]))
class MetricsExplorerDel(TemplateViewLoggedIn):
def get(self, request, pk):
bl = ctrl.BusinessLogic(request)
exercise = ctrl.models.Exercise.objects.get(pk=pk, user__pk=bl.user.pk)
results = ctrl.models.Results.objects.filter(exercise__pk=exercise.pk)
results.delete()
return HttpResponseRedirect(reverse('metrics_explorer',None,[pk]))