├── .coveragerc ├── .gitignore ├── .sampleenv ├── .travis.yml ├── CHANGELOG.txt ├── LICENSE ├── MANIFEST.in ├── README.rst ├── README_production.rst ├── api ├── __init__.py ├── apps.py ├── serializers.py ├── tests.py ├── urls.py └── views.py ├── docker ├── Dockerfile_codeserver ├── Dockerfile_django ├── Files │ ├── 000-default.conf │ ├── Docker-script.sh │ └── Start-codeserver.sh └── docker-compose.yml ├── grades ├── __init__.py ├── admin.py ├── apps.py ├── forms.py ├── migrations │ ├── 0001_initial.py │ ├── __init__.py │ └── default_grading_system.py ├── models.py ├── templates │ ├── add_grades.html │ └── grading_systems.html ├── tests │ ├── __init__.py │ ├── test_models.py │ └── test_views.py ├── urls.py └── views.py ├── manage.py ├── online_test ├── __init__.py ├── celery_settings.py ├── settings.py ├── test_settings.py ├── urls.py ├── views.py └── wsgi.py ├── release_testing_guide.md ├── requirements ├── requirements-codeserver.txt ├── requirements-common.txt └── requirements-production.txt ├── setup.cfg ├── setup.py ├── stats ├── __init__.py ├── admin.py ├── apps.py ├── migrations │ ├── 0001_initial.py │ ├── 0002_release_0_29_1.py │ └── __init__.py ├── models.py ├── templates │ └── view_lesson_tracking.html ├── test_models.py ├── tests.py ├── urls.py └── views.py ├── tasks.py ├── upload ├── models.py ├── urls.py ├── utils.py └── views.py └── yaksh ├── __init__.py ├── admin.py ├── base_evaluator.py ├── bash_code_evaluator.py ├── bash_stdio_evaluator.py ├── code_server.py ├── cpp_code_evaluator.py ├── cpp_stdio_evaluator.py ├── decorators.py ├── docs ├── sample.args ├── sample.sh ├── sample_questions.py └── sample_questions.xml ├── documentation ├── Makefile ├── about_yaksh.rst ├── conf.py ├── images │ ├── add_exercise.jpg │ ├── add_lesson.jpg │ ├── add_module.jpg │ ├── add_question.jpg │ ├── add_quiz.jpg │ ├── bash_standard_testcase.jpg │ ├── course_details_features.jpg │ ├── course_features.jpg │ ├── course_modules.jpg │ ├── cpp_standard_testcase.jpg │ ├── create_course.jpg │ ├── create_course.png │ ├── design_course.jpg │ ├── design_module.jpg │ ├── design_questionpaper.jpg │ ├── embed_video.jpg │ ├── float_testcase.jpg │ ├── hook_testcase.jpg │ ├── integer_testcase.jpg │ ├── java_standard_testcase.jpg │ ├── mcc_testcase.jpg │ ├── mcq_testcase.jpg │ ├── moderator_dashboard.jpg │ ├── python_standard_testcase.jpg │ ├── questions.jpg │ ├── r_standard_testcase.jpg │ ├── scilab_standard_testcase.jpg │ ├── stdio_testcase.jpg │ └── string_testcase.jpg ├── index.rst ├── installation.rst ├── introduction.rst ├── make.bat ├── moderator_dashboard.rst └── moderator_docs │ ├── creating_course.rst │ ├── creating_lessons_modules.rst │ ├── creating_question.rst │ ├── creating_quiz.rst │ └── other_features.rst ├── error_messages.py ├── evaluator_tests ├── __init__.py ├── test_bash_evaluation.py ├── test_c_cpp_evaluation.py ├── test_grader_evaluation.py ├── test_java_evaluation.py ├── test_python_evaluation.py ├── test_python_stdio_evaluator.py ├── test_r_evaluation.py ├── test_scilab_evaluation.py └── test_simple_question_types.py ├── file_utils.py ├── fixtures ├── demo_fixtures.json ├── demo_questions.zip ├── existing_user.csv ├── invalid_yaml.yaml ├── marks_correct.csv ├── marks_header_missing.csv ├── marks_header_modified.csv ├── marks_invalid_data.csv ├── marks_invalid_question_id.csv ├── marks_invalid_user.csv ├── marks_not_attempted_question.csv ├── marks_single_question.csv ├── sample_lesson_toc.yaml ├── sample_user_upload.csv ├── user_existing_email.csv ├── users_add_update_reject.csv ├── users_correct.csv ├── users_some_headers_missing.csv ├── users_some_values_missing.csv └── users_with_no_values.csv ├── forms.py ├── grader.py ├── hook_evaluator.py ├── java_code_evaluator.py ├── java_stdio_evaluator.py ├── language_registry.py ├── live_server_tests ├── __init__.py ├── load_test.py └── selenium_test.py ├── management ├── __init__.py └── commands │ ├── __init__.py │ └── create_moderator.py ├── middleware ├── __init__.py ├── get_notifications.py ├── one_session_per_user.py └── user_time_zone.py ├── migrations ├── 0001_initial.py ├── 0002_questionpaper_fixed_question_order.py ├── 0003_auto_20170321_0917.py ├── 0004_auto_20170331_0632.py ├── 0005_auto_20170410_1024.py ├── 0006_release_0_6_0.py ├── 0007_alter_profile_activation_key.py ├── 0008_release_0_7_0.py ├── 0009_auto_20180113_1124.py ├── 0010_auto_20180226_1324.py ├── 0011_release_0_8_0.py ├── 0012_release_0_8_1.py ├── 0013_release_0_9_0.py ├── 0014_release_0_9_1.py ├── 0015_release_0_10_0.py ├── 0016_release_0_12_0.py ├── 0017_release_0_14_0.py ├── 0018_auto_20200408_1206.py ├── 0019_release_0_20_0.py ├── 0020_release_0_21_0.py ├── 0021_auto_20200703_1556.py ├── 0022_release_0_22_1.py ├── 0023_release_0_23_0.py ├── 0024_release_0_24_0.py ├── 0025_release_0_26.py ├── 0026_release_0_27_0.py ├── 0027_release_0_28_0.py ├── 0028_auto_20210112_1039.py ├── 0029_release_0_31_0.py ├── 0030_alter_answerpaper_user_ip_max_len.py └── __init__.py ├── models.py ├── pipeline ├── __init__.py ├── settings.py └── user.py ├── python_assertion_evaluator.py ├── python_stdio_evaluator.py ├── r_code_evaluator.py ├── scilab_code_evaluator.py ├── scripts ├── __init__.py └── yaksh_script.sh ├── send_emails.py ├── settings.py ├── static └── yaksh │ ├── css │ ├── animate.min.css │ ├── argon.css │ ├── argon.min.css │ ├── autotaggit.css │ ├── bootstrap-social.css │ ├── bootstrap.css │ ├── bootstrap.min.css │ ├── bootstrap.min.css.map │ ├── codemirror │ │ └── lib │ │ │ └── codemirror.css │ ├── custom.css │ ├── design_course.css │ ├── exam.css │ ├── font-awesome.css │ ├── jquery-ui │ │ ├── images │ │ │ ├── ui-bg_flat_0_aaaaaa_40x100.png │ │ │ ├── ui-bg_flat_75_ffffff_40x100.png │ │ │ ├── ui-bg_glass_55_fbf9ee_1x400.png │ │ │ ├── ui-bg_glass_65_ffffff_1x400.png │ │ │ ├── ui-bg_glass_75_dadada_1x400.png │ │ │ ├── ui-bg_glass_75_e6e6e6_1x400.png │ │ │ ├── ui-bg_glass_95_fef1ec_1x400.png │ │ │ ├── ui-bg_highlight-soft_75_cccccc_1x100.png │ │ │ ├── ui-icons_222222_256x240.png │ │ │ ├── ui-icons_2e83ff_256x240.png │ │ │ ├── ui-icons_444444_256x240.png │ │ │ ├── ui-icons_454545_256x240.png │ │ │ ├── ui-icons_555555_256x240.png │ │ │ ├── ui-icons_777620_256x240.png │ │ │ ├── ui-icons_777777_256x240.png │ │ │ ├── ui-icons_888888_256x240.png │ │ │ ├── ui-icons_cc0000_256x240.png │ │ │ ├── ui-icons_cd0a0a_256x240.png │ │ │ └── ui-icons_ffffff_256x240.png │ │ ├── jquery-ui-1.12.1.css │ │ └── jquery-ui.css │ ├── jquery.datetimepicker.css │ ├── lesson.css │ ├── offline.css │ ├── ontop.css │ ├── plyr.css │ ├── question.css │ ├── question_paper_creation.css │ ├── simplemde.min.css │ ├── toastr.min.css │ ├── video-js.css │ └── yakshcustom.css │ ├── fonts │ ├── FontAwesome.otf │ ├── fontawesome-webfont.eot │ ├── fontawesome-webfont.svg │ ├── fontawesome-webfont.ttf │ ├── fontawesome-webfont.woff │ ├── fontawesome-webfont.woff2 │ ├── glyphicons-halflings-regular.eot │ ├── glyphicons-halflings-regular.svg │ ├── glyphicons-halflings-regular.ttf │ └── glyphicons-halflings-regular.woff │ ├── images │ ├── check_answer.gif │ ├── fosseelogo.jpg │ ├── profile_change.gif │ ├── yaksh_banner.png │ ├── yaksh_circular_logo.png │ └── yaksh_text.png │ └── js │ ├── add_course.js │ ├── add_grades.js │ ├── add_question.js │ ├── add_questionpaper.js │ ├── add_quiz.js │ ├── argon.js │ ├── argon.min.js │ ├── bootstrap.min.js │ ├── bootstrap.min.js.map │ ├── codemirror │ ├── lib │ │ └── codemirror.js │ └── mode │ │ ├── clike │ │ ├── clike.js │ │ ├── index.html │ │ ├── scala.html │ │ └── test.js │ │ ├── python │ │ ├── index.html │ │ ├── python.js │ │ └── test.js │ │ ├── r │ │ ├── index.html │ │ └── r.js │ │ └── shell │ │ ├── index.html │ │ ├── shell.js │ │ └── test.js │ ├── course.js │ ├── design_course.js │ ├── edit_question.js │ ├── edit_quiz.js │ ├── html5shiv.js │ ├── jquery-1.9.1.min.js │ ├── jquery-3.3.1.min.js │ ├── jquery-migrate-3.0.0.min.js │ ├── jquery-sortable.js │ ├── jquery-ui-1.12.1.js │ ├── jquery-ui.js │ ├── jquery.datetimepicker.full.min.js │ ├── jquery.tablesorter.min.js │ ├── js.cookie.js │ ├── lesson.js │ ├── mathjax │ ├── MathJax.js │ ├── config │ │ └── TeX-MML-AM_CHTML.js │ ├── fonts │ │ └── HTML-CSS │ │ │ └── TeX │ │ │ └── woff │ │ │ ├── MathJax_AMS-Regular.woff │ │ │ ├── MathJax_Caligraphic-Bold.woff │ │ │ ├── MathJax_Caligraphic-Regular.woff │ │ │ ├── MathJax_Fraktur-Bold.woff │ │ │ ├── MathJax_Fraktur-Regular.woff │ │ │ ├── MathJax_Main-Bold.woff │ │ │ ├── MathJax_Main-Italic.woff │ │ │ ├── MathJax_Main-Regular.woff │ │ │ ├── MathJax_Math-BoldItalic.woff │ │ │ ├── MathJax_Math-Italic.woff │ │ │ ├── MathJax_Math-Regular.woff │ │ │ ├── MathJax_SansSerif-Bold.woff │ │ │ ├── MathJax_SansSerif-Italic.woff │ │ │ ├── MathJax_SansSerif-Regular.woff │ │ │ ├── MathJax_Script-Regular.woff │ │ │ ├── MathJax_Size1-Regular.woff │ │ │ ├── MathJax_Size2-Regular.woff │ │ │ ├── MathJax_Size3-Regular.woff │ │ │ ├── MathJax_Size4-Regular.woff │ │ │ ├── MathJax_Typewriter-Regular.woff │ │ │ ├── MathJax_Vector-Bold.woff │ │ │ └── MathJax_Vector-Regular.woff │ └── jax │ │ └── output │ │ └── CommonHTML │ │ ├── fonts │ │ └── TeX │ │ │ └── fontdata.js │ │ └── jax.js │ ├── min.js │ ├── moderator_dashboard.js │ ├── plyr.js │ ├── popper.min.js │ ├── question_paper_creation.js │ ├── requesthandler.js │ ├── show_courses.js │ ├── show_question.js │ ├── show_quiz.js │ ├── show_testcase.js │ ├── show_toc.js │ ├── simplemde.min.js │ ├── tinymce │ └── js │ │ └── tinymce │ │ ├── icons │ │ └── default │ │ │ └── icons.min.js │ │ ├── jquery.tinymce.min.js │ │ ├── license.txt │ │ ├── plugins │ │ ├── advlist │ │ │ └── plugin.min.js │ │ ├── anchor │ │ │ └── plugin.min.js │ │ ├── autolink │ │ │ └── plugin.min.js │ │ ├── autoresize │ │ │ └── plugin.min.js │ │ ├── autosave │ │ │ └── plugin.min.js │ │ ├── bbcode │ │ │ └── plugin.min.js │ │ ├── charmap │ │ │ └── plugin.min.js │ │ ├── code │ │ │ └── plugin.min.js │ │ ├── codesample │ │ │ └── plugin.min.js │ │ ├── colorpicker │ │ │ └── plugin.min.js │ │ ├── contextmenu │ │ │ └── plugin.min.js │ │ ├── directionality │ │ │ └── plugin.min.js │ │ ├── emoticons │ │ │ ├── js │ │ │ │ ├── emojis.js │ │ │ │ └── emojis.min.js │ │ │ └── plugin.min.js │ │ ├── fullpage │ │ │ └── plugin.min.js │ │ ├── fullscreen │ │ │ └── plugin.min.js │ │ ├── help │ │ │ └── plugin.min.js │ │ ├── hr │ │ │ └── plugin.min.js │ │ ├── image │ │ │ └── plugin.min.js │ │ ├── imagetools │ │ │ └── plugin.min.js │ │ ├── importcss │ │ │ └── plugin.min.js │ │ ├── insertdatetime │ │ │ └── plugin.min.js │ │ ├── legacyoutput │ │ │ └── plugin.min.js │ │ ├── link │ │ │ └── plugin.min.js │ │ ├── lists │ │ │ └── plugin.min.js │ │ ├── media │ │ │ └── plugin.min.js │ │ ├── nonbreaking │ │ │ └── plugin.min.js │ │ ├── noneditable │ │ │ └── plugin.min.js │ │ ├── pagebreak │ │ │ └── plugin.min.js │ │ ├── paste │ │ │ └── plugin.min.js │ │ ├── preview │ │ │ └── plugin.min.js │ │ ├── print │ │ │ └── plugin.min.js │ │ ├── quickbars │ │ │ └── plugin.min.js │ │ ├── save │ │ │ └── plugin.min.js │ │ ├── searchreplace │ │ │ └── plugin.min.js │ │ ├── spellchecker │ │ │ └── plugin.min.js │ │ ├── tabfocus │ │ │ └── plugin.min.js │ │ ├── table │ │ │ └── plugin.min.js │ │ ├── template │ │ │ └── plugin.min.js │ │ ├── textcolor │ │ │ └── plugin.min.js │ │ ├── textpattern │ │ │ └── plugin.min.js │ │ ├── toc │ │ │ └── plugin.min.js │ │ ├── visualblocks │ │ │ └── plugin.min.js │ │ ├── visualchars │ │ │ └── plugin.min.js │ │ └── wordcount │ │ │ └── plugin.min.js │ │ ├── skins │ │ ├── content │ │ │ ├── dark │ │ │ │ └── content.min.css │ │ │ ├── default │ │ │ │ └── content.min.css │ │ │ ├── document │ │ │ │ └── content.min.css │ │ │ └── writer │ │ │ │ └── content.min.css │ │ └── ui │ │ │ ├── oxide-dark │ │ │ ├── content.inline.min.css │ │ │ ├── content.min.css │ │ │ ├── content.mobile.min.css │ │ │ ├── fonts │ │ │ │ └── tinymce-mobile.woff │ │ │ ├── skin.min.css │ │ │ └── skin.mobile.min.css │ │ │ └── oxide │ │ │ ├── content.inline.min.css │ │ │ ├── content.min.css │ │ │ ├── content.mobile.min.css │ │ │ ├── fonts │ │ │ └── tinymce-mobile.woff │ │ │ ├── skin.min.css │ │ │ └── skin.mobile.min.css │ │ ├── themes │ │ ├── mobile │ │ │ └── theme.min.js │ │ └── silver │ │ │ └── theme.min.js │ │ └── tinymce.min.js │ ├── toastr.min.js │ ├── video.js │ └── wow.min.js ├── stdio_evaluator.py ├── storage_backends.py ├── tasks.py ├── templates ├── 404.html ├── 500.html ├── base.html ├── exam.html ├── manage.html ├── registration │ ├── password_change_done.html │ ├── password_change_form.html │ ├── password_reset_complete.html │ ├── password_reset_confirm.html │ ├── password_reset_done.html │ └── password_reset_form.html ├── user.html └── yaksh │ ├── activation_status.html │ ├── add_course.html │ ├── add_exercise.html │ ├── add_lesson.html │ ├── add_module.html │ ├── add_question.html │ ├── add_quiz.html │ ├── add_topic.html │ ├── add_video_quiz.html │ ├── addteacher.html │ ├── complete.html │ ├── course_added_modules.html │ ├── course_detail.html │ ├── course_detail_options.html │ ├── course_forum.html │ ├── course_modules.html │ ├── course_progress.html │ ├── course_send_mail.html │ ├── course_students.html │ ├── course_teachers.html │ ├── courses.html │ ├── demo_video.html │ ├── design_course_session.html │ ├── design_questionpaper.html │ ├── download_course_templates │ ├── index.html │ ├── module.html │ ├── quiz.html │ └── unit.html │ ├── editprofile.html │ ├── editquestionpaper.html │ ├── error_template.html │ ├── grade_user.html │ ├── intro.html │ ├── lessons.html │ ├── lessons_forum.html │ ├── login.html │ ├── micromanaged.html │ ├── micromonitor.html │ ├── moderator_dashboard.html │ ├── modules.html │ ├── monitor.html │ ├── paginator.html │ ├── post_comments.html │ ├── preview_questionpaper.html │ ├── profile_updated.html │ ├── question.html │ ├── quit.html │ ├── quizzes.html │ ├── quizzes_user.html │ ├── register.html │ ├── results_user.html │ ├── show_lesson_quiz.html │ ├── show_lesson_statistics.html │ ├── show_toc.html │ ├── show_video.html │ ├── showquestionpapers.html │ ├── showquestions.html │ ├── sidebar.html │ ├── statistics_question.html │ ├── upload_download_course_md.html │ ├── upload_file.html │ ├── user_data.html │ ├── user_status.html │ ├── view_answerpaper.html │ ├── view_notifications.html │ └── view_profile.html ├── templatetags ├── __init__.py ├── custom_filters.py └── test_custom_filters.py ├── test_models.py ├── test_views.py ├── tests ├── __init__.py ├── test_code_server.py └── test_questions.json ├── urls.py ├── urls_password_reset.py └── views.py /.coveragerc: -------------------------------------------------------------------------------- 1 | [run] 2 | branch = True 3 | source = . 4 | omit = 5 | *tests* 6 | *migrations* 7 | yaksh/test_views.py 8 | yaksh/test_models.py 9 | yaksh/scripts/* 10 | online_test/settings.py 11 | online_test/urls.py 12 | online_test/test_settings.py 13 | manage.py 14 | online_test/wsgi.py 15 | online_test/__init__.py 16 | yaksh/__init__.py 17 | yaksh/pipeline/* 18 | yaksh/migrations/* 19 | yaksh/templatetags/__init__.py 20 | yaksh/templatetags/test_custom_filters.py 21 | yaksh/middleware/__init__.py 22 | setup.py 23 | tasks.py 24 | yaksh/admin.py 25 | *management* 26 | 27 | [report] 28 | exclude_lines = 29 | except ImportError: 30 | raise NotImplementedError 31 | if __name__ == .__main__.: 32 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | *.zip 3 | *~ 4 | .project 5 | .pydevproject 6 | app.yaml 7 | build 8 | tests/coverageResults 9 | *,cover 10 | tests/.coverage 11 | *.git 12 | *.egg-info 13 | eggs 14 | parts 15 | .installed.cfg 16 | bin 17 | develop-eggs 18 | .DS_Store 19 | .settings 20 | .*.swp 21 | *.egg 22 | *.egg-link 23 | *.svn* 24 | *.wpr 25 | .installed.cfg 26 | src/* 27 | parts 28 | downloads 29 | .xvpics* 30 | .project 31 | pytask/local.py 32 | pytask/pytask.egg-info 33 | pytask/static/media 34 | pytask/uploads 35 | apache/* 36 | *.swp 37 | *.bak 38 | *.swo 39 | *.db-journal 40 | *.db 41 | wsgi.log 42 | *.sqlite3 43 | data/ 44 | _build/ 45 | -------------------------------------------------------------------------------- /.sampleenv: -------------------------------------------------------------------------------- 1 | # Django settings 2 | SECRET_KEY=dUmMy_s3cR3t_k3y 3 | #DB_ENGINE=mysql 4 | #DB_NAME=yaksh 5 | #DB_USER=root 6 | #DB_PASSWORD=root 7 | #DB_HOST=yaksh-db 8 | #DB_PORT=3306 9 | # Yaksh settings 10 | N_CODE_SERVERS=5 11 | #SERVER_POOL_PORT=53579 12 | #SERVER_HOST_NAME=http://yaksh-codeserver 13 | #SERVER_TIMEOUT=4 14 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | 3 | python: 4 | - "3.6" 5 | 6 | services: 7 | - xvfb 8 | - redis-server 9 | 10 | before_install: 11 | - sudo apt-get update -qq 12 | - sudo apt-get install -y scilab 13 | - sudo apt-get install -y r-base 14 | - export DISPLAY=:99.0 15 | 16 | # command to install dependencies 17 | install: 18 | - pip install -r requirements/requirements-common.txt 19 | - pip install codecov 20 | - python setup.py develop 21 | 22 | before_script: 23 | - python manage.py makemigrations notifications_plugin 24 | - python manage.py makemigrations stats 25 | - python manage.py makemigrations 26 | - python manage.py migrate auth 27 | - python manage.py migrate 28 | 29 | # command to run tests and coverage 30 | script: 31 | - coverage erase 32 | - celery multi start 1 -A online_test worker -B 33 | - coverage run -p manage.py test -v 2 yaksh 34 | - coverage run -p manage.py test -v 2 stats 35 | - coverage run -p manage.py test -v 2 grades 36 | - coverage run -p manage.py test -v 2 yaksh.live_server_tests.load_test 37 | - coverage run -p manage.py test -v 2 api 38 | - celery multi stop 1 39 | - find . -type f -name "*.pid" -exec rm -f {} \; 40 | 41 | after_success: 42 | - coverage combine 43 | - coverage report 44 | - codecov 45 | 46 | dist: 47 | xenial 48 | 49 | addons: 50 | firefox: "46.0" 51 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | This is distributed under the terms of the BSD license. 2 | 3 | Developed by IIT Bombay, is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License. 4 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include LICENSE 2 | include README.md 3 | recursive-include yaksh/static * 4 | recursive-include yaksh/templates * 5 | recursive-include yaksh/demo_templates * 6 | recursive-include yaksh/management * 7 | recursive-include yaksh/output * 8 | recursive-include yaksh/fixtures * 9 | recursive-include yaksh/docs * -------------------------------------------------------------------------------- /api/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FOSSEE/online_test/9ea045b637f2087c1f1cdf8855d2d42b5f74a875/api/__init__.py -------------------------------------------------------------------------------- /api/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class ApiConfig(AppConfig): 5 | name = 'api' 6 | -------------------------------------------------------------------------------- /api/serializers.py: -------------------------------------------------------------------------------- 1 | from rest_framework import serializers 2 | from yaksh.models import ( 3 | Question, Quiz, QuestionPaper, AnswerPaper, Course, 4 | LearningModule, LearningUnit, Lesson 5 | ) 6 | 7 | 8 | class QuestionSerializer(serializers.ModelSerializer): 9 | test_cases = serializers.SerializerMethodField() 10 | 11 | def get_test_cases(self, obj): 12 | test_cases = obj.get_test_cases_as_dict() 13 | return test_cases 14 | 15 | class Meta: 16 | model = Question 17 | exclude = ('partial_grading', ) 18 | 19 | 20 | class QuizSerializer(serializers.ModelSerializer): 21 | class Meta: 22 | model = Quiz 23 | exclude = ('view_answerpaper', ) 24 | 25 | 26 | class QuestionPaperSerializer(serializers.ModelSerializer): 27 | class Meta: 28 | model = QuestionPaper 29 | fields = '__all__' 30 | 31 | 32 | class AnswerPaperSerializer(serializers.ModelSerializer): 33 | 34 | questions = QuestionSerializer(many=True) 35 | 36 | class Meta: 37 | model = AnswerPaper 38 | fields = '__all__' 39 | 40 | 41 | class LessonSerializer(serializers.ModelSerializer): 42 | class Meta: 43 | model = Lesson 44 | fields = '__all__' 45 | 46 | 47 | class LearningUnitSerializer(serializers.ModelSerializer): 48 | 49 | quiz = QuizSerializer() 50 | lesson = LessonSerializer() 51 | 52 | class Meta: 53 | model = LearningUnit 54 | fields = '__all__' 55 | 56 | 57 | class LearningModuleSerializer(serializers.ModelSerializer): 58 | 59 | learning_unit = LearningUnitSerializer(many=True) 60 | 61 | class Meta: 62 | model = LearningModule 63 | fields = '__all__' 64 | 65 | 66 | class CourseSerializer(serializers.ModelSerializer): 67 | 68 | learning_module = LearningModuleSerializer(many=True) 69 | 70 | class Meta: 71 | model = Course 72 | exclude = ( 73 | 'teachers', 74 | 'rejected', 75 | 'requests', 76 | 'students', 77 | 'grading_system', 78 | 'view_grade', 79 | ) 80 | -------------------------------------------------------------------------------- /api/urls.py: -------------------------------------------------------------------------------- 1 | from django.conf.urls import url 2 | from rest_framework.urlpatterns import format_suffix_patterns 3 | from api import views 4 | 5 | app_name = 'api' 6 | 7 | urlpatterns = [ 8 | url(r'questions/$', views.QuestionList.as_view(), name='questions'), 9 | url(r'questions/(?P[0-9]+)/$', views.QuestionDetail.as_view(), 10 | name='question'), 11 | url(r'get_courses/$', views.CourseList.as_view(), name='get_courses'), 12 | url(r'start_quiz/(?P[0-9]+)/(?P[0-9]+)/$', views.StartQuiz.as_view(), 13 | name='start_quiz'), 14 | url(r'quizzes/$', views.QuizList.as_view(), name='quizzes'), 15 | url(r'quizzes/(?P[0-9]+)/$', views.QuizDetail.as_view(), name='quiz'), 16 | url(r'questionpapers/$', views.QuestionPaperList.as_view(), 17 | name='questionpapers'), 18 | url(r'questionpapers/(?P[0-9]+)/$', 19 | views.QuestionPaperDetail.as_view(), name='questionpaper'), 20 | url(r'answerpapers/$', views.AnswerPaperList.as_view(), 21 | name='answerpapers'), 22 | url(r'validate/(?P[0-9]+)/(?P[0-9]+)/$', 23 | views.AnswerValidator.as_view(), name='validators'), 24 | url(r'validate/(?P[0-9]+)/$', 25 | views.AnswerValidator.as_view(), name='validator'), 26 | url(r'course/(?P[0-9]+)/$', 27 | views.GetCourse.as_view(), name='get_course'), 28 | url(r'quit/(?P\d+)/$', views.QuitQuiz.as_view(), 29 | name="quit_quiz"), 30 | url(r'login/$', views.login, name='login') 31 | ] 32 | 33 | urlpatterns = format_suffix_patterns(urlpatterns) 34 | -------------------------------------------------------------------------------- /docker/Dockerfile_codeserver: -------------------------------------------------------------------------------- 1 | FROM ubuntu:16.04 2 | 3 | MAINTAINER FOSSEE 4 | 5 | RUN apt-get update && \ 6 | apt-get install git python3-pip libmysqlclient-dev sudo default-jre default-jdk -y 7 | 8 | VOLUME /Sites/online_test 9 | 10 | ADD Files/requirements-* /tmp/ 11 | 12 | RUN pip3 install -r /tmp/requirements-codeserver.txt && mkdir -p /Sites/online_test/yaksh_data/output /Sites/online_test/yaksh_data/data 13 | 14 | WORKDIR /Sites/online_test 15 | 16 | ADD Files/Start-codeserver.sh /Sites 17 | 18 | EXPOSE 53579 19 | 20 | CMD [ "/bin/bash" , "/Sites/Start-codeserver.sh" ] 21 | -------------------------------------------------------------------------------- /docker/Dockerfile_django: -------------------------------------------------------------------------------- 1 | FROM ubuntu:16.04 2 | 3 | MAINTAINER FOSSEE 4 | 5 | RUN apt-get update -y && apt-get install git python3-pip vim libmysqlclient-dev sudo -y 6 | 7 | RUN apt-get install apache2 libapache2-mod-wsgi-py3 python3-django -y && mkdir -p /Sites/online_test 8 | 9 | VOLUME /Sites/online_test 10 | 11 | ADD Files/requirements-* /tmp/ 12 | 13 | RUN cd /Sites/online_test && pip3 install -r /tmp/requirements-py3.txt 14 | 15 | ADD Files/000-default.conf /etc/apache2/sites-enabled/ 16 | 17 | ADD Files/Docker-script.sh /Sites/Docker-script.sh 18 | 19 | EXPOSE 80 20 | 21 | WORKDIR /Sites/online_test 22 | 23 | CMD [ "/bin/bash" , "/Sites/Docker-script.sh" ] 24 | -------------------------------------------------------------------------------- /docker/Files/000-default.conf: -------------------------------------------------------------------------------- 1 | 2 | ServerName localhost 3 | ServerAdmin webmaster@localhost 4 | DocumentRoot /Sites/online_test 5 | WSGIDaemonProcess yaksh threads=5 python-path=/usr/local/lib/python3.5/dist-packages home=/Sites/online_test 6 | WSGIScriptAlias / /Sites/online_test/online_test/wsgi.py 7 | WSGIProcessGroup yaksh 8 | Alias /static/ /Sites/online_test/yaksh/static/ 9 | 10 | WSGIProcessGroup yaksh 11 | WSGIApplicationGroup %{GLOBAL} 12 | Order deny,allow 13 | Allow from all 14 | Require all granted 15 | 16 | ErrorLog ${APACHE_LOG_DIR}/error.log 17 | CustomLog ${APACHE_LOG_DIR}/access.log combined 18 | 19 | -------------------------------------------------------------------------------- /docker/Files/Docker-script.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | chown -R www-data /Sites/online_test 3 | chown -R www-data /Sites/online_test/yaksh 4 | chown -R nobody /Sites/online_test/yaksh_data 5 | chmod -R 664 /Sites/online_test 6 | chmod -R +X /Sites 7 | /usr/sbin/apache2ctl -D FOREGROUND 8 | -------------------------------------------------------------------------------- /docker/Files/Start-codeserver.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | chown -R nobody /Sites/online_test/yaksh_data 3 | chmod -R a+rwX yaksh_data/output 4 | chmod -R a+rX yaksh_data/data 5 | chmod -R o-w yaksh_data/data 6 | /usr/bin/sudo -su nobody python3 -m yaksh.code_server 7 | -------------------------------------------------------------------------------- /docker/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '2' 2 | services: 3 | yaksh-django: 4 | build: 5 | context: . 6 | dockerfile: Dockerfile_django 7 | image: yaksh.django 8 | container_name: yaksh_django 9 | volumes: 10 | - ../.:/Sites/online_test 11 | depends_on: 12 | - yaksh-db 13 | - yaksh-codeserver 14 | links: 15 | - yaksh-db 16 | - yaksh-codeserver 17 | ports: 18 | - 8000:80 19 | restart: always 20 | 21 | 22 | yaksh-codeserver: 23 | build: 24 | context: . 25 | dockerfile: Dockerfile_codeserver 26 | image: yaksh.codeserver 27 | container_name: yaksh_codeserver 28 | volumes: 29 | - ..:/Sites/online_test 30 | restart: always 31 | 32 | 33 | yaksh-db: 34 | image: mariadb:10.2 35 | container_name: yaksh_db 36 | volumes: 37 | - ./mysql:/var/lib/mysql 38 | environment: 39 | MYSQL_ROOT_PASSWORD: root 40 | MYSQL_DATABASE: yaksh 41 | restart: always 42 | -------------------------------------------------------------------------------- /grades/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FOSSEE/online_test/9ea045b637f2087c1f1cdf8855d2d42b5f74a875/grades/__init__.py -------------------------------------------------------------------------------- /grades/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | from grades.models import GradingSystem, GradeRange 3 | 4 | 5 | class GradingSystemAdmin(admin.ModelAdmin): 6 | readonly_fields = ('creator',) 7 | 8 | admin.site.register(GradingSystem, GradingSystemAdmin) 9 | admin.site.register(GradeRange) 10 | -------------------------------------------------------------------------------- /grades/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class GradesConfig(AppConfig): 5 | name = 'grades' 6 | -------------------------------------------------------------------------------- /grades/forms.py: -------------------------------------------------------------------------------- 1 | from grades.models import GradingSystem, GradeRange 2 | from django import forms 3 | 4 | 5 | class GradingSystemForm(forms.ModelForm): 6 | 7 | def __init__(self, *args, **kwargs): 8 | super(GradingSystemForm, self).__init__(*args, **kwargs) 9 | self.fields['name'].widget.attrs.update( 10 | {'class': "form-control", 'placeholder': 'Grading Name'} 11 | ) 12 | self.fields['description'].widget.attrs.update( 13 | {'class': "form-control", 14 | 'placeholder': 'Grading description'} 15 | ) 16 | class Meta: 17 | model = GradingSystem 18 | fields = ['name', 'description'] 19 | 20 | 21 | class GradeRangeForm(forms.ModelForm): 22 | def __init__(self, *args, **kwargs): 23 | super(GradeRangeForm, self).__init__(*args, **kwargs) 24 | self.fields['lower_limit'].widget.attrs.update( 25 | {'class': "form-control", 'placeholder': 'Lower limit'} 26 | ) 27 | self.fields['upper_limit'].widget.attrs.update( 28 | {'class': "form-control", 'placeholder': 'Upper limit'} 29 | ) 30 | self.fields['grade'].widget.attrs.update( 31 | {'class': "form-control", 'placeholder': 'Grade'} 32 | ) 33 | self.fields['description'].widget.attrs.update( 34 | {'class': "form-control", 35 | 'placeholder': 'Description'} 36 | ) 37 | 38 | class Meta: 39 | model = GradeRange 40 | fields = "__all__" 41 | -------------------------------------------------------------------------------- /grades/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.9.5 on 2018-02-12 11:12 3 | from __future__ import unicode_literals 4 | 5 | from django.conf import settings 6 | from django.db import migrations, models 7 | import django.db.models.deletion 8 | 9 | 10 | class Migration(migrations.Migration): 11 | 12 | initial = True 13 | 14 | dependencies = [ 15 | migrations.swappable_dependency(settings.AUTH_USER_MODEL), 16 | ] 17 | 18 | operations = [ 19 | migrations.CreateModel( 20 | name='GradeRange', 21 | fields=[ 22 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 23 | ('lower_limit', models.FloatField()), 24 | ('upper_limit', models.FloatField()), 25 | ('grade', models.CharField(max_length=10)), 26 | ('description', models.CharField(blank=True, max_length=127, null=True)), 27 | ], 28 | ), 29 | migrations.CreateModel( 30 | name='GradingSystem', 31 | fields=[ 32 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 33 | ('name', models.CharField(max_length=255, unique=True)), 34 | ('description', models.TextField(default='About the grading system!')), 35 | ('creator', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), 36 | ], 37 | ), 38 | migrations.AddField( 39 | model_name='graderange', 40 | name='system', 41 | field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='grades.GradingSystem'), 42 | ), 43 | ] 44 | -------------------------------------------------------------------------------- /grades/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FOSSEE/online_test/9ea045b637f2087c1f1cdf8855d2d42b5f74a875/grades/migrations/__init__.py -------------------------------------------------------------------------------- /grades/migrations/default_grading_system.py: -------------------------------------------------------------------------------- 1 | from django.db import migrations 2 | 3 | 4 | def create_default_system(apps, schema_editor): 5 | GradingSystem = apps.get_model('grades', 'GradingSystem') 6 | GradeRange = apps.get_model('grades', 'GradeRange') 7 | db = schema_editor.connection.alias 8 | 9 | default_system = GradingSystem.objects.using(db).create(name='default') 10 | 11 | graderanges_objects = [ 12 | GradeRange(system=default_system, lower_limit=0, upper_limit=40, 13 | grade='F', description='Fail'), 14 | GradeRange(system=default_system, lower_limit=40, upper_limit=55, 15 | grade='P', description='Pass'), 16 | GradeRange(system=default_system, lower_limit=55, upper_limit=60, 17 | grade='C', description='Average'), 18 | GradeRange(system=default_system, lower_limit=60, upper_limit=75, 19 | grade='B', description='Satisfactory'), 20 | GradeRange(system=default_system, lower_limit=75, upper_limit=90, 21 | grade='A', description='Good'), 22 | GradeRange(system=default_system, lower_limit=90, upper_limit=101, 23 | grade='A+', description='Excellent') 24 | ] 25 | GradeRange.objects.using(db).bulk_create(graderanges_objects) 26 | 27 | 28 | def delete_default_system(apps, schema_editor): 29 | GradingSystem = apps.get_model('grades', 'GradingSystem') 30 | GradeRange = apps.get_model('grades', 'GradeRange') 31 | db = schema_editor.connection.alias 32 | 33 | default_system = GradingSystem.objects.using(db).get(creator=None) 34 | GradeRange.object.using(db).filter(system=default_system).delete() 35 | default_system.delete() 36 | 37 | 38 | class Migration(migrations.Migration): 39 | dependencies = [('grades', '0001_initial'), ] 40 | operations = [migrations.RunPython(create_default_system, 41 | delete_default_system), ] 42 | -------------------------------------------------------------------------------- /grades/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | from django.contrib.auth.models import User 3 | 4 | 5 | class GradingSystem(models.Model): 6 | name = models.CharField(max_length=255, unique=True) 7 | description = models.TextField(default='About the grading system!') 8 | creator = models.ForeignKey(User, null=True, blank=True, 9 | on_delete=models.CASCADE) 10 | 11 | def get_grade(self, marks): 12 | ranges = self.graderange_set.all() 13 | lower_limits = ranges.values_list('lower_limit', flat=True) 14 | upper_limits = ranges.values_list('upper_limit', flat=True) 15 | lower_limit = self._get_lower_limit(marks, lower_limits) 16 | upper_limit = self._get_upper_limit(marks, upper_limits) 17 | grade_range = ranges.filter(lower_limit=lower_limit, 18 | upper_limit=upper_limit).first() 19 | if grade_range: 20 | return grade_range.grade 21 | 22 | def _get_upper_limit(self, marks, upper_limits): 23 | greater_than = [upper_limit for upper_limit in upper_limits 24 | if upper_limit > marks] 25 | if greater_than: 26 | return min(greater_than, key=lambda x: x-marks) 27 | 28 | def _get_lower_limit(self, marks, lower_limits): 29 | less_than = [] 30 | for lower_limit in lower_limits: 31 | if lower_limit == marks: 32 | return lower_limit 33 | if lower_limit < marks: 34 | less_than.append(lower_limit) 35 | if less_than: 36 | return max(less_than, key=lambda x: x-marks) 37 | 38 | def __str__(self): 39 | return self.name.title() 40 | 41 | 42 | class GradeRange(models.Model): 43 | system = models.ForeignKey(GradingSystem, on_delete=models.CASCADE) 44 | lower_limit = models.FloatField() 45 | upper_limit = models.FloatField() 46 | grade = models.CharField(max_length=10) 47 | description = models.CharField(max_length=127, null=True, blank=True) 48 | 49 | def __str__(self): 50 | return self.system.name.title() 51 | -------------------------------------------------------------------------------- /grades/tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FOSSEE/online_test/9ea045b637f2087c1f1cdf8855d2d42b5f74a875/grades/tests/__init__.py -------------------------------------------------------------------------------- /grades/tests/test_models.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | from grades.models import GradingSystem 3 | 4 | 5 | class GradingSystemTestCase(TestCase): 6 | def setUp(self): 7 | GradingSystem.objects.create(name='unusable') 8 | 9 | def test_get_grade(self): 10 | # Given 11 | grading_system = GradingSystem.objects.get(name='default') 12 | expected_grades = {0: 'F', 31: 'F', 49: 'P', 55: 'C', 60: 'B', 80: 'A', 13 | 95: 'A+', 100: 'A+', 100.5: 'A+', 101: None, 14 | 109: None} 15 | for marks in expected_grades.keys(): 16 | # When 17 | grade = grading_system.get_grade(marks) 18 | # Then 19 | self.assertEqual(expected_grades.get(marks), grade) 20 | 21 | def test_grade_system_unusable(self): 22 | # Given 23 | # System with out ranges 24 | grading_system = GradingSystem.objects.get(name='unusable') 25 | # When 26 | grade = grading_system.get_grade(29) 27 | # Then 28 | self.assertIsNone(grade) 29 | -------------------------------------------------------------------------------- /grades/urls.py: -------------------------------------------------------------------------------- 1 | from django.conf.urls import url 2 | from grades import views 3 | 4 | app_name = 'grades' 5 | 6 | urlpatterns = [ 7 | url(r'^$', views.grading_systems, name="grading_systems_home"), 8 | url(r'^grading_systems/$', views.grading_systems, name="grading_systems"), 9 | url(r'^add_grade/$', views.add_grading_system, name="add_grade"), 10 | url(r'^add_grade/(?P\d+)/$', views.add_grading_system, 11 | name="edit_grade"), 12 | ] 13 | -------------------------------------------------------------------------------- /grades/views.py: -------------------------------------------------------------------------------- 1 | from django.shortcuts import render 2 | from django.contrib.auth.decorators import login_required 3 | from django.forms import inlineformset_factory 4 | from django.contrib import messages 5 | from grades.forms import GradingSystemForm, GradeRangeForm 6 | from grades.models import GradingSystem, GradeRange 7 | 8 | 9 | @login_required 10 | def grading_systems(request): 11 | user = request.user 12 | default_grading_system = GradingSystem.objects.get(name='default') 13 | grading_systems = GradingSystem.objects.filter(creator=user) 14 | return render(request, 'grading_systems.html', {'default_grading_system': 15 | default_grading_system, 'grading_systems': grading_systems}) 16 | 17 | 18 | @login_required 19 | def add_grading_system(request, system_id=None): 20 | user = request.user 21 | grading_system = None 22 | if system_id is not None: 23 | grading_system = GradingSystem.objects.get(id=system_id) 24 | GradeRangeFormSet = inlineformset_factory(GradingSystem, GradeRange, 25 | GradeRangeForm, extra=0) 26 | grade_form = GradingSystemForm(instance=grading_system) 27 | is_default = (grading_system is not None and 28 | grading_system.name == 'default') 29 | 30 | if request.method == 'POST': 31 | formset = GradeRangeFormSet(request.POST, instance=grading_system) 32 | grade_form = GradingSystemForm(request.POST, instance=grading_system) 33 | if grade_form.is_valid(): 34 | grading_system = grade_form.save(commit=False) 35 | grading_system.creator = user 36 | grading_system.save() 37 | system_id = grading_system.id 38 | if formset.is_valid(): 39 | formset.save() 40 | messages.success(request, "Grading system saved successfully") 41 | if 'add' in request.POST: 42 | GradeRangeFormSet = inlineformset_factory( 43 | GradingSystem, GradeRange, GradeRangeForm, extra=1 44 | ) 45 | formset = GradeRangeFormSet(instance=grading_system) 46 | 47 | return render(request, 'add_grades.html', 48 | {'formset': formset, 49 | 'grade_form': grade_form, "system_id": system_id, 50 | 'is_default': is_default} 51 | ) 52 | -------------------------------------------------------------------------------- /manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import os 3 | import sys 4 | 5 | if __name__ == "__main__": 6 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "online_test.settings") 7 | 8 | from django.core.management import execute_from_command_line 9 | 10 | execute_from_command_line(sys.argv) 11 | -------------------------------------------------------------------------------- /online_test/__init__.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import, unicode_literals 2 | 3 | from online_test.celery_settings import app as celery_app 4 | 5 | __all__ = ('celery_app',) 6 | 7 | __version__ = '0.31.1' 8 | -------------------------------------------------------------------------------- /online_test/celery_settings.py: -------------------------------------------------------------------------------- 1 | import os 2 | from django.conf import settings 3 | from celery import Celery 4 | 5 | # set the default Django settings module for the 'celery' program. 6 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'online_test.settings') 7 | 8 | app = Celery('online_test') 9 | 10 | # Using a string here means the worker doesn't have to serialize 11 | # the configuration object to child processes. 12 | # - namespace='CELERY' means all celery-related configuration keys 13 | # should have a `CELERY_` prefix. 14 | app.config_from_object('django.conf:settings', namespace='CELERY') 15 | 16 | # Load task modules from all registered Django app configs. 17 | app.autodiscover_tasks(lambda: settings.INSTALLED_APPS) 18 | 19 | @app.task(name='celery.ping') 20 | def ping(): 21 | # type: () -> str 22 | """Simple task that just returns 'pong'.""" 23 | return 'pong' 24 | -------------------------------------------------------------------------------- /online_test/test_settings.py: -------------------------------------------------------------------------------- 1 | from online_test.settings import * 2 | 3 | 4 | MIGRATION_MODULES = {'yaksh': None} -------------------------------------------------------------------------------- /online_test/urls.py: -------------------------------------------------------------------------------- 1 | from django.conf.urls import include, url 2 | from django.conf import settings 3 | from django.conf.urls.static import static 4 | from django.contrib import admin 5 | from online_test import views 6 | admin.autodiscover() 7 | 8 | urlpatterns = [ 9 | # Examples: 10 | # url(r'^$', 'online_test.views.home', name='home'), 11 | # url(r'^blog/', include('blog.urls')), 12 | 13 | url(r'^admin/', admin.site.urls), 14 | url(r'^$', views.index, name='index'), 15 | url(r'^exam/', include(('yaksh.urls', 'yaksh'))), 16 | url(r'^exam/reset/', include('django.contrib.auth.urls')), 17 | url(r'^', include('social_django.urls', namespace='social')), 18 | url(r'^grades/', include(('grades.urls', 'grades'))), 19 | url(r'^api/', include('api.urls', namespace='api')), 20 | url(r'^stats/', include('stats.urls', namespace='stats')), 21 | url(r'^flatfiles/', include(('upload.urls', 'upload'))), 22 | 23 | ] 24 | urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) 25 | -------------------------------------------------------------------------------- /online_test/views.py: -------------------------------------------------------------------------------- 1 | from django.shortcuts import redirect 2 | 3 | from .settings import URL_ROOT 4 | 5 | 6 | def index(request): 7 | return redirect('{0}/exam/'.format(URL_ROOT)) 8 | -------------------------------------------------------------------------------- /online_test/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for online_test project. 3 | 4 | It exposes the WSGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/1.6/howto/deployment/wsgi/ 8 | """ 9 | 10 | import os 11 | from django.core.wsgi import get_wsgi_application 12 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "online_test.settings") 13 | 14 | application = get_wsgi_application() 15 | -------------------------------------------------------------------------------- /requirements/requirements-codeserver.txt: -------------------------------------------------------------------------------- 1 | pytest 2 | python-decouple 3 | requests 4 | tornado==4.5.3 5 | psutil 6 | nose==1.3.7 7 | -------------------------------------------------------------------------------- /requirements/requirements-common.txt: -------------------------------------------------------------------------------- 1 | -r requirements-codeserver.txt 2 | invoke==0.21.0 3 | django==3.1.7 4 | django-taggit==1.2.0 5 | pytz==2019.3 6 | requests-oauthlib>=0.6.1 7 | social-auth-app-django==3.1.0 8 | selenium==2.53.6 9 | coverage 10 | ruamel.yaml==0.16.10 11 | pyyaml==5.3.1 12 | markdown==2.6.9 13 | pygments==2.2.0 14 | celery==4.4.2 15 | redis==3.4.1 16 | notifications-plugin==0.1.2 17 | django-celery-beat==2.0.0 18 | django-celery-results==1.2.1 19 | djangorestframework==3.11.2 20 | django-cors-headers==3.1.0 21 | Pillow 22 | pandas 23 | qrcode 24 | more-itertools==8.4.0 25 | django-storages==1.11.1 26 | boto3==1.17.17 27 | -------------------------------------------------------------------------------- /requirements/requirements-production.txt: -------------------------------------------------------------------------------- 1 | -r requirements-common.txt 2 | mysqlclient==1.4.6 3 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [metadata] 2 | description-file = README.rst 3 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | import os 2 | from setuptools import setup, find_packages 3 | 4 | README = open(os.path.join(os.path.dirname(__file__), 'README.rst')).read() 5 | 6 | # allow setup.py to be run from any path 7 | os.chdir(os.path.normpath(os.path.join(os.path.abspath(__file__), os.pardir))) 8 | 9 | 10 | def get_version(): 11 | import os 12 | data = {} 13 | fname = os.path.join('online_test', '__init__.py') 14 | exec(compile(open(fname).read(), fname, 'exec'), data) 15 | return data.get('__version__') 16 | 17 | 18 | install_requires = [ 19 | 'django==3.1.7', 20 | 'django-taggit==1.2.0', 21 | 'pytz==2019.3', 22 | 'requests-oauthlib>=0.6.1', 23 | 'python-social-auth==0.2.19', 24 | 'tornado', 25 | 'psutil', 26 | 'ruamel.yaml==0.15.23', 27 | 'invoke==0.21.0', 28 | 'requests', 29 | 'markdown==2.6.9', 30 | ] 31 | 32 | setup( 33 | name='yaksh', 34 | author='Python Team at FOSSEE, IIT Bombay', 35 | author_email='python@fossee.in', 36 | version=get_version(), 37 | packages=find_packages(), 38 | include_package_data=True, 39 | url='https://pypi.python.org/pypi/yaksh/', 40 | license='BSD License', 41 | entry_points={ 42 | 'console_scripts': [ 43 | 'yaksh = yaksh.code_server:main', 44 | ], 45 | }, 46 | description='A django app to conduct online programming tests.', 47 | long_description=README, 48 | install_requires=install_requires, 49 | classifiers=[ 50 | 'Development Status :: 4 - Beta', 51 | 'Environment :: Web Environment', 52 | 'Framework :: Django', 53 | 'Intended Audience :: Developers', 54 | 'Intended Audience :: Education', 55 | 'Intended Audience :: End Users/Desktop', 56 | 'License :: OSI Approved :: BSD License', 57 | 'Natural Language :: English', 58 | 'Operating System :: OS Independent', 59 | 'Programming Language :: Python', 60 | 'Programming Language :: Python :: 2.6', 61 | 'Programming Language :: Python :: 2.7', 62 | 'Programming Language :: Python :: 3.5', 63 | 'Topic :: Internet :: WWW/HTTP :: Dynamic Content', 64 | ], 65 | ) 66 | -------------------------------------------------------------------------------- /stats/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FOSSEE/online_test/9ea045b637f2087c1f1cdf8855d2d42b5f74a875/stats/__init__.py -------------------------------------------------------------------------------- /stats/admin.py: -------------------------------------------------------------------------------- 1 | # Django Imports 2 | from django.contrib import admin 3 | 4 | # Local Imports 5 | from stats.models import TrackLesson 6 | 7 | 8 | class TrackLessonAdmin(admin.ModelAdmin): 9 | search_fields = ['user__first_name', 'user__last_name', 'user__username', 10 | 'course__name', 'lesson__name'] 11 | readonly_fields = ["course", "user", "lesson"] 12 | 13 | 14 | admin.site.register(TrackLesson, TrackLessonAdmin) 15 | -------------------------------------------------------------------------------- /stats/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class StatsConfig(AppConfig): 5 | name = 'stats' 6 | -------------------------------------------------------------------------------- /stats/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 3.0.7 on 2020-11-07 13:46 2 | 3 | from django.conf import settings 4 | from django.db import migrations, models 5 | import django.db.models.deletion 6 | import django.utils.timezone 7 | 8 | 9 | class Migration(migrations.Migration): 10 | 11 | initial = True 12 | 13 | dependencies = [ 14 | migrations.swappable_dependency(settings.AUTH_USER_MODEL), 15 | ('yaksh', '0027_release_0_28_0'), 16 | ] 17 | 18 | operations = [ 19 | migrations.CreateModel( 20 | name='TrackLesson', 21 | fields=[ 22 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 23 | ('current_time', models.CharField(default='00:00:00', max_length=100)), 24 | ('video_duration', models.CharField(default='00:00:00', max_length=100)), 25 | ('creation_time', models.DateTimeField(auto_now_add=True)), 26 | ('course', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='yaksh.Course')), 27 | ('lesson', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='yaksh.Lesson')), 28 | ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), 29 | ], 30 | options={ 31 | 'unique_together': {('user', 'course', 'lesson')}, 32 | }, 33 | ), 34 | migrations.CreateModel( 35 | name='LessonLog', 36 | fields=[ 37 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 38 | ('last_access_time', models.DateTimeField(default=django.utils.timezone.now)), 39 | ('track', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='stats.TrackLesson')), 40 | ], 41 | ), 42 | ] 43 | -------------------------------------------------------------------------------- /stats/migrations/0002_release_0_29_1.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 3.0.7 on 2020-11-12 12:11 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('stats', '0001_initial'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AddField( 14 | model_name='lessonlog', 15 | name='current_time', 16 | field=models.CharField(default='00:00:00', max_length=20), 17 | ), 18 | migrations.AddField( 19 | model_name='tracklesson', 20 | name='watched', 21 | field=models.BooleanField(default=False), 22 | ), 23 | ] 24 | -------------------------------------------------------------------------------- /stats/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FOSSEE/online_test/9ea045b637f2087c1f1cdf8855d2d42b5f74a875/stats/migrations/__init__.py -------------------------------------------------------------------------------- /stats/urls.py: -------------------------------------------------------------------------------- 1 | from django.urls import path 2 | from stats import views 3 | 4 | 5 | app_name = "stats" 6 | 7 | urlpatterns = [ 8 | path('submit/video/watch/', 9 | views.add_tracker, name='add_tracker'), 10 | path('view/watch/stats//', 11 | views.view_lesson_watch_stats, name='view_lesson_watch_stats'), 12 | ] 13 | -------------------------------------------------------------------------------- /upload/models.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FOSSEE/online_test/9ea045b637f2087c1f1cdf8855d2d42b5f74a875/upload/models.py -------------------------------------------------------------------------------- /upload/urls.py: -------------------------------------------------------------------------------- 1 | from django.conf.urls import url 2 | from upload import views 3 | 4 | app_name = 'upload' 5 | 6 | urlpatterns = [ 7 | url(r'^download_course_md/(?P\d+)/$', 8 | views.download_course_md, name="download_course_md"), 9 | ] -------------------------------------------------------------------------------- /upload/views.py: -------------------------------------------------------------------------------- 1 | import tempfile 2 | import os 3 | from zipfile import ZipFile 4 | from io import BytesIO as string_io 5 | 6 | from django.http import HttpResponse 7 | from django.shortcuts import render 8 | from django.contrib.auth.decorators import login_required 9 | from django.contrib import messages 10 | 11 | from upload.utils import upload_course, write_course_to_file 12 | 13 | 14 | def upload_course_md(request): 15 | if request.method == 'POST': 16 | status = False 17 | msg = None 18 | user = request.user 19 | course_upload_file = request.FILES.get('course_upload_md') 20 | file_extension = os.path.splitext(course_upload_file.name)[1][1:] 21 | if file_extension not in ['zip']: 22 | messages.warning( 23 | request, "Please upload zip file" 24 | ) 25 | else: 26 | curr_dir = os.getcwd() 27 | try: 28 | with tempfile.TemporaryDirectory() as tmpdirname, ZipFile(course_upload_file, 'r') as zip_file: 29 | zip_file.extractall(tmpdirname) 30 | os.chdir(tmpdirname) 31 | status, msg = upload_course(user) 32 | except Exception as e: 33 | import traceback 34 | traceback.print_exc() 35 | messages.warning(request, f"Error parsing file structure: {e}") 36 | finally: 37 | os.chdir(curr_dir) 38 | 39 | return status, msg 40 | 41 | def download_course_md(request, course_id): 42 | curr_dir = os.getcwd() 43 | zip_file_name = string_io() 44 | try: 45 | with tempfile.TemporaryDirectory() as tmpdirname, ZipFile(zip_file_name, 'w') as zip_file: 46 | os.chdir(tmpdirname) 47 | write_course_to_file(course_id) 48 | 49 | for foldername, subfolders, filenames in os.walk(tmpdirname): 50 | for filename in filenames: 51 | zip_file.write(os.path.join(filename)) 52 | except Exception as e: 53 | messages.warning(request, f"Error while downloading file: {e}") 54 | finally: 55 | os.chdir(curr_dir) 56 | 57 | zip_file_name.seek(0) 58 | response = HttpResponse(content_type='application/zip') 59 | response['Content-Disposition'] = 'attachment; filename=course.zip' 60 | response.write(zip_file_name.read()) 61 | 62 | return response -------------------------------------------------------------------------------- /yaksh/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FOSSEE/online_test/9ea045b637f2087c1f1cdf8855d2d42b5f74a875/yaksh/__init__.py -------------------------------------------------------------------------------- /yaksh/base_evaluator.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from __future__ import unicode_literals 3 | import os 4 | from os.path import abspath, exists 5 | import subprocess 6 | import stat 7 | import signal 8 | 9 | 10 | # Local imports 11 | from .grader import TimeoutException 12 | 13 | 14 | class BaseEvaluator(object): 15 | """Base Evaluator class containing generic attributes 16 | and callable methods""" 17 | 18 | def __init__(self): 19 | pass 20 | 21 | def check_code(self): 22 | raise NotImplementedError("check_code method not implemented") 23 | 24 | def compile_code(self): 25 | pass 26 | 27 | def _run_command(self, cmd_args, *args, **kw): 28 | """Run a command in a subprocess while blocking, the process is killed 29 | if it takes more than 2 seconds to run. Return the Popen object, the 30 | stdout and stderr. 31 | """ 32 | try: 33 | proc = subprocess.Popen(cmd_args, 34 | preexec_fn=os.setpgrp, *args, **kw) 35 | stdout, stderr = proc.communicate() 36 | except TimeoutException: 37 | # Runaway code, so kill it. 38 | os.killpg(os.getpgid(proc.pid), signal.SIGKILL) 39 | # Re-raise exception. 40 | raise 41 | return proc, stdout.decode('utf-8'), stderr.decode('utf-8') 42 | 43 | def _remove_null_substitute_char(self, string): 44 | """Returns a string without any null and substitute characters""" 45 | stripped = "" 46 | for c in string: 47 | if ord(c) != 26 and ord(c) != 0: 48 | stripped = stripped + c 49 | return ''.join(stripped) 50 | 51 | def create_submit_code_file(self, file_name): 52 | """ Set the file path for code (`answer`)""" 53 | submit_path = abspath(file_name) 54 | if not exists(submit_path): 55 | submit_f = open(submit_path, 'w') 56 | submit_f.close() 57 | 58 | return submit_path 59 | 60 | def write_to_submit_code_file(self, file_path, user_answer): 61 | """ Write the code (`answer`) to a file""" 62 | submit_f = open(file_path, 'w') 63 | submit_f.write(user_answer.lstrip()) 64 | submit_f.close() 65 | 66 | def _set_file_as_executable(self, fname): 67 | os.chmod(fname, stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR | 68 | stat.S_IRGRP | stat.S_IWGRP | stat.S_IXGRP | stat.S_IROTH | 69 | stat.S_IWOTH | stat.S_IXOTH) 70 | -------------------------------------------------------------------------------- /yaksh/decorators.py: -------------------------------------------------------------------------------- 1 | from django.shortcuts import render 2 | from django.conf import settings 3 | 4 | # Local imports 5 | from yaksh.forms import ProfileForm 6 | 7 | 8 | def user_has_profile(user): 9 | return hasattr(user, 'profile') 10 | 11 | 12 | def has_profile(func): 13 | """ 14 | This decorator is used to check if the user account has a profile. 15 | If the user does not have a profile then redirect the user to 16 | profile edit page. 17 | """ 18 | 19 | def _wrapped_view(request, *args, **kwargs): 20 | if user_has_profile(request.user): 21 | return func(request, *args, **kwargs) 22 | if request.user.groups.filter(name='moderator').exists(): 23 | template = 'manage.html' 24 | else: 25 | template = 'user.html' 26 | form = ProfileForm(user=request.user, instance=None) 27 | context = {'template': template, 'form': form} 28 | return render(request, 'yaksh/editprofile.html', context) 29 | return _wrapped_view 30 | 31 | 32 | def email_verified(func): 33 | """ 34 | This decorator is used to check if email is verified. 35 | If email is not verified then redirect user for email 36 | verification. 37 | """ 38 | 39 | def is_email_verified(request, *args, **kwargs): 40 | user = request.user 41 | context = {} 42 | if not settings.IS_DEVELOPMENT: 43 | if user.is_authenticated and user_has_profile(user): 44 | if not user.profile.is_email_verified: 45 | context['success'] = False 46 | context['msg'] = "Your account is not verified. \ 47 | Please verify your account" 48 | return render( 49 | request, 'yaksh/activation_status.html', context 50 | ) 51 | return func(request, *args, **kwargs) 52 | return is_email_verified 53 | -------------------------------------------------------------------------------- /yaksh/docs/sample.args: -------------------------------------------------------------------------------- 1 | 1 2 2 | 2 1 3 | -------------------------------------------------------------------------------- /yaksh/docs/sample.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | [[ $# -eq 2 ]] && echo $(( $1 + $2 )) && exit $(( $1 + $2 )) 3 | -------------------------------------------------------------------------------- /yaksh/docs/sample_questions.py: -------------------------------------------------------------------------------- 1 | from datetime import date 2 | 3 | questions = [ 4 | [Question( 5 | summary='Factorial', 6 | points=2, 7 | language='python', 8 | type='code', 9 | description=''' 10 | Write a function called fact which takes a single integer argument 11 | (say n) and returns the factorial of the number. 12 | For example:
13 | fact(3) -> 6 14 | ''', 15 | test=''' 16 | assert fact(0) == 1 17 | assert fact(5) == 120 18 | ''', 19 | snippet="def fact(num):" 20 | ), 21 | #Add tags here as a list of string. 22 | ['Python','function','factorial'], 23 | ], 24 | 25 | [Question( 26 | summary='Simple function', 27 | points=1, 28 | language='python', 29 | type='code', 30 | description='''Create a simple function called sqr which takes a single 31 | argument and returns the square of the argument. For example:
32 | sqr(3) -> 9.''', 33 | test=''' 34 | import math 35 | assert sqr(3) == 9 36 | assert abs(sqr(math.sqrt(2)) - 2.0) < 1e-14 37 | ''', 38 | snippet="def sqr(num):" 39 | ), 40 | #Add tags here as a list of string. 41 | ['Python','function'], 42 | ], 43 | 44 | [Question( 45 | summary='Bash addition', 46 | points=2, 47 | language='bash', 48 | type='code', 49 | description='''Write a shell script which takes two arguments on the 50 | command line and prints the sum of the two on the output.''', 51 | test='''\ 52 | docs/sample.sh 53 | docs/sample.args 54 | ''', 55 | snippet="#!/bin/bash" 56 | ), 57 | #Add tags here as a list of string. 58 | [''], 59 | ], 60 | 61 | [Question( 62 | summary='Size of integer in Python', 63 | points=0.5, 64 | language='python', 65 | type='mcq', 66 | description='''What is the largest integer value that can be represented 67 | in Python?''', 68 | options='''No Limit 69 | 2**32 70 | 2**32 - 1 71 | None of the above 72 | ''', 73 | test = "No Limit" 74 | ), 75 | #Add tags here as a list of string. 76 | ['mcq'], 77 | ], 78 | 79 | ] #list of questions ends here 80 | 81 | quiz = Quiz(duration=10, 82 | description='Basic Python Quiz 1', 83 | time_between_attempts=0 84 | ) 85 | -------------------------------------------------------------------------------- /yaksh/docs/sample_questions.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Factorial 6 | 7 | 8 | Write a function called "fact" which takes a single integer argument (say "n") 9 | and returns the factorial of the number. 10 | For example fact(3) -> 6 11 | 12 | 2 13 | python 14 | 15 | assert fact(0) == 1 16 | assert fact(5) == 120 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | Simple function 25 | 26 | 27 | Create a simple function called "sqr" which takes a single argument and 28 | returns the square of the argument 29 | For example sqr(3) -> 9. 30 | 31 | 1 32 | python 33 | 34 | import math 35 | assert sqr(3) == 9 36 | assert abs(sqr(math.sqrt(2)) - 2.0) < 1e-14 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /yaksh/documentation/about_yaksh.rst: -------------------------------------------------------------------------------- 1 | =========== 2 | About Yaksh 3 | =========== 4 | 5 | History 6 | ------- 7 | 8 | At FOSSEE, Nishanth had implemented a nice django based app to test for multiple-choice questions. Prabhu Ramachandran was inspired by a programming contest that he saw at PyCon APAC 2011. Chris Boesch, who administered the contest, used a nice web application Singpath that he had built on top of GAE that basically checked your Python code, live. This made it fun and interesting. 9 | 10 | Prabhu wanted an implementation that was not tied to GAE and hence wrote the initial cut of what is now 'Yaksh'. The idea being that anyone can use this to test students programming skills and not have to worry about grading their answers manually and instead do so on their machines. 11 | 12 | The application has since been refactored and maintained by FOSSEE Developers. 13 | 14 | 15 | Contact 16 | ------- 17 | 18 | For further information and support you can contact 19 | 20 | `Python Team at FOSSEE `_ 21 | 22 | License 23 | ------- 24 | This is distributed under the terms of the BSD license. 25 | 26 | Authors 27 | ------- 28 | FOSSEE Developers 29 | -------------------------------------------------------------------------------- /yaksh/documentation/images/add_exercise.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FOSSEE/online_test/9ea045b637f2087c1f1cdf8855d2d42b5f74a875/yaksh/documentation/images/add_exercise.jpg -------------------------------------------------------------------------------- /yaksh/documentation/images/add_lesson.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FOSSEE/online_test/9ea045b637f2087c1f1cdf8855d2d42b5f74a875/yaksh/documentation/images/add_lesson.jpg -------------------------------------------------------------------------------- /yaksh/documentation/images/add_module.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FOSSEE/online_test/9ea045b637f2087c1f1cdf8855d2d42b5f74a875/yaksh/documentation/images/add_module.jpg -------------------------------------------------------------------------------- /yaksh/documentation/images/add_question.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FOSSEE/online_test/9ea045b637f2087c1f1cdf8855d2d42b5f74a875/yaksh/documentation/images/add_question.jpg -------------------------------------------------------------------------------- /yaksh/documentation/images/add_quiz.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FOSSEE/online_test/9ea045b637f2087c1f1cdf8855d2d42b5f74a875/yaksh/documentation/images/add_quiz.jpg -------------------------------------------------------------------------------- /yaksh/documentation/images/bash_standard_testcase.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FOSSEE/online_test/9ea045b637f2087c1f1cdf8855d2d42b5f74a875/yaksh/documentation/images/bash_standard_testcase.jpg -------------------------------------------------------------------------------- /yaksh/documentation/images/course_details_features.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FOSSEE/online_test/9ea045b637f2087c1f1cdf8855d2d42b5f74a875/yaksh/documentation/images/course_details_features.jpg -------------------------------------------------------------------------------- /yaksh/documentation/images/course_features.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FOSSEE/online_test/9ea045b637f2087c1f1cdf8855d2d42b5f74a875/yaksh/documentation/images/course_features.jpg -------------------------------------------------------------------------------- /yaksh/documentation/images/course_modules.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FOSSEE/online_test/9ea045b637f2087c1f1cdf8855d2d42b5f74a875/yaksh/documentation/images/course_modules.jpg -------------------------------------------------------------------------------- /yaksh/documentation/images/cpp_standard_testcase.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FOSSEE/online_test/9ea045b637f2087c1f1cdf8855d2d42b5f74a875/yaksh/documentation/images/cpp_standard_testcase.jpg -------------------------------------------------------------------------------- /yaksh/documentation/images/create_course.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FOSSEE/online_test/9ea045b637f2087c1f1cdf8855d2d42b5f74a875/yaksh/documentation/images/create_course.jpg -------------------------------------------------------------------------------- /yaksh/documentation/images/create_course.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FOSSEE/online_test/9ea045b637f2087c1f1cdf8855d2d42b5f74a875/yaksh/documentation/images/create_course.png -------------------------------------------------------------------------------- /yaksh/documentation/images/design_course.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FOSSEE/online_test/9ea045b637f2087c1f1cdf8855d2d42b5f74a875/yaksh/documentation/images/design_course.jpg -------------------------------------------------------------------------------- /yaksh/documentation/images/design_module.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FOSSEE/online_test/9ea045b637f2087c1f1cdf8855d2d42b5f74a875/yaksh/documentation/images/design_module.jpg -------------------------------------------------------------------------------- /yaksh/documentation/images/design_questionpaper.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FOSSEE/online_test/9ea045b637f2087c1f1cdf8855d2d42b5f74a875/yaksh/documentation/images/design_questionpaper.jpg -------------------------------------------------------------------------------- /yaksh/documentation/images/embed_video.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FOSSEE/online_test/9ea045b637f2087c1f1cdf8855d2d42b5f74a875/yaksh/documentation/images/embed_video.jpg -------------------------------------------------------------------------------- /yaksh/documentation/images/float_testcase.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FOSSEE/online_test/9ea045b637f2087c1f1cdf8855d2d42b5f74a875/yaksh/documentation/images/float_testcase.jpg -------------------------------------------------------------------------------- /yaksh/documentation/images/hook_testcase.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FOSSEE/online_test/9ea045b637f2087c1f1cdf8855d2d42b5f74a875/yaksh/documentation/images/hook_testcase.jpg -------------------------------------------------------------------------------- /yaksh/documentation/images/integer_testcase.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FOSSEE/online_test/9ea045b637f2087c1f1cdf8855d2d42b5f74a875/yaksh/documentation/images/integer_testcase.jpg -------------------------------------------------------------------------------- /yaksh/documentation/images/java_standard_testcase.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FOSSEE/online_test/9ea045b637f2087c1f1cdf8855d2d42b5f74a875/yaksh/documentation/images/java_standard_testcase.jpg -------------------------------------------------------------------------------- /yaksh/documentation/images/mcc_testcase.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FOSSEE/online_test/9ea045b637f2087c1f1cdf8855d2d42b5f74a875/yaksh/documentation/images/mcc_testcase.jpg -------------------------------------------------------------------------------- /yaksh/documentation/images/mcq_testcase.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FOSSEE/online_test/9ea045b637f2087c1f1cdf8855d2d42b5f74a875/yaksh/documentation/images/mcq_testcase.jpg -------------------------------------------------------------------------------- /yaksh/documentation/images/moderator_dashboard.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FOSSEE/online_test/9ea045b637f2087c1f1cdf8855d2d42b5f74a875/yaksh/documentation/images/moderator_dashboard.jpg -------------------------------------------------------------------------------- /yaksh/documentation/images/python_standard_testcase.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FOSSEE/online_test/9ea045b637f2087c1f1cdf8855d2d42b5f74a875/yaksh/documentation/images/python_standard_testcase.jpg -------------------------------------------------------------------------------- /yaksh/documentation/images/questions.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FOSSEE/online_test/9ea045b637f2087c1f1cdf8855d2d42b5f74a875/yaksh/documentation/images/questions.jpg -------------------------------------------------------------------------------- /yaksh/documentation/images/r_standard_testcase.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FOSSEE/online_test/9ea045b637f2087c1f1cdf8855d2d42b5f74a875/yaksh/documentation/images/r_standard_testcase.jpg -------------------------------------------------------------------------------- /yaksh/documentation/images/scilab_standard_testcase.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FOSSEE/online_test/9ea045b637f2087c1f1cdf8855d2d42b5f74a875/yaksh/documentation/images/scilab_standard_testcase.jpg -------------------------------------------------------------------------------- /yaksh/documentation/images/stdio_testcase.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FOSSEE/online_test/9ea045b637f2087c1f1cdf8855d2d42b5f74a875/yaksh/documentation/images/stdio_testcase.jpg -------------------------------------------------------------------------------- /yaksh/documentation/images/string_testcase.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FOSSEE/online_test/9ea045b637f2087c1f1cdf8855d2d42b5f74a875/yaksh/documentation/images/string_testcase.jpg -------------------------------------------------------------------------------- /yaksh/documentation/index.rst: -------------------------------------------------------------------------------- 1 | Welcome to Yaksh's documentation! 2 | ================================= 3 | 4 | Yaksh lets user create and take online programming quiz. Yaksh is an open source project developed by FOSSEE. The code is available on `github `_. 5 | 6 | The user documentation for the site is organized into a few sections: 7 | 8 | .. toctree:: 9 | 10 | introduction.rst 11 | installation.rst 12 | moderator_dashboard.rst 13 | about_yaksh.rst -------------------------------------------------------------------------------- /yaksh/documentation/introduction.rst: -------------------------------------------------------------------------------- 1 | ============ 2 | Introduction 3 | ============ 4 | 5 | This project provides an "exam" app that lets users take an online programming quiz. 6 | 7 | 8 | Features 9 | -------- 10 | * Easy installation and cross platform support for Linux and Mac OS. 11 | * Define fairly complicated programming problems and have users solve the problem. 12 | * Immediate verification of code solution. 13 | * Supports pretty much arbitrary coding questions in Python, C, C++, Java, Scilab and simple Bash and uses "test cases" to test the implementations of the students. 14 | * Supports simple multiple choice questions, fill in the blanks questions and assignment evaluations. 15 | * Since it runs on Python, you could technically test any Python based library. 16 | * Completely safe from malicious code. 17 | * Scales to over 500+ simultaneous users. 18 | * Distributed under the BSD license. 19 | 20 | -------------------------------------------------------------------------------- /yaksh/documentation/moderator_dashboard.rst: -------------------------------------------------------------------------------- 1 | ===================== 2 | Moderator's Dashboard 3 | ===================== 4 | 5 | On logging in moderators see the following dashboard. 6 | 7 | .. image:: images/moderator_dashboard.jpg 8 | 9 | There are two options available: 10 | * **Add Course** 11 | It allows to create a new course. 12 | * **Create Demo Course** 13 | It creates a demo course contaning sample lesson and quiz with questions. 14 | 15 | The dashboard contains all the courses. Each course provides two options 16 | 17 | * **Manage Course** 18 | Click on this button to manage the course. See the Manage course section 19 | in the :doc:`moderator_docs/creating_course` page for more details. 20 | * **Details** 21 | Clicking on the Details button shows all the quizzes in the course. 22 | Click on the quiz link to monitor the quiz. 23 | 24 | 25 | The following pages explain the various functions available for moderators 26 | 27 | .. toctree:: 28 | 29 | moderator_docs/creating_course.rst 30 | moderator_docs/creating_quiz.rst 31 | moderator_docs/creating_question.rst 32 | moderator_docs/creating_lessons_modules.rst 33 | moderator_docs/other_features.rst -------------------------------------------------------------------------------- /yaksh/documentation/moderator_docs/other_features.rst: -------------------------------------------------------------------------------- 1 | ============== 2 | Other Features 3 | ============== 4 | 5 | Grade User 6 | ---------- 7 | 8 | Grade User is a feature of Yaksh to access students' answer papers for each quiz and grade them where necessary. 9 | 10 | Clicking on the **Grade User** link from the nav bar will show all the courses. 11 | 12 | Click on the **Details** button to show the quizzes associated to a particular course. 13 | 14 | Click on the **Grade User** button next to the quiz name to view all the students who have attempted the quiz. 15 | 16 | Click on the student name to view their submissions. 17 | 18 | Monitor 19 | ------- 20 | 21 | Monitor is a feature of Yaksh where the moderator can monitor a quiz and view statistics. 22 | 23 | Clicking on the **Monitor** link from the nav bar will show all the courses. 24 | 25 | Click on the **Details** button to show the quizzes associated to a particular course. 26 | 27 | Click on the **Monitor** button next to the quiz name to view all the students who are attempting the quiz. 28 | 29 | Click on the student name to view their submissions. 30 | 31 | Grader 32 | ------ 33 | 34 | Click the **Grader** link on the navigation bar. 35 | This allows you to regrade answerpapers of students using three ways: 36 | 37 | 1. **Question wise regrade** 38 | Answerpapers can be regraded per Question. 39 | 2. **Quiz wise regrade** 40 | Answerpapers can be regraded per Quiz. 41 | 3. **User wise regrade** 42 | Answerpaper can be regraded for a particular student. 43 | 44 | -------------------------------------------------------------------------------- /yaksh/evaluator_tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FOSSEE/online_test/9ea045b637f2087c1f1cdf8855d2d42b5f74a875/yaksh/evaluator_tests/__init__.py -------------------------------------------------------------------------------- /yaksh/evaluator_tests/test_grader_evaluation.py: -------------------------------------------------------------------------------- 1 | from __future__ import unicode_literals 2 | import unittest 3 | from yaksh import python_assertion_evaluator 4 | from yaksh.language_registry import _LanguageRegistry, get_registry 5 | from yaksh.settings import code_evaluators 6 | 7 | 8 | class RegistryTestCase(unittest.TestCase): 9 | def setUp(self): 10 | self.registry_object = get_registry() 11 | self.language_registry = _LanguageRegistry() 12 | assertion_evaluator_path = ("yaksh.python_assertion_evaluator" 13 | ".PythonAssertionEvaluator" 14 | ) 15 | stdio_evaluator_path = ("yaksh.python_stdio_evaluator." 16 | "PythonStdIOEvaluator" 17 | ) 18 | 19 | hook_evaluator_path = ("yaksh.hook_evaluator." 20 | "HookEvaluator" 21 | ) 22 | code_evaluators['python'] = \ 23 | {"standardtestcase": assertion_evaluator_path, 24 | "stdiobasedtestcase": stdio_evaluator_path, 25 | "hooktestcase": hook_evaluator_path 26 | } 27 | 28 | def test_set_register(self): 29 | evaluator_class = self.registry_object.get_class( 30 | "python", "standardtestcase" 31 | ) 32 | class_name = getattr( 33 | python_assertion_evaluator, 'PythonAssertionEvaluator' 34 | ) 35 | self.assertEqual(evaluator_class, class_name) 36 | 37 | def tearDown(self): 38 | self.registry_object = None 39 | 40 | 41 | if __name__ == '__main__': 42 | unittest.main() 43 | -------------------------------------------------------------------------------- /yaksh/evaluator_tests/test_python_stdio_evaluator.py: -------------------------------------------------------------------------------- 1 | from yaksh.error_messages import compare_outputs 2 | 3 | 4 | def test_compare_outputs(): 5 | exp = "5\n5\n" 6 | given = "5\n5\n" 7 | success, msg = compare_outputs(given, exp) 8 | assert success 9 | 10 | exp = "5\n5\n" 11 | given = "5\n5" 12 | success, msg = compare_outputs(given, exp) 13 | assert success 14 | 15 | exp = "5\r5" 16 | given = "5\n5" 17 | success, msg = compare_outputs(given, exp) 18 | assert success 19 | 20 | exp = " 5 \r 5 " 21 | given = " 5 \n 5 " 22 | success, msg = compare_outputs(given, exp) 23 | assert success 24 | 25 | exp = "5\n5\n" 26 | given = "5 5" 27 | success, msg = compare_outputs(given, exp) 28 | error_msg = msg.get('error_msg') 29 | assert not success 30 | m = ("Incorrect Answer: We had expected 1 number of lines. " + 31 | "We got 2 number of lines.") 32 | assert m == error_msg 33 | 34 | exp = "5\n5\n" 35 | given = "5\n6" 36 | success, msg = compare_outputs(given, exp) 37 | error_msg = msg.get('error_msg') 38 | m = "Incorrect Answer: Line number(s) 2 did not match." 39 | assert not success 40 | assert m == error_msg 41 | -------------------------------------------------------------------------------- /yaksh/file_utils.py: -------------------------------------------------------------------------------- 1 | import shutil 2 | import os 3 | import zipfile 4 | import tempfile 5 | import csv 6 | 7 | 8 | def copy_files(file_paths): 9 | """ Copy Files to current directory, takes 10 | tuple with file paths and extract status""" 11 | 12 | files = [] 13 | for src in file_paths: 14 | file_path, extract = src 15 | file_name = os.path.basename(file_path) 16 | files.append(file_name) 17 | shutil.copy(file_path, os.getcwd()) 18 | if extract: 19 | z_files, path = extract_files(file_name, os.getcwd()) 20 | for file in z_files: 21 | files.append(file) 22 | return files 23 | 24 | 25 | def delete_files(files, file_path=None): 26 | """ Delete Files from directory """ 27 | for file_name in files: 28 | if file_path: 29 | file = os.path.join(file_path, file_name) 30 | else: 31 | file = file_name 32 | if os.path.exists(file): 33 | if os.path.isfile(file): 34 | os.remove(file) 35 | else: 36 | shutil.rmtree(file) 37 | 38 | 39 | def extract_files(zip_file, path=None): 40 | """ extract files from zip """ 41 | zfiles = [] 42 | if zipfile.is_zipfile(zip_file): 43 | zip_file = zipfile.ZipFile(zip_file, 'r') 44 | for z_file in zip_file.namelist(): 45 | zfiles.append(z_file) 46 | if path: 47 | extract_path = path 48 | else: 49 | extract_path = tempfile.mkdtemp() 50 | zip_file.extractall(extract_path) 51 | zip_file.close() 52 | return zfiles, extract_path 53 | 54 | 55 | def is_csv(document): 56 | ''' Check if document is csv with ',' as the delimiter''' 57 | try: 58 | try: 59 | content = document.read(1024).decode('utf-8') 60 | except AttributeError: 61 | document.seek(0) 62 | content = document.read(1024) 63 | sniffer = csv.Sniffer() 64 | dialect = sniffer.sniff(content, delimiters=',') 65 | document.seek(0) 66 | except (csv.Error, UnicodeDecodeError): 67 | return False, None 68 | return True, dialect 69 | -------------------------------------------------------------------------------- /yaksh/fixtures/demo_questions.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FOSSEE/online_test/9ea045b637f2087c1f1cdf8855d2d42b5f74a875/yaksh/fixtures/demo_questions.zip -------------------------------------------------------------------------------- /yaksh/fixtures/existing_user.csv: -------------------------------------------------------------------------------- 1 | firstname, lastname, email, username 2 | abcd, abcd, demo2@test.com, demo_user2 3 | -------------------------------------------------------------------------------- /yaksh/fixtures/invalid_yaml.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | name: 'Sample lesson topic 1' 3 | description: 'Topic 1 description' 4 | --- 5 | name: 'Sample lesson topic 1' 6 | description: 'Topic 1 description' 7 | content_type: 1 8 | time: '000000' -------------------------------------------------------------------------------- /yaksh/fixtures/marks_correct.csv: -------------------------------------------------------------------------------- 1 | user__username,Q-1212-Dummy1-1.0-marks,Q-1212-Dummy1-comments,Q-1213-Dummy2-1.0-marks,Q-1213-Dummy2-comments 2 | student1,1,good work,1,nice 3 | student2,1,good work,0,bad -------------------------------------------------------------------------------- /yaksh/fixtures/marks_header_missing.csv: -------------------------------------------------------------------------------- 1 | user__username,Q-1212-Dummy1-1.0-marks 2 | student1,0.9 3 | student2,1 4 | -------------------------------------------------------------------------------- /yaksh/fixtures/marks_header_modified.csv: -------------------------------------------------------------------------------- 1 | user__username,Q-1212-Dummmy1-1.0-marks,Q-1212-Dummy1-comments,Q-1213-Dummy2-1.0-marks,Q-1213-Dummy2-comments 2 | student1,0.75,fine work,1,not nice 3 | student2,1,good work,0,not okay 4 | -------------------------------------------------------------------------------- /yaksh/fixtures/marks_invalid_data.csv: -------------------------------------------------------------------------------- 1 | user__username,Q-1212-Dummy1-1.0-marks,Q-1212-Dummy1-comments,Q-1213-Dummy2-1.0-marks,Q-1213-Dummy2-comments 2 | student1,NA,good work,1,nice 3 | student2,1,good work,0,bad 4 | -------------------------------------------------------------------------------- /yaksh/fixtures/marks_invalid_question_id.csv: -------------------------------------------------------------------------------- 1 | user__username,Q-12112-Dummy1-1.0-marks,Q-1212-Dummy1-comments,Q-1213-Dummy2-1.0-marks,Q-1213-Dummy2-comments 2 | student1,1,good work,1,nice 3 | student2,1,good work,0,bad 4 | -------------------------------------------------------------------------------- /yaksh/fixtures/marks_invalid_user.csv: -------------------------------------------------------------------------------- 1 | user__username,Q-1212-Dummy1-1.0-marks,Q-1212-Dummy1-comments,Q-1213-Dummy2-1.0-marks,Q-1213-Dummy2-comments 2 | student1,1,good work,1,nice 3 | student452,1,good work,0,bad 4 | -------------------------------------------------------------------------------- /yaksh/fixtures/marks_not_attempted_question.csv: -------------------------------------------------------------------------------- 1 | user__username,Q-1212-Dummy1-1.0-marks,Q-1212-Dummy1-comments,Q-1213-Dummy2-1.0-marks,Q-1213-Dummy2-comments 2 | student1,1,good work,1,nice 3 | student2,0.3,very good,1,good 4 | -------------------------------------------------------------------------------- /yaksh/fixtures/marks_single_question.csv: -------------------------------------------------------------------------------- 1 | user__username,Q-1212-Dummy1-1.0-marks,Q-1212-Dummy1-comments 2 | student1,0.5,okay work 3 | student2,1,good work 4 | -------------------------------------------------------------------------------- /yaksh/fixtures/sample_lesson_toc.yaml: -------------------------------------------------------------------------------- 1 | # content_type 1: Topic, 2: Grading quiz, 3: Exercise, 4: Poll 2 | --- 3 | summary: |- 4 | Sample lesson quiz 1 5 | type: |- 6 | mcq 7 | language: |- 8 | other 9 | description: |- 10 | Choose the letter from the following 11 | points: 1.0 12 | testcase: 13 | - test_case_type: |- 14 | mcqtestcase 15 | options: |- 16 | A 17 | correct: false 18 | - test_case_type: |- 19 | mcqtestcase 20 | options: |- 21 | B 22 | correct: true 23 | - test_case_type: |- 24 | mcqtestcase 25 | options: |- 26 | C 27 | correct: false 28 | - test_case_type: |- 29 | mcqtestcase 30 | options: |- 31 | D 32 | correct: false 33 | active: true 34 | topic: 'Dummy1' 35 | content_type: 2 36 | time: '00:02:00' 37 | --- 38 | summary: |- 39 | Sample lesson quiz 2 40 | type: |- 41 | mcq 42 | language: |- 43 | python 44 | description: |- 45 | What will be the output of the statement 46 |
47 | print(1+2) 48 | points: 1.0 49 | testcase: 50 | - test_case_type: |- 51 | integertestcase 52 | correct: '3' 53 | active: true 54 | topic: 'Dummy2' 55 | content_type: 2 56 | time: '00:05:00' 57 | --- 58 | name: 'Sample lesson topic 1' 59 | description: 'Topic 1 description' 60 | content_type: 1 61 | time: '00:00:00' 62 | --- 63 | name: 'Sample lesson topic 2' 64 | description: 'Topic 2 description' 65 | content_type: 1 66 | time: '00:01:00' 67 | -------------------------------------------------------------------------------- /yaksh/fixtures/sample_user_upload.csv: -------------------------------------------------------------------------------- 1 | firstname,lastname,email,username,password,institute,department,roll_no,remove 2 | sample,user,sampleuser@xyz.com,sample_user,sample,sample,sample,sample123,False 3 | -------------------------------------------------------------------------------- /yaksh/fixtures/user_existing_email.csv: -------------------------------------------------------------------------------- 1 | firstname, lastname, email 2 | abc, abc, demo_student@test.com 3 | -------------------------------------------------------------------------------- /yaksh/fixtures/users_add_update_reject.csv: -------------------------------------------------------------------------------- 1 | firstname, lastname, email, institute,department,roll_no,remove,password,username 2 | test, test, test@g.com, TEST, TEST, TEST101, FALSE, TEST, test 3 | test2, test, test2@g.com, TEST, TEST, TEST101, FALSE, TEST, test2 4 | test2, test, test2@g.com, TEST, TEST, TEST101, TRUE, TEST, test2 5 | -------------------------------------------------------------------------------- /yaksh/fixtures/users_correct.csv: -------------------------------------------------------------------------------- 1 | firstname, lastname, email 2 | abc, abc, abc@xyz.com 3 | -------------------------------------------------------------------------------- /yaksh/fixtures/users_some_headers_missing.csv: -------------------------------------------------------------------------------- 1 | noname, lastname, email 2 | abc, abc, abc@xyz.com 3 | -------------------------------------------------------------------------------- /yaksh/fixtures/users_some_values_missing.csv: -------------------------------------------------------------------------------- 1 | firstname, lastname, email 2 | abc, , abc@xyz.com 3 | dummy, dummy , dummy@xyz.com 4 | dummy, dummy , dummy@xyz.com 5 | -------------------------------------------------------------------------------- /yaksh/fixtures/users_with_no_values.csv: -------------------------------------------------------------------------------- 1 | firstname, lastname, email 2 | -------------------------------------------------------------------------------- /yaksh/language_registry.py: -------------------------------------------------------------------------------- 1 | from __future__ import unicode_literals 2 | import importlib 3 | 4 | # Local imports 5 | from .settings import code_evaluators 6 | 7 | registry = None 8 | 9 | 10 | def get_registry(): 11 | global registry 12 | if registry is None: 13 | registry = _LanguageRegistry() 14 | return registry 15 | 16 | 17 | def create_evaluator_instance(metadata, test_case): 18 | """Create instance of relevant EvaluateCode class based on language""" 19 | registry = get_registry() 20 | cls = registry.get_class(metadata.get('language'), 21 | test_case.get('test_case_type')) 22 | instance = cls(metadata, test_case) 23 | return instance 24 | 25 | 26 | class _LanguageRegistry(object): 27 | def __init__(self): 28 | self._register = {} 29 | for language, module in code_evaluators.items(): 30 | self._register[language] = None 31 | 32 | # Public Protocol ########## 33 | def get_class(self, language, test_case_type): 34 | """ Get the code evaluator class for the given language """ 35 | if not self._register.get(language): 36 | self._register[language] = code_evaluators.get(language) 37 | test_case_register = self._register[language] 38 | cls = test_case_register.get(test_case_type) 39 | module_name, class_name = cls.rsplit(".", 1) 40 | # load the module, will raise ImportError if module cannot be loaded 41 | get_module = importlib.import_module(module_name) 42 | # get the class, will raise AttributeError if class cannot be found 43 | get_class = getattr(get_module, class_name) 44 | return get_class 45 | 46 | def register(self, language, class_names): 47 | """ Register a new code evaluator class for language""" 48 | self._register[language] = class_names 49 | -------------------------------------------------------------------------------- /yaksh/live_server_tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FOSSEE/online_test/9ea045b637f2087c1f1cdf8855d2d42b5f74a875/yaksh/live_server_tests/__init__.py -------------------------------------------------------------------------------- /yaksh/management/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FOSSEE/online_test/9ea045b637f2087c1f1cdf8855d2d42b5f74a875/yaksh/management/__init__.py -------------------------------------------------------------------------------- /yaksh/management/commands/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FOSSEE/online_test/9ea045b637f2087c1f1cdf8855d2d42b5f74a875/yaksh/management/commands/__init__.py -------------------------------------------------------------------------------- /yaksh/management/commands/create_moderator.py: -------------------------------------------------------------------------------- 1 | ''' 2 | This command creates a moderator group and adds users to the moderator group 3 | with permissions to add, change and delete 4 | the objects in the exam app. 5 | ''' 6 | 7 | # django imports 8 | from django.core.management.base import BaseCommand, CommandError 9 | from django.contrib.auth.models import User, Group, Permission 10 | 11 | # local imports 12 | from yaksh.models import create_group 13 | from yaksh.views import _create_or_update_profile 14 | 15 | 16 | class Command(BaseCommand): 17 | help = 'Adds users to the moderator group' 18 | 19 | def add_arguments(self, parser): 20 | # Positional arguments 21 | parser.add_argument('usernames', nargs='*', type=str) 22 | 23 | def handle(self, *args, **options): 24 | app_label = 'yaksh' 25 | group_name = 'moderator' 26 | group = create_group(group_name, app_label) 27 | if group and isinstance(group, Group): 28 | self.stdout.write(self.style.SUCCESS( 29 | 'Moderator group added successfully')) 30 | 31 | if options['usernames']: 32 | for uname in options['usernames']: 33 | try: 34 | user = User.objects.get(username=uname) 35 | except User.DoesNotExist: 36 | raise CommandError( 37 | 'User "{0}" does not exist'.format(uname) 38 | ) 39 | if user in group.user_set.all(): 40 | self.stdout.write( 41 | self.style.WARNING( 42 | 'User "{0}" is already' 43 | ' a Moderator'.format(uname) 44 | ) 45 | ) 46 | else: 47 | if not hasattr(user, 'profile'): 48 | _create_or_update_profile(user, 49 | {'is_email_verified': True} 50 | ) 51 | user.profile.is_moderator = True 52 | user.profile.save() 53 | self.stdout.write( 54 | self.style.SUCCESS( 55 | 'Successfully added User "{0}"' 56 | ' to Moderator group'.format(uname) 57 | ) 58 | ) 59 | -------------------------------------------------------------------------------- /yaksh/middleware/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FOSSEE/online_test/9ea045b637f2087c1f1cdf8855d2d42b5f74a875/yaksh/middleware/__init__.py -------------------------------------------------------------------------------- /yaksh/middleware/get_notifications.py: -------------------------------------------------------------------------------- 1 | from notifications_plugin.models import Notification 2 | 3 | class NotificationMiddleware(object): 4 | """ Middleware to get user's notifications """ 5 | def __init__(self, get_response): 6 | self.get_response = get_response 7 | 8 | def __call__(self, request): 9 | # Code to be executed for each request before 10 | # the view (and later middleware) are called. 11 | user = request.user 12 | if user.is_authenticated: 13 | notifications = Notification.objects.get_unread_receiver_notifications( 14 | user.id 15 | ).count() 16 | request.custom_notifications = notifications 17 | response = self.get_response(request) 18 | 19 | # Code to be executed for each request/response after 20 | # the view is called. 21 | return response 22 | -------------------------------------------------------------------------------- /yaksh/middleware/one_session_per_user.py: -------------------------------------------------------------------------------- 1 | from django.contrib.auth.models import User 2 | from django.contrib.sessions.models import Session 3 | 4 | from yaksh.models import ConcurrentUser 5 | 6 | 7 | class OneSessionPerUserMiddleware(object): 8 | """ 9 | Middleware to handle multiple logins with same credentials 10 | - Creates a Database entry to record the current user and active 11 | session key 12 | - Checks if the current user has already been logged in. If True, the 13 | new session key is stored with respect to the user and the old 14 | session key is deleted, 15 | effectively terminating the older session for the same user. 16 | - The concurrentuser attribute of the User model refers to the 17 | ConcurrentUser 18 | model object and not the concurrent_user field due to behaviour 19 | described in the Documentation 20 | Link: https://docs.djangoproject.com/en/1.5/topics/auth/customizing/ 21 | #extending-the-existing-user-model 22 | """ 23 | 24 | def __init__(self, get_response): 25 | self.get_response = get_response 26 | 27 | def __call__(self, request): 28 | # Code to be executed for each request before 29 | # the view (and later middleware) are called. 30 | if isinstance(request.user, User): 31 | current_key = request.session.session_key 32 | if hasattr(request.user, 'concurrentuser'): 33 | active_key = request.user.concurrentuser.session_key 34 | if active_key != current_key: 35 | Session.objects.filter(session_key=active_key).delete() 36 | request.user.concurrentuser.session_key = current_key 37 | request.user.concurrentuser.save() 38 | else: 39 | ConcurrentUser.objects.create( 40 | concurrent_user=request.user, 41 | session_key=current_key, 42 | ) 43 | 44 | response = self.get_response(request) 45 | # Code to be executed for each request/response after 46 | # the view is called. 47 | return response 48 | -------------------------------------------------------------------------------- /yaksh/middleware/user_time_zone.py: -------------------------------------------------------------------------------- 1 | import pytz 2 | 3 | from django.utils import timezone 4 | 5 | 6 | class TimezoneMiddleware(object): 7 | """ Middleware to get user's timezone and activate timezone 8 | if user timezone is not available default value 'Asia/Kolkata' 9 | is activated 10 | """ 11 | def __init__(self, get_response): 12 | self.get_response = get_response 13 | 14 | def __call__(self, request): 15 | # Code to be executed for each request before 16 | # the view (and later middleware) are called. 17 | user = request.user 18 | user_tz = 'Asia/Kolkata' 19 | if hasattr(user, 'profile'): 20 | if user.profile.timezone: 21 | user_tz = user.profile.timezone 22 | timezone.activate(pytz.timezone(user_tz)) 23 | 24 | response = self.get_response(request) 25 | 26 | # Code to be executed for each request/response after 27 | # the view is called. 28 | return response 29 | -------------------------------------------------------------------------------- /yaksh/migrations/0002_questionpaper_fixed_question_order.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.9.5 on 2017-03-20 13:32 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('yaksh', '0001_initial'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AddField( 16 | model_name='questionpaper', 17 | name='fixed_question_order', 18 | field=models.CharField(blank=True, max_length=255), 19 | ), 20 | ] 21 | -------------------------------------------------------------------------------- /yaksh/migrations/0004_auto_20170331_0632.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.9.5 on 2017-03-31 06:32 3 | from __future__ import unicode_literals 4 | 5 | import datetime 6 | from django.db import migrations, models 7 | import django.utils.timezone 8 | from django.utils.timezone import utc 9 | 10 | 11 | class Migration(migrations.Migration): 12 | 13 | dependencies = [ 14 | ('yaksh', '0003_auto_20170321_0917'), 15 | ] 16 | 17 | operations = [ 18 | migrations.AddField( 19 | model_name='course', 20 | name='end_enroll_time', 21 | field=models.DateTimeField(default=datetime.datetime(2199, 1, 1, 0, 0, tzinfo=utc), null=True, verbose_name='End Date and Time for enrollment of course'), 22 | ), 23 | migrations.AddField( 24 | model_name='course', 25 | name='start_enroll_time', 26 | field=models.DateTimeField(default=django.utils.timezone.now, null=True, verbose_name='Start Date and Time for enrollment of course'), 27 | ), 28 | ] 29 | -------------------------------------------------------------------------------- /yaksh/migrations/0005_auto_20170410_1024.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.9.5 on 2017-04-10 10:24 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | import django.db.models.deletion 7 | 8 | 9 | class Migration(migrations.Migration): 10 | 11 | dependencies = [ 12 | ('yaksh', '0004_auto_20170331_0632'), 13 | ] 14 | 15 | operations = [ 16 | migrations.AddField( 17 | model_name='assignmentupload', 18 | name='question_paper', 19 | field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='yaksh.QuestionPaper'), 20 | ), 21 | migrations.AlterField( 22 | model_name='hooktestcase', 23 | name='hook_code', 24 | field=models.TextField(default='def check_answer(user_answer):\n \'\'\' Evaluates user answer to return -\n success - Boolean, indicating if code was executed correctly\n mark_fraction - Float, indicating fraction of the\n weight to a test case\n error - String, error message if success is false\n\n In case of assignment upload there will be no user answer \'\'\'\n\n success = False\n err = "Incorrect Answer" # Please make this more specific\n mark_fraction = 0.0\n\n # write your code here\n\n return success, err, mark_fraction\n\n'), 25 | ), 26 | ] 27 | -------------------------------------------------------------------------------- /yaksh/migrations/0006_release_0_6_0.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.9.5 on 2017-05-11 09:59 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('yaksh', '0005_auto_20170410_1024'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AddField( 16 | model_name='course', 17 | name='code', 18 | field=models.CharField(blank=True, max_length=128, null=True), 19 | ), 20 | migrations.AddField( 21 | model_name='course', 22 | name='hidden', 23 | field=models.BooleanField(default=False), 24 | ), 25 | migrations.AddField( 26 | model_name='profile', 27 | name='activation_key', 28 | field=models.CharField(blank=True, max_length=40, null=True), 29 | ), 30 | migrations.AddField( 31 | model_name='profile', 32 | name='is_email_verified', 33 | field=models.BooleanField(default=False), 34 | ), 35 | migrations.AddField( 36 | model_name='profile', 37 | name='key_expiry_time', 38 | field=models.DateTimeField(blank=True, null=True), 39 | ), 40 | migrations.AlterField( 41 | model_name='course', 42 | name='enrollment', 43 | field=models.CharField(choices=[('default', 'Enroll Request'), ('open', 'Open Enrollment')], max_length=32), 44 | ), 45 | ] 46 | -------------------------------------------------------------------------------- /yaksh/migrations/0007_alter_profile_activation_key.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.9.5 on 2017-05-16 12:31 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('yaksh', '0006_release_0_6_0'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AlterField( 16 | model_name='profile', 17 | name='activation_key', 18 | field=models.CharField(blank=True, max_length=255, null=True), 19 | ), 20 | ] 21 | -------------------------------------------------------------------------------- /yaksh/migrations/0008_release_0_7_0.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.9.5 on 2017-11-14 14:29 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('yaksh', '0007_alter_profile_activation_key'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AddField( 16 | model_name='answerpaper', 17 | name='questions_order', 18 | field=models.TextField(blank=True, default=''), 19 | ), 20 | migrations.AlterField( 21 | model_name='question', 22 | name='snippet', 23 | field=models.TextField(blank=True), 24 | ), 25 | ] 26 | -------------------------------------------------------------------------------- /yaksh/migrations/0010_auto_20180226_1324.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.9.5 on 2018-02-26 13:24 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('yaksh', '0009_auto_20180113_1124'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AddField( 16 | model_name='learningmodule', 17 | name='active', 18 | field=models.BooleanField(default=True), 19 | ), 20 | migrations.AddField( 21 | model_name='lesson', 22 | name='active', 23 | field=models.BooleanField(default=True), 24 | ), 25 | migrations.AlterField( 26 | model_name='quiz', 27 | name='time_between_attempts', 28 | field=models.FloatField(verbose_name='Time Between Quiz Attempts in hours'), 29 | ), 30 | migrations.AlterUniqueTogether( 31 | name='answerpaper', 32 | unique_together=set([('user', 'question_paper', 'attempt_number', 'course')]), 33 | ), 34 | ] 35 | -------------------------------------------------------------------------------- /yaksh/migrations/0012_release_0_8_1.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.10 on 2018-06-18 06:13 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('yaksh', '0011_release_0_8_0'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AddField( 16 | model_name='coursestatus', 17 | name='percent_completed', 18 | field=models.IntegerField(default=0), 19 | ), 20 | migrations.AlterField( 21 | model_name='quiz', 22 | name='time_between_attempts', 23 | field=models.FloatField(default=0.0, verbose_name='Time Between Quiz Attempts in hours'), 24 | ), 25 | ] 26 | -------------------------------------------------------------------------------- /yaksh/migrations/0013_release_0_9_0.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.10 on 2018-07-13 14:16 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | import yaksh.models 7 | 8 | def set_is_moderator(apps, schema_editor): 9 | """ Set is_moderator to True for all users that belong 10 | to Moderator group """ 11 | 12 | Profile = apps.get_model('yaksh', 'Profile') 13 | for prof in Profile.objects.all(): 14 | user = prof.user 15 | if user.groups.filter(name='moderator').exists(): 16 | prof.is_moderator = True 17 | prof.save() 18 | 19 | class Migration(migrations.Migration): 20 | 21 | dependencies = [ 22 | ('yaksh', '0012_release_0_8_1'), 23 | ] 24 | 25 | operations = [ 26 | migrations.AddField( 27 | model_name='lesson', 28 | name='video_file', 29 | field=models.FileField(blank=True, default=None, help_text='Please upload video files in mp4, ogv, webm format', null=True, upload_to=yaksh.models.get_file_dir), 30 | ), 31 | migrations.AddField( 32 | model_name='profile', 33 | name='is_moderator', 34 | field=models.BooleanField(default=False), 35 | ), 36 | migrations.AlterField( 37 | model_name='lessonfile', 38 | name='file', 39 | field=models.FileField(default=None, upload_to=yaksh.models.get_file_dir), 40 | ), 41 | migrations.RunPython(set_is_moderator), 42 | ] 43 | -------------------------------------------------------------------------------- /yaksh/migrations/0014_release_0_9_1.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.10 on 2019-02-07 10:41 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | import django.db.models.deletion 7 | 8 | 9 | class Migration(migrations.Migration): 10 | 11 | dependencies = [ 12 | ('yaksh', '0013_release_0_9_0'), 13 | ] 14 | 15 | operations = [ 16 | migrations.AddField( 17 | model_name='assignmentupload', 18 | name='course', 19 | field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='yaksh.Course'), 20 | ), 21 | ] 22 | -------------------------------------------------------------------------------- /yaksh/migrations/0015_release_0_10_0.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.10 on 2019-04-24 10:41 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('yaksh', '0014_release_0_9_1'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AddField( 16 | model_name='course', 17 | name='view_grade', 18 | field=models.BooleanField(default=False), 19 | ), 20 | migrations.AddField( 21 | model_name='learningmodule', 22 | name='check_prerequisite_passes', 23 | field=models.BooleanField(default=False), 24 | ), 25 | ] 26 | -------------------------------------------------------------------------------- /yaksh/migrations/0016_release_0_12_0.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.11.21 on 2020-02-05 05:38 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('yaksh', '0015_release_0_10_0'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AlterField( 16 | model_name='question', 17 | name='language', 18 | field=models.CharField(choices=[('python', 'Python'), ('bash', 'Bash'), ('c', 'C Language'), ('cpp', 'C++ Language'), ('java', 'Java Language'), ('scilab', 'Scilab'), ('r', 'R')], max_length=24), 19 | ), 20 | ] 21 | -------------------------------------------------------------------------------- /yaksh/migrations/0018_auto_20200408_1206.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 3.0.3 on 2020-04-08 06:36 2 | 3 | import datetime 4 | from django.db import migrations, models 5 | from django.utils.timezone import utc 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('yaksh', '0017_release_0_14_0'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AlterField( 16 | model_name='course', 17 | name='end_enroll_time', 18 | field=models.DateTimeField(default=datetime.datetime(2198, 12, 31, 18, 7, tzinfo=utc), null=True, verbose_name='End Date and Time for enrollment of course'), 19 | ), 20 | migrations.AlterField( 21 | model_name='quiz', 22 | name='end_date_time', 23 | field=models.DateTimeField(default=datetime.datetime(2198, 12, 31, 18, 7, tzinfo=utc), null=True, verbose_name='End Date and Time of the quiz'), 24 | ), 25 | ] 26 | -------------------------------------------------------------------------------- /yaksh/migrations/0020_release_0_21_0.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 3.0.3 on 2020-07-02 08:13 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('yaksh', '0019_release_0_20_0'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AddField( 14 | model_name='hooktestcase', 15 | name='hidden', 16 | field=models.BooleanField(default=False), 17 | ), 18 | migrations.AddField( 19 | model_name='standardtestcase', 20 | name='hidden', 21 | field=models.BooleanField(default=False), 22 | ), 23 | migrations.AddField( 24 | model_name='stdiobasedtestcase', 25 | name='hidden', 26 | field=models.BooleanField(default=False), 27 | ), 28 | ] 29 | -------------------------------------------------------------------------------- /yaksh/migrations/0021_auto_20200703_1556.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 3.0.7 on 2020-07-03 10:26 2 | 3 | import datetime 4 | from django.db import migrations, models 5 | from django.utils.timezone import utc 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('yaksh', '0020_release_0_21_0'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AlterField( 16 | model_name='course', 17 | name='end_enroll_time', 18 | field=models.DateTimeField(default=datetime.datetime(2198, 12, 31, 18, 7, tzinfo=utc), null=True, verbose_name='End Date and Time for enrollment of course'), 19 | ), 20 | migrations.AlterField( 21 | model_name='quiz', 22 | name='end_date_time', 23 | field=models.DateTimeField(default=datetime.datetime(2198, 12, 31, 18, 7, tzinfo=utc), null=True, verbose_name='End Date and Time of the quiz'), 24 | ), 25 | ] 26 | -------------------------------------------------------------------------------- /yaksh/migrations/0022_release_0_22_1.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 3.0.7 on 2020-08-28 07:17 2 | 3 | import datetime 4 | from django.db import migrations, models 5 | from django.utils.timezone import utc 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('yaksh', '0021_auto_20200703_1556'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AlterField( 16 | model_name='course', 17 | name='end_enroll_time', 18 | field=models.DateTimeField(default=datetime.datetime(2199, 1, 1, 0, 0, tzinfo=utc), null=True, verbose_name='End Date and Time for enrollment of course'), 19 | ), 20 | migrations.AlterField( 21 | model_name='questionpaper', 22 | name='fixed_question_order', 23 | field=models.TextField(blank=True), 24 | ), 25 | migrations.AlterField( 26 | model_name='quiz', 27 | name='end_date_time', 28 | field=models.DateTimeField(default=datetime.datetime(2199, 1, 1, 0, 0, tzinfo=utc), null=True, verbose_name='End Date and Time of the quiz'), 29 | ), 30 | ] 31 | -------------------------------------------------------------------------------- /yaksh/migrations/0023_release_0_23_0.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 3.0.7 on 2020-09-09 02:25 2 | 3 | from django.conf import settings 4 | from django.db import migrations, models 5 | import django.db.models.deletion 6 | import django.utils.timezone 7 | 8 | 9 | class Migration(migrations.Migration): 10 | 11 | dependencies = [ 12 | migrations.swappable_dependency(settings.AUTH_USER_MODEL), 13 | ('yaksh', '0022_release_0_22_1'), 14 | ] 15 | 16 | operations = [ 17 | migrations.AddField( 18 | model_name='answerpaper', 19 | name='extra_time', 20 | field=models.FloatField(default=0.0, verbose_name='Additional time in mins'), 21 | ), 22 | migrations.AddField( 23 | model_name='answerpaper', 24 | name='is_special', 25 | field=models.BooleanField(default=False), 26 | ), 27 | migrations.CreateModel( 28 | name='MicroManager', 29 | fields=[ 30 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 31 | ('special_attempt', models.BooleanField(default=False)), 32 | ('attempts_permitted', models.IntegerField(default=0)), 33 | ('permitted_time', models.DateTimeField(default=django.utils.timezone.now)), 34 | ('attempts_utilised', models.IntegerField(default=0)), 35 | ('wait_time', models.IntegerField(default=0, verbose_name='Days to wait before special attempt')), 36 | ('attempt_valid_for', models.IntegerField(default=90, verbose_name='Validity days')), 37 | ('course', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='yaksh.Course')), 38 | ('manager', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='micromanaging', to=settings.AUTH_USER_MODEL)), 39 | ('quiz', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='yaksh.Quiz')), 40 | ('student', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='micromanaged', to=settings.AUTH_USER_MODEL)), 41 | ], 42 | options={ 43 | 'unique_together': {('student', 'course', 'quiz')}, 44 | }, 45 | ), 46 | ] 47 | -------------------------------------------------------------------------------- /yaksh/migrations/0024_release_0_24_0.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 3.0.7 on 2020-09-14 10:45 2 | 3 | from django.db import migrations, models 4 | import yaksh.models 5 | 6 | 7 | class Migration(migrations.Migration): 8 | 9 | dependencies = [ 10 | ('yaksh', '0023_release_0_23_0'), 11 | ] 12 | 13 | operations = [ 14 | migrations.AlterField( 15 | model_name='assignmentupload', 16 | name='assignmentFile', 17 | field=models.FileField(max_length=255, upload_to=yaksh.models.get_assignment_dir), 18 | ), 19 | ] 20 | -------------------------------------------------------------------------------- /yaksh/migrations/0026_release_0_27_0.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 3.0.7 on 2020-10-08 11:21 2 | 3 | from django.db import migrations, models 4 | import django.db.models.deletion 5 | 6 | 7 | class Migration(migrations.Migration): 8 | 9 | dependencies = [ 10 | ('contenttypes', '0002_remove_content_type_name'), 11 | ('yaksh', '0025_release_0_26'), 12 | ] 13 | 14 | operations = [ 15 | migrations.RemoveField( 16 | model_name='post', 17 | name='course', 18 | ), 19 | migrations.AddField( 20 | model_name='forumbase', 21 | name='anonymous', 22 | field=models.BooleanField(default=False), 23 | ), 24 | migrations.AddField( 25 | model_name='post', 26 | name='target_ct', 27 | field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='target_obj', to='contenttypes.ContentType'), 28 | ), 29 | migrations.AddField( 30 | model_name='post', 31 | name='target_id', 32 | field=models.PositiveIntegerField(blank=True, db_index=True, null=True), 33 | ), 34 | ] 35 | -------------------------------------------------------------------------------- /yaksh/migrations/0027_release_0_28_0.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 3.0.7 on 2020-11-04 13:40 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('yaksh', '0026_release_0_27_0'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AddField( 14 | model_name='answer', 15 | name='comment', 16 | field=models.TextField(blank=True, null=True), 17 | ), 18 | ] 19 | -------------------------------------------------------------------------------- /yaksh/migrations/0028_auto_20210112_1039.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 3.0.7 on 2021-01-12 05:09 2 | 3 | import datetime 4 | from django.db import migrations, models 5 | from django.utils.timezone import utc 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('yaksh', '0027_release_0_28_0'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AlterField( 16 | model_name='course', 17 | name='end_enroll_time', 18 | field=models.DateTimeField(default=datetime.datetime(2198, 12, 31, 18, 7, tzinfo=utc), null=True, verbose_name='End Date and Time for enrollment of course'), 19 | ), 20 | migrations.AlterField( 21 | model_name='quiz', 22 | name='end_date_time', 23 | field=models.DateTimeField(default=datetime.datetime(2198, 12, 31, 18, 7, tzinfo=utc), null=True, verbose_name='End Date and Time of the quiz'), 24 | ), 25 | ] 26 | -------------------------------------------------------------------------------- /yaksh/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FOSSEE/online_test/9ea045b637f2087c1f1cdf8855d2d42b5f74a875/yaksh/migrations/__init__.py -------------------------------------------------------------------------------- /yaksh/pipeline/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FOSSEE/online_test/9ea045b637f2087c1f1cdf8855d2d42b5f74a875/yaksh/pipeline/__init__.py -------------------------------------------------------------------------------- /yaksh/pipeline/settings.py: -------------------------------------------------------------------------------- 1 | AUTH_PIPELINE = ( 2 | # Get the information we can about the user and return it in a simple 3 | # format to create the user instance later. On some cases the details are 4 | # already part of the auth response from the provider, but sometimes this 5 | # could hit a provider API. 6 | 'social.pipeline.social_auth.social_details', 7 | 8 | # Get the social uid from whichever service we're authing thru. The uid is 9 | # the unique identifier of the given user in the provider. 10 | 'social.pipeline.social_auth.social_uid', 11 | 12 | # Verifies that the current auth process is valid within the current 13 | # project, this is where emails and domains whitelists are applied (if 14 | # defined). 15 | 'social.pipeline.social_auth.auth_allowed', 16 | 17 | # Checks if the current social-account is already associated in the site. 18 | 'social.pipeline.social_auth.social_user', 19 | 20 | # Make up a username for this person, appends a random string at the end if 21 | # there's any collision. 22 | 'social.pipeline.user.get_username', 23 | 24 | # Send a validation email to the user to verify its email address. 25 | # Disabled by default. 26 | # 'social.pipeline.mail.mail_validation', 27 | 28 | # Associates the current social details with another user account with 29 | # a similar email address. Disabled by default. 30 | 'social.pipeline.social_auth.associate_by_email', 31 | 32 | # Create a user account if we haven't found one yet. 33 | 'social.pipeline.user.create_user', 34 | 35 | # Create a profile if profile does not exist 36 | 'yaksh.pipeline.user.save_profile', 37 | 38 | # Create the record that associated the social account with this user. 39 | 'social.pipeline.social_auth.associate_user', 40 | 41 | # Populate the extra_data field in the social record with the values 42 | # specified by settings (and the default ones like access_token, etc). 43 | 'social.pipeline.social_auth.load_extra_data', 44 | 45 | # Update the user record with any changed info from the auth service. 46 | 'social.pipeline.user.user_details', 47 | ) 48 | -------------------------------------------------------------------------------- /yaksh/pipeline/user.py: -------------------------------------------------------------------------------- 1 | from yaksh.models import Profile 2 | 3 | 4 | def save_profile(backend, user, response, *args, **kwargs): 5 | if not hasattr(user, 'profile'): 6 | profile = Profile.objects.create(user=user) 7 | profile.roll_number = profile.id 8 | else: 9 | profile = Profile.objects.get(user=user) 10 | profile.is_email_verified = True 11 | profile.save() 12 | -------------------------------------------------------------------------------- /yaksh/scripts/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FOSSEE/online_test/9ea045b637f2087c1f1cdf8855d2d42b5f74a875/yaksh/scripts/__init__.py -------------------------------------------------------------------------------- /yaksh/scripts/yaksh_script.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Basic script to install pip packages and run the yaksh code server command 3 | 4 | chown -R nobody output 5 | chmod -R a+rwX output 6 | chmod -R a+rX data yaksh 7 | chmod -R o-w data yaksh 8 | echo "** [CONTAINER] Installing python dependencies **" 9 | pip3 install -r ./requirements-codeserver.txt 10 | echo "** [CONTAINER] Running code server **" 11 | touch server_running.txt 12 | /usr/bin/sudo -su nobody python3 -m yaksh.code_server 13 | -------------------------------------------------------------------------------- /yaksh/static/yaksh/css/autotaggit.css: -------------------------------------------------------------------------------- 1 | .ac_results { 2 | padding: 0px; 3 | border: 1px solid #efefef; 4 | background-color: white; 5 | overflow: hidden; 6 | z-index: 99999; 7 | } 8 | 9 | .ac_results ul { 10 | width: 100%; 11 | list-style-position: outside; 12 | list-style: none; 13 | padding: 0; 14 | margin: 0; 15 | } 16 | 17 | .ac_results li { 18 | margin: 0px; 19 | padding: 2px 5px; 20 | cursor: default; 21 | display: block; 22 | /* 23 | if width will be 100% horizontal scrollbar will apear 24 | when scroll mode will be used 25 | */ 26 | /*width: 100%;*/ 27 | font: menu; 28 | font-size: 12px; 29 | /* 30 | it is very important, if line-height not setted or setted 31 | in relative units scroll will be broken in firefox 32 | */ 33 | line-height: 16px; 34 | overflow: hidden; 35 | } 36 | 37 | .ac_loading { 38 | background: white url('indicator.gif') right center no-repeat; 39 | } 40 | 41 | .ac_odd { 42 | background-color: #CACACA; 43 | } 44 | 45 | .ac_over { 46 | background-color: #f5f5f5; 47 | color: black; 48 | } 49 | -------------------------------------------------------------------------------- /yaksh/static/yaksh/css/design_course.css: -------------------------------------------------------------------------------- 1 | #available-lesson-quiz .col-md-12 > div{ 2 | background: #f5f5f5; 3 | border: 1px solid #333333; 4 | overflow-y: scroll; 5 | height: 400px; 6 | } -------------------------------------------------------------------------------- /yaksh/static/yaksh/css/exam.css: -------------------------------------------------------------------------------- 1 | #assertion td, #assertion th, #stdio td, #stdio th { border: #ff8295 solid 1px !important; 2 | word-wrap: break-word !important; 3 | white-space: pre-wrap !important; 4 | } 5 | #stdio, #assertion { 6 | table-layout: fixed 7 | } 8 | .legend_table{ 9 | border: 1px solid; 10 | width: 15em; 11 | background-color: white; 12 | border-spacing: 5px; 13 | border-collapse: collapse; 14 | } 15 | -------------------------------------------------------------------------------- /yaksh/static/yaksh/css/jquery-ui/images/ui-bg_flat_0_aaaaaa_40x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FOSSEE/online_test/9ea045b637f2087c1f1cdf8855d2d42b5f74a875/yaksh/static/yaksh/css/jquery-ui/images/ui-bg_flat_0_aaaaaa_40x100.png -------------------------------------------------------------------------------- /yaksh/static/yaksh/css/jquery-ui/images/ui-bg_flat_75_ffffff_40x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FOSSEE/online_test/9ea045b637f2087c1f1cdf8855d2d42b5f74a875/yaksh/static/yaksh/css/jquery-ui/images/ui-bg_flat_75_ffffff_40x100.png -------------------------------------------------------------------------------- /yaksh/static/yaksh/css/jquery-ui/images/ui-bg_glass_55_fbf9ee_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FOSSEE/online_test/9ea045b637f2087c1f1cdf8855d2d42b5f74a875/yaksh/static/yaksh/css/jquery-ui/images/ui-bg_glass_55_fbf9ee_1x400.png -------------------------------------------------------------------------------- /yaksh/static/yaksh/css/jquery-ui/images/ui-bg_glass_65_ffffff_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FOSSEE/online_test/9ea045b637f2087c1f1cdf8855d2d42b5f74a875/yaksh/static/yaksh/css/jquery-ui/images/ui-bg_glass_65_ffffff_1x400.png -------------------------------------------------------------------------------- /yaksh/static/yaksh/css/jquery-ui/images/ui-bg_glass_75_dadada_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FOSSEE/online_test/9ea045b637f2087c1f1cdf8855d2d42b5f74a875/yaksh/static/yaksh/css/jquery-ui/images/ui-bg_glass_75_dadada_1x400.png -------------------------------------------------------------------------------- /yaksh/static/yaksh/css/jquery-ui/images/ui-bg_glass_75_e6e6e6_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FOSSEE/online_test/9ea045b637f2087c1f1cdf8855d2d42b5f74a875/yaksh/static/yaksh/css/jquery-ui/images/ui-bg_glass_75_e6e6e6_1x400.png -------------------------------------------------------------------------------- /yaksh/static/yaksh/css/jquery-ui/images/ui-bg_glass_95_fef1ec_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FOSSEE/online_test/9ea045b637f2087c1f1cdf8855d2d42b5f74a875/yaksh/static/yaksh/css/jquery-ui/images/ui-bg_glass_95_fef1ec_1x400.png -------------------------------------------------------------------------------- /yaksh/static/yaksh/css/jquery-ui/images/ui-bg_highlight-soft_75_cccccc_1x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FOSSEE/online_test/9ea045b637f2087c1f1cdf8855d2d42b5f74a875/yaksh/static/yaksh/css/jquery-ui/images/ui-bg_highlight-soft_75_cccccc_1x100.png -------------------------------------------------------------------------------- /yaksh/static/yaksh/css/jquery-ui/images/ui-icons_222222_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FOSSEE/online_test/9ea045b637f2087c1f1cdf8855d2d42b5f74a875/yaksh/static/yaksh/css/jquery-ui/images/ui-icons_222222_256x240.png -------------------------------------------------------------------------------- /yaksh/static/yaksh/css/jquery-ui/images/ui-icons_2e83ff_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FOSSEE/online_test/9ea045b637f2087c1f1cdf8855d2d42b5f74a875/yaksh/static/yaksh/css/jquery-ui/images/ui-icons_2e83ff_256x240.png -------------------------------------------------------------------------------- /yaksh/static/yaksh/css/jquery-ui/images/ui-icons_444444_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FOSSEE/online_test/9ea045b637f2087c1f1cdf8855d2d42b5f74a875/yaksh/static/yaksh/css/jquery-ui/images/ui-icons_444444_256x240.png -------------------------------------------------------------------------------- /yaksh/static/yaksh/css/jquery-ui/images/ui-icons_454545_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FOSSEE/online_test/9ea045b637f2087c1f1cdf8855d2d42b5f74a875/yaksh/static/yaksh/css/jquery-ui/images/ui-icons_454545_256x240.png -------------------------------------------------------------------------------- /yaksh/static/yaksh/css/jquery-ui/images/ui-icons_555555_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FOSSEE/online_test/9ea045b637f2087c1f1cdf8855d2d42b5f74a875/yaksh/static/yaksh/css/jquery-ui/images/ui-icons_555555_256x240.png -------------------------------------------------------------------------------- /yaksh/static/yaksh/css/jquery-ui/images/ui-icons_777620_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FOSSEE/online_test/9ea045b637f2087c1f1cdf8855d2d42b5f74a875/yaksh/static/yaksh/css/jquery-ui/images/ui-icons_777620_256x240.png -------------------------------------------------------------------------------- /yaksh/static/yaksh/css/jquery-ui/images/ui-icons_777777_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FOSSEE/online_test/9ea045b637f2087c1f1cdf8855d2d42b5f74a875/yaksh/static/yaksh/css/jquery-ui/images/ui-icons_777777_256x240.png -------------------------------------------------------------------------------- /yaksh/static/yaksh/css/jquery-ui/images/ui-icons_888888_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FOSSEE/online_test/9ea045b637f2087c1f1cdf8855d2d42b5f74a875/yaksh/static/yaksh/css/jquery-ui/images/ui-icons_888888_256x240.png -------------------------------------------------------------------------------- /yaksh/static/yaksh/css/jquery-ui/images/ui-icons_cc0000_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FOSSEE/online_test/9ea045b637f2087c1f1cdf8855d2d42b5f74a875/yaksh/static/yaksh/css/jquery-ui/images/ui-icons_cc0000_256x240.png -------------------------------------------------------------------------------- /yaksh/static/yaksh/css/jquery-ui/images/ui-icons_cd0a0a_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FOSSEE/online_test/9ea045b637f2087c1f1cdf8855d2d42b5f74a875/yaksh/static/yaksh/css/jquery-ui/images/ui-icons_cd0a0a_256x240.png -------------------------------------------------------------------------------- /yaksh/static/yaksh/css/jquery-ui/images/ui-icons_ffffff_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FOSSEE/online_test/9ea045b637f2087c1f1cdf8855d2d42b5f74a875/yaksh/static/yaksh/css/jquery-ui/images/ui-icons_ffffff_256x240.png -------------------------------------------------------------------------------- /yaksh/static/yaksh/css/lesson.css: -------------------------------------------------------------------------------- 1 | .helptext{ 2 | font-weight: bold; 3 | color: #31708f; 4 | background-color: #d9edf7; 5 | border-color: #bce8f1; 6 | padding: 6px; 7 | margin-bottom: 20px; 8 | border: 1px solid transparent; 9 | border-radius: 4px; 10 | } -------------------------------------------------------------------------------- /yaksh/static/yaksh/css/offline.css: -------------------------------------------------------------------------------- 1 | #footer { 2 | position:fixed; 3 | bottom:0; 4 | width:100%; 5 | height:60px; /* Height of the footer */ 6 | background-color: #D3D3D3; 7 | color: black; 8 | text-align: center; 9 | } 10 | 11 | .module { 12 | border: none; 13 | border-spacing: 0; 14 | border-collapse: collapse; 15 | } 16 | .module tr td:nth-child(2) { 17 | border-left: 1px solid #D3D3D3; 18 | } 19 | 20 | /* 21 | * Sidebar 22 | */ 23 | 24 | .sidebar { 25 | position: fixed; 26 | top: 0; 27 | bottom: 0; 28 | left: 0; 29 | z-index: 100; /* Behind the navbar */ 30 | padding: 48px 0 0; /* Height of navbar */ 31 | box-shadow: inset -1px 0 0 rgba(0, 0, 0, .1); 32 | } 33 | 34 | .sidebar-sticky { 35 | position: relative; 36 | top: 0; 37 | height: calc(100vh - 48px); 38 | padding-top: .5rem; 39 | overflow-x: hidden; 40 | overflow-y: auto; /* Scrollable contents if viewport is shorter than content. */ 41 | } 42 | 43 | @supports ((position: -webkit-sticky) or (position: sticky)) { 44 | .sidebar-sticky { 45 | position: -webkit-sticky; 46 | position: sticky; 47 | } 48 | } 49 | 50 | .sidebar .nav-link { 51 | font-weight: 500; 52 | color: #333; 53 | } 54 | 55 | .sidebar .nav-link .feather { 56 | margin-right: 4px; 57 | color: #999; 58 | } 59 | 60 | .sidebar .nav-link.active { 61 | color: #007bff; 62 | } 63 | 64 | .sidebar .nav-link:hover .feather, 65 | .sidebar .nav-link.active .feather { 66 | color: inherit; 67 | } 68 | 69 | .sidebar-heading { 70 | font-size: .75rem; 71 | text-transform: uppercase; 72 | } 73 | 74 | section{ 75 | padding: 2rem; 76 | } 77 | 78 | .bg-grey{ 79 | background-color:#dbf9f2; 80 | } 81 | -------------------------------------------------------------------------------- /yaksh/static/yaksh/css/ontop.css: -------------------------------------------------------------------------------- 1 | #ontop { 2 | position: fixed; 3 | display: none; 4 | width: 100%; 5 | height: 100%; 6 | top:0; 7 | bottom: 0; 8 | left:0; 9 | right: 0; 10 | background-color: rgba(0,0,0,0.5); 11 | z-index: 1001; /* 1001 coz sidebar is 1000. So will be on top of sidebar*/ 12 | } 13 | 14 | #state { 15 | position: absolute; 16 | top: 30%; 17 | left: 40%; 18 | font-size: 30px; 19 | color: white; 20 | } 21 | 22 | -------------------------------------------------------------------------------- /yaksh/static/yaksh/css/question.css: -------------------------------------------------------------------------------- 1 | 2 | .time-div 3 | { 4 | background-color:#142624; 5 | color: #5DFC0A; 6 | vertical-align:middle; 7 | width: 160px; 8 | height: 50px; 9 | float:right; 10 | border-radius: 6px 6px 6px 6px; 11 | font-size:30px; 12 | } 13 | .td1-class 14 | { 15 | width:300px; 16 | } 17 | .td2-class 18 | { 19 | width:50px; 20 | padding: 5px 10px 9px; 21 | } 22 | #codeTextarea{ 23 | 24 | } 25 | .textAreaWithLines{ 26 | font-family:courier; 27 | border:1px solid #eee; 28 | 29 | } 30 | .textAreaWithLines textarea,.textAreaWithLines div{ 31 | border:0px; 32 | line-height:120%; 33 | font-size:12px; 34 | } 35 | .lineObj{ 36 | color: grey; 37 | } 38 | 39 | #string{ 40 | width: 60em; 41 | height: 10em; 42 | } 43 | -------------------------------------------------------------------------------- /yaksh/static/yaksh/fonts/FontAwesome.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FOSSEE/online_test/9ea045b637f2087c1f1cdf8855d2d42b5f74a875/yaksh/static/yaksh/fonts/FontAwesome.otf -------------------------------------------------------------------------------- /yaksh/static/yaksh/fonts/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FOSSEE/online_test/9ea045b637f2087c1f1cdf8855d2d42b5f74a875/yaksh/static/yaksh/fonts/fontawesome-webfont.eot -------------------------------------------------------------------------------- /yaksh/static/yaksh/fonts/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FOSSEE/online_test/9ea045b637f2087c1f1cdf8855d2d42b5f74a875/yaksh/static/yaksh/fonts/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /yaksh/static/yaksh/fonts/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FOSSEE/online_test/9ea045b637f2087c1f1cdf8855d2d42b5f74a875/yaksh/static/yaksh/fonts/fontawesome-webfont.woff -------------------------------------------------------------------------------- /yaksh/static/yaksh/fonts/fontawesome-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FOSSEE/online_test/9ea045b637f2087c1f1cdf8855d2d42b5f74a875/yaksh/static/yaksh/fonts/fontawesome-webfont.woff2 -------------------------------------------------------------------------------- /yaksh/static/yaksh/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FOSSEE/online_test/9ea045b637f2087c1f1cdf8855d2d42b5f74a875/yaksh/static/yaksh/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /yaksh/static/yaksh/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FOSSEE/online_test/9ea045b637f2087c1f1cdf8855d2d42b5f74a875/yaksh/static/yaksh/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /yaksh/static/yaksh/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FOSSEE/online_test/9ea045b637f2087c1f1cdf8855d2d42b5f74a875/yaksh/static/yaksh/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /yaksh/static/yaksh/images/check_answer.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FOSSEE/online_test/9ea045b637f2087c1f1cdf8855d2d42b5f74a875/yaksh/static/yaksh/images/check_answer.gif -------------------------------------------------------------------------------- /yaksh/static/yaksh/images/fosseelogo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FOSSEE/online_test/9ea045b637f2087c1f1cdf8855d2d42b5f74a875/yaksh/static/yaksh/images/fosseelogo.jpg -------------------------------------------------------------------------------- /yaksh/static/yaksh/images/profile_change.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FOSSEE/online_test/9ea045b637f2087c1f1cdf8855d2d42b5f74a875/yaksh/static/yaksh/images/profile_change.gif -------------------------------------------------------------------------------- /yaksh/static/yaksh/images/yaksh_banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FOSSEE/online_test/9ea045b637f2087c1f1cdf8855d2d42b5f74a875/yaksh/static/yaksh/images/yaksh_banner.png -------------------------------------------------------------------------------- /yaksh/static/yaksh/images/yaksh_circular_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FOSSEE/online_test/9ea045b637f2087c1f1cdf8855d2d42b5f74a875/yaksh/static/yaksh/images/yaksh_circular_logo.png -------------------------------------------------------------------------------- /yaksh/static/yaksh/images/yaksh_text.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FOSSEE/online_test/9ea045b637f2087c1f1cdf8855d2d42b5f74a875/yaksh/static/yaksh/images/yaksh_text.png -------------------------------------------------------------------------------- /yaksh/static/yaksh/js/add_course.js: -------------------------------------------------------------------------------- 1 | $(document).ready(function () { 2 | $(function() { 3 | tinymce.init({ 4 | selector: 'textarea#id_instructions', 5 | setup : function(ed) { 6 | ed.on('change', function(e) { 7 | tinymce.triggerSave(); 8 | }); 9 | }, 10 | max_height: 400, 11 | height: 400, 12 | plugins: "image code link", 13 | convert_urls: false 14 | }); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /yaksh/static/yaksh/js/add_grades.js: -------------------------------------------------------------------------------- 1 | $(function() { 2 | tinymce.init({ 3 | selector: 'textarea#id_description', 4 | setup : function(ed) { 5 | ed.on('change', function(e) { 6 | tinymce.triggerSave(); 7 | }); 8 | }, 9 | max_height: 400, 10 | height: 400, 11 | plugins: "image code link", 12 | convert_urls: false 13 | }); 14 | }); 15 | -------------------------------------------------------------------------------- /yaksh/static/yaksh/js/add_questionpaper.js: -------------------------------------------------------------------------------- 1 | function load_data() 2 | { 3 | var url_root = document.getElementById('url_root').value; 4 | var value = document.getElementById('mode').value; 5 | var pathArray = window.location.pathname.split( '/' ); 6 | length = pathArray.length; 7 | var digit = parseInt(pathArray[length-2]); 8 | 9 | if (! isNaN(digit) && value == 'Automatic') 10 | { 11 | window.location = url_root + "/exam/manage/designquestionpaper/automatic/" + digit; 12 | } 13 | else if(!isNaN(digit) && value == 'Manual') 14 | { 15 | window.location = url_root + "/exam/manage/designquestionpaper/manual/" + digit; 16 | } 17 | else if(value == 'Automatic') 18 | { 19 | window.location = window.location.pathname + "automatic"; 20 | } 21 | else if( value == 'Manual') 22 | { 23 | window.location = window.location.pathname + "manual"; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /yaksh/static/yaksh/js/add_quiz.js: -------------------------------------------------------------------------------- 1 | function test() 2 | { 3 | document.getElementById('id_duration').setAttribute('class','mini-text form-control'); 4 | document.getElementById('id_pass_criteria').setAttribute('class','mini-text form-control'); 5 | tinymce.init({ 6 | selector: 'textarea#id_instructions', 7 | setup : function(ed) { 8 | ed.on('change', function(e) { 9 | tinymce.triggerSave(); 10 | }); 11 | }, 12 | max_height: 400, 13 | height: 400, 14 | plugins: "image code link", 15 | convert_urls: false 16 | }); 17 | } 18 | 19 | String.prototype.beginsWith = function (string) { 20 | return(this.indexOf(string) === 0); 21 | }; 22 | 23 | function usermode(location) 24 | { 25 | window.location.replace(location); 26 | } 27 | -------------------------------------------------------------------------------- /yaksh/static/yaksh/js/codemirror/mode/clike/test.js: -------------------------------------------------------------------------------- 1 | // CodeMirror, copyright (c) by Marijn Haverbeke and others 2 | // Distributed under an MIT license: http://codemirror.net/LICENSE 3 | 4 | (function() { 5 | var mode = CodeMirror.getMode({indentUnit: 2}, "text/x-c"); 6 | function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1)); } 7 | 8 | MT("indent", 9 | "[variable-3 void] [def foo]([variable-3 void*] [variable a], [variable-3 int] [variable b]) {", 10 | " [variable-3 int] [variable c] [operator =] [variable b] [operator +]", 11 | " [number 1];", 12 | " [keyword return] [operator *][variable a];", 13 | "}"); 14 | 15 | MT("indent_switch", 16 | "[keyword switch] ([variable x]) {", 17 | " [keyword case] [number 10]:", 18 | " [keyword return] [number 20];", 19 | " [keyword default]:", 20 | " [variable printf]([string \"foo %c\"], [variable x]);", 21 | "}"); 22 | 23 | MT("def", 24 | "[variable-3 void] [def foo]() {}", 25 | "[keyword struct] [def bar]{}", 26 | "[variable-3 int] [variable-3 *][def baz]() {}"); 27 | 28 | MT("def_new_line", 29 | "::[variable std]::[variable SomeTerribleType][operator <][variable T][operator >]", 30 | "[def SomeLongMethodNameThatDoesntFitIntoOneLine]([keyword const] [variable MyType][operator &] [variable param]) {}") 31 | 32 | MT("double_block", 33 | "[keyword for] (;;)", 34 | " [keyword for] (;;)", 35 | " [variable x][operator ++];", 36 | "[keyword return];"); 37 | 38 | MT("preprocessor", 39 | "[meta #define FOO 3]", 40 | "[variable-3 int] [variable foo];", 41 | "[meta #define BAR\\]", 42 | "[meta 4]", 43 | "[variable-3 unsigned] [variable-3 int] [variable bar] [operator =] [number 8];", 44 | "[meta #include ][comment // comment]") 45 | 46 | 47 | var mode_cpp = CodeMirror.getMode({indentUnit: 2}, "text/x-c++src"); 48 | function MTCPP(name) { test.mode(name, mode_cpp, Array.prototype.slice.call(arguments, 1)); } 49 | 50 | MTCPP("cpp14_literal", 51 | "[number 10'000];", 52 | "[number 0b10'000];", 53 | "[number 0x10'000];", 54 | "[string '100000'];"); 55 | })(); 56 | -------------------------------------------------------------------------------- /yaksh/static/yaksh/js/codemirror/mode/python/test.js: -------------------------------------------------------------------------------- 1 | // CodeMirror, copyright (c) by Marijn Haverbeke and others 2 | // Distributed under an MIT license: http://codemirror.net/LICENSE 3 | 4 | (function() { 5 | var mode = CodeMirror.getMode({indentUnit: 4}, 6 | {name: "python", 7 | version: 3, 8 | singleLineStringErrors: false}); 9 | function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1)); } 10 | 11 | // Error, because "foobarhello" is neither a known type or property, but 12 | // property was expected (after "and"), and it should be in parentheses. 13 | MT("decoratorStartOfLine", 14 | "[meta @dec]", 15 | "[keyword def] [def function]():", 16 | " [keyword pass]"); 17 | 18 | MT("decoratorIndented", 19 | "[keyword class] [def Foo]:", 20 | " [meta @dec]", 21 | " [keyword def] [def function]():", 22 | " [keyword pass]"); 23 | 24 | MT("matmulWithSpace:", "[variable a] [operator @] [variable b]"); 25 | MT("matmulWithoutSpace:", "[variable a][operator @][variable b]"); 26 | MT("matmulSpaceBefore:", "[variable a] [operator @][variable b]"); 27 | 28 | MT("fValidStringPrefix", "[string f'this is a {formatted} string']"); 29 | MT("uValidStringPrefix", "[string u'this is an unicode string']"); 30 | })(); 31 | -------------------------------------------------------------------------------- /yaksh/static/yaksh/js/codemirror/mode/shell/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | CodeMirror: Shell mode 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 14 | 27 | 28 |
29 |

Shell mode

30 | 31 | 32 | 56 | 57 | 64 | 65 |

MIME types defined: text/x-sh.

66 |
67 | -------------------------------------------------------------------------------- /yaksh/static/yaksh/js/codemirror/mode/shell/test.js: -------------------------------------------------------------------------------- 1 | // CodeMirror, copyright (c) by Marijn Haverbeke and others 2 | // Distributed under an MIT license: http://codemirror.net/LICENSE 3 | 4 | (function() { 5 | var mode = CodeMirror.getMode({}, "shell"); 6 | function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1)); } 7 | 8 | MT("var", 9 | "text [def $var] text"); 10 | MT("varBraces", 11 | "text[def ${var}]text"); 12 | MT("varVar", 13 | "text [def $a$b] text"); 14 | MT("varBracesVarBraces", 15 | "text[def ${a}${b}]text"); 16 | 17 | MT("singleQuotedVar", 18 | "[string 'text $var text']"); 19 | MT("singleQuotedVarBraces", 20 | "[string 'text ${var} text']"); 21 | 22 | MT("doubleQuotedVar", 23 | '[string "text ][def $var][string text"]'); 24 | MT("doubleQuotedVarBraces", 25 | '[string "text][def ${var}][string text"]'); 26 | MT("doubleQuotedVarPunct", 27 | '[string "text ][def $@][string text"]'); 28 | MT("doubleQuotedVarVar", 29 | '[string "][def $a$b][string "]'); 30 | MT("doubleQuotedVarBracesVarBraces", 31 | '[string "][def ${a}${b}][string "]'); 32 | 33 | MT("notAString", 34 | "text\\'text"); 35 | MT("escapes", 36 | "outside\\'\\\"\\`\\\\[string \"inside\\`\\'\\\"\\\\`\\$notAVar\"]outside\\$\\(notASubShell\\)"); 37 | 38 | MT("subshell", 39 | "[builtin echo] [quote $(whoami)] s log, stardate [quote `date`]."); 40 | MT("doubleQuotedSubshell", 41 | "[builtin echo] [string \"][quote $(whoami)][string 's log, stardate `date`.\"]"); 42 | 43 | MT("hashbang", 44 | "[meta #!/bin/bash]"); 45 | MT("comment", 46 | "text [comment # Blurb]"); 47 | 48 | MT("numbers", 49 | "[number 0] [number 1] [number 2]"); 50 | MT("keywords", 51 | "[keyword while] [atom true]; [keyword do]", 52 | " [builtin sleep] [number 3]", 53 | "[keyword done]"); 54 | MT("options", 55 | "[builtin ls] [attribute -l] [attribute --human-readable]"); 56 | MT("operator", 57 | "[def var][operator =]value"); 58 | })(); 59 | -------------------------------------------------------------------------------- /yaksh/static/yaksh/js/design_course.js: -------------------------------------------------------------------------------- 1 | $(document).ready(function(){ 2 | var checked_vals = []; 3 | $('input:checkbox[name="quiz_lesson"]').click(function() { 4 | if($(this).prop("checked") == true){ 5 | checked_vals.push($(this).val()); 6 | } 7 | else{ 8 | checked_vals.pop($(this).val()); 9 | } 10 | }); 11 | $('#design_course_form').submit(function(eventObj) { 12 | var input_order = $("input[name*='order']"); 13 | var order_list = [] 14 | if (input_order){ 15 | $(input_order).each(function(index) { 16 | order_list.push($(this).data('item-id')+":"+$(this).val()); 17 | }); 18 | } 19 | $(this).append(''); 20 | $(this).append(''); 21 | return true; 22 | }); 23 | var completion_msg = "This will check if the previous module is completed " + 24 | "before viewing the next module." 25 | $("#prereq_msg").attr("title", completion_msg); 26 | $("#prereq_msg").tooltip(); 27 | var completion_msg = "This will check if the previous module is completed " + 28 | "before viewing the next module based on quiz passing status." 29 | $("#prereq_passing_msg").attr("title", completion_msg); 30 | }); -------------------------------------------------------------------------------- /yaksh/static/yaksh/js/edit_quiz.js: -------------------------------------------------------------------------------- 1 | function form_load() 2 | { 3 | var tags = document.getElementsByName('tags'); 4 | 5 | for (var i=0;iarticle,aside,figcaption,figure,footer,header,hgroup,nav,section{display:block}mark{background:#FF0;color:#000}"; 3 | c=d.insertBefore(c.lastChild,d.firstChild);b.hasCSS=!!c}g||t(a,b);return a}var k=l.html5||{},s=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,r=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,j,o="_html5shiv",h=0,n={},g;(function(){try{var a=f.createElement("a");a.innerHTML="";j="hidden"in a;var b;if(!(b=1==a.childNodes.length)){f.createElement("a");var c=f.createDocumentFragment();b="undefined"==typeof c.cloneNode|| 4 | "undefined"==typeof c.createDocumentFragment||"undefined"==typeof c.createElement}g=b}catch(d){g=j=!0}})();var e={elements:k.elements||"abbr article aside audio bdi canvas data datalist details figcaption figure footer header hgroup mark meter nav output progress section summary time video",shivCSS:!1!==k.shivCSS,supportsUnknownElements:g,shivMethods:!1!==k.shivMethods,type:"default",shivDocument:q,createElement:p,createDocumentFragment:function(a,b){a||(a=f);if(g)return a.createDocumentFragment(); 5 | for(var b=b||i(a),c=b.frag.cloneNode(),d=0,e=m(),h=e.length;dv(e)&&(i=o+c);var m=e.getParam("max_height",0,"number");if(m&&m")}),(t=n).ui.registry.addButton("hr",{icon:"horizontal-rule",tooltip:"Horizontal line",onAction:function(){return t.execCommand("InsertHorizontalRule")}}),t.ui.registry.addMenuItem("hr",{icon:"horizontal-rule",text:"Horizontal line",onAction:function(){return t.execCommand("InsertHorizontalRule")}})})}()}(); -------------------------------------------------------------------------------- /yaksh/static/yaksh/js/tinymce/js/tinymce/plugins/nonbreaking/plugin.min.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Tiny Technologies, Inc. All rights reserved. 3 | * Licensed under the LGPL or a commercial license. 4 | * For LGPL see License.txt in the project root for license information. 5 | * For commercial licenses see https://www.tiny.cloud/ 6 | * 7 | * Version: 5.3.0 (2020-05-21) 8 | */ 9 | !function(){"use strict";var n=tinymce.util.Tools.resolve("tinymce.PluginManager"),i=function(n,e){for(var a="",o=0;o'+i(" ",e)+"":i(" ",e);n.undoManager.transact(function(){return n.insertContent(o)})},c=tinymce.util.Tools.resolve("tinymce.util.VK");!function e(){n.add("nonbreaking",function(n){var e,a,o,i,t;(e=n).addCommand("mceNonBreaking",function(){r(e,1)}),(a=n).ui.registry.addButton("nonbreaking",{icon:"non-breaking",tooltip:"Nonbreaking space",onAction:function(){return a.execCommand("mceNonBreaking")}}),a.ui.registry.addMenuItem("nonbreaking",{icon:"non-breaking",text:"Nonbreaking space",onAction:function(){return a.execCommand("mceNonBreaking")}}),0<(t="boolean"==typeof(i=(o=n).getParam("nonbreaking_force_tab",0))?!0===i?3:0:i)&&o.on("keydown",function(n){if(n.keyCode===c.TAB&&!n.isDefaultPrevented()){if(n.shiftKey)return;n.preventDefault(),n.stopImmediatePropagation(),r(o,t)}})})}()}(); -------------------------------------------------------------------------------- /yaksh/static/yaksh/js/tinymce/js/tinymce/plugins/noneditable/plugin.min.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Tiny Technologies, Inc. All rights reserved. 3 | * Licensed under the LGPL or a commercial license. 4 | * For LGPL see License.txt in the project root for license information. 5 | * For commercial licenses see https://www.tiny.cloud/ 6 | * 7 | * Version: 5.3.0 (2020-05-21) 8 | */ 9 | !function(){"use strict";var t=tinymce.util.Tools.resolve("tinymce.PluginManager"),l=tinymce.util.Tools.resolve("tinymce.util.Tools"),u=function(t){return t.getParam("noneditable_noneditable_class","mceNonEditable")},f=function(n){return function(t){return-1!==(" "+t.attr("class")+" ").indexOf(n)}},s=function(i,o,c){return function(t){var n=arguments,e=n[n.length-2],r=0"===r){var a=o.lastIndexOf("<",e);if(-1!==a)if(-1!==o.substring(a,e).indexOf('contenteditable="false"'))return t}return''+i.dom.encode("string"==typeof n[1]?n[1]:n[0])+""}},n=function(n){var t,e,r="contenteditable";t=" "+l.trim(n.getParam("noneditable_editable_class","mceEditable"))+" ",e=" "+l.trim(u(n))+" ";var a,i=f(t),o=f(e),c=(a=n.getParam("noneditable_regexp",[]))&&a.constructor===RegExp?[a]:a;n.on("PreInit",function(){0'};!function n(){e.add("pagebreak",function(e){var a,n,o,i,t,r;(a=e).addCommand("mcePageBreak",function(){a.settings.pagebreak_split_block?a.insertContent("

"+g()+"

"):a.insertContent(g())}),(n=e).ui.registry.addButton("pagebreak",{icon:"page-break",tooltip:"Page break",onAction:function(){return n.execCommand("mcePageBreak")}}),n.ui.registry.addMenuItem("pagebreak",{text:"Page break",icon:"page-break",onAction:function(){return n.execCommand("mcePageBreak")}}),i=(o=e).getParam("pagebreak_separator","\x3c!-- pagebreak --\x3e"),t=new RegExp(i.replace(/[\?\.\*\[\]\(\)\{\}\+\^\$\:]/g,function(e){return"\\"+e}),"gi"),o.on("BeforeSetContent",function(e){e.content=e.content.replace(t,g())}),o.on("PreInit",function(){o.serializer.addNodeFilter("img",function(e){for(var a,n,t=e.length;t--;)if((n=(a=e[t]).attr("class"))&&-1!==n.indexOf("mce-pagebreak")){var r=a.parent;if(o.schema.getBlockElements()[r.name]&&o.getParam("pagebreak_split_block",!1)){r.type=3,r.value=i,r.raw=!0,a.remove();continue}a.type=3,a.value=i,a.raw=!0}})}),(r=e).on("ResolveName",function(e){"IMG"===e.target.nodeName&&r.dom.hasClass(e.target,c())&&(e.name="pagebreak")})})}()}(); -------------------------------------------------------------------------------- /yaksh/static/yaksh/js/tinymce/js/tinymce/plugins/preview/plugin.min.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Tiny Technologies, Inc. All rights reserved. 3 | * Licensed under the LGPL or a commercial license. 4 | * For LGPL see License.txt in the project root for license information. 5 | * For commercial licenses see https://www.tiny.cloud/ 6 | * 7 | * Version: 5.3.0 (2020-05-21) 8 | */ 9 | !function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager"),l=tinymce.util.Tools.resolve("tinymce.util.Tools"),m=tinymce.util.Tools.resolve("tinymce.Env"),i=function(e){var t=function(t){var n="",i=t.dom.encode,e=t.getParam("content_style","");n+='',e&&(n+='");var o=t.getParam("content_css_cors",!1,"boolean")?' crossorigin="anonymous"':"";l.each(t.contentCSS,function(e){n+='"});var r=t.settings.body_id||"tinymce";-1!==r.indexOf("=")&&(r=(r=t.getParam("body_id","","hash"))[t.id]||r);var a=t.settings.body_class||"";-1!==a.indexOf("=")&&(a=(a=t.getParam("body_class","","hash"))[t.id]||"");var c=' 19 | {% endblock %} 20 | {% block content %} 21 |

22 |
23 |
24 |
25 |

Your password has been changed successfully.

26 |

Redirecting ...

27 |
28 |
29 |
30 |
31 | {% endblock %} 32 | -------------------------------------------------------------------------------- /yaksh/templates/registration/password_reset_complete.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% load static %} 3 | 4 | {% block title %} Forgot Password {% endblock %} 5 | 6 | {% block nav %} 7 | 12 | {% endblock %} 13 | 14 | {% block content %} 15 |
16 |
17 |

Your password has been reset.

18 |

Log in

19 |
20 |
21 | {% endblock %} 22 | -------------------------------------------------------------------------------- /yaksh/templates/registration/password_reset_done.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% load static %} 3 | {% block title %} Forgot Password {% endblock %} 4 | 5 | {% block nav %} 6 | 11 | {% endblock %} 12 | 13 | {% block content %} 14 |
15 |

Password reset successful

16 |
17 | Instruction for setting new password has been mailed to your registered email address 18 |
19 |
20 | Go to Login 21 |
22 | {% endblock %} 23 | -------------------------------------------------------------------------------- /yaksh/templates/registration/password_reset_form.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% load static %} 3 | 4 | {% block title %} Forgot Password {% endblock %} 5 | 6 | {% block nav %} 7 | 12 | {% endblock %} 13 | 14 | {% block content %} 15 |
16 |

