__init__.py 8.72 KB
Newer Older
1
2
3
4
# -*- coding:utf-8 -*
#
# Copyright 2016,2017
# - Skia <skia@libskia.so>
5
# - Sli <antoine@bartuccio.fr>
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#
# 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.
#
#

Skia's avatar
Skia committed
26
import types
27

Sli's avatar
Sli committed
28
from sentry_sdk import last_event_id
29
from django.shortcuts import render
Sli's avatar
Sli committed
30
31
32
33
34
35
from django.http import (
    HttpResponseForbidden,
    HttpResponseNotFound,
    HttpResponseServerError,
)
from django.template import RequestContext
Sli's avatar
Sli committed
36
37
38
39
40
from django.core.exceptions import (
    PermissionDenied,
    ObjectDoesNotExist,
    ImproperlyConfigured,
)
41
from django.views.generic.base import View
Krophil's avatar
Krophil committed
42
from django.db.models import Count
43

44
from core.models import Group
Skia's avatar
Skia committed
45
from core.views.forms import LoginForm
46
from haystack.query import SearchQuerySet
47

Sli's avatar
Sli committed
48

49
def forbidden(request):
50
    try:
Sli's avatar
Sli committed
51
52
53
54
55
56
57
58
59
60
61
        return HttpResponseForbidden(
            render(
                request,
                "core/403.jinja",
                context={
                    "next": request.path,
                    "form": LoginForm(),
                    "popup": request.resolver_match.kwargs["popup"] or "",
                },
            )
        )
62
    except:
Sli's avatar
Sli committed
63
64
65
66
67
68
69
70
        return HttpResponseForbidden(
            render(
                request,
                "core/403.jinja",
                context={"next": request.path, "form": LoginForm()},
            )
        )

71
72

def not_found(request):
73
    return HttpResponseNotFound(render(request, "core/404.jinja"))
74

Sli's avatar
Sli committed
75

Sli's avatar
Sli committed
76
77
78
79
80
def internal_servor_error(request):
    request.sentry_last_event_id = last_event_id
    return HttpResponseServerError(render(request, "core/500.jinja"))


Skia's avatar
Skia committed
81
82
83
84
85
def can_edit_prop(obj, user):
    if obj is None or user.is_owner(obj):
        return True
    return False

Sli's avatar
Sli committed
86

Skia's avatar
Skia committed
87
88
89
90
91
def can_edit(obj, user):
    if obj is None or user.can_edit(obj):
        return True
    return can_edit_prop(obj, user)

Sli's avatar
Sli committed
92

Skia's avatar
Skia committed
93
94
95
96
def can_view(obj, user):
    if obj is None or user.can_view(obj):
        return True
    return can_edit(obj, user)
97

Sli's avatar
Sli committed
98

99
100
101
102
103
class CanCreateMixin(View):
    """
    This view is made to protect any child view that would create an object, and thus, that can not be protected by any
    of the following mixin
    """
Sli's avatar
Sli committed
104

Skia's avatar
Skia committed
105
106
107
108
109
110
    def dispatch(self, request, *arg, **kwargs):
        res = super(CanCreateMixin, self).dispatch(request, *arg, **kwargs)
        if not request.user.is_authenticated():
            raise PermissionDenied
        return res

111
112
113
114
    def form_valid(self, form):
        obj = form.instance
        if can_edit_prop(obj, self.request.user):
            return super(CanCreateMixin, self).form_valid(form)
115
116
        raise PermissionDenied

Sli's avatar
Sli committed
117

118
119
120
121
122
123
124
class CanEditPropMixin(View):
    """
    This view is made to protect any child view that would be showing some properties of an object that are restricted
    to only the owner group of the given object.
    In other word, you can make a view with this view as parent, and it would be retricted to the users that are in the
    object's owner_group
    """
Sli's avatar
Sli committed
125

126
    def dispatch(self, request, *arg, **kwargs):
