views.py 24.5 KB
Newer Older
1
2
3
4
# standard library imports
from datetime import date
from cStringIO import StringIO
# core django imports
Daniel W Bond's avatar
Daniel W Bond committed
5
6
from django.views.generic import View, DetailView, ListView, CreateView,\
    UpdateView, DeleteView
7
from django.http import Http404, HttpResponseForbidden
8
from django.forms.widgets import HiddenInput
9
from django.core.urlresolvers import reverse
10
from django.core.files.uploadedfile import SimpleUploadedFile
11
12
13
from django.core.mail import EmailMultiAlternatives
from django.template.loader import get_template
from django.template import Context
14
from django.utils.safestring import mark_safe
15
# third party imports
16
import requests
17
from PIL import Image
18
from braces.views import LoginRequiredMixin, SuperuserRequiredMixin
19
from braces.views import FormValidMessageMixin
Daniel W Bond's avatar
Daniel W Bond committed
20
from ratelimit.decorators import ratelimit
21
22
# imports from your apps
from .models import Listing, Bid, Flag, Rating
23
24
from .forms import ListingForm, BidForm, FlagForm, ExchangeListingForm,\
    UnExchangeListingForm, RatingForm
25
from core.models import Student
26

Daniel W Bond's avatar
Daniel W Bond committed
27

28
29
# pulls worldcat metadata from ISBNs
def ISBNMetadata(standardISBN):
30
    # passing in numbers starting with 0 throws "SyntaxError: invalid token"
Daniel W Bond's avatar
Daniel W Bond committed
31
32
33
    url = "http://xisbn.worldcat.org/webservices/xid/isbn/" +\
          str(standardISBN) +\
          "?method=getMetadata&format=json&fl=title,year,author,ed"
Jean Michel Rouly's avatar
Jean Michel Rouly committed
34
35
36
37
38
39
40

    # In case the API fails to return, simply return None.
    try:
        metadata = requests.get(url, timeout=0.1)
    except ConnectionError:
        return None

41
42
43
44
45
46
47
48
    # format into a dictionary
    dejson = metadata.json()
    try:
        metadataDict = dejson.get('list')
        return metadataDict[0]
    except:
        return None

Daniel W Bond's avatar
Daniel W Bond committed
49

50
51
52
# flagging
# you can only flag a listing once...
def can_flag(flagger, listing):
Daniel W Bond's avatar
Daniel W Bond committed
53
54
    user_flag_num = Flag.objects.filter(flagger=flagger,
                                        listing=listing).count()
55
56
57
58
59
60
    # we're assuming that this isn't going to go over 1
    if user_flag_num:
        return False
    else:
        return True

Daniel W Bond's avatar
Daniel W Bond committed
61

62
63
64
65
66
67
68
# get the listing's slug to pass to the create flag page
def flag_slug(flagger, listing):
    if not can_flag(flagger, listing):
        return Flag.objects.get(flagger=flagger, listing=listing).slug
    else:
        return None

69

Daniel W Bond's avatar
Daniel W Bond committed
70
71
72
73
# rating
# (basically) duplicated code!!!
def can_rate(rater, listing):
    user_rate_num = Rating.objects.filter(rater=rater,
Daniel W Bond's avatar
Daniel W Bond committed
74
                                          listing=listing).count()
Daniel W Bond's avatar
Daniel W Bond committed
75
76
77
78
79
80
81
    # we're assuming that this isn't going to go over 1
    if user_rate_num:
        return False
    else:
        return True


Daniel W Bond's avatar
Daniel W Bond committed
82
83
84
class ListListings(LoginRequiredMixin, ListView):
    model = Listing
    context_object_name = 'listings'
85
    paginate_by = 16
Daniel W Bond's avatar
Daniel W Bond committed
86
    queryset = Listing.objects.exclude(cancelled=True).order_by('-created')
87
    template_name = 'list_listings.html'
88
    login_url = 'login'
89

Daniel W Bond's avatar
Daniel W Bond committed
90

91
class CreateListing(LoginRequiredMixin, FormValidMessageMixin, CreateView):
92
    model = Listing
Daniel W Bond's avatar
Daniel W Bond committed
93
94
    fields = ['isbn', 'title', 'author', 'edition', 'year', 'course_abbr',
              'condition', 'access_code', 'price', 'photo', 'description']
95
96
97
    template_name = 'create_listing.html'
    context_object_name = 'listing'
    # ISBN query!