Enter your registered email address to reset your password

17 |
18 |
19 |
20 |
21 |

Forgot Password?

22 |
23 |
24 |
25 | {% csrf_token %} 26 | 27 | {{ form }} 28 |

29 | 32 | 33 | Cancel 34 | 35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 | {% endblock content %} 44 | -------------------------------------------------------------------------------- /yaksh/templates/yaksh/add_topic.html: -------------------------------------------------------------------------------- 1 | {% if topic_id %} 2 |
3 | {% else %} 4 | 5 | {% endif %} 6 | {% csrf_token %} 7 | {{ form.as_p }} 8 |
9 | 12 |
13 | -------------------------------------------------------------------------------- /yaksh/templates/yaksh/course_teachers.html: -------------------------------------------------------------------------------- 1 |

Teacher(s)/TA(s)

2 |
3 | 4 | {% if teachers %} 5 |
6 | {% csrf_token %} 7 |
8 |
9 | {% if teachers|length > 10 %} 10 |
11 | {% else %} 12 |
13 | {% endif %} 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | {% for teacher in teachers %} 24 | 25 | 26 | 27 | 28 | 29 | {% endfor %} 30 | 31 |
SelectNameEmail
{{ teacher.get_full_name }}{{ teacher.email }}
32 |
33 |
34 |
35 |
36 | 40 | 41 | {% else %} 42 |
No Teacher(s) added
43 | {% endif %} -------------------------------------------------------------------------------- /yaksh/templates/yaksh/demo_video.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 | 7 |
  8 |
