views.py 7.32 KB
Newer Older
1
import csv
2
import json
Sébastiaan Versteeg's avatar
Sébastiaan Versteeg committed
3
import os
4
from datetime import date, datetime
5

6
from django.contrib.auth.decorators import login_required, permission_required
7
from django.core.paginator import EmptyPage, PageNotAnInteger, Paginator
8
from django.db.models import Q
9
from django.http import HttpResponse
10 11
from django.shortcuts import get_object_or_404, render
from django.utils.text import slugify
12
from django.utils.translation import gettext as _
13
from sendfile import sendfile
14

15
from members.models import Member
16
from members.services import member_achievements
Thom Wiggers's avatar
Thom Wiggers committed
17
from . import models
18
from .forms import MemberForm
19

20

21
def filter_users(tab, keywords, year_range):
22 23
    memberships_query = Q(until__gt=datetime.now()) | Q(until=None)
    members_query = ~Q(id=None)
24

25 26 27 28 29 30
    if tab and tab.isdigit():
        members_query &= Q(starting_year=int(tab))
    elif tab == 'old':
        members_query &= Q(starting_year__lt=year_range[-1])
    elif tab == 'ex':
        # Filter out all current active memberships
31
        memberships_query &= Q(type='member') | Q(type='honorary')
32 33
        memberships = models.Membership.objects.filter(memberships_query)
        members_query &= ~Q(user__in=memberships.values('user'))
34
        # Members_query contains users that are not currently (honorary)member
35
    elif tab == 'honor':
36 37 38
        memberships_query = Q(until__gt=datetime.now().date()) | Q(until=None)
        memberships_query &= Q(type='honorary')

39 40
    if keywords:
        for key in keywords:
41 42 43 44 45 46 47
            members_query &= (
                (Q(user__member__nickname__icontains=key) &
                 # Works because relevant options all have `nick` in their key
                 Q(user__member__display_name_preference__contains='nick')) |
                Q(user__first_name__icontains=key) |
                Q(user__last_name__icontains=key) |
                Q(user__username__icontains=key))
48

49
    if tab == 'ex':
50 51 52 53 54 55 56 57 58 59
        memberships_query = Q(type='member') | Q(type='honorary')
        memberships = models.Membership.objects.filter(memberships_query)
        all_memberships = models.Membership.objects.all()
        # Only keep members that were once members, or are legacy users that
        #  do not have any memberships at all
        members_query &= (Q(user__in=memberships.values('user')) |
                          ~Q(user__in=all_memberships.values('user')))
    else:
        memberships = models.Membership.objects.filter(memberships_query)
        members_query &= Q(user__in=memberships.values('user'))
60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
    return (models.Member.objects.filter(members_query)
                                 .order_by('-starting_year',
                                           'user__first_name'))


@login_required
def index(request):
    query_filter = '' if request.GET.get(
        'filter') is None else request.GET.get('filter')
    keywords = '' if request.GET.get('keywords') is None else request.GET.get(
        'keywords').split()

    page = request.GET.get('page')
    page = 1 if page is None or not page.isdigit() else int(page)

    start_year = date.today().year - 4
    # If language is English show one year less
    # since the width is smaller than needed for the translations to fit
    if request.LANGUAGE_CODE == 'en':
        start_year += 1
    year_range = list(reversed(range(start_year, date.today().year + 1)))

    members = filter_users(query_filter, keywords, year_range)
83 84 85

    paginator = Paginator(members, 24)

Sébastiaan Versteeg's avatar
Sébastiaan Versteeg committed
86 87 88 89 90 91 92 93 94
    try:
        members = paginator.page(page)
    except PageNotAnInteger:
        # If page is not an integer, deliver first page.
        members = paginator.page(1)
    except EmptyPage:
        # If page is out of range (e.g. 9999), deliver last page of results.
        members = paginator.page(paginator.num_pages)

95 96 97
    page_range = range(1, paginator.num_pages + 1)
    if paginator.num_pages > 7:
        if page > 3:
98 99 100 101
            page_range_end = paginator.num_pages
            if page + 3 <= paginator.num_pages:
                page_range_end = page + 3

