Skip to content

Commit

Permalink
Merge pull request #807 from prathamesh920/add-test-cases-for-QRcode-…
Browse files Browse the repository at this point in the history
…based-upload

Add test cases for qrcode based upload
  • Loading branch information
adityacp authored Mar 24, 2021
2 parents f44cbc4 + 04684f6 commit f8504f1
Show file tree
Hide file tree
Showing 7 changed files with 511 additions and 16 deletions.
1 change: 1 addition & 0 deletions requirements/requirements-common.txt
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ djangorestframework==3.11.0
django-cors-headers==3.1.0
Pillow
pandas
qrcode
more-itertools==8.4.0
django-storages==1.11.1
boto3==1.17.17
87 changes: 85 additions & 2 deletions yaksh/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,11 @@
from textwrap import dedent
from ast import literal_eval
import pandas as pd
import qrcode
import hashlib

# Django Imports
from django.db import models
from django.db import models, IntegrityError
from django.contrib.auth.models import User, Group, Permission
from django.core.exceptions import ValidationError
from django.contrib.contenttypes.models import ContentType
Expand Down Expand Up @@ -2267,7 +2269,7 @@ class AnswerPaper(models.Model):
percent = models.FloatField(null=True, default=0.0)

# Result of the quiz, True if student passes the exam.
passed = models.NullBooleanField()
passed = models.BooleanField(null=True)