9 |
10 |
11 |
-------------------------------------------------------------------------------- /yaksh/templates/yaksh/editquestionpaper.html: -------------------------------------------------------------------------------- 1 | {% extends "manage.html" %} 2 | 3 | 4 | {% block subtitle %}Questions in "{{ papers.quiz.description }}"{% endblock %} 5 | 6 | {% block script %} 7 | 8 | {% endblock %} 9 | 10 | {% block manage %} 11 |
12 |
13 | {% csrf_token %} 14 |

Fixed Questions

15 | {% for q in fixed_questions %} 16 |   {{ q.summary}}
17 | {% endfor %} 18 |

Random Questions

19 | {% for random_set in random_questions %} 20 |

{{ random_set.num_questions}} question(s) from {{ random_set.questions.all|length }} question(s)

21 | {% for q in random_set.questions.all %} 22 |   {{ q.summary}}
23 | {% endfor %} 24 | {% endfor %} 25 |
26 |
27 |
28 | {% endblock %} 29 | -------------------------------------------------------------------------------- /yaksh/templates/yaksh/intro.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | 3 | {% block title %} {{questionpaper.quiz.description}} {% endblock %} 4 | {% block pagetitle %} Quiz Instructions and Rules {% endblock pagetitle %} 5 | 6 | {% block content %} 7 |
8 |
9 |
10 | {{questionpaper.quiz.description}} 11 |
12 |
13 | {% if questionpaper.quiz.is_expired %} 14 |
15 | This Quiz has expired. You can no longer attempt this Quiz. 16 |
17 | {% else %} 18 |
19 | You can attempt this Quiz at any time between {{ questionpaper.quiz.start_date_time }} and {{ questionpaper.quiz.end_date_time }} 20 |
21 | {% endif %} 22 |

