From 2db246f7abb2b8781e60673edec9912166621f4c Mon Sep 17 00:00:00 2001 From: adityacp Date: Tue, 18 Feb 2020 13:29:24 +0530 Subject: Change forms, views, models, templates - Fix UI in add question page - Add test case form for question formset with custom attributes - Add a model method in question class to get question test cases based on type and language of the question - Retain the state of the list view and grid view in courses page - Requested students list will be shown on top in the course detail page --- yaksh/forms.py | 14 +- yaksh/models.py | 54 +++++++ yaksh/static/yaksh/js/add_question.js | 159 ++++++++++--------- yaksh/static/yaksh/js/course.js | 1 + yaksh/static/yaksh/js/show_courses.js | 39 +++++ yaksh/templates/yaksh/add_question.html | 243 +++++++++++++++++------------ yaksh/templates/yaksh/course_students.html | 132 ++++++++-------- yaksh/templates/yaksh/courses.html | 14 +- yaksh/views.py | 25 +-- 9 files changed, 427 insertions(+), 254 deletions(-) create mode 100644 yaksh/static/yaksh/js/show_courses.js diff --git a/yaksh/forms.py b/yaksh/forms.py index 73d4b54..767e51f 100644 --- a/yaksh/forms.py +++ b/yaksh/forms.py @@ -1,7 +1,7 @@ from django import forms from yaksh.models import ( get_model_class, Profile, Quiz, Question, Course, QuestionPaper, Lesson, - LearningModule + LearningModule, TestCase ) from grades.models import GradingSystem from django.contrib.auth import authenticate @@ -537,3 +537,15 @@ class LearningModuleForm(forms.ModelForm): class Meta: model = LearningModule fields = ['name', 'description', 'active'] + + +class TestcaseForm(forms.ModelForm): + + type = forms.CharField( + widget=forms.TextInput( + attrs={'readonly': 'readonly', 'class': form_input_class}) + ) + + class Meta: + model = TestCase + fields = ["type"] diff --git a/yaksh/models.py b/yaksh/models.py index efd4fd7..e9c025f 100644 --- a/yaksh/models.py +++ b/yaksh/models.py @@ -1268,6 +1268,42 @@ class Question(models.Model): # Solution for the question. solution = models.TextField(blank=True) + tc_code_types = { + "python": [ + ("standardtestcase", "Standard TestCase"), + ("stdiobasedtestcase", "StdIO TestCase"), + ("hooktestcase", "Hook TestCase") + ], + "c": [ + ("standardtestcase", "Standard TestCase"), + ("stdiobasedtestcase", "StdIO TestCase"), + ("hooktestcase", "Hook TestCase") + ], + "cpp": [ + ("standardtestcase", "Standard TestCase"), + ("stdiobasedtestcase", "StdIO TestCase"), + ("hooktestcase", "Hook TestCase") + ], + "java": [ + ("standardtestcase", "Standard TestCase"), + ("stdiobasedtestcase", "StdIO TestCase"), + ("hooktestcase", "Hook TestCase") + ], + "r": [ + ("standardtestcase", "Standard TestCase"), + ("hooktestcase", "Hook TestCase") + ], + "bash": [ + ("standardtestcase", "Standard TestCase"), + ("stdiobasedtestcase", "StdIO TestCase"), + ("hooktestcase", "Hook TestCase") + ], + "scilab": [ + ("standardtestcase", "Standard TestCase"), + ("hooktestcase", "Hook TestCase") + ] + } + def consolidate_answer_data(self, user_answer, user=None): question_data = {} metadata = {} @@ -1469,6 +1505,24 @@ class Question(models.Model): files, extract_path = extract_files(zip_file_path) self.read_yaml(extract_path, user, files) + def get_test_case_options(self): + options = None + if self.type == "code": + options = self.tc_code_types.get(self.language) + elif self.type == "mcq" or self.type == "mcc": + options = [("mcqtestcase", "Mcq TestCase")] + elif self.type == "integer": + options = [("integertestcase", "Integer TestCase")] + elif self.type == "float": + options = [("floattestcase", "Float TestCase")] + elif self.type == "string": + options = [("stringtestcase", "String TestCase")] + elif self.type == "arrange": + options = [("arrangetestcase", "Arrange TestCase")] + elif self.type == "upload": + options = [("hooktestcase", "Hook TestCase")] + return options + def __str__(self): return self.summary diff --git a/yaksh/static/yaksh/js/add_question.js b/yaksh/static/yaksh/js/add_question.js index 2db5301..310fed5 100644 --- a/yaksh/static/yaksh/js/add_question.js +++ b/yaksh/static/yaksh/js/add_question.js @@ -1,41 +1,39 @@ function increase(frm) { - if(frm.points.value == "") - { - frm.points.value = "0.5"; - return; - } - frm.points.value = parseFloat(frm.points.value) + 0.5; + if(frm.points.value == "") + { + frm.points.value = "0.5"; + return; + } + frm.points.value = parseFloat(frm.points.value) + 0.5; } function decrease(frm) { - if(frm.points.value > 0) - { - frm.points.value = parseFloat(frm.points.value) - 0.5; - } - else - { - frm.points.value=0; - } - - + if(frm.points.value > 0) + { + frm.points.value = parseFloat(frm.points.value) - 0.5; + } + else + { + frm.points.value=0; + } } function setSelectionRange(input, selectionStart, selectionEnd) { if (input.setSelectionRange) { - input.focus(); - input.setSelectionRange(selectionStart, selectionEnd); + input.focus(); + input.setSelectionRange(selectionStart, selectionEnd); } else if (input.createTextRange) { - var range = input.createTextRange(); - range.collapse(true); - range.moveEnd('character', selectionEnd); - range.moveStart('character', selectionStart); - range.select(); + var range = input.createTextRange(); + range.collapse(true); + range.moveEnd('character', selectionEnd); + range.moveStart('character', selectionStart); + range.select(); } } @@ -43,76 +41,76 @@ function replaceSelection (input, replaceString) { if (input.setSelectionRange) { - var selectionStart = input.selectionStart; - var selectionEnd = input.selectionEnd; - input.value = input.value.substring(0, selectionStart)+ replaceString + input.value.substring(selectionEnd); - if (selectionStart != selectionEnd) - { - setSelectionRange(input, selectionStart, selectionStart + replaceString.length); - } - else - { - setSelectionRange(input, selectionStart + replaceString.length, selectionStart + replaceString.length); - } + var selectionStart = input.selectionStart; + var selectionEnd = input.selectionEnd; + input.value = input.value.substring(0, selectionStart)+ replaceString + input.value.substring(selectionEnd); + if (selectionStart != selectionEnd) + { + setSelectionRange(input, selectionStart, selectionStart + replaceString.length); + } + else + { + setSelectionRange(input, selectionStart + replaceString.length, selectionStart + replaceString.length); + } } else if (document.selection) { - var range = document.selection.createRange(); - if (range.parentElement() == input) - { - var isCollapsed = range.text == ''; - range.text = replaceString; - if (!isCollapsed) - { - range.moveStart('character', -replaceString.length); - range.select(); - } - } + var range = document.selection.createRange(); + if (range.parentElement() == input) + { + var isCollapsed = range.text == ''; + range.text = replaceString; + if (!isCollapsed) + { + range.moveStart('character', -replaceString.length); + range.select(); + } + } } } function textareaformat() { - document.getElementById('id_type').setAttribute('class','custom-select'); - document.getElementById('id_points').setAttribute('class','mini-text'); + document.getElementById('id_type').setAttribute('class','custom-select'); + document.getElementById('id_points').setAttribute('class','mini-text form-control'); document.getElementById('id_tags').setAttribute('class','form-control'); $("[id*="+'test_case_args'+"]").attr('placeholder', 'Command Line arguments for bash only'); - $('#id_snippet').bind('keydown', function( event ){ + $('#id_snippet').bind('keydown', function( event ){ if(navigator.userAgent.match("Gecko")) - { - c=event.which; - } - else - { - c=event.keyCode; - } - if(c==9) - { - replaceSelection(document.getElementById('id_snippet'),String.fromCharCode(9)); - setTimeout(document.getElementById('id_snippet'),0); - return false; - } + { + c=event.which; + } + else + { + c=event.keyCode; + } + if(c==9) + { + replaceSelection(document.getElementById('id_snippet'),String.fromCharCode(9)); + setTimeout(document.getElementById('id_snippet'),0); + return false; + } }); - - $('#id_description').bind('focus', function( event ){ + + $('#id_description').bind('focus', function( event ){ document.getElementById("id_description").rows=5; document.getElementById("id_description").cols=40; }); - $('#id_description').bind('blur', function( event ){ + $('#id_description').bind('blur', function( event ){ document.getElementById("id_description").rows=1; document.getElementById("id_description").cols=40; }); - - $('#id_description').bind('keypress', function (event){ - document.getElementById('my').innerHTML = document.getElementById('id_description').value ; - }); - $('#id_solution').bind('keypress', function (event){ - document.getElementById('rend_solution').innerHTML = document.getElementById('id_solution').value ; - }); + $('#id_description').bind('keypress', function (event){ + document.getElementById('rendered_text').innerHTML = document.getElementById('id_description').value ; + }); + + $('#id_solution').bind('keypress', function (event){ + document.getElementById('rend_solution').innerHTML = document.getElementById('id_solution').value ; + }); $('#id_type').bind('focus', function(event){ var type = document.getElementById('id_type'); @@ -123,8 +121,6 @@ function textareaformat() var language = document.getElementById('id_language'); language.style.border = '1px solid #ccc'; }); - document.getElementById('my').innerHTML = document.getElementById('id_description').value ; - document.getElementById('rend_solution').innerHTML = document.getElementById('id_solution').value ; var question_type = document.getElementById('id_type').value if (document.getElementById('id_grade_assignment_upload').checked || @@ -146,10 +142,17 @@ function textareaformat() $('#id_file_field').on('change',function(){ //get the file name - var fileName = $(this).val(); - //replace the "Choose a file" label - $(this).next('.custom-file-label').html(fileName); - }) + var files = []; + for (var i = 0; i < $(this)[0].files.length; i++) { + files.push($(this)[0].files[i].name); + } + $(this).next('.custom-file-label').html(files.join(', ')); + }); + + $("#question_form").each(function(){ + $(this).find('textarea').addClass("form-control"); + $(this).find('input[type=number]').addClass("form-control"); + }); } function autosubmit() @@ -165,6 +168,6 @@ function autosubmit() { type.style.border = 'solid red'; return false; - } + } } diff --git a/yaksh/static/yaksh/js/course.js b/yaksh/static/yaksh/js/course.js index a4b5579..19f8562 100644 --- a/yaksh/static/yaksh/js/course.js +++ b/yaksh/static/yaksh/js/course.js @@ -127,4 +127,5 @@ $(document).ready(function(){ animate: false, container: 'body' }); + }); // end document ready diff --git a/yaksh/static/yaksh/js/show_courses.js b/yaksh/static/yaksh/js/show_courses.js new file mode 100644 index 0000000..1209ce3 --- /dev/null +++ b/yaksh/static/yaksh/js/show_courses.js @@ -0,0 +1,39 @@ +window.onload = function() { + document.getElementById("listbtn").onclick = function() { + showListView(); + localStorage.setItem('.courseview', 'list'); + return false; + }; + + document.getElementById("gridbtn").onclick = function() { + showGridView(); + localStorage.setItem('.courseview', 'grid'); + return false; + }; + + let itemClass = localStorage.getItem('.courseview'); + + if(itemClass == "list") { + showListView(); + } else { + showGridView(); + } + + function showListView() { + $('#listview').addClass('active'); + $('#listview').removeClass('fade'); + $('#gridview').addClass('fade'); + $('#gridview').removeClass('active'); + $('#listbtn').addClass('active'); + $('#gridbtn').removeClass('active'); + } + + function showGridView() { + $('#listview').addClass('fade'); + $('#listview').removeClass('active'); + $('#gridview').addClass('active'); + $('#gridview').removeClass('fade'); + $('#gridbtn').addClass('active'); + $('#listbtn').removeClass('active'); + } +} \ No newline at end of file diff --git a/yaksh/templates/yaksh/add_question.html b/yaksh/templates/yaksh/add_question.html index a400e35..1ad7deb 100644 --- a/yaksh/templates/yaksh/add_question.html +++ b/yaksh/templates/yaksh/add_question.html @@ -1,4 +1,5 @@ {% extends "manage.html" %} +{% load custom_filters %} {% load staticfiles %} {% block title %} Add Question {% endblock title %} {% block pagetitle %} Add Question {% endblock pagetitle %} @@ -8,6 +9,7 @@ {% endblock %} {% block script %} + {% endblock %} @@ -15,109 +17,156 @@ {% block onload %} onload='javascript:textareaformat();' {% endblock %} {% block content %} -
-
+
+ +  Back + +

