annotate gpp/messages/views2.py @ 428:77b3b01843b5

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