diff options
67 files changed, 5039 insertions, 3461 deletions
diff --git a/CHANGELOG.txt b/CHANGELOG.txt index dc80135..4145e07 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -1,3 +1,14 @@ +=== 0.12.0 (04-02-2020) === + +* Added syntax highlighting to the code answers in answerpaper +* Added feature to allow adding newlines to Standard IO testcases +* Added an evaluator to support R language +* Fixed bug to only allow self created grading systems to show up in the course +form +* Fixed bug to hide deleted questions from search results +* Fixed bug to check if residual files exist before teardown operations in +JavaStdIOEvaluator + === 0.11.0 (27-09-2019) === * Upgraded python-social-auth 0.2.19 to social-auth-app-django 3.1.0 diff --git a/grades/templates/add_grades.html b/grades/templates/add_grades.html index 6a9dec9..59a344d 100644 --- a/grades/templates/add_grades.html +++ b/grades/templates/add_grades.html @@ -13,11 +13,6 @@ </a> </li> <li class="nav-item"> - <a class="nav-link" href="{% url 'yaksh:allotted_courses' %}"> - Allotted Courses - </a> - </li> - <li class="nav-item"> <a class="nav-link" href="{% url 'yaksh:add_course' %}"> Add New Course </a> diff --git a/grades/templates/grading_systems.html b/grades/templates/grading_systems.html index 0b26e8e..8102230 100644 --- a/grades/templates/grading_systems.html +++ b/grades/templates/grading_systems.html @@ -12,11 +12,6 @@ </a> </li> <li class="nav-item"> - <a class="nav-link" href="{% url 'yaksh:allotted_courses' %}"> - Allotted Courses - </a> - </li> - <li class="nav-item"> <a class="nav-link" href="{% url 'yaksh:add_course' %}"> Add New Course </a> diff --git a/online_test/__init__.py b/online_test/__init__.py index f323a57..2c7bffb 100644 --- a/online_test/__init__.py +++ b/online_test/__init__.py @@ -1 +1 @@ -__version__ = '0.11.0' +__version__ = '0.12.0' diff --git a/requirements/requirements-common.txt b/requirements/requirements-common.txt index 913ef1f..54e4c84 100644 --- a/requirements/requirements-common.txt +++ b/requirements/requirements-common.txt @@ -9,3 +9,4 @@ selenium==2.53.6 coverage ruamel.yaml==0.15.23 markdown==2.6.9 +pygments==2.2.0 diff --git a/yaksh/admin.py b/yaksh/admin.py index 7ea8ed6..495b48d 100644 --- a/yaksh/admin.py +++ b/yaksh/admin.py @@ -1,6 +1,8 @@ from yaksh.models import Question, Quiz, QuestionPaper, Profile from yaksh.models import (TestCase, StandardTestCase, StdIOBasedTestCase, - Course, AnswerPaper) + Course, AnswerPaper, CourseStatus, LearningModule, + Lesson + ) from django.contrib import admin @@ -14,12 +16,36 @@ class ProfileAdmin(admin.ModelAdmin): "roll_number", "institute", "department"] +class CourseStatusAdmin(admin.ModelAdmin): + search_fields = ['user__first_name', 'user__last_name', 'user__username'] + list_filter = ['course__is_trial'] + + +class CourseAdmin(admin.ModelAdmin): + list_filter = ['active', 'is_trial'] + + +class LearningModuleAdmin(admin.ModelAdmin): + list_filter = ['active', 'is_trial'] + + +class LessonAdmin(admin.ModelAdmin): + list_filter = ['active'] + + +class QuizAdmin(admin.ModelAdmin): + list_filter = ['active', 'is_trial'] + + admin.site.register(Profile, ProfileAdmin) admin.site.register(Question) admin.site.register(TestCase) admin.site.register(StandardTestCase) admin.site.register(StdIOBasedTestCase) -admin.site.register(Course) -admin.site.register(Quiz) +admin.site.register(Course, CourseAdmin) +admin.site.register(Quiz, QuizAdmin) admin.site.register(QuestionPaper) admin.site.register(AnswerPaper, AnswerPaperAdmin) +admin.site.register(CourseStatus, CourseStatusAdmin) +admin.site.register(Lesson, LessonAdmin) +admin.site.register(LearningModule, LearningModuleAdmin) diff --git a/yaksh/error_messages.py b/yaksh/error_messages.py index f34bf28..2d27417 100644 --- a/yaksh/error_messages.py +++ b/yaksh/error_messages.py @@ -34,8 +34,7 @@ def _get_incorrect_user_lines(exp_lines, user_lines): err_line_numbers = [] for line_no, (expected_line, user_line) in \ enumerate(zip_longest(exp_lines, user_lines)): - if (not user_line or not expected_line or - user_line.strip() != expected_line.strip()): + if user_line != expected_line: err_line_numbers.append(line_no) return err_line_numbers diff --git a/yaksh/forms.py b/yaksh/forms.py index def9c32..73d4b54 100644 --- a/yaksh/forms.py +++ b/yaksh/forms.py @@ -3,6 +3,7 @@ from yaksh.models import ( get_model_class, Profile, Quiz, Question, Course, QuestionPaper, Lesson, LearningModule ) +from grades.models import GradingSystem from django.contrib.auth import authenticate from django.contrib.auth.models import User from django.conf import settings @@ -216,6 +217,13 @@ class UserLoginForm(forms.Form): class ExerciseForm(forms.ModelForm): + + def __init__(self, *args, **kwargs): + super(ExerciseForm, self).__init__(*args, **kwargs) + self.fields['description'].widget.attrs.update( + {'class': form_input_class, 'placeholder': "Exercise Description"} + ) + class Meta: model = Quiz fields = ['description', 'view_answerpaper', 'active'] @@ -228,6 +236,34 @@ class QuizForm(forms.ModelForm): def __init__(self, *args, **kwargs): super(QuizForm, self).__init__(*args, **kwargs) + self.fields['start_date_time'].widget.attrs.update( + {'class': form_input_class} + ) + self.fields['end_date_time'].widget.attrs.update( + {'class': form_input_class} + ) + self.fields['duration'].widget.attrs.update( + {'class': form_input_class} + ) + self.fields['description'].widget.attrs.update( + {'class': form_input_class} + ) + self.fields['attempts_allowed'].widget.attrs.update( + {'class': 'custom-select'} + ) + self.fields['time_between_attempts'].widget.attrs.update( + {'class': form_input_class} + ) + self.fields['instructions'].widget.attrs.update( + {'class': form_input_class} + ) + self.fields['weightage'].widget.attrs.update( + {'class': form_input_class} + ) + self.fields['pass_criteria'].widget.attrs.update( + {'class': form_input_class} + ) + self.fields["instructions"].initial = dedent("""\ <p> This examination system has been developed with the intention of @@ -341,8 +377,26 @@ class QuestionFilterForm(forms.Form): class CourseForm(forms.ModelForm): """ course form for moderators """ + class Meta: + model = Course + fields = [ + 'name', 'enrollment', 'active', 'code', 'instructions', + 'start_enroll_time', 'end_enroll_time', 'grading_system', + 'view_grade' + ] - def __init__(self, *args, **kwargs): + def save(self, commit=True, *args, **kwargs): + instance = super(CourseForm, self).save(commit=False) + if instance.code: + instance.hidden = True + else: + instance.hidden = False + + if commit: + instance.save() + return instance + + def __init__(self, user, *args, **kwargs): super(CourseForm, self).__init__(*args, **kwargs) self.fields['name'].widget.attrs.update( {'class': form_input_class, 'placeholder': 'Course Name'} @@ -365,25 +419,14 @@ class CourseForm(forms.ModelForm): self.fields['grading_system'].widget.attrs.update( {'class': 'custom-select'} ) - - def save(self, commit=True, *args, **kwargs): - instance = super(CourseForm, self).save(commit=False) - if instance.code: - instance.hidden = True + if (self.instance.id and + self.instance.teachers.filter(id=user.id).exists()): + self.fields['grading_system'].widget.attrs['disabled'] = True else: - instance.hidden = False - - if commit: - instance.save() - return instance - - class Meta: - model = Course - fields = [ - 'name', 'enrollment', 'active', 'code', 'instructions', - 'start_enroll_time', 'end_enroll_time', 'grading_system', - 'view_grade' - ] + grading_choices = GradingSystem.objects.filter( + creator=user + ) + self.fields['grading_system'].queryset = grading_choices class ProfileForm(forms.ModelForm): @@ -446,9 +489,15 @@ class LessonForm(forms.ModelForm): def __init__(self, *args, **kwargs): super(LessonForm, self).__init__(*args, **kwargs) des_msg = "Enter Lesson Description as Markdown text" - name_msg = "Enter Lesson Name" - self.fields['description'].widget.attrs['placeholder'] = des_msg - self.fields['name'].widget.attrs['placeholder'] = name_msg + self.fields['name'].widget.attrs.update( + {'class': form_input_class, 'placeholder': 'Lesson Name'} + ) + self.fields['description'].widget.attrs.update( + {'class': form_input_class, 'placeholder': des_msg} + ) + self.fields['video_file'].widget.attrs.update( + {'class': "custom-file-input"} + ) class Meta: model = Lesson @@ -468,17 +517,22 @@ class LessonForm(forms.ModelForm): class LessonFileForm(forms.Form): - Lesson_files = forms.FileField(widget=forms.ClearableFileInput( - attrs={'multiple': True}), - required=False) + Lesson_files = forms.FileField( + widget=forms.ClearableFileInput( + attrs={'multiple': True, 'class': "custom-file-input"}), + required=False) class LearningModuleForm(forms.ModelForm): def __init__(self, *args, **kwargs): super(LearningModuleForm, self).__init__(*args, **kwargs) - name_msg = "Enter Learning Module Name" - self.fields['name'].widget.attrs['placeholder'] = name_msg self.fields['name'].widget.attrs['size'] = 30 + self.fields['name'].widget.attrs.update( + {'class': form_input_class, 'placeholder': 'Module Name'} + ) + self.fields['description'].widget.attrs.update( + {'class': form_input_class, 'placeholder': 'Module Description'} + ) class Meta: model = LearningModule diff --git a/yaksh/java_stdio_evaluator.py b/yaksh/java_stdio_evaluator.py index 89f9fc4..0d7e480 100644 --- a/yaksh/java_stdio_evaluator.py +++ b/yaksh/java_stdio_evaluator.py @@ -26,7 +26,8 @@ class JavaStdIOEvaluator(StdIOEvaluator): self.weight = test_case_data.get('weight') def teardown(self): - os.remove(self.submit_code_path) + if os.path.exists(self.submit_code_path): + os.remove(self.submit_code_path) if self.files: delete_files(self.files) diff --git a/yaksh/live_server_tests/selenium_test.py b/yaksh/live_server_tests/selenium_test.py index 41a0fad..6d9117d 100644 --- a/yaksh/live_server_tests/selenium_test.py +++ b/yaksh/live_server_tests/selenium_test.py @@ -74,6 +74,7 @@ class SeleniumTest(): submit_answer_elem.click() WebDriverWait(self.driver, 90).until(ElementDisplay( (By.XPATH, "//*[@id='ontop']"))) + self.driver.execute_script("scrollBy(0,-1000);") def test_c_question(self, question_label): # Incorrect Answer @@ -127,7 +128,7 @@ class SeleniumTest(): # open module link self.driver.find_elements_by_partial_link_text( 'START')[0].click() - self.driver.find_element_by_link_text('Start').click() + self.driver.find_element_by_link_text('START').click() # open quiz link self.driver.find_element_by_link_text(self.quiz_name).click() diff --git a/yaksh/migrations/0016_release_0_12_0.py b/yaksh/migrations/0016_release_0_12_0.py new file mode 100644 index 0000000..74edaa5 --- /dev/null +++ b/yaksh/migrations/0016_release_0_12_0.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.21 on 2020-02-05 05:38 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('yaksh', '0015_release_0_10_0'), + ] + + operations = [ + migrations.AlterField( + model_name='question', + name='language', + field=models.CharField(choices=[('python', 'Python'), ('bash', 'Bash'), ('c', 'C Language'), ('cpp', 'C++ Language'), ('java', 'Java Language'), ('scilab', 'Scilab'), ('r', 'R')], max_length=24), + ), + ] diff --git a/yaksh/models.py b/yaksh/models.py index 6881b4f..efd4fd7 100644 --- a/yaksh/models.py +++ b/yaksh/models.py @@ -46,6 +46,7 @@ languages = ( ("cpp", "C++ Language"), ("java", "Java Language"), ("scilab", "Scilab"), + ("r", "R"), ) question_types = ( @@ -879,6 +880,7 @@ class Course(models.Model): copy_module_name = "Copy of {0}".format(module.name) new_module = module._create_module_copy(user, copy_module_name) new_course.learning_module.add(new_module) + return new_course def request(self, *users): self.requests.add(*users) @@ -1160,6 +1162,11 @@ class CourseStatus(models.Model): self.current_unit = unit self.save() + def __str__(self): + return "{0} status for {1}".format( + self.course.name, self.user.username + ) + ############################################################################### class ConcurrentUser(models.Model): diff --git a/yaksh/python_stdio_evaluator.py b/yaksh/python_stdio_evaluator.py index 64a2809..a1e8f72 100644 --- a/yaksh/python_stdio_evaluator.py +++ b/yaksh/python_stdio_evaluator.py @@ -46,6 +46,7 @@ class PythonStdIOEvaluator(BaseEvaluator): if self.file_paths: self.files = copy_files(self.file_paths) submitted = compile(self.user_answer, '<string>', mode='exec') + self.expected_output = self.expected_output.replace('\r', '') if self.expected_input: self.expected_input = self.expected_input.replace('\r', '') input_buffer = StringIO() @@ -55,7 +56,7 @@ class PythonStdIOEvaluator(BaseEvaluator): with redirect_stdout() as output_buffer: exec_scope = {} exec(submitted, exec_scope) - self.output_value = output_buffer.getvalue().rstrip("\n") + self.output_value = output_buffer.getvalue() return self.output_value def check_code(self): diff --git a/yaksh/r_code_evaluator.py b/yaksh/r_code_evaluator.py new file mode 100644 index 0000000..ca4c94a --- /dev/null +++ b/yaksh/r_code_evaluator.py @@ -0,0 +1,96 @@ +#!/usr/bin/env python +from __future__ import unicode_literals +import os +import subprocess +import re + +# Local imports +from .base_evaluator import BaseEvaluator +from .file_utils import copy_files, delete_files + + +class RCodeEvaluator(BaseEvaluator): + """Tests the R code obtained from Code Server""" + def __init__(self, metadata, test_case_data): + self.files = [] + self.submit_code_path = "" + self.test_code_path = "" + # Set metadata values + self.user_answer = metadata.get('user_answer') + self.file_paths = metadata.get('file_paths') + self.partial_grading = metadata.get('partial_grading') + + # Set test case data values + self.test_case = test_case_data.get('test_case') + self.weight = test_case_data.get('weight') + + def teardown(self): + # Delete the created file. + if os.path.exists(self.submit_code_path): + os.remove(self.submit_code_path) + if os.path.exists(self.test_code_path): + os.remove(self.test_code_path) + if self.files: + delete_files(self.files) + + def check_code(self): + self.submit_code_path = self.create_submit_code_file('function.r') + self.test_code_path = self.create_submit_code_file('main.r') + if self.file_paths: + self.files = copy_files(self.file_paths) + clean_ref_path = self.test_code_path + self.user_answer, terminate_commands = \ + self._remove_r_quit(self.user_answer.lstrip()) + + success = False + mark_fraction = 0.0 + self.write_to_submit_code_file(self.submit_code_path, self.user_answer) + self.write_to_submit_code_file(self.test_code_path, self.test_case) + # Throw message if there are commmands that terminates scilab + add_err = "" + if terminate_commands: + add_err = "Please do not use quit() in your\ + code.\n Otherwise your code will not be evaluated\ + correctly.\n" + + cmd = 'Rscript main.r' + ret = self._run_command(cmd, shell=True, stdout=subprocess.PIPE, + stderr=subprocess.PIPE + ) + proc, stdout, stderr = ret + + if stderr is '': + # Clean output + stdout = self._strip_output(stdout) + if proc.returncode == 31: + success, err = True, None + mark_fraction = 1.0 if self.partial_grading else 0.0 + else: + err = add_err + stdout + else: + err = add_err + stderr + + return success, err, mark_fraction + + def _remove_r_quit(self, string): + """ + Removes quit from the R code + """ + new_string = "" + terminate_commands = False + for line in string.splitlines(): + new_line = re.sub(r"quit.*$", "", line) + if line != new_line: + terminate_commands = True + new_string = new_string + '\n' + new_line + return new_string, terminate_commands + + def _strip_output(self, out): + """ + Cleans whitespace from the output + """ + strip_out = "Message" + for l in out.split('\n'): + if l.strip(): + strip_out = strip_out+"\n"+l.strip() + return strip_out + out diff --git a/yaksh/settings.py b/yaksh/settings.py index 9e9597d..7b42298 100644 --- a/yaksh/settings.py +++ b/yaksh/settings.py @@ -55,4 +55,8 @@ code_evaluators = { "standardtestcase": "yaksh.scilab_code_evaluator.ScilabCodeEvaluator", "hooktestcase": "yaksh.hook_evaluator.HookEvaluator" }, + "r": { + "standardtestcase": "yaksh.r_code_evaluator.RCodeEvaluator", + "hooktestcase": "yaksh.hook_evaluator.HookEvaluator" + }, } diff --git a/yaksh/static/yaksh/css/custom.css b/yaksh/static/yaksh/css/custom.css index 55d5d6d..63ee455 100644 --- a/yaksh/static/yaksh/css/custom.css +++ b/yaksh/static/yaksh/css/custom.css @@ -1,25 +1,3 @@ -.yakshfooter { - background-color: #142624; - padding-top: 1%; - padding-left: 10%; - padding-right: 10%; - padding-bottom: 1%; - color: white; - bottom: 0; - width: 100%; - position: absolute; - text-align: center; -} - -.yakshfooter .nav-pills>li>a, .yakshfooter .nav-pills .nav-link,.yakshnav .nav-pills>li>a { - color: white; -} - -.yakshfooter .nav-pills>li>a:hover, .yakshnav .nav-pills>li>a:hover { - color: black; - background-color: white; -} - body, .dropdown-menu { font-size: 1.25rem; } @@ -36,3 +14,86 @@ body, .dropdown-menu { .dropdown { display: flex; } + +.course-detail, #result-table { + table-layout: fixed; + width: 100%; +} + +.course-detail, #result-table > th, td { + word-wrap: break-word; +} + +#rendered_text{ + width: 550px; +} + +.navbar { + padding: 15px 10px; + background: #fff; + border: none; + border-radius: 0; + margin-bottom: 40px; + box-shadow: 1px 1px 3px rgba(0, 0, 0, 0.1); +} + +.navbar-btn { + box-shadow: none; + outline: none !important; + border: none; +} + +.line { + width: 100%; + height: 1px; + border-bottom: 1px dashed #ddd; + margin: 40px 0; +} + +/* --------------------------------------------------- + SIDEBAR STYLE +----------------------------------------------------- */ + +.wrapper { + display: flex; + width: 100%; + align-items: stretch; +} + +#sidebar { + min-width: 350px; + max-width: 350px; + background: #fff; + transition: all 0.3s; +} + +#sidebar.active { + margin-left: -350px; +} + +#sidebar .sidebar-header { + padding: 20px; + background: #158CBA; +} + +#sidebar ul.components { + padding: 20px 0; + border-bottom: 1px solid #fff; +} + +#sidebar ul li a { + padding: 10px; + font-size: 1.1em; + display: block; +} + +/* --------------------------------------------------- + CONTENT STYLE +----------------------------------------------------- */ + +#content { + width: 100%; + padding: 20px; + min-height: 100vh; + transition: all 0.3s; +} diff --git a/yaksh/static/yaksh/css/design_course.css b/yaksh/static/yaksh/css/design_course.css index d1bf4bd..a0dcd10 100644 --- a/yaksh/static/yaksh/css/design_course.css +++ b/yaksh/static/yaksh/css/design_course.css @@ -1,17 +1,6 @@ -body { - font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; - font-size: 13px; - font-weight: normal; - line-height: 18px; - color: #404040; -} - -#available-lesson-quiz .col-md-8 > div{ +#available-lesson-quiz .col-md-12 > div{ background: #f5f5f5; border: 1px solid #333333; overflow-y: scroll; - height: 300px; -} -#available-lesson-quiz .available-list > div{ - height: 300px; -} + height: 400px; +}
\ No newline at end of file diff --git a/yaksh/static/yaksh/css/question_paper_creation.css b/yaksh/static/yaksh/css/question_paper_creation.css index ff4bf32..bc8feeb 100644 --- a/yaksh/static/yaksh/css/question_paper_creation.css +++ b/yaksh/static/yaksh/css/question_paper_creation.css @@ -1,10 +1,3 @@ -body { - font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; - font-size: 13px; - font-weight: normal; - line-height: 18px; - color: #404040; -} .nav-tabs > li.active > a, .nav-tabs > li.active > a:hover, .nav-tabs > li.active > a:focus { background-color: #FFFFFF; border-color: #DDDDDD #DDDDDD rgba(0, 0, 0, 0); @@ -63,20 +56,20 @@ body { #fixed-questions .col-md-6 > div, #random-questions .col-md-6 > div{ background: #f5f5f5; - height: 200px; + height: 300px; border: 1px solid #333333; padding: 5px; } #fixed-available, #random-available { - height: 125px; - min-height: 125px; + height: 220px; + min-height: 200px; overflow-y: scroll; margin-bottom: 15px; } #fixed-added, #random-added { - height: 160px; + height: 220px; overflow-y: scroll; } #fixed-added hr, diff --git a/yaksh/static/yaksh/js/add_quiz.js b/yaksh/static/yaksh/js/add_quiz.js index 57993ef..dab5a3d 100644 --- a/yaksh/static/yaksh/js/add_quiz.js +++ b/yaksh/static/yaksh/js/add_quiz.js @@ -1,8 +1,8 @@ function test() { - document.getElementById('id_duration').setAttribute('class','mini-text'); - document.getElementById('id_pass_criteria').setAttribute('class','mini-text'); + document.getElementById('id_duration').setAttribute('class','mini-text form-control'); + document.getElementById('id_pass_criteria').setAttribute('class','mini-text form-control'); if (document.getElementById("id_description").value != "") { document.getElementById("submit").innerHTML = "Save"; diff --git a/yaksh/static/yaksh/js/course.js b/yaksh/static/yaksh/js/course.js index bd197a8..a4b5579 100644 --- a/yaksh/static/yaksh/js/course.js +++ b/yaksh/static/yaksh/js/course.js @@ -1,5 +1,5 @@ $(document).ready(function(){
-$(".checkall").change( function(){
+ $(".checkall").change( function(){
if($(this).prop("checked")) {
$("#enroll-all input:checkbox").each(function(index, element) {
$(this).prop('checked', true);
@@ -11,7 +11,7 @@ $(".checkall").change( function(){ });
}
});
-$(".enroll").change( function(){
+ $(".enroll").change( function(){
if($(this).prop("checked")) {
$("#enroll input:checkbox").each(function(index, element) {
$(this).prop('checked', true);
@@ -23,7 +23,7 @@ $(".enroll").change( function(){ });
}
});
-$(".reject").change( function(){
+ $(".reject").change( function(){
if($(this).prop("checked")) {
$("#reject input:checkbox").each(function(index, element) {
$(this).prop('checked', true);
@@ -36,68 +36,95 @@ $(".reject").change( function(){ }
});
-$(function() {
- tinymce.init({
- selector: 'textarea#email_body',
- max_height: 200,
- height: 200
+ $(".send_check").change( function(){
+ if($(this).prop("checked")) {
+ $("#sender_list input:checkbox").each(function(index, element) {
+ $(this).prop('checked', true);
+ });
+ }
+ else {
+ $("#sender_list input:checkbox").each(function(index, element) {
+ $(this).prop('checked', false);
+ });
+ }
});
-});
-$("#send_mail").click(function(){
- var subject = $("#subject").val();
- var body = tinymce.get("email_body").getContent();
- var status = false;
- var selected = [];
- $('#reject input:checked').each(function() {
- selected.push($(this).attr('value'));
+ $(function() {
+ tinymce.init({
+ selector: 'textarea#email_body',
+ max_height: 200,
+ height: 200
+ });
});
- if (subject == '' || body == ''){
- $("#error_msg").html("Please enter mail details");
- $("#dialog").dialog();
- }
- else if (selected.length == 0){
- $("#error_msg").html("Please select atleast one user");
- $("#dialog").dialog();
- }
- else {
- status = true;
- }
- return status;
-});
+ $("#send_mail").click(function(){
+ var subject = $("#subject").val();
+ var body = tinymce.get("email_body").getContent();
+ var status = false;
+ var selected = [];
+ $('#sender_list input:checked').each(function() {
+ selected.push($(this).attr('value'));
+ });
+ if (subject == '' || body == ''){
+ $("#error_msg").html("Please enter mail details");
+ $("#dialog").dialog();
+ }
+ else if (selected.length == 0){
+ $("#error_msg").html("Please select atleast one user");
+ $("#dialog").dialog();
+ }
+ else {
+ status = true;
+ }
+ return status;
+ });
-// Table sorter for course details
-$("table").tablesorter({});
-// Get user course completion status
-$('.user_data').click(function() {
- var data = $(this).data('item-id');
- course_id = data.split("+")[0];
- student_id = data.split("+")[1];
- var status_div = $("#show_status_"+course_id+"_"+student_id);
- if(!status_div.is(":visible")){
- var get_url = window.location.protocol + "//" + window.location.host +
- "/exam/manage/get_user_status/" + course_id + "/" + student_id;
- $.ajax({
- url: get_url,
- timeout: 8000,
- type: "GET",
- dataType: "json",
- contentType: 'application/json; charset=utf-8',
- success: function(data) {
+ // Table sorter for course details
+ $("table").tablesorter({});
+
+ // Get user course completion status
+ $('.user_data').click(function() {
+ var data = $(this).data('item-id');
+ course_id = data.split("+")[0];
+ student_id = data.split("+")[1];
+ var status_div = $("#show_status_"+course_id+"_"+student_id);
+ if(!status_div.is(":visible")){
+ var get_url = $("#url-"+student_id).attr("data-url");
+ $.ajax({
+ url: get_url,
+ timeout: 8000,
+ type: "GET",
+ dataType: "json",
+ contentType: 'application/json; charset=utf-8',
+ success: function(data) {
status_div.toggle();
status_div.html(data.user_data);
- },
- error: function(jqXHR, textStatus) {
- alert("Unable to get user data. Please Try again later.");
- }
- });
- } else {
- status_div.toggle();
- }
-});
+ },
+ error: function(jqXHR, textStatus) {
+ alert("Unable to get user data. Please Try again later.");
+ }
+ });
+ } else {
+ status_div.toggle();
+ }
+ });
-$('[data-toggle="tooltip"]').tooltip();
+ $('[data-toggle="tooltip"]').tooltip();
+ $('#upload').on('change',function(){
+ //get the file name
+ 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(', '));
+ });
+
+ $('[data-toggle="tab"]').tooltip({
+ trigger: 'hover',
+ placement: 'top',
+ animate: false,
+ container: 'body'
+ });
}); // end document ready
diff --git a/yaksh/static/yaksh/js/lesson.js b/yaksh/static/yaksh/js/lesson.js index 6f873b9..55d4846 100644 --- a/yaksh/static/yaksh/js/lesson.js +++ b/yaksh/static/yaksh/js/lesson.js @@ -44,9 +44,9 @@ $(document).ready(function(){ $("#embed").click(function() { $("#dialog_iframe").toggle(); $("#dialog_iframe").dialog({ - resizable: false, - height: '300', - width: '450' + resizable: true, + height: '450', + width: '640' }); }); @@ -75,4 +75,22 @@ $(document).ready(function(){ alert("Unable to copy. Press Ctrl+C or Cmd+C to copy") } }); + + $('#id_video_file').on('change',function(){ + //get the file name + 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(', ')); + }); + + $('#id_Lesson_files').on('change',function(){ + //get the file name + 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(', ')); + }); }); diff --git a/yaksh/templates/base.html b/yaksh/templates/base.html index 0cfe8a3..c70c265 100644 --- a/yaksh/templates/base.html +++ b/yaksh/templates/base.html @@ -49,7 +49,7 @@ <div id="ontop"> <div id="state"> - Checking...<img src="{{ URL_ROOT }}/static/yaksh/images/check_answer.gif"/> + Checking...<img src="{% static 'yaksh/images/check_answer.gif' %}"/> </div></div> diff --git a/yaksh/templates/exam.html b/yaksh/templates/exam.html index d439c64..a773076 100644 --- a/yaksh/templates/exam.html +++ b/yaksh/templates/exam.html @@ -1,83 +1,94 @@ {% extends "base.html" %} {% load custom_filters %} +{% load static %} + +{% block title %}{{ paper.question_paper.quiz.description }}{% endblock %} + {% block nav %} -<div class="container-fluid yakshnav"> - <nav class="navbar fixed-top navbar-expand-lg yakshheading yakshnav"> - <div class="container"> - <button class="navbar-toggler navbar-dark" type="button" data-toggle="collapse" data-target="#myNavbar" aria-controls="myNavbar" aria-expanded="false" aria-label="Toggle navigation"> - <span class="navbar-toggler-icon" style="color: white"></span> - </button> - <a class="navbar-brand"> - <img src="{{ URL_ROOT }}/static/yaksh/images/yaksh_banner.png" alt="YAKSH"> - </img> - </a> - <div class="collapse navbar-collapse col-md-6" id="myNavbar"> - <div class="nav nav-pills nav-fill ml-auto"> - <span class="time-div nav-item" id="time_left" ></span> - <form id="logout" action="{{URL_ROOT}}/exam/quit/{{ paper.attempt_number }}/{{module.id}}/{{ paper.question_paper.id }}/{{course.id}}/" method="post" class="ml-auto"> - {% csrf_token %} - <span class="nav-item"><button class="nav-link btn-danger" type="submit" name="quit"> - {% if paper.questions_unanswered.all %} - Quit {{ quiz_type }} - {% else %} - Finish {{ quiz_type }} - {% endif %} - <span class="fa fa-power-off"></span></button></span> - </form> - </div> - </div><!-- /.navbar --> - </div><!-- /.container --> - </nav><!-- /.navbar --> +<div class="container-fluid"> + <nav class="navbar navbar-expand-sm navbar-dark bg-primary fixed-top"> + <img src="{% static 'yaksh/images/yaksh_banner.png' %}" alt="YAKSH"> + <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarColor01" aria-controls="navbarColor01" aria-expanded="false" aria-label="Toggle navigation"> + <span class="navbar-toggler-icon"></span> + </button> + + <div class="collapse navbar-collapse" id="navbarColor01"> + <div class="row ml-auto"> + <div class="col-md-4"> + <span class="time-div nav-item" id="time_left"></span> + </div> + <div class="col-md-7"> + <form id="logout" action="{% url 'yaksh:quit_quiz' paper.attempt_number module.id paper.question_paper.id course.id %}" method="post" class="ml-auto"> + {% csrf_token %} + <span class="nav-item"><button class="btn btn-danger btn-lg" type="submit" name="quit"> + {% if paper.questions_unanswered.all %} + Quit {{quiz_type}} + {% else %} + Finish {{quiz_type}} + {% endif %} + <i class="fa fa-power-off"></i></button></span> + </form> + </div> + </div> + </div> + </nav> </div> {% endblock %} {% block content %} <div class="container-fluid"> <div class="row"> - <!-- Side bar --> - <div class="col-md-3 yakshlabel collapse" id="sidebar"> - <center> - <b class="yakshheading">{{course.name}}</b><br> - {{ paper.question_paper.quiz.description }}</h4> - <hr> - </center> - <div class="yakshwell"> - <p class="text-center">Question Navigator</p> - <div> - {% for qid in paper.get_all_ordered_questions %} - {%if paper.question_paper.quiz.allow_skip %} - {% if qid in paper.get_questions_unanswered %} - {% if qid.id == question.id %} - <a class="active btn btn-outline-success " href="#"data-toggle="tooltip" - title="{{ qid.description|striptags }}" - onclick="call_skip('{{ URL_ROOT }}/exam/{{ question.id }}/skip/{{ qid.id }}/{{ paper.attempt_number }}/{{ module.id }}/{{ paper.question_paper.id }}/{{course.id}}/')">{{ forloop.counter }}</a> - {% else %} - <a class=" btn btn-outline-success " href="#" data-toggle="tooltip" title="{{ qid.description|striptags }}" - onclick="call_skip('{{ URL_ROOT }}/exam/{{ question.id }}/skip/{{ qid.id }}/{{ paper.attempt_number }}/{{ module.id }}/{{ paper.question_paper.id }}/{{course.id}}/')">{{ forloop.counter }}</a> - {% endif %} - {% endif %} - {% if qid in paper.get_questions_answered %} - <a class="btn btn-outline-light question-nav-bg" href="#" data-toggle="tooltip" - onclick="call_skip('{{ URL_ROOT }}/exam/{{ question.id }}/skip/{{ qid.id }}/{{ paper.attempt_number }}/{{ module.id }}/{{ paper.question_paper.id }}/{{course.id}}/')" - title="{{ qid.description }}">{{ forloop.counter }}</a> - {% endif %} - {% else %} - {% if qid.id == question.id %} - <a class="active btn btn-outline-success" data-toggle="tooltip" title="{{ qid.description|striptags }}">{{ forloop.counter }}</a> - {% elif qid in paper.get_questions_answered %} - <a class="btn btn-outline-success question-nav-bg" href="#" data-toggle="tooltip" - onclick="call_skip('{{ URL_ROOT }}/exam/{{ question.id }}/skip/{{ qid.id }}/{{ paper.attempt_number }}/{{ module.id }}/{{ paper.question_paper.id }}/{{course.id}}/')" - title="{{ qid.description }}">{{ forloop.counter }}</a> - {% else %} - <a class="disabled btn btn-outline-success " data-toggle="tooltip" title="{{ qid.description|striptags }}">{{ forloop.counter }}</a> - {% endif %} - {% endif %} - {% endfor %} - </div> - <br> - <p class="text-center">Question(s) left: <b>{{ paper.questions_left }}</b></p> - </div> - <br> - <table class = "legend_table table-bordered table-sm"> + <!-- Side Component --> + <div class="col-md-3 bg-secondary" style="overflow-x: scroll;"> + <br> + <center> + <b>{{course.name}}</b><br> + {{ paper.question_paper.quiz.description }}</h4> + </center> + <hr> + <center><p><b><u>Question Navigator</b></u></p></center> + <br> + <div class="justify-content-center"> + {% for qid in paper.get_all_ordered_questions %} + {% if paper.question_paper.quiz.allow_skip %} + {% if qid in paper.get_questions_unanswered %} + {% if qid.id == question.id %} + <a class="active btn btn-outline-primary " href="#"data-toggle="tooltip" + title="{{ qid.description|striptags|truncatechars:100 }}" style="width: 50px" + onclick="call_skip('{{ URL_ROOT }}/exam/{{ question.id }}/skip/{{ qid.id }}/{{ paper.attempt_number }}/{{ module.id }}/{{ paper.question_paper.id }}/{{course.id}}/')">{{ forloop.counter }}</a> + {% else %} + <a class=" btn btn-outline-primary " href="#" data-toggle="tooltip" title="{{ qid.description|striptags|truncatechars:100 }}" style="width: 50px" + onclick="call_skip('{{ URL_ROOT }}/exam/{{ question.id }}/skip/{{ qid.id }}/{{ paper.attempt_number }}/{{ module.id }}/{{ paper.question_paper.id }}/{{course.id}}/')">{{ forloop.counter }}</a> + {% endif %} + {% endif %} + {% if qid in paper.get_questions_answered %} + <a class="btn btn-success" href="#" data-toggle="tooltip" style="width: 50px" + onclick="call_skip('{{ URL_ROOT }}/exam/{{ question.id }}/skip/{{ qid.id }}/{{ paper.attempt_number }}/{{ module.id }}/{{ paper.question_paper.id }}/{{course.id}}/')" + title="{{ qid.description|striptags|truncatechars:100 }}">{{ forloop.counter }}</a> + {% endif %} + {% else %} + {% if qid.id == question.id %} + <a class="active btn btn-outline-primary" data-toggle="tooltip" title="{{ qid.description|striptags|truncatechars:100 }}" style="width: 50px">{{ forloop.counter }}</a> + {% elif qid in paper.get_questions_answered %} + <a class="btn btn-success" href="#" data-toggle="tooltip" style="width: 50px" + onclick="call_skip('{{ URL_ROOT }}/exam/{{ question.id }}/skip/{{ qid.id }}/{{ paper.attempt_number }}/{{ module.id }}/{{ paper.question_paper.id }}/{{course.id}}/')" + title="{{ qid.description|striptags|truncatechars:100 }}">{{ forloop.counter }}</a> + {% else %} + <a class="btn btn-outline-primary" style="width: 50px" data-toggle="tooltip" title="{{ qid.description|striptags|truncatechars:100 }}">{{ forloop.counter }}</a> + {% endif %} + {% endif %} + {% endfor %} + </div> + <br> + <p><span class="btn btn-success"></span> Attempted question(s)</p> + <p><span class="btn btn-primary"></span> Current question</p> + <p><span class="btn btn-outline-primary"></span> Unattempted question(s)</p> + <br> + <div> + <p class="text-center">Question(s) left: <b>{{ paper.questions_left }}</b></p> + </div> + <br> + <div> + <table class="table table-bordered table-responsive-sm"> <thead> <tr> <th>Category</th> @@ -97,16 +108,15 @@ {% endfor %} </tbody> </table> - </div> <!--end of sidebar --> - <a href="#sidebar" data-toggle="collapse" id="sidebaricon"><i class="fa fa-navicon fa-lg"></i></a> - - <main class="col" id="sidebarbody"> - <div class="container-fluid yakshwell"> - - {% block main %} - {% endblock %} - </div> - </main> + <br> + </div> + </div> + <!-- Main Component --> + <div class="col-md-9"> + <br> + {% block main %} + {% endblock %} + </div> </div> </div> diff --git a/yaksh/templates/manage.html b/yaksh/templates/manage.html index 9557582..8e74494 100644 --- a/yaksh/templates/manage.html +++ b/yaksh/templates/manage.html @@ -46,38 +46,35 @@ </div> </nav> +<!-- iframe div for video embed --> +<div id="iframe_div" style="display: none;"> + <iframe class="embed-responsive-item" id="video_frame" width="640" height="480" allowfullscreen> + </iframe> +</div> +<!-- end iframe div --> - - <!-- iframe div for video embed --> - <div id="iframe_div" style="display: none;"> - <div class="embed-responsive embed-responsive-16by9" style=" position: relative;"> - <iframe class="embed-responsive-item" id="video_frame" width="800" height="500" allowfullscreen> - </iframe> - <div style="width: 80px; height: 80px; position: absolute; opacity: 0; right: 0px; top: 0px;"> - </div> - </div> - </div> - <!-- end iframe div --> - - <!-- Dialog to video embed --> - <div id="dialog_iframe" title="Embed Video URL" style="display: none;"> - <label>Enter embed url:</label> - <input id="url" name="url" type="text" required="true"> - <input type="button" id="submit_info" name="submit_info" class="btn" value="Submit" /> - <div id="error_div" style="display: none;"> - <b> Please enter URL</b> - </div> - <div id="copy_div"> - <br> - <label>Paste HTML to embed in website:</label> - <textarea rows="5" cols="35" id="html_text"></textarea> - <br> - <a class="btn btn-default" id="copy" data-toggle="tooltip" title="Copy to Clipboard"> - <i class="fa fa-clipboard" aria-hidden="true"></i> - </a> - </div> +<!-- Dialog to video embed --> +<div id="dialog_iframe" title="Embed Video URL" style="display: none;"> + <div class="input-group mb-3"> + <input id="url" name="url" type="text" required="true" class="form-control" placeholder="Enter video link"> + <div class="input-group-append"> + <input type="button" id="submit_info" name="submit_info" class="btn btn-primary" value="Submit" /> </div> - <!-- end dialog --> + </div> + <div id="error_div" style="display: none;"> + <b> Please enter URL</b> + </div> + <div id="copy_div"> + <br> + <label>Paste HTML to embed in website:</label> + <textarea id="html_text" class="form-control" rows="5" cols="100"></textarea> + <br> + <a class="btn btn-secondary" id="copy" data-toggle="tooltip" title="Copy to Clipboard"> + <i class="fa fa-clipboard" aria-hidden="true"></i> + </a> + </div> +</div> +<!-- end dialog --> {% endblock %} {% block content %} diff --git a/yaksh/templates/user.html b/yaksh/templates/user.html index 4ded0a3..4e3974b 100644 --- a/yaksh/templates/user.html +++ b/yaksh/templates/user.html @@ -1,39 +1,46 @@ {% extends "base.html" %} - +{% load static %} {% block nav %} -<div class="container-fluid yakshnav"> -<nav class="navbar fixed-top navbar-expand-lg yakshheading yakshnav"> - <div class="container"> - <button class="navbar-toggler navbar-dark" type="button" data-toggle="collapse" data-target="#myNavbar" aria-controls="myNavbar" aria-expanded="false" aria-label="Toggle navigation"> - <span class="navbar-toggler-icon" style="color: white"></span> - </button> - <a class="navbar-brand" href="{{ URL_ROOT }}/exam/"> - <img src="{{ URL_ROOT }}/static/yaksh/images/yaksh_banner.png" alt="YAKSH" style="margin-top: -3px; margin-left:-15px"> - </img> - </a> - <div class="collapse navbar-collapse" id="myNavbar"> - <ul class="nav nav-pills ml-auto"> - <li class="nav-item"><a class="nav-link" href="{{ URL_ROOT }}/exam/"><i class="fa fa-home" style="size: 18px"></i></a></li> - <li class="nav-item dropdown"> - <a class="dropdown-toggle nav-link" id="user_dropdown" data-toggle="dropdown" href="#"> {{user.get_full_name|title}}</a> - <div class="dropdown-menu"> - <a class="dropdown-item" href="{{ URL_ROOT }}/exam/viewprofile/"><i class="fa fa-user"></i> My Profile</a> - <div class="dropdown-divider"></div> - {% if user.profile.is_moderator %} - <a class="dropdown-item" href="{{URL_ROOT}}/exam/toggle_moderator/"><i class="fa fa-exchange"></i> - Switch To Moderator - </a> - <div class="dropdown-divider"></div> - {% endif %} - <a class="dropdown-item" href="{{ URL_ROOT }}/exam/reset/changepassword/"><i class="fa fa-key"></i> Change Password</a> - <div class="dropdown-divider"></div> - <a id="user_logout" class="dropdown-item" href="{{URL_ROOT}}/exam/logout/"><i class="fa fa-sign-out"></i> Logout</a> - </div> - </li> +<div class="container-fluid"> + <nav class="navbar navbar-expand-sm navbar-dark bg-primary fixed-top"> + <a class="navbar-brand" href="{% url 'yaksh:index' %}"> + <img src="{% static 'yaksh/images/yaksh_banner.png' %}" alt="YAKSH"> + </a> + <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarColor01" aria-controls="navbarColor01" aria-expanded="false" aria-label="Toggle navigation"> + <span class="navbar-toggler-icon"></span> + </button> + + <div class="collapse navbar-collapse" id="navbarColor01"> + <ul class="navbar-nav mr-auto"> + <li class="nav-item"><a class="nav-link" href="{% url 'yaksh:index' %}"><i class="fa fa-home" style="size: 18px"></i> Home</a></li> </ul> - </div> - </div> -</nav> + <ul class="navbar-nav ml-auto"> + <li class="nav-item dropdown my-lg-0" style="font-size: 1.2rem"> + <a class="dropdown-toggle nav-link" id="user_dropdown" data-toggle="dropdown" href="#">{{user.get_full_name|title}} + </a> + <div class="dropdown-menu dropdown-menu-right"> + <a class="dropdown-item" href="{% url 'yaksh:edit_profile' %}"> + <i class="fa fa-user"></i> My Profile + </a> + <div class="dropdown-divider"></div> + {% if user.profile.is_moderator %} + <a class="dropdown-item" href="{% url 'yaksh:toggle_moderator' %}"><i class="fa fa-exchange"></i> + Switch To Moderator + </a> + <div class="dropdown-divider"></div> + {% endif %} + <a class="dropdown-item" href="{% url 'password_change' %}"> + <i class="fa fa-key"></i> Change Password + </a> + <div class="dropdown-divider"></div> + <a class="dropdown-item" id="user_logout" href="{% url 'yaksh:logout' %}"> + <i class="fa fa-sign-out"></i> Logout + </a> + </div> + </li> + </ul> + </div> + </nav> </div> {% endblock %} @@ -44,25 +51,3 @@ {% endblock %} {% endblock %} {% endblock %} - -{% block footer %} - <!--footer--> - <footer class="container-fluid yakshfooter text-center "> - <div class="row justify-content-center"> - <div class="col-sm-5 "> - {% if user %} - {% block info %} - <b>{{user.get_full_name|title}}</b> with Roll no. <b>{{user.profile.roll_number}}</b> is logged in as <b>{{user.username}}</b> - {% endblock %} - {% endif %} - </div> - <div class="col-sm-2"> - | - </div> - <div class="col-sm-4 text-left"> - <b>Any Queries?</b> Email : info@fossee.in - </div> - </div> - </footer> - <!--footer end--> -{% endblock %}
\ No newline at end of file diff --git a/yaksh/templates/yaksh/add_course.html b/yaksh/templates/yaksh/add_course.html index 6276425..72403ce 100644 --- a/yaksh/templates/yaksh/add_course.html +++ b/yaksh/templates/yaksh/add_course.html @@ -22,11 +22,6 @@ </a> </li> <li class="nav-item"> - <a class="nav-link" href="{% url 'yaksh:allotted_courses' %}"> - Allotted Courses - </a> - </li> - <li class="nav-item"> <a class="nav-link active" href="{% url 'yaksh:add_course' %}"> Add New Course </a> @@ -67,7 +62,7 @@ <center> <button class="btn btn-success btn-lg" type="submit" id="submit" name="course"> - Save + <i class="fa fa-save"></i> Save </button> <a class="btn btn-danger btn-lg" name="button" href="{% url 'yaksh:courses' %}"> Cancel diff --git a/yaksh/templates/yaksh/add_exercise.html b/yaksh/templates/yaksh/add_exercise.html index 21ef6cc..d3d9068 100644 --- a/yaksh/templates/yaksh/add_exercise.html +++ b/yaksh/templates/yaksh/add_exercise.html @@ -1,54 +1,101 @@ {% extends "manage.html" %} +{% load static %} - +{% block title %}Add Exercise{% endblock %} {% block subtitle %}Add Exercise{% endblock %} {% block css %} {% endblock %} {% block script %} -<script src="{{ URL_ROOT }}/static/yaksh/js/jquery-3.3.1.min.js"></script> -<script src="{{ URL_ROOT }}/static/yaksh/js/add_quiz.js"></script> +<script src="{% static 'yaksh/js/jquery-3.3.1.min.js' %}"></script> +<script src="{% static 'yaksh/js/add_quiz.js' %}"></script> {% endblock %} {% block onload %} window.onload="javascript:test();" {% endblock %} {% block content %} -<div class="yakshwell container"> -<form name=frm id=frm action="" method="post" > - {% csrf_token %} - <center> - <table class="span1 table table-responsive-sm"> - {{ form.as_table }} - </table> - <br/><br/> - </center> - <center><button class="btn btn-success" type="submit" id="submit" name="save_exercise"> Save - </button> - - <button class="btn btn-danger" type="button" name="button" onClick='location.replace("{{URL_ROOT}}/exam/manage/courses/");'>Cancel</button> </center> -</form> -{% if exercise and course_id %} - {% if exercise.questionpaper_set.get.id %} - <center> - <h4>You can check the quiz by attempting it in the following modes:</h4> - <a href="{{URL_ROOT}}/exam/manage/designquestionpaper/{{ exercise.id }}/{{exercise.questionpaper_set.get.id}}/{{course_id}}" class="btn btn-primary">View Question Paper</a> - <button class="btn" type="button" name="button" onClick='usermode("{{URL_ROOT}}/exam/manage/usermode/{{exercise.id}}/{{course_id}}/");'>User Mode</button> +<div class="container"> + {% 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 %} + {% if course_id %} + <a class="btn btn-primary" href="{% url 'yaksh:get_course_modules' course_id %}"> + <i class="fa fa-arrow-left"></i> + Back + </a> + {% else %} + <a class="btn btn-primary" href="{% url 'yaksh:show_all_quizzes' %}"> + <i class="fa fa-arrow-left"></i> + Back + </a> + {% endif %} + <br><br> + <form name=frm id=frm action="" method="post" > + {% csrf_token %} + <center> + <table class="span1 table table-responsive-sm"> + {{ form.as_table }} + </table> + <br/><br/> + </center> + <center> + <button class="btn btn-success btn-lg" type="submit" id="submit" name="save_exercise"> + <i class="fa fa-save"></i> Save + </button> + </center> + </form> + <br> + {% if exercise and course_id %} + {% if exercise.questionpaper_set.get.id %} + <center> + <a href="{% url 'yaksh:designquestionpaper' exercise.id exercise.questionpaper_set.get.id course_id %}" class="btn btn-primary"> + <i class="fa fa-edit"></i> Edit Question Paper + </a> + <a href="{% url 'yaksh:preview_questionpaper' exercise.questionpaper_set.get.id %}" class="btn btn-info" target="_blank"> + <i class="fa fa-eye"></i> Preview Question Paper + </a> + <br> + <br> + <h4>You can check the quiz by attempting it in the following modes:</h4> + <a class="btn btn-outline-info" name="button" href="{% url 'yaksh:test_quiz' 'usermode' exercise.id course_id %}" target="blank"> + User Mode + </a> - <button class="btn" type="button" name="button" onClick='location.replace("{{URL_ROOT}}/exam/manage/godmode/{{exercise.id}}/{{course_id}}/");'> - God Mode</button> - <a data-toggle="collapse" data-target="#help"> - <span class="glyphicon glyphicon-info-sign">Help</span></a> - <div id="help" class="collapse"> - <br/> - <ul> - <li><b>User Mode:</b> Attempt quiz the way normal users will attempt i.e. - - <ul> - <li><i>Quiz will have the same duration as that of the original quiz.</li> - <li>Quiz won't start if the course is inactive or the quiz time has expired.</li> - <li>You will be notified about quiz prerequisites.(You can still attempt the quiz though)</i></li> - </ul> - </p> - <li> <b>God Mode:</b> Attempt quiz without any time or eligibilty constraints.</p> - </div> + <a class="btn btn-outline-info" name="button" href="{% url 'yaksh:test_quiz' 'godmode' exercise.id course_id %}" target="blank"> + God Mode + </a> + <a data-toggle="modal" data-target="#help"> + <span class="text-info"><i class="fa fa-info-circle"></i> Help</span></a> + </center> + {% endif %} {% endif %} -{% endif %} +</div> +<div class="modal" id="help"> + <div class="modal-dialog" role="document"> + <div class="modal-content"> + <div class="modal-header"> + <h5 class="modal-title">Quiz Test Modes</h5> + <button type="button" class="close" data-dismiss="modal" aria-label="Close"> + <span aria-hidden="true"><i class="fa fa-close"></i></span> + </button> + </div> + <div class="modal-body"> + <p> + <b>User Mode:</b> Attempt quiz the way normal users will attempt i.e. - + <ul class="list-group list-group-flush"> + <li class="list-group-item">Quiz will have the same duration as that of the original quiz.</li> + <li class="list-group-item">Quiz won't start if the course is inactive or the quiz time has expired.</li> + <li class="list-group-item">You will be notified about quiz prerequisites.(You can still attempt the quiz though)</li> + </ul> + <b>God Mode:</b> Attempt quiz without any time or eligibilty constraints. + </p> + </div> + </div> + </div> </div> {% endblock %} diff --git a/yaksh/templates/yaksh/add_lesson.html b/yaksh/templates/yaksh/add_lesson.html index 87fb8d0..99fc31a 100644 --- a/yaksh/templates/yaksh/add_lesson.html +++ b/yaksh/templates/yaksh/add_lesson.html @@ -1,85 +1,161 @@ {% extends "manage.html" %} {% load custom_filters %} +{% load static %} {% block title %}Create/Edit Lesson{% endblock %} {% block script %} -<script src="{{ URL_ROOT }}/static/yaksh/js/lesson.js"></script> -<script src="{{ URL_ROOT }}/static/yaksh/js/jquery-ui-1.12.1.js"></script> +<script type="text/javascript" src="{% static 'yaksh/js/lesson.js' %}"> +</script> +<script type="text/javascript" src="{% static 'yaksh/js/jquery-ui.js' %}"> +</script> {% endblock %} {% block css %} -<link rel="stylesheet" href="{{URL_ROOT}}/static/yaksh/css/jquery-ui/jquery-ui-1.12.1.css"> -<link rel="stylesheet" href="{{URL_ROOT}}/static/yaksh/css/lesson.css"> +<link rel="stylesheet" href="{% static 'yaksh/css/lesson.css' %}" type="text/css" /> +<link rel="stylesheet" href="{% static 'yaksh/css/jquery-ui/jquery-ui.css' %}" type="text/css" /> {% endblock %} {% block content %} -<div class="yakshwell container"> +<div class="container"> {% if error %} <div class="alert alert-danger"> {{error}} </div> {% endif %} -<form name=frm id=frm action="" method="post" enctype="multipart/form-data"> - {% csrf_token %} - <center> - <table class="table table-bordered table-responsive-sm"> - {{ lesson_form.as_table }} - {{ lesson_file_form.as_table }} - </table> - </center> - <br><br> - {% if lesson_files %} - <center> - <div class="alert alert-success col-md-8 animated flash"> - <h4>Files added to this lesson</h4> - </div> - </center> - {% for f in lesson_files %} - <li class="list-group-item"> - <h4> - <input type="checkbox" name="delete_files" value="{{f.id}}"> - </input> - <a href="{{f.file.url}}">{{ f.file.name|file_title }}</a> - </h4> - </li> - {% endfor %} - {% else %} - - <center> - <div class="alert alert-warning col-md-8 animated flash"> - <h4 class="alert-warning">No Files added to this lesson</h4> - </div> - </center> - {% endif %} - <br><br> - <center> - <button class="btn btn-success" type="submit" id="submit" name="Save"> Save - </button> - {% if lesson_files %} - <button class="btn btn-danger" type="submit" id="submit" name="Delete"> Delete Files - </button> - {% endif %} - {% if course_id %} - <button class="btn btn-danger" type="button" name="button" onClick='location.replace("{{URL_ROOT}}/exam/manage/courses/");'>Cancel</button> - {% else %} - <button class="btn btn-danger" type="button" name="button" onClick='location.replace("{{URL_ROOT}}/exam/manage/courses/all_lessons/");'>Cancel</button> - {% endif %} - </form> - <button class="btn btn-outline-primary" type="button" name="button" id="preview">Preview Lesson Description - </button> - <button class="btn btn-outline-primary" type="button" name="button" id="embed"> - Embed Video link - </button> - </center> - <hr> - <div class="card" id="preview_text_div" style="display: none;"> - <div class="card-heading"> - <center> - <h3>Description Preview</h3> - </center> - </div> - <div class="card-body" id="description_body"> +<div class="container"> + <div class="row justify-content-center form-group"> + <div class="col-md-9 col-md-offset-4"> + {% if course_id %} + <a class="btn btn-primary" href="{% url 'yaksh:get_course_modules' course_id %}"> + <i class="fa fa-arrow-left"></i> + Back + </a> + {% else %} + <a class="btn btn-primary" href="{% url 'yaksh:show_all_lessons' %}"> + <i class="fa fa-arrow-left"></i> + Back + </a> + {% endif %} + <br> + {% if messages %} + <br> + {% 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 %} + <br> + <form name=frm id=frm action="" method="post" enctype="multipart/form-data"> + <fieldset> + {% csrf_token %} + {% if lesson_form.errors %} + {% for field in lesson_form %} + {% 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 lesson_form.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 %} + {{lesson_form.name}} + <br> + {{lesson_form.description}} + <br> + Active: {{lesson_form.active}} + <br><br> + Video File: + <span class="badge badge-info"> + {{lesson_form.video_file.help_text}} + </span> + <div class="input-group mb-3"> + <div class="custom-file"> + {{lesson_form.video_file}} + <label class="custom-file-label" for="id_video_file"> + Choose file + </label> + </div> + </div> + <br> + Lesson Files: + <div class="input-group mb-3"> + <div class="custom-file"> + {{lesson_file_form.Lesson_files}} + <label class="custom-file-label" for="id_video_file"> + Choose file + </label> + </div> + </div> + <br> + {% if lesson_files %} + <center> + <div class="alert alert-info"> + <h4>Files added to this lesson</h4> + </div> + </center> + {% for f in lesson_files %} + <li class="list-group-item"> + <h4> + <input type="checkbox" name="delete_files" value="{{f.id}}"> + </input> + <a href="{{f.file.url}}">{{ f.file.name|file_title }}</a> + </h4> + </li> + {% endfor %} + <br> + {% else %} + <center> + <div class="alert alert-warning"> + <h4 class="alert-warning">No Files added to this lesson</h4> + </div> + </center> + {% endif %} + <center> + <button class="btn btn-success btn-lg" type="submit" id="submit" name="Save"> + <i class="fa fa-save"></i> + Save + </button> + {% if lesson_files %} + <button class="btn btn-danger btn-lg" type="submit" id="submit" name="Delete"> <i class="fa fa-trash"></i> Delete Files + </button> + {% endif %} + <button class="btn btn-outline-primary btn-lg" type="button" name="button" id="preview"> + <i class="fa fa-eye"></i> + Preview Description + </button> + <button class="btn btn-outline-primary btn-lg" type="button" name="button" id="embed"> + <i class="fa fa-angle-left"></i> <i class="fa fa-angle-right"></i> + Embed Video link + </button> + </center> + </form> + <hr> + <div class="card" id="preview_text_div" style="display: none;"> + <div class="card-heading"> + <center> + <h3>Description Preview</h3> + </center> + </div> + <div class="card-body" id="description_body"> + </div> + </div> + </fieldset> + </form> </div> </div> </div> diff --git a/yaksh/templates/yaksh/add_module.html b/yaksh/templates/yaksh/add_module.html index 6b2214b..edbfaa2 100644 --- a/yaksh/templates/yaksh/add_module.html +++ b/yaksh/templates/yaksh/add_module.html @@ -1,70 +1,125 @@ {% extends "manage.html" %} +{% load static %} {% block title %}Create/Edit Learning Module{% endblock %} -{% block pagetitle %}<h4>Design Learning Module</h4>{% endblock %} - {% block script %} -<script src="{{ URL_ROOT }}/static/yaksh/js/jquery-3.3.1.min.js"></script> -<script src="{{ URL_ROOT }}/static/yaksh/js/design_course.js"></script> -<script src="{{ URL_ROOT }}/static/yaksh/js/lesson.js"></script> -<script src="{{ URL_ROOT }}/static/yaksh/js/jquery-ui.js"></script> +<script type="text/javascript" src="{% static 'yaksh/js/jquery-3.3.1.min.js' %}"> +</script> +<script type="text/javascript" src="{% static 'yaksh/js/design_course.js' %}"> +</script> +<script type="text/javascript" src="{% static 'yaksh/js/lesson.js' %}"> +</script> +<script type="text/javascript" src="{% static 'yaksh/js/jquery-ui.js' %}"> +</script> {% endblock %} {% block css %} -<link rel="stylesheet" media="all" type="text/css" href="{{ URL_ROOT }}/static/yaksh/css/design_course.css" /> -<link rel="stylesheet" href="{{ URL_ROOT }}/static/yaksh/css/jquery-ui/jquery-ui.css"> +<link rel="stylesheet" href="{% static 'yaksh/css/design_course.css' %}" type="text/css" /> +<link rel="stylesheet" href="{% static 'yaksh/css/jquery-ui/jquery-ui.css' %}" type="text/css" /> {% endblock %} {% block content %} -<div class="yaskhwell container"> +<div class="container"> +{% 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 %} {% if course_id %} - <a href="{{URL_ROOT}}/exam/manage/courses/" class="btn btn-primary"> - Back to Courses</a> + <a class="btn btn-primary" href="{% url 'yaksh:get_course_modules' course_id %}"> + <i class="fa fa-arrow-left"></i> + Back + </a> {% else %} - <a href="{{URL_ROOT}}/exam/manage/courses/all_learning_module" class="btn btn-primary"> - Back to Learning Modules</a> + <a class="btn btn-primary" href="{% url 'yaksh:show_all_modules' %}"> + <i class="fa fa-arrow-left"></i> + Back + </a> {% endif %} +</div> +<br> {% if status == "add" %} -<form name=frm id=frm action="" method="post"> - {% csrf_token %} - <br> - <center> - <table class="table table-bordered table-responsive-sm"> - {{ module_form.as_table }} - </table> - </center> - <br><br> - <center> - <button class="btn btn-success" type="submit" id="submit" name="Save"> - Save - </button> - <button class="btn btn-outline-primary" type="button" name="button" id="preview"> - Preview Module Description - </button> - <button class="btn btn-outline-primary" type="button" name="button" id="embed"> - Embed Video link - </button> - </center> -</form> -<hr> -<div class="card" id="preview_text_div" style="display: none;"> - <div class="card-heading"> - <center> - <h3>Description Preview</h3> - </center> - </div> - <div class="card-body" id="description_body"> +<div class="container"> + <div class="row justify-content-center form-group"> + <div class="col-md-9 col-md-offset-4"> + <form name=frm id=frm action="" method="post"> + <fieldset> + {% csrf_token %} + {% if module_form.errors %} + {% for field in module_form %} + {% 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 form.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 %} + {{module_form.name}} + <br> + {{module_form.description}} + <br> + Active: {{module_form.active}} + <br> + <center> + <button class="btn btn-success btn-lg" type="submit" id="submit" name="Save"> + <i class="fa fa-save"></i> + Save + </button> + <button class="btn btn-outline-primary btn-lg" type="button" name="button" id="preview"> + <i class="fa fa-eye"></i> + Preview Description + </button> + <button class="btn btn-outline-primary btn-lg" type="button" name="button" id="embed"> + <i class="fa fa-angle-left"></i> <i class="fa fa-angle-right"></i> + Embed Video link + </button> + </center> + </form> + <hr> + <div class="card" id="preview_text_div" style="display: none;"> + <div class="card-heading"> + <center> + <h3>Description Preview</h3> + </center> + </div> + <div class="card-body" id="description_body"> + </div> + </div> + </fieldset> + </form> + </div> </div> </div> {% endif %} <!-- Add learning Units --> {% if status == "design" %} +<div class="container"> <center><h3><u>Add/Edit Learning Units</h3></u></center> -<form action="{{URL_ROOT}}/exam/manage/courses/designmodule/{{module_id}}/" method="POST" id="design_course_form"> +{% if course_id %} +<form action="{% url 'yaksh:design_module' module_id course_id %}" method="POST" id="design_course_form"> +{% else %} +<form action="{% url 'yaksh:design_module' module_id %}" method="POST" id="design_course_form"> +{% endif %} {% csrf_token %} <div class="tab-pane active" id="available-lesson-quiz"> <div class="row"> - <div class="col-md-8 available-list col-md-offset-2"> + <div class="col-md-12 available-list"> <div id="fixed-available-wrapper"> <p><u><b>Available Lessons and quizzes: (Add Lessons and Quizzes)</b></u></p> <div id="fixed-available"> @@ -87,13 +142,13 @@ </div> <br> <center> - <button class="btn btn-success" type="submit" id="submit" name="Add"> - Add to Module + <button class="btn btn-success" type="submit" id="submit" name="Add"><i class="fa fa-plus-square"></i> + Add to Module </button> </center> <br><br> </div> - <div class="col-md-8 col-md-offset-2"> + <div class="col-md-12 col-md-offset-2"> <div id="fixed-added-wrapper"> <p><u><b>Chosen Lessons and quizzes:</b></u> </p> @@ -152,8 +207,8 @@ </div> <br> <center> - <button id="Remove" name="Remove" class="btn btn-danger" type="submit">Remove from Module</button> - <button id="Change" name="Change" class="btn btn-info" type="submit"> Change Order</button> + <button id="Remove" name="Remove" class="btn btn-danger" type="submit"> <i class="fa fa-minus-square"></i> Remove from Module</button> + <button id="Change" name="Change" class="btn btn-info" type="submit"><i class="fa fa-reorder"></i> Change Order</button> <button id="Change" name="Change_prerequisite" class="btn btn-primary" type="submit"> Change Prerequisite</button> </center> </div> diff --git a/yaksh/templates/yaksh/add_question.html b/yaksh/templates/yaksh/add_question.html index 665e86a..a400e35 100644 --- a/yaksh/templates/yaksh/add_question.html +++ b/yaksh/templates/yaksh/add_question.html @@ -62,11 +62,13 @@ <div class="form-group"> {{ formset.management_form }} - {% for form in formset %} - <div class="link-formset well"> - {{ form.as_p }} - </div> - {% endfor %} + {% for form in formset %} + <div class="link-formset well"> + {% autoescape off %} + {{ form.as_p }} + {% endautoescape %} + </div> + {% endfor %} </div> {% endfor %} diff --git a/yaksh/templates/yaksh/add_quiz.html b/yaksh/templates/yaksh/add_quiz.html index 48d64ce..57b4d77 100644 --- a/yaksh/templates/yaksh/add_quiz.html +++ b/yaksh/templates/yaksh/add_quiz.html @@ -1,73 +1,109 @@ {% extends "manage.html" %} +{% load static %} +{% block title %}Add/Edit Quiz{% endblock %} -{% block subtitle %}Add Quiz{% endblock %} +{% block subtitle %}Add/Edit Quiz{% endblock %} {% block css %} -<link rel="stylesheet" href="{{ URL_ROOT }}/static/yaksh/css/jquery.datetimepicker.css" type="text/css" /> + +<link rel="stylesheet" href="{% static 'yaksh/css/jquery.datetimepicker.css' %}" type="text/css" /> {% endblock %} {% block script %} -<script src="{{ URL_ROOT }}/static/yaksh/js/jquery-3.3.1.min.js"></script> -<script src="{{ URL_ROOT }}/static/yaksh/js/add_quiz.js"></script> -<script src="{{ URL_ROOT }}/static/yaksh/js/jquery.datetimepicker.full.min.js"></script> + +<script src="{% static 'yaksh/js/jquery-3.3.1.min.js' %}"></script> +<script src="{% static 'yaksh/js/add_quiz.js' %}"></script> +<script src="{% static 'yaksh/js/jquery.datetimepicker.full.min.js' %}"></script> + {% endblock %} {% block onload %} onload="javascript:test();" {% endblock %} {% block content %} -<div class="yakshwell container"> -<form name=frm id=frm action="" method="post" > - {% csrf_token %} - <center> - <table class="span1 table table-responsive-sm"> - {{ form.as_table }} - </table> - <script type="text/javascript"> - $("#id_start_date_time").datetimepicker({format: 'Y-m-d H:i:s'}); - $("#id_end_date_time").datetimepicker({format: 'Y-m-d H:i:s'}); - </script> - <br/><br/> - </center> - - <center><button class="btn btn-success" type="submit" id="submit" name="questionpaper"> Save - </button> - - <button class="btn btn-danger" type="button" name="button" onClick='location.replace("{{URL_ROOT}}/exam/manage/courses/");'>Cancel</button> </center> - -</form> -<br> -{% if quiz and course_id %} - {% if quiz.questionpaper_set.get.id %} - <center> - <a href="{{URL_ROOT}}/exam/manage/designquestionpaper/{{ quiz.id }}/{{quiz.questionpaper_set.get.id}}/{{course_id}}" class="btn btn-primary">Edit Question Paper</a> - <a href="{{URL_ROOT}}/exam/manage/preview_questionpaper/{{quiz.questionpaper_set.get.id}}" class="btn btn-primary" target="_blank"> - Preview Question Paper +<div class="container"> + {% 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 %} + {% if course_id %} + <a class="btn btn-primary" href="{% url 'yaksh:get_course_modules' course_id %}"> + <i class="fa fa-arrow-left"></i> + Back + </a> + {% else %} + <a class="btn btn-primary" href="{% url 'yaksh:show_all_quizzes' %}"> + <i class="fa fa-arrow-left"></i> + Back </a> - <br> - <br> - <h4>You can check the quiz by attempting it in the following modes:</h4> - <button class="btn btn-outline-info" type="button" name="button" onClick='usermode("{{URL_ROOT}}/exam/manage/usermode/{{quiz.id}}/{{course_id}}/");'>User Mode</button> + {% endif %} + <br><br> + <form name=frm id=frm action="" method="post" > + {% csrf_token %} + <center> + <table class="table"> + {{ form.as_table }} + </table> + <script type="text/javascript"> + $("#id_start_date_time").datetimepicker({format: 'Y-m-d H:i:s'}); + $("#id_end_date_time").datetimepicker({format: 'Y-m-d H:i:s'}); + </script> + <br/> + <button class="btn btn-success btn-lg" id="submit" name="questionpaper"> + <i class="fa fa-save"> Save</i> + </button> + </center> + </form> + <br> + {% if quiz and course_id %} + {% if quiz.questionpaper_set.get.id %} + <center> + <a href="{% url 'yaksh:designquestionpaper' quiz.id quiz.questionpaper_set.get.id course_id %}" class="btn btn-primary"> + <i class="fa fa-edit"></i> Edit Question Paper + </a> + <a href="{% url 'yaksh:preview_questionpaper' quiz.questionpaper_set.get.id %}" class="btn btn-info" target="_blank"> + <i class="fa fa-eye"></i> Preview Question Paper + </a> + <br> + <br> + <h4>You can check the quiz by attempting it in the following modes:</h4> + <a class="btn btn-outline-info" name="button" href="{% url 'yaksh:test_quiz' 'usermode' quiz.id course_id %}" target="blank"> + User Mode + </a> - <button class="btn btn-outline-info" type="button" name="button" onClick='location.replace("{{URL_ROOT}}/exam/manage/godmode/{{quiz.id}}/{{course_id}}/");'> - God Mode</button> - <a data-toggle="collapse" data-target="#help"> - <span class=" text-info"><i class="fa fa-info-circle"></i> Help</span></a> - <div id="help" class="collapse"> - <br/> - <ul> - <li><b>User Mode:</b> Attempt quiz the way normal users will attempt i.e. - - <ul> - <li><i>Quiz will have the same duration as that of the original quiz.</li> - <li>Quiz won't start if the course is inactive or the quiz time has expired.</li> - <li>You will be notified about quiz prerequisites.(You can still attempt the quiz though)</i></li> - </ul> - </p> - <li> <b>God Mode:</b> Attempt quiz without any time or eligibilty constraints.</p> + <a class="btn btn-outline-info" name="button" href="{% url 'yaksh:test_quiz' 'godmode' quiz.id course_id %}" target="blank"> + God Mode + </a> + <a data-toggle="modal" data-target="#help"> + <span class="text-info"><i class="fa fa-info-circle"></i> Help</span></a> + </center> + {% endif %} + {% endif %} +</div> +<div class="modal" id="help"> + <div class="modal-dialog" role="document"> + <div class="modal-content"> + <div class="modal-header"> + <h5 class="modal-title">Quiz Test Modes</h5> + <button type="button" class="close" data-dismiss="modal" aria-label="Close"> + <span aria-hidden="true"><i class="fa fa-close"></i></span> + </button> + </div> + <div class="modal-body"> + <p> + <b>User Mode:</b> Attempt quiz the way normal users will attempt i.e. - + <ul class="list-group list-group-flush"> + <li class="list-group-item">Quiz will have the same duration as that of the original quiz.</li> + <li class="list-group-item">Quiz won't start if the course is inactive or the quiz time has expired.</li> + <li class="list-group-item">You will be notified about quiz prerequisites.(You can still attempt the quiz though)</li> + </ul> + <b>God Mode:</b> Attempt quiz without any time or eligibilty constraints. + </p> + </div> </div> - {% endif %} -{% endif %} -<style type="text/css"> - #rendered_text{ - width: 550px; - } -</style> + </div> </div> {% endblock %} diff --git a/yaksh/templates/yaksh/addteacher.html b/yaksh/templates/yaksh/addteacher.html index fa322f3..58f48d9 100644 --- a/yaksh/templates/yaksh/addteacher.html +++ b/yaksh/templates/yaksh/addteacher.html @@ -1,76 +1,86 @@ -{% extends "manage.html" %} - -{% block title %} Add teacher {% endblock title %} -{% block subtitle %} {{ course.name }} {% endblock %} - -{% block content %} -<div class="yakshwell container"> -<center><h3>Add Teachers for this course</h3><br></center> -<center><h3>Search teacher with username, firstname, lastname, email</h3><br></center> -<div align="center"> - <form action="{{ URL_ROOT }}/exam/manage/searchteacher/{{ course.id }}/" method="post"> - {% csrf_token %} - Search Teacher: <input type="text" name="uname" style="height: 25px; padding: 0px"><br><br> - <center><button class="btn btn-info" type="submit">Search</button> - <button class="btn btn-danger" type="button" name="button" onClick='location.replace("{{URL_ROOT}}/exam/manage/courses");'>Cancel</button> </center></form> -</div> +<div class="container"> +<center><h3>Add Teachers/TAs</h3><br></center> +<form action="{% url 'yaksh:search_teacher' course.id %}" method="post"> + {% csrf_token %} + <div class="form-group"> + <input class="form-control form-control-lg" type="text" name="uname" id="inputLarge" placeholder="Search teachers with username, firstname, lastname, email" required> + </div> + <center> + <button class="btn btn-info btn-lg" type="submit"> + <i class="fa fa-search"></i> + Search + </button> + </center> +</form> <br><br> -<form action="{{ URL_ROOT }}/exam/manage/addteacher/{{ course.id }}/" method="post"> -{% csrf_token %} -{% if success == True %} - {% if teachers|length == 0 %} - <center><h3>No results found</h3></center> - {% else %} - <center><b><u>Search Results</u></b></center><br> - <center><b>Search results does not include teachers already added</b></center><br> - <table class="table table-striped table-responsive-sm"> +{% if success %} + {% if teachers|length == 0 %} + <center><h3 class="badge badge-warning">No results found</h3></center> + {% else %} + <center><b><u>Search Results</u></b></center><br> + <center> + <p class="alert alert-info"> + Search results does not include teachers already added + </p> + </center> + <br> + <form action="{% url 'yaksh:add_teacher' course.id %}" method="post"> + {% csrf_token %} + <table class="table table-striped table-responsive-sm course-detail"> <th></th> <th>Username</th> - <th>First Name</th> - <th>Last Name</th> - <th>Email</th> - <th>Institute</th> - <th>Department</th> + <th>First Name</th> + <th>Last Name</th> + <th>Email</th> + <th>Institute</th> + <th>Department</th> <th>Position</th> - {% for teacher in teachers %} - {% if teacher not in course.get_teachers %} - <tr class="yakshgreen"> - <td><input type="checkbox" name="check" value="{{ teacher.id }}"></td> - <td>{{ teacher.username }}</td> - <td>{{ teacher.first_name }}</td> - <td>{{ teacher.last_name }}</td> - <td>{{ teacher.email }}</td> - <td>{{ teacher.profile.institute }}</td> - <td>{{ teacher.profile.department }}</td> - <td>{{ teacher.profile.position }}</td> - </tr> - {% endif %} - {% endfor %} - </table> - </br> - <button class="btn btn-success" type="submit">Add Selected</button> - {% endif %} + {% for teacher in teachers %} + {% if teacher not in course.get_teachers %} + <tr class="yakshgreen"> + <td><input type="checkbox" name="check" value="{{ teacher.id }}"></td> + <td>{{ teacher.username }}</td> + <td>{{ teacher.first_name }}</td> + <td>{{ teacher.last_name }}</td> + <td>{{ teacher.email }}</td> + <td>{{ teacher.profile.institute }}</td> + <td>{{ teacher.profile.department }}</td> + <td>{{ teacher.profile.position }}</td> + </tr> + {% endif %} + {% endfor %} + </table> + </br> + <button class="btn btn-success btn-lg" type="submit"> + <i class="fa fa-plus-circle"></i> + Add Selected + </button> + </form> + {% endif %} {% endif %} -</form> -{% if status == True %} -<div class="row"> - <div class="span6 offset4 wrap"> + + +{% if status %} +<div class="container"> + <center><b><u>Teacher(s) added</u></b></center> + <br> {% if teachers_added %} - {% for teacher in teachers_added %} - <div class="well"> - <div class="row"> - <div class="span3" style="width: auto;"> - <h5>{{ teacher.get_full_name }}</h5> - </div> - </div> - </div> - {% endfor %} + <table class="table table-responsive-sm"> + <tr> + <th>Sr No.</th> + <th>Name</th> + </tr> + {% for teacher in teachers_added %} + <tr> + <td>{{forloop.counter}}</td> + <td>{{ teacher.get_full_name }}</td> + </tr> + {% endfor %} + <table> {% else %} - <center><b>No Teacher(s) Added</b></center> + <center><b class="badge badge-info">No Teacher(s)TA(s) Added</b></center> {% endif %} - </div> </div> {% endif %} </div> -{% endblock %} diff --git a/yaksh/templates/yaksh/complete.html b/yaksh/templates/yaksh/complete.html index 8c8073e..df76e13 100644 --- a/yaksh/templates/yaksh/complete.html +++ b/yaksh/templates/yaksh/complete.html @@ -1,18 +1,21 @@ {% extends "base.html" %} +{% load static %} + +{% block title %} Complete Quiz {% endblock %} {% block nav %} <nav class="navbar navbar-expand-lg navbar-dark bg-primary fixed-top"> - <a class="navbar-brand" href="{{ URL_ROOT }}/exam/"> - <img src="{{ URL_ROOT }}/static/yaksh/images/yaksh_banner.png" alt="YAKSH"> - </a> + <a class="navbar-brand" href="{% url 'yaksh:index' %}"> + <img src="{% static 'yaksh/images/yaksh_banner.png' %}" alt="YAKSH"> + </a> </nav> {% endblock %} {% block content %} <br> -{% if module_id and not paper.question_paper.quiz.is_trial %} +{% if module_id and not paper.course.is_trial %} <center> - <div class="alert alert-info col-md-8 animated flash"> + <div class="alert alert-info col-md-8"> Note:- Please Click on the Next button to submit the quiz. Please do not close the browser without clicking Next. </div> </center> @@ -20,11 +23,11 @@ {% csrf_token %} {% if paper.questions_answered.all or paper.questions_unanswered.all %} <center> - <div class="col-md-8 yakshwell"> + <div class="col-md-8"> <h3>Submission Status</h3> <table class="table table-bordered table-responsive-sm" > <thead> - <tr class="yakshred text-center"> + <tr class="text-center"> <th> Question</th> <th> Status </th> </tr> @@ -37,7 +40,7 @@ <td> {{ question.summary }} </td> <td> Attempted </td> {% else %} - <tr class="table-danger"> + <tr class="table-warning"> <td> {{ question }} </td> <td> Not completed </td> {% endif %} @@ -56,20 +59,20 @@ </center> <center> <br> - {% if module_id and not paper.question_paper.quiz.is_trial %} + {% if module_id and not paper.course.is_trial %} {% if first_unit %} - <a href="{{URL_ROOT}}/exam/next_unit/{{course_id}}/{{module_id}}/{{learning_unit.id}}/1" class="btn btn-info" id="Next"> Next + <a href="{% url 'yaksh:next_unit' course_id module_id learning_unit.id '1' %}" class="btn btn-info btn-lg" id="Next"> Next <span class="fa fa-step-forward"> </span> </a> {% else %} - <a href="{{URL_ROOT}}/exam/next_unit/{{course_id}}/{{module_id}}/{{learning_unit.id}}" class="btn btn-info" id="Next"> Next + <a href="{% url 'yaksh:next_unit' course_id module_id learning_unit.id %}" class="btn btn-info btn-lg" id="Next"> Next <span class="fa fa-step-forward"> </span> </a> {% endif %} {% else %} - <a href="{{URL_ROOT}}/exam/" id="home" class="btn btn-primary btn-lg"> Home </a> + <a href="{% url 'yaksh:index' %}" id="home" class="btn btn-primary btn-lg"> Home </a> {% endif %} </center> {% endblock content %} diff --git a/yaksh/templates/yaksh/course_added_modules.html b/yaksh/templates/yaksh/course_added_modules.html new file mode 100644 index 0000000..c70eb7a --- /dev/null +++ b/yaksh/templates/yaksh/course_added_modules.html @@ -0,0 +1,49 @@ +{% if is_modules %} + {% block pagetitle %} <center> <h3>Course Modules</h3> </center> {% endblock %} + {% if modules %} + <table class="table table-responsive"> + <tr> + <th>Module</th> + <th>Module Design</th> + <th>Lessons/Quizzes</th> + </tr> + {% for module in modules %} + <tr> + <td> + <a href="{% url 'yaksh:edit_module' module.id course.id %}"> + {{module.name}}</a> + </td> + <td> + <a href="{% url 'yaksh:design_module' module.id course.id %}"> + Add Quizzes/Lessons for {{module.name}} + </a> + </td> + <td> + {% for unit in module.get_learning_units %} + <ul class="inputs-list"> + <li> + {% if unit.type == "quiz" %} + {% if unit.quiz.is_exercise %} + <a href="{% url 'yaksh:edit_exercise' unit.quiz.id course.id %}"> + {{unit.quiz.description}}</a> + {% else %} + <a href="{% url 'yaksh:edit_quiz' unit.quiz.id course.id %}"> + {{unit.quiz.description}}</a> + {% endif %} + {% else %} + <a href="{% url 'yaksh:edit_lesson' unit.lesson.id course.id %}"> + {{unit.lesson.name}}</a> + {% endif %} + </li> + </ul> + {% endfor %} + </td> + </tr> + {% endfor %} <!-- end for modules --> + </table> + {% else %} + <center> + <span class="badge badge-warning"><big>No learning modules</big></span> + </center> + {% endif %} +{% endif %}
\ No newline at end of file diff --git a/yaksh/templates/yaksh/course_detail.html b/yaksh/templates/yaksh/course_detail.html index f75e362..654f373 100644 --- a/yaksh/templates/yaksh/course_detail.html +++ b/yaksh/templates/yaksh/course_detail.html @@ -1,383 +1,94 @@ {% extends "manage.html" %} +{% load static %} {% load custom_filters %} {% block title %} Course Details {% endblock title %} -<div class="text-center col-md-offset-2"> -{% block pagetitle %} Course Details for {{ course.name|title }} {% endblock %} -</div> - {% block script %} -<script language="JavaScript" type="text/javascript" src="{{ URL_ROOT }}/static/yaksh/js/course.js"></script> -<script type="text/javascript" src="{{ URL_ROOT }}/static/yaksh/js/tinymce/js/tinymce/tinymce.min.js"></script> -<script src="{{ URL_ROOT }}/static/yaksh/js/jquery-ui.js"></script> -<script src="{{ URL_ROOT }}/static/yaksh/js/jquery.tablesorter.min.js"></script> +<script type="text/javascript" src="{% static 'yaksh/js/course.js' %}"></script> +<script type="text/javascript" src="{% static 'yaksh/js/tinymce/js/tinymce/tinymce.min.js' %}"></script> +<script type="text/javascript" src="{% static 'yaksh/js/jquery-ui.js' %}"></script> +<script type="text/javascript" src="{% static 'yaksh/js/jquery.tablesorter.min.js' %}"> +</script> {% endblock %} {% block css %} -<link rel="stylesheet" href="{{ URL_ROOT }}/static/yaksh/css/jquery-ui/jquery-ui.css"> -<style> - .user_data + .tooltip.top > .tooltip-inner { - padding: 12px; - font-size: 10px; - } -</style> +<link rel="stylesheet" href="{% static 'yaksh/css/jquery-ui/jquery-ui.css' %}"> {% endblock %} + +<div class="text-center"> +{% block pagetitle %} <h1>{{ course.name|title }}</h1> {% endblock %} +</div> + {% block content %} -<div class="row"> - <!-- Side bar --> - <div class="col-md-3 yakshlabel collapse" id="sidebar"> - <div class="list-group"> - {% if state == 'mail' or state == 'course_status' %} - <a href="{{URL_ROOT}}/exam/manage/course_detail/{{course.id}}/" class="list-group-item" data-parent="#sidebar"><i class="fa fa-caret-left"></i> Go to Course Details </a> - {% else %} - <a href="#student-requests" id="request" class="list-group-item" data-parent="#sidebar"> Requested Students </a> - <a href="#enrolled-students" id="enroll-students" class="list-group-item" data-parent="#sidebar"> Enrolled Students</a> - <a href="#rejected-students" id="reject-students" class="list-group-item" data-parent="#sidebar"> Rejected Students </a> - {% endif %} - <a href="{{URL_ROOT}}/exam/manage/send_mail/{{ course.id }}/" class="list-group-item" data-parent="#sidebar"> Send Mail </a> - <a href="{{URL_ROOT}}/exam/manage/course_status/{{ course.id }}/" class="list-group-item" data-parent="#sidebar"> View Course Status </a> +<hr> +<div id="dialog" title="Alert"> + <p id="error_msg"></p> +</div> +<div class="container-fluid"> + <div class="row"> + <div class="col-sm-3"> + {% include "yaksh/course_detail_options.html" %} </div> - </div> - <a href="#sidebar" data-toggle="collapse" id="sidebaricon"><i class="fa fa-navicon fa-lg"></i></a> - <!-- End of sidebar --> - <main class="col" id="sidebarbody"> - <div class="container-fluid yakshwell"> - - <form id="upload_users" action="{{ URL_ROOT }}/exam/manage/upload_users/{{course.id}}/" - method="POST" enctype="multipart/form-data" class="yakshwell"> - {% csrf_token %} - <input type="file" name="csv_file" /> - <button class="btn btn-outline-primary" type=submit> Upload Users <span class="glyphicon glyphicon-open"/></button> - </form> - <div class="card" role="alert"> - <div class="card-body"> - <p> - - The uploaded csv should have headers exactly same as mentioned below:<br /> - <b>firstname, lastname, email, username, password, institute, roll_no, department, - remove</b><br /> - - Mandatory fields are <b> firstname, lastname and email. </b><br /> - - Other fields are optional. <br /> - - If username and password are not provided then - <b>Users created will have username and password same as their email</b> - </p> - <p> - <b> Click <a class="btn btn-success" href="{{ URL_ROOT }}/exam/manage/download_sample_csv/ - ">here</a> to download a sample CSV, edit and upload it</b> - </p> - </div> - </div> - <div class="yakshwell"> - {% if message %} - <center> - <div class="alert alert-warning animated flash col-md-8" role="alert"> - <strong> {{ message }} </strong> - </div> - </center> - {% endif %} - {% if upload_details %} - <div class="alert alert-info" role="info"> - {% for detail in upload_details %} - <strong> {{ detail }} </strong><br> - {% endfor %} + <div class="col-md-9"> + <div class="tab-content"> + {% 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 %} - - {% if state == 'mail' %} - <div id="enrolled-students" > - <center ><div class="yakshlabel"><h5>Send Mails to Students</h5></div></center><br> - {% if course.get_enrolled %} - <input type="checkbox" class="reject"/> <font class="text-info">Select all</font> - <div id="reject" class="yakshwell"> - <form action="{{URL_ROOT}}/exam/manage/send_mail/{{ course.id }}/" method="post" id="send_mail_form"> - {% csrf_token %} - <table id="mail_table" class="tablesorter table table-striped table-responsive-sm" data-sortlist="[1,0]"> - <thead> - <th></th> - <th></th> - <th>Full Name</th> - <th>Email</th> - <th>Roll Number</th> - <th>Institute</th> - <th>Department</th> - </thead> - <tbody> - {% for enrolled in course.get_enrolled %} - <tr> - <td><input type="checkbox" name="check" value="{{ enrolled.id }}"></td> - <td>{{ forloop.counter }}.</td> - <td> {{ enrolled.get_full_name|title }} </td> - <td> {{enrolled.email}}</td> - <td> {{enrolled.profile.roll_number}}</td> - <td> {{enrolled.profile.institute}}</td> - <td> {{enrolled.profile.department}}</td> - </tr> - {% endfor %} - </tbody> - </table> - <br> - <div class="card"> - <textarea name="subject" id="subject" placeholder="Email Subject" cols="50"></textarea> - <br><br> - <textarea name="body" id="email_body"></textarea><br> - <span class="yakshwell"> Attachments: <input type="file" name="email_attach" multiple=""></span> - <br> - </div> - <div class="text-center yakshwell"> - <button class="btn btn-success" type="submit" name='send_mail' value='send_mail' id="send_mail"> - Send Mail to Selected Students</button> - </div> - </form> - </div> - {% endif %} - </div> - {% elif state == "course_status" %} - <div class="course_data"> - - <center> - <div class="row"> - <div class="col"> - <h5>Course Status</h5> - </div> - <div class="col-md-8"> - Number Of Students: {{ student_details | length }} - </div> - <div class="col"> - <input type="hidden" id="course_name" value="{{course.name}}"> - <a href="#" class="btn btn-outline-success" id="export">Export to CSV</a> - </div> - </div> - </center> - <div class="yakshwell"> - <table class="tablesorter table table-bordered table-responsive-sm" id="course_table" data-sortlist="[0,0]"> - <thead> - <tr class="yakshlight"> - <th>Roll No.</th> - <th>Name</th> - <th>Current Unit</th> - <th>Course Completion Percentage</th> - <th>Grade</th> - </tr> - </thead> - <tbody> - {% for student, grade, percent, unit in student_details %} - <tr> - <td> - {{ student.profile.roll_number}} - </td> - <td width="50%"> - <a class="user_data" data-item-id="{{course.id}}+{{student.id}}" data-toggle="tooltip" title="Click to view Overall Course progress" data-placement="top"> - {{ student.get_full_name|title}} - <i class="fa fa-caret-down"></i> - </a> - <div id="show_status_{{course.id}}_{{student.id}}" style="display: None;"> - </div> - </td> - <td> - {% if unit %} - {% if unit.type == 'quiz' %} - {{unit.quiz.description}} - {% else %} - {{unit.lesson.name}} - {% endif %} - {% else %} - NA - {% endif%} - </td> - <td> - {{ percent }} % - </td> - <td> - {{ grade }} - </td> - </tr> - {% endfor %} - </tbody> - </table> - </div> - </div> + {% if is_students %} + {% include "yaksh/course_students.html" %} + {% elif is_mail %} + {% include "yaksh/course_send_mail.html" %} + {% elif is_progress %} + {% include "yaksh/course_progress.html" %} + {% elif is_modules %} + {% include "yaksh/course_added_modules.html" %} + {% elif is_design_course %} + {% include "yaksh/design_course_session.html" %} + {% elif is_add_teacher %} + {% include "yaksh/addteacher.html" %} + {% elif is_teachers %} + {% include "yaksh/course_teachers.html" %} {% else %} - <div id="students_enrollment"> - <div id="student-requests" class="card"> - <center><div class="yakshlabel card-heading">Requests</div></center><br> - <div class="card-body"> - {% if course.get_requests %} - <input type="checkbox" class="checkall"/> <font size="2">Select all</font> - <div id="enroll-all"> - <form action="{{URL_ROOT}}/exam/manage/enroll/{{ course.id }}/" method="post"> - {% csrf_token %} - <table id="requested_table" class="tablesorter table table-striped table-responsive-sm" data-sortlist="[1,0]"> - <thead> - <th></th> - <th></th> - <th>Full Name</th> - <th>Email</th> - <th>Roll Number</th> - <th>Institute</th> - <th>Department</th> - <th>Enroll/Reject</th> - </thead> - <tbody> - {% for request in course.get_requests %} - <tr> - <td><input type="checkbox" name="check" value="{{ request.id }}"></td> - <td>{{ forloop.counter }}.</td> - <td>{{request.get_full_name}}</td> - <td> {{request.email}}</td> - <td> {{request.profile.roll_number}}</td> - <td> {{request.profile.institute}}</td> - <td> {{request.profile.department}}</td> - <td> - <a class="btn btn-success" - href="{{URL_ROOT}}/exam/manage/enroll/{{ course.id }}/{{ request.id }}/"> - Enroll </a> - <a class="btn btn-danger" - href="{{URL_ROOT}}/exam/manage/reject/{{ course.id }}/{{ request.id }}/"> - Reject </a> - </td> - </tr> - {% endfor %} - </tbody> - </table> - <button class="btn btn-success pull-right" type="submit" name='enroll' value='enroll'>Enroll Selected</button> <br> - </form> - </div> - {% else %} - <center> - <span class="badge badge-warning"><big> No requests yet</big></span> - </center> - {% endif %} - </div> - </div> - <br> - <div id="enrolled-students" class="card"> - <center><div class="yakshlabel card-heading">Enrolled</div></center><br> - <div class="card-body"> - {% if course.get_enrolled %} - <input type="checkbox" class="reject"/> <font size="2">Select all</font> - <div id="reject"> - <form action="{{URL_ROOT}}/exam/manage/enrolled/reject/{{ course.id }}/" method="post" id="reject-form"> - {% csrf_token %} - <table id="enrolled_table" class="tablesorter table table-striped table-responsive-sm" data-sortlist="[1,0]"> - <thead> - <th></th> - <th></th> - <th>Full Name</th> - <th>Email</th> - <th>Roll Number</th> - <th>Institute</th> - <th>Department</th> - <th>Reject</th> - </thead> - <tbody> - {% for enrolled in course.get_enrolled %} - <tr> - <td><input type="checkbox" name="check" value="{{ enrolled.id }}"></td> - <td>{{ forloop.counter }}.</td> - <td> {{ enrolled.get_full_name|title }} </td> - <td> {{enrolled.email}}</td> - <td> {{enrolled.profile.roll_number}}</td> - <td> {{enrolled.profile.institute}}</td> - <td> {{enrolled.profile.department}}</td> - <td><a class="btn btn-danger" - href="{{URL_ROOT}}/exam/manage/enrolled/reject/{{ course.id }}/{{ enrolled.id }}/"> - Reject </a> - </td> - </tr> - {% endfor %} - </tbody> - </table> - <button class="btn btn-danger pull-right" type="submit" name='reject' value='reject'> - Reject Selected</button> <br> - </form> - </div> - {% else %} - <center> - <span class="badge badge-warning"><big> No enrolled students yet</big></span> - </center> - {% endif %} - </div> - </div> - <br> - <div id="rejected-students" class="card"> - <center><div class="yakshlabel card-heading">Rejected</div></center><br> - <div class="card-body"> - {% if course.get_rejected %} - <input type="checkbox" class="enroll"/> <font size="2">Select all</font> - <div id="enroll"> - <form action="{{URL_ROOT}}/exam/manage/enroll/rejected/{{ course.id }}/" method="post"> - {% csrf_token %} - <table id="rejected_table" class="tablesorter table table-striped table-responsive-sm" data-sortlist="[1,0]"> - <thead> - <th></th> - <th></th> - <th>Full Name</th> - <th>Email</th> - <th>Roll Number</th> - <th>Institute</th> - <th>Department</th> - <th>Enroll</th> - </thead> - <tbody> - {% for rejected in course.get_rejected %} - <tr> - <td><input type="checkbox" name="check" value="{{ rejected.id }}"></td> - <td>{{ forloop.counter }}.</td> - <td>{{rejected.get_full_name|title}}</td> - <td> {{rejected.email}}</td> - <td> {{rejected.profile.roll_number}}</td> - <td> {{rejected.profile.institute}}</td> - <td> {{rejected.profile.department}}</td> - <td> - <a class="btn btn-success" - href="{{URL_ROOT}}/exam/manage/enroll/rejected/{{ course.id }}/{{ rejected.id }}/"> - Enroll </a> - </td> - </tr> - {% endfor %} - </tbody> - </table> - <br> - <button class="btn btn-success pull-right" type="submit" name='enroll' value='enroll'> - Enroll Selected</button> <br> - </form> - </div> - {% else %} - <center> - <span class="badge badge-warning"><big> No rejected students yet</big></span> - </center> - {% endif %} - </div> - </div> + <div class="jumbotron"> + <h1 class="display-4">Manage Course</h1> + <hr class="my-4"> + <p> + <ul> + <li> + Students enrollments + </li> + <li> + Add and View Modules, Lessons and Quizzes + </li> + <li> + Send mail to the students + </li> + <li> + View Students course progress + </li> + <li> + Add and View Teachers/TAs + </li> + </ul> + </p> + <p class="lead"> + <a class="btn btn-primary btn-lg" href="https://yaksh.readthedocs.io/en/latest/moderator_docs/creating_course.html" role="button" target="blank"> + <i class="fa fa-info-circle"></i> + Learn more + </a> + </p> </div> {% endif %} </div> - <!-- Dialog to display error message --> - <div id="dialog" title="Alert"> - <p id="error_msg"></p> - </div> </div> - </main> + </div> </div> {% endblock %} -{% block footer %} - <!--footer--> - <footer class="container-fluid yakshsidebarfooter text-center"> - <div class="row justify-content-center"> - <div class="col-sm-5 "> - {% if user %} - {% block info %} - <b>{{user.get_full_name|title}}</b> with Roll no. <b>{{user.profile.roll_number}}</b> is logged in as <b>{{user.username}}</b> - {% endblock %} - {% endif %} - </div> - <div class="col-sm-2"> - | - </div> - <div class="col-sm-4 text-left"> - <b>Any Queries?</b> Email : info@fossee.in - </div> - </div> - </footer> - <!--footer end--> -{% endblock %} diff --git a/yaksh/templates/yaksh/course_detail_options.html b/yaksh/templates/yaksh/course_detail_options.html new file mode 100644 index 0000000..43422ed --- /dev/null +++ b/yaksh/templates/yaksh/course_detail_options.html @@ -0,0 +1,47 @@ +<ul class="nav nav-pills list-group"> + <li class="nav-item"> + <a href="{% url 'yaksh:courses' %}" class="nav-link list-group-item" title="View all the courses" data-placement="top" data-toggle="tooltip"> + Back to Courses + </a> + </li> + <li class="nav-item"> + <a href="{% url 'yaksh:course_students' course.id %}" id="enroll-students" class="nav-link list-group-item {% if is_students %} active {% endif %}" title="View the course requested, rejected and added students" data-placement="top" data-toggle="tooltip"> + Enroll Students + </a> + </li> + <li class="nav-item"> + <a href="{% url 'yaksh:send_mail' course.id %}" class="nav-link list-group-item {% if is_mail %} active {% endif %}" title="Send mail to course students" data-placement="top" data-toggle="tooltip"> + Send Mail + </a> + </li> + <li class="nav-item"> + <a href="{% url 'yaksh:course_status' course.id %}" class="nav-link list-group-item {% if is_progress %} active {% endif %}" title="View Students course progress" data-placement="top" data-toggle="tooltip"> + Course Progress + </a> + </li> + <li class="nav-item"> + <a class="nav-link list-group-item" href="{% url 'yaksh:duplicate_course' course.id %}" data-toggle="tooltip" title="Creates copy of this course and all its contents" data-placement="top"> + Clone Course + </a> + </li> + <li class="nav-item"> + <a class="nav-link list-group-item {% if is_design_course %} active {% endif %}" href="{% url 'yaksh:design_course' course.id %}" title="Add modules to this course" data-placement="top" data-toggle="tooltip"> + Design Course + </a> + </li> + <li class="nav-item"> + <a class="nav-link list-group-item {% if is_modules %} active {% endif %}" href="{% url 'yaksh:get_course_modules' course.id %}" title="View modules added to the course" data-placement="top" data-toggle="tooltip"> + Course Modules + </a> + </li> + <li class="nav-item"> + <a class="nav-link list-group-item {% if is_add_teacher %} active {% endif %}" href="{% url 'yaksh:search_teacher' course.id %}" data-toggle="tooltip" title="Add Teachers/TAs to this course" data-placement="top"> + Add Teachers/TAs + </a> + </li> + <li class="nav-item"> + <a class="nav-link list-group-item {% if is_teachers %} active {% endif %}" href="{% url 'yaksh:course_teachers' course.id %}" data-toggle="tooltip" title="View all the Teachers/TAs for this course" data-placement="top"> + Current Teachers/TAs + </a> + </li> +</ul>
\ No newline at end of file diff --git a/yaksh/templates/yaksh/course_modules.html b/yaksh/templates/yaksh/course_modules.html index 8440d51..214f8c7 100644 --- a/yaksh/templates/yaksh/course_modules.html +++ b/yaksh/templates/yaksh/course_modules.html @@ -1,186 +1,175 @@ {% extends "user.html" %} {% load custom_filters %} {% block title %} Course Modules {% endblock %} -{% block script %} -<script> - function view_unit(unit){ - $("#"+unit+"_down").toggle(); - $("#"+unit+"_up").toggle(); - } - -</script> -{% endblock %} {% block main %} - <div class="container"> -<div class="row justify-content-md-center yakshwell"> - <div class="col-md-10 bg-light card" id="card"> - <div class="row align-items-center"> - <div class="col h4"> {{ course.name }} </div> - <div class = "col"> - {% if course.has_lessons %} - <a href="{% url 'yaksh:download_course' course.id %}" data-toggle="tooltip" title="Download course content" class="btn btn-primary pull-right"> - Download Course - </a> - {% endif %} - </div> - </div> - </div> -</div> - -<center> - {% if course.view_grade %} - <div class=" col-md-8"> - <b>Grade: {% if grade %} {{ grade }} {% else %} Will be available once the course is complete {% endif %}</b> + <div class="card"> + <div class="card-header"> + {{ course.name }} </div> - {% endif %} - - {% if msg %} - <div class="col-md-8 alert alert-warning animated flash" role="alert"> - {{ msg }} - </div> - {% endif %} -</center> - -<div class="row justify-content-md-center "> -{% if modules %} - <div class="col-md-10 yakshwell"> - - <strong>Overall Course Progress</strong> - <div class="progress"> - {% if course_percentage <= 50 %} - <div class="progress-bar progress-bar-danger" role="progressbar" aria-valuenow="40" - aria-valuemin="0" aria-valuemax="100" style="width:{{course_percentage}}%"> - {% elif course_percentage <= 75 %} - <div class="progress-bar progress-bar-warning" role="progressbar" aria-valuenow="40" - aria-valuemin="0" aria-valuemax="100" style="width:{{course_percentage}}%"> - {% else %} - <div class="progress-bar progress-bar-success" role="progressbar" aria-valuenow="40" - aria-valuemin="0" aria-valuemax="100" style="width:{{course_percentage}}%"> - {% endif %} - <b style="color: black;">{{course_percentage}}% Completed</b> - </div> - </div> - - {% for module, percent in modules %} - <div class="yakshwell"> - <div class="row yakshlabel align-items-center"> - <div class="col-md-4"> - {{module.name|title}} + <div class="card-body"> + {% if course.view_grade %} + <center> + <b>Grade:</b> {% if grade %} {{ grade }} {% else %} Will be available once the course is complete {% endif %} + </center> + {% endif %} + {% if msg %} + <div class="alert alert-dismissible alert-warning"> + <button type="button" class="close" data-dismiss="alert"> + <i class="fa fa-close"></i> + </button> + <strong>{{ msg }}</strong> </div> - - <div class="col-md-1"> - <a data-toggle="collapse" data-target="#learning_units{{module.id}}{{course.id}}" onclick="view_unit('learning_units{{module.id}}{{course.id}}');"> - <div class="btn yakshred"> - <span class="fa fa-caret-down fa-2x" id="learning_units{{module.id}}{{course.id}}_down" > - </span> - <span class="fa fa-caret-right fa-2x" id="learning_units{{module.id}}{{course.id}}_up" style="display: none; "> - </span> + {% endif %} + {% if modules %} + <strong>Overall Course Progress:</strong> + <div class="progress"> + {% if course_percentage %} + {% if course_percentage <= 50 %} + <div class="progress-bar bg-danger" role="progressbar" aria-valuenow="{{course_percentage}}" + aria-valuemin="0" aria-valuemax="100" style="width:{{course_percentage}}%"> + {% elif course_percentage <= 75 %} + <div class="progress-bar bg-warning" role="progressbar" aria-valuenow="{{course_percentage}}" + aria-valuemin="0" aria-valuemax="100" style="width:{{course_percentage}}%"> + {% else %} + <div class="progress-bar bg-success" role="progressbar" aria-valuenow="{{course_percentage}}" + aria-valuemin="0" aria-valuemax="100" style="width:{{course_percentage}}%"> + {% endif %} + <b style="color: white;">{{course_percentage}}% Completed</b> </div> - </a> - + {% else %} + <b style="color: black;">0% Completed</b> + {% endif %} + </div> + {% else %} + <div class="alert alert-danger"> + <strong>No lectures found</strong> </div> - <div class="col-md-5 ml-auto"> - <div class="row align-items-center justify-content-md-end"> - <div class="col-md-3"> - <a href="{{URL_ROOT}}/exam/quizzes/view_module/{{module.id}}/{{course.id}}"> - {% get_module_status user module course as module_status %} - {% if module_status == "completed" %} - <div class="btn btn-success "> - View - </div> - {% elif module_status == "inprogress" %} - <div class="btn btn-info"> - Continue - </div> - {% else %} - <div class="btn btn-danger "> - Start + {% endif %} + <br> + {% for module, percent in modules %} + <div class="accordian-{{module.id}}"> + <div class="card"> + <div class="card-header"> + <div class="row"> + <div class="col-md-4"> + {{ module.name|title }} + </div> + <div class="col-md-3"> + <a class="card-link btn btn-outline-info" data-toggle="collapse" href="#collapse-{{module.id}}"> + Details <i class="fa fa-toggle-down"></i> + </a> + </div> + <div class="col-md-2"> + <a href="{% url 'yaksh:view_module' module.id course.id %}"> + {% get_module_status user module course as module_status %} + {% if module_status == "completed" %} + <div class="btn btn-info "> + View + </div> + {% elif module_status == "inprogress" %} + <div class="btn btn-primary"> + Continue + </div> + {% else %} + <div class="btn btn-success "> + Start + </div> + {% endif %} + </a> + </div> + <div class="col-md-3"> + <div class="progress bg-white"> + {% if percent %} + {% get_module_status user module course as module_status %} + {% if module_status == "completed" %} + <div class="progress-bar bg-success" role="progressbar" aria-valuenow="{{percent}}" + aria-valuemin="0" aria-valuemax="100" style="width:{{percent}}%"> + {% elif module_status == "inprogress" %} + <div class="progress-bar bg-warning" role="progressbar" + aria-valuemin="0" aria-valuemax="100" style="width:{{percent}}%"> + {% endif %} + <b style="color: white;">{{percent}}% Completed</b> + </div> + {% else %} + <b style="color: black;">0% Completed</b> + {% endif %} + </div> + </div> </div> - {% endif %} - </a> </div> - <div class="col-md-6"> - {% get_module_status user module course as module_status %} - {% if module_status == "completed" %} - <div class="progress"> - <div class="progress-bar bg-success" role="progressbar" style="width: 100%; color: black;" aria-valuenow="100" aria-valuemin="0" aria-valuemax="100">{{ percent }} % completed</div> - </div> - {% elif module_status == "inprogress" %} - <div class="progress"> - <div class="progress-bar bg-warning " role="progressbar" style="width: 50%; color: black;" aria-valuenow="50" aria-valuemin="0" aria-valuemax="100">{{ percent }} % completed</div> + <div id="collapse-{{module.id}}" class="collapse hide" data-parent="#accordion-{{module.id}}"> + <div class="card-body"> + <table class="table yakshwell"> + {% for unit in module.get_learning_units %} + <tr> + <td> + {% if unit.type == "quiz" %} + {% if unit.quiz.is_exercise %} + <span class="fa fa-pencil"></span> + {% else %} + <span class="fa fa-puzzle-piece"></span> + {% endif %} + {% else %} + <span class="fa fa-book"></span> + {% endif %} + </td> + <td> + {% if unit.type == "quiz" %} + {{unit.quiz.description}} + {% else %} + {{unit.lesson.name}} + {% endif %} + </td> + <td> + {% if unit.type == "lesson" %} + <a href="{% url 'yaksh:show_lesson' unit.lesson.id module.id course.id %}" class="btn btn-outline-info"> + View + </a> + {% else %} + <a href="{% url 'yaksh:start_quiz' unit.quiz.questionpaper_set.get.id module.id course.id %}" class="btn btn-outline-info"> + View + </a> + {% endif %} + </td> + <td> + {% get_unit_status course module unit user as status %} + {% if status == "completed" %} + <span class="badge badge-success">{{status|title}} + </span> + {% elif status == "inprogress" %} + <span class="badge badge-info">{{status|title}} + </span> + {% else %} + <span class="badge badge-warning">{{status|title}} + </span> + {% endif %} + </td> + <td> + {% if unit.type == "quiz" %} + {% if unit.quiz.view_answerpaper %} + <a href="{% url 'yaksh:view_answerpaper' unit.quiz.questionpaper_set.get.id course.id %}" > + <i class="fa fa-eye"></i> Answer paper</a> + {% else %} + <a > + <i class="fa fa-eye-slash" aria-hidden="true"> + </i>Answer paper</a> + {% endif %} + {% else %} + ------ + {% endif %} + </td> + </tr> + {% endfor %} + </table> </div> - {% else %} - <div class="progress"> - <div class="progress-bar bg-danger" role="progressbar" style="width: 1%; color: black;" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100">{{ percent }} % completed</div> - </div> - {% endif %} - </div> </div> </div> </div> - <div id="learning_units{{module.id}}{{course.id}}" class="collapse"> - <table class="table yakshwell"> - - {% for unit in module.get_learning_units %} - <tr> - <td> - {% if unit.type == "quiz" %} - {% if unit.quiz.is_exercise %} - <span class="fa fa-pencil"></span> - {% else %} - <span class="fa fa-puzzle-piece"></span> - {% endif %} - {% else %} - <span class="fa fa-book"></span> - {% endif %} - </td> - <td> - {% if unit.type == "quiz" %} - {{unit.quiz.description}} - {% else %} - {{unit.lesson.name}} - {% endif %} - </td> - - <td> - {% get_unit_status course module unit user as status %} - {% if status == "completed" %} - <span class="badge badge-success">{{status|title}} - </span> - {% elif status == "inprogress" %} - <span class="badge badge-info">{{status|title}} - </span> - {% else %} - <span class="badge badge-warning">{{status|title}} - </span> - {% endif %} - </td> - <td> - {% if unit.type == "quiz" %} - {% if unit.quiz.view_answerpaper %} - <a href="{{ URL_ROOT }}/exam/view_answerpaper/{{ unit.quiz.questionpaper_set.get.id }}/{{course.id}}" > - <i class="fa fa-eye" aria-hidden="true"></i>Answer paper</a> - {% else %} - <a > - <i class="fa fa-eye-slash" aria-hidden="true"> - </i>Answer paper</a> - {% endif %} - {% else %} - ------ - {% endif %} - </td> - </tr> - {% endfor %} - </table> - </div> + <br> + {% endfor %} </div> - {% endfor %} </div> -{% else %} - <h3 class="alert-danger"> No lectures found </h3> -{% endif %} -</div> </div> {% endblock %} diff --git a/yaksh/templates/yaksh/course_progress.html b/yaksh/templates/yaksh/course_progress.html new file mode 100644 index 0000000..a833c92 --- /dev/null +++ b/yaksh/templates/yaksh/course_progress.html @@ -0,0 +1,70 @@ +<!-- Course Status --> +{% if is_progress %} +<div class="course_data"> + {% if student_details %} + <div class="text-center"> + <h3>Course Progress</h3> + <div class="col"> + Number Of Students: {{ students_no }} + </div> + </div> + {% include "yaksh/paginator.html" %} + <table class="tablesorter table table-bordered table-responsive-sm" id="course_table" data-sortlist="[0,0]"> + <thead> + <tr> + <th>Sr. No</th> + <th>Roll No.</th> + <th>Name</th> + <th>Current Unit</th> + <th>Completion Percentage</th> + <th>Grade</th> + </tr> + </thead> + <tbody> + {% for student, grade, percent, unit in student_details %} + <tr> + <td>{{forloop.counter}}</td> + <td> + {{ student.profile.roll_number}} + </td> + <td width="50%"> + <input type="hidden" id="url-{{student.id}}" data-url="{% url 'yaksh:get_user_data' course.id student.id %}"> + <a class="user_data" data-item-id="{{course.id}}+{{student.id}}" data-toggle="tooltip" title="Click to view Overall Course progress" data-placement="top"> + {{ student.get_full_name|title}} + <i class="fa fa-caret-down"></i> + </a> + <div id="show_status_{{course.id}}_{{student.id}}" style="display: None;"> + </div> + </td> + <td> + {% if unit %} + {% if unit.type == 'quiz' %} + {{unit.quiz.description}} + {% else %} + {{unit.lesson.name}} + {% endif %} + {% else %} + NA + {% endif%} + </td> + <td> + {{ percent }} % + </td> + <td> + {{ grade }} + </td> + </tr> + {% endfor %} + </tbody> + </table> + {% include "yaksh/paginator.html" %} + {% else %} + <center> + <span class="badge badge-warning"> + <big>No course data found</big> + </span> + </center> + {% endif %} +</div> +<!-- End Course Status --> +{% endif %}
\ No newline at end of file diff --git a/yaksh/templates/yaksh/course_send_mail.html b/yaksh/templates/yaksh/course_send_mail.html new file mode 100644 index 0000000..57442a6 --- /dev/null +++ b/yaksh/templates/yaksh/course_send_mail.html @@ -0,0 +1,63 @@ +<!-- Send Mail --> +{% if is_mail %} +<div id="send-mail"> + {% if enrolled %} + <form action="{% url 'yaksh:send_mail' course.id %}" method="post" id="send_mail_form" enctype="multipart/form-data"> + {% csrf_token %} + <div class="card"> + <div class="card-body"> + <textarea name="subject" class="form-control" id="subject" placeholder="Email Subject"></textarea> + <br><br> + <textarea name="body" id="email_body"></textarea><br> + Attachments: + <div class="input-group mb-3"> + <div class="custom-file"> + <input type="file" class="custom-file-input" name="email_attach" id="upload" multiple=""> + <label class="custom-file-label" for="upload">Choose file</label> + </div> + </div> + <br> + </div> + </div> + <br> + <input type="checkbox" class="send_check"/> + <font size="5">Select all</font> + <div id="sender_list"> + <table id="mail_table" class="tablesorter table table-striped table-responsive-sm course-detail" data-sortlist="[1,0]"> + <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> + </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 user_profile %} + <td> {{user_profile.roll_number}}</td> + <td> {{user_profile.institute}}</td> + {% endwith %} + </tr> + {% endfor %} + </tbody> + </table> + <button class="btn btn-success btn-lg" type="submit" name='send_mail' value='send_mail' id="send_mail"> + Send Mail + </button> + </div> + </form> + {% else %} + <center> + <span class="badge badge-warning"><big> No enrolled students yet</big></span> + </center> + {% endif %} +</div> +<!-- End send mail --> +{% endif %}
\ No newline at end of file diff --git a/yaksh/templates/yaksh/course_students.html b/yaksh/templates/yaksh/course_students.html new file mode 100644 index 0000000..03c57b8 --- /dev/null +++ b/yaksh/templates/yaksh/course_students.html @@ -0,0 +1,245 @@ +{% if is_students %} <!-- Start if course students --> +<!-- Upload Users --> +<div id="accordian-upload" class="card"> + <div class="card-header"> + <a class="card-link" data-toggle="collapse" href="#upload_users_csv"> + Upload Users <i class="fa fa-angle-down"></i> + </a> + </div> +</div> +<div id="upload_users_csv" class="collapse hide" data-parent="#accordion-upload"> + <div class="card-body"> + <form id="upload_users" action="{% url 'yaksh:upload_users' course.id %}" method="POST" enctype="multipart/form-data"> + {% csrf_token %} + <div class="input-group mb-3"> + <div class="custom-file"> + <input type="file" class="custom-file-input" name="csv_file" id="upload"/> + <label class="custom-file-label" for="upload">Choose file</label> + </div> + <div class="input-group-append"> + <button class="btn btn-outline-primary" type="submit"> + <i class="fa fa-upload"></i> + Upload + </button> + </div> + </div> + </form> + <hr> + <p> + - The uploaded csv should have headers exactly same as mentioned below:<br /> + <b>firstname, lastname, email, username, password, institute, roll_no, department, + remove</b><br /> + - Mandatory fields are <b> firstname, lastname and email. </b><br /> + - Other fields are optional. <br /> + - If username and password are not provided then + <b>Users created will have username and password same as their email</b> + </p> + <p> + <b> Click + <a class="btn btn-success" href="{% url 'yaksh:download_sample_csv' %}"> + here + </a> to download a sample CSV, edit and upload it</b> + </p> + </div> +</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"> + <a class="card-link" data-toggle="collapse" href="#requested"> + Requested Students <i class="fa fa-angle-down"></i> + </a> + </div> +</div> +<div id="requested" class="collapse hide" data-parent="#accordion-request"> + {% if requested %} + <br> + <input type="checkbox" class="checkall"/> + <font size="5">Select all</font> + <div id="enroll-all"> + <form action="{% url 'yaksh:enroll_users' course.id %}" method="post"> + {% csrf_token %} + <table id="requested_table" class="tablesorter table table-striped table-responsive-sm course-detail" data-sortlist="[1,0]"> + <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>Enroll/Reject</th> + </thead> + <tbody> + {% for request in requested %} + <tr> + <td> + {{ forloop.counter }}. + <input type="checkbox" name="check" value="{{ request.id }}"> + </td> + <td>{{request.get_full_name}}</td> + <td> {{request.email}}</td> + {% with request.profile as request_profile %} + <td> {{request_profile.roll_number}}</td> + <td> {{request_profile.institute}}</td> + <td> {{request_profile.department}}</td> + {% endwith %} + <td> + <a class="btn btn-success" + href="{% url 'yaksh:enroll_user' course.id request.id %}"> + <i class="fa fa-plus-square"></i> + Enroll </a> + <a class="btn btn-danger" + href="{% url 'yaksh:reject_user' course.id request.id %}"> + <i class="fa fa-minus-square"></i> + Reject </a> + </td> + </tr> + {% endfor %} + </tbody> + </table> + <button class="btn btn-success btn-lg" type="submit" name='enroll' value='enroll'> + <i class="fa fa-plus-square"></i> + Enroll Selected + </button> <br> + </form> + </div> + {% else %} + <center> + <span class="badge badge-warning"><big> No requests yet</big></span> + </center> + {% endif %} +</div> +<!-- End Requested Students --> +<br> +<!-- Rejected Students --> +<div id="accordian-rejected" class="card"> + <div class="card-header"> + <a class="card-link" data-toggle="collapse" href="#rejected"> + Rejected Students <i class="fa fa-angle-down"></i> + </a> + </div> +</div> +<div id="rejected" class="collapse hide" data-parent="#accordion-rejected"> + {% if rejected %} + <br> + <input type="checkbox" class="enroll"/> + <font size="5">Select all</font> + <div id="enroll"> + <form action="{% url 'yaksh:enroll_rejected' course.id %}" method="post"> + {% csrf_token %} + <table id="rejected_table" class="tablesorter table table-striped table-responsive-sm course-detail" data-sortlist="[1,0]"> + <thead> + <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>Enroll</th> + </thead> + <tbody> + {% for reject in rejected %} + <tr> + <td> + {{ forloop.counter }}. + <input type="checkbox" name="check" value="{{ reject.id }}"> + </td> + <td>{{reject.get_full_name|title}}</td> + <td> {{reject.email}}</td> + {% with reject.profile as reject_profile %} + <td> {{reject_profile.roll_number}}</td> + <td> {{reject_profile.institute}}</td> + <td> {{reject_profile.department}}</td> + {% endwith %} + <td> + <a class="btn btn-success" + href="{% url 'yaksh:enroll_rejected' course.id reject.id %}"> + <i class="fa fa-plus-square"></i> + Enroll </a> + </td> + </tr> + {% endfor %} + </tbody> + </table> + <br> + <button class="btn btn-success btn-lg" type="submit" name='enroll' value='enroll'> + <i class="fa fa-plus-square"></i> + Enroll Selected + </button> + <br> + </form> + </div> + {% else %} + <center> + <span class="badge badge-warning"><big> No rejected students yet</big></span> + </center> + {% endif %} +</div> +<!-- End Rejected Students --> +{% endif %}
\ No newline at end of file diff --git a/yaksh/templates/yaksh/course_teachers.html b/yaksh/templates/yaksh/course_teachers.html new file mode 100644 index 0000000..1b1af87 --- /dev/null +++ b/yaksh/templates/yaksh/course_teachers.html @@ -0,0 +1,29 @@ +<center><h3>Teacher(s)/TA(s)</h3></center> +<br> + +{% if teachers %} + <form action="{% url 'yaksh:remove_teacher' course.id %}" method="post"> + {% csrf_token %} + <div class="container"> + <table class="table table-responsive-sm course-detail"> + <tr> + <th>Select</th> + <th>Name</th> + </tr> + {% for teacher in teachers %} + <tr> + <td><input type="checkbox" name="remove" value="{{ teacher.id }}"></td> + <td>{{ teacher.get_full_name }}</td> + </tr> + {% endfor %} + <table> + </div> + <br> + <button class="btn btn-danger" type="submit" data-toggle="tooltip" title="Remove Selected Teachers from this course"> + <i class="fa fa-minus-square"></i> + Remove Teachers + </button> + </form> +{% else %} + <center><b class="badge badge-warning">No Teacher(s) added</b></center> +{% endif %}
\ No newline at end of file diff --git a/yaksh/templates/yaksh/courses.html b/yaksh/templates/yaksh/courses.html index e5f3936..5d2c913 100644 --- a/yaksh/templates/yaksh/courses.html +++ b/yaksh/templates/yaksh/courses.html @@ -22,11 +22,6 @@ </a> </li> <li class="nav-item"> - <a class="nav-link {% if allotted %}active{% endif %}" href="{% url 'yaksh:allotted_courses' %}"> - Allotted Courses - </a> - </li> - <li class="nav-item"> <a class="nav-link" href="{% url 'yaksh:add_course' %}"> Add New Course </a> @@ -35,16 +30,16 @@ <a class="nav-link dropdown-toggle" data-toggle="dropdown" href="#" role="button" aria-haspopup="true" aria-expanded="true">More</a> <div class="dropdown-menu hide" x-placement="bottom-start" style="position: absolute; transform: translate3d(0px, 37px, 0px); top: 0px; left: 0px; will-change: transform;"> <a class="dropdown-item" href="{% url 'yaksh:show_all_quizzes' %}"> - View Quizzes + Add/View Quizzes </a> <a class="dropdown-item" href="{% url 'yaksh:show_all_lessons' %}"> - View Lessons + Add/View Lessons </a> <a class="dropdown-item" href="{% url 'yaksh:show_all_modules' %}"> - View Modules + Add/View Modules </a> <a href="{% url 'grades:grading_systems'%}" class="dropdown-item" > - View Grading Systems + Add/View Grading Systems </a> </div> </li> @@ -52,20 +47,17 @@ </div> </div> </div> - {% if not objects %} - <center> - <h2> No Courses Found </h2> - <br> - <a href="{% url 'yaksh:add_course' %}" class="btn btn-success btn-lg"> - <span class=" fa fa-plus-circle"></span> Add Course - </a> - </center> - {% else %} - <div class="container"> + <div class="container"> + {% if not objects %} + <br><br> + <div class="alert alert-info"> + <center> <h3> No Courses Found </h3> </center> + </div> + {% else %} <hr> {% if messages %} {% for message in messages %} - <div class="alert alert-dismissible alert-info"> + <div class="alert alert-dismissible alert-{{ message.tags }}"> <button type="button" class="close" data-dismiss="alert"> <i class="fa fa-close"></i> </button> @@ -74,28 +66,121 @@ {% endfor %} {% endif %} {% with objects as courses %} - {% include "yaksh/paginator.html" %} <div class="row"> - <br> - {% for course in courses %} - <div class="col-md-6"> - <div class="card border-primary"> - <div class="card-header" style="height: 150px"> - {{course.name}} - </div> - <div class="card-body"> - <div class="row"> - <div class="col"> - <strong>Starts On:</strong> - {{course.start_enroll_time}} - <br> - <strong>Ends On:</strong> - {{course.end_enroll_time}} + <div class="col-md-4"> + {% include "yaksh/paginator.html" %} + </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> + </div> + </div> + </div> + + <div class="tab-content"> + <div class="tab-pane active" id="gridview" role="tabpanel" aria-labelledby="gridbtn"> + <!-- GridView --> + <br> + <div class="row"> + <br> + {% for course in courses %} + <div class="col-md-6"> + <div class="card border-primary"> + <div class="card-header" style="height: 150px"> + {{course.name}} + </div> + <div class="card-body"> + <div class="row"> + <div class="col"> + <strong>Starts On:</strong> + {{course.start_enroll_time}} + <br> + <strong>Ends On:</strong> + {{course.end_enroll_time}} + </div> + </div> + <hr> + <div class="row"> + <div class="col-md-5"> + <span class="badge badge-pill badge-info"> + {% if user.id != course.creator.id %} + Allotted Course + {% else %} + Created Course + {% endif %} + </span> + </div> + <div class="col-md-3"> + {% if course.active %} + <span class="badge badge-pill badge-success"> + Active + </span> + {% else %} + <span class="badge badge-pill badge-danger"> + Inactive + </span> + {% endif %} + </div> + <div class="col-md-4"> + <a href="{% url 'yaksh:toggle_course_status' course.id %}"> + {% if course.active %} + <i class="fa fa-toggle-on fa-2x"></i> + {% else %} + <i class="fa fa-toggle-off fa-2x"></i> + {% endif %} + </a> + </div> + </div> + <hr> + <div class="row"> + <div class="col-md-4"> + <a href="{% url 'yaksh:edit_course' course.id %}" class="btn btn-info"> + <i class="fa fa-edit"></i> + Edit Course + </a> + </div> + <div class="col-md-4"> + <a href="{% url 'yaksh:course_detail' course.id %}" class="btn btn-primary"> + <i class="fa fa-tasks"></i> + Manage Course + </a> + </div> + <div class="col-md-4"> + <a href="{% url 'yaksh:download_course_csv' course.id %}" class="btn btn-secondary"> + <i class="fa fa-download"></i> + Download CSV + </a> + </div> + </div> </div> </div> - <hr> + <br> + </div> + {% endfor %} + <br> + </div> + </div> + <div class="tab-pane" id="listview" role="tabpanel" aria-labelledby="gridbtn"> + <!-- ListView --> + <br> + {% for course in courses %} + <div class="card"> + <div class="card-header"> <div class="row"> - <div class="col-md-6"> + <div class="col-md-5"> + {{course.name}} + </div> + <div class="col-md-3"> + <span class="badge badge-pill badge-info"> + {% if user.id != course.creator.id %} + Allotted Course + {% else %} + Created Course + {% endif %} + </span> + </div> + <div class="col-md-2"> {% if course.active %} <span class="badge badge-pill badge-success"> Active @@ -106,8 +191,8 @@ </span> {% endif %} </div> - <div class="col-md-6"> - <a href="{{URL_ROOT}}/exam/manage/toggle_status/{{ course.id }}/"> + <div class="col-md-2"> + <a href="{% url 'yaksh:toggle_course_status' course.id %}"> {% if course.active %} <i class="fa fa-toggle-on fa-2x"></i> {% else %} @@ -116,20 +201,34 @@ </a> </div> </div> + </div> + <div class="card-body"> + <div class="row"> + <div class="col"> + <strong>Starts On:</strong> + {{course.start_enroll_time}} + <br> + <strong>Ends On:</strong> + {{course.end_enroll_time}} + </div> + </div> <hr> <div class="row"> <div class="col-md-4"> - <a href="{{URL_ROOT}}/exam/manage/edit_course/{{course.id}}" class="btn btn-primary"> + <a href="{% url 'yaksh:edit_course' course.id %}" class="btn btn-info"> + <i class="fa fa-edit"></i> Edit Course </a> </div> <div class="col-md-4"> - <a href="{% url 'yaksh:course_detail' course.id %}" class="btn btn-info"> + <a href="{% url 'yaksh:course_detail' course.id %}" class="btn btn-primary"> + <i class="fa fa-tasks"></i> Manage Course </a> </div> <div class="col-md-4"> - <a href="{{URL_ROOT}}/exam/manage/courses/download_course_csv/{{course.id}}" class="btn btn-secondary"> + <a href="{% url 'yaksh:download_course_csv' course.id %}" class="btn btn-secondary"> + <i class="fa fa-download"></i> Download CSV </a> </div> @@ -137,13 +236,13 @@ </div> </div> <br> - </div> - {% endfor %} - <br> + {% endfor %} + <br> + </div> </div> {% include "yaksh/paginator.html" %} {% endwith %} - </div> - {% endif %} + {% endif %} + </div> </div> {% endblock %}
\ No newline at end of file diff --git a/yaksh/templates/yaksh/design_course_session.html b/yaksh/templates/yaksh/design_course_session.html index a2d9b08..a15f4b1 100644 --- a/yaksh/templates/yaksh/design_course_session.html +++ b/yaksh/templates/yaksh/design_course_session.html @@ -1,30 +1,20 @@ -{% extends "manage.html" %} -{% load custom_filters %} -{% block title %}Design Course Session{% endblock %} +{% load static %} -{% block pagetitle %}Design Course Session{% endblock %} +{% block title %} <center> <h3> Design Course Session </h3> </center>{% endblock %} {% block script %} -<script src="{{ URL_ROOT }}/static/yaksh/js/jquery-3.3.1.min.js"></script> -<script src="{{ URL_ROOT }}/static/yaksh/js/design_course.js"></script> +<script language="JavaScript" type="text/javascript" src="{% static 'yaksh/js/design_course.js' %}"></script> {% endblock %} {% block css %} -<link rel="stylesheet" media="all" type="text/css" href="{{ URL_ROOT }}/static/yaksh/css/design_course.css" /> +<link rel="stylesheet" href="{% static 'yaksh/css/design_course.css' %}"> {% endblock %} -{% block main %} -<div class="yakshwell container"> -<a href="{{URL_ROOT}}/exam/manage/courses/" class="btn btn-primary"> - Back to Courses -</a> -<br/> -<br/> -<form action="{{URL_ROOT}}/exam/manage/courses/designcourse/{{course_id}}/" method="POST" id="design_course_form"> +<form action="{% url 'yaksh:design_course' course.id %}" method="POST" id="design_course_form"> {% csrf_token %} - <div class="tab-pane active" id="available-lesson-quiz"> + <div id="available-lesson-quiz"> <div class="row"> - <div class="col-md-8 col-md-offset-2 available-list"> + <div class="col-md-12 available-list"> <div id="fixed-available-wrapper"> <p><u><b>Available Modules:</b></u></p> <div id="fixed-available"> @@ -61,11 +51,12 @@ </div> <br> <center> - <button id="Add" name="Add" class="btn btn-success" type="submit">Add to course</button> + <button id="Add" name="Add" class="btn btn-success" type="submit"> + <i class="fa fa-plus-square"></i> Add to course</button> </center> <br><br> </div> - <div class="col-md-8 col-md-offset-2"> + <div class="col-md-12"> <div id="fixed-added-wrapper"> <p><u><b>Chosen Modules:</b></u></p> <div id="fixed-added"> @@ -136,8 +127,8 @@ </div> <br> <center> - <button id="Remove" name="Remove" class="btn btn-danger" type="submit">Remove from course</button> - <button id="Change" name="Change" class="btn btn-info" type="submit"> Change Order</button> + <button id="Remove" name="Remove" class="btn btn-danger" type="submit"><i class="fa fa-minus-square"></i> Remove from course</button> + <button id="Change" name="Change" class="btn btn-info" type="submit"><i class="fa fa-reorder"></i> Change Order</button> <button id="Change" name="change_prerequisite_completion" class="btn btn-primary" type="submit"> Change Prerequisite Completion</button> <button id="Change_prereq_passing" name="change_prerequisite_passing" class="btn btn-primary" type="submit"> Change Prerequisite Passing</button> @@ -145,6 +136,4 @@ </div> </div> <!-- /.row --> </div> -</form> -</div> -{% endblock %}
\ No newline at end of file +</form>
\ No newline at end of file diff --git a/yaksh/templates/yaksh/design_questionpaper.html b/yaksh/templates/yaksh/design_questionpaper.html index 0ab7cc0..6e916a3 100644 --- a/yaksh/templates/yaksh/design_questionpaper.html +++ b/yaksh/templates/yaksh/design_questionpaper.html @@ -1,39 +1,36 @@ {% extends "manage.html" %} +{% load static %} {% block title %} Design Question Paper {% endblock title %} {% block subtitle %} Design Question Paper {% endblock %} {% block css %} - <link rel="stylesheet" media="all" type="text/css" href="{{ URL_ROOT }}/static/yaksh/css/question_paper_creation.css" /> -<style> -select -{ - width:auto; -} -</style> + <link rel="stylesheet" media="all" type="text/css" href="{% static 'yaksh/css/question_paper_creation.css' %}" /> {% endblock %} {% block script %} - <script src="{{ URL_ROOT }}/static/yaksh/js/jquery-3.3.1.min.js"></script> - <script src="{{ URL_ROOT }}/static/yaksh/js/jquery-ui.js"></script> - <script src="{{ URL_ROOT }}/static/yaksh/js/bootstrap.min.js"></script> - <script src="{{ URL_ROOT }}/static/yaksh/js/question_paper_creation.js"></script> + <script src="{% static 'yaksh/js/jquery-ui.js' %}"></script> + <script src="{% static 'yaksh/js/question_paper_creation.js' %}"></script> {% endblock %} {% block content %} -<div class="yakshwell container"> +<div class="container"> <input type=hidden id="url_root" value={{ URL_ROOT }}> {% if course_id %} - <form action="{{ URL_ROOT }}/exam/manage/designquestionpaper/{{ qpaper.quiz.id }}/{{ qpaper.id }}/{{course_id}}/" method="POST" id="design_q"> - <a href="{{URL_ROOT}}/exam/manage/courses" class="btn btn-danger">Cancel</a> + <form action="{% url 'yaksh:designquestionpaper' qpaper.quiz.id qpaper.id course_id %}" method="POST" id="design_q"> + <a href="{% url 'yaksh:get_course_modules' course_id %}" class="btn btn-primary"> + <i class="fa fa-arrow-left"></i> Back + </a> {% else %} - <form action="{{ URL_ROOT }}/exam/manage/designquestionpaper/{{ qpaper.quiz.id }}/{{ qpaper.id }}/" method="POST" id="design_q"> - <a href="{{URL_ROOT}}/exam/manage/courses/all_quizzes" class="btn btn-danger">Cancel</a> + <form action="{% url 'yaksh:designquestionpaper' qpaper.quiz.id qpaper.id %}" method="POST" id="design_q"> + <a href="{% url 'yaksh:show_all_quizzes' %}" class="btn btn-primary"> + <i class="fa fa-arrow-left"></i> Back + </a> {% endif %} {% csrf_token %} <input type=hidden name="is_active" id="is_active" value="{{ state }}"> -<center><b>Manual mode to design the {{lang}} Question Paper</center><br> + <center><b>Manual mode to design the {{lang}} Question Paper</center><br> <div class = "tab-base"> <ul class="nav nav-pills tabs"> <li id="fixed-tab"> @@ -55,86 +52,105 @@ select </a></li> </ul> </div> + <br> <div> - <h3>Total Marks: <span id="total_marks" class="well"> {{ qpaper.total_marks }} </span></h3> + <h3>Total Marks: + <span id="total_marks" class="well"> {{ qpaper.total_marks }}</span> + </h3> </div> -<div class="tab-content"> - <!-- common to fixed and random questions --> - <div class="row" id="selectors"> - <div class = "col-md-8"> - <h5>Please select Question type and Marks</h5> + <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> - <div class="col-md-6"> - {{ filter_form.question_type }} - </div> - <div class="col-md-6"> - {{ filter_form.marks }} - </div> - </div> <!-- /.row --> - <br><br> - {% csrf_token %} - <div class="tab-pane active" id="fixed-questions"> - <h4>Or</h4> - <!-- Search questions using tags --> - <h4>Search using Tags: </h4> - <span class="input-group-addon" id="basic-addon1">Search Questions: </span> - <div class="col-md-14"> - <div class="input-group"> - <input type="text" id="question_tags" name="question_tags" class="form-control" - placeholder="Search using comma separated Tags"> - <span class="input-group-btn"> - <button class="btn btn-default" type="submit">Search</button> - </span> + {% endfor %} + {% endif %} + <div class="tab-content"> + <!-- common to fixed and random questions --> + <div class="row" id="selectors"> + <div class = "col-md-8"> + <h5>Please select Question type and Marks</h5> + </div> <div class="col-md-6"> - <select class="form-control" id="sel1" onchange="append_tag(this);"> - {% if all_tags %} - <option value="" disabled selected>Available Tags</option> - {% for tag in all_tags %} - <option> - {{tag}} - </option> - {% endfor %} - {% else %} - <option value="" disabled selected>No Available Tags</option> - {% endif %} - </select> + {{ filter_form.question_type }} </div> - </div> - </div> - <br><br> - <div class="row"> <div class="col-md-6"> - <div id="fixed-available-wrapper"> - <p><u>Select questions to add:</u></p> - <div id="fixed-available"> - {% if state == "fixed" or state == "None" %} - <ul class="inputs-list"> - {% for question in questions %} - <li> - <label> - <input type="checkbox" name="questions" data-qid="{{question.id}}" value={{question.id}}> - <span> - {% if user == question.user %} - <a href="{{URL_ROOT}}/exam/manage/addquestion/{{ question.id }}" target="_blank">{{ question.summary }}</a> - {% else %} - {{question.summary}} - {% endif %} - </span> - <span> {{ question.points }}</span> - </label> - </li> - {% endfor %} - </ul> - {% endif %} - </div> - <br /><br /> - <button id="add-fixed" name="add-fixed" class="btn small btn-primary pull-right" type="submit">Add to paper</button> + {{ filter_form.marks }} + </div> + </div> <!-- /.row --> + <br> + {% csrf_token %} + <div class="tab-pane active" id="fixed-questions"> + <h4>Or</h4> + <!-- Search questions using tags --> + <h4>Search using Tags: </h4> + <span class="input-group-addon" id="basic-addon1">Search Questions: </span> + <div class="col-md-14"> + <div class="input-group"> + <input type="text" id="question_tags" name="question_tags" class="form-control" + placeholder="Search using comma separated Tags"> + <span class="input-group-btn"> + <button class="btn btn-outline-primary" type="submit"> + <i class="fa fa-search"></i> Search + </button> + </span> + <div class="col-md-6"> + <select class="form-control" id="sel1" onchange="append_tag(this);"> + {% if all_tags %} + <option value="" disabled selected>Available Tags</option> + {% for tag in all_tags %} + <option> + {{tag}} + </option> + {% endfor %} + {% else %} + <option value="" disabled selected>No Available Tags</option> + {% endif %} + </select> </div> </div> - <div class="col-md-6"> - <div id="fixed-added-wrapper"> - <p><u>Fixed questions currently in paper:</u></p> - <div id="fixed-added"> + </div> + <br><br> + <br> + <div class="row"> + <div class="col-md-6"> + <div id="fixed-available-wrapper"> + <p><u>Select questions to add:</u></p> + <div id="fixed-available"> + {% if state == "fixed" or state == "None" %} + <ul class="inputs-list"> + {% for question in questions %} + <li> + <label> + <input type="checkbox" name="questions" data-qid="{{question.id}}" value={{question.id}}> + <span> + {% if user == question.user %} + <a href="{% url 'yaksh:add_question' question.id %}" target="_blank">{{ question.summary }}</a> + {% else %} + {{question.summary}} + {% endif %} + </span> + <span> {{ question.points }}</span> + </label> + </li> + {% endfor %} + </ul> + {% endif %} + </div> + </div> + <br /> + <button id="add-fixed" name="add-fixed" class="btn btn-success pull-right" type="submit"> + <i class="fa fa-plus-square"></i> Add to paper + </button> + </div> + <div class="col-md-6"> + <div id="fixed-added-wrapper"> + <p><u>Fixed questions currently in paper:</u></p> + <div id="fixed-added"> <ul class="inputs-list"> {% for question in fixed_questions %} <li> @@ -143,7 +159,7 @@ select data-qid="{{question.id}}" value={{question.id}}> <span> {% if user == question.user %} - <a href="{{URL_ROOT}}/exam/manage/addquestion/{{ question.id }}" target="_blank">{{ question.summary }}</a> + <a href="{% url 'yaksh:add_question' question.id %}" target="_blank">{{ question.summary }}</a> {% else %} {{question.summary}} {% endif %} @@ -153,119 +169,125 @@ select </li> {% endfor %} </ul> + </div> </div> - <br /> - <button id="remove-fixed" name="remove-fixed" class="btn btn-danger pull-right" type="submit"> Remove from paper</button> + <br /> + <button id="remove-fixed" name="remove-fixed" class="btn btn-danger pull-right" type="submit"> + <i class="fa fa-minus-square"></i> Remove from paper + </button> </div> + </div> <!-- /.row --> + <br> + <div class="pull-right"> + <a class="btn btn-info" id="fixed-next">Next ></a> </div> - </div> <!-- /.row --> - <br> - <div class="pull-right"> - <a class="btn btn-info" id="fixed-next">Next ></a> - </div> - </div> <!-- /#fixed-questions --> + </div> <!-- /#fixed-questions --> - <div class="tab-pane" id="random-questions"> - <div class="row"> - <div class="col-md-6"> - <div id="random-available-wrapper"> - <p><u>Select questions to add to the pool:</u></p> - <div id="random-available"> - {% if state == "random" %} - <select id="num_of_questions" name="num_of_questions"> - <option value="1">Number of questions to be picked from the pool</option> - {% for q in questions %} - {% if forloop.counter0 != 0 %} - <option value={{forloop.counter0}}>{{ forloop.counter0}}</option> + <div class="tab-pane" id="random-questions"> + <div class="row"> + <div class="col-md-6"> + <div id="random-available-wrapper"> + <p><u>Select questions to add to the pool:</u></p> + <div id="random-available"> + {% if state == "random" %} + <select id="num_of_questions" name="num_of_questions"> + <option value="1">Number of questions to be picked from the pool</option> + {% for q in questions %} + {% if forloop.counter0 != 0 %} + <option value={{forloop.counter0}}>{{ forloop.counter0}}</option> + {% endif %} + {% if questions|length == 1%} + <option value=1>1</option> {% endif %} - {% if questions|length == 1%} - <option value=1>1</option> - {% endif %} + {% endfor %} + </select> + <ul class="inputs-list"> + {% for question in questions %} + <li> + <label> + <input type="checkbox" name="random_questions" data-qid="{{question.id}}" value={{question.id}}> + <span> + {% if user == question.user %} + <a href="{% url 'yaksh:add_question' question.id %}" target="_blank">{{ question.summary }}</a> + {% else %} + {{question.summary}} + {% endif %}</span> + <span> {{ question.points }} </span> + </label> + </li> {% endfor %} - </select> - <ul class="inputs-list"> - {% for question in questions %} - <li> - <label> - <input type="checkbox" name="random_questions" data-qid="{{question.id}}" value={{question.id}}> - <span> - {% if user == question.user %} - <a href="{{URL_ROOT}}/exam/manage/addquestion/{{ question.id }}" target="_blank">{{ question.summary }}</a> - {% else %} - {{question.summary}} - {% endif %}</span> - <span> {{ question.points }} </span> - </label> - </li> - {% endfor %} - </ul> - {% endif %} + </ul> + {% endif %} + </div> </div> - <br /><br /> - <button id="add-random" name="add-random" class="btn btn-primary pull-right" type="submit">Add to paper</button> + <br> + <button id="add-random" name="add-random" class="btn btn-success pull-right" type="submit"> + <i class="fa fa-plus-square"></i> Add to paper + </button> </div> - </div> - <div class="col-md-6"> - <div id="random-added-wrapper"> - <p><u>Pool of questions currently in paper:</u></p> - <div id="random-added"> - <ul class="inputs-list"> - {% for random_set in random_sets %} - <li> - <label> - <input type="checkbox" name="random_sets" data-qid="{{random_set.id}}" value={{random_set.id}}> - <span> Random Set {{ forloop.counter }} (will take {{ random_set.num_questions }} randomly out of {{ random_set.questions.count }})</span> - </label> - </li> - {% for question in random_set.questions.all %} - <li> - <label> - <span> - {% if user == question.user %} - <a href="{{URL_ROOT}}/exam/manage/addquestion/{{ question.id }}" target="_blank">{{ question.summary }}</a> - {% else %} - {{question.summary}} - {% endif %}</span> - <span> {{ question.points }} </span> - </label> - </li> + <div class="col-md-6"> + <div id="random-added-wrapper"> + <p><u>Pool of questions currently in paper:</u></p> + <div id="random-added"> + <ul class="inputs-list"> + {% for random_set in random_sets %} + <li> + <label> + <input type="checkbox" name="random_sets" data-qid="{{random_set.id}}" value={{random_set.id}}> + <span> Random Set {{ forloop.counter }} (will take {{ random_set.num_questions }} randomly out of {{ random_set.questions.count }})</span> + </label> + </li> + {% for question in random_set.questions.all %} + <li> + <label> + <span> + {% if user == question.user %} + <a href="{% url 'yaksh:add_question' question.id %}" target="_blank">{{ question.summary }}</a> + {% else %} + {{question.summary}} + {% endif %}</span> + <span> {{ question.points }} </span> + </label> + </li> + {% endfor %} {% endfor %} - {% endfor %} - </ul> + </ul> + </div> </div> <br /> - <button id="remove-random" name="remove-random" class="btn btn-danger pull-right" type="submit"> Remove from paper</button> + <button id="remove-random" name="remove-random" class="btn btn-danger pull-right" type="submit"> + <i class="fa fa-minus-square"></i> Remove from paper + </button> </div> - </div> - </div> <!-- /.row --> - <br> - <div class="pull-left"> - <a class="btn btn-info" id="random-prev">< Previous</a> - </div> - <div class="pull-right"> - <a class="btn btn-info" id="random-next">Next ></a> - </div> - </div> <!-- /#random-questions --> - - <div class="tab-pane" id="finish"> - <center> - <h5><u>Almost finished creating your question paper</u></h5> - <label style="float: none;"> - {{ qpaper_form.shuffle_questions }} - <span>Shuffle questions' order for each student</span> - </label> <br><br> - <label style="float: none;"> - {{ qpaper_form.shuffle_testcases }} - <span>Shuffle MCQ/MCC options for each student</span> - </label> <br><br> - <input class ="btn btn-success" type="submit" name="save" id="save" value="Save question paper"> + </div> <!-- /.row --> <br> <div class="pull-left"> - <a class="btn btn-info" id="finish-prev">< Previous</a> + <a class="btn btn-info" id="random-prev">< Previous</a> </div> - </center> - </div> <!-- /#finish --> -</div> + <div class="pull-right"> + <a class="btn btn-info" id="random-next">Next ></a> + </div> + </div> <!-- /#random-questions --> + + <div class="tab-pane" id="finish"> + <center> + <h5><u>Almost finished creating your question paper</u></h5> + <label style="float: none;"> + {{ qpaper_form.shuffle_questions }} + <span>Shuffle questions' order for each student</span> + </label> <br><br> + <label style="float: none;"> + {{ qpaper_form.shuffle_testcases }} + <span>Shuffle MCQ/MCC options for each student</span> + </label> <br><br> + <input class="btn btn-success btn-lg" type="submit" name="save" id="save" value="Save"> + <br> + <div class="pull-left"> + <a class="btn btn-info" id="finish-prev">< Previous</a> + </div> + </center> + </div> <!-- /#finish --> + </div> <!-- /.tab-content --> </form> <br> diff --git a/yaksh/templates/yaksh/error_template.html b/yaksh/templates/yaksh/error_template.html index 5530844..9cfeac1 100644 --- a/yaksh/templates/yaksh/error_template.html +++ b/yaksh/templates/yaksh/error_template.html @@ -1,12 +1,17 @@ +{% load static %} +{% block css%} + <link rel="stylesheet" href="{% static 'yaksh/css/dashboard.css' %}" type="text/css" /> +{% endblock %} +{% block script %} + <script src="{% static 'yaksh/js/jquery-ui.js' %}"></script> +{% endblock %} {% load custom_filters %} {% if error_message %} -<div class="container-fluid row justify-content-center"> {% for error in error_message %} -<div class="col-md-10 yakshwell"> <div class="card "> <div class="card-header alert-danger">Error No. {{ forloop.counter }}</div> - <div class="card-body "> + <div class="card-body "> <div class=""> {% if not error.type %} <pre><code> {{error|safe}} </code></pre> @@ -64,8 +69,8 @@ </tr> {% for expected,user in error.expected_output|zip:error.user_output %} <td> {{forloop.counter}} </td> - <td>{{expected|default:""}} </td> - <td>{{user|default:""}}</td> + <td>{{expected|default:""|highlight_spaces|safe}} </td> + <td>{{user|default:""|highlight_spaces|safe}}</td> {% if forloop.counter0 in error.error_line_numbers or not expected or not user %} <td><span class ="fa fa-times text-warning"/></td> {% else %} @@ -85,7 +90,7 @@ </div> </div> </div> + <br> </div> - {% endfor %} -</div> + {% endfor %} {% endif %}
\ No newline at end of file diff --git a/yaksh/templates/yaksh/grade_user.html b/yaksh/templates/yaksh/grade_user.html index a76f2c7..e3888b8 100644 --- a/yaksh/templates/yaksh/grade_user.html +++ b/yaksh/templates/yaksh/grade_user.html @@ -1,15 +1,15 @@ {% extends "manage.html" %} {% load custom_filters %} +{% load static %} {% block title %} Grade User {% endblock %} {% block pagetitle %} Grade User {% endblock pagetitle %} -{% block content %} -<div class="yakshwell container"> {% block script %} -<script src="{{ URL_ROOT }}/static/yaksh/js/jquery.tablesorter.min.js"></script> -<script src="{{ URL_ROOT }}/static/yaksh/js/mathjax/MathJax.js?config=TeX-MML-AM_CHTML"></script> +<script type="text/javascript" src="{% static 'yaksh/js/jquery.tablesorter.min.js' %}"> +</script> +<script type="text/javascript" src="{% static 'yaksh/js/mathjax/MathJax.js' %}?config=TeX-MML-AM_CHTML"></script> <script type="text/javascript"> $(document).ready(function() { @@ -19,371 +19,486 @@ $(document).ready(function() </script> {% endblock script %} -{% if course_details %} -<div class="table-wrapper-2"> - <table id="course-details" class="table table-bordered table-responsive-sm"> - <tr class="yakshlabel yakshred text-center"> - <th><i class="fa fa-book"></i> Courses</th> - <th><i class="fa fa-puzzle-piece"></i> Quizzes </th> - </tr> - - {% for course in course_details %} - <tr> - <td><ul class="list-group">{{course.name}} </td> - - {% if course.get_quizzes %} - <td> - {% for quiz in course.get_quizzes %} - <li class="list-group-item"><a href = "{{URL_ROOT}}/exam/manage/gradeuser/{{quiz.id}}/{{course.id}}/"> - {{quiz.description}} - </a></li> - {% endfor %} - </td> - {% else %} - <td> No quiz</td> - {% endif %} - </ul></tr> - {% endfor %} - </table> - </div> -{% endif %} - -<div class="row"> -{% if not course_details %} -{% if users %} - <div id = "student" class="col-md-2"> - {% for user in users %} - <p><a href = "{{URL_ROOT}}/exam/manage/gradeuser/{{quiz_id}}/{{user.user__id}}/{{course_id}}/" class="btn btn-primary"> - {{user.user__first_name}} {{user.user__last_name}}</a></p> - {% endfor %} +{% block content %} +<div class="container"> +{% if objects %} + {% include "yaksh/paginator.html" %} + <div id="accordion"> + {% for course in objects %} + <div class="card"> + <div class="card-header"> + <div class="row"> + <div class="col-md-9"> + <h5 data-toggle="tooltip" title="{{course.name}}"> + {{ course.name }} + </h5> + </div> + <div class="col-md"> + <a class="card-link btn btn-info" data-toggle="collapse" href="#collapse{{course.id}}"> + Details + <i class="fa fa-toggle-down" id="toggle_course_{{course.id}}"></i> + </a> + </div> + </div> + </div> + <div id="collapse{{course.id}}" class="collapse hide" data-parent="#accordion"> + <div class="card-body"> + {% with course.get_quizzes as quizzes %} + {% if quizzes %} + <ul class="list-group"> + {% for quiz in quizzes %} + <li class="list-group-item"> + <div class="row"> + <div class="col-md-8"> + {{quiz.description}} + </div> + <div class="col-md-2"> + <a href="{% url 'yaksh:grade_user' quiz.id course.id%}" class="btn btn-primary"> + Grade + </a> + </div> + </div> + </li> + {% endfor %} + </ul> + {% else %} + <center> + <p class="badge badge-danger badge-pill"> + No Quizzes + </p> + </center> + {% endif %} + {% endwith %} + </div> + </div> + </div> + <br> + {% endfor %} </div> -{% else %} -<center> - <div class="alert-warning alert animated flash"> -<h4>No Users Found for {{ quiz.description }}</h4> -</center> -{% endif %} -{% endif %} - -{% if has_quiz_assignments %} - -<a href="{{URL_ROOT}}/exam/manage/download/quiz_assignments/{{quiz_id}}/{{course_id}}" class="btn btn-outline-info"> - Download All Assignments</a> -{% endif %} - -<div id = "paper" class="col-md-10"> -{% if data %} - - -<p> <h3> <center> Showing paper for {{data.user.get_full_name.title}} </center></h3> -<p><b>Name:</b> {{ data.user.get_full_name.title }} -{% if data.profile %} - -<p><b> Roll number:</b> {{ data.profile.roll_number }} -<p><b>Position: </b> {{ data.profile.position }} -<p><b>Department: </b>{{ data.profile.department }} -<p><b>Institute: </b>{{ data.profile.institute }} -{% endif %} - -{% if data.papers %} - -{% for paper in data.papers %} -<hr> -{{ paper.total_marks }} - -<h4> Course: {{ paper.question_paper.quiz.course.name }}</h4> -<h4> Quiz: {{ paper.question_paper.quiz.description }} </h4> - -<p> -Attempt Number: <b>{{paper.attempt_number}} </b> -<select id = "attempt" onchange="window.location.href=this.value"> -<option selected="">Select attempt number</option> -{%for attempt in attempts %} -<option value = "{{URL_ROOT}}/exam/manage/gradeuser/{{quiz_id}}/{{user_id}}/{{attempt.attempt_number}}/{{course_id}}/"> -{{attempt.attempt_number}} -</option> -{% endfor %} -</select> -<br/>Questions correctly answered: {{ paper.get_answered_str }} <br/> -Total attempts at questions: {{ paper.answers.count }} <br/> -Marks obtained: {{ paper.marks_obtained }} <br/> -Start time: {{ paper.start_time }} <br/> -End time: {{ paper.end_time }} <br/> -{%if paper.percent%} -Percentage obtained: {{paper.percent}}% <br/> -{% endif %} -{% if paper.passed %} -Status : <b style="color: green;"> Passed </b><br/> -{% else %} -Status : <b style="color: red;"> Failed </b><br/> + {% include "yaksh/paginator.html" %} +{% elif msg == 'grade' and not objects %} + <br> + <div class="alert alert-info"> + <center><h3>No courses found to grade</h3></center> + </div> {% endif %} -</p> -{% if paper.answers.count %} - -<h4> Report </h4><br> -<table class="tablesorter table table-striped table-bordered table-responsive-sm" id ='marks_table'> - <thead> - <tr class="yakshlabel text-center yakshred"> - <th>Question Id</th> - <th>Questions</th> - <th>Marks Obtained</th> - </tr> - </thead> - <tbody> - {% for question, answers in paper.get_question_answers.items %} - {% with answers|last as answer %} - <tr> - <td>{{question.id}}</td> - <td><a href="#question_{{question.id}}">{{ question.summary }}</a></td> - <td>{{ answer.answer.marks }}</td> - </tr> - {% endwith %} - {% endfor %} - </tbody> -</table> - -<div class="table-wrapper-2"> -<h3> Answers </h3><br> -<form name=frm id="q{{ paper.quiz.id }}_form" - action="{{URL_ROOT}}/exam/manage/gradeuser/{{quiz_id}}/{{user_id}}/{{paper.attempt_number}}/{{course_id}}/" - method="post"> -{% csrf_token %} - -{% for question, answers in paper.get_question_answers.items %} -<div class = "yakshlabel"> -<div class="card"> - <div class="card-heading alert-info" id="question_{{question.id}}"> - <strong> Details: {{forloop.counter}}. {{ question.summary }} - <span class="marks pull-right"> Mark(s): {{ question.points }} </span> - </strong> - </div> - <div class="card-body"> - <h5><u>Question:</u></h5> <strong>{{ question.description|safe }}</strong> - {% if question.type == "mcq" or question.type == "mcc" %} - <h5> <u>Choices:</u></h5> - {% for testcase in question.get_test_cases %} - {% if testcase.correct %} - <br/> - <strong>{{ forloop.counter }}. {{ testcase.options }}</strong> - <span class="alert alert-success"> Correct </span> - {% else %} - <br/><strong> - {{ forloop.counter }}. {{ testcase.options }}</strong> - {% endif %} - {% endfor %} - - {% elif question.type == "integer" or question.type == "string" or question.type == "float" %} - <h5> <u>Correct Answer:</u></h5> - {% for testcase in question.get_test_cases %} - <strong>{{ testcase.correct }}</strong> - {% if testcase.error_margin %} - <strong>{{ testcase.error_margin }}</strong> - {% endif %} - {% endfor %} - {% elif question.type == "arrange" %} - <h5> <u>Correct Order:</u></h5> - <div class="list-group" > - {% for testcase in question.get_test_cases %} - <li class="list-group-item"><strong>{{ testcase.options }}</strong></li> - {% endfor %} - </div> - - {% else %} - <h5> <u>Test cases: </u></h5> - {% for testcase in question.get_test_cases %} - <br/><strong>{{ forloop.counter }}. {{ testcase }}</strong> - {% endfor %} - {%endif%} +</div> +<div class="container-fluid"> + <div class="row"> + {% if status == "grade" %} + {% if users %} + <div id="student" class="col-md-3"> + <ul class="nav nav-pills list-group"> + {% for user in users %} + <li class="nav-item"> + <a href="{% url 'yaksh:grade_user' quiz_id user.user__id course_id %}" class="list-group-item{% if user.user__id == data.user.id %} active {% endif %}"> + {{user.user__first_name}} {{user.user__last_name}} + </a> + </li> + {% endfor %} + </ul> </div> - </div> - <h5>Student answer: </h5> - {% if question.type == "upload" %} - {% if has_user_assignments %} - <a href="{{URL_ROOT}}/exam/manage/download/user_assignment/{{question.id}}/{{data.user.id}}/{{paper.question_paper.quiz.id}}/{{course_id}}"> - <div class="btn btn-outline-info text-center"> - Assignment File for {{ data.user.get_full_name.title }} + {% else %} + <div class="col-md-1"></div> + <div class="col-md-10"> + <div class="alert alert-warning"> + <center> + <h4>No Users Found for {{ quiz.description }}</h4> + </center> + </div> </div> - </a> - {% with answers|last as answer%} - {% if answer.answer.correct %} - <div class="card "> - <div class="card-heading alert-success">Correct answer</div></div> - {% else %} - <div class="card "> - <div class="card-heading alert-danger">Incorrect Answer</div></div> - {% endif %} - {% endwith %} - {% else %} - <center> - <div class="alert alert-warning animated flash"> - <h5>No Assignment submitted by {{ data.user.get_full_name.title }}</h5> - </div> - </center> + {% endif %} {% endif %} - {% else %} - {% for ans in answers %} - {% if ans.answer.correct %} - <div class="card "> - <div class="card-heading alert-success">Correct answer: - {% else %} - <div class="card "> - <div class="card-heading-heading alert-danger">Error: - {% endif %} - {% with ans.error_list as err %} - {% for error in err %} - {% if error.type == 'stdio' %} - <div class = "card"> - <div class="card-body"> - {% if error.given_input %} - <table class="table table-bordered table-responsive-sm"> - <col width="30%"> - <tr class = "table-active"> - <td> For given Input value(s):</td> - <td>{{error.given_input}}</td> - </tr> - </table> - {% endif %} - <table class="table table-bordered table-responsive-sm" width="100%" id="output" style="table-layout: fixed"> - <col width="10%"> - <col width="40%"> - <col width="40%"> - <col width="10%"> - <tr> - <th><center>Line No.</center></th> - <th><center>Expected Output</center></th> - <th><center>User output</center></th> - <th><center>Status</center></th> - </tr> - {% for expected,user in error.expected_output|zip:error.user_output %} - <td> {{forloop.counter}} </td> - <td>{{expected|default:""}} </td> - <td>{{user|default:""}}</td> - {% if forloop.counter0 in error.error_line_numbers or not expected or not user %} - <td><span class ="fa fa-times text-warning"/></td> - {% else %} - <td><span class ="fa fa-check text-success"/></td> - {% endif %} - </tr> - {% endfor %} - </table> - <table width="100%" class="table table-bordered table-responsive-sm"> - <col width="10"> - <tr> - <td><b>Error:</b></td> - <td>{{error.error_msg}}</td> - </tr> - </table> - </div> - </div> - {% elif error.type == 'assertion' %} - {% if error.test_case %} - <strong> We tried you code with the following test case:</strong><br/></br> - <pre><code><strong style="color:#d9534f">{{error.test_case}}</strong></code></pre> - {% endif %} - <p> <b>The following error took place: </b></p> - <div class="card"> - <div class="card-body"> - <table class="table table-bordered table-responsive-sm" width="100%" style="table-layout: fixed"> - <col width="30%"> - <tr class = "active"> - <td><b>Exception Name: </b></td> - <td><span style="color: #d9534f">{{error.exception}}</span></td> - </tr> - <tr> - <td><b>Exception Message: </b></td><td>{{error.message}}</td> - </tr> - <tr> - {% if error.traceback %} - <td><b>Full Traceback: </b></td> - <td><pre>{{error.traceback}}</pre></td> - {% endif %} - </tr> - </table> - </div> - </div> <!-- Closes card --> - {% else %} - <pre><code> {{error}} </code></pre> - {% endif %} - {% endfor %} - {% endwith %} - </div> - - <div class="card-body"> - {% if question.type == "code" %} - <pre><code>{{ ans.answer.answer.strip }}</code></pre> - {% elif question.type == "mcc"%} - <div class="card"> - <div class="card-body"> - {% for testcases in question.get_test_cases %} - {%if testcases.id|stringformat:"i" in ans.answer.answer.strip %} - <li>{{ testcases.options.strip }}</li> - {% endif %} - {% endfor %} + <div id="paper" class="col-md-9"> + {% if has_quiz_assignments %} + <a href="{% url 'yaksh:download_quiz_assignment' quiz_id course_id %}" class="btn btn-outline-info"> + <i class="fa fa-download"></i> Download All Assignments + </a> + <br><br> + {% endif %} + + {% 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> - </div> - {% elif question.type == "mcq"%} - <div class="card"> - <div class="card-body"> - {% for testcases in question.get_test_cases %} - {%if testcases.id|stringformat:"i" == ans.answer.answer.strip %} - <li>{{ testcases.options.strip }}</li> - {% endif %} {% endfor %} - </div> - </div> + {% endif %} - {% elif question.type == "arrange"%} + {% if data %} <div class="card"> + <div class="card-header"> + Student Details + </div> <div class="card-body"> - {% get_answer_for_arrange_options ans.answer.answer question as tc_list %} - {% for testcases in tc_list %} - <li>{{ testcases.options.strip }}</li> - {% endfor %} - </div> - </div> - - {% else %} - <div class="card"> - <div class="card-body"> - {{ ans.answer.answer.strip }} + <p><b>Name:</b> {{ data.user.get_full_name.title }}</p> + {% with data.profile as profile %} + {% if profile %} + <div class="row"> + <div class="col-md-4"> + <p><b> Roll number:</b> {{ profile.roll_number }}</p> + <p><b>Position: </b> {{ profile.position }}</p> + </div> + <div class="col-md-7"> + <p><b>Department: </b>{{ profile.department }}</p> + <p><b>Institute: </b>{{ profile.institute }}</p> + </div> + </div> + {% endif %} + {% endwith %} </div> </div> - {% endif %} - </div> - </div> - {% endfor %} - {% endif %} - {% with answers|last as answer %} - Marks: <input id="q{{ question.id }}" type="text" - name="q{{ question.id }}_marks" size="4" - value="{{ answer.answer.marks }}"><br><br> - {% endwith %} - <hr/> - </div> - - {% endfor %} {# for question, answers ... #} - </div> -<div class="form-group"> -<h3>Teacher comments: </h3> -<textarea id="comments_{{paper.question_paper.id}}" class="form-control" - name="comments_{{ paper.question_paper.id }}">{{ paper.comments }}</textarea> -</div> -<br><button class="btn btn-primary" type="submit" name="submit_{{paper.quiz.id}}">Save Marks</button> - -</form> -</div> - -{% endif %} {# if paper.answers.count #} - - -{% endfor %} {# for paper in data.papers #} - -{% endif %} {# if data.papers #} -{% else %} + <hr> + {% if data.papers %} + {% with data.papers.0 as paper %} + <div class="card"> + <div class="card-header"> + Course Details + </div> + <div class="card-body"> + <div class="row"> + <div class="col-md-6"> + <p><b>Course:</b> {{ paper.course.name }}</p> + <p><b>Quiz:</b> {{ paper.question_paper.quiz.description }}</p> + </div> + <div class="col-md-6"> + <p><b>Start time:</b> {{ paper.start_time }}</p> + <p><b>End time:</b> {{ paper.end_time }}</p> + </div> + </div> + </div> + </div> + {% endwith %} + {% for paper in data.papers %} + <hr> + <div class="card"> + <div class="card-header"> + Scorecard + </div> + <div class="card-body"> + <div class="row"> + <div class="col-md-4"> + <p><b>Status:</b> + {% if paper.passed %} + <span class="badge badge-pill badge-success"> Passed </span> + {% else %} + <span class="badge badge-pill badge-danger"> Failed </span> + {% endif %} + </p> + <p><b>Total Marks:</b> {{ paper.question_paper.total_marks }}</p> + <p><b>Marks obtained:</b> {{ paper.marks_obtained }}</p> + </div> + <div class="col-md-4"> + {% if paper.percent %} + <p><b>Percentage obtained:</b> {{paper.percent}}%</p> + {% endif %} + <p><b>Total attempts at questions:</b> {{ paper.answers.count }}</p> + <p> + <b>Attempt Number:</b> + <span class="badge badge-pill badge-info"> + {{paper.attempt_number}} + </span> + <select id="attempt" onchange="window.location.href=this.value" class="custom-select"> + <option selected="">Select attempt number</option> + {% for attempt in attempts %} + <option value="{% url 'yaksh:grade_user' quiz_id user_id attempt.attempt_number course_id %}"> + {{attempt.attempt_number}} + </option> + {% endfor %} + </select> + </p> + </div> + </div> + </div> + </div> + <hr> + {% if paper.answers.count %} + <div class="card"> + <div class="card-header"> + Submission Details + </div> + <div class="card-body"> + <table class="tablesorter table table-striped table-bordered table-responsive-sm" id='marks_table'> + <thead> + <tr> + <th>Questions</th> + <th>Type</th> + <th>Marks Obtained</th> + </tr> + </thead> + <tbody> + {% for question, answers in paper.get_question_answers.items %} + {% with answers|last as answer %} + <tr> + <td> + <a href="#question_{{question.id}}"> + {{ question.summary }} + </a> + </td> + <td>{{ question.type }}</td> + <td>{{ answer.answer.marks }}</td> + </tr> + {% endwith %} + {% endfor %} + </tbody> + </table> + <form name=frm id="q{{ paper.quiz.id }}_form" + action="{% url 'yaksh:grade_user' quiz_id user_id paper.attempt_number course_id %}" + method="post"> + {% csrf_token %} + {% for question, answers in paper.get_question_answers.items %} + <div class="card" id="question_{{question.id}}"> + <div class="card-header text-white bg-info"> + <strong> + Details: {{forloop.counter}}. {{ question.summary }} + <span class="marks pull-right"> Mark(s): {{ question.points }} </span> + </strong> + </div> + <div class="card-body"> + <h5> + <span class="badge badge-pill badge-primary">Question:</span> + </h5> + <strong>{{ question.description }}</strong> + <br><br> + {% if question.type == "mcq" or question.type == "mcc" %} + <h5> + <span class="badge badge-pill badge-primary">Choices:</span> + </h5> + {% for testcase in question.get_test_cases %} + {% if testcase.correct %} + <strong> + <span class="badge badge-pill badge-success"> + {{ forloop.counter }}. + </span> + {{ testcase.options|safe }} + </strong> + {% else %} + <strong> + <span class="badge badge-pill badge-secondary"> + {{ forloop.counter }}. + </span> + {{ testcase.options|safe }} + </strong> + {% endif %} + <br> + {% endfor %} + {% elif question.type == "integer" or question.type == "string" or question.type == "float" %} + <h5> + <span class="badge badge-pill badge-primary"> + Correct Answer: + </span> + </h5> + {% for testcase in question.get_test_cases %} + <strong>{{ testcase.correct }}</strong> + {% if testcase.error_margin %} + <strong>{{ testcase.error_margin }}</strong> + {% endif %} + {% endfor %} + {% elif question.type == "arrange" %} + <h5> + <span class="badge badge-pill badge-primary"> + Correct Order:</span> + </h5> + <div class="list-group" > + {% for testcase in question.get_test_cases %} + <li class="list-group-item"> + <strong>{{ testcase.options }}</strong> + </li> + {% endfor %} + </div> + {% else %} + <h5> + <span class="badge badge-pill badge-primary">Test cases: + </span> + </h5> + {% for testcase in question.get_test_cases %} + <strong> + {{ forloop.counter }}. {{ testcase }} + </strong> + <br> + {% endfor %} + {% endif %} + <br> + <h5> + <span class="badge badge-pill badge-primary">Student answer(s): + </span> + </h5> + {% if question.type == "upload" %} + {% if has_user_assignments %} + <a href="{% url 'yaksh:download_user_assignment' question.id data.user.id paper.question_paper.quiz.id course_id %}"> + <div class="btn btn-outline-info text-center"> + Assignment File for {{ data.user.get_full_name.title }} + </div> + </a> + {% else %} + <center> + <div class="alert alert-warning"> + <h5> + Assignment not submitted by {{ data.user.get_full_name.title }} + </h5> + </div> + </center> + {% endif %} <!-- End has_user_assignments --> + {% else %} + {% for ans in answers %} + <strong> + Attempt Number: {{forloop.counter}} + </strong> + <div id="accordian"> + <div class="card"> + {% if ans.answer.correct %} + <div class="card-header"> + <span class="badge badge-success"> + Correct answer: + </span> + <a class="card-link" data-toggle="collapse" href="#submitted_{{ans.answer.id}}"> + <span class="pull-right"> + Details <i class="fa fa-toggle-down"></i> + </span> + </a> + </div> + {% else %} + <div class="card-header"> + <span class="badge badge-danger"> + Error: + </span> + <a class="card-link" data-toggle="collapse" href="#submitted_{{ans.answer.id}}"> + <span class="pull-right"> + Details <i class="fa fa-toggle-down"></i> + </span> + </a> + </div> + {% endif %} + <div class="collapse hide" id="submitted_{{ans.answer.id}}" data-parent="#accordion"> + <div class="card-body"> + {% with ans.error_list as err %} + {% for error in err %} + {% if error.type == 'stdio' %} + {% if error.given_input %} + <table class="table table-bordered table-responsive-sm"> + <tr class="table-active"> + <td> For given Input value(s):</td> + <td>{{error.given_input}}</td> + </tr> + </table> + {% endif %} + <table id="course-detail" class="table table-bordered table-responsive-sm" width="100%" id="output"> + <tr> + <th><center>Line No.</center></th> + <th><center>Expected Output</center></th> + <th><center>User output</center></th> + <th><center>Status</center></th> + </tr> + {% for expected,user in error.expected_output|zip:error.user_output %} + <td> {{forloop.counter}} </td> + <td>{{expected|default:""}} </td> + <td>{{user|default:""}}</td> + {% if forloop.counter0 in error.error_line_numbers or not expected or not user %} + <td><span class ="fa fa-times text-warning"/></td> + {% else %} + <td><span class ="fa fa-check text-success"/></td> + {% endif %} + </tr> + {% endfor %} + </table> + <table width="100%" class="table table-bordered table-responsive-sm"> + <col width="10"> + <tr> + <td>Error:</td> + <td>{{error.error_msg}}</td> + </tr> + </table> + {% elif error.type == 'assertion' %} + {% if error.test_case %} + <strong> + We tried you code with the following test case: + </strong><br><br> + <pre><code> + <strong>{{error.test_case}}</strong> + </code></pre> + {% endif %} + <p><b>The following error took place: </b></p> + <table id="course-detail" class="table table-bordered table-responsive-sm" width="100%"> + <tr class = "active"> + <td><b>Exception Name: </b></td> + <td><span>{{error.exception}}</span></td> + </tr> + <tr> + <td><b>Exception Message: </b></td><td>{{error.message}}</td> + </tr> + <tr> + {% if error.traceback %} + <td><b>Full Traceback: </b></td> + <td><pre>{{error.traceback}}</pre></td> + {% endif %} + </tr> + </table> + {% else %} + <pre><code> {{error}} </code></pre> + {% endif %} + {% endfor %} + {% endwith %} + {% if question.type == "code" %} + {% pygmentise_user_answer question.language ans.answer.answer.strip as user_answer %} + <style type="text/css">{{user_answer.1}}</style> + <pre><code>{{user_answer.0|safe}}</code></pre> + {% elif question.type == "mcc" or question.type == "mcq" %} + {% for testcases in question.get_test_cases %} + {% if testcases.id|stringformat:"i" in ans.answer.answer.strip %} + <li>{{ testcases.options.strip|safe }}</li> + {% endif %} + {% endfor %} + {% elif question.type == "arrange"%} + {% get_answer_for_arrange_options ans.answer.answer question as tc_list %} + {% for testcases in tc_list %} + <li>{{ testcases.options.strip }}</li> + {% endfor %} + {% else %} + {{ ans.answer.answer.strip }} + {% endif %} + </div> + </div> + </div> + </div> + <br> + {% endfor %} <!-- End for ans in answers --> + </div> + </div> + {% endif %} + <br> + <div class="form-group"> + <div class="col-md-2"> + <label class="col-form-label" for="q{{ question.id }}">Marks:</label> + {% with answers|last as answer %} + <input id="q{{ question.id }}" type="text" name="q{{ question.id }}_marks" size="4" class="form-control" value="{{ answer.answer.marks }}"><br><br> + {% endwith %} + </div> + </div> + <hr/> + {% endfor %} {# for question, answers ... #} + <div class="form-group"> + <h3>Teacher comments: </h3> + <textarea id="comments_{{paper.question_paper.id}}" class="form-control" + name="comments_{{ paper.question_paper.id }}">{{ paper.comments }}</textarea> + <br> + <button class="btn btn-success btn-lg" type="submit" name="submit_{{paper.quiz.id}}"> + <i class="fa fa-save"></i> Save + </button> + </div> + </form> + </div> + </div> + {% endif %} {# if paper.answers.count #} + {% endfor %} {# for paper in data.papers #} + {% endif %} {# if data.papers #} + {% else %} + <!-- No Data --> + {% endif %} {#if data#} </div> -{% endif %} {#if data#} - -</div> + </div> </div> {% endblock%} diff --git a/yaksh/templates/yaksh/intro.html b/yaksh/templates/yaksh/intro.html index 567282a..7657a65 100644 --- a/yaksh/templates/yaksh/intro.html +++ b/yaksh/templates/yaksh/intro.html @@ -1,61 +1,54 @@ {% extends "base.html" %} -{% block pagetitle %} OnlineTest Instructions and Rules {% endblock pagetitle %} +{% block title %} {{questionpaper.quiz.description}} {% endblock %} +{% block pagetitle %} Quiz Instructions and Rules {% endblock pagetitle %} {% block content %} -<div class="container-fluid card col-md-10"> - <center class="yakshwell"> - {% if questionpaper.quiz.is_expired %} - <div class="alert col-md-8 alert-error animated flash"> +<div class="container"> + <div class="card"> + <div class="card-header"> + {{questionpaper.quiz.description}} + </div> + <div class="card-body"> + {% if questionpaper.quiz.is_expired %} + <div class="alert alert-error"> This Quiz has expired. You can no longer attempt this Quiz. - <br/> </div> - {% else %} - <div class="alert alert-success col-md-8 animated flash"> - {% load tz %} - {% get_current_timezone as TIME_ZONE %} - You can attempt this Quiz at any time between {{ questionpaper.quiz.start_date_time }} {{ TIME_ZONE }} and {{ questionpaper.quiz.end_date_time }} {{ TIME_ZONE }} - <br/> - You are not allowed to attempt the Quiz before or after this duration - <br/> + {% else %} + <div class="alert alert-info"> + You can attempt this Quiz at any time between <b>{{ questionpaper.quiz.start_date_time }}</b> and <b>{{ questionpaper.quiz.end_date_time }}</b> </div> - {% endif %} - </center> - <div class="yakshwell"> + {% endif %} <p> Welcome <strong>{{user.get_full_name|title}}</strong>, to the programming quiz! </p> {{ questionpaper.quiz.instructions|safe }} - <div class="row yakshwell"> - <div class="col-md-6"> - <center> - {% if status != "moderator" %} - <a href="{{URL_ROOT}}/exam/quizzes/view_module/{{module.id}}/{{course.id}}" class="btn btn-primary" name="home"> - <i class="fa fa-step-backward"> - </i> - Go Back</a> - {% else %} - <a href="{{URL_ROOT}}/exam" class="btn btn-primary" name="home"> - <i class="fa fa-step-backward"> - </i> - Go Back</a> - {% endif %} - </center> - </div> - <div class="col-md-6"> - {% if not questionpaper.quiz.is_expired %} - <form action="{{URL_ROOT}}/exam/start/{{ attempt_num }}/{{module.id}}/{{ questionpaper.id }}/{{course.id}}/" method="post" align="center"> - {% csrf_token %} - <center><button class="btn btn-success" type="submit" name="start"> Start Exam <i class="fa fa-play"></i></button></center> - </form> - {% endif %} - </div> + <div class="row"> + <div class="col-md-6"> + <center> + {% if status != "moderator" %} + <a href="{% url 'yaksh:view_module' module.id course.id %}" class="btn btn-primary btn-lg" name="home"> + <i class="fa fa-step-backward"></i> + Go Back + </a> + {% else %} + <a href="{% url 'yaksh:index' %}" class="btn btn-primary btn-lg" name="home"> + <i class="fa fa-step-backward"></i> + Go Back + </a> + {% endif %} + </center> + </div> + <div class="col-md-6"> + {% if not questionpaper.quiz.is_expired %} + <form action="{% url 'yaksh:start_quiz' attempt_num module.id questionpaper.id course.id %}" method="post" align="center"> + {% csrf_token %} + <button class="btn btn-success btn-lg" type="submit" name="start"> + Start <i class="fa fa-play"></i> + </button> + </form> + {% endif %} + </div> </div> </div> - </div> + </div> +</div> {% endblock content %} - -{% if user %} - {% block info %} - <h5>{{user.get_full_name|title}}({{user.profile.roll_number}}) Logged in as {{user.username}}</h5> - {% endblock %} -{% endif %} - diff --git a/yaksh/templates/yaksh/lessons.html b/yaksh/templates/yaksh/lessons.html new file mode 100644 index 0000000..0146a6b --- /dev/null +++ b/yaksh/templates/yaksh/lessons.html @@ -0,0 +1,86 @@ +{% extends "manage.html" %} +{% load static %} +{% block title %} My Lessons {% endblock %} +{% block content %} +<div class="container"> + <div class="row"> + <div class="col-md-8"> + <ul class="nav nav-pills" id="course_tabs"> + <li class="nav-item"> + <a class="nav-link {% if created %}active{% endif %}" href="{% url 'yaksh:courses' %}"> + My Courses + </a> + </li> + <li class="nav-item"> + <a class="nav-link" href="{% url 'yaksh:add_course' %}"> + Add New Course + </a> + </li> + <li class="nav-item dropdown hide"> + <a class="nav-link dropdown-toggle active" data-toggle="dropdown" href="#" role="button" aria-haspopup="true" aria-expanded="true">More</a> + <div class="dropdown-menu hide" x-placement="bottom-start" style="position: absolute; transform: translate3d(0px, 37px, 0px); top: 0px; left: 0px; will-change: transform;"> + <a class="dropdown-item" href="{% url 'yaksh:show_all_quizzes' %}"> + Add/View Quizzes + </a> + <a class="dropdown-item active" href="{% url 'yaksh:show_all_lessons' %}"> + Add/View Lessons + </a> + <a class="dropdown-item" href="{% url 'yaksh:show_all_modules' %}"> + Add/View Modules + </a> + <a href="{% url 'grades:grading_systems'%}" class="dropdown-item" > + Add/View Grading Systems + </a> + </div> + </li> + </ul> + </div> + </div> +</div> +<div class="container"> + <hr> + <a href="{% url 'yaksh:edit_lesson' %}" class="btn btn-primary btn-lg"> + <i class="fa fa-plus-circle"></i> Add new Lesson + </a> + {% if not lessons %} + <br><br> + <div class="alert alert-info"> + <center><h3> No new Lessons added</h3></center> + </div> + {% else %} + <center><h3> Lessons </h3></center> + <table id="course-details" class="table table-bordered table-responsive-sm"> + <tr> + <th>Sr.No</th> + <th>Lesson</th> + </tr> + + {% for lesson in lessons %} + <tr> + <td width="2%">{{forloop.counter}}</td> + <td width="30%"> + <div class="row"> + <div class="col-md-8"> + <a href="{% url 'yaksh:edit_lesson' lesson.id %}"> + {{ lesson.name }} + </a> + </div> + <div class="col-md-4"> + {% if lesson.active %} + <span class="badge badge-success badge-pill"> + Active + </span> + {% else %} + <span class="badge badge-danger badge-pill"> + Closed + </span> + {% endif %} + </div> + </div> + </td> + {% endfor %} <!-- end for lessons --> + </tr> + </table> + {% endif %} +</div> +{% endblock %}
\ No newline at end of file diff --git a/yaksh/templates/yaksh/login.html b/yaksh/templates/yaksh/login.html index e2adca7..63a2ef2 100644 --- a/yaksh/templates/yaksh/login.html +++ b/yaksh/templates/yaksh/login.html @@ -52,9 +52,11 @@ </table> </center> <div class="row justify-content-center"> - <button class="btn btn-lg btn-success btn-block" type="submit" id="login-btn">Login</button> + <button class="btn btn-lg btn-success btn-block" type="submit" id="login-btn"> + <i class="fa fa-sign-in"></i> Login + </button> <a href="{% url 'yaksh:register' %}" class="btn btn-lg btn-primary btn-block" id="signup-btn"> - NEW USER? SIGN UP + <i class="fa fa-user-plus"></i> NEW USER? SIGN UP </a> <a class="btn btn-lg btn-primary btn-block" href="{% url 'password_reset' %}" id="forgot-btn"> Forgot Password? diff --git a/yaksh/templates/yaksh/moderator_dashboard.html b/yaksh/templates/yaksh/moderator_dashboard.html index db37983..b2d38b0 100644 --- a/yaksh/templates/yaksh/moderator_dashboard.html +++ b/yaksh/templates/yaksh/moderator_dashboard.html @@ -19,22 +19,22 @@ <a href="{% url 'yaksh:create_demo_course' %}" class="btn btn-primary btn-lg"> Create Demo Course </a> - <br> - {% if msg %} - <div class="container"> - <div class="alert alert-dismissible alert-info"> + <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>{{ msg }}</strong> + <strong>{{ message }}</strong> </div> - </div> + {% endfor %} {% endif %} </center> {% with objects as courses %} <br> {% if not courses %} - <div class="alert alert-secondary"> + <div class="alert alert-info"> No Courses found. Add a new course or Create demo course </div> {% else %} @@ -62,12 +62,13 @@ {% endif %} </div> <div class="col-md-3"> - <a href="{% url 'yaksh:course_detail' course.id %}" class="btn btn-primary btn-lg"> + <a href="{% url 'yaksh:course_detail' course.id %}" class="btn btn-primary"> + <i class="fa fa-tasks"></i> Manage Course </a> </div> <div class="col-md"> - <a class="card-link btn btn-info btn-lg" data-toggle="collapse" href="#collapse{{course.id}}"> + <a class="card-link btn btn-info" data-toggle="collapse" href="#collapse{{course.id}}"> Details <i class="fa fa-toggle-down" id="toggle_course_{{course.id}}"></i> </a> diff --git a/yaksh/templates/yaksh/modules.html b/yaksh/templates/yaksh/modules.html new file mode 100644 index 0000000..4fafbf1 --- /dev/null +++ b/yaksh/templates/yaksh/modules.html @@ -0,0 +1,114 @@ +{% extends "manage.html" %} +{% load static %} + +{% block title %} My Modules {% endblock %} +{% block content %} +<div class="container"> + <div class="row"> + <div class="col-md-8"> + <ul class="nav nav-pills" id="course_tabs"> + <li class="nav-item"> + <a class="nav-link {% if created %}active{% endif %}" href="{% url 'yaksh:courses' %}"> + My Courses + </a> + </li> + <li class="nav-item"> + <a class="nav-link" href="{% url 'yaksh:add_course' %}"> + Add New Course + </a> + </li> + <li class="nav-item dropdown hide"> + <a class="nav-link dropdown-toggle active" data-toggle="dropdown" href="#" role="button" aria-haspopup="true" aria-expanded="true">More</a> + <div class="dropdown-menu hide" x-placement="bottom-start" style="position: absolute; transform: translate3d(0px, 37px, 0px); top: 0px; left: 0px; will-change: transform;"> + <a class="dropdown-item" href="{% url 'yaksh:show_all_quizzes' %}"> + Add/View Quizzes + </a> + <a class="dropdown-item" href="{% url 'yaksh:show_all_lessons' %}"> + Add/View Lessons + </a> + <a class="dropdown-item active" href="{% url 'yaksh:show_all_modules' %}"> + Add/View Modules + </a> + <a href="{% url 'grades:grading_systems'%}" class="dropdown-item" > + Add/View Grading Systems + </a> + </div> + </li> + </ul> + </div> + </div> +</div> +<div class="container"> + <hr> + <a href="{% url 'yaksh:add_module' %}" class="btn btn-primary btn-lg"> + <i class="fa fa-plus-circle"></i> Add new Module + </a> + {% if not modules %} + <br><br> + <div class="alert alert-info"> + <center><h3> No new learning modules added</h3></center> + </div> + {% else %} + <center><h3> Learning Modules </h3></center> + <table class="table table-bordered table-responsive-sm"> + <tr> + <th>Sr.No</th> + <th>Learning Modules</th> + <th>Design Module</th> + <th>Lessons/Quizzes</th> + </tr> + {% for module in modules %} + <tr> + <td width="2%">{{forloop.counter}}</td> + <td width="30%"> + <div class="row"> + <div class="col-md-7"> + <a href="{% url 'yaksh:edit_module' module.id %}"> + {{ module.name }} + </a> + </div> + <div class="col-md-4"> + {% if module.active %} + <span class="badge badge-success badge-pill"> + Active + </span> + {% else %} + <span class="badge badge-danger badge-pill"> + Closed + </span> + {% endif %} + </div> + </div> + </td> + <td width="40%"> + <a href="{% url 'yaksh:design_module' module.id %}"> + Add Quizzes/Lessons for {{module.name}} + </a> + </td> + <td width="30%"> + {% with module.get_learning_units as units %} + {% if units %} + <ul class="list-group"> + {% for unit in units %} + <li class="list-group-item"> + {% if unit.type == 'quiz' %} + {{unit.quiz.description}} + {% else %} + {{unit.lesson.name}} + {% endif %} + </li> + {% endfor %} <!-- end for learning units --> + </ul> + {% else %} + <span class="badge badge-danger badge-pill"> + No Learning units + </span> + {% endif %} + {% endwith %} + </td> + {% endfor %} <!-- end for modules --> + </tr> + </table> + {% endif %} +</div> +{% endblock %}
\ No newline at end of file diff --git a/yaksh/templates/yaksh/monitor.html b/yaksh/templates/yaksh/monitor.html index a9f8328..cf6888c 100644 --- a/yaksh/templates/yaksh/monitor.html +++ b/yaksh/templates/yaksh/monitor.html @@ -1,14 +1,15 @@ {% extends "manage.html" %} {% load custom_filters %} +{% load static %} {% block title %} Monitor {% endblock %} -{% block pagetitle %} {{ msg }} {% endblock pagetitle %} +{% block pagetitle %} Monitor {% endblock pagetitle %} {% block meta %} <meta http-equiv="refresh" content="30"/> {% endblock meta %} - {% block script %} {% if papers %} -<script src="{{ URL_ROOT }}/static/yaksh/js/jquery.tablesorter.min.js"></script> +<script type="text/javascript" src="{% static 'yaksh/js/jquery.tablesorter.min.js' %}"> +</script> <script type="text/javascript"> $(document).ready(function() { @@ -29,166 +30,210 @@ $(document).ready(function() {% block content %} <div class="container"> - <div class="yakshwell"> - {# ############################################################### #} - {# This is rendered when we are just viewing exam/monitor #} - - {% if course_details %} - <div class="table-wrapper-2"> - <table id="course-details" class="table table-bordered table-responsive-sm"> - <tr class="table-info"> - <th>Courses</th> - <th> Quizzes </th> - </tr> - - {% for course in course_details %} - <tr> - <td><ul class="list-group">{{course.name}} </td> - - {% if course.get_quizzes %} - <td> - {% for quiz in course.get_quizzes %} - <li class="list-group-item"><a href = "{{URL_ROOT}}/exam/manage/monitor/{{quiz.id}}/{{course.id}}/"> - {{quiz.description}} - </a></li> - {% endfor %} - </td> - {% else %} - <td> No quiz</td> - {% endif %} - </ul></tr> - {% endfor %} - </table> - </div> - {% endif %} + {# ############################################################### #} + {# This is rendered when we are just viewing exam/monitor #} + {% if objects %} + {% include "yaksh/paginator.html" %} + <div id="accordion"> + {% for course in objects %} + <div class="card"> + <div class="card-header"> + <div class="row"> + <div class="col-md-9"> + <h5 data-toggle="tooltip" title="{{course.name}}"> + {{ course.name }} + </h5> + </div> + <div class="col-md"> + <a class="card-link btn btn-info" data-toggle="collapse" href="#collapse{{course.id}}"> + Details + <i class="fa fa-toggle-down" id="toggle_course_{{course.id}}"></i> + </a> + </div> + </div> + </div> + <div id="collapse{{course.id}}" class="collapse hide" data-parent="#accordion"> + <div class="card-body"> + {% with course.get_quizzes as quizzes %} + {% if quizzes %} + <ul class="list-group"> + {% for quiz in quizzes %} + <li class="list-group-item"> + <div class="row"> + <div class="col-md-8"> + {{quiz.description}} + </div> + <div class="col-md-2"> + <a href="{% url 'yaksh:monitor' quiz.id course.id%}" class="btn btn-primary"> + Monitor + </a> + </div> + </div> + </li> + {% endfor %} + </ul> + {% else %} + <center> + <p class="badge badge-danger badge-pill"> + No Quizzes + </p> + </center> + {% endif %} + {% endwith %} + </div> + </div> + </div> + <br> + {% endfor %} + </div> + {% include "yaksh/paginator.html" %} - {# ############################################################### #} - {# This is rendered when we are just viewing exam/monitor/quiz_num #} - {% if msg != "Monitor" %} - {% if quiz %} + {% elif msg == 'Monitor' and not objects %} + <br> + <div class="alert alert-info"> + <center><h3>No courses to monitor</h3></center> + </div> + {% endif %} + {# ############################################################### #} + {# This is rendered when we are just viewing exam/monitor/quiz_num #} + {% if msg != "Monitor" %} + {% if quiz %} {% if papers %} - <div class="row"> - <div class="card col-md-10"> - <div class = "table-responsive""> - <table class = "table"> - <tr> - <td><b>Course Name: </b></td> - <td>{{course.name}}</td> - </tr> - <tr> - <td><b>Quiz Name: </b></td> - <td>{{quiz.description}}</td> - </tr> - <tr> - <td><b>Number of papers:  </b></td> - <td>{{papers|length}}</td> - </tr> - <tr> - <td><b>Papers Completed:  </b></td> - <td> - {% completed papers as completed_papers %} - <b class = "yakshgreen">{{completed_papers}}</b> - </td> - </tr> - <tr> - <td><b>Papers in progress:  </b></td> - <td> - {% inprogress papers as inprogress_papers %} - <b class="yakshred"> {{ inprogress_papers }} </b> - </td> - </tr> - </table> + <div class="card"> + <div class="table-responsive"> + <table id="course-detail" class="table"> + <tr> + <td><b>Course Name: </b></td> + <td>{{course.name}}</td> + </tr> + <tr> + <td><b>Quiz Name: </b></td> + <td>{{quiz.description}}</td> + </tr> + <tr> + <td><b>Number of papers:  </b></td> + <td>{{papers|length}}</td> + </tr> + <tr> + <td><b>Papers Completed:  </b></td> + <td> + {% completed papers as completed_papers %} + <b>{{completed_papers}}</b> + </td> + </tr> + <tr> + <td><b>Papers in progress:  </b></td> + <td> + {% inprogress papers as inprogress_papers %} + <b>{{ inprogress_papers }}</b> + </td> + </tr> + </table> + </div> + </div> + <br> + <div class="row"> + <div class="col-md-4"> + <a href="{% url 'yaksh:show_statistics' papers.0.question_paper.id course.id %}" class="btn btn-primary"> + <i class="fa fa-line-chart"></i> Question Statistics + </a> </div> - </div> - <div class = "row"> - <div class="col-md-2"> - <p><a href="{{URL_ROOT}}/exam/manage/statistics/question/{{papers.0.question_paper.id}}/{{course.id}}" class="btn btn-primary">Question Statisitics</a></p> - <p> - <button type="button" class="btn btn-info" data-toggle="modal" data-target="#csvModal"> - Download CSV <span class="fa fa-download"></span> - </button> - </p> + <div class="col-md-4"> + <button type="button" class="btn btn-info" data-toggle="modal" data-target="#csvModal"> + <i class="fa fa-download"></i> Download CSV + </button> </div> - </div> - <div class="table-wrapper-2"> - <table id="result-table" class="tablesorter table table-striped table-responsive-sm"> - <thead> - <tr class="table-info"> - <th> Name </th> - <th> Username </th> - <th> Roll number </th> - <th> Institute </th> - <th> Questions answered </th> - <th> Marks obtained </th> - <th> Attempts </th> - <th> Time Remaining </th> - <th> Status </th> - </tr> - </thead> - <tbody> - {% for paper in latest_attempts %} - <tr> - <td> <a href="{{URL_ROOT}}/exam/manage/user_data/{{paper.user.id}}/{{paper.question_paper.id}}/{{course.id}}"><i class="fa fa-circle fa-sm"></i> {{ paper.user.get_full_name.title }}</a> </td> - <td> {{ paper.user.username }} </td> - <td> {{ paper.user.profile.roll_number }} </td> - <td> {{ paper.user.profile.institute }} </td> - <td> {{ paper.get_answered_str }} </td> - <td> {{ paper.marks_obtained }} </td> - <td> {{ paper.answers.count }} </td> - <td id="time_left{{forloop.counter0}}"> {{ paper.time_left }} </td> - <td>{{ paper.status }}</td> - </tr> - {% endfor %} - </tbody> - </table> - </div> - {% else %} - <p> No answer papers found for {{ quiz.description }}</p> - {% endif %} {# if papers #} - {% else %} - <h4>No Quiz Found</h4> - {% endif %} - {% endif %} - </div> - <!-- CSV Modal --> - <div class="modal fade" id="csvModal" role="dialog"> - <div class="modal-dialog"> + </div> + <br> + <table id="result-table" class="tablesorter table table-striped table-responsive-sm"> + <thead> + <tr> + <th> Name <i class="fa fa-sort"></i> </th> + <th> Username <i class="fa fa-sort"></i> </th> + <th> Roll No <i class="fa fa-sort"></i> </th> + <th> Institute <i class="fa fa-sort"></i> </th> + <th> Marks <i class="fa fa-sort"></i> </th> + <th> Attempts <i class="fa fa-sort"></i> </th> + <th> Time <i class="fa fa-sort"></i> </th> + <th> Status <i class="fa fa-sort"></i> </th> + </tr> + </thead> + <tbody> + {% for paper in latest_attempts %} + <tr> + <td> <a href="{% url 'yaksh:user_data' paper.user.id paper.question_paper.id course.id %}"> + {{ paper.user.get_full_name.title }}</a> </td> + <td> {{ paper.user.username }} </td> + <td> {{ paper.user.profile.roll_number }} </td> + <td> {{ paper.user.profile.institute }} </td> + <td> {{ paper.marks_obtained }} </td> + <td> {{ paper.answers.count }} </td> + <td id="time_left{{forloop.counter0}}"> {{ paper.time_left }} </td> + <td>{{ paper.status }}</td> + </tr> + {% endfor %} + </tbody> + </table> + <!-- CSV Modal --> + <div class="modal fade" id="csvModal" role="dialog"> + <div class="modal-dialog"> - <!-- Modal content--> - <div class="modal-content"> - <div class="modal-header"> - <button type="button" class="close" data-dismiss="modal">×</button> - <h3 class="modal-title">Uncheck unwanted columns</h3> - </div> - <form action="{{URL_ROOT}}/exam/manage/download_quiz_csv/{{ course.id }}/{{ quiz.id }}/" method="post"> - {% csrf_token %} - <div class="modal-body"> - {% for field in csv_fields %} - <div class="form-check form-check-inline"> - <label class="form-check-label"> - <input class="form-check-input" name="csv_fields" type="checkbox" value="{{ field }}" checked> {{ field }} - </label> - </div> - {% endfor %} - <b>Select Attempt Number: Default latest attempt</b> - <select class="form-control" name = "attempt_number"> - {%for attempt_number in attempt_numbers %} - {% if forloop.last %} - <option value="{{ attempt_number }}" selected>{{ attempt_number }} (Latest)</option> - {% else %} - <option value = "{{ attempt_number }}"> {{ attempt_number }}</option> - {% endif %} - {% endfor %} - </select> - </div> - <div class="modal-footer"> - <button type="submit" class="btn btn-primary"> Download <span class="glyphicon glyphicon-save"></span></button> - <button type="button" class="btn btn-default" data-dismiss="modal">Close</button> + <!-- Modal content--> + <div class="modal-content"> + <div class="modal-header"> + <h3 class="modal-title">Download CSV for {{quiz.description}} </h3> + <button type="button" class="close" data-dismiss="modal"> + <i class="fa fa-close"></i> + </button> + </div> + <form action="{% url 'yaksh:download_quiz_csv' course.id quiz.id %}" method="post"> + {% csrf_token %} + <div class="modal-body"> + <b>Uncheck unwanted columns</b> + <br> + {% for field in csv_fields %} + <div class="form-check form-check-inline"> + <label class="form-check-label"> + <input class="form-check-input" name="csv_fields" type="checkbox" value="{{ field }}" checked> {{ field }} + </label> + </div> + <br> + {% endfor %} + <b>Select Attempt Number: Default latest attempt</b> + <select class="form-control" name = "attempt_number"> + {%for attempt_number in attempt_numbers %} + {% if forloop.last %} + <option value="{{ attempt_number }}" selected>{{ attempt_number }} (Latest)</option> + {% else %} + <option value = "{{ attempt_number }}"> {{ attempt_number }}</option> + {% endif %} + {% endfor %} + </select> + </div> + <div class="modal-footer"> + <button type="submit" class="btn btn-success"> + <span class="fa fa-save"></span> Download + </button> + <button type="button" class="btn btn-secondary" data-dismiss="modal"> + Close + </button> + </div> + </form> + </div> + </div> + </div> + {% else %} + <div class="col-md-12"> + <div class="alert alert-warning"> + <center> + <h4>No Users Found for {{ quiz.description }}</h4> + </center> </div> - </form> - </div> - </div> - </div> - </div> + </div> + {% endif %} {# if papers #} + {% else %} + <h4>No Quiz Found</h4> + {% endif %} + {% endif %} </div> {% endblock %} diff --git a/yaksh/templates/yaksh/preview_questionpaper.html b/yaksh/templates/yaksh/preview_questionpaper.html index d6391e1..72355ea 100644 --- a/yaksh/templates/yaksh/preview_questionpaper.html +++ b/yaksh/templates/yaksh/preview_questionpaper.html @@ -1,24 +1,33 @@ {% extends "base.html" %} +{% block title %} Preview Question paper {% endblock title %} {% block pagetitle %} Quiz: {{ paper.quiz.description }} {% endblock pagetitle %} {% block content %} -<div class="yakshwell container"> +<div class="container"> <div class="card"> - <div class="col-md-12 card-body"> - <div class="col-md-6">Maximum Mark(s): {{ paper.total_marks }}</div> - <div class="col-md-6"><span class="pull-right">Total Time: {{ paper.quiz.duration }} minutes</span></div> - </div> + <div class="card-body"> + <div class="row"> + <div class="col-md-6">Maximum Mark(s): {{ paper.total_marks }}</div> + <div class="col-md-6"> + <span class="pull-right"> + Total Time: {{ paper.quiz.duration }} minutes + </span> + </div> + </div> + </div> </div> +<br> <div class="card"> - <div class="card-heading">Instructions</div> - <div class="card-body" id="instructions"> - {{ paper.quiz.instructions|safe }} - </div> + <div class="card-header">Instructions</div> + <div class="card-body" id="instructions"> + {{ paper.quiz.instructions|safe }} + </div> </div> +<br> {% for question in questions %} <div class="card"> - <div class="card-heading yakshlabel"> + <div class="card-header"> <strong> {{forloop.counter}}. {{ question.summary }} <span class="marks pull-right"> Mark(s): {{ question.points }} </span> </strong> @@ -39,6 +48,7 @@ </div> </div> + <br> {% endfor %} </div> {% endblock %} diff --git a/yaksh/templates/yaksh/question.html b/yaksh/templates/yaksh/question.html index f13de1a..74343f8 100644 --- a/yaksh/templates/yaksh/question.html +++ b/yaksh/templates/yaksh/question.html @@ -1,11 +1,12 @@ {% extends "exam.html" %} {% load custom_filters %} - +{% load static %} {% block css %} -<link rel="stylesheet" href="{{ URL_ROOT }}/static/yaksh/css/question.css" type="text/css" /> -<link rel="stylesheet" href="{{ URL_ROOT }}/static/yaksh/css/codemirror/lib/codemirror.css" type="text/css" /> -<link rel="stylesheet" href="{{ URL_ROOT }}/static/yaksh/css/exam.css" type="text/css" /> + +<link rel="stylesheet" href="{% static 'yaksh/css/question.css' %}" type="text/css" /> +<link rel="stylesheet" href="{% static 'yaksh/css/codemirror/lib/codemirror.css' %}" type="text/css" /> +<link rel="stylesheet" href="{% static 'yaksh/css/exam.css' %}" type="text/css" /> <style> .CodeMirror{ border-style: groove; @@ -18,13 +19,15 @@ {% endblock %} {% block script %} -<script src="{{ URL_ROOT }}/static/yaksh/js/requesthandler.js"></script> -<script src="{{ URL_ROOT }}/static/yaksh/js/codemirror/lib/codemirror.js"></script> -<script src="{{ URL_ROOT }}/static/yaksh/js/codemirror/mode/python/python.js"></script> -<script src="{{ URL_ROOT }}/static/yaksh/js/codemirror/mode/clike/clike.js"></script> -<script src="{{ URL_ROOT }}/static/yaksh/js/codemirror/mode/shell/shell.js"></script> -<script src="{{ URL_ROOT }}/static/yaksh/js/mathjax/MathJax.js?config=TeX-MML-AM_CHTML"></script> -<script src="{{ URL_ROOT }}/static/yaksh/js/jquery-sortable.js"></script> + + +<script src="{% static 'yaksh/js/requesthandler.js' %}"></script> +<script src="{% static 'yaksh/js/codemirror/lib/codemirror.js' %}"></script> +<script src="{% static 'yaksh/js/codemirror/mode/python/python.js' %}"></script> +<script src="{% static 'yaksh/js/codemirror/mode/clike/clike.js' %}"></script> +<script src="{% static 'yaksh/js/codemirror/mode/shell/shell.js' %}"></script> +<script type="text/javascript" src="{% static 'yaksh/js/mathjax/MathJax.js' %}?config=TeX-MML-AM_CHTML"></script> +<script src="{% static 'yaksh/js/jquery-sortable.js' %}"></script> <script> init_val = '{{ last_attempt|escape_quotes|safe }}'; lang = "{{ question.language }}" @@ -34,9 +37,9 @@ is_exercise = "{{ quiz.is_exercise }}" can_skip = "{{ can_skip }}" delay_time = new Number("{{ delay_time }}") -var time_left = {{ paper.time_left }} +var time_left = "{{ paper.time_left }}" {% if quiz.is_exercise %} - time_left = {{ delay_time }} + time_left = "{{ delay_time }}" {% endif %} function getTimeRemaining(endtime){ @@ -115,252 +118,275 @@ question_type = "{{ question.type }}" {% block main %} - <form id="code" action="{{URL_ROOT}}/exam/{{ question.id }}/check/{{ paper.attempt_number }}/{{ module.id }}/{{ paper.question_paper.id }}/{{course.id}}/" method="post" enctype="multipart/form-data"> - {% csrf_token %} - <input type=hidden name="question_id" id="question_id" value={{ question.id }}></input> - <div class="yakshwell"> - <div class="card "> - <div class="col-md-12 bg-light"> - <div class="row align-items-center "> - <div class="col-md-6 yakshheading"> {{ question.summary }} </div> - <div class="col-md-3 ml-auto yakshwell text-center"> - {% if question.type == "mcq" %} - SINGLE CORRECT CHOICE - {% elif question.type == "mcc" %} - MULTIPLE CORRECT CHOICES - {% elif question.type == "code" %} - PROGRAMMING - {% elif question.type == "upload" %} - ASSIGNMENT UPLOAD - {% elif question.type == "integer" %} - FILL IN THE BLANKS WITH INTEGER ANSWER - {% elif question.type == "string" %} - FILL IN THE BLANKS WITH STRING ANSWER - {% if testcase.string_check == "lower" %} - <br>(CASE INSENSITIVE) - {% else %} - <br>(CASE SENSITIVE) - {% endif %} - {% elif question.type == "float" %} - FILL IN THE BLANKS WITH FLOAT ANSWER - {% elif question.type == "arrange" %} - ARRANGE THE OPTIONS IN CORRECT ORDER - {% endif %} - </div> - <div class="col-md-2 ml-auto text-center"> - <div class="row"> - <div class="col-md-6"> - <h5> - <span class="badge badge-warning"> - {{ question.points }} Marks - </span> - </h5> - </div> - </div> - </div> - </div> - </div> - <div class="yakshwell"> - <font size=3 face=arial> {{ question.description|safe }} </font> - {% if files %} - <div class="yakshwell col-md-5"> - <div class="card yakshwell"> - <span> Files to download for this question </span> <hr> - {% for f_name in files %} - <div class="yakshwell"> - <a href="{{f_name.file.url}}" class="btn btn-outline-secondary btn-sm " target="_blank">{{f_name.get_filename}}</a> - <br> - </div> - {% endfor %} - </div> - </div> - {% endif %} - </div> - </div> - <br/> - <center> - {% if notification %} - {% if question.type == "code" %} - <div id="notification" class="alert alert-success col-md-8 animated flash" role="alert"> - <strong>Note:</strong> {{ notification }} + <div> + <center> + {% if notification %} + {% if question.type == "code" %} + <div id="notification" class="alert alert-info col-md-8" role="alert"> + <button type="button" class="close" data-dismiss="alert"> + <i class="fa fa-close"></i> + </button> + <strong>Note:</strong> {{ notification }} + </div> + {% else %} + <div id="notification" class="alert alert-info col-md-8" role="alert"> + <button type="button" class="close" data-dismiss="alert"> + <i class="fa fa-close"></i> + </button> + <strong>Note:</strong> {{ notification }} + </div> + {% endif %} + {% else %} + <div id="notification" role="alert"> + </div> + {% endif %} + </center> + </div> + <form id="code" action="{% url 'yaksh:check' question.id paper.attempt_number module.id paper.question_paper.id course.id %}" method="post" enctype="multipart/form-data"> + {% csrf_token %} + <input type=hidden name="question_id" id="question_id" value="{{ question.id }}"></input> + <div class="card"> + <div class="card-header"> + <div class="row"> + <div class="col-md-6"> + {{ question.summary }} </div> - {% else %} - <div id="notification" class="alert alert-warning col-md-8 animated flash" role="alert"> - <strong>Note:</strong> {{ notification }} + <div class="col-md-4"> + {% if question.type == "mcq" %} + SINGLE CORRECT CHOICE + {% elif question.type == "mcc" %} + MULTIPLE CORRECT CHOICES + {% elif question.type == "code" %} + PROGRAMMING + {% elif question.type == "upload" %} + ASSIGNMENT UPLOAD + {% elif question.type == "integer" %} + FILL IN THE BLANKS WITH INTEGER ANSWER + {% elif question.type == "string" %} + FILL IN THE BLANKS WITH STRING ANSWER + {% if testcase.string_check == "lower" %} + <br>(CASE INSENSITIVE) + {% else %} + <br>(CASE SENSITIVE) + {% endif %} + {% elif question.type == "float" %} + FILL IN THE BLANKS WITH FLOAT ANSWER + {% elif question.type == "arrange" %} + ARRANGE THE OPTIONS IN CORRECT ORDER + {% endif %} </div> - {% endif %} - {% else %} - <div id="notification" role="alert"> + <div class="col-md-2"> + <span class="badge badge-info"> + {{ question.points }} Marks + </span> + </div> + </div> + </div> + <div class="card-body"> + <div> + {{ question.description|safe }} + </div> + {% if files %} + <div class="col-md-5"> + <div class="card"> + <div class="card-header"> + <span> Files to download for this question </span> + </div> + <div class="card-body"> + {% for f_name in files %} + <a href="{{f_name.file.url}}" class="list-group-item" target="_blank">{{f_name.get_filename}} + </a> + {% endfor %} + </div> + </div> </div> {% endif %} - </center> - {% if quiz.is_exercise %} - {% if can_skip %} - <div class = "card col-md-8" id="solution"> - {% else %} - <div id="solution" style="display:none"> - {% endif %} - {% if question.solution %} - <h4><u> Solution by teacher</u></h4> - {% endif%} - <font size=3 face=arial> {{ question.solution|safe }} </font> - </div> - {% endif %} - <div class="card"> - <div class="yakshwell"> - {% if question.type == "mcq" %} - {% for test_case in test_cases %} - {% if last_attempt and last_attempt|safe == test_case.id|safe %} - <input name="answer" type="radio" value="{{ test_case.id }}" checked /> - {{ test_case.options|safe }} <br/> - {% else %} - <input name="answer" type="radio" value="{{ test_case.id }}" /> - {{ test_case.options|safe }} <br/> - {% endif %} - {% endfor %} - {% endif %} - {% if question.type == "integer" %} - Enter Integer:<br/> - <input autofocus name="answer" type="number" id="integer" value="{{ last_attempt|safe }}" /> - <br/><br/> - {% endif %} + {% if quiz.is_exercise %} + <div> + {% if can_skip %} + <div id="solution"> + {% else %} + <div id="solution" style="display:none"> + {% endif %} + {% if question.solution %} + <br> + <h4><u> Solution by teacher</u></h4> + {% endif %} + <font size=3 face=arial> {{ question.solution|safe }} </font> + </div> + </div> + {% endif %} + <br> + <div> + <!-- MCQ type question --> + {% if question.type == "mcq" %} + {% for test_case in test_cases %} + {% if last_attempt and last_attempt|safe == test_case.id|safe %} + <input name="answer" type="radio" value="{{ test_case.id }}" checked /> + {{ test_case.options|safe }} <br/> + {% else %} + <input name="answer" type="radio" value="{{ test_case.id }}" /> + {{ test_case.options|safe }} <br/> + {% endif %} + {% endfor %} + {% endif %} - {% if question.type == "string" %} - Enter Text:<br/> - <textarea autofocus name="answer" id="string">{{ last_attempt|safe }}</textarea> - <br/><br/> - {% endif %} + <!-- Integer type question --> + {% if question.type == "integer" %} + Enter Integer:<br/> + <input autofocus class="form-control" name="answer" type="number" id="integer" value="{{ last_attempt|safe }}" /> + <br><br> + {% endif %} - {% if question.type == "float" %} - Enter Decimal Value :<br/> - <input autofocus name="answer" type="number" step="any" id="float" value="{{ last_attempt|safe }}" /> - <br/><br/> - {% endif %} + <!-- String type question --> + {% if question.type == "string" %} + Enter Text:<br/> + <textarea autofocus name="answer" id="string" class="form-control" style="width: 100%">{{ last_attempt|safe }}</textarea> + <br/><br/> + {% endif %} - {% if question.type == "mcc" %} - {% for test_case in test_cases %} - {% if last_attempt and test_case.id|safe in last_attempt|safe %} - <input name="answer" type="checkbox" value="{{ test_case.id }}" checked/> {{ test_case.options| safe }} - <br> - {% else %} - <input name="answer" type="checkbox" value="{{ test_case.id }}"> - {{ test_case.options| safe }} - <br/> - {% endif %} - {% endfor %} - {% endif %} - {% if question.type == "upload" %} - <p>Upload assignment file for the said question<p> - <input type=file id="assignment" name="assignment" multiple=""> - {% endif %} + <!-- Float type question --> + {% if question.type == "float" %} + Enter Decimal Value :<br/> + <input autofocus class="form-control" name="answer" type="number" step="any" id="float" value="{{ last_attempt|safe }}" /> + <br/><br/> + {% endif %} - {% if question.type == "arrange" %} - {% if last_attempt %} - {% get_answer_for_arrange_options last_attempt question as test_cases %} - {% endif %} - <input name="answer" type="hidden" id='arrange_order'/> - <div class="list-group"> - <ol class="arrange "> - {% for test_case in test_cases %} - <li class="list-group-item yakshlight" id={{test_case.id}}>{{test_case.options| safe }}</li> {% endfor %} - </ol> - </div> - <script type="text/javascript"> - var arrange = $("ol.arrange"); - var order_array = $(arrange).sortable(['serialize']); - </script> - {% endif %} + <!-- MCC type question --> + {% if question.type == "mcc" %} + {% for test_case in test_cases %} + {% if last_attempt and test_case.id|safe in last_attempt|safe %} + <input name="answer" type="checkbox" value="{{ test_case.id }}" checked/> + {{ test_case.options| safe }} + <br> + {% else %} + <input name="answer" type="checkbox" value="{{ test_case.id }}"> + {{ test_case.options| safe }} + <br> + {% endif %} + {% endfor %} + {% endif %} + <!-- Upload type question --> + {% if question.type == "upload" %} + <p>Upload assignment file for the said question<p> + <input type=file id="assignment" name="assignment" multiple=""> + {% endif %} - {% if question.type == "code" %} - <div class="row align-items-center"> - <div class="col-md-9"> - <h5>Write your program below:</h5> - </div> - <div class="col-md-3 ml-auto"> - <a href="#answer" class=" btn btn-outline-primary" onclick="confirm()" name="reset" id="reset">Undo Changes <span class="glyphicon glyphicon-refresh"></span></a> - </div> - </div> - <div class="yakshwell"> - <textarea autofocus name="answer" id="answer"></textarea> - </div> - {% endif %} - </div> - </div> - <div class="text-center yakshwell"> + <!-- Arrange type question --> + {% if question.type == "arrange" %} + {% if last_attempt %} + {% get_answer_for_arrange_options last_attempt question as test_cases %} + {% endif %} + <input name="answer" type="hidden" id='arrange_order'/> + <div class="list-group"> + <ol class="arrange"> + {% for test_case in test_cases %} + <li class="list-group-item yakshlight" id={{test_case.id}}> + {{test_case.options| safe }}</li> {% endfor %} + </ol> + </div> + <script type="text/javascript"> + var arrange = $("ol.arrange"); + var order_array = $(arrange).sortable(['serialize']); + </script> + {% endif %} - {% if question.type == "mcq" or question.type == "mcc" or question.type == "integer" or question.type == "float" or question.type == "string" %} - <br><button class="btn btn-success" type="submit" name="check" id="check">Submit Answer</button> - {% elif question.type == "upload" %} - <br><button class="btn btn-success" type="submit" name="check" id="check" onClick="return validate();">Upload</button> - {% elif question.type == "arrange" %} - <br><button class="btn btn-success" type="submit" name="check" id="check" onClick="return user_arranged_options();">Submit Answer</button> + <!-- Code type question --> + {% if question.type == "code" %} + <div class="row align-items-center"> + <div class="col-md-9"> + <h4>Write your program below:</h4> + </div> + <div class="col-md-3 ml-auto"> + <a href="#answer" class=" btn btn-outline-primary" onclick="confirm()" name="reset" id="reset">Undo Changes <span class="fa fa-refresh"></span></a> + </div> + </div> + <br> + <div> + <textarea autofocus name="answer" id="answer"></textarea> + </div> + {% endif %} + <!-- Submit Buttons --> + <br> + <div> + {% if question.type == "mcq" or question.type == "mcc" or question.type == "integer" or question.type == "float" or question.type == "string" %} + <br><button class="btn btn-success" type="submit" name="check" id="check">Submit Answer</button> + {% elif question.type == "upload" %} + <br><button class="btn btn-success" type="submit" name="check" id="check" onClick="return validate();">Upload</button> + {% elif question.type == "arrange" %} + <br><button class="btn btn-success" type="submit" name="check" id="check" onClick="return user_arranged_options();">Submit Answer</button> + {% else %} + {% if question in paper.get_questions_unanswered or quiz.is_exercise %} + <button class="btn btn-success" type="submit" name="check" id="check" > + Check Answer + </button> + {% endif %} + {% endif %} + {% if quiz.is_exercise %} + {% if can_skip %} + <button id="skip_ex" class="btn btn-primary" onclick="call_skip('{{ URL_ROOT }}/exam/{{ question.id }}/skip/{{ paper.attempt_number }}/{{ module.id }}/{{ paper.question_paper.id }}/{{course.id}}/')" name="skip"> Next <span class="fa fa-step-forward"></span></button> + {% else %} + <button id="skip_ex" class="btn btn-primary" onclick="call_skip('{{ URL_ROOT }}/exam/{{ question.id }}/skip/{{ paper.attempt_number }}/{{ module.id }}/{{ paper.question_paper.id }}/{{course.id}}/')" name="skip" style="visibility:hidden"> Next <span class="fa fa-step-forward"></span> + </button> + {% endif %} + {% endif %} - {% else %} - {% if question in paper.get_questions_unanswered or quiz.is_exercise %} - <button class="btn btn-success" type="submit" name="check" id="check" >Check Answer <span class="glyphicon glyphicon-cog"></span></button> - {% endif %} - {% endif %} - {% if quiz.is_exercise %} - {% if can_skip %} - <button id="skip_ex" class="btn btn-primary" onclick="call_skip('{{ URL_ROOT }}/exam/{{ question.id }}/skip/{{ paper.attempt_number }}/{{ module.id }}/{{ paper.question_paper.id }}/{{course.id}}/')" name="skip"> Next <span class="glyphicon glyphicon-arrow-right"></span></button> - {% else %} - <button id="skip_ex" class="btn btn-primary" onclick="call_skip('{{ URL_ROOT }}/exam/{{ question.id }}/skip/{{ paper.attempt_number }}/{{ module.id }}/{{ paper.question_paper.id }}/{{course.id}}/')" name="skip" style="visibility:hidden"> Next <span class="fa fa-step-forward"></span></button> - {% endif %} - {% endif %} + {% if paper.question_paper.quiz.allow_skip and not paper.get_questions_unanswered|length_is:"1" %} + {% if question in paper.get_questions_unanswered %} + <button class="btn btn-primary" onclick="call_skip('{{ URL_ROOT }}/exam/{{ question.id }}/skip/{{ paper.attempt_number }}/{{ module.id }}/{{ paper.question_paper.id }}/{{course.id}}/')" name="skip" id="skip"> + Attempt Later <span class="fa fa-step-forward"></span> + </button> + {% endif %} + {% endif %} + </div> + </div> + </div> + </div> + </form> - {% if paper.question_paper.quiz.allow_skip and not paper.get_questions_unanswered|length_is:"1" %} - {% if question in paper.get_questions_unanswered %} - <button class="btn btn-primary" onclick="call_skip('{{ URL_ROOT }}/exam/{{ question.id }}/skip/{{ paper.attempt_number }}/{{ module.id }}/{{ paper.question_paper.id }}/{{course.id}}/')" name="skip" id="skip">Attempt Later <span class="fa fa-step-forward"></span></button> - {% endif %} - {% endif %} - </div> - </form> - - </div> - </div> - <br/> - <p id="status"></p> + <!-- Errors for code questions --> + <p id="status"></p> {% if question.type == 'code' or question.type == 'upload' %} - <div class="row" id="error_panel"></div> + <div id="error_panel"></div> {% endif %} - <!-- Modal --> - <div class="modal" id="upload_alert" > - <div class="modal-dialog"> - <div class="modal-content"> - <div class="modal-header"> - <h4 class="modal-title" id="myModalLabel">File not selected</h4> - </div> - <div id = "modal_body"class="modal-body"> - <font color="brown"><b>Kindly attach a file and then click upload.</b></font> - </div> - <div class="modal-footer"> - <button type="button" class="btn btn-primary" data-dismiss="modal">OK</button> - </div> + <!-- Modal --> + <div class="modal" id="upload_alert" > + <div class="modal-dialog"> + <div class="modal-content"> + <div class="modal-header"> + <h4 class="modal-title" id="myModalLabel">File not selected</h4> + </div> + <div id = "modal_body"class="modal-body"> + <font color="brown"><b>Kindly attach a file and then click upload.</b></font> + </div> + <div class="modal-footer"> + <button type="button" class="btn btn-primary" data-dismiss="modal">OK</button> </div> </div> - </div> + </div> + </div> - <!-- UNDO CHANGES Modal --> - <div class="modal" id="undo_changes" > - <div class="modal-dialog"> - <div class="modal-content"> - <div class="modal-header"> - <h4 class="modal-title" id="myModalLabel">Are you Sure?</h4> - </div> - <div id = "modal_body"class="modal-body"> - <font color="brown"><b>Your code will be reset.</b></font> - </div> - <div class="modal-footer"> - <button type="button" class="btn btn-warning" onclick="reset_editor()">OK</button> - <button type="button" class="btn btn-primary" data-dismiss="modal">Cancel</button> - </div> + <!-- UNDO CHANGES Modal --> + <div class="modal" id="undo_changes" > + <div class="modal-dialog"> + <div class="modal-content"> + <div class="modal-header"> + <h4 class="modal-title" id="myModalLabel">Are you Sure?</h4> + </div> + <div id = "modal_body"class="modal-body"> + <font color="brown"><b>Your code will be reset.</b></font> + </div> + <div class="modal-footer"> + <button type="button" class="btn btn-warning" onclick="reset_editor()">OK</button> + <button type="button" class="btn btn-primary" data-dismiss="modal">Cancel</button> </div> </div> - </div> + </div> + </div> {% endblock main %} diff --git a/yaksh/templates/yaksh/quit.html b/yaksh/templates/yaksh/quit.html index dd06ff9..ccb0893 100644 --- a/yaksh/templates/yaksh/quit.html +++ b/yaksh/templates/yaksh/quit.html @@ -1,13 +1,15 @@ {% extends "base.html" %} +{% load static %} + +{% block title %} Quit Quiz {% endblock %} {% block nav %} <div class="container-fluid yakshnav"> <nav class="navbar fixed-top navbar-expand-lg yakshheading yakshnav"> <div class="container"> - <a class="navbar-brand"> - <img src="{{ URL_ROOT }}/static/yaksh/images/yaksh_banner.png" alt="YAKSH"> - </img> - </a> + <a class="navbar-brand" href="{% url 'yaksh:index' %}"> + <img src="{% static 'yaksh/images/yaksh_banner.png' %}" alt="YAKSH"> + </a> </div><!-- /.container --> </nav><!-- /.navbar --> </div> @@ -15,11 +17,11 @@ {% block content %} <center> -<div class="col-md-8 yakshwell"> +<div class="col-md-8"> <h3>Submission Status</h3> <table class="table table-bordered table-responsive-sm" > <thead> - <tr class="yakshred text-center"> + <tr class="text-center"> <th> Question</th> <th> Status </th> </tr> @@ -32,7 +34,7 @@ <td> {{ question.summary }} </td> <td> Attempted </td> {% else %} - <tr class="table-danger"> + <tr class="table-warning"> <td> {{ question }} </td> <td> Not completed </td> {% endif %} @@ -50,11 +52,11 @@ <center><h4> Are you sure you wish to quit the exam?</h4></center> <center><h4> Be sure, as you won't be able to restart this exam.</h4></center> {% endif %} - <form action="{{URL_ROOT}}/exam/complete/{{ paper.attempt_number }}/{{module_id}}/{{ paper.question_paper.id }}/{{course_id}}/" method="post"> + <form action="{% url 'yaksh:complete' paper.attempt_number module_id paper.question_paper.id course_id %}" method="post"> {% csrf_token %} <center> - <button class="btn btn-outline-success" type="submit" name="yes">Yes!</button> - <button class="btn btn-outline-danger" type="button" name="no" onClick="window.location='{{ URL_ROOT }}/exam/start/{{ paper.attempt_number }}/{{module_id}}/{{ paper.question_paper.id }}/{{course_id}}'">No!</button> + <button class="btn btn-outline-success btn-lg" type="submit" name="yes">Yes</button> + <a class="btn btn-outline-danger btn-lg" name="no" href="{% url 'yaksh:start_quiz' paper.attempt_number module_id paper.question_paper.id course_id %}">No</a> </center> </form> {% endblock content %} diff --git a/yaksh/templates/yaksh/quizzes.html b/yaksh/templates/yaksh/quizzes.html new file mode 100644 index 0000000..7e53d31 --- /dev/null +++ b/yaksh/templates/yaksh/quizzes.html @@ -0,0 +1,122 @@ +{% extends "manage.html" %} +{% load static %} + +{% block title %} My Quizzes {% endblock %} +{% block content %} +<div class="container"> + <div class="row"> + <div class="col-md-8"> + <ul class="nav nav-pills" id="course_tabs"> + <li class="nav-item"> + <a class="nav-link {% if created %}active{% endif %}" href="{% url 'yaksh:courses' %}"> + My Courses + </a> + </li> + <li class="nav-item"> + <a class="nav-link" href="{% url 'yaksh:add_course' %}"> + Add New Course + </a> + </li> + <li class="nav-item dropdown hide"> + <a class="nav-link dropdown-toggle active" data-toggle="dropdown" href="#" role="button" aria-haspopup="true" aria-expanded="true">More</a> + <div class="dropdown-menu hide" x-placement="bottom-start" style="position: absolute; transform: translate3d(0px, 37px, 0px); top: 0px; left: 0px; will-change: transform;"> + <a class="dropdown-item active" href="{% url 'yaksh:show_all_quizzes' %}"> + Add/View Quizzes + </a> + <a class="dropdown-item" href="{% url 'yaksh:show_all_lessons' %}"> + Add/View Lessons + </a> + <a class="dropdown-item" href="{% url 'yaksh:show_all_modules' %}"> + Add/View Modules + </a> + <a href="{% url 'grades:grading_systems'%}" class="dropdown-item" > + Add/View Grading Systems + </a> + </div> + </li> + </ul> + </div> + </div> +</div> +<div class="container"> + <hr> + <a href="{% url 'yaksh:add_quiz' %}" class="btn btn-primary btn-lg"> + <i class="fa fa-plus-circle"></i> Add New Quiz + </a> + <a href="{% url 'yaksh:add_exercise' %}" class="btn btn-info btn-lg"> + <i class="fa fa-plus-circle"></i> Add New Exercise + </a> + {% if not quizzes %} + <br><br> + <div class="alert alert-info"> + <center><h3> No new Quiz added</h3></center> + </div> + {% else %} + <center><h3> Quizzes </h3></center> + <table class="table table-bordered table-responsive-sm"> + <tr> + <th>Sr.No</th> + <th>Quiz/Exercise</th> + <th>QuestionPaper</th> + </tr> + {% for quiz in quizzes %} + <tr> + <td>{{forloop.counter}}</td> + <td width="30%"> + <div class="row"> + <div class="col-md-7"> + {% if quiz.is_exercise %} + <a href="{% url 'yaksh:edit_exercise' quiz.id %}"> + {{ quiz.description }} + </a> + {% else %} + <a href="{% url 'yaksh:edit_quiz' quiz.id %}"> + {{ quiz.description }} + </a> + {% endif %} + </div> + <div class="col-md-5"> + {% if quiz.active %} + <span class="badge badge-success badge-pill"> + Active + </span> + {% else %} + <span class="badge badge-danger badge-pill"> + Closed + </span> + {% endif %} + </div> + </div> + </td> + <td> + {% if quiz.questionpaper_set.get %} + <div class="row"> + <div class="col-md-7"> + <a href="{% url 'yaksh:designquestionpaper' quiz.id quiz.questionpaper_set.get.id %}"> + Question Paper for {{ quiz.description }}</a> + </div> + <div class="col-md-5"> + <a href="{% url 'yaksh:preview_questionpaper' quiz.questionpaper_set.get.id %}" class="btn btn-primary active btn-xs" target="_blank"> + <i class="fa fa-eye"></i> Preview + </a> + </div> + </div> + {% else %} + <div class="row"> + <div class="col-md-7"> + <p>No Question Paper</p> + </div> + <div class="col-md-5"> + <a href="{% url 'yaksh:designquestionpaper' quiz.id %}" class="btn btn-success"> + <i class="fa fa-plus-circle"></i> Add + </a> + </div> + </div> + {% endif %} + </td> + {% endfor %} <!-- end for quizzes --> + </tr> + </table> + {% endif %} +</div> +{% endblock %}
\ No newline at end of file diff --git a/yaksh/templates/yaksh/quizzes_user.html b/yaksh/templates/yaksh/quizzes_user.html index eb3705e..7771954 100644 --- a/yaksh/templates/yaksh/quizzes_user.html +++ b/yaksh/templates/yaksh/quizzes_user.html @@ -7,186 +7,161 @@ {% block main %} <div class="container"> - {% if msg %} - <center><div class="col-md-8 alert alert-warning animated flash" role="alert"> - {{ msg }} - </div></center> - {% endif %} - - {% block navtab %} - {% if 'Enrolled Courses' not in title%} - <div class="container"> - <div class="nav nav-tabs yakshnavtab"> - <li class="nav-item" > - <a class="active nav-link bg-light" href="{{ URL_ROOT }}/exam/quizzes/" id="yakshactive">ALL COURSES</a> - </li> - <li class="nav-item"> - <a class="nav-link" href="{{ URL_ROOT }}/exam/quizzes/enrolled/">ENROLLED COURSES</a> - </li> - </div> - </div> - <div class="row justify-content-center yakshwell"> - <div class="col-md-6"> - <div class="yakshwell"> - <form action="{{ URL_ROOT }}/exam/quizzes/" method="post" id="custom-search-form" > - {% csrf_token %} - <div class="col-md-12"> - <div class="input-group"> - <div class="input-group-prepend"> - <span class="input-group-text" id="basic-addon1">Search Course</span> - </div> - <input type="text" name="course_code" class="form-control" type="search" placeholder="Enter Course-Code"> - <span class="input-group-append"> - <button class="btn btn-outline-secondary" type="submit"><i class="fa fa-search yakshred"></i></button> - <button class="btn btn-outline-secondary" type="button" name="button" onClick='location.replace("{{URL_ROOT}}/exam/quizzes/");'>Go Back</button> - </span> - </div> - </div> - </form> - </div> - </div> - </div> - {% else %} - <div class="container"> - <div class="nav nav-tabs yakshnavtab"> - <li class="nav-item" > - <a class="nav-link" href="{{ URL_ROOT }}/exam/quizzes/">ALL COURSES</a> - </li> - <li class="nav-item"> - <a class="active nav-link bg-light" href="{{ URL_ROOT }}/exam/quizzes/enrolled/" id="yakshactive">ENROLLED COURSES</a> - </li> + <center> + <h2>All Courses</h2> + </center> + <hr> + <div class="row justify-content-center"> + <div class="col-md-8"> + <form action="{% url 'yaksh:quizlist_user' %}" method="post" id="custom-search-form" > + {% csrf_token %} + <div class="col-md-12"> + <div class="input-group"> + <input type="text" name="course_code" class="form-control" type="search" placeholder="Enter course code to search" required=""> + <span class="input-group-append"> + <button class="btn btn-outline-info" type="submit"><i class="fa fa-search"></i> Search</button> + </span> + </div> </div> - </div> + </form> + </div> + {% if title == "Search" %} + <div class="col-md-4"> + <a href="{% url 'yaksh:quizlist_user' %}" class="btn btn-primary"> + <i class="fa fa-times"></i> Clear search + </a> + </div> {% endif %} - {% endblock %} + </div> + <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> + <br> + {% endfor %} + {% endif %} {% if not courses %} - <center><div class="col-md-8 alert alert-warning animated flash" role="alert"> + <center><div class="col-md-8 alert alert-warning" role="alert"> No Courses to display </div></center> {% endif %} - <div class="row justify-content-md-center align-items-center" > - <div class="col col-sm-10 yakshwell"> - {% for course in courses %} - <div class="yakshwell"> - <div class="row yakshlabel align-items-center"> - <div class="col"> - <a data-toggle="collapse" href="#collapsedetails{{course.data.id}}" role="button" aria-expanded="false" aria-controls="#collapsedetails{{course.data.id}}"> - <h4><b> - {{ course.data.name }} by {{ course.data.creator.get_full_name }} - </b></h4> - </a> - {% if course.data.is_active_enrollment %} - <div class="text-left"> - <span class="yakshgreen">{{course.data.start_enroll_time}}</span> to <span class="yakshgreen">{{course.data.end_enroll_time}}</span> - </div> - {% endif %} - </div> - <div class="col-sm-auto"> - {% if course.data.days_before_start != 0 %} - <span class="label label-info" style="font-size: 15px"> - {{course.data.days_before_start}} day(s) to start - </span> - {% endif %} - - </div> - <div class="container-fluid"> - <a class="btn btn-primary" data-toggle="collapse" href="#collapsedetails{{course.data.id}}" role="button" aria-expanded="false" aria-controls="#collapsedetails{{course.data.id}}">DETAILS</a> - {% if user in course.data.requests.all %} <span class="badge badge-warning">Request Pending </span> - {% elif user in course.data.rejected.all %}<span class="badge badge-danger">Request Rejected</span> - {% elif user in course.data.students.all %} - {% if course.data.has_lessons %} - <a href="{% url 'yaksh:download_course' course.data.id %}" data-toggle="tooltip" title="Download course content" class="btn btn-primary"> - Download Course - </a> - {% endif %} - <a class="btn btn-success" href="{{URL_ROOT}}/exam/course_modules/{{course.data.id}}" > - {% if course.completion_percentage > 0 %} - CONTINUE - {% else %} - START - {% endif %} - </a> - {% else %} - {% if course.data.active %} - {% if course.data.is_active_enrollment %} - {% if course.data.is_self_enroll %} - <a class="btn btn-success" href="{{ URL_ROOT }}/exam/self_enroll/{{ course.data.id }}">ENROLL</a> + <div class="col-md-12"> + <div id="accordian"> + {% for course in courses %} + <div class="card"> + <div class="card-header"> + <div class="row"> + <div class="col-md-7">{{course.data.name}}</div> + <div class="col-md-2"> + <a class="card-link btn btn-info" data-toggle="collapse" href="#collapse{{course.data.id}}"> + Details <i class="fa fa-toggle-down" id="toggle_course_{{course.id}}"></i> + </a> + </div> + <div class="col-md-2"> + {% if user in course.data.requests.all %} + <span class="badge badge-warning badge-pill"> + Request Pending + </span> + {% elif user in course.data.rejected.all %} + <span class="badge badge-danger badge-pill"> + Request Rejected + </span> + {% elif user in course.data.students.all %} + {% if course.completion_percentage > 0 %} + <a class="btn btn-primary" href="{% url 'yaksh:course_modules' course.data.id %}" > + Continue + </a> + {% else %} + <a class="btn btn-success" href="{% url 'yaksh:course_modules' course.data.id %}"> + Start + </a> + {% endif %} {% else %} - <a class="btn btn-success" href="{{ URL_ROOT }}/exam/enroll_request/{{ course.data.id }}">ENROLL</a> + {% if course.data.active %} + {% if course.data.is_active_enrollment %} + {% if course.data.is_self_enroll %} + <a class="btn btn-primary" href="{% url 'yaksh:self_enroll' course.data.id %}">Enroll</a> + {% else %} + <a class="btn btn-primary" href="{% url 'yaksh:enroll_request' course.data.id %}">Enroll</a> + {% endif %} + {% else %} + <span class="badge badge-danger badge-pill"> + Enrollment Closed + </span> + {% endif %} + {% else %} + <span class="badge badge-danger"> + Inactive Course + </span> + {% endif %} {% endif %} - {% else %} - <span class="btn btn-danger disabled" style="font-size: 15px"> - Enrollment Closed - </span> - {% endif %} - {% else %} - <span class="badge badge-danger" style="font-size: 15px"> - Inactive Course - </span> - {% endif %} - {% endif %} - </div> - <!-- About course--> - <div class="collapse container-fluid" id="collapsedetails{{course.data.id}}"> - <div class="card card-body "> - <h4>{{ course.data.name }} by {{ course.data.creator.get_full_name }}</h4><hr> - <div class="row"> - <div class="col-md-7"> - {% if course.data.description %} - <p> <span class="yakshred yakshheading">About the course</span><br> - {{ course.data.description }} - </p> - {% endif %} - {% if course.data.get_learning_modules %} - <p> <span class="yakshred yakshheading">What you'll learn</span> - <ul> - {% for module in course.data.get_learning_modules %} - <li>{{module.name|title}}</li> - {% endfor %} - </ul> - </p> - {% endif %} - <p> <span class="yakshred yakshheading">Instructor</span><br> - {{ course.data.creator.get_full_name }} - </p> - {% if course.data.instructions %} - <p> <span class="yakshred yakshheading">Instructions</span><br> - {{ course.data.instructions|safe }} - </p> - {% endif %} - </div> - <div class="col-md-4"> - <div class="row my-3"> - <div class="col-md-5"> - STARTS ON - </div> - <div class="col-md-7"> - {{course.data.start_enroll_time}} </div> </div> - <div class="row my-3"> - <div class="col-md-5"> - ENDS ON - </div> - <div class="col-md-7"> - {{course.data.end_enroll_time}} + </div> + <div id="collapse{{course.data.id}}" class="collapse hide" data-parent="#accordion"> + <div class="card-body"> + <div class="row"> + <div class="col-md-8"> + <p><b>Instructor:</b> {{course.data.creator.get_full_name|title}}</p> + {% with course.data.get_learning_modules as modules %} + {% if modules %} + <p> <span class="badge badge-pill badge-primary"> + Course Content</span> + <ul> + {% for module in modules %} + <li>{{module.name|title}}</li> + {% endfor %} + </ul> + </p> + {% endif %} + {% endwith %} + {% if course.data.instructions %} + <p> <span class="badge badge-pill badge-primary"> + Instructions</span><br> + {{ course.data.instructions|safe }} + </p> + {% endif %} + </div> + <div class="col-md-4"> + <p><b>Starts On:</b> {{course.data.start_enroll_time}}</p> + <p><b>Ends On:</b> {{course.data.end_enroll_time}}</p> + {% with course.completion_percentage as percent %} + <p><b>Course Progress:</b></p> + <div class="progress"> + {% if percent %} + {% if percent <= 50 %} + <div class="progress-bar bg-danger" role="progressbar" aria-valuenow="{{percent}}" + aria-valuemin="0" aria-valuemax="100" style="width:{{percent}}%"> + {% elif percent <= 75 %} + <div class="progress-bar bg-warning" role="progressbar" aria-valuenow="{{percent}}" + aria-valuemin="0" aria-valuemax="100" style="width:{{percent}}%"> + {% else %} + <div class="progress-bar bg-success" role="progressbar" aria-valuenow="{{percent}}" + aria-valuemin="0" aria-valuemax="100" style="width:{{percent}}%"> + {% endif %} + <b style="color: white;">{{percent}}% completed</b> + </div> + {% else %} + <b style="color: black;">0% completed</b> + {% endif %} + </div> + {% endwith %} + </div> </div> </div> - <div class="row my-3"> - <div class="progress-bar bg-success" role="progressbar" style="width:{{course.completion_percentage}}%"; color: black;" aria-valuenow="100" aria-valuemin="0" aria-valuemax="100">{{course.completion_percentage}} % completed - </div> - </div> </div> </div> - </div> - </div> - <!-- End of About course--> + <br> + {% endfor %} </div> </div> - {% endfor %} - </div> </div> </div> diff --git a/yaksh/templates/yaksh/show_video.html b/yaksh/templates/yaksh/show_video.html index 9d24b44..a2edbe0 100644 --- a/yaksh/templates/yaksh/show_video.html +++ b/yaksh/templates/yaksh/show_video.html @@ -2,168 +2,162 @@ {% load custom_filters %} {% block title %} {{ learning_module.name }} {% endblock %} - - {% block main %} - -<div class="row"> - - <!-- Side bar --> - <div class="col-md-3 yakshlabel collapse" id="sidebar"> - <center><h4><a class="text-dark" href="{{ URL_ROOT }}/exam/course_modules/{{course.id}}"><i class="fa fa-caret-left"></i> {{course.name}}</h4></center> - {% for module in all_modules %} - <div class="list-group"> - - <a href="{{URL_ROOT}}/exam/quizzes/view_module/{{module.id}}/{{course.id}}" id="menu1" class="list-group-item bg-light" data-parent="#sidebar"> - {% if module.id == learning_module.id %} - <i class="fa fa-toggle-on yakshred" data-toggle="tooltip" title="Currently on"> - </i> - {% else %} - <i class="fa fa-toggle-off" data-toggle="tooltip" title="Currently off"></i> - {% endif %} - {{module}} +<div class="wrapper"> + <!-- Sidebar --> + <nav id="sidebar"> + <div class="sidebar-header"> + <a class="text-light" href="{% url 'yaksh:course_modules' course.id %}"> + {{course.name}} </a> - {% for unit in module.get_learning_units %} - {% get_unit_status course module unit user as status %} - <span id="menudrop"> - {% if unit.type == "quiz" %} - <a href="{{ URL_ROOT }}/exam/start/{{unit.quiz.questionpaper_set.get.id}}/{{module.id}}/{{course.id}}" class="list-group-item" data-parent="#menu1"> - {% if status == "completed" %} - <i class="fa fa-check-square yakshgreen"></i> - {% else %} - <i class="fa fa-square-o"></i> - {% endif %} - {{ unit.quiz.description }} - {% if unit.id == current_unit.id %} - <i class="fa fa-thumb-tack yakshred" data-toggle="tooltip" title="Currently on"> - </i> - {% endif %} - </a> + </div> + {% for module in all_modules %} + <div id="accordian"> + <div class="card"> + <div class="card-header"> + <div class="row"> + <div class="col-md-10"> + <a href="{% url 'yaksh:view_module' module.id course.id %}"> + {{module.name}} + {% if learning_module.id == module.id %} + <i class="fa fa-edit"></i> + {% endif %} + </a> + </div> + <div class="col-md-2"> + <a class="card-link" data-toggle="collapse" href="#collapse{{module.id}}"> + <i class="fa fa-angle-down"></i> + </a> + </div> + </div> + </div> + {% if learning_module.id == module.id %} + <div id="collapse{{module.id}}" class="collapse show" data-parent="#accordion"> {% else %} - <a href="{{ URL_ROOT }}/exam/show_lesson/{{unit.lesson.id}}/{{module.id}}/{{course.id}}" class="list-group-item" data-parent="#menu1"> - {% if status == "completed" %} - <i class="fa fa-check-square yakshgreen"></i> - {% else %} - <i class="fa fa-square-o"></i> - {% endif %} - {{ unit.lesson.name }} - {% if unit.id == current_unit.id %} - <i class="fa fa-thumb-tack yakshred" data-toggle="tooltip" title="Currently on"> - </i> - {% endif %} - </a> + <div id="collapse{{module.id}}" class="collapse hide" data-parent="#accordion"> {% endif %} - </span> - {% endfor %} - - </div> + <div class="card-body"> + {% for unit in module.get_learning_units %} + {% get_unit_status course module unit user as status %} + {% if unit.type == "quiz" %} + <a href="{% url 'yaksh:start_quiz' unit.quiz.questionpaper_set.get.id module.id course.id %}" class="list-group-item"> + {% if status == "completed" %} + <i class="fa fa-check-square"></i> + {% else %} + <i class="fa fa-square-o"></i> + {% endif %} + {{ unit.quiz.description }} + </a> + {% else %} + <a href="{% url 'yaksh:show_lesson' unit.lesson.id module.id course.id %}" class="list-group-item"> + {% if status == "completed" %} + <i class="fa fa-check-square"></i> + {% else %} + <i class="fa fa-square-o"></i> + {% endif %} + {{ unit.lesson.name }} + {% if unit.id == current_unit.id %} + <i class="fa fa-play-circle" data-toggle="tooltip" title="Currently on"> + </i> + {% endif %} + </a> + {% endif %} + {% endfor %} + </div> + </div> + </div> + </div> {% endfor %} - </div> - <a href="#sidebar" data-toggle="collapse" id="sidebaricon"><i class="fa fa-navicon fa-lg"></i></a> - <!-- End of sidebar--> + </nav> - <main class="col" id="sidebarbody"> + <!-- Page Content --> + <div id="content"> - <div class="container-fluid yakshwell"> - <div class="yakshwell bg-light"> - <div class="row align-items-center "> - <div class="col h3 text-center"> - {{ learning_module.name }} - {% if state == "lesson" %} - : {{lesson.name}} - {% endif %} - </div> - </div> - </div> - - - {% if msg %} + <button type="button" id="sidebarCollapse" class="btn btn-outline-info"> + <i class="fa fa-navicon fa-lg"></i> + </button> + + <br><br> + <ol class="breadcrumb"> + <li class="breadcrumb-item"> + {{course.name}} + </li> + <li class="breadcrumb-item"> + {{ learning_module.name }} + </li> + {% if state == "lesson" %} + <li class="breadcrumb-item active">{{lesson.name}}</li> + {% endif %} + </ol> + <br> + + {% if msg %} <center> - <div class="col-md-8 yakshwell"> - <div class="alert alert-warning animated flash">{{msg}}</div> + <div class="alert alert-dismissible alert-warning"> + <button type="button" class="close" data-dismiss="alert"> + <i class="fa fa-close"></i> + </button> + <strong>{{ msg }}</strong> </div> </center> - {% endif %} + {% endif %} + - <div class="col-md-12 main"> {% if state == "module" %} <!-- Module instructions body --> - <div class="row yakshwell"> - <div class="col-md-8 "> - {{learning_module.html_data|safe}} - {% if learning_module.html_data%} - {% endif %} - </div> - </div> - <div class="yakshwell text-center"> - {% if first_unit %} - <a href="{{ URL_ROOT }}/exam/next_unit/{{course.id}}/{{learning_module.id}}/{{first_unit.id}}/1" class="btn btn-success">Start - <i class="fa fa-play"> - </i> - </a> - {% else %} - <a href="{{ URL_ROOT }}/exam/next_unit/{{course.id}}/{{learning_module.id}}" class="btn btn-success">Next - <i class="fa fa-step-forward"> - </i> - </a> - {% endif %} - </div> - </div> + {% if learning_module.html_data %} + {{learning_module.html_data|safe}} + {% else %} + No Module information + {% endif %} + <br> + {% if first_unit %} + <a href="{% url 'yaksh:next_unit' course.id learning_module.id first_unit.id '1' %}" class="btn btn-success btn-lg">Start + <i class="fa fa-play"> + </i> + </a> + {% else %} + <a href="{% url 'yaksh:next_unit' course.id learning_module.id %}" class="btn btn-success btn-lg">Next + <i class="fa fa-step-forward"> + </i> + </a> + {% endif %} {% else %} <!-- Lesson body --> - - <div class="yakshwell"> - <div class="yakshwell text-center "> - {{lesson.html_data|safe}} - </div> - {% if lesson.get_files %} - <div class="yakshwell col-md-5"> - <div class="card yakshwell"> - <span class="h4"> Files for this lesson </span> <hr> - <span class="col-md-2"> - {% for f in lesson.get_files %} - <div class="yakshwell"> - <a href="{{f.file.url}}" class="btn btn-outline-secondary"><b>{{forloop.counter}}.</b> {{ f.file.name|file_title }}</a> - <br> - </div> - {% endfor %} - </span> + <div class="col-md-6" style="width: 100%"> + {{lesson.html_data|safe}} + <br> + <a href="{% url 'yaksh:next_unit' course.id learning_module.id current_unit.id %}" class="btn btn-info btn-lg" > + Next <i class="fa fa-step-forward"></i> + </a> + </div> + <br> + <div class="col-md-7"> + {% with lesson.get_files as lesson_files %} + {% if lesson_files %} + <div class="card"> + <div class="card-header"> + Files for this lesson + </div> + <div class="card-body"> + {% for f in lesson_files %} + <a href="{{f.file.url}}" class="list-group-item"> + {{forloop.counter}}.{{ f.file.name|file_title }} + </a> + {% endfor %} </div> </div> {% endif %} - </div> - <div class="yakshwell text-center"> - <a href="{{ URL_ROOT }}/exam/next_unit/{{course.id}}/{{learning_module.id}}/{{current_unit.id}}" class="btn btn-info" >Next - <i class="fa fa-step-forward"> - </i> - </a> + {% endwith %} </div> {% endif %} - </div> </div> - </main> </div> -{% endblock %} - - -{% block footer %} - <!--footer--> - <footer class="container-fluid yakshsidebarfooter text-center"> - <div class="row justify-content-center"> - <div class="col-sm-5 "> - {% if user %} - {% block info %} - <b>{{user.get_full_name|title}}</b> with Roll no. <b>{{user.profile.roll_number}}</b> is logged in as <b>{{user.username}}</b> - {% endblock %} - {% endif %} - </div> - <div class="col-sm-2"> - | - </div> - <div class="col-sm-4 text-left"> - <b>Any Queries?</b> Email : info@fossee.in - </div> - </div> - </footer> - <!--footer end--> +<script type="text/javascript"> + $(document).ready(function () { + $('#sidebarCollapse').on('click', function () { + $('#sidebar').toggleClass('active'); + }); + }); +</script> {% endblock %} diff --git a/yaksh/templates/yaksh/showquestions.html b/yaksh/templates/yaksh/showquestions.html index 4216d94..895c345 100644 --- a/yaksh/templates/yaksh/showquestions.html +++ b/yaksh/templates/yaksh/showquestions.html @@ -14,9 +14,9 @@ {% block content %} <div class="container"> <!-- Side bar --> - <div class="nav nav-pills" id="sidebar" role="tablist" aria-orientation="vertical"> + <div class="nav nav-pills" role="tablist" aria-orientation="vertical"> <a href="#show" id="showbar" class="nav-link active" data-toggle="pill" role="tab" aria-controls="show" aria-selected="true"> Show all Questions</a> - <a href="#updown" id="updownbar" class="nav-link" data-toggle="pill" role="tab" aria-controls="updown" aria-selected="false" > Upload and Download Questions</a> + <a href="#updown" id="updownbar" class="nav-link" data-toggle="pill" role="tab" aria-controls="updown" aria-selected="false" > Upload Questions</a> </div> <!-- End of side bar --> <div class="tab-content"> @@ -49,7 +49,7 @@ <form action="" method="post" enctype="multipart/form-data"> {% csrf_token %} <div class="form-group col-md-6"> - <a class="btn btn-lg btn-primary" href="{% url 'yaksh:download_yaml_template' %}"> + <a class="btn btn-info" href="{% url 'yaksh:download_yaml_template' %}"> <i class="fa fa-download"></i> Download Template</a> <br><br> <h4> Or </h4> @@ -61,8 +61,10 @@ Choose file </label> </div> + <div class="input-group-append"> + <button class="btn btn-outline-primary" type="submit" name="upload" value="upload"><i class="fa fa-upload"></i> Upload File</button> + </div> </div> - <button class="btn btn-lg btn-success" type="submit" name="upload" value="upload"><i class="fa fa-upload"></i> Upload File</button> </div> <script> $('#id_file').on('change',function(){ @@ -138,11 +140,14 @@ {% endif %} </select> </div> + <br><br> + <div class="col-md-6"> + <a class="btn btn-primary" href="{% url 'yaksh:show_questions' %}"> + Clear Filters + </a> + </div> </div> </div> - <br/> - <a class="btn btn-lg btn-primary" href="{% url 'yaksh:show_questions' %}"> - Clear Filters</a> </div> </div> <div id="filtered-questions"> @@ -160,13 +165,13 @@ <thead> <tr class="yakshred"> <th> Select </th> - <th> Summary </th> - <th> Language </th> - <th> Type </th> - <th> Marks </th> + <th> Summary <i class="fa fa-sort"></i> </th> + <th> Language <i class="fa fa-sort"></i> </th> + <th> Type <i class="fa fa-sort"></i> </th> + <th> Marks <i class="fa fa-sort"></i> </th> </tr> </thead> - <tbody> + <tbody> {% for question in questions %} <tr> <td> @@ -183,6 +188,11 @@ </div> </div> {% include "yaksh/paginator.html" %} + {% else %} + <br><br> + <div class="alert alert-info"> + <center><h3>No Questions created</h3></center> + </div> {% endif %} </div> <br> @@ -190,9 +200,9 @@ {% if questions %} <button class="btn btn-lg btn-primary" type="submit" name='download' value='download'><i class="fa fa-download"></i> Download Selected</button> <button class="btn btn-lg btn-primary" type="submit" name="test" value="test">Test Selected</button> + <button class="btn btn-lg btn-danger" type="submit" onClick="return confirm_delete(frm);" name='delete' value='delete'> + <i class="fa fa-trash"></i> Delete Selected</button> {% endif %} - <button class="btn btn-lg btn-danger" type="submit" onClick="return confirm_delete(frm);" name='delete' value='delete'> - <i class="fa fa-trash"></i> Delete Selected</button> </center> </form> </div> diff --git a/yaksh/templates/yaksh/statistics_question.html b/yaksh/templates/yaksh/statistics_question.html index 4d737eb..58fd8db 100644 --- a/yaksh/templates/yaksh/statistics_question.html +++ b/yaksh/templates/yaksh/statistics_question.html @@ -3,24 +3,29 @@ {% block pagetitle %} Statistics for {{ quiz.description }}{% endblock pagetitle %} {% block content %} -<div class="yakshwell container"> -<div class="row"> - <div class="col-md-2"> -{% for attempt in attempts %} - <p><a href="{{URL_ROOT}}/exam/manage/statistics/question/{{questionpaper_id}}/{{attempt}}/{{course_id}}">Attempt {{ attempt }}</a></p> - {% endfor %} -</div> -<div class="col-md-9"> -{% if question_stats %} - <p><b>Total number of participants: {{ total }}</b></p> - <table class="table table-bordered table-responsive-sm"> - <tr class="bg-light yakshred"><th>Question</th><th>Type</th><th>Total</th><th>Answered</th></tr> - {% for question, value in question_stats.items %} - <tr><td>{{ question.summary }}</td><td>{{ question.type }}</td><td>{{value.1}}</td><td>{{ value.0 }} ({% widthratio value.0 value.1 100 %}%)</td></tr> - {% endfor %} - </table> - {% endif %} +<div class="container"> + <div class="row"> + <div class="col-md-2"> + <ul class="list-group"> + {% for attempt in attempts %} + <li class="list-group-item"> + <a href="{% url 'yaksh:show_statistics' questionpaper_id attempt course_id %}">Attempt {{ attempt }} + </a> + </li> + {% endfor %} + </ul> + </div> + <div class="col-md-9"> + {% if question_stats %} + <p><b>Total number of participants: {{ total }}</b></p> + <table class="table table-bordered table-responsive-sm"> + <tr class="bg-light yakshred"><th>Question</th><th>Type</th><th>Total</th><th>Answered</th></tr> + {% for question, value in question_stats.items %} + <tr><td>{{ question.summary }}</td><td>{{ question.type }}</td><td>{{value.1}}</td><td>{{ value.0 }} ({% widthratio value.0 value.1 100 %}%)</td></tr> + {% endfor %} + </table> + {% endif %} + </div> </div> </div> -</div> {% endblock %} diff --git a/yaksh/templates/yaksh/user_data.html b/yaksh/templates/yaksh/user_data.html index 317cb15..6547851 100644 --- a/yaksh/templates/yaksh/user_data.html +++ b/yaksh/templates/yaksh/user_data.html @@ -1,299 +1,354 @@ {% extends "manage.html" %} {% load custom_filters %} +{% load static %} +{% block title %} User Data {% endblock %} {% block pagetitle %} Data for user {{ data.user.get_full_name.title }} {% endblock pagetitle %} -{% block content %} + {% block script %} -<script src= "{{ URL_ROOT }}/static/yaksh/js/edit_question.js"></script> -<script src="{{ URL_ROOT }}/static/yaksh/js/mathjax/MathJax.js?config=TeX-MML-AM_CHTML"></script> +<script type="text/javascript" src="{% static 'yaksh/js/jquery.tablesorter.min.js' %}"> +</script> +<script type="text/javascript" src="{% static 'yaksh/js/mathjax/MathJax.js' %}?config=TeX-MML-AM_CHTML"></script> {% endblock %} -<div class="yakshwell container"> - <div class="card col-md-4"> - <p class="card-body"> - Name: {{ data.user.get_full_name.title }} <br/> - Username: {{ data.user.username }} <br/> - {% if data.profile %} - Roll number: {{ data.profile.roll_number }} <br/> - Position: {{ data.profile.position }} <br/> - Department: {{ data.profile.department }} <br/> - Institute: {{ data.profile.institute }} <br/> - {% endif %} - Email: {{ data.user.email }} <br/> - Date joined: {{ data.user.date_joined }} <br/> - Last login: {{ data.user.last_login }} - </p> - </div> - {% if data.papers %} - <p class="text-center"><a href="{{URL_ROOT}}/exam/manage/gradeuser/{{data.papers.0.question_paper.quiz.id}}/{{ data.user.id }}/{{course_id}}/" class="btn btn-info "> - Grade/correct paper</a> - </p> - {% for paper in data.papers %} - {% if forloop.counter == 2 and data.questionpaperid %} - <hr> - <u> - <h2> Previous attempts </h2> - </u> - {% endif %} - <h2> Quiz: {{ paper.question_paper.quiz.description }} </h2> - <p> - Attempt Number: {{ paper.attempt_number }}<br/> - Questions correctly answered: {{ paper.get_answered_str }} <br/> - Total attempts at questions: {{ paper.answers.count }} <br/> - Marks obtained: {{ paper.marks_obtained }} <br/> - Start time: {{ paper.start_time }} <br/> - User IP address: {{ paper.user_ip }} - </p> - {% if paper.answers.count %} - <div class="table-wrapper-2"> - <h3> Answers </h3> - <br> - {% for question, answers in paper.get_question_answers.items %} - <div class = "yakshlabel"> - <div class="card"> - <div class="card-heading alert-info" id="question_{{question.id}}"> - <strong> Details: {{forloop.counter}}. {{ question.summary }} - <a href="" onClick="grade_data('show_question{{question.id}}{{paper.attempt_number}}'); return false;"> Show Question </a> - <span class="marks pull-right"> Mark(s): {{ question.points }} </span> +{% block content %} +<div class="container"> + {% if data.papers %} + <p class="text-center"> + {% with data.papers.0 as paper %} + <div class="card"> + <div class="card-header"> + Course Details + </div> + <div class="card-body"> + <div class="row"> + <div class="col-md-6"> + <p><b>Course:</b> {{ paper.course.name }}</p> + <p><b>Quiz:</b> {{ paper.question_paper.quiz.description }}</p> + </div> + <div class="col-md-6"> + <p><b>Start time:</b> {{ paper.start_time }}</p> + <p><b>End time:</b> {{ paper.end_time }}</p> + <p><b>User IP:</b> {{paper.user_ip}} </p> + </div> + </div> + </div> + </div> + {% endwith %} + <br> + <a href="{% url 'yaksh:grade_user' data.papers.0.question_paper.quiz.id data.user.id course_id %}" class="btn btn-info"> + Grade User + </a> + <br> + {% for paper in data.papers %} + <br> + <h3><b><u>Attempt Number:</u></b> <span class="badge badge-pill badge-info"> + {{paper.attempt_number}} + </span></h3> + <div class="card"> + <div class="card-header"> + Scorecard + </div> + <div class="card-body"> + <p><b>Status:</b> + {% if paper.passed %} + <span class="badge badge-pill badge-success"> Passed </span> + {% else %} + <span class="badge badge-pill badge-danger"> Failed </span> + {% endif %} + </p> + <p><b>Total Marks:</b> {{ paper.question_paper.total_marks }}</p> + <p><b>Marks obtained:</b> {{ paper.marks_obtained }}</p> + {% if paper.percent %} + <p><b>Percentage obtained:</b> {{paper.percent}}%</p> + {% endif %} + <p><b>Total attempts at questions:</b> {{ paper.answers.count }}</p> + </div> + </div> + <br> + {% if paper.answers.count %} + <div class="card"> + <div class="card-header"> + Submission Details + </div> + <div class="card-body"> + <table class="tablesorter table table-striped table-bordered table-responsive-sm" id='marks_table'> + <thead> + <tr> + <th>Questions</th> + <th>Type</th> + <th>Marks Obtained</th> + </tr> + </thead> + <tbody> + {% for question, answers in paper.get_question_answers.items %} + {% with answers|last as answer %} + <tr> + <td> + <a href="#question_{{question.id}}"> + {{ question.summary }} + </a> + </td> + <td>{{ question.type }}</td> + <td>{{ answer.answer.marks }}</td> + </tr> + {% endwith %} + {% endfor %} + </tbody> + </table> + {% for question, answers in paper.get_question_answers.items %} + <div class="card" id="question_{{question.id}}"> + <div class="card-header text-white bg-info"> + <strong> + Details: {{forloop.counter}}. {{ question.summary }} + <span class="marks pull-right"> Mark(s): {{ question.points }} </span> </strong> - </div> - <div class="card-body" id="show_question{{question.id}}{{paper.attempt_number}}" style="display: none;"> - <h5><u>Question:</u></h5> + </div> + <div class="card-body"> + <h5> + <span class="badge badge-pill badge-primary">Question:</span> + </h5> <strong>{{ question.description|safe }}</strong> + <br><br> {% if question.type == "mcq" or question.type == "mcc" %} - <h5> <u>Choices:</u></h5> - {% for testcase in question.get_test_cases %} - {% if testcase.correct %} - <br/> - <strong>{{ forloop.counter }}. {{ testcase.options|safe }}</strong> - <span class="badge badge-success">Correct </span> - {% else %} - <br/><strong> - {{ forloop.counter }}. {{ testcase.options|safe }}</strong> - {% endif %} - {% endfor %} + <h5> + <span class="badge badge-pill badge-primary">Choices:</span> + </h5> + {% for testcase in question.get_test_cases %} + {% if testcase.correct %} + <strong> + <span class="badge badge-pill badge-success"> + {{ forloop.counter }}. + </span> + {{ testcase.options|safe }} + </strong> + {% else %} + <strong> + <span class="badge badge-pill badge-secondary"> + {{ forloop.counter }}. + </span> + {{ testcase.options|safe }} + </strong> + {% endif %} + <br> + {% endfor %} {% elif question.type == "integer" or question.type == "string" or question.type == "float" %} - <h5> <u>Correct Answer:</u></h5> - {% for testcase in question.get_test_cases %} - <strong>{{ testcase.correct|safe }}</strong> - {% if testcase.error_margin %} - <strong>{{ testcase.error_margin|safe }}</strong> - {% endif %} - {% endfor %} + <h5> + <span class="badge badge-pill badge-primary"> + Correct Answer: + </span> + </h5> + {% for testcase in question.get_test_cases %} + <strong>{{ testcase.correct }}</strong> + {% if testcase.error_margin %} + <strong>{{ testcase.error_margin }}</strong> + {% endif %} + {% endfor %} {% elif question.type == "arrange" %} - <h5> <u>Correct Order:</u></h5> - <div class="list-group" > - {% for testcase in question.get_test_cases %} - <li class="list-group-item"><strong>{{ testcase.options|safe }}</strong></li> - {% endfor %} - </div> + <h5> + <span class="badge badge-pill badge-primary"> + Correct Order:</span> + </h5> + <div class="list-group" > + {% for testcase in question.get_test_cases %} + <li class="list-group-item"> + <strong>{{ testcase.options }}</strong> + </li> + {% endfor %} + </div> {% else %} - <h5> <u>Test cases: </u></h5> - {% for testcase in question.get_test_cases %} - <br/><strong>{{ forloop.counter }}. {{ testcase }}</strong> - {% endfor %} - {%endif%} - </div> - </div> - <h5>Student answer: </h5> - {% if question.type == "upload" %} - {% if has_user_assignments %} - <a href="{{URL_ROOT}}/exam/manage/download/user_assignment/{{question.id}}/{{data.user.id}}/{{paper.question_paper.quiz.id}}/{{course_id}}"> - <div class="btn btn-outline-info text-center"> - Assignment File for {{ data.user.get_full_name.title }} - </div> - </a> - {% with answers|last as answer%} - {% if answer.answer.correct %} - <div class="card "> - <div class="card-heading alert-success">Correct answer</div> - </div> - {% else %} - <div class="card "> - <div class="card-heading alert-danger">Incorrect Answer</div> - </div> - {% endif %} - {% endwith %} - {% else %} - <center> - <div class="alert alert-warning animated flash"> - <h5>No Assignment submitted by {{ data.user.get_full_name.title }}</h5> - </div> - </center> - {% endif %} - {% else %} - {% for ans in answers %} - {% if ans.answer.correct %} - <div class="card "> - <div class="card-heading alert-success"> - Correct answer: + <h5> + <span class="badge badge-pill badge-primary">Test cases: + </span> + </h5> + {% for testcase in question.get_test_cases %} + <strong> + {{ forloop.counter }}. {{ testcase }} + </strong> + <br> + {% endfor %} + {% endif %} + <br> + <h5> + <span class="badge badge-pill badge-primary">Student answer(s): + </span> + </h5> + {% if question.type == "upload" %} + {% if has_user_assignments %} + <a href="{% url 'yaksh:download_user_assignment' question.id data.user.id paper.question_paper.quiz.id course_id %}"> + <div class="btn btn-outline-info text-center"> + Assignment File for {{ data.user.get_full_name.title }} + </div> + </a> + {% else %} + <center> + <div class="alert alert-warning"> + <h5> + Assignment not submitted by {{ data.user.get_full_name.title }} + </h5> + </div> + </center> + {% endif %} <!-- End has_user_assignments --> {% else %} - <div class="card "> - <div class="card-heading-heading alert-danger"> - Error: + {% for ans in answers %} + <strong> + Attempt Number: {{forloop.counter}} + </strong> + <div id="accordian"> + <div class="card"> + {% if ans.answer.correct %} + <div class="card-header"> + <span class="badge badge-success"> + Correct answer: + </span> + <a class="card-link" data-toggle="collapse" href="#submitted_{{ans.answer.id}}"> + <span class="pull-right"> + Details <i class="fa fa-toggle-down"></i> + </span> + </a> + </div> + {% else %} + <div class="card-header"> + <span class="badge badge-danger"> + Error: + </span> + <a class="card-link" data-toggle="collapse" href="#submitted_{{ans.answer.id}}"> + <span class="pull-right"> + Details <i class="fa fa-toggle-down"></i> + </span> + </a> + </div> {% endif %} - {% with ans.error_list as err %} - {% for error in err %} - {% if error.type == 'stdio' %} - <div class = "card"> - <div class="card-body"> - {% if error.given_input %} - <table class="table table-bordered table-responsive-sm"> - <col width="30%"> - <tr class = "table-active"> - <td> For given Input value(s):</td> - <td>{{error.given_input}}</td> - </tr> - </table> - {% endif %} - <table class="table table-bordered table-responsive-sm" width="100%" id="output" style="table-layout: fixed"> - <col width="10%"> - <col width="40%"> - <col width="40%"> - <col width="10%"> - <tr> - <th> - <center>Line No.</center> - </th> - <th> - <center>Expected Output</center> - </th> - <th> - <center>User output</center> - </th> - <th> - <center>Status</center> - </th> - </tr> - {% for expected,user in error.expected_output|zip:error.user_output %} - <tr> + <div class="collapse hide" id="submitted_{{ans.answer.id}}" data-parent="#accordion"> + <div class="card-body"> + {% with ans.error_list as err %} + {% for error in err %} + {% if error.type == 'stdio' %} + {% if error.given_input %} + <table class="table table-bordered table-responsive-sm"> + <tr class="table-active"> + <td> For given Input value(s):</td> + <td>{{error.given_input}}</td> + </tr> + </table> + {% endif %} + <table id="course-detail" class="table table-bordered table-responsive-sm" width="100%" id="output"> + <tr> + <th><center>Line No.</center></th> + <th><center>Expected Output</center></th> + <th><center>User output</center></th> + <th><center>Status</center></th> + </tr> + {% for expected,user in error.expected_output|zip:error.user_output %} <td> {{forloop.counter}} </td> <td>{{expected|default:""}} </td> <td>{{user|default:""}}</td> {% if forloop.counter0 in error.error_line_numbers or not expected or not user %} - <td><span class ="fa fa-times text-warning"></span></td> + <td><span class ="fa fa-times text-warning"/></td> {% else %} - <td><span class ="fa fa-check text-success"></span></td> + <td><span class ="fa fa-check text-success"/></td> {% endif %} - </tr> - {% endfor %} - </table> - <table width="100%" class="table table-bordered table-responsive-sm"> - <col width="10"> - <tr> - <td><b>Error:</b></td> - <td>{{error.error_msg}}</td> - </tr> - </table> - </div> - </div> - {% elif error.type == 'assertion' %} - {% if error.test_case %} - <strong> We tried you code with the following test case:</strong><br/></br> - <pre><code><strong style="color:#d9534f">{{error.test_case}}</strong></code></pre> - {% endif %} - <p> <b>The following error took place: </b></p> - <div class="card"> - <div class="card-body"> - <table class="table table-bordered table-responsive-sm" width="100%" style="table-layout: fixed"> - <col width="30%"> - <tr class = "active"> - <td><b>Exception Name: </b></td> - <td><span style="color: #d9534f">{{error.exception}}</span></td> - </tr> - <tr> - <td><b>Exception Message: </b></td> - <td>{{error.message}}</td> - </tr> - <tr> - {% if error.traceback %} - <td><b>Full Traceback: </b></td> - <td> - <pre>{{error.traceback}}</pre> - </td> - {% endif %} - </tr> - </table> - </div> - </div> - <!-- Closes card --> - {% else %} - <pre><code> {{error|safe}} </code></pre> - {% endif %} - {% endfor %} - {% endwith %} - </div> - <div class="card-body"> - {% if question.type == "code" %} - <pre><code>{{ ans.answer.answer.strip|safe }}</code></pre> - {% elif question.type == "mcc"%} - <div class="card"> - <div class="card-body"> - {% for testcases in question.get_test_cases %} - {%if testcases.id|stringformat:"i" in ans.answer.answer.strip|safe %} - <li>{{ testcases.options.strip|safe }}</li> - {% endif %} + </tr> + {% endfor %} + </table> + <table width="100%" class="table table-bordered table-responsive-sm"> + <col width="10"> + <tr> + <td>Error:</td> + <td>{{error.error_msg}}</td> + </tr> + </table> + {% elif error.type == 'assertion' %} + {% if error.test_case %} + <strong> + We tried you code with the following test case: + </strong><br><br> + <pre><code> + <strong>{{error.test_case}}</strong> + </code></pre> + {% endif %} + <p><b>The following error took place: </b></p> + <table id="course-detail" class="table table-bordered table-responsive-sm" width="100%"> + <tr class = "active"> + <td><b>Exception Name: </b></td> + <td><span>{{error.exception}}</span></td> + </tr> + <tr> + <td><b>Exception Message: </b></td><td>{{error.message}}</td> + </tr> + <tr> + {% if error.traceback %} + <td><b>Full Traceback: </b></td> + <td><pre>{{error.traceback}}</pre></td> + {% endif %} + </tr> + </table> + {% else %} + <pre><code> {{error}} </code></pre> + {% endif %} {% endfor %} - </div> - </div> - {% elif question.type == "mcq"%} - <div class="card"> - <div class="card-body"> + {% endwith %} + {% if question.type == "code" %} + {% pygmentise_user_answer question.language ans.answer.answer.strip as user_answer %} + <style type="text/css">{{user_answer.1}}</style> + <pre><code>{{user_answer.0|safe}}</code></pre> + {% elif question.type == "mcc" or question.type == "mcq" %} {% for testcases in question.get_test_cases %} - {%if testcases.id|stringformat:"i" == ans.answer.answer.strip|safe %} - <li>{{ testcases.options.strip|safe }}</li> - {% endif %} + {% if testcases.id|stringformat:"i" in ans.answer.answer.strip %} + <li>{{ testcases.options.strip|safe }}</li> + {% endif %} {% endfor %} - </div> - </div> - {% elif question.type == "arrange"%} - <div class="card"> - <div class="card-body"> + {% elif question.type == "arrange"%} {% get_answer_for_arrange_options ans.answer.answer question as tc_list %} {% for testcases in tc_list %} - <li>{{ testcases.options.strip|safe }}</li> + <li>{{ testcases.options.strip }}</li> {% endfor %} - </div> - </div> - {% else %} - <div class="card"> - <div class="card-body"> - {{ ans.answer.answer.strip|safe }} - </div> + {% else %} + {{ ans.answer.answer.strip }} + {% endif %} + </div> </div> - {% endif %} - </div> - </div> - {% endfor %} - {% endif %} + </div> + </div> + <br> + {% endfor %} <!-- End for ans in answers --> + </div> + </div> + {% endif %} + <br> + <div class="form-group"> + <div class="col-md-2"> + <label class="col-form-label" for="q{{ question.id }}">Marks:</label> {% with answers|last as answer %} - Marks: <input id="q{{ question.id }}" type="text" - name="q{{ question.id }}_marks" size="4" - value="{{ answer.answer.marks }}"><br><br> + <input id="q{{ question.id }}" type="text" name="q{{ question.id }}_marks" size="4" class="form-control" value="{{ answer.answer.marks }}" readonly=""><br><br> {% endwith %} - <hr/> - </div> - - {% endfor %} {# for question, answers ... #} - </div> - - -<h3>Teacher comments: </h3> -{{ paper.comments|default:"None" }} -{% endif %} {# if paper.answers.count #} -{% endfor %} {# for paper in data.papers #} -{% endif %} {# if data.papers #} + </div> + </div> + <hr/> + {% endfor %} {# for question, answers ... #} + <div class="form-group"> + <h3>Teacher comments: </h3> + <textarea id="comments_{{paper.question_paper.id}}" class="form-control" + name="comments_{{ paper.question_paper.id }}" readonly="">{{ paper.comments }}</textarea> + </div> + </div> + </div> + {% else %} + <div class="alert alert-warning"> + No submissions found + </div> + {% endif %} {# if paper.answers.count #} + <hr> + {% endfor %} {# for paper in data.papers #} + {% else %} + <br> + <center> + <div class="alert alert-warning"> + {% if quiz.is_exercise %} + You have not attempted the Exercise {{ quiz.description }} + {% else %} + You have not attempted the quiz {{ quiz.description }} + {% endif %} + </div> + </center> + {% endif %} {# if data.papers #} </div> - -<br /> -<hr /> -{% with data.papers.0 as paper %} -<a href="{{URL_ROOT}}/exam/manage/gradeuser/{{paper.question_paper.quiz.id}}/{{ data.user.id }}/{{course_id}}/">Grade/correct paper</a> -{% endwith %} -<br /> -{% if data.papers.count > 1 %} -<a href="{{URL_ROOT}}/exam/manage/monitor/">Monitor quiz</a> -{% else %} -{% with data.papers.0 as paper %} -<a href="{{URL_ROOT}}/exam/manage/monitor/{{paper.question_paper.id}}/">Monitor quiz</a> -{% endwith %} -{% endif %} -{% endblock %}
\ No newline at end of file +{% endblock %} diff --git a/yaksh/templates/yaksh/view_answerpaper.html b/yaksh/templates/yaksh/view_answerpaper.html index b87c818..c1f13d1 100644 --- a/yaksh/templates/yaksh/view_answerpaper.html +++ b/yaksh/templates/yaksh/view_answerpaper.html @@ -1,264 +1,354 @@ {% extends "user.html" %} {% load custom_filters %} +{% load static %} +{% block title %} View Answer paper {% endblock %} {% block pagetitle %} Answer Paper for {{ quiz.description }}{% endblock pagetitle %} {% block script %} -<script src="{{ URL_ROOT }}/static/yaksh/js/mathjax/MathJax.js?config=TeX-MML-AM_CHTML"></script> - -{% endblock script %} - -{% block main %} -<div class="yakshwell container"> -{% if not data.papers %} - {% if quiz.is_exercise %} - <p><b> You have not attempted the Exercise {{ quiz.description }} </b></p> - {% else %} - <p><b> You have not attempted the quiz {{ quiz.description }} </b></p> - {% endif %} -{% else %} - {% for paper in data.papers %} - {% if forloop.counter == 2 and data.questionpaperid %} - <U><h2> Previous attempts </h2></U> - {% endif %} - {% if quiz.is_exercise %} - <h2> Exercise: {{ paper.question_paper.quiz.description }} </h2> - {% else %} - <h2> Quiz: {{ paper.question_paper.quiz.description }} </h2> - {% endif %} - - <div class="card"> - <div class="card-body"> - Attempt Number: {{ paper.attempt_number }}<br/> - Questions correctly answered: {{ paper.get_answered_str }} <br/> - Marks obtained: {{ paper.marks_obtained }} <br/> - Start time: {{ paper.start_time }} <br/> - End time : {{ paper.end_time }} <br/> - Percentage obtained: {{ paper.percent }}% <br/> - {% if paper.passed %} - Status : <b style="color: green;"> Passed </b><br/> - {% else %} - Status : <b style="color: red;"> Failed </b><br/> - {% endif %} - </div> - </div> - - {% if paper.answers.count %} - <h3> Answerpaper: </h3> - {% for question, answers in paper.get_question_answers.items %} - - <div class="card"> - <div class="card-heading yakshlabel"> - <strong> Details: {{forloop.counter}}. {{ question.summary }} - <span class="marks pull-right"> Mark(s): {{ question.points }} </span> - </strong> +<script type="text/javascript" src="{% static 'yaksh/js/jquery.tablesorter.min.js' %}"> +</script> +<script type="text/javascript" src="{% static 'yaksh/js/mathjax/MathJax.js' %}?config=TeX-MML-AM_CHTML"></script> +{% endblock %} +{% block content %} +<div class="container"> + <a class="btn btn-primary" href="{% url 'yaksh:course_modules' course_id %}"> + <i class="fa fa-arrow-left"></i> + Back + </a> + <br><br> + {% if data.papers %} + <p class="text-center"> + {% with data.papers.0 as paper %} + <div class="card"> + <div class="card-header"> + Course Details </div> <div class="card-body"> - <h5><u>Question:</u></h5> <strong>{{ question.description }}</strong> - {% if question.type == "mcq" or question.type == "mcc" %} - <h5> <u>Choices:</u></h5> - {% get_ordered_testcases question paper as testcases %} - {% for testcase in testcases %} - {% if testcase.correct %} - <br/> - <strong>{{ forloop.counter }}. {{ testcase.options }}</strong> - <span class="alert alert-success"> Correct</span> - {% else %} - <br/><strong> - {{ forloop.counter }}. {{ testcase.options }}</strong> - {% endif %} - {% endfor %} - - {% elif question.type == "integer" or question.type == "string" or question.type == "float" %} - <h5> <u>Correct Answer:</u></h5> - {% for testcase in question.get_test_cases %} - <strong>{{ testcase.correct }}</strong> - {% endfor %} - - {% elif question.type == "arrange" %} - <h5> <u>Correct Order:</u></h5> - <div class="list-group"> - {% for testcase in question.get_test_cases %} - <li class="list-group-item"><strong>{{ testcase.options }}</strong></li> - {% endfor %} - </div> - - {% else %} - <h5> <u>Test cases: </u></h5> - {% for testcase in question.get_test_cases %} - <br/><strong>{{ forloop.counter }}. {{ testcase }}</strong> - {% endfor %} - {% endif %} - - </div> - </div> - {% if question.type != "code" %} - {% if "Correct answer" in answers.0.error_list %} - <div class="card alert-success"> - {% else %} - <div class="card card-danger"> - {% endif %} - <div class="card-heading"> - <strong>{{ answers.0.error_list.0 }}</strong> + <div class="row"> + <div class="col-md-6"> + <p><b>Course:</b> {{ paper.course.name }}</p> + <p><b>Quiz:</b> {{ paper.question_paper.quiz.description }}</p> </div> - <div class="card-body"> - {% if question.type == "mcc"%} - <div class="card"> - <div class="card-body"> - {% for testcases in question.get_test_cases %} - {%if testcases.id|stringformat:"i" in answers.0.answer %} - <li>{{ testcases.options.strip }}</li> - {% endif %} - {% endfor %} + <div class="col-md-6"> + <p><b>Start time:</b> {{ paper.start_time }}</p> + <p><b>End time:</b> {{ paper.end_time }}</p> + </div> + </div> </div> </div> - {% elif question.type == "mcq"%} - <div class="card"> - <div class="card-body"> - {% for testcases in question.get_test_cases %} - {%if testcases.id|stringformat:"i" == answers.0.answer %} - <li>{{ testcases.options.strip }}</li> - {% endif %} - {% endfor %} + {% endwith %} + {% for paper in data.papers %} + <br> + <h3><b><u>Attempt Number:</u></b> <span class="badge badge-pill badge-info"> + {{paper.attempt_number}} + </span></h3> + <div class="card"> + <div class="card-header"> + Scorecard + </div> + <div class="card-body"> + <p><b>Status:</b> + {% if paper.passed %} + <span class="badge badge-pill badge-success"> Passed </span> + {% else %} + <span class="badge badge-pill badge-danger"> Failed </span> + {% endif %} + </p> + <p><b>Total Marks:</b> {{ paper.question_paper.total_marks }}</p> + <p><b>Marks obtained:</b> {{ paper.marks_obtained }}</p> + {% if paper.percent %} + <p><b>Percentage obtained:</b> {{paper.percent}}%</p> + {% endif %} + <p><b>Total attempts at questions:</b> {{ paper.answers.count }}</p> </div> </div> - {% elif question.type == "arrange"%} + <br> + {% if paper.answers.count %} <div class="card"> + <div class="card-header"> + Submission Details + </div> <div class="card-body"> - {% get_answer_for_arrange_options answers.0.answer question as tc_list %} - {% for testcases in tc_list %} - <li>{{ testcases.options.strip }}</li> - {% endfor %} - </div> - </div> - {% elif question.type == "upload" and has_user_assignment %} - <a href="{{URL_ROOT}}/exam/download/user_assignment/{{question.id}}/{{data.user.id}}/{{paper.question_paper.quiz.id}}"> - <div class="card"> + <table class="tablesorter table table-striped table-bordered table-responsive-sm" id='marks_table'> + <thead> + <tr> + <th>Questions</th> + <th>Type</th> + <th>Marks Obtained</th> + </tr> + </thead> + <tbody> + {% for question, answers in paper.get_question_answers.items %} + {% with answers|last as answer %} + <tr> + <td> + <a href="#question_{{question.id}}"> + {{ question.summary }} + </a> + </td> + <td>{{ question.type }}</td> + <td>{{ answer.answer.marks }}</td> + </tr> + {% endwith %} + {% endfor %} + </tbody> + </table> + {% for question, answers in paper.get_question_answers.items %} + <div class="card" id="question_{{question.id}}"> + <div class="card-header text-white bg-info"> + <strong> + Details: {{forloop.counter}}. {{ question.summary }} + <span class="marks pull-right"> Mark(s): {{ question.points }} </span> + </strong> + </div> <div class="card-body"> - Assignment File for {{ data.user.get_full_name.title }} - </div></a> + <h5> + <span class="badge badge-pill badge-primary">Question:</span> + </h5> + <strong>{{ question.description|safe }}</strong> + <br><br> + {% if question.type == "mcq" or question.type == "mcc" %} + <h5> + <span class="badge badge-pill badge-primary">Choices:</span> + </h5> + {% for testcase in question.get_test_cases %} + {% if testcase.correct %} + <strong> + <span class="badge badge-pill badge-success"> + {{ forloop.counter }}. + </span> + {{ testcase.options|safe }} + </strong> + {% else %} + <strong> + <span class="badge badge-pill badge-secondary"> + {{ forloop.counter }}. + </span> + {{ testcase.options|safe }} + </strong> + {% endif %} + <br> + {% endfor %} + {% elif question.type == "integer" or question.type == "string" or question.type == "float" %} + <h5> + <span class="badge badge-pill badge-primary"> + Correct Answer: + </span> + </h5> + {% for testcase in question.get_test_cases %} + <strong>{{ testcase.correct }}</strong> + {% if testcase.error_margin %} + <strong>{{ testcase.error_margin }}</strong> + {% endif %} + {% endfor %} + {% elif question.type == "arrange" %} + <h5> + <span class="badge badge-pill badge-primary"> + Correct Order:</span> + </h5> + <div class="list-group" > + {% for testcase in question.get_test_cases %} + <li class="list-group-item"> + <strong>{{ testcase.options }}</strong> + </li> + {% endfor %} + </div> + {% else %} + <h5> + <span class="badge badge-pill badge-primary">Test cases: + </span> + </h5> + {% for testcase in question.get_test_cases %} + <strong> + {{ forloop.counter }}. {{ testcase }} + </strong> + <br> + {% endfor %} + {% endif %} + <br> + <h5> + <span class="badge badge-pill badge-primary">Student answer(s): + </span> + </h5> + {% if question.type == "upload" %} + {% if has_user_assignments %} + <a href="{% url 'yaksh:download_user_assignment' question.id data.user.id paper.question_paper.quiz.id course_id %}"> + <div class="btn btn-outline-info text-center"> + Assignment File for {{ data.user.get_full_name.title }} + </div> + </a> + {% else %} + <center> + <div class="alert alert-warning"> + <h5> + Assignment not submitted by {{ data.user.get_full_name.title }} + </h5> + </div> + </center> + {% endif %} <!-- End has_user_assignments --> + {% else %} + {% for ans in answers %} + <strong> + Attempt Number: {{forloop.counter}} + </strong> + <div id="accordian"> + <div class="card"> + {% if ans.answer.correct %} + <div class="card-header"> + <span class="badge badge-success"> + Correct answer: + </span> + <a class="card-link" data-toggle="collapse" href="#submitted_{{ans.answer.id}}"> + <span class="pull-right"> + Details <i class="fa fa-toggle-down"></i> + </span> + </a> + </div> + {% else %} + <div class="card-header"> + <span class="badge badge-danger"> + Error: + </span> + <a class="card-link" data-toggle="collapse" href="#submitted_{{ans.answer.id}}"> + <span class="pull-right"> + Details <i class="fa fa-toggle-down"></i> + </span> + </a> + </div> + {% endif %} + <div class="collapse hide" id="submitted_{{ans.answer.id}}" data-parent="#accordion"> + <div class="card-body"> + {% with ans.error_list as err %} + {% for error in err %} + {% if error.type == 'stdio' %} + {% if error.given_input %} + <table class="table table-bordered table-responsive-sm"> + <tr class="table-active"> + <td> For given Input value(s):</td> + <td>{{error.given_input}}</td> + </tr> + </table> + {% endif %} + <table id="course-detail" class="table table-bordered table-responsive-sm" width="100%" id="output"> + <tr> + <th><center>Line No.</center></th> + <th><center>Expected Output</center></th> + <th><center>User output</center></th> + <th><center>Status</center></th> + </tr> + {% for expected,user in error.expected_output|zip:error.user_output %} + <td> {{forloop.counter}} </td> + <td>{{expected|default:""}} </td> + <td>{{user|default:""}}</td> + {% if forloop.counter0 in error.error_line_numbers or not expected or not user %} + <td><span class ="fa fa-times text-warning"/></td> + {% else %} + <td><span class ="fa fa-check text-success"/></td> + {% endif %} + </tr> + {% endfor %} + </table> + <table width="100%" class="table table-bordered table-responsive-sm"> + <col width="10"> + <tr> + <td>Error:</td> + <td>{{error.error_msg}}</td> + </tr> + </table> + {% elif error.type == 'assertion' %} + {% if error.test_case %} + <strong> + We tried you code with the following test case: + </strong><br><br> + <pre><code> + <strong>{{error.test_case}}</strong> + </code></pre> + {% endif %} + <p><b>The following error took place: </b></p> + <table id="course-detail" class="table table-bordered table-responsive-sm" width="100%"> + <tr class = "active"> + <td><b>Exception Name: </b></td> + <td><span>{{error.exception}}</span></td> + </tr> + <tr> + <td><b>Exception Message: </b></td><td>{{error.message}}</td> + </tr> + <tr> + {% if error.traceback %} + <td><b>Full Traceback: </b></td> + <td><pre>{{error.traceback}}</pre></td> + {% endif %} + </tr> + </table> + {% else %} + <pre><code> {{error}} </code></pre> + {% endif %} + {% endfor %} + {% endwith %} + {% if question.type == "code" %} + {% pygmentise_user_answer question.language ans.answer.answer.strip as user_answer %} + <style type="text/css">{{user_answer.1}}</style> + <pre><code>{{user_answer.0|safe}}</code></pre> + {% elif question.type == "mcc" or question.type == "mcq" %} + {% for testcases in question.get_test_cases %} + {% if testcases.id|stringformat:"i" in ans.answer.answer.strip %} + <li>{{ testcases.options.strip|safe }}</li> + {% endif %} + {% endfor %} + {% elif question.type == "arrange"%} + {% get_answer_for_arrange_options ans.answer.answer question as tc_list %} + {% for testcases in tc_list %} + <li>{{ testcases.options.strip }}</li> + {% endfor %} + {% else %} + {{ ans.answer.answer.strip }} + {% endif %} + </div> + </div> + </div> + </div> + <br> + {% endfor %} <!-- End for ans in answers --> </div> - {% else %} - <h5><u>Student answer:</u></h5> - <div class="card"> - <div class="card-body"> - {{ answers.0.answer }} - </div> - </div> - {% endif %} - </div> - </div> - {% else %} - <h5>Student answer: </h5> - {% for answer in answers %} - {% if not answer.skipped %} - {% if answer.answer.correct %} - <div class="card"> - <div class="card-heading alert-success"> - <strong>Correct Answer</strong> - </div> - {% else %} - <div class="card "> - <div class="card-heading alert-danger"> - <strong>Incorrect Answer</strong> - </div> - {% endif %} - - {% with answer.error_list as err %} - {% for error in err %} - - {% if error.type == 'stdio' %} - <div class = "card"> - <div class="card-body"> - {% if error.given_input %} - <table class="table table-bordered table-responsive-sm"> - <col width="30%"> - <tr class = "table-active"> - <td> For given Input value(s):</td> - <td>{{error.given_input}}</td> - </tr> - </table> - {% endif %} - <table class="table table-bordered table-responsive-sm" width="100%" id="output" style="table-layout: fixed"> - <col width="10%"> - <col width="40%"> - <col width="40%"> - <col width="10%"> - <tr class="info"> - <th><center>Line No.</center></th> - <th><center>Expected Output</center></th> - <th><center>User output</center></th> - <th><center>Status</center></th> - </tr> - {% for expected,user in error.expected_output|zip:error.user_output %} - <td> {{forloop.counter}} </td> - <td>{{expected|default:""}} </td> - <td>{{user|default:""}}</td> - {% if forloop.counter0 in error.error_line_numbers or not expected or not user %} - <td><span class ="fa fa-times text-warning"/></td> - {% else %} - <td><span class ="fa fa-check text-success"/></td> - {% endif %} - </tr> - {% endfor %} - </table> - <table width="100%" class="table table-bordered table-responsive-sm"> - <col width="10"> - <tr class = "table-danger"> - <td><b>Error:</b></td> - <td>{{error.error_msg}}</td> - </tr> - </table> + </div> + {% endif %} + <br> + <div class="form-group"> + <div class="col-md-2"> + <label class="col-form-label" for="q{{ question.id }}">Marks:</label> + {% with answers|last as answer %} + <input id="q{{ question.id }}" type="text" name="q{{ question.id }}_marks" size="4" class="form-control" value="{{ answer.answer.marks }}" readonly=""><br><br> + {% endwith %} + </div> + </div> + <hr/> + {% endfor %} {# for question, answers ... #} + <div class="form-group"> + <h3>Teacher comments: </h3> + <textarea id="comments_{{paper.question_paper.id}}" class="form-control" + name="comments_{{ paper.question_paper.id }}" readonly="">{{ paper.comments }}</textarea> + </div> + </div> </div> - </div> - {% elif error.type == 'assertion' %} - {% if error.test_case %} - <strong> We tried you code with the following test case:</strong><br/></br> - <pre><code><strong style="color:#d9534f">{{error.test_case}}</strong></code></pre> - {% endif %} - <p> <b>The following error took place: </b></p> - <div class="well well-sm"> - <table class="table table-bordered table-responsive-sm" width="100%" style="table-layout: fixed"> - <col width="30%"> - <tr class = "active"> - <td><b>Exception Name: </b></td> - <td><span style="color: #d9534f">{{error.exception}}</span></td> - </tr> - <tr> - <td><b>Exception Message: </b></td><td>{{error.message}}</td> - </tr> - <tr> - {% if error.traceback %} - <td><b>Full Traceback: </b></td> - <td><pre>{{error.traceback}}</pre></td> - {% endif %} - </tr> - </table> - </div> <!-- Closes well --> - {% else %} - <pre><code> {{error}} </code></pre> - {% endif %} - {% endfor %} - {% endwith %} - <div class="panel-body"> - <pre><code>{{ answer.answer.answer.strip }}</code></pre> - </div> - </div> - {% endif %} - {% endfor %} - {% endif %} - {% with answers|last as answer %} - <p><em><mark>Obtained Marks: {{answer.answer.marks}}</mark></em> </p> - {% endwith %} - <hr> - {% endfor %} {# for question, answers ... #} - <h3>Teacher comments: </h3> - {{ paper.comments|default:"None" }} - <hr><hr> - {% endif %} {# if paper.answers.count #} - + {% else %} + <div class="alert alert-warning"> + No submissions found + </div> + {% endif %} {# if paper.answers.count #} + <hr> {% endfor %} {# for paper in data.papers #} - -{% endif %} {# if not data.papers #} + {% else %} + <br> + <center> + <div class="alert alert-warning"> + {% if quiz.is_exercise %} + You have not attempted the Exercise {{ quiz.description }} + {% else %} + You have not attempted the quiz {{ quiz.description }} + {% endif %} + </div> + </center> + {% endif %} {# if data.papers #} </div> {% endblock %} diff --git a/yaksh/templatetags/custom_filters.py b/yaksh/templatetags/custom_filters.py index 1cd3ca2..a78440d 100644 --- a/yaksh/templatetags/custom_filters.py +++ b/yaksh/templatetags/custom_filters.py @@ -7,6 +7,9 @@ try: from itertools import zip_longest except ImportError: from itertools import izip_longest as zip_longest +from pygments import highlight +from pygments.lexers import get_lexer_by_name +from pygments.formatters import HtmlFormatter register = template.Library() @@ -93,3 +96,26 @@ def course_grade(course, user): @register.filter(name='is_checkbox') def is_checkbox(value): return isinstance(value, CheckboxInput) + + +@register.simple_tag +def pygmentise_user_answer(language, answer): + lexer = get_lexer_by_name(language, stripall=True) + formatter = HtmlFormatter(linenos="inline", + cssclass="highlight", + style="colorful") + style = formatter.get_style_defs('.highlight') + result = highlight(answer, lexer, formatter) + return result, style + + +@register.simple_tag +def course_grade(course, user): + return course.get_grade(user) + + +@register.filter(name='highlight_spaces') +def highlight_spaces(text): + return text.replace( + " ", '<span style="background-color:#ffb6db"> </span>' + ) diff --git a/yaksh/templatetags/test_custom_filters.py b/yaksh/templatetags/test_custom_filters.py index eb1f0fb..9d7f246 100644 --- a/yaksh/templatetags/test_custom_filters.py +++ b/yaksh/templatetags/test_custom_filters.py @@ -11,7 +11,8 @@ from yaksh.models import (User, Profile, Question, Quiz, QuestionPaper, from yaksh.templatetags.custom_filters import (completed, inprogress, get_ordered_testcases, - get_answer_for_arrange_options + get_answer_for_arrange_options, + highlight_spaces ) @@ -57,6 +58,7 @@ def tearDownModule(): User.objects.get(username="teacher2000").delete() Group.objects.all().delete() + class CustomFiltersTestCases(unittest.TestCase): @classmethod @@ -148,3 +150,10 @@ class CustomFiltersTestCases(unittest.TestCase): self.assertSequenceEqual(testcases, ordered_testcases) new_answerpaper.delete() + + def test_highlight_spaces(self): + expected_output = "A " + highlighted_output = highlight_spaces(expected_output) + self.assertEqual(highlighted_output, + 'A<span style="background-color:#ffb6db"> </span>' + ) diff --git a/yaksh/test_views.py b/yaksh/test_views.py index 714fc67..569b468 100644 --- a/yaksh/test_views.py +++ b/yaksh/test_views.py @@ -20,6 +20,7 @@ from django.core import mail from django.conf import settings from django.core.files.uploadedfile import SimpleUploadedFile from django.core.files import File +from django.contrib.messages import get_messages from yaksh.models import ( @@ -429,29 +430,6 @@ class TestStudentDashboard(TestCase): self.assertEqual(response.context['title'], 'All Courses') self.assertEqual(response.context['courses'][0], courses_in_context) - def test_student_dashboard_enrolled_courses_get(self): - """ - Check student dashboard for all courses in which student is - enrolled - """ - self.client.login( - username=self.student.username, - password=self.student_plaintext_pass - ) - self.course.students.add(self.student) - response = self.client.get(reverse('yaksh:quizlist_user', - kwargs={'enrolled': "enrolled"}), - follow=True - ) - courses_in_context = { - 'data': self.course, - 'completion_percentage': 0, - } - self.assertEqual(response.status_code, 200) - self.assertTemplateUsed(response, "yaksh/quizzes_user.html") - self.assertEqual(response.context['title'], 'Enrolled Courses') - self.assertEqual(response.context['courses'][0], courses_in_context) - def test_student_dashboard_hidden_courses_post(self): """ Get courses for student based on the course code @@ -610,7 +588,7 @@ class TestMonitor(TestCase): ) self.assertEqual(response.status_code, 200) self.assertTemplateUsed(response, "yaksh/monitor.html") - self.assertEqual(response.context['course_details'][0], self.course) + self.assertEqual(response.context['objects'][0], self.course) self.assertEqual(response.context['msg'], "Monitor") def test_monitor_display_quiz_results(self): @@ -796,7 +774,7 @@ class TestGradeUser(TestCase): ) self.assertEqual(response.status_code, 200) self.assertTemplateUsed(response, "yaksh/grade_user.html") - self.assertEqual(response.context['course_details'][0], self.course) + self.assertEqual(response.context['objects'][0], self.course) def test_grade_user_get_quiz_users(self): """ @@ -1209,9 +1187,6 @@ class TestAddQuiz(TestCase): self.assertEqual(updated_quiz.description, 'updated demo quiz') self.assertEqual(updated_quiz.pass_criteria, 40) - self.assertEqual(response.status_code, 302) - self.assertRedirects(response, '/exam/manage/courses/all_quizzes/') - def test_add_quiz_post_new_quiz(self): """ POST request to add quiz should add new quiz if no quiz exists @@ -1254,9 +1229,6 @@ class TestAddQuiz(TestCase): self.assertEqual(new_quiz.description, 'new demo quiz') self.assertEqual(new_quiz.pass_criteria, 50) - self.assertEqual(response.status_code, 302) - self.assertRedirects(response, '/exam/manage/courses/all_quizzes/') - def test_add_exercise_denies_anonymous(self): """ If not logged in redirect to login page @@ -1319,8 +1291,6 @@ class TestAddQuiz(TestCase): self.assertEqual(updated_exercise.description, 'updated demo exercise') self.assertEqual(updated_exercise.pass_criteria, 0) self.assertTrue(updated_exercise.is_exercise) - self.assertEqual(response.status_code, 302) - self.assertRedirects(response, '/exam/manage/courses/all_quizzes/') def test_add_exercise_post_new_exercise(self): """ @@ -1346,8 +1316,6 @@ class TestAddQuiz(TestCase): self.assertEqual(new_exercise.description, 'Demo Exercise') self.assertEqual(new_exercise.pass_criteria, 0) self.assertTrue(new_exercise.is_exercise) - self.assertEqual(response.status_code, 302) - self.assertRedirects(response, '/exam/manage/courses/all_quizzes/') def test_show_all_quizzes(self): self.client.login( @@ -1359,9 +1327,8 @@ class TestAddQuiz(TestCase): follow=True ) self.assertEqual(response.status_code, 200) - self.assertEqual(response.context['type'], "quiz") self.assertEqual(response.context['quizzes'][0], self.quiz) - self.assertTemplateUsed(response, "yaksh/courses.html") + self.assertTemplateUsed(response, "yaksh/quizzes.html") class TestAddAsModerator(TestCase): @@ -1720,7 +1687,8 @@ class TestRemoveTeacher(TestCase): institute='IIT', department='Chemical', position='Moderator', - timezone='UTC' + timezone='UTC', + is_moderator=True ) # Create Student @@ -1836,16 +1804,10 @@ class TestRemoveTeacher(TestCase): ), data={'remove': teacher_id_list} ) - - self.assertEqual(response.status_code, 302) - redirect_destination = '/exam/manage/courses' - self.assertRedirects( - response, redirect_destination, status_code=302, - target_status_code=301 + self.assertEqual(response.status_code, 200) + self.assertFalse( + self.course.teachers.filter(id__in=teacher_id_list).exists() ) - for t_id in teacher_id_list: - teacher = User.objects.get(id=t_id) - self.assertNotIn(teacher, self.course.teachers.all()) class TestCourses(TestCase): @@ -2092,7 +2054,8 @@ class TestCourses(TestCase): ) # Student is not allowed if not enrolled in the course err_msg = "You are not enrolled for this course!" - self.assertEqual(response.context['msg'], err_msg) + messages = [m.message for m in get_messages(response.wsgi_request)] + self.assertEqual(messages[0], err_msg) self.assertEqual(response.status_code, 200) self.assertTemplateUsed(response, "yaksh/quizzes_user.html") @@ -2108,7 +2071,8 @@ class TestCourses(TestCase): ) err_msg = "{0} is either expired or not active".format( self.user1_course.name) - self.assertEqual(response.context['msg'], err_msg) + messages = [m.message for m in get_messages(response.wsgi_request)] + self.assertEqual(messages[0], err_msg) self.assertEqual(response.status_code, 200) self.assertTemplateUsed(response, "yaksh/quizzes_user.html") @@ -2157,9 +2121,9 @@ class TestCourses(TestCase): follow=True ) err_msg = "You do not have permissions" - self.assertEqual(response.status_code, 200) - self.assertTemplateUsed(response, "yaksh/complete.html") - self.assertIn(err_msg, response.context['message']) + self.assertEqual(response.status_code, 404) + messages = [m.message for m in get_messages(response.wsgi_request)] + self.assertIn(err_msg, messages[0]) # Test clone/duplicate courses and create copies of modules and units @@ -2577,10 +2541,10 @@ class TestCourseDetail(TestCase): # Then uploaded_user = User.objects.filter(email="abc@xyz.com") self.assertEqual(uploaded_user.count(), 1) - self.assertEqual(response.status_code, 200) - self.assertIn('upload_details', response.context) + self.assertEqual(response.status_code, 302) + messages = [m.message for m in get_messages(response.wsgi_request)] + self.assertIn("abc@xyz.com", messages[0]) self.assertIn(uploaded_user.first(), self.user1_course.students.all()) - self.assertTemplateUsed(response, 'yaksh/course_detail.html') def test_upload_existing_user(self): # Given @@ -2598,9 +2562,9 @@ class TestCourseDetail(TestCase): data={'csv_file': upload_file}) # Then - self.assertEqual(response.status_code, 200) - self.assertIn('upload_details', response.context) - self.assertTemplateUsed(response, 'yaksh/course_detail.html') + self.assertEqual(response.status_code, 302) + messages = [m.message for m in get_messages(response.wsgi_request)] + self.assertIn("demo_user2", messages[0]) self.assertIn(self.user2, self.user1_course.students.all()) def test_upload_same_user_multiple_course(self): @@ -2627,15 +2591,21 @@ class TestCourseDetail(TestCase): # Then uploaded_users = User.objects.filter(email='abc@xyz.com') - self.assertEqual(response1.status_code, 200) - self.assertIn('upload_details', response1.context) - self.assertTemplateUsed(response1, 'yaksh/course_detail.html') - self.assertEqual(response2.status_code, 200) - self.assertIn('upload_details', response2.context) - self.assertTemplateUsed(response2, 'yaksh/course_detail.html') - self.assertIn(uploaded_users.first(), self.user1_course.students.all()) - self.assertIn(uploaded_users.first(), - self.user1_othercourse.students.all()) + self.assertEqual(response1.status_code, 302) + messages1 = [m.message for m in get_messages(response1.wsgi_request)] + self.assertIn('abc@xyz.com', messages1[0]) + self.assertEqual(response2.status_code, 302) + messages2 = [m.message for m in get_messages(response2.wsgi_request)] + self.assertIn('abc@xyz.com', messages2[0]) + self.assertIn('abc@xyz.com', messages2[1]) + self.assertTrue( + self.user1_course.students.filter( + id=uploaded_users.first().id).exists() + ) + self.assertTrue( + self.user1_othercourse.students.filter( + id=uploaded_users.first().id).exists() + ) def test_upload_users_add_update_reject(self): # Given @@ -2661,9 +2631,10 @@ class TestCourseDetail(TestCase): self.assertEqual(uploaded_user.count(), 1) self.assertEqual(user.first_name, "test2") self.assertIn(user, self.user1_course.get_rejected()) - self.assertEqual(response.status_code, 200) - self.assertIn('upload_details', response.context) - self.assertTemplateUsed(response, 'yaksh/course_detail.html') + self.assertEqual(response.status_code, 302) + messages = [m.message for m in get_messages(response.wsgi_request)] + self.assertIn('test2', messages[2]) + self.assertIn('User rejected', messages[2]) def test_upload_users_with_wrong_csv(self): # Given @@ -2684,11 +2655,9 @@ class TestCourseDetail(TestCase): csv_file.close() # Then - self.assertEqual(response.status_code, 200) - self.assertNotIn('upload_details', response.context) - self.assertIn('message', response.context) - self.assertEqual(response.context['message'], message) - self.assertTemplateUsed(response, 'yaksh/course_detail.html') + self.assertEqual(response.status_code, 302) + messages = [m.message for m in get_messages(response.wsgi_request)] + self.assertEqual('The file uploaded is not a CSV file.', messages[0]) def test_upload_users_csv_with_missing_headers(self): # Given @@ -2710,11 +2679,11 @@ class TestCourseDetail(TestCase): csv_file.close() # Then - self.assertEqual(response.status_code, 200) - self.assertNotIn('upload_details', response.context) - self.assertIn('message', response.context) - self.assertEqual(response.context['message'], message) - self.assertTemplateUsed(response, 'yaksh/course_detail.html') + self.assertEqual(response.status_code, 302) + messages = [m.message for m in get_messages(response.wsgi_request)] + self.assertIn( + 'The CSV file does not contain the required headers', messages[0] + ) def test_upload_users_csv_with_no_values(self): # Given @@ -2735,12 +2704,9 @@ class TestCourseDetail(TestCase): csv_file.close() # Then - self.assertEqual(response.status_code, 200) - self.assertIn('upload_details', response.context) - self.assertNotIn('message', response.context) - self.assertIn("No rows in the CSV file", - response.context['upload_details']) - self.assertTemplateUsed(response, 'yaksh/course_detail.html') + self.assertEqual(response.status_code, 302) + messages = [m.message for m in get_messages(response.wsgi_request)] + self.assertIn("No rows in the CSV file", messages[0]) def test_upload_users_csv_with_missing_values(self): ''' @@ -2776,10 +2742,9 @@ class TestCourseDetail(TestCase): # Then uploaded_user = User.objects.filter(email="dummy@xyz.com") self.assertEqual(uploaded_user.count(), 1) - self.assertEqual(response.status_code, 200) - self.assertIn('upload_details', response.context) - self.assertNotIn('message', response.context) - self.assertTemplateUsed(response, 'yaksh/course_detail.html') + self.assertEqual(response.status_code, 302) + messages = [m.message for m in get_messages(response.wsgi_request)] + self.assertIn("Missing Values", messages[0]) def test_course_detail_denies_anonymous(self): """ @@ -2862,7 +2827,7 @@ class TestCourseDetail(TestCase): 'user_id': self.student.id}) ) enrolled_student = self.user1_course.students.all() - self.assertEqual(response.status_code, 200) + self.assertEqual(response.status_code, 302) self.assertSequenceEqual([self.student], enrolled_student) def test_student_course_enroll_post(self): @@ -2879,7 +2844,7 @@ class TestCourseDetail(TestCase): data={'check': self.student1.id} ) enrolled_student = self.user1_course.students.all() - self.assertEqual(response.status_code, 200) + self.assertEqual(response.status_code, 302) self.assertSequenceEqual([self.student1], enrolled_student) def test_student_course_reject_get(self): @@ -2896,7 +2861,7 @@ class TestCourseDetail(TestCase): 'user_id': self.student.id}) ) enrolled_student = self.user1_course.rejected.all() - self.assertEqual(response.status_code, 200) + self.assertEqual(response.status_code, 302) self.assertSequenceEqual([self.student], enrolled_student) def test_student_course_reject_post(self): @@ -2913,7 +2878,7 @@ class TestCourseDetail(TestCase): data={'check': self.student1.id} ) enrolled_student = self.user1_course.rejected.all() - self.assertEqual(response.status_code, 200) + self.assertEqual(response.status_code, 302) self.assertSequenceEqual([self.student1], enrolled_student) def test_toggle_course_status_get(self): @@ -2991,7 +2956,7 @@ class TestCourseDetail(TestCase): ) self.assertEqual(get_response.status_code, 200) self.assertEqual(get_response.context['course'], self.user1_course) - self.assertEqual(get_response.context['state'], 'mail') + self.assertTrue(get_response.context['is_mail']) def test_download_users_template(self): """ Test to check download users template """ @@ -3037,7 +3002,7 @@ class TestCourseDetail(TestCase): response = self.client.get(reverse('yaksh:course_status', kwargs={'course_id': self.user1_course.id})) self.assertEqual(response.status_code, 200) - self.assertEqual(response.context['state'], "course_status") + self.assertTrue(response.context['is_progress']) self.assertEqual(response.context['course'], self.user1_course) student_details = response.context['student_details'][0] student, grade, percent, current_unit = student_details @@ -3052,7 +3017,7 @@ class TestCourseDetail(TestCase): response = self.client.get(reverse('yaksh:course_status', kwargs={'course_id': self.user1_course.id})) self.assertEqual(response.status_code, 200) - self.assertEqual(response.context['state'], "course_status") + self.assertTrue(response.context['is_progress']) self.assertEqual(response.context['course'], self.user1_course) student_details = response.context['student_details'][0] student, grade, percent, current_unit = student_details @@ -4000,37 +3965,8 @@ class TestModeratorDashboard(TestCase): response = self.client.get(reverse('yaksh:manage'), follow=True) self.assertEqual(response.status_code, 200) self.assertTemplateUsed(response, "yaksh/moderator_dashboard.html") - self.assertEqual(response.context['trial_paper'][0], - self.trial_answerpaper) self.assertEqual(response.context['courses'][0], self.course) - def test_moderator_dashboard_delete_trial_papers(self): - """ - Check moderator dashboard to delete trial papers - """ - self.client.login( - username=self.user.username, - password=self.user_plaintext_pass - ) - self.course.is_trial = True - self.course.save() - response = self.client.post( - reverse('yaksh:manage'), - data={'delete_paper': [self.trial_answerpaper.id]} - ) - - self.assertEqual(response.status_code, 200) - self.assertTemplateUsed(response, "yaksh/moderator_dashboard.html") - updated_answerpaper = AnswerPaper.objects.filter(user=self.user) - updated_quiz = Quiz.objects.filter( - description=self.trial_question_paper.quiz.description - ) - updated_course = Course.objects.filter( - name=self.trial_course.name) - self.assertSequenceEqual(updated_answerpaper, []) - self.assertSequenceEqual(updated_quiz, []) - self.assertSequenceEqual(updated_course, []) - class TestUserLogin(TestCase): def setUp(self): @@ -4448,7 +4384,9 @@ class TestShowQuestions(TestCase): ) self.assertEqual(response.status_code, 200) self.assertTemplateUsed(response, 'yaksh/showquestions.html') - self.assertIn("download", response.context['msg']) + messages = [m.message for m in get_messages(response.wsgi_request)] + err_msg = "Please select atleast one question to download" + self.assertIn(err_msg, messages[0]) def test_upload_zip_questions(self): """ @@ -4490,7 +4428,8 @@ class TestShowQuestions(TestCase): ) self.assertEqual(response.status_code, 200) self.assertTemplateUsed(response, 'yaksh/showquestions.html') - self.assertIn("ZIP file", response.context['message']) + messages = [m.message for m in get_messages(response.wsgi_request)] + self.assertIn("Please Upload a ZIP file", messages[0]) def test_upload_yaml_questions(self): """ @@ -5392,7 +5331,7 @@ class TestQuestionPaper(TestCase): # Design question paper for a quiz response = self.client.post( - reverse('yaksh:design_questionpaper', + reverse('yaksh:designquestionpaper', kwargs={"quiz_id": self.quiz_without_qp.id}), data={"marks": "1.0", "question_type": "code"}) self.assertEqual(response.status_code, 200) @@ -5710,8 +5649,7 @@ class TestLearningModule(TestCase): "description": "my test1", "Save": "Save"}) - self.assertEqual(response.status_code, 302) - self.assertRedirects(response, self.expected_url) + self.assertEqual(response.status_code, 200) learning_module = LearningModule.objects.get(name="test module1") self.assertEqual(learning_module.description, "my test1") self.assertEqual(learning_module.creator, self.user) @@ -5734,8 +5672,7 @@ class TestLearningModule(TestCase): "description": "my test2", "Save": "Save"}) - self.assertEqual(response.status_code, 302) - self.assertRedirects(response, self.expected_url) + self.assertEqual(response.status_code, 200) learning_module = LearningModule.objects.get(name="test module2") self.assertEqual(learning_module.description, "my test2") self.assertEqual(learning_module.creator, self.user) @@ -5751,9 +5688,7 @@ class TestLearningModule(TestCase): ) response = self.client.get(reverse('yaksh:show_all_modules')) self.assertEqual(response.status_code, 200) - self.assertTemplateUsed(response, 'yaksh/courses.html') - self.assertEqual(response.context['type'], "learning_module") - self.assertEqual(response.context['learning_modules'][0], + self.assertEqual(response.context['modules'][0], self.learning_module) def test_teacher_can_edit_module(self): @@ -5770,8 +5705,7 @@ class TestLearningModule(TestCase): "description": "teacher module 2", "Save": "Save"}) - self.assertEqual(response.status_code, 302) - self.assertRedirects(response, "/exam/manage/courses/") + self.assertEqual(response.status_code, 200) learning_module = LearningModule.objects.get(name="teacher module 2") self.assertEqual(learning_module.description, "teacher module 2") self.assertEqual(learning_module.creator, self.user) @@ -6054,8 +5988,6 @@ class TestLessons(TestCase): self.learning_module.id, self.learning_module2.id]) self.course.teachers.add(self.teacher.id) - self.expected_url = "/exam/manage/courses/" - def tearDown(self): self.user.delete() self.student.delete() @@ -6103,18 +6035,16 @@ class TestLessons(TestCase): ) # Teacher edits existing lesson and adds file - self.assertEqual(response.status_code, 302) - self.assertRedirects(response, self.expected_url) + self.assertEqual(response.status_code, 200) updated_lesson = Lesson.objects.get(name="updated lesson") self.assertEqual(updated_lesson.description, "updated description") self.assertEqual(updated_lesson.creator, self.user) self.assertEqual(updated_lesson.html_data, Markdown().convert("updated description")) - self.assertEqual(os.path.basename(updated_lesson.video_file.name), - "test.mp4") + self.assertIn("test", os.path.basename(updated_lesson.video_file.name)) lesson_files = LessonFile.objects.filter( lesson=self.lesson).first() - self.assertIn("test.txt", lesson_files.file.name) + self.assertIn("test", lesson_files.file.name) lesson_file_path = lesson_files.file.path # Teacher removes the lesson file response = self.client.post( @@ -6124,8 +6054,7 @@ class TestLessons(TestCase): data={"delete_files": [str(lesson_files.id)], "Delete": "Delete"} ) - self.assertEqual(response.status_code, 302) - self.assertRedirects(response, self.expected_url) + self.assertEqual(response.status_code, 200) lesson_file_exists = LessonFile.objects.filter( lesson=self.lesson).exists() self.assertFalse(lesson_file_exists) @@ -6200,8 +6129,7 @@ class TestLessons(TestCase): ) response = self.client.get(reverse('yaksh:show_all_lessons')) self.assertEqual(response.status_code, 200) - self.assertTemplateUsed(response, "yaksh/courses.html") - self.assertEqual(response.context["type"], "lesson") + self.assertTemplateUsed(response, "yaksh/lessons.html") self.assertEqual(response.context["lessons"][0], self.lesson) def test_preview_lesson_description(self): diff --git a/yaksh/urls.py b/yaksh/urls.py index 3397fb1..49c3d4f 100644 --- a/yaksh/urls.py +++ b/yaksh/urls.py @@ -11,18 +11,19 @@ urlpatterns = [ url(r'^toggle_moderator/$', views.toggle_moderator_role, name='toggle_moderator'), url(r'^quizzes/$', views.quizlist_user, name='quizlist_user'), - url(r'^quizzes/(?P<enrolled>\w+)/$', views.quizlist_user, - name='quizlist_user'), url(r'^results/$', views.results_user), url(r'^start/(?P<questionpaper_id>\d+)/(?P<module_id>\d+)/' - '(?P<course_id>\d+)/$', views.start), + '(?P<course_id>\d+)/$', views.start, name="start_quiz"), url(r'^start/(?P<attempt_num>\d+)/(?P<module_id>\d+)/' - '(?P<questionpaper_id>\d+)/(?P<course_id>\d+)/$', views.start), + '(?P<questionpaper_id>\d+)/(?P<course_id>\d+)/$', views.start, + name="start_quiz"), url(r'^quit/(?P<attempt_num>\d+)/(?P<module_id>\d+)/' - '(?P<questionpaper_id>\d+)/(?P<course_id>\d+)/$', views.quit), - url(r'^complete/$', views.complete), + '(?P<questionpaper_id>\d+)/(?P<course_id>\d+)/$', views.quit, + name="quit_quiz"), + url(r'^complete/$', views.complete, name="complete"), url(r'^complete/(?P<attempt_num>\d+)/(?P<module_id>\d+)/' - '(?P<questionpaper_id>\d+)/(?P<course_id>\d+)/$', views.complete), + '(?P<questionpaper_id>\d+)/(?P<course_id>\d+)/$', views.complete, + name="complete"), url(r'^register/$', views.user_register, name="register"), url(r'^(?P<q_id>\d+)/check/$', views.check, name="check"), url(r'^get_result/(?P<uid>\d+)/(?P<course_id>\d+)/(?P<module_id>\d+)/$', @@ -32,10 +33,10 @@ urlpatterns = [ views.check, name="check"), url(r'^(?P<q_id>\d+)/skip/(?P<attempt_num>\d+)/(?P<module_id>\d+)/' '(?P<questionpaper_id>\d+)/(?P<course_id>\d+)/$', - views.skip), + views.skip, name="skip_question"), url(r'^(?P<q_id>\d+)/skip/(?P<next_q>\d+)/(?P<attempt_num>\d+)/' '(?P<module_id>\d+)/(?P<questionpaper_id>\d+)/(?P<course_id>\d+)/$', - views.skip), + views.skip, name="skip_question"), url(r'^enroll_request/(?P<course_id>\d+)/$', views.enroll_request, name='enroll_request'), url(r'^self_enroll/(?P<course_id>\d+)/$', views.self_enroll, @@ -91,7 +92,7 @@ urlpatterns = [ views.user_data, name="user_data"), url(r'^manage/user_data/(?P<user_id>\d+)/$', views.user_data), url(r'^manage/quiz/designquestionpaper/(?P<quiz_id>\d+)/$', - views.design_questionpaper, name='design_questionpaper'), + views.design_questionpaper, name='designquestionpaper'), url(r'^manage/designquestionpaper/(?P<quiz_id>\d+)/' '(?P<questionpaper_id>\d+)/$', views.design_questionpaper, name='designquestionpaper'), @@ -109,8 +110,6 @@ urlpatterns = [ url(r'^manage/duplicate_course/(?P<course_id>\d+)/$', views.duplicate_course, name='duplicate_course'), url(r'manage/courses/$', views.courses, name='courses'), - url(r'manage/allotted/courses/$', views.allotted_courses, - name='allotted_courses'), url(r'manage/add_course/$', views.add_course, name='add_course'), url(r'manage/edit_course/(?P<course_id>\d+)$', views.add_course, name='edit_course'), @@ -119,7 +118,7 @@ urlpatterns = [ url(r'manage/enroll/(?P<course_id>\d+)/(?P<user_id>\d+)/$', views.enroll, name="enroll_user"), url(r'manage/enroll/rejected/(?P<course_id>\d+)/(?P<user_id>\d+)/$', - views.enroll, {'was_rejected': True}), + views.enroll, {'was_rejected': True}, name="enroll_rejected"), url(r'manage/upload_users/(?P<course_id>\d+)/$', views.upload_users, name="upload_users"), url(r'manage/send_mail/(?P<course_id>\d+)/$', views.send_mail, @@ -137,10 +136,11 @@ urlpatterns = [ url(r'^manage/enroll/(?P<course_id>\d+)/$', views.enroll, name="enroll_users"), url(r'manage/enroll/rejected/(?P<course_id>\d+)/$', - views.enroll, {'was_rejected': True}), + views.enroll, {'was_rejected': True}, name="enroll_rejected"), url(r'manage/enrolled/reject/(?P<course_id>\d+)/$', views.reject, {'was_enrolled': True}, name="reject_users"), - url(r'^manage/searchteacher/(?P<course_id>\d+)/$', views.search_teacher), + url(r'^manage/searchteacher/(?P<course_id>\d+)/$', views.search_teacher, + name="search_teacher"), url(r'^manage/addteacher/(?P<course_id>\d+)/$', views.add_teacher, name='add_teacher'), url(r'^manage/remove_teachers/(?P<course_id>\d+)/$', views.remove_teachers, @@ -161,7 +161,7 @@ urlpatterns = [ url(r'^manage/regrade/paper/(?P<course_id>\d+)/(?P<answerpaper_id>\d+)/$', views.regrade, name='regrade'), url(r'^manage/(?P<mode>godmode|usermode)/(?P<quiz_id>\d+)/' - '(?P<course_id>\d+)/$', views.test_quiz), + '(?P<course_id>\d+)/$', views.test_quiz, name="test_quiz"), url(r'^manage/create_demo_course/$', views.create_demo_course, name="create_demo_course"), url(r'^manage/courses/download_course_csv/(?P<course_id>\d+)/$', @@ -202,8 +202,6 @@ urlpatterns = [ views.add_module, name="edit_module"), url(r'^manage/courses/designcourse/(?P<course_id>\d+)/$', views.design_course, name="design_course"), - url(r'^manage/courses/designcourse/(?P<course_id>\d+)/$', - views.design_course, name="design_course"), url(r'^manage/course_status/(?P<course_id>\d+)/$', views.course_status, name="course_status"), url(r'^manage/preview_questionpaper/(?P<questionpaper_id>\d+)/$', @@ -214,4 +212,10 @@ urlpatterns = [ views.download_course, name="download_course"), url(r'^download_course/(?P<course_id>\d+)/$', views.download_course, name="download_course"), + url(r'^manage/course/enrollments/(?P<course_id>\d+)', + views.course_students, name="course_students"), + url(r'^manage/course/all/modules/(?P<course_id>\d+)', + views.get_course_modules, name="get_course_modules"), + url(r'^manage/course/teachers/(?P<course_id>\d+)', + views.course_teachers, name="course_teachers"), ] diff --git a/yaksh/views.py b/yaksh/views.py index 98fde00..d1e8b7b 100644 --- a/yaksh/views.py +++ b/yaksh/views.py @@ -6,10 +6,12 @@ from django.shortcuts import render, get_object_or_404, redirect from django.template import Context, Template from django.http import Http404 from django.db.models import Max, Q, F +from django.db import models from django.views.decorators.csrf import csrf_exempt from django.contrib.auth.decorators import login_required from django.contrib.auth.models import Group from django.forms.models import inlineformset_factory +from django.forms import fields from django.utils import timezone from django.core.exceptions import ( MultipleObjectsReturned, ObjectDoesNotExist @@ -17,6 +19,7 @@ from django.core.exceptions import ( from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger from django.contrib import messages from taggit.models import Tag +from django.urls import reverse import json import six from textwrap import dedent @@ -99,6 +102,13 @@ def get_html_text(md_text): return Markdown().convert(md_text) +def formfield_callback(field): + if (isinstance(field, models.TextField) and field.name == 'expected_output' + or field.name == 'expected_input'): + return fields.CharField(strip=False) + return field.formfield() + + @email_verified def index(request, next_url=None): """The start page. @@ -165,20 +175,20 @@ def quizlist_user(request, enrolled=None, msg=None): hidden_courses = Course.objects.get_hidden_courses(code=course_code) courses = hidden_courses title = 'Search' - - elif enrolled is not None: - courses = user.students.filter(is_trial=False).order_by('-id') - title = 'Enrolled Courses' else: - courses = Course.objects.filter( - active=True, is_trial=False + courses = list(Course.objects.filter( + active=True, is_trial=False, ).exclude( ~Q(requests=user), ~Q(rejected=user), hidden=True - ).order_by('-id') + ).order_by('-id')) + enrolled_course = list( + user.students.filter(is_trial=False).order_by('-id') + ) + courses.extend(enrolled_course) title = 'All Courses' for course in courses: - if user in course.students.all(): + if course.students.filter(id=user.id).exists(): _percent = course.get_completion_percent(user) else: _percent = None @@ -189,9 +199,10 @@ def quizlist_user(request, enrolled=None, msg=None): } ) + messages.info(request, msg) context = { 'user': user, 'courses': courses_data, - 'title': title, 'msg': msg + 'title': title } return my_render_to_response(request, "yaksh/quizzes_user.html", context) @@ -245,8 +256,12 @@ 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__') + + formset = inlineformset_factory( + Question, testcase, extra=0, + fields='__all__', + formfield_callback=formfield_callback + ) formsets.append(formset( request.POST, request.FILES, instance=question ) @@ -323,15 +338,11 @@ def add_quiz(request, quiz_id=None, course_id=None): if quiz is None: form.instance.creator = user form.save() - if not course_id: - return my_redirect("/exam/manage/courses/all_quizzes/") - else: - return my_redirect("/exam/manage/courses/") - + messages.success(request, "Quiz saved successfully") else: form = QuizForm(instance=quiz) - context["course_id"] = course_id - context["quiz"] = quiz + context["course_id"] = course_id + context["quiz"] = quiz context["form"] = form return my_render_to_response(request, 'yaksh/add_quiz.html', context) @@ -368,12 +379,9 @@ def add_exercise(request, quiz_id=None, course_id=None): quiz.duration = 1000 quiz.pass_criteria = 0 quiz.save() - - if not course_id: - return my_redirect("/exam/manage/courses/all_quizzes/") - else: - return my_redirect("/exam/manage/courses/") - + messages.success( + request, "{0} saved successfully".format(quiz.description) + ) else: form = ExerciseForm(instance=quiz) context["exercise"] = quiz @@ -395,8 +403,8 @@ def prof_manage(request, msg=None): return my_redirect('/exam/') courses = Course.objects.get_queryset().filter( Q(creator=user) | Q(teachers=user), - is_trial=False).distinct().order_by("-id") - paginator = Paginator(courses, 10) + is_trial=False).distinct().order_by("-active") + paginator = Paginator(courses, 30) page = request.GET.get('page') try: courses = paginator.page(page) @@ -406,28 +414,8 @@ def prof_manage(request, msg=None): except EmptyPage: # If page is out of range (e.g. 9999), deliver last page of results. courses = paginator.page(paginator.num_pages) - trial_paper = AnswerPaper.objects.filter( - user=user, question_paper__quiz__is_trial=True, - course__is_trial=True - ) - if request.method == "POST": - delete_paper = request.POST.getlist('delete_paper') - for answerpaper_id in delete_paper: - answerpaper = AnswerPaper.objects.get(id=answerpaper_id) - qpaper = answerpaper.question_paper - answerpaper.course.remove_trial_modules() - answerpaper.course.delete() - if qpaper.quiz.is_trial: - qpaper.quiz.delete() - else: - if qpaper.answerpaper_set.count() == 1: - qpaper.quiz.delete() - else: - answerpaper.delete() - - context = {'user': user, 'objects': courses, - 'trial_paper': trial_paper, 'msg': msg - } + messages.info(request, msg) + context = {'user': user, 'objects': courses} return my_render_to_response( request, 'yaksh/moderator_dashboard.html', context ) @@ -509,14 +497,14 @@ def start(request, questionpaper_id=None, attempt_num=None, course_id=None, # is user enrolled in the course if not course.is_enrolled(user): msg = 'You are not enrolled in {0} course'.format(course.name) - if is_moderator(user): + if is_moderator(user) and course.is_trial: return prof_manage(request, msg=msg) return quizlist_user(request, msg=msg) # if course is active and is not expired if not course.active or not course.is_active_enrollment(): msg = "{0} is either expired or not active".format(course.name) - if is_moderator(user): + if is_moderator(user) and course.is_trial: return prof_manage(request, msg=msg) return quizlist_user(request, msg=msg) @@ -524,7 +512,7 @@ def start(request, questionpaper_id=None, attempt_num=None, course_id=None, if quest_paper.quiz.is_expired() or not quest_paper.quiz.active: msg = "{0} is either expired or not active".format( quest_paper.quiz.description) - if is_moderator(user): + if is_moderator(user) and course.is_trial: return prof_manage(request, msg=msg) return view_module(request, module_id=module_id, course_id=course_id, msg=msg) @@ -534,7 +522,7 @@ def start(request, questionpaper_id=None, attempt_num=None, course_id=None, if not learning_unit.is_prerequisite_complete( user, learning_module, course): msg = "You have not completed the previous Lesson/Quiz/Exercise" - if is_moderator(user): + if is_moderator(user) and course.is_trial: return prof_manage(request, msg=msg) return view_module(request, module_id=module_id, course_id=course_id, msg=msg) @@ -938,10 +926,9 @@ def complete(request, reason=None, attempt_num=None, questionpaper_id=None, """Show a page to inform user that the quiz has been completed.""" user = request.user if questionpaper_id is None: - message = ( - reason or "An Unexpected Error occurred." - " Please contact your instructor/administrator." - ) + message = reason or ("An Unexpected Error occurred. Please " + "contact your instructor/administrator." + ) context = {'message': message} return my_render_to_response(request, 'yaksh/complete.html', context) else: @@ -979,19 +966,22 @@ def add_course(request, course_id=None): if not is_moderator(user): raise Http404('You are not allowed to view this page') if request.method == 'POST': - form = CourseForm(request.POST, instance=course) + form = CourseForm(user, request.POST, instance=course) if form.is_valid(): new_course = form.save(commit=False) if course_id is None: new_course.creator = user new_course.save() + messages.success( + request, "Saved {0} successfully".format(new_course.name) + ) return my_redirect('/exam/manage/courses') else: return my_render_to_response( request, 'yaksh/add_course.html', {'form': form} ) else: - form = CourseForm(instance=course) + form = CourseForm(user, instance=course) return my_render_to_response( request, 'yaksh/add_course.html', {'form': form} ) @@ -1007,9 +997,15 @@ def enroll_request(request, course_id): 'Unable to add enrollments for this course, please contact your ' 'instructor/administrator.' ) - return complete(request, msg, attempt_num=None, questionpaper_id=None) - - course.request(user) + messages.warning(request, msg) + else: + course.request(user) + messages.success( + request, + "Enrollment request sent for {0} by {1}".format( + course.name, course.creator.get_full_name() + ) + ) if is_moderator(user): return my_redirect('/exam/manage/courses') else: @@ -1024,6 +1020,12 @@ def self_enroll(request, course_id): if course.is_self_enroll(): was_rejected = False course.enroll(was_rejected, user) + messages.success( + request, + "Enrolled in {0} by {1}".format( + course.name, course.creator.get_full_name() + ) + ) if is_moderator(user): return my_redirect('/exam/manage/') else: @@ -1037,8 +1039,9 @@ def courses(request): if not is_moderator(user): raise Http404('You are not allowed to view this page') courses = Course.objects.filter( - creator=user, is_trial=False).order_by('-id') - paginator = Paginator(courses, 20) + Q(creator=user) | Q(teachers=user), + is_trial=False).order_by('-active').distinct() + paginator = Paginator(courses, 30) page = request.GET.get('page') try: courses = paginator.page(page) @@ -1054,28 +1057,6 @@ def courses(request): @login_required @email_verified -def allotted_courses(request): - user = request.user - if not is_moderator(user): - raise Http404('You are not allowed to view this page') - allotted_courses = Course.objects.filter( - teachers=user, is_trial=False).order_by('-id') - paginator = Paginator(allotted_courses, 20) - page = request.GET.get('page') - try: - allotted_courses = paginator.page(page) - except PageNotAnInteger: - # If page is not an integer, deliver first page. - allotted_courses = paginator.page(1) - except EmptyPage: - # If page is out of range (e.g. 9999), deliver last page of results. - allotted_courses = paginator.page(paginator.num_pages) - context = {'allotted': True, "objects": allotted_courses} - return my_render_to_response(request, 'yaksh/courses.html', context) - - -@login_required -@email_verified def course_detail(request, course_id): user = request.user @@ -1105,7 +1086,8 @@ def enroll(request, course_id, user_id=None, was_rejected=False): ' please contact your ' 'instructor/administrator.' ) - return complete(request, msg, attempt_num=None, questionpaper_id=None) + messages.warning(request, msg) + return my_redirect(reverse('yaksh:course_students', args=[course_id])) if not course.is_creator(user) and not course.is_teacher(user): raise Http404('This course does not belong to you') @@ -1115,12 +1097,13 @@ def enroll(request, course_id, user_id=None, was_rejected=False): else: enroll_ids = [user_id] if not enroll_ids: - return my_render_to_response( - request, 'yaksh/course_detail.html', {'course': course} - ) + messages.warning(request, "Please select atleast one student") + return my_redirect(reverse('yaksh:course_students', args=[course_id])) + users = User.objects.filter(id__in=enroll_ids) course.enroll(was_rejected, *users) - return course_detail(request, course_id) + messages.success(request, "Enrolled student(s) successfully") + return my_redirect(reverse('yaksh:course_students', args=[course_id])) @login_required @@ -1146,9 +1129,10 @@ def send_mail(request, course_id, user_id=None): message = send_bulk_mail( subject, email_body, recipients, attachments ) + messages.info(request, message) context = { 'course': course, 'message': message, - 'state': 'mail' + 'enrolled': course.get_enrolled(), 'is_mail': True } return my_render_to_response(request, 'yaksh/course_detail.html', context) @@ -1169,14 +1153,13 @@ def reject(request, course_id, user_id=None, was_enrolled=False): else: reject_ids = [user_id] if not reject_ids: - message = "Please select atleast one User" - return my_render_to_response( - request, 'yaksh/course_detail.html', - {'course': course, 'message': message}, - ) + messages.warning(request, "Please select atleast one student") + return my_redirect(reverse('yaksh:course_students', args=[course_id])) + users = User.objects.filter(id__in=reject_ids) course.reject(was_enrolled, *users) - return course_detail(request, course_id) + messages.success(request, "Rejected students successfully") + return my_redirect(reverse('yaksh:course_students', args=[course_id])) @login_required @@ -1242,17 +1225,24 @@ def monitor(request, quiz_id=None, course_id=None): """Monitor the progress of the papers taken so far.""" user = request.user - if not user.is_authenticated() or not is_moderator(user): + if not is_moderator(user): raise Http404('You are not allowed to view this page!') if quiz_id is None: - course_details = Course.objects.filter( + courses = Course.objects.filter( Q(creator=user) | Q(teachers=user), is_trial=False - ).distinct() + ).order_by("-id").distinct() + paginator = Paginator(courses, 30) + page = request.GET.get('page') + try: + courses = paginator.page(page) + except PageNotAnInteger: + courses = paginator.page(1) + except EmptyPage: + courses = paginator.page(paginator.num_pages) context = { - "papers": [], "course_details": course_details, - "msg": "Monitor" + "papers": [], "objects": courses, "msg": "Monitor" } return my_render_to_response(request, 'yaksh/monitor.html', context) # quiz_id is not None. @@ -1364,12 +1354,12 @@ def _remove_already_present(questionpaper_id, questions): return questions -def _get_questions_from_tags(question_tags, user): +def _get_questions_from_tags(question_tags, user, active=True): search_tags = [] for tags in question_tags: search_tags.extend(re.split('[; |, |\*|\n]', tags)) return Question.objects.filter(tags__name__in=search_tags, - user=user).distinct() + user=user, active=active).distinct() @login_required @@ -1427,19 +1417,27 @@ def design_questionpaper(request, quiz_id, questionpaper_id=None, question_paper.fixed_question_order = questions_order question_paper.save() question_paper.fixed_questions.add(*questions) + messages.success(request, "Questions added successfully") + else: + messages.warning(request, "Please select atleast one question") if 'remove-fixed' in request.POST: question_ids = request.POST.getlist('added-questions', None) - if question_paper.fixed_question_order: - que_order = question_paper.fixed_question_order.split(",") - for qid in question_ids: - que_order.remove(qid) - if que_order: - question_paper.fixed_question_order = ",".join(que_order) - else: - question_paper.fixed_question_order = "" - question_paper.save() - question_paper.fixed_questions.remove(*question_ids) + if question_ids: + if question_paper.fixed_question_order: + que_order = question_paper.fixed_question_order.split(",") + for qid in question_ids: + que_order.remove(qid) + if que_order: + question_paper.fixed_question_order = ",".join( + que_order) + else: + question_paper.fixed_question_order = "" + question_paper.save() + question_paper.fixed_questions.remove(*question_ids) + messages.success(request, "Questions removed successfully") + else: + messages.warning(request, "Please select atleast one question") if 'add-random' in request.POST: question_ids = request.POST.getlist('random_questions', None) @@ -1451,14 +1449,21 @@ def design_questionpaper(request, quiz_id, questionpaper_id=None, random_ques = Question.objects.filter(id__in=question_ids) random_set.questions.add(*random_ques) question_paper.random_questions.add(random_set) + messages.success(request, "Questions removed successfully") + else: + messages.warning(request, "Please select atleast one question") if 'remove-random' in request.POST: random_set_ids = request.POST.getlist('random_sets', None) - question_paper.random_questions.remove(*random_set_ids) + if random_set_ids: + question_paper.random_questions.remove(*random_set_ids) + messages.success(request, "Questions removed successfully") + else: + messages.warning(request, "Please select question set") if 'save' in request.POST or 'back' in request.POST: qpaper_form.save() - return my_redirect('/exam/manage/courses/all_quizzes/') + messages.success(request, "Question Paper saved successfully") if marks: questions = _get_questions(user, question_type, marks) @@ -1506,7 +1511,7 @@ def show_all_questions(request): user_tags = questions.values_list('tags', flat=True).distinct() all_tags = Tag.objects.filter(id__in=user_tags) upload_form = UploadFileForm() - paginator = Paginator(questions, 10) + paginator = Paginator(questions, 30) page = request.GET.get('page') try: questions = paginator.page(page) @@ -1590,7 +1595,7 @@ def show_all_questions(request): def user_data(request, user_id, questionpaper_id=None, course_id=None): """Render user data.""" current_user = request.user - if not current_user.is_authenticated() or not is_moderator(current_user): + if not is_moderator(current_user): raise Http404('You are not allowed to view this page!') user = User.objects.get(id=user_id) data = AnswerPaper.objects.get_user_data(user, questionpaper_id, course_id) @@ -1693,12 +1698,22 @@ def grade_user(request, quiz_id=None, user_id=None, attempt_number=None, and update all their marks and also give comments for each paper. """ current_user = request.user - if not current_user.is_authenticated() or not is_moderator(current_user): + if not is_moderator(current_user): raise Http404('You are not allowed to view this page!') - course_details = Course.objects.filter(Q(creator=current_user) | - Q(teachers=current_user), - is_trial=False).distinct() - context = {"course_details": course_details} + if not course_id: + courses = Course.objects.filter( + Q(creator=current_user) | Q(teachers=current_user), is_trial=False + ).order_by("-id").distinct() + paginator = Paginator(courses, 30) + page = request.GET.get('page') + try: + courses = paginator.page(page) + except PageNotAnInteger: + courses = paginator.page(1) + except EmptyPage: + courses = paginator.page(paginator.num_pages) + context = {"objects": courses, "msg": "grade"} + if quiz_id is not None: questionpaper_id = QuestionPaper.objects.filter( quiz_id=quiz_id @@ -1720,7 +1735,8 @@ def grade_user(request, quiz_id=None, user_id=None, attempt_number=None, "quiz_id": quiz_id, "quiz": quiz, "has_quiz_assignments": has_quiz_assignments, - "course_id": course_id + "course_id": course_id, + "status": "grade" } if user_id is not None: attempts = AnswerPaper.objects.get_user_all_attempts( @@ -1747,7 +1763,8 @@ def grade_user(request, quiz_id=None, user_id=None, attempt_number=None, "user_id": user_id, "has_user_assignments": has_user_assignments, "has_quiz_assignments": has_quiz_assignments, - "course_id": course_id + "course_id": course_id, + "status": "grade" } if request.method == "POST": papers = data['papers'] @@ -1762,6 +1779,7 @@ def grade_user(request, quiz_id=None, user_id=None, attempt_number=None, paper.comments = request.POST.get( 'comments_%d' % paper.question_paper.id, 'No comments') paper.save() + messages.success(request, "Student data saved successfully") course_status = CourseStatus.objects.filter(course=course, user=user) if course_status.exists(): @@ -1854,7 +1872,8 @@ def search_teacher(request, course_id): ) context['success'] = True context['teachers'] = teachers - return my_render_to_response(request, 'yaksh/addteacher.html', context) + context['is_add_teacher'] = True + return my_render_to_response(request, 'yaksh/course_detail.html', context) @login_required @@ -1904,7 +1923,9 @@ def add_teacher(request, course_id): course.add_teachers(*teachers) context['status'] = True context['teachers_added'] = teachers - return my_render_to_response(request, 'yaksh/addteacher.html', context) + messages.success(request, "Added teachers successfully") + context['is_add_teacher'] = True + return my_render_to_response(request, 'yaksh/course_detail.html', context) @login_required @@ -1920,9 +1941,13 @@ def remove_teachers(request, course_id): if request.method == "POST": teacher_ids = request.POST.getlist('remove') - teachers = User.objects.filter(id__in=teacher_ids) - course.remove_teachers(*teachers) - return my_redirect('/exam/manage/courses') + if teacher_ids: + teachers = User.objects.filter(id__in=teacher_ids) + course.remove_teachers(*teachers) + messages.success(request, "Removed teachers successfully") + else: + messages.warning(request, "Please select atleast one teacher") + return course_teachers(request, course_id) def test_mode(user, godmode=False, questions_list=None, quiz_id=None, @@ -1963,6 +1988,10 @@ def test_quiz(request, mode, quiz_id, course_id=None): current_user = request.user quiz = Quiz.objects.get(id=quiz_id) if (quiz.is_expired() or not quiz.active) and not godmode: + messages.warning( + request, + "{0} is either expired or inactive".format(quiz.description) + ) return my_redirect('/exam/manage') trial_questionpaper, trial_course, trial_module = test_mode( @@ -2233,66 +2262,60 @@ def upload_users(request, course_id): context = {'course': course} if not (course.is_teacher(user) or course.is_creator(user)): - msg = 'You do not have permissions to this course.' - return complete(request, reason=msg) + raise Http404('You are not allowed to view this page!') if request.method == 'POST': if 'csv_file' not in request.FILES: - context['message'] = "Please upload a CSV file." - return my_render_to_response( - request, 'yaksh/course_detail.html', context - ) + messages.warning(request, "Please upload a CSV file.") + return my_redirect(reverse('yaksh:course_students', + args=[course_id])) csv_file = request.FILES['csv_file'] is_csv_file, dialect = is_csv(csv_file) if not is_csv_file: - context['message'] = "The file uploaded is not a CSV file." - return my_render_to_response( - request, 'yaksh/course_detail.html', context - ) + messages.warning(request, "The file uploaded is not a CSV file.") + return my_redirect(reverse('yaksh:course_students', + args=[course_id])) required_fields = ['firstname', 'lastname', 'email'] try: reader = csv.DictReader( csv_file.read().decode('utf-8').splitlines(), dialect=dialect) except TypeError: - context['message'] = "Bad CSV file" - return my_render_to_response( - request, 'yaksh/course_detail.html', context - ) + messages.warning(request, "Bad CSV file") + return my_redirect(reverse('yaksh:course_students', + args=[course_id])) stripped_fieldnames = [ field.strip().lower() for field in reader.fieldnames] for field in required_fields: if field not in stripped_fieldnames: - context['message'] = "The CSV file does not contain the"\ - " required headers" - return my_render_to_response( - request, 'yaksh/course_detail.html', context - ) + msg = "The CSV file does not contain the required headers" + messages.warning(request, msg) + return my_redirect(reverse('yaksh:course_students', + args=[course_id])) reader.fieldnames = stripped_fieldnames - context['upload_details'] = _read_user_csv(reader, course) - return my_render_to_response(request, 'yaksh/course_detail.html', context) + _read_user_csv(request, reader, course) + return my_redirect(reverse('yaksh:course_students', args=[course_id])) -def _read_user_csv(reader, course): +def _read_user_csv(request, reader, course): fields = reader.fieldnames - upload_details = ["Upload Summary:"] counter = 0 for row in reader: counter += 1 (username, email, first_name, last_name, password, roll_no, institute, department, remove) = _get_csv_values(row, fields) if not email or not first_name or not last_name: - upload_details.append("{0} -- Missing Values".format(counter)) + messages.info(request, "{0} -- Missing Values".format(counter)) continue users = User.objects.filter(username=username) if users.exists(): user = users[0] if remove.strip().lower() == 'true': _remove_from_course(user, course) - upload_details.append("{0} -- {1} -- User rejected".format( - counter, user.username)) + messages.info(request, "{0} -- {1} -- User rejected".format( + counter, user.username)) else: _add_to_course(user, course) - upload_details.append( + messages.info(request, "{0} -- {1} -- User Added Successfully".format( counter, user.username)) continue @@ -2309,11 +2332,10 @@ def _read_user_csv(reader, course): course.students.add(user) else: state = "Updated" - upload_details.append("{0} -- {1} -- User {2} Successfully".format( - counter, user.username, state)) + messages.info(request, "{0} -- {1} -- User {2} Successfully".format( + counter, user.username, state)) if counter == 0: - upload_details.append("No rows in the CSV file") - return upload_details + messages.warning(request, "No rows in the CSV file") def _get_csv_values(row, fields): @@ -2395,15 +2417,21 @@ def duplicate_course(request, course_id): if course.is_teacher(user) or course.is_creator(user): # Create new entries of modules, lessons/quizzes # from current course to copied course - course.create_duplicate_course(user) + duplicate_course = course.create_duplicate_course(user) + msg = dedent( + '''\ + Course duplication successful with the name {0} , please check + the courses page.'''.format(duplicate_course.name) + ) + messages.success(request, msg) else: msg = dedent( '''\ You do not have permissions to clone {0} course, please contact your instructor/administrator.'''.format(course.name) ) - return complete(request, msg, attempt_num=None, questionpaper_id=None) - return my_redirect('/exam/manage/courses/') + messages.warning(request, msg) + return my_redirect(reverse('yaksh:course_detail', args=[course_id])) @login_required @@ -2440,9 +2468,9 @@ def edit_lesson(request, lesson_id=None, course_id=None): course = get_object_or_404(Course, id=course_id) if not course.is_creator(user) and not course.is_teacher(user): raise Http404('This Lesson does not belong to you') - redirect_url = "/exam/manage/courses/" + redirect_url = reverse("yaksh:get_course_modules", args=[course_id]) else: - redirect_url = "/exam/manage/courses/all_lessons/" + redirect_url = reverse("yaksh:show_all_lessons") context = {} if request.method == "POST": if "Save" in request.POST: @@ -2467,7 +2495,9 @@ def edit_lesson(request, lesson_id=None, course_id=None): LessonFile.objects.get_or_create( lesson=lesson, file=les_file ) - return my_redirect(redirect_url) + messages.success( + request, "Saved {0} successfully".format(lesson.name) + ) else: context['lesson_form'] = lesson_form context['error'] = lesson_form["video_file"].errors @@ -2479,7 +2509,13 @@ def edit_lesson(request, lesson_id=None, course_id=None): files = LessonFile.objects.filter(id__in=remove_files_id) for file in files: file.remove() - return my_redirect(redirect_url) + messages.success( + request, "Deleted files successfully" + ) + else: + messages.warning( + request, "Please select atleast one file to delete" + ) lesson_files = LessonFile.objects.filter(lesson=lesson) lesson_files_form = LessonFileForm() @@ -2553,9 +2589,10 @@ def design_module(request, module_id, course_id=None): learning_module = LearningModule.objects.get(id=module_id) if request.method == "POST": if "Add" in request.POST: - add_values = request.POST.get("chosen_list").split(',') + add_values = request.POST.get("chosen_list") to_add_list = [] if add_values: + add_values = add_values.split(',') ordered_units = learning_module.get_learning_units() if ordered_units.exists(): start_val = ordered_units.last().order + 1 @@ -2573,29 +2610,56 @@ def design_module(request, module_id, course_id=None): type=type) to_add_list.append(learning_unit) learning_module.learning_unit.add(*to_add_list) + messages.success(request, "Lesson/Quiz added successfully") + else: + messages.warning(request, "Please select a lesson/quiz to add") if "Change" in request.POST: - order_list = request.POST.get("ordered_list").split(",") - for order in order_list: - learning_unit, learning_order = order.split(":") - if learning_order: - learning_unit = learning_module.learning_unit.get( - id=learning_unit) - learning_unit.order = learning_order - learning_unit.save() + order_list = request.POST.get("ordered_list") + print(order_list) + if order_list: + order_list = order_list.split(",") + for order in order_list: + learning_unit, learning_order = order.split(":") + if learning_order: + learning_unit = learning_module.learning_unit.get( + id=learning_unit) + learning_unit.order = learning_order + learning_unit.save() + messages.success(request, "Order changed successfully") + else: + messages.warning( + request, "Please select a lesson/quiz to change" + ) if "Remove" in request.POST: remove_values = request.POST.getlist("delete_list") if remove_values: learning_module.learning_unit.remove(*remove_values) LearningUnit.objects.filter(id__in=remove_values).delete() + messages.success( + request, "Lessons/quizzes deleted successfully" + ) + else: + messages.warning( + request, "Please select a lesson/quiz to remove" + ) if "Change_prerequisite" in request.POST: unit_list = request.POST.getlist("check_prereq") - for unit in unit_list: - learning_unit = learning_module.learning_unit.get(id=unit) - learning_unit.toggle_check_prerequisite() - learning_unit.save() + if unit_list: + for unit in unit_list: + learning_unit = learning_module.learning_unit.get(id=unit) + learning_unit.toggle_check_prerequisite() + learning_unit.save() + messages.success( + request, "Changed prerequisite status successfully" + ) + else: + messages.warning( + request, + "Please select a lesson/quiz to change prerequisite" + ) added_quiz_lesson = learning_module.get_added_quiz_lesson() quizzes = [("quiz", quiz) for quiz in Quiz.objects.filter( @@ -2617,12 +2681,12 @@ def add_module(request, module_id=None, course_id=None): user = request.user if not is_moderator(user): raise Http404('You are not allowed to view this page!') - redirect_url = "/exam/manage/courses/all_learning_module/" + redirect_url = reverse("yaksh:show_all_modules") if course_id: course = Course.objects.get(id=course_id) if not course.is_creator(user) and not course.is_teacher(user): raise Http404('This course does not belong to you') - redirect_url = "/exam/manage/courses/" + redirect_url = reverse("yaksh:get_course_modules", args=[course_id]) if module_id: module = LearningModule.objects.get(id=module_id) if not module.creator == user and not course_id: @@ -2639,7 +2703,10 @@ def add_module(request, module_id=None, course_id=None): module = module_form.save() module.html_data = get_html_text(module.description) module.save() - return my_redirect(redirect_url) + messages.success( + request, + "Saved {0} successfully".format(module.name) + ) else: context['module_form'] = module_form @@ -2657,8 +2724,8 @@ def show_all_quizzes(request): if not is_moderator(user): raise Http404('You are not allowed to view this page!') quizzes = Quiz.objects.filter(creator=user, is_trial=False) - context = {"quizzes": quizzes, "type": "quiz"} - return my_render_to_response(request, 'yaksh/courses.html', context) + context = {"quizzes": quizzes} + return my_render_to_response(request, 'yaksh/quizzes.html', context) @login_required @@ -2668,8 +2735,8 @@ def show_all_lessons(request): if not is_moderator(user): raise Http404('You are not allowed to view this page!') lessons = Lesson.objects.filter(creator=user) - context = {"lessons": lessons, "type": "lesson"} - return my_render_to_response(request, 'yaksh/courses.html', context) + context = {"lessons": lessons} + return my_render_to_response(request, 'yaksh/lessons.html', context) @login_required @@ -2680,8 +2747,10 @@ def show_all_modules(request): raise Http404('You are not allowed to view this page!') learning_modules = LearningModule.objects.filter( creator=user, is_trial=False) - context = {"learning_modules": learning_modules, "type": "learning_module"} - return my_render_to_response(request, 'yaksh/courses.html', context) + context = {"modules": learning_modules} + return my_render_to_response( + request, 'yaksh/modules.html', context + ) @login_required @@ -2704,7 +2773,7 @@ def get_next_unit(request, course_id, module_id, current_unit_id=None, user = request.user course = Course.objects.prefetch_related("learning_module").get( id=course_id) - if user not in course.students.all(): + if not course.students.filter(id=user.id).exists(): raise Http404('You are not enrolled for this course!') learning_module = course.learning_module.prefetch_related( "learning_unit").get(id=module_id) @@ -2812,9 +2881,10 @@ def design_course(request, course_id): learning_modules = set(all_learning_modules) - set(added_learning_modules) context['added_learning_modules'] = added_learning_modules context['learning_modules'] = learning_modules - context['course_id'] = course_id + context['course'] = course + context['is_design_course'] = True return my_render_to_response( - request, 'yaksh/design_course_session.html', context + request, 'yaksh/course_detail.html', context ) @@ -2898,13 +2968,26 @@ def course_status(request, course_id): course = get_object_or_404(Course, pk=course_id) if not course.is_creator(user) and not course.is_teacher(user): raise Http404('This course does not belong to you') - students = course.get_only_students() + students = course.students.order_by("-id") + students_no = students.count() + paginator = Paginator(students, 100) + page = request.GET.get('page') + try: + students = paginator.page(page) + except PageNotAnInteger: + # If page is not an integer, deliver first page. + students = paginator.page(1) + except EmptyPage: + # If page is out of range (e.g. 9999), deliver last page of results. + students = paginator.page(paginator.num_pages) + stud_details = [(student, course.get_grade(student), course.get_completion_percent(student), - course.get_current_unit(student)) for student in students] + course.get_current_unit(student)) + for student in students.object_list] context = { - 'course': course, 'student_details': stud_details, - 'state': 'course_status' + 'course': course, 'objects': students, 'is_progress': True, + 'student_details': stud_details, 'students_no': students_no } return my_render_to_response(request, 'yaksh/course_detail.html', context) @@ -2991,6 +3074,8 @@ def get_user_data(request, course_id, student_id): @email_verified def download_course(request, course_id): user = request.user + if not is_moderator(user): + raise Http404('You are not allowed to view this page!') course = get_object_or_404(Course, pk=course_id) if (not course.is_creator(user) and not course.is_teacher(user) and not course.is_student(user)): @@ -3017,3 +3102,51 @@ def download_course(request, course_id): ) response.write(zip_file.read()) return response + + +@login_required +@email_verified +def course_students(request, course_id): + user = request.user + if not is_moderator(user): + raise Http404('You are not allowed to view this page!') + course = get_object_or_404(Course, pk=course_id) + if not course.is_creator(user) and not course.is_teacher(user): + raise Http404("You are not allowed to view {0}".format( + course.name)) + enrolled = course.get_enrolled() + requested = course.get_requests() + rejected = course.get_rejected() + context = {"enrolled": enrolled, "requested": requested, "course": course, + "rejected": rejected, "is_students": True} + return my_render_to_response(request, 'yaksh/course_detail.html', context) + + +@login_required +@email_verified +def course_teachers(request, course_id): + user = request.user + if not is_moderator(user): + raise Http404('You are not allowed to view this page!') + course = get_object_or_404(Course, pk=course_id) + if not course.is_creator(user) and not course.is_teacher(user): + raise Http404("You are not allowed to view {0}".format( + course.name)) + teachers = course.get_teachers() + context = {"teachers": teachers, "is_teachers": True, "course": course} + return my_render_to_response(request, 'yaksh/course_detail.html', context) + + +@login_required +@email_verified +def get_course_modules(request, course_id): + user = request.user + if not is_moderator(user): + raise Http404('You are not allowed to view this page!') + course = get_object_or_404(Course, pk=course_id) + if not course.is_creator(user) and not course.is_teacher(user): + raise Http404("You are not allowed to view {0}".format( + course.name)) + modules = course.get_learning_modules() + context = {"modules": modules, "is_modules": True, "course": course} + return my_render_to_response(request, 'yaksh/course_detail.html', context) |