diff options
author | mahesh | 2017-08-24 23:26:46 +0530 |
---|---|---|
committer | mahesh | 2017-08-24 23:26:46 +0530 |
commit | 751dc83729e5bf57b2dd1a2798bb7b527a2e3584 (patch) | |
tree | fa1d11bd00ac9060cfa36056f62d1321455a4916 | |
parent | 6ab383c02085936ecc20ffeb4b9f41ca642256c3 (diff) | |
parent | 9d5c4a01fd7856f1ef8793b75a9734324c254344 (diff) | |
download | online_test-751dc83729e5bf57b2dd1a2798bb7b527a2e3584.tar.gz online_test-751dc83729e5bf57b2dd1a2798bb7b527a2e3584.tar.bz2 online_test-751dc83729e5bf57b2dd1a2798bb7b527a2e3584.zip |
Merge branch 'master' of https://github.com/fossee/online_test into yaml_questions
-rw-r--r-- | online_test/settings.py | 3 | ||||
-rw-r--r-- | yaksh/decorators.py | 40 | ||||
-rw-r--r-- | yaksh/forms.py | 17 | ||||
-rw-r--r-- | yaksh/models.py | 5 | ||||
-rw-r--r-- | yaksh/send_emails.py | 32 | ||||
-rw-r--r-- | yaksh/static/yaksh/js/course.js | 31 | ||||
-rw-r--r-- | yaksh/templates/yaksh/course_detail.html | 103 | ||||
-rw-r--r-- | yaksh/templates/yaksh/login.html | 8 | ||||
-rw-r--r-- | yaksh/templates/yaksh/moderator_dashboard.html | 2 | ||||
-rw-r--r-- | yaksh/test_views.py | 168 | ||||
-rw-r--r-- | yaksh/urls.py | 1 | ||||
-rw-r--r-- | yaksh/views.py | 101 |
12 files changed, 437 insertions, 74 deletions
diff --git a/online_test/settings.py b/online_test/settings.py index 4ca2967..90cce9d 100644 --- a/online_test/settings.py +++ b/online_test/settings.py @@ -113,7 +113,8 @@ EMAIL_HOST_USER = 'email_host_user' EMAIL_HOST_PASSWORD = 'email_host_password' -# Set EMAIL_BACKEND to 'django.core.mail.backends.smtp.EmailBackend' in production +# Set EMAIL_BACKEND to 'django.core.mail.backends.smtp.EmailBackend' +# in production EMAIL_BACKEND = 'django.core.mail.backends.dummy.EmailBackend' # SENDER_EMAIL, REPLY_EMAIL, PRODUCTION_URL, IS_DEVELOPMENT are used in email diff --git a/yaksh/decorators.py b/yaksh/decorators.py index f0d354c..9e9bc6d 100644 --- a/yaksh/decorators.py +++ b/yaksh/decorators.py @@ -1,12 +1,42 @@ -from django.shortcuts import render_to_response +from django.shortcuts import render_to_response, redirect from django.conf import settings from django.template import RequestContext +# Local imports +from yaksh.forms import ProfileForm + + +def user_has_profile(user): + return hasattr(user, 'profile') + + +def has_profile(func): + """ + This decorator is used to check if the user account has a profile. + If the user does not have a profile then redirect the user to + profile edit page. + """ + + def _wrapped_view(request, *args, **kwargs): + if user_has_profile(request.user): + return func(request, *args, **kwargs) + ci = RequestContext(request) + if request.user.groups.filter(name='moderator').exists(): + template = 'manage.html' + else: + template = 'user.html' + form = ProfileForm(user=request.user, instance=None) + context = {'template': template, 'form': form} + return render_to_response('yaksh/editprofile.html', context, + context_instance=ci) + return _wrapped_view + def email_verified(func): - """ This decorator is used to check if email is verified. - If email is not verified then redirect user for email - verification + """ + This decorator is used to check if email is verified. + If email is not verified then redirect user for email + verification. """ def is_email_verified(request, *args, **kwargs): @@ -14,7 +44,7 @@ def email_verified(func): user = request.user context = {} if not settings.IS_DEVELOPMENT: - if user.is_authenticated() and hasattr(user, 'profile'): + if user.is_authenticated() and user_has_profile(user): if not user.profile.is_email_verified: context['success'] = False context['msg'] = "Your account is not verified. \ diff --git a/yaksh/forms.py b/yaksh/forms.py index 3459be9..2740497 100644 --- a/yaksh/forms.py +++ b/yaksh/forms.py @@ -181,9 +181,13 @@ class QuizForm(forms.ModelForm): user = kwargs.pop('user') course_id = kwargs.pop('course') super(QuizForm, self).__init__(*args, **kwargs) - self.fields['prerequisite'] = forms.ModelChoiceField( - queryset=Quiz.objects.filter(course__id=course_id, - is_trial=False)) + + prerequisite_list = Quiz.objects.filter( + course__id=course_id, + is_trial=False + ).exclude(id=self.instance.id) + + self.fields['prerequisite'] = forms.ModelChoiceField(prerequisite_list) self.fields['prerequisite'].required = False self.fields['course'] = forms.ModelChoiceField( queryset=Course.objects.filter(id=course_id), empty_label=None) @@ -240,6 +244,13 @@ class QuizForm(forms.ModelForm): </p> """) + def clean_prerequisite(self): + prereq = self.cleaned_data['prerequisite'] + if prereq and prereq.prerequisite: + if prereq.prerequisite.id == self.instance.id: + raise forms.ValidationError("Please set another prerequisite quiz") + return prereq + class Meta: model = Quiz exclude = ["is_trial"] diff --git a/yaksh/models.py b/yaksh/models.py index b4c665c..d9218ef 100644 --- a/yaksh/models.py +++ b/yaksh/models.py @@ -96,11 +96,6 @@ def get_model_class(model): return model_class -def has_profile(user): - """ check if user has profile """ - return True if hasattr(user, 'profile') else False - - def get_upload_dir(instance, filename): return os.sep.join(( 'question_%s' % (instance.question.id), filename diff --git a/yaksh/send_emails.py b/yaksh/send_emails.py index 24215dd..ae49f23 100644 --- a/yaksh/send_emails.py +++ b/yaksh/send_emails.py @@ -7,11 +7,14 @@ from string import digits, punctuation import hashlib from textwrap import dedent import smtplib +import os # Django imports from django.utils.crypto import get_random_string from django.conf import settings -from django.core.mail import send_mass_mail, send_mail +from django.core.mail import EmailMultiAlternatives, send_mail +from django.core.files.storage import default_storage +from django.core.files.base import ContentFile def generate_activation_key(username): @@ -57,3 +60,30 @@ def send_user_mail(user_mail, key): success = False return success, msg + +def send_bulk_mail(subject, email_body, recipients, attachments): + try: + text_msg = "" + msg = EmailMultiAlternatives(subject, text_msg, settings.SENDER_EMAIL, + recipients + ) + msg.attach_alternative(email_body, "text/html") + if attachments: + for file in attachments: + path = default_storage.save('attachments/'+file.name, + ContentFile(file.read()) + ) + msg.attach_file(os.sep.join((settings.MEDIA_ROOT, path)), + mimetype="text/html" + ) + default_storage.delete(path) + msg.send() + + message = "Email Sent Successfully" + + except Exception as exc_msg: + message = """Error: {0}. Please check email address.\ + If email address is correct then + Please contact {1}.""".format(exc_msg, settings.REPLY_EMAIL) + + return message diff --git a/yaksh/static/yaksh/js/course.js b/yaksh/static/yaksh/js/course.js index 5b79e68..8fb2773 100644 --- a/yaksh/static/yaksh/js/course.js +++ b/yaksh/static/yaksh/js/course.js @@ -35,4 +35,35 @@ $(".reject").change( function(){ });
}
});
+
+$(function() {
+ $('textarea#email_body').froalaEditor({
+ heightMin: 200,
+ heightMax: 200
+ })
+ });
+
+$("#send_mail").click(function(){
+ var subject = $("#subject").val();
+ var body = $('#email_body').val();
+ var status = false;
+ var selected = [];
+ $('#reject input:checked').each(function() {
+ selected.push($(this).attr('value'));
+ });
+
+ if (subject == '' || body == ''){
+ $("#error_msg").html("Please enter mail details");
+ $("#dialog").dialog();
+ }
+ else if (selected.length == 0){
+ $("#error_msg").html("Please select atleast one user");
+ $("#dialog").dialog();
+ }
+ else {
+ status = true;
+ }
+ return status;
+});
+
});
diff --git a/yaksh/templates/yaksh/course_detail.html b/yaksh/templates/yaksh/course_detail.html index cd4144f..bcada42 100644 --- a/yaksh/templates/yaksh/course_detail.html +++ b/yaksh/templates/yaksh/course_detail.html @@ -6,6 +6,13 @@ {% block script %} <script language="JavaScript" type="text/javascript" src="{{ URL_ROOT }}/static/yaksh/js/course.js"></script> +<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/froala-editor/2.5.1/js/froala_editor.min.js"></script> +<script src="https://code.jquery.com/ui/1.9.1/jquery-ui.js"></script> +{% endblock %} +{% block css %} +<link rel="stylesheet" href="https://code.jquery.com/ui/1.9.1/themes/base/jquery-ui.css"> +<link href="https://cdnjs.cloudflare.com/ajax/libs/froala-editor/2.5.1/css/froala_editor.min.css" rel="stylesheet" type="text/css" /> +<link href="https://cdnjs.cloudflare.com/ajax/libs/froala-editor/2.5.1/css/froala_style.min.css" rel="stylesheet" type="text/css" /> {% endblock %} {% block content %} <br/> @@ -13,9 +20,17 @@ <div class="row"> <div class="col-sm-3 col-md-2 sidebar"> <ul class="nav nav-sidebar"> - <li><a href="#student-requests" id="request"> Requested Students </a></li> - <li><a href="#enrolled-students" id="enroll-students"> Enrolled Students </a></li> - <li><a href="#rejected-students" id="reject-students"> Rejected Students </a></li> + {% if state == 'mail'%} + <li><a href="{{URL_ROOT}}/exam/manage/course_detail/{{course.id}}/"> + Go to Course Details</a></li> + {% else %} + <li><a href="#student-requests" id="request"> + Requested Students </a></li> + <li><a href="#enrolled-students" id="enroll-students"> + Enrolled Students </a></li> + <li><a href="#rejected-students" id="reject-students"> + Rejected Students </a></li> + {% endif %} <li> <a href="{{URL_ROOT}}/exam/manage/toggle_status/{{ course.id }}/"> {% if course.active %}Deactivate Course {% else %} Activate Course {% endif %}</a> @@ -24,16 +39,70 @@ <a href="{{URL_ROOT}}/exam/manage/duplicate_course/{{ course.id }}/"> Clone Course</a> </li> + <li> + <a href="{{URL_ROOT}}/exam/manage/send_mail/{{ course.id }}/"> + Send Mail</a> + </li> </ul> </div> </div> <div class="col-md-9 col-md-offset-2 main"> <div class="row"> + {% if message %} + <div class="alert alert-warning" role="alert"> + <center> + <strong> {{ message }} </strong> + </center> + </div> + {% endif %} + {% if state == 'mail' %} + <div id="enrolled-students"> + <center><b><u>Send Mails to Students</u></b></center><br> + {% if course.get_enrolled %} + <input type="checkbox" class="reject"/> <font size="2">Select all</font> + <div id="reject"> + <form action="{{URL_ROOT}}/exam/manage/send_mail/{{ course.id }}/" method="post" id="send_mail_form"> + {% csrf_token %} + <table class="table table-striped"> + <th></th> + <th></th> + <th>Full Name</th> + <th>Email</th> + <th>Roll Number</th> + <th>Institute</th> + <th>Department</th> + {% for enrolled in course.get_enrolled %} + <tr> + <td><input type="checkbox" name="check" value="{{ enrolled.id }}"></td> + <td>{{ forloop.counter }}.</td> + <td> {{ enrolled.get_full_name|title }} </td> + <td> {{enrolled.email}}</td> + <td> {{enrolled.profile.roll_number}}</td> + <td> {{enrolled.profile.institute}}</td> + <td> {{enrolled.profile.department}}</td> + </tr> + {% endfor %} + </table> + <br> + <textarea name="subject" id="subject" placeholder="Email Subject" cols="50"></textarea> + <br><br> + <textarea name="body" id="email_body"></textarea><br> + Attachments: <input type="file" name="email_attach" multiple=""> + <br> + <button class="btn btn-success" type="submit" name='send_mail' value='send_mail' id="send_mail"> + Send Mail to Selected Students</button> + </div> + {% endif %} + </form> + </div> + {% else %} <div id="student-requests"> <center><b><u>Requests</u></b></center><br> {% if course.get_requests %} <input type="checkbox" class="checkall"/> <font size="2">Select all</font> <div id="enroll-all"> + <form action="{{URL_ROOT}}/exam/manage/enroll/{{ course.id }}/" method="post"> + {% csrf_token %} <table class="table table-striped"> <th></th> <th></th> @@ -43,9 +112,7 @@ <th>Institute</th> <th>Department</th> <th>Enroll/Reject</th> - <form action="{{URL_ROOT}}/exam/manage/enroll/{{ course.id }}/" method="post"> - {% csrf_token %} - {% for request in course.get_requests %} + {% for request in course.get_requests %} <tr> <td><input type="checkbox" name="check" value="{{ request.id }}"></td> <td>{{ forloop.counter }}.</td> @@ -76,6 +143,8 @@ {% if course.get_enrolled %} <input type="checkbox" class="reject"/> <font size="2">Select all</font> <div id="reject"> + <form action="{{URL_ROOT}}/exam/manage/enrolled/reject/{{ course.id }}/" method="post" id="reject-form"> + {% csrf_token %} <table class="table table-striped"> <th></th> <th></th> @@ -86,9 +155,7 @@ <th>Department</th> <th>Reject</th> {% for enrolled in course.get_enrolled %} - <form action="{{URL_ROOT}}/exam/manage/enrolled/reject/{{ course.id }}/" method="post"> - {% csrf_token %} - <tr> + <tr> <td><input type="checkbox" name="check" value="{{ enrolled.id }}"></td> <td>{{ forloop.counter }}.</td> <td> {{ enrolled.get_full_name|title }} </td> @@ -99,11 +166,12 @@ <td><a class="btn btn-danger" href="{{URL_ROOT}}/exam/manage/enrolled/reject/{{ course.id }}/{{ enrolled.id }}/"> Reject </a> - </td> - </tr> + </td> + </tr> {% endfor %} </table> - <button class="btn btn-danger" type="submit" name='reject' value='reject'>Reject Selected</button> + <button class="btn btn-danger" type="submit" name='reject' value='reject'> + Reject Selected</button> </div> {% endif %} </form> @@ -114,6 +182,8 @@ {% if course.get_rejected %} <input type="checkbox" class="enroll"/> <font size="2">Select all</font> <div id="enroll"> + <form action="{{URL_ROOT}}/exam/manage/enroll/rejected/{{ course.id }}/" method="post"> + {% csrf_token %} <table class="table table-striped"> <th></th> <th></th> @@ -123,9 +193,7 @@ <th>Institute</th> <th>Department</th> <th>Enroll</th> - {% for rejected in course.get_rejected %} - <form action="{{URL_ROOT}}/exam/manage/enroll/rejected/{{ course.id }}/" method="post"> - {% csrf_token %} + {% for rejected in course.get_rejected %} <tr> <td><input type="checkbox" name="check" value="{{ rejected.id }}"></td> <td>{{ forloop.counter }}.</td> @@ -149,6 +217,11 @@ {% endif %} </form> </div> + {% endif %} </div> </div> +<!-- Dialog to display error message --> +<div id="dialog" title="Alert"> + <p id="error_msg"></p> +</div> {% endblock %} diff --git a/yaksh/templates/yaksh/login.html b/yaksh/templates/yaksh/login.html index e4b5933..f40b12f 100644 --- a/yaksh/templates/yaksh/login.html +++ b/yaksh/templates/yaksh/login.html @@ -36,6 +36,14 @@ <li>Scales to over 500+ simultaneous users.</li> </ul> </p> + <br/> + <p><b>Fork us at:</b> + <a class = "btn btn-social-icon btn-github" + href ="https://github.com/fossee/online_test"> + + <span class="fa fa-github" style="font-size:48px"></span> + </p> + </a> </div> </div> diff --git a/yaksh/templates/yaksh/moderator_dashboard.html b/yaksh/templates/yaksh/moderator_dashboard.html index faccffe..c61675d 100644 --- a/yaksh/templates/yaksh/moderator_dashboard.html +++ b/yaksh/templates/yaksh/moderator_dashboard.html @@ -20,7 +20,7 @@ {{ paper.quiz.course.name }} </td> <td> - <a href="{{URL_ROOT}}/exam/manage/monitor/{{paper.id}}/">{{ paper.quiz.description }}</a> + <a href="{{URL_ROOT}}/exam/manage/monitor/{{ paper.quiz.id }}/">{{ paper.quiz.description }}</a> </td> <td> {{ answer_papers|length }} user(s) diff --git a/yaksh/test_views.py b/yaksh/test_views.py index 0060ed8..064c39d 100644 --- a/yaksh/test_views.py +++ b/yaksh/test_views.py @@ -21,8 +21,9 @@ from django.conf import settings from django.core.files.uploadedfile import SimpleUploadedFile from yaksh.models import User, Profile, Question, Quiz, QuestionPaper,\ - QuestionSet, AnswerPaper, Answer, Course, StandardTestCase, has_profile,\ + QuestionSet, AnswerPaper, Answer, Course, StandardTestCase,\ AssignmentUpload, FileUpload +from yaksh.decorators import user_has_profile class TestUserRegistration(TestCase): @@ -90,18 +91,18 @@ class TestProfile(TestCase): self.user2.delete() - def test_has_profile_for_user_without_profile(self): + def test_user_has_profile_for_user_without_profile(self): """ If no profile exists for user passed as argument return False """ - has_profile_status = has_profile(self.user1) + has_profile_status = user_has_profile(self.user1) self.assertFalse(has_profile_status) - def test_has_profile_for_user_with_profile(self): + def test_user_has_profile_for_user_with_profile(self): """ If profile exists for user passed as argument return True """ - has_profile_status = has_profile(self.user2) + has_profile_status = user_has_profile(self.user2) self.assertTrue(has_profile_status) @@ -206,6 +207,30 @@ class TestProfile(TestCase): self.assertEqual(response.status_code, 200) self.assertTemplateUsed(response, 'yaksh/editprofile.html') + def test_edit_profile_get_for_user_without_profile(self): + """ + If no profile exists a blank profile form will be displayed + """ + self.client.login( + username=self.user1.username, + password=self.user1_plaintext_pass + ) + response = self.client.get(reverse('yaksh:edit_profile')) + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, 'yaksh/editprofile.html') + + def test_edit_profile_get_for_user_with_profile(self): + """ + If profile exists a editprofile.html template will be rendered + """ + self.client.login( + username=self.user2.username, + password=self.user2_plaintext_pass + ) + response = self.client.get(reverse('yaksh:edit_profile')) + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, 'yaksh/editprofile.html') + def test_update_email_for_user_post(self): """ POST request to update email if multiple users with same email are found @@ -249,6 +274,16 @@ class TestStudentDashboard(TestCase): timezone='UTC' ) + # student without profile + self.student_no_profile_plaintext_pass = 'student2' + self.student_no_profile = User.objects.create_user( + username='student_no_profile', + password=self.student_no_profile_plaintext_pass, + first_name='first_name', + last_name='last_name', + email='student_no_profile@test.com' + ) + # moderator self.user_plaintext_pass = 'demo' self.user = User.objects.create_user( @@ -291,6 +326,30 @@ class TestStudentDashboard(TestCase): redirection_url = '/exam/login/?next=/exam/quizzes/' self.assertRedirects(response, redirection_url) + def test_student_dashboard_get_for_user_without_profile(self): + """ + If no profile exists a blank profile form will be displayed + """ + self.client.login( + username=self.student_no_profile.username, + password=self.student_no_profile_plaintext_pass + ) + response = self.client.get(reverse('yaksh:quizlist_user')) + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, 'yaksh/editprofile.html') + + def test_student_dashboard_get_for_user_with_profile(self): + """ + If profile exists a editprofile.html template will be rendered + """ + self.client.login( + username=self.student.username, + password=self.student_plaintext_pass + ) + response = self.client.get(reverse('yaksh:quizlist_user')) + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, 'yaksh/quizzes_user.html') + def test_student_dashboard_all_courses_get(self): """ Check student dashboard for all non hidden courses @@ -1195,6 +1254,7 @@ class TestAddTeacher(TestCase): username=self.user.username, password=self.user_plaintext_pass ) + teacher_id_list = [] for i in range(5): @@ -1833,6 +1893,70 @@ class TestCourseDetail(TestCase): self.assertEqual(response.status_code, 200) course = Course.objects.get(name="Python Course") self.assertFalse(course.active) + self.assertEqual(self.user1_course, response.context['course']) + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, 'yaksh/course_detail.html') + + def test_send_mail_to_course_students(self): + """ Check if bulk mail is sent to multiple students enrolled in a course + """ + self.client.login( + username=self.user1.username, + password=self.user1_plaintext_pass + ) + self.student2 = User.objects.create_user( + username='demo_student2', + password=self.student_plaintext_pass, + first_name='student_first_name', + last_name='student_last_name', + email='demo_student2@test.com' + ) + self.student3 = User.objects.create_user( + username='demo_student3', + password=self.student_plaintext_pass, + first_name='student_first_name', + last_name='student_last_name', + email='demo_student3@test.com' + ) + self.student4 = User.objects.create_user( + username='demo_student4', + password=self.student_plaintext_pass, + first_name='student_first_name', + last_name='student_last_name', + email='demo_student4@test.com' + ) + user_ids = [self.student.id, self.student2.id, self.student3.id, + self.student4.id] + user_emails = [self.student.email, self.student2.email, + self.student3.email, self.student4.email] + + self.user1_course.students.add(*user_ids) + attachment = SimpleUploadedFile("file.txt", b"Test") + email_data = { + 'send_mail': 'send_mail', 'email_attach': [attachment], + 'subject': 'test_bulk_mail', 'body': 'Test_Mail', + 'check': user_ids + } + self.client.post(reverse( + 'yaksh:send_mail', kwargs={'course_id': self.user1_course.id}), + data=email_data + ) + attachment_file = mail.outbox[0].attachments[0][0] + subject = mail.outbox[0].subject + body = mail.outbox[0].alternatives[0][0] + recipients = mail.outbox[0].recipients() + self.assertEqual(attachment_file, "file.txt") + self.assertEqual(subject, "test_bulk_mail") + self.assertEqual(body, "Test_Mail") + self.assertSequenceEqual(recipients, user_emails) + + # Test for get request in send mail + get_response = self.client.get(reverse( + 'yaksh:send_mail', kwargs={'course_id': self.user1_course.id}) + ) + self.assertEqual(get_response.status_code, 200) + self.assertEqual(get_response.context['course'], self.user1_course) + self.assertEqual(get_response.context['state'], 'mail') class TestEnrollRequest(TestCase): @@ -2496,6 +2620,16 @@ class TestModeratorDashboard(TestCase): position='Moderator', timezone='UTC' ) + + self.mod_no_profile_plaintext_pass = 'demo2' + self.mod_no_profile = User.objects.create_user( + username='demo_user2', + password=self.mod_no_profile_plaintext_pass, + first_name='user_first_name22', + last_name='user_last_name', + email='demo2@test.com' + ) + self.mod_group.user_set.add(self.user) self.course = Course.objects.create(name="Python Course", enrollment="Enroll Request", creator=self.user) @@ -2589,6 +2723,30 @@ class TestModeratorDashboard(TestCase): self.assertEqual(response.status_code, 200) self.assertRedirects(response, '/exam/quizzes/') + def test_moderator_dashboard_get_for_user_without_profile(self): + """ + If no profile exists a blank profile form will be displayed + """ + self.client.login( + username=self.mod_no_profile.username, + password=self.mod_no_profile_plaintext_pass + ) + response = self.client.get(reverse('yaksh:quizlist_user')) + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, 'yaksh/editprofile.html') + + def test_moderator_dashboard_get_for_user_with_profile(self): + """ + If profile exists a editprofile.html template will be rendered + """ + self.client.login( + username=self.user.username, + password=self.user_plaintext_pass + ) + response = self.client.get(reverse('yaksh:quizlist_user')) + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, 'yaksh/quizzes_user.html') + def test_moderator_dashboard_get_all_quizzes(self): """ Check moderator dashboard to get all the moderator created quizzes diff --git a/yaksh/urls.py b/yaksh/urls.py index 87ee655..4aa3276 100644 --- a/yaksh/urls.py +++ b/yaksh/urls.py @@ -67,6 +67,7 @@ urlpatterns = [ name="enroll_user"), url(r'manage/enroll/rejected/(?P<course_id>\d+)/(?P<user_id>\d+)/$', views.enroll, {'was_rejected': True}), + url(r'manage/send_mail/(?P<course_id>\d+)/$', views.send_mail, name="send_mail"), url(r'manage/reject/(?P<course_id>\d+)/(?P<user_id>\d+)/$', views.reject, name="reject_user"), url(r'manage/enrolled/reject/(?P<course_id>\d+)/(?P<user_id>\d+)/$', diff --git a/yaksh/views.py b/yaksh/views.py index 68253bc..81d180b 100644 --- a/yaksh/views.py +++ b/yaksh/views.py @@ -32,7 +32,7 @@ except ImportError: # Local imports. from yaksh.models import get_model_class, Quiz, Question, QuestionPaper, QuestionSet, Course from yaksh.models import Profile, Answer, AnswerPaper, User, TestCase, FileUpload,\ - has_profile, StandardTestCase, McqTestCase,\ + StandardTestCase, McqTestCase,\ StdIOBasedTestCase, HookTestCase, IntegerTestCase,\ FloatTestCase, StringTestCase from yaksh.forms import UserRegisterForm, UserLoginForm, QuizForm,\ @@ -42,8 +42,8 @@ from yaksh.forms import UserRegisterForm, UserLoginForm, QuizForm,\ from .settings import URL_ROOT from yaksh.models import AssignmentUpload from .file_utils import extract_files -from .send_emails import send_user_mail, generate_activation_key -from .decorators import email_verified +from .send_emails import send_user_mail, generate_activation_key, send_bulk_mail +from .decorators import email_verified, has_profile def my_redirect(url): @@ -127,6 +127,7 @@ def user_logout(request): @login_required +@has_profile @email_verified def quizlist_user(request, enrolled=None): """Show All Quizzes that is available to logged-in user.""" @@ -143,7 +144,11 @@ def quizlist_user(request, enrolled=None): courses = user.students.all() title = 'Enrolled Courses' else: - courses = Course.objects.filter(active=True, is_trial=False, hidden=False) + courses = Course.objects.filter( + active=True, is_trial=False + ).exclude( + ~Q(requests=user), ~Q(rejected=user), hidden=True + ) title = 'All Courses' context = {'user': user, 'courses': courses, 'title': title} @@ -256,32 +261,27 @@ def add_quiz(request, course_id, quiz_id=None): if form.is_valid(): form.save() return my_redirect("/exam/manage/courses/") - else: - context["form"] = form - return my_render_to_response('yaksh/add_quiz.html', - context, - context_instance=ci) + else: quiz = Quiz.objects.get(id=quiz_id) form = QuizForm(request.POST, user=user, course=course_id, - instance=quiz) + instance=quiz + ) if form.is_valid(): form.save() - context["quiz_id"] = quiz_id return my_redirect("/exam/manage/courses/") + else: - if quiz_id is None: - form = QuizForm(course=course_id, user=user) - else: - quiz = Quiz.objects.get(id=quiz_id) - form = QuizForm(user=user,course=course_id, instance=quiz) - context["quiz_id"] = quiz_id - context["form"] = form - return my_render_to_response('yaksh/add_quiz.html', - context, - context_instance=ci) + quiz = Quiz.objects.get(id=quiz_id) if quiz_id else None + form = QuizForm(user=user,course=course_id, instance=quiz) + context["quiz_id"] = quiz_id + context["form"] = form + return my_render_to_response('yaksh/add_quiz.html', + context, + context_instance=ci) @login_required +@has_profile @email_verified def prof_manage(request, msg=None): """Take credentials of the user with professor/moderator @@ -735,6 +735,39 @@ def enroll(request, course_id, user_id=None, was_rejected=False): @login_required @email_verified +def send_mail(request, course_id, user_id=None): + user = request.user + ci = RequestContext(request) + if not is_moderator(user): + 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') + + message = None + if request.method == 'POST': + user_ids = request.POST.getlist('check') + if request.POST.get('send_mail') == 'send_mail': + users = User.objects.filter(id__in=user_ids) + recipients = [student.email for student in users] + email_body = request.POST.get('body') + subject = request.POST.get('subject') + attachments = request.FILES.getlist('email_attach') + message = send_bulk_mail( + subject, email_body, recipients, attachments + ) + context = { + 'course': course, 'message': message, + 'state': 'mail' + } + return my_render_to_response( + 'yaksh/course_detail.html', context, context_instance=ci + ) + + +@login_required +@email_verified def reject(request, course_id, user_id=None, was_enrolled=False): user = request.user ci = RequestContext(request) @@ -750,8 +783,10 @@ def reject(request, course_id, user_id=None, was_enrolled=False): else: reject_ids = [user_id] if not reject_ids: - return my_render_to_response('yaksh/course_detail.html', {'course': course}, - context_instance=ci) + message = "Please select atleast one User" + return my_render_to_response('yaksh/course_detail.html', + {'course': course, "message": message}, + context_instance=ci) users = User.objects.filter(id__in=reject_ids) course.reject(was_enrolled, *users) return course_detail(request, course_id) @@ -1188,6 +1223,7 @@ def grade_user(request, quiz_id=None, user_id=None, attempt_number=None): @login_required +@has_profile @email_verified def view_profile(request): """ view moderators and users profile """ @@ -1197,20 +1233,12 @@ def view_profile(request): template = 'manage.html' else: template = 'user.html' - context = {'template': template} - if has_profile(user): - context['user'] = user - return my_render_to_response('yaksh/view_profile.html', context) - else: - form = ProfileForm(user=user) - msg = True - context['form'] = form - context['msg'] = msg - return my_render_to_response('yaksh/editprofile.html', context, - context_instance=ci) + context = {'template': template, 'user': user} + return my_render_to_response('yaksh/view_profile.html', context) @login_required +@has_profile @email_verified def edit_profile(request): """ edit profile details facility for moderator and students """ @@ -1222,10 +1250,7 @@ def edit_profile(request): else: template = 'user.html' context = {'template': template} - if has_profile(user): - profile = Profile.objects.get(user_id=user.id) - else: - profile = None + profile = Profile.objects.get(user_id=user.id) if request.method == 'POST': form = ProfileForm(request.POST, user=user, instance=profile) |