From 2955c57b10c33a12b9c6def60169ee2105ca20e4 Mon Sep 17 00:00:00 2001 From: adityacp Date: Fri, 10 Mar 2017 11:10:09 +0530 Subject: Changes in models and views - Display error message if questions_dump.json is not found in zip file - Provide a sample zip file to for easy zip file creation --- yaksh/models.py | 3 +++ yaksh/views.py | 19 ++++++++++++++++--- 2 files changed, 19 insertions(+), 3 deletions(-) (limited to 'yaksh') diff --git a/yaksh/models.py b/yaksh/models.py index 398f508..0a84d4e 100644 --- a/yaksh/models.py +++ b/yaksh/models.py @@ -402,6 +402,9 @@ class Question(models.Model): with open(json_file, 'r') as q_file: questions_list = q_file.read() self.load_questions(questions_list, user, file_path, files) + return "Questions Uploaded Successfully" + else: + return "Please upload zip file with questions_dump.json in it." def create_demo_questions(self, user): zip_file_path = os.path.join( diff --git a/yaksh/views.py b/yaksh/views.py index 63653e6..02019f4 100644 --- a/yaksh/views.py +++ b/yaksh/views.py @@ -20,7 +20,6 @@ import pytz from taggit.models import Tag from itertools import chain import json -import zipfile import six # Local imports. from yaksh.models import get_model_class, Quiz, Question, QuestionPaper, QuestionSet, Course @@ -31,6 +30,7 @@ from yaksh.forms import UserRegisterForm, UserLoginForm, QuizForm,\ QuestionFilterForm, CourseForm, ProfileForm, UploadFileForm,\ get_object_form, FileForm, QuestionPaperForm from .settings import URL_ROOT +from django.conf import settings from yaksh.models import AssignmentUpload from .file_utils import extract_files @@ -894,7 +894,8 @@ def show_all_questions(request): if request.POST.get('delete') == 'delete': data = request.POST.getlist('question') if data is not None: - questions = Question.objects.filter(id__in=data, user_id=user.id, active=True) + questions = Question.objects.filter(id__in=data, user_id=user.id, + active=True) for question in questions: question.active = False question.save() @@ -907,7 +908,8 @@ def show_all_questions(request): if file_name[-1] == "zip": ques = Question() files, extract_path = extract_files(questions_file) - ques.read_json(extract_path, user, files) + context['message'] = ques.read_json(extract_path, user, + files) else: message = "Please Upload a ZIP file" context['message'] = message @@ -947,6 +949,17 @@ def show_all_questions(request): return my_render_to_response('yaksh/showquestions.html', context, context_instance=ci) +@login_required +def download_demo_questions(request): + user = request.user + if not is_moderator(user): + raise Http404("You are not allowed to download!") + f_path = os.path.join(settings.FIXTURE_DIRS, "demo_questions.zip") + zip_file = open(f_path, "rb") + response = HttpResponse(zip_file, content_type='application/zip') + response['Content-Disposition'] = '''attachment;\ + filename=demo_questions.zip''' + return response @login_required def user_data(request, user_id, questionpaper_id=None): -- cgit From 2da746134de706e82f848ef975da229f9f15d64e Mon Sep 17 00:00:00 2001 From: adityacp Date: Fri, 10 Mar 2017 11:14:34 +0530 Subject: Add url to download sample zip file --- yaksh/urls.py | 1 + 1 file changed, 1 insertion(+) (limited to 'yaksh') diff --git a/yaksh/urls.py b/yaksh/urls.py index ad58985..e7a3a66 100644 --- a/yaksh/urls.py +++ b/yaksh/urls.py @@ -28,6 +28,7 @@ urlpatterns = [ url(r'^view_answerpaper/(?P\d+)/$', views.view_answerpaper, name='view_answerpaper'), url(r'^manage/$', views.prof_manage, name='manage'), url(r'^manage/addquestion/$', views.add_question), + url(r'^manage/download_demo_question/$', views.download_demo_questions), url(r'^manage/addquestion/(?P\d+)/$', views.add_question), url(r'^manage/addquiz/(?P\d+)/$', views.add_quiz, name='add_quiz'), url(r'^manage/addquiz/(?P\d+)/(?P\d+)/$', views.add_quiz, name='edit_quiz'), -- cgit From 508a576ccfb63169c24056ded25f742bdcd186f2 Mon Sep 17 00:00:00 2001 From: adityacp Date: Fri, 10 Mar 2017 11:15:05 +0530 Subject: Add a link to download sample zip file --- yaksh/templates/yaksh/showquestions.html | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'yaksh') diff --git a/yaksh/templates/yaksh/showquestions.html b/yaksh/templates/yaksh/showquestions.html index 3668c9e..73612d5 100644 --- a/yaksh/templates/yaksh/showquestions.html +++ b/yaksh/templates/yaksh/showquestions.html @@ -10,11 +10,16 @@ {% block content %} +

Please Download Sample Zip file to view zip file contents before uploading +Questions

+Sample Zip File +

Upload ZIP file for adding questions

{% csrf_token %} {{ upload_form.as_p }} - +
{% if message %}

{{ message }}

@@ -22,6 +27,7 @@ {% if msg %}

{{ msg }}

{% endif %} +

{% csrf_token %}
-- cgit From 1a50fb3407550869cf988b307f24af62ad3e57e7 Mon Sep 17 00:00:00 2001 From: prathamesh Date: Mon, 13 Mar 2017 12:58:17 +0530 Subject: Added migrations folder to the app. This required because when we do migration for the first time, initial migrations will be created only if migrations folder is present in the installed app. Otherwise, running makemigrations will not detect the initial migrations for that app. Though we can exclusively specify the app name as the argument to the makemigrations command. But did this so that by default apply migrations. Note: Removed migrations from .gitignore --- yaksh/migrations/__init__.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 yaksh/migrations/__init__.py (limited to 'yaksh') diff --git a/yaksh/migrations/__init__.py b/yaksh/migrations/__init__.py new file mode 100644 index 0000000..e69de29 -- cgit From 4ce30381757815f851fce701ee61d86001a6624b Mon Sep 17 00:00:00 2001 From: prathamesh Date: Mon, 13 Mar 2017 13:14:33 +0530 Subject: Added migration commands to the script. Removed migrate with run-syncdb argument because this does not create migration files, so further migrations become difficult. Model changes are detected by make_migrations and the migrate command applies those migrations. This is done every time when user runs a demo. There is no harm in doing so. --- yaksh/scripts/cli.py | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) (limited to 'yaksh') diff --git a/yaksh/scripts/cli.py b/yaksh/scripts/cli.py index 4a58e48..a1a49ee 100644 --- a/yaksh/scripts/cli.py +++ b/yaksh/scripts/cli.py @@ -101,10 +101,6 @@ def create_demo(project_name='yaksh_demo', project_dir=CUR_DIR): 'fixture_dir': fixture_dir}) urls_template_path = path.join(TEMPLATE_DIR, 'demo_urls.py') urls_target_path = path.join(project_path, 'demo_urls.py') - command = ("python ../manage.py migrate --run-syncdb " - "--noinput --settings={0}.demo_settings").format( - project_name) - loaddata_command = ("python ../manage.py loaddata " "--settings={0}.demo_settings {1}").format( project_name, fixture_path) @@ -115,14 +111,18 @@ def create_demo(project_name='yaksh_demo', project_dir=CUR_DIR): ) # Create demo_urls file _render_demo_files(urls_template_path, urls_target_path) - # Run syncdb - subprocess.call( - "{0}; {1}".format(command, loaddata_command), shell=True - ) + # Create database and load initial data + command_path = path.join(top_dir, 'manage.py') + _check_migrations(project_name, command_path) + _migrate(project_name, command_path) + subprocess.call(loaddata_command, shell=True) def run_demo(project_name, top_dir): with _chdir(top_dir): + command_path = path.join(top_dir, 'manage.py') + _check_migrations(project_name, command_path) + _migrate(project_name, command_path) command = ("python manage.py runserver " "--settings={0}.demo_settings").format(project_name) subprocess.call(command, shell=True) @@ -136,6 +136,18 @@ def run_server(args=None): print("Error: {0}\nExiting yaksh code server".format(e)) +def _check_migrations(project_name, command_path): + migrations = ("python {0} makemigrations --settings={1}.demo_settings" + ).format(command_path, project_name) + subprocess.call(migrations, shell=True) + + +def _migrate(project_name, command_path): + migrate = ("python {0} migrate --settings={1}.demo_settings" + ).format(command_path, project_name) + subprocess.call(migrate, shell=True) + + def _render_demo_files(template_path, output_path, context=None): with open(template_path, 'r') as template_file: content = template_file.read() -- cgit From 9ebedf2865963d2c2306b5c31b829f409a9bc2da Mon Sep 17 00:00:00 2001 From: prathamesh Date: Mon, 13 Mar 2017 13:36:59 +0530 Subject: Removed a function call to datetime now in default quiz start time. Every time when we run makemigrations, model changes are detected. "Alter field start_date_time on quiz" was always detected, even if you have not mode any changes to the models! This was happening because of default time value was datetime.now(). So every time when you ran migrations current datetime was set which will always change. Now removed parenthesis(), so that now function is not called. And no unnecessary model changes will be detected --- yaksh/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'yaksh') diff --git a/yaksh/models.py b/yaksh/models.py index 398f508..8709710 100644 --- a/yaksh/models.py +++ b/yaksh/models.py @@ -532,7 +532,7 @@ class Quiz(models.Model): # The start date of the quiz. start_date_time = models.DateTimeField( "Start Date and Time of the quiz", - default=timezone.now(), + default=timezone.now, null=True ) -- cgit From 39fcbfd9b8d4072482b1dee2532ef66c64ad630a Mon Sep 17 00:00:00 2001 From: prathamesh Date: Tue, 14 Mar 2017 14:20:48 +0530 Subject: Added initial migration for Yaksh --- yaksh/migrations/0001_initial.py | 268 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 268 insertions(+) create mode 100644 yaksh/migrations/0001_initial.py (limited to 'yaksh') diff --git a/yaksh/migrations/0001_initial.py b/yaksh/migrations/0001_initial.py new file mode 100644 index 0000000..8ee8c6a --- /dev/null +++ b/yaksh/migrations/0001_initial.py @@ -0,0 +1,268 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.5 on 2017-03-14 08:33 +from __future__ import unicode_literals + +import datetime +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion +import django.utils.timezone +from django.utils.timezone import utc +import taggit.managers +import yaksh.models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('taggit', '0002_auto_20150616_2121'), + ] + + operations = [ + migrations.CreateModel( + name='Answer', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('answer', models.TextField(blank=True, null=True)), + ('error', models.TextField()), + ('marks', models.FloatField(default=0.0)), + ('correct', models.BooleanField(default=False)), + ('skipped', models.BooleanField(default=False)), + ], + ), + migrations.CreateModel( + name='AnswerPaper', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('attempt_number', models.IntegerField()), + ('start_time', models.DateTimeField()), + ('end_time', models.DateTimeField()), + ('user_ip', models.CharField(max_length=15)), + ('comments', models.TextField()), + ('marks_obtained', models.FloatField(default=0.0, null=True)), + ('percent', models.FloatField(default=0.0, null=True)), + ('passed', models.NullBooleanField()), + ('status', models.CharField(choices=[('inprogress', 'Inprogress'), ('completed', 'Completed')], default='inprogress', max_length=20)), + ('answers', models.ManyToManyField(to='yaksh.Answer')), + ], + ), + migrations.CreateModel( + name='AssignmentUpload', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('assignmentFile', models.FileField(upload_to=yaksh.models.get_assignment_dir)), + ], + ), + migrations.CreateModel( + name='ConcurrentUser', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('session_key', models.CharField(max_length=40)), + ('concurrent_user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ], + ), + migrations.CreateModel( + name='Course', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=128)), + ('enrollment', models.CharField(choices=[('default', 'Enroll Request'), ('open', 'Open Course')], max_length=32)), + ('active', models.BooleanField(default=True)), + ('created_on', models.DateTimeField(auto_now_add=True)), + ('is_trial', models.BooleanField(default=False)), + ('instructions', models.TextField(blank=True, default=None, null=True)), + ('creator', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='creator', to=settings.AUTH_USER_MODEL)), + ('rejected', models.ManyToManyField(related_name='rejected', to=settings.AUTH_USER_MODEL)), + ('requests', models.ManyToManyField(related_name='requests', to=settings.AUTH_USER_MODEL)), + ('students', models.ManyToManyField(related_name='students', to=settings.AUTH_USER_MODEL)), + ('teachers', models.ManyToManyField(related_name='teachers', to=settings.AUTH_USER_MODEL)), + ], + ), + migrations.CreateModel( + name='FileUpload', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('file', models.FileField(blank=True, upload_to=yaksh.models.get_upload_dir)), + ('extract', models.BooleanField(default=False)), + ('hide', models.BooleanField(default=False)), + ], + ), + migrations.CreateModel( + name='Profile', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('roll_number', models.CharField(max_length=20)), + ('institute', models.CharField(max_length=128)), + ('department', models.CharField(max_length=64)), + ('position', models.CharField(max_length=64)), + ('timezone', models.CharField(choices=[('Africa/Abidjan', 'Africa/Abidjan'), ('Africa/Accra', 'Africa/Accra'), ('Africa/Addis_Ababa', 'Africa/Addis_Ababa'), ('Africa/Algiers', 'Africa/Algiers'), ('Africa/Asmara', 'Africa/Asmara'), ('Africa/Bamako', 'Africa/Bamako'), ('Africa/Bangui', 'Africa/Bangui'), ('Africa/Banjul', 'Africa/Banjul'), ('Africa/Bissau', 'Africa/Bissau'), ('Africa/Blantyre', 'Africa/Blantyre'), ('Africa/Brazzaville', 'Africa/Brazzaville'), ('Africa/Bujumbura', 'Africa/Bujumbura'), ('Africa/Cairo', 'Africa/Cairo'), ('Africa/Casablanca', 'Africa/Casablanca'), ('Africa/Ceuta', 'Africa/Ceuta'), ('Africa/Conakry', 'Africa/Conakry'), ('Africa/Dakar', 'Africa/Dakar'), ('Africa/Dar_es_Salaam', 'Africa/Dar_es_Salaam'), ('Africa/Djibouti', 'Africa/Djibouti'), ('Africa/Douala', 'Africa/Douala'), ('Africa/El_Aaiun', 'Africa/El_Aaiun'), ('Africa/Freetown', 'Africa/Freetown'), ('Africa/Gaborone', 'Africa/Gaborone'), ('Africa/Harare', 'Africa/Harare'), ('Africa/Johannesburg', 'Africa/Johannesburg'), ('Africa/Juba', 'Africa/Juba'), ('Africa/Kampala', 'Africa/Kampala'), ('Africa/Khartoum', 'Africa/Khartoum'), ('Africa/Kigali', 'Africa/Kigali'), ('Africa/Kinshasa', 'Africa/Kinshasa'), ('Africa/Lagos', 'Africa/Lagos'), ('Africa/Libreville', 'Africa/Libreville'), ('Africa/Lome', 'Africa/Lome'), ('Africa/Luanda', 'Africa/Luanda'), ('Africa/Lubumbashi', 'Africa/Lubumbashi'), ('Africa/Lusaka', 'Africa/Lusaka'), ('Africa/Malabo', 'Africa/Malabo'), ('Africa/Maputo', 'Africa/Maputo'), ('Africa/Maseru', 'Africa/Maseru'), ('Africa/Mbabane', 'Africa/Mbabane'), ('Africa/Mogadishu', 'Africa/Mogadishu'), ('Africa/Monrovia', 'Africa/Monrovia'), ('Africa/Nairobi', 'Africa/Nairobi'), ('Africa/Ndjamena', 'Africa/Ndjamena'), ('Africa/Niamey', 'Africa/Niamey'), ('Africa/Nouakchott', 'Africa/Nouakchott'), ('Africa/Ouagadougou', 'Africa/Ouagadougou'), ('Africa/Porto-Novo', 'Africa/Porto-Novo'), ('Africa/Sao_Tome', 'Africa/Sao_Tome'), ('Africa/Tripoli', 'Africa/Tripoli'), ('Africa/Tunis', 'Africa/Tunis'), ('Africa/Windhoek', 'Africa/Windhoek'), ('America/Adak', 'America/Adak'), ('America/Anchorage', 'America/Anchorage'), ('America/Anguilla', 'America/Anguilla'), ('America/Antigua', 'America/Antigua'), ('America/Araguaina', 'America/Araguaina'), ('America/Argentina/Buenos_Aires', 'America/Argentina/Buenos_Aires'), ('America/Argentina/Catamarca', 'America/Argentina/Catamarca'), ('America/Argentina/Cordoba', 'America/Argentina/Cordoba'), ('America/Argentina/Jujuy', 'America/Argentina/Jujuy'), ('America/Argentina/La_Rioja', 'America/Argentina/La_Rioja'), ('America/Argentina/Mendoza', 'America/Argentina/Mendoza'), ('America/Argentina/Rio_Gallegos', 'America/Argentina/Rio_Gallegos'), ('America/Argentina/Salta', 'America/Argentina/Salta'), ('America/Argentina/San_Juan', 'America/Argentina/San_Juan'), ('America/Argentina/San_Luis', 'America/Argentina/San_Luis'), ('America/Argentina/Tucuman', 'America/Argentina/Tucuman'), ('America/Argentina/Ushuaia', 'America/Argentina/Ushuaia'), ('America/Aruba', 'America/Aruba'), ('America/Asuncion', 'America/Asuncion'), ('America/Atikokan', 'America/Atikokan'), ('America/Bahia', 'America/Bahia'), ('America/Bahia_Banderas', 'America/Bahia_Banderas'), ('America/Barbados', 'America/Barbados'), ('America/Belem', 'America/Belem'), ('America/Belize', 'America/Belize'), ('America/Blanc-Sablon', 'America/Blanc-Sablon'), ('America/Boa_Vista', 'America/Boa_Vista'), ('America/Bogota', 'America/Bogota'), ('America/Boise', 'America/Boise'), ('America/Cambridge_Bay', 'America/Cambridge_Bay'), ('America/Campo_Grande', 'America/Campo_Grande'), ('America/Cancun', 'America/Cancun'), ('America/Caracas', 'America/Caracas'), ('America/Cayenne', 'America/Cayenne'), ('America/Cayman', 'America/Cayman'), ('America/Chicago', 'America/Chicago'), ('America/Chihuahua', 'America/Chihuahua'), ('America/Costa_Rica', 'America/Costa_Rica'), ('America/Creston', 'America/Creston'), ('America/Cuiaba', 'America/Cuiaba'), ('America/Curacao', 'America/Curacao'), ('America/Danmarkshavn', 'America/Danmarkshavn'), ('America/Dawson', 'America/Dawson'), ('America/Dawson_Creek', 'America/Dawson_Creek'), ('America/Denver', 'America/Denver'), ('America/Detroit', 'America/Detroit'), ('America/Dominica', 'America/Dominica'), ('America/Edmonton', 'America/Edmonton'), ('America/Eirunepe', 'America/Eirunepe'), ('America/El_Salvador', 'America/El_Salvador'), ('America/Fort_Nelson', 'America/Fort_Nelson'), ('America/Fortaleza', 'America/Fortaleza'), ('America/Glace_Bay', 'America/Glace_Bay'), ('America/Godthab', 'America/Godthab'), ('America/Goose_Bay', 'America/Goose_Bay'), ('America/Grand_Turk', 'America/Grand_Turk'), ('America/Grenada', 'America/Grenada'), ('America/Guadeloupe', 'America/Guadeloupe'), ('America/Guatemala', 'America/Guatemala'), ('America/Guayaquil', 'America/Guayaquil'), ('America/Guyana', 'America/Guyana'), ('America/Halifax', 'America/Halifax'), ('America/Havana', 'America/Havana'), ('America/Hermosillo', 'America/Hermosillo'), ('America/Indiana/Indianapolis', 'America/Indiana/Indianapolis'), ('America/Indiana/Knox', 'America/Indiana/Knox'), ('America/Indiana/Marengo', 'America/Indiana/Marengo'), ('America/Indiana/Petersburg', 'America/Indiana/Petersburg'), ('America/Indiana/Tell_City', 'America/Indiana/Tell_City'), ('America/Indiana/Vevay', 'America/Indiana/Vevay'), ('America/Indiana/Vincennes', 'America/Indiana/Vincennes'), ('America/Indiana/Winamac', 'America/Indiana/Winamac'), ('America/Inuvik', 'America/Inuvik'), ('America/Iqaluit', 'America/Iqaluit'), ('America/Jamaica', 'America/Jamaica'), ('America/Juneau', 'America/Juneau'), ('America/Kentucky/Louisville', 'America/Kentucky/Louisville'), ('America/Kentucky/Monticello', 'America/Kentucky/Monticello'), ('America/Kralendijk', 'America/Kralendijk'), ('America/La_Paz', 'America/La_Paz'), ('America/Lima', 'America/Lima'), ('America/Los_Angeles', 'America/Los_Angeles'), ('America/Lower_Princes', 'America/Lower_Princes'), ('America/Maceio', 'America/Maceio'), ('America/Managua', 'America/Managua'), ('America/Manaus', 'America/Manaus'), ('America/Marigot', 'America/Marigot'), ('America/Martinique', 'America/Martinique'), ('America/Matamoros', 'America/Matamoros'), ('America/Mazatlan', 'America/Mazatlan'), ('America/Menominee', 'America/Menominee'), ('America/Merida', 'America/Merida'), ('America/Metlakatla', 'America/Metlakatla'), ('America/Mexico_City', 'America/Mexico_City'), ('America/Miquelon', 'America/Miquelon'), ('America/Moncton', 'America/Moncton'), ('America/Monterrey', 'America/Monterrey'), ('America/Montevideo', 'America/Montevideo'), ('America/Montserrat', 'America/Montserrat'), ('America/Nassau', 'America/Nassau'), ('America/New_York', 'America/New_York'), ('America/Nipigon', 'America/Nipigon'), ('America/Nome', 'America/Nome'), ('America/Noronha', 'America/Noronha'), ('America/North_Dakota/Beulah', 'America/North_Dakota/Beulah'), ('America/North_Dakota/Center', 'America/North_Dakota/Center'), ('America/North_Dakota/New_Salem', 'America/North_Dakota/New_Salem'), ('America/Ojinaga', 'America/Ojinaga'), ('America/Panama', 'America/Panama'), ('America/Pangnirtung', 'America/Pangnirtung'), ('America/Paramaribo', 'America/Paramaribo'), ('America/Phoenix', 'America/Phoenix'), ('America/Port-au-Prince', 'America/Port-au-Prince'), ('America/Port_of_Spain', 'America/Port_of_Spain'), ('America/Porto_Velho', 'America/Porto_Velho'), ('America/Puerto_Rico', 'America/Puerto_Rico'), ('America/Rainy_River', 'America/Rainy_River'), ('America/Rankin_Inlet', 'America/Rankin_Inlet'), ('America/Recife', 'America/Recife'), ('America/Regina', 'America/Regina'), ('America/Resolute', 'America/Resolute'), ('America/Rio_Branco', 'America/Rio_Branco'), ('America/Santarem', 'America/Santarem'), ('America/Santiago', 'America/Santiago'), ('America/Santo_Domingo', 'America/Santo_Domingo'), ('America/Sao_Paulo', 'America/Sao_Paulo'), ('America/Scoresbysund', 'America/Scoresbysund'), ('America/Sitka', 'America/Sitka'), ('America/St_Barthelemy', 'America/St_Barthelemy'), ('America/St_Johns', 'America/St_Johns'), ('America/St_Kitts', 'America/St_Kitts'), ('America/St_Lucia', 'America/St_Lucia'), ('America/St_Thomas', 'America/St_Thomas'), ('America/St_Vincent', 'America/St_Vincent'), ('America/Swift_Current', 'America/Swift_Current'), ('America/Tegucigalpa', 'America/Tegucigalpa'), ('America/Thule', 'America/Thule'), ('America/Thunder_Bay', 'America/Thunder_Bay'), ('America/Tijuana', 'America/Tijuana'), ('America/Toronto', 'America/Toronto'), ('America/Tortola', 'America/Tortola'), ('America/Vancouver', 'America/Vancouver'), ('America/Whitehorse', 'America/Whitehorse'), ('America/Winnipeg', 'America/Winnipeg'), ('America/Yakutat', 'America/Yakutat'), ('America/Yellowknife', 'America/Yellowknife'), ('Antarctica/Casey', 'Antarctica/Casey'), ('Antarctica/Davis', 'Antarctica/Davis'), ('Antarctica/DumontDUrville', 'Antarctica/DumontDUrville'), ('Antarctica/Macquarie', 'Antarctica/Macquarie'), ('Antarctica/Mawson', 'Antarctica/Mawson'), ('Antarctica/McMurdo', 'Antarctica/McMurdo'), ('Antarctica/Palmer', 'Antarctica/Palmer'), ('Antarctica/Rothera', 'Antarctica/Rothera'), ('Antarctica/Syowa', 'Antarctica/Syowa'), ('Antarctica/Troll', 'Antarctica/Troll'), ('Antarctica/Vostok', 'Antarctica/Vostok'), ('Arctic/Longyearbyen', 'Arctic/Longyearbyen'), ('Asia/Aden', 'Asia/Aden'), ('Asia/Almaty', 'Asia/Almaty'), ('Asia/Amman', 'Asia/Amman'), ('Asia/Anadyr', 'Asia/Anadyr'), ('Asia/Aqtau', 'Asia/Aqtau'), ('Asia/Aqtobe', 'Asia/Aqtobe'), ('Asia/Ashgabat', 'Asia/Ashgabat'), ('Asia/Baghdad', 'Asia/Baghdad'), ('Asia/Bahrain', 'Asia/Bahrain'), ('Asia/Baku', 'Asia/Baku'), ('Asia/Bangkok', 'Asia/Bangkok'), ('Asia/Barnaul', 'Asia/Barnaul'), ('Asia/Beirut', 'Asia/Beirut'), ('Asia/Bishkek', 'Asia/Bishkek'), ('Asia/Brunei', 'Asia/Brunei'), ('Asia/Chita', 'Asia/Chita'), ('Asia/Choibalsan', 'Asia/Choibalsan'), ('Asia/Colombo', 'Asia/Colombo'), ('Asia/Damascus', 'Asia/Damascus'), ('Asia/Dhaka', 'Asia/Dhaka'), ('Asia/Dili', 'Asia/Dili'), ('Asia/Dubai', 'Asia/Dubai'), ('Asia/Dushanbe', 'Asia/Dushanbe'), ('Asia/Gaza', 'Asia/Gaza'), ('Asia/Hebron', 'Asia/Hebron'), ('Asia/Ho_Chi_Minh', 'Asia/Ho_Chi_Minh'), ('Asia/Hong_Kong', 'Asia/Hong_Kong'), ('Asia/Hovd', 'Asia/Hovd'), ('Asia/Irkutsk', 'Asia/Irkutsk'), ('Asia/Jakarta', 'Asia/Jakarta'), ('Asia/Jayapura', 'Asia/Jayapura'), ('Asia/Jerusalem', 'Asia/Jerusalem'), ('Asia/Kabul', 'Asia/Kabul'), ('Asia/Kamchatka', 'Asia/Kamchatka'), ('Asia/Karachi', 'Asia/Karachi'), ('Asia/Kathmandu', 'Asia/Kathmandu'), ('Asia/Khandyga', 'Asia/Khandyga'), ('Asia/Kolkata', 'Asia/Kolkata'), ('Asia/Krasnoyarsk', 'Asia/Krasnoyarsk'), ('Asia/Kuala_Lumpur', 'Asia/Kuala_Lumpur'), ('Asia/Kuching', 'Asia/Kuching'), ('Asia/Kuwait', 'Asia/Kuwait'), ('Asia/Macau', 'Asia/Macau'), ('Asia/Magadan', 'Asia/Magadan'), ('Asia/Makassar', 'Asia/Makassar'), ('Asia/Manila', 'Asia/Manila'), ('Asia/Muscat', 'Asia/Muscat'), ('Asia/Nicosia', 'Asia/Nicosia'), ('Asia/Novokuznetsk', 'Asia/Novokuznetsk'), ('Asia/Novosibirsk', 'Asia/Novosibirsk'), ('Asia/Omsk', 'Asia/Omsk'), ('Asia/Oral', 'Asia/Oral'), ('Asia/Phnom_Penh', 'Asia/Phnom_Penh'), ('Asia/Pontianak', 'Asia/Pontianak'), ('Asia/Pyongyang', 'Asia/Pyongyang'), ('Asia/Qatar', 'Asia/Qatar'), ('Asia/Qyzylorda', 'Asia/Qyzylorda'), ('Asia/Rangoon', 'Asia/Rangoon'), ('Asia/Riyadh', 'Asia/Riyadh'), ('Asia/Sakhalin', 'Asia/Sakhalin'), ('Asia/Samarkand', 'Asia/Samarkand'), ('Asia/Seoul', 'Asia/Seoul'), ('Asia/Shanghai', 'Asia/Shanghai'), ('Asia/Singapore', 'Asia/Singapore'), ('Asia/Srednekolymsk', 'Asia/Srednekolymsk'), ('Asia/Taipei', 'Asia/Taipei'), ('Asia/Tashkent', 'Asia/Tashkent'), ('Asia/Tbilisi', 'Asia/Tbilisi'), ('Asia/Tehran', 'Asia/Tehran'), ('Asia/Thimphu', 'Asia/Thimphu'), ('Asia/Tokyo', 'Asia/Tokyo'), ('Asia/Tomsk', 'Asia/Tomsk'), ('Asia/Ulaanbaatar', 'Asia/Ulaanbaatar'), ('Asia/Urumqi', 'Asia/Urumqi'), ('Asia/Ust-Nera', 'Asia/Ust-Nera'), ('Asia/Vientiane', 'Asia/Vientiane'), ('Asia/Vladivostok', 'Asia/Vladivostok'), ('Asia/Yakutsk', 'Asia/Yakutsk'), ('Asia/Yekaterinburg', 'Asia/Yekaterinburg'), ('Asia/Yerevan', 'Asia/Yerevan'), ('Atlantic/Azores', 'Atlantic/Azores'), ('Atlantic/Bermuda', 'Atlantic/Bermuda'), ('Atlantic/Canary', 'Atlantic/Canary'), ('Atlantic/Cape_Verde', 'Atlantic/Cape_Verde'), ('Atlantic/Faroe', 'Atlantic/Faroe'), ('Atlantic/Madeira', 'Atlantic/Madeira'), ('Atlantic/Reykjavik', 'Atlantic/Reykjavik'), ('Atlantic/South_Georgia', 'Atlantic/South_Georgia'), ('Atlantic/St_Helena', 'Atlantic/St_Helena'), ('Atlantic/Stanley', 'Atlantic/Stanley'), ('Australia/Adelaide', 'Australia/Adelaide'), ('Australia/Brisbane', 'Australia/Brisbane'), ('Australia/Broken_Hill', 'Australia/Broken_Hill'), ('Australia/Currie', 'Australia/Currie'), ('Australia/Darwin', 'Australia/Darwin'), ('Australia/Eucla', 'Australia/Eucla'), ('Australia/Hobart', 'Australia/Hobart'), ('Australia/Lindeman', 'Australia/Lindeman'), ('Australia/Lord_Howe', 'Australia/Lord_Howe'), ('Australia/Melbourne', 'Australia/Melbourne'), ('Australia/Perth', 'Australia/Perth'), ('Australia/Sydney', 'Australia/Sydney'), ('Canada/Atlantic', 'Canada/Atlantic'), ('Canada/Central', 'Canada/Central'), ('Canada/Eastern', 'Canada/Eastern'), ('Canada/Mountain', 'Canada/Mountain'), ('Canada/Newfoundland', 'Canada/Newfoundland'), ('Canada/Pacific', 'Canada/Pacific'), ('Europe/Amsterdam', 'Europe/Amsterdam'), ('Europe/Andorra', 'Europe/Andorra'), ('Europe/Astrakhan', 'Europe/Astrakhan'), ('Europe/Athens', 'Europe/Athens'), ('Europe/Belgrade', 'Europe/Belgrade'), ('Europe/Berlin', 'Europe/Berlin'), ('Europe/Bratislava', 'Europe/Bratislava'), ('Europe/Brussels', 'Europe/Brussels'), ('Europe/Bucharest', 'Europe/Bucharest'), ('Europe/Budapest', 'Europe/Budapest'), ('Europe/Busingen', 'Europe/Busingen'), ('Europe/Chisinau', 'Europe/Chisinau'), ('Europe/Copenhagen', 'Europe/Copenhagen'), ('Europe/Dublin', 'Europe/Dublin'), ('Europe/Gibraltar', 'Europe/Gibraltar'), ('Europe/Guernsey', 'Europe/Guernsey'), ('Europe/Helsinki', 'Europe/Helsinki'), ('Europe/Isle_of_Man', 'Europe/Isle_of_Man'), ('Europe/Istanbul', 'Europe/Istanbul'), ('Europe/Jersey', 'Europe/Jersey'), ('Europe/Kaliningrad', 'Europe/Kaliningrad'), ('Europe/Kiev', 'Europe/Kiev'), ('Europe/Kirov', 'Europe/Kirov'), ('Europe/Lisbon', 'Europe/Lisbon'), ('Europe/Ljubljana', 'Europe/Ljubljana'), ('Europe/London', 'Europe/London'), ('Europe/Luxembourg', 'Europe/Luxembourg'), ('Europe/Madrid', 'Europe/Madrid'), ('Europe/Malta', 'Europe/Malta'), ('Europe/Mariehamn', 'Europe/Mariehamn'), ('Europe/Minsk', 'Europe/Minsk'), ('Europe/Monaco', 'Europe/Monaco'), ('Europe/Moscow', 'Europe/Moscow'), ('Europe/Oslo', 'Europe/Oslo'), ('Europe/Paris', 'Europe/Paris'), ('Europe/Podgorica', 'Europe/Podgorica'), ('Europe/Prague', 'Europe/Prague'), ('Europe/Riga', 'Europe/Riga'), ('Europe/Rome', 'Europe/Rome'), ('Europe/Samara', 'Europe/Samara'), ('Europe/San_Marino', 'Europe/San_Marino'), ('Europe/Sarajevo', 'Europe/Sarajevo'), ('Europe/Simferopol', 'Europe/Simferopol'), ('Europe/Skopje', 'Europe/Skopje'), ('Europe/Sofia', 'Europe/Sofia'), ('Europe/Stockholm', 'Europe/Stockholm'), ('Europe/Tallinn', 'Europe/Tallinn'), ('Europe/Tirane', 'Europe/Tirane'), ('Europe/Ulyanovsk', 'Europe/Ulyanovsk'), ('Europe/Uzhgorod', 'Europe/Uzhgorod'), ('Europe/Vaduz', 'Europe/Vaduz'), ('Europe/Vatican', 'Europe/Vatican'), ('Europe/Vienna', 'Europe/Vienna'), ('Europe/Vilnius', 'Europe/Vilnius'), ('Europe/Volgograd', 'Europe/Volgograd'), ('Europe/Warsaw', 'Europe/Warsaw'), ('Europe/Zagreb', 'Europe/Zagreb'), ('Europe/Zaporozhye', 'Europe/Zaporozhye'), ('Europe/Zurich', 'Europe/Zurich'), ('GMT', 'GMT'), ('Indian/Antananarivo', 'Indian/Antananarivo'), ('Indian/Chagos', 'Indian/Chagos'), ('Indian/Christmas', 'Indian/Christmas'), ('Indian/Cocos', 'Indian/Cocos'), ('Indian/Comoro', 'Indian/Comoro'), ('Indian/Kerguelen', 'Indian/Kerguelen'), ('Indian/Mahe', 'Indian/Mahe'), ('Indian/Maldives', 'Indian/Maldives'), ('Indian/Mauritius', 'Indian/Mauritius'), ('Indian/Mayotte', 'Indian/Mayotte'), ('Indian/Reunion', 'Indian/Reunion'), ('Pacific/Apia', 'Pacific/Apia'), ('Pacific/Auckland', 'Pacific/Auckland'), ('Pacific/Bougainville', 'Pacific/Bougainville'), ('Pacific/Chatham', 'Pacific/Chatham'), ('Pacific/Chuuk', 'Pacific/Chuuk'), ('Pacific/Easter', 'Pacific/Easter'), ('Pacific/Efate', 'Pacific/Efate'), ('Pacific/Enderbury', 'Pacific/Enderbury'), ('Pacific/Fakaofo', 'Pacific/Fakaofo'), ('Pacific/Fiji', 'Pacific/Fiji'), ('Pacific/Funafuti', 'Pacific/Funafuti'), ('Pacific/Galapagos', 'Pacific/Galapagos'), ('Pacific/Gambier', 'Pacific/Gambier'), ('Pacific/Guadalcanal', 'Pacific/Guadalcanal'), ('Pacific/Guam', 'Pacific/Guam'), ('Pacific/Honolulu', 'Pacific/Honolulu'), ('Pacific/Johnston', 'Pacific/Johnston'), ('Pacific/Kiritimati', 'Pacific/Kiritimati'), ('Pacific/Kosrae', 'Pacific/Kosrae'), ('Pacific/Kwajalein', 'Pacific/Kwajalein'), ('Pacific/Majuro', 'Pacific/Majuro'), ('Pacific/Marquesas', 'Pacific/Marquesas'), ('Pacific/Midway', 'Pacific/Midway'), ('Pacific/Nauru', 'Pacific/Nauru'), ('Pacific/Niue', 'Pacific/Niue'), ('Pacific/Norfolk', 'Pacific/Norfolk'), ('Pacific/Noumea', 'Pacific/Noumea'), ('Pacific/Pago_Pago', 'Pacific/Pago_Pago'), ('Pacific/Palau', 'Pacific/Palau'), ('Pacific/Pitcairn', 'Pacific/Pitcairn'), ('Pacific/Pohnpei', 'Pacific/Pohnpei'), ('Pacific/Port_Moresby', 'Pacific/Port_Moresby'), ('Pacific/Rarotonga', 'Pacific/Rarotonga'), ('Pacific/Saipan', 'Pacific/Saipan'), ('Pacific/Tahiti', 'Pacific/Tahiti'), ('Pacific/Tarawa', 'Pacific/Tarawa'), ('Pacific/Tongatapu', 'Pacific/Tongatapu'), ('Pacific/Wake', 'Pacific/Wake'), ('Pacific/Wallis', 'Pacific/Wallis'), ('US/Alaska', 'US/Alaska'), ('US/Arizona', 'US/Arizona'), ('US/Central', 'US/Central'), ('US/Eastern', 'US/Eastern'), ('US/Hawaii', 'US/Hawaii'), ('US/Mountain', 'US/Mountain'), ('US/Pacific', 'US/Pacific'), ('UTC', 'UTC')], default='UTC', max_length=64)), + ('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ], + ), + migrations.CreateModel( + name='Question', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('summary', models.CharField(max_length=256)), + ('description', models.TextField()), + ('points', models.FloatField(default=1.0)), + ('language', models.CharField(choices=[('python', 'Python'), ('bash', 'Bash'), ('c', 'C Language'), ('cpp', 'C++ Language'), ('java', 'Java Language'), ('scilab', 'Scilab')], max_length=24)), + ('type', models.CharField(choices=[('mcq', 'Multiple Choice'), ('mcc', 'Multiple Correct Choices'), ('code', 'Code'), ('upload', 'Assignment Upload')], max_length=24)), + ('active', models.BooleanField(default=True)), + ('snippet', models.CharField(blank=True, max_length=256)), + ('partial_grading', models.BooleanField(default=False)), + ('tags', taggit.managers.TaggableManager(blank=True, help_text='A comma-separated list of tags.', through='taggit.TaggedItem', to='taggit.Tag', verbose_name='Tags')), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='user', to=settings.AUTH_USER_MODEL)), + ], + ), + migrations.CreateModel( + name='QuestionPaper', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('shuffle_questions', models.BooleanField(default=False)), + ('total_marks', models.FloatField(blank=True, default=0.0)), + ('fixed_questions', models.ManyToManyField(to='yaksh.Question')), + ], + ), + migrations.CreateModel( + name='QuestionSet', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('marks', models.FloatField()), + ('num_questions', models.IntegerField()), + ('questions', models.ManyToManyField(to='yaksh.Question')), + ], + ), + migrations.CreateModel( + name='Quiz', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('start_date_time', models.DateTimeField(default=django.utils.timezone.now, null=True, verbose_name='Start Date and Time of the quiz')), + ('end_date_time', models.DateTimeField(default=datetime.datetime(2199, 1, 1, 0, 0, tzinfo=utc), null=True, verbose_name='End Date and Time of the quiz')), + ('duration', models.IntegerField(default=20, verbose_name='Duration of quiz in minutes')), + ('active', models.BooleanField(default=True)), + ('description', models.CharField(max_length=256)), + ('pass_criteria', models.FloatField(default=40, verbose_name='Passing percentage')), + ('language', models.CharField(choices=[('python', 'Python'), ('bash', 'Bash'), ('c', 'C Language'), ('cpp', 'C++ Language'), ('java', 'Java Language'), ('scilab', 'Scilab')], max_length=20)), + ('attempts_allowed', models.IntegerField(choices=[(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (-1, 'Infinite')], default=1)), + ('time_between_attempts', models.IntegerField(choices=[(0, 0), (1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6), (7, 7), (8, 8), (9, 9), (10, 10), (11, 11), (12, 12), (13, 13), (14, 14), (15, 15), (16, 16), (17, 17), (18, 18), (19, 19), (20, 20), (21, 21), (22, 22), (23, 23), (24, 24), (25, 25), (26, 26), (27, 27), (28, 28), (29, 29), (30, 30), (31, 31), (32, 32), (33, 33), (34, 34), (35, 35), (36, 36), (37, 37), (38, 38), (39, 39), (40, 40), (41, 41), (42, 42), (43, 43), (44, 44), (45, 45), (46, 46), (47, 47), (48, 48), (49, 49), (50, 50), (51, 51), (52, 52), (53, 53), (54, 54), (55, 55), (56, 56), (57, 57), (58, 58), (59, 59), (60, 60), (61, 61), (62, 62), (63, 63), (64, 64), (65, 65), (66, 66), (67, 67), (68, 68), (69, 69), (70, 70), (71, 71), (72, 72), (73, 73), (74, 74), (75, 75), (76, 76), (77, 77), (78, 78), (79, 79), (80, 80), (81, 81), (82, 82), (83, 83), (84, 84), (85, 85), (86, 86), (87, 87), (88, 88), (89, 89), (90, 90), (91, 91), (92, 92), (93, 93), (94, 94), (95, 95), (96, 96), (97, 97), (98, 98), (99, 99), (100, 100), (101, 101), (102, 102), (103, 103), (104, 104), (105, 105), (106, 106), (107, 107), (108, 108), (109, 109), (110, 110), (111, 111), (112, 112), (113, 113), (114, 114), (115, 115), (116, 116), (117, 117), (118, 118), (119, 119), (120, 120), (121, 121), (122, 122), (123, 123), (124, 124), (125, 125), (126, 126), (127, 127), (128, 128), (129, 129), (130, 130), (131, 131), (132, 132), (133, 133), (134, 134), (135, 135), (136, 136), (137, 137), (138, 138), (139, 139), (140, 140), (141, 141), (142, 142), (143, 143), (144, 144), (145, 145), (146, 146), (147, 147), (148, 148), (149, 149), (150, 150), (151, 151), (152, 152), (153, 153), (154, 154), (155, 155), (156, 156), (157, 157), (158, 158), (159, 159), (160, 160), (161, 161), (162, 162), (163, 163), (164, 164), (165, 165), (166, 166), (167, 167), (168, 168), (169, 169), (170, 170), (171, 171), (172, 172), (173, 173), (174, 174), (175, 175), (176, 176), (177, 177), (178, 178), (179, 179), (180, 180), (181, 181), (182, 182), (183, 183), (184, 184), (185, 185), (186, 186), (187, 187), (188, 188), (189, 189), (190, 190), (191, 191), (192, 192), (193, 193), (194, 194), (195, 195), (196, 196), (197, 197), (198, 198), (199, 199), (200, 200), (201, 201), (202, 202), (203, 203), (204, 204), (205, 205), (206, 206), (207, 207), (208, 208), (209, 209), (210, 210), (211, 211), (212, 212), (213, 213), (214, 214), (215, 215), (216, 216), (217, 217), (218, 218), (219, 219), (220, 220), (221, 221), (222, 222), (223, 223), (224, 224), (225, 225), (226, 226), (227, 227), (228, 228), (229, 229), (230, 230), (231, 231), (232, 232), (233, 233), (234, 234), (235, 235), (236, 236), (237, 237), (238, 238), (239, 239), (240, 240), (241, 241), (242, 242), (243, 243), (244, 244), (245, 245), (246, 246), (247, 247), (248, 248), (249, 249), (250, 250), (251, 251), (252, 252), (253, 253), (254, 254), (255, 255), (256, 256), (257, 257), (258, 258), (259, 259), (260, 260), (261, 261), (262, 262), (263, 263), (264, 264), (265, 265), (266, 266), (267, 267), (268, 268), (269, 269), (270, 270), (271, 271), (272, 272), (273, 273), (274, 274), (275, 275), (276, 276), (277, 277), (278, 278), (279, 279), (280, 280), (281, 281), (282, 282), (283, 283), (284, 284), (285, 285), (286, 286), (287, 287), (288, 288), (289, 289), (290, 290), (291, 291), (292, 292), (293, 293), (294, 294), (295, 295), (296, 296), (297, 297), (298, 298), (299, 299), (300, 300), (301, 301), (302, 302), (303, 303), (304, 304), (305, 305), (306, 306), (307, 307), (308, 308), (309, 309), (310, 310), (311, 311), (312, 312), (313, 313), (314, 314), (315, 315), (316, 316), (317, 317), (318, 318), (319, 319), (320, 320), (321, 321), (322, 322), (323, 323), (324, 324), (325, 325), (326, 326), (327, 327), (328, 328), (329, 329), (330, 330), (331, 331), (332, 332), (333, 333), (334, 334), (335, 335), (336, 336), (337, 337), (338, 338), (339, 339), (340, 340), (341, 341), (342, 342), (343, 343), (344, 344), (345, 345), (346, 346), (347, 347), (348, 348), (349, 349), (350, 350), (351, 351), (352, 352), (353, 353), (354, 354), (355, 355), (356, 356), (357, 357), (358, 358), (359, 359), (360, 360), (361, 361), (362, 362), (363, 363), (364, 364), (365, 365), (366, 366), (367, 367), (368, 368), (369, 369), (370, 370), (371, 371), (372, 372), (373, 373), (374, 374), (375, 375), (376, 376), (377, 377), (378, 378), (379, 379), (380, 380), (381, 381), (382, 382), (383, 383), (384, 384), (385, 385), (386, 386), (387, 387), (388, 388), (389, 389), (390, 390), (391, 391), (392, 392), (393, 393), (394, 394), (395, 395), (396, 396), (397, 397), (398, 398), (399, 399), (400, 400)], verbose_name='Number of Days')), + ('is_trial', models.BooleanField(default=False)), + ('instructions', models.TextField(blank=True, default=None, null=True, verbose_name='Instructions for Students')), + ('view_answerpaper', models.BooleanField(default=False, verbose_name='Allow student to view their answer paper')), + ('allow_skip', models.BooleanField(default=True, verbose_name='Allow students to skip questions')), + ('course', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='yaksh.Course')), + ('prerequisite', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='yaksh.Quiz')), + ], + options={ + 'verbose_name_plural': 'Quizzes', + }, + ), + migrations.CreateModel( + name='TestCase', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('type', models.CharField(choices=[('standardtestcase', 'Standard Testcase'), ('stdiobasedtestcase', 'StdIO Based Testcase'), ('mcqtestcase', 'MCQ Testcase'), ('hooktestcase', 'Hook Testcase')], max_length=24, null=True)), + ], + ), + migrations.CreateModel( + name='HookTestCase', + fields=[ + ('testcase_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='yaksh.TestCase')), + ('hook_code', 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 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')), + ('weight', models.FloatField(default=1.0)), + ], + bases=('yaksh.testcase',), + ), + migrations.CreateModel( + name='McqTestCase', + fields=[ + ('testcase_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='yaksh.TestCase')), + ('options', models.TextField(default=None)), + ('correct', models.BooleanField(default=False)), + ], + bases=('yaksh.testcase',), + ), + migrations.CreateModel( + name='StandardTestCase', + fields=[ + ('testcase_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='yaksh.TestCase')), + ('test_case', models.TextField()), + ('weight', models.FloatField(default=1.0)), + ('test_case_args', models.TextField(blank=True)), + ], + bases=('yaksh.testcase',), + ), + migrations.CreateModel( + name='StdIOBasedTestCase', + fields=[ + ('testcase_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='yaksh.TestCase')), + ('expected_input', models.TextField(blank=True, default=None, null=True)), + ('expected_output', models.TextField(default=None)), + ('weight', models.IntegerField(default=1.0)), + ], + bases=('yaksh.testcase',), + ), + migrations.AddField( + model_name='testcase', + name='question', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='yaksh.Question'), + ), + migrations.AddField( + model_name='questionpaper', + name='quiz', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='yaksh.Quiz'), + ), + migrations.AddField( + model_name='questionpaper', + name='random_questions', + field=models.ManyToManyField(to='yaksh.QuestionSet'), + ), + migrations.AddField( + model_name='fileupload', + name='question', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='question', to='yaksh.Question'), + ), + migrations.AddField( + model_name='assignmentupload', + name='assignmentQuestion', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='yaksh.Question'), + ), + migrations.AddField( + model_name='assignmentupload', + name='user', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='yaksh.Profile'), + ), + migrations.AddField( + model_name='answerpaper', + name='question_paper', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='yaksh.QuestionPaper'), + ), + migrations.AddField( + model_name='answerpaper', + name='questions', + field=models.ManyToManyField(related_name='questions', to='yaksh.Question'), + ), + migrations.AddField( + model_name='answerpaper', + name='questions_answered', + field=models.ManyToManyField(related_name='questions_answered', to='yaksh.Question'), + ), + migrations.AddField( + model_name='answerpaper', + name='questions_unanswered', + field=models.ManyToManyField(related_name='questions_unanswered', to='yaksh.Question'), + ), + migrations.AddField( + model_name='answerpaper', + name='user', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL), + ), + migrations.AddField( + model_name='answer', + name='question', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='yaksh.Question'), + ), + ] -- cgit From df12682919a5b7b1e3acc8f27a3cd6020b990ff9 Mon Sep 17 00:00:00 2001 From: maheshgudi Date: Wed, 15 Mar 2017 00:51:58 +0530 Subject: Added mathjax support for quiz and answerpapers --- yaksh/templates/yaksh/add_question.html | 1 + yaksh/templates/yaksh/grade_user.html | 15 ++++++++++++++- yaksh/templates/yaksh/question.html | 1 + yaksh/templates/yaksh/user_data.html | 20 ++++++++++++++++---- yaksh/templates/yaksh/view_answerpaper.html | 14 +++++++++++--- 5 files changed, 43 insertions(+), 8 deletions(-) (limited to 'yaksh') diff --git a/yaksh/templates/yaksh/add_question.html b/yaksh/templates/yaksh/add_question.html index 75802b4..b01ddc3 100644 --- a/yaksh/templates/yaksh/add_question.html +++ b/yaksh/templates/yaksh/add_question.html @@ -8,6 +8,7 @@ {% block script %} + {% endblock %} {% block onload %} onload='javascript:textareaformat();' {% endblock %} diff --git a/yaksh/templates/yaksh/grade_user.html b/yaksh/templates/yaksh/grade_user.html index 63ff5eb..d20695b 100644 --- a/yaksh/templates/yaksh/grade_user.html +++ b/yaksh/templates/yaksh/grade_user.html @@ -4,6 +4,11 @@ {% block content %} +{% block script %} + +{% endblock script %} + + {% if course_details %} @@ -160,7 +165,15 @@ Status : Passed
{{ err }}
{% endfor %} -
{{ ans.answer.answer.strip|safe }}
+
+ {% if question.type != "code" %} +
+ {{ ans.answer.answer.strip|safe }} +
+ {% else %} +
{{ ans.answer.answer.strip|safe }}
+ {% endif %} +
{% endfor %} {% with answers|last as answer %} diff --git a/yaksh/templates/yaksh/question.html b/yaksh/templates/yaksh/question.html index 9dd0de5..eaaacbf 100644 --- a/yaksh/templates/yaksh/question.html +++ b/yaksh/templates/yaksh/question.html @@ -19,6 +19,7 @@ + + + {% endblock %} @@ -83,7 +84,7 @@ User IP address: {{ paper.user_ip }} {%endif%} - {% if question.type == "mcq" or question.type == "mcc" %} + {% if question.type != "code" %} {% if "Correct answer" in answers.0.error_list %}
{% else %} @@ -94,7 +95,9 @@ User IP address: {{ paper.user_ip }}
Student answer:
-
{{forloop.counter}}. {{ answers.0.answer|safe }}
+
+ {{ answers.0.answer|safe }} +
{% else %} @@ -114,7 +117,16 @@ User IP address: {{ paper.user_ip }} {% endif %} -
{{ answer.answer.answer.strip }}
+
+ {% if question.type != "code" %} +
+ {{question.type}} + {{ answer.answer.answer.strip|safe }} +
+ {% else %} +
{{ answer.answer.answer.strip|safe }}
+ {% endif %} +
{% endfor %} diff --git a/yaksh/templates/yaksh/view_answerpaper.html b/yaksh/templates/yaksh/view_answerpaper.html index 5eb55df..f4edf67 100644 --- a/yaksh/templates/yaksh/view_answerpaper.html +++ b/yaksh/templates/yaksh/view_answerpaper.html @@ -2,6 +2,10 @@ {% block pagetitle %} Answer Paper for {{ quiz.description }}{% endblock pagetitle %} +{% block script %} + +{% endblock script %} + {% block main %} {% if not data.papers %} @@ -60,7 +64,7 @@ - {% if question.type == "mcq" or question.type == "mcc" %} + {% if question.type != "code" %} {% if "Correct answer" in answers.0.error_list %}
{% else %} @@ -71,7 +75,9 @@
Student answer:
-
{{forloop.counter}}. {{ answers.0.answer|safe }}
+
+ {{ answers.0.answer|safe }} +
{% else %} @@ -84,7 +90,9 @@
{% endif %}
Autocheck: {{ answer.error }}
-
{{ answer.answer.strip }}
+
+
{{ answer.answer.answer.strip }}
+
{% endif %} {% endfor %} -- cgit From 24db3d6821fba560da4c3a4ca03f96ba6daae5a6 Mon Sep 17 00:00:00 2001 From: ankitjavalkar Date: Wed, 15 Mar 2017 16:48:28 +0530 Subject: Multiple fixes in stdio_evaluator and models: - Change the way stdio output is printed - Fix minor errors when creating the uploaded file path in the models --- yaksh/models.py | 2 +- yaksh/stdio_evaluator.py | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) (limited to 'yaksh') diff --git a/yaksh/models.py b/yaksh/models.py index 398f508..103504e 100644 --- a/yaksh/models.py +++ b/yaksh/models.py @@ -66,7 +66,7 @@ test_status = ( def get_assignment_dir(instance, filename): return os.sep.join(( - instance.user.user, instance.assignmentQuestion.id, filename + instance.user.user.username, str(instance.assignmentQuestion.id), filename )) diff --git a/yaksh/stdio_evaluator.py b/yaksh/stdio_evaluator.py index fb9dfb3..fa78a68 100644 --- a/yaksh/stdio_evaluator.py +++ b/yaksh/stdio_evaluator.py @@ -14,17 +14,17 @@ class StdIOEvaluator(BaseEvaluator): output_err = output_err_bytes.decode('utf-8') expected_output = expected_output.replace("\r", "") if not expected_input: - error_msg = "Expected Output is {0} ".\ - format(repr(expected_output)) + error_msg = "Expected Output is\n{0} ".\ + format(str(expected_output)) else: - error_msg = " Given Input is\n {0} \n Expected Output is {1} ".\ - format(expected_input, repr(expected_output)) + error_msg = "Given Input is\n{0}\nExpected Output is\n{1}".\ + format(expected_input, str(expected_output)) if output_err == '': if user_output == expected_output: success, err = True, None else: - err = " Incorrect answer\n" + error_msg +\ - "\n Your output is {0}".format(repr(user_output)) + err = "Incorrect answer:\n" + error_msg +\ + "\nYour output is\n{0}".format(str(user_output)) else: - err = "Error:\n {0}".format(output_err) + err = "Error:\n{0}".format(output_err) return success, err -- cgit From b37244f2c6573b0f16b9dcea614400ee1ae24cf8 Mon Sep 17 00:00:00 2001 From: adityacp Date: Thu, 16 Mar 2017 16:43:12 +0530 Subject: Changes in models views and urls - Handle Json parsing error - Remove Sample file download from views and urls --- yaksh/models.py | 30 ++++++++++++++++++------------ yaksh/urls.py | 1 - yaksh/views.py | 13 ------------- 3 files changed, 18 insertions(+), 26 deletions(-) (limited to 'yaksh') diff --git a/yaksh/models.py b/yaksh/models.py index 0a84d4e..dc015d5 100644 --- a/yaksh/models.py +++ b/yaksh/models.py @@ -318,17 +318,19 @@ class Question(models.Model): file_names = question.pop('files') test_cases = question.pop('testcase') que, result = Question.objects.get_or_create(**question) - if file_names: - que._add_files_to_db(file_names, file_path) - for test_case in test_cases: - test_case_type = test_case.pop('test_case_type') - model_class = get_model_class(test_case_type) - new_test_case, obj_create_status = \ - model_class.objects.get_or_create( - question=que, **test_case - ) - new_test_case.type = test_case_type - new_test_case.save() + if not result: + if file_names: + que._add_files_to_db(file_names, file_path) + for test_case in test_cases: + test_case_type = test_case.pop('test_case_type') + model_class = get_model_class(test_case_type) + new_test_case, obj_create_status = \ + model_class.objects.get_or_create( + question=que, **test_case + ) + new_test_case.type = test_case_type + new_test_case.save() + if files_list: delete_files(files_list, file_path) @@ -401,7 +403,11 @@ class Question(models.Model): if os.path.exists(json_file): with open(json_file, 'r') as q_file: questions_list = q_file.read() - self.load_questions(questions_list, user, file_path, files) + try: + self.load_questions(questions_list, user, file_path, files) + except ValueError: + return "Syntax Error in Json. Please check your json file." + return "Questions Uploaded Successfully" else: return "Please upload zip file with questions_dump.json in it." diff --git a/yaksh/urls.py b/yaksh/urls.py index e7a3a66..ad58985 100644 --- a/yaksh/urls.py +++ b/yaksh/urls.py @@ -28,7 +28,6 @@ urlpatterns = [ url(r'^view_answerpaper/(?P\d+)/$', views.view_answerpaper, name='view_answerpaper'), url(r'^manage/$', views.prof_manage, name='manage'), url(r'^manage/addquestion/$', views.add_question), - url(r'^manage/download_demo_question/$', views.download_demo_questions), url(r'^manage/addquestion/(?P\d+)/$', views.add_question), url(r'^manage/addquiz/(?P\d+)/$', views.add_quiz, name='add_quiz'), url(r'^manage/addquiz/(?P\d+)/(?P\d+)/$', views.add_quiz, name='edit_quiz'), diff --git a/yaksh/views.py b/yaksh/views.py index 02019f4..daa81eb 100644 --- a/yaksh/views.py +++ b/yaksh/views.py @@ -30,7 +30,6 @@ from yaksh.forms import UserRegisterForm, UserLoginForm, QuizForm,\ QuestionFilterForm, CourseForm, ProfileForm, UploadFileForm,\ get_object_form, FileForm, QuestionPaperForm from .settings import URL_ROOT -from django.conf import settings from yaksh.models import AssignmentUpload from .file_utils import extract_files @@ -949,18 +948,6 @@ def show_all_questions(request): return my_render_to_response('yaksh/showquestions.html', context, context_instance=ci) -@login_required -def download_demo_questions(request): - user = request.user - if not is_moderator(user): - raise Http404("You are not allowed to download!") - f_path = os.path.join(settings.FIXTURE_DIRS, "demo_questions.zip") - zip_file = open(f_path, "rb") - response = HttpResponse(zip_file, content_type='application/zip') - response['Content-Disposition'] = '''attachment;\ - filename=demo_questions.zip''' - return response - @login_required def user_data(request, user_id, questionpaper_id=None): """Render user data.""" -- cgit From 7d568d24514cfc67a149b1eae80ba3d8490c1016 Mon Sep 17 00:00:00 2001 From: adityacp Date: Thu, 16 Mar 2017 16:45:37 +0530 Subject: Remove link for sample download of questions upload --- yaksh/templates/yaksh/showquestions.html | 4 ---- 1 file changed, 4 deletions(-) (limited to 'yaksh') diff --git a/yaksh/templates/yaksh/showquestions.html b/yaksh/templates/yaksh/showquestions.html index 73612d5..157b378 100644 --- a/yaksh/templates/yaksh/showquestions.html +++ b/yaksh/templates/yaksh/showquestions.html @@ -10,10 +10,6 @@ {% block content %} -

Please Download Sample Zip file to view zip file contents before uploading -Questions

-Sample Zip File -

Upload ZIP file for adding questions

{% csrf_token %} -- cgit From eb3afa3b86ca7a129c9d1365e0ae7946b0c25d32 Mon Sep 17 00:00:00 2001 From: adityacp Date: Thu, 16 Mar 2017 16:46:29 +0530 Subject: Change docs with method for uploading questions --- .../moderator_docs/creating_question.rst | 31 ++++++++++++++++++++++ 1 file changed, 31 insertions(+) (limited to 'yaksh') diff --git a/yaksh/documentation/moderator_docs/creating_question.rst b/yaksh/documentation/moderator_docs/creating_question.rst index f99bf7f..94bb95c 100644 --- a/yaksh/documentation/moderator_docs/creating_question.rst +++ b/yaksh/documentation/moderator_docs/creating_question.rst @@ -264,6 +264,37 @@ Features in Question Click on the browse button. This will open up a window. Select the zip file of questions and click Ok and then click on Upload file button, questions will be uploaded and displayed on the Questions page. + Zip file should contain **questions_dump.json** from which questions will be loaded. + Zip file can contain files related to questions. + Sample entry in **questions_dump.json** is as shown below. :: + [{ + "snippet": "", + "testcase": [ + { + "test_case_args": "", + "test_case_type": "standardtestcase", + "weight": 1.0, + "test_case": "Test Case here" + }, + ], + "points": 2.0, + "description": "Question Description here", + "language": "python", + "active": true, + "type": "code", + "files": [[demo1.txt, false], [demo2.zip, true]], + "summary": "Question Summary here" + }] + + .. Note:: 1. In **files** entry in json, the list contains two items which + are filename (demo1.txt) and extract status (false) i.e file needs to extracted or not. + + 2. If there are no files then **files** entry can be empty + i.e it should be "files": []. + + 3. From sample, zip file should contain demo1.txt and demo2.zip since it is + required for question. + * **Test Questions** Select questions from the list of question displayed on the Questions page. Click on Test selected button. This will take you to a quiz with the selected questions. -- cgit From 69ab40cc3d4d769d0d3f1c783f950cac52f7935e Mon Sep 17 00:00:00 2001 From: adityacp Date: Thu, 16 Mar 2017 17:15:38 +0530 Subject: Fix test cases for loading questions --- yaksh/models.py | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) (limited to 'yaksh') diff --git a/yaksh/models.py b/yaksh/models.py index dc015d5..c10f953 100644 --- a/yaksh/models.py +++ b/yaksh/models.py @@ -318,18 +318,17 @@ class Question(models.Model): file_names = question.pop('files') test_cases = question.pop('testcase') que, result = Question.objects.get_or_create(**question) - if not result: - if file_names: - que._add_files_to_db(file_names, file_path) - for test_case in test_cases: - test_case_type = test_case.pop('test_case_type') - model_class = get_model_class(test_case_type) - new_test_case, obj_create_status = \ - model_class.objects.get_or_create( - question=que, **test_case - ) - new_test_case.type = test_case_type - new_test_case.save() + if file_names: + que._add_files_to_db(file_names, file_path) + for test_case in test_cases: + test_case_type = test_case.pop('test_case_type') + model_class = get_model_class(test_case_type) + new_test_case, obj_create_status = \ + model_class.objects.get_or_create( + question=que, **test_case + ) + new_test_case.type = test_case_type + new_test_case.save() if files_list: delete_files(files_list, file_path) -- cgit From 8547c5bfe7be64256b412f484ab6a9f60628ef06 Mon Sep 17 00:00:00 2001 From: adityacp Date: Thu, 16 Mar 2017 19:00:48 +0530 Subject: Handle json file syntax errors in uploading question --- yaksh/models.py | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) (limited to 'yaksh') diff --git a/yaksh/models.py b/yaksh/models.py index c10f953..80e215e 100644 --- a/yaksh/models.py +++ b/yaksh/models.py @@ -15,6 +15,8 @@ except ImportError: from io import BytesIO as string_io import pytz import os +import sys +import traceback import stat from os.path import join, exists import shutil @@ -312,7 +314,13 @@ class Question(models.Model): def load_questions(self, questions_list, user, file_path=None, files_list=None): - questions = json.loads(questions_list) + try: + questions = json.loads(questions_list) + except json.decoder.JSONDecodeError: + exc_type, exc_value, exc_tb = sys.exc_info() + tb_list = traceback.format_exception(exc_type, exc_value, exc_tb) + msg = "Error Parsing Json: {0}".format(tb_list[-1]) + return msg for question in questions: question['user'] = user file_names = question.pop('files') @@ -329,9 +337,7 @@ class Question(models.Model): ) new_test_case.type = test_case_type new_test_case.save() - - if files_list: - delete_files(files_list, file_path) + return "Questions Uploaded Successfully" def get_test_cases(self, **kwargs): tc_list = [] @@ -399,17 +405,17 @@ class Question(models.Model): def read_json(self, file_path, user, files=None): json_file = os.path.join(file_path, "questions_dump.json") + msg = "" if os.path.exists(json_file): with open(json_file, 'r') as q_file: questions_list = q_file.read() - try: - self.load_questions(questions_list, user, file_path, files) - except ValueError: - return "Syntax Error in Json. Please check your json file." - - return "Questions Uploaded Successfully" + msg = self.load_questions(questions_list, user, file_path, files) else: - return "Please upload zip file with questions_dump.json in it." + msg = "Please upload zip file with questions_dump.json in it." + + if files: + delete_files(files, file_path) + return msg def create_demo_questions(self, user): zip_file_path = os.path.join( -- cgit From 6c53c90ee5dd7184889fd3f99130b194e75fef4c Mon Sep 17 00:00:00 2001 From: adityacp Date: Fri, 17 Mar 2017 13:57:21 +0530 Subject: Change Exception message for load questions --- yaksh/models.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'yaksh') diff --git a/yaksh/models.py b/yaksh/models.py index 80e215e..970f136 100644 --- a/yaksh/models.py +++ b/yaksh/models.py @@ -316,10 +316,8 @@ class Question(models.Model): files_list=None): try: questions = json.loads(questions_list) - except json.decoder.JSONDecodeError: - exc_type, exc_value, exc_tb = sys.exc_info() - tb_list = traceback.format_exception(exc_type, exc_value, exc_tb) - msg = "Error Parsing Json: {0}".format(tb_list[-1]) + except ValueError as exc_msg: + msg = "Error Parsing Json: {0}".format(exc_msg) return msg for question in questions: question['user'] = user -- cgit