-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathviews.py
285 lines (261 loc) · 10.1 KB
/
views.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
## Copyright (c) 2010 by Jose Antonio Martin <jantonio.martin AT gmail DOT com>
## This program is free software: you can redistribute it and/or modify it
## under the terms of the GNU Affero General Public License as published by the
## Free Software Foundation, either version 3 of the License, or (at your option
## any later version.
##
## This program is distributed in the hope that it will be useful, but WITHOUT
## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
## FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License
## for more details.
##
## You should have received a copy of the GNU Affero General Public License
## along with this program. If not, see <http://www.gnu.org/licenses/agpl.txt>.
##
## This license is also included in the file COPYING
##
## AUTHOR: Jose Antonio Martin <jantonio.martin AT gmail DOT com>
import datetime
from django.contrib.auth.decorators import login_required
from django.shortcuts import render_to_response, get_object_or_404, redirect
from django.http import Http404, HttpResponseRedirect
from django.utils.translation import ugettext_lazy as _
from django.utils.decorators import method_decorator
from django.urls import reverse
from django.conf import global_settings
from django.views.generic.list import ListView
from django_messages.utils import format_quote
from django_messages.models import Message
from django.contrib import messages
from machiavelli.models import Player, Game
from machiavelli.views import get_game_context
from condottieri_messages.exceptions import LetterError
import condottieri_messages.forms as forms
from condottieri_messages.models import Letter
class LoginRequiredMixin(object):
""" Mixin to check that the user has authenticated.
(Always the first mixin in class)
"""
@method_decorator(login_required)
def dispatch(self, *args, **kwargs):
return super(LoginRequiredMixin, self).dispatch(*args, **kwargs)
def check_errors(request, game, sender_player, recipient_player):
msg = None
if sender_player.eliminated or recipient_player.eliminated:
msg = _("Eliminated players cannot send or receive letters")
## if the game is inactive, return 404 error
elif game.phase == 0:
msg = _("You cannot send letters in an inactive game.")
## check if the sender has excommunicated the recipient
elif sender_player.may_excommunicate and recipient_player.is_excommunicated:
msg = _("You cannot write to a country that you have excommunicated.")
else:
return True
raise LetterError(msg)
@login_required
def compose(request, sender_id=None, recipient_id=None, letter_id=None):
if sender_id and recipient_id:
## check that the sender is legitimate
sender_player = get_object_or_404(Player, user=request.user, id=sender_id)
game = sender_player.game
recipient_player = get_object_or_404(Player, id=recipient_id, game=game)
parent = Letter.objects.none()
elif letter_id:
parent = get_object_or_404(Letter, id=letter_id)
if parent.sender != request.user and parent.recipient != request.user:
raise Http404
sender_player = parent.recipient_player
recipient_player = parent.sender_player
game = sender_player.game
else:
raise Http404
if not game.configuration.letters:
raise Http404
context = get_game_context(request, game, sender_player)
try:
check_errors(request, game, sender_player, recipient_player)
except LetterError as e:
messages.error(request, e.value)
return redirect(game)
## try to find a common language for the two players
common_language_code = None
sender_lang = sender_player.user.profile.spokenlanguage_set.values_list('code', flat=True)
recipient_lang = recipient_player.user.profile.spokenlanguage_set.values_list('code', flat=True)
for lang in sender_lang:
if lang in recipient_lang:
common_language_code = lang
break
if common_language_code is not None:
lang_dict = dict(global_settings.LANGUAGES)
if common_language_code in list(lang_dict.keys()):
common_language = lang_dict[common_language_code]
context.update({'common_language': common_language })
LetterForm = forms.letter_form_factory(sender_player, recipient_player)
if request.method == 'POST':
letter_form = LetterForm(sender_player, recipient_player, data=request.POST)
if letter_form.is_valid():
bcc_errors = False
bcc = letter_form.cleaned_data["bcc"]
excom = False
for r in bcc:
try:
check_errors(request, game, sender_player, r)
except LetterError as e:
bcc_errors = True
messages.error(request, e.value)
if not bcc_errors:
letter = letter_form.save()
for r in bcc:
letter_copy = Letter(sender_player=letter.sender_player,
recipient_player=r,
subject=letter.subject,
body=letter.body)
letter_copy.save()
if not sender_player.is_excommunicated and \
r.is_excommunicated:
excom = True
messages.success(request, _("The letter has been successfully sent."))
## check if sender must be excommunicated
if not sender_player.is_excommunicated and \
recipient_player.is_excommunicated:
excom = True
if excom:
sender_player.set_excommunication(by_pope=False)
messages.info(request, _("You have been excommunicated."))
return redirect(game)
else:
if parent:
initial = {'body': str(format_quote(recipient_player.contender, parent.body)),
'subject': _("Re: %(subject)s") % {'subject': parent.subject},
}
else:
initial = {}
letter_form = LetterForm(sender_player,
recipient_player,
initial=initial)
if not sender_player.is_excommunicated and recipient_player.is_excommunicated:
context['excom_notice'] = True
if sender_player.is_excommunicated and not recipient_player.is_excommunicated:
messages.error(request, _("You can write letters only to other excommunicated countries."))
return redirect(game)
context.update({'form': letter_form,
'sender_player': sender_player,
'recipient_player': recipient_player,
})
return render_to_response('condottieri_messages/compose.html',
context)
@login_required
def view(request, message_id):
"""
Modified version of condottieri-messages view.
Shows a single message.``message_id`` argument is required.
The user is only allowed to see the message, if he is either
the sender or the recipient. If the user is not allowed a 404
is raised.
If the user is the recipient and the message is unread
``read_at`` is set to the current datetime.
"""
user = request.user
now = datetime.datetime.now()
message = get_object_or_404(Letter, id=message_id)
if (message.sender != user) and (message.recipient != user):
raise Http404
game = message.sender_player.game
player = Player.objects.get(user=request.user, game=game)
context = get_game_context(request, game, player)
if message.read_at is None and message.recipient == user:
message.read_at = now
message.save()
context.update({'message' : message,})
return render_to_response('condottieri_messages/view.html',
context)
class BoxListView(LoginRequiredMixin, ListView):
allow_empty = True
model = Message
paginate_by = 25
context_object_name = 'message_list'
template_name = 'condottieri_messages/messages_box.html'
box = None
allowed_boxes = ['inbox', 'outbox', 'trash']
def get_queryset(self):
if not self.box in self.allowed_boxes:
return Message.objects.none()
if self.box == 'inbox':
message_list = Message.objects.inbox_for(self.request.user)
elif self.box == 'outbox':
message_list = Message.objects.outbox_for(self.request.user)
elif self.box == 'trash':
message_list = Message.objects.trash_for(self.request.user)
try:
slug = self.kwargs['slug']
except KeyError:
pass
else:
self.game = get_object_or_404(Game, slug=slug)
message_list = message_list.filter(letter__sender_player__game=self.game)
return message_list
def get_context_data(self, **kwargs):
context = super(BoxListView, self).get_context_data(**kwargs)
if hasattr(self, 'game'):
context['game'] = self.game
context['box'] = self.box
return context
##
## 'delete' and 'undelete' code is taken from django-messages and modified
## to disable notifications when a message is deleted or recovered
##
@login_required
def delete(request, message_id, success_url=None):
"""
Marks a message as deleted by sender or recipient. The message is not
really removed from the database, because two users must delete a message
before it's save to remove it completely.
A cron-job should prune the database and remove old messages which are
deleted by both users.
As a side effect, this makes it easy to implement a trash with undelete.
You can pass ?next=/foo/bar/ via the url to redirect the user to a different
page (e.g. `/foo/bar/`) than ``success_url`` after deletion of the message.
"""
user = request.user
now = datetime.datetime.now()
message = get_object_or_404(Message, id=message_id)
deleted = False
if success_url is None:
success_url = reverse('messages_inbox')
if 'next' in request.GET:
success_url = request.GET['next']
if message.sender == user:
message.sender_deleted_at = now
deleted = True
if message.recipient == user:
message.recipient_deleted_at = now
deleted = True
if deleted:
message.save()
messages.success(request, _("Message successfully deleted."))
return HttpResponseRedirect(success_url)
raise Http404
@login_required
def undelete(request, message_id, success_url=None):
"""
Recovers a message from trash. This is achieved by removing the
``(sender|recipient)_deleted_at`` from the model.
"""
user = request.user
message = get_object_or_404(Message, id=message_id)
undeleted = False
if success_url is None:
success_url = reverse('messages_inbox')
if 'next' in request.GET:
success_url = request.GET['next']
if message.sender == user:
message.sender_deleted_at = None
undeleted = True
if message.recipient == user:
message.recipient_deleted_at = None
undeleted = True
if undeleted:
message.save()
messages.success(request, _("Message successfully recovered."))
return HttpResponseRedirect(success_url)
raise Http404