98
    login_url = 'login'
99

100
    # eventually figure out how to use {% url 'create_listing' %}
101
102
    form_valid_message = mark_safe("""Your listing was successfully created!
                         <a href="/share/new/">Create another here!</a>""")
103

104
    def form_valid(self, form):
105
106
        me = Student.objects.get(user=self.request.user)

107
        form.instance.poster = me
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127

        image_name = form.instance.photo.name
        user_image = Image.open(form.instance.photo)
        image_format = user_image.format

        print user_image
        width, height = user_image.size
        print user_image.size
        print width, "width"
        print height, "height"
        maxsize = (2560, 1920)
        # five megapixels is 2560x1920
        if (width > 2560) or (height > 1920):
            user_image.thumbnail(maxsize)

            temp_image = StringIO()
            user_image.save(temp_image, image_format)
            temp_image.seek(0)

            new_uploaded_file = SimpleUploadedFile(image_name,
Daniel W Bond's avatar
Daniel W Bond committed
128
                                    temp_image.read(), content_type=image_format)
129
130
131

            form.instance.photo = new_uploaded_file

132
        return super(CreateListing, self).form_valid(form)
133

134
135
    def get_context_data(self, **kwargs):
        context = super(CreateListing, self).get_context_data(**kwargs)
136

137
138
        form = ListingForm()
        context['my_form'] = form
139
140
        return context

Daniel W Bond's avatar
Daniel W Bond committed
141
    @ratelimit(key='user', rate='5/m', method='POST', block=True)
142
    @ratelimit(key='user', rate='50/day', method='POST', block=True)
Daniel W Bond's avatar
Daniel W Bond committed
143
144
145
    def post(self, request, *args, **kwargs):
        return super(CreateListing, self).post(request, *args, **kwargs)

Daniel W Bond's avatar
Daniel W Bond committed
146

147
148
# These next two views are tied together...
class DetailListing(DetailView):
149
150
    model = Listing
    context_object_name = 'listing'
151
    template_name = 'detail_listing.html'
152

Daniel W Bond's avatar
Daniel W Bond committed
153
154
    def get_context_data(self, **kwargs):
        context = super(DetailListing, self).get_context_data(**kwargs)
155
        me = Student.objects.get(user=self.request.user)
156
157

        # make the form available to the template on get
158
        # set the bidder and the listing
159
        form = BidForm(initial={'listing': self.get_object()})
160
        form.fields['listing'].widget = HiddenInput()
161
162
        context['my_form'] = form

Daniel W Bond's avatar
Daniel W Bond committed
163
164
165
166
167
        try:
            context['rating'] = Rating.objects.get(listing=self.get_object())
        except:
            context['rating'] = False

Daniel W Bond's avatar
Daniel W Bond committed
168
        # bids, filter by listing name of the current listing, order by date created
169
        context['bids'] = Bid.objects.filter(listing=self.get_object()).order_by('-price')
170
171
172
173
        context['bid_count'] = Bid.objects.filter(listing=self.get_object).count()
        # flags
        context['flags'] = Flag.objects.filter(listing=self.get_object()).order_by('-created')
        context['flag_count'] = Flag.objects.filter(listing=self.get_object()).count()
174
175
        context['can_flag'] = can_flag(me, self.get_object())
        context['flag_slug'] = flag_slug(me, self.get_object())
Daniel W Bond's avatar
Daniel W Bond committed
176
177
        return context

178

179
180
181
182
183
184
185
class DeleteListing(LoginRequiredMixin, SuperuserRequiredMixin, DeleteView):
    model = Listing
    context_object_name = 'listing'
    template_name = 'delete_listing.html'
    login_url = 'login'

    def get_success_url(self):
186
        return reverse('flag_mod')
187
188


189
190
class CreateBid(CreateView):
    model = Bid
Daniel W Bond's avatar
Daniel W Bond committed
191
    fields = ['listing', 'price', 'text', ]
192
    context_object_name = 'bid'
193
    template_name = 'detail_listing.html'
194

195
196
197
198
199
200
    def form_valid(self, form):
        me = Student.objects.get(user=self.request.user)

        form.instance.bidder = me
        return super(CreateBid, self).form_valid(form)

201
    def get_success_url(self):
Daniel W Bond's avatar
Daniel W Bond committed
202
203
204
        return reverse('detail_listing',
                       kwargs={'slug': self.object.listing.slug})

