# HG changeset patch # User Brian Neal # Date 1410643186 18000 # Node ID cf486a8e8b43d39d6ea34ff56aeb49c5cf583ceb # Parent 74e84f5fc948001006e8167334a3e52a30a8953e Added the ability to export private messages to email. diff -r 74e84f5fc948 -r cf486a8e8b43 messages/static/js/messages.js --- a/messages/static/js/messages.js Wed Sep 10 19:38:55 2014 -0500 +++ b/messages/static/js/messages.js Sat Sep 13 16:19:46 2014 -0500 @@ -6,6 +6,11 @@ } function bulkMsgAction(action) { + var total = $('input[name="pm_ids"]:checked').length; + if (total <= 0) { + alert('Please check some messages first.'); + return false; + } return confirm("Really " + action + " checked messages?"); return false; } diff -r 74e84f5fc948 -r cf486a8e8b43 messages/tests/test_views.py --- a/messages/tests/test_views.py Wed Sep 10 19:38:55 2014 -0500 +++ b/messages/tests/test_views.py Sat Sep 13 16:19:46 2014 -0500 @@ -50,7 +50,7 @@ self._test_post(url_name) def test_delete(self): - self._test_get('messages-delete') + self._test_get('messages-bulk') def test_undelete(self): self._test_get('messages-undelete') @@ -107,7 +107,7 @@ def test_wrong_method(self): view_names = [ - 'messages-delete', + 'messages-bulk', 'messages-undelete', ] for view_name in view_names: @@ -343,8 +343,9 @@ delete_post_data = { 'pm_ids': [msg2.pk], + 'action': 'Delete', } - view_name = 'messages-delete' + view_name = 'messages-bulk' url = reverse(view_name) response = self.client.post(url, data=delete_post_data, follow=True) self.assertContains(response, "1 message deleted", status_code=200) @@ -373,8 +374,9 @@ self.assertTrue(self.client.login(username='eddie', password='12345')) delete_post_data = { 'pm_ids': [msg2.pk], + 'action': 'Delete', } - view_name = 'messages-delete' + view_name = 'messages-bulk' url = reverse(view_name) response = self.client.post(url, data=delete_post_data, follow=True) self.assertContains(response, "1 message deleted", status_code=200) @@ -389,8 +391,9 @@ # eddie deletes then undeletes message 1 delete_post_data = { 'pm_ids': [msg1.pk], + 'action': 'Delete', } - view_name = 'messages-delete' + view_name = 'messages-bulk' url = reverse(view_name) response = self.client.post(url, data=delete_post_data, follow=True) self.assertContains(response, "1 message deleted", status_code=200) @@ -604,6 +607,37 @@ self.assertContains(response, "Your outbox is full", status_code=200) self.assertEqual(Message.objects.all().count(), self.MSG_BOX_LIMIT) + def test_email_export(self): + + post_data = { + 'receiver': 'eddie', + 'subject': 'Mr. Moto Demo', + 'message': 'Gig at Newport High School', + } + view_name = 'messages-compose' + url = reverse(view_name) + response = self.client.post(url, data=post_data) + self.assertContains(response, "Message sent", status_code=200) + + msg = Message.objects.get(receiver=self.users['eddie']) + post_data = { + 'pm_ids': [msg.id], + 'action': 'Email', + } + view_name = 'messages-bulk' + url = reverse(view_name) + response = self.client.post(url, data=post_data, follow=True) + self.assertContains(response, "1 message sent to email", status_code=200) + + # Ensure email sent + self.assertEqual(len(mail.outbox), 1) + + if len(mail.outbox) == 1: + email = mail.outbox[0] + self.assertEqual(len(email.recipients()), 1) + self.assertEqual(email.recipients()[0], 'pj@example.com') + self.assertTrue(email.subject.startswith('Private messages from')) + class EmailTestCase(TestCase): """Testing to ensure email is sent when PM is sent if options allow.""" diff -r 74e84f5fc948 -r cf486a8e8b43 messages/urls.py --- a/messages/urls.py Wed Sep 10 19:38:55 2014 -0500 +++ b/messages/urls.py Sat Sep 13 16:19:46 2014 -0500 @@ -21,9 +21,9 @@ url(r'^options/$', 'messages.views.options', name='messages-options'), - url(r'^delete/$', - 'messages.views.delete', - name='messages-delete'), + url(r'^bulk/$', + 'messages.views.bulk', + name='messages-bulk'), url(r'^undelete/$', 'messages.views.undelete', name='messages-undelete'), diff -r 74e84f5fc948 -r cf486a8e8b43 messages/views.py --- a/messages/views.py Wed Sep 10 19:38:55 2014 -0500 +++ b/messages/views.py Sat Sep 13 16:19:46 2014 -0500 @@ -11,15 +11,20 @@ from django.core.urlresolvers import reverse from django.shortcuts import get_object_or_404 from django.shortcuts import render, redirect +from django.db.models import Q +from django.template.loader import render_to_string +from django.contrib.sites.models import Site +from django.conf import settings from messages.models import Flag, Message, Options from messages.forms import OptionsForm, ComposeForm, ReportForm from messages.utils import reply_subject from messages import MSG_BOX_LIMIT -from core.functions import email_admins, quote_message +from core.functions import email_admins, quote_message, send_mail MSGS_PER_PAGE = 20 # message pagination value +PM_EMAIL_MAX = 100 # max messages we will send via email REPORT_SUBJECT = 'A user has flagged a private message' REPORT_MSG = """Hello, @@ -204,13 +209,46 @@ }) -def _delete_pms(user, pm_ids): +@login_required +@require_POST +def bulk(request): + """ + Perform bulk action on a list of PMs. + + """ + pm_ids = request.POST.getlist('pm_ids') + + # Figure out what action to perform + action = None + action_val = request.POST.get('action', '') + if action_val.startswith('Delete'): + action = _delete_pms + elif action_val.startswith('Email'): + action = _email_pms + + if pm_ids and action: + action(request, pm_ids) + + # Figure out where to redirect to + src = request.POST.get('src', 'inbox') + try: + page = int(request.POST.get('page', '1')) + except ValueError: + page = 1 + + view_name = 'messages-inbox' if src == 'inbox' else 'messages-outbox' + url = reverse(view_name) + '?page={}'.format(page) + return redirect(url) + + +def _delete_pms(request, pm_ids): """ Process the request to delete the list of PM ids by user. Returns the number of PM's deleted. """ + user = request.user msgs = Message.objects.filter(id__in=pm_ids) now = datetime.datetime.now() @@ -236,33 +274,11 @@ msg.save() count += 1 - return count - - -@login_required -@require_POST -def delete(request): - """ - Deletes the requested PM's. The user must be either a sender or receiver for - this to work. - - """ - pm_ids = request.POST.getlist('pm_ids') - if pm_ids: - count = _delete_pms(request.user, pm_ids) - msg = '{} message{} deleted.'.format(count, '' if count == 1 else 's') + msg = '{} message{} deleted.'.format(count, '' if count == 1 else 's') + if count > 0: django_messages.success(request, msg) - - # Figure out where to redirect to - src = request.POST.get('src', 'inbox') - try: - page = int(request.POST.get('page', '1')) - except ValueError: - page = 1 - - view_name = 'messages-inbox' if src == 'inbox' else 'messages-outbox' - url = reverse(view_name) + '?page={}'.format(page) - return redirect(url) + else: + django_messages.error(request, msg) def _undelete_pms(user, msg_ids): @@ -345,3 +361,48 @@ 'msg': msg, 'form': form, }) + + +def _email_pms(request, msg_ids): + """ + Attempts to email the messages given by the msg_ids list to the user. + This will only succeed if the user is either the sender or receiver. + + Returns the number of PM's sent. + + """ + # Does the user have an email address? + user = request.user + email_addr = user.email + if not email_addr: + return 0 + + msgs = Message.objects.filter( + Q(sender=user) | Q(receiver=user), + id__in=msg_ids).order_by('pk')[:PM_EMAIL_MAX] + + count = len(msgs) + if count == 0: + return 0 + + site = Site.objects.get_current() + admin_email = settings.ADMINS[0][1] + + subject = 'Private messages from {} - {}'.format(site.domain, + msgs[0].subject) + if count > 1: + subject += ' (et al.)' + from_email = '{}@{}'.format(settings.GPP_NO_REPLY_EMAIL, site.domain) + msg_body = render_to_string('messages/pm_email.txt', { + 'site': site, + 'user': user, + 'msgs': msgs, + 'admin_email': admin_email, + }) + send_mail(subject, msg_body, from_email, [email_addr], defer=False) + + msg = '{} message{} sent to email.'.format(count, '' if count == 1 else 's') + if count > 0: + django_messages.success(request, msg) + else: + django_messages.error(request, msg) diff -r 74e84f5fc948 -r cf486a8e8b43 sg101/templates/messages/inbox.html --- a/sg101/templates/messages/inbox.html Wed Sep 10 19:38:55 2014 -0500 +++ b/sg101/templates/messages/inbox.html Sat Sep 13 16:19:46 2014 -0500 @@ -10,7 +10,7 @@

