views.py 7.23 KB
Newer Older
Sli's avatar
Sli committed
1
2
3
# -*- coding:utf-8 -*
#
# Copyright 2017
Sli's avatar
Sli committed
4
# - Sli <antoine@bartuccio.fr>
Sli's avatar
Sli committed
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#
# Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
# http://ae.utbm.fr.
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License a published by the Free Software
# Foundation; either version 3 of the License, or (at your option) any later
# version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
# details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, write to the Free Sofware Foundation, Inc., 59 Temple
# Place - Suite 330, Boston, MA 02111-1307, USA.
#
#
24
from ast import literal_eval
Sli's avatar
Sli committed
25
from enum import Enum
Sli's avatar
Sli committed
26

Sli's avatar
Sli committed
27
from django.views.generic import ListView, View
Sli's avatar
Sli committed
28
29
30
from django.views.generic.edit import FormView
from django.utils.translation import ugettext_lazy as _
from django.views.generic.detail import SingleObjectMixin
Sli's avatar
Sli committed
31
from django.http.response import HttpResponseRedirect
32
from django.urls import reverse
Sli's avatar
Sli committed
33
34
35
from django import forms

from core.models import User
Sli's avatar
Sli committed
36
from core.views import FormerSubscriberMixin
Sli's avatar
Sli committed
37
from core.views.forms import SelectDate
Sli's avatar
Sli committed
38
from core.views import search_user
Sli's avatar
Sli committed
39
40
from phonenumber_field.widgets import PhoneNumberInternationalFallbackWidget

Sli's avatar
Sli committed
41
42
43
44
45
46
47
48
49
# Enum to select search type


class SearchType(Enum):
    NORMAL = 1
    REVERSE = 2
    QUICK = 3


Sli's avatar
Sli committed
50
51
52
53
54
55
56
# Custom form


class SearchForm(forms.ModelForm):
    class Meta:
        model = User
        fields = [
Sli's avatar
Sli committed
57
58
59
60
61
62
63
64
65
            "first_name",
            "last_name",
            "nick_name",
            "role",
            "department",
            "semester",
            "promo",
            "date_of_birth",
            "phone",
Sli's avatar
Sli committed
66
67
        ]
        widgets = {
Sli's avatar
Sli committed
68
69
            "date_of_birth": SelectDate,
            "phone": PhoneNumberInternationalFallbackWidget,
Sli's avatar
Sli committed
70
71
        }

Sli's avatar
Sli committed
72
    sex = forms.ChoiceField(
73
74
75
76
77
        choices=[
            ("MAN", _("Man")),
            ("WOMAN", _("Woman")),
            ("INDIFFERENT", _("Indifferent")),
        ],
Sli's avatar
Sli committed
78
79
80
81
        widget=forms.RadioSelect,
        initial="INDIFFERENT",
        label=_("Sex"),
    )
Sli's avatar
Sli committed
82

Sli's avatar
Sli committed
83
    quick = forms.CharField(label=_("Last/First name or nickname"), max_length=255)
Sli's avatar
Sli committed
84

Sli's avatar
Sli committed
85
86
87
88
89
    def __init__(self, *args, **kwargs):
        super(SearchForm, self).__init__(*args, **kwargs)
        for key in self.fields.keys():
            self.fields[key].required = False

Sli's avatar
Sli committed
90
91
92
93
    @property
    def cleaned_data_json(self):
        data = self.cleaned_data
        for key in data.keys():
Sli's avatar
Sli committed
94
            if key in ("date_of_birth", "phone") and data[key] is not None:
Sli's avatar
Sli committed
95
96
                data[key] = str(data[key])
        return data
Sli's avatar
Sli committed
97

Sli's avatar
Sli committed
98

Sli's avatar
Sli committed
99
100
# Views

Sli's avatar
Sli committed
101

Sli's avatar
Sli committed
102
class SearchFormListView(FormerSubscriberMixin, SingleObjectMixin, ListView):
Sli's avatar
Sli committed
103
    model = User
Sli's avatar
Sli committed
104
105
    ordering = ["-id"]
    paginate_by = 12
Sli's avatar
Sli committed
106
    template_name = "matmat/search_form.jinja"
Sli's avatar
Sli committed
107
108

    def dispatch(self, request, *args, **kwargs):
Sli's avatar
Sli committed
109
110
        self.form_class = kwargs["form"]
        self.search_type = kwargs["search_type"]
111
        self.session = request.session
Sli's avatar
Sli committed
112
        self.last_search = self.session.get("matmat_search_result", str([]))
113
        self.last_search = literal_eval(self.last_search)
Sli's avatar
Sli committed
114
115
        if "valid_form" in kwargs.keys():
            self.valid_form = kwargs["valid_form"]
Sli's avatar
Sli committed
116
117
118
119
        else:
            self.valid_form = None

        self.init_query = self.model.objects
Sli's avatar
Sli committed
120
        self.can_see_hidden = True
Sli's avatar
Sli committed
121
        if not (request.user.is_board_member or request.user.is_root):