205

206
207
# ...to make this single view
class ListingPage(LoginRequiredMixin, View):
208
    login_url = 'login'
209
210
211
212
213
214
215
216

    # see this page for an explanation
    # https://docs.djangoproject.com/en/1.7/topics/class-based-views/mixins/#an-alternative-better-solution

    def get(self, request, *args, **kwargs):
        view = DetailListing.as_view()
        return view(request, *args, **kwargs)

Daniel W Bond's avatar
Daniel W Bond committed
217
218
    @ratelimit(key='user', rate='5/m', method='POST', block=True)
    # rate limit is higher for bids
219
    @ratelimit(key='user', rate='100/d', method='POST', block=True)
220
221
222
223
    def post(self, request, *args, **kwargs):
        view = CreateBid.as_view()
        return view(request, *args, **kwargs)

224

Daniel W Bond's avatar
Daniel W Bond committed
225
# and we return to our regularly schedule programming
226
227
class CreateFlag(LoginRequiredMixin, CreateView):
    model = Flag
Daniel W Bond's avatar
Daniel W Bond committed
228
    fields = ['reason', ]
229
    template_name = 'create_flag.html'
230
    context_object_name = 'flag'
231
    login_url = 'login'
232

233
    def get(self, request, *args, **kwargs):
234
235
        me = Student.objects.get(user=self.request.user)

236
        # duplicated code!!!
237
238
239
240
241
        current_url = self.request.get_full_path()
        listing_slug = current_url.split('/')[3]
        # [u'', u'share', u'listing', u'C1s3oD', u'flag']
        selected_listing = Listing.objects.get(slug=listing_slug)

242
        posting_student = selected_listing.poster
243

244
245
246
247
248
249
250
251
252
253
        # can only create a flag if you haven't previously created one
        if not can_flag(me, selected_listing):
            # because the page shouldn't exist in this scenario
            raise Http404

        # you can't flag your own listing
        if (posting_student == me):
            return HttpResponseForbidden()
        else:
            return super(CreateFlag, self).get(request, *args, **kwargs)
254
255
256
257
258

    def get_context_data(self, **kwargs):
        context = super(CreateFlag, self).get_context_data(**kwargs)
        me = Student.objects.get(user=self.request.user)

259
        # duplicated code!!!
260
261
262
263
264
265
        current_url = self.request.get_full_path()
        listing_slug = current_url.split('/')[3]
        # [u'', u'share', u'listing', u'C1s3oD', u'flag']
        selected_listing = Listing.objects.get(slug=listing_slug)

        context['listing'] = selected_listing
266
267
268

        form = FlagForm()
        context['my_form'] = form
269
270
        return context

271
272
273
274
275
276
277
278
279
280
281
282
    def form_valid(self, form):
        me = Student.objects.get(user=self.request.user)

        current_url = self.request.get_full_path()
        listing_slug = current_url.split('/')[3]
        # [u'', u'share', u'listing', u'C1s3oD', u'flag']
        selected_listing = Listing.objects.get(slug=listing_slug)

        form.instance.flagger = me
        form.instance.listing = selected_listing
        return super(CreateFlag, self).form_valid(form)

Daniel W Bond's avatar
Daniel W Bond committed
283
    @ratelimit(key='user', rate='5/m', method='POST', block=True)
284
    @ratelimit(key='user', rate='100/d', method='POST', block=True)
Daniel W Bond's avatar
Daniel W Bond committed
285
286
287
    def post(self, request, *args, **kwargs):
        return super(CreateFlag, self).post(request, *args, **kwargs)

288
289
290
291
    def get_success_url(self):
        return reverse('detail_listing',
                       kwargs={'slug': self.object.listing.slug})

Daniel W Bond's avatar
Daniel W Bond committed
292

293
294
class DeleteFlag(LoginRequiredMixin, DeleteView):
    model = Flag
295
    context_object_name = 'flag'
296
    template_name = 'delete_flag.html'
297
    login_url = 'login'
298

299
    def get(self, request, *args, **kwargs):
300
        me = Student.objects.get(user=self.request.user)
301
        flag_student = self.get_object().flagger
302

303
        # if you didn't create the flag, you can't delete the flag
304
        if not(flag_student == me):
305
            return HttpResponseForbidden()
306
307
        else:
            return super(DeleteFlag, self).get(request, *args, **kwargs)
308

