summaryrefslogtreecommitdiff
path: root/yaksh/views.py
diff options
context:
space:
mode:
Diffstat (limited to 'yaksh/views.py')
-rw-r--r--yaksh/views.py240
1 files changed, 132 insertions, 108 deletions
diff --git a/yaksh/views.py b/yaksh/views.py
index d8d630b..3341aca 100644
--- a/yaksh/views.py
+++ b/yaksh/views.py
@@ -1,30 +1,20 @@
-import random
-import string
import os
-from datetime import datetime, timedelta
-import collections
import csv
from django.http import HttpResponse, JsonResponse
-from django.core.urlresolvers import reverse
from django.contrib.auth import login, logout, authenticate
from django.shortcuts import render, get_object_or_404, redirect
-from django.template import RequestContext, Context, Template
-from django.template.loader import get_template, render_to_string
+from django.template import Context, Template
from django.http import Http404
-from django.db.models import Sum, Max, Q, F
+from django.db.models import Max, Q, F
from django.views.decorators.csrf import csrf_exempt
from django.contrib.auth.decorators import login_required
from django.contrib.auth.models import Group
from django.forms.models import inlineformset_factory
from django.utils import timezone
-from django.core.validators import URLValidator
from django.core.exceptions import (
- MultipleObjectsReturned, ObjectDoesNotExist, ValidationError
+ MultipleObjectsReturned, ObjectDoesNotExist
)
-from django.conf import settings
-import pytz
from taggit.models import Tag
-from itertools import chain
import json
import six
from textwrap import dedent
@@ -38,24 +28,22 @@ import re
# Local imports.
from yaksh.code_server import get_result as get_result_from_code_server
from yaksh.models import (
- Answer, AnswerPaper, AssignmentUpload, Course, FileUpload, FloatTestCase,
- HookTestCase, IntegerTestCase, McqTestCase, Profile,
- QuestionPaper, QuestionSet, Quiz, Question, StandardTestCase,
- StdIOBasedTestCase, StringTestCase, TestCase, User,
- get_model_class, FIXTURES_DIR_PATH, Lesson, LessonFile,
- LearningUnit, LearningModule,
+ Answer, AnswerPaper, AssignmentUpload, Course, FileUpload, Profile,
+ QuestionPaper, QuestionSet, Quiz, Question, TestCase, User,
+ FIXTURES_DIR_PATH, Lesson, LessonFile, LearningUnit, LearningModule,
CourseStatus
)
from yaksh.forms import (
UserRegisterForm, UserLoginForm, QuizForm, QuestionForm,
- RandomQuestionForm, QuestionFilterForm, CourseForm, ProfileForm,
- UploadFileForm, get_object_form, FileForm, QuestionPaperForm, LessonForm,
+ QuestionFilterForm, CourseForm, ProfileForm,
+ UploadFileForm, FileForm, QuestionPaperForm, LessonForm,
LessonFileForm, LearningModuleForm, ExerciseForm
)
-from yaksh.settings import SERVER_POOL_PORT, SERVER_HOST_NAME
+from yaksh.settings import SERVER_POOL_PORT, SERVER_HOST_NAME
from .settings import URL_ROOT
from .file_utils import extract_files, is_csv
-from .send_emails import send_user_mail, generate_activation_key, send_bulk_mail
+from .send_emails import (send_user_mail,
+ generate_activation_key, send_bulk_mail)
from .decorators import email_verified, has_profile
@@ -88,8 +76,9 @@ def add_to_group(users):
if not is_moderator(user):
user.groups.add(group)
+
CSV_FIELDS = ['name', 'username', 'roll_number', 'institute', 'department',
- 'questions', 'marks_obtained', 'out_of', 'percentage', 'status']
+ 'questions', 'marks_obtained', 'out_of', 'percentage', 'status']
def get_html_text(md_text):
@@ -121,7 +110,6 @@ def user_register(request):
if request.method == "POST":
form = UserRegisterForm(request.POST)
if form.is_valid():
- data = form.cleaned_data
u_name, pwd, user_email, key = form.save()
new_user = authenticate(username=u_name, password=pwd)
login(request, new_user)
@@ -549,7 +537,7 @@ def start(request, questionpaper_id=None, attempt_num=None, course_id=None,
raise Http404(msg)
new_paper = quest_paper.make_answerpaper(user, ip, attempt_number,
course_id)
- if new_paper.status == 'inprogress':
+ if new_paper.status == 'inprogress':
return show_question(
request, new_paper.current_question(),
new_paper, course_id=course_id,
@@ -559,12 +547,13 @@ def start(request, questionpaper_id=None, attempt_num=None, course_id=None,
msg = 'You have already finished the quiz!'
raise Http404(msg)
+
@login_required
@email_verified
-def show_question(request, question, paper, error_message=None, notification=None,
- course_id=None, module_id=None, previous_question=None):
+def show_question(request, question, paper, error_message=None,
+ notification=None, course_id=None, module_id=None,
+ previous_question=None):
"""Show a question if possible."""
- user = request.user
quiz = paper.question_paper.quiz
quiz_type = 'Exam'
can_skip = False
@@ -574,7 +563,8 @@ def show_question(request, question, paper, error_message=None, notification=Non
delay_time = paper.time_left_on_question(question)
if previous_question and quiz.is_exercise:
- if delay_time <= 0 or previous_question in paper.questions_answered.all():
+ if (delay_time <= 0 or previous_question in
+ paper.questions_answered.all()):
can_skip = True
question = previous_question
if not question:
@@ -640,7 +630,6 @@ def show_question(request, question, paper, error_message=None, notification=Non
@email_verified
def skip(request, q_id, next_q=None, attempt_num=None, questionpaper_id=None,
course_id=None, module_id=None):
- user = request.user
paper = get_object_or_404(
AnswerPaper, user=request.user, attempt_number=attempt_num,
question_paper=questionpaper_id, course_id=course_id
@@ -727,7 +716,7 @@ def check(request, q_id, attempt_num=None, questionpaper_id=None,
previous_question=current_question
)
for fname in assignment_filename:
- fname._name = fname._name.replace(" ","_")
+ fname._name = fname._name.replace(" ", "_")
assignment_files = AssignmentUpload.objects.filter(
assignmentQuestion=current_question,
assignmentFile__icontains=fname, user=user,
@@ -766,34 +755,36 @@ def check(request, q_id, attempt_num=None, questionpaper_id=None,
previous_question=current_question
)
if current_question in paper.get_questions_answered()\
- and current_question.type not in ['code', 'upload']:
+ and current_question.type not in ['code', 'upload']:
new_answer = paper.get_latest_answer(current_question.id)
new_answer.answer = user_answer
new_answer.correct = False
else:
new_answer = Answer(
- question=current_question, answer=user_answer,
- correct=False, error=json.dumps([])
- )
+ question=current_question, answer=user_answer,
+ correct=False, error=json.dumps([])
+ )
new_answer.save()
uid = new_answer.id
paper.answers.add(new_answer)
# If we were not skipped, we were asked to check. For any non-mcq
# questions, we obtain the results via XML-RPC with the code executed
# safely in a separate process (the code_server.py) running as nobody.
- json_data = current_question.consolidate_answer_data(user_answer, user) \
- if current_question.type == 'code' or \
+ json_data = current_question.consolidate_answer_data(
+ user_answer, user) if current_question.type == 'code' or \
current_question.type == 'upload' else None
result = paper.validate_answer(
user_answer, current_question, json_data, uid
)
if current_question.type in ['code', 'upload']:
- if paper.time_left() <= 0 and not paper.question_paper.quiz.is_exercise:
+ if (paper.time_left() <= 0 and not
+ paper.question_paper.quiz.is_exercise):
url = '{0}:{1}'.format(SERVER_HOST_NAME, SERVER_POOL_PORT)
- result_details = get_result_from_code_server(url, uid, block=True)
+ result_details = get_result_from_code_server(url, uid,
+ block=True)
result = json.loads(result_details.get('result'))
- next_question, error_message, paper = _update_paper(request, uid,
- result)
+ next_question, error_message, paper = _update_paper(
+ request, uid, result)
return show_question(request, next_question, paper,
error_message, course_id=course_id,
module_id=module_id,
@@ -801,7 +792,8 @@ def check(request, q_id, attempt_num=None, questionpaper_id=None,
else:
return JsonResponse(result)
else:
- next_question, error_message, paper = _update_paper(request, uid, result)
+ next_question, error_message, paper = _update_paper(
+ request, uid, result)
return show_question(request, next_question, paper, error_message,
course_id=course_id, module_id=module_id,
previous_question=current_question)
@@ -850,22 +842,25 @@ def _update_paper(request, uid, result):
if result.get('success'):
new_answer.marks = (current_question.points * result['weight'] /
- current_question.get_maximum_test_case_weight()) \
+ current_question.get_maximum_test_case_weight()) \
if current_question.partial_grading and \
- current_question.type == 'code' or current_question.type == 'upload' \
- else current_question.points
+ current_question.type == 'code' or \
+ current_question.type == 'upload' else current_question.points
new_answer.correct = result.get('success')
error_message = None
new_answer.error = json.dumps(result.get('error'))
next_question = paper.add_completed_question(current_question.id)
else:
new_answer.marks = (current_question.points * result['weight'] /
- current_question.get_maximum_test_case_weight()) \
+ current_question.get_maximum_test_case_weight()) \
if current_question.partial_grading and \
- current_question.type == 'code' or current_question.type == 'upload' \
+ current_question.type == 'code' or \
+ current_question.type == 'upload' \
else 0
- error_message = result.get('error') if current_question.type == 'code' \
- or current_question.type == 'upload' else None
+ error_message = result.get('error') \
+ if current_question.type == 'code' or \
+ current_question.type == 'upload' \
+ else None
new_answer.error = json.dumps(result.get('error'))
next_question = current_question if current_question.type == 'code' \
or current_question.type == 'upload' \
@@ -1301,20 +1296,19 @@ def design_questionpaper(request, quiz_id, questionpaper_id=None,
marks = None
state = None
if questionpaper_id is None:
- question_paper = QuestionPaper.objects.get_or_create(quiz_id=quiz_id)[0]
+ question_paper = QuestionPaper.objects.get_or_create(
+ quiz_id=quiz_id)[0]
else:
question_paper = get_object_or_404(QuestionPaper, id=questionpaper_id,
quiz_id=quiz_id)
qpaper_form = QuestionPaperForm(instance=question_paper)
if request.method == 'POST':
-
filter_form = QuestionFilterForm(request.POST, user=user)
qpaper_form = QuestionPaperForm(request.POST, instance=question_paper)
question_type = request.POST.get('question_type', None)
marks = request.POST.get('marks', None)
state = request.POST.get('is_active', None)
-
if 'add-fixed' in request.POST:
question_ids = request.POST.get('checked_ques', None)
if question_paper.fixed_question_order:
@@ -1345,10 +1339,11 @@ def design_questionpaper(request, quiz_id, questionpaper_id=None,
question_ids = request.POST.getlist('random_questions', None)
num_of_questions = request.POST.get('num_of_questions', 1)
if question_ids and marks:
- random_set = QuestionSet(marks=marks, num_questions=num_of_questions)
+ random_set = QuestionSet(marks=marks,
+ num_questions=num_of_questions)
random_set.save()
- for question in Question.objects.filter(id__in=question_ids):
- random_set.questions.add(question)
+ random_ques = Question.objects.filter(id__in=question_ids)
+ random_set.questions.add(*random_ques)
question_paper.random_questions.add(random_set)
if 'remove-random' in request.POST:
@@ -1395,7 +1390,7 @@ def show_all_questions(request):
questions = Question.objects.filter(user_id=user.id, active=True)
form = QuestionFilterForm(user=user)
user_tags = questions.values_list('tags', flat=True).distinct()
- all_tags = Tag.objects.filter(id__in = user_tags)
+ all_tags = Tag.objects.filter(id__in=user_tags)
upload_form = UploadFileForm()
context['questions'] = questions
context['all_tags'] = all_tags
@@ -1408,8 +1403,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()
@@ -1441,7 +1436,8 @@ def show_all_questions(request):
response.write(zip_file.read())
return response
else:
- context['msg'] = "Please select atleast one question to download"
+ context['msg'] = ("Please select atleast" +
+ "one question to download")
if request.POST.get('test') == 'test':
question_ids = request.POST.getlist("question")
@@ -1459,7 +1455,7 @@ def show_all_questions(request):
question_tags = request.POST.getlist("question_tags")
search_tags = []
for tags in question_tags:
- search_tags.extend(re.split('[; |, |\*|\n]',tags))
+ search_tags.extend(re.split('[; |, |\*|\n]', tags))
search_result = Question.objects.filter(tags__name__in=search_tags,
user=user).distinct()
context['questions'] = search_result
@@ -1485,8 +1481,9 @@ def _expand_questions(questions, field_list):
i = field_list.index('questions')
field_list.remove('questions')
for question in questions:
- field_list.insert(i, '{0}-{1}'.format(question.summary, question.points))
- return field_list
+ field_list.insert(
+ i, '{0}-{1}'.format(question.summary, question.points))
+ return field_list
@login_required
@@ -1497,7 +1494,8 @@ def download_quiz_csv(request, course_id, quiz_id):
raise Http404('You are not allowed to view this page!')
course = get_object_or_404(Course, id=course_id)
quiz = get_object_or_404(Quiz, id=quiz_id)
- if not course.is_creator(current_user) and not course.is_teacher(current_user):
+ if not course.is_creator(current_user) and \
+ not course.is_teacher(current_user):
raise Http404('The quiz does not belong to your course')
users = course.get_enrolled().order_by('first_name')
if not users:
@@ -1509,19 +1507,22 @@ def download_quiz_csv(request, course_id, quiz_id):
question_paper.id, course.id).last()
if request.method == 'POST':
csv_fields = request.POST.getlist('csv_fields')
- attempt_number = request.POST.get('attempt_number', last_attempt_number)
+ attempt_number = request.POST.get('attempt_number',
+ last_attempt_number)
if not csv_fields:
csv_fields = CSV_FIELDS
if not attempt_number:
attempt_number = last_attempt_number
questions = question_paper.get_question_bank()
- answerpapers = AnswerPaper.objects.filter(question_paper=question_paper,
- attempt_number=attempt_number, course_id=course_id)
+ answerpapers = AnswerPaper.objects.filter(
+ question_paper=question_paper,
+ attempt_number=attempt_number, course_id=course_id)
if not answerpapers:
return monitor(request, quiz_id, course_id)
response = HttpResponse(content_type='text/csv')
- response['Content-Disposition'] = 'attachment; filename="{0}-{1}-attempt{2}.csv"'.format(
+ response['Content-Disposition'] = \
+ 'attachment; filename="{0}-{1}-attempt{2}.csv"'.format(
course.name.replace('.', ''), quiz.description.replace('.', ''),
attempt_number)
writer = csv.writer(response)
@@ -1529,21 +1530,24 @@ def download_quiz_csv(request, course_id, quiz_id):
csv_fields = _expand_questions(questions, csv_fields)
writer.writerow(csv_fields)
- csv_fields_values = {'name': 'user.get_full_name().title()',
+ csv_fields_values = {
+ 'name': 'user.get_full_name().title()',
'roll_number': 'user.profile.roll_number',
'institute': 'user.profile.institute',
'department': 'user.profile.department',
'username': 'user.username',
'marks_obtained': 'answerpaper.marks_obtained',
'out_of': 'question_paper.total_marks',
- 'percentage': 'answerpaper.percent', 'status': 'answerpaper.status'}
+ 'percentage': 'answerpaper.percent',
+ 'status': 'answerpaper.status'}
questions_scores = {}
for question in questions:
questions_scores['{0}-{1}'.format(question.summary, question.points)] \
- = 'answerpaper.get_per_question_score({0})'.format(question.id)
+ = 'answerpaper.get_per_question_score({0})'.format(question.id)
csv_fields_values.update(questions_scores)
- users = users.exclude(id=course.creator.id).exclude(id__in=course.teachers.all())
+ users = users.exclude(id=course.creator.id).exclude(
+ id__in=course.teachers.all())
for user in users:
row = []
answerpaper = None
@@ -1626,7 +1630,8 @@ def grade_user(request, quiz_id=None, user_id=None, attempt_number=None,
if request.method == "POST":
papers = data['papers']
for paper in papers:
- for question, answers in six.iteritems(paper.get_question_answers()):
+ for question, answers in six.iteritems(
+ paper.get_question_answers()):
marks = float(request.POST.get('q%d_marks' % question.id, 0))
answer = answers[-1]['answer']
answer.set_marks(marks)
@@ -1742,7 +1747,7 @@ def add_teacher(request, course_id):
context = {}
course = get_object_or_404(Course, pk=course_id)
- if user == course.creator or user in course.teachers.all():
+ if course.is_creator(user) or course.is_teacher(user):
context['course'] = course
else:
raise Http404('You are not allowed to view this page!')
@@ -1764,8 +1769,8 @@ def remove_teachers(request, course_id):
user = request.user
course = get_object_or_404(Course, pk=course_id)
- if not is_moderator(user) and (user != course.creator and user
- not in course.teachers.all()):
+ if not is_moderator(user) and (not course.is_creator(user) and
+ course.is_teacher(user)):
raise Http404('You are not allowed to view this page!')
if request.method == "POST":
@@ -1782,9 +1787,10 @@ def test_mode(user, godmode=False, questions_list=None, quiz_id=None,
if questions_list is not None:
trial_course = Course.objects.create_trial_course(user)
trial_quiz = Quiz.objects.create_trial_quiz(user)
- trial_questionpaper = QuestionPaper.objects.create_trial_paper_to_test_questions(
- trial_quiz, questions_list
- )
+ trial_questionpaper = QuestionPaper.objects. \
+ create_trial_paper_to_test_questions(
+ trial_quiz, questions_list
+ )
trial_unit, created = LearningUnit.objects.get_or_create(
order=1, type="quiz", quiz=trial_quiz,
check_prerequisite=False)
@@ -1797,9 +1803,10 @@ def test_mode(user, godmode=False, questions_list=None, quiz_id=None,
trial_quiz, trial_course, module = Quiz.objects.create_trial_from_quiz(
quiz_id, user, godmode, course_id
)
- trial_questionpaper = QuestionPaper.objects.create_trial_paper_to_test_quiz(
- trial_quiz, quiz_id
- )
+ trial_questionpaper = QuestionPaper.objects. \
+ create_trial_paper_to_test_quiz(
+ trial_quiz, quiz_id
+ )
return trial_questionpaper, trial_course, module
@@ -1864,7 +1871,8 @@ def grader(request, extra_context=None):
if not is_moderator(user):
raise Http404('You are not allowed to view this page!')
courses = Course.objects.filter(is_trial=False)
- user_courses = list(courses.filter(creator=user)) + list(courses.filter(teachers=user))
+ user_courses = list(courses.filter(creator=user)) + \
+ list(courses.filter(teachers=user))
context = {'courses': user_courses}
if extra_context:
context.update(extra_context)
@@ -1877,24 +1885,26 @@ def regrade(request, course_id, question_id=None, answerpaper_id=None,
questionpaper_id=None):
user = request.user
course = get_object_or_404(Course, pk=course_id)
- if not is_moderator(user) or (user != course.creator and user not in course.teachers.all()):
+ if not is_moderator(user) or (course.is_creator(user) and
+ course.is_teacher(user)):
raise Http404('You are not allowed to view this page!')
details = []
if answerpaper_id is not None and question_id is None:
answerpaper = get_object_or_404(AnswerPaper, pk=answerpaper_id)
for question in answerpaper.questions.all():
details.append(answerpaper.regrade(question.id))
- course_status = CourseStatus.objects.filter(user=answerpaper.user,
- course=answerpaper.course)
+ course_status = CourseStatus.objects.filter(
+ user=answerpaper.user, course=answerpaper.course)
if course_status.exists():
course_status.first().set_grade()
if questionpaper_id is not None and question_id is not None:
- answerpapers = AnswerPaper.objects.filter(questions=question_id,
- question_paper_id=questionpaper_id, course_id=course_id)
+ answerpapers = AnswerPaper.objects.filter(
+ questions=question_id,
+ question_paper_id=questionpaper_id, course_id=course_id)
for answerpaper in answerpapers:
details.append(answerpaper.regrade(question_id))
- course_status = CourseStatus.objects.filter(user=answerpaper.user,
- course=answerpaper.course)
+ course_status = CourseStatus.objects.filter(
+ user=answerpaper.user, course=answerpaper.course)
if course_status.exists():
course_status.first().set_grade()
if answerpaper_id is not None and question_id is not None:
@@ -1931,8 +1941,8 @@ def download_course_csv(request, course_id):
total_course_marks = 0.0
user_course_marks = 0.0
for quiz in quizzes:
- quiz_best_marks = AnswerPaper.objects.get_user_best_of_attempts_marks\
- (quiz, student["id"], course_id)
+ quiz_best_marks = AnswerPaper.objects. \
+ get_user_best_of_attempts_marks(quiz, student["id"], course_id)
user_course_marks += quiz_best_marks
total_course_marks += quiz.questionpaper_set.values_list(
"total_marks", flat=True)[0]
@@ -1943,7 +1953,7 @@ def download_course_csv(request, course_id):
response['Content-Disposition'] = 'attachment; filename="{0}.csv"'.format(
(course.name).lower().replace('.', ''))
header = ['first_name', 'last_name', "roll_number", "email", "institute"]\
- + [quiz.description for quiz in quizzes] + ['total_scored', 'out_of']
+ + [quiz.description for quiz in quizzes] + ['total_scored', 'out_of']
writer = csv.DictWriter(response, fieldnames=header, extrasaction='ignore')
writer.writeheader()
for student in students:
@@ -1993,7 +2003,9 @@ def new_activation(request, email=None):
context['success'] = False
context['msg'] = "Your account is not verified. \
Please verify your account"
- return render_to_response('yaksh/activation_status.html', context)
+ return my_render_to_response(
+ request, 'yaksh/activation_status.html', context
+ )
if not user.profile.is_email_verified:
user.profile.activation_key = generate_activation_key(user.username)
@@ -2088,17 +2100,20 @@ def upload_users(request, course_id):
)
required_fields = ['firstname', 'lastname', 'email']
try:
- reader = csv.DictReader(csv_file.read().decode('utf-8').splitlines(),
- dialect=dialect)
+ reader = csv.DictReader(
+ csv_file.read().decode('utf-8').splitlines(),
+ dialect=dialect)
except TypeError:
context['message'] = "Bad CSV file"
return my_render_to_response(
request, 'yaksh/course_detail.html', context
)
- stripped_fieldnames = [field.strip().lower() for field in reader.fieldnames]
+ stripped_fieldnames = [
+ field.strip().lower() for field in reader.fieldnames]
for field in required_fields:
if field not in stripped_fieldnames:
- context['message'] = "The CSV file does not contain the required headers"
+ context['message'] = "The CSV file does not contain the"\
+ " required headers"
return my_render_to_response(
request, 'yaksh/course_detail.html', context
)
@@ -2136,9 +2151,11 @@ def _read_user_csv(reader, course):
continue
user_defaults = {'email': email, 'first_name': first_name,
'last_name': last_name}
- user, created = _create_or_update_user(username, password, user_defaults)
+ user, created = _create_or_update_user(username, password,
+ user_defaults)
profile_defaults = {'institute': institute, 'roll_number': roll_no,
- 'department': department, 'is_email_verified': True}
+ 'department': department,
+ 'is_email_verified': True}
_create_or_update_profile(user, profile_defaults)
if created:
state = "Added"
@@ -2174,8 +2191,8 @@ def _get_csv_values(row, fields):
username = row['username'].strip()
if 'remove' in fields:
remove = row['remove']
- return (username, email, first_name, last_name, password, roll_no, institute,
- department, remove)
+ return (username, email, first_name, last_name, password,
+ roll_no, institute, department, remove)
def _remove_from_course(user, course):
@@ -2681,8 +2698,10 @@ def course_modules(request, course_id, msg=None):
context = {"course": course, "user": user, "msg": msg}
course_status = CourseStatus.objects.filter(course=course, user=user)
context['course_percentage'] = course.get_completion_percent(user)
- context['modules'] = [(module, module.get_module_complete_percent(course, user))
- for module in learning_modules]
+ context['modules'] = [
+ (module, module.get_module_complete_percent(course, user))
+ for module in learning_modules
+ ]
if course_status.exists():
course_status = course_status.first()
if not course_status.grade:
@@ -2761,16 +2780,21 @@ def get_user_data(request, course_id, student_id):
data['msg'] = 'You are not a moderator'
data['status'] = False
elif not course.is_creator(user) and not course.is_teacher(user):
- msg = 'You are neither course creator nor course teacher for {0}'.format(
- course.name)
+ msg = dedent(
+ """\
+ You are neither course creator nor course teacher for {0}
+ """.format(course.name)
+ )
data['msg'] = msg
data['status'] = False
else:
student = User.objects.get(id=student_id)
data['status'] = True
modules = course.get_learning_modules()
- module_percent = [(module, module.get_module_complete_percent(course, student))
- for module in modules]
+ module_percent = [
+ (module, module.get_module_complete_percent(course, student))
+ for module in modules
+ ]
data['modules'] = module_percent
_update_course_percent(course, student)
data['course_percentage'] = course.get_completion_percent(student)