annotate gpp/messages/views.py @ 429:d0f0800eef0c

Making the jquery tabbed version of the messages app the current version and removing the old. Also figured out how to dynamically update the base template's count of unread messages when messages are read.
author Brian Neal <bgneal@gmail.com>
date Tue, 03 May 2011 02:56:58 +0000
parents gpp/messages/views2.py@77b3b01843b5
children 9df368d9775d
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@428 8 from django.contrib.auth.models import User
bgneal@425 9 from django.contrib import messages
bgneal@425 10 from django.core.paginator import Paginator, EmptyPage, InvalidPage
bgneal@425 11 from django.core.urlresolvers import reverse
bgneal@425 12 from django.http import HttpResponse
bgneal@425 13 from django.http import HttpResponseForbidden
bgneal@425 14 from django.http import HttpResponseNotAllowed
bgneal@425 15 from django.http import HttpResponseRedirect
bgneal@425 16 from django.shortcuts import get_object_or_404
bgneal@425 17 from django.shortcuts import render
bgneal@425 18 import django.utils.simplejson as json
bgneal@425 19
bgneal@425 20 from messages.models import Message, Options
bgneal@425 21 from messages.forms import OptionsForm, ComposeForm
bgneal@425 22 from messages.utils import reply_subject, quote_message
bgneal@425 23
bgneal@425 24
bgneal@425 25 MSGS_PER_PAGE = 20
bgneal@425 26
bgneal@425 27 TAB_INDICES = {
bgneal@425 28 'inbox': 0,
bgneal@425 29 'compose': 1,
bgneal@425 30 'outbox': 2,
bgneal@425 31 'trash': 3,
bgneal@425 32 'options': 4,
bgneal@425 33 }
bgneal@425 34
bgneal@425 35
bgneal@425 36 def _get_page(request):
bgneal@425 37 try:
bgneal@425 38 n = int(request.GET.get('page', '1'))
bgneal@425 39 except ValueError:
bgneal@425 40 n = 1
bgneal@425 41 return n
bgneal@425 42
bgneal@425 43
bgneal@425 44 @login_required
bgneal@425 45 def index(request, tab=None):
bgneal@425 46 """
bgneal@425 47 This function displays the base tabbed private messages view.
bgneal@425 48
bgneal@425 49 """
bgneal@425 50 tab_index = TAB_INDICES[tab] if tab else 0
bgneal@425 51 return render(request, 'messages/tabbed_base.html', {
bgneal@425 52 'tab': tab_index,
bgneal@429 53 'unread_count': Message.objects.unread_count(request.user),
bgneal@425 54 })
bgneal@425 55
bgneal@425 56
bgneal@428 57 @login_required
bgneal@428 58 def compose_to(request, receiver):
bgneal@428 59 """
bgneal@428 60 This function displays the base tabbed private messages view,
bgneal@428 61 and configures it to display the compose PM tab for the given
bgneal@428 62 receiver.
bgneal@428 63
bgneal@428 64 """
bgneal@428 65 user = get_object_or_404(User, username=receiver)
bgneal@428 66 tab_index = TAB_INDICES['compose']
bgneal@428 67 return render(request, 'messages/tabbed_base.html', {
bgneal@428 68 'tab': tab_index,
bgneal@428 69 'receiver': receiver,
bgneal@429 70 'unread_count': Message.objects.unread_count(request.user),
bgneal@428 71 })
bgneal@428 72
bgneal@428 73
bgneal@425 74 def inbox(request):
bgneal@425 75 """
bgneal@425 76 Returns the inbox for the user.
bgneal@425 77
bgneal@425 78 """
bgneal@425 79 if not request.user.is_authenticated():
bgneal@425 80 return HttpResponseForbidden()
bgneal@425 81
bgneal@425 82 msg_list = Message.objects.inbox(request.user)
bgneal@425 83 paginator = Paginator(msg_list, MSGS_PER_PAGE)
bgneal@425 84 try:
bgneal@425 85 msgs = paginator.page(_get_page(request))
bgneal@425 86 except EmptyPage, InvalidPage:
bgneal@425 87 msgs = paginator.page(paginator.num_pages)
bgneal@425 88
bgneal@425 89 return render(request, 'messages/inbox_tab.html', {
bgneal@425 90 'msgs': msgs,
bgneal@429 91 'url': reverse('messages-inbox'),
bgneal@425 92 })
bgneal@425 93
bgneal@425 94
bgneal@425 95 def outbox(request):
bgneal@425 96 """
bgneal@425 97 Returns the outbox for the user.
bgneal@425 98
bgneal@425 99 """
bgneal@425 100 if not request.user.is_authenticated():
bgneal@425 101 return HttpResponseForbidden()
bgneal@425 102
bgneal@425 103 msg_list = Message.objects.outbox(request.user)
bgneal@425 104 paginator = Paginator(msg_list, MSGS_PER_PAGE)
bgneal@425 105 try:
bgneal@425 106 msgs = paginator.page(_get_page(request))
bgneal@425 107 except EmptyPage, InvalidPage:
bgneal@425 108 msgs = paginator.page(paginator.num_pages)
bgneal@425 109
bgneal@425 110 return render(request, 'messages/outbox_tab.html', {
bgneal@425 111 'msgs': msgs,
bgneal@429 112 'url': reverse('messages-outbox'),
bgneal@425 113 })
bgneal@425 114
bgneal@425 115
bgneal@425 116 def trash(request):
bgneal@425 117 """
bgneal@425 118 Returns the trash for the user.
bgneal@425 119
bgneal@425 120 """
bgneal@425 121 if not request.user.is_authenticated():
bgneal@425 122 return HttpResponseForbidden()
bgneal@425 123
bgneal@425 124 msg_list = Message.objects.trash(request.user)
bgneal@425 125 paginator = Paginator(msg_list, MSGS_PER_PAGE)
bgneal@425 126 try:
bgneal@425 127 msgs = paginator.page(_get_page(request))
bgneal@425 128 except EmptyPage, InvalidPage:
bgneal@425 129 msgs = paginator.page(paginator.num_pages)
bgneal@425 130
bgneal@425 131 return render(request, 'messages/trash_tab.html', {
bgneal@425 132 'msgs': msgs,
bgneal@429 133 'url': reverse('messages-trash'),
bgneal@425 134 })
bgneal@425 135
bgneal@425 136
bgneal@425 137 def message(request):
bgneal@425 138 """
bgneal@425 139 This view function retrieves a message and returns it as a JSON object.
bgneal@425 140
bgneal@425 141 """
bgneal@425 142 if not request.user.is_authenticated():
bgneal@425 143 return HttpResponseForbidden()
bgneal@425 144 if request.method != 'POST':
bgneal@425 145 return HttpResponseNotAllowed(['POST'])
bgneal@425 146
bgneal@425 147 msg_id = request.POST.get('msg_id')
bgneal@425 148 msg = get_object_or_404(Message.objects.select_related(), pk=msg_id)
bgneal@425 149 if msg.sender != request.user and msg.receiver != request.user:
bgneal@425 150 return HttpResponseForbidden()
bgneal@425 151
bgneal@425 152 if msg.receiver == request.user and msg.read_date is None:
bgneal@425 153 msg.read_date = datetime.datetime.now()
bgneal@425 154 msg.save()
bgneal@425 155
bgneal@425 156 msg_dict = dict(subject=msg.subject,
bgneal@425 157 sender=msg.sender.username,
bgneal@425 158 receiver=msg.receiver.username,
bgneal@425 159 content=msg.html,
bgneal@425 160 re_subject=reply_subject(msg.subject),
bgneal@425 161 re_content=quote_message(msg.sender.username, msg.send_date,
bgneal@425 162 msg.message))
bgneal@425 163
bgneal@425 164 result = json.dumps(msg_dict, ensure_ascii=False)
bgneal@425 165 return HttpResponse(result, content_type='application/json')
bgneal@425 166
bgneal@425 167
bgneal@425 168 def options(request):
bgneal@425 169 """
bgneal@425 170 This view handles the displaying and changing of private message options.
bgneal@425 171
bgneal@425 172 """
bgneal@425 173 if not request.user.is_authenticated():
bgneal@425 174 return HttpResponseForbidden()
bgneal@425 175
bgneal@425 176 if request.method == "POST":
bgneal@425 177 options = Options.objects.for_user(request.user)
bgneal@425 178 form = OptionsForm(request.POST, instance=options, prefix='opts')
bgneal@425 179 if form.is_valid():
bgneal@425 180 form.save()
bgneal@425 181 messages.success(request, 'Options saved.')
bgneal@425 182 else:
bgneal@425 183 options = Options.objects.for_user(request.user)
bgneal@425 184 form = OptionsForm(instance=options, prefix='opts')
bgneal@425 185
bgneal@425 186 return render(request, 'messages/options_tab.html', {
bgneal@425 187 'form': form,
bgneal@425 188 })
bgneal@425 189
bgneal@425 190
bgneal@425 191 def compose(request, receiver=None):
bgneal@425 192 """
bgneal@425 193 Process or prepare the compose form to create a new private message.
bgneal@425 194
bgneal@425 195 """
bgneal@425 196 if not request.user.is_authenticated():
bgneal@425 197 return HttpResponseForbidden()
bgneal@425 198
bgneal@425 199 if request.method == "POST":
bgneal@425 200 compose_form = ComposeForm(request.user, request.POST)
bgneal@425 201 if compose_form.is_valid():
bgneal@425 202 compose_form.save(sender=request.user)
bgneal@425 203 messages.success(request, 'Message sent.')
bgneal@429 204 return HttpResponseRedirect(reverse('messages-index_named', args=['compose']))
bgneal@425 205 else:
bgneal@425 206 if receiver is not None:
bgneal@425 207 form_data = {'receiver': receiver}
bgneal@425 208 compose_form = ComposeForm(request.user, initial=form_data)
bgneal@425 209 else:
bgneal@425 210 compose_form = ComposeForm(request.user)
bgneal@425 211
bgneal@425 212 return render(request, 'messages/compose_tab.html', {
bgneal@425 213 'compose_form': compose_form,
bgneal@425 214 })
bgneal@425 215
bgneal@425 216
bgneal@425 217 def _only_integers(slist):
bgneal@425 218 """
bgneal@425 219 Accepts a list of strings. Returns a list of integers consisting of only
bgneal@425 220 those elements from the original list that could be converted to integers
bgneal@425 221
bgneal@425 222 """
bgneal@425 223 result = []
bgneal@425 224 for s in slist:
bgneal@425 225 try:
bgneal@425 226 n = int(s)
bgneal@425 227 except ValueError:
bgneal@425 228 pass
bgneal@425 229 else:
bgneal@425 230 result.append(n)
bgneal@425 231 return result
bgneal@425 232
bgneal@425 233
bgneal@425 234 def _delete_msgs(user, msg_ids):
bgneal@425 235 """
bgneal@425 236 Deletes the messages given by the list of msg_ids. For this to succeed, the
bgneal@425 237 user has to be either the sender or receiver on each message.
bgneal@425 238
bgneal@425 239 """
bgneal@425 240 msg_ids = _only_integers(msg_ids)
bgneal@425 241 msgs = Message.objects.filter(id__in=msg_ids)
bgneal@425 242
bgneal@425 243 for msg in msgs:
bgneal@425 244 if msg.sender == user:
bgneal@425 245 if (msg.receiver_delete_date is not None or
bgneal@425 246 msg.read_date is None):
bgneal@425 247 # Both parties deleted the message or receiver hasn't read it
bgneal@425 248 # yet, we can delete it now
bgneal@425 249 msg.delete()
bgneal@425 250 else:
bgneal@425 251 # receiver still has it in inbox
bgneal@425 252 msg.sender_delete_date = datetime.datetime.now()
bgneal@425 253 msg.save()
bgneal@425 254
bgneal@425 255 elif msg.receiver == user:
bgneal@425 256 if msg.sender_delete_date is not None:
bgneal@425 257 # both parties deleted the message, we can delete it now
bgneal@425 258 msg.delete()
bgneal@425 259 else:
bgneal@425 260 # sender still has it in the outbox
bgneal@425 261 msg.receiver_delete_date = datetime.datetime.now()
bgneal@425 262 msg.save()
bgneal@425 263
bgneal@425 264
bgneal@425 265 def _undelete_msgs(user, msg_ids):
bgneal@425 266 """
bgneal@425 267 Attempts to "undelete" the messages given by the msg_ids list.
bgneal@425 268 This will only succeed if the user is either the sender or receiver.
bgneal@425 269
bgneal@425 270 """
bgneal@425 271 msg_ids = _only_integers(msg_ids)
bgneal@425 272 msgs = Message.objects.filter(id__in=msg_ids)
bgneal@425 273 for msg in msgs:
bgneal@425 274 if msg.sender == user:
bgneal@425 275 msg.sender_delete_date = None
bgneal@425 276 msg.save()
bgneal@425 277 elif msg.receiver == user:
bgneal@425 278 msg.receiver_delete_date = None
bgneal@425 279 msg.save()
bgneal@425 280
bgneal@425 281
bgneal@425 282 def bulk(request):
bgneal@425 283 """
bgneal@425 284 This view processes messages in bulk. Arrays of message ids are expected in
bgneal@425 285 the POST query dict: inbox_ids and outbox_ids will be deleted; trash_ids will
bgneal@425 286 be undeleted.
bgneal@425 287
bgneal@425 288 """
bgneal@425 289 if not request.user.is_authenticated():
bgneal@425 290 return HttpResponseForbidden()
bgneal@425 291 if request.method != 'POST':
bgneal@425 292 return HttpResponseNotAllowed(['POST'])
bgneal@425 293
bgneal@425 294 delete_ids = []
bgneal@425 295 if 'inbox_ids' in request.POST:
bgneal@425 296 delete_ids.extend(request.POST.getlist('inbox_ids'))
bgneal@425 297 if 'outbox_ids' in request.POST:
bgneal@425 298 delete_ids.extend(request.POST.getlist('outbox_ids'))
bgneal@425 299
bgneal@425 300 if len(delete_ids):
bgneal@425 301 _delete_msgs(request.user, delete_ids)
bgneal@425 302
bgneal@425 303 if 'trash_ids' in request.POST:
bgneal@425 304 _undelete_msgs(request.user, request.POST.getlist('trash_ids'))
bgneal@425 305
bgneal@425 306 return HttpResponse('');