From 171a82aa3ef07fc9344c8c5b42542bec0a3ca5ab Mon Sep 17 00:00:00 2001 From: ankitjavalkar Date: Thu, 30 Mar 2017 18:10:09 +0530 Subject: Multiple changes to Course: - Allow a start and end time for Course enrollment - Allow Course to be editable --- yaksh/forms.py | 3 ++- yaksh/models.py | 21 ++++++++++++++++++ yaksh/templates/yaksh/courses.html | 7 ++++-- yaksh/templates/yaksh/quizzes_user.html | 4 ++++ yaksh/test_models.py | 32 +++++++++++++++++++++++++++ yaksh/test_views.py | 5 +++-- yaksh/urls.py | 1 + yaksh/views.py | 38 +++++++++++++++++++++++++++++++++ 8 files changed, 106 insertions(+), 5 deletions(-) diff --git a/yaksh/forms.py b/yaksh/forms.py index c6283c8..a0eee71 100644 --- a/yaksh/forms.py +++ b/yaksh/forms.py @@ -276,7 +276,8 @@ class CourseForm(forms.ModelForm): class Meta: model = Course - fields = ['name', 'active', 'enrollment', 'instructions'] + fields = ['name', 'active', 'enrollment', + 'start_enroll_time', 'end_enroll_time', 'instructions'] class ProfileForm(forms.ModelForm): diff --git a/yaksh/models.py b/yaksh/models.py index 9e05af0..802a1fc 100644 --- a/yaksh/models.py +++ b/yaksh/models.py @@ -126,6 +126,24 @@ class Course(models.Model): teachers = models.ManyToManyField(User, related_name='teachers') is_trial = models.BooleanField(default=False) instructions = models.TextField(default=None, null=True, blank=True) + + # The start date of the course enrollment. + start_enroll_time = models.DateTimeField( + "Start Date and Time for enrollment of course", + default=timezone.now, + null=True + ) + + # The end date and time of the course enrollment + end_enroll_time = models.DateTimeField( + "End Date and Time for enrollment of course", + default=datetime( + 2199, 1, 1, + tzinfo=pytz.timezone(timezone.get_current_timezone_name()) + ), + null=True + ) + objects = CourseManager() def request(self, *users): @@ -134,6 +152,9 @@ class Course(models.Model): def get_requests(self): return self.requests.all() + def is_active_enrollment(self): + return self.start_enroll_time <= timezone.now() < self.end_enroll_time + def enroll(self, was_rejected, *users): self.students.add(*users) if not was_rejected: diff --git a/yaksh/templates/yaksh/courses.html b/yaksh/templates/yaksh/courses.html index 970d488..075d5aa 100644 --- a/yaksh/templates/yaksh/courses.html +++ b/yaksh/templates/yaksh/courses.html @@ -78,8 +78,11 @@
- -

Download CSV

+
+ Add New Quiz + Edit Course + Download CSV +


