diff options
author | adityacp | 2020-02-18 13:29:24 +0530 |
---|---|---|
committer | adityacp | 2020-02-18 13:29:24 +0530 |
commit | 2db246f7abb2b8781e60673edec9912166621f4c (patch) | |
tree | e5b8ed04dc4c8fd28c401216313d1968d0d59edb /yaksh | |
parent | 8b0fb468fd94565b359f3c5bf2f2b694e7a9c97a (diff) | |
download | online_test-2db246f7abb2b8781e60673edec9912166621f4c.tar.gz online_test-2db246f7abb2b8781e60673edec9912166621f4c.tar.bz2 online_test-2db246f7abb2b8781e60673edec9912166621f4c.zip |
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
Diffstat (limited to 'yaksh')
-rw-r--r-- | yaksh/forms.py | 14 | ||||
-rw-r--r-- | yaksh/models.py | 54 | ||||
-rw-r--r-- | yaksh/static/yaksh/js/add_question.js | 159 | ||||
-rw-r--r-- | yaksh/static/yaksh/js/course.js | 1 | ||||
-rw-r--r-- | yaksh/static/yaksh/js/show_courses.js | 39 | ||||
-rw-r--r-- | yaksh/templates/yaksh/add_question.html | 243 | ||||
-rw-r--r-- | yaksh/templates/yaksh/course_students.html | 132 | ||||
-rw-r--r-- | yaksh/templates/yaksh/courses.html | 14 | ||||
-rw-r--r-- | yaksh/views.py | 25 |
9 files changed, 427 insertions, 254 deletions
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 %} + <script type="text/javascript" src="{% static 'yaksh/js/tinymce/js/tinymce/tinymce.min.js' %}"></script> <script type="text/javascript" src="{% static 'yaksh/js/add_question.js' %}"></script> <script type="text/javascript" src="{% static 'yaksh/js/mathjax/MathJax.js' %}?config=TeX-MML-AM_CHTML"></script> {% endblock %} @@ -15,109 +17,156 @@ {% block onload %} onload='javascript:textareaformat();' {% endblock %} {% block content %} -<div class="yakshwell container"> - <form action="{% if question %}{% url 'yaksh:add_question' question.id %}{% endif %}" method="post" name=frm onSubmit="return autosubmit();" enctype="multipart/form-data"> +<div class="container"> + <a class="btn btn-primary" href="{% url 'yaksh:show_questions' %}"> + <i class="fa fa-arrow-left"></i> Back + </a> + <br><br> + {% if messages %} + {% for message in messages %} + <div class="alert alert-dismissible alert-{{ message.tags }}"> + <button type="button" class="close" data-dismiss="alert"> + <i class="fa fa-close"></i> + </button> + <strong>{{ message }}</strong> + </div> + {% endfor %} + {% endif %} + <form action="{% if question %}{% url 'yaksh:add_question' question.id %}{% endif %}" method="post" id="question_form" name=frm onSubmit="return autosubmit();" enctype="multipart/form-data"> {% csrf_token %} - <center> - {{qform.instance.language}} - <table class="table table-responsive-sm"> - <tr><td>Summary: <td>{{ qform.summary }}{{ qform.summary.errors }} - <tr><td> Language: <td> {{qform.language}}{{qform.language.errors}} - <tr><td> Type: <td> {{ qform.type }}{{qform.type.errors}} - <tr><td>Points:<td><button class="btn-mini" type="button" onClick="increase(frm);">+</button>{{qform.points }}<button class="btn-mini" type="button" onClick="decrease(frm);">-</button>{{ qform.points.errors }} - <tr><td><strong>Rendered: </strong><td><p id='my'></p> - <tr><td>Description: <td>{{ qform.description}} {{qform.description.errors}} - <tr><td>Tags: <td>{{ qform.tags }} - <tr><td><strong>Rendered Solution: </strong><td><p id='rend_solution'></p> - <tr><td>Solution: <td>{{ qform.solution }} - <tr><td>Snippet: <td>{{ qform.snippet }} - <tr><td>Minimum Time(in minutes):<td> {{ qform.min_time }} - <tr><td>Partial Grading: <td>{{ qform.partial_grading }} - <tr><td>Grade Assignment Upload:<td> {{ qform.grade_assignment_upload }} - <tr><td> File: <td> - <div class="input-group mb-3"> - <div class="custom-file"> - {{ fileform.file_field }}{{ fileform.file_field.errors }} - <label class="custom-file-label" for="id_file"> - Choose file - </label> - </div> - </div> - {% if uploaded_files %} + <table class="table table-responsive-sm"> + {% if qform.errors %} + {% for field in qform %} + {% for error in field.errors %} + <div class="alert alert-dismissible alert-danger"> + <button type="button" class="close" data-dismiss="alert"> + <i class="fa fa-close"></i> + </button> + <strong>{{ error|escape }}</strong> + </div> + {% endfor %} + {% endfor %} + {% for error in qform.non_field_errors %} + <div class="alert alert-dismissible alert-danger"> + <button type="button" class="close" data-dismiss="alert"> + <i class="fa fa-close"></i> + </button> + <strong>{{ error|escape }}</strong> + </div> + {% endfor %} + {% endif %} + {% for field in qform %} + <tr> + <td>{{ field.label }}</td> + <td>{{ field }} <small>{{ field.help_text }}</small></td> + </tr> + {% endfor %} + <tr> + <td> File: </td> + <td> + <div class="input-group mb-3"> + <div class="custom-file"> + {{ fileform.file_field }}{{ fileform.file_field.errors }} + <label class="custom-file-label" for="id_file"> + Choose file + </label> + </div> + </div> + </td> + </tr> + {% if question %} + <tr><td>Add Test Case:</td> + <td> + <select id="case_type" class="form-control" name="case_type" onchange="frm.submit()"> + <option value="" selected="selected">Select Testcase</option> + {% for key, value in testcase_options %} + <option value="{{key}}">{{value}}</option> + {% endfor %} + </select> + </td> + </tr> + {% endif %} + </table> + {% if uploaded_files %} + <div class="card"> + <div class="card-header"> + <h3>Uploaded files</h3> + </div> + <div class="card-body"> + <div> + <p>Check on <b>Delete</b> to delete files, + <b>Extract</b> to extract files and <b>Hide</b> to hide files + </p> + <a href="https://yaksh.readthedocs.io/en/latest/moderator_docs/creating_question.html#setting-up-questions" class="btn btn-primary" target="blank"> + <i class="fa fa-info-circle"></i> More info + </a> + </div> <br> - <b>Uploaded files:</b><br> - Check on delete to delete files, - extract to extract files and hide to hide files from student(if required)<br> - {% for file in uploaded_files %} - <input type="checkbox" name="clear" value="{{file.id}}"> delete</input> - <input type="checkbox" name="extract" value="{{file.id}}" >{% if file.extract %} dont extract{% else %}extract{% endif %}</input> - <input type="checkbox" name="hide" value="{{file.id}}" >{% if file.hide %} show{% else %}hide{% endif %}</input> - <a href="{{file.file.url}}">{{ file.file.name }}</a> - <br> - {% endfor %} - {% endif %} - </table> - </center> - {% for formset in formsets %} - <div class="form-group"> - {{ formset.management_form }} - - {% for form in formset %} - <div class="link-formset well"> - {% autoescape off %} - {{ form.as_p }} - {% endautoescape %} + <ul class="list-group"> + {% for file in uploaded_files %} + <li class="list-group-item"> + <input type="checkbox" name="clear" value="{{file.id}}"> + Delete + </input> + <input type="checkbox" name="extract" value="{{file.id}}"> + {% if file.extract %} Dont extract {% else %} Extract {% endif %} + </input> + <input type="checkbox" name="hide" value="{{file.id}}"> + {% if file.hide %} Show {% else %} Hide {% endif %} + </input> + <a href="{{file.file.url}}">{{ file.file.name|file_title }}</a> + </li> + {% endfor %} + </ul> </div> - {% endfor %} - - </div> - {% endfor %} - <div class="form-group"> - {% if question %} - <label for="case_type">Add Test Case:</label> - {% if question.type == "code" %} - {% if qform.instance.language == "bash" %} - <select id="case_type" class="form-control w-auto" name="case_type" onchange="frm.submit()"> - <option value="" selected="selected">---------</option> - <option value="standardtestcase">Standard </option> - <option value="stdiobasedtestcase">StdIO </option> - <option value="hooktestcase">Hook </option> - </select> - {% elif qform.instance.language == "scilab" %} - <select id="case_type" class="form-control w-auto" name="case_type" onchange="frm.submit()"> - <option value="" selected="selected">---------</option> - <option value="standardtestcase">Standard </option> - <option value="hooktestcase">Hook </option> - </select> - {% else %} - <select id="case_type" class="form-control w-auto" name="case_type" onchange="frm.submit()"> - <option value="" selected="selected">---------</option> - <option value="standardtestcase">Standard </option> - <option value="stdiobasedtestcase">StdIO </option> - <option value="hooktestcase">Hook </option> - <option value="easystandardtestcase">Easy Standard </option> - </select> - {% endif %} - {% else %} - <select id="case_type" class="form-control w-auto" name="case_type" onchange="frm.submit()"> - <option value="" selected="selected">---------</option> - <option value="standardtestcase">Standard </option> - <option value="stdiobasedtestcase">StdIO </option> - <option value="mcqtestcase">MCQ/MCC </option> - <option value="hooktestcase">Hook </option> - <option value="integertestcase">Integer </option> - <option value="stringtestcase"> String </option> - <option value="floattestcase"> Float </option> - <option value="arrangetestcase">Arrange options </option> - </select> - {% endif %} - {% endif %} </div> + {% endif %} + <br> + <div class="card"> + <div class="card-header"> + <h3>Test Cases</h3> + </div> + <div class="card-body"> + {% for formset in formsets %} + {{ formset.management_form }} + <div id="accordion"> + {% for form in formset %} + <div class="card"> + <div class="card-header"> + <div class="row"> + <div class="col-md-4"> + <span class="badge badge-info"> + Test case {{forloop.counter}}. + </span> + </div> + <div class="ml-auto"> + <a class="card-link" data-toggle="collapse" href="#collapse{{form.instance.id}}"> + <i class="fa fa-toggle-down"></i> + </a> + </div> + </div> + </div> + <div id="collapse{{form.instance.id}}" class="collapse {% if formset.extra == 1 %} show {% else %} hide {% endif %}" data-parent="#accordion"> + <div class="card-body"> + {% autoescape off %} + {{form.as_p}} + {% endautoescape %} + </div> + </div> + </div> + <br> + {% endfor %} + </div> + {% endfor %} + </div> + </div> + <br> <center> - <button class="btn btn-lg btn-success" type="submit" name="save_question">Save</button> - <a class="btn btn-lg btn-info" href="{% url 'yaksh:show_questions' %}">Back to Questions</a> - <button class="btn btn-lg btn-danger" type="submit" name="delete_files">Delete Selected Files</button> + <button class="btn btn-lg btn-success" type="submit" name="save_question"> + <i class="fa fa-save"></i> Save + </button> </center> </form> </div> + {% 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 @@ -44,72 +44,6 @@ </div> <!-- End Upload users --> <br> -<!-- Enrolled Students --> -<div id="accordian-enrolled" class="card"> - <div class="card-header"> - <a class="card-link" data-toggle="collapse" href="#enrolled"> - Enrolled Students <i class="fa fa-angle-down"></i> - </a> - </div> -</div> -<div id="enrolled" class="collapse hide" data-parent="#accordion-enrolled"> - {% if enrolled %} - <br> - <input type="checkbox" class="reject"/> - <font size="5">Select all</font> - <div id="reject"> - <form action="{% url 'yaksh:reject_users' course.id %}" method="post" id="reject-form"> - {% csrf_token %} - <table id="enrolled_table" class="tablesorter table table-striped table-responsive-sm course-detail" data-sortlist="[1,0]" style="width: 100%"> - <thead> - <th></th> - <th>Full Name <i class="fa fa-sort"></i></th> - <th>Email <i class="fa fa-sort"></i></th> - <th>Roll Number <i class="fa fa-sort"></i></th> - <th>Institute <i class="fa fa-sort"></i></th> - <th>Department <i class="fa fa-sort"></i></th> - <th>Reject</th> - </thead> - <tbody> - {% for enroll in enrolled %} - <tr> - <td> - {{ forloop.counter }}. - <input type="checkbox" name="check" value="{{ enroll.id }}"> - </td> - <td> {{ enroll.get_full_name|title }} </td> - <td> {{enroll.email}}</td> - {% with enroll.profile as enroll_profile %} - <td> {{enroll_profile.roll_number}}</td> - <td> {{enroll_profile.institute}}</td> - <td> {{enroll_profile.department}}</td> - {% endwith %} - <td> - <a class="btn btn-danger" - href="{% url 'yaksh:reject_user' course.id enroll.id %}"> - <i class="fa fa-minus-square"></i> - Reject - </a> - </td> - </tr> - {% endfor %} - </tbody> - </table> - <button class="btn btn-danger btn-lg" type="submit" name='reject' value='reject'> - <i class="fa fa-minus-square"></i> - Reject Selected - </button> <br> - </form> - </div> - {% else %} - <center> - <span class="badge badge-warning"><big> No enrolled students yet</big></span> - </center> - {% endif %} -</div> -<!-- End Enrolled Students --> - -<br> <!-- Requested Students --> <div id="accordian-request" class="card"> <div class="card-header"> @@ -178,6 +112,72 @@ </div> <!-- End Requested Students --> <br> +<!-- Enrolled Students --> +<div id="accordian-enrolled" class="card"> + <div class="card-header"> + <a class="card-link" data-toggle="collapse" href="#enrolled"> + Enrolled Students <i class="fa fa-angle-down"></i> + </a> + </div> +</div> +<div id="enrolled" class="collapse hide" data-parent="#accordion-enrolled"> + {% if enrolled %} + <br> + <input type="checkbox" class="reject"/> + <font size="5">Select all</font> + <div id="reject"> + <form action="{% url 'yaksh:reject_users' course.id %}" method="post" id="reject-form"> + {% csrf_token %} + <table id="enrolled_table" class="tablesorter table table-striped table-responsive-sm course-detail" data-sortlist="[1,0]" style="width: 100%"> + <thead> + <th></th> + <th>Full Name <i class="fa fa-sort"></i></th> + <th>Email <i class="fa fa-sort"></i></th> + <th>Roll Number <i class="fa fa-sort"></i></th> + <th>Institute <i class="fa fa-sort"></i></th> + <th>Department <i class="fa fa-sort"></i></th> + <th>Reject</th> + </thead> + <tbody> + {% for enroll in enrolled %} + <tr> + <td> + {{ forloop.counter }}. + <input type="checkbox" name="check" value="{{ enroll.id }}"> + </td> + <td> {{ enroll.get_full_name|title }} </td> + <td> {{enroll.email}}</td> + {% with enroll.profile as enroll_profile %} + <td> {{enroll_profile.roll_number}}</td> + <td> {{enroll_profile.institute}}</td> + <td> {{enroll_profile.department}}</td> + {% endwith %} + <td> + <a class="btn btn-danger" + href="{% url 'yaksh:reject_user' course.id enroll.id %}"> + <i class="fa fa-minus-square"></i> + Reject + </a> + </td> + </tr> + {% endfor %} + </tbody> + </table> + <button class="btn btn-danger btn-lg" type="submit" name='reject' value='reject'> + <i class="fa fa-minus-square"></i> + Reject Selected + </button> <br> + </form> + </div> + {% else %} + <center> + <span class="badge badge-warning"><big> No enrolled students yet</big></span> + </center> + {% endif %} +</div> +<!-- End Enrolled Students --> + +<br> <!-- Rejected Students --> <div id="accordian-rejected" class="card"> <div class="card-header"> 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 %} +<script type="text/javascript" src="{% static 'yaksh/js/show_courses.js' %}"> +</script> +{% endblock %} + {% block css %} <style> .test + .tooltip.top > .tooltip-inner { @@ -72,8 +78,12 @@ </div> <div class="ml-auto"> <div class="nav nav-pills" role="tablist" aria-orientation="vertical"> - <a href="#listview" id="listbtn" class="nav-link" data-toggle="pill" role="tab" aria-controls="show" aria-selected="true"> <i class="fa fa-list"></i></a> - <a href="#gridview" id="gridbtn" class="nav-link active" data-toggle="pill" role="tab" aria-controls="updown" aria-selected="false" > <i class="fa fa-columns"></i></a> + <a id="listbtn" class="nav-link" data-toggle="pill" role="tab" aria-controls="show" aria-selected="true"> + <i class="fa fa-list"></i> + </a> + <a id="gridbtn" class="nav-link" data-toggle="pill" role="tab" aria-controls="updown" aria-selected="false"> + <i class="fa fa-columns"></i> + </a> </div> </div> </div> diff --git a/yaksh/views.py b/yaksh/views.py index d1e8b7b..59efc59 100644 --- a/yaksh/views.py +++ b/yaksh/views.py @@ -44,7 +44,7 @@ from yaksh.forms import ( UserRegisterForm, UserLoginForm, QuizForm, QuestionForm, QuestionFilterForm, CourseForm, ProfileForm, UploadFileForm, FileForm, QuestionPaperForm, LessonForm, - LessonFileForm, LearningModuleForm, ExerciseForm + LessonFileForm, LearningModuleForm, ExerciseForm, TestcaseForm ) from yaksh.settings import SERVER_POOL_PORT, SERVER_HOST_NAME from .settings import URL_ROOT @@ -230,22 +230,21 @@ def add_question(request, question_id=None): else: question = None uploaded_files = [] - if request.method == "POST" and 'delete_files' in request.POST: - remove_files_id = request.POST.getlist('clear') - if remove_files_id: - files = FileUpload.objects.filter(id__in=remove_files_id) - for file in files: - file.remove() if request.method == 'POST': qform = QuestionForm(request.POST, instance=question) fileform = FileForm(request.POST, request.FILES) + remove_files_id = request.POST.getlist('clear') files = request.FILES.getlist('file_field') extract_files_id = request.POST.getlist('extract') hide_files_id = request.POST.getlist('hide') if files: for file in files: FileUpload.objects.get_or_create(question=question, file=file) + if remove_files_id: + files = FileUpload.objects.filter(id__in=remove_files_id) + for file in files: + file.remove() if extract_files_id: files = FileUpload.objects.filter(id__in=extract_files_id) for file in files: @@ -256,10 +255,10 @@ def add_question(request, question_id=None): file.toggle_hide_status() formsets = [] for testcase in TestCase.__subclasses__(): - formset = inlineformset_factory( Question, testcase, extra=0, fields='__all__', + form=TestcaseForm, formfield_callback=formfield_callback ) formsets.append(formset( @@ -278,6 +277,7 @@ def add_question(request, question_id=None): formset.save() test_case_type = request.POST.get('case_type', None) uploaded_files = FileUpload.objects.filter(question_id=question.id) + messages.success(request, "Question saved successfully") else: context = { 'qform': qform, @@ -286,6 +286,7 @@ def add_question(request, question_id=None): 'formsets': formsets, 'uploaded_files': uploaded_files } + messages.warning(request, "Unable to save the question") return render(request, "yaksh/add_question.html", context) qform = QuestionForm(instance=question) @@ -294,11 +295,13 @@ def add_question(request, question_id=None): for testcase in TestCase.__subclasses__(): if test_case_type == testcase.__name__.lower(): formset = inlineformset_factory( - Question, testcase, extra=1, fields='__all__' + Question, testcase, extra=1, fields='__all__', + form=TestcaseForm ) else: formset = inlineformset_factory( - Question, testcase, extra=0, fields='__all__' + Question, testcase, extra=0, fields='__all__', + form=TestcaseForm ) formsets.append( formset( @@ -308,6 +311,8 @@ def add_question(request, question_id=None): ) context = {'qform': qform, 'fileform': fileform, 'question': question, 'formsets': formsets, 'uploaded_files': uploaded_files} + if question is not None: + context["testcase_options"] = question.get_test_case_options() return render(request, "yaksh/add_question.html", context) |