# Status of the quiz attempt
status = models.CharField(
Expand Down Expand Up @@ -3312,3 +3314,84 @@ def revoke_special_attempt(self):
def __str__(self):
return 'MicroManager for {0} - {1}'.format(self.student.username,
self.course.name)


class QRcode(models.Model):
random_key = models.CharField(max_length=128, blank=True)
short_key = models.CharField(max_length=128, null=True, unique=True)
image = models.ImageField(upload_to='qrcode', blank=True)
used = models.BooleanField(default=False)
active = models.BooleanField(default=False)
handler = models.ForeignKey('QRcodeHandler', on_delete=models.CASCADE)

def __str__(self):
return 'QRcode {0}'.format(self.short_key)

def is_active(self):
return self.active

def is_used(self):
return self.used

def deactivate(self):
self.active = False

def activate(self):
self.active = True

def set_used(self):
self.used = True

def set_random_key(self):
key = hashlib.sha1('{0}'.format(self.id).encode()).hexdigest()
self.random_key = key

def set_short_key(self):
key = self.random_key
if key:
num = 5
for i in range(40):
try:
self.short_key = key[0:num]
self.save()
break
except IntegrityError:
num = num + 1

def is_qrcode_available(self):
return self.active and not self.used and self.image is not None

def generate_image(self, content):
img = qrcode.make(content)
qr_dir = os.path.join(settings.MEDIA_ROOT, 'qrcode')
if not os.path.exists(qr_dir):
os.makedirs(qr_dir)
path = os.path.join(qr_dir, f'{self.short_key}.png')
img.save(path)
self.image = os.path.join('qrcode', '{0}.png'.format(self.short_key))
self.activate()


class QRcodeHandler(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
answerpaper = models.ForeignKey(AnswerPaper, on_delete=models.CASCADE)
question = models.ForeignKey(Question, on_delete=models.CASCADE)

def __str__(self):
return 'QRcode Handler for {0}'.format(self.user.username)

def get_qrcode(self):
qrcodes = self.qrcode_set.filter(active=True, used=False)
if qrcodes.exists():
return qrcodes.last()
else:
return self._create_qrcode()

def _create_qrcode(self):
qrcode = QRcode.objects.create(handler=self)
qrcode.set_random_key()
qrcode.set_short_key()
return qrcode

def can_use(self):
return self.answerpaper.is_attempt_inprogress()
36 changes: 26 additions & 10 deletions yaksh/templates/yaksh/question.html
Original file line number Diff line number Diff line change
Expand Up @@ -270,15 +270,6 @@ <h4><u> Solution by teacher</u></h4>

<!-- Upload type question -->
{% if question.type == "upload" %}
<p>Upload assignment file for the said question<p>
<div class="dropzone needsclick dz-clickable" id="dropzone_file">
<div class="dz-message needsclick">
<button type="button" class="dz-button">
Drop files here or click to upload.
</button>
</div>
</div>
<br>
{% if assignment_files %}
<div>
<ul class="list-group">
Expand All @@ -290,6 +281,32 @@ <h4><u> Solution by teacher</u></h4>
</ul>
</div>
{% endif %}
<br />
<div class="row">
<div class="col-md-8">
<p>Upload assignment file for the said question.
<br>
<span class="badge badge-primary">
</u> <strong>You can upload using the file browser below or via the QR code.</strong></u>
</span>
</p>
<div class="dropzone needsclick dz-clickable" id="dropzone_file">
<div class="dz-message needsclick">
<button type="button" class="dz-button">
Drop files here or click to upload.
</button>
</div>
</div>
</div>
<div class="col-md-4">
{% if qrcode %}
<img src="{{ qrcode.image.url }}" width="200" height="200">
{% else %}
<a class="active btn btn-outline-primary " href="{% url 'yaksh:generate_qrcode' paper.id question.id module.id %}" data-toggle="tooltip"
title="Upload from any device using the QR Code">Generate QR Code</a>
{% endif %}
</div>
</div>
{% endif %}

<!-- Arrange type question -->
Expand Down Expand Up @@ -370,7 +387,6 @@ <h4>Write your program below:</h4>
{% if question.type == 'code' or question.type == 'upload' %}
<div id="error_panel"></div>
{% endif %}

<!-- Modal -->
<div class="modal" id="upload_alert" >
<div class="modal-dialog">
Expand Down
78 changes: 78 additions & 0 deletions yaksh/templates/yaksh/upload_file.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
{% load static %}
<html>
<title> Upload File </title>
<script language="JavaScript" type="text/javascript" src="{% static 'yaksh/js/jquery-3.3.1.min.js' %}"></script>
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/dropzone/5.8.1/dropzone.min.css">
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/dropzone/5.8.1/basic.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/dropzone/5.8.1/min/dropzone.min.js"></script>
<style>
div, input, button {
font-size: x-large;
text-align: center;
}
</style>
<div>
{% if success %}
<p> {{ msg }}</p>
{% else %}
<form id="code" action="{% url 'yaksh:upload_file' key %}" method="post" enctype="multipart/form-data">
{% csrf_token %}
<h3>Upload assignment file for {{ question.summary }}</h3>
<div class="dropzone needsclick dz-clickable" id="dropzone_file">
<div class="dz-message needsclick">
<button type="button" class="dz-button">
Drop files here or click to upload.
</button>
</div>
</div>
<br>
<button class="btn btn-success" type="submit" name="check" id="check">Upload</button>
</form>
{% endif %}
</div>
</html>
<script>
Dropzone.autoDiscover = false;
var submitfiles;
$(document).ready(function(){
var filezone = $("div#dropzone_file").dropzone({
url: $("#code").attr("action"),
parallelUploads: 10,
uploadMultiple: true,
maxFiles:20,
paramName: "assignment",
autoProcessQueue: false,
init: function() {
var submitButton = document.querySelector("#check");
myDropzone = this;
submitButton.addEventListener("click", function(e) {
if (myDropzone.getQueuedFiles().length === 0) {
alert("Please select a file and upload");
e.preventDefault();
return;
}
if (myDropzone.getAcceptedFiles().length > 0) {
if (submitfiles === true) {
submitfiles = false;
return;
}
e.preventDefault();
myDropzone.processQueue();
myDropzone.on("complete", function () {
submitfiles = true;
$('#check').trigger('click');
});
}
});
},
success: function (file, response) {
document.open();
document.write(response);
document.close();
},
headers: {
"X-CSRFToken": document.getElementById("code").elements[0].value
}
});
});
</script>
Loading

0 comments on commit f8504f1

Please sign in to comment.