Welcome {{user.get_full_name|title}}, to the programming quiz!

23 | {{ questionpaper.quiz.instructions|safe }} 24 |
25 |
26 |
27 | {% if status != "moderator" %} 28 | 29 | 30 | Go Back 31 | 32 | {% else %} 33 | 34 | 35 | Go Back 36 | 37 | {% endif %} 38 |
39 |
40 |
41 | {% if not questionpaper.quiz.is_expired %} 42 |
43 | {% csrf_token %} 44 | 47 |
48 | {% endif %} 49 |
50 |
51 |
52 |
53 |
54 | {% endblock content %} 55 | -------------------------------------------------------------------------------- /yaksh/templates/yaksh/micromanaged.html: -------------------------------------------------------------------------------- 1 | {% if micromanagers %} 2 |
3 |
4 | {% for micromanager in micromanagers %} 5 | {% if micromanager.attempts_permitted > 0 %} 6 |
7 |

You have been given a special attempt to the {{ micromanager.quiz.description }} by the course creator

8 |
9 |
10 | {% if micromanager.can_student_attempt %} 11 | 12 | Start Special Attempt 13 | 14 | {% else %} 15 | Exhausted 16 | {% endif %} 17 |
18 | {% endif %} 19 | {% endfor %} 20 |
21 | {% endif %} 22 | 23 | -------------------------------------------------------------------------------- /yaksh/templates/yaksh/micromonitor.html: -------------------------------------------------------------------------------- 1 | {% if micromanager %} 2 | {% if micromanager.can_student_attempt %} 3 | Revoke 4 | {% else %} 5 | Allow 6 | {% endif %} 7 | {% else %} 8 | Allow 9 | {% endif %} 10 | -------------------------------------------------------------------------------- /yaksh/templates/yaksh/preview_questionpaper.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | 3 | {% block title %} Preview Question paper {% endblock title %} 4 | {% block pagetitle %} Quiz: {{ paper.quiz.description }} {% endblock pagetitle %} 5 | 6 | {% block content %} 7 |
8 |
9 |
10 |
11 |
Maximum Mark(s): {{ paper.total_marks }}
12 |
13 | 14 | Total Time: {{ paper.quiz.duration }} minutes 15 | 16 |
17 |
18 |
19 |
20 |
21 |
22 |
Instructions
23 |
24 | {{ paper.quiz.instructions|safe }} 25 |
26 |
27 |
28 | {% for question in questions %} 29 |
30 |
31 | {{forloop.counter}}. {{ question.summary }} 32 | Mark(s): {{ question.points }} 33 | 34 |
35 |
36 |
Question:
{{ question.description|safe }} 37 |
Answer:
38 | {% if question.type == "code" %} 39 |
{{ question.snippet }}