Skia's avatar
Skia committed
127
128
129
130
        try:
            self.object = self.get_object()
            if can_edit_prop(self.object, request.user):
                return super(CanEditPropMixin, self).dispatch(request, *arg, **kwargs)
Skia's avatar
Skia committed
131
            return forbidden(request)
Sli's avatar
Sli committed
132
133
        except:
            pass
Skia's avatar
Skia committed
134
135
        # If we get here, it's a ListView
        l_id = [o.id for o in self.get_queryset() if can_edit_prop(o, request.user)]
136
        if not l_id and self.get_queryset().count() != 0:
Skia's avatar
Skia committed
137
138
            raise PermissionDenied
        self._get_queryset = self.get_queryset
Sli's avatar
Sli committed
139

Skia's avatar
Skia committed
140
141
        def get_qs(self2):
            return self2._get_queryset().filter(id__in=l_id)
Sli's avatar
Sli committed
142

Skia's avatar
Skia committed
143
144
        self.get_queryset = types.MethodType(get_qs, self)
        return super(CanEditPropMixin, self).dispatch(request, *arg, **kwargs)
145

Sli's avatar
Sli committed
146

Skia's avatar
Skia committed
147
class CanEditMixin(View):
148
    """
149
    This view makes exactly the same thing as its direct parent, but checks the group on the edit_groups field of the
150
151
    object
    """
Sli's avatar
Sli committed
152

153
    def dispatch(self, request, *arg, **kwargs):
Skia's avatar
Skia committed
154
155
156
157
        try:
            self.object = self.get_object()
            if can_edit(self.object, request.user):
                return super(CanEditMixin, self).dispatch(request, *arg, **kwargs)
Skia's avatar
Skia committed
158
            return forbidden(request)
Sli's avatar
Sli committed
159
160
        except:
            pass
Skia's avatar
Skia committed
161
162
        # If we get here, it's a ListView
        l_id = [o.id for o in self.get_queryset() if can_edit(o, request.user)]
163
        if not l_id and self.get_queryset().count() != 0:
Skia's avatar
Skia committed
164
165
            raise PermissionDenied
        self._get_queryset = self.get_queryset
Sli's avatar
Sli committed
166

Skia's avatar
Skia committed
167
168
        def get_qs(self2):
            return self2._get_queryset().filter(id__in=l_id)
Sli's avatar
Sli committed
169

Skia's avatar
Skia committed
170
171
        self.get_queryset = types.MethodType(get_qs, self)
        return super(CanEditMixin, self).dispatch(request, *arg, **kwargs)
172

Sli's avatar
Sli committed
173

Skia's avatar
Skia committed
174
class CanViewMixin(View):
175
    """
176
    This view still makes exactly the same thing as its direct parent, but checks the group on the view_groups field of
177
178
    the object
    """
Sli's avatar
Sli committed
179

180
    def dispatch(self, request, *arg, **kwargs):
181

Skia's avatar
Skia committed
182
183
184
185
        try:
            self.object = self.get_object()
            if can_view(self.object, request.user):
                return super(CanViewMixin, self).dispatch(request, *arg, **kwargs)
Skia's avatar
Skia committed
186
            return forbidden(request)
Sli's avatar
Sli committed
187
188
        except:
            pass
Skia's avatar
Skia committed
189
        # If we get here, it's a ListView
190
191
        queryset = self.get_queryset()

192
        l_id = [o.id for o in queryset if can_view(o, request.user)]
193
        if not l_id and queryset.count() != 0:
Skia's avatar
Skia committed
194
195
            raise PermissionDenied
        self._get_queryset = self.get_queryset
Sli's avatar
Sli committed
196

Skia's avatar
Skia committed
197
        def get_qs(self2):
Sli's avatar
Sli committed
198
            return self2._get_queryset().filter(id__in=l_id)
Sli's avatar
Sli committed
199

