Add grammar to tags. Also: respect custom tag slugs on publishing.
[wolnelektury.git] / src / club / views.py
1 # This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later.
2 # Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
3 #
4 from django.conf import settings
5 from django.contrib.auth.decorators import login_required, permission_required
6 from django.db.models import Sum
7 from django.http import HttpResponseRedirect
8 from django.shortcuts import get_object_or_404, render
9 from django.urls import reverse
10 from django.utils.decorators import method_decorator
11 from django.views.decorators.cache import never_cache
12 from django.views.generic import FormView, CreateView, TemplateView, DetailView, UpdateView
13 from django.views import View
14 from .payu import POSS
15 from .payu import views as payu_views
16 from .forms import ScheduleForm, PayUCardTokenForm
17 from . import forms
18 from . import models
19 from .helpers import get_active_schedule
20 from .payment_methods import recurring_payment_method
21
22
23 class ClubView(TemplateView):
24     template_name = 'club/index.html'
25
26     def get_context_data(self, *args, **kwargs):
27         ctx = super().get_context_data(*args, **kwargs)
28         ctx['active_menu_item'] = 'club'
29         return ctx
30
31
32
33 class DonationStep1(UpdateView):
34     queryset = models.Schedule.objects.filter(payed_at=None)
35     form_class = forms.DonationStep1Form
36     slug_field = slug_url_kwarg = 'key'
37     template_name = 'club/2022/donation_step1.html'
38     step = 1
39
40     def get_context_data(self, **kwargs):
41         c = super().get_context_data(**kwargs)
42         c['club'] = models.Club.objects.first()
43         return c
44
45     def get_success_url(self):
46         return reverse('donation_step2', args=[self.object.key])
47
48
49 class DonationStep2(UpdateView):
50     queryset = models.Schedule.objects.filter(payed_at=None)
51     form_class = forms.DonationStep2Form
52     slug_field = slug_url_kwarg = 'key'
53     template_name = 'club/2022/donation_step2.html'
54     step = 2
55
56
57 class JoinView(CreateView):
58     @property
59     def club(self):
60         return models.Club.objects.first()
61
62     @property
63     def new_layout(self):
64         return self.request.EXPERIMENTS['layout'].value
65     
66     def get_template_names(self):
67         if self.new_layout:
68             return 'club/2022/donation_step1.html'
69         return 'club/membership_form.html'
70
71     def get_form_class(self):
72         if self.new_layout:
73             return forms.DonationStep1Form
74         return ScheduleForm
75     
76     def is_app(self):
77         return self.request.GET.get('app')
78
79     def get(self, request):
80         if settings.CLUB_APP_HOST and self.is_app() and request.META['HTTP_HOST'] != settings.CLUB_APP_HOST:
81             return HttpResponseRedirect("https://" + settings.CLUB_APP_HOST + request.get_full_path())
82
83         if self.is_app():
84             request.session['from_app'] = True
85         elif request.session and 'from_app' in request.session:
86             del request.session['from_app']
87
88         return super().get(request)
89
90     def get_context_data(self, **kwargs):
91         c = super(JoinView, self).get_context_data(**kwargs)
92         c['membership'] = getattr(self.request.user, 'membership', None)
93         c['active_menu_item'] = 'club'
94         c['club'] = models.Club.objects.first()
95
96         c['ambassador'] = models.Ambassador.objects.all().order_by('?').first()
97         return c
98
99     def get_initial(self):
100         if self.request.user.is_authenticated and self.request.user.email:
101             return {
102                 'email': self.request.user.email
103             }
104
105     def get_form_kwargs(self):
106         kwargs = super().get_form_kwargs()
107         if not self.new_layout:
108             kwargs['referer'] = self.request.META.get('HTTP_REFERER', '')
109         return kwargs
110
111     def form_valid(self, form):
112         retval = super(JoinView, self).form_valid(form)
113         if self.request.user.is_authenticated:
114             form.instance.membership, created = models.Membership.objects.get_or_create(user=self.request.user)
115             form.instance.save()
116         return retval
117
118     def get_success_url(self):
119         if self.new_layout:
120             return reverse('donation_step2', args=[self.object.key])
121         return self.object.initiate_payment(self.request)
122
123
124 @method_decorator(never_cache, name='dispatch')
125 class ScheduleView(DetailView):
126     queryset = models.Schedule.objects.exclude(email='')
127     slug_field = slug_url_kwarg = 'key'
128     template_name = 'club/schedule.html'
129     step = 3
130     
131     def get_template_names(self):
132         if self.request.EXPERIMENTS['layout'].value:
133             if not self.object.payed_at:
134                 return 'club/2022/donation_step3.html'
135         return 'club/schedule.html'
136         
137     def get_context_data(self, *args, **kwargs):
138         ctx = super().get_context_data(*args, **kwargs)
139         ctx['active_menu_item'] = 'club'
140         return ctx
141
142     def post(self, request, key):
143         schedule = self.get_object()
144         return HttpResponseRedirect(schedule.initiate_payment(request))
145
146
147 @login_required
148 def claim(request, key):
149     schedule = models.Schedule.objects.get(key=key, membership=None)
150     schedule.membership, created = models.Membership.objects.get_or_create(user=request.user)
151     schedule.save()
152     return HttpResponseRedirect(schedule.get_absolute_url())
153
154
155 def cancel(request, key):
156     schedule = models.Schedule.objects.get(key=key)
157     schedule.is_cancelled = True
158     schedule.save()
159     return HttpResponseRedirect(schedule.get_absolute_url())
160
161
162 class DummyPaymentView(TemplateView):
163     template_name = 'club/dummy_payment.html'
164
165     def get_context_data(self, key):
166         return {
167             'schedule': models.Schedule.objects.get(key=key),
168         }
169
170     def post(self, request, key):
171         schedule = models.Schedule.objects.get(key=key)
172         schedule.create_payment()
173
174         return HttpResponseRedirect(schedule.get_absolute_url())
175
176
177 class PayUPayment(DetailView):
178     model = models.Schedule
179     slug_field = slug_url_kwarg = 'key'
180
181     def get(self, request, key):
182         schedule = self.get_object()
183         schedule.method = 'payu'
184         schedule.save(update_fields=['method'])
185         return HttpResponseRedirect(schedule.initiate_payment(request))
186
187
188
189 class PayURecPayment(payu_views.RecPayment):
190     form_class = PayUCardTokenForm
191
192     def get_schedule(self):
193         return get_object_or_404(models.Schedule, key=self.kwargs['key'])
194
195     def get_pos(self):
196         pos_id = recurring_payment_method.pos_id
197         return POSS[pos_id]
198
199     def get_success_url(self):
200         schedule = self.get_schedule()
201         schedule.method = 'payu-re'
202         schedule.save(update_fields=['method'])
203         return schedule.pay(self.request)
204
205
206 class PayUNotifyView(payu_views.NotifyView):
207     order_model = models.PayUOrder
208
209
210 class ScheduleThanksView(DetailView):
211     model = models.Schedule
212     slug_field = slug_url_kwarg = 'key'
213     step = 4
214
215     def get_template_names(self):
216         if self.request.EXPERIMENTS['layout'].value:
217             return 'club/2022/donation_step4.html'
218         return 'club/thanks.html'
219     
220     def get_context_data(self, *args, **kwargs):
221         ctx = super().get_context_data(*args, **kwargs)
222         ctx['active_menu_item'] = 'club'
223         return ctx
224
225
226 class YearSummaryView(DetailView):
227     model = models.Schedule
228     slug_field = slug_url_kwarg = 'key'
229     template_name = 'club/year_summary.html'
230
231     def get_context_data(self, *args, **kwargs):
232         ctx = super().get_context_data(*args, **kwargs)
233         ctx['payments'] = models.PayUOrder.objects.filter(
234             status='COMPLETED',
235             completed_at__year=self.kwargs['year'],
236             schedule__email=self.object.email,
237         ).order_by('completed_at')
238         ctx['total_amount'] = ctx['payments'].aggregate(s=Sum('schedule__amount'))['s']
239         return ctx
240
241
242 @permission_required('club.schedule_view')
243 def member_verify(request):
244     if request.method == 'POST':
245         emails = request.POST.get('emails').strip().split('\n')
246         rows = ['email;członek;nazwa użytkownika;aktywny;co najmniej do']
247         for email in emails:
248             email = email.strip()
249             row = [email]
250             schedules = models.Schedule.objects.filter(email=email).exclude(payed_at=None)
251             if schedules.exists():
252                 row.append('tak')
253                 akt = False
254                 unames = set()
255                 exp = None
256                 for s in schedules:
257                     if s.is_active():
258                         akt = True
259                     if s.membership:
260                         unames.add(s.membership.user.username) 
261                     if exp is None or s.expires_at > exp:
262                         exp = s.expires_at
263                 row.append(','.join(sorted(unames)))
264                 row.append('tak' if akt else 'nie')
265                 row.append(exp.date().isoformat())
266             else:
267                 row.append('nie')
268             rows.append(';'.join(row))
269         rows = '\n'.join(rows)
270     else:
271         rows = ''
272
273     return render(
274         request,
275         'club/member_verify.html',
276         {
277             'result': rows
278         }
279     )