diff --git a/yaksh/templates/yaksh/quizzes_user.html b/yaksh/templates/yaksh/quizzes_user.html index 72fce30..ce74844 100644 --- a/yaksh/templates/yaksh/quizzes_user.html +++ b/yaksh/templates/yaksh/quizzes_user.html @@ -13,11 +13,15 @@ {% elif user in course.rejected.all %}Request Rejected {% elif user in course.students.all %}Enrolled {% else %} + {% if course.is_active_enrollment %} {% if course.is_self_enroll %} Enroll {% else %} Enroll {% endif %} + {% else %} + Enrollment Closed + {% endif %} {% endif %} diff --git a/yaksh/test_models.py b/yaksh/test_models.py index f8f506a..7e14ce7 100644 --- a/yaksh/test_models.py +++ b/yaksh/test_models.py @@ -843,6 +843,29 @@ class CourseTestCases(unittest.TestCase): self.quiz1 = Quiz.objects.get(description='demo quiz 1') self.quiz2 = Quiz.objects.get(description='demo quiz 2') + # create courses with + self.enroll_request_course = Course.objects.create( + name="Enrollment Request Course With Enrollment Disabled", + enrollment="Enroll Request", + creator=self.creator, + start_enroll_time=datetime(2015, 10, 9, 10, 8, 15, 0, + tzinfo=pytz.utc + ), + end_enroll_time=datetime(2015, 11, 9, 10, 8, 15, 0, + tzinfo=pytz.utc + ), + ) + self.open_course = Course.objects.create( + name="Open Course With Enrollment Disabled", + enrollment="Open Course", + creator=self.creator, + start_enroll_time=datetime(2015, 10, 9, 10, 8, 15, 0, + tzinfo=pytz.utc + ), + end_enroll_time=datetime(2015, 11, 9, 10, 8, 15, 0, + tzinfo=pytz.utc + ), + ) def test_is_creator(self): """ Test is_creator method of Course""" @@ -926,6 +949,15 @@ class CourseTestCases(unittest.TestCase): self.assertIn(self.creator, trial_course.students.all()) self.assertTrue(trial_course.is_trial) + def test_disabled_enrollment_for_open_course(self): + """Test to check enrollment is closed for open course""" + self.assertFalse(self.open_course.is_active_enrollment()) + + def test_disabled_enrollment_for_enroll_request_course(self): + """Test to check enrollment is closed for open course""" + self.assertFalse(self.enroll_request_course.is_active_enrollment()) + + ############################################################################### class TestCaseTestCases(unittest.TestCase): diff --git a/yaksh/test_views.py b/yaksh/test_views.py index aa6561a..4e262dc 100644 --- a/yaksh/test_views.py +++ b/yaksh/test_views.py @@ -884,7 +884,9 @@ class TestAddCourse(TestCase): response = self.client.post(reverse('yaksh:add_course'), data={'name': 'new_demo_course_1', 'active': True, - 'enrollment': 'open' + 'enrollment': 'open', + 'start_enroll_time': '2016-01-10 09:00:15', + 'end_enroll_time': '2016-01-15 09:00:15', } ) course_list = Course.objects.all().order_by('-id') @@ -892,7 +894,6 @@ class TestAddCourse(TestCase): self.assertEqual(new_course.name, 'new_demo_course_1') self.assertEqual(new_course.enrollment, 'open') self.assertEqual(new_course.active, True) - self.assertEqual(response.status_code, 302) self.assertRedirects(response, '/exam/manage/') diff --git a/yaksh/urls.py b/yaksh/urls.py index ad58985..05d167e 100644 --- a/yaksh/urls.py +++ b/yaksh/urls.py @@ -56,6 +56,7 @@ urlpatterns = [ views.download_csv), url(r'manage/courses/$', views.courses, name='courses'), url(r'manage/add_course/$', views.add_course, name='add_course'), + url(r'manage/edit_course/(?P\d+)$', views.edit_course, name='edit_course'), url(r'manage/course_detail/(?P\d+)/$', views.course_detail, name='course_detail'), url(r'manage/enroll/(?P\d+)/(?P\d+)/$', views.enroll), url(r'manage/enroll/rejected/(?P\d+)/(?P\d+)/$', diff --git a/yaksh/views.py b/yaksh/views.py index 2adc2c3..7208e82 100644 --- a/yaksh/views.py +++ b/yaksh/views.py @@ -613,11 +613,44 @@ def add_course(request): context_instance=ci) +@login_required +def edit_course(request, course_id=None): + user = request.user + ci = RequestContext(request) + if course_id: + course = Course.objects.get(id=course_id) + else: + course = None + + if not is_moderator(user): + raise Http404('You are not allowed to view this page') + if request.method == 'POST': + form = CourseForm(request.POST, instance=course) + if form.is_valid(): + new_course = form.save(commit=False) + new_course.creator = user + new_course.save() + return my_redirect('/exam/manage/') + else: + return my_render_to_response('yaksh/add_course.html', + {'form': form}, + context_instance=ci) + else: + form = CourseForm(instance=course) + return my_render_to_response('yaksh/add_course.html', {'form': form}, + context_instance=ci) + + @login_required def enroll_request(request, course_id): user = request.user ci = RequestContext(request) course = get_object_or_404(Course, pk=course_id) + if not course.is_active_enrollment: + msg = 'Enrollment for this course has been closed, please contact your '\ + 'instructor/administrator.' + return complete(request, msg, attempt_num, questionpaper_id=None) + course.request(user) if is_moderator(user): return my_redirect('/exam/manage/') @@ -676,6 +709,11 @@ def enroll(request, course_id, user_id=None, was_rejected=False): raise Http404('You are not allowed to view this page') course = get_object_or_404(Course, pk=course_id) + if not course.is_active_enrollment: + msg = 'Enrollment for this course has been closed, please contact your '\ + 'instructor/administrator.' + return complete(request, msg, attempt_num, questionpaper_id=None) + if not course.is_creator(user) and not course.is_teacher(user): raise Http404('This course does not belong to you') -- cgit From 55bbe6b8da21401983876555150aa0bf856e4d40 Mon Sep 17 00:00:00 2001 From: ankitjavalkar Date: Fri, 31 Mar 2017 12:04:54 +0530 Subject: Add migration for start and end enroll time --- yaksh/migrations/0004_auto_20170331_0632.py | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 yaksh/migrations/0004_auto_20170331_0632.py diff --git a/yaksh/migrations/0004_auto_20170331_0632.py b/yaksh/migrations/0004_auto_20170331_0632.py new file mode 100644 index 0000000..3e4b830 --- /dev/null +++ b/yaksh/migrations/0004_auto_20170331_0632.py @@ -0,0 +1,28 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.5 on 2017-03-31 06:32 +from __future__ import unicode_literals + +import datetime +from django.db import migrations, models +import django.utils.timezone +from django.utils.timezone import utc + + +class Migration(migrations.Migration): + + dependencies = [ + ('yaksh', '0003_auto_20170321_0917'), + ] + + operations = [ + migrations.AddField( + model_name='course', + name='end_enroll_time', + 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'), + ), + migrations.AddField( + model_name='course', + name='start_enroll_time', + field=models.DateTimeField(default=django.utils.timezone.now, null=True, verbose_name='Start Date and Time for enrollment of course'), + ), + ] -- cgit From e9d8be7cfd031c156da153d59355e49cb7d2071a Mon Sep 17 00:00:00 2001 From: adityacp Date: Mon, 3 Apr 2017 11:41:13 +0530 Subject: Change courses.html to allow teachers to add/edit Questionpaper --- yaksh/templates/yaksh/courses.html | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/yaksh/templates/yaksh/courses.html b/yaksh/templates/yaksh/courses.html index 970d488..4d19fb9 100644 --- a/yaksh/templates/yaksh/courses.html +++ b/yaksh/templates/yaksh/courses.html @@ -130,19 +130,31 @@ -
+ -
+

