1+ import logging
2+
13from django .contrib import messages
4+ from django .http import Http404
25from django .shortcuts import redirect
3- from django .views .generic import DeleteView
6+ from django .views .generic import DeleteView , FormView
7+ from django .views .generic .detail import SingleObjectMixin
48
59from ..services .auditor import Auditor
610
11+ logger = logging .getLogger (__name__ )
12+
13+
14+ class NamedThingMixin :
15+ """
16+ A helper to generate consistent messages and titles.
17+ If needed, individual messages can be overriden in subclasses.
18+ """
19+
20+ thing_name = None
21+
22+ def add_title (self , thing_name ):
23+ return f"Add { thing_name } "
24+
25+ def added_message (self , thing_name ):
26+ return f"Added { thing_name } "
27+
28+ def update_title (self , thing_name ):
29+ return f"Edit { thing_name } "
30+
31+ def updated_message (self , thing_name ):
32+ return f"Updated { thing_name } "
33+
34+ def delete_button_text (self , thing_name ):
35+ return f"Delete { thing_name } "
36+
37+ def deleted_message_text (self , thing_name ):
38+ return f"Deleted { thing_name } "
39+
40+ def confirm_delete_link_text (self , thing_name ):
41+ return f"Delete this { thing_name } "
42+
43+ def get_thing_name (self , instance = None ):
44+ """
45+ The name of the thing in lowercase, e.g. "appointment"
46+ """
47+ if self .thing_name :
48+ return self .thing_name
49+
50+ raise ValueError ("thing_name is unset" )
51+
52+
53+ class AddWithAuditView (NamedThingMixin , FormView ):
54+ """
55+ A generic view that adds an object, similar to django.views.generic.CreateView but not based on ModelForms.
56+ An audit record is created and a success message is shown on redirect.
57+
58+ If valid, the form's create() method will be called.
59+ """
60+
61+ template_name = "layout-form.jinja"
62+
63+ def get_success_message_content (self , object ):
64+ return self .added_message (thing_name = self .get_thing_name (object ))
65+
66+ def get_context_data (self , ** kwargs ):
67+ context = super ().get_context_data ()
68+
69+ title = self .add_title (thing_name = self .get_thing_name ())
70+
71+ context .update (
72+ {
73+ "heading" : title ,
74+ "page_title" : title ,
75+ },
76+ )
77+
78+ return context
79+
80+ def get_create_kwargs (self ):
81+ return {}
82+
83+ def form_valid (self , form ):
84+ created_object = form .create (** self .get_create_kwargs ())
85+
86+ auditor = Auditor .from_request (self .request )
87+ auditor .audit_create (created_object )
88+
89+ messages .add_message (
90+ self .request ,
91+ messages .SUCCESS ,
92+ self .get_success_message_content (created_object ),
93+ )
94+
95+ return super ().form_valid (form )
96+
97+
98+ class UpdateWithAuditView (NamedThingMixin , SingleObjectMixin , FormView ):
99+ """
100+ A generic view that updates an object, similar to django.views.generic.UpdateView but not based on ModelForms.
101+ An audit record is created and a success message is shown on redirect.
102+
103+ The form's constructor is expected to have an `instance` parameter.
104+ If valid, the form's update() method will be called.
105+ """
106+
107+ template_name = "layout-form.jinja"
108+
109+ def get_success_message_content (self , object ):
110+ return self .updated_message (thing_name = self .get_thing_name (object ))
111+
112+ def get_form_kwargs (self ):
113+ kwargs = super ().get_form_kwargs ()
114+ kwargs ["instance" ] = self .object
115+ return kwargs
116+
117+ def get (self , request , * args , ** kwargs ):
118+ self .object = self .get_object ()
119+ if self .object is None :
120+ logger .warning ("Object does not exist, redirecting to success URL" )
121+ return redirect (self .get_success_url ())
122+ return super ().get (request , * args , ** kwargs )
123+
124+ def post (self , request , * args , ** kwargs ):
125+ self .object = self .get_object ()
126+ if self .object is None :
127+ raise Http404
128+ return super ().post (request , * args , ** kwargs )
129+
130+ def get_delete_url (self ):
131+ return None
132+
133+ def get_context_data (self , ** kwargs ):
134+ context = super ().get_context_data ()
135+
136+ thing_name = self .get_thing_name (self .object )
137+ title = self .update_title (thing_name = thing_name )
138+
139+ delete_href = self .get_delete_url ()
140+ if delete_href :
141+ context ["delete_link" ] = {
142+ "text" : self .confirm_delete_link_text (thing_name = thing_name ),
143+ "class" : "nhsuk-link app-link--warning" ,
144+ "href" : delete_href ,
145+ }
146+
147+ context .update (
148+ {
149+ "heading" : title ,
150+ "page_title" : title ,
151+ },
152+ )
153+
154+ return context
155+
156+ def form_valid (self , form ):
157+ created_object = form .update ()
7158
8- class DeleteWithAuditView (DeleteView ):
159+ auditor = Auditor .from_request (self .request )
160+ auditor .audit_update (created_object )
161+
162+ messages .add_message (
163+ self .request ,
164+ messages .SUCCESS ,
165+ self .get_success_message_content (created_object ),
166+ )
167+
168+ return super ().form_valid (form )
169+
170+
171+ class DeleteWithAuditView (NamedThingMixin , DeleteView ):
9172 """
10173 A generic delete view with a confirmation page, success message,
11174 and some default context variables.
@@ -14,25 +177,24 @@ class DeleteWithAuditView(DeleteView):
14177 """
15178
16179 template_name = "layout-confirmation.jinja"
17-
18- def get_thing_name (self , object ):
19- return object ._meta .verbose_name
180+ title_pattern = "Are you sure you want to delete this {thing_name}"
20181
21182 def get_success_message_content (self , object ):
22- return f"Deleted { self .get_thing_name (object )} "
183+ return self .deleted_message_text ( thing_name = self . get_thing_name (object ))
23184
24185 def get_cancel_url (self ):
25186 return self .get_success_url ()
26187
27188 def get_context_data (self , ** kwargs ):
28189 context = super ().get_context_data (** kwargs )
29190 thing_name = self .get_thing_name (self .object )
191+ title = self .title_pattern .format (thing_name = thing_name )
30192 context .update (
31193 {
32- "page_title" : f"Are you sure you want to delete this { thing_name } ?" ,
33- "heading" : f"Are you sure you want to delete this { thing_name } ?" ,
194+ "page_title" : title ,
195+ "heading" : title ,
34196 "confirm_action" : {
35- "text" : f"Delete { thing_name } " ,
197+ "text" : self . delete_button_text ( thing_name = thing_name ) ,
36198 "href" : self .request .get_full_path (),
37199 },
38200 "cancel_action" : {"href" : self .get_cancel_url ()},
0 commit comments