{% if page.object_list %} {% include "messages/pagination.html" %} -
{% csrf_token %} + {% csrf_token %} @@ -30,7 +30,12 @@ {% endfor %} - + + +
From
+ + +
diff -r 74e84f5fc948 -r cf486a8e8b43 sg101/templates/messages/outbox.html --- a/sg101/templates/messages/outbox.html Wed Sep 10 19:38:55 2014 -0500 +++ b/sg101/templates/messages/outbox.html Sat Sep 13 16:19:46 2014 -0500 @@ -10,7 +10,7 @@

{% if page.object_list %} {% include "messages/pagination.html" %} - {% csrf_token %} + {% csrf_token %} @@ -32,7 +32,12 @@ {% endfor %} - + + +
To
+ + +
diff -r 74e84f5fc948 -r cf486a8e8b43 sg101/templates/messages/pm_email.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sg101/templates/messages/pm_email.txt Sat Sep 13 16:19:46 2014 -0500 @@ -0,0 +1,20 @@ +Hello {{ user.username }}, + +{{ site.name }} has received a request to email you the following +private messages. +{% for msg in msgs %} +---- +Message ID: {{ msg.id }} +From: {{ msg.sender.username }} +To: {{ msg.receiver.username }} +Sent: {{ msg.send_date|date:"M j, Y g:i A" }} +Received: {{ msg.read_date|date:"M j, Y g:i A" }} +Replied Date: {{ msg.reply_date|date:"M j, Y g:i A" }} +Subject: {{ msg.subject|safe }} + +{{ msg.message.rstrip|safe }} + +{% endfor %} +---- + +If you did not request this email, please contact {{ admin_email }}.