+ {% if messages %} + {% for message in messages %} +
+ + {{ message }} +
+ {% endfor %} + {% endif %} + {% csrf_token %} -
- {{qform.instance.language}} - -
Summary: {{ qform.summary }}{{ qform.summary.errors }} -
Language: {{qform.language}}{{qform.language.errors}} -
Type: {{ qform.type }}{{qform.type.errors}} -
Points:{{qform.points }}{{ qform.points.errors }} -
Rendered:

-
Description: {{ qform.description}} {{qform.description.errors}} -
Tags: {{ qform.tags }} -
Rendered Solution:

-
Solution: {{ qform.solution }} -
Snippet: {{ qform.snippet }} -
Minimum Time(in minutes): {{ qform.min_time }} -
Partial Grading: {{ qform.partial_grading }} -
Grade Assignment Upload: {{ qform.grade_assignment_upload }} -
File: -
-
- {{ fileform.file_field }}{{ fileform.file_field.errors }} - -
-
- {% if uploaded_files %} + + {% if qform.errors %} + {% for field in qform %} + {% for error in field.errors %} +
+ + {{ error|escape }} +
+ {% endfor %} + {% endfor %} + {% for error in qform.non_field_errors %} +
+ + {{ error|escape }} +
+ {% endfor %} + {% endif %} + {% for field in qform %} + + + + + {% endfor %} + + + + + {% if question %} + + + + {% endif %} +
{{ field.label }}{{ field }} {{ field.help_text }}
File: +
+
+ {{ fileform.file_field }}{{ fileform.file_field.errors }} + +
+
+
Add Test Case: + +
+ {% if uploaded_files %} +
+
+