Skia's avatar
Skia committed
200
201
        self.get_queryset = types.MethodType(get_qs, self)
        return super(CanViewMixin, self).dispatch(request, *arg, **kwargs)
Skia's avatar
Skia committed
202

Sli's avatar
Sli committed
203

Sli's avatar
Sli committed
204
class FormerSubscriberMixin(View):
Sli's avatar
Sli committed
205
206
207
    """
    This view check if the user was at least an old subscriber
    """
Sli's avatar
Sli committed
208

Sli's avatar
Sli committed
209
210
211
    def dispatch(self, request, *args, **kwargs):
        if not request.user.was_subscribed:
            raise PermissionDenied
Sli's avatar
Sli committed
212
        return super(FormerSubscriberMixin, self).dispatch(request, *args, **kwargs)
Sli's avatar
Sli committed
213
214


215
216
217
218
class TabedViewMixin(View):
    """
    This view provide the basic functions for displaying tabs in the template
    """
Sli's avatar
Sli committed
219

220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
    def get_tabs_title(self):
        try:
            return self.tabs_title
        except:
            raise ImproperlyConfigured("tabs_title is required")

    def get_current_tab(self):
        try:
            return self.current_tab
        except:
            raise ImproperlyConfigured("current_tab is required")

    def get_list_of_tabs(self):
        try:
            return self.list_of_tabs
        except:
            raise ImproperlyConfigured("list_of_tabs is required")

    def get_context_data(self, **kwargs):
        kwargs = super(TabedViewMixin, self).get_context_data(**kwargs)
Sli's avatar
Sli committed
240
241
242
        kwargs["tabs_title"] = self.get_tabs_title()
        kwargs["current_tab"] = self.get_current_tab()
        kwargs["list_of_tabs"] = self.get_list_of_tabs()
243
244
        return kwargs

Sli's avatar
Sli committed
245

Skia's avatar
Skia committed
246
class QuickNotifMixin:
Skia's avatar
Skia committed
247
    quick_notif_list = []
Skia's avatar
Skia committed
248
249

    def dispatch(self, request, *arg, **kwargs):
Sli's avatar
Sli committed
250
251
252
        self.quick_notif_list = (
            []
        )  # In some cases, the class can stay instanciated, so we need to reset the list
Skia's avatar
Skia committed
253
254
        return super(QuickNotifMixin, self).dispatch(request, *arg, **kwargs)

Skia's avatar
Skia committed
255
256
257
    def get_success_url(self):
        ret = super(QuickNotifMixin, self).get_success_url()
        try:
Sli's avatar
Sli committed
258
259
            if "?" in ret:
                ret += "&" + self.quick_notif_url_arg
Skia's avatar
Skia committed
260
            else:
Sli's avatar
Sli committed
261
262
263
                ret += "?" + self.quick_notif_url_arg
        except:
            pass
Skia's avatar
Skia committed
264
265
266
267
268
        return ret

    def get_context_data(self, **kwargs):
        """Add quick notifications to context"""
        kwargs = super(QuickNotifMixin, self).get_context_data(**kwargs)
Sli's avatar
Sli committed
269
        kwargs["quick_notifs"] = []
Skia's avatar
Skia committed
270
        for n in self.quick_notif_list:
Sli's avatar
Sli committed
271
272
            kwargs["quick_notifs"].append(settings.SITH_QUICK_NOTIF[n])
        for k, v in settings.SITH_QUICK_NOTIF.items():
Skia's avatar
Skia committed
273
274
            for gk in self.request.GET.keys():
                if k == gk:
Sli's avatar
Sli committed
275
                    kwargs["quick_notifs"].append(v)
Skia's avatar
Skia committed
276
277
278
        return kwargs


Skia's avatar
Skia committed
279
280
from .user import *
from .page import *
Skia's avatar
Skia committed
281
from .files import *
Skia's avatar
Skia committed
282
from .site import *
283
from .group import *