annotate messages/views.py @ 807:22cc8c1aec03

Private message refactor: add undelete functionality.
author Brian Neal <bgneal@gmail.com>
date Mon, 01 Sep 2014 16:22:13 -0500
parents 59e36169a814
children 4a4fa174a0ec
rev   line source
bgneal@425 1 """
bgneal@425 2 Views for the messages application.
bgneal@425 3
bgneal@425 4 """
bgneal@425 5 import datetime
bgneal@425 6
bgneal@425 7 from django.contrib.auth.decorators import login_required
bgneal@806 8 from django.views.decorators.http import require_POST
bgneal@436 9 from django.contrib import messages as django_messages
bgneal@801 10 from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
bgneal@425 11 from django.core.urlresolvers import reverse
bgneal@425 12 from django.shortcuts import get_object_or_404
bgneal@805 13 from django.shortcuts import render, redirect
bgneal@425 14
bgneal@425 15 from messages.models import Message, Options
bgneal@425 16 from messages.forms import OptionsForm, ComposeForm
bgneal@566 17 from messages.utils import reply_subject
bgneal@436 18 from messages import MSG_BOX_LIMIT
bgneal@566 19 from core.functions import quote_message
bgneal@425 20
bgneal@425 21
bgneal@436 22 MSGS_PER_PAGE = 20 # message pagination value
bgneal@425 23
bgneal@425 24
bgneal@436 25 def _quota_check(box_name, count, request):
bgneal@436 26 """
bgneal@436 27 Checks the message box count against MSG_BOX_LIMIT.
bgneal@436 28 Emits a message to the user if the quota is exceeded.
bgneal@441 29
bgneal@568 30 Returns the percent used as an integer between 0-100.
bgneal@568 31
bgneal@436 32 """
bgneal@436 33 if count >= MSG_BOX_LIMIT:
bgneal@436 34 django_messages.warning(request,
bgneal@436 35 "Your %s is full. Please delete some messages." % box_name)
bgneal@436 36
bgneal@568 37 return 100 * count / MSG_BOX_LIMIT
bgneal@568 38
bgneal@436 39
bgneal@801 40 def _get_page(request, qs):
bgneal@801 41 """Paginates the given queryset and returns a page object"""
bgneal@801 42 paginator = Paginator(qs, MSGS_PER_PAGE)
bgneal@801 43 try:
bgneal@801 44 page = paginator.page(request.GET.get('page', '1'))
bgneal@801 45 except PageNotAnInteger:
bgneal@801 46 page = paginator.page(1)
bgneal@801 47 except EmptyPage:
bgneal@801 48 page = paginator.page(paginator.num_pages)
bgneal@801 49 return page
bgneal@801 50
bgneal@801 51
bgneal@425 52 @login_required
bgneal@801 53 def inbox(request):
bgneal@425 54
bgneal@801 55 msg_list = Message.objects.inbox(request.user)
bgneal@801 56 msg_count = msg_list.count()
bgneal@801 57 pct_used = _quota_check('inbox', msg_count, request)
bgneal@801 58
bgneal@801 59 page = _get_page(request, msg_list)
bgneal@801 60
bgneal@801 61 return render(request, 'messages/inbox.html', {
bgneal@801 62 'tab': 'inbox',
bgneal@801 63 'page': page,
bgneal@801 64 'inbox_pct': pct_used,
bgneal@801 65 'outbox_pct': None,
bgneal@801 66 })
bgneal@801 67
bgneal@801 68
bgneal@801 69 @login_required
bgneal@801 70 def outbox(request):
bgneal@801 71
bgneal@801 72 msg_list = Message.objects.outbox(request.user)
bgneal@801 73 msg_count = msg_list.count()
bgneal@801 74 pct_used = _quota_check('outbox', msg_count, request)
bgneal@801 75
bgneal@801 76 page = _get_page(request, msg_list)
bgneal@801 77
bgneal@801 78 return render(request, 'messages/outbox.html', {
bgneal@801 79 'tab': 'outbox',
bgneal@801 80 'page': page,
bgneal@801 81 'inbox_pct': None,
bgneal@801 82 'outbox_pct': pct_used,
bgneal@425 83 })
bgneal@425 84
bgneal@425 85
bgneal@428 86 @login_required
bgneal@802 87 def trash(request):
bgneal@802 88
bgneal@802 89 msg_list = Message.objects.trash(request.user)
bgneal@802 90
bgneal@802 91 page = _get_page(request, msg_list)
bgneal@802 92
bgneal@802 93 return render(request, 'messages/trash.html', {
bgneal@802 94 'tab': 'trash',
bgneal@802 95 'page': page,
bgneal@802 96 'inbox_pct': None,
bgneal@802 97 'outbox_pct': None,
bgneal@802 98 })
bgneal@802 99
bgneal@802 100
bgneal@802 101 @login_required
bgneal@803 102 def options(request):
bgneal@803 103 """
bgneal@803 104 This view handles the displaying and changing of private message options.
bgneal@803 105
bgneal@803 106 """
bgneal@803 107 if request.method == 'POST':
bgneal@803 108 options = Options.objects.for_user(request.user)
bgneal@803 109 form = OptionsForm(request.POST, instance=options, prefix='opts')
bgneal@803 110 if form.is_valid():
bgneal@803 111 form.save()
bgneal@803 112 django_messages.success(request, 'Options saved.')
bgneal@803 113 else:
bgneal@803 114 options = Options.objects.for_user(request.user)
bgneal@803 115 form = OptionsForm(instance=options, prefix='opts')
bgneal@803 116
bgneal@803 117 return render(request, 'messages/options.html', {
bgneal@803 118 'tab': 'options',
bgneal@803 119 'form': form,
bgneal@803 120 })
bgneal@803 121
bgneal@803 122
bgneal@803 123 @login_required
bgneal@804 124 def compose(request):
bgneal@428 125 """
bgneal@804 126 Process or prepare the compose form to create a new private message.
bgneal@428 127
bgneal@428 128 """
bgneal@804 129 if request.method == 'POST':
bgneal@804 130 compose_form = ComposeForm(request.user, request.POST)
bgneal@804 131 if compose_form.is_valid():
bgneal@804 132 compose_form.save()
bgneal@804 133 django_messages.success(request, 'Message sent.')
bgneal@804 134 compose_form = ComposeForm(request.user)
bgneal@804 135 else:
bgneal@804 136 receiver = request.GET.get('to')
bgneal@804 137 if receiver:
bgneal@804 138 form_data = {'receiver': receiver}
bgneal@804 139 compose_form = ComposeForm(request.user, initial=form_data)
bgneal@804 140 else:
bgneal@804 141 compose_form = ComposeForm(request.user)
bgneal@804 142
bgneal@804 143 _quota_check('outbox', Message.objects.outbox(request.user).count(), request)
bgneal@804 144
bgneal@804 145 return render(request, 'messages/compose.html', {
bgneal@804 146 'tab': 'compose',
bgneal@804 147 'compose_form': compose_form,
bgneal@428 148 })
bgneal@428 149
bgneal@428 150
bgneal@804 151 @login_required
bgneal@804 152 def view(request, msg_id):
bgneal@425 153 """
bgneal@805 154 This view function displays a private message for reading to the user. If
bgneal@805 155 the user is a recipient of the message, a reply can be composed and sent.
bgneal@425 156
bgneal@425 157 """
bgneal@805 158 if request.method == 'POST':
bgneal@805 159 form = ComposeForm(request.user, request.POST)
bgneal@805 160 if form.is_valid():
bgneal@805 161 form.save()
bgneal@805 162 django_messages.success(request, 'Reply sent.')
bgneal@805 163 return redirect('messages-inbox')
bgneal@805 164 else:
bgneal@805 165 msg = get_object_or_404(Message.objects.select_related(), pk=msg_id)
bgneal@805 166 if msg.sender != request.user and msg.receiver != request.user:
bgneal@805 167 django_messages.error(request,
bgneal@805 168 "You don't have permission to read that message.")
bgneal@805 169 return redirect('messages-inbox')
bgneal@425 170
bgneal@805 171 initial_data = {
bgneal@805 172 'receiver': msg.sender.username,
bgneal@805 173 'subject': reply_subject(msg.subject),
bgneal@805 174 'message': quote_message(msg.sender.username, msg.message),
bgneal@805 175 'parent_id': msg.pk,
bgneal@805 176 }
bgneal@425 177
bgneal@805 178 if msg.receiver == request.user:
bgneal@805 179 if msg.read_date is None:
bgneal@805 180 msg.read_date = datetime.datetime.now()
bgneal@805 181 msg.save()
bgneal@805 182 else:
bgneal@805 183 initial_data['receiver'] = msg.receiver.username
bgneal@425 184
bgneal@805 185 form = ComposeForm(request.user, initial=initial_data)
bgneal@425 186
bgneal@805 187 return render(request, 'messages/view_message.html', {
bgneal@805 188 'msg': msg,
bgneal@805 189 'form': form,
bgneal@805 190 })
bgneal@425 191
bgneal@425 192
bgneal@806 193 def _delete_pms(user, pm_ids):
bgneal@425 194 """
bgneal@806 195 Process the request to delete the list of PM ids by user.
bgneal@425 196
bgneal@807 197 Returns the number of PM's deleted.
bgneal@807 198
bgneal@425 199 """
bgneal@806 200 msgs = Message.objects.filter(id__in=pm_ids)
bgneal@806 201 now = datetime.datetime.now()
bgneal@425 202
bgneal@807 203 count = 0
bgneal@425 204 for msg in msgs:
bgneal@425 205 if msg.sender == user:
bgneal@806 206 if msg.receiver_delete_date is not None or msg.read_date is None:
bgneal@425 207 # Both parties deleted the message or receiver hasn't read it
bgneal@425 208 # yet, we can delete it now
bgneal@425 209 msg.delete()
bgneal@425 210 else:
bgneal@806 211 # receiver still has PM in their inbox
bgneal@806 212 msg.sender_delete_date = now
bgneal@425 213 msg.save()
bgneal@807 214 count += 1
bgneal@425 215 elif msg.receiver == user:
bgneal@425 216 if msg.sender_delete_date is not None:
bgneal@425 217 # both parties deleted the message, we can delete it now
bgneal@425 218 msg.delete()
bgneal@425 219 else:
bgneal@806 220 # sender still has PM in their inbox
bgneal@806 221 msg.receiver_delete_date = now
bgneal@425 222 msg.save()
bgneal@807 223 count += 1
bgneal@807 224
bgneal@807 225 return count
bgneal@425 226
bgneal@425 227
bgneal@806 228 @login_required
bgneal@806 229 @require_POST
bgneal@806 230 def delete(request):
bgneal@806 231 """
bgneal@806 232 Deletes the requested PM's. The user must be either a sender or receiver for
bgneal@806 233 this to work.
bgneal@806 234
bgneal@806 235 """
bgneal@806 236 pm_ids = request.POST.getlist('pm_ids')
bgneal@806 237 if pm_ids:
bgneal@807 238 count = _delete_pms(request.user, pm_ids)
bgneal@807 239 msg = '{} message{} deleted.'.format(count, '' if count == 1 else 's')
bgneal@807 240 django_messages.success(request, msg)
bgneal@806 241
bgneal@806 242 # Figure out where to redirect to
bgneal@806 243 src = request.POST.get('src', 'inbox')
bgneal@806 244 try:
bgneal@806 245 page = int(request.POST.get('page', '1'))
bgneal@806 246 except ValueError:
bgneal@806 247 page = 1
bgneal@806 248
bgneal@807 249 view_name = 'messages-inbox' if src == 'inbox' else 'messages-outbox'
bgneal@806 250 url = reverse(view_name) + '?page={}'.format(page)
bgneal@806 251 return redirect(url)
bgneal@806 252
bgneal@806 253
bgneal@807 254 def _undelete_pms(user, msg_ids):
bgneal@425 255 """
bgneal@425 256 Attempts to "undelete" the messages given by the msg_ids list.
bgneal@425 257 This will only succeed if the user is either the sender or receiver.
bgneal@425 258
bgneal@807 259 Returns the number of PM's undeleted.
bgneal@807 260
bgneal@425 261 """
bgneal@425 262 msgs = Message.objects.filter(id__in=msg_ids)
bgneal@807 263 count = 0
bgneal@425 264 for msg in msgs:
bgneal@425 265 if msg.sender == user:
bgneal@425 266 msg.sender_delete_date = None
bgneal@425 267 msg.save()
bgneal@807 268 count += 1
bgneal@425 269 elif msg.receiver == user:
bgneal@425 270 msg.receiver_delete_date = None
bgneal@425 271 msg.save()
bgneal@807 272 count += 1
bgneal@807 273 return count
bgneal@425 274
bgneal@425 275
bgneal@807 276 @login_required
bgneal@807 277 @require_POST
bgneal@807 278 def undelete(request):
bgneal@425 279 """
bgneal@807 280 Undeletes the requested PM's. The user must be either a sender or receiver for
bgneal@807 281 this to work.
bgneal@425 282
bgneal@425 283 """
bgneal@807 284 pm_ids = request.POST.getlist('pm_ids')
bgneal@807 285 if pm_ids:
bgneal@807 286 count = _undelete_pms(request.user, pm_ids)
bgneal@807 287 msg = '{} message{} undeleted.'.format(count, '' if count == 1 else 's')
bgneal@807 288 django_messages.success(request, msg)
bgneal@425 289
bgneal@807 290 # Figure out where to redirect to
bgneal@807 291 try:
bgneal@807 292 page = int(request.POST.get('page', '1'))
bgneal@807 293 except ValueError:
bgneal@807 294 page = 1
bgneal@425 295
bgneal@807 296 url = reverse('messages-trash') + '?page={}'.format(page)
bgneal@807 297 return redirect(url)