40 | {% endif %} 41 | {% if question.type == "mcq" or question.type == "mcc" %} 42 |
Choices:
43 | {% for testcase in question.get_test_cases %} 44 |
45 | {{ forloop.counter }}. {{ testcase.options|safe }} 46 | {% endfor %} 47 | {% endif %} 48 | 49 |
50 |
51 |
52 | {% endfor %} 53 |
54 | {% endblock %} 55 | -------------------------------------------------------------------------------- /yaksh/templates/yaksh/profile_updated.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% load static %} 3 | {% block title %} Profile {% endblock %} 4 | 5 | {% block nav %} 6 | 11 | {% endblock %} 12 | 13 | 14 | {% block script %} 15 | 18 | {% endblock script %} 19 | {% block content %} 20 |
21 |
22 |
23 |
24 |

Your Profile is changed

25 |

Redirecting...

26 |
27 |
28 |
29 |
30 |
31 | {% endblock content %} 32 | -------------------------------------------------------------------------------- /yaksh/templates/yaksh/results_user.html: -------------------------------------------------------------------------------- 1 | {% extends "user.html" %} 2 | 3 | {% block pagetitle %} Results {% endblock pagetitle %} 4 | {% block content %} 5 |
6 |
7 | {% csrf_token %} 8 |
9 | 15 | 16 | 17 | 18 | 19 | 20 | {% endfor %} 21 |
Quiz Description 10 | Obtained Marks 11 | Maximum Marks 12 | Percentage 13 | {% for paper in papers %} 14 |
{{ paper.question_paper.quiz.description }}{{ paper.marks_obtained }}{{ paper.question_paper.total_marks }}{{ paper.percent }}
22 |
23 |
24 | {% endblock %} 25 | 26 | -------------------------------------------------------------------------------- /yaksh/templates/yaksh/showquestionpapers.html: -------------------------------------------------------------------------------- 1 | {% extends "manage.html" %} 2 | 3 | 4 | {% block subtitle %}List of Question Papers {% endblock %} 5 | 6 | {% block script %} 7 | 8 | {% endblock %} 9 | 10 | {% block manage %} 11 |
12 | {% if papers %} 13 |
14 | {% csrf_token %} 15 | {% for i in papers %} 16 |   {{ i.quiz.description }}
17 | {% endfor %} 18 |
19 | 20 |
21 | {% else %} 22 |

