Mercurial > public > sg101
comparison 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 |
comparison
equal
deleted
inserted
replaced
580:c525f3e0b5d0 | 581:ee87ea74d46b |
---|---|
1 """ | |
2 Views for the messages application. | |
3 | |
4 """ | |
5 import datetime | |
6 | |
7 from django.contrib.auth.decorators import login_required | |
8 from django.contrib.auth.models import User | |
9 from django.contrib import messages as django_messages | |
10 from django.core.paginator import Paginator, EmptyPage, InvalidPage | |
11 from django.core.urlresolvers import reverse | |
12 from django.http import HttpResponse | |
13 from django.http import HttpResponseForbidden | |
14 from django.http import HttpResponseNotAllowed | |
15 from django.shortcuts import get_object_or_404 | |
16 from django.shortcuts import render | |
17 import django.utils.simplejson as json | |
18 | |
19 from messages.models import Message, Options | |
20 from messages.forms import OptionsForm, ComposeForm | |
21 from messages.utils import reply_subject | |
22 from messages import MSG_BOX_LIMIT | |
23 from core.functions import quote_message | |
24 | |
25 | |
26 MSGS_PER_PAGE = 20 # message pagination value | |
27 | |
28 # This must match the jQuery UI tab control | |
29 TAB_INDICES = { | |
30 'inbox': 0, | |
31 'compose': 1, | |
32 'outbox': 2, | |
33 'trash': 3, | |
34 'options': 4, | |
35 } | |
36 | |
37 | |
38 def _get_page(request): | |
39 try: | |
40 n = int(request.GET.get('page', '1')) | |
41 except ValueError: | |
42 n = 1 | |
43 return n | |
44 | |
45 | |
46 def _quota_check(box_name, count, request): | |
47 """ | |
48 Checks the message box count against MSG_BOX_LIMIT. | |
49 Emits a message to the user if the quota is exceeded. | |
50 | |
51 Returns the percent used as an integer between 0-100. | |
52 | |
53 """ | |
54 if count >= MSG_BOX_LIMIT: | |
55 django_messages.warning(request, | |
56 "Your %s is full. Please delete some messages." % box_name) | |
57 | |
58 return 100 * count / MSG_BOX_LIMIT | |
59 | |
60 | |
61 @login_required | |
62 def index(request, tab=None): | |
63 """ | |
64 This function displays the base tabbed private messages view. | |
65 | |
66 """ | |
67 tab_index = TAB_INDICES[tab] if tab else 0 | |
68 return render(request, 'messages/tabbed_base.html', { | |
69 'tab': tab_index, | |
70 'unread_count': Message.objects.unread_count(request.user), | |
71 }) | |
72 | |
73 | |
74 @login_required | |
75 def compose_to(request, receiver): | |
76 """ | |
77 This function displays the base tabbed private messages view, | |
78 and configures it to display the compose PM tab for the given | |
79 receiver. | |
80 | |
81 """ | |
82 user = get_object_or_404(User, username=receiver) | |
83 tab_index = TAB_INDICES['compose'] | |
84 return render(request, 'messages/tabbed_base.html', { | |
85 'tab': tab_index, | |
86 'receiver': receiver, | |
87 'unread_count': Message.objects.unread_count(request.user), | |
88 }) | |
89 | |
90 | |
91 def inbox(request): | |
92 """ | |
93 Returns the inbox for the user. | |
94 | |
95 """ | |
96 if not request.user.is_authenticated(): | |
97 return HttpResponseForbidden() | |
98 | |
99 msg_list = Message.objects.inbox(request.user) | |
100 msg_count = msg_list.count() | |
101 pct_used = _quota_check('inbox', msg_count, request) | |
102 | |
103 paginator = Paginator(msg_list, MSGS_PER_PAGE) | |
104 try: | |
105 msgs = paginator.page(_get_page(request)) | |
106 except (EmptyPage, InvalidPage): | |
107 msgs = paginator.page(paginator.num_pages) | |
108 | |
109 return render(request, 'messages/inbox_tab.html', { | |
110 'msgs': msgs, | |
111 'url': reverse('messages-inbox'), | |
112 'pct_used': pct_used, | |
113 }) | |
114 | |
115 | |
116 def outbox(request): | |
117 """ | |
118 Returns the outbox for the user. | |
119 | |
120 """ | |
121 if not request.user.is_authenticated(): | |
122 return HttpResponseForbidden() | |
123 | |
124 msg_list = Message.objects.outbox(request.user) | |
125 msg_count = msg_list.count() | |
126 pct_used = _quota_check('outbox', msg_count, request) | |
127 | |
128 paginator = Paginator(msg_list, MSGS_PER_PAGE) | |
129 try: | |
130 msgs = paginator.page(_get_page(request)) | |
131 except (EmptyPage, InvalidPage): | |
132 msgs = paginator.page(paginator.num_pages) | |
133 | |
134 return render(request, 'messages/outbox_tab.html', { | |
135 'msgs': msgs, | |
136 'url': reverse('messages-outbox'), | |
137 'pct_used': pct_used, | |
138 }) | |
139 | |
140 | |
141 def trash(request): | |
142 """ | |
143 Returns the trash for the user. | |
144 | |
145 """ | |
146 if not request.user.is_authenticated(): | |
147 return HttpResponseForbidden() | |
148 | |
149 msg_list = Message.objects.trash(request.user) | |
150 paginator = Paginator(msg_list, MSGS_PER_PAGE) | |
151 try: | |
152 msgs = paginator.page(_get_page(request)) | |
153 except (EmptyPage, InvalidPage): | |
154 msgs = paginator.page(paginator.num_pages) | |
155 | |
156 return render(request, 'messages/trash_tab.html', { | |
157 'msgs': msgs, | |
158 'url': reverse('messages-trash'), | |
159 }) | |
160 | |
161 | |
162 def message(request): | |
163 """ | |
164 This view function retrieves a message and returns it as a JSON object. | |
165 | |
166 """ | |
167 if not request.user.is_authenticated(): | |
168 return HttpResponseForbidden() | |
169 if request.method != 'POST': | |
170 return HttpResponseNotAllowed(['POST']) | |
171 | |
172 msg_id = request.POST.get('msg_id') | |
173 msg = get_object_or_404(Message.objects.select_related(), pk=msg_id) | |
174 if msg.sender != request.user and msg.receiver != request.user: | |
175 return HttpResponseForbidden() | |
176 | |
177 if msg.receiver == request.user and msg.read_date is None: | |
178 msg.read_date = datetime.datetime.now() | |
179 msg.save() | |
180 | |
181 msg_dict = dict(subject=msg.subject, | |
182 sender=msg.sender.username, | |
183 receiver=msg.receiver.username, | |
184 content=msg.html, | |
185 re_subject=reply_subject(msg.subject), | |
186 re_content=quote_message(msg.sender.username, msg.message)) | |
187 | |
188 result = json.dumps(msg_dict, ensure_ascii=False) | |
189 return HttpResponse(result, content_type='application/json') | |
190 | |
191 | |
192 def options(request): | |
193 """ | |
194 This view handles the displaying and changing of private message options. | |
195 | |
196 """ | |
197 if not request.user.is_authenticated(): | |
198 return HttpResponseForbidden() | |
199 | |
200 if request.method == "POST": | |
201 options = Options.objects.for_user(request.user) | |
202 form = OptionsForm(request.POST, instance=options, prefix='opts') | |
203 if form.is_valid(): | |
204 form.save() | |
205 django_messages.success(request, 'Options saved.') | |
206 else: | |
207 options = Options.objects.for_user(request.user) | |
208 form = OptionsForm(instance=options, prefix='opts') | |
209 | |
210 return render(request, 'messages/options_tab.html', { | |
211 'form': form, | |
212 }) | |
213 | |
214 | |
215 def compose(request, receiver=None): | |
216 """ | |
217 Process or prepare the compose form to create a new private message. | |
218 | |
219 """ | |
220 if not request.user.is_authenticated(): | |
221 return HttpResponseForbidden() | |
222 | |
223 if request.method == "POST": | |
224 compose_form = ComposeForm(request.user, request.POST) | |
225 | |
226 # Is this a reply to another message? | |
227 parent_msg_id = request.POST.get('reply_to') | |
228 if parent_msg_id: | |
229 parent_msg = get_object_or_404(Message, id=parent_msg_id) | |
230 if (request.user != parent_msg.receiver and | |
231 request.user != parent_msg.sender): | |
232 return HttpResponseForbidden() | |
233 else: | |
234 parent_msg = None | |
235 | |
236 if compose_form.is_valid(): | |
237 compose_form.save(parent_msg=parent_msg) | |
238 django_messages.success(request, 'Message sent.') | |
239 compose_form = ComposeForm(request.user) | |
240 else: | |
241 if receiver is not None: | |
242 form_data = {'receiver': receiver} | |
243 compose_form = ComposeForm(request.user, initial=form_data) | |
244 else: | |
245 compose_form = ComposeForm(request.user) | |
246 | |
247 _quota_check('outbox', Message.objects.outbox(request.user).count(), request) | |
248 | |
249 return render(request, 'messages/compose_tab.html', { | |
250 'compose_form': compose_form, | |
251 }) | |
252 | |
253 | |
254 def _only_integers(slist): | |
255 """ | |
256 Accepts a list of strings. Returns a list of integers consisting of only | |
257 those elements from the original list that could be converted to integers | |
258 | |
259 """ | |
260 result = [] | |
261 for s in slist: | |
262 try: | |
263 n = int(s) | |
264 except ValueError: | |
265 pass | |
266 else: | |
267 result.append(n) | |
268 return result | |
269 | |
270 | |
271 def _delete_msgs(user, msg_ids): | |
272 """ | |
273 Deletes the messages given by the list of msg_ids. For this to succeed, the | |
274 user has to be either the sender or receiver on each message. | |
275 | |
276 """ | |
277 msg_ids = _only_integers(msg_ids) | |
278 msgs = Message.objects.filter(id__in=msg_ids) | |
279 | |
280 for msg in msgs: | |
281 if msg.sender == user: | |
282 if (msg.receiver_delete_date is not None or | |
283 msg.read_date is None): | |
284 # Both parties deleted the message or receiver hasn't read it | |
285 # yet, we can delete it now | |
286 msg.delete() | |
287 else: | |
288 # receiver still has it in inbox | |
289 msg.sender_delete_date = datetime.datetime.now() | |
290 msg.save() | |
291 | |
292 elif msg.receiver == user: | |
293 if msg.sender_delete_date is not None: | |
294 # both parties deleted the message, we can delete it now | |
295 msg.delete() | |
296 else: | |
297 # sender still has it in the outbox | |
298 msg.receiver_delete_date = datetime.datetime.now() | |
299 msg.save() | |
300 | |
301 | |
302 def _undelete_msgs(user, msg_ids): | |
303 """ | |
304 Attempts to "undelete" the messages given by the msg_ids list. | |
305 This will only succeed if the user is either the sender or receiver. | |
306 | |
307 """ | |
308 msg_ids = _only_integers(msg_ids) | |
309 msgs = Message.objects.filter(id__in=msg_ids) | |
310 for msg in msgs: | |
311 if msg.sender == user: | |
312 msg.sender_delete_date = None | |
313 msg.save() | |
314 elif msg.receiver == user: | |
315 msg.receiver_delete_date = None | |
316 msg.save() | |
317 | |
318 | |
319 def bulk(request): | |
320 """ | |
321 This view processes messages in bulk. Arrays of message ids are expected in | |
322 the POST query dict: inbox_ids and outbox_ids will be deleted; trash_ids will | |
323 be undeleted. | |
324 | |
325 """ | |
326 if not request.user.is_authenticated(): | |
327 return HttpResponseForbidden() | |
328 if request.method != 'POST': | |
329 return HttpResponseNotAllowed(['POST']) | |
330 | |
331 delete_ids = [] | |
332 if 'inbox_ids' in request.POST: | |
333 delete_ids.extend(request.POST.getlist('inbox_ids')) | |
334 if 'outbox_ids' in request.POST: | |
335 delete_ids.extend(request.POST.getlist('outbox_ids')) | |
336 | |
337 if len(delete_ids): | |
338 _delete_msgs(request.user, delete_ids) | |
339 | |
340 if 'trash_ids' in request.POST: | |
341 _undelete_msgs(request.user, request.POST.getlist('trash_ids')) | |
342 | |
343 return HttpResponse(''); |