summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--yaksh/forms.py3
-rw-r--r--yaksh/migrations/0004_auto_20170331_0632.py28
-rw-r--r--yaksh/models.py21
-rw-r--r--yaksh/templates/yaksh/courses.html23
-rw-r--r--yaksh/templates/yaksh/quizzes_user.html4
-rw-r--r--yaksh/test_models.py36
-rw-r--r--yaksh/test_views.py7
-rw-r--r--yaksh/urls.py1
-rw-r--r--yaksh/views.py27
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