From db8aa57e9a3caf9b2ed080b440703d634abd14a1 Mon Sep 17 00:00:00 2001 From: adityacp Date: Mon, 15 May 2017 15:00:48 +0530 Subject: Add send_bulk_mail function to send mails to students enrolled in a course --- yaksh/send_emails.py | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) (limited to 'yaksh') diff --git a/yaksh/send_emails.py b/yaksh/send_emails.py index 37736d5..bcf633f 100644 --- a/yaksh/send_emails.py +++ b/yaksh/send_emails.py @@ -8,11 +8,14 @@ import hashlib from random import randint 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): @@ -56,3 +59,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 = "Yaksh" + 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 -- cgit From bd255f751dbff97d92e9c34652af37c67b62b2ff Mon Sep 17 00:00:00 2001 From: adityacp Date: Mon, 15 May 2017 15:01:10 +0530 Subject: Change urls.py and views.py - Change views to send mails to students enrolled in a course - Add reverse resolution in urls.py --- yaksh/urls.py | 2 +- yaksh/views.py | 31 +++++++++++++++++++++++++++---- 2 files changed, 28 insertions(+), 5 deletions(-) (limited to 'yaksh') diff --git a/yaksh/urls.py b/yaksh/urls.py index e4676d3..825e5f5 100644 --- a/yaksh/urls.py +++ b/yaksh/urls.py @@ -79,7 +79,7 @@ urlpatterns = [ url(r'manage/enroll/rejected/(?P\d+)/$', views.enroll, {'was_rejected': True}), url(r'manage/enrolled/reject/(?P\d+)/$', - views.reject, {'was_enrolled': True}), + views.reject, {'was_enrolled': True}, name="reject_users"), url(r'^manage/searchteacher/(?P\d+)/$', views.search_teacher), url(r'^manage/addteacher/(?P\d+)/$', views.add_teacher, name='add_teacher'), url(r'^manage/remove_teachers/(?P\d+)/$', views.remove_teachers, name='remove_teacher'), diff --git a/yaksh/views.py b/yaksh/views.py index c7af5cc..41db80e 100644 --- a/yaksh/views.py +++ b/yaksh/views.py @@ -42,7 +42,7 @@ 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 .send_emails import send_user_mail, generate_activation_key, send_bulk_mail from .decorators import email_verified @@ -771,12 +771,35 @@ def reject(request, course_id, user_id=None, was_enrolled=False): raise Http404('This course does not belong to you') if request.method == 'POST': - reject_ids = request.POST.getlist('check') + user_ids = request.POST.getlist('check') + if not user_ids: + message = "Please select atleast one User" + return my_render_to_response('yaksh/course_detail.html', + {'course': course, "message": message}, + context_instance=ci) + + if request.POST.get('send_mail') == 'send_mail': + users = User.objects.filter(id__in=user_ids) + recipients = [user.email for user 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) + + return my_render_to_response('yaksh/course_detail.html', + {'course': course, "message": message}, + context_instance=ci) + + if request.POST.get('reject') == 'reject': + reject_ids = user_ids 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) -- cgit From 2d62359adf671d5a75201a2314825039adc7291a Mon Sep 17 00:00:00 2001 From: adityacp Date: Mon, 15 May 2017 15:03:21 +0530 Subject: Change course.js and course_detail.html - Allow moderator to send emails to students enrollded in a course - Add validations to check email data in course.js --- yaksh/static/yaksh/js/course.js | 45 ++++++++++++++++++++++++ yaksh/templates/yaksh/course_detail.html | 59 +++++++++++++++++++++++++------- 2 files changed, 92 insertions(+), 12 deletions(-) (limited to 'yaksh') diff --git a/yaksh/static/yaksh/js/course.js b/yaksh/static/yaksh/js/course.js index 5b79e68..3e214be 100644 --- a/yaksh/static/yaksh/js/course.js +++ b/yaksh/static/yaksh/js/course.js @@ -35,4 +35,49 @@ $(".reject").change( function(){ }); } }); + +$(function() { + $('textarea#email_body').froalaEditor({ + heightMin: 100, + heightMax: 200 + }) + }); + +var status; +var btn_name; + +$("#send_mail").click(function(){ + btn_name = "send_mail"; + var subject = $("#subject").val(); + var body = $('#email_body').val(); + if (subject == '' || body == ''){ + status = false; + $("#error_msg").html("Please enter email details"); + $("#dialog").dialog(); + } + else{ + status = true; + } +}); + +$('#reject-form').submit(function(eventObj) { + if (btn_name == 'send_mail'){ + if(status == false){ + return false; + } + } + var selected = []; + $('#reject input:checked').each(function() { + selected.push($(this).attr('value')); + }); + if(selected.length > 0){ + return true; + } + else{ + $("#error_msg").html("Please select atleast one user"); + $( "#dialog" ).dialog(); + return false; + } +}); + }); diff --git a/yaksh/templates/yaksh/course_detail.html b/yaksh/templates/yaksh/course_detail.html index cd4144f..2cbdf8b 100644 --- a/yaksh/templates/yaksh/course_detail.html +++ b/yaksh/templates/yaksh/course_detail.html @@ -6,6 +6,14 @@ {% block script %} + + +{% endblock %} +{% block css %} + + + + {% endblock %} {% block content %}
@@ -29,11 +37,20 @@
+ {% if message %} + + {% endif %}
Requests

