Mercurial > public > sg101
diff messages/views.py @ 581:ee87ea74d46b
For Django 1.4, rearranged project structure for new manage.py.
author | Brian Neal <bgneal@gmail.com> |
---|---|
date | Sat, 05 May 2012 17:10:48 -0500 |
parents | gpp/messages/views.py@7cec8d6f9581 |
children | 89b240fe9297 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/messages/views.py Sat May 05 17:10:48 2012 -0500 @@ -0,0 +1,343 @@ +""" +Views for the messages application. + +""" +import datetime + +from django.contrib.auth.decorators import login_required +from django.contrib.auth.models import User +from django.contrib import messages as django_messages +from django.core.paginator import Paginator, EmptyPage, InvalidPage +from django.core.urlresolvers import reverse +from django.http import HttpResponse +from django.http import HttpResponseForbidden +from django.http import HttpResponseNotAllowed +from django.shortcuts import get_object_or_404 +from django.shortcuts import render +import django.utils.simplejson as json + +from messages.models import Message, Options +from messages.forms import OptionsForm, ComposeForm +from messages.utils import reply_subject +from messages import MSG_BOX_LIMIT +from core.functions import quote_message + + +MSGS_PER_PAGE = 20 # message pagination value + +# This must match the jQuery UI tab control +TAB_INDICES = { + 'inbox': 0, + 'compose': 1, + 'outbox': 2, + 'trash': 3, + 'options': 4, +} + + +def _get_page(request): + try: + n = int(request.GET.get('page', '1')) + except ValueError: + n = 1 + return n + + +def _quota_check(box_name, count, request): + """ + Checks the message box count against MSG_BOX_LIMIT. + Emits a message to the user if the quota is exceeded. + + Returns the percent used as an integer between 0-100. + + """ + if count >= MSG_BOX_LIMIT: + django_messages.warning(request, + "Your %s is full. Please delete some messages." % box_name) + + return 100 * count / MSG_BOX_LIMIT + + +@login_required +def index(request, tab=None): + """ + This function displays the base tabbed private messages view. + + """ + tab_index = TAB_INDICES[tab] if tab else 0 + return render(request, 'messages/tabbed_base.html', { + 'tab': tab_index, + 'unread_count': Message.objects.unread_count(request.user), + }) + + +@login_required +def compose_to(request, receiver): + """ + This function displays the base tabbed private messages view, + and configures it to display the compose PM tab for the given + receiver. + + """ + user = get_object_or_404(User, username=receiver) + tab_index = TAB_INDICES['compose'] + return render(request, 'messages/tabbed_base.html', { + 'tab': tab_index, + 'receiver': receiver, + 'unread_count': Message.objects.unread_count(request.user), + }) + + +def inbox(request): + """ + Returns the inbox for the user. + + """ + if not request.user.is_authenticated(): + return HttpResponseForbidden() + + msg_list = Message.objects.inbox(request.user) + msg_count = msg_list.count() + pct_used = _quota_check('inbox', msg_count, request) + + paginator = Paginator(msg_list, MSGS_PER_PAGE) + try: + msgs = paginator.page(_get_page(request)) + except (EmptyPage, InvalidPage): + msgs = paginator.page(paginator.num_pages) + + return render(request, 'messages/inbox_tab.html', { + 'msgs': msgs, + 'url': reverse('messages-inbox'), + 'pct_used': pct_used, + }) + + +def outbox(request): + """ + Returns the outbox for the user. + + """ + if not request.user.is_authenticated(): + return HttpResponseForbidden() + + msg_list = Message.objects.outbox(request.user) + msg_count = msg_list.count() + pct_used = _quota_check('outbox', msg_count, request) + + paginator = Paginator(msg_list, MSGS_PER_PAGE) + try: + msgs = paginator.page(_get_page(request)) + except (EmptyPage, InvalidPage): + msgs = paginator.page(paginator.num_pages) + + return render(request, 'messages/outbox_tab.html', { + 'msgs': msgs, + 'url': reverse('messages-outbox'), + 'pct_used': pct_used, + }) + + +def trash(request): + """ + Returns the trash for the user. + + """ + if not request.user.is_authenticated(): + return HttpResponseForbidden() + + msg_list = Message.objects.trash(request.user) + paginator = Paginator(msg_list, MSGS_PER_PAGE) + try: + msgs = paginator.page(_get_page(request)) + except (EmptyPage, InvalidPage): + msgs = paginator.page(paginator.num_pages) + + return render(request, 'messages/trash_tab.html', { + 'msgs': msgs, + 'url': reverse('messages-trash'), + }) + + +def message(request): + """ + This view function retrieves a message and returns it as a JSON object. + + """ + if not request.user.is_authenticated(): + return HttpResponseForbidden() + if request.method != 'POST': + return HttpResponseNotAllowed(['POST']) + + msg_id = request.POST.get('msg_id') + msg = get_object_or_404(Message.objects.select_related(), pk=msg_id) + if msg.sender != request.user and msg.receiver != request.user: + return HttpResponseForbidden() + + if msg.receiver == request.user and msg.read_date is None: + msg.read_date = datetime.datetime.now() + msg.save() + + msg_dict = dict(subject=msg.subject, + sender=msg.sender.username, + receiver=msg.receiver.username, + content=msg.html, + re_subject=reply_subject(msg.subject), + re_content=quote_message(msg.sender.username, msg.message)) + + result = json.dumps(msg_dict, ensure_ascii=False) + return HttpResponse(result, content_type='application/json') + + +def options(request): + """ + This view handles the displaying and changing of private message options. + + """ + if not request.user.is_authenticated(): + return HttpResponseForbidden() + + if request.method == "POST": + options = Options.objects.for_user(request.user) + form = OptionsForm(request.POST, instance=options, prefix='opts') + if form.is_valid(): + form.save() + django_messages.success(request, 'Options saved.') + else: + options = Options.objects.for_user(request.user) + form = OptionsForm(instance=options, prefix='opts') + + return render(request, 'messages/options_tab.html', { + 'form': form, + }) + + +def compose(request, receiver=None): + """ + Process or prepare the compose form to create a new private message. + + """ + if not request.user.is_authenticated(): + return HttpResponseForbidden() + + if request.method == "POST": + compose_form = ComposeForm(request.user, request.POST) + + # Is this a reply to another message? + parent_msg_id = request.POST.get('reply_to') + if parent_msg_id: + parent_msg = get_object_or_404(Message, id=parent_msg_id) + if (request.user != parent_msg.receiver and + request.user != parent_msg.sender): + return HttpResponseForbidden() + else: + parent_msg = None + + if compose_form.is_valid(): + compose_form.save(parent_msg=parent_msg) + django_messages.success(request, 'Message sent.') + compose_form = ComposeForm(request.user) + else: + if receiver is not None: + form_data = {'receiver': receiver} + compose_form = ComposeForm(request.user, initial=form_data) + else: + compose_form = ComposeForm(request.user) + + _quota_check('outbox', Message.objects.outbox(request.user).count(), request) + + return render(request, 'messages/compose_tab.html', { + 'compose_form': compose_form, + }) + + +def _only_integers(slist): + """ + Accepts a list of strings. Returns a list of integers consisting of only + those elements from the original list that could be converted to integers + + """ + result = [] + for s in slist: + try: + n = int(s) + except ValueError: + pass + else: + result.append(n) + return result + + +def _delete_msgs(user, msg_ids): + """ + Deletes the messages given by the list of msg_ids. For this to succeed, the + user has to be either the sender or receiver on each message. + + """ + msg_ids = _only_integers(msg_ids) + msgs = Message.objects.filter(id__in=msg_ids) + + for msg in msgs: + if msg.sender == user: + if (msg.receiver_delete_date is not None or + msg.read_date is None): + # Both parties deleted the message or receiver hasn't read it + # yet, we can delete it now + msg.delete() + else: + # receiver still has it in inbox + msg.sender_delete_date = datetime.datetime.now() + msg.save() + + elif msg.receiver == user: + if msg.sender_delete_date is not None: + # both parties deleted the message, we can delete it now + msg.delete() + else: + # sender still has it in the outbox + msg.receiver_delete_date = datetime.datetime.now() + msg.save() + + +def _undelete_msgs(user, msg_ids): + """ + Attempts to "undelete" the messages given by the msg_ids list. + This will only succeed if the user is either the sender or receiver. + + """ + msg_ids = _only_integers(msg_ids) + msgs = Message.objects.filter(id__in=msg_ids) + for msg in msgs: + if msg.sender == user: + msg.sender_delete_date = None + msg.save() + elif msg.receiver == user: + msg.receiver_delete_date = None + msg.save() + + +def bulk(request): + """ + This view processes messages in bulk. Arrays of message ids are expected in + the POST query dict: inbox_ids and outbox_ids will be deleted; trash_ids will + be undeleted. + + """ + if not request.user.is_authenticated(): + return HttpResponseForbidden() + if request.method != 'POST': + return HttpResponseNotAllowed(['POST']) + + delete_ids = [] + if 'inbox_ids' in request.POST: + delete_ids.extend(request.POST.getlist('inbox_ids')) + if 'outbox_ids' in request.POST: + delete_ids.extend(request.POST.getlist('outbox_ids')) + + if len(delete_ids): + _delete_msgs(request.user, delete_ids) + + if 'trash_ids' in request.POST: + _undelete_msgs(request.user, request.POST.getlist('trash_ids')) + + return HttpResponse('');