Sli's avatar
Sli committed
122
            self.can_see_hidden = False
Sli's avatar
Sli committed
123
124
125
126
127
128
129
130
131
132
            self.init_query = self.init_query.exclude(is_subscriber_viewable=False)

        return super(SearchFormListView, self).dispatch(request, *args, **kwargs)

    def post(self, request, *args, **kwargs):
        return self.get(request, *args, **kwargs)

    def get_context_data(self, **kwargs):
        self.object = None
        kwargs = super(SearchFormListView, self).get_context_data(**kwargs)
Sli's avatar
Sli committed
133
134
        kwargs["form"] = self.form_class
        kwargs["result_exists"] = self.result_exists
Sli's avatar
Sli committed
135
136
137
        return kwargs

    def get_queryset(self):
138
        q = self.init_query
Sli's avatar
Sli committed
139
        if self.valid_form is not None:
Sli's avatar
Sli committed
140
            if self.search_type == SearchType.REVERSE:
Sli's avatar
Sli committed
141
                q = q.filter(phone=self.valid_form["phone"]).all()
Sli's avatar
Sli committed
142
            elif self.search_type == SearchType.QUICK:
Sli's avatar
Sli committed
143
144
                if self.valid_form["quick"].strip():
                    q = search_user(self.valid_form["quick"])
145
146
147
                else:
                    q = []
                if not self.can_see_hidden and len(q) > 0:
Sli's avatar
Sli committed
148
                    q = [user for user in q if user.is_subscriber_viewable]
Sli's avatar
Sli committed
149
            else:
Sli's avatar
Sli committed
150
151
                search_dict = {}
                for key, value in self.valid_form.items():
Sli's avatar
Sli committed
152
153
154
                    if key not in ("phone", "quick") and not (
                        value == "" or value is None or value == "INDIFFERENT"
                    ):
Sli's avatar
Sli committed
155
156
                        search_dict[key + "__icontains"] = value
                q = q.filter(**search_dict).all()
Sli's avatar
Sli committed
157
        else:
158
            q = q.filter(pk__in=self.last_search).all()
Sli's avatar
Sli committed
159
160
161
162
        if isinstance(q, list):
            self.result_exists = len(q) > 0
        else:
            self.result_exists = q.exists()
163
164
165
        self.last_search = []
        for user in q:
            self.last_search.append(user.id)
Sli's avatar
Sli committed
166
        self.session["matmat_search_result"] = str(self.last_search)
167
        return q
Sli's avatar
Sli committed
168
169


Sli's avatar
Sli committed
170
class SearchFormView(FormerSubscriberMixin, FormView):
Sli's avatar
Sli committed
171
172
173
    """
    Allows users to search inside the user list
    """
Sli's avatar
Sli committed
174

Sli's avatar
Sli committed
175
176
177
    form_class = SearchForm

    def dispatch(self, request, *args, **kwargs):
Sli's avatar
Sli committed
178
        self.session = request.session
Sli's avatar
Sli committed
179
        self.init_query = User.objects
Sli's avatar
Sli committed
180
181
        kwargs["form"] = self.get_form()
        kwargs["search_type"] = self.search_type
Sli's avatar
Sli committed
182
183
184
185
186
187
188
189
190
191
        return super(SearchFormView, self).dispatch(request, *args, **kwargs)

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

    def post(self, request, *args, **kwargs):
        form = self.get_form()
        view = SearchFormListView.as_view()
        if form.is_valid():
Sli's avatar
Sli committed
192
193
            kwargs["valid_form"] = form.clean()
            request.session["matmat_search_form"] = form.cleaned_data_json
Sli's avatar
Sli committed
194
195
196
        return view(request, *args, **kwargs)

    def get_initial(self):
Sli's avatar
Sli committed
197
        init = self.session.get("matmat_search_form", {})
198
        if not init:
Sli's avatar
Sli committed
199
            init["department"] = ""
200
        return init
Sli's avatar
Sli committed
201
202


Sli's avatar
Sli committed
203
204
205
206
class SearchNormalFormView(SearchFormView):
    search_type = SearchType.NORMAL


Sli's avatar
Sli committed
207
class SearchReverseFormView(SearchFormView):
Sli's avatar
Sli committed
208
209
210
211
212
    search_type = SearchType.REVERSE


class SearchQuickFormView(SearchFormView):
    search_type = SearchType.QUICK
Sli's avatar
Sli committed
213
214


Sli's avatar
Sli committed
215
class SearchClearFormView(FormerSubscriberMixin, View):
Sli's avatar
Sli committed
216
217
218
219
220
221
    """
    Clear SearchFormView and redirect to it
    """

    def dispatch(self, request, *args, **kwargs):
        super(SearchClearFormView, self).dispatch(request, *args, **kwargs)
Sli's avatar
Sli committed
222
223
224
225
226
        if "matmat_search_form" in request.session.keys():
            request.session.pop("matmat_search_form")
        if "matmat_search_result" in request.session.keys():
            request.session.pop("matmat_search_result")
        return HttpResponseRedirect(reverse("matmat:search"))