diff options
-rw-r--r-- | yaksh/forms.py | 3 | ||||
-rw-r--r-- | yaksh/migrations/0004_auto_20170331_0632.py | 28 | ||||
-rw-r--r-- | yaksh/models.py | 21 | ||||
-rw-r--r-- | yaksh/templates/yaksh/courses.html | 23 | ||||
-rw-r--r-- | yaksh/templates/yaksh/quizzes_user.html | 4 | ||||
-rw-r--r-- | yaksh/test_models.py | 36 | ||||
-rw-r--r-- | yaksh/test_views.py | 7 | ||||
-rw-r--r-- | yaksh/urls.py | 1 | ||||
-rw-r--r-- | yaksh/views.py | 27 |
9 files changed, 136 insertions, 14 deletions
diff --git a/yaksh/forms.py b/yaksh/forms.py index c6283c8..f7f7a10 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'] + exclude = ['creator', 'requests', 'students', 'rejected', + 'created_on', 'is_trial', 'teachers'] class ProfileForm(forms.ModelForm): 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'), + ), + ] 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 766b444..e09a9cc 100644 --- a/yaksh/templates/yaksh/courses.html +++ b/yaksh/templates/yaksh/courses.html @@ -78,8 +78,9 @@ </div> </div> <br/> - <button class="btn btn-primary pull-right"type="button" onClick='location.replace("{{URL_ROOT}}/exam/manage/addquiz/{{course.id}}/");'>Add New Quiz</button> - <p><a href="{{URL_ROOT}}/exam/manage/courses/download_course_csv/{{course.id}}">Download CSV</a></p> + <a class="btn btn-success" href="{{URL_ROOT}}/exam/manage/addquiz/{{course.id}}/">Add New Quiz</a> + <a class="btn btn-primary"href="{{URL_ROOT}}/exam/manage/edit_course/{{course.id}}">Edit Course</a> + <a class="btn btn-default"href="{{URL_ROOT}}/exam/manage/courses/download_course_csv/{{course.id}}">Download CSV</a> </div> </div> <br><br> @@ -130,19 +131,31 @@ </div> </div> </div> - <div class="col-md-4"> + <div> <p><b><a href="{{URL_ROOT}}/exam/manage/searchteacher/{{course.id}}/">Add Teacher</a></b></p> </div> - <div class="col-md-4"> + <div class="col-md-2"> <p><b><u>Quiz(zes)</u></b></p> {% if course.get_quizzes %} {% for quiz in course.get_quizzes %} <a href="{{URL_ROOT}}/exam/manage/addquiz/{{course.id}}/{{quiz.id}}/">{{ quiz.description }}</a><br> - {% endfor %} + {% endfor %} {% else %} <p><b>No quiz </b></p> {% endif %} </div> + <div class="col-md-4"> + <p><b><u>Question Paper(s)</u></b></p> + {% for quiz in course.get_quizzes %} + {% if quiz.questionpaper_set.get %} + <a href="{{URL_ROOT}}/exam/manage/designquestionpaper/{{ quiz.id }}/{{quiz.questionpaper_set.get.id}}/">Question Paper for {{ quiz.description }}</a><br> + {% else %} + <p>No Question Paper + <a href="#" onClick='location.replace("{{URL_ROOT}}/exam/manage/quiz/designquestionpaper/{{ quiz.id }}/");'>Add</a> + </p> + {% endif %} + {% endfor %} + </div> </div> <br/> <button class="btn btn-primary pull-right"type="button" onClick='location.replace("{{URL_ROOT}}/exam/manage/addquiz/{{course.id}}/");'>Add New Quiz</button> 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 %}<span class="label label-danger">Request Rejected</span> {% elif user in course.students.all %}<span class="label label-info">Enrolled</span> {% else %} + {% if course.is_active_enrollment %} {% if course.is_self_enroll %} <a class="btn btn-success" href="{{ URL_ROOT }}/exam/self_enroll/{{ course.id }}">Enroll</a> {% else %} <a class="btn btn-success" href="{{ URL_ROOT }}/exam/enroll_request/{{ course.id }}">Enroll</a> {% endif %} + {% else %} + <span class="label label-danger">Enrollment Closed</span> + {% endif %} {% endif %} </div> </div> diff --git a/yaksh/test_models.py b/yaksh/test_models.py index f8f506a..dbd367b 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 disabled enrollment + 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,19 @@ 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()) + + 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..3fcdde2 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/') @@ -1130,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 9108b7b..91f4137 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<course_id>\d+)$', views.add_course, name='edit_course'), url(r'manage/course_detail/(?P<course_id>\d+)/$', views.course_detail, name='course_detail'), url(r'manage/enroll/(?P<course_id>\d+)/(?P<user_id>\d+)/$', views.enroll), url(r'manage/enroll/rejected/(?P<course_id>\d+)/(?P<user_id>\d+)/$', diff --git a/yaksh/views.py b/yaksh/views.py index 17274d8..27276ae 100644 --- a/yaksh/views.py +++ b/yaksh/views.py @@ -593,13 +593,18 @@ def complete(request, reason=None, attempt_num=None, questionpaper_id=None): @login_required -def add_course(request): +def add_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) + form = CourseForm(request.POST, instance=course) if form.is_valid(): new_course = form.save(commit=False) new_course.creator = user @@ -610,7 +615,7 @@ def add_course(request): {'form': form}, context_instance=ci) else: - form = CourseForm() + form = CourseForm(instance=course) return my_render_to_response('yaksh/add_course.html', {'form': form}, context_instance=ci) @@ -620,9 +625,14 @@ 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=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/') @@ -678,6 +688,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=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') @@ -862,7 +877,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 |