309
310
311
    def get_success_url(self):
        return reverse('detail_listing',
                       kwargs={'slug': self.object.listing.slug})
312

Daniel W Bond's avatar
Daniel W Bond committed
313

314
# not implemented -- tbd
315
316
317
318
319
320
class DeleteBid(LoginRequiredMixin, DeleteView):
    model = Bid
    success_url = '/'

    # can be deleted by either creator or person for lister

Daniel W Bond's avatar
Daniel W Bond committed
321

Daniel W Bond's avatar
Daniel W Bond committed
322
class EditBid(LoginRequiredMixin, FormValidMessageMixin, UpdateView):
323
    model = Bid
Daniel W Bond's avatar
Daniel W Bond committed
324
325
    template_name = 'bid_edit.html'
    context_object_name = 'bid'
Daniel W Bond's avatar
Daniel W Bond committed
326
    # form_class = EditBidForm
Daniel W Bond's avatar
Daniel W Bond committed
327
328
    fields = ['price', 'text', ]

329
    login_url = 'login'
Daniel W Bond's avatar
Daniel W Bond committed
330

331
    form_valid_message = "Your bid was successfully updated!"
Daniel W Bond's avatar
Daniel W Bond committed
332

333
    def get(self, request, *args, **kwargs):
Daniel W Bond's avatar
Daniel W Bond committed
334
335
336
        me = Student.objects.get(user=self.request.user)
        bidding_student = self.get_object().bidder

337
338
        # if exchanged or cancelled, this page doesn't exist
        if self.get_object().listing.exchanged or self.get_object().listing.cancelled:
Daniel W Bond's avatar
Daniel W Bond committed
339
340
            raise Http404

341
342
343
344
345
346
347
348
        if not(bidding_student == me):
            return HttpResponseForbidden()
        else:
            return super(EditBid, self).get(request, *args, **kwargs)

    def get_success_url(self):
        return reverse('detail_listing',
                       kwargs={'slug': self.object.listing.slug})
349

Daniel W Bond's avatar
Daniel W Bond committed
350

351
class EditListing(LoginRequiredMixin, FormValidMessageMixin, UpdateView):
Daniel W Bond's avatar
Daniel W Bond committed
352
    model = Listing
353
354
    template_name = 'listing_edit.html'
    context_object_name = 'listing'
Daniel W Bond's avatar
Daniel W Bond committed
355
    # form_class = EditListingForm
356
357
358
    fields = ['title', 'author', 'isbn', 'year', 'edition', 'condition',
              'access_code', 'description', 'price', 'photo', ]

359
    login_url = 'login'
Daniel W Bond's avatar
Daniel W Bond committed
360

361
    form_valid_message = "Your listing was successfully updated!"
362

363
364
365
366
367
368
369
370
371
372
373
    def get(self, request, *args, **kwargs):
        me = Student.objects.get(user=self.request.user)
        posting_student = self.get_object().poster

        if (self.get_object().cancelled is True):
            raise Http404

        if not(posting_student == me):
            return HttpResponseForbidden()
        else:
            return super(EditListing, self).get(request, *args, **kwargs)
374
375
376
377

    def get_context_data(self, **kwargs):
        context = super(EditListing, self).get_context_data(**kwargs)

378
        me = Student.objects.get(user=self.request.user)
379
        posting_student = self.get_object().poster
380

381
        if not(posting_student == me):
382
            return HttpResponseForbidden()
383

Daniel W Bond's avatar
Daniel W Bond committed
384
385
        return context

386

387
class ExchangeListing(LoginRequiredMixin, FormValidMessageMixin, UpdateView):
388
    model = Listing
Daniel W Bond's avatar
Daniel W Bond committed
389
    fields = ['email_message', 'winning_bid', ]
390
    context_object_name = 'listing'
391
    template_name = 'listing_exchange.html'
392
    login_url = 'login'
393

394
    form_valid_message = "Your email was successfully sent!"
395

396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
    def get(self, request, *args, **kwargs):
        me = Student.objects.get(user=self.request.user)
        posting_student = self.get_object().poster

        bid_count = Bid.objects.filter(listing=self.get_object).count()
        if bid_count < 1:
            # because the page shouldn't exist in this scenario
            raise Http404

        if (self.get_object().cancelled is True):
            raise Http404

        if not(posting_student == me):
            return HttpResponseForbidden()
        else:
            return super(ExchangeListing, self).get(request, *args, **kwargs)

    def get_context_data(self, **kwargs):
        context = super(ExchangeListing, self).get_context_data(**kwargs)

        form = ExchangeListingForm()
        form.fields['winning_bid'].queryset = Bid.objects.filter(listing=self.get_object())

        context['my_form'] = form

        return context

