views.py 6.96 KB
Newer Older
1
import csv
2
import json
3
from datetime import date, datetime
4

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

12
from members.services import member_achievements
13
from members.models import Member
Thom Wiggers's avatar
Thom Wiggers committed
14
from . import models
15
from .forms import ProfileForm
16

17

18
def filter_users(tab, keywords, year_range):
19 20
    memberships_query = Q(until__gt=datetime.now()) | Q(until=None)
    members_query = ~Q(id=None)
21

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

36 37
    if keywords:
        for key in keywords:
38
            members_query &= (
39
                (Q(profile__nickname__icontains=key) &
40
                 # Works because relevant options all have `nick` in their key
41 42 43 44
                 Q(profile__display_name_preference__contains='nick')) |
                Q(first_name__icontains=key) |
                Q(last_name__icontains=key) |
                Q(username__icontains=key))
45

46
    if tab == 'ex':
47 48 49 50 51
        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
52 53
        members_query &= (Q(pk__in=memberships.values('user__pk')) |
                          ~Q(pk__in=all_memberships.values('user__pk')))
54 55
    else:
        memberships = models.Membership.objects.filter(memberships_query)
56 57 58 59 60
        members_query &= Q(pk__in=memberships.values('user__pk'))
    return (Member.objects
                  .filter(members_query)
                  .order_by('-profile__starting_year',
                            'first_name'))
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80


@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)
81 82 83

    paginator = Paginator(members, 24)

Sébastiaan Versteeg's avatar
Sébastiaan Versteeg committed
84 85 86 87 88 89 90 91 92
    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)

93 94 95
    page_range = range(1, paginator.num_pages + 1)
    if paginator.num_pages > 7:
        if page > 3:
96 97 98 99
            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
100
            page_range = range(page - 2, page_range_end)
101 102 103 104
            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
105

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


112
@login_required
113 114
def profile(request, pk=None):
    if pk:
115
        member = get_object_or_404(Member, pk=int(pk))
116
    else:
117
        member = request.member
Sébastiaan Versteeg's avatar
Sébastiaan Versteeg committed
118

119
    # Group the memberships under the committees for easier template rendering
120
    achievements = member_achievements(member)
121 122

    membership = member.current_membership
123
    membership_type = _("Unknown membership history")
124 125
    if membership:
        membership_type = membership.get_type_display()
126 127 128 129 130 131 132
    elif member.has_been_honorary_member():
        membership_type = _("Former honorary member")
    elif member.has_been_member():
        membership_type = _("Former member")
    elif member.latest_membership:
        membership_type = _("Former supporter")

133
    return render(request, 'members/profile.html',
134 135 136 137 138
                  {
                      'achievements': achievements,
                      'member': member,
                      'membership_type': membership_type,
                   })
139

140

141 142 143 144
@login_required
def account(request):
    return render(request, 'members/account.html')

145

146 147
@login_required
def edit_profile(request):
148
    profile = get_object_or_404(models.Profile, user=request.user)
149
    saved = False
150 151

    if request.POST:
152
        form = ProfileForm(request.POST, request.FILES, instance=profile)
153
        if form.is_valid():
154
            saved = True
155 156
            form.save()
    else:
157
        form = ProfileForm(instance=profile)
158 159

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

162

163 164 165 166 167
@permission_required('auth.change_user')
def iban_export(request):
    header_fields = ['name', 'username', 'iban']
    rows = []

168 169
    members = Member.active_members.filter(
            profile__direct_debit_authorized=True)
170 171

    for member in members:
172 173 174
        if (member.current_membership.type != 'honorary'):
            rows.append({
                'name': member.get_full_name(),
175 176
                'username': member.username,
                'iban': member.profile.bank_account
177
            })
178 179 180 181 182 183 184 185 186 187 188 189 190

    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


191
def statistics(request):
192
    member_types = ("member", "supporter", "honorary")
193 194

    # The numbers
195
    total = Member.active_members.count()
196 197

    context = {
Thom Wiggers's avatar
Thom Wiggers committed
198
        "total_members": total,
199 200 201
        "total_stats_year": json.dumps(models.gen_stats_year(member_types)),
        "total_stats_member_type": json.dumps(
            models.gen_stats_member_type(member_types)),
202 203 204
    }

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