{% if course.get_requests %}  Select all
+
+ {% csrf_token %} @@ -43,9 +60,7 @@ - - {% csrf_token %} - {% for request in course.get_requests %} + {% for request in course.get_requests %} @@ -76,6 +91,8 @@ {% if course.get_enrolled %}  Select all
+ + {% csrf_token %}
Institute Department Enroll/Reject
{{ forloop.counter }}.
@@ -86,9 +103,7 @@ {% for enrolled in course.get_enrolled %} - - {% csrf_token %} - + @@ -99,11 +114,27 @@ - + + {% endfor %}
Department Reject
{{ forloop.counter }}. {{ enrolled.get_full_name|title }} Reject -
- + + + Click Here to send email to students + +
+
+ +

+
+ Attachments: +
+ +
+

+
{% endif %} @@ -114,6 +145,8 @@ {% if course.get_rejected %}  Select all
+
+ {% csrf_token %} @@ -123,9 +156,7 @@ - {% for rejected in course.get_rejected %} - - {% csrf_token %} + {% for rejected in course.get_rejected %} @@ -151,4 +182,8 @@ + +
+

+
{% endblock %} -- cgit From eff546b51b7b0d025b48472b4238325f406f06db Mon Sep 17 00:00:00 2001 From: adityacp Date: Mon, 15 May 2017 15:06:11 +0530 Subject: Add tests to check bulk email sending --- yaksh/test_views.py | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) (limited to 'yaksh') diff --git a/yaksh/test_views.py b/yaksh/test_views.py index 37e5ce4..7018bd2 100644 --- a/yaksh/test_views.py +++ b/yaksh/test_views.py @@ -8,6 +8,7 @@ from django.test import TestCase from django.test import Client from django.utils import timezone from django.core import mail +from django.core.files.uploadedfile import SimpleUploadedFile from yaksh.models import User, Profile, Question, Quiz, QuestionPaper,\ QuestionSet, AnswerPaper, Answer, Course, StandardTestCase,\ @@ -1072,6 +1073,57 @@ class TestCourseDetail(TestCase): 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") + response = self.client.post(reverse('yaksh:reject_users', + kwargs={'course_id': self.user1_course.id}), + data={'send_mail': 'send_mail', 'email_attach': [attachment], + 'subject': 'test_bulk_mail', 'body': 'Test_Mail', + 'check': user_ids} + ) + 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) + + class TestEnrollRequest(TestCase): def setUp(self): self.client = Client() -- cgit From 689e777cf21e30b33fd9fccbd6c2cd5dc4d935ea Mon Sep 17 00:00:00 2001 From: ankitjavalkar Date: Wed, 31 May 2017 19:43:52 +0530 Subject: Validate quiz prerequisite field --- yaksh/forms.py | 16 +++++++++++++--- yaksh/views.py | 28 +++++++++++----------------- 2 files changed, 24 insertions(+), 20 deletions(-) (limited to 'yaksh') diff --git a/yaksh/forms.py b/yaksh/forms.py index 3459be9..14a3db0 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,12 @@ class QuizForm(forms.ModelForm):