No Question Papers available

23 | {% endif %} 24 |
25 | {% endblock %} 26 | -------------------------------------------------------------------------------- /yaksh/templates/yaksh/sidebar.html: -------------------------------------------------------------------------------- 1 | 2 |
3 | 15 |
16 | 17 | -------------------------------------------------------------------------------- /yaksh/templates/yaksh/upload_download_course_md.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |  Download 4 | 5 |

6 |
7 | {% csrf_token %} 8 | 9 | 12 |
13 |
-------------------------------------------------------------------------------- /yaksh/templates/yaksh/user_status.html: -------------------------------------------------------------------------------- 1 | {% if status %} 2 | Student Name: {{student.get_full_name|title}} 3 |
4 |
5 |
6 |
7 | Course completed 8 |
9 |
10 | 11 | {% if course_percentage %} {{course_percentage}} {% else %} 0 {% endif %}% 12 | 13 |
14 |
15 |
16 |
23 |
24 |
25 |
26 |
27 | Per Module Progress: 28 |
29 | 30 | {% for module, percent in modules %} 31 | 32 | 33 | 54 | 55 | {% endfor %} 56 |
{{ module.name }} 34 |
35 |
36 |
37 | 38 | {% if percent %} {{percent}} {% else %} 0 {% endif %}% 39 | 40 |
41 |
42 |
43 |
50 |
51 |
52 |
53 |
57 | {% else %} 58 | {{ msg }} 59 | {% endif %} -------------------------------------------------------------------------------- /yaksh/templates/yaksh/view_profile.html: -------------------------------------------------------------------------------- 1 | {% extends template %} 2 | 3 | {% block pagetitle %} Profile {% endblock %} 4 | {% block main %} 5 |
6 |
7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 |
41 | Edit Profile 42 |
43 |
44 | {% endblock %} 45 | -------------------------------------------------------------------------------- /yaksh/templatetags/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FOSSEE/online_test/9ea045b637f2087c1f1cdf8855d2d42b5f74a875/yaksh/templatetags/__init__.py -------------------------------------------------------------------------------- /yaksh/tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FOSSEE/online_test/9ea045b637f2087c1f1cdf8855d2d42b5f74a875/yaksh/tests/__init__.py -------------------------------------------------------------------------------- /yaksh/tests/test_questions.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "snippet": "", 4 | "testcase": [ 5 | { 6 | "test_case": "assert is_palindrome(\"hello\") == False" 7 | }, 8 | { 9 | "test_case": "assert is_palindrome(\"nitin\") == True" 10 | } 11 | ], 12 | "points": 3.0, 13 | "test_case_type": "standardtestcase", 14 | "description": "Write a function is_palindrome(arg) which will take one string argument. Return true if the argument is palindrome & false otherwise.\r\n

