changeset 818:cf486a8e8b43

Added the ability to export private messages to email.
author Brian Neal <bgneal@gmail.com>
date Sat, 13 Sep 2014 16:19:46 -0500
parents 74e84f5fc948
children 38db6ec61af3
files messages/static/js/messages.js messages/tests/test_views.py messages/urls.py messages/views.py sg101/templates/messages/inbox.html sg101/templates/messages/outbox.html sg101/templates/messages/pm_email.txt
diffstat 7 files changed, 170 insertions(+), 40 deletions(-) [+]
line wrap: on
line diff
--- 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;
 }
--- 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."""
--- 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'),
--- 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)
--- 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 @@
 </p>
 {% if page.object_list %}
    {% include "messages/pagination.html" %}
-   <form action="{% url 'messages-delete' %}" method="post" onsubmit="return bulkMsgAction('delete');">{% csrf_token %}
+   <form action="{% url 'messages-bulk' %}" method="post">{% csrf_token %}
    <table class="messages">
    <tr>
       <th>From</th>
@@ -30,7 +30,12 @@
       <td><input type="checkbox" name="pm_ids" value="{{ msg.id }}" /></td>
    </tr>
    {% endfor %}
-   <tr><td colspan="4"><input type="submit" value="Delete Checked Messages" /></td></tr>
+   <tr>
+      <td colspan="4">
+         <input type="submit" name="action" value="Email Checked Messages" onclick="return bulkMsgAction('email');" />
+         <input type="submit" name="action" value="Delete Checked Messages" onclick="return bulkMsgAction('delete');" />
+      </td>
+   </tr>
    </table>
    <input type="hidden" name="src" value="inbox" />
    <input type="hidden" name="page" value="{{ page.number }}" />
--- 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 @@
 </p>
 {% if page.object_list %}
    {% include "messages/pagination.html" %}
-   <form action="{% url 'messages-delete' %}" method="post" onsubmit="return bulkMsgAction('delete');">{% csrf_token %}
+   <form action="{% url 'messages-bulk' %}" method="post">{% csrf_token %}
    <table class="messages"> 
    <tr>
       <th>To</th>
@@ -32,7 +32,12 @@
       <td><input type="checkbox" name="pm_ids" value="{{ msg.id }}" /></td>
    </tr>
    {% endfor %}
-   <tr><td colspan="5"><input type="submit" value="Delete Checked Messages" /></td></tr>
+   <tr>
+      <td colspan="5">
+         <input type="submit" name="action" value="Email Checked Messages" onclick="return bulkMsgAction('email');" />
+         <input type="submit" name="action" value="Delete Checked Messages" onclick="return bulkMsgAction('delete');" />
+      </td>
+   </tr>
    </table>
    <input type="hidden" name="src" value="outbox" />
    <input type="hidden" name="page" value="{{ page.number }}" />
--- /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 }}.