summaryrefslogtreecommitdiff
path: root/yaksh
diff options
context:
space:
mode:
authoradityacp2020-02-18 13:29:24 +0530
committeradityacp2020-02-18 13:29:24 +0530
commit2db246f7abb2b8781e60673edec9912166621f4c (patch)
treee5b8ed04dc4c8fd28c401216313d1968d0d59edb /yaksh
parent8b0fb468fd94565b359f3c5bf2f2b694e7a9c97a (diff)
downloadonline_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.py14
-rw-r--r--yaksh/models.py54
-rw-r--r--yaksh/static/yaksh/js/add_question.js159
-rw-r--r--yaksh/static/yaksh/js/course.js1
-rw-r--r--yaksh/static/yaksh/js/show_courses.js39
-rw-r--r--yaksh/templates/yaksh/add_question.html243
-rw-r--r--yaksh/templates/yaksh/course_students.html132
-rw-r--r--yaksh/templates/yaksh/courses.html14
-rw-r--r--yaksh/views.py25
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>&nbsp;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>&nbsp;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}}">&nbsp;delete</input>&nbsp;
- <input type="checkbox" name="extract" value="{{file.id}}" >{% if file.extract %} dont extract{% else %}extract{% endif %}</input>&nbsp;&nbsp;
- <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>&nbsp;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&nbsp;<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"/>&nbsp;
- <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&nbsp;<i class="fa fa-sort"></i></th>
- <th>Email&nbsp;<i class="fa fa-sort"></i></th>
- <th>Roll Number&nbsp;<i class="fa fa-sort"></i></th>
- <th>Institute&nbsp;<i class="fa fa-sort"></i></th>
- <th>Department&nbsp;<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&nbsp;<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"/>&nbsp;
+ <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&nbsp;<i class="fa fa-sort"></i></th>
+ <th>Email&nbsp;<i class="fa fa-sort"></i></th>
+ <th>Roll Number&nbsp;<i class="fa fa-sort"></i></th>
+ <th>Institute&nbsp;<i class="fa fa-sort"></i></th>
+ <th>Department&nbsp;<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)