423
    def form_valid(self, form):
424
        # filling out fields
425
        today = date.today()
426
        self.obj = self.get_object()
427

428
        form.instance.exchanged = True
429
        form.instance.date_closed = today
430
431

        # sending email
Daniel W Bond's avatar
Daniel W Bond committed
432
        # I'm still second guessing as to whether this should be in this method
433
434
        text_email = get_template('email/exchanged.txt')
        html_email = get_template('email/exchanged.html')
435

Daniel W Bond's avatar
Daniel W Bond committed
436
437
        email_context = Context({
            'bidder_first_name': form.instance.winning_bid.bidder.user.first_name,
438
            'poster_name': self.obj.poster.user.get_full_name(),
Daniel W Bond's avatar
Daniel W Bond committed
439
440
            'bid_num': form.instance.winning_bid.price,
            'listing_title': self.obj.title,
441
            'poster_email': self.obj.poster.user.email,
Daniel W Bond's avatar
Daniel W Bond committed
442
            'email_message': form.instance.email_message, })
443

Daniel W Bond's avatar
Daniel W Bond committed
444
        subject, from_email, to, cc = ('Your bid has been selected on Bookshare!',
Daniel W Bond's avatar
Daniel W Bond committed
445
                                       'no-reply@bookshare.srct.io',
Daniel W Bond's avatar
Daniel W Bond committed
446
                                       # form.instance.winning_bid.bidder.user.email,
447
                                       # self.obj.poster.user.email)
448
449
                                       'success@simulator.amazonses.com',
                                       'success@simulator.amazonses.com')
450
        text_content = text_email.render(email_context)
451
        html_content = html_email.render(email_context)
Daniel W Bond's avatar
Daniel W Bond committed
452
453
        msg = EmailMultiAlternatives(subject, text_content,
                                     from_email, [to], [cc])
454
        msg.attach_alternative(html_content, "text/html")
455
456
        msg.send()

457
458
459
        self.obj.poster.emails_sent += 2
        self.obj.poster.save()

460
        return super(ExchangeListing, self).form_valid(form)
461

Daniel W Bond's avatar
Daniel W Bond committed
462
    @ratelimit(key='user', rate='5/m', method='POST', block=True)
463
    @ratelimit(key='user', rate='50/d', method='POST', block=True)
Daniel W Bond's avatar
Daniel W Bond committed
464
    def post(self, request, *args, **kwargs):
465
        return super(ExchangeListing, self).post(request, *args, **kwargs)
Daniel W Bond's avatar
Daniel W Bond committed
466

467

468
class UnExchangeListing(LoginRequiredMixin, FormValidMessageMixin, UpdateView):
469
    model = Listing
470
    fields = ['email_message', ]
471
    context_object_name = 'listing'
472
    template_name = 'listing_unexchange.html'
473
    login_url = 'login'
Daniel W Bond's avatar
Daniel W Bond committed
474

475
    form_valid_message = """Your exchange has been successfully cancelled,
476
                     and your email successfully sent!"""
477

478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
    def get(self, request, *args, **kwargs):
        me = Student.objects.get(user=self.request.user)
        posting_student = self.get_object().poster

        if (self.get_object().cancelled is True):
            raise Http404

        if not(posting_student == me):
            return HttpResponseForbidden()
        else:
            return super(UnExchangeListing, self).get(request, *args, **kwargs)

    def get_context_data(self, **kwargs):
        context = super(UnExchangeListing, self).get_context_data(**kwargs)

        form = UnExchangeListingForm()
        context['my_form'] = form

        return context

498
    def form_valid(self, form):
499
        self.obj = self.get_object()
500
501
        text_email = get_template('email/unexchanged.txt')
        html_email = get_template('email/unexchanged.html')
502
503
504

        email_context = Context({
            'bidder_first_name': self.obj.winning_bid.bidder.user.first_name,
505
            'poster_name': self.obj.poster.user.get_full_name(),
506
507
            'bid_num': self.obj.winning_bid.price,
            'listing_title': self.obj.title,
508
509
            'poster_email': self.obj.poster.user.email,
            'poster_email': form.instance.email_message, })
