Projet

Général

Profil

0003-pricing-simplify-mixins-and-permission-checks-65442.patch

Lauréline Guérin, 31 mai 2022 15:01

Télécharger (22,8 ko)

Voir les différences:

Subject: [PATCH 3/3] pricing: simplify mixins and permission checks (#65442)

 lingo/agendas/models.py                       |   6 -
 lingo/agendas/views.py                        |  20 +---
 .../manager_agenda_pricing_detail.html        |   4 -
 lingo/pricing/urls.py                         |  63 +++++-----
 lingo/pricing/views.py                        | 108 +-----------------
 5 files changed, 41 insertions(+), 160 deletions(-)
lingo/agendas/models.py
67 67

  
68 68
        return False, agenda
69 69

  
70
    def can_be_managed(self, user):
71
        return True
72

  
73
    def can_be_viewed(self, user):
74
        return True
75

  
76 70

  
77 71
class CheckTypeGroup(models.Model):
78 72
    slug = models.SlugField(_('Identifier'), max_length=160, unique=True)
lingo/agendas/views.py
14 14
# You should have received a copy of the GNU Affero General Public License
15 15
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 16

  
17
from django.core.exceptions import PermissionDenied
18 17
from django.shortcuts import get_object_or_404
19 18

  
20 19
from .models import Agenda
21 20

  
22 21

  
23
class ViewableAgendaMixin:
22
class AgendaMixin:
24 23
    agenda = None
25 24

  
26 25
    def set_agenda(self, **kwargs):
......
28 27

  
29 28
    def dispatch(self, request, *args, **kwargs):
30 29
        self.set_agenda(**kwargs)
31
        if not self.check_permissions(request.user):
32
            raise PermissionDenied()
33 30
        return super().dispatch(request, *args, **kwargs)
34 31

  
35
    def check_permissions(self, user):
36
        return True  # return self.agenda.can_be_viewed(user)
37

  
38 32
    def get_context_data(self, **kwargs):
39 33
        context = super().get_context_data(**kwargs)
40 34
        context['agenda'] = self.agenda
41 35
        return context
42 36

  
43

  
44
class ManagedAgendaMixin(ViewableAgendaMixin):
45
    def check_permissions(self, user):
46
        return True  # XXX: return self.agenda.can_be_managed(user)
47

  
48
    def get_form_kwargs(self):
49
        kwargs = super().get_form_kwargs()
50
        if not kwargs.get('instance'):
51
            kwargs['instance'] = self.model()
52
        kwargs['instance'].agenda = self.agenda
53
        return kwargs
54

  
55 37
    def get_success_url(self):
56 38
        # XXX:  return reverse('lingo-manager-agenda-settings', kwargs={'pk': self.agenda.id})
57 39
        return '/'
lingo/pricing/templates/lingo/pricing/manager_agenda_pricing_detail.html
10 10
<h2>
11 11
    {{ object.pricing }} ({{ object.date_start|date:'d/m/Y' }} - {{ object.date_end|date:'d/m/Y' }})
12 12
</h2>
13
{% if user_can_manage %}
14 13
<span class="actions">
15 14
  <a class="extra-actions-menu-opener"></a>
16 15
  <ul class="extra-actions-menu">
......
18 17
    <li><a rel="popup" href="{% url 'lingo-manager-agenda-pricing-delete' agenda.pk object.pk %}">{% trans 'Delete' %}</a></li>
19 18
  </ul>
20 19
</span>
21
{% endif %}
22 20
{% endblock %}
23 21

  
24 22
{% block content %}
......
44 42
      {% endfor %}
45 43
    </tbody>
46 44
  </table>
47
  {% if user_can_manage %}
48 45
  <p>
49 46
  <a class="pk-button" href="{% if matrix.criteria %}{% url 'lingo-manager-agenda-pricing-matrix-slug-edit' agenda.pk object.pk matrix.criteria.slug %}{% else %}{% url 'lingo-manager-agenda-pricing-matrix-edit' agenda.pk object.pk %}{% endif %}">{% trans "Edit pricing" %}</a>
50 47
  </p>
51
  {% endif %}
52 48
</div>
53 49
</div>
54 50
{% empty %}
lingo/pricing/urls.py
15 15
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 16

  
17 17
from django.conf.urls import url
18
from django.contrib.admin.views.decorators import staff_member_required
18 19

  
19 20
from . import views
20 21

  
21 22
urlpatterns = [
22
    url(r'^$', views.pricing_list, name='lingo-manager-pricing-list'),
23
    url(r'^import/$', views.config_import, name='lingo-manager-pricing-config-import'),
24
    url(r'^export/$', views.config_export, name='lingo-manager-pricing-config-export'),
23
    url(r'^$', staff_member_required(views.pricing_list), name='lingo-manager-pricing-list'),
24
    url(r'^import/$', staff_member_required(views.config_import), name='lingo-manager-pricing-config-import'),
25
    url(r'^export/$', staff_member_required(views.config_export), name='lingo-manager-pricing-config-export'),
25 26
    url(
26 27
        r'^add/$',
27
        views.pricing_add,
28
        staff_member_required(views.pricing_add),
28 29
        name='lingo-manager-pricing-add',
29 30
    ),
30 31
    url(
31 32
        r'^(?P<pk>\d+)/$',
32
        views.pricing_detail,
33
        staff_member_required(views.pricing_detail),
33 34
        name='lingo-manager-pricing-detail',
34 35
    ),
35 36
    url(
36 37
        r'^(?P<pk>\d+)/edit/$',
37
        views.pricing_edit,
38
        staff_member_required(views.pricing_edit),
38 39
        name='lingo-manager-pricing-edit',
39 40
    ),
40 41
    url(
41 42
        r'^(?P<pk>\d+)/delete/$',
42
        views.pricing_delete,
43
        staff_member_required(views.pricing_delete),
43 44
        name='lingo-manager-pricing-delete',
44 45
    ),
45 46
    url(
46 47
        r'^(?P<pk>\d+)/duplicate/$',
47
        views.pricing_duplicate,
48
        staff_member_required(views.pricing_duplicate),
48 49
        name='lingo-manager-pricing-duplicate',
49 50
    ),
50 51
    url(
51 52
        r'^(?P<pk>\d+)/export/$',
52
        views.pricing_export,
53
        staff_member_required(views.pricing_export),
53 54
        name='lingo-manager-pricing-export',
54 55
    ),
55 56
    url(
56 57
        r'^(?P<pk>\d+)/variable/$',
57
        views.pricing_variable_edit,
58
        staff_member_required(views.pricing_variable_edit),
58 59
        name='lingo-manager-pricing-variable-edit',
59 60
    ),
60 61
    url(
61 62
        r'^(?P<pk>\d+)/category/add/$',
62
        views.pricing_criteria_category_add,
63
        staff_member_required(views.pricing_criteria_category_add),
63 64
        name='lingo-manager-pricing-criteria-category-add',
64 65
    ),
65 66
    url(
66 67
        r'^(?P<pk>\d+)/category/(?P<category_pk>\d+)/edit/$',
67
        views.pricing_criteria_category_edit,
68
        staff_member_required(views.pricing_criteria_category_edit),
68 69
        name='lingo-manager-pricing-criteria-category-edit',
69 70
    ),
70 71
    url(
71 72
        r'^(?P<pk>\d+)/category/(?P<category_pk>\d+)/delete/$',
72
        views.pricing_criteria_category_delete,
73
        staff_member_required(views.pricing_criteria_category_delete),
73 74
        name='lingo-manager-pricing-criteria-category-delete',
74 75
    ),
75 76
    url(
76 77
        r'^(?P<pk>\d+)/order/$',
77
        views.pricing_criteria_category_order,
78
        staff_member_required(views.pricing_criteria_category_order),
78 79
        name='lingo-manager-pricing-criteria-category-order',
79 80
    ),
80
    url(r'^criterias/$', views.criteria_list, name='lingo-manager-pricing-criteria-list'),
81
    url(
82
        r'^criterias/$',
83
        staff_member_required(views.criteria_list),
84
        name='lingo-manager-pricing-criteria-list',
85
    ),
81 86
    url(
82 87
        r'^criteria/category/add/$',
83
        views.criteria_category_add,
88
        staff_member_required(views.criteria_category_add),
84 89
        name='lingo-manager-pricing-criteria-category-add',
85 90
    ),
86 91
    url(
87 92
        r'^criteria/category/(?P<pk>\d+)/edit/$',
88
        views.criteria_category_edit,
93
        staff_member_required(views.criteria_category_edit),
89 94
        name='lingo-manager-pricing-criteria-category-edit',
90 95
    ),
91 96
    url(
92 97
        r'^criteria/category/(?P<pk>\d+)/delete/$',
93
        views.criteria_category_delete,
98
        staff_member_required(views.criteria_category_delete),
94 99
        name='lingo-manager-pricing-criteria-category-delete',
95 100
    ),
96 101
    url(
97 102
        r'^criteria/category/(?P<pk>\d+)/export/$',
98
        views.criteria_category_export,
103
        staff_member_required(views.criteria_category_export),
99 104
        name='lingo-manager-pricing-criteria-category-export',
100 105
    ),
101 106
    url(
102 107
        r'^criteria/category/(?P<pk>\d+)/order/$',
103
        views.criteria_order,
108
        staff_member_required(views.criteria_order),
104 109
        name='lingo-manager-pricing-criteria-order',
105 110
    ),
106 111
    url(
107 112
        r'^criteria/category/(?P<category_pk>\d+)/add/$',
108
        views.criteria_add,
113
        staff_member_required(views.criteria_add),
109 114
        name='lingo-manager-pricing-criteria-add',
110 115
    ),
111 116
    url(
112 117
        r'^criteria/category/(?P<category_pk>\d+)/(?P<pk>\d+)/edit/$',
113
        views.criteria_edit,
118
        staff_member_required(views.criteria_edit),
114 119
        name='lingo-manager-pricing-criteria-edit',
115 120
    ),
116 121
    url(
117 122
        r'^criteria/category/(?P<category_pk>\d+)/(?P<pk>\d+)/delete/$',
118
        views.criteria_delete,
123
        staff_member_required(views.criteria_delete),
119 124
        name='lingo-manager-pricing-criteria-delete',
120 125
    ),
121 126
    url(
122 127
        r'^agenda/(?P<pk>\d+)/pricing/add/$',
123
        views.agenda_pricing_add,
128
        staff_member_required(views.agenda_pricing_add),
124 129
        name='lingo-manager-agenda-pricing-add',
125 130
    ),
126 131
    url(
127 132
        r'^agenda/(?P<pk>\d+)/pricing/(?P<pricing_pk>\d+)/$',
128
        views.agenda_pricing_detail,
133
        staff_member_required(views.agenda_pricing_detail),
129 134
        name='lingo-manager-agenda-pricing-detail',
130 135
    ),
131 136
    url(
132 137
        r'^agenda/(?P<pk>\d+)/pricing/(?P<pricing_pk>\d+)/edit/$',
133
        views.agenda_pricing_edit,
138
        staff_member_required(views.agenda_pricing_edit),
134 139
        name='lingo-manager-agenda-pricing-edit',
135 140
    ),
136 141
    url(
137 142
        r'^agenda/(?P<pk>\d+)/pricing/(?P<pricing_pk>\d+)/delete/$',
138
        views.agenda_pricing_delete,
143
        staff_member_required(views.agenda_pricing_delete),
139 144
        name='lingo-manager-agenda-pricing-delete',
140 145
    ),
141 146
    url(
142 147
        r'^agenda/(?P<pk>\d+)/pricing/(?P<pricing_pk>\d+)/matrix/edit/$',
143
        views.agenda_pricing_matrix_edit,
148
        staff_member_required(views.agenda_pricing_matrix_edit),
144 149
        name='lingo-manager-agenda-pricing-matrix-edit',
145 150
    ),
146 151
    url(
147 152
        r'^agenda/(?P<pk>\d+)/pricing/(?P<pricing_pk>\d+)/matrix/(?P<slug>[-_a-zA-Z0-9]+)/edit/$',
148
        views.agenda_pricing_matrix_edit,
153
        staff_member_required(views.agenda_pricing_matrix_edit),
149 154
        name='lingo-manager-agenda-pricing-matrix-slug-edit',
150 155
    ),
151 156
]
lingo/pricing/views.py
21 21

  
22 22
from django import forms
23 23
from django.contrib import messages
24
from django.core.exceptions import PermissionDenied
25 24
from django.db.models import Prefetch
26 25
from django.http import Http404, HttpResponse, HttpResponseBadRequest, HttpResponseRedirect
27 26
from django.shortcuts import get_object_or_404
......
33 32
from django.views.generic.detail import SingleObjectMixin
34 33

  
35 34
from lingo.agendas.models import Agenda
36
from lingo.agendas.views import ManagedAgendaMixin, ViewableAgendaMixin
35
from lingo.agendas.views import AgendaMixin
37 36
from lingo.pricing.forms import (
38 37
    AgendaPricingForm,
39 38
    CriteriaForm,
......
55 54
    form_class = ExportForm
56 55
    template_name = 'lingo/pricing/export.html'
57 56

  
58
    def dispatch(self, request, *args, **kwargs):
59
        if not request.user.is_staff:
60
            raise PermissionDenied()
61
        return super().dispatch(request, *args, **kwargs)
62

  
63 57
    def form_valid(self, form):
64 58
        response = HttpResponse(content_type='application/json')
65 59
        today = datetime.date.today()
......
78 72
    template_name = 'lingo/pricing/import.html'
79 73
    success_url = reverse_lazy('lingo-manager-pricing-list')
80 74

  
81
    def dispatch(self, request, *args, **kwargs):
82
        if not request.user.is_staff:
83
            raise PermissionDenied()
84
        return super().dispatch(request, *args, **kwargs)
85

  
86 75
    def form_valid(self, form):
87 76
        try:
88 77
            config_json = json.loads(force_text(self.request.FILES['config_json'].read()))
......
189 178
    template_name = 'lingo/pricing/manager_pricing_list.html'
190 179
    model = Pricing
191 180

  
192
    def dispatch(self, request, *args, **kwargs):
193
        if not request.user.is_staff:
194
            raise PermissionDenied()
195
        return super().dispatch(request, *args, **kwargs)
196

  
197 181

  
198 182
pricing_list = PricingListView.as_view()
199 183

  
......
202 186
    template_name = 'lingo/pricing/manager_criteria_list.html'
203 187
    model = CriteriaCategory
204 188

  
205
    def dispatch(self, request, *args, **kwargs):
206
        if not request.user.is_staff:
207
            raise PermissionDenied()
208
        return super().dispatch(request, *args, **kwargs)
209

  
210 189
    def get_queryset(self):
211 190
        return CriteriaCategory.objects.prefetch_related('criterias')
212 191

  
......
219 198
    model = Pricing
220 199
    fields = ['label']
221 200

  
222
    def dispatch(self, request, *args, **kwargs):
223
        if not request.user.is_staff:
224
            raise PermissionDenied()
225
        return super().dispatch(request, *args, **kwargs)
226

  
227 201
    def get_success_url(self):
228 202
        return reverse('lingo-manager-pricing-detail', args=[self.object.pk])
229 203

  
......
235 209
    template_name = 'lingo/pricing/manager_pricing_detail.html'
236 210
    model = Pricing
237 211

  
238
    def dispatch(self, request, *args, **kwargs):
239
        if not request.user.is_staff:
240
            raise PermissionDenied()
241
        return super().dispatch(request, *args, **kwargs)
242

  
243 212
    def get_queryset(self):
244 213
        return (
245 214
            super()
......
260 229
    model = Pricing
261 230
    fields = ['label', 'slug']
262 231

  
263
    def dispatch(self, request, *args, **kwargs):
264
        if not request.user.is_staff:
265
            raise PermissionDenied()
266
        return super().dispatch(request, *args, **kwargs)
267

  
268 232
    def get_success_url(self):
269 233
        return reverse('lingo-manager-pricing-detail', args=[self.object.pk])
270 234

  
......
276 240
    template_name = 'lingo/manager_confirm_delete.html'
277 241
    model = Pricing
278 242

  
279
    def dispatch(self, request, *args, **kwargs):
280
        if not request.user.is_staff:
281
            raise PermissionDenied()
282
        return super().dispatch(request, *args, **kwargs)
283

  
284 243
    def get_success_url(self):
285 244
        return reverse('lingo-manager-pricing-list')
286 245

  
......
295 254

  
296 255
    def dispatch(self, request, *args, **kwargs):
297 256
        self.object = self.get_object()
298
        if not request.user.is_staff:
299
            raise PermissionDenied()
300 257
        return super().dispatch(request, *args, **kwargs)
301 258

  
302 259
    def get_success_url(self):
......
313 270
class PricingExport(DetailView):
314 271
    model = Pricing
315 272

  
316
    def dispatch(self, request, *args, **kwargs):
317
        if not request.user.is_staff:
318
            raise PermissionDenied()
319
        return super().dispatch(request, *args, **kwargs)
320

  
321 273
    def get(self, request, *args, **kwargs):
322 274
        response = HttpResponse(content_type='application/json')
323 275
        today = datetime.date.today()
......
339 291

  
340 292
    def dispatch(self, request, *args, **kwargs):
341 293
        self.object = get_object_or_404(Pricing, pk=kwargs['pk'])
342
        if not request.user.is_staff:
343
            raise PermissionDenied()
344 294
        return super().dispatch(request, *args, **kwargs)
345 295

  
346 296
    def get_context_data(self, **kwargs):
......
378 328
        self.object = get_object_or_404(Pricing, pk=kwargs['pk'])
379 329
        if self.object.categories.count() >= 3:
380 330
            raise Http404
381
        if not request.user.is_staff:
382
            raise PermissionDenied()
383 331
        return super().dispatch(request, *args, **kwargs)
384 332

  
385 333
    def get_form_kwargs(self):
......
410 358
    def dispatch(self, request, *args, **kwargs):
411 359
        self.object = get_object_or_404(Pricing, pk=kwargs['pk'])
412 360
        self.category = get_object_or_404(self.object.categories, pk=kwargs['category_pk'])
413
        if not request.user.is_staff:
414
            raise PermissionDenied()
415 361
        return super().dispatch(request, *args, **kwargs)
416 362

  
417 363
    def get_form_kwargs(self):
......
447 393

  
448 394
    def dispatch(self, request, *args, **kwargs):
449 395
        self.pricing = get_object_or_404(Pricing, pk=kwargs['pk'])
450
        if not request.user.is_staff:
451
            raise PermissionDenied()
452 396
        return super().dispatch(request, *args, **kwargs)
453 397

  
454 398
    def get_queryset(self):
......
470 414
class PricingCriteriaCategoryOrder(DetailView):
471 415
    model = Pricing
472 416

  
473
    def dispatch(self, request, *args, **kwargs):
474
        if not request.user.is_staff:
475
            raise PermissionDenied()
476
        return super().dispatch(request, *args, **kwargs)
477

  
478 417
    def get(self, request, *args, **kwargs):
479 418
        if 'new-order' not in request.GET:
480 419
            return HttpResponseBadRequest('missing new-order parameter')
......
499 438
    model = CriteriaCategory
500 439
    fields = ['label']
501 440

  
502
    def dispatch(self, request, *args, **kwargs):
503
        if not request.user.is_staff:
504
            raise PermissionDenied()
505
        return super().dispatch(request, *args, **kwargs)
506

  
507 441
    def get_success_url(self):
508 442
        return reverse('lingo-manager-pricing-criteria-list')
509 443

  
......
516 450
    model = CriteriaCategory
517 451
    fields = ['label', 'slug']
518 452

  
519
    def dispatch(self, request, *args, **kwargs):
520
        if not request.user.is_staff:
521
            raise PermissionDenied()
522
        return super().dispatch(request, *args, **kwargs)
523

  
524 453
    def get_success_url(self):
525 454
        return reverse('lingo-manager-pricing-criteria-list')
526 455

  
......
532 461
    template_name = 'lingo/manager_confirm_delete.html'
533 462
    model = CriteriaCategory
534 463

  
535
    def dispatch(self, request, *args, **kwargs):
536
        if not request.user.is_staff:
537
            raise PermissionDenied()
538
        return super().dispatch(request, *args, **kwargs)
539

  
540 464
    def get_success_url(self):
541 465
        return reverse('lingo-manager-pricing-criteria-list')
542 466

  
......
547 471
class CriteriaCategoryExport(DetailView):
548 472
    model = CriteriaCategory
549 473

  
550
    def dispatch(self, request, *args, **kwargs):
551
        if not request.user.is_staff:
552
            raise PermissionDenied()
553
        return super().dispatch(request, *args, **kwargs)
554

  
555 474
    def get(self, request, *args, **kwargs):
556 475
        response = HttpResponse(content_type='application/json')
557 476
        today = datetime.date.today()
......
569 488
class CriteriaOrder(DetailView):
570 489
    model = CriteriaCategory
571 490

  
572
    def dispatch(self, request, *args, **kwargs):
573
        if not request.user.is_staff:
574
            raise PermissionDenied()
575
        return super().dispatch(request, *args, **kwargs)
576

  
577 491
    def get(self, request, *args, **kwargs):
578 492
        if 'new-order' not in request.GET:
579 493
            return HttpResponseBadRequest('missing new-order parameter')
......
602 516

  
603 517
    def dispatch(self, request, *args, **kwargs):
604 518
        self.category_pk = kwargs.pop('category_pk')
605
        if not request.user.is_staff:
606
            raise PermissionDenied()
607 519
        return super().dispatch(request, *args, **kwargs)
608 520

  
609 521
    def get_form_kwargs(self):
......
627 539

  
628 540
    def dispatch(self, request, *args, **kwargs):
629 541
        self.category_pk = kwargs.pop('category_pk')
630
        if not request.user.is_staff:
631
            raise PermissionDenied()
632 542
        return super().dispatch(request, *args, **kwargs)
633 543

  
634 544
    def get_queryset(self):
......
647 557

  
648 558
    def dispatch(self, request, *args, **kwargs):
649 559
        self.category_pk = kwargs.pop('category_pk')
650
        if not request.user.is_staff:
651
            raise PermissionDenied()
652 560
        return super().dispatch(request, *args, **kwargs)
653 561

  
654 562
    def get_queryset(self):
......
661 569
criteria_delete = CriteriaDeleteView.as_view()
662 570

  
663 571

  
664
class AgendaPricingAddView(ManagedAgendaMixin, CreateView):
572
class AgendaPricingAddView(AgendaMixin, CreateView):
665 573
    template_name = 'lingo/pricing/manager_agenda_pricing_form.html'
666 574
    model = AgendaPricing
667 575
    form_class = AgendaPricingForm
......
673 581
agenda_pricing_add = AgendaPricingAddView.as_view()
674 582

  
675 583

  
676
class AgendaPricingDetailView(ViewableAgendaMixin, DetailView):
584
class AgendaPricingDetailView(AgendaMixin, DetailView):
677 585
    model = AgendaPricing
678 586
    pk_url_kwarg = 'pricing_pk'
679 587
    template_name = 'lingo/pricing/manager_agenda_pricing_detail.html'
......
686 594
            'pricing__criterias__category'
687 595
        )
688 596

  
689
    def get_context_data(self, **kwargs):
690
        kwargs['user_can_manage'] = self.agenda.can_be_managed(self.request.user)
691
        return super().get_context_data(**kwargs)
692

  
693 597

  
694 598
agenda_pricing_detail = AgendaPricingDetailView.as_view()
695 599

  
696 600

  
697
class AgendaPricingEditView(ManagedAgendaMixin, UpdateView):
601
class AgendaPricingEditView(AgendaMixin, UpdateView):
698 602
    template_name = 'lingo/pricing/manager_agenda_pricing_form.html'
699 603
    model = AgendaPricing
700 604
    pk_url_kwarg = 'pricing_pk'
......
713 617
agenda_pricing_edit = AgendaPricingEditView.as_view()
714 618

  
715 619

  
716
class AgendaPricingDeleteView(ManagedAgendaMixin, DeleteView):
620
class AgendaPricingDeleteView(AgendaMixin, DeleteView):
717 621
    template_name = 'lingo/manager_confirm_delete.html'
718 622
    model = AgendaPricing
719 623
    pk_url_kwarg = 'pricing_pk'
......
728 632
agenda_pricing_delete = AgendaPricingDeleteView.as_view()
729 633

  
730 634

  
731
class AgendaPricingMatrixEdit(ManagedAgendaMixin, FormView):
635
class AgendaPricingMatrixEdit(AgendaMixin, FormView):
732 636
    template_name = 'lingo/pricing/manager_agenda_pricing_matrix_form.html'
733 637

  
734 638
    def set_agenda(self, **kwargs):
735
-