Quiz(zes)

{% if course.get_quizzes %} {% for quiz in course.get_quizzes %} {{ quiz.description }}
- {% endfor %} + {% endfor %} {% else %}

No quiz

{% endif %}
+
+

Question Paper(s)

+ {% for quiz in course.get_quizzes %} + {% if quiz.questionpaper_set.get %} + Question Paper for {{ quiz.description }}
+ {% else %} +

No Question Paper + Add +

+ {% endif %} + {% endfor %} +

-- cgit From c1bdc56f889e60a246e6fccb450f339b68897395 Mon Sep 17 00:00:00 2001 From: adityacp Date: Tue, 4 Apr 2017 10:35:05 +0530 Subject: Check if user is teacher or moderator for creating QuestionPaper --- yaksh/views.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/yaksh/views.py b/yaksh/views.py index 2adc2c3..247aca4 100644 --- a/yaksh/views.py +++ b/yaksh/views.py @@ -661,8 +661,7 @@ def course_detail(request, course_id): raise Http404('You are not allowed to view this page') course = get_object_or_404(Course, pk=course_id) - if not course.is_creator(user) and not course.is_teacher(user): - raise Http404('This course does not belong to you') + return my_render_to_response('yaksh/course_detail.html', {'course': course}, context_instance=ci) @@ -859,7 +858,9 @@ def design_questionpaper(request, quiz_id, questionpaper_id=None): if not is_moderator(user): raise Http404('You are not allowed to view this page!') - + quiz = Quiz.objects.get(id=quiz_id) + if not quiz.course.is_creator(user) and not quiz.course.is_teacher(user): + raise Http404('This course does not belong to you') filter_form = QuestionFilterForm(user=user) questions = None marks = None -- cgit From 09756c7db9341aace9e9ac25c9078c8cd4bf8399 Mon Sep 17 00:00:00 2001 From: adityacp Date: Tue, 4 Apr 2017 10:42:22 +0530 Subject: Fix failing test views test --- yaksh/views.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/yaksh/views.py b/yaksh/views.py index 247aca4..661d472 100644 --- a/yaksh/views.py +++ b/yaksh/views.py @@ -661,7 +661,8 @@ def course_detail(request, course_id): raise Http404('You are not allowed to view this page') course = get_object_or_404(Course, pk=course_id) - + if not course.is_creator(user) and not course.is_teacher(user): + raise Http404('This course does not belong to you') return my_render_to_response('yaksh/course_detail.html', {'course': course}, context_instance=ci) -- cgit From 1a6653567bdf58b5b70e874822cae6a1116b942f Mon Sep 17 00:00:00 2001 From: ankitjavalkar Date: Wed, 5 Apr 2017 18:31:56 +0530 Subject: Add multiple fixes based on code review --- yaksh/forms.py | 4 ++-- yaksh/templates/yaksh/courses.html | 8 +++----- yaksh/test_models.py | 6 +++++- yaksh/test_views.py | 2 +- yaksh/urls.py | 2 +- yaksh/views.py | 31 ++++--------------------------- 6 files changed, 16 insertions(+), 37 deletions(-) diff --git a/yaksh/forms.py b/yaksh/forms.py index a0eee71..f7f7a10 100644 --- a/yaksh/forms.py +++ b/yaksh/forms.py @@ -276,8 +276,8 @@ class CourseForm(forms.ModelForm): class Meta: model = Course - fields = ['name', 'active', 'enrollment', - 'start_enroll_time', 'end_enroll_time', 'instructions'] + exclude = ['creator', 'requests', 'students', 'rejected', + 'created_on', 'is_trial', 'teachers'] class ProfileForm(forms.ModelForm): diff --git a/yaksh/templates/yaksh/courses.html b/yaksh/templates/yaksh/courses.html index 075d5aa..c304e1a 100644 --- a/yaksh/templates/yaksh/courses.html +++ b/yaksh/templates/yaksh/courses.html @@ -78,11 +78,9 @@

