]> git.0d.be Git - panikdb.git/blob - panikdb/aa/views.py
8c8237d9a363387a7f044007e27698f1bad55033
[panikdb.git] / panikdb / aa / views.py
1 import vobject
2 from django.conf import settings
3 from django.contrib.admin.views.decorators import staff_member_required
4 from django.contrib.auth.decorators import login_required
5 from django.contrib.auth.models import Group, Permission
6 from django.core.exceptions import PermissionDenied
7 from django.db.models import Q, Sum
8 from django.http import HttpResponse, HttpResponseRedirect
9 from django.urls import reverse_lazy
10 from django.utils.timezone import now
11 from django.utils.translation import ugettext_lazy as _
12 from django.views.decorators.http import require_POST
13 from django.views.generic.base import RedirectView, TemplateView, View
14 from django.views.generic.detail import DetailView
15 from django.views.generic.edit import CreateView, DeleteView, FormView, UpdateView
16 from django.views.generic.list import ListView
17
18 from .forms import MemberCreateForm, MemberEditForm, MemberEmissionForm, MembershipForm
19 from .models import Membership, User
20
21 RELEVANT_PERMISSIONS = [
22     ('nonstop.add_track', _('Add tracks to nonstop')),
23     ('emissions.change_nonstop', _('Adjust nonstop schedule')),
24     ('emissions.change_schedule', _('Adjust emissions schedules')),
25     ('emissions.add_diffusion', _('Add a diffusion out of regular schedules')),
26     ('emissions.add_emission', _('Add a new emission')),
27     ('emissions.delete_emission', _('Delete an emission (careful!)')),
28     ('nonstop.add_scheduleddiffusion', _('Define a stream in an episode')),
29     ('nonstop.change_stream', _('Manage available streams')),
30     ('service_messages.change_message', _('Manage service messages')),
31     ('agendas.add_booking', _('Manage agendas')),
32     ('aa.add_user', _('Manage users and goups')),
33 ]
34
35
36 class ProfileView(TemplateView):
37     template_name = 'aa/profile.html'
38
39
40 profile_view = login_required(ProfileView.as_view())
41
42
43 class ProfileContactEditView(UpdateView):
44     model = User
45     fields = ['phone', 'mobile', 'share_contact_details']
46     success_url = reverse_lazy('profile-view')
47     template_name = 'aa/profile_form.html'
48
49     def get_object(self):
50         return self.request.user
51
52
53 profile_contact_edit = login_required(ProfileContactEditView.as_view())
54
55
56 class MembersListView(ListView):
57     paginate_by = 10
58
59     def get_queryset(self):
60         qs = User.objects.all().prefetch_related('emissions').prefetch_related('groups')
61         if not (self.request.user.is_staff and self.request.GET.get('q')):
62             # filter on active users unless a search term is given
63             qs = qs.filter(is_active=True)
64         if self.request.GET.get('q'):
65             for part in self.request.GET.get('q').split():
66                 part = part.strip()
67                 if not part:
68                     continue
69                 if part.lower() in ('ca', 'cp'):
70                     qs = qs.filter(groups__name=part.upper())
71                     continue
72                 qs = qs.filter(
73                     Q(first_name__icontains=part)
74                     | Q(last_name__icontains=part)
75                     | Q(emissions__title__icontains=part)
76                     | Q(emissions__slug__icontains=part)
77                 )
78         current_year = now().year
79         if self.request.GET.get('membership') == 'ok':
80             qs = qs.filter(membership__year=current_year)
81         if self.request.GET.get('membership') == 'renew':
82             qs = qs.filter(membership__year=current_year - 1).exclude(membership__year=current_year)
83         qs = qs.distinct()
84         return qs
85
86     def get_context_data(self, **kwargs):
87         context = super().get_context_data(**kwargs)
88         if self.request.GET.get('membership') == 'ok':
89             context['total_membership'] = True
90             context['total_money'] = (
91                 self.get_queryset()
92                 .aggregate(Sum('membership__payment_amount'))
93                 .get('membership__payment_amount__sum')
94             )
95         return context
96
97
98 members_list_view = login_required(MembersListView.as_view())
99
100
101 class MembersVCardView(MembersListView):
102     def get_queryset(self):
103         qs = super().get_queryset()
104         if not self.request.user.is_staff:
105             qs = qs.filter(share_contact_details=True)
106         qs = qs.exclude(email='')
107         return qs
108
109     def render_to_response(self, context, **response_kwargs):
110         members = []
111         for member in self.get_queryset():
112             card = vobject.vCard()
113             card.add('n')
114             card.n.value = vobject.vcard.Name(family=member.last_name, given=member.first_name)
115             card.add('fn')
116             card.fn.value = str(member)
117             card.add('email')
118             card.email.value = member.email
119             card.email.type_param = 'INTERNET'
120             card.add('note')
121             note_parts = []
122             if member.is_ca():
123                 note_parts.append('CA')
124             if member.is_cp():
125                 note_parts.append('CP')
126             note_parts.extend([str(x) for x in member.active_emissions()])
127             card.note.value = ', '.join(note_parts)
128             if member.phone:
129                 card.add('tel')
130                 card.tel.value = member.phone
131                 card.tel.type_param = 'HOME'
132             if member.mobile:
133                 card.add('tel')
134                 card.tel.value = member.mobile
135                 card.tel.type_param = 'CELL'
136             members.append(card.serialize())
137         content = ''.join(members)
138         return HttpResponse(content, content_type='text/vcard')
139
140
141 members_vcard = login_required(MembersVCardView.as_view())
142
143
144 class MemberView(DetailView):
145     model = User
146
147     def get_queryset(self):
148         return User.objects.all().prefetch_related('emissions').prefetch_related('groups')
149
150     def get_context_data(self, **kwargs):
151         context = super().get_context_data(**kwargs)
152         current_year = now().year
153         user = self.get_object()
154         memberships = user.membership_set.all().order_by('-year')
155         try:
156             context['current_membership'] = [x for x in memberships if x.year == current_year][0]
157         except IndexError:
158             pass
159         context['past_memberships'] = [x for x in memberships if x.year != current_year]
160         return context
161
162
163 member_view = login_required(MemberView.as_view())
164
165
166 class MemberEditView(UpdateView):
167     model = User
168     form_class = MemberEditForm
169
170     def get_object(self):
171         if not self.request.user.has_perm('aa.add_user'):
172             raise PermissionDenied()
173         return super().get_object()
174
175     def form_valid(self, form):
176         response = super().form_valid(form)
177         if Group.objects.filter(name__iexact='admin').exists():
178             self.object.is_superuser = bool(self.object.groups.filter(name__iexact='admin').exists())
179             self.object.save()
180         return response
181
182     def get_success_url(self):
183         return reverse_lazy('member-view', kwargs={'pk': self.get_object().id})
184
185
186 member_edit = login_required(MemberEditView.as_view())
187
188
189 class MemberCreateView(CreateView):
190     model = User
191     form_class = MemberCreateForm
192
193     def get_object(self):
194         if not self.request.user.has_perm('aa.add_user'):
195             raise PermissionDenied()
196         return super().get_object()
197
198     def form_valid(self, form):
199         form.instance.username = form.instance.email
200         response = super().form_valid(form)
201         self.object.set_password(form.cleaned_data['password'])
202         self.object.save()
203         return response
204
205     def get_success_url(self):
206         return reverse_lazy('member-view', kwargs={'pk': self.object.id})
207
208
209 member_new = login_required(MemberCreateView.as_view())
210
211
212 class MemberEmissionsView(FormView):
213     form_class = MemberEmissionForm
214     template_name = 'aa/member_emissions.html'
215
216     def get_context_data(self, **kwargs):
217         context = super().get_context_data(**kwargs)
218         context['member'] = User.objects.get(id=self.kwargs['pk'])
219         return context
220
221     def form_valid(self, form):
222         response = super().form_valid(form)
223         member = User.objects.get(id=self.kwargs['pk'])
224         member.emissions.add(form.cleaned_data['emission'])
225         return response
226
227     def get_success_url(self):
228         return reverse_lazy('member-view', kwargs={'pk': self.kwargs['pk']})
229
230
231 member_emissions = login_required(MemberEmissionsView.as_view())
232
233
234 class MemberEmissionRemoveView(RedirectView):
235     def get_redirect_url(self, *args, **kwargs):
236         if not self.request.user.has_perm('aa.add_user'):
237             raise PermissionDenied()
238         member = User.objects.get(id=kwargs['pk'])
239         member.emissions.remove(kwargs['em_pk'])
240         return reverse_lazy('member-view', kwargs={'pk': member.id})
241
242
243 member_emission_remove = login_required(MemberEmissionRemoveView.as_view())
244
245
246 @staff_member_required
247 def mark_as_active(request, pk):
248     User.objects.filter(pk=pk).update(is_active=True)
249     return HttpResponseRedirect(reverse_lazy('member-view', kwargs={'pk': pk}))
250
251
252 @staff_member_required
253 def mark_as_inactive(request, pk):
254     User.objects.filter(pk=pk).update(is_active=False)
255     return HttpResponseRedirect(reverse_lazy('member-view', kwargs={'pk': pk}))
256
257
258 class RegisterMembershipView(FormView):
259     form_class = MembershipForm
260     template_name = 'aa/register_membership.html'
261
262     def get_context_data(self, **kwargs):
263         if not self.request.user.has_perm('aa.add_membership'):
264             raise PermissionDenied()
265         context = super().get_context_data(**kwargs)
266         context['member'] = User.objects.get(id=self.kwargs['pk'])
267         return context
268
269     def get_initial(self):
270         initial = super().get_initial()
271         initial['year'] = now().year
272         initial['payment_date'] = now().date()
273         initial['payment_amount'] = settings.MEMBERSHIP_DEFAULT_AMOUNT or ''
274         return initial
275
276     def form_valid(self, form):
277         member = User.objects.get(id=self.kwargs['pk'])
278         membership, created = Membership.objects.get_or_create(member=member, year=form.cleaned_data['year'])
279         membership.payment_date = form.cleaned_data['payment_date']
280         membership.payment_amount = form.cleaned_data['payment_amount']
281         membership.notes = form.cleaned_data['notes']
282         membership.save()
283         return super().form_valid(form)
284
285     def get_success_url(self):
286         return reverse_lazy('member-view', kwargs={'pk': self.kwargs['pk']})
287
288
289 register_membership = login_required(RegisterMembershipView.as_view())
290
291
292 class GroupsList(ListView):
293     paginate_by = 100
294     template_name = 'aa/groups_list.html'
295
296     def dispatch(self, request, *args, **kwargs):
297         if not self.request.user.has_perm('aa.add_user'):
298             raise PermissionDenied()
299         return super().dispatch(request, *args, **kwargs)
300
301     def get_queryset(self):
302         return Group.objects.order_by('name')
303
304
305 groups_list = login_required(GroupsList.as_view())
306
307
308 class GroupCreateView(CreateView):
309     model = Group
310     fields = ['name']
311     template_name = 'aa/group_new.html'
312     success_url = reverse_lazy('groups-list')
313
314     def get_object(self):
315         if not self.request.user.has_perm('aa.add_user'):
316             raise PermissionDenied()
317         return super().get_object()
318
319
320 group_new = login_required(GroupCreateView.as_view())
321
322
323 class GroupDetailView(DetailView):
324     model = Group
325     template_name = 'aa/group_detail.html'
326
327     def get_object(self):
328         if not self.request.user.has_perm('aa.add_user'):
329             raise PermissionDenied()
330         return super().get_object()
331
332     def get_context_data(self, **kwargs):
333         context = super().get_context_data(**kwargs)
334         group = self.get_object()
335         has_perms = [
336             f'{x.content_type.app_label}.{x.codename}' for x in group.permissions.all().select_related()
337         ]
338         context['perms'] = [
339             {'code': x[0], 'label': x[1], 'enabled': x[0] in has_perms} for x in RELEVANT_PERMISSIONS
340         ]
341         return context
342
343
344 group_view = login_required(GroupDetailView.as_view())
345
346
347 class GroupUpdatePerms(View):
348     def post(self, request, *args, **kwargs):
349         if not request.user.has_perm('aa.add_user'):
350             raise PermissionDenied()
351         group = Group.objects.get(**kwargs)
352         set_permissions = set()
353         unset_permissions = set()
354         for perm in RELEVANT_PERMISSIONS:
355             app_label, codename = perm[0].split('.')
356             perm_obj = Permission.objects.filter(content_type__app_label=app_label, codename=codename).first()
357             if not perm_obj:
358                 continue
359             if perm[0] in request.POST.getlist('perms'):
360                 group.permissions.add(perm_obj)
361             else:
362                 group.permissions.remove(perm_obj)
363         return HttpResponseRedirect(reverse_lazy('groups-list'))
364
365
366 group_update_perms = login_required(require_POST(GroupUpdatePerms.as_view()))
367
368
369 class GroupDeleteView(DeleteView):
370     model = Group
371     template_name = 'aa/group_confirm_delete.html'
372     success_url = reverse_lazy('groups-list')
373
374     def get_object(self):
375         if not self.request.user.has_perm('aa.add_user'):
376             raise PermissionDenied()
377         return super().get_object()
378
379
380 group_delete = login_required(GroupDeleteView.as_view())