Sébastiaan Versteeg's avatar
Sébastiaan Versteeg committed
102
            page_range = range(page - 2, page_range_end)
103 104 105 106
            while page_range.stop - page_range.start < 5:
                page_range = range(page_range.start - 1, page_range.stop)
        else:
            page_range = range(1, 6)
Sébastiaan Versteeg's avatar
Sébastiaan Versteeg committed
107

Sébastiaan Versteeg's avatar
Sébastiaan Versteeg committed
108 109 110
    return render(request, 'members/index.html',
                  {'members': members, 'filter': query_filter,
                   'year_range': year_range, 'page_range': page_range,
111
                   'keywords': keywords})
Sébastiaan Versteeg's avatar
Sébastiaan Versteeg committed
112 113


114
@login_required
115 116
def profile(request, pk=None):
    if pk:
117
        member = get_object_or_404(models.Member, user__pk=int(pk))
118
    else:
Thom Wiggers's avatar
Thom Wiggers committed
119
        member = get_object_or_404(models.Member, user=request.user)
Sébastiaan Versteeg's avatar
Sébastiaan Versteeg committed
120

121
    # Group the memberships under the committees for easier template rendering
122
    achievements = member_achievements(member)
123 124 125 126 127

    membership = member.current_membership
    membership_type = _("Former member")
    if membership:
        membership_type = membership.get_type_display()
128
    return render(request, 'members/profile.html',
129 130 131 132 133
                  {
                      'achievements': achievements,
                      'member': member,
                      'membership_type': membership_type,
                   })
134

135

136 137 138 139
@login_required
def account(request):
    return render(request, 'members/account.html')

140

141 142
@login_required
def edit_profile(request):
Thom Wiggers's avatar
Thom Wiggers committed
143
    member = get_object_or_404(models.Member, user=request.user)
144
    saved = False
145 146

    if request.POST:
147
        form = MemberForm(request.POST, request.FILES, instance=member)
148
        if form.is_valid():
149
            saved = True
150 151 152
            form.save()
    else:
        form = MemberForm(instance=member)
153 154

    return render(request, 'members/edit_profile.html',
155
                  {'form': form, 'saved': saved})
156

157

158 159 160 161 162 163 164 165
@permission_required('auth.change_user')
def iban_export(request):
    header_fields = ['name', 'username', 'iban']
    rows = []

    members = Member.active_members.filter(direct_debit_authorized=True)

    for member in members:
166 167 168 169 170 171
        if (member.current_membership.type != 'honorary'):
            rows.append({
                'name': member.get_full_name(),
                'username': member.user.username,
                'iban': member.bank_account
            })
172 173 174 175 176 177 178 179 180 181 182 183 184

    response = HttpResponse(content_type='text/csv')
    writer = csv.DictWriter(response, header_fields)
    writer.writeheader()

    for row in rows:
        writer.writerow(row)

    response['Content-Disposition'] = (
        'attachment; filename="iban-export.csv"')
    return response


185
def become_a_member(request):
Thom Wiggers's avatar
Thom Wiggers committed
186
    context = {'documents': models.BecomeAMemberDocument.objects.all()}
187 188 189 190
    return render(request, 'singlepages/become_a_member.html', context)


def get_become_a_member_document(request, pk):
Thom Wiggers's avatar
Thom Wiggers committed
191
    document = get_object_or_404(models.BecomeAMemberDocument, pk=int(pk))
192
    ext = os.path.splitext(document.file.path)[1]
Thom Wiggers's avatar
Thom Wiggers committed
193 194 195
    return sendfile(request,
                    document.file.path,
                    attachment=True,
196
                    attachment_filename=slugify(document.name) + ext)
197 198 199


def statistics(request):
200
    member_types = ("member", "supporter", "honorary")
201 202

    # The numbers
Thom Wiggers's avatar
Thom Wiggers committed
203
    total = models.Member.active_members.count()
204 205

    context = {
Thom Wiggers's avatar
Thom Wiggers committed
206
        "total_members": total,
207 208 209
        "total_stats_year": json.dumps(models.gen_stats_year(member_types)),
        "total_stats_member_type": json.dumps(
            models.gen_stats_member_type(member_types)),
210 211 212
    }

    return render(request, 'members/statistics.html', context)