Uploaded files

+
+
+
+

Check on Delete to delete files, + Extract to extract files and Hide to hide files +

+ +  More info + +

- Uploaded files:
- Check on delete to delete files, - extract to extract files and hide to hide files from student(if required)
- {% for file in uploaded_files %} -  delete  - {% if file.extract %} dont extract{% else %}extract{% endif %}   - {% if file.hide %} show{% else %}hide{% endif %} - {{ file.file.name }} -
- {% endfor %} - {% endif %} -
-
- {% for formset in formsets %} -
- {{ formset.management_form }} - - {% for form in formset %} - - {% endfor %} - -
- {% endfor %} -
- {% if question %} - - {% if question.type == "code" %} - {% if qform.instance.language == "bash" %} - - {% elif qform.instance.language == "scilab" %} - - {% else %} - - {% endif %} - {% else %} - - {% endif %} - {% endif %}
+ {% endif %} +
+
+
+

Test Cases

+
+
+ {% for formset in formsets %} + {{ formset.management_form }} +
+ {% for form in formset %} +
+
+
+
+ + Test case {{forloop.counter}}. + +
+
+ + + +
+
+
+
+
+ {% autoescape off %} + {{form.as_p}} + {% endautoescape %} +
+
+
+
+ {% endfor %} +
+ {% endfor %} +
+
+
- - Back to Questions - +
+ {% endblock %} diff --git a/yaksh/templates/yaksh/course_students.html b/yaksh/templates/yaksh/course_students.html index 03c57b8..fe64ce4 100644 --- a/yaksh/templates/yaksh/course_students.html +++ b/yaksh/templates/yaksh/course_students.html @@ -43,72 +43,6 @@
-
- -
-
- - Enrolled Students  - -
-
-
- {% if enrolled %} -
-   - Select all -
-
- {% csrf_token %} - - - - - - - - - - - - {% for enroll in enrolled %} - - - - - {% with enroll.profile as enroll_profile %} - - - - {% endwith %} - - - {% endfor %} - -
Full Name Email Roll Number Institute Department Reject
- {{ forloop.counter }}. - - {{ enroll.get_full_name|title }} {{enroll.email}} {{enroll_profile.roll_number}} {{enroll_profile.institute}} {{enroll_profile.department}} - - - Reject - -
-
-
-
- {% else %} -
- No enrolled students yet -
- {% endif %} -
- -
@@ -177,6 +111,72 @@ {% endif %}
+
+ +
+
+ + Enrolled Students  + +
+
+
+ {% if enrolled %} +
+   + Select all +
+
+ {% csrf_token %} + + + + + + + + + + + + {% for enroll in enrolled %} + + + + + {% with enroll.profile as enroll_profile %} + + + + {% endwith %} + + + {% endfor %} + +
Full Name Email Roll Number Institute Department Reject
+ {{ forloop.counter }}. + + {{ enroll.get_full_name|title }} {{enroll.email}} {{enroll_profile.roll_number}} {{enroll_profile.institute}} {{enroll_profile.department}} + + + Reject + +
+
+
+
+ {% else %} +
+ No enrolled students yet +
+ {% endif %} +
+ +
diff --git a/yaksh/templates/yaksh/courses.html b/yaksh/templates/yaksh/courses.html index 5d2c913..6a98ee3 100644 --- a/yaksh/templates/yaksh/courses.html +++ b/yaksh/templates/yaksh/courses.html @@ -1,7 +1,13 @@ {% extends "manage.html" %} +{% load static %} {% block title %} Courses {% endblock %} {% block pagetitle %} Courses {% endblock pagetitle %} +{% block script %} + +{% endblock %} + {% block css %}