1
1
import dataclasses
2
2
from typing import List
3
3
4
- from django .contrib .auth .mixins import LoginRequiredMixin , UserPassesTestMixin
4
+ from django .contrib .auth .mixins import AccessMixin
5
5
from django .core .cache import cache
6
6
from django .core .exceptions import PermissionDenied
7
7
from django .http import Http404 , StreamingHttpResponse
14
14
15
15
from view_breadcrumbs import BaseBreadcrumbMixin
16
16
17
+ from open_inwoner .openzaak .api_models import Zaak
17
18
from open_inwoner .openzaak .cases import (
18
19
fetch_case_information_objects ,
20
+ fetch_case_information_objects_for_case_and_info ,
19
21
fetch_cases ,
22
+ fetch_roles_for_case_and_bsn ,
20
23
fetch_single_case ,
21
24
fetch_specific_statuses ,
22
25
fetch_status_history ,
35
38
from open_inwoner .openzaak .utils import filter_info_object_visibility
36
39
37
40
38
- class CaseListView (
39
- BaseBreadcrumbMixin , LoginRequiredMixin , UserPassesTestMixin , TemplateView
40
- ):
41
- template_name = "pages/cases/list.html"
41
+ class CaseAccessMixin (AccessMixin ):
42
+ """
43
+ Shared authorisation check
42
44
43
- @cached_property
44
- def crumbs (self ):
45
- return [(_ ("Mijn aanvragen" ), reverse ("accounts:my_cases" ))]
45
+ Base checks:
46
+ - user is authenticated
47
+ - user has a BSN
48
+
49
+ When retrieving a case :
50
+ - users BSN has a role for this case
51
+ """
52
+
53
+ case : Zaak = None
54
+
55
+ def dispatch (self , request , * args , ** kwargs ):
56
+ if not request .user .is_authenticated :
57
+ return self .handle_no_permission ()
58
+
59
+ if not request .user .bsn :
60
+ return self .handle_no_permission ()
61
+
62
+ if "object_id" in kwargs :
63
+ case_uuid = kwargs ["object_id" ]
64
+ self .case = fetch_single_case (case_uuid )
65
+
66
+ if self .case :
67
+ # check if we have a role in this case
68
+ if not fetch_roles_for_case_and_bsn (self .case .url , request .user .bsn ):
69
+ return self .handle_no_permission ()
46
70
47
- def test_func (self ):
48
- return self .request .user .bsn is not None
71
+ return super ().dispatch (request , * args , ** kwargs )
49
72
50
73
def handle_no_permission (self ):
51
74
if self .request .user .is_authenticated :
52
75
return redirect (reverse ("root" ))
53
76
54
77
return super ().handle_no_permission ()
55
78
79
+
80
+ class CaseListView (BaseBreadcrumbMixin , CaseAccessMixin , TemplateView ):
81
+ template_name = "pages/cases/list.html"
82
+
83
+ @cached_property
84
+ def crumbs (self ):
85
+ return [(_ ("Mijn aanvragen" ), reverse ("accounts:my_cases" ))]
86
+
56
87
def get_context_data (self , ** kwargs ):
57
88
context = super ().get_context_data (** kwargs )
58
89
@@ -122,9 +153,7 @@ class SimpleFile:
122
153
url : str
123
154
124
155
125
- class CaseDetailView (
126
- BaseBreadcrumbMixin , LoginRequiredMixin , UserPassesTestMixin , TemplateView
127
- ):
156
+ class CaseDetailView (BaseBreadcrumbMixin , CaseAccessMixin , TemplateView ):
128
157
template_name = "pages/cases/status.html"
129
158
130
159
@cached_property
@@ -137,40 +166,30 @@ def crumbs(self):
137
166
),
138
167
]
139
168
140
- def test_func (self ):
141
- return self .request .user .bsn is not None
142
-
143
- def handle_no_permission (self ):
144
- if self .request .user .is_authenticated :
145
- return redirect (reverse ("root" ))
146
-
147
- return super ().handle_no_permission ()
148
-
149
169
def get_context_data (self , ** kwargs ):
150
170
context = super ().get_context_data (** kwargs )
151
171
152
- case_uuid = context ["object_id" ]
153
- case = fetch_single_case (case_uuid )
154
-
155
- if case :
156
- documents = self .get_case_document_files (case )
172
+ if self .case :
173
+ documents = self .get_case_document_files (self .case )
157
174
158
- statuses = fetch_status_history (case .url )
175
+ statuses = fetch_status_history (self . case .url )
159
176
statuses .sort (key = lambda status : status .datum_status_gezet )
160
177
161
- case_type = fetch_single_case_type (case .zaaktype )
162
- status_types = fetch_status_types (case_type = case .zaaktype )
178
+ case_type = fetch_single_case_type (self . case .zaaktype )
179
+ status_types = fetch_status_types (case_type = self . case .zaaktype )
163
180
164
181
status_types_mapping = {st .url : st for st in status_types }
165
182
for status in statuses :
166
183
status_type = status_types_mapping [status .statustype ]
167
184
status .statustype = status_type
168
185
169
186
context ["case" ] = {
170
- "identification" : case .identificatie ,
171
- "start_date" : case .startdatum ,
172
- "end_date" : (case .einddatum if hasattr (case , "einddatum" ) else None ),
173
- "description" : case .omschrijving ,
187
+ "identification" : self .case .identificatie ,
188
+ "start_date" : self .case .startdatum ,
189
+ "end_date" : (
190
+ self .case .einddatum if hasattr (self .case , "einddatum" ) else None
191
+ ),
192
+ "description" : self .case .omschrijving ,
174
193
"type_description" : (
175
194
case_type .omschrijving if case_type else _ ("No data available" )
176
195
),
@@ -222,7 +241,8 @@ def get_case_document_files(self, case) -> List[SimpleFile]:
222
241
url = reverse (
223
242
"accounts:case_document_download" ,
224
243
kwargs = {
225
- "object_id" : info_obj .uuid ,
244
+ "object_id" : case .uuid ,
245
+ "info_id" : info_obj .uuid ,
226
246
},
227
247
),
228
248
)
@@ -241,29 +261,30 @@ def get_anchors(self, statuses, documents):
241
261
return anchors
242
262
243
263
244
- class CaseDocumentDownloadView (LoginRequiredMixin , UserPassesTestMixin , View ):
245
- def test_func (self ):
246
- return self .request .user .bsn is not None
247
-
248
- def handle_no_permission (self ):
249
- if self .request .user .is_authenticated :
250
- return redirect (reverse ("root" ))
251
-
252
- return super ().handle_no_permission ()
253
-
254
- def get (self , * args , ** kwargs ):
255
- info_object_uuid = kwargs ["object_id" ]
264
+ class CaseDocumentDownloadView (CaseAccessMixin , View ):
265
+ def get (self , request , * args , ** kwargs ):
266
+ if not self .case :
267
+ raise Http404
256
268
269
+ info_object_uuid = kwargs ["info_id" ]
257
270
info_object = fetch_single_information_object (uuid = info_object_uuid )
258
271
if not info_object :
259
272
raise Http404
260
273
274
+ # check if this info_object belongs to this case
275
+ if not fetch_case_information_objects_for_case_and_info (
276
+ self .case .url , info_object .url
277
+ ):
278
+ raise PermissionDenied ()
279
+
280
+ # check if this info_object should be visible
261
281
config = OpenZaakConfig .get_solo ()
262
282
if not filter_info_object_visibility (
263
283
info_object , config .document_max_confidentiality
264
284
):
265
285
raise PermissionDenied ()
266
286
287
+ # retrieve and stream content
267
288
content_stream = download_document (info_object .inhoud )
268
289
if not content_stream :
269
290
raise Http404
@@ -275,3 +296,7 @@ def get(self, *args, **kwargs):
275
296
}
276
297
response = StreamingHttpResponse (content_stream , headers = headers )
277
298
return response
299
+
300
+ def handle_no_permission (self ):
301
+ # plain error and no redirect
302
+ raise PermissionDenied ()
0 commit comments