510
511
512

        subject, from_email, to, cc = ('Your transaction has been cancelled on Bookshare',
                                       'no-reply@bookshare.srct.io',
Daniel W Bond's avatar
Daniel W Bond committed
513
                                       # self.obj.winning_bid.bidder.user.email,
514
                                       # self.obj.poster.user.email)
515
516
517
518
519
520
521
522
523
                                       'success@simulator.amazonses.com',
                                       'success@simulator.amazonses.com')
        text_content = text_email.render(email_context)
        html_content = html_email.render(email_context)
        msg = EmailMultiAlternatives(subject, text_content,
                                     from_email, [to], [cc])
        msg.attach_alternative(html_content, "text/html")
        msg.send()

524
525
526
        self.obj.poster.emails_sent += 2
        self.obj.poster.save()

527
        # this has to come after the email has been sent, otherwise these are
Daniel W Bond's avatar
Daniel W Bond committed
528
        # cleaned out
529
        form.instance.exchanged = False
530
531
        form.instance.date_closed = None
        form.instance.winning_bid = None
532

533
        return super(UnExchangeListing, self).form_valid(form)
534

Daniel W Bond's avatar
Daniel W Bond committed
535
    @ratelimit(key='user', rate='5/m', method='POST', block=True)
536
    @ratelimit(key='user', rate='50/d', method='POST', block=True)
Daniel W Bond's avatar
Daniel W Bond committed
537
    def post(self, request, *args, **kwargs):
538
        return super(UnExchangeListing, self).post(request, *args, **kwargs)
539

Daniel W Bond's avatar
Daniel W Bond committed
540

541
class CancelListing(LoginRequiredMixin, FormValidMessageMixin, UpdateView):
Daniel W Bond's avatar
Daniel W Bond committed
542
    model = Listing
543
    fields = []
544
    template_suffix_name = '_cancel'
545
546
    context_object_name = 'listing'
    template_name = 'listing_cancel.html'
547
    login_url = 'login'
Daniel W Bond's avatar
Daniel W Bond committed
548

549
550
    form_valid_message = "Your listing was successfully cancelled!"

551
    def get(self, request, *args, **kwargs):
552
        me = Student.objects.get(user=self.request.user)
553
        posting_student = self.get_object().poster
Daniel W Bond's avatar
Daniel W Bond committed
554

555
556
557
558
        # you can only cancel the listing if the listing isn't already cancelled
        if (self.get_object().cancelled is True):
            raise Http404

559
        if not(posting_student == me):
560
            return HttpResponseForbidden()
561
562
        else:
            return super(CancelListing, self).get(request, *args, **kwargs)
Daniel W Bond's avatar
Daniel W Bond committed
563

564
565
566
567
568
569
    def form_valid(self, form):
        today = date.today()

        form.instance.cancelled = True
        form.instance.date_closed = today
        return super(CancelListing, self).form_valid(form)
570

Daniel W Bond's avatar
Daniel W Bond committed
571

572
class ReopenListing(LoginRequiredMixin, FormValidMessageMixin, UpdateView):
573
    model = Listing
574
    fields = []
575
    template_suffix_name = '_reopen'
576
577
    context_object_name = 'listing'
    template_name = 'listing_reopen.html'
578
    login_url = 'login'
579

580
    form_valid_message = "Your listing was successfully reopened!"
581

582
    def get(self, request, *args, **kwargs):
583
        me = Student.objects.get(user=self.request.user)
584
        posting_student = self.get_object().poster
585

586
587
588
589
        # you can only reopen the listing if the listing is cancelled
        if (self.get_object().cancelled is False):
            raise Http404

590
        if not(posting_student == me):
591
            return HttpResponseForbidden()
592
593
        else:
            return super(ReopenListing, self).get(request, *args, **kwargs)
594

595
596
597
598
    def form_valid(self, form):
        form.instance.cancelled = False
        form.instance.date_closed = None
        return super(ReopenListing, self).form_valid(form)
Daniel W Bond's avatar
Daniel W Bond committed
599
600
601
602
603
604
605
606
607


class CreateRating(LoginRequiredMixin, CreateView):
    model = Rating
    fields = ['stars', 'review', ]
    template_name = 'create_rating.html'
    context_object_name = 'rating'
    login_url = 'login'

608
    def get(self, request, *args, **kwargs):
Daniel W Bond's avatar
Daniel W Bond committed
609
610
        me = Student.objects.get(user=self.request.user)

