2
2
from datetime import timedelta
3
3
4
4
from django .contrib import admin
5
+ from django .contrib import messages
5
6
from django .contrib .auth import get_permission_codename
6
7
from django .contrib .auth .models import User
8
+ from django .http import HttpResponseRedirect
9
+ from django .shortcuts import render
10
+ from django .utils .translation import ngettext
7
11
from core import utils
8
12
9
13
from apps .ifc_validation_models .models import ValidationRequest , ValidationTask , ValidationOutcome
@@ -27,22 +31,30 @@ def save_model(self, request, obj, form, change):
27
31
super ().save_model (request , obj , form , change )
28
32
29
33
30
- class ValidationRequestAdmin (BaseAdmin ):
34
+ class NonAdminAddable (admin .ModelAdmin ):
35
+
36
+ def has_add_permission (self , request ):
37
+
38
+ # disable add via Admin ('+ Add' button)
39
+ return False
40
+
41
+
42
+ class ValidationRequestAdmin (BaseAdmin , NonAdminAddable ):
31
43
32
44
fieldsets = [
33
- ('General Information' , {"classes" : ("wide" ), "fields" : ["id" , "file_name" , "file" , "file_size_text" ]}),
45
+ ('General Information' , {"classes" : ("wide" ), "fields" : ["id" , "public_id" , " file_name" , "file" , "file_size_text" , "deleted " ]}),
34
46
('Status Information' , {"classes" : ("wide" ), "fields" : ["status" , "status_reason" , "progress" ]}),
35
47
('Auditing Information' , {"classes" : ("wide" ), "fields" : [("created" , "created_by" ), ("updated" , "updated_by" )]})
36
48
]
37
49
38
- list_display = ["id" , "file_name" , "file_size_text" , "status" , "progress" , "duration_text" , "created" , "created_by" , "updated" , "updated_by" ]
39
- readonly_fields = ["id" , "file_name" , "file" , "file_size_text" , "duration" , "duration_text" , "created" , "created_by" , "updated" , "updated_by" ]
50
+ list_display = ["id" , "public_id" , " file_name" , "file_size_text" , "status" , "progress" , "duration_text" , "created" , "created_by" , "updated" , "updated_by" , "is_deleted " ]
51
+ readonly_fields = ["id" , "public_id" , "deleted" , " file_name" , "file" , "file_size_text" , "duration" , "duration_text" , "created" , "created_by" , "updated" , "updated_by" ]
40
52
date_hierarchy = "created"
41
53
42
- list_filter = ["status" , "created_by" , "created" , "updated" ]
54
+ list_filter = ["status" , "deleted" , " created_by" , "created" , "updated" ]
43
55
search_fields = ('file_name' , 'status' , 'created_by__username' , 'updated_by__username' )
44
56
45
- actions = ["mark_as_failed_action" , "restart_processing_action" ]
57
+ actions = ["soft_delete_action" , "soft_restore_action" , " mark_as_failed_action" , "restart_processing_action" , "hard_delete_action " ]
46
58
actions_on_top = True
47
59
48
60
@admin .display (description = "Duration (sec)" )
@@ -56,11 +68,89 @@ def duration_text(self, obj):
56
68
else :
57
69
return None
58
70
71
+ @admin .display (description = "Deleted ?" )
72
+ def is_deleted (self , obj ):
73
+
74
+ return ("Yes" if obj .deleted else "No" )
75
+
59
76
@admin .display (description = "File Size" )
60
77
def file_size_text (self , obj ):
61
78
62
79
return utils .format_human_readable_file_size (obj .size )
63
80
81
+ @admin .action (
82
+ description = "Permanently delete selected Validation Requests" ,
83
+ permissions = ["hard_delete" ]
84
+ )
85
+ def hard_delete_action (self , request , queryset ):
86
+
87
+ if 'apply' in request .POST :
88
+
89
+ for obj in queryset :
90
+ obj .hard_delete ()
91
+
92
+ self .message_user (
93
+ request ,
94
+ ngettext (
95
+ "%d Validation Request was successfully deleted." ,
96
+ "%d Validation Requests were successfully deleted." ,
97
+ len (queryset ),
98
+ )
99
+ % len (queryset ),
100
+ messages .SUCCESS ,
101
+ )
102
+ return HttpResponseRedirect (request .get_full_path ())
103
+
104
+ return render (request , 'admin/hard_delete_intermediate.html' , context = {'val_requests' : queryset , 'entity_name' : 'Validation Request(s)' })
105
+
106
+ @admin .action (
107
+ description = "Soft-delete selected Validation Requests" ,
108
+ permissions = ["soft_delete" ]
109
+ )
110
+ def soft_delete_action (self , request , queryset ):
111
+ # TODO: move to middleware component?
112
+ if request .user .is_authenticated :
113
+ logger .info (f"Authenticated, user.id = { request .user .id } " )
114
+ set_user_context (request .user )
115
+
116
+ for obj in queryset :
117
+ obj .soft_delete ()
118
+
119
+ self .message_user (
120
+ request ,
121
+ ngettext (
122
+ "%d Validation Request was successfully marked as deleted." ,
123
+ "%d Validation Requests were successfully marked as deleted." ,
124
+ len (queryset ),
125
+ )
126
+ % len (queryset ),
127
+ messages .SUCCESS ,
128
+ )
129
+
130
+ @admin .action (
131
+ description = "Soft-restore selected Validation Requests" ,
132
+ permissions = ["soft_restore" ]
133
+ )
134
+ def soft_restore_action (self , request , queryset ):
135
+ # TODO: move to middleware component?
136
+ if request .user .is_authenticated :
137
+ logger .info (f"Authenticated, user.id = { request .user .id } " )
138
+ set_user_context (request .user )
139
+
140
+ for obj in queryset :
141
+ obj .undo_delete ()
142
+
143
+ self .message_user (
144
+ request ,
145
+ ngettext (
146
+ "%d Validation Request was successfully marked as restored." ,
147
+ "%d Validation Requests were successfully marked as restored." ,
148
+ len (queryset ),
149
+ )
150
+ % len (queryset ),
151
+ messages .SUCCESS ,
152
+ )
153
+
64
154
@admin .action (
65
155
description = "Mark selected Validation Requests as Failed" ,
66
156
permissions = ["change_status" ]
@@ -70,6 +160,7 @@ def mark_as_failed_action(self, request, queryset):
70
160
if request .user .is_authenticated :
71
161
logger .info (f"Authenticated, user.id = { request .user .id } " )
72
162
set_user_context (request .user )
163
+
73
164
queryset .update (status = ValidationRequest .Status .FAILED )
74
165
75
166
@admin .action (
@@ -90,26 +181,47 @@ def restart_processing_action(self, request, queryset):
90
181
ifc_file_validation_task .delay (obj .id , obj .file_name )
91
182
logger .info (f"Task 'ifc_file_validation_task' re-submitted for id:{ obj .id } file_name: { obj .file_name } " )
92
183
184
+ def get_actions (self , request ):
185
+
186
+ actions = super ().get_actions (request )
187
+
188
+ # remove default 'delete' action from list
189
+ if 'delete_selected' in actions :
190
+ del actions ['delete_selected' ]
191
+
192
+ return actions
193
+
93
194
def has_change_status_permission (self , request ):
94
195
95
- """
96
- Does the user have the 'change status' permission?
97
- """
98
196
opts = self .opts
99
197
codename = get_permission_codename ("change_status" , opts )
100
198
return request .user .has_perm ("%s.%s" % (opts .app_label , codename ))
199
+
200
+ def has_hard_delete_permission (self , request ):
201
+
202
+ opts = self .opts
203
+ codename = get_permission_codename ("delete" , opts )
204
+ return request .user .has_perm ("%s.%s" % (opts .app_label , codename ))
101
205
206
+ def has_soft_delete_permission (self , request ):
102
207
103
- class ValidationTaskAdmin (BaseAdmin ):
208
+ return self .has_hard_delete_permission (request )
209
+
210
+ def has_soft_restore_permission (self , request ):
211
+
212
+ return self .has_soft_delete_permission (request )
213
+
214
+
215
+ class ValidationTaskAdmin (BaseAdmin , NonAdminAddable ):
104
216
105
217
fieldsets = [
106
- ('General Information' , {"classes" : ("wide" ), "fields" : ["id" , "request" , "type" , "process_id" , "process_cmd" ]}),
218
+ ('General Information' , {"classes" : ("wide" ), "fields" : ["id" , "public_id" , " request" , "type" , "process_id" , "process_cmd" ]}),
107
219
('Status Information' , {"classes" : ("wide" ), "fields" : ["status" , "status_reason" , "progress" , "started" , "ended" , "duration" ]}),
108
220
('Auditing Information' , {"classes" : ("wide" ), "fields" : ["created" , "updated" ]})
109
221
]
110
222
111
- list_display = ["id" , "request" , "type" , "status" , "progress" , "started" , "ended" , "duration_text" , "created" , "updated" ]
112
- readonly_fields = ["id" , "request" , "type" , "process_id" , "process_cmd" , "started" , "ended" , "duration" , "created" , "updated" ]
223
+ list_display = ["id" , "public_id" , " request" , "type" , "status" , "progress" , "started" , "ended" , "duration_text" , "created" , "updated" ]
224
+ readonly_fields = ["id" , "public_id" , " request" , "type" , "process_id" , "process_cmd" , "started" , "ended" , "duration" , "created" , "updated" ]
113
225
date_hierarchy = "created"
114
226
115
227
list_filter = ["status" , "type" , "status" , "started" , "ended" , "created" , "updated" ]
@@ -130,10 +242,10 @@ def duration_text(self, obj):
130
242
return None
131
243
132
244
133
- class ValidationOutcomeAdmin (BaseAdmin ):
245
+ class ValidationOutcomeAdmin (BaseAdmin , NonAdminAddable ):
134
246
135
- list_display = ["id" , "file_name_text" , "type_text" , "instance_id" , "feature" , "feature_version" , "outcome_code" , "severity" , "expected" , "observed" , "created" , "updated" ]
136
- readonly_fields = ["id" , "created" , "updated" ]
247
+ list_display = ["id" , "public_id" , " file_name_text" , "type_text" , "instance_id" , "feature" , "feature_version" , "outcome_code" , "severity" , "expected" , "observed" , "created" , "updated" ]
248
+ readonly_fields = ["id" , "public_id" , " created" , "updated" ]
137
249
138
250
list_filter = ['validation_task__type' , 'severity' , 'outcome_code' ]
139
251
search_fields = ('validation_task__request__file_name' , 'feature' , 'feature_version' , 'outcome_code' , 'severity' , 'expected' , 'observed' )
@@ -147,10 +259,10 @@ def type_text(self, obj):
147
259
return obj .validation_task .type
148
260
149
261
150
- class ModelAdmin (BaseAdmin ):
262
+ class ModelAdmin (BaseAdmin , NonAdminAddable ):
151
263
152
- list_display = ["id" , "file_name" , "size_text" , "date" , "schema" , "mvd" , "nbr_of_elements" , "nbr_of_geometries" , "nbr_of_properties" , "produced_by" , "created" , "updated" ]
153
- readonly_fields = ["id" , "file" , "file_name" , "size" , "size_text" , "date" , "schema" , "mvd" , "number_of_elements" , "number_of_geometries" , "number_of_properties" , "produced_by" , "created" , "updated" ]
264
+ list_display = ["id" , "public_id" , " file_name" , "size_text" , "date" , "schema" , "mvd" , "nbr_of_elements" , "nbr_of_geometries" , "nbr_of_properties" , "produced_by" , "created" , "updated" ]
265
+ readonly_fields = ["id" , "public_id" , " file" , "file_name" , "size" , "size_text" , "date" , "schema" , "mvd" , "number_of_elements" , "number_of_geometries" , "number_of_properties" , "produced_by" , "created" , "updated" ]
154
266
155
267
search_fields = ('file_name' , 'schema' , 'mvd' , 'produced_by__name' , 'produced_by__version' )
156
268
@@ -175,9 +287,9 @@ def size_text(self, obj):
175
287
return utils .format_human_readable_file_size (obj .size )
176
288
177
289
178
- class ModelInstanceAdmin (BaseAdmin ):
290
+ class ModelInstanceAdmin (BaseAdmin , NonAdminAddable ):
179
291
180
- list_display = ["id" , "stepfile_id" , "model" , "ifc_type" , "created" , "updated" ]
292
+ list_display = ["id" , "public_id" , " stepfile_id" , "model" , "ifc_type" , "created" , "updated" ]
181
293
182
294
search_fields = ('stepfile_id' , 'model__file_name' , 'ifc_type' )
183
295
0 commit comments