- + Add New Quiz + Edit Course + Download CSV

diff --git a/yaksh/test_models.py b/yaksh/test_models.py index 7e14ce7..dbd367b 100644 --- a/yaksh/test_models.py +++ b/yaksh/test_models.py @@ -843,7 +843,7 @@ class CourseTestCases(unittest.TestCase): self.quiz1 = Quiz.objects.get(description='demo quiz 1') self.quiz2 = Quiz.objects.get(description='demo quiz 2') - # create courses with + # create courses with disabled enrollment self.enroll_request_course = Course.objects.create( name="Enrollment Request Course With Enrollment Disabled", enrollment="Enroll Request", @@ -949,6 +949,10 @@ class CourseTestCases(unittest.TestCase): self.assertIn(self.creator, trial_course.students.all()) self.assertTrue(trial_course.is_trial) + def test_enabled_enrollment_for_course(self): + """Test to check enrollment is closed for open course""" + self.assertTrue(self.course.is_active_enrollment()) + def test_disabled_enrollment_for_open_course(self): """Test to check enrollment is closed for open course""" self.assertFalse(self.open_course.is_active_enrollment()) diff --git a/yaksh/test_views.py b/yaksh/test_views.py index 4e262dc..3fcdde2 100644 --- a/yaksh/test_views.py +++ b/yaksh/test_views.py @@ -1131,7 +1131,7 @@ class TestEnrollRequest(TestCase): ), follow=True ) - self.assertRedirects(response, '/exam/manage/') + self.assertRedirects(response, '/exam/manage/courses/') class TestViewAnswerPaper(TestCase): diff --git a/yaksh/urls.py b/yaksh/urls.py index 05d167e..00b34e4 100644 --- a/yaksh/urls.py +++ b/yaksh/urls.py @@ -56,7 +56,7 @@ urlpatterns = [ views.download_csv), url(r'manage/courses/$', views.courses, name='courses'), url(r'manage/add_course/$', views.add_course, name='add_course'), - url(r'manage/edit_course/(?P\d+)$', views.edit_course, name='edit_course'), + url(r'manage/edit_course/(?P\d+)$', views.add_course, name='edit_course'), url(r'manage/course_detail/(?P\d+)/$', views.course_detail, name='course_detail'), url(r'manage/enroll/(?P\d+)/(?P\d+)/$', views.enroll), url(r'manage/enroll/rejected/(?P\d+)/(?P\d+)/$', diff --git a/yaksh/views.py b/yaksh/views.py index 7208e82..275cb6f 100644 --- a/yaksh/views.py +++ b/yaksh/views.py @@ -591,30 +591,7 @@ def complete(request, reason=None, attempt_num=None, questionpaper_id=None): @login_required -def add_course(request): - user = request.user - ci = RequestContext(request) - if not is_moderator(user): - raise Http404('You are not allowed to view this page') - if request.method == 'POST': - form = CourseForm(request.POST) - if form.is_valid(): - new_course = form.save(commit=False) - new_course.creator = user - new_course.save() - return my_redirect('/exam/manage/') - else: - return my_render_to_response('yaksh/add_course.html', - {'form': form}, - context_instance=ci) - else: - form = CourseForm() - return my_render_to_response('yaksh/add_course.html', {'form': form}, - context_instance=ci) - - -@login_required -def edit_course(request, course_id=None): +def add_course(request, course_id=None): user = request.user ci = RequestContext(request) if course_id: @@ -649,11 +626,11 @@ def enroll_request(request, course_id): if not course.is_active_enrollment: msg = 'Enrollment for this course has been closed, please contact your '\ 'instructor/administrator.' - return complete(request, msg, attempt_num, questionpaper_id=None) + return complete(request, msg, attempt_num=None, questionpaper_id=None) course.request(user) if is_moderator(user): - return my_redirect('/exam/manage/') + return my_redirect('/exam/manage/courses') else: return my_redirect('/exam/quizzes/') @@ -712,7 +689,7 @@ def enroll(request, course_id, user_id=None, was_rejected=False): if not course.is_active_enrollment: msg = 'Enrollment for this course has been closed, please contact your '\ 'instructor/administrator.' - return complete(request, msg, attempt_num, questionpaper_id=None) + return complete(request, msg, attempt_num=None, questionpaper_id=None) if not course.is_creator(user) and not course.is_teacher(user): raise Http404('This course does not belong to you') -- cgit