611
        # duplicated code!!!
Daniel W Bond's avatar
Daniel W Bond committed
612
613
614
615
616
        current_url = self.request.get_full_path()
        listing_slug = current_url.split('/')[3]
        # [u'', u'share', u'listing', u'C1s3oD', u'flag']
        selected_listing = Listing.objects.get(slug=listing_slug)

617
        winning_student = selected_listing.winning_bid.bidder
Daniel W Bond's avatar
Daniel W Bond committed
618

619
620
621
622
623
624
625
626
627
628
        # can only create a rating if you haven't previously created one
        if not can_rate(me, selected_listing):
            # because the page shouldn't exist in this scenario
            raise Http404

        # you can only rate a listing that you won
        if not (winning_student == me):
            return HttpResponseForbidden()
        else:
            return super(CreateRating, self).get(request, *args, **kwargs)
Daniel W Bond's avatar
Daniel W Bond committed
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647

    def get_context_data(self, **kwargs):
        context = super(CreateRating, self).get_context_data(**kwargs)
        me = Student.objects.get(user=self.request.user)

        # duplicated code!!!
        current_url = self.request.get_full_path()
        listing_slug = current_url.split('/')[3]
        # [u'', u'share', u'listing', u'C1s3oD', u'flag']
        selected_listing = Listing.objects.get(slug=listing_slug)

        winning_student = selected_listing.winning_bid.bidder

        context['listing'] = selected_listing

        form = RatingForm()
        context['my_form'] = form
        return context

648
649
650
651
652
653
654
655
656
657
658
659
    def form_valid(self, form):
        me = Student.objects.get(user=self.request.user)

        current_url = self.request.get_full_path()
        listing_slug = current_url.split('/')[3]
        # [u'', u'share', u'listing', u'C1s3oD', u'flag']
        selected_listing = Listing.objects.get(slug=listing_slug)

        form.instance.rater = me
        form.instance.listing = selected_listing
        return super(CreateRating, self).form_valid(form)

660
    # no per-day limit because you can only rate listings you've exchanged
Daniel W Bond's avatar
Daniel W Bond committed
661
662
663
664
    @ratelimit(key='user', rate='5/m', method='POST', block=True)
    def post(self, request, *args, **kwargs):
        return super(CreateRating, self).post(request, *args, **kwargs)

665
666
667
668
    def get_success_url(self):
        return reverse('ratings',
                       kwargs={'slug': self.object.listing.poster.slug})

Daniel W Bond's avatar
Daniel W Bond committed
669
670
671
672
673

class EditRating(LoginRequiredMixin, UpdateView):
    model = Rating
    template_name = 'rating_edit.html'
    context_object_name = 'rating'
Daniel W Bond's avatar
Daniel W Bond committed
674
    # form_class = EditListingForm
Daniel W Bond's avatar
Daniel W Bond committed
675
676
677
678
    login_url = 'login'

    fields = ['stars', 'review', ]

679
    def get(self, request, *args, **kwargs):
Daniel W Bond's avatar
Daniel W Bond committed
680
681
682
683
684
        me = Student.objects.get(user=self.request.user)
        rating_student = self.get_object().rater

        if not(rating_student == me):
            return HttpResponseForbidden()
685
686
        else:
            return super(EditRating, self).get(request, *args, **kwargs)
Daniel W Bond's avatar
Daniel W Bond committed
687

688
689
690
    def get_success_url(self):
        return reverse('ratings',
                       kwargs={'slug': self.object.listing.poster.slug})
Daniel W Bond's avatar
Daniel W Bond committed
691
692
693
694
695
696
697
698


class DeleteRating(LoginRequiredMixin, DeleteView):
    model = Rating
    context_object_name = 'rating'
    template_name = 'delete_rating.html'
    login_url = 'login'

699
    def get(self, request, *args, **kwargs):
Daniel W Bond's avatar
Daniel W Bond committed
700
701
702
703
704
        me = Student.objects.get(user=self.request.user)
        rating_student = self.get_object().rater

        if not(rating_student == me):
            return HttpResponseForbidden()
705
706
        else:
            return super(DeleteRating, self).get(request, *args, **kwargs)
Daniel W Bond's avatar
Daniel W Bond committed
707

708
709
710
    def get_success_url(self):
        return reverse('detail_listing',
                       kwargs={'slug': self.object.listing.slug})