\r\nFor Example:\r\n
\r\nis_palindrome(\"Hello\") should return False\r\n
\r\n

", 15 | "language": "python", 16 | "active": true, 17 | "type": "code", 18 | "summary": "Python, check palindrome (Code)" 19 | }, 20 | { 21 | "snippet": "#!/bin/bash", 22 | "testcase": [ 23 | { 24 | "test_case": "bash_files/sample.sh, bash_files/sample.args" 25 | } 26 | ], 27 | "points": 1.0, 28 | "test_case_type": "standardtestcase", 29 | "description": "Write a bash script that takes exactly two arguments and returns the sum of the numbers", 30 | "language": "bash", 31 | "active": true, 32 | "type": "code", 33 | "summary": "Bash Question Concatenate Files(Code)" 34 | }, 35 | { 36 | "snippet": "", 37 | "testcase": [ 38 | { 39 | "test_case": "c_cpp_files/main2.c" 40 | } 41 | ], 42 | "points": 1.0, 43 | "test_case_type": "standardtestcase", 44 | "description": "Write a program to add 3 nos", 45 | "language": "c", 46 | "active": true, 47 | "type": "code", 48 | "summary": "selenium test" 49 | } 50 | ] 51 | -------------------------------------------------------------------------------- /yaksh/urls_password_reset.py: -------------------------------------------------------------------------------- 1 | from django.conf.urls import url 2 | from django.contrib.auth.views import password_reset, password_reset_confirm,\ 3 | password_reset_done, password_reset_complete, password_change,\ 4 | password_change_done 5 | 6 | urlpatterns = [ 7 | url(r'^forgotpassword/$', password_reset, 8 | name="password_reset"), 9 | url(r'^password_reset/(?P[0-9A-Za-z]+)-(?P.+)/$', 10 | password_reset_confirm, 11 | name='password_reset_confirm'), 12 | url(r'^password_reset/mail_sent/$', password_reset_done, 13 | name='password_reset_done'), 14 | url(r'^password_reset/complete/$', password_reset_complete, 15 | name='password_reset_complete'), 16 | url(r'^changepassword/$', password_change, 17 | name='password_change'), 18 | url(r'^password_change/done/$', password_change_done, 19 | name='password_change_done'), 20 | ] 21 | --------------------------------------------------------------------------------