""") + def clean_prerequisite(self): + prereq = self.cleaned_data['prerequisite'] + if prereq and prereq.prerequisite.id == self.instance.id: + raise forms.ValidationError("Please set another prerequisite quiz") + return None + class Meta: model = Quiz exclude = ["is_trial"] diff --git a/yaksh/views.py b/yaksh/views.py index 7db0366..8746a57 100644 --- a/yaksh/views.py +++ b/yaksh/views.py @@ -256,30 +256,24 @@ 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 -- cgit From c277c1f742d8d984fc7ab066cd3ac513e83f0d89 Mon Sep 17 00:00:00 2001 From: ankitjavalkar Date: Wed, 31 May 2017 19:44:43 +0530 Subject: Fix conditional logic to pass test --- yaksh/forms.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'yaksh') diff --git a/yaksh/forms.py b/yaksh/forms.py index 14a3db0..2740497 100644 --- a/yaksh/forms.py +++ b/yaksh/forms.py @@ -246,9 +246,10 @@ class QuizForm(forms.ModelForm): def clean_prerequisite(self): prereq = self.cleaned_data['prerequisite'] - if prereq and prereq.prerequisite.id == self.instance.id: - raise forms.ValidationError("Please set another prerequisite quiz") - return None + 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 -- cgit From 928ebb23f8b2926240fc220791655614cc4192d2 Mon Sep 17 00:00:00 2001 From: Date: Mon, 12 Jun 2017 18:19:21 +0530 Subject: Change views.py and urls.py - Add new url for sending email - Add new view function to send email to students --- yaksh/urls.py | 1 + yaksh/views.py | 27 ++++++++++++++++++++------- 2 files changed, 21 insertions(+), 7 deletions(-) (limited to 'yaksh') diff --git a/yaksh/urls.py b/yaksh/urls.py index 825e5f5..068df7a 100644 --- a/yaksh/urls.py +++ b/yaksh/urls.py @@ -69,6 +69,7 @@ urlpatterns = [ url(r'manage/enroll/rejected/(?P\d+)/(?P\d+)/$', views.enroll, {'was_rejected': True}), url(r'manage/reject/(?P\d+)/(?P\d+)/$', views.reject), + url(r'manage/send_mail/(?P\d+)/$', views.send_mail, name="send_mail"), url(r'manage/enrolled/reject/(?P\d+)/(?P\d+)/$', views.reject, {'was_enrolled': True}), url(r'manage/toggle_status/(?P\d+)/$', views.toggle_course_status), diff --git a/yaksh/views.py b/yaksh/views.py index 41db80e..3319773 100644 --- a/yaksh/views.py +++ b/yaksh/views.py @@ -757,10 +757,9 @@ def enroll(request, course_id, user_id=None, was_rejected=False): course.enroll(was_rejected, *users) return course_detail(request, course_id) - @login_required @email_verified -def reject(request, course_id, user_id=None, was_enrolled=False): +def send_mail(request, course_id, user_id=None): user = request.user ci = RequestContext(request) if not is_moderator(user): @@ -770,6 +769,7 @@ def reject(request, course_id, user_id=None, was_enrolled=False): 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 not user_ids: @@ -787,12 +787,25 @@ def reject(request, course_id, user_id=None, was_enrolled=False): message = send_bulk_mail(subject, email_body, recipients, attachments) - return my_render_to_response('yaksh/course_detail.html', - {'course': course, "message": message}, - context_instance=ci) + return my_render_to_response('yaksh/course_detail.html', + {'course': course, "message": message, + 'msg': 'mail'}, + context_instance=ci) - if request.POST.get('reject') == 'reject': - reject_ids = user_ids +@login_required +@email_verified +def reject(request, course_id, user_id=None, was_enrolled=False): + 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') + + if request.method == 'POST': + reject_ids = request.POST.getlist('check') else: reject_ids = [user_id] if not reject_ids: -- cgit From a7c9591eac66eb2751a2706b5686a997d7c236dd Mon Sep 17 00:00:00 2001 From: adityacp Date: Mon, 12 Jun 2017 18:22:21 +0530 Subject: Add separate form to send emails --- yaksh/static/yaksh/js/course.js | 2 +- yaksh/templates/yaksh/course_detail.html | 67 ++++++++++++++++++++++++-------- 2 files changed, 52 insertions(+), 17 deletions(-) (limited to 'yaksh') diff --git a/yaksh/static/yaksh/js/course.js b/yaksh/static/yaksh/js/course.js index 3e214be..74ad37c 100644 --- a/yaksh/static/yaksh/js/course.js +++ b/yaksh/static/yaksh/js/course.js @@ -60,7 +60,7 @@ $("#send_mail").click(function(){ } }); -$('#reject-form').submit(function(eventObj) { +$('#send_mail_form').submit(function(eventObj) { if (btn_name == 'send_mail'){ if(status == false){ return false; diff --git a/yaksh/templates/yaksh/course_detail.html b/yaksh/templates/yaksh/course_detail.html index 2cbdf8b..676d7f3 100644 --- a/yaksh/templates/yaksh/course_detail.html +++ b/yaksh/templates/yaksh/course_detail.html @@ -21,9 +21,13 @@ @@ -44,6 +52,47 @@ {% endif %} + {% if msg == 'mail' %} +
+
Send Mails to Students

+ {% if course.get_enrolled %} +  Select all +
+ + {% csrf_token %} +
Institute Department Enroll
{{ forloop.counter }}.
+ + + + + + + + {% for enrolled in course.get_enrolled %} + + + + + + + + + + {% endfor %} +
Full NameEmailRoll NumberInstituteDepartment
{{ forloop.counter }}. {{ enrolled.get_full_name|title }} {{enrolled.email}} {{enrolled.profile.roll_number}} {{enrolled.profile.institute}} {{enrolled.profile.department}}
+
+ +

+
+ Attachments: +
+ +
+ {% endif %} + +
+ {% else %}
Requests

{% if course.get_requests %} @@ -91,7 +140,7 @@ {% if course.get_enrolled %}  Select all
-
+ {% csrf_token %} @@ -118,21 +167,6 @@ {% endfor %}
- - - Click Here to send email to students - -
-
- -

-
- Attachments: -
- -
-

@@ -180,6 +214,7 @@ {% endif %}
+ {% endif %}
-- cgit From a002ab59dbff856ee3838078cbe4f8fa439fd894 Mon Sep 17 00:00:00 2001 From: adityacp Date: Mon, 12 Jun 2017 18:23:17 +0530 Subject: Change views tests to check send email --- yaksh/test_views.py | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) (limited to 'yaksh') diff --git a/yaksh/test_views.py b/yaksh/test_views.py index 7018bd2..caec9d4 100644 --- a/yaksh/test_views.py +++ b/yaksh/test_views.py @@ -1108,7 +1108,7 @@ class TestCourseDetail(TestCase): self.user1_course.students.add(*user_ids) attachment = SimpleUploadedFile("file.txt", b"Test") - response = self.client.post(reverse('yaksh:reject_users', + response = self.client.post(reverse('yaksh:send_mail', kwargs={'course_id': self.user1_course.id}), data={'send_mail': 'send_mail', 'email_attach': [attachment], 'subject': 'test_bulk_mail', 'body': 'Test_Mail', @@ -1123,6 +1123,20 @@ class TestCourseDetail(TestCase): 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(response.status_code, 200) + self.assertEqual(response.context['course'], self.user1_course) + + # Test if no users are selected + post_response = self.client.post(reverse('yaksh:send_mail', + kwargs={'course_id': self.user1_course.id}), + data={'check': []} + ) + self.assertIn('select', post_response.context['message']) + class TestEnrollRequest(TestCase): def setUp(self): -- cgit From 57eaf342d16f33b8ea67b89c78907d9c1f7b4632 Mon Sep 17 00:00:00 2001 From: adityacp Date: Wed, 14 Jun 2017 12:33:45 +0530 Subject: Change send_emails.py and course_detail.html - Change variable assignment in send_emails.py - Add proper indentation in course_detail.html --- yaksh/send_emails.py | 2 +- yaksh/templates/yaksh/course_detail.html | 12 ++++++++---- 2 files changed, 9 insertions(+), 5 deletions(-) (limited to 'yaksh') diff --git a/yaksh/send_emails.py b/yaksh/send_emails.py index 4465ce9..ae49f23 100644 --- a/yaksh/send_emails.py +++ b/yaksh/send_emails.py @@ -63,7 +63,7 @@ def send_user_mail(user_mail, key): def send_bulk_mail(subject, email_body, recipients, attachments): try: - text_msg = "Yaksh" + text_msg = "" msg = EmailMultiAlternatives(subject, text_msg, settings.SENDER_EMAIL, recipients ) diff --git a/yaksh/templates/yaksh/course_detail.html b/yaksh/templates/yaksh/course_detail.html index 676d7f3..4ff380e 100644 --- a/yaksh/templates/yaksh/course_detail.html +++ b/yaksh/templates/yaksh/course_detail.html @@ -22,11 +22,15 @@ -- cgit From ca630cd1a3464bc665f06ade7c6e78efa27e93cb Mon Sep 17 00:00:00 2001 From: adityacp Date: Thu, 17 Aug 2017 10:40:43 +0530 Subject: Change course.js to validate email form details --- yaksh/static/yaksh/js/course.js | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) (limited to 'yaksh') diff --git a/yaksh/static/yaksh/js/course.js b/yaksh/static/yaksh/js/course.js index 74ad37c..0eeb017 100644 --- a/yaksh/static/yaksh/js/course.js +++ b/yaksh/static/yaksh/js/course.js @@ -43,37 +43,30 @@ $(function() { }) }); -var status; -var btn_name; - $("#send_mail").click(function(){ - btn_name = "send_mail"; var subject = $("#subject").val(); var body = $('#email_body').val(); + var status; if (subject == '' || body == ''){ status = false; - $("#error_msg").html("Please enter email details"); + $("#error_msg").html("Please enter mail details"); $("#dialog").dialog(); } else{ status = true; } + return status; }); $('#send_mail_form').submit(function(eventObj) { - if (btn_name == 'send_mail'){ - if(status == false){ - return false; - } - } var selected = []; $('#reject input:checked').each(function() { selected.push($(this).attr('value')); }); - if(selected.length > 0){ + if(selected.length > 0) { return true; } - else{ + else { $("#error_msg").html("Please select atleast one user"); $( "#dialog" ).dialog(); return false; -- cgit From 8c1d2ffb0670998c35bd963d5458d245ac97c5fd Mon Sep 17 00:00:00 2001 From: adityacp Date: Thu, 17 Aug 2017 10:45:38 +0530 Subject: Course Detail Template change - Change input html tag to textarea for email subject - Change confussing variable name from template --- yaksh/templates/yaksh/course_detail.html | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'yaksh') diff --git a/yaksh/templates/yaksh/course_detail.html b/yaksh/templates/yaksh/course_detail.html index 4ff380e..1f0e894 100644 --- a/yaksh/templates/yaksh/course_detail.html +++ b/yaksh/templates/yaksh/course_detail.html @@ -10,8 +10,7 @@ {% endblock %} {% block css %} - - + {% endblock %} @@ -21,7 +20,7 @@
{% endif %} - {% if msg == 'mail' %} + {% if status == 'mail' %}
Send Mails to Students

{% if course.get_enrolled %} @@ -85,7 +84,7 @@ {% endfor %}
- +


Attachments: -- cgit From 4f305d1e2ccce8b2250624838a29d2000d0d9230 Mon Sep 17 00:00:00 2001 From: adityacp Date: Thu, 17 Aug 2017 10:47:50 +0530 Subject: Change views.py - Pep8 changes - Remove redundant check from send mail function - Move validation send mail validation to js --- yaksh/views.py | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) (limited to 'yaksh') diff --git a/yaksh/views.py b/yaksh/views.py index ffdcf98..b4ab9bb 100644 --- a/yaksh/views.py +++ b/yaksh/views.py @@ -732,6 +732,7 @@ def enroll(request, course_id, user_id=None, was_rejected=False): course.enroll(was_rejected, *users) return course_detail(request, course_id) + @login_required @email_verified def send_mail(request, course_id, user_id=None): @@ -747,25 +748,23 @@ def send_mail(request, course_id, user_id=None): message = None if request.method == 'POST': user_ids = request.POST.getlist('check') - if not user_ids: - message = "Please select atleast one User" - return my_render_to_response('yaksh/course_detail.html', - {'course': course, "message": message}, - context_instance=ci) - if request.POST.get('send_mail') == 'send_mail': users = User.objects.filter(id__in=user_ids) - recipients = [user.email for user in users] + 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) + message = send_bulk_mail( + subject, email_body, recipients, attachments + ) + context = { + 'course': course, 'message': message, + 'status': 'mail' + } + return my_render_to_response( + 'yaksh/course_detail.html', context, context_instance=ci + ) - return my_render_to_response('yaksh/course_detail.html', - {'course': course, "message": message, - 'msg': 'mail'}, - context_instance=ci) @login_required @email_verified -- cgit From 30bd1c36a4abea6c6afea3a52d3a84d335c5673a Mon Sep 17 00:00:00 2001 From: adityacp Date: Thu, 17 Aug 2017 10:50:52 +0530 Subject: Change test_views.py - Remove validation test case for send mail - Pep8 changes --- yaksh/test_views.py | 35 ++++++++++++++++------------------- 1 file changed, 16 insertions(+), 19 deletions(-) (limited to 'yaksh') diff --git a/yaksh/test_views.py b/yaksh/test_views.py index 3c5b0dd..763f5ff 100644 --- a/yaksh/test_views.py +++ b/yaksh/test_views.py @@ -1869,16 +1869,19 @@ class TestCourseDetail(TestCase): 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.student3.email, self.student4.email] self.user1_course.students.add(*user_ids) attachment = SimpleUploadedFile("file.txt", b"Test") - response = self.client.post(reverse('yaksh:send_mail', - kwargs={'course_id': self.user1_course.id}), - data={'send_mail': 'send_mail', 'email_attach': [attachment], - 'subject': 'test_bulk_mail', 'body': 'Test_Mail', - 'check': user_ids} - ) + 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] @@ -1889,18 +1892,12 @@ class TestCourseDetail(TestCase): 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(response.status_code, 200) - self.assertEqual(response.context['course'], self.user1_course) - - # Test if no users are selected - post_response = self.client.post(reverse('yaksh:send_mail', - kwargs={'course_id': self.user1_course.id}), - data={'check': []} - ) - self.assertIn('select', post_response.context['message']) + 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['status'], 'mail') class TestEnrollRequest(TestCase): -- cgit From dade8a89e3e3f882aa05f974feed1b7248fd6de8 Mon Sep 17 00:00:00 2001 From: adityacp Date: Tue, 22 Aug 2017 12:22:32 +0530 Subject: Change course.js, course_detail.html and views.py - Change form submission for send email in js - Change template and view variable for mail status --- yaksh/static/yaksh/js/course.js | 31 ++++++++++++------------------- yaksh/templates/yaksh/course_detail.html | 4 ++-- yaksh/views.py | 2 +- 3 files changed, 15 insertions(+), 22 deletions(-) (limited to 'yaksh') diff --git a/yaksh/static/yaksh/js/course.js b/yaksh/static/yaksh/js/course.js index 0eeb017..8fb2773 100644 --- a/yaksh/static/yaksh/js/course.js +++ b/yaksh/static/yaksh/js/course.js @@ -38,7 +38,7 @@ $(".reject").change( function(){ $(function() { $('textarea#email_body').froalaEditor({ - heightMin: 100, + heightMin: 200, heightMax: 200 }) }); @@ -46,31 +46,24 @@ $(function() { $("#send_mail").click(function(){ var subject = $("#subject").val(); var body = $('#email_body').val(); - var status; - if (subject == '' || body == ''){ - status = false; - $("#error_msg").html("Please enter mail details"); - $("#dialog").dialog(); - } - else{ - status = true; - } - return status; -}); - -$('#send_mail_form').submit(function(eventObj) { + var status = false; var selected = []; $('#reject input:checked').each(function() { selected.push($(this).attr('value')); }); - if(selected.length > 0) { - return true; + + if (subject == '' || body == ''){ + $("#error_msg").html("Please enter mail details"); + $("#dialog").dialog(); } - else { + else if (selected.length == 0){ $("#error_msg").html("Please select atleast one user"); - $( "#dialog" ).dialog(); - return false; + $("#dialog").dialog(); } + else { + status = true; + } + return status; }); }); diff --git a/yaksh/templates/yaksh/course_detail.html b/yaksh/templates/yaksh/course_detail.html index 1f0e894..bcada42 100644 --- a/yaksh/templates/yaksh/course_detail.html +++ b/yaksh/templates/yaksh/course_detail.html @@ -20,7 +20,7 @@
{% endif %} - {% if status == 'mail' %} + {% if state == 'mail' %}
Send Mails to Students

{% if course.get_enrolled %} diff --git a/yaksh/views.py b/yaksh/views.py index b4ab9bb..db45a89 100644 --- a/yaksh/views.py +++ b/yaksh/views.py @@ -759,7 +759,7 @@ def send_mail(request, course_id, user_id=None): ) context = { 'course': course, 'message': message, - 'status': 'mail' + 'state': 'mail' } return my_render_to_response( 'yaksh/course_detail.html', context, context_instance=ci -- cgit From d6c4d44dca8520926fd781b87e35ecd7843e515c Mon Sep 17 00:00:00 2001 From: adityacp Date: Tue, 22 Aug 2017 12:25:47 +0530 Subject: Change test_views for send mail test --- yaksh/test_views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'yaksh') diff --git a/yaksh/test_views.py b/yaksh/test_views.py index 763f5ff..f8a7c87 100644 --- a/yaksh/test_views.py +++ b/yaksh/test_views.py @@ -1897,7 +1897,7 @@ class TestCourseDetail(TestCase): ) self.assertEqual(get_response.status_code, 200) self.assertEqual(get_response.context['course'], self.user1_course) - self.assertEqual(get_response.context['status'], 'mail') + self.assertEqual(get_response.context['state'], 'mail') class TestEnrollRequest(TestCase): -- cgit From ceb55baf69c2f5f7346855ee5a6e5e9f77456fcb Mon Sep 17 00:00:00 2001 From: ankitjavalkar Date: Fri, 21 Jul 2017 17:07:24 +0530 Subject: Add a has_profile decorator --- yaksh/decorators.py | 37 ++++++++++++++++++++++++++++++++----- yaksh/models.py | 5 ----- yaksh/test_views.py | 35 ++++++++++++++++++++++++++++++----- yaksh/views.py | 26 +++++++++----------------- 4 files changed, 71 insertions(+), 32 deletions(-) (limited to 'yaksh') diff --git a/yaksh/decorators.py b/yaksh/decorators.py index f0d354c..8e5f879 100644 --- a/yaksh/decorators.py +++ b/yaksh/decorators.py @@ -1,12 +1,39 @@ -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) + template = 'manage.html' if 'moderator' in request.user.groups.all() else '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 +41,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/models.py b/yaksh/models.py index 87e6260..30ecde0 100644 --- a/yaksh/models.py +++ b/yaksh/models.py @@ -92,11 +92,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/test_views.py b/yaksh/test_views.py index f8a7c87..fefe9bc 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 diff --git a/yaksh/views.py b/yaksh/views.py index 248a333..823e506 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,\ @@ -43,7 +43,7 @@ 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, send_bulk_mail -from .decorators import email_verified +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.""" @@ -280,6 +281,7 @@ def add_quiz(request, course_id, quiz_id=None): context_instance=ci) @login_required +@has_profile @email_verified def prof_manage(request, msg=None): """Take credentials of the user with professor/moderator @@ -1221,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 """ @@ -1230,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 """ @@ -1255,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) -- cgit From 281e28819d4ab62cc01722d90dd4951e417e16cb Mon Sep 17 00:00:00 2001 From: ankitjavalkar Date: Thu, 3 Aug 2017 15:44:39 +0530 Subject: Add review changes and more tests --- yaksh/decorators.py | 5 +++- yaksh/test_views.py | 68 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 72 insertions(+), 1 deletion(-) (limited to 'yaksh') diff --git a/yaksh/decorators.py b/yaksh/decorators.py index 8e5f879..9e9bc6d 100644 --- a/yaksh/decorators.py +++ b/yaksh/decorators.py @@ -21,7 +21,10 @@ def has_profile(func): if user_has_profile(request.user): return func(request, *args, **kwargs) ci = RequestContext(request) - template = 'manage.html' if 'moderator' in request.user.groups.all() else 'user.html' + 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, diff --git a/yaksh/test_views.py b/yaksh/test_views.py index fefe9bc..8025ecf 100644 --- a/yaksh/test_views.py +++ b/yaksh/test_views.py @@ -274,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( @@ -316,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 @@ -2586,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) @@ -2679,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 -- cgit